From 1e7c3a58b9a18c3901efc52be0d958f434e3e237 Mon Sep 17 00:00:00 2001 From: Ricardo Pardini Date: Sat, 1 Jun 2024 08:28:27 +0200 Subject: [PATCH 1/3] hook-mdev: add `persistent-storage` script from upstream Alpine (ipsis-literis) - original persistent-storage from upstream Alpine: - source https://gitlab.alpinelinux.org/alpine/mdev-conf/-/blob/master/persistent-storage?ref_type=heads - revision a21d1053dd5ca37538b0435d66c58a30cb273658 - this is being added as reference for future rebases; it will be shellfmt'ed and modified in later commits Signed-off-by: Ricardo Pardini --- images/hook-mdev/persistent-storage | 148 ++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 images/hook-mdev/persistent-storage diff --git a/images/hook-mdev/persistent-storage b/images/hook-mdev/persistent-storage new file mode 100644 index 00000000..2ccd2c24 --- /dev/null +++ b/images/hook-mdev/persistent-storage @@ -0,0 +1,148 @@ +#!/bin/sh + +symlink_action() { + case "$ACTION" in + add) ln -sf "$1" "$2";; + remove) rm -f "$2";; + esac +} + +sanitise_file() { + sed -E -e 's/^\s+//' -e 's/\s+$//' -e 's/ /_/g' "$@" 2>/dev/null +} + +sanitise_string() { + echo "$@" | sanitise_file +} + +blkid_encode_string() { + # Rewrites string similar to libblk's blkid_encode_string + # function which is used by udev/eudev. + echo "$@" | sed -e 's| |\\x20|g' +} + +: ${SYSFS:=/sys} + +# cdrom symlink +case "$MDEV" in + sr*|xvd*) + caps="$(cat $SYSFS/block/$MDEV/capability 2>/dev/null)" + if [ $(( 0x${caps:-0} & 8 )) -gt 0 ] || [ "$(cat $SYSFS/block/$MDEV/removable 2>/dev/null)" = "1" ]; then + symlink_action $MDEV cdrom + fi +esac + + +# /dev/block symlinks +mkdir -p block +if [ -f "$SYSFS/class/block/$MDEV/dev" ]; then + maj_min=$(sanitise_file "$SYSFS/class/block/$MDEV/dev") + symlink_action ../$MDEV block/${maj_min} +fi + + +# by-id symlinks +mkdir -p disk/by-id + +if [ -f "$SYSFS/class/block/$MDEV/partition" ]; then + # This is a partition of a device, find out its parent device + _parent_dev="$(basename $(${SBINDIR:-/usr/bin}/readlink -f "$SYSFS/class/block/$MDEV/.."))" + + partition=$(cat $SYSFS/class/block/$MDEV/partition 2>/dev/null) + case "$partition" in + [0-9]*) partsuffix="-part$partition";; + esac + # Get name, model, serial, wwid from parent device of the partition + _check_dev="$_parent_dev" +else + _check_dev="$MDEV" +fi + +model=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/model") +name=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/name") +serial=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/serial") +# Special case where block devices have serials attached to the block itself, like virtio-blk +: ${serial:=$(sanitise_file "$SYSFS/class/block/$_check_dev/serial")} +wwid=$(sanitise_file "$SYSFS/class/block/$_check_dev/wwid") +: ${wwid:=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/wwid")} + +# Sets variables LABEL, PARTLABEL, PARTUUID, TYPE, UUID depending on +# blkid output (busybox blkid will not provide PARTLABEL or PARTUUID) +eval $(blkid /dev/$MDEV | cut -d: -f2-) + +if [ -n "$wwid" ]; then + case "$MDEV" in + nvme*) symlink_action ../../$MDEV disk/by-id/nvme-${wwid}${partsuffix};; + esac + case "$wwid" in + naa.*) symlink_action ../../$MDEV disk/by-id/wwn-0x${wwid#naa.}${partsuffix};; + esac +fi + +if [ -n "$serial" ]; then + if [ -n "$model" ]; then + case "$MDEV" in + nvme*) symlink_action ../../$MDEV disk/by-id/nvme-${model}_${serial}${partsuffix};; + sd*) symlink_action ../../$MDEV disk/by-id/ata-${model}_${serial}${partsuffix};; + esac + fi + if [ -n "$name" ]; then + case "$MDEV" in + mmcblk*) symlink_action ../../$MDEV disk/by-id/mmc-${name}_${serial}${partsuffix};; + esac + fi + + # virtio-blk + case "$MDEV" in + vd*) symlink_action ../../$MDEV disk/by-id/virtio-${serial}${partsuffix};; + esac +fi + +# by-label, by-partlabel, by-partuuid, by-uuid symlinks +if [ -n "$LABEL" ]; then + mkdir -p disk/by-label + symlink_action ../../$MDEV disk/by-label/"$(blkid_encode_string "$LABEL")" +fi +if [ -n "$PARTLABEL" ]; then + mkdir -p disk/by-partlabel + symlink_action ../../$MDEV disk/by-partlabel/"$(blkid_encode_string "$PARTLABEL")" +fi +if [ -n "$PARTUUID" ]; then + mkdir -p disk/by-partuuid + symlink_action ../../$MDEV disk/by-partuuid/"$PARTUUID" +fi +if [ -n "$UUID" ]; then + mkdir -p disk/by-uuid + symlink_action ../../$MDEV disk/by-uuid/"$UUID" +fi + +# nvme EBS storage symlinks +if [ "${MDEV#nvme}" != "$MDEV" ] && [ "$model" = "Amazon_Elastic_Block_Store" ] && command -v nvme >/dev/null; then + n=30 + while [ $n -gt 0 ]; do + ebs_alias=$(nvme id-ctrl -b /dev/$_check_dev \ + | dd bs=32 skip=96 count=1 2>/dev/null \ + | sed -nre '/^(\/dev\/)?(s|xv)d[a-z]{1,2} /p' \ + | tr -d ' ') + if [ -n "$ebs_alias" ]; then + symlink_action "$MDEV" ${ebs_alias#/dev/}$partition + break + fi + n=$((n - 1)) + sleep 0.1 + done +fi + +# backwards compatibility with /dev/usbdisk for /dev/sd* +if [ "${MDEV#sd}" != "$MDEV" ]; then + sysdev=$(readlink $SYSFS/class/block/$MDEV) + case "$sysdev" in + *usb[0-9]*) + # require vfat for devices without partition + if ! [ -e $SYSFS/block/$MDEV ] || [ TYPE="vfat" ]; then + symlink_action $MDEV usbdisk + fi + ;; + esac +fi + From a29d4875462829aec910b55bec2a35010dbea52a Mon Sep 17 00:00:00 2001 From: Ricardo Pardini Date: Sat, 1 Jun 2024 09:47:01 +0200 Subject: [PATCH 2/3] hook-mdev: rename to `persistent-storage.sh` and shellfmt it (no real changes) - simple rename & shellfmt; separate commit for easy future rebasing Signed-off-by: Ricardo Pardini --- ...rsistent-storage => persistent-storage.sh} | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) rename images/hook-mdev/{persistent-storage => persistent-storage.sh} (82%) diff --git a/images/hook-mdev/persistent-storage b/images/hook-mdev/persistent-storage.sh similarity index 82% rename from images/hook-mdev/persistent-storage rename to images/hook-mdev/persistent-storage.sh index 2ccd2c24..ea4a794a 100644 --- a/images/hook-mdev/persistent-storage +++ b/images/hook-mdev/persistent-storage.sh @@ -2,13 +2,13 @@ symlink_action() { case "$ACTION" in - add) ln -sf "$1" "$2";; - remove) rm -f "$2";; + add) ln -sf "$1" "$2" ;; + remove) rm -f "$2" ;; esac } sanitise_file() { - sed -E -e 's/^\s+//' -e 's/\s+$//' -e 's/ /_/g' "$@" 2>/dev/null + sed -E -e 's/^\s+//' -e 's/\s+$//' -e 's/ /_/g' "$@" 2> /dev/null } sanitise_string() { @@ -25,14 +25,14 @@ blkid_encode_string() { # cdrom symlink case "$MDEV" in - sr*|xvd*) - caps="$(cat $SYSFS/block/$MDEV/capability 2>/dev/null)" - if [ $(( 0x${caps:-0} & 8 )) -gt 0 ] || [ "$(cat $SYSFS/block/$MDEV/removable 2>/dev/null)" = "1" ]; then + sr* | xvd*) + caps="$(cat $SYSFS/block/$MDEV/capability 2> /dev/null)" + if [ $((0x${caps:-0} & 8)) -gt 0 ] || [ "$(cat $SYSFS/block/$MDEV/removable 2> /dev/null)" = "1" ]; then symlink_action $MDEV cdrom fi + ;; esac - # /dev/block symlinks mkdir -p block if [ -f "$SYSFS/class/block/$MDEV/dev" ]; then @@ -40,7 +40,6 @@ if [ -f "$SYSFS/class/block/$MDEV/dev" ]; then symlink_action ../$MDEV block/${maj_min} fi - # by-id symlinks mkdir -p disk/by-id @@ -48,9 +47,9 @@ if [ -f "$SYSFS/class/block/$MDEV/partition" ]; then # This is a partition of a device, find out its parent device _parent_dev="$(basename $(${SBINDIR:-/usr/bin}/readlink -f "$SYSFS/class/block/$MDEV/.."))" - partition=$(cat $SYSFS/class/block/$MDEV/partition 2>/dev/null) + partition=$(cat $SYSFS/class/block/$MDEV/partition 2> /dev/null) case "$partition" in - [0-9]*) partsuffix="-part$partition";; + [0-9]*) partsuffix="-part$partition" ;; esac # Get name, model, serial, wwid from parent device of the partition _check_dev="$_parent_dev" @@ -72,29 +71,29 @@ eval $(blkid /dev/$MDEV | cut -d: -f2-) if [ -n "$wwid" ]; then case "$MDEV" in - nvme*) symlink_action ../../$MDEV disk/by-id/nvme-${wwid}${partsuffix};; + nvme*) symlink_action ../../$MDEV disk/by-id/nvme-${wwid}${partsuffix} ;; esac case "$wwid" in - naa.*) symlink_action ../../$MDEV disk/by-id/wwn-0x${wwid#naa.}${partsuffix};; + naa.*) symlink_action ../../$MDEV disk/by-id/wwn-0x${wwid#naa.}${partsuffix} ;; esac fi if [ -n "$serial" ]; then if [ -n "$model" ]; then case "$MDEV" in - nvme*) symlink_action ../../$MDEV disk/by-id/nvme-${model}_${serial}${partsuffix};; - sd*) symlink_action ../../$MDEV disk/by-id/ata-${model}_${serial}${partsuffix};; + nvme*) symlink_action ../../$MDEV disk/by-id/nvme-${model}_${serial}${partsuffix} ;; + sd*) symlink_action ../../$MDEV disk/by-id/ata-${model}_${serial}${partsuffix} ;; esac fi if [ -n "$name" ]; then case "$MDEV" in - mmcblk*) symlink_action ../../$MDEV disk/by-id/mmc-${name}_${serial}${partsuffix};; + mmcblk*) symlink_action ../../$MDEV disk/by-id/mmc-${name}_${serial}${partsuffix} ;; esac fi # virtio-blk case "$MDEV" in - vd*) symlink_action ../../$MDEV disk/by-id/virtio-${serial}${partsuffix};; + vd*) symlink_action ../../$MDEV disk/by-id/virtio-${serial}${partsuffix} ;; esac fi @@ -117,13 +116,13 @@ if [ -n "$UUID" ]; then fi # nvme EBS storage symlinks -if [ "${MDEV#nvme}" != "$MDEV" ] && [ "$model" = "Amazon_Elastic_Block_Store" ] && command -v nvme >/dev/null; then +if [ "${MDEV#nvme}" != "$MDEV" ] && [ "$model" = "Amazon_Elastic_Block_Store" ] && command -v nvme > /dev/null; then n=30 while [ $n -gt 0 ]; do - ebs_alias=$(nvme id-ctrl -b /dev/$_check_dev \ - | dd bs=32 skip=96 count=1 2>/dev/null \ - | sed -nre '/^(\/dev\/)?(s|xv)d[a-z]{1,2} /p' \ - | tr -d ' ') + ebs_alias=$(nvme id-ctrl -b /dev/$_check_dev | + dd bs=32 skip=96 count=1 2> /dev/null | + sed -nre '/^(\/dev\/)?(s|xv)d[a-z]{1,2} /p' | + tr -d ' ') if [ -n "$ebs_alias" ]; then symlink_action "$MDEV" ${ebs_alias#/dev/}$partition break @@ -145,4 +144,3 @@ if [ "${MDEV#sd}" != "$MDEV" ]; then ;; esac fi - From c361f854cf1dd5fb08e6f35faa0bfc98181381ea Mon Sep 17 00:00:00 2001 From: Ricardo Pardini Date: Sat, 1 Jun 2024 09:54:41 +0200 Subject: [PATCH 3/3] hook-mdev: add customized `persistent-storage` script which tries harder to produce /dev/disk/by-id entries by parsing `wwid` - this is still not-even-close to systemd's udev, but should at least add _something_ to by-id when Alpine's mdev wouldn't - if device reports model and serial, all was/is good; - introduce: - if model or serial missing, try parsing them from wwid; - falls back to using the sanitized wwid as serial if parsing fails - last resort: falls back to using 'noserial' as serial for devices that only have a model. - also adds `util-linux` related apks, which brings a more capable `blkid` - for context: https://gitlab.alpinelinux.org/alpine/mdev-conf/-/commits/master/?ref_type=HEADS - add a log of logging, which you can see with `cat /var/log/mdev.log` on Hook's console Signed-off-by: Ricardo Pardini --- images/hook-mdev/Dockerfile | 11 +++- images/hook-mdev/persistent-storage.sh | 82 +++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/images/hook-mdev/Dockerfile b/images/hook-mdev/Dockerfile index 3415ff33..f4008e59 100644 --- a/images/hook-mdev/Dockerfile +++ b/images/hook-mdev/Dockerfile @@ -2,7 +2,16 @@ FROM alpine USER root:root -RUN apk add --no-cache mdev-conf && rm -rf /var/cache/apk/* +RUN apk add --no-cache mdev-conf util-linux util-linux-misc busybox && rm -rf /var/cache/apk/* + +# Overwrite the persistent storage script +COPY persistent-storage.sh lib/mdev/persistent-storage +RUN chmod +x lib/mdev/persistent-storage CMD ["mdev", "-v", "-df"] +# -v Verbose +# -S Log to syslog too +# -s Scan /sys and populate /dev +# -d Daemon, listen on netlink +# -f Run in foreground diff --git a/images/hook-mdev/persistent-storage.sh b/images/hook-mdev/persistent-storage.sh index ea4a794a..5951a325 100644 --- a/images/hook-mdev/persistent-storage.sh +++ b/images/hook-mdev/persistent-storage.sh @@ -1,8 +1,13 @@ #!/bin/sh +echo "--> STARTING persistent-storage script with MDEV='${MDEV}' ACTION='${ACTION}' all params: $*" >&2 + symlink_action() { case "$ACTION" in - add) ln -sf "$1" "$2" ;; + add) + echo "SYMLINK ADD: ln -sf '$1' '$2'" >&2 + ln -sf "$1" "$2" + ;; remove) rm -f "$2" ;; esac } @@ -58,12 +63,18 @@ else fi model=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/model") -name=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/name") +echo "INITIAL model: '${model}'" >&2 +name=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/name") # only used for mmcblk case +echo "INITIAL name: '${name}'" >&2 serial=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/serial") +echo "INITIAL serial: '${serial}'" >&2 # Special case where block devices have serials attached to the block itself, like virtio-blk : ${serial:=$(sanitise_file "$SYSFS/class/block/$_check_dev/serial")} +echo "DEVICE serial (after block-serial): '${serial}'" >&2 wwid=$(sanitise_file "$SYSFS/class/block/$_check_dev/wwid") +echo "INITIAL wwid: '${wwid}'" >&2 : ${wwid:=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/wwid")} +echo "DEVICE wwid (from device-wwid): '${wwid}'" >&2 # Sets variables LABEL, PARTLABEL, PARTUUID, TYPE, UUID depending on # blkid output (busybox blkid will not provide PARTLABEL or PARTUUID) @@ -72,17 +83,79 @@ eval $(blkid /dev/$MDEV | cut -d: -f2-) if [ -n "$wwid" ]; then case "$MDEV" in nvme*) symlink_action ../../$MDEV disk/by-id/nvme-${wwid}${partsuffix} ;; + sd*) symlink_action ../../$MDEV disk/by-id/scsi-${wwid}${partsuffix} ;; + sr*) symlink_action ../../$MDEV disk/by-id/scsi-ro-${wwid}${partsuffix} ;; + vd*) symlink_action ../../$MDEV disk/by-id/virtio-${wwid}${partsuffix} ;; esac case "$wwid" in naa.*) symlink_action ../../$MDEV disk/by-id/wwn-0x${wwid#naa.}${partsuffix} ;; esac fi +# if no model or no serial is available, lets parse the wwid and try to use it +if [ -n "${serial}" ] && [ -n "${model}" ]; then + echo "USING SYSFS model='${model}' serial='${serial}'" >&2 +else + echo "SYSFS model='${model}' serial='${serial}' insufficient, trying to parse from wwid" >&2 + unset wwid_raw + if [ -f "$SYSFS/class/block/$_check_dev/wwid" ]; then + echo "FOUND WWID FILE: '$SYSFS/class/block/$_check_dev/wwid'" >&2 + wwid_raw="$(cat "$SYSFS/class/block/$_check_dev/wwid")" + elif [ -f "$SYSFS/class/block/$_check_dev/device/wwid" ]; then + echo "FOUND WWID FILE: '$SYSFS/class/block/$_check_dev/device/wwid'" >&2 + wwid_raw="$(cat "$SYSFS/class/block/$_check_dev/device/wwid")" + fi + echo "SYSFS parse model/serial from wwid_raw:'${wwid_raw}'" >&2 + if [ -n "${wwid_raw}" ]; then + wwid_raw=$(echo "${wwid_raw}" | sed 's/^ *//;s/ *$//') # Remove leading and trailing spaces + wwid_prefix=$(echo "${wwid_raw}" | awk '{print $1}') # Extract the wwid_prefix (first field) + rest=$(echo "${wwid_raw}" | sed "s/^${wwid_prefix} *//") # Remove the wwid_prefix from the wwid string + wwid_serial=$(echo "${rest}" | awk '{print $NF}') # Extract the serial (last field) + rest=$(echo "${rest}" | sed "s/ ${wwid_serial}$//") # Remove the serial from the rest of the string + wwid_model=$(echo "${rest}" | tr ' ' '_') # Replace any remaining spaces in the rest part with underscores + wwid_model=$(echo "${wwid_model}" | sed 's/__*/_/g') # Remove consecutive underscores + wwid_model=$(echo "${wwid_model}" | sed 's/^_//;s/_$//') # Remove leading and trailing underscores + wwid_prefix=$(echo "${wwid_prefix}" | sed 's/\./-/g') # Replace periods in the wwid_prefix with dashes + unset rest + echo "WWID parsing came up with wwid_prefix='${wwid_prefix}' wwid_model='${wwid_model}', wwid_serial='${wwid_serial}'" >&2 + else + echo "WWID is empty or not found" >&2 + fi + + # if model is unset, replace it with the parsed wwid_model + if [ -z "${model}" ]; then + echo "USING WWID model='${wwid_model}' as model..." >&2 + model="${wwid_model}" + fi + + # if serial is unset, replace it with the parsed wwid_serial + if [ -z "${serial}" ]; then + echo "USING WWID wwid_serial='${wwid_serial}' as serial..." >&2 + serial="${wwid_serial}" + fi + + # if we still have no serial, just use the wwid as serial as fallback; + if [ -z "${serial}" ]; then + echo "FALLBACK: USING WWID as serial='${wwid}'" >&2 + serial="${wwid}" + fi + + # rescue: if _still_ no serial set, set to hardcoded string 'noserial'. + if [ -z "${serial}" ]; then + echo "FALLBACK: USING 'noserial' as serial..." >&2 + serial="noserial" + fi +fi + if [ -n "$serial" ]; then + echo "GOT SERIAL: serial='${serial}' model='${model}'" >&2 if [ -n "$model" ]; then + echo "GOT MODEL: serial='${serial}' model='${model}'" >&2 case "$MDEV" in nvme*) symlink_action ../../$MDEV disk/by-id/nvme-${model}_${serial}${partsuffix} ;; + sr*) symlink_action ../../$MDEV disk/by-id/ata-ro-${model}_${serial}${partsuffix} ;; sd*) symlink_action ../../$MDEV disk/by-id/ata-${model}_${serial}${partsuffix} ;; + vd*) symlink_action ../../$MDEV disk/by-id/virtio-${model}_${serial}${partsuffix} ;; esac fi if [ -n "$name" ]; then @@ -138,9 +211,12 @@ if [ "${MDEV#sd}" != "$MDEV" ]; then case "$sysdev" in *usb[0-9]*) # require vfat for devices without partition - if ! [ -e $SYSFS/block/$MDEV ] || [ TYPE="vfat" ]; then + if ! [ -e $SYSFS/block/$MDEV ] || [ TYPE="vfat" ]; then # @TODO: rpardini: upstream bug here? should be $TYPE symlink_action $MDEV usbdisk fi ;; esac fi + +echo "--> FINISHED persistent-storage script with MDEV='${MDEV}' ACTION='${ACTION}' all params: $*" >&2 +echo "" >&2