@@ -189,25 +189,58 @@ find_mount_first_only() {
189189 find_mount --first-only " $@ "
190190}
191191
192- bind_mount_fsroot () {
193- local with_fsroot without_fsroot
194-
195- with_fsroot=" $( ON_START=" finding bind mount with filesystem root for ${1?} " find_mount -o SOURCE -M " ${1?} " ) " || return
196- without_fsroot=" $( ON_START=" finding bind mount without filesystem root for ${1?} " find_mount --nofsroot -o SOURCE -M " ${1?} " ) " || return
197-
198- # Not a bind mount
199- [[ " $with_fsroot " != " $without_fsroot " ]] || {
200- # shellcheck disable=SC2319
201- local rc=" $? "
202- debug " ${1?} does not appear to be a bind mount"
203- return " $rc "
204- }
205-
206- local fsroot=" ${with_fsroot# " ${without_fsroot} [" } "
207-
208- debug " found filesystem root ${fsroot} for bind mount ${1?} "
192+ # Bash translation of the Python script from https://unix.stackexchange.com/a/346444
193+ bind_mounts () {
194+ declare -gA BIND_MOUNT_MAP=()
195+
196+ local -A id2majmin
197+ local -A id2fsroot
198+ local -A id2tgt
199+ local -A majmin2count
200+
201+ local id majmin fsroot tgt count
202+ while read -r id majmin fsroot tgt; do
203+ id2majmin[" $id " ]=" $majmin "
204+ id2fsroot[" $id " ]=" $fsroot "
205+ id2tgt[" $id " ]=" $tgt "
206+ count=" ${majmin2count["$majmin"]:- 0} "
207+ majmin2count[" $majmin " ]=" $(( count + 1 )) "
208+ done < <( ON_START=' fetching bind mount data' find_mount -o ID,MAJ:MIN,FSROOT,TARGET)
209+
210+ local src_id src src_fsroot
211+ for majmin in " ${! majmin2count[@]} " ; do
212+ unset src_id src src_fsroot
213+
214+ if (( "${majmin2count["$majmin"]} " < 2 )) ; then
215+ continue
216+ fi
209217
210- printf -- ' %s\n' " ${fsroot% ]} "
218+ local src src_fsroot tgt_fsroot
219+ while read -d $' \0' -r id; do
220+ if [[ -z " ${src_id:- } " ]]; then
221+ src_id=" $id "
222+ src=" ${id2tgt["$src_id"]} "
223+ src_fsroot=" ${id2fsroot["$src_id"]} "
224+ else
225+ tgt_fsroot=" ${id2fsroot["$id"]} "
226+ if [[ " $src_fsroot " = " $tgt_fsroot " ]]; then
227+ BIND_MOUNT_MAP[" $id " ]=" $src "
228+ else
229+ BIND_MOUNT_MAP[" $id " ]=" $( clean_path " ${src} /${tgt_fsroot# " ${src_fsroot} " } " ) "
230+ fi
231+ fi
232+ done < <(
233+ # Assume that the shortest mount point for this MAJ:MIN is the "original"
234+ # mount.
235+ for id in " ${! id2majmin[@]} " ; do
236+ id_majmin=" ${id2majmin["$id"]} "
237+ if [[ " $id_majmin " == " $majmin " ]]; then
238+ id_fsroot=" ${id2fsroot["$id"]} "
239+ printf -- ' %s %s\0' " ${# id_fsroot} " " $id "
240+ fi
241+ done | sort -z -n -k1,1 | cut -d' ' -f2- -z
242+ )
243+ done
211244}
212245
213246mount_is_overlay () {
@@ -247,14 +280,20 @@ mount_options_match() {
247280}
248281
249282bind_mount_has_expected_source () {
283+ if ! declare -p BIND_MOUNT_MAP & > /dev/null; then
284+ bind_mounts || return
285+ fi
286+
250287 local src=" $1 "
251288 shift
252289
253290 local tgt=" $1 "
254291 shift
255292
256- local fsroot
257- if fsroot=" $( bind_mount_fsroot " $tgt " ) " && [[ " $fsroot " == " $src " ]]; then
293+ local id
294+ id=" $( ON_START=" fetching mount ID for target ${tgt} " find_mount_first_only -o ID -M " $tgt " ) " || return
295+
296+ if [[ " ${BIND_MOUNT_MAP["$id"]:- } " == " $src " ]]; then
258297 debug " source ${src} appears to be bind-mounted at target ${tgt} "
259298 return 0
260299 else
0 commit comments