Fix IPv6 address assignment.
[util-vserver.git] / scripts / vserver.functions
index 2c02276..c1751e8 100644 (file)
@@ -73,6 +73,22 @@ 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"
@@ -87,12 +103,15 @@ function _generateChbindOptions
 
     getFileValue nid "$vdir/ncontext" "$vdir/context"
     
-    CHBIND_OPTS=( $SILENT_OPT ${nid:+--nid "$nid"} ${bcast:+--bcast "$bcast"} )
+    CHBIND_OPTS=( $SILENT_OPT --secure ${nid:+--nid "$nid"} ${bcast:+--bcast "$bcast"} )
 
     for i in "${INTERFACES[@]}"; do
        CHBIND_OPTS=( "${CHBIND_OPTS[@]}" --ip "$i" )
     done
 
+    _readFileToArray "$vdir"/nflags        CHBIND_OPTS --flag
+    _readFileToArray "$vdir"/ncapabilities CHBIND_OPTS --ncap
+
     _HAVE_CHBIND_OPTIONS=1
 }
 
@@ -139,31 +158,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 +250,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 +266,6 @@ function _generateInitOptions
        (xrescue)
            INITCMD_START=( "${INITCMD_RESCUE[@]}" )
            INITCMD_STOP=( /sbin/killall5 )
-           _IS_FAKEINIT=1
-           _NEED_VSHELPER_SYNC=
            ;;
            
        (xsysv)
@@ -299,7 +301,12 @@ function _generateInitOptions
            ;;
 
        (xgentoo)
-           panic "init-style '$INITSTYLE' is no longer supported; please use plain instead; aborting";;
+           test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
+
+           INITCMD_START=( /lib/rcscripts/sh/init-vserver.sh "$RUNLEVEL_START" )
+           INITCMD_STOP=( /sbin/rc shutdown )
+           INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
+           ;;
 
        (x) ;;
        (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
@@ -390,6 +397,11 @@ function _generateChcontextOptions
 function _generateScheduleOptions
 {
     local vdir=$1
+    if test -d "$vdir"/sched; then
+      OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
+      return 0
+    fi
+
     local f="$vdir"/schedule
     test -e "$f" || return 0
 
@@ -527,23 +539,26 @@ 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
+           use_bcast="broadcast ${bcast:-+}"
+           echo "$ip" | $_GREP -q : && use_bcast=
+           _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev"
            #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
            _addInterfaceCmd IP_LINK  "$dev" $up
        elif ! test -n "$ctx"; then
@@ -805,7 +820,7 @@ function mountVserver
     _mountVserverInternal "$cfgdir"/fstab.remote $_CHBIND "${CHBIND_OPTS[@]}"
 
     isNamespaceCleanup "$cfgdir" && \
-        _namespaceCleanup
+        _namespaceCleanup "$cfgdir"
 
     isAvoidNamespace "$cfgdir" || \
        $_SECURE_MOUNT --rbind -n "$vdir" "/"
@@ -1045,7 +1060,7 @@ 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"
 }
 
 
@@ -1141,6 +1156,8 @@ function _saveSingleDiskLimit
 
     $_VDLIMIT --xid $ctx "$directory" | \
        $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
+
+    $_VDLIMIT --xid $ctx --remove "$directory"
 }
 
 
@@ -1161,26 +1178,64 @@ function saveDiskLimits
 
 function _namespaceCleanup
 {
-    local root=$(readlink -f "$vdir")
-    local tmp="$root"
+    local vdir="$1"
+    local root=$($_VSERVER_INFO "$1" VDIR 1)
     local -a list
-    while [ "$tmp" ]; do
-       list=( "${list[@]}" "$tmp" )
-       tmp="${tmp%/*}"
+    local -a skip
+    local tmp
+
+    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" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
+       while test -n "$tmp"; do
+           list=( "${list[@]}" "$tmp" )
+           tmp="${tmp%/*}"
+       done
     done
+
     local -a list_umount
     while read dev path opts; do
-        [ "$path" ] || continue
-        for i in "$root" /dev /proc; do
-            [ "${path#$i}" != "$path" ] && continue 2
-        done
-        for i in "${list[@]}" /; do
-            [ "$path" = "$i" ] && continue 2
-        done
-        list_umount=( "${list_umount[@]}" "$path" )
+       test -n "$path" || continue
+       for i in "$root" /dev /proc; do
+           test "${path#$i}" != "$path" && continue 2
+       done
+       for i in "${list[@]}" /; do
+           test "$path" = "$i" && continue 2
+       done
+       # unmount them in reverse order so mounts further down the tree get unmounted first
+       list_umount=( "$path" "${list_umount[@]}" )
     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"
     done
 }
 
+function loadDeviceMap
+{
+    local xid="$1"
+    local dir="$2"
+    local flags device target
+
+    test -d "$dir" || 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" "${vdevmap_opts[@]}" || return $?
+    done
+}