mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-08-03 07:23:23 +00:00
Merge git://github.com/lxc/lxc
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
This commit is contained in:
commit
2e3ae157d5
46
.gitignore
vendored
46
.gitignore
vendored
@ -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
|
||||
|
@ -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
16
COPYING
@ -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!
|
||||
|
||||
|
||||
|
4
INSTALL
4
INSTALL
@ -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.
|
||||
|
||||
|
@ -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
37
README
@ -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
2
TODO
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
3
config/lxc.conf.libvirt
Normal file
@ -0,0 +1,3 @@
|
||||
lxc.network.type = veth
|
||||
lxc.network.link = virbr0
|
||||
lxc.network.flags = up
|
3
config/lxc.conf.ubuntu
Normal file
3
config/lxc.conf.ubuntu
Normal file
@ -0,0 +1,3 @@
|
||||
lxc.network.type = veth
|
||||
lxc.network.link = lxcbr0
|
||||
lxc.network.flags = up
|
1
config/lxc.conf.unknown
Normal file
1
config/lxc.conf.unknown
Normal file
@ -0,0 +1 @@
|
||||
lxc.network.type = empty
|
135
configure.ac
135
configure.ac
@ -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],[[]],[[]])
|
||||
|
@ -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
|
||||
|
@ -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
156
doc/legacy/lxc-ls.sgml.in
Normal 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:
|
||||
-->
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -1,3 +1,3 @@
|
||||
READMEdir=@LXCROOTFSMOUNT@
|
||||
|
||||
README_DATA=README
|
||||
README_DATA=README
|
||||
|
@ -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
32
runapitests.sh
Normal 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
|
@ -1 +1 @@
|
||||
SUBDIRS = lxc
|
||||
SUBDIRS = lxc tests python-lxc
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
175
src/lxc/cgroup.c
175
src/lxc/cgroup.c
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
580
src/lxc/conf.c
580
src/lxc/conf.c
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include "log.h"
|
||||
#include "start.h"
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
95
src/lxc/lxc-device
Normal 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
251
src/lxc/lxc-ls
Normal 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))
|
@ -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'.
|
||||
|
@ -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 "$@")
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
289
src/lxc/lxc-start-ephemeral.in
Normal file
289
src/lxc/lxc-start-ephemeral.in
Normal 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)
|
@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
echo "lxc version: @PACKAGE_VERSION@"
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
1001
src/lxc/lxccontainer.c
Normal file
File diff suppressed because it is too large
Load Diff
79
src/lxc/lxccontainer.h
Normal file
79
src/lxc/lxccontainer.h
Normal 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
105
src/lxc/lxclock.c
Normal 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
61
src/lxc/lxclock.h
Normal 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
49
src/lxc/lxcseccomp.h
Normal 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
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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
|
||||
|
14
src/lxc/nl.c
14
src/lxc/nl.c
@ -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;
|
||||
|
||||
|
32
src/lxc/nl.h
32
src/lxc/nl.h
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
155
src/lxc/seccomp.c
Normal 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
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
115
src/lxc/state.c
115
src/lxc/state.c
@ -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
Loading…
Reference in New Issue
Block a user