-
Notifications
You must be signed in to change notification settings - Fork 10
/
whatsmyboot
executable file
·152 lines (138 loc) · 4 KB
/
whatsmyboot
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/bin/sh
# whatsmyboot (part of ossobv/vcutil) // wdoekes/2024 // Public Domain
#
# Figure out which boot and/or root drive(s) we're using.
#
# This looks to be non-trivial on various systems. This script uses the
# following heuristics:
# - Check efibootmgr -v and read HD(n,GTP,uuid) entries;
# - If not found, ask df where /boot is;
# - If found, check for ZFS and extract source disks.
# Lastly, the partitions are converted to drives by querying udevadm.
#
# Use -r to find the root drives. If you want to exclude drives for e.g. full
# disk encryption, use `whatsmyboot -a` to find both boot and root drives to
# exclude.
#
# USAGE:
#
# # whatsmyboot [-r|-a]
# /dev/sda
# /dev/sdb
#
set -eu
_pathboots() {
local path
path="$1"
local dev type partitions
partitions=$(\
df -l --output=source,fstype "$path" | sed -e1d |
while read dev type; do
if test "$dev" != "${dev#/}"; then
echo "$dev"
elif test "$type" = "zfs"; then
zpool status -LP "${dev%%/*}" |
awk 'substr($1,1,5)=="/dev/"{print $1}'
else
echo "$0: Not implemented: $dev $type" >&2
exit 1
fi
done
)
if test -n "$partitions"; then
echo "$partitions"
else
echo "$0: No BIOS partitions?" >&2
exit 1
fi
}
biosboots() {
_pathboots /boot
}
efiboots() {
local efiout
if efiout=$(efibootmgr -v 2>/dev/null) && test -n "$efiout"; then
local partitions
partitions=$(printf '%s\n' "$efiout" | awk '
/^BootOrder:/{split($2,boots,",")}
/^Boot[0-9].*HD[(][0-9]*,GPT,/{
idx=substr($1,5,4);gsub("^.*HD[(][0-9]*,GPT,","");gsub(",.*","");
bs[idx]=$0}
END{for(bidx in boots){if(bs[boots[bidx]])print bs[boots[bidx]]}}
' | xargs -IX blkid -o device --match-token=PARTUUID=X | uniq)
if test -z "$partitions"; then
echo "$0: EFI, but no boot partitions found?" >&2
exit 1
fi
echo "$partitions"
elif test -d /sys/firmware/efi; then
echo "$0: EFI directory found, but efibootmgr failed?" >&2
exit 1
fi
}
boot_partitions() {
local out
out=$(efiboots)
if test -n "$out"; then
echo "$out"
else
biosboots
fi
}
root_partitions() {
_pathboots /
}
partitions_to_devices() {
# awk '
# /^\/dev\/nvme/{
# gsub("p[0-9]+$", "");if(!($0 in uniq))print $0;uniq[$0]=1}
# /^\/dev\/sd[a-z]/{
# gsub("[0-9]+$", "");if(!($0 in uniq))print $0;uniq[$0]=1}
# !/^\/dev\/(nvme|sd[a-z])/{if(!($0 in uniq))print $0;uniq[$0]=1}
# '
local partition tmp dev dirname
while read partition; do
tmp=$(udevadm info --query=property --name="$partition" |
grep ^DEVPATH=)
if test -z "$tmp"; then
echo "udevadm fail on $partition" >&2
exit 1
fi
tmp=${tmp%/*}
dev=${tmp##*/}
# Is this mdadm? Then we have to translate some more.
if test "$dev" != "${dev#md}"; then
grep "^$dev[[:blank:]]" /proc/mdstat | tr ' ' '\n' |
sed -e '/[[]/!d;s/[[].*//;s@^@/dev/@' |
partitions_to_devices
# Is this nvme? Then strip the namespace.
elif test "$dev" != "${dev#nvme}"; then
tmp=${tmp%/*}
dev=${tmp##*/}
echo "/dev/$dev"
else
echo "/dev/$dev"
fi
done | awk '{if(!($0 in uniq)){print;uniq[$0]=1}}'
}
boot_devices() {
boot_partitions | partitions_to_devices
}
root_devices() {
root_partitions | partitions_to_devices
}
if test $# -eq 0; then
data=$(boot_devices || true)
elif test $# -eq 1 && test "$1" = "-r"; then
data=$(root_devices || true)
elif test $# -eq 1 && test "$1" = "-a"; then
data=$( { boot_devices && root_devices; } | sort -u )
else
echo "usage: $0 [-r|-a]" >&2
exit 1
fi
if test -z "$data"; then
echo "$0: Detection failure" >&2
exit 1
fi
echo "$data"