Merge git://github.com/lxc/lxc

Signed-off-by: Daniel Lezcano <daniel.lezcano@free.fr>
This commit is contained in:
Daniel Lezcano 2013-09-09 21:07:12 +02:00
commit be9f766c1e
194 changed files with 16302 additions and 4927 deletions

12
.gitignore vendored
View File

@ -28,6 +28,7 @@ templates/lxc-alpine
templates/lxc-altlinux
templates/lxc-archlinux
templates/lxc-busybox
templates/lxc-cirros
templates/lxc-debian
templates/lxc-fedora
templates/lxc-opensuse
@ -43,6 +44,7 @@ src/lxc/lxc-checkconfig
src/lxc/lxc-checkpoint
src/lxc/lxc-clone
src/lxc/lxc-console
src/lxc/lxc-config
src/lxc/lxc-create
src/lxc/lxc-destroy
src/lxc/lxc-execute
@ -52,6 +54,7 @@ src/lxc/lxc-info
src/lxc/lxc-init
src/lxc/lxc-kill
src/lxc/lxc-monitor
src/lxc/lxc-monitord
src/lxc/lxc-netstat
src/lxc/lxc-ps
src/lxc/lxc-restart
@ -64,20 +67,25 @@ src/lxc/lxc-unshare
src/lxc/lxc-version
src/lxc/lxc-wait
src/lxc/legacy/lxc-ls
src/lxc/lxc-user-nic
src/python-lxc/build/
src/python-lxc/lxc/__pycache__/
src/tests/lxc-test-cgpath
src/tests/lxc-test-clonetest
src/tests/lxc-test-console
src/tests/lxc-test-containertests
src/tests/lxc-test-createtest
src/tests/lxc-test-destroytest
src/tests/lxc-test-get_item
src/tests/lxc-test-getkeys
src/tests/lxc-test-locktests
src/tests/lxc-test-lxcpath
src/tests/lxc-test-saveconfig
src/tests/lxc-test-shutdowntest
src/tests/lxc-test-startone
src/tests/lxc-usernic-test
config/compile
config/config.guess
@ -104,3 +112,5 @@ src/stamp-h1
.pc
patches
*.orig
*.rej

View File

@ -40,6 +40,30 @@ You can submit your patches to the lxc-devel@lists.sourceforge.net mailing
list. Use https://lists.sourceforge.net/lists/listinfo/lxc-devel to subscribe
to the list.
Licensing for new files:
------------------------
LXC is made of files shipped under a few different licenses.
Anything that ends up being part of the LXC library needs to be released
under LGPLv2.1+ or a license compatible with it (though the latter will
only be accepted for cases where the code originated elsewhere and was
imported into LXC).
Language bindings for the libraries need to be released under LGPLv2.1+.
Anything else (non-libaries) needs to be Free Software and needs to be
allowed to link with LGPLv2.1+ code (if needed). LXC upstream prefers
LGPLv2.1+ or GPLv2 for those.
When introducing a new file into the project, please make sure it has a
copyright header making clear under which license it's being released
and if it doesn't match the criteria described above, please explain
your decision on the lxc-devel mailing-list when submitting your patch.
Developer Certificate of Origin:
--------------------------------

View File

@ -1,4 +1,25 @@
#!/bin/sh
#
# lxc: linux Container library
#
# (C) Copyright IBM Corp. 2007, 2008
#
# Authors:
# Daniel Lezcano <daniel.lezcano at free.fr>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
set -x

View File

@ -1,11 +1,11 @@
configdir = $(sysconfdir)/lxc
config_DATA = default.conf
defaultconf = @LXC_DEFAULT_CONF@
distroconf = @LXC_DISTRO_CONF@
EXTRA_DIST = default.conf.ubuntu default.conf.libvirt default.conf.unknown
default.conf:
cp $(defaultconf) $@
cp $(distroconf) $@
clean-local:
@$(RM) -f default.conf

View File

@ -6,7 +6,7 @@ AC_INIT([lxc], [0.9.0])
AC_CONFIG_SRCDIR([configure.ac])
AC_CONFIG_AUX_DIR([config])
AC_CONFIG_HEADERS([src/config.h])
AM_INIT_AUTOMAKE([-Wall -Werror -Wno-portability])
AM_INIT_AUTOMAKE([-Wall -Werror -Wno-portability subdir-objects])
AC_CANONICAL_HOST
AM_PROG_CC_C_O
AC_GNU_SOURCE
@ -39,19 +39,22 @@ if test "z$with_distro" = "z"; then
fi
case $with_distro in
ubuntu)
defaultconf=default.conf.ubuntu
distroconf=default.conf.ubuntu
;;
redhat|fedora|oracle|oracleserver)
defaultconf=default.conf.libvirt
distroconf=default.conf.libvirt
;;
*)
echo -n "Linux distribution network config unknown, defaulting to lxc.network.type = empty"
defaultconf=default.conf.unknown
distroconf=default.conf.unknown
;;
esac
AC_MSG_RESULT([$with_distro])
AM_CONDITIONAL([HAVE_DEBIAN], [test x"$with_distro" = "xdebian" -o x"$with_distro" = "xubuntu"])
AC_CHECK_PROG([NEWUIDMAP], [newuidmap], [newuidmap])
AM_CONDITIONAL([HAVE_NEWUIDMAP], [test -n "$NEWUIDMAP"])
# Allow disabling rpath
AC_ARG_ENABLE([rpath],
[AC_HELP_STRING([--disable-rpath], [do not set rpath in executables])],
@ -60,14 +63,15 @@ AM_CONDITIONAL([ENABLE_RPATH], [test "x$enable_rpath" = "xyes"])
# Documentation (manpages)
AC_ARG_ENABLE([doc],
[AC_HELP_STRING([--enable-doc], [make mans (require docbook2x-man installed) [default=auto]])],
[AC_HELP_STRING([--enable-doc], [make mans (requires docbook2man or docbook2x-man to be installed) [default=auto]])],
[], [enable_doc=auto])
if test "x$enable_doc" = "xyes" -o "x$enable_doc" = "xauto"; then
db2xman=""
dbparsers="docbook2x-man db2x_docbook2man docbook2man"
AC_MSG_CHECKING(for docbook2x-man)
for name in docbook2x-man db2x_docbook2man; do
for name in ${dbparsers}; do
if "$name" --help >/dev/null 2>&1; then
db2xman="$name"
break;
@ -87,6 +91,13 @@ if test "x$enable_doc" = "xyes" -o "x$enable_doc" = "xauto"; then
fi
AM_CONDITIONAL([ENABLE_DOCBOOK], [test "x$db2xman" != "x"])
if test "x$db2xman" = "xdocbook2man"; then
docdtd="\"-//Davenport//DTD DocBook V3.0//EN\""
else
docdtd="\"-//OASIS//DTD DocBook XML\" \"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd\""
fi
AC_SUBST(docdtd)
# Apparmor
AC_ARG_ENABLE([apparmor],
[AC_HELP_STRING([--enable-apparmor], [enable apparmor])],
@ -97,6 +108,8 @@ if test "$enable_apparmor" = "check" ; then
fi
AM_CONDITIONAL([ENABLE_APPARMOR], [test "x$enable_apparmor" = "xyes"])
AC_CHECK_LIB([gnutls], [gnutls_hash_fast])
AM_COND_IF([ENABLE_APPARMOR],
[AC_CHECK_HEADER([sys/apparmor.h],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
AC_CHECK_LIB([apparmor], [aa_change_profile],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
@ -137,22 +150,75 @@ AM_COND_IF([ENABLE_PYTHON],
PKG_CHECK_MODULES([PYTHONDEV], [python3 >= 3.2],[],[AC_MSG_ERROR([You must install python3-dev])])
AC_DEFINE_UNQUOTED([ENABLE_PYTHON], 1, [Python3 is available])])
# Lua module and scripts
if test x"$with_distro" = "xdebian" -o x"$with_distro" = "xubuntu" ; then
LUAPKGCONFIG=lua5.1
else
LUAPKGCONFIG=lua
fi
# Not in older autoconf versions
# AS_VAR_COPY(DEST, SOURCE)
# -------------------------
# Set the polymorphic shell variable DEST to the contents of the polymorphic
# shell variable SOURCE.
m4_ifdef([AS_VAR_COPY], [],
[AC_DEFUN([AS_VAR_COPY],
[AS_LITERAL_IF([$1[]$2], [$1=$$2], [eval $1=\$$2])])
])
dnl PKG_CHECK_VAR was introduced with pkg-config 0.28
m4_ifdef([PKG_CHECK_VAR], [],
[AC_DEFUN([PKG_CHECK_VAR],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
_PKG_CONFIG([$1], [variable="][$3]["], [$2])
AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])# PKG_CHECK_VAR
])
# Lua module and scripts
AC_ARG_ENABLE([lua],
[AC_HELP_STRING([--enable-lua], [enable lua binding])],
[enable_lua=yes], [enable_lua=no])
[], [enable_lua=check])
AM_CONDITIONAL([ENABLE_LUA], [test "x$enable_lua" = "xyes"])
AC_ARG_WITH([lua-pc],
[AS_HELP_STRING(
[--with-lua-pc=PKG],
[Specify pkg-config package name for lua]
)], [], [with_lua_pc=no])
if test "x$enable_lua" = "xyes" -a "x$with_lua_pc" != "xno"; then
# exit with error if not found
PKG_CHECK_MODULES([LUA], [$with_lua_pc], [LUAPKGCONFIG=$with_lua_pc])
fi
if test "x$enable_lua" = "xcheck" -a "x$with_lua_pc" != "xno"; then
PKG_CHECK_MODULES([LUA], [$with_lua_pc],
[LUAPKGCONFIG=$with_lua_pc
enable_lua=yes],
[enable_lua=no])
fi
if test "x$enable_lua" != "xno"; then
PKG_CHECK_MODULES([LUA], [lua], [LUAPKGCONFIG=lua],
[PKG_CHECK_MODULES([LUA], [lua5.2], [LUAPKGCONFIG=lua5.2],
[PKG_CHECK_MODULES([LUA], [lua5.1], [LUAPKGCONFIG=lua5.1],
[AS_IF([test "x$enable_lua" = "xyes"],
[AC_MSG_ERROR([Lua not found. Please use --with-lua-pc=PKG])],
[enable_lua=no])]
)]
)])
AS_IF([test "x$LUAPKGCONFIG" != "x"], [enable_lua=yes])
fi
AM_CONDITIONAL([ENABLE_LUA],
[test "x$enable_lua" = "xyes"])
AM_COND_IF([ENABLE_LUA],
[PKG_CHECK_MODULES([LUA], [$LUAPKGCONFIG >= 5.1],[],[AC_MSG_ERROR([You must install lua-devel for lua 5.1])])
AC_DEFINE_UNQUOTED([ENABLE_LUA], 1, [Lua is available])])
[AC_MSG_CHECKING([Lua version])
PKG_CHECK_VAR([LUA_VERSION], [$LUAPKGCONFIG], [V],,
[PKG_CHECK_VAR([LUA_VERSION], [$LUAPKGCONFIG], [major_version])])
AC_MSG_RESULT([$LUA_VERSION])
PKG_CHECK_VAR([LUA_INSTALL_CMOD], [$LUAPKGCONFIG], [INSTALL_CMOD],,
[LUA_INSTALL_CMOD=$libdir/lua/$LUA_VERSION])
PKG_CHECK_VAR([LUA_INSTALL_LMOD], [$LUAPKGCONFIG], [INSTALL_LMOD],,
[LUA_INSTALL_LMOD=$datadir/lua/$LUA_VERSION])
])
# Optional test binaries
AC_ARG_ENABLE([tests],
@ -176,6 +242,18 @@ AC_ARG_WITH([global-conf],
[global lxc configuration file]
)], [], [with_global_conf=['${sysconfdir}/lxc/lxc.conf']])
AC_ARG_WITH([usernic-conf],
[AC_HELP_STRING(
[--with-usernic-conf],
[user network interface configuration file]
)], [], [with_usernic_conf=['${sysconfdir}/lxc/lxc-usernet']])
AC_ARG_WITH([usernic-db],
[AC_HELP_STRING(
[--with-usernic-db],
[lxc user nic database]
)], [], [with_usernic_db=['/run/lxc/nics']])
# Rootfs path, where the container mount structure is assembled
AC_ARG_WITH([rootfs-path],
[AC_HELP_STRING(
@ -210,13 +288,16 @@ AS_AC_EXPAND(BINDIR, "$bindir")
AS_AC_EXPAND(LIBEXECDIR, "$libexecdir")
AS_AC_EXPAND(INCLUDEDIR, "$includedir")
AS_AC_EXPAND(SYSCONFDIR, "$sysconfdir")
AS_AC_EXPAND(LXC_DEFAULT_CONFIG, "$sysconfdir/lxc/default.conf")
AS_AC_EXPAND(DATADIR, "$datadir")
AS_AC_EXPAND(LOCALSTATEDIR, "$localstatedir")
AS_AC_EXPAND(DOCDIR, "$docdir")
AS_AC_EXPAND(LXC_DEFAULT_CONF, "$defaultconf")
AS_AC_EXPAND(LXC_DISTRO_CONF, "$distroconf")
AS_AC_EXPAND(LXC_GENERATE_DATE, "$(date)")
AS_AC_EXPAND(LXCPATH, "$with_config_path")
AS_AC_EXPAND(LXC_GLOBAL_CONF, "$with_global_conf")
AS_AC_EXPAND(LXC_USERNIC_CONF, "$with_usernic_conf")
AS_AC_EXPAND(LXC_USERNIC_DB, "$with_usernic_db")
AS_AC_EXPAND(LXCROOTFSMOUNT, "$with_rootfs_path")
AS_AC_EXPAND(LXCTEMPLATEDIR, "$datadir/lxc/templates")
AS_AC_EXPAND(LXCHOOKDIR, "$datadir/lxc/hooks")
@ -270,10 +351,10 @@ AM_CONDITIONAL([IS_BIONIC], [test "x$is_bionic" = "xyes"])
AC_CHECK_DECLS([PR_CAPBSET_DROP], [], [], [#include <sys/prctl.h>])
# Check for some headers
AC_CHECK_HEADERS([sys/signalfd.h pty.h sys/capability.h sys/personality.h utmpx.h sys/timerfd.h])
AC_CHECK_HEADERS([sys/signalfd.h pty.h ifaddrs.h sys/capability.h sys/personality.h utmpx.h sys/timerfd.h])
# Check for some syscalls functions
AC_CHECK_FUNCS([setns pivot_root sethostname unshare])
AC_CHECK_FUNCS([setns pivot_root sethostname unshare rand_r confstr])
# Check for some functions
AC_CHECK_LIB(util, openpty)
@ -326,7 +407,6 @@ AC_CONFIG_FILES([
doc/lxc-netstat.sgml
doc/lxc-ps.sgml
doc/lxc-restart.sgml
doc/lxc-shutdown.sgml
doc/lxc-start-ephemeral.sgml
doc/lxc-start.sgml
doc/lxc-stop.sgml
@ -355,6 +435,7 @@ AC_CONFIG_FILES([
hooks/Makefile
templates/Makefile
templates/lxc-cirros
templates/lxc-debian
templates/lxc-ubuntu
templates/lxc-ubuntu-cloud
@ -373,11 +454,7 @@ AC_CONFIG_FILES([
src/lxc/lxc-netstat
src/lxc/lxc-checkconfig
src/lxc/lxc-version
src/lxc/lxc-create
src/lxc/lxc-clone
src/lxc/lxc-shutdown
src/lxc/lxc-start-ephemeral
src/lxc/lxc-destroy
src/lxc/legacy/lxc-ls
src/lxc/lxc.functions

View File

@ -22,7 +22,6 @@ man_MANS = \
lxc-netstat.1 \
lxc-ps.1 \
lxc-restart.1 \
lxc-shutdown.1 \
lxc-start.1 \
lxc-stop.1 \
lxc-unfreeze.1 \

View File

@ -19,7 +19,7 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->

View File

@ -20,11 +20,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY seealso SYSTEM "@builddir@/../see_also.sgml">
]>
@ -50,7 +50,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<cmdsynopsis>
<command>lxc-ls</command>
<arg choice="opt">--active</arg>
<arg choice="opt">ls option</arg>
<arg choice="opt"><replaceable>ls options</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
@ -79,7 +79,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<varlistentry>
<term>
<option><optional>ls options</optional></option>
<option><optional><replaceable>ls options</replaceable></optional></option>
</term>
<listitem>
<para>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -17,11 +17,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -20,11 +20,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -50,13 +50,31 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsynopsisdiv>
<cmdsynopsis>
<command>lxc-clone</command>
<arg choice="opt">-s </arg>
<arg choice="opt">-K </arg>
<arg choice="opt">-M </arg>
<arg choice="opt">-H </arg>
<arg choice="opt">-B <replaceable>backingstore</replaceable></arg>
<arg choice="opt">-L <replaceable>fssize</replaceable></arg>
<arg choice="opt">-p <replaceable>lxcpath</replaceable></arg>
<arg choice="opt">-P <replaceable>newlxcpath</replaceable></arg>
<arg choice="req">-o <replaceable>orig</replaceable></arg>
<arg choice="req">-n <replaceable>new</replaceable></arg>
<arg choice="opt">-- hook arguments</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>lxc-clone</command>
<arg choice="opt">-s </arg>
<arg choice="opt">-K </arg>
<arg choice="opt">-M </arg>
<arg choice="opt">-H </arg>
<arg choice="opt">-B <replaceable>backingstore</replaceable></arg>
<arg choice="opt">-L <replaceable>fssize</replaceable></arg>
<arg choice="opt">-v <replaceable>vgname</replaceable></arg>
<arg choice="opt">-p <replaceable>lxc_lv_prefix</replaceable></arg>
<arg choice="opt">-t <replaceable>fstype</replaceable></arg>
<arg choice="opt">-p <replaceable>lxcpath</replaceable></arg>
<arg choice="opt">-P <replaceable>newlxcpath</replaceable></arg>
<arg choice="req">orig</arg>
<arg choice="req">new</arg>
<arg choice="opt">-- hook arguments</arg>
</cmdsynopsis>
</refsynopsisdiv>
@ -64,10 +82,29 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<title>Description</title>
<para>
<command>lxc-clone</command> Creates a new container as a copy of an existing
container. When the original container's rootfs is an LVM block device or
is on a btrfs filesystem, then a snapshotted clone can be created, taking up
very little initial disk space.
<command>lxc-clone</command> Creates a new container as a clone of an existing
container. Two types of clones are supported: copy and snapshot. A copy
clone copies the root filessytem from the original container to the new. A
snapshot filesystem uses the backing store's snapshot functionality to create
a very small copy-on-write snapshot of the original container. Snapshot
clones require the new container backing store to support snapshotting. Currently
this includes only btrfs, lvm, overlayfs and zfs. LVM devices do not support
snapshots fo snapshots.
</para>
<para>
The backing store of the new container will be the same type as the
original container,
with one exception: overlayfs snapshots can be created of directory backed
containers. This can be requested by using the <replaceable>-B overlayfs</replaceable>
arguments.
</para>
<para>
The names of the original and new container can be given (in that order)
after all options, or can be specified with the
<replaceable>-o</replaceable> and <replaceable>-n</replaceable> options,
respectively.
</para>
</refsect1>
@ -78,6 +115,108 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<variablelist>
<varlistentry>
<term>
<option>-s, --snapshot</option>
</term>
<listitem>
<para>
The new container's rootfs should be a LVM or btrfs snapshot of the original.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-K, --keepname</option>
</term>
<listitem>
<para>
Do not change the hostname of the container (in the root
filesystem).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-M, --keepmac</option>
</term>
<listitem>
<para>
Use the same MAC address as the original container, rather tahn
generating a new random one.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-H, --copyhooks</option>
</term>
<listitem>
<para>
Copy all mount hooks into the new container's directory, and
update any lxcpaths and container names as needed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-L, --fssize <replaceable>fssize</replaceable></option>
</term>
<listitem>
<para>
In the case of a block device backed container, a size for the new
block device. By default, the new device will be made the
same size as the original.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-p, --lxcpath <replaceable>fssize</replaceable></option>
</term>
<listitem>
<para>
The lxcpath of the original container. By default, the system
wide configured lxcpath will be used.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-P, --newpath <replaceable>fssize</replaceable></option>
</term>
<listitem>
<para>
The lxcpath for the new container. By default the same lxcpath
as the original will be used. Note that with btrfs snapshots,
changing lxcpaths may not be possible, as subvolume snapshots
must be in the same btrfs filesystem.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-B, --backingstore <replaceable>fssize</replaceable></option>
</term>
<listitem>
<para>
Select a different backing store for the new container. By
default the same as the original container's is used. Note that
currently changing the backingstore is only supported for
overlayfs snapshots of directory backed containers. Valid
backing stores include dir (directory), btrfs, lvm, zfs, loop
and overlayfs.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-o, --orig <replaceable>orig</replaceable></option>
@ -100,73 +239,28 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-s, --snapshot</option>
</term>
<listitem>
<para>
The new container's rootfs should be a LVM or btrfs snapshot of the original.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-L, --fssize <replaceable>fssize</replaceable></option>
</term>
<listitem>
<para>
In the case of a LVM-backed container, a size for the new
block device. By default, the new device will be made the
same size as the original.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-v, --vgname <replaceable>vgname</replaceable></option>
</term>
<listitem>
<para>
For an LVM-backed container, the volume group name to use. By
default it is 'lxc'.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-p, --lvprefix <replaceable>lxc_lv_prefix</replaceable></option>
</term>
<listitem>
<para>
For an LVM-backed container, a string to prefix to the container name to
form the logical volume name. For instance, specifying
<command>-n c1 -p lxc_</command> will cause the container rootfs to
be on a logical volume called <replaceable>lxc_c1</replaceable>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-t, --fstype <replaceable>fstype</replaceable></option>
</term>
<listitem>
<para>
For a non-snapshot LVM clone, the file system to use for the new
container. Note this option is ignored when requesting a
snapshotted container.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Clone hook</title>
<para>
If the container being cloned has one or more <filename>lxc.hook.clone</filename>
specified, then the specified hooks will be called for the new container. The
first 3 arguments passed to the clone hook will be the container name, a section
('lxc'), and the hook type ('clone'). Extra arguments passed
<command>lxc-clone</command> will be passed to the hook program starting at
argument 4. The <filename>LXC_ROOTFS_MOUNT</filename> environment variable gives
the path under which the container's root filesystem is mounted. The
configuration file pathname is stored in <filename>LXC_CONFIG_FILE</filename>, the
new container name in <filename>LXC_NAME</filename>, the old container name in
<filename>LXC_SRC_NAME</filename>, and the path or device on which
the rootfs is located is in <filename>LXC_ROOTFS_PATH</filename>.
</para>
</refsect1>
&seealso;
<refsect1>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -77,6 +77,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
the state it was before the disconnection.
</para>
<para>
A <replaceable>ttynum</replaceable> of 0 may be given to attach
to the container's /dev/console instead of its
dev/tty&lt;<replaceable>ttynum</replaceable>&gt;.
</para>
<para>
A keyboard escape sequence may be used to disconnect from the tty
and quit lxc-console. The default escape sequence is &lt;Ctrl+a q&gt;.
@ -107,8 +113,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</term>
<listitem>
<para>
Specify the tty number to connect, if not specified a tty
number will be automatically choosen by the container.
Specify the tty number to connect to or 0 for the console. If not
specified the next available tty number will be automatically
choosen by the container.
</para>
</listitem>
</varlistentry>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -125,16 +125,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</term>
<listitem>
<para>
'backingstore' is one of 'none', 'dir', 'lvm', or 'btrfs'. The
'backingstore' is one of 'none', 'dir', 'lvm', 'loop', or 'btrfs'. The
default is 'none', meaning that the container root filesystem
will be a directory under <filename>@LXCPATH@/container/rootfs</filename>.
'dir' has the same meaning as 'none', but also allows the optional
<replaceable>--dir ROOTFS</replaceable> to be specified, meaning
that the container rootfs should be placed under the specified path,
rather than the default.
The option 'btrfs' need not be specified as it will be used
automatically if the <filename>@LXCPATH@</filename> filesystem is found to
be btrfs. If backingstore is 'lvm', then an lvm block device will be
rather than the default. If 'btrfs' is specified, then the
target filesystem must be btrfs, and the container rootfs will be
created as a new subvolume. This allows snapshotted clones to be
created, but also causes rsync --one-filesystem to treat it as a
separate filesystem.
If backingstore is 'lvm', then an lvm block device will be
used and the following further options are available:
<replaceable>--lvname lvname1</replaceable> will create an LV
named <filename>lvname1</filename> rather than the default, which

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -81,17 +81,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-P, --lxcpath=<replaceable>PATH</replaceable></option></term>
<listitem>
<para>
Use an alternate container path. The default is @LXCPATH@.
</para>
</listitem>
</varlistentry>
</variablelist>
<varlistentry>
<term><option>-P, --lxcpath=<replaceable>PATH</replaceable></option></term>
<listitem>
<para>
Use an alternate container path. The default is @LXCPATH@.
</para>
</listitem>
</varlistentry>
</refsect1>
<refsect1>

View File

@ -18,11 +18,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -132,12 +132,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<para>
Signal the end of options and disables further option
processing. Any arguments after the -- are treated as
arguments.
arguments to <replaceable>command</replaceable>.
</para>
<para>
This option is useful when you want to execute, with the
command <command>lxc-execute</command>, a command line
with its own options.
This option is useful when you want specify options
to <replaceable>command</replaceable> and don't want
<command>lxc-execute</command> to interpret them.
</para>
</listitem>
</varlistentry>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -17,11 +17,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -48,9 +48,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<cmdsynopsis>
<command>lxc-info</command>
<arg choice="req">-n <replaceable>name</replaceable></arg>
<arg choice="req">-s</arg>
<arg choice="req">-p</arg>
<arg choice="req">-t <replaceable>state</replaceable></arg>
<arg choice="opt">-c <replaceable>KEY</replaceable></arg>
<arg choice="opt">-s</arg>
<arg choice="opt">-p</arg>
<arg choice="opt">-t <replaceable>state</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
@ -77,6 +78,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</listitem>
</varlistentry>
<varlistentry>
<term>
<option><optional>-c <replaceable>KEY</replaceable></optional></option>
</term>
<listitem>
<para>
Print a configuration key from the running container. This option
may be given mulitple times to print out multiple key = value pairs.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option><optional>-s</optional></option>
@ -135,6 +148,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</listitem>
</varlistentry>
<varlistentry>
<term>lxc-info -n foo -c lxc.network.0.veth.pair</term>
<listitem>
<para>
prints the veth pair name of foo.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -20,11 +20,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -63,22 +63,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
to monitor all the containers, several of them or just one.
</para>
<para>
The <option>-P, --lxcpath</option>=PATH option may be specified multiple
times to monitor more than one container path. Note however that
containers with the same name in multiple paths will be
indistinguishable in the output.
</para>
</refsect1>
&commonoptions;
<refsect1>
<title>Bugs</title>
<para>
Only one <command>lxc-monitor</command> can run at a time. Other
invocations will fail with the following error:
</para>
<para>
lxc-monitor: bind : Address already in use
</para>
</refsect1>
<refsect1>
<title>Examples</title>
<variablelist>

View File

@ -17,11 +17,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]>

View File

@ -20,11 +20,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]>
@ -52,7 +52,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<arg choice="opt">--name <replaceable>name</replaceable></arg>
<arg choice="opt">--lxc</arg>
<arg choice="opt">--host</arg>
<arg choice="opt">-- ps option</arg>
<arg choice="opt">-- <replaceable>ps options</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
@ -69,7 +69,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
the container associated to processes.
</para>
<para>
The additionnal specified ps options must not
The additional specified <replaceable>ps options</replaceable> must not
remove the default ps header and the pid information,
to be able to have the <command>lxc-ps</command> to find
the container associated to processes.
@ -119,7 +119,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<varlistentry>
<term>
<option><optional>ps options</optional></option>
<option><optional><replaceable>ps options</replaceable></optional></option>
</term>
<listitem>
<para>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -1,98 +0,0 @@
<!--
Copyright (C) 2012 Canonical, Inc
Authors: Serge Hallyn <serge.hallyn@canonical.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]>
<refentry>
<docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
<refmeta>
<refentrytitle>lxc-shutdown</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>lxc-shutdown</refname>
<refpurpose>
externally shut down or reboot a container
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>lxc-shutdown</command>
<arg choice="req">-n <replaceable>name</replaceable></arg>
<arg choice="opt">-w</arg>
<arg choice="opt">-r</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>lxc-shutdown</command> sends a SIGPWR signal to the
specified container to request it to cleanly shut down. If
<optional>-w</optional> is specified, then <command>lxc-shutdown</command>
will wait until the container has shut down before exiting.
If <optional>-r</optional> is specified, the container will be
asked to reboot (using a SIGINT signal), and <optional>-w</optional>
will be ignored. If the container ignore these signals, then
nothing will happen. In that case, you can use <command>lxc-stop</command>
to force the container to stop.
</para>
</refsect1>
&commonoptions;
&seealso;
<refsect1>
<title>Author</title>
<para>Serge Hallyn <email>serge.hallyn@canonical.com</email></para>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:2
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:nil
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
-->

View File

@ -18,11 +18,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -50,6 +50,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<cmdsynopsis>
<command>lxc-stop</command>
<arg choice="req">-n <replaceable>name</replaceable></arg>
<arg choice="opt">-W</arg>
<arg choice="opt">-r</arg>
<arg choice="opt">-t <replaceable>timeout</replaceable></arg>
<arg choice="opt">-k</arg>
<arg choice="opt">-s</arg>
</cmdsynopsis>
</refsynopsisdiv>
@ -57,14 +62,90 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<title>Description</title>
<para>
<command>lxc-stop</command> kills all the processes inside the
container. This command should be used if the processes are no
longer accessible and can no be exited normally.
<command>lxc-stop</command> reboots, cleanly shuts down, or kills
all the processes inside the container. By default, it will
request a clean shutdown of the container (by sending SIGPWR to
the container), wait 60 seconds for the container to exit, and
returns. If the container fails to cleanly exit, then after 60
seconds the container will be sent the
<command>lxc.stopsignal</command> to force it to shut down.
</para>
<para>
The <optional>-W</optional>, <optional>-r</optional>, <optional>-s</optional>
and <optional>-k</optional> options specify the action to perform.
<optional>-W</optional> indicates that after performing the specified
action, <command>lxc-stop</command> should immediately exit, while
<optional>-t TIMEOUT</optional> specifies the maximum amount of time
to wait for the container to complete the shutdown or reboot.
</para>
</refsect1>
&commonoptions;
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term>
<option>-r,--reboot </option>
</term>
<listitem>
<para>
Request a reboot of the container.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-s,--shutdown </option>
</term>
<listitem>
<para>
Only request a clean shutdown, do not kill the container tasks if the
clean shutdown fails.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-k,--kill </option>
</term>
<listitem>
<para>
Rather than requesting a clean shutdown of the container, explicitly
kill all tasks in the container. This is the legacy
<command>lxc-stop</command> behavior.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-W,--nowait </option>
</term>
<listitem>
<para>
Simply perform the requestion action (reboot, shutdown, or hard
kill) and exit.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-t,--timeout <replaceable>TIMEOUT</replaceable></option>
</term>
<listitem>
<para>
Wait TIMEOUT seconds before hard-stopping the container of (in
the reboot case) returning failure.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Diagnostic</title>
@ -92,7 +173,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -17,11 +17,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -20,11 +20,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -49,7 +49,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsynopsisdiv>
<cmdsynopsis>
<command>lxc-clone</command>
<command>lxc-unshare</command>
<arg choice="req">-s <replaceable>namespaces</replaceable></arg>
<arg choice="req">-u <replaceable>user</replaceable></arg>
<arg choice="req">command</arg>
@ -115,7 +115,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<para>
To spawn a new shell with its own UTS (hostname) namespace,
<programlisting>
lxc-clone -s UTSNAME /bin/bash
lxc-unshare -s UTSNAME /bin/bash
</programlisting>
If the hostname is changed in that shell, the change will not be
reflected on the host.
@ -123,7 +123,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<para>
To spawn a shell in a new network, pid, and mount namespace,
<programlisting>
lxc-clone -s "NETWORK|PID|MOUNT" /bin/bash
lxc-unshare -s "NETWORK|PID|MOUNT" /bin/bash
</programlisting>
The resulting shell will have pid 1 and will see no network interfaces.
After re-mounting /proc in that shell,

View File

@ -17,11 +17,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]>

View File

@ -20,11 +20,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]>
@ -65,8 +65,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<para>
The configuration file defines the different system resources to
be assigned for the container. At present, the utsname, the
network, the mount points, the root file system and the control
groups are supported.
network, the mount points, the root file system, the user namespace,
and the control groups are supported.
</para>
<para>
@ -75,12 +75,38 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
the line is a comment.
</para>
<refsect2>
<title>Configuration</title>
<para>
In order to ease administration of multiple related containers, it
is possible to have a container configuration file cause another
file to be loaded. For instance, network configuration
can be defined in one common file which is included by multiple
containers. Then, if the containers are moved to another host,
only one file may need to be updated.
</para>
<variablelist>
<varlistentry>
<term>
<option>lxc.include</option>
</term>
<listitem>
<para>
Specify the file to be included. The included file must be
in the same valid lxc configuration file format.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Architecture</title>
<para>
Allows to set the architecture for the container. For example,
set a 32bits architecture for a container running 32bits
binaries on a 64bits host. That fix the container scripts
binaries on a 64bits host. This fixes the container scripts
which rely on the architecture to do some work like
downloading the packages.
</para>
@ -229,7 +255,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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 locallay, or <option>bridge</option>, it
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
@ -258,7 +284,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
specify an action to do for the
network.
</para>
<para><option>up:</option> activates the interface.
</para>
</listitem>
@ -395,6 +421,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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>
@ -415,6 +446,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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>
@ -448,7 +484,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<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 goes the output of this console.
where the output of this console goes.
</para>
<variablelist>
<varlistentry>
@ -471,14 +507,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsect2>
<title>Console through the ttys</title>
<para>
If the container is configured with a root filesystem and the
inittab file is setup to launch a getty on the ttys. This
option will specify the number of ttys to be available for the
container. The number of getty in the inittab file of the
container should not be greater than the number of ttys
specified in this configuration file, otherwise the excess
getty sessions will die and respawn indefinitly giving
annoying messages on the console.
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>
@ -534,7 +570,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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. Addional
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>
@ -590,13 +626,20 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<para>
specify a file location in
the <filename>fstab</filename> format, containing the
mount informations. If the rootfs is an image file or a
device block and the fstab is used to mount a point
mount information. If the rootfs is an image file or a
block device and the fstab is used to mount a point
somewhere in this rootfs, the path of the rootfs mount
point should be prefixed with the
<filename>@LXCROOTFSMOUNT@</filename> default path or
the value of <option>lxc.rootfs.mount</option> if
specified.
specified. Note that when mounting a filesystem from an
image file or block device the third field (fs_vfstype)
cannot be auto as with
<citerefentry>
<refentrytitle>mount</refentrytitle>
<manvolnum>8</manvolnum>
</citerefentry>
but must be explicitly specified.
</para>
</listitem>
</varlistentry>
@ -728,6 +771,67 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</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>.
</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>
</variablelist>
</refsect2>
<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 should begin with a version number
(which currently must be 1) on the first line, a policy type
(which must be 'whitelist') on the second line, followed by a
list of allowed system call numbers, one per line.
</para>
<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>
</variablelist>
</refsect2>
@ -763,11 +867,37 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</refsect2>
<refsect2>
<title>Startup hooks</title>
<title>Container hooks</title>
<para>
Startup hooks are programs or scripts which can be executed
Container hooks are programs or scripts which can be executed
at various times in a container's lifetime.
</para>
<para>
When a container hook is executed, information is passed both
as command line arguments and through environment variables.
The arguments are:
<itemizedlist>
<listitem> Container name. </listitem>
<listitem> Section (always 'lxc'). </listitem>
<listitem> The hook type (i.e. 'clone' or 'pre-mount'). </listitem>
<listitem> Additional arguments In the
case of the clone hook, any extra arguments passed to
lxc-clone will appear as further arguments to the hook. </listitem>
</itemizedlist>
The following environment variables are set:
<itemizedlist>
<listitem> LXC_NAME: is the container's name. </listitem>
<listitem> LXC_ROOTFS_MOUNT: the path to the mounted root filesystem. </listitem>
<listitem> LXC_CONFIG_FILE: the path to the container configuration file. </listitem>
<listitem> LXC_SRC_NAME: in the case of the clone hook, this is the original container's name. </listitem>
<listitem> LXC_ROOTFS_PATH: this is the lxc.rootfs enty for the container. Note this is likely not where the mounted rootfs is to be found, use LXC_ROOTFS_MOUNT for that. </listitem>
</itemizedlist>
</para>
<para>
Standard output from the hooks is logged at debug level.
Standard error is not logged, but can be captured by the
hook redirecting its standard error to standard output.
</para>
<variablelist>
<varlistentry>
<term>
@ -859,10 +989,24 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</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 <refentrytitle><command>lxc-clone</command></refentrytitle>
<manvolnum>1</manvolnum> for more information.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Startup hooks Environment Variables</title>
<title>Container hooks Environment Variables</title>
<para>
A number of environment variables are made available to the startup
hooks to provide configuration information and assist in the
@ -893,7 +1037,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
addotional configuration information not otherwise made
additional configuration information not otherwise made
available. [<option>-f</option>]
</para>
</listitem>
@ -957,6 +1101,54 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</variablelist>
</refsect2>
<refsect2>
<title> Logging</title>
<para>
Logging can be configured on a per-container basis. By default,
depending upon how the lxc package was compiled, container startup
is logged only at the ERROR level, and logged to a file named after
the container (with '.log' appended) either under the container path,
or under @LOGPATH@.
</para>
<para>
Both the default log level and the log file can be specified in the
container configuration file, overriding the default behavior. Note
that the configuration file entries can in turn be overridden by the
command line options to <command>lxc-start</command>.
</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>
</variablelist>
</refsect2>
</refsect1>
@ -1069,8 +1261,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<citerefentry>
<refentrytitle><filename>fstab</filename></refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry>
</citerefentry>,
<citerefentry>
<refentrytitle><filename>capabilities</filename></refentrytitle>
<manvolnum>7</manvolnum>
</citerefentry>
</simpara>
</refsect1>

View File

@ -19,11 +19,11 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!DOCTYPE refentry PUBLIC @docdtd@ [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]>

View File

@ -19,7 +19,7 @@ Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-->

View File

@ -1,7 +1,9 @@
hooksdir=@LXCHOOKDIR@
hooks_SCRIPTS = \
clonehostname \
mountcgroups \
mountecryptfsroot
mountecryptfsroot \
ubuntu-cloud-prep
EXTRA_DIST=$(hooks_SCRIPTS)

29
hooks/clonehostname Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
#
# Update the hostname in the cloned container's scripts
#
# Copyright © 2013 Oracle.
#
# This library is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Note that /etc/hostname is updated by lxc itself
for file in \
$LXC_ROOTFS_PATH/etc/sysconfig/network \
$LXC_ROOTFS_PATH/etc/sysconfig/network-scripts/ifcfg-* ;
do
if [ -f $file ]; then
sed -i "s|$LXC_SRC_NAME|$LXC_NAME|" $file
fi
done
exit 0

View File

@ -14,7 +14,7 @@
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# This is an example hook to mount all mounted cgroups in the
@ -26,17 +26,40 @@
set -e
c=$1
configfile=$LXC_CONFIG_FILE
d=/sys/fs/cgroup
d2=$LXC_ROOTFS_MOUNT/${d}
# name lxc hook lxcpath
lxcpath=$4
if [ ! -d "$d" ]; then
exit 0
fi
mount -n -t tmpfs tmpfs ${d2}
do_devices_setup() {
local devdir="$1"
local c="$2"
local line
local w # which (allow or deny)
local v # value
egrep "^lxc.cgroup.devices.(allow|deny)[ \t]*=" ${configfile} | while read line; do
w=`echo $line | awk -F. '{ print $4 }' | awk '{ print $1 }'`
v=`echo $line | awk -F= '{ print $2 }'`
echo "$v" >> "$devdir"/devices.$w
done
}
# XXX TODO - we'll need to account for other cgroup groups beside 'lxc',
# i.e. 'build' or 'users/joe'.
for dir in `/bin/ls $d`; do
if [ "$dir" = "devices" ]; then
devicesdir="${d}/${dir}/lxc/${c}"
mkdir -p "$devicesdir"
# set the devices cgroup perms now - we can't change from blacklist to
# whitelist, or add perms, once we have children.
do_devices_setup "$devicesdir" "${c}"
fi
mkdir -p "${d}/${dir}/lxc/${c}/${c}.real"
echo 1 > "${d}/${dir}/lxc/${c}/${c}.real/tasks"
mkdir -p ${d2}/${dir}

View File

@ -14,7 +14,7 @@
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# This hook can be used to mount an ecryptfs filesystem as a container's
# rootfs.

184
hooks/ubuntu-cloud-prep Executable file
View File

@ -0,0 +1,184 @@
#!/bin/bash
## If the container being cloned has one or more lxc.hook.clone
## specified, then the specified hooks will be called for the new
## container. The arguments passed to the clone hook are:
## 1. the container name
## 2. a section ('lxc')
## 3. hook type ('clone')
## 4. .. additional arguments to lxc-clone
## Environment variables:
## LXC_ROOTFS_MOUNT: path to the root filesystem
## LXC_CONFIG_FILE: path to config file
## LXC_SRC_NAME: old container name
## LXC_ROOTFS_PATH: path or device on which the root fs is located
set -f
VERBOSITY="0"
error() { echo "$@" 1>&2; }
debug() { [ "$VERBOSITY" -ge "$1" ] || return; shift; error "$@"; }
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
prep_usage() {
cat <<EOF
Usage: ${0##*/} [options] root-dir
root-dir is the root directory to operate on
[ -C | --cloud ]: do not configure a datasource. incompatible with
options marked '[ds]'
[ -i | --instance-id]: instance-id for cloud-init, defaults to random [ds]
[ -L | --nolocales ]: Do not copy host's locales into container
[ -S | --auth-key ]: ssh public key file for datasource [ds]
[ -u | --userdata ]: user-data file for cloud-init [ds]
EOF
}
prep() {
local short_opts="Chi:L:S:u:v"
local long_opts="auth-key:,cloud,help,hostid:,name:,nolocales:,create-etc-init,userdata:,verbose"
local getopt_out getopt_ret
getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@" 2>/dev/null) ||
:
getopt_ret=$?
if [ $getopt_ret -eq 0 ]; then
eval set -- "${getopt_out}" ||
{ error "Unexpected error reading usage"; return 1; }
fi
local cur="" next=""
local userdata="" hostid="" authkey="" locales=1 cloud=0
local create_etc_init=0 name="ubuntucloud-lxc"
while [ $# -ne 0 ]; do
cur="$1"; next="$2";
case "$cur" in
-C|--cloud) cloud=1;;
-h|--help) prep_usage; return 0;;
--name) name="$next";;
-i|--hostid) hostid="$next";;
-L|--nolocales) locales=0;;
--create-etc-init) create_etc_init=1;;
-S|--auth-key)
[ -f "$next" ] ||
{ error "--auth-key: '$next' not a file"; return 1; }
authkey="$next";;
-u|--userdata)
[ -f "$next" ] ||
{ error "--userdata: '$next' not a file"; return 1; }
userdata="$next";;
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
--) shift; break;;
esac
shift;
done
[ $# -eq 1 ] || {
prep_usage 1>&2;
error "expected 1 arguments, got ($_LXC_HOOK) $#: $*";
return 1;
}
local root_d="$1";
if [ $getopt_ret -ne 0 -a "$_LXC_HOOK" = "clone" ]; then
# getopt above failed, but we were called from lxc clone. there might
# be multiple clone hooks and the args provided here not for us. This
# seems like not the greatest interface, so all we'll do is mention it.
error "${0##*}: usage failed, continuing with defaults"
fi
[ "$create_etc_init" -eq 0 ] ||
echo "#upstart needs help for overlayfs (LP: #1213925)." > \
"$root_d/etc/init/.overlayfs-upstart-helper" ||
{ error "failed to create /etc/init in overlay"; return 1; }
local seed_d=""
seed_d="$root_d/var/lib/cloud/seed/nocloud-net"
echo "$name" > "$root_d/etc/hostname" ||
{ error "failed to write /etc/hostname"; return 1; }
if [ $cloud -eq 1 ]; then
debug 1 "--cloud provided, not modifying seed in '$seed_d'"
else
if [ -z "$hostid" ]; then
hostid=$(uuidgen | cut -c -8) && [ -n "$hostid" ] ||
{ error "failed to get hostid"; return 1; }
fi
mkdir -p "$seed_d" ||
{ error "failed to create '$seed_d'"; return 1; }
echo "instance-id: lxc-$hostid" > "$seed_d/meta-data" ||
{ error "failed to write to $seed_d/meta-data"; return 1; }
echo "local-hostname: $name" >> "$seed_d/meta-data" ||
{ error "failed to write to $seed_d/meta-data"; return 1; }
if [ -n "$authkey" ]; then
{
echo "public-keys:" &&
sed -e '/^$/d' -e 's,^,- ,' "$authkey"
} >> "$seed_d/meta-data"
[ $? -eq 0 ] ||
{ error "failed to write public keys to metadata"; return 1; }
fi
local larch="usr/lib/locale/locale-archive"
if [ $locales -eq 1 ]; then
cp "/$larch" "$root_d/$larch" || {
error "failed to cp '/$larch' '$root_d/$larch'";
return 1;
}
fi
if [ -z "$MIRROR" ]; then
MIRROR="http://archive.ubuntu.com/ubuntu"
fi
if [ -n "$userdata" ]; then
cp "$userdata" "$seed_d/user-data"
else
{
local lc=$(locale | awk -F= '/LANG=/ {print $NF; }')
echo "#cloud-config"
echo "output: {all: '| tee -a /var/log/cloud-init-output.log'}"
echo "apt_mirror: $MIRROR"
echo "manage_etc_hosts: localhost"
[ -z "$LANG" ] || echo "locale: $LANG";
echo "password: ubuntu"
echo "chpasswd: { expire: false; }"
} > "$seed_d/user-data"
fi
[ $? -eq 0 ] || {
error "failed to write user-data write to '$seed_d/user-data'";
return 1;
}
fi
}
main() {
# main just joins 2 modes of being called. from user one from lxc clone
local _LXC_HOOK
if [ -n "$LXC_ROOTFS_MOUNT" -a "$3" = "clone" ]; then
_LXC_HOOK="clone"
local name="$1" create_etc_init=""
shift 3
# if mountpoint is overlayfs then add '--create-etc-init'
[ "${LXC_ROOTFS_PATH#overlayfs}" != "${LXC_ROOTFS_PATH}" ] &&
create_etc_init="--create-etc-init"
debug 1 prep "--name=$name" $create_etc_init "$LXC_ROOTFS_MOUNT" "$@"
prep "--name=$name" $create_etc_init "$LXC_ROOTFS_MOUNT" "$@"
else
_LXC_HOOK=""
prep "$@"
fi
return $?
}
main "$@"
# vi: ts=4 expandtab

View File

@ -18,7 +18,7 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Name: @PACKAGE@
Version: @VERSION@
@ -100,7 +100,6 @@ rm -rf %{buildroot}
%attr(4111,root,root) %{_bindir}/lxc-attach
%attr(4111,root,root) %{_bindir}/lxc-create
%attr(4111,root,root) %{_bindir}/lxc-clone
%attr(4111,root,root) %{_bindir}/lxc-shutdown
%attr(4111,root,root) %{_bindir}/lxc-start
%attr(4111,root,root) %{_bindir}/lxc-netstat
%attr(4111,root,root) %{_bindir}/lxc-unshare

View File

@ -1,4 +1,22 @@
#!/bin/sh
# liblxcapi
#
# Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
# Copyright © 2012 Canonical Ltd.
#
# 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
cleanup() {
rm -f /etc/lxc/test-busybox.conf

View File

@ -1,3 +1,32 @@
/*
* Copyright (c) 2006 SPARTA, Inc.
* All rights reserved.
*
* This software was developed by SPARTA ISSO under SPAWAR contract
* N66001-04-C-6019 ("SEFOS").
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>

View File

@ -1,6 +1,37 @@
/*
* Copyright (c) 2006 SPARTA, Inc.
* All rights reserved.
*
* This software was developed by SPARTA ISSO under SPAWAR contract
* N66001-04-C-6019 ("SEFOS").
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _getline_h
#define _getline_h
#include <stdio.h>
extern ssize_t getline(char **outbuf, size_t *outsize, FILE *fp);
#endif

597
src/include/ifaddrs.c Normal file
View File

@ -0,0 +1,597 @@
/*
Copyright (c) 2013, Kenneth MacKay
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ifaddrs.h"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
typedef struct NetlinkList
{
struct NetlinkList *m_next;
struct nlmsghdr *m_data;
unsigned int m_size;
} NetlinkList;
static int netlink_socket(void)
{
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if(l_socket < 0)
{
return -1;
}
struct sockaddr_nl l_addr;
memset(&l_addr, 0, sizeof(l_addr));
l_addr.nl_family = AF_NETLINK;
if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
{
close(l_socket);
return -1;
}
return l_socket;
}
static int netlink_send(int p_socket, int p_request)
{
char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
memset(l_buffer, 0, sizeof(l_buffer));
struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer;
struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
l_hdr->nlmsg_type = p_request;
l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
l_hdr->nlmsg_pid = 0;
l_hdr->nlmsg_seq = p_socket;
l_msg->rtgen_family = AF_UNSPEC;
struct sockaddr_nl l_addr;
memset(&l_addr, 0, sizeof(l_addr));
l_addr.nl_family = AF_NETLINK;
return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
}
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
{
struct msghdr l_msg;
struct iovec l_iov = { p_buffer, p_len };
struct sockaddr_nl l_addr;
for(;;)
{
l_msg.msg_name = (void *)&l_addr;
l_msg.msg_namelen = sizeof(l_addr);
l_msg.msg_iov = &l_iov;
l_msg.msg_iovlen = 1;
l_msg.msg_control = NULL;
l_msg.msg_controllen = 0;
l_msg.msg_flags = 0;
int l_result = recvmsg(p_socket, &l_msg, 0);
if(l_result < 0)
{
if(errno == EINTR)
{
continue;
}
return -2;
}
if(l_msg.msg_flags & MSG_TRUNC)
{ // buffer was too small
return -1;
}
return l_result;
}
}
static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
{
size_t l_size = 4096;
void *l_buffer = NULL;
for(;;)
{
free(l_buffer);
l_buffer = malloc(l_size);
int l_read = netlink_recv(p_socket, l_buffer, l_size);
*p_size = l_read;
if(l_read == -2)
{
free(l_buffer);
return NULL;
}
if(l_read >= 0)
{
pid_t l_pid = getpid();
struct nlmsghdr *l_hdr;
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
*p_done = 1;
break;
}
if(l_hdr->nlmsg_type == NLMSG_ERROR)
{
free(l_buffer);
return NULL;
}
}
return l_buffer;
}
l_size *= 2;
}
}
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
{
NetlinkList *l_item = malloc(sizeof(NetlinkList));
l_item->m_next = NULL;
l_item->m_data = p_data;
l_item->m_size = p_size;
return l_item;
}
static void freeResultList(NetlinkList *p_list)
{
NetlinkList *l_cur;
while(p_list)
{
l_cur = p_list;
p_list = p_list->m_next;
free(l_cur->m_data);
free(l_cur);
}
}
static NetlinkList *getResultList(int p_socket, int p_request)
{
if(netlink_send(p_socket, p_request) < 0)
{
return NULL;
}
NetlinkList *l_list = NULL;
NetlinkList *l_end = NULL;
int l_size;
int l_done = 0;
while(!l_done)
{
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
if(!l_hdr)
{ // error
freeResultList(l_list);
return NULL;
}
NetlinkList *l_item = newListItem(l_hdr, l_size);
if(!l_list)
{
l_list = l_item;
}
else
{
l_end->m_next = l_item;
}
l_end = l_item;
}
return l_list;
}
static size_t maxSize(size_t a, size_t b)
{
return (a > b ? a : b);
}
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
{
switch(p_family)
{
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
case AF_PACKET:
return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
default:
return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
}
}
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
{
switch(p_family)
{
case AF_INET:
memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
break;
case AF_INET6:
memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
break;
case AF_PACKET:
memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
break;
default:
memcpy(p_dest->sa_data, p_data, p_size);
break;
}
p_dest->sa_family = p_family;
}
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
{
if(!*p_resultList)
{
*p_resultList = p_entry;
}
else
{
struct ifaddrs *l_cur = *p_resultList;
while(l_cur->ifa_next)
{
l_cur = l_cur->ifa_next;
}
l_cur->ifa_next = p_entry;
}
}
static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
{
struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
size_t l_nameSize = 0;
size_t l_addrSize = 0;
size_t l_dataSize = 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
struct rtattr *l_rta;
for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFLA_ADDRESS:
case IFLA_BROADCAST:
l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
break;
case IFLA_IFNAME:
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
break;
case IFLA_STATS:
l_dataSize += NLMSG_ALIGN(l_rtaSize);
break;
default:
break;
}
}
struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize);
memset(l_entry, 0, sizeof(struct ifaddrs));
l_entry->ifa_name = "";
char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
char *l_addr = l_name + l_nameSize;
char *l_data = l_addr + l_addrSize;
l_entry->ifa_flags = l_info->ifi_flags;
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFLA_ADDRESS:
case IFLA_BROADCAST:
{
size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
if(l_rta->rta_type == IFLA_ADDRESS)
{
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
}
l_addr += NLMSG_ALIGN(l_addrLen);
break;
}
case IFLA_IFNAME:
strncpy(l_name, l_rtaData, l_rtaDataSize);
l_name[l_rtaDataSize] = '\0';
l_entry->ifa_name = l_name;
break;
case IFLA_STATS:
memcpy(l_data, l_rtaData, l_rtaDataSize);
l_entry->ifa_data = l_data;
break;
default:
break;
}
}
addToEnd(p_resultList, l_entry);
p_links[l_info->ifi_index - 1] = l_entry;
}
static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
{
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
size_t l_nameSize = 0;
size_t l_addrSize = 0;
int l_addedNetmask = 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
struct rtattr *l_rta;
for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
if(l_info->ifa_family == AF_PACKET)
{
continue;
}
switch(l_rta->rta_type)
{
case IFA_ADDRESS:
case IFA_LOCAL:
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
{ // make room for netmask
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
l_addedNetmask = 1;
}
case IFA_BROADCAST:
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
break;
case IFA_LABEL:
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
break;
default:
break;
}
}
struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
memset(l_entry, 0, sizeof(struct ifaddrs));
l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name;
char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
char *l_addr = l_name + l_nameSize;
l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags;
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFA_ADDRESS:
case IFA_BROADCAST:
case IFA_LOCAL:
{
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
if(l_info->ifa_family == AF_INET6)
{
if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
{
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
}
}
if(l_rta->rta_type == IFA_ADDRESS)
{ // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address
if(l_entry->ifa_addr)
{
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
}
else if(l_rta->rta_type == IFA_LOCAL)
{
if(l_entry->ifa_addr)
{
l_entry->ifa_dstaddr = l_entry->ifa_addr;
}
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
}
l_addr += NLMSG_ALIGN(l_addrLen);
break;
}
case IFA_LABEL:
strncpy(l_name, l_rtaData, l_rtaDataSize);
l_name[l_rtaDataSize] = '\0';
l_entry->ifa_name = l_name;
break;
default:
break;
}
}
if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
{
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
char l_mask[16] = {0};
unsigned i;
for(i=0; i<(l_prefix/8); ++i)
{
l_mask[i] = 0xff;
}
l_mask[i] = 0xff << (8 - (l_prefix % 8));
makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
l_entry->ifa_netmask = (struct sockaddr *)l_addr;
}
addToEnd(p_resultList, l_entry);
}
static void interpret(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
{
pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
break;
}
if(l_hdr->nlmsg_type == RTM_NEWLINK)
{
interpretLink(l_hdr, p_links, p_resultList);
}
else if(l_hdr->nlmsg_type == RTM_NEWADDR)
{
interpretAddr(l_hdr, p_links, p_resultList);
}
}
}
}
static unsigned countLinks(int p_socket, NetlinkList *p_netlinkList)
{
unsigned l_links = 0;
pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
break;
}
if(l_hdr->nlmsg_type == RTM_NEWLINK)
{
++l_links;
}
}
}
return l_links;
}
int getifaddrs(struct ifaddrs **ifap)
{
if(!ifap)
{
return -1;
}
*ifap = NULL;
int l_socket = netlink_socket();
if(l_socket < 0)
{
return -1;
}
NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
if(!l_linkResults)
{
close(l_socket);
return -1;
}
NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
if(!l_addrResults)
{
close(l_socket);
freeResultList(l_linkResults);
return -1;
}
unsigned l_numLinks = countLinks(l_socket, l_linkResults) + countLinks(l_socket, l_addrResults);
struct ifaddrs *l_links[l_numLinks];
memset(l_links, 0, l_numLinks * sizeof(struct ifaddrs *));
interpret(l_socket, l_linkResults, l_links, ifap);
interpret(l_socket, l_addrResults, l_links, ifap);
freeResultList(l_linkResults);
freeResultList(l_addrResults);
close(l_socket);
return 0;
}
void freeifaddrs(struct ifaddrs *ifa)
{
struct ifaddrs *l_cur;
while(ifa)
{
l_cur = ifa;
ifa = ifa->ifa_next;
free(l_cur);
}
}

54
src/include/ifaddrs.h Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 1995, 1999
* Berkeley Software Design, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
*/
#ifndef _IFADDRS_H_
#define _IFADDRS_H_
struct ifaddrs {
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr;
struct sockaddr *ifa_netmask;
struct sockaddr *ifa_dstaddr;
void *ifa_data;
};
/*
* This may have been defined in <net/if.h>. Note that if <net/if.h> is
* to be included it must be included before this header file.
*/
#ifndef ifa_broadaddr
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
#endif
#include <sys/cdefs.h>
__BEGIN_DECLS
extern int getifaddrs(struct ifaddrs **ifap);
extern void freeifaddrs(struct ifaddrs *ifa);
__END_DECLS
#endif

View File

@ -1,3 +1,23 @@
/* Utilities for reading/writing fstab, mtab, etc.
Copyright (C) 1995-2000, 2001, 2002, 2003, 2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <string.h>
#include <mntent.h>

View File

@ -1,3 +1,23 @@
/* Utilities for reading/writing fstab, mtab, etc.
Copyright (C) 1995-2000, 2001, 2002, 2003, 2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _lxcmntent_h
#define _lxcmntent_h
@ -15,6 +35,7 @@ struct mntent
};
extern struct mntent *getmntent (FILE *stream);
extern struct mntent *getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz);
#endif
#ifndef HAVE_SETMNTENT

View File

@ -1,21 +1,25 @@
/* Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
/*
* openpty: glibc implementation
*
* Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc.
*
* Authors:
* Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
*
* 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.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
* 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.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _XOPEN_SOURCE /* See feature_test_macros(7) */
#include <errno.h>

View File

@ -1,3 +1,26 @@
/*
* openpty: glibc implementation
*
* Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc.
*
* Authors:
* Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _openpty_h
#define _openpty_h

View File

@ -1,7 +1,7 @@
if ENABLE_LUA
luadir=$(datadir)/lua/5.1
sodir=$(libdir)/lua/5.1/lxc
luadir=$(LUA_INSTALL_LMOD)
sodir=$(LUA_INSTALL_CMOD)/lxc
lua_SCRIPTS=lxc.lua

View File

@ -6,27 +6,37 @@
* Authors:
* Dwight Engen <dwight.engen@oracle.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define LUA_LIB
#define _GNU_SOURCE
#include <lua.h>
#include <lauxlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <lxc/lxccontainer.h>
#if LUA_VERSION_NUM < 502
#define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l))
#define luaL_setfuncs(L,l,n) (assert(n==0), luaL_register(L,NULL,l))
#define luaL_checkunsigned(L,n) luaL_checknumber(L,n)
#endif
#ifdef NO_CHECK_UDATA
#define checkudata(L,i,tname) lua_touserdata(L, i)
#else
@ -111,7 +121,7 @@ static int container_create(lua_State *L)
argv[i] = strdupa(luaL_checkstring(L, i+3));
argv[i] = NULL;
lua_pushboolean(L, !!c->create(c, template_name, argv));
lua_pushboolean(L, !!c->create(c, template_name, NULL, NULL, 0, argv));
return 1;
}
@ -372,10 +382,24 @@ static int lxc_default_config_path_get(lua_State *L) {
return 1;
}
/* utility functions */
static int lxc_util_usleep(lua_State *L) {
usleep((useconds_t)luaL_checkunsigned(L, 1));
return 0;
}
static int lxc_util_dirname(lua_State *L) {
char *path = strdupa(luaL_checkstring(L, 1));
lua_pushstring(L, dirname(path));
return 1;
}
static luaL_Reg lxc_lib_methods[] = {
{"version_get", lxc_version_get},
{"default_config_path_get", lxc_default_config_path_get},
{"container_new", container_new},
{"usleep", lxc_util_usleep},
{"dirname", lxc_util_dirname},
{NULL, NULL}
};
@ -388,7 +412,7 @@ static int lxc_lib_uninit(lua_State *L) {
LUALIB_API int luaopen_lxc_core(lua_State *L) {
/* this is where we would initialize liblxc.so if we needed to */
luaL_register(L, "lxc", lxc_lib_methods);
luaL_newlib(L, lxc_lib_methods);
lua_newuserdata(L, 0);
lua_newtable(L); /* metatable */
@ -400,12 +424,12 @@ LUALIB_API int luaopen_lxc_core(lua_State *L) {
lua_rawset(L, -3);
luaL_newmetatable(L, CONTAINER_TYPENAME);
luaL_setfuncs(L, lxc_container_methods, 0);
lua_pushvalue(L, -1); /* push metatable */
lua_pushstring(L, "__gc");
lua_pushcfunction(L, container_gc);
lua_settable(L, -3);
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
luaL_register(L, NULL, lxc_container_methods);
lua_pop(L, 1);
return 1;
}

View File

@ -6,18 +6,19 @@
-- Authors:
-- Dwight Engen <dwight.engen@oracle.com>
--
-- This library is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License version 2, as
-- published by the Free Software Foundation.
-- 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 program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
-- 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 General Public License along
-- with this program; if not, write to the Free Software Foundation, Inc.,
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-- 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
--
local core = require("lxc.core")
@ -31,6 +32,11 @@ local lxc_path
local cgroup_path
local log_level = 3
-- lua 5.1 compat
if table.unpack == nil then
table.unpack = unpack
end
-- the following two functions can be useful for debugging
function printf(...)
local function wrapper(...) io.write(string.format(...)) end
@ -64,22 +70,6 @@ function string:split(delim, max_cols)
return cols
end
function dirname(path)
local f,output
f = io.popen("dirname " .. path)
output = f:read('*all')
f:close()
return output:sub(1,-2)
end
function basename(path, suffix)
local f,output
f = io.popen("basename " .. path .. " " .. (suffix or ""))
output = f:read('*all')
f:close()
return output:sub(1,-2)
end
function cgroup_path_get()
local f,line,cgroup_path
@ -88,9 +78,12 @@ function cgroup_path_get()
while true do
local c
line = f:read()
if line == nil then
break
end
c = line:split(" ", 6)
if (c[1] == "cgroup") then
cgroup_path = dirname(c[2])
cgroup_path = core.dirname(c[2])
break
end
end
@ -261,7 +254,7 @@ end
-- methods for stats collection from various cgroup files
-- read integers at given coordinates from a cgroup file
function container:stat_get_ints(controller, item, coords)
local f = io.open(cgroup_path.."/"..controller.."/lxc/"..self.ctname.."/"..item, "r")
local f = io.open(cgroup_path.."/"..controller.."/"..self.ctname.."/"..item, "r")
local lines = {}
local result = {}
@ -282,12 +275,12 @@ function container:stat_get_ints(controller, item, coords)
table.insert(result, val)
end
end
return unpack(result)
return table.unpack(result)
end
-- read an integer from a cgroup file
function container:stat_get_int(controller, item)
local f = io.open(cgroup_path.."/"..controller.."/lxc/"..self.ctname.."/"..item, "r")
local f = io.open(cgroup_path.."/"..controller.."/"..self.ctname.."/"..item, "r")
if (not f) then
return 0
end
@ -301,36 +294,23 @@ end
function container:stat_match_get_int(controller, item, match, column)
local val
local f = io.open(cgroup_path.."/"..controller.."/lxc/"..self.ctname.."/"..item, "r")
local f = io.open(cgroup_path.."/"..controller.."/"..self.ctname.."/"..item, "r")
if (not f) then
return 0
end
for line in f:lines() do
printf("matching line:%s with match:%s\n", line, match)
if (string.find(line, match)) then
local col
col = line:split(" ", 80)
val = tonumber(col[column]) or 0
printf("found line!! val:%d\n", val)
end
end
f:close()
return val
end
function stats_clear(stat)
stat.mem_used = 0
stat.mem_limit = 0
stat.memsw_used = 0
stat.memsw_limit = 0
stat.cpu_use_nanos = 0
stat.cpu_use_user = 0
stat.cpu_use_sys = 0
stat.blkio = 0
end
function container:stats_get(total)
local stat = {}
stat.mem_used = self:stat_get_int("memory", "memory.usage_in_bytes")
@ -355,10 +335,32 @@ function container:stats_get(total)
return stat
end
local M = { container = container }
function M.stats_clear(stat)
stat.mem_used = 0
stat.mem_limit = 0
stat.memsw_used = 0
stat.memsw_limit = 0
stat.cpu_use_nanos = 0
stat.cpu_use_user = 0
stat.cpu_use_sys = 0
stat.blkio = 0
end
function M.stats_clear(stat)
stat.mem_used = 0
stat.mem_limit = 0
stat.memsw_used = 0
stat.memsw_limit = 0
stat.cpu_use_nanos = 0
stat.cpu_use_user = 0
stat.cpu_use_sys = 0
stat.blkio = 0
end
-- return configured containers found in LXC_PATH directory
function containers_configured(names_only)
function M.containers_configured(names_only)
local containers = {}
for dir in lfs.dir(lxc_path) do
@ -386,39 +388,29 @@ function containers_configured(names_only)
end
-- return running containers found in cgroup fs
function containers_running(names_only)
function M.containers_running(names_only)
local containers = {}
local attr
local names = M.containers_configured(true)
-- the lxc directory won't exist if no containers has ever been started
attr = lfs.attributes(cgroup_path .. "/cpu/lxc")
if (not attr) then
return containers
end
for file in lfs.dir(cgroup_path .. "/cpu/lxc") do
if (file ~= "." and file ~= "..")
then
local pathfile = cgroup_path .. "/cpu/lxc/" .. file
local attr = lfs.attributes(pathfile)
if (attr.mode == "directory") then
for _,name in ipairs(names) do
local ct = container:new(name)
if ct:running() then
-- note, this is a "mixed" table, ie both dictionary and list
table.insert(containers, name)
if (names_only) then
-- note, this is a "mixed" table, ie both dictionary and list
containers[file] = true
table.insert(containers, file)
containers[name] = true
ct = nil
else
local ct = container:new(file)
-- note, this is a "mixed" table, ie both dictionary and list
containers[file] = ct
table.insert(containers, file)
containers[name] = ct
end
end
end
end
table.sort(containers, function (a,b) return (a < b) end)
return containers
end
lxc_path = core.default_config_path_get()
cgroup_path = cgroup_path_get()
return M

View File

@ -1,25 +1,28 @@
pkginclude_HEADERS = \
arguments.h \
start.h \
console.h \
error.h \
monitor.h \
utils.h \
namespace.h \
attach.h \
attach_options.h \
bdev.h \
caps.h \
lxc.h \
cgroup.h \
conf.h \
console.h \
error.h \
list.h \
log.h \
state.h \
attach.h \
lxccontainer.h \
lxc.h \
lxclock.h \
monitor.h \
namespace.h \
start.h \
state.h \
utils.h \
version.h
if IS_BIONIC
pkginclude_HEADERS += \
../include/ifaddrs.h \
../include/openpty.h \
../include/lxcmntent.h
endif
@ -36,9 +39,9 @@ so_PROGRAMS = liblxc.so
liblxc_so_SOURCES = \
arguments.c arguments.h \
bdev.c bdev.h \
commands.c commands.h \
start.c start.h \
stop.c \
execute.c \
monitor.c monitor.h \
console.c \
@ -60,9 +63,9 @@ liblxc_so_SOURCES = \
attach.c attach.h \
\
network.c network.h \
nl.c nl.h \
rtnl.c rtnl.h \
genl.c genl.h \
nl.c nl.h \
rtnl.c rtnl.h \
genl.c genl.h \
\
caps.c caps.h \
lxcseccomp.h \
@ -77,6 +80,7 @@ liblxc_so_SOURCES = \
if IS_BIONIC
liblxc_so_SOURCES += \
../include/ifaddrs.c ../include/ifaddrs.h \
../include/openpty.c ../include/openpty.h \
../include/lxcmntent.c ../include/lxcmntent.h
endif
@ -93,12 +97,19 @@ AM_CFLAGS=-I$(top_srcdir)/src \
-DLXC_GLOBAL_CONF=\"$(LXC_GLOBAL_CONF)\" \
-DLXCINITDIR=\"$(LXCINITDIR)\" \
-DLXCTEMPLATEDIR=\"$(LXCTEMPLATEDIR)\" \
-DLOGPATH=\"$(LOGPATH)\"
-DLOGPATH=\"$(LOGPATH)\" \
-DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\" \
-DLXC_USERNIC_DB=\"$(LXC_USERNIC_DB)\" \
-DLXC_USERNIC_CONF=\"$(LXC_USERNIC_CONF)\"
if ENABLE_APPARMOR
AM_CFLAGS += -DHAVE_APPARMOR
endif
if HAVE_NEWUIDMAP
AM_CFLAGS += -DHAVE_NEWUIDMAP
endif
if USE_CONFIGPATH_LOGS
AM_CFLAGS += -DUSE_CONFIGPATH_LOGS
endif
@ -120,11 +131,7 @@ bin_SCRIPTS = \
lxc-ps \
lxc-netstat \
lxc-checkconfig \
lxc-version \
lxc-create \
lxc-clone \
lxc-shutdown \
lxc-destroy
lxc-version
EXTRA_DIST = \
lxc-device \
@ -132,15 +139,15 @@ EXTRA_DIST = \
lxc-top
if ENABLE_PYTHON
bin_SCRIPTS += lxc-device
bin_SCRIPTS += lxc-ls
bin_SCRIPTS += lxc-start-ephemeral
bin_SCRIPTS += lxc-device
bin_SCRIPTS += lxc-ls
bin_SCRIPTS += lxc-start-ephemeral
else
bin_SCRIPTS += legacy/lxc-ls
bin_SCRIPTS += legacy/lxc-ls
endif
if ENABLE_LUA
bin_SCRIPTS += lxc-top
bin_SCRIPTS += lxc-top
endif
bin_PROGRAMS = \
@ -148,8 +155,10 @@ bin_PROGRAMS = \
lxc-unshare \
lxc-stop \
lxc-start \
lxc-clone \
lxc-execute \
lxc-monitor \
lxc-monitord \
lxc-wait \
lxc-console \
lxc-freeze \
@ -158,14 +167,19 @@ bin_PROGRAMS = \
lxc-unfreeze \
lxc-checkpoint \
lxc-restart \
lxc-kill
lxc-kill \
lxc-config \
lxc-destroy \
lxc-create \
lxc-user-nic
if HAVE_NEWUIDMAP
bin_PROGRAMS += lxc-usernsexec
endif
pkglibexec_PROGRAMS = \
lxc-init
#pkglibexec_SCRIPTS = \
# lxc.functions
AM_LDFLAGS = -Wl,-E
if ENABLE_RPATH
AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
@ -175,19 +189,26 @@ LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SECCOMP_LIBS@
lxc_attach_SOURCES = lxc_attach.c
lxc_cgroup_SOURCES = lxc_cgroup.c
lxc_checkpoint_SOURCES = lxc_checkpoint.c
lxc_config_SOURCES = lxc_config.c
lxc_console_SOURCES = lxc_console.c
lxc_destroy_SOURCES = lxc_destroy.c
lxc_execute_SOURCES = lxc_execute.c
lxc_freeze_SOURCES = lxc_freeze.c
lxc_info_SOURCES = lxc_info.c
lxc_init_SOURCES = lxc_init.c
lxc_monitor_SOURCES = lxc_monitor.c
lxc_monitord_SOURCES = lxc_monitord.c
lxc_restart_SOURCES = lxc_restart.c
lxc_clone_SOURCES = lxc_clone.c
lxc_start_SOURCES = lxc_start.c
lxc_stop_SOURCES = lxc_stop.c
lxc_unfreeze_SOURCES = lxc_unfreeze.c
lxc_unshare_SOURCES = lxc_unshare.c
lxc_wait_SOURCES = lxc_wait.c
lxc_kill_SOURCES = lxc_kill.c
lxc_create_SOURCES = lxc_create.c
lxc_usernsexec_SOURCES = lxc_usernsexec.c
lxc_user_nic_SOURCES = lxc_user_nic.c
install-exec-local: install-soPROGRAMS
mkdir -p $(DESTDIR)$(datadir)/lxc

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <unistd.h>
@ -36,6 +36,7 @@ lxc_log_define(lxc_af_unix, lxc);
int lxc_af_unix_open(const char *path, int type, int flags)
{
int fd;
size_t len;
struct sockaddr_un addr;
if (flags & O_TRUNC)
@ -52,8 +53,16 @@ int lxc_af_unix_open(const char *path, int type, int flags)
addr.sun_family = AF_UNIX;
/* copy entire buffer in case of abstract socket */
memcpy(addr.sun_path, path,
path[0]?strlen(path):sizeof(addr.sun_path));
len = sizeof(addr.sun_path);
if (path[0]) {
len = strlen(path);
if (len >= sizeof(addr.sun_path)) {
close(fd);
errno = ENAMETOOLONG;
return -1;
}
}
memcpy(addr.sun_path, path, len);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
int tmp = errno;
@ -61,7 +70,7 @@ int lxc_af_unix_open(const char *path, int type, int flags)
errno = tmp;
return -1;
}
if (type == SOCK_STREAM && listen(fd, 100)) {
int tmp = errno;
close(fd);
@ -75,8 +84,8 @@ int lxc_af_unix_open(const char *path, int type, int flags)
int lxc_af_unix_close(int fd)
{
struct sockaddr_un addr;
socklen_t addrlen;
socklen_t addrlen = sizeof(addr);
if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) &&
addr.sun_path[0])
unlink(addr.sun_path);

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
extern int lxc_af_unix_open(const char *path, int type, int flags);

View File

@ -1,3 +1,23 @@
/* apparmor
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -36,16 +56,19 @@ again:
f = fopen(path, "r");
if (!f) {
SYSERROR("opening %s\n", path);
if (buf)
free(buf);
return NULL;
}
sz += 1024;
buf = realloc(buf, sz);
memset(buf, 0, sz);
if (!buf) {
ERROR("out of memory");
fclose(f);
return NULL;
}
ret = fread(buf, 1, sz, f);
ret = fread(buf, 1, sz - 1, f);
fclose(f);
if (ret >= sz)
goto again;

View File

@ -1,3 +1,23 @@
/* apparmor
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <lxc/start.h> /* for lxc_handler */
#include <lxc/conf.h>

View File

@ -19,7 +19,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
@ -147,16 +147,37 @@ for any corresponding short options.\n\
See the %s man page for further information.\n\n",
args->progname, args->help, args->progname);
if (args->helpfn)
args->helpfn(args);
exit(code);
}
static int lxc_arguments_lxcpath_add(struct lxc_arguments *args,
const char *lxcpath)
{
if (args->lxcpath_additional != -1 &&
args->lxcpath_cnt > args->lxcpath_additional) {
fprintf(stderr, "This command only accepts %d -P,--lxcpath arguments\n",
args->lxcpath_additional + 1);
exit(EXIT_FAILURE);
}
args->lxcpath = realloc(args->lxcpath, (args->lxcpath_cnt + 1) *
sizeof(args->lxcpath[0]));
if (args->lxcpath == NULL) {
lxc_error(args, "no memory");
return -ENOMEM;
}
args->lxcpath[args->lxcpath_cnt++] = lxcpath;
return 0;
}
extern int lxc_arguments_parse(struct lxc_arguments *args,
int argc, char * const argv[])
{
char shortopts[256];
int ret = 0;
args->lxcpath = default_lxc_path();
ret = build_shortopts(args->options, shortopts, sizeof(shortopts));
if (ret < 0) {
lxc_error(args, "build_shortopts() failed : %s",
@ -174,9 +195,12 @@ extern int lxc_arguments_parse(struct lxc_arguments *args,
case 'n': args->name = optarg; break;
case 'o': args->log_file = optarg; break;
case 'l': args->log_priority = optarg; break;
case 'c': args->console = optarg; break;
case 'q': args->quiet = 1; break;
case 'P': args->lxcpath = optarg; break;
case 'P':
ret = lxc_arguments_lxcpath_add(args, optarg);
if (ret < 0)
return ret;
break;
case OPT_USAGE: print_usage(args->options, args);
case '?': print_help(args, 1);
case 'h': print_help(args, 0);
@ -195,6 +219,13 @@ extern int lxc_arguments_parse(struct lxc_arguments *args,
args->argv = &argv[optind];
args->argc = argc - optind;
/* If no lxcpaths were given, use default */
if (!args->lxcpath_cnt) {
ret = lxc_arguments_lxcpath_add(args, default_lxc_path());
if (ret < 0)
return ret;
}
/* Check the command options */
if (!args->name) {

View File

@ -19,7 +19,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __arguments_h
#define __arguments_h
@ -33,6 +33,7 @@ typedef int (*lxc_arguments_checker_t) (const struct lxc_arguments *);
struct lxc_arguments {
const char *help;
void(*helpfn)(const struct lxc_arguments *);
const char *progname;
const struct option* options;
lxc_arguments_parser_t parser;
@ -47,7 +48,10 @@ struct lxc_arguments {
const char *console;
const char *console_log;
const char *pidfile;
const char *lxcpath;
const char **lxcpath;
int lxcpath_cnt;
/* set to 0 to accept only 1 lxcpath, -1 for unlimited */
int lxcpath_additional;
/* for lxc-checkpoint/restart */
const char *statefile;
@ -58,13 +62,27 @@ struct lxc_arguments {
int ttynum;
char escape;
/* for lxc-wait */
/* for lxc-wait and lxc-shutdown */
char *states;
long timeout;
int nowait;
int reboot;
int hardstop;
int shutdown;
/* for lxc-destroy */
int force;
/* close fds from parent? */
int close_all_fds;
/* lxc-create */
char *bdevtype, *configfile, *template;
char *fstype;
unsigned long fssize;
char *lvname, *vgname;
char *zfsroot, *lowerdir, *dir;
/* remaining arguments */
char *const *argv;
int argc;

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _GNU_SOURCE
@ -31,6 +31,7 @@
#include <sys/param.h>
#include <sys/prctl.h>
#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <linux/unistd.h>
@ -46,42 +47,20 @@
#include "caps.h"
#include "config.h"
#include "apparmor.h"
#include "utils.h"
#include "commands.h"
#include "cgroup.h"
#if HAVE_SYS_PERSONALITY_H
#include <sys/personality.h>
#endif
#ifndef SOCK_CLOEXEC
# define SOCK_CLOEXEC 02000000
#endif
lxc_log_define(lxc_attach, lxc);
/* Define setns() if missing from the C library */
#ifndef HAVE_SETNS
static int setns(int fd, int nstype)
{
#ifdef __NR_setns
return syscall(__NR_setns, fd, nstype);
#else
errno = ENOSYS;
return -1;
#endif
}
#endif
/* Define unshare() if missing from the C library */
#ifndef HAVE_UNSHARE
static int unshare(int flags)
{
#ifdef __NR_unshare
return syscall(__NR_unshare, flags);
#else
errno = ENOSYS;
return -1;
#endif
}
#endif
/* Define getline() if missing from the C library */
#ifndef HAVE_GETLINE
#ifdef HAVE_FGETLN
#include <../include/getline.h>
#endif
#endif
struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
{
struct lxc_proc_context_info *info = calloc(1, sizeof(*info));
@ -114,6 +93,8 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
}
}
if (line)
free(line);
fclose(proc_file);
if (!found) {
@ -145,7 +126,6 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
out_error:
free(info);
free(line);
return NULL;
}
@ -182,7 +162,7 @@ int lxc_attach_to_ns(pid_t pid, int which)
}
snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]);
fd[i] = open(path, O_RDONLY);
fd[i] = open(path, O_RDONLY | O_CLOEXEC);
if (fd[i] < 0) {
saved_errno = errno;
@ -279,23 +259,83 @@ int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char** extra_env, char** extra_keep)
{
/* TODO: implement extra_env, extra_keep
* Rationale:
* - extra_env is an array of strings of the form
* "VAR=VALUE", which are to be set (after clearing or not,
* depending on the value of the policy variable)
* - extra_keep is an array of strings of the form
* "VAR", which are extra environment variables to be kept
* around after clearing (if that is done, otherwise, the
* remain anyway)
*/
(void) extra_env;
(void) extra_keep;
if (policy == LXC_ATTACH_CLEAR_ENV) {
char **extra_keep_store = NULL;
int path_kept = 0;
if (extra_keep) {
size_t count, i;
for (count = 0; extra_keep[count]; count++);
extra_keep_store = calloc(count, sizeof(char *));
if (!extra_keep_store) {
SYSERROR("failed to allocate memory for storing current "
"environment variable values that will be kept");
return -1;
}
for (i = 0; i < count; i++) {
char *v = getenv(extra_keep[i]);
if (v) {
extra_keep_store[i] = strdup(v);
if (!extra_keep_store[i]) {
SYSERROR("failed to allocate memory for storing current "
"environment variable values that will be kept");
while (i > 0)
free(extra_keep_store[--i]);
free(extra_keep_store);
return -1;
}
if (strcmp(extra_keep[i], "PATH") == 0)
path_kept = 1;
}
/* calloc sets entire array to zero, so we don't
* need an else */
}
}
if (clearenv()) {
char **p;
SYSERROR("failed to clear environment");
/* don't error out though */
if (extra_keep_store) {
for (p = extra_keep_store; *p; p++)
free(*p);
free(extra_keep_store);
}
return -1;
}
if (extra_keep_store) {
size_t i;
for (i = 0; extra_keep[i]; i++) {
if (extra_keep_store[i])
setenv(extra_keep[i], extra_keep_store[i], 1);
free(extra_keep_store[i]);
}
free(extra_keep_store);
}
/* always set a default path; shells and execlp tend
* to be fine without it, but there is a disturbing
* 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
setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
#endif
}
}
@ -304,6 +344,24 @@ int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char** extra
return -1;
}
/* set extra environment variables */
if (extra_env) {
for (; *extra_env; extra_env++) {
/* duplicate the string, just to be on
* the safe side, because putenv does not
* do it for us */
char *p = strdup(*extra_env);
/* we just assume the user knows what they
* are doing, so we don't do any checks */
if (!p) {
SYSERROR("failed to allocate memory for additional environment "
"variables");
return -1;
}
putenv(p);
}
}
return 0;
}
@ -358,7 +416,7 @@ char *lxc_attach_getpwshell(uid_t uid)
continue;
/* trim line on the right hand side */
for (i = strlen(line); line && i > 0 && (line[i - 1] == '\n' || line[i - 1] == '\r'); --i)
for (i = strlen(line); i > 0 && (line[i - 1] == '\n' || line[i - 1] == '\r'); --i)
line[i - 1] = '\0';
/* split into tokens: first user name */
@ -507,3 +565,492 @@ void lxc_attach_get_init_uidgid(uid_t* init_uid, gid_t* init_gid)
/* TODO: we should also parse supplementary groups and use
* setgroups() to set them */
}
struct attach_clone_payload {
int ipc_socket;
lxc_attach_options_t* options;
struct lxc_proc_context_info* init_ctx;
lxc_attach_exec_t exec_function;
void* exec_payload;
};
static int attach_child_main(void* data);
/* help the optimizer along if it doesn't know that exit always exits */
#define rexit(c) do { int __c = (c); exit(__c); return __c; } while(0)
/* define default options if no options are supplied by the user */
static lxc_attach_options_t attach_static_default_options = LXC_ATTACH_OPTIONS_DEFAULT;
int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_function, void* exec_payload, lxc_attach_options_t* options, pid_t* attached_process)
{
int ret, status;
pid_t init_pid, pid, attached_pid;
struct lxc_proc_context_info *init_ctx;
char* cwd;
char* new_cwd;
int ipc_sockets[2];
if (!options)
options = &attach_static_default_options;
init_pid = lxc_cmd_get_init_pid(name, lxcpath);
if (init_pid < 0) {
ERROR("failed to get the init pid");
return -1;
}
init_ctx = lxc_proc_get_context_info(init_pid);
if (!init_ctx) {
ERROR("failed to get context of the init process, pid = %ld", (long)init_pid);
return -1;
}
cwd = getcwd(NULL, 0);
/* determine which namespaces the container was created with
* by asking lxc-start, if necessary
*/
if (options->namespaces == -1) {
options->namespaces = lxc_cmd_get_clone_flags(name, lxcpath);
/* call failed */
if (options->namespaces == -1) {
ERROR("failed to automatically determine the "
"namespaces which the container unshared");
free(cwd);
free(init_ctx->aa_profile);
free(init_ctx);
return -1;
}
}
/* create a socket pair for IPC communication; set SOCK_CLOEXEC in order
* to make sure we don't irritate other threads that want to fork+exec away
*
* IMPORTANT: if the initial process is multithreaded and another call
* just fork()s away without exec'ing directly after, the socket fd will
* exist in the forked process from the other thread and any close() in
* our own child process will not really cause the socket to close properly,
* potentiall causing the parent to hang.
*
* For this reason, while IPC is still active, we have to use shutdown()
* if the child exits prematurely in order to signal that the socket
* is closed and cannot assume that the child exiting will automatically
* do that.
*
* IPC mechanism: (X is receiver)
* initial process intermediate attached
* X <--- send pid of
* attached proc,
* then exit
* send 0 ------------------------------------> X
* [do initialization]
* X <------------------------------------ send 1
* [add to cgroup, ...]
* send 2 ------------------------------------> X
* close socket close socket
* run program
*/
ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
if (ret < 0) {
SYSERROR("could not set up required IPC mechanism for attaching");
free(cwd);
free(init_ctx->aa_profile);
free(init_ctx);
return -1;
}
/* create intermediate subprocess, three reasons:
* 1. runs all pthread_atfork handlers and the
* child will no longer be threaded
* (we can't properly setns() in a threaded process)
* 2. we can't setns() in the child itself, since
* we want to make sure we are properly attached to
* the pidns
* 3. also, the initial thread has to put the attached
* process into the cgroup, which we can only do if
* we didn't already setns() (otherwise, user
* namespaces will hate us)
*/
pid = fork();
if (pid < 0) {
SYSERROR("failed to create first subprocess");
free(cwd);
free(init_ctx->aa_profile);
free(init_ctx);
return -1;
}
if (pid) {
pid_t to_cleanup_pid = pid;
int expected = 0;
/* inital thread, we close the socket that is for the
* subprocesses
*/
close(ipc_sockets[1]);
free(cwd);
/* get pid from intermediate process */
ret = lxc_read_nointr_expect(ipc_sockets[0], &attached_pid, sizeof(attached_pid), NULL);
if (ret <= 0) {
if (ret != 0)
ERROR("error using IPC to receive pid of attached process");
goto cleanup_error;
}
/* reap intermediate process */
ret = wait_for_pid(pid);
if (ret < 0)
goto cleanup_error;
/* we will always have to reap the grandchild now */
to_cleanup_pid = attached_pid;
/* tell attached process it may start initializing */
status = 0;
ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
if (ret <= 0) {
ERROR("error using IPC to notify attached process for initialization (0)");
goto cleanup_error;
}
/* wait for the attached process to finish initializing */
expected = 1;
ret = lxc_read_nointr_expect(ipc_sockets[0], &status, sizeof(status), &expected);
if (ret <= 0) {
if (ret != 0)
ERROR("error using IPC to receive notification from attached process (1)");
goto cleanup_error;
}
/* attach to cgroup, if requested */
if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
ret = lxc_cgroup_attach(attached_pid, name, lxcpath);
if (ret < 0) {
ERROR("could not move attached process %ld to cgroup of container", (long)attached_pid);
goto cleanup_error;
}
}
/* tell attached process we're done */
status = 2;
ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
if (ret <= 0) {
ERROR("error using IPC to notify attached process for initialization (2)");
goto cleanup_error;
}
/* now shut down communication with child, we're done */
shutdown(ipc_sockets[0], SHUT_RDWR);
close(ipc_sockets[0]);
free(init_ctx->aa_profile);
free(init_ctx);
/* we're done, the child process should now execute whatever
* it is that the user requested. The parent can now track it
* with waitpid() or similar.
*/
*attached_process = attached_pid;
return 0;
cleanup_error:
/* first shut down the socket, then wait for the pid,
* otherwise the pid we're waiting for may never exit
*/
shutdown(ipc_sockets[0], SHUT_RDWR);
close(ipc_sockets[0]);
if (to_cleanup_pid)
(void) wait_for_pid(to_cleanup_pid);
free(init_ctx->aa_profile);
free(init_ctx);
return -1;
}
/* first subprocess begins here, we close the socket that is for the
* initial thread
*/
close(ipc_sockets[0]);
/* attach now, create another subprocess later, since pid namespaces
* only really affect the children of the current process
*/
ret = lxc_attach_to_ns(init_pid, options->namespaces);
if (ret < 0) {
ERROR("failed to enter the namespace");
shutdown(ipc_sockets[1], SHUT_RDWR);
rexit(-1);
}
/* attach succeeded, try to cwd */
if (options->initial_cwd)
new_cwd = options->initial_cwd;
else
new_cwd = cwd;
ret = chdir(new_cwd);
if (ret < 0)
WARN("could not change directory to '%s'", new_cwd);
free(cwd);
/* now create the real child process */
{
struct attach_clone_payload payload = {
.ipc_socket = ipc_sockets[1],
.options = options,
.init_ctx = init_ctx,
.exec_function = exec_function,
.exec_payload = exec_payload
};
/* We use clone_parent here to make this subprocess a direct child of
* the initial process. Then this intermediate process can exit and
* the parent can directly track the attached process.
*/
pid = lxc_clone(attach_child_main, &payload, CLONE_PARENT);
}
/* shouldn't happen, clone() should always return positive pid */
if (pid <= 0) {
SYSERROR("failed to create subprocess");
shutdown(ipc_sockets[1], SHUT_RDWR);
rexit(-1);
}
/* tell grandparent the pid of the pid of the newly created child */
ret = lxc_write_nointr(ipc_sockets[1], &pid, sizeof(pid));
if (ret != sizeof(pid)) {
/* if this really happens here, this is very unfortunate, since the
* parent will not know the pid of the attached process and will
* not be able to wait for it (and we won't either due to CLONE_PARENT)
* so the parent won't be able to reap it and the attached process
* will remain a zombie
*/
ERROR("error using IPC to notify main process of pid of the attached process");
shutdown(ipc_sockets[1], SHUT_RDWR);
rexit(-1);
}
/* the rest is in the hands of the initial and the attached process */
rexit(0);
}
int attach_child_main(void* data)
{
struct attach_clone_payload* payload = (struct attach_clone_payload*)data;
int ipc_socket = payload->ipc_socket;
lxc_attach_options_t* options = payload->options;
struct lxc_proc_context_info* init_ctx = payload->init_ctx;
#if HAVE_SYS_PERSONALITY_H
long new_personality;
#endif
int ret;
int status;
int expected;
long flags;
int fd;
uid_t new_uid;
gid_t new_gid;
/* wait for the initial thread to signal us that it's ready
* for us to start initializing
*/
expected = 0;
status = -1;
ret = lxc_read_nointr_expect(ipc_socket, &status, sizeof(status), &expected);
if (ret <= 0) {
ERROR("error using IPC to receive notification from initial process (0)");
shutdown(ipc_socket, SHUT_RDWR);
rexit(-1);
}
/* load apparmor profile */
if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_APPARMOR)) {
ret = attach_apparmor(init_ctx->aa_profile);
if (ret < 0) {
shutdown(ipc_socket, SHUT_RDWR);
rexit(-1);
}
}
/* A description of the purpose of this functionality is
* provided in the lxc-attach(1) manual page. We have to
* remount here and not in the parent process, otherwise
* /proc may not properly reflect the new pid namespace.
*/
if (!(options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_REMOUNT_PROC_SYS)) {
ret = lxc_attach_remount_sys_proc();
if (ret < 0) {
shutdown(ipc_socket, SHUT_RDWR);
rexit(-1);
}
}
/* now perform additional attachments*/
#if HAVE_SYS_PERSONALITY_H
if (options->personality < 0)
new_personality = init_ctx->personality;
else
new_personality = options->personality;
if (options->attach_flags & LXC_ATTACH_SET_PERSONALITY) {
ret = personality(new_personality);
if (ret < 0) {
SYSERROR("could not ensure correct architecture");
shutdown(ipc_socket, SHUT_RDWR);
rexit(-1);
}
}
#endif
if (options->attach_flags & LXC_ATTACH_DROP_CAPABILITIES) {
ret = lxc_attach_drop_privs(init_ctx);
if (ret < 0) {
ERROR("could not drop privileges");
shutdown(ipc_socket, SHUT_RDWR);
rexit(-1);
}
}
/* always set the environment (specify (LXC_ATTACH_KEEP_ENV, NULL, NULL) if you want this to be a no-op) */
ret = lxc_attach_set_environment(options->env_policy, options->extra_env_vars, options->extra_keep_env);
if (ret < 0) {
ERROR("could not set initial environment for attached process");
shutdown(ipc_socket, SHUT_RDWR);
rexit(-1);
}
/* set user / group id */
new_uid = 0;
new_gid = 0;
/* ignore errors, we will fall back to root in that case
* (/proc was not mounted etc.)
*/
if (options->namespaces & CLONE_NEWUSER)
lxc_attach_get_init_uidgid(&new_uid, &new_gid);
if (options->uid != (uid_t)-1)
new_uid = options->uid;
if (options->gid != (gid_t)-1)
new_gid = options->gid;
/* try to set the uid/gid combination */
if ((new_gid != 0 || options->namespaces & CLONE_NEWUSER) && setgid(new_gid)) {
SYSERROR("switching to container gid");
shutdown(ipc_socket, SHUT_RDWR);
rexit(-1);
}
if ((new_uid != 0 || options->namespaces & CLONE_NEWUSER) && setuid(new_uid)) {
SYSERROR("switching to container uid");
shutdown(ipc_socket, SHUT_RDWR);
rexit(-1);
}
/* tell initial process it may now put us into the cgroups */
status = 1;
ret = lxc_write_nointr(ipc_socket, &status, sizeof(status));
if (ret != sizeof(status)) {
ERROR("error using IPC to notify initial process for initialization (1)");
shutdown(ipc_socket, SHUT_RDWR);
rexit(-1);
}
/* wait for the initial thread to signal us that it has done
* everything for us when it comes to cgroups etc.
*/
expected = 2;
status = -1;
ret = lxc_read_nointr_expect(ipc_socket, &status, sizeof(status), &expected);
if (ret <= 0) {
ERROR("error using IPC to receive final notification from initial process (2)");
shutdown(ipc_socket, SHUT_RDWR);
rexit(-1);
}
shutdown(ipc_socket, SHUT_RDWR);
close(ipc_socket);
free(init_ctx->aa_profile);
free(init_ctx);
/* The following is done after the communication socket is
* shut down. That way, all errors that might (though
* unlikely) occur up until this point will have their messages
* printed to the original stderr (if logging is so configured)
* and not the fd the user supplied, if any.
*/
/* fd handling for stdin, stdout and stderr;
* ignore errors here, user may want to make sure
* the fds are closed, for example */
if (options->stdin_fd >= 0 && options->stdin_fd != 0)
dup2(options->stdin_fd, 0);
if (options->stdout_fd >= 0 && options->stdout_fd != 1)
dup2(options->stdout_fd, 1);
if (options->stderr_fd >= 0 && options->stderr_fd != 2)
dup2(options->stderr_fd, 2);
/* close the old fds */
if (options->stdin_fd > 2)
close(options->stdin_fd);
if (options->stdout_fd > 2)
close(options->stdout_fd);
if (options->stderr_fd > 2)
close(options->stderr_fd);
/* try to remove CLOEXEC flag from stdin/stdout/stderr,
* but also here, ignore errors */
for (fd = 0; fd <= 2; fd++) {
flags = fcntl(fd, F_GETFL);
if (flags < 0)
continue;
if (flags & FD_CLOEXEC)
fcntl(fd, F_SETFL, flags & ~FD_CLOEXEC);
}
/* we're done, so we can now do whatever the user intended us to do */
rexit(payload->exec_function(payload->exec_payload));
}
int lxc_attach_run_command(void* payload)
{
lxc_attach_command_t* cmd = (lxc_attach_command_t*)payload;
execvp(cmd->program, cmd->argv);
SYSERROR("failed to exec '%s'", cmd->program);
return -1;
}
int lxc_attach_run_shell(void* payload)
{
uid_t uid;
struct passwd *passwd;
char *user_shell;
/* ignore payload parameter */
(void)payload;
uid = getuid();
passwd = getpwuid(uid);
/* this probably happens because of incompatible nss
* implementations in host and container (remember, this
* code is still using the host's glibc but our mount
* namespace is in the container)
* we may try to get the information by spawning a
* [getent passwd uid] process and parsing the result
*/
if (!passwd)
user_shell = lxc_attach_getpwshell(uid);
else
user_shell = passwd->pw_shell;
if (user_shell)
execlp(user_shell, user_shell, NULL);
/* executed if either no passwd entry or execvp fails,
* we will fall back on /bin/sh as a default shell
*/
execlp("/bin/sh", "/bin/sh", NULL);
SYSERROR("failed to exec shell");
return -1;
}

View File

@ -18,13 +18,14 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _attach_h
#define _attach_h
#include <sys/types.h>
#include "attach_options.h"
struct lxc_proc_context_info {
char *aa_profile;
@ -34,11 +35,6 @@ struct lxc_proc_context_info {
extern struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid);
typedef enum lxc_attach_env_policy_t {
LXC_ATTACH_KEEP_ENV,
LXC_ATTACH_CLEAR_ENV
} lxc_attach_env_policy_t;
extern int lxc_attach_to_ns(pid_t other_pid, int which);
extern int lxc_attach_remount_sys_proc();
extern int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx);
@ -48,4 +44,6 @@ extern char *lxc_attach_getpwshell(uid_t uid);
extern void lxc_attach_get_init_uidgid(uid_t* init_uid, gid_t* init_gid);
extern int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_function, void* exec_payload, lxc_attach_options_t* options, pid_t* attached_process);
#endif

120
src/lxc/attach_options.h Normal file
View File

@ -0,0 +1,120 @@
/*
* lxc: linux Container library
*
* (C) Copyright IBM Corp. 2007, 2008
*
* Authors:
* Daniel Lezcano <daniel.lezcano at free.fr>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LXC_ATTACH_OPTIONS_H
#define _LXC_ATTACH_OPTIONS_H
#include <sys/types.h>
typedef enum lxc_attach_env_policy_t {
LXC_ATTACH_KEEP_ENV,
LXC_ATTACH_CLEAR_ENV
} lxc_attach_env_policy_t;
enum {
/* the following are on by default: */
LXC_ATTACH_MOVE_TO_CGROUP = 0x00000001,
LXC_ATTACH_DROP_CAPABILITIES = 0x00000002,
LXC_ATTACH_SET_PERSONALITY = 0x00000004,
LXC_ATTACH_APPARMOR = 0x00000008,
/* the following are off by default */
LXC_ATTACH_REMOUNT_PROC_SYS = 0x00010000,
/* we have 16 bits for things that are on by default
* and 16 bits that are off by default, that should
* be sufficient to keep binary compatibility for
* a while
*/
LXC_ATTACH_DEFAULT = 0x0000FFFF
};
typedef struct lxc_attach_options_t lxc_attach_options_t;
typedef int (*lxc_attach_exec_t)(void* payload);
struct lxc_attach_options_t {
/* any combination of the above enum */
int attach_flags;
/* the namespaces to attach to (CLONE_NEW... flags) */
int namespaces;
/* initial personality, -1 to autodetect
* (may be ignored if lxc is compiled w/o personality support) */
long personality;
/* inital current directory, use NULL to use cwd
* (might not exist in container, then / will be
* used because of kernel defaults)
*/
char* initial_cwd;
/* the uid and gid to attach to,
* -1 for default (init uid/gid for userns containers,
* otherwise or if detection fails 0/0)
*/
uid_t uid;
gid_t gid;
/* environment handling */
lxc_attach_env_policy_t env_policy;
char** extra_env_vars;
char** extra_keep_env;
/* file descriptors for stdin, stdout and stderr,
* dup2() will be used before calling exec_function,
* (assuming not 0, 1 and 2 are specified) and the
* original fds are closed before passing control
* over. Any O_CLOEXEC flag will be removed after
* that
*/
int stdin_fd;
int stdout_fd;
int stderr_fd;
};
#define LXC_ATTACH_OPTIONS_DEFAULT \
{ \
/* .attach_flags = */ LXC_ATTACH_DEFAULT, \
/* .namespaces = */ -1, \
/* .personality = */ -1, \
/* .initial_cwd = */ NULL, \
/* .uid = */ (uid_t)-1, \
/* .gid = */ (gid_t)-1, \
/* .env_policy = */ LXC_ATTACH_KEEP_ENV, \
/* .extra_env_vars = */ NULL, \
/* .extra_keep_env = */ NULL, \
/* .stdin_fd = */ 0, 1, 2 \
}
typedef struct lxc_attach_command_t {
char* program; /* the program to run (passed to execvp) */
char** argv; /* the argv pointer of that program, including the program itself in argv[0] */
} lxc_attach_command_t;
/* default execution functions:
* run_command: pointer to lxc_attach_command_t
* run_shell: no payload, will be ignored
*/
extern int lxc_attach_run_command(void* payload);
extern int lxc_attach_run_shell(void* payload);
#endif

2070
src/lxc/bdev.c Normal file

File diff suppressed because it is too large Load Diff

138
src/lxc/bdev.h Normal file
View File

@ -0,0 +1,138 @@
/*
* lxc: linux Container library
*
* (C) Copyright IBM Corp. 2007, 2008
*
* Authors:
* Daniel Lezcano <daniel.lezcano at free.fr>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __LXC_BDEV_H
#define __LXC_BDEV_H
/* blockdev operations for:
* dir, raw, btrfs, overlayfs, aufs, lvm, loop, zfs
* someday: qemu-nbd, qcow2, qed
*/
#include "config.h"
#include "lxccontainer.h"
struct bdev;
/*
* specifications for how to create a new backing store
*/
struct bdev_specs {
union {
struct {
char *zfsroot;
} zfs;
struct {
char *vg;
char *lv;
char *fstype;
unsigned long fssize; // fs size in bytes
} lvm;
struct {
char *fstype;
unsigned long fssize; // fs size in bytes
} loop;
} u;
};
struct bdev_ops {
/* detect whether path is of this bdev type */
int (*detect)(const char *path);
// mount requires src and dest to be set.
int (*mount)(struct bdev *bdev);
int (*umount)(struct bdev *bdev);
int (*destroy)(struct bdev *bdev);
int (*create)(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs);
/* given original mount, rename the paths for cloned container */
int (*clone_paths)(struct bdev *orig, struct bdev *new, const char *oldname,
const char *cname, const char *oldpath, const char *lxcpath,
int snap, unsigned long newsize);
};
/*
* When lxc-start (conf.c) is mounting a rootfs, then src will be the
* 'lxc.rootfs' value, dest will be mount dir (i.e. $libdir/lxc) When clone
* or create is doing so, then dest will be $lxcpath/$lxcname/rootfs, since
* we may need to rsync from one to the other.
* data is so far unused.
*/
struct bdev {
struct bdev_ops *ops;
char *type;
char *src;
char *dest;
char *data;
// turn the following into a union if need be
// lofd is the open fd for the mounted loopback file
int lofd;
};
char *overlayfs_getlower(char *p);
/*
* Instantiate a bdev object. The src is used to determine which blockdev
* type this should be. The dst and data are optional, and will be used
* in case of mount/umount.
*
* Optionally, src can be 'dir:/var/lib/lxc/c1' or 'lvm:/dev/lxc/c1'. For
* other backing stores, this will allow additional options. In particular,
* "overlayfs:/var/lib/lxc/canonical/rootfs:/var/lib/lxc/c1/delta" will mean
* use /var/lib/lxc/canonical/rootfs as lower dir, and /var/lib/lxc/c1/delta
* as the upper, writeable layer.
*/
struct bdev *bdev_init(const char *src, const char *dst, const char *data);
struct bdev *bdev_copy(const char *src, const char *oldname, const char *cname,
const char *oldpath, const char *lxcpath, const char *bdevtype,
int snap, const char *bdevdata, unsigned long newsize,
int *needs_rdep);
struct bdev *bdev_create(const char *dest, const char *type,
const char *cname, struct bdev_specs *specs);
void bdev_put(struct bdev *bdev);
/* define constants if the kernel/glibc headers don't define them */
#ifndef MS_DIRSYNC
#define MS_DIRSYNC 128
#endif
#ifndef MS_REC
#define MS_REC 16384
#endif
#ifndef MNT_DETACH
#define MNT_DETACH 2
#endif
#ifndef MS_SLAVE
#define MS_SLAVE (1<<19)
#endif
#ifndef MS_RELATIME
#define MS_RELATIME (1 << 21)
#endif
#ifndef MS_STRICTATIME
#define MS_STRICTATIME (1 << 24)
#endif
#endif

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _GNU_SOURCE
@ -227,42 +227,4 @@ int lxc_caps_last_cap(void)
return last_cap;
}
/*
* check if we have the caps needed to start a container. returns 1 on
* success, 0 on error. (I'd prefer this be a bool, but am afraid that
* might fail to build on some distros).
*/
int lxc_caps_check(void)
{
uid_t uid = getuid();
cap_t caps;
cap_flag_value_t value;
int i, ret;
cap_value_t needed_caps[] = { CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_SETUID, CAP_SETGID };
#define NUMCAPS ((int) (sizeof(needed_caps) / sizeof(cap_t)))
if (!uid)
return 1;
caps = cap_get_proc();
if (!caps) {
ERROR("failed to cap_get_proc: %m");
return 0;
}
for (i=0; i<NUMCAPS; i++) {
ret = cap_get_flag(caps, needed_caps[i], CAP_EFFECTIVE, &value);
if (ret) {
ERROR("Failed to cap_get_flag: %m");
return 0;
}
if (!value) {
return 0;
}
}
return 1;
}
#endif

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
@ -30,7 +30,6 @@ extern int lxc_caps_reset(void);
extern int lxc_caps_down(void);
extern int lxc_caps_up(void);
extern int lxc_caps_init(void);
extern int lxc_caps_check(void);
extern int lxc_caps_last_cap(void);
#else
@ -46,9 +45,6 @@ static inline int lxc_caps_up(void) {
static inline int lxc_caps_init(void) {
return 0;
}
static inline int lxc_caps_check(void) {
return 1;
}
static inline int lxc_caps_last_cap(void) {
return 0;

File diff suppressed because it is too large Load Diff

View File

@ -18,21 +18,40 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _cgroup_h
#define _cgroup_h
#include <stdbool.h>
#define MAXPRIOLEN 24
/*
* cgroup_desc: describe a container's cgroup membership
*/
struct cgroup_desc {
char *mntpt; /* where this is mounted */
char *subsystems; /* comma-separated list of subsystems, or NULL */
char *curcgroup; /* task's current cgroup, full pathanme */
char *realcgroup; /* the cgroup as known in /proc/self/cgroup */
struct cgroup_desc *next;
};
struct lxc_handler;
extern int lxc_cgroup_destroy(const char *cgpath);
extern int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name,
extern void lxc_cgroup_destroy_desc(struct cgroup_desc *cgroups);
extern char *lxc_cgroup_path_get(const char *subsystem, const char *name,
const char *lxcpath);
extern int lxc_cgroup_nrtasks(const char *cgpath);
extern char *lxc_cgroup_path_create(const char *lxcgroup, const char *name);
extern int lxc_cgroup_enter(const char *cgpath, pid_t pid);
extern int lxc_cgroup_nrtasks(struct lxc_handler *handler);
struct cgroup_desc *lxc_cgroup_path_create(const char *name);
extern int lxc_cgroup_enter(struct cgroup_desc *cgroups, pid_t pid);
extern int lxc_cgroup_attach(pid_t pid, const char *name, const char *lxcpath);
extern int cgroup_path_get(char **path, const char *subsystem, const char *cgpath);
extern int lxc_get_cgpath(const char **path, const char *subsystem, const char *name, const char *lxcpath);
extern char *cgroup_path_get(const char *subsystem, const char *cgpath);
extern bool get_subsys_mount(char *dest, const char *subsystem);
extern bool is_in_subcgroup(int pid, const char *subsystem, struct cgroup_desc *d);
/*
* Called by commands.c by a container's monitor to find out the
* container's cgroup path in a specific subsystem
*/
extern char *cgroup_get_subsys_path(struct lxc_handler *handler, const char *subsys);
struct lxc_list;
extern int setup_cgroup(struct lxc_handler *h, struct lxc_list *cgroups);
extern int setup_cgroup_devices(struct lxc_handler *h, struct lxc_list *cgroups);
#endif

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <lxc/lxc.h>
#include <lxc/log.h>

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
@ -34,27 +34,41 @@
#include <stdlib.h>
#include <lxc/log.h>
#include <lxc/lxc.h>
#include <lxc/conf.h>
#include <lxc/start.h> /* for struct lxc_handler */
#include <lxc/utils.h>
#include "commands.h"
#include "console.h"
#include "confile.h"
#include "mainloop.h"
#include "af_unix.h"
#include "config.h"
/*
* This file provides the different functions to have the client
* and the server to communicate
* This file provides the different functions for clients to
* query/command the server. The client is typically some lxc
* tool and the server is typically the container (ie. lxc-start).
*
* Each command is transactional, the client send a request to
* the server and the server answer the request with a message
* 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.
*
* Each command is wrapped in a ancillary message in order to pass
* a credential making possible to the server to check if the client
* is allowed to ask for this command or not.
*
* IMPORTANTLY: Note that semantics for current commands are fixed. If you
* wish to make any changes to how, say, LXC_CMD_GET_CONFIG_ITEM works by
* adding information to the end of cmd.data, then you must introduce a new
* LXC_CMD_GET_CONFIG_ITEM_V2 define with a new number. You may wish to
* also mark LXC_CMD_GET_CONFIG_ITEM deprecated in commands.h.
*
* This is necessary in order to avoid having a newly compiled lxc command
* communicating with a running (old) monitor from crashing the running
* container.
*/
lxc_log_define(lxc_commands, lxc);
@ -81,181 +95,642 @@ static int fill_sock_name(char *path, int len, const char *name,
return 0;
}
static int receive_answer(int sock, struct lxc_answer *answer)
static const char *lxc_cmd_str(lxc_cmd_t cmd)
{
int ret;
static char answerpath[MAXPATHLEN];
static const char *cmdname[LXC_CMD_MAX] = {
[LXC_CMD_CONSOLE] = "console",
[LXC_CMD_STOP] = "stop",
[LXC_CMD_GET_STATE] = "get_state",
[LXC_CMD_GET_INIT_PID] = "get_init_pid",
[LXC_CMD_GET_CLONE_FLAGS] = "get_clone_flags",
[LXC_CMD_GET_CGROUP] = "get_cgroup",
[LXC_CMD_GET_CONFIG_ITEM] = "get_config_item",
};
ret = lxc_af_unix_recv_fd(sock, &answer->fd, answer, sizeof(*answer));
if (ret < 0)
ERROR("failed to receive answer for the command");
if (answer->pathlen == 0)
return ret;
if (answer->pathlen >= MAXPATHLEN) {
ERROR("cgroup path was too long");
if (cmd < 0 || cmd >= LXC_CMD_MAX)
return "Unknown cmd";
return cmdname[cmd];
}
/*
* lxc_cmd_rsp_recv: Receive a response to a command
*
* @sock : the socket connected to the container
* @cmd : command to put response in
*
* Returns the size of the response message or < 0 on failure
*
* Note that if the command response datalen > 0, then data is
* a malloc()ed buffer and should be free()ed by the caller. If
* the response data is <= a void * worth of data, it will be
* stored directly in data and datalen will be 0.
*
* As a special case, the response for LXC_CMD_CONSOLE is created
* here as it contains an fd for the master pty passed through the
* unix socket.
*/
static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
{
int ret,rspfd;
struct lxc_cmd_rsp *rsp = &cmd->rsp;
ret = lxc_af_unix_recv_fd(sock, &rspfd, rsp, sizeof(*rsp));
if (ret < 0) {
ERROR("command %s failed to receive response",
lxc_cmd_str(cmd->req.cmd));
return -1;
}
ret = recv(sock, answerpath, answer->pathlen, 0);
if (ret != answer->pathlen) {
ERROR("failed to receive answer for the command");
ret = 0;
} else
answer->path = answerpath;
if (cmd->req.cmd == LXC_CMD_CONSOLE) {
struct lxc_cmd_console_rsp_data *rspdata;
/* recv() returns 0 bytes when a tty cannot be allocated,
* rsp->ret is < 0 when the peer permission check failed
*/
if (ret == 0 || rsp->ret < 0)
return 0;
rspdata = malloc(sizeof(*rspdata));
if (!rspdata) {
ERROR("command %s couldn't allocate response buffer",
lxc_cmd_str(cmd->req.cmd));
return -1;
}
rspdata->masterfd = rspfd;
rspdata->ttynum = PTR_TO_INT(rsp->data);
rsp->data = rspdata;
}
if (rsp->datalen == 0)
return ret;
if (rsp->datalen > LXC_CMD_DATA_MAX) {
ERROR("command %s response data %d too long",
lxc_cmd_str(cmd->req.cmd), rsp->datalen);
errno = EFBIG;
return -1;
}
rsp->data = malloc(rsp->datalen);
if (!rsp->data) {
ERROR("command %s unable to allocate response buffer",
lxc_cmd_str(cmd->req.cmd));
return -1;
}
ret = recv(sock, rsp->data, rsp->datalen, 0);
if (ret != rsp->datalen) {
ERROR("command %s failed to receive response data",
lxc_cmd_str(cmd->req.cmd));
if (ret >= 0)
ret = -1;
}
return ret;
}
static int __lxc_command(const char *name, struct lxc_command *command,
int *stopped, int stay_connected, const char *lxcpath)
/*
* lxc_cmd_rsp_send: Send a command response
*
* @fd : file descriptor of socket to send response on
* @rsp : response to send
*
* Returns 0 on success, < 0 on failure
*/
static int lxc_cmd_rsp_send(int fd, struct lxc_cmd_rsp *rsp)
{
int ret;
ret = send(fd, rsp, sizeof(*rsp), 0);
if (ret != sizeof(*rsp)) {
ERROR("failed to send command response %d %s", ret,
strerror(errno));
return -1;
}
if (rsp->datalen > 0) {
ret = send(fd, rsp->data, rsp->datalen, 0);
if (ret != rsp->datalen) {
WARN("failed to send command response data %d %s", ret,
strerror(errno));
return -1;
}
}
return 0;
}
/*
* lxc_cmd: Connect to the specified running container, send it a command
* request and collect the response
*
* @name : name of container to connect to
* @cmd : command with initialized reqest to send
* @stopped : output indicator if the container was not running
* @lxcpath : the lxcpath in which the container is running
*
* Returns the size of the response message on success, < 0 on failure
*
* Note that there is a special case for LXC_CMD_CONSOLE. For this command
* the fd cannot be closed because it is used as a placeholder to indicate
* that a particular tty slot is in use. The fd is also used as a signal to
* the container that when the caller dies or closes the fd, the container
* will notice the fd on its side of the socket in its mainloop select and
* then free the slot with lxc_cmd_fd_cleanup(). The socket fd will be
* returned in the cmd response structure.
*/
static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
const char *lxcpath)
{
int sock, ret = -1;
char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
char *offset = &path[1];
int len;
int stay_connected = cmd->req.cmd == LXC_CMD_CONSOLE;
len = sizeof(path)-1;
if (fill_sock_name(offset, len, name, lxcpath))
return -1;
sock = lxc_af_unix_connect(path);
if (sock < 0 && errno == ECONNREFUSED) {
*stopped = 1;
return -1;
}
if (sock < 0) {
SYSERROR("failed to connect to '@%s'", offset);
if (errno == ECONNREFUSED)
*stopped = 1;
else
SYSERROR("command %s failed to connect to '@%s'",
lxc_cmd_str(cmd->req.cmd), offset);
return -1;
}
ret = lxc_af_unix_send_credential(sock, &command->request,
sizeof(command->request));
if (ret < 0) {
SYSERROR("failed to send request to '@%s'", offset);
ret = lxc_af_unix_send_credential(sock, &cmd->req, sizeof(cmd->req));
if (ret != sizeof(cmd->req)) {
SYSERROR("command %s failed to send req to '@%s' %d",
lxc_cmd_str(cmd->req.cmd), offset, ret);
if (ret >=0)
ret = -1;
goto out;
}
if (ret != sizeof(command->request)) {
SYSERROR("message partially sent to '@%s'", offset);
goto out;
if (cmd->req.datalen > 0) {
ret = send(sock, cmd->req.data, cmd->req.datalen, 0);
if (ret != cmd->req.datalen) {
SYSERROR("command %s failed to send request data to '@%s' %d",
lxc_cmd_str(cmd->req.cmd), offset, ret);
if (ret >=0)
ret = -1;
goto out;
}
}
ret = receive_answer(sock, &command->answer);
ret = lxc_cmd_rsp_recv(sock, cmd);
out:
if (!stay_connected || ret < 0)
if (!stay_connected || ret <= 0)
close(sock);
if (stay_connected && ret > 0)
cmd->rsp.ret = sock;
return ret;
}
extern int lxc_command(const char *name,
struct lxc_command *command, int *stopped,
const char *lxcpath)
{
return __lxc_command(name, command, stopped, 0, lxcpath);
}
/* Implentations of the commands and their callbacks */
extern int lxc_command_connected(const char *name,
struct lxc_command *command, int *stopped,
const char *lxcpath)
/*
* lxc_cmd_get_init_pid: Get pid of the container's init process
*
* @name : name of container to connect to
* @lxcpath : the lxcpath in which the container is running
*
* Returns the pid on success, < 0 on failure
*/
pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath)
{
return __lxc_command(name, command, stopped, 1, lxcpath);
}
pid_t get_init_pid(const char *name, const char *lxcpath)
{
struct lxc_command command = {
.request = { .type = LXC_COMMAND_PID },
int ret, stopped = 0;
struct lxc_cmd_rr cmd = {
.req = { .cmd = LXC_CMD_GET_INIT_PID },
};
int ret, stopped = 0;
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
if (ret < 0)
return ret;
ret = lxc_command(name, &command, &stopped, lxcpath);
if (ret < 0 && stopped)
return -1;
if (ret < 0) {
ERROR("failed to send command");
return -1;
}
if (command.answer.ret) {
ERROR("failed to retrieve the init pid: %s",
strerror(-command.answer.ret));
return -1;
}
return command.answer.pid;
return PTR_TO_INT(cmd.rsp.data);
}
int lxc_get_clone_flags(const char *name, const char *lxcpath)
static int lxc_cmd_get_init_pid_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler)
{
struct lxc_command command = {
.request = { .type = LXC_COMMAND_CLONE_FLAGS },
struct lxc_cmd_rsp rsp = { .data = INT_TO_PTR(handler->pid) };
return lxc_cmd_rsp_send(fd, &rsp);
}
/*
* lxc_cmd_get_clone_flags: Get clone flags container was spawned with
*
* @name : name of container to connect to
* @lxcpath : the lxcpath in which the container is running
*
* Returns the clone flags on success, < 0 on failure
*/
int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath)
{
int ret, stopped = 0;
struct lxc_cmd_rr cmd = {
.req = { .cmd = LXC_CMD_GET_CLONE_FLAGS },
};
int ret, stopped = 0;
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
if (ret < 0)
return ret;
ret = lxc_command(name, &command, &stopped, lxcpath);
return PTR_TO_INT(cmd.rsp.data);
}
static int lxc_cmd_get_clone_flags_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler)
{
struct lxc_cmd_rsp rsp = { .data = INT_TO_PTR(handler->clone_flags) };
return lxc_cmd_rsp_send(fd, &rsp);
}
extern char *cgroup_get_subsys_path(struct lxc_handler *handler, const char *subsys);
/*
* lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a
* particular subsystem. This is the cgroup path relative to the root
* of the cgroup filesystem.
*
* @name : name of container to connect to
* @lxcpath : the lxcpath in which the container is running
* @subsystem : the subsystem being asked about
*
* Returns the path on success, NULL on failure. The caller must free() the
* returned path.
*/
char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
const char *subsystem)
{
int ret, stopped = 0;
struct lxc_cmd_rr cmd = {
.req = {
.cmd = LXC_CMD_GET_CGROUP,
.datalen = strlen(subsystem)+1,
.data = subsystem,
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
if (ret < 0)
return NULL;
if (!ret) {
WARN("'%s' has stopped before sending its state", name);
return NULL;
}
if (cmd.rsp.ret < 0 || cmd.rsp.datalen < 0) {
ERROR("command %s failed for '%s': %s",
lxc_cmd_str(cmd.req.cmd), name,
strerror(-cmd.rsp.ret));
return NULL;
}
return cmd.rsp.data;
}
static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler)
{
struct lxc_cmd_rsp rsp;
char *path;
if (req->datalen < 1)
return -1;
path = cgroup_get_subsys_path(handler, req->data);
if (!path)
return -1;
rsp.datalen = strlen(path) + 1,
rsp.data = path;
rsp.ret = 0;
return lxc_cmd_rsp_send(fd, &rsp);
}
/*
* lxc_cmd_get_config_item: Get config item the running container
*
* @name : name of container to connect to
* @item : the configuration item to retrieve (ex: lxc.network.0.veth.pair)
* @lxcpath : the lxcpath in which the container is running
*
* Returns the item on success, NULL on failure. The caller must free() the
* returned item.
*/
char *lxc_cmd_get_config_item(const char *name, const char *item,
const char *lxcpath)
{
int ret, stopped = 0;
struct lxc_cmd_rr cmd = {
.req = { .cmd = LXC_CMD_GET_CONFIG_ITEM,
.data = item,
.datalen = strlen(item)+1,
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
if (ret < 0)
return NULL;
if (cmd.rsp.ret == 0)
return cmd.rsp.data;
return NULL;
}
static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler)
{
int cilen;
struct lxc_cmd_rsp rsp;
char *cidata;
memset(&rsp, 0, sizeof(rsp));
cilen = lxc_get_config_item(handler->conf, req->data, NULL, 0);
if (cilen <= 0)
goto err1;
cidata = alloca(cilen + 1);
if (lxc_get_config_item(handler->conf, req->data, cidata, cilen + 1) != cilen)
goto err1;
cidata[cilen] = '\0';
rsp.data = cidata;
rsp.datalen = cilen + 1;
rsp.ret = 0;
goto out;
err1:
rsp.ret = -1;
out:
return lxc_cmd_rsp_send(fd, &rsp);
}
/*
* lxc_cmd_get_state: Get current state of the container
*
* @name : name of container to connect to
* @lxcpath : the lxcpath in which the container is running
*
* Returns the state on success, < 0 on failure
*/
lxc_state_t lxc_cmd_get_state(const char *name, const char *lxcpath)
{
int ret, stopped = 0;
struct lxc_cmd_rr cmd = {
.req = { .cmd = LXC_CMD_GET_STATE }
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
if (ret < 0 && stopped)
return STOPPED;
if (ret < 0)
return -1;
if (ret < 0) {
ERROR("failed to send command");
if (!ret) {
WARN("'%s' has stopped before sending its state", name);
return -1;
}
return command.answer.ret;
DEBUG("'%s' is in '%s' state", name,
lxc_state2str(PTR_TO_INT(cmd.rsp.data)));
return PTR_TO_INT(cmd.rsp.data);
}
extern void lxc_console_remove_fd(int, struct lxc_tty_info *);
extern int lxc_console_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_stop_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_state_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_pid_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_clone_flags_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_cgroup_callback(int, struct lxc_request *, struct lxc_handler *);
static int lxc_cmd_get_state_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler)
{
struct lxc_cmd_rsp rsp = { .data = INT_TO_PTR(handler->state) };
static int trigger_command(int fd, struct lxc_request *request,
return lxc_cmd_rsp_send(fd, &rsp);
}
/*
* lxc_cmd_stop: Stop the container previously started with lxc_start. All
* the processes running inside this container will be killed.
*
* @name : name of container to connect to
* @lxcpath : the lxcpath in which the container is running
*
* Returns 0 on success, < 0 on failure
*/
int lxc_cmd_stop(const char *name, const char *lxcpath)
{
int ret, stopped = 0;
struct lxc_cmd_rr cmd = {
.req = { .cmd = LXC_CMD_STOP },
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
if (ret < 0) {
if (stopped) {
INFO("'%s' is already stopped", name);
return 0;
}
return -1;
}
/* we do not expect any answer, because we wait for the connection to be
* closed
*/
if (ret > 0) {
ERROR("failed to stop '%s': %s", name, strerror(-cmd.rsp.ret));
return -1;
}
INFO("'%s' has stopped", name);
return 0;
}
static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler)
{
struct lxc_cmd_rsp rsp;
int ret;
int stopsignal = SIGKILL;
if (handler->conf->stopsignal)
stopsignal = handler->conf->stopsignal;
memset(&rsp, 0, sizeof(rsp));
rsp.ret = kill(handler->pid, stopsignal);
if (!rsp.ret) {
char *path = cgroup_get_subsys_path(handler, "freezer");
if (!path) {
ERROR("container %s:%s is not in a freezer cgroup",
handler->lxcpath, handler->name);
return 0;
}
ret = lxc_unfreeze_bypath(path);
if (!ret)
return 0;
ERROR("failed to unfreeze container");
rsp.ret = ret;
}
return lxc_cmd_rsp_send(fd, &rsp);
}
/*
* lxc_cmd_console_winch: To process as if a SIGWINCH were received
*
* @name : name of container to connect to
* @lxcpath : the lxcpath in which the container is running
*
* Returns 0 on success, < 0 on failure
*/
int lxc_cmd_console_winch(const char *name, const char *lxcpath)
{
int ret, stopped = 0;
struct lxc_cmd_rr cmd = {
.req = { .cmd = LXC_CMD_CONSOLE_WINCH },
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
if (ret < 0)
return ret;
return 0;
}
static int lxc_cmd_console_winch_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler)
{
struct lxc_cmd_rsp rsp = { .data = 0 };
lxc_console_sigwinch(SIGWINCH);
return lxc_cmd_rsp_send(fd, &rsp);
}
/*
* lxc_cmd_console: Open an fd to a tty in the container
*
* @name : name of container to connect to
* @ttynum : in: the tty to open or -1 for next available
* : out: the tty allocated
* @fd : out: file descriptor for master side of pty
* @lxcpath : the lxcpath in which the container is running
*
* Returns fd holding tty allocated on success, < 0 on failure
*/
int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath)
{
int ret, stopped = 0;
struct lxc_cmd_console_rsp_data *rspdata;
struct lxc_cmd_rr cmd = {
.req = { .cmd = LXC_CMD_CONSOLE, .data = INT_TO_PTR(*ttynum) },
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
if (ret < 0)
return ret;
if (cmd.rsp.ret < 0) {
ERROR("console access denied: %s", strerror(-cmd.rsp.ret));
ret = -1;
goto out;
}
if (ret == 0) {
ERROR("console %d invalid,busy or all consoles busy", *ttynum);
ret = -1;
goto out;
}
rspdata = cmd.rsp.data;
if (rspdata->masterfd < 0) {
ERROR("unable to allocate fd for tty %d", rspdata->ttynum);
goto out;
}
ret = cmd.rsp.ret; /* sock fd */
*fd = rspdata->masterfd;
*ttynum = rspdata->ttynum;
INFO("tty %d allocated fd %d sock %d", rspdata->ttynum, *fd, ret);
out:
free(cmd.rsp.data);
return ret;
}
static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler)
{
int ttynum = PTR_TO_INT(req->data);
int masterfd;
struct lxc_cmd_rsp rsp;
masterfd = lxc_console_allocate(handler->conf, fd, &ttynum);
if (masterfd < 0)
goto out_close;
memset(&rsp, 0, sizeof(rsp));
rsp.data = INT_TO_PTR(ttynum);
if (lxc_af_unix_send_fd(fd, masterfd, &rsp, sizeof(rsp)) < 0) {
ERROR("failed to send tty to client");
lxc_console_free(handler->conf, fd);
goto out_close;
}
return 0;
out_close:
/* special indicator to lxc_cmd_handler() to close the fd and do
* related cleanup
*/
return 1;
}
static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler)
{
typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
typedef int (*callback)(int, struct lxc_cmd_req *, struct lxc_handler *);
callback cb[LXC_COMMAND_MAX] = {
[LXC_COMMAND_TTY] = lxc_console_callback,
[LXC_COMMAND_STOP] = lxc_stop_callback,
[LXC_COMMAND_STATE] = lxc_state_callback,
[LXC_COMMAND_PID] = lxc_pid_callback,
[LXC_COMMAND_CLONE_FLAGS] = lxc_clone_flags_callback,
[LXC_COMMAND_CGROUP] = lxc_cgroup_callback,
callback cb[LXC_CMD_MAX] = {
[LXC_CMD_CONSOLE] = lxc_cmd_console_callback,
[LXC_CMD_CONSOLE_WINCH] = lxc_cmd_console_winch_callback,
[LXC_CMD_STOP] = lxc_cmd_stop_callback,
[LXC_CMD_GET_STATE] = lxc_cmd_get_state_callback,
[LXC_CMD_GET_INIT_PID] = lxc_cmd_get_init_pid_callback,
[LXC_CMD_GET_CLONE_FLAGS] = lxc_cmd_get_clone_flags_callback,
[LXC_CMD_GET_CGROUP] = lxc_cmd_get_cgroup_callback,
[LXC_CMD_GET_CONFIG_ITEM] = lxc_cmd_get_config_item_callback,
};
if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
if (req->cmd < 0 || req->cmd >= LXC_CMD_MAX) {
ERROR("bad cmd %d recieved", req->cmd);
return -1;
return cb[request->type](fd, request, handler);
}
return cb[req->cmd](fd, req, handler);
}
static void command_fd_cleanup(int fd, struct lxc_handler *handler,
static void lxc_cmd_fd_cleanup(int fd, struct lxc_handler *handler,
struct lxc_epoll_descr *descr)
{
lxc_console_remove_fd(fd, &handler->conf->tty_info);
lxc_console_free(handler->conf, fd);
lxc_mainloop_del_handler(descr, fd);
close(fd);
}
static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
static int lxc_cmd_handler(int fd, void *data, struct lxc_epoll_descr *descr)
{
int ret;
struct lxc_request request;
struct lxc_cmd_req req;
struct lxc_handler *handler = data;
ret = lxc_af_unix_rcv_credential(fd, &request, sizeof(request));
ret = lxc_af_unix_rcv_credential(fd, &req, sizeof(req));
if (ret == -EACCES) {
/* we don't care for the peer, just send and close */
struct lxc_answer answer = { .ret = ret };
send(fd, &answer, sizeof(answer), 0);
struct lxc_cmd_rsp rsp = { .ret = ret };
lxc_cmd_rsp_send(fd, &rsp);
goto out_close;
}
@ -269,12 +744,32 @@ static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
goto out_close;
}
if (ret != sizeof(request)) {
if (ret != sizeof(req)) {
WARN("partial request, ignored");
ret = -1;
goto out_close;
}
ret = trigger_command(fd, &request, handler);
if (req.datalen > LXC_CMD_DATA_MAX) {
ERROR("cmd data length %d too large", req.datalen);
ret = -1;
goto out_close;
}
if (req.datalen > 0) {
void *reqdata;
reqdata = alloca(req.datalen);
ret = recv(fd, reqdata, req.datalen, 0);
if (ret != req.datalen) {
WARN("partial request, ignored");
ret = -1;
goto out_close;
}
req.data = reqdata;
}
ret = lxc_cmd_process(fd, &req, handler);
if (ret) {
/* this is not an error, but only a request to close fd */
ret = 0;
@ -284,12 +779,11 @@ static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
out:
return ret;
out_close:
command_fd_cleanup(fd, handler, descr);
lxc_cmd_fd_cleanup(fd, handler, descr);
goto out;
}
static int incoming_command_handler(int fd, void *data,
struct lxc_epoll_descr *descr)
static int lxc_cmd_accept(int fd, void *data, struct lxc_epoll_descr *descr)
{
int opt = 1, ret = -1, connection;
@ -310,7 +804,7 @@ static int incoming_command_handler(int fd, void *data,
goto out_close;
}
ret = lxc_mainloop_add_handler(descr, connection, command_handler, data);
ret = lxc_mainloop_add_handler(descr, connection, lxc_cmd_handler, data);
if (ret) {
ERROR("failed to add handler");
goto out_close;
@ -324,8 +818,8 @@ out_close:
goto out;
}
extern int lxc_command_init(const char *name, struct lxc_handler *handler,
const char *lxcpath)
int lxc_cmd_init(const char *name, struct lxc_handler *handler,
const char *lxcpath)
{
int fd;
char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
@ -357,14 +851,13 @@ extern int lxc_command_init(const char *name, struct lxc_handler *handler,
return 0;
}
extern int lxc_command_mainloop_add(const char *name,
struct lxc_epoll_descr *descr,
struct lxc_handler *handler)
int lxc_cmd_mainloop_add(const char *name,
struct lxc_epoll_descr *descr,
struct lxc_handler *handler)
{
int ret, fd = handler->conf->maincmd_fd;
ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler,
handler);
ret = lxc_mainloop_add_handler(descr, fd, lxc_cmd_accept, handler);
if (ret) {
ERROR("failed to add handler for command socket");
close(fd);

View File

@ -18,54 +18,75 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __commands_h
#define __commands_h
enum {
LXC_COMMAND_TTY,
LXC_COMMAND_STOP,
LXC_COMMAND_STATE,
LXC_COMMAND_PID,
LXC_COMMAND_CLONE_FLAGS,
LXC_COMMAND_CGROUP,
LXC_COMMAND_MAX,
#include "state.h"
#define LXC_CMD_DATA_MAX (MAXPATHLEN*2)
/* https://developer.gnome.org/glib/2.28/glib-Type-Conversion-Macros.html */
#define INT_TO_PTR(n) ((void *) (long) (n))
#define PTR_TO_INT(p) ((int) (long) (p))
typedef enum {
LXC_CMD_CONSOLE,
LXC_CMD_CONSOLE_WINCH,
LXC_CMD_STOP,
LXC_CMD_GET_STATE,
LXC_CMD_GET_INIT_PID,
LXC_CMD_GET_CLONE_FLAGS,
LXC_CMD_GET_CGROUP,
LXC_CMD_GET_CONFIG_ITEM,
LXC_CMD_MAX,
} lxc_cmd_t;
struct lxc_cmd_req {
lxc_cmd_t cmd;
int datalen;
const void *data;
};
struct lxc_request {
int type;
int data;
};
struct lxc_answer {
int fd;
struct lxc_cmd_rsp {
int ret; /* 0 on success, -errno on failure */
pid_t pid;
int pathlen;
const char *path;
int datalen;
void *data;
};
struct lxc_command {
struct lxc_request request;
struct lxc_answer answer;
struct lxc_cmd_rr {
struct lxc_cmd_req req;
struct lxc_cmd_rsp rsp;
};
extern pid_t get_init_pid(const char *name, const char *lxcpath);
extern int lxc_get_clone_flags(const char *name, const char *lxcpath);
struct lxc_cmd_console_rsp_data {
int masterfd;
int ttynum;
};
extern int lxc_command(const char *name, struct lxc_command *command,
int *stopped, const char *lxcpath);
extern int lxc_command_connected(const char *name, struct lxc_command *command,
int *stopped, const char *lxcpath);
extern int lxc_cmd_console_winch(const char *name, const char *lxcpath);
extern int lxc_cmd_console(const char *name, int *ttynum, int *fd,
const char *lxcpath);
/*
* Get the 'real' cgroup path (as seen in /proc/self/cgroup) for a container
* for a particular subsystem
*/
extern char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
const char *subsystem);
extern int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath);
extern char *lxc_cmd_get_config_item(const char *name, const char *item, const char *lxcpath);
extern pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath);
extern lxc_state_t lxc_cmd_get_state(const char *name, const char *lxcpath);
extern int lxc_cmd_stop(const char *name, const char *lxcpath);
struct lxc_epoll_descr;
struct lxc_handler;
extern int lxc_command_init(const char *name, struct lxc_handler *handler,
extern int lxc_cmd_init(const char *name, struct lxc_handler *handler,
const char *lxcpath);
extern int lxc_command_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
extern int lxc_cmd_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
struct lxc_handler *handler);
#endif
#endif /* __commands_h */

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _GNU_SOURCE
#include <stdio.h>
@ -31,6 +31,13 @@
#include <unistd.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <time.h>
#if HAVE_IFADDRS_H
#include <ifaddrs.h>
#else
#include <../include/ifaddrs.h>
#endif
#if HAVE_PTY_H
#include <pty.h>
@ -64,6 +71,7 @@
#include "log.h"
#include "lxc.h" /* for lxc_cgroup_set() */
#include "caps.h" /* for lxc_caps_last_cap() */
#include "bdev.h"
#if HAVE_APPARMOR
#include <apparmor.h>
@ -92,30 +100,6 @@ lxc_log_define(lxc_conf, lxc);
#define MAXMTULEN 16
#define MAXLINELEN 128
#ifndef MS_DIRSYNC
#define MS_DIRSYNC 128
#endif
#ifndef MS_REC
#define MS_REC 16384
#endif
#ifndef MNT_DETACH
#define MNT_DETACH 2
#endif
#ifndef MS_SLAVE
#define MS_SLAVE (1<<19)
#endif
#ifndef MS_RELATIME
#define MS_RELATIME (1 << 21)
#endif
#ifndef MS_STRICTATIME
#define MS_STRICTATIME (1 << 24)
#endif
#if HAVE_SYS_CAPABILITY_H
#ifndef CAP_SETFCAP
#define CAP_SETFCAP 31
@ -172,7 +156,7 @@ return -1;
#endif
char *lxchook_names[NUM_LXC_HOOKS] = {
"pre-start", "pre-mount", "mount", "autodev", "start", "post-stop" };
"pre-start", "pre-mount", "mount", "autodev", "start", "post-stop", "clone" };
typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
@ -295,10 +279,75 @@ static struct caps_opt caps_opt[] = {
static struct caps_opt caps_opt[] = {};
#endif
static char padchar[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static char *mkifname(char *template)
{
char *name = NULL;
int i = 0;
FILE *urandom;
unsigned int seed;
struct ifaddrs *ifaddr, *ifa;
int ifexists = 0;
/* Get all the network interfaces */
getifaddrs(&ifaddr);
/* Initialize the random number generator */
urandom = fopen ("/dev/urandom", "r");
if (urandom != NULL) {
if (fread (&seed, sizeof(seed), 1, urandom) <= 0)
seed = time(0);
fclose(urandom);
}
else
seed = time(0);
#ifndef HAVE_RAND_R
srand(seed);
#endif
/* Generate random names until we find one that doesn't exist */
while(1) {
ifexists = 0;
name = strdup(template);
if (name == NULL)
return NULL;
for (i = 0; i < strlen(name); i++) {
if (name[i] == 'X') {
#ifdef HAVE_RAND_R
name[i] = padchar[rand_r(&seed) % (strlen(padchar) - 1)];
#else
name[i] = padchar[rand() % (strlen(padchar) - 1)];
#endif
}
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (strcmp(ifa->ifa_name, name) == 0) {
ifexists = 1;
break;
}
}
if (ifexists == 0)
break;
free(name);
}
freeifaddrs(ifaddr);
return name;
}
static int run_buffer(char *buffer)
{
FILE *f;
char *output;
int ret;
f = popen(buffer, "r");
if (!f) {
@ -309,6 +358,7 @@ static int run_buffer(char *buffer)
output = malloc(LXC_LOG_BUFFER_SIZE);
if (!output) {
ERROR("failed to allocate memory for script output");
pclose(f);
return -1;
}
@ -317,14 +367,72 @@ static int run_buffer(char *buffer)
free(output);
if (pclose(f) == -1) {
ret = pclose(f);
if (ret == -1) {
SYSERROR("Script exited on error");
return -1;
} else if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) {
ERROR("Script exited with status %d", WEXITSTATUS(ret));
return -1;
} else if (WIFSIGNALED(ret)) {
ERROR("Script terminated by signal %d (%s)", WTERMSIG(ret),
strsignal(WTERMSIG(ret)));
return -1;
}
return 0;
}
static int run_script_argv(const char *name, const char *section,
const char *script, const char *hook, const char *lxcpath,
char **argsin)
{
int ret, i;
char *buffer;
size_t size = 0;
INFO("Executing script '%s' for container '%s', config section '%s'",
script, name, section);
for (i=0; argsin && argsin[i]; i++)
size += strlen(argsin[i]) + 1;
size += strlen(hook) + 1;
size += strlen(script);
size += strlen(name);
size += strlen(section);
size += 3;
if (size > INT_MAX)
return -1;
buffer = alloca(size);
if (!buffer) {
ERROR("failed to allocate memory");
return -1;
}
ret = snprintf(buffer, size, "%s %s %s %s", script, name, section, hook);
if (ret < 0 || ret >= size) {
ERROR("Script name too long");
return -1;
}
for (i=0; argsin && argsin[i]; i++) {
int len = size-ret;
int rc;
rc = snprintf(buffer + ret, len, " %s", argsin[i]);
if (rc < 0 || rc >= len) {
ERROR("Script args too long");
return -1;
}
ret += rc;
}
return run_buffer(buffer);
}
static int run_script(const char *name, const char *section,
const char *script, ...)
{
@ -358,7 +466,6 @@ static int run_script(const char *name, const char *section,
ret = snprintf(buffer, size, "%s %s %s", script, name, section);
if (ret < 0 || ret >= size) {
ERROR("Script name too long");
free(buffer);
return -1;
}
@ -368,7 +475,6 @@ static int run_script(const char *name, const char *section,
int rc;
rc = snprintf(buffer + ret, len, " %s", p);
if (rc < 0 || rc >= len) {
free(buffer);
ERROR("Script args too long");
return -1;
}
@ -537,6 +643,7 @@ static int mount_rootfs_file(const char *rootfs, const char *target)
if (errno != ENXIO) {
WARN("unexpected error for ioctl on '%s': %m",
direntp->d_name);
close(fd);
continue;
}
@ -581,8 +688,8 @@ int pin_rootfs(const char *rootfs)
return -2;
if (!realpath(rootfs, absrootfs)) {
SYSERROR("failed to get real path for '%s'", rootfs);
return -1;
INFO("failed to get real path for '%s', not pinning", rootfs);
return -2;
}
if (access(absrootfs, F_OK)) {
@ -700,7 +807,8 @@ static int setup_tty(const struct lxc_rootfs *rootfs,
SYSERROR("error creating %s\n", lxcpath);
return -1;
}
close(ret);
if (ret >= 0)
close(ret);
ret = unlink(path);
if (ret && errno != ENOENT) {
SYSERROR("error unlinking %s\n", path);
@ -749,7 +857,7 @@ static int setup_tty(const struct lxc_rootfs *rootfs,
static int setup_rootfs_pivot_root_cb(char *buffer, void *data)
{
struct lxc_list *mountlist, *listentry, *iterator;
char *pivotdir, *mountpoint, *mountentry;
char *pivotdir, *mountpoint, *mountentry, *saveptr = NULL;
int found;
void **cbparm;
@ -760,12 +868,12 @@ static int setup_rootfs_pivot_root_cb(char *buffer, void *data)
pivotdir = cbparm[1];
/* parse entry, first field is mountname, ignore */
mountpoint = strtok(mountentry, " ");
mountpoint = strtok_r(mountentry, " ", &saveptr);
if (!mountpoint)
return -1;
/* second field is mountpoint */
mountpoint = strtok(NULL, " ");
mountpoint = strtok_r(NULL, " ", &saveptr);
if (!mountpoint)
return -1;
@ -794,6 +902,7 @@ static int setup_rootfs_pivot_root_cb(char *buffer, void *data)
listentry->elem = strdup(mountpoint);
if (!listentry->elem) {
SYSERROR("strdup failed");
free(listentry);
return -1;
}
lxc_list_add_tail(mountlist, listentry);
@ -1055,8 +1164,10 @@ int detect_shared_rootfs(void)
if (strcmp(p+1, "/") == 0) {
// this is '/'. is it shared?
p = index(p2+1, ' ');
if (strstr(p, "shared:"))
if (p && strstr(p, "shared:")) {
fclose(f);
return 1;
}
}
}
fclose(f);
@ -1150,6 +1261,15 @@ static int setup_rootfs(struct lxc_conf *conf)
}
}
// First try mounting rootfs using a bdev
struct bdev *bdev = bdev_init(rootfs->path, rootfs->mount, NULL);
if (bdev && bdev->ops->mount(bdev) == 0) {
bdev_put(bdev);
DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount);
return 0;
}
if (bdev)
bdev_put(bdev);
if (mount_rootfs(rootfs->path, rootfs->mount)) {
ERROR("failed to mount rootfs");
return -1;
@ -1248,8 +1368,8 @@ static int setup_dev_console(const struct lxc_rootfs *rootfs,
return 0;
}
if (console->peer == -1) {
INFO("no console output required");
if (console->master < 0) {
INFO("no console");
return 0;
}
@ -1311,10 +1431,11 @@ static int setup_ttydir_console(const struct lxc_rootfs *rootfs,
SYSERROR("error %d creating %s\n", errno, lxcpath);
return -1;
}
close(ret);
if (ret >= 0)
close(ret);
if (console->peer == -1) {
INFO("no console output required");
if (console->master < 0) {
INFO("no console");
return 0;
}
@ -1380,34 +1501,6 @@ static int setup_kmsg(const struct lxc_rootfs *rootfs,
return 0;
}
int setup_cgroup(const char *cgpath, struct lxc_list *cgroups)
{
struct lxc_list *iterator;
struct lxc_cgroup *cg;
int ret = -1;
if (lxc_list_empty(cgroups))
return 0;
lxc_list_for_each(iterator, cgroups) {
cg = iterator->elem;
if (lxc_cgroup_set_bypath(cgpath, cg->subsystem, cg->value)) {
ERROR("Error setting %s to %s for %s\n", cg->subsystem,
cg->value, cgpath);
goto out;
}
DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
}
ret = 0;
INFO("cgroup has been setup");
out:
return ret;
}
static void parse_mntopt(char *opt, unsigned long *flags, char **data)
{
struct mount_opt *mo;
@ -1745,7 +1838,76 @@ static int setup_caps(struct lxc_list *caps)
}
DEBUG("capabilities has been setup");
DEBUG("capabilities have been setup");
return 0;
}
static int dropcaps_except(struct lxc_list *caps)
{
struct lxc_list *iterator;
char *keep_entry;
char *ptr;
int i, capid;
int numcaps = lxc_caps_last_cap() + 1;
INFO("found %d capabilities\n", numcaps);
if (numcaps <= 0 || numcaps > 200)
return -1;
// caplist[i] is 1 if we keep capability i
int *caplist = alloca(numcaps * sizeof(int));
memset(caplist, 0, numcaps * sizeof(int));
lxc_list_for_each(iterator, caps) {
keep_entry = iterator->elem;
capid = -1;
for (i = 0; i < sizeof(caps_opt)/sizeof(caps_opt[0]); i++) {
if (strcmp(keep_entry, caps_opt[i].name))
continue;
capid = caps_opt[i].value;
break;
}
if (capid < 0) {
/* try to see if it's numeric, so the user may specify
* capabilities that the running kernel knows about but
* we don't */
capid = strtol(keep_entry, &ptr, 10);
if (!ptr || *ptr != '\0' ||
capid == LONG_MIN || capid == LONG_MAX)
/* not a valid number */
capid = -1;
else if (capid > lxc_caps_last_cap())
/* we have a number but it's not a valid
* capability */
capid = -1;
}
if (capid < 0) {
ERROR("unknown capability %s", keep_entry);
return -1;
}
DEBUG("drop capability '%s' (%d)", keep_entry, capid);
caplist[capid] = 1;
}
for (i=0; i<numcaps; i++) {
if (caplist[i])
continue;
if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0)) {
SYSERROR("failed to remove capability %d", i);
return -1;
}
}
DEBUG("capabilities have been setup");
return 0;
}
@ -2063,21 +2225,31 @@ struct lxc_conf *lxc_conf_init(void)
}
memset(new, 0, sizeof(*new));
new->loglevel = LXC_LOG_PRIORITY_NOTSET;
new->personality = -1;
new->console.log_path = NULL;
new->console.log_fd = -1;
new->console.path = NULL;
new->console.peer = -1;
new->console.peerpty.busy = -1;
new->console.peerpty.master = -1;
new->console.peerpty.slave = -1;
new->console.master = -1;
new->console.slave = -1;
new->console.name[0] = '\0';
new->maincmd_fd = -1;
new->rootfs.mount = default_rootfs_mount;
new->rootfs.mount = strdup(default_rootfs_mount);
if (!new->rootfs.mount) {
ERROR("lxc_conf_init : %m");
free(new);
return NULL;
}
new->kmsg = 1;
lxc_list_init(&new->cgroup);
lxc_list_init(&new->network);
lxc_list_init(&new->mount_list);
lxc_list_init(&new->caps);
lxc_list_init(&new->keepcaps);
lxc_list_init(&new->id_map);
for (i=0; i<NUM_LXC_HOOKS; i++)
lxc_list_init(&new->hooks[i]);
@ -2105,13 +2277,13 @@ static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
ERROR("veth1 name too long");
return -1;
}
veth1 = mktemp(veth1buf);
veth1 = mkifname(veth1buf);
/* store away for deconf */
memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
}
snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
veth2 = mktemp(veth2buf);
veth2 = mkifname(veth2buf);
if (!strlen(veth1) || !strlen(veth2)) {
ERROR("failed to allocate a temporary name");
@ -2217,7 +2389,7 @@ static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n
if (err >= sizeof(peerbuf))
return -1;
peer = mktemp(peerbuf);
peer = mkifname(peerbuf);
if (!strlen(peer)) {
ERROR("failed to make a temporary name");
return -1;
@ -2715,7 +2887,7 @@ int uid_shift_ttys(int pid, struct lxc_conf *conf)
return 0;
}
int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char *lxcpath)
{
#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
int mounted;
@ -2731,7 +2903,7 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
return -1;
}
if (run_lxc_hooks(name, "pre-mount", lxc_conf)) {
if (run_lxc_hooks(name, "pre-mount", lxc_conf, lxcpath, NULL)) {
ERROR("failed to run pre-mount hooks for container '%s'.", name);
return -1;
}
@ -2758,13 +2930,13 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
return -1;
}
if (run_lxc_hooks(name, "mount", lxc_conf)) {
if (run_lxc_hooks(name, "mount", lxc_conf, lxcpath, NULL)) {
ERROR("failed to run mount hooks for container '%s'.", name);
return -1;
}
if (lxc_conf->autodev) {
if (run_lxc_hooks(name, "autodev", lxc_conf)) {
if (run_lxc_hooks(name, "autodev", lxc_conf, lxcpath, NULL)) {
ERROR("failed to run autodev hooks for container '%s'.", name);
return -1;
}
@ -2774,7 +2946,7 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
}
}
if (setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
if (!lxc_conf->is_execute && setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
ERROR("failed to setup the console for '%s'", name);
return -1;
}
@ -2784,7 +2956,7 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
ERROR("failed to setup kmsg for '%s'", name);
}
if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) {
if (!lxc_conf->is_execute && setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) {
ERROR("failed to setup the ttys for '%s'", name);
return -1;
}
@ -2792,9 +2964,13 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
INFO("rootfs path is .%s., mount is .%s.", lxc_conf->rootfs.path,
lxc_conf->rootfs.mount);
if (lxc_conf->rootfs.path == NULL || strlen(lxc_conf->rootfs.path) == 0)
mounted = 0;
else
if (lxc_conf->rootfs.path == NULL || strlen(lxc_conf->rootfs.path) == 0) {
if (mount("proc", "/proc", "proc", 0, NULL)) {
SYSERROR("Failed mounting /proc, proceeding");
mounted = 0;
} else
mounted = 1;
} else
mounted = lsm_mount_proc_if_needed(lxc_conf->rootfs.path, lxc_conf->rootfs.mount);
if (mounted == -1) {
SYSERROR("failed to mount /proc in the container.");
@ -2820,7 +2996,16 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
}
if (lxc_list_empty(&lxc_conf->id_map)) {
if (setup_caps(&lxc_conf->caps)) {
if (!lxc_list_empty(&lxc_conf->keepcaps)) {
if (!lxc_list_empty(&lxc_conf->caps)) {
ERROR("Simultaneously requested dropping and keeping caps");
return -1;
}
if (dropcaps_except(&lxc_conf->keepcaps)) {
ERROR("failed to keep requested caps\n");
return -1;
}
} else if (setup_caps(&lxc_conf->caps)) {
ERROR("failed to drop capabilities");
return -1;
}
@ -2831,7 +3016,8 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
return 0;
}
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
const char *lxcpath, char *argv[])
{
int which = -1;
struct lxc_list *it;
@ -2848,12 +3034,14 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
which = LXCHOOK_START;
else if (strcmp(hook, "post-stop") == 0)
which = LXCHOOK_POSTSTOP;
else if (strcmp(hook, "clone") == 0)
which = LXCHOOK_CLONE;
else
return -1;
lxc_list_for_each(it, &conf->hooks[which]) {
int ret;
char *hookname = it->elem;
ret = run_script(name, "lxc", hookname, hook, NULL);
ret = run_script_argv(name, "lxc", hookname, hook, lxcpath, argv);
if (ret)
return ret;
}
@ -3004,6 +3192,30 @@ int lxc_clear_config_caps(struct lxc_conf *c)
return 0;
}
int lxc_clear_idmaps(struct lxc_conf *c)
{
struct lxc_list *it, *next;
lxc_list_for_each_safe(it, &c->id_map, next) {
lxc_list_del(it);
free(it->elem);
free(it);
}
return 0;
}
int lxc_clear_config_keepcaps(struct lxc_conf *c)
{
struct lxc_list *it,*next;
lxc_list_for_each_safe(it, &c->keepcaps, next) {
lxc_list_del(it);
free(it->elem);
free(it);
}
return 0;
}
int lxc_clear_cgroups(struct lxc_conf *c, const char *key)
{
struct lxc_list *it,*next;
@ -3084,7 +3296,7 @@ void lxc_conf_free(struct lxc_conf *conf)
return;
if (conf->console.path)
free(conf->console.path);
if (conf->rootfs.mount != default_rootfs_mount)
if (conf->rootfs.mount)
free(conf->rootfs.mount);
if (conf->rootfs.path)
free(conf->rootfs.path);
@ -3094,6 +3306,8 @@ void lxc_conf_free(struct lxc_conf *conf)
free(conf->ttydir);
if (conf->fstab)
free(conf->fstab);
if (conf->rcfile)
free(conf->rcfile);
lxc_clear_config_network(conf);
#if HAVE_APPARMOR
if (conf->aa_profile)
@ -3101,9 +3315,11 @@ void lxc_conf_free(struct lxc_conf *conf)
#endif
lxc_seccomp_free(conf);
lxc_clear_config_caps(conf);
lxc_clear_config_keepcaps(conf);
lxc_clear_cgroups(conf, "lxc.cgroup");
lxc_clear_hooks(conf, "lxc.hook");
lxc_clear_mount_entries(conf);
lxc_clear_saved_nics(conf);
lxc_clear_idmaps(conf);
free(conf);
}

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _conf_h
#define _conf_h
@ -188,6 +188,8 @@ struct lxc_tty_info {
struct lxc_pty_info *pty_info;
};
struct lxc_tty_state;
/*
* Defines the structure to store the console information
* @peer : the file descriptor put/get console traffic
@ -197,11 +199,14 @@ struct lxc_console {
int slave;
int master;
int peer;
struct lxc_pty_info peerpty;
struct lxc_epoll_descr *descr;
char *path;
char *log_path;
int log_fd;
char name[MAXPATHLEN];
struct termios *tios;
struct lxc_tty_state *tty_state;
};
/*
@ -227,7 +232,8 @@ struct lxc_rootfs {
* @network : network configuration
* @utsname : container utsname
* @fstab : path to a fstab file format
* @caps : list of the capabilities
* @caps : list of the capabilities to drop
* @keepcaps : list of the capabilities to keep
* @tty_info : tty data
* @console : console data
* @ttydir : directory (under /dev) in which to create console and ttys
@ -237,7 +243,7 @@ struct lxc_rootfs {
*/
enum lxchooks {
LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_AUTODEV,
LXCHOOK_START, LXCHOOK_POSTSTOP, NUM_LXC_HOOKS};
LXCHOOK_START, LXCHOOK_POSTSTOP, LXCHOOK_CLONE, NUM_LXC_HOOKS};
extern char *lxchook_names[NUM_LXC_HOOKS];
struct saved_nic {
@ -246,6 +252,7 @@ struct saved_nic {
};
struct lxc_conf {
int is_execute;
char *fstab;
int tty;
int pts;
@ -260,6 +267,7 @@ struct lxc_conf {
int num_savednics;
struct lxc_list mount_list;
struct lxc_list caps;
struct lxc_list keepcaps;
struct lxc_tty_info tty_info;
struct lxc_console console;
struct lxc_rootfs rootfs;
@ -282,11 +290,19 @@ struct lxc_conf {
int stopsignal; // signal used to stop container
int kmsg; // if 1, create /dev/kmsg symlink
char *rcfile; // Copy of the top level rcfile we read
// Logfile and logleve can be set in a container config file.
// Those function as defaults. The defaults can be overriden
// by command line. However we don't want the command line
// specified values to be saved on c->save_config(). So we
// store the config file specified values here.
char *logfile; // the logfile as specifed in config
int loglevel; // loglevel as specifed in config (if any)
};
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
const char *lxcpath, char *argv[]);
extern int setup_cgroup(const char *cgpath, struct lxc_list *cgroups);
extern int detect_shared_rootfs(void);
/*
@ -309,19 +325,19 @@ extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
extern int lxc_clear_config_network(struct lxc_conf *c);
extern int lxc_clear_nic(struct lxc_conf *c, const char *key);
extern int lxc_clear_config_caps(struct lxc_conf *c);
extern int lxc_clear_config_keepcaps(struct lxc_conf *c);
extern int lxc_clear_cgroups(struct lxc_conf *c, const char *key);
extern int lxc_clear_mount_entries(struct lxc_conf *c);
extern int lxc_clear_hooks(struct lxc_conf *c, const char *key);
extern int setup_cgroup(const char *name, struct lxc_list *cgroups);
extern int uid_shift_ttys(int pid, struct lxc_conf *conf);
/*
* Configure the container from inside
*/
extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf);
extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf,
const char *lxcpath);
extern void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf);
#endif

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _GNU_SOURCE
#include <stdio.h>
@ -85,6 +85,7 @@ static int config_network_script(const char *, const char *, struct lxc_conf *);
static int config_network_ipv6(const char *, const char *, struct lxc_conf *);
static int config_network_ipv6_gateway(const char *, const char *, struct lxc_conf *);
static int config_cap_drop(const char *, const char *, struct lxc_conf *);
static int config_cap_keep(const char *, const char *, struct lxc_conf *);
static int config_console(const char *, const char *, struct lxc_conf *);
static int config_seccomp(const char *, const char *, struct lxc_conf *);
static int config_includefile(const char *, const char *, struct lxc_conf *);
@ -117,6 +118,7 @@ static struct lxc_config_t config[] = {
{ "lxc.hook.autodev", config_hook },
{ "lxc.hook.start", config_hook },
{ "lxc.hook.post-stop", config_hook },
{ "lxc.hook.clone", config_hook },
{ "lxc.network.type", config_network_type },
{ "lxc.network.flags", config_network_flags },
{ "lxc.network.link", config_network_link },
@ -135,6 +137,7 @@ static struct lxc_config_t config[] = {
/* config_network_nic must come after all other 'lxc.network.*' entries */
{ "lxc.network.", config_network_nic },
{ "lxc.cap.drop", config_cap_drop },
{ "lxc.cap.keep", config_cap_keep },
{ "lxc.console", config_console },
{ "lxc.seccomp", config_seccomp },
{ "lxc.include", config_includefile },
@ -272,6 +275,7 @@ static int config_network_type(const char *key, const char *value,
list = malloc(sizeof(*list));
if (!list) {
SYSERROR("failed to allocate memory");
free(netdev);
return -1;
}
@ -610,6 +614,7 @@ static int config_network_ipv4(const char *key, const char *value,
list = malloc(sizeof(*list));
if (!list) {
SYSERROR("failed to allocate memory");
free(inetdev);
return -1;
}
@ -619,6 +624,8 @@ static int config_network_ipv4(const char *key, const char *value,
addr = strdup(value);
if (!addr) {
ERROR("no address specified");
free(inetdev);
free(list);
return -1;
}
@ -636,12 +643,16 @@ static int config_network_ipv4(const char *key, const char *value,
if (!inet_pton(AF_INET, addr, &inetdev->addr)) {
SYSERROR("invalid ipv4 address: %s", value);
free(inetdev);
free(addr);
free(list);
return -1;
}
if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) {
SYSERROR("invalid ipv4 broadcast address: %s", value);
free(inetdev);
free(list);
free(addr);
return -1;
}
@ -683,6 +694,7 @@ static int config_network_ipv4_gateway(const char *key, const char *value,
if (!value) {
ERROR("no ipv4 gateway address specified");
free(gw);
return -1;
}
@ -692,6 +704,7 @@ static int config_network_ipv4_gateway(const char *key, const char *value,
} else {
if (!inet_pton(AF_INET, value, gw)) {
SYSERROR("invalid ipv4 gateway address: %s", value);
free(gw);
return -1;
}
@ -725,6 +738,7 @@ static int config_network_ipv6(const char *key, const char *value,
list = malloc(sizeof(*list));
if (!list) {
SYSERROR("failed to allocate memory");
free(inet6dev);
return -1;
}
@ -734,6 +748,8 @@ static int config_network_ipv6(const char *key, const char *value,
valdup = strdup(value);
if (!valdup) {
ERROR("no address specified");
free(list);
free(inet6dev);
return -1;
}
@ -745,8 +761,10 @@ static int config_network_ipv6(const char *key, const char *value,
inet6dev->prefix = atoi(netmask);
}
if (!inet_pton(AF_INET6, value, &inet6dev->addr)) {
SYSERROR("invalid ipv6 address: %s", value);
if (!inet_pton(AF_INET6, valdup, &inet6dev->addr)) {
SYSERROR("invalid ipv6 address: %s", valdup);
free(list);
free(inet6dev);
free(valdup);
return -1;
}
@ -761,18 +779,11 @@ static int config_network_ipv6_gateway(const char *key, const char *value,
struct lxc_conf *lxc_conf)
{
struct lxc_netdev *netdev;
struct in6_addr *gw;
netdev = network_netdev(key, value, &lxc_conf->network);
if (!netdev)
return -1;
gw = malloc(sizeof(*gw));
if (!gw) {
SYSERROR("failed to allocate ipv6 gateway address");
return -1;
}
if (!value) {
ERROR("no ipv6 gateway address specified");
return -1;
@ -782,8 +793,17 @@ static int config_network_ipv6_gateway(const char *key, const char *value,
netdev->ipv6_gateway = NULL;
netdev->ipv6_gateway_auto = true;
} else {
struct in6_addr *gw;
gw = malloc(sizeof(*gw));
if (!gw) {
SYSERROR("failed to allocate ipv6 gateway address");
return -1;
}
if (!inet_pton(AF_INET6, value, gw)) {
SYSERROR("invalid ipv6 gateway address: %s", value);
free(gw);
return -1;
}
@ -877,6 +897,8 @@ static int config_hook(const char *key, const char *value,
return add_hook(lxc_conf, LXCHOOK_START, copy);
else if (strcmp(key, "lxc.hook.post-stop") == 0)
return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
else if (strcmp(key, "lxc.hook.clone") == 0)
return add_hook(lxc_conf, LXCHOOK_CLONE, copy);
SYSERROR("Unknown key: %s", key);
free(copy);
return -1;
@ -970,6 +992,11 @@ static int config_aa_profile(const char *key, const char *value,
static int config_logfile(const char *key, const char *value,
struct lxc_conf *lxc_conf)
{
// store these values in the lxc_conf, and then try to set for
// actual current logging.
if (lxc_conf->logfile)
free(lxc_conf->logfile);
lxc_conf->logfile = strdup(value);
return lxc_log_set_file(value);
}
@ -989,6 +1016,9 @@ static int config_loglevel(const char *key, const char *value,
newlevel = atoi(value);
else
newlevel = lxc_log_priority_to_int(value);
// store these values in the lxc_conf, and then try to set for
// actual current logging.
lxc_conf->loglevel = newlevel;
return lxc_log_set_level(newlevel);
}
@ -1233,8 +1263,10 @@ static int config_mount(const char *key, const char *value,
return -1;
mntelem = strdup(value);
if (!mntelem)
if (!mntelem) {
free(mntlist);
return -1;
}
mntlist->elem = mntelem;
lxc_list_add_tail(&lxc_conf->mount_list, mntlist);
@ -1242,6 +1274,52 @@ static int config_mount(const char *key, const char *value,
return 0;
}
static int config_cap_keep(const char *key, const char *value,
struct lxc_conf *lxc_conf)
{
char *keepcaps, *keepptr, *sptr, *token;
struct lxc_list *keeplist;
int ret = -1;
if (!strlen(value))
return -1;
keepcaps = strdup(value);
if (!keepcaps) {
SYSERROR("failed to dup '%s'", value);
return -1;
}
/* in case several capability keep is specified in a single line
* split these caps in a single element for the list */
for (keepptr = keepcaps;;keepptr = NULL) {
token = strtok_r(keepptr, " \t", &sptr);
if (!token) {
ret = 0;
break;
}
keeplist = malloc(sizeof(*keeplist));
if (!keeplist) {
SYSERROR("failed to allocate keepcap list");
break;
}
keeplist->elem = strdup(token);
if (!keeplist->elem) {
SYSERROR("failed to dup '%s'", token);
free(keeplist);
break;
}
lxc_list_add_tail(&lxc_conf->keepcaps, keeplist);
}
free(keepcaps);
return ret;
}
static int config_cap_drop(const char *key, const char *value,
struct lxc_conf *lxc_conf)
{
@ -1344,6 +1422,7 @@ static int config_utsname(const char *key, const char *value,
if (strlen(value) >= sizeof(utsname->nodename)) {
ERROR("node name '%s' is too long",
utsname->nodename);
free(utsname);
return -1;
}
@ -1607,6 +1686,22 @@ static int lxc_get_item_cap_drop(struct lxc_conf *c, char *retv, int inlen)
return fulllen;
}
static int lxc_get_item_cap_keep(struct lxc_conf *c, char *retv, int inlen)
{
int len, fulllen = 0;
struct lxc_list *it;
if (!retv)
inlen = 0;
else
memset(retv, 0, inlen);
lxc_list_for_each(it, &c->keepcaps) {
strprint(retv, inlen, "%s\n", (char *)it->elem);
}
return fulllen;
}
static int lxc_get_mount_entries(struct lxc_conf *c, char *retv, int inlen)
{
int len, fulllen = 0;
@ -1682,8 +1777,12 @@ static int lxc_get_item_nic(struct lxc_conf *c, char *retv, int inlen,
strprint(retv, inlen, "%s", mode);
}
} else if (strcmp(p1, "veth.pair") == 0) {
if (netdev->type == LXC_NET_VETH && netdev->priv.veth_attr.pair)
strprint(retv, inlen, "%s", netdev->priv.veth_attr.pair);
if (netdev->type == LXC_NET_VETH) {
strprint(retv, inlen, "%s",
netdev->priv.veth_attr.pair ?
netdev->priv.veth_attr.pair :
netdev->priv.veth_attr.veth1);
}
} else if (strcmp(p1, "vlan") == 0) {
if (netdev->type == LXC_NET_VLAN) {
strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
@ -1783,6 +1882,8 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
v = c->rootfs.pivot;
else if (strcmp(key, "lxc.cap.drop") == 0)
return lxc_get_item_cap_drop(c, retv, inlen);
else if (strcmp(key, "lxc.cap.keep") == 0)
return lxc_get_item_cap_keep(c, retv, inlen);
else if (strncmp(key, "lxc.hook", 8) == 0)
return lxc_get_item_hooks(c, retv, inlen, key);
else if (strcmp(key, "lxc.network") == 0)
@ -1806,6 +1907,8 @@ int lxc_clear_config_item(struct lxc_conf *c, const char *key)
return lxc_clear_nic(c, key + 12);
else if (strcmp(key, "lxc.cap.drop") == 0)
return lxc_clear_config_caps(c);
else if (strcmp(key, "lxc.cap.keep") == 0)
return lxc_clear_config_keepcaps(c);
else if (strncmp(key, "lxc.cgroup", 10) == 0)
return lxc_clear_cgroups(c, key);
else if (strcmp(key, "lxc.mount.entries") == 0)
@ -1846,10 +1949,10 @@ void write_config(FILE *fout, struct lxc_conf *c)
if (c->aa_profile)
fprintf(fout, "lxc.aa_profile = %s\n", c->aa_profile);
#endif
if (lxc_log_get_level() != LXC_LOG_PRIORITY_NOTSET)
fprintf(fout, "lxc.loglevel = %s\n", lxc_log_priority_to_string(lxc_log_get_level()));
if (lxc_log_get_file())
fprintf(fout, "lxc.logfile = %s\n", lxc_log_get_file());
if (c->loglevel != LXC_LOG_PRIORITY_NOTSET)
fprintf(fout, "lxc.loglevel = %s\n", lxc_log_priority_to_string(c->loglevel));
if (c->logfile)
fprintf(fout, "lxc.logfile = %s\n", c->logfile);
lxc_list_for_each(it, &c->cgroup) {
struct lxc_cgroup *cg = it->elem;
fprintf(fout, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value);
@ -1918,6 +2021,14 @@ void write_config(FILE *fout, struct lxc_conf *c)
}
lxc_list_for_each(it, &c->caps)
fprintf(fout, "lxc.cap.drop = %s\n", (char *)it->elem);
lxc_list_for_each(it, &c->keepcaps)
fprintf(fout, "lxc.cap.keep = %s\n", (char *)it->elem);
lxc_list_for_each(it, &c->id_map) {
struct id_map *idmap = it->elem;
fprintf(fout, "lxc.id_map = %c %lu %lu %lu\n",
idmap->idtype == ID_TYPE_UID ? 'u' : 'g', idmap->nsid,
idmap->hostid, idmap->range);
}
for (i=0; i<NUM_LXC_HOOKS; i++) {
lxc_list_for_each(it, &c->hooks[i])
fprintf(fout, "lxc.hook.%s = %s\n",

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>

View File

@ -18,9 +18,11 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -29,6 +31,7 @@
#include <sys/types.h>
#include <termios.h>
#include "lxccontainer.h"
#include "log.h"
#include "conf.h"
#include "config.h"
@ -37,6 +40,8 @@
#include "commands.h"
#include "mainloop.h"
#include "af_unix.h"
#include "lxclock.h"
#include "utils.h"
#if HAVE_PTY_H
#include <pty.h>
@ -46,240 +51,495 @@
lxc_log_define(lxc_console, lxc);
extern int lxc_console(const char *name, int ttynum, int *fd, const char *lxcpath)
static struct lxc_list lxc_ttys;
typedef void (*sighandler_t)(int);
struct lxc_tty_state
{
int ret, stopped = 0;
struct lxc_command command = {
.request = { .type = LXC_COMMAND_TTY, .data = ttynum },
};
struct lxc_list node;
int stdinfd;
int stdoutfd;
int masterfd;
int escape;
int saw_escape;
const char *winch_proxy;
const char *winch_proxy_lxcpath;
int sigfd;
sigset_t oldmask;
};
ret = lxc_command_connected(name, &command, &stopped, lxcpath);
if (ret < 0 && stopped) {
ERROR("'%s' is stopped", name);
__attribute__((constructor))
void lxc_console_init(void)
{
lxc_list_init(&lxc_ttys);
}
/* lxc_console_winsz: propagte winsz from one terminal to another
*
* @srcfd : terminal to get size from (typically a slave pty)
* @dstfd : terminal to set size on (typically a master pty)
*/
static void lxc_console_winsz(int srcfd, int dstfd)
{
struct winsize wsz;
if (isatty(srcfd) && ioctl(srcfd, TIOCGWINSZ, &wsz) == 0) {
DEBUG("set winsz dstfd:%d cols:%d rows:%d", dstfd,
wsz.ws_col, wsz.ws_row);
ioctl(dstfd, TIOCSWINSZ, &wsz);
}
}
static void lxc_console_winch(struct lxc_tty_state *ts)
{
lxc_console_winsz(ts->stdinfd, ts->masterfd);
if (ts->winch_proxy) {
lxc_cmd_console_winch(ts->winch_proxy,
ts->winch_proxy_lxcpath);
}
}
void lxc_console_sigwinch(int sig)
{
if (process_lock() == 0) {
struct lxc_list *it;
struct lxc_tty_state *ts;
lxc_list_for_each(it, &lxc_ttys) {
ts = it->elem;
lxc_console_winch(ts);
}
process_unlock();
}
}
static int lxc_console_cb_sigwinch_fd(int fd, void *cbdata,
struct lxc_epoll_descr *descr)
{
struct signalfd_siginfo siginfo;
struct lxc_tty_state *ts = cbdata;
if (read(fd, &siginfo, sizeof(siginfo)) < 0) {
ERROR("failed to read signal info");
return -1;
}
if (ret < 0) {
ERROR("failed to send command");
return -1;
}
if (!ret) {
ERROR("console denied by '%s'", name);
return -1;
}
if (command.answer.ret) {
ERROR("console access denied: %s",
strerror(-command.answer.ret));
return -1;
}
*fd = command.answer.fd;
if (*fd <0) {
ERROR("unable to allocate fd for tty %d", ttynum);
return -1;
}
INFO("tty %d allocated", ttynum);
lxc_console_winch(ts);
return 0;
}
/*----------------------------------------------------------------------------
* functions used by lxc-start mainloop
* to handle above command request.
*--------------------------------------------------------------------------*/
extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info)
/*
* lxc_console_sigwinch_init: install SIGWINCH handler
*
* @srcfd : src for winsz in SIGWINCH handler
* @dstfd : dst for winsz in SIGWINCH handler
*
* Returns lxc_tty_state structure on success or NULL on failure. The sigfd
* member of the returned lxc_tty_state can be select()/poll()ed/epoll()ed
* on (ie added to a mainloop) for SIGWINCH.
*
* Must be called with process_lock held to protect the lxc_ttys list, or
* from a non-threaded context.
*
* Note that SIGWINCH isn't installed as a classic asychronous handler,
* rather signalfd(2) is used so that we can handle the signal when we're
* ready for it. This avoids deadlocks since a signal handler
* (ie lxc_console_sigwinch()) would need to take the thread mutex to
* prevent lxc_ttys list corruption, but using the fd we can provide the
* tty_state needed to the callback (lxc_console_cb_sigwinch_fd()).
*/
static struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
{
int i;
sigset_t mask;
struct lxc_tty_state *ts;
for (i = 0; i < tty_info->nbtty; i++) {
ts = malloc(sizeof(*ts));
if (!ts)
return NULL;
if (tty_info->pty_info[i].busy != fd)
continue;
memset(ts, 0, sizeof(*ts));
ts->stdinfd = srcfd;
ts->masterfd = dstfd;
ts->sigfd = -1;
tty_info->pty_info[i].busy = 0;
/* add tty to list to be scanned at SIGWINCH time */
lxc_list_add_elem(&ts->node, ts);
lxc_list_add_tail(&lxc_ttys, &ts->node);
sigemptyset(&mask);
sigaddset(&mask, SIGWINCH);
if (sigprocmask(SIG_BLOCK, &mask, &ts->oldmask)) {
SYSERROR("failed to block SIGWINCH");
goto err1;
}
return;
ts->sigfd = signalfd(-1, &mask, 0);
if (ts->sigfd < 0) {
SYSERROR("failed to get signalfd");
goto err2;
}
DEBUG("%d got SIGWINCH fd %d", getpid(), ts->sigfd);
goto out;
err2:
sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
err1:
lxc_list_del(&ts->node);
free(ts);
ts = NULL;
out:
return ts;
}
extern int lxc_console_callback(int fd, struct lxc_request *request,
struct lxc_handler *handler)
/*
* lxc_console_sigwinch_fini: uninstall SIGWINCH handler
*
* @ts : the lxc_tty_state returned by lxc_console_sigwinch_init
*
* Restore the saved signal handler that was in effect at the time
* lxc_console_sigwinch_init() was called.
*
* Must be called with process_lock held to protect the lxc_ttys list, or
* from a non-threaded context.
*/
static void lxc_console_sigwinch_fini(struct lxc_tty_state *ts)
{
int ttynum = request->data;
struct lxc_tty_info *tty_info = &handler->conf->tty_info;
if (ts->sigfd >= 0)
close(ts->sigfd);
lxc_list_del(&ts->node);
sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
free(ts);
}
if (ttynum > 0) {
if (ttynum > tty_info->nbtty)
goto out_close;
static int lxc_console_cb_con(int fd, void *data,
struct lxc_epoll_descr *descr)
{
struct lxc_console *console = (struct lxc_console *)data;
char buf[1024];
int r,w;
if (tty_info->pty_info[ttynum - 1].busy)
goto out_close;
goto out_send;
w = r = read(fd, buf, sizeof(buf));
if (r < 0) {
SYSERROR("failed to read");
return 1;
}
/* fixup index tty1 => [0] */
if (!r) {
INFO("console client on fd %d has exited", fd);
lxc_mainloop_del_handler(descr, fd);
close(fd);
return 0;
}
if (fd == console->peer)
w = write(console->master, buf, r);
if (fd == console->master) {
if (console->log_fd >= 0)
w = write(console->log_fd, buf, r);
if (console->peer >= 0)
w = write(console->peer, buf, r);
}
if (w != r)
WARN("console short write r:%d w:%d", r, w);
return 0;
}
static void lxc_console_mainloop_add_peer(struct lxc_console *console)
{
if (console->peer >= 0) {
if (lxc_mainloop_add_handler(console->descr, console->peer,
lxc_console_cb_con, console))
WARN("console peer not added to mainloop");
}
if (console->tty_state) {
if (lxc_mainloop_add_handler(console->descr,
console->tty_state->sigfd,
lxc_console_cb_sigwinch_fd,
console->tty_state)) {
WARN("failed to add to mainloop SIGWINCH handler for '%d'",
console->tty_state->sigfd);
}
}
}
int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
struct lxc_handler *handler)
{
struct lxc_conf *conf = handler->conf;
struct lxc_console *console = &conf->console;
if (conf->is_execute) {
INFO("no console for lxc-execute.");
return 0;
}
if (!conf->rootfs.path) {
INFO("no rootfs, no console.");
return 0;
}
if (console->master < 0) {
INFO("no console");
return 0;
}
if (lxc_mainloop_add_handler(descr, console->master,
lxc_console_cb_con, console)) {
ERROR("failed to add to mainloop console handler for '%d'",
console->master);
return -1;
}
/* we cache the descr so that we can add an fd to it when someone
* does attach to it in lxc_console_allocate()
*/
console->descr = descr;
lxc_console_mainloop_add_peer(console);
return 0;
}
static int setup_tios(int fd, struct termios *oldtios)
{
struct termios newtios;
if (!isatty(fd)) {
ERROR("'%d' is not a tty", fd);
return -1;
}
/* Get current termios */
if (tcgetattr(fd, oldtios)) {
SYSERROR("failed to get current terminal settings");
return -1;
}
newtios = *oldtios;
/* Remove the echo characters and signal reception, the echo
* will be done with master proxying */
newtios.c_iflag &= ~IGNBRK;
newtios.c_iflag &= BRKINT;
newtios.c_lflag &= ~(ECHO|ICANON|ISIG);
newtios.c_cc[VMIN] = 1;
newtios.c_cc[VTIME] = 0;
/* Set new attributes */
if (tcsetattr(fd, TCSAFLUSH, &newtios)) {
ERROR("failed to set new terminal settings");
return -1;
}
return 0;
}
static void lxc_console_peer_proxy_free(struct lxc_console *console)
{
if (console->tty_state) {
lxc_console_sigwinch_fini(console->tty_state);
console->tty_state = NULL;
}
close(console->peerpty.master);
close(console->peerpty.slave);
console->peerpty.master = -1;
console->peerpty.slave = -1;
console->peerpty.busy = -1;
console->peerpty.name[0] = '\0';
console->peer = -1;
}
static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd)
{
struct termios oldtermio;
struct lxc_tty_state *ts;
if (console->master < 0) {
ERROR("console not set up");
return -1;
}
if (console->peerpty.busy != -1 || console->peer != -1) {
NOTICE("console already in use");
return -1;
}
if (console->tty_state) {
ERROR("console already has tty_state");
return -1;
}
/* this is the proxy pty that will be given to the client, and that
* the real pty master will send to / recv from
*/
if (openpty(&console->peerpty.master, &console->peerpty.slave,
console->peerpty.name, NULL, NULL)) {
SYSERROR("failed to create proxy pty");
return -1;
}
if (setup_tios(console->peerpty.slave, &oldtermio) < 0)
goto err1;
ts = lxc_console_sigwinch_init(console->peerpty.master, console->master);
if (!ts)
goto err1;
console->tty_state = ts;
console->peer = console->peerpty.slave;
console->peerpty.busy = sockfd;
lxc_console_mainloop_add_peer(console);
DEBUG("%d %s peermaster:%d sockfd:%d", getpid(), __FUNCTION__, console->peerpty.master, sockfd);
return 0;
err1:
lxc_console_peer_proxy_free(console);
return -1;
}
/* lxc_console_allocate: allocate the console or a tty
*
* @conf : the configuration of the container to allocate from
* @sockfd : the socket fd whose remote side when closed, will be an
* indication that the console or tty is no longer in use
* @ttyreq : the tty requested to be opened, -1 for any, 0 for the console
*/
int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
{
int masterfd = -1, ttynum;
struct lxc_tty_info *tty_info = &conf->tty_info;
struct lxc_console *console = &conf->console;
process_lock();
if (*ttyreq == 0) {
if (lxc_console_peer_proxy_alloc(console, sockfd) < 0)
goto out;
masterfd = console->peerpty.master;
goto out;
}
if (*ttyreq > 0) {
if (*ttyreq > tty_info->nbtty)
goto out;
if (tty_info->pty_info[*ttyreq - 1].busy)
goto out;
/* the requested tty is available */
ttynum = *ttyreq;
goto out_tty;
}
/* search for next available tty, fixup index tty1 => [0] */
for (ttynum = 1;
ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
ttynum++);
/* we didn't find any available slot for tty */
if (ttynum > tty_info->nbtty)
goto out_close;
goto out;
out_send:
if (lxc_af_unix_send_fd(fd, tty_info->pty_info[ttynum - 1].master,
&ttynum, sizeof(ttynum)) < 0) {
ERROR("failed to send tty to client");
goto out_close;
}
*ttyreq = ttynum;
tty_info->pty_info[ttynum - 1].busy = fd;
return 0;
out_close:
/* the close fd and related cleanup will be done by caller */
return 1;
out_tty:
tty_info->pty_info[ttynum - 1].busy = sockfd;
masterfd = tty_info->pty_info[ttynum - 1].master;
out:
process_unlock();
return masterfd;
}
static int get_default_console(char **console)
/* lxc_console_free: mark the console or a tty as unallocated, free any
* resources allocated by lxc_console_allocate().
*
* @conf : the configuration of the container whose tty was closed
* @fd : the socket fd whose remote side was closed, which indicated
* the console or tty is no longer in use. this is used to match
* which console/tty is being freed.
*/
void lxc_console_free(struct lxc_conf *conf, int fd)
{
int fd;
int i;
struct lxc_tty_info *tty_info = &conf->tty_info;
struct lxc_console *console = &conf->console;
if (!access("/dev/tty", F_OK)) {
process_lock();
for (i = 0; i < tty_info->nbtty; i++) {
if (tty_info->pty_info[i].busy == fd)
tty_info->pty_info[i].busy = 0;
}
if (console->peerpty.busy == fd) {
lxc_mainloop_del_handler(console->descr, console->peerpty.slave);
lxc_console_peer_proxy_free(console);
}
process_unlock();
}
static void lxc_console_peer_default(struct lxc_console *console)
{
struct lxc_tty_state *ts;
const char *path = console->path;
/* if no console was given, try current controlling terminal, there
* won't be one if we were started as a daemon (-d)
*/
if (!path && !access("/dev/tty", F_OK)) {
int fd;
fd = open("/dev/tty", O_RDWR);
if (fd >= 0) {
close(fd);
*console = strdup("/dev/tty");
goto out;
path = "/dev/tty";
}
}
if (!access("/dev/null", F_OK)) {
*console = strdup("/dev/null");
if (!path)
goto out;
}
ERROR("No suitable default console");
out:
return *console ? 0 : -1;
}
DEBUG("opening %s for console peer", path);
console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT |
O_APPEND, 0600));
if (console->peer < 0)
goto out;
int lxc_create_console(struct lxc_conf *conf)
{
struct termios tios;
struct lxc_console *console = &conf->console;
int fd;
if (!conf->rootfs.path)
return 0;
if (!console->path && get_default_console(&console->path)) {
ERROR("failed to get default console");
return -1;
}
if (!strcmp(console->path, "none"))
return 0;
if (openpty(&console->master, &console->slave,
console->name, NULL, NULL)) {
SYSERROR("failed to allocate a pty");
return -1;
}
if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
SYSERROR("failed to set console master to close-on-exec");
goto err;
}
if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
SYSERROR("failed to set console slave to close-on-exec");
goto err;
}
if (console->log_path) {
fd = lxc_unpriv(open(console->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
if (fd < 0) {
SYSERROR("failed to open '%s'", console->log_path);
goto err;
}
DEBUG("using '%s' as console log", console->log_path);
console->log_fd = fd;
}
fd = lxc_unpriv(open(console->path, O_CLOEXEC | O_RDWR | O_CREAT |
O_APPEND, 0600));
if (fd < 0) {
SYSERROR("failed to open '%s'", console->path);
goto err_close_console_log;
}
DEBUG("using '%s' as console", console->path);
console->peer = fd;
DEBUG("using '%s' as console", path);
if (!isatty(console->peer))
return 0;
return;
console->tios = malloc(sizeof(tios));
ts = lxc_console_sigwinch_init(console->peer, console->master);
if (!ts)
WARN("Unable to install SIGWINCH");
console->tty_state = ts;
lxc_console_winsz(console->peer, console->master);
console->tios = malloc(sizeof(*console->tios));
if (!console->tios) {
SYSERROR("failed to allocate memory");
goto err_close_console;
goto err1;
}
/* Get termios */
if (tcgetattr(console->peer, console->tios)) {
SYSERROR("failed to get current terminal settings");
goto err_free;
}
if (setup_tios(console->peer, console->tios) < 0)
goto err2;
tios = *console->tios;
return;
/* Remove the echo characters and signal reception, the echo
* will be done below with master proxying */
tios.c_iflag &= ~IGNBRK;
tios.c_iflag &= BRKINT;
tios.c_lflag &= ~(ECHO|ICANON|ISIG);
tios.c_cc[VMIN] = 1;
tios.c_cc[VTIME] = 0;
/* Set new attributes */
if (tcsetattr(console->peer, TCSAFLUSH, &tios)) {
ERROR("failed to set new terminal settings");
goto err_free;
}
return 0;
err_free:
err2:
free(console->tios);
err_close_console:
console->tios = NULL;
err1:
close(console->peer);
console->peer = -1;
err_close_console_log:
if (console->log_fd >= 0) {
close(console->log_fd);
console->log_fd = -1;
}
err:
close(console->master);
console->master = -1;
close(console->slave);
console->slave = -1;
return -1;
out:
DEBUG("no console peer");
}
void lxc_delete_console(struct lxc_console *console)
void lxc_console_delete(struct lxc_console *console)
{
if (console->tios &&
if (console->tios && console->peer >= 0 &&
tcsetattr(console->peer, TCSAFLUSH, console->tios))
WARN("failed to set old terminal settings");
free(console->tios);
@ -300,73 +560,213 @@ void lxc_delete_console(struct lxc_console *console)
console->slave = -1;
}
static int console_handler(int fd, void *data, struct lxc_epoll_descr *descr)
int lxc_console_create(struct lxc_conf *conf)
{
struct lxc_console *console = (struct lxc_console *)data;
struct lxc_console *console = &conf->console;
if (conf->is_execute) {
INFO("no console for lxc-execute.");
return 0;
}
if (!conf->rootfs.path)
return 0;
if (console->path && !strcmp(console->path, "none"))
return 0;
if (openpty(&console->master, &console->slave,
console->name, NULL, NULL)) {
SYSERROR("failed to allocate a pty");
return -1;
}
if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
SYSERROR("failed to set console master to close-on-exec");
goto err;
}
if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
SYSERROR("failed to set console slave to close-on-exec");
goto err;
}
lxc_console_peer_default(console);
if (console->log_path) {
console->log_fd = lxc_unpriv(open(console->log_path,
O_CLOEXEC | O_RDWR |
O_CREAT | O_APPEND, 0600));
if (console->log_fd < 0) {
SYSERROR("failed to open '%s'", console->log_path);
goto err;
}
DEBUG("using '%s' as console log", console->log_path);
}
return 0;
err:
lxc_console_delete(console);
return -1;
}
static int lxc_console_cb_tty_stdin(int fd, void *cbdata,
struct lxc_epoll_descr *descr)
{
struct lxc_tty_state *ts = cbdata;
char c;
assert(fd == ts->stdinfd);
if (read(ts->stdinfd, &c, 1) < 0) {
SYSERROR("failed to read");
return 1;
}
/* we want to exit the console with Ctrl+a q */
if (c == ts->escape && !ts->saw_escape) {
ts->saw_escape = 1;
return 0;
}
if (c == 'q' && ts->saw_escape)
return 1;
ts->saw_escape = 0;
if (write(ts->masterfd, &c, 1) < 0) {
SYSERROR("failed to write");
return 1;
}
return 0;
}
static int lxc_console_cb_tty_master(int fd, void *cbdata,
struct lxc_epoll_descr *descr)
{
struct lxc_tty_state *ts = cbdata;
char buf[1024];
int r,w;
assert(fd == ts->masterfd);
r = read(fd, buf, sizeof(buf));
if (r < 0) {
SYSERROR("failed to read");
return 1;
}
if (!r) {
INFO("console client has exited");
lxc_mainloop_del_handler(descr, fd);
close(fd);
return 0;
w = write(ts->stdoutfd, buf, r);
if (w < 0 || w != r) {
SYSERROR("failed to write");
return 1;
}
/* no output for the console, do nothing */
if (console->peer == -1)
return 0;
if (console->peer == fd)
w = write(console->master, buf, r);
else {
w = write(console->peer, buf, r);
if (console->log_fd > 0)
w = write(console->log_fd, buf, r);
}
if (w != r)
WARN("console short write");
return 0;
}
int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
struct lxc_handler *handler)
int lxc_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
{
struct lxc_conf *conf = handler->conf;
struct lxc_console *console = &conf->console;
return lxc_cmd_console(c->name, ttynum, masterfd, c->config_path);
}
if (!conf->rootfs.path) {
INFO("no rootfs, no console.");
return 0;
}
int lxc_console(struct lxc_container *c, int ttynum,
int stdinfd, int stdoutfd, int stderrfd,
int escape)
{
int ret, ttyfd, masterfd;
struct lxc_epoll_descr descr;
struct termios oldtios;
struct lxc_tty_state *ts;
if (!console->path) {
INFO("no console specified");
return 0;
}
if (console->peer == -1) {
INFO("no console will be used");
return 0;
}
if (lxc_mainloop_add_handler(descr, console->master,
console_handler, console)) {
ERROR("failed to add to mainloop console handler for '%d'",
console->master);
if (!isatty(stdinfd)) {
ERROR("stdin is not a tty");
return -1;
}
if (console->peer != -1 &&
lxc_mainloop_add_handler(descr, console->peer,
console_handler, console))
WARN("console input disabled");
ret = setup_tios(stdinfd, &oldtios);
if (ret) {
ERROR("failed to setup tios");
return -1;
}
return 0;
process_lock();
ttyfd = lxc_cmd_console(c->name, &ttynum, &masterfd, c->config_path);
if (ttyfd < 0) {
ret = ttyfd;
goto err1;
}
fprintf(stderr, "\n"
"Connected to tty %1$d\n"
"Type <Ctrl+%2$c q> to exit the console, "
"<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n",
ttynum, 'a' + escape - 1);
ret = setsid();
if (ret)
INFO("already group leader");
ts = lxc_console_sigwinch_init(stdinfd, masterfd);
if (!ts) {
ret = -1;
goto err2;
}
ts->escape = escape;
ts->winch_proxy = c->name;
ts->winch_proxy_lxcpath = c->config_path;
lxc_console_winsz(stdinfd, masterfd);
lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
ret = lxc_mainloop_open(&descr);
if (ret) {
ERROR("failed to create mainloop");
goto err3;
}
ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
lxc_console_cb_sigwinch_fd, ts);
if (ret) {
ERROR("failed to add handler for SIGWINCH fd");
goto err4;
}
ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
lxc_console_cb_tty_stdin, ts);
if (ret) {
ERROR("failed to add handler for stdinfd");
goto err4;
}
ret = lxc_mainloop_add_handler(&descr, ts->masterfd,
lxc_console_cb_tty_master, ts);
if (ret) {
ERROR("failed to add handler for masterfd");
goto err4;
}
process_unlock();
ret = lxc_mainloop(&descr, -1);
process_lock();
if (ret) {
ERROR("mainloop returned an error");
goto err4;
}
ret = 0;
err4:
lxc_mainloop_close(&descr);
err3:
lxc_console_sigwinch_fini(ts);
err2:
close(masterfd);
close(ttyfd);
err1:
tcsetattr(stdinfd, TCSAFLUSH, &oldtios);
process_unlock();
return ret;
}

View File

@ -18,9 +18,21 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
extern int lxc_create_console(struct lxc_conf *);
extern void lxc_delete_console(struct lxc_console *);
extern int lxc_console_mainloop_add(struct lxc_epoll_descr *, struct lxc_handler *);
struct lxc_epoll_descr;
struct lxc_container;
extern int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttynum);
extern int lxc_console_create(struct lxc_conf *);
extern void lxc_console_delete(struct lxc_console *);
extern void lxc_console_free(struct lxc_conf *conf, int fd);
extern int lxc_console_mainloop_add(struct lxc_epoll_descr *, struct lxc_handler *);
extern void lxc_console_sigwinch(int sig);
extern int lxc_console(struct lxc_container *c, int ttynum,
int stdinfd, int stdoutfd, int stderrfd,
int escape);
extern int lxc_console_getfd(struct lxc_container *c, int *ttynum,
int *masterfd);

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __lxc_error_h
#define __lxc_error_h

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/types.h>
@ -27,6 +27,7 @@
#include <unistd.h>
#include <stdlib.h>
#include "conf.h"
#include "log.h"
#include "start.h"
@ -54,7 +55,7 @@ static char *choose_init(void)
ret = snprintf(retv, PATH_MAX, LXCINITDIR "/lxc/lxc-init");
if (ret < 0 || ret >= PATH_MAX) {
ERROR("pathname too long");
return NULL;
goto out1;
}
ret = stat(retv, &mystat);
@ -64,7 +65,7 @@ static char *choose_init(void)
ret = snprintf(retv, PATH_MAX, "/usr/lib/lxc/lxc-init");
if (ret < 0 || ret >= PATH_MAX) {
ERROR("pathname too long");
return NULL;
goto out1;
}
ret = stat(retv, &mystat);
if (ret == 0)
@ -72,11 +73,13 @@ static char *choose_init(void)
ret = snprintf(retv, PATH_MAX, "/sbin/lxc-init");
if (ret < 0 || ret >= PATH_MAX) {
ERROR("pathname too long");
return NULL;
goto out1;
}
ret = stat(retv, &mystat);
if (ret == 0)
return retv;
out1:
free(retv);
return NULL;
}
@ -85,23 +88,44 @@ static int execute_start(struct lxc_handler *handler, void* data)
int j, i = 0;
struct execute_args *my_args = data;
char **argv;
int argc = 0;
int argc = 0, argc_add;
char *initpath;
while (my_args->argv[argc++]);
argv = malloc((argc + my_args->quiet ? 5 : 4) * sizeof(*argv));
argc_add = 4;
if (my_args->quiet)
argc_add++;
if (!handler->conf->rootfs.path) {
argc_add += 4;
if (lxc_log_has_valid_level())
argc_add += 2;
}
argv = malloc((argc + argc_add) * sizeof(*argv));
if (!argv)
return 1;
goto out1;
initpath = choose_init();
if (!initpath) {
ERROR("Failed to find an lxc-init");
return 1;
goto out2;
}
argv[i++] = initpath;
if (my_args->quiet)
argv[i++] = "--quiet";
if (!handler->conf->rootfs.path) {
argv[i++] = "--name";
argv[i++] = (char *)handler->name;
argv[i++] = "--lxcpath";
argv[i++] = (char *)handler->lxcpath;
if (lxc_log_has_valid_level()) {
argv[i++] = "--logpriority";
argv[i++] = (char *)
lxc_log_priority_to_string(lxc_log_get_level());
}
}
argv[i++] = "--";
for (j = 0; j < argc; j++)
argv[i++] = my_args->argv[j];
@ -111,6 +135,10 @@ static int execute_start(struct lxc_handler *handler, void* data)
execvp(argv[0], argv);
SYSERROR("failed to exec %s", argv[0]);
free(initpath);
out2:
free(argv);
out1:
return 1;
}
@ -137,5 +165,6 @@ int lxc_execute(const char *name, char *const argv[], int quiet,
if (lxc_check_inherited(conf, -1))
return -1;
conf->is_execute = 1;
return __lxc_start(name, conf, &execute_start_ops, &args, lxcpath);
}

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _GNU_SOURCE
#include <stdio.h>
@ -120,14 +120,16 @@ out:
static int freeze_unfreeze(const char *name, int freeze, const char *lxcpath)
{
char *nsgroup;
char *cgabspath;
int ret;
ret = lxc_cgroup_path_get(&nsgroup, "freezer", name, lxcpath);
if (ret)
cgabspath = lxc_cgroup_path_get("freezer", name, lxcpath);
if (!cgabspath)
return -1;
return do_unfreeze(nsgroup, freeze, name, lxcpath);
ret = do_unfreeze(cgabspath, freeze, name, lxcpath);
free(cgabspath);
return ret;
}
int lxc_freeze(const char *name, const char *lxcpath)
@ -141,14 +143,19 @@ int lxc_unfreeze(const char *name, const char *lxcpath)
return freeze_unfreeze(name, 0, lxcpath);
}
int lxc_unfreeze_bypath(const char *cgpath)
int lxc_unfreeze_bypath(const char *cgrelpath)
{
char *nsgroup;
int ret;
ret = cgroup_path_get(&nsgroup, "freezer", cgpath);
if (ret)
return -1;
char cgabspath[MAXPATHLEN];
int len, ret;
return do_unfreeze(nsgroup, 0, NULL, NULL);
if (!get_subsys_mount(cgabspath, "freezer"))
return -1;
len = strlen(cgabspath);
ret = snprintf(cgabspath+len, MAXPATHLEN-len, "/%s", cgrelpath);
if (ret < 0 || ret >= MAXPATHLEN-len) {
ERROR("freezer path name too long");
return -1;
}
return do_unfreeze(cgabspath, 0, NULL, NULL);
}

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <stdio.h>
@ -60,45 +60,46 @@ static int genetlink_resolve_family(const char *family)
ret = netlink_open(&handler, NETLINK_GENERIC);
if (ret)
return ret;
goto out;
ret = nla_put_string((struct nlmsg *)&request->nlmsghdr,
CTRL_ATTR_FAMILY_NAME, family);
if (ret)
goto out;
goto out_close;
ret = netlink_transaction(&handler, (struct nlmsg *)&request->nlmsghdr,
(struct nlmsg *)&reply->nlmsghdr);
if (ret < 0)
goto out;
goto out_close;
genlmsghdr = NLMSG_DATA(&reply->nlmsghdr);
len = reply->nlmsghdr.nlmsg_len;
ret = -ENOMSG;
if (reply->nlmsghdr.nlmsg_type != GENL_ID_CTRL)
goto out;
goto out_close;
if (genlmsghdr->cmd != CTRL_CMD_NEWFAMILY)
goto out;
goto out_close;
ret = -EMSGSIZE;
len -= NLMSG_LENGTH(GENL_HDRLEN);
if (len < 0)
goto out;
goto out_close;
attr = (struct nlattr *)GENLMSG_DATA(reply);
attr = (struct nlattr *)((char *)attr + NLA_ALIGN(attr->nla_len));
ret = -ENOMSG;
if (attr->nla_type != CTRL_ATTR_FAMILY_ID)
goto out;
goto out_close;
ret = *(__u16 *) NLA_DATA(attr);
out_close:
netlink_close(&handler);
out:
genlmsg_free(request);
genlmsg_free(reply);
netlink_close(&handler);
return ret;
}

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __genl_h
#define __genl_h

View File

@ -15,7 +15,7 @@
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
. @DATADIR@/lxc/lxc.functions

View File

@ -18,6 +18,6 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <list.h>

View File

@ -1,3 +1,26 @@
/*
* lxc: linux Container library
*
* (C) Copyright IBM Corp. 2007, 2008
*
* Authors:
* Daniel Lezcano <daniel.lezcano at free.fr>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _list_h
#define _list_h

View File

@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <errno.h>
@ -35,15 +35,19 @@
#include "log.h"
#include "caps.h"
#include "utils.h"
#define LXC_LOG_PREFIX_SIZE 32
#define LXC_LOG_BUFFER_SIZE 512
int lxc_log_fd = -1;
static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
static char *log_fname = NULL;
/* command line values for logfile or logpriority should always override
* values from the configuration file or defaults
*/
static int lxc_logfile_specified = 0;
static int lxc_loglevel_specified = 0;
// if logfile was specifed on command line, it won't be overridden by lxc.logfile
static int lxc_log_specified = 0;
lxc_log_define(lxc_log, lxc);
@ -119,12 +123,6 @@ struct lxc_log_category lxc_log_category_lxc = {
};
/*---------------------------------------------------------------------------*/
extern void lxc_log_setprefix(const char *prefix)
{
strncpy(log_prefix, prefix, sizeof(log_prefix));
log_prefix[sizeof(log_prefix) - 1] = 0;
}
static int build_dir(const char *name)
{
char *n = strdup(name); // because we'll be modifying it
@ -180,29 +178,50 @@ static int log_open(const char *name)
return newfd;
}
static char *build_log_path(const char *name)
/*
* 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
*/
static char *build_log_path(const char *name, const char *lxcpath)
{
char *p;
int len, ret;
int len, ret, use_dir;
#if USE_CONFIGPATH_LOGS
use_dir = 1;
#else
use_dir = 0;
#endif
/*
* '$logpath' + '/' + '$name' + '.log' + '\0'
* or
* If USE_CONFIGPATH_LOGS is true or lxcpath is given, the resulting
* path will be:
* '$logpath' + '/' + '$name' + '/' + '$name' + '.log' + '\0'
* sizeof(LOGPATH) includes its \0
*
* If USE_CONFIGPATH_LOGS is false the resulting path will be:
* '$logpath' + '/' + '$name' + '.log' + '\0'
*/
len = sizeof(LOGPATH) + strlen(name) + 6;
#if USE_CONFIGPATH_LOGS
len += strlen(name) + 1; /* add "/$container_name/" */
#endif
len = strlen(name) + 6; /* 6 == '/' + '.log' + '\0' */
if (lxcpath)
use_dir = 1;
else
lxcpath = LOGPATH;
if (use_dir)
len += strlen(lxcpath) + 1 + strlen(name) + 1; /* add "/$container_name/" */
else
len += strlen(lxcpath) + 1;
p = malloc(len);
if (!p)
return p;
#if USE_CONFIGPATH_LOGS
ret = snprintf(p, len, "%s/%s/%s.log", LOGPATH, name, name);
#else
ret = snprintf(p, len, "%s/%s.log", LOGPATH, name);
#endif
if (use_dir)
ret = snprintf(p, len, "%s/%s/%s.log", lxcpath, name, name);
else
ret = snprintf(p, len, "%s/%s.log", lxcpath, name);
if (ret < 0 || ret >= len) {
free(p);
return NULL;
@ -210,19 +229,67 @@ static char *build_log_path(const char *name)
return p;
}
int do_lxc_log_set_file(const char *fname, int from_default);
/*
* This can be called:
* 1. when a program calls lxc_log_init with no logfile parameter (in which
* case the default is used). In this case lxc.logfile can override this.
* 2. when a program calls lxc_log_init with a logfile parameter. In this
* case we don't want lxc.logfile to override this.
* 3. When a lxc.logfile entry is found in config file.
*/
static int __lxc_log_set_file(const char *fname, int create_dirs)
{
if (lxc_log_fd != -1) {
// we are overriding the default.
close(lxc_log_fd);
free(log_fname);
}
#if USE_CONFIGPATH_LOGS
// we don't build_dir for the default if the default is
// i.e. /var/lib/lxc/$container/$container.log
if (create_dirs)
#endif
if (build_dir(fname)) {
ERROR("failed to create dir for log file \"%s\" : %s", fname,
strerror(errno));
return -1;
}
lxc_log_fd = log_open(fname);
if (lxc_log_fd == -1)
return -1;
log_fname = strdup(fname);
return 0;
}
static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_dirs)
{
char *logfile;
int ret;
logfile = build_log_path(name, lxcpath);
if (!logfile) {
ERROR("could not build log path");
return -1;
}
ret = __lxc_log_set_file(logfile, create_dirs);
free(logfile);
return ret;
}
/*---------------------------------------------------------------------------*/
extern int lxc_log_init(const char *name, const char *file,
const char *priority, const char *prefix, int quiet)
const char *priority, const char *prefix, int quiet,
const char *lxcpath)
{
int lxc_priority = LXC_LOG_PRIORITY_ERROR;
int ret;
char *tmpfile = NULL;
int want_lxc_log_specified = 0;
if (lxc_log_fd != -1)
if (lxc_log_fd != -1) {
WARN("lxc_log_init called with log already initialized");
return 0;
}
if (priority) {
lxc_loglevel_specified = 1;
@ -241,39 +308,41 @@ extern int lxc_log_init(const char *name, const char *file,
lxc_log_category_lxc.appender->next = &log_appender_stderr;
if (prefix)
lxc_log_setprefix(prefix);
lxc_log_set_prefix(prefix);
if (file && strcmp(file, "none") == 0) {
want_lxc_log_specified = 1;
return 0;
}
if (!file) {
tmpfile = build_log_path(name);
if (!tmpfile) {
ERROR("could not build log path");
return -1;
}
if (file) {
lxc_logfile_specified = 1;
if (strcmp(file, "none") == 0)
return 0;
ret = __lxc_log_set_file(file, 1);
} else {
want_lxc_log_specified = 1;
ret = -1;
if (!lxcpath)
lxcpath = LOGPATH;
/* try LOGPATH if lxcpath is the default */
if (strcmp(lxcpath, default_lxc_path()) == 0)
ret = _lxc_log_set_file(name, NULL, 0);
/* try in lxcpath */
if (ret < 0)
ret = _lxc_log_set_file(name, lxcpath, 1);
/* try LOGPATH in case its writable by the caller */
if (ret < 0)
ret = _lxc_log_set_file(name, NULL, 0);
}
ret = do_lxc_log_set_file(tmpfile ? tmpfile : file, !want_lxc_log_specified);
if (want_lxc_log_specified)
lxc_log_specified = 1;
/*
* If !want_lxc_log_specified, that is, if the user did not request
* this logpath, then ignore failures and continue logging to console
* If !file, that is, if the user did not request this logpath, then
* ignore failures and continue logging to console
*/
if (!want_lxc_log_specified && ret != 0) {
if (!file && ret != 0) {
INFO("Ignoring failure to open default logfile.");
ret = 0;
}
if (tmpfile)
free(tmpfile);
return ret;
}
@ -294,51 +363,6 @@ extern int lxc_log_set_level(int level)
return 0;
}
char *log_fname; // default to NULL, set in lxc_log_set_file.
/*
* This can be called:
* 1. when a program calls lxc_log_init with no logfile parameter (in which
* case the default is used). In this case lxc.logfile can override this.
* 2. when a program calls lxc_log_init with a logfile parameter. In this
* case we don't want lxc.logfile to override this.
* 3. When a lxc.logfile entry is found in config file.
*/
int do_lxc_log_set_file(const char *fname, int from_default)
{
if (lxc_log_specified) {
INFO("lxc.logfile overridden by command line");
return 0;
}
if (lxc_log_fd != -1) {
// we are overriding the default.
close(lxc_log_fd);
free(log_fname);
}
#if USE_CONFIGPATH_LOGS
// we don't build_dir for the default if the default is
// i.e. /var/lib/lxc/$container/$container.log
if (!from_default)
#endif
if (build_dir(fname)) {
ERROR("failed to create dir for log file \"%s\" : %s", fname,
strerror(errno));
return -1;
}
lxc_log_fd = log_open(fname);
if (lxc_log_fd == -1)
return -1;
log_fname = strdup(fname);
return 0;
}
extern int lxc_log_set_file(const char *fname)
{
return do_lxc_log_set_file(fname, 0);
}
extern int lxc_log_get_level(void)
{
if (!lxc_loglevel_specified)
@ -346,7 +370,38 @@ extern int lxc_log_get_level(void)
return lxc_log_category_lxc.priority;
}
extern bool lxc_log_has_valid_level(void)
{
int log_level = lxc_log_get_level();
if (log_level < 0 || log_level >= LXC_LOG_PRIORITY_NOTSET)
return false;
return true;
}
/*
* This is called when we read a lxc.logfile entry in a lxc.conf file. This
* happens after processing command line arguments, which override the .conf
* settings. So only set the file if previously unset.
*/
extern int lxc_log_set_file(const char *fname)
{
if (lxc_logfile_specified)
return 0;
return __lxc_log_set_file(fname, 0);
}
extern const char *lxc_log_get_file(void)
{
return log_fname;
}
extern void lxc_log_set_prefix(const char *prefix)
{
strncpy(log_prefix, prefix, sizeof(log_prefix));
log_prefix[sizeof(log_prefix) - 1] = 0;
}
extern const char *lxc_log_get_prefix(void)
{
return log_prefix;
}

View File

@ -19,7 +19,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _log_h
#define _log_h
@ -28,6 +28,7 @@
#include <stdio.h>
#include <sys/time.h>
#include <string.h>
#include <stdbool.h>
#ifndef O_CLOEXEC
#define O_CLOEXEC 02000000
@ -172,7 +173,7 @@ __lxc_log(const struct lxc_log_category* category,
}
/*
* Helper macro to define log fonctions.
* Helper macro to define log functions.
*/
#define lxc_log_priority_define(acategory, PRIORITY) \
\
@ -288,11 +289,14 @@ extern struct lxc_log_category lxc_log_category_lxc;
extern int lxc_log_fd;
extern int lxc_log_init(const char *name, const char *file,
const char *priority, const char *prefix, int quiet);
const char *priority, const char *prefix, int quiet,
const char *lxcpath);
extern void lxc_log_setprefix(const char *a_prefix);
extern int lxc_log_set_level(int level);
extern int lxc_log_set_file(const char *fname);
extern int lxc_log_get_level(void);
extern int lxc_log_set_level(int level);
extern void lxc_log_set_prefix(const char *prefix);
extern const char *lxc_log_get_file(void);
extern int lxc_log_get_level(void);
extern bool lxc_log_has_valid_level(void);
extern const char *lxc_log_get_prefix(void);
#endif

View File

@ -10,7 +10,7 @@ SETCOLOR_WARNING="printf \\033[1;33m"
SETCOLOR_NORMAL="printf \\033[0;39m"
is_set() {
$GREP -q "$1=[y|m]" $CONFIG
$GREP "$1=[y|m]" $CONFIG > /dev/null
return $?
}

View File

@ -1,324 +0,0 @@
#!/bin/sh
#
# lxc: linux Container library
# Authors:
# Serge Hallyn <serge.hallyn@ubuntu.com>
# Daniel Lezcano <daniel.lezcano@free.fr>
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
set -e
usage() {
echo "usage: $(basename $0) -o ORIG_NAME -n NEW_NAME [-s] [-h] [-L FS_SIZE]" >&2
echo " [-v VG_NAME] [-p LV_PREFIX] [-t FS_TYPE]" >&2
}
help() {
usage
echo >&2
echo "Clone an existing container on the system." >&2
echo >&2
echo "Options:" >&2
echo " -o ORIG_NAME specify the name of the original container" >&2
echo " -n NEW_NAME specify the name of the new container" >&2
echo " -s make the new rootfs a snapshot of the original" >&2
echo " -L FS_SIZE specify the new filesystem size (default: same as original)" >&2
echo " -v VG_NAME specify the new LVM volume group name (default: lxc)" >&2
echo " -p LV_PREFIX add a prefix to new LVM logical volume names" >&2
echo " -t FS_TYPE specify the new filesystem type (default: ext3;" >&2
echo " only works for non-snapshot LVM)" >&2
}
usage_err() {
[ -n "$1" ] && echo "$1" >&2
usage
exit 1
}
optarg_check() {
[ -n "$2" ] || usage_err "option $1 requires an argument"
}
. @DATADIR@/lxc/lxc.functions
snapshot=no
lxc_size=_unset
lxc_vg=lxc
lxc_lv_prefix=""
fstype=ext3
while [ $# -gt 0 ]; do
opt="$1"
shift
case "$opt" in
-h|--help)
help
exit 1
;;
-s|--snapshot)
snapshot=yes
snapshot_opt="-s"
;;
-o|--orig)
optarg_check $opt $1
lxc_orig=$1
shift
;;
-L|--fssize)
optarg_check $opt $1
lxc_size=$1
shift
;;
-t|--fstype)
optarg_check $opt $1
fstype=$1
shift
;;
-v|--vgname)
optarg_check $opt $1
lxc_vg=$1
shift
;;
-n|--name)
optarg_check $opt $1
lxc_new=$1
shift
;;
-p|--lvprefix)
optarg_check $opt $1
lxc_lv_prefix=$1
shift
;;
--)
break
;;
-?)
usage_err "Unknown option: '$opt'"
;;
-*)
# split opts -abc into -a -b -c
set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
;;
*)
usage_err
;;
esac
done
if [ -z "$lxc_path" ]; then
echo "$(basename $0): no configuration path defined" >&2
exit 1
fi
if [ ! -r $lxc_path ]; then
echo "$(basename $0): configuration path '$lxc_path' not found" >&2
exit 1
fi
if [ -z "$lxc_orig" ]; then
echo "$(basename $0): no original container name specified" >&2
usage
exit 1
fi
if [ -z "$lxc_new" ]; then
echo "$(basename $0): no new container name specified" >&2
usage
exit 1
fi
if [ "$(id -u)" != "0" ]; then
echo "$(basename $0): must be run as root" >&2
exit 1
fi
if [ ! -d "$lxc_path/$lxc_orig" ]; then
echo "$(basename $0): '$lxc_orig' does not exist" >&2
exit 1
fi
if [ -d "$lxc_path/$lxc_new" ]; then
echo "$(basename $0): '$lxc_new' already exists" >&2
exit 1
fi
mounted=0
frozen=0
oldroot=`grep lxc.rootfs $lxc_path/$lxc_orig/config | awk -F= '{ print $2 '}`
cleanup() {
if [ -b $oldroot ]; then
if [ $mounted -eq 1 ]; then
umount $rootfs || true
fi
lvremove -f $rootdev || true
fi
${bindir}/lxc-destroy -n $lxc_new || true
if [ $frozen -eq 1 ]; then
lxc-unfreeze -n $lxc_orig
fi
echo "$(basename $0): aborted" >&2
exit 1
}
trap cleanup HUP INT TERM
mkdir -p $lxc_path/$lxc_new
hostname=$lxc_new
echo "Tweaking configuration"
cp $lxc_path/$lxc_orig/config $lxc_path/$lxc_new/config
sed -i '/lxc.utsname/d' $lxc_path/$lxc_new/config
echo "lxc.utsname = $hostname" >> $lxc_path/$lxc_new/config
grep "lxc.mount[ \t]" $lxc_path/$lxc_new/config >/dev/null 2>&1 && { sed -i '/lxc.mount[ \t]/d' $lxc_path/$lxc_new/config; echo "lxc.mount = $lxc_path/$lxc_new/fstab" >> $lxc_path/$lxc_new/config; }
if [ -e $lxc_path/$lxc_orig/fstab ];then
cp $lxc_path/$lxc_orig/fstab $lxc_path/$lxc_new/fstab
sed -i "s@$lxc_path/$lxc_orig@$lxc_path/$lxc_new@" $lxc_path/$lxc_new/fstab
fi
echo "Copying rootfs..."
oldroot=`grep lxc.rootfs $lxc_path/$lxc_orig/config | awk -F'[= \t]+' '{ print $2 }'`
rootfs=`echo $oldroot |sed "s/$lxc_orig/$lxc_new/"`
container_running=True
lxc-info -n $lxc_orig --state-is RUNNING || container_running=False
sed -i '/lxc.rootfs/d' $lxc_path/$lxc_new/config
if [ -b $oldroot ]; then
which vgscan >/dev/null 2>&1 || { echo "$(basename $0): lvm is not installed" >&2; false; }
lvdisplay $oldroot > /dev/null 2>&1 || { echo "$(basename $0): non-lvm blockdev cloning is not supported" >&2; false; }
lvm=TRUE
# ok, create a snapshot of the lvm device
if [ $container_running = "True" ]; then
lxc-freeze -n $lxc_orig
frozen=1
fi
if [ $lxc_size = "_unset" ]; then
lxc_size=`lvdisplay $oldroot | grep Size | awk '{ print $3 $4 }'`
fi
newlv="${lxc_lv_prefix}${lxc_new}_snapshot"
lvcreate -s -L $lxc_size -n $newlv $oldroot
which xfs_admin > /dev/null 2>&1 && {
# change filesystem UUID if it is an xfs filesystem
xfs_admin -u /dev/$lxc_vg/$newlv && xfs_admin -U generate /dev/$lxc_vg/$newlv
}
if [ $container_running = "True" ]; then
lxc-unfreeze -n $lxc_orig
frozen=0
fi
if [ $snapshot = "no" ]; then
#mount snapshot
mkdir -p ${rootfs}_snapshot
mount /dev/$lxc_vg/${lxc_lv_prefix}${lxc_new}_snapshot ${rootfs}_snapshot || { echo "$(basename $0): failed to mount new rootfs_snapshot" >&2; false; }
#create a new lv
lvcreate -L $lxc_size $lxc_vg -n ${lxc_lv_prefix}$lxc_new
echo "lxc.rootfs = /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new" >> $lxc_path/$lxc_new/config
# and mount it so we can tweak it
mkdir -p $rootfs
mkfs -t $fstype /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new
mount /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new $rootfs || { echo "$(basename $0): failed to mount new rootfs" >&2; false; }
mounted=1
rsync -Hax ${rootfs}_snapshot/ ${rootfs}/ || { echo "$(basename $0): copying data to new lv failed" >&2; false; }
umount ${rootfs}_snapshot
rmdir ${rootfs}_snapshot
lvremove -f $lxc_vg/${lxc_lv_prefix}${lxc_new}_snapshot
else
lvrename $lxc_vg/${lxc_lv_prefix}${lxc_new}_snapshot $lxc_vg/${lxc_lv_prefix}$lxc_new
echo "lxc.rootfs = /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new" >> $lxc_path/$lxc_new/config
# and mount it so we can tweak it
mkdir -p $rootfs
mount /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new $rootfs || { echo "$(basename $0): failed to mount new rootfs" >&2; false; }
mounted=1
fi
elif which btrfs >/dev/null 2>&1 && btrfs subvolume list $oldroot >/dev/null 2>&1; then
# if oldroot is a btrfs subvolume, assume they want a snapshot
btrfs subvolume snapshot "$oldroot" "$rootfs" 2>&1 || { echo "$(basename $0): btrfs snapshot failed" >&2; false; }
echo "lxc.rootfs = $rootfs" >> "$lxc_path/$lxc_new/config"
elif [ -d $lxc_path/$lxc_orig/delta0 ]; then # this is a quasi-ephemeral container
if [ $container_running = "True" ]; then
echo "$(basename $0): container $lxc_orig is running." >&2
cleanup
fi
rsync -Hax $lxc_path/$lxc_orig/delta0 $lxc_path/$lxc_new/
touch $lxc_path/$lxc_new/configured
cp -f $lxc_path/$lxc_orig/pre-mount $lxc_path/$lxc_new/
sed -i "s@$lxc_path/$lxc_orig@$lxc_path/$lxc_new@g" $lxc_path/$lxc_new/config
sed -i "s@$lxc_path/$lxc_orig@$lxc_path/$lxc_new@g" $lxc_path/$lxc_new/pre-mount
sed -i "s@LXC_NAME=\"$lxc_orig@LXC_NAME=\"$lxc_new@" $lxc_path/$lxc_new/pre-mount
# lxc-start-ephemeral will have updated /etc/hostname and such under the
# delta0, so just mounting the delta should suffice.
mkdir -p $rootfs
mount --bind $lxc_path/$lxc_new/delta0 $rootfs
mounted=1
echo "lxc.rootfs = $rootfs" >> "$lxc_path/$lxc_new/config"
else
if [ $snapshot = "yes" ]; then
echo "$(basename $0): cannot snapshot a directory" >&2
cleanup
fi
if [ $container_running = "True" ]; then
lxc-freeze -n $lxc_orig
frozen=1
fi
mkdir -p $rootfs/
rsync -Hax $oldroot/ $rootfs/
echo "lxc.rootfs = $rootfs" >> $lxc_path/$lxc_new/config
if [ $container_running = "True" ]; then
lxc-unfreeze -n $lxc_orig
frozen=0
fi
fi
echo "Updating rootfs..."
# so you can 'ssh $hostname.' or 'ssh $hostname.local'
if [ -f $rootfs/etc/dhcp/dhclient.conf ] && ! grep -q "^send host-name.*hostname" $rootfs/etc/dhcp/dhclient.conf; then
sed -i "s/send host-name.*$/send host-name \"$hostname\";/" $rootfs/etc/dhcp/dhclient.conf
fi
c=$lxc_path/$lxc_new/config
# change hwaddrs
mv ${c} ${c}.old
(
while read line; do
if echo $line | grep -q -w '^lxc.network.hwaddr'; then
echo "lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')"
else
echo "$line"
fi
done
) < ${c}.old > ${c}
rm -f ${c}.old
# set the hostname
cat <<EOF > $rootfs/etc/hostname
$hostname
EOF
# set minimal hosts
cat <<EOF > $rootfs/etc/hosts
127.0.0.1 localhost $hostname
EOF
# if this was a block device, then umount it now
if [ $mounted -eq 1 ]; then
umount $rootfs
fi
echo "'$lxc_new' created"

View File

@ -1,357 +0,0 @@
#!/bin/sh
#
# lxc: linux Container library
# Authors:
# Daniel Lezcano <daniel.lezcano@free.fr>
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
. @DATADIR@/lxc/lxc.functions
usage() {
echo "usage: $(basename $0) -n NAME [-f CONFIG_FILE] [-t TEMPLATE] [FS_OPTIONS] --" >&2
echo " [-P lxcpath] [TEMPLATE_OPTIONS]" >&2
echo >&2
echo "where FS_OPTIONS is one of:" >&2
echo " -B none" >&2
echo " -B dir [--dir rootfs_dir]" >&2
echo " -B lvm [--lvname LV_NAME] [--vgname VG_NAME] [--fstype FS_TYPE]" >&2
echo " [--fssize FS_SIZE]" >&2
echo " -B btrfs" >&2
}
help() {
usage
echo >&2
echo "Create a new container on the system." >&2
echo >&2
echo "Options:" >&2
echo " -n NAME specify the name of the container" >&2
echo " -f CONFIG_FILE use an existing configuration file" >&2
echo " -t TEMPLATE use an accessible template script" >&2
echo " -B BACKING_STORE alter the container backing store (default: none)" >&2
echo " --lxcpath path specify an alternate container patch (default: $lxc_path)" >&2
echo " --lvname LV_NAME specify the LVM logical volume name" >&2
echo " (default: container name)" >&2
echo " --dir ROOTFS_DIR specify path for custom rootfs directory location" >&2
echo " --vgname VG_NAME specify the LVM volume group name (default: lxc)" >&2
echo " --fstype FS_TYPE specify the filesystem type (default: ext4)" >&2
echo " --fssize FS_SIZE specify the filesystem size (default: 500M)" >&2
echo >&2
if [ -z "$lxc_template" ]; then
echo "To see template-specific options, specify a template. For example:" >&2
echo " $(basename $0) -t ubuntu -h" >&2
exit 0
fi
if [ -x ${templatedir}/lxc-$lxc_template ]; then
echo >&2
echo "Template-specific options (TEMPLATE_OPTIONS):" >&2
${templatedir}/lxc-$lxc_template -h
fi
}
usage_err() {
[ -n "$1" ] && echo "$1" >&2
usage
exit 1
}
optarg_check() {
if [ -z "$2" ]; then
usage_err "option '$1' requires an argument"
fi
}
backingstore=_unset
fstype=ext4
fssize=500M
vgname=lxc
custom_rootfs=""
while [ $# -gt 0 ]; do
opt="$1"
shift
case "$opt" in
-h|--help)
help
exit 1
;;
-n|--name)
optarg_check $opt "$1"
lxc_name=$1
shift
;;
-f|--config)
optarg_check $opt "$1"
lxc_config=$1
shift
;;
-P|--lxcpath)
optarg_check $opt "$1"
lxc_path=$1
shift
;;
-t|--template)
optarg_check $opt "$1"
lxc_template=$1
shift
;;
-B|--backingstore)
optarg_check $opt "$1"
backingstore=$1
shift
;;
--dir)
optarg_check $opt "$1"
custom_rootfs=$1
shift
;;
--lvname)
optarg_check $opt "$1"
lvname=$1
shift
;;
--vgname)
optarg_check $opt "$1"
vgname=$1
shift
;;
--fstype)
optarg_check $opt "$1"
fstype=$1
shift
;;
--fssize)
optarg_check $opt "$1"
fssize=$1
shift
;;
--)
break;;
-?)
usage_err "unknown option '$opt'"
;;
-*)
# split opts -abc into -a -b -c
set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
;;
*)
usage
exit 1
;;
esac
done
# If -h or --help was passed into the container, we'll want to cleanup
# afterward
wantedhelp=0
for var in "$@"; do
if [ "$var" = "-h" ] || [ "$var" = "--help" ]; then
help
exit 1
fi
done
if [ -z "$lxc_path" ]; then
echo "$(basename $0): no configuration path defined" >&2
exit 1
fi
if [ ! -r $lxc_path ]; then
echo "$(basename $0): configuration path '$lxc_path' not found" >&2
exit 1
fi
if [ -z "$lxc_name" ]; then
echo "$(basename $0): no container name specified" >&2
usage
exit 1
fi
if [ -z "$lvname" ]; then
lvname="$lxc_name"
fi
if [ "$(id -u)" != "0" ]; then
echo "$(basename $0): must be run as root" >&2
exit 1
fi
if [ -n "$custom_rootfs" ] && [ "$backingstore" != "dir" ]; then
echo "--dir is only valid with -B dir"
fi
case "$backingstore" in
dir|lvm|none|btrfs|_unset) :;;
*)
echo "$(basename $0): '$backingstore' is not known (try 'none', 'dir', 'lvm', 'btrfs')" >&2
usage
exit 1
;;
esac
if [ -d "$lxc_path/$lxc_name" ]; then
echo "$(basename $0): '$lxc_name' already exists" >&2
exit 1
fi
rootfs="$lxc_path/$lxc_name/rootfs"
if [ "$backingstore" = "_unset" ] || [ "$backingstore" = "btrfs" ]; then
# if no backing store was given, then see if btrfs would work
if which btrfs >/dev/null 2>&1 && \
btrfs filesystem df "$lxc_path/" >/dev/null 2>&1; then
backingstore="btrfs"
else
if [ "$backingstore" = "btrfs" ]; then
echo "$(basename $0): missing 'btrfs' command or $lxc_path is not btrfs" >&2
exit 1;
fi
backingstore="none"
fi
fi
if [ "$backingstore" = "lvm" ]; then
which vgscan > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "$(basename $0): vgscan not found (is lvm2 installed?)" >&2
exit 1
fi
grep -q "\<$fstype\>" /proc/filesystems
if [ $? -ne 0 ]; then
echo "$(basename $0): $fstype is not listed in /proc/filesystems" >&2
exit 1
fi
vgscan | grep -q "Found volume group \"$vgname\""
if [ $? -ne 0 ]; then
echo "$(basename $0): could not find volume group \"$vgname\"" >&2
exit 1
fi
rootdev=/dev/$vgname/$lvname
lvdisplay $rootdev > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "$(basename $0): backing store already exists: $rootdev" >&2
echo "please delete it (using \"lvremove $rootdev\") and try again" >&2
exit 1
fi
elif [ "$backingstore" = "btrfs" ]; then
mkdir "$lxc_path/$lxc_name"
if ! out=$(btrfs subvolume create "$rootfs" 2>&1); then
echo "$(basename $0): failed to create subvolume in $rootfs: $out" >&2
exit 1;
fi
fi
cleanup() {
if [ "$backingstore" = "lvm" ]; then
umount $rootfs
lvremove -f $rootdev
elif [ "$backingstore" = "btrfs" ]; then
btrfs subvolume delete "$rootfs"
fi
${bindir}/lxc-destroy -n $lxc_name
echo "$(basename $0): aborted" >&2
exit 1
}
trap cleanup HUP INT TERM
mkdir -p $lxc_path/$lxc_name
if [ -z "$lxc_config" ]; then
lxc_config="@SYSCONFDIR@/lxc/default.conf"
echo
echo "$(basename $0): No config file specified, using the default config $lxc_config"
fi
if [ ! -r "$lxc_config" ]; then
echo "$(basename $0): '$lxc_config' configuration file not found" >&2
exit 1
fi
if [ ! -z "$lxc_template" ]; then
# Allow for a path to be provided as the template name
if [ -x "$lxc_template" -a $(echo "$lxc_template" | cut -c 1) = '/' ]; then
template_path=$lxc_template
else
template_path=${templatedir}/lxc-$lxc_template
fi
if ! [ -x "$template_path" ]; then
echo "$(basename $0): unknown template '$lxc_template'" >&2
cleanup
fi
sum=$(sha1sum $template_path | cut -d ' ' -f1)
echo "# Template used to create this container: $lxc_template" >> $lxc_path/$lxc_name/config
if [ -n "$*" ]; then
echo "# Parameters passed to the template: $*" >> $lxc_path/$lxc_name/config
fi
echo "# Template script checksum (SHA-1): $sum" >> $lxc_path/$lxc_name/config
echo "" >> $lxc_path/$lxc_name/config
fi
cat $lxc_config >> $lxc_path/$lxc_name/config
echo "" >> $lxc_path/$lxc_name/config
if [ -n "$custom_rootfs" ]; then
if grep -q "lxc.rootfs" $lxc_path/$lxc_name/config ; then
echo "configuration file already specifies a lxc.rootfs"
exit 1
fi
if [ -d "$custom_rootfs" ]; then
echo "specified rootfs ($custom_rootfs) already exists. Bailing."
exit 1
fi
echo "lxc.rootfs = $custom_rootfs" >> $lxc_path/$lxc_name/config
fi
# Create the fs as needed
if [ "$backingstore" = "lvm" ]; then
[ -d "$rootfs" ] || mkdir $rootfs
lvcreate -L $fssize -n $lvname $vgname || exit 1
udevadm settle
mkfs -t $fstype $rootdev || exit 1
mount -t $fstype $rootdev $rootfs
fi
if [ ! -z "$lxc_template" ]; then
$template_path --path=$lxc_path/$lxc_name --name=$lxc_name $*
if [ $? -ne 0 ]; then
echo "$(basename $0): failed to execute template '$lxc_template'" >&2
cleanup
fi
echo "'$lxc_template' template installed"
fi
if [ "$backingstore" = "lvm" ]; then
echo "Unmounting LVM"
umount $rootfs
# TODO: make the templates set this right from the start?
sed -i '/lxc.rootfs/d' $lxc_path/$lxc_name/config
echo "lxc.rootfs = $rootdev" >> $lxc_path/$lxc_name/config
fi
echo "'$lxc_name' created"

View File

@ -18,7 +18,7 @@
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# This script allows to set or remove the capabilities on the lxc tools.
@ -40,19 +40,55 @@ help() {
echo " -P lxcpath container is in specified lxcpath" >&2
}
. @DATADIR@/lxc/lxc.functions
usage_err() {
[ -n "$1" ] && echo "$1" >&2
usage
exit 1
}
verify_zfs() {
local path=$1
which zfs > /dev/null 2>&1 || { echo no; return; }
if zfs list -H $path >/dev/null 2>&1; then
echo zfs
else
echo no
fi
}
busy_zfs() {
local path=$1
local dev
dev=`zfs list -H $path 2>/dev/null | awk '{ print $1 }'`
if zfs list -t snapshot | grep -q "$dev"; then
echo busy
else
echo zfs
fi
}
verify_lvm() {
local path=$1
if [ -b $path -o -h $path ]; then
lvdisplay $path > /dev/null 2>&1 && { echo lvm; return; }
fi
echo no
}
busy_lvm() {
local path=$1
lvdisplay $path | grep -q "LV snapshot status.*source of" && { echo busy; return; }
echo lvm
}
optarg_check() {
if [ -z "$2" ]; then
usage_err "option '$1' requires an argument"
fi
}
. @DATADIR@/lxc/lxc.functions
force=0
while [ $# -gt 0 ]; do
@ -121,16 +157,29 @@ if ! lxc-info -n $lxc_name -P $lxc_path --state-is "STOPPED"; then
fi
# Deduce the type of rootfs
# If LVM partition, destroy it. For btrfs, we delete the subvolue. If anything
# If LVM partition, destroy it. For btrfs, we delete the subvolume. If anything
# else, ignore it. We'll support deletion of others later.
rootdev=`grep lxc.rootfs $lxc_path/$lxc_name/config 2>/dev/null | sed -e 's/^[^/]*/\//'`
rootdev=`grep '^\s*lxc\.rootfs' $lxc_path/$lxc_name/config 2>/dev/null | sed -e 's/^[^/]*//'`
if [ -n "$rootdev" ]; then
if [ -b "$rootdev" -o -h "$rootdev" ]; then
lvdisplay $rootdev > /dev/null 2>&1
if [ $? -eq 0 ]; then
if [ `verify_lvm $rootdev` = "lvm" ]; then
if [ `busy_lvm $rootdev` = "busy" ]; then
echo "$rootdev has lvm snapshots - not deleting"
exit 1
else
echo "removing backing store: $rootdev"
lvremove -f $rootdev
fi
elif [ `verify_zfs $rootdev` = "zfs" ]; then
if [ `busy_zfs $rootdev` = "busy" ]; then
echo "$rootdev has zfs snapshots - not deleting"
exit 1
else
zfs destroy $(zfs list | grep $rootdev | awk '{ print $1 }')
if [ $? -ne 0 ]; then
echo "zfs destroy failed - please wait a bit and try again"
exit 1
fi
fi
elif [ -h "$rootdev" -o -d "$rootdev" ]; then
if which btrfs >/dev/null 2>&1 &&
btrfs subvolume list "$rootdev" >/dev/null 2>&1; then

View File

@ -22,7 +22,7 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# NOTE: To remove once the API is stabilized

View File

@ -22,7 +22,7 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# NOTE: To remove once the API is stabilized
@ -89,12 +89,13 @@ def getTerminalSize():
def getSubContainers(container, lxcpath):
attach = ['lxc-attach', '-R', '-s', 'NETWORK|PID', '-n', container,
attach = ['lxc-attach', '-P', lxcpath, '-R', '-s', 'NETWORK|PID',
'-n', container,
'--', sys.argv[0], "--nesting"]
with open(os.devnull, "w") as fd:
newenv = dict(os.environ)
newenv['NESTED'] = "/proc/1/root/%s" % lxcpath
newenv['NESTED'] = "/proc/1/root/%s" % lxc.default_config_path
sp = subprocess.Popen(attach, stderr=fd, stdout=subprocess.PIPE,
env=newenv, universal_newlines=True)
sp.wait()
@ -201,10 +202,10 @@ for container_name in lxc.list_containers(config_path=lxcpath):
entry['pid'] = str(container.init_pid)
# Get the IPs
for protocol in ('ipv4', 'ipv6'):
for family, protocol in {'inet': 'ipv4', 'inet6': 'ipv6'}.items():
if protocol in args.fancy_format or args.nesting:
entry[protocol] = "-"
ips = container.get_ips(protocol=protocol, timeout=1)
ips = container.get_ips(family=family)
if ips:
entry[protocol] = ", ".join(ips)

View File

@ -15,10 +15,12 @@
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
. @DATADIR@/lxc/lxc.functions
usage() {
echo "usage: $(basename $0) -n|--name <name> -- [netstat_options]" >&2
echo "usage: $(basename $0) -n|--name <name> [-P|--lxcpath <lxc_path>] -- [netstat_options]" >&2
}
help() {
@ -26,8 +28,9 @@ help() {
echo >&2
echo "Execute 'netstat' for the specified container." >&2
echo >&2
echo " --name NAME specify the container name" >&2
echo " NETSTAT_OPTIONS netstat command options (see \`netstat --help')" >&2
echo " --name NAME specify the container name" >&2
echo " --lxcpath LXC_PATH use an alternate container path" >&2
echo " NETSTAT_OPTIONS netstat command options (see \`netstat --help')" >&2
}
get_parent_cgroup()
@ -71,8 +74,20 @@ while true; do
case $1 in
-h|--help)
help; exit 1;;
-n|--name)
-n)
# If we already have a value for $name, treat -n as being an
# argument for netstat
if [ -n "$name" ]
then
break
else
name="$2"; shift 2;
fi
;;
--name)
name=$2; shift 2;;
-P|--lxcpath)
lxc_path="$2"; shift 2;;
--exec)
exec="exec"; shift;;
--)
@ -92,11 +107,17 @@ if [ -z "$name" ]; then
exit 1
fi
if [ -z "$exec" ]; then
exec @BINDIR@/lxc-unshare -s MOUNT -- $0 -n $name --exec "$@"
if [ -z "$lxc_path" ]; then
echo "$(basename $0): no configuration path defined" >&2
usage
exit 1
fi
if lxc-info -n $name --state-is 'STOPPED'; then
if [ -z "$exec" ]; then
exec @BINDIR@/lxc-unshare -s MOUNT -- $0 -n $name -P "$lxc_path" --exec -- "$@"
fi
if lxc-info -n $name -P "$lxc_path" --state-is 'STOPPED'; then
echo "$(basename $0): container '$name' is not running" >&2
exit 1
fi

View File

@ -15,11 +15,13 @@
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
. @DATADIR@/lxc/lxc.functions
usage()
{
echo "usage: $(basename $0) [--lxc | --host | --name NAME] [--] [PS_OPTIONS...]" >&2
echo "usage: $(basename $0) [-P PATH] [--lxc | --host | --name NAME] [[--] [PS_OPTIONS...]" >&2
}
help() {
@ -31,14 +33,16 @@ help() {
echo " --host show processes not related to any container, i.e. to the host" >&2
echo " --name NAME show processes in the specified container" >&2
echo " (multiple containers can be separated by commas)" >&2
echo " -P PATH show container in lxcpath PATH" >&2
echo " PS_OPTIONS ps command options (see \`ps --help')" >&2
}
get_parent_cgroup()
{
local hierarchies hierarchy fields subsystems init_cgroup mountpoint
local hierarchies hierarchy fields init_cgroup mountpoint
parent_cgroup=""
subsystems=""
# Obtain a list of hierarchies that contain one or more subsystems
hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
@ -62,11 +66,7 @@ get_parent_cgroup()
if [ -z "$mountpoint" ]; then continue; fi
# Return the absolute path to the containers' parent cgroup
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
case ",$subsystems," in
*,ns,*) parent_cgroup="${mountpoint}${init_cgroup%/}";;
*) parent_cgroup="${mountpoint}${init_cgroup%/}/lxc";;
esac
parent_cgroup="${mountpoint}${init_cgroup%/}";
break
done
}
@ -83,6 +83,8 @@ while true; do
list_container_processes=1; shift;;
--host)
list_container_processes=-1; shift;;
-P|--lxcpath)
lxc_path=$2; shift 2;;
--)
shift; break;;
*)
@ -101,7 +103,10 @@ if [ ! -d "$parent_cgroup" ]; then
fi
if [ -z "$containers" ]; then
containers="$(find $parent_cgroup -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed 's:.*/::')"
case ",$subsystems," in
*,ns,*) containers="$(find $parent_cgroup -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed 's:.*/::')";;
*) containers="$(find $parent_cgroup/lxc -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed 's:.*/::')";;
esac
fi
container_field_width=9
@ -111,8 +116,12 @@ for container in ${containers}; do
container_field_width=${#container}
fi
if [ -f "$parent_cgroup/$container/tasks" ]; then
tasks_files="$tasks_files $parent_cgroup/$container/tasks"
if ! lxc-info -P $lxc_path -t STOPPED -n $container; then
initpid=`lxc-info -P $lxc_path -p -n $container | awk -F: '{ print $2 }' | awk '{ print $1 }'`
cgroup=`head -n 1 /proc/$initpid/cgroup | awk -F: '{ print $3}'`
if [ -f "$parent_cgroup/$cgroup/tasks" ]; then
tasks_files="$tasks_files $parent_cgroup$cgroup/tasks"
fi
fi
done

Some files were not shown because too many files have changed in this diff Show More