OSDN Git Service

Fix to the same point.
[portsreinstall/current.git] / lib / libfs.sh
1 #!/bin/sh -e
2 # ==============================================================================
3 # portsreinstall library script
4 # - File system operations -
5 # Copyright (C) 2018 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
6 # This software is distributed under the 2-Clause BSD License.
7 # ==============================================================================
8
9 # ============= Get the global path of a possibly not yet created file/directory =============
10 fs_global_path ()
11 {
12         local $path_src
13         path_src=$1
14         if [ -e "$path_src" ]
15         then
16                 realpath "$path_src"
17         else
18                 expr "$path_src" : '^/' > /dev/null || echo -n `realpath .`
19                 echo "$path_src"
20         fi
21 }
22
23 # ============= Inspect the privilege of the current environment on file system operation =============
24 fs_inspect_fs_privilege ()
25 {
26         local tgv mp mp_regexp mount_privilege basedir
27         [ -d "${TMPDIR}"/fs_privilege ] && return
28         tgv=${TMPDIR}/fs_privilege/test_tg
29         mkdir -p "$tgv" "${TMPDIR}"/fs_privilege/test_mp
30         mp=`realpath "${TMPDIR}"/fs_privilege/test_mp`
31         mp_regexp=`str_escape_regexp "$mp"`
32         echo yes > ${TMPDIR}/fs_privilege/fs_privilege
33         cat > ${TMPDIR}/fs_privilege/fslist << eof
34 devfs   devfs
35 fdescfs null
36 procfs  proc
37 tmpfs   tmpfs
38 nullfs  "$tgv"
39 unionfs "$tgv"
40 eof
41         while read fs tg
42         do
43                 if mount -t $fs "$tgv" "$mp" 2> /dev/null && umount "$mp"
44                 then
45                         echo yes
46                 else
47                         echo no
48                         echo no > ${TMPDIR}/fs_privilege/fs_privilege
49                 fi > ${TMPDIR}/fs_privilege/fs_privilege:$fs 2> /dev/null
50                 umount -f "$mp" 2> /dev/null || :
51                 [ -e "${TMPDIR}"/fs_privilege/basedir ] && continue
52                 mount -t $fs "$tgv" "$mp" 2> /dev/null && \
53                         df "$mp" > ${TMPDIR}/fs_privilege/df:$fs && \
54                         umount "$mp"
55                 real_mp=`sed 1d "${TMPDIR}"/fs_privilege/df:$fs | tail -n 1 | \
56                         sed -E 's/^.*[[:space:]][0-9]+%[[:space:]]+//'`
57                 echo "$real_mp" | sed -E "s/$mp_regexp$//" > ${TMPDIR}/fs_privilege/basedir
58         done < ${TMPDIR}/fs_privilege/fslist
59         mount_privilege=`cat "${TMPDIR}"/fs_privilege/fs_privilege`
60         if [ "x$mount_privilege" = xyes ]
61         then
62                 mount -t nullfs /bin "$mp" 2> /dev/null
63                 if [ `ls "$mp" 2> /dev/null | wc -l` -gt 0 ]
64                 then
65                         echo yes
66                 else
67                         echo no
68                 fi > ${TMPDIR}/fs_privilege/nullfs_target_recognition
69                 umount -f "$mp" 2> /dev/null || :
70                 nullfs_target_recognition=`cat "${TMPDIR}"/fs_privilege/nullfs_target_recognition`
71                 if [ "x$nullfs_target_recognition" = xyes ]
72                 then
73                         message_echo "INFO: The current environment has the full required privilege of mounting/unmounting file systems."
74                 else
75                         message_echo "INFO: The current environment formally has the full required privilege of mounting/unmounting file systems but the recognition of nullfs/unionfs targets is incorrect."
76                 fi
77         else
78                 echo no > ${TMPDIR}/fs_privilege/nullfs_target_recognition
79                 message_echo "INFO: The current environment does not have the privilege of mounting/unmounting for the following file system(s)."
80                 while read fs tg
81                 do
82                          mount_privilege=`cat "${TMPDIR}"/fs_privilege/fs_privilege:$fs`
83                          [ "x$mount_privilege" = xyes ] || echo '  '$fs
84                 done < ${TMPDIR}/fs_privilege/fslist | message_cat
85         fi
86         basedir=`cat "${TMPDIR}"/fs_privilege/basedir 2> /dev/null || :`
87         if [ -n "$basedir" ]
88         then
89                 message_echo "INFO: The current environment will be a chroot/jail guest whose base directory is \"$basedir\"."
90         fi
91         if [ "x$opt_invalidate_mount_privilege" = xyes ]
92         then
93                 message_echo "INFO: The privilege of mounting/unmounting in this environment is forcibly invalidated."
94         fi
95 }
96
97 # ============= Check whether mounting file systems are available at the current environment =============
98 fs_chk_mount_privilege ()
99 {
100         local mount_privilege
101         fs_inspect_fs_privilege
102         [ "x$opt_invalidate_mount_privilege" = xno ] || return
103         mount_privilege=`cat "${TMPDIR}"/fs_privilege/fs_privilege`
104         nullfs_target_recognition=`cat "${TMPDIR}"/fs_privilege/nullfs_target_recognition`
105         [ "x$nullfs_target_recognition" = xyes -a "x$mount_privilege" = xyes ]
106 }
107
108 # ============= Check whether mounting file systems are available at the current environment =============
109 fs_chk_unmount_privilege ()
110 {
111         local mount_privilege
112         fs_inspect_fs_privilege
113         [ "x$opt_invalidate_mount_privilege" = xno ] || return
114         mount_privilege=`cat "${TMPDIR}"/fs_privilege/fs_privilege`
115         [ "x$mount_privilege" = xyes ]
116 }
117
118 # ============= Get the base directory the current environment (applicable in case of a chroot guest) =============
119 fs_get_system_basedir ()
120 {
121         fs_inspect_fs_privilege
122         cat "${TMPDIR}"/fs_privilege/basedir 2> /dev/null || :
123 }
124
125 # ============= Get the regular expression pattern of the actual mount point =============
126 fs_get_actual_mount_point_pattern ()
127 {
128         local mountpoint basedir mountpoint_real
129         mountpoint=$1
130         [ -e  "$mountpoint" ] || return
131         fs_inspect_fs_privilege
132         basedir=`cat "${TMPDIR}"/fs_privilege/basedir 2> /dev/null || :`
133         mountpoint_real=`realpath "$mountpoint"`
134         mountpoint_real_full=`echo "$basedir$mountpoint_real" | sed 's|//*|/|'`
135         str_escape_regexp "$mountpoint_real_full"
136 }
137
138 # ============= Get mount info at the descendant directory levels required for builder chroot environment =============
139 fs_get_descendant_mount_info ()
140 {
141         local mountpoint mountpoint_real_regexp basedir
142         mountpoint=$1
143         mountpoint_real_regexp=`fs_get_actual_mount_point_pattern "$mountpoint"` || return
144         basedir=`cat "${TMPDIR}"/fs_privilege/basedir 2> /dev/null || :`
145         basedir_ptn=`str_escape_regexp "$basedir"`
146         df | sed 1d | grep -E "%[[:space:]]+$mountpoint_real_regexp\/" | while read fs data
147         do
148                 echo "$fs" | grep -q -e '^/' -e '^<above>:' && fs=normal
149                 mp_abs=`echo "$data" | sed -E  's|.*%[[:space:]]+(/.+)$|\1|'`
150                 mp=`echo "$mp_abs" | sed -E "s|^$basedir_ptn||"`
151                 relative=`echo "$mp_abs" | sed -E "s|^$mountpoint_real_regexp||"`
152                 printf '%s\t%s\t%s\n' "$fs" "$mp" "$relative"
153         done
154 }
155
156 # ============= Repair the unionfs image if applicable and hidden =============
157 # Use the side effect of find(1).
158 fs_fix_unionfs_image_if_hidden ()
159 {
160         local needlepath needlepath_cur needlepath_next
161         needlepath=$1
162         needlepath_cur=$needlepath
163         while :
164         do
165                 find -dx "$needlepath_cur" -maxdepth 0 > /dev/null 2>&1 || :
166                 needlepath_next=`dirname "$needlepath_cur"`
167                 [ "x$needlepath_cur" = "x$needlepath_next" ] && break
168                 needlepath_cur=$needlepath_next
169         done
170         [ -e "$needlepath" ] && return
171         message_echo "ERROR: Lost mandatory file, probably due to the bug of unionfs: $needlepath" >&2
172         exit 1
173 }
174
175 # ============= Check whether a directory is mounted properly =============
176 fs_chk_mounted ()
177 {
178         local type target mountpoint target_ptn mountpoint_real_regexp tmpsrc
179         type=$1
180         target=$2
181         mountpoint=$3
182         target_ptn=`echo "$target" | sed 's|//*|/|g' | str_escape_regexp_filter`
183         mountpoint_real_regexp=`fs_get_actual_mount_point_pattern "$mountpoint"` || return
184         basedir=`cat "${TMPDIR}"/fs_privilege/basedir 2> /dev/null || :`
185         basedir_target_ptn=`echo "$basedir/$target" | sed 's|//*|/|g' | str_escape_regexp_filter`
186         tmpsrc=${TMPDIR}/fs_chk_mounted:src
187         df | sed 1d | grep -E "%[[:space:]]+$mountpoint_real_regexp$" > $tmpsrc
188         case $type in
189                 nullfs )
190                         grep -qE "^${target_ptn}[[:space:]]" "$tmpsrc" || grep -qE "^${basedir_target_ptn}[[:space:]]" "$tmpsrc"
191                         ;;
192                 unionfs )
193                         grep -qE "^<above>:${target_ptn}[[:space:]]" "$tmpsrc" || grep -qE "^<above>:${basedir_target_ptn}[[:space:]]" "$tmpsrc"
194                         ;;
195                 devfs | fdescfs | procfs | linprocfs | tmpfs )
196                         grep -q "^$type" "$tmpsrc"
197                         ;;
198                 *)
199                         message_echo "ERROR: Unsupported fyle system [$type]" >&2
200                         exit 1
201                         ;;
202         esac
203 }
204