Skip to content

Commit d310643

Browse files
committed
fix: reliably identify canonical bind mount source
1 parent baccb9f commit d310643

File tree

1 file changed

+59
-20
lines changed

1 file changed

+59
-20
lines changed

common/anything-sync-daemon.in

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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

213246
mount_is_overlay() {
@@ -247,14 +280,20 @@ mount_options_match() {
247280
}
248281

249282
bind_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

Comments
 (0)