]> git.proxmox.com Git - mirror_lxc.git/commitdiff
Merge pull request #1718 from agaida/patch-1
authorStéphane Graber <stgraber@stgraber.org>
Fri, 6 Oct 2017 20:37:13 +0000 (16:37 -0400)
committerGitHub <noreply@github.com>
Fri, 6 Oct 2017 20:37:13 +0000 (16:37 -0400)
Don't force getty@ configuration

150 files changed:
.gitignore
.travis.yml
config/apparmor/abstractions/container-base
config/apparmor/abstractions/container-base.in
config/templates/userns.conf.in
configure.ac
doc/Makefile.am
doc/ja/Makefile.am
doc/ja/lxc-monitor.sgml.in
doc/ja/lxc-update-config.sgml.in [new file with mode: 0644]
doc/ja/lxc.container.conf.sgml.in
doc/ja/lxc.sgml.in
doc/ko/lxc-monitor.sgml.in
doc/ko/lxc.container.conf.sgml.in
doc/ko/lxc.sgml.in
doc/lxc-monitor.sgml.in
doc/lxc-update-config.sgml.in [new file with mode: 0644]
doc/lxc.container.conf.sgml.in
doc/lxc.sgml.in
src/lxc/Makefile.am
src/lxc/af_unix.c
src/lxc/af_unix.h
src/lxc/arguments.c
src/lxc/arguments.h
src/lxc/attach.c
src/lxc/attach.h
src/lxc/attach_options.h
src/lxc/bdev/bdev.c [deleted file]
src/lxc/bdev/bdev.h [deleted file]
src/lxc/bdev/lxcaufs.c [deleted file]
src/lxc/bdev/lxcaufs.h [deleted file]
src/lxc/bdev/lxcbtrfs.c [deleted file]
src/lxc/bdev/lxcbtrfs.h [deleted file]
src/lxc/bdev/lxcdir.c [deleted file]
src/lxc/bdev/lxcdir.h [deleted file]
src/lxc/bdev/lxcloop.c [deleted file]
src/lxc/bdev/lxcloop.h [deleted file]
src/lxc/bdev/lxclvm.c [deleted file]
src/lxc/bdev/lxclvm.h [deleted file]
src/lxc/bdev/lxcnbd.c [deleted file]
src/lxc/bdev/lxcnbd.h [deleted file]
src/lxc/bdev/lxcoverlay.c [deleted file]
src/lxc/bdev/lxcoverlay.h [deleted file]
src/lxc/bdev/lxcrbd.c [deleted file]
src/lxc/bdev/lxcrbd.h [deleted file]
src/lxc/bdev/lxcrsync.c [deleted file]
src/lxc/bdev/lxcrsync.h [deleted file]
src/lxc/bdev/lxczfs.c [deleted file]
src/lxc/bdev/lxczfs.h [deleted file]
src/lxc/bdev/storage_utils.c [deleted file]
src/lxc/bdev/storage_utils.h [deleted file]
src/lxc/cgroups/cgfs.c
src/lxc/cgroups/cgfsng.c
src/lxc/cgroups/cgmanager.c
src/lxc/cgroups/cgroup.c
src/lxc/cgroups/cgroup.h
src/lxc/commands.c
src/lxc/conf.c
src/lxc/conf.h
src/lxc/confile.c
src/lxc/confile.h
src/lxc/confile_legacy.c
src/lxc/confile_utils.c
src/lxc/confile_utils.h
src/lxc/console.c [changed mode: 0755->0644]
src/lxc/criu.c
src/lxc/list.h
src/lxc/log.c
src/lxc/lsm/apparmor.c
src/lxc/lxc_user_nic.c
src/lxc/lxccontainer.c
src/lxc/lxccontainer.h
src/lxc/lxclock.c
src/lxc/lxclock.h
src/lxc/lxcutmp.c [deleted file]
src/lxc/lxcutmp.h [deleted file]
src/lxc/monitor.c
src/lxc/network.c
src/lxc/network.h
src/lxc/nl.c
src/lxc/parse.c
src/lxc/rtnl.c
src/lxc/rtnl.h
src/lxc/seccomp.c
src/lxc/start.c
src/lxc/start.h
src/lxc/storage/aufs.c [new file with mode: 0644]
src/lxc/storage/aufs.h [new file with mode: 0644]
src/lxc/storage/btrfs.c [new file with mode: 0644]
src/lxc/storage/btrfs.h [new file with mode: 0644]
src/lxc/storage/dir.c [new file with mode: 0644]
src/lxc/storage/dir.h [new file with mode: 0644]
src/lxc/storage/loop.c [new file with mode: 0644]
src/lxc/storage/loop.h [new file with mode: 0644]
src/lxc/storage/lvm.c [new file with mode: 0644]
src/lxc/storage/lvm.h [new file with mode: 0644]
src/lxc/storage/nbd.c [new file with mode: 0644]
src/lxc/storage/nbd.h [new file with mode: 0644]
src/lxc/storage/overlay.c [new file with mode: 0644]
src/lxc/storage/overlay.h [new file with mode: 0644]
src/lxc/storage/rbd.c [new file with mode: 0644]
src/lxc/storage/rbd.h [new file with mode: 0644]
src/lxc/storage/rsync.c [new file with mode: 0644]
src/lxc/storage/rsync.h [new file with mode: 0644]
src/lxc/storage/storage.c [new file with mode: 0644]
src/lxc/storage/storage.h [new file with mode: 0644]
src/lxc/storage/storage_utils.c [new file with mode: 0644]
src/lxc/storage/storage_utils.h [new file with mode: 0644]
src/lxc/storage/zfs.c [new file with mode: 0644]
src/lxc/storage/zfs.h [new file with mode: 0644]
src/lxc/sync.c
src/lxc/sync.h
src/lxc/tools/lxc-checkconfig.in
src/lxc/tools/lxc-update-config.in [new file with mode: 0644]
src/lxc/tools/lxc_clone.c
src/lxc/tools/lxc_copy.c
src/lxc/tools/lxc_create.c
src/lxc/tools/lxc_destroy.c
src/lxc/tools/lxc_execute.c
src/lxc/tools/lxc_ls.c
src/lxc/tools/lxc_snapshot.c
src/lxc/tools/lxc_start.c
src/lxc/tools/lxc_unshare.c
src/lxc/tools/lxc_usernsexec.c
src/lxc/utils.c
src/lxc/utils.h
src/tests/aa.c
src/tests/concurrent.c
src/tests/config_jump_table.c
src/tests/console.c
src/tests/containertests.c
src/tests/destroytest.c
src/tests/getkeys.c
src/tests/lxc-test-apparmor-mount
src/tests/lxc-test-unpriv
src/tests/lxc-test-usernic.in
src/tests/lxc-test-utils.c
src/tests/parse_config_file.c
src/tests/saveconfig.c
src/tests/shortlived.c
src/tests/startone.c
templates/Makefile.am
templates/lxc-alpine.in
templates/lxc-busybox.in
templates/lxc-debian.in
templates/lxc-oci.in [new file with mode: 0755]
templates/lxc-opensuse.in
templates/lxc-plamo.in
templates/lxc-sabayon.in
templates/lxc-ubuntu.in

index c88aea06f21febeb32a83670402cafb8b0d1b119..80f6889b75c35edad0db5f58b87a5efb94235a4b 100644 (file)
@@ -37,6 +37,7 @@ src/lxc/lxc-attach
 src/lxc/lxc-autostart
 src/lxc/lxc-cgroup
 src/lxc/tools/lxc-checkconfig
+src/lxc/tools/lxc-update-config
 src/lxc/lxc-checkpoint
 src/lxc/lxc-clone
 src/lxc/lxc-console
index 294e06cd48ee1a247dbfa33b420485a91ead535a..758f2ea3accefca67155cc99f218eab39523a6a8 100644 (file)
@@ -10,7 +10,7 @@ script:
  - ./autogen.sh
  - mkdir build
  - cd build
- - ../configure --enable-tests
+ - ../configure --enable-tests --with-distro=unknown
  - make -j4
  - make DESTDIR=$TRAVIS_BUILD_DIR/install install
 notifications:
index 06290de2c16694deda7f0dea22ef307fd83c5895..a5e6c35f6077b63067a27ebf31bc71a4880b93c0 100644 (file)
@@ -72,8 +72,6 @@
 
   # block some other dangerous paths
   deny @{PROC}/kcore rwklx,
-  deny @{PROC}/kmem rwklx,
-  deny @{PROC}/mem rwklx,
   deny @{PROC}/sysrq-trigger rwklx,
 
   # deny writes in /sys except for /sys/fs/cgroup, also allow
index 5bc9b28bf22d71212ec170b6072e8101e944a2e3..16529bbf0df7b6383460c61479b9dd1c04fdfd1a 100644 (file)
@@ -72,8 +72,6 @@
 
   # block some other dangerous paths
   deny @{PROC}/kcore rwklx,
-  deny @{PROC}/kmem rwklx,
-  deny @{PROC}/mem rwklx,
   deny @{PROC}/sysrq-trigger rwklx,
 
   # deny writes in /sys except for /sys/fs/cgroup, also allow
index b43d4f3dbba7e87ad209384374ec0dbf29548122..be4fbbc6beee06524597e9b45b7d49416aa19fc2 100644 (file)
@@ -4,11 +4,3 @@ lxc.cgroup.devices.allow =
 
 # We can't move bind-mounts, so don't use /dev/lxc/
 lxc.tty.dir =
-
-# Extra bind-mounts for userns
-lxc.mount.entry = /dev/full dev/full none bind,create=file 0 0
-lxc.mount.entry = /dev/null dev/null none bind,create=file 0 0
-lxc.mount.entry = /dev/random dev/random none bind,create=file 0 0
-lxc.mount.entry = /dev/tty dev/tty none bind,create=file 0 0
-lxc.mount.entry = /dev/urandom dev/urandom none bind,create=file 0 0
-lxc.mount.entry = /dev/zero dev/zero none bind,create=file 0 0
index 0e29cb9d9a3da5aaeb5680158412dd3bcde2df76..642b78e7e1308a91b62abb57dc04d7beec8c2956 100644 (file)
@@ -3,12 +3,12 @@
 
 m4_define([lxc_devel], 1)
 m4_define([lxc_version_major], 2)
-m4_define([lxc_version_minor], 0)
+m4_define([lxc_version_minor], 1)
 m4_define([lxc_version_micro], 0)
 m4_define([lxc_version_beta], [])
 
 m4_define([lxc_abi_major], 1)
-m4_define([lxc_abi_minor], 2)
+m4_define([lxc_abi_minor], 3)
 m4_define([lxc_abi_micro], 0)
 m4_define([lxc_abi], [lxc_abi_major.lxc_abi_minor.lxc_abi_micro])
 
@@ -558,7 +558,7 @@ AC_ARG_WITH([cgroup-pattern],
        [AC_HELP_STRING(
                [--with-cgroup-pattern=pattern],
                [pattern for container cgroups]
-       )], [], [with_cgroup_pattern=['/lxc/%n']])
+       )], [], [with_cgroup_pattern=['lxc/%n']])
 
 # Container log path.  By default, use $lxcpath.
 AC_MSG_CHECKING([Whether to place logfiles in container config path])
@@ -785,6 +785,7 @@ AC_CONFIG_FILES([
        doc/lxc-top.sgml
        doc/lxc-unfreeze.sgml
        doc/lxc-unshare.sgml
+       doc/lxc-update-config.sgml
        doc/lxc-user-nic.sgml
        doc/lxc-usernsexec.sgml
        doc/lxc-wait.sgml
@@ -833,6 +834,7 @@ AC_CONFIG_FILES([
        doc/ja/lxc-top.sgml
        doc/ja/lxc-unfreeze.sgml
        doc/ja/lxc-unshare.sgml
+       doc/ja/lxc-update-config.sgml
        doc/ja/lxc-user-nic.sgml
        doc/ja/lxc-usernsexec.sgml
        doc/ja/lxc-wait.sgml
@@ -896,6 +898,7 @@ AC_CONFIG_FILES([
        templates/lxc-fedora
        templates/lxc-fedora-legacy
        templates/lxc-gentoo
+       templates/lxc-oci
        templates/lxc-openmandriva
        templates/lxc-opensuse
        templates/lxc-oracle
@@ -914,6 +917,7 @@ AC_CONFIG_FILES([
        src/lxc/lxc.functions
        src/lxc/tools/lxc-checkconfig
        src/lxc/tools/lxc-start-ephemeral
+       src/lxc/tools/lxc-update-config
        src/lxc/version.h
        src/python-lxc/Makefile
 
index b0f81151761492330fc6fca39ae66368fbafed61..ae023e4114e5b29dab7e10f9f796cfbc136b378e 100644 (file)
@@ -38,6 +38,7 @@ man_MANS = \
        lxc-top.1 \
        lxc-unfreeze.1 \
        lxc-unshare.1 \
+       lxc-update-config.1 \
        lxc-user-nic.1 \
        lxc-usernsexec.1 \
        lxc-wait.1 \
index 201094be963096fd8229e5a8059fccfc5a30fb27..f30346d3abfccce0967b9bd22ac1918170f07cb5 100644 (file)
@@ -30,6 +30,7 @@ man_MANS = \
        lxc-top.1 \
        lxc-unfreeze.1 \
        lxc-unshare.1 \
+       lxc-update-config.1 \
        lxc-user-nic.1 \
        lxc-usernsexec.1 \
        lxc-wait.1 \
index e2794a614d7da0258a8ae02c9974f9838e560eeb..d31731cd5d80c25ab12892a89acd7989d6f7e208 100644 (file)
@@ -148,7 +148,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       </varlistentry>
 
       <varlistentry>
-       <term>lxc-monitor -n '[f|b].*'</term>
+       <term>lxc-monitor -n '[fb].*'</term>
        <listitem>
        <para>
           <!--
diff --git a/doc/ja/lxc-update-config.sgml.in b/doc/ja/lxc-update-config.sgml.in
new file mode 100644 (file)
index 0000000..2312f0e
--- /dev/null
@@ -0,0 +1,151 @@
+<!--
+
+lxc-update-config
+
+(C) Copyright 2017 Canonical Ltd.
+
+Authors:
+Christian Brauner <christian.brauner@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 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-update-config</refentrytitle>
+        <manvolnum>1</manvolnum>
+    </refmeta>
+
+    <refnamediv>
+        <refname>lxc-update-config</refname>
+
+        <refpurpose>
+          <!--
+            update a legacy pre LXC 2.1 configuration file
+            -->
+          LXC 2.1 より前の古い形式の設定ファイルを新しい形式に更新する
+        </refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv>
+        <cmdsynopsis>
+            <command>lxc-update-config</command>
+            <arg choice="req">-c <replaceable>config</replaceable></arg>
+        </cmdsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1>
+        <title><!-- Description -->説明</title>
+
+        <para>
+          <!--
+            <command>lxc-update-config</command> detects any legacy
+            configuration keys in the given <replaceable>config</replaceable>
+            file and will replace them with the appropriate new configuration
+            keys.
+            -->
+          <command>lxc-update-config</command> は、<replaceable>config</replaceable> で指定したファイルの古い形式の設定項目を検出し、適切な新しい設定項目に置き換えます。
+        </para>
+        <para>
+          <!--
+            <command>lxc-update-config</command> will first create a backup of
+            the old <replaceable>config</replaceable> file in the same directory
+            and name it <replaceable>config.backup</replaceable> and then update
+            the original <replaceable>config</replaceable> file in place. In
+            case the update fails to apply or leads to an invalid
+            <replaceable>config</replaceable> file that cannot be used to start
+            a container users can either compare
+            <replaceable>config</replaceable> with
+            <replaceable>config.backup</replaceable> and try to manually repair
+            any the invalid configuration keys or simply rollback to the legacy
+            configuration file by copying
+            <replaceable>config.backup</replaceable> to
+            <replaceable>config</replaceable>.
+            -->
+          <command>lxc-update-config</command> はまず、古い <replaceable>config</replaceable> ファイルのバックアップを <replaceable>config.backup</replaceable> という名前で同じディレクトリに作成します。そして、元の <replaceable>config</replaceable> ファイルを更新します。
+          更新が失敗した場合や、コンテナの起動ができない無効な <replaceable>config</replaceable> ファイルである場合は、ユーザが <replaceable>config</replaceable> と <replaceable>config.backup</replaceable> を比較して、手動で無効な設定項目を修正するか、<replaceable>config.backup</replaceable> を <replaceable>config</replaceable> にコピーして以前の設定ファイルに戻せます。
+        </para>
+        <para>
+          <!--
+            Any failures for <command>lxc-update-config</command> to generate a
+            useable <replaceable>config</replaceable> file are a bug and should
+            be reported upstream.
+            -->
+          <command>lxc-update-config</command> が使えない <replaceable>config</replaceable> ファイルを生成した場合はバグですので、開発元に報告してください。
+        </para>
+    </refsect1>
+
+    <refsect1>
+        <title><!-- Options -->オプション</title>
+        <variablelist>
+            <varlistentry>
+                <term>
+                    <option>-c, --config</option>
+                </term>
+                <listitem>
+                    <para>
+                      <!--
+                      Path to the configuration file to update.
+                        -->
+                      更新したい設定ファイルのパス
+                    </para>
+                </listitem>
+            </varlistentry>
+
+            <varlistentry>
+                <term>
+                    <option>-h, --help</option>
+                </term>
+                <listitem>
+                    <para>
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </refsect1>
+
+    &seealso;
+
+    <refsect1>
+        <title><!-- Author -->作者</title>
+        <para>Christian Brauner <email>christian.brauner@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:
+-->
index 6c4dadef022f7a3234d3ff64fbef8d635d502605..525e2d5515653389f8df1d1a6bd3a5f470d4ef33 100644 (file)
@@ -105,11 +105,11 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       example, a process running as UID and GID 0 inside the container might
       appear as UID and GID 100000 on the host.  The implementation and working
       details can be gathered from the corresponding user namespace man page.
-      UID and GID mappings can be defined with the <option>lxc.id_map</option>
+      UID and GID mappings can be defined with the <option>lxc.idmap</option>
       key.
         -->
       本質的には、ユーザ名前空間は与えられた UID、GID の組を隔離します。ユーザ名前空間は、ホスト上の UID、GID のある範囲を、それとは異なるコンテナ上の UID、GID の範囲へマッピングすることで実現します。カーネルは、ホスト上では実際には UID、GID は特権を持たないにも関わらず、コンテナ内ではすべての UID、GID が期待されるように見えるように変換を行います。
-      例えば、コンテナ内では UID、GID が 0 として実行中のプロセスは、ホスト上では UID、GID が 100000 として見えるでしょう。実装と動作の詳細は、ユーザ名前空間の man ページから得られます。UID と GID のマッピングは <option>lxc.id_map</option> を使って定義できます。
+      例えば、コンテナ内では UID、GID が 0 として実行中のプロセスは、ホスト上では UID、GID が 100000 として見えるでしょう。実装と動作の詳細は、ユーザ名前空間の man ページから得られます。UID と GID のマッピングは <option>lxc.idmap</option> を使って定義できます。
     </para>
 
     <para>
@@ -337,15 +337,25 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <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.execute.cmd</option>
+          </term>
+          <listitem>
+            <para>
+             <!--
+              Absolute path from container rootfs to the binary to run by default.  This
+             mostly makes sense for lxc-execute.
+             -->
+             デフォルトで実行するバイナリのコンテナの root からの絶対パスを指定します。これは <command>lxc-execute</command> のための設定です。
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
       <variablelist>
         <varlistentry>
           <term>
@@ -354,9 +364,10 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
           <listitem>
             <para>
               <!--
-                  Absolute path from container rootfs to the binary to use as init.
+                  Absolute path from container rootfs to the binary to use as init. This
+                 mostly makes sense for lxc-start. Default is /sbin/init.
                 -->
-              init として使うバイナリの、コンテナの rootfs からの絶対パスを指定します。
+              init として使うバイナリの、コンテナの root からの絶対パスを指定します。これは <command>lxc-start</command> のための設定です。デフォルトは <command>/sbin/init</command> です。
             </para>
           </listitem>
         </varlistentry>
@@ -1561,6 +1572,31 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
             </para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.cgroup.dir</option>
+          </term>
+          <listitem>
+            <para>
+             <!--
+              specify a directory or path in which the container's cgroup will
+              be created. For example, setting
+              <option>lxc.cgroup.dir = my-cgroup/first</option> for a container
+              named "c1" will create the container's cgroup as a sub-cgroup of
+              "my-cgroup". For example, if the user's current cgroup "my-user"
+              is located in the root cgroup of the cpuset controllerin in a
+              cgroup v1 hierarchy this would create the cgroup
+              "/sys/fs/cgroup/cpuset/my-user/my-cgroup/first/c1" for the
+              container. Any missing cgroups will be created by LXC. This
+              presupposes that the user has write access to its current cgroup.
+             -->
+             コンテナの cgroup を作成するパスやディレクトリを指定します。
+             例えば、"c1" という名前のコンテナで <option>lxc.cgroup.dir = my-cgroup/first</option> のように設定すると、"my-cgroup" のサブ cgroup のようにコンテナの cgroup を作成します。
+             例えば、ユーザのカレントの cgroup である "my-user" が cgroup v1 階層にある cpuset コントローラの root cgroup 内に存在する場合、この設定は "/sys/fs/cgroup/cpuset/my-user/my-cgroup/first/c1" という cgroup をこのコンテナ向けに作成します。
+             存在しない cgroup は LXC が作成しますが、ユーザがカレントの cgroup に書き込み権を持っていることが前提となります。
+            </para>
+          </listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
 
@@ -1904,7 +1940,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
       <variablelist>
         <varlistentry>
           <term>
-            <option>lxc.id_map</option>
+            <option>lxc.idmap</option>
           </term>
           <listitem>
             <para>
@@ -2068,6 +2104,23 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
           </listitem>
         </varlistentry>
       </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.hook.start-host</option>
+          </term>
+          <listitem>
+            <para>
+              <!--
+              A hook to be run in the host's namespace after the
+              container has been setup, and immediately before starting
+              the container init.
+              -->
+              コンテナのセットアップが済んだあと、コンテナの init を実行する直前に、ホストの名前空間で実行するためのフックです。
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
       <variablelist>
         <varlistentry>
           <term>
@@ -2642,8 +2695,8 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
         この設定は、コンテナ内のユーザとグループ両方の id 0-9999 の範囲を、ホスト上の 100000-109999 へマッピングします。
       </para>
       <programlisting>
-        lxc.id_map = u 0 100000 10000
-        lxc.id_map = g 0 100000 10000
+        lxc.idmap = u 0 100000 10000
+        lxc.idmap = g 0 100000 10000
       </programlisting>
     </refsect2>
 
index 8f5d1723882d63dc583c74631049e2fe9f76673d..e02765d3a5cdff05fe0f0fe91d618e12bcb55271 100644 (file)
@@ -57,218 +57,125 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
     </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.
+      The container technology is actively being pushed into the mainstream
+      Linux kernel. It provides resource management through control groups and
+      resource isolation via namespaces.
       -->
-      コンテナ技術は、メインストリームの linux kernel で活発に開発が進んでいる技術です。
-      コンテナ技術は、process container という名前でも知られる control groups の機能を使って、リソース管理を提供し、名前空間を使って、リソースの隔離を提供します。
+      コンテナ技術は、メインストリームの Linux Kernel で活発に開発が進んでいる技術です。コンテナ技術は、cgroup によりリソースを管理する機能を提供し、名前空間によりリソースを隔離する機能を提供します。
     </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.
+      <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 full system.
       -->
-      linux コンテナ (<command>lxc</command>) は、ユーザースペースのコンテナオブジェクトを提供するための新しい機能を使う事を目指しています。
-      この新しい機能とは、アプリケーションやシステムでの利用を目的とした、完全なリソースの隔離やリソースコントロールを提供する機能です。
+      <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.
+      <command>lxc</command> is small enough to easily manage a container with
+      simple command lines and complete enough to be used for other purposes.
       -->
-      このプロジェクトの第一の目的は、コンテナプロジェクトに参加するカーネル開発者の作業を快適にすることと、特に新機能である Checkpoint/Restart 機能への取り組みを続ける事です。
-      <command>lxc</command> コマンドは、シンプルなコマンドでコンテナの管理を簡単に行えるように小さく、他の目的のために使うのに充分な機能を持っています。
+      <command>lxc</command> は、シンプルなコマンドラインでコンテナを簡単に管理できるほど軽量で、他の用途に使うのにも十分に機能がそろっています。
     </para>
   </refsect1>
 
   <refsect1>
-    <title><!-- Requirements -->å¿\85è¦\81条件</title>
+    <title><!-- Requirements -->å\8b\95ä½\9c条件</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.
+      The kernel version >= 3.10 shipped with the distros, will work with
+      <command>lxc</command>, this one will have less functionalities but enough
+      to be interesting.
       -->
-      <command>lxc</command> は、カーネルが提供するいくつかの機能に依存しており、その機能がアクティブになっている必要があります。
-      機能が足りない場合は、<command>lxc</command> は、いくつかの機能が制限されるか、単純に動作が失敗します。
+      カーネルのバージョンが 3.10 以上のディストリビューションであれば、<command>lxc</command> が動作するでしょう。このバージョンは機能は少ないですが、それでも十分楽しめるでしょう。
     </para>
 
     <para>
       <!--
-      The following list gives the kernel features to be enabled in
-      the kernel to have the full features container:
+      <command>lxc</command> relies on a set of functionalities provided by the
+      kernel. The helper script <command>lxc-checkconfig</command> will give
+      you information about your kernel configuration, required, and missing
+      features.
       -->
-      以下のリストは、コンテナの全機能を有効にするために、カーネルで有効にする必要のある機能の一覧です
+      <command>lxc</command> はカーネルが提供する様々な機能に依存します。<command>lxc-checkconfig</command> がカーネルの設定や、必要な機能、足りない機能についての情報を提供してくれるでしょう
     </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.
-        -->
-       control group は、どこにでもマウント可能です。
-        例えば、<command>mount -t cgroup cgroup /cgroup</command> のようにです。
-
-       しかし、cgroup の階層構造を /sys/fs/cgroup 以下にマウントするために cgmanager や cgroup-lite や systemd の使用が推奨されています。
-      </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.
+      A container is an object isolating some resources of the host, for the
+      application or system running in it.
       -->
-      ã\82³ã\83³ã\83\86ã\83\8aã\81¯ã\80\81ã\82³ã\83³ã\83\86ã\83\8aå\86\85ã\81§å®\9fè¡\8cã\81\95ã\82\8cã\81¦ã\81\84ã\82\8bã\82·ã\82¹ã\83\86ã\83 ã\82\84ã\82¢ã\83\97ã\83ªã\82±ã\83¼ã\82·ã\83§ã\83³ã\81«å¯¾ã\81\99ã\82\8bã\83\9bã\82¹ã\83\88ã\81®ã\83ªã\82½ã\83¼ã\82¹ã\81®ã\81\84ã\81\8fã\81¤ã\81\8bã\81\8cã\80\81é\9a\94é\9b¢ã\81\95ã\82\8cã\81¦ã\81\84ã\82\8bã\82ªã\83\96ã\82¸ã\82§ã\82¯ã\83\88ã\81§す。
+      ã\82³ã\83³ã\83\86ã\83\8aã\81¯ã\80\81ã\83\9bã\82¹ã\83\88ã\81®ã\83ªã\82½ã\83¼ã\82¹ã\81®ã\81\84ã\81\8fã\81¤ã\81\8bã\82\92é\9a\94é\9b¢ã\81\97ã\81¦ã\80\81å\86\85é\83¨ã\81§ã\82¢ã\83\97ã\83ªã\82±ã\83¼ã\82·ã\83§ã\83³ã\82\84ã\82·ã\82¹ã\83\86ã\83 ã\82\92å®\9fè¡\8cã\81\97ã\81¾す。
     </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.
+      The application / system will be launched inside a container specified by
+      a configuration that is either initially created or passed as a parameter
+      of the commands.
       -->
-      アプリケーション/システムは、あらかじめ作成された設定もしくは開始コマンドのパラメータで指定された設定で、コンテナ内で実行されます。
+      アプリケーションやシステムは、あらかじめ作成した設定や、コマンドへのパラメータで与えた設定で、コンテナ内で実行されます。
     </para>
 
     <para>
       <!--
-         How to run an application in a container ?
-       -->
-      ã\81©ã\81\86ã\82\84ã\81£ã\81¦ã\82³ã\83³ã\83\86ã\83\8aå\86\85ã\81§ã\82¢ã\83\97ã\83ªã\82±ã\83¼ã\82·ã\83§ã\83³ã\82\92å®\9fè¡\8cã\81\99ã\82\8bã\81®ã\81§ã\81\97ã\82\87ã\81\86?
+      How to run an application in a container
+      -->
+      ã\82³ã\83³ã\83\86ã\83\8aå\86\85ã\81§ã\82¢ã\83\97ã\83ªã\82±ã\83¼ã\82·ã\83§ã\83³ã\82\92å®\9fè¡\8cã\81\99ã\82\8bæ\96¹æ³\95
     </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
+      Before running an application, you should know what are the resources you
+      want to isolate. The default configuration is to isolate PIDs, the sysv
+      IPC and 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> を再度マウントしなければなりません。
-      どんな場合でも、衝突を避けたい場合、コンテナ専用の rootfs を指定することができます。
-      rootfs はディレクトリツリーとなる事も可能で、前もって元の rootfs を bind マウントし、しかし、自身の <filename>/etc</filename> や <filename>/home</filename>を使って。自身のディストリビューションを使うことが可能です。
+      アプリケーションを実行する前に、隔離したいリソースについて知っておくべきです。デフォルトの設定では、PID、sysv IPC、マウントポイントが隔離されます。コンテナ内でシンプルなシェルを実行したい場合で、特に rootfs を共有したい場合、基本的な設定が必要です。
+      もし、<command>sshd</command> のようなアプリケーションを実行したい場合、新しいネットワークスタックと、新しいホスト名を準備しなくてはなりません。もし、同じファイル (<filename>/var/run/httpd.pid</filename> 等) の衝突を避けたい場合、空の <filename>/var/run/</filename> を再度マウントしなければなりません。
+      どんな場合でも衝突を避けたい場合、コンテナ専用の rootfs を指定することができます。rootfs はディレクトリツリーとする事も可能で、前もって元の rootfs を bind マウントし、<filename>/etc</filename> や <filename>/home</filename>だけは自身のディレクトリを使って、自身のディストリビューションを使えます。
     </para>
     <para>
       <!--
       Here is an example of directory tree
       for <command>sshd</command>:
-      <programlisting> 
+      <programlisting>  
 [root@lxc sshd]$ tree -d rootfs
-       
-rootfs 
-|&#045;&#045; bin      
-|&#045;&#045; dev      
+        
+rootfs  
+|&#045;&#045; bin       
+|&#045;&#045; dev       
 |   |&#045;&#045; pts
 |   `&#045;&#045; shm
 |       `&#045;&#045; network
-|&#045;&#045; etc      
+|&#045;&#045; etc       
 |   `&#045;&#045; ssh
-|&#045;&#045; lib      
+|&#045;&#045; lib       
 |&#045;&#045; proc
 |&#045;&#045; root
 |&#045;&#045; sbin
-|&#045;&#045; sys      
-|&#045;&#045; usr      
-`&#045;&#045; var      
+|&#045;&#045; sys       
+|&#045;&#045; usr       
+`&#045;&#045; var       
     |&#045;&#045; empty
-    |   `&#045;&#045; sshd
+    |   `&#045;&#045; sshddd
     |&#045;&#045; lib
     |   `&#045;&#045; empty
     |       `&#045;&#045; sshd
@@ -278,33 +185,33 @@ rootfs
 
       and the mount points file associated with it:
       <programlisting>
-       [root@lxc sshd]$ cat fstab
+        [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
+        /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> 
+        ここで、<command>sshd</command> のためのディレクトリツリーのサンプルを示しましょう。
+      <programlisting>  
 [root@lxc sshd]$ tree -d rootfs
-       
-rootfs 
-|-- bin        
-|-- dev        
+        
+rootfs  
+|-- bin         
+|-- dev         
 |   |-- pts
 |   `-- shm
 |       `-- network
-|-- etc        
+|-- etc         
 |   `-- ssh
-|-- lib        
+|-- lib         
 |-- proc
 |-- root
 |-- sbin
-|-- sys        
-|-- usr        
-`-- var        
+|-- sys         
+|-- usr         
+`-- var         
     |-- empty
     |   `-- sshd
     |-- lib
@@ -316,87 +223,63 @@ rootfs
 
       そして、それに対応するマウントポイントのファイルは以下のようになります。
       <programlisting>
-       [root@lxc sshd]$ cat fstab
+        [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
+        /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 ?
+      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
+    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 needs 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:
+        -->
+    コンテナ内でシステムを実行するのは、逆説的ではありますが、アプリケーションを実行するよりも簡単です。
+    それは、隔離するリソースについて考える必要がないからで、全てを隔離する必要があるからです。
+    他のリソースは、コンテナが設定を行うので、設定なしで隔離されるように指定されます。
+    例えば、IPv4 アドレスはコンテナの init スクリプトでシステムによってセットアップされるでしょう。
+    以下に、(システムを実行するときの) マウントポイントファイルを示します。
+    </para>
 
       <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
+        [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
+        /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.
-       -->
-       コンテナが作成されるとき、コンテナは設定情報を含みます。
-        プロセスが生成されるとき、コンテナは開始し、実行されるでしょう。
-        コンテナ内で実行されている最後のプロセスが終了したとき、コンテナは停止します。
+        <!--
+        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.
-       -->
-       コンテナの初期化時の失敗の場合は、(以下の図の) 中断の状態を通ります。
+        <!--
+        In case of failure when the container is initialized, it will pass
+        through the aborting state.
+        -->
+        コンテナの初期化時の失敗の場合は、(以下の図の) 中断の状態を通ります。
       </para>
 
       <programlisting>
@@ -432,158 +315,133 @@ rootfs
     <refsect2>
       <title><!-- Configuration -->設定</title>
       <para>
-       <!--
-       The container is configured through a configuration
-       file, the format of the configuration file is described in
+        <!--
+        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>
+        <refentrytitle><filename>lxc.conf</filename></refentrytitle>
+        <manvolnum>5</manvolnum>
       </citerefentry>
       -->
       </para>
-       コンテナは設定ファイル経由で設定します。設定の書式は以下で説明しています。
+      コンテナは設定ファイル経由で設定します。設定の書式は
       <citerefentry>
-       <refentrytitle><filename>lxc.conf</filename></refentrytitle>
-       <manvolnum>5</manvolnum>
+        <refentrytitle><filename>lxc.conf</filename></refentrytitle>
+        <manvolnum>5</manvolnum>
       </citerefentry>
+      で説明しています。
     </refsect2>
 
     <refsect2>
-      <title><!--Creating / Destroying container
-       (persistent container) -->コンテナの生成と終了 (持続性のコンテナ)</title>
+      <title><!-- Creating / Destroying containers -->コンテナの作成と削除</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>
+        <!--
+        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.
+        -->
+        持続性のコンテナオブジェクトは <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>
+        <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>
+          It is not mandatory to create a container object before starting it.
+          The container can be directly started with a configuration file as
+          parameter.
+          -->
+        コンテナを開始する前にコンテナオブジェクトを作成する必要はありません。パラメータとして設定ファイルを指定して、コンテナを直接起動できます。
+        </para>
     </refsect2>
 
     <refsect2>
-      <title><!-- Starting / Stopping container -->コンテナの開始と終了</title>
+      <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> を使用する必要があります。
+        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 ended, the container will be stopped, but if needed the
+        <command>lxc-stop</command> command can be used to stop the container.
+        -->
+        コンテナが作成されると、アプリケーションもしくはシステムを実行できます。このために使用するのが <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>
+        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:
         -->
-        コンテナ内のアプリケーションの実行は、正確にはシステムとして実行するのとは異なります。
-        そのような理由で、コンテナ内でアプリケーションを実行するためのコマンドには、2 種類の違ったものがあります。
+        コンテナ内でアプリケーションを実行することは、正確にはシステムとして実行するのとは異なります。このため、コンテナ内でアプリケーションを実行するためのコマンドには、2 種類の違ったものがあります。
         <programlisting>
-         lxc-execute -n foo [-f config] /bin/bash
-         lxc-start -n foo [-f config] [/bin/bash]
-       </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.
+        The <command>lxc-execute</command> command will run the specified command
+        into a 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 PID 1 and the first process of the
+        application has PID 2.
         -->
-        <command>lxc-execute</command> コマンドは、<command>lxc-init</command> プロセス経由で、コンテナ内で特定のコマンドを実行します。
+        <command>lxc-execute</command> コマンドは、間に <command>lxc-init</command> プロセスを介して、コンテナ内で指定したコマンドを実行します。
         lxc-init はコマンドを実行した後、(コンテナ内でのデーモンの実行をサポートするために) 実行したコマンドと生成された全てのプロセスが終了するのを待ちます。
-        言いかえると、コンテナ内では <command>lxc-init</command> は pid 1 を持ち、アプリケーションの最初のプロセスは pid 2 をもちます。
+        言いかえると、コンテナ内では <command>lxc-init</command> は PID 1 を持ち、アプリケーションの最初のプロセスは PID 2 をもちます。
       </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> .
+        The <command>lxc-start</command> command will directly run the specified
+        command in 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 となります。
-        もし、実行するコマンドが指定されない場合は、<command>lxc-start</command> は lxc.init.cmd で設定されたコマンドを実行します。もし lxc.init.cmd が設定されていない場合は <filename>/sbin/init</filename> を実行します。
+        <command>lxc-start</command> コマンドは、コンテナ内の特定のコマンドを直接実行します。最初のプロセスの PID が 1 となります。
+        もし、実行するコマンドが指定されていない場合は、<command>lxc-start</command> は lxc.init.cmd で設定されたコマンドを実行します。もし 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.
+        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>
+        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.
         -->
-        もしアプリケーションの反応がなくなった場合や、アクセスできなくなった場合、自分で終了することができない場合は、荒っぽいですが、<command>lxc-stop</command> コマンドがコンテナ内の全てのプロセスを容赦なく停止させてくれるでしょう。
+        もしアプリケーションの反応がなくなった場合や、アクセスできなくなった場合、自分で終了できない場合は、荒っぽいですが、<command>lxc-stop</command> コマンドがコンテナ内の全てのプロセスを容赦なく停止させてくれるでしょう。
+        <programlisting>
+          lxc-stop -n foo -k
+        </programlisting>
+
       </para>
     </refsect2>
 
@@ -591,21 +449,17 @@ rootfs
       <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>
+        If the container is configured with ttys, it is possible to access it
+        through them. It is up to the container to provide a set of available
+        ttys to be used by the following command. When the tty is lost, it is
+        possible to reconnect to it without login again.
         -->
         コンテナが tty を持つように設定されているならば、tty を通してコンテナにアクセスすることができます。
-        ã\81\9dã\82\8cã\81¯ä»¥ä¸\8bã\81®ã\82³ã\83\9eã\83³ã\83\89ã\81\8c使ã\81\86 tty ã\81\8cã\82³ã\83³ã\83\86ã\83\8aã\81§å\88©ç\94¨å\8f¯è\83½に設定されているか次第です。
+        ã\82¢ã\82¯ã\82»ã\82¹ã\81§ã\81\8dã\82\8bã\81\8bã\81©ã\81\86ã\81\8bã\81¯ã\80\81以ä¸\8bã\81®ã\82³ã\83\9eã\83³ã\83\89ã\81\8c使ã\81\86 tty ã\81\8cã\82³ã\83³ã\83\86ã\83\8aã\81§å\88©ç\94¨ã\81§ã\81\8dã\82\8bã\82\88ã\81\86に設定されているか次第です。
         tty が失われたとき、再度のログインなしでその tty に再接続することが可能です。
-       <programlisting>
-         lxc-console -n foo -t 3
-       </programlisting>
+        <programlisting>
+          lxc-console -n foo -t 3
+        </programlisting>
       </para>
     </refsect2>
 
@@ -613,40 +467,40 @@ rootfs
       <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>
+        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
+        will put all the processes in an uninteruptible state and
 
-       <programlisting>
-         lxc-unfreeze -n foo
-       </programlisting>
+        <programlisting>
+          lxc-unfreeze -n foo
+        </programlisting>
 
-       will resume them.
+        will resume them.
         -->
         ジョブスケジューリングなどで、コンテナに属する全てのプロセスを停止する事が役に立つときがあります。
         コマンド
-       <programlisting>
-         lxc-freeze -n foo
-       </programlisting>
+        <programlisting>
+          lxc-freeze -n foo
+        </programlisting>
         は、全てのプロセスを中断不可能な状態に置きます。そして、
 
-       <programlisting>
-         lxc-unfreeze -n foo
-       </programlisting>
+        <programlisting>
+          lxc-unfreeze -n foo
+        </programlisting>
 
         その全てのプロセスを再開します。
       </para>
 
       <para>
         <!--
-       This feature is enabled if the cgroup freezer is enabled in the
-       kernel.
+        This feature is enabled if the freezer cgroup v1 controller is enabled
+        in the kernel.
         -->
-        この機能は、カーネルで cgroup freezer 機能が有効になっている場合に使用可能です。
+        この機能は、カーネルで cgroup v1 の freezer コントローラが有効になっている場合に使用できます。
       </para>
     </refsect2>
 
@@ -655,54 +509,41 @@ rootfs
         コンテナに関する情報の取得</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>
+      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 in a
+      specific container. For this reason, the following commands may be useful:
         -->
-        多数のコンテナが存在する場合、それらが実行されたり破壊されたりすること、何が実行されていて、特定のコンテナ内で実行されている pid が何であるかをフォローするのは大変です。
-        このような時には、以下のようなコマンドが役に立つかもしれません。
-       <programlisting>
-         lxc-ls
-         lxc-info -n foo
-       </programlisting>
+        多数のコンテナが存在する場合、それらが実行されたり削除されたりすること、何が実行されていて、特定のコンテナ内で実行されている PID が何であるかをフォローするのは大変です。このような時には、以下のようなコマンドが役に立つかもしれません。
+        <programlisting>
+          lxc-ls -f
+          lxc-info -n foo
+        </programlisting>
       </para>
       <para>
         <!--
-       <command>lxc-ls</command> lists the containers of the
-       system.
+        <command>lxc-ls</command> lists containers.
         -->
-        <command>lxc-ls</command> ã\81¯ã\80\81ã\82·ã\82¹ã\83\86ã\83 ã\81®ã\82³ã\83³ã\83\86ã\83\8aã\82\92ä¸\80覧します。
+        <command>lxc-ls</command> ã\81¯ã\82³ã\83³ã\83\86ã\83\8aã\82\92ã\83ªã\82¹ã\83\88表示します。
       </para>
 
       <para>
         <!--
-       <command>lxc-info</command> gives information for a specific
-       container.
+        <command>lxc-info</command> gives information for a specific container.
         -->
-        <command>lxc-info</command> は、指定したコンテナに関する情報を取得します。
+        <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>
+        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>
@@ -711,177 +552,127 @@ rootfs
       <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.
+        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> command will monitor one or several
+        containers. The parameter of this command accepts a regular expression
+        for example:
+        -->
+        <command>lxc-monitor</command> コマンドは、一つもしくは複数のコンテナをモニタリングします。このコマンドのパラメータは、正規表現を受け付けます。例えば
+        <programlisting>
+          lxc-monitor -n "foo|bar"
+        </programlisting>
+        <!--
+        will monitor the states of containers named 'foo' and 'bar', and:
         -->
-        <command>lxc-monitor</command> コマンドは、一つもしくはいくつかのコンテナをモニタリングします。
-        このコマンドのパラメータは、正規表現を受け付けます。例えば
-       <programlisting>
-         lxc-monitor -n "foo|bar"
-       </programlisting>
         は 'foo' と 'bar' という名前のコンテナの状態をモニタリングします。そして、
-       <programlisting>
-         lxc-monitor -n ".*"
-       </programlisting>
+        <programlisting>
+          lxc-monitor -n ".*"
+        </programlisting>
+        <!--
+        will monitor all the containers.
+        -->
         は全てのコンテナの状態をモニタリングします。
       </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>
+        For a container 'foo' starting, doing some work and exiting,
+        the output will be in the form:
         -->
         コンテナ 'foo' が開始され、いくつか処理を行い、終了した場合、出力は以下のようになります。
-       <programlisting>
-         'foo' changed state to [STARTING]
-         'foo' changed state to [RUNNING]
-         'foo' changed state to [STOPPING]
-         'foo' changed state to [STOPPED]
-       </programlisting>
+        <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> 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 it successfully
+        started as a daemon.
         -->
-        <command>lxc-wait</command> コマンドは指定した状態を待って、終了します。
-        これは、コンテナの開始や終了に同期したいスクリプトで役に立ちます。
-        パラメータは、異なった状態の論理和 (OR) を指定します。
+        <command>lxc-wait</command> コマンドは指定した状態を待って終了します。これは、コンテナの開始や終了に同期したいスクリプトで役に立ちます。パラメータは、異なった状態の論理和 (OR) を指定します。
         以下の例は、バックグラウンドで実行されたコンテナをどのようにして待つかを示します。
 
-       <programlisting>
+        <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"
+          # 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>
+        </programlisting>
       </para>
     </refsect2>
 
     <refsect2>
-      <title><!-- Setting the control group for container -->
-        コンテナの control group の設定
-      </title>
+      <title><!-- cgroup settings for containers -->コンテナの cgroup の設定</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.
+        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.
         -->
-        コンテナは control group と結合しています。
-        コンテナが開始すると control group が生成され、それと結びつけられます。
-        control group のプロパティは、lxc-cgroup コマンドを使って、コンテナが実行中に読み取ったり、変更したりすることができます。
+        コンテナは control group と結合しています。コンテナを開始すると cgroup が生成され、結びつけられます。
+        cgroup のプロパティは、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> 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> コマンドは、コンテナと結びつけられている control group サブシステムを設定したり、取得したりするのに使います。
-        サブシステム名の指定はユーザが行ない、このコマンドはサブシステム名の文法チェックは一切行ないません。
-        もし、指定したサブシステム名が存在しない場合は、コマンドの実行は失敗します。
+        <command>lxc-cgroup</command> コマンドは、コンテナと結びつけられている control group サブシステムを設定したり、取得したりするのに使います。サブシステム名の指定はユーザが行ない、このコマンドはサブシステム名の文法チェックは一切行ないません。もし、指定したサブシステム名が存在しない場合は、コマンドの実行は失敗します。
       </para>
       <para>
+        <programlisting>
+          lxc-cgroup -n foo cpuset.cpus
+        </programlisting>
         <!--
-       <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.
+        will display the content of this subsystem.
         -->
-       <programlisting>
-         lxc-cgroup -n foo cpuset.cpus
-       </programlisting>
         は、このサブシステムの内容を表示します。
-       <programlisting>
-         lxc-cgroup -n foo cpu.shares 512
-       </programlisting>
+        <programlisting>
+          lxc-cgroup -n foo cpu.shares 512
+        </programlisting>
+        <!--
+        will set the subsystem to the specified value.
+        -->
         は、このサブシステムに指定した値を設定します。
       </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>
+    <para>Christian Brauner <email>christian.brauner@ubuntu.com</email></para>
+    <para>Serge Hallyn <email>serge@hallyn.com</email></para>
+    <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
   </refsect1>
 
 </refentry>
index ce710531995e40df955d812b05c72b50956e7eb0..d2cb5601a0e7b38659da3ba09035d02d2d2d3793 100644 (file)
@@ -148,7 +148,7 @@ by Sungbae Yoo <sungbae.yoo at samsung.com>
       </varlistentry>
 
       <varlistentry>
-       <term>lxc-monitor -n '[f|b].*'</term>
+       <term>lxc-monitor -n '[fb].*'</term>
        <listitem>
        <para>
           <!--
index b0466a1ebb9f930ab61c613030c453424b707445..e880525a6bb13c369f970733188e2ca80a587364 100644 (file)
@@ -1839,7 +1839,7 @@ mknod errno 0
       <variablelist>
        <varlistentry>
          <term>
-           <option>lxc.id_map</option>
+           <option>lxc.idmap</option>
          </term>
          <listitem>
            <para>
@@ -2564,8 +2564,8 @@ mknod errno 0
         이 설정은 UID와 GID 둘다를 컨테이너의 0 ~ 9999를 호스트의 100000 ~ 109999로 매핑한다.
       </para>
       <programlisting>
-       lxc.id_map = u 0 100000 10000
-       lxc.id_map = g 0 100000 10000
+       lxc.idmap = u 0 100000 10000
+       lxc.idmap = g 0 100000 10000
       </programlisting>
     </refsect2>
 
index 1b9f979f23a90aa931ca63a0201e6463c34bc6ee..dcfd970c03ce1afd56cef5f76bf3a24c471c6d56 100644 (file)
@@ -171,7 +171,7 @@ by Sungbae Yoo <sungbae.yoo at samsung.com>
        The helper script <command>lxc-checkconfig</command> will give
        you information about your kernel configuration.
        -->
-       배포판들에 포함된 2.6.32 이상의 커널에서는  <command>lxc</command>가 동작한다. 매우 작은 기능만 있지만 충분히 사용할 수 있다.
+       배포판들에 포함된 3.10 이상의 커널에서는  <command>lxc</command>가 동작한다. 매우 작은 기능만 있지만 충분히 사용할 수 있다.
         <command>lxc-checkconfig</command> 스크립트를 사용하면 현재 커널 설정에 대한 정보를 얻을 수 있다.
       </para>
 
index e57314e58ef26700235f6af6b585b095af90aa9f..b6b31cfe108416dc1b3c83c90ee63e2d425ff00e 100644 (file)
@@ -121,7 +121,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       </varlistentry>
 
       <varlistentry>
-       <term>lxc-monitor -n '[f|b].*'</term>
+       <term>lxc-monitor -n '[fb].*'</term>
        <listitem>
        <para>
          will monitor the different states for container with the
diff --git a/doc/lxc-update-config.sgml.in b/doc/lxc-update-config.sgml.in
new file mode 100644 (file)
index 0000000..520a898
--- /dev/null
@@ -0,0 +1,133 @@
+<!--
+
+lxc-update-config
+
+(C) Copyright 2017 Canonical Ltd.
+
+Authors:
+Christian Brauner <christian.brauner@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
+
+-->
+
+<!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-update-config</refentrytitle>
+        <manvolnum>1</manvolnum>
+    </refmeta>
+
+    <refnamediv>
+        <refname>lxc-update-config</refname>
+
+        <refpurpose>
+            update a legacy pre LXC 2.1 configuration file
+        </refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv>
+        <cmdsynopsis>
+            <command>lxc-update-config</command>
+            <arg choice="req">-c <replaceable>config</replaceable></arg>
+        </cmdsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1>
+        <title>Description</title>
+
+        <para>
+           <command>lxc-update-config</command> detects any legacy
+           configuration keys in the given <replaceable>config</replaceable>
+           file and will replace them with the appropriate new configuration
+           keys.
+        </para>
+       <para>
+           <command>lxc-update-config</command> will first create a backup of
+           the old <replaceable>config</replaceable> file in the same directory
+           and name it <replaceable>config.backup</replaceable> and then update
+           the original <replaceable>config</replaceable> file in place. In
+           case the update fails to apply or leads to an invalid
+           <replaceable>config</replaceable> file that cannot be used to start
+           a container users can either compare
+           <replaceable>config</replaceable> with
+           <replaceable>config.backup</replaceable> and try to manually repair
+           any the invalid configuration keys or simply rollback to the legacy
+           configuration file by copying
+           <replaceable>config.backup</replaceable> to
+           <replaceable>config</replaceable>.
+        </para>
+       <para>
+           Any failures for <command>lxc-update-config</command> to generate a
+           useable <replaceable>config</replaceable> file are a bug and should
+           be reported upstream.
+        </para>
+    </refsect1>
+
+    <refsect1>
+        <title>Options</title>
+        <variablelist>
+            <varlistentry>
+                <term>
+                    <option>-c, --config</option>
+                </term>
+                <listitem>
+                    <para>
+                       Path to the configuration file to update.
+                    </para>
+                </listitem>
+            </varlistentry>
+
+            <varlistentry>
+                <term>
+                    <option>-h, --help</option>
+                </term>
+                <listitem>
+                    <para>
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </refsect1>
+
+    &seealso;
+
+    <refsect1>
+        <title>Author</title>
+        <para>Christian Brauner <email>christian.brauner@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:
+-->
index f3b594ea084fa28d334d8588eac14dee402cce13..059942bc9191f2dda9fd8c6a7e6e1d7ef00aa0f4 100644 (file)
@@ -86,7 +86,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       example, a process running as UID and GID 0 inside the container might
       appear as UID and GID 100000 on the host.  The implementation and working
       details can be gathered from the corresponding user namespace man page.
-      UID and GID mappings can be defined with the <option>lxc.id_map</option>
+      UID and GID mappings can be defined with the <option>lxc.idmap</option>
       key.
     </para>
 
@@ -255,11 +255,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <title>Init command</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
       </para>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.execute.cmd</option>
+          </term>
+          <listitem>
+            <para>
+              Absolute path from container rootfs to the binary to run by default.  This
+             mostly makes sense for <command>lxc-execute</command>.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
       <variablelist>
         <varlistentry>
           <term>
@@ -267,7 +276,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
           </term>
           <listitem>
             <para>
-              Absolute path from container rootfs to the binary to use as init.
+              Absolute path from container rootfs to the binary to use as init. This
+             mostly makes sense for <command>lxc-start</command>. Default is <command>/sbin/init</command>.
             </para>
           </listitem>
         </varlistentry>
@@ -1129,6 +1139,25 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
             </para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term>
+            <option>lxc.cgroup.dir</option>
+          </term>
+          <listitem>
+            <para>
+              specify a directory or path in which the container's cgroup will
+              be created. For example, setting
+              <option>lxc.cgroup.dir = my-cgroup/first</option> for a container
+              named "c1" will create the container's cgroup as a sub-cgroup of
+              "my-cgroup". For example, if the user's current cgroup "my-user"
+              is located in the root cgroup of the cpuset controller in a
+              cgroup v1 hierarchy this would create the cgroup
+              "/sys/fs/cgroup/cpuset/my-user/my-cgroup/first/c1" for the
+              container. Any missing cgroups will be created by LXC. This
+              presupposes that the user has write access to its current cgroup.
+            </para>
+          </listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
 
@@ -1383,7 +1412,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
       <variablelist>
         <varlistentry>
           <term>
-            <option>lxc.id_map</option>
+            <option>lxc.idmap</option>
           </term>
           <listitem>
             <para>
@@ -1427,6 +1456,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
           <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.path 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>
+          <listitem><para> LXC_CGNS_AWARE: indicated whether the container is cgroup namespace aware.  </para></listitem>
+          <listitem><para> LXC_LOG_LEVEL: the container's log level.  </para></listitem>
         </itemizedlist>
       </para>
       <para>
@@ -1498,6 +1529,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
           </listitem>
         </varlistentry>
       </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>
+            <option>lxc.hook.start-host</option>
+          </term>
+          <listitem>
+            <para>
+              A hook to be run in the host's namespace after the
+              container has been setup, and immediately before starting
+             the container init.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
       <variablelist>
         <varlistentry>
           <term>
@@ -1935,8 +1980,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
         range 0-9999 in the container to the ids 100000-109999 on the host.
       </para>
       <programlisting>
-        lxc.id_map = u 0 100000 10000
-        lxc.id_map = g 0 100000 10000
+        lxc.idmap = u 0 100000 10000
+        lxc.idmap = g 0 100000 10000
       </programlisting>
     </refsect2>
 
index a068d2c1205f022abfd6e2d407100b1ac34e2cf8..894e6ca90d9ef3a0f94c49a3693f290c14049d48 100644 (file)
@@ -51,137 +51,68 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     </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>
-    </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.
+      The container technology is actively being pushed into the mainstream
+      Linux kernel. It provides resource management through control groups and
+      resource isolation via namespaces.
     </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.
+      <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 full system.
     </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.
+      <command>lxc</command> is small enough to easily manage a container with
+      simple command lines and complete enough to be used for other purposes.
     </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.
+      The kernel version >= 3.10 shipped with the distros, will work with
+      <command>lxc</command>, this one will have less functionalities but enough
+      to be interesting.
     </para>
-
+       
     <para>
-      The following list gives the kernel features to be enabled in
-      the kernel to have the full features container:
+      <command>lxc</command> relies on a set of functionalities provided by the
+      kernel. The helper script <command>lxc-checkconfig</command> will give
+      you information about your kernel configuration, required, and missing
+      features.
     </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.
-      </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.
-
-      </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.
+      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.
+      The application / system will be launched inside a container specified by
+      a configuration that is either initially created or passed as a parameter
+      of the commands.
     </para>
 
-    <para>How to run an application in a container ?</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
+      Before running an application, you should know what are the resources you
+      want to isolate. The default configuration is to isolate PIDs, the sysv
+      IPC and 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>
     </para>
     <para>
@@ -225,15 +156,17 @@ rootfs
       </programlisting>
     </para>
 
-    <para>How to run a system in a container ?</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
+    <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 needs 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:
+    </para>
 
       <programlisting>
        [root@lxc debian]$ cat fstab
@@ -242,26 +175,17 @@ rootfs
        /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>
-    </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.
+       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.
+       In case of failure when the container is initialized, it will pass
+       through the aborting state.
       </para>
 
       <programlisting>
@@ -306,17 +230,14 @@ rootfs
     </refsect2>
 
     <refsect2>
-      <title>Creating / Destroying container
-       (persistent container)</title>
+      <title>Creating / Destroying containers</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.
+       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
@@ -326,33 +247,30 @@ rootfs
 
     <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>
+         It is not mandatory to create a container object before starting 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.
+      <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 ended, the container will be stopped, but if needed the
+       <command>lxc-stop</command> command can be used to stop the container.
       </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:
+       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]
@@ -360,39 +278,35 @@ rootfs
       </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.
+       The <command>lxc-execute</command> command will run the specified command
+       into a 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 PID 1 and the first process of the
+       application has PID 2.
       </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> .
+       The <command>lxc-start</command> command will directly run the specified
+       command in 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> .
       </para>
 
       <para>
-       To summarize, <command>lxc-execute</command> is for running
-       an application and <command>lxc-start</command> is better suited for
+       To summarize, <command>lxc-execute</command> is for running an
+       application and <command>lxc-start</command> is better suited for
        running a system.
       </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.
+       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
+         lxc-stop -n foo -k
        </programlisting>
       </para>
     </refsect2>
@@ -400,11 +314,10 @@ rootfs
     <refsect2>
       <title>Connect to an available 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.
+       If the container is configured with ttys, it is possible to access it
+       through them. It is up to the container to provide a set of available
+       ttys to be used by the following command. When the tty is lost, it is
+       possible to reconnect to it without login again.
        <programlisting>
          lxc-console -n foo -t 3
        </programlisting>
@@ -430,30 +343,28 @@ rootfs
       </para>
 
       <para>
-       This feature is enabled if the cgroup freezer is enabled in the
-       kernel.
+       This feature is enabled if the freezer cgroup v1 controller is enabled
+       in the kernel.
       </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:
+      <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 in a
+      specific container. For this reason, the following commands may be useful:
        <programlisting>
-         lxc-ls
+         lxc-ls -f
          lxc-info -n foo
        </programlisting>
       </para>
       <para>
-       <command>lxc-ls</command> lists the containers of the
-       system.
+       <command>lxc-ls</command> lists containers.
       </para>
 
       <para>
-       <command>lxc-info</command> gives information for a specific
-       container.
+       <command>lxc-info</command> gives information for a specific container.
       </para>
 
       <para>
@@ -464,22 +375,20 @@ rootfs
            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>
+       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:
+       <command>lxc-monitor</command> command will monitor one or several
+       containers. The parameter of this command accepts a regular expression
+       for example:
        <programlisting>
          lxc-monitor -n "foo|bar"
        </programlisting>
@@ -504,8 +413,8 @@ rootfs
        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.
+       following example shows how to wait for a container if it successfully
+       started as a daemon.
 
        <programlisting>
 <![CDATA[
@@ -527,11 +436,12 @@ rootfs
     </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.
+      <title>cgroup settings for containers</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.
       </para>
       <para>
        <command>lxc-cgroup</command> command is used to set or get a
@@ -553,18 +463,14 @@ rootfs
     </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.</para>
-  </refsect1>
-
   &seealso;
 
   <refsect1>
     <title>Author</title>
     <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+    <para>Christian Brauner <email>christian.brauner@ubuntu.com</email></para>
+    <para>Serge Hallyn <email>serge@hallyn.com</email></para>
+    <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
   </refsect1>
 
 </refentry>
index a55103ec5b61b713db808de0c14f916d4c84c33a..9a429b8cfe95b4310b54a7dec2e341238ac1d82f 100644 (file)
@@ -6,18 +6,18 @@ pkginclude_HEADERS = \
 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 \
-       bdev/storage_utils.h \
+       storage/storage.h \
+       storage/aufs.h \
+       storage/btrfs.h \
+       storage/dir.h \
+       storage/loop.h \
+       storage/lvm.h \
+       storage/nbd.h \
+       storage/overlay.h \
+       storage/rbd.h \
+       storage/rsync.h \
+       storage/zfs.h \
+       storage/storage_utils.h \
        cgroups/cgroup.h \
        cgroups/cgroup_utils.h \
        caps.h \
@@ -77,18 +77,18 @@ endif
 lib_LTLIBRARIES = liblxc.la
 liblxc_la_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 \
-       bdev/storage_utils.c bdev/storage_utils.h \
+       storage/storage.c storage/storage.h \
+       storage/aufs.c storage/aufs.h \
+       storage/btrfs.c storage/btrfs.h \
+       storage/dir.c storage/dir.h \
+       storage/loop.c storage/loop.h \
+       storage/lvm.c storage/lvm.h \
+       storage/nbd.c storage/nbd.h \
+       storage/overlay.c storage/overlay.h \
+       storage/rbd.c storage/rbd.h \
+       storage/rsync.c storage/rsync.h \
+       storage/zfs.c storage/zfs.h \
+       storage/storage_utils.c storage/storage_utils.h \
        cgroups/cgfs.c \
        cgroups/cgfsng.c \
        cgroups/cgroup_utils.c cgroups/cgroup_utils.h \
@@ -127,7 +127,6 @@ liblxc_la_SOURCES = \
        mainloop.c mainloop.h \
        af_unix.c af_unix.h \
        \
-       lxcutmp.c lxcutmp.h \
        lxclock.h lxclock.c \
        lxccontainer.c lxccontainer.h \
        version.h \
@@ -170,7 +169,7 @@ AM_CFLAGS=-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
        -DSBINDIR=\"$(SBINDIR)\" \
        -I $(top_srcdir)/src \
        -I $(top_srcdir)/src/lxc \
-       -I $(top_srcdir)/src/lxc/bdev \
+       -I $(top_srcdir)/src/lxc/storage \
        -I $(top_srcdir)/src/lxc/cgroups
 
 if ENABLE_APPARMOR
@@ -209,7 +208,8 @@ liblxc_la_LIBADD += $(CGMANAGER_LIBS) $(DBUS_LIBS) $(NIH_LIBS) $(NIH_DBUS_LIBS)
 liblxc_la_CFLAGS += $(CGMANAGER_CFLAGS) $(DBUS_CFLAGS) $(NIH_CFLAGS) $(NIH_DBUS_CFLAGS)
 endif
 
-bin_SCRIPTS = tools/lxc-checkconfig
+bin_SCRIPTS = tools/lxc-checkconfig \
+             tools/lxc-update-config
 
 EXTRA_DIST = \
        tools/lxc-top.lua
index c354637b1246eff26a2ff2f033a86b5e6d85595d..01e86aaef24e22f24967bf9901b47319901f47a0 100644 (file)
@@ -38,7 +38,7 @@ lxc_log_define(lxc_af_unix, lxc);
 
 int lxc_abstract_unix_open(const char *path, int type, int flags)
 {
-       int fd;
+       int fd, ret;
        size_t len;
        struct sockaddr_un addr;
 
@@ -64,18 +64,24 @@ int lxc_abstract_unix_open(const char *path, int type, int flags)
        /* addr.sun_path[0] has already been set to 0 by memset() */
        strncpy(&addr.sun_path[1], &path[1], strlen(&path[1]));
 
-       if (bind(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + len + 1)) {
+       ret = bind(fd, (struct sockaddr *)&addr,
+                  offsetof(struct sockaddr_un, sun_path) + len + 1);
+       if (ret < 0) {
                int tmp = errno;
                close(fd);
                errno = tmp;
                return -1;
        }
 
-       if (type == SOCK_STREAM && listen(fd, 100)) {
-               int tmp = errno;
-               close(fd);
-               errno = tmp;
-               return -1;
+       if (type == SOCK_STREAM) {
+               ret = listen(fd, 100);
+               if (ret < 0) {
+                       int tmp = errno;
+                       close(fd);
+                       errno = tmp;
+                       return -1;
+               }
+
        }
 
        return fd;
@@ -84,13 +90,12 @@ int lxc_abstract_unix_open(const char *path, int type, int flags)
 int lxc_abstract_unix_close(int fd)
 {
        close(fd);
-
        return 0;
 }
 
 int lxc_abstract_unix_connect(const char *path)
 {
-       int fd;
+       int fd, ret;
        size_t len;
        struct sockaddr_un addr;
 
@@ -112,7 +117,9 @@ int lxc_abstract_unix_connect(const char *path)
        /* addr.sun_path[0] has already been set to 0 by memset() */
        strncpy(&addr.sun_path[1], &path[1], strlen(&path[1]));
 
-       if (connect(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + len + 1)) {
+       ret = connect(fd, (struct sockaddr *)&addr,
+                     offsetof(struct sockaddr_un, sun_path) + len + 1);
+       if (ret < 0) {
                close(fd);
                return -1;
        }
@@ -205,13 +212,11 @@ out:
 
 int lxc_abstract_unix_send_credential(int fd, void *data, size_t size)
 {
-       struct msghdr msg = { 0 };
+       struct msghdr msg = {0};
        struct iovec iov;
        struct cmsghdr *cmsg;
        struct ucred cred = {
-               .pid = getpid(),
-               .uid = getuid(),
-               .gid = getgid(),
+           .pid = getpid(), .uid = getuid(), .gid = getgid(),
        };
        char cmsgbuf[CMSG_SPACE(sizeof(cred))] = {0};
        char buf[1] = {0};
@@ -238,7 +243,7 @@ int lxc_abstract_unix_send_credential(int fd, void *data, size_t size)
 
 int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size)
 {
-       struct msghdr msg = { 0 };
+       struct msghdr msg = {0};
        struct iovec iov;
        struct cmsghdr *cmsg;
        struct ucred cred;
@@ -263,10 +268,11 @@ int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size)
        cmsg = CMSG_FIRSTHDR(&msg);
 
        if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)) &&
-                       cmsg->cmsg_level == SOL_SOCKET &&
-                       cmsg->cmsg_type == SCM_CREDENTIALS) {
+           cmsg->cmsg_level == SOL_SOCKET &&
+           cmsg->cmsg_type == SCM_CREDENTIALS) {
                memcpy(&cred, CMSG_DATA(cmsg), sizeof(cred));
-               if (cred.uid && (cred.uid != getuid() || cred.gid != getgid())) {
+               if (cred.uid &&
+                   (cred.uid != getuid() || cred.gid != getgid())) {
                        INFO("message denied for '%d/%d'", cred.uid, cred.gid);
                        return -EACCES;
                }
index fafa225b5a678a634c1f5e7743bf27fcd28df2fc..9dfccd16e96acd6d05dc578d8d31b6f6f5c5e6a9 100644 (file)
@@ -38,4 +38,4 @@ extern int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
 extern int lxc_abstract_unix_send_credential(int fd, void *data, size_t size);
 extern int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size);
 
-#endif
+#endif /* __LXC_AF_UNIX_H */
index cb29482e4cc3daea082cbda36293bc10bdd01a87..c6267387f8d44c29a6081b90c32ca749b7fad84c 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
  */
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <limits.h>
 #include <string.h>
-#include <ctype.h>             /* for isprint() */
-#include <errno.h>
+#include <unistd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <unistd.h>
 
 #include "arguments.h"
 #include "utils.h"
 #include "version.h"
 
-/*---------------------------------------------------------------------------*/
-static int build_shortopts(const struct option *a_options,
-                          char *a_shortopts, size_t a_size)
+static int build_shortopts(const struct option *a_options, char *a_shortopts,
+                          size_t a_size)
 {
-       const struct option *opt;
        size_t i = 0;
+       const struct option *opt;
 
        if (!a_options || !a_shortopts || !a_size)
                return -1;
@@ -79,12 +79,11 @@ static int build_shortopts(const struct option *a_options,
 
        return 0;
 
-      is2big:
+is2big:
        errno = E2BIG;
        return -1;
 }
 
-/*---------------------------------------------------------------------------*/
 static void print_usage(const struct option longopts[],
                        const struct lxc_arguments *a_args)
 
@@ -96,8 +95,9 @@ static void print_usage(const struct option longopts[],
 
        for (opt = longopts, i = 1; opt->name; opt++, i++) {
                int j;
-               char *uppername = strdup(opt->name);
+               char *uppername;
 
+               uppername = strdup(opt->name);
                if (!uppername)
                        exit(-ENOMEM);
 
@@ -129,7 +129,8 @@ static void print_usage(const struct option longopts[],
        exit(0);
 }
 
-static void print_version() {
+static void print_version()
+{
        printf("%s\n", LXC_VERSION);
        exit(0);
 }
@@ -164,13 +165,14 @@ static int lxc_arguments_lxcpath_add(struct lxc_arguments *args,
 {
        if (args->lxcpath_additional != -1 &&
            args->lxcpath_cnt > args->lxcpath_additional) {
-               fprintf(stderr, "This command only accepts %d -P,--lxcpath arguments\n",
+               fprintf(stderr,
+                       "This command only accepts %d -P,--lxcpath arguments\n",
                        args->lxcpath_additional + 1);
                exit(EXIT_FAILURE);
        }
 
-       args->lxcpath = realloc(args->lxcpath, (args->lxcpath_cnt + 1) *
-                                sizeof(args->lxcpath[0]));
+       args->lxcpath = realloc(
+           args->lxcpath, (args->lxcpath_cnt + 1) * sizeof(args->lxcpath[0]));
        if (args->lxcpath == NULL) {
                lxc_error(args, "no memory");
                return -ENOMEM;
@@ -179,11 +181,11 @@ static int lxc_arguments_lxcpath_add(struct lxc_arguments *args,
        return 0;
 }
 
-extern int lxc_arguments_parse(struct lxc_arguments *args,
-                              int argc, char * const argv[])
+extern int lxc_arguments_parse(struct lxc_arguments *args, int argc,
+                              char *const argv[])
 {
+       int ret = 0;
        char shortopts[256];
-       int  ret = 0;
 
        ret = build_shortopts(args->options, shortopts, sizeof(shortopts));
        if (ret < 0) {
@@ -192,28 +194,43 @@ extern int lxc_arguments_parse(struct lxc_arguments *args,
                return ret;
        }
 
-       while (1)  {
-               int c, index = 0;
+       while (true) {
+               int c;
+               int index = 0;
 
                c = getopt_long(argc, argv, shortopts, args->options, &index);
                if (c == -1)
                        break;
                switch (c) {
-               case 'n':       args->name = optarg; break;
-               case 'o':       args->log_file = optarg; break;
-               case 'l':       args->log_priority = optarg; break;
-               case 'q':       args->quiet = 1; break;
-               case OPT_RCFILE: args->rcfile = optarg; break;
+               case 'n':
+                       args->name = optarg;
+                       break;
+               case 'o':
+                       args->log_file = optarg;
+                       break;
+               case 'l':
+                       args->log_priority = optarg;
+                       break;
+               case 'q':
+                       args->quiet = 1;
+                       break;
+               case OPT_RCFILE:
+                       args->rcfile = optarg;
+                       break;
                case 'P':
                        remove_trailing_slashes(optarg);
                        ret = lxc_arguments_lxcpath_add(args, optarg);
                        if (ret < 0)
                                return ret;
                        break;
-               case OPT_USAGE: print_usage(args->options, args);
-               case OPT_VERSION: print_version();
-               case '?':       print_help(args, 1);
-               case 'h':       print_help(args, 0);
+               case OPT_USAGE:
+                       print_usage(args->options, args);
+               case OPT_VERSION:
+                       print_version();
+               case '?':
+                       print_help(args, 1);
+               case 'h':
+                       print_help(args, 0);
                default:
                        if (args->parser) {
                                ret = args->parser(args, c, optarg);
@@ -231,7 +248,8 @@ extern int lxc_arguments_parse(struct lxc_arguments *args,
 
        /* If no lxcpaths were given, use default */
        if (!args->lxcpath_cnt) {
-               ret = lxc_arguments_lxcpath_add(args, lxc_global_config_value("lxc.lxcpath"));
+               ret = lxc_arguments_lxcpath_add(
+                   args, lxc_global_config_value("lxc.lxcpath"));
                if (ret < 0)
                        return ret;
        }
index d51db45590b606dd2b2e98f4f0e249db3087e632..b07caf42bf52e67c34a6cb9fa45f5b4c796c4436 100644 (file)
 
 struct lxc_arguments;
 
-typedef int (*lxc_arguments_parser_t) (struct lxc_arguments *, int, char*);
-typedef int (*lxc_arguments_checker_t) (const struct lxc_arguments *);
+typedef int (*lxc_arguments_parser_t)(struct lxc_arguments *, int, char *);
+typedef int (*lxc_arguments_checker_t)(const struct lxc_arguments *);
 
 struct lxc_arguments {
        const char *help;
-       void(*helpfn)(const struct lxc_arguments *);
+       void (*helpfn)(const struct lxc_arguments *);
        const char *progname;
-       const struct optionoptions;
+       const struct option *options;
        lxc_arguments_parser_t parser;
        lxc_arguments_checker_t checker;
 
@@ -58,7 +58,7 @@ struct lxc_arguments {
        int lxcpath_additional;
 
        /* for lxc-start */
-       const char *share_ns[32]; // size must be greater than LXC_NS_MAX
+       const char *share_ns[32]; /* size must be greater than LXC_NS_MAX */
 
        /* for lxc-console */
        unsigned int ttynum;
@@ -143,29 +143,31 @@ struct lxc_arguments {
        void *data;
 };
 
-#define LXC_COMMON_OPTIONS \
-       {"name", required_argument, 0, 'n'}, \
-       {"help", no_argument, 0, 'h'}, \
-       {"usage", no_argument,  0, OPT_USAGE}, \
-       {"version", no_argument,        0, OPT_VERSION}, \
-       {"quiet", no_argument,  0, 'q'}, \
-       {"logfile", required_argument, 0, 'o'}, \
-       {"logpriority", required_argument, 0, 'l'}, \
-       {"lxcpath", required_argument, 0, 'P'}, \
-       {"rcfile", required_argument, 0, OPT_RCFILE}, \
-       {0, 0, 0, 0}
+#define LXC_COMMON_OPTIONS                                                     \
+           { "name",        required_argument, 0, 'n'         },              \
+            { "help",        no_argument,       0, 'h'         },              \
+           { "usage",       no_argument,       0, OPT_USAGE   },              \
+           { "version",     no_argument,       0, OPT_VERSION },              \
+           { "quiet",       no_argument,       0, 'q'         },              \
+           { "logfile",     required_argument, 0, 'o'         },              \
+           { "logpriority", required_argument, 0, 'l'         },              \
+           { "lxcpath",     required_argument, 0, 'P'         },              \
+           { "rcfile",      required_argument, 0, OPT_RCFILE  },              \
+           { 0,             0,                 0, 0           }
 
 /* option keys for long only options */
-#define        OPT_USAGE 0x1000
-#define        OPT_VERSION OPT_USAGE-1
-#define        OPT_RCFILE OPT_USAGE-2
+#define OPT_USAGE 0x1000
+#define OPT_VERSION OPT_USAGE - 1
+#define OPT_RCFILE OPT_USAGE - 2
 
-extern int lxc_arguments_parse(struct lxc_arguments *args,
-                              int argc, char *const argv[]);
+extern int lxc_arguments_parse(struct lxc_arguments *args, int argc,
+                              char *const argv[]);
 
-extern int lxc_arguments_str_to_int(struct lxc_arguments *args, const char *str);
+extern int lxc_arguments_str_to_int(struct lxc_arguments *args,
+                                   const char *str);
 
-#define lxc_error(arg, fmt, args...) if (!(arg)->quiet)                        \
-       fprintf(stderr, "%s: " fmt "\n", (arg)->progname,  ## args)
+#define lxc_error(arg, fmt, args...)                                           \
+       if (!(arg)->quiet)                                                     \
+       fprintf(stderr, "%s: " fmt "\n", (arg)->progname, ##args)
 
-#endif
+#endif /* __LXC_ARGUMENTS_H */
index 096a281cc9fb4c3cb112b3658f54769f016f1126..8a263f49015217d1b170bf9774c439b69ed06d18 100644 (file)
  */
 
 #define _GNU_SOURCE
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <signal.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <sys/mount.h>
 #include <sys/param.h>
 #include <sys/prctl.h>
-#include <sys/mount.h>
 #include <sys/socket.h>
 #include <sys/syscall.h>
 #include <sys/wait.h>
-#include <linux/unistd.h>
-#include <pwd.h>
+
+#include <lxc/lxccontainer.h>
 
 #ifndef HAVE_DECL_PR_CAPBSET_DROP
 #define PR_CAPBSET_DROP 24
 #define PR_GET_NO_NEW_PRIVS 39
 #endif
 
-#include "namespace.h"
-#include "log.h"
 #include "af_unix.h"
 #include "attach.h"
 #include "caps.h"
-#include "config.h"
-#include "utils.h"
-#include "commands.h"
 #include "cgroup.h"
-#include "lxclock.h"
+#include "commands.h"
 #include "conf.h"
-#include "lxcseccomp.h"
-#include <lxc/lxccontainer.h>
-#include "lsm/lsm.h"
+#include "config.h"
 #include "confile.h"
+#include "log.h"
+#include "lsm/lsm.h"
+#include "lxclock.h"
+#include "lxcseccomp.h"
+#include "namespace.h"
+#include "utils.h"
 
 #if HAVE_SYS_PERSONALITY_H
 #include <sys/personality.h>
 #endif
 
 #ifndef SOCK_CLOEXEC
-#  define SOCK_CLOEXEC                02000000
+#define SOCK_CLOEXEC 02000000
 #endif
 
 #ifndef MS_REC
@@ -80,7 +81,7 @@
 #endif
 
 #ifndef MS_SLAVE
-#define MS_SLAVE (1<<19)
+#define MS_SLAVE (1 << 19)
 #endif
 
 lxc_log_define(lxc_attach, lxc);
@@ -125,7 +126,7 @@ static int lsm_openat(int procfd, pid_t pid, int on_exec)
 static int lsm_set_label_at(int lsm_labelfd, int on_exec, char *lsm_label)
 {
        int fret = -1;
-       const charname;
+       const char *name;
        char *command = NULL;
 
        name = lsm_name();
@@ -143,7 +144,8 @@ static int lsm_set_label_at(int lsm_labelfd, int on_exec, char *lsm_label)
        if (strcmp(name, "AppArmor") == 0) {
                int size;
 
-               command = malloc(strlen(lsm_label) + strlen("changeprofile ") + 1);
+               command =
+                   malloc(strlen(lsm_label) + strlen("changeprofile ") + 1);
                if (!command) {
                        SYSERROR("Failed to write apparmor profile.");
                        goto out;
@@ -185,12 +187,12 @@ out:
 #define __PROC_STATUS_LEN (5 + (LXC_NUMSTRLEN64) + 7 + 1)
 static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
 {
+       int ret;
+       bool found;
        FILE *proc_file;
        char proc_fn[__PROC_STATUS_LEN];
-       bool found;
-       int ret;
-       char *line = NULL;
        size_t line_bufsz = 0;
+       char *line = NULL;
        struct lxc_proc_context_info *info = NULL;
 
        /* Read capabilities. */
@@ -224,7 +226,8 @@ static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
        fclose(proc_file);
 
        if (!found) {
-               SYSERROR("Could not read capability bounding set from %s.", proc_fn);
+               SYSERROR("Could not read capability bounding set from %s.",
+                        proc_fn);
                errno = ENOENT;
                goto on_error;
        }
@@ -251,7 +254,6 @@ static int lxc_attach_to_ns(pid_t pid, int which)
        int fd[LXC_NS_MAX];
        int i, j, saved_errno;
 
-
        if (access("/proc/self/ns", X_OK)) {
                ERROR("Does this kernel version support namespaces?");
                return -1;
@@ -275,7 +277,8 @@ static int lxc_attach_to_ns(pid_t pid, int which)
                                close(fd[j]);
 
                        errno = saved_errno;
-                       SYSERROR("Failed to open namespace: \"%s\".", ns_info[i].proc_name);
+                       SYSERROR("Failed to open namespace: \"%s\".",
+                                ns_info[i].proc_name);
                        return -1;
                }
        }
@@ -291,7 +294,8 @@ static int lxc_attach_to_ns(pid_t pid, int which)
                                close(fd[j]);
 
                        errno = saved_errno;
-                       SYSERROR("Failed to attach to namespace \"%s\".", ns_info[i].proc_name);
+                       SYSERROR("Failed to attach to namespace \"%s\".",
+                                ns_info[i].proc_name);
                        return -1;
                }
 
@@ -314,7 +318,7 @@ static int lxc_attach_remount_sys_proc(void)
        }
 
        if (detect_shared_rootfs()) {
-               if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
+               if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) {
                        SYSERROR("Failed to make / rslave.");
                        ERROR("Continuing...");
                }
@@ -354,9 +358,9 @@ static int lxc_attach_remount_sys_proc(void)
 
 static int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
 {
-       int last_cap = lxc_caps_last_cap();
-       int cap;
+       int cap, last_cap;
 
+       last_cap = lxc_caps_last_cap();
        for (cap = 0; cap <= last_cap; cap++) {
                if (ctx->capability_mask & (1LL << cap))
                        continue;
@@ -370,11 +374,12 @@ static int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
        return 0;
 }
 
-static int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char** extra_env, char** extra_keep)
+static int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy,
+                                     char **extra_env, char **extra_keep)
 {
        if (policy == LXC_ATTACH_CLEAR_ENV) {
-               char **extra_keep_store = NULL;
                int path_kept = 0;
+               char **extra_keep_store = NULL;
 
                if (extra_keep) {
                        size_t count, i;
@@ -410,6 +415,7 @@ static int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char*
 
                if (clearenv()) {
                        char **p;
+
                        SYSERROR("Failed to clear environment.");
                        if (extra_keep_store) {
                                for (p = extra_keep_store; *p; p++)
@@ -421,6 +427,7 @@ static int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char*
 
                if (extra_keep_store) {
                        size_t i;
+
                        for (i = 0; extra_keep[i]; i++) {
                                if (extra_keep_store[i]) {
                                        if (setenv(extra_keep[i], extra_keep_store[i], 1) < 0)
@@ -469,10 +476,9 @@ static int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char*
 
 static char *lxc_attach_getpwshell(uid_t uid)
 {
+       int fd, ret;
        pid_t pid;
        int pipes[2];
-       int ret;
-       int fd;
        char *result = NULL;
 
        /* We need to fork off a process that runs the getent program, and we
@@ -490,21 +496,20 @@ static char *lxc_attach_getpwshell(uid_t uid)
        }
 
        if (pid) {
+               int status;
                FILE *pipe_f;
-               char *line = NULL;
-               size_t line_bufsz = 0;
                int found = 0;
-               int status;
+               size_t line_bufsz = 0;
+               char *line = NULL;
 
                close(pipes[1]);
 
                pipe_f = fdopen(pipes[0], "r");
                while (getline(&line, &line_bufsz, pipe_f) != -1) {
-                       char *token;
-                       char *saveptr = NULL;
-                       long value;
-                       char *endptr = NULL;
                        int i;
+                       long value;
+                       char *token;
+                       char *endptr = NULL, *saveptr = NULL;
 
                        /* If we already found something, just continue to read
                         * until the pipe doesn't deliver any more data, but
@@ -615,7 +620,7 @@ static char *lxc_attach_getpwshell(uid_t uid)
        }
 }
 
-static void lxc_attach_get_init_uidgid(uid_t* init_uid, gid_t* init_gid)
+static void lxc_attach_get_init_uidgid(uid_t *init_uid, gid_t *init_gid)
 {
        FILE *proc_file;
        char proc_fn[__PROC_STATUS_LEN];
@@ -639,11 +644,11 @@ static void lxc_attach_get_init_uidgid(uid_t* init_uid, gid_t* init_gid)
                 */
                ret = sscanf(line, "Uid: %ld", &value);
                if (ret != EOF && ret == 1) {
-                       uid = (uid_t) value;
+                       uid = (uid_t)value;
                } else {
                        ret = sscanf(line, "Gid: %ld", &value);
                        if (ret != EOF && ret == 1)
-                               gid = (gid_t) value;
+                               gid = (gid_t)value;
                }
                if (uid != (uid_t)-1 && gid != (gid_t)-1)
                        break;
@@ -665,16 +670,21 @@ static void lxc_attach_get_init_uidgid(uid_t* init_uid, gid_t* init_gid)
 
 struct attach_clone_payload {
        int ipc_socket;
-       lxc_attach_options_toptions;
-       struct lxc_proc_context_infoinit_ctx;
+       lxc_attach_options_t *options;
+       struct lxc_proc_context_info *init_ctx;
        lxc_attach_exec_t exec_function;
-       voidexec_payload;
+       void *exec_payload;
 };
 
 static int attach_child_main(void* data);
 
 /* Help the optimizer along if it doesn't know that exit always exits. */
-#define rexit(c)  do { int __c = (c); _exit(__c); return __c; } while(0)
+#define rexit(c)                                                               \
+       do {                                                                   \
+               int __c = (c);                                                 \
+               _exit(__c);                                                    \
+               return __c;                                                    \
+       } while (0)
 
 /* Define default options if no options are supplied by the user. */
 static lxc_attach_options_t attach_static_default_options = LXC_ATTACH_OPTIONS_DEFAULT;
@@ -684,7 +694,8 @@ static bool fetch_seccomp(struct lxc_container *c,
 {
        char *path;
 
-       if (!(options->namespaces & CLONE_NEWNS) || !(options->attach_flags & LXC_ATTACH_LSM)) {
+       if (!(options->namespaces & CLONE_NEWNS) ||
+           !(options->attach_flags & LXC_ATTACH_LSM)) {
                free(c->lxc_conf->seccomp);
                c->lxc_conf->seccomp = NULL;
                return true;
@@ -724,15 +735,13 @@ static bool fetch_seccomp(struct lxc_container *c,
        return true;
 }
 
-static bool no_new_privs(struct lxc_container *c,
-                        lxc_attach_options_t *options)
+static bool no_new_privs(struct lxc_container *c, lxc_attach_options_t *options)
 {
        char *val;
 
        /* Remove current setting. */
-       if (!c->set_config_item(c, "lxc.no_new_privs", "")) {
+       if (!c->set_config_item(c, "lxc.no_new_privs", ""))
                return false;
-       }
 
        /* Retrieve currently active setting. */
        val = c->get_running_config_item(c, "lxc.no_new_privs");
@@ -753,25 +762,29 @@ static bool no_new_privs(struct lxc_container *c,
 
 static signed long get_personality(const char *name, const char *lxcpath)
 {
-       char *p = lxc_cmd_get_config_item(name, "lxc.arch", lxcpath);
+       char *p;
        signed long ret;
 
+       p = lxc_cmd_get_config_item(name, "lxc.arch", lxcpath);
        if (!p)
                return -1;
+
        ret = lxc_config_parse_arch(p);
        free(p);
+
        return ret;
 }
 
-int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_function, void* exec_payload, lxc_attach_options_t* options, pid_t* attached_process)
+int lxc_attach(const char *name, const char *lxcpath,
+              lxc_attach_exec_t exec_function, void *exec_payload,
+              lxc_attach_options_t *options, pid_t *attached_process)
 {
        int ret, status;
-       pid_t init_pid, pid, attached_pid, expected;
-       struct lxc_proc_context_info *init_ctx;
-       char* cwd;
-       char* new_cwd;
        int ipc_sockets[2];
+       char *cwd, *new_cwd;
        signed long personality;
+       pid_t attached_pid, expected, init_pid, pid;
+       struct lxc_proc_context_info *init_ctx;
 
        if (!options)
                options = &attach_static_default_options;
@@ -784,14 +797,13 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
 
        init_ctx = lxc_proc_get_context_info(init_pid);
        if (!init_ctx) {
-               ERROR("Failed to get context of init process: %ld.",
-                     (long)init_pid);
+               ERROR("Failed to get context of init process: %ld", (long)init_pid);
                return -1;
        }
 
        personality = get_personality(name, lxcpath);
        if (init_ctx->personality < 0) {
-               ERROR("Failed to get personality of the container.");
+               ERROR("Failed to get personality of the container");
                lxc_proc_put_context_info(init_ctx);
                return -1;
        }
@@ -876,7 +888,6 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
         *          setns() (otherwise, user namespaces will hate us).
         */
        pid = fork();
-
        if (pid < 0) {
                SYSERROR("Failed to create first subprocess.");
                free(cwd);
@@ -901,9 +912,9 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
                }
 
                /* Setup resource limits */
-               if (!lxc_list_empty(&init_ctx->container->lxc_conf->limits) && setup_resource_limits(&init_ctx->container->lxc_conf->limits, pid)) {
-                       goto on_error;
-               }
+               if (!lxc_list_empty(&init_ctx->container->lxc_conf->limits))
+                       if (setup_resource_limits(&init_ctx->container->lxc_conf->limits, pid) < 0)
+                               goto on_error;
 
                /* Open /proc before setns() to the containers namespace so we
                 * don't rely on any information from inside the container.
@@ -924,7 +935,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
                }
 
                /* Get pid of attached process from intermediate process. */
-               ret = lxc_read_nointr_expect(ipc_sockets[0], &attached_pid, sizeof(attached_pid), NULL);
+               ret = lxc_read_nointr_expect(ipc_sockets[0], &attached_pid,
+                                            sizeof(attached_pid), NULL);
                if (ret <= 0) {
                        if (ret != 0)
                                ERROR("Expected to receive pid: %s.", strerror(errno));
@@ -955,7 +967,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
 
                /* Wait for the attached process to finish initializing. */
                expected = 1;
-               ret = lxc_read_nointr_expect(ipc_sockets[0], &status, sizeof(status), &expected);
+               ret = lxc_read_nointr_expect(ipc_sockets[0], &status,
+                                            sizeof(status), &expected);
                if (ret <= 0) {
                        if (ret != 0)
                                ERROR("Expected to receive sequence number 1: %s.", strerror(errno));
@@ -974,7 +987,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
                 * up its LSM labels.
                 */
                expected = 3;
-               ret = lxc_read_nointr_expect(ipc_sockets[0], &status, sizeof(status), &expected);
+               ret = lxc_read_nointr_expect(ipc_sockets[0], &status,
+                                            sizeof(status), &expected);
                if (ret <= 0) {
                        ERROR("Expected to receive sequence number 3: %s.",
                              strerror(errno));
@@ -982,9 +996,12 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
                }
 
                /* Open LSM fd and send it to child. */
-               if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) {
+               if ((options->namespaces & CLONE_NEWNS) &&
+                   (options->attach_flags & LXC_ATTACH_LSM) &&
+                   init_ctx->lsm_label) {
                        int on_exec, saved_errno;
                        int labelfd = -1;
+
                        on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
                        /* Open fd for the LSM security module. */
                        labelfd = lsm_openat(procfd, attached_pid, on_exec);
@@ -1025,7 +1042,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
                shutdown(ipc_sockets[0], SHUT_RDWR);
                close(ipc_sockets[0]);
                if (to_cleanup_pid)
-                       (void) wait_for_pid(to_cleanup_pid);
+                       (void)wait_for_pid(to_cleanup_pid);
                lxc_proc_put_context_info(init_ctx);
                return -1;
        }
@@ -1038,7 +1055,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
        /* Wait for the parent to have setup cgroups. */
        expected = 0;
        status = -1;
-       ret = lxc_read_nointr_expect(ipc_sockets[1], &status, sizeof(status), &expected);
+       ret = lxc_read_nointr_expect(ipc_sockets[1], &status, sizeof(status),
+                                    &expected);
        if (ret <= 0) {
                ERROR("Expected to receive sequence number 0: %s.", strerror(errno));
                shutdown(ipc_sockets[1], SHUT_RDWR);
@@ -1112,21 +1130,17 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
 
 static int attach_child_main(void* data)
 {
-       struct attach_clone_payload* payload = (struct attach_clone_payload*)data;
-       int ipc_socket = payload->ipc_socket;
-       lxc_attach_options_t* options = payload->options;
-       struct lxc_proc_context_info* init_ctx = payload->init_ctx;
+       int expected, fd, lsm_labelfd, ret, status;
+       long flags;
 #if HAVE_SYS_PERSONALITY_H
        long new_personality;
 #endif
-       int ret;
-       int status;
-       int expected;
-       long flags;
-       int fd;
-       int lsm_labelfd;
        uid_t new_uid;
        gid_t new_gid;
+       struct attach_clone_payload* payload = (struct attach_clone_payload*)data;
+       int ipc_socket = payload->ipc_socket;
+       lxc_attach_options_t* options = payload->options;
+       struct lxc_proc_context_info* init_ctx = payload->init_ctx;
 
        /* Wait for the initial thread to signal us that it's ready for us to
         * start initializing.
@@ -1145,7 +1159,8 @@ static int attach_child_main(void* data)
         * parent process, otherwise /proc may not properly reflect the new pid
         * namespace.
         */
-       if (!(options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_REMOUNT_PROC_SYS)) {
+       if (!(options->namespaces & CLONE_NEWNS) &&
+           (options->attach_flags & LXC_ATTACH_REMOUNT_PROC_SYS)) {
                ret = lxc_attach_remount_sys_proc();
                if (ret < 0) {
                        shutdown(ipc_socket, SHUT_RDWR);
@@ -1182,7 +1197,9 @@ static int attach_child_main(void* data)
        /* Always set the environment (specify (LXC_ATTACH_KEEP_ENV, NULL, NULL)
         * if you want this to be a no-op).
         */
-       ret = lxc_attach_set_environment(options->env_policy, options->extra_env_vars, options->extra_keep_env);
+       ret = lxc_attach_set_environment(options->env_policy,
+                                        options->extra_env_vars,
+                                        options->extra_keep_env);
        if (ret < 0) {
                ERROR("Could not set initial environment for attached process.");
                shutdown(ipc_socket, SHUT_RDWR);
@@ -1226,7 +1243,8 @@ static int attach_child_main(void* data)
                        rexit(-1);
                }
        }
-       if ((new_uid != 0 || options->namespaces & CLONE_NEWUSER) && setuid(new_uid)) {
+       if ((new_uid != 0 || options->namespaces & CLONE_NEWUSER) &&
+           setuid(new_uid)) {
                SYSERROR("Switching to container uid.");
                shutdown(ipc_socket, SHUT_RDWR);
                rexit(-1);
@@ -1276,7 +1294,8 @@ static int attach_child_main(void* data)
                rexit(-1);
        }
 
-       if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) {
+       if ((options->namespaces & CLONE_NEWNS) &&
+           (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) {
                int on_exec;
                /* Receive fd for LSM security module. */
                ret = lxc_abstract_unix_recv_fds(ipc_socket, &lsm_labelfd, 1, NULL, 0);
index 39fcab783b9ff65d1415db57a4a326911859eeb2..fb6bc5a079030e8ca7155ed63a9a48868ae7b6e3 100644 (file)
@@ -24,8 +24,8 @@
 #ifndef __LXC_ATTACH_H
 #define __LXC_ATTACH_H
 
-#include <sys/types.h>
 #include <lxc/attach_options.h>
+#include <sys/types.h>
 
 struct lxc_conf;
 
@@ -36,6 +36,8 @@ struct lxc_proc_context_info {
        unsigned long long capability_mask;
 };
 
-extern int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_function, void* exec_payload, lxc_attach_options_t* options, pid_t* attached_process);
+extern int lxc_attach(const char *name, const char *lxcpath,
+                     lxc_attach_exec_t exec_function, void *exec_payload,
+                     lxc_attach_options_t *options, pid_t *attached_process);
 
-#endif
+#endif /* __LXC_ATTACH_H */
index 1df69924c2b6eb8db1caea3276de12153a73b556..7055f7a1f4ff390417bc5bcc607745964b451588 100644 (file)
@@ -35,29 +35,28 @@ extern "C" {
  * LXC environment policy.
  */
 typedef enum lxc_attach_env_policy_t {
-       LXC_ATTACH_KEEP_ENV,   //!< Retain the environment
-       LXC_ATTACH_CLEAR_ENV   //!< Clear the environment
+       LXC_ATTACH_KEEP_ENV,   /*!< Retain the environment */
+       LXC_ATTACH_CLEAR_ENV   /*!< Clear the environment */
 } lxc_attach_env_policy_t;
 
 enum {
-       /* the following are on by default: */
-       LXC_ATTACH_MOVE_TO_CGROUP        = 0x00000001, //!< Move to cgroup
-       LXC_ATTACH_DROP_CAPABILITIES     = 0x00000002, //!< Drop capabilities
-       LXC_ATTACH_SET_PERSONALITY       = 0x00000004, //!< Set personality
-       LXC_ATTACH_LSM_EXEC              = 0x00000008, //!< Execute under a Linux Security Module
-
-       /* the following are off by default */
-       LXC_ATTACH_REMOUNT_PROC_SYS      = 0x00010000, //!< Remount /proc filesystem
-       LXC_ATTACH_LSM_NOW               = 0x00020000, //!< FIXME: unknown
+       /* The following are on by default: */
+       LXC_ATTACH_MOVE_TO_CGROUP        = 0x00000001, /*!< Move to cgroup */
+       LXC_ATTACH_DROP_CAPABILITIES     = 0x00000002, /*!< Drop capabilities */
+       LXC_ATTACH_SET_PERSONALITY       = 0x00000004, /*!< Set personality */
+       LXC_ATTACH_LSM_EXEC              = 0x00000008, /*!< Execute under a Linux Security Module */
+
+       /* The following are off by default: */
+       LXC_ATTACH_REMOUNT_PROC_SYS      = 0x00010000, /*!< Remount /proc filesystem */
+       LXC_ATTACH_LSM_NOW               = 0x00020000, /*!< FIXME: unknown */
        /* Set PR_SET_NO_NEW_PRIVS to block execve() gainable privileges. */
-       LXC_ATTACH_NO_NEW_PRIVS          = 0x00040000, //!< PR_SET_NO_NEW_PRIVS
+       LXC_ATTACH_NO_NEW_PRIVS          = 0x00040000, /*!< PR_SET_NO_NEW_PRIVS */
 
-       /* we have 16 bits for things that are on by default
-        * and 16 bits that are off by default, that should
-        * be sufficient to keep binary compatibility for
-        * a while
+       /* We have 16 bits for things that are on by default and 16 bits that
+        * are off by default, that should be sufficient to keep binary
+        * compatibility for a while
         */
-       LXC_ATTACH_DEFAULT               = 0x0000FFFF  //!< Mask of flags to apply by default
+       LXC_ATTACH_DEFAULT               = 0x0000FFFF  /*!< Mask of flags to apply by default */
 };
 
 /*! All Linux Security Module flags */
@@ -84,13 +83,14 @@ typedef struct lxc_attach_options_t {
        int namespaces;
 
        /*! Initial personality (\c -1 to autodetect).
-        * \warning This may be ignored if lxc is compiled without personality support)
+        * \warning This may be ignored if lxc is compiled without personality
+        * support)
         */
        long personality;
 
        /*! Initial current directory, use \c NULL to use cwd.
-        * If the current directory does not exist in the container, the
-        * root directory will be used instead because of kernel defaults.
+        * If the current directory does not exist in the container, the root
+        * directory will be used instead because of kernel defaults.
         */
        char* initial_cwd;
 
@@ -134,18 +134,18 @@ typedef struct lxc_attach_options_t {
 } lxc_attach_options_t;
 
 /*! Default attach options to use */
-#define LXC_ATTACH_OPTIONS_DEFAULT \
-       { \
-               /* .attach_flags = */   LXC_ATTACH_DEFAULT, \
-               /* .namespaces = */     -1, \
-               /* .personality = */    -1, \
-               /* .initial_cwd = */    NULL, \
-               /* .uid = */            (uid_t)-1, \
-               /* .gid = */            (gid_t)-1, \
-               /* .env_policy = */     LXC_ATTACH_KEEP_ENV, \
-               /* .extra_env_vars = */ NULL, \
-               /* .extra_keep_env = */ NULL, \
-               /* .stdin_fd = */       0, 1, 2 \
+#define LXC_ATTACH_OPTIONS_DEFAULT                                             \
+       {                                                                      \
+               /* .attach_flags = */   LXC_ATTACH_DEFAULT,                    \
+               /* .namespaces = */     -1,                                    \
+               /* .personality = */    -1,                                    \
+               /* .initial_cwd = */    NULL,                                  \
+               /* .uid = */            (uid_t)-1,                             \
+               /* .gid = */            (gid_t)-1,                             \
+               /* .env_policy = */     LXC_ATTACH_KEEP_ENV,                   \
+               /* .extra_env_vars = */ NULL,                                  \
+               /* .extra_keep_env = */ NULL,                                  \
+               /* .stdin_fd = */       0, 1, 2                                \
        }
 
 /*!
diff --git a/src/lxc/bdev/bdev.c b/src/lxc/bdev/bdev.c
deleted file mode 100644 (file)
index 1bc8afc..0000000
+++ /dev/null
@@ -1,627 +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 <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 "storage_utils.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 = "dir",       .ops = &dir_ops,   },
-       { .name = "zfs",       .ops = &zfs_ops,   },
-       { .name = "lvm",       .ops = &lvm_ops,   },
-       { .name = "rbd",       .ops = &rbd_ops,   },
-       { .name = "btrfs",     .ops = &btrfs_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);
-
-static const struct bdev_type *get_bdev_by_name(const char *name)
-{
-       size_t i, cmplen;
-
-       cmplen = strcspn(name, ":");
-       if (cmplen == 0)
-               return NULL;
-
-       for (i = 0; i < numbdevs; i++)
-               if (strncmp(bdevs[i].name, name, cmplen) == 0)
-                       break;
-
-       if (i == numbdevs)
-               return NULL;
-
-       DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
-       return &bdevs[i];
-}
-
-const struct bdev_type *bdev_query(struct lxc_conf *conf, const char *src)
-{
-       size_t i;
-       const struct bdev_type *bdev;
-
-       bdev = get_bdev_by_name(src);
-       if (bdev)
-               return bdev;
-
-       for (i = 0; i < numbdevs; i++)
-               if (bdevs[i].ops->detect(src))
-                       break;
-
-       if (i == numbdevs)
-               return NULL;
-
-       DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
-       return &bdevs[i];
-}
-
-struct bdev *bdev_get(const char *type)
-{
-       size_t 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 struct bdev *do_bdev_create(const char *dest, const char *type,
-                                  const char *cname, struct bdev_specs *specs)
-{
-
-       struct bdev *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;
-}
-
-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;
-       char *src_no_prefix;
-       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;
-       }
-
-       src_no_prefix = lxc_storage_get_path(new->src, new->type);
-
-       if (am_unpriv() && chown_mapped_root(src_no_prefix, 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,
-                                   "rsync_rootfs_wrapper");
-       else
-               ret = rsync_rootfs(&data);
-       if (ret < 0)
-               ERROR("Failed to rsync");
-
-       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;
-}
-
-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);
-}
-
-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;
-}
-
-char *lxc_storage_get_path(char *src, const char *prefix)
-{
-       size_t prefix_len;
-
-       prefix_len = strlen(prefix);
-       if (!strncmp(src, prefix, prefix_len) && (*(src + prefix_len) == ':'))
-               return (src + prefix_len + 1);
-
-       return src;
-}
diff --git a/src/lxc/bdev/bdev.h b/src/lxc/bdev/bdev.h
deleted file mode 100644 (file)
index 2213317..0000000
+++ /dev/null
@@ -1,130 +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
- */
-
-#ifndef __LXC_BDEV_H
-#define __LXC_BDEV_H
-
-#include "config.h"
-#include <stdint.h>
-#include <sys/mount.h>
-
-#include <lxc/lxccontainer.h>
-
-#ifndef MS_DIRSYNC
-#define MS_DIRSYNC 128
-#endif
-
-#ifndef MS_REC
-#define MS_REC 16384
-#endif
-
-#ifndef MNT_DETACH
-#define MNT_DETACH 2
-#endif
-
-#ifndef MS_SLAVE
-#define MS_SLAVE (1 << 19)
-#endif
-
-#ifndef MS_RELATIME
-#define MS_RELATIME (1 << 21)
-#endif
-
-#ifndef MS_STRICTATIME
-#define MS_STRICTATIME (1 << 24)
-#endif
-
-#define DEFAULT_FS_SIZE 1073741824
-#define DEFAULT_FSTYPE "ext3"
-
-struct bdev;
-
-struct bdev_ops {
-       /* detect whether path is of this bdev type */
-       int (*detect)(const char *path);
-       // mount requires src and dest to be set.
-       int (*mount)(struct bdev *bdev);
-       int (*umount)(struct bdev *bdev);
-       int (*destroy)(struct bdev *bdev);
-       int (*create)(struct bdev *bdev, const char *dest, const char *n,
-                     struct bdev_specs *specs);
-       /* given original mount, rename the paths for cloned container */
-       int (*clone_paths)(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);
-       bool can_snapshot;
-       bool can_backup;
-};
-
-/*
- * When lxc-start is mounting a rootfs, then src will be the "lxc.rootfs" value,
- * dest will be mount dir (i.e. $libdir/lxc)  When clone or create is doing so,
- * then dest will be $lxcpath/$lxcname/rootfs, since we may need to rsync from
- * one to the other.
- * data is so far unused.
- */
-struct bdev {
-       const struct bdev_ops *ops;
-       const char *type;
-       char *src;
-       char *dest;
-       char *mntopts;
-       /* Turn the following into a union if need be. */
-       /* lofd is the open fd for the mounted loopback file. */
-       int lofd;
-       /* index for the connected nbd device. */
-       int nbd_idx;
-};
-
-bool bdev_is_dir(struct lxc_conf *conf, const char *path);
-bool bdev_can_backup(struct lxc_conf *conf);
-
-/*
- * Instantiate a bdev object. The src is used to determine which blockdev type
- * this should be. The dst and data are optional, and will be used in case of
- * mount/umount.
- *
- * Optionally, src can be 'dir:/var/lib/lxc/c1' or 'lvm:/dev/lxc/c1'.  For
- * other backing stores, this will allow additional options. In particular,
- * "overlayfs:/var/lib/lxc/canonical/rootfs:/var/lib/lxc/c1/delta" will mean
- * use /var/lib/lxc/canonical/rootfs as lower dir, and /var/lib/lxc/c1/delta
- * as the upper, writeable layer.
- */
-struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst,
-                      const char *data);
-
-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 *bdev_create(const char *dest, const char *type, const char *cname,
-                        struct bdev_specs *specs);
-void bdev_put(struct bdev *bdev);
-bool bdev_destroy(struct lxc_conf *conf);
-
-/* callback function to be used with userns_exec_1() */
-int bdev_destroy_wrapper(void *data);
-extern bool rootfs_is_blockdev(struct lxc_conf *conf);
-extern char *lxc_storage_get_path(char *src, const char *prefix);
-
-#endif // __LXC_BDEV_H
diff --git a/src/lxc/bdev/lxcaufs.c b/src/lxc/bdev/lxcaufs.c
deleted file mode 100644 (file)
index 481b62f..0000000
+++ /dev/null
@@ -1,422 +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
- */
-
-#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,
-                                           "rsync_delta_wrapper");
-               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))
-               return 1;
-
-       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
deleted file mode 100644 (file)
index fa623f7..0000000
+++ /dev/null
@@ -1,73 +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
- */
-
-#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
deleted file mode 100644 (file)
index 1defa76..0000000
+++ /dev/null
@@ -1,789 +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
- */
-
-#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 <sys/vfs.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("Failed to lookup path for %llu %llu %s - %s\n",
-                                (unsigned long long) dir_id,
-                                (unsigned long long) objid,
-                                name, strerror(e));
-               return NULL;
-       } else
-               INFO("Got path for %llu %llu - %s\n",
-                       (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;
-}
-
-/*
- * Taken from btrfs toolsuite. Test if path is a subvolume.
- *     return 0;   path exists but it is not a subvolume
- *     return 1;   path exists and it is  a subvolume
- *     return < 0; error
- */
-int is_btrfs_subvol(const char *path)
-{
-       struct stat st;
-       struct statfs stfs;
-       int ret;
-
-       ret = stat(path, &st);
-       if (ret < 0)
-               return -errno;
-
-       if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode))
-               return 0;
-
-       ret = statfs(path, &stfs);
-       if (ret < 0)
-               return -errno;
-
-       return stfs.f_type == BTRFS_SUPER_MAGIC;
-}
-
-int btrfs_detect(const char *path)
-{
-       struct stat st;
-       int ret;
-
-       if (!strncmp(path, "btrfs:", 6))
-               return 1;
-
-       if (!is_btrfs_fs(path))
-               return 0;
-
-       /* 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, *src;
-       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;
-       }
-
-       src = lxc_storage_get_path(bdev->src, "btrfs");
-
-       ret = mount(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)
-{
-       char *src;
-       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;
-       }
-
-       src = lxc_storage_get_path(arg->src, "btrfs");
-
-       return btrfs_snapshot(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)
-{
-       char *src;
-
-       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") + 6 + 3;
-               new->src = malloc(len);
-               if (!new->src)
-                       return -1;
-
-               ret = snprintf(new->src, len, "btrfs:%s/%s/rootfs", lxcpath, cname);
-               if (ret < 0 || ret >= len)
-                       return -1;
-       } else {
-               /* In case rootfs is in custom path, reuse it. */
-               new->src = dir_new_path(orig->src, oldname, cname, oldpath, lxcpath);
-               if (!new->src)
-                       return -1;
-
-       }
-
-       src = lxc_storage_get_path(new->src, "btrfs");
-       new->dest = strdup(src);
-       if (!new->dest)
-               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,
-                                    "btrfs_snapshot_wrapper");
-       }
-
-       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)
-{
-       char *src;
-
-       src = lxc_storage_get_path(orig->src, "btrfs");
-
-       return btrfs_recursive_destroy(src);
-}
-
-int btrfs_create(struct bdev *bdev, const char *dest, const char *n,
-                struct bdev_specs *specs)
-{
-       int ret;
-       size_t len;
-
-       len = strlen(dest) + 1;
-       /* strlen("btrfs:") */
-       len += 6;
-       bdev->src = malloc(len);
-       if (!bdev->src)
-               return -1;
-
-       ret = snprintf(bdev->src, len, "btrfs:%s", dest);
-       if (ret < 0 || (size_t)ret >= len)
-               return -1;
-
-       bdev->dest = strdup(dest);
-       if (!bdev->dest)
-               return -1;
-
-       return btrfs_subvolume_create(bdev->dest);
-}
diff --git a/src/lxc/bdev/lxcbtrfs.h b/src/lxc/bdev/lxcbtrfs.h
deleted file mode 100644 (file)
index ebd8421..0000000
+++ /dev/null
@@ -1,416 +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
- */
-
-#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>
-
-#ifndef BTRFS_SUPER_MAGIC
-#  define BTRFS_SUPER_MAGIC       0x9123683E
-#endif
-
-typedef uint8_t u8;
-typedef uint16_t u16;
-typedef uint32_t u32;
-typedef uint64_t u64;
-
-struct btrfs_ioctl_space_info {
-       unsigned long long flags;
-       unsigned long long total_bytes;
-       unsigned long long used_bytes;
-};
-
-struct btrfs_ioctl_space_args {
-       unsigned long long space_slots;
-       unsigned long long total_spaces;
-       struct btrfs_ioctl_space_info spaces[];
-};
-
-#define BTRFS_IOCTL_MAGIC 0x94
-#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, unsigned long long)
-#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
-                                    struct btrfs_ioctl_space_args)
-
-#define BTRFS_FSID_SIZE 16
-struct btrfs_ioctl_fs_info_args {
-       unsigned long long max_id;
-       unsigned long long num_devices;
-       char fsid[BTRFS_FSID_SIZE];
-       unsigned long long reserved[124];
-};
-
-#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
-               struct btrfs_ioctl_fs_info_args)
-
-
-#define BTRFS_SUBVOL_NAME_MAX 4039
-#define BTRFS_PATH_NAME_MAX 4087
-
-struct btrfs_ioctl_vol_args {
-       signed long long fd;
-       char name[BTRFS_PATH_NAME_MAX + 1];
-};
-
-#define BTRFS_IOCTL_MAGIC 0x94
-#define BTRFS_IOC_SUBVOL_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 24, \
-                                   struct btrfs_ioctl_vol_args_v2)
-#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
-                                   struct btrfs_ioctl_vol_args_v2)
-#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
-                                   struct btrfs_ioctl_vol_args)
-#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
-                                   struct btrfs_ioctl_vol_args)
-
-#define BTRFS_QGROUP_INHERIT_SET_LIMITS (1ULL << 0)
-
-struct btrfs_ioctl_vol_args_v2 {
-       signed long long fd;
-       unsigned long long transid;
-       unsigned long long flags;
-       union {
-               struct {
-                       unsigned long long size;
-                       //struct btrfs_qgroup_inherit *qgroup_inherit;
-                       void *qgroup_inherit;
-               };
-               unsigned long long unused[4];
-       };
-       char name[BTRFS_SUBVOL_NAME_MAX + 1];
-};
-
-/*
- * root backrefs tie subvols and snapshots to the directory entries that
- * reference them
- */
-#define BTRFS_ROOT_BACKREF_KEY  144
-
-/*
- * root items point to tree roots.  There are typically in the root
- * tree used by the super block to find all the other trees
- */
-#define BTRFS_ROOT_ITEM_KEY     132
-
-/*
- * root refs make a fast index for listing all of the snapshots and
- * subvolumes referenced by a given root.  They point directly to the
- * directory item in the root that references the subvol
- */
-#define BTRFS_ROOT_REF_KEY      156
-
-#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL
-#define BTRFS_DIR_ITEM_KEY      84
-
-/*
- *  * this is used for both forward and backward root refs
- *   */
-struct btrfs_root_ref {
-       __le64 dirid;
-       __le64 sequence;
-       __le16 name_len;
-} __attribute__ ((__packed__));
-
-struct btrfs_disk_key {
-       __le64 objectid;
-       u8 type;
-       __le64 offset;
-} __attribute__ ((__packed__));
-
-struct btrfs_dir_item {
-       struct btrfs_disk_key location;
-       __le64 transid;
-       __le16 data_len;
-       __le16 name_len;
-       u8 type;
-} __attribute__ ((__packed__));
-
-#define BTRFS_IOCTL_MAGIC 0x94
-#define BTRFS_VOL_NAME_MAX 255
-#define BTRFS_PATH_NAME_MAX 4087
-
-struct btrfs_ioctl_search_key {
-       /* which root are we searching.  0 is the tree of tree roots */
-       __u64 tree_id;
-
-       /* keys returned will be >= min and <= max */
-       __u64 min_objectid;
-       __u64 max_objectid;
-
-       /* keys returned will be >= min and <= max */
-       __u64 min_offset;
-       __u64 max_offset;
-
-       /* max and min transids to search for */
-       __u64 min_transid;
-       __u64 max_transid;
-
-       /* keys returned will be >= min and <= max */
-       __u32 min_type;
-       __u32 max_type;
-
-       /*
-        * how many items did userland ask for, and how many are we
-        * returning
-        */
-       __u32 nr_items;
-
-       /* align to 64 bits */
-       __u32 unused;
-
-       /* some extra for later */
-       __u64 unused1;
-       __u64 unused2;
-       __u64 unused3;
-       __u64 unused4;
-};
-
-struct btrfs_ioctl_search_header {
-       __u64 transid;
-       __u64 objectid;
-       __u64 offset;
-       __u32 type;
-       __u32 len;
-} __attribute__((may_alias));
-
-#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
-/*
- * the buf is an array of search headers where
- * each header is followed by the actual item
- * the type field is expanded to 32 bits for alignment
- */
-struct btrfs_ioctl_search_args {
-       struct btrfs_ioctl_search_key key;
-       char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
-};
-
-#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
-                                   struct btrfs_ioctl_search_args)
-#define BTRFS_UUID_SIZE 16
-
-struct btrfs_timespec {
-       __le64 sec;
-       __le32 nsec;
-} __attribute__ ((__packed__));
-
-struct btrfs_inode_item {
-       /* nfs style generation number */
-       __le64 generation;
-       /* transid that last touched this inode */
-       __le64 transid;
-       __le64 size;
-       __le64 nbytes;
-       __le64 block_group;
-       __le32 nlink;
-       __le32 uid;
-       __le32 gid;
-       __le32 mode;
-       __le64 rdev;
-       __le64 flags;
-
-       /* modification sequence number for NFS */
-       __le64 sequence;
-
-       /*
-        * a little future expansion, for more than this we can
-        * just grow the inode item and version it
-        */
-       __le64 reserved[4];
-       struct btrfs_timespec atime;
-       struct btrfs_timespec ctime;
-       struct btrfs_timespec mtime;
-       struct btrfs_timespec otime;
-} __attribute__ ((__packed__));
-
-struct btrfs_root_item_v0 {
-       struct btrfs_inode_item inode;
-       __le64 generation;
-       __le64 root_dirid;
-       __le64 bytenr;
-       __le64 byte_limit;
-       __le64 bytes_used;
-       __le64 last_snapshot;
-       __le64 flags;
-       __le32 refs;
-       struct btrfs_disk_key drop_progress;
-       u8 drop_level;
-       u8 level;
-} __attribute__ ((__packed__));
-
-struct btrfs_root_item {
-       struct btrfs_inode_item inode;
-       __le64 generation;
-       __le64 root_dirid;
-       __le64 bytenr;
-       __le64 byte_limit;
-       __le64 bytes_used;
-       __le64 last_snapshot;
-       __le64 flags;
-       __le32 refs;
-       struct btrfs_disk_key drop_progress;
-       u8 drop_level;
-       u8 level;
-
-       /*
-        * The following fields appear after subvol_uuids+subvol_times
-        * were introduced.
-        */
-
-       /*
-        * This generation number is used to test if the new fields are valid
-        * and up to date while reading the root item. Every time the root item
-        * is written out, the "generation" field is copied into this field. If
-        * anyone ever mounted the fs with an older kernel, we will have
-        * mismatching generation values here and thus must invalidate the
-        * new fields. See btrfs_update_root and btrfs_find_last_root for
-        * details.
-        * the offset of generation_v2 is also used as the start for the memset
-        * when invalidating the fields.
-        */
-       __le64 generation_v2;
-       u8 uuid[BTRFS_UUID_SIZE];
-       u8 parent_uuid[BTRFS_UUID_SIZE];
-       u8 received_uuid[BTRFS_UUID_SIZE];
-       __le64 ctransid; /* updated when an inode changes */
-       __le64 otransid; /* trans when created */
-       __le64 stransid; /* trans when sent. non-zero for received subvol */
-       __le64 rtransid; /* trans when received. non-zero for received subvol */
-       struct btrfs_timespec ctime;
-       struct btrfs_timespec otime;
-       struct btrfs_timespec stime;
-       struct btrfs_timespec rtime;
-       __le64 reserved[8]; /* for future */
-} __attribute__ ((__packed__));
-
-#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
-                                   struct btrfs_ioctl_ino_lookup_args)
-
-#define BTRFS_INO_LOOKUP_PATH_MAX 4080
-struct btrfs_ioctl_ino_lookup_args {
-       __u64 treeid;
-       __u64 objectid;
-       char name[BTRFS_INO_LOOKUP_PATH_MAX];
-};
-
-/*
- * All files have objectids in this range.
- */
-#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);
-int is_btrfs_subvol(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
deleted file mode 100644 (file)
index 48287dd..0000000
+++ /dev/null
@@ -1,175 +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
- */
-
-#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 ret;
-       size_t len;
-
-       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") + 4 + 3;
-       new->src = malloc(len);
-       if (!new->src)
-               return -1;
-
-       ret = snprintf(new->src, len, "dir:%s/%s/rootfs", lxcpath, cname);
-       if (ret < 0 || (size_t)ret >= len)
-               return -1;
-
-       new->dest = strdup(new->src + 4);
-       if (!new->dest)
-               return -1;
-
-       return 0;
-}
-
-int dir_create(struct bdev *bdev, const char *dest, const char *n,
-              struct bdev_specs *specs)
-{
-       int ret;
-       const char *src;
-       size_t len;
-
-       /* strlen("dir:") */
-       len = 4;
-       if (specs && specs->dir)
-               src = specs->dir;
-       else
-               src = dest;
-
-       len += strlen(src) + 1;
-       bdev->src = malloc(len);
-       if (!bdev->src)
-               return -1;
-
-       ret = snprintf(bdev->src, len, "dir:%s", src);
-       if (ret < 0 || (size_t)ret >= len)
-               return -1;
-
-       bdev->dest = strdup(dest);
-       if (!bdev->dest)
-               return -1;
-
-       ret = mkdir_p(src, 0755);
-       if (ret < 0) {
-               ERROR("Failed to create %s", src);
-               return -1;
-       }
-
-       ret = mkdir_p(bdev->dest, 0755);
-       if (ret < 0) {
-               ERROR("Failed to create %s", bdev->dest);
-               return -1;
-       }
-
-       return 0;
-}
-
-int dir_destroy(struct bdev *orig)
-{
-       char *src;
-
-       src = lxc_storage_get_path(orig->src, orig->src);
-
-       if (lxc_rmdir_onedev(src, NULL) < 0)
-               return -1;
-
-       return 0;
-}
-
-int dir_detect(const char *path)
-{
-       if (!strncmp(path, "dir:", 4))
-               return 1;
-
-       if (is_dir(path))
-               return 1;
-
-       return 0;
-}
-
-int dir_mount(struct bdev *bdev)
-{
-       unsigned long mntflags;
-       char *src, *mntdata;
-       int ret;
-       unsigned long mflags;
-
-       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;
-       }
-
-       src = lxc_storage_get_path(bdev->src, bdev->type);
-
-       ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
-       if ((0 == ret) && (mntflags & MS_RDONLY)) {
-               DEBUG("remounting %s on %s with readonly options",
-                       src ? src : "(none)", bdev->dest ? bdev->dest : "(none)");
-               mflags = add_required_remount_flags(src, bdev->dest, MS_BIND | MS_REC | mntflags | MS_REMOUNT);
-               ret = mount(src, bdev->dest, "bind", mflags, 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
deleted file mode 100644 (file)
index f5cca9a..0000000
+++ /dev/null
@@ -1,52 +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
- */
-
-#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
deleted file mode 100644 (file)
index 017ead5..0000000
+++ /dev/null
@@ -1,260 +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
- */
-
-#define _GNU_SOURCE
-#include <dirent.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <linux/loop.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "bdev.h"
-#include "log.h"
-#include "lxcloop.h"
-#include "storage_utils.h"
-#include "utils.h"
-
-lxc_log_define(lxcloop, lxc);
-
-static int do_loop_create(const char *path, uint64_t size, const char *fstype);
-
-/*
- * 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)
-{
-       int ret;
-       struct stat s;
-
-       if (!strncmp(path, "loop:", 5))
-               return 1;
-
-       ret = stat(path, &s);
-       if (ret < 0)
-               return 0;
-
-       if (__S_ISTYPE(s.st_mode, S_IFREG))
-               return 1;
-
-       return 0;
-}
-
-int loop_mount(struct bdev *bdev)
-{
-       int ret, loopfd;
-       char loname[MAXPATHLEN];
-       char *src = bdev->src;
-
-       if (strcmp(bdev->type, "loop"))
-               return -22;
-
-       if (!bdev->src || !bdev->dest)
-               return -22;
-
-       /* skip prefix */
-       if (!strncmp(bdev->src, "loop:", 5))
-               src += 5;
-
-       loopfd = lxc_prepare_loop_dev(src, loname, LO_FLAGS_AUTOCLEAR);
-       if (loopfd < 0) {
-               ERROR("failed to prepare loop device for loop file \"%s\"", src);
-               return -1;
-       }
-       DEBUG("prepared loop device \"%s\"", loname);
-
-       ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts);
-       if (ret < 0)
-               ERROR("failed to mount rootfs \"%s\" onto \"%s\" via loop device \"%s\"", bdev->src, bdev->dest, loname);
-       else
-               bdev->lofd = loopfd;
-       DEBUG("mounted rootfs \"%s\" onto \"%s\" via loop device \"%s\"", bdev->src, bdev->dest, loname);
-
-       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;
-       const char *cmd_args[2] = {fstype, path};
-       char cmd_output[MAXPATHLEN];
-
-       // 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
-       ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
-                         (void *)cmd_args);
-       if (ret < 0)
-               return -1;
-
-       return 0;
-}
diff --git a/src/lxc/bdev/lxcloop.h b/src/lxc/bdev/lxcloop.h
deleted file mode 100644 (file)
index 5d33182..0000000
+++ /dev/null
@@ -1,52 +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
- */
-
-#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
deleted file mode 100644 (file)
index 9c90627..0000000
+++ /dev/null
@@ -1,473 +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
- */
-
-#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/sysmacros.h>
-#include <sys/wait.h>
-
-#include "bdev.h"
-#include "config.h"
-#include "log.h"
-#include "lxclvm.h"
-#include "storage_utils.h"
-#include "utils.h"
-
-/* major()/minor() */
-#ifdef MAJOR_IN_MKDEV
-#    include <sys/mkdev.h>
-#endif
-
-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;
-       }
-
-       (void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1);
-       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))
-               return 1;
-
-       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)
-{
-       char *src;
-
-       if (strcmp(bdev->type, "lvm"))
-               return -22;
-
-       if (!bdev->src || !bdev->dest)
-               return -22;
-
-       src = lxc_storage_get_path(bdev->src, bdev->type);
-
-       /* If we might pass in data sometime, then we'll have to enrich
-        * mount_unknown_fs().
-        */
-       return mount_unknown_fs(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;
-       }
-
-       (void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 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;
-       const char *cmd_args[2];
-       char cmd_output[MAXPATHLEN];
-
-       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");
-               if (!vg) {
-                       ERROR("The \"lxc.bdev.lvm.vg\" key is not set");
-                       return -1;
-               }
-
-               len = strlen("/dev/") + strlen(vg) + strlen(cname) + 4 + 2;
-               new->src = malloc(len);
-               if (!new->src)
-                       return -1;
-
-               ret = snprintf(new->src, len, "lvm:/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) {
-               char *newsrc, *origsrc;
-
-               origsrc = lxc_storage_get_path(orig->src, "lvm");
-               newsrc = lxc_storage_get_path(new->src, "lvm");
-
-               if (lvm_snapshot(origsrc, newsrc, size) < 0) {
-                       ERROR("could not create %s snapshot of %s", new->src, orig->src);
-                       return -1;
-               }
-       } else {
-               char *src;
-
-               src = lxc_storage_get_path(new->src, "lvm");
-               if (do_lvm_create(src, size, lxc_global_config_value("lxc.bdev.lvm.thin_pool")) < 0) {
-                       ERROR("Error creating new lvm blockdev");
-                       return -1;
-               }
-
-               cmd_args[0] = fstype;
-               cmd_args[1] = src;
-               // create an fs in the loopback file
-               ret = run_command(cmd_output, sizeof(cmd_output),
-                                 do_mkfs_exec_wrapper, (void *)cmd_args);
-               if (ret < 0)
-                       return -1;
-       }
-
-       return 0;
-}
-
-int lvm_destroy(struct bdev *orig)
-{
-       char *src;
-
-       pid_t pid;
-
-       if ((pid = fork()) < 0)
-               return -1;
-
-       if (!pid) {
-               (void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1);
-               src = lxc_storage_get_path(orig->src, "lvm");
-               execlp("lvremove", "lvremove", "-f", 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;
-       const char *cmd_args[2];
-       char cmd_output[MAXPATHLEN];
-
-       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) + 4 + 7;
-       bdev->src = malloc(len);
-       if (!bdev->src)
-               return -1;
-
-       ret = snprintf(bdev->src, len, "lvm:/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 + 4, 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;
-
-       cmd_args[0] = fstype;
-       cmd_args[1] = bdev->src + 4;
-       ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
-                         (void *)cmd_args);
-       if (ret < 0)
-               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
deleted file mode 100644 (file)
index 6f1a972..0000000
+++ /dev/null
@@ -1,56 +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
- */
-
-#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
deleted file mode 100644 (file)
index e6ce590..0000000
+++ /dev/null
@@ -1,316 +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
- */
-
-#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 "storage_utils.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))
-               return 1;
-
-       return 0;
-}
-
-int nbd_mount(struct bdev *bdev)
-{
-       int ret = -1, partition;
-       char *src;
-       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;
-
-       src = lxc_storage_get_path(bdev->src, bdev->type);
-       partition = nbd_get_partition(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)
-{
-       if (strcmp(bdev->type, "nbd"))
-               return -22;
-
-       if (!bdev->src || !bdev->dest)
-               return -22;
-
-       return umount(bdev->dest);
-}
-
-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
deleted file mode 100644 (file)
index 1404d5a..0000000
+++ /dev/null
@@ -1,58 +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
- */
-
-#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
deleted file mode 100644 (file)
index 50a72e2..0000000
+++ /dev/null
@@ -1,775 +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
- */
-
-#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;
-static char *ovl_version[] = {"overlay", "overlayfs"};
-
-/* 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);
-static int ovl_remount_on_enodev(const char *lower, const char *target,
-                                const char *name, unsigned long mountflags,
-                                const void *options);
-
-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)
-{
-        char *src;
-
-       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);
-
-               src = lxc_storage_get_path(orig->src, orig->type);
-               // the src will be 'overlayfs:lowerdir:upperdir'
-               len = strlen(delta) + strlen(src) + 12;
-               new->src = malloc(len);
-               if (!new->src) {
-                       free(delta);
-                       return -ENOMEM;
-               }
-               ret = snprintf(new->src, len, "overlayfs:%s:%s", 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))
-               return 1;
-
-       if (!strncmp(path, "overlay:", 8))
-               return 1;
-
-       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;
-       }
-
-        /* Assume we need a workdir as we are on a overlay version >= v22. */
-       ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
-                                   MS_MGC_VAL | mntflags, options_work);
-       if (ret < 0) {
-               INFO("Overlayfs: Error mounting %s onto %s with options %s. "
-                    "Retrying without workdir: %s.",
-                    lower, bdev->dest, options_work, strerror(errno));
-
-                /* Assume we cannot use a workdir as we are on a version <= v21. */
-               ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
-                                         MS_MGC_VAL | mntflags, options);
-               if (ret < 0)
-                       SYSERROR("Overlayfs: Error mounting %s onto %s with "
-                                "options %s: %s.",
-                                lower, bdev->dest, options,
-                                strerror(errno));
-               else
-                       INFO("Overlayfs: Mounted %s onto %s with options %s.",
-                            lower, bdev->dest, options);
-       } else {
-               INFO("Overlayfs: Mounted %s onto %s with options %s.", lower,
-                    bdev->dest, options_work);
-       }
-       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;
-       size_t 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_remount_on_enodev(const char *lower, const char *target,
-                                const char *name, unsigned long mountflags,
-                                const void *options)
-{
-        int ret;
-        ret = mount(lower, target, ovl_name, MS_MGC_VAL | mountflags, options);
-        if (ret < 0 && errno == ENODEV) /* Try other module name. */
-               ret = mount(lower, target,
-                           ovl_name == ovl_version[0] ? ovl_version[1]
-                                                      : ovl_version[0],
-                           MS_MGC_VAL | mountflags, options);
-        return ret;
-}
-
-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 = ovl_version[0];
-       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\toverlayfs\n") == 0) {
-                       v = ovl_version[1];
-                       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,
-                                   "ovl_rsync_wrapper");
-       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
deleted file mode 100644 (file)
index 8ef277b..0000000
+++ /dev/null
@@ -1,93 +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
- */
-
-#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
deleted file mode 100644 (file)
index 8500140..0000000
+++ /dev/null
@@ -1,197 +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
- */
-
-#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 "storage_utils.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;
-       const char *cmd_args[2];
-       char cmd_output[MAXPATHLEN];
-
-       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) + 4 + 11;
-       bdev->src = malloc(len);
-       if (!bdev->src)
-               return -1;
-
-       ret = snprintf(bdev->src, len, "rbd:/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;
-
-       cmd_args[0] = fstype;
-       cmd_args[1] = bdev->src + 4;
-       ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
-                         (void *)cmd_args);
-       if (ret < 0)
-               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)
-{
-       char *src;
-       pid_t pid;
-       char *rbdfullname;
-
-       src = lxc_storage_get_path(orig->src, orig->type);
-       if (file_exists(src)) {
-               if ((pid = fork()) < 0)
-                       return -1;
-               if (!pid) {
-                       execlp("rbd", "rbd", "unmap" , src, (char *)NULL);
-                       exit(1);
-               }
-               if (wait_for_pid(pid) < 0)
-                       return -1;
-       }
-
-       if ((pid = fork()) < 0)
-               return -1;
-       if (!pid) {
-               rbdfullname = alloca(strlen(src) - 8);
-               strcpy( rbdfullname, &src[9] );
-               execlp("rbd", "rbd", "rm" , rbdfullname, (char *)NULL);
-               exit(1);
-       }
-       return wait_for_pid(pid);
-
-}
-
-int rbd_detect(const char *path)
-{
-       if (!strncmp(path, "rbd:", 4))
-               return 1;
-
-       if (!strncmp(path, "/dev/rbd/", 9))
-               return 1;
-
-       return 0;
-}
-
-int rbd_mount(struct bdev *bdev)
-{
-       char *src;
-       if (strcmp(bdev->type, "rbd"))
-               return -22;
-
-       if (!bdev->src || !bdev->dest)
-               return -22;
-
-       src = lxc_storage_get_path(bdev->src, bdev->type);
-       if (!file_exists(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
deleted file mode 100644 (file)
index 19fa026..0000000
+++ /dev/null
@@ -1,52 +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
- */
-
-#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
deleted file mode 100644 (file)
index 41eb881..0000000
+++ /dev/null
@@ -1,141 +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
- */
-
-#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", "-aHXS", "--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
deleted file mode 100644 (file)
index 802a885..0000000
+++ /dev/null
@@ -1,46 +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
- */
-
-#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
deleted file mode 100644 (file)
index 8fe7413..0000000
+++ /dev/null
@@ -1,334 +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
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.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)
-{
-       if (!strncmp(path, "zfs:", 4))
-               return 1;
-
-       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)
-{
-       int ret;
-       char *mntdata, *src;
-       unsigned long mntflags;
-
-       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;
-       }
-
-       src = lxc_storage_get_path(bdev->src, bdev->type);
-       ret = mount(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) {
-                       int dev0 = open("/dev/null", O_WRONLY);
-                       if (dev0 >= 0)
-                               dup2(dev0, STDERR_FILENO);
-                       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)
-{
-       char *origsrc, *newsrc;
-       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") + 4 + 3;
-       new->src = malloc(len);
-       if (!new->src)
-               return -1;
-
-       ret = snprintf(new->src, len, "zfs:%s/%s/rootfs", lxcpath, cname);
-       if (ret < 0 || ret >= len)
-               return -1;
-
-       newsrc = lxc_storage_get_path(new->src, new->type);
-       new->dest = strdup(newsrc);
-       if (!new->dest)
-               return -1;
-
-       origsrc = lxc_storage_get_path(orig->src, orig->type);
-       return zfs_clone(origsrc, newsrc, 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, *src;
-
-       if ((pid = fork()) < 0)
-               return -1;
-       if (pid)
-               return wait_for_pid(pid);
-
-       src = lxc_storage_get_path(orig->src, orig->type);
-       if (!zfs_list_entry(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", "-r", output, (char *)NULL);
-       exit(EXIT_FAILURE);
-}
-
-struct zfs_exec_args {
-       char *dataset;
-       char *options;
-};
-
-int zfs_create_exec_wrapper(void *args)
-{
-       struct zfs_exec_args *zfs_args = args;
-
-       execlp("zfs", "zfs", "create", zfs_args->options, zfs_args->dataset,
-              (char *)NULL);
-       return -1;
-}
-
-int zfs_create(struct bdev *bdev, const char *dest, const char *n,
-               struct bdev_specs *specs)
-{
-       const char *zfsroot;
-       char cmd_output[MAXPATHLEN], dev[MAXPATHLEN], option[MAXPATHLEN];
-       int ret;
-       size_t len;
-       struct zfs_exec_args cmd_args;
-
-       if (!specs || !specs->zfs.zfsroot)
-               zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
-       else
-               zfsroot = specs->zfs.zfsroot;
-
-       bdev->dest = strdup(dest);
-       if (!bdev->dest) {
-               ERROR("No mount target specified or out of memory");
-               return -1;
-       }
-
-       len = strlen(bdev->dest) + 1;
-       /* strlen("zfs:") */
-       len += 4;
-       bdev->src = malloc(len);
-       if (!bdev->src)
-               return -1;
-
-       ret = snprintf(bdev->src, len, "zfs:%s", bdev->dest);
-       if (ret < 0 || (size_t)ret >= len)
-               return -1;
-
-       ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s", bdev->dest);
-       if (ret < 0  || ret >= MAXPATHLEN)
-               return -1;
-
-       ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, n);
-       if (ret < 0  || ret >= MAXPATHLEN)
-               return -1;
-
-       cmd_args.options = option;
-       cmd_args.dataset = dev;
-       ret = run_command(cmd_output, sizeof(cmd_output),
-                         zfs_create_exec_wrapper, (void *)&cmd_args);
-       if (ret < 0)
-               ERROR("Failed to create zfs dataset \"%s\": %s", dev, cmd_output);
-       return ret;
-}
diff --git a/src/lxc/bdev/lxczfs.h b/src/lxc/bdev/lxczfs.h
deleted file mode 100644 (file)
index 0484619..0000000
+++ /dev/null
@@ -1,61 +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
- */
-
-#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 */
diff --git a/src/lxc/bdev/storage_utils.c b/src/lxc/bdev/storage_utils.c
deleted file mode 100644 (file)
index 0cf9710..0000000
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * Copyright © 2017 Canonical Ltd.
- *
- * Authors:
- * Christian Brauner <christian.brauner@ubuntu.com>
- *
- * This program 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 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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 <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 "log.h"
-#include "lxcnbd.h"
-#include "parse.h"
-#include "storage_utils.h"
-#include "utils.h"
-
-#ifndef BLKGETSIZE64
-#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
-#endif
-
-lxc_log_define(storage_utils, lxc);
-
-/* 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;
-}
-
-/*
- * return block size of dev->src in units of bytes
- */
-int blk_getsize(struct bdev *bdev, uint64_t *size)
-{
-       int fd, ret;
-       char *src;
-
-       src = lxc_storage_get_path(bdev->src, bdev->type);
-       fd = open(src, 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, *srcdev, *line = NULL;
-
-       if (!bdev || !bdev->src || !bdev->dest)
-               return -1;
-
-       srcdev = lxc_storage_get_path(bdev->src, bdev->type);
-
-       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_exec_wrapper(void *args)
-{
-       int ret;
-       char *mkfs;
-       char **data = args;
-       /* strlen("mkfs.")
-        * +
-        * strlen(data[0])
-        * +
-        * \0
-        */
-       size_t len = 5 + strlen(data[0]) + 1;
-
-       mkfs = malloc(len);
-       if (!mkfs)
-               return -1;
-
-       ret = snprintf(mkfs, len, "mkfs.%s", data[0]);
-       if (ret < 0 || (size_t)ret >= len) {
-               free(mkfs);
-               return -1;
-       }
-
-       TRACE("executing \"%s %s\"", mkfs, data[1]);
-       execlp(mkfs, mkfs, data[1], (char *)NULL);
-       SYSERROR("failed to run \"%s %s \"", mkfs, data[1]);
-       return -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)
-{
-       size_t i;
-       int ret;
-       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++) {
-               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;
-}
-
-/*
- * 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
- */
-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;
-}
-
-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
- */
-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;
-}
-
-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;
-
-       return 0;
-}
diff --git a/src/lxc/bdev/storage_utils.h b/src/lxc/bdev/storage_utils.h
deleted file mode 100644 (file)
index cfd6aa4..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * Copyright © 2017 Canonical Ltd.
- *
- * Authors:
- * Christian Brauner <christian.brauner@ubuntu.com>
- *
- * This program 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 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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
- */
-
-#ifndef __LXC_STORAGE_UTILS_H
-#define __LXC_STORAGE_UTILS_H
-
-#include "config.h"
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#include "conf.h"
-
-struct bdev;
-struct lxc_conf;
-
-extern char *dir_new_path(char *src, const char *oldname, const char *name,
-                         const char *oldpath, const char *lxcpath);
-extern bool attach_block_device(struct lxc_conf *conf);
-extern void detach_block_device(struct lxc_conf *conf);
-extern int blk_getsize(struct bdev *bdev, uint64_t *size);
-extern int detect_fs(struct bdev *bdev, char *type, int len);
-extern int do_mkfs_exec_wrapper(void *args);
-extern int is_blktype(struct bdev *b);
-extern int mount_unknown_fs(const char *rootfs, const char *target,
-                           const char *options);
-extern int find_fstype_cb(char *buffer, void *data);
-extern char *linkderef(char *path, char *dest);
-extern bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
-                               bool maybesnap);
-extern bool is_valid_bdev_type(const char *type);
-extern int bdev_destroy_wrapper(void *data);
-
-#endif // __LXC_STORAGE_UTILS_H
index 5b5e0d32bf6fdf1f4f7c5eebe9c9709975fc31e6..bcbd66134eb4884ed8b3acea1316674ace3f1c9e 100644 (file)
@@ -39,7 +39,6 @@
 #include <netinet/in.h>
 #include <net/if.h>
 
-#include "bdev.h"
 #include "error.h"
 #include "commands.h"
 #include "list.h"
@@ -49,6 +48,7 @@
 #include "cgroup.h"
 #include "start.h"
 #include "state.h"
+#include "storage.h"
 
 #if IS_BIONIC
 #include <../include/lxcmntent.h>
@@ -1800,7 +1800,9 @@ static char **subsystems_from_mount_options(const char *mount_options,
                        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'
+                       /* 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);
@@ -2068,9 +2070,10 @@ static bool cgroup_devices_has_allow_or_deny(struct cgfs_data *d,
                NULL
        };
 
-       // XXX FIXME if users could use something other than 'lxc.devices.deny = a'.
-       // not sure they ever do, but they *could*
-       // right now, I'm assuming they do NOT
+       /* XXX FIXME if users could use something other than 'lxc.devices.deny =
+        * a'.  not sure they ever do, but they *could* right now, I'm assuming
+        * they do NOT
+        */
        if (!for_allow && strcmp(v, "a") != 0 && strcmp(v, "a *:* rwm") != 0)
                return false;
 
@@ -2340,7 +2343,7 @@ struct cgroup_ops *cgfs_ops_init(void)
        return &cgfs_ops;
 }
 
-static void *cgfs_init(const char *name)
+static void *cgfs_init(struct lxc_handler *handler)
 {
        struct cgfs_data *d;
 
@@ -2349,7 +2352,7 @@ static void *cgfs_init(const char *name)
                return NULL;
 
        memset(d, 0, sizeof(*d));
-       d->name = strdup(name);
+       d->name = strdup(handler->name);
        if (!d->name)
                goto err1;
 
index af4455476909b83af523e3e34f819c119bc73f92..897336f07fdff28d2f6ec5d50125f0cdc80a10cc 100644 (file)
 #include <unistd.h>
 #include <sys/types.h>
 
-#include "bdev.h"
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+
 #include "cgroup.h"
 #include "cgroup_utils.h"
 #include "commands.h"
+#include "conf.h"
 #include "log.h"
+#include "storage/storage.h"
 #include "utils.h"
 
 lxc_log_define(lxc_cgfsng, lxc);
@@ -78,17 +82,21 @@ struct hierarchy {
 
 /*
  * The cgroup data which is attached to the lxc_handler.
- * @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
+ * @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 name of the container.
+ * @cgroup_meta      : A copy of the container's cgroup information. This
+ *                     overrides @cgroup_pattern.
  */
 struct cgfsng_handler_data {
        char *cgroup_pattern;
-       char *container_cgroup; // cgroup we created for the container
-       char *name; // container name
+       char *container_cgroup; /* cgroup we created for the container */
+       char *name; /* container name */
+       /* per-container cgroup information */
+       struct lxc_cgroup cgroup_meta;
 };
 
 /*
@@ -217,6 +225,10 @@ static void free_handler_data(struct cgfsng_handler_data *d)
        free(d->cgroup_pattern);
        free(d->container_cgroup);
        free(d->name);
+       if (d->cgroup_meta.dir)
+               free(d->cgroup_meta.dir);
+       if (d->cgroup_meta.controllers)
+               free(d->cgroup_meta.controllers);
        free(d);
 }
 
@@ -383,7 +395,7 @@ static ssize_t get_max_cpus(char *cpulist)
                c2 = c1;
        else if (c1 < c2)
                c1 = c2;
-       else if (!c1 && c2) // The reverse case is obvs. not needed.
+       else if (!c1 && c2) /* The reverse case is obvs. not needed. */
                c1 = c2;
 
        /* If the above logic is correct, c1 should always hold a valid string
@@ -411,7 +423,7 @@ static bool filter_and_set_cpus(char *path, bool am_initialized)
        bool bret = false, flipped_bit = false;
 
        lastslash = strrchr(path, '/');
-       if (!lastslash) { // bug...  this shouldn't be possible
+       if (!lastslash) { /* bug...  this shouldn't be possible */
                ERROR("Invalid path: %s.", path);
                return bret;
        }
@@ -543,7 +555,7 @@ static bool copy_parent_file(char *path, char *file)
        int ret;
 
        lastslash = strrchr(path, '/');
-       if (!lastslash) { // bug...  this shouldn't be possible
+       if (!lastslash) { /* bug...  this shouldn't be possible */
                ERROR("cgfsng:copy_parent_file: bad path %s", path);
                return false;
        }
@@ -983,8 +995,12 @@ static void lxc_cgfsng_print_handler_data(const struct cgfsng_handler_data *d)
        printf("Cgroup information:\n");
        printf("  container name: %s\n", d->name ? d->name : "(null)");
        printf("  lxc.cgroup.use: %s\n", cgroup_use ? cgroup_use : "(null)");
-       printf("  lxc.cgroup.pattern: %s\n", d->cgroup_pattern ? d->cgroup_pattern : "(null)");
-       printf("  cgroup: %s\n", d->container_cgroup ? d->container_cgroup : "(null)");
+       printf("  lxc.cgroup.pattern: %s\n",
+              d->cgroup_pattern ? d->cgroup_pattern : "(null)");
+       printf("  lxc.cgroup.dir: %s\n",
+              d->cgroup_meta.dir ? d->cgroup_meta.dir : "(null)");
+       printf("  cgroup: %s\n",
+              d->container_cgroup ? d->container_cgroup : "(null)");
 }
 
 static void lxc_cgfsng_print_hierarchies()
@@ -1138,7 +1154,7 @@ static bool collect_hierarchy_info(void)
        const char *tmp;
        errno = 0;
        tmp = lxc_global_config_value("lxc.cgroup.use");
-       if (!cgroup_use && errno != 0) { // lxc.cgroup.use can be NULL
+       if (!cgroup_use && errno != 0) { /* lxc.cgroup.use can be NULL */
                SYSERROR("cgfsng: error reading list of cgroups to use");
                return false;
        }
@@ -1147,18 +1163,27 @@ static bool collect_hierarchy_info(void)
        return parse_hierarchies();
 }
 
-static void *cgfsng_init(const char *name)
+static void *cgfsng_init(struct lxc_handler *handler)
 {
-       struct cgfsng_handler_data *d;
        const char *cgroup_pattern;
+       struct cgfsng_handler_data *d;
 
        d = must_alloc(sizeof(*d));
        memset(d, 0, sizeof(*d));
 
-       d->name = must_copy_string(name);
+       /* copy container name */
+       d->name = must_copy_string(handler->name);
 
+       /* copy per-container cgroup information */
+       if (handler->conf) {
+               d->cgroup_meta.dir = must_copy_string(handler->conf->cgroup_meta.dir);
+               d->cgroup_meta.controllers = must_copy_string(handler->conf->cgroup_meta.controllers);
+       }
+
+       /* copy system-wide cgroup information */
        cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
-       if (!cgroup_pattern) { // lxc.cgroup.pattern is only NULL on error
+       if (!cgroup_pattern) {
+               /* lxc.cgroup.pattern is only NULL on error. */
                ERROR("Error getting cgroup pattern");
                goto out_free;
        }
@@ -1176,6 +1201,7 @@ out_free:
 
 static int cgroup_rmdir(char *dirname)
 {
+       int ret;
        struct dirent *direntp;
        DIR *dir;
        int r = 0;
@@ -1185,8 +1211,8 @@ static int cgroup_rmdir(char *dirname)
                return -1;
 
        while ((direntp = readdir(dir))) {
-               struct stat mystat;
                char *pathname;
+               struct stat mystat;
 
                if (!direntp)
                        break;
@@ -1197,32 +1223,40 @@ static int cgroup_rmdir(char *dirname)
 
                pathname = must_make_path(dirname, direntp->d_name, NULL);
 
-               if (lstat(pathname, &mystat)) {
+               ret = lstat(pathname, &mystat);
+               if (ret < 0) {
                        if (!r)
-                               WARN("failed to stat %s", pathname);
+                               WARN("Failed to stat %s", pathname);
                        r = -1;
                        goto next;
                }
 
                if (!S_ISDIR(mystat.st_mode))
                        goto next;
-               if (cgroup_rmdir(pathname) < 0)
+
+               ret = cgroup_rmdir(pathname);
+               if (ret < 0)
                        r = -1;
 next:
                free(pathname);
        }
 
-       if (rmdir(dirname) < 0) {
+       ret = rmdir(dirname);
+       if (ret < 0) {
                if (!r)
-                       WARN("failed to delete %s: %s", dirname, strerror(errno));
+                       WARN("Failed to delete \"%s\": %s", dirname,
+                            strerror(errno));
                r = -1;
        }
 
-       if (closedir(dir) < 0) {
+       ret = closedir(dir);
+       if (ret < 0) {
                if (!r)
-                       WARN("failed to delete %s: %s", dirname, strerror(errno));
+                       WARN("Failed to delete \"%s\": %s", dirname,
+                            strerror(errno));
                r = -1;
        }
+
        return r;
 }
 
@@ -1288,7 +1322,7 @@ struct cgroup_ops *cgfsng_ops_init(void)
 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
+       if (dir_exists(h->fullcgpath)) { /* it must not already exist */
                ERROR("Path \"%s\" already existed.", h->fullcgpath);
                return false;
        }
@@ -1313,25 +1347,29 @@ static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
  */
 static inline bool cgfsng_create(void *hdata)
 {
-       struct cgfsng_handler_data *d = hdata;
-       char *tmp, *cgname, *offset;
        int i;
-       int idx = 0;
        size_t len;
+       char *cgname, *offset, *tmp;
+       int idx = 0;
+       struct cgfsng_handler_data *d = hdata;
 
        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 (d->cgroup_meta.dir)
+               tmp = lxc_string_join("/", (const char *[]){d->cgroup_meta.dir, d->name, NULL}, false);
+       else
+               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
+       len = strlen(tmp) + 5; /* leave room for -NNN\0 */
        cgname = must_alloc(len);
        strcpy(cgname, tmp);
        free(tmp);
@@ -1359,7 +1397,7 @@ again:
        for (i = 0; hierarchies[i]; i++) {
                if (!create_path_for_hierarchy(hierarchies[i], cgname)) {
                        int j;
-                       SYSERROR("Failed to create %s: %s", hierarchies[i]->fullcgpath, strerror(errno));
+                       ERROR("Failed to create \"%s\"", hierarchies[i]->fullcgpath);
                        free(hierarchies[i]->fullcgpath);
                        hierarchies[i]->fullcgpath = NULL;
                        for (j = 0; j < i; j++)
@@ -1402,7 +1440,7 @@ static bool cgfsng_enter(void *hdata, pid_t pid)
 
 struct chown_data {
        struct cgfsng_handler_data *d;
-       uid_t origuid; // target uid in parent namespace
+       uid_t origuid; /* target uid in parent namespace */
 };
 
 /*
@@ -1811,7 +1849,7 @@ static bool cgfsng_attach(const char *name, const char *lxcpath, pid_t pid)
                struct hierarchy *h = hierarchies[i];
 
                path = lxc_cmd_get_cgroup_path(name, lxcpath, h->controllers[0]);
-               if (!path) // not running
+               if (!path) /* not running */
                        continue;
 
                fullpath = build_full_cgpath_from_monitorpath(h, path, "cgroup.procs");
@@ -1844,7 +1882,7 @@ static int cgfsng_get(const char *filename, char *value, size_t len, const char
                *p = '\0';
 
        path = lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
-       if (!path) // not running
+       if (!path) /* not running */
                return -1;
 
        h = get_hierarchy(subsystem);
@@ -1876,7 +1914,7 @@ static int cgfsng_set(const char *filename, const char *value, const char *name,
                *p = '\0';
 
        path = lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
-       if (!path) // not running
+       if (!path) /* not running */
                return -1;
 
        h = get_hierarchy(subsystem);
@@ -1891,27 +1929,120 @@ static int cgfsng_set(const char *filename, const char *value, const char *name,
        return ret;
 }
 
+/*
+ * take devices cgroup line
+ *    /dev/foo rwx
+ * and convert it to a valid
+ *    type major:minor mode
+ * line.  Return <0 on error.  Dest is a preallocated buffer
+ * long enough to hold the output.
+ */
+static int convert_devpath(const char *invalue, char *dest)
+{
+       int n_parts;
+       char *p, *path, type;
+       struct stat sb;
+       unsigned long minor, major;
+       int ret = -EINVAL;
+       char *mode = NULL;
+
+       path = must_copy_string(invalue);
+
+       /*
+        * read path followed by mode;  ignore any trailing text.
+        * A '    # comment' would be legal.  Technically other text
+        * is not legal, we could check for that if we cared to
+        */
+       for (n_parts = 1, p = path; *p && n_parts < 3; p++) {
+               if (*p != ' ')
+                       continue;
+               *p = '\0';
+               if (n_parts != 1)
+                       break;
+               p++;
+               n_parts++;
+               while (*p == ' ')
+                       p++;
+               mode = p;
+               if (*p == '\0')
+                       goto out;
+       }
+
+       if (n_parts == 1)
+               goto out;
+
+       ret = stat(path, &sb);
+       if (ret < 0)
+               goto out;
+
+       mode_t m = sb.st_mode & S_IFMT;
+       switch (m) {
+       case S_IFBLK:
+               type = 'b';
+               break;
+       case S_IFCHR:
+               type = 'c';
+               break;
+       default:
+               ERROR("Unsupported device type %i for %s", m, path);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       major = MAJOR(sb.st_rdev);
+       minor = MINOR(sb.st_rdev);
+       ret = snprintf(dest, 50, "%c %lu:%lu %s", type, major, minor, mode);
+       if (ret < 0 || ret >= 50) {
+               ERROR("Error on configuration value \"%c %lu:%lu %s\" (max 50 "
+                     "chars)", type, major, minor, mode);
+               ret = -ENAMETOOLONG;
+               goto out;
+       }
+       ret = 0;
+
+out:
+       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;
+       char *fullpath, *p;
+       /* "b|c <2^64-1>:<2^64-1> r|w|m" = 47 chars max */
+       char converted_value[50];
        struct hierarchy *h;
+       int ret = 0;
+       char *controller = NULL;
 
-       subsystem = alloca(strlen(filename) + 1);
-       strcpy(subsystem, filename);
-       if ((p = strchr(subsystem, '.')) != NULL)
+       controller = alloca(strlen(filename) + 1);
+       strcpy(controller, filename);
+       if ((p = strchr(controller, '.')) != NULL)
                *p = '\0';
 
-       h = get_hierarchy(subsystem);
-       if (h) {
-               char *fullpath = must_make_path(h->fullcgpath, filename, NULL);
-               ret = lxc_write_to_file(fullpath, value, strlen(value), false);
-               free(fullpath);
+       if (strcmp("devices.allow", filename) == 0 && value[0] == '/') {
+               ret = convert_devpath(value, converted_value);
+               if (ret < 0)
+                       return ret;
+               value = converted_value;
+
        }
+
+       h = get_hierarchy(controller);
+       if (!h) {
+               ERROR("Failed to setup limits for the \"%s\" controller. "
+                     "The controller seems to be unused by \"cgfsng\" cgroup "
+                     "driver or not enabled on the cgroup hierarchy",
+                     controller);
+               return -1;
+       }
+
+       fullpath = must_make_path(h->fullcgpath, filename, NULL);
+       ret = lxc_write_to_file(fullpath, value, strlen(value), false);
+       free(fullpath);
        return ret;
 }
 
index 96b4edba64b0345c695c08f9b11e3edcd92d0664..054eb1715525dd54696e5580b7450d5cfdabfd09 100644 (file)
@@ -41,7 +41,6 @@
 #include <net/if.h>
 #include <poll.h>
 
-#include "bdev.h"
 #include "error.h"
 #include "commands.h"
 #include "list.h"
@@ -51,6 +50,7 @@
 #include "cgroup.h"
 #include "start.h"
 #include "state.h"
+#include "storage.h"
 
 #define CGM_SUPPORTS_GET_ABS 3
 #define CGM_SUPPORTS_NAMED 4
@@ -139,7 +139,7 @@ static bool cgm_dbus_connect(void)
 
        cgm_lock();
        if (!dbus_threads_initialized) {
-               // tell dbus to do struct locking for thread safety
+               /* tell dbus to do struct locking for thread safety */
                dbus_threads_init_default();
                dbus_threads_initialized = true;
        }
@@ -169,7 +169,7 @@ static bool cgm_dbus_connect(void)
                return false;
        }
 
-       // get the api version
+       /* get the api version */
        if (cgmanager_get_api_version_sync(NULL, cgroup_manager, &api_version) != 0) {
                NihError *nerr;
                nerr = nih_error_get();
@@ -540,7 +540,7 @@ static void cgm_remove_cgroup(const char *controller, const char *path)
                INFO("cgroup removal attempt: %s:%s did not exist", controller, path);
 }
 
-static void *cgm_init(const char *name)
+static void *cgm_init(struct lxc_handler *handler)
 {
        struct cgm_data *d;
 
@@ -554,7 +554,7 @@ static void *cgm_init(const char *name)
        }
 
        memset(d, 0, sizeof(*d));
-       d->name = strdup(name);
+       d->name = strdup(handler->name);
        if (!d->name) {
                cgm_dbus_disconnect();
                goto err1;
@@ -562,7 +562,7 @@ static void *cgm_init(const char *name)
 
        d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
 
-       // cgm_create immediately gets called so keep the connection open
+       /* cgm_create immediately gets called so keep the connection open */
        return d;
 
 err1:
@@ -620,10 +620,10 @@ static inline bool cgm_create(void *hdata)
 
        if (!d)
                return false;
-// XXX we should send a hint to the cgmanager that when these
-// cgroups become empty they should be deleted.  Requires a cgmanager
-// extension
 
+       /* XXX we should send a hint to the cgmanager that when these cgroups
+        * become empty they should be deleted. Requires a cgmanager extension.
+        */
        memset(result, 0, MAXPATHLEN);
        tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
        if (!tmp)
@@ -639,7 +639,7 @@ static inline bool cgm_create(void *hdata)
        while (*tmp == '/')
                tmp++;
 again:
-       if (index == 100) { // turn this into a warn later
+       if (index == 100) { /* turn this into a warn later */
                ERROR("cgroup error?  100 cgroups with this name already running");
                goto bad;
        }
@@ -662,7 +662,7 @@ again:
                if (existed == 1)
                        goto next;
        }
-       // success
+       /* success */
        cgroup_path = strdup(tmp);
        if (!cgroup_path) {
                cleanup_cgroups(tmp);
@@ -947,7 +947,7 @@ static int cgm_get(const char *filename, char *value, size_t len, const char *na
                close(p[1]);
                return -1;
        }
-       if (!pid) // do_cgm_get exits
+       if (!pid) /* do_cgm_get exits */
                do_cgm_get(name, lxcpath, filename, p[1], len && value);
        close(p[1]);
        ret = read(p[0], &newlen, sizeof(newlen));
@@ -962,12 +962,12 @@ static int cgm_get(const char *filename, char *value, size_t len, const char *na
                goto out;
        }
        memset(value, 0, len);
-       if (newlen < 0) { // child is reporting an error
+       if (newlen < 0) { /* child is reporting an error */
                close(p[0]);
                ret = -1;
                goto out;
        }
-       if (newlen == 0) { // empty read
+       if (newlen == 0) { /* empty read */
                close(p[0]);
                ret = 0;
                goto out;
@@ -983,7 +983,7 @@ static int cgm_get(const char *filename, char *value, size_t len, const char *na
                value[len-1] = '\0';
                newlen = len-1;
        } else if (newlen+1 < len) {
-               // cgmanager doesn't add eol to last entry
+               /* cgmanager doesn't add eol to last entry */
                value[newlen++] = '\n';
                value[newlen] = '\0';
        }
@@ -997,7 +997,7 @@ out:
 static void do_cgm_set(const char *name, const char *lxcpath, const char *filename, const char *value, int outp)
 {
        char *controller, *key, *cgroup = NULL;
-       int retval = 0;  // value we are sending to the parent over outp
+       int retval = 0;  /* value we are sending to the parent over outp */
        int ret;
        char *cglast;
 
@@ -1083,7 +1083,7 @@ static int cgm_set(const char *filename, const char *value, const char *name, co
                close(p[0]);
                return -1;
        }
-       if (!pid) // do_cgm_set exits
+       if (!pid) /* do_cgm_set exits */
                do_cgm_set(name, lxcpath, filename, value, p[1]);
        close(p[1]);
        ret = read(p[0], &v, sizeof(v));
@@ -1328,7 +1328,7 @@ static bool collect_subsystems(void)
        size_t sz = 0;
        FILE *f = NULL;
 
-       if (subsystems) // already initialized
+       if (subsystems) /* already initialized */
                return true;
 
        subsystems_inone = malloc(2 * sizeof(char *));
@@ -1439,7 +1439,7 @@ struct cgroup_ops *cgm_ops_init(void)
        if (api_version < CGM_SUPPORTS_MULT_CONTROLLERS)
                cgm_all_controllers_same = false;
 
-       // if root, try to escape to root cgroup
+       /* if root, try to escape to root cgroup */
        if (geteuid() == 0 && !cgm_escape(NULL)) {
                free_subsystems();
                return NULL;
@@ -1502,7 +1502,7 @@ static bool cgm_setup_limits(void *hdata, struct lxc_list *cgroup_settings, bool
                cg = iterator->elem;
                if (do_devices != !strncmp("devices", cg->subsystem, 7))
                        continue;
-               if (strlen(cg->subsystem) > 100) // i smell a rat
+               if (strlen(cg->subsystem) > 100) /* i smell a rat */
                        goto out;
                strcpy(controller, cg->subsystem);
                p = strchr(controller, '.');
@@ -1559,7 +1559,7 @@ static bool cgm_chown(void *hdata, struct lxc_conf *conf)
 }
 
 /*
- * TODO: this should be re-written to use the get_config_item("lxc.id_map")
+ * TODO: this should be re-written to use the get_config_item("lxc.idmap")
  * cmd api instead of getting the idmap from c->lxc_conf.  The reason is
  * that the id_maps may be different if the container was started with a
  * -f or -s argument.
@@ -1648,7 +1648,7 @@ static bool cgm_mount_cgroup(void *hdata, const char *root, int type)
                return cgm_bind_dir(root, CGMANAGER_LOWER_SOCK);
        if (dir_exists(CGMANAGER_UPPER_SOCK))
                return cgm_bind_dir(root, CGMANAGER_UPPER_SOCK);
-       // Host doesn't have cgmanager running?  Then how did we get here?
+       /* Host doesn't have cgmanager running?  Then how did we get here? */
        return false;
 }
 
index 78472d4fc28fc92c4efdf6d2ec4fa7950d09fa02..674e3090527db148781b40c0e7d355bc51f204cb 100644 (file)
@@ -37,8 +37,7 @@ 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))
-void cgroup_ops_init(void)
+__attribute__((constructor)) void cgroup_ops_init(void)
 {
        if (ops) {
                INFO("cgroup driver %s", ops->name);
@@ -46,9 +45,9 @@ void cgroup_ops_init(void)
        }
 
        DEBUG("cgroup_init");
-       #if HAVE_CGMANAGER
+#if HAVE_CGMANAGER
        ops = cgm_ops_init();
-       #endif
+#endif
        if (!ops)
                ops = cgfsng_ops_init();
        if (!ops)
@@ -60,14 +59,15 @@ void cgroup_ops_init(void)
 bool cgroup_init(struct lxc_handler *handler)
 {
        if (handler->cgroup_data) {
-               ERROR("cgroup_init called on already inited handler");
+               ERROR("cgroup_init called on already initialized handler");
                return true;
        }
 
        if (ops) {
                INFO("cgroup driver %s initing for %s", ops->name, handler->name);
-               handler->cgroup_data = ops->init(handler->name);
+               handler->cgroup_data = ops->init(handler);
        }
+
        return handler->cgroup_data != NULL;
 }
 
@@ -79,22 +79,21 @@ void cgroup_destroy(struct lxc_handler *handler)
        }
 }
 
-/* Create the container cgroups for all requested controllers */
+/* Create the container cgroups for all requested controllers. */
 bool cgroup_create(struct lxc_handler *handler)
 {
        if (ops)
                return ops->create(handler->cgroup_data);
+
        return false;
 }
 
-/*
- * Enter the container init into its new cgroups for all
- * requested controllers
- */
+/* Enter the container init into its new cgroups for all requested controllers. */
 bool cgroup_enter(struct lxc_handler *handler)
 {
        if (ops)
                return ops->enter(handler->cgroup_data, handler->pid);
+
        return false;
 }
 
@@ -102,13 +101,16 @@ bool cgroup_create_legacy(struct lxc_handler *handler)
 {
        if (ops && ops->create_legacy)
                return ops->create_legacy(handler->cgroup_data, handler->pid);
+
        return true;
 }
 
-const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem)
+const char *cgroup_get_cgroup(struct lxc_handler *handler,
+                             const char *subsystem)
 {
        if (ops)
                return ops->get_cgroup(handler->cgroup_data, subsystem);
+
        return NULL;
 }
 
@@ -116,6 +118,7 @@ bool cgroup_escape(struct lxc_handler *handler)
 {
        if (ops)
                return ops->escape(handler->cgroup_data);
+
        return false;
 }
 
@@ -139,6 +142,7 @@ bool cgroup_unfreeze(struct lxc_handler *handler)
 {
        if (ops)
                return ops->unfreeze(handler->cgroup_data);
+
        return false;
 }
 
@@ -147,6 +151,7 @@ bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
        if (ops)
                return ops->setup_limits(handler->cgroup_data,
                                         &handler->conf->cgroup, with_devices);
+
        return false;
 }
 
@@ -154,14 +159,15 @@ bool cgroup_chown(struct lxc_handler *handler)
 {
        if (ops && ops->chown)
                return ops->chown(handler->cgroup_data, handler->conf);
+
        return true;
 }
 
 bool cgroup_mount(const char *root, struct lxc_handler *handler, int type)
 {
-       if (ops) {
+       if (ops)
                return ops->mount_cgroup(handler->cgroup_data, root, type);
-       }
+
        return false;
 }
 
@@ -171,8 +177,9 @@ int cgroup_nrtasks(struct lxc_handler *handler)
                if (ops->nrtasks)
                        return ops->nrtasks(handler->cgroup_data);
                else
-                       WARN("CGROUP driver %s doesn't implement nrtasks", ops->name);
+                       WARN("cgroup driver \"%s\" doesn't implement nrtasks", ops->name);
        }
+
        return -1;
 }
 
@@ -180,20 +187,25 @@ bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid)
 {
        if (ops)
                return ops->attach(name, lxcpath, pid);
+
        return false;
 }
 
-int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+int lxc_cgroup_set(const char *filename, const char *value, const char *name,
+                  const char *lxcpath)
 {
        if (ops)
                return ops->set(filename, value, name, lxcpath);
+
        return -1;
 }
 
-int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+int lxc_cgroup_get(const char *filename, char *value, size_t len,
+                  const char *name, const char *lxcpath)
 {
        if (ops)
                return ops->get(filename, value, len, name, lxcpath);
+
        return -1;
 }
 
@@ -219,30 +231,32 @@ void prune_init_scope(char *cg)
        point = cg + strlen(cg) - strlen(INIT_SCOPE);
        if (point < cg)
                return;
+
        if (strcmp(point, INIT_SCOPE) == 0) {
                if (point == cg)
-                       *(point+1) = '\0';
+                       *(point + 1) = '\0';
                else
                        *point = '\0';
        }
 }
 
-/*
- * Return true if this is a subsystem which we cannot do
- * without.
+/* Return true if this is a subsystem which we cannot do without.
  *
- * systemd is questionable here.  The way callers currently
- * use this, if systemd is not mounted then it will be ignored.
- * But if systemd is mounted, then it must be setup so that lxc
- * can create cgroups in it, else containers will fail.
+ * systemd is questionable here. The way callers currently use this, if systemd
+ * is not mounted then it will be ignored. But if systemd is mounted, then it
+ * must be setup so that lxc can create cgroups in it, else containers will
+ * fail.
  */
 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 11b251e698edb0f2ea0f8c8890d26cb56e4fbf8b..f17a6abe0adc2b69191966f2cc599738fbc7510c 100644 (file)
@@ -41,7 +41,7 @@ typedef enum {
 struct cgroup_ops {
        const char *name;
 
-       void *(*init)(const char *name);
+       void *(*init)(struct lxc_handler *handler);
        void (*destroy)(void *hdata, struct lxc_conf *conf);
        bool (*create)(void *hdata);
        bool (*enter)(void *hdata, pid_t pid);
index c6ece2cc704170bb3b5f92b6748ce7e4ff75ba14..68fbd387cb3edd431b385ea31fc20d009c24002d 100644 (file)
@@ -516,7 +516,7 @@ static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req,
        struct lxc_config_t *item;
 
        memset(&rsp, 0, sizeof(rsp));
-       item = lxc_getconfig(req->data);
+       item = lxc_get_config(req->data);
        if (!item)
                goto err1;
        cilen = item->get(req->data, NULL, 0, handler->conf, NULL);
index ab038d36db5fb6b0ee6d403c039b56d2720fbc16..6871b83a0523cd9c913055c0bdf3f8b3aaed88bf 100644 (file)
 #endif
 
 #include "af_unix.h"
-#include "bdev.h"
 #include "caps.h"       /* for lxc_caps_last_cap() */
 #include "cgroup.h"
 #include "conf.h"
 #include "confile_utils.h"
 #include "error.h"
 #include "log.h"
-#include "lxcaufs.h"
 #include "lxclock.h"
-#include "lxcoverlay.h"
 #include "lxcseccomp.h"
 #include "namespace.h"
 #include "network.h"
 #include "parse.h"
+#include "storage.h"
+#include "storage/aufs.h"
+#include "storage/overlay.h"
 #include "utils.h"
 #include "lsm/lsm.h"
 
@@ -234,10 +234,10 @@ static int memfd_create(const char *name, unsigned int flags) {
 extern int memfd_create(const char *name, unsigned int flags);
 #endif
 
-char *lxchook_names[NUM_LXC_HOOKS] = {
-       "pre-start", "pre-mount", "mount", "autodev", "start", "stop", "post-stop", "clone", "destroy" };
-
-typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
+char *lxchook_names[NUM_LXC_HOOKS] = {"pre-start", "pre-mount", "mount",
+                                     "autodev",   "start",     "stop",
+                                     "post-stop", "clone",     "destroy",
+                                     "start-host"};
 
 struct mount_opt {
        char *name;
@@ -269,38 +269,6 @@ struct lxc_conf *current_config;
 /* Declare this here, since we don't want to reshuffle the whole file. */
 static int in_caplist(int cap, struct lxc_list *caps);
 
-static int instantiate_veth(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_macvlan(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_vlan(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_phys(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_empty(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_none(struct lxc_handler *, struct lxc_netdev *);
-
-static  instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
-       [LXC_NET_VETH]    = instantiate_veth,
-       [LXC_NET_MACVLAN] = instantiate_macvlan,
-       [LXC_NET_VLAN]    = instantiate_vlan,
-       [LXC_NET_PHYS]    = instantiate_phys,
-       [LXC_NET_EMPTY]   = instantiate_empty,
-       [LXC_NET_NONE]    = instantiate_none,
-};
-
-static int shutdown_veth(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_macvlan(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_vlan(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_phys(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_empty(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_none(struct lxc_handler *, struct lxc_netdev *);
-
-static  instantiate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
-       [LXC_NET_VETH]    = shutdown_veth,
-       [LXC_NET_MACVLAN] = shutdown_macvlan,
-       [LXC_NET_VLAN]    = shutdown_vlan,
-       [LXC_NET_PHYS]    = shutdown_phys,
-       [LXC_NET_EMPTY]   = shutdown_empty,
-       [LXC_NET_NONE]    = shutdown_none,
-};
-
 static struct mount_opt mount_opt[] = {
        { "async",         1, MS_SYNCHRONOUS },
        { "atime",         1, MS_NOATIME     },
@@ -529,8 +497,7 @@ static int run_script_argv(const char *name, const char *section,
        return run_buffer(buffer);
 }
 
-static int run_script(const char *name, const char *section, const char *script,
-                     ...)
+int run_script(const char *name, const char *section, const char *script, ...)
 {
        int ret;
        char *buffer, *p;
@@ -816,7 +783,7 @@ static const struct dev_symlinks dev_symlinks[] = {
        {"/proc/self/fd/2",     "stderr"},
 };
 
-static int setup_dev_symlinks(const struct lxc_rootfs *rootfs)
+static int lxc_setup_dev_symlinks(const struct lxc_rootfs *rootfs)
 {
        char path[MAXPATHLEN];
        int ret,i;
@@ -851,9 +818,7 @@ static int setup_dev_symlinks(const struct lxc_rootfs *rootfs)
        return 0;
 }
 
-/*
- * Build a space-separate list of ptys to pass to systemd.
- */
+/* Build a space-separate list of ptys to pass to systemd. */
 static bool append_ptyname(char **pp, char *name)
 {
        char *p;
@@ -874,7 +839,7 @@ static bool append_ptyname(char **pp, char *name)
        return true;
 }
 
-static int lxc_setup_tty(struct lxc_conf *conf)
+static int lxc_setup_ttys(struct lxc_conf *conf)
 {
        int i, ret;
        const struct lxc_tty_info *tty_info = &conf->tty_info;
@@ -888,23 +853,19 @@ static int lxc_setup_tty(struct lxc_conf *conf)
                struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
 
                ret = snprintf(path, sizeof(path), "/dev/tty%d", i + 1);
-               if (ret < 0 || (size_t)ret >= sizeof(path)) {
-                       ERROR("pathname too long for ttys");
+               if (ret < 0 || (size_t)ret >= sizeof(path))
                        return -1;
-               }
 
                if (ttydir) {
                        /* create dev/lxc/tty%d" */
                        ret = snprintf(lxcpath, sizeof(lxcpath),
                                       "/dev/%s/tty%d", ttydir, i + 1);
-                       if (ret < 0 || (size_t)ret >= sizeof(lxcpath)) {
-                               ERROR("pathname too long for ttys");
+                       if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
                                return -1;
-                       }
 
                        ret = creat(lxcpath, 0660);
                        if (ret < 0 && errno != EEXIST) {
-                               SYSERROR("failed to create \"%s\"", lxcpath);
+                               SYSERROR("Failed to create \"%s\"", lxcpath);
                                return -1;
                        }
                        if (ret >= 0)
@@ -912,13 +873,13 @@ static int lxc_setup_tty(struct lxc_conf *conf)
 
                        ret = unlink(path);
                        if (ret < 0 && errno != ENOENT) {
-                               SYSERROR("failed to unlink \"%s\"", path);
+                               SYSERROR("Failed to unlink \"%s\"", path);
                                return -1;
                        }
 
                        ret = mount(pty_info->name, lxcpath, "none", MS_BIND, 0);
                        if (ret < 0) {
-                               WARN("failed to bind mount \"%s\" onto \"%s\"",
+                               WARN("Failed to bind mount \"%s\" onto \"%s\"",
                                     pty_info->name, path);
                                continue;
                        }
@@ -927,14 +888,12 @@ static int lxc_setup_tty(struct lxc_conf *conf)
 
                        ret = snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d",
                                       ttydir, i + 1);
-                       if (ret < 0 || (size_t)ret >= sizeof(lxcpath)) {
-                               ERROR("tty pathname too long");
+                       if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
                                return -1;
-                       }
 
                        ret = symlink(lxcpath, path);
                        if (ret < 0) {
-                               SYSERROR("failed to create symlink \"%s\" -> \"%s\"",
+                               SYSERROR("Failed to create symlink \"%s\" -> \"%s\"",
                                         path, lxcpath);
                                return -1;
                        }
@@ -946,7 +905,7 @@ static int lxc_setup_tty(struct lxc_conf *conf)
                        if (ret < 0) {
                                ret = creat(path, 0660);
                                if (ret < 0) {
-                                       SYSERROR("failed to create \"%s\"", path);
+                                       SYSERROR("Failed to create \"%s\"", path);
                                        /* this isn't fatal, continue */
                                } else {
                                        close(ret);
@@ -955,11 +914,11 @@ static int lxc_setup_tty(struct lxc_conf *conf)
 
                        ret = mount(pty_info->name, path, "none", MS_BIND, 0);
                        if (ret < 0) {
-                               SYSERROR("failed to mount '%s'->'%s'", pty_info->name, path);
+                               SYSERROR("Failed to mount '%s'->'%s'", pty_info->name, path);
                                continue;
                        }
 
-                       DEBUG("bind mounted \"%s\" onto \"%s\"", pty_info->name,
+                       DEBUG("Bind mounted \"%s\" onto \"%s\"", pty_info->name,
                              path);
                }
 
@@ -969,10 +928,154 @@ static int lxc_setup_tty(struct lxc_conf *conf)
                }
        }
 
-       INFO("finished setting up %d /dev/tty<N> device(s)", tty_info->nbtty);
+       INFO("Finished setting up %d /dev/tty<N> device(s)", tty_info->nbtty);
+       return 0;
+}
+
+int lxc_allocate_ttys(const char *name, struct lxc_conf *conf)
+{
+       struct lxc_tty_info *tty_info = &conf->tty_info;
+       int i, ret;
+
+       /* no tty in the configuration */
+       if (!conf->tty)
+               return 0;
+
+       tty_info->pty_info = malloc(sizeof(*tty_info->pty_info) * conf->tty);
+       if (!tty_info->pty_info) {
+               SYSERROR("failed to allocate struct *pty_info");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < conf->tty; i++) {
+               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+               process_lock();
+               ret = openpty(&pty_info->master, &pty_info->slave,
+                             pty_info->name, NULL, NULL);
+               process_unlock();
+               if (ret) {
+                       SYSERROR("failed to create pty device number %d", i);
+                       tty_info->nbtty = i;
+                       lxc_delete_tty(tty_info);
+                       return -ENOTTY;
+               }
+
+               DEBUG("allocated pty \"%s\" with master fd %d and slave fd %d",
+                     pty_info->name, pty_info->master, pty_info->slave);
+
+               /* Prevent leaking the file descriptors to the container */
+               ret = fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
+               if (ret < 0)
+                       WARN("failed to set FD_CLOEXEC flag on master fd %d of "
+                            "pty device \"%s\": %s",
+                            pty_info->master, pty_info->name, strerror(errno));
+
+               ret = fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
+               if (ret < 0)
+                       WARN("failed to set FD_CLOEXEC flag on slave fd %d of "
+                            "pty device \"%s\": %s",
+                            pty_info->slave, pty_info->name, strerror(errno));
+
+               pty_info->busy = 0;
+       }
+
+       tty_info->nbtty = conf->tty;
+
+       INFO("finished allocating %d pts devices", conf->tty);
        return 0;
 }
 
+void lxc_delete_tty(struct lxc_tty_info *tty_info)
+{
+       int i;
+
+       for (i = 0; i < tty_info->nbtty; i++) {
+               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+               close(pty_info->master);
+               close(pty_info->slave);
+       }
+
+       free(tty_info->pty_info);
+       tty_info->pty_info = NULL;
+       tty_info->nbtty = 0;
+}
+
+static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
+{
+       int i;
+       struct lxc_conf *conf = handler->conf;
+       struct lxc_tty_info *tty_info = &conf->tty_info;
+       int sock = handler->data_sock[0];
+       int ret = -1;
+
+       if (!conf->tty)
+               return 0;
+
+       for (i = 0; i < conf->tty; i++) {
+               int ttyfds[2];
+               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+               ttyfds[0] = pty_info->master;
+               ttyfds[1] = pty_info->slave;
+
+               ret = lxc_abstract_unix_send_fds(sock, ttyfds, 2, NULL, 0);
+               if (ret < 0)
+                       break;
+
+               TRACE("Send pty \"%s\" with master fd %d and slave fd %d to "
+                     "parent", pty_info->name, pty_info->master, pty_info->slave);
+       }
+
+       if (ret < 0)
+               ERROR("Failed to send %d ttys to parent: %s", conf->tty,
+                     strerror(errno));
+       else
+               TRACE("Sent %d ttys to parent", conf->tty);
+
+       return ret;
+}
+
+static int lxc_create_ttys(struct lxc_handler *handler)
+{
+       int ret = -1;
+       struct lxc_conf *conf = handler->conf;
+
+       ret = lxc_allocate_ttys(handler->name, conf);
+       if (ret < 0) {
+               ERROR("Failed to allocate ttys");
+               goto on_error;
+       }
+
+       ret = lxc_send_ttys_to_parent(handler);
+       if (ret < 0) {
+               ERROR("Failed to send ttys to parent");
+               goto on_error;
+       }
+
+       if (!conf->is_execute) {
+               ret = lxc_setup_ttys(conf);
+               if (ret < 0) {
+                       ERROR("Failed to setup ttys");
+                       goto on_error;
+               }
+       }
+
+       if (conf->pty_names) {
+               ret = setenv("container_ttys", conf->pty_names, 1);
+               if (ret < 0)
+                       SYSERROR("Failed to set \"container_ttys=%s\"", conf->pty_names);
+       }
+
+       ret = 0;
+
+on_error:
+       lxc_delete_tty(&conf->tty_info);
+
+       return ret;
+}
+
 static int setup_rootfs_pivot_root(const char *rootfs)
 {
        int oldroot = -1, newroot = -1;
@@ -1034,58 +1137,56 @@ fail:
        return -1;
 }
 
-/*
- * Just create a path for /dev under $lxcpath/$name and in rootfs
- * If we hit an error, log it but don't fail yet.
+/* Just create a path for /dev under $lxcpath/$name and in rootfs If we hit an
+ * error, log it but don't fail yet.
  */
-static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, const char *lxcpath)
+static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs,
+                        const char *lxcpath)
 {
        int ret;
        size_t clen;
        char *path;
 
-       INFO("Mounting container /dev");
+       INFO("Preparing \"/dev\"");
 
        /* $(rootfs->mount) + "/dev/pts" + '\0' */
        clen = (rootfs->path ? strlen(rootfs->mount) : 0) + 9;
        path = alloca(clen);
 
        ret = snprintf(path, clen, "%s/dev", rootfs->path ? rootfs->mount : "");
-       if (ret < 0 || ret >= clen)
+       if (ret < 0 || (size_t)ret >= clen)
                return -1;
 
        if (!dir_exists(path)) {
-               WARN("No /dev in container.");
-               WARN("Proceeding without autodev setup");
+               WARN("\"/dev\" directory does not exist. Proceeding without "
+                    "autodev being set up");
                return 0;
        }
 
        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);
+                        rootfs->path ? rootfs->mount : NULL);
+       if (ret < 0) {
+               SYSERROR("Failed to mount tmpfs on \"%s\"", path);
                return -1;
        }
-
-       INFO("Mounted tmpfs onto %s",  path);
+       INFO("Mounted tmpfs on \"%s\"", path);
 
        ret = snprintf(path, clen, "%s/dev/pts", rootfs->path ? rootfs->mount : "");
-       if (ret < 0 || ret >= clen)
+       if (ret < 0 || (size_t)ret >= clen)
                return -1;
 
-       /*
-        * If we are running on a devtmpfs mapping, dev/pts may already exist.
+       /* If we are running on a devtmpfs mapping, dev/pts may already exist.
         * If not, then create it and exit if that fails...
         */
        if (!dir_exists(path)) {
                ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
-               if (ret) {
-                       SYSERROR("Failed to create /dev/pts in container");
+               if (ret < 0) {
+                       SYSERROR("Failed to create directory \"%s\"", path);
                        return -1;
                }
        }
 
-       INFO("Mounted container /dev");
+       INFO("Prepared \"/dev\"");
        return 0;
 }
 
@@ -1097,12 +1198,12 @@ struct lxc_devs {
 };
 
 static const struct lxc_devs lxc_devs[] = {
-       { "null",       S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 3     },
-       { "zero",       S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 5     },
-       { "full",       S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 7     },
-       { "urandom",    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 9     },
-       { "random",     S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 8     },
-       { "tty",        S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 5, 0     },
+       { "null",    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 3 },
+       { "zero",    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 5 },
+       { "full",    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 7 },
+       { "urandom", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 9 },
+       { "random",  S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 8 },
+       { "tty",     S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 5, 0 },
 };
 
 static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
@@ -1112,29 +1213,30 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
        int i;
        mode_t cmask;
 
-       ret = snprintf(path, MAXPATHLEN, "%s/dev", rootfs->path ? rootfs->mount : "");
-       if (ret < 0 || ret >= MAXPATHLEN) {
-               ERROR("Error calculating container /dev location");
+       ret = snprintf(path, MAXPATHLEN, "%s/dev",
+                      rootfs->path ? rootfs->mount : "");
+       if (ret < 0 || ret >= MAXPATHLEN)
                return -1;
-       }
 
        /* ignore, just don't try to fill in */
        if (!dir_exists(path))
                return 0;
 
-       INFO("populating container /dev");
+       INFO("Populating \"/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];
 
-               ret = snprintf(path, MAXPATHLEN, "%s/dev/%s", rootfs->path ? rootfs->mount : "", d->name);
+               ret = snprintf(path, MAXPATHLEN, "%s/dev/%s",
+                              rootfs->path ? rootfs->mount : "", d->name);
                if (ret < 0 || ret >= MAXPATHLEN)
                        return -1;
 
                ret = mknod(path, d->mode, makedev(d->maj, d->min));
                if (ret < 0) {
-                       char hostpath[MAXPATHLEN];
                        FILE *pathfile;
+                       char hostpath[MAXPATHLEN];
 
                        if (errno == EEXIST) {
                                DEBUG("\"%s\" device already existed", path);
@@ -1147,31 +1249,38 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
                        ret = snprintf(hostpath, MAXPATHLEN, "/dev/%s", d->name);
                        if (ret < 0 || ret >= MAXPATHLEN)
                                return -1;
+
                        pathfile = fopen(path, "wb");
                        if (!pathfile) {
-                               SYSERROR("Failed to create device mount target '%s'", path);
+                               SYSERROR("Failed to create file \"%s\"", path);
                                return -1;
                        }
                        fclose(pathfile);
-                       if (safe_mount(hostpath, path, 0, MS_BIND, NULL, rootfs->path ? rootfs->mount : NULL) != 0) {
-                               SYSERROR("Failed bind mounting device %s from host into container", d->name);
+
+                       ret = safe_mount(hostpath, path, 0, MS_BIND, NULL,
+                                        rootfs->path ? rootfs->mount : NULL);
+                       if (ret < 0) {
+                               SYSERROR("Failed to bind mount \"%s\" from "
+                                        "host into container",
+                                        d->name);
                                return -1;
                        }
-                       DEBUG("bind mounted \"%s\" onto \"%s\"", hostpath, path);
+                       DEBUG("Bind mounted \"%s\" onto \"%s\"", hostpath,
+                             path);
                } else {
-                       DEBUG("created device node \"%s\"", path);
+                       DEBUG("Created device node \"%s\"", path);
                }
        }
        umask(cmask);
 
-       INFO("populated container /dev");
+       INFO("Populated \"/dev\"");
        return 0;
 }
 
 static int lxc_setup_rootfs(struct lxc_conf *conf)
 {
        int ret;
-       struct bdev *bdev;
+       struct lxc_storage *bdev;
        const struct lxc_rootfs *rootfs;
 
        rootfs = &conf->rootfs;
@@ -1189,7 +1298,7 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
                return -1;
        }
 
-       bdev = bdev_init(conf, rootfs->path, rootfs->mount, rootfs->options);
+       bdev = storage_init(conf, rootfs->path, rootfs->mount, rootfs->options);
        if (!bdev) {
                ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\".",
                      rootfs->path, rootfs->mount,
@@ -1198,7 +1307,7 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
        }
 
        ret = bdev->ops->mount(bdev);
-       bdev_put(bdev);
+       storage_put(bdev);
        if (ret < 0) {
                ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\".",
                      rootfs->path, rootfs->mount,
@@ -1332,7 +1441,8 @@ static int setup_pivot_root(const struct lxc_rootfs *rootfs)
 static int lxc_setup_devpts(int num_pts)
 {
        int ret;
-       const char *devpts_mntopts = "newinstance,ptmxmode=0666,mode=0620,gid=5";
+       const char *default_devpts_mntopts = "newinstance,ptmxmode=0666,mode=0620,gid=5";
+       char devpts_mntopts[256];
 
        if (!num_pts) {
                DEBUG("no new devpts instance will be mounted since no pts "
@@ -1340,6 +1450,11 @@ static int lxc_setup_devpts(int num_pts)
                return 0;
        }
 
+       ret = snprintf(devpts_mntopts, sizeof(devpts_mntopts), "%s,max=%d",
+                      default_devpts_mntopts, num_pts);
+       if (ret < 0 || (size_t)ret >= sizeof(devpts_mntopts))
+               return -1;
+
        /* Unmount old devpts instance. */
        ret = access("/dev/pts/ptmx", F_OK);
        if (!ret) {
@@ -1507,7 +1622,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
                SYSERROR("failed with errno %d to create %s", errno, path);
                return -errno;
        }
-       DEBUG("created directory for console and tty devices at \%s\"", path);
+       DEBUG("Created directory for console and tty devices at \"%s\"", path);
 
        ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/console", rootfs->mount, ttydir);
        if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
@@ -1720,174 +1835,201 @@ static char *get_field(char *src, int nfields)
 
 static int mount_entry(const char *fsname, const char *target,
                       const char *fstype, unsigned long mountflags,
-                      const char *data, int optional, int dev, const char *rootfs)
+                      const char *data, int optional, int dev,
+                      const char *rootfs)
 {
+       int ret;
 #ifdef HAVE_STATVFS
        struct statvfs sb;
 #endif
 
-       if (safe_mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data, rootfs)) {
+       ret = safe_mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data,
+                        rootfs);
+       if (ret < 0) {
                if (optional) {
-                       INFO("failed to mount '%s' on '%s' (optional): %s", fsname,
-                            target, strerror(errno));
+                       INFO("Failed to mount \"%s\" on \"%s\" (optional): %s",
+                            fsname, target, strerror(errno));
                        return 0;
                }
-               else {
-                       SYSERROR("failed to mount '%s' on '%s'", fsname, target);
-                       return -1;
-               }
+
+               SYSERROR("Failed to mount \"%s\" on \"%s\"", fsname, target);
+               return -1;
        }
 
        if ((mountflags & MS_REMOUNT) || (mountflags & MS_BIND)) {
-               DEBUG("remounting %s on %s to respect bind or remount options",
-                     fsname ? fsname : "(none)", target ? target : "(none)");
                unsigned long rqd_flags = 0;
+
+               DEBUG("Remounting \"%s\" on \"%s\" to respect bind or remount "
+                     "options",
+                     fsname ? fsname : "(none)", target ? target : "(none)");
+
                if (mountflags & MS_RDONLY)
                        rqd_flags |= MS_RDONLY;
 #ifdef HAVE_STATVFS
                if (statvfs(fsname, &sb) == 0) {
                        unsigned long required_flags = rqd_flags;
+
                        if (sb.f_flag & MS_NOSUID)
                                required_flags |= MS_NOSUID;
+
                        if (sb.f_flag & MS_NODEV && !dev)
                                required_flags |= MS_NODEV;
+
                        if (sb.f_flag & MS_RDONLY)
                                required_flags |= MS_RDONLY;
+
                        if (sb.f_flag & MS_NOEXEC)
                                required_flags |= MS_NOEXEC;
-                       DEBUG("(at remount) flags for %s was %lu, required extra flags are %lu", fsname, sb.f_flag, required_flags);
-                       /*
-                        * If this was a bind mount request, and required_flags
+
+                       DEBUG("Flags for \"%s\" were %lu, required extra flags "
+                             "are %lu", fsname, sb.f_flag, required_flags);
+
+                       /* If this was a bind mount request, and required_flags
                         * does not have any flags which are not already in
-                        * mountflags, then skip the remount
+                        * mountflags, then skip the remount.
                         */
                        if (!(mountflags & MS_REMOUNT)) {
-                               if (!(required_flags & ~mountflags) && rqd_flags == 0) {
-                                       DEBUG("mountflags already was %lu, skipping remount",
-                                               mountflags);
+                               if (!(required_flags & ~mountflags) &&
+                                   rqd_flags == 0) {
+                                       DEBUG("Mountflags already were %lu, "
+                                             "skipping remount", mountflags);
                                        goto skipremount;
                                }
                        }
+
                        mountflags |= required_flags;
                }
 #endif
 
-               if (mount(fsname, target, fstype,
-                         mountflags | MS_REMOUNT, data) < 0) {
+               ret = mount(fsname, target, fstype, mountflags | MS_REMOUNT, data);
+               if (ret < 0) {
                        if (optional) {
-                               INFO("failed to mount '%s' on '%s' (optional): %s",
-                                        fsname, target, strerror(errno));
+                               INFO("Failed to mount \"%s\" on \"%s\" "
+                                    "(optional): %s", fsname, target,
+                                    strerror(errno));
                                return 0;
                        }
-                       else {
-                               SYSERROR("failed to mount '%s' on '%s'",
-                                        fsname, target);
-                               return -1;
-                       }
+
+                       SYSERROR("Failed to mount \"%s\" on \"%s\"", fsname, target);
+                       return -1;
                }
        }
 
 #ifdef HAVE_STATVFS
 skipremount:
 #endif
-       DEBUG("mounted '%s' on '%s', type '%s'", fsname, target, fstype);
+       DEBUG("Mounted \"%s\" on \"%s\" with filesystem type \"%s\"", fsname,
+             target, fstype);
 
        return 0;
 }
 
-/*
- * Remove 'optional', 'create=dir', and 'create=file' from mntopt
- */
+/* Remove "optional", "create=dir", and "create=file" from mntopt */
 static void cull_mntent_opt(struct mntent *mntent)
 {
        int i;
-       char *p, *p2;
-       char *list[] = {"create=dir",
-                       "create=file",
-                       "optional",
-                       NULL };
-
-       for (i=0; list[i]; i++) {
-               if (!(p = strstr(mntent->mnt_opts, list[i])))
+       char *list[] = {"create=dir", "create=file", "optional", NULL};
+
+       for (i = 0; list[i]; i++) {
+               char *p, *p2;
+
+               p = strstr(mntent->mnt_opts, list[i]);
+               if (!p)
                        continue;
+
                p2 = strchr(p, ',');
                if (!p2) {
                        /* no more mntopts, so just chop it here */
                        *p = '\0';
                        continue;
                }
-               memmove(p, p2+1, strlen(p2+1)+1);
+
+               memmove(p, p2 + 1, strlen(p2 + 1) + 1);
        }
 }
 
 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)
+                                      const char *path,
+                                      const struct lxc_rootfs *rootfs,
+                                      const char *lxc_name,
+                                      const char *lxc_path)
 {
-       char *pathdirname = NULL;
        int ret = 0;
-       FILE *pathfile = NULL;
 
-       if (strncmp(mntent->mnt_type, "overlay", 7) == 0) {
-               if (ovl_mkdir(mntent, rootfs, lxc_name, lxc_path) < 0)
-                       return -1;
-       } else if (strncmp(mntent->mnt_type, "aufs", 4) == 0) {
-               if (aufs_mkdir(mntent, rootfs, lxc_name, lxc_path) < 0)
-                       return -1;
-       }
+       if (!strncmp(mntent->mnt_type, "overlay", 7))
+               ret = ovl_mkdir(mntent, rootfs, lxc_name, lxc_path);
+       else if (!strncmp(mntent->mnt_type, "aufs", 4))
+               ret = aufs_mkdir(mntent, rootfs, lxc_name, lxc_path);
+       if (ret < 0)
+               return -1;
 
        if (hasmntopt(mntent, "create=dir")) {
-               if (mkdir_p(path, 0755) < 0) {
-                       WARN("Failed to create mount target '%s'", path);
-                       ret = -1;
+               ret = mkdir_p(path, 0755);
+               if (ret < 0 && errno != EEXIST) {
+                       SYSERROR("Failed to create directory \"%s\"", path);
+                       return -1;
                }
        }
 
        if (hasmntopt(mntent, "create=file") && access(path, F_OK)) {
-               pathdirname = strdup(path);
-               pathdirname = dirname(pathdirname);
-               if (mkdir_p(pathdirname, 0755) < 0) {
-                       WARN("Failed to create target directory");
-               }
-               pathfile = fopen(path, "wb");
-               if (!pathfile) {
-                       WARN("Failed to create mount target '%s'", path);
-                       ret = -1;
-               } else {
-                       fclose(pathfile);
+               int fd;
+               char *p1, *p2;
+
+               p1 = strdup(path);
+               if (!p1)
+                       return -1;
+
+               p2 = dirname(p1);
+
+               ret = mkdir_p(p2, 0755);
+               free(p1);
+               if (ret < 0 && errno != EEXIST) {
+                       SYSERROR("Failed to create directory \"%s\"", path);
+                       return -1;
                }
+
+               fd = open(path, O_CREAT, 0644);
+               if (fd < 0)
+                       return -1;
+               close(fd);
        }
-       free(pathdirname);
-       return ret;
+
+       return 0;
 }
 
 /* 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)
+                                        const char *path,
+                                        const struct lxc_rootfs *rootfs,
+                                        const char *lxc_name,
+                                        const char *lxc_path)
 {
+       int ret;
        unsigned long mntflags;
        char *mntdata;
-       int ret;
-       bool optional = hasmntopt(mntent, "optional") != NULL;
-       bool dev = hasmntopt(mntent, "dev") != NULL;
-
+       bool dev, optional;
        char *rootfs_path = NULL;
+
+       optional = hasmntopt(mntent, "optional") != NULL;
+       dev = hasmntopt(mntent, "dev") != 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)
-               return optional ? 0 : -1;
+       ret = mount_entry_create_dir_file(mntent, path, rootfs, lxc_name,
+                                         lxc_path);
+       if (ret < 0) {
+               if (optional)
+                       return 0;
 
+               return -1;
+       }
        cull_mntent_opt(mntent);
 
-       if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
-               free(mntdata);
+       ret = parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata);
+       if (ret < 0)
                return -1;
-       }
 
        ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags,
                          mntdata, optional, dev, rootfs_path);
@@ -1898,20 +2040,18 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
 
 static inline int mount_entry_on_systemfs(struct mntent *mntent)
 {
-       char path[MAXPATHLEN];
        int ret;
+       char path[MAXPATHLEN];
 
        /* For containers created without a rootfs all mounts are treated as
-        * absolute paths starting at / on the host. */
+        * 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");
+       if (ret < 0 || ret >= sizeof(path))
                return -1;
-       }
 
        return mount_entry_on_generic(mntent, path, NULL, NULL, NULL);
 }
@@ -1921,21 +2061,21 @@ static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
                                          const char *lxc_name,
                                          const char *lxc_path)
 {
+       int offset;
        char *aux;
-       char path[MAXPATHLEN];
-       int r, ret = 0, offset;
        const char *lxcpath;
+       char path[MAXPATHLEN];
+       int ret = 0;
 
        lxcpath = lxc_global_config_value("lxc.lxcpath");
-       if (!lxcpath) {
-               ERROR("Out of memory");
+       if (!lxcpath)
                return -1;
-       }
 
-       /* if rootfs->path is a blockdev path, allow container fstab to
-        * use $lxcpath/CN/rootfs as the target prefix */
-       r = snprintf(path, MAXPATHLEN, "%s/%s/rootfs", lxcpath, lxc_name);
-       if (r < 0 || r >= MAXPATHLEN)
+       /* If rootfs->path is a blockdev path, allow container fstab to use
+        * <lxcpath>/<name>/rootfs" as the target prefix.
+        */
+       ret = snprintf(path, MAXPATHLEN, "%s/%s/rootfs", lxcpath, lxc_name);
+       if (ret < 0 || ret >= MAXPATHLEN)
                goto skipvarlib;
 
        aux = strstr(mntent->mnt_dir, path);
@@ -1947,19 +2087,15 @@ static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
 skipvarlib:
        aux = strstr(mntent->mnt_dir, rootfs->path);
        if (!aux) {
-               WARN("ignoring mount point '%s'", mntent->mnt_dir);
+               WARN("Ignoring mount point \"%s\"", mntent->mnt_dir);
                return ret;
        }
        offset = strlen(rootfs->path);
 
 skipabs:
-
-       r = snprintf(path, MAXPATHLEN, "%s/%s", rootfs->mount,
-                aux + offset);
-       if (r < 0 || r >= MAXPATHLEN) {
-               WARN("pathnme too long for '%s'", mntent->mnt_dir);
+       ret = snprintf(path, MAXPATHLEN, "%s/%s", rootfs->mount, aux + offset);
+       if (ret < 0 || ret >= MAXPATHLEN)
                return -1;
-       }
 
        return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path);
 }
@@ -1982,57 +2118,123 @@ static int mount_entry_on_relative_rootfs(struct mntent *mntent,
        return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path);
 }
 
-static int mount_file_entries(const struct lxc_rootfs *rootfs, FILE *file,
-       const char *lxc_name, const char *lxc_path)
+/* This logs a NOTICE() when a user specifies mounts that would conflict with
+ * devices liblxc sets up automatically.
+ */
+static void log_notice_on_conflict(const struct lxc_conf *conf, const char *src,
+                                  const char *dest)
+{
+       char *clean_mnt_fsname, *clean_mnt_dir, *tmp;
+       bool needs_warning = false;
+
+       clean_mnt_fsname = lxc_deslashify(src);
+       if (!clean_mnt_fsname)
+               return;
+
+       clean_mnt_dir = lxc_deslashify(dest);
+       if (!clean_mnt_dir) {
+               free(clean_mnt_fsname);
+               return;
+       }
+
+       tmp = clean_mnt_dir;
+       if (*tmp == '/')
+               tmp++;
+
+       if (strncmp(src, "/dev", 4) || strncmp(tmp, "dev", 3)) {
+               free(clean_mnt_dir);
+               free(clean_mnt_fsname);
+               return;
+       }
+
+       if (!conf->autodev && !conf->pts && !conf->tty &&
+           (!conf->console.path || !strcmp(conf->console.path, "none"))) {
+               free(clean_mnt_dir);
+               free(clean_mnt_fsname);
+               return;
+       }
+
+       if (!strcmp(tmp, "dev") && conf->autodev > 0)
+               needs_warning = true;
+       else if (!strcmp(tmp, "dev/pts") && (conf->autodev > 0 || conf->pts > 0))
+               needs_warning = true;
+       else if (!strcmp(tmp, "dev/ptmx") && (conf->autodev > 0 || conf->pts > 0))
+               needs_warning = true;
+       else if (!strcmp(tmp, "dev/pts/ptmx") && (conf->autodev > 0 || conf->pts > 0))
+               needs_warning = true;
+       else if (!strcmp(tmp, "dev/null") && conf->autodev > 0)
+               needs_warning = true;
+       else if (!strcmp(tmp, "dev/zero") && conf->autodev > 0)
+               needs_warning = true;
+       else if (!strcmp(tmp, "dev/full") && conf->autodev > 0)
+               needs_warning = true;
+       else if (!strcmp(tmp, "dev/urandom") && conf->autodev > 0)
+               needs_warning = true;
+       else if (!strcmp(tmp, "dev/random") && conf->autodev > 0)
+               needs_warning = true;
+       else if (!strcmp(tmp, "dev/tty") && conf->autodev > 0)
+               needs_warning = true;
+       else if (!strncmp(tmp, "dev/tty", 7) && (conf->autodev > 0 || conf->tty > 0))
+               needs_warning = true;
+
+       if (needs_warning)
+               NOTICE("Requesting to mount \"%s\" on \"%s\" while requesting "
+                      "automatic device setup under \"/dev\"",
+                      clean_mnt_fsname, clean_mnt_dir);
+
+       free(clean_mnt_dir);
+       free(clean_mnt_fsname);
+}
+
+static int mount_file_entries(const struct lxc_conf *conf,
+                             const struct lxc_rootfs *rootfs, FILE *file,
+                             const char *lxc_name, const char *lxc_path)
 {
        struct mntent mntent;
        char buf[4096];
        int ret = -1;
 
        while (getmntent_r(file, &mntent, buf, sizeof(buf))) {
+               log_notice_on_conflict(conf, mntent.mnt_fsname, mntent.mnt_dir);
 
-               if (!rootfs->path) {
-                       if (mount_entry_on_systemfs(&mntent))
-                               goto out;
-                       continue;
-               }
-
-               /* We have a separate root, mounts are relative to it */
-               if (mntent.mnt_dir[0] != '/') {
-                       if (mount_entry_on_relative_rootfs(&mntent, rootfs, lxc_name, lxc_path))
-                               goto out;
-                       continue;
-               }
-
-               if (mount_entry_on_absolute_rootfs(&mntent, rootfs, lxc_name, lxc_path))
-                       goto out;
+               if (!rootfs->path)
+                       ret = mount_entry_on_systemfs(&mntent);
+               else if (mntent.mnt_dir[0] != '/')
+                       ret = mount_entry_on_relative_rootfs(&mntent, rootfs,
+                                                            lxc_name, lxc_path);
+               else
+                       ret = mount_entry_on_absolute_rootfs(&mntent, rootfs,
+                                                            lxc_name, lxc_path);
+               if (ret < 0)
+                       return -1;
        }
-
        ret = 0;
 
-       INFO("mount points have been setup");
-out:
+       INFO("Set up mount entries");
        return ret;
 }
 
-static int setup_mount(const struct lxc_rootfs *rootfs, const char *fstab,
-       const char *lxc_name, const char *lxc_path)
+static int setup_mount(const struct lxc_conf *conf,
+                      const struct lxc_rootfs *rootfs, const char *fstab,
+                      const char *lxc_name, const char *lxc_path)
 {
-       FILE *file;
+       FILE *f;
        int ret;
 
        if (!fstab)
                return 0;
 
-       file = setmntent(fstab, "r");
-       if (!file) {
-               SYSERROR("failed to use '%s'", fstab);
+       f = setmntent(fstab, "r");
+       if (!f) {
+               SYSERROR("Failed to open \"%s\"", fstab);
                return -1;
        }
 
-       ret = mount_file_entries(rootfs, file, lxc_name, lxc_path);
+       ret = mount_file_entries(conf, rootfs, f, lxc_name, lxc_path);
+       if (ret < 0)
+               ERROR("Failed to set up mount entries");
 
-       endmntent(file);
+       endmntent(f);
        return ret;
 }
 
@@ -2041,55 +2243,59 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount)
        int ret;
        char *mount_entry;
        struct lxc_list *iterator;
-       FILE *file;
+       FILE *f;
        int fd = -1;
 
        fd = memfd_create("lxc_mount_file", MFD_CLOEXEC);
        if (fd < 0) {
                if (errno != ENOSYS)
                        return NULL;
-               file = tmpfile();
+               f = tmpfile();
+               TRACE("Created temporary mount file");
        } else {
-               file = fdopen(fd, "r+");
+               f = fdopen(fd, "r+");
+               TRACE("Created anonymous mount file");
        }
 
-       if (!file) {
-               int saved_errno = errno;
+       if (!f) {
+               SYSERROR("Could not create mount file");
                if (fd != -1)
                        close(fd);
-               ERROR("Could not create mount entry file: %s.", strerror(saved_errno));
                return NULL;
        }
 
        lxc_list_for_each(iterator, mount) {
                mount_entry = iterator->elem;
-               ret = fprintf(file, "%s\n", mount_entry);
+               ret = fprintf(f, "%s\n", mount_entry);
                if (ret < strlen(mount_entry))
-                       WARN("Could not write mount entry to anonymous mount file.");
+                       WARN("Could not write mount entry to mount file");
        }
 
-       if (fseek(file, 0, SEEK_SET) < 0) {
-               fclose(file);
+       ret = fseek(f, 0, SEEK_SET);
+       if (ret < 0) {
+               SYSERROR("Failed to seek mount file");
+               fclose(f);
                return NULL;
        }
 
-       return file;
+       return f;
 }
 
-static int setup_mount_entries(const struct lxc_rootfs *rootfs,
+static int setup_mount_entries(const struct lxc_conf *conf,
+                              const struct lxc_rootfs *rootfs,
                               struct lxc_list *mount, const char *lxc_name,
                               const char *lxc_path)
 {
-       FILE *file;
+       FILE *f;
        int ret;
 
-       file = make_anonymous_mount_file(mount);
-       if (!file)
+       f = make_anonymous_mount_file(mount);
+       if (!f)
                return -1;
 
-       ret = mount_file_entries(rootfs, file, lxc_name, lxc_path);
+       ret = mount_file_entries(conf, rootfs, f, lxc_name, lxc_path);
 
-       fclose(file);
+       fclose(f);
        return ret;
 }
 
@@ -2185,7 +2391,7 @@ static int dropcaps_except(struct lxc_list *caps)
        if (numcaps <= 0 || numcaps > 200)
                return -1;
 
-       // caplist[i] is 1 if we keep capability i
+       /* caplist[i] is 1 if we keep capability i */
        int *caplist = alloca(numcaps * sizeof(int));
        memset(caplist, 0, numcaps * sizeof(int));
 
@@ -2221,311 +2427,6 @@ static int dropcaps_except(struct lxc_list *caps)
        return 0;
 }
 
-static int setup_hw_addr(char *hwaddr, const char *ifname)
-{
-       struct sockaddr sockaddr;
-       struct ifreq ifr;
-       int ret, fd, saved_errno;
-
-       ret = lxc_convert_mac(hwaddr, &sockaddr);
-       if (ret) {
-               ERROR("mac address '%s' conversion failed : %s",
-                     hwaddr, strerror(-ret));
-               return -1;
-       }
-
-       memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-       ifr.ifr_name[IFNAMSIZ-1] = '\0';
-       memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
-
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-       if (fd < 0) {
-               ERROR("socket failure : %s", strerror(errno));
-               return -1;
-       }
-
-       ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
-       saved_errno = errno;
-       close(fd);
-       if (ret)
-               ERROR("ioctl failure : %s", strerror(saved_errno));
-
-       DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifr.ifr_name);
-
-       return ret;
-}
-
-static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
-{
-       struct lxc_list *iterator;
-       struct lxc_inetdev *inetdev;
-       int err;
-
-       lxc_list_for_each(iterator, ip) {
-
-               inetdev = iterator->elem;
-
-               err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
-                                       &inetdev->bcast, inetdev->prefix);
-               if (err) {
-                       ERROR("failed to setup_ipv4_addr ifindex %d : %s",
-                             ifindex, strerror(-err));
-                       return -1;
-               }
-       }
-
-       return 0;
-}
-
-static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
-{
-       struct lxc_list *iterator;
-       struct lxc_inet6dev *inet6dev;
-       int err;
-
-       lxc_list_for_each(iterator, ip) {
-
-               inet6dev = iterator->elem;
-
-               err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
-                                       &inet6dev->mcast, &inet6dev->acast,
-                                       inet6dev->prefix);
-               if (err) {
-                       ERROR("failed to setup_ipv6_addr ifindex %d : %s",
-                             ifindex, strerror(-err));
-                       return -1;
-               }
-       }
-
-       return 0;
-}
-
-static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
-{
-       char ifname[IFNAMSIZ];
-       int err;
-       const char *net_type_name;
-       char *current_ifname = ifname;
-
-       /* empty network namespace */
-       if (!netdev->ifindex) {
-               if (netdev->flags & IFF_UP) {
-                       err = lxc_netdev_up("lo");
-                       if (err) {
-                               ERROR("failed to set the loopback up : %s",
-                                     strerror(-err));
-                               return -1;
-                       }
-               }
-
-               if (netdev->type == LXC_NET_EMPTY)
-                       return 0;
-
-               if (netdev->type == LXC_NET_NONE)
-                       return 0;
-
-               if (netdev->type != LXC_NET_VETH) {
-                       net_type_name = lxc_net_type_to_str(netdev->type);
-                       ERROR("%s networks are not supported for containers "
-                             "not setup up by privileged users",
-                             net_type_name);
-                       return -1;
-               }
-
-               netdev->ifindex = if_nametoindex(netdev->name);
-       }
-
-       /* get the new ifindex in case of physical netdev */
-       if (netdev->type == LXC_NET_PHYS) {
-               if (!(netdev->ifindex = if_nametoindex(netdev->link))) {
-                       ERROR("failed to get ifindex for %s",
-                               netdev->link);
-                       return -1;
-               }
-       }
-
-       /* retrieve the name of the interface */
-       if (!if_indextoname(netdev->ifindex, current_ifname)) {
-               ERROR("no interface corresponding to index '%d'",
-                     netdev->ifindex);
-               return -1;
-       }
-
-       /* default: let the system to choose one interface name */
-       if (!netdev->name)
-               netdev->name = netdev->type == LXC_NET_PHYS ?
-                       netdev->link : "eth%d";
-
-       /* rename the interface name */
-       if (strcmp(ifname, netdev->name) != 0) {
-               err = lxc_netdev_rename_by_name(ifname, netdev->name);
-               if (err) {
-                       ERROR("failed to rename %s->%s : %s", ifname, netdev->name,
-                             strerror(-err));
-                       return -1;
-               }
-       }
-
-       /* Re-read the name of the interface because its name has changed
-        * and would be automatically allocated by the system
-        */
-       if (!if_indextoname(netdev->ifindex, current_ifname)) {
-               ERROR("no interface corresponding to index '%d'",
-                     netdev->ifindex);
-               return -1;
-       }
-
-       /* set a mac address */
-       if (netdev->hwaddr) {
-               if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
-                       ERROR("failed to setup hw address for '%s'",
-                             current_ifname);
-                       return -1;
-               }
-       }
-
-       /* setup ipv4 addresses on the interface */
-       if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
-               ERROR("failed to setup ip addresses for '%s'",
-                             ifname);
-               return -1;
-       }
-
-       /* setup ipv6 addresses on the interface */
-       if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
-               ERROR("failed to setup ipv6 addresses for '%s'",
-                             ifname);
-               return -1;
-       }
-
-       /* set the network device up */
-       if (netdev->flags & IFF_UP) {
-               int err;
-
-               err = lxc_netdev_up(current_ifname);
-               if (err) {
-                       ERROR("failed to set '%s' up : %s", current_ifname,
-                             strerror(-err));
-                       return -1;
-               }
-
-               /* the network is up, make the loopback up too */
-               err = lxc_netdev_up("lo");
-               if (err) {
-                       ERROR("failed to set the loopback up : %s",
-                             strerror(-err));
-                       return -1;
-               }
-       }
-
-       /* We can only set up the default routes after bringing
-        * up the interface, sine bringing up the interface adds
-        * the link-local routes and we can't add a default
-        * route if the gateway is not reachable. */
-
-       /* setup ipv4 gateway on the interface */
-       if (netdev->ipv4_gateway) {
-               if (!(netdev->flags & IFF_UP)) {
-                       ERROR("Cannot add ipv4 gateway for %s when not bringing up the interface", ifname);
-                       return -1;
-               }
-
-               if (lxc_list_empty(&netdev->ipv4)) {
-                       ERROR("Cannot add ipv4 gateway for %s when not assigning an address", ifname);
-                       return -1;
-               }
-
-               err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
-               if (err) {
-                       err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway);
-                       if (err) {
-                               ERROR("failed to add ipv4 dest for '%s': %s",
-                                             ifname, strerror(-err));
-                       }
-
-                       err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
-                       if (err) {
-                               ERROR("failed to setup ipv4 gateway for '%s': %s",
-                                             ifname, strerror(-err));
-                               if (netdev->ipv4_gateway_auto) {
-                                       char buf[INET_ADDRSTRLEN];
-                                       inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
-                                       ERROR("tried to set autodetected ipv4 gateway '%s'", buf);
-                               }
-                               return -1;
-                       }
-               }
-       }
-
-       /* setup ipv6 gateway on the interface */
-       if (netdev->ipv6_gateway) {
-               if (!(netdev->flags & IFF_UP)) {
-                       ERROR("Cannot add ipv6 gateway for %s when not bringing up the interface", ifname);
-                       return -1;
-               }
-
-               if (lxc_list_empty(&netdev->ipv6) && !IN6_IS_ADDR_LINKLOCAL(netdev->ipv6_gateway)) {
-                       ERROR("Cannot add ipv6 gateway for %s when not assigning an address", ifname);
-                       return -1;
-               }
-
-               err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
-               if (err) {
-                       err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway);
-                       if (err) {
-                               ERROR("failed to add ipv6 dest for '%s': %s",
-                                     ifname, strerror(-err));
-                       }
-
-                       err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
-                       if (err) {
-                               ERROR("failed to setup ipv6 gateway for '%s': %s",
-                                             ifname, strerror(-err));
-                               if (netdev->ipv6_gateway_auto) {
-                                       char buf[INET6_ADDRSTRLEN];
-                                       inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
-                                       ERROR("tried to set autodetected ipv6 gateway '%s'", buf);
-                               }
-                               return -1;
-                       }
-               }
-       }
-
-       DEBUG("'%s' has been setup", current_ifname);
-
-       return 0;
-}
-
-static int lxc_setup_networks_in_child_namespaces(const struct lxc_conf *conf,
-                                                 struct lxc_list *network)
-{
-       struct lxc_list *iterator;
-       struct lxc_netdev *netdev;
-
-       lxc_log_configured_netdevs(conf);
-
-       lxc_list_for_each(iterator, network) {
-               netdev = iterator->elem;
-
-               /* REMOVE in LXC 3.0 */
-               if (netdev->idx < 0) {
-                       ERROR("WARNING: using \"lxc.network.*\" keys to define "
-                             "networks is DEPRECATED, please switch to using "
-                             "\"lxc.net.[i].* keys\"");
-               }
-
-               if (lxc_setup_netdev_in_child_namespaces(netdev)) {
-                       ERROR("failed to setup netdev");
-                       return -1;
-               }
-       }
-
-       if (!lxc_list_empty(network))
-               INFO("network has been setup");
-
-       return 0;
-}
-
 static int parse_resource(const char *res) {
        size_t i;
        int resid = -1;
@@ -2565,46 +2466,6 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
        return 0;
 }
 
-/* try to move physical nics to the init netns */
-void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf)
-{
-       int i, oldfd;
-       char ifname[IFNAMSIZ];
-
-       if (netnsfd < 0 || conf->num_savednics == 0)
-               return;
-
-       INFO("Running to reset %d nic names.", conf->num_savednics);
-
-       oldfd = lxc_preserve_ns(getpid(), "net");
-       if (oldfd < 0) {
-               SYSERROR("Failed to open monitor netns fd.");
-               return;
-       }
-
-       if (setns(netnsfd, 0) != 0) {
-               SYSERROR("Failed to enter container netns to reset nics");
-               close(oldfd);
-               return;
-       }
-       for (i=0; i<conf->num_savednics; i++) {
-               struct saved_nic *s = &conf->saved_nics[i];
-               /* 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, s->orig_name))
-                       WARN("Error moving nic name:%s back to host netns", ifname);
-               free(s->orig_name);
-       }
-       conf->num_savednics = 0;
-
-       if (setns(oldfd, 0) != 0)
-               SYSERROR("Failed to re-enter monitor's netns");
-       close(oldfd);
-}
-
 static char *default_rootfs_mount = LXCROOTFSMOUNT;
 
 struct lxc_conf *lxc_conf_init(void)
@@ -2665,731 +2526,87 @@ struct lxc_conf *lxc_conf_init(void)
         * default to running as UID/GID 0 when using lxc-execute */
        new->init_uid = 0;
        new->init_gid = 0;
+       memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
 
        return new;
 }
 
-static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
+static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
+                           size_t buf_size)
 {
-       char *veth1, *veth2;
-       char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
-       int bridge_index, err;
-       unsigned int mtu = 0;
-
-       if (netdev->priv.veth_attr.pair) {
-               veth1 = netdev->priv.veth_attr.pair;
-               if (handler->conf->reboot)
-                       lxc_netdev_delete_by_name(veth1);
-       } else {
-               err = snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
-               if (err >= sizeof(veth1buf)) { /* can't *really* happen, but... */
-                       ERROR("veth1 name too long");
-                       return -1;
-               }
-               veth1 = lxc_mkifname(veth1buf);
-               if (!veth1) {
-                       ERROR("failed to allocate a temporary name");
-                       return -1;
-               }
-               /* store away for deconf */
-               memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
-       }
-
-       snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
-       veth2 = lxc_mkifname(veth2buf);
-       if (!veth2) {
-               ERROR("failed to allocate a temporary name");
-               goto out_delete;
-       }
-
-       err = lxc_veth_create(veth1, veth2);
-       if (err) {
-               ERROR("failed to create veth pair \"%s\" and \"%s\": %s", veth1,
-                     veth2, strerror(-err));
-               goto out_delete;
-       }
-
-       /* changing the high byte of the mac address to 0xfe, the bridge interface
-        * will always keep the host's mac address and not take the mac address
-        * of a container */
-       err = setup_private_host_hw_addr(veth1);
-       if (err) {
-               ERROR("failed to change mac address of host interface \"%s\": %s",
-                     veth1, strerror(-err));
-               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) {
-               if (lxc_safe_uint(netdev->mtu, &mtu) < 0)
-                       WARN("failed to parse mtu from");
-               else
-                       INFO("retrieved mtu %d", mtu);
-       } else if (netdev->link) {
-               bridge_index = if_nametoindex(netdev->link);
-               if (bridge_index) {
-                       mtu = netdev_get_mtu(bridge_index);
-                       INFO("retrieved mtu %d from %s", mtu, netdev->link);
-               } else {
-                       mtu = netdev_get_mtu(netdev->ifindex);
-                       INFO("retrieved mtu %d from %s", mtu, veth2);
-               }
-       }
-
-       if (mtu) {
-               err = lxc_netdev_set_mtu(veth1, mtu);
-               if (!err)
-                       err = lxc_netdev_set_mtu(veth2, mtu);
-               if (err) {
-                       ERROR("failed to set mtu \"%d\" for veth pair \"%s\" "
-                             "and \"%s\": %s",
-                             mtu, veth1, veth2, strerror(-err));
-                       goto out_delete;
-               }
-       }
+       char path[MAXPATHLEN];
+       int fd, ret;
 
-       if (netdev->link) {
-               err = lxc_bridge_attach(handler->lxcpath, handler->name, netdev->link, veth1);
-               if (err) {
-                       ERROR("failed to attach \"%s\" to bridge \"%s\": %s",
-                             veth1, netdev->link, strerror(-err));
-                       goto out_delete;
-               }
-               INFO("attached \"%s\" to bridge \"%s\"", veth1, netdev->link);
+       ret = snprintf(path, MAXPATHLEN, "/proc/%d/%cid_map", pid,
+                      idtype == ID_TYPE_UID ? 'u' : 'g');
+       if (ret < 0 || ret >= MAXPATHLEN) {
+               ERROR("failed to create path \"%s\"", path);
+               return -E2BIG;
        }
 
-       err = lxc_netdev_up(veth1);
-       if (err) {
-               ERROR("failed to set \"%s\" up: %s", veth1, strerror(-err));
-               goto out_delete;
+       fd = open(path, O_WRONLY);
+       if (fd < 0) {
+               SYSERROR("failed to open \"%s\"", path);
+               return -1;
        }
 
-       if (netdev->upscript) {
-               err = run_script(handler->name, "net", netdev->upscript, "up",
-                                "veth", veth1, (char*) NULL);
-               if (err)
-                       goto out_delete;
+       errno = 0;
+       ret = lxc_write_nointr(fd, buf, buf_size);
+       if (ret != buf_size) {
+               SYSERROR("failed to write %cid mapping to \"%s\"",
+                        idtype == ID_TYPE_UID ? 'u' : 'g', path);
+               close(fd);
+               return -1;
        }
+       close(fd);
 
-       DEBUG("instantiated veth \"%s/%s\", index is \"%d\"", veth1, veth2,
-             netdev->ifindex);
-
-       return 0;
-
-out_delete:
-       if (netdev->ifindex != 0)
-               lxc_netdev_delete_by_name(veth1);
-       if (!netdev->priv.veth_attr.pair)
-               free(veth1);
-       free(veth2);
-       return -1;
-}
-
-static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       char *veth1;
-       int err;
-
-       if (netdev->priv.veth_attr.pair)
-               veth1 = netdev->priv.veth_attr.pair;
-       else
-               veth1 = netdev->priv.veth_attr.veth1;
-
-       if (netdev->downscript) {
-               err = run_script(handler->name, "net", netdev->downscript,
-                                "down", "veth", veth1, (char*) NULL);
-               if (err)
-                       return -1;
-       }
        return 0;
 }
 
-static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+/* Check whether a binary exist and has either CAP_SETUID, CAP_SETGID or both.
+ *
+ * @return  1      if functional binary was found
+ * @return  0      if binary exists but is lacking privilege
+ * @return -ENOENT if binary does not exist
+ * @return -EINVAL if cap to check is neither CAP_SETUID nor CAP_SETGID
+ *
+ */
+static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
 {
-       char peerbuf[IFNAMSIZ], *peer;
-       int err;
-
-       if (!netdev->link) {
-               ERROR("no link specified for macvlan netdev");
-               return -1;
-       }
+       char *path;
+       int ret;
+       struct stat st;
+       int fret = 0;
 
-       err = snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX");
-       if (err >= sizeof(peerbuf))
-               return -1;
+       if (cap != CAP_SETUID && cap != CAP_SETGID)
+               return -EINVAL;
 
-       peer = lxc_mkifname(peerbuf);
-       if (!peer) {
-               ERROR("failed to make a temporary name");
-               return -1;
-       }
+       path = on_path(binary, NULL);
+       if (!path)
+               return -ENOENT;
 
-       err = lxc_macvlan_create(netdev->link, peer,
-                                netdev->priv.macvlan_attr.mode);
-       if (err) {
-               ERROR("failed to create macvlan interface '%s' on '%s' : %s",
-                     peer, netdev->link, strerror(-err));
-               goto out;
+       ret = stat(path, &st);
+       if (ret < 0) {
+               fret = -errno;
+               goto cleanup;
        }
 
-       netdev->ifindex = if_nametoindex(peer);
-       if (!netdev->ifindex) {
-               ERROR("failed to retrieve the index for %s", peer);
-               goto out;
+       /* Check if the binary is setuid. */
+       if (st.st_mode & S_ISUID) {
+               DEBUG("The binary \"%s\" does have the setuid bit set.", path);
+               fret = 1;
+               goto cleanup;
        }
 
-       if (netdev->upscript) {
-               err = run_script(handler->name, "net", netdev->upscript, "up",
-                                "macvlan", netdev->link, (char*) NULL);
-               if (err)
-                       goto out;
-       }
-
-       DEBUG("instantiated macvlan '%s', index is '%d' and mode '%d'",
-             peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
-
-       return 0;
-out:
-       lxc_netdev_delete_by_name(peer);
-       free(peer);
-       return -1;
-}
-
-static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       int err;
-
-       if (netdev->downscript) {
-               err = run_script(handler->name, "net", netdev->downscript,
-                                "down", "macvlan", netdev->link,
-                                (char*) NULL);
-               if (err)
-                       return -1;
-       }
-       return 0;
-}
-
-/* XXX: merge with instantiate_macvlan */
-static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       char peer[IFNAMSIZ];
-       int err;
-       static uint16_t vlan_cntr = 0;
-       unsigned int mtu = 0;
-
-       if (!netdev->link) {
-               ERROR("no link specified for vlan netdev");
-               return -1;
-       }
-
-       err = snprintf(peer, sizeof(peer), "vlan%d-%d", netdev->priv.vlan_attr.vid, vlan_cntr++);
-       if (err >= sizeof(peer)) {
-               ERROR("peer name too long");
-               return -1;
-       }
-
-       err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
-       if (err) {
-               ERROR("failed to create vlan interface '%s' on '%s' : %s",
-                     peer, netdev->link, strerror(-err));
-               return -1;
-       }
-
-       netdev->ifindex = if_nametoindex(peer);
-       if (!netdev->ifindex) {
-               ERROR("failed to retrieve the ifindex for %s", peer);
-               lxc_netdev_delete_by_name(peer);
-               return -1;
-       }
-
-       DEBUG("instantiated vlan '%s', ifindex is '%d'", " vlan1000",
-             netdev->ifindex);
-       if (netdev->mtu) {
-               if (lxc_safe_uint(netdev->mtu, &mtu) < 0) {
-                       ERROR("Failed to retrieve mtu from: '%d'/'%s'.",
-                             netdev->ifindex, netdev->name);
-                       return -1;
-               }
-               err = lxc_netdev_set_mtu(peer, mtu);
-               if (err) {
-                       ERROR("failed to set mtu '%s' for %s : %s",
-                             netdev->mtu, peer, strerror(-err));
-                       lxc_netdev_delete_by_name(peer);
-                       return -1;
-               }
-       }
-
-       return 0;
-}
-
-static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       return 0;
-}
-
-static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       if (!netdev->link) {
-               ERROR("no link specified for the physical interface");
-               return -1;
-       }
-
-       netdev->ifindex = if_nametoindex(netdev->link);
-       if (!netdev->ifindex) {
-               ERROR("failed to retrieve the index for %s", netdev->link);
-               return -1;
-       }
-
-       if (netdev->upscript) {
-               int err;
-               err = run_script(handler->name, "net", netdev->upscript,
-                                "up", "phys", netdev->link, (char*) NULL);
-               if (err)
-                       return -1;
-       }
-
-       return 0;
-}
-
-static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       int err;
-
-       if (netdev->downscript) {
-               err = run_script(handler->name, "net", netdev->downscript,
-                                "down", "phys", netdev->link, (char*) NULL);
-               if (err)
-                       return -1;
-       }
-       return 0;
-}
-
-static int instantiate_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       netdev->ifindex = 0;
-       return 0;
-}
-
-static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       netdev->ifindex = 0;
-       if (netdev->upscript) {
-               int err;
-               err = run_script(handler->name, "net", netdev->upscript,
-                                "up", "empty", (char*) NULL);
-               if (err)
-                       return -1;
-       }
-       return 0;
-}
-
-static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       int err;
-
-       if (netdev->downscript) {
-               err = run_script(handler->name, "net", netdev->downscript,
-                                "down", "empty", (char*) NULL);
-               if (err)
-                       return -1;
-       }
-       return 0;
-}
-
-static int shutdown_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       return 0;
-}
-
-int lxc_requests_empty_network(struct lxc_handler *handler)
-{
-       struct lxc_list *network = &handler->conf->network;
-       struct lxc_list *iterator;
-       struct lxc_netdev *netdev;
-       bool found_none = false, found_nic = false;
-
-       if (lxc_list_empty(network))
-               return 0;
-
-       lxc_list_for_each(iterator, network) {
-
-               netdev = iterator->elem;
-
-               if (netdev->type == LXC_NET_NONE)
-                       found_none = true;
-               else
-                       found_nic = true;
-       }
-       if (found_none && !found_nic)
-               return 1;
-       return 0;
-}
-
-int lxc_setup_networks_in_parent_namespaces(struct lxc_handler *handler)
-{
-       bool am_root;
-       struct lxc_netdev *netdev;
-       struct lxc_list *iterator;
-       struct lxc_list *network = &handler->conf->network;
-
-       /* We need to be root. */
-       am_root = (getuid() == 0);
-       if (!am_root)
-               return 0;
-
-       lxc_list_for_each(iterator, network) {
-               netdev = iterator->elem;
-
-               if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE) {
-                       ERROR("invalid network configuration type '%d'",
-                             netdev->type);
-                       return -1;
-               }
-
-               if (netdev->type != LXC_NET_MACVLAN &&
-                   netdev->priv.macvlan_attr.mode) {
-                       ERROR("Invalid macvlan.mode for a non-macvlan netdev");
-                       return -1;
-               }
-
-               if (netdev->type != LXC_NET_VETH &&
-                   netdev->priv.veth_attr.pair) {
-                       ERROR("Invalid veth pair for a non-veth netdev");
-                       return -1;
-               }
-
-               if (netdev->type != LXC_NET_VLAN &&
-                   netdev->priv.vlan_attr.vid > 0) {
-                       ERROR("Invalid vlan.id for a non-macvlan netdev");
-                       return -1;
-               }
-
-               if (netdev_conf[netdev->type](handler, netdev)) {
-                       ERROR("failed to create netdev");
-                       return -1;
-               }
-
-       }
-
-       return 0;
-}
-
-bool lxc_delete_network(struct lxc_handler *handler)
-{
-       int ret;
-       struct lxc_list *network = &handler->conf->network;
-       struct lxc_list *iterator;
-       struct lxc_netdev *netdev;
-       bool deleted_all = true;
-
-       lxc_list_for_each(iterator, network) {
-               netdev = iterator->elem;
-
-               if (netdev->ifindex != 0 && netdev->type == LXC_NET_PHYS) {
-                       if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link))
-                               WARN("Failed to rename interface with index %d "
-                                    "to its initial name \"%s\".",
-                                    netdev->ifindex, netdev->link);
-                       continue;
-               }
-
-               if (netdev_deconf[netdev->type](handler, netdev)) {
-                       WARN("Failed to destroy netdev");
-               }
-
-               /* Recent kernel remove the virtual interfaces when the network
-                * namespace is destroyed but in case we did not moved the
-                * interface to the network namespace, we have to destroy it
-                */
-               if (netdev->ifindex != 0) {
-                       ret = lxc_netdev_delete_by_index(netdev->ifindex);
-                       if (-ret == ENODEV) {
-                               INFO("Interface \"%s\" with index %d already "
-                                    "deleted or existing in different network "
-                                    "namespace.",
-                                    netdev->name ? netdev->name : "(null)",
-                                    netdev->ifindex);
-                       } else if (ret < 0) {
-                               deleted_all = false;
-                               WARN("Failed to remove interface \"%s\" with "
-                                    "index %d: %s.",
-                                    netdev->name ? netdev->name : "(null)",
-                                    netdev->ifindex, strerror(-ret));
-                       } else {
-                               INFO("Removed interface \"%s\" with index %d.",
-                                    netdev->name ? netdev->name : "(null)",
-                                    netdev->ifindex);
-                       }
-               }
-
-               /* Explicitly delete host veth device to prevent lingering
-                * devices. We had issues in LXD around this.
-                */
-               if (netdev->ifindex != 0 && netdev->type == LXC_NET_VETH && !am_unpriv()) {
-                       char *hostveth;
-                       if (netdev->priv.veth_attr.pair) {
-                               hostveth = netdev->priv.veth_attr.pair;
-                               ret = lxc_netdev_delete_by_name(hostveth);
-                               if (ret < 0) {
-                                       WARN("Failed to remove interface \"%s\" from host: %s.", hostveth, strerror(-ret));
-                               } else {
-                                       INFO("Removed interface \"%s\" from host.", hostveth);
-                               }
-                       } else if (strlen(netdev->priv.veth_attr.veth1) > 0) {
-                               hostveth = netdev->priv.veth_attr.veth1;
-                               ret = lxc_netdev_delete_by_name(hostveth);
-                               if (ret < 0) {
-                                       WARN("Failed to remove \"%s\" from host: %s.", hostveth, strerror(-ret));
-                               } else {
-                                       INFO("Removed interface \"%s\" from host.", hostveth);
-                                       memset((void *)&netdev->priv.veth_attr.veth1, 0, sizeof(netdev->priv.veth_attr.veth1));
-                               }
-                       }
-               }
-       }
-
-       return deleted_all;
-}
-
-#define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
-
-/* lxc-user-nic returns "interface_name:interface_name\n" */
-#define MAX_BUFFER_SIZE IFNAMSIZ * 2 + 2
-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",
-                     netdev->type);
-               return -1;
-       }
-
-       if (pipe(pipefd) < 0) {
-               SYSERROR("pipe failed");
-               return -1;
-       }
-
-       child = fork();
-       if (child < 0) {
-               SYSERROR("fork");
-               close(pipefd[0]);
-               close(pipefd[1]);
-               return -1;
-       }
-
-       if (child == 0) { // child
-               /* Call lxc-user-nic pid type bridge. */
-               int ret;
-               char pidstr[LXC_NUMSTRLEN64];
-
-               close(pipefd[0]); /* Close the read-end of the pipe. */
-
-               /* Redirect stdout to write-end of the pipe. */
-               ret = dup2(pipefd[1], STDOUT_FILENO);
-               close(pipefd[1]); /* Close the write-end of the pipe. */
-               if (ret < 0) {
-                       SYSERROR("Failed to dup2() to redirect stdout to pipe file descriptor.");
-                       exit(EXIT_FAILURE);
-               }
-
-               if (netdev->link)
-                       strncpy(netdev_link, netdev->link, IFNAMSIZ);
-               else
-                       strncpy(netdev_link, "none", IFNAMSIZ);
-
-               ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
-               if (ret < 0 || ret >= LXC_NUMSTRLEN64)
-                       exit(EXIT_FAILURE);
-               pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
-
-               INFO("Execing lxc-user-nic %s %s %s veth %s %s", lxcpath,
-                    lxcname, pidstr, netdev_link, netdev->name);
-               execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, lxcpath, lxcname,
-                      pidstr, "veth", netdev_link, netdev->name, NULL);
-
-               SYSERROR("Failed to exec lxc-user-nic.");
-               exit(EXIT_FAILURE);
-       }
-
-       /* close the write-end of the pipe */
-       close(pipefd[1]);
-
-       bytes = read(pipefd[0], &buffer, MAX_BUFFER_SIZE);
-       if (bytes < 0)
-               SYSERROR("Failed to read from pipe file descriptor.");
-       buffer[bytes - 1] = '\0';
-
-       if (wait_for_pid(child) != 0) {
-               close(pipefd[0]);
-               return -1;
-       }
-
-       /* close the read-end of the pipe */
-       close(pipefd[0]);
-
-       /* fill netdev->name field */
-       token = strtok_r(buffer, ":", &saveptr);
-       if (!token)
-               return -1;
-
-       netdev->name = malloc(IFNAMSIZ + 1);
-       if (!netdev->name) {
-               SYSERROR("Failed to allocate memory.");
-               return -1;
-       }
-       memset(netdev->name, 0, IFNAMSIZ + 1);
-       strncpy(netdev->name, token, IFNAMSIZ);
-
-       /* fill netdev->veth_attr.pair field */
-       token = strtok_r(NULL, ":", &saveptr);
-       if (!token)
-               return -1;
-
-       netdev->priv.veth_attr.pair = strdup(token);
-       if (!netdev->priv.veth_attr.pair) {
-               ERROR("Failed to allocate memory.");
-               return -1;
-       }
-
-       return 0;
-}
-
-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;
-
-       lxc_list_for_each(iterator, network) {
-
-               netdev = iterator->elem;
-
-               if (netdev->type == LXC_NET_VETH && !am_root) {
-                       if (netdev->mtu)
-                               INFO("mtu ignored due to insufficient privilege");
-                       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.
-                        * netdev->ifindex will be filed in at
-                        * lxc_setup_netdev_in_child_namespaces.
-                        */
-                       continue;
-               }
-
-               /* empty network namespace, nothing to move */
-               if (!netdev->ifindex)
-                       continue;
-
-               /* 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));
-                       return -1;
-               }
-
-               DEBUG("move '%s'/'%s' to '%d': .", ifname, netdev->name, pid);
-       }
-
-       return 0;
-}
-
-static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
-                           size_t buf_size)
-{
-       char path[MAXPATHLEN];
-       int fd, ret;
-
-       ret = snprintf(path, MAXPATHLEN, "/proc/%d/%cid_map", pid,
-                      idtype == ID_TYPE_UID ? 'u' : 'g');
-       if (ret < 0 || ret >= MAXPATHLEN) {
-               ERROR("failed to create path \"%s\"", path);
-               return -E2BIG;
-       }
-
-       fd = open(path, O_WRONLY);
-       if (fd < 0) {
-               SYSERROR("failed to open \"%s\"", path);
-               return -1;
-       }
-
-       errno = 0;
-       ret = lxc_write_nointr(fd, buf, buf_size);
-       if (ret != buf_size) {
-               SYSERROR("failed to write %cid mapping to \"%s\"",
-                        idtype == ID_TYPE_UID ? 'u' : 'g', path);
-               close(fd);
-               return -1;
-       }
-       close(fd);
-
-       return 0;
-}
-
-/* Check whether a binary exist and has either CAP_SETUID, CAP_SETGID or both.
- *
- * @return  1      if functional binary was found
- * @return  0      if binary exists but is lacking privilege
- * @return -ENOENT if binary does not exist
- * @return -EINVAL if cap to check is neither CAP_SETUID nor CAP_SETGID
- *
- */
-static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
-{
-       char *path;
-       int ret;
-       struct stat st;
-       int fret = 0;
-
-       if (cap != CAP_SETUID && cap != CAP_SETGID)
-               return -EINVAL;
-
-       path = on_path(binary, NULL);
-       if (!path)
-               return -ENOENT;
-
-       ret = stat(path, &st);
-       if (ret < 0) {
-               fret = -errno;
-               goto cleanup;
-       }
-
-       /* Check if the binary is setuid. */
-       if (st.st_mode & S_ISUID) {
-               DEBUG("The binary \"%s\" does have the setuid bit set.", path);
-               fret = 1;
-               goto cleanup;
-       }
-
-       #if HAVE_LIBCAP && LIBCAP_SUPPORTS_FILE_CAPABILITIES
-       /* Check if it has the CAP_SETUID capability. */
-       if ((cap & CAP_SETUID) &&
-           lxc_file_cap_is_set(path, CAP_SETUID, CAP_EFFECTIVE) &&
-           lxc_file_cap_is_set(path, CAP_SETUID, CAP_PERMITTED)) {
-               DEBUG("The binary \"%s\" has CAP_SETUID in its CAP_EFFECTIVE "
-                     "and CAP_PERMITTED sets.", path);
-               fret = 1;
-               goto cleanup;
+       #if HAVE_LIBCAP && LIBCAP_SUPPORTS_FILE_CAPABILITIES
+       /* Check if it has the CAP_SETUID capability. */
+       if ((cap & CAP_SETUID) &&
+           lxc_file_cap_is_set(path, CAP_SETUID, CAP_EFFECTIVE) &&
+           lxc_file_cap_is_set(path, CAP_SETUID, CAP_PERMITTED)) {
+               DEBUG("The binary \"%s\" has CAP_SETUID in its CAP_EFFECTIVE "
+                     "and CAP_PERMITTED sets.", path);
+               fret = 1;
+               goto cleanup;
        }
 
        /* Check if it has the CAP_SETGID capability. */
@@ -3514,14 +2731,18 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
                                          lxc_map_ids_exec_wrapper,
                                          (void *)mapbuf);
                        if (ret < 0) {
-                               ERROR("new%cidmap failed to write mapping: %s",
-                                     u_or_g, cmd_output);
+                               ERROR("new%cidmap failed to write mapping \"%s\": %s",
+                                     u_or_g, cmd_output, mapbuf);
                                return -1;
                        }
+                       TRACE("new%cidmap wrote mapping \"%s\"", u_or_g, mapbuf);
                } else {
                        ret = write_id_mapping(type, pid, mapbuf, pos - mapbuf);
-                       if (ret < 0)
+                       if (ret < 0) {
+                               ERROR("Failed to write mapping: %s", mapbuf);
                                return -1;
+                       }
+                       TRACE("Wrote mapping \"%s\"", mapbuf);
                }
 
                memset(mapbuf, 0, sizeof(mapbuf));
@@ -3547,162 +2768,43 @@ bool get_mapped_rootid(struct lxc_conf *conf, enum idtype idtype,
                        continue;
                if (map->nsid != 0)
                        continue;
-               *val = map->hostid;
-               return true;
-       }
-       return false;
-}
-
-int mapped_hostid(unsigned id, struct lxc_conf *conf, enum idtype idtype)
-{
-       struct lxc_list *it;
-       struct id_map *map;
-       lxc_list_for_each(it, &conf->id_map) {
-               map = it->elem;
-               if (map->idtype != idtype)
-                       continue;
-               if (id >= map->hostid && id < map->hostid + map->range)
-                       return (id - map->hostid) + map->nsid;
-       }
-       return -1;
-}
-
-int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype)
-{
-       struct lxc_list *it;
-       struct id_map *map;
-       unsigned int freeid = 0;
-again:
-       lxc_list_for_each(it, &conf->id_map) {
-               map = it->elem;
-               if (map->idtype != idtype)
-                       continue;
-               if (freeid >= map->nsid && freeid < map->nsid + map->range) {
-                       freeid = map->nsid + map->range;
-                       goto again;
-               }
-       }
-       return freeid;
-}
-
-int lxc_find_gateway_addresses(struct lxc_handler *handler)
-{
-       struct lxc_list *network = &handler->conf->network;
-       struct lxc_list *iterator;
-       struct lxc_netdev *netdev;
-       int link_index;
-
-       lxc_list_for_each(iterator, network) {
-               netdev = iterator->elem;
-
-               if (!netdev->ipv4_gateway_auto && !netdev->ipv6_gateway_auto)
-                       continue;
-
-               if (netdev->type != LXC_NET_VETH && netdev->type != LXC_NET_MACVLAN) {
-                       ERROR("gateway = auto only supported for "
-                             "veth and macvlan");
-                       return -1;
-               }
-
-               if (!netdev->link) {
-                       ERROR("gateway = auto needs a link interface");
-                       return -1;
-               }
-
-               link_index = if_nametoindex(netdev->link);
-               if (!link_index)
-                       return -EINVAL;
-
-               if (netdev->ipv4_gateway_auto) {
-                       if (lxc_ipv4_addr_get(link_index, &netdev->ipv4_gateway)) {
-                               ERROR("failed to automatically find ipv4 gateway "
-                                     "address from link interface '%s'", netdev->link);
-                               return -1;
-                       }
-               }
-
-               if (netdev->ipv6_gateway_auto) {
-                       if (lxc_ipv6_addr_get(link_index, &netdev->ipv6_gateway)) {
-                               ERROR("failed to automatically find ipv6 gateway "
-                                     "address from link interface '%s'", netdev->link);
-                               return -1;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-int lxc_create_tty(const char *name, struct lxc_conf *conf)
-{
-       struct lxc_tty_info *tty_info = &conf->tty_info;
-       int i, ret;
-
-       /* no tty in the configuration */
-       if (!conf->tty)
-               return 0;
-
-       tty_info->pty_info = malloc(sizeof(*tty_info->pty_info) * conf->tty);
-       if (!tty_info->pty_info) {
-               SYSERROR("failed to allocate struct *pty_info");
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < conf->tty; i++) {
-               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
-
-               process_lock();
-               ret = openpty(&pty_info->master, &pty_info->slave,
-                             pty_info->name, NULL, NULL);
-               process_unlock();
-               if (ret) {
-                       SYSERROR("failed to create pty device number %d", i);
-                       tty_info->nbtty = i;
-                       lxc_delete_tty(tty_info);
-                       return -ENOTTY;
-               }
-
-               DEBUG("allocated pty \"%s\" with master fd %d and slave fd %d",
-                     pty_info->name, pty_info->master, pty_info->slave);
-
-               /* Prevent leaking the file descriptors to the container */
-               ret = fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
-               if (ret < 0)
-                       WARN("failed to set FD_CLOEXEC flag on master fd %d of "
-                            "pty device \"%s\": %s",
-                            pty_info->master, pty_info->name, strerror(errno));
-
-               ret = fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
-               if (ret < 0)
-                       WARN("failed to set FD_CLOEXEC flag on slave fd %d of "
-                            "pty device \"%s\": %s",
-                            pty_info->slave, pty_info->name, strerror(errno));
-
-               pty_info->busy = 0;
+               *val = map->hostid;
+               return true;
        }
-
-       tty_info->nbtty = conf->tty;
-
-       INFO("finished allocating %d pts devices", conf->tty);
-       return 0;
+       return false;
 }
 
-void lxc_delete_tty(struct lxc_tty_info *tty_info)
+int mapped_hostid(unsigned id, struct lxc_conf *conf, enum idtype idtype)
 {
-       int i;
-
-       for (i = 0; i < tty_info->nbtty; i++) {
-               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
-
-               close(pty_info->master);
-               close(pty_info->slave);
+       struct lxc_list *it;
+       struct id_map *map;
+       lxc_list_for_each(it, &conf->id_map) {
+               map = it->elem;
+               if (map->idtype != idtype)
+                       continue;
+               if (id >= map->hostid && id < map->hostid + map->range)
+                       return (id - map->hostid) + map->nsid;
        }
-
-       free(tty_info->pty_info);
-       tty_info->pty_info = NULL;
-       tty_info->nbtty = 0;
+       return -1;
 }
 
+int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype)
+{
+       struct lxc_list *it;
+       struct id_map *map;
+       unsigned int freeid = 0;
+again:
+       lxc_list_for_each(it, &conf->id_map) {
+               map = it->elem;
+               if (map->idtype != idtype)
+                       continue;
+               if (freeid >= map->nsid && freeid < map->nsid + map->range) {
+                       freeid = map->nsid + map->range;
+                       goto again;
+               }
+       }
+       return freeid;
+}
 
 int chown_mapped_root_exec_wrapper(void *args)
 {
@@ -3722,7 +2824,6 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
 {
        uid_t rootuid, rootgid;
        unsigned long val;
-       char *chownpath = path;
        int hostuid, hostgid, ret;
        struct stat sb;
        char map1[100], map2[100], map3[100], map4[100], map5[100];
@@ -3758,23 +2859,6 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
        }
        rootgid = (gid_t)val;
 
-       /*
-        * In case of overlay, we want only the writeable layer to be chowned
-        */
-       if (strncmp(path, "overlayfs:", 10) == 0 || strncmp(path, "aufs:", 5) == 0) {
-               chownpath = strchr(path, ':');
-               if (!chownpath) {
-                       ERROR("Bad overlay path: %s", path);
-                       return -1;
-               }
-               chownpath = strchr(chownpath + 1, ':');
-               if (!chownpath) {
-                       ERROR("Bad overlay path: %s", path);
-                       return -1;
-               }
-               chownpath++;
-       }
-       path = chownpath;
        if (hostuid == 0) {
                if (chown(path, rootuid, rootgid) < 0) {
                        ERROR("Error chowning %s", path);
@@ -3784,7 +2868,7 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
        }
 
        if (rootuid == hostuid) {
-               // nothing to do
+               /* nothing to do */
                INFO("Container root is our uid; no need to chown");
                return 0;
        }
@@ -3811,28 +2895,28 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
                return -1;
        }
 
-       // "u:0:rootuid:1"
+       /* "u:0:rootuid:1" */
        ret = snprintf(map1, 100, "u:0:%d:1", rootuid);
        if (ret < 0 || ret >= 100) {
                ERROR("Error uid printing map string");
                return -1;
        }
 
-       // "u:hostuid:hostuid:1"
+       /* "u:hostuid:hostuid:1" */
        ret = snprintf(map2, 100, "u:%d:%d:1", hostuid, hostuid);
        if (ret < 0 || ret >= 100) {
                ERROR("Error uid printing map string");
                return -1;
        }
 
-       // "g:0:rootgid:1"
+       /* "g:0:rootgid:1" */
        ret = snprintf(map3, 100, "g:0:%d:1", rootgid);
        if (ret < 0 || ret >= 100) {
                ERROR("Error gid printing map string");
                return -1;
        }
 
-       // "g:pathgid:rootgid+pathgid:1"
+       /* "g:pathgid:rootgid+pathgid:1" */
        ret = snprintf(map4, 100, "g:%d:%d:1", (gid_t)sb.st_gid,
                       rootgid + (gid_t)sb.st_gid);
        if (ret < 0 || ret >= 100) {
@@ -3840,14 +2924,14 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
                return -1;
        }
 
-       // "g:hostgid:hostgid:1"
+       /* "g:hostgid:hostgid:1" */
        ret = snprintf(map5, 100, "g:%d:%d:1", hostgid, hostgid);
        if (ret < 0 || ret >= 100) {
                ERROR("Error gid printing map string");
                return -1;
        }
 
-       // "0:pathgid" (chown)
+       /* "0:pathgid" (chown) */
        ret = snprintf(ugid, 100, "0:%d", (gid_t)sb.st_gid);
        if (ret < 0 || ret >= 100) {
                ERROR("Error owner printing format string for chown");
@@ -4050,50 +3134,9 @@ static bool verify_start_hooks(struct lxc_conf *conf)
        return true;
 }
 
-static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
-{
-       int i;
-       int *ttyfds;
-       struct lxc_pty_info *pty_info;
-       struct lxc_conf *conf = handler->conf;
-       const struct lxc_tty_info *tty_info = &conf->tty_info;
-       int sock = handler->ttysock[0];
-       int ret = -1;
-       size_t num_ttyfds = (2 * conf->tty);
-
-       ttyfds = malloc(num_ttyfds * sizeof(int));
-       if (!ttyfds)
-               return -1;
-
-       for (i = 0; i < num_ttyfds; i++) {
-               pty_info = &tty_info->pty_info[i / 2];
-               ttyfds[i++] = pty_info->slave;
-               ttyfds[i] = pty_info->master;
-               TRACE("send pty \"%s\" with master fd %d and slave fd %d to "
-                     "parent",
-                     pty_info->name, pty_info->master, pty_info->slave);
-       }
-
-       ret = lxc_abstract_unix_send_fds(sock, ttyfds, num_ttyfds, NULL, 0);
-       if (ret < 0)
-               ERROR("failed to send %d ttys to parent: %s", conf->tty,
-                     strerror(errno));
-       else
-               TRACE("sent %d ttys to parent", conf->tty);
-
-       close(handler->ttysock[0]);
-       close(handler->ttysock[1]);
-
-       for (i = 0; i < num_ttyfds; i++)
-               close(ttyfds[i]);
-
-       free(ttyfds);
-
-       return ret;
-}
-
 int lxc_setup(struct lxc_handler *handler)
 {
+       int ret;
        const char *name = handler->name;
        struct lxc_conf *lxc_conf = handler->conf;
        const char *lxcpath = handler->lxcpath;
@@ -4110,12 +3153,16 @@ int lxc_setup(struct lxc_handler *handler)
                }
        }
 
-       if (lxc_setup_networks_in_child_namespaces(lxc_conf,
-                                                  &lxc_conf->network)) {
+       if (lxc_setup_network_in_child_namespaces(lxc_conf, &lxc_conf->network)) {
                ERROR("failed to setup the network for '%s'", name);
                return -1;
        }
 
+       if (lxc_network_send_name_and_ifindex_to_parent(handler) < 0) {
+               ERROR("Failed to network device names and ifindices to parent");
+               return -1;
+       }
+
        if (lxc_conf->autodev > 0) {
                if (mount_autodev(name, &lxc_conf->rootfs, lxcpath)) {
                        ERROR("failed to mount /dev in the container");
@@ -4131,12 +3178,12 @@ int lxc_setup(struct lxc_handler *handler)
                return -1;
        }
 
-       if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name, lxcpath)) {
+       if (setup_mount(lxc_conf, &lxc_conf->rootfs, lxc_conf->fstab, name, lxcpath)) {
                ERROR("failed to setup the mounts for '%s'", name);
                return -1;
        }
 
-       if (!lxc_list_empty(&lxc_conf->mount_list) && setup_mount_entries(&lxc_conf->rootfs, &lxc_conf->mount_list, name, lxcpath)) {
+       if (!lxc_list_empty(&lxc_conf->mount_list) && setup_mount_entries(lxc_conf, &lxc_conf->rootfs, &lxc_conf->mount_list, name, lxcpath)) {
                ERROR("failed to setup the mount entries for '%s'", name);
                return -1;
        }
@@ -4167,19 +3214,23 @@ int lxc_setup(struct lxc_handler *handler)
                        ERROR("failed to run autodev hooks for container '%s'.", name);
                        return -1;
                }
+
                if (lxc_fill_autodev(&lxc_conf->rootfs)) {
                        ERROR("failed to populate /dev in the container");
                        return -1;
                }
        }
 
-       if (!lxc_conf->is_execute && lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
-               ERROR("failed to setup the console for '%s'", name);
+       ret = lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console,
+                               lxc_conf->ttydir);
+       if (ret < 0) {
+               ERROR("Failed to setup console");
                return -1;
        }
 
-       if (!lxc_conf->is_execute && setup_dev_symlinks(&lxc_conf->rootfs)) {
-               ERROR("failed to setup /dev symlinks for '%s'", name);
+       ret = lxc_setup_dev_symlinks(&lxc_conf->rootfs);
+       if (ret < 0) {
+               ERROR("Failed to setup /dev symlinks");
                return -1;
        }
 
@@ -4199,24 +3250,9 @@ int lxc_setup(struct lxc_handler *handler)
                return -1;
        }
 
-       if (lxc_create_tty(name, lxc_conf)) {
-               ERROR("failed to create the ttys");
-               return -1;
-       }
-
-       if (lxc_send_ttys_to_parent(handler) < 0) {
-               ERROR("failure sending console info to parent");
-               return -1;
-       }
-
-       if (!lxc_conf->is_execute && lxc_setup_tty(lxc_conf)) {
-               ERROR("failed to setup the ttys for '%s'", name);
+       ret = lxc_create_ttys(handler);
+       if (ret < 0)
                return -1;
-       }
-
-       if (lxc_conf->pty_names && setenv("container_ttys", lxc_conf->pty_names, 1))
-               SYSERROR("failed to set environment variable for container ptys");
-
 
        if (setup_personality(lxc_conf->personality)) {
                ERROR("failed to setup personality");
@@ -4250,6 +3286,8 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
 
        if (strcmp(hook, "pre-start") == 0)
                which = LXCHOOK_PRESTART;
+       else if (strcmp(hook, "start-host") == 0)
+               which = LXCHOOK_START_HOST;
        else if (strcmp(hook, "pre-mount") == 0)
                which = LXCHOOK_PREMOUNT;
        else if (strcmp(hook, "mount") == 0)
@@ -4280,7 +3318,7 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
 
 int lxc_clear_config_caps(struct lxc_conf *c)
 {
-       struct lxc_list *it,*next;
+       struct lxc_list *it, *next;
 
        lxc_list_for_each_safe(it, &c->caps, next) {
                lxc_list_del(it);
@@ -4396,7 +3434,6 @@ int lxc_clear_environment(struct lxc_conf *c)
        return 0;
 }
 
-
 int lxc_clear_mount_entries(struct lxc_conf *c)
 {
        struct lxc_list *it,*next;
@@ -4447,17 +3484,6 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key)
        return 0;
 }
 
-static void lxc_clear_saved_nics(struct lxc_conf *conf)
-{
-       int i;
-
-       if (!conf->saved_nics)
-               return;
-       for (i=0; i < conf->num_savednics; i++)
-               free(conf->saved_nics[i].orig_name);
-       free(conf->saved_nics);
-}
-
 static inline void lxc_clear_aliens(struct lxc_conf *conf)
 {
        struct lxc_list *it,*next;
@@ -4499,6 +3525,7 @@ void lxc_conf_free(struct lxc_conf *conf)
        free(conf->ttydir);
        free(conf->fstab);
        free(conf->rcfile);
+       free(conf->execute_cmd);
        free(conf->init_cmd);
        free(conf->unexpanded_config);
        free(conf->pty_names);
@@ -4512,13 +3539,14 @@ void lxc_conf_free(struct lxc_conf *conf)
        lxc_clear_cgroups(conf, "lxc.cgroup");
        lxc_clear_hooks(conf, "lxc.hook");
        lxc_clear_mount_entries(conf);
-       lxc_clear_saved_nics(conf);
        lxc_clear_idmaps(conf);
        lxc_clear_groups(conf);
        lxc_clear_includes(conf);
        lxc_clear_aliens(conf);
        lxc_clear_environment(conf);
        lxc_clear_limits(conf, "lxc.prlimit");
+       free(conf->cgroup_meta.dir);
+       free(conf->cgroup_meta.controllers);
        free(conf);
 }
 
@@ -4661,6 +3689,9 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
        close(p[0]);
        p[0] = -1;
 
+       euid = geteuid();
+       egid = getegid();
+
        /* Find container root. */
        lxc_list_for_each(it, &conf->id_map) {
                map = it->elem;
@@ -4676,6 +3707,12 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
                        container_root_uid->hostid = map->hostid;
                        container_root_uid->nsid = 0;
                        container_root_uid->range = map->range;
+
+                       /* Check if container root mapping contains a mapping
+                        * for user's uid.
+                        */
+                       if (euid >= map->hostid && euid < map->hostid + map->range)
+                               host_uid_map = container_root_uid;
                } else if (map->idtype == ID_TYPE_GID && container_root_gid == NULL) {
                        container_root_gid = malloc(sizeof(*container_root_gid));
                        if (!container_root_gid)
@@ -4684,6 +3721,12 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
                        container_root_gid->hostid = map->hostid;
                        container_root_gid->nsid = 0;
                        container_root_gid->range = map->range;
+
+                       /* Check if container root mapping contains a mapping
+                        * for user's gid.
+                        */
+                       if (egid >= map->hostid && egid < map->hostid + map->range)
+                               host_gid_map = container_root_gid;
                }
 
                /* Found container root. */
@@ -4697,16 +3740,11 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
                goto on_error;
        }
 
-       host_uid_map = container_root_uid;
-       host_gid_map = container_root_gid;
-
        /* Check whether the {g,u}id of the user has a mapping. */
-       euid = geteuid();
-       egid = getegid();
-       if (euid != container_root_uid->hostid)
+       if (!host_uid_map)
                host_uid_map = idmap_add(conf, euid, ID_TYPE_UID);
 
-       if (egid != container_root_gid->hostid)
+       if (!host_gid_map)
                host_gid_map = idmap_add(conf, egid, ID_TYPE_GID);
 
        if (!host_uid_map) {
@@ -4785,8 +3823,7 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
        ret = lxc_map_ids(idmap, pid);
        if (ret < 0) {
                ERROR("error setting up {g,u}id mappings for child process "
-                     "\"%d\"",
-                     pid);
+                     "\"%d\"", pid);
                goto on_error;
        }
 
@@ -4818,6 +3855,184 @@ on_error:
        return ret;
 }
 
+int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
+                    const char *fn_name)
+{
+       pid_t pid;
+       uid_t euid, egid;
+       struct userns_fn_data d;
+       int p[2];
+       struct id_map *map;
+       struct lxc_list *cur;
+       char c = '1';
+       int ret = -1;
+       struct lxc_list *idmap = NULL, *tmplist = NULL;
+       struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
+                     *host_uid_map = NULL, *host_gid_map = NULL;
+
+       ret = pipe(p);
+       if (ret < 0) {
+               SYSERROR("opening pipe");
+               return -1;
+       }
+       d.fn = fn;
+       d.fn_name = fn_name;
+       d.arg = data;
+       d.p[0] = p[0];
+       d.p[1] = p[1];
+
+       /* Clone child in new user namespace. */
+       pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER);
+       if (pid < 0) {
+               ERROR("failed to clone child process in new user namespace");
+               goto on_error;
+       }
+
+       close(p[0]);
+       p[0] = -1;
+
+       euid = geteuid();
+       egid = getegid();
+
+       /* Allocate new {g,u}id map list. */
+       idmap = malloc(sizeof(*idmap));
+       if (!idmap)
+               goto on_error;
+       lxc_list_init(idmap);
+
+       /* Find container root. */
+       lxc_list_for_each(cur, &conf->id_map) {
+               struct id_map *tmpmap;
+
+               tmplist = malloc(sizeof(*tmplist));
+               if (!tmplist)
+                       goto on_error;
+
+               tmpmap = malloc(sizeof(*tmpmap));
+               if (!tmpmap) {
+                       free(tmplist);
+                       goto on_error;
+               }
+
+               memset(tmpmap, 0, sizeof(*tmpmap));
+               memcpy(tmpmap, cur->elem, sizeof(*tmpmap));
+               tmplist->elem = tmpmap;
+
+               lxc_list_add_tail(idmap, tmplist);
+
+               map = cur->elem;
+
+               if (map->idtype == ID_TYPE_UID)
+                       if (euid >= map->hostid && euid < map->hostid + map->range)
+                               host_uid_map = map;
+
+               if (map->idtype == ID_TYPE_GID)
+                       if (egid >= map->hostid && egid < map->hostid + map->range)
+                               host_gid_map = map;
+
+               if (map->nsid != 0)
+                       continue;
+
+               if (map->idtype == ID_TYPE_UID)
+                       if (container_root_uid == NULL)
+                               container_root_uid = map;
+
+               if (map->idtype == ID_TYPE_GID)
+                       if (container_root_gid == NULL)
+                               container_root_gid = map;
+       }
+
+       if (!container_root_uid || !container_root_gid) {
+               ERROR("No mapping for container root found");
+               goto on_error;
+       }
+
+       /* Check whether the {g,u}id of the user has a mapping. */
+       if (!host_uid_map)
+               host_uid_map = idmap_add(conf, euid, ID_TYPE_UID);
+       else
+               host_uid_map = container_root_uid;
+
+       if (!host_gid_map)
+               host_gid_map = idmap_add(conf, egid, ID_TYPE_GID);
+       else
+               host_gid_map = container_root_gid;
+
+       if (!host_uid_map) {
+               DEBUG("Failed to find mapping for uid %d", euid);
+               goto on_error;
+       }
+
+       if (!host_gid_map) {
+               DEBUG("Failed to find mapping for gid %d", egid);
+               goto on_error;
+       }
+
+       if (host_uid_map && (host_uid_map != container_root_uid)) {
+               /* Add container root to the map. */
+               tmplist = malloc(sizeof(*tmplist));
+               if (!tmplist)
+                       goto on_error;
+               lxc_list_add_elem(tmplist, host_uid_map);
+               lxc_list_add_tail(idmap, tmplist);
+       }
+       /* idmap will now keep track of that memory. */
+       host_uid_map = NULL;
+
+       if (host_gid_map && (host_gid_map != container_root_gid)) {
+               tmplist = malloc(sizeof(*tmplist));
+               if (!tmplist)
+                       goto on_error;
+               lxc_list_add_elem(tmplist, host_gid_map);
+               lxc_list_add_tail(idmap, tmplist);
+       }
+       /* idmap will now keep track of that memory. */
+       host_gid_map = NULL;
+
+       if (lxc_log_get_level() == LXC_LOG_LEVEL_TRACE ||
+           conf->loglevel == LXC_LOG_LEVEL_TRACE) {
+               lxc_list_for_each(cur, idmap) {
+                       map = cur->elem;
+                       TRACE("establishing %cid mapping for \"%d\" in new "
+                             "user namespace: nsuid %lu - hostid %lu - range "
+                             "%lu",
+                             (map->idtype == ID_TYPE_UID) ? 'u' : 'g', pid,
+                             map->nsid, map->hostid, map->range);
+               }
+       }
+
+       /* Set up {g,u}id mapping for user namespace of child process. */
+       ret = lxc_map_ids(idmap, pid);
+       if (ret < 0) {
+               ERROR("error setting up {g,u}id mappings for child process "
+                     "\"%d\"", pid);
+               goto on_error;
+       }
+
+       /* Tell child to proceed. */
+       if (write(p[1], &c, 1) != 1) {
+               SYSERROR("failed telling child process \"%d\" to proceed", pid);
+               goto on_error;
+       }
+
+       /* Wait for child to finish. */
+       ret = wait_for_pid(pid);
+
+on_error:
+       if (idmap)
+               lxc_free_idmap(idmap);
+       if (host_uid_map && (host_uid_map != container_root_uid))
+               free(host_uid_map);
+       if (host_gid_map && (host_gid_map != container_root_gid))
+               free(host_gid_map);
+
+       if (p[0] != -1)
+               close(p[0]);
+       close(p[1]);
+
+       return ret;
+}
+
 /* not thread-safe, do not use from api without first forking */
 static char* getuname(void)
 {
@@ -4941,8 +4156,8 @@ void suggest_default_idmap(void)
        ERROR("To pass uid mappings to lxc-create, you could create");
        ERROR("~/.config/lxc/default.conf:");
        ERROR("lxc.include = %s", LXC_DEFAULT_CONFIG);
-       ERROR("lxc.id_map = u 0 %u %u", uid, urange);
-       ERROR("lxc.id_map = g 0 %u %u", gid, grange);
+       ERROR("lxc.idmap = u 0 %u %u", uid, urange);
+       ERROR("lxc.idmap = g 0 %u %u", gid, grange);
 
        free(gname);
        free(uname);
index 8150c3744972ac00122e593c89b66139b59939c3..169857f2bb711c25f53503ce9aec969f934dbe4d 100644 (file)
@@ -26,8 +26,8 @@
 #include "config.h"
 
 #include <stdio.h>
-#include <netinet/in.h>
 #include <net/if.h>
+#include <netinet/in.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #if HAVE_SYS_RESOURCE_H
@@ -46,112 +46,30 @@ typedef void * scmp_filter_ctx;
 #define subuidfile "/etc/subuid"
 #define subgidfile "/etc/subgid"
 
-enum {
-       LXC_NET_EMPTY,
-       LXC_NET_VETH,
-       LXC_NET_MACVLAN,
-       LXC_NET_PHYS,
-       LXC_NET_VLAN,
-       LXC_NET_NONE,
-       LXC_NET_MAXCONFTYPE,
-};
-
-/*
- * Defines the structure to configure an ipv4 address
- * @address   : ipv4 address
- * @broadcast : ipv4 broadcast address
- * @mask      : network mask
- */
-struct lxc_inetdev {
-       struct in_addr addr;
-       struct in_addr bcast;
-       unsigned int prefix;
-};
-
-struct lxc_route {
-       struct in_addr addr;
-};
-
-/*
- * Defines the structure to configure an ipv6 address
- * @flags     : set the address up
- * @address   : ipv6 address
- * @broadcast : ipv6 broadcast address
- * @mask      : network mask
- */
-struct lxc_inet6dev {
-       struct in6_addr addr;
-       struct in6_addr mcast;
-       struct in6_addr acast;
-       unsigned int prefix;
-};
-
-struct lxc_route6 {
-       struct in6_addr addr;
-};
-
-struct ifla_veth {
-       char *pair; /* pair name */
-       char veth1[IFNAMSIZ]; /* needed for deconf */
-};
-
-struct ifla_vlan {
-       unsigned int   flags;
-       unsigned int   fmask;
-       unsigned short   vid;
-       unsigned short   pad;
-};
-
-struct ifla_macvlan {
-       int mode; /* private, vepa, bridge, passthru */
-};
-
-union netdev_p {
-       struct ifla_veth veth_attr;
-       struct ifla_vlan vlan_attr;
-       struct ifla_macvlan macvlan_attr;
-};
-
-/*
- * Defines a structure to configure a network device
- * @link       : lxc.net.[i].link, name of bridge or host iface to attach if any
- * @name       : lxc.net.[i].name, name of iface on the container side
- * @flags      : flag of the network device (IFF_UP, ... )
- * @ipv4       : a list of ipv4 addresses to be set on the network device
- * @ipv6       : a list of ipv6 addresses to be set on the network device
- * @upscript   : a script filename to be executed during interface configuration
- * @downscript : a script filename to be executed during interface destruction
- * @idx        : network counter
- */
-struct lxc_netdev {
-       ssize_t idx;
-       int type;
-       int flags;
-       int ifindex;
-       char *link;
-       char *name;
-       char *hwaddr;
-       char *mtu;
-       union netdev_p priv;
-       struct lxc_list ipv4;
-       struct lxc_list ipv6;
-       struct in_addr *ipv4_gateway;
-       bool ipv4_gateway_auto;
-       struct in6_addr *ipv6_gateway;
-       bool ipv6_gateway_auto;
-       char *upscript;
-       char *downscript;
-};
-
 /*
- * Defines a generic struct to configure the control group.
- * It is up to the programmer to specify the right subsystem.
+ * Defines a generic struct to configure the control group. It is up to the
+ * programmer to specify the right subsystem.
  * @subsystem : the targeted subsystem
  * @value     : the value to set
+ *
+ * @controllers : The controllers to use for this container.
+ * @dir         : The name of the directory containing the container's cgroup.
+ *                Not that this is a per-container setting.
  */
 struct lxc_cgroup {
-       char *subsystem;
-       char *value;
+       union {
+               /* information about a specific controller */
+               struct /* controller */ {
+                       char *subsystem;
+                       char *value;
+               };
+
+               /* meta information about cgroup configuration */
+               struct /* meta */ {
+                       char *controllers;
+                       char *dir;
+               };
+       };
 };
 
 #if !HAVE_SYS_RESOURCE_H
@@ -178,10 +96,10 @@ enum idtype {
 
 /*
  * id_map is an id map entry.  Form in confile is:
- * lxc.id_map = u 0    9800 100
- * lxc.id_map = u 1000 9900 100
- * lxc.id_map = g 0    9800 100
- * lxc.id_map = g 1000 9900 100
+ * lxc.idmap = u 0    9800 100
+ * lxc.idmap = u 1000 9900 100
+ * lxc.idmap = g 0    9800 100
+ * lxc.idmap = g 1000 9900 100
  * meaning the container can use uids and gids 0-99 and 1000-1099,
  * with [ug]id 0 mapping to [ug]id 9800 on the host, and [ug]id 1000 to
  * [ug]id 9900 on the host.
@@ -301,30 +219,32 @@ enum {
  * @lsm_se_context : selinux type to switch to or NULL
  */
 enum lxchooks {
-       LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_AUTODEV,
-       LXCHOOK_START, LXCHOOK_STOP, LXCHOOK_POSTSTOP, LXCHOOK_CLONE, LXCHOOK_DESTROY,
-       NUM_LXC_HOOKS};
-extern char *lxchook_names[NUM_LXC_HOOKS];
-
-struct saved_nic {
-       int ifindex;
-       char *orig_name;
+       LXCHOOK_PRESTART,
+       LXCHOOK_PREMOUNT,
+       LXCHOOK_MOUNT,
+       LXCHOOK_AUTODEV,
+       LXCHOOK_START,
+       LXCHOOK_STOP,
+       LXCHOOK_POSTSTOP,
+       LXCHOOK_CLONE,
+       LXCHOOK_DESTROY,
+       LXCHOOK_START_HOST,
+       NUM_LXC_HOOKS
 };
 
+extern char *lxchook_names[NUM_LXC_HOOKS];
+
 struct lxc_conf {
        int is_execute;
        char *fstab;
        unsigned int tty;
        unsigned int pts;
        int reboot;
-       int need_utmp_watch;
        signed long personality;
        struct utsname *utsname;
        struct lxc_list cgroup;
        struct lxc_list id_map;
        struct lxc_list network;
-       struct saved_nic *saved_nics;
-       int num_savednics;
        int auto_mounts;
        struct lxc_list mount_list;
        struct lxc_list caps;
@@ -342,24 +262,24 @@ struct lxc_conf {
        unsigned int lsm_aa_allow_incomplete;
        char *lsm_se_context;
        int tmp_umount_proc;
-       char *seccomp;  // filename with the seccomp rules
+       char *seccomp;  /* filename with the seccomp rules */
 #if HAVE_SCMP_FILTER_CTX
        scmp_filter_ctx seccomp_ctx;
 #endif
        int maincmd_fd;
-       unsigned 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
-       char *rcfile;   // Copy of the top level rcfile we read
-
-       // Logfile and logleve can be set in a container config file.
-       // Those function as defaults.  The defaults can be overriden
-       // by command line.  However we don't want the command line
-       // specified values to be saved on c->save_config().  So we
-       // store the config file specified values here.
-       char *logfile;  // the logfile as specifed in config
-       int loglevel;   // loglevel as specifed in config (if any)
+       unsigned 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 */
+       char *rcfile;   /* Copy of the top level rcfile we read */
+
+       /* Logfile and logleve can be set in a container config file. Those
+        * function as defaults. The defaults can be overriden by command line.
+        * However we don't want the command line specified values to be saved
+        * on c->save_config(). So we store the config file specified values
+        * here. */
+       char *logfile; /* the logfile as specifed in config */
+       int loglevel; /* loglevel as specifed in config (if any) */
        int logfd;
 
        int inherit_ns_fd[LXC_NS_MAX];
@@ -389,6 +309,9 @@ struct lxc_conf {
        char *unexpanded_config;
        size_t unexpanded_len, unexpanded_alloced;
 
+       /* default command for lxc-execute */
+       char *execute_cmd;
+
        /* init command */
        char *init_cmd;
 
@@ -409,6 +332,19 @@ struct lxc_conf {
 
        /* RLIMIT_* limits */
        struct lxc_list limits;
+
+       /* REMOVE IN LXC 3.0
+        * Indicator whether the current config file we're using contained any
+        * legacy configuration keys.
+        */
+       bool contains_legacy_key;
+
+       /* Contains generic info about the cgroup configuration for this
+        * container. Note that struct lxc_cgroup contains a union. It is only
+        * valid to access the members of the anonymous "meta" struct within
+        * that union.
+        */
+       struct lxc_cgroup cgroup_meta;
 };
 
 #ifdef HAVE_TLS
@@ -417,30 +353,15 @@ extern __thread struct lxc_conf *current_config;
 extern struct lxc_conf *current_config;
 #endif
 
-int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
-                 const char *lxcpath, char *argv[]);
-
+extern int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
+                        const char *lxcpath, char *argv[]);
 extern int detect_shared_rootfs(void);
-
-/*
- * Initialize the lxc configuration structure
- */
 extern struct lxc_conf *lxc_conf_init(void);
 extern void lxc_conf_free(struct lxc_conf *conf);
-
 extern int pin_rootfs(const char *rootfs);
-
-extern int lxc_requests_empty_network(struct lxc_handler *handler);
-extern int lxc_setup_networks_in_parent_namespaces(struct lxc_handler *handler);
-extern bool lxc_delete_network(struct lxc_handler *handler);
-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);
-
 extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
 extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
-
 extern int lxc_clear_config_caps(struct lxc_conf *c);
 extern int lxc_clear_config_keepcaps(struct lxc_conf *c);
 extern int lxc_clear_cgroups(struct lxc_conf *c, const char *key);
@@ -453,35 +374,29 @@ extern int lxc_clear_environment(struct lxc_conf *c);
 extern int lxc_clear_limits(struct lxc_conf *c, const char *key);
 extern int lxc_delete_autodev(struct lxc_handler *handler);
 extern void lxc_clear_includes(struct lxc_conf *conf);
-
 extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
                           const char *lxcpath);
-
-/*
- * Configure the container from inside
- */
-
-struct cgroup_process_info;
 extern int lxc_setup(struct lxc_handler *handler);
-
 extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
-
-extern void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf);
-
 extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype);
-extern int mapped_hostid(unsigned id, struct lxc_conf *conf, enum idtype idtype);
+extern int mapped_hostid(unsigned id, struct lxc_conf *conf,
+                        enum idtype idtype);
 extern int chown_mapped_root(char *path, struct lxc_conf *conf);
 extern int lxc_ttys_shift_ids(struct lxc_conf *c);
 extern int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
                         const char *fn_name);
+extern int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *),
+                           void *data, const char *fn_name);
 extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
                         char **mntdata);
 extern void tmp_proc_unmount(struct lxc_conf *lxc_conf);
-void remount_all_slave(void);
+extern void remount_all_slave(void);
 extern void suggest_default_idmap(void);
-FILE *make_anonymous_mount_file(struct lxc_list *mount);
-struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings);
-unsigned long add_required_remount_flags(const char *s, const char *d,
-               unsigned long flags);
-
-#endif
+extern FILE *make_anonymous_mount_file(struct lxc_list *mount);
+extern struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings);
+extern unsigned long add_required_remount_flags(const char *s, const char *d,
+                                               unsigned long flags);
+extern int run_script(const char *name, const char *section, const char *script,
+                     ...);
+
+#endif /* __LXC_CONF_H */
index 55917e8c45514762b931b27e4bab0192d6417d6c..e9435343d2d98a966f45f97fcdb0a5ee71c0db04 100644 (file)
@@ -4,6 +4,8 @@
  *
  * Authors:
  * Daniel Lezcano <daniel.lezcano at free.fr>
+ * Serge Hallyn <serge@hallyn.com>
+ * Christian Brauner <christian.brauner@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 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. */
+#define __STDC_FORMAT_MACROS
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <syslog.h>
+#include <time.h>
 #include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <inttypes.h> /* Required for PRIu64 to work. */
-#include <signal.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <sys/param.h>
 #include <sys/utsname.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <time.h>
-#include <dirent.h>
-#include <syslog.h>
 
-#include "bdev.h"
-#include "parse.h"
+#include "conf.h"
 #include "config.h"
 #include "confile.h"
 #include "confile_legacy.h"
 #include "confile_utils.h"
-#include "utils.h"
 #include "log.h"
-#include "conf.h"
-#include "network.h"
 #include "lxcseccomp.h"
+#include "network.h"
+#include "parse.h"
+#include "storage.h"
+#include "utils.h"
 
 #if HAVE_IFADDRS_H
 #include <ifaddrs.h>
 
 lxc_log_define(lxc_confile, lxc);
 
-#define lxc_config_define(name)                                                \
-       static int set_config_##name(const char *, const char *,        \
-                       struct lxc_conf *, void *);                     \
-       static int get_config_##name(const char *, char *, int,         \
-                       struct lxc_conf *, void *);                     \
-       static int clr_config_##name(const char *, struct lxc_conf *,   \
-                       void *);
+#define lxc_config_define(name)                                                \
+       static int set_config_##name(const char *, const char *,               \
+                                    struct lxc_conf *, void *);               \
+       static int get_config_##name(const char *, char *, int,                \
+                                    struct lxc_conf *, void *);               \
+       static int clr_config_##name(const char *, struct lxc_conf *, void *);
 
-
-lxc_config_define(personality);
-lxc_config_define(pty_max);
-lxc_config_define(tty_max);
-lxc_config_define(tty_dir);
-lxc_config_define(apparmor_profile);
+lxc_config_define(autodev);
 lxc_config_define(apparmor_allow_incomplete);
-lxc_config_define(selinux_context);
-lxc_config_define(cgroup);
+lxc_config_define(apparmor_profile);
+lxc_config_define(cap_drop);
+lxc_config_define(cap_keep);
+lxc_config_define(cgroup_controller);
+lxc_config_define(cgroup_dir);
+lxc_config_define(console_logfile);
+lxc_config_define(console_path);
+lxc_config_define(environment);
+lxc_config_define(ephemeral);
+lxc_config_define(execute_cmd);
+lxc_config_define(group);
+lxc_config_define(hooks);
 lxc_config_define(idmaps);
-lxc_config_define(log_level);
+lxc_config_define(includefiles);
+lxc_config_define(init_cmd);
+lxc_config_define(init_gid);
+lxc_config_define(init_uid);
 lxc_config_define(log_file);
+lxc_config_define(log_level);
+lxc_config_define(log_syslog);
+lxc_config_define(monitor);
 lxc_config_define(mount);
 lxc_config_define(mount_auto);
 lxc_config_define(mount_fstab);
-lxc_config_define(rootfs_mount);
-lxc_config_define(rootfs_options);
-lxc_config_define(rootfs_backend);
-lxc_config_define(rootfs_path);
-lxc_config_define(uts_name);
-lxc_config_define(hooks);
-lxc_config_define(net_type);
+lxc_config_define(net);
 lxc_config_define(net_flags);
-lxc_config_define(net_link);
-lxc_config_define(net_name);
-lxc_config_define(net_veth_pair);
-lxc_config_define(net_macvlan_mode);
 lxc_config_define(net_hwaddr);
-lxc_config_define(net_vlan_id);
-lxc_config_define(net_mtu);
 lxc_config_define(net_ipv4_address);
 lxc_config_define(net_ipv4_gateway);
-lxc_config_define(net_script_up);
-lxc_config_define(net_script_down);
 lxc_config_define(net_ipv6_address);
 lxc_config_define(net_ipv6_gateway);
+lxc_config_define(net_link);
+lxc_config_define(net_macvlan_mode);
+lxc_config_define(net_mtu);
+lxc_config_define(net_name);
 lxc_config_define(net_nic);
-lxc_config_define(net);
-lxc_config_define(cap_drop);
-lxc_config_define(cap_keep);
-lxc_config_define(console_logfile);
-lxc_config_define(console_path);
+lxc_config_define(net_script_down);
+lxc_config_define(net_script_up);
+lxc_config_define(net_type);
+lxc_config_define(net_veth_pair);
+lxc_config_define(net_vlan_id);
+lxc_config_define(no_new_privs);
+lxc_config_define(noop);
+lxc_config_define(personality);
+lxc_config_define(prlimit);
+lxc_config_define(pty_max);
+lxc_config_define(rootfs_backend);
+lxc_config_define(rootfs_mount);
+lxc_config_define(rootfs_options);
+lxc_config_define(rootfs_path);
 lxc_config_define(seccomp_profile);
-lxc_config_define(includefiles);
-lxc_config_define(autodev);
+lxc_config_define(selinux_context);
 lxc_config_define(signal_halt);
 lxc_config_define(signal_reboot);
 lxc_config_define(signal_stop);
 lxc_config_define(start);
-lxc_config_define(monitor);
-lxc_config_define(group);
-lxc_config_define(environment);
-lxc_config_define(init_cmd);
-lxc_config_define(init_uid);
-lxc_config_define(init_gid);
-lxc_config_define(ephemeral);
-lxc_config_define(log_syslog);
-lxc_config_define(no_new_privs);
-lxc_config_define(prlimit);
+lxc_config_define(tty_max);
+lxc_config_define(tty_dir);
+lxc_config_define(uts_name);
 
 static struct lxc_config_t config[] = {
-       { "lxc.arch",                      set_config_personality,                 get_config_personality,                 clr_config_personality,               },
-       { "lxc.pty.max",                   set_config_pty_max,                     get_config_pty_max,                     clr_config_pty_max,                   },
-       { "lxc.tty.dir",                   set_config_tty_dir,                     get_config_tty_dir,                     clr_config_tty_dir,                   },
-       { "lxc.tty.max",                   set_config_tty_max,                     get_config_tty_max,                     clr_config_tty_max,                   },
-
-       /* REMOVE IN LXC 3.0
-          legacy pts key
-        */
-       { "lxc.pts",                       set_config_pty_max,                     get_config_pty_max,                     clr_config_pty_max,                   },
-
-       /* REMOVE IN LXC 3.0
-          legacy devttydir key
-        */
-       { "lxc.devttydir",                 set_config_tty_dir,                     get_config_tty_dir,                     clr_config_tty_dir,                   },
-
-       /* REMOVE IN LXC 3.0
-          legacy tty key
-        */
-       { "lxc.tty",                       set_config_tty_max,                     get_config_tty_max,                     clr_config_tty_max,                   },
-
-       { "lxc.apparmor.profile",          set_config_apparmor_profile,            get_config_apparmor_profile,            clr_config_apparmor_profile,          },
-       { "lxc.apparmor.allow_incomplete", set_config_apparmor_allow_incomplete,   get_config_apparmor_allow_incomplete,   clr_config_apparmor_allow_incomplete, },
-       { "lxc.selinux.context",           set_config_selinux_context,             get_config_selinux_context,             clr_config_selinux_context,           },
-
-       /* REMOVE IN LXC 3.0
-          legacy security keys
-        */
-       { "lxc.aa_profile",                set_config_lsm_aa_profile,              get_config_lsm_aa_profile,              clr_config_lsm_aa_profile,            },
-       { "lxc.aa_allow_incomplete",       set_config_lsm_aa_incomplete,           get_config_lsm_aa_incomplete,           clr_config_lsm_aa_incomplete,         },
-       { "lxc.se_context",                set_config_lsm_se_context,              get_config_lsm_se_context,              clr_config_lsm_se_context,            },
-
-       { "lxc.cgroup",                    set_config_cgroup,                      get_config_cgroup,                      clr_config_cgroup,                    },
-       { "lxc.id_map",                    set_config_idmaps,                      get_config_idmaps,                      clr_config_idmaps,                    },
-       { "lxc.mount.entry",               set_config_mount,                       get_config_mount,                       clr_config_mount,                     },
-       { "lxc.mount.auto",                set_config_mount_auto,                  get_config_mount_auto,                  clr_config_mount_auto,                },
-       { "lxc.mount.fstab",               set_config_mount_fstab,                 get_config_mount_fstab,                 clr_config_mount_fstab,               },
-       { "lxc.rootfs.mount",              set_config_rootfs_mount,                get_config_rootfs_mount,                clr_config_rootfs_mount,              },
-       { "lxc.rootfs.options",            set_config_rootfs_options,              get_config_rootfs_options,              clr_config_rootfs_options,            },
-       { "lxc.rootfs.path",               set_config_rootfs_path,                 get_config_rootfs_path,                 clr_config_rootfs_path,               },
-
-       /* REMOVE IN LXC 3.0
-          legacy mount key
-        */
-       { "lxc.mount",                     set_config_mount_fstab,                 get_config_mount_fstab,                 clr_config_mount_fstab,               },
-
-       /* REMOVE IN LXC 3.0
-          legacy rootfs.backend key
-        */
-       { "lxc.rootfs.backend",            set_config_rootfs_backend,              get_config_rootfs_backend,              clr_config_rootfs_backend,            },
-
-       /* REMOVE IN LXC 3.0
-          legacy rootfs key
-        */
-       { "lxc.rootfs",                    set_config_rootfs_path,                 get_config_rootfs_path,                 clr_config_rootfs_path,               },
-
-       /* REMOVE IN LXC 3.0
-          legacy utsname key
-        */
-       { "lxc.utsname",                   set_config_uts_name,                    get_config_uts_name,                    clr_config_uts_name,                   },
-
-       { "lxc.uts.name",                  set_config_uts_name,                    get_config_uts_name,                    clr_config_uts_name,                   },
-       { "lxc.hook.pre-start",            set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
-       { "lxc.hook.pre-mount",            set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
-       { "lxc.hook.mount",                set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
-       { "lxc.hook.autodev",              set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
-       { "lxc.hook.start",                set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
-       { "lxc.hook.stop",                 set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
-       { "lxc.hook.post-stop",            set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
-       { "lxc.hook.clone",                set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
-       { "lxc.hook.destroy",              set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
-       { "lxc.hook",                      set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
-
-       /* REMOVE IN LXC 3.0
-          legacy security keys
-        */
-       { "lxc.network.type",              set_config_network_legacy_type,         get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.flags",             set_config_network_legacy_flags,        get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.link",              set_config_network_legacy_link,         get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.name",              set_config_network_legacy_name,         get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.macvlan.mode",      set_config_network_legacy_macvlan_mode, get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.veth.pair",         set_config_network_legacy_veth_pair,    get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.script.up",         set_config_network_legacy_script_up,    get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.script.down",       set_config_network_legacy_script_down,  get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.hwaddr",            set_config_network_legacy_hwaddr,       get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.mtu",               set_config_network_legacy_mtu,          get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.vlan.id",           set_config_network_legacy_vlan_id,      get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.ipv4.gateway",      set_config_network_legacy_ipv4_gateway, get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.ipv4",              set_config_network_legacy_ipv4,         get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.ipv6.gateway",      set_config_network_legacy_ipv6_gateway, get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.ipv6",              set_config_network_legacy_ipv6,         get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network.",                  set_config_network_legacy_nic,          get_config_network_legacy_item,         clr_config_network_legacy_item,       },
-       { "lxc.network",                   set_config_network_legacy,              get_config_network_legacy,              clr_config_network_legacy,            },
-
-       { "lxc.net.type",                  set_config_net_type,                    get_config_net_type,                    clr_config_net_type,                  },
-       { "lxc.net.flags",                 set_config_net_flags,                   get_config_net_flags,                   clr_config_net_flags,                 },
-       { "lxc.net.link",                  set_config_net_link,                    get_config_net_link,                    clr_config_net_link,                  },
-       { "lxc.net.name",                  set_config_net_name,                    get_config_net_name,                    clr_config_net_name,                  },
-       { "lxc.net.macvlan.mode",          set_config_net_macvlan_mode,            get_config_net_macvlan_mode,            clr_config_net_macvlan_mode,          },
-       { "lxc.net.veth.pair",             set_config_net_veth_pair,               get_config_net_veth_pair,               clr_config_net_veth_pair,             },
-       { "lxc.net.script.up",             set_config_net_script_up,               get_config_net_script_up,               clr_config_net_script_up,             },
-       { "lxc.net.script.down",           set_config_net_script_down,             get_config_net_script_down,             clr_config_net_script_down,           },
-       { "lxc.net.hwaddr",                set_config_net_hwaddr,                  get_config_net_hwaddr,                  clr_config_net_hwaddr,                },
-       { "lxc.net.mtu",                   set_config_net_mtu,                     get_config_net_mtu,                     clr_config_net_mtu,                   },
-       { "lxc.net.vlan.id",               set_config_net_vlan_id,                 get_config_net_vlan_id,                 clr_config_net_vlan_id,               },
-       { "lxc.net.ipv4.gateway",          set_config_net_ipv4_gateway,            get_config_net_ipv4_gateway,            clr_config_net_ipv4_gateway,          },
-       { "lxc.net.ipv4.address",          set_config_net_ipv4_address,            get_config_net_ipv4_address,            clr_config_net_ipv4_address,          },
-       { "lxc.net.ipv6.gateway",          set_config_net_ipv6_gateway,            get_config_net_ipv6_gateway,            clr_config_net_ipv6_gateway,          },
-       { "lxc.net.ipv6.address",          set_config_net_ipv6_address,            get_config_net_ipv6_address,            clr_config_net_ipv6_address,          },
-       { "lxc.net.",                      set_config_net_nic,                     get_config_net_nic,                     clr_config_net_nic,                   },
-       { "lxc.net",                       set_config_net,                         get_config_net,                         clr_config_net,                       },
-       { "lxc.cap.drop",                  set_config_cap_drop,                    get_config_cap_drop,                    clr_config_cap_drop,                  },
-       { "lxc.cap.keep",                  set_config_cap_keep,                    get_config_cap_keep,                    clr_config_cap_keep,                  },
-       { "lxc.console.logfile",           set_config_console_logfile,             get_config_console_logfile,             clr_config_console_logfile,           },
-       { "lxc.console.path",              set_config_console_path,                get_config_console_path,                clr_config_console_path,              },
-       { "lxc.seccomp.profile",           set_config_seccomp_profile,             get_config_seccomp_profile,             clr_config_seccomp_profile,           },
-       { "lxc.include",                   set_config_includefiles,                get_config_includefiles,                clr_config_includefiles,              },
-       { "lxc.autodev",                   set_config_autodev,                     get_config_autodev,                     clr_config_autodev,                   },
-
-       /* REMOVE IN LXC 3.0
-          legacy seccomp key
-        */
-       { "lxc.seccomp",                   set_config_seccomp_profile,             get_config_seccomp_profile,             clr_config_seccomp_profile,           },
-
-       /* REMOVE IN LXC 3.0
-          legacy console key
-        */
-       { "lxc.console",                   set_config_console_path,                get_config_console_path,                clr_config_console_path,              },
-
-       /* REMOVE IN LXC 3.0
-          legacy singal keys
-        */
-       { "lxc.haltsignal",                set_config_signal_halt,                 get_config_signal_halt,                 clr_config_signal_halt,               },
-       { "lxc.rebootsignal",              set_config_signal_reboot,               get_config_signal_reboot,               clr_config_signal_reboot,             },
-       { "lxc.stopsignal",                set_config_signal_stop,                 get_config_signal_stop,                 clr_config_signal_stop,               },
-
-       { "lxc.signal.halt",               set_config_signal_halt,                 get_config_signal_halt,                 clr_config_signal_halt,               },
-       { "lxc.signal.reboot",             set_config_signal_reboot,               get_config_signal_reboot,               clr_config_signal_reboot,             },
-       { "lxc.signal.stop",               set_config_signal_stop,                 get_config_signal_stop,                 clr_config_signal_stop,               },
-       { "lxc.start.auto",                set_config_start,                       get_config_start,                       clr_config_start,                     },
-       { "lxc.start.delay",               set_config_start,                       get_config_start,                       clr_config_start,                     },
-       { "lxc.start.order",               set_config_start,                       get_config_start,                       clr_config_start,                     },
-       { "lxc.monitor.unshare",           set_config_monitor,                     get_config_monitor,                     clr_config_monitor,                   },
-       { "lxc.group",                     set_config_group,                       get_config_group,                       clr_config_group,                     },
-       { "lxc.environment",               set_config_environment,                 get_config_environment,                 clr_config_environment,               },
-       { "lxc.ephemeral",                 set_config_ephemeral,                   get_config_ephemeral,                   clr_config_ephemeral,                 },
-       { "lxc.no_new_privs",              set_config_no_new_privs,                get_config_no_new_privs,                clr_config_no_new_privs,              },
-
-       /* REMOVE IN LXC 3.0: legacy keys  [START]*/
-       { "lxc.syslog",                    set_config_log_syslog,                  get_config_log_syslog,                  clr_config_log_syslog,                },
-       { "lxc.loglevel",                  set_config_log_level,                   get_config_log_level,                   clr_config_log_level,                 },
-       { "lxc.logfile",                   set_config_log_file,                    get_config_log_file,                    clr_config_log_file,                  },
-       { "lxc.init_cmd",                  set_config_init_cmd,                    get_config_init_cmd,                    clr_config_init_cmd,                  },
-       { "lxc.init_uid",                  set_config_init_uid,                    get_config_init_uid,                    clr_config_init_uid,                  },
-       { "lxc.init_gid",                  set_config_init_gid,                    get_config_init_gid,                    clr_config_init_gid,                  },
-       { "lxc.limit",                     set_config_limit,                       get_config_limit,                       clr_config_limit,                     },
-       /* REMOVE IN LXC 3.0: legacy keys  [END]*/
-
-       { "lxc.log.syslog",                set_config_log_syslog,                  get_config_log_syslog,                  clr_config_log_syslog,                },
-       { "lxc.log.level",                 set_config_log_level,                   get_config_log_level,                   clr_config_log_level,                 },
-       { "lxc.log.file",                  set_config_log_file,                    get_config_log_file,                    clr_config_log_file,                  },
-       { "lxc.init.cmd",                  set_config_init_cmd,                    get_config_init_cmd,                    clr_config_init_cmd,                  },
-       { "lxc.init.uid",                  set_config_init_uid,                    get_config_init_uid,                    clr_config_init_uid,                  },
-       { "lxc.init.gid",                  set_config_init_gid,                    get_config_init_gid,                    clr_config_init_gid,                  },
-       { "lxc.prlimit",                   set_config_prlimit,                     get_config_prlimit,                     clr_config_prlimit,                   },
+                                           /* REMOVE in LXC 3.0 */
+       { "lxc.arch",                      false,                  set_config_personality,                 get_config_personality,                 clr_config_personality,               },
+       { "lxc.apparmor.profile",          false,                  set_config_apparmor_profile,            get_config_apparmor_profile,            clr_config_apparmor_profile,          },
+       { "lxc.apparmor.allow_incomplete", false,                  set_config_apparmor_allow_incomplete,   get_config_apparmor_allow_incomplete,   clr_config_apparmor_allow_incomplete, },
+       { "lxc.autodev",                   false,                  set_config_autodev,                     get_config_autodev,                     clr_config_autodev,                   },
+       { "lxc.cap.drop",                  false,                  set_config_cap_drop,                    get_config_cap_drop,                    clr_config_cap_drop,                  },
+       { "lxc.cap.keep",                  false,                  set_config_cap_keep,                    get_config_cap_keep,                    clr_config_cap_keep,                  },
+       { "lxc.cgroup.dir",                false,                  set_config_cgroup_dir,                  get_config_cgroup_dir,                  clr_config_cgroup_dir,                },
+       { "lxc.cgroup",                    false,                  set_config_cgroup_controller,           get_config_cgroup_controller,           clr_config_cgroup_controller,         },
+       { "lxc.console.logfile",           false,                  set_config_console_logfile,             get_config_console_logfile,             clr_config_console_logfile,           },
+       { "lxc.console.path",              false,                  set_config_console_path,                get_config_console_path,                clr_config_console_path,              },
+       { "lxc.environment",               false,                  set_config_environment,                 get_config_environment,                 clr_config_environment,               },
+       { "lxc.ephemeral",                 false,                  set_config_ephemeral,                   get_config_ephemeral,                   clr_config_ephemeral,                 },
+       { "lxc.execute.cmd",               false,                  set_config_execute_cmd,                 get_config_execute_cmd,                 clr_config_execute_cmd,                  },
+       { "lxc.group",                     false,                  set_config_group,                       get_config_group,                       clr_config_group,                     },
+       { "lxc.hook.autodev",              false,                  set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
+       { "lxc.hook.clone",                false,                  set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
+       { "lxc.hook.destroy",              false,                  set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
+       { "lxc.hook.mount",                false,                  set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
+       { "lxc.hook.post-stop",            false,                  set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
+       { "lxc.hook.start-host",           false,                  set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
+       { "lxc.hook.pre-start",            false,                  set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
+       { "lxc.hook.pre-mount",            false,                  set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
+       { "lxc.hook.start",                false,                  set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
+       { "lxc.hook.stop",                 false,                  set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
+       { "lxc.hook",                      false,                  set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
+       { "lxc.idmap",                     false,                  set_config_idmaps,                      get_config_idmaps,                      clr_config_idmaps,                    },
+       { "lxc.include",                   false,                  set_config_includefiles,                get_config_includefiles,                clr_config_includefiles,              },
+       { "lxc.init.cmd",                  false,                  set_config_init_cmd,                    get_config_init_cmd,                    clr_config_init_cmd,                  },
+       { "lxc.init.gid",                  false,                  set_config_init_gid,                    get_config_init_gid,                    clr_config_init_gid,                  },
+       { "lxc.init.uid",                  false,                  set_config_init_uid,                    get_config_init_uid,                    clr_config_init_uid,                  },
+       { "lxc.log.file",                  false,                  set_config_log_file,                    get_config_log_file,                    clr_config_log_file,                  },
+       { "lxc.log.level",                 false,                  set_config_log_level,                   get_config_log_level,                   clr_config_log_level,                 },
+       { "lxc.log.syslog",                false,                  set_config_log_syslog,                  get_config_log_syslog,                  clr_config_log_syslog,                },
+       { "lxc.monitor.unshare",           false,                  set_config_monitor,                     get_config_monitor,                     clr_config_monitor,                   },
+       { "lxc.mount.auto",                false,                  set_config_mount_auto,                  get_config_mount_auto,                  clr_config_mount_auto,                },
+       { "lxc.mount.entry",               false,                  set_config_mount,                       get_config_mount,                       clr_config_mount,                     },
+       { "lxc.mount.fstab",               false,                  set_config_mount_fstab,                 get_config_mount_fstab,                 clr_config_mount_fstab,               },
+
+       /* [START]: REMOVE IN LXC 3.0 */
+       { "lxc.network.type",              true,                   set_config_network_legacy_type,         get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.flags",             true,                   set_config_network_legacy_flags,        get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.link",              true,                   set_config_network_legacy_link,         get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.name",              true,                   set_config_network_legacy_name,         get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.macvlan.mode",      true,                   set_config_network_legacy_macvlan_mode, get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.veth.pair",         true,                   set_config_network_legacy_veth_pair,    get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.script.up",         true,                   set_config_network_legacy_script_up,    get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.script.down",       true,                   set_config_network_legacy_script_down,  get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.hwaddr",            true,                   set_config_network_legacy_hwaddr,       get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.mtu",               true,                   set_config_network_legacy_mtu,          get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.vlan.id",           true,                   set_config_network_legacy_vlan_id,      get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.ipv4.gateway",      true,                   set_config_network_legacy_ipv4_gateway, get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.ipv4",              true,                   set_config_network_legacy_ipv4,         get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.ipv6.gateway",      true,                   set_config_network_legacy_ipv6_gateway, get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.ipv6",              true,                   set_config_network_legacy_ipv6,         get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network.",                  true,                   set_config_network_legacy_nic,          get_config_network_legacy_item,         clr_config_network_legacy_item,       },
+       { "lxc.network",                   true,                   set_config_network_legacy,              get_config_network_legacy,              clr_config_network_legacy,            },
+       /* [END]: REMOVE IN LXC 3.0 */
+
+       { "lxc.net.flags",                 false,                  set_config_net_flags,                   get_config_net_flags,                   clr_config_net_flags,                 },
+       { "lxc.net.hwaddr",                false,                  set_config_net_hwaddr,                  get_config_net_hwaddr,                  clr_config_net_hwaddr,                },
+       { "lxc.net.ipv4.address",          false,                  set_config_net_ipv4_address,            get_config_net_ipv4_address,            clr_config_net_ipv4_address,          },
+       { "lxc.net.ipv4.gateway",          false,                  set_config_net_ipv4_gateway,            get_config_net_ipv4_gateway,            clr_config_net_ipv4_gateway,          },
+       { "lxc.net.ipv6.address",          false,                  set_config_net_ipv6_address,            get_config_net_ipv6_address,            clr_config_net_ipv6_address,          },
+       { "lxc.net.ipv6.gateway",          false,                  set_config_net_ipv6_gateway,            get_config_net_ipv6_gateway,            clr_config_net_ipv6_gateway,          },
+       { "lxc.net.link",                  false,                  set_config_net_link,                    get_config_net_link,                    clr_config_net_link,                  },
+       { "lxc.net.macvlan.mode",          false,                  set_config_net_macvlan_mode,            get_config_net_macvlan_mode,            clr_config_net_macvlan_mode,          },
+       { "lxc.net.mtu",                   false,                  set_config_net_mtu,                     get_config_net_mtu,                     clr_config_net_mtu,                   },
+       { "lxc.net.name",                  false,                  set_config_net_name,                    get_config_net_name,                    clr_config_net_name,                  },
+       { "lxc.net.script.down",           false,                  set_config_net_script_down,             get_config_net_script_down,             clr_config_net_script_down,           },
+       { "lxc.net.script.up",             false,                  set_config_net_script_up,               get_config_net_script_up,               clr_config_net_script_up,             },
+       { "lxc.net.type",                  false,                  set_config_net_type,                    get_config_net_type,                    clr_config_net_type,                  },
+       { "lxc.net.vlan.id",               false,                  set_config_net_vlan_id,                 get_config_net_vlan_id,                 clr_config_net_vlan_id,               },
+       { "lxc.net.veth.pair",             false,                  set_config_net_veth_pair,               get_config_net_veth_pair,               clr_config_net_veth_pair,             },
+       { "lxc.net.",                      false,                  set_config_net_nic,                     get_config_net_nic,                     clr_config_net_nic,                   },
+       { "lxc.net",                       false,                  set_config_net,                         get_config_net,                         clr_config_net,                       },
+       { "lxc.no_new_privs",              false,                  set_config_no_new_privs,                get_config_no_new_privs,                clr_config_no_new_privs,              },
+       { "lxc.prlimit",                   false,                  set_config_prlimit,                     get_config_prlimit,                     clr_config_prlimit,                   },
+       { "lxc.pty.max",                   false,                  set_config_pty_max,                     get_config_pty_max,                     clr_config_pty_max,                   },
+       { "lxc.rootfs.mount",              false,                  set_config_rootfs_mount,                get_config_rootfs_mount,                clr_config_rootfs_mount,              },
+       { "lxc.rootfs.options",            false,                  set_config_rootfs_options,              get_config_rootfs_options,              clr_config_rootfs_options,            },
+       { "lxc.rootfs.path",               false,                  set_config_rootfs_path,                 get_config_rootfs_path,                 clr_config_rootfs_path,               },
+       { "lxc.seccomp.profile",           false,                  set_config_seccomp_profile,             get_config_seccomp_profile,             clr_config_seccomp_profile,           },
+       { "lxc.selinux.context",           false,                  set_config_selinux_context,             get_config_selinux_context,             clr_config_selinux_context,           },
+       { "lxc.signal.halt",               false,                  set_config_signal_halt,                 get_config_signal_halt,                 clr_config_signal_halt,               },
+       { "lxc.signal.reboot",             false,                  set_config_signal_reboot,               get_config_signal_reboot,               clr_config_signal_reboot,             },
+       { "lxc.signal.stop",               false,                  set_config_signal_stop,                 get_config_signal_stop,                 clr_config_signal_stop,               },
+       { "lxc.start.auto",                false,                  set_config_start,                       get_config_start,                       clr_config_start,                     },
+       { "lxc.start.delay",               false,                  set_config_start,                       get_config_start,                       clr_config_start,                     },
+       { "lxc.start.order",               false,                  set_config_start,                       get_config_start,                       clr_config_start,                     },
+       { "lxc.tty.dir",                   false,                  set_config_tty_dir,                     get_config_tty_dir,                     clr_config_tty_dir,                   },
+       { "lxc.tty.max",                   false,                  set_config_tty_max,                     get_config_tty_max,                     clr_config_tty_max,                   },
+       { "lxc.uts.name",                  false,                  set_config_uts_name,                    get_config_uts_name,                    clr_config_uts_name,                  },
+
+       /* [START]: REMOVE IN LXC 3.0 */
+       { "lxc.pts",                       true,                   set_config_pty_max,                     get_config_pty_max,                     clr_config_pty_max,                   },
+       { "lxc.devttydir",                 true,                   set_config_tty_dir,                     get_config_tty_dir,                     clr_config_tty_dir,                   },
+       { "lxc.tty",                       true,                   set_config_tty_max,                     get_config_tty_max,                     clr_config_tty_max,                   },
+       { "lxc.aa_profile",                true,                   set_config_lsm_aa_profile,              get_config_lsm_aa_profile,              clr_config_lsm_aa_profile,            },
+       { "lxc.aa_allow_incomplete",       true,                   set_config_lsm_aa_incomplete,           get_config_lsm_aa_incomplete,           clr_config_lsm_aa_incomplete,         },
+       { "lxc.se_context",                true,                   set_config_lsm_se_context,              get_config_lsm_se_context,              clr_config_lsm_se_context,            },
+       { "lxc.id_map",                    true,                   set_config_idmaps,                      get_config_idmaps,                      clr_config_idmaps,                    },
+       { "lxc.mount",                     true,                   set_config_mount_fstab,                 get_config_mount_fstab,                 clr_config_mount_fstab,               },
+       { "lxc.rootfs.backend",            true,                   set_config_rootfs_backend,              get_config_rootfs_backend,              clr_config_rootfs_backend,            },
+       { "lxc.rootfs",                    true,                   set_config_rootfs_path,                 get_config_rootfs_path,                 clr_config_rootfs_path,               },
+       { "lxc.utsname",                   true,                   set_config_uts_name,                    get_config_uts_name,                    clr_config_uts_name,                  },
+       { "lxc.seccomp",                   true,                   set_config_seccomp_profile,             get_config_seccomp_profile,             clr_config_seccomp_profile,           },
+       { "lxc.console",                   true,                   set_config_console_path,                get_config_console_path,                clr_config_console_path,              },
+       { "lxc.haltsignal",                true,                   set_config_signal_halt,                 get_config_signal_halt,                 clr_config_signal_halt,               },
+       { "lxc.rebootsignal",              true,                   set_config_signal_reboot,               get_config_signal_reboot,               clr_config_signal_reboot,             },
+       { "lxc.stopsignal",                true,                   set_config_signal_stop,                 get_config_signal_stop,                 clr_config_signal_stop,               },
+       { "lxc.syslog",                    true,                   set_config_log_syslog,                  get_config_log_syslog,                  clr_config_log_syslog,                },
+       { "lxc.kmsg",                      true,                   set_config_noop,                        get_config_noop,                        clr_config_noop,                      },
+       { "lxc.loglevel",                  true,                   set_config_log_level,                   get_config_log_level,                   clr_config_log_level,                 },
+       { "lxc.logfile",                   true,                   set_config_log_file,                    get_config_log_file,                    clr_config_log_file,                  },
+       { "lxc.init_cmd",                  true,                   set_config_init_cmd,                    get_config_init_cmd,                    clr_config_init_cmd,                  },
+       { "lxc.init_uid",                  true,                   set_config_init_uid,                    get_config_init_uid,                    clr_config_init_uid,                  },
+       { "lxc.init_gid",                  true,                   set_config_init_gid,                    get_config_init_gid,                    clr_config_init_gid,                  },
+       { "lxc.limit",                     true,                   set_config_limit,                       get_config_limit,                       clr_config_limit,                     },
+       { "lxc.pivotdir",                  true,                   set_config_noop,                        get_config_noop,                        clr_config_noop,                      },
+       /* [END]: REMOVE IN LXC 3.0 */
 };
 
 struct signame {
@@ -386,35 +347,15 @@ static const struct signame signames[] = {
 
 static const size_t config_size = sizeof(config) / sizeof(struct lxc_config_t);
 
-extern struct lxc_config_t *lxc_getconfig(const char *key)
+struct lxc_config_t *lxc_get_config(const char *key)
 {
        size_t i;
 
        for (i = 0; i < config_size; i++)
                if (!strncmp(config[i].name, key, strlen(config[i].name)))
                        return &config[i];
-       return NULL;
-}
-
-int lxc_listconfigs(char *retv, int inlen)
-{
-       size_t i;
-       int len;
-       int fulllen = 0;
 
-       if (!retv)
-               inlen = 0;
-       else
-               memset(retv, 0, inlen);
-
-       for (i = 0; i < config_size; i++) {
-               char *s = config[i].name;
-               if (s[strlen(s) - 1] == '.')
-                       continue;
-               strprint(retv, inlen, "%s\n", s);
-       }
-
-       return fulllen;
+       return NULL;
 }
 
 static int set_config_net(const char *key, const char *value,
@@ -465,98 +406,6 @@ static int set_config_net_type(const char *key, const char *value,
        return 0;
 }
 
-/*
- * If you have p="lxc.net.0.link", pass it p+8
- * to get back '0' (the index of the nic).
- */
-static int get_network_netdev_idx(const char *key)
-{
-       int ret, idx;
-
-       if (*key < '0' || *key > '9')
-               return -1;
-
-       ret = sscanf(key, "%d", &idx);
-       if (ret != 1)
-               return -1;
-
-       return idx;
-}
-
-/*
- * If you have p="lxc.net.0", pass this p+8 and it will return
- * the netdev of the first configured nic.
- */
-static struct lxc_netdev *get_netdev_from_key(const char *key,
-                                             struct lxc_list *network)
-{
-       int idx;
-       struct lxc_list *it;
-       int i = 0;
-       struct lxc_netdev *netdev = NULL;
-
-       idx = get_network_netdev_idx(key);
-       if (idx == -1)
-               return NULL;
-
-       lxc_list_for_each(it, network) {
-               if (idx == i++) {
-                       netdev = it->elem;
-                       break;
-               }
-       }
-
-       return netdev;
-}
-
-extern int lxc_list_nicconfigs(struct lxc_conf *c, const char *key, char *retv,
-                              int inlen)
-{
-       struct lxc_netdev *netdev;
-       int len;
-       int fulllen = 0;
-
-       netdev = get_netdev_from_key(key + 8, &c->network);
-       if (!netdev)
-               return -1;
-
-       if (!retv)
-               inlen = 0;
-       else
-               memset(retv, 0, inlen);
-
-       strprint(retv, inlen, "type\n");
-       strprint(retv, inlen, "script.up\n");
-       strprint(retv, inlen, "script.down\n");
-       if (netdev->type != LXC_NET_EMPTY) {
-               strprint(retv, inlen, "flags\n");
-               strprint(retv, inlen, "link\n");
-               strprint(retv, inlen, "name\n");
-               strprint(retv, inlen, "hwaddr\n");
-               strprint(retv, inlen, "mtu\n");
-               strprint(retv, inlen, "ipv6.address\n");
-               strprint(retv, inlen, "ipv6.gateway\n");
-               strprint(retv, inlen, "ipv4.address\n");
-               strprint(retv, inlen, "ipv4.gateway\n");
-       }
-
-       switch (netdev->type) {
-       case LXC_NET_VETH:
-               strprint(retv, inlen, "veth.pair\n");
-               break;
-       case LXC_NET_MACVLAN:
-               strprint(retv, inlen, "macvlan.mode\n");
-               break;
-       case LXC_NET_VLAN:
-               strprint(retv, inlen, "vlan.id\n");
-               break;
-       case LXC_NET_PHYS:
-               break;
-       }
-
-       return fulllen;
-}
-
 static int set_config_net_flags(const char *key, const char *value,
                                struct lxc_conf *lxc_conf, void *data)
 {
@@ -578,7 +427,7 @@ static int set_config_net_flags(const char *key, const char *value,
 }
 
 static int create_matched_ifnames(const char *value, struct lxc_conf *lxc_conf,
-                          struct lxc_netdev *netdev)
+                                 struct lxc_netdev *netdev)
 {
        struct ifaddrs *ifaddr, *ifa;
        int n;
@@ -640,7 +489,7 @@ static int set_config_net_link(const char *key, const char *value,
        if (value[strlen(value) - 1] == '+' && netdev->type == LXC_NET_PHYS)
                ret = create_matched_ifnames(value, lxc_conf, netdev);
        else
-               ret = network_ifname(&netdev->link, value);
+               ret = network_ifname(netdev->link, value);
 
        return ret;
 }
@@ -660,7 +509,7 @@ static int set_config_net_name(const char *key, const char *value,
        if (!netdev)
                return -1;
 
-       return network_ifname(&netdev->name, value);
+       return network_ifname(netdev->name, value);
 }
 
 static int set_config_net_veth_pair(const char *key, const char *value,
@@ -678,7 +527,7 @@ static int set_config_net_veth_pair(const char *key, const char *value,
        if (!netdev)
                return -1;
 
-       return network_ifname(&netdev->priv.veth_attr.pair, value);
+       return network_ifname(netdev->priv.veth_attr.pair, value);
 }
 
 static int set_config_net_macvlan_mode(const char *key, const char *value,
@@ -716,10 +565,9 @@ static int set_config_net_hwaddr(const char *key, const char *value,
                return -1;
 
        new_value = strdup(value);
-       if (!new_value) {
-               SYSERROR("failed to strdup \"%s\"", value);
+       if (!new_value)
                return -1;
-       }
+
        rand_complete_hwaddr(new_value);
 
        if (lxc_config_value_empty(new_value)) {
@@ -735,6 +583,7 @@ static int set_config_net_hwaddr(const char *key, const char *value,
 static int set_config_net_vlan_id(const char *key, const char *value,
                                  struct lxc_conf *lxc_conf, void *data)
 {
+       int ret;
        struct lxc_netdev *netdev;
 
        if (lxc_config_value_empty(value))
@@ -747,7 +596,8 @@ static int set_config_net_vlan_id(const char *key, const char *value,
        if (!netdev)
                return -1;
 
-       if (get_u16(&netdev->priv.vlan_attr.vid, value, 0))
+       ret = get_u16(&netdev->priv.vlan_attr.vid, value, 0);
+       if (ret < 0)
                return -1;
 
        return 0;
@@ -774,6 +624,7 @@ static int set_config_net_mtu(const char *key, const char *value,
 static int set_config_net_ipv4_address(const char *key, const char *value,
                                       struct lxc_conf *lxc_conf, void *data)
 {
+       int ret;
        struct lxc_netdev *netdev;
        struct lxc_inetdev *inetdev;
        struct lxc_list *list;
@@ -791,15 +642,13 @@ static int set_config_net_ipv4_address(const char *key, const char *value,
                return -1;
 
        inetdev = malloc(sizeof(*inetdev));
-       if (!inetdev) {
-               SYSERROR("failed to allocate ipv4 address");
+       if (!inetdev)
                return -1;
-       }
+
        memset(inetdev, 0, sizeof(*inetdev));
 
        list = malloc(sizeof(*list));
        if (!list) {
-               SYSERROR("failed to allocate memory");
                free(inetdev);
                return -1;
        }
@@ -809,7 +658,6 @@ static int set_config_net_ipv4_address(const char *key, const char *value,
 
        addr = strdup(value);
        if (!addr) {
-               ERROR("no address specified");
                free(inetdev);
                free(list);
                return -1;
@@ -827,25 +675,31 @@ static int set_config_net_ipv4_address(const char *key, const char *value,
                prefix = slash + 1;
        }
 
-       if (!inet_pton(AF_INET, addr, &inetdev->addr)) {
-               SYSERROR("invalid ipv4 address: %s", value);
+       ret = inet_pton(AF_INET, addr, &inetdev->addr);
+       if (!ret || ret < 0) {
+               SYSERROR("Invalid ipv4 address \"%s\"", value);
                free(inetdev);
                free(addr);
                free(list);
                return -1;
        }
 
-       if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) {
-               SYSERROR("invalid ipv4 broadcast address: %s", value);
-               free(inetdev);
-               free(list);
-               free(addr);
-               return -1;
+       if (bcast) {
+               ret = inet_pton(AF_INET, bcast, &inetdev->bcast);
+               if (!ret || ret < 0) {
+                       SYSERROR("Invalid ipv4 broadcast address \"%s\"", value);
+                       free(inetdev);
+                       free(list);
+                       free(addr);
+                       return -1;
+               }
+
        }
 
        /* No prefix specified, determine it from the network class. */
        if (prefix) {
-               if (lxc_safe_uint(prefix, &inetdev->prefix) < 0)
+               ret = lxc_safe_uint(prefix, &inetdev->prefix);
+               if (ret < 0)
                        return -1;
        } else {
                inetdev->prefix = config_ip_prefix(&inetdev->addr);
@@ -856,8 +710,7 @@ static int set_config_net_ipv4_address(const char *key, const char *value,
         */
        if (!bcast) {
                inetdev->bcast.s_addr = inetdev->addr.s_addr;
-               inetdev->bcast.s_addr |=
-                   htonl(INADDR_BROADCAST >> inetdev->prefix);
+               inetdev->bcast.s_addr |= htonl(INADDR_BROADCAST >> inetdev->prefix);
        }
 
        lxc_list_add_tail(&netdev->ipv4, list);
@@ -887,16 +740,16 @@ static int set_config_net_ipv4_gateway(const char *key, const char *value,
                netdev->ipv4_gateway = NULL;
                netdev->ipv4_gateway_auto = true;
        } else {
+               int ret;
                struct in_addr *gw;
 
                gw = malloc(sizeof(*gw));
-               if (!gw) {
-                       SYSERROR("failed to allocate ipv4 gateway address");
+               if (!gw)
                        return -1;
-               }
 
-               if (!inet_pton(AF_INET, value, gw)) {
-                       SYSERROR("invalid ipv4 gateway address: %s", value);
+               ret = inet_pton(AF_INET, value, gw);
+               if (!ret || ret < 0) {
+                       SYSERROR("Invalid ipv4 gateway address \"%s\"", value);
                        free(gw);
                        return -1;
                }
@@ -911,6 +764,7 @@ static int set_config_net_ipv4_gateway(const char *key, const char *value,
 static int set_config_net_ipv6_address(const char *key, const char *value,
                                       struct lxc_conf *lxc_conf, void *data)
 {
+       int ret;
        struct lxc_netdev *netdev;
        struct lxc_inet6dev *inet6dev;
        struct lxc_list *list;
@@ -927,15 +781,13 @@ static int set_config_net_ipv6_address(const char *key, const char *value,
                return -1;
 
        inet6dev = malloc(sizeof(*inet6dev));
-       if (!inet6dev) {
-               SYSERROR("failed to allocate ipv6 address");
+       if (!inet6dev)
                return -1;
-       }
+
        memset(inet6dev, 0, sizeof(*inet6dev));
 
        list = malloc(sizeof(*list));
        if (!list) {
-               SYSERROR("failed to allocate memory");
                free(inet6dev);
                return -1;
        }
@@ -945,7 +797,6 @@ static int set_config_net_ipv6_address(const char *key, const char *value,
 
        valdup = strdup(value);
        if (!valdup) {
-               ERROR("no address specified");
                free(list);
                free(inet6dev);
                return -1;
@@ -960,8 +811,9 @@ static int set_config_net_ipv6_address(const char *key, const char *value,
                        return -1;
        }
 
-       if (!inet_pton(AF_INET6, valdup, &inet6dev->addr)) {
-               SYSERROR("invalid ipv6 address: %s", valdup);
+       ret = inet_pton(AF_INET6, valdup, &inet6dev->addr);
+       if (!ret || ret < 0) {
+               SYSERROR("Invalid ipv6 address \"%s\"", valdup);
                free(list);
                free(inet6dev);
                free(valdup);
@@ -995,16 +847,16 @@ static int set_config_net_ipv6_gateway(const char *key, const char *value,
                netdev->ipv6_gateway = NULL;
                netdev->ipv6_gateway_auto = true;
        } else {
+               int ret;
                struct in6_addr *gw;
 
                gw = malloc(sizeof(*gw));
-               if (!gw) {
-                       SYSERROR("failed to allocate ipv6 gateway address");
+               if (!gw)
                        return -1;
-               }
 
-               if (!inet_pton(AF_INET6, value, gw)) {
-                       SYSERROR("invalid ipv6 gateway address: %s", value);
+               ret = inet_pton(AF_INET6, value, gw);
+               if (!ret || ret < 0) {
+                       SYSERROR("Invalid ipv6 gateway address \"%s\"", value);
                        free(gw);
                        return -1;
                }
@@ -1073,6 +925,12 @@ static int set_config_seccomp_profile(const char *key, const char *value,
        return set_config_path_item(&lxc_conf->seccomp, value);
 }
 
+static int set_config_execute_cmd(const char *key, const char *value,
+                              struct lxc_conf *lxc_conf, void *data)
+{
+       return set_config_path_item(&lxc_conf->execute_cmd, value);
+}
+
 static int set_config_init_cmd(const char *key, const char *value,
                               struct lxc_conf *lxc_conf, void *data)
 {
@@ -1084,15 +942,14 @@ static int set_config_init_uid(const char *key, const char *value,
 {
        unsigned int init_uid;
 
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->init_uid = 0;
                return 0;
        }
 
-       /* Parse new config value. */
        if (lxc_safe_uint(value, &init_uid) < 0)
                return -1;
+
        lxc_conf->init_uid = init_uid;
 
        return 0;
@@ -1103,15 +960,14 @@ static int set_config_init_gid(const char *key, const char *value,
 {
        unsigned int init_gid;
 
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->init_gid = 0;
                return 0;
        }
 
-       /* Parse new config value. */
        if (lxc_safe_uint(value, &init_gid) < 0)
                return -1;
+
        lxc_conf->init_gid = init_gid;
 
        return 0;
@@ -1126,17 +982,18 @@ static int set_config_hooks(const char *key, const char *value,
                return lxc_clear_hooks(lxc_conf, key);
 
        if (strcmp(key + 4, "hook") == 0) {
-               ERROR("lxc.hook cannot take a value");
+               ERROR("lxc.hook must not have a value");
                return -1;
        }
+
        copy = strdup(value);
-       if (!copy) {
-               SYSERROR("failed to dup string '%s'", value);
+       if (!copy)
                return -1;
-       }
 
        if (strcmp(key + 9, "pre-start") == 0)
                return add_hook(lxc_conf, LXCHOOK_PRESTART, copy);
+       else if (strcmp(key + 9, "start-host") == 0)
+               return add_hook(lxc_conf, LXCHOOK_START_HOST, copy);
        else if (strcmp(key + 9, "pre-mount") == 0)
                return add_hook(lxc_conf, LXCHOOK_PREMOUNT, copy);
        else if (strcmp(key + 9, "autodev") == 0)
@@ -1154,7 +1011,6 @@ static int set_config_hooks(const char *key, const char *value,
        else if (strcmp(key + 9, "destroy") == 0)
                return add_hook(lxc_conf, LXCHOOK_DESTROY, copy);
 
-       SYSERROR("Unknown key: %s", key);
        free(copy);
        return -1;
 }
@@ -1167,7 +1023,7 @@ static int set_config_personality(const char *key, const char *value,
        if (personality >= 0)
                lxc_conf->personality = personality;
        else
-               WARN("unsupported personality '%s'", value);
+               WARN("Unsupported personality \"%s\"", value);
 
        return 0;
 }
@@ -1175,13 +1031,11 @@ static int set_config_personality(const char *key, const char *value,
 static int set_config_pty_max(const char *key, const char *value,
                              struct lxc_conf *lxc_conf, void *data)
 {
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->pts = 0;
                return 0;
        }
 
-       /* Parse new config value. */
        if (lxc_safe_uint(value, &lxc_conf->pts) < 0)
                return -1;
 
@@ -1201,13 +1055,11 @@ static int set_config_start(const char *key, const char *value,
        is_empty = lxc_config_value_empty(value);
 
        if (*(key + 10) == 'a') { /* lxc.start.auto */
-               /* Set config value to default. */
                if (is_empty) {
                        lxc_conf->start_auto = 0;
                        return 0;
                }
 
-               /* Parse new config value. */
                if (lxc_safe_uint(value, &lxc_conf->start_auto) < 0)
                        return -1;
 
@@ -1216,43 +1068,35 @@ static int set_config_start(const char *key, const char *value,
 
                return 0;
        } else if (*(key + 10) == 'd') { /* lxc.start.delay */
-               /* Set config value to default. */
                if (is_empty) {
                        lxc_conf->start_delay = 0;
                        return 0;
                }
 
-               /* Parse new config value. */
                return lxc_safe_uint(value, &lxc_conf->start_delay);
        } else if (*(key + 10) == 'o') { /* lxc.start.order */
-               /* Set config value to default. */
                if (is_empty) {
                        lxc_conf->start_order = 0;
                        return 0;
                }
 
-               /* Parse new config value. */
                return lxc_safe_int(value, &lxc_conf->start_order);
        }
 
-       SYSERROR("Unknown key: %s", key);
        return -1;
 }
 
 static int set_config_monitor(const char *key, const char *value,
                              struct lxc_conf *lxc_conf, void *data)
 {
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->monitor_unshare = 0;
                return 0;
        }
 
-       /* Parse new config value. */
        if (strcmp(key + 12, "unshare") == 0)
                return lxc_safe_uint(value, &lxc_conf->monitor_unshare);
 
-       SYSERROR("Unknown key: %s", key);
        return -1;
 }
 
@@ -1267,13 +1111,11 @@ static int set_config_group(const char *key, const char *value,
                return lxc_clear_groups(lxc_conf);
 
        groups = strdup(value);
-       if (!groups) {
-               SYSERROR("failed to dup '%s'", value);
+       if (!groups)
                return -1;
-       }
 
-       /* In case several groups are specified in a single line
-        * split these groups in a single element for the list.
+       /* In case several groups are specified in a single line split these
+        * groups in a single element for the list.
         */
        for (groupptr = groups;; groupptr = NULL) {
                token = strtok_r(groupptr, " \t", &sptr);
@@ -1283,14 +1125,11 @@ static int set_config_group(const char *key, const char *value,
                }
 
                grouplist = malloc(sizeof(*grouplist));
-               if (!grouplist) {
-                       SYSERROR("failed to allocate groups list");
+               if (!grouplist)
                        break;
-               }
 
                grouplist->elem = strdup(token);
                if (!grouplist->elem) {
-                       SYSERROR("failed to dup '%s'", token);
                        free(grouplist);
                        break;
                }
@@ -1331,13 +1170,11 @@ on_error:
 static int set_config_tty_max(const char *key, const char *value,
                              struct lxc_conf *lxc_conf, void *data)
 {
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->tty = 0;
                return 0;
        }
 
-       /* Parse new config value. */
        return lxc_safe_uint(value, &lxc_conf->tty);
 }
 
@@ -1359,21 +1196,16 @@ static int set_config_apparmor_allow_incomplete(const char *key,
                                                struct lxc_conf *lxc_conf,
                                                void *data)
 {
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->lsm_aa_allow_incomplete = 0;
                return 0;
        }
 
-       /* Parse new config value. */
        if (lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_incomplete) < 0)
                return -1;
 
-       if (lxc_conf->lsm_aa_allow_incomplete > 1) {
-               ERROR("Wrong value for lxc.apparmor.allow_incomplete. Can only "
-                     "be set to 0 or 1");
+       if (lxc_conf->lsm_aa_allow_incomplete > 1)
                return -1;
-       }
 
        return 0;
 }
@@ -1401,6 +1233,7 @@ static int set_config_log_file(const char *key, const char *value,
        ret = set_config_path_item(&c->logfile, value);
        if (ret == 0)
                ret = lxc_log_set_file(&c->logfd, c->logfile);
+
        return ret;
 }
 
@@ -1409,13 +1242,11 @@ static int set_config_log_level(const char *key, const char *value,
 {
        int newlevel;
 
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->loglevel = LXC_LOG_LEVEL_NOTSET;
                return 0;
        }
 
-       /* Parse new config value. */
        if (value[0] >= '0' && value[0] <= '9') {
                if (lxc_safe_int(value, &newlevel) < 0)
                        return -1;
@@ -1433,20 +1264,16 @@ static int set_config_log_level(const char *key, const char *value,
 static int set_config_autodev(const char *key, const char *value,
                              struct lxc_conf *lxc_conf, void *data)
 {
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->autodev = 0;
                return 0;
        }
 
-       /* Parse new config value. */
        if (lxc_safe_uint(value, &lxc_conf->autodev) < 0)
                return -1;
 
-       if (lxc_conf->autodev > 1) {
-               ERROR("Wrong value for lxc.autodev. Can only be set to 0 or 1");
+       if (lxc_conf->autodev > 1)
                return -1;
-       }
 
        return 0;
 }
@@ -1505,17 +1332,15 @@ static int set_config_signal_halt(const char *key, const char *value,
 {
        int sig_n;
 
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->haltsignal = 0;
                return 0;
        }
 
-       /* Parse new config value. */
        sig_n = sig_parse(value);
-
        if (sig_n < 0)
                return -1;
+
        lxc_conf->haltsignal = sig_n;
 
        return 0;
@@ -1526,16 +1351,15 @@ static int set_config_signal_reboot(const char *key, const char *value,
 {
        int sig_n;
 
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->rebootsignal = 0;
                return 0;
        }
 
-       /* Parse new config value. */
        sig_n = sig_parse(value);
        if (sig_n < 0)
                return -1;
+
        lxc_conf->rebootsignal = sig_n;
 
        return 0;
@@ -1546,23 +1370,22 @@ static int set_config_signal_stop(const char *key, const char *value,
 {
        int sig_n;
 
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->stopsignal = 0;
                return 0;
        }
 
-       /* Parse new config value. */
        sig_n = sig_parse(value);
        if (sig_n < 0)
                return -1;
+
        lxc_conf->stopsignal = sig_n;
 
        return 0;
 }
 
-static int set_config_cgroup(const char *key, const char *value,
-                            struct lxc_conf *lxc_conf, void *data)
+static int set_config_cgroup_controller(const char *key, const char *value,
+                                       struct lxc_conf *lxc_conf, void *data)
 {
        char *subkey;
        char *token = "lxc.cgroup.";
@@ -1607,18 +1430,24 @@ static int set_config_cgroup(const char *key, const char *value,
 
 out:
        free(cglist);
-
        if (cgelem) {
                free(cgelem->subsystem);
-
                free(cgelem->value);
-
                free(cgelem);
        }
 
        return -1;
 }
 
+static int set_config_cgroup_dir(const char *key, const char *value,
+                                struct lxc_conf *lxc_conf, void *data)
+{
+       if (lxc_config_value_empty(value))
+               return clr_config_cgroup_dir(key, lxc_conf, NULL);
+
+       return set_config_string_item(&lxc_conf->cgroup_meta.dir, value);
+}
+
 static int set_config_prlimit(const char *key, const char *value,
                            struct lxc_conf *lxc_conf, void *data)
 {
@@ -1735,7 +1564,7 @@ static int set_config_idmaps(const char *key, const char *value,
        if (ret < 0)
                goto on_error;
 
-       INFO("read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
+       INFO("Read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
        if (type == 'u')
                idmap->idtype = ID_TYPE_UID;
        else if (type == 'g')
@@ -1796,9 +1625,9 @@ static int set_config_mount_auto(const char *key, const char *value,
            { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED  },
            { "cgroup-full:ro",    LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO     },
            { "cgroup-full:rw",    LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW     },
-           /* NB: For adding anything that is just a single on/off, but has
-            *     no options: keep mask and flag identical and just define the
-            *     enum value as an unused bit so far
+           /* For adding anything that is just a single on/off, but has no
+            * options: keep mask and flag identical and just define the enum
+            * value as an unused bit so far
             */
            { NULL,                0,                    0                           }
        };
@@ -1809,10 +1638,8 @@ static int set_config_mount_auto(const char *key, const char *value,
        }
 
        autos = strdup(value);
-       if (!autos) {
-               SYSERROR("failed to dup '%s'", value);
+       if (!autos)
                return -1;
-       }
 
        for (autoptr = autos;; autoptr = NULL) {
                token = strtok_r(autoptr, " \t", &sptr);
@@ -1827,7 +1654,7 @@ static int set_config_mount_auto(const char *key, const char *value,
                }
 
                if (!allowed_auto_mounts[i].token) {
-                       ERROR("Invalid filesystem to automount: %s", token);
+                       ERROR("Invalid filesystem to automount \"%s\"", token);
                        break;
                }
 
@@ -1875,10 +1702,8 @@ static int set_config_cap_keep(const char *key, const char *value,
                return lxc_clear_config_keepcaps(lxc_conf);
 
        keepcaps = strdup(value);
-       if (!keepcaps) {
-               SYSERROR("failed to dup '%s'", value);
+       if (!keepcaps)
                return -1;
-       }
 
        /* In case several capability keep is specified in a single line
         * split these caps in a single element for the list.
@@ -1894,14 +1719,11 @@ static int set_config_cap_keep(const char *key, const char *value,
                        lxc_clear_config_keepcaps(lxc_conf);
 
                keeplist = malloc(sizeof(*keeplist));
-               if (!keeplist) {
-                       SYSERROR("failed to allocate keepcap list");
+               if (!keeplist)
                        break;
-               }
 
                keeplist->elem = strdup(token);
                if (!keeplist->elem) {
-                       SYSERROR("failed to dup '%s'", token);
                        free(keeplist);
                        break;
                }
@@ -1925,10 +1747,8 @@ static int set_config_cap_drop(const char *key, const char *value,
                return lxc_clear_config_caps(lxc_conf);
 
        dropcaps = strdup(value);
-       if (!dropcaps) {
-               SYSERROR("failed to dup '%s'", value);
+       if (!dropcaps)
                return -1;
-       }
 
        /* In case several capability drop is specified in a single line
         * split these caps in a single element for the list.
@@ -1941,14 +1761,11 @@ static int set_config_cap_drop(const char *key, const char *value,
                }
 
                droplist = malloc(sizeof(*droplist));
-               if (!droplist) {
-                       SYSERROR("failed to allocate drop list");
+               if (!droplist)
                        break;
-               }
 
                droplist->elem = strdup(token);
                if (!droplist->elem) {
-                       SYSERROR("failed to dup '%s'", token);
                        free(droplist);
                        break;
                }
@@ -1996,6 +1813,7 @@ int append_unexp_config_line(const char *line, struct lxc_conf *conf)
                strcat(conf->unexpanded_config, "\n");
                conf->unexpanded_len++;
        }
+
        return 0;
 }
 
@@ -2008,10 +1826,8 @@ static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
        int ret = -1;
 
        dir = opendir(dirp);
-       if (!dir) {
-               SYSERROR("failed to open '%s'", dirp);
+       if (!dir)
                return -1;
-       }
 
        while ((direntp = readdir(dir))) {
                const char *fnam;
@@ -2028,9 +1844,9 @@ static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
                len = strlen(fnam);
                if (len < 6 || strncmp(fnam + len - 5, ".conf", 5) != 0)
                        continue;
+
                len = snprintf(path, MAXPATHLEN, "%s/%s", dirp, fnam);
                if (len < 0 || len >= MAXPATHLEN) {
-                       ERROR("lxc.include filename too long under '%s'", dirp);
                        ret = -1;
                        goto out;
                }
@@ -2042,8 +1858,7 @@ static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
        ret = 0;
 
 out:
-       if (closedir(dir))
-               WARN("lxc.include dir: failed to close directory");
+       closedir(dir);
 
        return ret;
 }
@@ -2051,13 +1866,11 @@ out:
 static int set_config_includefiles(const char *key, const char *value,
                                   struct lxc_conf *lxc_conf, void *data)
 {
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                clr_config_includefiles(key, lxc_conf, NULL);
                return 0;
        }
 
-       /* Parse new config value. */
        if (is_dir(value))
                return do_includedir(value, lxc_conf);
 
@@ -2099,13 +1912,10 @@ static int set_config_uts_name(const char *key, const char *value,
        }
 
        utsname = malloc(sizeof(*utsname));
-       if (!utsname) {
-               SYSERROR("failed to allocate memory");
+       if (!utsname)
                return -1;
-       }
 
        if (strlen(value) >= sizeof(utsname->nodename)) {
-               ERROR("node name '%s' is too long", value);
                free(utsname);
                return -1;
        }
@@ -2124,44 +1934,51 @@ struct parse_line_conf {
 
 static int parse_line(char *buffer, void *data)
 {
-       struct lxc_config_t *config;
        char *dot, *key, *line, *linep, *value;
-       struct parse_line_conf *plc = data;
+       bool empty_line;
+       struct lxc_config_t *config;
        int ret = 0;
+       char *dup = buffer;
+       struct parse_line_conf *plc = data;
 
-       if (lxc_is_line_empty(buffer))
-               return 0;
+       /* If there are newlines in the config file we should keep them. */
+       empty_line = lxc_is_line_empty(dup);
+       if (empty_line)
+               dup = "\n";
 
-       /* we have to dup the buffer otherwise, at the re-exec for
-        * reboot we modified the original string on the stack by
-        * replacing '=' by '\0' below
+       /* We have to dup the buffer otherwise, at the re-exec for reboot we
+        * modified the original string on the stack by replacing '=' by '\0'
+        * below.
         */
-       linep = line = strdup(buffer);
-       if (!line) {
-               SYSERROR("failed to allocate memory for '%s'", buffer);
+       linep = line = strdup(dup);
+       if (!line)
                return -1;
+
+       if (!plc->from_include) {
+               ret = append_unexp_config_line(line, plc->conf);
+               if (ret < 0)
+                       goto on_error;
        }
 
-       if (!plc->from_include)
-               if ((ret = append_unexp_config_line(line, plc->conf)))
-                       goto out;
+       if (empty_line)
+               return 0;
 
        line += lxc_char_left_gc(line, strlen(line));
 
        /* ignore comments */
        if (line[0] == '#')
-               goto out;
+               goto on_error;
 
        /* martian option - don't add it to the config itself */
        if (strncmp(line, "lxc.", 4))
-               goto out;
+               goto on_error;
 
        ret = -1;
 
-       dot = strstr(line, "=");
+       dot = strchr(line, '=');
        if (!dot) {
-               ERROR("invalid configuration line: %s", line);
-               goto out;
+               ERROR("Invalid configuration line: %s", line);
+               goto on_error;
        }
 
        *dot = '\0';
@@ -2174,22 +1991,37 @@ static int parse_line(char *buffer, void *data)
        value[lxc_char_right_gc(value, strlen(value))] = '\0';
 
        if (*value == '\'' || *value == '\"') {
-               size_t len = strlen(value);
+               size_t len;
+
+               len = strlen(value);
                if (len > 1 && value[len - 1] == *value) {
                        value[len - 1] = '\0';
                        value++;
                }
        }
 
-       config = lxc_getconfig(key);
+       config = lxc_get_config(key);
        if (!config) {
-               ERROR("unknown key %s", key);
-               goto out;
+               ERROR("Unknown configuration key \"%s\"", key);
+               goto on_error;
+       }
+
+       /* [START]: REMOVE IN LXC 3.0 */
+       if (config->is_legacy_key && !plc->conf->contains_legacy_key) {
+               plc->conf->contains_legacy_key = true;
+               /* Warn the user once loud and clear that there is at least one
+                * legacy configuration item in the configuration file and then
+                * an update is required.
+                */
+               fprintf(stderr, "The configuration file contains legacy "
+                               "configuration keys.\nPlease update your "
+                               "configuration file!\n");
        }
+       /* [END]: REMOVE IN LXC 3.0 */
 
        ret = config->set(key, value, plc->conf, NULL);
 
-out:
+on_error:
        free(linep);
        return ret;
 }
@@ -2206,16 +2038,17 @@ static int lxc_config_readline(char *buffer, struct lxc_conf *conf)
 
 int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
 {
+       int ret;
        struct parse_line_conf c;
 
        c.conf = conf;
        c.from_include = from_include;
 
-       if (access(file, R_OK) == -1) {
+       ret = access(file, R_OK);
+       if (ret < 0)
                return -1;
-       }
 
-       /* Catch only the top level config file name in the structure */
+       /* Catch only the top level config file name in the structure. */
        if (!conf->rcfile)
                conf->rcfile = strdup(file);
 
@@ -2317,21 +2150,20 @@ int lxc_fill_elevated_privileges(char *flaglist, int *flags)
 
        if (!flaglist) {
                /* For the sake of backward compatibility, drop all privileges
-                * if none is specified.
+                if none is specified.
                 */
-               for (i = 0; all_privs[i].token; i++) {
+               for (i = 0; all_privs[i].token; i++)
                        *flags |= all_privs[i].flag;
-               }
+
                return 0;
        }
 
        token = strtok_r(flaglist, "|", &saveptr);
        while (token) {
                aflag = -1;
-               for (i = 0; all_privs[i].token; i++) {
+               for (i = 0; all_privs[i].token; i++)
                        if (!strcmp(all_privs[i].token, token))
                                aflag = all_privs[i].flag;
-               }
                if (aflag < 0)
                        return -1;
 
@@ -2354,7 +2186,7 @@ void write_config(FILE *fout, struct lxc_conf *c)
 
        ret = fwrite(c->unexpanded_config, 1, len, fout);
        if (ret != len)
-               SYSERROR("Error writing configuration file");
+               SYSERROR("Failed to write configuration file");
 }
 
 bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
@@ -2431,19 +2263,15 @@ bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
        olddir = alloca(olddirlen + 1);
        ret = snprintf(olddir, olddirlen + 1, "%s=%s/%s", ovldir, oldpath,
                       oldname);
-       if (ret < 0 || ret >= olddirlen + 1) {
-               ERROR("failed to create string");
+       if (ret < 0 || ret >= olddirlen + 1)
                return false;
-       }
 
        newdirlen = strlen(ovldir) + strlen(newpath) + strlen(newname) + 2;
        newdir = alloca(newdirlen + 1);
        ret = snprintf(newdir, newdirlen + 1, "%s=%s/%s", ovldir, newpath,
                       newname);
-       if (ret < 0 || ret >= newdirlen + 1) {
-               ERROR("failed to create string");
+       if (ret < 0 || ret >= newdirlen + 1)
                return false;
-       }
 
        if (!conf->unexpanded_config)
                return true;
@@ -2503,15 +2331,14 @@ bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
                        size_t poffset = q - conf->unexpanded_config;
 
                        new = realloc(conf->unexpanded_config, newlen + 1);
-                       if (!new) {
-                               ERROR("Out of memory");
+                       if (!new)
                                return false;
-                       }
+
                        conf->unexpanded_len = newlen;
                        conf->unexpanded_alloced = newlen + 1;
                        new[newlen - 1] = '\0';
                        lend = new + (lend - conf->unexpanded_config);
-                       /* move over the remainder to make room for the newdir
+                       /* Move over the remainder to make room for the newdir.
                         */
                        memmove(new + poffset + newdirlen,
                                new + poffset + olddirlen,
@@ -2540,20 +2367,18 @@ bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
        olddirlen = strlen(oldpath) + strlen(oldname) + 1;
        olddir = alloca(olddirlen + 1);
        ret = snprintf(olddir, olddirlen + 1, "%s/%s", oldpath, oldname);
-       if (ret < 0 || ret >= olddirlen + 1) {
-               ERROR("failed to create string");
+       if (ret < 0 || ret >= olddirlen + 1)
                return false;
-       }
 
        newdirlen = strlen(newpath) + strlen(newname) + 1;
        newdir = alloca(newdirlen + 1);
        ret = snprintf(newdir, newdirlen + 1, "%s/%s", newpath, newname);
-       if (ret < 0 || ret >= newdirlen + 1) {
-               ERROR("failed to create string");
+       if (ret < 0 || ret >= newdirlen + 1)
                return false;
-       }
+
        if (!conf->unexpanded_config)
                return true;
+
        while (*lstart) {
                lend = strchr(lstart, '\n');
                if (!lend)
@@ -2596,15 +2421,14 @@ bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
                        size_t poffset = p - conf->unexpanded_config;
 
                        new = realloc(conf->unexpanded_config, newlen + 1);
-                       if (!new) {
-                               ERROR("failed to allocate memory");
+                       if (!new)
                                return false;
-                       }
+
                        conf->unexpanded_len = newlen;
                        conf->unexpanded_alloced = newlen + 1;
                        new[newlen - 1] = '\0';
                        lend = new + (lend - conf->unexpanded_config);
-                       /* move over the remainder to make room for the newdir
+                       /* Move over the remainder to make room for the newdir.
                         */
                        memmove(new + poffset + newdirlen,
                                new + poffset + olddirlen,
@@ -2628,9 +2452,8 @@ bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
                }                                                              \
        }
 
-/*
- * This is called only from clone.  We wish to update all hwaddrs in the
- * unexpanded config file.  We can't/don't want to update any which come from
+/* This is called only from clone.  We wish to update all hwaddrs in the
+ * unexpanded config file. We can't/don't want to update any which come from
  * lxc.includes (there shouldn't be any).
  * We can't just walk the c->lxc-conf->network list because that includes netifs
  * from the include files.  So we update the ones which we find in the unexp
@@ -2688,9 +2511,9 @@ bool network_new_hwaddrs(struct lxc_conf *conf)
                        return false;
 
                memcpy(p, newhwaddr, 17);
-               lxc_list_for_each(it, &conf->network)
-               {
+               lxc_list_for_each(it, &conf->network) {
                        struct lxc_netdev *n = it->elem;
+
                        if (n->hwaddr && memcmp(oldhwaddr, n->hwaddr, 17) == 0)
                                memcpy(n->hwaddr, newhwaddr, 17);
                }
@@ -2704,21 +2527,16 @@ bool network_new_hwaddrs(struct lxc_conf *conf)
 static int set_config_ephemeral(const char *key, const char *value,
                                struct lxc_conf *lxc_conf, void *data)
 {
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->ephemeral = 0;
                return 0;
        }
 
-       /* Parse new config value. */
        if (lxc_safe_uint(value, &lxc_conf->ephemeral) < 0)
                return -1;
 
-       if (lxc_conf->ephemeral > 1) {
-               ERROR(
-                   "Wrong value for lxc.ephemeral. Can only be set to 0 or 1");
+       if (lxc_conf->ephemeral > 1)
                return -1;
-       }
 
        return 0;
 }
@@ -2728,22 +2546,17 @@ static int set_config_log_syslog(const char *key, const char *value,
 {
        int facility;
 
-       /* Clear any previously set value. */
        if (lxc_conf->syslog) {
                free(lxc_conf->syslog);
                lxc_conf->syslog = NULL;
        }
 
-       /* Check if value is empty. */
        if (lxc_config_value_empty(value))
                return 0;
 
-       /* Parse value. */
        facility = lxc_syslog_priority_to_int(value);
-       if (facility == -EINVAL) {
-               ERROR("Wrong value for lxc.log.syslog.");
+       if (facility == -EINVAL)
                return -1;
-       }
 
        lxc_log_syslog(facility);
        return set_config_string_item(&lxc_conf->syslog, value);
@@ -2754,27 +2567,28 @@ static int set_config_no_new_privs(const char *key, const char *value,
 {
        unsigned int v;
 
-       /* Set config value to default. */
        if (lxc_config_value_empty(value)) {
                lxc_conf->no_new_privs = false;
                return 0;
        }
 
-       /* Parse new config value. */
        if (lxc_safe_uint(value, &v) < 0)
                return -1;
 
-       if (v > 1) {
-               ERROR("Wrong value for lxc.no_new_privs. Can only be set to 0 "
-                     "or 1");
+       if (v > 1)
                return -1;
-       }
 
        lxc_conf->no_new_privs = v ? true : false;
 
        return 0;
 }
 
+static int set_config_noop(const char *key, const char *value,
+                          struct lxc_conf *lxc_conf, void *data)
+{
+       return 0;
+}
+
 /* Callbacks to get configuration items. */
 static int get_config_personality(const char *key, char *retv, int inlen,
                                  struct lxc_conf *c, void *data)
@@ -2842,17 +2656,16 @@ static int get_config_selinux_context(const char *key, char *retv, int inlen,
        return lxc_get_conf_str(retv, inlen, c->lsm_se_context);
 }
 
-/*
- * If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list,
- * then just the value(s) will be printed.  Since there still could be
- * more than one, it is newline-separated.
- * (Maybe that's ambigous, since some values, i.e. devices.list, will
- * already have newlines?)
- * If you ask for 'lxc.cgroup", then all cgroup entries will be printed,
- * in 'lxc.cgroup.subsystem.key = value' format.
+/* If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list, then
+ * just the value(s) will be printed. Since there still could be more than one,
+ * it is newline-separated.
+ * (Maybe that's ambigous, since some values, i.e. devices.list, will already
+ * have newlines?)
+ * If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
+ * 'lxc.cgroup.subsystem.key = value' format.
  */
-static int get_config_cgroup(const char *key, char *retv, int inlen,
-                            struct lxc_conf *c, void *data)
+static int get_config_cgroup_controller(const char *key, char *retv, int inlen,
+                                       struct lxc_conf *c, void *data)
 {
        struct lxc_list *it;
        int len;
@@ -2873,8 +2686,10 @@ static int get_config_cgroup(const char *key, char *retv, int inlen,
 
        lxc_list_for_each(it, &c->cgroup) {
                struct lxc_cgroup *cg = it->elem;
+
                if (get_all) {
-                       strprint(retv, inlen, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value);
+                       strprint(retv, inlen, "lxc.cgroup.%s = %s\n",
+                                cg->subsystem, cg->value);
                } else if (!strcmp(cg->subsystem, key)) {
                        strprint(retv, inlen, "%s\n", cg->value);
                }
@@ -2883,6 +2698,22 @@ static int get_config_cgroup(const char *key, char *retv, int inlen,
        return fulllen;
 }
 
+static int get_config_cgroup_dir(const char *key, char *retv, int inlen,
+                                struct lxc_conf *lxc_conf, void *data)
+{
+       int len;
+       int fulllen = 0;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.dir);
+
+       return fulllen;
+}
+
 static int get_config_idmaps(const char *key, char *retv, int inlen,
                             struct lxc_conf *c, void *data)
 {
@@ -3047,8 +2878,7 @@ static int get_config_mount(const char *key, char *retv, int inlen,
        else
                memset(retv, 0, inlen);
 
-       lxc_list_for_each(it, &c->mount_list)
-       {
+       lxc_list_for_each(it, &c->mount_list) {
                strprint(retv, inlen, "%s\n", (char *)it->elem);
        }
 
@@ -3095,7 +2925,6 @@ static int get_config_hooks(const char *key, char *retv, int inlen,
        struct lxc_list *it;
        int i;
 
-       /* "lxc.hook.mount" */
        subkey = strchr(key, '.');
        if (subkey)
                subkey = strchr(subkey + 1, '.');
@@ -3158,6 +2987,7 @@ static int get_config_cap_drop(const char *key, char *retv, int inlen,
        lxc_list_for_each(it, &c->caps) {
                strprint(retv, inlen, "%s\n", (char *)it->elem);
        }
+
        return fulllen;
 }
 
@@ -3175,6 +3005,7 @@ static int get_config_cap_keep(const char *key, char *retv, int inlen,
        lxc_list_for_each(it, &c->keepcaps) {
                strprint(retv, inlen, "%s\n", (char *)it->elem);
        }
+
        return fulllen;
 }
 
@@ -3203,19 +3034,19 @@ static int get_config_autodev(const char *key, char *retv, int inlen,
 }
 
 static int get_config_signal_halt(const char *key, char *retv, int inlen,
-                                struct lxc_conf *c, void *data)
+                                 struct lxc_conf *c, void *data)
 {
        return lxc_get_conf_int(c, retv, inlen, c->haltsignal);
 }
 
 static int get_config_signal_reboot(const char *key, char *retv, int inlen,
-                                  struct lxc_conf *c, void *data)
+                                   struct lxc_conf *c, void *data)
 {
        return lxc_get_conf_int(c, retv, inlen, c->rebootsignal);
 }
 
 static int get_config_signal_stop(const char *key, char *retv, int inlen,
-                                struct lxc_conf *c, void *data)
+                                 struct lxc_conf *c, void *data)
 {
        return lxc_get_conf_int(c, retv, inlen, c->stopsignal);
 }
@@ -3234,7 +3065,7 @@ static int get_config_start(const char *key, char *retv, int inlen,
 }
 
 static int get_config_log_syslog(const char *key, char *retv, int inlen,
-                            struct lxc_conf *c, void *data)
+                                struct lxc_conf *c, void *data)
 {
        return lxc_get_conf_str(retv, inlen, c->syslog);
 }
@@ -3259,6 +3090,7 @@ static int get_config_group(const char *key, char *retv, int inlen,
        lxc_list_for_each(it, &c->groups) {
                strprint(retv, inlen, "%s\n", (char *)it->elem);
        }
+
        return fulllen;
 }
 
@@ -3276,9 +3108,16 @@ static int get_config_environment(const char *key, char *retv, int inlen,
        lxc_list_for_each(it, &c->environment) {
                strprint(retv, inlen, "%s\n", (char *)it->elem);
        }
+
        return fulllen;
 }
 
+static int get_config_execute_cmd(const char *key, char *retv, int inlen,
+                              struct lxc_conf *c, void *data)
+{
+       return lxc_get_conf_str(retv, inlen, c->execute_cmd);
+}
+
 static int get_config_init_cmd(const char *key, char *retv, int inlen,
                               struct lxc_conf *c, void *data)
 {
@@ -3309,8 +3148,7 @@ static int get_config_no_new_privs(const char *key, char *retv, int inlen,
        return lxc_get_conf_int(c, retv, inlen, c->no_new_privs);
 }
 
-/*
- * If you ask for a specific value, i.e. lxc.prlimit.nofile, then just the value
+/* If you ask for a specific value, i.e. lxc.prlimit.nofile, then just the value
  * will be printed. If you ask for 'lxc.prlimit', then all limit entries will be
  * printed, in 'lxc.prlimit.resource = value' format.
  */
@@ -3348,19 +3186,18 @@ static int get_config_prlimit(const char *key, char *retv, int inlen,
                                          (uint64_t)lim->limit.rlim_cur);
                }
                if (lim->limit.rlim_cur != lim->limit.rlim_max) {
-                       if (lim->limit.rlim_max == RLIM_INFINITY) {
+                       if (lim->limit.rlim_max == RLIM_INFINITY)
                                memcpy(buf + partlen, ":unlimited",
                                       sizeof(":unlimited"));
-                       } else {
+                       else
                                sprintf(buf + partlen, ":%" PRIu64,
                                        (uint64_t)lim->limit.rlim_max);
-                       }
                }
 
                if (get_all) {
                        strprint(retv, inlen, "lxc.prlimit.%s = %s\n",
                                 lim->resource, buf);
-               } else if (strcmp(lim->resource, key) == 0) {
+               } else if (!strcmp(lim->resource, key)) {
                        strprint(retv, inlen, "%s", buf);
                }
        }
@@ -3368,6 +3205,12 @@ static int get_config_prlimit(const char *key, char *retv, int inlen,
        return fulllen;
 }
 
+static int get_config_noop(const char *key, char *retv, int inlen,
+                          struct lxc_conf *c, void *data)
+{
+       return 0;
+}
+
 /* Callbacks to clear config items. */
 static inline int clr_config_personality(const char *key, struct lxc_conf *c,
                                         void *data)
@@ -3422,12 +3265,23 @@ static inline int clr_config_selinux_context(const char *key,
        return 0;
 }
 
-static inline int clr_config_cgroup(const char *key, struct lxc_conf *c,
-                                   void *data)
+static inline int clr_config_cgroup_controller(const char *key,
+                                              struct lxc_conf *c, void *data)
 {
        return lxc_clear_cgroups(c, key);
 }
 
+static int clr_config_cgroup_dir(const char *key, struct lxc_conf *lxc_conf,
+                                void *data)
+{
+       if (lxc_conf->cgroup_meta.dir) {
+               free(lxc_conf->cgroup_meta.dir);
+               lxc_conf->cgroup_meta.dir = NULL;
+       }
+
+       return 0;
+}
+
 static inline int clr_config_idmaps(const char *key, struct lxc_conf *c,
                                    void *data)
 {
@@ -3625,6 +3479,14 @@ static inline int clr_config_environment(const char *key, struct lxc_conf *c,
        return lxc_clear_environment(c);
 }
 
+static inline int clr_config_execute_cmd(const char *key, struct lxc_conf *c,
+                                     void *data)
+{
+       free(c->execute_cmd);
+       c->execute_cmd = NULL;
+       return 0;
+}
+
 static inline int clr_config_init_cmd(const char *key, struct lxc_conf *c,
                                      void *data)
 {
@@ -3674,126 +3536,157 @@ static inline int clr_config_includefiles(const char *key, struct lxc_conf *c,
        return 0;
 }
 
+static inline int clr_config_noop(const char *key, struct lxc_conf *c,
+                                 void *data)
+{
+       return 0;
+}
+
 static int get_config_includefiles(const char *key, char *retv, int inlen,
                                   struct lxc_conf *c, void *data)
 {
        return -ENOSYS;
 }
 
-static struct lxc_config_t *
-get_network_config_ops(const char *key, struct lxc_conf *lxc_conf, ssize_t *idx)
+static struct lxc_config_t *get_network_config_ops(const char *key,
+                                                  struct lxc_conf *lxc_conf,
+                                                  ssize_t *idx,
+                                                  char **deindexed_key)
 {
+       int ret;
+       unsigned int tmpidx;
+       size_t numstrlen;
        char *copy, *idx_start, *idx_end;
        struct lxc_config_t *config = NULL;
 
        /* check that this is a sensible network key */
-       if (strncmp("lxc.net.", key, 8))
+       if (strncmp("lxc.net.", key, 8)) {
+               ERROR("Invalid network configuration key \"%s\"", key);
                return NULL;
+       }
 
        copy = strdup(key);
-       if (!copy)
+       if (!copy) {
+               ERROR("Failed to duplicate string \"%s\"", key);
                return NULL;
+       }
 
        /* lxc.net.<n> */
-       if (isdigit(*(key + 8))) {
-               int ret;
-               unsigned int tmpidx;
-               size_t numstrlen;
+       if (!isdigit(*(key + 8))) {
+               ERROR("Failed to detect digit in string \"%s\"", key + 8);
+               goto on_error;
+       }
 
-               /* beginning of index string */
-               idx_start = (copy + 7);
-               *idx_start = '\0';
+       /* beginning of index string */
+       idx_start = (copy + 7);
+       *idx_start = '\0';
 
-               /* end of index string */
-               idx_end = strchr((copy + 8), '.');
-               if (!idx_end)
-                       goto on_error;
+       /* end of index string */
+       idx_end = strchr((copy + 8), '.');
+       if (idx_end)
                *idx_end = '\0';
 
-               /* parse current index */
-               ret = lxc_safe_uint((idx_start + 1), &tmpidx);
-               if (ret < 0) {
-                       *idx = ret;
-                       goto on_error;
-               }
+       /* parse current index */
+       ret = lxc_safe_uint((idx_start + 1), &tmpidx);
+       if (ret < 0) {
+               ERROR("Failed to parse usigned integer from string \"%s\": %s",
+                     idx_start + 1, strerror(-ret));
+               *idx = ret;
+               goto on_error;
+       }
 
-               /* This, of course is utterly nonsensical on so many levels, but
-                * better safe than sorry.
-                * (Checking for INT_MAX here is intentional.)
-                */
-               if (tmpidx == INT_MAX) {
-                       SYSERROR(
-                           "number of configured networks would overflow the "
-                           "counter... what are you doing?");
-                       goto on_error;
-               }
-               *idx = tmpidx;
+       /* This, of course is utterly nonsensical on so many levels, but
+        * better safe than sorry.
+        * (Checking for INT_MAX here is intentional.)
+        */
+       if (tmpidx == INT_MAX) {
+               SYSERROR("Number of configured networks would overflow the "
+                        "counter");
+               goto on_error;
+       }
+       *idx = tmpidx;
+
+       numstrlen = strlen((idx_start + 1));
 
-               numstrlen = strlen((idx_start + 1));
+       /* repair configuration key */
+       *idx_start = '.';
 
-               /* repair configuration key */
-               *idx_start = '.';
+       /* lxc.net.<idx>.<subkey> */
+       if (idx_end) {
                *idx_end = '.';
 
                memmove(copy + 8, idx_end + 1, strlen(idx_end + 1));
                copy[strlen(key) - numstrlen + 1] = '\0';
+
+               config = lxc_get_config(copy);
+               if (!config) {
+                       ERROR("Unknown network configuration key \"%s\"", key);
+                       goto on_error;
+               }
        }
 
-       config = lxc_getconfig(copy);
-       if (!config)
-               ERROR("unknown network configuration key %s", key);
+       if (deindexed_key)
+               *deindexed_key = copy;
+
+       return config;
 
 on_error:
        free(copy);
-       return config;
+       return NULL;
 }
 
-/*
- * Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.'
- * was found.  So we make sure next comes an integer, find the right callback
- * (by rewriting the key), and call it.
+/* Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.' was
+ * found. So we make sure next comes an integer, find the right callback (by
+ * rewriting the key), and call it.
  */
 static int set_config_net_nic(const char *key, const char *value,
                              struct lxc_conf *lxc_conf, void *data)
 {
+       int ret;
+       const char *idxstring;
        struct lxc_config_t *config;
        struct lxc_netdev *netdev;
        ssize_t idx = -1;
+       char *deindexed_key = NULL;
+
+       idxstring = key + 8;
+       if (!isdigit(*idxstring))
+               return -1;
 
        if (lxc_config_value_empty(value))
                return clr_config_net_nic(key, lxc_conf, data);
 
-       config = get_network_config_ops(key, lxc_conf, &idx);
+       config = get_network_config_ops(key, lxc_conf, &idx, &deindexed_key);
        if (!config || idx < 0)
                return -1;
 
        netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, true);
-       if (!netdev)
+       if (!netdev) {
+               free(deindexed_key);
                return -1;
+       }
 
-       return config->set(key, value, lxc_conf, netdev);
+       ret = config->set(deindexed_key, value, lxc_conf, netdev);
+       free(deindexed_key);
+       return ret;
 }
 
-/*
- * Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.'
- * was found.  So we make sure next comes an integer, find the right callback
- * (by rewriting the key), and call it.
- */
 static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf,
                              void *data)
 {
+       int ret;
        const char *idxstring;
        struct lxc_config_t *config;
        struct lxc_netdev *netdev;
-       ssize_t idx;
+       ssize_t idx = -1;
+       char *deindexed_key = NULL;
 
-       /* If we get passed "lxc.net.<n>" we clear the whole network. */
-       if (strncmp("lxc.net.", key, 8))
+       idxstring = key + 8;
+       if (!isdigit(*idxstring))
                return -1;
 
-       idxstring = key + 8;
        /* The left conjunct is pretty self-explanatory. The right conjunct
-        * checks whether the two pointers are equal. If they are we now that
+        * checks whether the two pointers are equal. If they are we know that
         * this is not a key that is namespaced any further and so we are
         * supposed to clear the whole network.
         */
@@ -3808,15 +3701,19 @@ static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf,
                return 0;
        }
 
-       config = get_network_config_ops(key, lxc_conf, &idx);
+       config = get_network_config_ops(key, lxc_conf, &idx, &deindexed_key);
        if (!config || idx < 0)
                return -1;
 
        netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, false);
-       if (!netdev)
+       if (!netdev) {
+               free(deindexed_key);
                return -1;
+       }
 
-       return config->clr(key, lxc_conf, netdev);
+       ret = config->clr(deindexed_key, lxc_conf, netdev);
+       free(deindexed_key);
+       return ret;
 }
 
 static int clr_config_net_type(const char *key, struct lxc_conf *lxc_conf,
@@ -3848,8 +3745,7 @@ static int clr_config_net_name(const char *key, struct lxc_conf *lxc_conf,
        if (!netdev)
                return -1;
 
-       free(netdev->name);
-       netdev->name = NULL;
+       netdev->name[0] = '\0';
 
        return 0;
 }
@@ -3883,8 +3779,7 @@ static int clr_config_net_link(const char *key, struct lxc_conf *lxc_conf,
        if (!netdev)
                return -1;
 
-       free(netdev->link);
-       netdev->link = NULL;
+       netdev->link[0] = '\0';
 
        return 0;
 }
@@ -3921,8 +3816,7 @@ static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
        if (!netdev)
                return -1;
 
-       free(netdev->priv.veth_attr.pair);
-       netdev->priv.veth_attr.pair = NULL;
+       netdev->priv.veth_attr.pair[0] = '\0';
 
        return 0;
 }
@@ -4099,19 +3993,30 @@ static int clr_config_net_ipv6_address(const char *key,
 static int get_config_net_nic(const char *key, char *retv, int inlen,
                              struct lxc_conf *c, void *data)
 {
+       int ret;
+       const char *idxstring;
        struct lxc_config_t *config;
        struct lxc_netdev *netdev;
        ssize_t idx = -1;
+       char *deindexed_key = NULL;
+
+       idxstring = key + 8;
+       if (!isdigit(*idxstring))
+               return -1;
 
-       config = get_network_config_ops(key, c, &idx);
+       config = get_network_config_ops(key, c, &idx, &deindexed_key);
        if (!config || idx < 0)
                return -1;
 
        netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false);
-       if (!netdev)
+       if (!netdev) {
+               free(deindexed_key);
                return -1;
+       }
 
-       return config->get(key, retv, inlen, c, netdev);
+       ret = config->get(deindexed_key, retv, inlen, c, netdev);
+       free(deindexed_key);
+       return ret;
 }
 
 static int get_config_net_type(const char *key, char *retv, int inlen,
@@ -4179,7 +4084,7 @@ static int get_config_net_link(const char *key, char *retv, int inlen,
        if (!netdev)
                return -1;
 
-       if (netdev->link)
+       if (netdev->link[0] != '\0')
                strprint(retv, inlen, "%s", netdev->link);
 
        return fulllen;
@@ -4203,7 +4108,7 @@ static int get_config_net_name(const char *key, char *retv, int inlen,
        if (!netdev)
                return -1;
 
-       if (netdev->name)
+       if (netdev->name[0] != '\0')
                strprint(retv, inlen, "%s", netdev->name);
 
        return fulllen;
@@ -4276,8 +4181,9 @@ static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
                return 0;
 
        strprint(retv, inlen, "%s",
-                netdev->priv.veth_attr.pair ? netdev->priv.veth_attr.pair
-                                            : netdev->priv.veth_attr.veth1);
+                netdev->priv.veth_attr.pair[0] != '\0'
+                    ? netdev->priv.veth_attr.pair
+                    : netdev->priv.veth_attr.veth1);
 
        return fulllen;
 }
@@ -4525,3 +4431,147 @@ static int get_config_net_ipv6_address(const char *key, char *retv, int inlen,
 
        return fulllen;
 }
+
+int lxc_list_config_items(char *retv, int inlen)
+{
+       size_t i;
+       int len;
+       int fulllen = 0;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       for (i = 0; i < config_size; i++) {
+               char *s = config[i].name;
+
+               if (s[strlen(s) - 1] == '.')
+                       continue;
+
+               strprint(retv, inlen, "%s\n", s);
+       }
+
+       return fulllen;
+}
+
+int lxc_list_subkeys(struct lxc_conf *conf, const char *key, char *retv,
+                    int inlen)
+{
+       int len;
+       int fulllen = 0;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       if (!strcmp(key, "lxc.apparmor")) {
+               strprint(retv, inlen, "allow_incomplete\n");
+               strprint(retv, inlen, "profile\n");
+       } else if (!strcmp(key, "lxc.cgroup")) {
+               strprint(retv, inlen, "dir\n");
+       } else if (!strcmp(key, "lxc.selinux")) {
+               strprint(retv, inlen, "context\n");
+       } else if (!strcmp(key, "lxc.mount")) {
+               strprint(retv, inlen, "auto\n");
+               strprint(retv, inlen, "entry\n");
+               strprint(retv, inlen, "fstab\n");
+       } else if (!strcmp(key, "lxc.rootfs")) {
+               strprint(retv, inlen, "mount\n");
+               strprint(retv, inlen, "options\n");
+               strprint(retv, inlen, "path\n");
+       } else if (!strcmp(key, "lxc.uts")) {
+               strprint(retv, inlen, "name\n");
+       } else if (!strcmp(key, "lxc.hook")) {
+               strprint(retv, inlen, "autodev\n");
+               strprint(retv, inlen, "clone\n");
+               strprint(retv, inlen, "destroy\n");
+               strprint(retv, inlen, "mount\n");
+               strprint(retv, inlen, "post-stop\n");
+               strprint(retv, inlen, "pre-mount\n");
+               strprint(retv, inlen, "pre-start\n");
+               strprint(retv, inlen, "start-host\n");
+               strprint(retv, inlen, "start\n");
+               strprint(retv, inlen, "stop\n");
+       } else if (!strcmp(key, "lxc.cap")) {
+               strprint(retv, inlen, "drop\n");
+               strprint(retv, inlen, "keep\n");
+       } else if (!strcmp(key, "lxc.console")) {
+               strprint(retv, inlen, "logfile\n");
+               strprint(retv, inlen, "path\n");
+       } else if (!strcmp(key, "lxc.seccomp")) {
+               strprint(retv, inlen, "profile\n");
+       } else if (!strcmp(key, "lxc.signal")) {
+               strprint(retv, inlen, "halt\n");
+               strprint(retv, inlen, "reboot\n");
+               strprint(retv, inlen, "stop\n");
+       } else if (!strcmp(key, "lxc.start")) {
+               strprint(retv, inlen, "auto\n");
+               strprint(retv, inlen, "delay\n");
+               strprint(retv, inlen, "order\n");
+       } else if (!strcmp(key, "lxc.monitor")) {
+               strprint(retv, inlen, "unshare\n");
+       } else {
+               fulllen = -1;
+       }
+
+       return fulllen;
+}
+
+int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
+{
+       int len;
+       const char *idxstring;
+       struct lxc_netdev *netdev;
+       int fulllen = 0;
+       ssize_t idx = -1;
+
+       idxstring = key + 8;
+       if (!isdigit(*idxstring))
+               return -1;
+
+       (void)get_network_config_ops(key, c, &idx, NULL);
+       if (idx < 0)
+               return -1;
+
+       netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false);
+       if (!netdev)
+               return -1;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       strprint(retv, inlen, "type\n");
+       strprint(retv, inlen, "script.up\n");
+       strprint(retv, inlen, "script.down\n");
+       if (netdev->type != LXC_NET_EMPTY) {
+               strprint(retv, inlen, "flags\n");
+               strprint(retv, inlen, "link\n");
+               strprint(retv, inlen, "name\n");
+               strprint(retv, inlen, "hwaddr\n");
+               strprint(retv, inlen, "mtu\n");
+               strprint(retv, inlen, "ipv6.address\n");
+               strprint(retv, inlen, "ipv6.gateway\n");
+               strprint(retv, inlen, "ipv4.address\n");
+               strprint(retv, inlen, "ipv4.gateway\n");
+       }
+
+       switch (netdev->type) {
+       case LXC_NET_VETH:
+               strprint(retv, inlen, "veth.pair\n");
+               break;
+       case LXC_NET_MACVLAN:
+               strprint(retv, inlen, "macvlan.mode\n");
+               break;
+       case LXC_NET_VLAN:
+               strprint(retv, inlen, "vlan.id\n");
+               break;
+       case LXC_NET_PHYS:
+               break;
+       }
+
+       return fulllen;
+}
index 047e0ee6c84881f076d2b4598f60c360b4b1a0d8..d50217860408e6151774c0d61988f428a481b586 100644 (file)
@@ -5,6 +5,8 @@
  *
  * Authors:
  * Daniel Lezcano <daniel.lezcano at free.fr>
+ * Serge Hallyn <serge@hallyn.com>
+ * Christian Brauner <christian.brauner@ubuntu.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #ifndef __LXC_CONFILE_H
 #define __LXC_CONFILE_H
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <lxc/attach_options.h>
-#include <stdbool.h>
 
 struct lxc_conf;
 struct lxc_list;
 
-typedef int (*config_set_cb)(const char *, const char *, struct lxc_conf *,
+/* Callback prototype to set a configuration item.
+ * Must be implemented when adding a new configuration key.
+ */
+typedef int (*config_set_cb)(const char *key, const char *value,
+                            struct lxc_conf *conf, void *data);
+
+/* Callback prototype to get a configuration item.
+ * Must be implemented when adding a new configuration key.
+ */
+typedef int (*config_get_cb)(const char *key, char *value, int inlen,
+                            struct lxc_conf *conf, void *data);
+
+/* Callback prototype to clear a configuration item.
+ * Must be implemented when adding a new configuration key.
+ */
+typedef int (*config_clr_cb)(const char *key, struct lxc_conf *conf,
                             void *data);
-typedef int (*config_get_cb)(const char *, char *, int, struct lxc_conf *,
-                            void *);
-typedef int (*config_clr_cb)(const char *, struct lxc_conf *c, void *data);
+
 struct lxc_config_t {
        char *name;
+       bool is_legacy_key; /* REMOVE in LXC 3.0 */
        config_set_cb set;
        config_get_cb get;
        config_clr_cb clr;
 };
 
-extern struct lxc_config_t *lxc_getconfig(const char *key);
-extern int lxc_list_nicconfigs(struct lxc_conf *c, const char *key, char *retv, int inlen);
-extern int lxc_listconfigs(char *retv, int inlen);
-extern int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include);
+/* Get the jump table entry for the given configuration key. */
+extern struct lxc_config_t *lxc_get_config(const char *key);
+
+/* List all available config items. */
+extern int lxc_list_config_items(char *retv, int inlen);
+
+/* Given a configuration key namespace (e.g. lxc.apparmor) list all associated
+ * subkeys for that namespace.
+ * Must be implemented when adding a new configuration key.
+ */
+extern int lxc_list_subkeys(struct lxc_conf *conf, const char *key, char *retv,
+                           int inlen);
+
+/* List all configuration items associated with a given network. For example
+ * pass "lxc.net.[i]" to retrieve all configuration items associated with
+ * the network associated with index [i].
+ */
+extern int lxc_list_net(struct lxc_conf *c, const char *key, char *retv,
+                       int inlen);
+
+extern int lxc_config_read(const char *file, struct lxc_conf *conf,
+                          bool from_include);
+
 extern int append_unexp_config_line(const char *line, struct lxc_conf *conf);
 
 extern int lxc_config_define_add(struct lxc_list *defines, char* arg);
+
 extern int lxc_config_define_load(struct lxc_list *defines,
                                  struct lxc_conf *conf);
 
 /* needed for lxc-attach */
 extern signed long lxc_config_parse_arch(const char *arch);
+
 extern int lxc_fill_elevated_privileges(char *flaglist, int *flags);
 
 extern int lxc_clear_config_item(struct lxc_conf *c, const char *key);
+
 extern void write_config(FILE *fout, struct lxc_conf *c);
 
-extern bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key, const char *v);
+extern bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
+                                       const char *v);
 
 /* These are used when cloning a container */
-extern void clear_unexp_config_line(struct lxc_conf *conf, const char *key, bool rm_subkeys);
+extern void clear_unexp_config_line(struct lxc_conf *conf, const char *key,
+                                   bool rm_subkeys);
+
 extern bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
-       const char *newpath, const char *oldname, const char *newmame);
+                                    const char *newpath, const char *oldname,
+                                    const char *newmame);
+
 bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
                                  const char *newpath, const char *oldname,
                                  const char *newname, const char *ovldir);
+
 extern bool network_new_hwaddrs(struct lxc_conf *conf);
-#endif
+
+#endif /* __LXC_CONFILE_H */
index e97bd87acc6534ff9f72511ae85ab30c218bc6f5..93df473764b38503b3a298901fa3837541a1b168 100644 (file)
@@ -41,7 +41,6 @@
 #include <dirent.h>
 #include <syslog.h>
 
-#include "bdev.h"
 #include "parse.h"
 #include "config.h"
 #include "confile.h"
@@ -52,6 +51,7 @@
 #include "conf.h"
 #include "network.h"
 #include "lxcseccomp.h"
+#include "storage.h"
 
 #if HAVE_IFADDRS_H
 #include <ifaddrs.h>
@@ -91,7 +91,7 @@ int set_config_network_legacy_nic(const char *key, const char *value,
                goto out;
 
        strcpy(copy + 12, p + 1);
-       config = lxc_getconfig(copy);
+       config = lxc_get_config(copy);
        if (!config) {
                ERROR("unknown key %s", key);
                goto out;
@@ -110,10 +110,6 @@ static void lxc_remove_nic(struct lxc_list *it)
 
        lxc_list_del(it);
 
-       free(netdev->link);
-       free(netdev->name);
-       if (netdev->type == LXC_NET_VETH)
-               free(netdev->priv.veth_attr.pair);
        free(netdev->upscript);
        free(netdev->downscript);
        free(netdev->hwaddr);
@@ -423,7 +419,7 @@ int set_config_network_legacy_link(const char *key, const char *value,
                free(it);
                ret = create_matched_ifnames(value, lxc_conf, NULL);
        } else {
-               ret = network_ifname(&netdev->link, value);
+               ret = network_ifname(netdev->link, value);
        }
 
        return ret;
@@ -438,7 +434,7 @@ int set_config_network_legacy_name(const char *key, const char *value,
        if (!netdev)
                return -1;
 
-       return network_ifname(&netdev->name, value);
+       return network_ifname(netdev->name, value);
 }
 
 int set_config_network_legacy_veth_pair(const char *key, const char *value,
@@ -455,7 +451,7 @@ int set_config_network_legacy_veth_pair(const char *key, const char *value,
                return -1;
        }
 
-       return network_ifname(&netdev->priv.veth_attr.pair, value);
+       return network_ifname(netdev->priv.veth_attr.pair, value);
 }
 
 int set_config_network_legacy_macvlan_mode(const char *key, const char *value,
@@ -848,12 +844,12 @@ int get_config_network_legacy_item(const char *key, char *retv, int inlen,
        if (!netdev)
                return -1;
        if (strcmp(p1, "name") == 0) {
-               if (netdev->name)
+               if (netdev->name[0] != '\0')
                        strprint(retv, inlen, "%s", netdev->name);
        } else if (strcmp(p1, "type") == 0) {
                strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
        } else if (strcmp(p1, "link") == 0) {
-               if (netdev->link)
+               if (netdev->link[0] != '\0')
                        strprint(retv, inlen, "%s", netdev->link);
        } else if (strcmp(p1, "flags") == 0) {
                if (netdev->flags & IFF_UP)
@@ -895,7 +891,7 @@ int get_config_network_legacy_item(const char *key, char *retv, int inlen,
        } else if (strcmp(p1, "veth.pair") == 0) {
                if (netdev->type == LXC_NET_VETH) {
                        strprint(retv, inlen, "%s",
-                                netdev->priv.veth_attr.pair
+                                netdev->priv.veth_attr.pair[0] != '\0'
                                     ? netdev->priv.veth_attr.pair
                                     : netdev->priv.veth_attr.veth1);
                }
index 332b98ae895ee9b08242d69f450e570149ebc55d..e4917880923d0f809401e2b0ee6c358a915f38a2 100644 (file)
@@ -31,6 +31,7 @@
 #include "error.h"
 #include "log.h"
 #include "list.h"
+#include "network.h"
 #include "parse.h"
 #include "utils.h"
 
@@ -91,8 +92,6 @@ int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
 
        /* Move beyond \0. */
        slide++;
-       /* align */
-       window = slide;
        /* Validate that only whitespace follows. */
        slide += strspn(slide, " \t\r");
        /* If there was only one whitespace then we whiped it with our \0 above.
@@ -117,8 +116,6 @@ int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
 
        /* Move beyond \0. */
        slide++;
-       /* align */
-       window = slide;
        /* Validate that only whitespace follows. */
        slide += strspn(slide, " \t\r");
        /* If there was only one whitespace then we whiped it with our \0 above.
@@ -253,12 +250,19 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
                netdev = it->elem;
 
                TRACE("index: %zd", netdev->idx);
+               TRACE("ifindex: %d", netdev->ifindex);
                switch (netdev->type) {
                case LXC_NET_VETH:
                        TRACE("type: veth");
-                       if (netdev->priv.veth_attr.pair)
+                       if (netdev->priv.veth_attr.pair[0] != '\0')
                                TRACE("veth pair: %s",
                                      netdev->priv.veth_attr.pair);
+                       if (netdev->priv.veth_attr.veth1[0] != '\0')
+                               TRACE("veth1 : %s",
+                                     netdev->priv.veth_attr.veth1);
+                       if (netdev->priv.veth_attr.ifindex > 0)
+                               TRACE("host side ifindex for veth device: %d",
+                                     netdev->priv.veth_attr.ifindex);
                        break;
                case LXC_NET_MACVLAN:
                        TRACE("type: macvlan");
@@ -277,6 +281,10 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
                        break;
                case LXC_NET_PHYS:
                        TRACE("type: phys");
+                       if (netdev->priv.phys_attr.ifindex > 0) {
+                               TRACE("host side ifindex for phys device: %d",
+                                     netdev->priv.phys_attr.ifindex);
+                       }
                        break;
                case LXC_NET_EMPTY:
                        TRACE("type: empty");
@@ -292,9 +300,9 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
                if (netdev->type != LXC_NET_EMPTY) {
                        TRACE("flags: %s",
                              netdev->flags == IFF_UP ? "up" : "none");
-                       if (netdev->link)
+                       if (netdev->link[0] != '\0')
                                TRACE("link: %s", netdev->link);
-                       if (netdev->name)
+                       if (netdev->name[0] != '\0')
                                TRACE("name: %s", netdev->name);
                        if (netdev->hwaddr)
                                TRACE("hwaddr: %s", netdev->hwaddr);
@@ -342,10 +350,6 @@ static void lxc_free_netdev(struct lxc_netdev *netdev)
 {
        struct lxc_list *cur, *next;
 
-       free(netdev->link);
-       free(netdev->name);
-       if (netdev->type == LXC_NET_VETH)
-               free(netdev->priv.veth_attr.pair);
        free(netdev->upscript);
        free(netdev->downscript);
        free(netdev->hwaddr);
@@ -495,9 +499,15 @@ int config_ip_prefix(struct in_addr *addr)
        return 0;
 }
 
-int network_ifname(char **valuep, const char *value)
+int network_ifname(char *valuep, const char *value)
 {
-       return set_config_string_item_max(valuep, value, IFNAMSIZ);
+       if (strlen(value) >= IFNAMSIZ) {
+               ERROR("Network devie name \"%s\" is too long (>= %zu)", value,
+                     (size_t)IFNAMSIZ);
+       }
+
+       strcpy(valuep, value);
+       return 0;
 }
 
 int rand_complete_hwaddr(char *hwaddr)
@@ -680,4 +690,3 @@ bool parse_limit_value(const char **value, unsigned long *res)
 
        return true;
 }
-
index 222de3de9fb064cd54d9e27dda687d321183879c..2f1079a2c3c31c9e224700ca7594c449315efa56 100644 (file)
@@ -77,7 +77,7 @@ extern int set_config_string_item_max(char **conf_item, const char *value,
                                      size_t max);
 extern int set_config_path_item(char **conf_item, const char *value);
 extern int config_ip_prefix(struct in_addr *addr);
-extern int network_ifname(char **valuep, const char *value);
+extern int network_ifname(char *valuep, const char *value);
 extern int rand_complete_hwaddr(char *hwaddr);
 extern bool lxc_config_net_hwaddr(const char *line);
 extern void update_hwaddr(const char *line);
old mode 100755 (executable)
new mode 100644 (file)
index 666754d..c8e545e
@@ -174,6 +174,15 @@ static int lxc_console_cb_con(int fd, uint32_t events, void *data,
        if (r <= 0) {
                INFO("console client on fd %d has exited", fd);
                lxc_mainloop_del_handler(descr, fd);
+               if (fd == console->peer) {
+                       if (console->tty_state) {
+                               lxc_console_sigwinch_fini(console->tty_state);
+                               console->tty_state = NULL;
+                       }
+                       console->peer = -1;
+                       close(fd);
+                       return 0;
+               }
                close(fd);
                return 1;
        }
@@ -219,11 +228,6 @@ extern int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
 {
        struct lxc_console *console = &conf->console;
 
-       if (conf->is_execute) {
-               INFO("no console for lxc-execute.");
-               return 0;
-       }
-
        if (!conf->rootfs.path) {
                INFO("no rootfs, no console.");
                return 0;
@@ -471,7 +475,6 @@ static int lxc_console_peer_default(struct lxc_console *console)
        console->tios = malloc(sizeof(*console->tios));
        if (!console->tios) {
                SYSERROR("failed to allocate memory");
-               ret = -ENOMEM;
                goto on_error1;
        }
 
@@ -483,7 +486,6 @@ static int lxc_console_peer_default(struct lxc_console *console)
 on_error2:
        free(console->tios);
        console->tios = NULL;
-       ret = -ENOTTY;
 
 on_error1:
        close(console->peer);
@@ -519,11 +521,6 @@ int lxc_console_create(struct lxc_conf *conf)
        struct lxc_console *console = &conf->console;
        int ret;
 
-       if (conf->is_execute) {
-               INFO("not allocating a console device for lxc-execute.");
-               return 0;
-       }
-
        if (!conf->rootfs.path) {
                INFO("container does not have a rootfs, console device will be shared with the host");
                return 0;
index b1ab5d46e5453813e60782834259653fe34067cc..96688edc05e2440599219ce16ea0748897bb69ed 100644 (file)
@@ -34,7 +34,6 @@
 
 #include "config.h"
 
-#include "bdev.h"
 #include "cgroup.h"
 #include "conf.h"
 #include "commands.h"
@@ -43,6 +42,7 @@
 #include "lxc.h"
 #include "lxclock.h"
 #include "network.h"
+#include "storage.h"
 #include "utils.h"
 
 #if IS_BIONIC
@@ -126,6 +126,47 @@ static int load_tty_major_minor(char *directory, char *output, int len)
        return 0;
 }
 
+static int cmp_version(const char *v1, const char *v2)
+{
+       int ret;
+       int oct_v1[3], oct_v2[3];
+
+       memset(oct_v1, -1, sizeof(oct_v1));
+       memset(oct_v2, -1, sizeof(oct_v2));
+
+       ret = sscanf(v1, "%d.%d.%d", &oct_v1[0], &oct_v1[1], &oct_v1[2]);
+       if (ret < 1)
+               return -1;
+
+       ret = sscanf(v2, "%d.%d.%d", &oct_v2[0], &oct_v2[1], &oct_v2[2]);
+       if (ret < 1)
+               return -1;
+
+       /* Major version is greater. */
+       if (oct_v1[0] > oct_v2[0])
+               return 1;
+
+       if (oct_v1[0] < oct_v2[0])
+               return -1;
+
+       /* Minor number is greater.*/
+       if (oct_v1[1] > oct_v2[1])
+               return 1;
+
+       if (oct_v1[1] < oct_v2[1])
+               return -1;
+
+       /* Patch number is greater. */
+       if (oct_v1[2] > oct_v2[2])
+               return 1;
+
+       /* Patch numbers are equal. */
+       if (oct_v1[2] == oct_v2[2])
+               return 0;
+
+       return -1;
+}
+
 static void exec_criu(struct criu_opts *opts)
 {
        char **argv, log[PATH_MAX];
@@ -263,7 +304,7 @@ static void exec_criu(struct criu_opts *opts)
 
        for (i = 0; i < cgroup_num_hierarchies(); i++) {
                char **controllers = NULL, *fullname;
-               char *path;
+               char *path, *tmp;
 
                if (!cgroup_get_hierarchies(i, &controllers)) {
                        ERROR("failed to get hierarchy %d", i);
@@ -296,11 +337,15 @@ static void exec_criu(struct criu_opts *opts)
                        }
                }
 
-               if (!lxc_deslashify(&path)) {
-                       ERROR("failed to deslashify %s", path);
+               tmp = lxc_deslashify(path);
+               if (!tmp) {
+                       ERROR("Failed to remove extraneous slashes from \"%s\"",
+                             path);
                        free(path);
                        goto err;
                }
+               free(path);
+               path = tmp;
 
                fullname = lxc_string_join(",", (const char **) controllers, false);
                if (!fullname) {
@@ -496,7 +541,7 @@ static void exec_criu(struct criu_opts *opts)
                        struct lxc_netdev *n = it->elem;
                        bool external_not_veth;
 
-                       if (strcmp(opts->criu_version, CRIU_EXTERNAL_NOT_VETH) >= 0) {
+                       if (cmp_version(opts->criu_version, CRIU_EXTERNAL_NOT_VETH) >= 0) {
                                /* Since criu version 2.8 the usage of --veth-pair
                                 * has been deprecated:
                                 * git tag --contains f2037e6d3445fc400
@@ -506,7 +551,7 @@ static void exec_criu(struct criu_opts *opts)
                                external_not_veth = false;
                        }
 
-                       if (n->name) {
+                       if (n->name[0] != '\0') {
                                if (strlen(n->name) >= sizeof(eth))
                                        goto err;
                                strncpy(eth, n->name, sizeof(eth));
@@ -520,7 +565,7 @@ static void exec_criu(struct criu_opts *opts)
                        case LXC_NET_VETH:
                                veth = n->priv.veth_attr.pair;
 
-                               if (n->link) {
+                               if (n->link[0] != '\0') {
                                        if (external_not_veth)
                                                fmt = "veth[%s]:%s@%s";
                                        else
@@ -539,7 +584,7 @@ static void exec_criu(struct criu_opts *opts)
                                        goto err;
                                break;
                        case LXC_NET_MACVLAN:
-                               if (!n->link) {
+                               if (n->link[0] == '\0') {
                                        ERROR("no host interface for macvlan %s", n->name);
                                        goto err;
                                }
@@ -761,11 +806,13 @@ static bool restore_net_info(struct lxc_container *c)
 
                snprintf(template, sizeof(template), "vethXXXXXX");
 
-               if (!netdev->priv.veth_attr.pair)
-                       netdev->priv.veth_attr.pair = lxc_mkifname(template);
+               if (netdev->priv.veth_attr.pair[0] == '\0' &&
+                   netdev->priv.veth_attr.veth1[0] == '\0') {
+                       if (!lxc_mkifname(template))
+                               goto out_unlock;
 
-               if (!netdev->priv.veth_attr.pair)
-                       goto out_unlock;
+                       strcpy(netdev->priv.veth_attr.veth1, template);
+               }
        }
 
        has_error = false;
@@ -775,8 +822,9 @@ out_unlock:
        return !has_error;
 }
 
-// do_restore never returns, the calling process is used as the
-// monitor process. do_restore calls exit() if it fails.
+/* do_restore never returns, the calling process is used as the monitor process.
+ * do_restore calls exit() if it fails.
+ */
 static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_opts *opts, char *criu_version)
 {
        pid_t pid;
@@ -1210,7 +1258,7 @@ bool __criu_restore(struct lxc_container *c, struct migrate_opts *opts)
 
        if (pid == 0) {
                close(pipefd[0]);
-               // this never returns
+               /* this never returns */
                do_restore(c, pipefd[1], opts, criu_version);
        }
 
@@ -1223,9 +1271,10 @@ bool __criu_restore(struct lxc_container *c, struct migrate_opts *opts)
                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 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;
index 91ea3a4954fbade13a60b569be8258cab3a9f9f9..9858081ab59006a8f927dc64ae53d5224ba9caf5 100644 (file)
 #ifndef __LXC_LIST_H
 #define __LXC_LIST_H
 
+#include <stdio.h>
+
 struct lxc_list {
        void *elem;
        struct lxc_list *next;
        struct lxc_list *prev;
 };
 
-#define lxc_init_list(l) { .next = l, .prev = l }
+#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) {
+ *        type *tmp;
  *       tmp = iterator->elem;
- *        // Do stuff with tmp.
  * }
- * free(iterator);
  */
-#define lxc_list_for_each(__iterator, __list)                          \
-       for (__iterator = (__list)->next;                               \
-            __iterator != __list;                                      \
+#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
+/* 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.
+ * struct lxc_list *cur, *next;
+ * lxc_list_for_each_safe(cur, list, next) {
+ *        type *tmp;
+ *       tmp = cur->elem;
  * }
- * 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)
+#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)
@@ -72,7 +71,8 @@ static inline void lxc_list_init(struct lxc_list *list)
 }
 
 /* Add an element to a list. See lxc_list_add() and lxc_list_add_tail() for an
- * idiom. */
+ * idiom.
+ */
 static inline void lxc_list_add_elem(struct lxc_list *list, void *elem)
 {
        list->elem = elem;
@@ -97,8 +97,7 @@ static inline int lxc_list_empty(struct lxc_list *list)
 }
 
 /* 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,
+static inline void __lxc_list_add(struct lxc_list *new, struct lxc_list *prev,
                                  struct lxc_list *next)
 {
        next->prev = new;
@@ -107,8 +106,7 @@ 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:
+/* Idiom to add an element to the beginning of an lxc list:
  *
  *     struct lxc_list *tmp = malloc(sizeof(*tmp));
  *     if (tmp == NULL)
@@ -121,8 +119,7 @@ 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:
+/* Idiom to add an element to the end of an lxc list:
  *
  *     struct lxc_list *tmp = malloc(sizeof(*tmp));
  *     if (tmp == NULL)
@@ -136,14 +133,13 @@ static inline void lxc_list_add_tail(struct lxc_list *head,
        __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);
+/* Idiom to remove an element from a list:
+ * struct lxc_list *cur, *next;
+ * lxc_list_for_each_safe(cur, list, next) {
+ *       lxc_list_del(cur);
+ *       free(cur->elem);
+ *       free(cur);
  * }
- * free(iterator);
  */
 static inline void lxc_list_del(struct lxc_list *list)
 {
@@ -160,6 +156,7 @@ static inline size_t lxc_list_len(struct lxc_list *list)
 {
         size_t i = 0;
         struct lxc_list *iter;
+
         lxc_list_for_each(iter, list) {
                i++;
         }
@@ -167,4 +164,4 @@ static inline size_t lxc_list_len(struct lxc_list *list)
         return i;
 }
 
-#endif
+#endif /* __LXC_LIST_H */
index 8105aca7cae9cdbb701e76111c7f440c72c3ecfa..6ca315bd6a6257c68ca5af4ef67cfa1779609e0b 100644 (file)
@@ -340,10 +340,11 @@ struct lxc_log_category lxc_log_category_lxc = {
 /*---------------------------------------------------------------------------*/
 static int build_dir(const char *name)
 {
-       char *n = strdup(name);  // because we'll be modifying it
-       char *p, *e;
        int ret;
+       char *e, *n, *p;
 
+       /* Make copy of string since we'll be modifying it. */
+       n = strdup(name);
        if (!n) {
                ERROR("Out of memory while creating directory '%s'.", name);
                return -1;
@@ -470,10 +471,9 @@ extern void lxc_log_close(void)
  */
 static int __lxc_log_set_file(const char *fname, int create_dirs)
 {
-       if (lxc_log_fd != -1) {
-               // we are overriding the default.
+       /* we are overriding the default. */
+       if (lxc_log_fd != -1)
                lxc_log_close();
-       }
 
        if (!fname)
                return -1;
@@ -484,8 +484,9 @@ static int __lxc_log_set_file(const char *fname, int create_dirs)
        }
 
 #if USE_CONFIGPATH_LOGS
-       // we don't build_dir for the default if the default is
-       // i.e. /var/lib/lxc/$container/$container.log
+       /* We don't build_dir for the default if the default is i.e.
+        * /var/lib/lxc/$container/$container.log.
+        */
        if (create_dirs)
 #endif
        if (build_dir(fname)) {
index 8098fde9e9ac665a8f601077cb1a4103c12b18a0..e74f7c20de89bfeaf2f350da2f5c18d14aa403a8 100644 (file)
@@ -189,10 +189,10 @@ static int apparmor_process_label_set(const char *inlabel, struct lxc_conf *conf
        curlabel = apparmor_process_label_get(getpid());
 
        if (!aa_stacking_supported() && aa_needs_transition(curlabel)) {
-               // we're already confined, and stacking isn't supported
+               /* we're already confined, and stacking isn't supported */
 
                if (!label || strcmp(curlabel, label) == 0) {
-                       // no change requested
+                       /* no change requested */
                        free(curlabel);
                        return 0;
                }
index c93b4cc70d1d6ebf13fb5beb0e3188abc1bec1de..6f550f0da9adc5f18ad9e37b8fcd9a0c91cea711 100644 (file)
@@ -17,7 +17,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#define _GNU_SOURCE             /* See feature_test_macros(7) */
+#define _GNU_SOURCE
 #include <alloca.h>
 #include <ctype.h>
 #include <errno.h>
 
 static void usage(char *me, bool fail)
 {
-       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);
-}
+       fprintf(stderr, "Usage: %s create {lxcpath} {name} {pid} {type} "
+                       "{bridge} {nicname}\n", me);
+       fprintf(stderr, "Usage: %s delete {lxcpath} {name} "
+                       "{/proc/<pid>/ns/net} {type} {bridge} {nicname}\n", me);
+       fprintf(stderr, "{nicname} is the name to use inside the container\n");
+
+       if (fail)
+               exit(EXIT_FAILURE);
 
-static char *lxcpath, *lxcname;
+       exit(EXIT_SUCCESS);
+}
 
 static int open_and_lock(char *path)
 {
-       int fd;
+       int fd, ret;
        struct flock lk;
 
-       fd = open(path, O_RDWR|O_CREAT, S_IWUSR | S_IRUSR);
+       fd = open(path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR);
        if (fd < 0) {
-               usernic_error("Failed to open %s: %s.\n", path, strerror(errno));
+               usernic_error("Failed to open \"%s\": %s\n", path,
+                             strerror(errno));
                return -1;
        }
 
@@ -81,8 +87,11 @@ static int open_and_lock(char *path)
        lk.l_whence = SEEK_SET;
        lk.l_start = 0;
        lk.l_len = 0;
-       if (fcntl(fd, F_SETLKW, &lk) < 0) {
-               usernic_error("Failed to lock %s: %s.\n", path, strerror(errno));
+
+       ret = fcntl(fd, F_SETLKW, &lk);
+       if (ret < 0) {
+               usernic_error("Failed to lock \"%s\": %s\n", path,
+                             strerror(errno));
                close(fd);
                return -1;
        }
@@ -90,14 +99,13 @@ static int open_and_lock(char *path)
        return fd;
 }
 
-
 static char *get_username(void)
 {
        struct passwd *pwd;
 
        pwd = getpwuid(getuid());
        if (!pwd) {
-               usernic_error("Failed to call get username: %s.\n", strerror(errno));
+               usernic_error("Failed to get username: %s\n", strerror(errno));
                return NULL;
        }
 
@@ -127,9 +135,8 @@ static char **get_groupnames(void)
 
        ngroups = getgroups(0, NULL);
        if (ngroups < 0) {
-               usernic_error(
-                   "Failed to get number of groups the user belongs to: %s.\n",
-                   strerror(errno));
+               usernic_error("Failed to get number of groups the user "
+                             "belongs to: %s\n", strerror(errno));
                return NULL;
        }
        if (ngroups == 0)
@@ -138,7 +145,7 @@ static char **get_groupnames(void)
        group_ids = malloc(sizeof(gid_t) * ngroups);
        if (!group_ids) {
                usernic_error("Failed to allocate memory while getting groups "
-                             "the user belongs to: %s.\n",
+                             "the user belongs to: %s\n",
                              strerror(errno));
                return NULL;
        }
@@ -146,7 +153,7 @@ static char **get_groupnames(void)
        ret = getgroups(ngroups, group_ids);
        if (ret < 0) {
                free(group_ids);
-               usernic_error("Failed to get process groups: %s.\n",
+               usernic_error("Failed to get process groups: %s\n",
                              strerror(errno));
                return NULL;
        }
@@ -155,7 +162,7 @@ static char **get_groupnames(void)
        if (!groupnames) {
                free(group_ids);
                usernic_error("Failed to allocate memory while getting group "
-                             "names: %s.\n",
+                             "names: %s\n",
                              strerror(errno));
                return NULL;
        }
@@ -165,7 +172,7 @@ static char **get_groupnames(void)
        for (i = 0; i < ngroups; i++) {
                gr = getgrgid(group_ids[i]);
                if (!gr) {
-                       usernic_error("Failed to get group name: %s.\n",
+                       usernic_error("Failed to get group name: %s\n",
                                      strerror(errno));
                        free(group_ids);
                        free_groupnames(groupnames);
@@ -174,7 +181,7 @@ static char **get_groupnames(void)
 
                groupnames[i] = strdup(gr->gr_name);
                if (!groupnames[i]) {
-                       usernic_error("Failed to copy group name \"%s\".",
+                       usernic_error("Failed to copy group name \"%s\"",
                                      gr->gr_name);
                        free(group_ids);
                        free_groupnames(groupnames);
@@ -203,19 +210,21 @@ struct alloted_s {
        struct alloted_s *next;
 };
 
-static struct alloted_s *append_alloted(struct alloted_s **head, char *name, int n)
+static struct alloted_s *append_alloted(struct alloted_s **head, char *name,
+                                       int n)
 {
        struct alloted_s *cur, *al;
 
        if (!head || !name) {
-               // sanity check. parameters should not be null
-               usernic_error("%s\n", "Unexpected NULL argument.");
+               /* Sanity check. Parameters should not be null. */
+               usernic_error("%s\n", "Unexpected NULL argument");
                return NULL;
        }
 
        al = malloc(sizeof(struct alloted_s));
        if (!al) {
-               usernic_error("Failed to allocate memory: %s.\n", strerror(errno));
+               usernic_error("Failed to allocate memory: %s\n",
+                             strerror(errno));
                return NULL;
        }
 
@@ -266,7 +275,8 @@ static void free_alloted(struct alloted_s **head)
  * 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, struct alloted_s **alloted)
+static int get_alloted(char *me, char *intype, char *link,
+                      struct alloted_s **alloted)
 {
        int n, ret;
        char name[100], type[100], br[100];
@@ -279,13 +289,15 @@ static int get_alloted(char *me, char *intype, char *link, struct alloted_s **al
 
        fin = fopen(LXC_USERNIC_CONF, "r");
        if (!fin) {
-               usernic_error("Failed to open \"%s\": %s.\n", LXC_USERNIC_CONF, strerror(errno));
+               usernic_error("Failed to open \"%s\": %s\n", LXC_USERNIC_CONF,
+                             strerror(errno));
                return -1;
        }
 
        groups = get_groupnames();
        while ((getline(&line, &len, fin)) != -1) {
-               ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name, type, br, &n);
+               ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name,
+                            type, br, &n);
                if (ret != 4)
                        continue;
 
@@ -345,92 +357,119 @@ static char *get_eow(char *s, char *e)
        return s;
 }
 
-static char *find_line(char *p, char *e, char *u, char *t, char *l)
+static char *find_line(char *buf_start, char *buf_end, char *name,
+                      char *net_type, char *net_link, char *net_dev,
+                      bool *owner, bool *found, bool *keep)
 {
-       char *p1, *p2, *ret;
+       char *end_of_line, *end_of_word, *line;
 
-       while ((p < e) && (p1 = get_eol(p, e)) < e) {
-               ret = p;
-               if (*p == '#')
-                       goto next;
+       while (buf_start < buf_end) {
+               size_t len;
+               char netdev_name[IFNAMSIZ];
+
+               *found = false;
+               *keep = true;
+               *owner = false;
 
-               while ((p < e) && isblank(*p))
-                       p++;
+               end_of_line = get_eol(buf_start, buf_end);
+               if (end_of_line >= buf_end)
+                       return NULL;
 
-               p2 = get_eow(p, e);
-               if (!p2 || ((size_t)(p2 - p)) != strlen(u) || strncmp(p, u, strlen(u)))
+               line = buf_start;
+               if (*buf_start == '#')
                        goto next;
 
-               p = p2 + 1;
-               while ((p < e) && isblank(*p))
-                       p++;
+               while ((buf_start < buf_end) && isblank(*buf_start))
+                       buf_start++;
 
-               p2 = get_eow(p, e);
-               if (!p2 || ((size_t)(p2 - p)) != strlen(t) || strncmp(p, t, strlen(t)))
-                       goto next;
+               /* Check whether the line contains the caller's name. */
+               end_of_word = get_eow(buf_start, buf_end);
+               /* corrupt db */
+               if (!end_of_word)
+                       return NULL;
 
-               p = p2 + 1;
-               while ((p < e) && isblank(*p))
-                       p++;
+               if (strncmp(buf_start, name, strlen(name)))
+                       *found = false;
 
-               p2 = get_eow(p, e);
-               if (!p2 || ((size_t)(p2 - p)) != strlen(l) || strncmp(p, l, strlen(l)))
-                       goto next;
+               *owner = true;
 
-               return ret;
-next:
-               p = p1 + 1;
-       }
+               buf_start = end_of_word + 1;
+               while ((buf_start < buf_end) && isblank(*buf_start))
+                       buf_start++;
 
-       return NULL;
-}
+               /* Check whether line is of the right network type. */
+               end_of_word = get_eow(buf_start, buf_end);
+               /* corrupt db */
+               if (!end_of_word)
+                       return NULL;
 
-static bool nic_exists(char *nic)
-{
-       char path[MAXPATHLEN];
-       int ret;
-       struct stat sb;
+               if (strncmp(buf_start, net_type, strlen(net_type)))
+                       *found = false;
 
-       if (!strcmp(nic, "none"))
-               return true;
+               buf_start = end_of_word + 1;
+               while ((buf_start < buf_end) && isblank(*buf_start))
+                       buf_start++;
 
-       ret = snprintf(path, MAXPATHLEN, "/sys/class/net/%s", nic);
-       if (ret < 0 || ret >= MAXPATHLEN)
-               return false;
+               /* Check whether line is contains the right link. */
+               end_of_word = get_eow(buf_start, buf_end);
+               /* corrupt db */
+               if (!end_of_word)
+                       return NULL;
 
-       ret = stat(path, &sb);
-       if (ret < 0)
-               return false;
+               if (strncmp(buf_start, net_link, strlen(net_link)))
+                       *found = false;
 
-       return true;
-}
+               buf_start = end_of_word + 1;
+               while ((buf_start < buf_end) && isblank(*buf_start))
+                       buf_start++;
 
-static int instantiate_veth(char *n1, char **n2)
-{
-       int err;
+               /* Check whether line contains the right network device. */
+               end_of_word = get_eow(buf_start, buf_end);
+               /* corrupt db */
+               if (!end_of_word)
+                       return NULL;
 
-       err = snprintf(*n2, IFNAMSIZ, "%sp", n1);
-       if (err < 0 || err >= IFNAMSIZ) {
-               usernic_error("%s\n", "Could not create nic name.");
-               return -1;
+               len = end_of_word - buf_start;
+               /* corrupt db */
+               if (len >= IFNAMSIZ)
+                       return NULL;
+
+               memcpy(netdev_name, buf_start, len);
+               netdev_name[len] = '\0';
+               *keep = lxc_nic_exists(netdev_name);
+
+               if (net_dev && !strcmp(netdev_name, net_dev))
+                       *found = true;
+
+               return line;
+
+       next:
+               buf_start = end_of_line + 1;
        }
 
-       err = lxc_veth_create(n1, *n2);
-       if (err) {
-               usernic_error("Failed to create %s-%s : %s.\n", n1, *n2, strerror(-err));
+       return NULL;
+}
+
+static int instantiate_veth(char *veth1, char *veth2)
+{
+       int ret;
+
+       ret = lxc_veth_create(veth1, veth2);
+       if (ret < 0) {
+               usernic_error("Failed to create %s-%s : %s.\n", veth1, veth2,
+                             strerror(-ret));
                return -1;
        }
 
        /* Changing the high byte of the mac address to 0xfe, the bridge
         * interface will always keep the host's mac address and not take the
         * mac address of a container. */
-       err = setup_private_host_hw_addr(n1);
-       if (err)
+       ret = setup_private_host_hw_addr(veth1);
+       if (ret < 0)
                usernic_error("Failed to change mac address of host interface "
-                             "%s : %s.\n",
-                             n1, strerror(-err));
+                             "%s : %s\n", veth1, strerror(-ret));
 
-       return netdev_set_flag(n1, IFF_UP);
+       return netdev_set_flag(veth1, IFF_UP);
 }
 
 static int get_mtu(char *name)
@@ -438,31 +477,32 @@ static int get_mtu(char *name)
        int idx;
 
        idx = if_nametoindex(name);
+       if (idx < 0)
+               return -1;
        return netdev_get_mtu(idx);
 }
 
-static bool create_nic(char *nic, char *br, int pid, char **cnic)
+static int create_nic(char *nic, char *br, int pid, char **cnic)
 {
-       char *veth1buf, *veth2buf;
+       char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
        int mtu, ret;
 
-       veth1buf = alloca(IFNAMSIZ);
-       veth2buf = alloca(IFNAMSIZ);
-       if (!veth1buf || !veth2buf) {
-               usernic_error("Failed allocate memory: %s.\n", strerror(errno));
-               return false;
-       }
-
        ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic);
        if (ret < 0 || ret >= IFNAMSIZ) {
-               usernic_error("%s", "Could not create nic name.\n");
-               return false;
+               usernic_error("%s", "Could not create nic name\n");
+               return -1;
        }
 
+       ret = snprintf(veth2buf, IFNAMSIZ, "%sp", veth1buf);
+       if (ret < 0 || ret >= IFNAMSIZ) {
+               usernic_error("%s\n", "Could not create nic name");
+               return -1;
+       }
        /* create the nics */
-       if (instantiate_veth(veth1buf, &veth2buf) < 0) {
-               usernic_error("%s", "Error creating veth tunnel.\n");
-               return false;
+       ret = instantiate_veth(veth1buf, veth2buf);
+       if (ret < 0) {
+               usernic_error("%s", "Error creating veth tunnel\n");
+               return -1;
        }
 
        if (strcmp(br, "none")) {
@@ -471,21 +511,23 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
                if (mtu > 0) {
                        ret = lxc_netdev_set_mtu(veth1buf, mtu);
                        if (ret < 0) {
-                               usernic_error("Failed to set mtu to %d on %s.\n", mtu, veth1buf);
+                               usernic_error("Failed to set mtu to %d on %s\n",
+                                             mtu, veth1buf);
                                goto out_del;
                        }
 
                        ret = lxc_netdev_set_mtu(veth2buf, mtu);
                        if (ret < 0) {
-                               usernic_error("Failed to set mtu to %d on %s.\n", mtu, veth2buf);
+                               usernic_error("Failed to set mtu to %d on %s\n",
+                                             mtu, veth2buf);
                                goto out_del;
                        }
                }
 
                /* attach veth1 to bridge */
-               ret = lxc_bridge_attach(lxcpath, lxcname, br, veth1buf);
+               ret = lxc_bridge_attach(br, veth1buf);
                if (ret < 0) {
-                       usernic_error("Error attaching %s to %s.\n", veth1buf, br);
+                       usernic_error("Error attaching %s to %s\n", veth1buf, br);
                        goto out_del;
                }
        }
@@ -493,54 +535,22 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
        /* pass veth2 to target netns */
        ret = lxc_netdev_move_by_name(veth2buf, pid, NULL);
        if (ret < 0) {
-               usernic_error("Error moving %s to network namespace of %d.\n", veth2buf, pid);
+               usernic_error("Error moving %s to network namespace of %d\n",
+                             veth2buf, pid);
                goto out_del;
        }
 
        *cnic = strdup(veth2buf);
        if (!*cnic) {
-               usernic_error("Failed to copy string \"%s\".\n", veth2buf);
-               return false;
+               usernic_error("Failed to copy string \"%s\"\n", veth2buf);
+               return -1;
        }
 
-       return true;
+       return 0;
 
 out_del:
        lxc_netdev_delete_by_name(veth1buf);
-       return false;
-}
-
-/*
- * Get a new nic.
- * *dest will contain the name (vethXXXXXX) which is attached
- * on the host to the lxc bridge
- */
-static bool get_new_nicname(char **dest, char *br, int pid, char **cnic)
-{
-       int ret;
-       char template[IFNAMSIZ];
-
-       ret = snprintf(template, sizeof(template), "vethXXXXXX");
-       if (ret < 0 || (size_t)ret >= sizeof(template))
-               return false;
-
-       *dest = lxc_mkifname(template);
-       if (!create_nic(*dest, br, pid, cnic))
-               return false;
-
-       return true;
-}
-
-static bool get_nic_from_line(char *p, char **nic)
-{
-       int ret;
-       char user[100], type[100], br[100];
-
-       ret = sscanf(p, "%99[^ \t\n] %99[^ \t\n] %99[^ \t\n] %99[^ \t\n]", user, type, br, *nic);
-       if (ret != 4)
-               return false;
-
-       return true;
+       return -1;
 }
 
 struct entry_line {
@@ -549,186 +559,230 @@ struct entry_line {
        bool keep;
 };
 
-static bool cull_entries(int fd, char *me, char *t, char *br)
+static bool cull_entries(int fd, char *name, char *net_type, char *net_link,
+                        char *net_dev, bool *found_nicname)
 {
-       int i, n = 0;
-       off_t len;
-       char *buf, *p, *e, *nic;
+       int i, ret;
+       char *buf, *buf_end, *buf_start;
        struct stat sb;
+       int n = 0;
+       bool found, keep;
        struct entry_line *entry_lines = NULL;
 
-       nic = alloca(100);
-       if (!nic)
-               return false;
-
-       if (fstat(fd, &sb) < 0) {
-               usernic_error("Failed to fstat: %s.\n", strerror(errno));
+       ret = fstat(fd, &sb);
+       if (ret < 0) {
+               usernic_error("Failed to fstat: %s\n", strerror(errno));
                return false;
        }
 
-       len = sb.st_size;
-       if (len == 0)
-               return true;
+       if (!sb.st_size)
+               return false;
 
-       buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+       buf = lxc_strmmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        if (buf == MAP_FAILED) {
-               usernic_error("Failed to establish shared memory mapping: %s.\n", strerror(errno));
+               usernic_error("Failed to establish shared memory mapping: %s\n",
+                             strerror(errno));
                return false;
        }
 
-       p = buf;
-       e = buf + len;
-       while ((p = find_line(p, e, me, t, br))) {
+       buf_start = buf;
+       buf_end = buf + sb.st_size;
+       while ((buf_start = find_line(buf_start, buf_end, name, net_type,
+                                     net_link, net_dev, &(bool){true}, &found,
+                                     &keep))) {
                struct entry_line *newe;
 
                newe = realloc(entry_lines, sizeof(*entry_lines) * (n + 1));
                if (!newe) {
                        free(entry_lines);
+                       lxc_strmunmap(buf, sb.st_size);
                        return false;
                }
 
+               if (found)
+                       *found_nicname = true;
+
                entry_lines = newe;
-               entry_lines[n].start = p;
-               entry_lines[n].len = get_eol(p, e) - entry_lines[n].start;
-               entry_lines[n].keep = true;
+               entry_lines[n].start = buf_start;
+               entry_lines[n].len = get_eol(buf_start, buf_end) - entry_lines[n].start;
+               entry_lines[n].keep = keep;
                n++;
-               if (!get_nic_from_line(p, &nic))
-                       continue;
-
-               if (nic && !nic_exists(nic))
-                       entry_lines[n - 1].keep = false;
 
-               p += entry_lines[n - 1].len + 1;
-               if (p >= e)
+               buf_start += entry_lines[n - 1].len + 1;
+               if (buf_start >= buf_end)
                        break;
        }
 
-       p = buf;
+       buf_start = buf;
        for (i = 0; i < n; i++) {
                if (!entry_lines[i].keep)
                        continue;
 
-               memcpy(p, entry_lines[i].start, entry_lines[i].len);
-               p += entry_lines[i].len;
-               *p = '\n';
-               p++;
+               memcpy(buf_start, entry_lines[i].start, entry_lines[i].len);
+               buf_start += entry_lines[i].len;
+               *buf_start = '\n';
+               buf_start++;
        }
        free(entry_lines);
 
-       munmap(buf, sb.st_size);
-       if (ftruncate(fd, p - buf))
-               usernic_error("Failed to set new file size: %s.\n", strerror(errno));
+       lxc_strmunmap(buf, sb.st_size);
+       ret = ftruncate(fd, buf_start - buf);
+       if (ret < 0)
+               usernic_error("Failed to set new file size: %s\n",
+                             strerror(errno));
 
        return true;
 }
 
-static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
+static int count_entries(char *buf, off_t len, char *name, char *net_type, char *net_link)
 {
-       char *e;
        int count = 0;
-
-       e = &buf[len];
-       while ((buf = find_line(buf, e, me, t, br))) {
-               count++;
-               buf = get_eol(buf, e) + 1;
-               if (buf >= e)
+       bool owner = false;;
+       char *buf_end;
+
+       buf_end = &buf[len];
+       while ((buf = find_line(buf, buf_end, name, net_type, net_link, NULL,
+                               &owner, &(bool){true}, &(bool){true}))) {
+               if (owner)
+                       count++;
+               buf = get_eol(buf, buf_end) + 1;
+               if (buf >= buf_end)
                        break;
        }
 
        return count;
 }
 
-/*
- * The dbfile has lines of the format:
- * user type bridge nicname
- */
-static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid,
-                            char *intype, char *br, int allowed,
-                            char **nicname, char **cnic)
+/* The dbfile has lines of the format: user type bridge nicname. */
+static char *get_nic_if_avail(int fd, struct alloted_s *names, int pid,
+                             char *intype, char *br, int allowed, char **cnic)
 {
        int ret;
-       off_t len, slen;
+       size_t slen;
        char *newline, *owner;
+       char nicname[IFNAMSIZ];
        struct stat sb;
        struct alloted_s *n;
        int count = 0;
        char *buf = NULL;
 
        for (n = names; n != NULL; n = n->next)
-               cull_entries(fd, n->name, intype, br);
+               cull_entries(fd, n->name, intype, br, NULL, NULL);
 
        if (allowed == 0)
-               return false;
+               return NULL;
 
        owner = names->name;
 
-       if (fstat(fd, &sb) < 0) {
-               usernic_error("Failed to fstat: %s.\n", strerror(errno));
-               return false;
+       ret = fstat(fd, &sb);
+       if (ret < 0) {
+               usernic_error("Failed to fstat: %s\n", strerror(errno));
+               return NULL;
        }
 
-       len = sb.st_size;
-       if (len > 0) {
-               buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+       if (sb.st_size > 0) {
+               buf = lxc_strmmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
+                                 MAP_SHARED, fd, 0);
                if (buf == MAP_FAILED) {
-                       usernic_error("Failed to establish shared memory mapping: %s.\n", strerror(errno));
-                       return false;
+                       usernic_error("Failed to establish shared memory "
+                                     "mapping: %s\n", strerror(errno));
+                       return NULL;
                }
 
                owner = NULL;
                for (n = names; n != NULL; n = n->next) {
-                       count = count_entries(buf, len, n->name, intype, br);
-
+                       count = count_entries(buf, sb.st_size, n->name, intype, br);
                        if (count >= n->allowed)
                                continue;
 
                        owner = n->name;
                        break;
                }
+
+               lxc_strmunmap(buf, sb.st_size);
        }
 
        if (owner == NULL)
-               return false;
+               return NULL;
 
-       if (!get_new_nicname(nicname, br, pid, cnic))
-               return false;
+       ret = snprintf(nicname, sizeof(nicname), "vethXXXXXX");
+       if (ret < 0 || (size_t)ret >= sizeof(nicname))
+               return NULL;
+
+       if (!lxc_mkifname(nicname))
+               return NULL;
 
-       /* owner  ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
-       slen = strlen(owner) + strlen(intype) + strlen(br) + strlen(*nicname) + 5;
-       newline = alloca(slen);
+       ret = create_nic(nicname, br, pid, cnic);
+       if (ret < 0) {
+               usernic_error("%s", "Failed to create new nic\n");
+               return NULL;
+       }
+
+       /* strlen(owner)
+        * +
+        * " "
+        * +
+        * strlen(intype)
+        * +
+        * " "
+        * +
+        * strlen(br)
+        * +
+        * " "
+        * +
+        * strlen(nicname)
+        * +
+        * \n
+        * +
+        * \0
+        */
+       slen = strlen(owner) + strlen(intype) + strlen(br) + strlen(nicname) + 4;
+       newline = malloc(slen + 1);
        if (!newline) {
-               usernic_error("Failed allocate memory: %s.\n", strerror(errno));
-               return false;
+               free(newline);
+               usernic_error("Failed allocate memory: %s\n", strerror(errno));
+               return NULL;
        }
 
-       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)
-                       usernic_error("Error unlinking %s.\n", *nicname);
-               return false;
+       ret = snprintf(newline, slen + 1, "%s %s %s %s\n", owner, intype, br, nicname);
+       if (ret < 0 || (size_t)ret >= (slen + 1)) {
+               if (lxc_netdev_delete_by_name(nicname) != 0)
+                       usernic_error("Error unlinking %s\n", nicname);
+               free(newline);
+               return NULL;
        }
-       if (len)
-               munmap(buf, len);
 
-       if (ftruncate(fd, len + slen))
-               usernic_error("Failed to set new file size: %s.\n", strerror(errno));
+       /* Note that the file needs to be truncated to the size **without** the
+        * \0 byte! Files are not \0-terminated!
+        */
+       ret = ftruncate(fd, sb.st_size + slen);
+       if (ret < 0)
+               usernic_error("Failed to truncate file: %s\n", strerror(errno));
 
-       buf = mmap(NULL, len + slen, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+       buf = lxc_strmmap(NULL, sb.st_size + slen, PROT_READ | PROT_WRITE,
+                         MAP_SHARED, fd, 0);
        if (buf == MAP_FAILED) {
-               usernic_error("Failed to establish shared memory mapping: %s.\n", strerror(errno));
-               if (lxc_netdev_delete_by_name(*nicname) != 0)
-                       usernic_error("Error unlinking %s.\n", *nicname);
-               return false;
+               usernic_error("Failed to establish shared memory mapping: %s\n",
+                             strerror(errno));
+               if (lxc_netdev_delete_by_name(nicname) != 0)
+                       usernic_error("Error unlinking %s\n", nicname);
+               free(newline);
+               return NULL;
        }
 
-       strcpy(buf + len, newline);
-       munmap(buf, len + slen);
+       /* Note that the memory needs to be moved in the buffer **without** the
+        * \0 byte! Files are not \0-terminated!
+        */
+       memmove(buf + sb.st_size, newline, slen);
+       free(newline);
+       lxc_strmunmap(buf, sb.st_size + slen);
 
-       return true;
+       return strdup(nicname);
 }
 
 static bool create_db_dir(char *fnam)
 {
+       int ret;
        char *p;
 
        p = alloca(strlen(fnam) + 1);
@@ -743,8 +797,11 @@ again:
                return true;
 
        *p = '\0';
-       if (mkdir(fnam, 0755) && errno != EEXIST) {
-               usernic_error("Failed to create %s: %s.\n", fnam, strerror(errno));
+
+       ret = mkdir(fnam, 0755);
+       if (ret < 0 && errno != EEXIST) {
+               usernic_error("Failed to create %s: %s\n", fnam,
+                             strerror(errno));
                *p = '/';
                return false;
        }
@@ -753,23 +810,24 @@ again:
        goto again;
 }
 
-#define VETH_DEF_NAME "eth%d"
-static int rename_in_ns(int pid, char *oldname, char **newnamep)
+static char *lxc_secure_rename_in_ns(int pid, char *oldname, char *newname,
+                                    int *container_veth_ifidx)
 {
+       int ret;
        uid_t ruid, suid, euid;
-       int fret = -1;
-       int fd = -1, ifindex = -1, ofd = -1, ret;
-       bool grab_newname = false;
+       char ifname[IFNAMSIZ];
+       char *string_ret = NULL, *name = NULL;
+       int fd = -1, ifindex = -1, ofd = -1;
 
        ofd = lxc_preserve_ns(getpid(), "net");
        if (ofd < 0) {
-               usernic_error("Failed opening network namespace path for '%d'.", getpid());
-               return fret;
+               usernic_error("Failed opening network namespace path for %d", getpid());
+               return NULL;
        }
 
        fd = lxc_preserve_ns(pid, "net");
        if (fd < 0) {
-               usernic_error("Failed opening network namespace path for '%d'.", pid);
+               usernic_error("Failed opening network namespace path for %d", pid);
                goto do_partial_cleanup;
        }
 
@@ -786,7 +844,7 @@ static int rename_in_ns(int pid, char *oldname, char **newnamep)
        fd = -1;
        if (ret < 0) {
                usernic_error("Failed to setns() to the network namespace of "
-                             "the container with PID %d: %s.\n",
+                             "the container with PID %d: %s\n",
                              pid, strerror(errno));
                goto do_partial_cleanup;
        }
@@ -795,80 +853,83 @@ static int rename_in_ns(int pid, char *oldname, char **newnamep)
        if (ret < 0) {
                usernic_error("Failed to drop privilege by setting effective "
                              "user id and real user id to %d, and saved user "
-                             "ID to 0: %s.\n",
+                             "ID to 0: %s\n",
                              ruid, strerror(errno));
-               // COMMENT(brauner): It's ok to jump to do_full_cleanup here
-               // since setresuid() will succeed when trying to set real,
-               // effective, and saved to values they currently have.
+               /* It's ok to jump to do_full_cleanup here since setresuid()
+                * will succeed when trying to set real, effective, and saved to
+                * values they currently have.
+                */
                goto do_full_cleanup;
        }
 
-       if (!*newnamep) {
-               grab_newname = true;
-               *newnamep = VETH_DEF_NAME;
-
-               ifindex = if_nametoindex(oldname);
-               if (!ifindex) {
-                       usernic_error("Failed to get netdev index: %s.\n", strerror(errno));
-                       goto do_full_cleanup;
-               }
+       /* Check if old interface exists. */
+       ifindex = if_nametoindex(oldname);
+       if (!ifindex) {
+               usernic_error("Failed to get netdev index: %s\n", strerror(errno));
+               goto do_full_cleanup;
        }
 
-       ret = lxc_netdev_rename_by_name(oldname, *newnamep);
+       /* When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
+        * netlink will replace the format specifier with an appropriate index.
+        * So we pass "eth%d".
+        */
+       if (newname)
+               name = newname;
+       else
+               name = "eth%d";
+
+       ret = lxc_netdev_rename_by_name(oldname, name);
+       name = NULL;
        if (ret < 0) {
-               usernic_error("Error %d renaming netdev %s to %s in container.\n", ret, oldname, *newnamep);
+               usernic_error("Error %d renaming netdev %s to %s in container\n",
+                             ret, oldname, newname ? newname : "eth%d");
                goto do_full_cleanup;
        }
 
-       if (grab_newname) {
-               char ifname[IFNAMSIZ];
-               char *namep = ifname;
-
-               if (!if_indextoname(ifindex, namep)) {
-                       usernic_error("Failed to get new netdev name: %s.\n", strerror(errno));
-                       goto do_full_cleanup;
-               }
-
-               *newnamep = strdup(namep);
-               if (!*newnamep)
-                       goto do_full_cleanup;
+       /* Retrieve new name for interface. */
+       if (!if_indextoname(ifindex, ifname)) {
+               usernic_error("Failed to get new netdev name: %s\n", strerror(errno));
+               goto do_full_cleanup;
        }
 
-       fret = 0;
+       /* Allocation failure for strdup() is checked below. */
+       name = strdup(ifname);
+       string_ret = name;
+       *container_veth_ifidx = ifindex;
 
 do_full_cleanup:
        ret = setresuid(ruid, euid, suid);
        if (ret < 0) {
-               usernic_error("Failed to restore privilege by setting effective "
-                             "user id to %d, real user id to %d, and saved user "
-                             "ID to %d: %s.\n",
-                             ruid, euid, suid, strerror(errno));
-               fret = -1;
-               // COMMENT(brauner): setns() should fail if setresuid() doesn't
-               // succeed but there's no harm in falling through; keeps the
-               // code cleaner.
+               usernic_error("Failed to restore privilege by setting "
+                             "effective user id to %d, real user id to %d, "
+                             "and saved user ID to %d: %s\n", ruid, euid, suid,
+                             strerror(errno));
+
+               string_ret = NULL;
        }
 
        ret = setns(ofd, CLONE_NEWNET);
        if (ret < 0) {
                usernic_error("Failed to setns() to original network namespace "
-                             "of PID %d: %s.\n",
-                             ofd, strerror(errno));
-               fret = -1;
+                             "of PID %d: %s\n", ofd, strerror(errno));
+
+               string_ret = NULL;
        }
 
 do_partial_cleanup:
        if (fd >= 0)
                close(fd);
+
+       if (!string_ret && name)
+               free(name);
+
        close(ofd);
 
-       return fret;
+       return string_ret;
 }
 
-/*
- * If the caller (real uid, not effective uid) may read the
- * /proc/[pid]/ns/net, then it is either the caller's netns or one
- * which it created.
+/* If the caller (real uid, not effective uid) may read the /proc/[pid]/ns/net,
+ * then it is either the caller's netns or one which it created.
  */
 static bool may_access_netns(int pid)
 {
@@ -889,7 +950,7 @@ static bool may_access_netns(int pid)
        if (ret < 0) {
                usernic_error("Failed to drop privilege by setting effective "
                              "user id and real user id to %d, and saved user "
-                             "ID to %d: %s.\n",
+                             "ID to %d: %s\n",
                              ruid, euid, strerror(errno));
                return false;
        }
@@ -908,7 +969,7 @@ static bool may_access_netns(int pid)
        ret = setresuid(ruid, euid, suid);
        if (ret < 0) {
                usernic_error("Failed to restore user id to %d, real user id "
-                             "to %d, and saved user ID to %d: %s.\n",
+                             "to %d, and saved user ID to %d: %s\n",
                              ruid, euid, suid, strerror(errno));
                may_access = false;
        }
@@ -916,90 +977,272 @@ static bool may_access_netns(int pid)
        return may_access;
 }
 
+struct user_nic_args {
+       char *cmd;
+       char *lxc_path;
+       char *lxc_name;
+       char *pid;
+       char *type;
+       char *link;
+       char *veth_name;
+};
+
+#define LXC_USERNIC_CREATE 0
+#define LXC_USERNIC_DELETE 1
+
+static bool is_privileged_over_netns(int netns_fd)
+{
+       int ret;
+       uid_t euid, ruid, suid;
+       bool bret = false;
+       int ofd = -1;
+
+       ofd = lxc_preserve_ns(getpid(), "net");
+       if (ofd < 0) {
+               usernic_error("Failed opening network namespace path for %d", getpid());
+               return false;
+       }
+
+       ret = getresuid(&ruid, &euid, &suid);
+       if (ret < 0) {
+               usernic_error("Failed to retrieve real, effective, and saved "
+                             "user IDs: %s\n",
+                             strerror(errno));
+               goto do_partial_cleanup;
+       }
+
+       ret = setns(netns_fd, CLONE_NEWNET);
+       if (ret < 0) {
+               usernic_error("Failed to setns() to network namespace %s\n",
+                             strerror(errno));
+               goto do_partial_cleanup;
+       }
+
+       ret = setresuid(ruid, ruid, 0);
+       if (ret < 0) {
+               usernic_error("Failed to drop privilege by setting effective "
+                             "user id and real user id to %d, and saved user "
+                             "ID to 0: %s\n",
+                             ruid, strerror(errno));
+               /* It's ok to jump to do_full_cleanup here since setresuid()
+                * will succeed when trying to set real, effective, and saved to
+                * values they currently have.
+                */
+               goto do_full_cleanup;
+       }
+
+       /* Test whether we are privileged over the network namespace. To do this
+        * we try to delete the loopback interface which is not possible. If we
+        * are privileged over the network namespace we will get ENOTSUP. If we
+        * are not privileged over the network namespace we will get EPERM.
+        */
+       ret = lxc_netdev_delete_by_name("lo");
+       if (ret == -ENOTSUP)
+               bret = true;
+
+do_full_cleanup:
+       ret = setresuid(ruid, euid, suid);
+       if (ret < 0) {
+               usernic_error("Failed to restore privilege by setting "
+                             "effective user id to %d, real user id to %d, "
+                             "and saved user ID to %d: %s\n", ruid, euid, suid,
+                             strerror(errno));
+
+               bret = false;
+       }
+
+       ret = setns(ofd, CLONE_NEWNET);
+       if (ret < 0) {
+               usernic_error("Failed to setns() to original network namespace "
+                             "of PID %d: %s\n", ofd, strerror(errno));
+
+               bret = false;
+       }
+
+do_partial_cleanup:
+
+       close(ofd);
+       return bret;
+}
+
 int main(int argc, char *argv[])
 {
-       int n, fd;
-       char *me;
-       char *nicname;
-       int pid;
-       char *cnic = NULL; /* Created nic name in container is returned here. */
-       char *vethname = NULL;
-       bool gotone = false;
+       int fd, n, pid, request, ret;
+       char *me, *newname;
+       struct user_nic_args args;
+       int container_veth_ifidx = -1, host_veth_ifidx = -1, netns_fd = -1;
+       char *cnic = NULL, *nicname = NULL;
        struct alloted_s *alloted = NULL;
 
-       nicname = alloca(40);
-       if (!nicname) {
-               usernic_error("Failed allocate memory: %s.\n", strerror(errno));
+       if (argc < 7 || argc > 8) {
+               usage(argv[0], true);
                exit(EXIT_FAILURE);
        }
 
-       /* set a sane env, because we are setuid-root */
-       if (clearenv() < 0) {
-               usernic_error("%s", "Failed to clear environment.\n");
+       memset(&args, 0, sizeof(struct user_nic_args));
+       args.cmd = argv[1];
+       args.lxc_path = argv[2];
+       args.lxc_name = argv[3];
+       args.pid = argv[4];
+       args.type = argv[5];
+       args.link = argv[6];
+       if (argc >= 8)
+               args.veth_name = argv[7];
+
+       if (!strcmp(args.cmd, "create")) {
+               request = LXC_USERNIC_CREATE;
+       } else if (!strcmp(args.cmd, "delete")) {
+               request = LXC_USERNIC_DELETE;
+       } else {
+               usage(argv[0], true);
                exit(EXIT_FAILURE);
        }
-       if (setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1) < 0) {
-               usernic_error("%s", "Failed to set PATH, exiting.\n");
+
+       /* Set a sane env, because we are setuid-root. */
+       ret = clearenv();
+       if (ret) {
+               usernic_error("%s", "Failed to clear environment\n");
                exit(EXIT_FAILURE);
        }
-       if ((me = get_username()) == NULL) {
-               usernic_error("%s", "Failed to get username.\n");
+
+       ret = setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
+       if (ret < 0) {
+               usernic_error("%s", "Failed to set PATH, exiting\n");
                exit(EXIT_FAILURE);
        }
 
-       if (argc < 6)
-               usage(argv[0], true);
-
-       if (argc >= 7)
-               vethname = argv[6];
-
-       lxcpath = argv[1];
-       lxcname = argv[2];
-
-       errno = 0;
-       pid = strtol(argv[3], NULL, 10);
-       if (errno) {
-               usernic_error("Could not read pid: %s.\n", argv[1]);
+       me = get_username();
+       if (!me) {
+               usernic_error("%s", "Failed to get username\n");
                exit(EXIT_FAILURE);
        }
 
+       if (request == LXC_USERNIC_CREATE) {
+               ret = lxc_safe_int(args.pid, &pid);
+               if (ret < 0) {
+                       usernic_error("Could not read pid: %s\n", args.pid);
+                       exit(EXIT_FAILURE);
+               }
+       } else if (request == LXC_USERNIC_DELETE) {
+               netns_fd = open(args.pid, O_RDONLY);
+               if (netns_fd < 0) {
+                       usernic_error("Could not open \"%s\": %s\n", args.pid,
+                                     strerror(errno));
+                       exit(EXIT_FAILURE);
+               }
+       }
+
        if (!create_db_dir(LXC_USERNIC_DB)) {
-               usernic_error("%s", "Failed to create directory for db file.\n");
+               usernic_error("%s", "Failed to create directory for db file\n");
+               if (netns_fd >= 0)
+                       close(netns_fd);
                exit(EXIT_FAILURE);
        }
 
-       if ((fd = open_and_lock(LXC_USERNIC_DB)) < 0) {
-               usernic_error("Failed to lock %s.\n", LXC_USERNIC_DB);
+       fd = open_and_lock(LXC_USERNIC_DB);
+       if (fd < 0) {
+               usernic_error("Failed to lock %s\n", LXC_USERNIC_DB);
+               if (netns_fd >= 0)
+                       close(netns_fd);
                exit(EXIT_FAILURE);
        }
 
-       if (!may_access_netns(pid)) {
-               usernic_error("User %s may not modify netns for pid %d.\n", me, pid);
-               exit(EXIT_FAILURE);
+       if (request == LXC_USERNIC_CREATE) {
+               if (!may_access_netns(pid)) {
+                       usernic_error("User %s may not modify netns for pid %d\n", me, pid);
+                       exit(EXIT_FAILURE);
+               }
+       } else if (request == LXC_USERNIC_DELETE) {
+               bool has_priv;
+               has_priv = is_privileged_over_netns(netns_fd);
+               close(netns_fd);
+               if (!has_priv) {
+                       usernic_error("%s", "Process is not privileged over "
+                                           "network namespace\n");
+                       exit(EXIT_FAILURE);
+               }
        }
 
-       n = get_alloted(me, argv[4], argv[5], &alloted);
+       n = get_alloted(me, args.type, args.link, &alloted);
+
+       if (request == LXC_USERNIC_DELETE) {
+               int ret;
+               struct alloted_s *it;
+               bool found_nicname = false;
+
+               if (!is_ovs_bridge(args.link)) {
+                       usernic_error("%s", "Deletion of non ovs type network "
+                                           "devices not implemented\n");
+                       close(fd);
+                       free_alloted(&alloted);
+                       exit(EXIT_FAILURE);
+               }
+
+               /* Check whether the network device we are supposed to delete
+                * exists in the db. If it doesn't we will not delete it as we
+                * need to assume the network device is not under our control.
+                * As a side effect we also clear any invalid entries from the
+                * database.
+                */
+               for (it = alloted; it; it = it->next)
+                       cull_entries(fd, it->name, args.type, args.link,
+                                    args.veth_name, &found_nicname);
+               close(fd);
+               free_alloted(&alloted);
+
+               if (!found_nicname) {
+                       usernic_error("Caller is not allowed to delete network "
+                                     "device \"%s\"\n", args.veth_name);
+                       exit(EXIT_FAILURE);
+               }
+
+               ret = lxc_ovs_delete_port(args.link, args.veth_name);
+               if (ret < 0) {
+                       usernic_error("Failed to remove port \"%s\" from "
+                                     "openvswitch bridge \"%s\"",
+                                     args.veth_name, args.link);
+                       exit(EXIT_FAILURE);
+               }
+
+               exit(EXIT_SUCCESS);
+       }
        if (n > 0)
-               gotone = get_nic_if_avail(fd, alloted, pid, argv[4], argv[5], n, &nicname, &cnic);
+               nicname = get_nic_if_avail(fd, alloted, pid, args.type,
+                                          args.link, n, &cnic);
 
        close(fd);
        free_alloted(&alloted);
-       if (!gotone) {
-               usernic_error("%s", "Quota reached.\n");
+       if (!nicname) {
+               usernic_error("%s", "Quota reached\n");
                exit(EXIT_FAILURE);
        }
 
        /* Now rename the link. */
-       if (rename_in_ns(pid, cnic, &vethname) < 0) {
-               usernic_error("%s", "Failed to rename the link.\n");
-               if (lxc_netdev_delete_by_name(cnic) < 0)
-                       usernic_error("Failed to delete link \"%s\" the link. Manual cleanup needed.\n", cnic);
+       newname = lxc_secure_rename_in_ns(pid, cnic, args.veth_name,
+                                         &container_veth_ifidx);
+       if (!newname) {
+               usernic_error("%s", "Failed to rename the link\n");
+               ret = lxc_netdev_delete_by_name(cnic);
+               if (ret < 0)
+                       usernic_error("Failed to delete \"%s\"\n", cnic);
+               free(nicname);
+               exit(EXIT_FAILURE);
+       }
+
+       host_veth_ifidx = if_nametoindex(nicname);
+       if (!host_veth_ifidx) {
+               free(newname);
+               free(nicname);
+               usernic_error("Failed to get netdev index: %s\n", strerror(errno));
                exit(EXIT_FAILURE);
        }
 
-       /* Write the name of the interface pair to the stdout - like
-        * eth0:veth9MT2L4.
+       /* Write names of veth pairs and their ifindeces to stout:
+        * (e.g. eth0:731:veth9MT2L4:730)
         */
-       fprintf(stdout, "%s:%s\n", vethname, nicname);
+       fprintf(stdout, "%s:%d:%s:%d\n", newname, container_veth_ifidx, nicname,
+               host_veth_ifidx);
+       free(newname);
+       free(nicname);
        exit(EXIT_SUCCESS);
 }
index fa04becb68ecb9d5479c57221f997df25a18ec35..5e8ad00f98ae9d55c858883b0504be59b630dbe3 100644 (file)
@@ -40,9 +40,6 @@
 
 #include "af_unix.h"
 #include "attach.h"
-#include "bdev.h"
-#include "lxcoverlay.h"
-#include "lxcbtrfs.h"
 #include "cgroup.h"
 #include "conf.h"
 #include "config.h"
@@ -50,6 +47,7 @@
 #include "commands_utils.h"
 #include "confile.h"
 #include "confile_legacy.h"
+#include "confile_utils.h"
 #include "console.h"
 #include "criu.h"
 #include "log.h"
 #include "monitor.h"
 #include "namespace.h"
 #include "network.h"
-#include "sync.h"
 #include "start.h"
 #include "state.h"
+#include "storage.h"
+#include "storage/btrfs.h"
+#include "storage/overlay.h"
+#include "sync.h"
 #include "utils.h"
 #include "version.h"
 
@@ -105,7 +106,8 @@ static bool do_lxcapi_destroy(struct lxc_container *c);
 static const char *lxcapi_get_config_path(struct lxc_container *c);
 #define do_lxcapi_get_config_path(c) lxcapi_get_config_path(c)
 static bool do_lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v);
-static bool container_destroy(struct lxc_container *c);
+static bool container_destroy(struct lxc_container *c,
+                             struct lxc_storage *storage);
 static bool get_snappath_dir(struct lxc_container *c, char *snappath);
 static bool lxcapi_snapshot_destroy_all(struct lxc_container *c);
 static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file);
@@ -149,7 +151,7 @@ static int ongoing_create(struct lxc_container *c)
                return 0;
        fd = open(path, O_RDWR);
        if (fd < 0) {
-               // give benefit of the doubt
+               /* give benefit of the doubt */
                SYSERROR("Error opening partial file");
                return 0;
        }
@@ -159,18 +161,18 @@ static int ongoing_create(struct lxc_container *c)
        lk.l_len = 0;
        lk.l_pid = -1;
        if (fcntl(fd, F_GETLK, &lk) == 0 && lk.l_pid != -1) {
-               // create is still ongoing
+               /* create is still ongoing */
                close(fd);
                return 1;
        }
-       // create completed but partial is still there.
+       /* create completed but partial is still there. */
        close(fd);
        return 2;
 }
 
 static int create_partial(struct lxc_container *c)
 {
-       // $lxcpath + '/' + $name + '/partial' + \0
+       /* $lxcpath + '/' + $name + '/partial' + \0 */
        int len = strlen(c->config_path) + strlen(c->name) + 10;
        char *path = alloca(len);
        int fd, ret;
@@ -200,7 +202,7 @@ static int create_partial(struct lxc_container *c)
 
 static void remove_partial(struct lxc_container *c, int fd)
 {
-       // $lxcpath + '/' + $name + '/partial' + \0
+       /* $lxcpath + '/' + $name + '/partial' + \0 */
        int len = strlen(c->config_path) + strlen(c->name) + 10;
        char *path = alloca(len);
        int ret;
@@ -294,18 +296,21 @@ int lxc_container_get(struct lxc_container *c)
        if (!c)
                return 0;
 
-       // if someone else has already started freeing the container, don't
-       // try to take the lock, which may be invalid
+       /* If someone else has already started freeing the container, don't try
+        * to take the lock, which may be invalid.
+        */
        if (c->numthreads < 1)
                return 0;
 
        if (container_mem_lock(c))
                return 0;
-       if (c->numthreads < 1) {
-               // bail without trying to unlock, bc the privlock is now probably
-               // in freed memory
+
+       /* Bail without trying to unlock, bc the privlock is now probably in
+        * freed memory.
+        */
+       if (c->numthreads < 1)
                return 0;
-       }
+
        c->numthreads++;
        container_mem_unlock(c);
        return 1;
@@ -703,18 +708,6 @@ static int lxc_rcv_status(int state_socket)
 {
         int ret;
         int state = -1;
-        struct timeval timeout = {0};
-
-        /* Set 5 second timeout to prevent hanging forever in case something
-         * goes wrong. 5 seconds is a long time to get into RUNNING state.
-         */
-        timeout.tv_sec = 5;
-        ret = setsockopt(state_socket, SOL_SOCKET, SO_RCVTIMEO,
-                         (const void *)&timeout, sizeof(timeout));
-        if (ret < 0) {
-                SYSERROR("Failed to set 5s timeout on containter state socket");
-                return -1;
-        }
 
 again:
         /* Receive container state. */
@@ -1153,16 +1146,16 @@ static bool create_container_dir(struct lxc_container *c)
        return ret == 0;
 }
 
-/*
- * do_bdev_create: thin wrapper around bdev_create().  Like bdev_create(),
- * it returns a mounted bdev on success, NULL on error.
+/* do_storage_create: thin wrapper around storage_create(). Like
+ * storage_create(), it returns a mounted bdev on success, NULL on error.
  */
-static struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
-                                  struct bdev_specs *specs)
+static struct lxc_storage *do_storage_create(struct lxc_container *c,
+                                            const char *type,
+                                            struct bdev_specs *specs)
 {
        char *dest;
        size_t len;
-       struct bdev *bdev;
+       struct lxc_storage *bdev;
        int ret;
 
        /* rootfs.path or lxcpath/lxcname/rootfs */
@@ -1180,7 +1173,7 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
        if (ret < 0 || ret >= len)
                return NULL;
 
-       bdev = bdev_create(dest, type, c->name, specs);
+       bdev = storage_create(dest, type, c->name, specs);
        if (!bdev) {
                ERROR("Failed to create backing store type %s", type);
                return NULL;
@@ -1199,7 +1192,7 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
                if (chown_mapped_root(bdev->dest, c->lxc_conf) < 0) {
                        ERROR("Error chowning %s to container root", bdev->dest);
                        suggest_default_idmap();
-                       bdev_put(bdev);
+                       storage_put(bdev);
                        return NULL;
                }
        }
@@ -1229,9 +1222,9 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
                return false;
        }
 
-       if (pid == 0) { // child
+       if (pid == 0) { /* child */
                char *patharg, *namearg, *rootfsarg;
-               struct bdev *bdev = NULL;
+               struct lxc_storage *bdev = NULL;
                int i;
                int ret, len, nargs = 0;
                char **newargv;
@@ -1241,7 +1234,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
                        exit(1);
                }
 
-               bdev = bdev_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
+               bdev = storage_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
                if (!bdev) {
                        ERROR("Error opening rootfs");
                        exit(1);
@@ -1262,13 +1255,47 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
                if (strcmp(bdev->type, "dir") && strcmp(bdev->type, "btrfs")) {
                        if (geteuid() != 0) {
                                ERROR("non-root users can only create btrfs and directory-backed containers");
-                               exit(1);
+                               exit(EXIT_FAILURE);
                        }
-                       if (bdev->ops->mount(bdev) < 0) {
-                               ERROR("Error mounting rootfs");
-                               exit(1);
+
+                       if (!strcmp(bdev->type, "overlay") || !strcmp(bdev->type, "overlayfs")) {
+                               /* If we create an overlay container we need to
+                                * rsync the contents into
+                                * <container-path>/<container-name>/rootfs.
+                                * However, the overlay mount function will
+                                * mount will mount
+                                * <container-path>/<container-name>/delta0
+                                * over
+                                * <container-path>/<container-name>/rootfs
+                                * which means we would rsync the rootfs into
+                                * the delta directory. That doesn't make sense
+                                * since the delta directory only exists to
+                                * record the differences to
+                                * <container-path>/<container-name>/rootfs. So
+                                * let's simply bind-mount here and then rsync
+                                * directly into
+                                * <container-path>/<container-name>/rootfs.
+                                */
+                               char *src;
+
+                               src = ovl_get_rootfs(bdev->src, &(size_t){0});
+                               if (!src) {
+                                       ERROR("Failed to get rootfs");
+                                       exit(EXIT_FAILURE);
+                               }
+
+                               ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC, NULL);
+                               if (ret < 0) {
+                                       ERROR("Failed to mount rootfs");
+                                       return -1;
+                               }
+                       } else {
+                               if (bdev->ops->mount(bdev) < 0) {
+                                       ERROR("Failed to mount rootfs");
+                                       exit(EXIT_FAILURE);
+                               }
                        }
-               } else { // TODO come up with a better way here!
+               } else { /* TODO come up with a better way here! */
                        char *src;
                        free(bdev->dest);
                        src = lxc_storage_get_path(bdev->src, bdev->type);
@@ -1281,7 +1308,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
                 */
                if (argv)
                        for (nargs = 0; argv[nargs]; nargs++) ;
-               nargs += 4; // template, path, rootfs and name args
+               nargs += 4; /* template, path, rootfs and name args */
 
                newargv = malloc(nargs * sizeof(*newargv));
                if (!newargv)
@@ -1416,15 +1443,16 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
                        for (i = 0; i < nargs; i++)
                                n2[i + n2args] = newargv[i];
                        n2args += nargs;
-                       // Finally add "--mapped-uid $uid" to tell template what to chown
-                       // cached images to
+                       /* Finally add "--mapped-uid $uid" to tell template
+                        * what to chown cached images to.
+                        */
                        n2args += 4;
                        n2 = realloc(n2, n2args * sizeof(char *));
                        if (!n2) {
                                SYSERROR("out of memory");
                                exit(1);
                        }
-                       // note n2[n2args-1] is NULL
+                       /* note n2[n2args-1] is NULL */
                        n2[n2args-5] = "--mapped-uid";
                        snprintf(txtuid, 20, "%d", hostid_mapped);
                        n2[n2args-4] = txtuid;
@@ -1658,24 +1686,25 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
                goto out_unlock;
        }
 
-       if (pid == 0) { // child
-               struct bdev *bdev = NULL;
+       if (pid == 0) { /* child */
+               struct lxc_storage *bdev = NULL;
 
-               if (!(bdev = do_bdev_create(c, bdevtype, specs))) {
+               bdev = do_storage_create(c, bdevtype, specs);
+               if (!bdev) {
                        ERROR("Error creating backing store type %s for %s",
                                bdevtype ? bdevtype : "(none)", c->name);
-                       exit(1);
+                       exit(EXIT_FAILURE);
                }
 
                /* save config file again to store the new rootfs location */
                if (!do_lxcapi_save_config(c, NULL)) {
                        ERROR("failed to save starting configuration for %s", c->name);
-                       // parent task won't see bdev in config so we delete it
+                       /* Parent task won't see bdev in config so we delete it. */
                        bdev->ops->umount(bdev);
                        bdev->ops->destroy(bdev);
-                       exit(1);
+                       exit(EXIT_FAILURE);
                }
-               exit(0);
+               exit(EXIT_SUCCESS);
        }
        if (wait_for_pid(pid) != 0)
                goto out_unlock;
@@ -1689,8 +1718,9 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
        if (!create_run_template(c, tpath, !!(flags & LXC_CREATE_QUIET), argv))
                goto out_unlock;
 
-       // now clear out the lxc_conf we have, reload from the created
-       // container
+       /* Now clear out the lxc_conf we have, reload from the created
+        * container.
+        */
        do_lxcapi_clear_config(c);
 
        if (t) {
@@ -1706,7 +1736,7 @@ out_unlock:
                remove_partial(c, partial_fd);
 out:
        if (!ret)
-               container_destroy(c);
+               container_destroy(c, NULL);
 free_tpath:
        free(tpath);
        return ret;
@@ -1839,18 +1869,30 @@ out:
 
 static void do_clear_unexp_config_line(struct lxc_conf *conf, const char *key)
 {
-       if (strcmp(key, "lxc.cgroup") == 0)
-               clear_unexp_config_line(conf, key, true);
-       else if (strcmp(key, "lxc.network") == 0)
-               clear_unexp_config_line(conf, key, true);
-       else if (strcmp(key, "lxc.net") == 0)
-               clear_unexp_config_line(conf, key, true);
-       else if (strcmp(key, "lxc.hook") == 0)
-               clear_unexp_config_line(conf, key, true);
-       else
-               clear_unexp_config_line(conf, key, false);
-       if (!do_append_unexp_config_line(conf, key, ""))
-               WARN("Error clearing configuration for %s", key);
+       if (!strcmp(key, "lxc.cgroup"))
+               return clear_unexp_config_line(conf, key, true);
+
+       if (!strcmp(key, "lxc.network"))
+               return clear_unexp_config_line(conf, key, true);
+
+       if (!strcmp(key, "lxc.net"))
+               return clear_unexp_config_line(conf, key, true);
+
+       /* Clear a network with a specific index. */
+       if (!strncmp(key, "lxc.net.", 8)) {
+               int ret;
+               const char *idx;
+
+               idx = key + 8;
+               ret = lxc_safe_uint(idx, &(unsigned int){0});
+               if (!ret)
+                       return clear_unexp_config_line(conf, key, true);
+       }
+
+       if (!strcmp(key, "lxc.hook"))
+               return clear_unexp_config_line(conf, key, true);
+
+       return clear_unexp_config_line(conf, key, false);
 }
 
 static bool do_lxcapi_clear_config_item(struct lxc_container *c,
@@ -1865,7 +1907,7 @@ static bool do_lxcapi_clear_config_item(struct lxc_container *c,
        if (container_mem_lock(c))
                return false;
 
-       config = lxc_getconfig(key);
+       config = lxc_get_config(key);
        /* Verify that the config key exists and that it has a callback
         * implemented.
         */
@@ -1891,14 +1933,15 @@ static inline bool enter_net_ns(struct lxc_container *c)
        return switch_to_ns(pid, "net");
 }
 
-// used by qsort and bsearch functions for comparing names
+/* Used by qsort and bsearch functions for comparing names. */
 static inline int string_cmp(char **first, char **second)
 {
        return strcmp(*first, *second);
 }
 
-// used by qsort and bsearch functions for comparing container names
-static inline int container_cmp(struct lxc_container **first, struct lxc_container **second)
+/* Used by qsort and bsearch functions for comparing container names. */
+static inline int container_cmp(struct lxc_container **first,
+                               struct lxc_container **second)
 {
        return strcmp((*first)->name, (*second)->name);
 }
@@ -1916,15 +1959,17 @@ static bool add_to_array(char ***names, char *cname, int pos)
        if (!newnames[pos])
                return false;
 
-       // sort the arrray as we will use binary search on it
-       qsort(newnames, pos + 1, sizeof(char *), (int (*)(const void *,const void *))string_cmp);
+       /* Sort the arrray as we will use binary search on it. */
+       qsort(newnames, pos + 1, sizeof(char *),
+             (int (*)(const void *, const void *))string_cmp);
 
        return true;
 }
 
-static bool add_to_clist(struct lxc_container ***list, struct lxc_container *c, int pos, bool sort)
+static bool add_to_clist(struct lxc_container ***list, struct lxc_container *c,
+                        int pos, bool sort)
 {
-       struct lxc_container **newlist = realloc(*list, (pos+1) * sizeof(struct lxc_container *));
+       struct lxc_container **newlist = realloc(*list, (pos + 1) * sizeof(struct lxc_container *));
        if (!newlist) {
                ERROR("Out of memory");
                return false;
@@ -1933,9 +1978,10 @@ static bool add_to_clist(struct lxc_container ***list, struct lxc_container *c,
        *list = newlist;
        newlist[pos] = c;
 
-       // sort the arrray as we will use binary search on it
+       /* Sort the arrray as we will use binary search on it. */
        if (sort)
-               qsort(newlist, pos + 1, sizeof(struct lxc_container *), (int (*)(const void *,const void *))container_cmp);
+               qsort(newlist, pos + 1, sizeof(struct lxc_container *),
+                     (int (*)(const void *, const void *))container_cmp);
 
        return true;
 }
@@ -1982,7 +2028,7 @@ static char ** do_lxcapi_get_interfaces(struct lxc_container *c)
                return NULL;
        }
 
-       if (pid == 0) { // child
+       if (pid == 0) { /* child */
                int ret = 1, nbytes;
                struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
 
@@ -2071,7 +2117,7 @@ static char** do_lxcapi_get_ips(struct lxc_container *c, const char* interface,
                return NULL;
        }
 
-       if (pid == 0) { // child
+       if (pid == 0) { /* child */
                int ret = 1, nbytes;
                struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
                char addressOutputBuffer[INET6_ADDRSTRLEN];
@@ -2181,7 +2227,7 @@ static int do_lxcapi_get_config_item(struct lxc_container *c, const char *key, c
        if (container_mem_lock(c))
                return -1;
 
-       config = lxc_getconfig(key);
+       config = lxc_get_config(key);
        /* Verify that the config key exists and that it has a callback
         * implemented.
         */
@@ -2211,22 +2257,29 @@ WRAP_API_1(char *, lxcapi_get_running_config_item, const char *)
 
 static int do_lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv, int inlen)
 {
+       int ret = -1;
+
+       /* List all config items. */
        if (!key)
-               return lxc_listconfigs(retv, inlen);
-       /*
-        * Support 'lxc.net.<idx>', i.e. 'lxc.net.0'
-        * This is an intelligent result to show which keys are valid given
-        * the type of nic it is
-        */
+               return lxc_list_config_items(retv, inlen);
+
        if (!c || !c->lxc_conf)
                return -1;
+
        if (container_mem_lock(c))
                return -1;
-       int ret = -1;
-       if (strncmp(key, "lxc.net.", 8) == 0)
-               ret = lxc_list_nicconfigs(c->lxc_conf, key, retv, inlen);
+
+       /* Support 'lxc.net.<idx>', i.e. 'lxc.net.0'
+        * This is an intelligent result to show which keys are valid given the
+        * type of nic it is.
+        */
+       if (!strncmp(key, "lxc.net.", 8))
+               ret = lxc_list_net(c->lxc_conf, key, retv, inlen);
        else if (strncmp(key, "lxc.network.", 12) == 0)
                ret = lxc_list_nicconfigs_legacy(c->lxc_conf, key, retv, inlen);
+       else
+               ret = lxc_list_subkeys(c->lxc_conf, key, retv, inlen);
+
        container_mem_unlock(c);
        return ret;
 }
@@ -2242,9 +2295,9 @@ static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file)
        if (!alt_file)
                alt_file = c->configfile;
        if (!alt_file)
-               return false; // should we write to stdout if no file is specified?
+               return false;
 
-       // If we haven't yet loaded a config, load the stock config
+       /* If we haven't yet loaded a config, load the stock config. */
        if (!c->lxc_conf) {
                if (!do_lxcapi_load_config(c, lxc_global_config_value("lxc.default_config"))) {
                        ERROR("Error loading default configuration file %s while saving %s", lxc_global_config_value("lxc.default_config"), c->name);
@@ -2255,10 +2308,9 @@ static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file)
        if (!create_container_dir(c))
                return false;
 
-       /*
-        * If we're writing to the container's config file, take the
-        * disk lock.  Otherwise just take the memlock to protect the
-        * struct lxc_container while we're traversing it.
+       /* If we're writing to the container's config file, take the disk lock.
+        * Otherwise just take the memlock to protect the struct lxc_container
+        * while we're traversing it.
         */
        if (strcmp(c->configfile, alt_file) == 0)
                need_disklock = true;
@@ -2478,7 +2530,7 @@ static bool has_fs_snapshots(struct lxc_container *c)
                        goto out;
                ret = fscanf(f, "%d", &v);
                fclose(f);
-               // TODO: Figure out what to do with the return value of fscanf.
+               /* TODO: Figure out what to do with the return value of fscanf. */
                if (ret != 1)
                        INFO("Container uses new lxc-snapshots format %s", path);
        }
@@ -2517,13 +2569,18 @@ static bool has_snapshots(struct lxc_container *c)
 }
 
 static bool do_destroy_container(struct lxc_conf *conf) {
+       int ret;
+
        if (am_unpriv()) {
-               if (userns_exec_1(conf, bdev_destroy_wrapper, conf,
-                                 "bdev_destroy_wrapper") < 0)
+               ret = userns_exec_full(conf, storage_destroy_wrapper, conf,
+                                      "storage_destroy_wrapper");
+               if (ret < 0)
                        return false;
+
                return true;
        }
-       return bdev_destroy(conf);
+
+       return storage_destroy(conf);
 }
 
 static int lxc_rmdir_onedev_wrapper(void *data)
@@ -2532,11 +2589,21 @@ static int lxc_rmdir_onedev_wrapper(void *data)
        return lxc_rmdir_onedev(arg, "snaps");
 }
 
-static bool container_destroy(struct lxc_container *c)
+static int lxc_unlink_exec_wrapper(void *data)
 {
+       char *arg = data;
+       return unlink(arg);
+}
+
+static bool container_destroy(struct lxc_container *c,
+                             struct lxc_storage *storage)
+{
+       const char *p1;
+       size_t len;
+       struct lxc_conf *conf;
+       char *path = NULL;
        bool bret = false;
        int ret = 0;
-       struct lxc_conf *conf;
 
        if (!c || !do_lxcapi_is_defined(c))
                return false;
@@ -2546,35 +2613,34 @@ static bool container_destroy(struct lxc_container *c)
                return false;
 
        if (!is_stopped(c)) {
-               // we should queue some sort of error - in c->error_string?
+               /* We should queue some sort of error - in c->error_string? */
                ERROR("container %s is not stopped", c->name);
                goto out;
        }
 
        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");
-               }
+               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);
+                       ERROR("Failed to execute clone hook for \"%s\"", c->name);
                        goto out;
                }
        }
@@ -2597,23 +2663,72 @@ static bool container_destroy(struct lxc_container *c)
 
        mod_all_rdeps(c, false);
 
-       const char *p1 = do_lxcapi_get_config_path(c);
-       char *path = alloca(strlen(p1) + strlen(c->name) + 2);
-       sprintf(path, "%s/%s", p1, c->name);
+       p1 = do_lxcapi_get_config_path(c);
+       /* strlen(p1)
+        * +
+        * /
+        * +
+        * strlen(c->name)
+        * +
+        * /
+        * +
+        * strlen("config") = 6
+        * +
+        * \0
+        */
+       len = strlen(p1) + 1 + strlen(c->name) + 1 + 6 + 1;
+       path = malloc(len);
+       if (!path) {
+               ERROR("Failed to allocate memory");
+               goto out;
+       }
+
+       /* For an overlay container the rootfs is considered immutable and
+        * cannot be removed when restoring from a snapshot.
+        */
+       if (storage && (!strcmp(storage->type, "overlay") ||
+                       !strcmp(storage->type, "overlayfs")) &&
+           (storage->flags & LXC_STORAGE_INTERNAL_OVERLAY_RESTORE)) {
+               ret = snprintf(path, len, "%s/%s/config", p1, c->name);
+               if (ret < 0 || (size_t)ret >= len)
+                       goto out;
+
+               if (am_unpriv())
+                       ret = userns_exec_1(conf, lxc_unlink_exec_wrapper, path,
+                                           "lxc_unlink_exec_wrapper");
+               else
+                       ret = unlink(path);
+               if (ret < 0) {
+                       SYSERROR("Failed to destroy config file \"%s\" for \"%s\"",
+                                path, c->name);
+                       goto out;
+               }
+               INFO("Destroyed config file \"%s\" for \"%s\"", path, c->name);
+
+               bret = true;
+               goto out;
+       }
+
+       ret = snprintf(path, len, "%s/%s", p1, c->name);
+       if (ret < 0 || (size_t)ret >= len)
+               goto out;
        if (am_unpriv())
-               ret = userns_exec_1(conf, lxc_rmdir_onedev_wrapper, path,
-                                   "lxc_rmdir_onedev_wrapper");
+               ret = userns_exec_full(conf, lxc_rmdir_onedev_wrapper, path,
+                                      "lxc_rmdir_onedev_wrapper");
        else
                ret = lxc_rmdir_onedev(path, "snaps");
        if (ret < 0) {
-               ERROR("Error destroying container directory for %s", c->name);
+               ERROR("Failed to destroy directory \"%s\" for \"%s\"", path,
+                     c->name);
                goto out;
        }
-       INFO("Destroyed directory for %s", c->name);
+       INFO("Destroyed directory \"%s\" for \"%s\"", path, c->name);
 
        bret = true;
 
 out:
+       if (path)
+               free(path);
        container_disk_unlock(c);
        return bret;
 }
@@ -2632,7 +2747,7 @@ static bool do_lxcapi_destroy(struct lxc_container *c)
                return false;
        }
 
-       return container_destroy(c);
+       return container_destroy(c, NULL);
 }
 
 WRAP_API(bool, lxcapi_destroy)
@@ -2656,13 +2771,22 @@ static bool set_config_item_locked(struct lxc_container *c, const char *key, con
 
        if (!c->lxc_conf)
                c->lxc_conf = lxc_conf_init();
+
        if (!c->lxc_conf)
                return false;
-       config = lxc_getconfig(key);
+
+       config = lxc_get_config(key);
        if (!config)
                return false;
+
        if (config->set(key, v, c->lxc_conf, NULL) != 0)
                return false;
+
+       if (lxc_config_value_empty(v)) {
+               do_clear_unexp_config_line(c->lxc_conf, key);
+               return true;
+       }
+
        return do_append_unexp_config_line(c->lxc_conf, key, v);
 }
 
@@ -2861,7 +2985,7 @@ static int copy_file(const char *old, const char *new)
                if (len == 0)
                        break;
                ret = write(out, buf, len);
-               if (ret < len) { // should we retry?
+               if (ret < len) { /* should we retry? */
                        SYSERROR("Error: write to new file %s was interrupted", new);
                        goto err;
                }
@@ -2869,7 +2993,7 @@ static int copy_file(const char *old, const char *new)
        close(in);
        close(out);
 
-       // we set mode, but not owner/group
+       /* We set mode, but not owner/group. */
        ret = chmod(new, sbuf.st_mode);
        if (ret) {
                SYSERROR("Error setting mode on %s", new);
@@ -2901,13 +3025,13 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
                        char *hookname = it->elem;
                        char *fname = strrchr(hookname, '/');
                        char tmppath[MAXPATHLEN];
-                       if (!fname) // relative path - we don't support, but maybe we should
+                       if (!fname) /* relative path - we don't support, but maybe we should */
                                return 0;
                        if (strncmp(hookname, cpath, len - 1) != 0) {
-                               // this hook is public - ignore
+                               /* this hook is public - ignore */
                                continue;
                        }
-                       // copy the script, and change the entry in confile
+                       /* copy the script, and change the entry in confile */
                        ret = snprintf(tmppath, MAXPATHLEN, "%s/%s/%s",
                                        c->config_path, c->name, fname+1);
                        if (ret < 0 || ret >= MAXPATHLEN)
@@ -3020,7 +3144,7 @@ static bool add_rdepends(struct lxc_container *c, struct lxc_container *c0)
        if (!f)
                return false;
        bret = true;
-       // if anything goes wrong, just return an error
+       /* If anything goes wrong, just return an error. */
        if (fprintf(f, "%s\n%s\n", c0->config_path, c0->name) < 0)
                bret = false;
        if (fclose(f) != 0)
@@ -3058,14 +3182,14 @@ static int copy_storage(struct lxc_container *c0, struct lxc_container *c,
                        const char *newtype, int flags, const char *bdevdata,
                        uint64_t newsize)
 {
-       struct bdev *bdev;
-       int need_rdep;
+       struct lxc_storage *bdev;
+       bool 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);
+       bdev = storage_copy(c0, c->name, c->config_path, newtype, flags,
+                           bdevdata, newsize, &need_rdep);
        if (!bdev) {
                ERROR("Error copying storage.");
                return -1;
@@ -3074,7 +3198,7 @@ static int copy_storage(struct lxc_container *c0, struct lxc_container *c,
        /* Set new rootfs. */
        free(c->lxc_conf->rootfs.path);
        c->lxc_conf->rootfs.path = strdup(bdev->src);
-       bdev_put(bdev);
+       storage_put(bdev);
 
        if (!c->lxc_conf->rootfs.path) {
                ERROR("Out of memory while setting storage path.");
@@ -3127,7 +3251,7 @@ static int clone_update_rootfs(struct clone_update_data *data)
        char **hookargs = data->hookargs;
        int ret = -1;
        char path[MAXPATHLEN];
-       struct bdev *bdev;
+       struct lxc_storage *bdev;
        FILE *fout;
        struct lxc_conf *conf = c->lxc_conf;
 
@@ -3147,13 +3271,13 @@ static int clone_update_rootfs(struct clone_update_data *data)
 
        if (unshare(CLONE_NEWNS) < 0)
                return -1;
-       bdev = bdev_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
+       bdev = storage_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
        if (!bdev)
                return -1;
        if (strcmp(bdev->type, "dir") != 0) {
                if (unshare(CLONE_NEWNS) < 0) {
                        ERROR("error unsharing mounts");
-                       bdev_put(bdev);
+                       storage_put(bdev);
                        return -1;
                }
                if (detect_shared_rootfs()) {
@@ -3163,10 +3287,10 @@ static int clone_update_rootfs(struct clone_update_data *data)
                        }
                }
                if (bdev->ops->mount(bdev) < 0) {
-                       bdev_put(bdev);
+                       storage_put(bdev);
                        return -1;
                }
-       } else { // TODO come up with a better way
+       } else { /* TODO come up with a better way */
                free(bdev->dest);
                bdev->dest = strdup(bdev->src);
        }
@@ -3191,14 +3315,14 @@ static int clone_update_rootfs(struct clone_update_data *data)
 
                if (run_lxc_hooks(c->name, "clone", conf, c->get_config_path(c), hookargs)) {
                        ERROR("Error executing clone hook for %s", c->name);
-                       bdev_put(bdev);
+                       storage_put(bdev);
                        return -1;
                }
        }
 
        if (!(flags & LXC_CLONE_KEEPNAME)) {
                ret = snprintf(path, MAXPATHLEN, "%s/etc/hostname", bdev->dest);
-               bdev_put(bdev);
+               storage_put(bdev);
 
                if (ret < 0 || ret >= MAXPATHLEN)
                        return -1;
@@ -3214,9 +3338,9 @@ static int clone_update_rootfs(struct clone_update_data *data)
                }
                if (fclose(fout) < 0)
                        return -1;
+       } else {
+               storage_put(bdev);
        }
-       else
-               bdev_put(bdev);
 
        return 0;
 }
@@ -3232,8 +3356,8 @@ static int clone_update_rootfs_wrapper(void *data)
 sudo lxc-clone -o o1 -n n1 -s -L|-fssize fssize -v|--vgname vgname \
         -p|--lvprefix lvprefix -t|--fstype fstype  -B backingstore
 
--s [ implies overlayfs]
--s -B overlayfs
+-s [ implies overlay]
+-s -B overlay
 -s -B aufs
 
 only rootfs gets converted (copied/snapshotted) on clone.
@@ -3257,14 +3381,15 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                const char *bdevtype, const char *bdevdata, uint64_t newsize,
                char **hookargs)
 {
-       struct lxc_container *c2 = NULL;
        char newpath[MAXPATHLEN];
-       int ret, storage_copied = 0;
-       char *origroot = NULL, *saved_unexp_conf = NULL;
+       int ret;
        struct clone_update_data data;
        size_t saved_unexp_len;
        FILE *fout;
        pid_t pid;
+       int storage_copied = 0;
+       char *origroot = NULL, *saved_unexp_conf = NULL;
+       struct lxc_container *c2 = NULL;
 
        if (!c || !do_lxcapi_is_defined(c))
                return NULL;
@@ -3277,7 +3402,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                goto out;
        }
 
-       // Make sure the container doesn't yet exist.
+       /* Make sure the container doesn't yet exist. */
        if (!newname)
                newname = c->name;
        if (!lxcpath)
@@ -3287,6 +3412,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                SYSERROR("clone: failed making config pathname");
                goto out;
        }
+
        if (file_exists(newpath)) {
                ERROR("error: clone: %s exists", newpath);
                goto out;
@@ -3298,7 +3424,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                goto out;
        }
 
-       // copy the configuration, tweak it as needed,
+       /* Copy the configuration. Tweak it as needed. */
        if (c->lxc_conf->rootfs.path) {
                origroot = c->lxc_conf->rootfs.path;
                c->lxc_conf->rootfs.path = NULL;
@@ -3332,12 +3458,25 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
        saved_unexp_conf = NULL;
        c->lxc_conf->unexpanded_len = saved_unexp_len;
 
-       sprintf(newpath, "%s/%s/rootfs", lxcpath, newname);
-       if (mkdir(newpath, 0755) < 0) {
-               SYSERROR("error creating %s", newpath);
+       ret = snprintf(newpath, MAXPATHLEN, "%s/%s/rootfs", lxcpath, newname);
+       if (ret < 0 || ret >= MAXPATHLEN) {
+               SYSERROR("clone: failed making rootfs pathname");
                goto out;
        }
 
+       ret = mkdir(newpath, 0755);
+       if (ret < 0) {
+               /* For an overlay container the rootfs is considered immutable
+                * and will not have been removed when restoring from a
+                * snapshot.
+                */
+               if (errno != ENOENT &&
+                   !(flags & LXC_STORAGE_INTERNAL_OVERLAY_RESTORE)) {
+                       SYSERROR("Failed to create directory \"%s\"", newpath);
+                       goto out;
+               }
+       }
+
        if (am_unpriv()) {
                if (chown_mapped_root(newpath, c->lxc_conf) < 0) {
                        ERROR("Error chowning %s to container root", newpath);
@@ -3352,13 +3491,13 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                goto out;
        }
 
-       // copy/snapshot rootfs's
+       /* copy/snapshot rootfs's */
        ret = copy_storage(c, c2, bdevtype, flags, bdevdata, newsize);
        if (ret < 0)
                goto out;
 
 
-       // update utsname
+       /* update utsname */
        if (!(flags & LXC_CLONE_KEEPNAME)) {
                clear_unexp_config_line(c2->lxc_conf, "lxc.utsname", false);
                clear_unexp_config_line(c2->lxc_conf, "lxc.uts.name", false);
@@ -3369,7 +3508,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                }
        }
 
-       // copy hooks
+       /* copy hooks */
        ret = copyhooks(c, c2);
        if (ret < 0) {
                ERROR("error copying hooks");
@@ -3381,7 +3520,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                goto out;
        }
 
-       // update macaddrs
+       /* update macaddrs */
        if (!(flags & LXC_CLONE_KEEPMACADDR)) {
                if (!network_new_hwaddrs(c2->lxc_conf)) {
                        ERROR("Error updating mac addresses");
@@ -3389,12 +3528,13 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                }
        }
 
-       // update absolute paths for overlay mount directories
+       /* Update absolute paths for overlay mount directories. */
        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
-       // fail after this
+       /* We've now successfully created c2's storage, so clear it out if we
+        * fail after this.
+        */
        storage_copied = 1;
 
        if (!c2->save_config(c2, NULL))
@@ -3416,8 +3556,8 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
        data.flags = flags;
        data.hookargs = hookargs;
        if (am_unpriv())
-               ret = userns_exec_1(c->lxc_conf, clone_update_rootfs_wrapper,
-                                   &data, "clone_update_rootfs_wrapper");
+               ret = userns_exec_full(c->lxc_conf, clone_update_rootfs_wrapper,
+                                      &data, "clone_update_rootfs_wrapper");
        else
                ret = clone_update_rootfs(&data);
        if (ret < 0)
@@ -3452,7 +3592,7 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n
 
 static bool do_lxcapi_rename(struct lxc_container *c, const char *newname)
 {
-       struct bdev *bdev;
+       struct lxc_storage *bdev;
        struct lxc_container *newc;
 
        if (!c || !c->name || !c->config_path || !c->lxc_conf)
@@ -3462,14 +3602,14 @@ static bool do_lxcapi_rename(struct lxc_container *c, const char *newname)
                ERROR("Renaming a container with snapshots is not supported");
                return false;
        }
-       bdev = bdev_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
+       bdev = storage_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
        if (!bdev) {
                ERROR("Failed to find original backing store type");
                return false;
        }
 
        newc = lxcapi_clone(c, newname, c->config_path, LXC_CLONE_KEEPMACADDR, NULL, bdev->type, 0, NULL);
-       bdev_put(bdev);
+       storage_put(bdev);
        if (!newc) {
                lxc_container_put(newc);
                return false;
@@ -3478,7 +3618,7 @@ static bool do_lxcapi_rename(struct lxc_container *c, const char *newname)
        if (newc && lxcapi_is_defined(newc))
                lxc_container_put(newc);
 
-       if (!container_destroy(c)) {
+       if (!container_destroy(c, NULL)) {
                ERROR("Could not destroy existing container %s", c->name);
                return false;
        }
@@ -3581,7 +3721,7 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
        if (!c || !lxcapi_is_defined(c))
                return -1;
 
-       if (!bdev_can_backup(c->lxc_conf)) {
+       if (!storage_can_backup(c->lxc_conf)) {
                ERROR("%s's backing store cannot be backed up.", c->name);
                ERROR("Your container must use another backing store type.");
                return -1;
@@ -3607,10 +3747,10 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
         */
        flags = LXC_CLONE_SNAPSHOT | LXC_CLONE_KEEPMACADDR | LXC_CLONE_KEEPNAME |
                LXC_CLONE_KEEPBDEVTYPE | LXC_CLONE_MAYBE_SNAPSHOT;
-       if (bdev_is_dir(c->lxc_conf, c->lxc_conf->rootfs.path)) {
+       if (storage_is_dir(c->lxc_conf, c->lxc_conf->rootfs.path)) {
                ERROR("Snapshot of directory-backed container requested.");
                ERROR("Making a copy-clone.  If you do want snapshots, then");
-               ERROR("please create an aufs or overlayfs clone first, snapshot that");
+               ERROR("please create an aufs or overlay clone first, snapshot that");
                ERROR("and keep the original container pristine.");
                flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT;
        }
@@ -3622,7 +3762,7 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
 
        lxc_container_put(c2);
 
-       // Now write down the creation time
+       /* Now write down the creation time. */
        time_t timer;
        char buffer[25];
        struct tm* tm_info;
@@ -3652,7 +3792,7 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
        }
 
        if (commentfile) {
-               // $p / $name / comment \0
+               /* $p / $name / comment \0 */
                int len = strlen(snappath) + strlen(newname) + 10;
                char *path = alloca(len);
                sprintf(path, "%s/%s/comment", snappath, newname);
@@ -3674,7 +3814,7 @@ static void lxcsnap_free(struct lxc_snapshot *s)
 
 static char *get_snapcomment_path(char* snappath, char *name)
 {
-       // $snappath/$name/comment
+       /* $snappath/$name/comment */
        int ret, len = strlen(snappath) + strlen(name) + 10;
        char *s = malloc(len);
 
@@ -3801,7 +3941,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
        char clonelxcpath[MAXPATHLEN];
        int flags = 0;
        struct lxc_container *snap, *rest;
-       struct bdev *bdev;
+       struct lxc_storage *bdev;
        bool b = false;
 
        if (!c || !c->name || !c->config_path)
@@ -3812,47 +3952,61 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
                return false;
        }
 
-       bdev = bdev_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
+       bdev = storage_init(c->lxc_conf, c->lxc_conf->rootfs.path,
+                           c->lxc_conf->rootfs.mount, NULL);
        if (!bdev) {
                ERROR("Failed to find original backing store type");
                return false;
        }
 
+       /* For an overlay container the rootfs is considered immutable
+        * and cannot be removed when restoring from a snapshot. We pass this
+        * internal flag along to communicate this to various parts of the
+        * codebase.
+        */
+       if (!strcmp(bdev->type, "overlay") || !strcmp(bdev->type, "overlayfs"))
+               bdev->flags |= LXC_STORAGE_INTERNAL_OVERLAY_RESTORE;
+
        if (!newname)
                newname = c->name;
 
        if (!get_snappath_dir(c, clonelxcpath)) {
-               bdev_put(bdev);
+               storage_put(bdev);
                return false;
        }
-       // how should we lock this?
+       /* how should we lock this? */
 
        snap = lxc_container_new(snapname, clonelxcpath);
        if (!snap || !lxcapi_is_defined(snap)) {
                ERROR("Could not open snapshot %s", snapname);
-               if (snap) lxc_container_put(snap);
-               bdev_put(bdev);
+               if (snap)
+                       lxc_container_put(snap);
+               storage_put(bdev);
                return false;
        }
 
-       if (strcmp(c->name, newname) == 0) {
-               if (!container_destroy(c)) {
+       if (!strcmp(c->name, newname)) {
+               if (!container_destroy(c, bdev)) {
                        ERROR("Could not destroy existing container %s", newname);
                        lxc_container_put(snap);
-                       bdev_put(bdev);
+                       storage_put(bdev);
                        return false;
                }
        }
 
        if (strcmp(bdev->type, "dir") != 0 && strcmp(bdev->type, "loop") != 0)
                flags = LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT;
+
+       if (!strcmp(bdev->type, "overlay") || !strcmp(bdev->type, "overlayfs"))
+               flags |= LXC_STORAGE_INTERNAL_OVERLAY_RESTORE;
        rest = lxcapi_clone(snap, newname, c->config_path, flags,
                        bdev->type, NULL, 0, NULL);
-       bdev_put(bdev);
+       storage_put(bdev);
        if (rest && lxcapi_is_defined(rest))
                b = true;
        if (rest)
                lxc_container_put(rest);
+
        lxc_container_put(snap);
        return b;
 }
@@ -4136,7 +4290,7 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c, const char *ifna
                return false;
        }
 
-       if (pid == 0) { // child
+       if (pid == 0) { /* child */
                int ret = 0;
                if (!enter_net_ns(c)) {
                        ERROR("failed to enter namespace");
@@ -4353,13 +4507,13 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
 
        if (ongoing_create(c) == 2) {
                ERROR("Error: %s creation was not completed", c->name);
-               container_destroy(c);
+               container_destroy(c, NULL);
                lxcapi_clear_config(c);
        }
        c->daemonize = true;
        c->pidfile = NULL;
 
-       // assign the member functions
+       /* Assign the member functions. */
        c->is_defined = lxcapi_is_defined;
        c->state = lxcapi_state;
        c->is_running = lxcapi_is_running;
@@ -4460,7 +4614,7 @@ int list_defined_containers(const char *lxcpath, char ***names, struct lxc_conta
                if (!direntp)
                        break;
 
-               // Ignore '.', '..' and any hidden directory
+               /* Ignore '.', '..' and any hidden directory. */
                if (!strncmp(direntp->d_name, ".", 1))
                        continue;
 
@@ -4569,7 +4723,7 @@ int list_active_containers(const char *lxcpath, char ***nret,
                while (*p == '/')
                        p++;
 
-               // Now p is the start of lxc_name
+               /* Now p is the start of lxc_name. */
                p2 = strchr(p, '/');
                if (!p2 || strncmp(p2, "/command", 8) != 0)
                        continue;
@@ -4734,5 +4888,5 @@ free_ct_name:
 
 bool lxc_config_item_is_supported(const char *key)
 {
-       return !!lxc_getconfig(key);
+       return !!lxc_get_config(key);
 }
index fe8e73811453afa16d8ced2d0b5b98416deb35d7..3aee440e4ec788d0e22da40144c44eae4758d2a6 100644 (file)
@@ -59,7 +59,7 @@ struct migrate_opts;
  * changes, whenever possible stick to simply appending new members.
  */
 struct lxc_container {
-       // private fields
+       /* private fields */
        /*!
         * \private
         * Name of container.
@@ -105,7 +105,7 @@ struct lxc_container {
         */
        struct lxc_conf *lxc_conf;
 
-       // public fields
+       /* public fields */
        /*! Human-readable string representing last error */
        char *error_string;
 
index 1f6b8438bd38e9470310611faa699340b0a95cf8..c85a8461ca5c3665ca842cff321f423851377ffe 100644 (file)
@@ -54,7 +54,7 @@ static inline void dump_stacktrace(void)
        size = backtrace(array, MAX_STACKDEPTH);
        strings = backtrace_symbols(array, size);
 
-       // Using fprintf here as our logging module is not thread safe
+       /* Using fprintf here as our logging module is not thread safe. */
        fprintf(stderr, "\tObtained %zu stack frames.\n", size);
 
        for (i = 0; i < size; i++)
index e097216eeae801d8153ff3cae4f9c81ef318a86b..64975dbdf535b969cde71224f80786f312439ffe 100644 (file)
 #define LXC_LOCK_ANON_SEM 1 /*!< Anonymous semaphore lock */
 #define LXC_LOCK_FLOCK    2 /*!< flock(2) lock */
 
-// private
+/* private */
 /*!
  * LXC Lock
 */
 struct lxc_lock {
-       short type; //!< Lock type
+       short type; /*!< Lock type */
 
        union {
-               sem_t *sem; //!< Anonymous semaphore (LXC_LOCK_ANON_SEM)
+               sem_t *sem; /*!< Anonymous semaphore (LXC_LOCK_ANON_SEM) */
                /*! LXC_LOCK_FLOCK details */
                struct {
-                       int   fd; //!< fd on which a lock is held (if not -1)
-                       char *fname; //!< Name of lock
+                       int   fd; /*!< fd on which a lock is held (if not -1) */
+                       char *fname; /*!< Name of lock */
                } f;
-       } u; //!< Container for lock type elements
+       } u; /*!< Container for lock type elements */
 };
 
 /*!
diff --git a/src/lxc/lxcutmp.c b/src/lxc/lxcutmp.c
deleted file mode 100644 (file)
index ba65654..0000000
+++ /dev/null
@@ -1,489 +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
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/inotify.h>
-#include <sys/ioctl.h>
-#ifdef HAVE_SYS_TIMERFD_H
-#include <sys/timerfd.h>
-#else
-#include <sys/syscall.h>
-#ifndef TFD_NONBLOCK
-#define TFD_NONBLOCK O_NONBLOCK
-#endif
-
-#ifndef TFD_CLOEXEC
-#define TFD_CLOEXEC O_CLOEXEC
-#endif
-static int timerfd_create (clockid_t __clock_id, int __flags) {
-       return syscall(__NR_timerfd_create, __clock_id, __flags);
-}
-
-static int timerfd_settime (int __ufd, int __flags,
-                           const struct itimerspec *__utmr,
-                           struct itimerspec *__otmr) {
-
-       return syscall(__NR_timerfd_settime, __ufd, __flags,
-                           __utmr, __otmr);
-}
-
-#endif
-
-#include "conf.h"
-#include "cgroup.h"
-#include "start.h"
-#include "mainloop.h"
-#include "lxc.h"
-#include "log.h"
-
-#ifndef __USE_GNU
-#define __USE_GNU
-#endif
-#ifdef HAVE_UTMPX_H
-#include <utmpx.h>
-#ifndef HAVE_UTMPXNAME
-#include <utmp.h>
-#endif
-
-#else
-#include <utmp.h>
-
-#ifndef RUN_LVL
-#define RUN_LVL 1
-#endif
-
-static void setutxent(void) {
-       return setutent();
-}
-
-static struct utmp * getutxent (void) {
-       return (struct utmp *) getutent();
-}
-
-static void endutxent (void) {
-#ifdef IS_BIONIC
-       /* bionic isn't exporting endutend */
-       return;
-#else
-       return endutent();
-#endif
-}
-#endif
-
-#ifndef HAVE_UTMPXNAME
-static int utmpxname(const char *file) {
-       int result;
-       result = utmpname(file);
-
-#ifdef IS_BIONIC
-       /* Yeah bionic is that weird */
-       result = result - 1;
-#endif
-
-       return result;
-}
-#endif
-
-#undef __USE_GNU
-
-/* This file watches the /var/run/utmp file in the container
- * (that should probably be configurable)
- * We use inotify to put a watch on the /var/run directory for
- * create and modify events. These can trigger a read of the
- * utmp file looking for runlevel changes. If a runlevel change
- * to reboot or halt states is detected, we set up an itimer to
- * regularly check for the container shutdown, and reboot or halt
- * as appropriate when we get down to 1 task remaining.
- */
-
-lxc_log_define(lxc_utmp, lxc);
-
-struct lxc_utmp {
-       struct lxc_handler *handler;
-#define CONTAINER_STARTING  0
-#define CONTAINER_REBOOTING 1
-#define CONTAINER_HALTING   2
-#define CONTAINER_RUNNING   4
-       char container_state;
-       int timer_fd;
-       int prev_runlevel, curr_runlevel;
-};
-
-typedef void (*lxc_mainloop_timer_t) (void *data);
-
-static int utmp_get_runlevel(struct lxc_utmp *utmp_data);
-static int utmp_get_ntasks(struct lxc_handler *handler);
-static int utmp_shutdown_handler(int fd, uint32_t events, void *data,
-                                struct lxc_epoll_descr *descr);
-static int lxc_utmp_add_timer(struct lxc_epoll_descr *descr,
-                             lxc_mainloop_callback_t callback, void *data);
-static int lxc_utmp_del_timer(struct lxc_epoll_descr *descr,
-                             struct lxc_utmp *utmp_data);
-
-static int utmp_handler(int fd, uint32_t events, void *data,
-                       struct lxc_epoll_descr *descr)
-{
-       struct inotify_event *ie;
-       int size, ret, length;
-
-       struct lxc_utmp *utmp_data = (struct lxc_utmp *)data;
-
-       /*
-        * we're monitoring a directory. ie->name is not included in
-        * sizeof(struct inotify_event) if we don't read it all at once,
-        * read gives us EINVAL, so we read and cast to struct ie
-        */
-       char buffer[MAXPATHLEN];
-
-       if (ioctl(fd, FIONREAD, &size) < 0) {
-               SYSERROR("cannot determine the size of this notification");
-               return -1;
-       }
-
-       if (read(fd, buffer, size) < size) {
-               SYSERROR("failed to read notification");
-               return -1;
-       }
-
-       ie = (struct inotify_event *)buffer;
-
-       if (ie->len <= 0) {
-
-               if (ie->mask & IN_UNMOUNT) {
-                       DEBUG("watched directory removed");
-                       goto out;
-               }
-
-               SYSERROR("inotify event with no name (mask %d)", ie->mask);
-               return -1;
-       }
-
-       ret = 0;
-
-       DEBUG("got inotify event %d for %s", ie->mask, ie->name);
-
-       length = (4 < ie->len) ? 4 : ie->len;
-
-       /* only care about utmp */
-
-       if (strncmp(ie->name, "utmp", length))
-               return 0;
-
-       if (ie->mask & (IN_MODIFY | IN_CREATE))
-               ret = utmp_get_runlevel(utmp_data);
-
-       if (ret < 0)
-               goto out;
-
-       /* container halting, from running or starting state */
-       if (utmp_data->curr_runlevel == '0'
-           && ((utmp_data->container_state == CONTAINER_RUNNING)
-               || (utmp_data->container_state == CONTAINER_STARTING))) {
-               utmp_data->container_state = CONTAINER_HALTING;
-               if (utmp_data->timer_fd == -1)
-                       lxc_utmp_add_timer(descr, utmp_shutdown_handler, data);
-               DEBUG("Container halting");
-               goto out;
-       }
-
-       /* container rebooting, from running or starting state */
-       if (utmp_data->curr_runlevel == '6'
-           && ((utmp_data->container_state == CONTAINER_RUNNING)
-               || (utmp_data->container_state == CONTAINER_STARTING))) {
-               utmp_data->container_state = CONTAINER_REBOOTING;
-               if (utmp_data->timer_fd == -1)
-                       lxc_utmp_add_timer(descr, utmp_shutdown_handler, data);
-               DEBUG("Container rebooting");
-               goto out;
-       }
-
-       /* normal operation, running, from starting state. */
-       if (utmp_data->curr_runlevel > '0' && utmp_data->curr_runlevel < '6') {
-               utmp_data->container_state = CONTAINER_RUNNING;
-               if (utmp_data->timer_fd > 0)
-                       lxc_utmp_del_timer(descr, utmp_data);
-               DEBUG("Container running");
-               goto out;
-       }
-
-out:
-       return 0;
-}
-
-static int utmp_get_runlevel(struct lxc_utmp *utmp_data)
-{
-       #if HAVE_UTMPX_H
-       struct utmpx *utmpx;
-       #else
-       struct utmp *utmpx;
-       #endif
-       char path[MAXPATHLEN];
-       struct lxc_handler *handler = utmp_data->handler;
-
-       if (snprintf(path, MAXPATHLEN, "/proc/%d/root/run/utmp",
-                    handler->pid) > MAXPATHLEN) {
-               ERROR("path is too long");
-               return -1;
-       }
-
-       if (!access(path, F_OK) && !utmpxname(path))
-               goto utmp_ok;
-
-       if (snprintf(path, MAXPATHLEN, "/proc/%d/root/var/run/utmp",
-                    handler->pid) > MAXPATHLEN) {
-               ERROR("path is too long");
-               return -1;
-       }
-
-       if (utmpxname(path)) {
-               SYSERROR("failed to 'utmpxname'");
-               return -1;
-       }
-
-utmp_ok:
-
-       setutxent();
-
-       while ((utmpx = getutxent())) {
-
-               if (utmpx->ut_type == RUN_LVL) {
-                       utmp_data->prev_runlevel = utmpx->ut_pid / 256;
-                       utmp_data->curr_runlevel = utmpx->ut_pid % 256;
-                       DEBUG("utmp handler - run level is %c/%c",
-                             utmp_data->prev_runlevel,
-                             utmp_data->curr_runlevel);
-               }
-       }
-
-       endutxent();
-
-       return 0;
-}
-
-static int utmp_get_ntasks(struct lxc_handler *handler)
-{
-       int ntasks;
-
-       ntasks = cgroup_nrtasks(handler);
-
-       if (ntasks < 0) {
-               ERROR("failed to get the number of tasks");
-               return -1;
-       }
-
-       DEBUG("there are %d tasks running", ntasks);
-
-       return ntasks;
-}
-
-int lxc_utmp_mainloop_add(struct lxc_epoll_descr *descr,
-                         struct lxc_handler *handler)
-{
-       char path[MAXPATHLEN];
-       char path2[MAXPATHLEN];
-       int fd, wd;
-       struct lxc_utmp *utmp_data;
-
-       /* We set up a watch for the /var/run directory. We're only interested
-        * in utmp at the moment, but want to watch for delete and create
-        * events as well.
-        */
-       if (snprintf(path, MAXPATHLEN, "/proc/%d/root/run",
-                    handler->pid) > MAXPATHLEN) {
-               ERROR("path is too long");
-               return -1;
-       }
-       if (snprintf(path2, MAXPATHLEN, "/proc/%d/root/run/utmp",
-                    handler->pid) > MAXPATHLEN) {
-               ERROR("path is too long");
-               return -1;
-       }
-       if (!access(path2, F_OK))
-               goto run_ok;
-
-       if (snprintf(path, MAXPATHLEN, "/proc/%d/root/var/run",
-                    handler->pid) > MAXPATHLEN) {
-               ERROR("path is too long");
-               return -1;
-       }
-
-       if (access(path, F_OK)) {
-               WARN("'%s' not found", path);
-               return 0;
-       }
-
-run_ok:
-
-       utmp_data = (struct lxc_utmp *)malloc(sizeof(struct lxc_utmp));
-
-       if (NULL == utmp_data) {
-               SYSERROR("failed to malloc handler utmp_data");
-               return -1;
-       }
-
-       memset(utmp_data, 0, sizeof(struct lxc_utmp));
-
-       fd = inotify_init();
-       if (fd < 0) {
-               SYSERROR("failed to inotify_init");
-               goto out;
-       }
-
-       if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
-               SYSERROR("failed to set inotify fd to close-on-exec");
-               goto out_close;
-
-       }
-
-       wd = inotify_add_watch(fd, path, IN_MODIFY | IN_CREATE);
-       if (wd < 0) {
-               SYSERROR("failed to add watch for '%s'", path);
-               goto out_close;
-       }
-
-       utmp_data->handler = handler;
-       utmp_data->container_state = CONTAINER_STARTING;
-       utmp_data->timer_fd = -1;
-       utmp_data->prev_runlevel = 'N';
-       utmp_data->curr_runlevel = 'N';
-
-       if (lxc_mainloop_add_handler
-           (descr, fd, utmp_handler, (void *)utmp_data)) {
-               SYSERROR("failed to add mainloop");
-               goto out_close;
-       }
-
-       DEBUG("Added '%s' to inotifywatch", path);
-
-       return 0;
-out_close:
-       close(fd);
-out:
-       free(utmp_data);
-       return -1;
-}
-
-static int utmp_shutdown_handler(int fd, uint32_t events, void *data,
-                                struct lxc_epoll_descr *descr)
-{
-       int ntasks;
-       ssize_t nread;
-       struct lxc_utmp *utmp_data = (struct lxc_utmp *)data;
-       struct lxc_handler *handler = utmp_data->handler;
-       struct lxc_conf *conf = handler->conf;
-       uint64_t expirations;
-
-       /* read and clear notifications */
-       nread = read(fd, &expirations, sizeof(expirations));
-       if (nread < 0)
-               SYSERROR("Failed to read timer notification");
-
-       ntasks = utmp_get_ntasks(handler);
-
-       if (ntasks == 1 && (utmp_data->container_state == CONTAINER_HALTING)) {
-               INFO("container has shutdown");
-               /* shutdown timer */
-               lxc_utmp_del_timer(descr, utmp_data);
-
-               kill(handler->pid, SIGKILL);
-       }
-
-       if (ntasks == 1 && (utmp_data->container_state == CONTAINER_REBOOTING)) {
-               INFO("container has rebooted");
-               conf->reboot = 1;
-               /* shutdown timer */
-               lxc_utmp_del_timer(descr, utmp_data);
-               /* this seems a bit rough. */
-               kill(handler->pid, SIGKILL);
-       }
-       return 0;
-
-}
-
-int lxc_utmp_add_timer(struct lxc_epoll_descr *descr,
-                      lxc_mainloop_callback_t callback, void *data)
-{
-       int fd, result;
-       struct itimerspec timeout;
-       struct lxc_utmp *utmp_data = (struct lxc_utmp *)data;
-
-       fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
-       if (fd < 0) {
-               SYSERROR("failed to create timer");
-               return -1;
-       }
-
-       DEBUG("Setting up utmp shutdown timer");
-
-       /* set a one second timeout. Repeated. */
-       timeout.it_value.tv_sec = 1;
-       timeout.it_value.tv_nsec = 0;
-
-       timeout.it_interval.tv_sec = 1;
-       timeout.it_interval.tv_nsec = 0;
-
-       result = timerfd_settime(fd, 0, &timeout, NULL);
-
-       if (result < 0) {
-               SYSERROR("timerfd_settime:");
-               return -1;
-       }
-
-       if (lxc_mainloop_add_handler(descr, fd, callback, utmp_data)) {
-               SYSERROR("failed to add utmp timer to mainloop");
-               close(fd);
-               return -1;
-       }
-
-       utmp_data->timer_fd = fd;
-
-       return 0;
-}
-
-int lxc_utmp_del_timer(struct lxc_epoll_descr *descr,
-                      struct lxc_utmp *utmp_data)
-{
-       int result;
-
-       DEBUG("Clearing utmp shutdown timer");
-
-       result = lxc_mainloop_del_handler(descr, utmp_data->timer_fd);
-       if (result < 0)
-               SYSERROR("failed to del utmp timer from mainloop");
-
-       /* shutdown timer_fd */
-       close(utmp_data->timer_fd);
-       utmp_data->timer_fd = -1;
-
-       if (result < 0)
-               return -1;
-       else
-               return 0;
-}
diff --git a/src/lxc/lxcutmp.h b/src/lxc/lxcutmp.h
deleted file mode 100644 (file)
index 062ecdf..0000000
+++ /dev/null
@@ -1,34 +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
- */
-
-#ifndef __LXC_LXCUTMP_H
-#define __LXC_LXCUTMP_H
-
-#include "config.h"
-
-struct lxc_handler;
-struct lxc_epoll_descr;
-
-int lxc_utmp_mainloop_add(struct lxc_epoll_descr *descr,
-                         struct lxc_handler *handler);
-#endif
index ba062e8d9e627a6c85e2c7c1e70a01a2f88aa457..166329a7c6d2484e7ee2e13edb44d0e5f77b32ee 100644 (file)
@@ -243,7 +243,6 @@ int lxc_monitor_open(const char *lxcpath)
                ERROR("Failed to connect to monitor socket: %s.", strerror(errno));
                goto on_error;
        }
-       ret = 0;
 
        return fd;
 
@@ -262,7 +261,7 @@ int lxc_monitor_read_fdset(struct pollfd *fds, nfds_t nfds, struct lxc_msg *msg,
        if (ret == -1)
                return -1;
        else if (ret == 0)
-               return -2;  // timed out
+               return -2;  /* timed out */
 
        /* Only read from the first ready fd, the others will remain ready for
         * when this routine is called again.
index 0295d5d41207748d66ee7ad27dba21d096321c6a..909b7e58b3a7dc0788314462e452090d4781696c 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
  */
+
 #define _GNU_SOURCE
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
-#undef _GNU_SOURCe
 #include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
 #include <string.h>
-#include <stdio.h>
-#include <ctype.h>
 #include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/inotify.h>
+#include <unistd.h>
 #include <arpa/inet.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/ethernet.h>
-#include <netinet/in.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 #include <linux/sockios.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
-#include "nl.h"
-#include "network.h"
+#include "af_unix.h"
 #include "conf.h"
+#include "config.h"
+#include "log.h"
+#include "network.h"
+#include "nl.h"
 #include "utils.h"
 
 #if HAVE_IFADDRS_H
 #endif
 
 #ifndef IFLA_LINKMODE
-#  define IFLA_LINKMODE 17
+#define IFLA_LINKMODE 17
 #endif
 
 #ifndef IFLA_LINKINFO
-#  define IFLA_LINKINFO 18
+#define IFLA_LINKINFO 18
 #endif
 
 #ifndef IFLA_NET_NS_PID
-#  define IFLA_NET_NS_PID 19
+#define IFLA_NET_NS_PID 19
 #endif
 
 #ifndef IFLA_INFO_KIND
-# define IFLA_INFO_KIND 1
+#define IFLA_INFO_KIND 1
 #endif
 
 #ifndef IFLA_VLAN_ID
-# define IFLA_VLAN_ID 1
+#define IFLA_VLAN_ID 1
 #endif
 
 #ifndef IFLA_INFO_DATA
-#  define IFLA_INFO_DATA 2
+#define IFLA_INFO_DATA 2
 #endif
 
 #ifndef VETH_INFO_PEER
-# define VETH_INFO_PEER 1
+#define VETH_INFO_PEER 1
 #endif
 
 #ifndef IFLA_MACVLAN_MODE
-# define IFLA_MACVLAN_MODE 1
+#define IFLA_MACVLAN_MODE 1
 #endif
 
+lxc_log_define(lxc_network, lxc);
+
+typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
+
+static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+       int bridge_index, err;
+       char *veth1, *veth2;
+       char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
+       unsigned int mtu = 0;
+
+       if (netdev->priv.veth_attr.pair[0] != '\0') {
+               veth1 = netdev->priv.veth_attr.pair;
+               if (handler->conf->reboot)
+                       lxc_netdev_delete_by_name(veth1);
+       } else {
+               err = snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
+               if (err < 0 || (size_t)err >= sizeof(veth1buf))
+                       return -1;
+
+               veth1 = lxc_mkifname(veth1buf);
+               if (!veth1)
+                       return -1;
+
+               /* store away for deconf */
+               memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
+       }
+
+       snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
+       veth2 = lxc_mkifname(veth2buf);
+       if (!veth2)
+               goto out_delete;
+
+       err = lxc_veth_create(veth1, veth2);
+       if (err) {
+               ERROR("Failed to create veth pair \"%s\" and \"%s\": %s", veth1,
+                     veth2, strerror(-err));
+               goto out_delete;
+       }
+
+       /* changing the high byte of the mac address to 0xfe, the bridge interface
+        * will always keep the host's mac address and not take the mac address
+        * of a container */
+       err = setup_private_host_hw_addr(veth1);
+       if (err) {
+               ERROR("Failed to change mac address of host interface \"%s\": %s",
+                     veth1, strerror(-err));
+               goto out_delete;
+       }
+
+       /* Retrieve ifindex of the host's veth device. */
+       netdev->priv.veth_attr.ifindex = if_nametoindex(veth1);
+       if (!netdev->priv.veth_attr.ifindex) {
+               ERROR("Failed to retrieve ifindex for \"%s\"", veth1);
+               goto out_delete;
+       }
+
+       /* Note that we're retrieving the container's ifindex in the host's
+        * network namespace because we need it to move the device from the
+        * host's network namespace to the container's network namespace later
+        * on.
+        */
+       netdev->ifindex = if_nametoindex(veth2);
+       if (!netdev->ifindex) {
+               ERROR("Failed to retrieve ifindex for \"%s\"", veth2);
+               goto out_delete;
+       }
+
+       if (netdev->mtu) {
+               if (lxc_safe_uint(netdev->mtu, &mtu) < 0)
+                       WARN("Failed to parse mtu");
+               else
+                       INFO("Retrieved mtu %d", mtu);
+       } else if (netdev->link[0] != '\0') {
+               bridge_index = if_nametoindex(netdev->link);
+               if (bridge_index) {
+                       mtu = netdev_get_mtu(bridge_index);
+                       INFO("Retrieved mtu %d from %s", mtu, netdev->link);
+               } else {
+                       mtu = netdev_get_mtu(netdev->ifindex);
+                       INFO("Retrieved mtu %d from %s", mtu, veth2);
+               }
+       }
+
+       if (mtu) {
+               err = lxc_netdev_set_mtu(veth1, mtu);
+               if (!err)
+                       err = lxc_netdev_set_mtu(veth2, mtu);
+               if (err) {
+                       ERROR("Failed to set mtu \"%d\" for veth pair \"%s\" "
+                             "and \"%s\": %s",
+                             mtu, veth1, veth2, strerror(-err));
+                       goto out_delete;
+               }
+       }
+
+       if (netdev->link[0] != '\0') {
+               err = lxc_bridge_attach(netdev->link, veth1);
+               if (err) {
+                       ERROR("Failed to attach \"%s\" to bridge \"%s\": %s",
+                             veth1, netdev->link, strerror(-err));
+                       goto out_delete;
+               }
+               INFO("Attached \"%s\" to bridge \"%s\"", veth1, netdev->link);
+       }
+
+       err = lxc_netdev_up(veth1);
+       if (err) {
+               ERROR("Failed to set \"%s\" up: %s", veth1, strerror(-err));
+               goto out_delete;
+       }
+
+       if (netdev->upscript) {
+               err = run_script(handler->name, "net", netdev->upscript, "up",
+                                "veth", veth1, (char*) NULL);
+               if (err)
+                       goto out_delete;
+       }
+
+       DEBUG("Instantiated veth \"%s/%s\", index is \"%d\"", veth1, veth2,
+             netdev->ifindex);
+
+       return 0;
+
+out_delete:
+       if (netdev->ifindex != 0)
+               lxc_netdev_delete_by_name(veth1);
+       return -1;
+}
+
+static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+       char peerbuf[IFNAMSIZ], *peer;
+       int err;
+
+       if (netdev->link[0] == '\0') {
+               ERROR("No link for macvlan network device specified");
+               return -1;
+       }
+
+       err = snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX");
+       if (err < 0 || (size_t)err >= sizeof(peerbuf))
+               return -1;
+
+       peer = lxc_mkifname(peerbuf);
+       if (!peer)
+               return -1;
+
+       err = lxc_macvlan_create(netdev->link, peer,
+                                netdev->priv.macvlan_attr.mode);
+       if (err) {
+               ERROR("Failed to create macvlan interface \"%s\" on \"%s\": %s",
+                     peer, netdev->link, strerror(-err));
+               goto on_error;
+       }
+
+       netdev->ifindex = if_nametoindex(peer);
+       if (!netdev->ifindex) {
+               ERROR("Failed to retrieve ifindex for \"%s\"", peer);
+               goto on_error;
+       }
+
+       if (netdev->upscript) {
+               err = run_script(handler->name, "net", netdev->upscript, "up",
+                                "macvlan", netdev->link, (char*) NULL);
+               if (err)
+                       goto on_error;
+       }
+
+       DEBUG("Instantiated macvlan \"%s\" with ifindex is %d and mode %d",
+             peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
+
+       return 0;
+
+on_error:
+       lxc_netdev_delete_by_name(peer);
+       return -1;
+}
+
+static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+       char peer[IFNAMSIZ];
+       int err;
+       static uint16_t vlan_cntr = 0;
+       unsigned int mtu = 0;
+
+       if (netdev->link[0] == '\0') {
+               ERROR("No link for vlan network device specified");
+               return -1;
+       }
+
+       err = snprintf(peer, sizeof(peer), "vlan%d-%d", netdev->priv.vlan_attr.vid, vlan_cntr++);
+       if (err < 0 || (size_t)err >= sizeof(peer))
+               return -1;
+
+       err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
+       if (err) {
+               ERROR("Failed to create vlan interface \"%s\" on \"%s\": %s",
+                     peer, netdev->link, strerror(-err));
+               return -1;
+       }
+
+       netdev->ifindex = if_nametoindex(peer);
+       if (!netdev->ifindex) {
+               ERROR("Failed to retrieve ifindex for \"%s\"", peer);
+               lxc_netdev_delete_by_name(peer);
+               return -1;
+       }
+
+       DEBUG("Instantiated vlan \"%s\" with ifindex is \"%d\" (vlan1000)",
+             peer, netdev->ifindex);
+       if (netdev->mtu) {
+               if (lxc_safe_uint(netdev->mtu, &mtu) < 0) {
+                       ERROR("Failed to retrieve mtu from \"%d\"/\"%s\".",
+                             netdev->ifindex,
+                             netdev->name[0] != '\0' ? netdev->name : "(null)");
+                       return -1;
+               }
+               err = lxc_netdev_set_mtu(peer, mtu);
+               if (err) {
+                       ERROR("Failed to set mtu \"%s\" for \"%s\": %s",
+                             netdev->mtu, peer, strerror(-err));
+                       lxc_netdev_delete_by_name(peer);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+       if (netdev->link[0] == '\0') {
+               ERROR("No link for physical interface specified");
+               return -1;
+       }
+
+       /* Note that we're retrieving the container's ifindex in the host's
+        * network namespace because we need it to move the device from the
+        * host's network namespace to the container's network namespace later
+        * on.
+        * Note that netdev->link will contain the name of the physical network
+        * device in the host's namespace.
+        */
+       netdev->ifindex = if_nametoindex(netdev->link);
+       if (!netdev->ifindex) {
+               ERROR("Failed to retrieve ifindex for \"%s\"", netdev->link);
+               return -1;
+       }
+
+       /* Store the ifindex of the host's network device in the host's
+        * namespace.
+        */
+       netdev->priv.phys_attr.ifindex = netdev->ifindex;
+
+       if (netdev->upscript) {
+               int err;
+               err = run_script(handler->name, "net", netdev->upscript,
+                                "up", "phys", netdev->link, (char*) NULL);
+               if (err)
+                       return -1;
+       }
+
+       return 0;
+}
+
+static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+       netdev->ifindex = 0;
+       if (netdev->upscript) {
+               int err;
+               err = run_script(handler->name, "net", netdev->upscript,
+                                "up", "empty", (char*) NULL);
+               if (err)
+                       return -1;
+       }
+       return 0;
+}
+
+static int instantiate_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+       netdev->ifindex = 0;
+       return 0;
+}
+
+static  instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
+       [LXC_NET_VETH]    = instantiate_veth,
+       [LXC_NET_MACVLAN] = instantiate_macvlan,
+       [LXC_NET_VLAN]    = instantiate_vlan,
+       [LXC_NET_PHYS]    = instantiate_phys,
+       [LXC_NET_EMPTY]   = instantiate_empty,
+       [LXC_NET_NONE]    = instantiate_none,
+};
+
+static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+       char *veth1;
+       int err;
+
+       if (netdev->priv.veth_attr.pair[0] != '\0')
+               veth1 = netdev->priv.veth_attr.pair;
+       else
+               veth1 = netdev->priv.veth_attr.veth1;
+
+       if (netdev->downscript) {
+               err = run_script(handler->name, "net", netdev->downscript,
+                                "down", "veth", veth1, (char*) NULL);
+               if (err)
+                       return -1;
+       }
+       return 0;
+}
+
+static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+       int err;
+
+       if (netdev->downscript) {
+               err = run_script(handler->name, "net", netdev->downscript,
+                                "down", "macvlan", netdev->link,
+                                (char*) NULL);
+               if (err)
+                       return -1;
+       }
+       return 0;
+}
+
+static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+       return 0;
+}
+
+static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+       int err;
+
+       if (netdev->downscript) {
+               err = run_script(handler->name, "net", netdev->downscript,
+                                "down", "phys", netdev->link, (char*) NULL);
+               if (err)
+                       return -1;
+       }
+       return 0;
+}
 
-int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname)
+static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
 {
+       int err;
+
+       if (netdev->downscript) {
+               err = run_script(handler->name, "net", netdev->downscript,
+                                "down", "empty", (char*) NULL);
+               if (err)
+                       return -1;
+       }
+       return 0;
+}
+
+static int shutdown_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
+{
+       return 0;
+}
+
+static  instantiate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
+       [LXC_NET_VETH]    = shutdown_veth,
+       [LXC_NET_MACVLAN] = shutdown_macvlan,
+       [LXC_NET_VLAN]    = shutdown_vlan,
+       [LXC_NET_PHYS]    = shutdown_phys,
+       [LXC_NET_EMPTY]   = shutdown_empty,
+       [LXC_NET_NONE]    = shutdown_none,
+};
+
+int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char *ifname)
+{
+       int err;
        struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL;
        struct ifinfomsg *ifi;
-       int err;
+       struct nlmsg *nlmsg = NULL;
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -106,7 +479,7 @@ int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname)
        if (!nlmsg)
                goto out;
 
-       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
@@ -130,50 +503,56 @@ out:
        return err;
 }
 
-/*
- * If we are asked to move a wireless interface, then
- * we must actually move its phyN device.  Detect
- * that condition and return the physname here.  The
- * physname will be passed to lxc_netdev_move_wlan()
- * which will free it when done
+/* If we are asked to move a wireless interface, then we must actually move its
+ * phyN device. Detect that condition and return the physname here. The physname
+ * will be passed to lxc_netdev_move_wlan() which will free it when done.
  */
 #define PHYSNAME "/sys/class/net/%s/phy80211/name"
-static char * is_wlan(const char *ifname)
+static char *is_wlan(const char *ifname)
 {
-       char *path, *physname = NULL;
-       size_t len = strlen(ifname) + strlen(PHYSNAME) - 1;
-       struct stat sb;
+       int i, ret;
        long physlen;
+       size_t len;
+       char *path;
        FILE *f;
-       int ret, i;
+       struct stat sb;
+       char *physname = NULL;
 
-       path = alloca(len+1);
+       len = strlen(ifname) + strlen(PHYSNAME) - 1;
+       path = alloca(len + 1);
        ret = snprintf(path, len, PHYSNAME, ifname);
-       if (ret < 0 || ret >= len)
+       if (ret < 0 || (size_t)ret >= len)
                goto bad;
+
        ret = stat(path, &sb);
        if (ret)
                goto bad;
-       if (!(f = fopen(path, "r")))
+
+       f = fopen(path, "r");
+       if (!f)
                goto bad;
-       // feh - sb.st_size is always 4096
+
+       /* Feh - sb.st_size is always 4096. */
        fseek(f, 0, SEEK_END);
        physlen = ftell(f);
        fseek(f, 0, SEEK_SET);
-       physname = malloc(physlen+1);
+
+       physname = malloc(physlen + 1);
        if (!physname) {
                fclose(f);
                goto bad;
        }
-       memset(physname, 0, physlen+1);
+
+       memset(physname, 0, physlen + 1);
        ret = fread(physname, 1, physlen, f);
        fclose(f);
        if (ret < 0)
                goto bad;
 
-       for (i = 0;  i < physlen; i++) {
+       for (i = 0; i < physlen; i++) {
                if (physname[i] == '\n')
                        physname[i] = '\0';
+
                if (physname[i] == '\0')
                        break;
        }
@@ -185,30 +564,34 @@ bad:
        return NULL;
 }
 
-static int
-lxc_netdev_rename_by_name_in_netns(pid_t pid, const char *old, const char *new)
+static int lxc_netdev_rename_by_name_in_netns(pid_t pid, const char *old,
+                                             const char *new)
 {
-       pid_t fpid = fork();
+       pid_t fpid;
 
+       fpid = fork();
        if (fpid < 0)
                return -1;
+
        if (fpid != 0)
                return wait_for_pid(fpid);
+
        if (!switch_to_ns(pid, "net"))
                return -1;
+
        exit(lxc_netdev_rename_by_name(old, new));
 }
 
-static int
-lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid, const char* newname)
+static int lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid,
+                               const char *newname)
 {
-       int err = -1;
-       pid_t fpid;
        char *cmd;
+       pid_t fpid;
+       int err = -1;
 
        /* Move phyN into the container.  TODO - do this using netlink.
-        * However, IIUC this involves a bit more complicated work to
-        * talk to the 80211 module, so for now just call out to iw
+        * However, IIUC this involves a bit more complicated work to talk to
+        * the 80211 module, so for now just call out to iw.
         */
        cmd = on_path("iw", NULL);
        if (!cmd)
@@ -218,13 +601,15 @@ lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid, const char*
        fpid = fork();
        if (fpid < 0)
                goto out1;
+
        if (fpid == 0) {
                char pidstr[30];
                sprintf(pidstr, "%d", pid);
-               if (execlp("iw", "iw", "phy", physname, "set", "netns", pidstr, (char *)NULL))
-                       exit(1);
-               exit(0); // notreached
+               execlp("iw", "iw", "phy", physname, "set", "netns", pidstr,
+                      (char *)NULL);
+               exit(EXIT_FAILURE);
        }
+
        if (wait_for_pid(fpid))
                goto out1;
 
@@ -249,7 +634,8 @@ int lxc_netdev_move_by_name(const char *ifname, pid_t pid, const char* newname)
        if (!index)
                return -EINVAL;
 
-       if ((physname = is_wlan(ifname)))
+       physname = is_wlan(ifname);
+       if (physname)
                return lxc_netdev_move_wlan(physname, ifname, pid, newname);
 
        return lxc_netdev_move_by_index(index, pid, newname);
@@ -257,10 +643,10 @@ int lxc_netdev_move_by_name(const char *ifname, pid_t pid, const char* newname)
 
 int lxc_netdev_delete_by_index(int ifindex)
 {
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
-       struct ifinfomsg *ifi;
        int err;
+       struct ifinfomsg *ifi;
+       struct nl_handler nlh;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -275,7 +661,7 @@ int lxc_netdev_delete_by_index(int ifindex)
        if (!answer)
                goto out;
 
-       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
+       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST;
        nlmsg->nlmsghdr->nlmsg_type = RTM_DELLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
@@ -305,10 +691,10 @@ int lxc_netdev_delete_by_name(const char *name)
 
 int lxc_netdev_rename_by_index(int ifindex, const char *newname)
 {
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       int err, len;
        struct ifinfomsg *ifi;
-       int len, err;
+       struct nl_handler nlh;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -327,7 +713,7 @@ int lxc_netdev_rename_by_index(int ifindex, const char *newname)
        if (!answer)
                goto out;
 
-       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
+       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST;
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
@@ -364,10 +750,10 @@ int lxc_netdev_rename_by_name(const char *oldname, const char *newname)
 
 int netdev_set_flag(const char *name, int flag)
 {
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       int err, index, len;
        struct ifinfomsg *ifi;
-       int index, len, err;
+       struct nl_handler nlh;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -392,7 +778,7 @@ int netdev_set_flag(const char *name, int flag)
        if (!index)
                goto out;
 
-       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
@@ -413,12 +799,12 @@ out:
        return err;
 }
 
-int netdev_get_flag(const charname, int *flag)
+int netdev_get_flag(const char *name, int *flag)
 {
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       int err, index, len;
        struct ifinfomsg *ifi;
-       int index, len, err;
+       struct nl_handler nlh;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
        if (!name)
                return -EINVAL;
@@ -481,30 +867,28 @@ out:
  * 1 means interface is up.
  * Others means error happened, and ret-value is the error number.
  */
-int lxc_netdev_isup(const charname)
+int lxc_netdev_isup(const char *name)
 {
-       int flag;
-       int err;
+       int err, flag;
 
        err = netdev_get_flag(name, &flag);
        if (err)
-               goto out;
+               return err;
+
        if (flag & IFF_UP)
                return 1;
+
        return 0;
-out:
-       return err;
 }
 
 int netdev_get_mtu(int ifindex)
 {
+       int answer_len, err, res;
        struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
        struct ifinfomsg *ifi;
        struct nlmsghdr *msg;
-       int err, res;
-       int recv_len = 0, answer_len;
-       int readmore = 0;
+       int readmore = 0, recv_len = 0;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -521,10 +905,11 @@ int netdev_get_mtu(int ifindex)
 
        /* Save the answer buffer length, since it will be overwritten
         * on the first receive (and we might need to receive more than
-        * once. */
+        * once.
+        */
        answer_len = answer->nlmsghdr->nlmsg_len;
 
-       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
        nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
@@ -540,7 +925,8 @@ int netdev_get_mtu(int ifindex)
 
        do {
                /* Restore the answer buffer length, it might have been
-                * overwritten by a previous receive. */
+                * overwritten by a previous receive.
+                */
                answer->nlmsghdr->nlmsg_len = answer_len;
 
                /* Get the (next) batch of reply messages */
@@ -549,7 +935,6 @@ int netdev_get_mtu(int ifindex)
                        goto out;
 
                recv_len = err;
-               err = 0;
 
                /* Satisfy the typing for the netlink macros */
                msg = answer->nlmsghdr;
@@ -558,7 +943,8 @@ int netdev_get_mtu(int ifindex)
 
                        /* Stop reading if we see an error message */
                        if (msg->nlmsg_type == NLMSG_ERROR) {
-                               struct nlmsgerr *errmsg = (struct nlmsgerr*)NLMSG_DATA(msg);
+                               struct nlmsgerr *errmsg =
+                                   (struct nlmsgerr *)NLMSG_DATA(msg);
                                err = errmsg->error;
                                goto out;
                        }
@@ -572,32 +958,34 @@ int netdev_get_mtu(int ifindex)
                        ifi = NLMSG_DATA(msg);
                        if (ifi->ifi_index == ifindex) {
                                struct rtattr *rta = IFLA_RTA(ifi);
-                               int attr_len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
+                               int attr_len =
+                                   msg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
                                res = 0;
-                               while(RTA_OK(rta, attr_len)) {
-                                       /* Found a local address for the requested interface,
-                                        * return it. */
+                               while (RTA_OK(rta, attr_len)) {
+                                       /* Found a local address for the
+                                        * requested interface, return it.
+                                        */
                                        if (rta->rta_type == IFLA_MTU) {
-                                               memcpy(&res, RTA_DATA(rta), sizeof(int));
+                                               memcpy(&res, RTA_DATA(rta),
+                                                      sizeof(int));
                                                err = res;
                                                goto out;
                                        }
                                        rta = RTA_NEXT(rta, attr_len);
                                }
-
                        }
 
-                       /* Keep reading more data from the socket if the
-                        * last message had the NLF_F_MULTI flag set */
+                       /* Keep reading more data from the socket if the last
+                        * message had the NLF_F_MULTI flag set.
+                        */
                        readmore = (msg->nlmsg_flags & NLM_F_MULTI);
 
-                       /* Look at the next message received in this buffer */
+                       /* Look at the next message received in this buffer. */
                        msg = NLMSG_NEXT(msg, recv_len);
                }
        } while (readmore);
 
-       /* If we end up here, we didn't find any result, so signal an
-        * error */
+       /* If we end up here, we didn't find any result, so signal an error. */
        err = -1;
 
 out:
@@ -609,10 +997,10 @@ out:
 
 int lxc_netdev_set_mtu(const char *name, int mtu)
 {
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       int err, index, len;
        struct ifinfomsg *ifi;
-       int index, len, err;
+       struct nl_handler nlh;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -637,7 +1025,7 @@ int lxc_netdev_set_mtu(const char *name, int mtu)
        if (!index)
                goto out;
 
-       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
@@ -671,11 +1059,11 @@ int lxc_netdev_down(const char *name)
 
 int lxc_veth_create(const char *name1, const char *name2)
 {
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       int err, len;
        struct ifinfomsg *ifi;
+       struct nl_handler nlh;
        struct rtattr *nest1, *nest2, *nest3;
-       int len, err;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -700,7 +1088,7 @@ int lxc_veth_create(const char *name1, const char *name2)
                goto out;
 
        nlmsg->nlmsghdr->nlmsg_flags =
-               NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
+           NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
@@ -734,9 +1122,7 @@ int lxc_veth_create(const char *name1, const char *name2)
                goto out;
 
        nla_end_nested(nlmsg, nest3);
-
        nla_end_nested(nlmsg, nest2);
-
        nla_end_nested(nlmsg, nest1);
 
        if (nla_put_string(nlmsg, IFLA_IFNAME, name1))
@@ -750,14 +1136,14 @@ out:
        return err;
 }
 
-/* XXX: merge with lxc_macvlan_create */
+/* TODO: merge with lxc_macvlan_create */
 int lxc_vlan_create(const char *master, const char *name, unsigned short vlanid)
 {
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       int err, len, lindex;
        struct ifinfomsg *ifi;
+       struct nl_handler nlh;
        struct rtattr *nest, *nest2;
-       int lindex, len, err;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -787,7 +1173,7 @@ int lxc_vlan_create(const char *master, const char *name, unsigned short vlanid)
                goto err1;
 
        nlmsg->nlmsghdr->nlmsg_flags =
-               NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
+           NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
@@ -812,7 +1198,6 @@ int lxc_vlan_create(const char *master, const char *name, unsigned short vlanid)
                goto err1;
 
        nla_end_nested(nlmsg, nest2);
-
        nla_end_nested(nlmsg, nest);
 
        if (nla_put_u32(nlmsg, IFLA_LINK, lindex))
@@ -833,11 +1218,11 @@ err3:
 
 int lxc_macvlan_create(const char *master, const char *name, int mode)
 {
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       int err, index, len;
        struct ifinfomsg *ifi;
+       struct nl_handler nlh;
        struct rtattr *nest, *nest2;
-       int index, len, err;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -867,7 +1252,7 @@ int lxc_macvlan_create(const char *master, const char *name, int mode)
                goto out;
 
        nlmsg->nlmsghdr->nlmsg_flags =
-               NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
+           NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
 
        ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
@@ -913,7 +1298,8 @@ out:
 
 static int proc_sys_net_write(const char *path, const char *value)
 {
-       int fd, err = 0;
+       int fd;
+       int err = 0;
 
        fd = open(path, O_WRONLY);
        if (fd < 0)
@@ -928,18 +1314,18 @@ static int proc_sys_net_write(const char *path, const char *value)
 
 static int ip_forward_set(const char *ifname, int family, int flag)
 {
-       char path[MAXPATHLEN];
        int rc;
+       char path[MAXPATHLEN];
 
        if (family != AF_INET && family != AF_INET6)
                return -EINVAL;
 
        rc = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/forwarding",
-                family == AF_INET?"ipv4":"ipv6" , ifname);
-       if (rc >= MAXPATHLEN)
+                     family == AF_INET ? "ipv4" : "ipv6", ifname);
+       if (rc < 0 || (size_t)rc >= MAXPATHLEN)
                return -E2BIG;
 
-       return proc_sys_net_write(path, flag?"1":"0");
+       return proc_sys_net_write(path, flag ? "1" : "0");
 }
 
 int lxc_ip_forward_on(const char *ifname, int family)
@@ -954,19 +1340,19 @@ int lxc_ip_forward_off(const char *ifname, int family)
 
 static int neigh_proxy_set(const char *ifname, int family, int flag)
 {
-       char path[MAXPATHLEN];
        int ret;
+       char path[MAXPATHLEN];
 
        if (family != AF_INET && family != AF_INET6)
                return -EINVAL;
 
        ret = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/%s",
-               family == AF_INET?"ipv4":"ipv6" , ifname,
-               family == AF_INET?"proxy_arp":"proxy_ndp");
-       if (ret < 0 || ret >= MAXPATHLEN)
+                      family == AF_INET ? "ipv4" : "ipv6", ifname,
+                      family == AF_INET ? "proxy_arp" : "proxy_ndp");
+       if (ret < 0 || (size_t)ret >= MAXPATHLEN)
                return -E2BIG;
 
-       return proc_sys_net_write(path, flag?"1":"0");
+       return proc_sys_net_write(path, flag ? "1" : "0");
 }
 
 int lxc_neigh_proxy_on(const char *name, int family)
@@ -981,62 +1367,59 @@ int lxc_neigh_proxy_off(const char *name, int family)
 
 int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr)
 {
-       unsigned char *data;
-       char c;
        int i = 0;
        unsigned val;
+       char c;
+       unsigned char *data;
 
        sockaddr->sa_family = ARPHRD_ETHER;
        data = (unsigned char *)sockaddr->sa_data;
 
        while ((*macaddr != '\0') && (i < ETH_ALEN)) {
-           val = 0;
-           c = *macaddr++;
-           if (isdigit(c))
-                   val = c - '0';
-           else if (c >= 'a' && c <= 'f')
-                   val = c - 'a' + 10;
-           else if (c >= 'A' && c <= 'F')
-                   val = c - 'A' + 10;
-           else {
-                   return -EINVAL;
-           }
-           val <<= 4;
-           c = *macaddr;
-           if (isdigit(c))
-                   val |= c - '0';
-           else if (c >= 'a' && c <= 'f')
-                   val |= c - 'a' + 10;
-           else if (c >= 'A' && c <= 'F')
-                   val |= c - 'A' + 10;
-           else if (c == ':' || c == 0)
-                   val >>= 4;
-           else {
-                   return -EINVAL;
-           }
-           if (c != 0)
-                   macaddr++;
-           *data++ = (unsigned char) (val & 0377);
-           i++;
-
-           if (*macaddr == ':')
-                   macaddr++;
+               c = *macaddr++;
+               if (isdigit(c))
+                       val = c - '0';
+               else if (c >= 'a' && c <= 'f')
+                       val = c - 'a' + 10;
+               else if (c >= 'A' && c <= 'F')
+                       val = c - 'A' + 10;
+               else
+                       return -EINVAL;
+
+               val <<= 4;
+               c = *macaddr;
+               if (isdigit(c))
+                       val |= c - '0';
+               else if (c >= 'a' && c <= 'f')
+                       val |= c - 'a' + 10;
+               else if (c >= 'A' && c <= 'F')
+                       val |= c - 'A' + 10;
+               else if (c == ':' || c == 0)
+                       val >>= 4;
+               else
+                       return -EINVAL;
+               if (c != 0)
+                       macaddr++;
+               *data++ = (unsigned char)(val & 0377);
+               i++;
+
+               if (*macaddr == ':')
+                       macaddr++;
        }
 
        return 0;
 }
 
-static int ip_addr_add(int family, int ifindex,
-                      void *addr, void *bcast, void *acast, int prefix)
+static int ip_addr_add(int family, int ifindex, void *addr, void *bcast,
+                      void *acast, int prefix)
 {
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       int addrlen, err;
        struct ifaddrmsg *ifa;
-       int addrlen;
-       int err;
+       struct nl_handler nlh;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
-       addrlen = family == AF_INET ? sizeof(struct in_addr) :
-               sizeof(struct in6_addr);
+       addrlen = family == AF_INET ? sizeof(struct in_addr)
+                                   : sizeof(struct in6_addr);
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -1052,7 +1435,7 @@ static int ip_addr_add(int family, int ifindex,
                goto out;
 
        nlmsg->nlmsghdr->nlmsg_flags =
-               NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
+           NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
        nlmsg->nlmsghdr->nlmsg_type = RTM_NEWADDR;
 
        ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg));
@@ -1073,7 +1456,7 @@ static int ip_addr_add(int family, int ifindex,
        if (nla_put_buffer(nlmsg, IFA_BROADCAST, bcast, addrlen))
                goto out;
 
-       /* TODO : multicast, anycast with ipv6 */
+       /* TODO: multicast, anycast with ipv6 */
        err = -EPROTONOSUPPORT;
        if (family == AF_INET6 &&
            (memcmp(bcast, &in6addr_any, sizeof(in6addr_any)) ||
@@ -1089,48 +1472,52 @@ out:
 }
 
 int lxc_ipv6_addr_add(int ifindex, struct in6_addr *addr,
-                     struct in6_addr *mcast,
-                     struct in6_addr *acast, int prefix)
+                     struct in6_addr *mcast, struct in6_addr *acast,
+                     int prefix)
 {
        return ip_addr_add(AF_INET6, ifindex, addr, mcast, acast, prefix);
 }
 
-int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr,
-                     struct in_addr *bcast, int prefix)
+int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr, struct in_addr *bcast,
+                     int prefix)
 {
        return ip_addr_add(AF_INET, ifindex, addr, bcast, NULL, prefix);
 }
 
-/* Find an IFA_LOCAL (or IFA_ADDRESS if not IFA_LOCAL is present)
- * address from the given RTM_NEWADDR message.  Allocates memory for the
- * address and stores that pointer in *res (so res should be an
- * in_addr** or in6_addr**).
+/* Find an IFA_LOCAL (or IFA_ADDRESS if not IFA_LOCAL is present) address from
+ * the given RTM_NEWADDR message. Allocates memory for the address and stores
+ * that pointer in *res (so res should be an in_addr** or in6_addr**).
  */
-static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void** res) {
+static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void **res)
+{
+       int addrlen;
        struct ifaddrmsg *ifa = NLMSG_DATA(msg);
        struct rtattr *rta = IFA_RTA(ifa);
        int attr_len = NLMSG_PAYLOAD(msg, sizeof(struct ifaddrmsg));
-       int addrlen;
 
        if (ifa->ifa_family != family)
                return 0;
 
-       addrlen = family == AF_INET ? sizeof(struct in_addr) :
-               sizeof(struct in6_addr);
+       addrlen = family == AF_INET ? sizeof(struct in_addr)
+                                   : sizeof(struct in6_addr);
 
        /* Loop over the rtattr's in this message */
-       while(RTA_OK(rta, attr_len)) {
+       while (RTA_OK(rta, attr_len)) {
                /* Found a local address for the requested interface,
-                * return it. */
-               if (rta->rta_type == IFA_LOCAL || rta->rta_type == IFA_ADDRESS) {
-                       /* Sanity check. The family check above should
-                        * make sure the address length is correct, but
-                        * check here just in case */
+                * return it.
+                */
+               if (rta->rta_type == IFA_LOCAL ||
+                   rta->rta_type == IFA_ADDRESS) {
+                       /* Sanity check. The family check above should make sure
+                        * the address length is correct, but check here just in
+                        * case.
+                        */
                        if (RTA_PAYLOAD(rta) != addrlen)
                                return -1;
 
-                       /* We might have found an IFA_ADDRESS before,
-                        * which we now overwrite with an IFA_LOCAL. */
+                       /* We might have found an IFA_ADDRESS before, which we
+                        * now overwrite with an IFA_LOCAL.
+                        */
                        if (!*res) {
                                *res = malloc(addrlen);
                                if (!*res)
@@ -1138,7 +1525,6 @@ static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void** res) {
                        }
 
                        memcpy(*res, RTA_DATA(rta), addrlen);
-
                        if (rta->rta_type == IFA_LOCAL)
                                break;
                }
@@ -1149,13 +1535,12 @@ static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void** res) {
 
 static int ip_addr_get(int family, int ifindex, void **res)
 {
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       int answer_len, err;
        struct ifaddrmsg *ifa;
+       struct nl_handler nlh;
        struct nlmsghdr *msg;
-       int err;
-       int recv_len = 0, answer_len;
-       int readmore = 0;
+       int readmore = 0, recv_len = 0;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -1170,12 +1555,12 @@ static int ip_addr_get(int family, int ifindex, void **res)
        if (!answer)
                goto out;
 
-       /* Save the answer buffer length, since it will be overwritten
-        * on the first receive (and we might need to receive more than
-        * once. */
+       /* Save the answer buffer length, since it will be overwritten on the
+        * first receive (and we might need to receive more than once).
+        */
        answer_len = answer->nlmsghdr->nlmsg_len;
 
-       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ROOT;
+       nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
        nlmsg->nlmsghdr->nlmsg_type = RTM_GETADDR;
 
        ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg));
@@ -1183,18 +1568,20 @@ static int ip_addr_get(int family, int ifindex, void **res)
                goto out;
        ifa->ifa_family = family;
 
-       /* Send the request for addresses, which returns all addresses
-        * on all interfaces. */
+       /* Send the request for addresses, which returns all addresses on all
+        * interfaces.
+        */
        err = netlink_send(&nlh, nlmsg);
        if (err < 0)
                goto out;
 
        do {
                /* Restore the answer buffer length, it might have been
-                * overwritten by a previous receive. */
+                * overwritten by a previous receive.
+                */
                answer->nlmsghdr->nlmsg_len = answer_len;
 
-               /* Get the (next) batch of reply messages */
+               /* Get the (next) batch of reply messages. */
                err = netlink_rcv(&nlh, answer);
                if (err < 0)
                        goto out;
@@ -1202,18 +1589,19 @@ static int ip_addr_get(int family, int ifindex, void **res)
                recv_len = err;
                err = 0;
 
-               /* Satisfy the typing for the netlink macros */
+               /* Satisfy the typing for the netlink macros. */
                msg = answer->nlmsghdr;
 
                while (NLMSG_OK(msg, recv_len)) {
-                       /* Stop reading if we see an error message */
+                       /* Stop reading if we see an error message. */
                        if (msg->nlmsg_type == NLMSG_ERROR) {
-                               struct nlmsgerr *errmsg = (struct nlmsgerr*)NLMSG_DATA(msg);
+                               struct nlmsgerr *errmsg =
+                                   (struct nlmsgerr *)NLMSG_DATA(msg);
                                err = errmsg->error;
                                goto out;
                        }
 
-                       /* Stop reading if we see a NLMSG_DONE message */
+                       /* Stop reading if we see a NLMSG_DONE message. */
                        if (msg->nlmsg_type == NLMSG_DONE) {
                                readmore = 0;
                                break;
@@ -1231,22 +1619,24 @@ static int ip_addr_get(int family, int ifindex, void **res)
                                        goto out;
                                }
 
-                               /* Found a result, stop searching */
+                               /* Found a result, stop searching. */
                                if (*res)
                                        goto out;
                        }
 
-                       /* Keep reading more data from the socket if the
-                        * last message had the NLF_F_MULTI flag set */
+                       /* Keep reading more data from the socket if the last
+                        * message had the NLF_F_MULTI flag set.
+                        */
                        readmore = (msg->nlmsg_flags & NLM_F_MULTI);
 
-                       /* Look at the next message received in this buffer */
+                       /* Look at the next message received in this buffer. */
                        msg = NLMSG_NEXT(msg, recv_len);
                }
        } while (readmore);
 
        /* If we end up here, we didn't find any result, so signal an
-        * error */
+        * error.
+        */
        err = -1;
 
 out:
@@ -1258,24 +1648,23 @@ out:
 
 int lxc_ipv6_addr_get(int ifindex, struct in6_addr **res)
 {
-       return ip_addr_get(AF_INET6, ifindex, (void**)res);
+       return ip_addr_get(AF_INET6, ifindex, (void **)res);
 }
 
-int lxc_ipv4_addr_get(int ifindex, struct in_addr** res)
+int lxc_ipv4_addr_get(int ifindex, struct in_addr **res)
 {
-       return ip_addr_get(AF_INET, ifindex, (void**)res);
+       return ip_addr_get(AF_INET, ifindex, (void **)res);
 }
 
 static int ip_gateway_add(int family, int ifindex, void *gw)
 {
+       int addrlen, err;
        struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
        struct rtmsg *rt;
-       int addrlen;
-       int err;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
-       addrlen = family == AF_INET ? sizeof(struct in_addr) :
-               sizeof(struct in6_addr);
+       addrlen = family == AF_INET ? sizeof(struct in_addr)
+                                   : sizeof(struct in6_addr);
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -1291,7 +1680,7 @@ static int ip_gateway_add(int family, int ifindex, void *gw)
                goto out;
 
        nlmsg->nlmsghdr->nlmsg_flags =
-               NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
+           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));
@@ -1310,7 +1699,8 @@ static int ip_gateway_add(int family, int ifindex, void *gw)
                goto out;
 
        /* Adding the interface index enables the use of link-local
-        * addresses for the gateway */
+        * addresses for the gateway.
+        */
        if (nla_put_u32(nlmsg, RTA_OIF, ifindex))
                goto out;
 
@@ -1334,14 +1724,13 @@ int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw)
 
 static int ip_route_dest_add(int family, int ifindex, void *dest)
 {
+       int addrlen, err;
        struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
        struct rtmsg *rt;
-       int addrlen;
-       int err;
+       struct nlmsg *answer = NULL, *nlmsg = NULL;
 
-       addrlen = family == AF_INET ? sizeof(struct in_addr) :
-               sizeof(struct in6_addr);
+       addrlen = family == AF_INET ? sizeof(struct in_addr)
+                                   : sizeof(struct in6_addr);
 
        err = netlink_open(&nlh, NETLINK_ROUTE);
        if (err)
@@ -1357,7 +1746,7 @@ static int ip_route_dest_add(int family, int ifindex, void *dest)
                goto out;
 
        nlmsg->nlmsghdr->nlmsg_flags =
-               NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
+           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));
@@ -1368,7 +1757,7 @@ static int ip_route_dest_add(int family, int ifindex, void *dest)
        rt->rtm_scope = RT_SCOPE_LINK;
        rt->rtm_protocol = RTPROT_BOOT;
        rt->rtm_type = RTN_UNICAST;
-       rt->rtm_dst_len = addrlen*8;
+       rt->rtm_dst_len = addrlen * 8;
 
        err = -EINVAL;
        if (nla_put_buffer(nlmsg, RTA_DST, dest, addrlen))
@@ -1393,71 +1782,91 @@ int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest)
        return ip_route_dest_add(AF_INET6, ifindex, dest);
 }
 
-static bool is_ovs_bridge(const char *bridge)
+bool is_ovs_bridge(const char *bridge)
 {
-       char brdirname[22 + IFNAMSIZ + 1] = {0};
+       int ret;
        struct stat sb;
+       char brdirname[22 + IFNAMSIZ + 1] = {0};
 
-       snprintf(brdirname, 22 +IFNAMSIZ + 1, "/sys/class/net/%s/bridge", bridge);
-       if (stat(brdirname, &sb) == -1 && errno == ENOENT)
+       ret = snprintf(brdirname, 22 + IFNAMSIZ + 1, "/sys/class/net/%s/bridge",
+                      bridge);
+       if (ret < 0 || (size_t)ret >= 22 + IFNAMSIZ + 1)
+               return false;
+
+       ret = stat(brdirname, &sb);
+       if (ret < 0 && errno == ENOENT)
                return true;
+
        return false;
 }
 
-/*
- * Called from a background thread - when nic goes away, remove
- * it from the bridge
+struct ovs_veth_args {
+       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)
+static int lxc_ovs_delete_port_exec(void *data)
 {
-       if (lxc_check_inherited(NULL, true, &(int){-1}, 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 */
+       struct ovs_veth_args *args = data;
+
+       execlp("ovs-vsctl", "ovs-vsctl", "del-port", args->bridge, args->nic,
+              (char *)NULL);
+       return -1;
 }
 
-static int attach_to_ovs_bridge(const char *lxcpath, const char *name, const char *bridge, const char *nic)
+int lxc_ovs_delete_port(const char *bridge, const char *nic)
 {
-       pid_t pid;
-       char *cmd;
        int ret;
-
-       cmd = on_path("ovs-vsctl", NULL);
-       if (!cmd)
+       char cmd_output[MAXPATHLEN];
+       struct ovs_veth_args args;
+
+       args.bridge = bridge;
+       args.nic = nic;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         lxc_ovs_delete_port_exec, (void *)&args);
+       if (ret < 0) {
+               ERROR("Failed to delete \"%s\" from openvswitch bridge \"%s\": "
+                     "%s", bridge, nic, cmd_output);
                return -1;
-       free(cmd);
+       }
+
+       return 0;
+}
+
+static int lxc_ovs_attach_bridge_exec(void *data)
+{
+       struct ovs_veth_args *args = data;
+
+       execlp("ovs-vsctl", "ovs-vsctl", "add-port", args->bridge, args->nic,
+              (char *)NULL);
+       return -1;
+}
 
-       pid = fork();
-       if (pid < 0)
+static int lxc_ovs_attach_bridge(const char *bridge, const char *nic)
+{
+       int ret;
+       char cmd_output[MAXPATHLEN];
+       struct ovs_veth_args args;
+
+       args.bridge = bridge;
+       args.nic = nic;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         lxc_ovs_attach_bridge_exec, (void *)&args);
+       if (ret < 0) {
+               ERROR("Failed to attach \"%s\" to openvswitch bridge \"%s\": %s",
+                     bridge, nic, cmd_output);
                return -1;
-       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, (char *)NULL))
-               exit(1);
-       // not reached
-       exit(1);
+       return 0;
 }
 
-/*
- * 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 *lxcpath, const char *name, const char *bridge, const char *ifname)
+int lxc_bridge_attach(const char *bridge, const char *ifname)
 {
-       int fd, index, err;
+       int err, fd, index;
        struct ifreq ifr;
 
        if (strlen(ifname) >= IFNAMSIZ)
@@ -1468,14 +1877,14 @@ int lxc_bridge_attach(const char *lxcpath, const char *name, const char *bridge,
                return -EINVAL;
 
        if (is_ovs_bridge(bridge))
-               return attach_to_ovs_bridge(lxcpath, name, bridge, ifname);
+               return lxc_ovs_attach_bridge(bridge, ifname);
 
        fd = socket(AF_INET, SOCK_STREAM, 0);
        if (fd < 0)
                return -errno;
 
-       strncpy(ifr.ifr_name, bridge, IFNAMSIZ-1);
-       ifr.ifr_name[IFNAMSIZ-1] = '\0';
+       strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
+       ifr.ifr_name[IFNAMSIZ - 1] = '\0';
        ifr.ifr_ifindex = index;
        err = ioctl(fd, SIOCBRADDIF, &ifr);
        close(fd);
@@ -1485,7 +1894,7 @@ int lxc_bridge_attach(const char *lxcpath, const char *name, const char *bridge,
        return err;
 }
 
-static const charconst lxc_network_types[LXC_NET_MAXCONFTYPE + 1] = {
+static const char *const lxc_network_types[LXC_NET_MAXCONFTYPE + 1] = {
        [LXC_NET_EMPTY]   = "empty",
        [LXC_NET_VETH]    = "veth",
        [LXC_NET_MACVLAN] = "macvlan",
@@ -1498,46 +1907,47 @@ const char *lxc_net_type_to_str(int type)
 {
        if (type < 0 || type > LXC_NET_MAXCONFTYPE)
                return NULL;
+
        return lxc_network_types[type];
 }
 
-static const char padchar[] =
-"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static const char padchar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
 char *lxc_mkifname(char *template)
 {
-       char *name = NULL;
-       size_t i = 0;
-       FILE *urandom;
        unsigned int seed;
-       struct ifaddrs *ifaddr, *ifa;
-       int ifexists = 0;
+       FILE *urandom;
+       struct ifaddrs *ifa, *ifaddr;
+       char name[IFNAMSIZ];
+       bool exists = false;
+       size_t i = 0;
 
-       /* Get all the network interfaces */
+       if (strlen(template) >= IFNAMSIZ)
+               return NULL;
+
+       /* Get all the network interfaces. */
        getifaddrs(&ifaddr);
 
-       /* Initialize the random number generator */
-       urandom = fopen ("/dev/urandom", "r");
+       /* Initialize the random number generator. */
+       urandom = fopen("/dev/urandom", "r");
        if (urandom != NULL) {
-               if (fread (&seed, sizeof(seed), 1, urandom) <= 0)
+               if (fread(&seed, sizeof(seed), 1, urandom) <= 0)
                        seed = time(0);
                fclose(urandom);
-       }
-       else
+       } else {
                seed = time(0);
+       }
 
 #ifndef HAVE_RAND_R
        srand(seed);
 #endif
 
-       /* Generate random names until we find one that doesn't exist */
-       while(1) {
-               ifexists = 0;
-               name = strdup(template);
-
-               if (name == NULL)
-                       return NULL;
+       /* Generate random names until we find one that doesn't exist. */
+       while (true) {
+               name[0] = '\0';
+               strcpy(name, template);
 
+               exists = false;
                for (i = 0; i < strlen(name); i++) {
                        if (name[i] == 'X') {
 #ifdef HAVE_RAND_R
@@ -1549,33 +1959,33 @@ char *lxc_mkifname(char *template)
                }
 
                for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
-                       if (strcmp(ifa->ifa_name, name) == 0) {
-                               ifexists = 1;
+                       if (!strcmp(ifa->ifa_name, name)) {
+                               exists = true;
                                break;
                        }
                }
 
-               if (ifexists == 0)
+               if (!exists)
                        break;
-
-               free(name);
        }
 
        freeifaddrs(ifaddr);
-       return name;
+       return strcpy(template, name);
 }
 
 int setup_private_host_hw_addr(char *veth1)
 {
+       int err, sockfd;
        struct ifreq ifr;
-       int err;
-       int sockfd;
 
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd < 0)
                return -errno;
 
-       snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1);
+       err = snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1);
+       if (err < 0 || (size_t)err >= IFNAMSIZ)
+               return -E2BIG;
+
        err = ioctl(sockfd, SIOCGIFHWADDR, &ifr);
        if (err < 0) {
                close(sockfd);
@@ -1590,3 +2000,1126 @@ int setup_private_host_hw_addr(char *veth1)
 
        return 0;
 }
+
+int lxc_find_gateway_addresses(struct lxc_handler *handler)
+{
+       struct lxc_list *network = &handler->conf->network;
+       struct lxc_list *iterator;
+       struct lxc_netdev *netdev;
+       int link_index;
+
+       lxc_list_for_each(iterator, network) {
+               netdev = iterator->elem;
+
+               if (!netdev->ipv4_gateway_auto && !netdev->ipv6_gateway_auto)
+                       continue;
+
+               if (netdev->type != LXC_NET_VETH && netdev->type != LXC_NET_MACVLAN) {
+                       ERROR("Automatic gateway detection is only supported "
+                             "for veth and macvlan");
+                       return -1;
+               }
+
+               if (netdev->link[0] == '\0') {
+                       ERROR("Automatic gateway detection needs a link interface");
+                       return -1;
+               }
+
+               link_index = if_nametoindex(netdev->link);
+               if (!link_index)
+                       return -EINVAL;
+
+               if (netdev->ipv4_gateway_auto) {
+                       if (lxc_ipv4_addr_get(link_index, &netdev->ipv4_gateway)) {
+                               ERROR("Failed to automatically find ipv4 gateway "
+                                     "address from link interface \"%s\"", netdev->link);
+                               return -1;
+                       }
+               }
+
+               if (netdev->ipv6_gateway_auto) {
+                       if (lxc_ipv6_addr_get(link_index, &netdev->ipv6_gateway)) {
+                               ERROR("Failed to automatically find ipv6 gateway "
+                                     "address from link interface \"%s\"", netdev->link);
+                               return -1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+#define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
+static int lxc_create_network_unpriv_exec(const char *lxcpath, char *lxcname,
+                                         struct lxc_netdev *netdev, pid_t pid)
+{
+       int ret;
+       pid_t child;
+       int bytes, pipefd[2];
+       char *token, *saveptr = NULL;
+       char netdev_link[IFNAMSIZ + 1];
+       char buffer[MAXPATHLEN] = {0};
+
+       if (netdev->type != LXC_NET_VETH) {
+               ERROR("Network type %d not support for unprivileged use", netdev->type);
+               return -1;
+       }
+
+       ret = pipe(pipefd);
+       if (ret < 0) {
+               SYSERROR("Failed to create pipe");
+               return -1;
+       }
+
+       child = fork();
+       if (child < 0) {
+               SYSERROR("Failed to create new process");
+               close(pipefd[0]);
+               close(pipefd[1]);
+               return -1;
+       }
+
+       if (child == 0) {
+               int ret;
+               char pidstr[LXC_NUMSTRLEN64];
+
+               close(pipefd[0]);
+
+               ret = dup2(pipefd[1], STDOUT_FILENO);
+               if (ret >= 0)
+                       ret = dup2(pipefd[1], STDERR_FILENO);
+               close(pipefd[1]);
+               if (ret < 0) {
+                       SYSERROR("Failed to duplicate std{err,out} file descriptor");
+                       exit(EXIT_FAILURE);
+               }
+
+               if (netdev->link[0] != '\0')
+                       strncpy(netdev_link, netdev->link, IFNAMSIZ);
+               else
+                       strncpy(netdev_link, "none", IFNAMSIZ);
+
+               ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
+               if (ret < 0 || ret >= LXC_NUMSTRLEN64)
+                       exit(EXIT_FAILURE);
+               pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
+
+               INFO("Execing lxc-user-nic create %s %s %s veth %s %s", lxcpath,
+                    lxcname, pidstr, netdev_link,
+                    netdev->name[0] != '\0' ? netdev->name : "(null)");
+               if (netdev->name[0] != '\0')
+                       execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "create",
+                              lxcpath, lxcname, pidstr, "veth", netdev_link,
+                              netdev->name, (char *)NULL);
+               else
+                       execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "create",
+                              lxcpath, lxcname, pidstr, "veth", netdev_link,
+                              (char *)NULL);
+               SYSERROR("Failed to execute lxc-user-nic");
+               exit(EXIT_FAILURE);
+       }
+
+       /* close the write-end of the pipe */
+       close(pipefd[1]);
+
+       bytes = read(pipefd[0], &buffer, MAXPATHLEN);
+       if (bytes < 0) {
+               SYSERROR("Failed to read from pipe file descriptor");
+               close(pipefd[0]);
+               return -1;
+       }
+       buffer[bytes - 1] = '\0';
+
+       ret = wait_for_pid(child);
+       close(pipefd[0]);
+       if (ret != 0) {
+               ERROR("lxc-user-nic failed to configure requested network: %s",
+                     buffer[0] != '\0' ? buffer : "(null)");
+               return -1;
+       }
+       TRACE("Received output \"%s\" from lxc-user-nic", buffer);
+
+       /* netdev->name */
+       token = strtok_r(buffer, ":", &saveptr);
+       if (!token) {
+               ERROR("Failed to parse lxc-user-nic output");
+               return -1;
+       }
+
+       memset(netdev->name, 0, IFNAMSIZ + 1);
+       strncpy(netdev->name, token, IFNAMSIZ);
+
+       /* netdev->ifindex */
+       token = strtok_r(NULL, ":", &saveptr);
+       if (!token) {
+               ERROR("Failed to parse lxc-user-nic output");
+               return -1;
+       }
+
+       ret = lxc_safe_int(token, &netdev->ifindex);
+       if (ret < 0) {
+               ERROR("%s - Failed to convert string \"%s\" to integer",
+                     strerror(-ret), token);
+               return -1;
+       }
+
+       /* netdev->priv.veth_attr.veth1 */
+       token = strtok_r(NULL, ":", &saveptr);
+       if (!token) {
+               ERROR("Failed to parse lxc-user-nic output");
+               return -1;
+       }
+
+       if (strlen(token) >= IFNAMSIZ) {
+               ERROR("Host side veth device name returned by lxc-user-nic is "
+                     "too long");
+               return -E2BIG;
+       }
+       strcpy(netdev->priv.veth_attr.veth1, token);
+
+       /* netdev->priv.veth_attr.ifindex */
+       token = strtok_r(NULL, ":", &saveptr);
+       if (!token) {
+               ERROR("Failed to parse lxc-user-nic output");
+               return -1;
+       }
+
+       ret = lxc_safe_int(token, &netdev->priv.veth_attr.ifindex);
+       if (ret < 0) {
+               ERROR("%s - Failed to convert string \"%s\" to integer",
+                     strerror(-ret), token);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int lxc_delete_network_unpriv_exec(const char *lxcpath, char *lxcname,
+                                         struct lxc_netdev *netdev,
+                                         const char *netns_path)
+{
+       int bytes, ret;
+       pid_t child;
+       int pipefd[2];
+       char buffer[MAXPATHLEN] = {0};
+
+       if (netdev->type != LXC_NET_VETH) {
+               ERROR("Network type %d not support for unprivileged use", netdev->type);
+               return -1;
+       }
+
+       ret = pipe(pipefd);
+       if (ret < 0) {
+               SYSERROR("Failed to create pipe");
+               return -1;
+       }
+
+       child = fork();
+       if (child < 0) {
+               SYSERROR("Failed to create new process");
+               close(pipefd[0]);
+               close(pipefd[1]);
+               return -1;
+       }
+
+       if (child == 0) {
+               char *hostveth;
+               int ret;
+
+               close(pipefd[0]);
+
+               ret = dup2(pipefd[1], STDOUT_FILENO);
+               if (ret >= 0)
+                       ret = dup2(pipefd[1], STDERR_FILENO);
+               close(pipefd[1]);
+               if (ret < 0) {
+                       SYSERROR("Failed to duplicate std{err,out} file descriptor");
+                       exit(EXIT_FAILURE);
+               }
+
+               if (netdev->priv.veth_attr.pair[0] != '\0')
+                       hostveth = netdev->priv.veth_attr.pair;
+               else
+                       hostveth = netdev->priv.veth_attr.veth1;
+               if (hostveth[0] == '\0') {
+                       SYSERROR("Host side veth device name is missing");
+                       exit(EXIT_FAILURE);
+               }
+
+               if (netdev->link[0] == '\0') {
+                       SYSERROR("Network link for network device \"%s\" is "
+                                "missing", netdev->priv.veth_attr.veth1);
+                       exit(EXIT_FAILURE);
+               }
+
+               INFO("Execing lxc-user-nic delete %s %s %s veth %s %s", lxcpath,
+                    lxcname, netns_path, netdev->link, hostveth);
+               execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "delete", lxcpath,
+                      lxcname, netns_path, "veth", netdev->link, hostveth,
+                      (char *)NULL);
+               SYSERROR("Failed to exec lxc-user-nic.");
+               exit(EXIT_FAILURE);
+       }
+
+       close(pipefd[1]);
+
+       bytes = read(pipefd[0], &buffer, MAXPATHLEN);
+       if (bytes < 0) {
+               SYSERROR("Failed to read from pipe file descriptor.");
+               close(pipefd[0]);
+               return -1;
+       }
+       buffer[bytes - 1] = '\0';
+
+       if (wait_for_pid(child) != 0) {
+               ERROR("lxc-user-nic failed to delete requested network: %s",
+                     buffer[0] != '\0' ? buffer : "(null)");
+               close(pipefd[0]);
+               return -1;
+       }
+
+       close(pipefd[0]);
+
+       return 0;
+}
+
+bool lxc_delete_network_unpriv(struct lxc_handler *handler)
+{
+       int ret;
+       struct lxc_list *iterator;
+       struct lxc_list *network = &handler->conf->network;
+       /* strlen("/proc/") = 6
+        * +
+        * LXC_NUMSTRLEN64
+        * +
+        * strlen("/fd/") = 4
+        * +
+        * LXC_NUMSTRLEN64
+        * +
+        * \0
+        */
+       char netns_path[6 + LXC_NUMSTRLEN64 + 4 + LXC_NUMSTRLEN64 + 1];
+
+       *netns_path = '\0';
+
+       if (handler->netnsfd < 0) {
+               DEBUG("Cannot not guarantee safe deletion of network devices. "
+                     "Manual cleanup maybe needed");
+               return false;
+       }
+
+       ret = snprintf(netns_path, sizeof(netns_path), "/proc/%d/fd/%d",
+                      getpid(), handler->netnsfd);
+       if (ret < 0 || ret >= sizeof(netns_path))
+               return false;
+
+       lxc_list_for_each(iterator, network) {
+               char *hostveth = NULL;
+               struct lxc_netdev *netdev = iterator->elem;
+
+               /* We can only delete devices whose ifindex we have. If we don't
+                * have the index it means that we didn't create it.
+                */
+               if (!netdev->ifindex)
+                       continue;
+
+               if (netdev->type == LXC_NET_PHYS) {
+                       ret = lxc_netdev_rename_by_index(netdev->ifindex,
+                                                        netdev->link);
+                       if (ret < 0)
+                               WARN("Failed to rename interface with index %d "
+                                    "to its initial name \"%s\"",
+                                    netdev->ifindex, netdev->link);
+                       else
+                               TRACE("Renamed interface with index %d to its "
+                                     "initial name \"%s\"",
+                                     netdev->ifindex, netdev->link);
+                       goto clear_ifindices;
+               }
+
+               ret = netdev_deconf[netdev->type](handler, netdev);
+               if (ret < 0)
+                       WARN("Failed to deconfigure network device");
+
+               if (netdev->type != LXC_NET_VETH)
+                       goto clear_ifindices;
+
+               if (netdev->link[0] == '\0' || !is_ovs_bridge(netdev->link))
+                       goto clear_ifindices;
+
+               if (netdev->priv.veth_attr.pair[0] != '\0')
+                       hostveth = netdev->priv.veth_attr.pair;
+               else
+                       hostveth = netdev->priv.veth_attr.veth1;
+               if (hostveth[0] == '\0')
+                       goto clear_ifindices;
+
+               ret = lxc_delete_network_unpriv_exec(handler->lxcpath,
+                                                    handler->name, netdev,
+                                                    netns_path);
+               if (ret < 0) {
+                       WARN("Failed to remove port \"%s\" from openvswitch "
+                            "bridge \"%s\"", hostveth, netdev->link);
+                       goto clear_ifindices;
+               }
+               INFO("Removed interface \"%s\" from \"%s\"", hostveth,
+                    netdev->link);
+
+clear_ifindices:
+               /* We need to clear any ifindeces we recorded so liblxc won't
+                * have cached stale data which would cause it to fail on reboot
+                * we're we don't re-read the on-disk config file.
+                */
+               netdev->ifindex = 0;
+               if (netdev->type == LXC_NET_PHYS) {
+                       netdev->priv.phys_attr.ifindex = 0;
+               } else if (netdev->type == LXC_NET_VETH) {
+                       netdev->priv.veth_attr.veth1[0] = '\0';
+                       netdev->priv.veth_attr.ifindex = 0;
+               }
+       }
+
+       return true;
+}
+
+int lxc_create_network_priv(struct lxc_handler *handler)
+{
+       struct lxc_list *iterator;
+       struct lxc_list *network = &handler->conf->network;
+
+       if (!handler->am_root)
+               return 0;
+
+       lxc_list_for_each(iterator, network) {
+               struct lxc_netdev *netdev = iterator->elem;
+
+               if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE) {
+                       ERROR("Invalid network configuration type %d", netdev->type);
+                       return -1;
+               }
+
+               if (netdev_conf[netdev->type](handler, netdev)) {
+                       ERROR("Failed to create network device");
+                       return -1;
+               }
+
+       }
+
+       return 0;
+}
+
+int lxc_network_move_created_netdev_priv(const char *lxcpath, char *lxcname,
+                                        struct lxc_list *network, pid_t pid)
+{
+       int ret;
+       char ifname[IFNAMSIZ];
+       struct lxc_list *iterator;
+
+       if (am_unpriv())
+               return 0;
+
+       lxc_list_for_each(iterator, network) {
+               struct lxc_netdev *netdev = iterator->elem;
+
+               if (!netdev->ifindex)
+                       continue;
+
+               /* retrieve the name of the interface */
+               if (!if_indextoname(netdev->ifindex, ifname)) {
+                       ERROR("No interface corresponding to ifindex \"%d\"",
+                             netdev->ifindex);
+                       return -1;
+               }
+
+               ret = lxc_netdev_move_by_name(ifname, pid, NULL);
+               if (ret) {
+                       ERROR("Failed to move network device \"%s\" to "
+                             "network namespace %d: %s", ifname, pid,
+                             strerror(-ret));
+                       return -1;
+               }
+
+               DEBUG("Moved network device \"%s\"/\"%s\" to network namespace "
+                     "of %d",
+                     ifname, netdev->name[0] != '\0' ? netdev->name : "(null)",
+                     pid);
+       }
+
+       return 0;
+}
+
+int lxc_create_network_unpriv(const char *lxcpath, char *lxcname,
+                             struct lxc_list *network, pid_t pid)
+{
+       struct lxc_list *iterator;
+
+       if (!am_unpriv())
+               return 0;
+
+       lxc_list_for_each(iterator, network) {
+               struct lxc_netdev *netdev = iterator->elem;
+
+               if (netdev->type == LXC_NET_EMPTY)
+                       continue;
+
+               if (netdev->type == LXC_NET_NONE)
+                       continue;
+
+               if (netdev->type != LXC_NET_VETH) {
+                       ERROR("Networks of type %s are not supported by "
+                             "unprivileged containers",
+                             lxc_net_type_to_str(netdev->type));
+                       return -1;
+               }
+
+               if (netdev->mtu)
+                       INFO("mtu ignored due to insufficient privilege");
+
+               if (lxc_create_network_unpriv_exec(lxcpath, lxcname, netdev, pid))
+                       return -1;
+       }
+
+       return 0;
+}
+
+bool lxc_delete_network_priv(struct lxc_handler *handler)
+{
+       int ret;
+       struct lxc_list *iterator;
+       struct lxc_list *network = &handler->conf->network;
+
+       lxc_list_for_each(iterator, network) {
+               char *hostveth = NULL;
+               struct lxc_netdev *netdev = iterator->elem;
+
+               /* We can only delete devices whose ifindex we have. If we don't
+                * have the index it means that we didn't create it.
+                */
+               if (!netdev->ifindex)
+                       continue;
+
+               if (netdev->type == LXC_NET_PHYS) {
+                       ret = lxc_netdev_rename_by_index(netdev->ifindex, netdev->link);
+                       if (ret < 0)
+                               WARN("Failed to rename interface with index %d "
+                                    "from \"%s\" to its initial name \"%s\"",
+                                    netdev->ifindex, netdev->name, netdev->link);
+                       else
+                               TRACE("Renamed interface with index %d from "
+                                     "\"%s\" to its initial name \"%s\"",
+                                     netdev->ifindex, netdev->name,
+                                     netdev->link);
+                       goto clear_ifindices;
+               }
+
+               ret = netdev_deconf[netdev->type](handler, netdev);
+               if (ret < 0)
+                       WARN("Failed to deconfigure network device");
+
+               /* Recent kernels remove the virtual interfaces when the network
+                * namespace is destroyed but in case we did not move the
+                * interface to the network namespace, we have to destroy it.
+                */
+               ret = lxc_netdev_delete_by_index(netdev->ifindex);
+               if (-ret == ENODEV) {
+                       INFO("Interface \"%s\" with index %d already "
+                            "deleted or existing in different network "
+                            "namespace",
+                            netdev->name[0] != '\0' ? netdev->name : "(null)",
+                            netdev->ifindex);
+               } else if (ret < 0) {
+                       WARN("Failed to remove interface \"%s\" with "
+                            "index %d: %s",
+                            netdev->name[0] != '\0' ? netdev->name : "(null)",
+                            netdev->ifindex, strerror(-ret));
+                       goto clear_ifindices;
+               }
+               INFO("Removed interface \"%s\" with index %d",
+                    netdev->name[0] != '\0' ? netdev->name : "(null)",
+                    netdev->ifindex);
+
+               if (netdev->type != LXC_NET_VETH)
+                       goto clear_ifindices;
+
+               /* Explicitly delete host veth device to prevent lingering
+                * devices. We had issues in LXD around this.
+                */
+               if (netdev->priv.veth_attr.pair[0] != '\0')
+                       hostveth = netdev->priv.veth_attr.pair;
+               else
+                       hostveth = netdev->priv.veth_attr.veth1;
+               if (hostveth[0] == '\0')
+                       goto clear_ifindices;
+
+               ret = lxc_netdev_delete_by_name(hostveth);
+               if (ret < 0) {
+                       WARN("Failed to remove interface \"%s\" from \"%s\": %s",
+                            hostveth, netdev->link, strerror(-ret));
+                       goto clear_ifindices;
+               }
+               INFO("Removed interface \"%s\" from \"%s\"", hostveth, netdev->link);
+
+               if (netdev->link[0] == '\0' || !is_ovs_bridge(netdev->link)) {
+                       netdev->priv.veth_attr.veth1[0] = '\0';
+                       netdev->ifindex = 0;
+                       netdev->priv.veth_attr.ifindex = 0;
+                       goto clear_ifindices;
+               }
+
+               /* Delete the openvswitch port. */
+               ret = lxc_ovs_delete_port(netdev->link, hostveth);
+               if (ret < 0)
+                       WARN("Failed to remove port \"%s\" from openvswitch "
+                            "bridge \"%s\"", hostveth, netdev->link);
+               else
+                       INFO("Removed port \"%s\" from openvswitch bridge \"%s\"",
+                            hostveth, netdev->link);
+
+clear_ifindices:
+               /* We need to clear any ifindeces we recorded so liblxc won't
+                * have cached stale data which would cause it to fail on reboot
+                * we're we don't re-read the on-disk config file.
+                */
+               netdev->ifindex = 0;
+               if (netdev->type == LXC_NET_PHYS) {
+                       netdev->priv.phys_attr.ifindex = 0;
+               } else if (netdev->type == LXC_NET_VETH) {
+                       netdev->priv.veth_attr.veth1[0] = '\0';
+                       netdev->priv.veth_attr.ifindex = 0;
+               }
+       }
+
+       return true;
+}
+
+int lxc_requests_empty_network(struct lxc_handler *handler)
+{
+       struct lxc_list *network = &handler->conf->network;
+       struct lxc_list *iterator;
+       bool found_none = false, found_nic = false;
+
+       if (lxc_list_empty(network))
+               return 0;
+
+       lxc_list_for_each(iterator, network) {
+               struct lxc_netdev *netdev = iterator->elem;
+
+               if (netdev->type == LXC_NET_NONE)
+                       found_none = true;
+               else
+                       found_nic = true;
+       }
+       if (found_none && !found_nic)
+               return 1;
+       return 0;
+}
+
+/* try to move physical nics to the init netns */
+int lxc_restore_phys_nics_to_netns(struct lxc_handler *handler)
+{
+       int ret;
+       int oldfd;
+       char ifname[IFNAMSIZ];
+       struct lxc_list *iterator;
+       int netnsfd = handler->netnsfd;
+       struct lxc_conf *conf = handler->conf;
+
+       /* We need CAP_NET_ADMIN in the parent namespace in order to setns() to
+        * the parent network namespace. We won't have this capability if we are
+        * unprivileged.
+        */
+       if (!handler->am_root)
+               return 0;
+
+       TRACE("Moving physical network devices back to parent network namespace");
+
+       oldfd = lxc_preserve_ns(getpid(), "net");
+       if (oldfd < 0) {
+               SYSERROR("Failed to preserve network namespace");
+               return -1;
+       }
+
+       ret = setns(netnsfd, CLONE_NEWNET);
+       if (ret < 0) {
+               SYSERROR("Failed to enter network namespace");
+               close(oldfd);
+               return -1;
+       }
+
+       lxc_list_for_each(iterator, &conf->network) {
+               struct lxc_netdev *netdev = iterator->elem;
+
+               if (netdev->type != LXC_NET_PHYS)
+                       continue;
+
+               /* Retrieve the name of the interface in the container's network
+                * namespace.
+                */
+               if (!if_indextoname(netdev->ifindex, ifname)) {
+                       WARN("No interface corresponding to ifindex %d",
+                            netdev->ifindex);
+                       continue;
+               }
+
+               ret = lxc_netdev_move_by_name(ifname, 1, netdev->link);
+               if (ret < 0)
+                       WARN("Error moving network device \"%s\" back to "
+                            "network namespace", ifname);
+               else
+                       TRACE("Moved network device \"%s\" back to network "
+                             "namespace", ifname);
+       }
+
+       ret = setns(oldfd, CLONE_NEWNET);
+       close(oldfd);
+       if (ret < 0) {
+               SYSERROR("Failed to enter network namespace");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int setup_hw_addr(char *hwaddr, const char *ifname)
+{
+       struct sockaddr sockaddr;
+       struct ifreq ifr;
+       int ret, fd, saved_errno;
+
+       ret = lxc_convert_mac(hwaddr, &sockaddr);
+       if (ret) {
+               ERROR("Mac address \"%s\" conversion failed: %s", hwaddr,
+                     strerror(-ret));
+               return -1;
+       }
+
+       memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+       ifr.ifr_name[IFNAMSIZ-1] = '\0';
+       memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
+
+       fd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd < 0)
+               return -1;
+
+       ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
+       saved_errno = errno;
+       close(fd);
+       if (ret)
+               ERROR("Failed to perform ioctl: %s", strerror(saved_errno));
+
+       DEBUG("Mac address \"%s\" on \"%s\" has been setup", hwaddr,
+             ifr.ifr_name);
+
+       return ret;
+}
+
+static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
+{
+       struct lxc_list *iterator;
+       int err;
+
+       lxc_list_for_each(iterator, ip) {
+               struct lxc_inetdev *inetdev = iterator->elem;
+
+               err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
+                                       &inetdev->bcast, inetdev->prefix);
+               if (err) {
+                       ERROR("Failed to setup ipv4 address for network device "
+                             "with eifindex %d: %s", ifindex, strerror(-err));
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
+{
+       struct lxc_list *iterator;
+       int err;
+
+       lxc_list_for_each(iterator, ip) {
+               struct lxc_inet6dev *inet6dev = iterator->elem;
+
+               err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
+                                       &inet6dev->mcast, &inet6dev->acast,
+                                       inet6dev->prefix);
+               if (err) {
+                       ERROR("Failed to setup ipv6 address for network device "
+                             "with eifindex %d: %s", ifindex, strerror(-err));
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
+{
+       char ifname[IFNAMSIZ];
+       int err;
+       const char *net_type_name;
+       char *current_ifname = ifname;
+
+       /* empty network namespace */
+       if (!netdev->ifindex) {
+               if (netdev->flags & IFF_UP) {
+                       err = lxc_netdev_up("lo");
+                       if (err) {
+                               ERROR("Failed to set the loopback network "
+                                     "device up: %s",
+                                     strerror(-err));
+                               return -1;
+                       }
+               }
+
+               if (netdev->type == LXC_NET_EMPTY)
+                       return 0;
+
+               if (netdev->type == LXC_NET_NONE)
+                       return 0;
+
+               if (netdev->type != LXC_NET_VETH) {
+                       net_type_name = lxc_net_type_to_str(netdev->type);
+                       ERROR("%s networks are not supported for containers "
+                             "not setup up by privileged users", net_type_name);
+                       return -1;
+               }
+
+               netdev->ifindex = if_nametoindex(netdev->name);
+       }
+
+       /* get the new ifindex in case of physical netdev */
+       if (netdev->type == LXC_NET_PHYS) {
+               netdev->ifindex = if_nametoindex(netdev->link);
+               if (!netdev->ifindex) {
+                       ERROR("Failed to get ifindex for network device \"%s\"",
+                             netdev->link);
+                       return -1;
+               }
+       }
+
+       /* retrieve the name of the interface */
+       if (!if_indextoname(netdev->ifindex, current_ifname)) {
+               ERROR("Failed get name for network device with ifindex %d",
+                     netdev->ifindex);
+               return -1;
+       }
+
+       /* Default: let the system to choose one interface name.
+        * When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
+        * netlink will replace the format specifier with an appropriate index.
+        */
+       if (netdev->name[0] == '\0') {
+               if (netdev->type == LXC_NET_PHYS)
+                       strcpy(netdev->name, netdev->link);
+               else
+                       strcpy(netdev->name, "eth%d");
+       }
+
+       /* rename the interface name */
+       if (strcmp(ifname, netdev->name) != 0) {
+               err = lxc_netdev_rename_by_name(ifname, netdev->name);
+               if (err) {
+                       ERROR("Failed to rename network device \"%s\" to "
+                             "\"%s\": %s", ifname, netdev->name, strerror(-err));
+                       return -1;
+               }
+       }
+
+       /* Re-read the name of the interface because its name has changed
+        * and would be automatically allocated by the system
+        */
+       if (!if_indextoname(netdev->ifindex, current_ifname)) {
+               ERROR("Failed get name for network device with ifindex %d",
+                     netdev->ifindex);
+               return -1;
+       }
+
+       /* Now update the recorded name of the network device to reflect the
+        * name of the network device in the child's network namespace. We will
+        * later on send this information back to the parent.
+        */
+       strcpy(netdev->name, current_ifname);
+
+       /* set a mac address */
+       if (netdev->hwaddr) {
+               if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
+                       ERROR("Failed to setup hw address for network device \"%s\"",
+                             current_ifname);
+                       return -1;
+               }
+       }
+
+       /* setup ipv4 addresses on the interface */
+       if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
+               ERROR("Failed to setup ip addresses for network device \"%s\"",
+                     ifname);
+               return -1;
+       }
+
+       /* setup ipv6 addresses on the interface */
+       if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
+               ERROR("Failed to setup ipv6 addresses for network device \"%s\"",
+                     ifname);
+               return -1;
+       }
+
+       /* set the network device up */
+       if (netdev->flags & IFF_UP) {
+               int err;
+
+               err = lxc_netdev_up(current_ifname);
+               if (err) {
+                       ERROR("Failed to set network device \"%s\" up: %s",
+                             current_ifname, strerror(-err));
+                       return -1;
+               }
+
+               /* the network is up, make the loopback up too */
+               err = lxc_netdev_up("lo");
+               if (err) {
+                       ERROR("Failed to set the loopback network device up: %s",
+                             strerror(-err));
+                       return -1;
+               }
+       }
+
+       /* We can only set up the default routes after bringing
+        * up the interface, sine bringing up the interface adds
+        * the link-local routes and we can't add a default
+        * route if the gateway is not reachable. */
+
+       /* setup ipv4 gateway on the interface */
+       if (netdev->ipv4_gateway) {
+               if (!(netdev->flags & IFF_UP)) {
+                       ERROR("Cannot add ipv4 gateway for network device "
+                             "\"%s\" when not bringing up the interface", ifname);
+                       return -1;
+               }
+
+               if (lxc_list_empty(&netdev->ipv4)) {
+                       ERROR("Cannot add ipv4 gateway for network device "
+                             "\"%s\" when not assigning an address", ifname);
+                       return -1;
+               }
+
+               err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
+               if (err) {
+                       err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway);
+                       if (err) {
+                               ERROR("Failed to add ipv4 dest for network "
+                                     "device \"%s\": %s", ifname, strerror(-err));
+                       }
+
+                       err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
+                       if (err) {
+                               ERROR("Failed to setup ipv4 gateway for "
+                                     "network device \"%s\": %s",
+                                     ifname, strerror(-err));
+                               if (netdev->ipv4_gateway_auto) {
+                                       char buf[INET_ADDRSTRLEN];
+                                       inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
+                                       ERROR("Fried to set autodetected ipv4 gateway \"%s\"", buf);
+                               }
+                               return -1;
+                       }
+               }
+       }
+
+       /* setup ipv6 gateway on the interface */
+       if (netdev->ipv6_gateway) {
+               if (!(netdev->flags & IFF_UP)) {
+                       ERROR("Cannot add ipv6 gateway for network device "
+                             "\"%s\" when not bringing up the interface", ifname);
+                       return -1;
+               }
+
+               if (lxc_list_empty(&netdev->ipv6) && !IN6_IS_ADDR_LINKLOCAL(netdev->ipv6_gateway)) {
+                       ERROR("Cannot add ipv6 gateway for network device "
+                             "\"%s\" when not assigning an address", ifname);
+                       return -1;
+               }
+
+               err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
+               if (err) {
+                       err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway);
+                       if (err) {
+                               ERROR("Failed to add ipv6 dest for network "
+                                     "device \"%s\": %s", ifname, strerror(-err));
+                       }
+
+                       err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
+                       if (err) {
+                               ERROR("Failed to setup ipv6 gateway for "
+                                     "network device \"%s\": %s", ifname,
+                                     strerror(-err));
+                               if (netdev->ipv6_gateway_auto) {
+                                       char buf[INET6_ADDRSTRLEN];
+                                       inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
+                                       ERROR("Tried to set autodetected ipv6 "
+                                             "gateway for network device "
+                                             "\"%s\"", buf);
+                               }
+                               return -1;
+                       }
+               }
+       }
+
+       DEBUG("Network device \"%s\" has been setup", current_ifname);
+
+       return 0;
+}
+
+int lxc_setup_network_in_child_namespaces(const struct lxc_conf *conf,
+                                         struct lxc_list *network)
+{
+       struct lxc_list *iterator;
+       struct lxc_netdev *netdev;
+
+       lxc_list_for_each(iterator, network) {
+               netdev = iterator->elem;
+
+               /* REMOVE in LXC 3.0 */
+               if (netdev->idx < 0) {
+                       ERROR("WARNING: using \"lxc.network.*\" keys to define "
+                             "networks is DEPRECATED, please switch to using "
+                             "\"lxc.net.[i].* keys\"");
+               }
+
+               if (lxc_setup_netdev_in_child_namespaces(netdev)) {
+                       ERROR("failed to setup netdev");
+                       return -1;
+               }
+       }
+
+       if (!lxc_list_empty(network))
+               INFO("network has been setup");
+
+       return 0;
+}
+
+int lxc_network_send_veth_names_to_child(struct lxc_handler *handler)
+{
+       struct lxc_list *iterator;
+       struct lxc_list *network = &handler->conf->network;
+       int data_sock = handler->data_sock[0];
+
+       if (handler->am_root)
+               return 0;
+
+       lxc_list_for_each(iterator, network) {
+               int ret;
+               struct lxc_netdev *netdev = iterator->elem;
+
+               if (netdev->type != LXC_NET_VETH)
+                       continue;
+
+               ret = send(data_sock, netdev->name, IFNAMSIZ, 0);
+               if (ret < 0)
+                       return -1;
+               TRACE("Sent network device name \"%s\" to child", netdev->name);
+       }
+
+       return 0;
+}
+
+int lxc_network_recv_veth_names_from_parent(struct lxc_handler *handler)
+{
+       struct lxc_list *iterator;
+       struct lxc_list *network = &handler->conf->network;
+       int data_sock = handler->data_sock[1];
+
+       if (handler->am_root)
+               return 0;
+
+       lxc_list_for_each(iterator, network) {
+               int ret;
+               struct lxc_netdev *netdev = iterator->elem;
+
+               if (netdev->type != LXC_NET_VETH)
+                       continue;
+
+               ret = recv(data_sock, netdev->name, IFNAMSIZ, 0);
+               if (ret < 0)
+                       return -1;
+               TRACE("Received network device name \"%s\" from parent", netdev->name);
+       }
+
+       return 0;
+}
+
+int lxc_network_send_name_and_ifindex_to_parent(struct lxc_handler *handler)
+{
+       struct lxc_list *iterator, *network;
+       int data_sock = handler->data_sock[0];
+
+       if (!handler->am_root)
+               return 0;
+
+       network = &handler->conf->network;
+       lxc_list_for_each(iterator, network) {
+               int ret;
+               struct lxc_netdev *netdev = iterator->elem;
+
+               /* Send network device name in the child's namespace to parent. */
+               ret = send(data_sock, netdev->name, IFNAMSIZ, 0);
+               if (ret < 0)
+                       return -1;
+
+               /* Send network device ifindex in the child's namespace to
+                * parent.
+                */
+               ret = send(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), 0);
+               if (ret < 0)
+                       return -1;
+       }
+
+       TRACE("Sent network device names and ifindeces to parent");
+       return 0;
+}
+
+int lxc_network_recv_name_and_ifindex_from_child(struct lxc_handler *handler)
+{
+       struct lxc_list *iterator, *network;
+       int data_sock = handler->data_sock[1];
+
+       if (!handler->am_root)
+               return 0;
+
+       network = &handler->conf->network;
+       lxc_list_for_each(iterator, network) {
+               int ret;
+               struct lxc_netdev *netdev = iterator->elem;
+
+               /* Receive network device name in the child's namespace to
+                * parent.
+                */
+               ret = recv(data_sock, netdev->name, IFNAMSIZ, 0);
+               if (ret < 0)
+                       return -1;
+
+               /* Receive network device ifindex in the child's namespace to
+                * parent.
+                */
+               ret = recv(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), 0);
+               if (ret < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+void lxc_delete_network(struct lxc_handler *handler)
+{
+       bool bret;
+
+       if (handler->am_root)
+               bret = lxc_delete_network_priv(handler);
+       else
+               bret = lxc_delete_network_unpriv(handler);
+       if (!bret)
+               DEBUG("Failed to delete network devices");
+       else
+               DEBUG("Deleted network devices");
+}
index aa19dae33c35fffab498344583f32d31bbf9d836..3bacdc2b0b2c32941f63a2439dceb3fc528a28a4 100644 (file)
 #ifndef __LXC_NETWORK_H
 #define __LXC_NETWORK_H
 
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include "list.h"
+
+struct lxc_conf;
+struct lxc_handler;
+struct lxc_netdev;
+
+enum {
+       LXC_NET_EMPTY,
+       LXC_NET_VETH,
+       LXC_NET_MACVLAN,
+       LXC_NET_PHYS,
+       LXC_NET_VLAN,
+       LXC_NET_NONE,
+       LXC_NET_MAXCONFTYPE,
+};
+
 /*
- * Convert a string mac address to a socket structure
+ * Defines the structure to configure an ipv4 address
+ * @address   : ipv4 address
+ * @broadcast : ipv4 broadcast address
+ * @mask      : network mask
  */
-extern int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr);
+struct lxc_inetdev {
+       struct in_addr addr;
+       struct in_addr bcast;
+       unsigned int prefix;
+};
+
+struct lxc_route {
+       struct in_addr addr;
+};
 
 /*
- * Move a device between namespaces
+ * Defines the structure to configure an ipv6 address
+ * @flags     : set the address up
+ * @address   : ipv6 address
+ * @broadcast : ipv6 broadcast address
+ * @mask      : network mask
+ */
+struct lxc_inet6dev {
+       struct in6_addr addr;
+       struct in6_addr mcast;
+       struct in6_addr acast;
+       unsigned int prefix;
+};
+
+struct lxc_route6 {
+       struct in6_addr addr;
+};
+
+/* Contains information about the host side veth device.
+ * @pair    : Name of the host side veth device.
+ *            If the user requested that the host veth device be created with a
+ *            specific names this field will be set. If this field is set @veth1
+ *            is not set.
+ * @veth1   : Name of the host side veth device.
+ *            If the user did not request that the host veth device be created
+ *            with a specific name this field will be set. If this field is set
+ *            @pair is not set.
+ * @ifindex : Ifindex of the network device.
+ */
+struct ifla_veth {
+       char pair[IFNAMSIZ];
+       char veth1[IFNAMSIZ];
+       int ifindex;
+};
+
+struct ifla_vlan {
+       unsigned int   flags;
+       unsigned int   fmask;
+       unsigned short   vid;
+       unsigned short   pad;
+};
+
+struct ifla_macvlan {
+       int mode; /* private, vepa, bridge, passthru */
+};
+
+/* Contains information about the physical network device as seen from the host.
+ * @ifindex : The ifindex of the physical network device in the host's network
+ *            namespace.
  */
-extern int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname);
-extern int lxc_netdev_move_by_name(const char *ifname, pid_t pid, const char* newname);
+struct ifla_phys {
+       int ifindex;
+};
+
+union netdev_p {
+       struct ifla_macvlan macvlan_attr;
+       struct ifla_phys phys_attr;
+       struct ifla_veth veth_attr;
+       struct ifla_vlan vlan_attr;
+};
 
 /*
- * Delete a network device
+ * Defines a structure to configure a network device
+ * @idx               : network counter
+ * @ifindex           : ifindex of the network device
+ *                      Note that this is the ifindex of the network device in
+ *                      the container's network namespace. If the network device
+ *                      consists of a pair of network devices (e.g. veth pairs
+ *                      attached to a network bridge) then this index cannot be
+ *                      used to identify or modify the host veth device. See
+ *                      struct ifla_veth for the host side information.
+ * @type              : network type (veth, macvlan, vlan, ...)
+ * @flags             : flag of the network device (IFF_UP, ... )
+ * @link              : lxc.net.[i].link, name of bridge or host iface to attach
+ *                      if any
+ * @name              : lxc.net.[i].name, name of iface on the container side
+ * @hwaddr            : mac address
+ * @mtu               : maximum transmission unit
+ * @priv              : information specific to the specificed network type
+ *                      Note that this is a union so whether accessing a struct
+ *                      is possible is dependent on the network type.
+ * @ipv4              : a list of ipv4 addresses to be set on the network device
+ * @ipv6              : a list of ipv6 addresses to be set on the network device
+ * @ipv4_gateway_auto : whether the ipv4 gateway is to be automatically gathered
+ *                      from the associated @link
+ * @ipv4_gateway      : ipv4 gateway
+ * @ipv6_gateway_auto : whether the ipv6 gateway is to be automatically gathered
+ *                      from the associated @link
+ * @ipv6_gateway      : ipv6 gateway
+ * @upscript          : a script filename to be executed during interface
+ *                      configuration
+ * @downscript        : a script filename to be executed during interface
+ *                      destruction
  */
+struct lxc_netdev {
+       ssize_t idx;
+       int ifindex;
+       int type;
+       int flags;
+       char link[IFNAMSIZ];
+       char name[IFNAMSIZ];
+       char *hwaddr;
+       char *mtu;
+       union netdev_p priv;
+       struct lxc_list ipv4;
+       struct lxc_list ipv6;
+       bool ipv4_gateway_auto;
+       struct in_addr *ipv4_gateway;
+       bool ipv6_gateway_auto;
+       struct in6_addr *ipv6_gateway;
+       char *upscript;
+       char *downscript;
+};
+
+/* Convert a string mac address to a socket structure. */
+extern int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr);
+
+/* Move a device between namespaces. */
+extern int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char *ifname);
+extern int lxc_netdev_move_by_name(const char *ifname, pid_t pid,
+                                  const char *newname);
+
+/* Delete a network device. */
 extern int lxc_netdev_delete_by_name(const char *name);
 extern int lxc_netdev_delete_by_index(int ifindex);
 
-/*
- * Change the device name
- */
+/* Change the device name. */
 extern int lxc_netdev_rename_by_name(const char *oldname, const char *newname);
 extern int lxc_netdev_rename_by_index(int ifindex, const char *newname);
 
 extern int netdev_set_flag(const char *name, int flag);
 
-/*
- * Set the device network up or down
- */
-
+/* Set the device network up or down. */
 extern int lxc_netdev_isup(const char *name);
 extern int lxc_netdev_up(const char *name);
 extern int lxc_netdev_down(const char *name);
 
-/*
- * Change the mtu size for the specified device
- */
+/* Change the mtu size for the specified device. */
 extern int lxc_netdev_set_mtu(const char *name, int mtu);
 
-/*
- * Create a virtual network devices
- */
+/* Create a virtual network devices. */
 extern int lxc_veth_create(const char *name1, const char *name2);
 extern int lxc_macvlan_create(const char *master, const char *name, int mode);
-extern int lxc_vlan_create(const char *master, const char *name, unsigned short vid);
+extern int lxc_vlan_create(const char *master, const char *name,
+                          unsigned short vid);
 
-/*
- * Activate forwarding
- */
+/* Activate forwarding.*/
 extern int lxc_ip_forward_on(const char *name, int family);
 
-/*
- * Disable forwarding
- */
+/* Disable forwarding. */
 extern int lxc_ip_forward_off(const char *name, int family);
 
-/*
- * Set ip address
- */
+/* Set ip address. */
 extern int lxc_ipv6_addr_add(int ifindex, struct in6_addr *addr,
                             struct in6_addr *mcast,
                             struct in6_addr *acast, int prefix);
@@ -88,57 +221,62 @@ extern int lxc_ipv6_addr_add(int ifindex, struct in6_addr *addr,
 extern int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr,
                             struct in_addr *bcast, int prefix);
 
-/*
- * Get ip address
- */
+/* Get ip address. */
 extern int lxc_ipv4_addr_get(int ifindex, struct in_addr **res);
 extern int lxc_ipv6_addr_get(int ifindex, struct in6_addr **res);
 
-/*
- * Set a destination route to an interface
- */
+/* Set a destination route to an interface. */
 extern int lxc_ipv4_dest_add(int ifindex, struct in_addr *dest);
 extern int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest);
 
-/*
- * Set default route.
- */
+/* Set default route. */
 extern int lxc_ipv4_gateway_add(int ifindex, struct in_addr *gw);
 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 *lxcpath, const char *name, const char *bridge, const char *ifname);
+/* Attach an interface to the bridge. */
+extern int lxc_bridge_attach(const char *bridge, const char *ifname);
+extern int lxc_ovs_delete_port(const char *bridge, const char *nic);
 
-/*
- * Create default gateway
- */
+extern bool is_ovs_bridge(const char *bridge);
+
+/* Create default gateway. */
 extern int lxc_route_create_default(const char *addr, const char *ifname,
                                    int gateway);
 
-/*
- * Delete default gateway
- */
+/* Delete default gateway. */
 extern int lxc_route_delete_default(const char *addr, const char *ifname,
                                    int gateway);
 
-/*
- * Activate neighbor proxying
- */
+/* Activate neighbor proxying. */
 extern int lxc_neigh_proxy_on(const char *name, int family);
 
-/*
- * Disable neighbor proxying
- */
+/* Disable neighbor proxying. */
 extern int lxc_neigh_proxy_off(const char *name, int family);
 
-/*
- * Generate a new unique network interface name
+/* Generate a new unique network interface name.
+ * Allocated memory must be freed by caller.
  */
 extern char *lxc_mkifname(char *template);
 
 extern const char *lxc_net_type_to_str(int type);
 extern int setup_private_host_hw_addr(char *veth1);
 extern int netdev_get_mtu(int ifindex);
-#endif
+extern int lxc_create_network_priv(struct lxc_handler *handler);
+extern int lxc_network_move_created_netdev_priv(const char *lxcpath,
+                                               char *lxcname,
+                                               struct lxc_list *network,
+                                               pid_t pid);
+extern void lxc_delete_network(struct lxc_handler *handler);
+extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
+extern int lxc_create_network_unpriv(const char *lxcpath, char *lxcname,
+                                    struct lxc_list *network, pid_t pid);
+extern int lxc_requests_empty_network(struct lxc_handler *handler);
+extern int lxc_restore_phys_nics_to_netns(struct lxc_handler *handler);
+extern int lxc_setup_network_in_child_namespaces(const struct lxc_conf *conf,
+                                                struct lxc_list *network);
+extern int lxc_network_send_veth_names_to_child(struct lxc_handler *handler);
+extern int lxc_network_recv_veth_names_from_parent(struct lxc_handler *handler);
+extern int lxc_network_send_name_and_ifindex_to_parent(struct lxc_handler *handler);
+extern int lxc_network_recv_name_and_ifindex_from_child(struct lxc_handler *handler);
+
+#endif /* __LXC_NETWORK_H */
index f194efcf2bb920a7cd1c22995d3f8718e241657a..994c960df1151d3e3f13f7d6d289d663fcd20ac9 100644 (file)
@@ -156,7 +156,7 @@ extern struct nlmsg *nlmsg_alloc_reserve(size_t size)
        if (!nlmsg)
                return NULL;
 
-       // just set message length to cap directly
+       /* Just set message length to cap directly. */
        nlmsg->nlmsghdr->nlmsg_len = nlmsg->cap;
        return nlmsg;
 }
@@ -178,14 +178,14 @@ extern int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer)
                .iov_base = answer->nlmsghdr,
                .iov_len = answer->nlmsghdr->nlmsg_len,
        };
-       
+
        struct msghdr msg = {
                .msg_name = &nladdr,
                .msg_namelen = sizeof(nladdr),
                .msg_iov = &iov,
                .msg_iovlen = 1,
        };
-       
+
        memset(&nladdr, 0, sizeof(nladdr));
        nladdr.nl_family = AF_NETLINK;
        nladdr.nl_pid = 0;
@@ -223,7 +223,7 @@ extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg)
                .msg_iovlen = 1,
        };
        int ret;
-       
+
        memset(&nladdr, 0, sizeof(nladdr));
        nladdr.nl_family = AF_NETLINK;
        nladdr.nl_pid = 0;
index b8eef7f04eaeb141a2f77e95a32299ff9d16aa4d..9242763e991b21f3b346641a52f4fdc7590f029a 100644 (file)
@@ -51,8 +51,9 @@ int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data)
        while (getline(&line, &len, f) != -1) {
                err = callback(line, data);
                if (err) {
-                       // callback rv > 0 means stop here
-                       // callback rv < 0 means error
+                       /* Callback rv > 0 means stop here callback rv < 0 means
+                        * error.
+                        */
                        if (err < 0)
                                ERROR("Failed to parse config: %s", line);
                        break;
index 186c788a01344b6ebda9eb8a7a832b5af616126e..dd8f095f17d05fa237c27f0d219b0ff9d0212683 100644 (file)
@@ -54,20 +54,24 @@ extern int rtnetlink_send(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg)
 }
 
 extern int rtnetlink_transaction(struct rtnl_handler *handler,
-                         struct rtnlmsg *request, struct rtnlmsg *answer)
+                                struct rtnlmsg *request,
+                                struct rtnlmsg *answer)
 {
-       return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr,
+       return netlink_transaction(&handler->nlh,
+                                  (struct nlmsg *)&request->nlmsghdr,
                                   (struct nlmsg *)&answer->nlmsghdr);
 }
 
 extern struct rtnlmsg *rtnlmsg_alloc(size_t size)
 {
-/*     size_t len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtnlmsghdr))) + size; */
-/*     return  (struct rtnlmsg *)nlmsg_alloc(len); */
+       /*
+       size_t len;
+
+       len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtnlmsghdr))) + size;
+       return (struct rtnlmsg *)nlmsg_alloc(len);
+       */
+
        return NULL;
 }
 
-extern void rtnlmsg_free(struct rtnlmsg *rtnlmsg)
-{
-       free(rtnlmsg);
-}
+extern void rtnlmsg_free(struct rtnlmsg *rtnlmsg) { free(rtnlmsg); }
index d9ad45d71b3ff635c320836609b963471777b766..5d6e5a852dfed7d40ed3539a0cc47bc19feff50d 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
  */
+
 #ifndef __LXC_RTNL_H
 #define __LXC_RTNL_H
 
@@ -35,8 +36,7 @@
  *
  * @nlh: the netlink socket handler
  */
-struct rtnl_handler
-{
+struct rtnl_handler {
        struct nl_handler nlh;
 };
 
@@ -59,7 +59,7 @@ struct rtnlmsg {
  *
  * Returns 0 on success, < 0 otherwise
  */
-int rtnetlink_open(struct rtnl_handler *handler);
+extern int rtnetlink_open(struct rtnl_handler *handler);
 
 /*
  * genetlink_close : close a route netlink socket
@@ -68,7 +68,7 @@ int rtnetlink_open(struct rtnl_handler *handler);
  *
  * Returns 0 on success, < 0 otherwise
  */
-int rtnetlink_close(struct rtnl_handler *handler);
+extern int rtnetlink_close(struct rtnl_handler *handler);
 
 /*
  * rtnetlink_rcv : receive a route netlink socket, it is up
@@ -79,7 +79,7 @@ int rtnetlink_close(struct rtnl_handler *handler);
  *
  * Returns 0 on success, < 0 otherwise
  */
-int rtnetlink_rcv(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg);
+extern int rtnetlink_rcv(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg);
 
 /*
  * rtnetlink_send : send a route netlink socket, it is up
@@ -90,11 +90,12 @@ int rtnetlink_rcv(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg);
  *
  * Returns 0 on success, < 0 otherwise
  */
-int rtnetlink_send(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg);
+extern int rtnetlink_send(struct rtnl_handler *handler,
+                         struct rtnlmsg *rtnlmsg);
 
 struct genlmsg *genlmsg_alloc(size_t size);
 
-void rtnlmsg_free(struct rtnlmsg *rtnlmsg);
+extern void rtnlmsg_free(struct rtnlmsg *rtnlmsg);
 
 /*
  * rtnetlink_transaction : send and receive a route netlink message in one shot
@@ -105,6 +106,8 @@ void rtnlmsg_free(struct rtnlmsg *rtnlmsg);
  *
  * Returns 0 on success, < 0 otherwise
  */
-int rtnetlink_transaction(struct rtnl_handler *handler,
-                         struct rtnlmsg *request, struct rtnlmsg *answer);
-#endif
+extern int rtnetlink_transaction(struct rtnl_handler *handler,
+                                struct rtnlmsg *request,
+                                struct rtnlmsg *answer);
+
+#endif /* __LXC_RTNL_H */
index 7eee8cea7c2909dbd32f4bbbcb12157041e44e8b..deacd12173cb5e3ccfe58d4de042fa90d7118856 100644 (file)
@@ -75,7 +75,7 @@ static uint32_t get_v2_default_action(char *line)
 
        while (*line == ' ')
                line++;
-       // after 'whitelist' or 'blacklist' comes default behavior
+       /* After 'whitelist' or 'blacklist' comes default behavior. */
        if (strncmp(line, "kill", 4) == 0)
                ret_action = SCMP_ACT_KILL;
        else if (strncmp(line, "errno", 5) == 0) {
@@ -94,7 +94,7 @@ static uint32_t get_v2_default_action(char *line)
 
 static const char *get_action_name(uint32_t action)
 {
-       // The upper 16 bits indicate the type of the seccomp action
+       /* The upper 16 bits indicate the type of the seccomp action. */
        switch(action & 0xffff0000){
        case SCMP_ACT_KILL:
                return "kill";
@@ -170,7 +170,7 @@ int get_hostarch(void)
        }
        if (strcmp(uts.machine, "i686") == 0)
                return lxc_seccomp_arch_i386;
-       // no x32 kernels
+       /* no x32 kernels */
        else if (strcmp(uts.machine, "x86_64") == 0)
                return lxc_seccomp_arch_amd64;
        else if (strncmp(uts.machine, "armv7", 5) == 0)
@@ -434,7 +434,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
                remove_trailing_newlines(line);
                INFO("processing: .%s.", line);
                if (line[0] == '[') {
-                       // read the architecture for next set of rules
+                       /* Read the architecture for next set of rules. */
                        if (strcmp(line, "[x86]") == 0 ||
                            strcmp(line, "[X86]") == 0) {
                                if (native_arch != lxc_seccomp_arch_i386 &&
index 9fa208f2bc2042e46bdbb117d15948ae2da26660..402bba5520a30247aa3a6ab11aec93ca9f9052c2 100644 (file)
@@ -5,6 +5,8 @@
  *
  * Authors:
  * Daniel Lezcano <daniel.lezcano at free.fr>
+ * Serge Hallyn <serge@hallyn.com>
+ * Christian Brauner <christian.brauner@ubuntu.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #endif
 
 #include "af_unix.h"
-#include "bdev.h"
 #include "caps.h"
 #include "cgroup.h"
 #include "commands.h"
 #include "commands_utils.h"
 #include "conf.h"
+#include "confile_utils.h"
 #include "console.h"
 #include "error.h"
 #include "log.h"
 #include "lxccontainer.h"
 #include "lxclock.h"
 #include "lxcseccomp.h"
-#include "lxcutmp.h"
 #include "mainloop.h"
 #include "monitor.h"
 #include "namespace.h"
+#include "network.h"
 #include "start.h"
+#include "storage.h"
 #include "storage_utils.h"
 #include "sync.h"
 #include "utils.h"
@@ -88,7 +91,7 @@
 lxc_log_define(lxc_start, lxc);
 
 extern void mod_all_rdeps(struct lxc_container *c, bool inc);
-static bool do_destroy_container(struct lxc_conf *conf);
+static bool do_destroy_container(struct lxc_handler *handler);
 static int lxc_rmdir_onedev_wrapper(void *data);
 static void lxc_destroy_container_on_signal(struct lxc_handler *handler,
                                            const char *name);
@@ -233,6 +236,15 @@ restart:
                    (i < len_fds && fd == fds_to_ignore[i]))
                        continue;
 
+               if (conf) {
+                       for (i = 0; i < LXC_NS_MAX; i++)
+                               if (conf->inherit_ns_fd[i] == fd)
+                                       break;
+
+                       if (i < LXC_NS_MAX)
+                               continue;
+               }
+
                if (current_config && fd == current_config->logfd)
                        continue;
 
@@ -489,16 +501,6 @@ int lxc_poll(const char *name, struct lxc_handler *handler)
                goto out_mainloop_open;
        }
 
-       if (handler->conf->need_utmp_watch) {
-               #if HAVE_LIBCAP
-               if (lxc_utmp_mainloop_add(&descr, handler)) {
-                       ERROR("Failed to add utmp handler to LXC mainloop.");
-                       goto out_mainloop_open;
-               }
-               #else
-                       DEBUG("Not starting utmp handler as CAP_SYS_BOOT cannot be dropped without capabilities support.");
-               #endif
-       }
        TRACE("lxc mainloop is ready");
 
        return lxc_mainloop(&descr, -1);
@@ -544,7 +546,12 @@ struct lxc_handler *lxc_init_handler(const char *name, struct lxc_conf *conf,
 
        memset(handler, 0, sizeof(*handler));
 
-       handler->ttysock[0] = handler->ttysock[1] = -1;
+       /* Note that am_unpriv() checks the effective uid. We probably don't
+        * care if we are real root only if we are running as root so this
+        * should be fine.
+        */
+       handler->am_root = !am_unpriv();
+       handler->data_sock[0] = handler->data_sock[1] = -1;
        handler->conf = conf;
        handler->lxcpath = lxcpath;
        handler->pinfd = -1;
@@ -633,6 +640,9 @@ int lxc_init(const char *name, struct lxc_handler *handler)
 
        if (setenv("LXC_CGNS_AWARE", "1", 1))
                SYSERROR("Failed to set environment variable LXC_CGNS_AWARE=1.");
+
+       if (setenv("LXC_LOG_LEVEL", lxc_log_priority_to_string(handler->conf->loglevel), 1))
+               SYSERROR("Failed to set environment variable LXC_CGNS_AWARE=1.");
        /* End of environment variable setup for hooks. */
 
        TRACE("set environment variables");
@@ -731,8 +741,14 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
                handler->netnsfd = -1;
        }
 
+       cgroup_destroy(handler);
+
        lxc_set_state(name, handler, STOPPED);
 
+       /* close command socket */
+       close(handler->conf->maincmd_fd);
+       handler->conf->maincmd_fd = -1;
+
        if (run_lxc_hooks(name, "post-stop", handler->conf, handler->lxcpath, NULL)) {
                ERROR("Failed to run lxc.hook.post-stop for container \"%s\".", name);
                if (handler->conf->reboot) {
@@ -750,10 +766,6 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
        lxc_console_delete(&handler->conf->console);
        lxc_delete_tty(&handler->conf->tty_info);
 
-       /* close the command socket */
-       close(handler->conf->maincmd_fd);
-       handler->conf->maincmd_fd = -1;
-
        /* The command socket is now closed, no more state clients can register
         * themselves from now on. So free the list of state clients.
         */
@@ -766,16 +778,15 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
                free(cur);
        }
 
-       free(handler->name);
-       if (handler->ttysock[0] != -1) {
-               close(handler->ttysock[0]);
-               close(handler->ttysock[1]);
+       if (handler->data_sock[0] != -1) {
+               close(handler->data_sock[0]);
+               close(handler->data_sock[1]);
        }
 
        if (handler->conf->ephemeral == 1 && handler->conf->reboot != 1)
                lxc_destroy_container_on_signal(handler, name);
 
-       cgroup_destroy(handler);
+       free(handler->name);
        free(handler);
 }
 
@@ -791,120 +802,6 @@ void lxc_abort(const char *name, struct lxc_handler *handler)
        }
 }
 
-#include <sys/reboot.h>
-#include <linux/reboot.h>
-
-/* reboot(LINUX_REBOOT_CMD_CAD_ON) will return -EINVAL in a child pid namespace
- * if container reboot support exists.  Otherwise, it will either succeed or
- * return -EPERM.
- */
-static int container_reboot_supported(void *arg)
-{
-       int *cmd = arg;
-       int ret;
-
-       ret = reboot(*cmd);
-       if (ret == -1 && errno == EINVAL)
-               return 1;
-       return 0;
-}
-
-static int must_drop_cap_sys_boot(struct lxc_conf *conf)
-{
-       FILE *f;
-       int ret, cmd, v, flags;
-       long stack_size = 4096;
-       void *stack = alloca(stack_size);
-       int status;
-       pid_t pid;
-
-       f = fopen("/proc/sys/kernel/ctrl-alt-del", "r");
-       if (!f) {
-               DEBUG("failed to open /proc/sys/kernel/ctrl-alt-del");
-               return 1;
-       }
-
-       ret = fscanf(f, "%d", &v);
-       fclose(f);
-       if (ret != 1) {
-               DEBUG("Failed to read /proc/sys/kernel/ctrl-alt-del.");
-               return 1;
-       }
-       cmd = v ? LINUX_REBOOT_CMD_CAD_ON : LINUX_REBOOT_CMD_CAD_OFF;
-
-       flags = CLONE_NEWPID | SIGCHLD;
-       if (!lxc_list_empty(&conf->id_map))
-               flags |= CLONE_NEWUSER;
-
-#ifdef __ia64__
-       pid = __clone2(container_reboot_supported, stack, stack_size, flags,  &cmd);
-#else
-       stack += stack_size;
-       pid = clone(container_reboot_supported, stack, flags, &cmd);
-#endif
-       if (pid < 0) {
-               if (flags & CLONE_NEWUSER)
-                       ERROR("Failed to clone (%#x): %s (includes CLONE_NEWUSER).", flags, strerror(errno));
-               else
-                       ERROR("Failed to clone (%#x): %s.", flags, strerror(errno));
-               return -1;
-       }
-       if (wait(&status) < 0) {
-               SYSERROR("Unexpected wait error: %s.", strerror(errno));
-               return -1;
-       }
-
-       if (WEXITSTATUS(status) != 1)
-               return 1;
-
-       return 0;
-}
-
-/* netpipe is used in the unprivileged case to transfer the ifindexes from
- * parent to child
- */
-static int netpipe = -1;
-
-static inline int count_veths(struct lxc_list *network)
-{
-       struct lxc_list *iterator;
-       struct lxc_netdev *netdev;
-       int count = 0;
-
-       lxc_list_for_each(iterator, network) {
-               netdev = iterator->elem;
-               if (netdev->type != LXC_NET_VETH)
-                       continue;
-               count++;
-       }
-       return count;
-}
-
-static int read_unpriv_netifindex(struct lxc_list *network)
-{
-       struct lxc_list *iterator;
-       struct lxc_netdev *netdev;
-
-       if (netpipe == -1)
-               return 0;
-       lxc_list_for_each(iterator, network) {
-               netdev = iterator->elem;
-               if (netdev->type != LXC_NET_VETH)
-                       continue;
-               if (!(netdev->name = malloc(IFNAMSIZ))) {
-                       ERROR("Out of memory.");
-                       close(netpipe);
-                       return -1;
-               }
-               if (read(netpipe, netdev->name, IFNAMSIZ) != IFNAMSIZ) {
-                       close(netpipe);
-                       return -1;
-               }
-       }
-       close(netpipe);
-       return 0;
-}
-
 static int do_start(void *data)
 {
        struct lxc_list *iterator;
@@ -957,8 +854,10 @@ static int do_start(void *data)
        if (lxc_sync_barrier_parent(handler, LXC_SYNC_CONFIGURE))
                return -1;
 
-       if (read_unpriv_netifindex(&handler->conf->network) < 0)
+       if (lxc_network_recv_veth_names_from_parent(handler) < 0) {
+               ERROR("Failed to receive veth names from parent");
                goto out_warn_father;
+       }
 
        /* If we are in a new user namespace, become root there to have
         * privilege over our namespace.
@@ -979,16 +878,6 @@ static int do_start(void *data)
                goto out_warn_father;
        }
 
-       #if HAVE_LIBCAP
-       if (handler->conf->need_utmp_watch) {
-               if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
-                       SYSERROR("Failed to remove the CAP_SYS_BOOT capability.");
-                       goto out_warn_father;
-               }
-               DEBUG("Dropped the CAP_SYS_BOOT capability.");
-       }
-       #endif
-
        ret = snprintf(path, sizeof(path), "%s/dev/null", handler->conf->rootfs.mount);
        if (ret < 0 || ret >= sizeof(path))
                goto out_warn_father;
@@ -1036,8 +925,22 @@ static int do_start(void *data)
                INFO("Unshared CLONE_NEWCGROUP.");
        }
 
+       /* Add the requested environment variables to the current environment to
+        * allow them to be used by the various hooks, such as the start hook
+        * above.
+        */
+       lxc_list_for_each(iterator, &handler->conf->environment) {
+               if (putenv((char *)iterator->elem)) {
+                       SYSERROR("Failed to set environment variable: %s.", (char *)iterator->elem);
+                       goto out_warn_father;
+               }
+       }
+
        /* Setup the container, ip, names, utsname, ... */
-       if (lxc_setup(handler)) {
+       ret = lxc_setup(handler);
+       close(handler->data_sock[0]);
+       close(handler->data_sock[1]);
+       if (ret < 0) {
                ERROR("Failed to setup container \"%s\".", handler->name);
                goto out_warn_father;
        }
@@ -1082,37 +985,34 @@ static int do_start(void *data)
                goto out_warn_father;
        }
 
-       /* The container has been setup. We can now switch to an unprivileged
-        * uid/gid.
-        */
-       if (handler->conf->is_execute) {
-               bool have_cap_setgid;
-               uid_t new_uid = handler->conf->init_uid;
-               gid_t new_gid = handler->conf->init_gid;
+       close(handler->sigfd);
 
-               /* If we are in a new user namespace we already dropped all
-                * groups when we switched to root in the new user namespace
-                * further above. Only drop groups if we can, so ensure that we
-                * have necessary privilege.
-                */
-               #if HAVE_LIBCAP
-               have_cap_setgid = lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE);
-               #else
-               have_cap_setgid = false;
-               #endif
-               if (lxc_list_empty(&handler->conf->id_map) && have_cap_setgid) {
-                       if (lxc_setgroups(0, NULL) < 0)
-                               goto out_warn_father;
-               }
+       if (devnull_fd < 0) {
+               devnull_fd = open_devnull();
 
-               if (lxc_switch_uid_gid(new_uid, new_gid) < 0)
+               if (devnull_fd < 0)
                        goto out_warn_father;
        }
 
-       /* The clearenv() and putenv() calls have been moved here to allow us to
-        * use environment variables passed to the various hooks, such as the
-        * start hook above. Not all of the variables like CONFIG_PATH or ROOTFS
-        * are valid in this context but others are.
+       if (handler->conf->console.slave < 0 && handler->backgrounded)
+               if (set_stdfds(devnull_fd) < 0) {
+                       ERROR("Failed to redirect std{in,out,err} to "
+                             "\"/dev/null\"");
+                       goto out_warn_father;
+               }
+
+       if (devnull_fd >= 0) {
+               close(devnull_fd);
+               devnull_fd = -1;
+       }
+
+       setsid();
+
+       if (lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP_LIMITS))
+               goto out_warn_father;
+
+       /* Reset the environment variables the user requested in a clear
+        * environment.
         */
        if (clearenv()) {
                SYSERROR("Failed to clear environment.");
@@ -1138,32 +1038,33 @@ static int do_start(void *data)
                }
        }
 
-       close(handler->sigfd);
-
-       if (devnull_fd < 0) {
-               devnull_fd = open_devnull();
-
-               if (devnull_fd < 0)
-                       goto out_warn_father;
-       }
+       /* The container has been setup. We can now switch to an unprivileged
+        * uid/gid.
+        */
+       if (handler->conf->is_execute) {
+               bool have_cap_setgid;
+               uid_t new_uid = handler->conf->init_uid;
+               gid_t new_gid = handler->conf->init_gid;
 
-       if (handler->conf->console.slave < 0 && handler->backgrounded)
-               if (set_stdfds(devnull_fd) < 0) {
-                       ERROR("Failed to redirect std{in,out,err} to "
-                             "\"/dev/null\"");
-                       goto out_warn_father;
+               /* If we are in a new user namespace we already dropped all
+                * groups when we switched to root in the new user namespace
+                * further above. Only drop groups if we can, so ensure that we
+                * have necessary privilege.
+                */
+               #if HAVE_LIBCAP
+               have_cap_setgid = lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE);
+               #else
+               have_cap_setgid = false;
+               #endif
+               if (lxc_list_empty(&handler->conf->id_map) && have_cap_setgid) {
+                       if (lxc_setgroups(0, NULL) < 0)
+                               goto out_warn_father;
                }
 
-       if (devnull_fd >= 0) {
-               close(devnull_fd);
-               devnull_fd = -1;
+               if (lxc_switch_uid_gid(new_uid, new_gid) < 0)
+                       goto out_warn_father;
        }
 
-       setsid();
-
-       if (lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP_LIMITS))
-               goto out_warn_father;
-
        /* After this call, we are in error because this ops should not return
         * as it execs.
         */
@@ -1182,46 +1083,14 @@ out_error:
        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;
-
-               if (netdev->type != LXC_NET_PHYS)
-                       continue;
-               conf->saved_nics = realloc(conf->saved_nics,
-                               (conf->num_savednics+1)*sizeof(struct saved_nic));
-               if (!conf->saved_nics)
-                       return -1;
-               conf->saved_nics[conf->num_savednics].ifindex = netdev->ifindex;
-               conf->saved_nics[conf->num_savednics].orig_name = strdup(netdev->link);
-               if (!conf->saved_nics[conf->num_savednics].orig_name)
-                       return -1;
-               INFO("Stored saved_nic #%d idx %d name %s.", conf->num_savednics,
-                       conf->saved_nics[conf->num_savednics].ifindex,
-                       conf->saved_nics[conf->num_savednics].orig_name);
-               conf->num_savednics++;
-       }
-
-       return 0;
-}
-
 static int lxc_recv_ttys_from_child(struct lxc_handler *handler)
 {
        int i;
-       int *ttyfds;
        struct lxc_pty_info *pty_info;
        int ret = -1;
-       int sock = handler->ttysock[1];
+       int sock = handler->data_sock[1];
        struct lxc_conf *conf = handler->conf;
        struct lxc_tty_info *tty_info = &conf->tty_info;
-       size_t num_ttyfds = (2 * conf->tty);
 
        if (!conf->tty)
                return 0;
@@ -1230,36 +1099,34 @@ static int lxc_recv_ttys_from_child(struct lxc_handler *handler)
        if (!tty_info->pty_info)
                return -1;
 
-       ttyfds = malloc(num_ttyfds * sizeof(int));
-       if (!ttyfds)
-               return -1;
+       for (i = 0; i < conf->tty; i++) {
+               int ttyfds[2];
 
-       ret = lxc_abstract_unix_recv_fds(sock, ttyfds, num_ttyfds, NULL, 0);
-       for (i = 0; (ret >= 0 && *ttyfds != -1) && (i < num_ttyfds); i++) {
-               pty_info = &tty_info->pty_info[i / 2];
+               ret = lxc_abstract_unix_recv_fds(sock, ttyfds, 2, NULL, 0);
+               if (ret < 0)
+                       break;
+
+               pty_info = &tty_info->pty_info[i];
                pty_info->busy = 0;
-               pty_info->slave = ttyfds[i++];
-               pty_info->master = ttyfds[i];
-               TRACE("received pty with master fd %d and slave fd %d from "
+               pty_info->master = ttyfds[0];
+               pty_info->slave = ttyfds[1];
+               TRACE("Received pty with master fd %d and slave fd %d from "
                      "parent", pty_info->master, pty_info->slave);
        }
-
-       tty_info->nbtty = conf->tty;
-
-       free(ttyfds);
-
        if (ret < 0)
-               ERROR("failed to receive %d ttys from child: %s", conf->tty,
+               ERROR("Failed to receive %d ttys from child: %s", conf->tty,
                      strerror(errno));
        else
-               TRACE("received %d ttys from child", conf->tty);
+               TRACE("Received %d ttys from child", conf->tty);
+
+       tty_info->nbtty = conf->tty;
 
        return ret;
 }
 
 void resolve_clone_flags(struct lxc_handler *handler)
 {
-       handler->clone_flags = CLONE_NEWPID | CLONE_NEWNS;
+       handler->clone_flags = CLONE_NEWNS;
 
        if (!lxc_list_empty(&handler->conf->id_map))
                handler->clone_flags |= CLONE_NEWUSER;
@@ -1280,6 +1147,11 @@ void resolve_clone_flags(struct lxc_handler *handler)
                handler->clone_flags |= CLONE_NEWUTS;
        else
                INFO("Inheriting a UTS namespace.");
+
+       if (handler->conf->inherit_ns_fd[LXC_NS_PID] == -1)
+               handler->clone_flags |= CLONE_NEWPID;
+       else
+               INFO("Inheriting a PID namespace.");
 }
 
 /* lxc_spawn() performs crucial setup tasks and clone()s the new process which
@@ -1291,16 +1163,15 @@ void resolve_clone_flags(struct lxc_handler *handler)
  */
 static int lxc_spawn(struct lxc_handler *handler)
 {
-       int failed_before_rename = 0;
+       int i, flags, ret;
        const char *name = handler->name;
-       bool cgroups_connected = false;
-       int saved_ns_fd[LXC_NS_MAX];
-       int preserve_mask = 0, i, flags;
-       int netpipepair[2], nveths;
+       char pidstr[20];
        bool wants_to_map_ids;
+       int saved_ns_fd[LXC_NS_MAX];
        struct lxc_list *id_map;
+       int preserve_mask = 0;
+       bool cgroups_connected = false;
 
-       netpipe = -1;
        id_map = &handler->conf->id_map;
        wants_to_map_ids = !lxc_list_empty(id_map);
 
@@ -1311,7 +1182,9 @@ static int lxc_spawn(struct lxc_handler *handler)
        if (lxc_sync_init(handler))
                return -1;
 
-       if (socketpair(AF_UNIX, SOCK_DGRAM, 0, handler->ttysock) < 0) {
+       ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
+                        handler->data_sock);
+       if (ret < 0) {
                lxc_sync_fini(handler);
                return -1;
        }
@@ -1335,17 +1208,12 @@ static int lxc_spawn(struct lxc_handler *handler)
                        /* That should be done before the clone because we will
                         * fill the netdev index and use them in the child.
                         */
-                       if (lxc_setup_networks_in_parent_namespaces(handler)) {
+                       if (lxc_create_network_priv(handler)) {
                                ERROR("Failed to create the network.");
                                lxc_sync_fini(handler);
                                return -1;
                        }
                }
-
-               if (save_phys_nics(handler->conf)) {
-                       ERROR("Failed to save physical nic info.");
-                       goto out_abort;
-               }
        }
 
        if (!cgroup_init(handler)) {
@@ -1376,15 +1244,6 @@ static int lxc_spawn(struct lxc_handler *handler)
        if (attach_ns(handler->conf->inherit_ns_fd) < 0)
                goto out_delete_net;
 
-       if (am_unpriv() && (nveths = count_veths(&handler->conf->network))) {
-               if (pipe(netpipepair) < 0) {
-                       SYSERROR("Failed to create pipe.");
-                       goto out_delete_net;
-               }
-               /* Store netpipe in the global var for do_start's use. */
-               netpipe = netpipepair[0];
-       }
-
        /* Create a process in a new set of namespaces. */
        flags = handler->clone_flags;
        if (handler->clone_flags & CLONE_NEWUSER) {
@@ -1400,6 +1259,7 @@ static int lxc_spawn(struct lxc_handler *handler)
                SYSERROR("Failed to clone a new set of namespaces.");
                goto out_delete_net;
        }
+
        for (i = 0; i < LXC_NS_MAX; i++)
                if (flags & ns_info[i].clone_flag)
                        INFO("Cloned %s.", ns_info[i].flag_name);
@@ -1423,15 +1283,11 @@ static int lxc_spawn(struct lxc_handler *handler)
                goto out_delete_net;
        }
 
-       if (lxc_sync_wake_child(handler, LXC_SYNC_STARTUP)) {
-               failed_before_rename = 1;
+       if (lxc_sync_wake_child(handler, LXC_SYNC_STARTUP))
                goto out_delete_net;
-       }
 
-       if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE)) {
-               failed_before_rename = 1;
+       if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE))
                goto out_delete_net;
-       }
 
        if (!cgroup_create_legacy(handler)) {
                ERROR("Failed to setup legacy cgroups for container \"%s\".", name);
@@ -1448,33 +1304,33 @@ static int lxc_spawn(struct lxc_handler *handler)
        if (!cgroup_chown(handler))
                goto out_delete_net;
 
-       if (failed_before_rename)
+       handler->netnsfd = lxc_preserve_ns(handler->pid, "net");
+       if (handler->netnsfd < 0) {
+               ERROR("Failed to preserve network namespace");
                goto out_delete_net;
+       }
 
        /* Create the network configuration. */
        if (handler->clone_flags & CLONE_NEWNET) {
-               if (lxc_assign_network(handler->lxcpath, handler->name,
-                                      &handler->conf->network, handler->pid)) {
+               if (lxc_network_move_created_netdev_priv(handler->lxcpath,
+                                                        handler->name,
+                                                        &handler->conf->network,
+                                                        handler->pid)) {
                        ERROR("Failed to create the configured network.");
                        goto out_delete_net;
                }
-       }
-
-       if (netpipe != -1) {
-               struct lxc_list *iterator;
-               struct lxc_netdev *netdev;
 
-               close(netpipe);
-               lxc_list_for_each(iterator, &handler->conf->network) {
-                       netdev = iterator->elem;
-                       if (netdev->type != LXC_NET_VETH)
-                               continue;
-                       if (write(netpipepair[1], netdev->name, IFNAMSIZ) != IFNAMSIZ) {
-                               ERROR("Error writing veth name to container.");
-                               goto out_delete_net;
-                       }
+               if (lxc_create_network_unpriv(handler->lxcpath, handler->name,
+                                             &handler->conf->network,
+                                             handler->pid)) {
+                       ERROR("Failed to create the configured network.");
+                       goto out_delete_net;
                }
-               close(netpipepair[1]);
+       }
+
+       if (lxc_network_send_veth_names_to_child(handler) < 0) {
+               ERROR("Failed to send veth names to child");
+               goto out_delete_net;
        }
 
        /* Tell the child to continue its initialization. We'll get
@@ -1500,15 +1356,38 @@ static int lxc_spawn(struct lxc_handler *handler)
        cgroup_disconnect();
        cgroups_connected = false;
 
+       snprintf(pidstr, 20, "%d", handler->pid);
+       if (setenv("LXC_PID", pidstr, 1))
+               SYSERROR("Failed to set environment variable: LXC_PID=%s.", pidstr);
+
+       /* Run any host-side start hooks */
+       if (run_lxc_hooks(name, "start-host", handler->conf, handler->lxcpath, NULL)) {
+               ERROR("Failed to run lxc.hook.start-host for container \"%s\".", name);
+               return -1;
+       }
+
        /* Tell the child to complete its initialization and wait for it to exec
         * or return an error. (The child will never return
-        * LXC_SYNC_POST_CGROUP+1. It will either close the sync pipe, causing
+        * LXC_SYNC_READY_START+1. It will either close the sync pipe, causing
         * lxc_sync_barrier_child to return success, or return a different
         * value, causing us to error out).
         */
-       if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_CGROUP))
+       if (lxc_sync_barrier_child(handler, LXC_SYNC_READY_START))
                return -1;
 
+       if (lxc_network_recv_name_and_ifindex_from_child(handler) < 0) {
+               ERROR("Failed to receive names and ifindices for network "
+                     "devices from child");
+               goto out_delete_net;
+       }
+
+       /* Now all networks are created, network devices are moved into place,
+        * and the correct names and ifindeces in the respective namespaces have
+        * been recorded. The corresponding structs have now all been filled. So
+        * log them for debugging purposes.
+        */
+       lxc_log_configured_netdevs(handler->conf);
+
        /* Read tty fds allocated by child. */
        if (lxc_recv_ttys_from_child(handler) < 0) {
                ERROR("Failed to receive tty info from child process.");
@@ -1525,15 +1404,16 @@ static int lxc_spawn(struct lxc_handler *handler)
        }
 
        lxc_sync_fini(handler);
-       handler->netnsfd = lxc_preserve_ns(handler->pid, "net");
 
        return 0;
 
 out_delete_net:
        if (cgroups_connected)
                cgroup_disconnect();
+
        if (handler->clone_flags & CLONE_NEWNET)
                lxc_delete_network(handler);
+
 out_abort:
        lxc_abort(name, handler);
        lxc_sync_fini(handler);
@@ -1542,6 +1422,11 @@ out_abort:
                handler->pinfd = -1;
        }
 
+       if (handler->netnsfd >= 0) {
+               close(handler->netnsfd);
+               handler->netnsfd = -1;
+       }
+
        return -1;
 }
 
@@ -1551,7 +1436,6 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
 {
        int status;
        int err = -1;
-       bool removed_all_netdevs = true;
        struct lxc_conf *conf = handler->conf;
 
        if (lxc_init(name, handler) < 0) {
@@ -1563,17 +1447,6 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
        handler->backgrounded = backgrounded;
        handler->netnsfd = -1;
 
-       if (must_drop_cap_sys_boot(handler->conf)) {
-               #if HAVE_LIBCAP
-               DEBUG("Dropping CAP_SYS_BOOT capability.");
-               #else
-               DEBUG("Not dropping CAP_SYS_BOOT capability as capabilities aren't supported.");
-               #endif
-       } else {
-               DEBUG("Not dropping CAP_SYS_BOOT or watching utmp.");
-               handler->conf->need_utmp_watch = 0;
-       }
-
        if (!attach_block_device(handler->conf)) {
                ERROR("Failed to attach block device.");
                goto out_fini_nonet;
@@ -1608,10 +1481,6 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
        err = lxc_poll(name, handler);
        if (err) {
                ERROR("LXC mainloop exited with error: %d.", err);
-               if (handler->netnsfd >= 0) {
-                       close(handler->netnsfd);
-                       handler->netnsfd = -1;
-               }
                goto out_abort;
        }
 
@@ -1640,11 +1509,10 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
                }
        }
 
-       DEBUG("Pushing physical nics back to host namespace");
-       lxc_restore_phys_nics_to_netns(handler->netnsfd, handler->conf);
-
-       DEBUG("Tearing down virtual network devices used by container \"%s\".", name);
-       removed_all_netdevs = lxc_delete_network(handler);
+       err = lxc_restore_phys_nics_to_netns(handler);
+       if (err < 0)
+               ERROR("Failed to move physical network devices back to parent "
+                     "network namespace");
 
        if (handler->pinfd >= 0) {
                close(handler->pinfd);
@@ -1653,13 +1521,9 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
 
        lxc_monitor_send_exit_code(name, status, handler->lxcpath);
        err =  lxc_error_set_and_log(handler->pid, status);
+
 out_fini:
-       if (!removed_all_netdevs) {
-               DEBUG("Failed tearing down network devices used by container. Trying again!");
-               removed_all_netdevs = lxc_delete_network(handler);
-               if (!removed_all_netdevs)
-                       DEBUG("Failed tearing down network devices used by container. Not trying again!");
-       }
+       lxc_delete_network(handler);
 
 out_detach_blockdev:
        detach_block_device(handler->conf);
@@ -1708,7 +1572,6 @@ int lxc_start(const char *name, char *const argv[], struct lxc_handler *handler,
                .argv = argv,
        };
 
-       handler->conf->need_utmp_watch = 1;
        return __lxc_start(name, handler, &start_ops, &start_arg, lxcpath, backgrounded);
 }
 
@@ -1720,7 +1583,7 @@ static void lxc_destroy_container_on_signal(struct lxc_handler *handler,
        int ret = 0;
        struct lxc_container *c;
        if (handler->conf->rootfs.path && handler->conf->rootfs.mount) {
-               bret = do_destroy_container(handler->conf);
+               bret = do_destroy_container(handler);
                if (!bret) {
                        ERROR("Error destroying rootfs for container \"%s\".", name);
                        return;
@@ -1746,9 +1609,9 @@ static void lxc_destroy_container_on_signal(struct lxc_handler *handler,
                }
        }
 
-       if (am_unpriv())
-               ret = userns_exec_1(handler->conf, lxc_rmdir_onedev_wrapper,
-                                   destroy, "lxc_rmdir_onedev_wrapper");
+       if (!handler->am_root)
+               ret = userns_exec_full(handler->conf, lxc_rmdir_onedev_wrapper,
+                                      destroy, "lxc_rmdir_onedev_wrapper");
        else
                ret = lxc_rmdir_onedev(destroy, NULL);
 
@@ -1765,12 +1628,17 @@ static int lxc_rmdir_onedev_wrapper(void *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,
-                                 "bdev_destroy_wrapper") < 0)
+static bool do_destroy_container(struct lxc_handler *handler) {
+       int ret;
+
+       if (!handler->am_root) {
+               ret = userns_exec_full(handler->conf, storage_destroy_wrapper,
+                                      handler->conf, "storage_destroy_wrapper");
+               if (ret < 0)
                        return false;
+
                return true;
        }
-       return bdev_destroy(conf);
+
+       return storage_destroy(handler->conf);
 }
index d8d06cfbffef972ef8b5551c10fa1a47eee27c35..5955dfd79d07d2cf1570c65daec55b4357b589dd 100644 (file)
@@ -5,6 +5,8 @@
  *
  * Authors:
  * Daniel Lezcano <daniel.lezcano at free.fr>
+ * Serge Hallyn <serge@hallyn.com>
+ * Christian Brauner <christian.brauner@ubuntu.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #define __LXC_START_H
 
 #include <signal.h>
+#include <stdbool.h>
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <stdbool.h>
 
 #include "conf.h"
 #include "config.h"
-#include "state.h"
 #include "namespace.h"
+#include "state.h"
 
 struct lxc_handler {
-       pid_t pid;
-       char *name;
-       lxc_state_t state;
+       /* The clone flags that were requested. */
        int clone_flags;
-       int sigfd;
-       sigset_t oldmask;
-       struct lxc_conf *conf;
-       struct lxc_operations *ops;
-       void *data;
-       int sv[2];
+
+       /* File descriptors referring to the network namespace of the container. */
+       int netnsfd;
+
+       /* File descriptor to pin the rootfs for privileged containers. */
        int pinfd;
-       const char *lxcpath;
-       void *cgroup_data;
-       int ttysock[2]; // socketpair for child->parent tty fd passing
-       bool backgrounded; // indicates whether should we close std{in,out,err} on start
+
+       /* Signal file descriptor. */
+       int sigfd;
+
+       /* List of file descriptors referring to the namespaces of the
+        * container. Note that these are not necessarily identical to
+        * the "clone_flags" handler field in case namespace inheritance is
+        * requested.
+        */
        int nsfd[LXC_NS_MAX];
-       int netnsfd;
-       /* The socketpair() fds used to wait on successful daemonized
-        * startup.
+
+       /* Abstract unix domain SOCK_DGRAM socketpair to pass arbitrary data
+        * between child and parent.
         */
+       int data_sock[2];
+
+       /* The socketpair() fds used to wait on successful daemonized startup. */
        int state_socket_pair[2];
+
+       /* Socketpair to synchronize processes during container creation. */
+       int sync_sock[2];
+
+       /* The name of the container. */
+       char *name;
+
+       /* The path the container is running in. */
+       const char *lxcpath;
+
+       /* Whether the container's startup process euid is 0. */
+       bool am_root;
+
+       /* Indicates whether should we close std{in,out,err} on start. */
+       bool backgrounded;
+
+       /* The child's pid. */
+       pid_t pid;
+
+       /* The signal mask prior to setting up the signal file descriptor. */
+       sigset_t oldmask;
+
+       /* The container's in-memory configuration. */
+       struct lxc_conf *conf;
+
+       /* A list of clients registered to be informed about a container state. */
        struct lxc_list state_clients;
+
+       /* A set of operations to be performed at various stages of the
+        * container's life.
+        */
+       struct lxc_operations *ops;
+
+       /* This holds the cgroup information. Note that the data here is
+        * specific to the cgroup driver used.
+        */
+       void *cgroup_data;
+
+       /* Data to be passed to handler ops. */
+       void *data;
+
+       /* Current state of the container. */
+       lxc_state_t state;
 };
 
 struct lxc_operations {
@@ -89,8 +138,8 @@ extern void lxc_fini(const char *name, struct lxc_handler *handler);
  */
 extern int lxc_check_inherited(struct lxc_conf *conf, bool closeall,
                               int *fds_to_ignore, size_t len_fds);
-int __lxc_start(const char *, struct lxc_handler *, struct lxc_operations *,
-               void *, const char *, bool);
+extern int __lxc_start(const char *, struct lxc_handler *,
+                      struct lxc_operations *, void *, const char *, bool);
 
 extern void resolve_clone_flags(struct lxc_handler *handler);
 #endif
diff --git a/src/lxc/storage/aufs.c b/src/lxc/storage/aufs.c
new file mode 100644 (file)
index 0000000..a39cd60
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * 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 "aufs.h"
+#include "log.h"
+#include "rsync.h"
+#include "storage.h"
+#include "utils.h"
+
+lxc_log_define(aufs, 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 lxc_rsync_delta(struct rsync_data_char *data)
+{
+       int ret;
+
+       ret = lxc_switch_uid_gid(0, 0);
+       if (ret < 0)
+               return -1;
+
+       ret = lxc_setgroups(0, NULL);
+       if (ret < 0)
+               return -1;
+
+       ret = lxc_rsync_exec(data->src, data->dest);
+       if (ret < 0) {
+               ERROR("Failed to rsync from \"%s\" into \"%s\"", data->src,
+                     data->dest);
+               return -1;
+       }
+
+       return 0;
+}
+
+int lxc_rsync_delta_wrapper(void *data)
+{
+       struct rsync_data_char *arg = data;
+       return lxc_rsync_delta(arg);
+}
+
+int aufs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                   const char *oldname, const char *cname, const char *oldpath,
+                   const char *lxcpath, int snap, uint64_t newsize,
+                   struct lxc_conf *conf)
+{
+       char cmd_output[MAXPATHLEN];
+
+       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_full(conf, lxc_rsync_delta_wrapper,
+                                              &rdata, "lxc_rsync_delta_wrapper");
+               else
+                       ret = run_command(cmd_output, sizeof(cmd_output),
+                                         lxc_rsync_delta_wrapper,
+                                         (void *)&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 lxc_storage *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 lxc_storage *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);
+}
+
+bool aufs_detect(const char *path)
+{
+       if (!strncmp(path, "aufs:", 5))
+               return true;
+
+       return false;
+}
+
+int aufs_mount(struct lxc_storage *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 lxc_storage *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/storage/aufs.h b/src/lxc/storage/aufs.h
new file mode 100644 (file)
index 0000000..7960a3a
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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 <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "storage.h"
+
+struct lxc_storage;
+
+struct bdev_specs;
+
+struct lxc_conf;
+
+struct lxc_rootfs;
+
+int aufs_clonepaths(struct lxc_storage *orig, struct lxc_storage *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 lxc_storage *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs);
+int aufs_destroy(struct lxc_storage *orig);
+bool aufs_detect(const char *path);
+int aufs_mount(struct lxc_storage *bdev);
+int aufs_umount(struct lxc_storage *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/storage/btrfs.c b/src/lxc/storage/btrfs.c
new file mode 100644 (file)
index 0000000..29b44df
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+ * 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/wait.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+
+#include "log.h"
+#include "btrfs.h"
+#include "rsync.h"
+#include "storage.h"
+#include "utils.h"
+
+lxc_log_define(btrfs, lxc);
+
+/*
+ * 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("Failed to lookup path for %llu %llu %s - %s\n",
+                                (unsigned long long) dir_id,
+                                (unsigned long long) objid,
+                                name, strerror(e));
+               return NULL;
+       } else
+               INFO("Got path for %llu %llu - %s\n",
+                       (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;
+}
+
+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;
+}
+
+/*
+ * Taken from btrfs toolsuite. Test if path is a subvolume.
+ *     return 0;   path exists but it is not a subvolume
+ *     return 1;   path exists and it is  a subvolume
+ *     return < 0; error
+ */
+int is_btrfs_subvol(const char *path)
+{
+       struct stat st;
+       struct statfs stfs;
+       int ret;
+
+       ret = stat(path, &st);
+       if (ret < 0)
+               return -errno;
+
+       if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode))
+               return 0;
+
+       ret = statfs(path, &stfs);
+       if (ret < 0)
+               return -errno;
+
+       return stfs.f_type == BTRFS_SUPER_MAGIC;
+}
+
+bool btrfs_detect(const char *path)
+{
+       struct stat st;
+       int ret;
+
+       if (!strncmp(path, "btrfs:", 6))
+               return true;
+
+       if (!is_btrfs_fs(path))
+               return false;
+
+       /* make sure it's a subvolume */
+       ret = stat(path, &st);
+       if (ret < 0)
+               return false;
+
+       if (st.st_ino == 256 && S_ISDIR(st.st_mode))
+               return true;
+
+       return false;
+}
+
+int btrfs_mount(struct lxc_storage *bdev)
+{
+       unsigned long mntflags;
+       char *mntdata, *src;
+       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;
+       }
+
+       src = lxc_storage_get_path(bdev->src, "btrfs");
+
+       ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
+       free(mntdata);
+       return ret;
+}
+
+int btrfs_umount(struct lxc_storage *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, saved_errno;
+       struct btrfs_ioctl_vol_args args;
+       char *p, *newfull;
+       int fd = -1;
+
+       newfull = strdup(path);
+       if (!newfull) {
+               errno = ENOMEM;
+               return -ENOMEM;
+       }
+
+       p = strrchr(newfull, '/');
+       if (!p) {
+               free(newfull);
+               errno = EINVAL;
+               return -EINVAL;
+       }
+       *p = '\0';
+
+       fd = open(newfull, O_RDONLY);
+       if (fd < 0) {
+               free(newfull);
+               return -errno;
+       }
+
+       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);
+       saved_errno = errno;
+
+       close(fd);
+       free(newfull);
+       errno = saved_errno;
+       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)
+{
+       struct btrfs_ioctl_vol_args_v2 args;
+       char *newdir, *newname;
+       char *newfull = NULL;
+       int saved_errno = -1;
+       int fd = -1, fddst = -1, ret = -1;
+
+       newfull = strdup(new);
+       if (!newfull)
+               goto out;
+
+       ret = rmdir(newfull);
+       if (ret < 0 && errno != ENOENT)
+               goto out;
+
+       newname = basename(newfull);
+       fd = open(orig, O_RDONLY);
+       if (fd < 0)
+               goto out;
+
+       newdir = dirname(newfull);
+       fddst = open(newdir, O_RDONLY);
+       if (fddst < 0)
+               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);
+       saved_errno = errno;
+
+out:
+       if (fddst != -1)
+               close(fddst);
+       if (fd != -1)
+               close(fd);
+       free(newfull);
+
+       if (saved_errno >= 0)
+               errno = saved_errno;
+       return ret;
+}
+
+int btrfs_snapshot_wrapper(void *data)
+{
+       char *src;
+       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;
+       }
+
+       src = lxc_storage_get_path(arg->src, "btrfs");
+       return btrfs_snapshot(src, arg->dest);
+}
+
+int btrfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                    const char *oldname, const char *cname,
+                    const char *oldpath, const char *lxcpath, int snap,
+                    uint64_t newsize, struct lxc_conf *conf)
+{
+       char *src;
+
+       if (!orig->dest || !orig->src)
+               return -1;
+
+       if (strcmp(orig->type, "btrfs") && snap) {
+               ERROR("btrfs snapshot from %s backing store is not supported",
+                     orig->type);
+               return -1;
+       }
+
+       new->src = lxc_string_join(
+           "/",
+           (const char *[]){"btrfs:", *lxcpath != '/' ? lxcpath : ++lxcpath,
+                            cname, "rootfs", NULL},
+           false);
+       if (!new->src) {
+               ERROR("Failed to create new rootfs path");
+               return -1;
+       }
+       TRACE("Constructed new rootfs path \"%s\"", new->src);
+
+       src = lxc_storage_get_path(new->src, "btrfs");
+       new->dest = strdup(src);
+       if (!new->dest) {
+               ERROR("Failed to duplicate string \"%s\"", src);
+               return -1;
+       }
+
+       if (orig->mntopts) {
+               new->mntopts = strdup(orig->mntopts);
+               if (!new->mntopts) {
+                       ERROR("Failed to duplicate string \"%s\"",
+                             orig->mntopts);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+bool btrfs_create_clone(struct lxc_conf *conf, struct lxc_storage *orig,
+                       struct lxc_storage *new, uint64_t newsize)
+{
+       int ret;
+       struct rsync_data data = {0, 0};
+       char cmd_output[MAXPATHLEN] = {0};
+
+       ret = rmdir(new->dest);
+       if (ret < 0 && errno != ENOENT)
+               return false;
+
+       ret = btrfs_subvolume_create(new->dest);
+       if (ret < 0) {
+               SYSERROR("Failed to create btrfs subvolume \"%s\"", new->dest);
+               return false;
+       }
+
+       /* rsync the contents from source to target */
+       data.orig = orig;
+       data.new = new;
+       if (am_unpriv()) {
+               ret = userns_exec_full(conf, lxc_storage_rsync_exec_wrapper,
+                                      &data, "lxc_storage_rsync_exec_wrapper");
+               if (ret < 0) {
+                       ERROR("Failed to rsync from \"%s\" into \"%s\"",
+                             orig->dest, new->dest);
+                       return false;
+               }
+
+               return true;
+       }
+
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                       lxc_storage_rsync_exec_wrapper, (void *)&data);
+       if (ret < 0) {
+               ERROR("Failed to rsync from \"%s\" into \"%s\": %s", orig->dest,
+                     new->dest, cmd_output);
+               return false;
+       }
+
+       return true;
+}
+
+bool btrfs_create_snapshot(struct lxc_conf *conf, struct lxc_storage *orig,
+                          struct lxc_storage *new, uint64_t newsize)
+{
+       int ret;
+
+       ret = rmdir(new->dest);
+       if (ret < 0 && errno != ENOENT)
+               return false;
+
+       if (am_unpriv()) {
+               struct rsync_data_char args;
+
+               args.src = orig->dest;
+               args.dest = new->dest;
+
+               ret = userns_exec_1(conf, btrfs_snapshot_wrapper, &args,
+                               "btrfs_snapshot_wrapper");
+               if (ret < 0) {
+                       ERROR("Failed to run \"btrfs_snapshot_wrapper\"");
+                       return false;
+               }
+
+               TRACE("Created btrfs snapshot \"%s\" from \"%s\"", new->dest,
+                     orig->dest);
+               return true;
+       }
+
+       ret = btrfs_snapshot(orig->dest, new->dest);
+       if (ret < 0) {
+               SYSERROR("Failed to create btrfs snapshot \"%s\" from \"%s\"",
+                        new->dest, orig->dest);
+               return false;
+       }
+
+       TRACE("Created btrfs snapshot \"%s\" from \"%s\"", new->dest, orig->dest);
+       return true;
+}
+
+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 lxc_storage *orig)
+{
+       char *src;
+
+       src = lxc_storage_get_path(orig->src, "btrfs");
+
+       return btrfs_recursive_destroy(src);
+}
+
+int btrfs_create(struct lxc_storage *bdev, const char *dest, const char *n,
+                struct bdev_specs *specs)
+{
+       int ret;
+       size_t len;
+
+       len = strlen(dest) + 1;
+       /* strlen("btrfs:") */
+       len += 6;
+       bdev->src = malloc(len);
+       if (!bdev->src) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(bdev->src, len, "btrfs:%s", dest);
+       if (ret < 0 || (size_t)ret >= len) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       bdev->dest = strdup(dest);
+       if (!bdev->dest) {
+               ERROR("Failed to duplicate string \"%s\"", dest);
+               return -1;
+       }
+
+       ret = btrfs_subvolume_create(bdev->dest);
+       if (ret < 0) {
+               SYSERROR("Failed to create btrfs subvolume \"%s\"", bdev->dest);
+       }
+
+       return ret;
+}
diff --git a/src/lxc/storage/btrfs.h b/src/lxc/storage/btrfs.h
new file mode 100644 (file)
index 0000000..4bf459a
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * 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>
+
+#ifndef BTRFS_SUPER_MAGIC
+#  define BTRFS_SUPER_MAGIC       0x9123683E
+#endif
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+struct btrfs_ioctl_space_info {
+       unsigned long long flags;
+       unsigned long long total_bytes;
+       unsigned long long used_bytes;
+};
+
+struct btrfs_ioctl_space_args {
+       unsigned long long space_slots;
+       unsigned long long total_spaces;
+       struct btrfs_ioctl_space_info spaces[];
+};
+
+#define BTRFS_IOCTL_MAGIC 0x94
+#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, unsigned long long)
+#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
+                                    struct btrfs_ioctl_space_args)
+
+#define BTRFS_FSID_SIZE 16
+struct btrfs_ioctl_fs_info_args {
+       unsigned long long max_id;
+       unsigned long long num_devices;
+       char fsid[BTRFS_FSID_SIZE];
+       unsigned long long reserved[124];
+};
+
+#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
+               struct btrfs_ioctl_fs_info_args)
+
+
+#define BTRFS_SUBVOL_NAME_MAX 4039
+#define BTRFS_PATH_NAME_MAX 4087
+
+struct btrfs_ioctl_vol_args {
+       signed long long fd;
+       char name[BTRFS_PATH_NAME_MAX + 1];
+};
+
+#define BTRFS_IOCTL_MAGIC 0x94
+#define BTRFS_IOC_SUBVOL_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 24, \
+                                   struct btrfs_ioctl_vol_args_v2)
+#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
+                                   struct btrfs_ioctl_vol_args_v2)
+#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
+                                   struct btrfs_ioctl_vol_args)
+#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
+                                   struct btrfs_ioctl_vol_args)
+
+#define BTRFS_QGROUP_INHERIT_SET_LIMITS (1ULL << 0)
+
+struct btrfs_ioctl_vol_args_v2 {
+       signed long long fd;
+       unsigned long long transid;
+       unsigned long long flags;
+       union {
+               struct {
+                       unsigned long long size;
+                       /*struct btrfs_qgroup_inherit *qgroup_inherit; */
+                       void *qgroup_inherit;
+               };
+               unsigned long long unused[4];
+       };
+       char name[BTRFS_SUBVOL_NAME_MAX + 1];
+};
+
+/*
+ * root backrefs tie subvols and snapshots to the directory entries that
+ * reference them
+ */
+#define BTRFS_ROOT_BACKREF_KEY  144
+
+/*
+ * root items point to tree roots.  There are typically in the root
+ * tree used by the super block to find all the other trees
+ */
+#define BTRFS_ROOT_ITEM_KEY     132
+
+/*
+ * root refs make a fast index for listing all of the snapshots and
+ * subvolumes referenced by a given root.  They point directly to the
+ * directory item in the root that references the subvol
+ */
+#define BTRFS_ROOT_REF_KEY      156
+
+#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL
+#define BTRFS_DIR_ITEM_KEY      84
+
+/*
+ *  * this is used for both forward and backward root refs
+ *   */
+struct btrfs_root_ref {
+       __le64 dirid;
+       __le64 sequence;
+       __le16 name_len;
+} __attribute__ ((__packed__));
+
+struct btrfs_disk_key {
+       __le64 objectid;
+       u8 type;
+       __le64 offset;
+} __attribute__ ((__packed__));
+
+struct btrfs_dir_item {
+       struct btrfs_disk_key location;
+       __le64 transid;
+       __le16 data_len;
+       __le16 name_len;
+       u8 type;
+} __attribute__ ((__packed__));
+
+#define BTRFS_IOCTL_MAGIC 0x94
+#define BTRFS_VOL_NAME_MAX 255
+#define BTRFS_PATH_NAME_MAX 4087
+
+struct btrfs_ioctl_search_key {
+       /* which root are we searching.  0 is the tree of tree roots */
+       __u64 tree_id;
+
+       /* keys returned will be >= min and <= max */
+       __u64 min_objectid;
+       __u64 max_objectid;
+
+       /* keys returned will be >= min and <= max */
+       __u64 min_offset;
+       __u64 max_offset;
+
+       /* max and min transids to search for */
+       __u64 min_transid;
+       __u64 max_transid;
+
+       /* keys returned will be >= min and <= max */
+       __u32 min_type;
+       __u32 max_type;
+
+       /*
+        * how many items did userland ask for, and how many are we
+        * returning
+        */
+       __u32 nr_items;
+
+       /* align to 64 bits */
+       __u32 unused;
+
+       /* some extra for later */
+       __u64 unused1;
+       __u64 unused2;
+       __u64 unused3;
+       __u64 unused4;
+};
+
+struct btrfs_ioctl_search_header {
+       __u64 transid;
+       __u64 objectid;
+       __u64 offset;
+       __u32 type;
+       __u32 len;
+} __attribute__((may_alias));
+
+#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
+/*
+ * the buf is an array of search headers where
+ * each header is followed by the actual item
+ * the type field is expanded to 32 bits for alignment
+ */
+struct btrfs_ioctl_search_args {
+       struct btrfs_ioctl_search_key key;
+       char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
+};
+
+#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
+                                   struct btrfs_ioctl_search_args)
+#define BTRFS_UUID_SIZE 16
+
+struct btrfs_timespec {
+       __le64 sec;
+       __le32 nsec;
+} __attribute__ ((__packed__));
+
+struct btrfs_inode_item {
+       /* nfs style generation number */
+       __le64 generation;
+       /* transid that last touched this inode */
+       __le64 transid;
+       __le64 size;
+       __le64 nbytes;
+       __le64 block_group;
+       __le32 nlink;
+       __le32 uid;
+       __le32 gid;
+       __le32 mode;
+       __le64 rdev;
+       __le64 flags;
+
+       /* modification sequence number for NFS */
+       __le64 sequence;
+
+       /*
+        * a little future expansion, for more than this we can
+        * just grow the inode item and version it
+        */
+       __le64 reserved[4];
+       struct btrfs_timespec atime;
+       struct btrfs_timespec ctime;
+       struct btrfs_timespec mtime;
+       struct btrfs_timespec otime;
+} __attribute__ ((__packed__));
+
+struct btrfs_root_item_v0 {
+       struct btrfs_inode_item inode;
+       __le64 generation;
+       __le64 root_dirid;
+       __le64 bytenr;
+       __le64 byte_limit;
+       __le64 bytes_used;
+       __le64 last_snapshot;
+       __le64 flags;
+       __le32 refs;
+       struct btrfs_disk_key drop_progress;
+       u8 drop_level;
+       u8 level;
+} __attribute__ ((__packed__));
+
+struct btrfs_root_item {
+       struct btrfs_inode_item inode;
+       __le64 generation;
+       __le64 root_dirid;
+       __le64 bytenr;
+       __le64 byte_limit;
+       __le64 bytes_used;
+       __le64 last_snapshot;
+       __le64 flags;
+       __le32 refs;
+       struct btrfs_disk_key drop_progress;
+       u8 drop_level;
+       u8 level;
+
+       /*
+        * The following fields appear after subvol_uuids+subvol_times
+        * were introduced.
+        */
+
+       /*
+        * This generation number is used to test if the new fields are valid
+        * and up to date while reading the root item. Every time the root item
+        * is written out, the "generation" field is copied into this field. If
+        * anyone ever mounted the fs with an older kernel, we will have
+        * mismatching generation values here and thus must invalidate the
+        * new fields. See btrfs_update_root and btrfs_find_last_root for
+        * details.
+        * the offset of generation_v2 is also used as the start for the memset
+        * when invalidating the fields.
+        */
+       __le64 generation_v2;
+       u8 uuid[BTRFS_UUID_SIZE];
+       u8 parent_uuid[BTRFS_UUID_SIZE];
+       u8 received_uuid[BTRFS_UUID_SIZE];
+       __le64 ctransid; /* updated when an inode changes */
+       __le64 otransid; /* trans when created */
+       __le64 stransid; /* trans when sent. non-zero for received subvol */
+       __le64 rtransid; /* trans when received. non-zero for received subvol */
+       struct btrfs_timespec ctime;
+       struct btrfs_timespec otime;
+       struct btrfs_timespec stime;
+       struct btrfs_timespec rtime;
+       __le64 reserved[8]; /* for future */
+} __attribute__ ((__packed__));
+
+#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
+                                   struct btrfs_ioctl_ino_lookup_args)
+
+#define BTRFS_INO_LOOKUP_PATH_MAX 4080
+struct btrfs_ioctl_ino_lookup_args {
+       __u64 treeid;
+       __u64 objectid;
+       char name[BTRFS_INO_LOOKUP_PATH_MAX];
+};
+
+/*
+ * All files have objectids in this range.
+ */
+#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);
+
+struct lxc_storage;
+
+struct bdev_specs;
+
+struct lxc_conf;
+
+struct mytree_node {
+       u64 objid;
+       u64 parentid;
+       char *name;
+       char *dirname;
+};
+
+struct my_btrfs_tree {
+       struct mytree_node *nodes;
+       int num;
+};
+
+extern int btrfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                           const char *oldname, const char *cname,
+                           const char *oldpath, const char *lxcpath, int snap,
+                           uint64_t newsize, struct lxc_conf *conf);
+extern int btrfs_create(struct lxc_storage *bdev, const char *dest,
+                       const char *n, struct bdev_specs *specs);
+extern int btrfs_destroy(struct lxc_storage *orig);
+extern bool btrfs_detect(const char *path);
+extern int btrfs_mount(struct lxc_storage *bdev);
+extern int btrfs_umount(struct lxc_storage *bdev);
+
+extern char *get_btrfs_subvol_path(int fd, u64 dir_id, u64 objid, char *name,
+                                  int name_len);
+extern int btrfs_list_get_path_rootid(int fd, u64 *treeid);
+extern bool is_btrfs_fs(const char *path);
+extern int is_btrfs_subvol(const char *path);
+extern bool btrfs_try_remove_subvol(const char *path);
+extern int btrfs_same_fs(const char *orig, const char *new);
+extern int btrfs_snapshot(const char *orig, const char *new);
+extern int btrfs_snapshot_wrapper(void *data);
+extern bool btrfs_create_clone(struct lxc_conf *conf, struct lxc_storage *orig,
+                              struct lxc_storage *new, uint64_t newsize);
+extern bool btrfs_create_snapshot(struct lxc_conf *conf,
+                                 struct lxc_storage *orig,
+                                 struct lxc_storage *new, uint64_t newsize);
+
+#endif /* __LXC_BTRFS_H */
diff --git a/src/lxc/storage/dir.c b/src/lxc/storage/dir.c
new file mode 100644 (file)
index 0000000..9a050b2
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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 "log.h"
+#include "storage.h"
+#include "utils.h"
+
+lxc_log_define(dir, lxc);
+
+/* For a simple directory bind mount, we substitute the old container name and
+ * paths for the new.
+ */
+int dir_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                  const char *oldname, const char *cname, const char *oldpath,
+                  const char *lxcpath, int snap, uint64_t newsize,
+                  struct lxc_conf *conf)
+{
+       char *src_no_prefix;
+       int ret;
+       size_t len;
+
+       if (snap) {
+               ERROR("Directories cannot be snapshotted");
+               return -1;
+       }
+
+       if (!orig->dest || !orig->src)
+               return -1;
+
+       len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 4 + 3;
+       new->src = malloc(len);
+       if (!new->src) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(new->src, len, "dir:%s/%s/rootfs", lxcpath, cname);
+       if (ret < 0 || (size_t)ret >= len) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       src_no_prefix = lxc_storage_get_path(new->src, new->type);
+       new->dest = strdup(src_no_prefix);
+       if (!new->dest) {
+               ERROR("Failed to duplicate string \"%s\"", new->src);
+               return -1;
+       }
+
+       TRACE("Created new path \"%s\" for dir storage driver", new->dest);
+       return 0;
+}
+
+int dir_create(struct lxc_storage *bdev, const char *dest, const char *n,
+              struct bdev_specs *specs)
+{
+       int ret;
+       const char *src;
+       size_t len;
+
+       /* strlen("dir:") */
+       len = 4;
+       if (specs && specs->dir)
+               src = specs->dir;
+       else
+               src = dest;
+
+       len += strlen(src) + 1;
+       bdev->src = malloc(len);
+       if (!bdev->src) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(bdev->src, len, "dir:%s", src);
+       if (ret < 0 || (size_t)ret >= len) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       bdev->dest = strdup(dest);
+       if (!bdev->dest) {
+               ERROR("Failed to duplicate string \"%s\"", dest);
+               return -1;
+       }
+
+       ret = mkdir_p(dest, 0755);
+       if (ret < 0) {
+               ERROR("Failed to create directory \"%s\"", dest);
+               return -1;
+       }
+       TRACE("Created directory \"%s\"", dest);
+
+       return 0;
+}
+
+int dir_destroy(struct lxc_storage *orig)
+{
+       int ret;
+       char *src;
+
+       src = lxc_storage_get_path(orig->src, orig->src);
+
+       ret = lxc_rmdir_onedev(src, NULL);
+       if (ret < 0) {
+               ERROR("Failed to delete \"%s\"", src);
+               return -1;
+       }
+
+       return 0;
+}
+
+bool dir_detect(const char *path)
+{
+       if (!strncmp(path, "dir:", 4))
+               return true;
+
+       if (is_dir(path))
+               return true;
+
+       return false;
+}
+
+int dir_mount(struct lxc_storage *bdev)
+{
+       int ret;
+       unsigned long mflags, mntflags;
+       char *src, *mntdata;
+
+       if (strcmp(bdev->type, "dir"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata);
+       if (ret < 0) {
+               ERROR("Failed to parse mount options \"%s\"", bdev->mntopts);
+               free(mntdata);
+               return -22;
+       }
+
+       src = lxc_storage_get_path(bdev->src, bdev->type);
+
+       ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags,
+                   mntdata);
+       if ((0 == ret) && (mntflags & MS_RDONLY)) {
+               DEBUG("Remounting \"%s\" on \"%s\" readonly",
+                     src ? src : "(none)", bdev->dest ? bdev->dest : "(none)");
+               mflags = add_required_remount_flags(src, bdev->dest, MS_BIND | MS_REC | mntflags | MS_REMOUNT);
+               ret = mount(src, bdev->dest, "bind", mflags, mntdata);
+       }
+
+       if (ret < 0) {
+               SYSERROR("Failed to mount \"%s\" on \"%s\"", src, bdev->dest);
+               free(mntdata);
+               return -1;
+       }
+
+       TRACE("Mounted \"%s\" on \"%s\"", src, bdev->dest);
+       free(mntdata);
+       return ret;
+}
+
+int dir_umount(struct lxc_storage *bdev)
+{
+       if (strcmp(bdev->type, "dir"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       return umount(bdev->dest);
+}
diff --git a/src/lxc/storage/dir.h b/src/lxc/storage/dir.h
new file mode 100644 (file)
index 0000000..6858e00
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 <stdbool.h>
+#include <stdint.h>
+
+struct lxc_storage;
+
+struct bdev_specs;
+
+struct lxc_conf;
+
+extern int dir_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                         const char *oldname, const char *cname,
+                         const char *oldpath, const char *lxcpath, int snap,
+                         uint64_t newsize, struct lxc_conf *conf);
+extern int dir_create(struct lxc_storage *bdev, const char *dest, const char *n,
+                     struct bdev_specs *specs);
+extern int dir_destroy(struct lxc_storage *orig);
+extern bool dir_detect(const char *path);
+extern int dir_mount(struct lxc_storage *bdev);
+extern int dir_umount(struct lxc_storage *bdev);
+
+#endif /* __LXC_DIR_H */
diff --git a/src/lxc/storage/loop.c b/src/lxc/storage/loop.c
new file mode 100644 (file)
index 0000000..68a1b0f
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * 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
+#include <dirent.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <linux/loop.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "log.h"
+#include "loop.h"
+#include "storage.h"
+#include "storage_utils.h"
+#include "utils.h"
+
+lxc_log_define(loop, lxc);
+
+static int do_loop_create(const char *path, uint64_t size, const char *fstype);
+
+/*
+ * No idea what the original blockdev will be called, but the copy will be
+ * called $lxcpath/$lxcname/rootdev
+ */
+int loop_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                   const char *oldname, const char *cname, const char *oldpath,
+                   const char *lxcpath, int snap, uint64_t newsize,
+                   struct lxc_conf *conf)
+{
+       uint64_t size = newsize;
+       int len, ret;
+       char *srcdev;
+       char fstype[100] = "ext4";
+
+       if (snap) {
+               ERROR("The loop storage driver does not support snapshots");
+               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) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       new->src = malloc(len + 5);
+       if (!new->src) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(new->src, (len + 5), "loop:%s", srcdev);
+       if (ret < 0 || ret >= (len + 5)) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       new->dest = malloc(len);
+       if (!new->dest) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname);
+       if (ret < 0 || ret >= len) {
+               ERROR("Failed to create string");
+               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)) {
+               /* detect size */
+               if (!newsize && blk_getsize(orig, &size) < 0) {
+                       ERROR("Failed to detect size of loop file \"%s\"",
+                             orig->src);
+                       return -1;
+               }
+
+               /* detect filesystem */
+               if (detect_fs(orig, fstype, 100) < 0) {
+                       INFO("Failed to detect filesystem type for \"%s\"", orig->src);
+                       return -1;
+               }
+       } else if (!newsize) {
+                       size = DEFAULT_FS_SIZE;
+       }
+
+       ret = do_loop_create(srcdev, size, fstype);
+       if (ret < 0) {
+               ERROR("Failed to create loop storage volume \"%s\" with "
+                     "filesystem \"%s\" and size \"%" PRIu64 "\"",
+                     srcdev, fstype, size);
+               return -1;
+       }
+
+       return 0;
+}
+
+int loop_create(struct lxc_storage *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, and <src> will be "loop:<srcdev>".
+        */
+       len = strlen(dest) + 2;
+       srcdev = alloca(len);
+
+       ret = snprintf(srcdev, len, "%s", dest);
+       if (ret < 0 || ret >= len) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       ret = sprintf(srcdev + len - 4, "dev");
+       if (ret < 0) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       bdev->src = malloc(len + 5);
+       if (!bdev->src) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(bdev->src, len + 5, "loop:%s", srcdev);
+       if (ret < 0 || ret >= len + 5) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       sz = specs->fssize;
+       if (!sz)
+               sz = DEFAULT_FS_SIZE;
+
+       fstype = specs->fstype;
+       if (!fstype)
+               fstype = DEFAULT_FSTYPE;
+
+       bdev->dest = strdup(dest);
+       if (!bdev->dest) {
+               ERROR("Failed to duplicate string \"%s\"", dest);
+               return -1;
+       }
+
+       ret = mkdir_p(bdev->dest, 0755);
+       if (ret < 0) {
+               ERROR("Failed creating directory \"%s\"", bdev->dest);
+               return -1;
+       }
+
+
+       ret = do_loop_create(srcdev, sz, fstype);
+       if (ret < 0) {
+               ERROR("Failed to create loop storage volume \"%s\" with "
+                     "filesystem \"%s\" and size \"%" PRIu64 "\"",
+                     srcdev, fstype, sz);
+               return -1;
+       }
+
+       return 0;
+}
+
+int loop_destroy(struct lxc_storage *orig) {
+       return unlink(orig->src + 5);
+}
+
+bool loop_detect(const char *path)
+{
+       int ret;
+       struct stat s;
+
+       if (!strncmp(path, "loop:", 5))
+               return true;
+
+       ret = stat(path, &s);
+       if (ret < 0)
+               return false;
+
+       if (__S_ISTYPE(s.st_mode, S_IFREG))
+               return true;
+
+       return false;
+}
+
+int loop_mount(struct lxc_storage *bdev)
+{
+       int ret, loopfd;
+       char loname[MAXPATHLEN];
+       char *src;
+
+       if (strcmp(bdev->type, "loop"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       /* skip prefix */
+       src = lxc_storage_get_path(bdev->src, bdev->type);
+
+       loopfd = lxc_prepare_loop_dev(src, loname, LO_FLAGS_AUTOCLEAR);
+       if (loopfd < 0) {
+               ERROR("Failed to prepare loop device for loop file \"%s\"", src);
+               return -1;
+       }
+       DEBUG("Prepared loop device \"%s\"", loname);
+
+       ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts);
+       if (ret < 0) {
+               ERROR("Failed to mount rootfs \"%s\" on \"%s\" via loop device \"%s\"",
+                     bdev->src, bdev->dest, loname);
+               close(loopfd);
+               return -1;
+       }
+
+       bdev->lofd = loopfd;
+       DEBUG("Mounted rootfs \"%s\" on \"%s\" via loop device \"%s\"",
+             bdev->src, bdev->dest, loname);
+
+       return 0;
+}
+
+int loop_umount(struct lxc_storage *bdev)
+{
+       int ret, saved_errno;
+
+       if (strcmp(bdev->type, "loop"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       ret = umount(bdev->dest);
+       saved_errno = errno;
+       if (bdev->lofd >= 0) {
+               close(bdev->lofd);
+               bdev->lofd = -1;
+       }
+       errno = saved_errno;
+
+       if (ret < 0) {
+               SYSERROR("Failed to umount \"%s\"", bdev->dest);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int do_loop_create(const char *path, uint64_t size, const char *fstype)
+{
+       int fd, ret;
+       char cmd_output[MAXPATHLEN];
+       const char *cmd_args[2] = {fstype, path};
+
+       /* create the new loopback file */
+       fd = creat(path, S_IRUSR | S_IWUSR);
+       if (fd < 0) {
+               SYSERROR("Failed to create new loop file \"%s\"", path);
+               return -1;
+       }
+
+       ret = lseek(fd, size, SEEK_SET);
+       if (ret < 0) {
+               SYSERROR("Failed to seek to set new loop file size for loop "
+                        "file \"%s\"", path);
+               close(fd);
+               return -1;
+       }
+
+       ret = write(fd, "1", 1);
+       if (ret != 1) {
+               SYSERROR("Failed creating new loop file \"%s\"", path);
+               close(fd);
+               return -1;
+       }
+
+       ret = close(fd);
+       if (ret < 0) {
+               SYSERROR("Failed to create new loop file \"%s\"", path);
+               return -1;
+       }
+
+       /* Create an fs in the loopback file. */
+       ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
+                         (void *)cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to create new filesystem \"%s\" for loop file "
+                     "\"%s\": %s", fstype, path, cmd_output);
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/src/lxc/storage/loop.h b/src/lxc/storage/loop.h
new file mode 100644 (file)
index 0000000..a8b1a41
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 <stdbool.h>
+#include <stdint.h>
+
+struct lxc_storage;
+
+struct bdev_specs;
+
+struct lxc_conf;
+
+extern int loop_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                          const char *oldname, const char *cname,
+                          const char *oldpath, const char *lxcpath, int snap,
+                          uint64_t newsize, struct lxc_conf *conf);
+extern int loop_create(struct lxc_storage *bdev, const char *dest,
+                      const char *n, struct bdev_specs *specs);
+extern int loop_destroy(struct lxc_storage *orig);
+extern bool loop_detect(const char *path);
+extern int loop_mount(struct lxc_storage *bdev);
+extern int loop_umount(struct lxc_storage *bdev);
+
+#endif /* __LXC_LOOP_H */
diff --git a/src/lxc/storage/lvm.c b/src/lxc/storage/lvm.c
new file mode 100644 (file)
index 0000000..1053778
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * 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
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/sysmacros.h>
+#include <sys/wait.h>
+
+#include "config.h"
+#include "log.h"
+#include "lvm.h"
+#include "rsync.h"
+#include "storage.h"
+#include "storage_utils.h"
+#include "utils.h"
+
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#endif
+
+lxc_log_define(lvm, lxc);
+
+struct lvcreate_args {
+       const char *size;
+       const char *vg;
+       const char *lv;
+       const char *thinpool;
+
+       /* snapshot specific arguments */
+       const char *source_lv;
+};
+
+static int lvm_destroy_exec_wrapper(void *data)
+{
+       struct lvcreate_args *args = data;
+
+       (void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1);
+       execlp("lvremove", "lvremove", "-f", args->lv, (char *)NULL);
+
+       return -1;
+}
+
+static int lvm_create_exec_wrapper(void *data)
+{
+       struct lvcreate_args *args = data;
+
+       (void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1);
+       if (args->thinpool)
+               execlp("lvcreate", "lvcreate", "--thinpool", args->thinpool,
+                      "-V", args->size, args->vg, "-n", args->lv,
+                      (char *)NULL);
+       else
+               execlp("lvcreate", "lvcreate", "-L", args->size, args->vg, "-n",
+                      args->lv, (char *)NULL);
+
+       return -1;
+}
+
+static int lvm_snapshot_exec_wrapper(void *data)
+{
+       struct lvcreate_args *args = data;
+
+       (void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1);
+       if (args->thinpool)
+               execlp("lvcreate", "lvcreate", "-s", "-n", args->lv,
+                      args->source_lv, (char *)NULL);
+       else
+               execlp("lvcreate", "lvcreate", "-s", "-L", args->size, "-n",
+                      args->lv, args->source_lv, (char *)NULL);
+
+       return -1;
+}
+
+/* The path must be "/dev/<vg>/<lv>". The volume group <vg> must be an existing
+ * volume group, and the logical volume <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 logical volume from that
+ * thin pool.
+ */
+static int do_lvm_create(const char *path, uint64_t size, const char *thinpool)
+{
+       int len, ret;
+       char *pathdup, *vg, *lv;
+       char cmd_output[MAXPATHLEN];
+       char sz[24];
+       char *tp = NULL;
+       struct lvcreate_args cmd_args = {0};
+
+       ret = snprintf(sz, 24, "%" PRIu64 "b", size);
+       if (ret < 0 || ret >= 24) {
+               ERROR("Failed to create string: %d", ret);
+               return -1;
+       }
+
+       pathdup = strdup(path);
+       if (!pathdup) {
+               ERROR("Failed to duplicate string \"%s\"", path);
+               return -1;
+       }
+
+       lv = strrchr(pathdup, '/');
+       if (!lv) {
+               ERROR("Failed to detect \"/\" in string \"%s\"", pathdup);
+               free(pathdup);
+               return -1;
+       }
+       *lv = '\0';
+       lv++;
+       TRACE("Parsed logical volume \"%s\"", lv);
+
+       vg = strrchr(pathdup, '/');
+       if (!vg) {
+               ERROR("Failed to detect \"/\" in string \"%s\"", pathdup);
+               free(pathdup);
+               return -1;
+       }
+       vg++;
+       TRACE("Parsed volume group \"%s\"", 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) {
+                       ERROR("Failed to create string: %d", ret);
+                       free(pathdup);
+                       return -1;
+               }
+
+               ret = lvm_is_thin_pool(tp);
+               TRACE("got %d for thin pool at path: %s", ret, tp);
+               if (ret < 0) {
+                       ERROR("Failed to detect whether \"%s\" is a thinpool", tp);
+                       free(pathdup);
+                       return -1;
+               } else if (!ret) {
+                       TRACE("Detected that \"%s\" is not a thinpool", tp);
+                       tp = NULL;
+               } else {
+                       TRACE("Detected \"%s\" is a thinpool", tp);
+               }
+       }
+
+       cmd_args.thinpool = tp;
+       cmd_args.vg = vg;
+       cmd_args.lv = lv;
+       cmd_args.size = sz;
+       TRACE("Creating new lvm storage volume \"%s\" on volume group \"%s\" "
+             "of size \"%s\"", lv, vg, sz);
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         lvm_create_exec_wrapper, (void *)&cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to create logical volume \"%s\": %s", lv,
+                     cmd_output);
+               free(pathdup);
+               return -1;
+       }
+       TRACE("Created new lvm storage volume \"%s\" on volume group \"%s\" "
+             "of size \"%s\"", lv, vg, sz);
+
+       free(pathdup);
+       return ret;
+}
+
+/* Look at "/sys/dev/block/maj:min/dm/uuid". If it contains the hardcoded LVM
+ * prefix "LVM-" then this is an lvm2 LV.
+ */
+bool lvm_detect(const char *path)
+{
+       int fd;
+       ssize_t ret;
+       struct stat statbuf;
+       char devp[MAXPATHLEN], buf[4];
+
+       if (!strncmp(path, "lvm:", 4))
+               return true;
+
+       ret = stat(path, &statbuf);
+       if (ret < 0)
+               return false;
+
+       if (!S_ISBLK(statbuf.st_mode))
+               return false;
+
+       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("Failed to create string");
+               return false;
+       }
+
+       fd = open(devp, O_RDONLY);
+       if (fd < 0)
+               return false;
+
+       ret = read(fd, buf, sizeof(buf));
+       close(fd);
+       if (ret != sizeof(buf))
+               return false;
+
+       if (strncmp(buf, "LVM-", 4))
+               return false;
+
+       return true;
+}
+
+int lvm_mount(struct lxc_storage *bdev)
+{
+       char *src;
+
+       if (strcmp(bdev->type, "lvm"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       src = lxc_storage_get_path(bdev->src, bdev->type);
+
+       /* If we might pass in data sometime, then we'll have to enrich
+        * mount_unknown_fs().
+        */
+       return mount_unknown_fs(src, bdev->dest, bdev->mntopts);
+}
+
+int lvm_umount(struct lxc_storage *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, status;
+       size_t len;
+       char *cmd;
+       char output[12];
+       int start = 0;
+       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 || (size_t)ret >= len)
+               return -1;
+
+       f = lxc_popen(cmd);
+       if (!f) {
+               SYSERROR("popen failed");
+               return -1;
+       }
+
+       ret = 0;
+       if (!fgets(output, 12, f->f))
+               ret = 1;
+
+       status = lxc_pclose(f);
+       /* Assume either vg or lvs do not exist, default comparison to false. */
+       if (ret || WEXITSTATUS(status))
+               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;
+       char *pathdup, *lv;
+       char sz[24];
+       char cmd_output[MAXPATHLEN];
+       struct lvcreate_args cmd_args = {0};
+
+       ret = snprintf(sz, 24, "%" PRIu64 "b", size);
+       if (ret < 0 || ret >= 24) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       pathdup = strdup(path);
+       if (!pathdup) {
+               ERROR("Failed to duplicate string \"%s\"", path);
+               return -1;
+       }
+
+       lv = strrchr(pathdup, '/');
+       if (!lv) {
+               ERROR("Failed to detect \"/\" in string \"%s\"", pathdup);
+               free(pathdup);
+               return -1;
+       }
+       *lv = '\0';
+       lv++;
+       TRACE("Parsed logical volume \"%s\"", lv);
+
+       /* Check if the original logical volume is backed by a thinpool, in
+        * which case we cannot specify a size that's different from the
+        * original size.
+        */
+       ret = lvm_is_thin_volume(orig);
+       if (ret < 0) {
+               free(pathdup);
+               return -1;
+       } else if (ret) {
+               cmd_args.thinpool = orig;
+       }
+
+       cmd_args.lv = lv;
+       cmd_args.source_lv = orig;
+       cmd_args.size = sz;
+       TRACE("Creating new lvm snapshot \"%s\" of \"%s\" with size \"%s\"", lv,
+             orig, sz);
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         lvm_snapshot_exec_wrapper, (void *)&cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to create logical volume \"%s\": %s", orig,
+                     cmd_output);
+               free(pathdup);
+               return -1;
+       }
+
+       free(pathdup);
+       return 0;
+}
+
+int lvm_clonepaths(struct lxc_storage *orig, struct lxc_storage *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;
+       const char *vg;
+
+       if (!orig->src || !orig->dest)
+               return -1;
+
+       if (strcmp(orig->type, "lvm") && snap) {
+               ERROR("LVM snapshot from \"%s\" storage driver is not supported",
+                     orig->type);
+               return -1;
+       }
+
+       if (strcmp(orig->type, "lvm")) {
+               vg = lxc_global_config_value("lxc.bdev.lvm.vg");
+               new->src = lxc_string_join(
+                   "/",
+                   (const char *[]){"lvm:", "dev", vg, cname, NULL},
+                   false);
+       } else {
+               char *dup, *slider, *src;
+
+               src = lxc_storage_get_path(orig->src, orig->type);
+
+               dup = strdup(src);
+               if (!dup) {
+                       ERROR("Failed to duplicate string \"%s\"", src);
+                       return -1;
+               }
+
+               slider = strrchr(dup, '/');
+               if (!slider) {
+                       ERROR("Failed to detect \"/\" in string \"%s\"", dup);
+                       free(dup);
+                       return -1;
+               }
+               *slider = '\0';
+               slider = dup;
+
+               new->src = lxc_string_join(
+                   "/",
+                   (const char *[]){"lvm:", *slider == '/' ? ++slider : slider,
+                                    cname, NULL},
+                   false);
+               free(dup);
+       }
+       if (!new->src) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       if (orig->mntopts) {
+               new->mntopts = strdup(orig->mntopts);
+               if (!new->mntopts) {
+                       ERROR("Failed to duplicate string \"%s\"", orig->mntopts);
+                       return -1;
+               }
+       }
+
+       len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
+       new->dest = malloc(len);
+       if (!new->dest) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname);
+       if (ret < 0 || ret >= len) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       ret = mkdir_p(new->dest, 0755);
+       if (ret < 0) {
+               SYSERROR("Failed to create directory \"%s\"", new->dest);
+               return -1;
+       }
+
+       return 0;
+}
+
+bool lvm_create_clone(struct lxc_conf *conf, struct lxc_storage *orig,
+                     struct lxc_storage *new, uint64_t newsize)
+{
+       char *src;
+       const char *thinpool;
+       int ret;
+       struct rsync_data data;
+       char *cmd_args[2];
+       char cmd_output[MAXPATHLEN] = {0};
+       char fstype[100] = "ext4";
+       uint64_t size = newsize;
+
+       if (is_blktype(orig)) {
+               /* detect size */
+               if (!newsize && blk_getsize(orig, &size) < 0) {
+                       ERROR("Failed to detect size of logical volume \"%s\"",
+                             orig->src);
+                       return -1;
+               }
+
+               /* detect filesystem */
+               if (detect_fs(orig, fstype, 100) < 0) {
+                       INFO("Failed to detect filesystem type for \"%s\"", orig->src);
+                       return -1;
+               }
+       } else if (!newsize) {
+                       size = DEFAULT_FS_SIZE;
+       }
+
+       src = lxc_storage_get_path(new->src, "lvm");
+       thinpool = lxc_global_config_value("lxc.bdev.lvm.thin_pool");
+
+       ret = do_lvm_create(src, size, thinpool);
+       if (ret < 0) {
+               ERROR("Failed to create lvm storage volume \"%s\"", src);
+               return -1;
+       }
+
+       cmd_args[0] = fstype;
+       cmd_args[1] = src;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                       do_mkfs_exec_wrapper, (void *)cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to create new filesystem \"%s\" for lvm storage "
+                     "volume \"%s\": %s", fstype, src, cmd_output);
+               return -1;
+       }
+
+       data.orig = orig;
+       data.new = new;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         lxc_storage_rsync_exec_wrapper, (void *)&data);
+       if (ret < 0) {
+               ERROR("Failed to rsync from \"%s\" to \"%s\"", orig->dest,
+                     new->dest);
+               return false;
+       }
+
+       TRACE("Created lvm storage volume \"%s\"", new->dest);
+       return true;
+}
+
+bool lvm_create_snapshot(struct lxc_conf *conf, struct lxc_storage *orig,
+                        struct lxc_storage *new, uint64_t newsize)
+{
+       int ret;
+       char *newsrc, *origsrc;
+       uint64_t size = newsize;
+
+       if (is_blktype(orig)) {
+               if (!newsize && blk_getsize(orig, &size) < 0) {
+                       ERROR("Failed to detect size of logical volume \"%s\"",
+                             orig->src);
+                       return -1;
+               }
+       } else if (!newsize) {
+                       size = DEFAULT_FS_SIZE;
+       }
+
+       origsrc = lxc_storage_get_path(orig->src, "lvm");
+       newsrc = lxc_storage_get_path(new->src, "lvm");
+
+       ret = lvm_snapshot(origsrc, newsrc, size);
+       if (ret < 0) {
+               ERROR("Failed to create lvm \"%s\" snapshot of \"%s\"",
+                     new->src, orig->src);
+               return false;
+       }
+
+       TRACE("Created lvm snapshot \"%s\" from \"%s\"", new->dest, orig->dest);
+       return true;
+}
+
+int lvm_destroy(struct lxc_storage *orig)
+{
+       int ret;
+       char cmd_output[MAXPATHLEN];
+       struct lvcreate_args cmd_args = {0};
+
+       cmd_args.lv = lxc_storage_get_path(orig->src, "lvm");
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         lvm_destroy_exec_wrapper, (void *)&cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to destroy logical volume \"%s\": %s", orig->src,
+                     cmd_output);
+               return -1;
+       }
+
+       TRACE("Destroyed logical volume \"%s\"", orig->src);
+       return 0;
+}
+
+int lvm_create(struct lxc_storage *bdev, const char *dest, const char *n,
+              struct bdev_specs *specs)
+{
+       const char *vg, *thinpool, *fstype, *lv = n;
+       uint64_t sz;
+       int ret, len;
+       const char *cmd_args[2];
+       char cmd_output[MAXPATHLEN];
+
+       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) + 4 + 7;
+       bdev->src = malloc(len);
+       if (!bdev->src) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(bdev->src, len, "lvm:/dev/%s/%s", vg, lv);
+       if (ret < 0 || ret >= len) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       /* size is in bytes */
+       sz = specs->fssize;
+       if (!sz)
+               sz = DEFAULT_FS_SIZE;
+
+       ret = do_lvm_create(bdev->src + 4, sz, thinpool);
+       if (ret < 0) {
+               ERROR("Error creating new logical volume \"%s\" of size "
+                     "\"%" PRIu64 " bytes\"", bdev->src, sz);
+               return -1;
+       }
+
+       fstype = specs->fstype;
+       if (!fstype)
+               fstype = DEFAULT_FSTYPE;
+
+       cmd_args[0] = fstype;
+       cmd_args[1] = lxc_storage_get_path(bdev->src, bdev->type);
+       ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
+                         (void *)cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to create new logical volume \"%s\": %s",
+                     bdev->src, cmd_output);
+               return -1;
+       }
+
+       bdev->dest = strdup(dest);
+       if (!bdev->dest) {
+               ERROR("Failed to duplicate string \"%s\"", dest);
+               return -1;
+       }
+
+       ret = mkdir_p(bdev->dest, 0755);
+       if (ret < 0) {
+               SYSERROR("Failed to create directory \"%s\"", bdev->dest);
+               return -1;
+       }
+
+       TRACE("Created new logical volume \"%s\"", bdev->dest);
+       return 0;
+}
diff --git a/src/lxc/storage/lvm.h b/src/lxc/storage/lvm.h
new file mode 100644 (file)
index 0000000..6a82f80
--- /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 <stdbool.h>
+#include <stdint.h>
+
+struct lxc_storage;
+
+struct bdev_specs;
+
+struct lxc_conf;
+
+extern bool lvm_detect(const char *path);
+extern int lvm_mount(struct lxc_storage *bdev);
+extern int lvm_umount(struct lxc_storage *bdev);
+extern int lvm_compare_lv_attr(const char *path, int pos, const char expected);
+extern int lvm_is_thin_volume(const char *path);
+extern int lvm_is_thin_pool(const char *path);
+extern int lvm_snapshot(const char *orig, const char *path, uint64_t size);
+extern int lvm_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                         const char *oldname, const char *cname,
+                         const char *oldpath, const char *lxcpath, int snap,
+                         uint64_t newsize, struct lxc_conf *conf);
+extern int lvm_destroy(struct lxc_storage *orig);
+extern int lvm_create(struct lxc_storage *bdev, const char *dest, const char *n,
+                     struct bdev_specs *specs);
+extern bool lvm_create_clone(struct lxc_conf *conf, struct lxc_storage *orig,
+                            struct lxc_storage *new, uint64_t newsize);
+extern bool lvm_create_snapshot(struct lxc_conf *conf, struct lxc_storage *orig,
+                               struct lxc_storage *new, uint64_t newsize);
+
+#endif /* __LXC_LVM_H */
diff --git a/src/lxc/storage/nbd.c b/src/lxc/storage/nbd.c
new file mode 100644 (file)
index 0000000..1fff5b6
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * 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 "log.h"
+#include "nbd.h"
+#include "storage.h"
+#include "storage_utils.h"
+#include "utils.h"
+
+lxc_log_define(nbd, 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 lxc_storage *orig, struct lxc_storage *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 lxc_storage *bdev, const char *dest, const char *n,
+              struct bdev_specs *specs)
+{
+       return -ENOSYS;
+}
+
+int nbd_destroy(struct lxc_storage *orig)
+{
+       return -ENOSYS;
+}
+
+bool nbd_detect(const char *path)
+{
+       if (!strncmp(path, "nbd:", 4))
+               return true;
+
+       return false;
+}
+
+int nbd_mount(struct lxc_storage *bdev)
+{
+       int ret = -1, partition;
+       char *src;
+       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;
+
+       src = lxc_storage_get_path(bdev->src, bdev->type);
+       partition = nbd_get_partition(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 lxc_storage *bdev)
+{
+       if (strcmp(bdev->type, "nbd"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       return umount(bdev->dest);
+}
+
+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/storage/nbd.h b/src/lxc/storage/nbd.h
new file mode 100644 (file)
index 0000000..bd23359
--- /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_NBD_H
+#define __LXC_NBD_H
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <stdint.h>
+
+struct lxc_storage;
+
+struct bdev_specs;
+
+struct lxc_conf;
+
+extern int nbd_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                         const char *oldname, const char *cname,
+                         const char *oldpath, const char *lxcpath, int snap,
+                         uint64_t newsize, struct lxc_conf *conf);
+extern int nbd_create(struct lxc_storage *bdev, const char *dest, const char *n,
+                     struct bdev_specs *specs);
+extern int nbd_destroy(struct lxc_storage *orig);
+extern bool nbd_detect(const char *path);
+extern int nbd_mount(struct lxc_storage *bdev);
+extern int nbd_umount(struct lxc_storage *bdev);
+
+extern bool attach_nbd(char *src, struct lxc_conf *conf);
+extern void detach_nbd_idx(int idx);
+extern bool requires_nbd(const char *path);
+
+#endif /* __LXC_NBD_H */
diff --git a/src/lxc/storage/overlay.c b/src/lxc/storage/overlay.c
new file mode 100644 (file)
index 0000000..0efefbe
--- /dev/null
@@ -0,0 +1,985 @@
+/*
+ * 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 "conf.h"
+#include "confile.h"
+#include "log.h"
+#include "lxccontainer.h"
+#include "overlay.h"
+#include "rsync.h"
+#include "storage.h"
+#include "storage_utils.h"
+#include "utils.h"
+
+lxc_log_define(overlay, lxc);
+
+static char *ovl_name;
+static char *ovl_version[] = {"overlay", "overlayfs"};
+
+static char *ovl_detect_name(void);
+static int ovl_do_rsync(const char *src, const char *dest,
+                       struct lxc_conf *conf);
+static int ovl_remount_on_enodev(const char *lower, const char *target,
+                                const char *name, unsigned long mountflags,
+                                const void *options);
+
+int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char *oldname,
+                  const char *cname, const char *oldpath, const char *lxcpath,
+                  int snap, uint64_t newsize, struct lxc_conf *conf)
+{
+       int ret;
+       char *src;
+
+       if (!snap) {
+               ERROR("The overlay storage driver can only be used for "
+                     "snapshots");
+               return -22;
+       }
+
+       if (!orig->src || !orig->dest)
+               return -1;
+
+       new->dest = must_make_path(lxcpath, cname, "rootfs", NULL);
+
+       ret = mkdir_p(new->dest, 0755);
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create directory \"%s\"", new->dest);
+               return -1;
+       }
+
+       if (am_unpriv()) {
+               ret = chown_mapped_root(new->dest, conf);
+               if (ret < 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) {
+                       ERROR("Failed to detect \"/\" in string \"%s\"",
+                             new->dest);
+                       return -22;
+               }
+
+               if (strlen(lastslash) < (sizeof("/rootfs") - 1)) {
+                       ERROR("Failed to detect \"/rootfs\" in string \"%s\"",
+                             new->dest);
+                       return -22;
+               }
+
+               lastslash++;
+               lastslashidx = lastslash - new->dest;
+
+               delta = malloc(lastslashidx + 7);
+               if (!delta) {
+                       ERROR("Failed to allocate memory");
+                       return -1;
+               }
+
+               memcpy(delta, new->dest, lastslashidx + 1);
+               memcpy(delta + lastslashidx, "delta0", sizeof("delta0") - 1);
+               delta[lastslashidx + sizeof("delta0") - 1] = '\0';
+
+               ret = mkdir(delta, 0755);
+               if (ret < 0 && errno != EEXIST) {
+                       SYSERROR("Failed to create directory \"%s\"", delta);
+                       free(delta);
+                       return -1;
+               }
+
+               if (am_unpriv()) {
+                       ret = chown_mapped_root(delta, conf);
+                       if (ret < 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) {
+                       ERROR("Failed to allocate memory");
+                       free(delta);
+                       return -1;
+               }
+
+               memcpy(work, new->dest, lastslashidx + 1);
+               memcpy(work + lastslashidx, "olwork", sizeof("olwork") - 1);
+               work[lastslashidx + sizeof("olwork") - 1] = '\0';
+
+               ret = mkdir(work, 0755);
+               if (ret < 0) {
+                       SYSERROR("Failed to create directory \"%s\"", work);
+                       free(delta);
+                       free(work);
+                       return -1;
+               }
+
+               if (am_unpriv()) {
+                       ret = chown_mapped_root(work, conf);
+                       if (ret < 0)
+                               WARN("Failed to update ownership of %s", work);
+               }
+               free(work);
+
+               /* strlen("overlay:") = 8
+                * +
+                * strlen(delta)
+                * +
+                * :
+                * +
+                * strlen(src)
+                * +
+                * \0
+                */
+               src = lxc_storage_get_path(orig->src, orig->type);
+               len = 8 + strlen(delta) + 1 + strlen(src) + 1;
+               new->src = malloc(len);
+               if (!new->src) {
+                       ERROR("Failed to allocate memory");
+                       free(delta);
+                       return -ENOMEM;
+               }
+
+               ret = snprintf(new->src, len, "overlay:%s:%s", src, delta);
+               free(delta);
+               if (ret < 0 || (size_t)ret >= len) {
+                       ERROR("Failed to create string");
+                       return -1;
+               }
+       } else if (!strcmp(orig->type, "overlayfs") ||
+                  !strcmp(orig->type, "overlay")) {
+               char *clean_old_path, *clean_new_path;
+               char *lastslash, *ndelta, *nsrc, *odelta, *osrc, *s1, *s2, *s3,
+                   *work;
+               int ret, lastslashidx;
+               size_t len, name_len;
+
+               osrc = strdup(orig->src);
+               if (!osrc) {
+                       ERROR("Failed to duplicate string \"%s\"", orig->src);
+                       return -22;
+               }
+
+               nsrc = strchr(osrc, ':') + 1;
+               if ((nsrc != osrc + 8) && (nsrc != osrc + 10)) {
+                       ERROR("Detected \":\" in \"%s\" at wrong position", osrc);
+                       free(osrc);
+                       return -22;
+               }
+
+               odelta = strchr(nsrc, ':');
+               if (!odelta) {
+                       free(osrc);
+                       ERROR("Failed to find \":\" in \"%s\"", nsrc);
+                       return -22;
+               }
+
+               *odelta = '\0';
+               odelta++;
+               ndelta = must_make_path(lxcpath, cname, "delta0", NULL);
+
+               ret = mkdir(ndelta, 0755);
+               if (ret < 0 && errno != EEXIST) {
+                       SYSERROR("Failed to create directory \"%s\"", ndelta);
+                       free(osrc);
+                       free(ndelta);
+                       return -1;
+               }
+
+               if (am_unpriv()) {
+                       ret = chown_mapped_root(ndelta, conf);
+                       if (ret < 0)
+                               WARN("Failed to update ownership of %s",
+                                    ndelta);
+               }
+
+               /* Make workdir for overlayfs.v22 or higher (See the comment
+                * further up.).
+                */
+               lastslash = strrchr(ndelta, '/');
+               if (!lastslash) {
+                       ERROR("Failed to detect \"/\" in \"%s\"", ndelta);
+                       free(osrc);
+                       free(ndelta);
+                       return -1;
+               }
+               lastslash++;
+               lastslashidx = lastslash - ndelta;
+
+               work = malloc(lastslashidx + 7);
+               if (!work) {
+                       free(osrc);
+                       free(ndelta);
+                       ERROR("Failed to allocate memory");
+                       return -1;
+               }
+
+               memcpy(work, ndelta, lastslashidx + 1);
+               memcpy(work + lastslashidx, "olwork", sizeof("olwork") - 1);
+               work[lastslashidx + sizeof("olwork") - 1] = '\0';
+
+               ret = mkdir(work, 0755);
+               if (ret < 0 && errno != EEXIST) {
+                       SYSERROR("Failed to create directory \"%s\"", ndelta);
+                       free(osrc);
+                       free(ndelta);
+                       free(work);
+                       return -1;
+               }
+
+               if (am_unpriv()) {
+                       ret = chown_mapped_root(work, conf);
+                       if (ret < 0)
+                               WARN("Failed to update ownership of %s", work);
+               }
+               free(work);
+
+               /* strlen("overlay:") = 8
+                * +
+                * strlen(delta)
+                * +
+                * :
+                * +
+                * strlen(src)
+                * +
+                * \0
+                */
+               len = 8 + strlen(ndelta) + 1 + strlen(nsrc) + 1;
+               new->src = malloc(len);
+               if (!new->src) {
+                       free(osrc);
+                       free(ndelta);
+                       ERROR("Failed to allocate memory");
+                       return -ENOMEM;
+               }
+               ret = snprintf(new->src, len, "overlay:%s:%s", nsrc, ndelta);
+               if (ret < 0 || (size_t)ret >= len) {
+                       ERROR("Failed to create string");
+                       free(osrc);
+                       free(ndelta);
+                       return -1;
+               }
+
+               ret = ovl_do_rsync(odelta, ndelta, conf);
+               free(osrc);
+               free(ndelta);
+               if (ret < 0)
+                       return -1;
+
+               /* When we create an overlay snapshot of an overlay container in
+                * the snapshot directory under "<lxcpath>/<name>/snaps/" we
+                * don't need to record a dependency. If we would restore would
+                * also fail.
+                */
+               clean_old_path = lxc_deslashify(oldpath);
+               if (!clean_old_path)
+                       return -1;
+
+               clean_new_path = lxc_deslashify(lxcpath);
+               if (!clean_new_path) {
+                       free(clean_old_path);
+                       return -1;
+               }
+
+               s1 = strrchr(clean_old_path, '/');
+               if (!s1) {
+                       ERROR("Failed to detect \"/\" in string \"%s\"", clean_old_path);
+                       free(clean_old_path);
+                       free(clean_new_path);
+                       return -1;
+               }
+
+               s2 = strrchr(clean_new_path, '/');
+               if (!s2) {
+                       ERROR("Failed to detect \"/\" in string \"%s\"", clean_new_path);
+                       free(clean_old_path);
+                       free(clean_new_path);
+                       return -1;
+               }
+
+               if (!strncmp(s1, "/snaps", sizeof("/snaps") - 1)) {
+                       s1 = clean_new_path;
+                       s2 = clean_old_path;
+                       s3 = (char *)cname;
+               } else if (!strncmp(s2, "/snaps", sizeof("/snaps") - 1)) {
+                       s1 = clean_old_path;
+                       s2 = clean_new_path;
+                       s3 = (char *)oldname;
+               } else {
+                       free(clean_old_path);
+                       free(clean_new_path);
+                       return 0;
+               }
+
+               len = strlen(s1);
+               if (!strncmp(s1, s2, len)) {
+                       char *tmp;
+
+                       tmp = (char *)(s2 + len + 1);
+                       if (*tmp == '\0') {
+                               free(clean_old_path);
+                               free(clean_new_path);
+                               return 0;
+                       }
+
+                       name_len = strlen(s3);
+                       if (strncmp(s3, tmp, name_len)) {
+                               free(clean_old_path);
+                               free(clean_new_path);
+                               return 0;
+                       }
+
+                       free(clean_old_path);
+                       free(clean_new_path);
+                       return LXC_CLONE_SNAPSHOT;
+               }
+
+               free(clean_old_path);
+               free(clean_new_path);
+               return 0;
+       } else {
+               ERROR("overlay 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 overlay" 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 lxc_storage *bdev, const char *dest, const char *n,
+              struct bdev_specs *specs)
+{
+       char *delta;
+       int ret;
+       size_t len, newlen;
+
+       len = strlen(dest);
+       if (len < 8 || strcmp(dest + len - 7, "/rootfs")) {
+               ERROR("Failed to detect \"/rootfs\" in \"%s\"", dest);
+               return -1;
+       }
+
+       bdev->dest = strdup(dest);
+       if (!bdev->dest) {
+               ERROR("Failed to duplicate string \"%s\"", dest);
+               return -1;
+       }
+
+       delta = malloc(len + 1);
+       if (!delta) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       memcpy(delta, dest, len);
+       memcpy(delta + len - 6, "delta0", sizeof("delta0") - 1);
+       delta[len + sizeof("delta0")] = '\0';
+
+       ret = mkdir_p(delta, 0755);
+       if (ret < 0) {
+               SYSERROR("Failed to create directory \"%s\"", delta);
+               free(delta);
+               return -1;
+       }
+
+       /* overlay:lower:upper */
+       newlen = (2 * len) + strlen("overlay:") + 2;
+       bdev->src = malloc(newlen);
+       if (!bdev->src) {
+               ERROR("Failed to allocate memory");
+               free(delta);
+               return -1;
+       }
+
+       ret = snprintf(bdev->src, newlen, "overlay:%s:%s", dest, delta);
+       if (ret < 0 || (size_t)ret >= newlen) {
+               ERROR("Failed to create string");
+               free(delta);
+               return -1;
+       }
+
+       ret = mkdir_p(bdev->dest, 0755);
+       if (ret < 0) {
+               SYSERROR("Failed to create directory \"%s\"", bdev->dest);
+               free(delta);
+               return -1;
+       }
+
+       free(delta);
+       return 0;
+}
+
+int ovl_destroy(struct lxc_storage *orig)
+{
+       bool ovl;
+       char *upper = orig->src;
+
+       ovl = !strncmp(upper, "overlay:", 8);
+       if (!ovl && strncmp(upper, "overlayfs:", 10))
+               return -22;
+
+       /* For an overlay container the rootfs is considered immutable
+        * and cannot be removed when restoring from a snapshot.
+        */
+       if (orig->flags & LXC_STORAGE_INTERNAL_OVERLAY_RESTORE)
+               return 0;
+
+       if (ovl)
+               upper += 8;
+       else
+               upper += 10;
+
+       upper = strchr(upper, ':');
+       if (!upper)
+               return -22;
+       upper++;
+
+       return lxc_rmdir_onedev(upper, NULL);
+}
+
+bool ovl_detect(const char *path)
+{
+       if (!strncmp(path, "overlayfs:", 10))
+               return true;
+
+       if (!strncmp(path, "overlay:", 8))
+               return true;
+
+       return false;
+}
+
+int ovl_mount(struct lxc_storage *bdev)
+{
+       char *tmp, *options, *dup, *lower, *upper;
+       char *options_work, *work, *lastslash;
+       int lastslashidx;
+       size_t len, len2;
+       unsigned long mntflags;
+       char *mntdata;
+       int ret, ret2;
+
+       if (strcmp(bdev->type, "overlay") && 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 overlay * -o upperdir=${upper},lowerdir=${lower} lower dest
+        */
+       dup = strdup(bdev->src);
+       if (!dup) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       /* support multiple lower layers */
+       lower = strstr(dup, ":/");
+       if (!lower) {
+               ERROR("Failed to detect \":/\" in string \"%s\"", dup);
+               free(dup);
+               return -22;
+       }
+
+       lower++;
+       upper = lower;
+       while ((tmp = strstr(++upper, ":/"))) {
+               upper = tmp;
+       }
+
+       upper--;
+       if (upper == lower) {
+               free(dup);
+               return -22;
+       }
+       *upper = '\0';
+       upper++;
+
+       /* if delta doesn't yet exist, create it */
+       ret = mkdir_p(upper, 0755) < 0;
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create directory \"%s\"", upper);
+               free(dup);
+               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) {
+               ERROR("Failed to detect \"/\" in string \"%s\"", upper);
+               free(dup);
+               return -22;
+       }
+
+       lastslash++;
+       lastslashidx = lastslash - upper;
+
+       work = malloc(lastslashidx + 7);
+       if (!work) {
+               ERROR("Failed to allocate memory");
+               free(dup);
+               return -22;
+       }
+
+       memcpy(work, upper, lastslashidx + 1);
+       memcpy(work + lastslashidx, "olwork", sizeof("olwork") - 1);
+       work[lastslashidx + sizeof("olwork") - 1] = '\0';
+
+       ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata);
+       if (ret < 0) {
+               ERROR("Failed to parse mount options");
+               free(mntdata);
+               free(dup);
+               free(work);
+               return -22;
+       }
+
+       ret = mkdir_p(work, 0755);
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create directory \"%s\"", work);
+               free(mntdata);
+               free(dup);
+               free(work);
+               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) {
+               ERROR("Failed to create string");
+               free(mntdata);
+               free(dup);
+               free(work);
+               return -1;
+       }
+
+       /* Assume we need a workdir as we are on a overlay version >= v22. */
+       ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
+                                   MS_MGC_VAL | mntflags, options_work);
+       if (ret < 0) {
+               INFO("Failed to mount \"%s\" on \"%s\" with options \"%s\". "
+                    "Retrying without workdir: %s",
+                    lower, bdev->dest, options_work, strerror(errno));
+
+               /* Assume we cannot use a workdir as we are on a version <= v21.
+                */
+               ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
+                                           MS_MGC_VAL | mntflags, options);
+               if (ret < 0)
+                       SYSERROR("Failed to mount \"%s\" on \"%s\" with "
+                                "options \"%s\": %s",
+                                lower, bdev->dest, options, strerror(errno));
+               else
+                       INFO("Mounted \"%s\" on \"%s\" with options \"%s\"",
+                            lower, bdev->dest, options);
+       } else {
+               INFO("Mounted \"%s\" on \"%s\" with options \"%s\"", lower,
+                    bdev->dest, options_work);
+       }
+
+       free(dup);
+       free(work);
+       return ret;
+}
+
+int ovl_umount(struct lxc_storage *bdev)
+{
+       int ret;
+
+       if (strcmp(bdev->type, "overlay") && strcmp(bdev->type, "overlayfs"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       ret = umount(bdev->dest);
+       if (ret < 0)
+               SYSERROR("Failed to unmount \"%s\"", bdev->dest);
+       else
+               TRACE("Unmounted \"%s\"", bdev->dest);
+
+       return ret;
+}
+
+char *ovl_get_lower(const char *rootfs_path)
+{
+       char *s1;
+
+       s1 = strstr(rootfs_path, ":/");
+       if (!s1)
+               return NULL;
+       s1++;
+
+       s1 = strstr(s1, ":/");
+       if (!s1)
+               return NULL;
+       s1++;
+
+       return s1;
+}
+
+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;
+
+       s2 = strstr(s1, ":/");
+       if (s2) {
+               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 **opts;
+       int ret;
+       size_t arrlen, i, len, rootfslen;
+       int fret = -1;
+       size_t dirlen = 0;
+       char *rootfs_dir = NULL, *rootfs_path = NULL, *upperdir = NULL,
+            *workdir = NULL;
+
+       /* 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;
+
+               rootfs_dir = ovl_get_rootfs(rootfs_path, &rootfslen);
+               if (!rootfs_dir)
+                       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) &&
+                        strncmp(upperdir, rootfs_dir, rootfslen))
+                       ret = mkdir_p(upperdir, 0755);
+               if (ret < 0)
+                       WARN("Failed to create directory \"%s\": %s", upperdir,
+                            strerror(errno));
+       }
+
+       ret = 0;
+       if (workdir) {
+               if (!rootfs_path)
+                       ret = mkdir_p(workdir, 0755);
+               else if (!strncmp(workdir, lxcpath, dirlen) &&
+                        strncmp(workdir, rootfs_dir, rootfslen))
+                       ret = mkdir_p(workdir, 0755);
+               if (ret < 0)
+                       WARN("Failed to create directory \"%s\": %s", workdir,
+                            strerror(errno));
+       }
+
+       fret = 0;
+
+err:
+       free(rootfs_dir);
+       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 contain 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], new_work[MAXPATHLEN], old_upper[MAXPATHLEN],
+           old_work[MAXPATHLEN];
+       size_t i;
+       struct lxc_list *iterator;
+       char *cleanpath = NULL;
+       int fret = -1;
+       int ret = 0;
+       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, *new_mnt_entry = NULL, *tmp = NULL,
+                    *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_remount_on_enodev(const char *lower, const char *target,
+                                const char *name, unsigned long mountflags,
+                                const void *options)
+{
+       int ret;
+       ret = mount(lower, target, ovl_name, MS_MGC_VAL | mountflags, options);
+       if (ret < 0 && errno == ENODEV) /* Try other module name. */
+               ret = mount(lower, target,
+                           ovl_name == ovl_version[0] ? ovl_version[1]
+                                                      : ovl_version[0],
+                           MS_MGC_VAL | mountflags, options);
+       return ret;
+}
+
+static char *ovl_detect_name(void)
+{
+       FILE *f;
+       char *v = ovl_version[0];
+       char *line = NULL;
+       size_t len = 0;
+
+       f = fopen("/proc/filesystems", "r");
+       if (!f)
+               return v;
+
+       while (getline(&line, &len, f) != -1) {
+               if (strcmp(line, "nodev\toverlayfs\n") == 0) {
+                       v = ovl_version[1];
+                       break;
+               }
+       }
+
+       fclose(f);
+       free(line);
+       return v;
+}
+
+static int ovl_do_rsync(const char *src, const char *dest,
+                       struct lxc_conf *conf)
+{
+       int ret = -1;
+       struct rsync_data_char rdata = {0};
+       char cmd_output[MAXPATHLEN] = {0};
+
+       rdata.src = (char *)src;
+       rdata.dest = (char *)dest;
+       if (am_unpriv())
+               ret = userns_exec_full(conf, lxc_rsync_exec_wrapper, &rdata,
+                                      "lxc_rsync_exec_wrapper");
+       else
+               ret = run_command(cmd_output, sizeof(cmd_output),
+                                 lxc_rsync_exec_wrapper, (void *)&rdata);
+       if (ret < 0)
+               ERROR("Failed to rsync from \"%s\" into \"%s\"%s%s", src, dest,
+                     cmd_output[0] != '\0' ? ": " : "",
+                     cmd_output[0] != '\0' ? cmd_output : "");
+
+       return ret;
+}
diff --git a/src/lxc/storage/overlay.h b/src/lxc/storage/overlay.h
new file mode 100644 (file)
index 0000000..0aa3cb1
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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 <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "storage.h"
+
+struct lxc_storage;
+
+struct bdev_specs;
+
+struct lxc_conf;
+
+struct lxc_rootfs;
+
+extern int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                         const char *oldname, const char *cname,
+                         const char *oldpath, const char *lxcpath, int snap,
+                         uint64_t newsize, struct lxc_conf *conf);
+extern int ovl_create(struct lxc_storage *bdev, const char *dest, const char *n,
+                     struct bdev_specs *specs);
+extern int ovl_destroy(struct lxc_storage *orig);
+extern bool ovl_detect(const char *path);
+extern int ovl_mount(struct lxc_storage *bdev);
+extern int ovl_umount(struct lxc_storage *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 .
+ */
+extern 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.
+ */
+extern char *ovl_get_lower(const char *rootfs_path);
+
+/* Get rootfs path for overlay backed containers. Allocated memory must be freed
+ * by caller.
+ */
+extern char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen);
+
+/* Create upper- and workdirs for overlay mounts.
+ */
+extern 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/storage/rbd.c b/src/lxc/storage/rbd.c
new file mode 100644 (file)
index 0000000..e64e80d
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * 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 "log.h"
+#include "storage.h"
+#include "storage_utils.h"
+#include "utils.h"
+
+lxc_log_define(rbd, lxc);
+
+struct rbd_args {
+       const char *osd_pool_name;
+       const char *rbd_name;
+       const char *size;
+};
+
+int rbd_create_wrapper(void *data)
+{
+       struct rbd_args *args = data;
+
+       execlp("rbd", "rbd", "create", "--pool", args->osd_pool_name,
+              args->rbd_name, "--size", args->size, (char *)NULL);
+
+       return -1;
+}
+
+int rbd_map_wrapper(void *data)
+{
+       struct rbd_args *args = data;
+
+       execlp("rbd", "rbd", "map", "--pool", args->osd_pool_name,
+              args->rbd_name, (char *)NULL);
+
+       return -1;
+}
+
+int rbd_unmap_wrapper(void *data)
+{
+       struct rbd_args *args = data;
+
+       execlp("rbd", "rbd", "unmap", args->rbd_name, (char *)NULL);
+
+       return -1;
+}
+
+int rbd_delete_wrapper(void *data)
+{
+       struct rbd_args *args = data;
+
+       execlp("rbd", "rbd", "rm", args->rbd_name, (char *)NULL);
+
+       return -1;
+}
+
+int rbd_clonepaths(struct lxc_storage *orig, struct lxc_storage *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 lxc_storage *bdev, const char *dest, const char *n,
+              struct bdev_specs *specs)
+{
+       const char *rbdpool, *fstype;
+       uint64_t size;
+       int ret, len;
+       char sz[24];
+       const char *cmd_args[2];
+       char cmd_output[MAXPATHLEN];
+       const char *rbdname = n;
+       struct rbd_args args = {0};
+
+       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) + 4 + 11;
+       bdev->src = malloc(len);
+       if (!bdev->src) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(bdev->src, len, "rbd:/dev/rbd/%s/%s", rbdpool, rbdname);
+       if (ret < 0 || ret >= len) {
+               ERROR("Failed to create string");
+               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) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       args.osd_pool_name = rbdpool;
+       args.rbd_name = rbdname;
+       args.size = sz;
+       ret = run_command(cmd_output, sizeof(cmd_output), rbd_create_wrapper,
+                         (void *)&args);
+       if (ret < 0) {
+               ERROR("Failed to create rbd storage volume \"%s\": %s", rbdname,
+                     cmd_output);
+               return -1;
+       }
+
+       ret = run_command(cmd_output, sizeof(cmd_output), rbd_map_wrapper,
+                         (void *)&args);
+       if (ret < 0) {
+               ERROR("Failed to map rbd storage volume \"%s\": %s", rbdname,
+                     cmd_output);
+               return -1;
+       }
+
+       fstype = specs->fstype;
+       if (!fstype)
+               fstype = DEFAULT_FSTYPE;
+
+       cmd_args[0] = fstype;
+       cmd_args[1] = lxc_storage_get_path(bdev->src, bdev->type);
+       ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
+                         (void *)cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to map rbd storage volume \"%s\": %s", rbdname,
+                     cmd_output);
+               return -1;
+       }
+
+       bdev->dest = strdup(dest);
+       if (!bdev->dest) {
+               ERROR("Failed to duplicate string \"%s\"", dest);
+               return -1;
+       }
+
+       ret = mkdir_p(bdev->dest, 0755);
+       if (ret < 0 && errno != EEXIST) {
+               ERROR("Failed to create directory \"%s\"", bdev->dest);
+               return -1;
+       }
+
+       TRACE("Created rbd storage volume \"%s\"", bdev->dest);
+       return 0;
+}
+
+int rbd_destroy(struct lxc_storage *orig)
+{
+       int ret;
+       char *src;
+       char *rbdfullname;
+       char cmd_output[MAXPATHLEN];
+       struct rbd_args args = {0};
+
+       src = lxc_storage_get_path(orig->src, orig->type);
+       if (file_exists(src)) {
+               args.rbd_name = src;
+               ret = run_command(cmd_output, sizeof(cmd_output),
+                                 rbd_unmap_wrapper, (void *)&args);
+               if (ret < 0) {
+                       ERROR("Failed to map rbd storage volume \"%s\": %s",
+                             src, cmd_output);
+                       return -1;
+               }
+       }
+
+       rbdfullname = alloca(strlen(src) - 8);
+       strcpy(rbdfullname, &src[9]);
+       args.rbd_name = rbdfullname;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                       rbd_delete_wrapper, (void *)&args);
+       if (ret < 0) {
+               ERROR("Failed to delete rbd storage volume \"%s\": %s",
+                     rbdfullname, cmd_output);
+               return -1;
+       }
+
+       return 0;
+}
+
+bool rbd_detect(const char *path)
+{
+       if (!strncmp(path, "rbd:", 4))
+               return true;
+
+       if (!strncmp(path, "/dev/rbd/", 9))
+               return true;
+
+       return false;
+}
+
+int rbd_mount(struct lxc_storage *bdev)
+{
+       char *src;
+
+       if (strcmp(bdev->type, "rbd"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       src = lxc_storage_get_path(bdev->src, bdev->type);
+       if (!file_exists(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(src, bdev->dest, bdev->mntopts);
+}
+
+int rbd_umount(struct lxc_storage *bdev)
+{
+       if (strcmp(bdev->type, "rbd"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       return umount(bdev->dest);
+}
diff --git a/src/lxc/storage/rbd.h b/src/lxc/storage/rbd.h
new file mode 100644 (file)
index 0000000..9e6e57c
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 <stdbool.h>
+#include <stdint.h>
+
+struct lxc_storage;
+
+struct bdev_specs;
+
+struct lxc_conf;
+
+extern int rbd_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                         const char *oldname, const char *cname,
+                         const char *oldpath, const char *lxcpath, int snap,
+                         uint64_t newsize, struct lxc_conf *conf);
+extern int rbd_create(struct lxc_storage *bdev, const char *dest, const char *n,
+                     struct bdev_specs *specs);
+extern int rbd_destroy(struct lxc_storage *orig);
+extern bool rbd_detect(const char *path);
+extern int rbd_mount(struct lxc_storage *bdev);
+extern int rbd_umount(struct lxc_storage *bdev);
+
+#endif /* __LXC_RDB_H */
diff --git a/src/lxc/storage/rsync.c b/src/lxc/storage/rsync.c
new file mode 100644 (file)
index 0000000..55c9504
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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 "log.h"
+#include "rsync.h"
+#include "storage.h"
+#include "utils.h"
+
+lxc_log_define(rsync, lxc);
+
+int lxc_storage_rsync_exec_wrapper(void *data)
+{
+       struct rsync_data *arg = data;
+       return lxc_rsync(arg);
+}
+
+int lxc_rsync_exec_wrapper(void *data)
+{
+       int ret;
+       struct rsync_data_char *args = data;
+
+       ret = lxc_switch_uid_gid(0, 0);
+       if (ret < 0)
+               return -1;
+
+       ret = lxc_setgroups(0, NULL);
+       if (ret < 0)
+               return -1;
+
+       return lxc_rsync_exec(args->src, args->dest);
+}
+
+int lxc_rsync_exec(const char *src, const char *dest)
+{
+       int ret;
+       size_t l;
+       char *s;
+
+       l = strlen(src) + 2;
+       s = malloc(l);
+       if (!s)
+               return -1;
+
+       ret = snprintf(s, l, "%s", src);
+       if (ret < 0 || (size_t)ret >= l)
+               return -1;
+
+       s[l - 2] = '/';
+       s[l - 1] = '\0';
+
+       execlp("rsync", "rsync", "-aHXS", "--delete", s, dest, (char *)NULL);
+       return -1;
+}
+
+int lxc_rsync(struct rsync_data *data)
+{
+       int ret;
+       char *dest, *src;
+       struct lxc_storage *orig = data->orig, *new = data->new;
+
+       ret = unshare(CLONE_NEWNS);
+       if (ret < 0) {
+               SYSERROR("Failed to unshare CLONE_NEWNS");
+               return -1;
+       }
+
+       ret = detect_shared_rootfs();
+       if (ret) {
+               ret = mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL);
+               if (ret < 0)
+                       SYSERROR("Failed to make \"/\" a slave mount");
+       }
+
+       ret = orig->ops->mount(orig);
+       if (ret < 0) {
+               ERROR("Failed mounting \"%s\" on \"%s\"", orig->src, orig->dest);
+               return -1;
+       }
+
+       ret = new->ops->mount(new);
+       if (ret < 0) {
+               ERROR("Failed mounting \"%s\" onto \"%s\"", new->src, new->dest);
+               return -1;
+       }
+
+       ret = lxc_switch_uid_gid(0, 0);
+       if (ret < 0)
+               return -1;
+
+       ret = lxc_setgroups(0, NULL);
+       if (ret < 0)
+               return -1;
+
+       src = lxc_storage_get_path(orig->dest, orig->type);
+       dest = lxc_storage_get_path(new->dest, new->type);
+
+       ret = lxc_rsync_exec(src, dest);
+       if (ret < 0) {
+               ERROR("Failed to rsync from \"%s\" into \"%s\"", src, dest);
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/src/lxc/storage/rsync.h b/src/lxc/storage/rsync.h
new file mode 100644 (file)
index 0000000..fca81a7
--- /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 lxc_storage *orig;
+       struct lxc_storage *new;
+};
+
+struct rsync_data_char {
+       char *src;
+       char *dest;
+};
+
+/* new helpers */
+extern int lxc_rsync_exec_wrapper(void *data);
+extern int lxc_storage_rsync_exec_wrapper(void *data);
+extern int lxc_rsync_exec(const char *src, const char *dest);
+extern int lxc_rsync(struct rsync_data *data);
+
+#endif /* __LXC_RSYNC_H */
diff --git a/src/lxc/storage/storage.c b/src/lxc/storage/storage.c
new file mode 100644 (file)
index 0000000..2a91aab
--- /dev/null
@@ -0,0 +1,704 @@
+/*
+ * 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 <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 "aufs.h"
+#include "btrfs.h"
+#include "conf.h"
+#include "config.h"
+#include "dir.h"
+#include "error.h"
+#include "log.h"
+#include "loop.h"
+#include "lvm.h"
+#include "lxc.h"
+#include "lxclock.h"
+#include "nbd.h"
+#include "namespace.h"
+#include "overlay.h"
+#include "parse.h"
+#include "rbd.h"
+#include "rsync.h"
+#include "storage.h"
+#include "storage_utils.h"
+#include "utils.h"
+#include "zfs.h"
+
+#ifndef BLKGETSIZE64
+#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
+#endif
+
+lxc_log_define(storage, lxc);
+
+/* aufs */
+static const struct lxc_storage_ops aufs_ops = {
+    .detect = &aufs_detect,
+    .mount = &aufs_mount,
+    .umount = &aufs_umount,
+    .clone_paths = &aufs_clonepaths,
+    .destroy = &aufs_destroy,
+    .create = &aufs_create,
+    .copy = NULL,
+    .snapshot = NULL,
+    .can_snapshot = true,
+    .can_backup = true,
+};
+
+/* btrfs */
+static const struct lxc_storage_ops btrfs_ops = {
+    .detect = &btrfs_detect,
+    .mount = &btrfs_mount,
+    .umount = &btrfs_umount,
+    .clone_paths = &btrfs_clonepaths,
+    .destroy = &btrfs_destroy,
+    .create = &btrfs_create,
+    .copy = &btrfs_create_clone,
+    .snapshot = &btrfs_create_snapshot,
+    .can_snapshot = true,
+    .can_backup = true,
+};
+
+/* dir */
+static const struct lxc_storage_ops dir_ops = {
+    .detect = &dir_detect,
+    .mount = &dir_mount,
+    .umount = &dir_umount,
+    .clone_paths = &dir_clonepaths,
+    .destroy = &dir_destroy,
+    .create = &dir_create,
+    .copy = NULL,
+    .snapshot = NULL,
+    .can_snapshot = false,
+    .can_backup = true,
+};
+
+/* loop */
+static const struct lxc_storage_ops loop_ops = {
+    .detect = &loop_detect,
+    .mount = &loop_mount,
+    .umount = &loop_umount,
+    .clone_paths = &loop_clonepaths,
+    .destroy = &loop_destroy,
+    .create = &loop_create,
+    .copy = NULL,
+    .snapshot = NULL,
+    .can_snapshot = false,
+    .can_backup = true,
+};
+
+/* lvm */
+static const struct lxc_storage_ops lvm_ops = {
+    .detect = &lvm_detect,
+    .mount = &lvm_mount,
+    .umount = &lvm_umount,
+    .clone_paths = &lvm_clonepaths,
+    .destroy = &lvm_destroy,
+    .create = &lvm_create,
+    .copy = &lvm_create_clone,
+    .snapshot = &lvm_create_snapshot,
+    .can_snapshot = true,
+    .can_backup = false,
+};
+
+/* nbd */
+const struct lxc_storage_ops nbd_ops = {
+    .detect = &nbd_detect,
+    .mount = &nbd_mount,
+    .umount = &nbd_umount,
+    .clone_paths = &nbd_clonepaths,
+    .destroy = &nbd_destroy,
+    .create = &nbd_create,
+    .copy = NULL,
+    .snapshot = NULL,
+    .can_snapshot = true,
+    .can_backup = false,
+};
+
+/* overlay */
+static const struct lxc_storage_ops ovl_ops = {
+    .detect = &ovl_detect,
+    .mount = &ovl_mount,
+    .umount = &ovl_umount,
+    .clone_paths = &ovl_clonepaths,
+    .destroy = &ovl_destroy,
+    .create = &ovl_create,
+    .copy = NULL,
+    .snapshot = NULL,
+    .can_snapshot = true,
+    .can_backup = true,
+};
+
+/* rbd */
+static const struct lxc_storage_ops rbd_ops = {
+    .detect = &rbd_detect,
+    .mount = &rbd_mount,
+    .umount = &rbd_umount,
+    .clone_paths = &rbd_clonepaths,
+    .destroy = &rbd_destroy,
+    .create = &rbd_create,
+    .copy = NULL,
+    .snapshot = NULL,
+    .can_snapshot = false,
+    .can_backup = false,
+};
+
+/* zfs */
+static const struct lxc_storage_ops zfs_ops = {
+    .detect = &zfs_detect,
+    .mount = &zfs_mount,
+    .umount = &zfs_umount,
+    .clone_paths = &zfs_clonepaths,
+    .destroy = &zfs_destroy,
+    .create = &zfs_create,
+    .copy = &zfs_copy,
+    .snapshot = &zfs_snapshot,
+    .can_snapshot = true,
+    .can_backup = true,
+};
+
+struct lxc_storage_type {
+       const char *name;
+       const struct lxc_storage_ops *ops;
+};
+
+static const struct lxc_storage_type bdevs[] = {
+       { .name = "dir",       .ops = &dir_ops,   },
+       { .name = "zfs",       .ops = &zfs_ops,   },
+       { .name = "lvm",       .ops = &lvm_ops,   },
+       { .name = "rbd",       .ops = &rbd_ops,   },
+       { .name = "btrfs",     .ops = &btrfs_ops, },
+       { .name = "aufs",      .ops = &aufs_ops,  },
+       { .name = "overlay",   .ops = &ovl_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 lxc_storage_type);
+
+static const struct lxc_storage_type *get_storage_by_name(const char *name)
+{
+       size_t i, cmplen;
+
+       cmplen = strcspn(name, ":");
+       if (cmplen == 0)
+               return NULL;
+
+       for (i = 0; i < numbdevs; i++)
+               if (strncmp(bdevs[i].name, name, cmplen) == 0)
+                       break;
+
+       if (i == numbdevs)
+               return NULL;
+
+       DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
+       return &bdevs[i];
+}
+
+const struct lxc_storage_type *storage_query(struct lxc_conf *conf,
+                                            const char *src)
+{
+       size_t i;
+       const struct lxc_storage_type *bdev;
+
+       bdev = get_storage_by_name(src);
+       if (bdev)
+               return bdev;
+
+       for (i = 0; i < numbdevs; i++)
+               if (bdevs[i].ops->detect(src))
+                       break;
+
+       if (i == numbdevs)
+               return NULL;
+
+       DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
+       return &bdevs[i];
+}
+
+struct lxc_storage *storage_get(const char *type)
+{
+       size_t i;
+       struct lxc_storage *bdev;
+
+       for (i = 0; i < numbdevs; i++) {
+               if (strcmp(bdevs[i].name, type) == 0)
+                       break;
+       }
+
+       if (i == numbdevs)
+               return NULL;
+
+       bdev = malloc(sizeof(struct lxc_storage));
+       if (!bdev)
+               return NULL;
+
+       memset(bdev, 0, sizeof(struct lxc_storage));
+       bdev->ops = bdevs[i].ops;
+       bdev->type = bdevs[i].name;
+
+       if (!strcmp(bdev->type, "aufs"))
+               WARN("The \"aufs\" driver will is deprecated and will soon be "
+                    "removed. For similar functionality see the \"overlay\" "
+                    "storage driver");
+
+       return bdev;
+}
+
+static struct lxc_storage *do_storage_create(const char *dest, const char *type,
+                                            const char *cname,
+                                            struct bdev_specs *specs)
+{
+
+       struct lxc_storage *bdev;
+
+       if (!type)
+               type = "dir";
+
+       bdev = storage_get(type);
+       if (!bdev)
+               return NULL;
+
+       if (bdev->ops->create(bdev, dest, cname, specs) < 0) {
+               storage_put(bdev);
+               return NULL;
+       }
+
+       return bdev;
+}
+
+bool storage_can_backup(struct lxc_conf *conf)
+{
+       struct lxc_storage *bdev = storage_init(conf, NULL, NULL, NULL);
+       bool ret;
+
+       if (!bdev)
+               return false;
+
+       ret = bdev->ops->can_backup;
+       storage_put(bdev);
+       return ret;
+}
+
+/* If we're not snaphotting, then storage_copy becomes a simple case of mount
+ * the original, mount the new, and rsync the contents.
+ */
+struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
+                                const char *lxcpath, const char *bdevtype,
+                                int flags, const char *bdevdata,
+                                uint64_t newsize, bool *needs_rdep)
+{
+       int ret;
+       struct lxc_storage *orig, *new;
+       char *src_no_prefix;
+       bool snap = flags & LXC_CLONE_SNAPSHOT;
+       bool maybe_snap = flags & LXC_CLONE_MAYBE_SNAPSHOT;
+       bool keepbdevtype = flags & LXC_CLONE_KEEPBDEVTYPE;
+       const char *src = c->lxc_conf->rootfs.path;
+       const char *oldname = c->name;
+       const char *oldpath = c->config_path;
+       struct rsync_data data = {0};
+       char cmd_output[MAXPATHLEN] = {0};
+
+       if (!src) {
+               ERROR("No rootfs specified");
+               return NULL;
+       }
+
+       /* 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)) {
+               ERROR("Original rootfs path \"%s\" does not include container "
+                     "name \"%s\"", src, oldname);
+               return NULL;
+       }
+
+       orig = storage_init(c->lxc_conf, src, NULL, NULL);
+       if (!orig) {
+               ERROR("Failed to detect storage driver 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("Failed to allocate memory");
+                       goto on_error_put_orig;
+               }
+
+               ret = snprintf(orig->dest, len, "%s/%s/rootfs", oldpath, oldname);
+               if (ret < 0 || (size_t)ret >= len) {
+                       ERROR("Failed to create string");
+                       goto on_error_put_orig;
+               }
+
+               ret = stat(orig->dest, &sb);
+               if (ret < 0 && errno == ENOENT) {
+                       ret = mkdir_p(orig->dest, 0755);
+                       if (ret < 0)
+                               WARN("Failed to create directory \"%s\"", orig->dest);
+               }
+       }
+
+       /* Special case for snapshot. If the caller requested maybe_snapshot and
+        * keepbdevtype and the backing store is directory, then proceed with a
+        * 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 overlay. */
+       if (!bdevtype && !keepbdevtype && snap && !strcmp(orig->type, "dir"))
+               bdevtype = "overlay";
+
+       if (am_unpriv() && !unpriv_snap_allowed(orig, bdevtype, snap, maybe_snap)) {
+               ERROR("Unsupported snapshot type \"%s\" for unprivileged users",
+                     bdevtype ? bdevtype : "(null)");
+               goto on_error_put_orig;
+       }
+
+       *needs_rdep = false;
+       if (bdevtype) {
+               if (snap && !strcmp(orig->type, "lvm") &&
+                   !lvm_is_thin_volume(orig->src))
+                       *needs_rdep = true;
+               else if (!strcmp(bdevtype, "overlay") ||
+                        !strcmp(bdevtype, "overlayfs"))
+                       *needs_rdep = true;
+       } else {
+               if (!snap && strcmp(oldpath, lxcpath))
+                       bdevtype = "dir";
+               else
+                       bdevtype = orig->type;
+
+               if (!strcmp(bdevtype, "overlay") ||
+                   !strcmp(bdevtype, "overlayfs"))
+                       *needs_rdep = true;
+       }
+
+       /* get new bdev type */
+       new = storage_get(bdevtype);
+       if (!new) {
+               ERROR("Failed to initialize \"%s\" storage driver",
+                     bdevtype ? bdevtype : orig->type);
+               goto on_error_put_orig;
+       }
+       TRACE("Initialized \"%s\" storage driver", new->type);
+
+       /* create new paths */
+       ret = new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath,
+                                   snap, newsize, c->lxc_conf);
+       if (ret < 0) {
+               ERROR("Failed creating new paths for clone of \"%s\"", src);
+               goto on_error_put_new;
+       }
+
+       /* When we create an overlay snapshot of an overlay container in the
+        * snapshot directory under "<lxcpath>/<name>/snaps/" we don't need to
+        * record a dependency. If we would restore would also fail.
+        */
+       if ((!strcmp(new->type, "overlay") ||
+            !strcmp(new->type, "overlayfs")) &&
+           ret == LXC_CLONE_SNAPSHOT)
+               *needs_rdep = false;
+
+       /* btrfs */
+       if (!strcmp(orig->type, "btrfs") && !strcmp(new->type, "btrfs")) {
+               bool bret = false;
+               if (snap || btrfs_same_fs(orig->dest, new->dest) == 0)
+                       bret = new->ops->snapshot(c->lxc_conf, orig, new, 0);
+               else
+                       bret = new->ops->copy(c->lxc_conf, orig, new, 0);
+               if (!bret)
+                       goto on_error_put_new;
+
+               goto on_success;
+       }
+
+       /* lvm */
+       if (!strcmp(orig->type, "lvm") && !strcmp(new->type, "lvm")) {
+               bool bret = false;
+               if (snap)
+                       bret = new->ops->snapshot(c->lxc_conf, orig,
+                                                        new, newsize);
+               else
+                       bret = new->ops->copy(c->lxc_conf, orig, new, newsize);
+               if (!bret)
+                       goto on_error_put_new;
+
+               goto on_success;
+       }
+
+       /* zfs */
+       if (!strcmp(orig->type, "zfs") && !strcmp(new->type, "zfs")) {
+               bool bret = false;
+
+               if (snap)
+                       bret = new->ops->snapshot(c->lxc_conf, orig, new,
+                                                 newsize);
+               else
+                       bret = new->ops->copy(c->lxc_conf, orig, new, newsize);
+               if (!bret)
+                       goto on_error_put_new;
+
+               goto on_success;
+       }
+
+       if (strcmp(bdevtype, "btrfs")) {
+               if (!strcmp(new->type, "overlay") || !strcmp(new->type, "overlayfs"))
+                       src_no_prefix = ovl_get_lower(new->src);
+               else
+                       src_no_prefix = lxc_storage_get_path(new->src, new->type);
+
+               if (am_unpriv()) {
+                       ret = chown_mapped_root(src_no_prefix, c->lxc_conf);
+                       if (ret < 0)
+                               WARN("Failed to chown \"%s\"", new->src);
+               }
+       }
+
+       if (snap)
+               goto on_success;
+
+       /* rsync the contents from source to target */
+       data.orig = orig;
+       data.new = new;
+       if (am_unpriv())
+               ret = userns_exec_full(c->lxc_conf,
+                                      lxc_storage_rsync_exec_wrapper, &data,
+                                      "lxc_storage_rsync_exec_wrapper");
+       else
+               ret = run_command(cmd_output, sizeof(cmd_output),
+                                 lxc_storage_rsync_exec_wrapper, (void *)&data);
+       if (ret < 0) {
+               ERROR("Failed to rsync from \"%s\" into \"%s\"%s%s", orig->dest,
+                     new->dest,
+                     cmd_output[0] != '\0' ? ": " : "",
+                     cmd_output[0] != '\0' ? cmd_output : "");
+               goto on_error_put_new;
+       }
+
+on_success:
+       storage_put(orig);
+
+       return new;
+
+on_error_put_new:
+       storage_put(new);
+
+on_error_put_orig:
+       storage_put(orig);
+
+       return NULL;
+}
+
+/* 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 storage_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 lxc_storage *storage_create(const char *dest, const char *type,
+                                  const char *cname, struct bdev_specs *specs)
+{
+       struct lxc_storage *bdev;
+       char *best_options[] = {"btrfs", "zfs", "lvm", "dir", "rbd", NULL};
+
+       if (!type)
+               return do_storage_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++) {
+                       bdev = do_storage_create(dest, best_options[i], cname,
+                                                specs);
+                       if (bdev)
+                               return bdev;
+               }
+
+               return NULL;
+       }
+
+       /* -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_storage_create(dest, token, cname, specs)))
+                               return bdev;
+               }
+       }
+
+       return do_storage_create(dest, type, cname, specs);
+}
+
+bool storage_destroy(struct lxc_conf *conf)
+{
+       struct lxc_storage *r;
+       bool ret = false;
+
+       r = storage_init(conf, conf->rootfs.path, conf->rootfs.mount, NULL);
+       if (!r)
+               return ret;
+
+       if (r->ops->destroy(r) == 0)
+               ret = true;
+
+       storage_put(r);
+       return ret;
+}
+
+struct lxc_storage *storage_init(struct lxc_conf *conf, const char *src,
+                                const char *dst, const char *mntopts)
+{
+       struct lxc_storage *bdev;
+       const struct lxc_storage_type *q;
+
+       BUILD_BUG_ON(LXC_STORAGE_INTERNAL_OVERLAY_RESTORE <= LXC_CLONE_MAXFLAGS);
+
+       if (!src)
+               src = conf->rootfs.path;
+
+       if (!src)
+               return NULL;
+
+       q = storage_query(conf, src);
+       if (!q)
+               return NULL;
+
+       bdev = malloc(sizeof(struct lxc_storage));
+       if (!bdev)
+               return NULL;
+
+       memset(bdev, 0, sizeof(struct lxc_storage));
+       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;
+
+       if (!strcmp(bdev->type, "aufs"))
+               WARN("The \"aufs\" driver will is deprecated and will soon be "
+                    "removed. For similar functionality see the \"overlay\" "
+                    "storage driver");
+
+       return bdev;
+}
+
+bool storage_is_dir(struct lxc_conf *conf, const char *path)
+{
+       struct lxc_storage *orig;
+       bool bret = false;
+
+       orig = storage_init(conf, path, NULL, NULL);
+       if (!orig)
+               return bret;
+
+       if (strcmp(orig->type, "dir") == 0)
+               bret = true;
+
+       storage_put(orig);
+       return bret;
+}
+
+void storage_put(struct lxc_storage *bdev)
+{
+       free(bdev->mntopts);
+       free(bdev->src);
+       free(bdev->dest);
+       free(bdev);
+}
+
+bool rootfs_is_blockdev(struct lxc_conf *conf)
+{
+       const struct lxc_storage_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 = storage_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 ||
+           strcmp(q->name, "rbd") == 0 ||
+           strcmp(q->name, "zfs") == 0)
+               return true;
+
+       return false;
+}
+
+char *lxc_storage_get_path(char *src, const char *prefix)
+{
+       size_t prefix_len;
+
+       prefix_len = strlen(prefix);
+       if (!strncmp(src, prefix, prefix_len) && (*(src + prefix_len) == ':'))
+               return (src + prefix_len + 1);
+
+       return src;
+}
diff --git a/src/lxc/storage/storage.h b/src/lxc/storage/storage.h
new file mode 100644 (file)
index 0000000..c656d39
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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_STORAGE_H
+#define __LXC_STORAGE_H
+
+#include "config.h"
+#include <stdint.h>
+#include <sys/mount.h>
+
+#include <lxc/lxccontainer.h>
+
+#if IS_BIONIC
+#include <../include/lxcmntent.h>
+#else
+#include <mntent.h>
+#endif
+
+#ifndef MS_DIRSYNC
+#define MS_DIRSYNC 128
+#endif
+
+#ifndef MS_REC
+#define MS_REC 16384
+#endif
+
+#ifndef MNT_DETACH
+#define MNT_DETACH 2
+#endif
+
+#ifndef MS_SLAVE
+#define MS_SLAVE (1 << 19)
+#endif
+
+#ifndef MS_RELATIME
+#define MS_RELATIME (1 << 21)
+#endif
+
+#ifndef MS_STRICTATIME
+#define MS_STRICTATIME (1 << 24)
+#endif
+
+#define DEFAULT_FS_SIZE 1073741824
+#define DEFAULT_FSTYPE "ext3"
+
+#define LXC_STORAGE_INTERNAL_OVERLAY_RESTORE  (1 << 6)
+
+struct lxc_storage;
+
+struct lxc_storage_ops {
+       /* detect whether path is of this bdev type */
+       bool (*detect)(const char *path);
+
+       /* mount requires src and dest to be set. */
+       int (*mount)(struct lxc_storage *bdev);
+       int (*umount)(struct lxc_storage *bdev);
+       int (*destroy)(struct lxc_storage *bdev);
+       int (*create)(struct lxc_storage *bdev, const char *dest, const char *n,
+                     struct bdev_specs *specs);
+       /* given original mount, rename the paths for cloned container */
+       int (*clone_paths)(struct lxc_storage *orig, struct lxc_storage *new,
+                          const char *oldname, const char *cname,
+                          const char *oldpath, const char *lxcpath, int snap,
+                          uint64_t newsize, struct lxc_conf *conf);
+       bool (*copy)(struct lxc_conf *conf, struct lxc_storage *orig,
+                    struct lxc_storage *new, uint64_t newsize);
+       bool (*snapshot)(struct lxc_conf *conf, struct lxc_storage *orig,
+                        struct lxc_storage *new, uint64_t newsize);
+       bool can_snapshot;
+       bool can_backup;
+};
+
+/* When lxc is mounting a rootfs, then src will be the "lxc.rootfs.path" value,
+ * dest will be the mount dir (i.e. "<libdir>/lxc")  When clone or create is
+ * doing so, then dest will be "<lxcpath>/<lxcname>/rootfs", since we may need
+ * to rsync from one to the other.
+ */
+struct lxc_storage {
+       const struct lxc_storage_ops *ops;
+       const char *type;
+       char *src;
+       char *dest;
+       char *mntopts;
+       /* Turn the following into a union if need be. */
+       /* lofd is the open fd for the mounted loopback file. */
+       int lofd;
+       /* index for the connected nbd device. */
+       int nbd_idx;
+       int flags;
+};
+
+extern bool storage_is_dir(struct lxc_conf *conf, const char *path);
+extern bool storage_can_backup(struct lxc_conf *conf);
+
+/* Instantiate a lxc_storage object. The src is used to determine which blockdev
+ * type this should be. The dst and data are optional, and will be used in case
+ * of mount/umount.
+ *
+ * The source will be "dir:/var/lib/lxc/c1" or "lvm:/dev/lxc/c1". For other
+ * backing stores, this will allow additional options. In particular,
+ * "overlayfs:/var/lib/lxc/canonical/rootfs:/var/lib/lxc/c1/delta" will mean use
+ * /var/lib/lxc/canonical/rootfs as lower dir, and /var/lib/lxc/c1/delta as the
+ * upper, writeable layer.
+ */
+extern struct lxc_storage *storage_init(struct lxc_conf *conf, const char *src,
+                                       const char *dst, const char *data);
+
+extern struct lxc_storage *storage_copy(struct lxc_container *c0,
+                                       const char *cname, const char *lxcpath,
+                                       const char *bdevtype, int flags,
+                                       const char *bdevdata, uint64_t newsize,
+                                       bool *needs_rdep);
+extern struct lxc_storage *storage_create(const char *dest, const char *type,
+                                         const char *cname,
+                                         struct bdev_specs *specs);
+extern void storage_put(struct lxc_storage *bdev);
+extern bool storage_destroy(struct lxc_conf *conf);
+
+extern int storage_destroy_wrapper(void *data);
+extern bool rootfs_is_blockdev(struct lxc_conf *conf);
+extern char *lxc_storage_get_path(char *src, const char *prefix);
+
+#endif /* #define __LXC_STORAGE_H */
diff --git a/src/lxc/storage/storage_utils.c b/src/lxc/storage/storage_utils.c
new file mode 100644 (file)
index 0000000..787f138
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * Authors:
+ * Christian Brauner <christian.brauner@ubuntu.com>
+ *
+ * This program 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 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 <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 "log.h"
+#include "nbd.h"
+#include "parse.h"
+#include "storage.h"
+#include "storage_utils.h"
+#include "utils.h"
+
+#ifndef BLKGETSIZE64
+#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
+#endif
+
+lxc_log_define(storage_utils, lxc);
+
+/* 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) {
+               /* copy text up to oldname */
+               strncpy(p, src, p2 - src);
+               /* move target pointer (p) */
+               p += p2 - src;
+               /* print new name in place of oldname */
+               p += sprintf(p, "%s", name);
+               /* move src to end of oldname */
+               src = p2 + l2;
+       }
+       /* copy the rest of src */
+       sprintf(p, "%s", 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;
+}
+
+/*
+ * return block size of dev->src in units of bytes
+ */
+int blk_getsize(struct lxc_storage *bdev, uint64_t *size)
+{
+       int fd, ret;
+       char *src;
+
+       src = lxc_storage_get_path(bdev->src, bdev->type);
+       fd = open(src, O_RDONLY);
+       if (fd < 0)
+               return -1;
+
+       /* size of device in bytes */
+       ret = ioctl(fd, BLKGETSIZE64, size);
+       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 lxc_storage (presumably blockdev-based), detect the fstype
+ * by trying mounting (in a private mntns) it.
+ * @lxc_storage: 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 lxc_storage *bdev, char *type, int len)
+{
+       int p[2], ret;
+       size_t linelen;
+       pid_t pid;
+       FILE *f;
+       char *sp1, *sp2, *sp3, *srcdev, *line = NULL;
+
+       if (!bdev || !bdev->src || !bdev->dest)
+               return -1;
+
+       srcdev = lxc_storage_get_path(bdev->src, bdev->type);
+
+       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_exec_wrapper(void *args)
+{
+       int ret;
+       char *mkfs;
+       char **data = args;
+       /* strlen("mkfs.")
+        * +
+        * strlen(data[0])
+        * +
+        * \0
+        */
+       size_t len = 5 + strlen(data[0]) + 1;
+
+       mkfs = malloc(len);
+       if (!mkfs)
+               return -1;
+
+       ret = snprintf(mkfs, len, "mkfs.%s", data[0]);
+       if (ret < 0 || (size_t)ret >= len) {
+               free(mkfs);
+               return -1;
+       }
+
+       TRACE("executing \"%s %s\"", mkfs, data[1]);
+       execlp(mkfs, mkfs, data[1], (char *)NULL);
+       SYSERROR("failed to run \"%s %s \"", mkfs, data[1]);
+       return -1;
+}
+
+/*
+ * This will return 1 for physical disks, qemu-nbd, loop, etc right now only lvm
+ * is a block device.
+ */
+int is_blktype(struct lxc_storage *b)
+{
+       if (strcmp(b->type, "lvm") == 0)
+               return 1;
+
+       return 0;
+}
+
+int mount_unknown_fs(const char *rootfs, const char *target,
+                    const char *options)
+{
+       size_t i;
+       int ret;
+       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++) {
+               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;
+}
+
+/*
+ * 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
+ */
+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;
+}
+
+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
+ */
+bool unpriv_snap_allowed(struct lxc_storage *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, "overlay") == 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, "overlay") == 0 ||
+           strcmp(t, "overlayfs") == 0 ||
+           strcmp(t, "btrfs") == 0 ||
+           strcmp(t, "loop") == 0)
+               return true;
+
+       return false;
+}
+
+bool is_valid_storage_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, "overlay") == 0 ||
+           strcmp(type, "overlayfs") == 0 ||
+           strcmp(type, "rbd") == 0 ||
+           strcmp(type, "zfs") == 0)
+               return true;
+
+       return false;
+}
+
+int storage_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 (!storage_destroy(conf))
+               return -1;
+
+       return 0;
+}
diff --git a/src/lxc/storage/storage_utils.h b/src/lxc/storage/storage_utils.h
new file mode 100644 (file)
index 0000000..6f53d6f
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * Authors:
+ * Christian Brauner <christian.brauner@ubuntu.com>
+ *
+ * This program 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 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ */
+
+#ifndef __LXC_STORAGE_UTILS_H
+#define __LXC_STORAGE_UTILS_H
+
+#include "config.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "conf.h"
+
+struct lxc_storage;
+struct lxc_conf;
+
+extern char *dir_new_path(char *src, const char *oldname, const char *name,
+                         const char *oldpath, const char *lxcpath);
+extern bool attach_block_device(struct lxc_conf *conf);
+extern void detach_block_device(struct lxc_conf *conf);
+extern int blk_getsize(struct lxc_storage *bdev, uint64_t *size);
+extern int detect_fs(struct lxc_storage *bdev, char *type, int len);
+extern int do_mkfs_exec_wrapper(void *args);
+extern int is_blktype(struct lxc_storage *b);
+extern int mount_unknown_fs(const char *rootfs, const char *target,
+                           const char *options);
+extern int find_fstype_cb(char *buffer, void *data);
+extern char *linkderef(char *path, char *dest);
+extern bool unpriv_snap_allowed(struct lxc_storage *b, const char *t, bool snap,
+                               bool maybesnap);
+extern bool is_valid_storage_type(const char *type);
+extern int storage_destroy_wrapper(void *data);
+
+#endif /* __LXC_STORAGE_UTILS_H */
diff --git a/src/lxc/storage/zfs.c b/src/lxc/storage/zfs.c
new file mode 100644 (file)
index 0000000..be90e5a
--- /dev/null
@@ -0,0 +1,773 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "log.h"
+#include "parse.h"
+#include "rsync.h"
+#include "storage.h"
+#include "utils.h"
+#include "zfs.h"
+
+lxc_log_define(zfs, lxc);
+
+struct zfs_args {
+       const char *dataset;
+       const char *snapshot;
+       const char *options;
+       void *argv;
+};
+
+int zfs_detect_exec_wrapper(void *data)
+{
+       struct zfs_args *args = data;
+
+       execlp("zfs", "zfs", "get", "type", "-H", "-o", "name", args->dataset,
+              (char *)NULL);
+
+       return -1;
+}
+
+int zfs_create_exec_wrapper(void *args)
+{
+       struct zfs_args *zfs_args = args;
+
+       execvp("zfs", zfs_args->argv);
+
+       return -1;
+}
+
+int zfs_delete_exec_wrapper(void *args)
+{
+       struct zfs_args *zfs_args = args;
+
+       execlp("zfs", "zfs", "destroy", "-r", zfs_args->dataset, (char *)NULL);
+
+       return -1;
+}
+
+int zfs_snapshot_exec_wrapper(void *args)
+{
+       struct zfs_args *zfs_args = args;
+
+       execlp("zfs", "zfs", "snapshot", "-r", zfs_args->snapshot, (char *)NULL);
+
+       return -1;
+}
+
+int zfs_clone_exec_wrapper(void *args)
+{
+       struct zfs_args *zfs_args = args;
+
+       execlp("zfs", "zfs", "clone", "-p", "-o", "canmount=noauto", "-o",
+              zfs_args->options, zfs_args->snapshot, zfs_args->dataset,
+              (char *)NULL);
+
+       return -1;
+}
+
+int zfs_get_parent_snapshot_exec_wrapper(void *args)
+{
+       struct zfs_args *zfs_args = args;
+
+       execlp("zfs", "zfs", "get", "origin", "-o", "value", "-H",
+              zfs_args->dataset, (char *)NULL);
+
+       return -1;
+}
+
+static bool zfs_list_entry(const char *path, char *output, size_t inlen)
+{
+       struct lxc_popen_FILE *f;
+       bool found = false;
+
+       f = lxc_popen("zfs list 2> /dev/null");
+       if (f == NULL) {
+               SYSERROR("popen failed");
+               return false;
+       }
+
+       while (fgets(output, inlen, f->f)) {
+               if (strstr(output, path)) {
+                       found = true;
+                       break;
+               }
+       }
+       (void)lxc_pclose(f);
+
+       return found;
+}
+
+bool zfs_detect(const char *path)
+{
+       int ret;
+       char *dataset;
+       struct zfs_args cmd_args = {0};
+       char cmd_output[MAXPATHLEN] = {0};
+
+       if (!strncmp(path, "zfs:", 4))
+               return true;
+
+       /* This is a legacy zfs setup where the rootfs path
+        * "<lxcpath>/<lxcname>/rootfs" is given.
+        */
+       if (*path == '/') {
+               bool found;
+               char *output = malloc(LXC_LOG_BUFFER_SIZE);
+
+               if (!output) {
+                       ERROR("out of memory");
+                       return false;
+               }
+
+               found = zfs_list_entry(path, output, LXC_LOG_BUFFER_SIZE);
+               free(output);
+               return found;
+       }
+
+       cmd_args.dataset = path;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         zfs_detect_exec_wrapper, (void *)&cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to detect zfs dataset \"%s\": %s", path, cmd_output);
+               return false;
+       }
+
+       if (cmd_output[0] == '\0')
+               return false;
+
+       /* remove any possible leading and trailing whitespace */
+       dataset = cmd_output;
+       dataset += lxc_char_left_gc(dataset, strlen(dataset));
+       dataset[lxc_char_right_gc(dataset, strlen(dataset))] = '\0';
+
+       if (strcmp(dataset, path))
+               return false;
+
+       return true;
+}
+
+int zfs_mount(struct lxc_storage *bdev)
+{
+       int ret;
+       size_t oldlen, newlen, totallen;
+       char *mntdata, *src, *tmp;
+       unsigned long mntflags;
+       char cmd_output[MAXPATHLEN] = {0};
+
+       if (strcmp(bdev->type, "zfs"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata);
+       if (ret < 0) {
+               ERROR("Failed to parse mount options");
+               free(mntdata);
+               return -22;
+       }
+
+       /* This is a legacy zfs setup where the rootfs path
+        * "<lxcpath>/<lxcname>/rootfs" is given and we do a bind-mount.
+        */
+       src = lxc_storage_get_path(bdev->src, bdev->type);
+       if (*src == '/') {
+               bool found;
+
+               found = zfs_list_entry(src, cmd_output, sizeof(cmd_output));
+               if (!found) {
+                       ERROR("Failed to find zfs entry \"%s\"", src);
+                       return -1;
+               }
+
+               tmp = strchr(cmd_output, ' ');
+               if (!tmp) {
+                       ERROR("Failed to detect zfs dataset associated with "
+                             "\"%s\"", src);
+                       return -1;
+               }
+               *tmp = '\0';
+               src = cmd_output;
+       }
+
+       /* ','
+        * +
+        * strlen("zfsutil")
+        * +
+        * ','
+        * +
+        * strlen(mntpoint=)
+        * +
+        * strlen(src)
+        * +
+        * '\0'
+        */
+       newlen = 1 + 7 + 1 + 9 + strlen(src) + 1;
+       oldlen = mntdata ? strlen(mntdata) : 0;
+       totallen = (newlen + oldlen);
+       tmp = realloc(mntdata, totallen);
+       if (!tmp) {
+               ERROR("Failed to reallocate memory");
+               free(mntdata);
+               return -1;
+       }
+       mntdata = tmp;
+
+       ret = snprintf((mntdata + oldlen), newlen, ",zfsutil,mntpoint=%s", src);
+       if (ret < 0 || (size_t)ret >= newlen) {
+               ERROR("Failed to create string");
+               free(mntdata);
+               return -1;
+       }
+
+       ret = mount(src, bdev->dest, "zfs", mntflags, mntdata);
+       free(mntdata);
+       if (ret < 0 && errno != EBUSY) {
+               SYSERROR("Failed to mount \"%s\" on \"%s\"", src, bdev->dest);
+               return -1;
+       }
+
+       TRACE("Mounted \"%s\" on \"%s\"", src, bdev->dest);
+       return 0;
+}
+
+int zfs_umount(struct lxc_storage *bdev)
+{
+       int ret;
+
+       if (strcmp(bdev->type, "zfs"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       ret = umount(bdev->dest);
+       if (ret < 0)
+               SYSERROR("Failed to unmount \"%s\"", bdev->dest);
+       else
+               TRACE("Unmounted \"%s\"", bdev->dest);
+
+       return ret;
+}
+
+bool zfs_copy(struct lxc_conf *conf, struct lxc_storage *orig,
+             struct lxc_storage *new, uint64_t newsize)
+{
+       int ret;
+       char cmd_output[MAXPATHLEN], option[MAXPATHLEN];
+       struct rsync_data data = {0, 0};
+       struct zfs_args cmd_args = {0};
+       char *argv[] = {"zfs",                       /* 0    */
+                       "create",                    /* 1    */
+                       "-o",     "",                /* 2, 3 */
+                       "-o",     "canmount=noauto", /* 4, 5 */
+                       "-p",                        /* 6    */
+                       "",                          /* 7    */
+                       NULL};
+
+       /* mountpoint */
+       ret = snprintf(option, MAXPATHLEN, "mountpoint=%s", new->dest);
+       if (ret < 0 || ret >= MAXPATHLEN) {
+               ERROR("Failed to create string");
+               return false;
+       }
+       argv[3] = option;
+       argv[7] = lxc_storage_get_path(new->src, new->type);
+
+       cmd_args.argv = argv;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         zfs_create_exec_wrapper, (void *)&cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to create zfs dataset \"%s\": %s", new->src, cmd_output);
+               return false;
+       } else if (cmd_output[0] != '\0') {
+               INFO("Created zfs dataset \"%s\": %s", new->src, cmd_output);
+       } else {
+               TRACE("Created zfs dataset \"%s\"", new->src);
+       }
+
+       ret = mkdir_p(new->dest, 0755);
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create directory \"%s\"", new->dest);
+               return false;
+       }
+
+       data.orig = orig;
+       data.new = new;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         lxc_storage_rsync_exec_wrapper, (void *)&data);
+       if (ret < 0) {
+               ERROR("Failed to rsync from \"%s\" into \"%s\": %s", orig->dest,
+                     new->dest, cmd_output);
+               return false;
+       }
+       TRACE("Rsynced from \"%s\" to \"%s\"", orig->dest, new->dest);
+
+       return true;
+}
+
+/* create read-only snapshot and create a clone from it */
+bool zfs_snapshot(struct lxc_conf *conf, struct lxc_storage *orig,
+                 struct lxc_storage *new, uint64_t newsize)
+{
+       int ret;
+       size_t snapshot_len, len;
+       char *orig_src, *tmp, *snap_name, *snapshot;
+       struct zfs_args cmd_args = {0};
+       char cmd_output[MAXPATHLEN] = {0}, option[MAXPATHLEN];
+
+       orig_src = lxc_storage_get_path(orig->src, orig->type);
+       if (*orig_src == '/') {
+               bool found;
+
+               found = zfs_list_entry(orig_src, cmd_output, sizeof(cmd_output));
+               if (!found) {
+                       ERROR("Failed to find zfs entry \"%s\"", orig_src);
+                       return false;
+               }
+
+               tmp = strchr(cmd_output, ' ');
+               if (!tmp) {
+                       ERROR("Failed to detect zfs dataset associated with "
+                             "\"%s\"", orig_src);
+                       return false;
+               }
+               *tmp = '\0';
+               orig_src = cmd_output;
+       }
+
+       snapshot = strdup(orig_src);
+       if (!snapshot) {
+               ERROR("Failed to duplicate string \"%s\"", orig_src);
+               return false;
+       }
+
+       snap_name = strrchr(new->src, '/');
+       if (!snap_name) {
+               ERROR("Failed to detect \"/\" in \"%s\"", new->src);
+               free(snapshot);
+               return false;
+       }
+       snap_name++;
+
+       /* strlen(snapshot)
+        * +
+        * @
+        * +
+        * strlen(cname)
+        * +
+        * \0
+        */
+       snapshot_len = strlen(snapshot);
+       len = snapshot_len + 1 + strlen(snap_name) + 1;
+       tmp = realloc(snapshot, len);
+       if (!tmp) {
+               ERROR("Failed to reallocate memory");
+               free(snapshot);
+               return false;
+       }
+       snapshot = tmp;
+
+       len -= snapshot_len;
+       ret = snprintf(snapshot + snapshot_len, len, "@%s", snap_name);
+       if (ret < 0 || ret >= len) {
+               ERROR("Failed to create string");
+               free(snapshot);
+               return false;
+       }
+
+       cmd_args.snapshot = snapshot;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         zfs_snapshot_exec_wrapper, (void *)&cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to create zfs snapshot \"%s\": %s", snapshot, cmd_output);
+               free(snapshot);
+               return false;
+       } else if (cmd_output[0] != '\0') {
+               INFO("Created zfs snapshot \"%s\": %s", snapshot, cmd_output);
+       } else {
+               TRACE("Created zfs snapshot \"%s\"", snapshot);
+       }
+
+       ret = snprintf(option, MAXPATHLEN, "mountpoint=%s", new->dest);
+       if (ret < 0 || ret >= MAXPATHLEN) {
+               ERROR("Failed to create string");
+               free(snapshot);
+               return -1;
+       }
+
+       cmd_args.dataset = lxc_storage_get_path(new->src, new->type);
+       cmd_args.snapshot = snapshot;
+       cmd_args.options = option;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         zfs_clone_exec_wrapper, (void *)&cmd_args);
+       if (ret < 0)
+               ERROR("Failed to create zfs dataset \"%s\": %s", new->src, cmd_output);
+       else if (cmd_output[0] != '\0')
+               INFO("Created zfs dataset \"%s\": %s", new->src, cmd_output);
+       else
+               TRACE("Created zfs dataset \"%s\"", new->src);
+
+       free(snapshot);
+       return true;
+}
+
+int zfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                  const char *oldname, const char *cname, const char *oldpath,
+                  const char *lxcpath, int snap, uint64_t newsize,
+                  struct lxc_conf *conf)
+{
+       char *dataset, *orig_src, *tmp;
+       int ret;
+       size_t dataset_len, len;
+       char cmd_output[MAXPATHLEN] = {0};
+
+       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;
+       }
+
+       orig_src = lxc_storage_get_path(orig->src, orig->type);
+       if (!strcmp(orig->type, "zfs")) {
+               size_t len;
+               if (*orig_src == '/') {
+                       bool found;
+
+                       found = zfs_list_entry(orig_src, cmd_output,
+                                              sizeof(cmd_output));
+                       if (!found) {
+                               ERROR("Failed to find zfs entry \"%s\"", orig_src);
+                               return -1;
+                       }
+
+                       tmp = strchr(cmd_output, ' ');
+                       if (!tmp) {
+                               ERROR("Failed to detect zfs dataset associated "
+                                     "with \"%s\"", orig_src);
+                               return -1;
+                       }
+                       *tmp = '\0';
+                       orig_src = cmd_output;
+               }
+
+               tmp = strrchr(orig_src, '/');
+               if (!tmp) {
+                       ERROR("Failed to detect \"/\" in \"%s\"", orig_src);
+                       return -1;
+               }
+
+               len = tmp - orig_src;
+               dataset = strndup(orig_src, len);
+               if (!dataset) {
+                       ERROR("Failed to duplicate string \"%zu\" "
+                                       "bytes of string \"%s\"", len, orig_src);
+                       return -1;
+               }
+       } else {
+               tmp = (char *)lxc_global_config_value("lxc.bdev.zfs.root");
+               if (!tmp) {
+                       ERROR("The \"lxc.bdev.zfs.root\" property is not set");
+                       return -1;
+               }
+
+               dataset = strdup(tmp);
+               if (!dataset) {
+                       ERROR("Failed to duplicate string \"%s\"", tmp);
+                       return -1;
+               }
+       }
+
+       /* strlen("zfs:") = 4
+        * +
+        * strlen(dataset)
+        * +
+        * / = 1
+        * +
+        * strlen(cname)
+        * +
+        * \0
+        */
+       dataset_len = strlen(dataset);
+       len = 4 + dataset_len + 1 + strlen(cname) + 1;
+       new->src = realloc(dataset, len);
+       if (!new->src) {
+               ERROR("Failed to reallocate memory");
+               free(dataset);
+               return -1;
+       }
+       memmove(new->src + 4, new->src, dataset_len);
+       memmove(new->src, "zfs:", 4);
+
+       len -= dataset_len - 4;
+       ret = snprintf(new->src + dataset_len + 4, len, "/%s", cname);
+       if (ret < 0 || ret >= len) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+
+       /* strlen(lxcpath)
+        * +
+        * /
+        * +
+        * strlen(cname)
+        * +
+        * /
+        * +
+        * strlen("rootfs")
+        * +
+        * \0
+        */
+       len = strlen(lxcpath) + 1 + strlen(cname) + 1 + strlen("rootfs") + 1;
+       new->dest = malloc(len);
+       if (!new->dest) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname);
+       if (ret < 0 || ret >= len) {
+               ERROR("Failed to create string \"%s/%s/rootfs\"", lxcpath, cname);
+               return -1;
+       }
+
+       ret = mkdir_p(new->dest, 0755);
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create directory \"%s\"", new->dest);
+               return -1;
+       }
+
+       return 0;
+}
+
+int zfs_destroy(struct lxc_storage *orig)
+{
+       int ret;
+       char *dataset, *src, *tmp;
+       bool found;
+       char *parent_snapshot = NULL;
+       struct zfs_args cmd_args = {0};
+       char cmd_output[MAXPATHLEN] = {0};
+
+       src = lxc_storage_get_path(orig->src, orig->type);
+
+       /* This is a legacy zfs setup where the rootfs path
+        * "<lxcpath>/<lxcname>/rootfs" is given.
+        */
+       if (*src == '/') {
+               char *tmp;
+
+               found = zfs_list_entry(src, cmd_output, sizeof(cmd_output));
+               if (!found) {
+                       ERROR("Failed to find zfs entry \"%s\"", orig->src);
+                       return -1;
+               }
+
+               tmp = strchr(cmd_output, ' ');
+               if (!tmp) {
+                       ERROR("Failed to detect zfs dataset associated with "
+                             "\"%s\"", cmd_output);
+                       return -1;
+               }
+               *tmp = '\0';
+               dataset = cmd_output;
+       } else {
+               cmd_args.dataset = src;
+               ret = run_command(cmd_output, sizeof(cmd_output),
+                                 zfs_detect_exec_wrapper, (void *)&cmd_args);
+               if (ret < 0) {
+                       ERROR("Failed to detect zfs dataset \"%s\": %s", src,
+                             cmd_output);
+                       return -1;
+               }
+
+               if (cmd_output[0] == '\0') {
+                       ERROR("Failed to detect zfs dataset \"%s\"", src);
+                       return -1;
+               }
+
+               /* remove any possible leading and trailing whitespace */
+               dataset = cmd_output;
+               dataset += lxc_char_left_gc(dataset, strlen(dataset));
+               dataset[lxc_char_right_gc(dataset, strlen(dataset))] = '\0';
+
+               if (strcmp(dataset, src)) {
+                       ERROR("Detected dataset \"%s\" does not match expected "
+                             "dataset \"%s\"", dataset, src);
+                       return -1;
+               }
+       }
+
+       cmd_args.dataset = strdup(dataset);
+       if (!cmd_args.dataset) {
+               ERROR("Failed to duplicate string \"%s\"", dataset);
+               return -1;
+       }
+
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         zfs_get_parent_snapshot_exec_wrapper,
+                         (void *)&cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to retrieve parent snapshot of zfs dataset "
+                     "\"%s\": %s", dataset, cmd_output);
+               free((void *)cmd_args.dataset);
+               return -1;
+       } else {
+               INFO("Retrieved parent snapshot of zfs dataset \"%s\": %s", src,
+                    cmd_output);
+       }
+
+       /* remove any possible leading and trailing whitespace */
+       tmp = cmd_output;
+       tmp += lxc_char_left_gc(tmp, strlen(tmp));
+       tmp[lxc_char_right_gc(tmp, strlen(tmp))] = '\0';
+
+       /* check whether the dataset has a parent snapshot */
+       if (*tmp != '-' && *(tmp + 1) != '\0') {
+               parent_snapshot = strdup(tmp);
+               if (!parent_snapshot) {
+                       ERROR("Failed to duplicate string \"%s\"", tmp);
+                       free((void *)cmd_args.dataset);
+                       return -1;
+               }
+       }
+
+       /* delete dataset */
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         zfs_delete_exec_wrapper, (void *)&cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to delete zfs dataset \"%s\": %s", dataset,
+                     cmd_output);
+               free((void *)cmd_args.dataset);
+               free(parent_snapshot);
+               return -1;
+       } else if (cmd_output[0] != '\0') {
+               INFO("Deleted zfs dataset \"%s\": %s", src, cmd_output);
+       } else {
+               INFO("Deleted zfs dataset \"%s\"", src);
+       }
+
+       free((void *)cmd_args.dataset);
+
+       /* Not a clone so nothing more to do. */
+       if (!parent_snapshot)
+               return 0;
+
+       /* delete parent snapshot */
+       cmd_args.dataset = parent_snapshot;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         zfs_delete_exec_wrapper, (void *)&cmd_args);
+       if (ret < 0)
+               ERROR("Failed to delete zfs snapshot \"%s\": %s", dataset, cmd_output);
+       else if (cmd_output[0] != '\0')
+               INFO("Deleted zfs snapshot \"%s\": %s", src, cmd_output);
+       else
+               INFO("Deleted zfs snapshot \"%s\"", src);
+
+       free((void *)cmd_args.dataset);
+       return ret;
+}
+
+int zfs_create(struct lxc_storage *bdev, const char *dest, const char *n,
+              struct bdev_specs *specs)
+{
+       const char *zfsroot;
+       int ret;
+       size_t len;
+       struct zfs_args cmd_args = {0};
+       char cmd_output[MAXPATHLEN], option[MAXPATHLEN];
+       char *argv[] = {"zfs",                    /* 0    */
+                        "create",                /* 1    */
+                        "-o", "",                /* 2, 3 */
+                        "-o", "canmount=noauto", /* 4, 5 */
+                        "-p",                    /* 6    */
+                        "",                      /* 7    */
+                        NULL};
+
+       if (!specs || !specs->zfs.zfsroot)
+               zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
+       else
+               zfsroot = specs->zfs.zfsroot;
+
+       bdev->dest = strdup(dest);
+       if (!bdev->dest) {
+               ERROR("Failed to duplicate string \"%s\"", dest);
+               return -1;
+       }
+
+       len = strlen(zfsroot) + 1 + strlen(n) + 1;
+       /* strlen("zfs:") */
+       len += 4;
+       bdev->src = malloc(len);
+       if (!bdev->src) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       ret = snprintf(bdev->src, len, "zfs:%s/%s", zfsroot, n);
+       if (ret < 0 || ret >= len) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+       argv[7] = lxc_storage_get_path(bdev->src, bdev->type);
+
+       ret = snprintf(option, MAXPATHLEN, "mountpoint=%s", bdev->dest);
+       if (ret < 0 || ret >= MAXPATHLEN) {
+               ERROR("Failed to create string");
+               return -1;
+       }
+       argv[3] = option;
+
+       cmd_args.argv = argv;
+       ret = run_command(cmd_output, sizeof(cmd_output),
+                         zfs_create_exec_wrapper, (void *)&cmd_args);
+       if (ret < 0) {
+               ERROR("Failed to create zfs dataset \"%s\": %s", bdev->src, cmd_output);
+               return -1;
+       } else if (cmd_output[0] != '\0') {
+               INFO("Created zfs dataset \"%s\": %s", bdev->src, cmd_output);
+       } else {
+               TRACE("Created zfs dataset \"%s\"", bdev->src);
+       }
+
+       ret = mkdir_p(bdev->dest, 0755);
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create directory \"%s\"", bdev->dest);
+               return -1;
+       }
+
+       return ret;
+}
diff --git a/src/lxc/storage/zfs.h b/src/lxc/storage/zfs.h
new file mode 100644 (file)
index 0000000..abfc012
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+
+struct lxc_storage;
+
+struct bdev_specs;
+
+struct lxc_conf;
+
+extern int zfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
+                         const char *oldname, const char *cname,
+                         const char *oldpath, const char *lxcpath, int snap,
+                         uint64_t newsize, struct lxc_conf *conf);
+extern int zfs_create(struct lxc_storage *bdev, const char *dest, const char *n,
+                     struct bdev_specs *specs);
+extern int zfs_destroy(struct lxc_storage *orig);
+extern bool zfs_detect(const char *path);
+extern int zfs_mount(struct lxc_storage *bdev);
+extern int zfs_umount(struct lxc_storage *bdev);
+
+extern bool zfs_copy(struct lxc_conf *conf, struct lxc_storage *orig,
+                    struct lxc_storage *new, uint64_t newsize);
+extern bool zfs_snapshot(struct lxc_conf *conf, struct lxc_storage *orig,
+                        struct lxc_storage *new, uint64_t newsize);
+
+#endif /* __LXC_ZFS_H */
index 89cbf8a3b7ed6cff012f1abd40eccb8ae214c460..9c20c1d69c93ecc10c04da557d75b68e737b0773 100644 (file)
@@ -86,63 +86,63 @@ static int __sync_barrier(int fd, int sequence)
 
 int lxc_sync_barrier_parent(struct lxc_handler *handler, int sequence)
 {
-       return __sync_barrier(handler->sv[0], sequence);
+       return __sync_barrier(handler->sync_sock[0], sequence);
 }
 
 int lxc_sync_barrier_child(struct lxc_handler *handler, int sequence)
 {
-       return __sync_barrier(handler->sv[1], sequence);
+       return __sync_barrier(handler->sync_sock[1], sequence);
 }
 
 int lxc_sync_wake_parent(struct lxc_handler *handler, int sequence)
 {
-       return __sync_wake(handler->sv[0], sequence);
+       return __sync_wake(handler->sync_sock[0], sequence);
 }
 
 int lxc_sync_wait_parent(struct lxc_handler *handler, int sequence)
 {
-       return __sync_wait(handler->sv[0], sequence);
+       return __sync_wait(handler->sync_sock[0], sequence);
 }
 
 int lxc_sync_wait_child(struct lxc_handler *handler, int sequence)
 {
-       return __sync_wait(handler->sv[1], sequence);
+       return __sync_wait(handler->sync_sock[1], sequence);
 }
 
 int lxc_sync_wake_child(struct lxc_handler *handler, int sequence)
 {
-       return __sync_wake(handler->sv[1], sequence);
+       return __sync_wake(handler->sync_sock[1], sequence);
 }
 
 int lxc_sync_init(struct lxc_handler *handler)
 {
        int ret;
 
-       ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, handler->sv);
+       ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, handler->sync_sock);
        if (ret) {
                SYSERROR("failed to create synchronization socketpair");
                return -1;
        }
 
        /* Be sure we don't inherit this after the exec */
-       fcntl(handler->sv[0], F_SETFD, FD_CLOEXEC);
+       fcntl(handler->sync_sock[0], F_SETFD, FD_CLOEXEC);
 
        return 0;
 }
 
 void lxc_sync_fini_child(struct lxc_handler *handler)
 {
-       if (handler->sv[0] != -1) {
-               close(handler->sv[0]);
-               handler->sv[0] = -1;
+       if (handler->sync_sock[0] != -1) {
+               close(handler->sync_sock[0]);
+               handler->sync_sock[0] = -1;
        }
 }
 
 void lxc_sync_fini_parent(struct lxc_handler *handler)
 {
-       if (handler->sv[1] != -1) {
-               close(handler->sv[1]);
-               handler->sv[1] = -1;
+       if (handler->sync_sock[1] != -1) {
+               close(handler->sync_sock[1]);
+               handler->sync_sock[1] = -1;
        }
 }
 
index 744db613e4d813ba2a766cd23dbd196d35c43da8..5c0fb34310eb2cf8de2613704885faaefff371b4 100644 (file)
@@ -32,7 +32,7 @@ enum {
        LXC_SYNC_CGROUP,
        LXC_SYNC_CGROUP_UNSHARE,
        LXC_SYNC_CGROUP_LIMITS,
-       LXC_SYNC_POST_CGROUP,
+       LXC_SYNC_READY_START,
        LXC_SYNC_RESTART,
        LXC_SYNC_POST_RESTART,
        LXC_SYNC_ERROR = -1 /* Used to report errors from another process */
index 94bd268b5c495593a2bcc3c37a211b01d8ee4d79..61681ee127b8378e7d607edc5a85c4fa7902b68e 100644 (file)
@@ -105,16 +105,16 @@ echo
 echo -n "User namespace: " && is_enabled CONFIG_USER_NS
 echo
 if is_set CONFIG_USER_NS; then
-       if type newuidmap > /dev/null 2>&1; then
-               f=`type -P newuidmap`
+       if which newuidmap > /dev/null 2>&1; then
+               f=`which newuidmap`
                if [ ! -u "${f}" ]; then
                        echo "Warning: newuidmap is not setuid-root"
                fi
        else
                echo "newuidmap is not installed"
        fi
-       if type newgidmap > /dev/null 2>&1; then
-               f=`type -P newgidmap`
+       if which newgidmap > /dev/null 2>&1; then
+               f=`which newgidmap`
                if [ ! -u "${f}" ]; then
                        echo "Warning: newgidmap is not setuid-root"
                fi
@@ -128,30 +128,59 @@ if ([ $KVER_MAJOR -lt 4 ]) || ([ $KVER_MAJOR -eq 4 ] && [ $KVER_MINOR -lt 7 ]);
        echo -n "Multiple /dev/pts instances: " && is_enabled DEVPTS_MULTIPLE_INSTANCES
 fi
 echo
+
 echo "--- Control groups ---"
 
+echo -n "Cgroups: " && is_enabled CONFIG_CGROUPS
+echo
+
 print_cgroups() {
   # print all mountpoints for cgroup filesystems
   awk '$1 !~ /#/ && $3 == mp { print $2; } ; END { exit(0); } '  "mp=$1" "$2" ;
 }
 
-CGROUP_MNT_PATH=`print_cgroups cgroup /proc/self/mounts | head -n 1`
+CGROUP_V1_MNTS=`print_cgroups cgroup /proc/self/mounts`
+echo
+echo "Cgroup v1 mount points: "
+echo "$CGROUP_V1_MNTS"
+echo
 
-echo -n "Cgroup: " && is_enabled CONFIG_CGROUPS
+CGROUP_V2_MNTS=`print_cgroups cgroup2 /proc/self/mounts`
+echo "Cgroup v2 mount points: "
+echo "$CGROUP_V2_MNTS"
 echo
 
+CGROUP_SYSTEMD_MNTPT=`echo "$CGROUP_V1_MNTS" | grep "/systemd"`
+if [ -z "$CGROUP_SYSTEMD_MNTPT" ]; then
+    echo -n "Cgroup v1 systemd controller: "
+    "$SETCOLOR_FAILURE" && echo -n "missing" && $SETCOLOR_NORMAL
+    echo
+fi
+
+CGROUP_FREEZER_MNTPT=`echo "$CGROUP_V1_MNTS" | grep "/freezer"`
+if [ -z "$CGROUP_FREEZER_MNTPT" ]; then
+    echo -n "Cgroup v1 freezer controller: "
+    "$SETCOLOR_FAILURE" && echo -n "missing" && $SETCOLOR_NORMAL
+    echo
+fi
+
+CGROUP_MNT_PATH=`echo "$CGROUP_V1_MNTS" | head -n 1`
 if [ -f $CGROUP_MNT_PATH/cgroup.clone_children ]; then
-    echo -n "Cgroup clone_children flag: " &&
+    echo -n "Cgroup v1 clone_children flag: " &&
     $SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
 else
     echo -n "Cgroup namespace: " && is_enabled CONFIG_CGROUP_NS yes
 fi
+
 echo -n "Cgroup device: " && is_enabled CONFIG_CGROUP_DEVICE
 echo
+
 echo -n "Cgroup sched: " && is_enabled CONFIG_CGROUP_SCHED
 echo
+
 echo -n "Cgroup cpu account: " && is_enabled CONFIG_CGROUP_CPUACCT
 echo
+
 echo -n "Cgroup memory controller: "
 if ([ $KVER_MAJOR -ge 3 ] && [ $KVER_MINOR -ge 6 ]) || ([ $KVER_MAJOR -gt 3 ]); then
     is_enabled CONFIG_MEMCG
@@ -159,8 +188,10 @@ else
     is_enabled CONFIG_CGROUP_MEM_RES_CTLR
 fi
 echo
+
 is_set CONFIG_SMP && echo -n "Cgroup cpuset: " && is_enabled CONFIG_CPUSETS && echo
 echo
+
 echo "--- Misc ---"
 echo -n "Veth pair device: " && is_enabled CONFIG_VETH && is_probed veth
 echo
@@ -181,6 +212,7 @@ echo
 echo -n "CONFIG_IP6_NF_TARGET_MASQUERADE: " && is_enabled CONFIG_IP6_NF_TARGET_MASQUERADE && is_probed nf_nat_masquerade_ipv6
 echo
 echo -n "CONFIG_NETFILTER_XT_TARGET_CHECKSUM: " && is_enabled CONFIG_NETFILTER_XT_TARGET_CHECKSUM && is_probed xt_CHECKSUM
+echo -n "CONFIG_NETFILTER_XT_MATCH_COMMENT: " && is_enabled CONFIG_NETFILTER_XT_MATCH_COMMENT && is_probed xt_comment
 echo
 echo -n "FUSE (for use with lxcfs): " && is_enabled CONFIG_FUSE_FS && is_probed fuse
 echo
diff --git a/src/lxc/tools/lxc-update-config.in b/src/lxc/tools/lxc-update-config.in
new file mode 100644 (file)
index 0000000..785322c
--- /dev/null
@@ -0,0 +1,102 @@
+#!/bin/sh
+
+# Make sure the usual locations are in PATH
+export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
+
+set -e
+
+usage()
+{
+cat <<EOF
+$1 -h|--help [-c|--config]
+config: the container configuration to update
+EOF
+    return 0
+}
+
+OPTIONS=$(getopt -o c:h --long config:,help -- "${@}")
+eval set -- "${OPTIONS}"
+
+while true; do
+       case "${1}" in
+               -h|--help)
+                       usage "${0}"
+                       exit 0
+                       ;;
+               -c|--config)
+                       CONFIGPATH="${2}"
+                       shift 2
+                       ;;
+               --)
+                       shift 1
+                       break
+                       ;;
+               *)
+                       break
+                       ;;
+       esac
+done
+
+cp "${CONFIGPATH}" "${CONFIGPATH}.backup"
+
+sed -i \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.rootfs\)\([[:blank:]*]\|=\)/\1lxc\.rootfs\.path\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.id_map\)\([[:blank:]*]\|=\)/\1lxc\.idmap\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.pts\)\([[:blank:]*]\|=\)/\1lxc\.pty\.max\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.tty\)\([[:blank:]*]\|=\)/\1lxc\.tty\.max\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.devttydir\)\([[:blank:]*]\|=\)/\1lxc\.tty\.dir\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.aa_profile\)\([[:blank:]*]\|=\)/\1lxc\.apparmor\.profile\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.aa_allow_incomplete\)\([[:blank:]*]\|=\)/\1lxc\.apparmor\.allow_incomplete\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.se_context\)\([[:blank:]*]\|=\)/\1lxc\.selinux\.context\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.mount\)\([[:blank:]*]\|=\)/\1lxc\.mount\.fstab\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.utsname\)\([[:blank:]*]\|=\)/\1lxc\.uts\.name\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.rootfs\)\([[:blank:]*]\|=\)/\1lxc\.rootfs\.path\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.seccomp\)\([[:blank:]*]\|=\)/\1lxc\.seccomp\.profile\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.console\)\([[:blank:]*]\|=\)/\1lxc\.console\.path\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.haltsignal\)\([[:blank:]*]\|=\)/\1lxc\.signal\.halt\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.rebootsignal\)\([[:blank:]*]\|=\)/\1lxc\.signal\.reboot\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.stopsignal\)\([[:blank:]*]\|=\)/\1lxc\.signal\.stop\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.syslog\)\([[:blank:]*]\|=\)/\1lxc\.log\.syslog\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.loglevel\)\([[:blank:]*]\|=\)/\1lxc\.log\.level\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.logfile\)\([[:blank:]*]\|=\)/1lxc\.log\.file\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.init_cmd\)\([[:blank:]*]\|=\)/\1lxc\.init\.cmd\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.init_uid\)\([[:blank:]*]\|=\)/\1lxc\.init\.uid\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.init_gid\)\([[:blank:]*]\|=\)/\1lxc\.init\.gid\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.limit\)\([[:blank:]*]\|=\)/\1lxc\.prlimit\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.network\)\(\.[[:digit:]*]\)\(\.ipv4\)/\1lxc\.net\3\4\.address/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.network\)\(\.[[:digit:]*]\)/\1lxc\.net\3/g' \
+-e 's/\([[:blank:]*]\|#*\)\(lxc\.network\)\([[:blank:]*]\|=\)/\1lxc\.net\3/g' \
+-e '/\([[:blank:]*]\|#*\)\(lxc\.rootfs\.backend\)\([[:blank:]*]\|=\)/d' \
+-e '/\([[:blank:]*]\|#*\)\(lxc\.pivotdir\)\([[:blank:]*]\|=\)/d' \
+-e '/\([[:blank:]*]\|#*\)\(lxc\.kmsg\)\([[:blank:]*]\|=\)/d' \
+       "${CONFIGPATH}"
+
+# Finally, deal with network definitions of the following form:
+#
+# lxc.network.type = veth
+# lxc.network.flags = up
+# lxc.network.link = lxdbr0
+# lxc.network.name= eth0
+#
+# lxc.network.type = veth
+# lxc.network.flags = up
+# lxc.network.link = lxdbr0
+# lxc.network.name = eth1
+
+set +e
+
+TMPFILE=$(mktemp -p "${PWD}" XXXXXXXXXX)
+cp "${CONFIGPATH}" "${TMPFILE}"
+
+LINE_NUM=0
+IDX=-1
+while read -r LINE; do
+       LINE_NUM=$((LINE_NUM+1))
+       # A "lxc.network.type" key defines a new network. So everytime we see
+       # one we bump IDX and replace any "lxc.network.<subkey>" keys we
+       # encounter with "lxc.network.<IDX>.<subkey>".
+       echo "${LINE}" | grep -q "lxc.network.type" && IDX=$((IDX+1))
+       sed -i -e "${LINE_NUM} s/\([[:blank:]*]\|#*\)\(lxc\.network\)\.\([^[:digit:]*]\)/\1lxc\.net\.${IDX}\.\3/g" "${CONFIGPATH}"
+done < "${TMPFILE}"
+
+rm "${TMPFILE}"
index e7ecd0c5135234618cf7c8619c6fd04a7d97cbc0..b1062c822641ece00c3882fd3ed34410eb630ddf 100644 (file)
@@ -53,7 +53,7 @@ static uint64_t get_fssize(char *s)
        while (isblank(*end))
                end++;
        if (*end == '\0')
-               ret *= 1024ULL * 1024ULL; // MB by default
+               ret *= 1024ULL * 1024ULL; /* MB by default */
        else if (*end == 'b' || *end == 'B')
                ret *= 1ULL;
        else if (*end == 'k' || *end == 'K')
@@ -163,9 +163,10 @@ int main(int argc, char *argv[])
        if (keepname)  flags |= LXC_CLONE_KEEPNAME;
        if (keepmac)   flags |= LXC_CLONE_KEEPMACADDR;
 
-       // vgname and fstype could be supported by sending them through the
-       // bdevdata.  However, they currently are not yet.  I'm not convinced
-       // they are worthwhile.
+       /* vgname and fstype could be supported by sending them through the
+        * bdevdata.  However, they currently are not yet.  I'm not convinced
+        * they are worthwhile.
+        */
        if (vgname) {
                printf("Error: vgname not supported\n");
                usage(argv[0]);
index d884e590677724d54692c833cfc82d2dbf2f00aa..f1b51c4c7ba3d44e3a7d888311c5fc04410e0cb7 100644 (file)
 #include <lxc/lxccontainer.h>
 
 #include "attach.h"
-#include "bdev.h"
 #include "log.h"
 #include "confile.h"
 #include "arguments.h"
 #include "lxc.h"
 #include "conf.h"
 #include "state.h"
+#include "storage.h"
 #include "utils.h"
 
 #ifndef HAVE_GETSUBOPT
@@ -575,7 +575,7 @@ static uint64_t get_fssize(char *s)
        while (isblank(*end))
                end++;
        if (*end == '\0') {
-               ret *= 1024ULL * 1024ULL; // MB by default
+               ret *= 1024ULL * 1024ULL; /* MB by default */
        } else if (*end == 'b' || *end == 'B') {
                ret *= 1ULL;
        } else if (*end == 'k' || *end == 'K') {
index ad449dcada2ea8b333bb0672de46f5225bf485d9..7d925f5e0d4280474bf81ab0ae5ee9e972f99ebb 100644 (file)
@@ -27,9 +27,9 @@
 #include <sys/types.h>
 
 #include "arguments.h"
-#include "bdev.h"
 #include "log.h"
 #include "lxc.h"
+#include "storage.h"
 #include "storage_utils.h"
 #include "utils.h"
 
@@ -49,7 +49,7 @@ static uint64_t get_fssize(char *s)
        while (isblank(*end))
                end++;
        if (*end == '\0')
-               ret *= 1024ULL * 1024ULL; // MB by default
+               ret *= 1024ULL * 1024ULL; /* MB by default */
        else if (*end == 'b' || *end == 'B')
                ret *= 1ULL;
        else if (*end == 'k' || *end == 'K')
@@ -248,10 +248,10 @@ int main(int argc, char *argv[])
        if (strcmp(my_args.bdevtype, "none") == 0)
                my_args.bdevtype = "dir";
 
-       // Final check whether the user gave use a valid bdev type.
+       /* Final check whether the user gave use a valid bdev type. */
        if (strcmp(my_args.bdevtype, "best") &&
            strcmp(my_args.bdevtype, "_unset") &&
-           !is_valid_bdev_type(my_args.bdevtype)) {
+           !is_valid_storage_type(my_args.bdevtype)) {
                fprintf(stderr, "%s is not a valid backing storage type.\n", my_args.bdevtype);
                exit(EXIT_FAILURE);
        }
index fee4d80498510d9d45ff6bcea0ff75995d7bbe25..8b932dd1789c3c5bc8defbf4807c7b4a74d3a55f 100644 (file)
@@ -171,7 +171,7 @@ static bool do_destroy(struct lxc_container *c)
        if (ret < 0 || ret >= MAXPATHLEN)
                return false;
 
-       if (dir_exists(path)) {
+       if (rmdir(path) < 0 && errno != ENOENT) {
                if (!quiet)
                        fprintf(stdout, "Destroying %s failed: %s has snapshots.\n", c->name, c->name);
                return false;
@@ -271,7 +271,7 @@ static bool do_destroy_with_snapshots(struct lxc_container *c)
        if (ret < 0 || ret >= MAXPATHLEN)
                return false;
 
-       if (dir_exists(path))
+       if (rmdir(path) < 0 && errno != ENOENT)
                bret = c->destroy_with_snapshots(c);
        else
                bret = do_destroy(c);
index 0b3309a30fccfa9c9b81582f1ac52759505a74dd..234591c476d83b439f6535870ab6850deaaa10c0 100644 (file)
@@ -46,16 +46,6 @@ lxc_log_define(lxc_execute_ui, lxc);
 
 static struct lxc_list defines;
 
-static int my_checker(const struct lxc_arguments* args)
-{
-       if (!args->argc) {
-               lxc_error(args, "missing command to execute !");
-               return -1;
-       }
-
-       return 0;
-}
-
 static int my_parser(struct lxc_arguments* args, int c, char* arg)
 {
        switch (c) {
@@ -100,9 +90,26 @@ Options :\n\
   -g, --gid=GID        Execute COMMAND with GID inside the container\n",
        .options  = my_longopts,
        .parser   = my_parser,
-       .checker  = my_checker,
 };
 
+static bool set_argv(struct lxc_conf *conf, struct lxc_arguments *args)
+{
+       char **components, **p;
+
+       if (!conf->execute_cmd)
+               return false;
+
+       components = lxc_string_split_quoted(conf->execute_cmd);
+       if (!components)
+               return false;
+
+       args->argv = components;
+       for (p = components; *p; p++)
+               args->argc++;
+
+       return true;
+}
+
 int main(int argc, char *argv[])
 {
        struct lxc_container *c;
@@ -150,6 +157,14 @@ int main(int argc, char *argv[])
                }
        }
 
+       if (my_args.argc == 0) {
+               if (!set_argv(c->lxc_conf, &my_args)) {
+                       ERROR("missing command to execute!");
+                       lxc_container_put(c);
+                       exit(EXIT_FAILURE);
+               }
+       }
+
        if (my_args.uid)
                c->lxc_conf->init_uid = my_args.uid;
 
index ad102886b6ad85317af49264c255f20b6fb4e626..21f8d9264dd5cbe4fd8bf52b54d5f06fbcb843e2 100644 (file)
@@ -677,18 +677,22 @@ static char *ls_get_interface(struct lxc_container *c)
  */
 static double ls_get_swap(struct lxc_container *c)
 {
+       char *stat, *swap, *tmp;
        unsigned long long int num = 0;
-       char *stat = ls_get_cgroup_item(c, "memory.stat");
+
+       stat = ls_get_cgroup_item(c, "memory.stat");
        if (!stat)
                goto out;
 
-       char *swap = strstr(stat, "\nswap");
+       swap = strstr(stat, "\nswap");
        if (!swap)
                goto out;
 
-       swap = 1 + swap + 4 + 1; // start_of_swap_value = '\n' + strlen(swap) + ' '
+       /* start_of_swap_value = '\n' + strlen(swap) + ' ' */
+       swap = 1 + swap + 4 + 1;
 
-       char *tmp = strchr(swap, '\n'); // find end of swap value
+       /* find end of swap value */
+       tmp = strchr(swap, '\n');
        if (!tmp)
                goto out;
 
index 3c7bfade0324ef5c465134736a502ef208309ba6..82269ae387f6fc2f5ed7f1aee2f14956c932d808 100644 (file)
 
 #include <lxc/lxccontainer.h>
 
-#include "bdev.h"
 #include "lxc.h"
 #include "log.h"
 #include "arguments.h"
+#include "storage.h"
 #include "utils.h"
 
 lxc_log_define(lxc_snapshot_ui, lxc);
index ef45ffb083d435f57984ce212e5339cce308c9f4..d4653274572e8b590c291f1f9344a2b9afed5851 100644 (file)
@@ -53,6 +53,7 @@
 #define OPT_SHARE_NET OPT_USAGE + 1
 #define OPT_SHARE_IPC OPT_USAGE + 2
 #define OPT_SHARE_UTS OPT_USAGE + 3
+#define OPT_SHARE_PID OPT_USAGE + 4
 
 lxc_log_define(lxc_start_ui, lxc);
 
@@ -80,16 +81,11 @@ static int ensure_path(char **confpath, const char *path)
                        goto err;
                }
 
-               *confpath = strdup(fullpath);
-               if (!*confpath) {
-                       ERROR("failed to dup string '%s'", fullpath);
-                       goto err;
-               }
+               *confpath = fullpath;
        }
        err = EXIT_SUCCESS;
 
 err:
-       free(fullpath);
        return err;
 }
 
@@ -154,6 +150,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
        case OPT_SHARE_NET: args->share_ns[LXC_NS_NET] = arg; break;
        case OPT_SHARE_IPC: args->share_ns[LXC_NS_IPC] = arg; break;
        case OPT_SHARE_UTS: args->share_ns[LXC_NS_UTS] = arg; break;
+       case OPT_SHARE_PID: args->share_ns[LXC_NS_PID] = arg; break;
        }
        return 0;
 }
@@ -170,6 +167,7 @@ static const struct option my_longopts[] = {
        {"share-net", required_argument, 0, OPT_SHARE_NET},
        {"share-ipc", required_argument, 0, OPT_SHARE_IPC},
        {"share-uts", required_argument, 0, OPT_SHARE_UTS},
+       {"share-pid", required_argument, 0, OPT_SHARE_PID},
        LXC_COMMON_OPTIONS
 };
 
@@ -192,7 +190,7 @@ Options :\n\
                          If not specified, exit with failure instead\n\
                          Note: --daemon implies --close-all-fds\n\
   -s, --define KEY=VAL   Assign VAL to configuration variable KEY\n\
-      --share-[net|ipc|uts]=NAME Share a namespace with another container or pid\n\
+      --share-[net|ipc|uts|pid]=NAME Share a namespace with another container or pid\n\
 ",
        .options   = my_longopts,
        .parser    = my_parser,
index a0f943fd557f70544fba8c78bda82620b0831ae5..25af9711946eb4b20689d36d14a593c27f6fc58a 100644 (file)
@@ -137,7 +137,7 @@ static int do_start(void *arg)
                        exit(EXIT_FAILURE);
                }
 
-       // Setuid is useful even without a new user id space
+       /* Setuid is useful even without a new user id space. */
        if (start_arg->setuid && setuid(uid)) {
                ERROR("failed to set uid %d: %s", uid, strerror(errno));
                exit(EXIT_FAILURE);
@@ -228,6 +228,9 @@ int main(int argc, char *argv[])
         *      dest: del + 1 == OUNT|PID
         *      src:  del + 3 == NT|PID
         */
+       if (!namespaces)
+               usage(argv[0]);
+
        while ((del = strstr(namespaces, "MOUNT")))
                memmove(del + 1, del + 3, strlen(del) - 2);
 
index 7fd2acabb9f9c4d4e1a6c1f5d1c4e3706e345561..acba38da681896a633f013efa70e5786f383ce78 100644 (file)
@@ -99,13 +99,13 @@ static void opentty(const char * tty, int which) {
                close(fd);
        }
 }
-// Code copy end
+/* Code copy end */
 
 static int do_child(void *vargv)
 {
        char **argv = (char **)vargv;
 
-       // Assume we want to become root
+       /* Assume we want to become root */
        if (setgid(0) < 0) {
                perror("setgid");
                return -1;
@@ -272,8 +272,8 @@ int main(int argc, char *argv[])
        int pid;
        char *default_args[] = {"/bin/sh", NULL};
        char buf[1];
-       int pipe1[2],  // child tells parent it has unshared
-           pipe2[2];  // parent tells child it is mapped and may proceed
+       int pipe1[2],  /* child tells parent it has unshared */
+           pipe2[2];  /* parent tells child it is mapped and may proceed */
 
        memset(ttyname0, '\0', sizeof(ttyname0));
        memset(ttyname1, '\0', sizeof(ttyname1));
@@ -316,17 +316,15 @@ int main(int argc, char *argv[])
 
        argv = &argv[optind];
        argc = argc - optind;
-       if (argc < 1) {
+       if (argc < 1)
                argv = default_args;
-               argc = 1;
-       }
 
        if (pipe(pipe1) < 0 || pipe(pipe2) < 0) {
                perror("pipe");
                exit(EXIT_FAILURE);
        }
        if ((pid = fork()) == 0) {
-               // Child.
+               /* Child. */
 
                close(pipe1[0]);
                close(pipe2[1]);
@@ -367,10 +365,9 @@ int main(int argc, char *argv[])
 
        buf[0] = '1';
 
-       if (lxc_map_ids(&active_map, pid)) {
+       if (lxc_map_ids(&active_map, pid))
                fprintf(stderr, "error mapping child\n");
-               ret = 0;
-       }
+
        if (write(pipe2[1], buf, 1) < 0) {
                perror("write to pipe");
                exit(EXIT_FAILURE);
index f89c837d5bdc161d9efa029622b2c111d60c2424..c9a60979ab23eef58989cdee0312ff7e8dbafc37 100644 (file)
@@ -42,7 +42,6 @@
 #include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <sys/vfs.h>
 #include <sys/wait.h>
 
 #include "log.h"
@@ -183,22 +182,24 @@ static int _recursive_rmdir(char *dirname, dev_t pdev,
        return failed ? -1 : 0;
 }
 
-/* we have two different magic values for overlayfs, yay */
+/* We have two different magic values for overlayfs, yay. */
+#ifndef OVERLAYFS_SUPER_MAGIC
 #define OVERLAYFS_SUPER_MAGIC 0x794c764f
+#endif
+
+#ifndef OVERLAY_SUPER_MAGIC
 #define OVERLAY_SUPER_MAGIC 0x794c7630
-/*
- * In overlayfs, st_dev is unreliable.  so on overlayfs we don't do
- * the lxc_rmdir_onedev()
+#endif
+
+/* In overlayfs, st_dev is unreliable. So on overlayfs we don't do the
+ * lxc_rmdir_onedev()
  */
 static bool is_native_overlayfs(const char *path)
 {
-       struct statfs sb;
-
-       if (statfs(path, &sb) < 0)
-               return false;
-       if (sb.f_type == OVERLAYFS_SUPER_MAGIC ||
-                       sb.f_type == OVERLAY_SUPER_MAGIC)
+       if (has_fs_type(path, OVERLAY_SUPER_MAGIC) ||
+           has_fs_type(path, OVERLAYFS_SUPER_MAGIC))
                return true;
+
        return false;
 }
 
@@ -469,137 +470,105 @@ const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip)
        return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0);
 }
 
-extern struct lxc_popen_FILE *lxc_popen(const char *command)
+struct lxc_popen_FILE *lxc_popen(const char *command)
 {
-       struct lxc_popen_FILE *fp = NULL;
-       int parent_end = -1, child_end = -1;
+       int ret;
        int pipe_fds[2];
        pid_t child_pid;
+       struct lxc_popen_FILE *fp = NULL;
 
-       int r = pipe2(pipe_fds, O_CLOEXEC);
-
-       if (r < 0) {
-               ERROR("pipe2 failure");
+       ret = pipe2(pipe_fds, O_CLOEXEC);
+       if (ret < 0)
                return NULL;
-       }
-
-       parent_end = pipe_fds[0];
-       child_end = pipe_fds[1];
 
        child_pid = fork();
+       if (child_pid < 0)
+               goto on_error;
 
-       if (child_pid == 0) {
-               /* child */
-               int child_std_end = STDOUT_FILENO;
-
-               close(parent_end);
-               parent_end = -1;
+       if (!child_pid) {
+               sigset_t mask;
 
-               if (child_end != child_std_end) {
-                       /* dup2() doesn't dup close-on-exec flag */
-                       dup2(child_end, child_std_end);
+               close(pipe_fds[0]);
 
-                       /* it's safe not to close child_end here
-                        * as it's marked close-on-exec anyway
-                        */
-               } else {
-                       /*
-                        * The descriptor is already the one we will use.
-                        * But it must not be marked close-on-exec.
-                        * Undo the effects.
-                        */
-                       if (fcntl(child_end, F_SETFD, 0) != 0) {
-                               SYSERROR("Failed to remove FD_CLOEXEC from fd.");
-                               exit(127);
-                       }
-               }
-
-               /*
-                * Unblock signals.
-                * This is the main/only reason
-                * why we do our lousy popen() emulation.
-                */
-               {
-                       sigset_t mask;
-                       sigfillset(&mask);
-                       sigprocmask(SIG_UNBLOCK, &mask, NULL);
+               /* duplicate stdout */
+               if (pipe_fds[1] != STDOUT_FILENO)
+                       ret = dup2(pipe_fds[1], STDOUT_FILENO);
+               else
+                       ret = fcntl(pipe_fds[1], F_SETFD, 0);
+               if (ret < 0) {
+                       close(pipe_fds[1]);
+                       exit(EXIT_FAILURE);
                }
 
-               execl("/bin/sh", "sh", "-c", command, (char *) NULL);
-               exit(127);
-       }
+               /* duplicate stderr */
+               if (pipe_fds[1] != STDERR_FILENO)
+                       ret = dup2(pipe_fds[1], STDERR_FILENO);
+               else
+                       ret = fcntl(pipe_fds[1], F_SETFD, 0);
+               close(pipe_fds[1]);
+               if (ret < 0)
+                       exit(EXIT_FAILURE);
 
-       /* parent */
+               /* unblock all signals */
+               ret = sigfillset(&mask);
+               if (ret < 0)
+                       exit(EXIT_FAILURE);
 
-       close(child_end);
-       child_end = -1;
+               ret = sigprocmask(SIG_UNBLOCK, &mask, NULL);
+               if (ret < 0)
+                       exit(EXIT_FAILURE);
 
-       if (child_pid < 0) {
-               ERROR("fork failure");
-               goto error;
+               execl("/bin/sh", "sh", "-c", command, (char *)NULL);
+               exit(127);
        }
 
-       fp = calloc(1, sizeof(*fp));
-       if (!fp) {
-               ERROR("failed to allocate memory");
-               goto error;
-       }
+       close(pipe_fds[1]);
+       pipe_fds[1] = -1;
 
-       fp->f = fdopen(parent_end, "r");
-       if (!fp->f) {
-               ERROR("fdopen failure");
-               goto error;
-       }
+       fp = malloc(sizeof(*fp));
+       if (!fp)
+               goto on_error;
 
        fp->child_pid = child_pid;
+       fp->pipe = pipe_fds[0];
 
-       return fp;
-
-error:
+       fp->f = fdopen(pipe_fds[0], "r");
+       if (!fp->f)
+               goto on_error;
 
-       if (fp) {
-               if (fp->f) {
-                       fclose(fp->f);
-                       parent_end = -1; /* so we do not close it second time */
-               }
+       return fp;
 
+on_error:
+       if (fp)
                free(fp);
-       }
 
-       if (parent_end != -1)
-               close(parent_end);
+       if (pipe_fds[0] >= 0)
+               close(pipe_fds[0]);
+
+       if (pipe_fds[1] >= 0)
+               close(pipe_fds[1]);
 
        return NULL;
 }
 
-extern int lxc_pclose(struct lxc_popen_FILE *fp)
+int lxc_pclose(struct lxc_popen_FILE *fp)
 {
-       FILE *f = NULL;
-       pid_t child_pid = 0;
-       int wstatus = 0;
        pid_t wait_pid;
+       int wstatus = 0;
 
-       if (fp) {
-               f = fp->f;
-               child_pid = fp->child_pid;
-               /* free memory (we still need to close file stream) */
-               free(fp);
-               fp = NULL;
-       }
-
-       if (!f || fclose(f)) {
-               ERROR("fclose failure");
+       if (!fp)
                return -1;
-       }
 
        do {
-               wait_pid = waitpid(child_pid, &wstatus, 0);
-       } while (wait_pid == -1 && errno == EINTR);
+               wait_pid = waitpid(fp->child_pid, &wstatus, 0);
+       } while (wait_pid < 0 && errno == EINTR);
+
+       close(fp->pipe);
+       fclose(fp->f);
+       free(fp);
 
-       if (wait_pid == -1) {
-               ERROR("waitpid failure");
+       if (wait_pid < 0)
                return -1;
-       }
 
        return wstatus;
 }
@@ -728,47 +697,46 @@ char **lxc_normalize_path(const char *path)
        return components;
 }
 
-bool lxc_deslashify(char **path)
+char *lxc_deslashify(const char *path)
 {
-       bool ret = false;
-       char *p;
+       char *dup, *p;
        char **parts = NULL;
        size_t n, len;
 
-       parts = lxc_normalize_path(*path);
-       if (!parts)
-               return false;
+       dup = strdup(path);
+       if (!dup)
+               return NULL;
+
+       parts = lxc_normalize_path(dup);
+       if (!parts) {
+               free(dup);
+               return NULL;
+       }
 
        /* We'll end up here if path == "///" or path == "". */
        if (!*parts) {
-               len = strlen(*path);
+               len = strlen(dup);
                if (!len) {
-                       ret = true;
-                       goto out;
+                       lxc_free_array((void **)parts, free);
+                       return dup;
                }
-               n = strcspn(*path, "/");
+               n = strcspn(dup, "/");
                if (n == len) {
+                       free(dup);
+                       lxc_free_array((void **)parts, free);
+
                        p = strdup("/");
                        if (!p)
-                               goto out;
-                       free(*path);
-                       *path = p;
-                       ret = true;
-                       goto out;
+                               return NULL;
+
+                       return p;
                }
        }
 
-       p = lxc_string_join("/", (const char **)parts, **path == '/');
-       if (!p)
-               goto out;
-
-       free(*path);
-       *path = p;
-       ret = true;
-
-out:
+       p = lxc_string_join("/", (const char **)parts, *dup == '/');
+       free(dup);
        lxc_free_array((void **)parts, free);
-       return ret;
+       return p;
 }
 
 char *lxc_append_paths(const char *first, const char *second)
@@ -848,6 +816,74 @@ error_out:
        return NULL;
 }
 
+static bool complete_word(char ***result, char *start, char *end, size_t *cap, size_t *cnt)
+{
+       int r;
+
+       r = lxc_grow_array((void ***)result, cap, 2 + *cnt, 16);
+       if (r < 0)
+               return false;
+       (*result)[*cnt] = strndup(start, end - start);
+       if (!(*result)[*cnt])
+               return false;
+       (*cnt)++;
+
+       return true;
+}
+
+/*
+ * Given a a string 'one two "three four"', split into three words,
+ * one, two, and "three four"
+ */
+char **lxc_string_split_quoted(char *string)
+{
+       char *nextword = string, *p, state;
+       char **result = NULL;
+       size_t result_capacity = 0;
+       size_t result_count = 0;
+
+       if (!string || !*string)
+               return calloc(1, sizeof(char *));
+
+       // TODO I'm *not* handling escaped quote
+       state = ' ';
+       for (p = string; *p; p++) {
+               switch(state) {
+               case ' ':
+                       if (isspace(*p))
+                               continue;
+                       else if (*p == '"' || *p == '\'') {
+                               nextword = p;
+                               state = *p;
+                               continue;
+                       }
+                       nextword = p;
+                       state = 'a';
+                       continue;
+               case 'a':
+                       if (isspace(*p)) {
+                               complete_word(&result, nextword, p, &result_capacity, &result_count);
+                               state = ' ';
+                               continue;
+                       }
+                       continue;
+               case '"':
+               case '\'':
+                       if (*p == state) {
+                               complete_word(&result, nextword+1, p, &result_capacity, &result_count);
+                               state = ' ';
+                               continue;
+                       }
+                       continue;
+               }
+       }
+
+       if (state == 'a')
+               complete_word(&result, nextword, p, &result_capacity, &result_count);
+
+       return realloc(result, (result_count + 1) * sizeof(char *));
+}
+
 char **lxc_string_split_and_trim(const char *string, char _sep)
 {
        char *token, *str, *saveptr = NULL;
@@ -1069,7 +1105,7 @@ bool dir_exists(const char *path)
 
        ret = stat(path, &sb);
        if (ret < 0)
-               // could be something other than eexist, just say no
+               /* Could be something other than eexist, just say "no". */
                return false;
        return S_ISDIR(sb.st_mode);
 }
@@ -1125,7 +1161,7 @@ int detect_shared_rootfs(void)
                        continue;
                *p2 = '\0';
                if (strcmp(p + 1, "/") == 0) {
-                       // this is '/'.  is it shared?
+                       /* This is '/'. Is it shared? */
                        p = strchr(p2 + 1, ' ');
                        if (p && strstr(p, "shared:")) {
                                fclose(f);
@@ -1191,7 +1227,7 @@ bool detect_ramfs_rootfs(void)
                        continue;
                *p2 = '\0';
                if (strcmp(p + 1, "/") == 0) {
-                       // this is '/'.  is it the ramfs?
+                       /* This is '/'. Is it the ramfs? */
                        p = strchr(p2 + 1, '-');
                        if (p && strncmp(p, "- rootfs rootfs ", 16) == 0) {
                                free(line);
@@ -1572,20 +1608,21 @@ static int check_symlink(int fd)
 static int open_if_safe(int dirfd, const char *nextpath)
 {
        int newfd = openat(dirfd, nextpath, O_RDONLY | O_NOFOLLOW);
-       if (newfd >= 0) // was not a symlink, all good
+       if (newfd >= 0) /* Was not a symlink, all good. */
                return newfd;
 
        if (errno == ELOOP)
                return newfd;
 
        if (errno == EPERM || errno == EACCES) {
-               /* we're not root (cause we got EPERM) so
-                  try opening with O_PATH */
+               /* We're not root (cause we got EPERM) so try opening with
+                * O_PATH.
+                */
                newfd = openat(dirfd, nextpath, O_PATH | O_NOFOLLOW);
                if (newfd >= 0) {
-                       /* O_PATH will return an fd for symlinks.  We know
-                        * nextpath wasn't a symlink at last openat, so if fd
-                        * is now a link, then something * fishy is going on
+                       /* O_PATH will return an fd for symlinks. We know
+                        * nextpath wasn't a symlink at last openat, so if fd is
+                        * now a link, then something * fishy is going on.
                         */
                        int ret = check_symlink(newfd);
                        if (ret < 0) {
@@ -1685,8 +1722,10 @@ out:
 int safe_mount(const char *src, const char *dest, const char *fstype,
                unsigned long flags, const void *data, const char *rootfs)
 {
-       int srcfd = -1, destfd, ret, saved_errno;
-       char srcbuf[50], destbuf[50]; // only needs enough for /proc/self/fd/<fd>
+       int destfd, ret, saved_errno;
+       /* Only needs enough for /proc/self/fd/<fd>. */
+       char srcbuf[50], destbuf[50];
+       int srcfd = -1;
        const char *mntsrc = src;
 
        if (!rootfs)
@@ -2327,9 +2366,11 @@ int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args)
        /* close the write-end of the pipe */
        close(pipefd[1]);
 
-       bytes = read(pipefd[0], buf, (buf_size > 0) ? (buf_size - 1) : 0);
-       if (bytes > 0)
-               buf[bytes - 1] = '\0';
+       if (buf && buf_size > 0) {
+               bytes = read(pipefd[0], buf, buf_size - 1);
+               if (bytes > 0)
+                       buf[bytes - 1] = '\0';
+       }
 
        fret = wait_for_pid(child);
        /* close the read-end of the pipe */
@@ -2384,3 +2425,46 @@ void *must_realloc(void *orig, size_t sz)
 
        return ret;
 }
+
+bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val)
+{
+       return (fs->f_type == (fs_type_magic)magic_val);
+}
+
+bool has_fs_type(const char *path, fs_type_magic magic_val)
+{
+       bool has_type;
+       int ret;
+       struct statfs sb;
+
+       ret = statfs(path, &sb);
+       if (ret < 0)
+               return false;
+
+       has_type = is_fs_type(&sb, magic_val);
+       if (!has_type && magic_val == RAMFS_MAGIC)
+               WARN("When the ramfs it a tmpfs statfs() might report tmpfs");
+
+       return has_type;
+}
+
+bool lxc_nic_exists(char *nic)
+{
+#define __LXC_SYS_CLASS_NET_LEN 15 + IFNAMSIZ + 1
+       char path[__LXC_SYS_CLASS_NET_LEN];
+       int ret;
+       struct stat sb;
+
+       if (!strcmp(nic, "none"))
+               return true;
+
+       ret = snprintf(path, __LXC_SYS_CLASS_NET_LEN, "/sys/class/net/%s", nic);
+       if (ret < 0 || (size_t)ret >= __LXC_SYS_CLASS_NET_LEN)
+               return false;
+
+       ret = stat(path, &sb);
+       if (ret < 0)
+               return false;
+
+       return true;
+}
index 3465e6a6f2461066d4648acd49144b46692e454a..833ec44167acec339d522fe88708eb44cf35a785 100644 (file)
 #include <stdbool.h>
 #include <unistd.h>
 #include <linux/loop.h>
+#include <linux/magic.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
+#include <sys/vfs.h>
 
 #include "initutils.h"
 
@@ -90,7 +92,7 @@ static inline int unshare(int flags)
 #endif
 }
 #else
-int unshare(int);
+extern int unshare(int);
 #endif
 
 /* Define signalfd() if missing from the C library */
@@ -188,6 +190,7 @@ static inline int signalfd(int fd, const sigset_t *mask, int flags)
  * without additional wrappers.
  */
 struct lxc_popen_FILE {
+       int pipe;
        FILE *f;
        pid_t child_pid;
 };
@@ -243,24 +246,30 @@ extern int lxc_wait_for_pid_status(pid_t pid);
 /* send and receive buffers completely */
 extern ssize_t lxc_write_nointr(int fd, const void* buf, size_t count);
 extern ssize_t lxc_read_nointr(int fd, void* buf, size_t count);
-extern ssize_t lxc_read_nointr_expect(int fd, void* buf, size_t count, const void* expected_buf);
+extern ssize_t lxc_read_nointr_expect(int fd, void *buf, size_t count,
+                                     const void *expected_buf);
 #if HAVE_LIBGNUTLS
 #define SHA_DIGEST_LENGTH 20
 extern int sha1sum_file(char *fnam, unsigned char *md_value);
 #endif
 
 /* read and write whole files */
-extern int lxc_write_to_file(const char *filename, const void* buf, size_t count, bool add_newline);
+extern int lxc_write_to_file(const char *filename, const void *buf,
+                            size_t count, bool add_newline);
 extern int lxc_read_from_file(const char *filename, void* buf, size_t count);
 
 /* convert variadic argument lists to arrays (for execl type argument lists) */
 extern char** lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup);
 extern const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip);
 
-/* Some simple string functions; if they return pointers, they are allocated buffers. */
-extern char *lxc_string_replace(const char *needle, const char *replacement, const char *haystack);
+/* Some simple string functions; if they return pointers, they are allocated
+ * buffers.
+ */
+extern char *lxc_string_replace(const char *needle, const char *replacement,
+                               const char *haystack);
 extern bool lxc_string_in_array(const char *needle, const char **haystack);
-extern char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix);
+extern char *lxc_string_join(const char *sep, const char **parts,
+                            bool use_as_prefix);
 /* Normalize and split path: Leading and trailing / are removed, multiple
  * / are compactified, .. and . are resolved (.. on the top level is considered
  * identical to .).
@@ -273,22 +282,25 @@ extern char *lxc_string_join(const char *sep, const char **parts, bool use_as_pr
  */
 extern char **lxc_normalize_path(const char *path);
 /* remove multiple slashes from the path, e.g. ///foo//bar -> /foo/bar */
-extern bool lxc_deslashify(char **path);
+extern char *lxc_deslashify(const char *path);
 extern char *lxc_append_paths(const char *first, const char *second);
 /* Note: the following two functions use strtok(), so they will never
  *       consider an empty element, even if two delimiters are next to
  *       each other.
  */
-extern bool lxc_string_in_list(const char *needle, const char *haystack, char sep);
+extern bool lxc_string_in_list(const char *needle, const char *haystack,
+                              char sep);
 extern char **lxc_string_split(const char *string, char sep);
 extern char **lxc_string_split_and_trim(const char *string, char sep);
+extern char **lxc_string_split_quoted(char *string);
 /* Append string to NULL-terminated string array. */
 extern int lxc_append_string(char ***list, char *entry);
 
 /* some simple array manipulation utilities */
 typedef void (*lxc_free_fn)(void *);
 typedef void *(*lxc_dup_fn)(void *);
-extern int lxc_grow_array(void ***array, size_t* capacity, size_t new_size, size_t capacity_increment);
+extern int lxc_grow_array(void ***array, size_t *capacity, size_t new_size,
+                         size_t capacity_increment);
 extern void lxc_free_array(void **array, lxc_free_fn element_free_fn);
 extern size_t lxc_array_len(void **array);
 
@@ -301,7 +313,7 @@ extern void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
 /* 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
+/* initialize rand with urandom */
 extern int randseed(bool);
 
 inline static bool am_unpriv(void) {
@@ -316,50 +328,51 @@ extern uid_t get_ns_uid(uid_t orig);
 extern bool dir_exists(const char *path);
 
 #define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL)
-uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval);
-
-int detect_shared_rootfs(void);
-bool detect_ramfs_rootfs(void);
-char *on_path(const 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);
-int is_dir(const char *path);
-char *get_template_path(const char *t);
-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 lxc_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);
-int lxc_preserve_ns(const int pid, const char *ns);
+extern uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval);
+
+extern int detect_shared_rootfs(void);
+extern bool detect_ramfs_rootfs(void);
+extern char *on_path(const char *cmd, const char *rootfs);
+extern bool file_exists(const char *f);
+extern bool cgns_supported(void);
+extern char *choose_init(const char *rootfs);
+extern int print_to_file(const char *file, const char *content);
+extern bool switch_to_ns(pid_t pid, const char *ns);
+extern int is_dir(const char *path);
+extern char *get_template_path(const char *t);
+extern int setproctitle(char *title);
+extern int safe_mount(const char *src, const char *dest, const char *fstype,
+                     unsigned long flags, const void *data,
+                     const char *rootfs);
+extern int lxc_mount_proc_if_needed(const char *rootfs);
+extern int open_devnull(void);
+extern int set_stdfds(int fd);
+extern int null_stdfds(void);
+extern int lxc_count_file_lines(const char *fn);
+extern int lxc_preserve_ns(const int pid, const char *ns);
 
 /* Check whether a signal is blocked by a process. */
-bool task_blocking_signal(pid_t pid, int signal);
+extern bool task_blocking_signal(pid_t pid, int signal);
 
 /* Helper functions to parse numbers. */
-int lxc_safe_uint(const char *numstr, unsigned int *converted);
-int lxc_safe_int(const char *numstr, int *converted);
-int lxc_safe_long(const char *numstr, long int *converted);
-int lxc_safe_ulong(const char *numstr, unsigned long *converted);
+extern int lxc_safe_uint(const char *numstr, unsigned int *converted);
+extern int lxc_safe_int(const char *numstr, int *converted);
+extern int lxc_safe_long(const char *numstr, long int *converted);
+extern int lxc_safe_ulong(const char *numstr, unsigned long *converted);
 
 /* Switch to a new uid and gid. */
-int lxc_switch_uid_gid(uid_t uid, gid_t gid);
-int lxc_setgroups(int size, gid_t list[]);
+extern int lxc_switch_uid_gid(uid_t uid, gid_t gid);
+extern int lxc_setgroups(int size, gid_t list[]);
 
 /* Find an unused loop device and associate it with source. */
-int lxc_prepare_loop_dev(const char *source, char *loop_dev, int flags);
+extern int lxc_prepare_loop_dev(const char *source, char *loop_dev, int flags);
 
 /* Clear all mounts on a given node.
  * >= 0 successfully cleared. The number returned is the number of umounts
  *      performed.
  * < 0  error umounting. Return -errno.
  */
-int lxc_unstack_mountpoint(const char *path, bool lazy);
+extern int lxc_unstack_mountpoint(const char *path, bool lazy);
 
 /*
  * run_command runs a command and collect it's std{err,out} output in buf.
@@ -373,17 +386,24 @@ int lxc_unstack_mountpoint(const char *path, bool lazy);
  *                     function must exec.
  * @param[in] args     Arguments to be passed to child_fn.
  */
-int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args);
+extern int run_command(char *buf, size_t buf_size, int (*child_fn)(void *),
+                      void *args);
 
 /* Concatenate all passed-in strings into one path. Do not fail. If any piece
  * is not prefixed with '/', add a '/'.
  */
-char *must_make_path(const char *first, ...) __attribute__((sentinel));
+extern char *must_make_path(const char *first, ...) __attribute__((sentinel));
 
 /* return copy of string @entry;  do not fail. */
-char *must_copy_string(const char *entry);
+extern char *must_copy_string(const char *entry);
 
 /* Re-alllocate a pointer, do not fail */
-void *must_realloc(void *orig, size_t sz);
+extern void *must_realloc(void *orig, size_t sz);
+
+/* __typeof__ should be safe to use with all compilers. */
+typedef __typeof__(((struct statfs *)NULL)->f_type) fs_type_magic;
+extern bool has_fs_type(const char *path, fs_type_magic magic_val);
+extern bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val);
+extern bool lxc_nic_exists(char *nic);
 
 #endif /* __LXC_UTILS_H */
index c96b4666ad62903e2e5c57ae852cbbd37206c99e..025ac8c9d8eda1c5921f88cd8175683e9f5fb0ee 100644 (file)
@@ -105,7 +105,7 @@ char *files_to_allow[] = { "/sys/class/net/lo/ifalias",
                "/proc/sys/kernel/shmmax",
                NULL };
 
-char *files_to_deny[] = { "/proc/mem", "/proc/kmem",
+char *files_to_deny[] = {
                "/sys/kernel/uevent_helper",
                "/proc/sys/fs/file-nr",
                "/sys/kernel/mm/ksm/pages_to_scan",
index af63c6a073f929f535f5fc56f3f5c0dbe35b8c35..bcad8e52ec33d85c160c445c1308e6d6f319da4f 100644 (file)
@@ -188,7 +188,8 @@ int main(int argc, char *argv[]) {
                 }
                 modes[i] = tok;
             }
-            modes[i] = NULL;
+           if (modes)
+                   modes[i] = NULL;
             break;
         }
         default: /* '?' */
index f2f70dd33228851b5c3e571b967700e770553c54..8e86c48e4b83179f8cd85f82859a5f0d3bab2b05 100644 (file)
@@ -38,7 +38,7 @@ int main(int argc, char *argv[])
        int fulllen = 0, inlen = 0, ret = EXIT_FAILURE;
        char *key, *keys, *saveptr = NULL;
 
-       fulllen = lxc_listconfigs(NULL, inlen);
+       fulllen = lxc_list_config_items(NULL, inlen);
 
        keys = malloc(sizeof(char) * fulllen + 1);
        if (!keys) {
@@ -46,7 +46,7 @@ int main(int argc, char *argv[])
                exit(ret);
        }
 
-       if (lxc_listconfigs(keys, fulllen) != fulllen) {
+       if (lxc_list_config_items(keys, fulllen) != fulllen) {
                lxc_error("%s\n", "failed to retrieve configuration keys");
                goto on_error;
        }
@@ -54,7 +54,7 @@ int main(int argc, char *argv[])
        for (key = strtok_r(keys, "\n", &saveptr); key != NULL;
             key = strtok_r(NULL, "\n", &saveptr)) {
                struct lxc_config_t *config;
-               config = lxc_getconfig(key);
+               config = lxc_get_config(key);
                if (!config) {
                        lxc_error("configuration key \"%s\" not implemented in "
                                  "jump table",
index c47f25344b4fe084539d12bdb51fb718aa086fa6..9c32cf26995060dca24437da881f18b9bd13700f 100644 (file)
@@ -146,6 +146,7 @@ static int test_console(const char *lxcpath,
        }
        c->load_config(c, NULL);
        c->set_config_item(c, "lxc.tty.max", TTYCNT_STR);
+       c->set_config_item(c, "lxc.pty.max", "1024");
        c->save_config(c, NULL);
        c->want_daemonize(c, true);
        if (!c->startl(c, 0, NULL)) {
index dbfccb1f41f31bec031d6ae7de9cf9c474d0ff1a..256ff60fdf9b8fb75b6f61b7dd57a3746179f184 100644 (file)
@@ -40,10 +40,8 @@ static int destroy_busybox(void)
                return -1;
        }
        if (pid == 0) {
-               ret = execlp("lxc-destroy", "lxc-destroy", "-f", "-n", MYNAME, NULL);
-               // Should not return
-               perror("execl");
-               exit(1);
+               execlp("lxc-destroy", "lxc-destroy", "-f", "-n", MYNAME, NULL);
+               exit(EXIT_FAILURE);
        }
 again:
        ret = waitpid(pid, &status, 0);
@@ -72,10 +70,8 @@ static int create_busybox(void)
                return -1;
        }
        if (pid == 0) {
-               ret = execlp("lxc-create", "lxc-create", "-t", "busybox", "-n", MYNAME, NULL);
-               // Should not return
-               perror("execl");
-               exit(1);
+               execlp("lxc-create", "lxc-create", "-t", "busybox", "-n", MYNAME, NULL);
+               exit(EXIT_FAILURE);
        }
 again:
        ret = waitpid(pid, &status, 0);
index eaf3c84d07c06e7eae527cc9081be8d1f1a97946..b8ba8055d78ede4082dd4bbb31c58638facea178 100644 (file)
@@ -38,10 +38,8 @@ static int create_container(void)
                return -1;
        }
        if (pid == 0) {
-               ret = execlp("lxc-create", "lxc-create", "-t", "busybox", "-n", MYNAME, NULL);
-               // Should not return
-               perror("execl");
-               exit(1);
+               execlp("lxc-create", "lxc-create", "-t", "busybox", "-n", MYNAME, NULL);
+               exit(EXIT_FAILURE);
        }
 again:
        ret = waitpid(pid, &status, 0);
index ed68440b75e071b4a3f1e8416d5b4903b1a8898b..f5923921c8d55c9afe478b5cacd194d0b861277d 100644 (file)
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#include <lxc/lxccontainer.h>
 
-#include <unistd.h>
+#include <errno.h>
 #include <signal.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <stdlib.h>
-#include <errno.h>
+#include <lxc/lxccontainer.h>
+
 #include "lxc/state.h"
 
 #define MYNAME "lxctest1"
@@ -64,6 +66,111 @@ int main(int argc, char *argv[])
                goto out;
        }
        printf("get_keys for nic 1 returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.apparmor", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.selinux", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.mount", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.rootfs", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.uts", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.hook", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.cap", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.console", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.seccomp", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.signal", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.start", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.monitor", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
+       ret = c->get_keys(c, "lxc.cgroup", v3, 2000);
+       if (ret < 0) {
+               fprintf(stderr, "%d: failed to get keys(%d)\n", __LINE__, ret);
+               ret = 1;
+               goto out;
+       }
+       printf("get_keys returned %d\n%s", ret, v3);
+
        ret = 0;
 
 out:
index 390c6f46cf89e8aa334e0c370503d37811477e3b..ddcee8a76986981c41ba20d24b16dfb9775a5426 100755 (executable)
@@ -102,8 +102,8 @@ mkdir -p $HDIR/.config/lxc/
 cat > $HDIR/.config/lxc/default.conf << EOF
 lxc.net.0.type = veth
 lxc.net.0.link = lxcbr0
-lxc.id_map = u 0 910000 9999
-lxc.id_map = g 0 910000 9999
+lxc.idmap = u 0 910000 9999
+lxc.idmap = g 0 910000 9999
 EOF
 chown -R $TUSER: $HDIR
 
@@ -132,6 +132,7 @@ elif [ -e /sys/fs/cgroup/cgmanager/sock ]; then
        done
 else
        for d in /sys/fs/cgroup/*; do
+               [ "$d" = "/sys/fs/cgroup/unified" ] && continue
                [ -f $d/cgroup.clone_children ] && echo 1 > $d/cgroup.clone_children
                [ ! -d $d/lxctest ] && mkdir $d/lxctest
                chown -R $TUSER: $d/lxctest
index 40c6bf6676aec88d626be1dc0cd6bddeab3a1bec..5f2a18f68283f3d19c8bad015658df346027960d 100755 (executable)
@@ -118,8 +118,8 @@ mkdir -p $HDIR/.config/lxc/
 cat > $HDIR/.config/lxc/default.conf << EOF
 lxc.net.0.type = veth
 lxc.net.0.link = lxcbr0
-lxc.id_map = u 0 910000 9999
-lxc.id_map = g 0 910000 9999
+lxc.idmap = u 0 910000 9999
+lxc.idmap = g 0 910000 9999
 EOF
 chown -R $TUSER: $HDIR
 
@@ -148,6 +148,7 @@ elif [ -e /sys/fs/cgroup/cgmanager/sock ]; then
        done
 else
        for d in /sys/fs/cgroup/*; do
+               [ "$d" = "/sys/fs/cgroup/unified" ] && continue
                [ -f $d/cgroup.clone_children ] && echo 1 > $d/cgroup.clone_children
                [ ! -d $d/lxctest ] && mkdir $d/lxctest
                chown -R $TUSER: $d/lxctest
index 08b9b55fc3c25e8f73235d115470e544c0cee386..3e35008c6a8fc83f19d50557c17fbda808fefd96 100755 (executable)
@@ -81,8 +81,8 @@ usermod -v 910000-919999 -w 910000-919999 usernic-user
 mkdir -p /home/usernic-user/.config/lxc/
 cat > /home/usernic-user/.config/lxc/default.conf << EOF
 lxc.net.0.type = empty
-lxc.id_map = u 0 910000 10000
-lxc.id_map = g 0 910000 10000
+lxc.idmap = u 0 910000 10000
+lxc.idmap = g 0 910000 10000
 EOF
 
 if which cgm >/dev/null 2>&1; then
@@ -105,6 +105,7 @@ elif [ -e /sys/fs/cgroup/cgmanager/sock ]; then
        done
 else
        for d in /sys/fs/cgroup/*; do
+               [ "$d" = "/sys/fs/cgroup/unified" ] && continue
                [ -f $d/cgroup.clone_children ] && echo 1 > $d/cgroup.clone_children
                [ ! -d $d/lxctest ] && mkdir $d/lxctest
                chown -R usernic-user: $d/lxctest
@@ -153,7 +154,7 @@ 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 $lxcpath $lxcname $p1 veth usernic-br0 xx1"; then
+if run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p1 veth usernic-br0 xx1"; then
        echo "FAIL: able to create nic with no entries"
        exit 1
 fi
@@ -164,24 +165,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 $lxcpath $lxcname $p1 veth usernic-br1 xx1"; then
+if run_cmd "$LXC_USER_NIC create $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 $lxcpath $lxcname $p1 veth usernic-br0 xx2"; then
+if ! run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p1 veth usernic-br0 xx2"; then
        echo "FAIL: unable to create first nic"
        exit 1
 fi
 
-if ! run_cmd "$LXC_USER_NIC $lxcpath $lxcname $p1 veth usernic-br0 xx3"; then
+if ! run_cmd "$LXC_USER_NIC create $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 $lxcpath $lxcname $p1 veth usernic-br0 xx4"; then
+if run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p1 veth usernic-br0 xx4"; then
        echo "FAIL: able to create third nic"
        exit 1
 fi
@@ -191,7 +192,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 $lxcpath $lxcname $p1 veth usernic-br0 xx5"; then
+if ! run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p1 veth usernic-br0 xx5"; then
        echo "FAIL: unable to create nic after destroying the old"
        cleanup 1
 fi
@@ -204,7 +205,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 $lxcpath $lxcname $p2 veth usernic-br0 xx6"; then
+if run_cmd "$LXC_USER_NIC create $lxcpath $lxcname $p2 veth usernic-br0 xx6"; then
        echo "FAIL: able to attach nic to root-owned container"
        cleanup 1
 fi
index 01d8cd6eb67b4e96840521d63f495353d68bd3a0..aba7706abcb1d85823b5f47e366941066b6187e1 100644 (file)
 
 void test_lxc_deslashify(void)
 {
-       char *s = strdup("/A///B//C/D/E/");
-       if (!s)
+       char *s = "/A///B//C/D/E/";
+       char *t;
+
+       t = lxc_deslashify(s);
+       if (!t)
                exit(EXIT_FAILURE);
-       lxc_test_assert_abort(lxc_deslashify(&s));
-       lxc_test_assert_abort(strcmp(s, "/A/B/C/D/E") == 0);
-       free(s);
+       lxc_test_assert_abort(strcmp(t, "/A/B/C/D/E") == 0);
+       free(t);
 
-       s = strdup("/A");
-       if (!s)
+       s = "/A";
+
+       t = lxc_deslashify(s);
+       if (!t)
                exit(EXIT_FAILURE);
-       lxc_test_assert_abort(lxc_deslashify(&s));
-       lxc_test_assert_abort(strcmp(s, "/A") == 0);
-       free(s);
+       lxc_test_assert_abort(strcmp(t, "/A") == 0);
+       free(t);
 
-       s = strdup("");
-       if (!s)
+       s = "";
+       t = lxc_deslashify(s);
+       if (!t)
                exit(EXIT_FAILURE);
-       lxc_test_assert_abort(lxc_deslashify(&s));
-       lxc_test_assert_abort(strcmp(s, "") == 0);
-       free(s);
+       lxc_test_assert_abort(strcmp(t, "") == 0);
+       free(t);
+
+       s = "//";
 
-       s = strdup("//");
-       if (!s)
+       t = lxc_deslashify(s);
+       if (!t)
                exit(EXIT_FAILURE);
-       lxc_test_assert_abort(lxc_deslashify(&s));
-       lxc_test_assert_abort(strcmp(s, "/") == 0);
-       free(s);
+       lxc_test_assert_abort(strcmp(t, "/") == 0);
+       free(t);
 }
 
 /* /proc/int_as_str/ns/mnt\0 = (5 + 21 + 7 + 1) */
index d416d0b607f389105f02c822b1b9924e22fc1aba..db61dd0446451e573dde7afd4d4c05e182480051 100644 (file)
@@ -455,6 +455,34 @@ int main(int argc, char *argv[])
                return -1;
        }
 
+       /* lxc.idmap
+        * We can't really save the config here since save_config() wants to
+        * chown the container's directory but we haven't created an on-disk
+        * container. So let's test set-get-clear.
+        */
+       if (set_get_compare_clear_save_load(
+               c, "lxc.idmap", "u 0 100000 1000000000", NULL, false) < 0) {
+               lxc_error("%s\n", "lxc.idmap");
+               goto non_test_error;
+       }
+
+       if (!c->set_config_item(c, "lxc.idmap", "u 1 100000 10000000")) {
+               lxc_error("%s\n", "failed to set config item "
+                                 "\"lxc.idmap\" to \"u 1 100000 10000000\"");
+               return -1;
+       }
+
+       if (!c->set_config_item(c, "lxc.idmap", "g 1 100000 10000000")) {
+               lxc_error("%s\n", "failed to set config item "
+                                 "\"lxc.idmap\" to \"g 1 100000 10000000\"");
+               return -1;
+       }
+
+       if (!c->get_config_item(c, "lxc.idmap", retval, sizeof(retval))) {
+               lxc_error("%s\n", "failed to get config item \"lxc.cgroup\"");
+               return -1;
+       }
+
        c->clear_config(c);
        c->lxc_conf = NULL;
 
@@ -942,6 +970,12 @@ int main(int argc, char *argv[])
                goto non_test_error;
        }
 
+       if (!set_get_compare_clear_save_load(c, "lxc.net.0.asdf", "veth",
+                                           tmpf, true)) {
+               lxc_error("%s\n", "lxc.net.0.asdf");
+               goto non_test_error;
+       }
+
        if (set_get_compare_clear_save_load_network(
                c, "lxc.net.0.macvlan.mode", "private", tmpf, true,
                "macvlan")) {
@@ -1025,6 +1059,12 @@ int main(int argc, char *argv[])
                goto non_test_error;
        }
 
+       if (set_get_compare_clear_save_load(c, "lxc.cgroup.dir", "lxd", tmpf,
+                                           true)) {
+               lxc_error("%s\n", "lxc.cgroup.dir");
+               goto non_test_error;
+       }
+
        if (set_and_clear_complete_netdev(c) < 0) {
                lxc_error("%s\n", "failed to clear whole network");
                goto non_test_error;
index d8a4ca271d6116ab94f3c8d49c524a1ab7b4a621..58f4d24b6f2c7dea97daf6663076515a7245ba17 100644 (file)
@@ -38,10 +38,8 @@ static int create_container(void)
                return -1;
        }
        if (pid == 0) {
-               ret = execlp("lxc-create", "lxc-create", "-t", "busybox", "-n", MYNAME, NULL);
-               // Should not return
-               perror("execl");
-               exit(1);
+               execlp("lxc-create", "lxc-create", "-t", "busybox", "-n", MYNAME, NULL);
+               exit(EXIT_FAILURE);
        }
 again:
        ret = waitpid(pid, &status, 0);
index aff0e7d4f0a246790c2af12553f14f251fc74bac..6472ce7e0d37be2ebf61777aa0d30fda780af4ca 100644 (file)
@@ -40,10 +40,8 @@ static int destroy_container(void)
                return -1;
        }
        if (pid == 0) {
-               ret = execlp("lxc-destroy", "lxc-destroy", "-f", "-n", MYNAME, NULL);
-               // Should not return
-               perror("execl");
-               exit(1);
+               execlp("lxc-destroy", "lxc-destroy", "-f", "-n", MYNAME, NULL);
+               exit(EXIT_FAILURE);
        }
 again:
        ret = waitpid(pid, &status, 0);
@@ -72,10 +70,8 @@ static int create_container(void)
                return -1;
        }
        if (pid == 0) {
-               ret = execlp("lxc-create", "lxc-create", "-t", "busybox", "-n", MYNAME, NULL);
-               // Should not return
-               perror("execl");
-               exit(1);
+               execlp("lxc-create", "lxc-create", "-t", "busybox", "-n", MYNAME, NULL);
+               exit(EXIT_FAILURE);
        }
 again:
        ret = waitpid(pid, &status, 0);
index f875197032d13631254410e273c32e80d0dede2c..d8e82be8134de6e998960e879262904ff9b9c9cf 100644 (file)
@@ -40,10 +40,8 @@ static int destroy_container(void)
                return -1;
        }
        if (pid == 0) {
-               ret = execlp("lxc-destroy", "lxc-destroy", "-f", "-n", MYNAME, NULL);
-               // Should not return
-               perror("execl");
-               exit(1);
+               execlp("lxc-destroy", "lxc-destroy", "-f", "-n", MYNAME, NULL);
+               exit(EXIT_FAILURE);
        }
 again:
        ret = waitpid(pid, &status, 0);
@@ -72,10 +70,8 @@ static int create_container(void)
                return -1;
        }
        if (pid == 0) {
-               ret = execlp("lxc-create", "lxc-create", "-t", "busybox", "-n", MYNAME, NULL);
-               // Should not return
-               perror("execl");
-               exit(1);
+               execlp("lxc-create", "lxc-create", "-t", "busybox", "-n", MYNAME, NULL);
+               exit(EXIT_FAILURE);
        }
 again:
        ret = waitpid(pid, &status, 0);
index 61f062d42983162b0bcdae5483caf19d659523f0..c4a5b9555bde8cb1b147ab98c0a1262ae64af76b 100644 (file)
@@ -12,6 +12,7 @@ templates_SCRIPTS = \
        lxc-fedora \
        lxc-fedora-legacy \
        lxc-gentoo \
+       lxc-oci \
        lxc-openmandriva \
        lxc-opensuse \
        lxc-oracle \
index 359f02875bbb029c37398aa638f242826bef7b2d..768e69028f2fb91a378e3d7a943c8515b1f4e788 100644 (file)
@@ -185,7 +185,7 @@ fetch_apk_keys() {
 
        echo "$APK_KEYS_SHA256" | while read -r line; do
                keyname="${line##* }"
-               if [ ! -f "$keyname" ]; then
+               if [ ! -s "$keyname" ]; then
                        fetch "$APK_KEYS_URI/$keyname" > "$keyname"
                fi
                echo "$line" | sha256sum -c -
@@ -210,7 +210,7 @@ fetch_apk_static() {
        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'
+       [ -s "$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 \
index f27efa9ef338b8e8ed48dcf749d509e36cc18ac5..fa7c78ff79a998942a8bfddca973868c2fc88a1b 100644 (file)
@@ -342,7 +342,7 @@ copy_configuration()
 grep -q "^lxc.rootfs.path" $path/config 2>/dev/null || echo "lxc.rootfs.path = $rootfs" >> $path/config
 cat <<EOF >> $path/config
 lxc.signal.halt = SIGUSR1
-lxc.rebootsignal = SIGTERM
+lxc.signal.reboot = SIGTERM
 lxc.uts.name = $name
 lxc.tty.max = 1
 lxc.pty.max = 1
index af2cc961f38e8994b97f7ed7e15355c2025a6d13..7ba7ea0e0eae1bd98c7743fec1535454fa6b9c4b 100644 (file)
@@ -34,7 +34,7 @@ done
 export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
 export GREP_OPTIONS=""
 
-MIRROR=${MIRROR:-http://httpredir.debian.org/debian}
+MIRROR=${MIRROR:-http://deb.debian.org/debian}
 SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.debian.org/}
 LOCALSTATEDIR="@LOCALSTATEDIR@"
 LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
@@ -609,7 +609,7 @@ Options :
   -S, --auth-key=KEYFILE SSH public key to inject into the container as the root user.
   -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: wheezy, jessie, stretch, sid.
+  -r, --release=RELEASE  Debian release. Can be one of: wheezy, jessie, stretch, buster, sid.
                          Defaults to current stable.
   --mirror=MIRROR        Debian mirror to use during installation. Overrides the MIRROR
                          environment variable (see below).
@@ -770,7 +770,7 @@ fi
 
 current_release=$(wget "${MIRROR}/dists/stable/Release" -O - 2> /dev/null | head |awk '/^Codename: (.*)$/ { print $2; }')
 release=${release:-${current_release}}
-valid_releases=('wheezy' 'jessie' 'stretch' 'sid')
+valid_releases=('wheezy' 'jessie' 'stretch' 'buster' 'sid')
 if [[ ! "${valid_releases[*]}" =~ (^|[^[:alpha:]])$release([^[:alpha:]]|$) ]]; then
     echo "Invalid release ${release}, valid ones are: ${valid_releases[*]}"
     exit 1
diff --git a/templates/lxc-oci.in b/templates/lxc-oci.in
new file mode 100755 (executable)
index 0000000..c2cfb35
--- /dev/null
@@ -0,0 +1,212 @@
+#!/bin/bash
+
+# Create application containers from OCI images
+
+# Copyright © 2014 Stéphane Graber <stgraber@ubuntu.com>
+# Copyright © 2017 Serge Hallyn <serge@hallyn.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
+
+set -eu
+# set -x  # debug
+
+# Make sure the usual locations are in PATH
+export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
+
+# Check for required binaries
+for bin in skopeo umoci jq; do
+    if ! type $bin >/dev/null 2>&1; then
+        echo "ERROR: Missing required tool: $bin" 1>&2
+        exit 1
+    fi
+done
+
+# Some useful functions
+cleanup() {
+    if [ -d "$DOWNLOAD_TEMP" ]; then
+        rm -Rf $DOWNLOAD_TEMP
+    fi
+}
+
+in_userns() {
+    [ -e /proc/self/uid_map ] || { echo no; return; }
+    while read line; do
+        fields=$(echo $line | awk '{ print $1 " " $2 " " $3 }')
+        [ "$fields" = "0 0 4294967295" ] && { echo no; return; } || true
+        echo $fields | grep -q " 0 1$" && { echo userns-root; return; } || true
+    done < /proc/self/uid_map
+
+    [ "$(cat /proc/self/uid_map)" = "$(cat /proc/1/uid_map)" ] && \
+        { echo userns-root; return; }
+    echo yes
+}
+
+# get entrypoint from oci image.  Use sh if unspecified
+# TODO - we can get other things like resource limits here
+getep() {
+       basedir="$1"
+       q="$2"
+
+
+       digest=`cat "${basedir}/index.json" | jq --arg q "$q" '.manifests[] | if .annotations."org.opencontainers.image.ref.name" == $q then .digest else null end' | sed -e 's/"//g'`
+       if [ -z "${digest}" ]; then
+               echo "$q not found in index.json" >&2
+               echo "/bin/sh"
+               return
+       fi
+
+       # Ok we have the image config digest, now get the config from that,
+       d=${digest:7}
+       cdigest=`cat "${basedir}/blobs/sha256/${d}" | jq '.config.digest' | sed -e 's/"//g'`
+       if [ -z "${cdigest}" ]; then
+               echo "container config not found" >&2
+               echo "/bin/sh"
+               return
+       fi
+
+       d2=${cdigest:7}
+       ep=`cat "${basedir}/blobs/sha256/${d2}" | jq -c '.config.Entrypoint' | sed -e 's/^\[//; s/\]$//; s/","/" "/'`
+       cmd=`cat "${basedir}/blobs/sha256/${d2}" | jq -c '.config.Cmd' | sed -e 's/^\[//; s/\]$//; s/","/" "/'`
+       if [ "${ep}" = "null" ]; then
+               ep="${cmd}"
+               if [ "${ep}" = "null" ]; then
+                       ep="/bin/sh"
+               fi
+       elif [ "${cmd}" != "null" ]; then
+               ep="${ep} ${cmd}"
+       fi
+
+       if [ -z "${ep}" ]; then
+               echo "/bin/sh"
+               return
+       fi
+       echo "${ep}"
+       return
+}
+
+usage() {
+    cat <<EOF
+LXC container template for OCI images
+
+Special arguments:
+[ -h | --help ]: Print this help message and exit.
+
+Required arguments:
+[ -u | --url <url> ]: The OCI image URL
+
+LXC internal arguments (do not pass manually!):
+[ --name <name> ]: The container name
+[ --path <path> ]: The path to the container
+[ --rootfs <rootfs> ]: The path to the container's rootfs
+[ --mapped-uid <map> ]: A uid map (user namespaces)
+[ --mapped-gid <map> ]: A gid map (user namespaces)
+
+EOF
+    return 0
+}
+
+options=$(getopt -o u:h -l help,name:,path:,\
+rootfs:,mapped-uid:,mapped-gid: -- "$@")
+
+if [ $? -ne 0 ]; then
+    usage
+    exit 1
+fi
+eval set -- "$options"
+
+OCI_URL=""
+LXC_MAPPED_GID=
+LXC_MAPPED_UID=
+LXC_NAME=
+LXC_PATH=
+LXC_ROOTFS=
+
+while :; do
+    case "$1" in
+        -h|--help)          usage && exit 1;;
+        -u|--url)           OCI_URL=$2; shift 2;;
+        --name)             LXC_NAME=$2; shift 2;;
+        --path)             LXC_PATH=$2; shift 2;;
+        --rootfs)           LXC_ROOTFS=$2; shift 2;;
+        --mapped-uid)       LXC_MAPPED_UID=$2; shift 2;;
+        --mapped-gid)       LXC_MAPPED_GID=$2; shift 2;;
+        *)                  break;;
+    esac
+done
+
+# Check that we have all variables we need
+if [ -z "$LXC_NAME" ] || [ -z "$LXC_PATH" ] || [ -z "$LXC_ROOTFS" ]; then
+    echo "ERROR: Not running through LXC." 1>&2
+    exit 1
+fi
+
+if [ -z "$OCI_URL" ]; then
+    echo "ERROR: no OCI URL given"
+    exit 1
+fi
+
+USERNS=$(in_userns)
+
+if [ "$USERNS" != "no" ]; then
+    if [ "$USERNS" = "yes" ]; then
+        if [ -z "$LXC_MAPPED_UID" ] || [ "$LXC_MAPPED_UID" = "-1" ]; then
+            echo "ERROR: In a user namespace without a map." 1>&2
+            exit 1
+        fi
+        DOWNLOAD_MODE="user"
+        DOWNLOAD_TARGET="user"
+    else
+        DOWNLOAD_MODE="user"
+        DOWNLOAD_TARGET="system"
+    fi
+fi
+
+# Trap all exit signals
+trap cleanup EXIT HUP INT TERM
+
+if ! type mktemp >/dev/null 2>&1; then
+    DOWNLOAD_TEMP=/tmp/lxc-oci.$$
+    mkdir -p $DOWNLOAD_TEMP
+else
+    DOWNLOAD_TEMP=$(mktemp -d)
+fi
+
+# Download the image - TODO - cache
+skopeo copy "${OCI_URL}" "oci:${DOWNLOAD_TEMP}:latest"
+
+# Unpack the rootfs
+echo "Unpacking the rootfs"
+
+umoci unpack --image "${DOWNLOAD_TEMP}:latest" "${LXC_ROOTFS}.tmp"
+rmdir "${LXC_ROOTFS}"
+mv "${LXC_ROOTFS}.tmp/rootfs" "${LXC_ROOTFS}"
+entrypoint=$(getep ${DOWNLOAD_TEMP} latest)
+rm -rf "${LXC_ROOTFS}.tmp"
+
+LXC_CONF_FILE="${LXC_PATH}/config"
+echo "lxc.execute.cmd = '${entrypoint}'" >> "${LXC_CONF_FILE}"
+echo "lxc.mount.auto = proc:mixed sys:mixed cgroup:mixed" >> "${LXC_CONF_FILE}"
+
+echo "lxc.uts.name = ${LXC_NAME}" >> ${LXC_PATH}/config
+
+if [ -n "$LXC_MAPPED_UID" ] && [ "$LXC_MAPPED_UID" != "-1" ]; then
+    chown $LXC_MAPPED_UID $LXC_PATH/config $LXC_PATH/fstab >/dev/null 2>&1 || true
+fi
+if [ -n "$LXC_MAPPED_GID" ] && [ "$LXC_MAPPED_GID" != "-1" ]; then
+    chgrp $LXC_MAPPED_GID $LXC_PATH/config $LXC_PATH/fstab >/dev/null 2>&1 || true
+fi
+
+exit 0
index edecad5e32e78ddc24795ef7ac8ab252c8d8e87d..c2480dd6086194209db4f23baf77c609dee5c294 100644 (file)
@@ -12,6 +12,7 @@
 # Frederic Crozat <fcrozat@suse.com>
 # Michael H. Warfield <mhw@WittsEnd.com>
 # Johannes Kastl <mail@ojkastl.de>
+# Thomas Lamprecht <t.lamprecht@proxmox.com>
 
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -101,8 +102,10 @@ EOF
     ln -s /dev/null $rootfs/etc/systemd/system/proc-sys-fs-binfmt_misc.automount
     ln -s /dev/null $rootfs/etc/systemd/system/console-shell.service
     ln -s /dev/null $rootfs/etc/systemd/system/systemd-vconsole-setup.service
+    # enable getty and console services
     sed -e 's/ConditionPathExists=.*//' $rootfs/usr/lib/systemd/system/getty@.service > $rootfs/etc/systemd/system/getty@.service
     ln -s getty@.service $rootfs/etc/systemd/system/getty@tty1.service
+    mkdir -p $rootfs/etc/systemd/system/getty.target.wants/
     ln -s ../getty@.service $rootfs/etc/systemd/system/getty.target.wants/getty@console.service
     ln -s -f ../getty@.service $rootfs/etc/systemd/system/getty.target.wants/getty@tty1.service
     ln -s ../getty@.service $rootfs/etc/systemd/system/getty.target.wants/getty@tty2.service
@@ -138,26 +141,33 @@ download_opensuse()
     # download a mini opensuse into a cache
     echo "Downloading opensuse minimal ..."
     mkdir -p "$cache/partial-$arch-packages"
+
+    oss_repo_url="http://download.opensuse.org/distribution/$DISTRO/repo/oss/"
     if [[ $DISTRO == "tumbleweed" ]]; then
-        zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar http://download.opensuse.org/$DISTRO/repo/oss/ repo-oss || return 1
-    else
-        zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar http://download.opensuse.org/distribution/$DISTRO/repo/oss/ repo-oss || return 1
+        oss_repo_url="http://download.opensuse.org/$DISTRO/repo/oss/"
     fi
+    zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar "$oss_repo_url" repo-oss || return 1
+
+    update_repo_url="http://download.opensuse.org/update/$DISTRO/repo/oss"
     # Leap update repos were rearranged
     if [[ $DISTRO == "leap/4"* ]]; 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
+        update_repo_url="http://download.opensuse.org/update/$DISTRO/oss/"
+    fi
+    # tumbleweed has no update repo
+    if [[ $DISTRO != "tumbleweed" ]]; then
+        zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar "$update_repo_url" update || return 1
     fi
-       zypper --quiet --root $cache/partial-$arch-packages --non-interactive --gpg-auto-import-keys update || return 1
+
+    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
 Preinstall: filesystem fillup glibc grep insserv-compat perl-base
-Preinstall: libbz2-1 libncurses5 pam
-Preinstall: permissions libreadline6 rpm sed tar libz1 libselinux1
+Preinstall: libbz2-1 pam
+Preinstall: permissions rpm sed tar libz1 libselinux1
 Preinstall: liblzma5 libcap2 libacl1 libattr1
-Preinstall: libpopt0 libelf1 liblua5_1
+Preinstall: libpopt0 libelf1
 Preinstall: libpcre1
 
 RunScripts: aaa_base
@@ -170,7 +180,7 @@ Support: iputils
 Support: udev
 Support: netcfg
 Support: hwinfo insserv-compat module-init-tools openSUSE-release openssh
-Support: pwdutils rpcbind sysconfig
+Support: pwdutils sysconfig
 
 Ignore: rpm:suse-build-key,build-key
 Ignore: systemd:systemd-presets-branding
@@ -181,16 +191,21 @@ EOF
        echo "Support: python3-base" >> $cache/partial-$arch-packages/opensuse.conf
     fi
 
-    # dhcpcd is not in the default repos since Leap 42.1
-    if [[ $DISTRO != "leap/4"* ]]
-    then
-    echo "Support: dhcpcd" >> $cache/partial-$arch-packages/opensuse.conf
+    if [[ $DISTRO == "tumbleweed" ]]; then
+       echo "Preinstall: liblua5_3 libncurses6 libreadline7" >> $cache/partial-$arch-packages/opensuse.conf
+    else
+       echo "Preinstall: liblua5_1 libncurses5 libreadline6" >> $cache/partial-$arch-packages/opensuse.conf
+       echo "Support: rpcbind" >> $cache/partial-$arch-packages/opensuse.conf
     fi
 
-    # Leap doesn't seem to have iproute2 utils installed
-    if [[ $DISTRO == "leap/4"* ]]
-    then
-    echo "Support: net-tools iproute2" >> $cache/partial-$arch-packages/opensuse.conf
+    # dhcpcd is not in the default repos since Leap 42.1, neither in tumbleweed
+    if [[ $DISTRO != "leap/4"* ]] && [[ $DISTRO != "tumbleweed" ]]; then
+        echo "Support: dhcpcd" >> $cache/partial-$arch-packages/opensuse.conf
+    fi
+
+    # Leap and tumbleweed doesn't seem to have iproute2 utils installed
+    if [[ $DISTRO == "leap/4"* ]] || [[ $DISTRO == "tumbleweed" ]]; then
+        echo "Support: net-tools iproute2" >> $cache/partial-$arch-packages/opensuse.conf
     fi
 
     if [ "$arch" = "i686" ]; then
@@ -207,13 +222,16 @@ EOF
     # openSUSE 13.2 has no noarch directory in update
     [ -d $cache/partial-$arch-packages/var/cache/zypp/packages/update/noarch ] || mkdir -p $cache/partial-$arch-packages/var/cache/zypp/packages/update/noarch
 
-    CLEAN_BUILD=1 BUILD_ARCH="$arch" BUILD_ROOT="$cache/partial-$arch" BUILD_DIST="$cache/partial-$arch-packages/opensuse.conf" PATH="$PATH:$BUILD_DIR" $BUILD_DIR/init_buildsystem  --clean --configdir $BUILD_DIR/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
+    repos=("--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")
+    if [[ $DISTRO != "tumbleweed" ]]; then # tumbleweed has no update repo
+       repos+=("--repository" "$cache/partial-$arch-packages/var/cache/zypp/packages/update/$arch" "--repository" "$cache/partial-$arch-packages/var/cache/zypp/packages/update/noarch")
+    fi
 
-    if [[ $DISTRO == "leap/4"* ]]; 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
+    CLEAN_BUILD=1 BUILD_ARCH="$arch" BUILD_ROOT="$cache/partial-$arch" BUILD_DIST="$cache/partial-$arch-packages/opensuse.conf" PATH="$PATH:$BUILD_DIR" $BUILD_DIR/init_buildsystem  --clean --configdir $BUILD_DIR/configs --cachedir $cache/partial-$arch-cache ${repos[*]} || return 1
+
+    chroot $cache/partial-$arch /usr/bin/zypper --quiet --non-interactive ar "$oss_repo_url" repo-oss || return 1
+    if [[ $DISTRO != "tumbleweed" ]]; then
+        chroot $cache/partial-$arch /usr/bin/zypper --quiet --non-interactive ar "$update_repo_url" update || return 1
     fi
 
 #   really clean the image
@@ -482,7 +500,11 @@ else
         42.2|leap/42.2|422)
             echo "Selected openSUSE Leap 42.2"
             DISTRO="leap/42.2"
-            ;; 
+            ;;
+        42.3|leap/42.3|423)
+            echo "Selected openSUSE Leap 42.3"
+            DISTRO="leap/42.3"
+            ;;
         tumbleweed|factory)
             echo "Selected openSUSE Leap Tumbleweed"
             DISTRO="tumbleweed"
index d59c49bfc22d7ae1a1f66efa9cb82c4166716ffa..ec442ec3ab12210d59ad08ab1f4b16c32b4b2ee0 100644 (file)
@@ -186,7 +186,8 @@ configure_plamo() {
   # glibc configure
   mv $rootfs/etc/ld.so.conf{.new,}
   chroot $rootfs ldconfig
-  echo "Please change root password!"
+
+  # delete unnecessary process from rc.S
   ed - $rootfs/etc/rc.d/rc.S <<- "EOF"
        /^mount -w -n -t proc/;/^mkdir \/dev\/shm/-1d
        /^mknod \/dev\/null/;/^# Clean \/etc\/mtab/-2d
@@ -194,13 +195,22 @@ configure_plamo() {
        /^# Check the integrity/;/^# Clean up temporary/-1d
        w
        EOF
-  # /etc/rc.d/rc.M
+
+  # delete unnecessary process from rc.M
   ed - $rootfs/etc/rc.d/rc.M <<- "EOF"
        /^# Screen blanks/;/^# Initialize ip6tables/-1d
        /^# Initialize sysctl/;/^echo "Starting services/-1d
        /^sync/;/^# All done/-1d
        w
        EOF
+
+  # delete unnecessary process from rc.6
+  ed - $rootfs/etc/rc.d/rc.6 <<- "EOF"
+       /^# Save system time/;/^# Unmount any remote filesystems/-1d
+       /^# Turn off swap/;/^# See if this is a powerfail situation/-1d
+       w
+       EOF
+
   # /etc/rc.d/rc.inet1.tradnet
   head -n-93 $rootfs/sbin/netconfig.tradnet > /tmp/netconfig.rconly
   cat <<- EOF >> /tmp/netconfig.rconly
index 76e877d472649b0fa0873659b689bac500448080..75e5c765e9917a3386510a4d341c33bcb5e32731 100644 (file)
@@ -287,8 +287,8 @@ configure_container() {
     if [[ $unprivileged && $unprivileged == true ]] ; then
         if [[ $flush_owner == true ]] ; then
             unprivileged_options="
-lxc.id_map = u 0 ${mapped_uid} 65536
-lxc.id_map = g 0 ${mapped_gid} 65536
+lxc.idmap = u 0 ${mapped_uid} 65536
+lxc.idmap = g 0 ${mapped_gid} 65536
 "
         fi
 
index 7fc3e513287ccf72ff5936ad711cfd5ec6e686e5..80a28fd2ab84def6895fa6107036c02da4715931 100644 (file)
@@ -92,7 +92,15 @@ configure_ubuntu()
     password=$5
 
     # configure the network using the dhcp
-    cat <<EOF > $rootfs/etc/network/interfaces
+    if chroot $rootfs which netplan >/dev/null 2>&1; then
+        cat <<EOF > $rootfs/etc/netplan/10-lxc.yaml
+network:
+  ethernets:
+    eth0: {dhcp4: true}
+  version: 2
+EOF
+    else
+        cat <<EOF > $rootfs/etc/network/interfaces
 # This file describes the network interfaces available on your system
 # and how to activate them. For more information, see interfaces(5).
 
@@ -103,6 +111,7 @@ iface lo inet loopback
 auto eth0
 iface eth0 inet dhcp
 EOF
+    fi
 
     # set the hostname
     cat <<EOF > $rootfs/etc/hostname
@@ -152,13 +161,20 @@ exit 101
 EOF
         chmod +x $rootfs/usr/sbin/policy-rc.d
 
+        if [ -f "$rootfs/etc/init/ssh.conf" ]; then
+            mv "$rootfs/etc/init/ssh.conf" "$rootfs/etc/init/ssh.conf.disabled"
+        fi
+
         rm -f $rootfs/etc/ssh/ssh_host_*key*
-        mv $rootfs/etc/init/ssh.conf $rootfs/etc/init/ssh.conf.disabled
+
         DPKG_MAINTSCRIPT_PACKAGE=openssh DPKG_MAINTSCRIPT_NAME=postinst chroot $rootfs /var/lib/dpkg/info/openssh-server.postinst configure
-        mv $rootfs/etc/init/ssh.conf.disabled $rootfs/etc/init/ssh.conf
 
         sed -i "s/root@$(hostname)/root@$hostname/g" $rootfs/etc/ssh/ssh_host_*.pub
 
+        if [ -f "$rootfs/etc/init/ssh.conf.disabled" ]; then
+            mv "$rootfs/etc/init/ssh.conf.disabled" "$rootfs/etc/init/ssh.conf"
+        fi
+
         rm -f $rootfs/usr/sbin/policy-rc.d
     fi
 
@@ -359,7 +375,13 @@ download_ubuntu()
         debootstrap_parameters="$debootstrap_parameters --variant=$variant"
     fi
     if [ "$variant" = 'minbase' ]; then
-        packages_template="${packages_template},sudo,ifupdown,isc-dhcp-client"
+        packages_template="${packages_template},sudo"
+        # Newer releases use netplan, EOL releases not supported
+        case $release in
+          trusty|xenial|zesty)
+                packages_template="${packages_template},ifupdown,isc-dhcp-client"
+                ;;
+        esac
     fi
 
     echo "Installing packages in template: ${packages_template}"