mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-27 11:13:50 +00:00
Merge git://github.com/lxc/lxc
Signed-off-by: Daniel Lezcano <daniel.lezcano@free.fr>
This commit is contained in:
commit
be9f766c1e
12
.gitignore
vendored
12
.gitignore
vendored
@ -28,6 +28,7 @@ templates/lxc-alpine
|
||||
templates/lxc-altlinux
|
||||
templates/lxc-archlinux
|
||||
templates/lxc-busybox
|
||||
templates/lxc-cirros
|
||||
templates/lxc-debian
|
||||
templates/lxc-fedora
|
||||
templates/lxc-opensuse
|
||||
@ -43,6 +44,7 @@ src/lxc/lxc-checkconfig
|
||||
src/lxc/lxc-checkpoint
|
||||
src/lxc/lxc-clone
|
||||
src/lxc/lxc-console
|
||||
src/lxc/lxc-config
|
||||
src/lxc/lxc-create
|
||||
src/lxc/lxc-destroy
|
||||
src/lxc/lxc-execute
|
||||
@ -52,6 +54,7 @@ src/lxc/lxc-info
|
||||
src/lxc/lxc-init
|
||||
src/lxc/lxc-kill
|
||||
src/lxc/lxc-monitor
|
||||
src/lxc/lxc-monitord
|
||||
src/lxc/lxc-netstat
|
||||
src/lxc/lxc-ps
|
||||
src/lxc/lxc-restart
|
||||
@ -64,20 +67,25 @@ src/lxc/lxc-unshare
|
||||
src/lxc/lxc-version
|
||||
src/lxc/lxc-wait
|
||||
src/lxc/legacy/lxc-ls
|
||||
src/lxc/lxc-user-nic
|
||||
|
||||
src/python-lxc/build/
|
||||
src/python-lxc/lxc/__pycache__/
|
||||
|
||||
src/tests/lxc-test-cgpath
|
||||
src/tests/lxc-test-clonetest
|
||||
src/tests/lxc-test-console
|
||||
src/tests/lxc-test-containertests
|
||||
src/tests/lxc-test-createtest
|
||||
src/tests/lxc-test-destroytest
|
||||
src/tests/lxc-test-get_item
|
||||
src/tests/lxc-test-getkeys
|
||||
src/tests/lxc-test-locktests
|
||||
src/tests/lxc-test-lxcpath
|
||||
src/tests/lxc-test-saveconfig
|
||||
src/tests/lxc-test-shutdowntest
|
||||
src/tests/lxc-test-startone
|
||||
|
||||
src/tests/lxc-usernic-test
|
||||
|
||||
config/compile
|
||||
config/config.guess
|
||||
@ -104,3 +112,5 @@ src/stamp-h1
|
||||
|
||||
.pc
|
||||
patches
|
||||
*.orig
|
||||
*.rej
|
||||
|
24
CONTRIBUTING
24
CONTRIBUTING
@ -40,6 +40,30 @@ You can submit your patches to the lxc-devel@lists.sourceforge.net mailing
|
||||
list. Use https://lists.sourceforge.net/lists/listinfo/lxc-devel to subscribe
|
||||
to the list.
|
||||
|
||||
|
||||
Licensing for new files:
|
||||
------------------------
|
||||
|
||||
LXC is made of files shipped under a few different licenses.
|
||||
|
||||
Anything that ends up being part of the LXC library needs to be released
|
||||
under LGPLv2.1+ or a license compatible with it (though the latter will
|
||||
only be accepted for cases where the code originated elsewhere and was
|
||||
imported into LXC).
|
||||
|
||||
Language bindings for the libraries need to be released under LGPLv2.1+.
|
||||
|
||||
Anything else (non-libaries) needs to be Free Software and needs to be
|
||||
allowed to link with LGPLv2.1+ code (if needed). LXC upstream prefers
|
||||
LGPLv2.1+ or GPLv2 for those.
|
||||
|
||||
|
||||
When introducing a new file into the project, please make sure it has a
|
||||
copyright header making clear under which license it's being released
|
||||
and if it doesn't match the criteria described above, please explain
|
||||
your decision on the lxc-devel mailing-list when submitting your patch.
|
||||
|
||||
|
||||
Developer Certificate of Origin:
|
||||
--------------------------------
|
||||
|
||||
|
21
autogen.sh
21
autogen.sh
@ -1,4 +1,25 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# lxc: linux Container library
|
||||
#
|
||||
# (C) Copyright IBM Corp. 2007, 2008
|
||||
#
|
||||
# Authors:
|
||||
# Daniel Lezcano <daniel.lezcano at free.fr>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
set -x
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
configdir = $(sysconfdir)/lxc
|
||||
config_DATA = default.conf
|
||||
defaultconf = @LXC_DEFAULT_CONF@
|
||||
distroconf = @LXC_DISTRO_CONF@
|
||||
|
||||
EXTRA_DIST = default.conf.ubuntu default.conf.libvirt default.conf.unknown
|
||||
|
||||
default.conf:
|
||||
cp $(defaultconf) $@
|
||||
cp $(distroconf) $@
|
||||
|
||||
clean-local:
|
||||
@$(RM) -f default.conf
|
||||
|
125
configure.ac
125
configure.ac
@ -6,7 +6,7 @@ AC_INIT([lxc], [0.9.0])
|
||||
AC_CONFIG_SRCDIR([configure.ac])
|
||||
AC_CONFIG_AUX_DIR([config])
|
||||
AC_CONFIG_HEADERS([src/config.h])
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror -Wno-portability])
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror -Wno-portability subdir-objects])
|
||||
AC_CANONICAL_HOST
|
||||
AM_PROG_CC_C_O
|
||||
AC_GNU_SOURCE
|
||||
@ -39,19 +39,22 @@ if test "z$with_distro" = "z"; then
|
||||
fi
|
||||
case $with_distro in
|
||||
ubuntu)
|
||||
defaultconf=default.conf.ubuntu
|
||||
distroconf=default.conf.ubuntu
|
||||
;;
|
||||
redhat|fedora|oracle|oracleserver)
|
||||
defaultconf=default.conf.libvirt
|
||||
distroconf=default.conf.libvirt
|
||||
;;
|
||||
*)
|
||||
echo -n "Linux distribution network config unknown, defaulting to lxc.network.type = empty"
|
||||
defaultconf=default.conf.unknown
|
||||
distroconf=default.conf.unknown
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([$with_distro])
|
||||
AM_CONDITIONAL([HAVE_DEBIAN], [test x"$with_distro" = "xdebian" -o x"$with_distro" = "xubuntu"])
|
||||
|
||||
AC_CHECK_PROG([NEWUIDMAP], [newuidmap], [newuidmap])
|
||||
AM_CONDITIONAL([HAVE_NEWUIDMAP], [test -n "$NEWUIDMAP"])
|
||||
|
||||
# Allow disabling rpath
|
||||
AC_ARG_ENABLE([rpath],
|
||||
[AC_HELP_STRING([--disable-rpath], [do not set rpath in executables])],
|
||||
@ -60,14 +63,15 @@ AM_CONDITIONAL([ENABLE_RPATH], [test "x$enable_rpath" = "xyes"])
|
||||
|
||||
# Documentation (manpages)
|
||||
AC_ARG_ENABLE([doc],
|
||||
[AC_HELP_STRING([--enable-doc], [make mans (require docbook2x-man installed) [default=auto]])],
|
||||
[AC_HELP_STRING([--enable-doc], [make mans (requires docbook2man or docbook2x-man to be installed) [default=auto]])],
|
||||
[], [enable_doc=auto])
|
||||
|
||||
if test "x$enable_doc" = "xyes" -o "x$enable_doc" = "xauto"; then
|
||||
db2xman=""
|
||||
dbparsers="docbook2x-man db2x_docbook2man docbook2man"
|
||||
|
||||
AC_MSG_CHECKING(for docbook2x-man)
|
||||
for name in docbook2x-man db2x_docbook2man; do
|
||||
for name in ${dbparsers}; do
|
||||
if "$name" --help >/dev/null 2>&1; then
|
||||
db2xman="$name"
|
||||
break;
|
||||
@ -87,6 +91,13 @@ if test "x$enable_doc" = "xyes" -o "x$enable_doc" = "xauto"; then
|
||||
fi
|
||||
AM_CONDITIONAL([ENABLE_DOCBOOK], [test "x$db2xman" != "x"])
|
||||
|
||||
if test "x$db2xman" = "xdocbook2man"; then
|
||||
docdtd="\"-//Davenport//DTD DocBook V3.0//EN\""
|
||||
else
|
||||
docdtd="\"-//OASIS//DTD DocBook XML\" \"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd\""
|
||||
fi
|
||||
AC_SUBST(docdtd)
|
||||
|
||||
# Apparmor
|
||||
AC_ARG_ENABLE([apparmor],
|
||||
[AC_HELP_STRING([--enable-apparmor], [enable apparmor])],
|
||||
@ -97,6 +108,8 @@ if test "$enable_apparmor" = "check" ; then
|
||||
fi
|
||||
AM_CONDITIONAL([ENABLE_APPARMOR], [test "x$enable_apparmor" = "xyes"])
|
||||
|
||||
AC_CHECK_LIB([gnutls], [gnutls_hash_fast])
|
||||
|
||||
AM_COND_IF([ENABLE_APPARMOR],
|
||||
[AC_CHECK_HEADER([sys/apparmor.h],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
|
||||
AC_CHECK_LIB([apparmor], [aa_change_profile],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
|
||||
@ -137,22 +150,75 @@ AM_COND_IF([ENABLE_PYTHON],
|
||||
PKG_CHECK_MODULES([PYTHONDEV], [python3 >= 3.2],[],[AC_MSG_ERROR([You must install python3-dev])])
|
||||
AC_DEFINE_UNQUOTED([ENABLE_PYTHON], 1, [Python3 is available])])
|
||||
|
||||
# Lua module and scripts
|
||||
if test x"$with_distro" = "xdebian" -o x"$with_distro" = "xubuntu" ; then
|
||||
LUAPKGCONFIG=lua5.1
|
||||
else
|
||||
LUAPKGCONFIG=lua
|
||||
fi
|
||||
# Not in older autoconf versions
|
||||
# AS_VAR_COPY(DEST, SOURCE)
|
||||
# -------------------------
|
||||
# Set the polymorphic shell variable DEST to the contents of the polymorphic
|
||||
# shell variable SOURCE.
|
||||
m4_ifdef([AS_VAR_COPY], [],
|
||||
[AC_DEFUN([AS_VAR_COPY],
|
||||
[AS_LITERAL_IF([$1[]$2], [$1=$$2], [eval $1=\$$2])])
|
||||
])
|
||||
|
||||
dnl PKG_CHECK_VAR was introduced with pkg-config 0.28
|
||||
m4_ifdef([PKG_CHECK_VAR], [],
|
||||
[AC_DEFUN([PKG_CHECK_VAR],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
|
||||
_PKG_CONFIG([$1], [variable="][$3]["], [$2])
|
||||
AS_VAR_COPY([$1], [pkg_cv_][$1])
|
||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
||||
])# PKG_CHECK_VAR
|
||||
])
|
||||
|
||||
# Lua module and scripts
|
||||
AC_ARG_ENABLE([lua],
|
||||
[AC_HELP_STRING([--enable-lua], [enable lua binding])],
|
||||
[enable_lua=yes], [enable_lua=no])
|
||||
[], [enable_lua=check])
|
||||
|
||||
AM_CONDITIONAL([ENABLE_LUA], [test "x$enable_lua" = "xyes"])
|
||||
AC_ARG_WITH([lua-pc],
|
||||
[AS_HELP_STRING(
|
||||
[--with-lua-pc=PKG],
|
||||
[Specify pkg-config package name for lua]
|
||||
)], [], [with_lua_pc=no])
|
||||
|
||||
if test "x$enable_lua" = "xyes" -a "x$with_lua_pc" != "xno"; then
|
||||
# exit with error if not found
|
||||
PKG_CHECK_MODULES([LUA], [$with_lua_pc], [LUAPKGCONFIG=$with_lua_pc])
|
||||
fi
|
||||
|
||||
if test "x$enable_lua" = "xcheck" -a "x$with_lua_pc" != "xno"; then
|
||||
PKG_CHECK_MODULES([LUA], [$with_lua_pc],
|
||||
[LUAPKGCONFIG=$with_lua_pc
|
||||
enable_lua=yes],
|
||||
[enable_lua=no])
|
||||
fi
|
||||
|
||||
if test "x$enable_lua" != "xno"; then
|
||||
PKG_CHECK_MODULES([LUA], [lua], [LUAPKGCONFIG=lua],
|
||||
[PKG_CHECK_MODULES([LUA], [lua5.2], [LUAPKGCONFIG=lua5.2],
|
||||
[PKG_CHECK_MODULES([LUA], [lua5.1], [LUAPKGCONFIG=lua5.1],
|
||||
[AS_IF([test "x$enable_lua" = "xyes"],
|
||||
[AC_MSG_ERROR([Lua not found. Please use --with-lua-pc=PKG])],
|
||||
[enable_lua=no])]
|
||||
)]
|
||||
)])
|
||||
AS_IF([test "x$LUAPKGCONFIG" != "x"], [enable_lua=yes])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_LUA],
|
||||
[test "x$enable_lua" = "xyes"])
|
||||
|
||||
AM_COND_IF([ENABLE_LUA],
|
||||
[PKG_CHECK_MODULES([LUA], [$LUAPKGCONFIG >= 5.1],[],[AC_MSG_ERROR([You must install lua-devel for lua 5.1])])
|
||||
AC_DEFINE_UNQUOTED([ENABLE_LUA], 1, [Lua is available])])
|
||||
[AC_MSG_CHECKING([Lua version])
|
||||
PKG_CHECK_VAR([LUA_VERSION], [$LUAPKGCONFIG], [V],,
|
||||
[PKG_CHECK_VAR([LUA_VERSION], [$LUAPKGCONFIG], [major_version])])
|
||||
AC_MSG_RESULT([$LUA_VERSION])
|
||||
PKG_CHECK_VAR([LUA_INSTALL_CMOD], [$LUAPKGCONFIG], [INSTALL_CMOD],,
|
||||
[LUA_INSTALL_CMOD=$libdir/lua/$LUA_VERSION])
|
||||
PKG_CHECK_VAR([LUA_INSTALL_LMOD], [$LUAPKGCONFIG], [INSTALL_LMOD],,
|
||||
[LUA_INSTALL_LMOD=$datadir/lua/$LUA_VERSION])
|
||||
])
|
||||
|
||||
# Optional test binaries
|
||||
AC_ARG_ENABLE([tests],
|
||||
@ -176,6 +242,18 @@ AC_ARG_WITH([global-conf],
|
||||
[global lxc configuration file]
|
||||
)], [], [with_global_conf=['${sysconfdir}/lxc/lxc.conf']])
|
||||
|
||||
AC_ARG_WITH([usernic-conf],
|
||||
[AC_HELP_STRING(
|
||||
[--with-usernic-conf],
|
||||
[user network interface configuration file]
|
||||
)], [], [with_usernic_conf=['${sysconfdir}/lxc/lxc-usernet']])
|
||||
|
||||
AC_ARG_WITH([usernic-db],
|
||||
[AC_HELP_STRING(
|
||||
[--with-usernic-db],
|
||||
[lxc user nic database]
|
||||
)], [], [with_usernic_db=['/run/lxc/nics']])
|
||||
|
||||
# Rootfs path, where the container mount structure is assembled
|
||||
AC_ARG_WITH([rootfs-path],
|
||||
[AC_HELP_STRING(
|
||||
@ -210,13 +288,16 @@ AS_AC_EXPAND(BINDIR, "$bindir")
|
||||
AS_AC_EXPAND(LIBEXECDIR, "$libexecdir")
|
||||
AS_AC_EXPAND(INCLUDEDIR, "$includedir")
|
||||
AS_AC_EXPAND(SYSCONFDIR, "$sysconfdir")
|
||||
AS_AC_EXPAND(LXC_DEFAULT_CONFIG, "$sysconfdir/lxc/default.conf")
|
||||
AS_AC_EXPAND(DATADIR, "$datadir")
|
||||
AS_AC_EXPAND(LOCALSTATEDIR, "$localstatedir")
|
||||
AS_AC_EXPAND(DOCDIR, "$docdir")
|
||||
AS_AC_EXPAND(LXC_DEFAULT_CONF, "$defaultconf")
|
||||
AS_AC_EXPAND(LXC_DISTRO_CONF, "$distroconf")
|
||||
AS_AC_EXPAND(LXC_GENERATE_DATE, "$(date)")
|
||||
AS_AC_EXPAND(LXCPATH, "$with_config_path")
|
||||
AS_AC_EXPAND(LXC_GLOBAL_CONF, "$with_global_conf")
|
||||
AS_AC_EXPAND(LXC_USERNIC_CONF, "$with_usernic_conf")
|
||||
AS_AC_EXPAND(LXC_USERNIC_DB, "$with_usernic_db")
|
||||
AS_AC_EXPAND(LXCROOTFSMOUNT, "$with_rootfs_path")
|
||||
AS_AC_EXPAND(LXCTEMPLATEDIR, "$datadir/lxc/templates")
|
||||
AS_AC_EXPAND(LXCHOOKDIR, "$datadir/lxc/hooks")
|
||||
@ -270,10 +351,10 @@ AM_CONDITIONAL([IS_BIONIC], [test "x$is_bionic" = "xyes"])
|
||||
AC_CHECK_DECLS([PR_CAPBSET_DROP], [], [], [#include <sys/prctl.h>])
|
||||
|
||||
# Check for some headers
|
||||
AC_CHECK_HEADERS([sys/signalfd.h pty.h sys/capability.h sys/personality.h utmpx.h sys/timerfd.h])
|
||||
AC_CHECK_HEADERS([sys/signalfd.h pty.h ifaddrs.h sys/capability.h sys/personality.h utmpx.h sys/timerfd.h])
|
||||
|
||||
# Check for some syscalls functions
|
||||
AC_CHECK_FUNCS([setns pivot_root sethostname unshare])
|
||||
AC_CHECK_FUNCS([setns pivot_root sethostname unshare rand_r confstr])
|
||||
|
||||
# Check for some functions
|
||||
AC_CHECK_LIB(util, openpty)
|
||||
@ -326,7 +407,6 @@ AC_CONFIG_FILES([
|
||||
doc/lxc-netstat.sgml
|
||||
doc/lxc-ps.sgml
|
||||
doc/lxc-restart.sgml
|
||||
doc/lxc-shutdown.sgml
|
||||
doc/lxc-start-ephemeral.sgml
|
||||
doc/lxc-start.sgml
|
||||
doc/lxc-stop.sgml
|
||||
@ -355,6 +435,7 @@ AC_CONFIG_FILES([
|
||||
hooks/Makefile
|
||||
|
||||
templates/Makefile
|
||||
templates/lxc-cirros
|
||||
templates/lxc-debian
|
||||
templates/lxc-ubuntu
|
||||
templates/lxc-ubuntu-cloud
|
||||
@ -373,11 +454,7 @@ AC_CONFIG_FILES([
|
||||
src/lxc/lxc-netstat
|
||||
src/lxc/lxc-checkconfig
|
||||
src/lxc/lxc-version
|
||||
src/lxc/lxc-create
|
||||
src/lxc/lxc-clone
|
||||
src/lxc/lxc-shutdown
|
||||
src/lxc/lxc-start-ephemeral
|
||||
src/lxc/lxc-destroy
|
||||
src/lxc/legacy/lxc-ls
|
||||
src/lxc/lxc.functions
|
||||
|
||||
|
@ -22,7 +22,6 @@ man_MANS = \
|
||||
lxc-netstat.1 \
|
||||
lxc-ps.1 \
|
||||
lxc-restart.1 \
|
||||
lxc-shutdown.1 \
|
||||
lxc-start.1 \
|
||||
lxc-stop.1 \
|
||||
lxc-unfreeze.1 \
|
||||
|
@ -19,7 +19,7 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
|
@ -20,11 +20,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY seealso SYSTEM "@builddir@/../see_also.sgml">
|
||||
]>
|
||||
@ -50,7 +50,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<cmdsynopsis>
|
||||
<command>lxc-ls</command>
|
||||
<arg choice="opt">--active</arg>
|
||||
<arg choice="opt">ls option</arg>
|
||||
<arg choice="opt"><replaceable>ls options</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@ -79,7 +79,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option><optional>ls options</optional></option>
|
||||
<option><optional><replaceable>ls options</replaceable></optional></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
|
@ -17,11 +17,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
]>
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
|
@ -20,11 +20,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
@ -50,13 +50,31 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>lxc-clone</command>
|
||||
<arg choice="opt">-s </arg>
|
||||
<arg choice="opt">-K </arg>
|
||||
<arg choice="opt">-M </arg>
|
||||
<arg choice="opt">-H </arg>
|
||||
<arg choice="opt">-B <replaceable>backingstore</replaceable></arg>
|
||||
<arg choice="opt">-L <replaceable>fssize</replaceable></arg>
|
||||
<arg choice="opt">-p <replaceable>lxcpath</replaceable></arg>
|
||||
<arg choice="opt">-P <replaceable>newlxcpath</replaceable></arg>
|
||||
<arg choice="req">-o <replaceable>orig</replaceable></arg>
|
||||
<arg choice="req">-n <replaceable>new</replaceable></arg>
|
||||
<arg choice="opt">-- hook arguments</arg>
|
||||
</cmdsynopsis>
|
||||
<cmdsynopsis>
|
||||
<command>lxc-clone</command>
|
||||
<arg choice="opt">-s </arg>
|
||||
<arg choice="opt">-K </arg>
|
||||
<arg choice="opt">-M </arg>
|
||||
<arg choice="opt">-H </arg>
|
||||
<arg choice="opt">-B <replaceable>backingstore</replaceable></arg>
|
||||
<arg choice="opt">-L <replaceable>fssize</replaceable></arg>
|
||||
<arg choice="opt">-v <replaceable>vgname</replaceable></arg>
|
||||
<arg choice="opt">-p <replaceable>lxc_lv_prefix</replaceable></arg>
|
||||
<arg choice="opt">-t <replaceable>fstype</replaceable></arg>
|
||||
<arg choice="opt">-p <replaceable>lxcpath</replaceable></arg>
|
||||
<arg choice="opt">-P <replaceable>newlxcpath</replaceable></arg>
|
||||
<arg choice="req">orig</arg>
|
||||
<arg choice="req">new</arg>
|
||||
<arg choice="opt">-- hook arguments</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@ -64,10 +82,29 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
<command>lxc-clone</command> Creates a new container as a copy of an existing
|
||||
container. When the original container's rootfs is an LVM block device or
|
||||
is on a btrfs filesystem, then a snapshotted clone can be created, taking up
|
||||
very little initial disk space.
|
||||
<command>lxc-clone</command> Creates a new container as a clone of an existing
|
||||
container. Two types of clones are supported: copy and snapshot. A copy
|
||||
clone copies the root filessytem from the original container to the new. A
|
||||
snapshot filesystem uses the backing store's snapshot functionality to create
|
||||
a very small copy-on-write snapshot of the original container. Snapshot
|
||||
clones require the new container backing store to support snapshotting. Currently
|
||||
this includes only btrfs, lvm, overlayfs and zfs. LVM devices do not support
|
||||
snapshots fo snapshots.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The backing store of the new container will be the same type as the
|
||||
original container,
|
||||
with one exception: overlayfs snapshots can be created of directory backed
|
||||
containers. This can be requested by using the <replaceable>-B overlayfs</replaceable>
|
||||
arguments.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The names of the original and new container can be given (in that order)
|
||||
after all options, or can be specified with the
|
||||
<replaceable>-o</replaceable> and <replaceable>-n</replaceable> options,
|
||||
respectively.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
@ -78,6 +115,108 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-s, --snapshot</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The new container's rootfs should be a LVM or btrfs snapshot of the original.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-K, --keepname</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Do not change the hostname of the container (in the root
|
||||
filesystem).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-M, --keepmac</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the same MAC address as the original container, rather tahn
|
||||
generating a new random one.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-H, --copyhooks</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Copy all mount hooks into the new container's directory, and
|
||||
update any lxcpaths and container names as needed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-L, --fssize <replaceable>fssize</replaceable></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In the case of a block device backed container, a size for the new
|
||||
block device. By default, the new device will be made the
|
||||
same size as the original.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-p, --lxcpath <replaceable>fssize</replaceable></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The lxcpath of the original container. By default, the system
|
||||
wide configured lxcpath will be used.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-P, --newpath <replaceable>fssize</replaceable></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The lxcpath for the new container. By default the same lxcpath
|
||||
as the original will be used. Note that with btrfs snapshots,
|
||||
changing lxcpaths may not be possible, as subvolume snapshots
|
||||
must be in the same btrfs filesystem.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-B, --backingstore <replaceable>fssize</replaceable></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Select a different backing store for the new container. By
|
||||
default the same as the original container's is used. Note that
|
||||
currently changing the backingstore is only supported for
|
||||
overlayfs snapshots of directory backed containers. Valid
|
||||
backing stores include dir (directory), btrfs, lvm, zfs, loop
|
||||
and overlayfs.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-o, --orig <replaceable>orig</replaceable></option>
|
||||
@ -100,73 +239,28 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-s, --snapshot</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The new container's rootfs should be a LVM or btrfs snapshot of the original.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-L, --fssize <replaceable>fssize</replaceable></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In the case of a LVM-backed container, a size for the new
|
||||
block device. By default, the new device will be made the
|
||||
same size as the original.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-v, --vgname <replaceable>vgname</replaceable></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
For an LVM-backed container, the volume group name to use. By
|
||||
default it is 'lxc'.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-p, --lvprefix <replaceable>lxc_lv_prefix</replaceable></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
For an LVM-backed container, a string to prefix to the container name to
|
||||
form the logical volume name. For instance, specifying
|
||||
<command>-n c1 -p lxc_</command> will cause the container rootfs to
|
||||
be on a logical volume called <replaceable>lxc_c1</replaceable>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-t, --fstype <replaceable>fstype</replaceable></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
For a non-snapshot LVM clone, the file system to use for the new
|
||||
container. Note this option is ignored when requesting a
|
||||
snapshotted container.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Clone hook</title>
|
||||
<para>
|
||||
If the container being cloned has one or more <filename>lxc.hook.clone</filename>
|
||||
specified, then the specified hooks will be called for the new container. The
|
||||
first 3 arguments passed to the clone hook will be the container name, a section
|
||||
('lxc'), and the hook type ('clone'). Extra arguments passed
|
||||
<command>lxc-clone</command> will be passed to the hook program starting at
|
||||
argument 4. The <filename>LXC_ROOTFS_MOUNT</filename> environment variable gives
|
||||
the path under which the container's root filesystem is mounted. The
|
||||
configuration file pathname is stored in <filename>LXC_CONFIG_FILE</filename>, the
|
||||
new container name in <filename>LXC_NAME</filename>, the old container name in
|
||||
<filename>LXC_SRC_NAME</filename>, and the path or device on which
|
||||
the rootfs is located is in <filename>LXC_ROOTFS_PATH</filename>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
&seealso;
|
||||
|
||||
<refsect1>
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
@ -77,6 +77,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
the state it was before the disconnection.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A <replaceable>ttynum</replaceable> of 0 may be given to attach
|
||||
to the container's /dev/console instead of its
|
||||
dev/tty<<replaceable>ttynum</replaceable>>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A keyboard escape sequence may be used to disconnect from the tty
|
||||
and quit lxc-console. The default escape sequence is <Ctrl+a q>.
|
||||
@ -107,8 +113,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specify the tty number to connect, if not specified a tty
|
||||
number will be automatically choosen by the container.
|
||||
Specify the tty number to connect to or 0 for the console. If not
|
||||
specified the next available tty number will be automatically
|
||||
choosen by the container.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
@ -125,16 +125,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
'backingstore' is one of 'none', 'dir', 'lvm', or 'btrfs'. The
|
||||
'backingstore' is one of 'none', 'dir', 'lvm', 'loop', or 'btrfs'. The
|
||||
default is 'none', meaning that the container root filesystem
|
||||
will be a directory under <filename>@LXCPATH@/container/rootfs</filename>.
|
||||
'dir' has the same meaning as 'none', but also allows the optional
|
||||
<replaceable>--dir ROOTFS</replaceable> to be specified, meaning
|
||||
that the container rootfs should be placed under the specified path,
|
||||
rather than the default.
|
||||
The option 'btrfs' need not be specified as it will be used
|
||||
automatically if the <filename>@LXCPATH@</filename> filesystem is found to
|
||||
be btrfs. If backingstore is 'lvm', then an lvm block device will be
|
||||
rather than the default. If 'btrfs' is specified, then the
|
||||
target filesystem must be btrfs, and the container rootfs will be
|
||||
created as a new subvolume. This allows snapshotted clones to be
|
||||
created, but also causes rsync --one-filesystem to treat it as a
|
||||
separate filesystem.
|
||||
If backingstore is 'lvm', then an lvm block device will be
|
||||
used and the following further options are available:
|
||||
<replaceable>--lvname lvname1</replaceable> will create an LV
|
||||
named <filename>lvname1</filename> rather than the default, which
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
@ -81,17 +81,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-P, --lxcpath=<replaceable>PATH</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use an alternate container path. The default is @LXCPATH@.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-P, --lxcpath=<replaceable>PATH</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use an alternate container path. The default is @LXCPATH@.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -18,11 +18,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
]>
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
@ -132,12 +132,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<para>
|
||||
Signal the end of options and disables further option
|
||||
processing. Any arguments after the -- are treated as
|
||||
arguments.
|
||||
arguments to <replaceable>command</replaceable>.
|
||||
</para>
|
||||
<para>
|
||||
This option is useful when you want to execute, with the
|
||||
command <command>lxc-execute</command>, a command line
|
||||
with its own options.
|
||||
This option is useful when you want specify options
|
||||
to <replaceable>command</replaceable> and don't want
|
||||
<command>lxc-execute</command> to interpret them.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
|
@ -17,11 +17,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
@ -48,9 +48,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<cmdsynopsis>
|
||||
<command>lxc-info</command>
|
||||
<arg choice="req">-n <replaceable>name</replaceable></arg>
|
||||
<arg choice="req">-s</arg>
|
||||
<arg choice="req">-p</arg>
|
||||
<arg choice="req">-t <replaceable>state</replaceable></arg>
|
||||
<arg choice="opt">-c <replaceable>KEY</replaceable></arg>
|
||||
<arg choice="opt">-s</arg>
|
||||
<arg choice="opt">-p</arg>
|
||||
<arg choice="opt">-t <replaceable>state</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@ -77,6 +78,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option><optional>-c <replaceable>KEY</replaceable></optional></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Print a configuration key from the running container. This option
|
||||
may be given mulitple times to print out multiple key = value pairs.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option><optional>-s</optional></option>
|
||||
@ -135,6 +148,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>lxc-info -n foo -c lxc.network.0.veth.pair</term>
|
||||
<listitem>
|
||||
<para>
|
||||
prints the veth pair name of foo.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
|
@ -20,11 +20,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
]>
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
@ -63,22 +63,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
to monitor all the containers, several of them or just one.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <option>-P, --lxcpath</option>=PATH option may be specified multiple
|
||||
times to monitor more than one container path. Note however that
|
||||
containers with the same name in multiple paths will be
|
||||
indistinguishable in the output.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
&commonoptions;
|
||||
|
||||
<refsect1>
|
||||
<title>Bugs</title>
|
||||
|
||||
<para>
|
||||
Only one <command>lxc-monitor</command> can run at a time. Other
|
||||
invocations will fail with the following error:
|
||||
</para>
|
||||
<para>
|
||||
lxc-monitor: bind : Address already in use
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<variablelist>
|
||||
|
@ -17,11 +17,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
]>
|
||||
|
@ -20,11 +20,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
]>
|
||||
@ -52,7 +52,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<arg choice="opt">--name <replaceable>name</replaceable></arg>
|
||||
<arg choice="opt">--lxc</arg>
|
||||
<arg choice="opt">--host</arg>
|
||||
<arg choice="opt">-- ps option</arg>
|
||||
<arg choice="opt">-- <replaceable>ps options</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@ -69,7 +69,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
the container associated to processes.
|
||||
</para>
|
||||
<para>
|
||||
The additionnal specified ps options must not
|
||||
The additional specified <replaceable>ps options</replaceable> must not
|
||||
remove the default ps header and the pid information,
|
||||
to be able to have the <command>lxc-ps</command> to find
|
||||
the container associated to processes.
|
||||
@ -119,7 +119,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option><optional>ps options</optional></option>
|
||||
<option><optional><replaceable>ps options</replaceable></optional></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
|
@ -1,98 +0,0 @@
|
||||
<!--
|
||||
|
||||
Copyright (C) 2012 Canonical, Inc
|
||||
|
||||
Authors: Serge Hallyn <serge.hallyn@canonical.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
]>
|
||||
|
||||
<refentry>
|
||||
|
||||
<docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>lxc-shutdown</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>lxc-shutdown</refname>
|
||||
|
||||
<refpurpose>
|
||||
externally shut down or reboot a container
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>lxc-shutdown</command>
|
||||
<arg choice="req">-n <replaceable>name</replaceable></arg>
|
||||
<arg choice="opt">-w</arg>
|
||||
<arg choice="opt">-r</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
<command>lxc-shutdown</command> sends a SIGPWR signal to the
|
||||
specified container to request it to cleanly shut down. If
|
||||
<optional>-w</optional> is specified, then <command>lxc-shutdown</command>
|
||||
will wait until the container has shut down before exiting.
|
||||
If <optional>-r</optional> is specified, the container will be
|
||||
asked to reboot (using a SIGINT signal), and <optional>-w</optional>
|
||||
will be ignored. If the container ignore these signals, then
|
||||
nothing will happen. In that case, you can use <command>lxc-stop</command>
|
||||
to force the container to stop.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
&commonoptions;
|
||||
|
||||
&seealso;
|
||||
|
||||
<refsect1>
|
||||
<title>Author</title>
|
||||
<para>Serge Hallyn <email>serge.hallyn@canonical.com</email></para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-omittag:t
|
||||
sgml-shorttag:t
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-indent-step:2
|
||||
sgml-indent-data:t
|
||||
sgml-parent-document:nil
|
||||
sgml-default-dtd-file:nil
|
||||
sgml-exposed-tags:nil
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
End:
|
||||
-->
|
@ -18,11 +18,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
]>
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
@ -50,6 +50,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<cmdsynopsis>
|
||||
<command>lxc-stop</command>
|
||||
<arg choice="req">-n <replaceable>name</replaceable></arg>
|
||||
<arg choice="opt">-W</arg>
|
||||
<arg choice="opt">-r</arg>
|
||||
<arg choice="opt">-t <replaceable>timeout</replaceable></arg>
|
||||
<arg choice="opt">-k</arg>
|
||||
<arg choice="opt">-s</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@ -57,14 +62,90 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
<command>lxc-stop</command> kills all the processes inside the
|
||||
container. This command should be used if the processes are no
|
||||
longer accessible and can no be exited normally.
|
||||
<command>lxc-stop</command> reboots, cleanly shuts down, or kills
|
||||
all the processes inside the container. By default, it will
|
||||
request a clean shutdown of the container (by sending SIGPWR to
|
||||
the container), wait 60 seconds for the container to exit, and
|
||||
returns. If the container fails to cleanly exit, then after 60
|
||||
seconds the container will be sent the
|
||||
<command>lxc.stopsignal</command> to force it to shut down.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <optional>-W</optional>, <optional>-r</optional>, <optional>-s</optional>
|
||||
and <optional>-k</optional> options specify the action to perform.
|
||||
<optional>-W</optional> indicates that after performing the specified
|
||||
action, <command>lxc-stop</command> should immediately exit, while
|
||||
<optional>-t TIMEOUT</optional> specifies the maximum amount of time
|
||||
to wait for the container to complete the shutdown or reboot.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
&commonoptions;
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-r,--reboot </option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Request a reboot of the container.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-s,--shutdown </option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Only request a clean shutdown, do not kill the container tasks if the
|
||||
clean shutdown fails.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-k,--kill </option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Rather than requesting a clean shutdown of the container, explicitly
|
||||
kill all tasks in the container. This is the legacy
|
||||
<command>lxc-stop</command> behavior.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-W,--nowait </option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Simply perform the requestion action (reboot, shutdown, or hard
|
||||
kill) and exit.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>-t,--timeout <replaceable>TIMEOUT</replaceable></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Wait TIMEOUT seconds before hard-stopping the container of (in
|
||||
the reboot case) returning failure.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Diagnostic</title>
|
||||
@ -92,7 +173,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
|
@ -17,11 +17,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
]>
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
|
@ -20,11 +20,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
@ -49,7 +49,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>lxc-clone</command>
|
||||
<command>lxc-unshare</command>
|
||||
<arg choice="req">-s <replaceable>namespaces</replaceable></arg>
|
||||
<arg choice="req">-u <replaceable>user</replaceable></arg>
|
||||
<arg choice="req">command</arg>
|
||||
@ -115,7 +115,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<para>
|
||||
To spawn a new shell with its own UTS (hostname) namespace,
|
||||
<programlisting>
|
||||
lxc-clone -s UTSNAME /bin/bash
|
||||
lxc-unshare -s UTSNAME /bin/bash
|
||||
</programlisting>
|
||||
If the hostname is changed in that shell, the change will not be
|
||||
reflected on the host.
|
||||
@ -123,7 +123,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<para>
|
||||
To spawn a shell in a new network, pid, and mount namespace,
|
||||
<programlisting>
|
||||
lxc-clone -s "NETWORK|PID|MOUNT" /bin/bash
|
||||
lxc-unshare -s "NETWORK|PID|MOUNT" /bin/bash
|
||||
</programlisting>
|
||||
The resulting shell will have pid 1 and will see no network interfaces.
|
||||
After re-mounting /proc in that shell,
|
||||
|
@ -17,11 +17,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
]>
|
||||
|
@ -20,11 +20,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
]>
|
||||
@ -65,8 +65,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<para>
|
||||
The configuration file defines the different system resources to
|
||||
be assigned for the container. At present, the utsname, the
|
||||
network, the mount points, the root file system and the control
|
||||
groups are supported.
|
||||
network, the mount points, the root file system, the user namespace,
|
||||
and the control groups are supported.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -75,12 +75,38 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
the line is a comment.
|
||||
</para>
|
||||
|
||||
<refsect2>
|
||||
<title>Configuration</title>
|
||||
<para>
|
||||
In order to ease administration of multiple related containers, it
|
||||
is possible to have a container configuration file cause another
|
||||
file to be loaded. For instance, network configuration
|
||||
can be defined in one common file which is included by multiple
|
||||
containers. Then, if the containers are moved to another host,
|
||||
only one file may need to be updated.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>lxc.include</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specify the file to be included. The included file must be
|
||||
in the same valid lxc configuration file format.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Architecture</title>
|
||||
<para>
|
||||
Allows to set the architecture for the container. For example,
|
||||
set a 32bits architecture for a container running 32bits
|
||||
binaries on a 64bits host. That fix the container scripts
|
||||
binaries on a 64bits host. This fixes the container scripts
|
||||
which rely on the architecture to do some work like
|
||||
downloading the packages.
|
||||
</para>
|
||||
@ -229,7 +255,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
bridge is set up as a reflective relay. Broadcast
|
||||
frames coming in from the upper_dev get flooded to all
|
||||
macvlan interfaces in VEPA mode, local frames are not
|
||||
delivered locallay, or <option>bridge</option>, it
|
||||
delivered locally, or <option>bridge</option>, it
|
||||
provides the behavior of a simple bridge between
|
||||
different macvlan interfaces on the same port. Frames
|
||||
from one interface to another one get delivered directly
|
||||
@ -258,7 +284,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
specify an action to do for the
|
||||
network.
|
||||
</para>
|
||||
|
||||
|
||||
<para><option>up:</option> activates the interface.
|
||||
</para>
|
||||
</listitem>
|
||||
@ -395,6 +421,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
type, other arguments may be passed:
|
||||
veth/macvlan/phys. And finally (host-sided) device name.
|
||||
</para>
|
||||
<para>
|
||||
Standard output from the script is logged at debug level.
|
||||
Standard error is not logged, but can be captured by the
|
||||
hook redirecting its standard error to standard output.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@ -415,6 +446,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
type, other arguments may be passed:
|
||||
veth/macvlan/phys. And finally (host-sided) device name.
|
||||
</para>
|
||||
<para>
|
||||
Standard output from the script is logged at debug level.
|
||||
Standard error is not logged, but can be captured by the
|
||||
hook redirecting its standard error to standard output.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
@ -448,7 +484,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<para>
|
||||
If the container is configured with a root filesystem and the
|
||||
inittab file is setup to use the console, you may want to specify
|
||||
where goes the output of this console.
|
||||
where the output of this console goes.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
@ -471,14 +507,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<refsect2>
|
||||
<title>Console through the ttys</title>
|
||||
<para>
|
||||
If the container is configured with a root filesystem and the
|
||||
inittab file is setup to launch a getty on the ttys. This
|
||||
option will specify the number of ttys to be available for the
|
||||
container. The number of getty in the inittab file of the
|
||||
container should not be greater than the number of ttys
|
||||
specified in this configuration file, otherwise the excess
|
||||
getty sessions will die and respawn indefinitly giving
|
||||
annoying messages on the console.
|
||||
This option is useful if the container is configured with a root
|
||||
filesystem and the inittab file is setup to launch a getty on the
|
||||
ttys. The option specifies the number of ttys to be available for
|
||||
the container. The number of gettys in the inittab file of the
|
||||
container should not be greater than the number of ttys specified
|
||||
in this option, otherwise the excess getty sessions will die and
|
||||
respawn indefinitely giving annoying messages on the console or in
|
||||
<filename>/var/log/messages</filename>.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
@ -534,7 +570,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
rootfs LXC will mount a fresh tmpfs under <filename>/dev</filename>
|
||||
(limited to 100k) and fill in a minimal set of initial devices.
|
||||
This is generally required when starting a container containing
|
||||
a "systemd" based "init" but may be optional at other times. Addional
|
||||
a "systemd" based "init" but may be optional at other times. Additional
|
||||
devices in the containers /dev directory may be created through the
|
||||
use of the <option>lxc.hook.autodev</option> hook.
|
||||
</para>
|
||||
@ -590,13 +626,20 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<para>
|
||||
specify a file location in
|
||||
the <filename>fstab</filename> format, containing the
|
||||
mount informations. If the rootfs is an image file or a
|
||||
device block and the fstab is used to mount a point
|
||||
mount information. If the rootfs is an image file or a
|
||||
block device and the fstab is used to mount a point
|
||||
somewhere in this rootfs, the path of the rootfs mount
|
||||
point should be prefixed with the
|
||||
<filename>@LXCROOTFSMOUNT@</filename> default path or
|
||||
the value of <option>lxc.rootfs.mount</option> if
|
||||
specified.
|
||||
specified. Note that when mounting a filesystem from an
|
||||
image file or block device the third field (fs_vfstype)
|
||||
cannot be auto as with
|
||||
<citerefentry>
|
||||
<refentrytitle>mount</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</citerefentry>
|
||||
but must be explicitly specified.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -728,6 +771,67 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>lxc.cap.keep</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specify the capability to be kept in the container. All other
|
||||
capabilities will be dropped.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Apparmor profile</title>
|
||||
<para>
|
||||
If lxc was compiled and installed with apparmor support, and the host
|
||||
system has apparmor enabled, then the apparmor profile under which the
|
||||
container should be run can be specified in the container
|
||||
configuration. The default is <command>lxc-container-default</command>.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>lxc.aa_profile</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specify the apparmor profile under which the container should
|
||||
be run. To specify that the container should be unconfined,
|
||||
use
|
||||
</para>
|
||||
<programlisting>lxc.aa_profile = unconfined</programlisting>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Seccomp configuration</title>
|
||||
<para>
|
||||
A container can be started with a reduced set of available
|
||||
system calls by loading a seccomp profile at startup. The
|
||||
seccomp configuration file should begin with a version number
|
||||
(which currently must be 1) on the first line, a policy type
|
||||
(which must be 'whitelist') on the second line, followed by a
|
||||
list of allowed system call numbers, one per line.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>lxc.seccomp</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specify a file containing the seccomp configuration to
|
||||
load before the container starts.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
|
||||
@ -763,11 +867,37 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Startup hooks</title>
|
||||
<title>Container hooks</title>
|
||||
<para>
|
||||
Startup hooks are programs or scripts which can be executed
|
||||
Container hooks are programs or scripts which can be executed
|
||||
at various times in a container's lifetime.
|
||||
</para>
|
||||
<para>
|
||||
When a container hook is executed, information is passed both
|
||||
as command line arguments and through environment variables.
|
||||
The arguments are:
|
||||
<itemizedlist>
|
||||
<listitem> Container name. </listitem>
|
||||
<listitem> Section (always 'lxc'). </listitem>
|
||||
<listitem> The hook type (i.e. 'clone' or 'pre-mount'). </listitem>
|
||||
<listitem> Additional arguments In the
|
||||
case of the clone hook, any extra arguments passed to
|
||||
lxc-clone will appear as further arguments to the hook. </listitem>
|
||||
</itemizedlist>
|
||||
The following environment variables are set:
|
||||
<itemizedlist>
|
||||
<listitem> LXC_NAME: is the container's name. </listitem>
|
||||
<listitem> LXC_ROOTFS_MOUNT: the path to the mounted root filesystem. </listitem>
|
||||
<listitem> LXC_CONFIG_FILE: the path to the container configuration file. </listitem>
|
||||
<listitem> LXC_SRC_NAME: in the case of the clone hook, this is the original container's name. </listitem>
|
||||
<listitem> LXC_ROOTFS_PATH: this is the lxc.rootfs enty for the container. Note this is likely not where the mounted rootfs is to be found, use LXC_ROOTFS_MOUNT for that. </listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
Standard output from the hooks is logged at debug level.
|
||||
Standard error is not logged, but can be captured by the
|
||||
hook redirecting its standard error to standard output.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
@ -859,10 +989,24 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>lxc.hook.clone</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A hook to be run when the container is cloned to a new one.
|
||||
See <refentrytitle><command>lxc-clone</command></refentrytitle>
|
||||
<manvolnum>1</manvolnum> for more information.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Startup hooks Environment Variables</title>
|
||||
<title>Container hooks Environment Variables</title>
|
||||
<para>
|
||||
A number of environment variables are made available to the startup
|
||||
hooks to provide configuration information and assist in the
|
||||
@ -893,7 +1037,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Host relative path to the container configuration file. This
|
||||
gives the container to reference the original, top level,
|
||||
configuration file for the container in order to locate any
|
||||
addotional configuration information not otherwise made
|
||||
additional configuration information not otherwise made
|
||||
available. [<option>-f</option>]
|
||||
</para>
|
||||
</listitem>
|
||||
@ -957,6 +1101,54 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
</variablelist>
|
||||
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
<title> Logging</title>
|
||||
<para>
|
||||
Logging can be configured on a per-container basis. By default,
|
||||
depending upon how the lxc package was compiled, container startup
|
||||
is logged only at the ERROR level, and logged to a file named after
|
||||
the container (with '.log' appended) either under the container path,
|
||||
or under @LOGPATH@.
|
||||
</para>
|
||||
<para>
|
||||
Both the default log level and the log file can be specified in the
|
||||
container configuration file, overriding the default behavior. Note
|
||||
that the configuration file entries can in turn be overridden by the
|
||||
command line options to <command>lxc-start</command>.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>lxc.loglevel</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The level at which to log. The log level is an integer in
|
||||
the range of 0..8 inclusive, where a lower number means more
|
||||
verbose debugging. In particular 0 = trace, 1 = debug, 2 =
|
||||
info, 3 = notice, 4 = warn, 5 = error, 6 = critical, 7 =
|
||||
alert, and 8 = fatal. If unspecified, the level defaults
|
||||
to 5 (error), so that only errors and above are logged.
|
||||
</para>
|
||||
<para>
|
||||
Note that when a script (such as either a hook script or a
|
||||
network interface up or down script) is called, the script's
|
||||
standard output is logged at level 1, debug.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>lxc.logfile</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The file to which logging info should be written.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
|
||||
</refsect1>
|
||||
|
||||
@ -1069,8 +1261,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
<citerefentry>
|
||||
<refentrytitle><filename>fstab</filename></refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
</citerefentry>
|
||||
</citerefentry>,
|
||||
|
||||
<citerefentry>
|
||||
<refentrytitle><filename>capabilities</filename></refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
</citerefentry>
|
||||
</simpara>
|
||||
</refsect1>
|
||||
|
||||
|
@ -19,11 +19,11 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!DOCTYPE refentry PUBLIC @docdtd@ [
|
||||
|
||||
<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
|
||||
]>
|
||||
|
@ -19,7 +19,7 @@ Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-->
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
hooksdir=@LXCHOOKDIR@
|
||||
|
||||
hooks_SCRIPTS = \
|
||||
clonehostname \
|
||||
mountcgroups \
|
||||
mountecryptfsroot
|
||||
mountecryptfsroot \
|
||||
ubuntu-cloud-prep
|
||||
|
||||
EXTRA_DIST=$(hooks_SCRIPTS)
|
||||
|
29
hooks/clonehostname
Executable file
29
hooks/clonehostname
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Update the hostname in the cloned container's scripts
|
||||
#
|
||||
# Copyright © 2013 Oracle.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
# Note that /etc/hostname is updated by lxc itself
|
||||
for file in \
|
||||
$LXC_ROOTFS_PATH/etc/sysconfig/network \
|
||||
$LXC_ROOTFS_PATH/etc/sysconfig/network-scripts/ifcfg-* ;
|
||||
do
|
||||
if [ -f $file ]; then
|
||||
sed -i "s|$LXC_SRC_NAME|$LXC_NAME|" $file
|
||||
fi
|
||||
done
|
||||
exit 0
|
@ -14,7 +14,7 @@
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#
|
||||
# This is an example hook to mount all mounted cgroups in the
|
||||
@ -26,17 +26,40 @@
|
||||
set -e
|
||||
|
||||
c=$1
|
||||
configfile=$LXC_CONFIG_FILE
|
||||
d=/sys/fs/cgroup
|
||||
d2=$LXC_ROOTFS_MOUNT/${d}
|
||||
# name lxc hook lxcpath
|
||||
lxcpath=$4
|
||||
if [ ! -d "$d" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mount -n -t tmpfs tmpfs ${d2}
|
||||
|
||||
do_devices_setup() {
|
||||
local devdir="$1"
|
||||
local c="$2"
|
||||
local line
|
||||
local w # which (allow or deny)
|
||||
local v # value
|
||||
egrep "^lxc.cgroup.devices.(allow|deny)[ \t]*=" ${configfile} | while read line; do
|
||||
w=`echo $line | awk -F. '{ print $4 }' | awk '{ print $1 }'`
|
||||
v=`echo $line | awk -F= '{ print $2 }'`
|
||||
echo "$v" >> "$devdir"/devices.$w
|
||||
done
|
||||
}
|
||||
|
||||
# XXX TODO - we'll need to account for other cgroup groups beside 'lxc',
|
||||
# i.e. 'build' or 'users/joe'.
|
||||
for dir in `/bin/ls $d`; do
|
||||
if [ "$dir" = "devices" ]; then
|
||||
devicesdir="${d}/${dir}/lxc/${c}"
|
||||
mkdir -p "$devicesdir"
|
||||
# set the devices cgroup perms now - we can't change from blacklist to
|
||||
# whitelist, or add perms, once we have children.
|
||||
do_devices_setup "$devicesdir" "${c}"
|
||||
fi
|
||||
mkdir -p "${d}/${dir}/lxc/${c}/${c}.real"
|
||||
echo 1 > "${d}/${dir}/lxc/${c}/${c}.real/tasks"
|
||||
mkdir -p ${d2}/${dir}
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
# This hook can be used to mount an ecryptfs filesystem as a container's
|
||||
# rootfs.
|
||||
|
184
hooks/ubuntu-cloud-prep
Executable file
184
hooks/ubuntu-cloud-prep
Executable file
@ -0,0 +1,184 @@
|
||||
#!/bin/bash
|
||||
## If the container being cloned has one or more lxc.hook.clone
|
||||
## specified, then the specified hooks will be called for the new
|
||||
## container. The arguments passed to the clone hook are:
|
||||
## 1. the container name
|
||||
## 2. a section ('lxc')
|
||||
## 3. hook type ('clone')
|
||||
## 4. .. additional arguments to lxc-clone
|
||||
## Environment variables:
|
||||
## LXC_ROOTFS_MOUNT: path to the root filesystem
|
||||
## LXC_CONFIG_FILE: path to config file
|
||||
## LXC_SRC_NAME: old container name
|
||||
## LXC_ROOTFS_PATH: path or device on which the root fs is located
|
||||
|
||||
set -f
|
||||
VERBOSITY="0"
|
||||
|
||||
error() { echo "$@" 1>&2; }
|
||||
debug() { [ "$VERBOSITY" -ge "$1" ] || return; shift; error "$@"; }
|
||||
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
|
||||
|
||||
prep_usage() {
|
||||
cat <<EOF
|
||||
Usage: ${0##*/} [options] root-dir
|
||||
|
||||
root-dir is the root directory to operate on
|
||||
|
||||
[ -C | --cloud ]: do not configure a datasource. incompatible with
|
||||
options marked '[ds]'
|
||||
[ -i | --instance-id]: instance-id for cloud-init, defaults to random [ds]
|
||||
[ -L | --nolocales ]: Do not copy host's locales into container
|
||||
[ -S | --auth-key ]: ssh public key file for datasource [ds]
|
||||
[ -u | --userdata ]: user-data file for cloud-init [ds]
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
prep() {
|
||||
local short_opts="Chi:L:S:u:v"
|
||||
local long_opts="auth-key:,cloud,help,hostid:,name:,nolocales:,create-etc-init,userdata:,verbose"
|
||||
local getopt_out getopt_ret
|
||||
getopt_out=$(getopt --name "${0##*/}" \
|
||||
--options "${short_opts}" --long "${long_opts}" -- "$@" 2>/dev/null) ||
|
||||
:
|
||||
getopt_ret=$?
|
||||
if [ $getopt_ret -eq 0 ]; then
|
||||
eval set -- "${getopt_out}" ||
|
||||
{ error "Unexpected error reading usage"; return 1; }
|
||||
fi
|
||||
|
||||
local cur="" next=""
|
||||
local userdata="" hostid="" authkey="" locales=1 cloud=0
|
||||
local create_etc_init=0 name="ubuntucloud-lxc"
|
||||
|
||||
while [ $# -ne 0 ]; do
|
||||
cur="$1"; next="$2";
|
||||
case "$cur" in
|
||||
-C|--cloud) cloud=1;;
|
||||
-h|--help) prep_usage; return 0;;
|
||||
--name) name="$next";;
|
||||
-i|--hostid) hostid="$next";;
|
||||
-L|--nolocales) locales=0;;
|
||||
--create-etc-init) create_etc_init=1;;
|
||||
-S|--auth-key)
|
||||
[ -f "$next" ] ||
|
||||
{ error "--auth-key: '$next' not a file"; return 1; }
|
||||
authkey="$next";;
|
||||
-u|--userdata)
|
||||
[ -f "$next" ] ||
|
||||
{ error "--userdata: '$next' not a file"; return 1; }
|
||||
userdata="$next";;
|
||||
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
|
||||
--) shift; break;;
|
||||
esac
|
||||
shift;
|
||||
done
|
||||
|
||||
[ $# -eq 1 ] || {
|
||||
prep_usage 1>&2;
|
||||
error "expected 1 arguments, got ($_LXC_HOOK) $#: $*";
|
||||
return 1;
|
||||
}
|
||||
|
||||
local root_d="$1";
|
||||
|
||||
if [ $getopt_ret -ne 0 -a "$_LXC_HOOK" = "clone" ]; then
|
||||
# getopt above failed, but we were called from lxc clone. there might
|
||||
# be multiple clone hooks and the args provided here not for us. This
|
||||
# seems like not the greatest interface, so all we'll do is mention it.
|
||||
error "${0##*}: usage failed, continuing with defaults"
|
||||
fi
|
||||
|
||||
[ "$create_etc_init" -eq 0 ] ||
|
||||
echo "#upstart needs help for overlayfs (LP: #1213925)." > \
|
||||
"$root_d/etc/init/.overlayfs-upstart-helper" ||
|
||||
{ error "failed to create /etc/init in overlay"; return 1; }
|
||||
|
||||
local seed_d=""
|
||||
seed_d="$root_d/var/lib/cloud/seed/nocloud-net"
|
||||
|
||||
echo "$name" > "$root_d/etc/hostname" ||
|
||||
{ error "failed to write /etc/hostname"; return 1; }
|
||||
|
||||
if [ $cloud -eq 1 ]; then
|
||||
debug 1 "--cloud provided, not modifying seed in '$seed_d'"
|
||||
else
|
||||
if [ -z "$hostid" ]; then
|
||||
hostid=$(uuidgen | cut -c -8) && [ -n "$hostid" ] ||
|
||||
{ error "failed to get hostid"; return 1; }
|
||||
fi
|
||||
mkdir -p "$seed_d" ||
|
||||
{ error "failed to create '$seed_d'"; return 1; }
|
||||
|
||||
echo "instance-id: lxc-$hostid" > "$seed_d/meta-data" ||
|
||||
{ error "failed to write to $seed_d/meta-data"; return 1; }
|
||||
|
||||
echo "local-hostname: $name" >> "$seed_d/meta-data" ||
|
||||
{ error "failed to write to $seed_d/meta-data"; return 1; }
|
||||
|
||||
if [ -n "$authkey" ]; then
|
||||
{
|
||||
echo "public-keys:" &&
|
||||
sed -e '/^$/d' -e 's,^,- ,' "$authkey"
|
||||
} >> "$seed_d/meta-data"
|
||||
[ $? -eq 0 ] ||
|
||||
{ error "failed to write public keys to metadata"; return 1; }
|
||||
fi
|
||||
|
||||
local larch="usr/lib/locale/locale-archive"
|
||||
if [ $locales -eq 1 ]; then
|
||||
cp "/$larch" "$root_d/$larch" || {
|
||||
error "failed to cp '/$larch' '$root_d/$larch'";
|
||||
return 1;
|
||||
}
|
||||
fi
|
||||
|
||||
if [ -z "$MIRROR" ]; then
|
||||
MIRROR="http://archive.ubuntu.com/ubuntu"
|
||||
fi
|
||||
|
||||
if [ -n "$userdata" ]; then
|
||||
cp "$userdata" "$seed_d/user-data"
|
||||
else
|
||||
{
|
||||
local lc=$(locale | awk -F= '/LANG=/ {print $NF; }')
|
||||
echo "#cloud-config"
|
||||
echo "output: {all: '| tee -a /var/log/cloud-init-output.log'}"
|
||||
echo "apt_mirror: $MIRROR"
|
||||
echo "manage_etc_hosts: localhost"
|
||||
[ -z "$LANG" ] || echo "locale: $LANG";
|
||||
echo "password: ubuntu"
|
||||
echo "chpasswd: { expire: false; }"
|
||||
} > "$seed_d/user-data"
|
||||
fi
|
||||
[ $? -eq 0 ] || {
|
||||
error "failed to write user-data write to '$seed_d/user-data'";
|
||||
return 1;
|
||||
}
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
main() {
|
||||
# main just joins 2 modes of being called. from user one from lxc clone
|
||||
local _LXC_HOOK
|
||||
if [ -n "$LXC_ROOTFS_MOUNT" -a "$3" = "clone" ]; then
|
||||
_LXC_HOOK="clone"
|
||||
local name="$1" create_etc_init=""
|
||||
shift 3
|
||||
# if mountpoint is overlayfs then add '--create-etc-init'
|
||||
[ "${LXC_ROOTFS_PATH#overlayfs}" != "${LXC_ROOTFS_PATH}" ] &&
|
||||
create_etc_init="--create-etc-init"
|
||||
debug 1 prep "--name=$name" $create_etc_init "$LXC_ROOTFS_MOUNT" "$@"
|
||||
prep "--name=$name" $create_etc_init "$LXC_ROOTFS_MOUNT" "$@"
|
||||
else
|
||||
_LXC_HOOK=""
|
||||
prep "$@"
|
||||
fi
|
||||
return $?
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
# vi: ts=4 expandtab
|
@ -18,7 +18,7 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Name: @PACKAGE@
|
||||
Version: @VERSION@
|
||||
@ -100,7 +100,6 @@ rm -rf %{buildroot}
|
||||
%attr(4111,root,root) %{_bindir}/lxc-attach
|
||||
%attr(4111,root,root) %{_bindir}/lxc-create
|
||||
%attr(4111,root,root) %{_bindir}/lxc-clone
|
||||
%attr(4111,root,root) %{_bindir}/lxc-shutdown
|
||||
%attr(4111,root,root) %{_bindir}/lxc-start
|
||||
%attr(4111,root,root) %{_bindir}/lxc-netstat
|
||||
%attr(4111,root,root) %{_bindir}/lxc-unshare
|
||||
|
@ -1,4 +1,22 @@
|
||||
#!/bin/sh
|
||||
# liblxcapi
|
||||
#
|
||||
# Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
|
||||
# Copyright © 2012 Canonical Ltd.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
cleanup() {
|
||||
rm -f /etc/lxc/test-busybox.conf
|
||||
|
@ -1,3 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2006 SPARTA, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by SPARTA ISSO under SPAWAR contract
|
||||
* N66001-04-C-6019 ("SEFOS").
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -1,6 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2006 SPARTA, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by SPARTA ISSO under SPAWAR contract
|
||||
* N66001-04-C-6019 ("SEFOS").
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _getline_h
|
||||
#define _getline_h
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern ssize_t getline(char **outbuf, size_t *outsize, FILE *fp);
|
||||
|
||||
#endif
|
||||
|
597
src/include/ifaddrs.c
Normal file
597
src/include/ifaddrs.c
Normal file
@ -0,0 +1,597 @@
|
||||
/*
|
||||
Copyright (c) 2013, Kenneth MacKay
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ifaddrs.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
typedef struct NetlinkList
|
||||
{
|
||||
struct NetlinkList *m_next;
|
||||
struct nlmsghdr *m_data;
|
||||
unsigned int m_size;
|
||||
} NetlinkList;
|
||||
|
||||
static int netlink_socket(void)
|
||||
{
|
||||
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if(l_socket < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_nl l_addr;
|
||||
memset(&l_addr, 0, sizeof(l_addr));
|
||||
l_addr.nl_family = AF_NETLINK;
|
||||
if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
|
||||
{
|
||||
close(l_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return l_socket;
|
||||
}
|
||||
|
||||
static int netlink_send(int p_socket, int p_request)
|
||||
{
|
||||
char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
|
||||
memset(l_buffer, 0, sizeof(l_buffer));
|
||||
struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer;
|
||||
struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
|
||||
|
||||
l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
|
||||
l_hdr->nlmsg_type = p_request;
|
||||
l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
|
||||
l_hdr->nlmsg_pid = 0;
|
||||
l_hdr->nlmsg_seq = p_socket;
|
||||
l_msg->rtgen_family = AF_UNSPEC;
|
||||
|
||||
struct sockaddr_nl l_addr;
|
||||
memset(&l_addr, 0, sizeof(l_addr));
|
||||
l_addr.nl_family = AF_NETLINK;
|
||||
return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
|
||||
}
|
||||
|
||||
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
|
||||
{
|
||||
struct msghdr l_msg;
|
||||
struct iovec l_iov = { p_buffer, p_len };
|
||||
struct sockaddr_nl l_addr;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
l_msg.msg_name = (void *)&l_addr;
|
||||
l_msg.msg_namelen = sizeof(l_addr);
|
||||
l_msg.msg_iov = &l_iov;
|
||||
l_msg.msg_iovlen = 1;
|
||||
l_msg.msg_control = NULL;
|
||||
l_msg.msg_controllen = 0;
|
||||
l_msg.msg_flags = 0;
|
||||
int l_result = recvmsg(p_socket, &l_msg, 0);
|
||||
|
||||
if(l_result < 0)
|
||||
{
|
||||
if(errno == EINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(l_msg.msg_flags & MSG_TRUNC)
|
||||
{ // buffer was too small
|
||||
return -1;
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
|
||||
static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
|
||||
{
|
||||
size_t l_size = 4096;
|
||||
void *l_buffer = NULL;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
free(l_buffer);
|
||||
l_buffer = malloc(l_size);
|
||||
|
||||
int l_read = netlink_recv(p_socket, l_buffer, l_size);
|
||||
*p_size = l_read;
|
||||
if(l_read == -2)
|
||||
{
|
||||
free(l_buffer);
|
||||
return NULL;
|
||||
}
|
||||
if(l_read >= 0)
|
||||
{
|
||||
pid_t l_pid = getpid();
|
||||
struct nlmsghdr *l_hdr;
|
||||
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
*p_done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
free(l_buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return l_buffer;
|
||||
}
|
||||
|
||||
l_size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
|
||||
{
|
||||
NetlinkList *l_item = malloc(sizeof(NetlinkList));
|
||||
l_item->m_next = NULL;
|
||||
l_item->m_data = p_data;
|
||||
l_item->m_size = p_size;
|
||||
return l_item;
|
||||
}
|
||||
|
||||
static void freeResultList(NetlinkList *p_list)
|
||||
{
|
||||
NetlinkList *l_cur;
|
||||
while(p_list)
|
||||
{
|
||||
l_cur = p_list;
|
||||
p_list = p_list->m_next;
|
||||
free(l_cur->m_data);
|
||||
free(l_cur);
|
||||
}
|
||||
}
|
||||
|
||||
static NetlinkList *getResultList(int p_socket, int p_request)
|
||||
{
|
||||
if(netlink_send(p_socket, p_request) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NetlinkList *l_list = NULL;
|
||||
NetlinkList *l_end = NULL;
|
||||
int l_size;
|
||||
int l_done = 0;
|
||||
while(!l_done)
|
||||
{
|
||||
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
|
||||
if(!l_hdr)
|
||||
{ // error
|
||||
freeResultList(l_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NetlinkList *l_item = newListItem(l_hdr, l_size);
|
||||
if(!l_list)
|
||||
{
|
||||
l_list = l_item;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_end->m_next = l_item;
|
||||
}
|
||||
l_end = l_item;
|
||||
}
|
||||
return l_list;
|
||||
}
|
||||
|
||||
static size_t maxSize(size_t a, size_t b)
|
||||
{
|
||||
return (a > b ? a : b);
|
||||
}
|
||||
|
||||
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
|
||||
{
|
||||
switch(p_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return sizeof(struct sockaddr_in);
|
||||
case AF_INET6:
|
||||
return sizeof(struct sockaddr_in6);
|
||||
case AF_PACKET:
|
||||
return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
|
||||
default:
|
||||
return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
|
||||
{
|
||||
switch(p_family)
|
||||
{
|
||||
case AF_INET:
|
||||
memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
|
||||
break;
|
||||
case AF_PACKET:
|
||||
memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
|
||||
((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
|
||||
break;
|
||||
default:
|
||||
memcpy(p_dest->sa_data, p_data, p_size);
|
||||
break;
|
||||
}
|
||||
p_dest->sa_family = p_family;
|
||||
}
|
||||
|
||||
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
|
||||
{
|
||||
if(!*p_resultList)
|
||||
{
|
||||
*p_resultList = p_entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct ifaddrs *l_cur = *p_resultList;
|
||||
while(l_cur->ifa_next)
|
||||
{
|
||||
l_cur = l_cur->ifa_next;
|
||||
}
|
||||
l_cur->ifa_next = p_entry;
|
||||
}
|
||||
}
|
||||
|
||||
static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
|
||||
{
|
||||
struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
|
||||
|
||||
size_t l_nameSize = 0;
|
||||
size_t l_addrSize = 0;
|
||||
size_t l_dataSize = 0;
|
||||
|
||||
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
|
||||
struct rtattr *l_rta;
|
||||
for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFLA_ADDRESS:
|
||||
case IFLA_BROADCAST:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
|
||||
break;
|
||||
case IFLA_IFNAME:
|
||||
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
|
||||
break;
|
||||
case IFLA_STATS:
|
||||
l_dataSize += NLMSG_ALIGN(l_rtaSize);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize);
|
||||
memset(l_entry, 0, sizeof(struct ifaddrs));
|
||||
l_entry->ifa_name = "";
|
||||
|
||||
char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
|
||||
char *l_addr = l_name + l_nameSize;
|
||||
char *l_data = l_addr + l_addrSize;
|
||||
|
||||
l_entry->ifa_flags = l_info->ifi_flags;
|
||||
|
||||
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
|
||||
for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
void *l_rtaData = RTA_DATA(l_rta);
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFLA_ADDRESS:
|
||||
case IFLA_BROADCAST:
|
||||
{
|
||||
size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
|
||||
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
|
||||
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
|
||||
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
|
||||
if(l_rta->rta_type == IFLA_ADDRESS)
|
||||
{
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
l_addr += NLMSG_ALIGN(l_addrLen);
|
||||
break;
|
||||
}
|
||||
case IFLA_IFNAME:
|
||||
strncpy(l_name, l_rtaData, l_rtaDataSize);
|
||||
l_name[l_rtaDataSize] = '\0';
|
||||
l_entry->ifa_name = l_name;
|
||||
break;
|
||||
case IFLA_STATS:
|
||||
memcpy(l_data, l_rtaData, l_rtaDataSize);
|
||||
l_entry->ifa_data = l_data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
addToEnd(p_resultList, l_entry);
|
||||
p_links[l_info->ifi_index - 1] = l_entry;
|
||||
}
|
||||
|
||||
static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
|
||||
{
|
||||
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
|
||||
|
||||
size_t l_nameSize = 0;
|
||||
size_t l_addrSize = 0;
|
||||
|
||||
int l_addedNetmask = 0;
|
||||
|
||||
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
|
||||
struct rtattr *l_rta;
|
||||
for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
if(l_info->ifa_family == AF_PACKET)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_LOCAL:
|
||||
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
|
||||
{ // make room for netmask
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
l_addedNetmask = 1;
|
||||
}
|
||||
case IFA_BROADCAST:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
break;
|
||||
case IFA_LABEL:
|
||||
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
|
||||
memset(l_entry, 0, sizeof(struct ifaddrs));
|
||||
l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name;
|
||||
|
||||
char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
|
||||
char *l_addr = l_name + l_nameSize;
|
||||
|
||||
l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags;
|
||||
|
||||
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
|
||||
for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
void *l_rtaData = RTA_DATA(l_rta);
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_BROADCAST:
|
||||
case IFA_LOCAL:
|
||||
{
|
||||
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
|
||||
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
|
||||
if(l_info->ifa_family == AF_INET6)
|
||||
{
|
||||
if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
|
||||
{
|
||||
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
|
||||
}
|
||||
}
|
||||
|
||||
if(l_rta->rta_type == IFA_ADDRESS)
|
||||
{ // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address
|
||||
if(l_entry->ifa_addr)
|
||||
{
|
||||
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
}
|
||||
else if(l_rta->rta_type == IFA_LOCAL)
|
||||
{
|
||||
if(l_entry->ifa_addr)
|
||||
{
|
||||
l_entry->ifa_dstaddr = l_entry->ifa_addr;
|
||||
}
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
l_addr += NLMSG_ALIGN(l_addrLen);
|
||||
break;
|
||||
}
|
||||
case IFA_LABEL:
|
||||
strncpy(l_name, l_rtaData, l_rtaDataSize);
|
||||
l_name[l_rtaDataSize] = '\0';
|
||||
l_entry->ifa_name = l_name;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
|
||||
{
|
||||
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
|
||||
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
|
||||
char l_mask[16] = {0};
|
||||
unsigned i;
|
||||
for(i=0; i<(l_prefix/8); ++i)
|
||||
{
|
||||
l_mask[i] = 0xff;
|
||||
}
|
||||
l_mask[i] = 0xff << (8 - (l_prefix % 8));
|
||||
|
||||
makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
|
||||
l_entry->ifa_netmask = (struct sockaddr *)l_addr;
|
||||
}
|
||||
|
||||
addToEnd(p_resultList, l_entry);
|
||||
}
|
||||
|
||||
static void interpret(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
|
||||
{
|
||||
pid_t l_pid = getpid();
|
||||
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
|
||||
{
|
||||
unsigned int l_nlsize = p_netlinkList->m_size;
|
||||
struct nlmsghdr *l_hdr;
|
||||
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == RTM_NEWLINK)
|
||||
{
|
||||
interpretLink(l_hdr, p_links, p_resultList);
|
||||
}
|
||||
else if(l_hdr->nlmsg_type == RTM_NEWADDR)
|
||||
{
|
||||
interpretAddr(l_hdr, p_links, p_resultList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned countLinks(int p_socket, NetlinkList *p_netlinkList)
|
||||
{
|
||||
unsigned l_links = 0;
|
||||
pid_t l_pid = getpid();
|
||||
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
|
||||
{
|
||||
unsigned int l_nlsize = p_netlinkList->m_size;
|
||||
struct nlmsghdr *l_hdr;
|
||||
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == RTM_NEWLINK)
|
||||
{
|
||||
++l_links;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return l_links;
|
||||
}
|
||||
|
||||
int getifaddrs(struct ifaddrs **ifap)
|
||||
{
|
||||
if(!ifap)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
*ifap = NULL;
|
||||
|
||||
int l_socket = netlink_socket();
|
||||
if(l_socket < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
|
||||
if(!l_linkResults)
|
||||
{
|
||||
close(l_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
|
||||
if(!l_addrResults)
|
||||
{
|
||||
close(l_socket);
|
||||
freeResultList(l_linkResults);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned l_numLinks = countLinks(l_socket, l_linkResults) + countLinks(l_socket, l_addrResults);
|
||||
struct ifaddrs *l_links[l_numLinks];
|
||||
memset(l_links, 0, l_numLinks * sizeof(struct ifaddrs *));
|
||||
|
||||
interpret(l_socket, l_linkResults, l_links, ifap);
|
||||
interpret(l_socket, l_addrResults, l_links, ifap);
|
||||
|
||||
freeResultList(l_linkResults);
|
||||
freeResultList(l_addrResults);
|
||||
close(l_socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void freeifaddrs(struct ifaddrs *ifa)
|
||||
{
|
||||
struct ifaddrs *l_cur;
|
||||
while(ifa)
|
||||
{
|
||||
l_cur = ifa;
|
||||
ifa = ifa->ifa_next;
|
||||
free(l_cur);
|
||||
}
|
||||
}
|
54
src/include/ifaddrs.h
Normal file
54
src/include/ifaddrs.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 1999
|
||||
* Berkeley Software Design, Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
|
||||
*/
|
||||
|
||||
#ifndef _IFADDRS_H_
|
||||
#define _IFADDRS_H_
|
||||
|
||||
struct ifaddrs {
|
||||
struct ifaddrs *ifa_next;
|
||||
char *ifa_name;
|
||||
unsigned int ifa_flags;
|
||||
struct sockaddr *ifa_addr;
|
||||
struct sockaddr *ifa_netmask;
|
||||
struct sockaddr *ifa_dstaddr;
|
||||
void *ifa_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* This may have been defined in <net/if.h>. Note that if <net/if.h> is
|
||||
* to be included it must be included before this header file.
|
||||
*/
|
||||
#ifndef ifa_broadaddr
|
||||
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
extern int getifaddrs(struct ifaddrs **ifap);
|
||||
extern void freeifaddrs(struct ifaddrs *ifa);
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
@ -1,3 +1,23 @@
|
||||
/* Utilities for reading/writing fstab, mtab, etc.
|
||||
Copyright (C) 1995-2000, 2001, 2002, 2003, 2006
|
||||
Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <mntent.h>
|
||||
|
@ -1,3 +1,23 @@
|
||||
/* Utilities for reading/writing fstab, mtab, etc.
|
||||
Copyright (C) 1995-2000, 2001, 2002, 2003, 2006
|
||||
Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _lxcmntent_h
|
||||
#define _lxcmntent_h
|
||||
|
||||
@ -15,6 +35,7 @@ struct mntent
|
||||
};
|
||||
|
||||
extern struct mntent *getmntent (FILE *stream);
|
||||
extern struct mntent *getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SETMNTENT
|
||||
|
@ -1,21 +1,25 @@
|
||||
/* Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
|
||||
/*
|
||||
* openpty: glibc implementation
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE /* See feature_test_macros(7) */
|
||||
#include <errno.h>
|
||||
|
@ -1,3 +1,26 @@
|
||||
/*
|
||||
* openpty: glibc implementation
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _openpty_h
|
||||
#define _openpty_h
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
if ENABLE_LUA
|
||||
|
||||
luadir=$(datadir)/lua/5.1
|
||||
sodir=$(libdir)/lua/5.1/lxc
|
||||
luadir=$(LUA_INSTALL_LMOD)
|
||||
sodir=$(LUA_INSTALL_CMOD)/lxc
|
||||
|
||||
lua_SCRIPTS=lxc.lua
|
||||
|
||||
|
@ -6,27 +6,37 @@
|
||||
* Authors:
|
||||
* Dwight Engen <dwight.engen@oracle.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define LUA_LIB
|
||||
#define _GNU_SOURCE
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <lxc/lxccontainer.h>
|
||||
|
||||
#if LUA_VERSION_NUM < 502
|
||||
#define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l))
|
||||
#define luaL_setfuncs(L,l,n) (assert(n==0), luaL_register(L,NULL,l))
|
||||
#define luaL_checkunsigned(L,n) luaL_checknumber(L,n)
|
||||
#endif
|
||||
|
||||
#ifdef NO_CHECK_UDATA
|
||||
#define checkudata(L,i,tname) lua_touserdata(L, i)
|
||||
#else
|
||||
@ -111,7 +121,7 @@ static int container_create(lua_State *L)
|
||||
argv[i] = strdupa(luaL_checkstring(L, i+3));
|
||||
argv[i] = NULL;
|
||||
|
||||
lua_pushboolean(L, !!c->create(c, template_name, argv));
|
||||
lua_pushboolean(L, !!c->create(c, template_name, NULL, NULL, 0, argv));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -372,10 +382,24 @@ static int lxc_default_config_path_get(lua_State *L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* utility functions */
|
||||
static int lxc_util_usleep(lua_State *L) {
|
||||
usleep((useconds_t)luaL_checkunsigned(L, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lxc_util_dirname(lua_State *L) {
|
||||
char *path = strdupa(luaL_checkstring(L, 1));
|
||||
lua_pushstring(L, dirname(path));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static luaL_Reg lxc_lib_methods[] = {
|
||||
{"version_get", lxc_version_get},
|
||||
{"default_config_path_get", lxc_default_config_path_get},
|
||||
{"container_new", container_new},
|
||||
{"usleep", lxc_util_usleep},
|
||||
{"dirname", lxc_util_dirname},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@ -388,7 +412,7 @@ static int lxc_lib_uninit(lua_State *L) {
|
||||
LUALIB_API int luaopen_lxc_core(lua_State *L) {
|
||||
/* this is where we would initialize liblxc.so if we needed to */
|
||||
|
||||
luaL_register(L, "lxc", lxc_lib_methods);
|
||||
luaL_newlib(L, lxc_lib_methods);
|
||||
|
||||
lua_newuserdata(L, 0);
|
||||
lua_newtable(L); /* metatable */
|
||||
@ -400,12 +424,12 @@ LUALIB_API int luaopen_lxc_core(lua_State *L) {
|
||||
lua_rawset(L, -3);
|
||||
|
||||
luaL_newmetatable(L, CONTAINER_TYPENAME);
|
||||
luaL_setfuncs(L, lxc_container_methods, 0);
|
||||
lua_pushvalue(L, -1); /* push metatable */
|
||||
lua_pushstring(L, "__gc");
|
||||
lua_pushcfunction(L, container_gc);
|
||||
lua_settable(L, -3);
|
||||
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
|
||||
luaL_register(L, NULL, lxc_container_methods);
|
||||
lua_pop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
@ -6,18 +6,19 @@
|
||||
-- Authors:
|
||||
-- Dwight Engen <dwight.engen@oracle.com>
|
||||
--
|
||||
-- This library is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License version 2, as
|
||||
-- published by the Free Software Foundation.
|
||||
-- This library is free software; you can redistribute it and/or
|
||||
-- modify it under the terms of the GNU Lesser General Public
|
||||
-- License as published by the Free Software Foundation; either
|
||||
-- version 2.1 of the License, or (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
-- This library is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
-- Lesser General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along
|
||||
-- with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
-- You should have received a copy of the GNU Lesser General Public
|
||||
-- License along with this library; if not, write to the Free Software
|
||||
-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
--
|
||||
|
||||
local core = require("lxc.core")
|
||||
@ -31,6 +32,11 @@ local lxc_path
|
||||
local cgroup_path
|
||||
local log_level = 3
|
||||
|
||||
-- lua 5.1 compat
|
||||
if table.unpack == nil then
|
||||
table.unpack = unpack
|
||||
end
|
||||
|
||||
-- the following two functions can be useful for debugging
|
||||
function printf(...)
|
||||
local function wrapper(...) io.write(string.format(...)) end
|
||||
@ -64,22 +70,6 @@ function string:split(delim, max_cols)
|
||||
return cols
|
||||
end
|
||||
|
||||
function dirname(path)
|
||||
local f,output
|
||||
f = io.popen("dirname " .. path)
|
||||
output = f:read('*all')
|
||||
f:close()
|
||||
return output:sub(1,-2)
|
||||
end
|
||||
|
||||
function basename(path, suffix)
|
||||
local f,output
|
||||
f = io.popen("basename " .. path .. " " .. (suffix or ""))
|
||||
output = f:read('*all')
|
||||
f:close()
|
||||
return output:sub(1,-2)
|
||||
end
|
||||
|
||||
function cgroup_path_get()
|
||||
local f,line,cgroup_path
|
||||
|
||||
@ -88,9 +78,12 @@ function cgroup_path_get()
|
||||
while true do
|
||||
local c
|
||||
line = f:read()
|
||||
if line == nil then
|
||||
break
|
||||
end
|
||||
c = line:split(" ", 6)
|
||||
if (c[1] == "cgroup") then
|
||||
cgroup_path = dirname(c[2])
|
||||
cgroup_path = core.dirname(c[2])
|
||||
break
|
||||
end
|
||||
end
|
||||
@ -261,7 +254,7 @@ end
|
||||
-- methods for stats collection from various cgroup files
|
||||
-- read integers at given coordinates from a cgroup file
|
||||
function container:stat_get_ints(controller, item, coords)
|
||||
local f = io.open(cgroup_path.."/"..controller.."/lxc/"..self.ctname.."/"..item, "r")
|
||||
local f = io.open(cgroup_path.."/"..controller.."/"..self.ctname.."/"..item, "r")
|
||||
local lines = {}
|
||||
local result = {}
|
||||
|
||||
@ -282,12 +275,12 @@ function container:stat_get_ints(controller, item, coords)
|
||||
table.insert(result, val)
|
||||
end
|
||||
end
|
||||
return unpack(result)
|
||||
return table.unpack(result)
|
||||
end
|
||||
|
||||
-- read an integer from a cgroup file
|
||||
function container:stat_get_int(controller, item)
|
||||
local f = io.open(cgroup_path.."/"..controller.."/lxc/"..self.ctname.."/"..item, "r")
|
||||
local f = io.open(cgroup_path.."/"..controller.."/"..self.ctname.."/"..item, "r")
|
||||
if (not f) then
|
||||
return 0
|
||||
end
|
||||
@ -301,36 +294,23 @@ end
|
||||
|
||||
function container:stat_match_get_int(controller, item, match, column)
|
||||
local val
|
||||
local f = io.open(cgroup_path.."/"..controller.."/lxc/"..self.ctname.."/"..item, "r")
|
||||
local f = io.open(cgroup_path.."/"..controller.."/"..self.ctname.."/"..item, "r")
|
||||
if (not f) then
|
||||
return 0
|
||||
end
|
||||
|
||||
for line in f:lines() do
|
||||
printf("matching line:%s with match:%s\n", line, match)
|
||||
if (string.find(line, match)) then
|
||||
local col
|
||||
|
||||
col = line:split(" ", 80)
|
||||
val = tonumber(col[column]) or 0
|
||||
printf("found line!! val:%d\n", val)
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
return val
|
||||
end
|
||||
|
||||
function stats_clear(stat)
|
||||
stat.mem_used = 0
|
||||
stat.mem_limit = 0
|
||||
stat.memsw_used = 0
|
||||
stat.memsw_limit = 0
|
||||
stat.cpu_use_nanos = 0
|
||||
stat.cpu_use_user = 0
|
||||
stat.cpu_use_sys = 0
|
||||
stat.blkio = 0
|
||||
end
|
||||
|
||||
function container:stats_get(total)
|
||||
local stat = {}
|
||||
stat.mem_used = self:stat_get_int("memory", "memory.usage_in_bytes")
|
||||
@ -355,10 +335,32 @@ function container:stats_get(total)
|
||||
return stat
|
||||
end
|
||||
|
||||
local M = { container = container }
|
||||
|
||||
function M.stats_clear(stat)
|
||||
stat.mem_used = 0
|
||||
stat.mem_limit = 0
|
||||
stat.memsw_used = 0
|
||||
stat.memsw_limit = 0
|
||||
stat.cpu_use_nanos = 0
|
||||
stat.cpu_use_user = 0
|
||||
stat.cpu_use_sys = 0
|
||||
stat.blkio = 0
|
||||
end
|
||||
|
||||
function M.stats_clear(stat)
|
||||
stat.mem_used = 0
|
||||
stat.mem_limit = 0
|
||||
stat.memsw_used = 0
|
||||
stat.memsw_limit = 0
|
||||
stat.cpu_use_nanos = 0
|
||||
stat.cpu_use_user = 0
|
||||
stat.cpu_use_sys = 0
|
||||
stat.blkio = 0
|
||||
end
|
||||
|
||||
-- return configured containers found in LXC_PATH directory
|
||||
function containers_configured(names_only)
|
||||
function M.containers_configured(names_only)
|
||||
local containers = {}
|
||||
|
||||
for dir in lfs.dir(lxc_path) do
|
||||
@ -386,39 +388,29 @@ function containers_configured(names_only)
|
||||
end
|
||||
|
||||
-- return running containers found in cgroup fs
|
||||
function containers_running(names_only)
|
||||
function M.containers_running(names_only)
|
||||
local containers = {}
|
||||
local attr
|
||||
local names = M.containers_configured(true)
|
||||
|
||||
-- the lxc directory won't exist if no containers has ever been started
|
||||
attr = lfs.attributes(cgroup_path .. "/cpu/lxc")
|
||||
if (not attr) then
|
||||
return containers
|
||||
end
|
||||
|
||||
for file in lfs.dir(cgroup_path .. "/cpu/lxc") do
|
||||
if (file ~= "." and file ~= "..")
|
||||
then
|
||||
local pathfile = cgroup_path .. "/cpu/lxc/" .. file
|
||||
local attr = lfs.attributes(pathfile)
|
||||
|
||||
if (attr.mode == "directory") then
|
||||
for _,name in ipairs(names) do
|
||||
local ct = container:new(name)
|
||||
if ct:running() then
|
||||
-- note, this is a "mixed" table, ie both dictionary and list
|
||||
table.insert(containers, name)
|
||||
if (names_only) then
|
||||
-- note, this is a "mixed" table, ie both dictionary and list
|
||||
containers[file] = true
|
||||
table.insert(containers, file)
|
||||
containers[name] = true
|
||||
ct = nil
|
||||
else
|
||||
local ct = container:new(file)
|
||||
-- note, this is a "mixed" table, ie both dictionary and list
|
||||
containers[file] = ct
|
||||
table.insert(containers, file)
|
||||
containers[name] = ct
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(containers, function (a,b) return (a < b) end)
|
||||
return containers
|
||||
end
|
||||
|
||||
lxc_path = core.default_config_path_get()
|
||||
cgroup_path = cgroup_path_get()
|
||||
|
||||
return M
|
||||
|
@ -1,25 +1,28 @@
|
||||
pkginclude_HEADERS = \
|
||||
arguments.h \
|
||||
start.h \
|
||||
console.h \
|
||||
error.h \
|
||||
monitor.h \
|
||||
utils.h \
|
||||
namespace.h \
|
||||
attach.h \
|
||||
attach_options.h \
|
||||
bdev.h \
|
||||
caps.h \
|
||||
lxc.h \
|
||||
cgroup.h \
|
||||
conf.h \
|
||||
console.h \
|
||||
error.h \
|
||||
list.h \
|
||||
log.h \
|
||||
state.h \
|
||||
attach.h \
|
||||
lxccontainer.h \
|
||||
lxc.h \
|
||||
lxclock.h \
|
||||
monitor.h \
|
||||
namespace.h \
|
||||
start.h \
|
||||
state.h \
|
||||
utils.h \
|
||||
version.h
|
||||
|
||||
if IS_BIONIC
|
||||
pkginclude_HEADERS += \
|
||||
../include/ifaddrs.h \
|
||||
../include/openpty.h \
|
||||
../include/lxcmntent.h
|
||||
endif
|
||||
@ -36,9 +39,9 @@ so_PROGRAMS = liblxc.so
|
||||
|
||||
liblxc_so_SOURCES = \
|
||||
arguments.c arguments.h \
|
||||
bdev.c bdev.h \
|
||||
commands.c commands.h \
|
||||
start.c start.h \
|
||||
stop.c \
|
||||
execute.c \
|
||||
monitor.c monitor.h \
|
||||
console.c \
|
||||
@ -60,9 +63,9 @@ liblxc_so_SOURCES = \
|
||||
attach.c attach.h \
|
||||
\
|
||||
network.c network.h \
|
||||
nl.c nl.h \
|
||||
rtnl.c rtnl.h \
|
||||
genl.c genl.h \
|
||||
nl.c nl.h \
|
||||
rtnl.c rtnl.h \
|
||||
genl.c genl.h \
|
||||
\
|
||||
caps.c caps.h \
|
||||
lxcseccomp.h \
|
||||
@ -77,6 +80,7 @@ liblxc_so_SOURCES = \
|
||||
|
||||
if IS_BIONIC
|
||||
liblxc_so_SOURCES += \
|
||||
../include/ifaddrs.c ../include/ifaddrs.h \
|
||||
../include/openpty.c ../include/openpty.h \
|
||||
../include/lxcmntent.c ../include/lxcmntent.h
|
||||
endif
|
||||
@ -93,12 +97,19 @@ AM_CFLAGS=-I$(top_srcdir)/src \
|
||||
-DLXC_GLOBAL_CONF=\"$(LXC_GLOBAL_CONF)\" \
|
||||
-DLXCINITDIR=\"$(LXCINITDIR)\" \
|
||||
-DLXCTEMPLATEDIR=\"$(LXCTEMPLATEDIR)\" \
|
||||
-DLOGPATH=\"$(LOGPATH)\"
|
||||
-DLOGPATH=\"$(LOGPATH)\" \
|
||||
-DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\" \
|
||||
-DLXC_USERNIC_DB=\"$(LXC_USERNIC_DB)\" \
|
||||
-DLXC_USERNIC_CONF=\"$(LXC_USERNIC_CONF)\"
|
||||
|
||||
if ENABLE_APPARMOR
|
||||
AM_CFLAGS += -DHAVE_APPARMOR
|
||||
endif
|
||||
|
||||
if HAVE_NEWUIDMAP
|
||||
AM_CFLAGS += -DHAVE_NEWUIDMAP
|
||||
endif
|
||||
|
||||
if USE_CONFIGPATH_LOGS
|
||||
AM_CFLAGS += -DUSE_CONFIGPATH_LOGS
|
||||
endif
|
||||
@ -120,11 +131,7 @@ bin_SCRIPTS = \
|
||||
lxc-ps \
|
||||
lxc-netstat \
|
||||
lxc-checkconfig \
|
||||
lxc-version \
|
||||
lxc-create \
|
||||
lxc-clone \
|
||||
lxc-shutdown \
|
||||
lxc-destroy
|
||||
lxc-version
|
||||
|
||||
EXTRA_DIST = \
|
||||
lxc-device \
|
||||
@ -132,15 +139,15 @@ EXTRA_DIST = \
|
||||
lxc-top
|
||||
|
||||
if ENABLE_PYTHON
|
||||
bin_SCRIPTS += lxc-device
|
||||
bin_SCRIPTS += lxc-ls
|
||||
bin_SCRIPTS += lxc-start-ephemeral
|
||||
bin_SCRIPTS += lxc-device
|
||||
bin_SCRIPTS += lxc-ls
|
||||
bin_SCRIPTS += lxc-start-ephemeral
|
||||
else
|
||||
bin_SCRIPTS += legacy/lxc-ls
|
||||
bin_SCRIPTS += legacy/lxc-ls
|
||||
endif
|
||||
|
||||
if ENABLE_LUA
|
||||
bin_SCRIPTS += lxc-top
|
||||
bin_SCRIPTS += lxc-top
|
||||
endif
|
||||
|
||||
bin_PROGRAMS = \
|
||||
@ -148,8 +155,10 @@ bin_PROGRAMS = \
|
||||
lxc-unshare \
|
||||
lxc-stop \
|
||||
lxc-start \
|
||||
lxc-clone \
|
||||
lxc-execute \
|
||||
lxc-monitor \
|
||||
lxc-monitord \
|
||||
lxc-wait \
|
||||
lxc-console \
|
||||
lxc-freeze \
|
||||
@ -158,14 +167,19 @@ bin_PROGRAMS = \
|
||||
lxc-unfreeze \
|
||||
lxc-checkpoint \
|
||||
lxc-restart \
|
||||
lxc-kill
|
||||
lxc-kill \
|
||||
lxc-config \
|
||||
lxc-destroy \
|
||||
lxc-create \
|
||||
lxc-user-nic
|
||||
|
||||
if HAVE_NEWUIDMAP
|
||||
bin_PROGRAMS += lxc-usernsexec
|
||||
endif
|
||||
|
||||
pkglibexec_PROGRAMS = \
|
||||
lxc-init
|
||||
|
||||
#pkglibexec_SCRIPTS = \
|
||||
# lxc.functions
|
||||
|
||||
AM_LDFLAGS = -Wl,-E
|
||||
if ENABLE_RPATH
|
||||
AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
|
||||
@ -175,19 +189,26 @@ LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SECCOMP_LIBS@
|
||||
lxc_attach_SOURCES = lxc_attach.c
|
||||
lxc_cgroup_SOURCES = lxc_cgroup.c
|
||||
lxc_checkpoint_SOURCES = lxc_checkpoint.c
|
||||
lxc_config_SOURCES = lxc_config.c
|
||||
lxc_console_SOURCES = lxc_console.c
|
||||
lxc_destroy_SOURCES = lxc_destroy.c
|
||||
lxc_execute_SOURCES = lxc_execute.c
|
||||
lxc_freeze_SOURCES = lxc_freeze.c
|
||||
lxc_info_SOURCES = lxc_info.c
|
||||
lxc_init_SOURCES = lxc_init.c
|
||||
lxc_monitor_SOURCES = lxc_monitor.c
|
||||
lxc_monitord_SOURCES = lxc_monitord.c
|
||||
lxc_restart_SOURCES = lxc_restart.c
|
||||
lxc_clone_SOURCES = lxc_clone.c
|
||||
lxc_start_SOURCES = lxc_start.c
|
||||
lxc_stop_SOURCES = lxc_stop.c
|
||||
lxc_unfreeze_SOURCES = lxc_unfreeze.c
|
||||
lxc_unshare_SOURCES = lxc_unshare.c
|
||||
lxc_wait_SOURCES = lxc_wait.c
|
||||
lxc_kill_SOURCES = lxc_kill.c
|
||||
lxc_create_SOURCES = lxc_create.c
|
||||
lxc_usernsexec_SOURCES = lxc_usernsexec.c
|
||||
lxc_user_nic_SOURCES = lxc_user_nic.c
|
||||
|
||||
install-exec-local: install-soPROGRAMS
|
||||
mkdir -p $(DESTDIR)$(datadir)/lxc
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@ -36,6 +36,7 @@ lxc_log_define(lxc_af_unix, lxc);
|
||||
int lxc_af_unix_open(const char *path, int type, int flags)
|
||||
{
|
||||
int fd;
|
||||
size_t len;
|
||||
struct sockaddr_un addr;
|
||||
|
||||
if (flags & O_TRUNC)
|
||||
@ -52,8 +53,16 @@ int lxc_af_unix_open(const char *path, int type, int flags)
|
||||
|
||||
addr.sun_family = AF_UNIX;
|
||||
/* copy entire buffer in case of abstract socket */
|
||||
memcpy(addr.sun_path, path,
|
||||
path[0]?strlen(path):sizeof(addr.sun_path));
|
||||
len = sizeof(addr.sun_path);
|
||||
if (path[0]) {
|
||||
len = strlen(path);
|
||||
if (len >= sizeof(addr.sun_path)) {
|
||||
close(fd);
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
memcpy(addr.sun_path, path, len);
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
|
||||
int tmp = errno;
|
||||
@ -61,7 +70,7 @@ int lxc_af_unix_open(const char *path, int type, int flags)
|
||||
errno = tmp;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (type == SOCK_STREAM && listen(fd, 100)) {
|
||||
int tmp = errno;
|
||||
close(fd);
|
||||
@ -75,8 +84,8 @@ int lxc_af_unix_open(const char *path, int type, int flags)
|
||||
int lxc_af_unix_close(int fd)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
|
||||
if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) &&
|
||||
addr.sun_path[0])
|
||||
unlink(addr.sun_path);
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
extern int lxc_af_unix_open(const char *path, int type, int flags);
|
||||
|
@ -1,3 +1,23 @@
|
||||
/* apparmor
|
||||
*
|
||||
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
|
||||
* Copyright © 2012 Canonical Ltd.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@ -36,16 +56,19 @@ again:
|
||||
f = fopen(path, "r");
|
||||
if (!f) {
|
||||
SYSERROR("opening %s\n", path);
|
||||
if (buf)
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
sz += 1024;
|
||||
buf = realloc(buf, sz);
|
||||
memset(buf, 0, sz);
|
||||
if (!buf) {
|
||||
ERROR("out of memory");
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
ret = fread(buf, 1, sz, f);
|
||||
ret = fread(buf, 1, sz - 1, f);
|
||||
fclose(f);
|
||||
if (ret >= sz)
|
||||
goto again;
|
||||
|
@ -1,3 +1,23 @@
|
||||
/* apparmor
|
||||
*
|
||||
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
|
||||
* Copyright © 2012 Canonical Ltd.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <lxc/start.h> /* for lxc_handler */
|
||||
#include <lxc/conf.h>
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -147,16 +147,37 @@ for any corresponding short options.\n\
|
||||
See the %s man page for further information.\n\n",
|
||||
args->progname, args->help, args->progname);
|
||||
|
||||
if (args->helpfn)
|
||||
args->helpfn(args);
|
||||
exit(code);
|
||||
}
|
||||
|
||||
static int lxc_arguments_lxcpath_add(struct lxc_arguments *args,
|
||||
const char *lxcpath)
|
||||
{
|
||||
if (args->lxcpath_additional != -1 &&
|
||||
args->lxcpath_cnt > args->lxcpath_additional) {
|
||||
fprintf(stderr, "This command only accepts %d -P,--lxcpath arguments\n",
|
||||
args->lxcpath_additional + 1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
args->lxcpath = realloc(args->lxcpath, (args->lxcpath_cnt + 1) *
|
||||
sizeof(args->lxcpath[0]));
|
||||
if (args->lxcpath == NULL) {
|
||||
lxc_error(args, "no memory");
|
||||
return -ENOMEM;
|
||||
}
|
||||
args->lxcpath[args->lxcpath_cnt++] = lxcpath;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int lxc_arguments_parse(struct lxc_arguments *args,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
char shortopts[256];
|
||||
int ret = 0;
|
||||
|
||||
args->lxcpath = default_lxc_path();
|
||||
ret = build_shortopts(args->options, shortopts, sizeof(shortopts));
|
||||
if (ret < 0) {
|
||||
lxc_error(args, "build_shortopts() failed : %s",
|
||||
@ -174,9 +195,12 @@ extern int lxc_arguments_parse(struct lxc_arguments *args,
|
||||
case 'n': args->name = optarg; break;
|
||||
case 'o': args->log_file = optarg; break;
|
||||
case 'l': args->log_priority = optarg; break;
|
||||
case 'c': args->console = optarg; break;
|
||||
case 'q': args->quiet = 1; break;
|
||||
case 'P': args->lxcpath = optarg; break;
|
||||
case 'P':
|
||||
ret = lxc_arguments_lxcpath_add(args, optarg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
case OPT_USAGE: print_usage(args->options, args);
|
||||
case '?': print_help(args, 1);
|
||||
case 'h': print_help(args, 0);
|
||||
@ -195,6 +219,13 @@ extern int lxc_arguments_parse(struct lxc_arguments *args,
|
||||
args->argv = &argv[optind];
|
||||
args->argc = argc - optind;
|
||||
|
||||
/* If no lxcpaths were given, use default */
|
||||
if (!args->lxcpath_cnt) {
|
||||
ret = lxc_arguments_lxcpath_add(args, default_lxc_path());
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check the command options */
|
||||
|
||||
if (!args->name) {
|
||||
|
@ -19,7 +19,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __arguments_h
|
||||
#define __arguments_h
|
||||
@ -33,6 +33,7 @@ typedef int (*lxc_arguments_checker_t) (const struct lxc_arguments *);
|
||||
|
||||
struct lxc_arguments {
|
||||
const char *help;
|
||||
void(*helpfn)(const struct lxc_arguments *);
|
||||
const char *progname;
|
||||
const struct option* options;
|
||||
lxc_arguments_parser_t parser;
|
||||
@ -47,7 +48,10 @@ struct lxc_arguments {
|
||||
const char *console;
|
||||
const char *console_log;
|
||||
const char *pidfile;
|
||||
const char *lxcpath;
|
||||
const char **lxcpath;
|
||||
int lxcpath_cnt;
|
||||
/* set to 0 to accept only 1 lxcpath, -1 for unlimited */
|
||||
int lxcpath_additional;
|
||||
|
||||
/* for lxc-checkpoint/restart */
|
||||
const char *statefile;
|
||||
@ -58,13 +62,27 @@ struct lxc_arguments {
|
||||
int ttynum;
|
||||
char escape;
|
||||
|
||||
/* for lxc-wait */
|
||||
/* for lxc-wait and lxc-shutdown */
|
||||
char *states;
|
||||
long timeout;
|
||||
int nowait;
|
||||
int reboot;
|
||||
int hardstop;
|
||||
int shutdown;
|
||||
|
||||
/* for lxc-destroy */
|
||||
int force;
|
||||
|
||||
/* close fds from parent? */
|
||||
int close_all_fds;
|
||||
|
||||
/* lxc-create */
|
||||
char *bdevtype, *configfile, *template;
|
||||
char *fstype;
|
||||
unsigned long fssize;
|
||||
char *lvname, *vgname;
|
||||
char *zfsroot, *lowerdir, *dir;
|
||||
|
||||
/* remaining arguments */
|
||||
char *const *argv;
|
||||
int argc;
|
||||
|
649
src/lxc/attach.c
649
src/lxc/attach.c
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
@ -31,6 +31,7 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <linux/unistd.h>
|
||||
@ -46,42 +47,20 @@
|
||||
#include "caps.h"
|
||||
#include "config.h"
|
||||
#include "apparmor.h"
|
||||
#include "utils.h"
|
||||
#include "commands.h"
|
||||
#include "cgroup.h"
|
||||
|
||||
#if HAVE_SYS_PERSONALITY_H
|
||||
#include <sys/personality.h>
|
||||
#endif
|
||||
|
||||
#ifndef SOCK_CLOEXEC
|
||||
# define SOCK_CLOEXEC 02000000
|
||||
#endif
|
||||
|
||||
lxc_log_define(lxc_attach, lxc);
|
||||
|
||||
/* Define setns() if missing from the C library */
|
||||
#ifndef HAVE_SETNS
|
||||
static int setns(int fd, int nstype)
|
||||
{
|
||||
#ifdef __NR_setns
|
||||
return syscall(__NR_setns, fd, nstype);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Define unshare() if missing from the C library */
|
||||
#ifndef HAVE_UNSHARE
|
||||
static int unshare(int flags)
|
||||
{
|
||||
#ifdef __NR_unshare
|
||||
return syscall(__NR_unshare, flags);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Define getline() if missing from the C library */
|
||||
#ifndef HAVE_GETLINE
|
||||
#ifdef HAVE_FGETLN
|
||||
#include <../include/getline.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
|
||||
{
|
||||
struct lxc_proc_context_info *info = calloc(1, sizeof(*info));
|
||||
@ -114,6 +93,8 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
|
||||
}
|
||||
}
|
||||
|
||||
if (line)
|
||||
free(line);
|
||||
fclose(proc_file);
|
||||
|
||||
if (!found) {
|
||||
@ -145,7 +126,6 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
|
||||
|
||||
out_error:
|
||||
free(info);
|
||||
free(line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -182,7 +162,7 @@ int lxc_attach_to_ns(pid_t pid, int which)
|
||||
}
|
||||
|
||||
snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]);
|
||||
fd[i] = open(path, O_RDONLY);
|
||||
fd[i] = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd[i] < 0) {
|
||||
saved_errno = errno;
|
||||
|
||||
@ -279,23 +259,83 @@ int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
|
||||
|
||||
int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char** extra_env, char** extra_keep)
|
||||
{
|
||||
/* TODO: implement extra_env, extra_keep
|
||||
* Rationale:
|
||||
* - extra_env is an array of strings of the form
|
||||
* "VAR=VALUE", which are to be set (after clearing or not,
|
||||
* depending on the value of the policy variable)
|
||||
* - extra_keep is an array of strings of the form
|
||||
* "VAR", which are extra environment variables to be kept
|
||||
* around after clearing (if that is done, otherwise, the
|
||||
* remain anyway)
|
||||
*/
|
||||
(void) extra_env;
|
||||
(void) extra_keep;
|
||||
|
||||
if (policy == LXC_ATTACH_CLEAR_ENV) {
|
||||
char **extra_keep_store = NULL;
|
||||
int path_kept = 0;
|
||||
|
||||
if (extra_keep) {
|
||||
size_t count, i;
|
||||
|
||||
for (count = 0; extra_keep[count]; count++);
|
||||
|
||||
extra_keep_store = calloc(count, sizeof(char *));
|
||||
if (!extra_keep_store) {
|
||||
SYSERROR("failed to allocate memory for storing current "
|
||||
"environment variable values that will be kept");
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
char *v = getenv(extra_keep[i]);
|
||||
if (v) {
|
||||
extra_keep_store[i] = strdup(v);
|
||||
if (!extra_keep_store[i]) {
|
||||
SYSERROR("failed to allocate memory for storing current "
|
||||
"environment variable values that will be kept");
|
||||
while (i > 0)
|
||||
free(extra_keep_store[--i]);
|
||||
free(extra_keep_store);
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(extra_keep[i], "PATH") == 0)
|
||||
path_kept = 1;
|
||||
}
|
||||
/* calloc sets entire array to zero, so we don't
|
||||
* need an else */
|
||||
}
|
||||
}
|
||||
|
||||
if (clearenv()) {
|
||||
char **p;
|
||||
SYSERROR("failed to clear environment");
|
||||
/* don't error out though */
|
||||
if (extra_keep_store) {
|
||||
for (p = extra_keep_store; *p; p++)
|
||||
free(*p);
|
||||
free(extra_keep_store);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (extra_keep_store) {
|
||||
size_t i;
|
||||
for (i = 0; extra_keep[i]; i++) {
|
||||
if (extra_keep_store[i])
|
||||
setenv(extra_keep[i], extra_keep_store[i], 1);
|
||||
free(extra_keep_store[i]);
|
||||
}
|
||||
free(extra_keep_store);
|
||||
}
|
||||
|
||||
/* always set a default path; shells and execlp tend
|
||||
* to be fine without it, but there is a disturbing
|
||||
* number of C programs out there that just assume
|
||||
* that getenv("PATH") is never NULL and then die a
|
||||
* painful segfault death. */
|
||||
if (!path_kept) {
|
||||
#ifdef HAVE_CONFSTR
|
||||
size_t n;
|
||||
char *path_env;
|
||||
|
||||
n = confstr(_CS_PATH, NULL, 0);
|
||||
path_env = malloc(n);
|
||||
if (path_env) {
|
||||
confstr(_CS_PATH, path_env, n);
|
||||
setenv("PATH", path_env, 1);
|
||||
free(path_env);
|
||||
}
|
||||
/* don't error out, this is just an extra service */
|
||||
#else
|
||||
setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,6 +344,24 @@ int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char** extra
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set extra environment variables */
|
||||
if (extra_env) {
|
||||
for (; *extra_env; extra_env++) {
|
||||
/* duplicate the string, just to be on
|
||||
* the safe side, because putenv does not
|
||||
* do it for us */
|
||||
char *p = strdup(*extra_env);
|
||||
/* we just assume the user knows what they
|
||||
* are doing, so we don't do any checks */
|
||||
if (!p) {
|
||||
SYSERROR("failed to allocate memory for additional environment "
|
||||
"variables");
|
||||
return -1;
|
||||
}
|
||||
putenv(p);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -358,7 +416,7 @@ char *lxc_attach_getpwshell(uid_t uid)
|
||||
continue;
|
||||
|
||||
/* trim line on the right hand side */
|
||||
for (i = strlen(line); line && i > 0 && (line[i - 1] == '\n' || line[i - 1] == '\r'); --i)
|
||||
for (i = strlen(line); i > 0 && (line[i - 1] == '\n' || line[i - 1] == '\r'); --i)
|
||||
line[i - 1] = '\0';
|
||||
|
||||
/* split into tokens: first user name */
|
||||
@ -507,3 +565,492 @@ void lxc_attach_get_init_uidgid(uid_t* init_uid, gid_t* init_gid)
|
||||
/* TODO: we should also parse supplementary groups and use
|
||||
* setgroups() to set them */
|
||||
}
|
||||
|
||||
struct attach_clone_payload {
|
||||
int ipc_socket;
|
||||
lxc_attach_options_t* options;
|
||||
struct lxc_proc_context_info* init_ctx;
|
||||
lxc_attach_exec_t exec_function;
|
||||
void* exec_payload;
|
||||
};
|
||||
|
||||
static int attach_child_main(void* data);
|
||||
|
||||
/* help the optimizer along if it doesn't know that exit always exits */
|
||||
#define rexit(c) do { int __c = (c); exit(__c); return __c; } while(0)
|
||||
|
||||
/* define default options if no options are supplied by the user */
|
||||
static lxc_attach_options_t attach_static_default_options = LXC_ATTACH_OPTIONS_DEFAULT;
|
||||
|
||||
int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_function, void* exec_payload, lxc_attach_options_t* options, pid_t* attached_process)
|
||||
{
|
||||
int ret, status;
|
||||
pid_t init_pid, pid, attached_pid;
|
||||
struct lxc_proc_context_info *init_ctx;
|
||||
char* cwd;
|
||||
char* new_cwd;
|
||||
int ipc_sockets[2];
|
||||
|
||||
if (!options)
|
||||
options = &attach_static_default_options;
|
||||
|
||||
init_pid = lxc_cmd_get_init_pid(name, lxcpath);
|
||||
if (init_pid < 0) {
|
||||
ERROR("failed to get the init pid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
init_ctx = lxc_proc_get_context_info(init_pid);
|
||||
if (!init_ctx) {
|
||||
ERROR("failed to get context of the init process, pid = %ld", (long)init_pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cwd = getcwd(NULL, 0);
|
||||
|
||||
/* determine which namespaces the container was created with
|
||||
* by asking lxc-start, if necessary
|
||||
*/
|
||||
if (options->namespaces == -1) {
|
||||
options->namespaces = lxc_cmd_get_clone_flags(name, lxcpath);
|
||||
/* call failed */
|
||||
if (options->namespaces == -1) {
|
||||
ERROR("failed to automatically determine the "
|
||||
"namespaces which the container unshared");
|
||||
free(cwd);
|
||||
free(init_ctx->aa_profile);
|
||||
free(init_ctx);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* create a socket pair for IPC communication; set SOCK_CLOEXEC in order
|
||||
* to make sure we don't irritate other threads that want to fork+exec away
|
||||
*
|
||||
* IMPORTANT: if the initial process is multithreaded and another call
|
||||
* just fork()s away without exec'ing directly after, the socket fd will
|
||||
* exist in the forked process from the other thread and any close() in
|
||||
* our own child process will not really cause the socket to close properly,
|
||||
* potentiall causing the parent to hang.
|
||||
*
|
||||
* For this reason, while IPC is still active, we have to use shutdown()
|
||||
* if the child exits prematurely in order to signal that the socket
|
||||
* is closed and cannot assume that the child exiting will automatically
|
||||
* do that.
|
||||
*
|
||||
* IPC mechanism: (X is receiver)
|
||||
* initial process intermediate attached
|
||||
* X <--- send pid of
|
||||
* attached proc,
|
||||
* then exit
|
||||
* send 0 ------------------------------------> X
|
||||
* [do initialization]
|
||||
* X <------------------------------------ send 1
|
||||
* [add to cgroup, ...]
|
||||
* send 2 ------------------------------------> X
|
||||
* close socket close socket
|
||||
* run program
|
||||
*/
|
||||
ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
|
||||
if (ret < 0) {
|
||||
SYSERROR("could not set up required IPC mechanism for attaching");
|
||||
free(cwd);
|
||||
free(init_ctx->aa_profile);
|
||||
free(init_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create intermediate subprocess, three reasons:
|
||||
* 1. runs all pthread_atfork handlers and the
|
||||
* child will no longer be threaded
|
||||
* (we can't properly setns() in a threaded process)
|
||||
* 2. we can't setns() in the child itself, since
|
||||
* we want to make sure we are properly attached to
|
||||
* the pidns
|
||||
* 3. also, the initial thread has to put the attached
|
||||
* process into the cgroup, which we can only do if
|
||||
* we didn't already setns() (otherwise, user
|
||||
* namespaces will hate us)
|
||||
*/
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
SYSERROR("failed to create first subprocess");
|
||||
free(cwd);
|
||||
free(init_ctx->aa_profile);
|
||||
free(init_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid) {
|
||||
pid_t to_cleanup_pid = pid;
|
||||
int expected = 0;
|
||||
|
||||
/* inital thread, we close the socket that is for the
|
||||
* subprocesses
|
||||
*/
|
||||
close(ipc_sockets[1]);
|
||||
free(cwd);
|
||||
|
||||
/* get pid from intermediate process */
|
||||
ret = lxc_read_nointr_expect(ipc_sockets[0], &attached_pid, sizeof(attached_pid), NULL);
|
||||
if (ret <= 0) {
|
||||
if (ret != 0)
|
||||
ERROR("error using IPC to receive pid of attached process");
|
||||
goto cleanup_error;
|
||||
}
|
||||
|
||||
/* reap intermediate process */
|
||||
ret = wait_for_pid(pid);
|
||||
if (ret < 0)
|
||||
goto cleanup_error;
|
||||
|
||||
/* we will always have to reap the grandchild now */
|
||||
to_cleanup_pid = attached_pid;
|
||||
|
||||
/* tell attached process it may start initializing */
|
||||
status = 0;
|
||||
ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
|
||||
if (ret <= 0) {
|
||||
ERROR("error using IPC to notify attached process for initialization (0)");
|
||||
goto cleanup_error;
|
||||
}
|
||||
|
||||
/* wait for the attached process to finish initializing */
|
||||
expected = 1;
|
||||
ret = lxc_read_nointr_expect(ipc_sockets[0], &status, sizeof(status), &expected);
|
||||
if (ret <= 0) {
|
||||
if (ret != 0)
|
||||
ERROR("error using IPC to receive notification from attached process (1)");
|
||||
goto cleanup_error;
|
||||
}
|
||||
|
||||
/* attach to cgroup, if requested */
|
||||
if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
|
||||
ret = lxc_cgroup_attach(attached_pid, name, lxcpath);
|
||||
if (ret < 0) {
|
||||
ERROR("could not move attached process %ld to cgroup of container", (long)attached_pid);
|
||||
goto cleanup_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* tell attached process we're done */
|
||||
status = 2;
|
||||
ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status));
|
||||
if (ret <= 0) {
|
||||
ERROR("error using IPC to notify attached process for initialization (2)");
|
||||
goto cleanup_error;
|
||||
}
|
||||
|
||||
/* now shut down communication with child, we're done */
|
||||
shutdown(ipc_sockets[0], SHUT_RDWR);
|
||||
close(ipc_sockets[0]);
|
||||
free(init_ctx->aa_profile);
|
||||
free(init_ctx);
|
||||
|
||||
/* we're done, the child process should now execute whatever
|
||||
* it is that the user requested. The parent can now track it
|
||||
* with waitpid() or similar.
|
||||
*/
|
||||
|
||||
*attached_process = attached_pid;
|
||||
return 0;
|
||||
|
||||
cleanup_error:
|
||||
/* first shut down the socket, then wait for the pid,
|
||||
* otherwise the pid we're waiting for may never exit
|
||||
*/
|
||||
shutdown(ipc_sockets[0], SHUT_RDWR);
|
||||
close(ipc_sockets[0]);
|
||||
if (to_cleanup_pid)
|
||||
(void) wait_for_pid(to_cleanup_pid);
|
||||
free(init_ctx->aa_profile);
|
||||
free(init_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* first subprocess begins here, we close the socket that is for the
|
||||
* initial thread
|
||||
*/
|
||||
close(ipc_sockets[0]);
|
||||
|
||||
/* attach now, create another subprocess later, since pid namespaces
|
||||
* only really affect the children of the current process
|
||||
*/
|
||||
ret = lxc_attach_to_ns(init_pid, options->namespaces);
|
||||
if (ret < 0) {
|
||||
ERROR("failed to enter the namespace");
|
||||
shutdown(ipc_sockets[1], SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
|
||||
/* attach succeeded, try to cwd */
|
||||
if (options->initial_cwd)
|
||||
new_cwd = options->initial_cwd;
|
||||
else
|
||||
new_cwd = cwd;
|
||||
ret = chdir(new_cwd);
|
||||
if (ret < 0)
|
||||
WARN("could not change directory to '%s'", new_cwd);
|
||||
free(cwd);
|
||||
|
||||
/* now create the real child process */
|
||||
{
|
||||
struct attach_clone_payload payload = {
|
||||
.ipc_socket = ipc_sockets[1],
|
||||
.options = options,
|
||||
.init_ctx = init_ctx,
|
||||
.exec_function = exec_function,
|
||||
.exec_payload = exec_payload
|
||||
};
|
||||
/* We use clone_parent here to make this subprocess a direct child of
|
||||
* the initial process. Then this intermediate process can exit and
|
||||
* the parent can directly track the attached process.
|
||||
*/
|
||||
pid = lxc_clone(attach_child_main, &payload, CLONE_PARENT);
|
||||
}
|
||||
|
||||
/* shouldn't happen, clone() should always return positive pid */
|
||||
if (pid <= 0) {
|
||||
SYSERROR("failed to create subprocess");
|
||||
shutdown(ipc_sockets[1], SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
|
||||
/* tell grandparent the pid of the pid of the newly created child */
|
||||
ret = lxc_write_nointr(ipc_sockets[1], &pid, sizeof(pid));
|
||||
if (ret != sizeof(pid)) {
|
||||
/* if this really happens here, this is very unfortunate, since the
|
||||
* parent will not know the pid of the attached process and will
|
||||
* not be able to wait for it (and we won't either due to CLONE_PARENT)
|
||||
* so the parent won't be able to reap it and the attached process
|
||||
* will remain a zombie
|
||||
*/
|
||||
ERROR("error using IPC to notify main process of pid of the attached process");
|
||||
shutdown(ipc_sockets[1], SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
|
||||
/* the rest is in the hands of the initial and the attached process */
|
||||
rexit(0);
|
||||
}
|
||||
|
||||
int attach_child_main(void* data)
|
||||
{
|
||||
struct attach_clone_payload* payload = (struct attach_clone_payload*)data;
|
||||
int ipc_socket = payload->ipc_socket;
|
||||
lxc_attach_options_t* options = payload->options;
|
||||
struct lxc_proc_context_info* init_ctx = payload->init_ctx;
|
||||
#if HAVE_SYS_PERSONALITY_H
|
||||
long new_personality;
|
||||
#endif
|
||||
int ret;
|
||||
int status;
|
||||
int expected;
|
||||
long flags;
|
||||
int fd;
|
||||
uid_t new_uid;
|
||||
gid_t new_gid;
|
||||
|
||||
/* wait for the initial thread to signal us that it's ready
|
||||
* for us to start initializing
|
||||
*/
|
||||
expected = 0;
|
||||
status = -1;
|
||||
ret = lxc_read_nointr_expect(ipc_socket, &status, sizeof(status), &expected);
|
||||
if (ret <= 0) {
|
||||
ERROR("error using IPC to receive notification from initial process (0)");
|
||||
shutdown(ipc_socket, SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
|
||||
/* load apparmor profile */
|
||||
if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_APPARMOR)) {
|
||||
ret = attach_apparmor(init_ctx->aa_profile);
|
||||
if (ret < 0) {
|
||||
shutdown(ipc_socket, SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* A description of the purpose of this functionality is
|
||||
* provided in the lxc-attach(1) manual page. We have to
|
||||
* remount here and not in the parent process, otherwise
|
||||
* /proc may not properly reflect the new pid namespace.
|
||||
*/
|
||||
if (!(options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_REMOUNT_PROC_SYS)) {
|
||||
ret = lxc_attach_remount_sys_proc();
|
||||
if (ret < 0) {
|
||||
shutdown(ipc_socket, SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* now perform additional attachments*/
|
||||
#if HAVE_SYS_PERSONALITY_H
|
||||
if (options->personality < 0)
|
||||
new_personality = init_ctx->personality;
|
||||
else
|
||||
new_personality = options->personality;
|
||||
|
||||
if (options->attach_flags & LXC_ATTACH_SET_PERSONALITY) {
|
||||
ret = personality(new_personality);
|
||||
if (ret < 0) {
|
||||
SYSERROR("could not ensure correct architecture");
|
||||
shutdown(ipc_socket, SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (options->attach_flags & LXC_ATTACH_DROP_CAPABILITIES) {
|
||||
ret = lxc_attach_drop_privs(init_ctx);
|
||||
if (ret < 0) {
|
||||
ERROR("could not drop privileges");
|
||||
shutdown(ipc_socket, SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* always set the environment (specify (LXC_ATTACH_KEEP_ENV, NULL, NULL) if you want this to be a no-op) */
|
||||
ret = lxc_attach_set_environment(options->env_policy, options->extra_env_vars, options->extra_keep_env);
|
||||
if (ret < 0) {
|
||||
ERROR("could not set initial environment for attached process");
|
||||
shutdown(ipc_socket, SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
|
||||
/* set user / group id */
|
||||
new_uid = 0;
|
||||
new_gid = 0;
|
||||
/* ignore errors, we will fall back to root in that case
|
||||
* (/proc was not mounted etc.)
|
||||
*/
|
||||
if (options->namespaces & CLONE_NEWUSER)
|
||||
lxc_attach_get_init_uidgid(&new_uid, &new_gid);
|
||||
|
||||
if (options->uid != (uid_t)-1)
|
||||
new_uid = options->uid;
|
||||
if (options->gid != (gid_t)-1)
|
||||
new_gid = options->gid;
|
||||
|
||||
/* try to set the uid/gid combination */
|
||||
if ((new_gid != 0 || options->namespaces & CLONE_NEWUSER) && setgid(new_gid)) {
|
||||
SYSERROR("switching to container gid");
|
||||
shutdown(ipc_socket, SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
if ((new_uid != 0 || options->namespaces & CLONE_NEWUSER) && setuid(new_uid)) {
|
||||
SYSERROR("switching to container uid");
|
||||
shutdown(ipc_socket, SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
|
||||
/* tell initial process it may now put us into the cgroups */
|
||||
status = 1;
|
||||
ret = lxc_write_nointr(ipc_socket, &status, sizeof(status));
|
||||
if (ret != sizeof(status)) {
|
||||
ERROR("error using IPC to notify initial process for initialization (1)");
|
||||
shutdown(ipc_socket, SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
|
||||
/* wait for the initial thread to signal us that it has done
|
||||
* everything for us when it comes to cgroups etc.
|
||||
*/
|
||||
expected = 2;
|
||||
status = -1;
|
||||
ret = lxc_read_nointr_expect(ipc_socket, &status, sizeof(status), &expected);
|
||||
if (ret <= 0) {
|
||||
ERROR("error using IPC to receive final notification from initial process (2)");
|
||||
shutdown(ipc_socket, SHUT_RDWR);
|
||||
rexit(-1);
|
||||
}
|
||||
|
||||
shutdown(ipc_socket, SHUT_RDWR);
|
||||
close(ipc_socket);
|
||||
free(init_ctx->aa_profile);
|
||||
free(init_ctx);
|
||||
|
||||
/* The following is done after the communication socket is
|
||||
* shut down. That way, all errors that might (though
|
||||
* unlikely) occur up until this point will have their messages
|
||||
* printed to the original stderr (if logging is so configured)
|
||||
* and not the fd the user supplied, if any.
|
||||
*/
|
||||
|
||||
/* fd handling for stdin, stdout and stderr;
|
||||
* ignore errors here, user may want to make sure
|
||||
* the fds are closed, for example */
|
||||
if (options->stdin_fd >= 0 && options->stdin_fd != 0)
|
||||
dup2(options->stdin_fd, 0);
|
||||
if (options->stdout_fd >= 0 && options->stdout_fd != 1)
|
||||
dup2(options->stdout_fd, 1);
|
||||
if (options->stderr_fd >= 0 && options->stderr_fd != 2)
|
||||
dup2(options->stderr_fd, 2);
|
||||
|
||||
/* close the old fds */
|
||||
if (options->stdin_fd > 2)
|
||||
close(options->stdin_fd);
|
||||
if (options->stdout_fd > 2)
|
||||
close(options->stdout_fd);
|
||||
if (options->stderr_fd > 2)
|
||||
close(options->stderr_fd);
|
||||
|
||||
/* try to remove CLOEXEC flag from stdin/stdout/stderr,
|
||||
* but also here, ignore errors */
|
||||
for (fd = 0; fd <= 2; fd++) {
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
if (flags < 0)
|
||||
continue;
|
||||
if (flags & FD_CLOEXEC)
|
||||
fcntl(fd, F_SETFL, flags & ~FD_CLOEXEC);
|
||||
}
|
||||
|
||||
/* we're done, so we can now do whatever the user intended us to do */
|
||||
rexit(payload->exec_function(payload->exec_payload));
|
||||
}
|
||||
|
||||
int lxc_attach_run_command(void* payload)
|
||||
{
|
||||
lxc_attach_command_t* cmd = (lxc_attach_command_t*)payload;
|
||||
|
||||
execvp(cmd->program, cmd->argv);
|
||||
SYSERROR("failed to exec '%s'", cmd->program);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lxc_attach_run_shell(void* payload)
|
||||
{
|
||||
uid_t uid;
|
||||
struct passwd *passwd;
|
||||
char *user_shell;
|
||||
|
||||
/* ignore payload parameter */
|
||||
(void)payload;
|
||||
|
||||
uid = getuid();
|
||||
passwd = getpwuid(uid);
|
||||
|
||||
/* this probably happens because of incompatible nss
|
||||
* implementations in host and container (remember, this
|
||||
* code is still using the host's glibc but our mount
|
||||
* namespace is in the container)
|
||||
* we may try to get the information by spawning a
|
||||
* [getent passwd uid] process and parsing the result
|
||||
*/
|
||||
if (!passwd)
|
||||
user_shell = lxc_attach_getpwshell(uid);
|
||||
else
|
||||
user_shell = passwd->pw_shell;
|
||||
|
||||
if (user_shell)
|
||||
execlp(user_shell, user_shell, NULL);
|
||||
|
||||
/* executed if either no passwd entry or execvp fails,
|
||||
* we will fall back on /bin/sh as a default shell
|
||||
*/
|
||||
execlp("/bin/sh", "/bin/sh", NULL);
|
||||
SYSERROR("failed to exec shell");
|
||||
return -1;
|
||||
}
|
||||
|
@ -18,13 +18,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _attach_h
|
||||
#define _attach_h
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "attach_options.h"
|
||||
|
||||
struct lxc_proc_context_info {
|
||||
char *aa_profile;
|
||||
@ -34,11 +35,6 @@ struct lxc_proc_context_info {
|
||||
|
||||
extern struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid);
|
||||
|
||||
typedef enum lxc_attach_env_policy_t {
|
||||
LXC_ATTACH_KEEP_ENV,
|
||||
LXC_ATTACH_CLEAR_ENV
|
||||
} lxc_attach_env_policy_t;
|
||||
|
||||
extern int lxc_attach_to_ns(pid_t other_pid, int which);
|
||||
extern int lxc_attach_remount_sys_proc();
|
||||
extern int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx);
|
||||
@ -48,4 +44,6 @@ extern char *lxc_attach_getpwshell(uid_t uid);
|
||||
|
||||
extern void lxc_attach_get_init_uidgid(uid_t* init_uid, gid_t* init_gid);
|
||||
|
||||
extern int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_function, void* exec_payload, lxc_attach_options_t* options, pid_t* attached_process);
|
||||
|
||||
#endif
|
||||
|
120
src/lxc/attach_options.h
Normal file
120
src/lxc/attach_options.h
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* lxc: linux Container library
|
||||
*
|
||||
* (C) Copyright IBM Corp. 2007, 2008
|
||||
*
|
||||
* Authors:
|
||||
* Daniel Lezcano <daniel.lezcano at free.fr>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _LXC_ATTACH_OPTIONS_H
|
||||
#define _LXC_ATTACH_OPTIONS_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef enum lxc_attach_env_policy_t {
|
||||
LXC_ATTACH_KEEP_ENV,
|
||||
LXC_ATTACH_CLEAR_ENV
|
||||
} lxc_attach_env_policy_t;
|
||||
|
||||
enum {
|
||||
/* the following are on by default: */
|
||||
LXC_ATTACH_MOVE_TO_CGROUP = 0x00000001,
|
||||
LXC_ATTACH_DROP_CAPABILITIES = 0x00000002,
|
||||
LXC_ATTACH_SET_PERSONALITY = 0x00000004,
|
||||
LXC_ATTACH_APPARMOR = 0x00000008,
|
||||
|
||||
/* the following are off by default */
|
||||
LXC_ATTACH_REMOUNT_PROC_SYS = 0x00010000,
|
||||
|
||||
/* we have 16 bits for things that are on by default
|
||||
* and 16 bits that are off by default, that should
|
||||
* be sufficient to keep binary compatibility for
|
||||
* a while
|
||||
*/
|
||||
LXC_ATTACH_DEFAULT = 0x0000FFFF
|
||||
};
|
||||
|
||||
typedef struct lxc_attach_options_t lxc_attach_options_t;
|
||||
typedef int (*lxc_attach_exec_t)(void* payload);
|
||||
|
||||
struct lxc_attach_options_t {
|
||||
/* any combination of the above enum */
|
||||
int attach_flags;
|
||||
/* the namespaces to attach to (CLONE_NEW... flags) */
|
||||
int namespaces;
|
||||
/* initial personality, -1 to autodetect
|
||||
* (may be ignored if lxc is compiled w/o personality support) */
|
||||
long personality;
|
||||
|
||||
/* inital current directory, use NULL to use cwd
|
||||
* (might not exist in container, then / will be
|
||||
* used because of kernel defaults)
|
||||
*/
|
||||
char* initial_cwd;
|
||||
|
||||
/* the uid and gid to attach to,
|
||||
* -1 for default (init uid/gid for userns containers,
|
||||
* otherwise or if detection fails 0/0)
|
||||
*/
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
/* environment handling */
|
||||
lxc_attach_env_policy_t env_policy;
|
||||
char** extra_env_vars;
|
||||
char** extra_keep_env;
|
||||
|
||||
/* file descriptors for stdin, stdout and stderr,
|
||||
* dup2() will be used before calling exec_function,
|
||||
* (assuming not 0, 1 and 2 are specified) and the
|
||||
* original fds are closed before passing control
|
||||
* over. Any O_CLOEXEC flag will be removed after
|
||||
* that
|
||||
*/
|
||||
int stdin_fd;
|
||||
int stdout_fd;
|
||||
int stderr_fd;
|
||||
};
|
||||
|
||||
#define LXC_ATTACH_OPTIONS_DEFAULT \
|
||||
{ \
|
||||
/* .attach_flags = */ LXC_ATTACH_DEFAULT, \
|
||||
/* .namespaces = */ -1, \
|
||||
/* .personality = */ -1, \
|
||||
/* .initial_cwd = */ NULL, \
|
||||
/* .uid = */ (uid_t)-1, \
|
||||
/* .gid = */ (gid_t)-1, \
|
||||
/* .env_policy = */ LXC_ATTACH_KEEP_ENV, \
|
||||
/* .extra_env_vars = */ NULL, \
|
||||
/* .extra_keep_env = */ NULL, \
|
||||
/* .stdin_fd = */ 0, 1, 2 \
|
||||
}
|
||||
|
||||
typedef struct lxc_attach_command_t {
|
||||
char* program; /* the program to run (passed to execvp) */
|
||||
char** argv; /* the argv pointer of that program, including the program itself in argv[0] */
|
||||
} lxc_attach_command_t;
|
||||
|
||||
/* default execution functions:
|
||||
* run_command: pointer to lxc_attach_command_t
|
||||
* run_shell: no payload, will be ignored
|
||||
*/
|
||||
extern int lxc_attach_run_command(void* payload);
|
||||
extern int lxc_attach_run_shell(void* payload);
|
||||
|
||||
#endif
|
2070
src/lxc/bdev.c
Normal file
2070
src/lxc/bdev.c
Normal file
File diff suppressed because it is too large
Load Diff
138
src/lxc/bdev.h
Normal file
138
src/lxc/bdev.h
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* lxc: linux Container library
|
||||
*
|
||||
* (C) Copyright IBM Corp. 2007, 2008
|
||||
*
|
||||
* Authors:
|
||||
* Daniel Lezcano <daniel.lezcano at free.fr>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __LXC_BDEV_H
|
||||
#define __LXC_BDEV_H
|
||||
/* blockdev operations for:
|
||||
* dir, raw, btrfs, overlayfs, aufs, lvm, loop, zfs
|
||||
* someday: qemu-nbd, qcow2, qed
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "lxccontainer.h"
|
||||
|
||||
struct bdev;
|
||||
|
||||
/*
|
||||
* specifications for how to create a new backing store
|
||||
*/
|
||||
struct bdev_specs {
|
||||
union {
|
||||
struct {
|
||||
char *zfsroot;
|
||||
} zfs;
|
||||
struct {
|
||||
char *vg;
|
||||
char *lv;
|
||||
char *fstype;
|
||||
unsigned long fssize; // fs size in bytes
|
||||
} lvm;
|
||||
struct {
|
||||
char *fstype;
|
||||
unsigned long fssize; // fs size in bytes
|
||||
} loop;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct bdev_ops {
|
||||
/* detect whether path is of this bdev type */
|
||||
int (*detect)(const char *path);
|
||||
// mount requires src and dest to be set.
|
||||
int (*mount)(struct bdev *bdev);
|
||||
int (*umount)(struct bdev *bdev);
|
||||
int (*destroy)(struct bdev *bdev);
|
||||
int (*create)(struct bdev *bdev, const char *dest, const char *n,
|
||||
struct bdev_specs *specs);
|
||||
/* given original mount, rename the paths for cloned container */
|
||||
int (*clone_paths)(struct bdev *orig, struct bdev *new, const char *oldname,
|
||||
const char *cname, const char *oldpath, const char *lxcpath,
|
||||
int snap, unsigned long newsize);
|
||||
};
|
||||
|
||||
/*
|
||||
* When lxc-start (conf.c) is mounting a rootfs, then src will be the
|
||||
* 'lxc.rootfs' value, dest will be mount dir (i.e. $libdir/lxc) When clone
|
||||
* or create is doing so, then dest will be $lxcpath/$lxcname/rootfs, since
|
||||
* we may need to rsync from one to the other.
|
||||
* data is so far unused.
|
||||
*/
|
||||
struct bdev {
|
||||
struct bdev_ops *ops;
|
||||
char *type;
|
||||
char *src;
|
||||
char *dest;
|
||||
char *data;
|
||||
// turn the following into a union if need be
|
||||
// lofd is the open fd for the mounted loopback file
|
||||
int lofd;
|
||||
};
|
||||
|
||||
char *overlayfs_getlower(char *p);
|
||||
|
||||
/*
|
||||
* Instantiate a bdev object. The src is used to determine which blockdev
|
||||
* type this should be. The dst and data are optional, and will be used
|
||||
* in case of mount/umount.
|
||||
*
|
||||
* Optionally, src can be 'dir:/var/lib/lxc/c1' or 'lvm:/dev/lxc/c1'. For
|
||||
* other backing stores, this will allow additional options. In particular,
|
||||
* "overlayfs:/var/lib/lxc/canonical/rootfs:/var/lib/lxc/c1/delta" will mean
|
||||
* use /var/lib/lxc/canonical/rootfs as lower dir, and /var/lib/lxc/c1/delta
|
||||
* as the upper, writeable layer.
|
||||
*/
|
||||
struct bdev *bdev_init(const char *src, const char *dst, const char *data);
|
||||
|
||||
struct bdev *bdev_copy(const char *src, const char *oldname, const char *cname,
|
||||
const char *oldpath, const char *lxcpath, const char *bdevtype,
|
||||
int snap, const char *bdevdata, unsigned long newsize,
|
||||
int *needs_rdep);
|
||||
struct bdev *bdev_create(const char *dest, const char *type,
|
||||
const char *cname, struct bdev_specs *specs);
|
||||
void bdev_put(struct bdev *bdev);
|
||||
|
||||
/* define constants if the kernel/glibc headers don't define them */
|
||||
#ifndef MS_DIRSYNC
|
||||
#define MS_DIRSYNC 128
|
||||
#endif
|
||||
|
||||
#ifndef MS_REC
|
||||
#define MS_REC 16384
|
||||
#endif
|
||||
|
||||
#ifndef MNT_DETACH
|
||||
#define MNT_DETACH 2
|
||||
#endif
|
||||
|
||||
#ifndef MS_SLAVE
|
||||
#define MS_SLAVE (1<<19)
|
||||
#endif
|
||||
|
||||
#ifndef MS_RELATIME
|
||||
#define MS_RELATIME (1 << 21)
|
||||
#endif
|
||||
|
||||
#ifndef MS_STRICTATIME
|
||||
#define MS_STRICTATIME (1 << 24)
|
||||
#endif
|
||||
|
||||
#endif
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
@ -227,42 +227,4 @@ int lxc_caps_last_cap(void)
|
||||
return last_cap;
|
||||
}
|
||||
|
||||
/*
|
||||
* check if we have the caps needed to start a container. returns 1 on
|
||||
* success, 0 on error. (I'd prefer this be a bool, but am afraid that
|
||||
* might fail to build on some distros).
|
||||
*/
|
||||
int lxc_caps_check(void)
|
||||
{
|
||||
uid_t uid = getuid();
|
||||
cap_t caps;
|
||||
cap_flag_value_t value;
|
||||
int i, ret;
|
||||
|
||||
cap_value_t needed_caps[] = { CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_SETUID, CAP_SETGID };
|
||||
|
||||
#define NUMCAPS ((int) (sizeof(needed_caps) / sizeof(cap_t)))
|
||||
|
||||
if (!uid)
|
||||
return 1;
|
||||
|
||||
caps = cap_get_proc();
|
||||
if (!caps) {
|
||||
ERROR("failed to cap_get_proc: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i=0; i<NUMCAPS; i++) {
|
||||
ret = cap_get_flag(caps, needed_caps[i], CAP_EFFECTIVE, &value);
|
||||
if (ret) {
|
||||
ERROR("Failed to cap_get_flag: %m");
|
||||
return 0;
|
||||
}
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
@ -30,7 +30,6 @@ extern int lxc_caps_reset(void);
|
||||
extern int lxc_caps_down(void);
|
||||
extern int lxc_caps_up(void);
|
||||
extern int lxc_caps_init(void);
|
||||
extern int lxc_caps_check(void);
|
||||
|
||||
extern int lxc_caps_last_cap(void);
|
||||
#else
|
||||
@ -46,9 +45,6 @@ static inline int lxc_caps_up(void) {
|
||||
static inline int lxc_caps_init(void) {
|
||||
return 0;
|
||||
}
|
||||
static inline int lxc_caps_check(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lxc_caps_last_cap(void) {
|
||||
return 0;
|
||||
|
1277
src/lxc/cgroup.c
1277
src/lxc/cgroup.c
File diff suppressed because it is too large
Load Diff
@ -18,21 +18,40 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef _cgroup_h
|
||||
#define _cgroup_h
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MAXPRIOLEN 24
|
||||
/*
|
||||
* cgroup_desc: describe a container's cgroup membership
|
||||
*/
|
||||
struct cgroup_desc {
|
||||
char *mntpt; /* where this is mounted */
|
||||
char *subsystems; /* comma-separated list of subsystems, or NULL */
|
||||
char *curcgroup; /* task's current cgroup, full pathanme */
|
||||
char *realcgroup; /* the cgroup as known in /proc/self/cgroup */
|
||||
struct cgroup_desc *next;
|
||||
};
|
||||
|
||||
struct lxc_handler;
|
||||
extern int lxc_cgroup_destroy(const char *cgpath);
|
||||
extern int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name,
|
||||
extern void lxc_cgroup_destroy_desc(struct cgroup_desc *cgroups);
|
||||
extern char *lxc_cgroup_path_get(const char *subsystem, const char *name,
|
||||
const char *lxcpath);
|
||||
extern int lxc_cgroup_nrtasks(const char *cgpath);
|
||||
extern char *lxc_cgroup_path_create(const char *lxcgroup, const char *name);
|
||||
extern int lxc_cgroup_enter(const char *cgpath, pid_t pid);
|
||||
extern int lxc_cgroup_nrtasks(struct lxc_handler *handler);
|
||||
struct cgroup_desc *lxc_cgroup_path_create(const char *name);
|
||||
extern int lxc_cgroup_enter(struct cgroup_desc *cgroups, pid_t pid);
|
||||
extern int lxc_cgroup_attach(pid_t pid, const char *name, const char *lxcpath);
|
||||
extern int cgroup_path_get(char **path, const char *subsystem, const char *cgpath);
|
||||
extern int lxc_get_cgpath(const char **path, const char *subsystem, const char *name, const char *lxcpath);
|
||||
extern char *cgroup_path_get(const char *subsystem, const char *cgpath);
|
||||
extern bool get_subsys_mount(char *dest, const char *subsystem);
|
||||
extern bool is_in_subcgroup(int pid, const char *subsystem, struct cgroup_desc *d);
|
||||
/*
|
||||
* Called by commands.c by a container's monitor to find out the
|
||||
* container's cgroup path in a specific subsystem
|
||||
*/
|
||||
extern char *cgroup_get_subsys_path(struct lxc_handler *handler, const char *subsys);
|
||||
struct lxc_list;
|
||||
extern int setup_cgroup(struct lxc_handler *h, struct lxc_list *cgroups);
|
||||
extern int setup_cgroup_devices(struct lxc_handler *h, struct lxc_list *cgroups);
|
||||
#endif
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <lxc/lxc.h>
|
||||
#include <lxc/log.h>
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -34,27 +34,41 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <lxc/log.h>
|
||||
#include <lxc/lxc.h>
|
||||
#include <lxc/conf.h>
|
||||
#include <lxc/start.h> /* for struct lxc_handler */
|
||||
#include <lxc/utils.h>
|
||||
|
||||
#include "commands.h"
|
||||
#include "console.h"
|
||||
#include "confile.h"
|
||||
#include "mainloop.h"
|
||||
#include "af_unix.h"
|
||||
#include "config.h"
|
||||
|
||||
/*
|
||||
* This file provides the different functions to have the client
|
||||
* and the server to communicate
|
||||
* This file provides the different functions for clients to
|
||||
* query/command the server. The client is typically some lxc
|
||||
* tool and the server is typically the container (ie. lxc-start).
|
||||
*
|
||||
* Each command is transactional, the client send a request to
|
||||
* the server and the server answer the request with a message
|
||||
* Each command is transactional, the clients send a request to
|
||||
* the server and the server answers the request with a message
|
||||
* giving the request's status (zero or a negative errno value).
|
||||
* Both the request and response may contain addtional data.
|
||||
*
|
||||
* Each command is wrapped in a ancillary message in order to pass
|
||||
* a credential making possible to the server to check if the client
|
||||
* is allowed to ask for this command or not.
|
||||
*
|
||||
* IMPORTANTLY: Note that semantics for current commands are fixed. If you
|
||||
* wish to make any changes to how, say, LXC_CMD_GET_CONFIG_ITEM works by
|
||||
* adding information to the end of cmd.data, then you must introduce a new
|
||||
* LXC_CMD_GET_CONFIG_ITEM_V2 define with a new number. You may wish to
|
||||
* also mark LXC_CMD_GET_CONFIG_ITEM deprecated in commands.h.
|
||||
*
|
||||
* This is necessary in order to avoid having a newly compiled lxc command
|
||||
* communicating with a running (old) monitor from crashing the running
|
||||
* container.
|
||||
*/
|
||||
|
||||
lxc_log_define(lxc_commands, lxc);
|
||||
@ -81,181 +95,642 @@ static int fill_sock_name(char *path, int len, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int receive_answer(int sock, struct lxc_answer *answer)
|
||||
static const char *lxc_cmd_str(lxc_cmd_t cmd)
|
||||
{
|
||||
int ret;
|
||||
static char answerpath[MAXPATHLEN];
|
||||
static const char *cmdname[LXC_CMD_MAX] = {
|
||||
[LXC_CMD_CONSOLE] = "console",
|
||||
[LXC_CMD_STOP] = "stop",
|
||||
[LXC_CMD_GET_STATE] = "get_state",
|
||||
[LXC_CMD_GET_INIT_PID] = "get_init_pid",
|
||||
[LXC_CMD_GET_CLONE_FLAGS] = "get_clone_flags",
|
||||
[LXC_CMD_GET_CGROUP] = "get_cgroup",
|
||||
[LXC_CMD_GET_CONFIG_ITEM] = "get_config_item",
|
||||
};
|
||||
|
||||
ret = lxc_af_unix_recv_fd(sock, &answer->fd, answer, sizeof(*answer));
|
||||
if (ret < 0)
|
||||
ERROR("failed to receive answer for the command");
|
||||
if (answer->pathlen == 0)
|
||||
return ret;
|
||||
if (answer->pathlen >= MAXPATHLEN) {
|
||||
ERROR("cgroup path was too long");
|
||||
if (cmd < 0 || cmd >= LXC_CMD_MAX)
|
||||
return "Unknown cmd";
|
||||
return cmdname[cmd];
|
||||
}
|
||||
|
||||
/*
|
||||
* lxc_cmd_rsp_recv: Receive a response to a command
|
||||
*
|
||||
* @sock : the socket connected to the container
|
||||
* @cmd : command to put response in
|
||||
*
|
||||
* Returns the size of the response message or < 0 on failure
|
||||
*
|
||||
* Note that if the command response datalen > 0, then data is
|
||||
* a malloc()ed buffer and should be free()ed by the caller. If
|
||||
* the response data is <= a void * worth of data, it will be
|
||||
* stored directly in data and datalen will be 0.
|
||||
*
|
||||
* As a special case, the response for LXC_CMD_CONSOLE is created
|
||||
* here as it contains an fd for the master pty passed through the
|
||||
* unix socket.
|
||||
*/
|
||||
static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
|
||||
{
|
||||
int ret,rspfd;
|
||||
struct lxc_cmd_rsp *rsp = &cmd->rsp;
|
||||
|
||||
ret = lxc_af_unix_recv_fd(sock, &rspfd, rsp, sizeof(*rsp));
|
||||
if (ret < 0) {
|
||||
ERROR("command %s failed to receive response",
|
||||
lxc_cmd_str(cmd->req.cmd));
|
||||
return -1;
|
||||
}
|
||||
ret = recv(sock, answerpath, answer->pathlen, 0);
|
||||
if (ret != answer->pathlen) {
|
||||
ERROR("failed to receive answer for the command");
|
||||
ret = 0;
|
||||
} else
|
||||
answer->path = answerpath;
|
||||
|
||||
if (cmd->req.cmd == LXC_CMD_CONSOLE) {
|
||||
struct lxc_cmd_console_rsp_data *rspdata;
|
||||
|
||||
/* recv() returns 0 bytes when a tty cannot be allocated,
|
||||
* rsp->ret is < 0 when the peer permission check failed
|
||||
*/
|
||||
if (ret == 0 || rsp->ret < 0)
|
||||
return 0;
|
||||
|
||||
rspdata = malloc(sizeof(*rspdata));
|
||||
if (!rspdata) {
|
||||
ERROR("command %s couldn't allocate response buffer",
|
||||
lxc_cmd_str(cmd->req.cmd));
|
||||
return -1;
|
||||
}
|
||||
rspdata->masterfd = rspfd;
|
||||
rspdata->ttynum = PTR_TO_INT(rsp->data);
|
||||
rsp->data = rspdata;
|
||||
}
|
||||
|
||||
if (rsp->datalen == 0)
|
||||
return ret;
|
||||
if (rsp->datalen > LXC_CMD_DATA_MAX) {
|
||||
ERROR("command %s response data %d too long",
|
||||
lxc_cmd_str(cmd->req.cmd), rsp->datalen);
|
||||
errno = EFBIG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rsp->data = malloc(rsp->datalen);
|
||||
if (!rsp->data) {
|
||||
ERROR("command %s unable to allocate response buffer",
|
||||
lxc_cmd_str(cmd->req.cmd));
|
||||
return -1;
|
||||
}
|
||||
ret = recv(sock, rsp->data, rsp->datalen, 0);
|
||||
if (ret != rsp->datalen) {
|
||||
ERROR("command %s failed to receive response data",
|
||||
lxc_cmd_str(cmd->req.cmd));
|
||||
if (ret >= 0)
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __lxc_command(const char *name, struct lxc_command *command,
|
||||
int *stopped, int stay_connected, const char *lxcpath)
|
||||
/*
|
||||
* lxc_cmd_rsp_send: Send a command response
|
||||
*
|
||||
* @fd : file descriptor of socket to send response on
|
||||
* @rsp : response to send
|
||||
*
|
||||
* Returns 0 on success, < 0 on failure
|
||||
*/
|
||||
static int lxc_cmd_rsp_send(int fd, struct lxc_cmd_rsp *rsp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = send(fd, rsp, sizeof(*rsp), 0);
|
||||
if (ret != sizeof(*rsp)) {
|
||||
ERROR("failed to send command response %d %s", ret,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rsp->datalen > 0) {
|
||||
ret = send(fd, rsp->data, rsp->datalen, 0);
|
||||
if (ret != rsp->datalen) {
|
||||
WARN("failed to send command response data %d %s", ret,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* lxc_cmd: Connect to the specified running container, send it a command
|
||||
* request and collect the response
|
||||
*
|
||||
* @name : name of container to connect to
|
||||
* @cmd : command with initialized reqest to send
|
||||
* @stopped : output indicator if the container was not running
|
||||
* @lxcpath : the lxcpath in which the container is running
|
||||
*
|
||||
* Returns the size of the response message on success, < 0 on failure
|
||||
*
|
||||
* Note that there is a special case for LXC_CMD_CONSOLE. For this command
|
||||
* the fd cannot be closed because it is used as a placeholder to indicate
|
||||
* that a particular tty slot is in use. The fd is also used as a signal to
|
||||
* the container that when the caller dies or closes the fd, the container
|
||||
* will notice the fd on its side of the socket in its mainloop select and
|
||||
* then free the slot with lxc_cmd_fd_cleanup(). The socket fd will be
|
||||
* returned in the cmd response structure.
|
||||
*/
|
||||
static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
|
||||
const char *lxcpath)
|
||||
{
|
||||
int sock, ret = -1;
|
||||
char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
|
||||
char *offset = &path[1];
|
||||
int len;
|
||||
int stay_connected = cmd->req.cmd == LXC_CMD_CONSOLE;
|
||||
|
||||
len = sizeof(path)-1;
|
||||
if (fill_sock_name(offset, len, name, lxcpath))
|
||||
return -1;
|
||||
|
||||
sock = lxc_af_unix_connect(path);
|
||||
if (sock < 0 && errno == ECONNREFUSED) {
|
||||
*stopped = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sock < 0) {
|
||||
SYSERROR("failed to connect to '@%s'", offset);
|
||||
if (errno == ECONNREFUSED)
|
||||
*stopped = 1;
|
||||
else
|
||||
SYSERROR("command %s failed to connect to '@%s'",
|
||||
lxc_cmd_str(cmd->req.cmd), offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = lxc_af_unix_send_credential(sock, &command->request,
|
||||
sizeof(command->request));
|
||||
if (ret < 0) {
|
||||
SYSERROR("failed to send request to '@%s'", offset);
|
||||
ret = lxc_af_unix_send_credential(sock, &cmd->req, sizeof(cmd->req));
|
||||
if (ret != sizeof(cmd->req)) {
|
||||
SYSERROR("command %s failed to send req to '@%s' %d",
|
||||
lxc_cmd_str(cmd->req.cmd), offset, ret);
|
||||
if (ret >=0)
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ret != sizeof(command->request)) {
|
||||
SYSERROR("message partially sent to '@%s'", offset);
|
||||
goto out;
|
||||
if (cmd->req.datalen > 0) {
|
||||
ret = send(sock, cmd->req.data, cmd->req.datalen, 0);
|
||||
if (ret != cmd->req.datalen) {
|
||||
SYSERROR("command %s failed to send request data to '@%s' %d",
|
||||
lxc_cmd_str(cmd->req.cmd), offset, ret);
|
||||
if (ret >=0)
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = receive_answer(sock, &command->answer);
|
||||
ret = lxc_cmd_rsp_recv(sock, cmd);
|
||||
out:
|
||||
if (!stay_connected || ret < 0)
|
||||
if (!stay_connected || ret <= 0)
|
||||
close(sock);
|
||||
if (stay_connected && ret > 0)
|
||||
cmd->rsp.ret = sock;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern int lxc_command(const char *name,
|
||||
struct lxc_command *command, int *stopped,
|
||||
const char *lxcpath)
|
||||
{
|
||||
return __lxc_command(name, command, stopped, 0, lxcpath);
|
||||
}
|
||||
/* Implentations of the commands and their callbacks */
|
||||
|
||||
extern int lxc_command_connected(const char *name,
|
||||
struct lxc_command *command, int *stopped,
|
||||
const char *lxcpath)
|
||||
/*
|
||||
* lxc_cmd_get_init_pid: Get pid of the container's init process
|
||||
*
|
||||
* @name : name of container to connect to
|
||||
* @lxcpath : the lxcpath in which the container is running
|
||||
*
|
||||
* Returns the pid on success, < 0 on failure
|
||||
*/
|
||||
pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath)
|
||||
{
|
||||
return __lxc_command(name, command, stopped, 1, lxcpath);
|
||||
}
|
||||
|
||||
|
||||
pid_t get_init_pid(const char *name, const char *lxcpath)
|
||||
{
|
||||
struct lxc_command command = {
|
||||
.request = { .type = LXC_COMMAND_PID },
|
||||
int ret, stopped = 0;
|
||||
struct lxc_cmd_rr cmd = {
|
||||
.req = { .cmd = LXC_CMD_GET_INIT_PID },
|
||||
};
|
||||
|
||||
int ret, stopped = 0;
|
||||
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = lxc_command(name, &command, &stopped, lxcpath);
|
||||
if (ret < 0 && stopped)
|
||||
return -1;
|
||||
|
||||
if (ret < 0) {
|
||||
ERROR("failed to send command");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (command.answer.ret) {
|
||||
ERROR("failed to retrieve the init pid: %s",
|
||||
strerror(-command.answer.ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return command.answer.pid;
|
||||
return PTR_TO_INT(cmd.rsp.data);
|
||||
}
|
||||
|
||||
int lxc_get_clone_flags(const char *name, const char *lxcpath)
|
||||
static int lxc_cmd_get_init_pid_callback(int fd, struct lxc_cmd_req *req,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
struct lxc_command command = {
|
||||
.request = { .type = LXC_COMMAND_CLONE_FLAGS },
|
||||
struct lxc_cmd_rsp rsp = { .data = INT_TO_PTR(handler->pid) };
|
||||
|
||||
return lxc_cmd_rsp_send(fd, &rsp);
|
||||
}
|
||||
|
||||
/*
|
||||
* lxc_cmd_get_clone_flags: Get clone flags container was spawned with
|
||||
*
|
||||
* @name : name of container to connect to
|
||||
* @lxcpath : the lxcpath in which the container is running
|
||||
*
|
||||
* Returns the clone flags on success, < 0 on failure
|
||||
*/
|
||||
int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath)
|
||||
{
|
||||
int ret, stopped = 0;
|
||||
struct lxc_cmd_rr cmd = {
|
||||
.req = { .cmd = LXC_CMD_GET_CLONE_FLAGS },
|
||||
};
|
||||
|
||||
int ret, stopped = 0;
|
||||
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = lxc_command(name, &command, &stopped, lxcpath);
|
||||
return PTR_TO_INT(cmd.rsp.data);
|
||||
}
|
||||
|
||||
static int lxc_cmd_get_clone_flags_callback(int fd, struct lxc_cmd_req *req,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
struct lxc_cmd_rsp rsp = { .data = INT_TO_PTR(handler->clone_flags) };
|
||||
|
||||
return lxc_cmd_rsp_send(fd, &rsp);
|
||||
}
|
||||
|
||||
extern char *cgroup_get_subsys_path(struct lxc_handler *handler, const char *subsys);
|
||||
/*
|
||||
* lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a
|
||||
* particular subsystem. This is the cgroup path relative to the root
|
||||
* of the cgroup filesystem.
|
||||
*
|
||||
* @name : name of container to connect to
|
||||
* @lxcpath : the lxcpath in which the container is running
|
||||
* @subsystem : the subsystem being asked about
|
||||
*
|
||||
* Returns the path on success, NULL on failure. The caller must free() the
|
||||
* returned path.
|
||||
*/
|
||||
char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
|
||||
const char *subsystem)
|
||||
{
|
||||
int ret, stopped = 0;
|
||||
struct lxc_cmd_rr cmd = {
|
||||
.req = {
|
||||
.cmd = LXC_CMD_GET_CGROUP,
|
||||
.datalen = strlen(subsystem)+1,
|
||||
.data = subsystem,
|
||||
},
|
||||
};
|
||||
|
||||
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
if (!ret) {
|
||||
WARN("'%s' has stopped before sending its state", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cmd.rsp.ret < 0 || cmd.rsp.datalen < 0) {
|
||||
ERROR("command %s failed for '%s': %s",
|
||||
lxc_cmd_str(cmd.req.cmd), name,
|
||||
strerror(-cmd.rsp.ret));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cmd.rsp.data;
|
||||
}
|
||||
|
||||
static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
struct lxc_cmd_rsp rsp;
|
||||
char *path;
|
||||
|
||||
if (req->datalen < 1)
|
||||
return -1;
|
||||
|
||||
path = cgroup_get_subsys_path(handler, req->data);
|
||||
if (!path)
|
||||
return -1;
|
||||
rsp.datalen = strlen(path) + 1,
|
||||
rsp.data = path;
|
||||
rsp.ret = 0;
|
||||
|
||||
return lxc_cmd_rsp_send(fd, &rsp);
|
||||
}
|
||||
|
||||
/*
|
||||
* lxc_cmd_get_config_item: Get config item the running container
|
||||
*
|
||||
* @name : name of container to connect to
|
||||
* @item : the configuration item to retrieve (ex: lxc.network.0.veth.pair)
|
||||
* @lxcpath : the lxcpath in which the container is running
|
||||
*
|
||||
* Returns the item on success, NULL on failure. The caller must free() the
|
||||
* returned item.
|
||||
*/
|
||||
char *lxc_cmd_get_config_item(const char *name, const char *item,
|
||||
const char *lxcpath)
|
||||
{
|
||||
int ret, stopped = 0;
|
||||
struct lxc_cmd_rr cmd = {
|
||||
.req = { .cmd = LXC_CMD_GET_CONFIG_ITEM,
|
||||
.data = item,
|
||||
.datalen = strlen(item)+1,
|
||||
},
|
||||
};
|
||||
|
||||
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
if (cmd.rsp.ret == 0)
|
||||
return cmd.rsp.data;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
int cilen;
|
||||
struct lxc_cmd_rsp rsp;
|
||||
char *cidata;
|
||||
|
||||
memset(&rsp, 0, sizeof(rsp));
|
||||
cilen = lxc_get_config_item(handler->conf, req->data, NULL, 0);
|
||||
if (cilen <= 0)
|
||||
goto err1;
|
||||
|
||||
cidata = alloca(cilen + 1);
|
||||
if (lxc_get_config_item(handler->conf, req->data, cidata, cilen + 1) != cilen)
|
||||
goto err1;
|
||||
cidata[cilen] = '\0';
|
||||
rsp.data = cidata;
|
||||
rsp.datalen = cilen + 1;
|
||||
rsp.ret = 0;
|
||||
goto out;
|
||||
|
||||
err1:
|
||||
rsp.ret = -1;
|
||||
out:
|
||||
return lxc_cmd_rsp_send(fd, &rsp);
|
||||
}
|
||||
|
||||
/*
|
||||
* lxc_cmd_get_state: Get current state of the container
|
||||
*
|
||||
* @name : name of container to connect to
|
||||
* @lxcpath : the lxcpath in which the container is running
|
||||
*
|
||||
* Returns the state on success, < 0 on failure
|
||||
*/
|
||||
lxc_state_t lxc_cmd_get_state(const char *name, const char *lxcpath)
|
||||
{
|
||||
int ret, stopped = 0;
|
||||
struct lxc_cmd_rr cmd = {
|
||||
.req = { .cmd = LXC_CMD_GET_STATE }
|
||||
};
|
||||
|
||||
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
|
||||
if (ret < 0 && stopped)
|
||||
return STOPPED;
|
||||
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
if (ret < 0) {
|
||||
ERROR("failed to send command");
|
||||
if (!ret) {
|
||||
WARN("'%s' has stopped before sending its state", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return command.answer.ret;
|
||||
DEBUG("'%s' is in '%s' state", name,
|
||||
lxc_state2str(PTR_TO_INT(cmd.rsp.data)));
|
||||
return PTR_TO_INT(cmd.rsp.data);
|
||||
}
|
||||
|
||||
extern void lxc_console_remove_fd(int, struct lxc_tty_info *);
|
||||
extern int lxc_console_callback(int, struct lxc_request *, struct lxc_handler *);
|
||||
extern int lxc_stop_callback(int, struct lxc_request *, struct lxc_handler *);
|
||||
extern int lxc_state_callback(int, struct lxc_request *, struct lxc_handler *);
|
||||
extern int lxc_pid_callback(int, struct lxc_request *, struct lxc_handler *);
|
||||
extern int lxc_clone_flags_callback(int, struct lxc_request *, struct lxc_handler *);
|
||||
extern int lxc_cgroup_callback(int, struct lxc_request *, struct lxc_handler *);
|
||||
static int lxc_cmd_get_state_callback(int fd, struct lxc_cmd_req *req,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
struct lxc_cmd_rsp rsp = { .data = INT_TO_PTR(handler->state) };
|
||||
|
||||
static int trigger_command(int fd, struct lxc_request *request,
|
||||
return lxc_cmd_rsp_send(fd, &rsp);
|
||||
}
|
||||
|
||||
/*
|
||||
* lxc_cmd_stop: Stop the container previously started with lxc_start. All
|
||||
* the processes running inside this container will be killed.
|
||||
*
|
||||
* @name : name of container to connect to
|
||||
* @lxcpath : the lxcpath in which the container is running
|
||||
*
|
||||
* Returns 0 on success, < 0 on failure
|
||||
*/
|
||||
int lxc_cmd_stop(const char *name, const char *lxcpath)
|
||||
{
|
||||
int ret, stopped = 0;
|
||||
struct lxc_cmd_rr cmd = {
|
||||
.req = { .cmd = LXC_CMD_STOP },
|
||||
};
|
||||
|
||||
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
|
||||
if (ret < 0) {
|
||||
if (stopped) {
|
||||
INFO("'%s' is already stopped", name);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we do not expect any answer, because we wait for the connection to be
|
||||
* closed
|
||||
*/
|
||||
if (ret > 0) {
|
||||
ERROR("failed to stop '%s': %s", name, strerror(-cmd.rsp.ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
INFO("'%s' has stopped", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
struct lxc_cmd_rsp rsp;
|
||||
int ret;
|
||||
int stopsignal = SIGKILL;
|
||||
|
||||
if (handler->conf->stopsignal)
|
||||
stopsignal = handler->conf->stopsignal;
|
||||
memset(&rsp, 0, sizeof(rsp));
|
||||
rsp.ret = kill(handler->pid, stopsignal);
|
||||
if (!rsp.ret) {
|
||||
char *path = cgroup_get_subsys_path(handler, "freezer");
|
||||
if (!path) {
|
||||
ERROR("container %s:%s is not in a freezer cgroup",
|
||||
handler->lxcpath, handler->name);
|
||||
return 0;
|
||||
}
|
||||
ret = lxc_unfreeze_bypath(path);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
ERROR("failed to unfreeze container");
|
||||
rsp.ret = ret;
|
||||
}
|
||||
|
||||
return lxc_cmd_rsp_send(fd, &rsp);
|
||||
}
|
||||
|
||||
/*
|
||||
* lxc_cmd_console_winch: To process as if a SIGWINCH were received
|
||||
*
|
||||
* @name : name of container to connect to
|
||||
* @lxcpath : the lxcpath in which the container is running
|
||||
*
|
||||
* Returns 0 on success, < 0 on failure
|
||||
*/
|
||||
int lxc_cmd_console_winch(const char *name, const char *lxcpath)
|
||||
{
|
||||
int ret, stopped = 0;
|
||||
struct lxc_cmd_rr cmd = {
|
||||
.req = { .cmd = LXC_CMD_CONSOLE_WINCH },
|
||||
};
|
||||
|
||||
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lxc_cmd_console_winch_callback(int fd, struct lxc_cmd_req *req,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
struct lxc_cmd_rsp rsp = { .data = 0 };
|
||||
|
||||
lxc_console_sigwinch(SIGWINCH);
|
||||
return lxc_cmd_rsp_send(fd, &rsp);
|
||||
}
|
||||
|
||||
/*
|
||||
* lxc_cmd_console: Open an fd to a tty in the container
|
||||
*
|
||||
* @name : name of container to connect to
|
||||
* @ttynum : in: the tty to open or -1 for next available
|
||||
* : out: the tty allocated
|
||||
* @fd : out: file descriptor for master side of pty
|
||||
* @lxcpath : the lxcpath in which the container is running
|
||||
*
|
||||
* Returns fd holding tty allocated on success, < 0 on failure
|
||||
*/
|
||||
int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath)
|
||||
{
|
||||
int ret, stopped = 0;
|
||||
struct lxc_cmd_console_rsp_data *rspdata;
|
||||
struct lxc_cmd_rr cmd = {
|
||||
.req = { .cmd = LXC_CMD_CONSOLE, .data = INT_TO_PTR(*ttynum) },
|
||||
};
|
||||
|
||||
ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (cmd.rsp.ret < 0) {
|
||||
ERROR("console access denied: %s", strerror(-cmd.rsp.ret));
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ERROR("console %d invalid,busy or all consoles busy", *ttynum);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rspdata = cmd.rsp.data;
|
||||
if (rspdata->masterfd < 0) {
|
||||
ERROR("unable to allocate fd for tty %d", rspdata->ttynum);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = cmd.rsp.ret; /* sock fd */
|
||||
*fd = rspdata->masterfd;
|
||||
*ttynum = rspdata->ttynum;
|
||||
INFO("tty %d allocated fd %d sock %d", rspdata->ttynum, *fd, ret);
|
||||
out:
|
||||
free(cmd.rsp.data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
int ttynum = PTR_TO_INT(req->data);
|
||||
int masterfd;
|
||||
struct lxc_cmd_rsp rsp;
|
||||
|
||||
masterfd = lxc_console_allocate(handler->conf, fd, &ttynum);
|
||||
if (masterfd < 0)
|
||||
goto out_close;
|
||||
|
||||
memset(&rsp, 0, sizeof(rsp));
|
||||
rsp.data = INT_TO_PTR(ttynum);
|
||||
if (lxc_af_unix_send_fd(fd, masterfd, &rsp, sizeof(rsp)) < 0) {
|
||||
ERROR("failed to send tty to client");
|
||||
lxc_console_free(handler->conf, fd);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_close:
|
||||
/* special indicator to lxc_cmd_handler() to close the fd and do
|
||||
* related cleanup
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
|
||||
typedef int (*callback)(int, struct lxc_cmd_req *, struct lxc_handler *);
|
||||
|
||||
callback cb[LXC_COMMAND_MAX] = {
|
||||
[LXC_COMMAND_TTY] = lxc_console_callback,
|
||||
[LXC_COMMAND_STOP] = lxc_stop_callback,
|
||||
[LXC_COMMAND_STATE] = lxc_state_callback,
|
||||
[LXC_COMMAND_PID] = lxc_pid_callback,
|
||||
[LXC_COMMAND_CLONE_FLAGS] = lxc_clone_flags_callback,
|
||||
[LXC_COMMAND_CGROUP] = lxc_cgroup_callback,
|
||||
callback cb[LXC_CMD_MAX] = {
|
||||
[LXC_CMD_CONSOLE] = lxc_cmd_console_callback,
|
||||
[LXC_CMD_CONSOLE_WINCH] = lxc_cmd_console_winch_callback,
|
||||
[LXC_CMD_STOP] = lxc_cmd_stop_callback,
|
||||
[LXC_CMD_GET_STATE] = lxc_cmd_get_state_callback,
|
||||
[LXC_CMD_GET_INIT_PID] = lxc_cmd_get_init_pid_callback,
|
||||
[LXC_CMD_GET_CLONE_FLAGS] = lxc_cmd_get_clone_flags_callback,
|
||||
[LXC_CMD_GET_CGROUP] = lxc_cmd_get_cgroup_callback,
|
||||
[LXC_CMD_GET_CONFIG_ITEM] = lxc_cmd_get_config_item_callback,
|
||||
};
|
||||
|
||||
if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
|
||||
if (req->cmd < 0 || req->cmd >= LXC_CMD_MAX) {
|
||||
ERROR("bad cmd %d recieved", req->cmd);
|
||||
return -1;
|
||||
|
||||
return cb[request->type](fd, request, handler);
|
||||
}
|
||||
return cb[req->cmd](fd, req, handler);
|
||||
}
|
||||
|
||||
static void command_fd_cleanup(int fd, struct lxc_handler *handler,
|
||||
static void lxc_cmd_fd_cleanup(int fd, struct lxc_handler *handler,
|
||||
struct lxc_epoll_descr *descr)
|
||||
{
|
||||
lxc_console_remove_fd(fd, &handler->conf->tty_info);
|
||||
lxc_console_free(handler->conf, fd);
|
||||
lxc_mainloop_del_handler(descr, fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
|
||||
static int lxc_cmd_handler(int fd, void *data, struct lxc_epoll_descr *descr)
|
||||
{
|
||||
int ret;
|
||||
struct lxc_request request;
|
||||
struct lxc_cmd_req req;
|
||||
struct lxc_handler *handler = data;
|
||||
|
||||
ret = lxc_af_unix_rcv_credential(fd, &request, sizeof(request));
|
||||
ret = lxc_af_unix_rcv_credential(fd, &req, sizeof(req));
|
||||
if (ret == -EACCES) {
|
||||
/* we don't care for the peer, just send and close */
|
||||
struct lxc_answer answer = { .ret = ret };
|
||||
send(fd, &answer, sizeof(answer), 0);
|
||||
struct lxc_cmd_rsp rsp = { .ret = ret };
|
||||
|
||||
lxc_cmd_rsp_send(fd, &rsp);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
@ -269,12 +744,32 @@ static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (ret != sizeof(request)) {
|
||||
if (ret != sizeof(req)) {
|
||||
WARN("partial request, ignored");
|
||||
ret = -1;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
ret = trigger_command(fd, &request, handler);
|
||||
if (req.datalen > LXC_CMD_DATA_MAX) {
|
||||
ERROR("cmd data length %d too large", req.datalen);
|
||||
ret = -1;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (req.datalen > 0) {
|
||||
void *reqdata;
|
||||
|
||||
reqdata = alloca(req.datalen);
|
||||
ret = recv(fd, reqdata, req.datalen, 0);
|
||||
if (ret != req.datalen) {
|
||||
WARN("partial request, ignored");
|
||||
ret = -1;
|
||||
goto out_close;
|
||||
}
|
||||
req.data = reqdata;
|
||||
}
|
||||
|
||||
ret = lxc_cmd_process(fd, &req, handler);
|
||||
if (ret) {
|
||||
/* this is not an error, but only a request to close fd */
|
||||
ret = 0;
|
||||
@ -284,12 +779,11 @@ static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
|
||||
out:
|
||||
return ret;
|
||||
out_close:
|
||||
command_fd_cleanup(fd, handler, descr);
|
||||
lxc_cmd_fd_cleanup(fd, handler, descr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int incoming_command_handler(int fd, void *data,
|
||||
struct lxc_epoll_descr *descr)
|
||||
static int lxc_cmd_accept(int fd, void *data, struct lxc_epoll_descr *descr)
|
||||
{
|
||||
int opt = 1, ret = -1, connection;
|
||||
|
||||
@ -310,7 +804,7 @@ static int incoming_command_handler(int fd, void *data,
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
ret = lxc_mainloop_add_handler(descr, connection, command_handler, data);
|
||||
ret = lxc_mainloop_add_handler(descr, connection, lxc_cmd_handler, data);
|
||||
if (ret) {
|
||||
ERROR("failed to add handler");
|
||||
goto out_close;
|
||||
@ -324,8 +818,8 @@ out_close:
|
||||
goto out;
|
||||
}
|
||||
|
||||
extern int lxc_command_init(const char *name, struct lxc_handler *handler,
|
||||
const char *lxcpath)
|
||||
int lxc_cmd_init(const char *name, struct lxc_handler *handler,
|
||||
const char *lxcpath)
|
||||
{
|
||||
int fd;
|
||||
char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
|
||||
@ -357,14 +851,13 @@ extern int lxc_command_init(const char *name, struct lxc_handler *handler,
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int lxc_command_mainloop_add(const char *name,
|
||||
struct lxc_epoll_descr *descr,
|
||||
struct lxc_handler *handler)
|
||||
int lxc_cmd_mainloop_add(const char *name,
|
||||
struct lxc_epoll_descr *descr,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
int ret, fd = handler->conf->maincmd_fd;
|
||||
|
||||
ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler,
|
||||
handler);
|
||||
ret = lxc_mainloop_add_handler(descr, fd, lxc_cmd_accept, handler);
|
||||
if (ret) {
|
||||
ERROR("failed to add handler for command socket");
|
||||
close(fd);
|
||||
|
@ -18,54 +18,75 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __commands_h
|
||||
#define __commands_h
|
||||
|
||||
enum {
|
||||
LXC_COMMAND_TTY,
|
||||
LXC_COMMAND_STOP,
|
||||
LXC_COMMAND_STATE,
|
||||
LXC_COMMAND_PID,
|
||||
LXC_COMMAND_CLONE_FLAGS,
|
||||
LXC_COMMAND_CGROUP,
|
||||
LXC_COMMAND_MAX,
|
||||
#include "state.h"
|
||||
|
||||
#define LXC_CMD_DATA_MAX (MAXPATHLEN*2)
|
||||
|
||||
/* https://developer.gnome.org/glib/2.28/glib-Type-Conversion-Macros.html */
|
||||
#define INT_TO_PTR(n) ((void *) (long) (n))
|
||||
#define PTR_TO_INT(p) ((int) (long) (p))
|
||||
|
||||
typedef enum {
|
||||
LXC_CMD_CONSOLE,
|
||||
LXC_CMD_CONSOLE_WINCH,
|
||||
LXC_CMD_STOP,
|
||||
LXC_CMD_GET_STATE,
|
||||
LXC_CMD_GET_INIT_PID,
|
||||
LXC_CMD_GET_CLONE_FLAGS,
|
||||
LXC_CMD_GET_CGROUP,
|
||||
LXC_CMD_GET_CONFIG_ITEM,
|
||||
LXC_CMD_MAX,
|
||||
} lxc_cmd_t;
|
||||
|
||||
struct lxc_cmd_req {
|
||||
lxc_cmd_t cmd;
|
||||
int datalen;
|
||||
const void *data;
|
||||
};
|
||||
|
||||
struct lxc_request {
|
||||
int type;
|
||||
int data;
|
||||
};
|
||||
|
||||
struct lxc_answer {
|
||||
int fd;
|
||||
struct lxc_cmd_rsp {
|
||||
int ret; /* 0 on success, -errno on failure */
|
||||
pid_t pid;
|
||||
int pathlen;
|
||||
const char *path;
|
||||
int datalen;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct lxc_command {
|
||||
struct lxc_request request;
|
||||
struct lxc_answer answer;
|
||||
struct lxc_cmd_rr {
|
||||
struct lxc_cmd_req req;
|
||||
struct lxc_cmd_rsp rsp;
|
||||
};
|
||||
|
||||
extern pid_t get_init_pid(const char *name, const char *lxcpath);
|
||||
extern int lxc_get_clone_flags(const char *name, const char *lxcpath);
|
||||
struct lxc_cmd_console_rsp_data {
|
||||
int masterfd;
|
||||
int ttynum;
|
||||
};
|
||||
|
||||
extern int lxc_command(const char *name, struct lxc_command *command,
|
||||
int *stopped, const char *lxcpath);
|
||||
|
||||
extern int lxc_command_connected(const char *name, struct lxc_command *command,
|
||||
int *stopped, const char *lxcpath);
|
||||
extern int lxc_cmd_console_winch(const char *name, const char *lxcpath);
|
||||
extern int lxc_cmd_console(const char *name, int *ttynum, int *fd,
|
||||
const char *lxcpath);
|
||||
/*
|
||||
* Get the 'real' cgroup path (as seen in /proc/self/cgroup) for a container
|
||||
* for a particular subsystem
|
||||
*/
|
||||
extern char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
|
||||
const char *subsystem);
|
||||
extern int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath);
|
||||
extern char *lxc_cmd_get_config_item(const char *name, const char *item, const char *lxcpath);
|
||||
extern pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath);
|
||||
extern lxc_state_t lxc_cmd_get_state(const char *name, const char *lxcpath);
|
||||
extern int lxc_cmd_stop(const char *name, const char *lxcpath);
|
||||
|
||||
struct lxc_epoll_descr;
|
||||
struct lxc_handler;
|
||||
|
||||
extern int lxc_command_init(const char *name, struct lxc_handler *handler,
|
||||
extern int lxc_cmd_init(const char *name, struct lxc_handler *handler,
|
||||
const char *lxcpath);
|
||||
extern int lxc_command_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
|
||||
extern int lxc_cmd_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
|
||||
struct lxc_handler *handler);
|
||||
|
||||
#endif
|
||||
#endif /* __commands_h */
|
||||
|
390
src/lxc/conf.c
390
src/lxc/conf.c
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
@ -31,6 +31,13 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <time.h>
|
||||
|
||||
#if HAVE_IFADDRS_H
|
||||
#include <ifaddrs.h>
|
||||
#else
|
||||
#include <../include/ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_PTY_H
|
||||
#include <pty.h>
|
||||
@ -64,6 +71,7 @@
|
||||
#include "log.h"
|
||||
#include "lxc.h" /* for lxc_cgroup_set() */
|
||||
#include "caps.h" /* for lxc_caps_last_cap() */
|
||||
#include "bdev.h"
|
||||
|
||||
#if HAVE_APPARMOR
|
||||
#include <apparmor.h>
|
||||
@ -92,30 +100,6 @@ lxc_log_define(lxc_conf, lxc);
|
||||
#define MAXMTULEN 16
|
||||
#define MAXLINELEN 128
|
||||
|
||||
#ifndef MS_DIRSYNC
|
||||
#define MS_DIRSYNC 128
|
||||
#endif
|
||||
|
||||
#ifndef MS_REC
|
||||
#define MS_REC 16384
|
||||
#endif
|
||||
|
||||
#ifndef MNT_DETACH
|
||||
#define MNT_DETACH 2
|
||||
#endif
|
||||
|
||||
#ifndef MS_SLAVE
|
||||
#define MS_SLAVE (1<<19)
|
||||
#endif
|
||||
|
||||
#ifndef MS_RELATIME
|
||||
#define MS_RELATIME (1 << 21)
|
||||
#endif
|
||||
|
||||
#ifndef MS_STRICTATIME
|
||||
#define MS_STRICTATIME (1 << 24)
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_CAPABILITY_H
|
||||
#ifndef CAP_SETFCAP
|
||||
#define CAP_SETFCAP 31
|
||||
@ -172,7 +156,7 @@ return -1;
|
||||
#endif
|
||||
|
||||
char *lxchook_names[NUM_LXC_HOOKS] = {
|
||||
"pre-start", "pre-mount", "mount", "autodev", "start", "post-stop" };
|
||||
"pre-start", "pre-mount", "mount", "autodev", "start", "post-stop", "clone" };
|
||||
|
||||
typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
|
||||
|
||||
@ -295,10 +279,75 @@ static struct caps_opt caps_opt[] = {
|
||||
static struct caps_opt caps_opt[] = {};
|
||||
#endif
|
||||
|
||||
static char padchar[] =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
static char *mkifname(char *template)
|
||||
{
|
||||
char *name = NULL;
|
||||
int i = 0;
|
||||
FILE *urandom;
|
||||
unsigned int seed;
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
int ifexists = 0;
|
||||
|
||||
/* Get all the network interfaces */
|
||||
getifaddrs(&ifaddr);
|
||||
|
||||
/* Initialize the random number generator */
|
||||
urandom = fopen ("/dev/urandom", "r");
|
||||
if (urandom != NULL) {
|
||||
if (fread (&seed, sizeof(seed), 1, urandom) <= 0)
|
||||
seed = time(0);
|
||||
fclose(urandom);
|
||||
}
|
||||
else
|
||||
seed = time(0);
|
||||
|
||||
#ifndef HAVE_RAND_R
|
||||
srand(seed);
|
||||
#endif
|
||||
|
||||
/* Generate random names until we find one that doesn't exist */
|
||||
while(1) {
|
||||
ifexists = 0;
|
||||
name = strdup(template);
|
||||
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < strlen(name); i++) {
|
||||
if (name[i] == 'X') {
|
||||
#ifdef HAVE_RAND_R
|
||||
name[i] = padchar[rand_r(&seed) % (strlen(padchar) - 1)];
|
||||
#else
|
||||
name[i] = padchar[rand() % (strlen(padchar) - 1)];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
if (strcmp(ifa->ifa_name, name) == 0) {
|
||||
ifexists = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifexists == 0)
|
||||
break;
|
||||
|
||||
free(name);
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
return name;
|
||||
}
|
||||
|
||||
static int run_buffer(char *buffer)
|
||||
{
|
||||
FILE *f;
|
||||
char *output;
|
||||
int ret;
|
||||
|
||||
f = popen(buffer, "r");
|
||||
if (!f) {
|
||||
@ -309,6 +358,7 @@ static int run_buffer(char *buffer)
|
||||
output = malloc(LXC_LOG_BUFFER_SIZE);
|
||||
if (!output) {
|
||||
ERROR("failed to allocate memory for script output");
|
||||
pclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -317,14 +367,72 @@ static int run_buffer(char *buffer)
|
||||
|
||||
free(output);
|
||||
|
||||
if (pclose(f) == -1) {
|
||||
ret = pclose(f);
|
||||
if (ret == -1) {
|
||||
SYSERROR("Script exited on error");
|
||||
return -1;
|
||||
} else if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) {
|
||||
ERROR("Script exited with status %d", WEXITSTATUS(ret));
|
||||
return -1;
|
||||
} else if (WIFSIGNALED(ret)) {
|
||||
ERROR("Script terminated by signal %d (%s)", WTERMSIG(ret),
|
||||
strsignal(WTERMSIG(ret)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_script_argv(const char *name, const char *section,
|
||||
const char *script, const char *hook, const char *lxcpath,
|
||||
char **argsin)
|
||||
{
|
||||
int ret, i;
|
||||
char *buffer;
|
||||
size_t size = 0;
|
||||
|
||||
INFO("Executing script '%s' for container '%s', config section '%s'",
|
||||
script, name, section);
|
||||
|
||||
for (i=0; argsin && argsin[i]; i++)
|
||||
size += strlen(argsin[i]) + 1;
|
||||
|
||||
size += strlen(hook) + 1;
|
||||
|
||||
size += strlen(script);
|
||||
size += strlen(name);
|
||||
size += strlen(section);
|
||||
size += 3;
|
||||
|
||||
if (size > INT_MAX)
|
||||
return -1;
|
||||
|
||||
buffer = alloca(size);
|
||||
if (!buffer) {
|
||||
ERROR("failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = snprintf(buffer, size, "%s %s %s %s", script, name, section, hook);
|
||||
if (ret < 0 || ret >= size) {
|
||||
ERROR("Script name too long");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0; argsin && argsin[i]; i++) {
|
||||
int len = size-ret;
|
||||
int rc;
|
||||
rc = snprintf(buffer + ret, len, " %s", argsin[i]);
|
||||
if (rc < 0 || rc >= len) {
|
||||
ERROR("Script args too long");
|
||||
return -1;
|
||||
}
|
||||
ret += rc;
|
||||
}
|
||||
|
||||
return run_buffer(buffer);
|
||||
}
|
||||
|
||||
static int run_script(const char *name, const char *section,
|
||||
const char *script, ...)
|
||||
{
|
||||
@ -358,7 +466,6 @@ static int run_script(const char *name, const char *section,
|
||||
ret = snprintf(buffer, size, "%s %s %s", script, name, section);
|
||||
if (ret < 0 || ret >= size) {
|
||||
ERROR("Script name too long");
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -368,7 +475,6 @@ static int run_script(const char *name, const char *section,
|
||||
int rc;
|
||||
rc = snprintf(buffer + ret, len, " %s", p);
|
||||
if (rc < 0 || rc >= len) {
|
||||
free(buffer);
|
||||
ERROR("Script args too long");
|
||||
return -1;
|
||||
}
|
||||
@ -537,6 +643,7 @@ static int mount_rootfs_file(const char *rootfs, const char *target)
|
||||
if (errno != ENXIO) {
|
||||
WARN("unexpected error for ioctl on '%s': %m",
|
||||
direntp->d_name);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -581,8 +688,8 @@ int pin_rootfs(const char *rootfs)
|
||||
return -2;
|
||||
|
||||
if (!realpath(rootfs, absrootfs)) {
|
||||
SYSERROR("failed to get real path for '%s'", rootfs);
|
||||
return -1;
|
||||
INFO("failed to get real path for '%s', not pinning", rootfs);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (access(absrootfs, F_OK)) {
|
||||
@ -700,7 +807,8 @@ static int setup_tty(const struct lxc_rootfs *rootfs,
|
||||
SYSERROR("error creating %s\n", lxcpath);
|
||||
return -1;
|
||||
}
|
||||
close(ret);
|
||||
if (ret >= 0)
|
||||
close(ret);
|
||||
ret = unlink(path);
|
||||
if (ret && errno != ENOENT) {
|
||||
SYSERROR("error unlinking %s\n", path);
|
||||
@ -749,7 +857,7 @@ static int setup_tty(const struct lxc_rootfs *rootfs,
|
||||
static int setup_rootfs_pivot_root_cb(char *buffer, void *data)
|
||||
{
|
||||
struct lxc_list *mountlist, *listentry, *iterator;
|
||||
char *pivotdir, *mountpoint, *mountentry;
|
||||
char *pivotdir, *mountpoint, *mountentry, *saveptr = NULL;
|
||||
int found;
|
||||
void **cbparm;
|
||||
|
||||
@ -760,12 +868,12 @@ static int setup_rootfs_pivot_root_cb(char *buffer, void *data)
|
||||
pivotdir = cbparm[1];
|
||||
|
||||
/* parse entry, first field is mountname, ignore */
|
||||
mountpoint = strtok(mountentry, " ");
|
||||
mountpoint = strtok_r(mountentry, " ", &saveptr);
|
||||
if (!mountpoint)
|
||||
return -1;
|
||||
|
||||
/* second field is mountpoint */
|
||||
mountpoint = strtok(NULL, " ");
|
||||
mountpoint = strtok_r(NULL, " ", &saveptr);
|
||||
if (!mountpoint)
|
||||
return -1;
|
||||
|
||||
@ -794,6 +902,7 @@ static int setup_rootfs_pivot_root_cb(char *buffer, void *data)
|
||||
listentry->elem = strdup(mountpoint);
|
||||
if (!listentry->elem) {
|
||||
SYSERROR("strdup failed");
|
||||
free(listentry);
|
||||
return -1;
|
||||
}
|
||||
lxc_list_add_tail(mountlist, listentry);
|
||||
@ -1055,8 +1164,10 @@ int detect_shared_rootfs(void)
|
||||
if (strcmp(p+1, "/") == 0) {
|
||||
// this is '/'. is it shared?
|
||||
p = index(p2+1, ' ');
|
||||
if (strstr(p, "shared:"))
|
||||
if (p && strstr(p, "shared:")) {
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
@ -1150,6 +1261,15 @@ static int setup_rootfs(struct lxc_conf *conf)
|
||||
}
|
||||
}
|
||||
|
||||
// First try mounting rootfs using a bdev
|
||||
struct bdev *bdev = bdev_init(rootfs->path, rootfs->mount, NULL);
|
||||
if (bdev && bdev->ops->mount(bdev) == 0) {
|
||||
bdev_put(bdev);
|
||||
DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount);
|
||||
return 0;
|
||||
}
|
||||
if (bdev)
|
||||
bdev_put(bdev);
|
||||
if (mount_rootfs(rootfs->path, rootfs->mount)) {
|
||||
ERROR("failed to mount rootfs");
|
||||
return -1;
|
||||
@ -1248,8 +1368,8 @@ static int setup_dev_console(const struct lxc_rootfs *rootfs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (console->peer == -1) {
|
||||
INFO("no console output required");
|
||||
if (console->master < 0) {
|
||||
INFO("no console");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1311,10 +1431,11 @@ static int setup_ttydir_console(const struct lxc_rootfs *rootfs,
|
||||
SYSERROR("error %d creating %s\n", errno, lxcpath);
|
||||
return -1;
|
||||
}
|
||||
close(ret);
|
||||
if (ret >= 0)
|
||||
close(ret);
|
||||
|
||||
if (console->peer == -1) {
|
||||
INFO("no console output required");
|
||||
if (console->master < 0) {
|
||||
INFO("no console");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1380,34 +1501,6 @@ static int setup_kmsg(const struct lxc_rootfs *rootfs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setup_cgroup(const char *cgpath, struct lxc_list *cgroups)
|
||||
{
|
||||
struct lxc_list *iterator;
|
||||
struct lxc_cgroup *cg;
|
||||
int ret = -1;
|
||||
|
||||
if (lxc_list_empty(cgroups))
|
||||
return 0;
|
||||
|
||||
lxc_list_for_each(iterator, cgroups) {
|
||||
|
||||
cg = iterator->elem;
|
||||
|
||||
if (lxc_cgroup_set_bypath(cgpath, cg->subsystem, cg->value)) {
|
||||
ERROR("Error setting %s to %s for %s\n", cg->subsystem,
|
||||
cg->value, cgpath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
INFO("cgroup has been setup");
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void parse_mntopt(char *opt, unsigned long *flags, char **data)
|
||||
{
|
||||
struct mount_opt *mo;
|
||||
@ -1745,7 +1838,76 @@ static int setup_caps(struct lxc_list *caps)
|
||||
|
||||
}
|
||||
|
||||
DEBUG("capabilities has been setup");
|
||||
DEBUG("capabilities have been setup");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dropcaps_except(struct lxc_list *caps)
|
||||
{
|
||||
struct lxc_list *iterator;
|
||||
char *keep_entry;
|
||||
char *ptr;
|
||||
int i, capid;
|
||||
int numcaps = lxc_caps_last_cap() + 1;
|
||||
INFO("found %d capabilities\n", numcaps);
|
||||
|
||||
if (numcaps <= 0 || numcaps > 200)
|
||||
return -1;
|
||||
|
||||
// caplist[i] is 1 if we keep capability i
|
||||
int *caplist = alloca(numcaps * sizeof(int));
|
||||
memset(caplist, 0, numcaps * sizeof(int));
|
||||
|
||||
lxc_list_for_each(iterator, caps) {
|
||||
|
||||
keep_entry = iterator->elem;
|
||||
|
||||
capid = -1;
|
||||
|
||||
for (i = 0; i < sizeof(caps_opt)/sizeof(caps_opt[0]); i++) {
|
||||
|
||||
if (strcmp(keep_entry, caps_opt[i].name))
|
||||
continue;
|
||||
|
||||
capid = caps_opt[i].value;
|
||||
break;
|
||||
}
|
||||
|
||||
if (capid < 0) {
|
||||
/* try to see if it's numeric, so the user may specify
|
||||
* capabilities that the running kernel knows about but
|
||||
* we don't */
|
||||
capid = strtol(keep_entry, &ptr, 10);
|
||||
if (!ptr || *ptr != '\0' ||
|
||||
capid == LONG_MIN || capid == LONG_MAX)
|
||||
/* not a valid number */
|
||||
capid = -1;
|
||||
else if (capid > lxc_caps_last_cap())
|
||||
/* we have a number but it's not a valid
|
||||
* capability */
|
||||
capid = -1;
|
||||
}
|
||||
|
||||
if (capid < 0) {
|
||||
ERROR("unknown capability %s", keep_entry);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG("drop capability '%s' (%d)", keep_entry, capid);
|
||||
|
||||
caplist[capid] = 1;
|
||||
}
|
||||
for (i=0; i<numcaps; i++) {
|
||||
if (caplist[i])
|
||||
continue;
|
||||
if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0)) {
|
||||
SYSERROR("failed to remove capability %d", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG("capabilities have been setup");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2063,21 +2225,31 @@ struct lxc_conf *lxc_conf_init(void)
|
||||
}
|
||||
memset(new, 0, sizeof(*new));
|
||||
|
||||
new->loglevel = LXC_LOG_PRIORITY_NOTSET;
|
||||
new->personality = -1;
|
||||
new->console.log_path = NULL;
|
||||
new->console.log_fd = -1;
|
||||
new->console.path = NULL;
|
||||
new->console.peer = -1;
|
||||
new->console.peerpty.busy = -1;
|
||||
new->console.peerpty.master = -1;
|
||||
new->console.peerpty.slave = -1;
|
||||
new->console.master = -1;
|
||||
new->console.slave = -1;
|
||||
new->console.name[0] = '\0';
|
||||
new->maincmd_fd = -1;
|
||||
new->rootfs.mount = default_rootfs_mount;
|
||||
new->rootfs.mount = strdup(default_rootfs_mount);
|
||||
if (!new->rootfs.mount) {
|
||||
ERROR("lxc_conf_init : %m");
|
||||
free(new);
|
||||
return NULL;
|
||||
}
|
||||
new->kmsg = 1;
|
||||
lxc_list_init(&new->cgroup);
|
||||
lxc_list_init(&new->network);
|
||||
lxc_list_init(&new->mount_list);
|
||||
lxc_list_init(&new->caps);
|
||||
lxc_list_init(&new->keepcaps);
|
||||
lxc_list_init(&new->id_map);
|
||||
for (i=0; i<NUM_LXC_HOOKS; i++)
|
||||
lxc_list_init(&new->hooks[i]);
|
||||
@ -2105,13 +2277,13 @@ static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
|
||||
ERROR("veth1 name too long");
|
||||
return -1;
|
||||
}
|
||||
veth1 = mktemp(veth1buf);
|
||||
veth1 = mkifname(veth1buf);
|
||||
/* store away for deconf */
|
||||
memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
|
||||
}
|
||||
|
||||
snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
|
||||
veth2 = mktemp(veth2buf);
|
||||
veth2 = mkifname(veth2buf);
|
||||
|
||||
if (!strlen(veth1) || !strlen(veth2)) {
|
||||
ERROR("failed to allocate a temporary name");
|
||||
@ -2217,7 +2389,7 @@ static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n
|
||||
if (err >= sizeof(peerbuf))
|
||||
return -1;
|
||||
|
||||
peer = mktemp(peerbuf);
|
||||
peer = mkifname(peerbuf);
|
||||
if (!strlen(peer)) {
|
||||
ERROR("failed to make a temporary name");
|
||||
return -1;
|
||||
@ -2715,7 +2887,7 @@ int uid_shift_ttys(int pid, struct lxc_conf *conf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
|
||||
int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char *lxcpath)
|
||||
{
|
||||
#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
|
||||
int mounted;
|
||||
@ -2731,7 +2903,7 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (run_lxc_hooks(name, "pre-mount", lxc_conf)) {
|
||||
if (run_lxc_hooks(name, "pre-mount", lxc_conf, lxcpath, NULL)) {
|
||||
ERROR("failed to run pre-mount hooks for container '%s'.", name);
|
||||
return -1;
|
||||
}
|
||||
@ -2758,13 +2930,13 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (run_lxc_hooks(name, "mount", lxc_conf)) {
|
||||
if (run_lxc_hooks(name, "mount", lxc_conf, lxcpath, NULL)) {
|
||||
ERROR("failed to run mount hooks for container '%s'.", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lxc_conf->autodev) {
|
||||
if (run_lxc_hooks(name, "autodev", lxc_conf)) {
|
||||
if (run_lxc_hooks(name, "autodev", lxc_conf, lxcpath, NULL)) {
|
||||
ERROR("failed to run autodev hooks for container '%s'.", name);
|
||||
return -1;
|
||||
}
|
||||
@ -2774,7 +2946,7 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
|
||||
}
|
||||
}
|
||||
|
||||
if (setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
|
||||
if (!lxc_conf->is_execute && setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
|
||||
ERROR("failed to setup the console for '%s'", name);
|
||||
return -1;
|
||||
}
|
||||
@ -2784,7 +2956,7 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
|
||||
ERROR("failed to setup kmsg for '%s'", name);
|
||||
}
|
||||
|
||||
if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) {
|
||||
if (!lxc_conf->is_execute && setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) {
|
||||
ERROR("failed to setup the ttys for '%s'", name);
|
||||
return -1;
|
||||
}
|
||||
@ -2792,9 +2964,13 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
|
||||
#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
|
||||
INFO("rootfs path is .%s., mount is .%s.", lxc_conf->rootfs.path,
|
||||
lxc_conf->rootfs.mount);
|
||||
if (lxc_conf->rootfs.path == NULL || strlen(lxc_conf->rootfs.path) == 0)
|
||||
mounted = 0;
|
||||
else
|
||||
if (lxc_conf->rootfs.path == NULL || strlen(lxc_conf->rootfs.path) == 0) {
|
||||
if (mount("proc", "/proc", "proc", 0, NULL)) {
|
||||
SYSERROR("Failed mounting /proc, proceeding");
|
||||
mounted = 0;
|
||||
} else
|
||||
mounted = 1;
|
||||
} else
|
||||
mounted = lsm_mount_proc_if_needed(lxc_conf->rootfs.path, lxc_conf->rootfs.mount);
|
||||
if (mounted == -1) {
|
||||
SYSERROR("failed to mount /proc in the container.");
|
||||
@ -2820,7 +2996,16 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
|
||||
}
|
||||
|
||||
if (lxc_list_empty(&lxc_conf->id_map)) {
|
||||
if (setup_caps(&lxc_conf->caps)) {
|
||||
if (!lxc_list_empty(&lxc_conf->keepcaps)) {
|
||||
if (!lxc_list_empty(&lxc_conf->caps)) {
|
||||
ERROR("Simultaneously requested dropping and keeping caps");
|
||||
return -1;
|
||||
}
|
||||
if (dropcaps_except(&lxc_conf->keepcaps)) {
|
||||
ERROR("failed to keep requested caps\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (setup_caps(&lxc_conf->caps)) {
|
||||
ERROR("failed to drop capabilities");
|
||||
return -1;
|
||||
}
|
||||
@ -2831,7 +3016,8 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
|
||||
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
|
||||
const char *lxcpath, char *argv[])
|
||||
{
|
||||
int which = -1;
|
||||
struct lxc_list *it;
|
||||
@ -2848,12 +3034,14 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
|
||||
which = LXCHOOK_START;
|
||||
else if (strcmp(hook, "post-stop") == 0)
|
||||
which = LXCHOOK_POSTSTOP;
|
||||
else if (strcmp(hook, "clone") == 0)
|
||||
which = LXCHOOK_CLONE;
|
||||
else
|
||||
return -1;
|
||||
lxc_list_for_each(it, &conf->hooks[which]) {
|
||||
int ret;
|
||||
char *hookname = it->elem;
|
||||
ret = run_script(name, "lxc", hookname, hook, NULL);
|
||||
ret = run_script_argv(name, "lxc", hookname, hook, lxcpath, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -3004,6 +3192,30 @@ int lxc_clear_config_caps(struct lxc_conf *c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lxc_clear_idmaps(struct lxc_conf *c)
|
||||
{
|
||||
struct lxc_list *it, *next;
|
||||
|
||||
lxc_list_for_each_safe(it, &c->id_map, next) {
|
||||
lxc_list_del(it);
|
||||
free(it->elem);
|
||||
free(it);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lxc_clear_config_keepcaps(struct lxc_conf *c)
|
||||
{
|
||||
struct lxc_list *it,*next;
|
||||
|
||||
lxc_list_for_each_safe(it, &c->keepcaps, next) {
|
||||
lxc_list_del(it);
|
||||
free(it->elem);
|
||||
free(it);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lxc_clear_cgroups(struct lxc_conf *c, const char *key)
|
||||
{
|
||||
struct lxc_list *it,*next;
|
||||
@ -3084,7 +3296,7 @@ void lxc_conf_free(struct lxc_conf *conf)
|
||||
return;
|
||||
if (conf->console.path)
|
||||
free(conf->console.path);
|
||||
if (conf->rootfs.mount != default_rootfs_mount)
|
||||
if (conf->rootfs.mount)
|
||||
free(conf->rootfs.mount);
|
||||
if (conf->rootfs.path)
|
||||
free(conf->rootfs.path);
|
||||
@ -3094,6 +3306,8 @@ void lxc_conf_free(struct lxc_conf *conf)
|
||||
free(conf->ttydir);
|
||||
if (conf->fstab)
|
||||
free(conf->fstab);
|
||||
if (conf->rcfile)
|
||||
free(conf->rcfile);
|
||||
lxc_clear_config_network(conf);
|
||||
#if HAVE_APPARMOR
|
||||
if (conf->aa_profile)
|
||||
@ -3101,9 +3315,11 @@ void lxc_conf_free(struct lxc_conf *conf)
|
||||
#endif
|
||||
lxc_seccomp_free(conf);
|
||||
lxc_clear_config_caps(conf);
|
||||
lxc_clear_config_keepcaps(conf);
|
||||
lxc_clear_cgroups(conf, "lxc.cgroup");
|
||||
lxc_clear_hooks(conf, "lxc.hook");
|
||||
lxc_clear_mount_entries(conf);
|
||||
lxc_clear_saved_nics(conf);
|
||||
lxc_clear_idmaps(conf);
|
||||
free(conf);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef _conf_h
|
||||
#define _conf_h
|
||||
@ -188,6 +188,8 @@ struct lxc_tty_info {
|
||||
struct lxc_pty_info *pty_info;
|
||||
};
|
||||
|
||||
struct lxc_tty_state;
|
||||
|
||||
/*
|
||||
* Defines the structure to store the console information
|
||||
* @peer : the file descriptor put/get console traffic
|
||||
@ -197,11 +199,14 @@ struct lxc_console {
|
||||
int slave;
|
||||
int master;
|
||||
int peer;
|
||||
struct lxc_pty_info peerpty;
|
||||
struct lxc_epoll_descr *descr;
|
||||
char *path;
|
||||
char *log_path;
|
||||
int log_fd;
|
||||
char name[MAXPATHLEN];
|
||||
struct termios *tios;
|
||||
struct lxc_tty_state *tty_state;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -227,7 +232,8 @@ struct lxc_rootfs {
|
||||
* @network : network configuration
|
||||
* @utsname : container utsname
|
||||
* @fstab : path to a fstab file format
|
||||
* @caps : list of the capabilities
|
||||
* @caps : list of the capabilities to drop
|
||||
* @keepcaps : list of the capabilities to keep
|
||||
* @tty_info : tty data
|
||||
* @console : console data
|
||||
* @ttydir : directory (under /dev) in which to create console and ttys
|
||||
@ -237,7 +243,7 @@ struct lxc_rootfs {
|
||||
*/
|
||||
enum lxchooks {
|
||||
LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_AUTODEV,
|
||||
LXCHOOK_START, LXCHOOK_POSTSTOP, NUM_LXC_HOOKS};
|
||||
LXCHOOK_START, LXCHOOK_POSTSTOP, LXCHOOK_CLONE, NUM_LXC_HOOKS};
|
||||
extern char *lxchook_names[NUM_LXC_HOOKS];
|
||||
|
||||
struct saved_nic {
|
||||
@ -246,6 +252,7 @@ struct saved_nic {
|
||||
};
|
||||
|
||||
struct lxc_conf {
|
||||
int is_execute;
|
||||
char *fstab;
|
||||
int tty;
|
||||
int pts;
|
||||
@ -260,6 +267,7 @@ struct lxc_conf {
|
||||
int num_savednics;
|
||||
struct lxc_list mount_list;
|
||||
struct lxc_list caps;
|
||||
struct lxc_list keepcaps;
|
||||
struct lxc_tty_info tty_info;
|
||||
struct lxc_console console;
|
||||
struct lxc_rootfs rootfs;
|
||||
@ -282,11 +290,19 @@ struct lxc_conf {
|
||||
int stopsignal; // signal used to stop container
|
||||
int kmsg; // if 1, create /dev/kmsg symlink
|
||||
char *rcfile; // Copy of the top level rcfile we read
|
||||
|
||||
// Logfile and logleve can be set in a container config file.
|
||||
// Those function as defaults. The defaults can be overriden
|
||||
// by command line. However we don't want the command line
|
||||
// specified values to be saved on c->save_config(). So we
|
||||
// store the config file specified values here.
|
||||
char *logfile; // the logfile as specifed in config
|
||||
int loglevel; // loglevel as specifed in config (if any)
|
||||
};
|
||||
|
||||
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
|
||||
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
|
||||
const char *lxcpath, char *argv[]);
|
||||
|
||||
extern int setup_cgroup(const char *cgpath, struct lxc_list *cgroups);
|
||||
extern int detect_shared_rootfs(void);
|
||||
|
||||
/*
|
||||
@ -309,19 +325,19 @@ extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
|
||||
extern int lxc_clear_config_network(struct lxc_conf *c);
|
||||
extern int lxc_clear_nic(struct lxc_conf *c, const char *key);
|
||||
extern int lxc_clear_config_caps(struct lxc_conf *c);
|
||||
extern int lxc_clear_config_keepcaps(struct lxc_conf *c);
|
||||
extern int lxc_clear_cgroups(struct lxc_conf *c, const char *key);
|
||||
extern int lxc_clear_mount_entries(struct lxc_conf *c);
|
||||
extern int lxc_clear_hooks(struct lxc_conf *c, const char *key);
|
||||
|
||||
extern int setup_cgroup(const char *name, struct lxc_list *cgroups);
|
||||
|
||||
extern int uid_shift_ttys(int pid, struct lxc_conf *conf);
|
||||
|
||||
/*
|
||||
* Configure the container from inside
|
||||
*/
|
||||
|
||||
extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf);
|
||||
extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf,
|
||||
const char *lxcpath);
|
||||
|
||||
extern void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf);
|
||||
#endif
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
@ -85,6 +85,7 @@ static int config_network_script(const char *, const char *, struct lxc_conf *);
|
||||
static int config_network_ipv6(const char *, const char *, struct lxc_conf *);
|
||||
static int config_network_ipv6_gateway(const char *, const char *, struct lxc_conf *);
|
||||
static int config_cap_drop(const char *, const char *, struct lxc_conf *);
|
||||
static int config_cap_keep(const char *, const char *, struct lxc_conf *);
|
||||
static int config_console(const char *, const char *, struct lxc_conf *);
|
||||
static int config_seccomp(const char *, const char *, struct lxc_conf *);
|
||||
static int config_includefile(const char *, const char *, struct lxc_conf *);
|
||||
@ -117,6 +118,7 @@ static struct lxc_config_t config[] = {
|
||||
{ "lxc.hook.autodev", config_hook },
|
||||
{ "lxc.hook.start", config_hook },
|
||||
{ "lxc.hook.post-stop", config_hook },
|
||||
{ "lxc.hook.clone", config_hook },
|
||||
{ "lxc.network.type", config_network_type },
|
||||
{ "lxc.network.flags", config_network_flags },
|
||||
{ "lxc.network.link", config_network_link },
|
||||
@ -135,6 +137,7 @@ static struct lxc_config_t config[] = {
|
||||
/* config_network_nic must come after all other 'lxc.network.*' entries */
|
||||
{ "lxc.network.", config_network_nic },
|
||||
{ "lxc.cap.drop", config_cap_drop },
|
||||
{ "lxc.cap.keep", config_cap_keep },
|
||||
{ "lxc.console", config_console },
|
||||
{ "lxc.seccomp", config_seccomp },
|
||||
{ "lxc.include", config_includefile },
|
||||
@ -272,6 +275,7 @@ static int config_network_type(const char *key, const char *value,
|
||||
list = malloc(sizeof(*list));
|
||||
if (!list) {
|
||||
SYSERROR("failed to allocate memory");
|
||||
free(netdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -610,6 +614,7 @@ static int config_network_ipv4(const char *key, const char *value,
|
||||
list = malloc(sizeof(*list));
|
||||
if (!list) {
|
||||
SYSERROR("failed to allocate memory");
|
||||
free(inetdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -619,6 +624,8 @@ static int config_network_ipv4(const char *key, const char *value,
|
||||
addr = strdup(value);
|
||||
if (!addr) {
|
||||
ERROR("no address specified");
|
||||
free(inetdev);
|
||||
free(list);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -636,12 +643,16 @@ static int config_network_ipv4(const char *key, const char *value,
|
||||
|
||||
if (!inet_pton(AF_INET, addr, &inetdev->addr)) {
|
||||
SYSERROR("invalid ipv4 address: %s", value);
|
||||
free(inetdev);
|
||||
free(addr);
|
||||
free(list);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) {
|
||||
SYSERROR("invalid ipv4 broadcast address: %s", value);
|
||||
free(inetdev);
|
||||
free(list);
|
||||
free(addr);
|
||||
return -1;
|
||||
}
|
||||
@ -683,6 +694,7 @@ static int config_network_ipv4_gateway(const char *key, const char *value,
|
||||
|
||||
if (!value) {
|
||||
ERROR("no ipv4 gateway address specified");
|
||||
free(gw);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -692,6 +704,7 @@ static int config_network_ipv4_gateway(const char *key, const char *value,
|
||||
} else {
|
||||
if (!inet_pton(AF_INET, value, gw)) {
|
||||
SYSERROR("invalid ipv4 gateway address: %s", value);
|
||||
free(gw);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -725,6 +738,7 @@ static int config_network_ipv6(const char *key, const char *value,
|
||||
list = malloc(sizeof(*list));
|
||||
if (!list) {
|
||||
SYSERROR("failed to allocate memory");
|
||||
free(inet6dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -734,6 +748,8 @@ static int config_network_ipv6(const char *key, const char *value,
|
||||
valdup = strdup(value);
|
||||
if (!valdup) {
|
||||
ERROR("no address specified");
|
||||
free(list);
|
||||
free(inet6dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -745,8 +761,10 @@ static int config_network_ipv6(const char *key, const char *value,
|
||||
inet6dev->prefix = atoi(netmask);
|
||||
}
|
||||
|
||||
if (!inet_pton(AF_INET6, value, &inet6dev->addr)) {
|
||||
SYSERROR("invalid ipv6 address: %s", value);
|
||||
if (!inet_pton(AF_INET6, valdup, &inet6dev->addr)) {
|
||||
SYSERROR("invalid ipv6 address: %s", valdup);
|
||||
free(list);
|
||||
free(inet6dev);
|
||||
free(valdup);
|
||||
return -1;
|
||||
}
|
||||
@ -761,18 +779,11 @@ static int config_network_ipv6_gateway(const char *key, const char *value,
|
||||
struct lxc_conf *lxc_conf)
|
||||
{
|
||||
struct lxc_netdev *netdev;
|
||||
struct in6_addr *gw;
|
||||
|
||||
netdev = network_netdev(key, value, &lxc_conf->network);
|
||||
if (!netdev)
|
||||
return -1;
|
||||
|
||||
gw = malloc(sizeof(*gw));
|
||||
if (!gw) {
|
||||
SYSERROR("failed to allocate ipv6 gateway address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
ERROR("no ipv6 gateway address specified");
|
||||
return -1;
|
||||
@ -782,8 +793,17 @@ static int config_network_ipv6_gateway(const char *key, const char *value,
|
||||
netdev->ipv6_gateway = NULL;
|
||||
netdev->ipv6_gateway_auto = true;
|
||||
} else {
|
||||
struct in6_addr *gw;
|
||||
|
||||
gw = malloc(sizeof(*gw));
|
||||
if (!gw) {
|
||||
SYSERROR("failed to allocate ipv6 gateway address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!inet_pton(AF_INET6, value, gw)) {
|
||||
SYSERROR("invalid ipv6 gateway address: %s", value);
|
||||
free(gw);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -877,6 +897,8 @@ static int config_hook(const char *key, const char *value,
|
||||
return add_hook(lxc_conf, LXCHOOK_START, copy);
|
||||
else if (strcmp(key, "lxc.hook.post-stop") == 0)
|
||||
return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
|
||||
else if (strcmp(key, "lxc.hook.clone") == 0)
|
||||
return add_hook(lxc_conf, LXCHOOK_CLONE, copy);
|
||||
SYSERROR("Unknown key: %s", key);
|
||||
free(copy);
|
||||
return -1;
|
||||
@ -970,6 +992,11 @@ static int config_aa_profile(const char *key, const char *value,
|
||||
static int config_logfile(const char *key, const char *value,
|
||||
struct lxc_conf *lxc_conf)
|
||||
{
|
||||
// store these values in the lxc_conf, and then try to set for
|
||||
// actual current logging.
|
||||
if (lxc_conf->logfile)
|
||||
free(lxc_conf->logfile);
|
||||
lxc_conf->logfile = strdup(value);
|
||||
return lxc_log_set_file(value);
|
||||
}
|
||||
|
||||
@ -989,6 +1016,9 @@ static int config_loglevel(const char *key, const char *value,
|
||||
newlevel = atoi(value);
|
||||
else
|
||||
newlevel = lxc_log_priority_to_int(value);
|
||||
// store these values in the lxc_conf, and then try to set for
|
||||
// actual current logging.
|
||||
lxc_conf->loglevel = newlevel;
|
||||
return lxc_log_set_level(newlevel);
|
||||
}
|
||||
|
||||
@ -1233,8 +1263,10 @@ static int config_mount(const char *key, const char *value,
|
||||
return -1;
|
||||
|
||||
mntelem = strdup(value);
|
||||
if (!mntelem)
|
||||
if (!mntelem) {
|
||||
free(mntlist);
|
||||
return -1;
|
||||
}
|
||||
mntlist->elem = mntelem;
|
||||
|
||||
lxc_list_add_tail(&lxc_conf->mount_list, mntlist);
|
||||
@ -1242,6 +1274,52 @@ static int config_mount(const char *key, const char *value,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int config_cap_keep(const char *key, const char *value,
|
||||
struct lxc_conf *lxc_conf)
|
||||
{
|
||||
char *keepcaps, *keepptr, *sptr, *token;
|
||||
struct lxc_list *keeplist;
|
||||
int ret = -1;
|
||||
|
||||
if (!strlen(value))
|
||||
return -1;
|
||||
|
||||
keepcaps = strdup(value);
|
||||
if (!keepcaps) {
|
||||
SYSERROR("failed to dup '%s'", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* in case several capability keep is specified in a single line
|
||||
* split these caps in a single element for the list */
|
||||
for (keepptr = keepcaps;;keepptr = NULL) {
|
||||
token = strtok_r(keepptr, " \t", &sptr);
|
||||
if (!token) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
keeplist = malloc(sizeof(*keeplist));
|
||||
if (!keeplist) {
|
||||
SYSERROR("failed to allocate keepcap list");
|
||||
break;
|
||||
}
|
||||
|
||||
keeplist->elem = strdup(token);
|
||||
if (!keeplist->elem) {
|
||||
SYSERROR("failed to dup '%s'", token);
|
||||
free(keeplist);
|
||||
break;
|
||||
}
|
||||
|
||||
lxc_list_add_tail(&lxc_conf->keepcaps, keeplist);
|
||||
}
|
||||
|
||||
free(keepcaps);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int config_cap_drop(const char *key, const char *value,
|
||||
struct lxc_conf *lxc_conf)
|
||||
{
|
||||
@ -1344,6 +1422,7 @@ static int config_utsname(const char *key, const char *value,
|
||||
if (strlen(value) >= sizeof(utsname->nodename)) {
|
||||
ERROR("node name '%s' is too long",
|
||||
utsname->nodename);
|
||||
free(utsname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1607,6 +1686,22 @@ static int lxc_get_item_cap_drop(struct lxc_conf *c, char *retv, int inlen)
|
||||
return fulllen;
|
||||
}
|
||||
|
||||
static int lxc_get_item_cap_keep(struct lxc_conf *c, char *retv, int inlen)
|
||||
{
|
||||
int len, fulllen = 0;
|
||||
struct lxc_list *it;
|
||||
|
||||
if (!retv)
|
||||
inlen = 0;
|
||||
else
|
||||
memset(retv, 0, inlen);
|
||||
|
||||
lxc_list_for_each(it, &c->keepcaps) {
|
||||
strprint(retv, inlen, "%s\n", (char *)it->elem);
|
||||
}
|
||||
return fulllen;
|
||||
}
|
||||
|
||||
static int lxc_get_mount_entries(struct lxc_conf *c, char *retv, int inlen)
|
||||
{
|
||||
int len, fulllen = 0;
|
||||
@ -1682,8 +1777,12 @@ static int lxc_get_item_nic(struct lxc_conf *c, char *retv, int inlen,
|
||||
strprint(retv, inlen, "%s", mode);
|
||||
}
|
||||
} else if (strcmp(p1, "veth.pair") == 0) {
|
||||
if (netdev->type == LXC_NET_VETH && netdev->priv.veth_attr.pair)
|
||||
strprint(retv, inlen, "%s", netdev->priv.veth_attr.pair);
|
||||
if (netdev->type == LXC_NET_VETH) {
|
||||
strprint(retv, inlen, "%s",
|
||||
netdev->priv.veth_attr.pair ?
|
||||
netdev->priv.veth_attr.pair :
|
||||
netdev->priv.veth_attr.veth1);
|
||||
}
|
||||
} else if (strcmp(p1, "vlan") == 0) {
|
||||
if (netdev->type == LXC_NET_VLAN) {
|
||||
strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
|
||||
@ -1783,6 +1882,8 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
|
||||
v = c->rootfs.pivot;
|
||||
else if (strcmp(key, "lxc.cap.drop") == 0)
|
||||
return lxc_get_item_cap_drop(c, retv, inlen);
|
||||
else if (strcmp(key, "lxc.cap.keep") == 0)
|
||||
return lxc_get_item_cap_keep(c, retv, inlen);
|
||||
else if (strncmp(key, "lxc.hook", 8) == 0)
|
||||
return lxc_get_item_hooks(c, retv, inlen, key);
|
||||
else if (strcmp(key, "lxc.network") == 0)
|
||||
@ -1806,6 +1907,8 @@ int lxc_clear_config_item(struct lxc_conf *c, const char *key)
|
||||
return lxc_clear_nic(c, key + 12);
|
||||
else if (strcmp(key, "lxc.cap.drop") == 0)
|
||||
return lxc_clear_config_caps(c);
|
||||
else if (strcmp(key, "lxc.cap.keep") == 0)
|
||||
return lxc_clear_config_keepcaps(c);
|
||||
else if (strncmp(key, "lxc.cgroup", 10) == 0)
|
||||
return lxc_clear_cgroups(c, key);
|
||||
else if (strcmp(key, "lxc.mount.entries") == 0)
|
||||
@ -1846,10 +1949,10 @@ void write_config(FILE *fout, struct lxc_conf *c)
|
||||
if (c->aa_profile)
|
||||
fprintf(fout, "lxc.aa_profile = %s\n", c->aa_profile);
|
||||
#endif
|
||||
if (lxc_log_get_level() != LXC_LOG_PRIORITY_NOTSET)
|
||||
fprintf(fout, "lxc.loglevel = %s\n", lxc_log_priority_to_string(lxc_log_get_level()));
|
||||
if (lxc_log_get_file())
|
||||
fprintf(fout, "lxc.logfile = %s\n", lxc_log_get_file());
|
||||
if (c->loglevel != LXC_LOG_PRIORITY_NOTSET)
|
||||
fprintf(fout, "lxc.loglevel = %s\n", lxc_log_priority_to_string(c->loglevel));
|
||||
if (c->logfile)
|
||||
fprintf(fout, "lxc.logfile = %s\n", c->logfile);
|
||||
lxc_list_for_each(it, &c->cgroup) {
|
||||
struct lxc_cgroup *cg = it->elem;
|
||||
fprintf(fout, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value);
|
||||
@ -1918,6 +2021,14 @@ void write_config(FILE *fout, struct lxc_conf *c)
|
||||
}
|
||||
lxc_list_for_each(it, &c->caps)
|
||||
fprintf(fout, "lxc.cap.drop = %s\n", (char *)it->elem);
|
||||
lxc_list_for_each(it, &c->keepcaps)
|
||||
fprintf(fout, "lxc.cap.keep = %s\n", (char *)it->elem);
|
||||
lxc_list_for_each(it, &c->id_map) {
|
||||
struct id_map *idmap = it->elem;
|
||||
fprintf(fout, "lxc.id_map = %c %lu %lu %lu\n",
|
||||
idmap->idtype == ID_TYPE_UID ? 'u' : 'g', idmap->nsid,
|
||||
idmap->hostid, idmap->range);
|
||||
}
|
||||
for (i=0; i<NUM_LXC_HOOKS; i++) {
|
||||
lxc_list_for_each(it, &c->hooks[i])
|
||||
fprintf(fout, "lxc.hook.%s = %s\n",
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -18,9 +18,11 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@ -29,6 +31,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "lxccontainer.h"
|
||||
#include "log.h"
|
||||
#include "conf.h"
|
||||
#include "config.h"
|
||||
@ -37,6 +40,8 @@
|
||||
#include "commands.h"
|
||||
#include "mainloop.h"
|
||||
#include "af_unix.h"
|
||||
#include "lxclock.h"
|
||||
#include "utils.h"
|
||||
|
||||
#if HAVE_PTY_H
|
||||
#include <pty.h>
|
||||
@ -46,240 +51,495 @@
|
||||
|
||||
lxc_log_define(lxc_console, lxc);
|
||||
|
||||
extern int lxc_console(const char *name, int ttynum, int *fd, const char *lxcpath)
|
||||
static struct lxc_list lxc_ttys;
|
||||
|
||||
typedef void (*sighandler_t)(int);
|
||||
struct lxc_tty_state
|
||||
{
|
||||
int ret, stopped = 0;
|
||||
struct lxc_command command = {
|
||||
.request = { .type = LXC_COMMAND_TTY, .data = ttynum },
|
||||
};
|
||||
struct lxc_list node;
|
||||
int stdinfd;
|
||||
int stdoutfd;
|
||||
int masterfd;
|
||||
int escape;
|
||||
int saw_escape;
|
||||
const char *winch_proxy;
|
||||
const char *winch_proxy_lxcpath;
|
||||
int sigfd;
|
||||
sigset_t oldmask;
|
||||
};
|
||||
|
||||
ret = lxc_command_connected(name, &command, &stopped, lxcpath);
|
||||
if (ret < 0 && stopped) {
|
||||
ERROR("'%s' is stopped", name);
|
||||
__attribute__((constructor))
|
||||
void lxc_console_init(void)
|
||||
{
|
||||
lxc_list_init(&lxc_ttys);
|
||||
}
|
||||
|
||||
/* lxc_console_winsz: propagte winsz from one terminal to another
|
||||
*
|
||||
* @srcfd : terminal to get size from (typically a slave pty)
|
||||
* @dstfd : terminal to set size on (typically a master pty)
|
||||
*/
|
||||
static void lxc_console_winsz(int srcfd, int dstfd)
|
||||
{
|
||||
struct winsize wsz;
|
||||
if (isatty(srcfd) && ioctl(srcfd, TIOCGWINSZ, &wsz) == 0) {
|
||||
DEBUG("set winsz dstfd:%d cols:%d rows:%d", dstfd,
|
||||
wsz.ws_col, wsz.ws_row);
|
||||
ioctl(dstfd, TIOCSWINSZ, &wsz);
|
||||
}
|
||||
}
|
||||
|
||||
static void lxc_console_winch(struct lxc_tty_state *ts)
|
||||
{
|
||||
lxc_console_winsz(ts->stdinfd, ts->masterfd);
|
||||
if (ts->winch_proxy) {
|
||||
lxc_cmd_console_winch(ts->winch_proxy,
|
||||
ts->winch_proxy_lxcpath);
|
||||
}
|
||||
}
|
||||
|
||||
void lxc_console_sigwinch(int sig)
|
||||
{
|
||||
if (process_lock() == 0) {
|
||||
struct lxc_list *it;
|
||||
struct lxc_tty_state *ts;
|
||||
|
||||
lxc_list_for_each(it, &lxc_ttys) {
|
||||
ts = it->elem;
|
||||
lxc_console_winch(ts);
|
||||
}
|
||||
process_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
static int lxc_console_cb_sigwinch_fd(int fd, void *cbdata,
|
||||
struct lxc_epoll_descr *descr)
|
||||
{
|
||||
struct signalfd_siginfo siginfo;
|
||||
struct lxc_tty_state *ts = cbdata;
|
||||
|
||||
if (read(fd, &siginfo, sizeof(siginfo)) < 0) {
|
||||
ERROR("failed to read signal info");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
ERROR("failed to send command");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
ERROR("console denied by '%s'", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (command.answer.ret) {
|
||||
ERROR("console access denied: %s",
|
||||
strerror(-command.answer.ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
*fd = command.answer.fd;
|
||||
if (*fd <0) {
|
||||
ERROR("unable to allocate fd for tty %d", ttynum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
INFO("tty %d allocated", ttynum);
|
||||
lxc_console_winch(ts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* functions used by lxc-start mainloop
|
||||
* to handle above command request.
|
||||
*--------------------------------------------------------------------------*/
|
||||
extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info)
|
||||
/*
|
||||
* lxc_console_sigwinch_init: install SIGWINCH handler
|
||||
*
|
||||
* @srcfd : src for winsz in SIGWINCH handler
|
||||
* @dstfd : dst for winsz in SIGWINCH handler
|
||||
*
|
||||
* Returns lxc_tty_state structure on success or NULL on failure. The sigfd
|
||||
* member of the returned lxc_tty_state can be select()/poll()ed/epoll()ed
|
||||
* on (ie added to a mainloop) for SIGWINCH.
|
||||
*
|
||||
* Must be called with process_lock held to protect the lxc_ttys list, or
|
||||
* from a non-threaded context.
|
||||
*
|
||||
* Note that SIGWINCH isn't installed as a classic asychronous handler,
|
||||
* rather signalfd(2) is used so that we can handle the signal when we're
|
||||
* ready for it. This avoids deadlocks since a signal handler
|
||||
* (ie lxc_console_sigwinch()) would need to take the thread mutex to
|
||||
* prevent lxc_ttys list corruption, but using the fd we can provide the
|
||||
* tty_state needed to the callback (lxc_console_cb_sigwinch_fd()).
|
||||
*/
|
||||
static struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
|
||||
{
|
||||
int i;
|
||||
sigset_t mask;
|
||||
struct lxc_tty_state *ts;
|
||||
|
||||
for (i = 0; i < tty_info->nbtty; i++) {
|
||||
ts = malloc(sizeof(*ts));
|
||||
if (!ts)
|
||||
return NULL;
|
||||
|
||||
if (tty_info->pty_info[i].busy != fd)
|
||||
continue;
|
||||
memset(ts, 0, sizeof(*ts));
|
||||
ts->stdinfd = srcfd;
|
||||
ts->masterfd = dstfd;
|
||||
ts->sigfd = -1;
|
||||
|
||||
tty_info->pty_info[i].busy = 0;
|
||||
/* add tty to list to be scanned at SIGWINCH time */
|
||||
lxc_list_add_elem(&ts->node, ts);
|
||||
lxc_list_add_tail(&lxc_ttys, &ts->node);
|
||||
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGWINCH);
|
||||
if (sigprocmask(SIG_BLOCK, &mask, &ts->oldmask)) {
|
||||
SYSERROR("failed to block SIGWINCH");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
return;
|
||||
ts->sigfd = signalfd(-1, &mask, 0);
|
||||
if (ts->sigfd < 0) {
|
||||
SYSERROR("failed to get signalfd");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
DEBUG("%d got SIGWINCH fd %d", getpid(), ts->sigfd);
|
||||
goto out;
|
||||
|
||||
err2:
|
||||
sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
|
||||
err1:
|
||||
lxc_list_del(&ts->node);
|
||||
free(ts);
|
||||
ts = NULL;
|
||||
out:
|
||||
return ts;
|
||||
}
|
||||
|
||||
extern int lxc_console_callback(int fd, struct lxc_request *request,
|
||||
struct lxc_handler *handler)
|
||||
/*
|
||||
* lxc_console_sigwinch_fini: uninstall SIGWINCH handler
|
||||
*
|
||||
* @ts : the lxc_tty_state returned by lxc_console_sigwinch_init
|
||||
*
|
||||
* Restore the saved signal handler that was in effect at the time
|
||||
* lxc_console_sigwinch_init() was called.
|
||||
*
|
||||
* Must be called with process_lock held to protect the lxc_ttys list, or
|
||||
* from a non-threaded context.
|
||||
*/
|
||||
static void lxc_console_sigwinch_fini(struct lxc_tty_state *ts)
|
||||
{
|
||||
int ttynum = request->data;
|
||||
struct lxc_tty_info *tty_info = &handler->conf->tty_info;
|
||||
if (ts->sigfd >= 0)
|
||||
close(ts->sigfd);
|
||||
lxc_list_del(&ts->node);
|
||||
sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
|
||||
free(ts);
|
||||
}
|
||||
|
||||
if (ttynum > 0) {
|
||||
if (ttynum > tty_info->nbtty)
|
||||
goto out_close;
|
||||
static int lxc_console_cb_con(int fd, void *data,
|
||||
struct lxc_epoll_descr *descr)
|
||||
{
|
||||
struct lxc_console *console = (struct lxc_console *)data;
|
||||
char buf[1024];
|
||||
int r,w;
|
||||
|
||||
if (tty_info->pty_info[ttynum - 1].busy)
|
||||
goto out_close;
|
||||
|
||||
goto out_send;
|
||||
w = r = read(fd, buf, sizeof(buf));
|
||||
if (r < 0) {
|
||||
SYSERROR("failed to read");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* fixup index tty1 => [0] */
|
||||
if (!r) {
|
||||
INFO("console client on fd %d has exited", fd);
|
||||
lxc_mainloop_del_handler(descr, fd);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fd == console->peer)
|
||||
w = write(console->master, buf, r);
|
||||
|
||||
if (fd == console->master) {
|
||||
if (console->log_fd >= 0)
|
||||
w = write(console->log_fd, buf, r);
|
||||
|
||||
if (console->peer >= 0)
|
||||
w = write(console->peer, buf, r);
|
||||
}
|
||||
|
||||
if (w != r)
|
||||
WARN("console short write r:%d w:%d", r, w);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lxc_console_mainloop_add_peer(struct lxc_console *console)
|
||||
{
|
||||
if (console->peer >= 0) {
|
||||
if (lxc_mainloop_add_handler(console->descr, console->peer,
|
||||
lxc_console_cb_con, console))
|
||||
WARN("console peer not added to mainloop");
|
||||
}
|
||||
|
||||
if (console->tty_state) {
|
||||
if (lxc_mainloop_add_handler(console->descr,
|
||||
console->tty_state->sigfd,
|
||||
lxc_console_cb_sigwinch_fd,
|
||||
console->tty_state)) {
|
||||
WARN("failed to add to mainloop SIGWINCH handler for '%d'",
|
||||
console->tty_state->sigfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
struct lxc_conf *conf = handler->conf;
|
||||
struct lxc_console *console = &conf->console;
|
||||
|
||||
if (conf->is_execute) {
|
||||
INFO("no console for lxc-execute.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!conf->rootfs.path) {
|
||||
INFO("no rootfs, no console.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (console->master < 0) {
|
||||
INFO("no console");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lxc_mainloop_add_handler(descr, console->master,
|
||||
lxc_console_cb_con, console)) {
|
||||
ERROR("failed to add to mainloop console handler for '%d'",
|
||||
console->master);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we cache the descr so that we can add an fd to it when someone
|
||||
* does attach to it in lxc_console_allocate()
|
||||
*/
|
||||
console->descr = descr;
|
||||
lxc_console_mainloop_add_peer(console);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_tios(int fd, struct termios *oldtios)
|
||||
{
|
||||
struct termios newtios;
|
||||
|
||||
if (!isatty(fd)) {
|
||||
ERROR("'%d' is not a tty", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get current termios */
|
||||
if (tcgetattr(fd, oldtios)) {
|
||||
SYSERROR("failed to get current terminal settings");
|
||||
return -1;
|
||||
}
|
||||
|
||||
newtios = *oldtios;
|
||||
|
||||
/* Remove the echo characters and signal reception, the echo
|
||||
* will be done with master proxying */
|
||||
newtios.c_iflag &= ~IGNBRK;
|
||||
newtios.c_iflag &= BRKINT;
|
||||
newtios.c_lflag &= ~(ECHO|ICANON|ISIG);
|
||||
newtios.c_cc[VMIN] = 1;
|
||||
newtios.c_cc[VTIME] = 0;
|
||||
|
||||
/* Set new attributes */
|
||||
if (tcsetattr(fd, TCSAFLUSH, &newtios)) {
|
||||
ERROR("failed to set new terminal settings");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lxc_console_peer_proxy_free(struct lxc_console *console)
|
||||
{
|
||||
if (console->tty_state) {
|
||||
lxc_console_sigwinch_fini(console->tty_state);
|
||||
console->tty_state = NULL;
|
||||
}
|
||||
close(console->peerpty.master);
|
||||
close(console->peerpty.slave);
|
||||
console->peerpty.master = -1;
|
||||
console->peerpty.slave = -1;
|
||||
console->peerpty.busy = -1;
|
||||
console->peerpty.name[0] = '\0';
|
||||
console->peer = -1;
|
||||
}
|
||||
|
||||
static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd)
|
||||
{
|
||||
struct termios oldtermio;
|
||||
struct lxc_tty_state *ts;
|
||||
|
||||
if (console->master < 0) {
|
||||
ERROR("console not set up");
|
||||
return -1;
|
||||
}
|
||||
if (console->peerpty.busy != -1 || console->peer != -1) {
|
||||
NOTICE("console already in use");
|
||||
return -1;
|
||||
}
|
||||
if (console->tty_state) {
|
||||
ERROR("console already has tty_state");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* this is the proxy pty that will be given to the client, and that
|
||||
* the real pty master will send to / recv from
|
||||
*/
|
||||
if (openpty(&console->peerpty.master, &console->peerpty.slave,
|
||||
console->peerpty.name, NULL, NULL)) {
|
||||
SYSERROR("failed to create proxy pty");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setup_tios(console->peerpty.slave, &oldtermio) < 0)
|
||||
goto err1;
|
||||
|
||||
ts = lxc_console_sigwinch_init(console->peerpty.master, console->master);
|
||||
if (!ts)
|
||||
goto err1;
|
||||
|
||||
console->tty_state = ts;
|
||||
console->peer = console->peerpty.slave;
|
||||
console->peerpty.busy = sockfd;
|
||||
lxc_console_mainloop_add_peer(console);
|
||||
|
||||
DEBUG("%d %s peermaster:%d sockfd:%d", getpid(), __FUNCTION__, console->peerpty.master, sockfd);
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
lxc_console_peer_proxy_free(console);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* lxc_console_allocate: allocate the console or a tty
|
||||
*
|
||||
* @conf : the configuration of the container to allocate from
|
||||
* @sockfd : the socket fd whose remote side when closed, will be an
|
||||
* indication that the console or tty is no longer in use
|
||||
* @ttyreq : the tty requested to be opened, -1 for any, 0 for the console
|
||||
*/
|
||||
int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
|
||||
{
|
||||
int masterfd = -1, ttynum;
|
||||
struct lxc_tty_info *tty_info = &conf->tty_info;
|
||||
struct lxc_console *console = &conf->console;
|
||||
|
||||
process_lock();
|
||||
if (*ttyreq == 0) {
|
||||
if (lxc_console_peer_proxy_alloc(console, sockfd) < 0)
|
||||
goto out;
|
||||
masterfd = console->peerpty.master;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*ttyreq > 0) {
|
||||
if (*ttyreq > tty_info->nbtty)
|
||||
goto out;
|
||||
|
||||
if (tty_info->pty_info[*ttyreq - 1].busy)
|
||||
goto out;
|
||||
|
||||
/* the requested tty is available */
|
||||
ttynum = *ttyreq;
|
||||
goto out_tty;
|
||||
}
|
||||
|
||||
/* search for next available tty, fixup index tty1 => [0] */
|
||||
for (ttynum = 1;
|
||||
ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
|
||||
ttynum++);
|
||||
|
||||
/* we didn't find any available slot for tty */
|
||||
if (ttynum > tty_info->nbtty)
|
||||
goto out_close;
|
||||
goto out;
|
||||
|
||||
out_send:
|
||||
if (lxc_af_unix_send_fd(fd, tty_info->pty_info[ttynum - 1].master,
|
||||
&ttynum, sizeof(ttynum)) < 0) {
|
||||
ERROR("failed to send tty to client");
|
||||
goto out_close;
|
||||
}
|
||||
*ttyreq = ttynum;
|
||||
|
||||
tty_info->pty_info[ttynum - 1].busy = fd;
|
||||
|
||||
return 0;
|
||||
|
||||
out_close:
|
||||
/* the close fd and related cleanup will be done by caller */
|
||||
return 1;
|
||||
out_tty:
|
||||
tty_info->pty_info[ttynum - 1].busy = sockfd;
|
||||
masterfd = tty_info->pty_info[ttynum - 1].master;
|
||||
out:
|
||||
process_unlock();
|
||||
return masterfd;
|
||||
}
|
||||
|
||||
static int get_default_console(char **console)
|
||||
/* lxc_console_free: mark the console or a tty as unallocated, free any
|
||||
* resources allocated by lxc_console_allocate().
|
||||
*
|
||||
* @conf : the configuration of the container whose tty was closed
|
||||
* @fd : the socket fd whose remote side was closed, which indicated
|
||||
* the console or tty is no longer in use. this is used to match
|
||||
* which console/tty is being freed.
|
||||
*/
|
||||
void lxc_console_free(struct lxc_conf *conf, int fd)
|
||||
{
|
||||
int fd;
|
||||
int i;
|
||||
struct lxc_tty_info *tty_info = &conf->tty_info;
|
||||
struct lxc_console *console = &conf->console;
|
||||
|
||||
if (!access("/dev/tty", F_OK)) {
|
||||
process_lock();
|
||||
for (i = 0; i < tty_info->nbtty; i++) {
|
||||
if (tty_info->pty_info[i].busy == fd)
|
||||
tty_info->pty_info[i].busy = 0;
|
||||
}
|
||||
|
||||
if (console->peerpty.busy == fd) {
|
||||
lxc_mainloop_del_handler(console->descr, console->peerpty.slave);
|
||||
lxc_console_peer_proxy_free(console);
|
||||
}
|
||||
process_unlock();
|
||||
}
|
||||
|
||||
static void lxc_console_peer_default(struct lxc_console *console)
|
||||
{
|
||||
struct lxc_tty_state *ts;
|
||||
const char *path = console->path;
|
||||
|
||||
/* if no console was given, try current controlling terminal, there
|
||||
* won't be one if we were started as a daemon (-d)
|
||||
*/
|
||||
if (!path && !access("/dev/tty", F_OK)) {
|
||||
int fd;
|
||||
fd = open("/dev/tty", O_RDWR);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
*console = strdup("/dev/tty");
|
||||
goto out;
|
||||
path = "/dev/tty";
|
||||
}
|
||||
}
|
||||
|
||||
if (!access("/dev/null", F_OK)) {
|
||||
*console = strdup("/dev/null");
|
||||
if (!path)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ERROR("No suitable default console");
|
||||
out:
|
||||
return *console ? 0 : -1;
|
||||
}
|
||||
DEBUG("opening %s for console peer", path);
|
||||
console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT |
|
||||
O_APPEND, 0600));
|
||||
if (console->peer < 0)
|
||||
goto out;
|
||||
|
||||
int lxc_create_console(struct lxc_conf *conf)
|
||||
{
|
||||
struct termios tios;
|
||||
struct lxc_console *console = &conf->console;
|
||||
int fd;
|
||||
|
||||
if (!conf->rootfs.path)
|
||||
return 0;
|
||||
|
||||
if (!console->path && get_default_console(&console->path)) {
|
||||
ERROR("failed to get default console");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!strcmp(console->path, "none"))
|
||||
return 0;
|
||||
|
||||
if (openpty(&console->master, &console->slave,
|
||||
console->name, NULL, NULL)) {
|
||||
SYSERROR("failed to allocate a pty");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
|
||||
SYSERROR("failed to set console master to close-on-exec");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
|
||||
SYSERROR("failed to set console slave to close-on-exec");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (console->log_path) {
|
||||
fd = lxc_unpriv(open(console->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
|
||||
if (fd < 0) {
|
||||
SYSERROR("failed to open '%s'", console->log_path);
|
||||
goto err;
|
||||
}
|
||||
DEBUG("using '%s' as console log", console->log_path);
|
||||
console->log_fd = fd;
|
||||
}
|
||||
|
||||
fd = lxc_unpriv(open(console->path, O_CLOEXEC | O_RDWR | O_CREAT |
|
||||
O_APPEND, 0600));
|
||||
if (fd < 0) {
|
||||
SYSERROR("failed to open '%s'", console->path);
|
||||
goto err_close_console_log;
|
||||
}
|
||||
|
||||
DEBUG("using '%s' as console", console->path);
|
||||
|
||||
console->peer = fd;
|
||||
DEBUG("using '%s' as console", path);
|
||||
|
||||
if (!isatty(console->peer))
|
||||
return 0;
|
||||
return;
|
||||
|
||||
console->tios = malloc(sizeof(tios));
|
||||
ts = lxc_console_sigwinch_init(console->peer, console->master);
|
||||
if (!ts)
|
||||
WARN("Unable to install SIGWINCH");
|
||||
console->tty_state = ts;
|
||||
|
||||
lxc_console_winsz(console->peer, console->master);
|
||||
|
||||
console->tios = malloc(sizeof(*console->tios));
|
||||
if (!console->tios) {
|
||||
SYSERROR("failed to allocate memory");
|
||||
goto err_close_console;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* Get termios */
|
||||
if (tcgetattr(console->peer, console->tios)) {
|
||||
SYSERROR("failed to get current terminal settings");
|
||||
goto err_free;
|
||||
}
|
||||
if (setup_tios(console->peer, console->tios) < 0)
|
||||
goto err2;
|
||||
|
||||
tios = *console->tios;
|
||||
return;
|
||||
|
||||
/* Remove the echo characters and signal reception, the echo
|
||||
* will be done below with master proxying */
|
||||
tios.c_iflag &= ~IGNBRK;
|
||||
tios.c_iflag &= BRKINT;
|
||||
tios.c_lflag &= ~(ECHO|ICANON|ISIG);
|
||||
tios.c_cc[VMIN] = 1;
|
||||
tios.c_cc[VTIME] = 0;
|
||||
|
||||
/* Set new attributes */
|
||||
if (tcsetattr(console->peer, TCSAFLUSH, &tios)) {
|
||||
ERROR("failed to set new terminal settings");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
err2:
|
||||
free(console->tios);
|
||||
|
||||
err_close_console:
|
||||
console->tios = NULL;
|
||||
err1:
|
||||
close(console->peer);
|
||||
console->peer = -1;
|
||||
|
||||
err_close_console_log:
|
||||
if (console->log_fd >= 0) {
|
||||
close(console->log_fd);
|
||||
console->log_fd = -1;
|
||||
}
|
||||
|
||||
err:
|
||||
close(console->master);
|
||||
console->master = -1;
|
||||
|
||||
close(console->slave);
|
||||
console->slave = -1;
|
||||
return -1;
|
||||
out:
|
||||
DEBUG("no console peer");
|
||||
}
|
||||
|
||||
void lxc_delete_console(struct lxc_console *console)
|
||||
void lxc_console_delete(struct lxc_console *console)
|
||||
{
|
||||
if (console->tios &&
|
||||
if (console->tios && console->peer >= 0 &&
|
||||
tcsetattr(console->peer, TCSAFLUSH, console->tios))
|
||||
WARN("failed to set old terminal settings");
|
||||
free(console->tios);
|
||||
@ -300,73 +560,213 @@ void lxc_delete_console(struct lxc_console *console)
|
||||
console->slave = -1;
|
||||
}
|
||||
|
||||
static int console_handler(int fd, void *data, struct lxc_epoll_descr *descr)
|
||||
int lxc_console_create(struct lxc_conf *conf)
|
||||
{
|
||||
struct lxc_console *console = (struct lxc_console *)data;
|
||||
struct lxc_console *console = &conf->console;
|
||||
|
||||
if (conf->is_execute) {
|
||||
INFO("no console for lxc-execute.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!conf->rootfs.path)
|
||||
return 0;
|
||||
|
||||
if (console->path && !strcmp(console->path, "none"))
|
||||
return 0;
|
||||
|
||||
if (openpty(&console->master, &console->slave,
|
||||
console->name, NULL, NULL)) {
|
||||
SYSERROR("failed to allocate a pty");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
|
||||
SYSERROR("failed to set console master to close-on-exec");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
|
||||
SYSERROR("failed to set console slave to close-on-exec");
|
||||
goto err;
|
||||
}
|
||||
|
||||
lxc_console_peer_default(console);
|
||||
|
||||
if (console->log_path) {
|
||||
console->log_fd = lxc_unpriv(open(console->log_path,
|
||||
O_CLOEXEC | O_RDWR |
|
||||
O_CREAT | O_APPEND, 0600));
|
||||
if (console->log_fd < 0) {
|
||||
SYSERROR("failed to open '%s'", console->log_path);
|
||||
goto err;
|
||||
}
|
||||
DEBUG("using '%s' as console log", console->log_path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
lxc_console_delete(console);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int lxc_console_cb_tty_stdin(int fd, void *cbdata,
|
||||
struct lxc_epoll_descr *descr)
|
||||
{
|
||||
struct lxc_tty_state *ts = cbdata;
|
||||
char c;
|
||||
|
||||
assert(fd == ts->stdinfd);
|
||||
if (read(ts->stdinfd, &c, 1) < 0) {
|
||||
SYSERROR("failed to read");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* we want to exit the console with Ctrl+a q */
|
||||
if (c == ts->escape && !ts->saw_escape) {
|
||||
ts->saw_escape = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c == 'q' && ts->saw_escape)
|
||||
return 1;
|
||||
|
||||
ts->saw_escape = 0;
|
||||
if (write(ts->masterfd, &c, 1) < 0) {
|
||||
SYSERROR("failed to write");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lxc_console_cb_tty_master(int fd, void *cbdata,
|
||||
struct lxc_epoll_descr *descr)
|
||||
{
|
||||
struct lxc_tty_state *ts = cbdata;
|
||||
char buf[1024];
|
||||
int r,w;
|
||||
|
||||
assert(fd == ts->masterfd);
|
||||
r = read(fd, buf, sizeof(buf));
|
||||
if (r < 0) {
|
||||
SYSERROR("failed to read");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!r) {
|
||||
INFO("console client has exited");
|
||||
lxc_mainloop_del_handler(descr, fd);
|
||||
close(fd);
|
||||
return 0;
|
||||
w = write(ts->stdoutfd, buf, r);
|
||||
if (w < 0 || w != r) {
|
||||
SYSERROR("failed to write");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* no output for the console, do nothing */
|
||||
if (console->peer == -1)
|
||||
return 0;
|
||||
|
||||
if (console->peer == fd)
|
||||
w = write(console->master, buf, r);
|
||||
else {
|
||||
w = write(console->peer, buf, r);
|
||||
if (console->log_fd > 0)
|
||||
w = write(console->log_fd, buf, r);
|
||||
}
|
||||
if (w != r)
|
||||
WARN("console short write");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
|
||||
struct lxc_handler *handler)
|
||||
int lxc_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
|
||||
{
|
||||
struct lxc_conf *conf = handler->conf;
|
||||
struct lxc_console *console = &conf->console;
|
||||
return lxc_cmd_console(c->name, ttynum, masterfd, c->config_path);
|
||||
}
|
||||
|
||||
if (!conf->rootfs.path) {
|
||||
INFO("no rootfs, no console.");
|
||||
return 0;
|
||||
}
|
||||
int lxc_console(struct lxc_container *c, int ttynum,
|
||||
int stdinfd, int stdoutfd, int stderrfd,
|
||||
int escape)
|
||||
{
|
||||
int ret, ttyfd, masterfd;
|
||||
struct lxc_epoll_descr descr;
|
||||
struct termios oldtios;
|
||||
struct lxc_tty_state *ts;
|
||||
|
||||
if (!console->path) {
|
||||
INFO("no console specified");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (console->peer == -1) {
|
||||
INFO("no console will be used");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lxc_mainloop_add_handler(descr, console->master,
|
||||
console_handler, console)) {
|
||||
ERROR("failed to add to mainloop console handler for '%d'",
|
||||
console->master);
|
||||
if (!isatty(stdinfd)) {
|
||||
ERROR("stdin is not a tty");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (console->peer != -1 &&
|
||||
lxc_mainloop_add_handler(descr, console->peer,
|
||||
console_handler, console))
|
||||
WARN("console input disabled");
|
||||
ret = setup_tios(stdinfd, &oldtios);
|
||||
if (ret) {
|
||||
ERROR("failed to setup tios");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
process_lock();
|
||||
ttyfd = lxc_cmd_console(c->name, &ttynum, &masterfd, c->config_path);
|
||||
if (ttyfd < 0) {
|
||||
ret = ttyfd;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n"
|
||||
"Connected to tty %1$d\n"
|
||||
"Type <Ctrl+%2$c q> to exit the console, "
|
||||
"<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n",
|
||||
ttynum, 'a' + escape - 1);
|
||||
|
||||
ret = setsid();
|
||||
if (ret)
|
||||
INFO("already group leader");
|
||||
|
||||
ts = lxc_console_sigwinch_init(stdinfd, masterfd);
|
||||
if (!ts) {
|
||||
ret = -1;
|
||||
goto err2;
|
||||
}
|
||||
ts->escape = escape;
|
||||
ts->winch_proxy = c->name;
|
||||
ts->winch_proxy_lxcpath = c->config_path;
|
||||
|
||||
lxc_console_winsz(stdinfd, masterfd);
|
||||
lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
|
||||
|
||||
ret = lxc_mainloop_open(&descr);
|
||||
if (ret) {
|
||||
ERROR("failed to create mainloop");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
|
||||
lxc_console_cb_sigwinch_fd, ts);
|
||||
if (ret) {
|
||||
ERROR("failed to add handler for SIGWINCH fd");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
|
||||
lxc_console_cb_tty_stdin, ts);
|
||||
if (ret) {
|
||||
ERROR("failed to add handler for stdinfd");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = lxc_mainloop_add_handler(&descr, ts->masterfd,
|
||||
lxc_console_cb_tty_master, ts);
|
||||
if (ret) {
|
||||
ERROR("failed to add handler for masterfd");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
process_unlock();
|
||||
ret = lxc_mainloop(&descr, -1);
|
||||
process_lock();
|
||||
if (ret) {
|
||||
ERROR("mainloop returned an error");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
err4:
|
||||
lxc_mainloop_close(&descr);
|
||||
err3:
|
||||
lxc_console_sigwinch_fini(ts);
|
||||
err2:
|
||||
close(masterfd);
|
||||
close(ttyfd);
|
||||
err1:
|
||||
tcsetattr(stdinfd, TCSAFLUSH, &oldtios);
|
||||
process_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -18,9 +18,21 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
extern int lxc_create_console(struct lxc_conf *);
|
||||
extern void lxc_delete_console(struct lxc_console *);
|
||||
extern int lxc_console_mainloop_add(struct lxc_epoll_descr *, struct lxc_handler *);
|
||||
struct lxc_epoll_descr;
|
||||
struct lxc_container;
|
||||
|
||||
extern int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttynum);
|
||||
extern int lxc_console_create(struct lxc_conf *);
|
||||
extern void lxc_console_delete(struct lxc_console *);
|
||||
extern void lxc_console_free(struct lxc_conf *conf, int fd);
|
||||
|
||||
extern int lxc_console_mainloop_add(struct lxc_epoll_descr *, struct lxc_handler *);
|
||||
extern void lxc_console_sigwinch(int sig);
|
||||
extern int lxc_console(struct lxc_container *c, int ttynum,
|
||||
int stdinfd, int stdoutfd, int stderrfd,
|
||||
int escape);
|
||||
extern int lxc_console_getfd(struct lxc_container *c, int *ttynum,
|
||||
int *masterfd);
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __lxc_error_h
|
||||
#define __lxc_error_h
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -27,6 +27,7 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "log.h"
|
||||
#include "start.h"
|
||||
|
||||
@ -54,7 +55,7 @@ static char *choose_init(void)
|
||||
ret = snprintf(retv, PATH_MAX, LXCINITDIR "/lxc/lxc-init");
|
||||
if (ret < 0 || ret >= PATH_MAX) {
|
||||
ERROR("pathname too long");
|
||||
return NULL;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
ret = stat(retv, &mystat);
|
||||
@ -64,7 +65,7 @@ static char *choose_init(void)
|
||||
ret = snprintf(retv, PATH_MAX, "/usr/lib/lxc/lxc-init");
|
||||
if (ret < 0 || ret >= PATH_MAX) {
|
||||
ERROR("pathname too long");
|
||||
return NULL;
|
||||
goto out1;
|
||||
}
|
||||
ret = stat(retv, &mystat);
|
||||
if (ret == 0)
|
||||
@ -72,11 +73,13 @@ static char *choose_init(void)
|
||||
ret = snprintf(retv, PATH_MAX, "/sbin/lxc-init");
|
||||
if (ret < 0 || ret >= PATH_MAX) {
|
||||
ERROR("pathname too long");
|
||||
return NULL;
|
||||
goto out1;
|
||||
}
|
||||
ret = stat(retv, &mystat);
|
||||
if (ret == 0)
|
||||
return retv;
|
||||
out1:
|
||||
free(retv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -85,23 +88,44 @@ static int execute_start(struct lxc_handler *handler, void* data)
|
||||
int j, i = 0;
|
||||
struct execute_args *my_args = data;
|
||||
char **argv;
|
||||
int argc = 0;
|
||||
int argc = 0, argc_add;
|
||||
char *initpath;
|
||||
|
||||
while (my_args->argv[argc++]);
|
||||
|
||||
argv = malloc((argc + my_args->quiet ? 5 : 4) * sizeof(*argv));
|
||||
argc_add = 4;
|
||||
if (my_args->quiet)
|
||||
argc_add++;
|
||||
if (!handler->conf->rootfs.path) {
|
||||
argc_add += 4;
|
||||
if (lxc_log_has_valid_level())
|
||||
argc_add += 2;
|
||||
}
|
||||
|
||||
argv = malloc((argc + argc_add) * sizeof(*argv));
|
||||
if (!argv)
|
||||
return 1;
|
||||
goto out1;
|
||||
|
||||
initpath = choose_init();
|
||||
if (!initpath) {
|
||||
ERROR("Failed to find an lxc-init");
|
||||
return 1;
|
||||
goto out2;
|
||||
}
|
||||
argv[i++] = initpath;
|
||||
if (my_args->quiet)
|
||||
argv[i++] = "--quiet";
|
||||
if (!handler->conf->rootfs.path) {
|
||||
argv[i++] = "--name";
|
||||
argv[i++] = (char *)handler->name;
|
||||
argv[i++] = "--lxcpath";
|
||||
argv[i++] = (char *)handler->lxcpath;
|
||||
|
||||
if (lxc_log_has_valid_level()) {
|
||||
argv[i++] = "--logpriority";
|
||||
argv[i++] = (char *)
|
||||
lxc_log_priority_to_string(lxc_log_get_level());
|
||||
}
|
||||
}
|
||||
argv[i++] = "--";
|
||||
for (j = 0; j < argc; j++)
|
||||
argv[i++] = my_args->argv[j];
|
||||
@ -111,6 +135,10 @@ static int execute_start(struct lxc_handler *handler, void* data)
|
||||
|
||||
execvp(argv[0], argv);
|
||||
SYSERROR("failed to exec %s", argv[0]);
|
||||
free(initpath);
|
||||
out2:
|
||||
free(argv);
|
||||
out1:
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -137,5 +165,6 @@ int lxc_execute(const char *name, char *const argv[], int quiet,
|
||||
if (lxc_check_inherited(conf, -1))
|
||||
return -1;
|
||||
|
||||
conf->is_execute = 1;
|
||||
return __lxc_start(name, conf, &execute_start_ops, &args, lxcpath);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
@ -120,14 +120,16 @@ out:
|
||||
|
||||
static int freeze_unfreeze(const char *name, int freeze, const char *lxcpath)
|
||||
{
|
||||
char *nsgroup;
|
||||
char *cgabspath;
|
||||
int ret;
|
||||
|
||||
ret = lxc_cgroup_path_get(&nsgroup, "freezer", name, lxcpath);
|
||||
if (ret)
|
||||
|
||||
cgabspath = lxc_cgroup_path_get("freezer", name, lxcpath);
|
||||
if (!cgabspath)
|
||||
return -1;
|
||||
|
||||
return do_unfreeze(nsgroup, freeze, name, lxcpath);
|
||||
ret = do_unfreeze(cgabspath, freeze, name, lxcpath);
|
||||
free(cgabspath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lxc_freeze(const char *name, const char *lxcpath)
|
||||
@ -141,14 +143,19 @@ int lxc_unfreeze(const char *name, const char *lxcpath)
|
||||
return freeze_unfreeze(name, 0, lxcpath);
|
||||
}
|
||||
|
||||
int lxc_unfreeze_bypath(const char *cgpath)
|
||||
int lxc_unfreeze_bypath(const char *cgrelpath)
|
||||
{
|
||||
char *nsgroup;
|
||||
int ret;
|
||||
|
||||
ret = cgroup_path_get(&nsgroup, "freezer", cgpath);
|
||||
if (ret)
|
||||
return -1;
|
||||
char cgabspath[MAXPATHLEN];
|
||||
int len, ret;
|
||||
|
||||
return do_unfreeze(nsgroup, 0, NULL, NULL);
|
||||
if (!get_subsys_mount(cgabspath, "freezer"))
|
||||
return -1;
|
||||
len = strlen(cgabspath);
|
||||
ret = snprintf(cgabspath+len, MAXPATHLEN-len, "/%s", cgrelpath);
|
||||
if (ret < 0 || ret >= MAXPATHLEN-len) {
|
||||
ERROR("freezer path name too long");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return do_unfreeze(cgabspath, 0, NULL, NULL);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@ -60,45 +60,46 @@ static int genetlink_resolve_family(const char *family)
|
||||
|
||||
ret = netlink_open(&handler, NETLINK_GENERIC);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
ret = nla_put_string((struct nlmsg *)&request->nlmsghdr,
|
||||
CTRL_ATTR_FAMILY_NAME, family);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto out_close;
|
||||
|
||||
ret = netlink_transaction(&handler, (struct nlmsg *)&request->nlmsghdr,
|
||||
(struct nlmsg *)&reply->nlmsghdr);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto out_close;
|
||||
|
||||
genlmsghdr = NLMSG_DATA(&reply->nlmsghdr);
|
||||
len = reply->nlmsghdr.nlmsg_len;
|
||||
|
||||
ret = -ENOMSG;
|
||||
if (reply->nlmsghdr.nlmsg_type != GENL_ID_CTRL)
|
||||
goto out;
|
||||
goto out_close;
|
||||
|
||||
if (genlmsghdr->cmd != CTRL_CMD_NEWFAMILY)
|
||||
goto out;
|
||||
goto out_close;
|
||||
|
||||
ret = -EMSGSIZE;
|
||||
len -= NLMSG_LENGTH(GENL_HDRLEN);
|
||||
if (len < 0)
|
||||
goto out;
|
||||
goto out_close;
|
||||
|
||||
attr = (struct nlattr *)GENLMSG_DATA(reply);
|
||||
attr = (struct nlattr *)((char *)attr + NLA_ALIGN(attr->nla_len));
|
||||
|
||||
ret = -ENOMSG;
|
||||
if (attr->nla_type != CTRL_ATTR_FAMILY_ID)
|
||||
goto out;
|
||||
goto out_close;
|
||||
|
||||
ret = *(__u16 *) NLA_DATA(attr);
|
||||
out_close:
|
||||
netlink_close(&handler);
|
||||
out:
|
||||
genlmsg_free(request);
|
||||
genlmsg_free(reply);
|
||||
netlink_close(&handler);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef __genl_h
|
||||
#define __genl_h
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
. @DATADIR@/lxc/lxc.functions
|
||||
|
||||
|
@ -18,6 +18,6 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <list.h>
|
||||
|
@ -1,3 +1,26 @@
|
||||
/*
|
||||
* lxc: linux Container library
|
||||
*
|
||||
* (C) Copyright IBM Corp. 2007, 2008
|
||||
*
|
||||
* Authors:
|
||||
* Daniel Lezcano <daniel.lezcano at free.fr>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _list_h
|
||||
#define _list_h
|
||||
|
||||
|
249
src/lxc/log.c
249
src/lxc/log.c
@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
@ -35,15 +35,19 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "caps.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define LXC_LOG_PREFIX_SIZE 32
|
||||
#define LXC_LOG_BUFFER_SIZE 512
|
||||
|
||||
int lxc_log_fd = -1;
|
||||
static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
|
||||
static char *log_fname = NULL;
|
||||
/* command line values for logfile or logpriority should always override
|
||||
* values from the configuration file or defaults
|
||||
*/
|
||||
static int lxc_logfile_specified = 0;
|
||||
static int lxc_loglevel_specified = 0;
|
||||
// if logfile was specifed on command line, it won't be overridden by lxc.logfile
|
||||
static int lxc_log_specified = 0;
|
||||
|
||||
lxc_log_define(lxc_log, lxc);
|
||||
|
||||
@ -119,12 +123,6 @@ struct lxc_log_category lxc_log_category_lxc = {
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
extern void lxc_log_setprefix(const char *prefix)
|
||||
{
|
||||
strncpy(log_prefix, prefix, sizeof(log_prefix));
|
||||
log_prefix[sizeof(log_prefix) - 1] = 0;
|
||||
}
|
||||
|
||||
static int build_dir(const char *name)
|
||||
{
|
||||
char *n = strdup(name); // because we'll be modifying it
|
||||
@ -180,29 +178,50 @@ static int log_open(const char *name)
|
||||
return newfd;
|
||||
}
|
||||
|
||||
static char *build_log_path(const char *name)
|
||||
/*
|
||||
* Build the path to the log file
|
||||
* @name : the name of the container
|
||||
* @lxcpath : the lxcpath to use as a basename or NULL to use LOGPATH
|
||||
* Returns malloced path on sucess, or NULL on failure
|
||||
*/
|
||||
static char *build_log_path(const char *name, const char *lxcpath)
|
||||
{
|
||||
char *p;
|
||||
int len, ret;
|
||||
int len, ret, use_dir;
|
||||
|
||||
#if USE_CONFIGPATH_LOGS
|
||||
use_dir = 1;
|
||||
#else
|
||||
use_dir = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* '$logpath' + '/' + '$name' + '.log' + '\0'
|
||||
* or
|
||||
* If USE_CONFIGPATH_LOGS is true or lxcpath is given, the resulting
|
||||
* path will be:
|
||||
* '$logpath' + '/' + '$name' + '/' + '$name' + '.log' + '\0'
|
||||
* sizeof(LOGPATH) includes its \0
|
||||
*
|
||||
* If USE_CONFIGPATH_LOGS is false the resulting path will be:
|
||||
* '$logpath' + '/' + '$name' + '.log' + '\0'
|
||||
*/
|
||||
len = sizeof(LOGPATH) + strlen(name) + 6;
|
||||
#if USE_CONFIGPATH_LOGS
|
||||
len += strlen(name) + 1; /* add "/$container_name/" */
|
||||
#endif
|
||||
len = strlen(name) + 6; /* 6 == '/' + '.log' + '\0' */
|
||||
if (lxcpath)
|
||||
use_dir = 1;
|
||||
else
|
||||
lxcpath = LOGPATH;
|
||||
|
||||
if (use_dir)
|
||||
len += strlen(lxcpath) + 1 + strlen(name) + 1; /* add "/$container_name/" */
|
||||
else
|
||||
len += strlen(lxcpath) + 1;
|
||||
p = malloc(len);
|
||||
if (!p)
|
||||
return p;
|
||||
#if USE_CONFIGPATH_LOGS
|
||||
ret = snprintf(p, len, "%s/%s/%s.log", LOGPATH, name, name);
|
||||
#else
|
||||
ret = snprintf(p, len, "%s/%s.log", LOGPATH, name);
|
||||
#endif
|
||||
|
||||
if (use_dir)
|
||||
ret = snprintf(p, len, "%s/%s/%s.log", lxcpath, name, name);
|
||||
else
|
||||
ret = snprintf(p, len, "%s/%s.log", lxcpath, name);
|
||||
|
||||
if (ret < 0 || ret >= len) {
|
||||
free(p);
|
||||
return NULL;
|
||||
@ -210,19 +229,67 @@ static char *build_log_path(const char *name)
|
||||
return p;
|
||||
}
|
||||
|
||||
int do_lxc_log_set_file(const char *fname, int from_default);
|
||||
/*
|
||||
* This can be called:
|
||||
* 1. when a program calls lxc_log_init with no logfile parameter (in which
|
||||
* case the default is used). In this case lxc.logfile can override this.
|
||||
* 2. when a program calls lxc_log_init with a logfile parameter. In this
|
||||
* case we don't want lxc.logfile to override this.
|
||||
* 3. When a lxc.logfile entry is found in config file.
|
||||
*/
|
||||
static int __lxc_log_set_file(const char *fname, int create_dirs)
|
||||
{
|
||||
if (lxc_log_fd != -1) {
|
||||
// we are overriding the default.
|
||||
close(lxc_log_fd);
|
||||
free(log_fname);
|
||||
}
|
||||
|
||||
#if USE_CONFIGPATH_LOGS
|
||||
// we don't build_dir for the default if the default is
|
||||
// i.e. /var/lib/lxc/$container/$container.log
|
||||
if (create_dirs)
|
||||
#endif
|
||||
if (build_dir(fname)) {
|
||||
ERROR("failed to create dir for log file \"%s\" : %s", fname,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
lxc_log_fd = log_open(fname);
|
||||
if (lxc_log_fd == -1)
|
||||
return -1;
|
||||
|
||||
log_fname = strdup(fname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_dirs)
|
||||
{
|
||||
char *logfile;
|
||||
int ret;
|
||||
|
||||
logfile = build_log_path(name, lxcpath);
|
||||
if (!logfile) {
|
||||
ERROR("could not build log path");
|
||||
return -1;
|
||||
}
|
||||
ret = __lxc_log_set_file(logfile, create_dirs);
|
||||
free(logfile);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
extern int lxc_log_init(const char *name, const char *file,
|
||||
const char *priority, const char *prefix, int quiet)
|
||||
const char *priority, const char *prefix, int quiet,
|
||||
const char *lxcpath)
|
||||
{
|
||||
int lxc_priority = LXC_LOG_PRIORITY_ERROR;
|
||||
int ret;
|
||||
char *tmpfile = NULL;
|
||||
int want_lxc_log_specified = 0;
|
||||
|
||||
if (lxc_log_fd != -1)
|
||||
if (lxc_log_fd != -1) {
|
||||
WARN("lxc_log_init called with log already initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (priority) {
|
||||
lxc_loglevel_specified = 1;
|
||||
@ -241,39 +308,41 @@ extern int lxc_log_init(const char *name, const char *file,
|
||||
lxc_log_category_lxc.appender->next = &log_appender_stderr;
|
||||
|
||||
if (prefix)
|
||||
lxc_log_setprefix(prefix);
|
||||
lxc_log_set_prefix(prefix);
|
||||
|
||||
if (file && strcmp(file, "none") == 0) {
|
||||
want_lxc_log_specified = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
tmpfile = build_log_path(name);
|
||||
if (!tmpfile) {
|
||||
ERROR("could not build log path");
|
||||
return -1;
|
||||
}
|
||||
if (file) {
|
||||
lxc_logfile_specified = 1;
|
||||
if (strcmp(file, "none") == 0)
|
||||
return 0;
|
||||
ret = __lxc_log_set_file(file, 1);
|
||||
} else {
|
||||
want_lxc_log_specified = 1;
|
||||
ret = -1;
|
||||
|
||||
if (!lxcpath)
|
||||
lxcpath = LOGPATH;
|
||||
|
||||
/* try LOGPATH if lxcpath is the default */
|
||||
if (strcmp(lxcpath, default_lxc_path()) == 0)
|
||||
ret = _lxc_log_set_file(name, NULL, 0);
|
||||
|
||||
/* try in lxcpath */
|
||||
if (ret < 0)
|
||||
ret = _lxc_log_set_file(name, lxcpath, 1);
|
||||
|
||||
/* try LOGPATH in case its writable by the caller */
|
||||
if (ret < 0)
|
||||
ret = _lxc_log_set_file(name, NULL, 0);
|
||||
}
|
||||
|
||||
ret = do_lxc_log_set_file(tmpfile ? tmpfile : file, !want_lxc_log_specified);
|
||||
|
||||
if (want_lxc_log_specified)
|
||||
lxc_log_specified = 1;
|
||||
/*
|
||||
* If !want_lxc_log_specified, that is, if the user did not request
|
||||
* this logpath, then ignore failures and continue logging to console
|
||||
* If !file, that is, if the user did not request this logpath, then
|
||||
* ignore failures and continue logging to console
|
||||
*/
|
||||
if (!want_lxc_log_specified && ret != 0) {
|
||||
if (!file && ret != 0) {
|
||||
INFO("Ignoring failure to open default logfile.");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (tmpfile)
|
||||
free(tmpfile);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -294,51 +363,6 @@ extern int lxc_log_set_level(int level)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *log_fname; // default to NULL, set in lxc_log_set_file.
|
||||
/*
|
||||
* This can be called:
|
||||
* 1. when a program calls lxc_log_init with no logfile parameter (in which
|
||||
* case the default is used). In this case lxc.logfile can override this.
|
||||
* 2. when a program calls lxc_log_init with a logfile parameter. In this
|
||||
* case we don't want lxc.logfile to override this.
|
||||
* 3. When a lxc.logfile entry is found in config file.
|
||||
*/
|
||||
int do_lxc_log_set_file(const char *fname, int from_default)
|
||||
{
|
||||
if (lxc_log_specified) {
|
||||
INFO("lxc.logfile overridden by command line");
|
||||
return 0;
|
||||
}
|
||||
if (lxc_log_fd != -1) {
|
||||
// we are overriding the default.
|
||||
close(lxc_log_fd);
|
||||
free(log_fname);
|
||||
}
|
||||
|
||||
#if USE_CONFIGPATH_LOGS
|
||||
// we don't build_dir for the default if the default is
|
||||
// i.e. /var/lib/lxc/$container/$container.log
|
||||
if (!from_default)
|
||||
#endif
|
||||
if (build_dir(fname)) {
|
||||
ERROR("failed to create dir for log file \"%s\" : %s", fname,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
lxc_log_fd = log_open(fname);
|
||||
if (lxc_log_fd == -1)
|
||||
return -1;
|
||||
|
||||
log_fname = strdup(fname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int lxc_log_set_file(const char *fname)
|
||||
{
|
||||
return do_lxc_log_set_file(fname, 0);
|
||||
}
|
||||
|
||||
extern int lxc_log_get_level(void)
|
||||
{
|
||||
if (!lxc_loglevel_specified)
|
||||
@ -346,7 +370,38 @@ extern int lxc_log_get_level(void)
|
||||
return lxc_log_category_lxc.priority;
|
||||
}
|
||||
|
||||
extern bool lxc_log_has_valid_level(void)
|
||||
{
|
||||
int log_level = lxc_log_get_level();
|
||||
if (log_level < 0 || log_level >= LXC_LOG_PRIORITY_NOTSET)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called when we read a lxc.logfile entry in a lxc.conf file. This
|
||||
* happens after processing command line arguments, which override the .conf
|
||||
* settings. So only set the file if previously unset.
|
||||
*/
|
||||
extern int lxc_log_set_file(const char *fname)
|
||||
{
|
||||
if (lxc_logfile_specified)
|
||||
return 0;
|
||||
return __lxc_log_set_file(fname, 0);
|
||||
}
|
||||
|
||||
extern const char *lxc_log_get_file(void)
|
||||
{
|
||||
return log_fname;
|
||||
}
|
||||
|
||||
extern void lxc_log_set_prefix(const char *prefix)
|
||||
{
|
||||
strncpy(log_prefix, prefix, sizeof(log_prefix));
|
||||
log_prefix[sizeof(log_prefix) - 1] = 0;
|
||||
}
|
||||
|
||||
extern const char *lxc_log_get_prefix(void)
|
||||
{
|
||||
return log_prefix;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef _log_h
|
||||
#define _log_h
|
||||
@ -28,6 +28,7 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 02000000
|
||||
@ -172,7 +173,7 @@ __lxc_log(const struct lxc_log_category* category,
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper macro to define log fonctions.
|
||||
* Helper macro to define log functions.
|
||||
*/
|
||||
#define lxc_log_priority_define(acategory, PRIORITY) \
|
||||
\
|
||||
@ -288,11 +289,14 @@ extern struct lxc_log_category lxc_log_category_lxc;
|
||||
extern int lxc_log_fd;
|
||||
|
||||
extern int lxc_log_init(const char *name, const char *file,
|
||||
const char *priority, const char *prefix, int quiet);
|
||||
const char *priority, const char *prefix, int quiet,
|
||||
const char *lxcpath);
|
||||
|
||||
extern void lxc_log_setprefix(const char *a_prefix);
|
||||
extern int lxc_log_set_level(int level);
|
||||
extern int lxc_log_set_file(const char *fname);
|
||||
extern int lxc_log_get_level(void);
|
||||
extern int lxc_log_set_level(int level);
|
||||
extern void lxc_log_set_prefix(const char *prefix);
|
||||
extern const char *lxc_log_get_file(void);
|
||||
extern int lxc_log_get_level(void);
|
||||
extern bool lxc_log_has_valid_level(void);
|
||||
extern const char *lxc_log_get_prefix(void);
|
||||
#endif
|
||||
|
@ -10,7 +10,7 @@ SETCOLOR_WARNING="printf \\033[1;33m"
|
||||
SETCOLOR_NORMAL="printf \\033[0;39m"
|
||||
|
||||
is_set() {
|
||||
$GREP -q "$1=[y|m]" $CONFIG
|
||||
$GREP "$1=[y|m]" $CONFIG > /dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
|
@ -1,324 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# lxc: linux Container library
|
||||
|
||||
# Authors:
|
||||
# Serge Hallyn <serge.hallyn@ubuntu.com>
|
||||
# Daniel Lezcano <daniel.lezcano@free.fr>
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
echo "usage: $(basename $0) -o ORIG_NAME -n NEW_NAME [-s] [-h] [-L FS_SIZE]" >&2
|
||||
echo " [-v VG_NAME] [-p LV_PREFIX] [-t FS_TYPE]" >&2
|
||||
}
|
||||
|
||||
help() {
|
||||
usage
|
||||
echo >&2
|
||||
echo "Clone an existing container on the system." >&2
|
||||
echo >&2
|
||||
echo "Options:" >&2
|
||||
echo " -o ORIG_NAME specify the name of the original container" >&2
|
||||
echo " -n NEW_NAME specify the name of the new container" >&2
|
||||
echo " -s make the new rootfs a snapshot of the original" >&2
|
||||
echo " -L FS_SIZE specify the new filesystem size (default: same as original)" >&2
|
||||
echo " -v VG_NAME specify the new LVM volume group name (default: lxc)" >&2
|
||||
echo " -p LV_PREFIX add a prefix to new LVM logical volume names" >&2
|
||||
echo " -t FS_TYPE specify the new filesystem type (default: ext3;" >&2
|
||||
echo " only works for non-snapshot LVM)" >&2
|
||||
}
|
||||
|
||||
usage_err() {
|
||||
[ -n "$1" ] && echo "$1" >&2
|
||||
usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
optarg_check() {
|
||||
[ -n "$2" ] || usage_err "option $1 requires an argument"
|
||||
}
|
||||
|
||||
. @DATADIR@/lxc/lxc.functions
|
||||
snapshot=no
|
||||
lxc_size=_unset
|
||||
lxc_vg=lxc
|
||||
lxc_lv_prefix=""
|
||||
fstype=ext3
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
opt="$1"
|
||||
shift
|
||||
case "$opt" in
|
||||
-h|--help)
|
||||
help
|
||||
exit 1
|
||||
;;
|
||||
-s|--snapshot)
|
||||
snapshot=yes
|
||||
snapshot_opt="-s"
|
||||
;;
|
||||
-o|--orig)
|
||||
optarg_check $opt $1
|
||||
lxc_orig=$1
|
||||
shift
|
||||
;;
|
||||
-L|--fssize)
|
||||
optarg_check $opt $1
|
||||
lxc_size=$1
|
||||
shift
|
||||
;;
|
||||
-t|--fstype)
|
||||
optarg_check $opt $1
|
||||
fstype=$1
|
||||
shift
|
||||
;;
|
||||
-v|--vgname)
|
||||
optarg_check $opt $1
|
||||
lxc_vg=$1
|
||||
shift
|
||||
;;
|
||||
-n|--name)
|
||||
optarg_check $opt $1
|
||||
lxc_new=$1
|
||||
shift
|
||||
;;
|
||||
-p|--lvprefix)
|
||||
optarg_check $opt $1
|
||||
lxc_lv_prefix=$1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
break
|
||||
;;
|
||||
-?)
|
||||
usage_err "Unknown option: '$opt'"
|
||||
;;
|
||||
-*)
|
||||
# split opts -abc into -a -b -c
|
||||
set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
|
||||
;;
|
||||
*)
|
||||
usage_err
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$lxc_path" ]; then
|
||||
echo "$(basename $0): no configuration path defined" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -r $lxc_path ]; then
|
||||
echo "$(basename $0): configuration path '$lxc_path' not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$lxc_orig" ]; then
|
||||
echo "$(basename $0): no original container name specified" >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$lxc_new" ]; then
|
||||
echo "$(basename $0): no new container name specified" >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
echo "$(basename $0): must be run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$lxc_path/$lxc_orig" ]; then
|
||||
echo "$(basename $0): '$lxc_orig' does not exist" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -d "$lxc_path/$lxc_new" ]; then
|
||||
echo "$(basename $0): '$lxc_new' already exists" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mounted=0
|
||||
frozen=0
|
||||
oldroot=`grep lxc.rootfs $lxc_path/$lxc_orig/config | awk -F= '{ print $2 '}`
|
||||
|
||||
cleanup() {
|
||||
if [ -b $oldroot ]; then
|
||||
if [ $mounted -eq 1 ]; then
|
||||
umount $rootfs || true
|
||||
fi
|
||||
lvremove -f $rootdev || true
|
||||
fi
|
||||
${bindir}/lxc-destroy -n $lxc_new || true
|
||||
if [ $frozen -eq 1 ]; then
|
||||
lxc-unfreeze -n $lxc_orig
|
||||
fi
|
||||
echo "$(basename $0): aborted" >&2
|
||||
exit 1
|
||||
}
|
||||
trap cleanup HUP INT TERM
|
||||
|
||||
mkdir -p $lxc_path/$lxc_new
|
||||
hostname=$lxc_new
|
||||
|
||||
echo "Tweaking configuration"
|
||||
cp $lxc_path/$lxc_orig/config $lxc_path/$lxc_new/config
|
||||
sed -i '/lxc.utsname/d' $lxc_path/$lxc_new/config
|
||||
echo "lxc.utsname = $hostname" >> $lxc_path/$lxc_new/config
|
||||
|
||||
grep "lxc.mount[ \t]" $lxc_path/$lxc_new/config >/dev/null 2>&1 && { sed -i '/lxc.mount[ \t]/d' $lxc_path/$lxc_new/config; echo "lxc.mount = $lxc_path/$lxc_new/fstab" >> $lxc_path/$lxc_new/config; }
|
||||
|
||||
if [ -e $lxc_path/$lxc_orig/fstab ];then
|
||||
cp $lxc_path/$lxc_orig/fstab $lxc_path/$lxc_new/fstab
|
||||
sed -i "s@$lxc_path/$lxc_orig@$lxc_path/$lxc_new@" $lxc_path/$lxc_new/fstab
|
||||
fi
|
||||
|
||||
echo "Copying rootfs..."
|
||||
oldroot=`grep lxc.rootfs $lxc_path/$lxc_orig/config | awk -F'[= \t]+' '{ print $2 }'`
|
||||
rootfs=`echo $oldroot |sed "s/$lxc_orig/$lxc_new/"`
|
||||
|
||||
container_running=True
|
||||
lxc-info -n $lxc_orig --state-is RUNNING || container_running=False
|
||||
|
||||
sed -i '/lxc.rootfs/d' $lxc_path/$lxc_new/config
|
||||
if [ -b $oldroot ]; then
|
||||
which vgscan >/dev/null 2>&1 || { echo "$(basename $0): lvm is not installed" >&2; false; }
|
||||
lvdisplay $oldroot > /dev/null 2>&1 || { echo "$(basename $0): non-lvm blockdev cloning is not supported" >&2; false; }
|
||||
lvm=TRUE
|
||||
# ok, create a snapshot of the lvm device
|
||||
if [ $container_running = "True" ]; then
|
||||
lxc-freeze -n $lxc_orig
|
||||
frozen=1
|
||||
fi
|
||||
if [ $lxc_size = "_unset" ]; then
|
||||
lxc_size=`lvdisplay $oldroot | grep Size | awk '{ print $3 $4 }'`
|
||||
fi
|
||||
newlv="${lxc_lv_prefix}${lxc_new}_snapshot"
|
||||
lvcreate -s -L $lxc_size -n $newlv $oldroot
|
||||
which xfs_admin > /dev/null 2>&1 && {
|
||||
# change filesystem UUID if it is an xfs filesystem
|
||||
xfs_admin -u /dev/$lxc_vg/$newlv && xfs_admin -U generate /dev/$lxc_vg/$newlv
|
||||
}
|
||||
|
||||
if [ $container_running = "True" ]; then
|
||||
lxc-unfreeze -n $lxc_orig
|
||||
frozen=0
|
||||
fi
|
||||
if [ $snapshot = "no" ]; then
|
||||
#mount snapshot
|
||||
mkdir -p ${rootfs}_snapshot
|
||||
mount /dev/$lxc_vg/${lxc_lv_prefix}${lxc_new}_snapshot ${rootfs}_snapshot || { echo "$(basename $0): failed to mount new rootfs_snapshot" >&2; false; }
|
||||
#create a new lv
|
||||
lvcreate -L $lxc_size $lxc_vg -n ${lxc_lv_prefix}$lxc_new
|
||||
echo "lxc.rootfs = /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new" >> $lxc_path/$lxc_new/config
|
||||
# and mount it so we can tweak it
|
||||
mkdir -p $rootfs
|
||||
mkfs -t $fstype /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new
|
||||
mount /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new $rootfs || { echo "$(basename $0): failed to mount new rootfs" >&2; false; }
|
||||
mounted=1
|
||||
rsync -Hax ${rootfs}_snapshot/ ${rootfs}/ || { echo "$(basename $0): copying data to new lv failed" >&2; false; }
|
||||
umount ${rootfs}_snapshot
|
||||
rmdir ${rootfs}_snapshot
|
||||
lvremove -f $lxc_vg/${lxc_lv_prefix}${lxc_new}_snapshot
|
||||
else
|
||||
lvrename $lxc_vg/${lxc_lv_prefix}${lxc_new}_snapshot $lxc_vg/${lxc_lv_prefix}$lxc_new
|
||||
echo "lxc.rootfs = /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new" >> $lxc_path/$lxc_new/config
|
||||
# and mount it so we can tweak it
|
||||
mkdir -p $rootfs
|
||||
mount /dev/$lxc_vg/${lxc_lv_prefix}$lxc_new $rootfs || { echo "$(basename $0): failed to mount new rootfs" >&2; false; }
|
||||
mounted=1
|
||||
fi
|
||||
|
||||
elif which btrfs >/dev/null 2>&1 && btrfs subvolume list $oldroot >/dev/null 2>&1; then
|
||||
# if oldroot is a btrfs subvolume, assume they want a snapshot
|
||||
btrfs subvolume snapshot "$oldroot" "$rootfs" 2>&1 || { echo "$(basename $0): btrfs snapshot failed" >&2; false; }
|
||||
echo "lxc.rootfs = $rootfs" >> "$lxc_path/$lxc_new/config"
|
||||
elif [ -d $lxc_path/$lxc_orig/delta0 ]; then # this is a quasi-ephemeral container
|
||||
if [ $container_running = "True" ]; then
|
||||
echo "$(basename $0): container $lxc_orig is running." >&2
|
||||
cleanup
|
||||
fi
|
||||
rsync -Hax $lxc_path/$lxc_orig/delta0 $lxc_path/$lxc_new/
|
||||
touch $lxc_path/$lxc_new/configured
|
||||
cp -f $lxc_path/$lxc_orig/pre-mount $lxc_path/$lxc_new/
|
||||
sed -i "s@$lxc_path/$lxc_orig@$lxc_path/$lxc_new@g" $lxc_path/$lxc_new/config
|
||||
sed -i "s@$lxc_path/$lxc_orig@$lxc_path/$lxc_new@g" $lxc_path/$lxc_new/pre-mount
|
||||
sed -i "s@LXC_NAME=\"$lxc_orig@LXC_NAME=\"$lxc_new@" $lxc_path/$lxc_new/pre-mount
|
||||
# lxc-start-ephemeral will have updated /etc/hostname and such under the
|
||||
# delta0, so just mounting the delta should suffice.
|
||||
mkdir -p $rootfs
|
||||
mount --bind $lxc_path/$lxc_new/delta0 $rootfs
|
||||
mounted=1
|
||||
echo "lxc.rootfs = $rootfs" >> "$lxc_path/$lxc_new/config"
|
||||
else
|
||||
if [ $snapshot = "yes" ]; then
|
||||
echo "$(basename $0): cannot snapshot a directory" >&2
|
||||
cleanup
|
||||
fi
|
||||
if [ $container_running = "True" ]; then
|
||||
lxc-freeze -n $lxc_orig
|
||||
frozen=1
|
||||
fi
|
||||
mkdir -p $rootfs/
|
||||
rsync -Hax $oldroot/ $rootfs/
|
||||
echo "lxc.rootfs = $rootfs" >> $lxc_path/$lxc_new/config
|
||||
if [ $container_running = "True" ]; then
|
||||
lxc-unfreeze -n $lxc_orig
|
||||
frozen=0
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Updating rootfs..."
|
||||
|
||||
# so you can 'ssh $hostname.' or 'ssh $hostname.local'
|
||||
if [ -f $rootfs/etc/dhcp/dhclient.conf ] && ! grep -q "^send host-name.*hostname" $rootfs/etc/dhcp/dhclient.conf; then
|
||||
sed -i "s/send host-name.*$/send host-name \"$hostname\";/" $rootfs/etc/dhcp/dhclient.conf
|
||||
fi
|
||||
|
||||
c=$lxc_path/$lxc_new/config
|
||||
# change hwaddrs
|
||||
mv ${c} ${c}.old
|
||||
(
|
||||
while read line; do
|
||||
if echo $line | grep -q -w '^lxc.network.hwaddr'; then
|
||||
echo "lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')"
|
||||
else
|
||||
echo "$line"
|
||||
fi
|
||||
done
|
||||
) < ${c}.old > ${c}
|
||||
rm -f ${c}.old
|
||||
|
||||
# set the hostname
|
||||
cat <<EOF > $rootfs/etc/hostname
|
||||
$hostname
|
||||
EOF
|
||||
# set minimal hosts
|
||||
cat <<EOF > $rootfs/etc/hosts
|
||||
127.0.0.1 localhost $hostname
|
||||
EOF
|
||||
|
||||
# if this was a block device, then umount it now
|
||||
if [ $mounted -eq 1 ]; then
|
||||
umount $rootfs
|
||||
fi
|
||||
|
||||
echo "'$lxc_new' created"
|
@ -1,357 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# lxc: linux Container library
|
||||
|
||||
# Authors:
|
||||
# Daniel Lezcano <daniel.lezcano@free.fr>
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
. @DATADIR@/lxc/lxc.functions
|
||||
|
||||
usage() {
|
||||
echo "usage: $(basename $0) -n NAME [-f CONFIG_FILE] [-t TEMPLATE] [FS_OPTIONS] --" >&2
|
||||
echo " [-P lxcpath] [TEMPLATE_OPTIONS]" >&2
|
||||
echo >&2
|
||||
echo "where FS_OPTIONS is one of:" >&2
|
||||
echo " -B none" >&2
|
||||
echo " -B dir [--dir rootfs_dir]" >&2
|
||||
echo " -B lvm [--lvname LV_NAME] [--vgname VG_NAME] [--fstype FS_TYPE]" >&2
|
||||
echo " [--fssize FS_SIZE]" >&2
|
||||
echo " -B btrfs" >&2
|
||||
}
|
||||
|
||||
help() {
|
||||
usage
|
||||
echo >&2
|
||||
echo "Create a new container on the system." >&2
|
||||
echo >&2
|
||||
echo "Options:" >&2
|
||||
echo " -n NAME specify the name of the container" >&2
|
||||
echo " -f CONFIG_FILE use an existing configuration file" >&2
|
||||
echo " -t TEMPLATE use an accessible template script" >&2
|
||||
echo " -B BACKING_STORE alter the container backing store (default: none)" >&2
|
||||
echo " --lxcpath path specify an alternate container patch (default: $lxc_path)" >&2
|
||||
echo " --lvname LV_NAME specify the LVM logical volume name" >&2
|
||||
echo " (default: container name)" >&2
|
||||
echo " --dir ROOTFS_DIR specify path for custom rootfs directory location" >&2
|
||||
echo " --vgname VG_NAME specify the LVM volume group name (default: lxc)" >&2
|
||||
echo " --fstype FS_TYPE specify the filesystem type (default: ext4)" >&2
|
||||
echo " --fssize FS_SIZE specify the filesystem size (default: 500M)" >&2
|
||||
echo >&2
|
||||
if [ -z "$lxc_template" ]; then
|
||||
echo "To see template-specific options, specify a template. For example:" >&2
|
||||
echo " $(basename $0) -t ubuntu -h" >&2
|
||||
exit 0
|
||||
fi
|
||||
if [ -x ${templatedir}/lxc-$lxc_template ]; then
|
||||
echo >&2
|
||||
echo "Template-specific options (TEMPLATE_OPTIONS):" >&2
|
||||
${templatedir}/lxc-$lxc_template -h
|
||||
fi
|
||||
}
|
||||
|
||||
usage_err() {
|
||||
[ -n "$1" ] && echo "$1" >&2
|
||||
usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
optarg_check() {
|
||||
if [ -z "$2" ]; then
|
||||
usage_err "option '$1' requires an argument"
|
||||
fi
|
||||
}
|
||||
|
||||
backingstore=_unset
|
||||
fstype=ext4
|
||||
fssize=500M
|
||||
vgname=lxc
|
||||
custom_rootfs=""
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
opt="$1"
|
||||
shift
|
||||
case "$opt" in
|
||||
-h|--help)
|
||||
help
|
||||
exit 1
|
||||
;;
|
||||
-n|--name)
|
||||
optarg_check $opt "$1"
|
||||
lxc_name=$1
|
||||
shift
|
||||
;;
|
||||
-f|--config)
|
||||
optarg_check $opt "$1"
|
||||
lxc_config=$1
|
||||
shift
|
||||
;;
|
||||
-P|--lxcpath)
|
||||
optarg_check $opt "$1"
|
||||
lxc_path=$1
|
||||
shift
|
||||
;;
|
||||
-t|--template)
|
||||
optarg_check $opt "$1"
|
||||
lxc_template=$1
|
||||
shift
|
||||
;;
|
||||
-B|--backingstore)
|
||||
optarg_check $opt "$1"
|
||||
backingstore=$1
|
||||
shift
|
||||
;;
|
||||
--dir)
|
||||
optarg_check $opt "$1"
|
||||
custom_rootfs=$1
|
||||
shift
|
||||
;;
|
||||
--lvname)
|
||||
optarg_check $opt "$1"
|
||||
lvname=$1
|
||||
shift
|
||||
;;
|
||||
--vgname)
|
||||
optarg_check $opt "$1"
|
||||
vgname=$1
|
||||
shift
|
||||
;;
|
||||
--fstype)
|
||||
optarg_check $opt "$1"
|
||||
fstype=$1
|
||||
shift
|
||||
;;
|
||||
--fssize)
|
||||
optarg_check $opt "$1"
|
||||
fssize=$1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
break;;
|
||||
-?)
|
||||
usage_err "unknown option '$opt'"
|
||||
;;
|
||||
-*)
|
||||
# split opts -abc into -a -b -c
|
||||
set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# If -h or --help was passed into the container, we'll want to cleanup
|
||||
# afterward
|
||||
wantedhelp=0
|
||||
for var in "$@"; do
|
||||
if [ "$var" = "-h" ] || [ "$var" = "--help" ]; then
|
||||
help
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
if [ -z "$lxc_path" ]; then
|
||||
echo "$(basename $0): no configuration path defined" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -r $lxc_path ]; then
|
||||
echo "$(basename $0): configuration path '$lxc_path' not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$lxc_name" ]; then
|
||||
echo "$(basename $0): no container name specified" >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$lvname" ]; then
|
||||
lvname="$lxc_name"
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
echo "$(basename $0): must be run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$custom_rootfs" ] && [ "$backingstore" != "dir" ]; then
|
||||
echo "--dir is only valid with -B dir"
|
||||
fi
|
||||
|
||||
case "$backingstore" in
|
||||
dir|lvm|none|btrfs|_unset) :;;
|
||||
*)
|
||||
echo "$(basename $0): '$backingstore' is not known (try 'none', 'dir', 'lvm', 'btrfs')" >&2
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -d "$lxc_path/$lxc_name" ]; then
|
||||
echo "$(basename $0): '$lxc_name' already exists" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rootfs="$lxc_path/$lxc_name/rootfs"
|
||||
|
||||
if [ "$backingstore" = "_unset" ] || [ "$backingstore" = "btrfs" ]; then
|
||||
# if no backing store was given, then see if btrfs would work
|
||||
if which btrfs >/dev/null 2>&1 && \
|
||||
btrfs filesystem df "$lxc_path/" >/dev/null 2>&1; then
|
||||
backingstore="btrfs"
|
||||
else
|
||||
if [ "$backingstore" = "btrfs" ]; then
|
||||
echo "$(basename $0): missing 'btrfs' command or $lxc_path is not btrfs" >&2
|
||||
exit 1;
|
||||
fi
|
||||
backingstore="none"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$backingstore" = "lvm" ]; then
|
||||
which vgscan > /dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$(basename $0): vgscan not found (is lvm2 installed?)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
grep -q "\<$fstype\>" /proc/filesystems
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$(basename $0): $fstype is not listed in /proc/filesystems" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
vgscan | grep -q "Found volume group \"$vgname\""
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$(basename $0): could not find volume group \"$vgname\"" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rootdev=/dev/$vgname/$lvname
|
||||
lvdisplay $rootdev > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "$(basename $0): backing store already exists: $rootdev" >&2
|
||||
echo "please delete it (using \"lvremove $rootdev\") and try again" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
elif [ "$backingstore" = "btrfs" ]; then
|
||||
mkdir "$lxc_path/$lxc_name"
|
||||
if ! out=$(btrfs subvolume create "$rootfs" 2>&1); then
|
||||
echo "$(basename $0): failed to create subvolume in $rootfs: $out" >&2
|
||||
exit 1;
|
||||
fi
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
if [ "$backingstore" = "lvm" ]; then
|
||||
umount $rootfs
|
||||
lvremove -f $rootdev
|
||||
elif [ "$backingstore" = "btrfs" ]; then
|
||||
btrfs subvolume delete "$rootfs"
|
||||
fi
|
||||
|
||||
${bindir}/lxc-destroy -n $lxc_name
|
||||
echo "$(basename $0): aborted" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap cleanup HUP INT TERM
|
||||
|
||||
mkdir -p $lxc_path/$lxc_name
|
||||
|
||||
if [ -z "$lxc_config" ]; then
|
||||
lxc_config="@SYSCONFDIR@/lxc/default.conf"
|
||||
echo
|
||||
echo "$(basename $0): No config file specified, using the default config $lxc_config"
|
||||
fi
|
||||
|
||||
if [ ! -r "$lxc_config" ]; then
|
||||
echo "$(basename $0): '$lxc_config' configuration file not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -z "$lxc_template" ]; then
|
||||
# Allow for a path to be provided as the template name
|
||||
if [ -x "$lxc_template" -a $(echo "$lxc_template" | cut -c 1) = '/' ]; then
|
||||
template_path=$lxc_template
|
||||
else
|
||||
template_path=${templatedir}/lxc-$lxc_template
|
||||
fi
|
||||
|
||||
if ! [ -x "$template_path" ]; then
|
||||
echo "$(basename $0): unknown template '$lxc_template'" >&2
|
||||
cleanup
|
||||
fi
|
||||
|
||||
sum=$(sha1sum $template_path | cut -d ' ' -f1)
|
||||
echo "# Template used to create this container: $lxc_template" >> $lxc_path/$lxc_name/config
|
||||
if [ -n "$*" ]; then
|
||||
echo "# Parameters passed to the template: $*" >> $lxc_path/$lxc_name/config
|
||||
fi
|
||||
echo "# Template script checksum (SHA-1): $sum" >> $lxc_path/$lxc_name/config
|
||||
echo "" >> $lxc_path/$lxc_name/config
|
||||
fi
|
||||
|
||||
cat $lxc_config >> $lxc_path/$lxc_name/config
|
||||
echo "" >> $lxc_path/$lxc_name/config
|
||||
|
||||
if [ -n "$custom_rootfs" ]; then
|
||||
if grep -q "lxc.rootfs" $lxc_path/$lxc_name/config ; then
|
||||
echo "configuration file already specifies a lxc.rootfs"
|
||||
exit 1
|
||||
fi
|
||||
if [ -d "$custom_rootfs" ]; then
|
||||
echo "specified rootfs ($custom_rootfs) already exists. Bailing."
|
||||
exit 1
|
||||
fi
|
||||
echo "lxc.rootfs = $custom_rootfs" >> $lxc_path/$lxc_name/config
|
||||
fi
|
||||
|
||||
# Create the fs as needed
|
||||
if [ "$backingstore" = "lvm" ]; then
|
||||
[ -d "$rootfs" ] || mkdir $rootfs
|
||||
lvcreate -L $fssize -n $lvname $vgname || exit 1
|
||||
udevadm settle
|
||||
mkfs -t $fstype $rootdev || exit 1
|
||||
mount -t $fstype $rootdev $rootfs
|
||||
fi
|
||||
|
||||
if [ ! -z "$lxc_template" ]; then
|
||||
$template_path --path=$lxc_path/$lxc_name --name=$lxc_name $*
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$(basename $0): failed to execute template '$lxc_template'" >&2
|
||||
cleanup
|
||||
fi
|
||||
|
||||
echo "'$lxc_template' template installed"
|
||||
fi
|
||||
|
||||
if [ "$backingstore" = "lvm" ]; then
|
||||
echo "Unmounting LVM"
|
||||
umount $rootfs
|
||||
|
||||
# TODO: make the templates set this right from the start?
|
||||
sed -i '/lxc.rootfs/d' $lxc_path/$lxc_name/config
|
||||
echo "lxc.rootfs = $rootdev" >> $lxc_path/$lxc_name/config
|
||||
fi
|
||||
|
||||
echo "'$lxc_name' created"
|
@ -18,7 +18,7 @@
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#
|
||||
# This script allows to set or remove the capabilities on the lxc tools.
|
||||
@ -40,19 +40,55 @@ help() {
|
||||
echo " -P lxcpath container is in specified lxcpath" >&2
|
||||
}
|
||||
|
||||
. @DATADIR@/lxc/lxc.functions
|
||||
|
||||
usage_err() {
|
||||
[ -n "$1" ] && echo "$1" >&2
|
||||
usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
verify_zfs() {
|
||||
local path=$1
|
||||
which zfs > /dev/null 2>&1 || { echo no; return; }
|
||||
if zfs list -H $path >/dev/null 2>&1; then
|
||||
echo zfs
|
||||
else
|
||||
echo no
|
||||
fi
|
||||
}
|
||||
|
||||
busy_zfs() {
|
||||
local path=$1
|
||||
local dev
|
||||
dev=`zfs list -H $path 2>/dev/null | awk '{ print $1 }'`
|
||||
if zfs list -t snapshot | grep -q "$dev"; then
|
||||
echo busy
|
||||
else
|
||||
echo zfs
|
||||
fi
|
||||
}
|
||||
|
||||
verify_lvm() {
|
||||
local path=$1
|
||||
if [ -b $path -o -h $path ]; then
|
||||
lvdisplay $path > /dev/null 2>&1 && { echo lvm; return; }
|
||||
fi
|
||||
echo no
|
||||
}
|
||||
|
||||
busy_lvm() {
|
||||
local path=$1
|
||||
lvdisplay $path | grep -q "LV snapshot status.*source of" && { echo busy; return; }
|
||||
echo lvm
|
||||
}
|
||||
|
||||
optarg_check() {
|
||||
if [ -z "$2" ]; then
|
||||
usage_err "option '$1' requires an argument"
|
||||
fi
|
||||
}
|
||||
|
||||
. @DATADIR@/lxc/lxc.functions
|
||||
force=0
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
@ -121,16 +157,29 @@ if ! lxc-info -n $lxc_name -P $lxc_path --state-is "STOPPED"; then
|
||||
fi
|
||||
|
||||
# Deduce the type of rootfs
|
||||
# If LVM partition, destroy it. For btrfs, we delete the subvolue. If anything
|
||||
# If LVM partition, destroy it. For btrfs, we delete the subvolume. If anything
|
||||
# else, ignore it. We'll support deletion of others later.
|
||||
rootdev=`grep lxc.rootfs $lxc_path/$lxc_name/config 2>/dev/null | sed -e 's/^[^/]*/\//'`
|
||||
rootdev=`grep '^\s*lxc\.rootfs' $lxc_path/$lxc_name/config 2>/dev/null | sed -e 's/^[^/]*//'`
|
||||
if [ -n "$rootdev" ]; then
|
||||
if [ -b "$rootdev" -o -h "$rootdev" ]; then
|
||||
lvdisplay $rootdev > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ `verify_lvm $rootdev` = "lvm" ]; then
|
||||
if [ `busy_lvm $rootdev` = "busy" ]; then
|
||||
echo "$rootdev has lvm snapshots - not deleting"
|
||||
exit 1
|
||||
else
|
||||
echo "removing backing store: $rootdev"
|
||||
lvremove -f $rootdev
|
||||
fi
|
||||
elif [ `verify_zfs $rootdev` = "zfs" ]; then
|
||||
if [ `busy_zfs $rootdev` = "busy" ]; then
|
||||
echo "$rootdev has zfs snapshots - not deleting"
|
||||
exit 1
|
||||
else
|
||||
zfs destroy $(zfs list | grep $rootdev | awk '{ print $1 }')
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "zfs destroy failed - please wait a bit and try again"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
elif [ -h "$rootdev" -o -d "$rootdev" ]; then
|
||||
if which btrfs >/dev/null 2>&1 &&
|
||||
btrfs subvolume list "$rootdev" >/dev/null 2>&1; then
|
||||
|
@ -22,7 +22,7 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
|
||||
# NOTE: To remove once the API is stabilized
|
||||
|
@ -22,7 +22,7 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
|
||||
# NOTE: To remove once the API is stabilized
|
||||
@ -89,12 +89,13 @@ def getTerminalSize():
|
||||
|
||||
|
||||
def getSubContainers(container, lxcpath):
|
||||
attach = ['lxc-attach', '-R', '-s', 'NETWORK|PID', '-n', container,
|
||||
attach = ['lxc-attach', '-P', lxcpath, '-R', '-s', 'NETWORK|PID',
|
||||
'-n', container,
|
||||
'--', sys.argv[0], "--nesting"]
|
||||
|
||||
with open(os.devnull, "w") as fd:
|
||||
newenv = dict(os.environ)
|
||||
newenv['NESTED'] = "/proc/1/root/%s" % lxcpath
|
||||
newenv['NESTED'] = "/proc/1/root/%s" % lxc.default_config_path
|
||||
sp = subprocess.Popen(attach, stderr=fd, stdout=subprocess.PIPE,
|
||||
env=newenv, universal_newlines=True)
|
||||
sp.wait()
|
||||
@ -201,10 +202,10 @@ for container_name in lxc.list_containers(config_path=lxcpath):
|
||||
entry['pid'] = str(container.init_pid)
|
||||
|
||||
# Get the IPs
|
||||
for protocol in ('ipv4', 'ipv6'):
|
||||
for family, protocol in {'inet': 'ipv4', 'inet6': 'ipv6'}.items():
|
||||
if protocol in args.fancy_format or args.nesting:
|
||||
entry[protocol] = "-"
|
||||
ips = container.get_ips(protocol=protocol, timeout=1)
|
||||
ips = container.get_ips(family=family)
|
||||
if ips:
|
||||
entry[protocol] = ", ".join(ips)
|
||||
|
||||
|
@ -15,10 +15,12 @@
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
. @DATADIR@/lxc/lxc.functions
|
||||
|
||||
usage() {
|
||||
echo "usage: $(basename $0) -n|--name <name> -- [netstat_options]" >&2
|
||||
echo "usage: $(basename $0) -n|--name <name> [-P|--lxcpath <lxc_path>] -- [netstat_options]" >&2
|
||||
}
|
||||
|
||||
help() {
|
||||
@ -26,8 +28,9 @@ help() {
|
||||
echo >&2
|
||||
echo "Execute 'netstat' for the specified container." >&2
|
||||
echo >&2
|
||||
echo " --name NAME specify the container name" >&2
|
||||
echo " NETSTAT_OPTIONS netstat command options (see \`netstat --help')" >&2
|
||||
echo " --name NAME specify the container name" >&2
|
||||
echo " --lxcpath LXC_PATH use an alternate container path" >&2
|
||||
echo " NETSTAT_OPTIONS netstat command options (see \`netstat --help')" >&2
|
||||
}
|
||||
|
||||
get_parent_cgroup()
|
||||
@ -71,8 +74,20 @@ while true; do
|
||||
case $1 in
|
||||
-h|--help)
|
||||
help; exit 1;;
|
||||
-n|--name)
|
||||
-n)
|
||||
# If we already have a value for $name, treat -n as being an
|
||||
# argument for netstat
|
||||
if [ -n "$name" ]
|
||||
then
|
||||
break
|
||||
else
|
||||
name="$2"; shift 2;
|
||||
fi
|
||||
;;
|
||||
--name)
|
||||
name=$2; shift 2;;
|
||||
-P|--lxcpath)
|
||||
lxc_path="$2"; shift 2;;
|
||||
--exec)
|
||||
exec="exec"; shift;;
|
||||
--)
|
||||
@ -92,11 +107,17 @@ if [ -z "$name" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$exec" ]; then
|
||||
exec @BINDIR@/lxc-unshare -s MOUNT -- $0 -n $name --exec "$@"
|
||||
if [ -z "$lxc_path" ]; then
|
||||
echo "$(basename $0): no configuration path defined" >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if lxc-info -n $name --state-is 'STOPPED'; then
|
||||
if [ -z "$exec" ]; then
|
||||
exec @BINDIR@/lxc-unshare -s MOUNT -- $0 -n $name -P "$lxc_path" --exec -- "$@"
|
||||
fi
|
||||
|
||||
if lxc-info -n $name -P "$lxc_path" --state-is 'STOPPED'; then
|
||||
echo "$(basename $0): container '$name' is not running" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
@ -15,11 +15,13 @@
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
. @DATADIR@/lxc/lxc.functions
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "usage: $(basename $0) [--lxc | --host | --name NAME] [--] [PS_OPTIONS...]" >&2
|
||||
echo "usage: $(basename $0) [-P PATH] [--lxc | --host | --name NAME] [[--] [PS_OPTIONS...]" >&2
|
||||
}
|
||||
|
||||
help() {
|
||||
@ -31,14 +33,16 @@ help() {
|
||||
echo " --host show processes not related to any container, i.e. to the host" >&2
|
||||
echo " --name NAME show processes in the specified container" >&2
|
||||
echo " (multiple containers can be separated by commas)" >&2
|
||||
echo " -P PATH show container in lxcpath PATH" >&2
|
||||
echo " PS_OPTIONS ps command options (see \`ps --help')" >&2
|
||||
}
|
||||
|
||||
get_parent_cgroup()
|
||||
{
|
||||
local hierarchies hierarchy fields subsystems init_cgroup mountpoint
|
||||
local hierarchies hierarchy fields init_cgroup mountpoint
|
||||
|
||||
parent_cgroup=""
|
||||
subsystems=""
|
||||
|
||||
# Obtain a list of hierarchies that contain one or more subsystems
|
||||
hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2)
|
||||
@ -62,11 +66,7 @@ get_parent_cgroup()
|
||||
if [ -z "$mountpoint" ]; then continue; fi
|
||||
|
||||
# Return the absolute path to the containers' parent cgroup
|
||||
# (do not append '/lxc' if the hierarchy contains the 'ns' subsystem)
|
||||
case ",$subsystems," in
|
||||
*,ns,*) parent_cgroup="${mountpoint}${init_cgroup%/}";;
|
||||
*) parent_cgroup="${mountpoint}${init_cgroup%/}/lxc";;
|
||||
esac
|
||||
parent_cgroup="${mountpoint}${init_cgroup%/}";
|
||||
break
|
||||
done
|
||||
}
|
||||
@ -83,6 +83,8 @@ while true; do
|
||||
list_container_processes=1; shift;;
|
||||
--host)
|
||||
list_container_processes=-1; shift;;
|
||||
-P|--lxcpath)
|
||||
lxc_path=$2; shift 2;;
|
||||
--)
|
||||
shift; break;;
|
||||
*)
|
||||
@ -101,7 +103,10 @@ if [ ! -d "$parent_cgroup" ]; then
|
||||
fi
|
||||
|
||||
if [ -z "$containers" ]; then
|
||||
containers="$(find $parent_cgroup -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed 's:.*/::')"
|
||||
case ",$subsystems," in
|
||||
*,ns,*) containers="$(find $parent_cgroup -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed 's:.*/::')";;
|
||||
*) containers="$(find $parent_cgroup/lxc -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed 's:.*/::')";;
|
||||
esac
|
||||
fi
|
||||
|
||||
container_field_width=9
|
||||
@ -111,8 +116,12 @@ for container in ${containers}; do
|
||||
container_field_width=${#container}
|
||||
fi
|
||||
|
||||
if [ -f "$parent_cgroup/$container/tasks" ]; then
|
||||
tasks_files="$tasks_files $parent_cgroup/$container/tasks"
|
||||
if ! lxc-info -P $lxc_path -t STOPPED -n $container; then
|
||||
initpid=`lxc-info -P $lxc_path -p -n $container | awk -F: '{ print $2 }' | awk '{ print $1 }'`
|
||||
cgroup=`head -n 1 /proc/$initpid/cgroup | awk -F: '{ print $3}'`
|
||||
if [ -f "$parent_cgroup/$cgroup/tasks" ]; then
|
||||
tasks_files="$tasks_files $parent_cgroup$cgroup/tasks"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user