pay attention to a few things:
1 - your code must follow the coding style rules
- 2 - the format of the submission must be email patches
+ 2 - the format of the submission must be email patches or github
+ pull requests
3 - your work must be signed
Submitting Modifications:
-------------------------
-The contributions should be email patches. The guidelines are the same
-as the patch submission for the Linux kernel except for the DCO which
-is defined below. The guidelines are defined in the
+The contributions should be email patches or github pull requests.
+The guidelines are the same as the patch submission for the Linux kernel
+except for the DCO which is defined below. The guidelines are defined in the
'SubmittingPatches' file, available in the directory 'Documentation'
of the Linux kernel source tree.
It can be accessed online too:
-http://lxr.linux.no/linux+v2.6.27/Documentation/SubmittingPatches
+https://www.kernel.org/doc/Documentation/SubmittingPatches
You can submit your patches to the lxc-devel@lists.linuxcontainers.org mailing
list. Use http://lists.linuxcontainers.org/listinfo/lxc-devel to subscribe
Signed-off-by: Random J Developer <random@developer.org>
+You can do it by using option -s or --signoff when you commit
+
+ git commit --signoff ...
+
using your real name (sorry, no pseudonyms or anonymous contributions.)
COMPREPLY=( $( compgen -W "$(ls /usr/local/share/lxc/templates/ | sed -e 's|^lxc-||' )" "$cur" ) )
}
- _lxc-generic-n() {
+ _lxc_generic_n() {
local cur prev
COMPREPLY=()
return 1
}
- _lxc-generic-ns() {
+ _lxc_generic_ns() {
local cur prev
COMPREPLY=()
return 1
}
- _lxc-generic-t() {
+ _lxc_generic_t() {
local cur prev
COMPREPLY=()
return 1
}
- _lxc-generic-o() {
+ _lxc_generic_o() {
local cur prev
COMPREPLY=()
return 1
}
- complete -o default -F _lxc-generic-n lxc-attach
- complete -o default -F _lxc-generic-n lxc-cgroup
- complete -o default -F _lxc-generic-n lxc-console
- complete -o default -F _lxc-generic-n lxc-destroy
- complete -o default -F _lxc-generic-n lxc-device
- complete -o default -F _lxc-generic-n lxc-execute
- complete -o default -F _lxc-generic-n lxc-freeze
- complete -o default -F _lxc-generic-n lxc-info
- complete -o default -F _lxc-generic-n lxc-monitor
- complete -o default -F _lxc-generic-n lxc-snapshot
- complete -o default -F _lxc-generic-n lxc-start
- complete -o default -F _lxc-generic-n lxc-stop
- complete -o default -F _lxc-generic-n lxc-unfreeze
-
- complete -o default -F _lxc-generic-ns lxc-wait
-
- complete -o default -F _lxc-generic-t lxc-create
-
- complete -o default -F _lxc-generic-o lxc-clone
- complete -o default -F _lxc-generic-o lxc-start-ephemeral
+ complete -o default -F _lxc_generic_n lxc-attach
+ complete -o default -F _lxc_generic_n lxc-cgroup
+ complete -o default -F _lxc_generic_n lxc-console
+ complete -o default -F _lxc_generic_n lxc-destroy
+ complete -o default -F _lxc_generic_n lxc-device
+ complete -o default -F _lxc_generic_n lxc-execute
+ complete -o default -F _lxc_generic_n lxc-freeze
+ complete -o default -F _lxc_generic_n lxc-info
+ complete -o default -F _lxc_generic_n lxc-monitor
+ complete -o default -F _lxc_generic_n lxc-snapshot
+ complete -o default -F _lxc_generic_n lxc-start
+ complete -o default -F _lxc_generic_n lxc-stop
+ complete -o default -F _lxc_generic_n lxc-unfreeze
+
+ complete -o default -F _lxc_generic_ns lxc-wait
+
+ complete -o default -F _lxc_generic_t lxc-create
+
+ complete -o default -F _lxc_generic_o lxc-clone
+ complete -o default -F _lxc_generic_o lxc-start-ephemeral
}
COMPREPLY=( $( compgen -W "$(ls @LXCTEMPLATEDIR@/ | sed -e 's|^lxc-||' )" "$cur" ) )
}
- _lxc-generic-n() {
+ _lxc_generic_n() {
local cur prev
COMPREPLY=()
return 1
}
- _lxc-generic-ns() {
+ _lxc_generic_ns() {
local cur prev
COMPREPLY=()
return 1
}
- _lxc-generic-t() {
+ _lxc_generic_t() {
local cur prev
COMPREPLY=()
return 1
}
- _lxc-generic-o() {
+ _lxc_generic_o() {
local cur prev
COMPREPLY=()
return 1
}
- complete -o default -F _lxc-generic-n lxc-attach
- complete -o default -F _lxc-generic-n lxc-cgroup
- complete -o default -F _lxc-generic-n lxc-console
- complete -o default -F _lxc-generic-n lxc-destroy
- complete -o default -F _lxc-generic-n lxc-device
- complete -o default -F _lxc-generic-n lxc-execute
- complete -o default -F _lxc-generic-n lxc-freeze
- complete -o default -F _lxc-generic-n lxc-info
- complete -o default -F _lxc-generic-n lxc-monitor
- complete -o default -F _lxc-generic-n lxc-snapshot
- complete -o default -F _lxc-generic-n lxc-start
- complete -o default -F _lxc-generic-n lxc-stop
- complete -o default -F _lxc-generic-n lxc-unfreeze
-
- complete -o default -F _lxc-generic-ns lxc-wait
-
- complete -o default -F _lxc-generic-t lxc-create
-
- complete -o default -F _lxc-generic-o lxc-clone
- complete -o default -F _lxc-generic-o lxc-start-ephemeral
+ complete -o default -F _lxc_generic_n lxc-attach
+ complete -o default -F _lxc_generic_n lxc-cgroup
+ complete -o default -F _lxc_generic_n lxc-console
+ complete -o default -F _lxc_generic_n lxc-destroy
+ complete -o default -F _lxc_generic_n lxc-device
+ complete -o default -F _lxc_generic_n lxc-execute
+ complete -o default -F _lxc_generic_n lxc-freeze
+ complete -o default -F _lxc_generic_n lxc-info
+ complete -o default -F _lxc_generic_n lxc-monitor
+ complete -o default -F _lxc_generic_n lxc-snapshot
+ complete -o default -F _lxc_generic_n lxc-start
+ complete -o default -F _lxc_generic_n lxc-stop
+ complete -o default -F _lxc_generic_n lxc-unfreeze
+
+ complete -o default -F _lxc_generic_ns lxc-wait
+
+ complete -o default -F _lxc_generic_t lxc-create
+
+ complete -o default -F _lxc_generic_o lxc-clone
+ complete -o default -F _lxc_generic_o lxc-start-ephemeral
}
if [ -n "$BOOTGROUPS" ]; then
BOOTGROUPS="-g $BOOTGROUPS"
fi
-
+ touch "$lockdir"/lxc
# Start containers
wait_for_bridge
# Start autoboot containers first then the NULL group "onboot,".
"$bindir"/lxc-autostart $OPTIONS $BOOTGROUPS
- touch "$lockdir"/lxc
+ rm -f "$lockdir"/lxc
;;
stop)
# delaying the system shutdown / reboot as much as we can since it's not
# parallelized... Even 5 second timout may be too long.
"$bindir"/lxc-autostart $STOPOPTS $SHUTDOWNDELAY
- rm -f "$lockdir"/lxc
;;
restart|reload|force-reload)
#!/bin/sh -
distrosysconfdir="@LXC_DISTRO_SYSCONF@"
-localstatedir="@LOCALSTATEDIR@"
varrun="@RUNTIME_PATH@/lxc"
+varlib="@LOCALSTATEDIR@/lib"
# These can be overridden in @LXC_DISTRO_SYSCONF@/lxc
# or in @LXC_DISTRO_SYSCONF@/lxc-net
LXC_DHCP_CONFILE=""
LXC_DOMAIN=""
+LXC_IPV6_ADDR=""
+LXC_IPV6_MASK=""
+LXC_IPV6_NETWORK=""
+LXC_IPV6_NAT="false"
+
[ ! -f $distrosysconfdir/lxc ] || . $distrosysconfdir/lxc
-if [ -d "$localstatedir"/lock/subsys ]; then
- lockdir="$localstatedir"/lock/subsys
-else
- lockdir="$localstatedir"/lock
-fi
+use_iptables_lock="-w"
+iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock=""
_netmask2cidr ()
{
}
ifdown() {
- which ip >/dev/null 2>&1
- if [ $? = 0 ]; then
- ip link set dev $1 down
- return
- fi
- which ifconfig >/dev/null 2>&1
- if [ $? = 0 ]; then
- ifconfig $1 down
- return
- fi
+ ip addr flush dev $1
+ ip link set dev $1 down
}
ifup() {
- which ip >/dev/null 2>&1
- if [ $? = 0 ]; then
- MASK=`_netmask2cidr ${LXC_NETMASK}`
- CIDR_ADDR="${LXC_ADDR}/${MASK}"
- ip addr add ${CIDR_ADDR} dev $1
- ip link set dev $1 up
- return
- fi
- which ifconfig >/dev/null 2>&1
- if [ $? = 0 ]; then
- ifconfig $1 $2 netmask $3 up
- return
- fi
+ MASK=`_netmask2cidr ${LXC_NETMASK}`
+ CIDR_ADDR="${LXC_ADDR}/${MASK}"
+ ip addr add ${CIDR_ADDR} dev $1
+ ip link set dev $1 up
}
start() {
- [ ! -f "${lockdir}"/lxc-net ] || { exit 0; }
-
[ "x$USE_LXC_BRIDGE" = "xtrue" ] || { exit 0; }
- use_iptables_lock="-w"
- iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock=""
- cleanup() {
- # dnsmasq failed to start, clean up the bridge
- iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT
- iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT
- iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 53 -j ACCEPT
- iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 53 -j ACCEPT
- iptables $use_iptables_lock -D FORWARD -i ${LXC_BRIDGE} -j ACCEPT
- iptables $use_iptables_lock -D FORWARD -o ${LXC_BRIDGE} -j ACCEPT
- iptables $use_iptables_lock -t nat -D POSTROUTING -s ${LXC_NETWORK} ! -d ${LXC_NETWORK} -j MASQUERADE || true
- iptables $use_iptables_lock -t mangle -D POSTROUTING -o ${LXC_BRIDGE} -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
- ifdown ${LXC_BRIDGE}
- brctl delbr ${LXC_BRIDGE} || true
- }
+ [ ! -f "${varrun}/network_up" ] || { echo "lxc-net is already running"; exit 1; }
if [ -d /sys/class/net/${LXC_BRIDGE} ]; then
- exit 0;
+ stop force || true
fi
+ FAILED=1
+
+ cleanup() {
+ set +e
+ if [ "$FAILED" = "1" ]; then
+ echo "Failed to setup lxc-net." >&2
+ stop force
+ fi
+ }
+
+ trap cleanup EXIT HUP INT TERM
+ set -e
+
# set up the lxc network
- brctl addbr ${LXC_BRIDGE} || { echo "Missing bridge support in kernel"; stop; exit 0; }
+ [ ! -d /sys/class/net/${LXC_BRIDGE} ] && ip link add dev ${LXC_BRIDGE} type bridge
echo 1 > /proc/sys/net/ipv4/ip_forward
+ echo 0 > /proc/sys/net/ipv6/conf/${LXC_BRIDGE}/accept_dad || true
# if we are run from systemd on a system with selinux enabled,
# the mkdir will create /run/lxc as init_var_run_t which dnsmasq
# can't write its pid into, so we restorecon it (to var_run_t)
if [ ! -d "${varrun}" ]; then
mkdir -p "${varrun}"
- which restorecon >/dev/null 2>&1
- if [ $? = 0 ]; then
+ if which restorecon >/dev/null 2>&1; then
restorecon "${varrun}"
fi
fi
ifup ${LXC_BRIDGE} ${LXC_ADDR} ${LXC_NETMASK}
+
+ LXC_IPV6_ARG=""
+ if [ -n "$LXC_IPV6_ADDR" ] && [ -n "$LXC_IPV6_MASK" ] && [ -n "$LXC_IPV6_NETWORK" ]; then
+ echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
+ echo 0 > /proc/sys/net/ipv6/conf/${LXC_BRIDGE}/autoconf
+ ip -6 addr add dev ${LXC_BRIDGE} ${LXC_IPV6_ADDR}/${LXC_IPV6_MASK}
+ if [ "$LXC_IPV6_NAT" = "true" ]; then
+ ip6tables $use_iptables_lock -t nat -A POSTROUTING -s ${LXC_IPV6_NETWORK} ! -d ${LXC_IPV6_NETWORK} -j MASQUERADE
+ fi
+ LXC_IPV6_ARG="--dhcp-range=${LXC_IPV6_ADDR},ra-only --listen-address ${LXC_IPV6_ADDR}"
+ fi
iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT
iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT
iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p udp --dport 53 -j ACCEPT
LXC_DOMAIN_ARG="-s $LXC_DOMAIN -S /$LXC_DOMAIN/"
fi
+ LXD_DHCP_CONFILE_ARG=""
+ if [ -n "$LXC_DHCP_CONFILE" ]; then
+ LXC_DHCP_CONFILE_ARG="--conf-file=${LXC_DHCP_CONFILE}"
+ fi
+
# https://lists.linuxcontainers.org/pipermail/lxc-devel/2014-October/010561.html
for DNSMASQ_USER in lxc-dnsmasq dnsmasq nobody
do
break
fi
done
- dnsmasq $LXC_DOMAIN_ARG -u ${DNSMASQ_USER} --strict-order --bind-interfaces --pid-file="${varrun}"/dnsmasq.pid --conf-file=${LXC_DHCP_CONFILE} --listen-address ${LXC_ADDR} --dhcp-range ${LXC_DHCP_RANGE} --dhcp-lease-max=${LXC_DHCP_MAX} --dhcp-no-override --except-interface=lo --interface=${LXC_BRIDGE} --dhcp-leasefile=/var/lib/misc/dnsmasq.${LXC_BRIDGE}.leases --dhcp-authoritative || cleanup
+
+ dnsmasq $LXC_DHCP_CONFILE_ARG $LXC_DOMAIN_ARG -u ${DNSMASQ_USER} --strict-order --bind-interfaces --pid-file="${varrun}"/dnsmasq.pid --listen-address ${LXC_ADDR} --dhcp-range ${LXC_DHCP_RANGE} --dhcp-lease-max=${LXC_DHCP_MAX} --dhcp-no-override --except-interface=lo --interface=${LXC_BRIDGE} --dhcp-leasefile="${varlib}"/misc/dnsmasq.${LXC_BRIDGE}.leases --dhcp-authoritative $LXC_IPV6_ARG || cleanup
+
touch "${varrun}"/network_up
- touch "${lockdir}"/lxc-net
+ FAILED=0
}
stop() {
[ "x$USE_LXC_BRIDGE" = "xtrue" ] || { exit 0; }
- [ -f "${varrun}/network_up" ] || { exit 0; }
- # if $LXC_BRIDGE has attached interfaces, don't shut it down
- ls /sys/class/net/${LXC_BRIDGE}/brif/* > /dev/null 2>&1 && exit 0;
+ [ -f "${varrun}/network_up" ] || [ "$1" = "force" ] || { echo "lxc-net isn't running"; exit 1; }
if [ -d /sys/class/net/${LXC_BRIDGE} ]; then
- use_iptables_lock="-w"
- iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock=""
ifdown ${LXC_BRIDGE}
iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT
iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT
iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 53 -j ACCEPT
iptables $use_iptables_lock -D FORWARD -i ${LXC_BRIDGE} -j ACCEPT
iptables $use_iptables_lock -D FORWARD -o ${LXC_BRIDGE} -j ACCEPT
- iptables $use_iptables_lock -t nat -D POSTROUTING -s ${LXC_NETWORK} ! -d ${LXC_NETWORK} -j MASQUERADE || true
+ iptables $use_iptables_lock -t nat -D POSTROUTING -s ${LXC_NETWORK} ! -d ${LXC_NETWORK} -j MASQUERADE
iptables $use_iptables_lock -t mangle -D POSTROUTING -o ${LXC_BRIDGE} -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
- pid=`cat "${varrun}"/dnsmasq.pid 2>/dev/null` && kill -9 $pid || true
+
+ if [ "$LXC_IPV6_NAT" = "true" ]; then
+ ip6tables $use_iptables_lock -t nat -D POSTROUTING -s ${LXC_IPV6_NETWORK} ! -d ${LXC_IPV6_NETWORK} -j MASQUERADE
+ fi
+
+ pid=`cat "${varrun}"/dnsmasq.pid 2>/dev/null` && kill -9 $pid
rm -f "${varrun}"/dnsmasq.pid
- brctl delbr ${LXC_BRIDGE}
+ # if $LXC_BRIDGE has attached interfaces, don't destroy the bridge
+ ls /sys/class/net/${LXC_BRIDGE}/brif/* > /dev/null 2>&1 || ip link delete ${LXC_BRIDGE}
fi
+
rm -f "${varrun}"/network_up
- rm -f "${lockdir}"/lxc-net
}
# See how we were called.
# don't load profiles if mount mediation is not supported
SYSF=/sys/kernel/security/apparmor/features/mount/mask
if [ -f $SYSF ]; then
- if [ -x /lib/init/apparmor-profile-load ]; then
- /lib/init/apparmor-profile-load usr.bin.lxc-start
- /lib/init/apparmor-profile-load lxc-containers
+ if [ -x /lib/apparmor/profile-load ]; then
+ /lib/apparmor/profile-load usr.bin.lxc-start
+ /lib/apparmor/profile-load lxc-containers
fi
fi
[Unit]
Description=LXC Container Initialization and Autoboot Code
-After=syslog.target network.target
+After=syslog.target network.target lxc-net.service
Wants=lxc-net.service
[Service]
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-@INIT_SCRIPT_UPSTART_FALSE@install-data-local:
@INIT_SCRIPT_UPSTART_FALSE@uninstall-local:
+@INIT_SCRIPT_UPSTART_FALSE@install-data-local:
clean: clean-am
clean-am: clean-generic mostlyclean-am
# don't load profiles if mount mediation is not supported
SYSF=/sys/kernel/security/apparmor/features/mount/mask
if [ -f $SYSF ]; then
- if [ -x /lib/init/apparmor-profile-load ]; then
- /lib/init/apparmor-profile-load usr.bin.lxc-start
- /lib/init/apparmor-profile-load lxc-containers
+ if [ -x /lib/apparmor/profile-load ]; then
+ /lib/apparmor/profile-load usr.bin.lxc-start
+ /lib/apparmor/profile-load lxc-containers
fi
fi
# lxc.cap.drop = setuid # breaks sshd,nfs statd
# lxc.cap.drop = audit_control # breaks sshd (set_loginuid failed)
# lxc.cap.drop = audit_write
-lxc.cap.drop = setfcap setpcap sys_nice sys_pacct sys_rawio
+lxc.cap.drop = sys_nice sys_pacct sys_rawio
# Container user ? see gentoo.common.conf
# do not mount sysfs, see http://blog.bofh.it/debian/id_413
-lxc.mount.entry=mqueue dev/mqueue mqueue rw,nodev,noexec,nosuid 0 0
-lxc.mount.entry=shm dev/shm tmpfs rw,nosuid,nodev,noexec,relatime 0 0
+lxc.mount.entry=mqueue dev/mqueue mqueue rw,nodev,noexec,nosuid,create=dir 0 0
+lxc.mount.entry=shm dev/shm tmpfs rw,nosuid,nodev,noexec,relatime,create=dir 0 0
lxc.mount.entry=run run tmpfs rw,nosuid,nodev,relatime,mode=755 0 0
-# this part is based on 'linux capabilities', see: man 7 capabilities
-# eg: you may also wish to drop 'cap_net_raw' (though it breaks ping)
+# Capabilities
+# Uncomment these if you don't run anything that needs the capability, and
+# would like the container to run with less privilege.
#
+# Dropping sys_admin disables container root from doing a lot of things
+# that could be bad like re-mounting lxc fstab entries rw for example,
+# but also disables some useful things like being able to nfs mount, and
+# things that are already namespaced with ns_capable() kernel checks, like
+# hostname(1).
+# lxc.cap.drop = sys_admin # breaks systemd
+# lxc.cap.drop = net_raw # breaks dhcp/ping
+# lxc.cap.drop = setgid # breaks login (initgroups/setgroups)
+# lxc.cap.drop = dac_read_search # breaks login (pam unix_chkpwd)
+# lxc.cap.drop = setuid # breaks sshd,nfs statd
+# lxc.cap.drop = audit_control # breaks sshd (set_loginuid failed)
+# lxc.cap.drop = audit_write
+# lxc.cap.drop = setpcap # breaks journald
+# lxc.cap.drop = sys_resources # breaks systemd
+lxc.cap.drop = audit_control audit_write dac_read_search fsetid ipc_owner linux_immutable mknod setfcap setpcap sys_admin sys_boot sys_nice sys_pacct sys_ptrace sys_rawio sys_resources sys_tty_config syslog
+
# WARNING: the security vulnerability reported for 'cap_net_admin' at
# http://mainisusuallyafunction.blogspot.com/2012/11/attacking-hardened-linux-systems-with.html
# via JIT spraying (the BPF JIT module disabled on most systems was used
# including the kernel - and multiple layers of security on any system
# where security is a priority. note that not only LXC but PAX (and
# others?) were vulnerable to this issue.
-#
-# conservative: lxc.cap.drop = sys_module mknod mac_override sys_boot
-# aggressive follows. (leaves open: chown dac_override fowner ipc_lock kill lease net_admin net_bind_service net_broadcast net_raw setgid setuid sys_chroot)
-
-lxc.cap.drop = audit_control audit_write dac_read_search fsetid ipc_owner linux_immutable mknod setfcap sys_admin sys_boot sys_pacct sys_ptrace sys_rawio sys_resource sys_tty_config syslog
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for lxc 1.1.2.
+# Generated by GNU Autoconf 2.69 for lxc 1.1.3.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
# Identity of this package.
PACKAGE_NAME='lxc'
PACKAGE_TARNAME='lxc'
-PACKAGE_VERSION='1.1.2'
-PACKAGE_STRING='lxc 1.1.2'
+PACKAGE_VERSION='1.1.3'
+PACKAGE_STRING='lxc 1.1.3'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures lxc 1.1.2 to adapt to many kinds of systems.
+\`configure' configures lxc 1.1.3 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of lxc 1.1.2:";;
+ short | recursive ) echo "Configuration of lxc 1.1.3:";;
esac
cat <<\_ACEOF
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-lxc configure 1.1.2
+lxc configure 1.1.3
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by lxc $as_me 1.1.2, which was
+It was created by lxc $as_me 1.1.3, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
fi
fi
-LXC_VERSION_BASE=1.1.2
+LXC_VERSION_BASE=1.1.3
LXC_VERSION_MINOR=1
-LXC_VERSION_MICRO=2
+LXC_VERSION_MICRO=3
-LXC_VERSION=1.1.2
+LXC_VERSION=1.1.3
# Define the identity of the package.
PACKAGE='lxc'
- VERSION='1.1.2'
+ VERSION='1.1.3'
cat >>confdefs.h <<_ACEOF
$as_echo "no" >&6; }
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cgmanager_list_controllers" >&5
+$as_echo_n "checking for cgmanager_list_controllers... " >&6; }
+save_LIBS=$LIBS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing cgmanager_list_controllers_sync" >&5
+$as_echo_n "checking for library containing cgmanager_list_controllers_sync... " >&6; }
+if ${ac_cv_search_cgmanager_list_controllers_sync+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cgmanager_list_controllers_sync ();
+int
+main ()
+{
+return cgmanager_list_controllers_sync ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' cgmanager; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib -lnih -lnih-dbus -ldbus-1 $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_cgmanager_list_controllers_sync=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_cgmanager_list_controllers_sync+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_cgmanager_list_controllers_sync+:} false; then :
+
+else
+ ac_cv_search_cgmanager_list_controllers_sync=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_cgmanager_list_controllers_sync" >&5
+$as_echo "$ac_cv_search_cgmanager_list_controllers_sync" >&6; }
+ac_res=$ac_cv_search_cgmanager_list_controllers_sync
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+ have_list_controllers=yes
+else
+ have_list_controllers=no
+fi
+
+LIBS=$save_LIBS
+if test "x$have_list_controllers" = "xyes"; then
+
+$as_echo "#define HAVE_CGMANAGER_LIST_CONTROLLERS 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
# Check for static libcap, make sure the function checked for differs from the
# the one checked below so the cache doesn't give a wrong answer
OLD_CFLAGS="$CFLAGS"
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by lxc $as_me 1.1.2, which was
+This file was extended by lxc $as_me 1.1.3, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-lxc config.status 1.1.2
+lxc config.status 1.1.3
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
m4_define([lxc_version_major], 1)
m4_define([lxc_version_minor], 1)
-m4_define([lxc_version_micro], 2)
+m4_define([lxc_version_micro], 3)
m4_define([lxc_version_beta], [])
m4_define([lxc_version_base], [lxc_version_major.lxc_version_minor.lxc_version_micro])
AC_MSG_RESULT([no])
fi
+AC_MSG_CHECKING(for cgmanager_list_controllers)
+save_LIBS=$LIBS
+AC_SEARCH_LIBS([cgmanager_list_controllers_sync], [cgmanager], [have_list_controllers=yes], [have_list_controllers=no], [-lnih -lnih-dbus -ldbus-1])
+LIBS=$save_LIBS
+if test "x$have_list_controllers" = "xyes"; then
+ AC_DEFINE([HAVE_CGMANAGER_LIST_CONTROLLERS], 1, [Have cgmanager_list_controllers])
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
+
# Check for static libcap, make sure the function checked for differs from the
# the one checked below so the cache doesn't give a wrong answer
OLD_CFLAGS="$CFLAGS"
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><option>--version</option></term>
+ <listitem>
+ <para>
+ Show the version number.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><option>--version</option></term>
+ <listitem>
+ <para>
+ <!--
+ Show the version number.
+ -->
+ バージョン番号を表示します。
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
<para>
<!--
Rather than performing the action, just print
- the container name.
+ the container name and wait delays until starting the next container.
-->
- 実際の動作は行わず、コンテナ名の表示だけを行います。
+ å®\9fé\9a\9bã\81®å\8b\95ä½\9cã\81¯è¡\8cã\82\8fã\81\9aã\80\81ã\82³ã\83³ã\83\86ã\83\8aå\90\8dã\81¨æ¬¡ã\81®ã\82³ã\83³ã\83\86ã\83\8aã\82\92é\96\8bå§\8bã\81\99ã\82\8bã\81¾ã\81§ã\81®é\96\93é\9a\94ã\81®è¡¨ç¤ºã\81 ã\81\91ã\82\92è¡\8cã\81\84ã\81¾ã\81\99ã\80\82
</para>
</listitem>
</varlistentry>
&seealso;
<refsect1>
- <title>Author</title>
+ <title><!-- Author -->作者</title>
<para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
</refsect1>
</refentry>
&seealso;
<refsect1>
- <title>Author</title>
+ <title><!-- Author -->作者</title>
<para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
</refsect1>
</refentry>
</refsynopsisdiv>
<refsect1>
- <title>Description</title>
+ <title><!-- Description -->説明</title>
<para>
<!--
<cmdsynopsis>
<command>lxc-ls</command>
<arg choice="opt">-1</arg>
+ <arg choice="opt">-P <replaceable>lxcpath</replaceable></arg>
<arg choice="opt">--active</arg>
<arg choice="opt">--frozen</arg>
<arg choice="opt">--running</arg>
<arg choice="opt">-g <replaceable>groups</replaceable></arg>
<arg choice="opt">--nesting</arg>
<arg choice="opt">filter</arg>
+ <arg choice="opt">--version</arg>
</cmdsynopsis>
</refsynopsisdiv>
</varlistentry>
<varlistentry>
+ <term>
+ <option><optional>-P</optional></option>
+ </term>
+ <listitem>
+ <para>
+ <!--
+ Use an alternate container path. The default is @LXCPATH@.
+ -->
+ デフォルトと別のコンテナパスを使用します。デフォルトは @LXCPATH@ です。
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>
<option><optional>--active</optional></option>
</term>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <option><optional>--version</optional></option>
+ </term>
+ <listitem>
+ <para>
+ <!--
+ Show the version number.
+ -->
+ バージョン番号を表示します。
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
&seealso;
<refsect1>
- <title>Author</title>
+ <title><!-- Author -->作者</title>
<para>Serge Hallyn <email>serge.hallyn@ubuntu.com </email></para>
</refsect1>
</refsect1>
- &commonoptions;
-
<refsect1>
<title>See Also</title>
</refsect1>
<refsect1>
- <title>Author</title>
+ <title><!-- Author -->作者</title>
<para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
</refsect1>
</refsect1>
<refsect1>
- <title>Author</title>
+ <title><!-- Author -->作者</title>
<para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
</refsect1>
&seealso;
<refsect1>
- <title>Author</title>
+ <title><!-- Author -->作者</title>
<para>Serge Hallyn <email>serge.hallyn@ubuntu.com</email></para>
</refsect1>
</refsect1>
<refsect1>
- <title>Author</title>
+ <title><!-- Author -->作者</title>
<para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
</refsect1>
</refentry>
containers.
-->
コンテナを追加したいコンテナグループ名を指定します。
- (複数回使用される可能性のある) 複数の値を設定可能です。
+ 複数の値を設定でき、複数回指定することもできます。
設定されたグループは、関連する一連のコンテナを起動させるために使われます。
</para>
</listitem>
&seealso;
<refsect1>
- <title>Author</title>
+ <title><!-- Author -->作者</title>
<para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
</refsect1>
</refentry>
<listitem>
<para>
Rather than performing the action, just print
- the container name.
+ the container name and wait delays until starting the next container.
</para>
</listitem>
</varlistentry>
<cmdsynopsis>
<command>lxc-ls</command>
<arg choice="opt">-1</arg>
+ <arg choice="opt">-P <replaceable>lxcpath</replaceable></arg>
<arg choice="opt">--active</arg>
<arg choice="opt">--frozen</arg>
<arg choice="opt">--running</arg>
<arg choice="opt">-g <replaceable>groups</replaceable></arg>
<arg choice="opt">--nesting</arg>
<arg choice="opt">filter</arg>
+ <arg choice="opt">--version</arg>
</cmdsynopsis>
</refsynopsisdiv>
<varlistentry>
<term>
+ <option><optional>-P</optional></option>
+ </term>
+ <listitem>
+ <para>
+ Use an alternate container path. The default is @LXCPATH@.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
<option><optional>--active</optional></option>
</term>
<listitem>
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>
+ <option><optional>--version</optional></option>
+ </term>
+ <listitem>
+ <para>
+ Show the version number.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
</refsect1>
- &commonoptions;
-
<refsect1>
<title>See Also</title>
%endif
Name: lxc
-Version: 1.1.2
+Version: 1.1.3
Release: %{?beta_rel:0.1.%{beta_rel}}%{?!beta_rel:%{norm_rel}}%{?dist}
URL: http://linuxcontainers.org
Source: http://linuxcontainers.org/downloads/%{name}-%{version}%{?beta_dot}.tar.gz
/* Have cgmanager_get_pid_cgroup_abs_sync */
#undef HAVE_CGMANAGER_GET_PID_CGROUP_ABS_SYNC
+/* Have cgmanager_list_controllers */
+#undef HAVE_CGMANAGER_LIST_CONTROLLERS
+
/* Define to 1 if you have the `confstr' function. */
#undef HAVE_CONFSTR
#endif
#if LUA_VERSION_NUM >= 503
+#ifndef luaL_checkunsigned
#define luaL_checkunsigned(L,n) ((lua_Unsigned)luaL_checkinteger(L,n))
#endif
+#endif
#ifdef NO_CHECK_UDATA
#define checkudata(L,i,tname) lua_touserdata(L, i)
conf.h \
console.h \
error.h \
+ initutils.h \
list.h \
log.h \
lxc.h \
namespace.h \
start.h \
state.h \
- utils.h
+ utils.h \
+ criu.h
if IS_BIONIC
noinst_HEADERS += \
cgfs.c \
cgroup.c cgroup.h \
lxc.h \
+ initutils.c initutils.h \
utils.c utils.h \
sync.c sync.h \
namespace.h namespace.c \
state.c state.h \
log.c log.h \
attach.c attach.h \
+ criu.c criu.h \
\
network.c network.h \
nl.c nl.h \
EXTRA_DIST = \
lxc-ls \
- lxc-restore-net \
lxc-top.lua
if ENABLE_PYTHON
if HAVE_STATIC_LIBCAP
sbin_PROGRAMS += init.lxc.static
-init_lxc_static_SOURCES = lxc_init.c error.c log.c utils.c caps.c
+init_lxc_static_SOURCES = lxc_init.c error.c log.c initutils.c caps.c
if !HAVE_GETLINE
if HAVE_FGETLN
install-exec-hook:
chmod u+s $(DESTDIR)$(libexecdir)/lxc/lxc-user-nic
-install-data-local:
- install -c -m 755 lxc-restore-net $(DESTDIR)$(datadir)/lxc
-
uninstall-local:
$(RM) $(DESTDIR)$(libdir)/liblxc.so*
init_lxc_OBJECTS = $(am_init_lxc_OBJECTS)
init_lxc_LDADD = $(LDADD)
init_lxc_DEPENDENCIES = liblxc.so
-am__init_lxc_static_SOURCES_DIST = lxc_init.c error.c log.c utils.c \
- caps.c ../include/getline.c
+am__init_lxc_static_SOURCES_DIST = lxc_init.c error.c log.c \
+ initutils.c caps.c ../include/getline.c
am__dirstamp = $(am__leading_dot)dirstamp
@HAVE_FGETLN_TRUE@@HAVE_GETLINE_FALSE@@HAVE_STATIC_LIBCAP_TRUE@am__objects_1 = ../include/init_lxc_static-getline.$(OBJEXT)
@HAVE_STATIC_LIBCAP_TRUE@am_init_lxc_static_OBJECTS = \
@HAVE_STATIC_LIBCAP_TRUE@ init_lxc_static-lxc_init.$(OBJEXT) \
@HAVE_STATIC_LIBCAP_TRUE@ init_lxc_static-error.$(OBJEXT) \
@HAVE_STATIC_LIBCAP_TRUE@ init_lxc_static-log.$(OBJEXT) \
-@HAVE_STATIC_LIBCAP_TRUE@ init_lxc_static-utils.$(OBJEXT) \
+@HAVE_STATIC_LIBCAP_TRUE@ init_lxc_static-initutils.$(OBJEXT) \
@HAVE_STATIC_LIBCAP_TRUE@ init_lxc_static-caps.$(OBJEXT) \
@HAVE_STATIC_LIBCAP_TRUE@ $(am__objects_1)
init_lxc_static_OBJECTS = $(am_init_lxc_static_OBJECTS)
am__liblxc_so_SOURCES_DIST = arguments.c arguments.h bdev.c bdev.h \
lxc-btrfs.h commands.c commands.h start.c start.h execute.c \
monitor.c monitor.h console.c freezer.c error.h error.c \
- parse.c parse.h cgfs.c cgroup.c cgroup.h lxc.h utils.c utils.h \
- sync.c sync.h namespace.h namespace.c conf.c conf.h confile.c \
- confile.h list.h state.c state.h log.c log.h attach.c attach.h \
- network.c network.h nl.c nl.h rtnl.c rtnl.h genl.c genl.h \
- caps.c caps.h lxcseccomp.h mainloop.c mainloop.h af_unix.c \
- af_unix.h lxcutmp.c lxcutmp.h lxclock.h lxclock.c \
- lxccontainer.c lxccontainer.h version.h lsm/nop.c lsm/lsm.h \
- lsm/lsm.c lsm/apparmor.c lsm/selinux.c cgmanager.c \
- ../include/ifaddrs.c ../include/ifaddrs.h ../include/openpty.c \
- ../include/openpty.h ../include/lxcmntent.c \
- ../include/lxcmntent.h ../include/getline.c \
- ../include/getline.h seccomp.c
+ parse.c parse.h cgfs.c cgroup.c cgroup.h lxc.h initutils.c \
+ initutils.h utils.c utils.h sync.c sync.h namespace.h \
+ namespace.c conf.c conf.h confile.c confile.h list.h state.c \
+ state.h log.c log.h attach.c attach.h criu.c criu.h network.c \
+ network.h nl.c nl.h rtnl.c rtnl.h genl.c genl.h caps.c caps.h \
+ lxcseccomp.h mainloop.c mainloop.h af_unix.c af_unix.h \
+ lxcutmp.c lxcutmp.h lxclock.h lxclock.c lxccontainer.c \
+ lxccontainer.h version.h lsm/nop.c lsm/lsm.h lsm/lsm.c \
+ lsm/apparmor.c lsm/selinux.c cgmanager.c ../include/ifaddrs.c \
+ ../include/ifaddrs.h ../include/openpty.c ../include/openpty.h \
+ ../include/lxcmntent.c ../include/lxcmntent.h \
+ ../include/getline.c ../include/getline.h seccomp.c
@ENABLE_APPARMOR_TRUE@am__objects_2 = \
@ENABLE_APPARMOR_TRUE@ lsm/liblxc_so-apparmor.$(OBJEXT)
@ENABLE_SELINUX_TRUE@am__objects_3 = lsm/liblxc_so-selinux.$(OBJEXT)
liblxc_so-monitor.$(OBJEXT) liblxc_so-console.$(OBJEXT) \
liblxc_so-freezer.$(OBJEXT) liblxc_so-error.$(OBJEXT) \
liblxc_so-parse.$(OBJEXT) liblxc_so-cgfs.$(OBJEXT) \
- liblxc_so-cgroup.$(OBJEXT) liblxc_so-utils.$(OBJEXT) \
- liblxc_so-sync.$(OBJEXT) liblxc_so-namespace.$(OBJEXT) \
- liblxc_so-conf.$(OBJEXT) liblxc_so-confile.$(OBJEXT) \
- liblxc_so-state.$(OBJEXT) liblxc_so-log.$(OBJEXT) \
- liblxc_so-attach.$(OBJEXT) liblxc_so-network.$(OBJEXT) \
+ liblxc_so-cgroup.$(OBJEXT) liblxc_so-initutils.$(OBJEXT) \
+ liblxc_so-utils.$(OBJEXT) liblxc_so-sync.$(OBJEXT) \
+ liblxc_so-namespace.$(OBJEXT) liblxc_so-conf.$(OBJEXT) \
+ liblxc_so-confile.$(OBJEXT) liblxc_so-state.$(OBJEXT) \
+ liblxc_so-log.$(OBJEXT) liblxc_so-attach.$(OBJEXT) \
+ liblxc_so-criu.$(OBJEXT) liblxc_so-network.$(OBJEXT) \
liblxc_so-nl.$(OBJEXT) liblxc_so-rtnl.$(OBJEXT) \
liblxc_so-genl.$(OBJEXT) liblxc_so-caps.$(OBJEXT) \
liblxc_so-mainloop.$(OBJEXT) liblxc_so-af_unix.$(OBJEXT) \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__noinst_HEADERS_DIST = arguments.h attach.h bdev.h caps.h cgroup.h \
- conf.h console.h error.h list.h log.h lxc.h lxc-btrfs.h \
- lxclock.h monitor.h namespace.h start.h state.h utils.h \
- ../include/ifaddrs.h ../include/openpty.h \
+ conf.h console.h error.h initutils.h list.h log.h lxc.h \
+ lxc-btrfs.h lxclock.h monitor.h namespace.h start.h state.h \
+ utils.h criu.h ../include/ifaddrs.h ../include/openpty.h \
../include/lxcmntent.h ../include/getline.h
HEADERS = $(noinst_HEADERS) $(pkginclude_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
version.h
noinst_HEADERS = arguments.h attach.h bdev.h caps.h cgroup.h conf.h \
- console.h error.h list.h log.h lxc.h lxc-btrfs.h lxclock.h \
- monitor.h namespace.h start.h state.h utils.h $(am__append_1) \
- $(am__append_2)
+ console.h error.h initutils.h list.h log.h lxc.h lxc-btrfs.h \
+ lxclock.h monitor.h namespace.h start.h state.h utils.h criu.h \
+ $(am__append_1) $(am__append_2)
sodir = $(libdir)
LSM_SOURCES = lsm/nop.c lsm/lsm.h lsm/lsm.c $(am__append_3) \
$(am__append_4)
liblxc_so_SOURCES = arguments.c arguments.h bdev.c bdev.h lxc-btrfs.h \
commands.c commands.h start.c start.h execute.c monitor.c \
monitor.h console.c freezer.c error.h error.c parse.c parse.h \
- cgfs.c cgroup.c cgroup.h lxc.h utils.c utils.h sync.c sync.h \
- namespace.h namespace.c conf.c conf.h confile.c confile.h \
- list.h state.c state.h log.c log.h attach.c attach.h network.c \
- network.h nl.c nl.h rtnl.c rtnl.h genl.c genl.h caps.c caps.h \
- lxcseccomp.h mainloop.c mainloop.h af_unix.c af_unix.h \
- lxcutmp.c lxcutmp.h lxclock.h lxclock.c lxccontainer.c \
- lxccontainer.h version.h $(LSM_SOURCES) $(am__append_5) \
- $(am__append_6) $(am__append_7) $(am__append_13)
+ cgfs.c cgroup.c cgroup.h lxc.h initutils.c initutils.h utils.c \
+ utils.h sync.c sync.h namespace.h namespace.c conf.c conf.h \
+ confile.c confile.h list.h state.c state.h log.c log.h \
+ attach.c attach.h criu.c criu.h network.c network.h nl.c nl.h \
+ rtnl.c rtnl.h genl.c genl.h caps.c caps.h lxcseccomp.h \
+ mainloop.c mainloop.h af_unix.c af_unix.h lxcutmp.c lxcutmp.h \
+ lxclock.h lxclock.c lxccontainer.c lxccontainer.h version.h \
+ $(LSM_SOURCES) $(am__append_5) $(am__append_6) $(am__append_7) \
+ $(am__append_13)
AM_CFLAGS = -I$(top_srcdir)/src -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
-DLXCPATH=\"$(LXCPATH)\" \
-DLXC_GLOBAL_CONF=\"$(LXC_GLOBAL_CONF)\" \
bin_SCRIPTS = lxc-checkconfig $(am__append_16) $(am__append_17)
EXTRA_DIST = \
lxc-ls \
- lxc-restore-net \
lxc-top.lua
AM_LDFLAGS = -Wl,-E $(am__append_18)
lxc_user_nic_SOURCES = lxc_user_nic.c network.c network.h
lxc_checkpoint_SOURCES = lxc_checkpoint.c
@HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_SOURCES = lxc_init.c error.c \
-@HAVE_STATIC_LIBCAP_TRUE@ log.c utils.c caps.c $(am__append_20)
+@HAVE_STATIC_LIBCAP_TRUE@ log.c initutils.c caps.c \
+@HAVE_STATIC_LIBCAP_TRUE@ $(am__append_20)
@HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_LDFLAGS = -static
@HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_LDADD = @CAP_LIBS@
@HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_CFLAGS = $(AM_CFLAGS) -DNO_LXC_CONF
@AMDEP_TRUE@@am__include@ @am__quote@../include/$(DEPDIR)/liblxc_so-openpty.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init_lxc_static-caps.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init_lxc_static-error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init_lxc_static-initutils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init_lxc_static-log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init_lxc_static-lxc_init.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init_lxc_static-utils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-af_unix.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-arguments.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-attach.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-conf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-confile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-console.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-criu.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-error.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-execute.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-freezer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-genl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-initutils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-lxccontainer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-lxclock.Po@am__quote@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-log.obj `if test -f 'log.c'; then $(CYGPATH_W) 'log.c'; else $(CYGPATH_W) '$(srcdir)/log.c'; fi`
-init_lxc_static-utils.o: utils.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-utils.o -MD -MP -MF $(DEPDIR)/init_lxc_static-utils.Tpo -c -o init_lxc_static-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-utils.Tpo $(DEPDIR)/init_lxc_static-utils.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils.c' object='init_lxc_static-utils.o' libtool=no @AMDEPBACKSLASH@
+init_lxc_static-initutils.o: initutils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-initutils.o -MD -MP -MF $(DEPDIR)/init_lxc_static-initutils.Tpo -c -o init_lxc_static-initutils.o `test -f 'initutils.c' || echo '$(srcdir)/'`initutils.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-initutils.Tpo $(DEPDIR)/init_lxc_static-initutils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='initutils.c' object='init_lxc_static-initutils.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-initutils.o `test -f 'initutils.c' || echo '$(srcdir)/'`initutils.c
-init_lxc_static-utils.obj: utils.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-utils.obj -MD -MP -MF $(DEPDIR)/init_lxc_static-utils.Tpo -c -o init_lxc_static-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi`
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-utils.Tpo $(DEPDIR)/init_lxc_static-utils.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils.c' object='init_lxc_static-utils.obj' libtool=no @AMDEPBACKSLASH@
+init_lxc_static-initutils.obj: initutils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-initutils.obj -MD -MP -MF $(DEPDIR)/init_lxc_static-initutils.Tpo -c -o init_lxc_static-initutils.obj `if test -f 'initutils.c'; then $(CYGPATH_W) 'initutils.c'; else $(CYGPATH_W) '$(srcdir)/initutils.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/init_lxc_static-initutils.Tpo $(DEPDIR)/init_lxc_static-initutils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='initutils.c' object='init_lxc_static-initutils.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -c -o init_lxc_static-initutils.obj `if test -f 'initutils.c'; then $(CYGPATH_W) 'initutils.c'; else $(CYGPATH_W) '$(srcdir)/initutils.c'; fi`
init_lxc_static-caps.o: caps.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(init_lxc_static_CFLAGS) $(CFLAGS) -MT init_lxc_static-caps.o -MD -MP -MF $(DEPDIR)/init_lxc_static-caps.Tpo -c -o init_lxc_static-caps.o `test -f 'caps.c' || echo '$(srcdir)/'`caps.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-cgroup.obj `if test -f 'cgroup.c'; then $(CYGPATH_W) 'cgroup.c'; else $(CYGPATH_W) '$(srcdir)/cgroup.c'; fi`
+liblxc_so-initutils.o: initutils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-initutils.o -MD -MP -MF $(DEPDIR)/liblxc_so-initutils.Tpo -c -o liblxc_so-initutils.o `test -f 'initutils.c' || echo '$(srcdir)/'`initutils.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-initutils.Tpo $(DEPDIR)/liblxc_so-initutils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='initutils.c' object='liblxc_so-initutils.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-initutils.o `test -f 'initutils.c' || echo '$(srcdir)/'`initutils.c
+
+liblxc_so-initutils.obj: initutils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-initutils.obj -MD -MP -MF $(DEPDIR)/liblxc_so-initutils.Tpo -c -o liblxc_so-initutils.obj `if test -f 'initutils.c'; then $(CYGPATH_W) 'initutils.c'; else $(CYGPATH_W) '$(srcdir)/initutils.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-initutils.Tpo $(DEPDIR)/liblxc_so-initutils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='initutils.c' object='liblxc_so-initutils.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-initutils.obj `if test -f 'initutils.c'; then $(CYGPATH_W) 'initutils.c'; else $(CYGPATH_W) '$(srcdir)/initutils.c'; fi`
+
liblxc_so-utils.o: utils.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-utils.o -MD -MP -MF $(DEPDIR)/liblxc_so-utils.Tpo -c -o liblxc_so-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-utils.Tpo $(DEPDIR)/liblxc_so-utils.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-attach.obj `if test -f 'attach.c'; then $(CYGPATH_W) 'attach.c'; else $(CYGPATH_W) '$(srcdir)/attach.c'; fi`
+liblxc_so-criu.o: criu.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-criu.o -MD -MP -MF $(DEPDIR)/liblxc_so-criu.Tpo -c -o liblxc_so-criu.o `test -f 'criu.c' || echo '$(srcdir)/'`criu.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-criu.Tpo $(DEPDIR)/liblxc_so-criu.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='criu.c' object='liblxc_so-criu.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-criu.o `test -f 'criu.c' || echo '$(srcdir)/'`criu.c
+
+liblxc_so-criu.obj: criu.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-criu.obj -MD -MP -MF $(DEPDIR)/liblxc_so-criu.Tpo -c -o liblxc_so-criu.obj `if test -f 'criu.c'; then $(CYGPATH_W) 'criu.c'; else $(CYGPATH_W) '$(srcdir)/criu.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-criu.Tpo $(DEPDIR)/liblxc_so-criu.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='criu.c' object='liblxc_so-criu.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-criu.obj `if test -f 'criu.c'; then $(CYGPATH_W) 'criu.c'; else $(CYGPATH_W) '$(srcdir)/criu.c'; fi`
+
liblxc_so-network.o: network.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-network.o -MD -MP -MF $(DEPDIR)/liblxc_so-network.Tpo -c -o liblxc_so-network.o `test -f 'network.c' || echo '$(srcdir)/'`network.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-network.Tpo $(DEPDIR)/liblxc_so-network.Po
info-am:
-install-data-am: install-data-local install-pkgincludeHEADERS \
- install-soPROGRAMS
+install-data-am: install-pkgincludeHEADERS install-soPROGRAMS
install-dvi: install-dvi-am
ctags-am distclean distclean-compile distclean-generic \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-binPROGRAMS install-binSCRIPTS \
- install-data install-data-am install-data-local install-dvi \
- install-dvi-am install-exec install-exec-am install-exec-hook \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-exec-hook \
install-exec-local install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-pkgincludeHEADERS install-pkglibexecPROGRAMS \
install-exec-hook:
chmod u+s $(DESTDIR)$(libexecdir)/lxc/lxc-user-nic
-install-data-local:
- install -c -m 755 lxc-restore-net $(DESTDIR)$(datadir)/lxc
-
uninstall-local:
$(RM) $(DESTDIR)$(libdir)/liblxc.so*
lxc_log_define(lxc_attach, lxc);
+int lsm_set_label_at(int procfd, int on_exec, char* lsm_label) {
+ int labelfd = -1;
+ int ret = 0;
+ const char* name;
+ char* command = NULL;
+
+ name = lsm_name();
+
+ if (strcmp(name, "nop") == 0)
+ goto out;
+
+ if (strcmp(name, "none") == 0)
+ goto out;
+
+ /* We don't support on-exec with AppArmor */
+ if (strcmp(name, "AppArmor") == 0)
+ on_exec = 0;
+
+ if (on_exec) {
+ labelfd = openat(procfd, "self/attr/exec", O_RDWR);
+ }
+ else {
+ labelfd = openat(procfd, "self/attr/current", O_RDWR);
+ }
+
+ if (labelfd < 0) {
+ SYSERROR("Unable to open LSM label");
+ ret = -1;
+ goto out;
+ }
+
+ if (strcmp(name, "AppArmor") == 0) {
+ int size;
+
+ command = malloc(strlen(lsm_label) + strlen("changeprofile ") + 1);
+ if (!command) {
+ SYSERROR("Failed to write apparmor profile");
+ ret = -1;
+ goto out;
+ }
+
+ size = sprintf(command, "changeprofile %s", lsm_label);
+ if (size < 0) {
+ SYSERROR("Failed to write apparmor profile");
+ ret = -1;
+ goto out;
+ }
+
+ if (write(labelfd, command, size + 1) < 0) {
+ SYSERROR("Unable to set LSM label");
+ ret = -1;
+ goto out;
+ }
+ }
+ else if (strcmp(name, "SELinux") == 0) {
+ if (write(labelfd, lsm_label, strlen(lsm_label) + 1) < 0) {
+ SYSERROR("Unable to set LSM label");
+ ret = -1;
+ goto out;
+ }
+ }
+ else {
+ ERROR("Unable to restore label for unknown LSM: %s", name);
+ ret = -1;
+ goto out;
+ }
+
+out:
+ free(command);
+
+ if (labelfd != -1)
+ close(labelfd);
+
+ return ret;
+}
+
static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
{
struct lxc_proc_context_info *info = calloc(1, sizeof(*info));
struct lxc_proc_context_info* init_ctx;
lxc_attach_exec_t exec_function;
void* exec_payload;
+ int procfd;
};
static int attach_child_main(void* data);
char* cwd;
char* new_cwd;
int ipc_sockets[2];
+ int procfd;
signed long personality;
if (!options)
rexit(-1);
}
+ procfd = open("/proc", O_DIRECTORY | O_RDONLY);
+ if (procfd < 0) {
+ SYSERROR("Unable to open /proc");
+ shutdown(ipc_sockets[1], SHUT_RDWR);
+ rexit(-1);
+ }
+
/* attach now, create another subprocess later, since pid namespaces
* only really affect the children of the current process
*/
.options = options,
.init_ctx = init_ctx,
.exec_function = exec_function,
- .exec_payload = exec_payload
+ .exec_payload = exec_payload,
+ .procfd = procfd
};
/* We use clone_parent here to make this subprocess a direct child of
* the initial process. Then this intermediate process can exit and
{
struct attach_clone_payload* payload = (struct attach_clone_payload*)data;
int ipc_socket = payload->ipc_socket;
+ int procfd = payload->procfd;
lxc_attach_options_t* options = payload->options;
struct lxc_proc_context_info* init_ctx = payload->init_ctx;
#if HAVE_SYS_PERSONALITY_H
close(ipc_socket);
/* set new apparmor profile/selinux context */
- if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM)) {
+ if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) {
int on_exec;
on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
- ret = lsm_process_label_set(init_ctx->lsm_label,
- init_ctx->container->lxc_conf, 0, on_exec);
- if (ret < 0) {
+ if (lsm_set_label_at(procfd, on_exec, init_ctx->lsm_label) < 0) {
rexit(-1);
}
}
}
}
+ /* we don't need proc anymore */
+ close(procfd);
+
/* we're done, so we can now do whatever the user intended us to do */
rexit(payload->exec_function(payload->exec_payload));
}
#define LO_FLAGS_AUTOCLEAR 4
#endif
+#ifndef LOOP_CTL_GET_FREE
+#define LOOP_CTL_GET_FREE 0x4C82
+#endif
+
#define DEFAULT_FS_SIZE 1073741824
#define DEFAULT_FSTYPE "ext3"
s[l-2] = '/';
s[l-1] = '\0';
- execlp("rsync", "rsync", "-a", s, dest, (char *)NULL);
+ execlp("rsync", "rsync", "-aHX", s, dest, (char *)NULL);
exit(1);
}
// If the file is not a block device, we don't want mkfs to ask
// us about whether to proceed.
- close(0);
- close(1);
- close(2);
- open("/dev/zero", O_RDONLY);
- open("/dev/null", O_RDWR);
- open("/dev/null", O_RDWR);
+ if (null_stdfds() < 0)
+ exit(1);
execlp("mkfs", "mkfs", "-t", fstype, path, NULL);
exit(1);
}
return 0;
}
-static bool is_btrfs_fs(const char *path)
+bool is_btrfs_fs(const char *path)
{
int fd, ret;
struct btrfs_ioctl_space_args sargs;
fd = open(newfull, O_RDONLY);
if (fd < 0) {
- ERROR("Error opening %s", newfull);
+ SYSERROR("Error opening %s", newfull);
free(newfull);
return -1;
}
return btrfs_do_destroy_subvol(path);
}
+bool btrfs_try_remove_subvol(const char *path)
+{
+ if (!btrfs_detect(path))
+ return false;
+ return btrfs_recursive_destroy(path) == 0;
+}
+
static int btrfs_destroy(struct bdev *orig)
{
return btrfs_recursive_destroy(orig->src);
return 0;
}
-static int find_free_loopdev(int *retfd, char *namep)
+static int find_free_loopdev_no_control(int *retfd, char *namep)
{
struct dirent dirent, *direntp;
struct loop_info64 lo;
return 0;
}
+static int find_free_loopdev(int *retfd, char *namep)
+{
+ int rc, fd = -1;
+ int ctl = open("/dev/loop-control", O_RDWR);
+ if (ctl < 0)
+ return find_free_loopdev_no_control(retfd, namep);
+ rc = ioctl(ctl, LOOP_CTL_GET_FREE);
+ if (rc >= 0) {
+ snprintf(namep, 100, "/dev/loop%d", rc);
+ fd = open(namep, O_RDWR);
+ }
+ close(ctl);
+ if (fd == -1) {
+ ERROR("No loop device found");
+ return -1;
+ }
+ *retfd = fd;
+ return 0;
+}
+
static int loop_mount(struct bdev *bdev)
{
int lfd, ffd = -1, ret = -1;
return -22;
}
+ if (mkdir_p(work, 0755) < 0 && errno != EEXIST) {
+ free(mntdata);
+ return -22;
+ }
+
// TODO We should check whether bdev->src is a blockdev, and if so
// but for now, only support overlays of a basic directory
//
static int aufs_mount(struct bdev *bdev)
{
- char *options, *dup, *lower, *upper, *rundir;
+ char *options, *dup, *lower, *upper;
int len;
unsigned long mntflags;
char *mntdata;
- char *runpath;
int ret;
+ const char *xinopath = "/dev/shm/aufs.xino";
if (strcmp(bdev->type, "aufs"))
return -22;
// TODO We should check whether bdev->src is a blockdev, and if so
// but for now, only support aufs of a basic directory
- rundir = get_rundir();
- if (!rundir)
- return -1;
-
- len = strlen(rundir) + strlen("/lxc") + 1;
- runpath = alloca(len);
- ret = snprintf(runpath, len, "%s/lxc", rundir);
- if (ret < 0 || ret >= len) {
- free(mntdata);
- free(rundir);
- return -1;
- }
- if (mkdir_p(runpath, 0755) < 0) {
- free(mntdata);
- free(rundir);
- return -1;
- }
-
// AUFS does not work on top of certain filesystems like (XFS or Btrfs)
- // so add xino=RUNDIR/lxc/aufs.xino parameter to mount options
+ // so add xino=/dev/shm/aufs.xino parameter to mount options.
+ // The same xino option can be specified to multiple aufs mounts, and
+ // a xino file is not shared among multiple aufs mounts.
//
// see http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg02587.html
+ // http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg05126.html
if (mntdata) {
- len = strlen(lower) + strlen(upper) + strlen(runpath) + strlen("br==rw:=ro,,xino=/aufs.xino") + strlen(mntdata) + 1;
+ len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,,xino=") + strlen(mntdata) + 1;
options = alloca(len);
- ret = snprintf(options, len, "br=%s=rw:%s=ro,%s,xino=%s/aufs.xino", upper, lower, mntdata, runpath);
+ ret = snprintf(options, len, "br=%s=rw:%s=ro,%s,xino=%s", upper, lower, mntdata, xinopath);
}
else {
- len = strlen(lower) + strlen(upper) + strlen(runpath) + strlen("br==rw:=ro,xino=/aufs.xino") + 1;
+ len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,xino=") + 1;
options = alloca(len);
- ret = snprintf(options, len, "br=%s=rw:%s=ro,xino=%s/aufs.xino", upper, lower, runpath);
+ ret = snprintf(options, len, "br=%s=rw:%s=ro,xino=%s", upper, lower, xinopath);
}
- free(rundir);
-
if (ret < 0 || ret >= len) {
free(mntdata);
return -1;
if (mkdir_p(new->dest, 0755) < 0)
return -1;
+ if (am_unpriv() && chown_mapped_root(new->dest, conf) < 0)
+ WARN("Failed to update ownership of %s", new->dest);
+
if (strcmp(orig->type, "dir") == 0) {
char *delta, *lastslash;
int ret, len, lastslashidx;
free(delta);
return -1;
}
+ if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
+ WARN("Failed to update ownership of %s", delta);
// the src will be 'aufs:lowerdir:upperdir'
len = strlen(delta) + strlen(orig->src) + 12;
free(osrc);
return -ENOMEM;
}
- if (do_rsync(odelta, ndelta) < 0) {
+ if ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
+ SYSERROR("error: mkdir %s", ndelta);
+ free(osrc);
+ free(ndelta);
+ return -1;
+ }
+ if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
+ WARN("Failed to update ownership of %s", ndelta);
+
+ struct rsync_data_char rdata;
+ rdata.src = odelta;
+ rdata.dest = ndelta;
+ if (am_unpriv())
+ ret = userns_exec_1(conf, rsync_delta_wrapper, &rdata);
+ else
+ ret = rsync_delta(&rdata);
+ if (ret) {
free(osrc);
free(ndelta);
ERROR("copying aufs delta");
// (unless snap && b->type == dir, in which case it will be
// overlayfs -- which is also allowed)
if (strcmp(b->type, "dir") == 0 ||
+ strcmp(b->type, "aufs") == 0 ||
strcmp(b->type, "overlayfs") == 0 ||
strcmp(b->type, "btrfs") == 0 ||
strcmp(b->type, "loop") == 0)
// unprivileged users can copy and snapshot dir, overlayfs,
// and loop. In particular, not zfs, btrfs, or lvm.
- if (strcmp(t, "dir") == 0 || strcmp(t, "overlayfs") == 0 ||
- strcmp(t, "btrfs") == 0 || strcmp(t, "loop") == 0)
+ if (strcmp(t, "dir") == 0 ||
+ strcmp(t, "aufs") == 0 ||
+ strcmp(t, "overlayfs") == 0 ||
+ strcmp(t, "btrfs") == 0 ||
+ strcmp(t, "loop") == 0)
return true;
return false;
}
#include "config.h"
#include <stdint.h>
#include <lxc/lxccontainer.h>
+#include <sys/mount.h>
+
+
+/* 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
struct bdev;
void detach_block_device(struct lxc_conf *conf);
bool rootfs_is_blockdev(struct lxc_conf *conf);
-
-/* 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
static int do_setup_cgroup_limits(struct cgfs_data *d,
struct lxc_list *cgroup_settings, bool do_devices)
{
- struct lxc_list *iterator;
+ struct lxc_list *iterator, *sorted_cgroup_settings, *next;
struct lxc_cgroup *cg;
int ret = -1;
if (lxc_list_empty(cgroup_settings))
return 0;
- lxc_list_for_each(iterator, cgroup_settings) {
+ sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
+ if (!sorted_cgroup_settings) {
+ return -1;
+ }
+
+ lxc_list_for_each(iterator, sorted_cgroup_settings) {
cg = iterator->elem;
if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
ret = 0;
INFO("cgroup has been setup");
out:
+ lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
+ lxc_list_del(iterator);
+ free(iterator);
+ }
+ free(sorted_cgroup_settings);
return ret;
}
#include <sys/mount.h>
#include <netinet/in.h>
#include <net/if.h>
+#include <poll.h>
#include "error.h"
#include "commands.h"
{
int sv[2] = {-1, -1}, optval = 1, ret = -1;
char buf[1];
+ struct pollfd fds;
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
SYSERROR("Error creating socketpair");
}
/* now send credentials */
- fd_set rfds;
- FD_ZERO(&rfds);
- FD_SET(sv[0], &rfds);
- if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) {
+ fds.fd = sv[0];
+ fds.events = POLLIN;
+ fds.revents = 0;
+ if (poll(&fds, 1, -1) <= 0) {
ERROR("Error getting go-ahead from server: %s", strerror(errno));
goto out;
}
SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__);
goto out;
}
- FD_ZERO(&rfds);
- FD_SET(sv[0], &rfds);
- if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) {
+ fds.fd = sv[0];
+ fds.events = POLLIN;
+ fds.revents = 0;
+ if (poll(&fds, 1, -1) <= 0) {
ERROR("Error getting go-ahead from server: %s", strerror(errno));
goto out;
}
SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__);
goto out;
}
- FD_ZERO(&rfds);
- FD_SET(sv[0], &rfds);
- if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) {
+ fds.fd = sv[0];
+ fds.events = POLLIN;
+ fds.revents = 0;
+ if (poll(&fds, 1, -1) <= 0) {
ERROR("Error getting go-ahead from server: %s", strerror(errno));
goto out;
}
return pids_len;
}
+#if HAVE_CGMANAGER_LIST_CONTROLLERS
+static bool lxc_list_controllers(char ***list)
+{
+ if (!cgm_dbus_connect()) {
+ ERROR("Error connecting to cgroup manager");
+ return false;
+ }
+ if (cgmanager_list_controllers_sync(NULL, cgroup_manager, list) != 0) {
+ NihError *nerr;
+ nerr = nih_error_get();
+ ERROR("call to cgmanager_list_controllers_sync failed: %s", nerr->message);
+ nih_free(nerr);
+ cgm_dbus_disconnect();
+ return false;
+ }
+
+ cgm_dbus_disconnect();
+ return true;
+}
+#else
+static bool lxc_list_controllers(char ***list)
+{
+ return false;
+}
+#endif
+
static inline void free_abs_cgroup(char *cgroup)
{
if (!cgroup)
}
}
+static bool in_comma_list(const char *inword, const char *cgroup_use)
+{
+ char *e;
+ size_t inlen = strlen(inword), len;
+
+ do {
+ e = strchr(cgroup_use, ',');
+ len = e ? e - cgroup_use : strlen(cgroup_use);
+ if (len == inlen && strncmp(inword, cgroup_use, len) == 0)
+ return true;
+ cgroup_use = e + 1;
+ } while (e);
+
+ return false;
+}
+
+static bool in_subsystem_list(const char *c)
+{
+ int i;
+
+ for (i = 0; i < nr_subsystems; i++) {
+ if (strcmp(c, subsystems[i]) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * If /etc/lxc/lxc.conf specifies lxc.cgroup.use = "freezer,memory",
+ * then clear out any other subsystems, and make sure that freezer
+ * and memory are both enabled
+ */
+static bool verify_and_prune(const char *cgroup_use)
+{
+ const char *p;
+ char *e;
+ int i, j;
+
+ for (p = cgroup_use; p && *p; p = e + 1) {
+ e = strchr(p, ',');
+ if (e)
+ *e = '\0';
+
+ if (!in_subsystem_list(p)) {
+ ERROR("Controller %s required by lxc.cgroup.use but not available\n", p);
+ return false;
+ }
+
+ if (e)
+ *e = ',';
+ if (!e)
+ break;
+ }
+
+ for (i = 0; i < nr_subsystems;) {
+ if (in_comma_list(subsystems[i], cgroup_use)) {
+ i++;
+ continue;
+ }
+ free(subsystems[i]);
+ for (j = i; j < nr_subsystems-1; j++)
+ subsystems[j] = subsystems[j+1];
+ subsystems[nr_subsystems-1] = NULL;
+ nr_subsystems--;
+ }
+
+ return true;
+}
+
static bool collect_subsytems(void)
{
char *line = NULL;
+ nih_local char **cgm_subsys_list = NULL;
size_t sz = 0;
- FILE *f;
+ FILE *f = NULL;
if (subsystems) // already initialized
return true;
subsystems_inone[0] = "all";
subsystems_inone[1] = NULL;
+ if (lxc_list_controllers(&cgm_subsys_list)) {
+ while (cgm_subsys_list[nr_subsystems]) {
+ char **tmp = NIH_MUST( realloc(subsystems,
+ (nr_subsystems+2)*sizeof(char *)) );
+ tmp[nr_subsystems] = NIH_MUST(
+ strdup(cgm_subsys_list[nr_subsystems++]) );
+ subsystems = tmp;
+ }
+ if (nr_subsystems)
+ subsystems[nr_subsystems] = NULL;
+ goto collected;
+ }
+
+ INFO("cgmanager_list_controllers failed, falling back to /proc/self/cgroups");
f = fopen_cloexec("/proc/self/cgroup", "r");
if (!f) {
f = fopen_cloexec("/proc/1/cgroup", "r");
}
}
fclose(f);
+ f = NULL;
free(line);
+ line = NULL;
+
+collected:
if (!nr_subsystems) {
ERROR("No cgroup subsystems found");
return false;
}
+ /* make sure that cgroup.use can be and is honored */
+ const char *cgroup_use = lxc_global_config_value("lxc.cgroup.use");
+ if (!cgroup_use && errno != 0)
+ goto out_good;
+ if (cgroup_use) {
+ if (!verify_and_prune(cgroup_use)) {
+ free_subsystems();
+ return false;
+ }
+ subsystems_inone[0] = NIH_MUST( strdup(cgroup_use) );
+ cgm_all_controllers_same = false;
+ }
+
+out_good:
return true;
out_free:
free(line);
- fclose(f);
+ if (f)
+ fclose(f);
free_subsystems();
return false;
}
static bool cgm_setup_limits(void *hdata, struct lxc_list *cgroup_settings, bool do_devices)
{
struct cgm_data *d = hdata;
- struct lxc_list *iterator;
+ struct lxc_list *iterator, *sorted_cgroup_settings, *next;
struct lxc_cgroup *cg;
bool ret = false;
return false;
}
- lxc_list_for_each(iterator, cgroup_settings) {
+ sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
+ if (!sorted_cgroup_settings) {
+ return false;
+ }
+
+ lxc_list_for_each(iterator, sorted_cgroup_settings) {
char controller[100], *p;
cg = iterator->elem;
if (do_devices != !strncmp("devices", cg->subsystem, 7))
ret = true;
INFO("cgroup limits have been setup");
out:
+ lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
+ lxc_list_del(iterator);
+ free(iterator);
+ }
+ free(sorted_cgroup_settings);
cgm_dbus_disconnect();
return ret;
}
return false;
}
- check_supports_multiple_controllers(pid);
-
- if (cgm_all_controllers_same)
- slist = subsystems_inone;
-
for (i = 0; slist[i]; i++) {
- if (slist == subsystems_inone)
- cgroup = try_get_abs_cgroup(name, lxcpath, subsystems[0]);
- else
- cgroup = try_get_abs_cgroup(name, lxcpath, slist[i]);
+ cgroup = try_get_abs_cgroup(name, lxcpath, slist[i]);
if (!cgroup) {
ERROR("Failed to get cgroup for controller %s", slist[i]);
cgm_dbus_disconnect();
break;
}
- if (umount2("./proc", MNT_DETACH)) {
- SYSERROR("Unable to umount /proc");
- return -1;
- }
+ /* This also can be skipped if a container uses unserns */
+ umount2("./proc", MNT_DETACH);
/* It is weird, but chdir("..") moves us in a new root */
if (chdir("..") == -1) {
char veth2buf[IFNAMSIZ], *veth2;
int err;
- if (netdev->priv.veth_attr.pair)
+ if (netdev->priv.veth_attr.pair) {
veth1 = netdev->priv.veth_attr.pair;
- else {
+ if (handler->conf->reboot)
+ lxc_netdev_delete_by_name(veth1);
+ } else {
err = snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
if (err >= sizeof(veth1buf)) { /* can't *really* happen, but... */
ERROR("veth1 name too long");
return 0;
}
-/*
- * _do_tmp_proc_mount: Mount /proc inside container if not already
- * mounted
- *
- * @rootfs : the rootfs where proc should be mounted
- *
- * Returns < 0 on failure, 0 if the correct proc was already mounted
- * and 1 if a new proc was mounted.
- */
-static int do_tmp_proc_mount(const char *rootfs)
-{
- char path[MAXPATHLEN];
- char link[20];
- int linklen, ret;
-
- ret = snprintf(path, MAXPATHLEN, "%s/proc/self", rootfs);
- if (ret < 0 || ret >= MAXPATHLEN) {
- SYSERROR("proc path name too long");
- return -1;
- }
- memset(link, 0, 20);
- linklen = readlink(path, link, 20);
- INFO("I am %d, /proc/self points to '%s'", getpid(), link);
- ret = snprintf(path, MAXPATHLEN, "%s/proc", rootfs);
- if (linklen < 0) /* /proc not mounted */
- goto domount;
- /* can't be longer than rootfs/proc/1 */
- if (strncmp(link, "1", linklen) != 0) {
- /* wrong /procs mounted */
- umount2(path, MNT_DETACH); /* ignore failure */
- goto domount;
- }
- /* the right proc is already mounted */
- return 0;
-
-domount:
- if (mount("proc", path, "proc", 0, NULL))
- return -1;
- INFO("Mounted /proc in container for security transition");
- return 1;
-}
-
int tmp_proc_mount(struct lxc_conf *lxc_conf)
{
int mounted;
} else
mounted = 1;
} else
- mounted = do_tmp_proc_mount(lxc_conf->rootfs.mount);
+ mounted = mount_proc_if_needed(lxc_conf->rootfs.mount);
if (mounted == -1) {
SYSERROR("failed to mount /proc in the container.");
return -1;
{
if (!conf)
return;
+ if (current_config == conf)
+ current_config = NULL;
free(conf->console.log_path);
free(conf->console.path);
free(conf->rootfs.mount);
free(gname);
free(uname);
}
+
+static void free_cgroup_settings(struct lxc_list *result)
+{
+ struct lxc_list *iterator, *next;
+
+ lxc_list_for_each_safe(iterator, result, next) {
+ lxc_list_del(iterator);
+ free(iterator);
+ }
+ free(result);
+}
+
+/*
+ * Return the list of cgroup_settings sorted according to the following rules
+ * 1. Put memory.limit_in_bytes before memory.memsw.limit_in_bytes
+ */
+struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings)
+{
+ struct lxc_list *result;
+ struct lxc_list *memsw_limit = NULL;
+ struct lxc_list *it = NULL;
+ struct lxc_cgroup *cg = NULL;
+ struct lxc_list *item = NULL;
+
+ result = malloc(sizeof(*result));
+ if (!result) {
+ ERROR("failed to allocate memory to sort cgroup settings");
+ return NULL;
+ }
+ lxc_list_init(result);
+
+ /*Iterate over the cgroup settings and copy them to the output list*/
+ lxc_list_for_each(it, cgroup_settings) {
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ERROR("failed to allocate memory to sort cgroup settings");
+ free_cgroup_settings(result);
+ return NULL;
+ }
+ item->elem = it->elem;
+ cg = it->elem;
+ if (strcmp(cg->subsystem, "memory.memsw.limit_in_bytes") == 0) {
+ /* Store the memsw_limit location */
+ memsw_limit = item;
+ } else if (strcmp(cg->subsystem, "memory.limit_in_bytes") == 0 && memsw_limit != NULL) {
+ /* lxc.cgroup.memory.memsw.limit_in_bytes is found before
+ * lxc.cgroup.memory.limit_in_bytes, swap these two items */
+ item->elem = memsw_limit->elem;
+ memsw_limit->elem = it->elem;
+ }
+ lxc_list_add_tail(result, item);
+ }
+
+ return result;
+}
void remount_all_slave(void);
extern void suggest_default_idmap(void);
FILE *write_mount_file(struct lxc_list *mount);
+struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings);
#endif
{ SIGTSTP, "TSTP" },
{ SIGTTIN, "TTIN" },
{ SIGTTOU, "TTOU" },
+#ifdef SIGTRAP
+ { SIGTRAP, "TRAP" },
+#endif
+#ifdef SIGIOT
+ { SIGIOT, "IOT" },
+#endif
+#ifdef SIGEMT
+ { SIGEMT, "EMT" },
+#endif
+#ifdef SIGBUS
+ { SIGBUS, "BUS" },
+#endif
+#ifdef SIGSTKFLT
+ { SIGSTKFLT, "STKFLT" },
+#endif
+#ifdef SIGCLD
+ { SIGCLD, "CLD" },
+#endif
+#ifdef SIGURG
+ { SIGURG, "URG" },
+#endif
+#ifdef SIGXCPU
+ { SIGXCPU, "XCPU" },
+#endif
+#ifdef SIGXFSZ
+ { SIGXFSZ, "XFSZ" },
+#endif
+#ifdef SIGVTALRM
+ { SIGVTALRM, "VTALRM" },
+#endif
+#ifdef SIGPROF
+ { SIGPROF, "PROF" },
+#endif
+#ifdef SIGWINCH
+ { SIGWINCH, "WINCH" },
+#endif
+#ifdef SIGIO
+ { SIGIO, "IO" },
+#endif
+#ifdef SIGPOLL
+ { SIGPOLL, "POLL" },
+#endif
+#ifdef SIGINFO
+ { SIGINFO, "INFO" },
+#endif
+#ifdef SIGLOST
+ { SIGLOST, "LOST" },
+#endif
+#ifdef SIGPWR
+ { SIGPWR, "PWR" },
+#endif
+#ifdef SIGUNUSED
+ { SIGUNUSED, "UNUSED" },
+#endif
+#ifdef SIGSYS
+ { SIGSYS, "SYS" },
+#endif
};
static const size_t config_size = sizeof(config)/sizeof(struct lxc_config_t);
--- /dev/null
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2014-2015 Canonical Ltd.
+ *
+ * Authors:
+ * Tycho Andersen <tycho.andersen@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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#define _GNU_SOURCE
+#include <assert.h>
+#include <linux/limits.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "config.h"
+
+#include "bdev.h"
+#include "cgroup.h"
+#include "conf.h"
+#include "criu.h"
+#include "log.h"
+#include "lxc.h"
+#include "lxclock.h"
+#include "network.h"
+#include "utils.h"
+
+lxc_log_define(lxc_criu, lxc);
+
+void exec_criu(struct criu_opts *opts)
+{
+ char **argv, log[PATH_MAX];
+ int static_args = 22, argc = 0, i, ret;
+ int netnr = 0;
+ struct lxc_list *it;
+
+ char buf[4096];
+
+ /* The command line always looks like:
+ * criu $(action) --tcp-established --file-locks --link-remap --force-irmap \
+ * --manage-cgroups action-script foo.sh -D $(directory) \
+ * -o $(directory)/$(action).log --ext-mount-map auto
+ * --enable-external-sharing --enable-external-masters
+ * --enable-fs hugetlbfs --enable-fs tracefs
+ * +1 for final NULL */
+
+ if (strcmp(opts->action, "dump") == 0) {
+ /* -t pid */
+ static_args += 2;
+
+ /* --leave-running */
+ if (!opts->stop)
+ static_args++;
+ } else if (strcmp(opts->action, "restore") == 0) {
+ /* --root $(lxc_mount_point) --restore-detached
+ * --restore-sibling --pidfile $foo --cgroup-root $foo */
+ static_args += 8;
+ } else {
+ return;
+ }
+
+ if (opts->verbose)
+ static_args++;
+
+ ret = snprintf(log, PATH_MAX, "%s/%s.log", opts->directory, opts->action);
+ if (ret < 0 || ret >= PATH_MAX) {
+ ERROR("logfile name too long\n");
+ return;
+ }
+
+ argv = malloc(static_args * sizeof(*argv));
+ if (!argv)
+ return;
+
+ memset(argv, 0, static_args * sizeof(*argv));
+
+#define DECLARE_ARG(arg) \
+ do { \
+ if (arg == NULL) { \
+ ERROR("Got NULL argument for criu"); \
+ goto err; \
+ } \
+ argv[argc++] = strdup(arg); \
+ if (!argv[argc-1]) \
+ goto err; \
+ } while (0)
+
+ argv[argc++] = on_path("criu", NULL);
+ if (!argv[argc-1]) {
+ ERROR("Couldn't find criu binary\n");
+ goto err;
+ }
+
+ DECLARE_ARG(opts->action);
+ DECLARE_ARG("--tcp-established");
+ DECLARE_ARG("--file-locks");
+ DECLARE_ARG("--link-remap");
+ DECLARE_ARG("--force-irmap");
+ DECLARE_ARG("--manage-cgroups");
+ DECLARE_ARG("--ext-mount-map");
+ DECLARE_ARG("auto");
+ DECLARE_ARG("--enable-external-sharing");
+ DECLARE_ARG("--enable-external-masters");
+ DECLARE_ARG("--enable-fs");
+ DECLARE_ARG("hugetlbfs");
+ DECLARE_ARG("--enable-fs");
+ DECLARE_ARG("tracefs");
+ DECLARE_ARG("-D");
+ DECLARE_ARG(opts->directory);
+ DECLARE_ARG("-o");
+ DECLARE_ARG(log);
+
+ if (opts->verbose)
+ DECLARE_ARG("-vvvvvv");
+
+ if (strcmp(opts->action, "dump") == 0) {
+ char pid[32];
+
+ if (sprintf(pid, "%d", opts->c->init_pid(opts->c)) < 0)
+ goto err;
+
+ DECLARE_ARG("-t");
+ DECLARE_ARG(pid);
+ if (!opts->stop)
+ DECLARE_ARG("--leave-running");
+ } else if (strcmp(opts->action, "restore") == 0) {
+ void *m;
+ int additional;
+
+ DECLARE_ARG("--root");
+ DECLARE_ARG(opts->c->lxc_conf->rootfs.mount);
+ DECLARE_ARG("--restore-detached");
+ DECLARE_ARG("--restore-sibling");
+ DECLARE_ARG("--pidfile");
+ DECLARE_ARG(opts->pidfile);
+ DECLARE_ARG("--cgroup-root");
+ DECLARE_ARG(opts->cgroup_path);
+
+ additional = lxc_list_len(&opts->c->lxc_conf->network) * 2;
+
+ m = realloc(argv, (argc + additional + 1) * sizeof(*argv)); \
+ if (!m) \
+ goto err; \
+ argv = m;
+
+ lxc_list_for_each(it, &opts->c->lxc_conf->network) {
+ char eth[128], *veth;
+ struct lxc_netdev *n = it->elem;
+
+ if (n->type != LXC_NET_VETH)
+ continue;
+
+ if (n->name) {
+ if (strlen(n->name) >= sizeof(eth))
+ goto err;
+ strncpy(eth, n->name, sizeof(eth));
+ } else
+ sprintf(eth, "eth%d", netnr);
+
+ veth = n->priv.veth_attr.pair;
+
+ ret = snprintf(buf, sizeof(buf), "%s=%s@%s", eth, veth, n->link);
+ if (ret < 0 || ret >= sizeof(buf))
+ goto err;
+
+ DECLARE_ARG("--veth-pair");
+ DECLARE_ARG(buf);
+ }
+
+ }
+
+ argv[argc] = NULL;
+
+#undef DECLARE_ARG
+ execv(argv[0], argv);
+err:
+ for (i = 0; argv[i]; i++)
+ free(argv[i]);
+ free(argv);
+}
+
+/*
+ * Check to see if the criu version is recent enough for all the features we
+ * use. This version allows either CRIU_VERSION or (CRIU_GITID_VERSION and
+ * CRIU_GITID_PATCHLEVEL) to work, enabling users building from git to c/r
+ * things potentially before a version is released with a particular feature.
+ *
+ * The intent is that when criu development slows down, we can drop this, but
+ * for now we shouldn't attempt to c/r with versions that we know won't work.
+ */
+static bool criu_version_ok()
+{
+ int pipes[2];
+ pid_t pid;
+
+ if (pipe(pipes) < 0) {
+ SYSERROR("pipe() failed");
+ return false;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ SYSERROR("fork() failed");
+ return false;
+ }
+
+ if (pid == 0) {
+ char *args[] = { "criu", "--version", NULL };
+ char *path;
+ close(pipes[0]);
+
+ close(STDERR_FILENO);
+ if (dup2(pipes[1], STDOUT_FILENO) < 0)
+ exit(1);
+
+ path = on_path("criu", NULL);
+ if (!path)
+ exit(1);
+
+ execv(path, args);
+ exit(1);
+ } else {
+ FILE *f;
+ char version[1024];
+ int patch;
+
+ close(pipes[1]);
+ if (wait_for_pid(pid) < 0) {
+ close(pipes[0]);
+ SYSERROR("execing criu failed, is it installed?");
+ return false;
+ }
+
+ f = fdopen(pipes[0], "r");
+ if (!f) {
+ close(pipes[0]);
+ return false;
+ }
+
+ if (fscanf(f, "Version: %1024[^\n]s", version) != 1)
+ goto version_error;
+
+ if (fgetc(f) != '\n')
+ goto version_error;
+
+ if (strcmp(version, CRIU_VERSION) >= 0)
+ goto version_match;
+
+ if (fscanf(f, "GitID: v%1024[^-]s", version) != 1)
+ goto version_error;
+
+ if (fgetc(f) != '-')
+ goto version_error;
+
+ if (fscanf(f, "%d", &patch) != 1)
+ goto version_error;
+
+ if (strcmp(version, CRIU_GITID_VERSION) < 0)
+ goto version_error;
+
+ if (patch < CRIU_GITID_PATCHLEVEL)
+ goto version_error;
+
+version_match:
+ fclose(f);
+ return true;
+
+version_error:
+ fclose(f);
+ ERROR("must have criu " CRIU_VERSION " or greater to checkpoint/restore\n");
+ return false;
+ }
+}
+
+/* Check and make sure the container has a configuration that we know CRIU can
+ * dump. */
+bool criu_ok(struct lxc_container *c)
+{
+ struct lxc_list *it;
+ bool found_deny_rule = false;
+
+ if (!criu_version_ok())
+ return false;
+
+ if (geteuid()) {
+ ERROR("Must be root to checkpoint\n");
+ return false;
+ }
+
+ /* We only know how to restore containers with veth networks. */
+ lxc_list_for_each(it, &c->lxc_conf->network) {
+ struct lxc_netdev *n = it->elem;
+ switch(n->type) {
+ case LXC_NET_VETH:
+ case LXC_NET_NONE:
+ case LXC_NET_EMPTY:
+ break;
+ default:
+ ERROR("Found network that is not VETH or NONE\n");
+ return false;
+ }
+ }
+
+ // These requirements come from http://criu.org/LXC
+ if (c->lxc_conf->console.path &&
+ strcmp(c->lxc_conf->console.path, "none") != 0) {
+ ERROR("lxc.console must be none\n");
+ return false;
+ }
+
+ if (c->lxc_conf->tty != 0) {
+ ERROR("lxc.tty must be 0\n");
+ return false;
+ }
+
+ lxc_list_for_each(it, &c->lxc_conf->cgroup) {
+ struct lxc_cgroup *cg = it->elem;
+ if (strcmp(cg->subsystem, "devices.deny") == 0 &&
+ strcmp(cg->value, "c 5:1 rwm") == 0) {
+
+ found_deny_rule = true;
+ break;
+ }
+ }
+
+ if (!found_deny_rule) {
+ ERROR("couldn't find devices.deny = c 5:1 rwm");
+ return false;
+ }
+
+ return true;
+}
+
+static bool restore_net_info(struct lxc_container *c)
+{
+ struct lxc_list *it;
+ bool has_error = true;
+
+ if (container_mem_lock(c))
+ return false;
+
+ lxc_list_for_each(it, &c->lxc_conf->network) {
+ struct lxc_netdev *netdev = it->elem;
+ char template[IFNAMSIZ];
+
+ if (netdev->type != LXC_NET_VETH)
+ continue;
+
+ snprintf(template, sizeof(template), "vethXXXXXX");
+
+ if (!netdev->priv.veth_attr.pair)
+ netdev->priv.veth_attr.pair = lxc_mkifname(template);
+
+ if (!netdev->priv.veth_attr.pair)
+ goto out_unlock;
+ }
+
+ has_error = false;
+
+out_unlock:
+ container_mem_unlock(c);
+ return !has_error;
+}
+
+void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose)
+{
+ pid_t pid;
+ char pidfile[L_tmpnam];
+ struct lxc_handler *handler;
+ int status;
+
+ if (!tmpnam(pidfile))
+ goto out;
+
+ handler = lxc_init(c->name, c->lxc_conf, c->config_path);
+ if (!handler)
+ goto out;
+
+ if (!cgroup_init(handler)) {
+ ERROR("failed initing cgroups");
+ goto out_fini_handler;
+ }
+
+ if (!cgroup_create(handler)) {
+ ERROR("failed creating groups");
+ goto out_fini_handler;
+ }
+
+ if (!restore_net_info(c)) {
+ ERROR("failed restoring network info");
+ goto out_fini_handler;
+ }
+
+ resolve_clone_flags(handler);
+
+ pid = fork();
+ if (pid < 0)
+ goto out_fini_handler;
+
+ if (pid == 0) {
+ struct criu_opts os;
+ struct lxc_rootfs *rootfs;
+
+ close(pipe);
+ pipe = -1;
+
+ if (unshare(CLONE_NEWNS))
+ goto out_fini_handler;
+
+ /* CRIU needs the lxc root bind mounted so that it is the root of some
+ * mount. */
+ rootfs = &c->lxc_conf->rootfs;
+
+ if (rootfs_is_blockdev(c->lxc_conf)) {
+ if (do_rootfs_setup(c->lxc_conf, c->name, c->config_path) < 0)
+ goto out_fini_handler;
+ } else {
+ if (mkdir(rootfs->mount, 0755) < 0 && errno != EEXIST)
+ goto out_fini_handler;
+
+ if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
+ SYSERROR("remount / to private failed");
+ goto out_fini_handler;
+ }
+
+ if (mount(rootfs->path, rootfs->mount, NULL, MS_BIND, NULL) < 0) {
+ rmdir(rootfs->mount);
+ goto out_fini_handler;
+ }
+ }
+
+ os.action = "restore";
+ os.directory = directory;
+ os.c = c;
+ os.pidfile = pidfile;
+ os.verbose = verbose;
+ os.cgroup_path = cgroup_canonical_path(handler);
+
+ /* exec_criu() returning is an error */
+ exec_criu(&os);
+ umount(rootfs->mount);
+ rmdir(rootfs->mount);
+ goto out_fini_handler;
+ } else {
+ int ret;
+ char title[2048];
+
+ pid_t w = waitpid(pid, &status, 0);
+ if (w == -1) {
+ SYSERROR("waitpid");
+ goto out_fini_handler;
+ }
+
+ ret = write(pipe, &status, sizeof(status));
+ close(pipe);
+ pipe = -1;
+
+ if (sizeof(status) != ret) {
+ SYSERROR("failed to write all of status");
+ goto out_fini_handler;
+ }
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status)) {
+ goto out_fini_handler;
+ } else {
+ int ret;
+ FILE *f = fopen(pidfile, "r");
+ if (!f) {
+ SYSERROR("couldn't read restore's init pidfile %s\n", pidfile);
+ goto out_fini_handler;
+ }
+
+ ret = fscanf(f, "%d", (int*) &handler->pid);
+ fclose(f);
+ if (unlink(pidfile) < 0 && errno != ENOENT)
+ SYSERROR("unlinking pidfile failed");
+
+ if (ret != 1) {
+ ERROR("reading restore pid failed");
+ goto out_fini_handler;
+ }
+
+ if (lxc_set_state(c->name, handler, RUNNING))
+ goto out_fini_handler;
+ }
+ } else {
+ ERROR("CRIU was killed with signal %d\n", WTERMSIG(status));
+ goto out_fini_handler;
+ }
+
+ /*
+ * See comment in lxcapi_start; we don't care if these
+ * fail because it's just a beauty thing. We just
+ * assign the return here to silence potential.
+ */
+ ret = snprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name);
+ ret = setproctitle(title);
+
+ ret = lxc_poll(c->name, handler);
+ if (ret)
+ lxc_abort(c->name, handler);
+ lxc_fini(c->name, handler);
+ exit(ret);
+ }
+
+out_fini_handler:
+ lxc_fini(c->name, handler);
+ if (unlink(pidfile) < 0 && errno != ENOENT)
+ SYSERROR("unlinking pidfile failed");
+
+out:
+ if (pipe >= 0) {
+ status = 1;
+ if (write(pipe, &status, sizeof(status)) != sizeof(status)) {
+ SYSERROR("writing status failed");
+ }
+ close(pipe);
+ }
+
+ exit(1);
+}
--- /dev/null
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2014-2015 Canonical Ltd.
+ *
+ * Authors:
+ * Tycho Andersen <tycho.andersen@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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __LXC_CRIU_H
+#define __LXC_CRIU_H
+
+#include <stdbool.h>
+
+#include <lxc/lxccontainer.h>
+
+// We require either the criu major/minor version, or the criu GITID if criu
+// was built from git.
+#define CRIU_VERSION "1.6"
+
+#define CRIU_GITID_VERSION "1.5"
+#define CRIU_GITID_PATCHLEVEL 133
+
+struct criu_opts {
+ /* The type of criu invocation, one of "dump" or "restore" */
+ char *action;
+
+ /* The directory to pass to criu */
+ char *directory;
+
+ /* The container to dump */
+ struct lxc_container *c;
+
+ /* Enable criu verbose mode? */
+ bool verbose;
+
+ /* dump: stop the container or not after dumping? */
+ bool stop;
+
+ /* restore: the file to write the init process' pid into */
+ char *pidfile;
+ const char *cgroup_path;
+};
+
+void exec_criu(struct criu_opts *opts);
+
+/* Check and make sure the container has a configuration that we know CRIU can
+ * dump. */
+bool criu_ok(struct lxc_container *c);
+
+// do_restore never returns, the calling process is used as the
+// monitor process. do_restore calls exit() if it fails.
+void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose);
+
+#endif
initpath = choose_init(NULL);
if (!initpath) {
- ERROR("Failed to find an lxc-init");
+ ERROR("Failed to find an lxc-init or init.lxc");
goto out2;
}
argv[i++] = initpath;
};
int lxc_execute(const char *name, char *const argv[], int quiet,
- struct lxc_conf *conf, const char *lxcpath)
+ struct lxc_conf *conf, const char *lxcpath, bool backgrounded)
{
struct execute_args args = {
.argv = argv,
return -1;
conf->is_execute = 1;
- return __lxc_start(name, conf, &execute_start_ops, &args, lxcpath);
+ return __lxc_start(name, conf, &execute_start_ops, &args, lxcpath, backgrounded);
}
--- /dev/null
+/*
+ * 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
+ */
+
+#include "initutils.h"
+#include "log.h"
+
+lxc_log_define(lxc_initutils, lxc);
+
+static int mount_fs(const char *source, const char *target, const char *type)
+{
+ /* the umount may fail */
+ if (umount(target))
+ WARN("failed to unmount %s : %s", target, strerror(errno));
+
+ if (mount(source, target, type, 0, NULL)) {
+ ERROR("failed to mount %s : %s", target, strerror(errno));
+ return -1;
+ }
+
+ DEBUG("'%s' mounted on '%s'", source, target);
+
+ return 0;
+}
+
+extern void lxc_setup_fs(void)
+{
+ if (mount_fs("proc", "/proc", "proc"))
+ INFO("failed to remount proc");
+
+ /* if we can't mount /dev/shm, continue anyway */
+ if (mount_fs("shmfs", "/dev/shm", "tmpfs"))
+ INFO("failed to mount /dev/shm");
+
+ /* If we were able to mount /dev/shm, then /dev exists */
+ /* Sure, but it's read-only per config :) */
+ if (access("/dev/mqueue", F_OK) && mkdir("/dev/mqueue", 0666)) {
+ DEBUG("failed to create '/dev/mqueue'");
+ return;
+ }
+
+ /* continue even without posix message queue support */
+ if (mount_fs("mqueue", "/dev/mqueue", "mqueue"))
+ INFO("failed to mount /dev/mqueue");
+}
+
+static char *copy_global_config_value(char *p)
+{
+ int len = strlen(p);
+ char *retbuf;
+
+ if (len < 1)
+ return NULL;
+ if (p[len-1] == '\n') {
+ p[len-1] = '\0';
+ len--;
+ }
+ retbuf = malloc(len+1);
+ if (!retbuf)
+ return NULL;
+ strcpy(retbuf, p);
+ return retbuf;
+}
+
+const char *lxc_global_config_value(const char *option_name)
+{
+ static const char * const options[][2] = {
+ { "lxc.bdev.lvm.vg", DEFAULT_VG },
+ { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL },
+ { "lxc.bdev.zfs.root", DEFAULT_ZFSROOT },
+ { "lxc.lxcpath", NULL },
+ { "lxc.default_config", NULL },
+ { "lxc.cgroup.pattern", NULL },
+ { "lxc.cgroup.use", NULL },
+ { NULL, NULL },
+ };
+
+ /* placed in the thread local storage pool for non-bionic targets */
+#ifdef HAVE_TLS
+ static __thread const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
+#else
+ static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
+#endif
+
+ /* user_config_path is freed as soon as it is used */
+ char *user_config_path = NULL;
+
+ /*
+ * The following variables are freed at bottom unconditionally.
+ * So NULL the value if it is to be returned to the caller
+ */
+ char *user_default_config_path = NULL;
+ char *user_lxc_path = NULL;
+ char *user_cgroup_pattern = NULL;
+
+ if (geteuid() > 0) {
+ const char *user_home = getenv("HOME");
+ if (!user_home)
+ user_home = "/";
+
+ user_config_path = malloc(sizeof(char) * (22 + strlen(user_home)));
+ user_default_config_path = malloc(sizeof(char) * (26 + strlen(user_home)));
+ user_lxc_path = malloc(sizeof(char) * (19 + strlen(user_home)));
+
+ sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home);
+ sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home);
+ sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home);
+ user_cgroup_pattern = strdup("lxc/%n");
+ }
+ else {
+ user_config_path = strdup(LXC_GLOBAL_CONF);
+ user_default_config_path = strdup(LXC_DEFAULT_CONFIG);
+ user_lxc_path = strdup(LXCPATH);
+ user_cgroup_pattern = strdup(DEFAULT_CGROUP_PATTERN);
+ }
+
+ const char * const (*ptr)[2];
+ size_t i;
+ char buf[1024], *p, *p2;
+ FILE *fin = NULL;
+
+ for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) {
+ if (!strcmp(option_name, (*ptr)[0]))
+ break;
+ }
+ if (!(*ptr)[0]) {
+ free(user_config_path);
+ free(user_default_config_path);
+ free(user_lxc_path);
+ free(user_cgroup_pattern);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (values[i]) {
+ free(user_config_path);
+ free(user_default_config_path);
+ free(user_lxc_path);
+ free(user_cgroup_pattern);
+ return values[i];
+ }
+
+ fin = fopen_cloexec(user_config_path, "r");
+ free(user_config_path);
+ if (fin) {
+ while (fgets(buf, 1024, fin)) {
+ if (buf[0] == '#')
+ continue;
+ p = strstr(buf, option_name);
+ if (!p)
+ continue;
+ /* see if there was just white space in front
+ * of the option name
+ */
+ for (p2 = buf; p2 < p; p2++) {
+ if (*p2 != ' ' && *p2 != '\t')
+ break;
+ }
+ if (p2 < p)
+ continue;
+ p = strchr(p, '=');
+ if (!p)
+ continue;
+ /* see if there was just white space after
+ * the option name
+ */
+ for (p2 += strlen(option_name); p2 < p; p2++) {
+ if (*p2 != ' ' && *p2 != '\t')
+ break;
+ }
+ if (p2 < p)
+ continue;
+ p++;
+ while (*p && (*p == ' ' || *p == '\t')) p++;
+ if (!*p)
+ continue;
+
+ if (strcmp(option_name, "lxc.lxcpath") == 0) {
+ free(user_lxc_path);
+ user_lxc_path = copy_global_config_value(p);
+ remove_trailing_slashes(user_lxc_path);
+ values[i] = user_lxc_path;
+ user_lxc_path = NULL;
+ goto out;
+ }
+
+ values[i] = copy_global_config_value(p);
+ goto out;
+ }
+ }
+ /* could not find value, use default */
+ if (strcmp(option_name, "lxc.lxcpath") == 0) {
+ remove_trailing_slashes(user_lxc_path);
+ values[i] = user_lxc_path;
+ user_lxc_path = NULL;
+ }
+ else if (strcmp(option_name, "lxc.default_config") == 0) {
+ values[i] = user_default_config_path;
+ user_default_config_path = NULL;
+ }
+ else if (strcmp(option_name, "lxc.cgroup.pattern") == 0) {
+ values[i] = user_cgroup_pattern;
+ user_cgroup_pattern = NULL;
+ }
+ else
+ values[i] = (*ptr)[1];
+
+ /* special case: if default value is NULL,
+ * and there is no config, don't view that
+ * as an error... */
+ if (!values[i])
+ errno = 0;
+
+out:
+ if (fin)
+ fclose(fin);
+
+ free(user_cgroup_pattern);
+ free(user_default_config_path);
+ free(user_lxc_path);
+
+ return values[i];
+}
+
+extern void remove_trailing_slashes(char *p)
+{
+ int l = strlen(p);
+ while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
+ p[l] = '\0';
+}
+
+FILE *fopen_cloexec(const char *path, const char *mode)
+{
+ int open_mode = 0;
+ int step = 0;
+ int fd;
+ int saved_errno = 0;
+ FILE *ret;
+
+ if (!strncmp(mode, "r+", 2)) {
+ open_mode = O_RDWR;
+ step = 2;
+ } else if (!strncmp(mode, "r", 1)) {
+ open_mode = O_RDONLY;
+ step = 1;
+ } else if (!strncmp(mode, "w+", 2)) {
+ open_mode = O_RDWR | O_TRUNC | O_CREAT;
+ step = 2;
+ } else if (!strncmp(mode, "w", 1)) {
+ open_mode = O_WRONLY | O_TRUNC | O_CREAT;
+ step = 1;
+ } else if (!strncmp(mode, "a+", 2)) {
+ open_mode = O_RDWR | O_CREAT | O_APPEND;
+ step = 2;
+ } else if (!strncmp(mode, "a", 1)) {
+ open_mode = O_WRONLY | O_CREAT | O_APPEND;
+ step = 1;
+ }
+ for (; mode[step]; step++)
+ if (mode[step] == 'x')
+ open_mode |= O_EXCL;
+ open_mode |= O_CLOEXEC;
+
+ fd = open(path, open_mode, 0666);
+ if (fd < 0)
+ return NULL;
+
+ ret = fdopen(fd, mode);
+ saved_errno = errno;
+ if (!ret)
+ close(fd);
+ errno = saved_errno;
+ return ret;
+}
--- /dev/null
+/*
+ * 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_INITUTILS_H
+#define __LXC_INITUTILS_H
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+
+#include "config.h"
+
+#define DEFAULT_VG "lxc"
+#define DEFAULT_THIN_POOL "lxc"
+#define DEFAULT_ZFSROOT "lxc"
+
+extern void lxc_setup_fs(void);
+extern const char *lxc_global_config_value(const char *option_name);
+
+/* open a file with O_CLOEXEC */
+extern void remove_trailing_slashes(char *p);
+FILE *fopen_cloexec(const char *path, const char *mode);
+
+#endif /* __LXC_INITUTILS_H */
#define LXC_LOG_PREFIX_SIZE 32
#define LXC_LOG_BUFFER_SIZE 512
-static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
-static void lock_mutex(pthread_mutex_t *l)
-{
- int ret;
-
- if ((ret = pthread_mutex_lock(l)) != 0) {
- fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret));
- exit(1);
- }
-}
-
-static void unlock_mutex(pthread_mutex_t *l)
-{
- int ret;
-
- if ((ret = pthread_mutex_unlock(l)) != 0) {
- fprintf(stderr, "pthread_mutex_unlock returned:%d %s\n", ret, strerror(ret));
- exit(1);
- }
-}
-
-void log_lock(void)
-{
- lock_mutex(&log_mutex);
-}
-
-void log_unlock(void)
-{
- unlock_mutex(&log_mutex);
-}
-
int lxc_log_fd = -1;
int lxc_quiet_specified;
int lxc_log_use_global_fd;
lxcpath = LOGPATH;
/* try LOGPATH if lxcpath is the default for the privileged containers */
- if (!geteuid() && strcmp(lxcpath, lxc_global_config_value("lxc.lxcpath")) == 0)
+ if (!geteuid() && strcmp(LXCPATH, lxcpath) == 0)
ret = _lxc_log_set_file(name, NULL, 0);
/* try in lxcpath */
if [ $RES -eq 0 ]; then
$SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
else
- if [ ! -z "$mandatory" -a "$mandatory" = yes ]; then
+ if [ ! -z "$mandatory" ] && [ "$mandatory" = yes ]; then
$SETCOLOR_FAILURE && echo "required" && $SETCOLOR_NORMAL
else
$SETCOLOR_WARNING && echo "missing" && $SETCOLOR_NORMAL
echo -n "Cgroup sched: " && is_enabled CONFIG_CGROUP_SCHED
echo -n "Cgroup cpu account: " && is_enabled CONFIG_CGROUP_CPUACCT
echo -n "Cgroup memory controller: "
-if [ $KVER_MAJOR -ge 3 -a $KVER_MINOR -ge 6 ]; then
+if ([ $KVER_MAJOR -ge 3 ] && [ $KVER_MINOR -ge 6 ]) || ([ $KVER_MAJOR -gt 3 ]); then
is_enabled CONFIG_MEMCG
else
is_enabled CONFIG_CGROUP_MEM_RES_CTLR
+++ /dev/null
-#!/bin/sh
-
-set -e
-
-i=0
-while true; do
- eval "bridge=\$LXC_CRIU_BRIDGE$i"
- eval "veth=\$LXC_CRIU_VETH$i"
-
- if [ -z "$bridge" ] || [ -z "$veth" ]; then
- exit 0
- fi
-
- if [ "$CRTOOLS_SCRIPT_ACTION" = "network-lock" ]; then
- brctl delif $bridge $veth
- fi
-
- if [ "$CRTOOLS_SCRIPT_ACTION" = "network-unlock" ]; then
- brctl addif $bridge $veth
- ip link set dev $veth up
- fi
-
- i=$((i+1))
-done
-
-exit 1
args = parser.parse_args()
-# Basic requirements check
-## We only support privileged containers for now
-if os.geteuid() != 0 and args.union_type != "overlayfs":
- parser.error(_("Unprivileged containers may only use "
- "overlayfs at this time."))
-
## Check that -d and CMD aren't used at the same time
if args.command and args.daemon:
parser.error(_("You can't use -d and a command at the same time."))
entry[0],
entry[1]))
elif args.union_type == "aufs":
- xino_path = "%s/lxc/aufs.xino" % get_rundir()
+ xino_path = "/dev/shm/aufs.xino"
if not os.path.exists(os.path.basename(xino_path)):
os.makedirs(os.path.basename(xino_path))
extern "C" {
#endif
+#include <stdbool.h>
#include <stddef.h>
#include <sys/select.h>
#include <sys/types.h>
/*
* Start the specified command inside a system container
- * @name : the name of the container
- * @argv : an array of char * corresponding to the commande line
- * @conf : configuration
+ * @name : the name of the container
+ * @argv : an array of char * corresponding to the commande line
+ * @conf : configuration
+ * @backgrounded : whether or not the container is daemonized
* Returns 0 on success, < 0 otherwise
*/
extern int lxc_start(const char *name, char *const argv[], struct lxc_conf *conf,
- const char *lxcpath);
+ const char *lxcpath, bool backgrounded);
/*
* Start the specified command inside an application container
- * @name : the name of the container
- * @argv : an array of char * corresponding to the commande line
- * @quiet : if != 0 then lxc-init won't produce any output
- * @conf : configuration
+ * @name : the name of the container
+ * @argv : an array of char * corresponding to the commande line
+ * @quiet : if != 0 then lxc-init won't produce any output
+ * @conf : configuration
+ * @backgrounded : whether or not the container is daemonized
* Returns 0 on success, < 0 otherwise
*/
extern int lxc_execute(const char *name, char *const argv[], int quiet,
- struct lxc_conf *conf, const char *lxcpath);
-
-/*
- * Open the monitoring mechanism for a specific container
- * The function will return an fd corresponding to the events
- * Returns a file descriptor on success, < 0 otherwise
- */
-extern int lxc_monitor_open(const char *lxcpath);
-
-/*
- * Blocking read for the next container state change
- * @fd : the file descriptor provided by lxc_monitor_open
- * @msg : the variable which will be filled with the state
- * Returns 0 if the monitored container has exited, > 0 if
- * data was read, < 0 otherwise
- */
-extern int lxc_monitor_read(int fd, struct lxc_msg *msg);
-
-/*
- * Blocking read for the next container state change with timeout
- * @fd : the file descriptor provided by lxc_monitor_open
- * @msg : the variable which will be filled with the state
- * @timeout : the timeout in seconds to wait for a state change
- * Returns 0 if the monitored container has exited, > 0 if
- * data was read, < 0 otherwise
- */
-extern int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout);
-
-/*
- * Blocking read from multiple monitors for the next container state
- * change with timeout
- * @rfds : an fd_set of file descriptors provided by lxc_monitor_open
- * @nfds : the maximum fd number in rfds + 1
- * @msg : the variable which will be filled with the state
- * @timeout : the timeout in seconds to wait for a state change
- * Returns 0 if the monitored container has exited, > 0 if
- * data was read, < 0 otherwise
- */
-extern int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg, int timeout);
+ struct lxc_conf *conf, const char *lxcpath,
+ bool backgrounded);
/*
* Close the fd associated with the monitoring
if ( list_contains_entry( workptr, workstr_list ) ) {
if ( *workptr ) {
fprintf(stderr, "Duplicate group \"%s\" in list - ignoring\n", workptr );
+ fflush(stderr);
} else {
- fprintf(stderr, "Duilicate NULL group in list - ignoring\n" );
+ fprintf(stderr, "Duplicate NULL group in list - ignoring\n" );
+ fflush(stderr);
}
} else {
worklist = malloc(sizeof(*worklist));
qsort(&containers[0], count, sizeof(struct lxc_container *), cmporder);
if (cmd_groups_list && my_args.all) {
- fprintf(stderr, "Specifying -a (all) with -g (groups) doesn't make sense. All option overrides.");
+ fprintf(stderr, "Specifying -a (all) with -g (groups) doesn't make sense. All option overrides.\n");
+ fflush(stderr);
}
if (!cmd_groups_list) {
if (my_args.shutdown) {
/* Shutdown the container */
if (c->is_running(c)) {
- if (my_args.list)
+ if (my_args.list) {
printf("%s\n", c->name);
+ fflush(stdout);
+ }
else {
if (!c->shutdown(c, my_args.timeout)) {
if (!c->stop(c)) {
fprintf(stderr, "Error shutting down container: %s\n", c->name);
+ fflush(stderr);
}
}
}
else if (my_args.hardstop) {
/* Kill the container */
if (c->is_running(c)) {
- if (my_args.list)
+ if (my_args.list) {
printf("%s\n", c->name);
+ fflush(stdout);
+ }
else {
- if (!c->stop(c))
+ if (!c->stop(c)) {
fprintf(stderr, "Error killing container: %s\n", c->name);
+ fflush(stderr);
+ }
}
}
}
else if (my_args.reboot) {
/* Reboot the container */
if (c->is_running(c)) {
- if (my_args.list)
+ if (my_args.list) {
printf("%s %d\n", c->name,
get_config_integer(c, "lxc.start.delay"));
+ fflush(stdout);
+ }
else {
- if (!c->reboot(c))
+ if (!c->reboot(c)) {
fprintf(stderr, "Error rebooting container: %s\n", c->name);
+ fflush(stderr);
+ }
else
sleep(get_config_integer(c, "lxc.start.delay"));
}
else {
/* Start the container */
if (!c->is_running(c)) {
- if (my_args.list)
+ if (my_args.list) {
printf("%s %d\n", c->name,
get_config_integer(c, "lxc.start.delay"));
+ fflush(stdout);
+ }
else {
- if (!c->start(c, 0, NULL))
+ if (!c->start(c, 0, NULL)) {
fprintf(stderr, "Error starting container: %s\n", c->name);
+ fflush(stderr);
+ }
else
sleep(get_config_integer(c, "lxc.start.delay"));
}
if (lxc_config_define_load(&defines, conf))
return 1;
- ret = lxc_execute(my_args.name, my_args.argv, my_args.quiet, conf, my_args.lxcpath[0]);
+ ret = lxc_execute(my_args.name, my_args.argv, my_args.quiet, conf, my_args.lxcpath[0], false);
lxc_conf_free(conf);
#include "log.h"
#include "caps.h"
#include "error.h"
-#include "utils.h"
+#include "initutils.h"
lxc_log_define(lxc_init, lxc);
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
+#include <poll.h>
#include "lxc.h"
#include "log.h"
.lxcpath_additional = -1,
};
+static void close_fds(struct pollfd *fds, nfds_t nfds)
+{
+ nfds_t i;
+
+ if (nfds < 1)
+ return;
+
+ for (i = 0; i < nfds; ++i) {
+ close(fds[i].fd);
+ }
+}
+
int main(int argc, char *argv[])
{
char *regexp;
struct lxc_msg msg;
regex_t preg;
- fd_set rfds, rfds_save;
- int len, rc, i, nfds = -1;
+ struct pollfd *fds;
+ nfds_t nfds;
+ int len, rc_main, rc_snp, i;
+
+ rc_main = 0;
if (lxc_arguments_parse(&my_args, argc, argv))
return 1;
ERROR("failed to allocate memory");
return 1;
}
- rc = snprintf(regexp, len, "^%s$", my_args.name);
- if (rc < 0 || rc >= len) {
+ rc_snp = snprintf(regexp, len, "^%s$", my_args.name);
+ if (rc_snp < 0 || rc_snp >= len) {
ERROR("Name too long");
- free(regexp);
- return 1;
+ rc_main = 1;
+ goto error;
}
if (regcomp(&preg, regexp, REG_NOSUB|REG_EXTENDED)) {
ERROR("failed to compile the regex '%s'", my_args.name);
- free(regexp);
- return 1;
+ rc_main = 1;
+ goto error;
}
- free(regexp);
- if (my_args.lxcpath_cnt > FD_SETSIZE) {
- ERROR("too many paths requested, only the first %d will be monitored", FD_SETSIZE);
- my_args.lxcpath_cnt = FD_SETSIZE;
+ fds = malloc(my_args.lxcpath_cnt * sizeof(struct pollfd));
+ if (!fds) {
+ SYSERROR("out of memory");
+ rc_main = -1;
+ goto cleanup;
}
- FD_ZERO(&rfds);
- for (i = 0; i < my_args.lxcpath_cnt; i++) {
+ nfds = my_args.lxcpath_cnt;
+ for (i = 0; i < nfds; i++) {
int fd;
lxc_monitord_spawn(my_args.lxcpath[i]);
fd = lxc_monitor_open(my_args.lxcpath[i]);
if (fd < 0) {
- regfree(&preg);
- return 1;
+ close_fds(fds, i);
+ rc_main = 1;
+ goto cleanup;
}
- FD_SET(fd, &rfds);
- if (fd > nfds)
- nfds = fd;
+ fds[i].fd = fd;
+ fds[i].events = POLLIN;
+ fds[i].revents = 0;
}
- memcpy(&rfds_save, &rfds, sizeof(rfds_save));
- nfds++;
setlinebuf(stdout);
for (;;) {
- memcpy(&rfds, &rfds_save, sizeof(rfds));
-
- if (lxc_monitor_read_fdset(&rfds, nfds, &msg, -1) < 0) {
- regfree(&preg);
- return 1;
+ if (lxc_monitor_read_fdset(fds, nfds, &msg, -1) < 0) {
+ rc_main = 1;
+ goto close_and_clean;
}
msg.name[sizeof(msg.name)-1] = '\0';
}
}
+close_and_clean:
+ close_fds(fds, nfds);
+
+cleanup:
regfree(&preg);
+ free(fds);
- return 0;
+error:
+ free(regexp);
+
+ return rc_main;
}
#include "console.h"
#include "cgroup.h"
#include "commands.h"
+#include "criu.h"
#include "log.h"
#include "bdev.h"
#include "utils.h"
static rettype fnname(struct lxc_container *c) \
{ \
rettype ret; \
- struct lxc_conf *old = current_config; \
current_config = c ? c->lxc_conf : NULL; \
ret = do_##fnname(c); \
- current_config = old; \
+ current_config = NULL; \
return ret; \
}
static rettype fnname(struct lxc_container *c, t1 a1) \
{ \
rettype ret; \
- struct lxc_conf *old = current_config; \
current_config = c ? c->lxc_conf : NULL; \
ret = do_##fnname(c, a1); \
- current_config = old; \
+ current_config = NULL; \
return ret; \
}
static rettype fnname(struct lxc_container *c, t1 a1, t2 a2) \
{ \
rettype ret; \
- struct lxc_conf *old = current_config; \
current_config = c ? c->lxc_conf : NULL; \
ret = do_##fnname(c, a1, a2); \
- current_config = old; \
+ current_config = NULL; \
return ret; \
}
static rettype fnname(struct lxc_container *c, t1 a1, t2 a2, t3 a3) \
{ \
rettype ret; \
- struct lxc_conf *old = current_config; \
current_config = c ? c->lxc_conf : NULL; \
ret = do_##fnname(c, a1, a2, a3); \
- current_config = old; \
+ current_config = NULL; \
return ret; \
}
int stdoutfd, int stderrfd, int escape)
{
int ret;
- struct lxc_conf *old = current_config;
- current_config = c ? c->lxc_conf : NULL;
+
+ if (!c)
+ return -1;
+
+ current_config = c->lxc_conf;
ret = lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape);
- current_config = old;
+ current_config = NULL;
return ret;
}
container_mem_unlock(c);
if (useinit) {
- ret = lxc_execute(c->name, argv, 1, conf, c->config_path);
+ ret = lxc_execute(c->name, argv, 1, conf, c->config_path, daemonize);
return ret == 0 ? true : false;
}
pid = fork();
if (pid < 0) {
SYSERROR("Error doing dual-fork");
- return false;
+ exit(1);
}
if (pid != 0)
exit(0);
/* like daemon(), chdir to / and redirect 0,1,2 to /dev/null */
if (chdir("/")) {
SYSERROR("Error chdir()ing to /.");
- return false;
+ exit(1);
}
lxc_check_inherited(conf, true, -1);
- close(0);
- close(1);
- close(2);
- open("/dev/zero", O_RDONLY);
- open("/dev/null", O_RDWR);
- open("/dev/null", O_RDWR);
+ if (null_stdfds() < 0) {
+ ERROR("failed to close fds");
+ exit(1);
+ }
setsid();
} else {
if (!am_single_threaded()) {
if (pid_fp == NULL) {
SYSERROR("Failed to create pidfile '%s' for '%s'",
c->pidfile, c->name);
+ if (daemonize)
+ exit(1);
return false;
}
SYSERROR("Failed to write '%s'", c->pidfile);
fclose(pid_fp);
pid_fp = NULL;
+ if (daemonize)
+ exit(1);
return false;
}
pid_fp = NULL;
}
-reboot:
conf->reboot = 0;
+reboot:
if (lxc_check_inherited(conf, daemonize, -1)) {
ERROR("Inherited fds found");
ret = 1;
goto out;
}
- ret = lxc_start(c->name, argv, conf, c->config_path);
+ ret = lxc_start(c->name, argv, conf, c->config_path, daemonize);
c->error_num = ret;
- if (conf->reboot) {
+ if (conf->reboot == 1) {
INFO("container requested reboot");
- conf->reboot = 0;
+ conf->reboot = 2;
goto reboot;
}
static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv[])
{
bool ret;
- struct lxc_conf *old = current_config;
current_config = c ? c->lxc_conf : NULL;
ret = do_lxcapi_start(c, useinit, argv);
- current_config = old;
+ current_config = NULL;
return ret;
}
if (!c)
return false;
- struct lxc_conf *old = current_config;
current_config = c->lxc_conf;
va_start(ap, useinit);
free(inargs);
}
- current_config = old;
+ current_config = NULL;
return bret;
}
return p;
}
-static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet,
+static bool create_run_template(struct lxc_container *c, char *tpath, bool need_null_stdfds,
char *const argv[])
{
pid_t pid;
char **newargv;
struct lxc_conf *conf = c->lxc_conf;
- if (quiet) {
- close(0);
- close(1);
- close(2);
- open("/dev/zero", O_RDONLY);
- open("/dev/null", O_RDWR);
- open("/dev/null", O_RDWR);
+ if (need_null_stdfds && null_stdfds() < 0) {
+ exit(1);
}
src = c->lxc_conf->rootfs.path;
char *const argv[])
{
bool ret;
- struct lxc_conf *old = current_config;
current_config = c ? c->lxc_conf : NULL;
ret = do_lxcapi_create(c, t, bdevtype, specs, flags, argv);
- current_config = old;
+ current_config = NULL;
return ret;
}
if (!c)
return false;
- struct lxc_conf *old = current_config;
- current_config = c ? c->lxc_conf : NULL;
+ current_config = c->lxc_conf;
/*
* since we're going to wait for create to finish, I don't think we
out:
free(args);
- current_config = old;
+ current_config = NULL;
return bret;
}
goto out;
}
+ if (current_config && c->lxc_conf == current_config) {
+ current_config = NULL;
+ if (c->lxc_conf->logfd != -1) {
+ close(c->lxc_conf->logfd);
+ c->lxc_conf->logfd = -1;
+ }
+ }
+
if (c->lxc_conf && c->lxc_conf->rootfs.path && c->lxc_conf->rootfs.mount) {
if (am_unpriv())
ret = userns_exec_1(c->lxc_conf, bdev_destroy_wrapper, c->lxc_conf);
// We will simply append a new lxc.rootfs entry to the unexpanded config
clear_unexp_config_line(c->lxc_conf, "lxc.rootfs", false);
if (!do_append_unexp_config_line(c->lxc_conf, "lxc.rootfs", c->lxc_conf->rootfs.path)) {
- ERROR("Error saving new rootfs to cloend config");
+ ERROR("Error saving new rootfs to cloned config");
return -1;
}
if (flags & LXC_CLONE_SNAPSHOT)
char **hookargs)
{
struct lxc_container * ret;
- struct lxc_conf *old = current_config;
current_config = c ? c->lxc_conf : NULL;
ret = do_lxcapi_clone(c, newname, lxcpath, flags, bdevtype, bdevdata, newsize, hookargs);
- current_config = old;
+ current_config = NULL;
return ret;
}
static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process)
{
- struct lxc_conf *old = current_config;
int ret;
if (!c)
current_config = c->lxc_conf;
ret = lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process);
- current_config = old;
+ current_config = NULL;
return ret;
}
static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
{
int ret;
- struct lxc_conf *old = current_config;
current_config = c ? c->lxc_conf : NULL;
ret = do_lxcapi_attach_run_wait(c, options, program, argv);
- current_config = old;
+ current_config = NULL;
return ret;
}
WRAP_API_2(bool, lxcapi_detach_interface, const char *, const char *)
-struct criu_opts {
- /* The type of criu invocation, one of "dump" or "restore" */
- char *action;
-
- /* The directory to pass to criu */
- char *directory;
-
- /* The container to dump */
- struct lxc_container *c;
-
- /* Enable criu verbose mode? */
- bool verbose;
-
- /* dump: stop the container or not after dumping? */
- bool stop;
-
- /* restore: the file to write the init process' pid into */
- char *pidfile;
- const char *cgroup_path;
-};
-
-static void exec_criu(struct criu_opts *opts)
-{
- char **argv, log[PATH_MAX];
- int static_args = 14, argc = 0, i, ret;
- int netnr = 0;
- struct lxc_list *it;
-
- struct mntent mntent;
- char buf[4096];
- FILE *mnts = NULL;
-
- /* The command line always looks like:
- * criu $(action) --tcp-established --file-locks --link-remap --force-irmap \
- * --manage-cgroups action-script foo.sh -D $(directory) \
- * -o $(directory)/$(action).log
- * +1 for final NULL */
-
- if (strcmp(opts->action, "dump") == 0) {
- /* -t pid */
- static_args += 2;
-
- /* --leave-running */
- if (!opts->stop)
- static_args++;
- } else if (strcmp(opts->action, "restore") == 0) {
- /* --root $(lxc_mount_point) --restore-detached
- * --restore-sibling --pidfile $foo --cgroup-root $foo */
- static_args += 8;
- } else {
- return;
- }
-
- if (opts->verbose)
- static_args++;
-
- ret = snprintf(log, PATH_MAX, "%s/%s.log", opts->directory, opts->action);
- if (ret < 0 || ret >= PATH_MAX) {
- ERROR("logfile name too long\n");
- return;
- }
-
- // We need to tell criu where cgmanager's socket is bind mounted from
- // if it exists since it's external.
- if (cgroup_driver() == CGMANAGER)
- static_args+=2;
-
- argv = malloc(static_args * sizeof(*argv));
- if (!argv)
- return;
-
- memset(argv, 0, static_args * sizeof(*argv));
-
-#define DECLARE_ARG(arg) \
- do { \
- if (arg == NULL) { \
- ERROR("Got NULL argument for criu"); \
- goto err; \
- } \
- argv[argc++] = strdup(arg); \
- if (!argv[argc-1]) \
- goto err; \
- } while (0)
-
- argv[argc++] = on_path("criu", NULL);
- if (!argv[argc-1]) {
- ERROR("Couldn't find criu binary\n");
- goto err;
- }
-
- DECLARE_ARG(opts->action);
- DECLARE_ARG("--tcp-established");
- DECLARE_ARG("--file-locks");
- DECLARE_ARG("--link-remap");
- DECLARE_ARG("--force-irmap");
- DECLARE_ARG("--manage-cgroups");
- DECLARE_ARG("--action-script");
- DECLARE_ARG(DATADIR "/lxc/lxc-restore-net");
- DECLARE_ARG("-D");
- DECLARE_ARG(opts->directory);
- DECLARE_ARG("-o");
- DECLARE_ARG(log);
-
- if (opts->verbose)
- DECLARE_ARG("-vvvvvv");
-
- /*
- * Note: this macro is not intended to be called unless argc is equal
- * to the length of the array; there is nothing that keeps track of the
- * length of the array besides the location in the code that this is
- * called. (Yes this is bad, and we should fix it.)
- */
-#define RESIZE_ARGS(additional) \
- do { \
- void *m; \
- if (additional < 0) { \
- ERROR("resizing by negative amount"); \
- goto err; \
- } else if (additional == 0) \
- continue; \
- \
- m = realloc(argv, (argc + additional + 1) * sizeof(*argv)); \
- if (!m) \
- goto err; \
- argv = m; \
- } while (0)
-
- if (strcmp(opts->action, "dump") == 0) {
- char pid[32];
-
- if (cgroup_driver() == CGMANAGER) {
- DECLARE_ARG("--ext-mount-map");
- DECLARE_ARG("/sys/fs/cgroup/cgmanager:cgmanager");
- }
-
- if (sprintf(pid, "%d", lxcapi_init_pid(opts->c)) < 0)
- goto err;
-
- DECLARE_ARG("-t");
- DECLARE_ARG(pid);
- if (!opts->stop)
- DECLARE_ARG("--leave-running");
- } else if (strcmp(opts->action, "restore") == 0) {
-
- if (cgroup_driver() == CGMANAGER) {
- DECLARE_ARG("--ext-mount-map");
- DECLARE_ARG("cgmanager:/sys/fs/cgroup/cgmanager");
- }
-
- DECLARE_ARG("--root");
- DECLARE_ARG(opts->c->lxc_conf->rootfs.mount);
- DECLARE_ARG("--restore-detached");
- DECLARE_ARG("--restore-sibling");
- DECLARE_ARG("--pidfile");
- DECLARE_ARG(opts->pidfile);
- DECLARE_ARG("--cgroup-root");
- DECLARE_ARG(opts->cgroup_path);
-
- RESIZE_ARGS(lxc_list_len(&opts->c->lxc_conf->network) * 2);
-
- lxc_list_for_each(it, &opts->c->lxc_conf->network) {
- char eth[128], *veth;
- struct lxc_netdev *n = it->elem;
-
- if (n->name) {
- if (strlen(n->name) >= sizeof(eth))
- goto err;
- strncpy(eth, n->name, sizeof(eth));
- } else
- sprintf(eth, "eth%d", netnr);
-
- veth = n->priv.veth_attr.pair;
-
- ret = snprintf(buf, sizeof(buf), "%s=%s", eth, veth);
- if (ret < 0 || ret >= sizeof(buf))
- goto err;
-
- DECLARE_ARG("--veth-pair");
- DECLARE_ARG(buf);
- }
- }
-
- // CRIU wants to know about any external bind mounts the
- // container has.
- mnts = write_mount_file(&opts->c->lxc_conf->mount_list);
- if (!mnts)
- goto err;
-
- RESIZE_ARGS(lxc_list_len(&opts->c->lxc_conf->mount_list) * 2);
-
- while (getmntent_r(mnts, &mntent, buf, sizeof(buf))) {
- char arg[2048], *key, *val;
- int ret;
-
- if (strcmp(opts->action, "dump") == 0) {
- key = mntent.mnt_fsname;
- val = mntent.mnt_dir;
- } else {
- key = mntent.mnt_dir;
- val = mntent.mnt_fsname;
- }
-
- ret = snprintf(arg, sizeof(arg), "%s:%s", key, val);
- if (ret < 0 || ret >= sizeof(arg)) {
- goto err;
- }
-
- DECLARE_ARG("--ext-mount-map");
- DECLARE_ARG(arg);
- }
- fclose(mnts);
-
- argv[argc] = NULL;
-
- netnr = 0;
- lxc_list_for_each(it, &opts->c->lxc_conf->network) {
- struct lxc_netdev *n = it->elem;
- char veth[128];
-
- /*
- * Here, we set some parameters that lxc-restore-net
- * will examine to figure out the right network to
- * restore.
- */
- snprintf(buf, sizeof(buf), "LXC_CRIU_BRIDGE%d", netnr);
- if (setenv(buf, n->link, 1))
- goto err;
-
- if (strcmp("restore", opts->action) == 0)
- strncpy(veth, n->priv.veth_attr.pair, sizeof(veth));
- else {
- char *tmp;
- ret = snprintf(buf, sizeof(buf), "lxc.network.%d.veth.pair", netnr);
- if (ret < 0 || ret >= sizeof(buf))
- goto err;
- tmp = lxcapi_get_running_config_item(opts->c, buf);
- strncpy(veth, tmp, sizeof(veth));
- free(tmp);
- }
-
- snprintf(buf, sizeof(buf), "LXC_CRIU_VETH%d", netnr);
- if (setenv(buf, veth, 1))
- goto err;
-
- netnr++;
- }
-
-#undef DECLARE_ARG
-#undef RESIZE_ARGS
- execv(argv[0], argv);
-err:
- if (mnts)
- fclose(mnts);
- for (i = 0; argv[i]; i++)
- free(argv[i]);
- free(argv);
-}
-
-/* Check and make sure the container has a configuration that we know CRIU can
- * dump. */
-static bool criu_ok(struct lxc_container *c)
-{
- struct lxc_list *it;
- bool found_deny_rule = false;
-
- if (geteuid()) {
- ERROR("Must be root to checkpoint\n");
- return false;
- }
-
- /* We only know how to restore containers with veth networks. */
- lxc_list_for_each(it, &c->lxc_conf->network) {
- struct lxc_netdev *n = it->elem;
- if (n->type != LXC_NET_VETH && n->type != LXC_NET_NONE) {
- ERROR("Found network that is not VETH or NONE\n");
- return false;
- }
- }
-
- // These requirements come from http://criu.org/LXC
- if (c->lxc_conf->console.path &&
- strcmp(c->lxc_conf->console.path, "none") != 0) {
- ERROR("lxc.console must be none\n");
- return false;
- }
-
- if (c->lxc_conf->tty != 0) {
- ERROR("lxc.tty must be 0\n");
- return false;
- }
-
- lxc_list_for_each(it, &c->lxc_conf->cgroup) {
- struct lxc_cgroup *cg = it->elem;
- if (strcmp(cg->subsystem, "devices.deny") == 0 &&
- strcmp(cg->value, "c 5:1 rwm") == 0) {
-
- found_deny_rule = true;
- break;
- }
- }
-
- if (!found_deny_rule) {
- ERROR("couldn't find devices.deny = c 5:1 rwm");
- return false;
- }
-
- return true;
-}
-
-static bool dump_net_info(struct lxc_container *c, char *directory)
-{
- int netnr;
- struct lxc_list *it;
-
- netnr = 0;
- lxc_list_for_each(it, &c->lxc_conf->network) {
- char *veth = NULL, *bridge = NULL, veth_path[PATH_MAX], eth[128];
- struct lxc_netdev *n = it->elem;
- bool has_error = true;
- int pret;
-
- pret = snprintf(veth_path, PATH_MAX, "lxc.network.%d.veth.pair", netnr);
- if (pret < 0 || pret >= PATH_MAX)
- goto out;
-
- veth = lxcapi_get_running_config_item(c, veth_path);
- if (!veth) {
- /* criu_ok() checks that all interfaces are
- * LXC_NET{VETH,NONE}, and VETHs should have this
- * config */
- assert(n->type == LXC_NET_NONE);
- break;
- }
-
- bridge = lxcapi_get_running_config_item(c, veth_path);
- if (!bridge)
- goto out;
-
- pret = snprintf(veth_path, PATH_MAX, "%s/veth%d", directory, netnr);
- if (pret < 0 || pret >= PATH_MAX || print_to_file(veth_path, veth) < 0)
- goto out;
-
- if (n->name) {
- if (strlen(n->name) >= 128)
- goto out;
- strncpy(eth, n->name, 128);
- } else
- sprintf(eth, "eth%d", netnr);
-
- has_error = false;
-out:
- free(veth);
- free(bridge);
- if (has_error)
- return false;
- }
-
- return true;
-}
-
static bool do_lxcapi_checkpoint(struct lxc_container *c, char *directory, bool stop, bool verbose)
{
pid_t pid;
int status;
+ char path[PATH_MAX];
if (!criu_ok(c))
return false;
if (mkdir(directory, 0700) < 0 && errno != EEXIST)
return false;
- if (!dump_net_info(c, directory))
+ status = snprintf(path, sizeof(path), "%s/inventory.img", directory);
+ if (status < 0 || status >= sizeof(path))
+ return false;
+
+ if (access(path, F_OK) == 0) {
+ ERROR("please use a fresh directory for the dump directory\n");
return false;
+ }
pid = fork();
if (pid < 0)
WRAP_API_3(bool, lxcapi_checkpoint, char *, bool, bool)
-static bool restore_net_info(struct lxc_container *c)
-{
- struct lxc_list *it;
- bool has_error = true;
-
- if (container_mem_lock(c))
- return false;
-
- lxc_list_for_each(it, &c->lxc_conf->network) {
- struct lxc_netdev *netdev = it->elem;
- char template[IFNAMSIZ];
- snprintf(template, sizeof(template), "vethXXXXXX");
-
- if (!netdev->priv.veth_attr.pair)
- netdev->priv.veth_attr.pair = lxc_mkifname(template);
-
- if (!netdev->priv.veth_attr.pair)
- goto out_unlock;
- }
-
- has_error = false;
-
-out_unlock:
- container_mem_unlock(c);
- return !has_error;
-}
-
-// do_restore never returns, the calling process is used as the
-// monitor process. do_restore calls exit() if it fails.
-static void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose)
-{
- pid_t pid;
- char pidfile[L_tmpnam];
- struct lxc_handler *handler;
- int status;
-
- if (!tmpnam(pidfile))
- goto out;
-
- handler = lxc_init(c->name, c->lxc_conf, c->config_path);
- if (!handler)
- goto out;
-
- if (!cgroup_init(handler)) {
- ERROR("failed initing cgroups");
- goto out_fini_handler;
- }
-
- if (!cgroup_create(handler)) {
- ERROR("failed creating groups");
- goto out_fini_handler;
- }
-
- if (!restore_net_info(c)) {
- ERROR("failed restoring network info");
- goto out_fini_handler;
- }
-
- resolve_clone_flags(handler);
-
- pid = fork();
- if (pid < 0)
- goto out_fini_handler;
-
- if (pid == 0) {
- struct criu_opts os;
- struct lxc_rootfs *rootfs;
-
- close(pipe);
- pipe = -1;
-
- if (unshare(CLONE_NEWNS))
- goto out_fini_handler;
-
- /* CRIU needs the lxc root bind mounted so that it is the root of some
- * mount. */
- rootfs = &c->lxc_conf->rootfs;
-
- if (rootfs_is_blockdev(c->lxc_conf)) {
- if (do_rootfs_setup(c->lxc_conf, c->name, c->config_path) < 0)
- goto out_fini_handler;
- } else {
- if (mkdir(rootfs->mount, 0755) < 0 && errno != EEXIST)
- goto out_fini_handler;
-
- if (mount(rootfs->path, rootfs->mount, NULL, MS_BIND, NULL) < 0) {
- rmdir(rootfs->mount);
- goto out_fini_handler;
- }
- }
-
- os.action = "restore";
- os.directory = directory;
- os.c = c;
- os.pidfile = pidfile;
- os.verbose = verbose;
- os.cgroup_path = cgroup_canonical_path(handler);
-
- /* exec_criu() returning is an error */
- exec_criu(&os);
- umount(rootfs->mount);
- rmdir(rootfs->mount);
- goto out_fini_handler;
- } else {
- int ret;
- char title[2048];
-
- pid_t w = waitpid(pid, &status, 0);
- if (w == -1) {
- SYSERROR("waitpid");
- goto out_fini_handler;
- }
-
- ret = write(pipe, &status, sizeof(status));
- close(pipe);
- pipe = -1;
-
- if (sizeof(status) != ret) {
- SYSERROR("failed to write all of status");
- goto out_fini_handler;
- }
-
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status)) {
- goto out_fini_handler;
- } else {
- int ret;
- FILE *f = fopen(pidfile, "r");
- if (!f) {
- SYSERROR("couldn't read restore's init pidfile %s\n", pidfile);
- goto out_fini_handler;
- }
-
- ret = fscanf(f, "%d", (int*) &handler->pid);
- fclose(f);
- if (ret != 1) {
- ERROR("reading restore pid failed");
- goto out_fini_handler;
- }
-
- if (lxc_set_state(c->name, handler, RUNNING))
- goto out_fini_handler;
- }
- } else {
- ERROR("CRIU was killed with signal %d\n", WTERMSIG(status));
- goto out_fini_handler;
- }
-
- /*
- * See comment in lxcapi_start; we don't care if these
- * fail because it's just a beauty thing. We just
- * assign the return here to silence potential.
- */
- ret = snprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name);
- ret = setproctitle(title);
-
- ret = lxc_poll(c->name, handler);
- if (ret)
- lxc_abort(c->name, handler);
- lxc_fini(c->name, handler);
- exit(ret);
- }
-
-out_fini_handler:
- lxc_fini(c->name, handler);
-
-out:
- if (pipe >= 0) {
- status = 1;
- if (write(pipe, &status, sizeof(status)) != sizeof(status)) {
- SYSERROR("writing status failed");
- }
- close(pipe);
- }
-
- exit(1);
-}
-
static bool do_lxcapi_restore(struct lxc_container *c, char *directory, bool verbose)
{
pid_t pid;
if (!c)
return -1;
- struct lxc_conf *old = current_config;
current_config = c->lxc_conf;
va_start(ap, arg);
ret = do_lxcapi_attach_run_wait(c, options, program, (const char * const *)argv);
free((void*)argv);
out:
- current_config = old;
+ current_config = NULL;
return ret;
}
bool (*destroy)(struct lxc_container *c);
/*!
- * \brief Delete the container and all its snapshots.
- *
- * \param c Container.
- *
- * \return \c true on success, else \c false.
- *
- * \note Container must be stopped.
- */
- bool (*destroy_with_snapshots)(struct lxc_container *c);
-
- /*!
* \brief Save configuaration to a file.
*
* \param c Container.
bool (*snapshot_destroy)(struct lxc_container *c, const char *snapname);
/*!
- * \brief Destroy all the container's snapshot.
- *
- * \param c Container.
- *
- * \return \c true on success, else \c false.
- */
- bool (*snapshot_destroy_all)(struct lxc_container *c);
-
- /*!
* \brief Determine if the caller may control the container.
*
* \param c Container.
*/
bool (*remove_device_node)(struct lxc_container *c, const char *src_path, const char *dest_path);
+ /* Post LXC-1.0 additions */
+
/*!
* \brief Add specified netdev to the container.
*
*
*/
bool (*restore)(struct lxc_container *c, char *directory, bool verbose);
+
+ /*!
+ * \brief Delete the container and all its snapshots.
+ *
+ * \param c Container.
+ *
+ * \return \c true on success, else \c false.
+ *
+ * \note Container must be stopped.
+ */
+ bool (*destroy_with_snapshots)(struct lxc_container *c);
+
+ /*!
+ * \brief Destroy all the container's snapshot.
+ *
+ * \param c Container.
+ *
+ * \return \c true on success, else \c false.
+ */
+ bool (*snapshot_destroy_all)(struct lxc_container *c);
+
+ /* Post LXC-1.1 additions */
};
/*!
char *rundir;
/* lockfile will be:
- * "/run" + "/lock/lxc/$lxcpath/$lxcname + '\0' if root
+ * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root
* or
- * $XDG_RUNTIME_DIR + "/lock/lxc/$lxcpath/$lxcname + '\0' if non-root
+ * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root
*/
- /* length of "/lock/lxc/" + $lxcpath + "/" + "." + $lxcname + '\0' */
- len = strlen("/lock/lxc/") + strlen(n) + strlen(p) + 3;
+ /* length of "/lxc/lock/" + $lxcpath + "/" + "." + $lxcname + '\0' */
+ len = strlen("/lxc/lock/") + strlen(n) + strlen(p) + 3;
rundir = get_rundir();
if (!rundir)
return NULL;
return NULL;
}
- ret = snprintf(dest, len, "%s/lock/lxc/%s", rundir, p);
+ ret = snprintf(dest, len, "%s/lxc/lock/%s", rundir, p);
if (ret < 0 || ret >= len) {
free(dest);
free(rundir);
}
ret = mkdir_p(dest, 0755);
if (ret < 0) {
- /* fall back to "/tmp/" + $(id -u) + "/lxc" + $lxcpath + "/" + "." + $lxcname + '\0'
- * * maximum length of $(id -u) is 10 calculated by (log (2 ** (sizeof(uid_t) * 8) - 1) / log 10 + 1)
- * * lxcpath always starts with '/'
- */
- int l2 = 22 + strlen(n) + strlen(p);
- if (l2 > len) {
- char *d;
- d = realloc(dest, l2);
- if (!d) {
- free(dest);
- free(rundir);
- return NULL;
- }
- len = l2;
- dest = d;
- }
- ret = snprintf(dest, len, "/tmp/%d/lxc%s", geteuid(), p);
- if (ret < 0 || ret >= len) {
- free(dest);
- free(rundir);
- return NULL;
- }
- ret = mkdir_p(dest, 0755);
- if (ret < 0) {
- free(dest);
- free(rundir);
- return NULL;
- }
- ret = snprintf(dest, len, "/tmp/%d/lxc%s/.%s", geteuid(), p, n);
- } else
- ret = snprintf(dest, len, "%s/lock/lxc/%s/.%s", rundir, p, n);
+ free(dest);
+ free(rundir);
+ return NULL;
+ }
+ ret = snprintf(dest, len, "%s/lxc/lock/%s/.%s", rundir, p, n);
free(rundir);
-
if (ret < 0 || ret >= len) {
free(dest);
return NULL;
#include <sys/wait.h>
#include <netinet/in.h>
#include <net/if.h>
+#include <poll.h>
#include "error.h"
#include "af_unix.h"
int lxc_monitor_open(const char *lxcpath)
{
struct sockaddr_un addr;
- int fd,ret;
+ int fd,ret = 0;
int retry,backoff_ms[] = {10, 50, 100};
size_t len;
return ret;
}
-int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg,
+int lxc_monitor_read_fdset(struct pollfd *fds, nfds_t nfds, struct lxc_msg *msg,
int timeout)
{
- struct timeval tval,*tv = NULL;
- int ret,i;
-
- if (timeout != -1) {
- tv = &tval;
- tv->tv_sec = timeout;
- tv->tv_usec = 0;
- }
+ long i;
+ int ret;
- ret = select(nfds, rfds, NULL, NULL, tv);
+ ret = poll(fds, nfds, timeout * 1000);
if (ret == -1)
return -1;
else if (ret == 0)
* for when this routine is called again
*/
for (i = 0; i < nfds; i++) {
- if (FD_ISSET(i, rfds)) {
- ret = recv(i, msg, sizeof(*msg), 0);
+ if (fds[i].revents != 0) {
+ fds[i].revents = 0;
+ ret = recv(fds[i].fd, msg, sizeof(*msg), 0);
if (ret <= 0) {
SYSERROR("client failed to recv (monitord died?) %s",
strerror(errno));
int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout)
{
- fd_set rfds;
+ struct pollfd fds;
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
+ fds.fd = fd;
+ fds.events = POLLIN | POLLPRI;
+ fds.revents = 0;
- return lxc_monitor_read_fdset(&rfds, fd+1, msg, timeout);
+ return lxc_monitor_read_fdset(&fds, 1, msg, timeout);
}
int lxc_monitor_read(int fd, struct lxc_msg *msg)
exit(EXIT_FAILURE);
}
lxc_check_inherited(NULL, true, pipefd[1]);
- close(0);
- close(1);
- close(2);
- open("/dev/null", O_RDONLY);
- open("/dev/null", O_RDWR);
- open("/dev/null", O_RDWR);
+ if (null_stdfds() < 0)
+ exit(EXIT_FAILURE);
close(pipefd[0]);
sprintf(pipefd_str, "%d", pipefd[1]);
execvp(args[0], args);
#include <limits.h>
#include <sys/param.h>
#include <sys/un.h>
+#include <poll.h>
#include "conf.h"
int value;
};
-extern int lxc_monitor_open(const char *lxcpath);
extern int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un *addr);
extern int lxc_monitor_fifo_name(const char *lxcpath, char *fifo_path,
size_t fifo_path_sz, int do_mkdirp);
const char *lxcpath);
extern int lxc_monitord_spawn(const char *lxcpath);
+/*
+ * Open the monitoring mechanism for a specific container
+ * The function will return an fd corresponding to the events
+ * Returns a file descriptor on success, < 0 otherwise
+ */
+extern int lxc_monitor_open(const char *lxcpath);
+
+/*
+ * Blocking read for the next container state change
+ * @fd : the file descriptor provided by lxc_monitor_open
+ * @msg : the variable which will be filled with the state
+ * Returns 0 if the monitored container has exited, > 0 if
+ * data was read, < 0 otherwise
+ */
+extern int lxc_monitor_read(int fd, struct lxc_msg *msg);
+
+/*
+ * Blocking read for the next container state change with timeout
+ * @fd : the file descriptor provided by lxc_monitor_open
+ * @msg : the variable which will be filled with the state
+ * @timeout : the timeout in seconds to wait for a state change
+ * Returns 0 if the monitored container has exited, > 0 if
+ * data was read, < 0 otherwise
+ */
+extern int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout);
+
+/*
+ * Blocking read from multiple monitors for the next container state
+ * change with timeout
+ * @fds : struct pollfd descripting the fds to use
+ * @nfds : the number of entries in fds
+ * @msg : the variable which will be filled with the state
+ * @timeout : the timeout in seconds to wait for a state change
+ * Returns 0 if the monitored container has exited, > 0 if
+ * data was read, < 0 otherwise
+ */
+extern int lxc_monitor_read_fdset(struct pollfd *fds, nfds_t nfds, struct lxc_msg *msg,
+ int timeout);
+
+
#endif
uint32_t default_policy_action = -1, default_rule_action = -1, action;
enum lxc_hostarch_t native_arch = get_hostarch(),
cur_rule_arch = native_arch;
+ uint32_t compat_arch = SCMP_ARCH_NATIVE;
if (strncmp(line, "blacklist", 9) == 0)
blacklist = true;
if (native_arch == lxc_seccomp_arch_amd64) {
cur_rule_arch = lxc_seccomp_arch_all;
+ compat_arch = SCMP_ARCH_X86;
compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
default_policy_action);
if (!compat_ctx)
continue;
}
cur_rule_arch = lxc_seccomp_arch_i386;
- if (native_arch == lxc_seccomp_arch_amd64) {
- if (compat_ctx)
- continue;
- compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
- default_policy_action);
- if (!compat_ctx)
- goto bad;
- }
} else if (strcmp(line, "[X86_64]") == 0 ||
strcmp(line, "[x86_64]") == 0) {
if (native_arch != lxc_seccomp_arch_amd64) {
} else if (strcmp(line, "[all]") == 0 ||
strcmp(line, "[ALL]") == 0) {
cur_rule_arch = lxc_seccomp_arch_all;
- if (native_arch == lxc_seccomp_arch_amd64 && !compat_ctx) {
- if (compat_ctx)
- continue;
- compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
- default_policy_action);
- if (!compat_ctx)
- goto bad;
- }
}
#ifdef SCMP_ARCH_ARM
else if (strcmp(line, "[arm]") == 0 ||
goto bad_rule;
}
- /*
- * TODO generalize - if !is_compat_only(native_arch, cur_rule_arch)
- *
- * in other words, the rule is 32-bit only, on 64-bit host; don't run
- * the rule against the native arch.
- */
- if (!(cur_rule_arch == lxc_seccomp_arch_i386 &&
- native_arch == lxc_seccomp_arch_amd64)) {
- INFO("Adding non-compat rule for %s action %d", line, action);
+ if (cur_rule_arch == native_arch ||
+ cur_rule_arch == lxc_seccomp_arch_native ||
+ compat_arch == SCMP_ARCH_NATIVE) {
+ INFO("Adding native rule for %s action %d", line, action);
if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
goto bad_rule;
}
-
- /*
- * TODO generalize - if need_compat(native_arch, cur_rule_arch)
- */
- if (native_arch == lxc_seccomp_arch_amd64 &&
- cur_rule_arch != lxc_seccomp_arch_amd64) {
- int nr1, nr2;
+ else if (cur_rule_arch != lxc_seccomp_arch_all) {
+ INFO("Adding compat-only rule for %s action %d", line, action);
+ if (!do_resolve_add_rule(compat_arch, line, compat_ctx, action))
+ goto bad_rule;
+ }
+ else {
+ INFO("Adding native rule for %s action %d", line, action);
+ if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
+ goto bad_rule;
INFO("Adding compat rule for %s action %d", line, action);
- nr1 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_X86, line);
- nr2 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE, line);
- if (nr1 == nr2) {
- /* If the syscall # is the same for 32- and 64-bit, then we cannot
- * apply it to the compat_ctx. So apply it to the noncompat ctx.
- * We may already have done so, but that's ok
- */
- INFO("Adding non-compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2);
- if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
- goto bad_rule;
- continue;
- }
- INFO("Really adding compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2);
- if (!do_resolve_add_rule(SCMP_ARCH_X86, line,
- compat_ctx, action))
+ if (!do_resolve_add_rule(compat_arch, line, compat_ctx, action))
goto bad_rule;
}
}
if (fd == fddir || fd == lxc_log_fd || fd == fd_to_ignore)
continue;
+ if (current_config && fd == current_config->logfd)
+ continue;
+
if (match_fd(fd))
continue;
close(handler->sigfd);
+ if (handler->backgrounded && null_stdfds() < 0)
+ goto out_warn_father;
+
/* after this call, we are in error because this
* ops should not return as it execs */
handler->ops->start(handler, handler->data);
}
int __lxc_start(const char *name, struct lxc_conf *conf,
- struct lxc_operations* ops, void *data, const char *lxcpath)
+ struct lxc_operations* ops, void *data, const char *lxcpath,
+ bool backgrounded)
{
struct lxc_handler *handler;
int err = -1;
}
handler->ops = ops;
handler->data = data;
+ handler->backgrounded = backgrounded;
if (must_drop_cap_sys_boot(handler->conf)) {
#if HAVE_SYS_CAPABILITY_H
goto out_detach_blockdev;
}
+ handler->conf->reboot = 0;
+
netnsfd = get_netns_fd(handler->pid);
err = lxc_poll(name, handler);
};
int lxc_start(const char *name, char *const argv[], struct lxc_conf *conf,
- const char *lxcpath)
+ const char *lxcpath, bool backgrounded)
{
struct start_args start_arg = {
.argv = argv,
};
conf->need_utmp_watch = 1;
- return __lxc_start(name, conf, &start_ops, &start_arg, lxcpath);
+ return __lxc_start(name, conf, &start_ops, &start_arg, lxcpath, backgrounded);
}
const char *lxcpath;
void *cgroup_data;
int ttysock[2]; // socketpair for child->parent tty fd passing
+ bool backgrounded; // indicates whether should we close std{in,out,err} on start
};
extern int lxc_check_inherited(struct lxc_conf *conf, bool closeall, int fd_to_ignore);
int __lxc_start(const char *, struct lxc_conf *, struct lxc_operations *,
- void *, const char *);
+ void *, const char *, bool);
extern void resolve_clone_flags(struct lxc_handler *handler);
#endif
lxc_log_define(lxc_utils, lxc);
+/*
+ * if path is btrfs, tries to remove it and any subvolumes beneath it
+ */
+extern bool btrfs_try_remove_subvol(const char *path);
+
static int _recursive_rmdir(char *dirname, dev_t pdev,
const char *exclude, int level, bool onedev)
{
ret = lstat(pathname, &mystat);
if (ret) {
ERROR("%s: failed to stat %s", __func__, pathname);
- failed=1;
+ failed = 1;
continue;
}
- if (onedev && mystat.st_dev != pdev)
+ if (onedev && mystat.st_dev != pdev) {
+ /* TODO should we be checking /proc/self/mountinfo for
+ * pathname and not doing this if found? */
+ if (btrfs_try_remove_subvol(pathname))
+ INFO("Removed btrfs subvolume at %s\n", pathname);
continue;
+ }
if (S_ISDIR(mystat.st_mode)) {
if (_recursive_rmdir(pathname, pdev, exclude, level+1, onedev) < 0)
failed=1;
}
}
- if (rmdir(dirname) < 0) {
- if (!hadexclude) {
- ERROR("%s: failed to delete %s", __func__, dirname);
- failed=1;
- }
+ if (rmdir(dirname) < 0 && !btrfs_try_remove_subvol(dirname) && !hadexclude) {
+ ERROR("%s: failed to delete %s", __func__, dirname);
+ failed=1;
}
ret = closedir(dir);
return _recursive_rmdir(path, mystat.st_dev, exclude, 0, onedev);
}
-static int mount_fs(const char *source, const char *target, const char *type)
-{
- /* the umount may fail */
- if (umount(target))
- WARN("failed to unmount %s : %s", target, strerror(errno));
-
- if (mount(source, target, type, 0, NULL)) {
- ERROR("failed to mount %s : %s", target, strerror(errno));
- return -1;
- }
-
- DEBUG("'%s' mounted on '%s'", source, target);
-
- return 0;
-}
-
-extern void lxc_setup_fs(void)
-{
- if (mount_fs("proc", "/proc", "proc"))
- INFO("failed to remount proc");
-
- /* if we can't mount /dev/shm, continue anyway */
- if (mount_fs("shmfs", "/dev/shm", "tmpfs"))
- INFO("failed to mount /dev/shm");
-
- /* If we were able to mount /dev/shm, then /dev exists */
- /* Sure, but it's read-only per config :) */
- if (access("/dev/mqueue", F_OK) && mkdir("/dev/mqueue", 0666)) {
- DEBUG("failed to create '/dev/mqueue'");
- return;
- }
-
- /* continue even without posix message queue support */
- if (mount_fs("mqueue", "/dev/mqueue", "mqueue"))
- INFO("failed to mount /dev/mqueue");
-}
-
/* borrowed from iproute2 */
extern int get_u16(unsigned short *val, const char *arg, int base)
{
return 0;
}
-extern void remove_trailing_slashes(char *p)
-{
- int l = strlen(p);
- while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
- p[l] = '\0';
-}
-
-static char *copy_global_config_value(char *p)
-{
- int len = strlen(p);
- char *retbuf;
-
- if (len < 1)
- return NULL;
- if (p[len-1] == '\n') {
- p[len-1] = '\0';
- len--;
- }
- retbuf = malloc(len+1);
- if (!retbuf)
- return NULL;
- strcpy(retbuf, p);
- return retbuf;
-}
-
-#define DEFAULT_VG "lxc"
-#define DEFAULT_THIN_POOL "lxc"
-#define DEFAULT_ZFSROOT "lxc"
-
-const char *lxc_global_config_value(const char *option_name)
-{
- static const char * const options[][2] = {
- { "lxc.bdev.lvm.vg", DEFAULT_VG },
- { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL },
- { "lxc.bdev.zfs.root", DEFAULT_ZFSROOT },
- { "lxc.lxcpath", NULL },
- { "lxc.default_config", NULL },
- { "lxc.cgroup.pattern", NULL },
- { "lxc.cgroup.use", NULL },
- { NULL, NULL },
- };
-
- /* placed in the thread local storage pool for non-bionic targets */
-#ifdef HAVE_TLS
- static __thread const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
-#else
- static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
-#endif
-
- /* user_config_path is freed as soon as it is used */
- char *user_config_path = NULL;
-
- /*
- * The following variables are freed at bottom unconditionally.
- * So NULL the value if it is to be returned to the caller
- */
- char *user_default_config_path = NULL;
- char *user_lxc_path = NULL;
- char *user_cgroup_pattern = NULL;
-
- if (geteuid() > 0) {
- const char *user_home = getenv("HOME");
- if (!user_home)
- user_home = "/";
-
- user_config_path = malloc(sizeof(char) * (22 + strlen(user_home)));
- user_default_config_path = malloc(sizeof(char) * (26 + strlen(user_home)));
- user_lxc_path = malloc(sizeof(char) * (19 + strlen(user_home)));
-
- sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home);
- sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home);
- sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home);
- user_cgroup_pattern = strdup("lxc/%n");
- }
- else {
- user_config_path = strdup(LXC_GLOBAL_CONF);
- user_default_config_path = strdup(LXC_DEFAULT_CONFIG);
- user_lxc_path = strdup(LXCPATH);
- user_cgroup_pattern = strdup(DEFAULT_CGROUP_PATTERN);
- }
-
- const char * const (*ptr)[2];
- size_t i;
- char buf[1024], *p, *p2;
- FILE *fin = NULL;
-
- for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) {
- if (!strcmp(option_name, (*ptr)[0]))
- break;
- }
- if (!(*ptr)[0]) {
- free(user_config_path);
- free(user_default_config_path);
- free(user_lxc_path);
- free(user_cgroup_pattern);
- errno = EINVAL;
- return NULL;
- }
-
- if (values[i]) {
- free(user_config_path);
- free(user_default_config_path);
- free(user_lxc_path);
- free(user_cgroup_pattern);
- return values[i];
- }
-
- fin = fopen_cloexec(user_config_path, "r");
- free(user_config_path);
- if (fin) {
- while (fgets(buf, 1024, fin)) {
- if (buf[0] == '#')
- continue;
- p = strstr(buf, option_name);
- if (!p)
- continue;
- /* see if there was just white space in front
- * of the option name
- */
- for (p2 = buf; p2 < p; p2++) {
- if (*p2 != ' ' && *p2 != '\t')
- break;
- }
- if (p2 < p)
- continue;
- p = strchr(p, '=');
- if (!p)
- continue;
- /* see if there was just white space after
- * the option name
- */
- for (p2 += strlen(option_name); p2 < p; p2++) {
- if (*p2 != ' ' && *p2 != '\t')
- break;
- }
- if (p2 < p)
- continue;
- p++;
- while (*p && (*p == ' ' || *p == '\t')) p++;
- if (!*p)
- continue;
-
- if (strcmp(option_name, "lxc.lxcpath") == 0) {
- free(user_lxc_path);
- user_lxc_path = copy_global_config_value(p);
- remove_trailing_slashes(user_lxc_path);
- values[i] = user_lxc_path;
- user_lxc_path = NULL;
- goto out;
- }
-
- values[i] = copy_global_config_value(p);
- goto out;
- }
- }
- /* could not find value, use default */
- if (strcmp(option_name, "lxc.lxcpath") == 0) {
- remove_trailing_slashes(user_lxc_path);
- values[i] = user_lxc_path;
- user_lxc_path = NULL;
- }
- else if (strcmp(option_name, "lxc.default_config") == 0) {
- values[i] = user_default_config_path;
- user_default_config_path = NULL;
- }
- else if (strcmp(option_name, "lxc.cgroup.pattern") == 0) {
- values[i] = user_cgroup_pattern;
- user_cgroup_pattern = NULL;
- }
- else
- values[i] = (*ptr)[1];
-
- /* special case: if default value is NULL,
- * and there is no config, don't view that
- * as an error... */
- if (!values[i])
- errno = 0;
-
-out:
- if (fin)
- fclose(fin);
-
- free(user_cgroup_pattern);
- free(user_default_config_path);
- free(user_lxc_path);
-
- return values[i];
-}
-
char *get_rundir()
{
char *rundir;
return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0);
}
-FILE *fopen_cloexec(const char *path, const char *mode)
-{
- int open_mode = 0;
- int step = 0;
- int fd;
- int saved_errno = 0;
- FILE *ret;
-
- if (!strncmp(mode, "r+", 2)) {
- open_mode = O_RDWR;
- step = 2;
- } else if (!strncmp(mode, "r", 1)) {
- open_mode = O_RDONLY;
- step = 1;
- } else if (!strncmp(mode, "w+", 2)) {
- open_mode = O_RDWR | O_TRUNC | O_CREAT;
- step = 2;
- } else if (!strncmp(mode, "w", 1)) {
- open_mode = O_WRONLY | O_TRUNC | O_CREAT;
- step = 1;
- } else if (!strncmp(mode, "a+", 2)) {
- open_mode = O_RDWR | O_CREAT | O_APPEND;
- step = 2;
- } else if (!strncmp(mode, "a", 1)) {
- open_mode = O_WRONLY | O_CREAT | O_APPEND;
- step = 1;
- }
- for (; mode[step]; step++)
- if (mode[step] == 'x')
- open_mode |= O_EXCL;
- open_mode |= O_CLOEXEC;
-
- fd = open(path, open_mode, 0666);
- if (fd < 0)
- return NULL;
-
- ret = fdopen(fd, mode);
- saved_errno = errno;
- if (!ret)
- close(fd);
- errno = saved_errno;
- return ret;
-}
-
extern struct lxc_popen_FILE *lxc_popen(const char *command)
{
struct lxc_popen_FILE *fp = NULL;
if (len >= arg_end - arg_start) {
env_start = env_end;
}
+
arg_end = arg_start + len;
+
+ /* check overflow */
+ if (arg_end < len || arg_end < arg_start) {
+ return -1;
+ }
+
}
strcpy((char*)arg_start, title);
- ret |= prctl(PR_SET_MM, PR_SET_MM_ARG_START, (long)arg_start, 0, 0);
- ret |= prctl(PR_SET_MM, PR_SET_MM_ARG_END, (long)arg_end, 0, 0);
- ret |= prctl(PR_SET_MM, PR_SET_MM_ENV_START, (long)env_start, 0, 0);
- ret |= prctl(PR_SET_MM, PR_SET_MM_ENV_END, (long)env_end, 0, 0);
+ ret |= prctl(PR_SET_MM, PR_SET_MM_ARG_START, arg_start, 0, 0);
+ ret |= prctl(PR_SET_MM, PR_SET_MM_ARG_END, arg_end, 0, 0);
+ ret |= prctl(PR_SET_MM, PR_SET_MM_ENV_START, env_start, 0, 0);
+ ret |= prctl(PR_SET_MM, PR_SET_MM_ENV_END, env_end, 0, 0);
+
+ return ret;
+}
+
+/*
+ * Mount a proc under @rootfs if proc self points to a pid other than
+ * my own. This is needed to have a known-good proc mount for setting
+ * up LSMs both at container startup and attach.
+ *
+ * @rootfs : the rootfs where proc should be mounted
+ *
+ * Returns < 0 on failure, 0 if the correct proc was already mounted
+ * and 1 if a new proc was mounted.
+ */
+int mount_proc_if_needed(const char *rootfs)
+{
+ char path[MAXPATHLEN];
+ char link[20];
+ int linklen, ret;
+ int mypid;
+
+ ret = snprintf(path, MAXPATHLEN, "%s/proc/self", rootfs);
+ if (ret < 0 || ret >= MAXPATHLEN) {
+ SYSERROR("proc path name too long");
+ return -1;
+ }
+ memset(link, 0, 20);
+ linklen = readlink(path, link, 20);
+ mypid = (int)getpid();
+ INFO("I am %d, /proc/self points to '%s'", mypid, link);
+ ret = snprintf(path, MAXPATHLEN, "%s/proc", rootfs);
+ if (linklen < 0) /* /proc not mounted */
+ goto domount;
+ if (atoi(link) != mypid) {
+ /* wrong /procs mounted */
+ umount2(path, MNT_DETACH); /* ignore failure */
+ goto domount;
+ }
+ /* the right proc is already mounted */
+ return 0;
+
+domount:
+ if (mount("proc", path, "proc", 0, NULL))
+ return -1;
+ INFO("Mounted /proc in container for security transition");
+ return 1;
+}
+int null_stdfds(void)
+{
+ int fd, ret = -1;
+
+ fd = open("/dev/null", O_RDWR);
+ if (fd < 0)
+ return -1;
+
+ if (dup2(fd, 0) < 0)
+ goto err;
+ if (dup2(fd, 1) < 0)
+ goto err;
+ if (dup2(fd, 2) < 0)
+ goto err;
+
+ ret = 0;
+err:
+ close(fd);
return ret;
}
#include <unistd.h>
#include "config.h"
+#include "initutils.h"
/* returns 1 on success, 0 if there were any failures */
extern int lxc_rmdir_onedev(char *path, const char *exclude);
-extern void lxc_setup_fs(void);
extern int get_u16(unsigned short *val, const char *arg, int base);
extern int mkdir_p(const char *dir, mode_t mode);
-extern void remove_trailing_slashes(char *p);
extern char *get_rundir(void);
-extern const char *lxc_global_config_value(const char *option_name);
-
/* Define getline() if missing from the C library */
#ifndef HAVE_GETLINE
#ifdef HAVE_FGETLN
}
#endif
-/* open a file with O_CLOEXEC */
-FILE *fopen_cloexec(const char *path, const char *mode);
-
-
/* Struct to carry child pid from lxc_popen() to lxc_pclose().
* Not an opaque struct to allow direct access to the underlying FILE *
* (i.e., struct lxc_popen_FILE *file; fgets(buf, sizeof(buf), file->f))
#define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL)
uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval);
-#endif
int detect_shared_rootfs(void);
int detect_ramfs_rootfs(void);
int is_dir(const char *path);
char *get_template_path(const char *t);
int setproctitle(char *title);
+int mount_proc_if_needed(const char *rootfs);
+int null_stdfds(void);
+#endif /* __LXC_UTILS_H */
#define LXC_VERSION_MAJOR 1
#define LXC_VERSION_MINOR 1
-#define LXC_VERSION_MICRO 2
-#define LXC_VERSION "1.1.2"
+#define LXC_VERSION_MICRO 3
+#define LXC_VERSION "1.1.3"
#endif
exit(1);
}
struct stat sb;
- char *pathname = RUNTIME_PATH "/lock/lxc/var/lib/lxc/";
+ char *pathname = RUNTIME_PATH "/lxc/lock/var/lib/lxc/";
ret = stat(pathname, &sb);
if (ret != 0) {
fprintf(stderr, "%d: filename %s not created\n", __LINE__,
# The first time this usually fails because CRIU cannot checkpoint things with
# data on a socket.
lxc-checkpoint -n $name -v -s -D /tmp/checkpoint || FAIL "failed checkpointing"
-lxc-wait -n u1 -s STOPPED
+lxc-wait -n $name -s STOPPED
lxc-checkpoint -n $name -v -r -D /tmp/checkpoint || FAIL "failed restoring"
lxc-stop -n $name -t 1
# verify the static apk binary signature
APK=$rootfs/sbin/apk.static
- openssl dgst -verify $rootfs/etc/apk/keys/$keyname \
+ openssl dgst -sha1 -verify $rootfs/etc/apk/keys/$keyname \
-signature "$APK.SIGN.RSA.$keyname" "$APK" || return 1
if [ "$auto_repo_dir" ]; then
# mounts point
lxc.mount.auto=cgroup:mixed proc:mixed sys:mixed
lxc.mount.entry=run run tmpfs nodev,noexec,nosuid,relatime,size=1m,mode=0755 0 0
-lxc.mount.entry=shm dev/shm tmpfs nodev,nosuid,noexec,mode=1777 0 0
+lxc.mount.entry=shm dev/shm tmpfs nodev,nosuid,noexec,mode=1777,create=dir 0 0
EOF
NM_CONTROLLED=no
TYPE=Ethernet
MTU=${MTU}
-DHCP_HOSTNAME=$name
+DHCP_HOSTNAME=\`hostname\`
EOF
# set the hostname
# download a mini centos into a cache
echo "Downloading centos minimal ..."
+ YUM0="yum --installroot $INSTALL_ROOT -y --nogpgcheck"
+
if yum -h | grep -q 'releasever=RELEASEVER'; then
- YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck --releasever=$release"
+ YUM="$YUM0 --releasever=$release"
else
- YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck"
+ YUM="$YUM0"
fi
PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils"
mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/urandom c 1 9
mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum
cp -al $INSTALL_ROOT/var/cache/yum/* $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum/
- chroot $INSTALL_ROOT $YUM install $PKG_LIST
+ chroot $INSTALL_ROOT $YUM0 install $PKG_LIST
if [ $? -ne 0 ]; then
echo "Failed to download the rootfs, aborting."
return 1
# Make sure the usual locations are in PATH
export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
+export GREP_OPTIONS=""
MIRROR=${MIRROR:-http://http.debian.net/debian}
SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.debian.org/}
EOF
# reconfigure some services
- if [ -z "$LANG" ]; then
- chroot $rootfs locale-gen en_US.UTF-8 UTF-8
- chroot $rootfs update-locale LANG=en_US.UTF-8
- else
- encoding=$(echo $LANG | cut -d. -f2)
- chroot $rootfs sed -e "s/^# \(${LANG} ${encoding}\)/\1/" \
- -i /etc/locale.gen 2> /dev/null
- chroot $rootfs locale-gen $LANG $encoding
- chroot $rootfs update-locale LANG=$LANG
- fi
# remove pointless services in a container
chroot $rootfs /usr/sbin/update-rc.d -f checkroot.sh disable
cat >> "${rootfs}/etc/apt/sources.list" << EOF
${prefix} $MIRROR ${release} main contrib non-free
+EOF
+
+ if [ "$release" != "unstable" -a "$release" != "sid" ]; then
+ cat >> "${rootfs}/etc/apt/sources.list" << EOF
${prefix} $SECURITY_MIRROR ${release}/updates main contrib non-free
EOF
+ fi
}
install_packages()
mkdir -p ${rootfs}/{lib,etc}/systemd/system
mkdir -p ${rootfs}/etc/systemd/system/getty.target.wants
+ # Fix getty-static-service as debootstrap does not install dbus
+ if [ -e $rootfs//lib/systemd/system/getty-static.service ] ; then
+ sed 's/ getty@tty[5-9].service//g' $rootfs/lib/systemd/system/getty-static.service | sed 's/\(tty2-tty\)[5-9]/\14/g' > $rootfs/etc/systemd/system/getty-static.service
+ fi
+
# This function has been copied and adapted from lxc-fedora
rm -f ${rootfs}/etc/systemd/system/default.target
chroot ${rootfs} ln -s /dev/null /etc/systemd/system/udev.service
# Re-enable service startup
rm ${rootfs}/usr/sbin/policy-rc.d
+
+ # reconfigure locales
+ if [ -z "$LANG" ]; then
+ cat >> $rootfs/etc/locale.gen << EOF
+en_US.UTF-8 UTF-8
+EOF
+ chroot $rootfs locale-gen en_US.UTF-8 UTF-8
+ chroot $rootfs update-locale LANG=en_US.UTF-8
+ else
+ encoding=$(echo $LANG | cut -d. -f2)
+ chroot $rootfs sed -e "s/^# \(${LANG} ${encoding}\)/\1/" \
+ -i /etc/locale.gen 2> /dev/null
+ cat >> $rootfs/etc/locale.gen << EOF
+$LANG $encoding
+EOF
+ chroot $rootfs locale-gen $LANG $encoding
+ chroot $rootfs update-locale LANG=$LANG
+ fi
+ # end
}
clean()
BOOTPROTO=dhcp
ONBOOT=yes
HOSTNAME=${utsname}
+DHCP_HOSTNAME=\`hostname\`
NM_CONTROLLED=no
TYPE=Ethernet
MTU=${MTU}
# Right now, we are using Fedora 20 for the inial bootstrap.
# We could make this the "current" Fedora rev (F > 15).
- rsync -av mirrors.kernel.org::fedora/releases/20/Fedora/$basearch/os/LiveOS .
+ rsync -av ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/LiveOS .
if [[ 0 == $? ]]
then
# of this LiveOS image we're camped out on. This is the beginning
# of the butt ugly hack. Look close or you may missing it...
- rsync -av mirrors.kernel.org::fedora/releases/20/Fedora/$basearch/os/Packages/r/rpm-[0-9]* \
- mirrors.kernel.org::fedora/releases/20/Fedora/$basearch/os/Packages/y/yum-[0-9]* .
+ rsync -av ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/Packages/r/rpm-[0-9]* \
+ ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/Packages/y/yum-[0-9]* .
# And here it is...
# The --nodeps is STUPID but F15 had a bogus dependency on RawHide?!?!
echo "Stage 1 creation complete. Building stage 2 Installation Bootstrap"
mount -o bind ../bootstrap run/install
- rsync -av mirrors.kernel.org::fedora/releases/20/Fedora/$basearch/os/Packages/f/fedora-release-20* .
+ rsync -av ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/Packages/f/fedora-release-20* .
# The --nodeps is STUPID but F15 had a bogus dependency on RawHide?!?!
chroot . rpm --root /run/install --nodeps -ivh fedora-release-*
exit 0
fi
-
basearch=${arch}
# Map a few architectures to their generic Fedora repository archs.
# The two ARM archs are a bit of a guesstimate for the v5 and v6
*) ;;
esac
+mirrorurl="archives.fedoraproject.org::fedora-archive"
+case "$basearch" in
+ppc64|s390x) mirrorurl="archives.fedoraproject.org::fedora-secondary" ;;
+*) ;;
+esac
+
# Somebody wants to specify an arch. This is very limited case.
# i386/i586/i686 on i386/x86_64
# - or -
if [ "$is_fedora" -a "$fedora_host_ver" ]; then
release=$fedora_host_ver
else
- echo "This is not a fedora host and release missing, defaulting to 20 use -R|--release to specify release"
- release=20
+ echo "This is not a fedora host and release missing, defaulting to 22 use -R|--release to specify release"
+ release=22
fi
fi
fi
if grep -q Harlequin /etc/os-release || grep -q Tumbleweed /etc/os-release ; then
- if [[ "$(zypper info build|awk -F "[- ]" '/Version/ {print $2}')" -lt "20141120" ]] ; then
+ BVER=`rpm -q --qf '%{version}\n' build`
+ if [ $? -ne 0 -o "$BVER" -lt "20141120" ]; then
echo "Building openSUSE containers with your version of the build package is broken. Please install the update to version 20141120 or newer."
exit 1
fi
fi
fi
if [ $container_release_major = "6" ]; then
- sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mkdir -p /dev/shm && mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.sysinit
- sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mkdir -p /dev/shm && mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.d/rc.sysinit
+ sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mkdir -p /dev/shm \&\& mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.sysinit
+ sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mkdir -p /dev/shm \&\& mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.d/rc.sysinit
fi
# there might be other services that are useless but the below set is a good start
BOOTPROTO=dhcp
ONBOOT=yes
HOSTNAME=$name
-DHCP_HOSTNAME=$name
+DHCP_HOSTNAME=\`hostname\`
NM_CONTROLLED=no
TYPE=Ethernet
EOF