Skip to content

Commit 19d73bd

Browse files
authored
hook-mdev: better /dev/disk/by-id via custom mdev script for wwid parsing and fallbacks (#227)
#### 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 #### hook-mdev: rename to `persistent-storage.sh` and shellfmt it (no real changes) - simple rename & shellfmt; separate commit for easy future rebasing #### 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
2 parents 454ff09 + c361f85 commit 19d73bd

File tree

2 files changed

+232
-1
lines changed

2 files changed

+232
-1
lines changed

images/hook-mdev/Dockerfile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,16 @@ FROM alpine
22

33
USER root:root
44

5-
RUN apk add --no-cache mdev-conf && rm -rf /var/cache/apk/*
5+
RUN apk add --no-cache mdev-conf util-linux util-linux-misc busybox && rm -rf /var/cache/apk/*
6+
7+
# Overwrite the persistent storage script
8+
COPY persistent-storage.sh lib/mdev/persistent-storage
9+
RUN chmod +x lib/mdev/persistent-storage
610

711
CMD ["mdev", "-v", "-df"]
812

13+
# -v Verbose
14+
# -S Log to syslog too
15+
# -s Scan /sys and populate /dev
16+
# -d Daemon, listen on netlink
17+
# -f Run in foreground
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
#!/bin/sh
2+
3+
echo "--> STARTING persistent-storage script with MDEV='${MDEV}' ACTION='${ACTION}' all params: $*" >&2
4+
5+
symlink_action() {
6+
case "$ACTION" in
7+
add)
8+
echo "SYMLINK ADD: ln -sf '$1' '$2'" >&2
9+
ln -sf "$1" "$2"
10+
;;
11+
remove) rm -f "$2" ;;
12+
esac
13+
}
14+
15+
sanitise_file() {
16+
sed -E -e 's/^\s+//' -e 's/\s+$//' -e 's/ /_/g' "$@" 2> /dev/null
17+
}
18+
19+
sanitise_string() {
20+
echo "$@" | sanitise_file
21+
}
22+
23+
blkid_encode_string() {
24+
# Rewrites string similar to libblk's blkid_encode_string
25+
# function which is used by udev/eudev.
26+
echo "$@" | sed -e 's| |\\x20|g'
27+
}
28+
29+
: ${SYSFS:=/sys}
30+
31+
# cdrom symlink
32+
case "$MDEV" in
33+
sr* | xvd*)
34+
caps="$(cat $SYSFS/block/$MDEV/capability 2> /dev/null)"
35+
if [ $((0x${caps:-0} & 8)) -gt 0 ] || [ "$(cat $SYSFS/block/$MDEV/removable 2> /dev/null)" = "1" ]; then
36+
symlink_action $MDEV cdrom
37+
fi
38+
;;
39+
esac
40+
41+
# /dev/block symlinks
42+
mkdir -p block
43+
if [ -f "$SYSFS/class/block/$MDEV/dev" ]; then
44+
maj_min=$(sanitise_file "$SYSFS/class/block/$MDEV/dev")
45+
symlink_action ../$MDEV block/${maj_min}
46+
fi
47+
48+
# by-id symlinks
49+
mkdir -p disk/by-id
50+
51+
if [ -f "$SYSFS/class/block/$MDEV/partition" ]; then
52+
# This is a partition of a device, find out its parent device
53+
_parent_dev="$(basename $(${SBINDIR:-/usr/bin}/readlink -f "$SYSFS/class/block/$MDEV/.."))"
54+
55+
partition=$(cat $SYSFS/class/block/$MDEV/partition 2> /dev/null)
56+
case "$partition" in
57+
[0-9]*) partsuffix="-part$partition" ;;
58+
esac
59+
# Get name, model, serial, wwid from parent device of the partition
60+
_check_dev="$_parent_dev"
61+
else
62+
_check_dev="$MDEV"
63+
fi
64+
65+
model=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/model")
66+
echo "INITIAL model: '${model}'" >&2
67+
name=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/name") # only used for mmcblk case
68+
echo "INITIAL name: '${name}'" >&2
69+
serial=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/serial")
70+
echo "INITIAL serial: '${serial}'" >&2
71+
# Special case where block devices have serials attached to the block itself, like virtio-blk
72+
: ${serial:=$(sanitise_file "$SYSFS/class/block/$_check_dev/serial")}
73+
echo "DEVICE serial (after block-serial): '${serial}'" >&2
74+
wwid=$(sanitise_file "$SYSFS/class/block/$_check_dev/wwid")
75+
echo "INITIAL wwid: '${wwid}'" >&2
76+
: ${wwid:=$(sanitise_file "$SYSFS/class/block/$_check_dev/device/wwid")}
77+
echo "DEVICE wwid (from device-wwid): '${wwid}'" >&2
78+
79+
# Sets variables LABEL, PARTLABEL, PARTUUID, TYPE, UUID depending on
80+
# blkid output (busybox blkid will not provide PARTLABEL or PARTUUID)
81+
eval $(blkid /dev/$MDEV | cut -d: -f2-)
82+
83+
if [ -n "$wwid" ]; then
84+
case "$MDEV" in
85+
nvme*) symlink_action ../../$MDEV disk/by-id/nvme-${wwid}${partsuffix} ;;
86+
sd*) symlink_action ../../$MDEV disk/by-id/scsi-${wwid}${partsuffix} ;;
87+
sr*) symlink_action ../../$MDEV disk/by-id/scsi-ro-${wwid}${partsuffix} ;;
88+
vd*) symlink_action ../../$MDEV disk/by-id/virtio-${wwid}${partsuffix} ;;
89+
esac
90+
case "$wwid" in
91+
naa.*) symlink_action ../../$MDEV disk/by-id/wwn-0x${wwid#naa.}${partsuffix} ;;
92+
esac
93+
fi
94+
95+
# if no model or no serial is available, lets parse the wwid and try to use it
96+
if [ -n "${serial}" ] && [ -n "${model}" ]; then
97+
echo "USING SYSFS model='${model}' serial='${serial}'" >&2
98+
else
99+
echo "SYSFS model='${model}' serial='${serial}' insufficient, trying to parse from wwid" >&2
100+
unset wwid_raw
101+
if [ -f "$SYSFS/class/block/$_check_dev/wwid" ]; then
102+
echo "FOUND WWID FILE: '$SYSFS/class/block/$_check_dev/wwid'" >&2
103+
wwid_raw="$(cat "$SYSFS/class/block/$_check_dev/wwid")"
104+
elif [ -f "$SYSFS/class/block/$_check_dev/device/wwid" ]; then
105+
echo "FOUND WWID FILE: '$SYSFS/class/block/$_check_dev/device/wwid'" >&2
106+
wwid_raw="$(cat "$SYSFS/class/block/$_check_dev/device/wwid")"
107+
fi
108+
echo "SYSFS parse model/serial from wwid_raw:'${wwid_raw}'" >&2
109+
if [ -n "${wwid_raw}" ]; then
110+
wwid_raw=$(echo "${wwid_raw}" | sed 's/^ *//;s/ *$//') # Remove leading and trailing spaces
111+
wwid_prefix=$(echo "${wwid_raw}" | awk '{print $1}') # Extract the wwid_prefix (first field)
112+
rest=$(echo "${wwid_raw}" | sed "s/^${wwid_prefix} *//") # Remove the wwid_prefix from the wwid string
113+
wwid_serial=$(echo "${rest}" | awk '{print $NF}') # Extract the serial (last field)
114+
rest=$(echo "${rest}" | sed "s/ ${wwid_serial}$//") # Remove the serial from the rest of the string
115+
wwid_model=$(echo "${rest}" | tr ' ' '_') # Replace any remaining spaces in the rest part with underscores
116+
wwid_model=$(echo "${wwid_model}" | sed 's/__*/_/g') # Remove consecutive underscores
117+
wwid_model=$(echo "${wwid_model}" | sed 's/^_//;s/_$//') # Remove leading and trailing underscores
118+
wwid_prefix=$(echo "${wwid_prefix}" | sed 's/\./-/g') # Replace periods in the wwid_prefix with dashes
119+
unset rest
120+
echo "WWID parsing came up with wwid_prefix='${wwid_prefix}' wwid_model='${wwid_model}', wwid_serial='${wwid_serial}'" >&2
121+
else
122+
echo "WWID is empty or not found" >&2
123+
fi
124+
125+
# if model is unset, replace it with the parsed wwid_model
126+
if [ -z "${model}" ]; then
127+
echo "USING WWID model='${wwid_model}' as model..." >&2
128+
model="${wwid_model}"
129+
fi
130+
131+
# if serial is unset, replace it with the parsed wwid_serial
132+
if [ -z "${serial}" ]; then
133+
echo "USING WWID wwid_serial='${wwid_serial}' as serial..." >&2
134+
serial="${wwid_serial}"
135+
fi
136+
137+
# if we still have no serial, just use the wwid as serial as fallback;
138+
if [ -z "${serial}" ]; then
139+
echo "FALLBACK: USING WWID as serial='${wwid}'" >&2
140+
serial="${wwid}"
141+
fi
142+
143+
# rescue: if _still_ no serial set, set to hardcoded string 'noserial'.
144+
if [ -z "${serial}" ]; then
145+
echo "FALLBACK: USING 'noserial' as serial..." >&2
146+
serial="noserial"
147+
fi
148+
fi
149+
150+
if [ -n "$serial" ]; then
151+
echo "GOT SERIAL: serial='${serial}' model='${model}'" >&2
152+
if [ -n "$model" ]; then
153+
echo "GOT MODEL: serial='${serial}' model='${model}'" >&2
154+
case "$MDEV" in
155+
nvme*) symlink_action ../../$MDEV disk/by-id/nvme-${model}_${serial}${partsuffix} ;;
156+
sr*) symlink_action ../../$MDEV disk/by-id/ata-ro-${model}_${serial}${partsuffix} ;;
157+
sd*) symlink_action ../../$MDEV disk/by-id/ata-${model}_${serial}${partsuffix} ;;
158+
vd*) symlink_action ../../$MDEV disk/by-id/virtio-${model}_${serial}${partsuffix} ;;
159+
esac
160+
fi
161+
if [ -n "$name" ]; then
162+
case "$MDEV" in
163+
mmcblk*) symlink_action ../../$MDEV disk/by-id/mmc-${name}_${serial}${partsuffix} ;;
164+
esac
165+
fi
166+
167+
# virtio-blk
168+
case "$MDEV" in
169+
vd*) symlink_action ../../$MDEV disk/by-id/virtio-${serial}${partsuffix} ;;
170+
esac
171+
fi
172+
173+
# by-label, by-partlabel, by-partuuid, by-uuid symlinks
174+
if [ -n "$LABEL" ]; then
175+
mkdir -p disk/by-label
176+
symlink_action ../../$MDEV disk/by-label/"$(blkid_encode_string "$LABEL")"
177+
fi
178+
if [ -n "$PARTLABEL" ]; then
179+
mkdir -p disk/by-partlabel
180+
symlink_action ../../$MDEV disk/by-partlabel/"$(blkid_encode_string "$PARTLABEL")"
181+
fi
182+
if [ -n "$PARTUUID" ]; then
183+
mkdir -p disk/by-partuuid
184+
symlink_action ../../$MDEV disk/by-partuuid/"$PARTUUID"
185+
fi
186+
if [ -n "$UUID" ]; then
187+
mkdir -p disk/by-uuid
188+
symlink_action ../../$MDEV disk/by-uuid/"$UUID"
189+
fi
190+
191+
# nvme EBS storage symlinks
192+
if [ "${MDEV#nvme}" != "$MDEV" ] && [ "$model" = "Amazon_Elastic_Block_Store" ] && command -v nvme > /dev/null; then
193+
n=30
194+
while [ $n -gt 0 ]; do
195+
ebs_alias=$(nvme id-ctrl -b /dev/$_check_dev |
196+
dd bs=32 skip=96 count=1 2> /dev/null |
197+
sed -nre '/^(\/dev\/)?(s|xv)d[a-z]{1,2} /p' |
198+
tr -d ' ')
199+
if [ -n "$ebs_alias" ]; then
200+
symlink_action "$MDEV" ${ebs_alias#/dev/}$partition
201+
break
202+
fi
203+
n=$((n - 1))
204+
sleep 0.1
205+
done
206+
fi
207+
208+
# backwards compatibility with /dev/usbdisk for /dev/sd*
209+
if [ "${MDEV#sd}" != "$MDEV" ]; then
210+
sysdev=$(readlink $SYSFS/class/block/$MDEV)
211+
case "$sysdev" in
212+
*usb[0-9]*)
213+
# require vfat for devices without partition
214+
if ! [ -e $SYSFS/block/$MDEV ] || [ TYPE="vfat" ]; then # @TODO: rpardini: upstream bug here? should be $TYPE
215+
symlink_action $MDEV usbdisk
216+
fi
217+
;;
218+
esac
219+
fi
220+
221+
echo "--> FINISHED persistent-storage script with MDEV='${MDEV}' ACTION='${ACTION}' all params: $*" >&2
222+
echo "" >&2

0 commit comments

Comments
 (0)