mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-08-06 01:45:47 +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.spec
|
||||||
lxc.pc
|
lxc.pc
|
||||||
|
|
||||||
templates/lxc-debian
|
|
||||||
templates/lxc-lucid
|
|
||||||
templates/lxc-maverick
|
|
||||||
templates/lxc-natty
|
|
||||||
templates/lxc-oneiric
|
|
||||||
templates/lxc-fedora
|
|
||||||
templates/lxc-altlinux
|
templates/lxc-altlinux
|
||||||
templates/lxc-sshd
|
|
||||||
templates/lxc-busybox
|
|
||||||
templates/lxc-archlinux
|
templates/lxc-archlinux
|
||||||
|
templates/lxc-busybox
|
||||||
|
templates/lxc-debian
|
||||||
|
templates/lxc-fedora
|
||||||
|
templates/lxc-lenny
|
||||||
|
templates/lxc-opensuse
|
||||||
|
templates/lxc-oracle
|
||||||
|
templates/lxc-sshd
|
||||||
|
templates/lxc-ubuntu
|
||||||
|
templates/lxc-ubuntu-cloud
|
||||||
|
|
||||||
|
|
||||||
src/lxc/lxc-attach
|
src/lxc/lxc-attach
|
||||||
src/lxc/lxc-cgroup
|
src/lxc/lxc-cgroup
|
||||||
src/lxc/lxc-checkconfig
|
src/lxc/lxc-checkconfig
|
||||||
src/lxc/lxc-checkpoint
|
src/lxc/lxc-checkpoint
|
||||||
src/lxc/lxc-cinit
|
src/lxc/lxc-clone
|
||||||
src/lxc/lxc-cmd
|
|
||||||
src/lxc/lxc-console
|
src/lxc/lxc-console
|
||||||
src/lxc/lxc-create
|
src/lxc/lxc-create
|
||||||
src/lxc/lxc-destroy
|
src/lxc/lxc-destroy
|
||||||
src/lxc/lxc-enter
|
|
||||||
src/lxc/lxc-exec
|
|
||||||
src/lxc/lxc-execute
|
src/lxc/lxc-execute
|
||||||
src/lxc/lxc-freeze
|
src/lxc/lxc-freeze
|
||||||
src/lxc/lxc-info
|
src/lxc/lxc-info
|
||||||
src/lxc/lxc-init
|
src/lxc/lxc-init
|
||||||
src/lxc/lxc-kill
|
src/lxc/lxc-kill
|
||||||
src/lxc/lxc-ls
|
|
||||||
src/lxc/lxc-monitor
|
src/lxc/lxc-monitor
|
||||||
src/lxc/lxc-netstat
|
src/lxc/lxc-netstat
|
||||||
src/lxc/lxc-setcap
|
|
||||||
src/lxc/lxc-ps
|
src/lxc/lxc-ps
|
||||||
src/lxc/lxc-restart
|
src/lxc/lxc-restart
|
||||||
|
src/lxc/lxc-setcap
|
||||||
|
src/lxc/lxc-setuid
|
||||||
|
src/lxc/lxc-shutdown
|
||||||
src/lxc/lxc-start
|
src/lxc/lxc-start
|
||||||
|
src/lxc/lxc-start-ephemeral
|
||||||
src/lxc/lxc-stop
|
src/lxc/lxc-stop
|
||||||
src/lxc/lxc-unfreeze
|
src/lxc/lxc-unfreeze
|
||||||
src/lxc/lxc-unshare
|
src/lxc/lxc-unshare
|
||||||
src/lxc/lxc-version
|
src/lxc/lxc-version
|
||||||
src/lxc/lxc-wait
|
src/lxc/lxc-wait
|
||||||
|
src/lxc/legacy/lxc-ls
|
||||||
|
|
||||||
|
src/python-lxc/build/
|
||||||
|
src/python-lxc/examples/api_test.py
|
||||||
|
src/python-lxc/lxc/__init__.py
|
||||||
|
src/python-lxc/lxc/__pycache__/
|
||||||
|
|
||||||
|
src/tests/lxc-test-containertests
|
||||||
|
src/tests/lxc-test-createtest
|
||||||
|
src/tests/lxc-test-destroytest
|
||||||
|
src/tests/lxc-test-get_item
|
||||||
|
src/tests/lxc-test-getkeys
|
||||||
|
src/tests/lxc-test-locktests
|
||||||
|
src/tests/lxc-test-saveconfig
|
||||||
|
src/tests/lxc-test-shutdowntest
|
||||||
|
src/tests/lxc-test-startone
|
||||||
|
|
||||||
|
|
||||||
config/compile
|
config/compile
|
||||||
config/config.guess
|
config/config.guess
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
Contributing to this project
|
Contributing to this project
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
|
||||||
@ -81,7 +81,6 @@ By making a contribution to this project, I certify that:
|
|||||||
|
|
||||||
then you just add a line saying
|
then you just add a line saying
|
||||||
|
|
||||||
Signed-off-by: Random J Developer <random@developer.org>
|
Signed-off-by: Random J Developer <random@developer.org>
|
||||||
|
|
||||||
using your real name (sorry, no pseudonyms or anonymous
|
using your real name (sorry, no pseudonyms or anonymous contributions.)
|
||||||
contributions.)
|
|
||||||
|
16
COPYING
16
COPYING
@ -1,5 +1,5 @@
|
|||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
Version 2.1, February 1999
|
Version 2.1, February 1999
|
||||||
|
|
||||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
@ -10,7 +10,7 @@
|
|||||||
as the successor of the GNU Library Public License, version 2, hence
|
as the successor of the GNU Library Public License, version 2, hence
|
||||||
the version number 2.1.]
|
the version number 2.1.]
|
||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
The licenses for most software are designed to take away your
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
@ -112,7 +112,7 @@ modification follow. Pay close attention to the difference between a
|
|||||||
former contains code derived from the library, whereas the latter must
|
former contains code derived from the library, whereas the latter must
|
||||||
be combined with the library in order to run.
|
be combined with the library in order to run.
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
0. This License Agreement applies to any software library or other
|
0. This License Agreement applies to any software library or other
|
||||||
@ -146,7 +146,7 @@ such a program is covered only if its contents constitute a work based
|
|||||||
on the Library (independent of the use of the Library in a tool for
|
on the Library (independent of the use of the Library in a tool for
|
||||||
writing it). Whether that is true depends on what the Library does
|
writing it). Whether that is true depends on what the Library does
|
||||||
and what the program that uses the Library does.
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Library's
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
complete source code as you receive it, in any medium, provided that
|
complete source code as you receive it, in any medium, provided that
|
||||||
you conspicuously and appropriately publish on each copy an
|
you conspicuously and appropriately publish on each copy an
|
||||||
@ -432,7 +432,7 @@ decision will be guided by the two goals of preserving the free status
|
|||||||
of all derivatives of our free software and of promoting the sharing
|
of all derivatives of our free software and of promoting the sharing
|
||||||
and reuse of software generally.
|
and reuse of software generally.
|
||||||
|
|
||||||
NO WARRANTY
|
NO WARRANTY
|
||||||
|
|
||||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
@ -455,7 +455,7 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
|||||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
DAMAGES.
|
DAMAGES.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
How to Apply These Terms to Your New Libraries
|
How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
@ -500,5 +500,3 @@ necessary. Here is a sample; alter the names:
|
|||||||
Ty Coon, President of Vice
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
That's all there is to it!
|
That's all there is to it!
|
||||||
|
|
||||||
|
|
||||||
|
4
INSTALL
4
INSTALL
@ -10,8 +10,8 @@ unlimited permission to copy, distribute and modify it.
|
|||||||
Basic Installation
|
Basic Installation
|
||||||
==================
|
==================
|
||||||
|
|
||||||
Briefly, the shell commands `./configure; make; make install' should
|
Briefly, the shell commands `./autogen.sh; ./configure; make; make install'
|
||||||
configure, build, and install this package. The following
|
should configure, build, and install this package. The following
|
||||||
more-detailed instructions are generic; see the `README' file for
|
more-detailed instructions are generic; see the `README' file for
|
||||||
instructions specific to this package.
|
instructions specific to this package.
|
||||||
|
|
||||||
|
@ -2,13 +2,17 @@
|
|||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I config
|
ACLOCAL_AMFLAGS = -I config
|
||||||
|
|
||||||
SUBDIRS = src templates doc
|
SUBDIRS = config src templates doc
|
||||||
DIST_SUBDIRS = config src templates doc
|
DIST_SUBDIRS = config src templates doc
|
||||||
EXTRA_DIST = autogen.sh lxc.spec CONTRIBUTING MAINTAINERS ChangeLog
|
EXTRA_DIST = autogen.sh lxc.spec CONTRIBUTING MAINTAINERS ChangeLog
|
||||||
|
|
||||||
pcdatadir = $(libdir)/pkgconfig
|
pcdatadir = $(libdir)/pkgconfig
|
||||||
pcdata_DATA = lxc.pc
|
pcdata_DATA = lxc.pc
|
||||||
|
|
||||||
|
install-data-local:
|
||||||
|
$(MKDIR_P) $(DESTDIR)$(LXCPATH)
|
||||||
|
$(MKDIR_P) $(DESTDIR)$(localstatedir)/cache/lxc
|
||||||
|
|
||||||
ChangeLog::
|
ChangeLog::
|
||||||
@touch ChangeLog
|
@touch ChangeLog
|
||||||
|
|
||||||
|
37
README
37
README
@ -7,7 +7,7 @@ What is lxc:
|
|||||||
kernel. It provides the resource management through the control groups aka
|
kernel. It provides the resource management through the control groups aka
|
||||||
process containers and resource isolation through the namespaces.
|
process containers and resource isolation through the namespaces.
|
||||||
|
|
||||||
The linux containers, lxc, aims to use these new functionnalities to pro-
|
The linux containers, lxc, aims to use these new functionalities to pro-
|
||||||
vide an userspace container object which provides full resource isolation
|
vide an userspace container object which provides full resource isolation
|
||||||
and resource control for an applications or a system.
|
and resource control for an applications or a system.
|
||||||
|
|
||||||
@ -29,9 +29,14 @@ Downloading the current source code:
|
|||||||
You can browse the up to the minute source code and change history online.
|
You can browse the up to the minute source code and change history online.
|
||||||
http://lxc.git.sourceforge.net
|
http://lxc.git.sourceforge.net
|
||||||
|
|
||||||
|
For an even more bleeding edge experience, you may want to look at the
|
||||||
|
staging branch where all changes aimed at the next release land before
|
||||||
|
getting pulled into the master branch.
|
||||||
|
http://github.com/lxc/lxc
|
||||||
|
|
||||||
For detailed build instruction refer to INSTALL and man lxc man page
|
For detailed build instruction refer to INSTALL and man lxc man page
|
||||||
but a short command line should work:
|
but a short command line should work:
|
||||||
./configure && make && sudo make install && sudo lxc-setcap
|
./autogen.sh && ./configure && make && sudo make install && sudo lxc-setcap
|
||||||
preceded by ./autogen.sh if configure do not exist yet.
|
preceded by ./autogen.sh if configure do not exist yet.
|
||||||
|
|
||||||
Getting help:
|
Getting help:
|
||||||
@ -48,7 +53,33 @@ Portability:
|
|||||||
|
|
||||||
lxc is developed and tested on Linux since kernel mainline version 2.6.27
|
lxc is developed and tested on Linux since kernel mainline version 2.6.27
|
||||||
(without network) and 2.6.29 with network isolation.
|
(without network) and 2.6.29 with network isolation.
|
||||||
is compiled with gcc, and supports i686, x86_64, ppc, ppc64, S390 archi.
|
It's compiled with gcc, and should work on most architectures as long as the
|
||||||
|
required kernel features are available. This includes (but isn't limited to):
|
||||||
|
i686, x86_64, ppc, ppc64, S390, armel and armhf.
|
||||||
|
|
||||||
AUTHOR
|
AUTHOR
|
||||||
Daniel Lezcano <daniel.lezcano@free.fr>
|
Daniel Lezcano <daniel.lezcano@free.fr>
|
||||||
|
|
||||||
|
Seccomp with LXC
|
||||||
|
----------------
|
||||||
|
|
||||||
|
To restrict a container with seccomp, you must specify a profile which is
|
||||||
|
basically a whitelist of system calls it may execute. In the container
|
||||||
|
config file, add a line like
|
||||||
|
|
||||||
|
lxc.seccomp = /var/lib/lxc/q1/seccomp.full
|
||||||
|
|
||||||
|
I created a usable (but basically worthless) seccomp.full file using
|
||||||
|
|
||||||
|
cat > seccomp.full << EOF
|
||||||
|
1
|
||||||
|
whitelist
|
||||||
|
EOF
|
||||||
|
for i in `seq 0 300`; do
|
||||||
|
echo $i >> seccomp.full
|
||||||
|
done
|
||||||
|
for i in `seq 1024 1079`; do
|
||||||
|
echo $i >> seccomp.full
|
||||||
|
done
|
||||||
|
|
||||||
|
-- Serge Hallyn <serge.hallyn@ubuntu.com> Fri, 27 Jul 2012 15:47:02 +0600
|
||||||
|
2
TODO
2
TODO
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
* create an interactive configuration with the lxc-create command
|
* create an interactive configuration with the lxc-create command
|
||||||
line, like the 'make menuconfig' of the kernel.
|
line, like the 'make menuconfig' of the kernel.
|
||||||
|
|
||||||
= lxc-create [-n foo] -m|--menuconfig
|
= lxc-create [-n foo] -m|--menuconfig
|
||||||
|
@ -1,2 +1,15 @@
|
|||||||
distclean:
|
configdir = $(sysconfdir)/lxc
|
||||||
|
config_DATA = lxc.conf
|
||||||
|
conffile = @LXC_CONFFILE@
|
||||||
|
|
||||||
|
EXTRA_DIST = lxc.conf.ubuntu lxc.conf.libvirt lxc.conf.unknown
|
||||||
|
|
||||||
|
lxc.conf:
|
||||||
|
cp $(conffile) $@
|
||||||
|
|
||||||
|
clean-local:
|
||||||
|
@$(RM) -f lxc.conf
|
||||||
|
|
||||||
|
distclean-local:
|
||||||
|
@$(RM) -f lxc.conf
|
||||||
@$(RM) -f compile config.guess config.sub depcomp install-sh ltmain.sh missing Makefile.in Makefile
|
@$(RM) -f compile config.guess config.sub depcomp install-sh ltmain.sh missing Makefile.in Makefile
|
||||||
|
@ -2,21 +2,21 @@ dnl as-ac-expand.m4 0.2.0
|
|||||||
dnl autostars m4 macro for expanding directories using configure's prefix
|
dnl autostars m4 macro for expanding directories using configure's prefix
|
||||||
dnl thomas@apestaart.org
|
dnl thomas@apestaart.org
|
||||||
dnl
|
dnl
|
||||||
|
|
||||||
dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
|
dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
|
||||||
dnl example
|
dnl example
|
||||||
dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
|
dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
|
||||||
dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local
|
dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local
|
||||||
|
|
||||||
AC_DEFUN([AS_AC_EXPAND],
|
AC_DEFUN([AS_AC_EXPAND],
|
||||||
[
|
[
|
||||||
EXP_VAR=[$1]
|
EXP_VAR=[$1]
|
||||||
FROM_VAR=[$2]
|
FROM_VAR=[$2]
|
||||||
|
|
||||||
dnl first expand prefix and exec_prefix if necessary
|
dnl first expand prefix and exec_prefix if necessary
|
||||||
prefix_save=$prefix
|
prefix_save=$prefix
|
||||||
exec_prefix_save=$exec_prefix
|
exec_prefix_save=$exec_prefix
|
||||||
|
|
||||||
dnl if no prefix given, then use /usr/local, the default prefix
|
dnl if no prefix given, then use /usr/local, the default prefix
|
||||||
if test "x$prefix" = "xNONE"; then
|
if test "x$prefix" = "xNONE"; then
|
||||||
prefix="$ac_default_prefix"
|
prefix="$ac_default_prefix"
|
||||||
@ -25,7 +25,7 @@ AC_DEFUN([AS_AC_EXPAND],
|
|||||||
if test "x$exec_prefix" = "xNONE"; then
|
if test "x$exec_prefix" = "xNONE"; then
|
||||||
exec_prefix=$prefix
|
exec_prefix=$prefix
|
||||||
fi
|
fi
|
||||||
|
|
||||||
full_var="$FROM_VAR"
|
full_var="$FROM_VAR"
|
||||||
dnl loop until it doesn't change anymore
|
dnl loop until it doesn't change anymore
|
||||||
while true; do
|
while true; do
|
||||||
@ -33,11 +33,11 @@ AC_DEFUN([AS_AC_EXPAND],
|
|||||||
if test "x$new_full_var" = "x$full_var"; then break; fi
|
if test "x$new_full_var" = "x$full_var"; then break; fi
|
||||||
full_var=$new_full_var
|
full_var=$new_full_var
|
||||||
done
|
done
|
||||||
|
|
||||||
dnl clean up
|
dnl clean up
|
||||||
full_var=$new_full_var
|
full_var=$new_full_var
|
||||||
AC_SUBST([$1], "$full_var")
|
AC_SUBST([$1], "$full_var")
|
||||||
|
|
||||||
dnl restore prefix and exec_prefix
|
dnl restore prefix and exec_prefix
|
||||||
prefix=$prefix_save
|
prefix=$prefix_save
|
||||||
exec_prefix=$exec_prefix_save
|
exec_prefix=$exec_prefix_save
|
||||||
@ -94,7 +94,7 @@ x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"`
|
|||||||
# Determine the number of characters in A and B.
|
# Determine the number of characters in A and B.
|
||||||
ax_compare_version_len_A=`echo "$A" | awk '{print(length)}'`
|
ax_compare_version_len_A=`echo "$A" | awk '{print(length)}'`
|
||||||
ax_compare_version_len_B=`echo "$B" | awk '{print(length)}'`
|
ax_compare_version_len_B=`echo "$B" | awk '{print(length)}'`
|
||||||
|
|
||||||
# Set A to no more than B's length and B to no more than A's length.
|
# Set A to no more than B's length and B to no more than A's length.
|
||||||
A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
|
A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
|
||||||
B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`
|
B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`
|
||||||
|
3
config/lxc.conf.libvirt
Normal file
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_SRCDIR([configure.ac])
|
||||||
AC_CONFIG_AUX_DIR([config])
|
AC_CONFIG_AUX_DIR([config])
|
||||||
AM_CONFIG_HEADER([src/config.h])
|
AM_CONFIG_HEADER([src/config.h])
|
||||||
AM_INIT_AUTOMAKE([-Wno-portability])
|
AM_INIT_AUTOMAKE([-Wall -Werror -Wno-portability])
|
||||||
AC_CANONICAL_HOST
|
AC_CANONICAL_HOST
|
||||||
AM_PROG_CC_C_O
|
AM_PROG_CC_C_O
|
||||||
AC_GNU_SOURCE
|
AC_GNU_SOURCE
|
||||||
AC_CHECK_PROG(SETCAP, setcap, yes, no, $PATH$PATH_SEPARATOR/sbin)
|
AC_CHECK_PROG(SETCAP, setcap, yes, no, $PATH$PATH_SEPARATOR/sbin)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([host distribution])
|
||||||
|
AC_ARG_WITH(distro, AS_HELP_STRING([--with-distro=DISTRO], [Specify the Linux distribution to target: One of redhat, oracle, fedora, suse, gentoo, debian, arch, slackware, paldo, mandriva or pardus]))
|
||||||
|
if test "z$with_distro" = "z"; then
|
||||||
|
with_distro=`lsb_release -is`
|
||||||
|
fi
|
||||||
|
if test "z$with_distro" = "z"; then
|
||||||
|
AC_CHECK_FILE(/etc/redhat-release,with_distro="redhat")
|
||||||
|
AC_CHECK_FILE(/etc/oracle-release,with_distro="oracle")
|
||||||
|
AC_CHECK_FILE(/etc/fedora-release,with_distro="fedora")
|
||||||
|
AC_CHECK_FILE(/etc/SuSE-release,with_distro="suse")
|
||||||
|
AC_CHECK_FILE(/etc/gentoo-release,with_distro="gentoo")
|
||||||
|
AC_CHECK_FILE(/etc/debian_version,with_distro="debian")
|
||||||
|
AC_CHECK_FILE(/etc/arch-release,with_distro="arch")
|
||||||
|
AC_CHECK_FILE(/etc/slackware-version,with_distro="slackware")
|
||||||
|
AC_CHECK_FILE(/etc/frugalware-release,with_distro="frugalware")
|
||||||
|
AC_CHECK_FILE(/etc/mandrakelinux-release, with_distro="mandriva")
|
||||||
|
AC_CHECK_FILE(/etc/mandriva-release,with_distro="mandriva")
|
||||||
|
AC_CHECK_FILE(/etc/pardus-release,with_distro="pardus")
|
||||||
|
fi
|
||||||
|
with_distro=`echo ${with_distro} | tr '[[:upper:]]' '[[:lower:]]'`
|
||||||
|
|
||||||
|
if test "z$with_distro" = "z"; then
|
||||||
|
with_distro="unknown"
|
||||||
|
fi
|
||||||
|
case $with_distro in
|
||||||
|
ubuntu)
|
||||||
|
conffile=lxc.conf.ubuntu
|
||||||
|
;;
|
||||||
|
redhat|fedora|oracle|oracleserver)
|
||||||
|
conffile=lxc.conf.libvirt
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -n "Linux distribution network config unknown, defaulting to lxc.network.type = empty"
|
||||||
|
conffile=lxc.conf.unknown
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
AC_MSG_RESULT([$with_distro])
|
||||||
|
|
||||||
|
AM_CONDITIONAL([HAVE_DEBIAN], [test x"$with_distro" = "xdebian" -o x"$with_distro" = "xubuntu"])
|
||||||
|
|
||||||
AC_ARG_ENABLE([rpath],
|
AC_ARG_ENABLE([rpath],
|
||||||
[AC_HELP_STRING([--disable-rpath], [do not set rpath in executables])],
|
[AC_HELP_STRING([--disable-rpath], [do not set rpath in executables])],
|
||||||
[], [enable_rpath=yes])
|
[], [enable_rpath=yes])
|
||||||
|
|
||||||
AM_CONDITIONAL([ENABLE_RPATH], [test "x$enable_rpath" = "xyes"])
|
AM_CONDITIONAL([ENABLE_RPATH], [test "x$enable_rpath" = "xyes"])
|
||||||
|
|
||||||
AC_ARG_ENABLE([apparmor],
|
|
||||||
[AC_HELP_STRING([--enable-apparmor], [enable apparmor])],
|
|
||||||
[], [enable_apparmor=yes])
|
|
||||||
AM_CONDITIONAL([ENABLE_APPARMOR], [test "x$enable_apparmor" = "xyes"])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([doc],
|
AC_ARG_ENABLE([doc],
|
||||||
[AC_HELP_STRING([--enable-doc], [make mans (require docbook2man installed) [default=auto]])],
|
[AC_HELP_STRING([--enable-doc], [make mans (require docbook2x-man installed) [default=auto]])],
|
||||||
[], [enable_doc=auto])
|
[], [enable_doc=auto])
|
||||||
|
|
||||||
if test "x$enable_doc" = "xyes" -o "x$enable_doc" = "xauto"; then
|
if test "x$enable_doc" = "xyes" -o "x$enable_doc" = "xauto"; then
|
||||||
AC_CHECK_PROG(have_docbook, [docbook2man], [yes], [no])
|
db2xman=""
|
||||||
|
|
||||||
test "x$have_docbook" = "xno" -a "x$enable_doc" = "xyes" && \
|
AC_MSG_CHECKING(for docbook2x-man)
|
||||||
AC_MSG_ERROR([docbook2man required by man request, but not found])
|
for name in docbook2x-man db2x_docbook2man; do
|
||||||
|
if "$name" --help >/dev/null 2>&1; then
|
||||||
|
db2xman="$name"
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if test -n "${db2xman}"; then
|
||||||
|
AC_MSG_RESULT(${db2xman})
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
if test "x$enable_doc" = "xyes"; then
|
||||||
|
AC_MSG_ERROR([docbook2x-man required by man request, but not found])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(db2xman)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([apparmor],
|
||||||
|
[AC_HELP_STRING([--enable-apparmor], [enable apparmor])],
|
||||||
|
[], [enable_apparmor=check])
|
||||||
|
|
||||||
|
if test "$enable_apparmor" = "check" ; then
|
||||||
|
AC_CHECK_LIB([apparmor],[aa_change_profile],[enable_apparmor=yes], [enable_apparmor=no])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL([ENABLE_APPARMOR], [test "x$enable_apparmor" = "xyes"])
|
||||||
|
|
||||||
AM_COND_IF([ENABLE_APPARMOR],
|
AM_COND_IF([ENABLE_APPARMOR],
|
||||||
[AC_CHECK_HEADER([sys/apparmor.h],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
|
[AC_CHECK_HEADER([sys/apparmor.h],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
|
||||||
AC_CHECK_LIB([apparmor], [aa_change_profile],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
|
AC_CHECK_LIB([apparmor], [aa_change_profile],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
|
||||||
AC_SUBST([APPARMOR_LIBS], [-lapparmor])])
|
AC_SUBST([APPARMOR_LIBS], [-lapparmor])])
|
||||||
|
|
||||||
AM_CONDITIONAL([ENABLE_DOCBOOK], [test "x$have_docbook" = "xyes"])
|
AC_ARG_ENABLE([seccomp],
|
||||||
|
[AC_HELP_STRING([--enable-seccomp], [enable seccomp])],
|
||||||
|
[], [enable_seccomp=check])
|
||||||
|
|
||||||
|
if test "$enable_seccomp" = "check" ; then
|
||||||
|
AC_CHECK_LIB([seccomp],[seccomp_init],[enable_seccomp=yes],[enable_seccomp=no])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL([ENABLE_SECCOMP], [test "x$enable_seccomp" = "xyes"])
|
||||||
|
|
||||||
|
AM_COND_IF([ENABLE_SECCOMP],
|
||||||
|
[AC_CHECK_HEADER([seccomp.h],[],[AC_MSG_ERROR([You must install the seccomp development package in order to compile lxc])])
|
||||||
|
AC_CHECK_LIB([seccomp], [seccomp_init],[],[AC_MSG_ERROR([You must install the seccomp development package in order to compile lxc])])
|
||||||
|
AC_SUBST([SECCOMP_LIBS], [-lseccomp])])
|
||||||
|
|
||||||
|
# HAVE_SCMP_FILTER_CTX=1 will tell us we have libseccomp api >= 1.0.0
|
||||||
|
AC_CHECK_TYPES([scmp_filter_ctx], [], [], [#include <seccomp.h>])
|
||||||
|
|
||||||
|
AM_CONDITIONAL([ENABLE_DOCBOOK], [test "x$db2xman" != "x"])
|
||||||
|
|
||||||
AC_ARG_ENABLE([examples],
|
AC_ARG_ENABLE([examples],
|
||||||
[AC_HELP_STRING([--disable-examples], [do not install configuration examples])],
|
[AC_HELP_STRING([--disable-examples], [do not install configuration examples])],
|
||||||
@ -47,6 +126,23 @@ AC_ARG_ENABLE([examples],
|
|||||||
|
|
||||||
AM_CONDITIONAL([ENABLE_EXAMPLES], [test "x$enable_examples" = "xyes"])
|
AM_CONDITIONAL([ENABLE_EXAMPLES], [test "x$enable_examples" = "xyes"])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([python],
|
||||||
|
[AC_HELP_STRING([--enable-python], [enable python binding])],
|
||||||
|
[enable_python=yes], [enable_python=no])
|
||||||
|
|
||||||
|
AM_CONDITIONAL([ENABLE_PYTHON], [test "x$enable_python" = "xyes"])
|
||||||
|
|
||||||
|
AM_COND_IF([ENABLE_PYTHON],
|
||||||
|
[AM_PATH_PYTHON([3.2], [], [AC_MSG_ERROR([You must install python3])])
|
||||||
|
AC_CHECK_HEADER([python$PYTHON_VERSION/Python.h],[],[AC_MSG_ERROR([You must install python3-dev])])
|
||||||
|
AC_DEFINE_UNQUOTED([ENABLE_PYTHON], 1, [Python3 is available])])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([tests],
|
||||||
|
[AC_HELP_STRING([--enable-tests], [build test/example binaries])],
|
||||||
|
[enable_tests=yes], [enable_tests=no])
|
||||||
|
|
||||||
|
AM_CONDITIONAL([ENABLE_TESTS], [test "x$enable_tests" = "xyes"])
|
||||||
|
|
||||||
AS_AC_EXPAND(PREFIX, $prefix)
|
AS_AC_EXPAND(PREFIX, $prefix)
|
||||||
AS_AC_EXPAND(LIBDIR, $libdir)
|
AS_AC_EXPAND(LIBDIR, $libdir)
|
||||||
AS_AC_EXPAND(BINDIR, $bindir)
|
AS_AC_EXPAND(BINDIR, $bindir)
|
||||||
@ -69,12 +165,13 @@ AC_ARG_WITH([rootfs-path],
|
|||||||
[lxc rootfs mount point]
|
[lxc rootfs mount point]
|
||||||
)], [], [with_rootfs_path=['${libdir}/lxc/rootfs']])
|
)], [], [with_rootfs_path=['${libdir}/lxc/rootfs']])
|
||||||
|
|
||||||
|
AS_AC_EXPAND(LXC_CONFFILE, $conffile)
|
||||||
AS_AC_EXPAND(LXC_GENERATE_DATE, "$(date)")
|
AS_AC_EXPAND(LXC_GENERATE_DATE, "$(date)")
|
||||||
AS_AC_EXPAND(LXCPATH, "${with_config_path}")
|
AS_AC_EXPAND(LXCPATH, "${with_config_path}")
|
||||||
AS_AC_EXPAND(LXCROOTFSMOUNT, "${with_rootfs_path}")
|
AS_AC_EXPAND(LXCROOTFSMOUNT, "${with_rootfs_path}")
|
||||||
AS_AC_EXPAND(LXCTEMPLATEDIR, ['${datadir}/lxc/templates'])
|
AS_AC_EXPAND(LXCTEMPLATEDIR, ['${datadir}/lxc/templates'])
|
||||||
|
|
||||||
AC_SUBST(LXCINITDIR, ['${libexecdir}'])
|
AS_AC_EXPAND(LXCINITDIR, ['${libexecdir}'])
|
||||||
|
|
||||||
AC_CHECK_HEADERS([linux/unistd.h linux/netlink.h linux/genetlink.h],
|
AC_CHECK_HEADERS([linux/unistd.h linux/netlink.h linux/genetlink.h],
|
||||||
[],
|
[],
|
||||||
@ -101,9 +198,10 @@ AC_CHECK_DECLS([PR_CAPBSET_DROP], [], [], [#include <sys/prctl.h>])
|
|||||||
AC_CHECK_HEADERS([sys/signalfd.h])
|
AC_CHECK_HEADERS([sys/signalfd.h])
|
||||||
|
|
||||||
AC_PROG_GCC_TRADITIONAL
|
AC_PROG_GCC_TRADITIONAL
|
||||||
|
AC_PROG_SED
|
||||||
|
|
||||||
if test "x$GCC" = "xyes"; then
|
if test "x$GCC" = "xyes"; then
|
||||||
CFLAGS="$CFLAGS -Wall"
|
CFLAGS="$CFLAGS -Wall -Werror"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_CONFIG_FILES([
|
AC_CONFIG_FILES([
|
||||||
@ -134,6 +232,7 @@ AC_CONFIG_FILES([
|
|||||||
doc/lxc.sgml
|
doc/lxc.sgml
|
||||||
doc/common_options.sgml
|
doc/common_options.sgml
|
||||||
doc/see_also.sgml
|
doc/see_also.sgml
|
||||||
|
doc/legacy/lxc-ls.sgml
|
||||||
|
|
||||||
doc/rootfs/Makefile
|
doc/rootfs/Makefile
|
||||||
|
|
||||||
@ -154,6 +253,7 @@ AC_CONFIG_FILES([
|
|||||||
templates/lxc-opensuse
|
templates/lxc-opensuse
|
||||||
templates/lxc-busybox
|
templates/lxc-busybox
|
||||||
templates/lxc-fedora
|
templates/lxc-fedora
|
||||||
|
templates/lxc-oracle
|
||||||
templates/lxc-altlinux
|
templates/lxc-altlinux
|
||||||
templates/lxc-sshd
|
templates/lxc-sshd
|
||||||
templates/lxc-archlinux
|
templates/lxc-archlinux
|
||||||
@ -161,7 +261,6 @@ AC_CONFIG_FILES([
|
|||||||
src/Makefile
|
src/Makefile
|
||||||
src/lxc/Makefile
|
src/lxc/Makefile
|
||||||
src/lxc/lxc-ps
|
src/lxc/lxc-ps
|
||||||
src/lxc/lxc-ls
|
|
||||||
src/lxc/lxc-netstat
|
src/lxc/lxc-netstat
|
||||||
src/lxc/lxc-checkconfig
|
src/lxc/lxc-checkconfig
|
||||||
src/lxc/lxc-setcap
|
src/lxc/lxc-setcap
|
||||||
@ -170,7 +269,15 @@ AC_CONFIG_FILES([
|
|||||||
src/lxc/lxc-create
|
src/lxc/lxc-create
|
||||||
src/lxc/lxc-clone
|
src/lxc/lxc-clone
|
||||||
src/lxc/lxc-shutdown
|
src/lxc/lxc-shutdown
|
||||||
|
src/lxc/lxc-start-ephemeral
|
||||||
src/lxc/lxc-destroy
|
src/lxc/lxc-destroy
|
||||||
|
src/lxc/legacy/lxc-ls
|
||||||
|
|
||||||
|
src/python-lxc/Makefile
|
||||||
|
src/python-lxc/lxc/__init__.py
|
||||||
|
src/python-lxc/examples/api_test.py
|
||||||
|
|
||||||
|
src/tests/Makefile
|
||||||
|
|
||||||
])
|
])
|
||||||
AC_CONFIG_COMMANDS([default],[[]],[[]])
|
AC_CONFIG_COMMANDS([default],[[]],[[]])
|
||||||
|
@ -32,8 +32,8 @@ error when starting a container.
|
|||||||
"[syserr] lxc_start:96: Invalid argument - failed to fork into a new
|
"[syserr] lxc_start:96: Invalid argument - failed to fork into a new
|
||||||
namespace"
|
namespace"
|
||||||
|
|
||||||
Answer:
|
Answer:
|
||||||
-------
|
-------
|
||||||
|
|
||||||
read the lxc man page about kernel version prereq :) most probably
|
read the lxc man page about kernel version prereq :) most probably
|
||||||
your kernel is not configured to support the container options you
|
your kernel is not configured to support the container options you
|
||||||
|
@ -19,7 +19,6 @@ man_MANS = \
|
|||||||
lxc-unfreeze.1 \
|
lxc-unfreeze.1 \
|
||||||
lxc-monitor.1 \
|
lxc-monitor.1 \
|
||||||
lxc-wait.1 \
|
lxc-wait.1 \
|
||||||
lxc-ls.1 \
|
|
||||||
lxc-ps.1 \
|
lxc-ps.1 \
|
||||||
lxc-cgroup.1 \
|
lxc-cgroup.1 \
|
||||||
lxc-kill.1 \
|
lxc-kill.1 \
|
||||||
@ -29,15 +28,23 @@ man_MANS = \
|
|||||||
\
|
\
|
||||||
lxc.7
|
lxc.7
|
||||||
|
|
||||||
|
if ENABLE_PYTHON
|
||||||
|
man_MANS += lxc-ls.1
|
||||||
|
else
|
||||||
|
man_MANS += legacy/lxc-ls.1
|
||||||
|
endif
|
||||||
|
|
||||||
%.1 : %.sgml
|
%.1 : %.sgml
|
||||||
docbook2man -w all $<
|
$(db2xman) $<
|
||||||
|
test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
|
||||||
|
|
||||||
%.5 : %.sgml
|
%.5 : %.sgml
|
||||||
docbook2man -w all $<
|
$(db2xman) $<
|
||||||
|
test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
|
||||||
|
|
||||||
%.7 : %.sgml
|
%.7 : %.sgml
|
||||||
docbook2man -w all $<
|
$(db2xman) $<
|
||||||
|
test "$(shell basename $@)" != "$@" && mv $(shell basename $@) $@ || true
|
||||||
|
|
||||||
lxc-%.sgml : common_options.sgml see_also.sgml
|
lxc-%.sgml : common_options.sgml see_also.sgml
|
||||||
|
|
||||||
|
156
doc/legacy/lxc-ls.sgml.in
Normal file
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 commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -52,6 +52,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
<arg choice="req">-n <replaceable>name</replaceable></arg>
|
<arg choice="req">-n <replaceable>name</replaceable></arg>
|
||||||
<arg choice="opt">-a <replaceable>arch</replaceable></arg>
|
<arg choice="opt">-a <replaceable>arch</replaceable></arg>
|
||||||
<arg choice="opt">-e</arg>
|
<arg choice="opt">-e</arg>
|
||||||
|
<arg choice="opt">-s <replaceable>namespaces</replaceable></arg>
|
||||||
|
<arg choice="opt">-R</arg>
|
||||||
<arg choice="opt">-- <replaceable>command</replaceable></arg>
|
<arg choice="opt">-- <replaceable>command</replaceable></arg>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
@ -125,7 +127,53 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>-s, --namespaces <replaceable>namespaces</replaceable></option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Specify the namespaces to attach to, as a pipe-separated list,
|
||||||
|
e.g. <replaceable>NETWORK|IPC</replaceable>. Allowed values are
|
||||||
|
<replaceable>MOUNT</replaceable>, <replaceable>PID</replaceable>,
|
||||||
|
<replaceable>UTSNAME</replaceable>, <replaceable>IPC</replaceable>,
|
||||||
|
<replaceable>USER </replaceable> and
|
||||||
|
<replaceable>NETWORK</replaceable>. This allows one to change
|
||||||
|
the context of the process to e.g. the network namespace of the
|
||||||
|
container while retaining the other namespaces as those of the
|
||||||
|
host.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>Important:</emphasis> This option implies
|
||||||
|
<option>-e</option>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>-R, --remount-sys-proc</option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
When using <option>-s</option> and the mount namespace is not
|
||||||
|
included, this flag will cause <command>lxc-attach</command>
|
||||||
|
to remount <replaceable>/proc</replaceable> and
|
||||||
|
<replaceable>/sys</replaceable> to reflect the current other
|
||||||
|
namespace contexts.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Please see the <emphasis>Notes</emphasis> section for more
|
||||||
|
details.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
This option will be ignored if one tries to attach to the
|
||||||
|
mount namespace anyway.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
@ -147,19 +195,86 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To deactivate the network link eth1 of a running container that
|
To deactivate the network link eth1 of a running container that
|
||||||
does not have the NET_ADMIN capability, use the <option>-e</option>
|
does not have the NET_ADMIN capability, use either the
|
||||||
option to use increased capabilities:
|
<option>-e</option> option to use increased capabilities,
|
||||||
|
assuming the <command>ip</command> tool is installed:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
lxc-attach -n container -e -- /sbin/ip link delete eth1
|
lxc-attach -n container -e -- /sbin/ip link delete eth1
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
Or, alternatively, use the <option>-s</option> to use the
|
||||||
|
tools installed on the host outside the container:
|
||||||
|
<programlisting>
|
||||||
|
lxc-attach -n container -s NETWORK -- /sbin/ip link delete eth1
|
||||||
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Compatibility</title>
|
||||||
|
<para>
|
||||||
|
Attaching completely (including the pid and mount namespaces) to a
|
||||||
|
container requires a patched kernel, please see the lxc website for
|
||||||
|
details. <command>lxc-attach</command> will fail in that case if
|
||||||
|
used with an unpatched kernel.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Nevertheless, it will succeed on an unpatched kernel of version 3.0
|
||||||
|
or higher if the <option>-s</option> option is used to restrict the
|
||||||
|
namespaces that the process is to be attached to to one or more of
|
||||||
|
<replaceable>NETWORK</replaceable>, <replaceable>IPC</replaceable>
|
||||||
|
and <replaceable>UTSNAME</replaceable>.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Attaching to user namespaces is currently completely unsupported
|
||||||
|
by the kernel. <command>lxc-attach</command> should however be able
|
||||||
|
to do this once once future kernel versions implement this.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Notes</title>
|
||||||
|
<para>
|
||||||
|
The Linux <replaceable>/proc</replaceable> and
|
||||||
|
<replaceable>/sys</replaceable> filesystems contain information
|
||||||
|
about some quantities that are affected by namespaces, such as
|
||||||
|
the directories named after process ids in
|
||||||
|
<replaceable>/proc</replaceable> or the network interface infromation
|
||||||
|
in <replaceable>/sys/class/net</replaceable>. The namespace of the
|
||||||
|
process mounting the pseudo-filesystems determines what information
|
||||||
|
is shown, <emphasis>not</emphasis> the namespace of the process
|
||||||
|
accessing <replaceable>/proc</replaceable> or
|
||||||
|
<replaceable>/sys</replaceable>.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
If one uses the <option>-s</option> option to only attach to
|
||||||
|
the pid namespace of a container, but not its mount namespace
|
||||||
|
(which will contain the <replaceable>/proc</replaceable> of the
|
||||||
|
container and not the host), the contents of <option>/proc</option>
|
||||||
|
will reflect that of the host and not the container. Analogously,
|
||||||
|
the same issue occurs when reading the contents of
|
||||||
|
<replaceable>/sys/class/net</replaceable> and attaching to just
|
||||||
|
the network namespace.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
To work around this problem, the <option>-R</option> flag provides
|
||||||
|
the option to remount <replaceable>/proc</replaceable> and
|
||||||
|
<replaceable>/sys</replaceable> in order for them to reflect the
|
||||||
|
network/pid namespace context of the attached process. In order
|
||||||
|
not to interfere with the host's actual filesystem, the mount
|
||||||
|
namespace will be unshared (like <command>lxc-unshare</command>
|
||||||
|
does) before this is done, esentially giving the process a new
|
||||||
|
mount namespace, which is identical to the hosts's mount namespace
|
||||||
|
except for the <replaceable>/proc</replaceable> and
|
||||||
|
<replaceable>/sys</replaceable> filesystems.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Security</title>
|
<title>Security</title>
|
||||||
<para>
|
<para>
|
||||||
The <option>-e</option> should be used with care, as it may break
|
The <option>-e</option> and <option>-s</option> options should
|
||||||
the isolation of the containers if used improperly.
|
be used with care, as it may break the isolation of the containers
|
||||||
|
if used improperly.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -143,7 +143,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
The container is not running.
|
The container is not running.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -67,7 +67,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
The available tty are free slots taken by this command. That
|
The available tty are free slots taken by this command. That
|
||||||
means if the container has four ttys available and the command
|
means if the container has four ttys available and the command
|
||||||
has been launched four times taking the different tty, the fifth
|
has been launched four times taking the different tty, the fifth
|
||||||
command will fail because no console will be available.
|
command will fail because no console will be available.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -114,7 +114,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
user "foo" and "bar" is trying to open a console to it.
|
user "foo" and "bar" is trying to open a console to it.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -113,6 +113,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
eg. busybox, debian, fedora, ubuntu or sshd.
|
eg. busybox, debian, fedora, ubuntu or sshd.
|
||||||
Refer to the examples in <filename>@LXCTEMPLATEDIR@</filename>
|
Refer to the examples in <filename>@LXCTEMPLATEDIR@</filename>
|
||||||
for details of the expected script structure.
|
for details of the expected script structure.
|
||||||
|
Alternatively, the full path to an executable template script
|
||||||
|
can also be passed as a parameter.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -123,9 +125,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
</term>
|
</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
'backingstore' is one of 'none', 'lvm', or 'btrfs'. The
|
'backingstore' is one of 'none', 'dir', 'lvm', or 'btrfs'. The
|
||||||
default is 'none', meaning that the container root filesystem
|
default is 'none', meaning that the container root filesystem
|
||||||
will be a directory under <filename>@LXCPATH@/container/rootfs</filename>.
|
will be a directory under <filename>@LXCPATH@/container/rootfs</filename>.
|
||||||
|
'dir' has the same meaning as 'none', but also allows the optional
|
||||||
|
<replaceable>--dir ROOTFS</replaceable> to be specified, meaning
|
||||||
|
that the container rootfs should be placed under the specified path,
|
||||||
|
rather than the default.
|
||||||
The option 'btrfs' need not be specified as it will be used
|
The option 'btrfs' need not be specified as it will be used
|
||||||
automatically if the <filename>@LXCPATH@</filename> filesystem is found to
|
automatically if the <filename>@LXCPATH@</filename> filesystem is found to
|
||||||
be btrfs. If backingstore is 'lvm', then an lvm block device will be
|
be btrfs. If backingstore is 'lvm', then an lvm block device will be
|
||||||
@ -141,6 +147,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
filesystem) of size SIZE rather than the default, which is 1G.
|
filesystem) of size SIZE rather than the default, which is 1G.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>
|
<term>
|
||||||
@ -175,7 +182,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
available containers on the system.
|
available containers on the system.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -100,7 +100,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
command to list the available containers on the system.
|
command to list the available containers on the system.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -162,7 +162,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
container or create a new one.
|
container or create a new one.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -81,7 +81,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
the <command>lxc-create</command> command.
|
the <command>lxc-create</command> command.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
]>
|
]>
|
||||||
@ -49,8 +49,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<cmdsynopsis>
|
<cmdsynopsis>
|
||||||
<command>lxc-ls</command>
|
<command>lxc-ls</command>
|
||||||
|
<arg choice="opt">-1</arg>
|
||||||
<arg choice="opt">--active</arg>
|
<arg choice="opt">--active</arg>
|
||||||
<arg choice="opt">ls option</arg>
|
<arg choice="opt">--frozen</arg>
|
||||||
|
<arg choice="opt">--running</arg>
|
||||||
|
<arg choice="opt">--stopped</arg>
|
||||||
|
<arg choice="opt">--fancy</arg>
|
||||||
|
<arg choice="opt">--fancy-format</arg>
|
||||||
|
<arg choice="opt">filter</arg>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
@ -65,77 +71,136 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Options</title>
|
<title>Options</title>
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>
|
<term>
|
||||||
<option><optional>--active</optional></option>
|
<option><optional>-1</optional></option>
|
||||||
</term>
|
</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
List active containers.
|
Show one entry per line. (default when /dev/stdout isn't a tty)
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>
|
<term>
|
||||||
<option><optional>ls options</optional></option>
|
<option><optional>--active</optional></option>
|
||||||
</term>
|
</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The option passed to <command>lxc-ls</command> are the
|
List only active containers (same as --frozen --running).
|
||||||
same as the <command>ls</command> command.
|
</para>
|
||||||
</para>
|
</listitem>
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
</variablelist>
|
|
||||||
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
<title>Examples</title>
|
|
||||||
<variablelist>
|
|
||||||
<varlistentry>
|
|
||||||
<term>lxc-ls -l</term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
list all the container and their permissions.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>lxc-ls --active -1</term>
|
<term>
|
||||||
<listitem>
|
<option><optional>--frozen</optional></option>
|
||||||
<para>
|
</term>
|
||||||
list active containers and display the list in one column.
|
<listitem>
|
||||||
</para>
|
<para>
|
||||||
</listitem>
|
List only frozen containers.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option><optional>--running</optional></option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
List only running containers.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option><optional>--stopped</optional></option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
List only stopped containers.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option><optional>--fancy</optional></option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Use a fancy, column-based output.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option><optional>--fancy-format</optional></option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Comma separate list of column to show in the fancy output.
|
||||||
|
Valid values are: name, state, ipv4, ipv6 and pid
|
||||||
|
Default is: name,state,ipv4,ipv6
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option><optional>filter</optional></option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The filter passed to <command>lxc-ls</command> will be
|
||||||
|
applied to the container name. The format is a regular expression.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See Also</title>
|
<title>See Also</title>
|
||||||
|
|
||||||
<simpara>
|
<simpara>
|
||||||
<citerefentry>
|
<citerefentry>
|
||||||
<refentrytitle>ls</refentrytitle>
|
<refentrytitle>ls</refentrytitle>
|
||||||
<manvolnum>1</manvolnum>
|
<manvolnum>1</manvolnum>
|
||||||
</citerefentry>,
|
</citerefentry>,
|
||||||
</simpara>
|
</simpara>
|
||||||
|
|
||||||
</refsect1>
|
<title>Examples</title>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>lxc-ls --fancy</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
list all the containers, listing one per line along with its
|
||||||
|
name, state, ipv4 and ipv6 addresses.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
&seealso;
|
<varlistentry>
|
||||||
|
<term>lxc-ls --active -1</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
list active containers and display the list in one column.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Author</title>
|
<title>Author</title>
|
||||||
<para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
|
<para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|
||||||
<!-- Keep this comment at the end of the file
|
<!-- Keep this comment at the end of the file
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -135,7 +135,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
the <command>lxc-create</command> command.
|
the <command>lxc-create</command> command.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
@ -145,7 +145,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See Also</title>
|
<title>See Also</title>
|
||||||
|
|
||||||
<simpara>
|
<simpara>
|
||||||
<citerefentry>
|
<citerefentry>
|
||||||
<refentrytitle>regex</refentrytitle>
|
<refentrytitle>regex</refentrytitle>
|
||||||
<manvolnum>7</manvolnum>
|
<manvolnum>7</manvolnum>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
]>
|
]>
|
||||||
@ -86,8 +86,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
specify the container <replaceable>name</replaceable>
|
specify the container <replaceable>name</replaceable>
|
||||||
to limit the output to the processes belonging
|
to limit the output to the processes belonging
|
||||||
to this container name.
|
to this container name.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -98,7 +98,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
</term>
|
</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
limit the output to the processes belonging
|
limit the output to the processes belonging
|
||||||
to all lxc containers.
|
to all lxc containers.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
@ -139,7 +139,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See Also</title>
|
<title>See Also</title>
|
||||||
|
|
||||||
<simpara>
|
<simpara>
|
||||||
<citerefentry>
|
<citerefentry>
|
||||||
<refentrytitle>ps</refentrytitle>
|
<refentrytitle>ps</refentrytitle>
|
||||||
<manvolnum>1</manvolnum>
|
<manvolnum>1</manvolnum>
|
||||||
|
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
|
@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -53,6 +53,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
<arg choice="opt">-f <replaceable>config_file</replaceable></arg>
|
<arg choice="opt">-f <replaceable>config_file</replaceable></arg>
|
||||||
<arg choice="opt">-c <replaceable>console_file</replaceable></arg>
|
<arg choice="opt">-c <replaceable>console_file</replaceable></arg>
|
||||||
<arg choice="opt">-d</arg>
|
<arg choice="opt">-d</arg>
|
||||||
|
<arg choice="opt">-p <replaceable>pid_file</replaceable></arg>
|
||||||
<arg choice="opt">-s KEY=VAL</arg>
|
<arg choice="opt">-s KEY=VAL</arg>
|
||||||
<arg choice="opt">-C</arg>
|
<arg choice="opt">-C</arg>
|
||||||
<arg choice="opt">command</arg>
|
<arg choice="opt">command</arg>
|
||||||
@ -107,6 +108,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>-p, --pidfile <replaceable>pid_file</replaceable></option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Create a file with the process id.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>
|
<term>
|
||||||
<option>-f, --rcfile <replaceable>config_file</replaceable></option>
|
<option>-f, --rcfile <replaceable>config_file</replaceable></option>
|
||||||
@ -186,7 +198,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
container or create a new one.
|
container or create a new one.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -80,7 +80,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
container or create a new one.
|
container or create a new one.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>The container was not found</term>
|
<term>The container was not found</term>
|
||||||
@ -90,7 +90,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
the <command>lxc-create</command> command.
|
the <command>lxc-create</command> command.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -78,7 +78,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
the <command>lxc-create</command> command.
|
the <command>lxc-create</command> command.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
@ -79,6 +79,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>-t <replaceable>timeout</replaceable></option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Wait timeout seconds for desired state to be reached.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
@ -122,7 +133,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
the <command>lxc-create</command> command.
|
the <command>lxc-create</command> command.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
@ -16,7 +16,7 @@ lxc.network.type = macvlan
|
|||||||
|
|
||||||
# specify the flags to be used for the network, actually only <up> is allowed
|
# specify the flags to be used for the network, actually only <up> is allowed
|
||||||
# which mean the network should be set up when created. If the network is set
|
# which mean the network should be set up when created. If the network is set
|
||||||
# up, the loopback is automatically set up too.
|
# up, the loopback is automatically set up too.
|
||||||
lxc.network.flags = up
|
lxc.network.flags = up
|
||||||
|
|
||||||
# specify the physical network device which will communicate with the
|
# specify the physical network device which will communicate with the
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
]>
|
]>
|
||||||
@ -235,7 +235,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
specify an action to do for the
|
specify an action to do for the
|
||||||
network.
|
network.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para><option>up:</option> activates the interface.
|
<para><option>up:</option> activates the interface.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
@ -374,6 +374,26 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>lxc.network.script.down</option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
add a configuration option to specify a script to be
|
||||||
|
executed before destroying the network used from the
|
||||||
|
host side. The following arguments are passed to the
|
||||||
|
script: container name and config section name (net)
|
||||||
|
Additional arguments depend on the config section
|
||||||
|
employing a script hook; the following are used by the
|
||||||
|
network system: execution context (down), network type
|
||||||
|
(empty/veth/macvlan/phys), Depending on the network
|
||||||
|
type, other arguments may be passed:
|
||||||
|
veth/macvlan/phys. And finally (host-sided) device name.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
@ -481,6 +501,31 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2>
|
||||||
|
<title>/dev directory</title>
|
||||||
|
<para>
|
||||||
|
By default, lxc does nothing with the container's
|
||||||
|
<filename>/dev</filename>. This allows the container's
|
||||||
|
<filename>/dev</filename> to be set up as needed in the container
|
||||||
|
rootfs. If lxc.autodev is set to 1, then after mounting the container's
|
||||||
|
rootfs LXC will mount a fresh tmpfs under <filename>/dev</filename>
|
||||||
|
(limited to 100k) and fill in a minimal set of initial devices.
|
||||||
|
</para>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>lxc.autodev</option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Set this to 1 to have LXC mount and populate a minimal
|
||||||
|
<filename>/dev</filename> when starting the container.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Mount points</title>
|
<title>Mount points</title>
|
||||||
<para>
|
<para>
|
||||||
@ -640,6 +685,84 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2>
|
||||||
|
<title>Startup hooks</title>
|
||||||
|
<para>
|
||||||
|
Startup hooks are programs or scripts which can be executed
|
||||||
|
at various times in a container's lifetime.
|
||||||
|
</para>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>lxc.hook.pre-start</option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
A hook to be run in the host's namespace before the
|
||||||
|
container ttys, consoles, or mounts are up.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>lxc.hook.pre-mount</option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
A hook to be run in the container's fs namespace but before
|
||||||
|
the rootfs has been set up. This allows for manipulation
|
||||||
|
of the rootfs, i.e. to mount an encrypted filesystem. Mounts
|
||||||
|
done in this hook will not be reflected on the host (apart from
|
||||||
|
mounts propagation), so they will be automatically cleaned up
|
||||||
|
when the container shuts down.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>lxc.hook.mount</option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
A hook to be run in the container's namespace after
|
||||||
|
mounting has been done, but before the pivot_root.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>lxc.hook.start</option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
A hook to be run in the container's namespace immediately
|
||||||
|
before executing the container's init. This requires the
|
||||||
|
program to be available in the container.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>lxc.hook.post-stop</option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
A hook to be run in the host's namespace after the
|
||||||
|
container has been shut down.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
@ -726,7 +849,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See Also</title>
|
<title>See Also</title>
|
||||||
<simpara>
|
<simpara>
|
||||||
<citerefentry>
|
<citerefentry>
|
||||||
<refentrytitle><command>chroot</command></refentrytitle>
|
<refentrytitle><command>chroot</command></refentrytitle>
|
||||||
<manvolnum>1</manvolnum>
|
<manvolnum>1</manvolnum>
|
||||||
@ -744,14 +867,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
</simpara>
|
</simpara>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
&seealso;
|
&seealso;
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Author</title>
|
<title>Author</title>
|
||||||
<para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
|
<para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|
||||||
<!-- Keep this comment at the end of the file
|
<!-- Keep this comment at the end of the file
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
|
|
||||||
lxc: linux Container library
|
lxc: linux Container library
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||||
|
|
||||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||||
]>
|
]>
|
||||||
@ -239,7 +239,7 @@ rootfs
|
|||||||
/sbin /home/root/sshd/rootfs/sbin none ro,bind 0 0
|
/sbin /home/root/sshd/rootfs/sbin none ro,bind 0 0
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>How to run a system in a container ?</para>
|
<para>How to run a system in a container ?</para>
|
||||||
|
|
||||||
<para>Running a system inside a container is paradoxically easier
|
<para>Running a system inside a container is paradoxically easier
|
||||||
@ -249,7 +249,7 @@ rootfs
|
|||||||
without configuration because the container will set them
|
without configuration because the container will set them
|
||||||
up. eg. the ipv4 address will be setup by the system container
|
up. eg. the ipv4 address will be setup by the system container
|
||||||
init scripts. Here is an example of the mount points file:
|
init scripts. Here is an example of the mount points file:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[root@lxc debian]$ cat fstab
|
[root@lxc debian]$ cat fstab
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ rootfs
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
|
<![CDATA[
|
||||||
---------
|
---------
|
||||||
| STOPPED |<---------------
|
| STOPPED |<---------------
|
||||||
--------- |
|
--------- |
|
||||||
@ -305,14 +305,14 @@ rootfs
|
|||||||
---------- |
|
---------- |
|
||||||
| |
|
| |
|
||||||
---------------------
|
---------------------
|
||||||
|
]]>
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Configuration</title>
|
<title>Configuration</title>
|
||||||
<para>The container is configured through a configuration
|
<para>The container is configured through a configuration
|
||||||
file, the format of the configuration file is described in
|
file, the format of the configuration file is described in
|
||||||
<citerefentry>
|
<citerefentry>
|
||||||
<refentrytitle><filename>lxc.conf</filename></refentrytitle>
|
<refentrytitle><filename>lxc.conf</filename></refentrytitle>
|
||||||
<manvolnum>5</manvolnum>
|
<manvolnum>5</manvolnum>
|
||||||
@ -363,7 +363,7 @@ rootfs
|
|||||||
but if needed the <command>lxc-stop</command> command can
|
but if needed the <command>lxc-stop</command> command can
|
||||||
be used to kill the still running application.
|
be used to kill the still running application.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Running an application inside a container is not exactly the
|
Running an application inside a container is not exactly the
|
||||||
same thing as running a system. For this reason, there are two
|
same thing as running a system. For this reason, there are two
|
||||||
@ -434,7 +434,7 @@ rootfs
|
|||||||
lxc-freeze -n foo
|
lxc-freeze -n foo
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
will put all the processes in an uninteruptible state and
|
will put all the processes in an uninteruptible state and
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
lxc-unfreeze -n foo
|
lxc-unfreeze -n foo
|
||||||
@ -570,7 +570,7 @@ rootfs
|
|||||||
to the background.
|
to the background.
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
|
<![CDATA[
|
||||||
# launch lxc-wait in background
|
# launch lxc-wait in background
|
||||||
lxc-wait -n foo -s STOPPED &
|
lxc-wait -n foo -s STOPPED &
|
||||||
LXC_WAIT_PID=$!
|
LXC_WAIT_PID=$!
|
||||||
@ -583,7 +583,7 @@ rootfs
|
|||||||
# is STOPPED
|
# is STOPPED
|
||||||
wait $LXC_WAIT_PID
|
wait $LXC_WAIT_PID
|
||||||
echo "'foo' is finished"
|
echo "'foo' is finished"
|
||||||
|
]]>
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
READMEdir=@LXCROOTFSMOUNT@
|
READMEdir=@LXCROOTFSMOUNT@
|
||||||
|
|
||||||
README_DATA=README
|
README_DATA=README
|
||||||
|
@ -29,8 +29,8 @@ Summary: %{name} : Linux Container
|
|||||||
Group: Applications/System
|
Group: Applications/System
|
||||||
License: LGPL
|
License: LGPL
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||||
Requires: libcap
|
Requires: libcap openssl rsync
|
||||||
BuildRequires: libcap libcap-devel docbook-utils
|
BuildRequires: libcap libcap-devel docbook2X
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|
||||||
@ -91,11 +91,13 @@ rm -rf %{buildroot}
|
|||||||
%{_mandir}/*
|
%{_mandir}/*
|
||||||
%{_datadir}/doc/*
|
%{_datadir}/doc/*
|
||||||
%{_datadir}/lxc/*
|
%{_datadir}/lxc/*
|
||||||
|
%{_sysconfdir}/lxc/*
|
||||||
|
|
||||||
%files libs
|
%files libs
|
||||||
%defattr(-,root,root)
|
%defattr(-,root,root)
|
||||||
%{_libdir}/*.so.*
|
%{_libdir}/*.so.*
|
||||||
%{_libdir}/%{name}
|
%{_libdir}/%{name}
|
||||||
|
%{_localstatedir}/*
|
||||||
%attr(4555,root,root) %{_libexecdir}/%{name}/lxc-init
|
%attr(4555,root,root) %{_libexecdir}/%{name}/lxc-init
|
||||||
|
|
||||||
%files devel
|
%files devel
|
||||||
|
32
runapitests.sh
Normal file
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 \
|
list.h \
|
||||||
log.h \
|
log.h \
|
||||||
state.h \
|
state.h \
|
||||||
attach.h
|
attach.h \
|
||||||
|
lxccontainer.h \
|
||||||
|
lxclock.h
|
||||||
|
|
||||||
sodir=$(libdir)
|
sodir=$(libdir)
|
||||||
# use PROGRAMS to avoid complains from automake
|
# use PROGRAMS to avoid complains from automake
|
||||||
@ -50,33 +52,41 @@ liblxc_so_SOURCES = \
|
|||||||
genl.c genl.h \
|
genl.c genl.h \
|
||||||
\
|
\
|
||||||
caps.c caps.h \
|
caps.c caps.h \
|
||||||
|
lxcseccomp.h \
|
||||||
mainloop.c mainloop.h \
|
mainloop.c mainloop.h \
|
||||||
af_unix.c af_unix.h \
|
af_unix.c af_unix.h \
|
||||||
\
|
\
|
||||||
utmp.c utmp.h \
|
utmp.c utmp.h \
|
||||||
apparmor.c apparmor.h
|
apparmor.c apparmor.h \
|
||||||
|
lxclock.h lxclock.c \
|
||||||
|
lxccontainer.c lxccontainer.h
|
||||||
|
|
||||||
AM_CFLAGS=-I$(top_srcdir)/src \
|
AM_CFLAGS=-I$(top_srcdir)/src \
|
||||||
-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
|
-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
|
||||||
-DLXCPATH=\"$(LXCPATH)\" \
|
-DLXCPATH=\"$(LXCPATH)\" \
|
||||||
-DLXCINITDIR=\"$(LXCINITDIR)\"
|
-DLXCINITDIR=\"$(LXCINITDIR)\" \
|
||||||
|
-DLXCTEMPLATEDIR=\"$(LXCTEMPLATEDIR)\"
|
||||||
|
|
||||||
if ENABLE_APPARMOR
|
if ENABLE_APPARMOR
|
||||||
AM_CFLAGS += -DHAVE_APPARMOR
|
AM_CFLAGS += -DHAVE_APPARMOR
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if ENABLE_SECCOMP
|
||||||
|
AM_CFLAGS += -DHAVE_SECCOMP
|
||||||
|
liblxc_so_SOURCES += seccomp.c
|
||||||
|
endif
|
||||||
|
|
||||||
liblxc_so_CFLAGS = -fPIC -DPIC $(AM_CFLAGS)
|
liblxc_so_CFLAGS = -fPIC -DPIC $(AM_CFLAGS)
|
||||||
|
|
||||||
liblxc_so_LDFLAGS = \
|
liblxc_so_LDFLAGS = \
|
||||||
-shared \
|
-shared \
|
||||||
-Wl,-soname,liblxc.so.$(firstword $(subst ., ,$(VERSION)))
|
-Wl,-soname,liblxc.so.$(firstword $(subst ., ,$(VERSION)))
|
||||||
|
|
||||||
liblxc_so_LDADD = -lutil $(CAP_LIBS) $(APPARMOR_LIBS)
|
liblxc_so_LDADD = -lutil $(CAP_LIBS) $(APPARMOR_LIBS) $(SECCOMP_LIBS) -lrt
|
||||||
|
|
||||||
bin_SCRIPTS = \
|
bin_SCRIPTS = \
|
||||||
lxc-ps \
|
lxc-ps \
|
||||||
lxc-netstat \
|
lxc-netstat \
|
||||||
lxc-ls \
|
|
||||||
lxc-checkconfig \
|
lxc-checkconfig \
|
||||||
lxc-setcap \
|
lxc-setcap \
|
||||||
lxc-setuid \
|
lxc-setuid \
|
||||||
@ -86,6 +96,14 @@ bin_SCRIPTS = \
|
|||||||
lxc-shutdown \
|
lxc-shutdown \
|
||||||
lxc-destroy
|
lxc-destroy
|
||||||
|
|
||||||
|
if ENABLE_PYTHON
|
||||||
|
bin_SCRIPTS += lxc-device
|
||||||
|
bin_SCRIPTS += lxc-ls
|
||||||
|
bin_SCRIPTS += lxc-start-ephemeral
|
||||||
|
else
|
||||||
|
bin_SCRIPTS += legacy/lxc-ls
|
||||||
|
endif
|
||||||
|
|
||||||
bin_PROGRAMS = \
|
bin_PROGRAMS = \
|
||||||
lxc-attach \
|
lxc-attach \
|
||||||
lxc-unshare \
|
lxc-unshare \
|
||||||
@ -110,7 +128,7 @@ AM_LDFLAGS = -Wl,-E
|
|||||||
if ENABLE_RPATH
|
if ENABLE_RPATH
|
||||||
AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
|
AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
|
||||||
endif
|
endif
|
||||||
LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@
|
LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SECCOMP_LIBS@ -lrt
|
||||||
|
|
||||||
lxc_attach_SOURCES = lxc_attach.c
|
lxc_attach_SOURCES = lxc_attach.c
|
||||||
lxc_cgroup_SOURCES = lxc_cgroup.c
|
lxc_cgroup_SOURCES = lxc_cgroup.c
|
||||||
|
@ -52,7 +52,7 @@ int lxc_af_unix_open(const char *path, int type, int flags)
|
|||||||
|
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
/* copy entire buffer in case of abstract socket */
|
/* copy entire buffer in case of abstract socket */
|
||||||
memcpy(addr.sun_path, path,
|
memcpy(addr.sun_path, path,
|
||||||
path[0]?strlen(path):sizeof(addr.sun_path));
|
path[0]?strlen(path):sizeof(addr.sun_path));
|
||||||
|
|
||||||
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
|
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
|
||||||
@ -73,7 +73,7 @@ int lxc_af_unix_close(int fd)
|
|||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
|
|
||||||
if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) &&
|
if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) &&
|
||||||
addr.sun_path[0])
|
addr.sun_path[0])
|
||||||
unlink(addr.sun_path);
|
unlink(addr.sun_path);
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ int lxc_af_unix_connect(const char *path)
|
|||||||
|
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
/* copy entire buffer in case of abstract socket */
|
/* copy entire buffer in case of abstract socket */
|
||||||
memcpy(addr.sun_path, path,
|
memcpy(addr.sun_path, path,
|
||||||
path[0]?strlen(path):sizeof(addr.sun_path));
|
path[0]?strlen(path):sizeof(addr.sun_path));
|
||||||
|
|
||||||
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) {
|
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) {
|
||||||
@ -161,7 +161,7 @@ int lxc_af_unix_recv_fd(int fd, int *recvfd, void *data, size_t size)
|
|||||||
|
|
||||||
cmsg = CMSG_FIRSTHDR(&msg);
|
cmsg = CMSG_FIRSTHDR(&msg);
|
||||||
|
|
||||||
/* if the message is wrong the variable will not be
|
/* if the message is wrong the variable will not be
|
||||||
* filled and the peer will notified about a problem */
|
* filled and the peer will notified about a problem */
|
||||||
*recvfd = -1;
|
*recvfd = -1;
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ struct lxc_arguments {
|
|||||||
int daemonize;
|
int daemonize;
|
||||||
const char *rcfile;
|
const char *rcfile;
|
||||||
const char *console;
|
const char *console;
|
||||||
|
const char *pidfile;
|
||||||
|
|
||||||
/* for lxc-checkpoint/restart */
|
/* for lxc-checkpoint/restart */
|
||||||
const char *statefile;
|
const char *statefile;
|
||||||
@ -57,6 +58,7 @@ struct lxc_arguments {
|
|||||||
|
|
||||||
/* for lxc-wait */
|
/* for lxc-wait */
|
||||||
char *states;
|
char *states;
|
||||||
|
long timeout;
|
||||||
|
|
||||||
/* close fds from parent? */
|
/* close fds from parent? */
|
||||||
int close_all_fds;
|
int close_all_fds;
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
#include <linux/unistd.h>
|
#include <linux/unistd.h>
|
||||||
|
|
||||||
#if !HAVE_DECL_PR_CAPBSET_DROP
|
#if !HAVE_DECL_PR_CAPBSET_DROP
|
||||||
@ -121,13 +122,22 @@ out_error:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lxc_attach_to_ns(pid_t pid)
|
int lxc_attach_to_ns(pid_t pid, int which)
|
||||||
{
|
{
|
||||||
char path[MAXPATHLEN];
|
char path[MAXPATHLEN];
|
||||||
char *ns[] = { "pid", "mnt", "net", "ipc", "uts" };
|
/* according to <http://article.gmane.org/gmane.linux.kernel.containers.lxc.devel/1429>,
|
||||||
const int size = sizeof(ns) / sizeof(char *);
|
* the file for user namepsaces in /proc/$pid/ns will be called
|
||||||
|
* 'user' once the kernel supports it
|
||||||
|
*/
|
||||||
|
static char *ns[] = { "mnt", "pid", "uts", "ipc", "user", "net" };
|
||||||
|
static int flags[] = {
|
||||||
|
CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
|
||||||
|
CLONE_NEWUSER, CLONE_NEWNET
|
||||||
|
};
|
||||||
|
static const int size = sizeof(ns) / sizeof(char *);
|
||||||
int fd[size];
|
int fd[size];
|
||||||
int i;
|
int i, j, saved_errno;
|
||||||
|
|
||||||
|
|
||||||
snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
|
snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
|
||||||
if (access(path, X_OK)) {
|
if (access(path, X_OK)) {
|
||||||
@ -136,16 +146,39 @@ int lxc_attach_to_ns(pid_t pid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
|
/* ignore if we are not supposed to attach to that
|
||||||
|
* namespace
|
||||||
|
*/
|
||||||
|
if (which != -1 && !(which & flags[i])) {
|
||||||
|
fd[i] = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]);
|
snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]);
|
||||||
fd[i] = open(path, O_RDONLY);
|
fd[i] = open(path, O_RDONLY);
|
||||||
if (fd[i] < 0) {
|
if (fd[i] < 0) {
|
||||||
|
saved_errno = errno;
|
||||||
|
|
||||||
|
/* close all already opened file descriptors before
|
||||||
|
* we return an error, so we don't leak them
|
||||||
|
*/
|
||||||
|
for (j = 0; j < i; j++)
|
||||||
|
close(fd[j]);
|
||||||
|
|
||||||
|
errno = saved_errno;
|
||||||
SYSERROR("failed to open '%s'", path);
|
SYSERROR("failed to open '%s'", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
if (setns(fd[i], 0)) {
|
if (fd[i] >= 0 && setns(fd[i], 0) != 0) {
|
||||||
|
saved_errno = errno;
|
||||||
|
|
||||||
|
for (j = i; j < size; j++)
|
||||||
|
close(fd[j]);
|
||||||
|
|
||||||
|
errno = saved_errno;
|
||||||
SYSERROR("failed to set namespace '%s'", ns[i]);
|
SYSERROR("failed to set namespace '%s'", ns[i]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -156,6 +189,49 @@ int lxc_attach_to_ns(pid_t pid)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lxc_attach_remount_sys_proc()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = unshare(CLONE_NEWNS);
|
||||||
|
if (ret < 0) {
|
||||||
|
SYSERROR("failed to unshare mount namespace");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assume /proc is always mounted, so remount it */
|
||||||
|
ret = umount2("/proc", MNT_DETACH);
|
||||||
|
if (ret < 0) {
|
||||||
|
SYSERROR("failed to unmount /proc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mount("none", "/proc", "proc", 0, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
SYSERROR("failed to remount /proc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to umount /sys - if it's not a mount point,
|
||||||
|
* we'll get EINVAL, then we ignore it because it
|
||||||
|
* may not have been mounted in the first place
|
||||||
|
*/
|
||||||
|
ret = umount2("/sys", MNT_DETACH);
|
||||||
|
if (ret < 0 && errno != EINVAL) {
|
||||||
|
SYSERROR("failed to unmount /sys");
|
||||||
|
return -1;
|
||||||
|
} else if (ret == 0) {
|
||||||
|
/* remount it */
|
||||||
|
ret = mount("none", "/sys", "sysfs", 0, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
SYSERROR("failed to remount /sys");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
|
int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
|
||||||
{
|
{
|
||||||
int last_cap = lxc_caps_last_cap();
|
int last_cap = lxc_caps_last_cap();
|
||||||
|
@ -33,7 +33,8 @@ struct lxc_proc_context_info {
|
|||||||
|
|
||||||
extern struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid);
|
extern struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid);
|
||||||
|
|
||||||
extern int lxc_attach_to_ns(pid_t other_pid);
|
extern int lxc_attach_to_ns(pid_t other_pid, int which);
|
||||||
|
extern int lxc_attach_remount_sys_proc();
|
||||||
extern int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx);
|
extern int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lxc_one_cgroup_attach(const char *name,
|
static int lxc_one_cgroup_finish_attach(int fd, pid_t pid)
|
||||||
struct mntent *mntent, pid_t pid)
|
|
||||||
{
|
{
|
||||||
FILE *f;
|
char buf[32];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
snprintf(buf, 32, "%ld", (long)pid);
|
||||||
|
|
||||||
|
ret = write(fd, buf, strlen(buf));
|
||||||
|
if (ret <= 0) {
|
||||||
|
SYSERROR("failed to write pid '%ld' to fd '%d'", (long)pid, fd);
|
||||||
|
ret = -1;
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lxc_one_cgroup_dispose_attach(int fd)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lxc_one_cgroup_prepare_attach(const char *name,
|
||||||
|
struct mntent *mntent)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
char tasks[MAXPATHLEN], initcgroup[MAXPATHLEN];
|
char tasks[MAXPATHLEN], initcgroup[MAXPATHLEN];
|
||||||
char *cgmnt = mntent->mnt_dir;
|
char *cgmnt = mntent->mnt_dir;
|
||||||
int flags, ret = 0;
|
int flags;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
flags = get_cgroup_flags(mntent);
|
flags = get_cgroup_flags(mntent);
|
||||||
@ -274,31 +299,83 @@ static int lxc_one_cgroup_attach(const char *name,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
f = fopen(tasks, "w");
|
fd = open(tasks, O_WRONLY);
|
||||||
if (!f) {
|
if (fd < 0) {
|
||||||
SYSERROR("failed to open '%s'", tasks);
|
SYSERROR("failed to open '%s'", tasks);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fprintf(f, "%d", pid) <= 0) {
|
return fd;
|
||||||
SYSERROR("failed to write pid '%d' to '%s'", pid, tasks);
|
}
|
||||||
ret = -1;
|
|
||||||
|
static int lxc_one_cgroup_attach(const char *name, struct mntent *mntent, pid_t pid)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = lxc_one_cgroup_prepare_attach(name, mntent);
|
||||||
|
if (fd < 0) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
return lxc_one_cgroup_finish_attach(fd, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lxc_cgroup_dispose_attach(void *data)
|
||||||
|
{
|
||||||
|
int *fds = data;
|
||||||
|
int ret, err;
|
||||||
|
|
||||||
|
if (!fds) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
for (; *fds >= 0; fds++) {
|
||||||
|
err = lxc_one_cgroup_dispose_attach(*fds);
|
||||||
|
if (err) {
|
||||||
|
ret = err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int lxc_cgroup_finish_attach(void *data, pid_t pid)
|
||||||
* for each mounted cgroup, attach a pid to the cgroup for the container
|
{
|
||||||
*/
|
int *fds = data;
|
||||||
int lxc_cgroup_attach(const char *name, pid_t pid)
|
int err;
|
||||||
|
|
||||||
|
if (!fds) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; *fds >= 0; fds++) {
|
||||||
|
err = lxc_one_cgroup_finish_attach(*fds, pid);
|
||||||
|
if (err) {
|
||||||
|
/* get rid of the rest of them */
|
||||||
|
lxc_cgroup_dispose_attach(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*fds = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lxc_cgroup_prepare_attach(const char *name, void **data)
|
||||||
{
|
{
|
||||||
struct mntent *mntent;
|
struct mntent *mntent;
|
||||||
FILE *file = NULL;
|
FILE *file = NULL;
|
||||||
int err = -1;
|
int err = -1;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
int *fds;
|
||||||
|
int i;
|
||||||
|
static const int MAXFDS = 256;
|
||||||
|
|
||||||
file = setmntent(MTAB, "r");
|
file = setmntent(MTAB, "r");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
@ -306,7 +383,29 @@ int lxc_cgroup_attach(const char *name, pid_t pid)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* create a large enough buffer for all practical
|
||||||
|
* use cases
|
||||||
|
*/
|
||||||
|
fds = malloc(sizeof(int) * MAXFDS);
|
||||||
|
if (!fds) {
|
||||||
|
err = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (i = 0; i < MAXFDS; i++) {
|
||||||
|
fds[i] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
i = 0;
|
||||||
while ((mntent = getmntent(file))) {
|
while ((mntent = getmntent(file))) {
|
||||||
|
if (i >= MAXFDS - 1) {
|
||||||
|
ERROR("too many cgroups to attach to, aborting");
|
||||||
|
lxc_cgroup_dispose_attach(fds);
|
||||||
|
errno = ENOMEM;
|
||||||
|
err = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG("checking '%s' (%s)", mntent->mnt_dir, mntent->mnt_type);
|
DEBUG("checking '%s' (%s)", mntent->mnt_dir, mntent->mnt_type);
|
||||||
|
|
||||||
if (strcmp(mntent->mnt_type, "cgroup"))
|
if (strcmp(mntent->mnt_type, "cgroup"))
|
||||||
@ -317,19 +416,41 @@ int lxc_cgroup_attach(const char *name, pid_t pid)
|
|||||||
INFO("[%d] found cgroup mounted at '%s',opts='%s'",
|
INFO("[%d] found cgroup mounted at '%s',opts='%s'",
|
||||||
++found, mntent->mnt_dir, mntent->mnt_opts);
|
++found, mntent->mnt_dir, mntent->mnt_opts);
|
||||||
|
|
||||||
err = lxc_one_cgroup_attach(name, mntent, pid);
|
fds[i] = lxc_one_cgroup_prepare_attach(name, mntent);
|
||||||
if (err)
|
if (fds[i] < 0) {
|
||||||
|
err = fds[i];
|
||||||
|
lxc_cgroup_dispose_attach(fds);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
ERROR("No cgroup mounted on the system");
|
ERROR("No cgroup mounted on the system");
|
||||||
|
|
||||||
|
*data = fds;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
endmntent(file);
|
endmntent(file);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* for each mounted cgroup, attach a pid to the cgroup for the container
|
||||||
|
*/
|
||||||
|
int lxc_cgroup_attach(const char *name, pid_t pid)
|
||||||
|
{
|
||||||
|
void *data = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = lxc_cgroup_prepare_attach(name, &data);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lxc_cgroup_finish_attach(data, pid);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rename cgname, which is under cgparent, to a new name starting
|
* rename cgname, which is under cgparent, to a new name starting
|
||||||
* with 'cgparent/dead'. That way cgname can be reused. Return
|
* with 'cgparent/dead'. That way cgname can be reused. Return
|
||||||
@ -421,7 +542,7 @@ static int lxc_one_cgroup_create(const char *name,
|
|||||||
/* if cgparent does not exist, create it */
|
/* if cgparent does not exist, create it */
|
||||||
if (access(cgparent, F_OK)) {
|
if (access(cgparent, F_OK)) {
|
||||||
ret = mkdir(cgparent, 0755);
|
ret = mkdir(cgparent, 0755);
|
||||||
if (ret == -1 && errno == EEXIST) {
|
if (ret == -1 && errno != EEXIST) {
|
||||||
SYSERROR("failed to create '%s' directory", cgparent);
|
SYSERROR("failed to create '%s' directory", cgparent);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -668,6 +789,13 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If you pass in NULL value or 0 len, then you are asking for the size
|
||||||
|
* of the file. Note that we can't get the file size quickly through stat
|
||||||
|
* or lseek. Therefore if you pass in len > 0 but less than the file size,
|
||||||
|
* your only indication will be that the return value will be equal to the
|
||||||
|
* passed-in ret. We will not return the actual full file size.
|
||||||
|
*/
|
||||||
int lxc_cgroup_get(const char *name, const char *filename,
|
int lxc_cgroup_get(const char *name, const char *filename,
|
||||||
char *value, size_t len)
|
char *value, size_t len)
|
||||||
{
|
{
|
||||||
@ -692,7 +820,18 @@ int lxc_cgroup_get(const char *name, const char *filename,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = read(fd, value, len);
|
if (!len || !value) {
|
||||||
|
char buf[100];
|
||||||
|
int count = 0;
|
||||||
|
while ((ret = read(fd, buf, 100)) > 0)
|
||||||
|
count += ret;
|
||||||
|
if (ret >= 0)
|
||||||
|
ret = count;
|
||||||
|
} else {
|
||||||
|
memset(value, 0, len);
|
||||||
|
ret = read(fd, value, len);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
ERROR("read %s : %s", path, strerror(errno));
|
ERROR("read %s : %s", path, strerror(errno));
|
||||||
|
|
||||||
|
@ -31,5 +31,8 @@ extern int lxc_cgroup_destroy(const char *name);
|
|||||||
extern int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name);
|
extern int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name);
|
||||||
extern int lxc_cgroup_nrtasks(const char *name);
|
extern int lxc_cgroup_nrtasks(const char *name);
|
||||||
extern int lxc_cgroup_attach(const char *name, pid_t pid);
|
extern int lxc_cgroup_attach(const char *name, pid_t pid);
|
||||||
|
extern int lxc_cgroup_prepare_attach(const char *name, void **data);
|
||||||
|
extern int lxc_cgroup_finish_attach(void *data, pid_t pid);
|
||||||
|
extern int lxc_cgroup_dispose_attach(void *data);
|
||||||
extern int lxc_ns_is_mounted(void);
|
extern int lxc_ns_is_mounted(void);
|
||||||
#endif
|
#endif
|
||||||
|
@ -154,11 +154,32 @@ pid_t get_init_pid(const char *name)
|
|||||||
return command.answer.pid;
|
return command.answer.pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lxc_get_clone_flags(const char *name)
|
||||||
|
{
|
||||||
|
struct lxc_command command = {
|
||||||
|
.request = { .type = LXC_COMMAND_CLONE_FLAGS },
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret, stopped = 0;
|
||||||
|
|
||||||
|
ret = lxc_command(name, &command, &stopped);
|
||||||
|
if (ret < 0 && stopped)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
ERROR("failed to send command");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return command.answer.ret;
|
||||||
|
}
|
||||||
|
|
||||||
extern void lxc_console_remove_fd(int, struct lxc_tty_info *);
|
extern void lxc_console_remove_fd(int, struct lxc_tty_info *);
|
||||||
extern int lxc_console_callback(int, struct lxc_request *, struct lxc_handler *);
|
extern int lxc_console_callback(int, struct lxc_request *, struct lxc_handler *);
|
||||||
extern int lxc_stop_callback(int, struct lxc_request *, struct lxc_handler *);
|
extern int lxc_stop_callback(int, struct lxc_request *, struct lxc_handler *);
|
||||||
extern int lxc_state_callback(int, struct lxc_request *, struct lxc_handler *);
|
extern int lxc_state_callback(int, struct lxc_request *, struct lxc_handler *);
|
||||||
extern int lxc_pid_callback(int, struct lxc_request *, struct lxc_handler *);
|
extern int lxc_pid_callback(int, struct lxc_request *, struct lxc_handler *);
|
||||||
|
extern int lxc_clone_flags_callback(int, struct lxc_request *, struct lxc_handler *);
|
||||||
|
|
||||||
static int trigger_command(int fd, struct lxc_request *request,
|
static int trigger_command(int fd, struct lxc_request *request,
|
||||||
struct lxc_handler *handler)
|
struct lxc_handler *handler)
|
||||||
@ -166,10 +187,11 @@ static int trigger_command(int fd, struct lxc_request *request,
|
|||||||
typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
|
typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
|
||||||
|
|
||||||
callback cb[LXC_COMMAND_MAX] = {
|
callback cb[LXC_COMMAND_MAX] = {
|
||||||
[LXC_COMMAND_TTY] = lxc_console_callback,
|
[LXC_COMMAND_TTY] = lxc_console_callback,
|
||||||
[LXC_COMMAND_STOP] = lxc_stop_callback,
|
[LXC_COMMAND_STOP] = lxc_stop_callback,
|
||||||
[LXC_COMMAND_STATE] = lxc_state_callback,
|
[LXC_COMMAND_STATE] = lxc_state_callback,
|
||||||
[LXC_COMMAND_PID] = lxc_pid_callback,
|
[LXC_COMMAND_PID] = lxc_pid_callback,
|
||||||
|
[LXC_COMMAND_CLONE_FLAGS] = lxc_clone_flags_callback,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
|
if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
|
||||||
@ -305,5 +327,6 @@ extern int lxc_command_mainloop_add(const char *name,
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handler->conf->maincmd_fd = fd;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ enum {
|
|||||||
LXC_COMMAND_STOP,
|
LXC_COMMAND_STOP,
|
||||||
LXC_COMMAND_STATE,
|
LXC_COMMAND_STATE,
|
||||||
LXC_COMMAND_PID,
|
LXC_COMMAND_PID,
|
||||||
|
LXC_COMMAND_CLONE_FLAGS,
|
||||||
LXC_COMMAND_MAX,
|
LXC_COMMAND_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,6 +49,7 @@ struct lxc_command {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern pid_t get_init_pid(const char *name);
|
extern pid_t get_init_pid(const char *name);
|
||||||
|
extern int lxc_get_clone_flags(const char *name);
|
||||||
|
|
||||||
extern int lxc_command(const char *name, struct lxc_command *command,
|
extern int lxc_command(const char *name, struct lxc_command *command,
|
||||||
int *stopped);
|
int *stopped);
|
||||||
|
580
src/lxc/conf.c
580
src/lxc/conf.c
@ -66,6 +66,8 @@
|
|||||||
#include <apparmor.h>
|
#include <apparmor.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "lxcseccomp.h"
|
||||||
|
|
||||||
lxc_log_define(lxc_conf, lxc);
|
lxc_log_define(lxc_conf, lxc);
|
||||||
|
|
||||||
#define MAXHWLEN 18
|
#define MAXHWLEN 18
|
||||||
@ -109,6 +111,9 @@ lxc_log_define(lxc_conf, lxc);
|
|||||||
#define PR_CAPBSET_DROP 24
|
#define PR_CAPBSET_DROP 24
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
char *lxchook_names[NUM_LXC_HOOKS] = {
|
||||||
|
"pre-start", "pre-mount", "mount", "start", "post-stop" };
|
||||||
|
|
||||||
extern int pivot_root(const char * new_root, const char * put_old);
|
extern int pivot_root(const char * new_root, const char * put_old);
|
||||||
|
|
||||||
typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
|
typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
|
||||||
@ -138,6 +143,20 @@ static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
|
|||||||
[LXC_NET_EMPTY] = instanciate_empty,
|
[LXC_NET_EMPTY] = instanciate_empty,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int shutdown_veth(struct lxc_handler *, struct lxc_netdev *);
|
||||||
|
static int shutdown_macvlan(struct lxc_handler *, struct lxc_netdev *);
|
||||||
|
static int shutdown_vlan(struct lxc_handler *, struct lxc_netdev *);
|
||||||
|
static int shutdown_phys(struct lxc_handler *, struct lxc_netdev *);
|
||||||
|
static int shutdown_empty(struct lxc_handler *, struct lxc_netdev *);
|
||||||
|
|
||||||
|
static instanciate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
|
||||||
|
[LXC_NET_VETH] = shutdown_veth,
|
||||||
|
[LXC_NET_MACVLAN] = shutdown_macvlan,
|
||||||
|
[LXC_NET_VLAN] = shutdown_vlan,
|
||||||
|
[LXC_NET_PHYS] = shutdown_phys,
|
||||||
|
[LXC_NET_EMPTY] = shutdown_empty,
|
||||||
|
};
|
||||||
|
|
||||||
static struct mount_opt mount_opt[] = {
|
static struct mount_opt mount_opt[] = {
|
||||||
{ "defaults", 0, 0 },
|
{ "defaults", 0, 0 },
|
||||||
{ "ro", 0, MS_RDONLY },
|
{ "ro", 0, MS_RDONLY },
|
||||||
@ -214,12 +233,41 @@ static struct caps_opt caps_opt[] = {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int run_buffer(char *buffer)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
char *output;
|
||||||
|
|
||||||
|
f = popen(buffer, "r");
|
||||||
|
if (!f) {
|
||||||
|
SYSERROR("popen failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
output = malloc(LXC_LOG_BUFFER_SIZE);
|
||||||
|
if (!output) {
|
||||||
|
ERROR("failed to allocate memory for script output");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(fgets(output, LXC_LOG_BUFFER_SIZE, f))
|
||||||
|
DEBUG("script output: %s", output);
|
||||||
|
|
||||||
|
free(output);
|
||||||
|
|
||||||
|
if (pclose(f) == -1) {
|
||||||
|
SYSERROR("Script exited on error");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int run_script(const char *name, const char *section,
|
static int run_script(const char *name, const char *section,
|
||||||
const char *script, ...)
|
const char *script, ...)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
FILE *f;
|
char *buffer, *p;
|
||||||
char *buffer, *p, *output;
|
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
@ -266,29 +314,7 @@ static int run_script(const char *name, const char *section,
|
|||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
f = popen(buffer, "r");
|
return run_buffer(buffer);
|
||||||
if (!f) {
|
|
||||||
SYSERROR("popen failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
output = malloc(LXC_LOG_BUFFER_SIZE);
|
|
||||||
if (!output) {
|
|
||||||
ERROR("failed to allocate memory for script output");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(fgets(output, LXC_LOG_BUFFER_SIZE, f))
|
|
||||||
DEBUG("script output: %s", output);
|
|
||||||
|
|
||||||
free(output);
|
|
||||||
|
|
||||||
if (pclose(f) == -1) {
|
|
||||||
SYSERROR("Script exited on error");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_fstype_cb(char* buffer, void *data)
|
static int find_fstype_cb(char* buffer, void *data)
|
||||||
@ -636,6 +662,15 @@ static int setup_tty(const struct lxc_rootfs *rootfs,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* If we populated /dev, then we need to create /dev/ttyN */
|
||||||
|
if (access(path, F_OK)) {
|
||||||
|
ret = creat(path, 0660);
|
||||||
|
if (ret==-1) {
|
||||||
|
SYSERROR("error creating %s\n", path);
|
||||||
|
/* this isn't fatal, continue */
|
||||||
|
} else
|
||||||
|
close(ret);
|
||||||
|
}
|
||||||
if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
|
if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
|
||||||
WARN("failed to mount '%s'->'%s'",
|
WARN("failed to mount '%s'->'%s'",
|
||||||
pty_info->name, path);
|
pty_info->name, path);
|
||||||
@ -708,7 +743,7 @@ static int umount_oldrootfs(const char *oldrootfs)
|
|||||||
{
|
{
|
||||||
char path[MAXPATHLEN];
|
char path[MAXPATHLEN];
|
||||||
void *cbparm[2];
|
void *cbparm[2];
|
||||||
struct lxc_list mountlist, *iterator;
|
struct lxc_list mountlist, *iterator, *next;
|
||||||
int ok, still_mounted, last_still_mounted;
|
int ok, still_mounted, last_still_mounted;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -748,7 +783,7 @@ static int umount_oldrootfs(const char *oldrootfs)
|
|||||||
last_still_mounted = still_mounted;
|
last_still_mounted = still_mounted;
|
||||||
still_mounted = 0;
|
still_mounted = 0;
|
||||||
|
|
||||||
lxc_list_for_each(iterator, &mountlist) {
|
lxc_list_for_each_safe(iterator, &mountlist, next) {
|
||||||
|
|
||||||
/* umount normally */
|
/* umount normally */
|
||||||
if (!umount(iterator->elem)) {
|
if (!umount(iterator->elem)) {
|
||||||
@ -843,6 +878,114 @@ static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do we want to add options for max size of /dev and a file to
|
||||||
|
* specify which devices to create?
|
||||||
|
*/
|
||||||
|
static int mount_autodev(char *root)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char path[MAXPATHLEN];
|
||||||
|
|
||||||
|
INFO("Mounting /dev under %s\n", root);
|
||||||
|
ret = snprintf(path, MAXPATHLEN, "%s/dev", root);
|
||||||
|
if (ret < 0 || ret > MAXPATHLEN)
|
||||||
|
return -1;
|
||||||
|
ret = mount("none", path, "tmpfs", 0, "size=100000");
|
||||||
|
if (ret) {
|
||||||
|
SYSERROR("Failed to mount /dev at %s\n", root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = snprintf(path, MAXPATHLEN, "%s/dev/pts", root);
|
||||||
|
if (ret < 0 || ret >= MAXPATHLEN)
|
||||||
|
return -1;
|
||||||
|
ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
|
||||||
|
if (ret) {
|
||||||
|
SYSERROR("Failed to create /dev/pts in container");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
INFO("Mounted /dev under %s\n", root);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to run MAKEDEV console in the container. If something fails,
|
||||||
|
* continue anyway as it should not be detrimental to the container.
|
||||||
|
* This makes sure that things like /dev/vcs* exist.
|
||||||
|
* (Pass devpath in to reduce stack usage)
|
||||||
|
*/
|
||||||
|
static void run_makedev(char *devpath)
|
||||||
|
{
|
||||||
|
int curd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
curd = open(".", O_RDONLY);
|
||||||
|
if (curd < 0)
|
||||||
|
return;
|
||||||
|
ret = chdir(devpath);
|
||||||
|
if (ret) {
|
||||||
|
close(curd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (run_buffer("/sbin/MAKEDEV console"))
|
||||||
|
INFO("Error running MAKEDEV console in %s", devpath);
|
||||||
|
ret = fchdir(curd);
|
||||||
|
if (ret)
|
||||||
|
INFO("Error returning to original directory: expect breakage");
|
||||||
|
close(curd);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lxc_devs {
|
||||||
|
char *name;
|
||||||
|
mode_t mode;
|
||||||
|
int maj;
|
||||||
|
int min;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lxc_devs lxc_devs[] = {
|
||||||
|
{ "null", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 3 },
|
||||||
|
{ "zero", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 5 },
|
||||||
|
{ "full", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 7 },
|
||||||
|
{ "urandom", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 9 },
|
||||||
|
{ "random", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 8 },
|
||||||
|
{ "tty", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 5, 0 },
|
||||||
|
{ "console", S_IFCHR | S_IRUSR | S_IWUSR, 5, 1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int setup_autodev(char *root)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct lxc_devs *d;
|
||||||
|
char path[MAXPATHLEN];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
INFO("Creating initial consoles under %s/dev\n", root);
|
||||||
|
|
||||||
|
ret = snprintf(path, MAXPATHLEN, "%s/dev", root);
|
||||||
|
if (ret < 0 || ret >= MAXPATHLEN) {
|
||||||
|
ERROR("Error calculating container /dev location");
|
||||||
|
return -1;
|
||||||
|
} else
|
||||||
|
run_makedev(path);
|
||||||
|
|
||||||
|
INFO("Populating /dev under %s\n", root);
|
||||||
|
for (i = 0; i < sizeof(lxc_devs) / sizeof(lxc_devs[0]); i++) {
|
||||||
|
d = &lxc_devs[i];
|
||||||
|
ret = snprintf(path, MAXPATHLEN, "%s/dev/%s", root, d->name);
|
||||||
|
if (ret < 0 || ret >= MAXPATHLEN)
|
||||||
|
return -1;
|
||||||
|
ret = mknod(path, d->mode, makedev(d->maj, d->min));
|
||||||
|
if (ret && errno != EEXIST) {
|
||||||
|
SYSERROR("Error creating %s\n", d->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INFO("Populated /dev under %s\n", root);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int setup_rootfs(const struct lxc_rootfs *rootfs)
|
static int setup_rootfs(const struct lxc_rootfs *rootfs)
|
||||||
{
|
{
|
||||||
if (!rootfs->path)
|
if (!rootfs->path)
|
||||||
@ -1061,6 +1204,8 @@ static int setup_kmsg(const struct lxc_rootfs *rootfs,
|
|||||||
char kpath[MAXPATHLEN];
|
char kpath[MAXPATHLEN];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!rootfs->path)
|
||||||
|
return 0;
|
||||||
ret = snprintf(kpath, sizeof(kpath), "%s/dev/kmsg", rootfs->mount);
|
ret = snprintf(kpath, sizeof(kpath), "%s/dev/kmsg", rootfs->mount);
|
||||||
if (ret < 0 || ret >= sizeof(kpath))
|
if (ret < 0 || ret >= sizeof(kpath))
|
||||||
return -1;
|
return -1;
|
||||||
@ -1228,8 +1373,8 @@ static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* if rootfs->path is a blockdev path, allow container fstab to
|
/* if rootfs->path is a blockdev path, allow container fstab to
|
||||||
* use /var/lib/lxc/CN/rootfs as the target prefix */
|
* use $LXCPATH/CN/rootfs as the target prefix */
|
||||||
r = snprintf(path, MAXPATHLEN, "/var/lib/lxc/%s/rootfs", lxc_name);
|
r = snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", lxc_name);
|
||||||
if (r < 0 || r >= MAXPATHLEN)
|
if (r < 0 || r >= MAXPATHLEN)
|
||||||
goto skipvarlib;
|
goto skipvarlib;
|
||||||
|
|
||||||
@ -1647,7 +1792,7 @@ static int setup_netdev(struct lxc_netdev *netdev)
|
|||||||
ifname, strerror(-err));
|
ifname, strerror(-err));
|
||||||
if (netdev->ipv6_gateway_auto) {
|
if (netdev->ipv6_gateway_auto) {
|
||||||
char buf[INET6_ADDRSTRLEN];
|
char buf[INET6_ADDRSTRLEN];
|
||||||
inet_ntop(AF_INET, netdev->ipv6_gateway, buf, sizeof(buf));
|
inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
|
||||||
ERROR("tried to set autodetected ipv6 gateway '%s'", buf);
|
ERROR("tried to set autodetected ipv6 gateway '%s'", buf);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
@ -1680,6 +1825,21 @@ static int setup_network(struct lxc_list *network)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
INFO("running to reset %d nic names", conf->num_savednics);
|
||||||
|
for (i=0; i<conf->num_savednics; i++) {
|
||||||
|
struct saved_nic *s = &conf->saved_nics[i];
|
||||||
|
INFO("resetting nic %d to %s\n", s->ifindex, s->orig_name);
|
||||||
|
lxc_netdev_rename_by_index(s->ifindex, s->orig_name);
|
||||||
|
free(s->orig_name);
|
||||||
|
}
|
||||||
|
conf->num_savednics = 0;
|
||||||
|
free(conf->saved_nics);
|
||||||
|
}
|
||||||
|
|
||||||
static int setup_private_host_hw_addr(char *veth1)
|
static int setup_private_host_hw_addr(char *veth1)
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
@ -1715,6 +1875,8 @@ static int setup_private_host_hw_addr(char *veth1)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *default_rootfs_mount = LXCROOTFSMOUNT;
|
||||||
|
|
||||||
struct lxc_conf *lxc_conf_init(void)
|
struct lxc_conf *lxc_conf_init(void)
|
||||||
{
|
{
|
||||||
struct lxc_conf *new;
|
struct lxc_conf *new;
|
||||||
@ -1733,7 +1895,8 @@ struct lxc_conf *lxc_conf_init(void)
|
|||||||
new->console.master = -1;
|
new->console.master = -1;
|
||||||
new->console.slave = -1;
|
new->console.slave = -1;
|
||||||
new->console.name[0] = '\0';
|
new->console.name[0] = '\0';
|
||||||
new->rootfs.mount = LXCROOTFSMOUNT;
|
new->rootfs.mount = default_rootfs_mount;
|
||||||
|
new->loglevel = LXC_LOG_PRIORITY_NOTSET;
|
||||||
lxc_list_init(&new->cgroup);
|
lxc_list_init(&new->cgroup);
|
||||||
lxc_list_init(&new->network);
|
lxc_list_init(&new->network);
|
||||||
lxc_list_init(&new->mount_list);
|
lxc_list_init(&new->mount_list);
|
||||||
@ -1765,6 +1928,8 @@ static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
veth1 = mktemp(veth1buf);
|
veth1 = mktemp(veth1buf);
|
||||||
|
/* store away for deconf */
|
||||||
|
memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
|
snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
|
||||||
@ -1841,6 +2006,25 @@ out_delete:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
|
{
|
||||||
|
char *veth1;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (netdev->priv.veth_attr.pair)
|
||||||
|
veth1 = netdev->priv.veth_attr.pair;
|
||||||
|
else
|
||||||
|
veth1 = netdev->priv.veth_attr.veth1;
|
||||||
|
|
||||||
|
if (netdev->downscript) {
|
||||||
|
err = run_script(handler->name, "net", netdev->downscript,
|
||||||
|
"down", "veth", veth1, (char*) NULL);
|
||||||
|
if (err)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
{
|
{
|
||||||
char peerbuf[IFNAMSIZ], *peer;
|
char peerbuf[IFNAMSIZ], *peer;
|
||||||
@ -1889,6 +2073,20 @@ static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (netdev->downscript) {
|
||||||
|
err = run_script(handler->name, "net", netdev->downscript,
|
||||||
|
"down", "macvlan", netdev->link,
|
||||||
|
(char*) NULL);
|
||||||
|
if (err)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: merge with instanciate_macvlan */
|
/* XXX: merge with instanciate_macvlan */
|
||||||
static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
{
|
{
|
||||||
@ -1926,6 +2124,11 @@ static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
{
|
{
|
||||||
if (!netdev->link) {
|
if (!netdev->link) {
|
||||||
@ -1950,6 +2153,19 @@ static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netd
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (netdev->downscript) {
|
||||||
|
err = run_script(handler->name, "net", netdev->downscript,
|
||||||
|
"down", "phys", netdev->link, (char*) NULL);
|
||||||
|
if (err)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
{
|
{
|
||||||
netdev->ifindex = 0;
|
netdev->ifindex = 0;
|
||||||
@ -1963,6 +2179,19 @@ static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *net
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (netdev->downscript) {
|
||||||
|
err = run_script(handler->name, "net", netdev->downscript,
|
||||||
|
"down", "empty", (char*) NULL);
|
||||||
|
if (err)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int lxc_create_network(struct lxc_handler *handler)
|
int lxc_create_network(struct lxc_handler *handler)
|
||||||
{
|
{
|
||||||
struct lxc_list *network = &handler->conf->network;
|
struct lxc_list *network = &handler->conf->network;
|
||||||
@ -1989,28 +2218,32 @@ int lxc_create_network(struct lxc_handler *handler)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lxc_delete_network(struct lxc_list *network)
|
void lxc_delete_network(struct lxc_handler *handler)
|
||||||
{
|
{
|
||||||
|
struct lxc_list *network = &handler->conf->network;
|
||||||
struct lxc_list *iterator;
|
struct lxc_list *iterator;
|
||||||
struct lxc_netdev *netdev;
|
struct lxc_netdev *netdev;
|
||||||
|
|
||||||
lxc_list_for_each(iterator, network) {
|
lxc_list_for_each(iterator, network) {
|
||||||
netdev = iterator->elem;
|
netdev = iterator->elem;
|
||||||
if (netdev->ifindex == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (netdev->type == LXC_NET_PHYS) {
|
if (netdev->ifindex != 0 && netdev->type == LXC_NET_PHYS) {
|
||||||
if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link))
|
if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link))
|
||||||
WARN("failed to rename to the initial name the " \
|
WARN("failed to rename to the initial name the " \
|
||||||
"netdev '%s'", netdev->link);
|
"netdev '%s'", netdev->link);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (netdev_deconf[netdev->type](handler, netdev)) {
|
||||||
|
WARN("failed to destroy netdev");
|
||||||
|
}
|
||||||
|
|
||||||
/* Recent kernel remove the virtual interfaces when the network
|
/* Recent kernel remove the virtual interfaces when the network
|
||||||
* namespace is destroyed but in case we did not moved the
|
* namespace is destroyed but in case we did not moved the
|
||||||
* interface to the network namespace, we have to destroy it
|
* interface to the network namespace, we have to destroy it
|
||||||
*/
|
*/
|
||||||
if (lxc_netdev_delete_by_index(netdev->ifindex))
|
if (netdev->ifindex != 0 &&
|
||||||
|
lxc_netdev_delete_by_index(netdev->ifindex))
|
||||||
WARN("failed to remove interface '%s'", netdev->name);
|
WARN("failed to remove interface '%s'", netdev->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2166,11 +2399,23 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (run_lxc_hooks(name, "pre-mount", lxc_conf)) {
|
||||||
|
ERROR("failed to run pre-mount hooks for container '%s'.", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (setup_rootfs(&lxc_conf->rootfs)) {
|
if (setup_rootfs(&lxc_conf->rootfs)) {
|
||||||
ERROR("failed to setup rootfs for '%s'", name);
|
ERROR("failed to setup rootfs for '%s'", name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lxc_conf->autodev) {
|
||||||
|
if (mount_autodev(lxc_conf->rootfs.mount)) {
|
||||||
|
ERROR("failed to mount /dev in the container");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name)) {
|
if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name)) {
|
||||||
ERROR("failed to setup the mounts for '%s'", name);
|
ERROR("failed to setup the mounts for '%s'", name);
|
||||||
return -1;
|
return -1;
|
||||||
@ -2186,6 +2431,13 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lxc_conf->autodev) {
|
||||||
|
if (setup_autodev(lxc_conf->rootfs.mount)) {
|
||||||
|
ERROR("failed to populate /dev in the container");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (setup_cgroup(name, &lxc_conf->cgroup)) {
|
if (setup_cgroup(name, &lxc_conf->cgroup)) {
|
||||||
ERROR("failed to setup the cgroups for '%s'", name);
|
ERROR("failed to setup the cgroups for '%s'", name);
|
||||||
return -1;
|
return -1;
|
||||||
@ -2196,10 +2448,8 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setup_kmsg(&lxc_conf->rootfs, &lxc_conf->console)) {
|
if (setup_kmsg(&lxc_conf->rootfs, &lxc_conf->console)) // don't fail
|
||||||
ERROR("failed to setup kmsg for '%s'", name);
|
ERROR("failed to setup kmsg for '%s'", name);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) {
|
if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) {
|
||||||
ERROR("failed to setup the ttys for '%s'", name);
|
ERROR("failed to setup the ttys for '%s'", name);
|
||||||
@ -2253,6 +2503,8 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
|
|||||||
|
|
||||||
if (strcmp(hook, "pre-start") == 0)
|
if (strcmp(hook, "pre-start") == 0)
|
||||||
which = LXCHOOK_PRESTART;
|
which = LXCHOOK_PRESTART;
|
||||||
|
else if (strcmp(hook, "pre-mount") == 0)
|
||||||
|
which = LXCHOOK_PREMOUNT;
|
||||||
else if (strcmp(hook, "mount") == 0)
|
else if (strcmp(hook, "mount") == 0)
|
||||||
which = LXCHOOK_MOUNT;
|
which = LXCHOOK_MOUNT;
|
||||||
else if (strcmp(hook, "start") == 0)
|
else if (strcmp(hook, "start") == 0)
|
||||||
@ -2270,3 +2522,253 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lxc_remove_nic(struct lxc_list *it)
|
||||||
|
{
|
||||||
|
struct lxc_netdev *netdev = it->elem;
|
||||||
|
struct lxc_list *it2,*next;
|
||||||
|
|
||||||
|
lxc_list_del(it);
|
||||||
|
|
||||||
|
if (netdev->link)
|
||||||
|
free(netdev->link);
|
||||||
|
if (netdev->name)
|
||||||
|
free(netdev->name);
|
||||||
|
if (netdev->upscript)
|
||||||
|
free(netdev->upscript);
|
||||||
|
if (netdev->hwaddr)
|
||||||
|
free(netdev->hwaddr);
|
||||||
|
if (netdev->mtu)
|
||||||
|
free(netdev->mtu);
|
||||||
|
if (netdev->ipv4_gateway)
|
||||||
|
free(netdev->ipv4_gateway);
|
||||||
|
if (netdev->ipv6_gateway)
|
||||||
|
free(netdev->ipv6_gateway);
|
||||||
|
lxc_list_for_each_safe(it2, &netdev->ipv4, next) {
|
||||||
|
lxc_list_del(it2);
|
||||||
|
free(it2->elem);
|
||||||
|
free(it2);
|
||||||
|
}
|
||||||
|
lxc_list_for_each_safe(it2, &netdev->ipv6, next) {
|
||||||
|
lxc_list_del(it2);
|
||||||
|
free(it2->elem);
|
||||||
|
free(it2);
|
||||||
|
}
|
||||||
|
free(netdev);
|
||||||
|
free(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we get passed in something like '0', '0.ipv4' or '1.ipv6' */
|
||||||
|
int lxc_clear_nic(struct lxc_conf *c, const char *key)
|
||||||
|
{
|
||||||
|
char *p1;
|
||||||
|
int ret, idx, i;
|
||||||
|
struct lxc_list *it;
|
||||||
|
struct lxc_netdev *netdev;
|
||||||
|
|
||||||
|
p1 = index(key, '.');
|
||||||
|
if (!p1 || *(p1+1) == '\0')
|
||||||
|
p1 = NULL;
|
||||||
|
|
||||||
|
ret = sscanf(key, "%d", &idx);
|
||||||
|
if (ret != 1) return -1;
|
||||||
|
if (idx < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
lxc_list_for_each(it, &c->network) {
|
||||||
|
if (i == idx)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i < idx) // we don't have that many nics defined
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!it || !it->elem)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
netdev = it->elem;
|
||||||
|
|
||||||
|
if (!p1) {
|
||||||
|
lxc_remove_nic(it);
|
||||||
|
} else if (strcmp(p1, "ipv4") == 0) {
|
||||||
|
struct lxc_list *it2,*next;
|
||||||
|
lxc_list_for_each_safe(it2, &netdev->ipv4, next) {
|
||||||
|
lxc_list_del(it2);
|
||||||
|
free(it2->elem);
|
||||||
|
free(it2);
|
||||||
|
}
|
||||||
|
} else if (strcmp(p1, "ipv6") == 0) {
|
||||||
|
struct lxc_list *it2,*next;
|
||||||
|
lxc_list_for_each_safe(it2, &netdev->ipv6, next) {
|
||||||
|
lxc_list_del(it2);
|
||||||
|
free(it2->elem);
|
||||||
|
free(it2);
|
||||||
|
}
|
||||||
|
} else if (strcmp(p1, "link") == 0) {
|
||||||
|
if (netdev->link) {
|
||||||
|
free(netdev->link);
|
||||||
|
netdev->link = NULL;
|
||||||
|
}
|
||||||
|
} else if (strcmp(p1, "name") == 0) {
|
||||||
|
if (netdev->name) {
|
||||||
|
free(netdev->name);
|
||||||
|
netdev->name = NULL;
|
||||||
|
}
|
||||||
|
} else if (strcmp(p1, "script.up") == 0) {
|
||||||
|
if (netdev->upscript) {
|
||||||
|
free(netdev->upscript);
|
||||||
|
netdev->upscript = NULL;
|
||||||
|
}
|
||||||
|
} else if (strcmp(p1, "hwaddr") == 0) {
|
||||||
|
if (netdev->hwaddr) {
|
||||||
|
free(netdev->hwaddr);
|
||||||
|
netdev->hwaddr = NULL;
|
||||||
|
}
|
||||||
|
} else if (strcmp(p1, "mtu") == 0) {
|
||||||
|
if (netdev->mtu) {
|
||||||
|
free(netdev->mtu);
|
||||||
|
netdev->mtu = NULL;
|
||||||
|
}
|
||||||
|
} else if (strcmp(p1, "ipv4_gateway") == 0) {
|
||||||
|
if (netdev->ipv4_gateway) {
|
||||||
|
free(netdev->ipv4_gateway);
|
||||||
|
netdev->ipv4_gateway = NULL;
|
||||||
|
}
|
||||||
|
} else if (strcmp(p1, "ipv6_gateway") == 0) {
|
||||||
|
if (netdev->ipv6_gateway) {
|
||||||
|
free(netdev->ipv6_gateway);
|
||||||
|
netdev->ipv6_gateway = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lxc_clear_config_network(struct lxc_conf *c)
|
||||||
|
{
|
||||||
|
struct lxc_list *it,*next;
|
||||||
|
lxc_list_for_each_safe(it, &c->network, next) {
|
||||||
|
lxc_remove_nic(it);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lxc_clear_config_caps(struct lxc_conf *c)
|
||||||
|
{
|
||||||
|
struct lxc_list *it,*next;
|
||||||
|
|
||||||
|
lxc_list_for_each_safe(it, &c->caps, next) {
|
||||||
|
lxc_list_del(it);
|
||||||
|
free(it->elem);
|
||||||
|
free(it);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lxc_clear_cgroups(struct lxc_conf *c, const char *key)
|
||||||
|
{
|
||||||
|
struct lxc_list *it,*next;
|
||||||
|
bool all = false;
|
||||||
|
const char *k = key + 11;
|
||||||
|
|
||||||
|
if (strcmp(key, "lxc.cgroup") == 0)
|
||||||
|
all = true;
|
||||||
|
|
||||||
|
lxc_list_for_each_safe(it, &c->cgroup, next) {
|
||||||
|
struct lxc_cgroup *cg = it->elem;
|
||||||
|
if (!all && strcmp(cg->subsystem, k) != 0)
|
||||||
|
continue;
|
||||||
|
lxc_list_del(it);
|
||||||
|
free(cg->subsystem);
|
||||||
|
free(cg->value);
|
||||||
|
free(cg);
|
||||||
|
free(it);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lxc_clear_mount_entries(struct lxc_conf *c)
|
||||||
|
{
|
||||||
|
struct lxc_list *it,*next;
|
||||||
|
|
||||||
|
lxc_list_for_each_safe(it, &c->mount_list, next) {
|
||||||
|
lxc_list_del(it);
|
||||||
|
free(it->elem);
|
||||||
|
free(it);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lxc_clear_hooks(struct lxc_conf *c, const char *key)
|
||||||
|
{
|
||||||
|
struct lxc_list *it,*next;
|
||||||
|
bool all = false, done = false;
|
||||||
|
const char *k = key + 9;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (strcmp(key, "lxc.hook") == 0)
|
||||||
|
all = true;
|
||||||
|
|
||||||
|
for (i=0; i<NUM_LXC_HOOKS; i++) {
|
||||||
|
if (all || strcmp(k, lxchook_names[i]) == 0) {
|
||||||
|
lxc_list_for_each_safe(it, &c->hooks[i], next) {
|
||||||
|
lxc_list_del(it);
|
||||||
|
free(it->elem);
|
||||||
|
free(it);
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!done) {
|
||||||
|
ERROR("Invalid hook key: %s", key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lxc_clear_saved_nics(struct lxc_conf *conf)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!conf->num_savednics)
|
||||||
|
return;
|
||||||
|
for (i=0; i < conf->num_savednics; i++)
|
||||||
|
free(conf->saved_nics[i].orig_name);
|
||||||
|
conf->saved_nics = 0;
|
||||||
|
free(conf->saved_nics);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lxc_conf_free(struct lxc_conf *conf)
|
||||||
|
{
|
||||||
|
if (!conf)
|
||||||
|
return;
|
||||||
|
if (conf->console.path)
|
||||||
|
free(conf->console.path);
|
||||||
|
if (conf->rootfs.mount != default_rootfs_mount)
|
||||||
|
free(conf->rootfs.mount);
|
||||||
|
if (conf->rootfs.path)
|
||||||
|
free(conf->rootfs.path);
|
||||||
|
if (conf->utsname)
|
||||||
|
free(conf->utsname);
|
||||||
|
if (conf->ttydir)
|
||||||
|
free(conf->ttydir);
|
||||||
|
if (conf->fstab)
|
||||||
|
free(conf->fstab);
|
||||||
|
if (conf->logfile)
|
||||||
|
free(conf->logfile);
|
||||||
|
lxc_clear_config_network(conf);
|
||||||
|
#if HAVE_APPARMOR
|
||||||
|
if (conf->aa_profile)
|
||||||
|
free(conf->aa_profile);
|
||||||
|
#endif
|
||||||
|
lxc_seccomp_free(conf);
|
||||||
|
lxc_clear_config_caps(conf);
|
||||||
|
lxc_clear_cgroups(conf, "lxc.cgroup");
|
||||||
|
lxc_clear_hooks(conf, "lxc.hook");
|
||||||
|
lxc_clear_mount_entries(conf);
|
||||||
|
lxc_clear_saved_nics(conf);
|
||||||
|
free(conf);
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#define _conf_h
|
#define _conf_h
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <net/if.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@ -31,6 +32,10 @@
|
|||||||
|
|
||||||
#include <lxc/start.h> /* for lxc_handler */
|
#include <lxc/start.h> /* for lxc_handler */
|
||||||
|
|
||||||
|
#if HAVE_SCMP_FILTER_CTX
|
||||||
|
typedef void * scmp_filter_ctx;
|
||||||
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
LXC_NET_EMPTY,
|
LXC_NET_EMPTY,
|
||||||
LXC_NET_VETH,
|
LXC_NET_VETH,
|
||||||
@ -76,6 +81,7 @@ struct lxc_route6 {
|
|||||||
|
|
||||||
struct ifla_veth {
|
struct ifla_veth {
|
||||||
char *pair; /* pair name */
|
char *pair; /* pair name */
|
||||||
|
char veth1[IFNAMSIZ]; /* needed for deconf */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ifla_vlan {
|
struct ifla_vlan {
|
||||||
@ -103,6 +109,7 @@ union netdev_p {
|
|||||||
* @ipv4 : a list of ipv4 addresses to be set on the network device
|
* @ipv4 : a list of ipv4 addresses to be set on the network device
|
||||||
* @ipv6 : a list of ipv6 addresses to be set on the network device
|
* @ipv6 : a list of ipv6 addresses to be set on the network device
|
||||||
* @upscript : a script filename to be executed during interface configuration
|
* @upscript : a script filename to be executed during interface configuration
|
||||||
|
* @downscript : a script filename to be executed during interface destruction
|
||||||
*/
|
*/
|
||||||
struct lxc_netdev {
|
struct lxc_netdev {
|
||||||
int type;
|
int type;
|
||||||
@ -120,6 +127,7 @@ struct lxc_netdev {
|
|||||||
struct in6_addr *ipv6_gateway;
|
struct in6_addr *ipv6_gateway;
|
||||||
bool ipv6_gateway_auto;
|
bool ipv6_gateway_auto;
|
||||||
char *upscript;
|
char *upscript;
|
||||||
|
char *downscript;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -203,8 +211,15 @@ struct lxc_rootfs {
|
|||||||
#endif
|
#endif
|
||||||
*/
|
*/
|
||||||
enum lxchooks {
|
enum lxchooks {
|
||||||
LXCHOOK_PRESTART, LXCHOOK_MOUNT, LXCHOOK_START,
|
LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_START,
|
||||||
LXCHOOK_POSTSTOP, NUM_LXC_HOOKS};
|
LXCHOOK_POSTSTOP, NUM_LXC_HOOKS};
|
||||||
|
extern char *lxchook_names[NUM_LXC_HOOKS];
|
||||||
|
|
||||||
|
struct saved_nic {
|
||||||
|
int ifindex;
|
||||||
|
char *orig_name;
|
||||||
|
};
|
||||||
|
|
||||||
struct lxc_conf {
|
struct lxc_conf {
|
||||||
char *fstab;
|
char *fstab;
|
||||||
int tty;
|
int tty;
|
||||||
@ -215,6 +230,8 @@ struct lxc_conf {
|
|||||||
struct utsname *utsname;
|
struct utsname *utsname;
|
||||||
struct lxc_list cgroup;
|
struct lxc_list cgroup;
|
||||||
struct lxc_list network;
|
struct lxc_list network;
|
||||||
|
struct saved_nic *saved_nics;
|
||||||
|
int num_savednics;
|
||||||
struct lxc_list mount_list;
|
struct lxc_list mount_list;
|
||||||
struct lxc_list caps;
|
struct lxc_list caps;
|
||||||
struct lxc_tty_info tty_info;
|
struct lxc_tty_info tty_info;
|
||||||
@ -226,9 +243,18 @@ struct lxc_conf {
|
|||||||
#if HAVE_APPARMOR
|
#if HAVE_APPARMOR
|
||||||
char *aa_profile;
|
char *aa_profile;
|
||||||
#endif
|
#endif
|
||||||
|
char *logfile;
|
||||||
|
int loglevel;
|
||||||
|
|
||||||
#if HAVE_APPARMOR /* || HAVE_SELINUX || HAVE_SMACK */
|
#if HAVE_APPARMOR /* || HAVE_SELINUX || HAVE_SMACK */
|
||||||
int lsm_umount_proc;
|
int lsm_umount_proc;
|
||||||
#endif
|
#endif
|
||||||
|
char *seccomp; // filename with the seccomp rules
|
||||||
|
#if HAVE_SCMP_FILTER_CTX
|
||||||
|
scmp_filter_ctx *seccomp_ctx;
|
||||||
|
#endif
|
||||||
|
int maincmd_fd;
|
||||||
|
int autodev; // if 1, mount and fill a /dev at start
|
||||||
};
|
};
|
||||||
|
|
||||||
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
|
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
|
||||||
@ -237,20 +263,30 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
|
|||||||
* Initialize the lxc configuration structure
|
* Initialize the lxc configuration structure
|
||||||
*/
|
*/
|
||||||
extern struct lxc_conf *lxc_conf_init(void);
|
extern struct lxc_conf *lxc_conf_init(void);
|
||||||
|
extern void lxc_conf_free(struct lxc_conf *conf);
|
||||||
|
|
||||||
extern int pin_rootfs(const char *rootfs);
|
extern int pin_rootfs(const char *rootfs);
|
||||||
|
|
||||||
extern int lxc_create_network(struct lxc_handler *handler);
|
extern int lxc_create_network(struct lxc_handler *handler);
|
||||||
extern void lxc_delete_network(struct lxc_list *networks);
|
extern void lxc_delete_network(struct lxc_handler *handler);
|
||||||
extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
|
extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
|
||||||
extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
|
extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
|
||||||
|
|
||||||
extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
|
extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
|
||||||
extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
|
extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
|
||||||
|
|
||||||
|
extern int lxc_clear_config_network(struct lxc_conf *c);
|
||||||
|
extern int lxc_clear_nic(struct lxc_conf *c, const char *key);
|
||||||
|
extern int lxc_clear_config_caps(struct lxc_conf *c);
|
||||||
|
extern int lxc_clear_cgroups(struct lxc_conf *c, const char *key);
|
||||||
|
extern int lxc_clear_mount_entries(struct lxc_conf *c);
|
||||||
|
extern int lxc_clear_hooks(struct lxc_conf *c, const char *key);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure the container from inside
|
* Configure the container from inside
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf);
|
extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf);
|
||||||
|
|
||||||
|
extern void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf);
|
||||||
#endif
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -27,6 +27,15 @@
|
|||||||
struct lxc_conf;
|
struct lxc_conf;
|
||||||
struct lxc_list;
|
struct lxc_list;
|
||||||
|
|
||||||
|
typedef int (*config_cb)(const char *, const char *, struct lxc_conf *);
|
||||||
|
struct lxc_config_t {
|
||||||
|
char *name;
|
||||||
|
config_cb cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct lxc_config_t *lxc_getconfig(const char *key);
|
||||||
|
extern int lxc_list_nicconfigs(struct lxc_conf *c, const char *key, char *retv, int inlen);
|
||||||
|
extern int lxc_listconfigs(char *retv, int inlen);
|
||||||
extern int lxc_config_read(const char *file, struct lxc_conf *conf);
|
extern int lxc_config_read(const char *file, struct lxc_conf *conf);
|
||||||
extern int lxc_config_readline(char *buffer, struct lxc_conf *conf);
|
extern int lxc_config_readline(char *buffer, struct lxc_conf *conf);
|
||||||
|
|
||||||
@ -37,4 +46,7 @@ extern int lxc_config_define_load(struct lxc_list *defines,
|
|||||||
/* needed for lxc-attach */
|
/* needed for lxc-attach */
|
||||||
extern signed long lxc_config_parse_arch(const char *arch);
|
extern signed long lxc_config_parse_arch(const char *arch);
|
||||||
|
|
||||||
|
extern int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv, int inlen);
|
||||||
|
extern int lxc_clear_config_item(struct lxc_conf *c, const char *key);
|
||||||
|
extern void write_config(FILE *fout, struct lxc_conf *c);
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "start.h"
|
#include "start.h"
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ static int genetlink_resolve_family(const char *family)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = nla_put_string((struct nlmsg *)&request->nlmsghdr,
|
ret = nla_put_string((struct nlmsg *)&request->nlmsghdr,
|
||||||
CTRL_ATTR_FAMILY_NAME, family);
|
CTRL_ATTR_FAMILY_NAME, family);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
@ -130,7 +130,7 @@ extern int genetlink_send(struct genl_handler *handler, struct genlmsg *genlmsg)
|
|||||||
return netlink_send(&handler->nlh, (struct nlmsg *)&genlmsg->nlmsghdr);
|
return netlink_send(&handler->nlh, (struct nlmsg *)&genlmsg->nlmsghdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int genetlink_transaction(struct genl_handler *handler,
|
extern int genetlink_transaction(struct genl_handler *handler,
|
||||||
struct genlmsg *request, struct genlmsg *answer)
|
struct genlmsg *request, struct genlmsg *answer)
|
||||||
{
|
{
|
||||||
return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr,
|
return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr,
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
|
#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct genl_handler : the structure which store the netlink handler
|
* struct genl_handler : the structure which store the netlink handler
|
||||||
* and the family number resulting of the auto-generating id family
|
* and the family number resulting of the auto-generating id family
|
||||||
* for the generic netlink protocol
|
* for the generic netlink protocol
|
||||||
*
|
*
|
||||||
@ -116,6 +116,6 @@ void genlmsg_free(struct genlmsg *genlmsg);
|
|||||||
*
|
*
|
||||||
* Returns 0 on success, < 0 otherwise
|
* Returns 0 on success, < 0 otherwise
|
||||||
*/
|
*/
|
||||||
int genetlink_transaction(struct genl_handler *handler,
|
int genetlink_transaction(struct genl_handler *handler,
|
||||||
struct genlmsg *request, struct genlmsg *answer);
|
struct genlmsg *request, struct genlmsg *answer);
|
||||||
#endif
|
#endif
|
||||||
|
@ -75,7 +75,7 @@ directory=$(readlink -f "$lxc_path")
|
|||||||
for i in "$@"; do
|
for i in "$@"; do
|
||||||
case $i in
|
case $i in
|
||||||
--help)
|
--help)
|
||||||
help; exit 1;;
|
help; exit;;
|
||||||
--active)
|
--active)
|
||||||
get_parent_cgroup; directory="$parent_cgroup"; shift;;
|
get_parent_cgroup; directory="$parent_cgroup"; shift;;
|
||||||
--)
|
--)
|
||||||
@ -90,10 +90,5 @@ if [ ! -z "$directory" ]; then
|
|||||||
containers=$(find $directory -mindepth 1 -maxdepth 1 -type d -printf "%f\n" 2>/dev/null)
|
containers=$(find $directory -mindepth 1 -maxdepth 1 -type d -printf "%f\n" 2>/dev/null)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$containers" ]; then
|
|
||||||
echo "$(basename $0): no containers found" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$directory"
|
cd "$directory"
|
||||||
ls -d $@ -- $containers
|
ls -d $@ -- $containers
|
@ -14,6 +14,11 @@ struct lxc_list {
|
|||||||
__iterator != __list; \
|
__iterator != __list; \
|
||||||
__iterator = __iterator->next)
|
__iterator = __iterator->next)
|
||||||
|
|
||||||
|
#define lxc_list_for_each_safe(__iterator, __list, __next) \
|
||||||
|
for (__iterator = (__list)->next, __next = __iterator->next; \
|
||||||
|
__iterator != __list; \
|
||||||
|
__iterator = __next, __next = __next->next)
|
||||||
|
|
||||||
static inline void lxc_list_init(struct lxc_list *list)
|
static inline void lxc_list_init(struct lxc_list *list)
|
||||||
{
|
{
|
||||||
list->elem = NULL;
|
list->elem = NULL;
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
int lxc_log_fd = -1;
|
int lxc_log_fd = -1;
|
||||||
static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
|
static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
|
||||||
|
int lxc_loglevel_specified = 0;
|
||||||
|
|
||||||
lxc_log_define(lxc_log, lxc);
|
lxc_log_define(lxc_log, lxc);
|
||||||
|
|
||||||
@ -153,7 +154,11 @@ extern int lxc_log_init(const char *file, const char *priority,
|
|||||||
{
|
{
|
||||||
int lxc_priority = LXC_LOG_PRIORITY_ERROR;
|
int lxc_priority = LXC_LOG_PRIORITY_ERROR;
|
||||||
|
|
||||||
|
if (lxc_log_fd != -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (priority) {
|
if (priority) {
|
||||||
|
lxc_loglevel_specified = 1;
|
||||||
lxc_priority = lxc_log_priority_to_int(priority);
|
lxc_priority = lxc_log_priority_to_int(priority);
|
||||||
|
|
||||||
if (lxc_priority == LXC_LOG_PRIORITY_NOTSET) {
|
if (lxc_priority == LXC_LOG_PRIORITY_NOTSET) {
|
||||||
@ -185,3 +190,39 @@ extern int lxc_log_init(const char *file, const char *priority,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is called when we read a lxc.loglevel entry in a lxc.conf file. This
|
||||||
|
* happens after processing command line arguments, which override the .conf
|
||||||
|
* settings. So only set the level if previously unset.
|
||||||
|
*/
|
||||||
|
extern int lxc_log_set_level(int level)
|
||||||
|
{
|
||||||
|
if (lxc_loglevel_specified)
|
||||||
|
return 0;
|
||||||
|
if (level < 0 || level >= LXC_LOG_PRIORITY_NOTSET) {
|
||||||
|
ERROR("invalid log priority %d", level);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
lxc_log_category_lxc.priority = level;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is called when we read a lxc.logfile entry in a lxc.conf file. This
|
||||||
|
* happens after processing command line arguments, which override the .conf
|
||||||
|
* settings. So only set the logfile if previously unset.
|
||||||
|
*/
|
||||||
|
extern int lxc_log_set_file(char *fname)
|
||||||
|
{
|
||||||
|
if (lxc_log_fd != -1) {
|
||||||
|
INFO("Configuration file was specified on command line, configuration file entry being ignored");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lxc_log_fd = log_open(fname);
|
||||||
|
if (lxc_log_fd == -1) {
|
||||||
|
ERROR("failed to open log file %s\n", fname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
#define LXC_LOG_BUFFER_SIZE 512
|
#define LXC_LOG_BUFFER_SIZE 512
|
||||||
|
|
||||||
/* predefined priorities. */
|
/* predefined priorities. */
|
||||||
enum {
|
enum lxc_loglevel {
|
||||||
LXC_LOG_PRIORITY_TRACE,
|
LXC_LOG_PRIORITY_TRACE,
|
||||||
LXC_LOG_PRIORITY_DEBUG,
|
LXC_LOG_PRIORITY_DEBUG,
|
||||||
LXC_LOG_PRIORITY_INFO,
|
LXC_LOG_PRIORITY_INFO,
|
||||||
@ -291,4 +291,6 @@ extern int lxc_log_init(const char *file, const char *priority,
|
|||||||
const char *prefix, int quiet);
|
const char *prefix, int quiet);
|
||||||
|
|
||||||
extern void lxc_log_setprefix(const char *a_prefix);
|
extern void lxc_log_setprefix(const char *a_prefix);
|
||||||
|
extern int lxc_log_set_level(int level);
|
||||||
|
extern int lxc_log_set_file(char *fname);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
# Allow environment variables to override grep and config
|
# Allow environment variables to override grep and config
|
||||||
: ${CONFIG:=/proc/config.gz}
|
: ${CONFIG:=/proc/config.gz}
|
||||||
: ${GREP:=zgrep}
|
: ${GREP:=zgrep}
|
||||||
|
|
||||||
SETCOLOR_SUCCESS="echo -en \\033[1;32m"
|
SETCOLOR_SUCCESS="printf \\e[1;32m"
|
||||||
SETCOLOR_FAILURE="echo -en \\033[1;31m"
|
SETCOLOR_FAILURE="printf \\e[1;31m"
|
||||||
SETCOLOR_WARNING="echo -en \\033[1;33m"
|
SETCOLOR_WARNING="printf \\e[1;33m"
|
||||||
SETCOLOR_NORMAL="echo -en \\033[0;39m"
|
SETCOLOR_NORMAL="printf \\e[0;39m"
|
||||||
|
|
||||||
is_set() {
|
is_set() {
|
||||||
$GREP -q "$1=[y|m]" $CONFIG
|
$GREP -q "$1=[y|m]" $CONFIG
|
||||||
@ -21,13 +21,13 @@ is_enabled() {
|
|||||||
RES=$?
|
RES=$?
|
||||||
|
|
||||||
if [ $RES -eq 0 ]; then
|
if [ $RES -eq 0 ]; then
|
||||||
$SETCOLOR_SUCCESS && echo -e "enabled" && $SETCOLOR_NORMAL
|
$SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
|
||||||
else
|
else
|
||||||
if [ ! -z "$mandatory" -a "$mandatory" = yes ]; then
|
if [ ! -z "$mandatory" -a "$mandatory" = yes ]; then
|
||||||
$SETCOLOR_FAILURE && echo -e "required" && $SETCOLOR_NORMAL
|
$SETCOLOR_FAILURE && echo "required" && $SETCOLOR_NORMAL
|
||||||
else
|
else
|
||||||
$SETCOLOR_WARNING && echo -e "missing" && $SETCOLOR_NORMAL
|
$SETCOLOR_WARNING && echo "missing" && $SETCOLOR_NORMAL
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,40 +68,45 @@ print_cgroups() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CGROUP_MNT_PATH=`print_cgroups cgroup /proc/self/mounts | head -1`
|
CGROUP_MNT_PATH=`print_cgroups cgroup /proc/self/mounts | head -1`
|
||||||
|
|
||||||
echo -n "Cgroup: " && is_enabled CONFIG_CGROUPS yes
|
|
||||||
|
|
||||||
if [ -f $CGROUP_MNT_PATH/cgroup.clone_children ]; then
|
|
||||||
echo -n "Cgroup clone_children flag: " &&
|
|
||||||
$SETCOLOR_SUCCESS && echo -e "enabled" && $SETCOLOR_NORMAL
|
|
||||||
else
|
|
||||||
echo -n "Cgroup namespace: " && is_enabled CONFIG_CGROUP_NS yes
|
|
||||||
fi
|
|
||||||
echo -n "Cgroup device: " && is_enabled CONFIG_CGROUP_DEVICE
|
|
||||||
echo -n "Cgroup sched: " && is_enabled CONFIG_CGROUP_SCHED
|
|
||||||
echo -n "Cgroup cpu account: " && is_enabled CONFIG_CGROUP_CPUACCT
|
|
||||||
echo -n "Cgroup memory controller: " && is_enabled CONFIG_CGROUP_MEM_RES_CTLR
|
|
||||||
is_set CONFIG_SMP && echo -n "Cgroup cpuset: " && is_enabled CONFIG_CPUSETS
|
|
||||||
echo
|
|
||||||
echo "--- Misc ---"
|
|
||||||
echo -n "Veth pair device: " && is_enabled CONFIG_VETH
|
|
||||||
echo -n "Macvlan: " && is_enabled CONFIG_MACVLAN
|
|
||||||
echo -n "Vlan: " && is_enabled CONFIG_VLAN_8021Q
|
|
||||||
KVER_MAJOR=$($GREP '^# Linux' $CONFIG | \
|
KVER_MAJOR=$($GREP '^# Linux' $CONFIG | \
|
||||||
sed -r 's/.* ([0-9])\.[0-9]{1,2}\.[0-9]{1,3}.*/\1/')
|
sed -r 's/.* ([0-9])\.[0-9]{1,2}\.[0-9]{1,3}.*/\1/')
|
||||||
if [[ $KVER_MAJOR == 2 ]]; then
|
if [ "$KVER_MAJOR" = "2" ]; then
|
||||||
KVER_MINOR=$($GREP '^# Linux' $CONFIG | \
|
KVER_MINOR=$($GREP '^# Linux' $CONFIG | \
|
||||||
sed -r 's/.* 2.6.([0-9]{2}).*/\1/')
|
sed -r 's/.* 2.6.([0-9]{2}).*/\1/')
|
||||||
else
|
else
|
||||||
KVER_MINOR=$($GREP '^# Linux' $CONFIG | \
|
KVER_MINOR=$($GREP '^# Linux' $CONFIG | \
|
||||||
sed -r 's/.* [0-9]\.([0-9]{1,3})\.[0-9]{1,3}.*/\1/')
|
sed -r 's/.* [0-9]\.([0-9]{1,3})\.[0-9]{1,3}.*/\1/')
|
||||||
fi
|
fi
|
||||||
echo -n "File capabilities: " &&
|
|
||||||
( [[ ${KVER_MAJOR} == 2 && ${KVER_MINOR} < 33 ]] &&
|
echo -n "Cgroup: " && is_enabled CONFIG_CGROUPS yes
|
||||||
is_enabled CONFIG_SECURITY_FILE_CAPABILITIES ) ||
|
|
||||||
( [[ ( ${KVER_MAJOR} == 2 && ${KVER_MINOR} > 32 ) ||
|
if [ -f $CGROUP_MNT_PATH/cgroup.clone_children ]; then
|
||||||
${KVER_MAJOR} > 2 ]] && $SETCOLOR_SUCCESS &&
|
echo -n "Cgroup clone_children flag: " &&
|
||||||
echo -e "enabled" && $SETCOLOR_NORMAL )
|
$SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
|
||||||
|
else
|
||||||
|
echo -n "Cgroup namespace: " && is_enabled CONFIG_CGROUP_NS yes
|
||||||
|
fi
|
||||||
|
echo -n "Cgroup device: " && is_enabled CONFIG_CGROUP_DEVICE
|
||||||
|
echo -n "Cgroup sched: " && is_enabled CONFIG_CGROUP_SCHED
|
||||||
|
echo -n "Cgroup cpu account: " && is_enabled CONFIG_CGROUP_CPUACCT
|
||||||
|
echo -n "Cgroup memory controller: "
|
||||||
|
if [ $KVER_MAJOR -ge 3 -a $KVER_MINOR -ge 6 ]; then
|
||||||
|
is_enabled CONFIG_MEMCG
|
||||||
|
else
|
||||||
|
is_enabled CONFIG_CGROUP_MEM_RES_CTLR
|
||||||
|
fi
|
||||||
|
is_set CONFIG_SMP && echo -n "Cgroup cpuset: " && is_enabled CONFIG_CPUSETS
|
||||||
|
echo
|
||||||
|
echo "--- Misc ---"
|
||||||
|
echo -n "Veth pair device: " && is_enabled CONFIG_VETH
|
||||||
|
echo -n "Macvlan: " && is_enabled CONFIG_MACVLAN
|
||||||
|
echo -n "Vlan: " && is_enabled CONFIG_VLAN_8021Q
|
||||||
|
echo -n "File capabilities: " && \
|
||||||
|
( [ "${KVER_MAJOR}" = 2 ] && [ ${KVER_MINOR} -lt 33 ] && \
|
||||||
|
is_enabled CONFIG_SECURITY_FILE_CAPABILITIES ) || \
|
||||||
|
( ( [ "${KVER_MAJOR}" = "2" ] && [ ${KVER_MINOR} -gt 32 ] ) || \
|
||||||
|
[ ${KVER_MAJOR} -gt 2 ] && $SETCOLOR_SUCCESS && \
|
||||||
|
echo "enabled" && $SETCOLOR_NORMAL )
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Note : Before booting a new kernel, you can check its configuration"
|
echo "Note : Before booting a new kernel, you can check its configuration"
|
||||||
|
@ -225,7 +225,7 @@ if [ -b $oldroot ]; then
|
|||||||
mkfs -t $fstype /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new
|
mkfs -t $fstype /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new
|
||||||
mount /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new $rootfs || { echo "$(basename $0): failed to mount new rootfs" >&2; false; }
|
mount /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new $rootfs || { echo "$(basename $0): failed to mount new rootfs" >&2; false; }
|
||||||
mounted=1
|
mounted=1
|
||||||
rsync -ax ${rootfs}_snapshot/ ${rootfs}/ || { echo "$(basename $0): copying data to new lv failed" >&2; false; }
|
rsync -Hax ${rootfs}_snapshot/ ${rootfs}/ || { echo "$(basename $0): copying data to new lv failed" >&2; false; }
|
||||||
umount ${rootfs}_snapshot
|
umount ${rootfs}_snapshot
|
||||||
rmdir ${rootfs}_snapshot
|
rmdir ${rootfs}_snapshot
|
||||||
lvremove -f $lxc_vg/${lxc_lv_prefix}${lxc_new}_snapshot
|
lvremove -f $lxc_vg/${lxc_lv_prefix}${lxc_new}_snapshot
|
||||||
@ -252,7 +252,7 @@ else
|
|||||||
frozen=1
|
frozen=1
|
||||||
fi
|
fi
|
||||||
mkdir -p $rootfs/
|
mkdir -p $rootfs/
|
||||||
rsync -ax $oldroot/ $rootfs/
|
rsync -Hax $oldroot/ $rootfs/
|
||||||
echo "lxc.rootfs = $rootfs" >> $lxc_path/$lxc_new/config
|
echo "lxc.rootfs = $rootfs" >> $lxc_path/$lxc_new/config
|
||||||
if [ $container_running = "True" ]; then
|
if [ $container_running = "True" ]; then
|
||||||
lxc-unfreeze -n $lxc_orig
|
lxc-unfreeze -n $lxc_orig
|
||||||
@ -272,11 +272,11 @@ c=$lxc_path/$lxc_new/config
|
|||||||
mv ${c} ${c}.old
|
mv ${c} ${c}.old
|
||||||
(
|
(
|
||||||
while read line; do
|
while read line; do
|
||||||
if [ "${line:0:18}" = "lxc.network.hwaddr" ]; then
|
if [ "${line:0:18}" = "lxc.network.hwaddr" ]; then
|
||||||
echo "lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')"
|
echo "lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')"
|
||||||
else
|
else
|
||||||
echo "$line"
|
echo "$line"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
) < ${c}.old > ${c}
|
) < ${c}.old > ${c}
|
||||||
rm -f ${c}.old
|
rm -f ${c}.old
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# lxc: linux Container library
|
# lxc: linux Container library
|
||||||
@ -26,6 +26,7 @@ usage() {
|
|||||||
echo >&2
|
echo >&2
|
||||||
echo "where FS_OPTIONS is one of:" >&2
|
echo "where FS_OPTIONS is one of:" >&2
|
||||||
echo " -B none" >&2
|
echo " -B none" >&2
|
||||||
|
echo " -B dir [--dir rootfs_dir]" >&2
|
||||||
echo " -B lvm [--lvname LV_NAME] [--vgname VG_NAME] [--fstype FS_TYPE]" >&2
|
echo " -B lvm [--lvname LV_NAME] [--vgname VG_NAME] [--fstype FS_TYPE]" >&2
|
||||||
echo " [--fssize FS_SIZE]" >&2
|
echo " [--fssize FS_SIZE]" >&2
|
||||||
echo " -B btrfs" >&2
|
echo " -B btrfs" >&2
|
||||||
@ -43,25 +44,35 @@ help() {
|
|||||||
echo " -B BACKING_STORE alter the container backing store (default: none)" >&2
|
echo " -B BACKING_STORE alter the container backing store (default: none)" >&2
|
||||||
echo " --lvname LV_NAME specify the LVM logical volume name" >&2
|
echo " --lvname LV_NAME specify the LVM logical volume name" >&2
|
||||||
echo " (default: container name)" >&2
|
echo " (default: container name)" >&2
|
||||||
|
echo " --dir ROOTFS_DIR specify path for custom rootfs directory location" >&2
|
||||||
echo " --vgname VG_NAME specify the LVM volume group name (default: lxc)" >&2
|
echo " --vgname VG_NAME specify the LVM volume group name (default: lxc)" >&2
|
||||||
echo " --fstype FS_TYPE specify the filesystem type (default: ext4)" >&2
|
echo " --fstype FS_TYPE specify the filesystem type (default: ext4)" >&2
|
||||||
echo " --fssize FS_SIZE specify the filesystem size (default: 500M)" >&2
|
echo " --fssize FS_SIZE specify the filesystem size (default: 500M)" >&2
|
||||||
echo >&2
|
echo >&2
|
||||||
if [ -z $lxc_template ]; then
|
if [ -z "$lxc_template" ]; then
|
||||||
echo "To see template-specific options, specify a template. For example:" >&2
|
echo "To see template-specific options, specify a template. For example:" >&2
|
||||||
echo " $(basename $0) -t ubuntu -h" >&2
|
echo " $(basename $0) -t ubuntu -h" >&2
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
type ${templatedir}/lxc-$lxc_template 2>/dev/null
|
if [ -x ${templatedir}/lxc-$lxc_template ]; then
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo >&2
|
echo >&2
|
||||||
echo "Template-specific options (TEMPLATE_OPTIONS):" >&2
|
echo "Template-specific options (TEMPLATE_OPTIONS):" >&2
|
||||||
${templatedir}/lxc-$lxc_template -h
|
${templatedir}/lxc-$lxc_template -h
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
shortoptions='hn:f:t:B:'
|
usage_err() {
|
||||||
longoptions='help,name:,config:,template:,backingstore:,fstype:,lvname:,vgname:,fssize:'
|
[ -n "$1" ] && echo "$1" >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
optarg_check() {
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
usage_err "option '$1' requires an argument"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
lxc_path=@LXCPATH@
|
lxc_path=@LXCPATH@
|
||||||
bindir=@BINDIR@
|
bindir=@BINDIR@
|
||||||
templatedir=@LXCTEMPLATEDIR@
|
templatedir=@LXCTEMPLATEDIR@
|
||||||
@ -69,80 +80,85 @@ backingstore=_unset
|
|||||||
fstype=ext4
|
fstype=ext4
|
||||||
fssize=500M
|
fssize=500M
|
||||||
vgname=lxc
|
vgname=lxc
|
||||||
|
custom_rootfs=""
|
||||||
|
|
||||||
getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@")
|
while [ $# -gt 0 ]; do
|
||||||
if [ $? != 0 ]; then
|
opt="$1"
|
||||||
usage
|
shift
|
||||||
exit 1;
|
case "$opt" in
|
||||||
fi
|
-h|--help)
|
||||||
|
help
|
||||||
eval set -- "$getopt"
|
exit 1
|
||||||
|
;;
|
||||||
while true; do
|
-n|--name)
|
||||||
case "$1" in
|
optarg_check $opt "$1"
|
||||||
-h|--help)
|
lxc_name=$1
|
||||||
help
|
shift
|
||||||
exit 1
|
;;
|
||||||
;;
|
-f|--config)
|
||||||
-n|--name)
|
optarg_check $opt "$1"
|
||||||
shift
|
lxc_config=$1
|
||||||
lxc_name=$1
|
shift
|
||||||
shift
|
;;
|
||||||
;;
|
-t|--template)
|
||||||
-f|--config)
|
optarg_check $opt "$1"
|
||||||
shift
|
lxc_template=$1
|
||||||
lxc_config=$1
|
shift
|
||||||
shift
|
;;
|
||||||
;;
|
-B|--backingstore)
|
||||||
-t|--template)
|
optarg_check $opt "$1"
|
||||||
shift
|
backingstore=$1
|
||||||
lxc_template=$1
|
shift
|
||||||
shift
|
;;
|
||||||
;;
|
--dir)
|
||||||
-B|--backingstore)
|
optarg_check $opt "$1"
|
||||||
shift
|
custom_rootfs=$1
|
||||||
backingstore=$1
|
shift
|
||||||
shift
|
;;
|
||||||
;;
|
--lvname)
|
||||||
--lvname)
|
optarg_check $opt "$1"
|
||||||
shift
|
lvname=$1
|
||||||
lvname=$1
|
shift
|
||||||
shift
|
;;
|
||||||
;;
|
--vgname)
|
||||||
--vgname)
|
optarg_check $opt "$1"
|
||||||
shift
|
vgname=$1
|
||||||
vgname=$1
|
shift
|
||||||
shift
|
;;
|
||||||
;;
|
--fstype)
|
||||||
--fstype)
|
optarg_check $opt "$1"
|
||||||
shift
|
fstype=$1
|
||||||
fstype=$1
|
shift
|
||||||
shift
|
;;
|
||||||
;;
|
--fssize)
|
||||||
--fssize)
|
optarg_check $opt "$1"
|
||||||
shift
|
fssize=$1
|
||||||
fssize=$1
|
shift
|
||||||
shift
|
;;
|
||||||
;;
|
--)
|
||||||
--)
|
break;;
|
||||||
shift
|
-?)
|
||||||
break;;
|
usage_err "unknown option '$opt'"
|
||||||
*)
|
;;
|
||||||
usage
|
-*)
|
||||||
exit 1
|
# split opts -abc into -a -b -c
|
||||||
;;
|
set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
|
||||||
esac
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# If -h or --help was passed into the container, we'll want to cleanup
|
# If -h or --help was passed into the container, we'll want to cleanup
|
||||||
# afterward
|
# afterward
|
||||||
wantedhelp=0
|
wantedhelp=0
|
||||||
for var in "$@"
|
for var in "$@"; do
|
||||||
do
|
if [ "$var" = "-h" ] || [ "$var" = "--help" ]; then
|
||||||
if [ "$var" = "-h" -o "$var" = "--help" ]; then
|
help
|
||||||
help
|
exit 1
|
||||||
exit 1
|
fi
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
@ -171,9 +187,14 @@ if [ "$(id -u)" != "0" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "$custom_rootfs" ] && [ "$backingstore" != "dir" ]; then
|
||||||
|
echo "--dir is only valid with -B dir"
|
||||||
|
fi
|
||||||
|
|
||||||
case "$backingstore" in
|
case "$backingstore" in
|
||||||
lvm|none|btrfs|_unset) :;;
|
dir|lvm|none|btrfs|_unset) :;;
|
||||||
*) echo "$(basename $0): '$backingstore' is not known (try 'none', 'lvm', 'btrfs')" >&2
|
*)
|
||||||
|
echo "$(basename $0): '$backingstore' is not known (try 'none', 'dir', 'lvm', 'btrfs')" >&2
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
@ -186,9 +207,9 @@ fi
|
|||||||
|
|
||||||
rootfs="$lxc_path/$lxc_name/rootfs"
|
rootfs="$lxc_path/$lxc_name/rootfs"
|
||||||
|
|
||||||
if [ "$backingstore" = "_unset" -o "$backingstore" = "btrfs" ]; then
|
if [ "$backingstore" = "_unset" ] || [ "$backingstore" = "btrfs" ]; then
|
||||||
# if no backing store was given, then see if btrfs would work
|
# if no backing store was given, then see if btrfs would work
|
||||||
if which btrfs >/dev/null 2>&1 &&
|
if which btrfs >/dev/null 2>&1 && \
|
||||||
btrfs filesystem df "$lxc_path/" >/dev/null 2>&1; then
|
btrfs filesystem df "$lxc_path/" >/dev/null 2>&1; then
|
||||||
backingstore="btrfs"
|
backingstore="btrfs"
|
||||||
else
|
else
|
||||||
@ -200,12 +221,13 @@ if [ "$backingstore" = "_unset" -o "$backingstore" = "btrfs" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $backingstore = "lvm" ]; then
|
if [ "$backingstore" = "lvm" ]; then
|
||||||
which vgscan > /dev/null
|
which vgscan > /dev/null
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "$(basename $0): vgscan not found (is lvm2 installed?)" >&2
|
echo "$(basename $0): vgscan not found (is lvm2 installed?)" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
grep -q "\<$fstype\>" /proc/filesystems
|
grep -q "\<$fstype\>" /proc/filesystems
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "$(basename $0): $fstype is not listed in /proc/filesystems" >&2
|
echo "$(basename $0): $fstype is not listed in /proc/filesystems" >&2
|
||||||
@ -225,6 +247,7 @@ if [ $backingstore = "lvm" ]; then
|
|||||||
echo "please delete it (using \"lvremove $rootdev\") and try again" >&2
|
echo "please delete it (using \"lvremove $rootdev\") and try again" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
elif [ "$backingstore" = "btrfs" ]; then
|
elif [ "$backingstore" = "btrfs" ]; then
|
||||||
mkdir "$lxc_path/$lxc_name"
|
mkdir "$lxc_path/$lxc_name"
|
||||||
if ! out=$(btrfs subvolume create "$rootfs" 2>&1); then
|
if ! out=$(btrfs subvolume create "$rootfs" 2>&1); then
|
||||||
@ -234,10 +257,13 @@ elif [ "$backingstore" = "btrfs" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
if [ $backingstore = "lvm" ]; then
|
if [ "$backingstore" = "lvm" ]; then
|
||||||
umount $rootfs
|
umount $rootfs
|
||||||
lvremove -f $rootdev
|
lvremove -f $rootdev
|
||||||
|
elif [ "$backingstore" = "btrfs" ]; then
|
||||||
|
btrfs subvolume delete "$rootfs"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${bindir}/lxc-destroy -n $lxc_name
|
${bindir}/lxc-destroy -n $lxc_name
|
||||||
echo "$(basename $0): aborted" >&2
|
echo "$(basename $0): aborted" >&2
|
||||||
exit 1
|
exit 1
|
||||||
@ -248,18 +274,54 @@ trap cleanup HUP INT TERM
|
|||||||
mkdir -p $lxc_path/$lxc_name
|
mkdir -p $lxc_path/$lxc_name
|
||||||
|
|
||||||
if [ -z "$lxc_config" ]; then
|
if [ -z "$lxc_config" ]; then
|
||||||
touch $lxc_path/$lxc_name/config
|
lxc_config="@SYSCONFDIR@/lxc/lxc.conf"
|
||||||
else
|
echo
|
||||||
if [ ! -r "$lxc_config" ]; then
|
echo "$(basename $0): No config file specified, using the default config $lxc_config"
|
||||||
echo "$(basename $0): '$lxc_config' configuration file not found" >&2
|
fi
|
||||||
exit 1
|
|
||||||
|
if [ ! -r "$lxc_config" ]; then
|
||||||
|
echo "$(basename $0): '$lxc_config' configuration file not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "$lxc_template" ]; then
|
||||||
|
# Allow for a path to be provided as the template name
|
||||||
|
if [ -x "$lxc_template" ]; then
|
||||||
|
template_path=$lxc_template
|
||||||
|
else
|
||||||
|
template_path=${templatedir}/lxc-$lxc_template
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cp $lxc_config $lxc_path/$lxc_name/config
|
if ! [ -x "$template_path" ]; then
|
||||||
|
echo "$(basename $0): unknown template '$lxc_template'" >&2
|
||||||
|
cleanup
|
||||||
|
fi
|
||||||
|
|
||||||
|
sum=$(sha1sum $template_path | cut -d ' ' -f1)
|
||||||
|
echo "# Template used to create this container: $lxc_template" >> $lxc_path/$lxc_name/config
|
||||||
|
if [ -n "$*" ]; then
|
||||||
|
echo "# Parameters passed to the template: $*" >> $lxc_path/$lxc_name/config
|
||||||
|
fi
|
||||||
|
echo "# Checksum of the template script (SHA-1): $sum" >> $lxc_path/$lxc_name/config
|
||||||
|
echo "" >> $lxc_path/$lxc_name/config
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat $lxc_config >> $lxc_path/$lxc_name/config
|
||||||
|
|
||||||
|
if [ -n "$custom_rootfs" ]; then
|
||||||
|
if grep -q "lxc.rootfs" $lxc_path/$lxc_name/config ; then
|
||||||
|
echo "configuration file already specifies a lxc.rootfs"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -d "$custom_rootfs" ]; then
|
||||||
|
echo "specified rootfs ($custom_rootfs) already exists. Bailing."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "lxc.rootfs = $custom_rootfs" >> $lxc_path/$lxc_name/config
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create the fs as needed
|
# Create the fs as needed
|
||||||
if [ $backingstore = "lvm" ]; then
|
if [ "$backingstore" = "lvm" ]; then
|
||||||
[ -d "$rootfs" ] || mkdir $rootfs
|
[ -d "$rootfs" ] || mkdir $rootfs
|
||||||
lvcreate -L $fssize -n $lvname $vgname || exit 1
|
lvcreate -L $fssize -n $lvname $vgname || exit 1
|
||||||
udevadm settle
|
udevadm settle
|
||||||
@ -267,22 +329,8 @@ if [ $backingstore = "lvm" ]; then
|
|||||||
mount -t $fstype $rootdev $rootfs
|
mount -t $fstype $rootdev $rootfs
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -z $lxc_template ]; then
|
if [ ! -z "$lxc_template" ]; then
|
||||||
|
$template_path --path=$lxc_path/$lxc_name --name=$lxc_name $*
|
||||||
type ${templatedir}/lxc-$lxc_template 2>/dev/null
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "$(basename $0): unknown template '$lxc_template'" >&2
|
|
||||||
cleanup
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$lxc_config" ]; then
|
|
||||||
echo "Note: Usually the template option is called with a configuration"
|
|
||||||
echo "file option too, mostly to configure the network."
|
|
||||||
echo "For more information look at lxc.conf (5)"
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
${templatedir}/lxc-$lxc_template --path=$lxc_path/$lxc_name --name=$lxc_name $*
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "$(basename $0): failed to execute template '$lxc_template'" >&2
|
echo "$(basename $0): failed to execute template '$lxc_template'" >&2
|
||||||
cleanup
|
cleanup
|
||||||
@ -291,7 +339,7 @@ if [ ! -z $lxc_template ]; then
|
|||||||
echo "'$lxc_template' template installed"
|
echo "'$lxc_template' template installed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $backingstore = "lvm" ]; then
|
if [ "$backingstore" = "lvm" ]; then
|
||||||
echo "Unmounting LVM"
|
echo "Unmounting LVM"
|
||||||
umount $rootfs
|
umount $rootfs
|
||||||
|
|
||||||
|
@ -54,26 +54,27 @@ eval set -- "$getopt"
|
|||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-h|--help)
|
-h|--help)
|
||||||
help
|
help
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
-n|--name)
|
-n|--name)
|
||||||
shift
|
shift
|
||||||
lxc_name=$1
|
lxc_name=$1
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
-f)
|
-f)
|
||||||
force=1
|
force=1
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--)
|
--)
|
||||||
shift
|
shift
|
||||||
break;;
|
break
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -96,13 +97,13 @@ fi
|
|||||||
# make sure the container isn't running
|
# make sure the container isn't running
|
||||||
lxc-info -n $lxc_name 2>/dev/null | grep -q RUNNING
|
lxc-info -n $lxc_name 2>/dev/null | grep -q RUNNING
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
if [ $force -eq 1 ]; then
|
if [ $force -eq 1 ]; then
|
||||||
lxc-stop -n $lxc_name
|
lxc-stop -n $lxc_name
|
||||||
lxc-wait -n $lxc_name -s STOPPED
|
lxc-wait -n $lxc_name -s STOPPED
|
||||||
else
|
else
|
||||||
echo "$(basename $0): '$lxc_name' is running; aborted" >&2
|
echo "$(basename $0): '$lxc_name' is running; aborted" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Deduce the type of rootfs
|
# Deduce the type of rootfs
|
||||||
@ -110,21 +111,22 @@ fi
|
|||||||
# else, ignore it. We'll support deletion of others later.
|
# else, ignore it. We'll support deletion of others later.
|
||||||
rootdev=`grep lxc.rootfs $lxc_path/$lxc_name/config 2>/dev/null | sed -e 's/^[^/]*/\//'`
|
rootdev=`grep lxc.rootfs $lxc_path/$lxc_name/config 2>/dev/null | sed -e 's/^[^/]*/\//'`
|
||||||
if [ -n "$rootdev" ]; then
|
if [ -n "$rootdev" ]; then
|
||||||
if [ -b "$rootdev" ]; then
|
if [ -b "$rootdev" -o -h "$rootdev" ]; then
|
||||||
lvdisplay $rootdev > /dev/null 2>&1
|
lvdisplay $rootdev > /dev/null 2>&1
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "removing backing store: $rootdev"
|
echo "removing backing store: $rootdev"
|
||||||
lvremove -f $rootdev
|
lvremove -f $rootdev
|
||||||
fi
|
fi
|
||||||
elif [ -h "$rootdev" -o -d "$rootdev" ]; then
|
elif [ -h "$rootdev" -o -d "$rootdev" ]; then
|
||||||
if which btrfs >/dev/null 2>&1 &&
|
if which btrfs >/dev/null 2>&1 &&
|
||||||
btrfs subvolume list "$rootdev" >/dev/null 2>&1; then
|
btrfs subvolume list "$rootdev" >/dev/null 2>&1; then
|
||||||
btrfs subvolume delete "$rootdev"
|
btrfs subvolume delete "$rootdev"
|
||||||
else
|
else
|
||||||
# In case rootfs is not under $lxc_path/$lxc_name, remove it
|
# In case rootfs is not under $lxc_path/$lxc_name, remove it
|
||||||
rm -rf --one-file-system --preserve-root $rootdev
|
rm -rf --one-file-system --preserve-root $rootdev
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# recursively remove the container to remove old container configuration
|
# recursively remove the container to remove old container configuration
|
||||||
rm -rf --one-file-system --preserve-root $lxc_path/$lxc_name
|
rm -rf --one-file-system --preserve-root $lxc_path/$lxc_name
|
||||||
|
95
src/lxc/lxc-device
Normal file
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
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
echo "usage: $(basename $0) -n|--name <name> -- [netstat_options]" >&2
|
echo "usage: $(basename $0) -n|--name <name> -- [netstat_options]" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
help() {
|
help() {
|
||||||
usage
|
usage
|
||||||
echo >&2
|
echo >&2
|
||||||
echo "Execute 'netstat' for the specified container." >&2
|
echo "Execute 'netstat' for the specified container." >&2
|
||||||
echo >&2
|
echo >&2
|
||||||
echo " --name NAME specify the container name" >&2
|
echo " --name NAME specify the container name" >&2
|
||||||
echo " NETSTAT_OPTIONS netstat command options (see \`netstat --help')" >&2
|
echo " NETSTAT_OPTIONS netstat command options (see \`netstat --help')" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
get_parent_cgroup()
|
get_parent_cgroup()
|
||||||
{
|
{
|
||||||
local hierarchies hierarchy fields subsystems init_cgroup mountpoint
|
local hierarchies hierarchy fields subsystems init_cgroup mountpoint
|
||||||
|
|
||||||
parent_cgroup=""
|
parent_cgroup=""
|
||||||
|
|
||||||
# Obtain a list of hierarchies that contain one or more subsystems
|
# Obtain a list of hierarchies that contain one or more subsystems
|
||||||
hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
|
hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
|
||||||
|
|
||||||
# Iterate through the list until a suitable hierarchy is found
|
# Iterate through the list until a suitable hierarchy is found
|
||||||
for hierarchy in $hierarchies; do
|
for hierarchy in $hierarchies; do
|
||||||
# Obtain information about the init process in the hierarchy
|
# Obtain information about the init process in the hierarchy
|
||||||
fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1)
|
fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1)
|
||||||
if [ -z "$fields" ]; then continue; fi
|
if [ -z "$fields" ]; then continue; fi
|
||||||
fields=${fields#*:}
|
fields=${fields#*:}
|
||||||
|
|
||||||
# Get a comma-separated list of the hierarchy's subsystems
|
# Get a comma-separated list of the hierarchy's subsystems
|
||||||
subsystems=${fields%:*}
|
subsystems=${fields%:*}
|
||||||
|
|
||||||
# Get the cgroup of the init process in the hierarchy
|
# Get the cgroup of the init process in the hierarchy
|
||||||
init_cgroup=${fields#*:}
|
init_cgroup=${fields#*:}
|
||||||
|
|
||||||
# Get the filesystem mountpoint of the hierarchy
|
# Get the filesystem mountpoint of the hierarchy
|
||||||
mountpoint=$(grep -E "^cgroup [^ ]+ [^ ]+ ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2)
|
mountpoint=$(grep -E "^cgroup [^ ]+ [^ ]+ ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2)
|
||||||
if [ -z "$mountpoint" ]; then continue; fi
|
if [ -z "$mountpoint" ]; then continue; fi
|
||||||
|
|
||||||
# Return the absolute path to the containers' parent cgroup
|
# Return the absolute path to the containers' parent cgroup
|
||||||
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
|
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
|
||||||
if [[ ",$subsystems," == *,ns,* ]]; then
|
if [[ ",$subsystems," == *,ns,* ]]; then
|
||||||
parent_cgroup="${mountpoint}${init_cgroup%/}"
|
parent_cgroup="${mountpoint}${init_cgroup%/}"
|
||||||
else
|
else
|
||||||
parent_cgroup="${mountpoint}${init_cgroup%/}/lxc"
|
parent_cgroup="${mountpoint}${init_cgroup%/}/lxc"
|
||||||
fi
|
fi
|
||||||
break
|
break
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
exec=""
|
exec=""
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
case $1 in
|
case $1 in
|
||||||
-h|--help)
|
-h|--help)
|
||||||
help; exit 1;;
|
help; exit 1;;
|
||||||
-n|--name)
|
-n|--name)
|
||||||
name=$2; shift 2;;
|
name=$2; shift 2;;
|
||||||
--exec)
|
--exec)
|
||||||
exec="exec"; shift;;
|
exec="exec"; shift;;
|
||||||
--)
|
--)
|
||||||
shift; break;;
|
shift; break;;
|
||||||
*)
|
*)
|
||||||
break;;
|
break;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$(id -u)" != "0" ]; then
|
if [ "$(id -u)" != "0" ]; then
|
||||||
echo "$(basename $0): must be run as root" >&2
|
echo "$(basename $0): must be run as root" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$name" ]; then
|
if [ -z "$name" ]; then
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$exec" ]; then
|
if [ -z "$exec" ]; then
|
||||||
exec @BINDIR@/lxc-unshare -s MOUNT -- $0 -n $name --exec "$@"
|
exec @BINDIR@/lxc-unshare -s MOUNT -- $0 -n $name --exec "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
lxc-info -n $name 2>&1 | grep -q 'STOPPED'
|
lxc-info -n $name 2>&1 | grep -q 'STOPPED'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "$(basename $0): container '$name' is not running" >&2
|
echo "$(basename $0): container '$name' is not running" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
get_parent_cgroup
|
get_parent_cgroup
|
||||||
if [ ! -d "$parent_cgroup" ]; then
|
if [ ! -d "$parent_cgroup" ]; then
|
||||||
echo "$(basename $0): no cgroup mount point found" >&2
|
echo "$(basename $0): no cgroup mount point found" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pid=$(head -1 $parent_cgroup/$name/tasks)
|
pid=$(head -1 $parent_cgroup/$name/tasks)
|
||||||
|
|
||||||
if [ -z "$pid" ]; then
|
if [ -z "$pid" ]; then
|
||||||
echo "$(basename $0): no process found for '$name'" >&2
|
echo "$(basename $0): no process found for '$name'" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tmpdir=$(mktemp -d)
|
tmpdir=$(mktemp -d)
|
||||||
|
|
||||||
if [ -z "$tmpdir" -o ! -d "$tmpdir" ]; then
|
if [ -z "$tmpdir" -o ! -d "$tmpdir" ]; then
|
||||||
echo "$(basename $0): unable to create temporary directory" >&2
|
echo "$(basename $0): unable to create temporary directory" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Bind mount /proc/$pid/net onto /proc/net before calling 'netstat'.
|
# Bind mount /proc/$pid/net onto /proc/net before calling 'netstat'.
|
||||||
|
@ -19,125 +19,124 @@
|
|||||||
|
|
||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
echo "usage: $(basename $0) [--lxc | --name NAME] [--] [PS_OPTIONS...]" >&2
|
echo "usage: $(basename $0) [--lxc | --name NAME] [--] [PS_OPTIONS...]" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
help() {
|
help() {
|
||||||
usage
|
usage
|
||||||
echo >&2
|
echo >&2
|
||||||
echo "List current processes with container names." >&2
|
echo "List current processes with container names." >&2
|
||||||
echo >&2
|
echo >&2
|
||||||
echo " --lxc show processes in all containers" >&2
|
echo " --lxc show processes in all containers" >&2
|
||||||
echo " --name NAME show processes in the specified container" >&2
|
echo " --name NAME show processes in the specified container" >&2
|
||||||
echo " (multiple containers can be separated by commas)" >&2
|
echo " (multiple containers can be separated by commas)" >&2
|
||||||
echo " PS_OPTIONS ps command options (see \`ps --help')" >&2
|
echo " PS_OPTIONS ps command options (see \`ps --help')" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
get_parent_cgroup()
|
get_parent_cgroup()
|
||||||
{
|
{
|
||||||
local hierarchies hierarchy fields subsystems init_cgroup mountpoint
|
local hierarchies hierarchy fields subsystems init_cgroup mountpoint
|
||||||
|
|
||||||
parent_cgroup=""
|
parent_cgroup=""
|
||||||
|
|
||||||
# Obtain a list of hierarchies that contain one or more subsystems
|
# Obtain a list of hierarchies that contain one or more subsystems
|
||||||
hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
|
hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
|
||||||
|
|
||||||
# Iterate through the list until a suitable hierarchy is found
|
# Iterate through the list until a suitable hierarchy is found
|
||||||
for hierarchy in $hierarchies; do
|
for hierarchy in $hierarchies; do
|
||||||
# Obtain information about the init process in the hierarchy
|
# Obtain information about the init process in the hierarchy
|
||||||
fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1)
|
fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1)
|
||||||
if [ -z "$fields" ]; then continue; fi
|
if [ -z "$fields" ]; then continue; fi
|
||||||
fields=${fields#*:}
|
fields=${fields#*:}
|
||||||
|
|
||||||
# Get a comma-separated list of the hierarchy's subsystems
|
# Get a comma-separated list of the hierarchy's subsystems
|
||||||
subsystems=${fields%:*}
|
subsystems=${fields%:*}
|
||||||
|
|
||||||
# Get the cgroup of the init process in the hierarchy
|
# Get the cgroup of the init process in the hierarchy
|
||||||
init_cgroup=${fields#*:}
|
init_cgroup=${fields#*:}
|
||||||
|
|
||||||
# Get the filesystem mountpoint of the hierarchy
|
# Get the filesystem mountpoint of the hierarchy
|
||||||
mountpoint=$(grep -E "^cgroup [^ ]+ [^ ]+ ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2)
|
mountpoint=$(grep -E "^cgroup [^ ]+ [^ ]+ ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2)
|
||||||
if [ -z "$mountpoint" ]; then continue; fi
|
if [ -z "$mountpoint" ]; then continue; fi
|
||||||
|
|
||||||
# Return the absolute path to the containers' parent cgroup
|
# Return the absolute path to the containers' parent cgroup
|
||||||
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
|
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
|
||||||
if [[ ",$subsystems," == *,ns,* ]]; then
|
if [[ ",$subsystems," == *,ns,* ]]; then
|
||||||
parent_cgroup="${mountpoint}${init_cgroup%/}"
|
parent_cgroup="${mountpoint}${init_cgroup%/}"
|
||||||
else
|
else
|
||||||
parent_cgroup="${mountpoint}${init_cgroup%/}/lxc"
|
parent_cgroup="${mountpoint}${init_cgroup%/}/lxc"
|
||||||
fi
|
fi
|
||||||
break
|
break
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
containers=""
|
containers=""
|
||||||
list_container_processes=0
|
list_container_processes=0
|
||||||
while true; do
|
while true; do
|
||||||
case $1 in
|
case $1 in
|
||||||
-h|--help)
|
-h|--help)
|
||||||
help; exit 1;;
|
help; exit 1;;
|
||||||
-n|--name)
|
-n|--name)
|
||||||
containers=$2; list_container_processes=1; shift 2;;
|
containers=$2; list_container_processes=1; shift 2;;
|
||||||
--lxc)
|
--lxc)
|
||||||
list_container_processes=1; shift;;
|
list_container_processes=1; shift;;
|
||||||
--)
|
--)
|
||||||
shift; break;;
|
shift; break;;
|
||||||
*)
|
*)
|
||||||
break;;
|
break;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$list_container_processes" -eq "1" ]; then
|
if [ "$list_container_processes" -eq "1" ]; then
|
||||||
set -- -e $@
|
set -- -e $@
|
||||||
fi
|
fi
|
||||||
|
|
||||||
get_parent_cgroup
|
get_parent_cgroup
|
||||||
if [ ! -d "$parent_cgroup" ]; then
|
if [ ! -d "$parent_cgroup" ]; then
|
||||||
echo "$(basename $0): no cgroup mount point found" >&2
|
echo "$(basename $0): no cgroup mount point found" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
declare -a container_of_pid
|
declare -a container_of_pid
|
||||||
container_field_width=9
|
container_field_width=9
|
||||||
IFS=","
|
IFS=","
|
||||||
if [ -z "$containers" ]; then
|
if [ -z "$containers" ]; then
|
||||||
containers=( $(find $parent_cgroup -mindepth 1 -maxdepth 1 -type d -printf "%f," 2>/dev/null) )
|
containers=( $(find $parent_cgroup -mindepth 1 -maxdepth 1 -type d -printf "%f," 2>/dev/null) )
|
||||||
else
|
else
|
||||||
containers=( $containers )
|
containers=( $containers )
|
||||||
fi
|
fi
|
||||||
|
|
||||||
declare -i pid
|
declare -i pid
|
||||||
IFS=$'\n'
|
IFS=$'\n'
|
||||||
for container in ${containers[@]}; do
|
for container in ${containers[@]}; do
|
||||||
if [ "${#container}" -gt "$container_field_width" ]; then
|
if [ "${#container}" -gt "$container_field_width" ]; then
|
||||||
container_field_width=${#container}
|
container_field_width=${#container}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f "$parent_cgroup/$container/tasks" ]; then
|
if [ -f "$parent_cgroup/$container/tasks" ]; then
|
||||||
while read pid; do
|
while read pid; do
|
||||||
container_of_pid[$pid]=$container
|
container_of_pid[$pid]=$container
|
||||||
done < "$parent_cgroup/$container/tasks"
|
done < "$parent_cgroup/$container/tasks"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
declare -i line_pid_end_position
|
declare -i line_pid_end_position
|
||||||
while read line; do
|
while read line; do
|
||||||
if [ -z "$line_pid_end_position" ]; then
|
if [ -z "$line_pid_end_position" ]; then
|
||||||
if [[ "$line" != *" PID"* ]]; then
|
if [[ "$line" != *" PID"* ]]; then
|
||||||
echo "$(basename $0): no PID column found in \`ps' output" >&2
|
echo "$(basename $0): no PID column found in \`ps' output" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
buffer=${line%" PID"*}
|
buffer=${line%" PID"*}
|
||||||
let line_pid_end_position=${#buffer}+4
|
let line_pid_end_position=${#buffer}+4
|
||||||
printf "%-${container_field_width}s %s\n" "CONTAINER" "$line"
|
printf "%-${container_field_width}s %s\n" "CONTAINER" "$line"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
buffer=${line:0:$line_pid_end_position}
|
buffer=${line:0:$line_pid_end_position}
|
||||||
pid=${buffer##* }
|
pid=${buffer##* }
|
||||||
if [ "$list_container_processes" -eq "0" -o ! -z "${container_of_pid[pid]}" ]; then
|
if [ "$list_container_processes" -eq "0" -o ! -z "${container_of_pid[pid]}" ]; then
|
||||||
printf "%-${container_field_width}s %s\n" "${container_of_pid[pid]}" "$line"
|
printf "%-${container_field_width}s %s\n" "${container_of_pid[pid]}" "$line"
|
||||||
fi
|
fi
|
||||||
done < <(ps "$@")
|
done < <(ps "$@")
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# lxc: linux Container library
|
# lxc: linux Container library
|
||||||
@ -81,35 +81,43 @@ lxc_dropcaps()
|
|||||||
chmod 0755 @LXCPATH@
|
chmod 0755 @LXCPATH@
|
||||||
}
|
}
|
||||||
|
|
||||||
shortoptions='hd'
|
usage_err() {
|
||||||
longoptions='help'
|
[ -n "$1" ] && echo "$1" >&2
|
||||||
|
|
||||||
getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@")
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
}
|
||||||
|
|
||||||
eval set -- "$getopt"
|
optarg_check() {
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
usage_err "option '$1' requires an argument"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
while true; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
opt="$1"
|
||||||
-d)
|
shift
|
||||||
LXC_DROP_CAPS="yes"
|
case "$opt" in
|
||||||
shift
|
-d)
|
||||||
;;
|
LXC_DROP_CAPS="yes"
|
||||||
-h|--help)
|
;;
|
||||||
help
|
-h|--help)
|
||||||
exit 0
|
help
|
||||||
;;
|
exit 0
|
||||||
--)
|
;;
|
||||||
shift
|
--)
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
*)
|
-?)
|
||||||
usage
|
usage_err "unknown option '$opt'"
|
||||||
exit 1
|
;;
|
||||||
;;
|
-*)
|
||||||
|
# split opts -abc into -a -b -c
|
||||||
|
set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done;
|
done;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# lxc: linux Container library
|
# lxc: linux Container library
|
||||||
@ -41,9 +41,9 @@ help() {
|
|||||||
setuid()
|
setuid()
|
||||||
{
|
{
|
||||||
if [ "$1" = "-r" ]; then
|
if [ "$1" = "-r" ]; then
|
||||||
chmod -s $2
|
chmod -s $2
|
||||||
else
|
else
|
||||||
chmod +s $1
|
chmod +s $1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,35 +78,43 @@ lxc_dropuid()
|
|||||||
chmod 0755 @LXCPATH@
|
chmod 0755 @LXCPATH@
|
||||||
}
|
}
|
||||||
|
|
||||||
shortoptions='hd'
|
usage_err() {
|
||||||
longoptions='help'
|
[ -n "$1" ] && echo "$1" >&2
|
||||||
|
|
||||||
getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@")
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
}
|
||||||
|
|
||||||
eval set -- "$getopt"
|
optarg_check() {
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
usage_err "option '$1' requires an argument"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
while true; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
opt="$1"
|
||||||
-d)
|
shift
|
||||||
LXC_DROP_CAPS="yes"
|
case "$opt" in
|
||||||
shift
|
-d)
|
||||||
;;
|
LXC_DROP_CAPS="yes"
|
||||||
-h|--help)
|
;;
|
||||||
help
|
-h|--help)
|
||||||
exit 0
|
help
|
||||||
;;
|
exit 0
|
||||||
--)
|
;;
|
||||||
shift
|
--)
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
*)
|
-?)
|
||||||
usage
|
usage_err "unknown option '$opt'"
|
||||||
exit 1
|
;;
|
||||||
;;
|
-*)
|
||||||
|
# split opts -abc into -a -b -c
|
||||||
|
set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done;
|
done;
|
||||||
|
|
||||||
|
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@"
|
echo "lxc version: @PACKAGE_VERSION@"
|
||||||
|
@ -84,6 +84,7 @@ extern int lxc_monitor_open(void);
|
|||||||
* data was readen, < 0 otherwise
|
* data was readen, < 0 otherwise
|
||||||
*/
|
*/
|
||||||
extern int lxc_monitor_read(int fd, struct lxc_msg *msg);
|
extern int lxc_monitor_read(int fd, struct lxc_msg *msg);
|
||||||
|
extern int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close the fd associated with the monitoring
|
* Close the fd associated with the monitoring
|
||||||
@ -178,6 +179,30 @@ extern int lxc_restart(const char *, int, struct lxc_conf *, int);
|
|||||||
*/
|
*/
|
||||||
extern const char const *lxc_version(void);
|
extern const char const *lxc_version(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create and return a new lxccontainer struct.
|
||||||
|
*/
|
||||||
|
extern struct lxc_container *lxc_container_new(const char *name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns 1 on success, 0 on failure.
|
||||||
|
*/
|
||||||
|
extern int lxc_container_get(struct lxc_container *c);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put a lxccontainer struct reference.
|
||||||
|
* Return -1 on error.
|
||||||
|
* Return 0 if this was not the last reference.
|
||||||
|
* If it is the last reference, free the lxccontainer and return 1.
|
||||||
|
*/
|
||||||
|
extern int lxc_container_put(struct lxc_container *c);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a list of valid wait states.
|
||||||
|
* If states is NULL, simply return the number of states
|
||||||
|
*/
|
||||||
|
extern int lxc_get_wait_states(const char **states);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -40,22 +40,30 @@
|
|||||||
#include "start.h"
|
#include "start.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "namespace.h"
|
||||||
|
|
||||||
lxc_log_define(lxc_attach_ui, lxc);
|
lxc_log_define(lxc_attach_ui, lxc);
|
||||||
|
|
||||||
static const struct option my_longopts[] = {
|
static const struct option my_longopts[] = {
|
||||||
{"elevated-privileges", no_argument, 0, 'e'},
|
{"elevated-privileges", no_argument, 0, 'e'},
|
||||||
{"arch", required_argument, 0, 'a'},
|
{"arch", required_argument, 0, 'a'},
|
||||||
|
{"namespaces", required_argument, 0, 's'},
|
||||||
|
{"remount-sys-proc", no_argument, 0, 'R'},
|
||||||
LXC_COMMON_OPTIONS
|
LXC_COMMON_OPTIONS
|
||||||
};
|
};
|
||||||
|
|
||||||
static int elevated_privileges = 0;
|
static int elevated_privileges = 0;
|
||||||
static signed long new_personality = -1;
|
static signed long new_personality = -1;
|
||||||
|
static int namespace_flags = -1;
|
||||||
|
static int remount_sys_proc = 0;
|
||||||
|
|
||||||
static int my_parser(struct lxc_arguments* args, int c, char* arg)
|
static int my_parser(struct lxc_arguments* args, int c, char* arg)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'e': elevated_privileges = 1; break;
|
case 'e': elevated_privileges = 1; break;
|
||||||
|
case 'R': remount_sys_proc = 1; break;
|
||||||
case 'a':
|
case 'a':
|
||||||
new_personality = lxc_config_parse_arch(arg);
|
new_personality = lxc_config_parse_arch(arg);
|
||||||
if (new_personality < 0) {
|
if (new_personality < 0) {
|
||||||
@ -63,6 +71,14 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 's':
|
||||||
|
namespace_flags = 0;
|
||||||
|
ret = lxc_fill_namespace_flags(arg, &namespace_flags);
|
||||||
|
if (ret)
|
||||||
|
return -1;
|
||||||
|
/* -s implies -e */
|
||||||
|
elevated_privileges = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -83,7 +99,18 @@ Options :\n\
|
|||||||
WARNING: This may leak privleges into the container.\n\
|
WARNING: This may leak privleges into the container.\n\
|
||||||
Use with care.\n\
|
Use with care.\n\
|
||||||
-a, --arch=ARCH Use ARCH for program instead of container's own\n\
|
-a, --arch=ARCH Use ARCH for program instead of container's own\n\
|
||||||
architecture.\n",
|
architecture.\n\
|
||||||
|
-s, --namespaces=FLAGS\n\
|
||||||
|
Don't attach to all the namespaces of the container\n\
|
||||||
|
but just to the following OR'd list of flags:\n\
|
||||||
|
MOUNT, PID, UTSNAME, IPC, USER or NETWORK\n\
|
||||||
|
WARNING: Using -s implies -e, it may therefore\n\
|
||||||
|
leak privileges into the container. Use with care.\n\
|
||||||
|
-R, --remount-sys-proc\n\
|
||||||
|
Remount /sys and /proc if not attaching to the\n\
|
||||||
|
mount namespace when using -s in order to properly\n\
|
||||||
|
reflect the correct namespace context. See the\n\
|
||||||
|
lxc-attach(1) manual page for details.\n",
|
||||||
.options = my_longopts,
|
.options = my_longopts,
|
||||||
.parser = my_parser,
|
.parser = my_parser,
|
||||||
.checker = NULL,
|
.checker = NULL,
|
||||||
@ -96,6 +123,7 @@ int main(int argc, char *argv[])
|
|||||||
struct passwd *passwd;
|
struct passwd *passwd;
|
||||||
struct lxc_proc_context_info *init_ctx;
|
struct lxc_proc_context_info *init_ctx;
|
||||||
struct lxc_handler *handler;
|
struct lxc_handler *handler;
|
||||||
|
void *cgroup_data = NULL;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
char *curdir;
|
char *curdir;
|
||||||
|
|
||||||
@ -124,6 +152,48 @@ int main(int argc, char *argv[])
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!elevated_privileges) {
|
||||||
|
/* we have to do this now since /sys/fs/cgroup may not
|
||||||
|
* be available inside the container or we may not have
|
||||||
|
* the required permissions anymore
|
||||||
|
*/
|
||||||
|
ret = lxc_cgroup_prepare_attach(my_args.name, &cgroup_data);
|
||||||
|
if (ret < 0) {
|
||||||
|
ERROR("failed to prepare attaching to cgroup");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
curdir = get_current_dir_name();
|
||||||
|
|
||||||
|
/* determine which namespaces the container was created with
|
||||||
|
* by asking lxc-start
|
||||||
|
*/
|
||||||
|
if (namespace_flags == -1) {
|
||||||
|
namespace_flags = lxc_get_clone_flags(my_args.name);
|
||||||
|
/* call failed */
|
||||||
|
if (namespace_flags == -1) {
|
||||||
|
ERROR("failed to automatically determine the "
|
||||||
|
"namespaces which the container unshared");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we need to attach before we fork since certain namespaces
|
||||||
|
* (such as pid namespaces) only really affect children of the
|
||||||
|
* current process and not the process itself
|
||||||
|
*/
|
||||||
|
ret = lxc_attach_to_ns(init_pid, namespace_flags);
|
||||||
|
if (ret < 0) {
|
||||||
|
ERROR("failed to enter the namespace");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curdir && chdir(curdir))
|
||||||
|
WARN("could not change directory to '%s'", curdir);
|
||||||
|
|
||||||
|
free(curdir);
|
||||||
|
|
||||||
/* hack: we need sync.h infrastructure - and that needs a handler */
|
/* hack: we need sync.h infrastructure - and that needs a handler */
|
||||||
handler = calloc(1, sizeof(*handler));
|
handler = calloc(1, sizeof(*handler));
|
||||||
|
|
||||||
@ -150,8 +220,22 @@ int main(int argc, char *argv[])
|
|||||||
if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE))
|
if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!elevated_privileges && lxc_cgroup_attach(my_args.name, pid))
|
/* now that we are done with all privileged operations,
|
||||||
return -1;
|
* we can add ourselves to the cgroup. Since we smuggled in
|
||||||
|
* the fds earlier, we still have write permission
|
||||||
|
*/
|
||||||
|
if (!elevated_privileges) {
|
||||||
|
/* since setns() for pid namespaces only really
|
||||||
|
* affects child processes, the pid we have is
|
||||||
|
* still valid outside the container, so this is
|
||||||
|
* fine
|
||||||
|
*/
|
||||||
|
ret = lxc_cgroup_finish_attach(cgroup_data, pid);
|
||||||
|
if (ret < 0) {
|
||||||
|
ERROR("failed to attach process to cgroup");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* tell the child we are done initializing */
|
/* tell the child we are done initializing */
|
||||||
if (lxc_sync_wake_child(handler, LXC_SYNC_POST_CONFIGURE))
|
if (lxc_sync_wake_child(handler, LXC_SYNC_POST_CONFIGURE))
|
||||||
@ -175,20 +259,20 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
lxc_sync_fini_parent(handler);
|
lxc_sync_fini_parent(handler);
|
||||||
|
lxc_cgroup_dispose_attach(cgroup_data);
|
||||||
|
|
||||||
curdir = get_current_dir_name();
|
/* A description of the purpose of this functionality is
|
||||||
|
* provided in the lxc-attach(1) manual page. We have to
|
||||||
ret = lxc_attach_to_ns(init_pid);
|
* remount here and not in the parent process, otherwise
|
||||||
if (ret < 0) {
|
* /proc may not properly reflect the new pid namespace.
|
||||||
ERROR("failed to enter the namespace");
|
*/
|
||||||
return -1;
|
if (!(namespace_flags & CLONE_NEWNS) && remount_sys_proc) {
|
||||||
|
ret = lxc_attach_remount_sys_proc();
|
||||||
|
if (ret < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curdir && chdir(curdir))
|
|
||||||
WARN("could not change directory to '%s'", curdir);
|
|
||||||
|
|
||||||
free(curdir);
|
|
||||||
|
|
||||||
if (new_personality < 0)
|
if (new_personality < 0)
|
||||||
new_personality = init_ctx->personality;
|
new_personality = init_ctx->personality;
|
||||||
|
|
||||||
|
@ -34,12 +34,14 @@
|
|||||||
|
|
||||||
static bool state;
|
static bool state;
|
||||||
static bool pid;
|
static bool pid;
|
||||||
|
static char *test_state = NULL;
|
||||||
|
|
||||||
static int my_parser(struct lxc_arguments* args, int c, char* arg)
|
static int my_parser(struct lxc_arguments* args, int c, char* arg)
|
||||||
{
|
{
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 's': state = true; break;
|
case 's': state = true; break;
|
||||||
case 'p': pid = true; break;
|
case 'p': pid = true; break;
|
||||||
|
case 't': test_state = arg; break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -47,6 +49,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
|
|||||||
static const struct option my_longopts[] = {
|
static const struct option my_longopts[] = {
|
||||||
{"state", no_argument, 0, 's'},
|
{"state", no_argument, 0, 's'},
|
||||||
{"pid", no_argument, 0, 'p'},
|
{"pid", no_argument, 0, 'p'},
|
||||||
|
{"state-is", required_argument, 0, 't'},
|
||||||
LXC_COMMON_OPTIONS,
|
LXC_COMMON_OPTIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,9 +61,11 @@ static struct lxc_arguments my_args = {
|
|||||||
lxc-info display some information about a container with the identifier NAME\n\
|
lxc-info display some information about a container with the identifier NAME\n\
|
||||||
\n\
|
\n\
|
||||||
Options :\n\
|
Options :\n\
|
||||||
-n, --name=NAME NAME for name of the container\n\
|
-n, --name=NAME NAME for name of the container\n\
|
||||||
-s, --state shows the state of the container\n\
|
-s, --state shows the state of the container\n\
|
||||||
-p, --pid shows the process id of the init container\n",
|
-p, --pid shows the process id of the init container\n\
|
||||||
|
-t, --state-is=STATE test if current state is STATE\n\
|
||||||
|
returns success if it matches, false otherwise\n",
|
||||||
.options = my_longopts,
|
.options = my_longopts,
|
||||||
.parser = my_parser,
|
.parser = my_parser,
|
||||||
.checker = NULL,
|
.checker = NULL,
|
||||||
@ -81,10 +86,12 @@ int main(int argc, char *argv[])
|
|||||||
if (!state && !pid)
|
if (!state && !pid)
|
||||||
state = pid = true;
|
state = pid = true;
|
||||||
|
|
||||||
if (state) {
|
if (state || test_state) {
|
||||||
ret = lxc_getstate(my_args.name);
|
ret = lxc_getstate(my_args.name);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
if (test_state)
|
||||||
|
return strcmp(lxc_state2str(ret), test_state) != 0;
|
||||||
|
|
||||||
printf("state:%10s\n", lxc_state2str(ret));
|
printf("state:%10s\n", lxc_state2str(ret));
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case lxc_msg_state:
|
case lxc_msg_state:
|
||||||
printf("'%s' changed state to [%s]\n",
|
printf("'%s' changed state to [%s]\n",
|
||||||
msg.name, lxc_state2str(msg.value));
|
msg.name, lxc_state2str(msg.value));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -62,6 +62,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
|
|||||||
case 'f': args->rcfile = arg; break;
|
case 'f': args->rcfile = arg; break;
|
||||||
case 'C': args->close_all_fds = 1; break;
|
case 'C': args->close_all_fds = 1; break;
|
||||||
case 's': return lxc_config_define_add(&defines, arg);
|
case 's': return lxc_config_define_add(&defines, arg);
|
||||||
|
case 'p': args->pidfile = arg; break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -72,6 +73,7 @@ static const struct option my_longopts[] = {
|
|||||||
{"define", required_argument, 0, 's'},
|
{"define", required_argument, 0, 's'},
|
||||||
{"console", required_argument, 0, 'c'},
|
{"console", required_argument, 0, 'c'},
|
||||||
{"close-all-fds", no_argument, 0, 'C'},
|
{"close-all-fds", no_argument, 0, 'C'},
|
||||||
|
{"pidfile", required_argument, 0, 'p'},
|
||||||
LXC_COMMON_OPTIONS
|
LXC_COMMON_OPTIONS
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,6 +87,7 @@ lxc-start start COMMAND in specified container NAME\n\
|
|||||||
Options :\n\
|
Options :\n\
|
||||||
-n, --name=NAME NAME for name of the container\n\
|
-n, --name=NAME NAME for name of the container\n\
|
||||||
-d, --daemon daemonize the container\n\
|
-d, --daemon daemonize the container\n\
|
||||||
|
-p, --pidfile=FILE Create a file with the process id\n\
|
||||||
-f, --rcfile=FILE Load configuration file FILE\n\
|
-f, --rcfile=FILE Load configuration file FILE\n\
|
||||||
-c, --console=FILE Set the file output for the container console\n\
|
-c, --console=FILE Set the file output for the container console\n\
|
||||||
-C, --close-all-fds If any fds are inherited, close them\n\
|
-C, --close-all-fds If any fds are inherited, close them\n\
|
||||||
@ -95,6 +98,7 @@ Options :\n\
|
|||||||
.parser = my_parser,
|
.parser = my_parser,
|
||||||
.checker = NULL,
|
.checker = NULL,
|
||||||
.daemonize = 0,
|
.daemonize = 0,
|
||||||
|
.pidfile = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@ -107,6 +111,7 @@ int main(int argc, char *argv[])
|
|||||||
"/sbin/init",
|
"/sbin/init",
|
||||||
'\0',
|
'\0',
|
||||||
};
|
};
|
||||||
|
FILE *pid_fp = NULL;
|
||||||
|
|
||||||
lxc_list_init(&defines);
|
lxc_list_init(&defines);
|
||||||
|
|
||||||
@ -117,7 +122,7 @@ int main(int argc, char *argv[])
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (!my_args.argc)
|
if (!my_args.argc)
|
||||||
args = default_args;
|
args = default_args;
|
||||||
else
|
else
|
||||||
args = my_args.argv;
|
args = my_args.argv;
|
||||||
|
|
||||||
@ -199,6 +204,15 @@ int main(int argc, char *argv[])
|
|||||||
free(console);
|
free(console);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (my_args.pidfile != NULL) {
|
||||||
|
pid_fp = fopen(my_args.pidfile, "w");
|
||||||
|
if (pid_fp == NULL) {
|
||||||
|
SYSERROR("failed to create pidfile '%s' for '%s'",
|
||||||
|
my_args.pidfile, my_args.name);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (my_args.daemonize) {
|
if (my_args.daemonize) {
|
||||||
/* do an early check for needed privs, since otherwise the
|
/* do an early check for needed privs, since otherwise the
|
||||||
* user won't see the error */
|
* user won't see the error */
|
||||||
@ -214,6 +228,14 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pid_fp != NULL) {
|
||||||
|
if (fprintf(pid_fp, "%d\n", getpid()) < 0) {
|
||||||
|
SYSERROR("failed to write '%s'", my_args.pidfile);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
fclose(pid_fp);
|
||||||
|
}
|
||||||
|
|
||||||
if (my_args.close_all_fds)
|
if (my_args.close_all_fds)
|
||||||
conf->close_all_fds = 1;
|
conf->close_all_fds = 1;
|
||||||
|
|
||||||
@ -230,6 +252,9 @@ int main(int argc, char *argv[])
|
|||||||
err = -1;
|
err = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (my_args.pidfile)
|
||||||
|
unlink(my_args.pidfile);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,51 +84,6 @@ static uid_t lookup_user(const char *optarg)
|
|||||||
return uid;
|
return uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *namespaces_list[] = {
|
|
||||||
"MOUNT", "PID", "UTSNAME", "IPC",
|
|
||||||
"USER", "NETWORK"
|
|
||||||
};
|
|
||||||
static int cloneflags_list[] = {
|
|
||||||
CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
|
|
||||||
CLONE_NEWUSER, CLONE_NEWNET
|
|
||||||
};
|
|
||||||
|
|
||||||
static int lxc_namespace_2_cloneflag(char *namespace)
|
|
||||||
{
|
|
||||||
int i, len;
|
|
||||||
len = sizeof(namespaces_list)/sizeof(namespaces_list[0]);
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
if (!strcmp(namespaces_list[i], namespace))
|
|
||||||
return cloneflags_list[i];
|
|
||||||
|
|
||||||
ERROR("invalid namespace name %s", namespace);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lxc_fill_namespace_flags(char *flaglist, int *flags)
|
|
||||||
{
|
|
||||||
char *token, *saveptr = NULL;
|
|
||||||
int aflag;
|
|
||||||
|
|
||||||
if (!flaglist) {
|
|
||||||
ERROR("need at least one namespace to unshare");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
token = strtok_r(flaglist, "|", &saveptr);
|
|
||||||
while (token) {
|
|
||||||
|
|
||||||
aflag = lxc_namespace_2_cloneflag(token);
|
|
||||||
if (aflag < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
*flags |= aflag;
|
|
||||||
|
|
||||||
token = strtok_r(NULL, "|", &saveptr);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct start_arg {
|
struct start_arg {
|
||||||
char ***args;
|
char ***args;
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <lxc/lxc.h>
|
#include <lxc/lxc.h>
|
||||||
@ -46,12 +48,14 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
|
|||||||
{
|
{
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 's': args->states = optarg; break;
|
case 's': args->states = optarg; break;
|
||||||
|
case 't': args->timeout = atol(optarg); break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct option my_longopts[] = {
|
static const struct option my_longopts[] = {
|
||||||
{"state", required_argument, 0, 's'},
|
{"state", required_argument, 0, 's'},
|
||||||
|
{"timeout", required_argument, 0, 't'},
|
||||||
LXC_COMMON_OPTIONS
|
LXC_COMMON_OPTIONS
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,37 +70,16 @@ Options :\n\
|
|||||||
-n, --name=NAME NAME for name of the container\n\
|
-n, --name=NAME NAME for name of the container\n\
|
||||||
-s, --state=STATE ORed states to wait for\n\
|
-s, --state=STATE ORed states to wait for\n\
|
||||||
STOPPED, STARTING, RUNNING, STOPPING,\n\
|
STOPPED, STARTING, RUNNING, STOPPING,\n\
|
||||||
ABORTING, FREEZING, FROZEN\n",
|
ABORTING, FREEZING, FROZEN\n\
|
||||||
|
-t, --timeout=TMO Seconds to wait for state changes\n",
|
||||||
.options = my_longopts,
|
.options = my_longopts,
|
||||||
.parser = my_parser,
|
.parser = my_parser,
|
||||||
.checker = my_checker,
|
.checker = my_checker,
|
||||||
|
.timeout = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int fillwaitedstates(char *strstates, int *states)
|
|
||||||
{
|
|
||||||
char *token, *saveptr = NULL;
|
|
||||||
int state;
|
|
||||||
|
|
||||||
token = strtok_r(strstates, "|", &saveptr);
|
|
||||||
while (token) {
|
|
||||||
|
|
||||||
state = lxc_str2state(token);
|
|
||||||
if (state < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
states[state] = 1;
|
|
||||||
|
|
||||||
token = strtok_r(NULL, "|", &saveptr);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct lxc_msg msg;
|
|
||||||
int s[MAX_STATE] = { }, fd;
|
|
||||||
int state, ret;
|
|
||||||
|
|
||||||
if (lxc_arguments_parse(&my_args, argc, argv))
|
if (lxc_arguments_parse(&my_args, argc, argv))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -104,53 +87,5 @@ int main(int argc, char *argv[])
|
|||||||
my_args.progname, my_args.quiet))
|
my_args.progname, my_args.quiet))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (fillwaitedstates(my_args.states, s))
|
return lxc_wait(strdup(my_args.name), my_args.states, my_args.timeout);
|
||||||
return -1;
|
|
||||||
|
|
||||||
fd = lxc_monitor_open();
|
|
||||||
if (fd < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if container present,
|
|
||||||
* then check if already in requested state
|
|
||||||
*/
|
|
||||||
ret = -1;
|
|
||||||
state = lxc_getstate(my_args.name);
|
|
||||||
if (state < 0) {
|
|
||||||
goto out_close;
|
|
||||||
} else if ((state >= 0) && (s[state])) {
|
|
||||||
ret = 0;
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
if (lxc_monitor_read(fd, &msg) < 0)
|
|
||||||
goto out_close;
|
|
||||||
|
|
||||||
if (strcmp(my_args.name, msg.name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (msg.type) {
|
|
||||||
case lxc_msg_state:
|
|
||||||
if (msg.value < 0 || msg.value >= MAX_STATE) {
|
|
||||||
ERROR("Receive an invalid state number '%d'",
|
|
||||||
msg.value);
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s[msg.value]) {
|
|
||||||
ret = 0;
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* just ignore garbage */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out_close:
|
|
||||||
lxc_monitor_close(fd);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
1001
src/lxc/lxccontainer.c
Normal file
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
|
/* If the handler returns a positive value, exit
|
||||||
the mainloop */
|
the mainloop */
|
||||||
if (handler->callback(handler->fd, handler->data,
|
if (handler->callback(handler->fd, handler->data,
|
||||||
descr) > 0)
|
descr) > 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ int lxc_mainloop(struct lxc_epoll_descr *descr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd,
|
int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd,
|
||||||
lxc_mainloop_callback_t callback, void *data)
|
lxc_mainloop_callback_t callback, void *data)
|
||||||
{
|
{
|
||||||
struct epoll_event ev;
|
struct epoll_event ev;
|
||||||
|
@ -28,13 +28,13 @@ struct lxc_epoll_descr {
|
|||||||
struct lxc_list handlers;
|
struct lxc_list handlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*lxc_mainloop_callback_t)(int fd, void *data,
|
typedef int (*lxc_mainloop_callback_t)(int fd, void *data,
|
||||||
struct lxc_epoll_descr *descr);
|
struct lxc_epoll_descr *descr);
|
||||||
|
|
||||||
extern int lxc_mainloop(struct lxc_epoll_descr *descr);
|
extern int lxc_mainloop(struct lxc_epoll_descr *descr);
|
||||||
|
|
||||||
extern int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd,
|
extern int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd,
|
||||||
lxc_mainloop_callback_t callback,
|
lxc_mainloop_callback_t callback,
|
||||||
void *data);
|
void *data);
|
||||||
|
|
||||||
extern int lxc_mainloop_del_handler(struct lxc_epoll_descr *descr, int fd);
|
extern int lxc_mainloop_del_handler(struct lxc_epoll_descr *descr, int fd);
|
||||||
|
@ -98,11 +98,28 @@ int lxc_monitor_open(void)
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lxc_monitor_read(int fd, struct lxc_msg *msg)
|
/* timeout of 0 means return immediately; -1 means wait forever */
|
||||||
|
int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout)
|
||||||
{
|
{
|
||||||
struct sockaddr_un from;
|
struct sockaddr_un from;
|
||||||
socklen_t len = sizeof(from);
|
socklen_t len = sizeof(from);
|
||||||
int ret;
|
int ret;
|
||||||
|
fd_set rfds;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
if (timeout != -1) {
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(fd, &rfds);
|
||||||
|
|
||||||
|
tv.tv_sec = timeout;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
ret = select(fd+1, &rfds, NULL, NULL, &tv);
|
||||||
|
if (ret == -1)
|
||||||
|
return -1;
|
||||||
|
else if (!ret)
|
||||||
|
return -2; // timed out
|
||||||
|
}
|
||||||
|
|
||||||
ret = recvfrom(fd, msg, sizeof(*msg), 0,
|
ret = recvfrom(fd, msg, sizeof(*msg), 0,
|
||||||
(struct sockaddr *)&from, &len);
|
(struct sockaddr *)&from, &len);
|
||||||
@ -114,6 +131,11 @@ int lxc_monitor_read(int fd, struct lxc_msg *msg)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lxc_monitor_read(int fd, struct lxc_msg *msg)
|
||||||
|
{
|
||||||
|
return lxc_monitor_read_timeout(fd, msg, -1);
|
||||||
|
}
|
||||||
|
|
||||||
int lxc_monitor_close(int fd)
|
int lxc_monitor_close(int fd)
|
||||||
{
|
{
|
||||||
return close(fd);
|
return close(fd);
|
||||||
|
@ -69,3 +69,48 @@ pid_t lxc_clone(int (*fn)(void *), void *arg, int flags)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *namespaces_list[] = {
|
||||||
|
"MOUNT", "PID", "UTSNAME", "IPC",
|
||||||
|
"USER", "NETWORK"
|
||||||
|
};
|
||||||
|
static int cloneflags_list[] = {
|
||||||
|
CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
|
||||||
|
CLONE_NEWUSER, CLONE_NEWNET
|
||||||
|
};
|
||||||
|
|
||||||
|
int lxc_namespace_2_cloneflag(char *namespace)
|
||||||
|
{
|
||||||
|
int i, len;
|
||||||
|
len = sizeof(namespaces_list)/sizeof(namespaces_list[0]);
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
if (!strcmp(namespaces_list[i], namespace))
|
||||||
|
return cloneflags_list[i];
|
||||||
|
|
||||||
|
ERROR("invalid namespace name %s", namespace);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lxc_fill_namespace_flags(char *flaglist, int *flags)
|
||||||
|
{
|
||||||
|
char *token, *saveptr = NULL;
|
||||||
|
int aflag;
|
||||||
|
|
||||||
|
if (!flaglist) {
|
||||||
|
ERROR("need at least one namespace to unshare");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok_r(flaglist, "|", &saveptr);
|
||||||
|
while (token) {
|
||||||
|
|
||||||
|
aflag = lxc_namespace_2_cloneflag(token);
|
||||||
|
if (aflag < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*flags |= aflag;
|
||||||
|
|
||||||
|
token = strtok_r(NULL, "|", &saveptr);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -54,4 +54,7 @@ int clone(int (*fn)(void *), void *child_stack,
|
|||||||
|
|
||||||
extern pid_t lxc_clone(int (*fn)(void *), void *arg, int flags);
|
extern pid_t lxc_clone(int (*fn)(void *), void *arg, int flags);
|
||||||
|
|
||||||
|
extern int lxc_namespace_2_cloneflag(char *namespace);
|
||||||
|
extern int lxc_fill_namespace_flags(char *flaglist, int *flags);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
|
|
||||||
#include "nl.h"
|
#include "nl.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
#include "conf.h"
|
||||||
|
|
||||||
#ifndef IFLA_LINKMODE
|
#ifndef IFLA_LINKMODE
|
||||||
# define IFLA_LINKMODE 17
|
# define IFLA_LINKMODE 17
|
||||||
@ -1004,3 +1005,18 @@ int lxc_bridge_attach(const char *bridge, const char *ifname)
|
|||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char* lxc_network_types[LXC_NET_MAXCONFTYPE + 1] = {
|
||||||
|
[LXC_NET_VETH] = "veth",
|
||||||
|
[LXC_NET_MACVLAN] = "macvlan",
|
||||||
|
[LXC_NET_VLAN] = "vlan",
|
||||||
|
[LXC_NET_PHYS] = "phys",
|
||||||
|
[LXC_NET_EMPTY] = "empty",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *lxc_net_type_to_str(int type)
|
||||||
|
{
|
||||||
|
if (type < 0 || type > LXC_NET_MAXCONFTYPE)
|
||||||
|
return NULL;
|
||||||
|
return lxc_network_types[type];
|
||||||
|
}
|
||||||
|
@ -100,7 +100,7 @@ extern int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw);
|
|||||||
*/
|
*/
|
||||||
extern int lxc_bridge_attach(const char *bridge, const char *ifname);
|
extern int lxc_bridge_attach(const char *bridge, const char *ifname);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create default gateway
|
* Create default gateway
|
||||||
*/
|
*/
|
||||||
extern int lxc_route_create_default(const char *addr, const char *ifname,
|
extern int lxc_route_create_default(const char *addr, const char *ifname,
|
||||||
@ -122,4 +122,5 @@ extern int lxc_neigh_proxy_on(const char *name, int family);
|
|||||||
*/
|
*/
|
||||||
extern int lxc_neigh_proxy_off(const char *name, int family);
|
extern int lxc_neigh_proxy_off(const char *name, int family);
|
||||||
|
|
||||||
|
extern const char *lxc_net_type_to_str(int type);
|
||||||
#endif
|
#endif
|
||||||
|
14
src/lxc/nl.c
14
src/lxc/nl.c
@ -48,7 +48,7 @@ extern void *nlmsg_data(struct nlmsg *nlmsg)
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nla_put(struct nlmsg *nlmsg, int attr,
|
static int nla_put(struct nlmsg *nlmsg, int attr,
|
||||||
const void *data, size_t len)
|
const void *data, size_t len)
|
||||||
{
|
{
|
||||||
struct rtattr *rta;
|
struct rtattr *rta;
|
||||||
@ -63,7 +63,7 @@ static int nla_put(struct nlmsg *nlmsg, int attr,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int nla_put_buffer(struct nlmsg *nlmsg, int attr,
|
extern int nla_put_buffer(struct nlmsg *nlmsg, int attr,
|
||||||
const void *data, size_t size)
|
const void *data, size_t size)
|
||||||
{
|
{
|
||||||
return nla_put(nlmsg, attr, data, size);
|
return nla_put(nlmsg, attr, data, size);
|
||||||
@ -193,7 +193,7 @@ extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg)
|
|||||||
#ifndef NLMSG_ERROR
|
#ifndef NLMSG_ERROR
|
||||||
#define NLMSG_ERROR 0x2
|
#define NLMSG_ERROR 0x2
|
||||||
#endif
|
#endif
|
||||||
extern int netlink_transaction(struct nl_handler *handler,
|
extern int netlink_transaction(struct nl_handler *handler,
|
||||||
struct nlmsg *request, struct nlmsg *answer)
|
struct nlmsg *request, struct nlmsg *answer)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -226,11 +226,11 @@ extern int netlink_open(struct nl_handler *handler, int protocol)
|
|||||||
if (handler->fd < 0)
|
if (handler->fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF,
|
if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF,
|
||||||
&sndbuf, sizeof(sndbuf)) < 0)
|
&sndbuf, sizeof(sndbuf)) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF,
|
if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF,
|
||||||
&rcvbuf,sizeof(rcvbuf)) < 0)
|
&rcvbuf,sizeof(rcvbuf)) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -238,12 +238,12 @@ extern int netlink_open(struct nl_handler *handler, int protocol)
|
|||||||
handler->local.nl_family = AF_NETLINK;
|
handler->local.nl_family = AF_NETLINK;
|
||||||
handler->local.nl_groups = 0;
|
handler->local.nl_groups = 0;
|
||||||
|
|
||||||
if (bind(handler->fd, (struct sockaddr*)&handler->local,
|
if (bind(handler->fd, (struct sockaddr*)&handler->local,
|
||||||
sizeof(handler->local)) < 0)
|
sizeof(handler->local)) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
socklen = sizeof(handler->local);
|
socklen = sizeof(handler->local);
|
||||||
if (getsockname(handler->fd, (struct sockaddr*)&handler->local,
|
if (getsockname(handler->fd, (struct sockaddr*)&handler->local,
|
||||||
&socklen) < 0)
|
&socklen) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
32
src/lxc/nl.h
32
src/lxc/nl.h
@ -39,7 +39,7 @@
|
|||||||
* struct nl_handler : the handler for netlink sockets, this structure
|
* struct nl_handler : the handler for netlink sockets, this structure
|
||||||
* is used all along the netlink socket life cycle to specify the
|
* is used all along the netlink socket life cycle to specify the
|
||||||
* netlink socket to be used.
|
* netlink socket to be used.
|
||||||
*
|
*
|
||||||
* @fd: the file descriptor of the netlink socket
|
* @fd: the file descriptor of the netlink socket
|
||||||
* @seq: the sequence number of the netlink messages
|
* @seq: the sequence number of the netlink messages
|
||||||
* @local: the bind address
|
* @local: the bind address
|
||||||
@ -77,7 +77,7 @@ struct nlmsg {
|
|||||||
int netlink_open(struct nl_handler *handler, int protocol);
|
int netlink_open(struct nl_handler *handler, int protocol);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* netlink_close : close a netlink socket, after this call,
|
* netlink_close : close a netlink socket, after this call,
|
||||||
* the handler is no longer valid
|
* the handler is no longer valid
|
||||||
*
|
*
|
||||||
* @handler: a handler to the netlink socket
|
* @handler: a handler to the netlink socket
|
||||||
@ -87,8 +87,8 @@ int netlink_open(struct nl_handler *handler, int protocol);
|
|||||||
int netlink_close(struct nl_handler *handler);
|
int netlink_close(struct nl_handler *handler);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* netlink_rcv : receive a netlink message from the kernel.
|
* netlink_rcv : receive a netlink message from the kernel.
|
||||||
* It is up to the caller to manage the allocation of the
|
* It is up to the caller to manage the allocation of the
|
||||||
* netlink message
|
* netlink message
|
||||||
*
|
*
|
||||||
* @handler: a handler to the netlink socket
|
* @handler: a handler to the netlink socket
|
||||||
@ -110,8 +110,8 @@ int netlink_rcv(struct nl_handler *handler, struct nlmsg *nlmsg);
|
|||||||
int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg);
|
int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* netlink_transaction: send a request to the kernel and read the response.
|
* netlink_transaction: send a request to the kernel and read the response.
|
||||||
* This is useful for transactional protocol. It is up to the caller
|
* This is useful for transactional protocol. It is up to the caller
|
||||||
* to manage the allocation of the netlink message.
|
* to manage the allocation of the netlink message.
|
||||||
*
|
*
|
||||||
* @handler: a handler to a opened netlink socket
|
* @handler: a handler to a opened netlink socket
|
||||||
@ -120,11 +120,11 @@ int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg);
|
|||||||
*
|
*
|
||||||
* Returns 0 on success, < 0 otherwise
|
* Returns 0 on success, < 0 otherwise
|
||||||
*/
|
*/
|
||||||
int netlink_transaction(struct nl_handler *handler,
|
int netlink_transaction(struct nl_handler *handler,
|
||||||
struct nlmsg *request, struct nlmsg *anwser);
|
struct nlmsg *request, struct nlmsg *anwser);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nla_put_string: copy a null terminated string to a netlink message
|
* nla_put_string: copy a null terminated string to a netlink message
|
||||||
* attribute
|
* attribute
|
||||||
*
|
*
|
||||||
* @nlmsg: the netlink message to be filled
|
* @nlmsg: the netlink message to be filled
|
||||||
@ -146,7 +146,7 @@ int nla_put_string(struct nlmsg *nlmsg, int attr, const char *string);
|
|||||||
*
|
*
|
||||||
* Returns 0 on success, < 0 otherwise
|
* Returns 0 on success, < 0 otherwise
|
||||||
*/
|
*/
|
||||||
int nla_put_buffer(struct nlmsg *nlmsg, int attr,
|
int nla_put_buffer(struct nlmsg *nlmsg, int attr,
|
||||||
const void *data, size_t size);
|
const void *data, size_t size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -172,7 +172,7 @@ int nla_put_u32(struct nlmsg *nlmsg, int attr, int value);
|
|||||||
int nla_put_u16(struct nlmsg *nlmsg, int attr, ushort value);
|
int nla_put_u16(struct nlmsg *nlmsg, int attr, ushort value);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nla_put_attr: add an attribute name to a netlink
|
* nla_put_attr: add an attribute name to a netlink
|
||||||
*
|
*
|
||||||
* @nlmsg: the netlink message to be filled
|
* @nlmsg: the netlink message to be filled
|
||||||
* @attr: the attribute name of the integer
|
* @attr: the attribute name of the integer
|
||||||
@ -185,7 +185,7 @@ int nla_put_attr(struct nlmsg *nlmsg, int attr);
|
|||||||
* nla_begin_nested: begin the nesting attribute
|
* nla_begin_nested: begin the nesting attribute
|
||||||
*
|
*
|
||||||
* @nlmsg: the netlink message to be filled
|
* @nlmsg: the netlink message to be filled
|
||||||
* @attr: the netsted attribute name
|
* @attr: the netsted attribute name
|
||||||
*
|
*
|
||||||
* Returns current nested pointer to be reused
|
* Returns current nested pointer to be reused
|
||||||
* to nla_end_nested.
|
* to nla_end_nested.
|
||||||
@ -198,17 +198,17 @@ struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr);
|
|||||||
* @nlmsg: the netlink message
|
* @nlmsg: the netlink message
|
||||||
* @nested: the nested pointer
|
* @nested: the nested pointer
|
||||||
*
|
*
|
||||||
* Returns the current
|
* Returns the current
|
||||||
*/
|
*/
|
||||||
void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr);
|
void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nlmsg_allocate : allocate a netlink message. The netlink format message
|
* nlmsg_allocate : allocate a netlink message. The netlink format message
|
||||||
* is a header, a padding, a payload and a padding again.
|
* is a header, a padding, a payload and a padding again.
|
||||||
* When a netlink message is allocated, the size specify the
|
* When a netlink message is allocated, the size specify the
|
||||||
* payload we want. So the real size of the allocated message
|
* payload we want. So the real size of the allocated message
|
||||||
* is sizeof(header) + sizeof(padding) + payloadsize + sizeof(padding),
|
* is sizeof(header) + sizeof(padding) + payloadsize + sizeof(padding),
|
||||||
* in other words, the function will allocate more than specified. When
|
* in other words, the function will allocate more than specified. When
|
||||||
* the buffer is allocated, the content is zeroed.
|
* the buffer is allocated, the content is zeroed.
|
||||||
* The function will also fill the field nlmsg_len with computed size.
|
* The function will also fill the field nlmsg_len with computed size.
|
||||||
* If the allocation must be for the specified size, just use malloc.
|
* If the allocation must be for the specified size, just use malloc.
|
||||||
@ -228,7 +228,7 @@ void nlmsg_free(struct nlmsg *nlmsg);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* nlmsg_data : returns a pointer to the data contained in the netlink message
|
* nlmsg_data : returns a pointer to the data contained in the netlink message
|
||||||
*
|
*
|
||||||
* @nlmsg : the netlink message to get the data
|
* @nlmsg : the netlink message to get the data
|
||||||
*
|
*
|
||||||
* Returns a pointer to the netlink data or NULL if there is no data
|
* Returns a pointer to the netlink data or NULL if there is no data
|
||||||
|
@ -53,7 +53,7 @@ extern int rtnetlink_send(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg)
|
|||||||
return netlink_send(&handler->nlh, (struct nlmsg *)&rtnlmsg->nlmsghdr);
|
return netlink_send(&handler->nlh, (struct nlmsg *)&rtnlmsg->nlmsghdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int rtnetlink_transaction(struct rtnl_handler *handler,
|
extern int rtnetlink_transaction(struct rtnl_handler *handler,
|
||||||
struct rtnlmsg *request, struct rtnlmsg *answer)
|
struct rtnlmsg *request, struct rtnlmsg *answer)
|
||||||
{
|
{
|
||||||
return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr,
|
return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr,
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
#define RTNLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + RTNL_HDRLEN))
|
#define RTNLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + RTNL_HDRLEN))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct genl_handler : the structure which store the netlink handler
|
* struct genl_handler : the structure which store the netlink handler
|
||||||
* and the family number
|
* and the family number
|
||||||
*
|
*
|
||||||
* @nlh: the netlink socket handler
|
* @nlh: the netlink socket handler
|
||||||
@ -105,6 +105,6 @@ void rtnlmsg_free(struct rtnlmsg *rtnlmsg);
|
|||||||
*
|
*
|
||||||
* Returns 0 on success, < 0 otherwise
|
* Returns 0 on success, < 0 otherwise
|
||||||
*/
|
*/
|
||||||
int rtnetlink_transaction(struct rtnl_handler *handler,
|
int rtnetlink_transaction(struct rtnl_handler *handler,
|
||||||
struct rtnlmsg *request, struct rtnlmsg *answer);
|
struct rtnlmsg *request, struct rtnlmsg *answer);
|
||||||
#endif
|
#endif
|
||||||
|
155
src/lxc/seccomp.c
Normal file
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 "sync.h"
|
||||||
#include "namespace.h"
|
#include "namespace.h"
|
||||||
#include "apparmor.h"
|
#include "apparmor.h"
|
||||||
|
#include "lxcseccomp.h"
|
||||||
|
|
||||||
lxc_log_define(lxc_start, lxc);
|
lxc_log_define(lxc_start, lxc);
|
||||||
|
|
||||||
@ -278,6 +279,29 @@ int lxc_pid_callback(int fd, struct lxc_request *request,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lxc_clone_flags_callback(int fd, struct lxc_request *request,
|
||||||
|
struct lxc_handler *handler)
|
||||||
|
{
|
||||||
|
struct lxc_answer answer;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
answer.pid = 0;
|
||||||
|
answer.ret = handler->clone_flags;
|
||||||
|
|
||||||
|
ret = send(fd, &answer, sizeof(answer), 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
WARN("failed to send answer to the peer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != sizeof(answer)) {
|
||||||
|
ERROR("partial answer sent");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int lxc_set_state(const char *name, struct lxc_handler *handler, lxc_state_t state)
|
int lxc_set_state(const char *name, struct lxc_handler *handler, lxc_state_t state)
|
||||||
{
|
{
|
||||||
handler->state = state;
|
handler->state = state;
|
||||||
@ -353,6 +377,11 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf)
|
|||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lxc_read_seccomp_config(conf) != 0) {
|
||||||
|
ERROR("failed loading seccomp policy");
|
||||||
|
goto out_free_name;
|
||||||
|
}
|
||||||
|
|
||||||
/* Begin the set the state to STARTING*/
|
/* Begin the set the state to STARTING*/
|
||||||
if (lxc_set_state(name, handler, STARTING)) {
|
if (lxc_set_state(name, handler, STARTING)) {
|
||||||
ERROR("failed to set state '%s'", lxc_state2str(STARTING));
|
ERROR("failed to set state '%s'", lxc_state2str(STARTING));
|
||||||
@ -530,6 +559,9 @@ static int do_start(void *data)
|
|||||||
if (apparmor_load(handler) < 0)
|
if (apparmor_load(handler) < 0)
|
||||||
goto out_warn_father;
|
goto out_warn_father;
|
||||||
|
|
||||||
|
if (lxc_seccomp_load(handler->conf) != 0)
|
||||||
|
goto out_warn_father;
|
||||||
|
|
||||||
if (run_lxc_hooks(handler->name, "start", handler->conf)) {
|
if (run_lxc_hooks(handler->name, "start", handler->conf)) {
|
||||||
ERROR("failed to run start hooks for container '%s'.", handler->name);
|
ERROR("failed to run start hooks for container '%s'.", handler->name);
|
||||||
goto out_warn_father;
|
goto out_warn_father;
|
||||||
@ -547,9 +579,39 @@ out_warn_father:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int save_phys_nics(struct lxc_conf *conf)
|
||||||
|
{
|
||||||
|
struct lxc_list *iterator;
|
||||||
|
|
||||||
|
lxc_list_for_each(iterator, &conf->network) {
|
||||||
|
struct lxc_netdev *netdev = iterator->elem;
|
||||||
|
|
||||||
|
if (netdev->type != LXC_NET_PHYS)
|
||||||
|
continue;
|
||||||
|
conf->saved_nics = realloc(conf->saved_nics,
|
||||||
|
(conf->num_savednics+1)*sizeof(struct saved_nic));
|
||||||
|
if (!conf->saved_nics) {
|
||||||
|
SYSERROR("failed to allocate memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
conf->saved_nics[conf->num_savednics].ifindex = netdev->ifindex;
|
||||||
|
conf->saved_nics[conf->num_savednics].orig_name = strdup(netdev->link);
|
||||||
|
if (!conf->saved_nics[conf->num_savednics].orig_name) {
|
||||||
|
SYSERROR("failed to allocate memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
INFO("stored saved_nic #%d idx %d name %s\n", conf->num_savednics,
|
||||||
|
conf->saved_nics[conf->num_savednics].ifindex,
|
||||||
|
conf->saved_nics[conf->num_savednics].orig_name);
|
||||||
|
conf->num_savednics++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int lxc_spawn(struct lxc_handler *handler)
|
int lxc_spawn(struct lxc_handler *handler)
|
||||||
{
|
{
|
||||||
int clone_flags;
|
|
||||||
int failed_before_rename = 0;
|
int failed_before_rename = 0;
|
||||||
const char *name = handler->name;
|
const char *name = handler->name;
|
||||||
int pinfd;
|
int pinfd;
|
||||||
@ -557,10 +619,10 @@ int lxc_spawn(struct lxc_handler *handler)
|
|||||||
if (lxc_sync_init(handler))
|
if (lxc_sync_init(handler))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS;
|
handler->clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS;
|
||||||
if (!lxc_list_empty(&handler->conf->network)) {
|
if (!lxc_list_empty(&handler->conf->network)) {
|
||||||
|
|
||||||
clone_flags |= CLONE_NEWNET;
|
handler->clone_flags |= CLONE_NEWNET;
|
||||||
|
|
||||||
/* Find gateway addresses from the link device, which is
|
/* Find gateway addresses from the link device, which is
|
||||||
* no longer accessible inside the container. Do this
|
* no longer accessible inside the container. Do this
|
||||||
@ -582,6 +644,11 @@ int lxc_spawn(struct lxc_handler *handler)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (save_phys_nics(handler->conf)) {
|
||||||
|
ERROR("failed to save physical nic info");
|
||||||
|
goto out_abort;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the rootfs is not a blockdev, prevent the container from
|
* if the rootfs is not a blockdev, prevent the container from
|
||||||
* marking it readonly.
|
* marking it readonly.
|
||||||
@ -594,7 +661,7 @@ int lxc_spawn(struct lxc_handler *handler)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Create a process in a new set of namespaces */
|
/* Create a process in a new set of namespaces */
|
||||||
handler->pid = lxc_clone(do_start, handler, clone_flags);
|
handler->pid = lxc_clone(do_start, handler, handler->clone_flags);
|
||||||
if (handler->pid < 0) {
|
if (handler->pid < 0) {
|
||||||
SYSERROR("failed to fork into a new namespace");
|
SYSERROR("failed to fork into a new namespace");
|
||||||
goto out_delete_net;
|
goto out_delete_net;
|
||||||
@ -612,7 +679,7 @@ int lxc_spawn(struct lxc_handler *handler)
|
|||||||
goto out_delete_net;
|
goto out_delete_net;
|
||||||
|
|
||||||
/* Create the network configuration */
|
/* Create the network configuration */
|
||||||
if (clone_flags & CLONE_NEWNET) {
|
if (handler->clone_flags & CLONE_NEWNET) {
|
||||||
if (lxc_assign_network(&handler->conf->network, handler->pid)) {
|
if (lxc_assign_network(&handler->conf->network, handler->pid)) {
|
||||||
ERROR("failed to create the configured network");
|
ERROR("failed to create the configured network");
|
||||||
goto out_delete_net;
|
goto out_delete_net;
|
||||||
@ -642,8 +709,8 @@ int lxc_spawn(struct lxc_handler *handler)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_delete_net:
|
out_delete_net:
|
||||||
if (clone_flags & CLONE_NEWNET)
|
if (handler->clone_flags & CLONE_NEWNET)
|
||||||
lxc_delete_network(&handler->conf->network);
|
lxc_delete_network(handler);
|
||||||
out_abort:
|
out_abort:
|
||||||
lxc_abort(name, handler);
|
lxc_abort(name, handler);
|
||||||
lxc_sync_fini(handler);
|
lxc_sync_fini(handler);
|
||||||
@ -675,7 +742,7 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
|
|||||||
err = lxc_spawn(handler);
|
err = lxc_spawn(handler);
|
||||||
if (err) {
|
if (err) {
|
||||||
ERROR("failed to spawn '%s'", name);
|
ERROR("failed to spawn '%s'", name);
|
||||||
goto out_fini;
|
goto out_fini_nonet;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = lxc_poll(name, handler);
|
err = lxc_poll(name, handler);
|
||||||
@ -708,8 +775,13 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lxc_rename_phys_nics_on_shutdown(handler->conf);
|
||||||
|
|
||||||
err = lxc_error_set_and_log(handler->pid, status);
|
err = lxc_error_set_and_log(handler->pid, status);
|
||||||
out_fini:
|
out_fini:
|
||||||
|
lxc_delete_network(handler);
|
||||||
|
|
||||||
|
out_fini_nonet:
|
||||||
lxc_cgroup_destroy(name);
|
lxc_cgroup_destroy(name);
|
||||||
lxc_fini(name, handler);
|
lxc_fini(name, handler);
|
||||||
return err;
|
return err;
|
||||||
|
@ -39,6 +39,7 @@ struct lxc_handler {
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
char *name;
|
char *name;
|
||||||
lxc_state_t state;
|
lxc_state_t state;
|
||||||
|
int clone_flags;
|
||||||
int sigfd;
|
int sigfd;
|
||||||
sigset_t oldmask;
|
sigset_t oldmask;
|
||||||
struct lxc_conf *conf;
|
struct lxc_conf *conf;
|
||||||
|
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
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -31,9 +32,11 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
|
|
||||||
|
#include <lxc/lxc.h>
|
||||||
#include <lxc/log.h>
|
#include <lxc/log.h>
|
||||||
#include <lxc/start.h>
|
#include <lxc/start.h>
|
||||||
#include <lxc/cgroup.h>
|
#include <lxc/cgroup.h>
|
||||||
|
#include <lxc/monitor.h>
|
||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@ -162,3 +165,115 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fillwaitedstates(const char *strstates, int *states)
|
||||||
|
{
|
||||||
|
char *token, *saveptr = NULL;
|
||||||
|
char *strstates_dup = strdup(strstates);
|
||||||
|
int state;
|
||||||
|
|
||||||
|
if (!strstates_dup)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
token = strtok_r(strstates_dup, "|", &saveptr);
|
||||||
|
while (token) {
|
||||||
|
|
||||||
|
state = lxc_str2state(token);
|
||||||
|
if (state < 0) {
|
||||||
|
free(strstates_dup);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
states[state] = 1;
|
||||||
|
|
||||||
|
token = strtok_r(NULL, "|", &saveptr);
|
||||||
|
}
|
||||||
|
free(strstates_dup);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int lxc_wait(const char *lxcname, const char *states, int timeout)
|
||||||
|
{
|
||||||
|
struct lxc_msg msg;
|
||||||
|
int state, ret;
|
||||||
|
int s[MAX_STATE] = { }, fd;
|
||||||
|
|
||||||
|
if (fillwaitedstates(states, s))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fd = lxc_monitor_open();
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if container present,
|
||||||
|
* then check if already in requested state
|
||||||
|
*/
|
||||||
|
ret = -1;
|
||||||
|
state = lxc_getstate(lxcname);
|
||||||
|
if (state < 0) {
|
||||||
|
goto out_close;
|
||||||
|
} else if ((state >= 0) && (s[state])) {
|
||||||
|
ret = 0;
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int elapsed_time, curtime = 0;
|
||||||
|
struct timeval tv;
|
||||||
|
int stop = 0;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (timeout != -1) {
|
||||||
|
retval = gettimeofday(&tv, NULL);
|
||||||
|
if (retval)
|
||||||
|
goto out_close;
|
||||||
|
curtime = tv.tv_sec;
|
||||||
|
}
|
||||||
|
if (lxc_monitor_read_timeout(fd, &msg, timeout) < 0)
|
||||||
|
goto out_close;
|
||||||
|
|
||||||
|
if (timeout != -1) {
|
||||||
|
retval = gettimeofday(&tv, NULL);
|
||||||
|
if (retval)
|
||||||
|
goto out_close;
|
||||||
|
elapsed_time = tv.tv_sec - curtime;
|
||||||
|
if (timeout - elapsed_time <= 0)
|
||||||
|
stop = 1;
|
||||||
|
timeout -= elapsed_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(lxcname, msg.name)) {
|
||||||
|
if (stop) {
|
||||||
|
ret = -2;
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (msg.type) {
|
||||||
|
case lxc_msg_state:
|
||||||
|
if (msg.value < 0 || msg.value >= MAX_STATE) {
|
||||||
|
ERROR("Receive an invalid state number '%d'",
|
||||||
|
msg.value);
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s[msg.value]) {
|
||||||
|
ret = 0;
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (stop) {
|
||||||
|
ret = -2;
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
/* just ignore garbage */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out_close:
|
||||||
|
lxc_monitor_close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user