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.pc
templates/lxc-debian
templates/lxc-lucid
templates/lxc-maverick
templates/lxc-natty
templates/lxc-oneiric
templates/lxc-fedora
templates/lxc-altlinux
templates/lxc-sshd
templates/lxc-busybox
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-cgroup
src/lxc/lxc-checkconfig
src/lxc/lxc-checkpoint
src/lxc/lxc-cinit
src/lxc/lxc-cmd
src/lxc/lxc-clone
src/lxc/lxc-console
src/lxc/lxc-create
src/lxc/lxc-destroy
src/lxc/lxc-enter
src/lxc/lxc-exec
src/lxc/lxc-execute
src/lxc/lxc-freeze
src/lxc/lxc-info
src/lxc/lxc-init
src/lxc/lxc-kill
src/lxc/lxc-ls
src/lxc/lxc-monitor
src/lxc/lxc-netstat
src/lxc/lxc-setcap
src/lxc/lxc-ps
src/lxc/lxc-restart
src/lxc/lxc-setcap
src/lxc/lxc-setuid
src/lxc/lxc-shutdown
src/lxc/lxc-start
src/lxc/lxc-start-ephemeral
src/lxc/lxc-stop
src/lxc/lxc-unfreeze
src/lxc/lxc-unshare
src/lxc/lxc-version
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/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
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
contributions.)
using your real name (sorry, no pseudonyms or anonymous contributions.)

16
COPYING
View File

@ -1,5 +1,5 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
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
the version number 2.1.]
Preamble
Preamble
The licenses for most software are designed to take away your
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
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
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
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
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
and reuse of software generally.
NO WARRANTY
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
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
DAMAGES.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
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
That's all there is to it!

View File

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

View File

@ -2,13 +2,17 @@
ACLOCAL_AMFLAGS = -I config
SUBDIRS = src templates doc
SUBDIRS = config src templates doc
DIST_SUBDIRS = config src templates doc
EXTRA_DIST = autogen.sh lxc.spec CONTRIBUTING MAINTAINERS ChangeLog
pcdatadir = $(libdir)/pkgconfig
pcdata_DATA = lxc.pc
install-data-local:
$(MKDIR_P) $(DESTDIR)$(LXCPATH)
$(MKDIR_P) $(DESTDIR)$(localstatedir)/cache/lxc
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
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
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.
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
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.
Getting help:
@ -48,7 +53,33 @@ Portability:
lxc is developed and tested on Linux since kernel mainline version 2.6.27
(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
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
line, like the 'make menuconfig' of the kernel.
line, like the 'make menuconfig' of the kernel.
= 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

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 thomas@apestaart.org
dnl
dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
dnl example
dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local
AC_DEFUN([AS_AC_EXPAND],
[
EXP_VAR=[$1]
FROM_VAR=[$2]
dnl first expand prefix and exec_prefix if necessary
prefix_save=$prefix
exec_prefix_save=$exec_prefix
dnl if no prefix given, then use /usr/local, the default prefix
if test "x$prefix" = "xNONE"; then
prefix="$ac_default_prefix"
@ -25,7 +25,7 @@ AC_DEFUN([AS_AC_EXPAND],
if test "x$exec_prefix" = "xNONE"; then
exec_prefix=$prefix
fi
full_var="$FROM_VAR"
dnl loop until it doesn't change anymore
while true; do
@ -33,11 +33,11 @@ AC_DEFUN([AS_AC_EXPAND],
if test "x$new_full_var" = "x$full_var"; then break; fi
full_var=$new_full_var
done
dnl clean up
full_var=$new_full_var
AC_SUBST([$1], "$full_var")
dnl restore prefix and exec_prefix
prefix=$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.
ax_compare_version_len_A=`echo "$A" | 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.
A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\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_AUX_DIR([config])
AM_CONFIG_HEADER([src/config.h])
AM_INIT_AUTOMAKE([-Wno-portability])
AM_INIT_AUTOMAKE([-Wall -Werror -Wno-portability])
AC_CANONICAL_HOST
AM_PROG_CC_C_O
AC_GNU_SOURCE
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_HELP_STRING([--disable-rpath], [do not set rpath in executables])],
[], [enable_rpath=yes])
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_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])
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_ERROR([docbook2man required by man request, but not found])
AC_MSG_CHECKING(for docbook2x-man)
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
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],
[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_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_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"])
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(LIBDIR, $libdir)
AS_AC_EXPAND(BINDIR, $bindir)
@ -69,12 +165,13 @@ AC_ARG_WITH([rootfs-path],
[lxc rootfs mount point]
)], [], [with_rootfs_path=['${libdir}/lxc/rootfs']])
AS_AC_EXPAND(LXC_CONFFILE, $conffile)
AS_AC_EXPAND(LXC_GENERATE_DATE, "$(date)")
AS_AC_EXPAND(LXCPATH, "${with_config_path}")
AS_AC_EXPAND(LXCROOTFSMOUNT, "${with_rootfs_path}")
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],
[],
@ -101,9 +198,10 @@ AC_CHECK_DECLS([PR_CAPBSET_DROP], [], [], [#include <sys/prctl.h>])
AC_CHECK_HEADERS([sys/signalfd.h])
AC_PROG_GCC_TRADITIONAL
AC_PROG_SED
if test "x$GCC" = "xyes"; then
CFLAGS="$CFLAGS -Wall"
CFLAGS="$CFLAGS -Wall -Werror"
fi
AC_CONFIG_FILES([
@ -134,6 +232,7 @@ AC_CONFIG_FILES([
doc/lxc.sgml
doc/common_options.sgml
doc/see_also.sgml
doc/legacy/lxc-ls.sgml
doc/rootfs/Makefile
@ -154,6 +253,7 @@ AC_CONFIG_FILES([
templates/lxc-opensuse
templates/lxc-busybox
templates/lxc-fedora
templates/lxc-oracle
templates/lxc-altlinux
templates/lxc-sshd
templates/lxc-archlinux
@ -161,7 +261,6 @@ AC_CONFIG_FILES([
src/Makefile
src/lxc/Makefile
src/lxc/lxc-ps
src/lxc/lxc-ls
src/lxc/lxc-netstat
src/lxc/lxc-checkconfig
src/lxc/lxc-setcap
@ -170,7 +269,15 @@ AC_CONFIG_FILES([
src/lxc/lxc-create
src/lxc/lxc-clone
src/lxc/lxc-shutdown
src/lxc/lxc-start-ephemeral
src/lxc/lxc-destroy
src/lxc/legacy/lxc-ls
src/python-lxc/Makefile
src/python-lxc/lxc/__init__.py
src/python-lxc/examples/api_test.py
src/tests/Makefile
])
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
namespace"
Answer:
-------
Answer:
-------
read the lxc man page about kernel version prereq :) most probably
your kernel is not configured to support the container options you

View File

@ -19,7 +19,6 @@ man_MANS = \
lxc-unfreeze.1 \
lxc-monitor.1 \
lxc-wait.1 \
lxc-ls.1 \
lxc-ps.1 \
lxc-cgroup.1 \
lxc-kill.1 \
@ -29,15 +28,23 @@ man_MANS = \
\
lxc.7
if ENABLE_PYTHON
man_MANS += lxc-ls.1
else
man_MANS += legacy/lxc-ls.1
endif
%.1 : %.sgml
docbook2man -w all $<
%.1 : %.sgml
$(db2xman) $<
test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
%.5 : %.sgml
docbook2man -w all $<
%.5 : %.sgml
$(db2xman) $<
test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
%.7 : %.sgml
docbook2man -w all $<
%.7 : %.sgml
$(db2xman) $<
test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
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 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="opt">-a <replaceable>arch</replaceable></arg>
<arg choice="opt">-e</arg>
<arg choice="opt">-s <replaceable>namespaces</replaceable></arg>
<arg choice="opt">-R</arg>
<arg choice="opt">-- <replaceable>command</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
@ -125,7 +127,53 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</listitem>
</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>
@ -147,19 +195,86 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</para>
<para>
To deactivate the network link eth1 of a running container that
does not have the NET_ADMIN capability, use the <option>-e</option>
option to use increased capabilities:
does not have the NET_ADMIN capability, use either the
<option>-e</option> option to use increased capabilities,
assuming the <command>ip</command> tool is installed:
<programlisting>
lxc-attach -n container -e -- /sbin/ip link delete eth1
</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>
</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>
<title>Security</title>
<para>
The <option>-e</option> should be used with care, as it may break
the isolation of the containers if used improperly.
The <option>-e</option> and <option>-s</option> options should
be used with care, as it may break the isolation of the containers
if used improperly.
</para>
</refsect1>

View File

@ -1,4 +1,4 @@
<!--
<!--
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 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.
</para>
</listitem>
</varlistentry>
</varlistentry>
</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 seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -1,4 +1,4 @@
<!--
<!--
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 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
means if the container has four ttys available and the command
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>
@ -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.
</para>
</listitem>
</varlistentry>
</varlistentry>
</variablelist>

View File

@ -1,4 +1,4 @@
<!--
<!--
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 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.
Refer to the examples in <filename>@LXCTEMPLATEDIR@</filename>
for details of the expected script structure.
Alternatively, the full path to an executable template script
can also be passed as a parameter.
</para>
</listitem>
</varlistentry>
@ -123,9 +125,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</term>
<listitem>
<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
will be a directory under <filename>@LXCPATH@/container/rootfs</filename>.
'dir' has the same meaning as 'none', but also allows the optional
<replaceable>--dir ROOTFS</replaceable> to be specified, meaning
that the container rootfs should be placed under the specified path,
rather than the default.
The option 'btrfs' need not be specified as it will be used
automatically if the <filename>@LXCPATH@</filename> filesystem is found to
be btrfs. If backingstore is 'lvm', then an lvm block device will be
@ -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.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
@ -175,7 +182,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
available containers on the system.
</para>
</listitem>
</varlistentry>
</varlistentry>
</variablelist>

View File

@ -1,4 +1,4 @@
<!--
<!--
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 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.
</para>
</listitem>
</varlistentry>
</varlistentry>
</variablelist>

View File

@ -1,4 +1,4 @@
<!--
<!--
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 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.
</para>
</listitem>
</varlistentry>
</varlistentry>
</variablelist>

View File

@ -1,4 +1,4 @@
<!--
<!--
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 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.
</para>
</listitem>
</varlistentry>
</varlistentry>
</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 seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -1,5 +1,5 @@
<!--
<!--
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">
]>
@ -49,8 +49,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsynopsisdiv>
<cmdsynopsis>
<command>lxc-ls</command>
<arg choice="opt">-1</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>
</refsynopsisdiv>
@ -65,77 +71,136 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term>
<option><optional>--active</optional></option>
</term>
<listitem>
<para>
List active containers.
</para>
</listitem>
<term>
<option><optional>-1</optional></option>
</term>
<listitem>
<para>
Show one entry per line. (default when /dev/stdout isn't a tty)
</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>
<term>
<option><optional>--active</optional></option>
</term>
<listitem>
<para>
List only active containers (same as --frozen --running).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>lxc-ls --active -1</term>
<listitem>
<para>
list active containers and display the list in one column.
</para>
</listitem>
<term>
<option><optional>--frozen</optional></option>
</term>
<listitem>
<para>
List only frozen containers.
</para>
</listitem>
</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>
</refsect1>
<refsect1>
<title>See Also</title>
<simpara>
<simpara>
<citerefentry>
<refentrytitle>ls</refentrytitle>
<manvolnum>1</manvolnum>
<refentrytitle>ls</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>,
</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>
<title>Author</title>
<para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
<para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file

View File

@ -1,4 +1,4 @@
<!--
<!--
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 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.
</para>
</listitem>
</varlistentry>
</varlistentry>
</variablelist>
@ -145,7 +145,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsect1>
<title>See Also</title>
<simpara>
<simpara>
<citerefentry>
<refentrytitle>regex</refentrytitle>
<manvolnum>7</manvolnum>

View File

@ -1,5 +1,5 @@
<!--
<!--
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">
]>
@ -86,8 +86,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<listitem>
<para>
specify the container <replaceable>name</replaceable>
to limit the output to the processes belonging
to this container name.
to limit the output to the processes belonging
to this container name.
</para>
</listitem>
</varlistentry>
@ -98,7 +98,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</term>
<listitem>
<para>
limit the output to the processes belonging
limit the output to the processes belonging
to all lxc containers.
</para>
</listitem>
@ -139,7 +139,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsect1>
<title>See Also</title>
<simpara>
<simpara>
<citerefentry>
<refentrytitle>ps</refentrytitle>
<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 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 seealso SYSTEM "@builddir@/see_also.sgml">

View File

@ -1,4 +1,4 @@
<!--
<!--
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 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">-c <replaceable>console_file</replaceable></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">-C</arg>
<arg choice="opt">command</arg>
@ -107,6 +108,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</listitem>
</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>
<term>
<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.
</para>
</listitem>
</varlistentry>
</varlistentry>
</variablelist>

View File

@ -1,4 +1,4 @@
<!--
<!--
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 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.
</para>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<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.
</para>
</listitem>
</varlistentry>
</varlistentry>
</variablelist>

View File

@ -1,4 +1,4 @@
<!--
<!--
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 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.
</para>
</listitem>
</varlistentry>
</varlistentry>
</variablelist>

View File

@ -1,5 +1,5 @@
<!--
<!--
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 seealso SYSTEM "@builddir@/see_also.sgml">
@ -79,6 +79,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</listitem>
</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>
</refsect1>
@ -122,7 +133,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
the <command>lxc-create</command> command.
</para>
</listitem>
</varlistentry>
</varlistentry>
</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
# 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
# specify the physical network device which will communicate with the

View File

@ -1,4 +1,4 @@
<!--
<!--
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">
]>
@ -235,7 +235,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
specify an action to do for the
network.
</para>
<para><option>up:</option> activates the interface.
</para>
</listitem>
@ -374,6 +374,26 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>lxc.network.script.down</option>
</term>
<listitem>
<para>
add a configuration option to specify a script to be
executed before destroying the network used from the
host side. The following arguments are passed to the
script: container name and config section name (net)
Additional arguments depend on the config section
employing a script hook; the following are used by the
network system: execution context (down), network type
(empty/veth/macvlan/phys), Depending on the network
type, other arguments may be passed:
veth/macvlan/phys. And finally (host-sided) device name.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect2>
@ -481,6 +501,31 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</variablelist>
</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>
<title>Mount points</title>
<para>
@ -640,6 +685,84 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</variablelist>
</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>
@ -726,7 +849,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<refsect1>
<title>See Also</title>
<simpara>
<simpara>
<citerefentry>
<refentrytitle><command>chroot</command></refentrytitle>
<manvolnum>1</manvolnum>
@ -744,14 +867,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</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

View File

@ -1,4 +1,4 @@
<!--
<!--
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">
]>
@ -239,7 +239,7 @@ rootfs
/sbin /home/root/sshd/rootfs/sbin none ro,bind 0 0
</programlisting>
</para>
<para>How to run a system in a container ?</para>
<para>Running a system inside a container is paradoxically easier
@ -249,7 +249,7 @@ rootfs
without configuration because the container will set them
up. eg. the ipv4 address will be setup by the system container
init scripts. Here is an example of the mount points file:
<programlisting>
[root@lxc debian]$ cat fstab
@ -280,7 +280,7 @@ rootfs
</para>
<programlisting>
<![CDATA[
---------
| STOPPED |<---------------
--------- |
@ -305,14 +305,14 @@ rootfs
---------- |
| |
---------------------
]]>
</programlisting>
</refsect2>
<refsect2>
<title>Configuration</title>
<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>
<refentrytitle><filename>lxc.conf</filename></refentrytitle>
<manvolnum>5</manvolnum>
@ -363,7 +363,7 @@ rootfs
but if needed the <command>lxc-stop</command> command can
be used to kill the still running application.
</para>
<para>
Running an application inside a container is not exactly the
same thing as running a system. For this reason, there are two
@ -434,7 +434,7 @@ rootfs
lxc-freeze -n foo
</programlisting>
will put all the processes in an uninteruptible state and
will put all the processes in an uninteruptible state and
<programlisting>
lxc-unfreeze -n foo
@ -570,7 +570,7 @@ rootfs
to the background.
<programlisting>
<![CDATA[
# launch lxc-wait in background
lxc-wait -n foo -s STOPPED &
LXC_WAIT_PID=$!
@ -583,7 +583,7 @@ rootfs
# is STOPPED
wait $LXC_WAIT_PID
echo "'foo' is finished"
]]>
</programlisting>
</para>
</refsect2>

View File

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

View File

@ -29,8 +29,8 @@ Summary: %{name} : Linux Container
Group: Applications/System
License: LGPL
BuildRoot: %{_tmppath}/%{name}-%{version}-build
Requires: libcap
BuildRequires: libcap libcap-devel docbook-utils
Requires: libcap openssl rsync
BuildRequires: libcap libcap-devel docbook2X
%description
@ -91,11 +91,13 @@ rm -rf %{buildroot}
%{_mandir}/*
%{_datadir}/doc/*
%{_datadir}/lxc/*
%{_sysconfdir}/lxc/*
%files libs
%defattr(-,root,root)
%{_libdir}/*.so.*
%{_libdir}/%{name}
%{_localstatedir}/*
%attr(4555,root,root) %{_libexecdir}/%{name}/lxc-init
%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 \
log.h \
state.h \
attach.h
attach.h \
lxccontainer.h \
lxclock.h
sodir=$(libdir)
# use PROGRAMS to avoid complains from automake
@ -50,33 +52,41 @@ liblxc_so_SOURCES = \
genl.c genl.h \
\
caps.c caps.h \
lxcseccomp.h \
mainloop.c mainloop.h \
af_unix.c af_unix.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 \
-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
-DLXCPATH=\"$(LXCPATH)\" \
-DLXCINITDIR=\"$(LXCINITDIR)\"
-DLXCINITDIR=\"$(LXCINITDIR)\" \
-DLXCTEMPLATEDIR=\"$(LXCTEMPLATEDIR)\"
if ENABLE_APPARMOR
AM_CFLAGS += -DHAVE_APPARMOR
endif
if ENABLE_SECCOMP
AM_CFLAGS += -DHAVE_SECCOMP
liblxc_so_SOURCES += seccomp.c
endif
liblxc_so_CFLAGS = -fPIC -DPIC $(AM_CFLAGS)
liblxc_so_LDFLAGS = \
-shared \
-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 = \
lxc-ps \
lxc-netstat \
lxc-ls \
lxc-checkconfig \
lxc-setcap \
lxc-setuid \
@ -86,6 +96,14 @@ bin_SCRIPTS = \
lxc-shutdown \
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 = \
lxc-attach \
lxc-unshare \
@ -110,7 +128,7 @@ AM_LDFLAGS = -Wl,-E
if ENABLE_RPATH
AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
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_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;
/* 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));
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
@ -73,7 +73,7 @@ int lxc_af_unix_close(int fd)
struct sockaddr_un addr;
socklen_t addrlen;
if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) &&
if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) &&
addr.sun_path[0])
unlink(addr.sun_path);
@ -95,7 +95,7 @@ int lxc_af_unix_connect(const char *path)
addr.sun_family = AF_UNIX;
/* 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));
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);
/* 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 */
*recvfd = -1;

View File

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

View File

@ -30,6 +30,7 @@
#include <fcntl.h>
#include <sys/param.h>
#include <sys/prctl.h>
#include <sys/mount.h>
#include <linux/unistd.h>
#if !HAVE_DECL_PR_CAPBSET_DROP
@ -121,13 +122,22 @@ out_error:
return NULL;
}
int lxc_attach_to_ns(pid_t pid)
int lxc_attach_to_ns(pid_t pid, int which)
{
char path[MAXPATHLEN];
char *ns[] = { "pid", "mnt", "net", "ipc", "uts" };
const int size = sizeof(ns) / sizeof(char *);
/* according to <http://article.gmane.org/gmane.linux.kernel.containers.lxc.devel/1429>,
* 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 i;
int i, j, saved_errno;
snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
if (access(path, X_OK)) {
@ -136,16 +146,39 @@ int lxc_attach_to_ns(pid_t pid)
}
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]);
fd[i] = open(path, O_RDONLY);
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);
return -1;
}
}
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]);
return -1;
}
@ -156,6 +189,49 @@ int lxc_attach_to_ns(pid_t pid)
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 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 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);
#endif

View File

@ -254,13 +254,38 @@ static int cgroup_enable_clone_children(const char *path)
return ret;
}
static int lxc_one_cgroup_attach(const char *name,
struct mntent *mntent, pid_t pid)
static int lxc_one_cgroup_finish_attach(int fd, 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 *cgmnt = mntent->mnt_dir;
int flags, ret = 0;
int flags;
int rc;
flags = get_cgroup_flags(mntent);
@ -274,31 +299,83 @@ static int lxc_one_cgroup_attach(const char *name,
return -1;
}
f = fopen(tasks, "w");
if (!f) {
fd = open(tasks, O_WRONLY);
if (fd < 0) {
SYSERROR("failed to open '%s'", tasks);
return -1;
}
if (fprintf(f, "%d", pid) <= 0) {
SYSERROR("failed to write pid '%d' to '%s'", pid, tasks);
ret = -1;
return fd;
}
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;
}
/*
* for each mounted cgroup, attach a pid to the cgroup for the container
*/
int lxc_cgroup_attach(const char *name, pid_t pid)
int lxc_cgroup_finish_attach(void *data, pid_t pid)
{
int *fds = data;
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;
FILE *file = NULL;
int err = -1;
int found = 0;
int *fds;
int i;
static const int MAXFDS = 256;
file = setmntent(MTAB, "r");
if (!file) {
@ -306,7 +383,29 @@ int lxc_cgroup_attach(const char *name, pid_t pid)
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))) {
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);
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'",
++found, mntent->mnt_dir, mntent->mnt_opts);
err = lxc_one_cgroup_attach(name, mntent, pid);
if (err)
fds[i] = lxc_one_cgroup_prepare_attach(name, mntent);
if (fds[i] < 0) {
err = fds[i];
lxc_cgroup_dispose_attach(fds);
goto out;
}
i++;
};
if (!found)
ERROR("No cgroup mounted on the system");
*data = fds;
out:
endmntent(file);
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
* 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 (access(cgparent, F_OK)) {
ret = mkdir(cgparent, 0755);
if (ret == -1 && errno == EEXIST) {
if (ret == -1 && errno != EEXIST) {
SYSERROR("failed to create '%s' directory", cgparent);
return -1;
}
@ -668,6 +789,13 @@ out:
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,
char *value, size_t len)
{
@ -692,7 +820,18 @@ int lxc_cgroup_get(const char *name, const char *filename,
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)
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_nrtasks(const char *name);
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);
#endif

View File

@ -154,11 +154,32 @@ pid_t get_init_pid(const char *name)
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 int lxc_console_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_stop_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_state_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_pid_callback(int, struct lxc_request *, struct lxc_handler *);
extern int lxc_clone_flags_callback(int, struct lxc_request *, struct lxc_handler *);
static int trigger_command(int fd, struct lxc_request *request,
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 *);
callback cb[LXC_COMMAND_MAX] = {
[LXC_COMMAND_TTY] = lxc_console_callback,
[LXC_COMMAND_STOP] = lxc_stop_callback,
[LXC_COMMAND_STATE] = lxc_state_callback,
[LXC_COMMAND_PID] = lxc_pid_callback,
[LXC_COMMAND_TTY] = lxc_console_callback,
[LXC_COMMAND_STOP] = lxc_stop_callback,
[LXC_COMMAND_STATE] = lxc_state_callback,
[LXC_COMMAND_PID] = lxc_pid_callback,
[LXC_COMMAND_CLONE_FLAGS] = lxc_clone_flags_callback,
};
if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
@ -305,5 +327,6 @@ extern int lxc_command_mainloop_add(const char *name,
close(fd);
}
handler->conf->maincmd_fd = fd;
return ret;
}

View File

@ -28,6 +28,7 @@ enum {
LXC_COMMAND_STOP,
LXC_COMMAND_STATE,
LXC_COMMAND_PID,
LXC_COMMAND_CLONE_FLAGS,
LXC_COMMAND_MAX,
};
@ -48,6 +49,7 @@ struct lxc_command {
};
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,
int *stopped);

View File

@ -66,6 +66,8 @@
#include <apparmor.h>
#endif
#include "lxcseccomp.h"
lxc_log_define(lxc_conf, lxc);
#define MAXHWLEN 18
@ -109,6 +111,9 @@ lxc_log_define(lxc_conf, lxc);
#define PR_CAPBSET_DROP 24
#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);
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,
};
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[] = {
{ "defaults", 0, 0 },
{ "ro", 0, MS_RDONLY },
@ -214,12 +233,41 @@ static struct caps_opt caps_opt[] = {
#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,
const char *script, ...)
{
int ret;
FILE *f;
char *buffer, *p, *output;
char *buffer, *p;
size_t size = 0;
va_list ap;
@ -266,29 +314,7 @@ static int run_script(const char *name, const char *section,
}
va_end(ap);
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;
return run_buffer(buffer);
}
static int find_fstype_cb(char* buffer, void *data)
@ -636,6 +662,15 @@ static int setup_tty(const struct lxc_rootfs *rootfs,
return -1;
}
} 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)) {
WARN("failed to mount '%s'->'%s'",
pty_info->name, path);
@ -708,7 +743,7 @@ static int umount_oldrootfs(const char *oldrootfs)
{
char path[MAXPATHLEN];
void *cbparm[2];
struct lxc_list mountlist, *iterator;
struct lxc_list mountlist, *iterator, *next;
int ok, still_mounted, last_still_mounted;
int rc;
@ -748,7 +783,7 @@ static int umount_oldrootfs(const char *oldrootfs)
last_still_mounted = still_mounted;
still_mounted = 0;
lxc_list_for_each(iterator, &mountlist) {
lxc_list_for_each_safe(iterator, &mountlist, next) {
/* umount normally */
if (!umount(iterator->elem)) {
@ -843,6 +878,114 @@ static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir)
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)
{
if (!rootfs->path)
@ -1061,6 +1204,8 @@ static int setup_kmsg(const struct lxc_rootfs *rootfs,
char kpath[MAXPATHLEN];
int ret;
if (!rootfs->path)
return 0;
ret = snprintf(kpath, sizeof(kpath), "%s/dev/kmsg", rootfs->mount);
if (ret < 0 || ret >= sizeof(kpath))
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
* use /var/lib/lxc/CN/rootfs as the target prefix */
r = snprintf(path, MAXPATHLEN, "/var/lib/lxc/%s/rootfs", lxc_name);
* use $LXCPATH/CN/rootfs as the target prefix */
r = snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", lxc_name);
if (r < 0 || r >= MAXPATHLEN)
goto skipvarlib;
@ -1647,7 +1792,7 @@ static int setup_netdev(struct lxc_netdev *netdev)
ifname, strerror(-err));
if (netdev->ipv6_gateway_auto) {
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);
}
return -1;
@ -1680,6 +1825,21 @@ static int setup_network(struct lxc_list *network)
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)
{
struct ifreq ifr;
@ -1715,6 +1875,8 @@ static int setup_private_host_hw_addr(char *veth1)
return 0;
}
static char *default_rootfs_mount = LXCROOTFSMOUNT;
struct lxc_conf *lxc_conf_init(void)
{
struct lxc_conf *new;
@ -1733,7 +1895,8 @@ struct lxc_conf *lxc_conf_init(void)
new->console.master = -1;
new->console.slave = -1;
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->network);
lxc_list_init(&new->mount_list);
@ -1765,6 +1928,8 @@ static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
return -1;
}
veth1 = mktemp(veth1buf);
/* store away for deconf */
memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
}
snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
@ -1841,6 +2006,25 @@ out_delete:
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)
{
char peerbuf[IFNAMSIZ], *peer;
@ -1889,6 +2073,20 @@ static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n
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 */
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;
}
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)
{
if (!netdev->link) {
@ -1950,6 +2153,19 @@ static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netd
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)
{
netdev->ifindex = 0;
@ -1963,6 +2179,19 @@ static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *net
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)
{
struct lxc_list *network = &handler->conf->network;
@ -1989,28 +2218,32 @@ int lxc_create_network(struct lxc_handler *handler)
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_netdev *netdev;
lxc_list_for_each(iterator, network) {
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))
WARN("failed to rename to the initial name the " \
"netdev '%s'", netdev->link);
continue;
}
if (netdev_deconf[netdev->type](handler, netdev)) {
WARN("failed to destroy netdev");
}
/* Recent kernel remove the virtual interfaces when the network
* namespace is destroyed but in case we did not moved the
* interface to the network namespace, we have to destroy it
*/
if (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);
}
}
@ -2166,11 +2399,23 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
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)) {
ERROR("failed to setup rootfs for '%s'", name);
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)) {
ERROR("failed to setup the mounts for '%s'", name);
return -1;
@ -2186,6 +2431,13 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
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)) {
ERROR("failed to setup the cgroups for '%s'", name);
return -1;
@ -2196,10 +2448,8 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
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);
return -1;
}
if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) {
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)
which = LXCHOOK_PRESTART;
else if (strcmp(hook, "pre-mount") == 0)
which = LXCHOOK_PREMOUNT;
else if (strcmp(hook, "mount") == 0)
which = LXCHOOK_MOUNT;
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;
}
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
#include <netinet/in.h>
#include <net/if.h>
#include <sys/param.h>
#include <stdbool.h>
@ -31,6 +32,10 @@
#include <lxc/start.h> /* for lxc_handler */
#if HAVE_SCMP_FILTER_CTX
typedef void * scmp_filter_ctx;
#endif
enum {
LXC_NET_EMPTY,
LXC_NET_VETH,
@ -76,6 +81,7 @@ struct lxc_route6 {
struct ifla_veth {
char *pair; /* pair name */
char veth1[IFNAMSIZ]; /* needed for deconf */
};
struct ifla_vlan {
@ -103,6 +109,7 @@ union netdev_p {
* @ipv4 : a list of ipv4 addresses to be set on the network device
* @ipv6 : a list of ipv6 addresses to be set on the network device
* @upscript : a script filename to be executed during interface configuration
* @downscript : a script filename to be executed during interface destruction
*/
struct lxc_netdev {
int type;
@ -120,6 +127,7 @@ struct lxc_netdev {
struct in6_addr *ipv6_gateway;
bool ipv6_gateway_auto;
char *upscript;
char *downscript;
};
/*
@ -203,8 +211,15 @@ struct lxc_rootfs {
#endif
*/
enum lxchooks {
LXCHOOK_PRESTART, LXCHOOK_MOUNT, LXCHOOK_START,
LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_START,
LXCHOOK_POSTSTOP, NUM_LXC_HOOKS};
extern char *lxchook_names[NUM_LXC_HOOKS];
struct saved_nic {
int ifindex;
char *orig_name;
};
struct lxc_conf {
char *fstab;
int tty;
@ -215,6 +230,8 @@ struct lxc_conf {
struct utsname *utsname;
struct lxc_list cgroup;
struct lxc_list network;
struct saved_nic *saved_nics;
int num_savednics;
struct lxc_list mount_list;
struct lxc_list caps;
struct lxc_tty_info tty_info;
@ -226,9 +243,18 @@ struct lxc_conf {
#if HAVE_APPARMOR
char *aa_profile;
#endif
char *logfile;
int loglevel;
#if HAVE_APPARMOR /* || HAVE_SELINUX || HAVE_SMACK */
int lsm_umount_proc;
#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);
@ -237,20 +263,30 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
* Initialize the lxc configuration structure
*/
extern struct lxc_conf *lxc_conf_init(void);
extern void lxc_conf_free(struct lxc_conf *conf);
extern int pin_rootfs(const char *rootfs);
extern int lxc_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_find_gateway_addresses(struct lxc_handler *handler);
extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
extern int lxc_clear_config_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
*/
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

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,15 @@
struct lxc_conf;
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_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 */
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

View File

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

View File

@ -62,7 +62,7 @@ static int genetlink_resolve_family(const char *family)
if (ret)
return ret;
ret = nla_put_string((struct nlmsg *)&request->nlmsghdr,
ret = nla_put_string((struct nlmsg *)&request->nlmsghdr,
CTRL_ATTR_FAMILY_NAME, family);
if (ret)
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);
}
extern int genetlink_transaction(struct genl_handler *handler,
extern int genetlink_transaction(struct genl_handler *handler,
struct genlmsg *request, struct genlmsg *answer)
{
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))
/*
* 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
* for the generic netlink protocol
*
@ -116,6 +116,6 @@ void genlmsg_free(struct genlmsg *genlmsg);
*
* 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);
#endif

View File

@ -75,7 +75,7 @@ directory=$(readlink -f "$lxc_path")
for i in "$@"; do
case $i in
--help)
help; exit 1;;
help; exit;;
--active)
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)
fi
if [ -z "$containers" ]; then
echo "$(basename $0): no containers found" >&2
exit 1
fi
cd "$directory"
ls -d $@ -- $containers

View File

@ -14,6 +14,11 @@ struct lxc_list {
__iterator != __list; \
__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)
{
list->elem = NULL;

View File

@ -41,6 +41,7 @@
int lxc_log_fd = -1;
static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
int lxc_loglevel_specified = 0;
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;
if (lxc_log_fd != -1)
return 0;
if (priority) {
lxc_loglevel_specified = 1;
lxc_priority = lxc_log_priority_to_int(priority);
if (lxc_priority == LXC_LOG_PRIORITY_NOTSET) {
@ -185,3 +190,39 @@ extern int lxc_log_init(const char *file, const char *priority,
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
/* predefined priorities. */
enum {
enum lxc_loglevel {
LXC_LOG_PRIORITY_TRACE,
LXC_LOG_PRIORITY_DEBUG,
LXC_LOG_PRIORITY_INFO,
@ -291,4 +291,6 @@ extern int lxc_log_init(const char *file, const char *priority,
const char *prefix, int quiet);
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

View File

@ -1,13 +1,13 @@
#!/bin/bash
#!/bin/sh
# Allow environment variables to override grep and config
: ${CONFIG:=/proc/config.gz}
: ${GREP:=zgrep}
SETCOLOR_SUCCESS="echo -en \\033[1;32m"
SETCOLOR_FAILURE="echo -en \\033[1;31m"
SETCOLOR_WARNING="echo -en \\033[1;33m"
SETCOLOR_NORMAL="echo -en \\033[0;39m"
SETCOLOR_SUCCESS="printf \\e[1;32m"
SETCOLOR_FAILURE="printf \\e[1;31m"
SETCOLOR_WARNING="printf \\e[1;33m"
SETCOLOR_NORMAL="printf \\e[0;39m"
is_set() {
$GREP -q "$1=[y|m]" $CONFIG
@ -21,13 +21,13 @@ is_enabled() {
RES=$?
if [ $RES -eq 0 ]; then
$SETCOLOR_SUCCESS && echo -e "enabled" && $SETCOLOR_NORMAL
$SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
else
if [ ! -z "$mandatory" -a "$mandatory" = yes ]; then
$SETCOLOR_FAILURE && echo -e "required" && $SETCOLOR_NORMAL
else
$SETCOLOR_WARNING && echo -e "missing" && $SETCOLOR_NORMAL
fi
if [ ! -z "$mandatory" -a "$mandatory" = yes ]; then
$SETCOLOR_FAILURE && echo "required" && $SETCOLOR_NORMAL
else
$SETCOLOR_WARNING && echo "missing" && $SETCOLOR_NORMAL
fi
fi
}
@ -68,40 +68,45 @@ print_cgroups() {
}
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 | \
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 | \
sed -r 's/.* 2.6.([0-9]{2}).*/\1/')
else
KVER_MINOR=$($GREP '^# Linux' $CONFIG | \
sed -r 's/.* [0-9]\.([0-9]{1,3})\.[0-9]{1,3}.*/\1/')
fi
echo -n "File capabilities: " &&
( [[ ${KVER_MAJOR} == 2 && ${KVER_MINOR} < 33 ]] &&
is_enabled CONFIG_SECURITY_FILE_CAPABILITIES ) ||
( [[ ( ${KVER_MAJOR} == 2 && ${KVER_MINOR} > 32 ) ||
${KVER_MAJOR} > 2 ]] && $SETCOLOR_SUCCESS &&
echo -e "enabled" && $SETCOLOR_NORMAL )
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 "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 "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
mount /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new $rootfs || { echo "$(basename $0): failed to mount new rootfs" >&2; false; }
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
rmdir ${rootfs}_snapshot
lvremove -f $lxc_vg/${lxc_lv_prefix}${lxc_new}_snapshot
@ -252,7 +252,7 @@ else
frozen=1
fi
mkdir -p $rootfs/
rsync -ax $oldroot/ $rootfs/
rsync -Hax $oldroot/ $rootfs/
echo "lxc.rootfs = $rootfs" >> $lxc_path/$lxc_new/config
if [ $container_running = "True" ]; then
lxc-unfreeze -n $lxc_orig
@ -272,11 +272,11 @@ c=$lxc_path/$lxc_new/config
mv ${c} ${c}.old
(
while read line; do
if [ "${line:0:18}" = "lxc.network.hwaddr" ]; then
echo "lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')"
else
echo "$line"
fi
if [ "${line:0:18}" = "lxc.network.hwaddr" ]; then
echo "lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')"
else
echo "$line"
fi
done
) < ${c}.old > ${c}
rm -f ${c}.old

View File

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

View File

@ -54,26 +54,27 @@ eval set -- "$getopt"
while true; do
case "$1" in
-h|--help)
help
exit 1
;;
-n|--name)
shift
lxc_name=$1
shift
;;
-f)
force=1
shift
;;
-h|--help)
help
exit 1
;;
-n|--name)
shift
lxc_name=$1
shift
;;
-f)
force=1
shift
;;
--)
shift
break;;
shift
break
;;
*)
usage
exit 1
;;
usage
exit 1
;;
esac
done
@ -96,13 +97,13 @@ fi
# make sure the container isn't running
lxc-info -n $lxc_name 2>/dev/null | grep -q RUNNING
if [ $? -eq 0 ]; then
if [ $force -eq 1 ]; then
lxc-stop -n $lxc_name
lxc-wait -n $lxc_name -s STOPPED
else
echo "$(basename $0): '$lxc_name' is running; aborted" >&2
exit 1
fi
if [ $force -eq 1 ]; then
lxc-stop -n $lxc_name
lxc-wait -n $lxc_name -s STOPPED
else
echo "$(basename $0): '$lxc_name' is running; aborted" >&2
exit 1
fi
fi
# Deduce the type of rootfs
@ -110,21 +111,22 @@ fi
# 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/^[^/]*/\//'`
if [ -n "$rootdev" ]; then
if [ -b "$rootdev" ]; then
lvdisplay $rootdev > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "removing backing store: $rootdev"
lvremove -f $rootdev
fi
elif [ -h "$rootdev" -o -d "$rootdev" ]; then
if which btrfs >/dev/null 2>&1 &&
btrfs subvolume list "$rootdev" >/dev/null 2>&1; then
btrfs subvolume delete "$rootdev"
else
# In case rootfs is not under $lxc_path/$lxc_name, remove it
rm -rf --one-file-system --preserve-root $rootdev
fi
fi
if [ -b "$rootdev" -o -h "$rootdev" ]; then
lvdisplay $rootdev > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "removing backing store: $rootdev"
lvremove -f $rootdev
fi
elif [ -h "$rootdev" -o -d "$rootdev" ]; then
if which btrfs >/dev/null 2>&1 &&
btrfs subvolume list "$rootdev" >/dev/null 2>&1; then
btrfs subvolume delete "$rootdev"
else
# In case rootfs is not under $lxc_path/$lxc_name, remove it
rm -rf --one-file-system --preserve-root $rootdev
fi
fi
fi
# recursively remove the container to remove old container configuration
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
usage() {
echo "usage: $(basename $0) -n|--name <name> -- [netstat_options]" >&2
echo "usage: $(basename $0) -n|--name <name> -- [netstat_options]" >&2
}
help() {
usage
echo >&2
echo "Execute 'netstat' for the specified container." >&2
echo >&2
echo " --name NAME specify the container name" >&2
echo " NETSTAT_OPTIONS netstat command options (see \`netstat --help')" >&2
usage
echo >&2
echo "Execute 'netstat' for the specified container." >&2
echo >&2
echo " --name NAME specify the container name" >&2
echo " NETSTAT_OPTIONS netstat command options (see \`netstat --help')" >&2
}
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
hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
# Obtain a list of hierarchies that contain one or more subsystems
hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
# Iterate through the list until a suitable hierarchy is found
for hierarchy in $hierarchies; do
# Obtain information about the init process in the hierarchy
fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1)
if [ -z "$fields" ]; then continue; fi
fields=${fields#*:}
# Iterate through the list until a suitable hierarchy is found
for hierarchy in $hierarchies; do
# Obtain information about the init process in the hierarchy
fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1)
if [ -z "$fields" ]; then continue; fi
fields=${fields#*:}
# Get a comma-separated list of the hierarchy's subsystems
subsystems=${fields%:*}
# Get a comma-separated list of the hierarchy's subsystems
subsystems=${fields%:*}
# Get the cgroup of the init process in the hierarchy
init_cgroup=${fields#*:}
# Get the cgroup of the init process in the hierarchy
init_cgroup=${fields#*:}
# Get the filesystem mountpoint of the hierarchy
mountpoint=$(grep -E "^cgroup [^ ]+ [^ ]+ ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2)
if [ -z "$mountpoint" ]; then continue; fi
# Get the filesystem mountpoint of the hierarchy
mountpoint=$(grep -E "^cgroup [^ ]+ [^ ]+ ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2)
if [ -z "$mountpoint" ]; then continue; fi
# Return the absolute path to the containers' parent cgroup
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
if [[ ",$subsystems," == *,ns,* ]]; then
parent_cgroup="${mountpoint}${init_cgroup%/}"
else
parent_cgroup="${mountpoint}${init_cgroup%/}/lxc"
fi
break
done
# Return the absolute path to the containers' parent cgroup
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
if [[ ",$subsystems," == *,ns,* ]]; then
parent_cgroup="${mountpoint}${init_cgroup%/}"
else
parent_cgroup="${mountpoint}${init_cgroup%/}/lxc"
fi
break
done
}
exec=""
while true; do
case $1 in
-h|--help)
help; exit 1;;
-n|--name)
name=$2; shift 2;;
--exec)
exec="exec"; shift;;
--)
shift; break;;
*)
break;;
esac
case $1 in
-h|--help)
help; exit 1;;
-n|--name)
name=$2; shift 2;;
--exec)
exec="exec"; shift;;
--)
shift; break;;
*)
break;;
esac
done
if [ "$(id -u)" != "0" ]; then
echo "$(basename $0): must be run as root" >&2
exit 1
echo "$(basename $0): must be run as root" >&2
exit 1
fi
if [ -z "$name" ]; then
usage
exit 1
usage
exit 1
fi
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
lxc-info -n $name 2>&1 | grep -q 'STOPPED'
if [ $? -eq 0 ]; then
echo "$(basename $0): container '$name' is not running" >&2
exit 1
echo "$(basename $0): container '$name' is not running" >&2
exit 1
fi
get_parent_cgroup
if [ ! -d "$parent_cgroup" ]; then
echo "$(basename $0): no cgroup mount point found" >&2
exit 1
echo "$(basename $0): no cgroup mount point found" >&2
exit 1
fi
pid=$(head -1 $parent_cgroup/$name/tasks)
if [ -z "$pid" ]; then
echo "$(basename $0): no process found for '$name'" >&2
exit 1
echo "$(basename $0): no process found for '$name'" >&2
exit 1
fi
tmpdir=$(mktemp -d)
if [ -z "$tmpdir" -o ! -d "$tmpdir" ]; then
echo "$(basename $0): unable to create temporary directory" >&2
exit 1
echo "$(basename $0): unable to create temporary directory" >&2
exit 1
fi
# Bind mount /proc/$pid/net onto /proc/net before calling 'netstat'.

View File

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

View File

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

View File

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

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@"

View File

@ -84,6 +84,7 @@ extern int lxc_monitor_open(void);
* data was readen, < 0 otherwise
*/
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
@ -178,6 +179,30 @@ extern int lxc_restart(const char *, int, struct lxc_conf *, int);
*/
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
}
#endif

View File

@ -40,22 +40,30 @@
#include "start.h"
#include "sync.h"
#include "log.h"
#include "namespace.h"
lxc_log_define(lxc_attach_ui, lxc);
static const struct option my_longopts[] = {
{"elevated-privileges", no_argument, 0, 'e'},
{"arch", required_argument, 0, 'a'},
{"namespaces", required_argument, 0, 's'},
{"remount-sys-proc", no_argument, 0, 'R'},
LXC_COMMON_OPTIONS
};
static int elevated_privileges = 0;
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)
{
int ret;
switch (c) {
case 'e': elevated_privileges = 1; break;
case 'R': remount_sys_proc = 1; break;
case 'a':
new_personality = lxc_config_parse_arch(arg);
if (new_personality < 0) {
@ -63,6 +71,14 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
return -1;
}
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;
@ -83,7 +99,18 @@ Options :\n\
WARNING: This may leak privleges into the container.\n\
Use with care.\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,
.parser = my_parser,
.checker = NULL,
@ -96,6 +123,7 @@ int main(int argc, char *argv[])
struct passwd *passwd;
struct lxc_proc_context_info *init_ctx;
struct lxc_handler *handler;
void *cgroup_data = NULL;
uid_t uid;
char *curdir;
@ -124,6 +152,48 @@ int main(int argc, char *argv[])
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 */
handler = calloc(1, sizeof(*handler));
@ -150,8 +220,22 @@ int main(int argc, char *argv[])
if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE))
return -1;
if (!elevated_privileges && lxc_cgroup_attach(my_args.name, pid))
return -1;
/* now that we are done with all privileged operations,
* 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 */
if (lxc_sync_wake_child(handler, LXC_SYNC_POST_CONFIGURE))
@ -175,20 +259,20 @@ int main(int argc, char *argv[])
if (!pid) {
lxc_sync_fini_parent(handler);
lxc_cgroup_dispose_attach(cgroup_data);
curdir = get_current_dir_name();
ret = lxc_attach_to_ns(init_pid);
if (ret < 0) {
ERROR("failed to enter the namespace");
return -1;
/* A description of the purpose of this functionality is
* provided in the lxc-attach(1) manual page. We have to
* remount here and not in the parent process, otherwise
* /proc may not properly reflect the new pid namespace.
*/
if (!(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)
new_personality = init_ctx->personality;

View File

@ -34,12 +34,14 @@
static bool state;
static bool pid;
static char *test_state = NULL;
static int my_parser(struct lxc_arguments* args, int c, char* arg)
{
switch (c) {
case 's': state = true; break;
case 'p': pid = true; break;
case 't': test_state = arg; break;
}
return 0;
}
@ -47,6 +49,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
static const struct option my_longopts[] = {
{"state", no_argument, 0, 's'},
{"pid", no_argument, 0, 'p'},
{"state-is", required_argument, 0, 't'},
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\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-s, --state shows the state of the container\n\
-p, --pid shows the process id of the init container\n",
-n, --name=NAME NAME for name of the container\n\
-s, --state shows the state of the 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,
.parser = my_parser,
.checker = NULL,
@ -81,10 +86,12 @@ int main(int argc, char *argv[])
if (!state && !pid)
state = pid = true;
if (state) {
if (state || test_state) {
ret = lxc_getstate(my_args.name);
if (ret < 0)
return 1;
if (test_state)
return strcmp(lxc_state2str(ret), test_state) != 0;
printf("state:%10s\n", lxc_state2str(ret));
}

View File

@ -102,7 +102,7 @@ int main(int argc, char *argv[])
switch (msg.type) {
case lxc_msg_state:
printf("'%s' changed state to [%s]\n",
printf("'%s' changed state to [%s]\n",
msg.name, lxc_state2str(msg.value));
break;
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 'C': args->close_all_fds = 1; break;
case 's': return lxc_config_define_add(&defines, arg);
case 'p': args->pidfile = arg; break;
}
return 0;
}
@ -72,6 +73,7 @@ static const struct option my_longopts[] = {
{"define", required_argument, 0, 's'},
{"console", required_argument, 0, 'c'},
{"close-all-fds", no_argument, 0, 'C'},
{"pidfile", required_argument, 0, 'p'},
LXC_COMMON_OPTIONS
};
@ -85,6 +87,7 @@ lxc-start start COMMAND in specified container NAME\n\
Options :\n\
-n, --name=NAME NAME for name of 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\
-c, --console=FILE Set the file output for the container console\n\
-C, --close-all-fds If any fds are inherited, close them\n\
@ -95,6 +98,7 @@ Options :\n\
.parser = my_parser,
.checker = NULL,
.daemonize = 0,
.pidfile = NULL,
};
int main(int argc, char *argv[])
@ -107,6 +111,7 @@ int main(int argc, char *argv[])
"/sbin/init",
'\0',
};
FILE *pid_fp = NULL;
lxc_list_init(&defines);
@ -117,7 +122,7 @@ int main(int argc, char *argv[])
return err;
if (!my_args.argc)
args = default_args;
args = default_args;
else
args = my_args.argv;
@ -199,6 +204,15 @@ int main(int argc, char *argv[])
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) {
/* do an early check for needed privs, since otherwise the
* 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)
conf->close_all_fds = 1;
@ -230,6 +252,9 @@ int main(int argc, char *argv[])
err = -1;
}
if (my_args.pidfile)
unlink(my_args.pidfile);
return err;
}

View File

@ -84,51 +84,6 @@ static uid_t lookup_user(const char *optarg)
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 {
char ***args;

View File

@ -24,6 +24,8 @@
#include <string.h>
#include <libgen.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <lxc/lxc.h>
@ -46,12 +48,14 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
{
switch (c) {
case 's': args->states = optarg; break;
case 't': args->timeout = atol(optarg); break;
}
return 0;
}
static const struct option my_longopts[] = {
{"state", required_argument, 0, 's'},
{"timeout", required_argument, 0, 't'},
LXC_COMMON_OPTIONS
};
@ -66,37 +70,16 @@ Options :\n\
-n, --name=NAME NAME for name of the container\n\
-s, --state=STATE ORed states to wait for\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,
.parser = my_parser,
.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[])
{
struct lxc_msg msg;
int s[MAX_STATE] = { }, fd;
int state, ret;
if (lxc_arguments_parse(&my_args, argc, argv))
return -1;
@ -104,53 +87,5 @@ int main(int argc, char *argv[])
my_args.progname, my_args.quiet))
return -1;
if (fillwaitedstates(my_args.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(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;
return lxc_wait(strdup(my_args.name), my_args.states, my_args.timeout);
}

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
the mainloop */
if (handler->callback(handler->fd, handler->data,
if (handler->callback(handler->fd, handler->data,
descr) > 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)
{
struct epoll_event ev;

View File

@ -28,13 +28,13 @@ struct lxc_epoll_descr {
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);
extern int lxc_mainloop(struct lxc_epoll_descr *descr);
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);
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;
}
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;
socklen_t len = sizeof(from);
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,
(struct sockaddr *)&from, &len);
@ -114,6 +131,11 @@ int lxc_monitor_read(int fd, struct lxc_msg *msg)
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)
{
return close(fd);

View File

@ -69,3 +69,48 @@ pid_t lxc_clone(int (*fn)(void *), void *arg, int flags)
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 int lxc_namespace_2_cloneflag(char *namespace);
extern int lxc_fill_namespace_flags(char *flaglist, int *flags);
#endif

View File

@ -47,6 +47,7 @@
#include "nl.h"
#include "network.h"
#include "conf.h"
#ifndef IFLA_LINKMODE
# define IFLA_LINKMODE 17
@ -1004,3 +1005,18 @@ int lxc_bridge_attach(const char *bridge, const char *ifname)
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);
/*
/*
* Create default gateway
*/
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 const char *lxc_net_type_to_str(int type);
#endif

View File

@ -48,7 +48,7 @@ extern void *nlmsg_data(struct nlmsg *nlmsg)
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)
{
struct rtattr *rta;
@ -63,7 +63,7 @@ static int nla_put(struct nlmsg *nlmsg, int attr,
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)
{
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
#define NLMSG_ERROR 0x2
#endif
extern int netlink_transaction(struct nl_handler *handler,
extern int netlink_transaction(struct nl_handler *handler,
struct nlmsg *request, struct nlmsg *answer)
{
int ret;
@ -226,11 +226,11 @@ extern int netlink_open(struct nl_handler *handler, int protocol)
if (handler->fd < 0)
return -errno;
if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF,
if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF,
&sndbuf, sizeof(sndbuf)) < 0)
return -errno;
if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF,
if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF,
&rcvbuf,sizeof(rcvbuf)) < 0)
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_groups = 0;
if (bind(handler->fd, (struct sockaddr*)&handler->local,
if (bind(handler->fd, (struct sockaddr*)&handler->local,
sizeof(handler->local)) < 0)
return -errno;
socklen = sizeof(handler->local);
if (getsockname(handler->fd, (struct sockaddr*)&handler->local,
if (getsockname(handler->fd, (struct sockaddr*)&handler->local,
&socklen) < 0)
return -errno;

View File

@ -39,7 +39,7 @@
* struct nl_handler : the handler for netlink sockets, this structure
* is used all along the netlink socket life cycle to specify the
* netlink socket to be used.
*
*
* @fd: the file descriptor of the netlink socket
* @seq: the sequence number of the netlink messages
* @local: the bind address
@ -77,7 +77,7 @@ struct nlmsg {
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
*
* @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);
/*
* netlink_rcv : receive a netlink message from the kernel.
* It is up to the caller to manage the allocation of the
* netlink_rcv : receive a netlink message from the kernel.
* It is up to the caller to manage the allocation of the
* netlink message
*
* @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);
/*
* netlink_transaction: send a request to the kernel and read the response.
* This is useful for transactional protocol. It is up to the caller
* netlink_transaction: send a request to the kernel and read the response.
* This is useful for transactional protocol. It is up to the caller
* to manage the allocation of the netlink message.
*
* @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
*/
int netlink_transaction(struct nl_handler *handler,
int netlink_transaction(struct nl_handler *handler,
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
*
* @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
*/
int nla_put_buffer(struct nlmsg *nlmsg, int attr,
int nla_put_buffer(struct nlmsg *nlmsg, int attr,
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);
/*
* 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
* @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
*
* @nlmsg: the netlink message to be filled
* @attr: the netsted attribute name
* @attr: the netsted attribute name
*
* Returns current nested pointer to be reused
* to nla_end_nested.
@ -198,17 +198,17 @@ struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr);
* @nlmsg: the netlink message
* @nested: the nested pointer
*
* Returns the current
* Returns the current
*/
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.
* 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
* 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 function will also fill the field nlmsg_len with computed size.
* 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 : the netlink message to get the 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);
}
extern int rtnetlink_transaction(struct rtnl_handler *handler,
extern int rtnetlink_transaction(struct rtnl_handler *handler,
struct rtnlmsg *request, struct rtnlmsg *answer)
{
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))
/*
* struct genl_handler : the structure which store the netlink handler
* struct genl_handler : the structure which store the netlink handler
* and the family number
*
* @nlh: the netlink socket handler
@ -105,6 +105,6 @@ void rtnlmsg_free(struct rtnlmsg *rtnlmsg);
*
* 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);
#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 "namespace.h"
#include "apparmor.h"
#include "lxcseccomp.h"
lxc_log_define(lxc_start, lxc);
@ -278,6 +279,29 @@ int lxc_pid_callback(int fd, struct lxc_request *request,
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)
{
handler->state = state;
@ -353,6 +377,11 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf)
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*/
if (lxc_set_state(name, handler, 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)
goto out_warn_father;
if (lxc_seccomp_load(handler->conf) != 0)
goto out_warn_father;
if (run_lxc_hooks(handler->name, "start", handler->conf)) {
ERROR("failed to run start hooks for container '%s'.", handler->name);
goto out_warn_father;
@ -547,9 +579,39 @@ out_warn_father:
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 clone_flags;
int failed_before_rename = 0;
const char *name = handler->name;
int pinfd;
@ -557,10 +619,10 @@ int lxc_spawn(struct lxc_handler *handler)
if (lxc_sync_init(handler))
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)) {
clone_flags |= CLONE_NEWNET;
handler->clone_flags |= CLONE_NEWNET;
/* Find gateway addresses from the link device, which is
* 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
* marking it readonly.
@ -594,7 +661,7 @@ int lxc_spawn(struct lxc_handler *handler)
}
/* 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) {
SYSERROR("failed to fork into a new namespace");
goto out_delete_net;
@ -612,7 +679,7 @@ int lxc_spawn(struct lxc_handler *handler)
goto out_delete_net;
/* Create the network configuration */
if (clone_flags & CLONE_NEWNET) {
if (handler->clone_flags & CLONE_NEWNET) {
if (lxc_assign_network(&handler->conf->network, handler->pid)) {
ERROR("failed to create the configured network");
goto out_delete_net;
@ -642,8 +709,8 @@ int lxc_spawn(struct lxc_handler *handler)
return 0;
out_delete_net:
if (clone_flags & CLONE_NEWNET)
lxc_delete_network(&handler->conf->network);
if (handler->clone_flags & CLONE_NEWNET)
lxc_delete_network(handler);
out_abort:
lxc_abort(name, handler);
lxc_sync_fini(handler);
@ -675,7 +742,7 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
err = lxc_spawn(handler);
if (err) {
ERROR("failed to spawn '%s'", name);
goto out_fini;
goto out_fini_nonet;
}
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);
out_fini:
lxc_delete_network(handler);
out_fini_nonet:
lxc_cgroup_destroy(name);
lxc_fini(name, handler);
return err;

View File

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

View File

@ -21,6 +21,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
@ -31,9 +32,11 @@
#include <sys/stat.h>
#include <sys/file.h>
#include <lxc/lxc.h>
#include <lxc/log.h>
#include <lxc/start.h>
#include <lxc/cgroup.h>
#include <lxc/monitor.h>
#include "commands.h"
#include "config.h"
@ -162,3 +165,115 @@ out:
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