Prototype FreeBSD store management
This commit is contained in:
234
tests/store/run-freebsd-store-prototype.sh
Executable file
234
tests/store/run-freebsd-store-prototype.sh
Executable file
@@ -0,0 +1,234 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
store_root=${STORE_ROOT:-/frx/store}
|
||||
state_root=${STATE_ROOT:-/frx/var}
|
||||
sysconf_root=${SYSCONF_ROOT:-/frx/etc}
|
||||
fruix_state_dir=$state_root/fruix
|
||||
fruix_gcroots_dir=$fruix_state_dir/gcroots
|
||||
store_group=${STORE_GROUP:-fruixbuild}
|
||||
workdir=${WORKDIR:-$(mktemp -d /tmp/fruix-store-prototype.XXXXXX)}
|
||||
cleanup_workdir=1
|
||||
metadata_file=$workdir/freebsd-store-prototype-metadata.txt
|
||||
access_read_out=$workdir/access-read.out
|
||||
access_write_err=$workdir/access-write.err
|
||||
first_gc_listing=$workdir/first-gc-listing.txt
|
||||
second_gc_listing=$workdir/second-gc-listing.txt
|
||||
store_root_stat=$workdir/store-root.stat
|
||||
gcroots_stat=$workdir/gcroots.stat
|
||||
|
||||
if [ -n "${WORKDIR:-}" ]; then
|
||||
cleanup_workdir=0
|
||||
fi
|
||||
if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then
|
||||
cleanup_workdir=0
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
set +e
|
||||
if [ "$cleanup_workdir" -eq 1 ]; then
|
||||
rm -rf "$workdir"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
ensure_store_group() {
|
||||
if ! pw groupshow "$store_group" >/dev/null 2>&1; then
|
||||
if ! sudo pw groupadd "$store_group" -g 35000 >/dev/null 2>&1; then
|
||||
sudo pw groupadd "$store_group" >/dev/null
|
||||
fi
|
||||
group_created=yes
|
||||
else
|
||||
group_created=no
|
||||
fi
|
||||
group_gid=$(pw groupshow "$store_group" | awk -F: '{print $3}')
|
||||
}
|
||||
|
||||
clean_demo_items() {
|
||||
sudo find "$store_root" -mindepth 2 -maxdepth 2 -name .fruix-demo -print 2>/dev/null |
|
||||
while IFS= read -r marker; do
|
||||
[ -n "$marker" ] || continue
|
||||
sudo rm -rf "$(dirname "$marker")"
|
||||
done
|
||||
sudo rm -f "$fruix_gcroots_dir/demo-root"
|
||||
}
|
||||
|
||||
install_store_item() {
|
||||
item_name=$1
|
||||
stage_dir=$2
|
||||
item_hash=$3
|
||||
destination=$store_root/${item_hash}-${item_name}
|
||||
|
||||
sudo rm -rf "$destination"
|
||||
sudo mkdir -p "$destination"
|
||||
sudo cp -a "$stage_dir/." "$destination/"
|
||||
sudo find "$destination" -type d -exec chmod 0555 {} +
|
||||
sudo find "$destination" -type f -exec chmod 0444 {} +
|
||||
if [ -d "$destination/bin" ]; then
|
||||
sudo find "$destination/bin" -type f -exec chmod 0555 {} +
|
||||
fi
|
||||
printf '%s\n' "$destination"
|
||||
}
|
||||
|
||||
mark_reachable() {
|
||||
item=$1
|
||||
[ -n "$item" ] || return 0
|
||||
[ -d "$item" ] || return 0
|
||||
if grep -Fxq "$item" "$reachable_file" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
printf '%s\n' "$item" >> "$reachable_file"
|
||||
if [ -f "$item/.references" ]; then
|
||||
while IFS= read -r ref; do
|
||||
[ -n "$ref" ] || continue
|
||||
mark_reachable "$ref"
|
||||
done < "$item/.references"
|
||||
fi
|
||||
}
|
||||
|
||||
run_gc() {
|
||||
reachable_file=$1
|
||||
: > "$reachable_file"
|
||||
if [ -d "$fruix_gcroots_dir" ]; then
|
||||
for root in "$fruix_gcroots_dir"/*; do
|
||||
[ -L "$root" ] || continue
|
||||
mark_reachable "$(readlink -f "$root")"
|
||||
done
|
||||
fi
|
||||
|
||||
sudo find "$store_root" -mindepth 2 -maxdepth 2 -name .fruix-demo -print |
|
||||
while IFS= read -r marker; do
|
||||
item=$(dirname "$marker")
|
||||
if ! grep -Fxq "$item" "$reachable_file" 2>/dev/null; then
|
||||
sudo rm -rf "$item"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
mkdir -p "$workdir/stage"
|
||||
ensure_store_group
|
||||
|
||||
sudo install -d -m 0755 -o root -g wheel /frx
|
||||
sudo install -d -m 1775 -o root -g "$store_group" "$store_root"
|
||||
sudo install -d -m 0755 -o root -g wheel "$state_root" "$sysconf_root" "$fruix_state_dir" "$fruix_gcroots_dir"
|
||||
|
||||
clean_demo_items
|
||||
sudo stat -f '%Su %Sg %OLp %Sp' "$store_root" > "$store_root_stat"
|
||||
sudo stat -f '%Su %Sg %OLp %Sp' "$fruix_gcroots_dir" > "$gcroots_stat"
|
||||
|
||||
data_stage=$workdir/stage/greeting-data
|
||||
app_stage=$workdir/stage/hello-app
|
||||
orphan_stage=$workdir/stage/orphan-data
|
||||
mkdir -p "$data_stage/share" "$app_stage/bin" "$orphan_stage/share"
|
||||
|
||||
printf 'hello-from-frx-store\n' > "$data_stage/share/greeting.txt"
|
||||
printf 'demo-item\n' > "$data_stage/.fruix-demo"
|
||||
: > "$data_stage/.references"
|
||||
data_manifest=$(printf 'name=demo-greeting-data\nfile=share/greeting.txt\ncontent=%s\n' "hello-from-frx-store")
|
||||
data_hash=$(printf '%s' "$data_manifest" | sha256 -q)
|
||||
data_path=$(install_store_item demo-greeting-data "$data_stage" "$data_hash")
|
||||
|
||||
cat > "$app_stage/bin/demo-hello" <<EOF
|
||||
#!/bin/sh
|
||||
exec /bin/cat "$data_path/share/greeting.txt"
|
||||
EOF
|
||||
printf '%s\n' "$data_path" > "$app_stage/.references"
|
||||
printf 'demo-item\n' > "$app_stage/.fruix-demo"
|
||||
app_manifest=$(printf 'name=demo-hello-app\nfile=bin/demo-hello\nref=%s\n' "$data_path")
|
||||
app_hash=$(printf '%s' "$app_manifest" | sha256 -q)
|
||||
app_path=$(install_store_item demo-hello-app "$app_stage" "$app_hash")
|
||||
|
||||
printf 'this-should-be-collected\n' > "$orphan_stage/share/orphan.txt"
|
||||
: > "$orphan_stage/.references"
|
||||
printf 'demo-item\n' > "$orphan_stage/.fruix-demo"
|
||||
orphan_manifest=$(printf 'name=demo-orphan-data\nfile=share/orphan.txt\ncontent=%s\n' "this-should-be-collected")
|
||||
orphan_hash=$(printf '%s' "$orphan_manifest" | sha256 -q)
|
||||
orphan_path=$(install_store_item demo-orphan-data "$orphan_stage" "$orphan_hash")
|
||||
|
||||
sudo ln -sfn "$app_path" "$fruix_gcroots_dir/demo-root"
|
||||
|
||||
sudo -u nobody /bin/sh -eu -c "
|
||||
cat '$data_path/share/greeting.txt'
|
||||
'$app_path/bin/demo-hello'
|
||||
" > "$access_read_out"
|
||||
|
||||
set +e
|
||||
sudo -u nobody /bin/sh -eu -c "touch '$store_root/should-not-write'" >/dev/null 2> "$access_write_err"
|
||||
write_rc=$?
|
||||
set -e
|
||||
if [ "$write_rc" -eq 0 ]; then
|
||||
echo "unexpected unprivileged store write succeeded" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
reachable_after_first_gc=$workdir/reachable-first.txt
|
||||
run_gc "$reachable_after_first_gc"
|
||||
find "$store_root" -maxdepth 1 -mindepth 1 | sort > "$first_gc_listing"
|
||||
|
||||
if [ -d "$orphan_path" ]; then
|
||||
echo "orphan store item survived rooted GC unexpectedly" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -d "$app_path" ] || [ ! -d "$data_path" ]; then
|
||||
echo "reachable store items missing after rooted GC" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo rm -f "$fruix_gcroots_dir/demo-root"
|
||||
reachable_after_second_gc=$workdir/reachable-second.txt
|
||||
run_gc "$reachable_after_second_gc"
|
||||
find "$store_root" -maxdepth 1 -mindepth 1 | sort > "$second_gc_listing"
|
||||
|
||||
if [ -d "$app_path" ] || [ -d "$data_path" ]; then
|
||||
echo "unrooted store items survived GC unexpectedly" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat > "$metadata_file" <<EOF
|
||||
store_root=$store_root
|
||||
state_root=$state_root
|
||||
sysconf_root=$sysconf_root
|
||||
fruix_state_dir=$fruix_state_dir
|
||||
fruix_gcroots_dir=$fruix_gcroots_dir
|
||||
store_group=$store_group
|
||||
store_group_gid=$group_gid
|
||||
group_created=$group_created
|
||||
store_root_stat=$(cat "$store_root_stat")
|
||||
gcroots_stat=$(cat "$gcroots_stat")
|
||||
data_hash=$data_hash
|
||||
app_hash=$app_hash
|
||||
orphan_hash=$orphan_hash
|
||||
data_path=$data_path
|
||||
app_path=$app_path
|
||||
orphan_path=$orphan_path
|
||||
nobody_read_output=$(tr '\n' '|' < "$access_read_out")
|
||||
unprivileged_write_rc=$write_rc
|
||||
unprivileged_write_err=$(tr '\n' '|' < "$access_write_err")
|
||||
first_gc_listing_file=$first_gc_listing
|
||||
second_gc_listing_file=$second_gc_listing
|
||||
first_gc_listing_begin
|
||||
$(cat "$first_gc_listing")
|
||||
first_gc_listing_end
|
||||
second_gc_listing_begin
|
||||
$(cat "$second_gc_listing")
|
||||
second_gc_listing_end
|
||||
EOF
|
||||
|
||||
if [ -n "${METADATA_OUT:-}" ]; then
|
||||
mkdir -p "$(dirname "$METADATA_OUT")"
|
||||
cp "$metadata_file" "$METADATA_OUT"
|
||||
fi
|
||||
|
||||
printf 'PASS freebsd-store-prototype\n'
|
||||
printf 'Metadata file: %s\n' "$metadata_file"
|
||||
if [ -n "${METADATA_OUT:-}" ]; then
|
||||
printf 'Copied metadata to: %s\n' "$METADATA_OUT"
|
||||
fi
|
||||
printf '%s\n' '--- nobody read output ---'
|
||||
cat "$access_read_out"
|
||||
printf '%s\n' '--- first GC listing ---'
|
||||
cat "$first_gc_listing"
|
||||
printf '%s\n' '--- second GC listing ---'
|
||||
cat "$second_gc_listing"
|
||||
printf '%s\n' '--- metadata ---'
|
||||
cat "$metadata_file"
|
||||
Reference in New Issue
Block a user