X-Git-Url: http://git.linux-vserver.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=scripts%2Fvserver.functions;h=1dc880a73a5111d42a983bf307af803a2e4e4c50;hb=e43cea82e4ad142e96689656d952d7f3c2f8c68b;hp=6570993263575bc8c388c755e06fe561ef94778b;hpb=93c4a7d40d5bedb16f2cdc9f8fb7629418275a9f;p=util-vserver.git diff --git a/scripts/vserver.functions b/scripts/vserver.functions index 6570993..1dc880a 100644 --- a/scripts/vserver.functions +++ b/scripts/vserver.functions @@ -20,7 +20,8 @@ # $VSERVER_NAME ... name of vserver declare -a NICE_CMD=() -declare -a CHBIND_OPTS=() +declare -a IONICE_CMD=() +declare -a CHBIND_CMD=() declare -a CAP_OPTS=() declare -a CHCONTEXT_INIT_OPTS=() declare -a CHCONTEXT_FLAG_OPTS=() @@ -40,9 +41,16 @@ declare -a ENTER_SHELL=() declare -a OPTS_VCONTEXT_CREATE=() declare -a OPTS_VCONTEXT_MIGRATE=() declare -a OPTS_VCONTEXT_ENTER=() +OPT_VCONTEXT_CHROOT=--chroot declare -a OPTS_VATTRIBUTE=( --flag fakeinit ) declare -a OPTS_VSCHED=() declare -a OPTS_ENV=() +declare -a OPTS_VTAG_CREATE=() +declare -a OPTS_VTAG_ENTER=() +declare -a OPTS_VMEMCTRL=() +declare -a OPTS_VSPACE=( --default ) +declare -a OPTS_VSPACE_SHARED=() +declare -a VSPACE_SHARED_CMD=() declare -a STOPCMD_PREPARE=() @@ -62,9 +70,15 @@ _IS_FAKEINIT= INITSTYLE=sysv S_CONTEXT= +N_CONTEXT= SILENT_OPT= +CGROUP_MNT=/dev/cgroup +CGROUP_SUBSYS=all +declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems ) +CGROUP_BASE="" + : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")} if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then @@ -73,26 +87,54 @@ else SILENT_OPT='--silent' fi +function _readFileToArray +{ + local _rfta_f="$1" + local _rfta_a="$2" + local _rfta_p="$3" + local _rfta_v + + test -e "$_rfta_f" || return 0 + while read _rfta_v; do + case x"$_rfta_v" in + (x|x\#*) ;; + (*) eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";; + esac + done <"$_rfta_f" +} + function _generateChbindOptions { local vdir="$1" local i local bcast= + local lback= local nid= test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir" - local f=$vdir/interfaces/bcast + if test -e "$vdir"/noncontext -o \ + \( -e "$vdir"/spaces/net -a ! -e "$vdir"/ncontext \); then + _HAVE_CHBIND_OPTIONS=1 + return 0 + fi + + local f="$vdir"/interfaces/bcast getFileValue bcast "$f" + f="$vdir"/interfaces/lback + getFileValue lback "$f" - getFileValue nid "$vdir/ncontext" "$vdir/context" - - CHBIND_OPTS=( $SILENT_OPT ${nid:+--nid "$nid"} ${bcast:+--bcast "$bcast"} ) + CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"} + ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"} + ) for i in "${INTERFACES[@]}"; do - CHBIND_OPTS=( "${CHBIND_OPTS[@]}" --ip "$i" ) + CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" ) done + _readFileToArray "$vdir"/nflags CHBIND_CMD --flag + _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap + _HAVE_CHBIND_OPTIONS=1 } @@ -108,6 +150,19 @@ function _generateNiceCommand NICE_CMD=( $_NICE -n $nice ) } +function _generateIONiceCommand +{ + local vdir=$1 + local ionice_class=2 + local ionice_priority=0 + + test -n "$_IONICE" || return 0 + + test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class + test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority + + IONICE_CMD=( $_IONICE -c$ionice_class -n$ionice_priority ) +} function _generatePersonalityOptions { @@ -139,31 +194,15 @@ function _generatePersonalityOptions function _generateCCapabilityOptions { local vdir=$1 - local cap - local f="$vdir"/ccapabilities - - test -e "$f" || return 0 - while read cap; do - case x"$cap" in - (x|x\#*) ;; - (*) OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --ccap "$cap" );; - esac - done <"$f" + + _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap } function _generateBCapabilityOptions { local vdir=$1 - local cap - local f="$vdir"/bcapabilities - - test -e "$f" || return 0 - while read cap; do - case x"$cap" in - (x|x\#*) ;; - (*) OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --bcap "$cap" );; - esac - done <"$f" + + _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap } function _generateCapabilityOptions @@ -247,7 +286,8 @@ function _generateInitOptions CHCONTEXT_INIT_OPTS=() - getFileValue INITSTYLE "$cfgdir"/style + test x"$INITSTYLE" = xrescue || \ + getFileValue INITSTYLE "$cfgdir"/style getFileValue RUNLEVEL_START "$cfgdir"/runlevel getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop @@ -262,8 +302,6 @@ function _generateInitOptions (xrescue) INITCMD_START=( "${INITCMD_RESCUE[@]}" ) INITCMD_STOP=( /sbin/killall5 ) - _IS_FAKEINIT=1 - _NEED_VSHELPER_SYNC= ;; (xsysv) @@ -276,6 +314,11 @@ function _generateInitOptions INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" ) done INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp ) + OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" ) + if test -n "$OPTION_DEBUG_SYSV"; then + INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" ) + INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" ) + fi ;; (xplain) @@ -300,25 +343,27 @@ function _generateInitOptions (xgentoo) test -n "$RUNLEVEL_START" || RUNLEVEL_START="default" + RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin + + if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then + RC_WRAP=/lib/rcscripts/sh/init-vserver.sh + elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then + RC_WRAP=/lib/rc/sh/init-vserver.sh + else + panic "init-vserver.sh not found; aborting" + fi - INITCMD_START=( /lib/rcscripts/sh/init-vserver.sh "$RUNLEVEL_START" ) - INITCMD_STOP=( /sbin/rc shutdown ) + OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM ) + INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" ) + INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown ) INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp ) + ;; - pushd "$vdir"/vdir &>/dev/null - basever=$($_CHROOT_SH cat /etc/gentoo-release | $_AWK '{print $5}') - popd &>/dev/null - - basemaj=${basever/.*} - basemin=${basever#*.} - basemin=${basemin/.*} - - test "$basemaj" -lt 1 -o "$basemin" -lt 13 && \ - panic "\ -Using init-style 'gentoo' requires >=baselayout-1.13 inside the vserver! - -Your vserver ($(basename "$vdir")) seems to have baselayout-$basever, -please use 'plain' init-style instead!" + (xarch) + test -n "$RUNLEVEL_START" || RUNLEVEL_START=3 + INITCMD_START=( /etc/rc.multi ) + INITCMD_STOP=( /etc/rc.shutdown ) + INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp ) ;; (x) ;; @@ -349,10 +394,12 @@ please use 'plain' init-style instead!" function _generateFlagOptions { local vdir=$1 + local file CHCONTEXT_FLAG_OPTS=() - test ! -e "$vdir"/flags || \ + findFile file "$vdir"/cflags "$vdir"/flags "" + test -z "$file" || \ while read flag; do case x"$flag" in (x|x\#*) ;; @@ -366,11 +413,13 @@ function _generateFlagOptions --flag "$flag" ) ;; esac - done <"$vdir"/flags + done <"$file" isAvoidNamespace "$vdir" || { USE_VNAMESPACE=1 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace ) + ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \ + OPT_VCONTEXT_CHROOT=--pivot-root } } @@ -510,6 +559,33 @@ create them before starting the vserver and use the 'nodev' flag then" return 0 } +function _getTunInfo +{ + local iface="$1" + + test -e "$iface/tun" -o -e "$iface/tap" || return 1 + test ! -e "$iface/tun" || echo --tun + test ! -e "$iface/tap" || echo --tap + test ! -e "$iface/nocsum" || echo --~checksum + test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT" + if test -e "$iface/uid"; then + local uid + getFileValue uid "$iface/uid" + echo --uid "$uid" + fi + if test -e "$iface/gid"; then + local gid + getFileValue gid "$iface/gid" + echo --gid "$gid" + fi + if test -e "$iface/linktype"; then + local linktype + getFileValue linktype "$iface/linktype" + echo --linktype "$linktype" + fi + return 0 +} + ## Usage: _processSingleInterface function _processSingleInterface { @@ -525,6 +601,7 @@ function _processSingleInterface local mac local extip local up="up" + local peer _getInterfaceValue ip '' "$iface" _getInterfaceValue extip '' "$iface" "$iface/.." @@ -535,6 +612,7 @@ function _processSingleInterface _getInterfaceValue name '' "$iface" _getInterfaceValue scope '' "$iface" "$iface/.." _getInterfaceValue mac '' "$iface" + _getInterfaceValue peer '' "$iface" test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; } test -n "$dev" -o -e "$iface"/nodev || { @@ -552,35 +630,44 @@ function _processSingleInterface ## LEGACY ALERT test ! -e "$iface"/only_ip || break - local vlan_info - if vlan_info=$(_getVLANInfo "$dev"); then - test -d /proc/net/vlan || { - echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2 - return 1 - } - test -e "$iface/vlandev" \ - -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \ - -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \ - -a ! -e "$iface/novlandev" \ - -a ! -e "$iface/../novlandev" \) && { + test -e "$iface/vlandev" \ + -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \ + -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \ + -a ! -e "$iface/novlandev" \ + -a ! -e "$iface/../novlandev" \) && { + local vlan_info + if vlan_info=$(_getVLANInfo "$dev"); then + test -d /proc/net/vlan || { + echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2 + return 1 + } _addInterfaceCmd VCONFIG $vlan_info - } - fi + fi + } if ! test -e "$iface"/indirect; then - _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" broadcast ${bcast:-+} ${name:+label "$dev:$name"} dev "$dev" + # XXX: IPv6 hack + local use_bcast="broadcast ${bcast:-+}" + echo "$ip" | $_GREP -q : && use_bcast= + + local tun_info + if tun_info=$(_getTunInfo "$iface"); then + _addInterfaceCmd TUNCTL "$dev" $tun_info + fi + + _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"} #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev" _addInterfaceCmd IP_LINK "$dev" $up - elif ! test -n "$ctx"; then + elif ! test -n "$N_CONTEXT"; then echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2 return 1 else - test -z "$mac" || _generateMac mac "$(basename $iface)" "$ctx" || return 1 + test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1 _addInterfaceCmd MODPROBE dummy "$dev" _addInterfaceCmd IP_LINK dev dummy0 address "$mac" _addInterfaceCmd NAMEIF "$dev" "$mac" _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev" - test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$ctx" "$extip" + test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip" fi break @@ -591,9 +678,11 @@ function _processSingleInterface function _generateInterfaceOptions { local iface - local ctx - test ! -e "$1"/context || read ctx <"$1"/context + # XXX: This is here instead of in _generateChbindOptions + # to avoid a circular dependency + getFileValue N_CONTEXT "$1/ncontext" "$1/context" + test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT" for iface in "$1/interfaces/"*; do test -d "$iface" || continue @@ -632,6 +721,11 @@ function enableInterfaces IP_ADDR_FLUSH) $_IP addr flush "$@";; IP_LINK) $_IP link set "$@";; IP_ROUTE) $_IP route add "$@";; + TUNCTL) + local dev="$1" + shift + $_TUNCTL --persist "$@" "$dev" + ;; *) echo "Unknown interface-command type '$type'" >&2; false;; esac @@ -667,6 +761,7 @@ function disableInterfaces IP_ADDR_FLUSH) ;; IP_LINK) ;; ## Ignore the link-down command for now IP_ROUTE) $_IP route del "$@";; + TUNCTL) $_TUNCTL --~persist "$1";; *) echo "Unknown interface-command type '$type'" >&2; false;; esac done @@ -674,14 +769,63 @@ function disableInterfaces unlock 1 } +function _generateTagOptions +{ + local vdir="$1" + local tag + + getFileValue tag "$vdir/tag" "$vdir/context" + test -n "$tag" || return 0 + + OPTS_VTAG_CREATE=( --tag "$tag" ) + OPTS_VTAG_ENTER=( --tag "$tag" ) +} + +function _generateMemctrlOptions +{ + local vdir="$1" + local badness + + getFileValue badness "$vdir/badness" + test -n "$badness" || return 0 + + OPTS_VMEMCTRL=( --badness "$badness" ) +} + +function _generateSpaceOptions +{ + local vdir="$1" + local d="$vdir"/spaces + local shared + local space + + for space in pid net; do + if test -e "$d"/$space; then + getFileValue shared "$d"/$space || shared="" + if test -z "$shared"; then + OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space ) + elif test "$shared" = "0"; then + : # Do nothing + else + OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space ) + VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- ) + fi + fi + done + + local mask + getFileValue mask "$d"/mask || \ + OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" ) +} + ## Usage: prepareInit function prepareInit { pushd "$1/vdir" >/dev/null case "$INITSTYLE" in sysv) - { find var/run ! -type d -print0; \ - find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm + { $_FIND var/run ! -type d -print0; \ + $_FIND var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm ;; plain) $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || : @@ -700,7 +844,7 @@ function prepareStop pushd "$1/vdir" >/dev/null case "$INITSTYLE" in (sysv) - export PREVLEVEL=$RUNLEVEL_START # required by Debian's initscripts + export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts ;; esac "${STOPCMD_PREPARE[@]}" @@ -713,10 +857,15 @@ function generateOptions _generateInterfaceOptions "$1" test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1" _generateNiceCommand "$1" + _generateIONiceCommand "$1" _generateInitOptions "$1" _generateChcontextOptions "$1" _generateScheduleOptions "$1" _generatePersonalityOptions "$1" + _generateTagOptions "$1" + _generateMemctrlOptions "$1" + _generateSpaceOptions "$1" + _generateCgroupOptions if test -n "$_IS_FAKEINIT"; then CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit ) @@ -785,6 +934,10 @@ function _mountVserverInternal # magic regarding the mtab file; when etc/mtab can not be touched, # add the '-n' flag to mount test -w etc -o -w etc/mtab || xflag=-n + if test -h etc/mtab; then + local l=$($_READLINK etc/mtab) + test "${l##/proc/}" = "$l" || xflag=-n + fi "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no popd >/dev/null } @@ -812,6 +965,8 @@ function mountVserver local ns_opt=$2 local vdir=$1/vdir local mtab_src + local extra_opt= + local real_vdir test -e "$cfgdir"/fstab -o \ -e "$cfgdir"/fstab.local -o \ @@ -827,13 +982,16 @@ function mountVserver _mountVserverInternal "$cfgdir"/fstab _mountVserverInternal "$cfgdir"/fstab.local - _mountVserverInternal "$cfgdir"/fstab.remote $_CHBIND "${CHBIND_OPTS[@]}" + _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" isNamespaceCleanup "$cfgdir" && \ _namespaceCleanup "$cfgdir" + real_vdir=$(getPhysicalDir "$vdir") isAvoidNamespace "$cfgdir" || \ - $_SECURE_MOUNT --rbind -n "$vdir" "/" + $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir" + ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \ + $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir" } function _umountVserverInternal @@ -870,14 +1028,30 @@ function umountVserver test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir" pushd "$vdir/" >/dev/null || return 1 - _umountVserverInternal "$cfgdir"/fstab.remote $_CHBIND "${CHBIND_OPTS[@]}" || is_ok= - _umountVserverInternal "$cfgdir"/fstab.local || is_ok= - _umountVserverInternal "$cfgdir"/fstab || is_ok= + _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok= + _umountVserverInternal "$cfgdir"/fstab.local || is_ok= + _umountVserverInternal "$cfgdir"/fstab || is_ok= popd >/dev/null || return 1 test -n "$is_ok" } +function fsckAllFS +{ + local cfgdir=$1 + local fstab="$cfgdir"/fstab + local FSTAB_FILE + local fsck_exitcode + + test -e "$fstab" || return 0 + + export FSTAB_FILE="$fstab" + $_FSCK -s -n -A -T + fsck_exitcode=$? + test "$fsck_exitcode" -eq 0 -o \ + "$fsck_exitcode" -eq 1 || return $fsck_exitcode +} + ## Usage: waitForSync function initSync { @@ -902,7 +1076,7 @@ function initWait rc=$? if test "$rc" -ne 0 -a "$rc" -ne 1; then - $_VPS axf | $_EGREP -e "^[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4 + $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4 killContext "$S_CONTEXT" 9 fi @@ -1059,7 +1233,7 @@ WARNING: There is no cachedirectory configured for this vserver; ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache " - find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';' + $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';' vshelper.doSanityCheck @@ -1070,7 +1244,16 @@ WARNING: There is no cachedirectory configured for this vserver; panic $"\ /proc/uptime can not be accessed. Usually, this is caused by procfs-security. Please read the FAQ for more details -http://www.linux-vserver.org/index.php?page=Linux-Vserver+FAQ" +http://linux-vserver.org/Proc-Security" + + test -e "$cfgdir"/context || { + TYPE=$( $_VSERVER_INFO 49152 XIDTYPE ) + test "$TYPE" != "static" || panic $"\ +The kernel does not have dynamic contexts enabled. Please configure +a static one by executing + + echo [number between 2 and 49151] > $cfgdir/context" + } } @@ -1166,6 +1349,8 @@ function _saveSingleDiskLimit $_VDLIMIT --xid $ctx "$directory" | \ $_GREP '_used=' > "$vdir/cache/dlimits/$cachename" + + $_VDLIMIT --xid $ctx --remove "$directory" } @@ -1190,25 +1375,31 @@ function _namespaceCleanup local root=$($_VSERVER_INFO "$1" VDIR 1) local -a list local -a skip - local tmp + local i + local j getFileArray skip "$vdir"/namespace-cleanup-skip \ "$__CONFDIR"/.defaults/namespace-cleanup-skip || : # these are things that have to be accessible post-cleanup - for tmp in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \ - "$__PKGSTATEDIR" "${skip[@]}"; do - while test -n "$tmp"; do - list=( "${list[@]}" "$tmp" ) - tmp="${tmp%/*}" + for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \ + "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do + local real=`getPhysicalDir "$i"` + test "$i" != "$real" || real= + for j in "$i" "$real"; do + while test -n "$j"; do + list=( "${list[@]}" "$j" ) + j="${j%/*}" + done done done local -a list_umount - while read dev path opts; do + while read -r dev path opts; do test -n "$path" || continue for i in "$root" /dev /proc; do - test "${path#$i}" != "$path" && continue 2 + path_dir="${path}/" + test "${path_dir#${i}/}" != "${path_dir}" && continue 2 done for i in "${list[@]}" /; do test "$path" = "$i" && continue 2 @@ -1218,7 +1409,158 @@ function _namespaceCleanup done < /proc/mounts # separate loop to avoid races while reading /proc/mounts for i in "${list_umount[@]}"; do - $_UMOUNT -l -n "$i" + $_UMOUNT -l -n -i "$i" + done +} + +function handleDeviceMap +{ + local op="$1" + local xid="$2" + local dir="$3" + local flags device target + + test -d "$dir" || return 0 + test -n "$xid" || return 0 + + for i in "$dir"/*; do + test -d "$i" || continue + + local -a vdevmap_opts=() + test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create ) + test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open ) + test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap ) + + getFileValue flags "$i/flags" || : + getFileValue device "$i/device" || : + getFileValue target "$i/target" || : + vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \ + ${device:+--device "$device"} ${target:+--target "$target"} ) + + $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $? done } +function hasCgroup +{ + $_GREP -q "cgroup" /proc/filesystems +} + +function _generateCgroupOptions +{ + local file + + hasCgroup || return 0 + + findFile file "$__CONFDIR/.defaults/cgroup/mnt" "" + if test -n "$file"; then + read CGROUP_MNT < "$file" + fi + findFile file "$__CONFDIR/.defaults/cgroup/subsys" "" + if test -n "$file"; then + read CGROUP_SUBSYS < "$file" + elif $_GREP -q '^ns[[:space:]]' /proc/cgroups; then + # Hack for the ns subsystem, with which we are incompatible + CGROUP_SUBSYS=$($_SED '/^#/d;/^ns[[:space:]]/d;s/[[:space:]].*//' /proc/cgroups | \ + (s=""; while read x; do test -n "$s" && s="$s,"; s="$s$x"; done; echo "$s")) + fi + findFile file "$__CONFDIR/.defaults/cgroup/inherit" "" + if test -n "$file"; then + _readFileToArray CGROUP_INHERIT "$file" "" + fi + findFile file "$__CONFDIR/.defaults/cgroup/base" "" + if test -n "$file"; then + read CGROUP_BASE < "$file" + test "$CGROUP_BASE" != "${CGROUP_BASE%/}" || \ + CGROUP_BASE="${CGROUP_BASE}/" + fi + + return 0 +} + +function useCgroup +{ + hasCgroup || return 1 + test -d "$CGROUP_MNT" || return 1 + memcg="" + if $_VSERVER_INFO - FEATURE memcg; then + memcg=1 + fi + test -d "$1/cgroup" -o \ + \( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \ + ! -e "$1/nocgroup" \) +} + +function _handleCgroup +{ + local action="$1" + local vdir="$2" + local dir + local name + local i + local j + local parent + + useCgroup "$vdir" || return 0 + + findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" "" + + if test -n "$dir" -a -r "$dir"/name; then + read name < "$dir"/name + else + name="$VSERVER_NAME" + fi + + if test "$action" = "attach"; then + if test -n "$CGROUP_BASE"; then + local -a dirs=() + i="$CGROUP_MNT/$CGROUP_BASE" + while test "$CGROUP_MNT" != "$i"; do + dirs=( "$i" "${dirs[@]}" ) + i="${i%/*}" + done + for i in "${dirs[@]}"; do + if mkdir "$i" 2>/dev/null; then + parent="${i%/*}" + for j in "${CGROUP_INHERIT[@]}"; do + test -f "$parent/$j" || continue + cat "$parent/$j" > "$i/$j" + done + fi + done + fi + if mkdir "$CGROUP_MNT/$CGROUP_BASE$name" 2>/dev/null; then + parent="$CGROUP_MNT/$CGROUP_BASE$name" + parent="${parent%/*}" + for i in "${CGROUP_INHERIT[@]}"; do + test -f "$parent/$i" || continue + cat "$parent/$i" > "$CGROUP_MNT/$CGROUP_BASE$name/$i" + done + + if test -n "$dir"; then + shopt -s nullglob + for i in "$dir"/*; do + f="${i##*/}" + test "$f" != mnt -a "$f" != subsys -a \ + "$f" != inherit -a "$f" != name || continue + cat "$i" > "$CGROUP_MNT/$CGROUP_BASE$name/$f" + done + fi + fi + echo "$$" > "$CGROUP_MNT/$CGROUP_BASE$name/tasks" + elif test "$action" = "destroy"; then + rmdir "$CGROUP_MNT/$name" 2>/dev/null || : + fi + + return 0 +} + +function attachToCgroup +{ + _handleCgroup attach "$@" +} + +function destroyCgroup +{ + _handleCgroup destroy "$@" +}