gentoo: use /var/run for new /run compatibility
[util-vserver.git] / scripts / vserver.functions
index b905968..77ca912 100644 (file)
@@ -42,6 +42,7 @@ declare -a OPTS_VCONTEXT_CREATE=()
 declare -a OPTS_VCONTEXT_MIGRATE=()
 declare -a OPTS_VCONTEXT_ENTER=()
 OPT_VCONTEXT_CHROOT=--chroot
+OPT_VCONTEXT_CLOSE_FD=""
 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
 declare -a OPTS_VSCHED=()
 declare -a OPTS_ENV=()
@@ -75,8 +76,10 @@ N_CONTEXT=
 SILENT_OPT=
 
 CGROUP_MNT=/dev/cgroup
-CGROUP_SUBSYS=all
+declare -a CGROUP_SUBSYS=()
 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems )
+CGROUP_BASE=""
+CGROUP_MNT_PER_SS=""
 
 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
 
@@ -112,7 +115,7 @@ function _generateChbindOptions
 
     test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
 
-    if test -e "$vdir"/noncontext -o
+    if test -e "$vdir"/noncontext -o \
            \( -e "$vdir"/spaces/net -a ! -e "$vdir"/ncontext \); then
        _HAVE_CHBIND_OPTIONS=1
        return 0
@@ -152,15 +155,21 @@ function _generateNiceCommand
 function _generateIONiceCommand
 {
     local vdir=$1
-    local ionice_class=2
-    local ionice_priority=0
+    local ionice_class=
+    local ionice_priority=
 
     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 )
+    test -n "$ionice_class$ionice_priority" || return 0
+
+    if test -z "$ionice_class" -a -n "$ionice_priority"; then
+       IONICE_CMD=( $_IONICE -c2 -n"$ionice_priority" )
+    else
+       IONICE_CMD=( $_IONICE ${ionice_class:+-c$ionice_class} ${ionice_priority:+-n$ionice_priority} )
+    fi
 }
 
 function _generatePersonalityOptions
@@ -204,6 +213,13 @@ function _generateBCapabilityOptions
     _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
 }
 
+function _generateUMaskOptions
+{
+    local vdir=$1
+
+    _readFileToArray "$vdir"/umask OPTS_VATTRIBUTE --umask
+}
+
 function _generateCapabilityOptions
 {
     local vdir=$1
@@ -340,7 +356,7 @@ function _generateInitOptions
            ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
            ;;
 
-       (xgentoo)
+       (xgentoo|xopenrc)
            test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
            RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
 
@@ -440,6 +456,7 @@ function _generateChcontextOptions
 
     _generateCapabilityOptions "$vdir"
     _generateFlagOptions       "$vdir"
+    _generateUMaskOptions      "$vdir"
 
     CHCONTEXT_OPTS=( $SILENT_OPT \
                      "${CHCONTEXT_FLAG_OPTS[@]}" \
@@ -451,6 +468,8 @@ function _generateChcontextOptions
 
     OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
                           ${ctx:+--xid "$ctx"} )
+    findFile file "$vdir"/keepfds "$__CONFDIR/.defaults/keepfds" ""
+    test -n "$file" || OPT_VCONTEXT_CLOSE_FD="--closefd"
     ## put '--secure' at front so that it can be overridden
     OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
 }
@@ -760,7 +779,11 @@ function disableInterfaces
            IP_ADDR_FLUSH)      ;;
            IP_LINK)            ;; ## Ignore the link-down command for now
            IP_ROUTE)           $_IP route del "$@";;
-           TUNCTL)             $_TUNCTL --~persist "$1";;
+           TUNCTL)
+               local dev="$1"
+               shift
+               $_TUNCTL --~persist "$@" "$dev"
+               ;;
            *)                  echo "Unknown interface-command type '$type'" >&2; false;;
        esac
     done
@@ -804,7 +827,7 @@ function _generateSpaceOptions
            if test -z "$shared"; then
                OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space )
            elif test "$shared" = "0"; then
-               # Do nothing
+               : # Do nothing
            else
                OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space )
                VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- )
@@ -823,8 +846,11 @@ 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
+           local -a dirs=( $($_CHROOT_SH realpath /var/run /var/lock | $_SED 's!^/*!!' || :) )
+           local dir
+           for dir in "${dirs[@]}"; do
+               $_FIND $dir ! -type d -print0 | xargs -0r $_CHROOT_SH rm
+           done
            ;;
        plain)
            $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
@@ -1393,11 +1419,19 @@ function _namespaceCleanup
        done
     done
 
+    # keep cgroup mount points
+    list=( "${list[@]}" "${CGROUP_MNT}" )
+    if test -n "$CGROUP_MNT_PER_SS"; then
+        for ss in "${CGROUP_SUBSYS[@]}"; do
+            list=( "${list[@]}" "${CGROUP_MNT}/${ss}" )
+        done
+    fi
+
     local -a list_umount
     while read -r dev path opts; do
        test -n "$path" || continue
-       for i in "$root" /dev /proc; do
-           path_dir="${path}/"
+       path_dir="${path}/"
+       for i in "$root" /dev /proc /sys; do
            test "${path_dir#${i}/}" != "${path_dir}" && continue 2
        done
        for i in "${list[@]}" /; do
@@ -1451,22 +1485,33 @@ function _generateCgroupOptions
 
     hasCgroup || return 0
 
-    findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
+    findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
     if test -n "$file"; then
-       read CGROUP_MNT < "$file"
+       _readFileToArray CGROUP_SUBSYS "$file"
+    else
+       CGROUP_SUBSYS=( $($_AWK '/^#/ { next; } $1 == "ns" { next; } $4 != "0" { print $1; }' /proc/cgroups) )
     fi
-    findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
+    findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
     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"))
+       read CGROUP_MNT < "$file"
+    elif test -d /sys/fs/cgroup -a -d /sys/fs/cgroup/"${CGROUP_SUBSYS[0]}"; then
+       CGROUP_MNT=/sys/fs/cgroup
+       CGROUP_MNT_PER_SS=1
     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
+    findFile file "$__CONFDIR/.defaults/cgroup/per-ss" ""
+    if test -n "$file"; then
+       CGROUP_MNT_PER_SS=1
+    fi
 
     return 0
 }
@@ -1474,9 +1519,24 @@ function _generateCgroupOptions
 function useCgroup
 {
     hasCgroup || return 1
-    test -d "$CGROUP_MNT" || return 1
+    if test -n "$CGROUP_MNT_PER_SS"; then
+       local existing=0
+       local ss
+       for ss in "${CGROUP_SUBSYS[@]}"; do
+           if test -e "$CGROUP_MNT/$ss/tasks"; then
+               let existing=${existing}+1
+           fi
+       done
+       test "$existing" -gt 0 || return 1
+    else
+       test -e "$CGROUP_MNT/tasks" || return 1
+    fi
+    local memcg=""
+    if $_VSERVER_INFO - FEATURE memcg; then
+       memcg=1
+    fi
     test -d "$1/cgroup" -o \
-       \( -d "$__CONFDIR/.defaults/cgroup" -a \
+       \( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \
           ! -e "$1/nocgroup" \)
 }
 
@@ -1487,40 +1547,78 @@ function _handleCgroup
     local dir
     local name
     local i
+    local j
     local parent
+    local -a mnts
+    local ss
 
     useCgroup "$vdir" || return 0
 
     findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
-    test -d "$dir" || return 0
 
-    if test -r "$dir"/name; then
+    if test -n "$dir" -a -r "$dir"/name; then
        read name < "$dir"/name
     else
        name="$VSERVER_NAME"
     fi
 
-    if test "$action" = "attach"; then
-       if mkdir "$CGROUP_MNT/$name" 2>/dev/null; then
-           parent="$CGROUP_MNT/$name"
-           parent="${parent%/*}"
-            for i in "${CGROUP_INHERIT[@]}"; do
-               test -f "$parent/$i" || continue
-               cat "$parent/$i" > "$CGROUP_MNT/$name/$i"
-           done
-
-           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/$name/$f"
-           done
-       fi
-       echo "$$" > "$CGROUP_MNT/$name/tasks"
-    elif test "$action" = "destroy"; then
-       rmdir "$CGROUP_MNT/$name" 2>/dev/null || :
+    if test -n "$CGROUP_MNT_PER_SS"; then
+       mnts=()
+       for ss in "${CGROUP_SUBSYS[@]}"; do
+           mnts=( "${mnts[@]}" "$CGROUP_MNT/$ss" )
+       done
+    else
+       mnts=( "$CGROUP_MNT" )
     fi
+    for mnt in "${mnts[@]}"; do
+       test -d "$mnt" || continue
+       if test "$action" = "attach"; then
+           if test -n "$CGROUP_BASE"; then
+               local -a dirs=()
+               i="$mnt/$CGROUP_BASE"
+               while test "$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 "$mnt/$CGROUP_BASE$name" 2>/dev/null; then
+               parent="$mnt/$CGROUP_BASE$name"
+               parent="${parent%/*}"
+               for i in "${CGROUP_INHERIT[@]}"; do
+                   test -f "$parent/$i" || continue
+                   cat "$parent/$i" > "$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 -a "$f" != base -a \
+                           "$f" != per-ss \
+                           || continue
+                       if test -n "$CGROUP_MNT_PER_SS"; then
+                           ss="${f%%.*}"
+                           test "$ss" = "${mnt##*/}" || continue
+                       fi
+                       cat "$i" > "$mnt/$CGROUP_BASE$name/$f"
+                   done
+               fi
+           fi
+           echo "$$" > "$mnt/$CGROUP_BASE$name/tasks"
+       elif test "$action" = "destroy"; then
+           rmdir "$mnt/$name" 2>/dev/null || :
+       fi
+    done
 
     return 0
 }