Skip to content

Commit 691d869

Browse files
committed
Merge branch 'pr-95'
2 parents f1e5492 + 14a387f commit 691d869

1 file changed

Lines changed: 71 additions & 24 deletions

File tree

repro.in

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,25 @@ function error() {
117117
printf "${RED}==> $(gettext "ERROR:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
118118
}
119119

120+
##
121+
# usage : nlock( $fd, $file, $message, [ $message_arguments... ] )
122+
#
123+
# Desc: non-blocking exclusive (write) lock
124+
##
125+
nlock() {
126+
# Only reopen the FD if it wasn't handed to us
127+
if ! [[ "/dev/fd/$1" -ef "$2" ]]; then
128+
mkdir -p -- "$(dirname -- "$2")"
129+
eval "exec $1>"'"$2"'
130+
fi
131+
132+
flock -n "$1"
133+
}
134+
120135
##
121136
# usage : lock( $fd, $file, $message, [ $message_arguments... ] )
137+
#
138+
# Desc: normal - blocking exclusive (write) lock
122139
##
123140
lock() {
124141
# Only reopen the FD if it wasn't handed to us
@@ -127,20 +144,22 @@ lock() {
127144
eval "exec $1>"'"$2"'
128145
fi
129146

130-
flock -n "$1"
147+
flock "$1"
131148
}
132149

133150
##
134151
# usage : slock( $fd, $file, $message, [ $message_arguments... ] )
152+
#
153+
# Desc: blocking shared (read) lock
135154
##
136-
nlock() {
155+
slock() {
137156
# Only reopen the FD if it wasn't handed to us
138157
if ! [[ "/dev/fd/$1" -ef "$2" ]]; then
139158
mkdir -p -- "$(dirname -- "$2")"
140159
eval "exec $1>"'"$2"'
141160
fi
142161

143-
flock "$1"
162+
flock -s "$1"
144163
}
145164

146165
##
@@ -158,13 +177,28 @@ lock_close() {
158177
# 2: Command to execute
159178
function exec_nspawn(){
160179
local container=$1
180+
181+
# EPHEMERAL in systemd-nspawn uses implicit overlayfs mounts to provide
182+
# the container. If the root container is being updated or files are in
183+
# the lower directory disappear the results are unspecified and might
184+
# cause weird behaviour.
185+
#
186+
# Thus we acquire read locks on the build container to ensure nothing gets
187+
# a write lock. The code is weird because the locking mechanism here is
188+
# implicit as opposed to explicit in the top level of cmd_check.
189+
if ((EPHEMERAL)); then
190+
slock 8 "$BUILDDIRECTORY/$container.lock"
191+
fi
161192
systemd-nspawn -q \
162-
--as-pid2 \
163-
--register=no \
164-
${EPHEMERAL:+--ephemeral} \
165-
--pipe \
166-
-E "PATH=/usr/local/sbin:/usr/local/bin:/usr/bin" \
167-
-D "$BUILDDIRECTORY/$container" "${@:2}"
193+
--as-pid2 \
194+
--register=no \
195+
${EPHEMERAL:+--ephemeral} \
196+
--pipe \
197+
-E "PATH=/usr/local/sbin:/usr/local/bin:/usr/bin" \
198+
-D "$BUILDDIRECTORY/$container" "${@:2}"
199+
if ((EPHEMERAL)); then
200+
lock_close 8 "$BUILDDIRECTORY/$container.lock"
201+
fi
168202
}
169203

170204
# Desc: Removes the root container
@@ -221,11 +255,13 @@ __END__
221255
function init_chroot(){
222256
mkdir -p "$BUILDDIRECTORY"
223257

224-
# Prepare root chroot
258+
# Always lock first. Otherwise we might end up...
259+
# - doing the same thing again - if using test/lock/mkdir
260+
# - with empty directory in the follow-up lock - if using test/mkdir/lock
261+
lock 9 "$BUILDDIRECTORY"/root.lock
225262
if [ ! -d "$BUILDDIRECTORY"/root ]; then
226263
get_bootstrap_img
227264

228-
lock 9 "$BUILDDIRECTORY"/root.lock
229265
msg "Preparing chroot"
230266
trap '{ cleanup_root_volume; exit 1; }' ERR
231267
trap '{ cleanup_root_volume; trap - INT; kill -INT $$; }' INT
@@ -241,23 +277,23 @@ function init_chroot(){
241277
msg2 "Setting up keyring, this might take a while..."
242278
exec_nspawn root pacman-key --init &> /dev/null
243279
exec_nspawn root pacman-key --populate archlinux &> /dev/null
244-
exec_nspawn root pacman -Sy
245-
exec_nspawn root pacman -Syu --noconfirm
246280
touch "$BUILDDIRECTORY/root/.repro-2"
247-
lock_close 9
248281
else
249282
if [ ! -f "$BUILDDIRECTORY/root/.repro-2" ]; then
250283
error "Please delete $BUILDDIRECTORY and initialize the chroots again"
251284
exit 1
252285
fi
253-
if lock 9 "$BUILDDIRECTORY"/root.lock; then
254-
msg "Reusing existing container"
255-
printf 'Server = %s\n' "$HOSTMIRROR" > "$BUILDDIRECTORY"/root/etc/pacman.d/mirrorlist
256-
exec_nspawn root pacman -Syu --noconfirm
257-
lock_close 9
258-
else
259-
msg "Couldn't acquire lock on root chroot, didn't update."
260-
fi
286+
msg "Reusing existing container"
287+
fi
288+
lock_close 9
289+
290+
if nlock 9 "$BUILDDIRECTORY"/root.lock; then
291+
msg "Updating container"
292+
printf 'Server = %s\n' "$HOSTMIRROR" > "$BUILDDIRECTORY"/root/etc/pacman.d/mirrorlist
293+
exec_nspawn root pacman -Syu --noconfirm
294+
lock_close 9
295+
else
296+
msg "Couldn't acquire container lock, didn't update."
261297
fi
262298
trap - ERR INT
263299
}
@@ -306,6 +342,10 @@ function cmd_check(){
306342
# Father I have sinned
307343
if ((!pkgbuild_file)); then
308344
msg2 "Fetching PKGBUILD from ASP..."
345+
346+
# Lock the cachedir as we might have a race condition with pacman -S and the cachedir
347+
lock 9 "${cachedir}.lock"
348+
309349
EPHEMERAL=1 exec_nspawn root --bind="${build_root_dir}/startdir:/startdir" --bind="$(readlink -e ${cachedir}):/var/cache/pacman/pkg" \
310350
bash <<-__END__
311351
shopt -s globstar
@@ -323,6 +363,7 @@ for rev in \$(git rev-list --all -- repos/); do
323363
done
324364
exit 1
325365
__END__
366+
lock_close 9 "${cachedir}.lock"
326367
elif [[ -r "PKGBUILD" ]]; then
327368
if [[ "$(sha256sum PKGBUILD | awk '{print $1}')" != "$pkgbuild_sha256sum" ]]; then
328369
error "PKGBUILD doesn't match the checksum"
@@ -343,10 +384,13 @@ __END__
343384

344385
mkdir -p "$KEYRINGCACHE"
345386

387+
# Always lock first. Otherwise we might end up...
388+
# - doing the same thing again - if using test/lock/mkdir
389+
# - with empty directory in the follow-up lock - if using test/mkdir/lock
390+
lock 9 "$KEYRINGCACHE/$keyring_package.lock"
346391
if [ ! -d "$KEYRINGCACHE/$keyring_package" ]; then
347392
msg2 "Setting up $keyring_package in keyring cache, this might take a while..."
348393

349-
nlock 9 "$KEYRINGCACHE/$keyring_package.lock"
350394
# shellcheck disable=SC2086
351395
keyring=$(printf -- '%s\n' ${packages[*]} | grep -E "archlinux-keyring")
352396
EPHEMERAL=1 exec_nspawn root --bind="${build_root_dir}:/mnt" --bind="$(readlink -e "${cachedir}"):/cache" bash -c \
@@ -386,12 +430,14 @@ echo "faked-system-time ${keyring_build_date}" >> /mnt/gpg.conf
386430
pacman-key --init
387431
pacman-key --populate archlinux
388432
__END__
389-
lock_close 9 "$KEYRINGCACHE/$keyring_package.lock"
390433
trap - ERR INT
391434
else
392435
msg2 "Found $keyring_package in keyring cache"
393436
fi
437+
lock_close 9 "$KEYRINGCACHE/$keyring_package.lock"
394438

439+
# Acquire shared locks for keyring as it could still be initialized at this point
440+
slock 9 "$KEYRINGCACHE/$keyring_package.lock"
395441
msg "Installing packages"
396442
# shellcheck disable=SC2086
397443
EPHEMERAL=1 exec_nspawn root \
@@ -404,6 +450,7 @@ cp --target-directory=/etc/pacman.d/ --recursive /gnupg
404450
echo "faked-system-time ${SOURCE_DATE_EPOCH}" >> /etc/pacman.d/gnupg/gpg.conf
405451
pacstrap -G -U /mnt --needed "\$@"
406452
__END__
453+
lock_close 9 "$KEYRINGCACHE/$keyring_package.lock"
407454

408455
# Setup environment
409456
{

0 commit comments

Comments
 (0)