OSDN Git Service

Fixed a bug that obsolete or moved ports were not inspected. For this purpose, the...
[portsreinstall/current.git] / lib / chroot / libfs.sh
index eb47095..8354d0c 100644 (file)
@@ -1,11 +1,15 @@
 #!/bin/sh -e
 # ==============================================================================
-# portsreinstall-chroot library script for portsreinstall-chroot
+# portsreinstall-chroot library script
+# Overlay onto lib/libfs.sh for portsreinstall-chroot
 # - File system operations -
 # Copyright (C) 2018 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
 # This software is distributed under the 2-Clause BSD License.
 # ==============================================================================
 
+FS_UNMOUNT_RETIAL_MAXNUM=5     # Number of retrial of unmounting
+FS_UNMOUNT_RETIAL_WAIT=3       # Wait seconds in retrial of unmounting
+
 # ============= Check the safety of the base directory of builder chroot environment =============
 fs_chk_safety_basedir ()
 {
@@ -38,16 +42,68 @@ fs_safeguard_basedir ()
        exit 1
 }
 
+# ============= Save the system base observed currently =============
+fs_save_current_systembase ()
+{
+       local systembase 
+       systembase=$1
+       echo "$systembase" >  ${TMPDIR}/fs_save_current_systembase
+}
+
+# ============= Save the system base observed at the time of mounting =============
+fs_save_mounttime_systembase ()
+{
+       local systembase 
+       systembase=$1
+       echo "$systembase" >  ${DBDIR}/fs_systembase
+}
+
+# ============= Get the system base observed currently =============
+fs_get_current_systembase ()
+{
+       cat  "${TMPDIR}/fs_save_current_systembase" 2> /dev/null
+}
+
+# ============= Get the system base observed at the time of mounting =============
+# Non-zero return means no file system was attempted to mount
+fs_get_mounttime_systembase ()
+{
+       cat "${DBDIR}/fs_systembase" 2> /dev/null
+}
+
+# ============= Get the system base in the scope of accessing =============
+fs_system_base_in_mp_access ()
+{
+       fs_get_current_systembase
+}
+
+# ============= Get the system base in the scope of creating mount points =============
+fs_system_base_in_mp_creation ()
+{
+       fs_get_current_systembase
+}
+
+# ============= Get the system base in the scope of referring to mount points =============
+fs_system_base_in_mp_reference ()
+{
+       str_regularize_df_path "`fs_get_current_systembase`/`fs_get_system_basedir`"
+}
+
+# ============= Get the system base in the scope of targets =============
+# Non-zero return means no file system was attempted to mount
+fs_system_base_in_target ()
+{
+       fs_get_mounttime_systembase
+}
+
 # ============= Build the file systems for the builder chroot environment =============
 fs_build_chroot ()
 {
-       local systembase
-       systembase=$1
        [ -e "${DBDIR}/mount_manifest" ] && return
        message_echo "Building the file systems for builder chroot environment (if not yet)."
        fs_safeguard_basedir "$opt_basedir"
-       fs_unmount "$systembase"
-       mkdir -p "$systembase/$opt_basedir"
+       fs_unmount || return
+       mkdir -p "$opt_basedir"
        # Prescan the f file system of the original environment
        cp /dev/null "${TMPDIR}/fs_build_chroot:directories"
        (
@@ -58,106 +114,141 @@ fs_build_chroot ()
                sysdirs_ptn="^/*(`str_escape_regexp_filter < ${TMPDIR}/fs_build_chroot:sys_dirs | tr '\n' '|' | sed 's/\|$//'`)/+"
                while read directory
                do
-                       [ -e "$systembase"/$directory ] || continue
-                       if [ -L "$systembase"/$directory ]
+                       [ -e "/$directory" ] || continue
+                       if [ -L "/$directory" ]
                        then
-                               src_mountpoint_real=`realpath "$systembase"/$directory`
-                                       printf '%s\t%s\n' link $directory >> ${TMPDIR}/fs_build_chroot:directories
+                               src_mountpoint_real=`realpath "/$directory"`
+                                       printf '%s\t%s\n' link "$directory" >> ${TMPDIR}/fs_build_chroot:directories
                                if ! echo "$src_mountpoint_real/" | grep -qE "$sysdirs_ptn"
                                then
                                        printf '%s\t%s\n' real "$src_mountpoint_real" >> ${TMPDIR}/fs_build_chroot:directories
                                        tmpdir_descendant=${TMPDIR}/fs_build_chroot:descendant/$src_mountpoint_real
                                        mkdir -p "$tmpdir_descendant"
-                                       misc_get_descendant_mount_info "$systembase/$src_mountpoint_real" > $tmpdir_descendant/list
+                                       fs_get_descendant_mount_info "/$src_mountpoint_real" > $tmpdir_descendant/list
                                fi
-                       elif [ -d "$systembase"/$directory ]
+                       elif [ -d "/$directory" ]
                        then
                                printf '%s\t%s\n' real $directory >> ${TMPDIR}/fs_build_chroot:directories
                                tmpdir_descendant=${TMPDIR}/fs_build_chroot:descendant/$directory
                                mkdir -p "$tmpdir_descendant"
-                               misc_get_descendant_mount_info "$systembase/$directory" > $tmpdir_descendant/list
+                               fs_get_descendant_mount_info "/$directory" > $tmpdir_descendant/list
                        fi
                done < ${TMPDIR}/fs_build_chroot:sys_dirs
        )
        # Prepare the grand base of the chroot environment
        (
-               cd "$systembase/$opt_basedir"
+               cd "/$opt_basedir"
                for directory in builder mask store
                do
                        [ -d $directory ] || mkdir $directory
                done
        )
+       # Directories to share with the host environment by nullfs
+       if [ "x$opt_share_port_pkgs_dirs" = xyes ]
+       then
+               echo "$PORTSDIR"
+               echo "$PORTSNAP_WORKDIR"
+               echo "$PKGNG_PKG_CACHEDIR"
+       fi | str_regularize_df_path_filter | grep -v '^[[:space:]]*$' | sort -u > ${DBDIR}/shared_dirs.lst
+       str_escape_regexp_filter < ${DBDIR}/shared_dirs.lst | sed 's|^|^|;s|$|\/|' > ${TMPDIR}/fs_build_chroot:shared_dirs.regexp.tmp
+       paste "${DBDIR}/shared_dirs.lst" "${TMPDIR}/fs_build_chroot:shared_dirs.regexp.tmp" > ${TMPDIR}/fs_build_chroot:shared_dirs.regexp
+       cp /dev/null "${TMPDIR}/fs_build_chroot:shared_dirs:added"
        # Build target directories and the manifest for mounting
        cp /dev/null "${DBDIR}/mount_manifest.tmp"
        (
-               cd "$systembase/$opt_basedir"/builder
+               cd "/$opt_basedir"/builder
                while read srcline
                do
                        type=`echo "$srcline" | cut -f 1`
                        directory=`echo "$srcline" | cut -f 2`
                        case $type in
                        link )
-                               [ -e "$directory" -o -L "$directory" ] || cp -RpP "$systembase/$directory" .
+                               [ -e "$directory" -o -L "$directory" ] || cp -RpP "/$directory" .
                                ;;
                        real )
                                mkdir -p "./$directory"
-                               masktarget=$systembase/$opt_basedir/mask/$directory
+                               masktarget=/$opt_basedir/mask/$directory
                                mkdir -p "$masktarget"
-                               printf '%s\t%s\t%s\t%s\n' nullfs "$systembase"/$directory $directory ro >> ${DBDIR}/mount_manifest.tmp
-                               printf '%s\t%s\t%s\t%s\n' unionfs "$masktarget" $directory noatime >> ${DBDIR}/mount_manifest.tmp
+                               printf '%s\t%s\t%s\t%s\n' nullfs "/$directory" "$directory" ro >> ${DBDIR}/mount_manifest.tmp
+                               printf '%s\t%s\t%s\t%s\n' unionfs "$masktarget" "$directory" rw,noatime >> ${DBDIR}/mount_manifest.tmp
                                while read srcline
                                do
                                        fs=`echo "$srcline" | cut -f 1`
-                                       mp=`echo "$srcline" | cut -f 2`
-                                       relative=`echo "$srcline" | cut -f 3`
+                                       mp=`echo "$srcline" | cut -f 2 | str_regularize_df_path_filter`
+                                       relative=`echo "$srcline" | cut -f 3 | str_regularize_df_path_filter`
+                                       fullpath=`str_regularize_df_path "/$directory/$relative"`
+                                       rm -f "${TMPDIR}/fs_build_chroot:shared_dirs:is_under"
+                                       rm -f "${TMPDIR}/fs_build_chroot:shared_dirs:is_itself"
+                                       while read -r shared_path shared_path_regexp
+                                       do
+                                               echo "$fullpath/" | grep -qE "$shared_path_regexp" || continue
+                                               echo "$shared_path"$'\n'"$fullpath" | while read mpath
+                                               do
+                                                       if  ! grep -qFx "$mpath" "${TMPDIR}/fs_build_chroot:shared_dirs:added"
+                                                       then
+                                                               echo "$mpath" >> ${TMPDIR}/fs_build_chroot:shared_dirs:added
+                                                               mkdir -p "/$mpath"
+                                                               mp_share=`realpath "/$mpath"`
+                                                               printf '%s\t%s\t%s\t%s\n' nullfs "$mp_share" "$mpath" rw >> ${DBDIR}/mount_manifest.tmp
+                                                       fi
+                                               done
+                                               touch "${TMPDIR}/fs_build_chroot:shared_dirs:is_under"
+                                       done < ${TMPDIR}/fs_build_chroot:shared_dirs.regexp
+                                       [ -e "${TMPDIR}/fs_build_chroot:shared_dirs:is_under" ] && continue
                                        case $fs in
                                                normal )
-                                                       masktarget=$systembase/$opt_basedir/mask/$directory/$relative
+                                                       masktarget=`str_regularize_df_path "/$opt_basedir/mask/$fullpath"`
                                                        mkdir -p "$masktarget"
-                                                       printf '%s\t%s\t%s\t%s\n' nullfs "$mp" "$directory/$relative" ro >> ${DBDIR}/mount_manifest.tmp
-                                                       printf '%s\t%s\t%s\t%s\n' unionfs "$masktarget" "$directory/$relative" noatime >> ${DBDIR}/mount_manifest.tmp
+                                                       printf '%s\t%s\t%s\t%s\n' nullfs "$mp" "$fullpath" ro >> ${DBDIR}/mount_manifest.tmp
+                                                       printf '%s\t%s\t%s\t%s\n' unionfs "$masktarget" "$fullpath" rw,noatime >> ${DBDIR}/mount_manifest.tmp
                                                        ;;
                                                devfs )
-                                                       printf '%s\t%s\t%s\t%s\n' devfs devfs "$directory/$relative" '' >> ${DBDIR}/mount_manifest.tmp
+                                                       printf '%s\t%s\t%s\t%s\n' devfs devfs "$fullpath" rw >> ${DBDIR}/mount_manifest.tmp
                                                        ;;
                                                fdescfs )
-                                                       printf '%s\t%s\t%s\t%s\n' fdescfs fdesc "$directory/$relative" '' >> ${DBDIR}/mount_manifest.tmp
+                                                       printf '%s\t%s\t%s\t%s\n' fdescfs fdesc "$fullpath" rw >> ${DBDIR}/mount_manifest.tmp
                                                        ;;
                                                procfs )
-                                                       printf '%s\t%s\t%s\t%s\n' procfs proc "$directory/$relative" '' >> ${DBDIR}/mount_manifest.tmp
+                                                       printf '%s\t%s\t%s\t%s\n' procfs proc "$fullpath" rw >> ${DBDIR}/mount_manifest.tmp
                                                        ;;
                                                linprocfs )
-                                                       printf '%s\t%s\t%s\t%s\n' linprocfs linproc "$directory/$relative" '' >> ${DBDIR}/mount_manifest.tmp
+                                                       printf '%s\t%s\t%s\t%s\n' linprocfs linproc "$fullpath" rw >> ${DBDIR}/mount_manifest.tmp
                                                        ;;
                                                tmpfs )
-                                                       printf '%s\t%s\t%s\t%s\n' tmpfs tmpfs "$directory/$relative" mode=1777 >> ${DBDIR}/mount_manifest.tmp
+                                                       printf '%s\t%s\t%s\t%s\n' tmpfs tmpfs "$fullpath" rw,mode=1777 >> ${DBDIR}/mount_manifest.tmp
                                                        ;;
                                        esac
                                done < ${TMPDIR}/fs_build_chroot:descendant/$directory/list
                                ;;
                        esac
                done < ${TMPDIR}/fs_build_chroot:directories
+               grep -Ev -f "${TMPDIR}/fs_build_chroot:shared_dirs:added" "${DBDIR}/shared_dirs.lst" | while read shared_dir
+               do
+                       mkdir -p "$shared_dir"
+                       mp_share=`realpath "$shared_dir"`
+                       printf '%s\t%s\t%s\t%s\n' nullfs "$mp_share" "/$shared_dir" rw >> ${DBDIR}/mount_manifest.tmp
+               done
                for directory in dev proc tmp 
                do
                        [ -e $directory ] || mkdir $directory
                done
-               printf '%s\t%s\t%s\t%s\n' devfs devfs dev '' >> ${DBDIR}/mount_manifest.tmp
-               printf '%s\t%s\t%s\t%s\n' fdescfs fdesc dev/fd '' >> ${DBDIR}/mount_manifest.tmp
-               printf '%s\t%s\t%s\t%s\n' procfs proc proc '' >> ${DBDIR}/mount_manifest.tmp
-               printf '%s\t%s\t%s\t%s\n' tmpfs tmpfs tmp mode=1777 >> ${DBDIR}/mount_manifest.tmp
+               printf '%s\t%s\t%s\t%s\n' devfs devfs dev rw >> ${DBDIR}/mount_manifest.tmp
+               printf '%s\t%s\t%s\t%s\n' fdescfs fdesc dev/fd rw >> ${DBDIR}/mount_manifest.tmp
+               printf '%s\t%s\t%s\t%s\n' procfs proc proc rw >> ${DBDIR}/mount_manifest.tmp
+               printf '%s\t%s\t%s\t%s\n' tmpfs tmpfs tmp rw,mode=1777 >> ${DBDIR}/mount_manifest.tmp
                mkdir -p ."${PROGRAM}"
-               cd "$systembase/$opt_basedir/mask"
+               cd "/$opt_basedir/mask"
                if [ ! -e root/.cshrc ]
                then
                        tmp_cshrc=${TMPDIR}/fs_build_chroot:.cshrc
                        [ -d root ] || mkdir root
-                       if [ -e "$systembase"/root/.cshrc ]
+                       if [ -e /root/.cshrc ]
                        then
-                               cp -p "$systembase"/root/.cshrc "$tmp_cshrc"
-                               cp -p "$systembase"/root/.cshrc "root/.cshrc.bak-${APPNAME}"
-                       elif [ -e "$systembase"/usr/share/skel/dot.cshrc ]
+                               cp -p /root/.cshrc "$tmp_cshrc"
+                               cp -p /root/.cshrc "root/.cshrc.bak-${APPNAME}"
+                       elif [ -e /usr/share/skel/dot.cshrc ]
                        then
-                               cp -p "$systembase"/usr/share/skel/dot.cshrc "$tmp_cshrc"
+                               cp -p /usr/share/skel/dot.cshrc "$tmp_cshrc"
                                touch "root/.cshrc.bak-${APPNAME}"
                        else
                                cp /dev/null "$tmp_cshrc"
@@ -166,7 +257,7 @@ fs_build_chroot ()
                        echo 'set prompt="%N@[builder]%m:%~ %# "' >> $tmp_cshrc
                        mv "$tmp_cshrc" root/.cshrc
                fi
-               printf '%s\t%s\t%s\t%s\n' nullfs "$systembase/$opt_basedir"/store ".${PROGRAM}" '' >> ${DBDIR}/mount_manifest.tmp
+               printf '%s\t%s\t%s\t%s\n' nullfs "/$opt_basedir"/store ".${PROGRAM}" rw >> ${DBDIR}/mount_manifest.tmp
        )
        mv "${DBDIR}/mount_manifest.tmp" "${DBDIR}/mount_manifest"
 }
@@ -174,47 +265,62 @@ fs_build_chroot ()
 # ============= Check whether the file systems for the builder chroot environment are all mounted =============
 fs_chk_mount ()
 {
-       local systembase
-       systembase=$1
+       local systembase_target systembase_mp tmp_remains
        [ -e "${DBDIR}/mount_manifest" ] || return
-       rm -rf ${TMPDIR}/fs_chk_mount:remains
+       systembase_target=`fs_system_base_in_target` || return
+       systembase_mp=`fs_system_base_in_mp_reference`
+       tmp_remains=${TMPDIR}/fs_chk_mount:remains
+       rm -rf "$tmp_remains"
        while read srcline
        do
                type=`echo "$srcline" | cut -f 1`
                target=`echo "$srcline" | cut -f 2`
-               [ "x$type" = xnullfs -o "x$type" = xunionfs ] && target=$systembase/$target
+               [ "x$type" = xnullfs -o "x$type" = xunionfs ] && target=`str_regularize_df_path "$systembase_target/$target"`
                directory=`echo "$srcline" | cut -f 3`
                opt=`echo "$srcline" | cut -f 4`
-               if ! misc_chk_mounted "$type" "$target" "$systembase/$opt_basedir/builder/$directory"
+               mp=`str_regularize_df_path "$systembase_mp/$opt_basedir/builder/$directory"`
+               if ! fs_chk_mounted "$type" "$target" "$mp"
                then
-                       touch "${TMPDIR}"/fs_chk_mount:remains
-                       break
+                       printf '%s\t%s\t%s\n' "$type" "$target" "$mp" >> $tmp_remains
                fi
        done < ${DBDIR}/mount_manifest
-       [ ! -e "${TMPDIR}"/fs_chk_mount:remains ]
+       ! cat "$tmp_remains" 2> /dev/null
 }
 
 # ============= Terminate when the file systems for the builder chroot environment cannot be mounted =============
 fs_terminate_if_mount_unavailable ()
 {
-       local systembase
-       systembase=$1
-       fs_chk_mount "$systembase" && return
-       misc_chk_mount_privilege && return
+       local systembase systembase_saved
+       systembase=`fs_get_current_systembase`
+       fs_chk_mount > /dev/null && return
+       if systembase_saved=`fs_get_mounttime_systembase`
+       then
+               if [ "x$systembase" = "x$systembase_saved" ]
+               then
+                       fs_chk_mount_privilege && return
+               elif [ -n "$systembase" ]
+               then
+                       temp_terminate_process ()
+                       {
+                               message_echo "ERROR: Cannot mount because the current file systems are being mounted from inside the virtual (chroot or jail) environment."  >&2
+                               message_echo "INFO: Instead of this command, mount from inside the virtual (chroot or jail) environment."
+                       }
+                       [ $TEMP_IN_TRAP = no ] || temp_terminate_process
+                       exit 1
+               fi
+       elif fs_chk_mount_privilege
+       then
+               fs_save_mounttime_systembase "`fs_get_current_systembase`"
+               return
+       fi
        temp_terminate_process ()
        {
-               local errno basedir
-               errno=${1:-0}
+               local basedir
                [ $opt_batch_mode = yes ] && return
-               if [ $errno -ne 2 ]
-               then
-                       message_echo "Aborted by unexpected error" >&2
-                       exit
-               fi
                message_echo
                message_echo "INFO: Terminated for mounting file systems because this utility was executed at a virtual (chroot or jail) environment."
                message_echo "Execute"
-               basedir=`misc_get_system_basedir`
+               basedir=`fs_get_system_basedir`
                if [ -n "$basedir" ]
                then
                        message_echo "  $basedir${SHAREDIR}/bin/portsreinstall-chroot-mount"
@@ -231,81 +337,120 @@ fs_terminate_if_mount_unavailable ()
                        message_echo "  ${APPNAME}"
                fi
        }
+       [ $TEMP_IN_TRAP = no ] || temp_terminate_process
        exit 2
 }
 
-# ============= Mount the file systems for the builder chroot environment if not yet =============
-fs_mount ()
+# ============= Generate a custom fstab file for the builder chroot environment =============
+fs_gen_fstab ()
 {
-       local systembase
-       systembase=$1
-       message_echo "Mounting the file systems for builder chroot environment."
+       local stage systembase_target systembase_mp
+       stage=$1
+       systembase_target=`fs_system_base_in_target`
+       case $stage in
+       mount )
+               systembase_mp=`fs_system_base_in_mp_creation`
+               ;;
+       unmount )
+               systembase_mp=`fs_system_base_in_mp_reference`
+               ;;
+       esac
        fs_safeguard_basedir "$opt_basedir"
        while read srcline
        do
                type=`echo "$srcline" | cut -f 1`
                target=`echo "$srcline" | cut -f 2`
-               [ "x$type" = xnullfs -o "x$type" = xunionfs ] && target=$systembase/$target
                directory=`echo "$srcline" | cut -f 3`
                opt=`echo "$srcline" | cut -f 4`
-               mp=$systembase/$opt_basedir/builder/$directory
-               if ! misc_chk_mounted "$type" "$target" "$mp"
+               [ "x$type" = xnullfs -o "x$type" = xunionfs ] && target=$systembase_target/$target
+               target=`str_regularize_df_path "$target"`
+               mp=`str_regularize_df_path "$systembase_mp/$opt_basedir/builder/$directory"`
+               opt=`echo "$opt" | sed 's/[[:space:]]/\\040/g'`
+               echo "$target $mp $type $opt 0 0"
+       done < ${DBDIR}/mount_manifest > ${DBDIR}/fstab
+}
+
+# ============= Mount the file systems for the builder chroot environment if not yet =============
+fs_mount ()
+{
+       local remining
+       if fs_chk_mount > /dev/null
+       then
+               message_echo "The builder chroot environment is already mounted."
+               message_echo
+               return
+       fi
+       fs_terminate_if_mount_unavailable
+       message_section_title "Mounting the file systems for builder chroot environment."
+       fs_gen_fstab mount
+       remining=
+       if ! mount -F "${DBDIR}/fstab" -a || ! remining=`fs_chk_mount`
+       then
+               cp "${DBDIR}/fstab" "${DBDIR}/fstab-mount-err"
+               message_echo "ERROR: Failed to mount the file systems. The followings remain unmounted:" >&2
+               if [ $opt_batch_mode = no ]
                then
-                       mount -t "$type" -o "$opt" "$target" "$mp"
+                       [ -n "$remining" ] || remining=`fs_chk_mount` || :
+                       echo "$remining" >&2
                fi
-       done < ${DBDIR}/mount_manifest
-       if ! fs_chk_mount "$systembase"
-       then
-               message_echo "Error: Failed to mount the file systems. Some of them remain unmounted." >&2
                exit 1
        fi
        message_echo "Mounting done."
+       message_echo
 }
 
 # ============= Check whether the file systems for the builder chroot environment are all unmounted or destroyed =============
 fs_chk_unmount ()
 {
-       local systembase
-       systembase=$1
+       local systembase_target systembase_mp tmp_remains
        [ -e "${DBDIR}/mount_manifest" ] || return 0
-       rm -rf ${TMPDIR}/fs_chk_unmount:remains
+       systembase_target=`fs_system_base_in_target` || return 0
+       systembase_mp=`fs_system_base_in_mp_reference`
+       tmp_remains=${TMPDIR}/fs_chk_unmount:remains
+       rm -rf "$tmp_remains"
        tail -r "${DBDIR}/mount_manifest" | while read srcline
        do
                type=`echo "$srcline" | cut -f 1`
                target=`echo "$srcline" | cut -f 2`
-               [ "x$type" = xnullfs -o "x$type" = xunionfs ] && target=$systembase/$target
+               [ "x$type" = xnullfs -o "x$type" = xunionfs ] && target=$systembase_target/$target
                directory=`echo "$srcline" | cut -f 3`
                opt=`echo "$srcline" | cut -f 4`
-               if misc_chk_mounted "$type" "$target" "$systembase/$opt_basedir/builder/$directory"
-               then
-                       touch "${TMPDIR}"/fs_chk_unmount:remains
-                       break
-               fi
+               mp=$systembase_mp/$opt_basedir/builder/$directory
+               fs_chk_mounted "$type" "$target" "$mp" || continue
+               str_regularize_df_path "$mp" >> $tmp_remains
        done
-       [ ! -e "${TMPDIR}"/fs_chk_unmount:remains ]
+       ! cat "$tmp_remains" 2> /dev/null
 }
 
 # ============= Terminate when the file systems for the builder chroot environment cannot be unmounted =============
 fs_terminate_if_unmount_unavailable ()
 {
-       local systembase
-       systembase=$1
-       fs_chk_unmount "$systembase" && return
-       misc_chk_unmount_privilege && return
+       local systembase systembase_saved
+       systembase=`fs_get_current_systembase`
+       systembase_saved=`fs_get_mounttime_systembase` || return 0
+       fs_chk_unmount > /dev/null && return
+       if [ "x$systembase" = "x$systembase_saved" ]
+       then
+               fs_chk_mount_privilege && return
+       elif [ -n "$systembase" ]
+       then
+               temp_terminate_process ()
+               {
+                       message_echo "ERROR: Cannot unmount because the current file systems were mounted from inside the virtual (chroot or jail) environment."  >&2
+                       message_echo "INFO: Instead of this command, unmount from inside the virtual (chroot or jail) environment."
+               }
+               [ $TEMP_IN_TRAP = no ] || temp_terminate_process
+               exit 1
+       fi
        temp_terminate_process ()
        {
                local errno basedir
                errno=${1:-0}
                [ $opt_batch_mode = yes ] && return
-               if [ $errno -ne 3 ]
-               then
-                       message_echo "Aborted by unexpected error" >&2
-                       exit
-               fi
                message_echo
                message_echo "INFO: Terminated for unmounting file systems because this utility was executed at a virtual (chroot or jail) environment."
                message_echo "Execute"
-               basedir=`misc_get_system_basedir`
+               basedir=`fs_get_system_basedir`
                if [ -n "$basedir" ]
                then
                        message_echo "  $basedir${SHAREDIR}/bin/portsreinstall-chroot-mount unmount"
@@ -322,48 +467,66 @@ fs_terminate_if_unmount_unavailable ()
                        message_echo "  ${APPNAME}"
                fi
        }
+       [ $TEMP_IN_TRAP = no ] || temp_terminate_process
        exit 3
 }
 
 # ============= Unmount  file systems for the chroot environment =============
 fs_unmount ()
 {
-       local systembase
-       systembase=$1
-       [ ! -d "$systembase/$opt_basedir"/builder ] && return
-       [ -e "${DBDIR}/mount_manifest" ] || return 0
-       message_echo "Unmounting the file systems for builder chroot."
-       fs_safeguard_basedir "$opt_basedir"
-       tail -r "${DBDIR}/mount_manifest" | while read srcline
-       do
-               type=`echo "$srcline" | cut -f 1`
-               target=`echo "$srcline" | cut -f 2`
-               [ "x$type" = xnullfs -o "x$type" = xunionfs ] && target=$systembase/$target
-               directory=`echo "$srcline" | cut -f 3`
-               opt=`echo "$srcline" | cut -f 4`
-               mp=$systembase/$opt_basedir/builder/$directory
-               if misc_chk_mounted "$type" "$target" "$mp"
+       local systembase_access systembase_saved remining
+       systembase_access=`fs_system_base_in_mp_access`
+       ! fs_get_mounttime_systembase > /dev/null && return
+       fs_terminate_if_unmount_unavailable
+       [ ! -d "$systembase_access/$opt_basedir"/builder ] && return
+       [ ! -e "${DBDIR}/mount_manifest" ] && return
+       if fs_chk_unmount > /dev/null
+       then
+               if [ $TEMP_IN_TRAP = no ]
                then
-                       umount -f "$mp"
+                       message_echo "The builder chroot environment is already unmounted."
+                       message_echo
                fi
+               return
+       fi
+       if [ $TEMP_IN_TRAP = no ]
+       then
+               message_section_title "Unmounting the file systems for builder chroot."
+       else
+               message_echo
+               message_echo "Unmounting the file systems for builder chroot."
+       fi
+       fs_gen_fstab unmount
+       umount -F "${DBDIR}/fstab" -af 2> /dev/null || :
+       itrial=${FS_UNMOUNT_RETIAL_MAXNUM}
+       while [ $itrial -gt 0 ]
+       do
+               remining=`fs_chk_unmount` && break
+               echo -n "$remining" | str_regularize_df_path_filter | while read remining_mp
+               do
+                       umount -f "$remining_mp" || :
+               done
+               message_echo "(Retrying to unmount the file systems...)" >&2
+               sleep ${FS_UNMOUNT_RETIAL_WAIT}
+               umount -F "${DBDIR}/fstab" -af 2> /dev/null || :
+               itrial=$(($itrial-1))
        done
-       if ! fs_chk_unmount "$systembase"
+       if [ $itrial -eq 0 ]
        then
-               message_echo "Error: Failed to unmount the file systems. Some of them remain mounted." >&2
-               exit 1
+               message_echo "WARNING: Failed to unmount the file systems. Some of them remain mounted." >&2
+               return 1
        fi
+       rm -f "${DBDIR}/fs_systembase"
        message_echo "Unmounting done."
+       message_echo
 }
 
 # ============= Destroy the chroot environment =============
 fs_destroy ()
 {
-       local systembase
-       systembase=$1
        fs_chk_safety_basedir "$opt_basedir" || return 0
        [ ! -d "$opt_basedir" ] && return
-       fs_terminate_if_unmount_unavailable "$systembase"
-       fs_unmount "$systembase"
+       fs_unmount || return
        chflags -R noschg "$opt_basedir"
        rm -rf "$opt_basedir"
 }