file,
umount,
- # The following 3 entries are only supported by recent apparmor versions.
- # Comment them if the apparmor parser doesn't recognize them.
+ # dbus, signal, ptrace and unix are only supported by recent apparmor
+ # versions. Comment them if the apparmor parser doesn't recognize them.
+
+ # This also needs additional rules to reach outside of the container via
+ # DBus, so just let all of DBus within the container.
dbus,
- signal,
- ptrace,
+
+ # Allow us to receive signals from anywhere. Note: if per-container profiles
+ # are supported, for container isolation this should be changed to something
+ # like:
+ # signal (receive) peer=unconfined,
+ # signal (receive) peer=/usr/bin/lxc-start,
+ signal (receive),
+
+ # Allow us to send signals to ourselves
+ signal peer=@{profile_name},
+
+ # Allow other processes to read our /proc entries, futexes, perf tracing and
+ # kcmp for now (they will need 'read' in the first place). Administrators can
+ # override with:
+ # deny ptrace (readby) ...
+ ptrace (readby),
+
+ # Allow other processes to trace us by default (they will need 'trace' in
+ # the first place). Administrators can override with:
+ # deny ptrace (tracedby) ...
+ ptrace (tracedby),
+
+ # Allow us to ptrace ourselves
+ ptrace peer=@{profile_name},
+
+ # Allow receive via unix sockets from anywhere. Note: if per-container
+ # profiles are supported, for container isolation this should be changed to
+ # something like:
+ # unix (receive) peer=(label=unconfined),
+ unix (receive),
+
+ # Allow all unix in the container
+ unix peer=(label=@{profile_name}),
# ignore DENIED message on / remount
deny mount options=(ro, remount) -> /,
+ deny mount options=(ro, remount, silent) -> /,
# allow tmpfs mounts everywhere
mount fstype=tmpfs,
file,
umount,
- # The following 3 entries are only supported by recent apparmor versions.
- # Comment them if the apparmor parser doesn't recognize them.
+ # dbus, signal, ptrace and unix are only supported by recent apparmor
+ # versions. Comment them if the apparmor parser doesn't recognize them.
+
+ # This also needs additional rules to reach outside of the container via
+ # DBus, so just let all of DBus within the container.
dbus,
- signal,
- ptrace,
+
+ # Allow us to receive signals from anywhere. Note: if per-container profiles
+ # are supported, for container isolation this should be changed to something
+ # like:
+ # signal (receive) peer=unconfined,
+ # signal (receive) peer=/usr/bin/lxc-start,
+ signal (receive),
+
+ # Allow us to send signals to ourselves
+ signal peer=@{profile_name},
+
+ # Allow other processes to read our /proc entries, futexes, perf tracing and
+ # kcmp for now (they will need 'read' in the first place). Administrators can
+ # override with:
+ # deny ptrace (readby) ...
+ ptrace (readby),
+
+ # Allow other processes to trace us by default (they will need 'trace' in
+ # the first place). Administrators can override with:
+ # deny ptrace (tracedby) ...
+ ptrace (tracedby),
+
+ # Allow us to ptrace ourselves
+ ptrace peer=@{profile_name},
+
+ # Allow receive via unix sockets from anywhere. Note: if per-container
+ # profiles are supported, for container isolation this should be changed to
+ # something like:
+ # unix (receive) peer=(label=unconfined),
+ unix (receive),
+
+ # Allow all unix in the container
+ unix peer=(label=@{profile_name}),
# ignore DENIED message on / remount
deny mount options=(ro, remount) -> /,
+ deny mount options=(ro, remount, silent) -> /,
# allow tmpfs mounts everywhere
mount fstype=tmpfs,
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-@ENABLE_BASH_FALSE@install-data-local:
@ENABLE_BASH_FALSE@uninstall-local:
+@ENABLE_BASH_FALSE@install-data-local:
clean: clean-am
clean-am: clean-generic mostlyclean-am
# Default mount
lxc.mount.auto = proc sys cgroup
+lxc.mount.entry = none dev/shm tmpfs nosuid,nodev,noexec,mode=1777 0 0
# Default capabilities
lxc.cap.drop = sys_module mac_admin mac_override sys_time
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for lxc 1.0.6.
+# Generated by GNU Autoconf 2.69 for lxc 1.0.7.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
# Identity of this package.
PACKAGE_NAME='lxc'
PACKAGE_TARNAME='lxc'
-PACKAGE_VERSION='1.0.6'
-PACKAGE_STRING='lxc 1.0.6'
+PACKAGE_VERSION='1.0.7'
+PACKAGE_STRING='lxc 1.0.7'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures lxc 1.0.6 to adapt to many kinds of systems.
+\`configure' configures lxc 1.0.7 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of lxc 1.0.6:";;
+ short | recursive ) echo "Configuration of lxc 1.0.7:";;
esac
cat <<\_ACEOF
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-lxc configure 1.0.6
+lxc configure 1.0.7
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by lxc $as_me 1.0.6, which was
+It was created by lxc $as_me 1.0.7, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
fi
fi
-LXC_VERSION_BASE=1.0.6
+LXC_VERSION_BASE=1.0.7
LXC_VERSION_MINOR=0
-LXC_VERSION_MICRO=6
+LXC_VERSION_MICRO=7
-LXC_VERSION=1.0.6
+LXC_VERSION=1.0.7
# Define the identity of the package.
PACKAGE='lxc'
- VERSION='1.0.6'
+ VERSION='1.0.7'
cat >>confdefs.h <<_ACEOF
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by lxc $as_me 1.0.6, which was
+This file was extended by lxc $as_me 1.0.7, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-lxc config.status 1.0.6
+lxc config.status 1.0.7
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
m4_define([lxc_version_major], 1)
m4_define([lxc_version_minor], 0)
-m4_define([lxc_version_micro], 6)
+m4_define([lxc_version_micro], 7)
m4_define([lxc_version_beta], [])
m4_define([lxc_version_base], [lxc_version_major.lxc_version_minor.lxc_version_micro])
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all refrences to function-like macros that are alone on a line, have an
+# remove all references to function-like macros that are alone on a line, have an
# all uppercase name, and do not end with a semicolon. Such function macros are
# typically used for boiler-plate code, and will confuse the parser if not
# removed.
the maximum number of pseudo ttys allowed for a pts
instance (this limitation is not implemented yet).
-->
- もし設定された場合、コンテナは新しい psuedo tty インスタンスを持ち、それを自身のプライベートとします。
+ もし設定された場合、コンテナは新しい pseudo tty インスタンスを持ち、それを自身のプライベートとします。
この値は pts インスタンスに許可される pseudo tty の最大数を指定します (この制限はまだ実装されていません)。
</para>
</listitem>
<para>
<!--
- The kernel version >= 2.6.27 shipped with the distros, will
+ 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.
- With the kernel 2.6.29, <command>lxc</command> is fully
- functional.
-
The helper script <command>lxc-checkconfig</command> will give
you information about your kernel configuration.
-->
- 2.6.27 以上のバージョンが採用されているディストリビューションならば、<command>lxc</command> は動作するでしょう。
+ 2.6.32 以上のバージョンが採用されているディストリビューションならば、<command>lxc</command> は動作するでしょう。
機能的には若干少ない形ですが、充分に楽しめるはずです。
- 2.6.29 カーネルであれば、<command>lxc</command> は完全に機能します。
ヘルパースクリプトの <command>lxc-checkconfig</command> を使って、あなたのカーネルの設定に関する情報を取得できるでしょう。
</para>
<para>
<!--
- Before using the <command>lxc</command>, your system should be
- configured with the file capabilities, otherwise you will need
- to run the <command>lxc</command> commands as root.
- -->
- <command>lxc</command> を使う前に、システムがファイルに対するケーパビリティーをえられるように設定するか、もしくは <command>lxc</command> コマンドを root で実行する必要があるでしょう。
- </para>
-
- <para>
- <!--
The control group can be mounted anywhere, eg:
<command>mount -t cgroup cgroup /cgroup</command>.
- If you want to dedicate a specific cgroup mount point
- for <command>lxc</command>, that is to have different cgroups
- mounted at different places with different options but
- let <command>lxc</command> to use one location, you can bind
- the mount point with the <option>lxc</option> name, eg:
- <command>mount -t cgroup lxc /cgroup4lxc</command> or
- <command>mount -t cgroup -ons,cpuset,freezer,devices
- lxc /cgroup4lxc</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 を持ち、一つの場所の <command>lxc</command> コマンドを使うための、特定の <command>lxc</command> のための専用の cgroup のマウントポイントを提供したければ、lxc という名前でマウントポイントにバインドすることが出来ます。例えば以下のようにです。
- <command>mount -t cgroup lxc /cgroup4lxc</command> or
- <command>mount -t cgroup -ons,cpuset,freezer,devices
- lxc /cgroup4lxc</command>
+ しかし、cgroup の階層構造を /sys/fs/cgroup 以下にマウントするために cgmanager や cgroup-lite や systemd の使用が推奨されています。
</para>
</refsect1>
<command>lxc-create</command>
<arg choice="req">-n <replaceable>name</replaceable></arg>
<arg choice="opt">-f <replaceable>config_file</replaceable></arg>
- <arg choice="opt">-t <replaceable>template</replaceable></arg>
+ <arg choice="reg">-t <replaceable>template</replaceable></arg>
<arg choice="opt">-B <replaceable>backingstore</replaceable></arg>
<arg choice="opt">-- <replaceable>template-options</replaceable></arg>
</cmdsynopsis>
<refsect2>
<title>Configuration</title>
<para>
- In order to ease administration of multiple related containers, it
- is possible to have a container configuration file cause another
- file to be loaded. For instance, network configuration
- can be defined in one common file which is included by multiple
- containers. Then, if the containers are moved to another host,
- only one file may need to be updated.
+ In order to ease administration of multiple related containers, it
+ is possible to have a container configuration file cause another
+ file to be loaded. For instance, network configuration
+ can be defined in one common file which is included by multiple
+ containers. Then, if the containers are moved to another host,
+ only one file may need to be updated.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.include</option>
- </term>
- <listitem>
- <para>
- Specify the file to be included. The included file must be
- in the same valid lxc configuration file format.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.include</option>
+ </term>
+ <listitem>
+ <para>
+ Specify the file to be included. The included file must be
+ in the same valid lxc configuration file format.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Architecture</title>
<para>
- Allows one to set the architecture for the container. For example,
- set a 32bits architecture for a container running 32bits
- binaries on a 64bits host. This fixes the container scripts
- which rely on the architecture to do some work like
- downloading the packages.
+ Allows one to set the architecture for the container. For example,
+ set a 32bits architecture for a container running 32bits
+ binaries on a 64bits host. This fixes the container scripts
+ which rely on the architecture to do some work like
+ downloading the packages.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.arch</option>
- </term>
- <listitem>
- <para>
- Specify the architecture for the container.
- </para>
- <para>
- Valid options are
- <option>x86</option>,
- <option>i686</option>,
- <option>x86_64</option>,
- <option>amd64</option>
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.arch</option>
+ </term>
+ <listitem>
+ <para>
+ Specify the architecture for the container.
+ </para>
+ <para>
+ Valid options are
+ <option>x86</option>,
+ <option>i686</option>,
+ <option>x86_64</option>,
+ <option>amd64</option>
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Hostname</title>
<para>
- The utsname section defines the hostname to be set for the
- container. That means the container can set its own hostname
- without changing the one from the system. That makes the
- hostname private for the container.
+ The utsname section defines the hostname to be set for the
+ container. That means the container can set its own hostname
+ without changing the one from the system. That makes the
+ hostname private for the container.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.utsname</option>
- </term>
- <listitem>
- <para>
- specify the hostname for the container
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.utsname</option>
+ </term>
+ <listitem>
+ <para>
+ specify the hostname for the container
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Network</title>
<para>
- The network section defines how the network is virtualized in
- the container. The network virtualization acts at layer
- two. In order to use the network virtualization, parameters
- must be specified to define the network interfaces of the
- container. Several virtual interfaces can be assigned and used
- in a container even if the system has only one physical
- network interface.
+ The network section defines how the network is virtualized in
+ the container. The network virtualization acts at layer
+ two. In order to use the network virtualization, parameters
+ must be specified to define the network interfaces of the
+ container. Several virtual interfaces can be assigned and used
+ in a container even if the system has only one physical
+ network interface.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.network.type</option>
- </term>
- <listitem>
- <para>
- specify what kind of network virtualization to be used
- for the container. Each time
- a <option>lxc.network.type</option> field is found a new
- round of network configuration begins. In this way,
- several network virtualization types can be specified
- for the same container, as well as assigning several
- network interfaces for one container. The different
- virtualization types can be:
- </para>
-
- <para>
- <option>none:</option> will cause the container to share
- the host's network namespace. This means the host
- network devices are usable in the container. It also
- means that if both the container and host have upstart as
- init, 'halt' in a container (for instance) will shut down the
- host.
- </para>
-
- <para>
- <option>empty:</option> will create only the loopback
- interface.
- </para>
-
- <para>
- <option>veth:</option> a peer network device is created
- with one side assigned to the container and the other
- side is attached to a bridge specified by
- the <option>lxc.network.link</option>. If the bridge is
- not specified, then the veth pair device will be created
- but not attached to any bridge. Otherwise, the bridge
- has to be setup before on the
- system, <command>lxc</command> won't handle any
- configuration outside of the container. By
- default <command>lxc</command> choose a name for the
- network device belonging to the outside of the
- container, this name is handled
- by <command>lxc</command>, but if you wish to handle
- this name yourself, you can tell <command>lxc</command>
- to set a specific name with
- the <option>lxc.network.veth.pair</option> option (except for
- unprivileged containers where this option is ignored for security
- reasons).
- </para>
-
- <para>
- <option>vlan:</option> a vlan interface is linked with
- the interface specified by
- the <option>lxc.network.link</option> and assigned to
- the container. The vlan identifier is specified with the
- option <option>lxc.network.vlan.id</option>.
- </para>
-
- <para>
- <option>macvlan:</option> a macvlan interface is linked
- with the interface specified by
- the <option>lxc.network.link</option> and assigned to
- the container.
- <option>lxc.network.macvlan.mode</option> specifies the
- mode the macvlan will use to communicate between
- different macvlan on the same upper device. The accepted
- modes are <option>private</option>, the device never
- communicates with any other device on the same upper_dev (default),
- <option>vepa</option>, the new Virtual Ethernet Port
- Aggregator (VEPA) mode, it assumes that the adjacent
- bridge returns all frames where both source and
- destination are local to the macvlan port, i.e. the
- bridge is set up as a reflective relay. Broadcast
- frames coming in from the upper_dev get flooded to all
- macvlan interfaces in VEPA mode, local frames are not
- delivered locally, or <option>bridge</option>, it
- provides the behavior of a simple bridge between
- different macvlan interfaces on the same port. Frames
- from one interface to another one get delivered directly
- and are not sent out externally. Broadcast frames get
- flooded to all other bridge ports and to the external
- interface, but when they come back from a reflective
- relay, we don't deliver them again. Since we know all
- the MAC addresses, the macvlan bridge mode does not
- require learning or STP like the bridge module does.
- </para>
-
- <para>
- <option>phys:</option> an already existing interface
- specified by the <option>lxc.network.link</option> is
- assigned to the container.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.network.flags</option>
- </term>
- <listitem>
- <para>
- specify an action to do for the
- network.
- </para>
-
- <para><option>up:</option> activates the interface.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.network.link</option>
- </term>
- <listitem>
- <para>
- specify the interface to be used for real network
- traffic.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.network.mtu</option>
- </term>
- <listitem>
- <para>
- specify the maximum transfer unit for this interface.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.network.name</option>
- </term>
- <listitem>
- <para>
- the interface name is dynamically allocated, but if
- another name is needed because the configuration files
- being used by the container use a generic name,
- eg. eth0, this option will rename the interface in the
- container.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.network.hwaddr</option>
- </term>
- <listitem>
- <para>
- the interface mac address is dynamically allocated by
- default to the virtual interface, but in some cases,
- this is needed to resolve a mac address conflict or to
- always have the same link-local ipv6 address.
- Any "x" in address will be replaced by random value,
- this allows setting hwaddr templates.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.network.ipv4</option>
- </term>
- <listitem>
- <para>
- specify the ipv4 address to assign to the virtualized
- interface. Several lines specify several ipv4 addresses.
- The address is in format x.y.z.t/m,
- eg. 192.168.1.123/24. The broadcast address should be
- specified on the same line, right after the ipv4
- address.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.network.ipv4.gateway</option>
- </term>
- <listitem>
- <para>
- specify the ipv4 address to use as the gateway inside the
- container. The address is in format x.y.z.t, eg.
- 192.168.1.123.
-
- Can also have the special value <option>auto</option>,
- which means to take the primary address from the bridge
- interface (as specified by the
- <option>lxc.network.link</option> option) and use that as
- the gateway. <option>auto</option> is only available when
- using the <option>veth</option> and
- <option>macvlan</option> network types.
- </para>
- </listitem>
- </varlistentry>
-
-
- <varlistentry>
- <term>
- <option>lxc.network.ipv6</option>
- </term>
- <listitem>
- <para>
- specify the ipv6 address to assign to the virtualized
- interface. Several lines specify several ipv6 addresses.
- The address is in format x::y/m,
- eg. 2003:db8:1:0:214:1234:fe0b:3596/64
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.network.ipv6.gateway</option>
- </term>
- <listitem>
- <para>
- specify the ipv6 address to use as the gateway inside the
- container. The address is in format x::y,
- eg. 2003:db8:1:0::1
-
- Can also have the special value <option>auto</option>,
- which means to take the primary address from the bridge
- interface (as specified by the
- <option>lxc.network.link</option> option) and use that as
- the gateway. <option>auto</option> is only available when
- using the <option>veth</option> and
- <option>macvlan</option> network types.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.network.script.up</option>
- </term>
- <listitem>
- <para>
- add a configuration option to specify a script to be
- executed after creating and configuring the network used
- from the host side. The following arguments are passed
- to the script: container name and config section name
- (net) Additional arguments depend on the config section
- employing a script hook; the following are used by the
- network system: execution context (up), network type
- (empty/veth/macvlan/phys), Depending on the network
- type, other arguments may be passed:
- veth/macvlan/phys. And finally (host-sided) device name.
- </para>
- <para>
- Standard output from the script is logged at debug level.
- Standard error is not logged, but can be captured by the
- hook redirecting its standard error to standard output.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.network.script.down</option>
- </term>
- <listitem>
- <para>
- add a configuration option to specify a script to be
- executed before destroying the network used from the
- host side. The following arguments are passed to the
- script: container name and config section name (net)
- Additional arguments depend on the config section
- employing a script hook; the following are used by the
- network system: execution context (down), network type
- (empty/veth/macvlan/phys), Depending on the network
- type, other arguments may be passed:
- veth/macvlan/phys. And finally (host-sided) device name.
- </para>
- <para>
- Standard output from the script is logged at debug level.
- Standard error is not logged, but can be captured by the
- hook redirecting its standard error to standard output.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.network.type</option>
+ </term>
+ <listitem>
+ <para>
+ specify what kind of network virtualization to be used
+ for the container. Each time
+ a <option>lxc.network.type</option> field is found a new
+ round of network configuration begins. In this way,
+ several network virtualization types can be specified
+ for the same container, as well as assigning several
+ network interfaces for one container. The different
+ virtualization types can be:
+ </para>
+
+ <para>
+ <option>none:</option> will cause the container to share
+ the host's network namespace. This means the host
+ network devices are usable in the container. It also
+ means that if both the container and host have upstart as
+ init, 'halt' in a container (for instance) will shut down the
+ host.
+ </para>
+
+ <para>
+ <option>empty:</option> will create only the loopback
+ interface.
+ </para>
+
+ <para>
+ <option>veth:</option> a peer network device is created
+ with one side assigned to the container and the other
+ side is attached to a bridge specified by
+ the <option>lxc.network.link</option>. If the bridge is
+ not specified, then the veth pair device will be created
+ but not attached to any bridge. Otherwise, the bridge
+ has to be setup before on the
+ system, <command>lxc</command> won't handle any
+ configuration outside of the container. By
+ default <command>lxc</command> choose a name for the
+ network device belonging to the outside of the
+ container, this name is handled
+ by <command>lxc</command>, but if you wish to handle
+ this name yourself, you can tell <command>lxc</command>
+ to set a specific name with
+ the <option>lxc.network.veth.pair</option> option (except for
+ unprivileged containers where this option is ignored for security
+ reasons).
+ </para>
+
+ <para>
+ <option>vlan:</option> a vlan interface is linked with
+ the interface specified by
+ the <option>lxc.network.link</option> and assigned to
+ the container. The vlan identifier is specified with the
+ option <option>lxc.network.vlan.id</option>.
+ </para>
+
+ <para>
+ <option>macvlan:</option> a macvlan interface is linked
+ with the interface specified by
+ the <option>lxc.network.link</option> and assigned to
+ the container.
+ <option>lxc.network.macvlan.mode</option> specifies the
+ mode the macvlan will use to communicate between
+ different macvlan on the same upper device. The accepted
+ modes are <option>private</option>, the device never
+ communicates with any other device on the same upper_dev (default),
+ <option>vepa</option>, the new Virtual Ethernet Port
+ Aggregator (VEPA) mode, it assumes that the adjacent
+ bridge returns all frames where both source and
+ destination are local to the macvlan port, i.e. the
+ bridge is set up as a reflective relay. Broadcast
+ frames coming in from the upper_dev get flooded to all
+ macvlan interfaces in VEPA mode, local frames are not
+ delivered locally, or <option>bridge</option>, it
+ provides the behavior of a simple bridge between
+ different macvlan interfaces on the same port. Frames
+ from one interface to another one get delivered directly
+ and are not sent out externally. Broadcast frames get
+ flooded to all other bridge ports and to the external
+ interface, but when they come back from a reflective
+ relay, we don't deliver them again. Since we know all
+ the MAC addresses, the macvlan bridge mode does not
+ require learning or STP like the bridge module does.
+ </para>
+
+ <para>
+ <option>phys:</option> an already existing interface
+ specified by the <option>lxc.network.link</option> is
+ assigned to the container.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.flags</option>
+ </term>
+ <listitem>
+ <para>
+ specify an action to do for the
+ network.
+ </para>
+
+ <para><option>up:</option> activates the interface.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.link</option>
+ </term>
+ <listitem>
+ <para>
+ specify the interface to be used for real network
+ traffic.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.mtu</option>
+ </term>
+ <listitem>
+ <para>
+ specify the maximum transfer unit for this interface.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.name</option>
+ </term>
+ <listitem>
+ <para>
+ the interface name is dynamically allocated, but if
+ another name is needed because the configuration files
+ being used by the container use a generic name,
+ eg. eth0, this option will rename the interface in the
+ container.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.hwaddr</option>
+ </term>
+ <listitem>
+ <para>
+ the interface mac address is dynamically allocated by
+ default to the virtual interface, but in some cases,
+ this is needed to resolve a mac address conflict or to
+ always have the same link-local ipv6 address.
+ Any "x" in address will be replaced by random value,
+ this allows setting hwaddr templates.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.ipv4</option>
+ </term>
+ <listitem>
+ <para>
+ specify the ipv4 address to assign to the virtualized
+ interface. Several lines specify several ipv4 addresses.
+ The address is in format x.y.z.t/m,
+ eg. 192.168.1.123/24. The broadcast address should be
+ specified on the same line, right after the ipv4
+ address.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.ipv4.gateway</option>
+ </term>
+ <listitem>
+ <para>
+ specify the ipv4 address to use as the gateway inside the
+ container. The address is in format x.y.z.t, eg.
+ 192.168.1.123.
+
+ Can also have the special value <option>auto</option>,
+ which means to take the primary address from the bridge
+ interface (as specified by the
+ <option>lxc.network.link</option> option) and use that as
+ the gateway. <option>auto</option> is only available when
+ using the <option>veth</option> and
+ <option>macvlan</option> network types.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.ipv6</option>
+ </term>
+ <listitem>
+ <para>
+ specify the ipv6 address to assign to the virtualized
+ interface. Several lines specify several ipv6 addresses.
+ The address is in format x::y/m,
+ eg. 2003:db8:1:0:214:1234:fe0b:3596/64
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.ipv6.gateway</option>
+ </term>
+ <listitem>
+ <para>
+ specify the ipv6 address to use as the gateway inside the
+ container. The address is in format x::y,
+ eg. 2003:db8:1:0::1
+
+ Can also have the special value <option>auto</option>,
+ which means to take the primary address from the bridge
+ interface (as specified by the
+ <option>lxc.network.link</option> option) and use that as
+ the gateway. <option>auto</option> is only available when
+ using the <option>veth</option> and
+ <option>macvlan</option> network types.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.script.up</option>
+ </term>
+ <listitem>
+ <para>
+ add a configuration option to specify a script to be
+ executed after creating and configuring the network used
+ from the host side. The following arguments are passed
+ to the script: container name and config section name
+ (net) Additional arguments depend on the config section
+ employing a script hook; the following are used by the
+ network system: execution context (up), network type
+ (empty/veth/macvlan/phys), Depending on the network
+ type, other arguments may be passed:
+ veth/macvlan/phys. And finally (host-sided) device name.
+ </para>
+ <para>
+ Standard output from the script is logged at debug level.
+ Standard error is not logged, but can be captured by the
+ hook redirecting its standard error to standard output.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.network.script.down</option>
+ </term>
+ <listitem>
+ <para>
+ add a configuration option to specify a script to be
+ executed before destroying the network used from the
+ host side. The following arguments are passed to the
+ script: container name and config section name (net)
+ Additional arguments depend on the config section
+ employing a script hook; the following are used by the
+ network system: execution context (down), network type
+ (empty/veth/macvlan/phys), Depending on the network
+ type, other arguments may be passed:
+ veth/macvlan/phys. And finally (host-sided) device name.
+ </para>
+ <para>
+ Standard output from the script is logged at debug level.
+ Standard error is not logged, but can be captured by the
+ hook redirecting its standard error to standard output.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>New pseudo tty instance (devpts)</title>
<para>
- For stricter isolation the container can have its own private
- instance of the pseudo tty.
+ For stricter isolation the container can have its own private
+ instance of the pseudo tty.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.pts</option>
- </term>
- <listitem>
- <para>
- If set, the container will have a new pseudo tty
- instance, making this private to it. The value specifies
+ <varlistentry>
+ <term>
+ <option>lxc.pts</option>
+ </term>
+ <listitem>
+ <para>
+ If set, the container will have a new pseudo tty
+ instance, making this private to it. The value specifies
the maximum number of pseudo ttys allowed for a pts
instance (this limitation is not implemented yet).
- </para>
- </listitem>
- </varlistentry>
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Container system console</title>
<para>
- If the container is configured with a root filesystem and the
- inittab file is setup to use the console, you may want to specify
- where the output of this console goes.
+ If the container is configured with a root filesystem and the
+ inittab file is setup to use the console, you may want to specify
+ where the output of this console goes.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.console.logfile</option>
- </term>
- <listitem>
- <para>
- Specify a path to a file where the console output will
- be written.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- <option>lxc.console</option>
- </term>
- <listitem>
- <para>
- Specify a path to a device to which the console will be
- attached. The keyword 'none' will simply disable the
- console. This is dangerous once if have a rootfs with a
- console device file where the application can write, the
- messages will fall in the host.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.console.logfile</option>
+ </term>
+ <listitem>
+ <para>
+ Specify a path to a file where the console output will
+ be written.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.console</option>
+ </term>
+ <listitem>
+ <para>
+ Specify a path to a device to which the console will be
+ attached. The keyword 'none' will simply disable the
+ console. This is dangerous once if have a rootfs with a
+ console device file where the application can write, the
+ messages will fall in the host.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Console through the ttys</title>
<para>
- This option is useful if the container is configured with a root
- filesystem and the inittab file is setup to launch a getty on the
- ttys. The option specifies the number of ttys to be available for
- the container. The number of gettys in the inittab file of the
- container should not be greater than the number of ttys specified
- in this option, otherwise the excess getty sessions will die and
- respawn indefinitely giving annoying messages on the console or in
- <filename>/var/log/messages</filename>.
+ This option is useful if the container is configured with a root
+ filesystem and the inittab file is setup to launch a getty on the
+ ttys. The option specifies the number of ttys to be available for
+ the container. The number of gettys in the inittab file of the
+ container should not be greater than the number of ttys specified
+ in this option, otherwise the excess getty sessions will die and
+ respawn indefinitely giving annoying messages on the console or in
+ <filename>/var/log/messages</filename>.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.tty</option>
- </term>
- <listitem>
- <para>
- Specify the number of tty to make available to the
- container.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.tty</option>
+ </term>
+ <listitem>
+ <para>
+ Specify the number of tty to make available to the
+ container.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<title>Console devices location</title>
<para>
LXC consoles are provided through Unix98 PTYs created on the
- host and bind-mounted over the expected devices in the container.
- By default, they are bind-mounted over <filename>/dev/console</filename>
- and <filename>/dev/ttyN</filename>. This can prevent package upgrades
- in the guest. Therefore you can specify a directory location (under
- <filename>/dev</filename> under which LXC will create the files and
- bind-mount over them. These will then be symbolically linked to
- <filename>/dev/console</filename> and <filename>/dev/ttyN</filename>.
- A package upgrade can then succeed as it is able to remove and replace
- the symbolic links.
+ host and bind-mounted over the expected devices in the container.
+ By default, they are bind-mounted over <filename>/dev/console</filename>
+ and <filename>/dev/ttyN</filename>. This can prevent package upgrades
+ in the guest. Therefore you can specify a directory location (under
+ <filename>/dev</filename> under which LXC will create the files and
+ bind-mount over them. These will then be symbolically linked to
+ <filename>/dev/console</filename> and <filename>/dev/ttyN</filename>.
+ A package upgrade can then succeed as it is able to remove and replace
+ the symbolic links.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.devttydir</option>
- </term>
- <listitem>
- <para>
- Specify a directory under <filename>/dev</filename>
- under which to create the container console devices.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.devttydir</option>
+ </term>
+ <listitem>
+ <para>
+ Specify a directory under <filename>/dev</filename>
+ under which to create the container console devices.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>/dev directory</title>
<para>
- By default, lxc creates a few symbolic links (fd,stdin,stdout,stderr)
- in the container's <filename>/dev</filename> directory but does not
- automatically create device node entries. This allows the container's
- <filename>/dev</filename> to be set up as needed in the container
- rootfs. If lxc.autodev is set to 1, then after mounting the container's
- rootfs LXC will mount a fresh tmpfs under <filename>/dev</filename>
- (limited to 100k) and fill in a minimal set of initial devices.
+ By default, lxc creates a few symbolic links (fd,stdin,stdout,stderr)
+ in the container's <filename>/dev</filename> directory but does not
+ automatically create device node entries. This allows the container's
+ <filename>/dev</filename> to be set up as needed in the container
+ rootfs. If lxc.autodev is set to 1, then after mounting the container's
+ rootfs LXC will mount a fresh tmpfs under <filename>/dev</filename>
+ (limited to 100k) and fill in a minimal set of initial devices.
This is generally required when starting a container containing
a "systemd" based "init" but may be optional at other times. Additional
devices in the containers /dev directory may be created through the
use of the <option>lxc.hook.autodev</option> hook.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.autodev</option>
- </term>
- <listitem>
- <para>
- Set this to 1 to have LXC mount and populate a minimal
- <filename>/dev</filename> when starting the container.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.autodev</option>
+ </term>
+ <listitem>
+ <para>
+ Set this to 1 to have LXC mount and populate a minimal
+ <filename>/dev</filename> when starting the container.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Mount points</title>
<para>
- The mount points section specifies the different places to be
- mounted. These mount points will be private to the container
- and won't be visible by the processes running outside of the
- container. This is useful to mount /etc, /var or /home for
- examples.
+ The mount points section specifies the different places to be
+ mounted. These mount points will be private to the container
+ and won't be visible by the processes running outside of the
+ container. This is useful to mount /etc, /var or /home for
+ examples.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.mount</option>
- </term>
- <listitem>
- <para>
- specify a file location in
- the <filename>fstab</filename> format, containing the
- mount information. The mount target location can and in
- most cases should be a relative path, which will become
- relative to the mounted container root. For instance,
- </para>
+ <varlistentry>
+ <term>
+ <option>lxc.mount</option>
+ </term>
+ <listitem>
+ <para>
+ specify a file location in
+ the <filename>fstab</filename> format, containing the
+ mount information. The mount target location can and in
+ most cases should be a relative path, which will become
+ relative to the mounted container root. For instance,
+ </para>
<screen>
proc proc proc nodev,noexec,nosuid 0 0
</screen>
- <para>
- Will mount a proc filesystem under the container's /proc,
- regardless of where the root filesystem comes from. This
- is resilient to block device backed filesystems as well as
- container cloning.
- </para>
- <para>
- Note that when mounting a filesystem from an
- image file or block device the third field (fs_vfstype)
- cannot be auto as with
+ <para>
+ Will mount a proc filesystem under the container's /proc,
+ regardless of where the root filesystem comes from. This
+ is resilient to block device backed filesystems as well as
+ container cloning.
+ </para>
+ <para>
+ Note that when mounting a filesystem from an
+ image file or block device the third field (fs_vfstype)
+ cannot be auto as with
<citerefentry>
- <refentrytitle>mount</refentrytitle>
+ <refentrytitle>mount</refentrytitle>
<manvolnum>8</manvolnum>
</citerefentry>
but must be explicitly specified.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.mount.entry</option>
- </term>
- <listitem>
- <para>
- specify a mount point corresponding to a line in the
- fstab format.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.mount.auto</option>
- </term>
- <listitem>
- <para>
- specify which standard kernel file systems should be
- automatically mounted. This may dramatically simplify
- the configuration. The file systems are:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <option>proc:mixed</option> (or <option>proc</option>):
- mount <filename>/proc</filename> as read-write, but
- remount <filename>/proc/sys</filename> and
- <filename>/proc/sysrq-trigger</filename> read-only
- for security / container isolation purposes.
- </para>
- </listitem>
- <listitem>
- <para>
- <option>proc:rw</option>: mount
- <filename>/proc</filename> as read-write
- </para>
- </listitem>
- <listitem>
- <para>
- <option>sys:ro</option> (or <option>sys</option>):
- mount <filename>/sys</filename> as read-only
- for security / container isolation purposes.
- </para>
- </listitem>
- <listitem>
- <para>
- <option>sys:rw</option>: mount
- <filename>/sys</filename> as read-write
- </para>
- </listitem>
- <listitem>
- <para>
- <option>cgroup:mixed</option>:
- mount a tmpfs to <filename>/sys/fs/cgroup</filename>,
- create directories for all hierarchies to which
- the container is added, create subdirectories
- there with the name of the cgroup, and bind-mount
- the container's own cgroup into that directory.
- The container will be able to write to its own
- cgroup directory, but not the parents, since they
- will be remounted read-only
- </para>
- </listitem>
- <listitem>
- <para>
- <option>cgroup:ro</option>: similar to
- <option>cgroup:mixed</option>, but everything will
- be mounted read-only.
- </para>
- </listitem>
- <listitem>
- <para>
- <option>cgroup:rw</option>: similar to
- <option>cgroup:mixed</option>, but everything will
- be mounted read-write. Note that the paths leading
- up to the container's own cgroup will be writable,
- but will not be a cgroup filesystem but just part
- of the tmpfs of <filename>/sys/fs/cgroup</filename>
- </para>
- </listitem>
- <listitem>
- <para>
- <option>cgroup</option> (without specifier):
- defaults to <option>cgroup:rw</option> if the
- container retains the CAP_SYS_ADMIN capability,
- <option>cgroup:mixed</option> otherwise.
- </para>
- </listitem>
- <listitem>
- <para>
- <option>cgroup-full:mixed</option>:
- mount a tmpfs to <filename>/sys/fs/cgroup</filename>,
- create directories for all hierarchies to which
- the container is added, bind-mount the hierarchies
- from the host to the container and make everything
- read-only except the container's own cgroup. Note
- that compared to <option>cgroup</option>, where
- all paths leading up to the container's own cgroup
- are just simple directories in the underlying
- tmpfs, here
- <filename>/sys/fs/cgroup/$hierarchy</filename>
- will contain the host's full cgroup hierarchy,
- albeit read-only outside the container's own cgroup.
- This may leak quite a bit of information into the
- container.
- </para>
- </listitem>
- <listitem>
- <para>
- <option>cgroup-full:ro</option>: similar to
- <option>cgroup-full:mixed</option>, but everything
- will be mounted read-only.
- </para>
- </listitem>
- <listitem>
- <para>
- <option>cgroup-full:rw</option>: similar to
- <option>cgroup-full:mixed</option>, but everything
- will be mounted read-write. Note that in this case,
- the container may escape its own cgroup. (Note also
- that if the container has CAP_SYS_ADMIN support
- and can mount the cgroup filesystem itself, it may
- do so anyway.)
- </para>
- </listitem>
- <listitem>
- <para>
- <option>cgroup-full</option> (without specifier):
- defaults to <option>cgroup-full:rw</option> if the
- container retains the CAP_SYS_ADMIN capability,
- <option>cgroup-full:mixed</option> otherwise.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Note that if automatic mounting of the cgroup filesystem
- is enabled, the tmpfs under
- <filename>/sys/fs/cgroup</filename> will always be
- mounted read-write (but for the <option>:mixed</option>
- and <option>:ro</option> cases, the individual
- hierarchies,
- <filename>/sys/fs/cgroup/$hierarchy</filename>, will be
- read-only). This is in order to work around a quirk in
- Ubuntu's
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.mount.entry</option>
+ </term>
+ <listitem>
+ <para>
+ specify a mount point corresponding to a line in the
+ fstab format.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.mount.auto</option>
+ </term>
+ <listitem>
+ <para>
+ specify which standard kernel file systems should be
+ automatically mounted. This may dramatically simplify
+ the configuration. The file systems are:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <option>proc:mixed</option> (or <option>proc</option>):
+ mount <filename>/proc</filename> as read-write, but
+ remount <filename>/proc/sys</filename> and
+ <filename>/proc/sysrq-trigger</filename> read-only
+ for security / container isolation purposes.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>proc:rw</option>: mount
+ <filename>/proc</filename> as read-write
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>sys:ro</option> (or <option>sys</option>):
+ mount <filename>/sys</filename> as read-only
+ for security / container isolation purposes.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>sys:rw</option>: mount
+ <filename>/sys</filename> as read-write
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>cgroup:mixed</option>:
+ mount a tmpfs to <filename>/sys/fs/cgroup</filename>,
+ create directories for all hierarchies to which
+ the container is added, create subdirectories
+ there with the name of the cgroup, and bind-mount
+ the container's own cgroup into that directory.
+ The container will be able to write to its own
+ cgroup directory, but not the parents, since they
+ will be remounted read-only
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>cgroup:ro</option>: similar to
+ <option>cgroup:mixed</option>, but everything will
+ be mounted read-only.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>cgroup:rw</option>: similar to
+ <option>cgroup:mixed</option>, but everything will
+ be mounted read-write. Note that the paths leading
+ up to the container's own cgroup will be writable,
+ but will not be a cgroup filesystem but just part
+ of the tmpfs of <filename>/sys/fs/cgroup</filename>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>cgroup</option> (without specifier):
+ defaults to <option>cgroup:rw</option> if the
+ container retains the CAP_SYS_ADMIN capability,
+ <option>cgroup:mixed</option> otherwise.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>cgroup-full:mixed</option>:
+ mount a tmpfs to <filename>/sys/fs/cgroup</filename>,
+ create directories for all hierarchies to which
+ the container is added, bind-mount the hierarchies
+ from the host to the container and make everything
+ read-only except the container's own cgroup. Note
+ that compared to <option>cgroup</option>, where
+ all paths leading up to the container's own cgroup
+ are just simple directories in the underlying
+ tmpfs, here
+ <filename>/sys/fs/cgroup/$hierarchy</filename>
+ will contain the host's full cgroup hierarchy,
+ albeit read-only outside the container's own cgroup.
+ This may leak quite a bit of information into the
+ container.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>cgroup-full:ro</option>: similar to
+ <option>cgroup-full:mixed</option>, but everything
+ will be mounted read-only.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>cgroup-full:rw</option>: similar to
+ <option>cgroup-full:mixed</option>, but everything
+ will be mounted read-write. Note that in this case,
+ the container may escape its own cgroup. (Note also
+ that if the container has CAP_SYS_ADMIN support
+ and can mount the cgroup filesystem itself, it may
+ do so anyway.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <option>cgroup-full</option> (without specifier):
+ defaults to <option>cgroup-full:rw</option> if the
+ container retains the CAP_SYS_ADMIN capability,
+ <option>cgroup-full:mixed</option> otherwise.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Note that if automatic mounting of the cgroup filesystem
+ is enabled, the tmpfs under
+ <filename>/sys/fs/cgroup</filename> will always be
+ mounted read-write (but for the <option>:mixed</option>
+ and <option>:ro</option> cases, the individual
+ hierarchies,
+ <filename>/sys/fs/cgroup/$hierarchy</filename>, will be
+ read-only). This is in order to work around a quirk in
+ Ubuntu's
<citerefentry>
- <refentrytitle>mountall</refentrytitle>
+ <refentrytitle>mountall</refentrytitle>
<manvolnum>8</manvolnum>
</citerefentry>
- command that will cause containers to wait for user
- input at boot if
- <filename>/sys/fs/cgroup</filename> is mounted read-only
- and the container can't remount it read-write due to a
- lack of CAP_SYS_ADMIN.
- </para>
- <para>
- Examples:
- </para>
- <programlisting>
- lxc.mount.auto = proc sys cgroup
- lxc.mount.auto = proc:rw sys:rw cgroup-full:rw
- </programlisting>
- </listitem>
- </varlistentry>
+ command that will cause containers to wait for user
+ input at boot if
+ <filename>/sys/fs/cgroup</filename> is mounted read-only
+ and the container can't remount it read-write due to a
+ lack of CAP_SYS_ADMIN.
+ </para>
+ <para>
+ Examples:
+ </para>
+ <programlisting>
+ lxc.mount.auto = proc sys cgroup
+ lxc.mount.auto = proc:rw sys:rw cgroup-full:rw
+ </programlisting>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Root file system</title>
<para>
- The root file system of the container can be different than that
- of the host system.
+ The root file system of the container can be different than that
+ of the host system.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.rootfs</option>
- </term>
- <listitem>
- <para>
- specify the root file system for the container. It can
- be an image file, a directory or a block device. If not
- specified, the container shares its root file system
- with the host.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.rootfs.mount</option>
- </term>
- <listitem>
- <para>
- where to recursively bind <option>lxc.rootfs</option>
- before pivoting. This is to ensure success of the
- <citerefentry>
- <refentrytitle><command>pivot_root</command></refentrytitle>
- <manvolnum>8</manvolnum>
- </citerefentry>
- syscall. Any directory suffices, the default should
- generally work.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.rootfs.options</option>
- </term>
- <listitem>
- <para>
- extra mount options to use when mounting the rootfs.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- <option>lxc.pivotdir</option>
- </term>
- <listitem>
- <para>
- where to pivot the original root file system under
- <option>lxc.rootfs</option>, specified relatively to
- that. The default is <filename>mnt</filename>.
- It is created if necessary, and also removed after
- unmounting everything from it during container setup.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.rootfs</option>
+ </term>
+ <listitem>
+ <para>
+ specify the root file system for the container. It can
+ be an image file, a directory or a block device. If not
+ specified, the container shares its root file system
+ with the host.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.rootfs.mount</option>
+ </term>
+ <listitem>
+ <para>
+ where to recursively bind <option>lxc.rootfs</option>
+ before pivoting. This is to ensure success of the
+ <citerefentry>
+ <refentrytitle><command>pivot_root</command></refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ syscall. Any directory suffices, the default should
+ generally work.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.rootfs.options</option>
+ </term>
+ <listitem>
+ <para>
+ extra mount options to use when mounting the rootfs.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.pivotdir</option>
+ </term>
+ <listitem>
+ <para>
+ where to pivot the original root file system under
+ <option>lxc.rootfs</option>, specified relatively to
+ that. The default is <filename>mnt</filename>.
+ It is created if necessary, and also removed after
+ unmounting everything from it during container setup.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Control group</title>
<para>
- The control group section contains the configuration for the
- different subsystem. <command>lxc</command> does not check the
- correctness of the subsystem name. This has the disadvantage
- of not detecting configuration errors until the container is
- started, but has the advantage of permitting any future
- subsystem.
+ The control group section contains the configuration for the
+ different subsystem. <command>lxc</command> does not check the
+ correctness of the subsystem name. This has the disadvantage
+ of not detecting configuration errors until the container is
+ started, but has the advantage of permitting any future
+ subsystem.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.cgroup.[subsystem name]</option>
- </term>
- <listitem>
- <para>
- specify the control group value to be set. The
- subsystem name is the literal name of the control group
- subsystem. The permitted names and the syntax of their
- values is not dictated by LXC, instead it depends on the
- features of the Linux kernel running at the time the
- container is started,
- eg. <option>lxc.cgroup.cpuset.cpus</option>
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.cgroup.[subsystem name]</option>
+ </term>
+ <listitem>
+ <para>
+ specify the control group value to be set. The
+ subsystem name is the literal name of the control group
+ subsystem. The permitted names and the syntax of their
+ values is not dictated by LXC, instead it depends on the
+ features of the Linux kernel running at the time the
+ container is started,
+ eg. <option>lxc.cgroup.cpuset.cpus</option>
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Capabilities</title>
<para>
- The capabilities can be dropped in the container if this one
- is run as root.
+ The capabilities can be dropped in the container if this one
+ is run as root.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.cap.drop</option>
- </term>
- <listitem>
- <para>
- Specify the capability to be dropped in the container. A
- single line defining several capabilities with a space
- separation is allowed. The format is the lower case of
- the capability definition without the "CAP_" prefix,
- eg. CAP_SYS_MODULE should be specified as
- sys_module. See
- <citerefentry>
- <refentrytitle><command>capabilities</command></refentrytitle>
- <manvolnum>7</manvolnum>
- </citerefentry>,
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- <option>lxc.cap.keep</option>
- </term>
- <listitem>
- <para>
- Specify the capability to be kept in the container. All other
- capabilities will be dropped.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.cap.drop</option>
+ </term>
+ <listitem>
+ <para>
+ Specify the capability to be dropped in the container. A
+ single line defining several capabilities with a space
+ separation is allowed. The format is the lower case of
+ the capability definition without the "CAP_" prefix,
+ eg. CAP_SYS_MODULE should be specified as
+ sys_module. See
+ <citerefentry>
+ <refentrytitle><command>capabilities</command></refentrytitle>
+ <manvolnum>7</manvolnum>
+ </citerefentry>,
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.cap.keep</option>
+ </term>
+ <listitem>
+ <para>
+ Specify the capability to be kept in the container. All other
+ capabilities will be dropped.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Apparmor profile</title>
<para>
- If lxc was compiled and installed with apparmor support, and the host
- system has apparmor enabled, then the apparmor profile under which the
- container should be run can be specified in the container
- configuration. The default is <command>lxc-container-default</command>.
+ If lxc was compiled and installed with apparmor support, and the host
+ system has apparmor enabled, then the apparmor profile under which the
+ container should be run can be specified in the container
+ configuration. The default is <command>lxc-container-default</command>.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.aa_profile</option>
- </term>
- <listitem>
- <para>
- Specify the apparmor profile under which the container should
- be run. To specify that the container should be unconfined,
- use
- </para>
- <programlisting>lxc.aa_profile = unconfined</programlisting>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.aa_profile</option>
+ </term>
+ <listitem>
+ <para>
+ Specify the apparmor profile under which the container should
+ be run. To specify that the container should be unconfined,
+ use
+ </para>
+ <programlisting>lxc.aa_profile = unconfined</programlisting>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>SELinux context</title>
<para>
- If lxc was compiled and installed with SELinux support, and the host
- system has SELinux enabled, then the SELinux context under which the
- container should be run can be specified in the container
- configuration. The default is <command>unconfined_t</command>,
- which means that lxc will not attempt to change contexts.
- See @DATADIR@/lxc/selinux/lxc.te for an example policy and more
- information.
+ If lxc was compiled and installed with SELinux support, and the host
+ system has SELinux enabled, then the SELinux context under which the
+ container should be run can be specified in the container
+ configuration. The default is <command>unconfined_t</command>,
+ which means that lxc will not attempt to change contexts.
+ See @DATADIR@/lxc/selinux/lxc.te for an example policy and more
+ information.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.se_context</option>
- </term>
- <listitem>
- <para>
- Specify the SELinux context under which the container should
- be run or <command>unconfined_t</command>. For example
- </para>
- <programlisting>lxc.se_context = system_u:system_r:lxc_t:s0:c22</programlisting>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.se_context</option>
+ </term>
+ <listitem>
+ <para>
+ Specify the SELinux context under which the container should
+ be run or <command>unconfined_t</command>. For example
+ </para>
+ <programlisting>lxc.se_context = system_u:system_r:lxc_t:s0:c22</programlisting>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<title>Seccomp configuration</title>
<para>
A container can be started with a reduced set of available
- system calls by loading a seccomp profile at startup. The
- seccomp configuration file must begin with a version number
- on the first line, a policy type on the second line, followed
- by the configuration.
+ system calls by loading a seccomp profile at startup. The
+ seccomp configuration file must begin with a version number
+ on the first line, a policy type on the second line, followed
+ by the configuration.
</para>
<para>
Versions 1 and 2 are currently supported. In version 1, the
- policy is a simple whitelist. The second line therefore must
- read "whitelist", with the rest of the file containing one (numeric)
- sycall number per line. Each syscall number is whitelisted,
- while every unlisted number is blacklisted for use in the container
+ policy is a simple whitelist. The second line therefore must
+ read "whitelist", with the rest of the file containing one (numeric)
+ sycall number per line. Each syscall number is whitelisted,
+ while every unlisted number is blacklisted for use in the container
</para>
<para>
mknod errno 0
</screen>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.seccomp</option>
- </term>
- <listitem>
- <para>
- Specify a file containing the seccomp configuration to
- load before the container starts.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.seccomp</option>
+ </term>
+ <listitem>
+ <para>
+ Specify a file containing the seccomp configuration to
+ load before the container starts.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<title>UID mappings</title>
<para>
A container can be started in a private user namespace with
- user and group id mappings. For instance, you can map userid
- 0 in the container to userid 200000 on the host. The root
- user in the container will be privileged in the container,
- but unprivileged on the host. Normally a system container
- will want a range of ids, so you would map, for instance,
- user and group ids 0 through 20,000 in the container to the
- ids 200,000 through 220,000.
+ user and group id mappings. For instance, you can map userid
+ 0 in the container to userid 200000 on the host. The root
+ user in the container will be privileged in the container,
+ but unprivileged on the host. Normally a system container
+ will want a range of ids, so you would map, for instance,
+ user and group ids 0 through 20,000 in the container to the
+ ids 200,000 through 220,000.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.id_map</option>
- </term>
- <listitem>
- <para>
- Four values must be provided. First a character, either
- 'u', or 'g', to specify whether user or group ids are
- being mapped. Next is the first userid as seen in the
- user namespace of the container. Next is the userid as
- seen on the host. Finally, a range indicating the number
- of consecutive ids to map.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.id_map</option>
+ </term>
+ <listitem>
+ <para>
+ Four values must be provided. First a character, either
+ 'u', or 'g', to specify whether user or group ids are
+ being mapped. Next is the first userid as seen in the
+ user namespace of the container. Next is the userid as
+ seen on the host. Finally, a range indicating the number
+ of consecutive ids to map.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<title>Container hooks</title>
<para>
Container hooks are programs or scripts which can be executed
- at various times in a container's lifetime.
+ at various times in a container's lifetime.
</para>
<para>
When a container hook is executed, information is passed both
- as command line arguments and through environment variables.
- The arguments are:
- <itemizedlist>
- <listitem><para> Container name. </para></listitem>
- <listitem><para> Section (always 'lxc'). </para></listitem>
- <listitem><para> The hook type (i.e. 'clone' or 'pre-mount'). </para></listitem>
- <listitem><para> Additional arguments In the
- case of the clone hook, any extra arguments passed to
- lxc-clone will appear as further arguments to the hook. </para></listitem>
- </itemizedlist>
- The following environment variables are set:
- <itemizedlist>
- <listitem><para> LXC_NAME: is the container's name. </para></listitem>
- <listitem><para> LXC_ROOTFS_MOUNT: the path to the mounted root filesystem. </para></listitem>
- <listitem><para> LXC_CONFIG_FILE: the path to the container configuration file. </para></listitem>
- <listitem><para> LXC_SRC_NAME: in the case of the clone hook, this is the original container's name. </para></listitem>
- <listitem><para> LXC_ROOTFS_PATH: this is the lxc.rootfs entry for the container. Note this is likely not where the mounted rootfs is to be found, use LXC_ROOTFS_MOUNT for that. </para></listitem>
- </itemizedlist>
+ as command line arguments and through environment variables.
+ The arguments are:
+ <itemizedlist>
+ <listitem><para> Container name. </para></listitem>
+ <listitem><para> Section (always 'lxc'). </para></listitem>
+ <listitem><para> The hook type (i.e. 'clone' or 'pre-mount'). </para></listitem>
+ <listitem><para> Additional arguments In the
+ case of the clone hook, any extra arguments passed to
+ lxc-clone will appear as further arguments to the hook. </para></listitem>
+ </itemizedlist>
+ The following environment variables are set:
+ <itemizedlist>
+ <listitem><para> LXC_NAME: is the container's name. </para></listitem>
+ <listitem><para> LXC_ROOTFS_MOUNT: the path to the mounted root filesystem. </para></listitem>
+ <listitem><para> LXC_CONFIG_FILE: the path to the container configuration file. </para></listitem>
+ <listitem><para> LXC_SRC_NAME: in the case of the clone hook, this is the original container's name. </para></listitem>
+ <listitem><para> LXC_ROOTFS_PATH: this is the lxc.rootfs entry for the container. Note this is likely not where the mounted rootfs is to be found, use LXC_ROOTFS_MOUNT for that. </para></listitem>
+ </itemizedlist>
</para>
<para>
Standard output from the hooks is logged at debug level.
hook redirecting its standard error to standard output.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.hook.pre-start</option>
- </term>
- <listitem>
- <para>
- A hook to be run in the host's namespace before the
- container ttys, consoles, or mounts are up.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.hook.pre-start</option>
+ </term>
+ <listitem>
+ <para>
+ A hook to be run in the host's namespace before the
+ container ttys, consoles, or mounts are up.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.hook.pre-mount</option>
- </term>
- <listitem>
- <para>
- A hook to be run in the container's fs namespace but before
- the rootfs has been set up. This allows for manipulation
- of the rootfs, i.e. to mount an encrypted filesystem. Mounts
- done in this hook will not be reflected on the host (apart from
- mounts propagation), so they will be automatically cleaned up
- when the container shuts down.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.hook.pre-mount</option>
+ </term>
+ <listitem>
+ <para>
+ A hook to be run in the container's fs namespace but before
+ the rootfs has been set up. This allows for manipulation
+ of the rootfs, i.e. to mount an encrypted filesystem. Mounts
+ done in this hook will not be reflected on the host (apart from
+ mounts propagation), so they will be automatically cleaned up
+ when the container shuts down.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.hook.mount</option>
- </term>
- <listitem>
- <para>
- A hook to be run in the container's namespace after
- mounting has been done, but before the pivot_root.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.hook.mount</option>
+ </term>
+ <listitem>
+ <para>
+ A hook to be run in the container's namespace after
+ mounting has been done, but before the pivot_root.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.hook.autodev</option>
- </term>
- <listitem>
- <para>
- A hook to be run in the container's namespace after
- mounting has been done and after any mount hooks have
- run, but before the pivot_root, if
- <option>lxc.autodev</option> == 1.
- The purpose of this hook is to assist in populating the
- /dev directory of the container when using the autodev
- option for systemd based containers. The container's /dev
- directory is relative to the
- ${<option>LXC_ROOTFS_MOUNT</option>} environment
- variable available when the hook is run.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.hook.autodev</option>
+ </term>
+ <listitem>
+ <para>
+ A hook to be run in the container's namespace after
+ mounting has been done and after any mount hooks have
+ run, but before the pivot_root, if
+ <option>lxc.autodev</option> == 1.
+ The purpose of this hook is to assist in populating the
+ /dev directory of the container when using the autodev
+ option for systemd based containers. The container's /dev
+ directory is relative to the
+ ${<option>LXC_ROOTFS_MOUNT</option>} environment
+ variable available when the hook is run.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.hook.start</option>
- </term>
- <listitem>
- <para>
- A hook to be run in the container's namespace immediately
- before executing the container's init. This requires the
- program to be available in the container.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.hook.start</option>
+ </term>
+ <listitem>
+ <para>
+ A hook to be run in the container's namespace immediately
+ before executing the container's init. This requires the
+ program to be available in the container.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.hook.post-stop</option>
- </term>
- <listitem>
- <para>
- A hook to be run in the host's namespace after the
- container has been shut down.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.hook.post-stop</option>
+ </term>
+ <listitem>
+ <para>
+ A hook to be run in the host's namespace after the
+ container has been shut down.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.hook.clone</option>
- </term>
- <listitem>
- <para>
- A hook to be run when the container is cloned to a new one.
- See <citerefentry><refentrytitle><command>lxc-clone</command></refentrytitle>
- <manvolnum>1</manvolnum></citerefentry> for more information.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.hook.clone</option>
+ </term>
+ <listitem>
+ <para>
+ A hook to be run when the container is cloned to a new one.
+ See <citerefentry><refentrytitle><command>lxc-clone</command></refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry> for more information.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
and, as such, not valid during the <option>lxc.hook.start</option> hook.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>LXC_NAME</option>
- </term>
- <listitem>
- <para>
- The LXC name of the container. Useful for logging messages
- in common log environments. [<option>-n</option>]
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>LXC_NAME</option>
+ </term>
+ <listitem>
+ <para>
+ The LXC name of the container. Useful for logging messages
+ in common log environments. [<option>-n</option>]
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<variablelist>
- <varlistentry>
- <term>
- <option>LXC_CONFIG_FILE</option>
- </term>
- <listitem>
- <para>
- Host relative path to the container configuration file. This
- gives the container to reference the original, top level,
- configuration file for the container in order to locate any
- additional configuration information not otherwise made
- available. [<option>-f</option>]
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>LXC_CONFIG_FILE</option>
+ </term>
+ <listitem>
+ <para>
+ Host relative path to the container configuration file. This
+ gives the container to reference the original, top level,
+ configuration file for the container in order to locate any
+ additional configuration information not otherwise made
+ available. [<option>-f</option>]
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<variablelist>
- <varlistentry>
- <term>
- <option>LXC_CONSOLE</option>
- </term>
- <listitem>
- <para>
- The path to the console output of the container if not NULL.
- [<option>-c</option>] [<option>lxc.console</option>]
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>LXC_CONSOLE</option>
+ </term>
+ <listitem>
+ <para>
+ The path to the console output of the container if not NULL.
+ [<option>-c</option>] [<option>lxc.console</option>]
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<variablelist>
- <varlistentry>
- <term>
- <option>LXC_CONSOLE_LOGPATH</option>
- </term>
- <listitem>
- <para>
- The path to the console log output of the container if not NULL.
- [<option>-L</option>]
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>LXC_CONSOLE_LOGPATH</option>
+ </term>
+ <listitem>
+ <para>
+ The path to the console log output of the container if not NULL.
+ [<option>-L</option>]
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<variablelist>
- <varlistentry>
- <term>
- <option>LXC_ROOTFS_MOUNT</option>
- </term>
- <listitem>
- <para>
- The mount location to which the container is initially bound.
- This will be the host relative path to the container rootfs
- for the container instance being started and is where changes
- should be made for that instance.
- [<option>lxc.rootfs.mount</option>]
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>LXC_ROOTFS_MOUNT</option>
+ </term>
+ <listitem>
+ <para>
+ The mount location to which the container is initially bound.
+ This will be the host relative path to the container rootfs
+ for the container instance being started and is where changes
+ should be made for that instance.
+ [<option>lxc.rootfs.mount</option>]
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<variablelist>
- <varlistentry>
- <term>
- <option>LXC_ROOTFS_PATH</option>
- </term>
- <listitem>
- <para>
- The host relative path to the container root which has been
- mounted to the rootfs.mount location.
- [<option>lxc.rootfs</option>]
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>LXC_ROOTFS_PATH</option>
+ </term>
+ <listitem>
+ <para>
+ The host relative path to the container root which has been
+ mounted to the rootfs.mount location.
+ [<option>lxc.rootfs</option>]
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
command line options to <command>lxc-start</command>.
</para>
<variablelist>
- <varlistentry>
- <term>
- <option>lxc.loglevel</option>
- </term>
- <listitem>
- <para>
- The level at which to log. The log level is an integer in
- the range of 0..8 inclusive, where a lower number means more
- verbose debugging. In particular 0 = trace, 1 = debug, 2 =
- info, 3 = notice, 4 = warn, 5 = error, 6 = critical, 7 =
- alert, and 8 = fatal. If unspecified, the level defaults
- to 5 (error), so that only errors and above are logged.
- </para>
- <para>
- Note that when a script (such as either a hook script or a
- network interface up or down script) is called, the script's
- standard output is logged at level 1, debug.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- <option>lxc.logfile</option>
- </term>
- <listitem>
- <para>
- The file to which logging info should be written.
- </para>
- </listitem>
- </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.loglevel</option>
+ </term>
+ <listitem>
+ <para>
+ The level at which to log. The log level is an integer in
+ the range of 0..8 inclusive, where a lower number means more
+ verbose debugging. In particular 0 = trace, 1 = debug, 2 =
+ info, 3 = notice, 4 = warn, 5 = error, 6 = critical, 7 =
+ alert, and 8 = fatal. If unspecified, the level defaults
+ to 5 (error), so that only errors and above are logged.
+ </para>
+ <para>
+ Note that when a script (such as either a hook script or a
+ network interface up or down script) is called, the script's
+ standard output is logged at level 1, debug.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.logfile</option>
+ </term>
+ <listitem>
+ <para>
+ The file to which logging info should be written.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect1>
<title>Examples</title>
<para>
- In addition to the few examples given below, you will find
- some other examples of configuration file in @DOCDIR@/examples
+ In addition to the few examples given below, you will find
+ some other examples of configuration file in @DOCDIR@/examples
</para>
<refsect2>
<title>Network</title>
<para>This configuration sets up a container to use a veth pair
- device with one side plugged to a bridge br0 (which has been
- configured before on the system by the administrator). The
- virtual network device visible in the container is renamed to
- eth0.</para>
+ device with one side plugged to a bridge br0 (which has been
+ configured before on the system by the administrator). The
+ virtual network device visible in the container is renamed to
+ eth0.</para>
<programlisting>
- lxc.utsname = myhostname
- lxc.network.type = veth
- lxc.network.flags = up
- lxc.network.link = br0
- lxc.network.name = eth0
- lxc.network.hwaddr = 4a:49:43:49:79:bf
- lxc.network.ipv4 = 10.2.3.5/24 10.2.3.255
- lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3597
+ lxc.utsname = myhostname
+ lxc.network.type = veth
+ lxc.network.flags = up
+ lxc.network.link = br0
+ lxc.network.name = eth0
+ lxc.network.hwaddr = 4a:49:43:49:79:bf
+ lxc.network.ipv4 = 10.2.3.5/24 10.2.3.255
+ lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3597
</programlisting>
</refsect2>
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.id_map = u 0 100000 10000
+ lxc.id_map = g 0 100000 10000
</programlisting>
</refsect2>
cpus.share prioritize the control group, devices.allow makes
usable the specified devices.</para>
<programlisting>
- lxc.cgroup.cpuset.cpus = 0,1
- lxc.cgroup.cpu.shares = 1234
- lxc.cgroup.devices.deny = a
- lxc.cgroup.devices.allow = c 1:3 rw
- lxc.cgroup.devices.allow = b 8:0 rw
+ lxc.cgroup.cpuset.cpus = 0,1
+ lxc.cgroup.cpu.shares = 1234
+ lxc.cgroup.devices.deny = a
+ lxc.cgroup.devices.allow = c 1:3 rw
+ lxc.cgroup.devices.allow = b 8:0 rw
</programlisting>
</refsect2>
network stack, using the control groups, setting a new hostname,
mounting some locations and a changing root file system.</para>
<programlisting>
- lxc.utsname = complex
- lxc.network.type = veth
- lxc.network.flags = up
- lxc.network.link = br0
- lxc.network.hwaddr = 4a:49:43:49:79:bf
- lxc.network.ipv4 = 10.2.3.5/24 10.2.3.255
- lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3597
- lxc.network.ipv6 = 2003:db8:1:0:214:5432:feab:3588
- lxc.network.type = macvlan
- lxc.network.flags = up
- lxc.network.link = eth0
- lxc.network.hwaddr = 4a:49:43:49:79:bd
- lxc.network.ipv4 = 10.2.3.4/24
- lxc.network.ipv4 = 192.168.10.125/24
- lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3596
- lxc.network.type = phys
- lxc.network.flags = up
- lxc.network.link = dummy0
- lxc.network.hwaddr = 4a:49:43:49:79:ff
- lxc.network.ipv4 = 10.2.3.6/24
- lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3297
- lxc.cgroup.cpuset.cpus = 0,1
- lxc.cgroup.cpu.shares = 1234
- lxc.cgroup.devices.deny = a
- lxc.cgroup.devices.allow = c 1:3 rw
- lxc.cgroup.devices.allow = b 8:0 rw
- lxc.mount = /etc/fstab.complex
- lxc.mount.entry = /lib /root/myrootfs/lib none ro,bind 0 0
- lxc.rootfs = /mnt/rootfs.complex
- lxc.cap.drop = sys_module mknod setuid net_raw
- lxc.cap.drop = mac_override
+ lxc.utsname = complex
+ lxc.network.type = veth
+ lxc.network.flags = up
+ lxc.network.link = br0
+ lxc.network.hwaddr = 4a:49:43:49:79:bf
+ lxc.network.ipv4 = 10.2.3.5/24 10.2.3.255
+ lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3597
+ lxc.network.ipv6 = 2003:db8:1:0:214:5432:feab:3588
+ lxc.network.type = macvlan
+ lxc.network.flags = up
+ lxc.network.link = eth0
+ lxc.network.hwaddr = 4a:49:43:49:79:bd
+ lxc.network.ipv4 = 10.2.3.4/24
+ lxc.network.ipv4 = 192.168.10.125/24
+ lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3596
+ lxc.network.type = phys
+ lxc.network.flags = up
+ lxc.network.link = dummy0
+ lxc.network.hwaddr = 4a:49:43:49:79:ff
+ lxc.network.ipv4 = 10.2.3.6/24
+ lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3297
+ lxc.cgroup.cpuset.cpus = 0,1
+ lxc.cgroup.cpu.shares = 1234
+ lxc.cgroup.devices.deny = a
+ lxc.cgroup.devices.allow = c 1:3 rw
+ lxc.cgroup.devices.allow = b 8:0 rw
+ lxc.mount = /etc/fstab.complex
+ lxc.mount.entry = /lib /root/myrootfs/lib none ro,bind 0 0
+ lxc.rootfs = /mnt/rootfs.complex
+ lxc.cap.drop = sys_module mknod setuid net_raw
+ lxc.cap.drop = mac_override
</programlisting>
</refsect2>
<title>See Also</title>
<simpara>
<citerefentry>
- <refentrytitle><command>chroot</command></refentrytitle>
- <manvolnum>1</manvolnum>
+ <refentrytitle><command>chroot</command></refentrytitle>
+ <manvolnum>1</manvolnum>
</citerefentry>,
<citerefentry>
- <refentrytitle><command>pivot_root</command></refentrytitle>
- <manvolnum>8</manvolnum>
+ <refentrytitle><command>pivot_root</command></refentrytitle>
+ <manvolnum>8</manvolnum>
</citerefentry>,
<citerefentry>
- <refentrytitle><filename>fstab</filename></refentrytitle>
- <manvolnum>5</manvolnum>
+ <refentrytitle><filename>fstab</filename></refentrytitle>
+ <manvolnum>5</manvolnum>
</citerefentry>,
<citerefentry>
- <refentrytitle><filename>capabilities</filename></refentrytitle>
- <manvolnum>7</manvolnum>
+ <refentrytitle><filename>capabilities</filename></refentrytitle>
+ <manvolnum>7</manvolnum>
</citerefentry>
</simpara>
</refsect1>
<para>
- The kernel version >= 2.6.27 shipped with the distros, will
+ 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.
- With the kernel 2.6.29, <command>lxc</command> is fully
- functional.
-
The helper script <command>lxc-checkconfig</command> will give
you information about your kernel configuration.
</para>
<para>
- Before using the <command>lxc</command>, your system should be
- configured with the file capabilities, otherwise you will need
- to run the <command>lxc</command> commands as root.
- </para>
-
- <para>
The control group can be mounted anywhere, eg:
<command>mount -t cgroup cgroup /cgroup</command>.
- If you want to dedicate a specific cgroup mount point
- for <command>lxc</command>, that is to have different cgroups
- mounted at different places with different options but
- let <command>lxc</command> to use one location, you can bind
- the mount point with the <option>lxc</option> name, eg:
- <command>mount -t cgroup lxc /cgroup4lxc</command> or
- <command>mount -t cgroup -ons,cpuset,freezer,devices
- lxc /cgroup4lxc</command>
+ It is however recommended to use cgmanager, cgroup-lite or systemd
+ to mount the cgroup hierarchy under /sys/fs/cgroup.
</para>
%endif
Name: lxc
-Version: 1.0.6
+Version: 1.0.7
Release: %{?beta_rel:0.1.%{beta_rel}}%{?!beta_rel:%{norm_rel}}%{?dist}
URL: http://linuxcontainers.org
Source: http://linuxcontainers.org/downloads/%{name}-%{version}%{?beta_dot}.tar.gz
%changelog
* Tue Oct 22 2013 Dwight Engen <dwight.engen@oracle.com> - 1.0.0-0.1.alpha2
- fix some rpmlint warnings/errors
-- split lua bits into seperate package
+- split lua bits into separate package
* Mon Sep 10 2012 Dwight Engen <dwight.engen@oracle.com> - 0.8.0
- fix lxc-init moved to libexec
%changelog
* Tue Oct 22 2013 Dwight Engen <dwight.engen@oracle.com> - 1.0.0-0.1.alpha2
- fix some rpmlint warnings/errors
-- split lua bits into seperate package
+- split lua bits into separate package
* Mon Sep 10 2012 Dwight Engen <dwight.engen@oracle.com> - 0.8.0
- fix lxc-init moved to libexec
* number of C programs out there that just assume
* that getenv("PATH") is never NULL and then die a
* painful segfault death. */
- if (!path_kept) {
-#ifdef HAVE_CONFSTR
- size_t n;
- char *path_env;
-
- n = confstr(_CS_PATH, NULL, 0);
- path_env = malloc(n);
- if (path_env) {
- confstr(_CS_PATH, path_env, n);
- setenv("PATH", path_env, 1);
- free(path_env);
- }
- /* don't error out, this is just an extra service */
-#else
+ if (!path_kept)
setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
-#endif
- }
}
if (putenv("container=lxc")) {
if (pid) {
pid_t to_cleanup_pid = pid;
- /* inital thread, we close the socket that is for the
+ /* initial thread, we close the socket that is for the
* subprocesses
*/
close(ipc_sockets[1]);
}
/* ignore SIGKILL (CTRL-C) and SIGQUIT (CTRL-\) - issue #313 */
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
+ if (options->stdin_fd == 0) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ }
/* reap intermediate process */
ret = wait_for_pid(pid);
*/
long personality;
- /*! Inital current directory, use \c NULL to use cwd.
+ /*! 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.
*/
/*
* this is all just a first shot for experiment. If we go this route, much
- * shoudl change. bdev should be a directory with per-bdev file. Things which
+ * 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
*/
goto out;
}
// make sure the directory doesn't already exist
- if (rmdir(newfull) < 0 && errno != -ENOENT) {
+ if (rmdir(newfull) < 0 && errno != ENOENT) {
SYSERROR("Error removing empty new rootfs");
goto out;
}
return userns_exec_1(conf, btrfs_snapshot_wrapper, &sdata);
}
- if (rmdir(new->dest) < 0 && errno != -ENOENT) {
+ if (rmdir(new->dest) < 0 && errno != ENOENT) {
SYSERROR("removing %s", new->dest);
return -1;
}
static int overlayfs_mount(struct bdev *bdev)
{
char *options, *dup, *lower, *upper;
- int len;
+ char *options_work, *work, *lastslash;
+ int lastslashidx;
+ int len, len2;
unsigned long mntflags;
char *mntdata;
- int ret;
+ int ret, ret2;
if (strcmp(bdev->type, "overlayfs"))
return -22;
*upper = '\0';
upper++;
+ // 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;
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) {
+ if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) {
free(mntdata);
return -1;
}
+ // mount without workdir option for overlayfs before v21
ret = mount(lower, bdev->dest, "overlayfs", MS_MGC_VAL | mntflags, options);
- if (ret < 0)
- SYSERROR("overlayfs: error mounting %s onto %s options %s",
+ if (ret < 0) {
+ INFO("overlayfs: error mounting %s onto %s options %s. retry with workdir",
lower, bdev->dest, options);
+
+ // retry with workdir option for overlayfs v22 and higher
+ ret = mount(lower, bdev->dest, "overlayfs", MS_MGC_VAL | mntflags, options_work);
+ if (ret < 0)
+ SYSERROR("overlayfs: error mounting %s onto %s options %s",
+ lower, bdev->dest, options_work);
+ else
+ INFO("overlayfs: mounted %s onto %s options %s",
+ lower, bdev->dest, options_work);
+ }
else
INFO("overlayfs: mounted %s onto %s options %s",
lower, bdev->dest, options);
WARN("Failed to update ownership of %s", new->dest);
if (strcmp(orig->type, "dir") == 0) {
- char *delta;
- int ret, len;
+ 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
- delta = strdup(new->dest);
- if (!delta) {
- return -1;
- }
- if (strlen(delta) < 6) {
- free(delta);
+ lastslash = strrchr(new->dest, '/');
+ if (!lastslash)
return -22;
- }
- strcpy(&delta[strlen(delta)-6], "delta0");
+ 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);
if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
WARN("Failed to update ownership of %s", delta);
+ // make workdir for overlayfs.v22 or higher
+ // workdir is /var/lib/lxc/c2/olwork
+ // it is used to prepare files before atomically swithing with destination,
+ // and needs to be on the same filesystem as upperdir,
+ // so it's OK for it to be empty.
+ work = malloc(lastslashidx + 7);
+ if (!work)
+ return -1;
+ strncpy(work, new->dest, lastslashidx+1);
+ strcpy(work+lastslashidx, "olwork");
+ if (mkdir(work, 0755) < 0) {
+ SYSERROR("error: mkdir %s", work);
+ free(work);
+ return -1;
+ }
+ if (am_unpriv() && chown_mapped_root(work, conf) < 0)
+ WARN("Failed to update ownership of %s", work);
+ free(work);
+
// the src will be 'overlayfs:lowerdir:upperdir'
len = strlen(delta) + strlen(orig->src) + 12;
new->src = malloc(len);
// 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;
+ char *osrc, *odelta, *nsrc, *ndelta, *work;
+ char *lastslash;
+ int len, ret, lastslashidx;
if (!(osrc = strdup(orig->src)))
return -22;
nsrc = index(osrc, ':') + 1;
free(osrc);
return -ENOMEM;
}
- if ((ret = mkdir(ndelta, 0755)) < 0) {
+ if ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
SYSERROR("error: mkdir %s", ndelta);
free(osrc);
free(ndelta);
}
if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
WARN("Failed to update ownership of %s", ndelta);
+
+ // make workdir for overlayfs.v22 or higher
+ // for details, see above.
+ lastslash = strrchr(ndelta, '/');
+ if (!lastslash)
+ return -1;
+ lastslash++;
+ lastslashidx = lastslash - ndelta;
+
+ work = malloc(lastslashidx + 7);
+ if (!work)
+ return -1;
+ strncpy(work, ndelta, lastslashidx+1);
+ strcpy(work+lastslashidx, "olwork");
+ if ((mkdir(work, 0755) < 0) && errno != EEXIST) {
+ SYSERROR("error: mkdir %s", work);
+ free(work);
+ return -1;
+ }
+ if (am_unpriv() && chown_mapped_root(work, conf) < 0)
+ WARN("Failed to update ownership of %s", work);
+ free(work);
+
struct rsync_data_char rdata;
rdata.src = odelta;
rdata.dest = ndelta;
return -1;
if (strcmp(orig->type, "dir") == 0) {
- char *delta;
- int ret, len;
+ char *delta, *lastslash;
+ int ret, len, lastslashidx;
// if we have /var/lib/lxc/c2/rootfs, then delta will be
// /var/lib/lxc/c2/delta0
- delta = strdup(new->dest);
- if (!delta) {
- return -1;
- }
- if (strlen(delta) < 6) {
- free(delta);
+ lastslash = strrchr(new->dest, '/');
+ if (!lastslash)
return -22;
- }
- strcpy(&delta[strlen(delta)-6], "delta0");
+ 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);
const char *oldname = c0->name;
const char *oldpath = c0->config_path;
struct rsync_data data;
+ char *rootfs;
/* 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
bdev_put(orig);
return NULL;
}
- ret = snprintf(orig->dest, MAXPATHLEN, "%s/%s/rootfs", oldpath, oldname);
+ rootfs = strrchr(orig->src, '/');
+ if (!rootfs) {
+ ERROR("invalid rootfs path");
+ bdev_put(orig);
+ return NULL;
+ }
+ rootfs++;
+ ret = snprintf(orig->dest, MAXPATHLEN, "%s/%s/%s", oldpath, oldname, rootfs);
if (ret < 0 || ret >= MAXPATHLEN) {
ERROR("rootfs path too long");
bdev_put(orig);
/*
* bdev_create:
* Create a backing store for a container.
- * If successfull, return a struct bdev *, with the bdev mounted and ready
+ * 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)
continue;
cleanup_from_error:
- /* called if an error occured in the loop, so we
+ /* called if an error occurred in the loop, so we
* do some additional cleanup here
*/
saved_errno = errno;
if (!d->name)
goto err1;
- /* if we are running as root, use system cgroup pattern, otherwise
- * just create a cgroup under the current one. But also fall back to
- * that if for some reason reading the configuration fails and no
- * default value is available
- */
- if (geteuid() == 0)
- d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
- if (!d->cgroup_pattern)
- d->cgroup_pattern = "%n";
+ d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
d->meta = lxc_cgroup_load_meta();
if (!d->meta) {
return true;
}
-static inline bool cgm_supports_multiple_controllers(void)
+static bool cgm_supports_multiple_controllers;
+/*
+ * if cgm_all_controllers_same is true, then cgm_supports_multiple_controllers
+ * is true
+ */
+static bool cgm_all_controllers_same;
+
+/*
+ * Check whether we can use "all" when talking to cgmanager.
+ * We check two things:
+ * 1. whether cgmanager is new enough to support this.
+ * 2. whether the task we are interested in is in the same
+ * cgroup for all controllers.
+ * In cgm_init (before an lxc-start) we care about our own
+ * cgroup. In cgm_attach, we care about the target task's
+ * cgroup.
+ */
+static void check_supports_multiple_controllers(pid_t pid)
{
- return api_version >= CGM_SUPPORTS_MULT_CONTROLLERS;
+ FILE *f;
+ char *line = NULL, *prevpath = NULL;
+ size_t sz = 0;
+ char path[100];
+
+ cgm_supports_multiple_controllers = false;
+ cgm_all_controllers_same = false;
+
+ if (api_version < CGM_SUPPORTS_MULT_CONTROLLERS) {
+ cgm_supports_multiple_controllers = false;
+ return;
+ }
+
+ cgm_supports_multiple_controllers = true;
+
+ if (pid == -1)
+ sprintf(path, "/proc/self/cgroup");
+ else
+ sprintf(path, "/proc/%d/cgroup", pid);
+ f = fopen(path, "r");
+ if (!f)
+ return;
+
+ cgm_all_controllers_same = true;
+
+ while (getline(&line, &sz, f) != -1) {
+ /* file format: hierarchy:subsystems:group */
+ char *colon;
+ if (!line[0])
+ continue;
+
+ colon = strchr(line, ':');
+ if (!colon)
+ continue;
+ colon = strchr(colon+1, ':');
+ if (!colon)
+ continue;
+ colon++;
+ if (!prevpath) {
+ prevpath = alloca(strlen(colon)+1);
+ strcpy(prevpath, colon);
+ continue;
+ }
+ if (strcmp(prevpath, colon) != 0) {
+ cgm_all_controllers_same = false;
+ fclose(f);
+ return;
+ }
+ }
+ fclose(f);
}
static int send_creds(int sock, int rpid, int ruid, int rgid)
char **slist = subsystems;
int i;
- if (cgm_supports_multiple_controllers())
+ if (cgm_all_controllers_same)
slist = subsystems_inone;
for (i = 0; slist[i]; i++) {
}
destuid = get_ns_uid(arg->origuid);
- if (cgm_supports_multiple_controllers())
+ if (cgm_supports_multiple_controllers)
slist = subsystems_inone;
for (i = 0; slist[i]; i++) {
* This can't be done in the child namespace because it only group-owns
* the cgroup
*/
- if (cgm_supports_multiple_controllers())
+ if (cgm_supports_multiple_controllers)
slist = subsystems_inone;
for (i = 0; slist[i]; i++) {
ERROR("Error connecting to cgroup manager");
return NULL;
}
+
+ check_supports_multiple_controllers(-1);
+
d = malloc(sizeof(*d));
if (!d) {
cgm_dbus_disconnect();
goto err1;
}
- /* if we are running as root, use system cgroup pattern, otherwise
- * just create a cgroup under the current one. But also fall back to
- * that if for some reason reading the configuration fails and no
- * default value is available
- */
- if (geteuid() == 0)
- d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
- if (!d->cgroup_pattern)
- d->cgroup_pattern = "%n";
+ d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
+
// cgm_create immediately gets called so keep the connection open
return d;
return;
}
- if (cgm_supports_multiple_controllers())
+ if (cgm_supports_multiple_controllers)
slist = subsystems_inone;
for (i = 0; slist[i]; i++)
cgm_remove_cgroup(slist[i], d->cgroup_path);
int i;
char **slist = subsystems;
- if (cgm_supports_multiple_controllers())
+ if (cgm_supports_multiple_controllers)
slist = subsystems_inone;
for (i = 0; slist[i]; i++)
cgm_remove_cgroup(slist[i], path);
}
existed = 0;
- if (cgm_supports_multiple_controllers())
+ if (cgm_supports_multiple_controllers)
slist = subsystems_inone;
for (i = 0; slist[i]; i++) {
return true;
}
-/* Internal helper, must be called with cgmanager dbus socket open */
-static bool do_cgm_enter(pid_t pid, const char *cgroup_path, bool abs)
-{
- char **slist = subsystems;
- int i;
-
- if (cgm_supports_multiple_controllers())
- slist = subsystems_inone;
-
- for (i = 0; slist[i]; i++) {
- if (!lxc_cgmanager_enter(pid, slist[i], cgroup_path, abs))
- return false;
- }
- return true;
-}
-
static inline bool cgm_enter(void *hdata, pid_t pid)
{
struct cgm_data *d = hdata;
+ char **slist = subsystems;
bool ret = false;
+ int i;
+
+ if (!d || !d->cgroup_path)
+ return false;
if (!cgm_dbus_connect()) {
ERROR("Error connecting to cgroup manager");
return false;
}
- if (!d || !d->cgroup_path)
- goto out;
- if (do_cgm_enter(pid, d->cgroup_path, false))
- ret = true;
+
+ if (cgm_all_controllers_same)
+ slist = subsystems_inone;
+
+ for (i = 0; slist[i]; i++) {
+ if (!lxc_cgmanager_enter(pid, slist[i], d->cgroup_path, false))
+ goto out;
+ }
+ ret = true;
out:
cgm_dbus_disconnect();
return ret;
WARN("Failed to warn cgm_get of error; parent may hang");
exit(1);
}
- cgroup = try_get_abs_cgroup(name, lxcpath, subsystems[0]);
+ cgroup = try_get_abs_cgroup(name, lxcpath, controller);
if (!cgroup) {
cgm_dbus_disconnect();
ret = write(outp, &len, sizeof(len));
WARN("Failed to warn cgm_set of error; parent may hang");
exit(1);
}
- cgroup = try_get_abs_cgroup(name, lxcpath, subsystems[0]);
+ cgroup = try_get_abs_cgroup(name, lxcpath, controller);
if (!cgroup) {
cgm_dbus_disconnect();
ret = write(outp, &retval, sizeof(retval));
*/
static bool cgm_attach(const char *name, const char *lxcpath, pid_t pid)
{
- bool pass;
+ bool pass = true;
char *cgroup = NULL;
+ char **slist = subsystems;
+ int i;
if (!cgm_dbus_connect()) {
ERROR("Error connecting to cgroup manager");
return false;
}
- // cgm_create makes sure that we have the same cgroup name for all
- // subsystems, so since this is a slow command over the cmd socket,
- // just get the cgroup name for the first one.
- cgroup = try_get_abs_cgroup(name, lxcpath, subsystems[0]);
- if (!cgroup) {
- ERROR("Failed to get cgroup for controller %s", subsystems[0]);
- cgm_dbus_disconnect();
- return false;
- }
- pass = do_cgm_enter(pid, cgroup, abs_cgroup_supported());
+ check_supports_multiple_controllers(pid);
+
+ if (cgm_all_controllers_same)
+ slist = subsystems_inone;
+
+ for (i = 0; slist[i]; i++) {
+ if (slist == subsystems_inone)
+ cgroup = try_get_abs_cgroup(name, lxcpath, subsystems[0]);
+ else
+ cgroup = try_get_abs_cgroup(name, lxcpath, slist[i]);
+ if (!cgroup) {
+ ERROR("Failed to get cgroup for controller %s", slist[i]);
+ cgm_dbus_disconnect();
+ return false;
+ }
+
+ if (!lxc_cgmanager_enter(pid, slist[i], cgroup, abs_cgroup_supported())) {
+ pass = false;
+ break;
+ }
+
+ }
cgm_dbus_disconnect();
if (!pass)
ERROR("Failed to enter group %s", cgroup);
* Each command is transactional, the clients send a request to
* the server and the server answers the request with a message
* giving the request's status (zero or a negative errno value).
- * Both the request and response may contain addtional data.
+ * Both the request and response may contain additional data.
*
* Each command is wrapped in a ancillary message in order to pass
* a credential making possible to the server to check if the client
#define __S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask))
#endif
+#ifndef MS_PRIVATE
+#define MS_PRIVATE (1<<18)
+#endif
+
char *lxchook_names[NUM_LXC_HOOKS] = {
"pre-start", "pre-mount", "mount", "autodev", "start", "post-stop", "clone" };
-typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
+typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
struct mount_opt {
char *name;
/* 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 instanciate_veth(struct lxc_handler *, struct lxc_netdev *);
-static int instanciate_macvlan(struct lxc_handler *, struct lxc_netdev *);
-static int instanciate_vlan(struct lxc_handler *, struct lxc_netdev *);
-static int instanciate_phys(struct lxc_handler *, struct lxc_netdev *);
-static int instanciate_empty(struct lxc_handler *, struct lxc_netdev *);
-static int instanciate_none(struct lxc_handler *, struct lxc_netdev *);
-
-static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
- [LXC_NET_VETH] = instanciate_veth,
- [LXC_NET_MACVLAN] = instanciate_macvlan,
- [LXC_NET_VLAN] = instanciate_vlan,
- [LXC_NET_PHYS] = instanciate_phys,
- [LXC_NET_EMPTY] = instanciate_empty,
- [LXC_NET_NONE] = instanciate_none,
+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_empty(struct lxc_handler *, struct lxc_netdev *);
static int shutdown_none(struct lxc_handler *, struct lxc_netdev *);
-static instanciate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
+static instantiate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
[LXC_NET_VETH] = shutdown_veth,
[LXC_NET_MACVLAN] = shutdown_macvlan,
[LXC_NET_VLAN] = shutdown_vlan,
* Get rid of old links and directoriess
* This could be either a symlink and we remove it,
* or an empty directory and we remove it,
- * or non-existant and we don't care,
+ * or non-existent and we don't care,
* or a non-empty directory, and we will then emit an error
* but we will not fail out the process.
*/
return 0;
}
-/*
- * I'll forgive you for asking whether all of this is needed :) The
- * answer is yes.
- * pivot_root will fail if the new root, the put_old dir, or the parent
- * of current->fs->root are MS_SHARED. (parent of current->fs_root may
- * or may not be current->fs_root - if we assumed it always was, we could
- * just mount --make-rslave /). So,
- * 1. mount a tiny tmpfs to be parent of current->fs->root.
- * 2. make that MS_SLAVE
- * 3. make a 'root' directory under that
- * 4. mount --rbind / under the $tinyroot/root.
- * 5. make that rslave
- * 6. chdir and chroot into $tinyroot/root
- * 7. $tinyroot will be unmounted by our parent in start.c
- */
-static int chroot_into_slave(struct lxc_conf *conf)
-{
- char path[MAXPATHLEN];
- const char *destpath = conf->rootfs.mount;
- int ret;
-
- if (mount(destpath, destpath, NULL, MS_BIND, 0)) {
- SYSERROR("failed to mount %s bind", destpath);
- return -1;
- }
- if (mount("", destpath, NULL, MS_SLAVE, 0)) {
- SYSERROR("failed to make %s slave", destpath);
- return -1;
- }
- if (mount("none", destpath, "tmpfs", 0, "size=10000,mode=755")) {
- SYSERROR("Failed to mount tmpfs / at %s", destpath);
- return -1;
- }
- ret = snprintf(path, MAXPATHLEN, "%s/root", destpath);
- if (ret < 0 || ret >= MAXPATHLEN) {
- ERROR("out of memory making root path");
- return -1;
- }
- if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
- SYSERROR("Failed to create /dev/pts in container");
- return -1;
- }
- if (mount("/", path, NULL, MS_BIND|MS_REC, 0)) {
- SYSERROR("Failed to rbind mount / to %s", path);
- return -1;
- }
- if (mount("", destpath, NULL, MS_SLAVE|MS_REC, 0)) {
- SYSERROR("Failed to make tmp-/ at %s rslave", path);
- return -1;
- }
- if (chroot(path)) {
- SYSERROR("Failed to chroot into tmp-/");
- return -1;
- }
- if (chdir("/")) {
- SYSERROR("Failed to chdir into tmp-/");
- return -1;
- }
- INFO("Chrooted into tmp-/ at %s", path);
- return 0;
-}
-
static int setup_rootfs(struct lxc_conf *conf)
{
const struct lxc_rootfs *rootfs = &conf->rootfs;
return 0;
}
+int prepare_ramfs_root(char *root)
+{
+ char buf[LINELEN], *p;
+ char nroot[PATH_MAX];
+ FILE *f;
+ int i;
+ char *p2;
+
+ if (realpath(root, nroot) == NULL)
+ return -1;
+
+ if (chdir("/") == -1)
+ return -1;
+
+ /*
+ * We could use here MS_MOVE, but in userns this mount is
+ * locked and can't be moved.
+ */
+ if (mount(root, "/", NULL, MS_REC | MS_BIND, NULL)) {
+ SYSERROR("Failed to move %s into /", root);
+ return -1;
+ }
+
+ if (mount(".", NULL, NULL, MS_REC | MS_PRIVATE, NULL)) {
+ SYSERROR("Failed to make . rprivate");
+ return -1;
+ }
+
+ /*
+ * The following code cleans up inhereted mounts which are not
+ * required for CT.
+ *
+ * The mountinfo file shows not all mounts, if a few points have been
+ * unmounted between read operations from the mountinfo. So we need to
+ * read mountinfo a few times.
+ *
+ * This loop can be skipped if a container uses unserns, because all
+ * inherited mounts are locked and we should live with all this trash.
+ */
+ while (1) {
+ int progress = 0;
+
+ f = fopen("./proc/self/mountinfo", "r");
+ if (!f) {
+ SYSERROR("Unable to open /proc/self/mountinfo");
+ return -1;
+ }
+ while (fgets(buf, LINELEN, f)) {
+ for (p = buf, i=0; p && i < 4; i++)
+ p = strchr(p+1, ' ');
+ if (!p)
+ continue;
+ p2 = strchr(p+1, ' ');
+ if (!p2)
+ continue;
+
+ *p2 = '\0';
+ *p = '.';
+
+ if (strcmp(p + 1, "/") == 0)
+ continue;
+ if (strcmp(p + 1, "/proc") == 0)
+ continue;
+
+ if (umount2(p, MNT_DETACH) == 0)
+ progress++;
+ }
+ fclose(f);
+ if (!progress)
+ break;
+ }
+
+ if (umount2("./proc", MNT_DETACH)) {
+ SYSERROR("Unable to umount /proc");
+ return -1;
+ }
+
+ /* It is weird, but chdir("..") moves us in a new root */
+ if (chdir("..") == -1) {
+ SYSERROR("Unable to change working directory");
+ return -1;
+ }
+
+ if (chroot(".") == -1) {
+ SYSERROR("Unable to chroot");
+ return -1;
+ }
+
+ return 0;
+}
+
static int setup_pivot_root(const struct lxc_rootfs *rootfs)
{
if (!rootfs->path)
return 0;
- if (setup_rootfs_pivot_root(rootfs->mount, rootfs->pivot)) {
+ if (detect_ramfs_rootfs()) {
+ if (prepare_ramfs_root(rootfs->mount))
+ return -1;
+ } else if (setup_rootfs_pivot_root(rootfs->mount, rootfs->pivot)) {
ERROR("failed to setup pivot root");
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;
+ if (mountflags & MS_RDONLY)
+ rqd_flags |= MS_RDONLY;
#ifdef HAVE_STATVFS
if (statvfs(fsname, &sb) == 0) {
- unsigned long required_flags = 0;
+ unsigned long required_flags = rqd_flags;
if (sb.f_flag & MS_NOSUID)
required_flags |= MS_NOSUID;
if (sb.f_flag & MS_NODEV)
* mountflags, then skip the remount
*/
if (!(mountflags & MS_REMOUNT)) {
- if (!(required_flags & ~mountflags)) {
+ if (!(required_flags & ~mountflags) && rqd_flags == 0) {
DEBUG("mountflags already was %lu, skipping remount",
mountflags);
goto skipremount;
}
for (i=0; i<conf->num_savednics; i++) {
struct saved_nic *s = &conf->saved_nics[i];
- if (lxc_netdev_move_by_index(s->ifindex, 1))
+ if (lxc_netdev_move_by_index(s->ifindex, 1, NULL))
WARN("Error moving nic index:%d back to host netns",
s->ifindex);
}
return new;
}
-static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
+static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
char veth1buf[IFNAMSIZ], *veth1;
char veth2buf[IFNAMSIZ], *veth2;
err = lxc_veth_create(veth1, veth2);
if (err) {
- ERROR("failed to create %s-%s : %s", veth1, veth2,
+ ERROR("failed to create veth pair (%s and %s): %s", veth1, veth2,
strerror(-err));
goto out_delete;
}
* of a container */
err = setup_private_host_hw_addr(veth1);
if (err) {
- ERROR("failed to change mac address of host interface '%s' : %s",
+ ERROR("failed to change mac address of host interface '%s': %s",
veth1, strerror(-err));
goto out_delete;
}
if (!err)
err = lxc_netdev_set_mtu(veth2, atoi(netdev->mtu));
if (err) {
- ERROR("failed to set mtu '%s' for %s-%s : %s",
+ ERROR("failed to set mtu '%s' for veth pair (%s and %s): %s",
netdev->mtu, veth1, veth2, strerror(-err));
goto out_delete;
}
if (netdev->link) {
err = lxc_bridge_attach(netdev->link, veth1);
if (err) {
- ERROR("failed to attach '%s' to the bridge '%s' : %s",
+ ERROR("failed to attach '%s' to the bridge '%s': %s",
veth1, netdev->link, strerror(-err));
goto out_delete;
}
goto out_delete;
}
- DEBUG("instanciated veth '%s/%s', index is '%d'",
+ DEBUG("instantiated veth '%s/%s', index is '%d'",
veth1, veth2, netdev->ifindex);
return 0;
return 0;
}
-static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
char peerbuf[IFNAMSIZ], *peer;
int err;
goto out;
}
- DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'",
+ DEBUG("instantiated macvlan '%s', index is '%d' and mode '%d'",
peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
return 0;
return 0;
}
-/* XXX: merge with instanciate_macvlan */
-static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
+/* XXX: merge with instantiate_macvlan */
+static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
char peer[IFNAMSIZ];
int err;
return -1;
}
- DEBUG("instanciated vlan '%s', ifindex is '%d'", " vlan1000",
+ DEBUG("instantiated vlan '%s', ifindex is '%d'", " vlan1000",
netdev->ifindex);
return 0;
return 0;
}
-static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
+static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
if (!netdev->link) {
ERROR("no link specified for the physical interface");
return 0;
}
-static int instanciate_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
+static int instantiate_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
netdev->ifindex = 0;
return 0;
}
-static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
+static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
netdev->ifindex = 0;
if (netdev->upscript) {
if (!netdev->ifindex)
continue;
- err = lxc_netdev_move_by_index(netdev->ifindex, pid);
+ err = lxc_netdev_move_by_index(netdev->ifindex, pid, NULL);
if (err) {
ERROR("failed to move '%s' to the container : %s",
netdev->link, strerror(-err));
}
}
-static void remount_all_slave(void)
+void remount_all_slave(void)
{
/* walk /proc/mounts and change any shared entries to slave */
FILE *f = fopen("/proc/self/mountinfo", "r");
const char *path = conf->rootfs.mount;
if (mount(path, path, "rootfs", MS_BIND, NULL) < 0) {
ERROR("Failed to bind-mount container / onto itself");
- return false;
- }
- }
-
- if (detect_ramfs_rootfs()) {
- if (chroot_into_slave(conf)) {
- ERROR("Failed to chroot into slave /");
return -1;
}
+ return 0;
}
remount_all_slave();
hookname);
return false;
}
+ return true;
}
return true;
free(netdev->mtu);
netdev->mtu = NULL;
}
- } else if (strcmp(p1, ".ipv4_gateway") == 0) {
+ } else if (strcmp(p1, ".ipv4.gateway") == 0) {
if (netdev->ipv4_gateway) {
free(netdev->ipv4_gateway);
netdev->ipv4_gateway = NULL;
}
- } else if (strcmp(p1, ".ipv6_gateway") == 0) {
+ } else if (strcmp(p1, ".ipv6.gateway") == 0) {
if (netdev->ipv6_gateway) {
free(netdev->ipv6_gateway);
netdev->ipv6_gateway = NULL;
/*
* Defines a generic struct to configure the control group.
* It is up to the programmer to specify the right subsystem.
- * @subsystem : the targetted subsystem
+ * @subsystem : the targeted subsystem
* @value : the value to set
*/
struct lxc_cgroup {
/*
* Defines the number of tty configured and contains the
- * instanciated ptys
+ * instantiated ptys
* @nbtty = number of configured ttys
*/
struct lxc_tty_info {
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 suggest_default_idmap(void);
#endif
strprint(retv, inlen, "hwaddr\n");
strprint(retv, inlen, "mtu\n");
strprint(retv, inlen, "ipv6\n");
- strprint(retv, inlen, "ipv6_gateway\n");
+ strprint(retv, inlen, "ipv6.gateway\n");
strprint(retv, inlen, "ipv4\n");
- strprint(retv, inlen, "ipv4_gateway\n");
+ strprint(retv, inlen, "ipv4.gateway\n");
}
switch(netdev->type) {
case LXC_NET_VETH:
static int config_fstab(const char *key, const char *value,
struct lxc_conf *lxc_conf)
{
+ if (!value || strlen(value) == 0)
+ return -1;
return config_path_item(&lxc_conf->fstab, value);
}
int i;
int ret = -1;
- if (!strlen(value))
- return -1;
+ if (!value || strlen(value) == 0) {
+ lxc_conf->auto_mounts = 0;
+ return 0;
+ }
autos = strdup(value);
if (!autos) {
return ret;
}
+/*
+ * TODO
+ * This fn is handling lxc.mount, lxc.mount.entry, and lxc.mount.auto.
+ * It should probably be split into 3 separate functions indexed by
+ * the config[] entries at top.
+ */
static int config_mount(const char *key, const char *value,
struct lxc_conf *lxc_conf)
{
char *mntelem;
struct lxc_list *mntlist;
- if (!value || strlen(value) == 0)
- return lxc_clear_mount_entries(lxc_conf);
-
subkey = strstr(key, token);
if (!subkey) {
return config_mount_auto(key, value, lxc_conf);
}
- if (!strlen(subkey))
- return -1;
+ /* At this point we definitely have key = lxc.mount.entry */
+ if (!value || strlen(value) == 0)
+ return lxc_clear_mount_entries(lxc_conf);
mntlist = malloc(sizeof(*mntlist));
if (!mntlist)
/*
* lxc.network.0.XXX, where XXX can be: name, type, link, flags, type,
* macvlan.mode, veth.pair, vlan, ipv4, ipv6, script.up, hwaddr, mtu,
- * ipv4_gateway, ipv6_gateway. ipvX_gateway can return 'auto' instead
+ * ipv4.gateway, ipv6.gateway. ipvX.gateway can return 'auto' instead
* of an address. ipv4 and ipv6 return lists (newline-separated).
* things like veth.pair return '' if invalid (i.e. if called for vlan
* type).
if (netdev->type == LXC_NET_VLAN) {
strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
}
- } else if (strcmp(p1, "ipv4_gateway") == 0) {
+ } else if (strcmp(p1, "ipv4.gateway") == 0) {
if (netdev->ipv4_gateway_auto) {
strprint(retv, inlen, "auto");
} else if (netdev->ipv4_gateway) {
struct lxc_inetdev *i = it2->elem;
char buf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
- strprint(retv, inlen, "%s\n", buf);
+ strprint(retv, inlen, "%s/%d\n", buf, i->prefix);
}
- } else if (strcmp(p1, "ipv6_gateway") == 0) {
+ } else if (strcmp(p1, "ipv6.gateway") == 0) {
if (netdev->ipv6_gateway_auto) {
strprint(retv, inlen, "auto");
} else if (netdev->ipv6_gateway) {
struct lxc_inet6dev *i = it2->elem;
char buf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
- strprint(retv, inlen, "%s\n", buf);
+ strprint(retv, inlen, "%s/%d\n", buf, i->prefix);
}
}
return fulllen;
lxc_seccomp_free(c);
return 0;
}
+ else if (strncmp(key, "lxc.id_map", 10) == 0) {
+ return lxc_clear_idmaps(c);
+ }
return -1;
}
containers=""
if [ ! -z "$directory" ]; then
if [ x"$parent_cgroup" = x ]; then
- containers=$(find $directory -mindepth 2 -maxdepth 2 -name config -type f |awk -F "/" '{print $(NF-1)}')
+ containers=$(find -L $directory -mindepth 2 -maxdepth 2 -name config -type f |awk -F "/" '{print $(NF-1)}')
else
containers=$(find $directory -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed 's:.*/::')
fi
return 0;
fprintf(stderr, "%s: ", log_prefix);
+ fprintf(stderr, "%s: %s: %d ", event->locinfo->file, event->locinfo->func, event->locinfo->line);
vfprintf(stderr, event->fmt, *event->vap);
fprintf(stderr, "\n");
return 0;
ms = event->timestamp.tv_usec / 1000;
n = snprintf(buffer, sizeof(buffer),
- "%15s %10ld.%03d %-8s %s - ",
+ "%15s %10ld.%03d %-8s %s - %s:%s:%d - ",
log_prefix,
event->timestamp.tv_sec,
ms,
lxc_log_priority_to_string(event->priority),
- event->category);
+ event->category,
+ event->locinfo->file, event->locinfo->func,
+ event->locinfo->line);
n += vsnprintf(buffer + n, sizeof(buffer) - n, event->fmt,
*event->vap);
*p = '\0';
if (access(n, F_OK)) {
ret = lxc_unpriv(mkdir(n, 0755));
- if (ret && errno != -EEXIST) {
+ if (ret && errno != EEXIST) {
SYSERROR("failed to create directory '%s'.", n);
free(n);
return -1;
* Build the path to the log file
* @name : the name of the container
* @lxcpath : the lxcpath to use as a basename or NULL to use LOGPATH
- * Returns malloced path on sucess, or NULL on failure
+ * Returns malloced path on success, or NULL on failure
*/
static char *build_log_path(const char *name, const char *lxcpath)
{
/*
* This generation number is used to test if the new fields are valid
- * and up to date while reading the root item. Everytime the root item
+ * 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
if [ ! -f "$CONFIG" ]; then
MODULEFILE=$(modinfo -k $KVER -n $MODNAME 2> /dev/null)
# don't want to modprobe, so give user a hint
- # altho scripts/extract-ikconfig could be used to extract contents without loading kernel module
+ # although scripts/extract-ikconfig could be used to extract contents without loading kernel module
# http://svn.pld-linux.org/trac/svn/browser/geninitrd/trunk/geninitrd?rev=12696#L327
fi
GREP=grep
* @name : the name of the container
* @argv : an array of char * corresponding to the commande line
* @conf : configuration
- * Returns 0 on sucess, < 0 otherwise
+ * Returns 0 on success, < 0 otherwise
*/
extern int lxc_start(const char *name, char *const argv[], struct lxc_conf *conf,
const char *lxcpath);
* @argv : an array of char * corresponding to the commande line
* @quiet : if != 0 then lxc-init won't produce any output
* @conf : configuration
- * Returns 0 on sucess, < 0 otherwise
+ * Returns 0 on success, < 0 otherwise
*/
extern int lxc_execute(const char *name, char *const argv[], int quiet,
struct lxc_conf *conf, const char *lxcpath);
/*
* Unfreeze all previously frozen tasks.
* @name : the name of the container
- * Return 0 on sucess, < 0 otherwise
+ * Return 0 on success, < 0 otherwise
*/
extern int lxc_unfreeze(const char *name, const char *lxcpath);
if (!ifname)
return;
printf("%-15s %s\n", "Link:", ifname);
+ fflush(stdout);
/* XXX: tx and rx are reversed from the host vs container
* perspective, print them from the container perspective
str_chomp(buf);
rx_bytes = str_size_humanize(buf, sizeof(buf));
printf("%-15s %s\n", " TX bytes:", buf);
+ fflush(stdout);
}
snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/tx_bytes", ifname);
str_chomp(buf);
tx_bytes = str_size_humanize(buf, sizeof(buf));
printf("%-15s %s\n", " RX bytes:", buf);
+ fflush(stdout);
}
sprintf(buf, "%llu", rx_bytes + tx_bytes);
str_size_humanize(buf, sizeof(buf));
printf("%-15s %s\n", " Total bytes:", buf);
+ fflush(stdout);
free(ifname);
}
}
} else {
printf("%-15s %s\n", "CPU use:", buf);
}
+ fflush(stdout);
}
ret = c->get_cgroup_item(c, "blkio.throttle.io_service_bytes", buf, sizeof(buf));
str_size_humanize(buf, sizeof(buf));
printf("%-15s %s\n", "BlkIO use:", buf);
}
+ fflush(stdout);
}
static const struct {
str_chomp(buf);
str_size_humanize(buf, sizeof(buf));
printf("%-15s %s\n", lxstat[i].name, buf);
+ fflush(stdout);
}
}
}
else
printf("%-15s %d\n", key, value);
}
+ fflush(stdout);
}
static void print_info_msg_str(const char *key, const char *value)
else
printf("%-15s %s\n", key, value);
}
+ fflush(stdout);
}
static int print_info(const char *name, const char *lxcpath)
} else {
fprintf(stderr, "%s invalid\n", key[i]);
}
+ fflush(stdout);
}
lxc_container_put(c);
}
}
+ if (c->is_running(c)) {
+ ERROR("Container is already running.");
+ err = 0;
+ goto out;
+ }
/*
* We should use set_config_item() over &defines, which would handle
* unset c->lxc_conf for us and let us not use lxc_config_define_load()
if (my_iflist) {
for (tmpif = my_iflist; tmpif; tmpif = tmpif->mi_next) {
- if (lxc_netdev_move_by_name(tmpif->mi_ifname, pid) < 0)
+ if (lxc_netdev_move_by_name(tmpif->mi_ifname, pid, NULL) < 0)
fprintf(stderr,"Could not move interface %s into container %d: %s\n", tmpif->mi_ifname, pid, strerror(errno));
}
}
return true;
}
-static int instanciate_veth(char *n1, char **n2)
+static int instantiate_veth(char *n1, char **n2)
{
int err;
}
/* create the nics */
- if (instanciate_veth(veth1buf, &veth2buf) < 0) {
+ if (instantiate_veth(veth1buf, &veth2buf) < 0) {
fprintf(stderr, "Error creating veth tunnel\n");
return false;
}
}
/* pass veth2 to target netns */
- ret = lxc_netdev_move_by_name(veth2buf, pid);
+ ret = lxc_netdev_move_by_name(veth2buf, pid, NULL);
if (ret < 0) {
fprintf(stderr, "Error moving %s to netns %d\n", veth2buf, pid);
goto out_del;
/*
* If the caller (real uid, not effective uid) may read the
- * /proc/pid/net/ns, then it is either the caller's netns or one
+ * /proc/[pid]/ns/net, then it is either the caller's netns or one
* which it created.
*/
static bool may_access_netns(int pid)
return ret == 0;
}
-static inline bool enter_to_ns(struct lxc_container *c) {
+static inline bool enter_net_ns(struct lxc_container *c) {
int netns, userns, ret = 0, init_pid = 0;;
char new_netns_path[MAXPATHLEN];
char new_userns_path[MAXPATHLEN];
/* close the read-end of the pipe */
close(pipefd[0]);
- if (!enter_to_ns(c)) {
+ if (!enter_net_ns(c)) {
SYSERROR("failed to enter namespace");
goto out;
}
/* close the read-end of the pipe */
close(pipefd[0]);
- if (!enter_to_ns(c)) {
+ if (!enter_net_ns(c)) {
SYSERROR("failed to enter namespace");
goto out;
}
* \param c Container.
* \param[in,out] ttynum Terminal number to attempt to allocate,
* or \c -1 to allocate the first available tty.
- * \param[out] masterfd File descriptor refering to the master side of the pty.
+ * \param[out] masterfd File descriptor referring to the master side of the pty.
*
* \return tty file descriptor number on success, or \c -1 on
* failure.
}
/* One thread can do fork() while another one is holding a mutex.
- * There is only one thread in child just after the fork(), so noone will ever release that mutex.
+ * There is only one thread in child just after the fork(), so no one will ever release that mutex.
* We setup a "child" fork handler to unlock the mutex just after the fork().
* For several mutex types, unlocking an unlocked mutex can lead to undefined behavior.
* One way to deal with it is to setup "prepare" fork handler
# define IFLA_MACVLAN_MODE 1
#endif
-struct link_req {
- struct nlmsg nlmsg;
- struct ifinfomsg ifinfomsg;
-};
-
-struct ip_req {
- struct nlmsg nlmsg;
- struct ifaddrmsg ifa;
-};
-
-struct rt_req {
- struct nlmsg nlmsg;
- struct rtmsg rt;
-};
-int lxc_netdev_move_by_index(int ifindex, pid_t pid)
+int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname)
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL;
- struct link_req *link_req;
+ struct ifinfomsg *ifi;
int err;
err = netlink_open(&nlh, NETLINK_ROUTE);
if (!nlmsg)
goto out;
- link_req = (struct link_req *)nlmsg;
- link_req->ifinfomsg.ifi_family = AF_UNSPEC;
- link_req->ifinfomsg.ifi_index = ifindex;
- nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
- nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+ nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
+
+ ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+ ifi->ifi_family = AF_UNSPEC;
+ ifi->ifi_index = ifindex;
if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
goto out;
+ if (ifname != NULL) {
+ if (nla_put_string(nlmsg, IFLA_IFNAME, ifname))
+ goto out;
+ }
+
err = netlink_transaction(&nlh, nlmsg, nlmsg);
out:
netlink_close(&nlh);
return err;
}
-int lxc_netdev_move_by_name(char *ifname, pid_t pid)
+int lxc_netdev_move_by_name(const char *ifname, pid_t pid, const char* newname)
{
int index;
return -EINVAL;
index = if_nametoindex(ifname);
+ if (!index)
+ return -EINVAL;
- return lxc_netdev_move_by_index(index, pid);
+ return lxc_netdev_move_by_index(index, pid, newname);
}
int lxc_netdev_delete_by_index(int ifindex)
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct link_req *link_req;
+ struct ifinfomsg *ifi;
int err;
err = netlink_open(&nlh, NETLINK_ROUTE);
if (!nlmsg)
goto out;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
if (!answer)
goto out;
- link_req = (struct link_req *)nlmsg;
- link_req->ifinfomsg.ifi_family = AF_UNSPEC;
- link_req->ifinfomsg.ifi_index = ifindex;
- nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
- nlmsg->nlmsghdr.nlmsg_type = RTM_DELLINK;
+ nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_DELLINK;
+
+ ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+ ifi->ifi_family = AF_UNSPEC;
+ ifi->ifi_index = ifindex;
err = netlink_transaction(&nlh, nlmsg, answer);
out:
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct link_req *link_req;
+ struct ifinfomsg *ifi;
int len, err;
err = netlink_open(&nlh, NETLINK_ROUTE);
if (!nlmsg)
goto out;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
if (!answer)
goto out;
- link_req = (struct link_req *)nlmsg;
- link_req->ifinfomsg.ifi_family = AF_UNSPEC;
- link_req->ifinfomsg.ifi_index = ifindex;
- nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
- nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+ nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
+
+ ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+ ifi->ifi_family = AF_UNSPEC;
+ ifi->ifi_index = ifindex;
if (nla_put_string(nlmsg, IFLA_IFNAME, newname))
goto out;
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct link_req *link_req;
+ struct ifinfomsg *ifi;
int index, len, err;
err = netlink_open(&nlh, NETLINK_ROUTE);
if (!nlmsg)
goto out;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
if (!answer)
goto out;
if (!index)
goto out;
- link_req = (struct link_req *)nlmsg;
- link_req->ifinfomsg.ifi_family = AF_UNSPEC;
- link_req->ifinfomsg.ifi_index = index;
- link_req->ifinfomsg.ifi_change |= IFF_UP;
- link_req->ifinfomsg.ifi_flags |= flag;
- nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
- nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+ nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
+
+ ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+ ifi->ifi_family = AF_UNSPEC;
+ ifi->ifi_index = index;
+ ifi->ifi_change |= IFF_UP;
+ ifi->ifi_flags |= flag;
err = netlink_transaction(&nlh, nlmsg, answer);
out:
return err;
}
+int netdev_get_flag(const char* name, int *flag)
+{
+ struct nl_handler nlh;
+ struct nlmsg *nlmsg = NULL, *answer = NULL;
+ struct ifinfomsg *ifi;
+ int index, len, err;
+
+ if (!name)
+ return -EINVAL;
+
+ err = netlink_open(&nlh, NETLINK_ROUTE);
+ if (err)
+ return err;
+
+ err = -EINVAL;
+ len = strlen(name);
+ if (len == 1 || len >= IFNAMSIZ)
+ goto out;
+
+ err = -ENOMEM;
+ nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ if (!nlmsg)
+ goto out;
+
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
+ if (!answer)
+ goto out;
+
+ err = -EINVAL;
+ index = if_nametoindex(name);
+ if (!index)
+ goto out;
+
+ nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK;
+
+ ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+ ifi->ifi_family = AF_UNSPEC;
+ ifi->ifi_index = index;
+
+ err = netlink_transaction(&nlh, nlmsg, answer);
+ if (err)
+ goto out;
+
+ ifi = NLMSG_DATA(answer->nlmsghdr);
+
+ *flag = ifi->ifi_flags;
+out:
+ netlink_close(&nlh);
+ nlmsg_free(nlmsg);
+ nlmsg_free(answer);
+ return err;
+}
+
+/*
+ * \brief Check a interface is up or not.
+ *
+ * \param name: name for the interface.
+ *
+ * \return int.
+ * 0 means interface is down.
+ * 1 means interface is up.
+ * Others means error happened, and ret-value is the error number.
+ */
+int lxc_netdev_isup(const char* name)
+{
+ int flag;
+ int err;
+
+ err = netdev_get_flag(name, &flag);
+ if (err)
+ goto out;
+ if (flag & IFF_UP)
+ return 1;
+ return 0;
+out:
+ return err;
+}
+
int netdev_get_mtu(int ifindex)
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct ip_req *ip_req;
+ struct ifinfomsg *ifi;
struct nlmsghdr *msg;
int err, res;
int recv_len = 0, answer_len;
if (!nlmsg)
goto out;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
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. */
- answer_len = answer->nlmsghdr.nlmsg_len;
+ answer_len = answer->nlmsghdr->nlmsg_len;
+
+ nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK;
- ip_req = (struct ip_req *)nlmsg;
- ip_req->nlmsg.nlmsghdr.nlmsg_len =
- NLMSG_LENGTH(sizeof(struct ifaddrmsg));
- ip_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
- ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_GETLINK;
- ip_req->ifa.ifa_family = AF_UNSPEC;
+ ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+ ifi->ifi_family = AF_UNSPEC;
/* Send the request for addresses, which returns all addresses
* on all interfaces. */
do {
/* Restore the answer buffer length, it might have been
* overwritten by a previous receive. */
- answer->nlmsghdr.nlmsg_len = answer_len;
+ answer->nlmsghdr->nlmsg_len = answer_len;
/* Get the (next) batch of reply messages */
err = netlink_rcv(&nlh, answer);
err = 0;
/* Satisfy the typing for the netlink macros */
- msg = &answer->nlmsghdr;
+ msg = answer->nlmsghdr;
while (NLMSG_OK(msg, recv_len)) {
break;
}
- struct ifinfomsg *ifi = NLMSG_DATA(msg);
+ 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));
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct link_req *link_req;
+ struct ifinfomsg *ifi;
int index, len, err;
err = netlink_open(&nlh, NETLINK_ROUTE);
if (!nlmsg)
goto out;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
if (!answer)
goto out;
if (!index)
goto out;
- link_req = (struct link_req *)nlmsg;
- link_req->ifinfomsg.ifi_family = AF_UNSPEC;
- link_req->ifinfomsg.ifi_index = index;
- nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
- nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+ nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
+
+ ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+ ifi->ifi_family = AF_UNSPEC;
+ ifi->ifi_index = index;
if (nla_put_u32(nlmsg, IFLA_MTU, mtu))
goto out;
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct link_req *link_req;
+ struct ifinfomsg *ifi;
struct rtattr *nest1, *nest2, *nest3;
int len, err;
if (!nlmsg)
goto out;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
if (!answer)
goto out;
- link_req = (struct link_req *)nlmsg;
- link_req->ifinfomsg.ifi_family = AF_UNSPEC;
- nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- nlmsg->nlmsghdr.nlmsg_flags =
+ nlmsg->nlmsghdr->nlmsg_flags =
NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
- nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
+
+ ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+ ifi->ifi_family = AF_UNSPEC;
err = -EINVAL;
nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO);
if (!nest3)
goto out;
- nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg);
+ ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+ if (!ifi)
+ goto out;
if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
goto out;
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct link_req *link_req;
+ struct ifinfomsg *ifi;
struct rtattr *nest, *nest2;
int lindex, len, err;
if (!nlmsg)
goto err3;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
if (!answer)
goto err2;
if (!lindex)
goto err1;
- link_req = (struct link_req *)nlmsg;
- link_req->ifinfomsg.ifi_family = AF_UNSPEC;
- nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- nlmsg->nlmsghdr.nlmsg_flags =
+ nlmsg->nlmsghdr->nlmsg_flags =
NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
- nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
+
+ ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+ ifi->ifi_family = AF_UNSPEC;
nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
if (!nest)
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct link_req *link_req;
+ struct ifinfomsg *ifi;
struct rtattr *nest, *nest2;
int index, len, err;
if (!nlmsg)
goto out;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
if (!answer)
goto out;
if (!index)
goto out;
- link_req = (struct link_req *)nlmsg;
- link_req->ifinfomsg.ifi_family = AF_UNSPEC;
- nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- nlmsg->nlmsghdr.nlmsg_flags =
+ nlmsg->nlmsghdr->nlmsg_flags =
NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
- nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
+
+ ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+ ifi->ifi_family = AF_UNSPEC;
nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
if (!nest)
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct ip_req *ip_req;
+ struct ifaddrmsg *ifa;
int addrlen;
int err;
if (!nlmsg)
goto out;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
if (!answer)
goto out;
- ip_req = (struct ip_req *)nlmsg;
- ip_req->nlmsg.nlmsghdr.nlmsg_len =
- NLMSG_LENGTH(sizeof(struct ifaddrmsg));
- ip_req->nlmsg.nlmsghdr.nlmsg_flags =
+ nlmsg->nlmsghdr->nlmsg_flags =
NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
- ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWADDR;
- ip_req->ifa.ifa_prefixlen = prefix;
- ip_req->ifa.ifa_index = ifindex;
- ip_req->ifa.ifa_family = family;
- ip_req->ifa.ifa_scope = 0;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_NEWADDR;
+
+ ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg));
+ ifa->ifa_prefixlen = prefix;
+ ifa->ifa_index = ifindex;
+ ifa->ifa_family = family;
+ ifa->ifa_scope = 0;
err = -EINVAL;
if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen))
* 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 ip_req *ip_info, void** res) {
- struct rtattr *rta = IFA_RTA(&ip_info->ifa);
- int attr_len = IFA_PAYLOAD(&ip_info->nlmsg.nlmsghdr);
+static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void** res) {
+ struct ifaddrmsg *ifa = NLMSG_DATA(msg);
+ struct rtattr *rta = IFA_RTA(ifa);
+ int attr_len = NLMSG_PAYLOAD(msg, sizeof(struct ifaddrmsg));
int addrlen;
- if (ip_info->ifa.ifa_family != family)
+ if (ifa->ifa_family != family)
return 0;
addrlen = family == AF_INET ? sizeof(struct in_addr) :
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct ip_req *ip_req, *ip_info;
+ struct ifaddrmsg *ifa;
struct nlmsghdr *msg;
int err;
int recv_len = 0, answer_len;
if (!nlmsg)
goto out;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
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. */
- answer_len = answer->nlmsghdr.nlmsg_len;
+ answer_len = answer->nlmsghdr->nlmsg_len;
+
+ nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ROOT;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_GETADDR;
- ip_req = (struct ip_req *)nlmsg;
- ip_req->nlmsg.nlmsghdr.nlmsg_len =
- NLMSG_LENGTH(sizeof(struct ifaddrmsg));
- ip_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ROOT;
- ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_GETADDR;
- ip_req->ifa.ifa_family = family;
+ ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg));
+ ifa->ifa_family = family;
/* Send the request for addresses, which returns all addresses
* on all interfaces. */
do {
/* Restore the answer buffer length, it might have been
* overwritten by a previous receive. */
- answer->nlmsghdr.nlmsg_len = answer_len;
+ answer->nlmsghdr->nlmsg_len = answer_len;
/* Get the (next) batch of reply messages */
err = netlink_rcv(&nlh, answer);
err = 0;
/* Satisfy the typing for the netlink macros */
- msg = &answer->nlmsghdr;
+ msg = answer->nlmsghdr;
while (NLMSG_OK(msg, recv_len)) {
/* Stop reading if we see an error message */
goto out;
}
- ip_info = (struct ip_req *)msg;
- if (ip_info->ifa.ifa_index == ifindex) {
- if (ifa_get_local_ip(family, ip_info, res) < 0) {
+ ifa = (struct ifaddrmsg *)NLMSG_DATA(msg);
+ if (ifa->ifa_index == ifindex) {
+ if (ifa_get_local_ip(family, msg, res) < 0) {
err = -1;
goto out;
}
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct rt_req *rt_req;
+ struct rtmsg *rt;
int addrlen;
int err;
if (!nlmsg)
goto out;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
if (!answer)
goto out;
- rt_req = (struct rt_req *)nlmsg;
- rt_req->nlmsg.nlmsghdr.nlmsg_len =
- NLMSG_LENGTH(sizeof(struct rtmsg));
- rt_req->nlmsg.nlmsghdr.nlmsg_flags =
+ nlmsg->nlmsghdr->nlmsg_flags =
NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
- rt_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWROUTE;
- rt_req->rt.rtm_family = family;
- rt_req->rt.rtm_table = RT_TABLE_MAIN;
- rt_req->rt.rtm_scope = RT_SCOPE_UNIVERSE;
- rt_req->rt.rtm_protocol = RTPROT_BOOT;
- rt_req->rt.rtm_type = RTN_UNICAST;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_NEWROUTE;
+
+ rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg));
+ rt->rtm_family = family;
+ rt->rtm_table = RT_TABLE_MAIN;
+ rt->rtm_scope = RT_SCOPE_UNIVERSE;
+ rt->rtm_protocol = RTPROT_BOOT;
+ rt->rtm_type = RTN_UNICAST;
/* "default" destination */
- rt_req->rt.rtm_dst_len = 0;
+ rt->rtm_dst_len = 0;
err = -EINVAL;
if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen))
{
struct nl_handler nlh;
struct nlmsg *nlmsg = NULL, *answer = NULL;
- struct rt_req *rt_req;
+ struct rtmsg *rt;
int addrlen;
int err;
if (!nlmsg)
goto out;
- answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+ answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
if (!answer)
goto out;
- rt_req = (struct rt_req *)nlmsg;
- rt_req->nlmsg.nlmsghdr.nlmsg_len =
- NLMSG_LENGTH(sizeof(struct rtmsg));
- rt_req->nlmsg.nlmsghdr.nlmsg_flags =
+ nlmsg->nlmsghdr->nlmsg_flags =
NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
- rt_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWROUTE;
- rt_req->rt.rtm_family = family;
- rt_req->rt.rtm_table = RT_TABLE_MAIN;
- rt_req->rt.rtm_scope = RT_SCOPE_LINK;
- rt_req->rt.rtm_protocol = RTPROT_BOOT;
- rt_req->rt.rtm_type = RTN_UNICAST;
- rt_req->rt.rtm_dst_len = addrlen*8;
+ nlmsg->nlmsghdr->nlmsg_type = RTM_NEWROUTE;
+
+ rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg));
+ rt->rtm_family = family;
+ rt->rtm_table = RT_TABLE_MAIN;
+ rt->rtm_scope = RT_SCOPE_LINK;
+ rt->rtm_protocol = RTPROT_BOOT;
+ rt->rtm_type = RTN_UNICAST;
+ rt->rtm_dst_len = addrlen*8;
err = -EINVAL;
if (nla_put_buffer(nlmsg, RTA_DST, dest, addrlen))
/*
* Move a device between namespaces
*/
-extern int lxc_netdev_move_by_index(int ifindex, pid_t pid);
-extern int lxc_netdev_move_by_name(char *ifname, pid_t pid);
+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
/*
* 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);
extern size_t nlmsg_len(const struct nlmsg *nlmsg)
{
- return nlmsg->nlmsghdr.nlmsg_len - NLMSG_HDRLEN;
+ return nlmsg->nlmsghdr->nlmsg_len - NLMSG_HDRLEN;
}
extern void *nlmsg_data(struct nlmsg *nlmsg)
{
- char *data = ((char *)nlmsg) + NLMSG_ALIGN(sizeof(struct nlmsghdr));
+ char *data = ((char *)nlmsg) + NLMSG_HDRLEN;
if (!nlmsg_len(nlmsg))
return NULL;
return data;
{
struct rtattr *rta;
size_t rtalen = RTA_LENGTH(len);
+ size_t tlen = NLMSG_ALIGN(nlmsg->nlmsghdr->nlmsg_len) + RTA_ALIGN(rtalen);
- rta = NLMSG_TAIL(&nlmsg->nlmsghdr);
- rta->rta_type = attr;
- rta->rta_len = rtalen;
- memcpy(RTA_DATA(rta), data, len);
- nlmsg->nlmsghdr.nlmsg_len =
- NLMSG_ALIGN(nlmsg->nlmsghdr.nlmsg_len) + RTA_ALIGN(rtalen);
+ if (tlen > nlmsg->cap)
+ return -ENOMEM;
+
+ rta = NLMSG_TAIL(nlmsg->nlmsghdr);
+ rta->rta_type = attr;
+ rta->rta_len = rtalen;
+ memcpy(RTA_DATA(rta), data, len);
+ nlmsg->nlmsghdr->nlmsg_len = tlen;
return 0;
}
struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr)
{
- struct rtattr *rtattr = NLMSG_TAIL(&nlmsg->nlmsghdr);
+ struct rtattr *rtattr = NLMSG_TAIL(nlmsg->nlmsghdr);
if (nla_put_attr(nlmsg, attr))
return NULL;
void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr)
{
- attr->rta_len = (void *)NLMSG_TAIL(&nlmsg->nlmsghdr) - (void *)attr;
+ attr->rta_len = (void *)NLMSG_TAIL(nlmsg->nlmsghdr) - (void *)attr;
}
extern struct nlmsg *nlmsg_alloc(size_t size)
{
struct nlmsg *nlmsg;
- size_t len = NLMSG_ALIGN(size) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
+ size_t len = NLMSG_HDRLEN + NLMSG_ALIGN(size);
- nlmsg = (struct nlmsg *)malloc(len);
+ nlmsg = (struct nlmsg *)malloc(sizeof(struct nlmsg));
if (!nlmsg)
return NULL;
- memset(nlmsg, 0, len);
- nlmsg->nlmsghdr.nlmsg_len = NLMSG_ALIGN(size);
+ nlmsg->nlmsghdr = (struct nlmsghdr *)malloc(len);
+ if (!nlmsg->nlmsghdr)
+ goto errout;
+
+ memset(nlmsg->nlmsghdr, 0, len);
+ nlmsg->cap = len;
+ nlmsg->nlmsghdr->nlmsg_len = NLMSG_HDRLEN;
return nlmsg;
+errout:
+ free(nlmsg);
+ return NULL;
+}
+
+extern void *nlmsg_reserve(struct nlmsg *nlmsg, size_t len)
+{
+ void *buf;
+ size_t nlmsg_len = nlmsg->nlmsghdr->nlmsg_len;
+ size_t tlen = NLMSG_ALIGN(len);
+
+ if (nlmsg_len + tlen > nlmsg->cap)
+ return NULL;
+
+ buf = ((char *)(nlmsg->nlmsghdr)) + nlmsg_len;
+ nlmsg->nlmsghdr->nlmsg_len += tlen;
+
+ if (tlen > len)
+ memset(buf + len, 0, tlen - len);
+
+ return buf;
+}
+
+extern struct nlmsg *nlmsg_alloc_reserve(size_t size)
+{
+ struct nlmsg *nlmsg;
+
+ nlmsg = nlmsg_alloc(size);
+ if (!nlmsg)
+ return NULL;
+
+ // just set message length to cap directly
+ nlmsg->nlmsghdr->nlmsg_len = nlmsg->cap;
+ return nlmsg;
}
extern void nlmsg_free(struct nlmsg *nlmsg)
{
+ if (!nlmsg)
+ return;
+
+ free(nlmsg->nlmsghdr);
free(nlmsg);
}
int ret;
struct sockaddr_nl nladdr;
struct iovec iov = {
- .iov_base = answer,
- .iov_len = answer->nlmsghdr.nlmsg_len,
+ .iov_base = answer->nlmsghdr,
+ .iov_len = answer->nlmsghdr->nlmsg_len,
};
struct msghdr msg = {
return 0;
if (msg.msg_flags & MSG_TRUNC &&
- ret == answer->nlmsghdr.nlmsg_len)
+ ret == answer->nlmsghdr->nlmsg_len)
return -EMSGSIZE;
return ret;
{
struct sockaddr_nl nladdr;
struct iovec iov = {
- .iov_base = (void*)nlmsg,
- .iov_len = nlmsg->nlmsghdr.nlmsg_len,
+ .iov_base = nlmsg->nlmsghdr,
+ .iov_len = nlmsg->nlmsghdr->nlmsg_len,
};
struct msghdr msg = {
.msg_name = &nladdr,
if (ret < 0)
return ret;
- if (answer->nlmsghdr.nlmsg_type == NLMSG_ERROR) {
- struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(answer);
+ if (answer->nlmsghdr->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(answer->nlmsghdr);
return err->error;
}
};
/*
- * struct nlmsg : the netlink message structure, it consists just
- * on a definition for a nlmsghdr. This message is to be used to
+ * struct nlmsg : the netlink message structure. This message is to be used to
* be allocated with netlink_alloc.
- * @nlmsghdr : a pointer to a netlink message header, this field
- * _must_ be always the first field of this structure
+ *
+ * @nlmsghdr: a pointer to a netlink message header
+ * @cap: capacity of the netlink message, this is the initially allocated size
+ * and later operations (e.g. reserve and put) can not exceed this limit.
*/
struct nlmsg {
- struct nlmsghdr nlmsghdr;
+ struct nlmsghdr *nlmsghdr;
+ ssize_t cap;
};
/*
* is sizeof(header) + sizeof(padding) + payloadsize + sizeof(padding),
* in other words, the function will allocate more than specified. When
* the buffer is allocated, the content is zeroed.
- * The function will also fill the field nlmsg_len with computed size.
+ * The function will also fill the field nlmsg_len with NLMSG_HDRLEN.
* If the allocation must be for the specified size, just use malloc.
*
- * @size: the size of the payload to be allocated
+ * @size: the capacity of the payload to be allocated
*
* Returns a pointer to the newly allocated netlink message, NULL otherwise
*/
struct nlmsg *nlmsg_alloc(size_t size);
/*
+ * nlmsg_alloc_reserve: like nlmsg_alloc(), but reserve the whole payload
+ * after allocated, that is, the field nlmsg_len be set to the capacity
+ * of nlmsg. Often used to allocate a message for the reply.
+ *
+ * @size: the capacity of the payload to be allocated.
+ */
+struct nlmsg *nlmsg_alloc_reserve(size_t size);
+
+/*
+ * Reserve room for additional data at the tail of a netlink message
+ *
+ * @nlmsg: the netlink message
+ * @len: length of additional data to reserve room for
+ *
+ * Returns a pointer to newly reserved room or NULL
+ */
+void *nlmsg_reserve(struct nlmsg *nlmsg, size_t len);
+
+/*
* nlmsg_free : free a previously allocate message
*
* @nlmsg: the netlink message to be freed
}
/* The clearenv() and putenv() calls have been moved here
- * to allow us to use enviroment variables passed to the various
+ * 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. */
ERROR("Error unsharing mounts");
goto out_fini_nonet;
}
+ remount_all_slave();
if (do_rootfs_setup(conf, name, lxcpath) < 0) {
ERROR("Error setting up rootfs mount as root before spawn");
goto out_fini_nonet;
{ "lxc.bdev.zfs.root", DEFAULT_ZFSROOT },
{ "lxc.lxcpath", NULL },
{ "lxc.default_config", NULL },
- { "lxc.cgroup.pattern", DEFAULT_CGROUP_PATTERN },
+ { "lxc.cgroup.pattern", NULL },
{ "lxc.cgroup.use", NULL },
{ NULL, NULL },
};
#else
static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
#endif
+
+ /* user_config_path is freed as soon as it is used */
char *user_config_path = NULL;
+
+ /*
+ * The following variables are freed at bottom unconditionally.
+ * So NULL the value if it is to be returned to the caller
+ */
char *user_default_config_path = NULL;
char *user_lxc_path = NULL;
+ char *user_cgroup_pattern = NULL;
if (geteuid() > 0) {
const char *user_home = getenv("HOME");
sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home);
sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home);
sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home);
+ user_cgroup_pattern = strdup("%n");
}
else {
user_config_path = strdup(LXC_GLOBAL_CONF);
user_default_config_path = strdup(LXC_DEFAULT_CONFIG);
user_lxc_path = strdup(LXCPATH);
+ user_cgroup_pattern = strdup(DEFAULT_CGROUP_PATTERN);
}
const char * const (*ptr)[2];
free(user_config_path);
free(user_default_config_path);
free(user_lxc_path);
+ free(user_cgroup_pattern);
errno = EINVAL;
return NULL;
}
free(user_config_path);
free(user_default_config_path);
free(user_lxc_path);
+ free(user_cgroup_pattern);
return values[i];
}
if (!*p)
continue;
- free(user_default_config_path);
-
if (strcmp(option_name, "lxc.lxcpath") == 0) {
free(user_lxc_path);
user_lxc_path = copy_global_config_value(p);
remove_trailing_slashes(user_lxc_path);
values[i] = user_lxc_path;
+ user_lxc_path = NULL;
goto out;
}
values[i] = copy_global_config_value(p);
- free(user_lxc_path);
goto out;
}
}
if (strcmp(option_name, "lxc.lxcpath") == 0) {
remove_trailing_slashes(user_lxc_path);
values[i] = user_lxc_path;
- free(user_default_config_path);
+ user_lxc_path = NULL;
}
else if (strcmp(option_name, "lxc.default_config") == 0) {
values[i] = user_default_config_path;
- free(user_lxc_path);
+ user_default_config_path = NULL;
}
- else {
- free(user_default_config_path);
- free(user_lxc_path);
- values[i] = (*ptr)[1];
+ else if (strcmp(option_name, "lxc.cgroup.pattern") == 0) {
+ values[i] = user_cgroup_pattern;
+ user_cgroup_pattern = NULL;
}
+ else
+ values[i] = (*ptr)[1];
+
/* special case: if default value is NULL,
* and there is no config, don't view that
* as an error... */
if (fin)
fclose(fin);
+ free(user_cgroup_pattern);
+ free(user_default_config_path);
+ free(user_lxc_path);
+
return values[i];
}
#define LXC_VERSION_MAJOR 1
#define LXC_VERSION_MINOR 0
-#define LXC_VERSION_MICRO 6
-#define LXC_VERSION "1.0.6"
+#define LXC_VERSION_MICRO 7
+#define LXC_VERSION "1.0.7"
#endif
lxc-test-autostart \
lxc-test-ubuntu \
lxc-test-unpriv \
- lxc-test-usernic \
may_control.c \
saveconfig.c \
shutdowntest.c \
lxc-test-autostart \
lxc-test-ubuntu \
lxc-test-unpriv \
- lxc-test-usernic \
may_control.c \
saveconfig.c \
shutdowntest.c \
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
- if (errno == -EINTR)
+ if (errno == EINTR)
goto again;
perror("waitpid");
return -1;
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
- if (errno == -EINTR)
+ if (errno == EINTR)
goto again;
perror("waitpid");
return -1;
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
- if (errno == -EINTR)
+ if (errno == EINTR)
goto again;
perror("waitpid");
return -1;
goto out;
}
+ if (!c->set_config_item(c, "lxc.network.ipv4.gateway", "10.2.3.254")) {
+ fprintf(stderr, "%d: failed to set ipv4.gateway\n", __LINE__);
+ ret = 1;
+ goto out;
+ }
+
+ ret = c->get_config_item(c, "lxc.network.0.ipv4.gateway", v2, 255);
+ if (ret <= 0) {
+ fprintf(stderr, "%d: lxc.network.0.ipv4.gateway returned %d\n", __LINE__, ret);
+ ret = 1;
+ goto out;
+ }
+ if (!c->clear_config_item(c, "lxc.network.0.ipv4.gateway")) {
+ fprintf(stderr, "%d: failed clearing ipv4.gateway\n", __LINE__);
+ ret = 1;
+ goto out;
+ }
+ ret = c->get_config_item(c, "lxc.network.0.ipv4.gateway", v2, 255);
+ if (ret != 0) {
+ fprintf(stderr, "%d: after clearing ipv4.gateway get_item(lxc.network.0.ipv4.gateway returned %d\n", __LINE__, ret);
+ ret = 1;
+ goto out;
+ }
+
ret = c->get_config_item(c, "lxc.network.0.link", v2, 255);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item returned %d\n", __LINE__, ret);
useradd $TUSER
mkdir -p $HDIR
-echo "$TUSER veth lxcbr0 2" > /etc/lxc/lxc-usernet
+echo "$TUSER veth lxcbr0 2" >> /etc/lxc/lxc-usernet
sed -i '/^lxcunpriv:/d' /etc/subuid /etc/subgid
usermod -v 910000-919999 -w 910000-919999 $TUSER
run_cmd lxc-stop -n c2
+if which cgm >/dev/null 2>&1; then
+ echo "Testing containers under different cgroups per subsystem"
+ run_cmd cgm create freezer x1/x2
+ cgm movepid freezer x1 $$
+ run_cmd lxc-start -n c1 -d
+ p1=$(run_cmd lxc-info -n c1 -p -H)
+ [ "$p1" != "-1" ] || { echo "Failed to start container c1"; false; }
+ run_cmd lxc-info -n c1
+ run_cmd lxc-attach -n c1 -- /bin/true
+ run_cmd lxc-cgroup -n c1 freezer.state
+
+ echo "Testing lxc-attach and lxc-cgroup from different cgroup"
+ cgm movepid freezer x2 $$
+ run_cmd lxc-attach -n c1 -- /bin/true
+ run_cmd lxc-cgroup -n c1 freezer.state
+ run_cmd lxc-cgroup -n c1 memory.limit_in_bytes
+fi
+
DONE=1
+++ /dev/null
-#!/bin/bash
-
-# lxc: linux Container library
-
-# Authors:
-# Serge Hallyn <serge.hallyn@ubuntu.com>
-#
-# This is a test script for the lxc-user-nic program
-
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-# This test assumes an Ubuntu host
-
-DONE=0
-LXC_USER_NIC="/usr/local/libexec/lxc/lxc-user-nic"
-
-cleanup() {
- (
- set +e
-
- lxc-stop -n usernic-c1 -k
- lxc-destroy -n usernic-c1
-
- sed -i '/usernic-user/d' /run/lxc/nics /etc/lxc/lxc-usernet
- ifconfig usernic-br0 down
- ifconfig usernic-br1 down
- brctl delbr usernic-br0
- brctl delbr usernic-br1
-
- run_cmd "lxc-stop -n b1 -k"
- pkill -u $(id -u usernic-user) -9
-
- rm -rf /tmp/usernic-test /home/usernic-user /run/user/$(id -u usernic-user)
-
- deluser usernic-user
- ) >/dev/null 2>&1
-
- if [ "$DONE" = "1" ]; then
- echo "PASS"
- exit 0
- fi
-
- echo "FAIL"
- exit 1
-}
-
-run_cmd() {
- sudo -i -u usernic-user \
- env http_proxy=${http_proxy:-} https_proxy=${https_proxy:-} \
- XDG_RUNTIME_DIR=/run/user/$(id -u usernic-user) $*
-}
-
-ARCH=i386
-if type dpkg >/dev/null 2>&1; then
- ARCH=$(dpkg --print-architecture)
-fi
-
-set -eu
-trap cleanup EXIT SIGHUP SIGINT SIGTERM
-
-# create a test user
-deluser usernic-user || true
-useradd usernic-user
-sudo mkdir -p /home/usernic-user
-sudo chown usernic-user: /home/usernic-user
-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.network.type = empty
-lxc.id_map = u 0 910000 10000
-lxc.id_map = g 0 910000 10000
-EOF
-
-if which cgm >/dev/null 2>&1; then
- cgm create all $TUSER
- cgm chown all $TUSER $(id -u $TUSER) $(id -g $TUSER)
- cgm movepid all $TUSER $$
-elif [ -e /sys/fs/cgroup/cgmanager/sock ]; then
- for d in $(cut -d : -f 2 /proc/self/cgroup); do
- dbus-send --print-reply --address=unix:path=/sys/fs/cgroup/cgmanager/sock \
- --type=method_call /org/linuxcontainers/cgmanager org.linuxcontainers.cgmanager0_0.Create \
- string:$d string:usernic-user >/dev/null
-
- dbus-send --print-reply --address=unix:path=/sys/fs/cgroup/cgmanager/sock \
- --type=method_call /org/linuxcontainers/cgmanager org.linuxcontainers.cgmanager0_0.Chown \
- string:$d string:usernic-user int32:$(id -u usernic-user) int32:$(id -g usernic-user) >/dev/null
-
- dbus-send --print-reply --address=unix:path=/sys/fs/cgroup/cgmanager/sock \
- --type=method_call /org/linuxcontainers/cgmanager org.linuxcontainers.cgmanager0_0.MovePid \
- string:$d string:usernic-user int32:$$ >/dev/null
- done
-else
- for d in /sys/fs/cgroup/*; do
- [ ! -d $d/lxctest ] && mkdir $d/lxctest
- chown -R usernic-user: $d/lxctest
- echo $$ > $d/lxctest/tasks
- done
-fi
-
-mkdir -p /run/user/$(id -u usernic-user)
-chown -R usernic-user: /run/user/$(id -u usernic-user) /home/usernic-user
-
-# Copy the download template cache if available
-run_cmd "mkdir -p /home/usernic-user/.cache/lxc"
-[ -d /var/cache/lxc/download ] && \
- cp -R /var/cache/lxc/download /home/usernic-user/.cache/lxc && \
- chown -R usernic-user: /home/usernic-user/.cache/lxc
-
-
-# Create two test bridges
-brctl addbr usernic-br0
-brctl addbr usernic-br1
-ifconfig usernic-br0 0.0.0.0 up
-ifconfig usernic-br1 0.0.0.0 up
-
-ARCH=i386
-if type dpkg >/dev/null 2>&1; then
- ARCH=$(dpkg --print-architecture)
-fi
-
-# Create three containers
-run_cmd "lxc-create -t download -n b1 -- -d ubuntu -r trusty -a $ARCH"
-run_cmd "lxc-start -n b1 -d"
-p1=$(run_cmd "lxc-info -n b1 -p -H")
-
-# Assign one veth, should fail as no allowed entries yet
-if run_cmd "$LXC_USER_NIC $p1 veth usernic-br0 xx1"; then
- echo "FAIL: able to create nic with no entries"
- exit 1
-fi
-
-# Give him a quota of two
-touch /etc/lxc/lxc-usernet
-sed -i '/^usernic-user/d' /etc/lxc/lxc-usernet
-echo "usernic-user veth usernic-br0 2" >> /etc/lxc/lxc-usernet
-
-# Assign one veth to second bridge, should fail
-if run_cmd "$LXC_USER_NIC $p1 veth usernic-br1 xx1"; then
- echo "FAIL: able to create nic with no entries"
- exit 1
-fi
-
-# Assign two veths, should succeed
-if ! run_cmd "$LXC_USER_NIC $p1 veth usernic-br0 xx2"; then
- echo "FAIL: unable to create first nic"
- exit 1
-fi
-
-if ! run_cmd "$LXC_USER_NIC $p1 veth usernic-br0 xx3"; then
- echo "FAIL: unable to create second nic"
- exit 1
-fi
-
-# Assign one more veth, should fail.
-if run_cmd "$LXC_USER_NIC $p1 veth usernic-br0 xx4"; then
- echo "FAIL: able to create third nic"
- exit 1
-fi
-
-# Shut down and restart the container, should be able to assign more nics
-run_cmd "lxc-stop -n b1 -k"
-run_cmd "lxc-start -n b1 -d"
-p1=$(run_cmd "lxc-info -n b1 -p -H")
-
-if ! run_cmd "$LXC_USER_NIC $p1 veth usernic-br0 xx5"; then
- echo "FAIL: unable to create nic after destroying the old"
- cleanup 1
-fi
-
-run_cmd "lxc-stop -n b1 -k"
-
-# Create a root-owned ns
-lxc-create -t busybox -n usernic-c1
-lxc-start -n usernic-c1 -d
-p2=$(lxc-info -n usernic-c1 -p -H)
-
-# assign veth to it - should fail
-if run_cmd "$LXC_USER_NIC $p2 veth usernic-br0 xx6"; then
- echo "FAIL: able to attach nic to root-owned container"
- cleanup 1
-fi
-
-echo "All tests passed"
-DONE=1
EOF
if which cgm >/dev/null 2>&1; then
- cgm create all $TUSER
- cgm chown all $TUSER $(id -u $TUSER) $(id -g $TUSER)
- cgm movepid all $TUSER $$
+ cgm create all usernic-user
+ cgm chown all usernic-user $(id -u usernic-user) $(id -g usernic-user)
+ cgm movepid all usernic-user $$
elif [ -e /sys/fs/cgroup/cgmanager/sock ]; then
for d in $(cut -d : -f 2 /proc/self/cgroup); do
dbus-send --print-reply --address=unix:path=/sys/fs/cgroup/cgmanager/sock \
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
- if (errno == -EINTR)
+ if (errno == EINTR)
goto again;
perror("waitpid");
return -1;
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
- if (errno == -EINTR)
+ if (errno == EINTR)
goto again;
perror("waitpid");
return -1;
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
- if (errno == -EINTR)
+ if (errno == EINTR)
goto again;
perror("waitpid");
return -1;
cat >"$rootfs"/etc/inittab<<EOF
::sysinit:/sbin/rc sysinit
::wait:/sbin/rc default
+console:12345:respawn:/sbin/getty 38400 console
tty1:12345:respawn:/sbin/getty 38400 tty1
tty2:12345:respawn:/sbin/getty 38400 tty2
tty3:12345:respawn:/sbin/getty 38400 tty3
lxc.mount.entry=proc proc proc nodev,noexec,nosuid 0 0
lxc.mount.entry=run run tmpfs nodev,noexec,nosuid,relatime,size=1m,mode=0755 0 0
lxc.mount.entry=none dev/pts devpts gid=5,mode=620 0 0
-lxc.mount.entry=shm dev/shm tmpfs nodev,nosuid,noexec 0 0
+lxc.mount.entry=shm dev/shm tmpfs nodev,nosuid,noexec,mode=1777 0 0
EOF
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-# Detect use under userns (unsupported)
-for arg in "$@"; do
- [ "$arg" = "--" ] && break
- if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
- echo "This template can't be used for unprivileged containers." 1>&2
- echo "You may want to try the \"download\" template instead." 1>&2
- exit 1
- fi
-done
+LXC_MAPPED_UID=
+LXC_MAPPED_GID=
# Make sure the usual locations are in PATH
export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
done
echo "lxc.mount.entry = /sys/kernel/security sys/kernel/security none ro,bind,optional 0 0" >>$path/config
echo "lxc.mount.auto = proc:mixed sys" >>$path/config
+
+ if [ -f "$path/fstab" ]; then
+ echo "lxc.mount = $path/fstab" >>$path/config
+ fi
+}
+
+remap_userns()
+{
+ path=$1
+
+ if [ -n "$LXC_MAPPED_UID" ] && [ "$LXC_MAPPED_UID" != "-1" ]; then
+ chown $LXC_MAPPED_UID $path/config $path/fstab >/dev/null 2>&1
+ chown -R root $path/rootfs >/dev/null 2>&1
+ fi
+
+ if [ -n "$LXC_MAPPED_GID" ] && [ "$LXC_MAPPED_GID" != "-1" ]; then
+ chgrp $LXC_MAPPED_GID $path/config $path/fstab >/dev/null 2>&1
+ chgrp -R root $path/rootfs >/dev/null 2>&1
+ fi
}
usage()
return 0
}
-options=$(getopt -o hp:n: -l help,rootfs:,path:,name: -- "$@")
+options=$(getopt -o hp:n: -l help,rootfs:,path:,name:,mapped-uid:,mapped-gid: -- "$@")
if [ $? -ne 0 ]; then
usage $(basename $0)
exit 1
-p|--path) path=$2; shift 2;;
--rootfs) rootfs=$2; shift 2;;
-n|--name) name=$2; shift 2;;
+ --mapped-uid) LXC_MAPPED_UID=$2; shift 2;;
+ --mapped-gid) LXC_MAPPED_GID=$2; shift 2;;
--) shift 1; break ;;
*) break ;;
esac
echo "failed to write configuration file"
exit 1
fi
+
+remap_userns $path
+if [ $? -ne 0 ]; then
+ echo "failed to remap files to user"
+ exit 1
+fi
#
# If the root password contains a ding ($) then try to expand it.
# That will pick up things like ${name} and ${RANDOM}.
-# If the root password contians more than 3 consecutive X's, pass it as
+# If the root password contains more than 3 consecutive X's, pass it as
# a template to mktemp and take the result.
#
# If root_display_password = yes, display the temporary root password at exit.
cat <<EOF
usage:
$1 -n|--name=<container_name>
- [-p|--path=<path>] [-c|--clean] [-R|--release=<CentOS_release>] [-A|--arch=<arch of the container>]
+ [-p|--path=<path>] [-c|--clean] [-R|--release=<CentOS_release>] [-a|--arch=<arch of the container>]
[-h|--help]
Mandatory args:
-n,--name container name, used to as an identifier for that container from now on
root_password=$(eval echo "${root_password}")
fi
- # If it has more than 3 consequtive X's in it, feed it
+ # If it has more than 3 consecutive X's in it, feed it
# through mktemp as a template.
if [ $(expr "${root_password}" : '.*XXXX') != 0 ]
then
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Detect use under userns (unsupported)
-for arg in "$@"; do
- [ "$arg" = "--" ] && break
- if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
- echo "This template can't be used for unprivileged containers." 1>&2
- echo "You may want to try the \"download\" template instead." 1>&2
- exit 1
- fi
-done
-
# Make sure the usual locations are in PATH
export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
VERBOSITY=0
DOWNLOAD_URL="http://download.cirros-cloud.net/"
-CACHE_D="@LOCALSTATEDIR@/cache/lxc/cirros"
UNAME_M=$(uname -m)
ARCHES=( i386 x86_64 amd64 arm )
STREAMS=( released devel )
SOURCES=( nocloud none )
BUILD="standard"
+LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
+
+LXC_MAPPED_GID=
+LXC_MAPPED_UID=
DEF_VERSION="released"
DEF_SOURCE="nocloud"
*) DEF_ARCH="i386";;
esac
+am_in_userns() {
+ [ -e /proc/self/uid_map ] || { echo no; return; }
+ [ "$(wc -l /proc/self/uid_map | awk '{ print $1 }')" -eq 1 ] || { echo yes; return; }
+ line=$(awk '{ print $1 " " $2 " " $3 }' /proc/self/uid_map)
+ [ "$line" = "0 0 4294967295" ] && { echo no; return; }
+ echo yes
+}
+
+in_userns=0
+[ $(am_in_userns) = "yes" ] && in_userns=1
+
+if [ $(id -u) -eq 0 ]; then
+ CACHE_D="@LOCALSTATEDIR@/cache/lxc/cirros"
+else
+ CACHE_D="$HOME/.cache/lxc/cirros"
+fi
+
error() { echo "$@" 1>&2; }
inargs() {
local needle="$1" x=""
# kvm
lxc.cgroup.devices.allow = c 10:232 rwm
EOF
+
+ if [ $in_userns -eq 1 ] && [ -e "${LXC_TEMPLATE_CONFIG}/ubuntu-cloud.userns.conf" ]; then
+ echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/ubuntu.userns.conf" >> $path/config
+ echo "lxc.mount.auto = cgroup:mixed proc:mixed sys:ro" >> $path/config
+ fi
+
}
insert_ds_nocloud() {
mkdir -p "${rootfs_d}" ||
{ error "failed to make rootfs dir ${rootfs_d}"; return 1; }
- tar -C "${rootfs_d}" -Sxzf "${tarball}" ||
- { error "failed to populate ${rootfs_d}"; return 1; }
+ if [ $in_userns -eq 1 ]; then
+ tar -C "${rootfs_d}" --anchored --exclude="dev/*" -Sxzf "${tarball}" ||
+ { error "failed to populate ${rootfs_d}"; return 1; }
+ else
+ tar -C "${rootfs_d}" -Sxzf "${tarball}" ||
+ { error "failed to populate ${rootfs_d}"; return 1; }
+ fi
return 0
}
create_main() {
local short_opts="a:hn:p:S:uvV"
- local long_opts="arch:,auth-key:,name:,path:,tarball:,userdata:,verbose,version:,rootfs:"
+ local long_opts="arch:,auth-key:,name:,path:,tarball:,userdata:,verbose,version:,rootfs:,mapped-uid:,mapped-gid:"
local getopt_out=""
getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
--tarball) tarball="$next"; shift;;
--source) dsource="$next"; shift;;
--rootfs) rootfs_d="$next"; shift;;
+ --mapped-uid) LXC_MAPPED_UID=$next; shift;;
+ --mapped-gid) LXC_MAPPED_GID=$next; shift;;
--) shift; break;;
esac
shift;
extract_rootfs "${tarball}" "${rootfs_d}" || return
- # cirros 0.3.1 was broken for /dev/random and /dev/urandom
- if [ -b "$rootfs_d/dev/random" ]; then
- rm -f "$rootfs_d/dev/random" &&
- mknod --mode=666 "$rootfs_d/dev/random" c 1 8 ||
- { error "failed to fix /dev/random"; return 1; }
- fi
- if [ -b "$rootfs_d/dev/urandom" ]; then
- rm -f "$rootfs_d/dev/urandom" &&
- mknod --mode=666 "$rootfs_d/dev/urandom" c 1 9 ||
- { error "failed to fix /dev/urandom"; return 1; }
- fi
-
if [ "$version" = "0.3.2~pre1" ]; then
debug 1 "fixing console for lxc and '$version'"
sed -i 's,^\(#console.* 115200 \)# /dev/console,\1 console,g' \
# Make sure the usual locations are in PATH
export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
-MIRROR=${MIRROR:-http://cdn.debian.net/debian}
+MIRROR=${MIRROR:-http://http.debian.net/debian}
+SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.debian.org/}
LOCALSTATEDIR="@LOCALSTATEDIR@"
LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
fi
# remove pointless services in a container
- chroot $rootfs /usr/sbin/update-rc.d -f checkroot.sh remove
- chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove
- chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove
- chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove
+ chroot $rootfs /usr/sbin/update-rc.d -f checkroot.sh disable
+ chroot $rootfs /usr/sbin/update-rc.d -f umountfs disable
+ chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh disable
+ chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh disable
# generate new SSH keys
if [ -x $rootfs/var/lib/dpkg/info/openssh-server.postinst ]; then
return 0
}
+write_sourceslist()
+{
+ local rootfs="$1"; shift
+ local release="$1"; shift
+ local arch="$1"; shift
+
+ local prefix="deb"
+ if [ -n "${arch}" ]; then
+ prefix="deb [arch=${arch}]"
+ fi
+
+ cat >> "${rootfs}/etc/apt/sources.list" << EOF
+${prefix} $MIRROR ${release} main contrib non-free
+${prefix} $SECURITY_MIRROR ${release}/updates main contrib non-free
+EOF
+}
+
+configure_debian_systemd()
+{
+ path=$1
+ rootfs=$2
+
+ init="$(chroot ${rootfs} dpkg-query --search /sbin/init | cut -d : -f 1)"
+ if [ "$init" = "systemd-sysv" ]; then
+ # only appropriate when systemd is PID 1
+ echo 'lxc.autodev = 1' >> "$path/config"
+ echo 'lxc.kmsg = 0' >> "$path/config"
+ fi
+
+ # this only works if we have getty@.service to manipulate
+ if [ -f ${rootfs}/lib/systemd/system/getty\@.service ]; then
+ sed -e 's/^ConditionPathExists=/# ConditionPathExists=/' \
+ -e 's/After=dev-%i.device/After=/' \
+ < ${rootfs}/lib/systemd/system/getty\@.service \
+ > ${rootfs}/etc/systemd/system/getty\@.service
+ fi
+
+ # just in case systemd is not installed
+ mkdir -p ${rootfs}/{lib,etc}/systemd/system
+ mkdir -p ${rootfs}/etc/systemd/system/getty.target.wants
+
+ # This function has been copied and adapted from lxc-fedora
+ rm -f ${rootfs}/etc/systemd/system/default.target
+ touch ${rootfs}/etc/fstab
+ chroot ${rootfs} ln -s /dev/null /etc/systemd/system/udev.service
+ chroot ${rootfs} ln -s /dev/null /etc/systemd/system/systemd-udevd.service
+ chroot ${rootfs} ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
+ # Make systemd honor SIGPWR
+ chroot ${rootfs} ln -s /lib/systemd/system/halt.target /etc/systemd/system/sigpwr.target
+ # Setup getty service on the 4 ttys we are going to allow in the
+ # default config. Number should match lxc.tty
+ ( cd ${rootfs}/etc/systemd/system/getty.target.wants
+ for i in 1 2 3 4 ; do ln -sf ../getty\@.service getty@tty${i}.service; done )
+
+ return 0
+}
+
cleanup()
{
rm -rf $cache/partial-$release-$arch
return 0
}
+post_process()
+{
+ local rootfs="$1"; shift
+ local release="$1"; shift
+ local arch="$1"; shift
+ local hostarch="$1"; shift
+
+ # Disable service startup
+ cat > ${rootfs}/usr/sbin/policy-rc.d << EOF
+#!/bin/sh
+exit 101
+EOF
+ chmod +x ${rootfs}/usr/sbin/policy-rc.d
+
+ # If the container isn't running a native architecture, setup multiarch
+ if [ "${arch}" != "${hostarch}" ]; then
+ mkdir -p ${rootfs}/etc/dpkg/dpkg.cfg.d
+ echo "foreign-architecture ${hostarch}" > ${rootfs}/etc/dpkg/dpkg.cfg.d/lxc-multiarch
+ fi
+
+ # Write a new sources.list containing both native and multiarch entries
+ > ${rootfs}/etc/apt/sources.list
+ if [ "${arch}" = "${hostarch}" ]; then
+ write_sourceslist ${rootfs} ${release} ${arch}
+ else
+ write_sourceslist ${rootfs} ${release}
+ fi
+
+ # Re-enable service startup
+ rm ${rootfs}/usr/sbin/policy-rc.d
+}
+
clean()
{
cache="$LOCALSTATEDIR/cache/lxc/debian"
usage()
{
cat <<EOF
-$1 -h|--help -p|--path=<path> [-a|--arch] [-r|--release=<release>] [-c|--clean]
-release: the debian release (e.g. wheezy): defaults to current stable
+$1 -h|--help -p|--path=<path> [-a|--arch] [-c|--clean] [--mirror=<mirror>] [-r|--release=<release>] [--security-mirror=<security mirror>]
arch: the container architecture (e.g. amd64): defaults to host arch
+release: the debian release (e.g. wheezy): defaults to current stable
+mirror: debain mirror to use during installation
+security mirror: debain mirror to use for security updates
EOF
return 0
}
-options=$(getopt -o hp:n:a:r:c -l help,rootfs:,path:,name:,arch:,release:,clean -- "$@")
+options=$(getopt -o hp:n:a:r:c -l arch:,clean,help,mirror:,name:,path:,release:,rootfs:,security-mirror: -- "$@")
if [ $? -ne 0 ]; then
usage $(basename $0)
exit 1
while true
do
case "$1" in
- -h|--help) usage $0 && exit 1;;
- -p|--path) path=$2; shift 2;;
- --rootfs) rootfs=$2; shift 2;;
- -a|--arch) arch=$2; shift 2;;
- -r|--release) release=$2; shift 2;;
- -n|--name) name=$2; shift 2;;
- -c|--clean) clean=$2; shift 1;;
- --) shift 1; break ;;
- *) break ;;
+ -h|--help) usage $0 && exit 1;;
+ --) shift 1; break ;;
+
+ -a|--arch) arch=$2; shift 2;;
+ -c|--clean) clean=$2; shift 1;;
+ --mirror) MIRROR=$2; shift 2;;
+ -n|--name) name=$2; shift 2;;
+ -p|--path) path=$2; shift 2;;
+ -r|--release) release=$2; shift 2;;
+ --rootfs) rootfs=$2; shift 2;;
+ --security-mirror) SECURITY_MIRROR=$2; shift 2;;
+ *) break ;;
esac
done
fi
fi
-
install_debian $rootfs $release $arch
if [ $? -ne 0 ]; then
echo "failed to install debian"
exit 1
fi
+configure_debian_systemd $path $rootfs
+
+post_process ${rootfs} ${release} ${arch} ${hostarch}
+
if [ ! -z $clean ]; then
clean || exit 1
exit 0
#
# If the root password contains a ding ($) then try to expand it.
# That will pick up things like ${name} and ${RANDOM}.
-# If the root password contians more than 3 consecutive X's, pass it as
+# If the root password contains more than 3 consecutive X's, pass it as
# a template to mktemp and take the result.
#
# If root_display_password = yes, display the temporary root password at exit.
# (mounting the iso) to the stage0 setup.
# This system is designed to be as autonomous as possible so all whitelists
-# and controlls are self-contained.
+# and controls are self-contained.
# Initial testing - Whitelist nobody. Build for everybody...
# Initial deployment - Whitelist Fedora.
# We know we don't have a cache directory of this version or we
# would have never reached this code to begin with. But we may
# have another Fedora cache directory from which we could run...
- # We'll give a preference for close matches prefering higher over
+ # We'll give a preference for close matches preferring higher over
# lower - which makes for really ugly code...
# Is this a "bashism" that will need cleaning up????
root_password=$(eval echo "${root_password}")
fi
- # If it has more than 3 consequtive X's in it, feed it
+ # If it has more than 3 consecutive X's in it, feed it
# through mktemp as a template.
if [ $(expr "${root_password}" : '.*XXXX') != 0 ]
then
printf "### cache_precheck(): doing some pre-start checks ...\n"
# never hurts to have a fail-safe.
[[ -n "${cacheroot//\/}" ]] \
- || die 8 "\$cacheroot (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPERATORS, THIS IS *VERY* BAD!\n" "${cacheroot}"
+ || die 8 "\$cacheroot (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPARATORS, THIS IS *VERY* BAD!\n" "${cacheroot}"
}
#get latest stage3 tarball
printf "### container_precheck(): doing some pre-start checks ...\n"
# never hurts to have a fail-safe.
[[ -n "${name//\/}" ]] \
- || die 8 "\$name (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPERATORS, THIS IS *VERY* BAD!\n" "${name}"
+ || die 8 "\$name (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPARATORS, THIS IS *VERY* BAD!\n" "${name}"
[[ -n "${rootfs//\/}" ]] \
- || die 8 "\$rootfs (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPERATORS, THIS IS *VERY* BAD!\n" "${rootfs}"
+ || die 8 "\$rootfs (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPARATORS, THIS IS *VERY* BAD!\n" "${rootfs}"
[[ -n "${cachefs//\/}" ]] \
- || die 8 "\$cachefs (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPERATORS, THIS IS *VERY* BAD!\n" "${cachefs}"
+ || die 8 "\$cachefs (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPARATORS, THIS IS *VERY* BAD!\n" "${cachefs}"
# check if the rootfs already exists
[[ -d "${rootfs}/etc" ]] && die 18 "Error: \$rootfs (%s) already exists!" "${rootfs}"
#PKGDIR="\${PKGDIR}/amd64
#or PKGDIR="\${PKGDIR}/hardened"
EOF
- printf " => portage stuff done, see /etc/portage/make.conf for additionnal tricks\n"
+ printf " => portage stuff done, see /etc/portage/make.conf for additional tricks\n"
}
#Analyse network configuration in config
container_conf_net "$path/config" >> "${rootfs}/etc/conf.d/net"
- # found how much nic finaly have
+ # found how much nic finally have
nic_count=$(( ${nic_last} + 1 ))
# unless openrc manage a nic, we now have to force openrc to automatic
container_hostname()
{
printf "#### container_hostname(): setting hostname... \n"
- printf "hostnale=%s\n" "${name}" > "${rootfs}/etc/conf.d/hostname"
+ printf "hostname=\"%s\"\n" "${name}" > "${rootfs}/etc/conf.d/hostname"
printf " => done.\n"
}
-n|--name) name=$2; shift 2;;
-a|--arch) arch=$2; shift 2;;
-F|--flush-cache) flush_cache=1; shift 1;;
- -c|--cache-only) cache_only=1; shitf 1;;
+ -c|--cache-only) cache_only=1; shift 1;;
-P|--private-portage) private_portage=1; shift 1;;
-v|--variant) variant=$2; shift 2;;
--portage-dir) portage_dir=$2; shift 2;;
-P|--profile) profile=$2; shift 2;;
-c|--clean) clean=$2; shift 2;;
-R|--release) release=$2; shift 2;;
- -a|--arch) arch=$2; shift 2;;
+ -A|--arch) arch=$2; shift 2;;
-4|--ipv4) ipv4=$2; shift 2;;
-6|--ipv6) ipv6=$2; shift 2;;
-g|--gw) gw=$2; shift 2;;
exit 1
fi
+if grep -q Harlequin /etc/os-release || grep -q Tumbleweed /etc/os-release ; then
+ echo "Building containers on openSUSE 13.2 or Tumbleweed is broken at the moment. We are working on this problem."
+ exit 1
+fi
+
if [ "$(id -u)" != "0" ]; then
echo "This script should be run as 'root'"
exit 1
chmod 666 $rootfs/dev/random
mknod -m 666 $rootfs/dev/urandom c 1 9
mkdir -m 755 $rootfs/dev/pts
+ mkdir -m 755 $rootfs/dev/shm
chmod 666 $rootfs/dev/tty
chmod 600 $rootfs/dev/console
mknod -m 666 $rootfs/dev/tty0 c 4 0
write_sourceslist()
{
- # $1 => path to the rootfs
+ # $1 => path to the partial cache or the rootfs
# $2 => architecture we want to add
# $3 => whether to use the multi-arch syntax or not
if [ -n "$APT_PROXY" ]; then
- mkdir -p $rootfs/etc/apt/apt.conf.d
- cat > $rootfs/etc/apt/apt.conf.d/70proxy << EOF
+ mkdir -p $1/etc/apt/apt.conf.d
+ cat > $1/etc/apt/apt.conf.d/70proxy << EOF
Acquire::http::Proxy "$APT_PROXY" ;
EOF
fi