summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--modules/dev.inc152
-rw-r--r--modules/regex.inc5
2 files changed, 137 insertions, 20 deletions
diff --git a/modules/dev.inc b/modules/dev.inc
index c2046d3..6080af6 100644
--- a/modules/dev.inc
+++ b/modules/dev.inc
@@ -8,42 +8,154 @@
# The output will be a list of matching devices,
# sorted from largest to smallest.
dev_find_partitions() {
- local ID dev exp target
- exp=
+ local ID dev target
# target for the scan, defaults to /dev to check everything
- if [ -b "$1" ]; then
+ if [ "${1:0:1}" = "/" ] && [ -b "$1" ]; then
target="$1"
shift
- elif [ -d "$1" ]; then
+ elif [ "${1:0:1}" = "/" ] && [ -d "$1" ]; then
target="$1/"
+ shift
else
target="/dev/"
fi
+ local want_label="never match this#"
+ local want_type="never match this#"
+ local want_uuid="never match this#"
while [ "$#" -gt 0 ]; do
ID="$1"
shift
[ -z "$ID" ] && continue
- # if single digit, e.g. 7, look for 0x7 and 0x07
if regex_imatch "$ID" "^[0-9a-f]$"; then
- ID="0?$ID"
- fi
-
- if regex_imatch "$ID" "^[0-9a-f?]{2,3}$"; then # Match two digit and the expanded three digit version from above
- # if double digit look for MBR types and OpenSLX-ID$ID GPT labels
- exp="$exp|ID_PART_ENTRY_(NAME=OpenSLX-ID|TYPE=0x)$ID"
+ want_type="$want_type|0$ID"
+ want_label="$want_label|OpenSLX-ID0$ID"
+ elif regex_imatch "$ID" "^[0-9a-f]{2}$"; then
+ want_type="$want_type|$ID"
+ want_label="$want_label|OpenSLX-ID$ID"
elif regex_imatch "$ID" "^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$"; then
- # if UUID, look for TYPE
- exp="$exp|ID_PART_ENTRY_TYPE=$ID"
- else
- # something else, look for names of partitions / filesystems
- ID="$( regex_escape "$ID" )"
- exp="$exp|ID_(PART_ENTRY_NAME|FS_LABEL)=$ID"
+ want_uuid="$want_uuid|$ID"
+ elif [ "${#ID}" -gt 3 ]; then # Safety measure: Want label length >= 4 chars
+ want_label="$want_label|$( regex_escape "$ID" )"
fi
done
- exp="${exp:1}"
+ local label number mbrid uuid
for dev in $(find $target* -type b); do
- udevadm info --name="$dev" | grep -iqE "($exp)\$" \
- && printf "%s\n" "$(blockdev --getsize64 "$dev") $dev"
+ dev_get_type "$dev"
+ if regex_imatch "$mbrid" "^($want_type)$" || regex_imatch "$uuid" "^($want_uuid)$" \
+ || regex_match "$label" "^($want_label)$"; then
+ printf "%s\n" "$(blockdev --getsize64 "$dev") $dev"
+ fi
done | sort -n -k1 -r | cut -d' ' -f2
}
+dev_get_type() {
+ local part dev partn devn pstart
+ dev=
+ mbrid=
+ uuid=
+ label=
+ number=
+ [ -b "$1" ] || return 1
+ part="$( readlink -f "$1" )"
+ partn="${part##*/}"
+ for devn in "${partn%p?}" "${partn%?}"; do
+ if [ "$dev" != "$part" ] && [ -f "/sys/block/${devn}/${partn}/uevent" ]; then
+ dev="/dev/${devn}"
+ break
+ fi
+ done
+ [ -z "$dev" ] && return 1
+ pstart="$( cat "/sys/block/${devn}/${partn}/start" )" # For validation
+ label="$( grep -Po '(?<=^PARTNAME=).*$' "/sys/block/${devn}/${partn}/uevent" )"
+ number="$( grep -Po '(?<=^PARTN=).*$' "/sys/block/${devn}/${partn}/uevent" )"
+ local gpt=
+ if [ "$( dd if="$dev" bs=1 count=8 skip=512 2> /dev/null )" = "EFI PART" ]; then
+ gpt=512
+ elif [ "$( dd if="$dev" bs=1 count=8 skip=4096 2> /dev/null )" = "EFI PART" ]; then
+ gpt=4096
+ fi
+ if [ -z "$label" ] && [ "$number" -lt 1000 ] && [ "$number" -gt 0 ] \
+ && [ "$( __read_mbrsig "$dev" 0 )" = "55aa" ]; then
+ # Get MBR ID
+ if [ "$number" -le 4 ]; then
+ # Primary
+ mbrid="$( __read_mbrid "$dev" 0 "$number" )"
+ else
+ # Scan for Primary type 05, scan linked list of fake MBRs from there
+ local no id ex_start log_id log_start next_id next_start current
+ for no in 1 2 3 4; do
+ id="$( __read_mbrid "$dev" 0 "$no" )"
+ echo "Scanning. Primary $no is type $id" >&2
+ [ "$id" = "05" ] && break
+ done
+ if [ "$id" != "05" ]; then
+ echo "No matching extended primary partition found" >&2
+ return 1
+ fi
+ ex_start="$( __read_mbrstart "$dev" 0 "$no" )"
+ current="$ex_start"
+ no=5 # Count through logical partitions
+ while [ "$no" != 0 ]; do
+ [ "$( __read_mbrsig "$dev" "$current" )" = "55aa" ] || break
+ log_id="$( __read_mbrid "$dev" "$current" 1 )"
+ if [ "$no" = "$number" ]; then
+ log_start="$( __read_mbrstart "$dev" "$current" 1 )"
+ log_start="$(( log_start + current ))"
+ if [ "$pstart" != "$log_start" ]; then
+ echo "Found partition $no, but start mismatch (want: $pstart found: $log_start)" >&2
+ return 1
+ fi
+ mbrid="$log_id"
+ break
+ fi
+ next_id="$( __read_mbrid "$dev" "$current" 2 )"
+ next_start="$( __read_mbrstart "$dev" "$current" 2 )"
+ echo "Extended id $log_id, next $next_id, $next_start" >&2
+ if [ "$next_id" = "05" ] && [ "$next_start" -gt 0 ]; then
+ current="$(( next_start + ex_start ))"
+ no="$(( no + 1 ))"
+ else
+ no=0
+ fi
+ done
+ fi
+ return 0
+ elif [ -n "$gpt" ]; then
+ # GPT
+ local table_start current entries no entry_size log_start
+ table_start="$( __read_le "$dev" "$(( gpt + 72 ))" 8 )"
+ entries="$( __read_le "$dev" "$(( gpt + 80 ))" 4 )"
+ entry_size="$( __read_le "$dev" "$(( gpt + 84 ))" 4 )"
+ current="$(( table_start * gpt ))"
+ if ! [ "$current" -ge "$(( gpt * 2 ))" ] || ! [ "$entries" -gt 0 ] \
+ || [ "$entries" -lt "$number" ] || ! [ "$entry_size" -le 4096 ]; then
+ echo "Bad GPT table. Start: $current, Partition count: $entries. Want: $number" >&2
+ return 1
+ fi
+ log_start="$( __read_le "$dev" "$(( current + entry_size * (number - 1) + 32 ))" 8 )"
+ if [ "$log_start" != "$pstart" ]; then
+ echo "Found partition $number, but start mismatch (want: $pstart found: $log_start)" >&2
+ return 1
+ fi
+ uuid="$( dd if="$dev" bs=1 count=16 skip="$(( current + entry_size * (number - 1) ))" 2> /dev/null | xxd -p \
+ | sed -r 's/^(..)(..)(..)(..)(..)(..)(..)(..)(....)/\4\3\2\1-\6\5-\8\7-\9-/' )"
+ return 0
+ fi
+}
+
+__read_mbrid() {
+ dd if="$1" bs=1 skip=$(( 512 * $2 + 446 + ($3 - 1) * 16 + 4 )) count=1 2> /dev/null | xxd -p
+}
+
+__read_mbrstart() {
+ __read_le "$1" "$(( 512 * $2 + 446 + ($3 - 1) * 16 + 8 ))" 4
+}
+
+__read_mbrsig() {
+ dd if="$1" bs=1 skip=$(( 512 * $2 + 510 )) count=2 2> /dev/null | xxd -p
+}
+
+__read_le() {
+ local v="$( dd if="$1" bs=1 count="$3" skip="$2" 2> /dev/null | xxd -e -g "$3" | cut -d' ' -f2 )"
+ echo $(( 0x$v ))
+}
diff --git a/modules/regex.inc b/modules/regex.inc
index 21c3d65..3188b2d 100644
--- a/modules/regex.inc
+++ b/modules/regex.inc
@@ -1,5 +1,10 @@
#!/bin/ash
+# Match $1 against perl regex $2, case sensitive
+regex_match() {
+ printf "%s" "$1" | grep -qP "$2"
+}
+
# Match $1 against perl regex $2, case insensitive
regex_imatch() {
printf "%s" "$1" | grep -qPi "$2"