diff options
Diffstat (limited to 'extra/openrc/modloop.initd')
-rwxr-xr-x | extra/openrc/modloop.initd | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/extra/openrc/modloop.initd b/extra/openrc/modloop.initd new file mode 100755 index 0000000..fb7006c --- /dev/null +++ b/extra/openrc/modloop.initd @@ -0,0 +1,153 @@ +#!/sbin/openrc-run + +# script that will mount image with modules + +depend() { + after dev-mount + before checkfs fsck hwdrivers modules hwclock dev sysfs + keyword -vserver -lxc +} + +# read kernel options +init_KOPT() { + for opt in $(cat /proc/cmdline 2>/dev/null); do + case "$opt" in + modloop=*|modloop_verify=*) + eval "KOPT_${opt%%=*}='${opt#*=}'" ;; + esac + done +} + +mountdirs() { + awk '$2 !~ /^\/(sys|proc|dev|run)/ && $2 != "/" {print $2}' /proc/mounts +} + +find_modloop() { + local dir="$1" + local kver=$(uname -r) + local oifs="$IFS" + IFS=$'\n' + set -- $(blkid "$dir"/boot/* "$dir"/*) + IFS="$oifs" + for line; do + img=${line%%:*} + verify_modloop "$img" || eerror "Failed to verify signature of $img!" + mount "$img" -o loop,ro /.modloop || continue + if [ -d /.modloop/modules/$kver ]; then + return 0 + fi + umount /.modloop + done + return 1 +} + +verify_modloop() { + local modloop=$1 key= + if ! yesno "${KOPT_modloop_verify:=yes}"; then + return 0 + fi + for key in /etc/apk/keys/*.pub; do + local sig=/var/cache/misc/${modloop##*/}.SIGN.RSA.${key##*/} + if [ -f "$sig" ]; then + if ! command -v openssl > /dev/null; then + ewarn "Missing openssl. Modloop verification disabled!" + return 0 + fi + einfo "Verifying modloop" + openssl dgst -sha1 -verify "$key" -signature "$sig" "$modloop" \ + >/dev/null 2>&1 || return 1 + fi + done +} + +find_backing_file() { + local dir="$1" + local dev=$(df -P "$dir" | tail -1 | awk '{print $1}') + cat /sys/block/${dev#/dev/}/loop/backing_file 2>/dev/null +} + +start() { + local modloop= mount_opts= modloop_dldir="/lib" + init_KOPT + + case "$KOPT_modloop" in + none) return 0;; + http://*|https://*|ftp://*) + modloop=$modloop_dldir/${KOPT_modloop##*/} + if [ ! -f "$modloop" ]; then + mkdir -p "$modloop_dldir" + wget -P "$modloop_dldir" "$KOPT_modloop" || eend 1 + fi + ;; + *) + for dir in $(mountdirs); do + if [ -f "$dir"/$KOPT_modloop ]; then + modloop="$dir/${KOPT_modloop##/}" + alpine_mnt="$dir" + break + fi + done + ;; + esac + + ebegin "Mounting modloop $modloop" + mkdir -p /.modloop + if [ -n "$modloop" ]; then + verify_modloop "$modloop" || eerror "Failed to verify signature of $img!" + mount -o loop,ro $modloop /.modloop + eend $? || return 1 + else + for dir in $(mountdirs); do + if find_modloop "$dir"; then + alpine_mnt="$dir" + break + fi + done + if [ -d /.modloop/modules/$(uname -r) ]; then + eend 0 + else + eend 1 || return 1 + fi + fi + + #use overlayfs if available and configured + if grep -q -w "overlay$" /proc/filesystems && [ ! -z ${unionfs_size+x} ]; then + ewarn "Use of unionfs_size is deprecated use overlay_size instead" + overlay_size="$unionfs_size" + fi + if grep -q -w "overlay$" /proc/filesystems && [ -n "$overlay_size" ]; then + ebegin "OverlayFS detected, mounting modloop rw" + [ "$overlay_size" != 0 ] && mount_ops="-o size=$overlay_size" + mkdir -p /.modoverlayfs /lib/modules + mount -t tmpfs $mount_ops tmpfs /.modoverlayfs + mkdir -p /.modoverlayfs/modules /.modoverlayfs/work + mount -t overlay -o upperdir=/.modoverlayfs/modules,lowerdir=/lib/modules:/.modloop/modules,workdir=/.modoverlayfs/work overlay /lib/modules + depmod -A + eend $? || return 1 + else + rm -rf /lib/modules && ln -sf /.modloop/modules /lib/ + fi + + # copy firmware if there are any + if [ -d $alpine_mnt/firmware ]; then + ebegin "Copying firmware from $alpine_mnt/firmware" + cp -R -a $alpine_mnt/firmware /lib/ + eend $? + elif [ -d /lib/modules/firmware ]; then + rmdir /lib/firmware 2>/dev/null \ + && ln -s /lib/modules/firmware /lib/ + fi + return 0 +} + +stop() { + local ret=0 + local mnt; for mnt in /lib/modules /.modoverlayfs /.modloop; do + if mountinfo --quiet "$mnt"; then + ebegin "Unmounting $mnt" + umount -d "$mnt" || ret=1 + fi + done + eend $ret || return 1 +} + |