Skip to content

Commit

Permalink
handle-writable-paths: extract the writable-path handling
Browse files Browse the repository at this point in the history
This PR moves the code that handle the writable-path for a core
system from the initramfs to the core20 snap. This has the benefit
that we don't have to change the initramfs if this code needs to
change. The initramfs will just call it from the core20 snap.
  • Loading branch information
mvo5 committed Nov 19, 2019
1 parent a7ec416 commit 2c316b6
Showing 1 changed file with 182 additions and 0 deletions.
182 changes: 182 additions & 0 deletions static/usr/lib/core/handle-writable-paths
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
#!/bin/sh
#
# Extracted code from:
# https://github.com/snapcore/core-build/blob/master/initramfs/scripts/ubuntu-core-rootfs
# to keep in the core20+ snap in sync with the writable-path file.
#
# Having it here means we don't need to rebuld all kernels if this file
# changes.

set -e

panic()
{
echo "PANIC: $*"
exit 1
}

# XXX: we really want the "synced" feature to go away
sync_dirs()
{
base="$1"
source="$2"
target="$3"

OLD_PWD="$PWD"
cd "$base"

for file in "$source"/*
do
# Skip empty directories
[ ! -e "$base/$file" -a ! -L "$base/$file" ] && continue

# If the target already exists as a file or link, there's nothing we can do
[ -e "$target/$file" -o -L "$target/$file" ] && [ ! -d "$target/$file" ] && continue

# If the target doesn't exist, just copy it over
if [ ! -e "$target/$file" -a ! -L "$target/$file" ]; then
cp -Ra "$base/$file" "$target/$file"
continue
fi

# That leaves us with directories and a recursive call
[ -d "$file" ] && sync_dirs "$base" "$file" "$target"
done

cd "$OLD_PWD"
}

# Process the list of bind-mounts (but don't mount them - systemd will handle that)
# File format is documented in writable-paths(5).
handle_writable_paths()
{
writable_paths="$1"
fstab="$2"

[ -n "$writable_paths" ] || panic "need writeable paths"
[ -e "$writable_paths" ] || panic "writeable paths does not exist"
[ -n "$fstab" ] || panic "need fstab"

cat "$writable_paths" | while read line; do
# tokenise
set -- $line

# skip invalid/commented entries
([ -z "$1" ] || \
[ -z "$2" ] || \
[ -z "$3" ] || \
[ -z "$4" ] || \
[ -z "$5" ]) && continue

# ignore anything that isn't an absolute path (including comments)
case "$1" in
/*) ;;
*) continue ;;
esac

# skip invalid mount points
dstpath="${rootmnt}$1"
[ ! -e "$dstpath" ] && continue

if [ "$3" = "temporary" ]; then
# Temporary entries are simple, just mount a tmpfs
echo "tmpfs $1 tmpfs $5 0 0" >> "$fstab"
elif [ "$3" = "persistent" ] || \
[ "$3" = "synced" ]; then
# Figure out the source path
if [ "$2" = "auto" ]; then
srcpath="${rootmnt}/writable/system-data${1}"
path="/writable/system-data${1}"
else
srcpath="${rootmnt}/writable/$2"
path="/writable/$2"
fi

if [ ! -e "$srcpath" ]; then
# Process new persistent or synced paths
dstown=$(stat -c "%u:%g" "$dstpath")
dstmode=$(stat -c "%a" "$dstpath")
mkdir -p ${srcpath%/*}
if [ ! -d "$dstpath" ]; then
# Deal with redirected files
if [ "$4" = "transition" ]; then
cp -a "$dstpath" "$srcpath"
else
touch "$srcpath"
chown "$dstown" "$srcpath"
chmod "$dstmode" "$srcpath"
fi
else
# Deal with redirected directories
if [ "$4" = "transition" ] || [ "$3" = "synced" ]; then
cp -aR "$dstpath" "$srcpath"
else
mkdir "$srcpath"
chown "$dstown" "$srcpath"
chmod "$dstmode" "$srcpath"
fi
fi
elif [ "$3" = "synced" ]; then
# Process existing synced paths
sync_dirs "$dstpath" . "$srcpath"
fi

# mount all /etc dirs right now, not later when fstab is
# processed, as it will cause races.
case $1 in
/etc*)
[ -e "${rootmnt}/writable/system-data/$1" ] || mkdir -p "${rootmnt}/writable/system-data/$1"
mount -o bind "${rootmnt}/writable/system-data/$1" "${rootmnt}/$1"
;;
*)
# Write the fstab entry
if [ "$5" = "none" ]; then
echo "$path $1 none bind 0 0" >> "$fstab"
else
echo "$path $1 none bind,$5 0 0" >> "$fstab"
fi
;;
esac
else
continue
fi
done
}

main()
{
writable_paths="${1:-${rootmnt}/etc/system-image/writable-paths}"
fstab="${2:-${rootmnt}/etc/fstab}"

# Add writable overlays
if [ -e "$writable_paths" ]; then
mkdir -p "${rootmnt}/run"
mkdir -p "$(dirname "$fstab")"

touch "${rootmnt}/run/image.fstab"
mount -o bind "${rootmnt}/run/image.fstab" "$fstab" || panic "Cannot bind mount fstab"
echo "# Auto-generated by $0" >> "$fstab"
echo "# DO NOT EDIT THIS FILE BY HAND - YOUR CHANGES WILL BE OVERWRITTEN" >> "$fstab"
echo "# (See writable-paths(5) for details)" >> "$fstab"
echo "/dev/root / rootfs defaults,ro 0 0" >> "$fstab"
# FIXME: ideally we would mount /writable RO here and
# let systemd do a "remount,rw" for us. unfortunately
# this is not supported by systemd so we need to do
# the RW mount and fsck dance etc here :/
echo "LABEL=writable /writable auto defaults 0 0" >> "$fstab"
handle_writable_paths "$writable_paths" "$fstab"
fi

# IMPORTANT: ensure we synced everything back to disk
sync
}

rootmnt="$1"
if [ -z "$rootmnt" ]; then
echo "need rootmnt as the first argument"
exit 1
fi
# "$2" is the (optional) writable-paths file
# "$3" is the (optional) /etc/fstab file
main "$2" "$3"

0 comments on commit 2c316b6

Please sign in to comment.