blob: 6080af67f1aeac2adca6ab176b12bf551b5cd49e (
plain) (
tree)
|
|
#!/bin/ash
# Get all partitions with given id (list of /dev/sdXX)
# Works for MBR/DOS by looking at the type (1 byte)
# and for GPT by looking for the label 'OpenSLX-ID$1'
# in case an id was given, or with the given UUID,
# or with the given name.
# The output will be a list of matching devices,
# sorted from largest to smallest.
dev_find_partitions() {
local ID dev target
# target for the scan, defaults to /dev to check everything
if [ "${1:0:1}" = "/" ] && [ -b "$1" ]; then
target="$1"
shift
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 regex_imatch "$ID" "^[0-9a-f]$"; then
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
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
local label number mbrid uuid
for dev in $(find $target* -type b); do
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 ))
}
|