OSDN Git Service

The HISTORY description about the adaption to the specification change to disallow...
[portsreinstall/current.git] / lib / chroot / libfs.sh
1 #!/bin/sh -e
2 # ==============================================================================
3 # portsreinstall-chroot library script
4 # Overlay onto lib/libfs.sh for portsreinstall-chroot
5 # - File system operations -
6 # Copyright (C) 2018-2022 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
7 # This software is distributed under the 2-Clause BSD License.
8 # ==============================================================================
9
10 FS_UNMOUNT_RETIAL_MAXNUM=5      # Number of retrial of unmounting
11 FS_UNMOUNT_RETIAL_WAIT=3        # Wait seconds in retrial of unmounting
12
13 # ============= Check the safety of the base directory of builder chroot environment =============
14 fs_chk_safety_basedir ()
15 {
16         local basedir
17         basedir=$1
18         [ -n "$basedir" ] || return
19         case "$basedir" in
20         /|/bin|/boot|/compat|/dev|/entropy|/etc|/home|/host|/lib|/libexec|/net|/proc|/rescue|/root|/sbin|/sys|/tmp|/usr|/var)
21                 return 1
22                 ;;
23         esac
24         expr "$basedir" : '^/boot/.*' > /dev/null && return 1
25         expr "$basedir" : '^/compat/.*' > /dev/null && return 1
26         expr "$basedir" : '^/dev/.*' > /dev/null && return 1
27         expr "$basedir" : '^/etc/.*' > /dev/null && return 1
28         expr "$basedir" : '^/lib/.*' > /dev/null && return 1
29         expr "$basedir" : '^/libexec/.*' > /dev/null && return 1
30         expr "$basedir" : '^/proc/.*' > /dev/null && return 1
31         expr "$basedir" : '^/sbin/.*' > /dev/null && return 1
32         :
33 }
34
35 # ============= Safeguard of the base directory of builder chroot environment =============
36 fs_safeguard_basedir ()
37 {
38         local basedir
39         basedir=$1
40         fs_chk_safety_basedir "$basedir" && return
41         message_echo "ERROR: The base directory [$opt_basedir] is not safe." >&2
42         exit 1
43 }
44
45 # ============= Save the system base observed currently =============
46 fs_save_current_systembase ()
47 {
48         local systembase 
49         systembase=$1
50         echo "$systembase" >  ${TMPDIR}/fs_save_current_systembase
51 }
52
53 # ============= Save the system base observed at the time of mounting =============
54 fs_save_mounttime_systembase ()
55 {
56         local systembase 
57         systembase=$1
58         echo "$systembase" >  ${DBDIR}/fs_systembase
59 }
60
61 # ============= Get the system base observed currently =============
62 fs_get_current_systembase ()
63 {
64         local systembase
65         systembase=`cat "${TMPDIR}/fs_save_current_systembase" 2> /dev/null`
66         [ -z "$systembase" ] || realpath "$systembase"
67 }
68
69 # ============= Get the system base observed at the time of mounting =============
70 # Non-zero return means no file system was attempted to mount
71 fs_get_mounttime_systembase ()
72 {
73         local systembase
74         systembase=`cat "${DBDIR}/fs_systembase" 2> /dev/null`
75         [ -z "$systembase" ] || realpath "$systembase"
76 }
77
78 # ============= Get the system base in the scope of accessing =============
79 fs_system_base_in_mp_access ()
80 {
81         fs_get_current_systembase
82 }
83
84 # ============= Get the system base in the scope of creating mount points =============
85 fs_system_base_in_mp_creation ()
86 {
87         fs_get_current_systembase
88 }
89
90 # ============= Get the system base in the scope of referring to mount points =============
91 fs_system_base_in_mp_reference ()
92 {
93         str_regularize_df_path "`fs_get_current_systembase`/`fs_get_system_basedir`"
94 }
95
96 # ============= Get the system base in the scope of targets =============
97 # Non-zero return means no file system was attempted to mount
98 fs_system_base_in_target ()
99 {
100         fs_get_mounttime_systembase
101 }
102
103 # ============= Build the file systems for the builder chroot environment =============
104 fs_build_chroot ()
105 {
106         [ -e "${DBDIR}/mount_manifest" ] && return
107         message_echo "Building the file systems for builder chroot environment (if not yet)."
108         fs_safeguard_basedir "$opt_basedir"
109         fs_unmount || return
110         mkdir -p "$opt_basedir"
111         # Prescan the file system of the original environment
112         cp /dev/null "${TMPDIR}/fs_build_chroot:directories"
113         (
114                 real_basedir=`realpath "$opt_basedir"`
115                 {
116 #                       echo bin compat etc lib libexec root sbin sys usr | tr ' ' '\n'
117                         echo bin compat etc lib libexec root sbin sys usr var | tr ' ' '\n'
118                         echo "$opt_extra_dirs" | tr "$opt_extra_dirs_delim" '\n'
119                 } | env LANG=C grep -v '^[[:space:]]*$' | sort -u | while read node
120                 do
121                         [ -e "/$node" ] || continue
122                         src_mountpoint_real=`realpath "/$node"`
123                         ptn_src_mountpoint_real=`str_escape_regexp "$src_mountpoint_real/"`
124                         if echo "$real_basedir" | grep -Eq "^$ptn_src_mountpoint_real"
125                         then
126                                 (
127                                         node_cur=$node
128                                         rm -f "${TMPDIR}/fs_build_chroot:hit_exact"
129                                         while [ ! -e "${TMPDIR}/fs_build_chroot:hit_exact" ]
130                                         do
131                                                 rm -f "${TMPDIR}/fs_build_chroot:hit_subnode"
132                                                 cd "/$node_cur"
133                                                 ls -a | while read subnode
134                                                 do
135                                                         if [ "$subnode" = . -o "$subnode" = .. ]
136                                                         then
137                                                                 continue
138                                                         elif [ -L "$subnode" -o -f "$subnode" ]
139                                                         then
140                                                                 echo "$node_cur/$subnode"
141                                                         elif [ -d "$subnode" ]
142                                                         then
143                                                                 node_cur_tmp_real=`realpath "/$node_cur/$subnode"`
144                                                                 ptn_node_cur_tmp_real=`str_escape_regexp "$node_cur_tmp_real/"`
145                                                                 if [ "$real_basedir" = "$node_cur_tmp_real" ]
146                                                                 then
147                                                                         touch "${TMPDIR}/fs_build_chroot:hit_exact"
148                                                                 elif echo "$real_basedir" | grep -Eq "^$ptn_node_cur_tmp_real"
149                                                                 then
150                                                                         echo "$subnode" > ${TMPDIR}/fs_build_chroot:hit_subnode
151                                                                 else
152                                                                         echo "$node_cur/$subnode"
153                                                                 fi
154                                                         fi
155                                                 done
156                                                 [ -e "${TMPDIR}/fs_build_chroot:hit_subnode" ] || break
157                                                 node_cur=$node_cur/`cat "${TMPDIR}/fs_build_chroot:hit_subnode"`
158                                         done
159                                 )
160                         else
161                                 echo "$node"
162                         fi
163                 done > ${TMPDIR}/fs_build_chroot:sys_nodes
164                 sysdirs_ptn="^/*(`str_escape_regexp_filter < ${TMPDIR}/fs_build_chroot:sys_nodes | tr '\n' '|' | sed 's/\|$//'`)/+"
165                 while read node
166                 do
167                         [ -e "/$node" ] || continue
168                         if [ -L "/$node" -a -d "/$node" ]
169                         then
170                                 src_mountpoint_real=`realpath "/$node"`
171                                         printf '%s\t%s\n' link "$node" >> ${TMPDIR}/fs_build_chroot:directories
172                                 if ! echo "$src_mountpoint_real/" | env LANG=C grep -qE "$sysdirs_ptn"
173                                 then
174                                         printf '%s\t%s\n' real "$src_mountpoint_real" >> ${TMPDIR}/fs_build_chroot:directories
175                                         tmpdir_descendant=${TMPDIR}/fs_build_chroot:descendant/$src_mountpoint_real
176                                         mkdir -p "$tmpdir_descendant"
177                                         fs_get_descendant_mount_info "/$src_mountpoint_real" > $tmpdir_descendant/list
178                                 fi
179                         elif [ -d "/$node" ]
180                         then
181                                 printf '%s\t%s\n' real $node >> ${TMPDIR}/fs_build_chroot:directories
182                                 tmpdir_descendant=${TMPDIR}/fs_build_chroot:descendant/$node
183                                 mkdir -p "$tmpdir_descendant"
184                                 fs_get_descendant_mount_info "/$node" > $tmpdir_descendant/list
185                         elif [ -L "/$node" -o -f "/$node" ]
186                         then
187                                 cp -p "/$node" "$node" 
188                         fi
189                 done < ${TMPDIR}/fs_build_chroot:sys_nodes
190         )
191         # Prepare the grand base of the chroot environment
192         (
193                 cd "$opt_basedir"
194                 for directory in builder mask store
195                 do
196                         [ -d $directory ] || mkdir $directory
197                 done
198         )
199         # Directories to share with the host environment by nullfs
200         if [ "x$opt_share_port_pkgs_dirs" = xyes ]
201         then
202                 echo "$PORTSDIR"
203                 echo "$PORTSNAP_WORKDIR"
204                 echo "$PKGNG_PKG_CACHEDIR"
205         fi | str_regularize_df_path_filter | env LANG=C grep -v '^[[:space:]]*$' | sort -u > ${DBDIR}/shared_dirs.lst
206         str_escape_regexp_filter < ${DBDIR}/shared_dirs.lst | sed 's|^|^|;s|$|\/|' > ${TMPDIR}/fs_build_chroot:shared_dirs.regexp.tmp
207         paste "${DBDIR}/shared_dirs.lst" "${TMPDIR}/fs_build_chroot:shared_dirs.regexp.tmp" > ${TMPDIR}/fs_build_chroot:shared_dirs.regexp
208         cp /dev/null "${TMPDIR}/fs_build_chroot:shared_dirs:added"
209         # Build target directories and the manifest for mounting
210         mkdir -p "$opt_basedir/mask"
211         cp /dev/null "${DBDIR}/mount_manifest.tmp"
212         (
213                 real_basedir=`realpath "$opt_basedir"`
214                 cd "$real_basedir"/builder
215                 while read srcline
216                 do
217                         type=`echo "$srcline" | cut -f 1`
218                         directory=`echo "$srcline" | cut -f 2`
219                         case $type in
220                         link )
221                                 [ -e "$directory" -o -L "$directory" ] || cp -RpP "/$directory" .
222                                 ;;
223                         real )
224                                 mkdir -p "./$directory"
225                                 masktarget=$real_basedir/mask/$directory
226                                 mkdir -p "$masktarget"
227                                 printf '%s\t%s\t%s\t%s\n' nullfs "/$directory" "$directory" ro >> ${DBDIR}/mount_manifest.tmp
228                                 printf '%s\t%s\t%s\t%s\n' unionfs "$masktarget" "$directory" rw,noatime >> ${DBDIR}/mount_manifest.tmp
229                                 while read srcline
230                                 do
231                                         fs=`echo "$srcline" | cut -f 1`
232                                         mp=`echo "$srcline" | cut -f 2 | str_regularize_df_path_filter`
233                                         relative=`echo "$srcline" | cut -f 3 | str_regularize_df_path_filter`
234                                         fullpath=`str_regularize_df_path "/$directory/$relative"`
235                                         rm -f "${TMPDIR}/fs_build_chroot:shared_dirs:is_under"
236                                         rm -f "${TMPDIR}/fs_build_chroot:shared_dirs:is_itself"
237                                         while read -r shared_path shared_path_regexp
238                                         do
239                                                 echo "$fullpath/" | env LANG=C grep -qE "$shared_path_regexp" || continue
240                                                 echo "$shared_path"$'\n'"$fullpath" | while read mpath
241                                                 do
242                                                         if  ! env LANG=C grep -qFx "$mpath" "${TMPDIR}/fs_build_chroot:shared_dirs:added"
243                                                         then
244                                                                 echo "$mpath" >> ${TMPDIR}/fs_build_chroot:shared_dirs:added
245                                                                 mkdir -p "/$mpath"
246                                                                 mp_share=`realpath "/$mpath"`
247                                                                 printf '%s\t%s\t%s\t%s\n' nullfs "$mp_share" "$mpath" rw >> ${DBDIR}/mount_manifest.tmp
248                                                         fi
249                                                 done
250                                                 touch "${TMPDIR}/fs_build_chroot:shared_dirs:is_under"
251                                         done < ${TMPDIR}/fs_build_chroot:shared_dirs.regexp
252                                         [ -e "${TMPDIR}/fs_build_chroot:shared_dirs:is_under" ] && continue
253                                         case $fs in
254                                                 normal )
255                                                         masktarget=`str_regularize_df_path "$real_basedir/mask/$fullpath"`
256                                                         mkdir -p "$masktarget"
257                                                         printf '%s\t%s\t%s\t%s\n' nullfs "$mp" "$fullpath" ro >> ${DBDIR}/mount_manifest.tmp
258                                                         printf '%s\t%s\t%s\t%s\n' unionfs "$masktarget" "$fullpath" rw,noatime >> ${DBDIR}/mount_manifest.tmp
259                                                         ;;
260                                                 devfs )
261                                                         printf '%s\t%s\t%s\t%s\n' devfs devfs "$fullpath" rw >> ${DBDIR}/mount_manifest.tmp
262                                                         ;;
263                                                 fdescfs )
264                                                         printf '%s\t%s\t%s\t%s\n' fdescfs fdesc "$fullpath" rw >> ${DBDIR}/mount_manifest.tmp
265                                                         ;;
266                                                 procfs )
267                                                         printf '%s\t%s\t%s\t%s\n' procfs proc "$fullpath" rw >> ${DBDIR}/mount_manifest.tmp
268                                                         ;;
269                                                 linprocfs )
270                                                         printf '%s\t%s\t%s\t%s\n' linprocfs linproc "$fullpath" rw >> ${DBDIR}/mount_manifest.tmp
271                                                         ;;
272                                                 tmpfs )
273                                                         printf '%s\t%s\t%s\t%s\n' tmpfs tmpfs "$fullpath" rw,mode=1777 >> ${DBDIR}/mount_manifest.tmp
274                                                         ;;
275                                         esac
276                                 done < ${TMPDIR}/fs_build_chroot:descendant/$directory/list
277                                 ;;
278                         esac
279                 done < ${TMPDIR}/fs_build_chroot:directories
280                 env LANG=C grep -Ev -f "${TMPDIR}/fs_build_chroot:shared_dirs:added" "${DBDIR}/shared_dirs.lst" | while read shared_dir
281                 do
282                         mkdir -p "$shared_dir"
283                         mp_share=`realpath "$shared_dir"`
284                         printf '%s\t%s\t%s\t%s\n' nullfs "$mp_share" "/$shared_dir" rw >> ${DBDIR}/mount_manifest.tmp
285                 done
286                 for directory in dev proc tmp 
287                 do
288                         [ -e $directory ] || mkdir $directory
289                 done
290                 printf '%s\t%s\t%s\t%s\n' devfs devfs dev rw >> ${DBDIR}/mount_manifest.tmp
291                 printf '%s\t%s\t%s\t%s\n' fdescfs fdesc dev/fd rw >> ${DBDIR}/mount_manifest.tmp
292                 printf '%s\t%s\t%s\t%s\n' procfs proc proc rw >> ${DBDIR}/mount_manifest.tmp
293                 printf '%s\t%s\t%s\t%s\n' tmpfs tmpfs tmp rw,mode=1777 >> ${DBDIR}/mount_manifest.tmp
294                 mkdir -p ."${PROGRAM}"
295                 cd "$real_basedir/mask"
296                 if [ ! -e root/.cshrc ]
297                 then
298                         tmp_cshrc=${TMPDIR}/fs_build_chroot:.cshrc
299                         [ -d root ] || mkdir root
300                         if [ -e /root/.cshrc ]
301                         then
302                                 cp -p /root/.cshrc "$tmp_cshrc"
303                                 cp -p /root/.cshrc "root/.cshrc.bak-${APPNAME}"
304                         elif [ -e /usr/share/skel/dot.cshrc ]
305                         then
306                                 cp -p /usr/share/skel/dot.cshrc "$tmp_cshrc"
307                                 touch "root/.cshrc.bak-${APPNAME}"
308                         else
309                                 cp /dev/null "$tmp_cshrc"
310                         fi
311                         echo >> $tmp_cshrc
312                         echo 'set prompt="%N@[builder]%m:%~ %# "' >> $tmp_cshrc
313                         mv "$tmp_cshrc" root/.cshrc
314                 fi
315                 printf '%s\t%s\t%s\t%s\n' nullfs "$real_basedir"/store ".${PROGRAM}" rw >> ${DBDIR}/mount_manifest.tmp
316         )
317         mv "${DBDIR}/mount_manifest.tmp" "${DBDIR}/mount_manifest"
318 }
319
320 # ============= Check whether the file systems for the builder chroot environment are all mounted =============
321 fs_chk_mount ()
322 {
323         local systembase_target systembase_mp tmp_remains
324         [ -e "${DBDIR}/mount_manifest" ] || return
325         systembase_target=`fs_system_base_in_target` || return
326         systembase_mp=`fs_system_base_in_mp_reference`
327         tmp_remains=${TMPDIR}/fs_chk_mount:remains
328         rm -rf "$tmp_remains"
329         while read srcline
330         do
331                 type=`echo "$srcline" | cut -f 1`
332                 target=`echo "$srcline" | cut -f 2`
333                 [ "x$type" = xnullfs -o "x$type" = xunionfs ] && target=`str_regularize_df_path "$systembase_target/$target"`
334                 directory=`echo "$srcline" | cut -f 3`
335                 opt=`echo "$srcline" | cut -f 4`
336                 mp=`str_regularize_df_path "$systembase_mp/$opt_basedir/builder/$directory"`
337                 expr "$target" : \\/ && target=`realpath "$target"`
338                 if ! real_mp=`realpath "$mp" 2> /dev/null` || ! fs_chk_mounted "$type" "$target" "$real_mp"
339                 then
340                         printf '%s\t%s\t%s\n' "$type" "$target" "$mp" >> $tmp_remains
341                 fi
342         done < ${DBDIR}/mount_manifest
343         ! cat "$tmp_remains" 2> /dev/null
344 }
345
346 # ============= Terminate when the file systems for the builder chroot environment cannot be mounted: For mounting at the grand host =============
347 fs_terminate_if_mount_unavailable__mount_at_host () { :; }
348
349 # ============= Terminate when the file systems for the builder chroot environment cannot be mounted =============
350 fs_terminate_if_mount_unavailable ()
351 {
352         local systembase systembase_saved
353         systembase=`fs_get_current_systembase`
354         fs_chk_mount > /dev/null && return
355         if systembase_saved=`fs_get_mounttime_systembase`
356         then
357                 if [ "x$systembase" = "x$systembase_saved" ]
358                 then
359                         fs_chk_mount_privilege && return
360                 elif [ -n "$systembase" ]
361                 then
362                         fs_terminate_if_mount_unavailable__mount_at_host
363                 fi
364         elif fs_chk_mount_privilege
365         then
366                 fs_save_mounttime_systembase "`fs_get_current_systembase`"
367                 return
368         fi
369         temp_terminate_process ()
370         {
371                 local basedir
372                 [ $opt_batch_mode = yes ] && return
373                 message_echo
374                 message_echo "INFO: Terminated for mounting file systems because this utility was executed at a virtual (chroot or jail) environment."
375                 message_echo "Execute"
376                 basedir=`fs_get_system_basedir`
377                 if [ -n "$basedir" ]
378                 then
379                         message_echo "  $basedir${SHAREDIR}/bin/portsreinstall-chroot-mount"
380                         message_echo "at the grand host environment."
381                 else
382                         message_echo "  \$BASEDIR${SHAREDIR}/bin/portsreinstall-chroot-mount"
383                         message_echo "at the grand host environment, where \$BASEDIR denotes the base directory of this virtual environment."
384                 fi
385                 message_echo "After its successful execution, rerun"
386                 if [ -n "$COMMAND_RESTART" ]
387                 then
388                         message_echo "  ${APPNAME} $COMMAND_RESTART"
389                 else
390                         message_echo "  ${APPNAME}"
391                 fi
392         }
393         [ $TEMP_IN_TRAP = no ] || temp_terminate_process
394         exit 2
395 }
396
397 # ============= Generate a custom fstab file for the builder chroot environment =============
398 fs_gen_fstab ()
399 {
400         local stage systembase_target systembase_mp
401         stage=$1
402         systembase_target=`fs_system_base_in_target`
403         case $stage in
404         mount )
405                 systembase_mp=`fs_system_base_in_mp_creation`
406                 ;;
407         unmount )
408                 systembase_mp=`fs_system_base_in_mp_reference`
409                 ;;
410         esac
411         fs_safeguard_basedir "$opt_basedir"
412         while read srcline
413         do
414                 type=`echo "$srcline" | cut -f 1`
415                 target=`echo "$srcline" | cut -f 2`
416                 directory=`echo "$srcline" | cut -f 3`
417                 opt=`echo "$srcline" | cut -f 4`
418                 [ "x$type" = xnullfs -o "x$type" = xunionfs ] && target=$systembase_target/$target
419                 target=`str_regularize_df_path "$target"`
420                 mp=`str_regularize_df_path "$systembase_mp/$opt_basedir/builder/$directory"`
421                 opt=`echo "$opt" | sed 's/[[:space:]]/\\040/g'`
422                 echo "$target $mp $type $opt 0 0"
423         done < ${DBDIR}/mount_manifest > ${DBDIR}/fstab
424 }
425
426 # ============= Mount the file systems for the builder chroot environment if not yet =============
427 fs_mount ()
428 {
429         local remining
430         if fs_chk_mount > /dev/null
431         then
432                 message_echo "The builder chroot environment is already mounted."
433                 message_echo
434                 return
435         fi
436         fs_terminate_if_mount_unavailable
437         message_section_title "Mounting the file systems for builder chroot environment."
438         fs_gen_fstab mount
439         remining=
440         if ! mount -F "${DBDIR}/fstab" -a || ! remining=`fs_chk_mount`
441         then
442                 cp "${DBDIR}/fstab" "${DBDIR}/fstab-mount-err"
443                 message_echo "ERROR: Failed to mount the file systems. The followings remain unmounted:" >&2
444                 if [ $opt_batch_mode = no ]
445                 then
446                         [ -n "$remining" ] || remining=`fs_chk_mount` || :
447                         echo "$remining" >&2
448                 fi
449                 exit 1
450         fi
451         message_echo "Mounting done."
452         message_echo
453 }
454
455 # ============= Check whether the file systems for the builder chroot environment are all unmounted or destroyed =============
456 fs_chk_unmount ()
457 {
458         local systembase_target systembase_mp tmp_remains
459         [ -e "${DBDIR}/mount_manifest" ] || return 0
460         systembase_target=`fs_system_base_in_target` || return 0
461         systembase_mp=`fs_system_base_in_mp_reference`
462         tmp_remains=${TMPDIR}/fs_chk_unmount:remains
463         rm -rf "$tmp_remains"
464         tail -r "${DBDIR}/mount_manifest" | while read srcline
465         do
466                 type=`echo "$srcline" | cut -f 1`
467                 target=`echo "$srcline" | cut -f 2`
468                 [ "x$type" = xnullfs -o "x$type" = xunionfs ] && target=$systembase_target/$target
469                 directory=`echo "$srcline" | cut -f 3`
470                 opt=`echo "$srcline" | cut -f 4`
471                 mp=`str_regularize_df_path "$systembase_mp/$opt_basedir/builder/$directory"`
472                 real_mp=`realpath "$mp" 2> /dev/null` || continue
473                 fs_chk_mounted "$type" "$target" "$real_mp" || continue
474                 str_regularize_df_path "$mp" >> $tmp_remains
475         done
476         ! cat "$tmp_remains" 2> /dev/null
477 }
478
479 # ============= Terminate when the file systems for the builder chroot environment cannot be unmounted =============
480 fs_terminate_if_unmount_unavailable ()
481 {
482         local systembase systembase_saved
483         systembase=`fs_get_current_systembase`
484         systembase_saved=`fs_get_mounttime_systembase` || return 0
485         fs_chk_unmount > /dev/null && return
486         if [ "x$systembase" = "x$systembase_saved" ]
487         then
488                 fs_chk_mount_privilege && return
489         elif [ -n "$systembase" ]
490         then
491                 temp_terminate_process ()
492                 {
493                         message_echo "ERROR: Cannot unmount because the current file systems were mounted from inside the virtual (chroot or jail) environment."  >&2
494                         message_echo "INFO: Instead of this command, unmount from inside the virtual (chroot or jail) environment."
495                 }
496                 [ $TEMP_IN_TRAP = no ] || temp_terminate_process
497                 exit 1
498         fi
499         temp_terminate_process ()
500         {
501                 local errno basedir
502                 errno=${1:-0}
503                 [ $opt_batch_mode = yes ] && return
504                 message_echo
505                 message_echo "INFO: Terminated for unmounting file systems because this utility was executed at a virtual (chroot or jail) environment."
506                 message_echo "Execute"
507                 basedir=`fs_get_system_basedir`
508                 if [ -n "$basedir" ]
509                 then
510                         message_echo "  $basedir${SHAREDIR}/bin/portsreinstall-chroot-mount unmount"
511                         message_echo "at the grand host environment."
512                 else
513                         message_echo "  \$BASEDIR${SHAREDIR}/bin/portsreinstall-chroot-mount unmount"
514                         message_echo "at the grand host environment, where \$BASEDIR denotes the base directory of this virtual environment."
515                 fi
516                 message_echo "After its successful execution, rerun"
517                 if [ -n "$COMMAND_RESTART" ]
518                 then
519                         message_echo "  ${APPNAME} $COMMAND_RESTART"
520                 else
521                         message_echo "  ${APPNAME}"
522                 fi
523         }
524         [ $TEMP_IN_TRAP = no ] || temp_terminate_process
525         exit 3
526 }
527
528 # ============= Unmount  file systems for the chroot environment =============
529 fs_unmount ()
530 {
531         local systembase_access systembase_saved remining
532         systembase_access=`fs_system_base_in_mp_access`
533         ! fs_get_mounttime_systembase > /dev/null && return
534         fs_terminate_if_unmount_unavailable
535         [ ! -d "$systembase_access/$opt_basedir"/builder ] && return
536         [ ! -e "${DBDIR}/mount_manifest" ] && return
537         if fs_chk_unmount > /dev/null
538         then
539                 if [ $TEMP_IN_TRAP = no ]
540                 then
541                         message_echo "The builder chroot environment is already unmounted."
542                         message_echo
543                 fi
544                 return
545         fi
546         if [ $TEMP_IN_TRAP = no ]
547         then
548                 message_section_title "Unmounting the file systems for builder chroot."
549         else
550                 message_echo
551                 message_echo "Unmounting the file systems for builder chroot."
552         fi
553         fs_gen_fstab unmount
554         umount -F "${DBDIR}/fstab" -af 2> /dev/null || :
555         itrial=${FS_UNMOUNT_RETIAL_MAXNUM}
556         while [ $itrial -gt 0 ]
557         do
558                 remining=`fs_chk_unmount` && break
559                 echo -n "$remining" | str_regularize_df_path_filter | while read remining_mp
560                 do
561                         umount -f "$remining_mp" || :
562                 done
563                 message_echo "(Retrying to unmount the file systems...)" >&2
564                 sleep ${FS_UNMOUNT_RETIAL_WAIT}
565                 umount -F "${DBDIR}/fstab" -af 2> /dev/null || :
566                 itrial=$(($itrial-1))
567         done
568         if [ $itrial -eq 0 ]
569         then
570                 message_echo "WARNING: Failed to unmount the file systems. Some of them remain mounted." >&2
571                 return 1
572         fi
573         rm -f "${DBDIR}/fs_systembase"
574         message_echo "Unmounting done."
575         message_echo
576 }
577
578 # ============= Destroy the chroot environment =============
579 fs_destroy ()
580 {
581         fs_chk_safety_basedir "$opt_basedir" || return 0
582         [ ! -d "$opt_basedir" ] && return
583         fs_unmount || return
584         chflags -R noschg "$opt_basedir"
585         rm -rf "$opt_basedir"
586 }