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

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
This commit is contained in:
Daniel Lezcano 2012-12-13 21:47:55 +01:00
commit 2e3ae157d5
128 changed files with 9532 additions and 1382 deletions

46
.gitignore vendored
View File

@ -24,45 +24,63 @@ libtool
lxc.spec lxc.spec
lxc.pc lxc.pc
templates/lxc-debian
templates/lxc-lucid
templates/lxc-maverick
templates/lxc-natty
templates/lxc-oneiric
templates/lxc-fedora
templates/lxc-altlinux templates/lxc-altlinux
templates/lxc-sshd
templates/lxc-busybox
templates/lxc-archlinux templates/lxc-archlinux
templates/lxc-busybox
templates/lxc-debian
templates/lxc-fedora
templates/lxc-lenny
templates/lxc-opensuse
templates/lxc-oracle
templates/lxc-sshd
templates/lxc-ubuntu
templates/lxc-ubuntu-cloud
src/lxc/lxc-attach src/lxc/lxc-attach
src/lxc/lxc-cgroup src/lxc/lxc-cgroup
src/lxc/lxc-checkconfig src/lxc/lxc-checkconfig
src/lxc/lxc-checkpoint src/lxc/lxc-checkpoint
src/lxc/lxc-cinit src/lxc/lxc-clone
src/lxc/lxc-cmd
src/lxc/lxc-console src/lxc/lxc-console
src/lxc/lxc-create src/lxc/lxc-create
src/lxc/lxc-destroy src/lxc/lxc-destroy
src/lxc/lxc-enter
src/lxc/lxc-exec
src/lxc/lxc-execute src/lxc/lxc-execute
src/lxc/lxc-freeze src/lxc/lxc-freeze
src/lxc/lxc-info src/lxc/lxc-info
src/lxc/lxc-init src/lxc/lxc-init
src/lxc/lxc-kill src/lxc/lxc-kill
src/lxc/lxc-ls
src/lxc/lxc-monitor src/lxc/lxc-monitor
src/lxc/lxc-netstat src/lxc/lxc-netstat
src/lxc/lxc-setcap
src/lxc/lxc-ps src/lxc/lxc-ps
src/lxc/lxc-restart src/lxc/lxc-restart
src/lxc/lxc-setcap
src/lxc/lxc-setuid
src/lxc/lxc-shutdown
src/lxc/lxc-start src/lxc/lxc-start
src/lxc/lxc-start-ephemeral
src/lxc/lxc-stop src/lxc/lxc-stop
src/lxc/lxc-unfreeze src/lxc/lxc-unfreeze
src/lxc/lxc-unshare src/lxc/lxc-unshare
src/lxc/lxc-version src/lxc/lxc-version
src/lxc/lxc-wait src/lxc/lxc-wait
src/lxc/legacy/lxc-ls
src/python-lxc/build/
src/python-lxc/examples/api_test.py
src/python-lxc/lxc/__init__.py
src/python-lxc/lxc/__pycache__/
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-saveconfig
src/tests/lxc-test-shutdowntest
src/tests/lxc-test-startone
config/compile config/compile
config/config.guess config/config.guess

View File

@ -1,5 +1,5 @@
Contributing to this project Contributing to this project
---------------------------- ----------------------------
@ -81,7 +81,6 @@ By making a contribution to this project, I certify that:
then you just add a line saying then you just add a line saying
Signed-off-by: Random J Developer <random@developer.org> Signed-off-by: Random J Developer <random@developer.org>
using your real name (sorry, no pseudonyms or anonymous using your real name (sorry, no pseudonyms or anonymous contributions.)
contributions.)

16
COPYING
View File

@ -1,5 +1,5 @@
GNU LESSER GENERAL PUBLIC LICENSE GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999 Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc. Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
@ -10,7 +10,7 @@
as the successor of the GNU Library Public License, version 2, hence as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.] the version number 2.1.]
Preamble Preamble
The licenses for most software are designed to take away your The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public freedom to share and change it. By contrast, the GNU General Public
@ -112,7 +112,7 @@ modification follow. Pay close attention to the difference between a
former contains code derived from the library, whereas the latter must former contains code derived from the library, whereas the latter must
be combined with the library in order to run. be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other 0. This License Agreement applies to any software library or other
@ -146,7 +146,7 @@ such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does. and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's 1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an you conspicuously and appropriately publish on each copy an
@ -432,7 +432,7 @@ decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing of all derivatives of our free software and of promoting the sharing
and reuse of software generally. and reuse of software generally.
NO WARRANTY NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
@ -455,7 +455,7 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES. DAMAGES.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries How to Apply These Terms to Your New Libraries
@ -500,5 +500,3 @@ necessary. Here is a sample; alter the names:
Ty Coon, President of Vice Ty Coon, President of Vice
That's all there is to it! That's all there is to it!

View File

@ -10,8 +10,8 @@ unlimited permission to copy, distribute and modify it.
Basic Installation Basic Installation
================== ==================
Briefly, the shell commands `./configure; make; make install' should Briefly, the shell commands `./autogen.sh; ./configure; make; make install'
configure, build, and install this package. The following should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for more-detailed instructions are generic; see the `README' file for
instructions specific to this package. instructions specific to this package.

View File

@ -2,13 +2,17 @@
ACLOCAL_AMFLAGS = -I config ACLOCAL_AMFLAGS = -I config
SUBDIRS = src templates doc SUBDIRS = config src templates doc
DIST_SUBDIRS = config src templates doc DIST_SUBDIRS = config src templates doc
EXTRA_DIST = autogen.sh lxc.spec CONTRIBUTING MAINTAINERS ChangeLog EXTRA_DIST = autogen.sh lxc.spec CONTRIBUTING MAINTAINERS ChangeLog
pcdatadir = $(libdir)/pkgconfig pcdatadir = $(libdir)/pkgconfig
pcdata_DATA = lxc.pc pcdata_DATA = lxc.pc
install-data-local:
$(MKDIR_P) $(DESTDIR)$(LXCPATH)
$(MKDIR_P) $(DESTDIR)$(localstatedir)/cache/lxc
ChangeLog:: ChangeLog::
@touch ChangeLog @touch ChangeLog

37
README
View File

@ -7,7 +7,7 @@ What is lxc:
kernel. It provides the resource management through the control groups aka kernel. It provides the resource management through the control groups aka
process containers and resource isolation through the namespaces. process containers and resource isolation through the namespaces.
The linux containers, lxc, aims to use these new functionnalities to pro- The linux containers, lxc, aims to use these new functionalities to pro-
vide an userspace container object which provides full resource isolation vide an userspace container object which provides full resource isolation
and resource control for an applications or a system. and resource control for an applications or a system.
@ -29,9 +29,14 @@ Downloading the current source code:
You can browse the up to the minute source code and change history online. You can browse the up to the minute source code and change history online.
http://lxc.git.sourceforge.net http://lxc.git.sourceforge.net
For an even more bleeding edge experience, you may want to look at the
staging branch where all changes aimed at the next release land before
getting pulled into the master branch.
http://github.com/lxc/lxc
For detailed build instruction refer to INSTALL and man lxc man page For detailed build instruction refer to INSTALL and man lxc man page
but a short command line should work: but a short command line should work:
./configure && make && sudo make install && sudo lxc-setcap ./autogen.sh && ./configure && make && sudo make install && sudo lxc-setcap
preceded by ./autogen.sh if configure do not exist yet. preceded by ./autogen.sh if configure do not exist yet.
Getting help: Getting help:
@ -48,7 +53,33 @@ Portability:
lxc is developed and tested on Linux since kernel mainline version 2.6.27 lxc is developed and tested on Linux since kernel mainline version 2.6.27
(without network) and 2.6.29 with network isolation. (without network) and 2.6.29 with network isolation.
is compiled with gcc, and supports i686, x86_64, ppc, ppc64, S390 archi. It's compiled with gcc, and should work on most architectures as long as the
required kernel features are available. This includes (but isn't limited to):
i686, x86_64, ppc, ppc64, S390, armel and armhf.
AUTHOR AUTHOR
Daniel Lezcano <daniel.lezcano@free.fr> Daniel Lezcano <daniel.lezcano@free.fr>
Seccomp with LXC
----------------
To restrict a container with seccomp, you must specify a profile which is
basically a whitelist of system calls it may execute. In the container
config file, add a line like
lxc.seccomp = /var/lib/lxc/q1/seccomp.full
I created a usable (but basically worthless) seccomp.full file using
cat > seccomp.full << EOF
1
whitelist
EOF
for i in `seq 0 300`; do
echo $i >> seccomp.full
done
for i in `seq 1024 1079`; do
echo $i >> seccomp.full
done
-- Serge Hallyn <serge.hallyn@ubuntu.com> Fri, 27 Jul 2012 15:47:02 +0600

2
TODO
View File

@ -1,6 +1,6 @@
* create an interactive configuration with the lxc-create command * create an interactive configuration with the lxc-create command
line, like the 'make menuconfig' of the kernel. line, like the 'make menuconfig' of the kernel.
= lxc-create [-n foo] -m|--menuconfig = lxc-create [-n foo] -m|--menuconfig

View File

@ -1,2 +1,15 @@
distclean: configdir = $(sysconfdir)/lxc
config_DATA = lxc.conf
conffile = @LXC_CONFFILE@
EXTRA_DIST = lxc.conf.ubuntu lxc.conf.libvirt lxc.conf.unknown
lxc.conf:
cp $(conffile) $@
clean-local:
@$(RM) -f lxc.conf
distclean-local:
@$(RM) -f lxc.conf
@$(RM) -f compile config.guess config.sub depcomp install-sh ltmain.sh missing Makefile.in Makefile @$(RM) -f compile config.guess config.sub depcomp install-sh ltmain.sh missing Makefile.in Makefile

View File

@ -2,21 +2,21 @@ dnl as-ac-expand.m4 0.2.0
dnl autostars m4 macro for expanding directories using configure's prefix dnl autostars m4 macro for expanding directories using configure's prefix
dnl thomas@apestaart.org dnl thomas@apestaart.org
dnl dnl
dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR) dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
dnl example dnl example
dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local
AC_DEFUN([AS_AC_EXPAND], AC_DEFUN([AS_AC_EXPAND],
[ [
EXP_VAR=[$1] EXP_VAR=[$1]
FROM_VAR=[$2] FROM_VAR=[$2]
dnl first expand prefix and exec_prefix if necessary dnl first expand prefix and exec_prefix if necessary
prefix_save=$prefix prefix_save=$prefix
exec_prefix_save=$exec_prefix exec_prefix_save=$exec_prefix
dnl if no prefix given, then use /usr/local, the default prefix dnl if no prefix given, then use /usr/local, the default prefix
if test "x$prefix" = "xNONE"; then if test "x$prefix" = "xNONE"; then
prefix="$ac_default_prefix" prefix="$ac_default_prefix"
@ -25,7 +25,7 @@ AC_DEFUN([AS_AC_EXPAND],
if test "x$exec_prefix" = "xNONE"; then if test "x$exec_prefix" = "xNONE"; then
exec_prefix=$prefix exec_prefix=$prefix
fi fi
full_var="$FROM_VAR" full_var="$FROM_VAR"
dnl loop until it doesn't change anymore dnl loop until it doesn't change anymore
while true; do while true; do
@ -33,11 +33,11 @@ AC_DEFUN([AS_AC_EXPAND],
if test "x$new_full_var" = "x$full_var"; then break; fi if test "x$new_full_var" = "x$full_var"; then break; fi
full_var=$new_full_var full_var=$new_full_var
done done
dnl clean up dnl clean up
full_var=$new_full_var full_var=$new_full_var
AC_SUBST([$1], "$full_var") AC_SUBST([$1], "$full_var")
dnl restore prefix and exec_prefix dnl restore prefix and exec_prefix
prefix=$prefix_save prefix=$prefix_save
exec_prefix=$exec_prefix_save exec_prefix=$exec_prefix_save
@ -94,7 +94,7 @@ x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"`
# Determine the number of characters in A and B. # Determine the number of characters in A and B.
ax_compare_version_len_A=`echo "$A" | awk '{print(length)}'` ax_compare_version_len_A=`echo "$A" | awk '{print(length)}'`
ax_compare_version_len_B=`echo "$B" | awk '{print(length)}'` ax_compare_version_len_B=`echo "$B" | awk '{print(length)}'`
# Set A to no more than B's length and B to no more than A's length. # Set A to no more than B's length and B to no more than A's length.
A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`

3
config/lxc.conf.libvirt Normal file
View File

@ -0,0 +1,3 @@
lxc.network.type = veth
lxc.network.link = virbr0
lxc.network.flags = up

3
config/lxc.conf.ubuntu Normal file
View File

@ -0,0 +1,3 @@
lxc.network.type = veth
lxc.network.link = lxcbr0
lxc.network.flags = up

1
config/lxc.conf.unknown Normal file
View File

@ -0,0 +1 @@
lxc.network.type = empty

View File

@ -6,40 +6,119 @@ AC_INIT([lxc], [0.8.0])
AC_CONFIG_SRCDIR([configure.ac]) AC_CONFIG_SRCDIR([configure.ac])
AC_CONFIG_AUX_DIR([config]) AC_CONFIG_AUX_DIR([config])
AM_CONFIG_HEADER([src/config.h]) AM_CONFIG_HEADER([src/config.h])
AM_INIT_AUTOMAKE([-Wno-portability]) AM_INIT_AUTOMAKE([-Wall -Werror -Wno-portability])
AC_CANONICAL_HOST AC_CANONICAL_HOST
AM_PROG_CC_C_O AM_PROG_CC_C_O
AC_GNU_SOURCE AC_GNU_SOURCE
AC_CHECK_PROG(SETCAP, setcap, yes, no, $PATH$PATH_SEPARATOR/sbin) AC_CHECK_PROG(SETCAP, setcap, yes, no, $PATH$PATH_SEPARATOR/sbin)
AC_MSG_CHECKING([host distribution])
AC_ARG_WITH(distro, AS_HELP_STRING([--with-distro=DISTRO], [Specify the Linux distribution to target: One of redhat, oracle, fedora, suse, gentoo, debian, arch, slackware, paldo, mandriva or pardus]))
if test "z$with_distro" = "z"; then
with_distro=`lsb_release -is`
fi
if test "z$with_distro" = "z"; then
AC_CHECK_FILE(/etc/redhat-release,with_distro="redhat")
AC_CHECK_FILE(/etc/oracle-release,with_distro="oracle")
AC_CHECK_FILE(/etc/fedora-release,with_distro="fedora")
AC_CHECK_FILE(/etc/SuSE-release,with_distro="suse")
AC_CHECK_FILE(/etc/gentoo-release,with_distro="gentoo")
AC_CHECK_FILE(/etc/debian_version,with_distro="debian")
AC_CHECK_FILE(/etc/arch-release,with_distro="arch")
AC_CHECK_FILE(/etc/slackware-version,with_distro="slackware")
AC_CHECK_FILE(/etc/frugalware-release,with_distro="frugalware")
AC_CHECK_FILE(/etc/mandrakelinux-release, with_distro="mandriva")
AC_CHECK_FILE(/etc/mandriva-release,with_distro="mandriva")
AC_CHECK_FILE(/etc/pardus-release,with_distro="pardus")
fi
with_distro=`echo ${with_distro} | tr '[[:upper:]]' '[[:lower:]]'`
if test "z$with_distro" = "z"; then
with_distro="unknown"
fi
case $with_distro in
ubuntu)
conffile=lxc.conf.ubuntu
;;
redhat|fedora|oracle|oracleserver)
conffile=lxc.conf.libvirt
;;
*)
echo -n "Linux distribution network config unknown, defaulting to lxc.network.type = empty"
conffile=lxc.conf.unknown
;;
esac
AC_MSG_RESULT([$with_distro])
AM_CONDITIONAL([HAVE_DEBIAN], [test x"$with_distro" = "xdebian" -o x"$with_distro" = "xubuntu"])
AC_ARG_ENABLE([rpath], AC_ARG_ENABLE([rpath],
[AC_HELP_STRING([--disable-rpath], [do not set rpath in executables])], [AC_HELP_STRING([--disable-rpath], [do not set rpath in executables])],
[], [enable_rpath=yes]) [], [enable_rpath=yes])
AM_CONDITIONAL([ENABLE_RPATH], [test "x$enable_rpath" = "xyes"]) AM_CONDITIONAL([ENABLE_RPATH], [test "x$enable_rpath" = "xyes"])
AC_ARG_ENABLE([apparmor],
[AC_HELP_STRING([--enable-apparmor], [enable apparmor])],
[], [enable_apparmor=yes])
AM_CONDITIONAL([ENABLE_APPARMOR], [test "x$enable_apparmor" = "xyes"])
AC_ARG_ENABLE([doc], AC_ARG_ENABLE([doc],
[AC_HELP_STRING([--enable-doc], [make mans (require docbook2man installed) [default=auto]])], [AC_HELP_STRING([--enable-doc], [make mans (require docbook2x-man installed) [default=auto]])],
[], [enable_doc=auto]) [], [enable_doc=auto])
if test "x$enable_doc" = "xyes" -o "x$enable_doc" = "xauto"; then if test "x$enable_doc" = "xyes" -o "x$enable_doc" = "xauto"; then
AC_CHECK_PROG(have_docbook, [docbook2man], [yes], [no]) db2xman=""
test "x$have_docbook" = "xno" -a "x$enable_doc" = "xyes" && \ AC_MSG_CHECKING(for docbook2x-man)
AC_MSG_ERROR([docbook2man required by man request, but not found]) for name in docbook2x-man db2x_docbook2man; do
if "$name" --help >/dev/null 2>&1; then
db2xman="$name"
break;
fi
done
if test -n "${db2xman}"; then
AC_MSG_RESULT(${db2xman})
else
AC_MSG_RESULT(no)
if test "x$enable_doc" = "xyes"; then
AC_MSG_ERROR([docbook2x-man required by man request, but not found])
fi
fi
AC_SUBST(db2xman)
fi fi
AC_ARG_ENABLE([apparmor],
[AC_HELP_STRING([--enable-apparmor], [enable apparmor])],
[], [enable_apparmor=check])
if test "$enable_apparmor" = "check" ; then
AC_CHECK_LIB([apparmor],[aa_change_profile],[enable_apparmor=yes], [enable_apparmor=no])
fi
AM_CONDITIONAL([ENABLE_APPARMOR], [test "x$enable_apparmor" = "xyes"])
AM_COND_IF([ENABLE_APPARMOR], 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_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])]) AC_CHECK_LIB([apparmor], [aa_change_profile],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
AC_SUBST([APPARMOR_LIBS], [-lapparmor])]) AC_SUBST([APPARMOR_LIBS], [-lapparmor])])
AM_CONDITIONAL([ENABLE_DOCBOOK], [test "x$have_docbook" = "xyes"]) AC_ARG_ENABLE([seccomp],
[AC_HELP_STRING([--enable-seccomp], [enable seccomp])],
[], [enable_seccomp=check])
if test "$enable_seccomp" = "check" ; then
AC_CHECK_LIB([seccomp],[seccomp_init],[enable_seccomp=yes],[enable_seccomp=no])
fi
AM_CONDITIONAL([ENABLE_SECCOMP], [test "x$enable_seccomp" = "xyes"])
AM_COND_IF([ENABLE_SECCOMP],
[AC_CHECK_HEADER([seccomp.h],[],[AC_MSG_ERROR([You must install the seccomp development package in order to compile lxc])])
AC_CHECK_LIB([seccomp], [seccomp_init],[],[AC_MSG_ERROR([You must install the seccomp development package in order to compile lxc])])
AC_SUBST([SECCOMP_LIBS], [-lseccomp])])
# HAVE_SCMP_FILTER_CTX=1 will tell us we have libseccomp api >= 1.0.0
AC_CHECK_TYPES([scmp_filter_ctx], [], [], [#include <seccomp.h>])
AM_CONDITIONAL([ENABLE_DOCBOOK], [test "x$db2xman" != "x"])
AC_ARG_ENABLE([examples], AC_ARG_ENABLE([examples],
[AC_HELP_STRING([--disable-examples], [do not install configuration examples])], [AC_HELP_STRING([--disable-examples], [do not install configuration examples])],
@ -47,6 +126,23 @@ AC_ARG_ENABLE([examples],
AM_CONDITIONAL([ENABLE_EXAMPLES], [test "x$enable_examples" = "xyes"]) AM_CONDITIONAL([ENABLE_EXAMPLES], [test "x$enable_examples" = "xyes"])
AC_ARG_ENABLE([python],
[AC_HELP_STRING([--enable-python], [enable python binding])],
[enable_python=yes], [enable_python=no])
AM_CONDITIONAL([ENABLE_PYTHON], [test "x$enable_python" = "xyes"])
AM_COND_IF([ENABLE_PYTHON],
[AM_PATH_PYTHON([3.2], [], [AC_MSG_ERROR([You must install python3])])
AC_CHECK_HEADER([python$PYTHON_VERSION/Python.h],[],[AC_MSG_ERROR([You must install python3-dev])])
AC_DEFINE_UNQUOTED([ENABLE_PYTHON], 1, [Python3 is available])])
AC_ARG_ENABLE([tests],
[AC_HELP_STRING([--enable-tests], [build test/example binaries])],
[enable_tests=yes], [enable_tests=no])
AM_CONDITIONAL([ENABLE_TESTS], [test "x$enable_tests" = "xyes"])
AS_AC_EXPAND(PREFIX, $prefix) AS_AC_EXPAND(PREFIX, $prefix)
AS_AC_EXPAND(LIBDIR, $libdir) AS_AC_EXPAND(LIBDIR, $libdir)
AS_AC_EXPAND(BINDIR, $bindir) AS_AC_EXPAND(BINDIR, $bindir)
@ -69,12 +165,13 @@ AC_ARG_WITH([rootfs-path],
[lxc rootfs mount point] [lxc rootfs mount point]
)], [], [with_rootfs_path=['${libdir}/lxc/rootfs']]) )], [], [with_rootfs_path=['${libdir}/lxc/rootfs']])
AS_AC_EXPAND(LXC_CONFFILE, $conffile)
AS_AC_EXPAND(LXC_GENERATE_DATE, "$(date)") AS_AC_EXPAND(LXC_GENERATE_DATE, "$(date)")
AS_AC_EXPAND(LXCPATH, "${with_config_path}") AS_AC_EXPAND(LXCPATH, "${with_config_path}")
AS_AC_EXPAND(LXCROOTFSMOUNT, "${with_rootfs_path}") AS_AC_EXPAND(LXCROOTFSMOUNT, "${with_rootfs_path}")
AS_AC_EXPAND(LXCTEMPLATEDIR, ['${datadir}/lxc/templates']) AS_AC_EXPAND(LXCTEMPLATEDIR, ['${datadir}/lxc/templates'])
AC_SUBST(LXCINITDIR, ['${libexecdir}']) AS_AC_EXPAND(LXCINITDIR, ['${libexecdir}'])
AC_CHECK_HEADERS([linux/unistd.h linux/netlink.h linux/genetlink.h], AC_CHECK_HEADERS([linux/unistd.h linux/netlink.h linux/genetlink.h],
[], [],
@ -101,9 +198,10 @@ AC_CHECK_DECLS([PR_CAPBSET_DROP], [], [], [#include <sys/prctl.h>])
AC_CHECK_HEADERS([sys/signalfd.h]) AC_CHECK_HEADERS([sys/signalfd.h])
AC_PROG_GCC_TRADITIONAL AC_PROG_GCC_TRADITIONAL
AC_PROG_SED
if test "x$GCC" = "xyes"; then if test "x$GCC" = "xyes"; then
CFLAGS="$CFLAGS -Wall" CFLAGS="$CFLAGS -Wall -Werror"
fi fi
AC_CONFIG_FILES([ AC_CONFIG_FILES([
@ -134,6 +232,7 @@ AC_CONFIG_FILES([
doc/lxc.sgml doc/lxc.sgml
doc/common_options.sgml doc/common_options.sgml
doc/see_also.sgml doc/see_also.sgml
doc/legacy/lxc-ls.sgml
doc/rootfs/Makefile doc/rootfs/Makefile
@ -154,6 +253,7 @@ AC_CONFIG_FILES([
templates/lxc-opensuse templates/lxc-opensuse
templates/lxc-busybox templates/lxc-busybox
templates/lxc-fedora templates/lxc-fedora
templates/lxc-oracle
templates/lxc-altlinux templates/lxc-altlinux
templates/lxc-sshd templates/lxc-sshd
templates/lxc-archlinux templates/lxc-archlinux
@ -161,7 +261,6 @@ AC_CONFIG_FILES([
src/Makefile src/Makefile
src/lxc/Makefile src/lxc/Makefile
src/lxc/lxc-ps src/lxc/lxc-ps
src/lxc/lxc-ls
src/lxc/lxc-netstat src/lxc/lxc-netstat
src/lxc/lxc-checkconfig src/lxc/lxc-checkconfig
src/lxc/lxc-setcap src/lxc/lxc-setcap
@ -170,7 +269,15 @@ AC_CONFIG_FILES([
src/lxc/lxc-create src/lxc/lxc-create
src/lxc/lxc-clone src/lxc/lxc-clone
src/lxc/lxc-shutdown src/lxc/lxc-shutdown
src/lxc/lxc-start-ephemeral
src/lxc/lxc-destroy src/lxc/lxc-destroy
src/lxc/legacy/lxc-ls
src/python-lxc/Makefile
src/python-lxc/lxc/__init__.py
src/python-lxc/examples/api_test.py
src/tests/Makefile
]) ])
AC_CONFIG_COMMANDS([default],[[]],[[]]) AC_CONFIG_COMMANDS([default],[[]],[[]])

View File

@ -32,8 +32,8 @@ error when starting a container.
"[syserr] lxc_start:96: Invalid argument - failed to fork into a new "[syserr] lxc_start:96: Invalid argument - failed to fork into a new
namespace" namespace"
Answer: Answer:
------- -------
read the lxc man page about kernel version prereq :) most probably read the lxc man page about kernel version prereq :) most probably
your kernel is not configured to support the container options you your kernel is not configured to support the container options you

View File

@ -19,7 +19,6 @@ man_MANS = \
lxc-unfreeze.1 \ lxc-unfreeze.1 \
lxc-monitor.1 \ lxc-monitor.1 \
lxc-wait.1 \ lxc-wait.1 \
lxc-ls.1 \
lxc-ps.1 \ lxc-ps.1 \
lxc-cgroup.1 \ lxc-cgroup.1 \
lxc-kill.1 \ lxc-kill.1 \
@ -29,15 +28,23 @@ man_MANS = \
\ \
lxc.7 lxc.7
if ENABLE_PYTHON
man_MANS += lxc-ls.1
else
man_MANS += legacy/lxc-ls.1
endif
%.1 : %.sgml %.1 : %.sgml
docbook2man -w all $< $(db2xman) $<
test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
%.5 : %.sgml %.5 : %.sgml
docbook2man -w all $< $(db2xman) $<
test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
%.7 : %.sgml %.7 : %.sgml
docbook2man -w all $< $(db2xman) $<
test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
lxc-%.sgml : common_options.sgml see_also.sgml lxc-%.sgml : common_options.sgml see_also.sgml

156
doc/legacy/lxc-ls.sgml.in Normal file
View File

@ -0,0 +1,156 @@
<!--
lxc: linux Container library
(C) Copyright IBM Corp. 2007, 2008
Authors:
Daniel Lezcano <dlezcano at fr.ibm.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 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 seealso SYSTEM "@builddir@/../see_also.sgml">
]>
<refentry>
<docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
<refmeta>
<refentrytitle>lxc-ls</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>lxc-ls</refname>
<refpurpose>
list the containers existing on the system
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>lxc-ls</command>
<arg choice="opt">--active</arg>
<arg choice="opt">ls option</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>lxc-ls</command> list the containers existing on the
system.
</para>
</refsect1>
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term>
<option><optional>--active</optional></option>
</term>
<listitem>
<para>
List active containers.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option><optional>ls options</optional></option>
</term>
<listitem>
<para>
The option passed to <command>lxc-ls</command> are the
same as the <command>ls</command> command.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Examples</title>
<variablelist>
<varlistentry>
<term>lxc-ls -l</term>
<listitem>
<para>
list all the container and their permissions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>lxc-ls --active -1</term>
<listitem>
<para>
list active containers and display the list in one column.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<simpara>
<citerefentry>
<refentrytitle>ls</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>,
</simpara>
</refsect1>
&seealso;
<refsect1>
<title>Author</title>
<para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:2
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:nil
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
-->

View File

@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -52,6 +52,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<arg choice="req">-n <replaceable>name</replaceable></arg> <arg choice="req">-n <replaceable>name</replaceable></arg>
<arg choice="opt">-a <replaceable>arch</replaceable></arg> <arg choice="opt">-a <replaceable>arch</replaceable></arg>
<arg choice="opt">-e</arg> <arg choice="opt">-e</arg>
<arg choice="opt">-s <replaceable>namespaces</replaceable></arg>
<arg choice="opt">-R</arg>
<arg choice="opt">-- <replaceable>command</replaceable></arg> <arg choice="opt">-- <replaceable>command</replaceable></arg>
</cmdsynopsis> </cmdsynopsis>
</refsynopsisdiv> </refsynopsisdiv>
@ -125,7 +127,53 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> <varlistentry>
<term>
<option>-s, --namespaces <replaceable>namespaces</replaceable></option>
</term>
<listitem>
<para>
Specify the namespaces to attach to, as a pipe-separated list,
e.g. <replaceable>NETWORK|IPC</replaceable>. Allowed values are
<replaceable>MOUNT</replaceable>, <replaceable>PID</replaceable>,
<replaceable>UTSNAME</replaceable>, <replaceable>IPC</replaceable>,
<replaceable>USER </replaceable> and
<replaceable>NETWORK</replaceable>. This allows one to change
the context of the process to e.g. the network namespace of the
container while retaining the other namespaces as those of the
host.
</para>
<para>
<emphasis>Important:</emphasis> This option implies
<option>-e</option>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-R, --remount-sys-proc</option>
</term>
<listitem>
<para>
When using <option>-s</option> and the mount namespace is not
included, this flag will cause <command>lxc-attach</command>
to remount <replaceable>/proc</replaceable> and
<replaceable>/sys</replaceable> to reflect the current other
namespace contexts.
</para>
<para>
Please see the <emphasis>Notes</emphasis> section for more
details.
</para>
<para>
This option will be ignored if one tries to attach to the
mount namespace anyway.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1> </refsect1>
@ -147,19 +195,86 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</para> </para>
<para> <para>
To deactivate the network link eth1 of a running container that To deactivate the network link eth1 of a running container that
does not have the NET_ADMIN capability, use the <option>-e</option> does not have the NET_ADMIN capability, use either the
option to use increased capabilities: <option>-e</option> option to use increased capabilities,
assuming the <command>ip</command> tool is installed:
<programlisting> <programlisting>
lxc-attach -n container -e -- /sbin/ip link delete eth1 lxc-attach -n container -e -- /sbin/ip link delete eth1
</programlisting> </programlisting>
Or, alternatively, use the <option>-s</option> to use the
tools installed on the host outside the container:
<programlisting>
lxc-attach -n container -s NETWORK -- /sbin/ip link delete eth1
</programlisting>
</para> </para>
</refsect1> </refsect1>
<refsect1>
<title>Compatibility</title>
<para>
Attaching completely (including the pid and mount namespaces) to a
container requires a patched kernel, please see the lxc website for
details. <command>lxc-attach</command> will fail in that case if
used with an unpatched kernel.
</para>
<para>
Nevertheless, it will succeed on an unpatched kernel of version 3.0
or higher if the <option>-s</option> option is used to restrict the
namespaces that the process is to be attached to to one or more of
<replaceable>NETWORK</replaceable>, <replaceable>IPC</replaceable>
and <replaceable>UTSNAME</replaceable>.
</para>
<para>
Attaching to user namespaces is currently completely unsupported
by the kernel. <command>lxc-attach</command> should however be able
to do this once once future kernel versions implement this.
</para>
</refsect1>
<refsect1>
<title>Notes</title>
<para>
The Linux <replaceable>/proc</replaceable> and
<replaceable>/sys</replaceable> filesystems contain information
about some quantities that are affected by namespaces, such as
the directories named after process ids in
<replaceable>/proc</replaceable> or the network interface infromation
in <replaceable>/sys/class/net</replaceable>. The namespace of the
process mounting the pseudo-filesystems determines what information
is shown, <emphasis>not</emphasis> the namespace of the process
accessing <replaceable>/proc</replaceable> or
<replaceable>/sys</replaceable>.
</para>
<para>
If one uses the <option>-s</option> option to only attach to
the pid namespace of a container, but not its mount namespace
(which will contain the <replaceable>/proc</replaceable> of the
container and not the host), the contents of <option>/proc</option>
will reflect that of the host and not the container. Analogously,
the same issue occurs when reading the contents of
<replaceable>/sys/class/net</replaceable> and attaching to just
the network namespace.
</para>
<para>
To work around this problem, the <option>-R</option> flag provides
the option to remount <replaceable>/proc</replaceable> and
<replaceable>/sys</replaceable> in order for them to reflect the
network/pid namespace context of the attached process. In order
not to interfere with the host's actual filesystem, the mount
namespace will be unshared (like <command>lxc-unshare</command>
does) before this is done, esentially giving the process a new
mount namespace, which is identical to the hosts's mount namespace
except for the <replaceable>/proc</replaceable> and
<replaceable>/sys</replaceable> filesystems.
</para>
</refsect1>
<refsect1> <refsect1>
<title>Security</title> <title>Security</title>
<para> <para>
The <option>-e</option> should be used with care, as it may break The <option>-e</option> and <option>-s</option> options should
the isolation of the containers if used improperly. be used with care, as it may break the isolation of the containers
if used improperly.
</para> </para>
</refsect1> </refsect1>

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -143,7 +143,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
The container is not running. The container is not running.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -67,7 +67,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
The available tty are free slots taken by this command. That The available tty are free slots taken by this command. That
means if the container has four ttys available and the command means if the container has four ttys available and the command
has been launched four times taking the different tty, the fifth has been launched four times taking the different tty, the fifth
command will fail because no console will be available. command will fail because no console will be available.
</para> </para>
<para> <para>
@ -114,7 +114,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
user "foo" and "bar" is trying to open a console to it. user "foo" and "bar" is trying to open a console to it.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -113,6 +113,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
eg. busybox, debian, fedora, ubuntu or sshd. eg. busybox, debian, fedora, ubuntu or sshd.
Refer to the examples in <filename>@LXCTEMPLATEDIR@</filename> Refer to the examples in <filename>@LXCTEMPLATEDIR@</filename>
for details of the expected script structure. for details of the expected script structure.
Alternatively, the full path to an executable template script
can also be passed as a parameter.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -123,9 +125,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</term> </term>
<listitem> <listitem>
<para> <para>
'backingstore' is one of 'none', 'lvm', or 'btrfs'. The 'backingstore' is one of 'none', 'dir', 'lvm', or 'btrfs'. The
default is 'none', meaning that the container root filesystem default is 'none', meaning that the container root filesystem
will be a directory under <filename>@LXCPATH@/container/rootfs</filename>. 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 The option 'btrfs' need not be specified as it will be used
automatically if the <filename>@LXCPATH@</filename> filesystem is found to automatically if the <filename>@LXCPATH@</filename> filesystem is found to
be btrfs. If backingstore is 'lvm', then an lvm block device will be be btrfs. If backingstore is 'lvm', then an lvm block device will be
@ -141,6 +147,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
filesystem) of size SIZE rather than the default, which is 1G. filesystem) of size SIZE rather than the default, which is 1G.
</para> </para>
</listitem> </listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term> <term>
@ -175,7 +182,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
available containers on the system. available containers on the system.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -100,7 +100,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
command to list the available containers on the system. command to list the available containers on the system.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -162,7 +162,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
container or create a new one. container or create a new one.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -81,7 +81,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
the <command>lxc-create</command> command. the <command>lxc-create</command> command.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -1,5 +1,5 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]> ]>
@ -49,8 +49,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsynopsisdiv> <refsynopsisdiv>
<cmdsynopsis> <cmdsynopsis>
<command>lxc-ls</command> <command>lxc-ls</command>
<arg choice="opt">-1</arg>
<arg choice="opt">--active</arg> <arg choice="opt">--active</arg>
<arg choice="opt">ls option</arg> <arg choice="opt">--frozen</arg>
<arg choice="opt">--running</arg>
<arg choice="opt">--stopped</arg>
<arg choice="opt">--fancy</arg>
<arg choice="opt">--fancy-format</arg>
<arg choice="opt">filter</arg>
</cmdsynopsis> </cmdsynopsis>
</refsynopsisdiv> </refsynopsisdiv>
@ -65,77 +71,136 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsect1> <refsect1>
<title>Options</title> <title>Options</title>
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term> <term>
<option><optional>--active</optional></option> <option><optional>-1</optional></option>
</term> </term>
<listitem> <listitem>
<para> <para>
List active containers. Show one entry per line. (default when /dev/stdout isn't a tty)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term> <term>
<option><optional>ls options</optional></option> <option><optional>--active</optional></option>
</term> </term>
<listitem> <listitem>
<para> <para>
The option passed to <command>lxc-ls</command> are the List only active containers (same as --frozen --running).
same as the <command>ls</command> command. </para>
</para> </listitem>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Examples</title>
<variablelist>
<varlistentry>
<term>lxc-ls -l</term>
<listitem>
<para>
list all the container and their permissions.
</para>
</listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>lxc-ls --active -1</term> <term>
<listitem> <option><optional>--frozen</optional></option>
<para> </term>
list active containers and display the list in one column. <listitem>
</para> <para>
</listitem> List only frozen containers.
</para>
</listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<option><optional>--running</optional></option>
</term>
<listitem>
<para>
List only running containers.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option><optional>--stopped</optional></option>
</term>
<listitem>
<para>
List only stopped containers.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option><optional>--fancy</optional></option>
</term>
<listitem>
<para>
Use a fancy, column-based output.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option><optional>--fancy-format</optional></option>
</term>
<listitem>
<para>
Comma separate list of column to show in the fancy output.
Valid values are: name, state, ipv4, ipv6 and pid
Default is: name,state,ipv4,ipv6
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option><optional>filter</optional></option>
</term>
<listitem>
<para>
The filter passed to <command>lxc-ls</command> will be
applied to the container name. The format is a regular expression.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1> <refsect1>
<title>See Also</title> <title>See Also</title>
<simpara> <simpara>
<citerefentry> <citerefentry>
<refentrytitle>ls</refentrytitle> <refentrytitle>ls</refentrytitle>
<manvolnum>1</manvolnum> <manvolnum>1</manvolnum>
</citerefentry>, </citerefentry>,
</simpara> </simpara>
</refsect1> <title>Examples</title>
<variablelist>
<varlistentry>
<term>lxc-ls --fancy</term>
<listitem>
<para>
list all the containers, listing one per line along with its
name, state, ipv4 and ipv6 addresses.
</para>
</listitem>
</varlistentry>
&seealso; <varlistentry>
<term>lxc-ls --active -1</term>
<listitem>
<para>
list active containers and display the list in one column.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1> <refsect1>
<title>Author</title> <title>Author</title>
<para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para> <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
</refsect1> </refsect1>
</refentry> </refentry>
<!-- Keep this comment at the end of the file <!-- Keep this comment at the end of the file

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -135,7 +135,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
the <command>lxc-create</command> command. the <command>lxc-create</command> command.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
@ -145,7 +145,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsect1> <refsect1>
<title>See Also</title> <title>See Also</title>
<simpara> <simpara>
<citerefentry> <citerefentry>
<refentrytitle>regex</refentrytitle> <refentrytitle>regex</refentrytitle>
<manvolnum>7</manvolnum> <manvolnum>7</manvolnum>

View File

@ -1,5 +1,5 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]> ]>
@ -86,8 +86,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<listitem> <listitem>
<para> <para>
specify the container <replaceable>name</replaceable> specify the container <replaceable>name</replaceable>
to limit the output to the processes belonging to limit the output to the processes belonging
to this container name. to this container name.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -98,7 +98,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</term> </term>
<listitem> <listitem>
<para> <para>
limit the output to the processes belonging limit the output to the processes belonging
to all lxc containers. to all lxc containers.
</para> </para>
</listitem> </listitem>
@ -139,7 +139,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsect1> <refsect1>
<title>See Also</title> <title>See Also</title>
<simpara> <simpara>
<citerefentry> <citerefentry>
<refentrytitle>ps</refentrytitle> <refentrytitle>ps</refentrytitle>
<manvolnum>1</manvolnum> <manvolnum>1</manvolnum>

View File

@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -53,6 +53,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<arg choice="opt">-f <replaceable>config_file</replaceable></arg> <arg choice="opt">-f <replaceable>config_file</replaceable></arg>
<arg choice="opt">-c <replaceable>console_file</replaceable></arg> <arg choice="opt">-c <replaceable>console_file</replaceable></arg>
<arg choice="opt">-d</arg> <arg choice="opt">-d</arg>
<arg choice="opt">-p <replaceable>pid_file</replaceable></arg>
<arg choice="opt">-s KEY=VAL</arg> <arg choice="opt">-s KEY=VAL</arg>
<arg choice="opt">-C</arg> <arg choice="opt">-C</arg>
<arg choice="opt">command</arg> <arg choice="opt">command</arg>
@ -107,6 +108,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<option>-p, --pidfile <replaceable>pid_file</replaceable></option>
</term>
<listitem>
<para>
Create a file with the process id.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term> <term>
<option>-f, --rcfile <replaceable>config_file</replaceable></option> <option>-f, --rcfile <replaceable>config_file</replaceable></option>
@ -186,7 +198,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
container or create a new one. container or create a new one.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -80,7 +80,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
container or create a new one. container or create a new one.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>The container was not found</term> <term>The container was not found</term>
@ -90,7 +90,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
the <command>lxc-create</command> command. the <command>lxc-create</command> command.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -78,7 +78,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
the <command>lxc-create</command> command. the <command>lxc-create</command> command.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -1,5 +1,5 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!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 commonoptions SYSTEM "@builddir@/common_options.sgml">
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
@ -79,6 +79,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<option>-t <replaceable>timeout</replaceable></option>
</term>
<listitem>
<para>
Wait timeout seconds for desired state to be reached.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
@ -122,7 +133,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
the <command>lxc-create</command> command. the <command>lxc-create</command> command.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -16,7 +16,7 @@ lxc.network.type = macvlan
# specify the flags to be used for the network, actually only <up> is allowed # specify the flags to be used for the network, actually only <up> is allowed
# which mean the network should be set up when created. If the network is set # which mean the network should be set up when created. If the network is set
# up, the loopback is automatically set up too. # up, the loopback is automatically set up too.
lxc.network.flags = up lxc.network.flags = up
# specify the physical network device which will communicate with the # specify the physical network device which will communicate with the

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]> ]>
@ -235,7 +235,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
specify an action to do for the specify an action to do for the
network. network.
</para> </para>
<para><option>up:</option> activates the interface. <para><option>up:</option> activates the interface.
</para> </para>
</listitem> </listitem>
@ -374,6 +374,26 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<option>lxc.network.script.down</option>
</term>
<listitem>
<para>
add a configuration option to specify a script to be
executed before destroying the network used from the
host side. The following arguments are passed to the
script: container name and config section name (net)
Additional arguments depend on the config section
employing a script hook; the following are used by the
network system: execution context (down), network type
(empty/veth/macvlan/phys), Depending on the network
type, other arguments may be passed:
veth/macvlan/phys. And finally (host-sided) device name.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect2> </refsect2>
@ -481,6 +501,31 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</variablelist> </variablelist>
</refsect2> </refsect2>
<refsect2>
<title>/dev directory</title>
<para>
By default, lxc does nothing with the container's
<filename>/dev</filename>. This allows the container's
<filename>/dev</filename> to be set up as needed in the container
rootfs. If lxc.autodev is set to 1, then after mounting the container's
rootfs LXC will mount a fresh tmpfs under <filename>/dev</filename>
(limited to 100k) and fill in a minimal set of initial devices.
</para>
<variablelist>
<varlistentry>
<term>
<option>lxc.autodev</option>
</term>
<listitem>
<para>
Set this to 1 to have LXC mount and populate a minimal
<filename>/dev</filename> when starting the container.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect2>
<refsect2> <refsect2>
<title>Mount points</title> <title>Mount points</title>
<para> <para>
@ -640,6 +685,84 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</variablelist> </variablelist>
</refsect2> </refsect2>
<refsect2>
<title>Startup hooks</title>
<para>
Startup hooks are programs or scripts which can be executed
at various times in a container's lifetime.
</para>
<variablelist>
<varlistentry>
<term>
<option>lxc.hook.pre-start</option>
</term>
<listitem>
<para>
A hook to be run in the host's namespace before the
container ttys, consoles, or mounts are up.
</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist>
<varlistentry>
<term>
<option>lxc.hook.pre-mount</option>
</term>
<listitem>
<para>
A hook to be run in the container's fs namespace but before
the rootfs has been set up. This allows for manipulation
of the rootfs, i.e. to mount an encrypted filesystem. Mounts
done in this hook will not be reflected on the host (apart from
mounts propagation), so they will be automatically cleaned up
when the container shuts down.
</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist>
<varlistentry>
<term>
<option>lxc.hook.mount</option>
</term>
<listitem>
<para>
A hook to be run in the container's namespace after
mounting has been done, but before the pivot_root.
</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist>
<varlistentry>
<term>
<option>lxc.hook.start</option>
</term>
<listitem>
<para>
A hook to be run in the container's namespace immediately
before executing the container's init. This requires the
program to be available in the container.
</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist>
<varlistentry>
<term>
<option>lxc.hook.post-stop</option>
</term>
<listitem>
<para>
A hook to be run in the host's namespace after the
container has been shut down.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect2>
</refsect1> </refsect1>
<refsect1> <refsect1>
@ -726,7 +849,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsect1> <refsect1>
<title>See Also</title> <title>See Also</title>
<simpara> <simpara>
<citerefentry> <citerefentry>
<refentrytitle><command>chroot</command></refentrytitle> <refentrytitle><command>chroot</command></refentrytitle>
<manvolnum>1</manvolnum> <manvolnum>1</manvolnum>
@ -744,14 +867,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</simpara> </simpara>
</refsect1> </refsect1>
&seealso; &seealso;
<refsect1> <refsect1>
<title>Author</title> <title>Author</title>
<para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para> <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
</refsect1> </refsect1>
</refentry> </refentry>
<!-- Keep this comment at the end of the file <!-- Keep this comment at the end of the file

View File

@ -1,4 +1,4 @@
<!-- <!--
lxc: linux Container library lxc: linux Container library
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--> -->
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml"> <!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
]> ]>
@ -239,7 +239,7 @@ rootfs
/sbin /home/root/sshd/rootfs/sbin none ro,bind 0 0 /sbin /home/root/sshd/rootfs/sbin none ro,bind 0 0
</programlisting> </programlisting>
</para> </para>
<para>How to run a system in a container ?</para> <para>How to run a system in a container ?</para>
<para>Running a system inside a container is paradoxically easier <para>Running a system inside a container is paradoxically easier
@ -249,7 +249,7 @@ rootfs
without configuration because the container will set them without configuration because the container will set them
up. eg. the ipv4 address will be setup by the system container up. eg. the ipv4 address will be setup by the system container
init scripts. Here is an example of the mount points file: init scripts. Here is an example of the mount points file:
<programlisting> <programlisting>
[root@lxc debian]$ cat fstab [root@lxc debian]$ cat fstab
@ -280,7 +280,7 @@ rootfs
</para> </para>
<programlisting> <programlisting>
<![CDATA[
--------- ---------
| STOPPED |<--------------- | STOPPED |<---------------
--------- | --------- |
@ -305,14 +305,14 @@ rootfs
---------- | ---------- |
| | | |
--------------------- ---------------------
]]>
</programlisting> </programlisting>
</refsect2> </refsect2>
<refsect2> <refsect2>
<title>Configuration</title> <title>Configuration</title>
<para>The container is configured through a configuration <para>The container is configured through a configuration
file, the format of the configuration file is described in file, the format of the configuration file is described in
<citerefentry> <citerefentry>
<refentrytitle><filename>lxc.conf</filename></refentrytitle> <refentrytitle><filename>lxc.conf</filename></refentrytitle>
<manvolnum>5</manvolnum> <manvolnum>5</manvolnum>
@ -363,7 +363,7 @@ rootfs
but if needed the <command>lxc-stop</command> command can but if needed the <command>lxc-stop</command> command can
be used to kill the still running application. be used to kill the still running application.
</para> </para>
<para> <para>
Running an application inside a container is not exactly the Running an application inside a container is not exactly the
same thing as running a system. For this reason, there are two same thing as running a system. For this reason, there are two
@ -434,7 +434,7 @@ rootfs
lxc-freeze -n foo lxc-freeze -n foo
</programlisting> </programlisting>
will put all the processes in an uninteruptible state and will put all the processes in an uninteruptible state and
<programlisting> <programlisting>
lxc-unfreeze -n foo lxc-unfreeze -n foo
@ -570,7 +570,7 @@ rootfs
to the background. to the background.
<programlisting> <programlisting>
<![CDATA[
# launch lxc-wait in background # launch lxc-wait in background
lxc-wait -n foo -s STOPPED & lxc-wait -n foo -s STOPPED &
LXC_WAIT_PID=$! LXC_WAIT_PID=$!
@ -583,7 +583,7 @@ rootfs
# is STOPPED # is STOPPED
wait $LXC_WAIT_PID wait $LXC_WAIT_PID
echo "'foo' is finished" echo "'foo' is finished"
]]>
</programlisting> </programlisting>
</para> </para>
</refsect2> </refsect2>

View File

@ -1,3 +1,3 @@
READMEdir=@LXCROOTFSMOUNT@ READMEdir=@LXCROOTFSMOUNT@
README_DATA=README README_DATA=README

View File

@ -29,8 +29,8 @@ Summary: %{name} : Linux Container
Group: Applications/System Group: Applications/System
License: LGPL License: LGPL
BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRoot: %{_tmppath}/%{name}-%{version}-build
Requires: libcap Requires: libcap openssl rsync
BuildRequires: libcap libcap-devel docbook-utils BuildRequires: libcap libcap-devel docbook2X
%description %description
@ -91,11 +91,13 @@ rm -rf %{buildroot}
%{_mandir}/* %{_mandir}/*
%{_datadir}/doc/* %{_datadir}/doc/*
%{_datadir}/lxc/* %{_datadir}/lxc/*
%{_sysconfdir}/lxc/*
%files libs %files libs
%defattr(-,root,root) %defattr(-,root,root)
%{_libdir}/*.so.* %{_libdir}/*.so.*
%{_libdir}/%{name} %{_libdir}/%{name}
%{_localstatedir}/*
%attr(4555,root,root) %{_libexecdir}/%{name}/lxc-init %attr(4555,root,root) %{_libexecdir}/%{name}/lxc-init
%files devel %files devel

32
runapitests.sh Normal file
View File

@ -0,0 +1,32 @@
#!/bin/sh
cleanup() {
rm -f /etc/lxc/test-busybox.conf
rm -f liblxc.so.0
}
if [ `id -u` -ne 0 ]; then
echo "Run as root"
exit 1
fi
cat > /etc/lxc/test-busybox.conf << EOF
lxc.network.type=veth
lxc.network.link=lxcbr0
lxc.network.flags=up
EOF
[ -f liblxc.so.0 ] || ln -s src/lxc/liblxc.so ./liblxc.so.0
export LD_LIBRARY_PATH=.
TESTS="lxc-test-containertests lxc-test-locktests lxc-test-startone"
for curtest in $TESTS; do
echo "running $curtest"
./src/tests/$curtest
if [ $? -ne 0 ]; then
echo "Test $curtest failed. Stopping"
cleanup
exit 1
fi
done
echo "All tests passed"
cleanup

View File

@ -1 +1 @@
SUBDIRS = lxc SUBDIRS = lxc tests python-lxc

View File

@ -13,7 +13,9 @@ pkginclude_HEADERS = \
list.h \ list.h \
log.h \ log.h \
state.h \ state.h \
attach.h attach.h \
lxccontainer.h \
lxclock.h
sodir=$(libdir) sodir=$(libdir)
# use PROGRAMS to avoid complains from automake # use PROGRAMS to avoid complains from automake
@ -50,33 +52,41 @@ liblxc_so_SOURCES = \
genl.c genl.h \ genl.c genl.h \
\ \
caps.c caps.h \ caps.c caps.h \
lxcseccomp.h \
mainloop.c mainloop.h \ mainloop.c mainloop.h \
af_unix.c af_unix.h \ af_unix.c af_unix.h \
\ \
utmp.c utmp.h \ utmp.c utmp.h \
apparmor.c apparmor.h apparmor.c apparmor.h \
lxclock.h lxclock.c \
lxccontainer.c lxccontainer.h
AM_CFLAGS=-I$(top_srcdir)/src \ AM_CFLAGS=-I$(top_srcdir)/src \
-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \ -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
-DLXCPATH=\"$(LXCPATH)\" \ -DLXCPATH=\"$(LXCPATH)\" \
-DLXCINITDIR=\"$(LXCINITDIR)\" -DLXCINITDIR=\"$(LXCINITDIR)\" \
-DLXCTEMPLATEDIR=\"$(LXCTEMPLATEDIR)\"
if ENABLE_APPARMOR if ENABLE_APPARMOR
AM_CFLAGS += -DHAVE_APPARMOR AM_CFLAGS += -DHAVE_APPARMOR
endif endif
if ENABLE_SECCOMP
AM_CFLAGS += -DHAVE_SECCOMP
liblxc_so_SOURCES += seccomp.c
endif
liblxc_so_CFLAGS = -fPIC -DPIC $(AM_CFLAGS) liblxc_so_CFLAGS = -fPIC -DPIC $(AM_CFLAGS)
liblxc_so_LDFLAGS = \ liblxc_so_LDFLAGS = \
-shared \ -shared \
-Wl,-soname,liblxc.so.$(firstword $(subst ., ,$(VERSION))) -Wl,-soname,liblxc.so.$(firstword $(subst ., ,$(VERSION)))
liblxc_so_LDADD = -lutil $(CAP_LIBS) $(APPARMOR_LIBS) liblxc_so_LDADD = -lutil $(CAP_LIBS) $(APPARMOR_LIBS) $(SECCOMP_LIBS) -lrt
bin_SCRIPTS = \ bin_SCRIPTS = \
lxc-ps \ lxc-ps \
lxc-netstat \ lxc-netstat \
lxc-ls \
lxc-checkconfig \ lxc-checkconfig \
lxc-setcap \ lxc-setcap \
lxc-setuid \ lxc-setuid \
@ -86,6 +96,14 @@ bin_SCRIPTS = \
lxc-shutdown \ lxc-shutdown \
lxc-destroy lxc-destroy
if ENABLE_PYTHON
bin_SCRIPTS += lxc-device
bin_SCRIPTS += lxc-ls
bin_SCRIPTS += lxc-start-ephemeral
else
bin_SCRIPTS += legacy/lxc-ls
endif
bin_PROGRAMS = \ bin_PROGRAMS = \
lxc-attach \ lxc-attach \
lxc-unshare \ lxc-unshare \
@ -110,7 +128,7 @@ AM_LDFLAGS = -Wl,-E
if ENABLE_RPATH if ENABLE_RPATH
AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir) AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
endif endif
LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SECCOMP_LIBS@ -lrt
lxc_attach_SOURCES = lxc_attach.c lxc_attach_SOURCES = lxc_attach.c
lxc_cgroup_SOURCES = lxc_cgroup.c lxc_cgroup_SOURCES = lxc_cgroup.c

View File

@ -52,7 +52,7 @@ int lxc_af_unix_open(const char *path, int type, int flags)
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
/* copy entire buffer in case of abstract socket */ /* copy entire buffer in case of abstract socket */
memcpy(addr.sun_path, path, memcpy(addr.sun_path, path,
path[0]?strlen(path):sizeof(addr.sun_path)); path[0]?strlen(path):sizeof(addr.sun_path));
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) { if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
@ -73,7 +73,7 @@ int lxc_af_unix_close(int fd)
struct sockaddr_un addr; struct sockaddr_un addr;
socklen_t addrlen; socklen_t addrlen;
if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) && if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) &&
addr.sun_path[0]) addr.sun_path[0])
unlink(addr.sun_path); unlink(addr.sun_path);
@ -95,7 +95,7 @@ int lxc_af_unix_connect(const char *path)
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
/* copy entire buffer in case of abstract socket */ /* copy entire buffer in case of abstract socket */
memcpy(addr.sun_path, path, memcpy(addr.sun_path, path,
path[0]?strlen(path):sizeof(addr.sun_path)); path[0]?strlen(path):sizeof(addr.sun_path));
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) { if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) {
@ -161,7 +161,7 @@ int lxc_af_unix_recv_fd(int fd, int *recvfd, void *data, size_t size)
cmsg = CMSG_FIRSTHDR(&msg); cmsg = CMSG_FIRSTHDR(&msg);
/* if the message is wrong the variable will not be /* if the message is wrong the variable will not be
* filled and the peer will notified about a problem */ * filled and the peer will notified about a problem */
*recvfd = -1; *recvfd = -1;

View File

@ -45,6 +45,7 @@ struct lxc_arguments {
int daemonize; int daemonize;
const char *rcfile; const char *rcfile;
const char *console; const char *console;
const char *pidfile;
/* for lxc-checkpoint/restart */ /* for lxc-checkpoint/restart */
const char *statefile; const char *statefile;
@ -57,6 +58,7 @@ struct lxc_arguments {
/* for lxc-wait */ /* for lxc-wait */
char *states; char *states;
long timeout;
/* close fds from parent? */ /* close fds from parent? */
int close_all_fds; int close_all_fds;

View File

@ -30,6 +30,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/mount.h>
#include <linux/unistd.h> #include <linux/unistd.h>
#if !HAVE_DECL_PR_CAPBSET_DROP #if !HAVE_DECL_PR_CAPBSET_DROP
@ -121,13 +122,22 @@ out_error:
return NULL; return NULL;
} }
int lxc_attach_to_ns(pid_t pid) int lxc_attach_to_ns(pid_t pid, int which)
{ {
char path[MAXPATHLEN]; char path[MAXPATHLEN];
char *ns[] = { "pid", "mnt", "net", "ipc", "uts" }; /* according to <http://article.gmane.org/gmane.linux.kernel.containers.lxc.devel/1429>,
const int size = sizeof(ns) / sizeof(char *); * the file for user namepsaces in /proc/$pid/ns will be called
* 'user' once the kernel supports it
*/
static char *ns[] = { "mnt", "pid", "uts", "ipc", "user", "net" };
static int flags[] = {
CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
CLONE_NEWUSER, CLONE_NEWNET
};
static const int size = sizeof(ns) / sizeof(char *);
int fd[size]; int fd[size];
int i; int i, j, saved_errno;
snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid); snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
if (access(path, X_OK)) { if (access(path, X_OK)) {
@ -136,16 +146,39 @@ int lxc_attach_to_ns(pid_t pid)
} }
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
/* ignore if we are not supposed to attach to that
* namespace
*/
if (which != -1 && !(which & flags[i])) {
fd[i] = -1;
continue;
}
snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]); snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]);
fd[i] = open(path, O_RDONLY); fd[i] = open(path, O_RDONLY);
if (fd[i] < 0) { if (fd[i] < 0) {
saved_errno = errno;
/* close all already opened file descriptors before
* we return an error, so we don't leak them
*/
for (j = 0; j < i; j++)
close(fd[j]);
errno = saved_errno;
SYSERROR("failed to open '%s'", path); SYSERROR("failed to open '%s'", path);
return -1; return -1;
} }
} }
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
if (setns(fd[i], 0)) { if (fd[i] >= 0 && setns(fd[i], 0) != 0) {
saved_errno = errno;
for (j = i; j < size; j++)
close(fd[j]);
errno = saved_errno;
SYSERROR("failed to set namespace '%s'", ns[i]); SYSERROR("failed to set namespace '%s'", ns[i]);
return -1; return -1;
} }
@ -156,6 +189,49 @@ int lxc_attach_to_ns(pid_t pid)
return 0; return 0;
} }
int lxc_attach_remount_sys_proc()
{
int ret;
ret = unshare(CLONE_NEWNS);
if (ret < 0) {
SYSERROR("failed to unshare mount namespace");
return -1;
}
/* assume /proc is always mounted, so remount it */
ret = umount2("/proc", MNT_DETACH);
if (ret < 0) {
SYSERROR("failed to unmount /proc");
return -1;
}
ret = mount("none", "/proc", "proc", 0, NULL);
if (ret < 0) {
SYSERROR("failed to remount /proc");
return -1;
}
/* try to umount /sys - if it's not a mount point,
* we'll get EINVAL, then we ignore it because it
* may not have been mounted in the first place
*/
ret = umount2("/sys", MNT_DETACH);
if (ret < 0 && errno != EINVAL) {
SYSERROR("failed to unmount /sys");
return -1;
} else if (ret == 0) {
/* remount it */
ret = mount("none", "/sys", "sysfs", 0, NULL);
if (ret < 0) {
SYSERROR("failed to remount /sys");
return -1;
}
}
return 0;
}
int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx) int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
{ {
int last_cap = lxc_caps_last_cap(); int last_cap = lxc_caps_last_cap();

View File

@ -33,7 +33,8 @@ struct lxc_proc_context_info {
extern struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid); extern struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid);
extern int lxc_attach_to_ns(pid_t other_pid); 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); extern int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx);
#endif #endif

View File

@ -254,13 +254,38 @@ static int cgroup_enable_clone_children(const char *path)
return ret; return ret;
} }
static int lxc_one_cgroup_attach(const char *name, static int lxc_one_cgroup_finish_attach(int fd, pid_t pid)
struct mntent *mntent, pid_t pid)
{ {
FILE *f; char buf[32];
int ret;
snprintf(buf, 32, "%ld", (long)pid);
ret = write(fd, buf, strlen(buf));
if (ret <= 0) {
SYSERROR("failed to write pid '%ld' to fd '%d'", (long)pid, fd);
ret = -1;
} else {
ret = 0;
}
close(fd);
return ret;
}
static int lxc_one_cgroup_dispose_attach(int fd)
{
close(fd);
return 0;
}
static int lxc_one_cgroup_prepare_attach(const char *name,
struct mntent *mntent)
{
int fd;
char tasks[MAXPATHLEN], initcgroup[MAXPATHLEN]; char tasks[MAXPATHLEN], initcgroup[MAXPATHLEN];
char *cgmnt = mntent->mnt_dir; char *cgmnt = mntent->mnt_dir;
int flags, ret = 0; int flags;
int rc; int rc;
flags = get_cgroup_flags(mntent); flags = get_cgroup_flags(mntent);
@ -274,31 +299,83 @@ static int lxc_one_cgroup_attach(const char *name,
return -1; return -1;
} }
f = fopen(tasks, "w"); fd = open(tasks, O_WRONLY);
if (!f) { if (fd < 0) {
SYSERROR("failed to open '%s'", tasks); SYSERROR("failed to open '%s'", tasks);
return -1; return -1;
} }
if (fprintf(f, "%d", pid) <= 0) { return fd;
SYSERROR("failed to write pid '%d' to '%s'", pid, tasks); }
ret = -1;
static int lxc_one_cgroup_attach(const char *name, struct mntent *mntent, pid_t pid)
{
int fd;
fd = lxc_one_cgroup_prepare_attach(name, mntent);
if (fd < 0) {
return -1;
} }
fclose(f); return lxc_one_cgroup_finish_attach(fd, pid);
}
int lxc_cgroup_dispose_attach(void *data)
{
int *fds = data;
int ret, err;
if (!fds) {
return 0;
}
ret = 0;
for (; *fds >= 0; fds++) {
err = lxc_one_cgroup_dispose_attach(*fds);
if (err) {
ret = err;
}
}
free(data);
return ret; return ret;
} }
/* int lxc_cgroup_finish_attach(void *data, pid_t pid)
* for each mounted cgroup, attach a pid to the cgroup for the container {
*/ int *fds = data;
int lxc_cgroup_attach(const char *name, pid_t pid) int err;
if (!fds) {
return 0;
}
for (; *fds >= 0; fds++) {
err = lxc_one_cgroup_finish_attach(*fds, pid);
if (err) {
/* get rid of the rest of them */
lxc_cgroup_dispose_attach(data);
return -1;
}
*fds = -1;
}
free(data);
return 0;
}
int lxc_cgroup_prepare_attach(const char *name, void **data)
{ {
struct mntent *mntent; struct mntent *mntent;
FILE *file = NULL; FILE *file = NULL;
int err = -1; int err = -1;
int found = 0; int found = 0;
int *fds;
int i;
static const int MAXFDS = 256;
file = setmntent(MTAB, "r"); file = setmntent(MTAB, "r");
if (!file) { if (!file) {
@ -306,7 +383,29 @@ int lxc_cgroup_attach(const char *name, pid_t pid)
return -1; return -1;
} }
/* create a large enough buffer for all practical
* use cases
*/
fds = malloc(sizeof(int) * MAXFDS);
if (!fds) {
err = -1;
goto out;
}
for (i = 0; i < MAXFDS; i++) {
fds[i] = -1;
}
err = 0;
i = 0;
while ((mntent = getmntent(file))) { while ((mntent = getmntent(file))) {
if (i >= MAXFDS - 1) {
ERROR("too many cgroups to attach to, aborting");
lxc_cgroup_dispose_attach(fds);
errno = ENOMEM;
err = -1;
goto out;
}
DEBUG("checking '%s' (%s)", mntent->mnt_dir, mntent->mnt_type); DEBUG("checking '%s' (%s)", mntent->mnt_dir, mntent->mnt_type);
if (strcmp(mntent->mnt_type, "cgroup")) if (strcmp(mntent->mnt_type, "cgroup"))
@ -317,19 +416,41 @@ int lxc_cgroup_attach(const char *name, pid_t pid)
INFO("[%d] found cgroup mounted at '%s',opts='%s'", INFO("[%d] found cgroup mounted at '%s',opts='%s'",
++found, mntent->mnt_dir, mntent->mnt_opts); ++found, mntent->mnt_dir, mntent->mnt_opts);
err = lxc_one_cgroup_attach(name, mntent, pid); fds[i] = lxc_one_cgroup_prepare_attach(name, mntent);
if (err) if (fds[i] < 0) {
err = fds[i];
lxc_cgroup_dispose_attach(fds);
goto out; goto out;
}
i++;
}; };
if (!found) if (!found)
ERROR("No cgroup mounted on the system"); ERROR("No cgroup mounted on the system");
*data = fds;
out: out:
endmntent(file); endmntent(file);
return err; return err;
} }
/*
* for each mounted cgroup, attach a pid to the cgroup for the container
*/
int lxc_cgroup_attach(const char *name, pid_t pid)
{
void *data = NULL;
int ret;
ret = lxc_cgroup_prepare_attach(name, &data);
if (ret < 0) {
return ret;
}
return lxc_cgroup_finish_attach(data, pid);
}
/* /*
* rename cgname, which is under cgparent, to a new name starting * rename cgname, which is under cgparent, to a new name starting
* with 'cgparent/dead'. That way cgname can be reused. Return * with 'cgparent/dead'. That way cgname can be reused. Return
@ -421,7 +542,7 @@ static int lxc_one_cgroup_create(const char *name,
/* if cgparent does not exist, create it */ /* if cgparent does not exist, create it */
if (access(cgparent, F_OK)) { if (access(cgparent, F_OK)) {
ret = mkdir(cgparent, 0755); ret = mkdir(cgparent, 0755);
if (ret == -1 && errno == EEXIST) { if (ret == -1 && errno != EEXIST) {
SYSERROR("failed to create '%s' directory", cgparent); SYSERROR("failed to create '%s' directory", cgparent);
return -1; return -1;
} }
@ -668,6 +789,13 @@ out:
return ret; return ret;
} }
/*
* If you pass in NULL value or 0 len, then you are asking for the size
* of the file. Note that we can't get the file size quickly through stat
* or lseek. Therefore if you pass in len > 0 but less than the file size,
* your only indication will be that the return value will be equal to the
* passed-in ret. We will not return the actual full file size.
*/
int lxc_cgroup_get(const char *name, const char *filename, int lxc_cgroup_get(const char *name, const char *filename,
char *value, size_t len) char *value, size_t len)
{ {
@ -692,7 +820,18 @@ int lxc_cgroup_get(const char *name, const char *filename,
return -1; return -1;
} }
ret = read(fd, value, len); if (!len || !value) {
char buf[100];
int count = 0;
while ((ret = read(fd, buf, 100)) > 0)
count += ret;
if (ret >= 0)
ret = count;
} else {
memset(value, 0, len);
ret = read(fd, value, len);
}
if (ret < 0) if (ret < 0)
ERROR("read %s : %s", path, strerror(errno)); ERROR("read %s : %s", path, strerror(errno));

View File

@ -31,5 +31,8 @@ extern int lxc_cgroup_destroy(const char *name);
extern int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name); extern int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name);
extern int lxc_cgroup_nrtasks(const char *name); extern int lxc_cgroup_nrtasks(const char *name);
extern int lxc_cgroup_attach(const char *name, pid_t pid); extern int lxc_cgroup_attach(const char *name, pid_t pid);
extern int lxc_cgroup_prepare_attach(const char *name, void **data);
extern int lxc_cgroup_finish_attach(void *data, pid_t pid);
extern int lxc_cgroup_dispose_attach(void *data);
extern int lxc_ns_is_mounted(void); extern int lxc_ns_is_mounted(void);
#endif #endif

View File

@ -154,11 +154,32 @@ pid_t get_init_pid(const char *name)
return command.answer.pid; return command.answer.pid;
} }
int lxc_get_clone_flags(const char *name)
{
struct lxc_command command = {
.request = { .type = LXC_COMMAND_CLONE_FLAGS },
};
int ret, stopped = 0;
ret = lxc_command(name, &command, &stopped);
if (ret < 0 && stopped)
return -1;
if (ret < 0) {
ERROR("failed to send command");
return -1;
}
return command.answer.ret;
}
extern void lxc_console_remove_fd(int, struct lxc_tty_info *); 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_console_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_stop_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_state_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_pid_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 *);
static int trigger_command(int fd, struct lxc_request *request, static int trigger_command(int fd, struct lxc_request *request,
struct lxc_handler *handler) struct lxc_handler *handler)
@ -166,10 +187,11 @@ static int trigger_command(int fd, struct lxc_request *request,
typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *); typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
callback cb[LXC_COMMAND_MAX] = { callback cb[LXC_COMMAND_MAX] = {
[LXC_COMMAND_TTY] = lxc_console_callback, [LXC_COMMAND_TTY] = lxc_console_callback,
[LXC_COMMAND_STOP] = lxc_stop_callback, [LXC_COMMAND_STOP] = lxc_stop_callback,
[LXC_COMMAND_STATE] = lxc_state_callback, [LXC_COMMAND_STATE] = lxc_state_callback,
[LXC_COMMAND_PID] = lxc_pid_callback, [LXC_COMMAND_PID] = lxc_pid_callback,
[LXC_COMMAND_CLONE_FLAGS] = lxc_clone_flags_callback,
}; };
if (request->type < 0 || request->type >= LXC_COMMAND_MAX) if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
@ -305,5 +327,6 @@ extern int lxc_command_mainloop_add(const char *name,
close(fd); close(fd);
} }
handler->conf->maincmd_fd = fd;
return ret; return ret;
} }

View File

@ -28,6 +28,7 @@ enum {
LXC_COMMAND_STOP, LXC_COMMAND_STOP,
LXC_COMMAND_STATE, LXC_COMMAND_STATE,
LXC_COMMAND_PID, LXC_COMMAND_PID,
LXC_COMMAND_CLONE_FLAGS,
LXC_COMMAND_MAX, LXC_COMMAND_MAX,
}; };
@ -48,6 +49,7 @@ struct lxc_command {
}; };
extern pid_t get_init_pid(const char *name); extern pid_t get_init_pid(const char *name);
extern int lxc_get_clone_flags(const char *name);
extern int lxc_command(const char *name, struct lxc_command *command, extern int lxc_command(const char *name, struct lxc_command *command,
int *stopped); int *stopped);

View File

@ -66,6 +66,8 @@
#include <apparmor.h> #include <apparmor.h>
#endif #endif
#include "lxcseccomp.h"
lxc_log_define(lxc_conf, lxc); lxc_log_define(lxc_conf, lxc);
#define MAXHWLEN 18 #define MAXHWLEN 18
@ -109,6 +111,9 @@ lxc_log_define(lxc_conf, lxc);
#define PR_CAPBSET_DROP 24 #define PR_CAPBSET_DROP 24
#endif #endif
char *lxchook_names[NUM_LXC_HOOKS] = {
"pre-start", "pre-mount", "mount", "start", "post-stop" };
extern int pivot_root(const char * new_root, const char * put_old); extern int pivot_root(const char * new_root, const char * put_old);
typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *); typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
@ -138,6 +143,20 @@ static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
[LXC_NET_EMPTY] = instanciate_empty, [LXC_NET_EMPTY] = instanciate_empty,
}; };
static int shutdown_veth(struct lxc_handler *, struct lxc_netdev *);
static int shutdown_macvlan(struct lxc_handler *, struct lxc_netdev *);
static int shutdown_vlan(struct lxc_handler *, struct lxc_netdev *);
static int shutdown_phys(struct lxc_handler *, struct lxc_netdev *);
static int shutdown_empty(struct lxc_handler *, struct lxc_netdev *);
static instanciate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
[LXC_NET_VETH] = shutdown_veth,
[LXC_NET_MACVLAN] = shutdown_macvlan,
[LXC_NET_VLAN] = shutdown_vlan,
[LXC_NET_PHYS] = shutdown_phys,
[LXC_NET_EMPTY] = shutdown_empty,
};
static struct mount_opt mount_opt[] = { static struct mount_opt mount_opt[] = {
{ "defaults", 0, 0 }, { "defaults", 0, 0 },
{ "ro", 0, MS_RDONLY }, { "ro", 0, MS_RDONLY },
@ -214,12 +233,41 @@ static struct caps_opt caps_opt[] = {
#endif #endif
}; };
static int run_buffer(char *buffer)
{
FILE *f;
char *output;
f = popen(buffer, "r");
if (!f) {
SYSERROR("popen failed");
return -1;
}
output = malloc(LXC_LOG_BUFFER_SIZE);
if (!output) {
ERROR("failed to allocate memory for script output");
return -1;
}
while(fgets(output, LXC_LOG_BUFFER_SIZE, f))
DEBUG("script output: %s", output);
free(output);
if (pclose(f) == -1) {
SYSERROR("Script exited on error");
return -1;
}
return 0;
}
static int run_script(const char *name, const char *section, static int run_script(const char *name, const char *section,
const char *script, ...) const char *script, ...)
{ {
int ret; int ret;
FILE *f; char *buffer, *p;
char *buffer, *p, *output;
size_t size = 0; size_t size = 0;
va_list ap; va_list ap;
@ -266,29 +314,7 @@ static int run_script(const char *name, const char *section,
} }
va_end(ap); va_end(ap);
f = popen(buffer, "r"); return run_buffer(buffer);
if (!f) {
SYSERROR("popen failed");
return -1;
}
output = malloc(LXC_LOG_BUFFER_SIZE);
if (!output) {
ERROR("failed to allocate memory for script output");
return -1;
}
while(fgets(output, LXC_LOG_BUFFER_SIZE, f))
DEBUG("script output: %s", output);
free(output);
if (pclose(f) == -1) {
SYSERROR("Script exited on error");
return -1;
}
return 0;
} }
static int find_fstype_cb(char* buffer, void *data) static int find_fstype_cb(char* buffer, void *data)
@ -636,6 +662,15 @@ static int setup_tty(const struct lxc_rootfs *rootfs,
return -1; return -1;
} }
} else { } else {
/* If we populated /dev, then we need to create /dev/ttyN */
if (access(path, F_OK)) {
ret = creat(path, 0660);
if (ret==-1) {
SYSERROR("error creating %s\n", path);
/* this isn't fatal, continue */
} else
close(ret);
}
if (mount(pty_info->name, path, "none", MS_BIND, 0)) { if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
WARN("failed to mount '%s'->'%s'", WARN("failed to mount '%s'->'%s'",
pty_info->name, path); pty_info->name, path);
@ -708,7 +743,7 @@ static int umount_oldrootfs(const char *oldrootfs)
{ {
char path[MAXPATHLEN]; char path[MAXPATHLEN];
void *cbparm[2]; void *cbparm[2];
struct lxc_list mountlist, *iterator; struct lxc_list mountlist, *iterator, *next;
int ok, still_mounted, last_still_mounted; int ok, still_mounted, last_still_mounted;
int rc; int rc;
@ -748,7 +783,7 @@ static int umount_oldrootfs(const char *oldrootfs)
last_still_mounted = still_mounted; last_still_mounted = still_mounted;
still_mounted = 0; still_mounted = 0;
lxc_list_for_each(iterator, &mountlist) { lxc_list_for_each_safe(iterator, &mountlist, next) {
/* umount normally */ /* umount normally */
if (!umount(iterator->elem)) { if (!umount(iterator->elem)) {
@ -843,6 +878,114 @@ static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir)
return 0; return 0;
} }
/*
* Do we want to add options for max size of /dev and a file to
* specify which devices to create?
*/
static int mount_autodev(char *root)
{
int ret;
char path[MAXPATHLEN];
INFO("Mounting /dev under %s\n", root);
ret = snprintf(path, MAXPATHLEN, "%s/dev", root);
if (ret < 0 || ret > MAXPATHLEN)
return -1;
ret = mount("none", path, "tmpfs", 0, "size=100000");
if (ret) {
SYSERROR("Failed to mount /dev at %s\n", root);
return -1;
}
ret = snprintf(path, MAXPATHLEN, "%s/dev/pts", root);
if (ret < 0 || ret >= MAXPATHLEN)
return -1;
ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
if (ret) {
SYSERROR("Failed to create /dev/pts in container");
return -1;
}
INFO("Mounted /dev under %s\n", root);
return 0;
}
/*
* Try to run MAKEDEV console in the container. If something fails,
* continue anyway as it should not be detrimental to the container.
* This makes sure that things like /dev/vcs* exist.
* (Pass devpath in to reduce stack usage)
*/
static void run_makedev(char *devpath)
{
int curd;
int ret;
curd = open(".", O_RDONLY);
if (curd < 0)
return;
ret = chdir(devpath);
if (ret) {
close(curd);
return;
}
if (run_buffer("/sbin/MAKEDEV console"))
INFO("Error running MAKEDEV console in %s", devpath);
ret = fchdir(curd);
if (ret)
INFO("Error returning to original directory: expect breakage");
close(curd);
}
struct lxc_devs {
char *name;
mode_t mode;
int maj;
int min;
};
struct lxc_devs lxc_devs[] = {
{ "null", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 3 },
{ "zero", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 5 },
{ "full", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 7 },
{ "urandom", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 9 },
{ "random", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 8 },
{ "tty", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 5, 0 },
{ "console", S_IFCHR | S_IRUSR | S_IWUSR, 5, 1 },
};
static int setup_autodev(char *root)
{
int ret;
struct lxc_devs *d;
char path[MAXPATHLEN];
int i;
INFO("Creating initial consoles under %s/dev\n", root);
ret = snprintf(path, MAXPATHLEN, "%s/dev", root);
if (ret < 0 || ret >= MAXPATHLEN) {
ERROR("Error calculating container /dev location");
return -1;
} else
run_makedev(path);
INFO("Populating /dev under %s\n", root);
for (i = 0; i < sizeof(lxc_devs) / sizeof(lxc_devs[0]); i++) {
d = &lxc_devs[i];
ret = snprintf(path, MAXPATHLEN, "%s/dev/%s", root, d->name);
if (ret < 0 || ret >= MAXPATHLEN)
return -1;
ret = mknod(path, d->mode, makedev(d->maj, d->min));
if (ret && errno != EEXIST) {
SYSERROR("Error creating %s\n", d->name);
return -1;
}
}
INFO("Populated /dev under %s\n", root);
return 0;
}
static int setup_rootfs(const struct lxc_rootfs *rootfs) static int setup_rootfs(const struct lxc_rootfs *rootfs)
{ {
if (!rootfs->path) if (!rootfs->path)
@ -1061,6 +1204,8 @@ static int setup_kmsg(const struct lxc_rootfs *rootfs,
char kpath[MAXPATHLEN]; char kpath[MAXPATHLEN];
int ret; int ret;
if (!rootfs->path)
return 0;
ret = snprintf(kpath, sizeof(kpath), "%s/dev/kmsg", rootfs->mount); ret = snprintf(kpath, sizeof(kpath), "%s/dev/kmsg", rootfs->mount);
if (ret < 0 || ret >= sizeof(kpath)) if (ret < 0 || ret >= sizeof(kpath))
return -1; return -1;
@ -1228,8 +1373,8 @@ static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
} }
/* if rootfs->path is a blockdev path, allow container fstab to /* if rootfs->path is a blockdev path, allow container fstab to
* use /var/lib/lxc/CN/rootfs as the target prefix */ * use $LXCPATH/CN/rootfs as the target prefix */
r = snprintf(path, MAXPATHLEN, "/var/lib/lxc/%s/rootfs", lxc_name); r = snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", lxc_name);
if (r < 0 || r >= MAXPATHLEN) if (r < 0 || r >= MAXPATHLEN)
goto skipvarlib; goto skipvarlib;
@ -1647,7 +1792,7 @@ static int setup_netdev(struct lxc_netdev *netdev)
ifname, strerror(-err)); ifname, strerror(-err));
if (netdev->ipv6_gateway_auto) { if (netdev->ipv6_gateway_auto) {
char buf[INET6_ADDRSTRLEN]; char buf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET, netdev->ipv6_gateway, buf, sizeof(buf)); inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
ERROR("tried to set autodetected ipv6 gateway '%s'", buf); ERROR("tried to set autodetected ipv6 gateway '%s'", buf);
} }
return -1; return -1;
@ -1680,6 +1825,21 @@ static int setup_network(struct lxc_list *network)
return 0; return 0;
} }
void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf)
{
int i;
INFO("running to reset %d nic names", conf->num_savednics);
for (i=0; i<conf->num_savednics; i++) {
struct saved_nic *s = &conf->saved_nics[i];
INFO("resetting nic %d to %s\n", s->ifindex, s->orig_name);
lxc_netdev_rename_by_index(s->ifindex, s->orig_name);
free(s->orig_name);
}
conf->num_savednics = 0;
free(conf->saved_nics);
}
static int setup_private_host_hw_addr(char *veth1) static int setup_private_host_hw_addr(char *veth1)
{ {
struct ifreq ifr; struct ifreq ifr;
@ -1715,6 +1875,8 @@ static int setup_private_host_hw_addr(char *veth1)
return 0; return 0;
} }
static char *default_rootfs_mount = LXCROOTFSMOUNT;
struct lxc_conf *lxc_conf_init(void) struct lxc_conf *lxc_conf_init(void)
{ {
struct lxc_conf *new; struct lxc_conf *new;
@ -1733,7 +1895,8 @@ struct lxc_conf *lxc_conf_init(void)
new->console.master = -1; new->console.master = -1;
new->console.slave = -1; new->console.slave = -1;
new->console.name[0] = '\0'; new->console.name[0] = '\0';
new->rootfs.mount = LXCROOTFSMOUNT; new->rootfs.mount = default_rootfs_mount;
new->loglevel = LXC_LOG_PRIORITY_NOTSET;
lxc_list_init(&new->cgroup); lxc_list_init(&new->cgroup);
lxc_list_init(&new->network); lxc_list_init(&new->network);
lxc_list_init(&new->mount_list); lxc_list_init(&new->mount_list);
@ -1765,6 +1928,8 @@ static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
return -1; return -1;
} }
veth1 = mktemp(veth1buf); veth1 = mktemp(veth1buf);
/* store away for deconf */
memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
} }
snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX"); snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
@ -1841,6 +2006,25 @@ out_delete:
return -1; return -1;
} }
static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
char *veth1;
int err;
if (netdev->priv.veth_attr.pair)
veth1 = netdev->priv.veth_attr.pair;
else
veth1 = netdev->priv.veth_attr.veth1;
if (netdev->downscript) {
err = run_script(handler->name, "net", netdev->downscript,
"down", "veth", veth1, (char*) NULL);
if (err)
return -1;
}
return 0;
}
static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev) static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{ {
char peerbuf[IFNAMSIZ], *peer; char peerbuf[IFNAMSIZ], *peer;
@ -1889,6 +2073,20 @@ static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n
return 0; return 0;
} }
static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
int err;
if (netdev->downscript) {
err = run_script(handler->name, "net", netdev->downscript,
"down", "macvlan", netdev->link,
(char*) NULL);
if (err)
return -1;
}
return 0;
}
/* XXX: merge with instanciate_macvlan */ /* XXX: merge with instanciate_macvlan */
static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev) static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{ {
@ -1926,6 +2124,11 @@ static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd
return 0; return 0;
} }
static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
return 0;
}
static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev) static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
{ {
if (!netdev->link) { if (!netdev->link) {
@ -1950,6 +2153,19 @@ static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netd
return 0; return 0;
} }
static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
int err;
if (netdev->downscript) {
err = run_script(handler->name, "net", netdev->downscript,
"down", "phys", netdev->link, (char*) NULL);
if (err)
return -1;
}
return 0;
}
static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev) static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
{ {
netdev->ifindex = 0; netdev->ifindex = 0;
@ -1963,6 +2179,19 @@ static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *net
return 0; return 0;
} }
static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
int err;
if (netdev->downscript) {
err = run_script(handler->name, "net", netdev->downscript,
"down", "empty", (char*) NULL);
if (err)
return -1;
}
return 0;
}
int lxc_create_network(struct lxc_handler *handler) int lxc_create_network(struct lxc_handler *handler)
{ {
struct lxc_list *network = &handler->conf->network; struct lxc_list *network = &handler->conf->network;
@ -1989,28 +2218,32 @@ int lxc_create_network(struct lxc_handler *handler)
return 0; return 0;
} }
void lxc_delete_network(struct lxc_list *network) void lxc_delete_network(struct lxc_handler *handler)
{ {
struct lxc_list *network = &handler->conf->network;
struct lxc_list *iterator; struct lxc_list *iterator;
struct lxc_netdev *netdev; struct lxc_netdev *netdev;
lxc_list_for_each(iterator, network) { lxc_list_for_each(iterator, network) {
netdev = iterator->elem; netdev = iterator->elem;
if (netdev->ifindex == 0)
continue;
if (netdev->type == LXC_NET_PHYS) { if (netdev->ifindex != 0 && netdev->type == LXC_NET_PHYS) {
if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link)) if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link))
WARN("failed to rename to the initial name the " \ WARN("failed to rename to the initial name the " \
"netdev '%s'", netdev->link); "netdev '%s'", netdev->link);
continue; continue;
} }
if (netdev_deconf[netdev->type](handler, netdev)) {
WARN("failed to destroy netdev");
}
/* Recent kernel remove the virtual interfaces when the network /* Recent kernel remove the virtual interfaces when the network
* namespace is destroyed but in case we did not moved the * namespace is destroyed but in case we did not moved the
* interface to the network namespace, we have to destroy it * interface to the network namespace, we have to destroy it
*/ */
if (lxc_netdev_delete_by_index(netdev->ifindex)) if (netdev->ifindex != 0 &&
lxc_netdev_delete_by_index(netdev->ifindex))
WARN("failed to remove interface '%s'", netdev->name); WARN("failed to remove interface '%s'", netdev->name);
} }
} }
@ -2166,11 +2399,23 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
return -1; return -1;
} }
if (run_lxc_hooks(name, "pre-mount", lxc_conf)) {
ERROR("failed to run pre-mount hooks for container '%s'.", name);
return -1;
}
if (setup_rootfs(&lxc_conf->rootfs)) { if (setup_rootfs(&lxc_conf->rootfs)) {
ERROR("failed to setup rootfs for '%s'", name); ERROR("failed to setup rootfs for '%s'", name);
return -1; return -1;
} }
if (lxc_conf->autodev) {
if (mount_autodev(lxc_conf->rootfs.mount)) {
ERROR("failed to mount /dev in the container");
return -1;
}
}
if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name)) { if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name)) {
ERROR("failed to setup the mounts for '%s'", name); ERROR("failed to setup the mounts for '%s'", name);
return -1; return -1;
@ -2186,6 +2431,13 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
return -1; return -1;
} }
if (lxc_conf->autodev) {
if (setup_autodev(lxc_conf->rootfs.mount)) {
ERROR("failed to populate /dev in the container");
return -1;
}
}
if (setup_cgroup(name, &lxc_conf->cgroup)) { if (setup_cgroup(name, &lxc_conf->cgroup)) {
ERROR("failed to setup the cgroups for '%s'", name); ERROR("failed to setup the cgroups for '%s'", name);
return -1; return -1;
@ -2196,10 +2448,8 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
return -1; return -1;
} }
if (setup_kmsg(&lxc_conf->rootfs, &lxc_conf->console)) { if (setup_kmsg(&lxc_conf->rootfs, &lxc_conf->console)) // don't fail
ERROR("failed to setup kmsg for '%s'", name); ERROR("failed to setup kmsg for '%s'", name);
return -1;
}
if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) { if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) {
ERROR("failed to setup the ttys for '%s'", name); ERROR("failed to setup the ttys for '%s'", name);
@ -2253,6 +2503,8 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
if (strcmp(hook, "pre-start") == 0) if (strcmp(hook, "pre-start") == 0)
which = LXCHOOK_PRESTART; which = LXCHOOK_PRESTART;
else if (strcmp(hook, "pre-mount") == 0)
which = LXCHOOK_PREMOUNT;
else if (strcmp(hook, "mount") == 0) else if (strcmp(hook, "mount") == 0)
which = LXCHOOK_MOUNT; which = LXCHOOK_MOUNT;
else if (strcmp(hook, "start") == 0) else if (strcmp(hook, "start") == 0)
@ -2270,3 +2522,253 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
} }
return 0; return 0;
} }
static void lxc_remove_nic(struct lxc_list *it)
{
struct lxc_netdev *netdev = it->elem;
struct lxc_list *it2,*next;
lxc_list_del(it);
if (netdev->link)
free(netdev->link);
if (netdev->name)
free(netdev->name);
if (netdev->upscript)
free(netdev->upscript);
if (netdev->hwaddr)
free(netdev->hwaddr);
if (netdev->mtu)
free(netdev->mtu);
if (netdev->ipv4_gateway)
free(netdev->ipv4_gateway);
if (netdev->ipv6_gateway)
free(netdev->ipv6_gateway);
lxc_list_for_each_safe(it2, &netdev->ipv4, next) {
lxc_list_del(it2);
free(it2->elem);
free(it2);
}
lxc_list_for_each_safe(it2, &netdev->ipv6, next) {
lxc_list_del(it2);
free(it2->elem);
free(it2);
}
free(netdev);
free(it);
}
/* we get passed in something like '0', '0.ipv4' or '1.ipv6' */
int lxc_clear_nic(struct lxc_conf *c, const char *key)
{
char *p1;
int ret, idx, i;
struct lxc_list *it;
struct lxc_netdev *netdev;
p1 = index(key, '.');
if (!p1 || *(p1+1) == '\0')
p1 = NULL;
ret = sscanf(key, "%d", &idx);
if (ret != 1) return -1;
if (idx < 0)
return -1;
i = 0;
lxc_list_for_each(it, &c->network) {
if (i == idx)
break;
i++;
}
if (i < idx) // we don't have that many nics defined
return -1;
if (!it || !it->elem)
return -1;
netdev = it->elem;
if (!p1) {
lxc_remove_nic(it);
} else if (strcmp(p1, "ipv4") == 0) {
struct lxc_list *it2,*next;
lxc_list_for_each_safe(it2, &netdev->ipv4, next) {
lxc_list_del(it2);
free(it2->elem);
free(it2);
}
} else if (strcmp(p1, "ipv6") == 0) {
struct lxc_list *it2,*next;
lxc_list_for_each_safe(it2, &netdev->ipv6, next) {
lxc_list_del(it2);
free(it2->elem);
free(it2);
}
} else if (strcmp(p1, "link") == 0) {
if (netdev->link) {
free(netdev->link);
netdev->link = NULL;
}
} else if (strcmp(p1, "name") == 0) {
if (netdev->name) {
free(netdev->name);
netdev->name = NULL;
}
} else if (strcmp(p1, "script.up") == 0) {
if (netdev->upscript) {
free(netdev->upscript);
netdev->upscript = NULL;
}
} else if (strcmp(p1, "hwaddr") == 0) {
if (netdev->hwaddr) {
free(netdev->hwaddr);
netdev->hwaddr = NULL;
}
} else if (strcmp(p1, "mtu") == 0) {
if (netdev->mtu) {
free(netdev->mtu);
netdev->mtu = NULL;
}
} else if (strcmp(p1, "ipv4_gateway") == 0) {
if (netdev->ipv4_gateway) {
free(netdev->ipv4_gateway);
netdev->ipv4_gateway = NULL;
}
} else if (strcmp(p1, "ipv6_gateway") == 0) {
if (netdev->ipv6_gateway) {
free(netdev->ipv6_gateway);
netdev->ipv6_gateway = NULL;
}
}
else return -1;
return 0;
}
int lxc_clear_config_network(struct lxc_conf *c)
{
struct lxc_list *it,*next;
lxc_list_for_each_safe(it, &c->network, next) {
lxc_remove_nic(it);
}
return 0;
}
int lxc_clear_config_caps(struct lxc_conf *c)
{
struct lxc_list *it,*next;
lxc_list_for_each_safe(it, &c->caps, 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;
bool all = false;
const char *k = key + 11;
if (strcmp(key, "lxc.cgroup") == 0)
all = true;
lxc_list_for_each_safe(it, &c->cgroup, next) {
struct lxc_cgroup *cg = it->elem;
if (!all && strcmp(cg->subsystem, k) != 0)
continue;
lxc_list_del(it);
free(cg->subsystem);
free(cg->value);
free(cg);
free(it);
}
return 0;
}
int lxc_clear_mount_entries(struct lxc_conf *c)
{
struct lxc_list *it,*next;
lxc_list_for_each_safe(it, &c->mount_list, next) {
lxc_list_del(it);
free(it->elem);
free(it);
}
return 0;
}
int lxc_clear_hooks(struct lxc_conf *c, const char *key)
{
struct lxc_list *it,*next;
bool all = false, done = false;
const char *k = key + 9;
int i;
if (strcmp(key, "lxc.hook") == 0)
all = true;
for (i=0; i<NUM_LXC_HOOKS; i++) {
if (all || strcmp(k, lxchook_names[i]) == 0) {
lxc_list_for_each_safe(it, &c->hooks[i], next) {
lxc_list_del(it);
free(it->elem);
free(it);
}
done = true;
}
}
if (!done) {
ERROR("Invalid hook key: %s", key);
return -1;
}
return 0;
}
void lxc_clear_saved_nics(struct lxc_conf *conf)
{
int i;
if (!conf->num_savednics)
return;
for (i=0; i < conf->num_savednics; i++)
free(conf->saved_nics[i].orig_name);
conf->saved_nics = 0;
free(conf->saved_nics);
}
void lxc_conf_free(struct lxc_conf *conf)
{
if (!conf)
return;
if (conf->console.path)
free(conf->console.path);
if (conf->rootfs.mount != default_rootfs_mount)
free(conf->rootfs.mount);
if (conf->rootfs.path)
free(conf->rootfs.path);
if (conf->utsname)
free(conf->utsname);
if (conf->ttydir)
free(conf->ttydir);
if (conf->fstab)
free(conf->fstab);
if (conf->logfile)
free(conf->logfile);
lxc_clear_config_network(conf);
#if HAVE_APPARMOR
if (conf->aa_profile)
free(conf->aa_profile);
#endif
lxc_seccomp_free(conf);
lxc_clear_config_caps(conf);
lxc_clear_cgroups(conf, "lxc.cgroup");
lxc_clear_hooks(conf, "lxc.hook");
lxc_clear_mount_entries(conf);
lxc_clear_saved_nics(conf);
free(conf);
}

View File

@ -24,6 +24,7 @@
#define _conf_h #define _conf_h
#include <netinet/in.h> #include <netinet/in.h>
#include <net/if.h>
#include <sys/param.h> #include <sys/param.h>
#include <stdbool.h> #include <stdbool.h>
@ -31,6 +32,10 @@
#include <lxc/start.h> /* for lxc_handler */ #include <lxc/start.h> /* for lxc_handler */
#if HAVE_SCMP_FILTER_CTX
typedef void * scmp_filter_ctx;
#endif
enum { enum {
LXC_NET_EMPTY, LXC_NET_EMPTY,
LXC_NET_VETH, LXC_NET_VETH,
@ -76,6 +81,7 @@ struct lxc_route6 {
struct ifla_veth { struct ifla_veth {
char *pair; /* pair name */ char *pair; /* pair name */
char veth1[IFNAMSIZ]; /* needed for deconf */
}; };
struct ifla_vlan { struct ifla_vlan {
@ -103,6 +109,7 @@ union netdev_p {
* @ipv4 : a list of ipv4 addresses to be set on the network device * @ipv4 : a list of ipv4 addresses to be set on the network device
* @ipv6 : a list of ipv6 addresses to be set on the network device * @ipv6 : a list of ipv6 addresses to be set on the network device
* @upscript : a script filename to be executed during interface configuration * @upscript : a script filename to be executed during interface configuration
* @downscript : a script filename to be executed during interface destruction
*/ */
struct lxc_netdev { struct lxc_netdev {
int type; int type;
@ -120,6 +127,7 @@ struct lxc_netdev {
struct in6_addr *ipv6_gateway; struct in6_addr *ipv6_gateway;
bool ipv6_gateway_auto; bool ipv6_gateway_auto;
char *upscript; char *upscript;
char *downscript;
}; };
/* /*
@ -203,8 +211,15 @@ struct lxc_rootfs {
#endif #endif
*/ */
enum lxchooks { enum lxchooks {
LXCHOOK_PRESTART, LXCHOOK_MOUNT, LXCHOOK_START, LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_START,
LXCHOOK_POSTSTOP, NUM_LXC_HOOKS}; LXCHOOK_POSTSTOP, NUM_LXC_HOOKS};
extern char *lxchook_names[NUM_LXC_HOOKS];
struct saved_nic {
int ifindex;
char *orig_name;
};
struct lxc_conf { struct lxc_conf {
char *fstab; char *fstab;
int tty; int tty;
@ -215,6 +230,8 @@ struct lxc_conf {
struct utsname *utsname; struct utsname *utsname;
struct lxc_list cgroup; struct lxc_list cgroup;
struct lxc_list network; struct lxc_list network;
struct saved_nic *saved_nics;
int num_savednics;
struct lxc_list mount_list; struct lxc_list mount_list;
struct lxc_list caps; struct lxc_list caps;
struct lxc_tty_info tty_info; struct lxc_tty_info tty_info;
@ -226,9 +243,18 @@ struct lxc_conf {
#if HAVE_APPARMOR #if HAVE_APPARMOR
char *aa_profile; char *aa_profile;
#endif #endif
char *logfile;
int loglevel;
#if HAVE_APPARMOR /* || HAVE_SELINUX || HAVE_SMACK */ #if HAVE_APPARMOR /* || HAVE_SELINUX || HAVE_SMACK */
int lsm_umount_proc; int lsm_umount_proc;
#endif #endif
char *seccomp; // filename with the seccomp rules
#if HAVE_SCMP_FILTER_CTX
scmp_filter_ctx *seccomp_ctx;
#endif
int maincmd_fd;
int autodev; // if 1, mount and fill a /dev at start
}; };
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);
@ -237,20 +263,30 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
* Initialize the lxc configuration structure * Initialize the lxc configuration structure
*/ */
extern struct lxc_conf *lxc_conf_init(void); extern struct lxc_conf *lxc_conf_init(void);
extern void lxc_conf_free(struct lxc_conf *conf);
extern int pin_rootfs(const char *rootfs); extern int pin_rootfs(const char *rootfs);
extern int lxc_create_network(struct lxc_handler *handler); extern int lxc_create_network(struct lxc_handler *handler);
extern void lxc_delete_network(struct lxc_list *networks); extern void lxc_delete_network(struct lxc_handler *handler);
extern int lxc_assign_network(struct lxc_list *networks, pid_t pid); extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
extern int lxc_find_gateway_addresses(struct lxc_handler *handler); extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
extern int lxc_create_tty(const char *name, struct lxc_conf *conf); extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
extern void lxc_delete_tty(struct lxc_tty_info *tty_info); 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_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);
/* /*
* Configure the container from inside * 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);
extern void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,15 @@
struct lxc_conf; struct lxc_conf;
struct lxc_list; struct lxc_list;
typedef int (*config_cb)(const char *, const char *, struct lxc_conf *);
struct lxc_config_t {
char *name;
config_cb cb;
};
extern struct lxc_config_t *lxc_getconfig(const char *key);
extern int lxc_list_nicconfigs(struct lxc_conf *c, const char *key, char *retv, int inlen);
extern int lxc_listconfigs(char *retv, int inlen);
extern int lxc_config_read(const char *file, struct lxc_conf *conf); extern int lxc_config_read(const char *file, struct lxc_conf *conf);
extern int lxc_config_readline(char *buffer, struct lxc_conf *conf); extern int lxc_config_readline(char *buffer, struct lxc_conf *conf);
@ -37,4 +46,7 @@ extern int lxc_config_define_load(struct lxc_list *defines,
/* needed for lxc-attach */ /* needed for lxc-attach */
extern signed long lxc_config_parse_arch(const char *arch); extern signed long lxc_config_parse_arch(const char *arch);
extern int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv, int inlen);
extern int lxc_clear_config_item(struct lxc_conf *c, const char *key);
extern void write_config(FILE *fout, struct lxc_conf *c);
#endif #endif

View File

@ -27,7 +27,6 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include "log.h" #include "log.h"
#include "start.h" #include "start.h"

View File

@ -62,7 +62,7 @@ static int genetlink_resolve_family(const char *family)
if (ret) if (ret)
return ret; return ret;
ret = nla_put_string((struct nlmsg *)&request->nlmsghdr, ret = nla_put_string((struct nlmsg *)&request->nlmsghdr,
CTRL_ATTR_FAMILY_NAME, family); CTRL_ATTR_FAMILY_NAME, family);
if (ret) if (ret)
goto out; goto out;
@ -130,7 +130,7 @@ extern int genetlink_send(struct genl_handler *handler, struct genlmsg *genlmsg)
return netlink_send(&handler->nlh, (struct nlmsg *)&genlmsg->nlmsghdr); return netlink_send(&handler->nlh, (struct nlmsg *)&genlmsg->nlmsghdr);
} }
extern int genetlink_transaction(struct genl_handler *handler, extern int genetlink_transaction(struct genl_handler *handler,
struct genlmsg *request, struct genlmsg *answer) struct genlmsg *request, struct genlmsg *answer)
{ {
return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr, return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr,

View File

@ -30,7 +30,7 @@
#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN)) #define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
/* /*
* struct genl_handler : the structure which store the netlink handler * struct genl_handler : the structure which store the netlink handler
* and the family number resulting of the auto-generating id family * and the family number resulting of the auto-generating id family
* for the generic netlink protocol * for the generic netlink protocol
* *
@ -116,6 +116,6 @@ void genlmsg_free(struct genlmsg *genlmsg);
* *
* Returns 0 on success, < 0 otherwise * Returns 0 on success, < 0 otherwise
*/ */
int genetlink_transaction(struct genl_handler *handler, int genetlink_transaction(struct genl_handler *handler,
struct genlmsg *request, struct genlmsg *answer); struct genlmsg *request, struct genlmsg *answer);
#endif #endif

View File

@ -75,7 +75,7 @@ directory=$(readlink -f "$lxc_path")
for i in "$@"; do for i in "$@"; do
case $i in case $i in
--help) --help)
help; exit 1;; help; exit;;
--active) --active)
get_parent_cgroup; directory="$parent_cgroup"; shift;; get_parent_cgroup; directory="$parent_cgroup"; shift;;
--) --)
@ -90,10 +90,5 @@ if [ ! -z "$directory" ]; then
containers=$(find $directory -mindepth 1 -maxdepth 1 -type d -printf "%f\n" 2>/dev/null) containers=$(find $directory -mindepth 1 -maxdepth 1 -type d -printf "%f\n" 2>/dev/null)
fi fi
if [ -z "$containers" ]; then
echo "$(basename $0): no containers found" >&2
exit 1
fi
cd "$directory" cd "$directory"
ls -d $@ -- $containers ls -d $@ -- $containers

View File

@ -14,6 +14,11 @@ struct lxc_list {
__iterator != __list; \ __iterator != __list; \
__iterator = __iterator->next) __iterator = __iterator->next)
#define lxc_list_for_each_safe(__iterator, __list, __next) \
for (__iterator = (__list)->next, __next = __iterator->next; \
__iterator != __list; \
__iterator = __next, __next = __next->next)
static inline void lxc_list_init(struct lxc_list *list) static inline void lxc_list_init(struct lxc_list *list)
{ {
list->elem = NULL; list->elem = NULL;

View File

@ -41,6 +41,7 @@
int lxc_log_fd = -1; int lxc_log_fd = -1;
static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc"; static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
int lxc_loglevel_specified = 0;
lxc_log_define(lxc_log, lxc); lxc_log_define(lxc_log, lxc);
@ -153,7 +154,11 @@ extern int lxc_log_init(const char *file, const char *priority,
{ {
int lxc_priority = LXC_LOG_PRIORITY_ERROR; int lxc_priority = LXC_LOG_PRIORITY_ERROR;
if (lxc_log_fd != -1)
return 0;
if (priority) { if (priority) {
lxc_loglevel_specified = 1;
lxc_priority = lxc_log_priority_to_int(priority); lxc_priority = lxc_log_priority_to_int(priority);
if (lxc_priority == LXC_LOG_PRIORITY_NOTSET) { if (lxc_priority == LXC_LOG_PRIORITY_NOTSET) {
@ -185,3 +190,39 @@ extern int lxc_log_init(const char *file, const char *priority,
return 0; return 0;
} }
/*
* This is called when we read a lxc.loglevel entry in a lxc.conf file. This
* happens after processing command line arguments, which override the .conf
* settings. So only set the level if previously unset.
*/
extern int lxc_log_set_level(int level)
{
if (lxc_loglevel_specified)
return 0;
if (level < 0 || level >= LXC_LOG_PRIORITY_NOTSET) {
ERROR("invalid log priority %d", level);
return -1;
}
lxc_log_category_lxc.priority = level;
return 0;
}
/*
* 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 logfile if previously unset.
*/
extern int lxc_log_set_file(char *fname)
{
if (lxc_log_fd != -1) {
INFO("Configuration file was specified on command line, configuration file entry being ignored");
return 0;
}
lxc_log_fd = log_open(fname);
if (lxc_log_fd == -1) {
ERROR("failed to open log file %s\n", fname);
return -1;
}
return 0;
}

View File

@ -41,7 +41,7 @@
#define LXC_LOG_BUFFER_SIZE 512 #define LXC_LOG_BUFFER_SIZE 512
/* predefined priorities. */ /* predefined priorities. */
enum { enum lxc_loglevel {
LXC_LOG_PRIORITY_TRACE, LXC_LOG_PRIORITY_TRACE,
LXC_LOG_PRIORITY_DEBUG, LXC_LOG_PRIORITY_DEBUG,
LXC_LOG_PRIORITY_INFO, LXC_LOG_PRIORITY_INFO,
@ -291,4 +291,6 @@ extern int lxc_log_init(const char *file, const char *priority,
const char *prefix, int quiet); const char *prefix, int quiet);
extern void lxc_log_setprefix(const char *a_prefix); extern void lxc_log_setprefix(const char *a_prefix);
extern int lxc_log_set_level(int level);
extern int lxc_log_set_file(char *fname);
#endif #endif

View File

@ -1,13 +1,13 @@
#!/bin/bash #!/bin/sh
# Allow environment variables to override grep and config # Allow environment variables to override grep and config
: ${CONFIG:=/proc/config.gz} : ${CONFIG:=/proc/config.gz}
: ${GREP:=zgrep} : ${GREP:=zgrep}
SETCOLOR_SUCCESS="echo -en \\033[1;32m" SETCOLOR_SUCCESS="printf \\e[1;32m"
SETCOLOR_FAILURE="echo -en \\033[1;31m" SETCOLOR_FAILURE="printf \\e[1;31m"
SETCOLOR_WARNING="echo -en \\033[1;33m" SETCOLOR_WARNING="printf \\e[1;33m"
SETCOLOR_NORMAL="echo -en \\033[0;39m" SETCOLOR_NORMAL="printf \\e[0;39m"
is_set() { is_set() {
$GREP -q "$1=[y|m]" $CONFIG $GREP -q "$1=[y|m]" $CONFIG
@ -21,13 +21,13 @@ is_enabled() {
RES=$? RES=$?
if [ $RES -eq 0 ]; then if [ $RES -eq 0 ]; then
$SETCOLOR_SUCCESS && echo -e "enabled" && $SETCOLOR_NORMAL $SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
else else
if [ ! -z "$mandatory" -a "$mandatory" = yes ]; then if [ ! -z "$mandatory" -a "$mandatory" = yes ]; then
$SETCOLOR_FAILURE && echo -e "required" && $SETCOLOR_NORMAL $SETCOLOR_FAILURE && echo "required" && $SETCOLOR_NORMAL
else else
$SETCOLOR_WARNING && echo -e "missing" && $SETCOLOR_NORMAL $SETCOLOR_WARNING && echo "missing" && $SETCOLOR_NORMAL
fi fi
fi fi
} }
@ -68,40 +68,45 @@ print_cgroups() {
} }
CGROUP_MNT_PATH=`print_cgroups cgroup /proc/self/mounts | head -1` CGROUP_MNT_PATH=`print_cgroups cgroup /proc/self/mounts | head -1`
echo -n "Cgroup: " && is_enabled CONFIG_CGROUPS yes
if [ -f $CGROUP_MNT_PATH/cgroup.clone_children ]; then
echo -n "Cgroup clone_children flag: " &&
$SETCOLOR_SUCCESS && echo -e "enabled" && $SETCOLOR_NORMAL
else
echo -n "Cgroup namespace: " && is_enabled CONFIG_CGROUP_NS yes
fi
echo -n "Cgroup device: " && is_enabled CONFIG_CGROUP_DEVICE
echo -n "Cgroup sched: " && is_enabled CONFIG_CGROUP_SCHED
echo -n "Cgroup cpu account: " && is_enabled CONFIG_CGROUP_CPUACCT
echo -n "Cgroup memory controller: " && is_enabled CONFIG_CGROUP_MEM_RES_CTLR
is_set CONFIG_SMP && echo -n "Cgroup cpuset: " && is_enabled CONFIG_CPUSETS
echo
echo "--- Misc ---"
echo -n "Veth pair device: " && is_enabled CONFIG_VETH
echo -n "Macvlan: " && is_enabled CONFIG_MACVLAN
echo -n "Vlan: " && is_enabled CONFIG_VLAN_8021Q
KVER_MAJOR=$($GREP '^# Linux' $CONFIG | \ KVER_MAJOR=$($GREP '^# Linux' $CONFIG | \
sed -r 's/.* ([0-9])\.[0-9]{1,2}\.[0-9]{1,3}.*/\1/') sed -r 's/.* ([0-9])\.[0-9]{1,2}\.[0-9]{1,3}.*/\1/')
if [[ $KVER_MAJOR == 2 ]]; then if [ "$KVER_MAJOR" = "2" ]; then
KVER_MINOR=$($GREP '^# Linux' $CONFIG | \ KVER_MINOR=$($GREP '^# Linux' $CONFIG | \
sed -r 's/.* 2.6.([0-9]{2}).*/\1/') sed -r 's/.* 2.6.([0-9]{2}).*/\1/')
else else
KVER_MINOR=$($GREP '^# Linux' $CONFIG | \ KVER_MINOR=$($GREP '^# Linux' $CONFIG | \
sed -r 's/.* [0-9]\.([0-9]{1,3})\.[0-9]{1,3}.*/\1/') sed -r 's/.* [0-9]\.([0-9]{1,3})\.[0-9]{1,3}.*/\1/')
fi fi
echo -n "File capabilities: " &&
( [[ ${KVER_MAJOR} == 2 && ${KVER_MINOR} < 33 ]] && echo -n "Cgroup: " && is_enabled CONFIG_CGROUPS yes
is_enabled CONFIG_SECURITY_FILE_CAPABILITIES ) ||
( [[ ( ${KVER_MAJOR} == 2 && ${KVER_MINOR} > 32 ) || if [ -f $CGROUP_MNT_PATH/cgroup.clone_children ]; then
${KVER_MAJOR} > 2 ]] && $SETCOLOR_SUCCESS && echo -n "Cgroup clone_children flag: " &&
echo -e "enabled" && $SETCOLOR_NORMAL ) $SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
else
echo -n "Cgroup namespace: " && is_enabled CONFIG_CGROUP_NS yes
fi
echo -n "Cgroup device: " && is_enabled CONFIG_CGROUP_DEVICE
echo -n "Cgroup sched: " && is_enabled CONFIG_CGROUP_SCHED
echo -n "Cgroup cpu account: " && is_enabled CONFIG_CGROUP_CPUACCT
echo -n "Cgroup memory controller: "
if [ $KVER_MAJOR -ge 3 -a $KVER_MINOR -ge 6 ]; then
is_enabled CONFIG_MEMCG
else
is_enabled CONFIG_CGROUP_MEM_RES_CTLR
fi
is_set CONFIG_SMP && echo -n "Cgroup cpuset: " && is_enabled CONFIG_CPUSETS
echo
echo "--- Misc ---"
echo -n "Veth pair device: " && is_enabled CONFIG_VETH
echo -n "Macvlan: " && is_enabled CONFIG_MACVLAN
echo -n "Vlan: " && is_enabled CONFIG_VLAN_8021Q
echo -n "File capabilities: " && \
( [ "${KVER_MAJOR}" = 2 ] && [ ${KVER_MINOR} -lt 33 ] && \
is_enabled CONFIG_SECURITY_FILE_CAPABILITIES ) || \
( ( [ "${KVER_MAJOR}" = "2" ] && [ ${KVER_MINOR} -gt 32 ] ) || \
[ ${KVER_MAJOR} -gt 2 ] && $SETCOLOR_SUCCESS && \
echo "enabled" && $SETCOLOR_NORMAL )
echo echo
echo "Note : Before booting a new kernel, you can check its configuration" echo "Note : Before booting a new kernel, you can check its configuration"

View File

@ -225,7 +225,7 @@ if [ -b $oldroot ]; then
mkfs -t $fstype /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new 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; } mount /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new $rootfs || { echo "$(basename $0): failed to mount new rootfs" >&2; false; }
mounted=1 mounted=1
rsync -ax ${rootfs}_snapshot/ ${rootfs}/ || { echo "$(basename $0): copying data to new lv failed" >&2; false; } rsync -Hax ${rootfs}_snapshot/ ${rootfs}/ || { echo "$(basename $0): copying data to new lv failed" >&2; false; }
umount ${rootfs}_snapshot umount ${rootfs}_snapshot
rmdir ${rootfs}_snapshot rmdir ${rootfs}_snapshot
lvremove -f $lxc_vg/${lxc_lv_prefix}${lxc_new}_snapshot lvremove -f $lxc_vg/${lxc_lv_prefix}${lxc_new}_snapshot
@ -252,7 +252,7 @@ else
frozen=1 frozen=1
fi fi
mkdir -p $rootfs/ mkdir -p $rootfs/
rsync -ax $oldroot/ $rootfs/ rsync -Hax $oldroot/ $rootfs/
echo "lxc.rootfs = $rootfs" >> $lxc_path/$lxc_new/config echo "lxc.rootfs = $rootfs" >> $lxc_path/$lxc_new/config
if [ $container_running = "True" ]; then if [ $container_running = "True" ]; then
lxc-unfreeze -n $lxc_orig lxc-unfreeze -n $lxc_orig
@ -272,11 +272,11 @@ c=$lxc_path/$lxc_new/config
mv ${c} ${c}.old mv ${c} ${c}.old
( (
while read line; do while read line; do
if [ "${line:0:18}" = "lxc.network.hwaddr" ]; then if [ "${line:0:18}" = "lxc.network.hwaddr" ]; then
echo "lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" echo "lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')"
else else
echo "$line" echo "$line"
fi fi
done done
) < ${c}.old > ${c} ) < ${c}.old > ${c}
rm -f ${c}.old rm -f ${c}.old

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/sh
# #
# lxc: linux Container library # lxc: linux Container library
@ -26,6 +26,7 @@ usage() {
echo >&2 echo >&2
echo "where FS_OPTIONS is one of:" >&2 echo "where FS_OPTIONS is one of:" >&2
echo " -B none" >&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 " -B lvm [--lvname LV_NAME] [--vgname VG_NAME] [--fstype FS_TYPE]" >&2
echo " [--fssize FS_SIZE]" >&2 echo " [--fssize FS_SIZE]" >&2
echo " -B btrfs" >&2 echo " -B btrfs" >&2
@ -43,25 +44,35 @@ help() {
echo " -B BACKING_STORE alter the container backing store (default: none)" >&2 echo " -B BACKING_STORE alter the container backing store (default: none)" >&2
echo " --lvname LV_NAME specify the LVM logical volume name" >&2 echo " --lvname LV_NAME specify the LVM logical volume name" >&2
echo " (default: container 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 " --vgname VG_NAME specify the LVM volume group name (default: lxc)" >&2
echo " --fstype FS_TYPE specify the filesystem type (default: ext4)" >&2 echo " --fstype FS_TYPE specify the filesystem type (default: ext4)" >&2
echo " --fssize FS_SIZE specify the filesystem size (default: 500M)" >&2 echo " --fssize FS_SIZE specify the filesystem size (default: 500M)" >&2
echo >&2 echo >&2
if [ -z $lxc_template ]; then if [ -z "$lxc_template" ]; then
echo "To see template-specific options, specify a template. For example:" >&2 echo "To see template-specific options, specify a template. For example:" >&2
echo " $(basename $0) -t ubuntu -h" >&2 echo " $(basename $0) -t ubuntu -h" >&2
exit 0 exit 0
fi fi
type ${templatedir}/lxc-$lxc_template 2>/dev/null if [ -x ${templatedir}/lxc-$lxc_template ]; then
if [ $? -eq 0 ]; then
echo >&2 echo >&2
echo "Template-specific options (TEMPLATE_OPTIONS):" >&2 echo "Template-specific options (TEMPLATE_OPTIONS):" >&2
${templatedir}/lxc-$lxc_template -h ${templatedir}/lxc-$lxc_template -h
fi fi
} }
shortoptions='hn:f:t:B:' usage_err() {
longoptions='help,name:,config:,template:,backingstore:,fstype:,lvname:,vgname:,fssize:' [ -n "$1" ] && echo "$1" >&2
usage
exit 1
}
optarg_check() {
if [ -z "$2" ]; then
usage_err "option '$1' requires an argument"
fi
}
lxc_path=@LXCPATH@ lxc_path=@LXCPATH@
bindir=@BINDIR@ bindir=@BINDIR@
templatedir=@LXCTEMPLATEDIR@ templatedir=@LXCTEMPLATEDIR@
@ -69,80 +80,85 @@ backingstore=_unset
fstype=ext4 fstype=ext4
fssize=500M fssize=500M
vgname=lxc vgname=lxc
custom_rootfs=""
getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@") while [ $# -gt 0 ]; do
if [ $? != 0 ]; then opt="$1"
usage shift
exit 1; case "$opt" in
fi -h|--help)
help
eval set -- "$getopt" exit 1
;;
while true; do -n|--name)
case "$1" in optarg_check $opt "$1"
-h|--help) lxc_name=$1
help shift
exit 1 ;;
;; -f|--config)
-n|--name) optarg_check $opt "$1"
shift lxc_config=$1
lxc_name=$1 shift
shift ;;
;; -t|--template)
-f|--config) optarg_check $opt "$1"
shift lxc_template=$1
lxc_config=$1 shift
shift ;;
;; -B|--backingstore)
-t|--template) optarg_check $opt "$1"
shift backingstore=$1
lxc_template=$1 shift
shift ;;
;; --dir)
-B|--backingstore) optarg_check $opt "$1"
shift custom_rootfs=$1
backingstore=$1 shift
shift ;;
;; --lvname)
--lvname) optarg_check $opt "$1"
shift lvname=$1
lvname=$1 shift
shift ;;
;; --vgname)
--vgname) optarg_check $opt "$1"
shift vgname=$1
vgname=$1 shift
shift ;;
;; --fstype)
--fstype) optarg_check $opt "$1"
shift fstype=$1
fstype=$1 shift
shift ;;
;; --fssize)
--fssize) optarg_check $opt "$1"
shift fssize=$1
fssize=$1 shift
shift ;;
;; --)
--) break;;
shift -?)
break;; usage_err "unknown option '$opt'"
*) ;;
usage -*)
exit 1 # split opts -abc into -a -b -c
;; set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
esac ;;
*)
usage
exit 1
;;
esac
done done
# If -h or --help was passed into the container, we'll want to cleanup # If -h or --help was passed into the container, we'll want to cleanup
# afterward # afterward
wantedhelp=0 wantedhelp=0
for var in "$@" for var in "$@"; do
do if [ "$var" = "-h" ] || [ "$var" = "--help" ]; then
if [ "$var" = "-h" -o "$var" = "--help" ]; then help
help exit 1
exit 1 fi
fi
done done
@ -171,9 +187,14 @@ if [ "$(id -u)" != "0" ]; then
exit 1 exit 1
fi fi
if [ -n "$custom_rootfs" ] && [ "$backingstore" != "dir" ]; then
echo "--dir is only valid with -B dir"
fi
case "$backingstore" in case "$backingstore" in
lvm|none|btrfs|_unset) :;; dir|lvm|none|btrfs|_unset) :;;
*) echo "$(basename $0): '$backingstore' is not known (try 'none', 'lvm', 'btrfs')" >&2 *)
echo "$(basename $0): '$backingstore' is not known (try 'none', 'dir', 'lvm', 'btrfs')" >&2
usage usage
exit 1 exit 1
;; ;;
@ -186,9 +207,9 @@ fi
rootfs="$lxc_path/$lxc_name/rootfs" rootfs="$lxc_path/$lxc_name/rootfs"
if [ "$backingstore" = "_unset" -o "$backingstore" = "btrfs" ]; then if [ "$backingstore" = "_unset" ] || [ "$backingstore" = "btrfs" ]; then
# if no backing store was given, then see if btrfs would work # if no backing store was given, then see if btrfs would work
if which btrfs >/dev/null 2>&1 && if which btrfs >/dev/null 2>&1 && \
btrfs filesystem df "$lxc_path/" >/dev/null 2>&1; then btrfs filesystem df "$lxc_path/" >/dev/null 2>&1; then
backingstore="btrfs" backingstore="btrfs"
else else
@ -200,12 +221,13 @@ if [ "$backingstore" = "_unset" -o "$backingstore" = "btrfs" ]; then
fi fi
fi fi
if [ $backingstore = "lvm" ]; then if [ "$backingstore" = "lvm" ]; then
which vgscan > /dev/null which vgscan > /dev/null
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "$(basename $0): vgscan not found (is lvm2 installed?)" >&2 echo "$(basename $0): vgscan not found (is lvm2 installed?)" >&2
exit 1 exit 1
fi fi
grep -q "\<$fstype\>" /proc/filesystems grep -q "\<$fstype\>" /proc/filesystems
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "$(basename $0): $fstype is not listed in /proc/filesystems" >&2 echo "$(basename $0): $fstype is not listed in /proc/filesystems" >&2
@ -225,6 +247,7 @@ if [ $backingstore = "lvm" ]; then
echo "please delete it (using \"lvremove $rootdev\") and try again" >&2 echo "please delete it (using \"lvremove $rootdev\") and try again" >&2
exit 1 exit 1
fi fi
elif [ "$backingstore" = "btrfs" ]; then elif [ "$backingstore" = "btrfs" ]; then
mkdir "$lxc_path/$lxc_name" mkdir "$lxc_path/$lxc_name"
if ! out=$(btrfs subvolume create "$rootfs" 2>&1); then if ! out=$(btrfs subvolume create "$rootfs" 2>&1); then
@ -234,10 +257,13 @@ elif [ "$backingstore" = "btrfs" ]; then
fi fi
cleanup() { cleanup() {
if [ $backingstore = "lvm" ]; then if [ "$backingstore" = "lvm" ]; then
umount $rootfs umount $rootfs
lvremove -f $rootdev lvremove -f $rootdev
elif [ "$backingstore" = "btrfs" ]; then
btrfs subvolume delete "$rootfs"
fi fi
${bindir}/lxc-destroy -n $lxc_name ${bindir}/lxc-destroy -n $lxc_name
echo "$(basename $0): aborted" >&2 echo "$(basename $0): aborted" >&2
exit 1 exit 1
@ -248,18 +274,54 @@ trap cleanup HUP INT TERM
mkdir -p $lxc_path/$lxc_name mkdir -p $lxc_path/$lxc_name
if [ -z "$lxc_config" ]; then if [ -z "$lxc_config" ]; then
touch $lxc_path/$lxc_name/config lxc_config="@SYSCONFDIR@/lxc/lxc.conf"
else echo
if [ ! -r "$lxc_config" ]; then echo "$(basename $0): No config file specified, using the default config $lxc_config"
echo "$(basename $0): '$lxc_config' configuration file not found" >&2 fi
exit 1
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" ]; then
template_path=$lxc_template
else
template_path=${templatedir}/lxc-$lxc_template
fi fi
cp $lxc_config $lxc_path/$lxc_name/config 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 "# Checksum of the template script (SHA-1): $sum" >> $lxc_path/$lxc_name/config
echo "" >> $lxc_path/$lxc_name/config
fi
cat $lxc_config >> $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 fi
# Create the fs as needed # Create the fs as needed
if [ $backingstore = "lvm" ]; then if [ "$backingstore" = "lvm" ]; then
[ -d "$rootfs" ] || mkdir $rootfs [ -d "$rootfs" ] || mkdir $rootfs
lvcreate -L $fssize -n $lvname $vgname || exit 1 lvcreate -L $fssize -n $lvname $vgname || exit 1
udevadm settle udevadm settle
@ -267,22 +329,8 @@ if [ $backingstore = "lvm" ]; then
mount -t $fstype $rootdev $rootfs mount -t $fstype $rootdev $rootfs
fi fi
if [ ! -z $lxc_template ]; then if [ ! -z "$lxc_template" ]; then
$template_path --path=$lxc_path/$lxc_name --name=$lxc_name $*
type ${templatedir}/lxc-$lxc_template 2>/dev/null
if [ $? -ne 0 ]; then
echo "$(basename $0): unknown template '$lxc_template'" >&2
cleanup
fi
if [ -z "$lxc_config" ]; then
echo "Note: Usually the template option is called with a configuration"
echo "file option too, mostly to configure the network."
echo "For more information look at lxc.conf (5)"
echo
fi
${templatedir}/lxc-$lxc_template --path=$lxc_path/$lxc_name --name=$lxc_name $*
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "$(basename $0): failed to execute template '$lxc_template'" >&2 echo "$(basename $0): failed to execute template '$lxc_template'" >&2
cleanup cleanup
@ -291,7 +339,7 @@ if [ ! -z $lxc_template ]; then
echo "'$lxc_template' template installed" echo "'$lxc_template' template installed"
fi fi
if [ $backingstore = "lvm" ]; then if [ "$backingstore" = "lvm" ]; then
echo "Unmounting LVM" echo "Unmounting LVM"
umount $rootfs umount $rootfs

View File

@ -54,26 +54,27 @@ eval set -- "$getopt"
while true; do while true; do
case "$1" in case "$1" in
-h|--help) -h|--help)
help help
exit 1 exit 1
;; ;;
-n|--name) -n|--name)
shift shift
lxc_name=$1 lxc_name=$1
shift shift
;; ;;
-f) -f)
force=1 force=1
shift shift
;; ;;
--) --)
shift shift
break;; break
;;
*) *)
usage usage
exit 1 exit 1
;; ;;
esac esac
done done
@ -96,13 +97,13 @@ fi
# make sure the container isn't running # make sure the container isn't running
lxc-info -n $lxc_name 2>/dev/null | grep -q RUNNING lxc-info -n $lxc_name 2>/dev/null | grep -q RUNNING
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
if [ $force -eq 1 ]; then if [ $force -eq 1 ]; then
lxc-stop -n $lxc_name lxc-stop -n $lxc_name
lxc-wait -n $lxc_name -s STOPPED lxc-wait -n $lxc_name -s STOPPED
else else
echo "$(basename $0): '$lxc_name' is running; aborted" >&2 echo "$(basename $0): '$lxc_name' is running; aborted" >&2
exit 1 exit 1
fi fi
fi fi
# Deduce the type of rootfs # Deduce the type of rootfs
@ -110,21 +111,22 @@ fi
# else, ignore it. We'll support deletion of others later. # 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 lxc.rootfs $lxc_path/$lxc_name/config 2>/dev/null | sed -e 's/^[^/]*/\//'`
if [ -n "$rootdev" ]; then if [ -n "$rootdev" ]; then
if [ -b "$rootdev" ]; then if [ -b "$rootdev" -o -h "$rootdev" ]; then
lvdisplay $rootdev > /dev/null 2>&1 lvdisplay $rootdev > /dev/null 2>&1
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "removing backing store: $rootdev" echo "removing backing store: $rootdev"
lvremove -f $rootdev lvremove -f $rootdev
fi fi
elif [ -h "$rootdev" -o -d "$rootdev" ]; then elif [ -h "$rootdev" -o -d "$rootdev" ]; then
if which btrfs >/dev/null 2>&1 && if which btrfs >/dev/null 2>&1 &&
btrfs subvolume list "$rootdev" >/dev/null 2>&1; then btrfs subvolume list "$rootdev" >/dev/null 2>&1; then
btrfs subvolume delete "$rootdev" btrfs subvolume delete "$rootdev"
else else
# In case rootfs is not under $lxc_path/$lxc_name, remove it # In case rootfs is not under $lxc_path/$lxc_name, remove it
rm -rf --one-file-system --preserve-root $rootdev rm -rf --one-file-system --preserve-root $rootdev
fi fi
fi fi
fi fi
# recursively remove the container to remove old container configuration # recursively remove the container to remove old container configuration
rm -rf --one-file-system --preserve-root $lxc_path/$lxc_name rm -rf --one-file-system --preserve-root $lxc_path/$lxc_name

95
src/lxc/lxc-device Normal file
View File

@ -0,0 +1,95 @@
#!/usr/bin/python3
#
# lxc-device: Add devices to a running container
#
# This python implementation is based on the work done in the original
# shell implementation done by Serge Hallyn in Ubuntu (and other contributors)
#
# (C) Copyright Canonical Ltd. 2012
#
# Authors:
# Stéphane Graber <stgraber@ubuntu.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# NOTE: To remove once the API is stabilized
import warnings
warnings.filterwarnings("ignore", "The python-lxc API isn't yet stable")
import argparse
import gettext
import lxc
import os
import sys
_ = gettext.gettext
gettext.textdomain("lxc-device")
# Begin parsing the command line
parser = argparse.ArgumentParser(description=_("LXC: Manage devices"),
formatter_class=argparse.RawTextHelpFormatter)
# Global arguments
parser.add_argument("-n", dest="container", metavar="CONTAINER",
help=_("Name of the container to add the device to"),
required=True)
# Commands
subparsers = parser.add_subparsers()
subparser_add = subparsers.add_parser('add', help=_('Add a device'))
subparser_add.set_defaults(action="add")
subparser_add.add_argument(dest="device", metavar="DEVICE",
help=_("Add a device "
"(path to a node or interface name)"))
subparser_add.add_argument(dest="name", metavar="NAME", nargs="?",
help=_("Use an alternative path or name "
"in the container"))
args = parser.parse_args()
# Some basic checks
if not hasattr(args, "action"):
parser.error(_("You must specify an action."))
## The user needs to be uid 0
if not os.geteuid() == 0:
parser.error(_("You must be root to run this script. Try running: sudo %s"
% (sys.argv[0])))
## Don't rename if no alternative name
if not args.name:
args.name = args.device
## Check that the container is ready
container = lxc.Container(args.container)
if not container.running:
parser.error("The container must be running.")
# Do the work
if args.action == "add":
if os.path.exists("/sys/class/net/%s/" % args.device):
ret = container.add_device_net(args.device, args.name)
else:
ret = container.add_device_node(args.device, args.name)
if ret:
print("Added '%s' to '%s' as '%s'." %
(args.device, container.name, args.name))
else:
print("Failed to add '%s' to '%s' as '%s'." %
(args.device, container.name, args.name))

251
src/lxc/lxc-ls Normal file
View File

@ -0,0 +1,251 @@
#!/usr/bin/python3
#
# lxc-ls: List containers
#
# This python implementation is based on the work done in the original
# shell implementation done by Serge Hallyn in Ubuntu (and other contributors)
#
# (C) Copyright Canonical Ltd. 2012
#
# Authors:
# Stéphane Graber <stgraber@ubuntu.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# NOTE: To remove once the API is stabilized
import warnings
warnings.filterwarnings("ignore", "The python-lxc API isn't yet stable")
import argparse
import gettext
import lxc
import os
import re
import sys
_ = gettext.gettext
gettext.textdomain("lxc-ls")
# Functions used later on
def batch(iterable, cols=1):
import math
length = len(iterable)
lines = math.ceil(length / cols)
for line in range(lines):
fields = []
for col in range(cols):
index = line + (col * lines)
if index < length:
fields.append(iterable[index])
yield fields
def getTerminalSize():
import os
env = os.environ
def ioctl_GWINSZ(fd):
try:
import fcntl
import termios
import struct
cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
'1234'))
return cr
except:
return
cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
if not cr:
try:
fd = os.open(os.ctermid(), os.O_RDONLY)
cr = ioctl_GWINSZ(fd)
os.close(fd)
except:
pass
if not cr:
cr = (env.get('LINES', 25), env.get('COLUMNS', 80))
return int(cr[1]), int(cr[0])
# Begin parsing the command line
parser = argparse.ArgumentParser(description=_("LXC: List containers"),
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("-1", dest="one", action="store_true",
help=_("list one container per line (default when piped)"))
parser.add_argument("--active", action="store_true",
help=_("list only active containers "
"(same as --running --frozen)"))
parser.add_argument("--frozen", dest="state", action="append_const",
const="FROZEN", help=_("list only frozen containers"))
parser.add_argument("--running", dest="state", action="append_const",
const="RUNNING", help=_("list only running containers"))
parser.add_argument("--stopped", dest="state", action="append_const",
const="STOPPED", help=_("list only stopped containers"))
parser.add_argument("--fancy", action="store_true",
help=_("use fancy output"))
parser.add_argument("--fancy-format", type=str, default="name,state,ipv4,ipv6",
help=_("comma separated list of fields to show"))
parser.add_argument("filter", metavar='FILTER', type=str, nargs="?",
help=_("regexp to be applied on the container list"))
args = parser.parse_args()
# --active is the same as --running --frozen
if args.active:
if not args.state:
args.state = []
args.state += ["RUNNING", "FROZEN"]
# If the output is piped, default to --one
if not sys.stdout.isatty():
args.one = True
# Turn args.fancy_format into a list
args.fancy_format = args.fancy_format.strip().split(",")
# Basic checks
## The user needs to be uid 0
if not os.geteuid() == 0 and (args.fancy or args.state):
parser.error(_("You must be root to access advanced container properties. "
"Try running: sudo %s"
% (sys.argv[0])))
# List of containers, stored as dictionaries
containers = []
for container_name in lxc.list_containers():
entry = {}
entry['name'] = container_name
# Apply filter
if args.filter and not re.match(args.filter, container_name):
continue
# Return before grabbing the object (non-root)
if not args.state and not args.fancy:
containers.append(entry)
continue
container = lxc.Container(container_name)
# Filter by status
if args.state and container.state not in args.state:
continue
# Nothing more is needed if we're not printing some fancy output
if not args.fancy:
containers.append(entry)
continue
# Some extra field we may want
if 'state' in args.fancy_format:
entry['state'] = container.state
if 'pid' in args.fancy_format:
entry['pid'] = "-"
if container.init_pid != -1:
entry['pid'] = str(container.init_pid)
# Get the IPs
for protocol in ('ipv4', 'ipv6'):
if protocol in args.fancy_format:
entry[protocol] = "-"
ips = container.get_ips(protocol=protocol, timeout=1)
if ips:
entry[protocol] = ", ".join(ips)
containers.append(entry)
# Print the list
## Standard list with one entry per line
if not args.fancy and args.one:
for container in sorted(containers,
key=lambda container: container['name']):
print(container['name'])
sys.exit(0)
## Standard list with multiple entries per line
if not args.fancy and not args.one:
# Get the longest name and extra simple list
field_maxlength = 0
container_names = []
for container in containers:
if len(container['name']) > field_maxlength:
field_maxlength = len(container['name'])
container_names.append(container['name'])
# Figure out how many we can put per line
width = getTerminalSize()[0]
entries = int(width / (field_maxlength + 2))
if entries == 0:
entries = 1
for line in batch(sorted(container_names), entries):
line_format = ""
for index in range(len(line)):
line_format += "{line[%s]:%s}" % (index, field_maxlength + 2)
print(line_format.format(line=line))
## Fancy listing
if args.fancy:
field_maxlength = {}
# Get the maximum length per field
for field in args.fancy_format:
field_maxlength[field] = len(field)
for container in containers:
for field in args.fancy_format:
if len(container[field]) > field_maxlength[field]:
field_maxlength[field] = len(container[field])
# Generate the line format string based on the maximum length and
# a 2 character padding
line_format = ""
index = 0
for field in args.fancy_format:
line_format += "{fields[%s]:%s}" % (index, field_maxlength[field] + 2)
index += 1
# Get the line length minus the padding of the last field
line_length = -2
for field in field_maxlength:
line_length += field_maxlength[field] + 2
# Print header
print(line_format.format(fields=[header.upper()
for header in args.fancy_format]))
print("-" * line_length)
# Print the entries
for container in sorted(containers,
key=lambda container: container['name']):
fields = [container[field] for field in args.fancy_format]
print(line_format.format(fields=fields))

View File

@ -18,110 +18,110 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
usage() { usage() {
echo "usage: $(basename $0) -n|--name <name> -- [netstat_options]" >&2 echo "usage: $(basename $0) -n|--name <name> -- [netstat_options]" >&2
} }
help() { help() {
usage usage
echo >&2 echo >&2
echo "Execute 'netstat' for the specified container." >&2 echo "Execute 'netstat' for the specified container." >&2
echo >&2 echo >&2
echo " --name NAME specify the container name" >&2 echo " --name NAME specify the container name" >&2
echo " NETSTAT_OPTIONS netstat command options (see \`netstat --help')" >&2 echo " NETSTAT_OPTIONS netstat command options (see \`netstat --help')" >&2
} }
get_parent_cgroup() get_parent_cgroup()
{ {
local hierarchies hierarchy fields subsystems init_cgroup mountpoint local hierarchies hierarchy fields subsystems init_cgroup mountpoint
parent_cgroup="" parent_cgroup=""
# Obtain a list of hierarchies that contain one or more subsystems # Obtain a list of hierarchies that contain one or more subsystems
hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2) hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
# Iterate through the list until a suitable hierarchy is found # Iterate through the list until a suitable hierarchy is found
for hierarchy in $hierarchies; do for hierarchy in $hierarchies; do
# Obtain information about the init process in the hierarchy # Obtain information about the init process in the hierarchy
fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1) fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1)
if [ -z "$fields" ]; then continue; fi if [ -z "$fields" ]; then continue; fi
fields=${fields#*:} fields=${fields#*:}
# Get a comma-separated list of the hierarchy's subsystems # Get a comma-separated list of the hierarchy's subsystems
subsystems=${fields%:*} subsystems=${fields%:*}
# Get the cgroup of the init process in the hierarchy # Get the cgroup of the init process in the hierarchy
init_cgroup=${fields#*:} init_cgroup=${fields#*:}
# Get the filesystem mountpoint of the hierarchy # Get the filesystem mountpoint of the hierarchy
mountpoint=$(grep -E "^cgroup [^ ]+ [^ ]+ ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2) mountpoint=$(grep -E "^cgroup [^ ]+ [^ ]+ ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2)
if [ -z "$mountpoint" ]; then continue; fi if [ -z "$mountpoint" ]; then continue; fi
# Return the absolute path to the containers' parent cgroup # Return the absolute path to the containers' parent cgroup
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem) # (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
if [[ ",$subsystems," == *,ns,* ]]; then if [[ ",$subsystems," == *,ns,* ]]; then
parent_cgroup="${mountpoint}${init_cgroup%/}" parent_cgroup="${mountpoint}${init_cgroup%/}"
else else
parent_cgroup="${mountpoint}${init_cgroup%/}/lxc" parent_cgroup="${mountpoint}${init_cgroup%/}/lxc"
fi fi
break break
done done
} }
exec="" exec=""
while true; do while true; do
case $1 in case $1 in
-h|--help) -h|--help)
help; exit 1;; help; exit 1;;
-n|--name) -n|--name)
name=$2; shift 2;; name=$2; shift 2;;
--exec) --exec)
exec="exec"; shift;; exec="exec"; shift;;
--) --)
shift; break;; shift; break;;
*) *)
break;; break;;
esac esac
done done
if [ "$(id -u)" != "0" ]; then if [ "$(id -u)" != "0" ]; then
echo "$(basename $0): must be run as root" >&2 echo "$(basename $0): must be run as root" >&2
exit 1 exit 1
fi fi
if [ -z "$name" ]; then if [ -z "$name" ]; then
usage usage
exit 1 exit 1
fi fi
if [ -z "$exec" ]; then if [ -z "$exec" ]; then
exec @BINDIR@/lxc-unshare -s MOUNT -- $0 -n $name --exec "$@" exec @BINDIR@/lxc-unshare -s MOUNT -- $0 -n $name --exec "$@"
fi fi
lxc-info -n $name 2>&1 | grep -q 'STOPPED' lxc-info -n $name 2>&1 | grep -q 'STOPPED'
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "$(basename $0): container '$name' is not running" >&2 echo "$(basename $0): container '$name' is not running" >&2
exit 1 exit 1
fi fi
get_parent_cgroup get_parent_cgroup
if [ ! -d "$parent_cgroup" ]; then if [ ! -d "$parent_cgroup" ]; then
echo "$(basename $0): no cgroup mount point found" >&2 echo "$(basename $0): no cgroup mount point found" >&2
exit 1 exit 1
fi fi
pid=$(head -1 $parent_cgroup/$name/tasks) pid=$(head -1 $parent_cgroup/$name/tasks)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
echo "$(basename $0): no process found for '$name'" >&2 echo "$(basename $0): no process found for '$name'" >&2
exit 1 exit 1
fi fi
tmpdir=$(mktemp -d) tmpdir=$(mktemp -d)
if [ -z "$tmpdir" -o ! -d "$tmpdir" ]; then if [ -z "$tmpdir" -o ! -d "$tmpdir" ]; then
echo "$(basename $0): unable to create temporary directory" >&2 echo "$(basename $0): unable to create temporary directory" >&2
exit 1 exit 1
fi fi
# Bind mount /proc/$pid/net onto /proc/net before calling 'netstat'. # Bind mount /proc/$pid/net onto /proc/net before calling 'netstat'.

View File

@ -19,125 +19,124 @@
usage() usage()
{ {
echo "usage: $(basename $0) [--lxc | --name NAME] [--] [PS_OPTIONS...]" >&2 echo "usage: $(basename $0) [--lxc | --name NAME] [--] [PS_OPTIONS...]" >&2
} }
help() { help() {
usage usage
echo >&2 echo >&2
echo "List current processes with container names." >&2 echo "List current processes with container names." >&2
echo >&2 echo >&2
echo " --lxc show processes in all containers" >&2 echo " --lxc show processes in all containers" >&2
echo " --name NAME show processes in the specified container" >&2 echo " --name NAME show processes in the specified container" >&2
echo " (multiple containers can be separated by commas)" >&2 echo " (multiple containers can be separated by commas)" >&2
echo " PS_OPTIONS ps command options (see \`ps --help')" >&2 echo " PS_OPTIONS ps command options (see \`ps --help')" >&2
} }
get_parent_cgroup() get_parent_cgroup()
{ {
local hierarchies hierarchy fields subsystems init_cgroup mountpoint local hierarchies hierarchy fields subsystems init_cgroup mountpoint
parent_cgroup="" parent_cgroup=""
# Obtain a list of hierarchies that contain one or more subsystems # Obtain a list of hierarchies that contain one or more subsystems
hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2) hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
# Iterate through the list until a suitable hierarchy is found # Iterate through the list until a suitable hierarchy is found
for hierarchy in $hierarchies; do for hierarchy in $hierarchies; do
# Obtain information about the init process in the hierarchy # Obtain information about the init process in the hierarchy
fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1) fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1)
if [ -z "$fields" ]; then continue; fi if [ -z "$fields" ]; then continue; fi
fields=${fields#*:} fields=${fields#*:}
# Get a comma-separated list of the hierarchy's subsystems # Get a comma-separated list of the hierarchy's subsystems
subsystems=${fields%:*} subsystems=${fields%:*}
# Get the cgroup of the init process in the hierarchy # Get the cgroup of the init process in the hierarchy
init_cgroup=${fields#*:} init_cgroup=${fields#*:}
# Get the filesystem mountpoint of the hierarchy # Get the filesystem mountpoint of the hierarchy
mountpoint=$(grep -E "^cgroup [^ ]+ [^ ]+ ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2) mountpoint=$(grep -E "^cgroup [^ ]+ [^ ]+ ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2)
if [ -z "$mountpoint" ]; then continue; fi if [ -z "$mountpoint" ]; then continue; fi
# Return the absolute path to the containers' parent cgroup # Return the absolute path to the containers' parent cgroup
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem) # (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
if [[ ",$subsystems," == *,ns,* ]]; then if [[ ",$subsystems," == *,ns,* ]]; then
parent_cgroup="${mountpoint}${init_cgroup%/}" parent_cgroup="${mountpoint}${init_cgroup%/}"
else else
parent_cgroup="${mountpoint}${init_cgroup%/}/lxc" parent_cgroup="${mountpoint}${init_cgroup%/}/lxc"
fi fi
break break
done done
} }
containers="" containers=""
list_container_processes=0 list_container_processes=0
while true; do while true; do
case $1 in case $1 in
-h|--help) -h|--help)
help; exit 1;; help; exit 1;;
-n|--name) -n|--name)
containers=$2; list_container_processes=1; shift 2;; containers=$2; list_container_processes=1; shift 2;;
--lxc) --lxc)
list_container_processes=1; shift;; list_container_processes=1; shift;;
--) --)
shift; break;; shift; break;;
*) *)
break;; break;;
esac esac
done done
if [ "$list_container_processes" -eq "1" ]; then if [ "$list_container_processes" -eq "1" ]; then
set -- -e $@ set -- -e $@
fi fi
get_parent_cgroup get_parent_cgroup
if [ ! -d "$parent_cgroup" ]; then if [ ! -d "$parent_cgroup" ]; then
echo "$(basename $0): no cgroup mount point found" >&2 echo "$(basename $0): no cgroup mount point found" >&2
exit 1 exit 1
fi fi
declare -a container_of_pid declare -a container_of_pid
container_field_width=9 container_field_width=9
IFS="," IFS=","
if [ -z "$containers" ]; then if [ -z "$containers" ]; then
containers=( $(find $parent_cgroup -mindepth 1 -maxdepth 1 -type d -printf "%f," 2>/dev/null) ) containers=( $(find $parent_cgroup -mindepth 1 -maxdepth 1 -type d -printf "%f," 2>/dev/null) )
else else
containers=( $containers ) containers=( $containers )
fi fi
declare -i pid declare -i pid
IFS=$'\n' IFS=$'\n'
for container in ${containers[@]}; do for container in ${containers[@]}; do
if [ "${#container}" -gt "$container_field_width" ]; then if [ "${#container}" -gt "$container_field_width" ]; then
container_field_width=${#container} container_field_width=${#container}
fi fi
if [ -f "$parent_cgroup/$container/tasks" ]; then if [ -f "$parent_cgroup/$container/tasks" ]; then
while read pid; do while read pid; do
container_of_pid[$pid]=$container container_of_pid[$pid]=$container
done < "$parent_cgroup/$container/tasks" done < "$parent_cgroup/$container/tasks"
fi fi
done done
declare -i line_pid_end_position declare -i line_pid_end_position
while read line; do while read line; do
if [ -z "$line_pid_end_position" ]; then if [ -z "$line_pid_end_position" ]; then
if [[ "$line" != *" PID"* ]]; then if [[ "$line" != *" PID"* ]]; then
echo "$(basename $0): no PID column found in \`ps' output" >&2 echo "$(basename $0): no PID column found in \`ps' output" >&2
exit 1 exit 1
fi fi
buffer=${line%" PID"*} buffer=${line%" PID"*}
let line_pid_end_position=${#buffer}+4 let line_pid_end_position=${#buffer}+4
printf "%-${container_field_width}s %s\n" "CONTAINER" "$line" printf "%-${container_field_width}s %s\n" "CONTAINER" "$line"
continue continue
fi fi
buffer=${line:0:$line_pid_end_position} buffer=${line:0:$line_pid_end_position}
pid=${buffer##* } pid=${buffer##* }
if [ "$list_container_processes" -eq "0" -o ! -z "${container_of_pid[pid]}" ]; then if [ "$list_container_processes" -eq "0" -o ! -z "${container_of_pid[pid]}" ]; then
printf "%-${container_field_width}s %s\n" "${container_of_pid[pid]}" "$line" printf "%-${container_field_width}s %s\n" "${container_of_pid[pid]}" "$line"
fi fi
done < <(ps "$@") done < <(ps "$@")

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/sh
# #
# lxc: linux Container library # lxc: linux Container library
@ -81,35 +81,43 @@ lxc_dropcaps()
chmod 0755 @LXCPATH@ chmod 0755 @LXCPATH@
} }
shortoptions='hd' usage_err() {
longoptions='help' [ -n "$1" ] && echo "$1" >&2
getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@")
if [ $? != 0 ]; then
usage usage
exit 1 exit 1
fi }
eval set -- "$getopt" optarg_check() {
if [ -z "$2" ]; then
usage_err "option '$1' requires an argument"
fi
}
while true; do while [ $# -gt 0 ]; do
case "$1" in opt="$1"
-d) shift
LXC_DROP_CAPS="yes" case "$opt" in
shift -d)
;; LXC_DROP_CAPS="yes"
-h|--help) ;;
help -h|--help)
exit 0 help
;; exit 0
--) ;;
shift --)
break break
;; ;;
*) -?)
usage usage_err "unknown option '$opt'"
exit 1 ;;
;; -*)
# split opts -abc into -a -b -c
set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
;;
*)
usage
exit 1
;;
esac esac
done; done;

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/sh
# #
# lxc: linux Container library # lxc: linux Container library
@ -41,9 +41,9 @@ help() {
setuid() setuid()
{ {
if [ "$1" = "-r" ]; then if [ "$1" = "-r" ]; then
chmod -s $2 chmod -s $2
else else
chmod +s $1 chmod +s $1
fi fi
} }
@ -78,35 +78,43 @@ lxc_dropuid()
chmod 0755 @LXCPATH@ chmod 0755 @LXCPATH@
} }
shortoptions='hd' usage_err() {
longoptions='help' [ -n "$1" ] && echo "$1" >&2
getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@")
if [ $? != 0 ]; then
usage usage
exit 1 exit 1
fi }
eval set -- "$getopt" optarg_check() {
if [ -z "$2" ]; then
usage_err "option '$1' requires an argument"
fi
}
while true; do while [ $# -gt 0 ]; do
case "$1" in opt="$1"
-d) shift
LXC_DROP_CAPS="yes" case "$opt" in
shift -d)
;; LXC_DROP_CAPS="yes"
-h|--help) ;;
help -h|--help)
exit 0 help
;; exit 0
--) ;;
shift --)
break break
;; ;;
*) -?)
usage usage_err "unknown option '$opt'"
exit 1 ;;
;; -*)
# split opts -abc into -a -b -c
set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
;;
*)
usage
exit 1
;;
esac esac
done; done;

View File

@ -0,0 +1,289 @@
#!/usr/bin/python3
#
# lxc-start-ephemeral: Start a copy of a container using an overlay
#
# This python implementation is based on the work done in the original
# shell implementation done by Serge Hallyn in Ubuntu (and other contributors)
#
# (C) Copyright Canonical Ltd. 2012
#
# Authors:
# Stéphane Graber <stgraber@ubuntu.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# NOTE: To remove once the API is stabilized
import warnings
warnings.filterwarnings("ignore", "The python-lxc API isn't yet stable")
import argparse
import gettext
import lxc
import os
import sys
import subprocess
import tempfile
_ = gettext.gettext
gettext.textdomain("lxc-start-ephemeral")
# Other functions
def randomMAC():
import random
mac = [0x00, 0x16, 0x3e,
random.randint(0x00, 0x7f),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff)]
return ':'.join(map(lambda x: "%02x" % x, mac))
# Begin parsing the command line
parser = argparse.ArgumentParser(description=_(
"LXC: Start an ephemeral container"),
formatter_class=argparse.RawTextHelpFormatter,
epilog=_("If a COMMAND is given, then the "
"""container will run only as long
as the command runs.
If no COMMAND is given, this command will attach to tty1 and stop the
container when exiting (with ctrl-a-q).
If no COMMAND is given and -d is used, the name and IP addresses of the
container will be printed to the console."""))
parser.add_argument("--orig", "-o", type=str, required=True,
help=_("name of the original container"))
parser.add_argument("--bdir", "-b", type=str,
help=_("directory to bind mount into container"))
parser.add_argument("--user", "-u", type=str,
help=_("the user to connect to the container as"))
parser.add_argument("--key", "-S", type=str,
help=_("the path to the SSH key to use to connect"))
parser.add_argument("--daemon", "-d", action="store_true",
help=_("run in the background"))
parser.add_argument("--union-type", "-U", type=str, default="overlayfs",
choices=("overlayfs", "aufs"),
help=_("type of union (overlayfs or aufs), "
"defaults to overlayfs."))
parser.add_argument("--keep-data", "-k", action="store_true",
help=_("Use a persistent backend instead of tmpfs."))
parser.add_argument("command", metavar='CMD', type=str, nargs="*",
help=_("Run specific command in container "
"(command as argument)"))
args = parser.parse_args()
# Basic requirements check
## Check that -d and CMD aren't used at the same time
if args.command and args.daemon:
parser.error(_("You can't use -d and a command at the same time."))
## The user needs to be uid 0
if not os.geteuid() == 0:
parser.error(_("You must be root to run this script. Try running: sudo %s"
% (sys.argv[0])))
# Load the orig container
orig = lxc.Container(args.orig)
if not orig.defined:
parser.error(_("Source container '%s' doesn't exist." % args.orig))
# Create the new container paths
dest_path = tempfile.mkdtemp(prefix="%s-" % args.orig, dir="@LXCPATH@")
os.mkdir(os.path.join(dest_path, "rootfs"))
# Setup the new container's configuration
dest = lxc.Container(os.path.basename(dest_path))
dest.load_config(orig.config_file_name)
dest.set_config_item("lxc.utsname", dest.name)
dest.set_config_item("lxc.rootfs", os.path.join(dest_path, "rootfs"))
dest.set_config_item("lxc.network.hwaddr", randomMAC())
overlay_dirs = [(orig.get_config_item("lxc.rootfs"), "%s/rootfs/" % dest_path)]
# Generate a new fstab
if orig.get_config_item("lxc.mount"):
dest.set_config_item("lxc.mount", os.path.join(dest_path, "fstab"))
with open(orig.get_config_item("lxc.mount"), "r") as orig_fd:
with open(dest.get_config_item("lxc.mount"), "w+") as dest_fd:
for line in orig_fd.read().split("\n"):
# Start by replacing any reference to the container rootfs
line.replace(orig.get_config_item("lxc.rootfs"),
dest.get_config_item("lxc.rootfs"))
# Skip any line that's not a bind mount
fields = line.split()
if len(fields) < 4:
dest_fd.write("%s\n" % line)
continue
if fields[2] != "bind" and "bind" not in fields[3]:
dest_fd.write("%s\n" % line)
continue
# Process any remaining line
dest_mount = os.path.abspath(os.path.join("%s/rootfs/" % (
dest_path), fields[1]))
if dest_mount == os.path.abspath("%s/rootfs/%s" % (
dest_path, args.bdir)):
dest_fd.write("%s\n" % line)
continue
if "%s/rootfs/" % dest_path not in dest_mount:
print(_("Skipping mount entry '%s' as it's outside "
"of the container rootfs.") % line)
overlay_dirs += [(fields[0], dest_mount)]
# Generate pre-mount script
with open(os.path.join(dest_path, "pre-mount"), "w+") as fd:
os.fchmod(fd.fileno(), 0o755)
fd.write("""#!/bin/sh
LXC_DIR="%s"
LXC_BASE="%s"
LXC_NAME="%s"
""" % (dest_path, orig.name, dest.name))
count = 0
for entry in overlay_dirs:
target = "%s/delta%s" % (dest_path, count)
fd.write("mkdir -p %s %s\n" % (target, entry[1]))
if not args.keep_data:
fd.write("mount -n -t tmpfs none %s\n" % (target))
if args.union_type == "overlayfs":
fd.write("mount -n -t overlayfs"
" -oupperdir=%s,lowerdir=%s none %s\n" % (
target,
entry[0],
entry[1]))
elif args.union_type == "aufs":
fd.write("mount -n -t aufs "
"-o br=${upper}=rw:${lower}=ro,noplink none %s\n" % (
target,
entry[0],
entry[1]))
count += 1
if args.bdir:
if not os.path.exists(args.bdir):
print(_("Path '%s' doesn't exist, won't be bind-mounted.") %
args.bdir)
else:
src_path = os.path.abspath(args.bdir)
dst_path = "%s/rootfs/%s" % (dest_path, os.path.abspath(args.bdir))
fd.write("mkdir -p %s\nmount -n --bind %s %s\n" % (
dst_path, src_path, dst_path))
fd.write("""
[ -e $LXC_DIR/configured ] && exit 0
for file in $LXC_DIR/rootfs/etc/hostname \\
$LXC_DIR/rootfs/etc/hosts \\
$LXC_DIR/rootfs/etc/sysconfig/network \\
$LXC_DIR/rootfs/etc/sysconfig/network-scripts/ifcfg-eth0; do
[ -f "$file" ] && sed -i -e "s/$LXC_BASE/$LXC_NAME/" $file
done
touch $LXC_DIR/configured
""")
dest.set_config_item("lxc.hook.pre-mount",
os.path.join(dest_path, "pre-mount"))
# Generate post-stop script
if not args.keep_data:
with open(os.path.join(dest_path, "post-stop"), "w+") as fd:
os.fchmod(fd.fileno(), 0o755)
fd.write("""#!/bin/sh
[ -d "%s" ] && rm -Rf "%s"
""" % (dest_path, dest_path))
dest.set_config_item("lxc.hook.post-stop",
os.path.join(dest_path, "post-stop"))
dest.save_config()
# Start the container
if not dest.start() or not dest.wait("RUNNING", timeout=5):
print(_("The container '%s' failed to start.") % dest.name)
dest.stop()
if dest.defined:
dest.destroy()
sys.exit(1)
# Deal with the case where we just attach to the container's console
if not args.command and not args.daemon:
dest.console(tty=1)
dest.shutdown(timeout=5)
sys.exit(0)
# Try to get the IP addresses
ips = dest.get_ips(timeout=10)
# Deal with the case where we just print info about the container
if args.daemon:
print(_("""The ephemeral container is now started.
You can enter it from the command line with: lxc-console -n %s
The following IP addresses have be found in the container:
%s""") % (dest.name,
"\n".join([" - %s" % entry for entry in ips]
or [" - %s" % _("No address could be found")])))
sys.exit(0)
# Now deal with the case where we want to run a command in the container
if not ips:
print(_("Failed to get an IP for container '%s'.") % dest.name)
dest.stop()
if dest.defined:
dest.destroy()
sys.exit(1)
# NOTE: To replace by .attach() once the kernel supports it
cmd = ["ssh",
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null"]
if args.user:
cmd += ["-l", args.user]
if args.key:
cmd += ["-k", args.key]
for ip in ips:
ssh_cmd = cmd + [ip] + args.command
retval = subprocess.call(ssh_cmd, universal_newlines=True)
if retval == 255:
print(_("SSH failed to connect, trying next IP address."))
continue
if retval != 0:
print(_("Command returned with non-zero return code: %s") % retval)
break
# Shutdown the container
dest.shutdown(timeout=5)
sys.exit(retval)

View File

@ -1,3 +1,3 @@
#!/bin/bash #!/bin/sh
echo "lxc version: @PACKAGE_VERSION@" echo "lxc version: @PACKAGE_VERSION@"

View File

@ -84,6 +84,7 @@ extern int lxc_monitor_open(void);
* data was readen, < 0 otherwise * data was readen, < 0 otherwise
*/ */
extern int lxc_monitor_read(int fd, struct lxc_msg *msg); extern int lxc_monitor_read(int fd, struct lxc_msg *msg);
extern int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout);
/* /*
* Close the fd associated with the monitoring * Close the fd associated with the monitoring
@ -178,6 +179,30 @@ extern int lxc_restart(const char *, int, struct lxc_conf *, int);
*/ */
extern const char const *lxc_version(void); extern const char const *lxc_version(void);
/*
* Create and return a new lxccontainer struct.
*/
extern struct lxc_container *lxc_container_new(const char *name);
/*
* Returns 1 on success, 0 on failure.
*/
extern int lxc_container_get(struct lxc_container *c);
/*
* Put a lxccontainer struct reference.
* Return -1 on error.
* Return 0 if this was not the last reference.
* If it is the last reference, free the lxccontainer and return 1.
*/
extern int lxc_container_put(struct lxc_container *c);
/*
* Get a list of valid wait states.
* If states is NULL, simply return the number of states
*/
extern int lxc_get_wait_states(const char **states);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -40,22 +40,30 @@
#include "start.h" #include "start.h"
#include "sync.h" #include "sync.h"
#include "log.h" #include "log.h"
#include "namespace.h"
lxc_log_define(lxc_attach_ui, lxc); lxc_log_define(lxc_attach_ui, lxc);
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
{"elevated-privileges", no_argument, 0, 'e'}, {"elevated-privileges", no_argument, 0, 'e'},
{"arch", required_argument, 0, 'a'}, {"arch", required_argument, 0, 'a'},
{"namespaces", required_argument, 0, 's'},
{"remount-sys-proc", no_argument, 0, 'R'},
LXC_COMMON_OPTIONS LXC_COMMON_OPTIONS
}; };
static int elevated_privileges = 0; static int elevated_privileges = 0;
static signed long new_personality = -1; static signed long new_personality = -1;
static int namespace_flags = -1;
static int remount_sys_proc = 0;
static int my_parser(struct lxc_arguments* args, int c, char* arg) static int my_parser(struct lxc_arguments* args, int c, char* arg)
{ {
int ret;
switch (c) { switch (c) {
case 'e': elevated_privileges = 1; break; case 'e': elevated_privileges = 1; break;
case 'R': remount_sys_proc = 1; break;
case 'a': case 'a':
new_personality = lxc_config_parse_arch(arg); new_personality = lxc_config_parse_arch(arg);
if (new_personality < 0) { if (new_personality < 0) {
@ -63,6 +71,14 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
return -1; return -1;
} }
break; break;
case 's':
namespace_flags = 0;
ret = lxc_fill_namespace_flags(arg, &namespace_flags);
if (ret)
return -1;
/* -s implies -e */
elevated_privileges = 1;
break;
} }
return 0; return 0;
@ -83,7 +99,18 @@ Options :\n\
WARNING: This may leak privleges into the container.\n\ WARNING: This may leak privleges into the container.\n\
Use with care.\n\ Use with care.\n\
-a, --arch=ARCH Use ARCH for program instead of container's own\n\ -a, --arch=ARCH Use ARCH for program instead of container's own\n\
architecture.\n", architecture.\n\
-s, --namespaces=FLAGS\n\
Don't attach to all the namespaces of the container\n\
but just to the following OR'd list of flags:\n\
MOUNT, PID, UTSNAME, IPC, USER or NETWORK\n\
WARNING: Using -s implies -e, it may therefore\n\
leak privileges into the container. Use with care.\n\
-R, --remount-sys-proc\n\
Remount /sys and /proc if not attaching to the\n\
mount namespace when using -s in order to properly\n\
reflect the correct namespace context. See the\n\
lxc-attach(1) manual page for details.\n",
.options = my_longopts, .options = my_longopts,
.parser = my_parser, .parser = my_parser,
.checker = NULL, .checker = NULL,
@ -96,6 +123,7 @@ int main(int argc, char *argv[])
struct passwd *passwd; struct passwd *passwd;
struct lxc_proc_context_info *init_ctx; struct lxc_proc_context_info *init_ctx;
struct lxc_handler *handler; struct lxc_handler *handler;
void *cgroup_data = NULL;
uid_t uid; uid_t uid;
char *curdir; char *curdir;
@ -124,6 +152,48 @@ int main(int argc, char *argv[])
return -1; return -1;
} }
if (!elevated_privileges) {
/* we have to do this now since /sys/fs/cgroup may not
* be available inside the container or we may not have
* the required permissions anymore
*/
ret = lxc_cgroup_prepare_attach(my_args.name, &cgroup_data);
if (ret < 0) {
ERROR("failed to prepare attaching to cgroup");
return -1;
}
}
curdir = get_current_dir_name();
/* determine which namespaces the container was created with
* by asking lxc-start
*/
if (namespace_flags == -1) {
namespace_flags = lxc_get_clone_flags(my_args.name);
/* call failed */
if (namespace_flags == -1) {
ERROR("failed to automatically determine the "
"namespaces which the container unshared");
return -1;
}
}
/* we need to attach before we fork since certain namespaces
* (such as pid namespaces) only really affect children of the
* current process and not the process itself
*/
ret = lxc_attach_to_ns(init_pid, namespace_flags);
if (ret < 0) {
ERROR("failed to enter the namespace");
return -1;
}
if (curdir && chdir(curdir))
WARN("could not change directory to '%s'", curdir);
free(curdir);
/* hack: we need sync.h infrastructure - and that needs a handler */ /* hack: we need sync.h infrastructure - and that needs a handler */
handler = calloc(1, sizeof(*handler)); handler = calloc(1, sizeof(*handler));
@ -150,8 +220,22 @@ int main(int argc, char *argv[])
if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE)) if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE))
return -1; return -1;
if (!elevated_privileges && lxc_cgroup_attach(my_args.name, pid)) /* now that we are done with all privileged operations,
return -1; * we can add ourselves to the cgroup. Since we smuggled in
* the fds earlier, we still have write permission
*/
if (!elevated_privileges) {
/* since setns() for pid namespaces only really
* affects child processes, the pid we have is
* still valid outside the container, so this is
* fine
*/
ret = lxc_cgroup_finish_attach(cgroup_data, pid);
if (ret < 0) {
ERROR("failed to attach process to cgroup");
return -1;
}
}
/* tell the child we are done initializing */ /* tell the child we are done initializing */
if (lxc_sync_wake_child(handler, LXC_SYNC_POST_CONFIGURE)) if (lxc_sync_wake_child(handler, LXC_SYNC_POST_CONFIGURE))
@ -175,20 +259,20 @@ int main(int argc, char *argv[])
if (!pid) { if (!pid) {
lxc_sync_fini_parent(handler); lxc_sync_fini_parent(handler);
lxc_cgroup_dispose_attach(cgroup_data);
curdir = get_current_dir_name(); /* A description of the purpose of this functionality is
* provided in the lxc-attach(1) manual page. We have to
ret = lxc_attach_to_ns(init_pid); * remount here and not in the parent process, otherwise
if (ret < 0) { * /proc may not properly reflect the new pid namespace.
ERROR("failed to enter the namespace"); */
return -1; if (!(namespace_flags & CLONE_NEWNS) && remount_sys_proc) {
ret = lxc_attach_remount_sys_proc();
if (ret < 0) {
return -1;
}
} }
if (curdir && chdir(curdir))
WARN("could not change directory to '%s'", curdir);
free(curdir);
if (new_personality < 0) if (new_personality < 0)
new_personality = init_ctx->personality; new_personality = init_ctx->personality;

View File

@ -34,12 +34,14 @@
static bool state; static bool state;
static bool pid; static bool pid;
static char *test_state = NULL;
static int my_parser(struct lxc_arguments* args, int c, char* arg) static int my_parser(struct lxc_arguments* args, int c, char* arg)
{ {
switch (c) { switch (c) {
case 's': state = true; break; case 's': state = true; break;
case 'p': pid = true; break; case 'p': pid = true; break;
case 't': test_state = arg; break;
} }
return 0; return 0;
} }
@ -47,6 +49,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
{"state", no_argument, 0, 's'}, {"state", no_argument, 0, 's'},
{"pid", no_argument, 0, 'p'}, {"pid", no_argument, 0, 'p'},
{"state-is", required_argument, 0, 't'},
LXC_COMMON_OPTIONS, LXC_COMMON_OPTIONS,
}; };
@ -58,9 +61,11 @@ static struct lxc_arguments my_args = {
lxc-info display some information about a container with the identifier NAME\n\ lxc-info display some information about a container with the identifier NAME\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME for name of the container\n\ -n, --name=NAME NAME for name of the container\n\
-s, --state shows the state of the container\n\ -s, --state shows the state of the container\n\
-p, --pid shows the process id of the init container\n", -p, --pid shows the process id of the init container\n\
-t, --state-is=STATE test if current state is STATE\n\
returns success if it matches, false otherwise\n",
.options = my_longopts, .options = my_longopts,
.parser = my_parser, .parser = my_parser,
.checker = NULL, .checker = NULL,
@ -81,10 +86,12 @@ int main(int argc, char *argv[])
if (!state && !pid) if (!state && !pid)
state = pid = true; state = pid = true;
if (state) { if (state || test_state) {
ret = lxc_getstate(my_args.name); ret = lxc_getstate(my_args.name);
if (ret < 0) if (ret < 0)
return 1; return 1;
if (test_state)
return strcmp(lxc_state2str(ret), test_state) != 0;
printf("state:%10s\n", lxc_state2str(ret)); printf("state:%10s\n", lxc_state2str(ret));
} }

View File

@ -102,7 +102,7 @@ int main(int argc, char *argv[])
switch (msg.type) { switch (msg.type) {
case lxc_msg_state: case lxc_msg_state:
printf("'%s' changed state to [%s]\n", printf("'%s' changed state to [%s]\n",
msg.name, lxc_state2str(msg.value)); msg.name, lxc_state2str(msg.value));
break; break;
default: default:

View File

@ -62,6 +62,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
case 'f': args->rcfile = arg; break; case 'f': args->rcfile = arg; break;
case 'C': args->close_all_fds = 1; break; case 'C': args->close_all_fds = 1; break;
case 's': return lxc_config_define_add(&defines, arg); case 's': return lxc_config_define_add(&defines, arg);
case 'p': args->pidfile = arg; break;
} }
return 0; return 0;
} }
@ -72,6 +73,7 @@ static const struct option my_longopts[] = {
{"define", required_argument, 0, 's'}, {"define", required_argument, 0, 's'},
{"console", required_argument, 0, 'c'}, {"console", required_argument, 0, 'c'},
{"close-all-fds", no_argument, 0, 'C'}, {"close-all-fds", no_argument, 0, 'C'},
{"pidfile", required_argument, 0, 'p'},
LXC_COMMON_OPTIONS LXC_COMMON_OPTIONS
}; };
@ -85,6 +87,7 @@ lxc-start start COMMAND in specified container NAME\n\
Options :\n\ Options :\n\
-n, --name=NAME NAME for name of the container\n\ -n, --name=NAME NAME for name of the container\n\
-d, --daemon daemonize the container\n\ -d, --daemon daemonize the container\n\
-p, --pidfile=FILE Create a file with the process id\n\
-f, --rcfile=FILE Load configuration file FILE\n\ -f, --rcfile=FILE Load configuration file FILE\n\
-c, --console=FILE Set the file output for the container console\n\ -c, --console=FILE Set the file output for the container console\n\
-C, --close-all-fds If any fds are inherited, close them\n\ -C, --close-all-fds If any fds are inherited, close them\n\
@ -95,6 +98,7 @@ Options :\n\
.parser = my_parser, .parser = my_parser,
.checker = NULL, .checker = NULL,
.daemonize = 0, .daemonize = 0,
.pidfile = NULL,
}; };
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -107,6 +111,7 @@ int main(int argc, char *argv[])
"/sbin/init", "/sbin/init",
'\0', '\0',
}; };
FILE *pid_fp = NULL;
lxc_list_init(&defines); lxc_list_init(&defines);
@ -117,7 +122,7 @@ int main(int argc, char *argv[])
return err; return err;
if (!my_args.argc) if (!my_args.argc)
args = default_args; args = default_args;
else else
args = my_args.argv; args = my_args.argv;
@ -199,6 +204,15 @@ int main(int argc, char *argv[])
free(console); free(console);
} }
if (my_args.pidfile != NULL) {
pid_fp = fopen(my_args.pidfile, "w");
if (pid_fp == NULL) {
SYSERROR("failed to create pidfile '%s' for '%s'",
my_args.pidfile, my_args.name);
return err;
}
}
if (my_args.daemonize) { if (my_args.daemonize) {
/* do an early check for needed privs, since otherwise the /* do an early check for needed privs, since otherwise the
* user won't see the error */ * user won't see the error */
@ -214,6 +228,14 @@ int main(int argc, char *argv[])
} }
} }
if (pid_fp != NULL) {
if (fprintf(pid_fp, "%d\n", getpid()) < 0) {
SYSERROR("failed to write '%s'", my_args.pidfile);
return err;
}
fclose(pid_fp);
}
if (my_args.close_all_fds) if (my_args.close_all_fds)
conf->close_all_fds = 1; conf->close_all_fds = 1;
@ -230,6 +252,9 @@ int main(int argc, char *argv[])
err = -1; err = -1;
} }
if (my_args.pidfile)
unlink(my_args.pidfile);
return err; return err;
} }

View File

@ -84,51 +84,6 @@ static uid_t lookup_user(const char *optarg)
return uid; return uid;
} }
static char *namespaces_list[] = {
"MOUNT", "PID", "UTSNAME", "IPC",
"USER", "NETWORK"
};
static int cloneflags_list[] = {
CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
CLONE_NEWUSER, CLONE_NEWNET
};
static int lxc_namespace_2_cloneflag(char *namespace)
{
int i, len;
len = sizeof(namespaces_list)/sizeof(namespaces_list[0]);
for (i = 0; i < len; i++)
if (!strcmp(namespaces_list[i], namespace))
return cloneflags_list[i];
ERROR("invalid namespace name %s", namespace);
return -1;
}
static int lxc_fill_namespace_flags(char *flaglist, int *flags)
{
char *token, *saveptr = NULL;
int aflag;
if (!flaglist) {
ERROR("need at least one namespace to unshare");
return -1;
}
token = strtok_r(flaglist, "|", &saveptr);
while (token) {
aflag = lxc_namespace_2_cloneflag(token);
if (aflag < 0)
return -1;
*flags |= aflag;
token = strtok_r(NULL, "|", &saveptr);
}
return 0;
}
struct start_arg { struct start_arg {
char ***args; char ***args;

View File

@ -24,6 +24,8 @@
#include <string.h> #include <string.h>
#include <libgen.h> #include <libgen.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h> #include <sys/types.h>
#include <lxc/lxc.h> #include <lxc/lxc.h>
@ -46,12 +48,14 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
{ {
switch (c) { switch (c) {
case 's': args->states = optarg; break; case 's': args->states = optarg; break;
case 't': args->timeout = atol(optarg); break;
} }
return 0; return 0;
} }
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
{"state", required_argument, 0, 's'}, {"state", required_argument, 0, 's'},
{"timeout", required_argument, 0, 't'},
LXC_COMMON_OPTIONS LXC_COMMON_OPTIONS
}; };
@ -66,37 +70,16 @@ Options :\n\
-n, --name=NAME NAME for name of the container\n\ -n, --name=NAME NAME for name of the container\n\
-s, --state=STATE ORed states to wait for\n\ -s, --state=STATE ORed states to wait for\n\
STOPPED, STARTING, RUNNING, STOPPING,\n\ STOPPED, STARTING, RUNNING, STOPPING,\n\
ABORTING, FREEZING, FROZEN\n", ABORTING, FREEZING, FROZEN\n\
-t, --timeout=TMO Seconds to wait for state changes\n",
.options = my_longopts, .options = my_longopts,
.parser = my_parser, .parser = my_parser,
.checker = my_checker, .checker = my_checker,
.timeout = -1,
}; };
static int fillwaitedstates(char *strstates, int *states)
{
char *token, *saveptr = NULL;
int state;
token = strtok_r(strstates, "|", &saveptr);
while (token) {
state = lxc_str2state(token);
if (state < 0)
return -1;
states[state] = 1;
token = strtok_r(NULL, "|", &saveptr);
}
return 0;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct lxc_msg msg;
int s[MAX_STATE] = { }, fd;
int state, ret;
if (lxc_arguments_parse(&my_args, argc, argv)) if (lxc_arguments_parse(&my_args, argc, argv))
return -1; return -1;
@ -104,53 +87,5 @@ int main(int argc, char *argv[])
my_args.progname, my_args.quiet)) my_args.progname, my_args.quiet))
return -1; return -1;
if (fillwaitedstates(my_args.states, s)) return lxc_wait(strdup(my_args.name), my_args.states, my_args.timeout);
return -1;
fd = lxc_monitor_open();
if (fd < 0)
return -1;
/*
* if container present,
* then check if already in requested state
*/
ret = -1;
state = lxc_getstate(my_args.name);
if (state < 0) {
goto out_close;
} else if ((state >= 0) && (s[state])) {
ret = 0;
goto out_close;
}
for (;;) {
if (lxc_monitor_read(fd, &msg) < 0)
goto out_close;
if (strcmp(my_args.name, msg.name))
continue;
switch (msg.type) {
case lxc_msg_state:
if (msg.value < 0 || msg.value >= MAX_STATE) {
ERROR("Receive an invalid state number '%d'",
msg.value);
goto out_close;
}
if (s[msg.value]) {
ret = 0;
goto out_close;
}
break;
default:
/* just ignore garbage */
break;
}
}
out_close:
lxc_monitor_close(fd);
return ret;
} }

1001
src/lxc/lxccontainer.c Normal file

File diff suppressed because it is too large Load Diff

79
src/lxc/lxccontainer.h Normal file
View File

@ -0,0 +1,79 @@
#include "lxclock.h"
#include <stdlib.h>
#include <malloc.h>
#include <stdbool.h>
struct lxc_container {
// private fields
char *name;
char *configfile;
sem_t *slock;
sem_t *privlock;
int numthreads; /* protected by privlock. */
struct lxc_conf *lxc_conf; // maybe we'll just want the whole lxc_handler?
// public fields
char *error_string;
int error_num;
int daemonize;
bool (*is_defined)(struct lxc_container *c); // did /var/lib/lxc/$name/config exist
const char *(*state)(struct lxc_container *c);
bool (*is_running)(struct lxc_container *c); // true so long as defined and not stopped
bool (*freeze)(struct lxc_container *c);
bool (*unfreeze)(struct lxc_container *c);
pid_t (*init_pid)(struct lxc_container *c);
bool (*load_config)(struct lxc_container *c, const char *alt_file);
/* The '...' is the command line. If provided, it must be ended with a NULL */
bool (*start)(struct lxc_container *c, int useinit, char * const argv[]);
bool (*startl)(struct lxc_container *c, int useinit, ...);
bool (*stop)(struct lxc_container *c);
void (*want_daemonize)(struct lxc_container *c);
// Return current config file name. The result is strdup()d, so free the result.
char *(*config_file_name)(struct lxc_container *c);
// for wait, timeout == -1 means wait forever, timeout == 0 means don't wait.
// otherwise timeout is seconds to wait.
bool (*wait)(struct lxc_container *c, const char *state, int timeout);
bool (*set_config_item)(struct lxc_container *c, const char *key, const char *value);
bool (*destroy)(struct lxc_container *c);
bool (*save_config)(struct lxc_container *c, const char *alt_file);
bool (*create)(struct lxc_container *c, char *t, char *const argv[]);
bool (*createl)(struct lxc_container *c, char *t, ...);
/* send SIGPWR. if timeout is not 0 or -1, do a hard stop after timeout seconds */
bool (*shutdown)(struct lxc_container *c, int timeout);
/* clear all network or capability items in the in-memory configuration */
bool (*clear_config_item)(struct lxc_container *c, const char *key);
/* print a config item to a in-memory string allocated by the caller. Return
* the length which was our would be printed. */
int (*get_config_item)(struct lxc_container *c, const char *key, char *retv, int inlen);
int (*get_keys)(struct lxc_container *c, const char *key, char *retv, int inlen);
/*
* get_cgroup_item returns the number of bytes read, or an error (<0).
* If retv NULL or inlen 0 is passed in, then the length of the cgroup
* file will be returned. * Otherwise it will return the # of bytes read.
* If inlen is less than the number of bytes available, then the returned
* value will be inlen, not the full available size of the file.
*/
int (*get_cgroup_item)(struct lxc_container *c, const char *subsys, char *retv, int inlen);
bool (*set_cgroup_item)(struct lxc_container *c, const char *subsys, const char *value);
#if 0
bool (*commit_cgroups)(struct lxc_container *c);
bool (*reread_cgroups)(struct lxc_container *c);
// question with clone: how do we handle non-standard config file in orig?
struct lxc_container (*clone)(struct container *c);
int (*ns_attach)(struct lxc_container *c, int ns_mask);
// we'll need some plumbing to support lxc-console
#endif
};
struct lxc_container *lxc_container_new(const char *name);
int lxc_container_get(struct lxc_container *c);
int lxc_container_put(struct lxc_container *c);
int lxc_get_wait_states(const char **states);
#if 0
char ** lxc_get_valid_keys();
char ** lxc_get_valid_values(char *key);
#endif

105
src/lxc/lxclock.c Normal file
View File

@ -0,0 +1,105 @@
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "lxclock.h"
#include <malloc.h>
#define OFLAG (O_CREAT | O_RDWR)
#define SEMMODE 0660
#define SEMVALUE 1
#define SEMVALUE_LOCKED 0
#define LXCLOCK_PREFIX "/lxcapi."
static char *lxclock_name(const char *container)
{
int ret;
int len = strlen(container) + strlen(LXCLOCK_PREFIX) + 1;
char *dest = malloc(len);
if (!dest)
return NULL;
ret = snprintf(dest, len, "%s%s", LXCLOCK_PREFIX, container);
if (ret < 0 || ret >= len) {
free(dest);
return NULL;
}
return dest;
}
static void lxcfree_name(char *name)
{
if (name)
free(name);
}
static sem_t *lxc_new_unnamed_sem(void)
{
sem_t *s;
int ret;
s = malloc(sizeof(*s));
if (!s)
return NULL;
ret = sem_init(s, 0, 1);
if (ret)
return NULL;
return s;
}
sem_t *lxc_newlock(const char *name)
{
char *lname;
sem_t *lock;
if (!name)
return lxc_new_unnamed_sem();
lname = lxclock_name(name);
if (!lname)
return NULL;
lock = sem_open(lname, OFLAG, SEMMODE, SEMVALUE);
lxcfree_name(lname);
if (lock == SEM_FAILED)
return NULL;
return lock;
}
int lxclock(sem_t *sem, int timeout)
{
int ret;
if (!timeout) {
ret = sem_wait(sem);
} else {
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
return -2;
ts.tv_sec += timeout;
ret = sem_timedwait(sem, &ts);
}
return ret;
}
int lxcunlock(sem_t *sem)
{
if (!sem)
return -2;
return sem_post(sem);
}

61
src/lxc/lxclock.h Normal file
View File

@ -0,0 +1,61 @@
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <semaphore.h>
#include <string.h>
#include <time.h>
/*
* lxc_newlock:
* if name is not given, create an unnamed semaphore. We use these
* to protect against racing threads.
* Note that an unnamed sem was malloced by us and needs to be freed.
*
* If name is given, it is prepended with '/lxcapi.', and used as the
* name for a system-wide (well, ipcns-wide) semaphore. We use that
* to protect the containers as represented on disk.
* A named sem should not be freed.
*
* XXX TODO
* We should probably introduce a lxclock_close() which detecs the type
* of lock and calls sem_close() or sem_destroy()+free() not as appropriate.
* For now, it is up to the caller to do so.
*
* sem is initialized to value of 1
*
* return NULL on failure, else a sem_t * which can be passed to
* lxclock() and lxcunlock().
*/
extern sem_t *lxc_newlock(const char *name);
/*
* lxclock: take an existing lock. If timeout is 0, wait
* indefinately. Otherwise use given timeout.
* return 0 if we got the lock, -2 on failure to set timeout, or -1
* otherwise in which case errno will be set by sem_wait()).
*/
extern int lxclock(sem_t *sem, int timeout);
/*
* lxcunlock: unlock given sem. Return 0 on success. Otherwise returns
* -1 and sem_post will leave errno set.
*/
extern int lxcunlock(sem_t *lock);

49
src/lxc/lxcseccomp.h Normal file
View File

@ -0,0 +1,49 @@
/*
* lxc: linux Container library
*
* (C) Copyright Canonical, Inc. 2012
*
* 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
*/
#ifndef _lxc_seccomp_h
#include "conf.h"
#ifdef HAVE_SECCOMP
int lxc_seccomp_load(struct lxc_conf *conf);
int lxc_read_seccomp_config(struct lxc_conf *conf);
void lxc_seccomp_free(struct lxc_conf *conf);
#else
static inline int lxc_seccomp_load(struct lxc_conf *conf) {
return 0;
}
static inline int lxc_read_seccomp_config(struct lxc_conf *conf) {
return 0;
}
static inline void lxc_seccomp_free(struct lxc_conf *conf) {
if (conf->seccomp) {
free(conf->seccomp);
conf->seccomp = NULL;
}
}
#endif
#endif

View File

@ -59,7 +59,7 @@ int lxc_mainloop(struct lxc_epoll_descr *descr)
/* If the handler returns a positive value, exit /* If the handler returns a positive value, exit
the mainloop */ the mainloop */
if (handler->callback(handler->fd, handler->data, if (handler->callback(handler->fd, handler->data,
descr) > 0) descr) > 0)
return 0; return 0;
} }
@ -69,7 +69,7 @@ int lxc_mainloop(struct lxc_epoll_descr *descr)
} }
} }
int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd, int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd,
lxc_mainloop_callback_t callback, void *data) lxc_mainloop_callback_t callback, void *data)
{ {
struct epoll_event ev; struct epoll_event ev;

View File

@ -28,13 +28,13 @@ struct lxc_epoll_descr {
struct lxc_list handlers; struct lxc_list handlers;
}; };
typedef int (*lxc_mainloop_callback_t)(int fd, void *data, typedef int (*lxc_mainloop_callback_t)(int fd, void *data,
struct lxc_epoll_descr *descr); struct lxc_epoll_descr *descr);
extern int lxc_mainloop(struct lxc_epoll_descr *descr); extern int lxc_mainloop(struct lxc_epoll_descr *descr);
extern int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd, extern int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd,
lxc_mainloop_callback_t callback, lxc_mainloop_callback_t callback,
void *data); void *data);
extern int lxc_mainloop_del_handler(struct lxc_epoll_descr *descr, int fd); extern int lxc_mainloop_del_handler(struct lxc_epoll_descr *descr, int fd);

View File

@ -98,11 +98,28 @@ int lxc_monitor_open(void)
return fd; return fd;
} }
int lxc_monitor_read(int fd, struct lxc_msg *msg) /* timeout of 0 means return immediately; -1 means wait forever */
int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout)
{ {
struct sockaddr_un from; struct sockaddr_un from;
socklen_t len = sizeof(from); socklen_t len = sizeof(from);
int ret; int ret;
fd_set rfds;
struct timeval tv;
if (timeout != -1) {
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
tv.tv_sec = timeout;
tv.tv_usec = 0;
ret = select(fd+1, &rfds, NULL, NULL, &tv);
if (ret == -1)
return -1;
else if (!ret)
return -2; // timed out
}
ret = recvfrom(fd, msg, sizeof(*msg), 0, ret = recvfrom(fd, msg, sizeof(*msg), 0,
(struct sockaddr *)&from, &len); (struct sockaddr *)&from, &len);
@ -114,6 +131,11 @@ int lxc_monitor_read(int fd, struct lxc_msg *msg)
return ret; return ret;
} }
int lxc_monitor_read(int fd, struct lxc_msg *msg)
{
return lxc_monitor_read_timeout(fd, msg, -1);
}
int lxc_monitor_close(int fd) int lxc_monitor_close(int fd)
{ {
return close(fd); return close(fd);

View File

@ -69,3 +69,48 @@ pid_t lxc_clone(int (*fn)(void *), void *arg, int flags)
return ret; return ret;
} }
static char *namespaces_list[] = {
"MOUNT", "PID", "UTSNAME", "IPC",
"USER", "NETWORK"
};
static int cloneflags_list[] = {
CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
CLONE_NEWUSER, CLONE_NEWNET
};
int lxc_namespace_2_cloneflag(char *namespace)
{
int i, len;
len = sizeof(namespaces_list)/sizeof(namespaces_list[0]);
for (i = 0; i < len; i++)
if (!strcmp(namespaces_list[i], namespace))
return cloneflags_list[i];
ERROR("invalid namespace name %s", namespace);
return -1;
}
int lxc_fill_namespace_flags(char *flaglist, int *flags)
{
char *token, *saveptr = NULL;
int aflag;
if (!flaglist) {
ERROR("need at least one namespace to unshare");
return -1;
}
token = strtok_r(flaglist, "|", &saveptr);
while (token) {
aflag = lxc_namespace_2_cloneflag(token);
if (aflag < 0)
return -1;
*flags |= aflag;
token = strtok_r(NULL, "|", &saveptr);
}
return 0;
}

View File

@ -54,4 +54,7 @@ int clone(int (*fn)(void *), void *child_stack,
extern pid_t lxc_clone(int (*fn)(void *), void *arg, int flags); extern pid_t lxc_clone(int (*fn)(void *), void *arg, int flags);
extern int lxc_namespace_2_cloneflag(char *namespace);
extern int lxc_fill_namespace_flags(char *flaglist, int *flags);
#endif #endif

View File

@ -47,6 +47,7 @@
#include "nl.h" #include "nl.h"
#include "network.h" #include "network.h"
#include "conf.h"
#ifndef IFLA_LINKMODE #ifndef IFLA_LINKMODE
# define IFLA_LINKMODE 17 # define IFLA_LINKMODE 17
@ -1004,3 +1005,18 @@ int lxc_bridge_attach(const char *bridge, const char *ifname)
return err; return err;
} }
static char* lxc_network_types[LXC_NET_MAXCONFTYPE + 1] = {
[LXC_NET_VETH] = "veth",
[LXC_NET_MACVLAN] = "macvlan",
[LXC_NET_VLAN] = "vlan",
[LXC_NET_PHYS] = "phys",
[LXC_NET_EMPTY] = "empty",
};
const char *lxc_net_type_to_str(int type)
{
if (type < 0 || type > LXC_NET_MAXCONFTYPE)
return NULL;
return lxc_network_types[type];
}

View File

@ -100,7 +100,7 @@ extern int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw);
*/ */
extern int lxc_bridge_attach(const char *bridge, const char *ifname); extern int lxc_bridge_attach(const char *bridge, const char *ifname);
/* /*
* Create default gateway * Create default gateway
*/ */
extern int lxc_route_create_default(const char *addr, const char *ifname, extern int lxc_route_create_default(const char *addr, const char *ifname,
@ -122,4 +122,5 @@ extern int lxc_neigh_proxy_on(const char *name, int family);
*/ */
extern int lxc_neigh_proxy_off(const char *name, int family); extern int lxc_neigh_proxy_off(const char *name, int family);
extern const char *lxc_net_type_to_str(int type);
#endif #endif

View File

@ -48,7 +48,7 @@ extern void *nlmsg_data(struct nlmsg *nlmsg)
return data; return data;
} }
static int nla_put(struct nlmsg *nlmsg, int attr, static int nla_put(struct nlmsg *nlmsg, int attr,
const void *data, size_t len) const void *data, size_t len)
{ {
struct rtattr *rta; struct rtattr *rta;
@ -63,7 +63,7 @@ static int nla_put(struct nlmsg *nlmsg, int attr,
return 0; return 0;
} }
extern int nla_put_buffer(struct nlmsg *nlmsg, int attr, extern int nla_put_buffer(struct nlmsg *nlmsg, int attr,
const void *data, size_t size) const void *data, size_t size)
{ {
return nla_put(nlmsg, attr, data, size); return nla_put(nlmsg, attr, data, size);
@ -193,7 +193,7 @@ extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg)
#ifndef NLMSG_ERROR #ifndef NLMSG_ERROR
#define NLMSG_ERROR 0x2 #define NLMSG_ERROR 0x2
#endif #endif
extern int netlink_transaction(struct nl_handler *handler, extern int netlink_transaction(struct nl_handler *handler,
struct nlmsg *request, struct nlmsg *answer) struct nlmsg *request, struct nlmsg *answer)
{ {
int ret; int ret;
@ -226,11 +226,11 @@ extern int netlink_open(struct nl_handler *handler, int protocol)
if (handler->fd < 0) if (handler->fd < 0)
return -errno; return -errno;
if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF, if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF,
&sndbuf, sizeof(sndbuf)) < 0) &sndbuf, sizeof(sndbuf)) < 0)
return -errno; return -errno;
if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF, if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF,
&rcvbuf,sizeof(rcvbuf)) < 0) &rcvbuf,sizeof(rcvbuf)) < 0)
return -errno; return -errno;
@ -238,12 +238,12 @@ extern int netlink_open(struct nl_handler *handler, int protocol)
handler->local.nl_family = AF_NETLINK; handler->local.nl_family = AF_NETLINK;
handler->local.nl_groups = 0; handler->local.nl_groups = 0;
if (bind(handler->fd, (struct sockaddr*)&handler->local, if (bind(handler->fd, (struct sockaddr*)&handler->local,
sizeof(handler->local)) < 0) sizeof(handler->local)) < 0)
return -errno; return -errno;
socklen = sizeof(handler->local); socklen = sizeof(handler->local);
if (getsockname(handler->fd, (struct sockaddr*)&handler->local, if (getsockname(handler->fd, (struct sockaddr*)&handler->local,
&socklen) < 0) &socklen) < 0)
return -errno; return -errno;

View File

@ -39,7 +39,7 @@
* struct nl_handler : the handler for netlink sockets, this structure * struct nl_handler : the handler for netlink sockets, this structure
* is used all along the netlink socket life cycle to specify the * is used all along the netlink socket life cycle to specify the
* netlink socket to be used. * netlink socket to be used.
* *
* @fd: the file descriptor of the netlink socket * @fd: the file descriptor of the netlink socket
* @seq: the sequence number of the netlink messages * @seq: the sequence number of the netlink messages
* @local: the bind address * @local: the bind address
@ -77,7 +77,7 @@ struct nlmsg {
int netlink_open(struct nl_handler *handler, int protocol); int netlink_open(struct nl_handler *handler, int protocol);
/* /*
* netlink_close : close a netlink socket, after this call, * netlink_close : close a netlink socket, after this call,
* the handler is no longer valid * the handler is no longer valid
* *
* @handler: a handler to the netlink socket * @handler: a handler to the netlink socket
@ -87,8 +87,8 @@ int netlink_open(struct nl_handler *handler, int protocol);
int netlink_close(struct nl_handler *handler); int netlink_close(struct nl_handler *handler);
/* /*
* netlink_rcv : receive a netlink message from the kernel. * netlink_rcv : receive a netlink message from the kernel.
* It is up to the caller to manage the allocation of the * It is up to the caller to manage the allocation of the
* netlink message * netlink message
* *
* @handler: a handler to the netlink socket * @handler: a handler to the netlink socket
@ -110,8 +110,8 @@ int netlink_rcv(struct nl_handler *handler, struct nlmsg *nlmsg);
int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg); int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg);
/* /*
* netlink_transaction: send a request to the kernel and read the response. * netlink_transaction: send a request to the kernel and read the response.
* This is useful for transactional protocol. It is up to the caller * This is useful for transactional protocol. It is up to the caller
* to manage the allocation of the netlink message. * to manage the allocation of the netlink message.
* *
* @handler: a handler to a opened netlink socket * @handler: a handler to a opened netlink socket
@ -120,11 +120,11 @@ int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg);
* *
* Returns 0 on success, < 0 otherwise * Returns 0 on success, < 0 otherwise
*/ */
int netlink_transaction(struct nl_handler *handler, int netlink_transaction(struct nl_handler *handler,
struct nlmsg *request, struct nlmsg *anwser); struct nlmsg *request, struct nlmsg *anwser);
/* /*
* nla_put_string: copy a null terminated string to a netlink message * nla_put_string: copy a null terminated string to a netlink message
* attribute * attribute
* *
* @nlmsg: the netlink message to be filled * @nlmsg: the netlink message to be filled
@ -146,7 +146,7 @@ int nla_put_string(struct nlmsg *nlmsg, int attr, const char *string);
* *
* Returns 0 on success, < 0 otherwise * Returns 0 on success, < 0 otherwise
*/ */
int nla_put_buffer(struct nlmsg *nlmsg, int attr, int nla_put_buffer(struct nlmsg *nlmsg, int attr,
const void *data, size_t size); const void *data, size_t size);
/* /*
@ -172,7 +172,7 @@ int nla_put_u32(struct nlmsg *nlmsg, int attr, int value);
int nla_put_u16(struct nlmsg *nlmsg, int attr, ushort value); int nla_put_u16(struct nlmsg *nlmsg, int attr, ushort value);
/* /*
* nla_put_attr: add an attribute name to a netlink * nla_put_attr: add an attribute name to a netlink
* *
* @nlmsg: the netlink message to be filled * @nlmsg: the netlink message to be filled
* @attr: the attribute name of the integer * @attr: the attribute name of the integer
@ -185,7 +185,7 @@ int nla_put_attr(struct nlmsg *nlmsg, int attr);
* nla_begin_nested: begin the nesting attribute * nla_begin_nested: begin the nesting attribute
* *
* @nlmsg: the netlink message to be filled * @nlmsg: the netlink message to be filled
* @attr: the netsted attribute name * @attr: the netsted attribute name
* *
* Returns current nested pointer to be reused * Returns current nested pointer to be reused
* to nla_end_nested. * to nla_end_nested.
@ -198,17 +198,17 @@ struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr);
* @nlmsg: the netlink message * @nlmsg: the netlink message
* @nested: the nested pointer * @nested: the nested pointer
* *
* Returns the current * Returns the current
*/ */
void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr); void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr);
/* /*
* nlmsg_allocate : allocate a netlink message. The netlink format message * nlmsg_allocate : allocate a netlink message. The netlink format message
* is a header, a padding, a payload and a padding again. * is a header, a padding, a payload and a padding again.
* When a netlink message is allocated, the size specify the * When a netlink message is allocated, the size specify the
* payload we want. So the real size of the allocated message * payload we want. So the real size of the allocated message
* is sizeof(header) + sizeof(padding) + payloadsize + sizeof(padding), * is sizeof(header) + sizeof(padding) + payloadsize + sizeof(padding),
* in other words, the function will allocate more than specified. When * in other words, the function will allocate more than specified. When
* the buffer is allocated, the content is zeroed. * the buffer is allocated, the content is zeroed.
* The function will also fill the field nlmsg_len with computed size. * The function will also fill the field nlmsg_len with computed size.
* If the allocation must be for the specified size, just use malloc. * If the allocation must be for the specified size, just use malloc.
@ -228,7 +228,7 @@ void nlmsg_free(struct nlmsg *nlmsg);
/* /*
* nlmsg_data : returns a pointer to the data contained in the netlink message * nlmsg_data : returns a pointer to the data contained in the netlink message
* *
* @nlmsg : the netlink message to get the data * @nlmsg : the netlink message to get the data
* *
* Returns a pointer to the netlink data or NULL if there is no data * Returns a pointer to the netlink data or NULL if there is no data

View File

@ -53,7 +53,7 @@ extern int rtnetlink_send(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg)
return netlink_send(&handler->nlh, (struct nlmsg *)&rtnlmsg->nlmsghdr); return netlink_send(&handler->nlh, (struct nlmsg *)&rtnlmsg->nlmsghdr);
} }
extern int rtnetlink_transaction(struct rtnl_handler *handler, extern int rtnetlink_transaction(struct rtnl_handler *handler,
struct rtnlmsg *request, struct rtnlmsg *answer) struct rtnlmsg *request, struct rtnlmsg *answer)
{ {
return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr, return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr,

View File

@ -30,7 +30,7 @@
#define RTNLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + RTNL_HDRLEN)) #define RTNLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + RTNL_HDRLEN))
/* /*
* struct genl_handler : the structure which store the netlink handler * struct genl_handler : the structure which store the netlink handler
* and the family number * and the family number
* *
* @nlh: the netlink socket handler * @nlh: the netlink socket handler
@ -105,6 +105,6 @@ void rtnlmsg_free(struct rtnlmsg *rtnlmsg);
* *
* Returns 0 on success, < 0 otherwise * Returns 0 on success, < 0 otherwise
*/ */
int rtnetlink_transaction(struct rtnl_handler *handler, int rtnetlink_transaction(struct rtnl_handler *handler,
struct rtnlmsg *request, struct rtnlmsg *answer); struct rtnlmsg *request, struct rtnlmsg *answer);
#endif #endif

155
src/lxc/seccomp.c Normal file
View File

@ -0,0 +1,155 @@
/*
* lxc: linux Container library
*
* (C) Copyright Canonical, Inc. 2012
*
* 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
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <seccomp.h>
#include <errno.h>
#include <seccomp.h>
#include "config.h"
#include "lxcseccomp.h"
#include "log.h"
lxc_log_define(lxc_seccomp, lxc);
/*
* The first line of the config file has a policy language version
* the second line has some directives
* then comes policy subject to the directives
* right now version must be '1'
* the directives must include 'whitelist' (only type of policy currently
* supported) and can include 'debug' (though debug is not yet supported).
*/
static int parse_config(FILE *f, struct lxc_conf *conf)
{
char line[1024];
int ret, version;
ret = fscanf(f, "%d\n", &version);
if (ret != 1 || version != 1) {
ERROR("invalid version");
return -1;
}
if (!fgets(line, 1024, f)) {
ERROR("invalid config file");
return -1;
}
if (!strstr(line, "whitelist")) {
ERROR("only whitelist policy is supported");
return -1;
}
if (strstr(line, "debug")) {
ERROR("debug not yet implemented");
return -1;
}
/* now read in the whitelist entries one per line */
while (fgets(line, 1024, f)) {
int nr;
ret = sscanf(line, "%d", &nr);
if (ret != 1)
return -1;
ret = seccomp_rule_add(
#if HAVE_SCMP_FILTER_CTX
conf->seccomp_ctx,
#endif
SCMP_ACT_ALLOW, nr, 0);
if (ret < 0) {
ERROR("failed loading allow rule for %d\n", nr);
return ret;
}
}
return 0;
}
int lxc_read_seccomp_config(struct lxc_conf *conf)
{
FILE *f;
int ret;
if (!conf->seccomp)
return 0;
#if HAVE_SCMP_FILTER_CTX
/* XXX for debug, pass in SCMP_ACT_TRAP */
conf->seccomp_ctx = seccomp_init(SCMP_ACT_ERRNO(31));
ret = !conf->seccomp_ctx;
#else
ret = seccomp_init(SCMP_ACT_ERRNO(31)) < 0;
#endif
if (ret) {
ERROR("failed initializing seccomp");
return -1;
}
/* turn of no-new-privs. We don't want it in lxc, and it breaks
* with apparmor */
if (seccomp_attr_set(
#if HAVE_SCMP_FILTER_CTX
conf->seccomp_ctx,
#endif
SCMP_FLTATR_CTL_NNP, 0)) {
ERROR("failed to turn off n-new-privs\n");
return -1;
}
f = fopen(conf->seccomp, "r");
if (!f) {
SYSERROR("failed to open seccomp policy file %s\n", conf->seccomp);
return -1;
}
ret = parse_config(f, conf);
fclose(f);
return ret;
}
int lxc_seccomp_load(struct lxc_conf *conf)
{
int ret;
if (!conf->seccomp)
return 0;
ret = seccomp_load(
#if HAVE_SCMP_FILTER_CTX
conf->seccomp_ctx
#endif
);
if (ret < 0) {
ERROR("Error loading the seccomp policy");
return -1;
}
return 0;
}
void lxc_seccomp_free(struct lxc_conf *conf) {
if (conf->seccomp) {
free(conf->seccomp);
conf->seccomp = NULL;
}
#if HAVE_SCMP_FILTER_CTX
if (conf->seccomp_ctx) {
seccomp_release(conf->seccomp_ctx);
conf->seccomp_ctx = NULL;
}
#endif
}

View File

@ -127,6 +127,7 @@ int signalfd(int fd, const sigset_t *mask, int flags)
#include "sync.h" #include "sync.h"
#include "namespace.h" #include "namespace.h"
#include "apparmor.h" #include "apparmor.h"
#include "lxcseccomp.h"
lxc_log_define(lxc_start, lxc); lxc_log_define(lxc_start, lxc);
@ -278,6 +279,29 @@ int lxc_pid_callback(int fd, struct lxc_request *request,
return 0; return 0;
} }
int lxc_clone_flags_callback(int fd, struct lxc_request *request,
struct lxc_handler *handler)
{
struct lxc_answer answer;
int ret;
answer.pid = 0;
answer.ret = handler->clone_flags;
ret = send(fd, &answer, sizeof(answer), 0);
if (ret < 0) {
WARN("failed to send answer to the peer");
return -1;
}
if (ret != sizeof(answer)) {
ERROR("partial answer sent");
return -1;
}
return 0;
}
int lxc_set_state(const char *name, struct lxc_handler *handler, lxc_state_t state) int lxc_set_state(const char *name, struct lxc_handler *handler, lxc_state_t state)
{ {
handler->state = state; handler->state = state;
@ -353,6 +377,11 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf)
goto out_free; goto out_free;
} }
if (lxc_read_seccomp_config(conf) != 0) {
ERROR("failed loading seccomp policy");
goto out_free_name;
}
/* Begin the set the state to STARTING*/ /* Begin the set the state to STARTING*/
if (lxc_set_state(name, handler, STARTING)) { if (lxc_set_state(name, handler, STARTING)) {
ERROR("failed to set state '%s'", lxc_state2str(STARTING)); ERROR("failed to set state '%s'", lxc_state2str(STARTING));
@ -530,6 +559,9 @@ static int do_start(void *data)
if (apparmor_load(handler) < 0) if (apparmor_load(handler) < 0)
goto out_warn_father; goto out_warn_father;
if (lxc_seccomp_load(handler->conf) != 0)
goto out_warn_father;
if (run_lxc_hooks(handler->name, "start", handler->conf)) { if (run_lxc_hooks(handler->name, "start", handler->conf)) {
ERROR("failed to run start hooks for container '%s'.", handler->name); ERROR("failed to run start hooks for container '%s'.", handler->name);
goto out_warn_father; goto out_warn_father;
@ -547,9 +579,39 @@ out_warn_father:
return -1; return -1;
} }
int save_phys_nics(struct lxc_conf *conf)
{
struct lxc_list *iterator;
lxc_list_for_each(iterator, &conf->network) {
struct lxc_netdev *netdev = iterator->elem;
if (netdev->type != LXC_NET_PHYS)
continue;
conf->saved_nics = realloc(conf->saved_nics,
(conf->num_savednics+1)*sizeof(struct saved_nic));
if (!conf->saved_nics) {
SYSERROR("failed to allocate memory");
return -1;
}
conf->saved_nics[conf->num_savednics].ifindex = netdev->ifindex;
conf->saved_nics[conf->num_savednics].orig_name = strdup(netdev->link);
if (!conf->saved_nics[conf->num_savednics].orig_name) {
SYSERROR("failed to allocate memory");
return -1;
}
INFO("stored saved_nic #%d idx %d name %s\n", conf->num_savednics,
conf->saved_nics[conf->num_savednics].ifindex,
conf->saved_nics[conf->num_savednics].orig_name);
conf->num_savednics++;
}
return 0;
}
int lxc_spawn(struct lxc_handler *handler) int lxc_spawn(struct lxc_handler *handler)
{ {
int clone_flags;
int failed_before_rename = 0; int failed_before_rename = 0;
const char *name = handler->name; const char *name = handler->name;
int pinfd; int pinfd;
@ -557,10 +619,10 @@ int lxc_spawn(struct lxc_handler *handler)
if (lxc_sync_init(handler)) if (lxc_sync_init(handler))
return -1; return -1;
clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS; handler->clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS;
if (!lxc_list_empty(&handler->conf->network)) { if (!lxc_list_empty(&handler->conf->network)) {
clone_flags |= CLONE_NEWNET; handler->clone_flags |= CLONE_NEWNET;
/* Find gateway addresses from the link device, which is /* Find gateway addresses from the link device, which is
* no longer accessible inside the container. Do this * no longer accessible inside the container. Do this
@ -582,6 +644,11 @@ int lxc_spawn(struct lxc_handler *handler)
} }
} }
if (save_phys_nics(handler->conf)) {
ERROR("failed to save physical nic info");
goto out_abort;
}
/* /*
* if the rootfs is not a blockdev, prevent the container from * if the rootfs is not a blockdev, prevent the container from
* marking it readonly. * marking it readonly.
@ -594,7 +661,7 @@ int lxc_spawn(struct lxc_handler *handler)
} }
/* Create a process in a new set of namespaces */ /* Create a process in a new set of namespaces */
handler->pid = lxc_clone(do_start, handler, clone_flags); handler->pid = lxc_clone(do_start, handler, handler->clone_flags);
if (handler->pid < 0) { if (handler->pid < 0) {
SYSERROR("failed to fork into a new namespace"); SYSERROR("failed to fork into a new namespace");
goto out_delete_net; goto out_delete_net;
@ -612,7 +679,7 @@ int lxc_spawn(struct lxc_handler *handler)
goto out_delete_net; goto out_delete_net;
/* Create the network configuration */ /* Create the network configuration */
if (clone_flags & CLONE_NEWNET) { if (handler->clone_flags & CLONE_NEWNET) {
if (lxc_assign_network(&handler->conf->network, handler->pid)) { if (lxc_assign_network(&handler->conf->network, handler->pid)) {
ERROR("failed to create the configured network"); ERROR("failed to create the configured network");
goto out_delete_net; goto out_delete_net;
@ -642,8 +709,8 @@ int lxc_spawn(struct lxc_handler *handler)
return 0; return 0;
out_delete_net: out_delete_net:
if (clone_flags & CLONE_NEWNET) if (handler->clone_flags & CLONE_NEWNET)
lxc_delete_network(&handler->conf->network); lxc_delete_network(handler);
out_abort: out_abort:
lxc_abort(name, handler); lxc_abort(name, handler);
lxc_sync_fini(handler); lxc_sync_fini(handler);
@ -675,7 +742,7 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
err = lxc_spawn(handler); err = lxc_spawn(handler);
if (err) { if (err) {
ERROR("failed to spawn '%s'", name); ERROR("failed to spawn '%s'", name);
goto out_fini; goto out_fini_nonet;
} }
err = lxc_poll(name, handler); err = lxc_poll(name, handler);
@ -708,8 +775,13 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
} }
} }
lxc_rename_phys_nics_on_shutdown(handler->conf);
err = lxc_error_set_and_log(handler->pid, status); err = lxc_error_set_and_log(handler->pid, status);
out_fini: out_fini:
lxc_delete_network(handler);
out_fini_nonet:
lxc_cgroup_destroy(name); lxc_cgroup_destroy(name);
lxc_fini(name, handler); lxc_fini(name, handler);
return err; return err;

View File

@ -39,6 +39,7 @@ struct lxc_handler {
pid_t pid; pid_t pid;
char *name; char *name;
lxc_state_t state; lxc_state_t state;
int clone_flags;
int sigfd; int sigfd;
sigset_t oldmask; sigset_t oldmask;
struct lxc_conf *conf; struct lxc_conf *conf;

View File

@ -21,6 +21,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
@ -31,9 +32,11 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/file.h> #include <sys/file.h>
#include <lxc/lxc.h>
#include <lxc/log.h> #include <lxc/log.h>
#include <lxc/start.h> #include <lxc/start.h>
#include <lxc/cgroup.h> #include <lxc/cgroup.h>
#include <lxc/monitor.h>
#include "commands.h" #include "commands.h"
#include "config.h" #include "config.h"
@ -162,3 +165,115 @@ out:
return ret; return ret;
} }
static int fillwaitedstates(const char *strstates, int *states)
{
char *token, *saveptr = NULL;
char *strstates_dup = strdup(strstates);
int state;
if (!strstates_dup)
return -1;
token = strtok_r(strstates_dup, "|", &saveptr);
while (token) {
state = lxc_str2state(token);
if (state < 0) {
free(strstates_dup);
return -1;
}
states[state] = 1;
token = strtok_r(NULL, "|", &saveptr);
}
free(strstates_dup);
return 0;
}
extern int lxc_wait(const char *lxcname, const char *states, int timeout)
{
struct lxc_msg msg;
int state, ret;
int s[MAX_STATE] = { }, fd;
if (fillwaitedstates(states, s))
return -1;
fd = lxc_monitor_open();
if (fd < 0)
return -1;
/*
* if container present,
* then check if already in requested state
*/
ret = -1;
state = lxc_getstate(lxcname);
if (state < 0) {
goto out_close;
} else if ((state >= 0) && (s[state])) {
ret = 0;
goto out_close;
}
for (;;) {
int elapsed_time, curtime = 0;
struct timeval tv;
int stop = 0;
int retval;
if (timeout != -1) {
retval = gettimeofday(&tv, NULL);
if (retval)
goto out_close;
curtime = tv.tv_sec;
}
if (lxc_monitor_read_timeout(fd, &msg, timeout) < 0)
goto out_close;
if (timeout != -1) {
retval = gettimeofday(&tv, NULL);
if (retval)
goto out_close;
elapsed_time = tv.tv_sec - curtime;
if (timeout - elapsed_time <= 0)
stop = 1;
timeout -= elapsed_time;
}
if (strcmp(lxcname, msg.name)) {
if (stop) {
ret = -2;
goto out_close;
}
continue;
}
switch (msg.type) {
case lxc_msg_state:
if (msg.value < 0 || msg.value >= MAX_STATE) {
ERROR("Receive an invalid state number '%d'",
msg.value);
goto out_close;
}
if (s[msg.value]) {
ret = 0;
goto out_close;
}
break;
default:
if (stop) {
ret = -2;
goto out_close;
}
/* just ignore garbage */
break;
}
}
out_close:
lxc_monitor_close(fd);
return ret;
}

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