]>
Commit | Line | Data |
---|---|---|
7a63766a JK |
1 | #!/bin/sh |
2 | ||
3 | _SCRIPT_NAME=efi-boot-update | |
4 | _SCRIPT_VERSION=0.0 | |
5 | ||
6 | . /etc/rc.d/init.d/functions | |
7 | ||
8 | usage () { | |
9 | ||
10 | echo "Usage: $0 OPTIONS" | |
11 | echo "Update EFI boot loaders" | |
12 | echo | |
13 | echo " --version Show version number" | |
14 | echo " --help, -h This help message" | |
15 | echo " --mount, -m Try to mount /boot/efi first" | |
16 | echo " --verbose, -v Verbose output" | |
17 | echo " --force Force file updates" | |
18 | } | |
19 | ||
20 | msg () { | |
21 | echo "efi-boot-update: $*" >&2 | |
22 | } | |
23 | ||
24 | verbose () { | |
25 | if is_yes "$VERBOSE" ; then | |
26 | echo "efi-boot-update: $*" >&2 | |
27 | fi | |
28 | } | |
29 | ||
30 | verbose_cmd () { | |
31 | if is_yes "$VERBOSE" ; then | |
32 | echo "+$*" >&2 | |
33 | fi | |
34 | "$@" | |
35 | } | |
36 | ||
37 | ||
38 | list_remove () { | |
39 | ||
40 | for item in $1 ; do | |
41 | if [ "$item" = "$2" ] ; then | |
42 | continue | |
43 | fi | |
44 | echo -n "$item " | |
45 | done | |
46 | } | |
47 | ||
48 | update_file () { | |
49 | local cmd | |
50 | local src | |
51 | local dest | |
52 | while [ -n "$1" ] ; do | |
53 | case $1 in | |
54 | --missingok) | |
55 | shift | |
56 | [ -e "$1" ] || return 0 | |
57 | ;; | |
58 | --*) | |
59 | msg "update_file: ignoring unknown option: $1" | |
60 | shift | |
61 | ;; | |
62 | *) | |
63 | break | |
64 | ;; | |
65 | esac | |
66 | done | |
67 | src="$1"; shift | |
68 | dst="$2"; shift | |
69 | if [ -n "$*" ] ; then | |
70 | msg "update_file: unexpected arguments: $*" | |
71 | return 1 | |
72 | fi | |
73 | if [ "${dst#/}" = "${dst}" ] ; then | |
74 | # relative path | |
75 | dst="$DESTDIR/$dst" | |
76 | fi | |
77 | if is_yes "$FORCE_UPDATES" ; then | |
78 | is_yes "$VERBOSE" && echo +cp --force --preserve=timestamps "$src" "$dst" | |
79 | cp --force --preserve=timestamps "$src" "$dst" | |
80 | else | |
81 | is_yes "$VERBOSE" && echo +cp --update --preserve=timestamps "$src" "$dst" | |
82 | cp --update --preserve=timestamps "$src" "$dst" | |
83 | fi | |
84 | } | |
85 | ||
86 | get_efibootmgr_opts() { | |
87 | local efi_disk | |
88 | local efi_partnum | |
89 | efi_disk=$(mount | awk '$3=="/boot/efi" {print $1}' 2>/dev/null) | |
90 | EFIBOOTMGR_OPTS="--gpt" | |
91 | if [ -n "$efi_disk" ] ; then | |
92 | efi_partnum="$(echo $efi_disk|sed -e's;^.*[^0-9]\([0-9]\+\)$;\1;')" | |
93 | efi_disk="$(echo $efi_disk|sed -e's;^\(.*\)[0-9]\+$;\1;')" | |
94 | if [ -b "$efi_disk" -a -n "$efi_partnum" ] ; then | |
95 | EFIBOOTMGR_OPTS="$EFIBOOTMGR_OPTS --disk $efi_disk" | |
96 | EFIBOOTMGR_OPTS="$EFIBOOTMGR_OPTS --part $efi_partnum" | |
97 | fi | |
98 | fi | |
99 | echo -n $EFIBOOTMGR_OPTS | |
100 | } | |
101 | ||
102 | find_bootmgr_entry () { | |
103 | ||
104 | $EFIBOOTMGR | awk -v find="$1" ' | |
105 | /^Boot[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\*?/ { | |
106 | sub(/^Boot/,""); | |
107 | sub(/\*/,""); | |
108 | num=$1; | |
109 | $1=""; | |
110 | gsub(/^[ \t]+|[ \t]+$/,""); | |
111 | if ($0 == find) print num | |
112 | }' | |
113 | } | |
114 | ||
115 | remove_bootmgr_entry () { | |
116 | local bootnum | |
117 | bootnum=$(find_bootmgr_entry "$1") | |
118 | [ -n "$bootnum" ] || return 0 | |
c1469194 | 119 | verbose_cmd $EFIBOOTMGR $EFIBOOTMGR_OPTS --quiet --delete-bootnum -b "$bootnum" |
7a63766a JK |
120 | echo -n "$bootnum" |
121 | } | |
122 | ||
123 | add_bootmgr_entry () { | |
124 | local label=$1 | |
125 | local binary=$2 | |
126 | local args=$3 | |
127 | local bootnum | |
128 | bootnum=$(find_bootmgr_entry "$label") | |
129 | ||
130 | if [ "${binary#/}" = "${binary}" ] ; then | |
131 | # relative path | |
132 | binary="$DESTDIR/$binary" | |
133 | fi | |
134 | binary="${binary#/boot/efi}" | |
135 | binary="$(echo -n "$binary"|sed -e's;/;\\;g')" | |
136 | ||
137 | if [ -n "$bootnum" ] ; then | |
138 | echo -n "$args" | verbose_cmd $EFIBOOTMGR $EFIBOOTMGR_OPTS --quiet \ | |
139 | --bootnum "$bootnum" --loader "$binary" -@ - | |
140 | else | |
141 | echo -n "$args" | verbose_cmd $EFIBOOTMGR $EFIBOOTMGR_OPTS --create \ | |
142 | --quiet --label "$label" --loader "$binary" -@ - | |
143 | bootnum="$(find_bootmgr_entry "$label")" | |
144 | fi | |
145 | echo -n "$bootnum" | |
146 | } | |
147 | ||
fff9d424 JK |
148 | safe_string () { |
149 | echo -n "$*" | tr -c '[a-zA-Z0-9_]' '_' | |
150 | } | |
151 | ||
7a63766a JK |
152 | FORCE_UPDATES="no" |
153 | MOUNT_EFI_PARTITION="no" | |
154 | LABEL_PREFIX="" | |
155 | DEFAULT="" | |
156 | VERBOSE="no" | |
157 | ||
158 | [ -e /etc/efi-boot/update.conf ] && . /etc/efi-boot/update.conf | |
159 | ||
160 | while [ -n "$*" ] ; do | |
161 | local arg | |
162 | arg="$1" | |
163 | shift | |
164 | case $arg in | |
165 | --help|-h) | |
166 | usage | |
167 | exit 0 | |
168 | ;; | |
169 | --version) | |
170 | echo "$_SCRIPT_NAME $_SCRIPT_VERSION" | |
171 | exit 0 | |
172 | ;; | |
173 | --mount|-m) | |
174 | MOUNT_EFI_PARTITION=yes | |
175 | ;; | |
176 | --verbose|-v) | |
177 | VERBOSE=yes | |
178 | ;; | |
179 | --force) | |
180 | FORCE_UPDATES="yes" | |
181 | ;; | |
182 | *) | |
183 | usage >&2 | |
184 | exit 2 | |
185 | ;; | |
186 | esac | |
187 | done | |
188 | ||
189 | if ! mountpoint -q /boot/efi ; then | |
190 | mkdir -p /boot/efi | |
191 | if is_yes "$MOUNT_EFI_PARTITION" ; then | |
192 | # first try via fstab | |
193 | if ! mount /boot/efi 2>/dev/null ; then | |
194 | local efi_device | |
195 | efi_device="$(/sbin/blkid -o device -l -t PARTUUID="54f69bcc-954d-4f97-8fef-80b359f9e4aa")" | |
196 | if [ -z "$efi_device" ] ; then | |
197 | msg "EFI system partition not found." | |
198 | exit 1 | |
199 | fi | |
200 | mount -t vfat "$efi_device" /boot/efi | |
201 | fi | |
202 | fi | |
203 | if ! mountpoint -q /boot/efi ; then | |
204 | msg "EFI system partition not mounted." | |
205 | exit 1 | |
206 | fi | |
207 | fi | |
208 | ||
209 | if [ -x /usr/sbin/efibootmgr ] ; then | |
210 | modprobe -q efivars | |
211 | EFIBOOTMGR=/usr/sbin/efibootmgr | |
212 | if ! $EFIBOOTMGR >/dev/null 2>&1 ; then | |
213 | msg "efibootmgr does not work (efivars interface not available?)" | |
214 | msg "won't update boot manager configuration" | |
215 | EFIBOOTMGR=/bin/true | |
216 | else | |
217 | EFIBOOTMGR_OPTS="$(get_efibootmgr_opts)" | |
218 | fi | |
219 | else | |
220 | msg "efibootmgr missing, won't update the boot manager configuration" | |
221 | EFIBOOTMGR=/bin/true | |
222 | fi | |
223 | ||
7a63766a JK |
224 | for bootloader_conf in /etc/efi-boot/update.d/*.conf ; do |
225 | if [ ! -e "$bootloader_conf" ] ; then | |
226 | continue | |
227 | fi | |
228 | ENABLED=yes | |
229 | CONFIG_NAME="$(basename "$bootloader_conf" .conf)" | |
230 | LABEL="$CONFIG_NAME" | |
231 | ARCH="$(uname -m)" | |
232 | BINARY="" | |
233 | ARGS="" | |
27eab27d JK |
234 | install_files() { |
235 | /bin/true | |
236 | } | |
7a63766a JK |
237 | |
238 | . "$bootloader_conf" || continue | |
239 | ||
240 | LABEL="$LABEL_PREFIX$LABEL" | |
241 | ||
242 | if ! is_yes "$ENABLED" ; then | |
07ca222f | 243 | remove_bootmgr_entry "$LABEL" >/dev/null |
7a63766a JK |
244 | continue |
245 | fi | |
246 | ||
5b02c492 JK |
247 | local efi_arch |
248 | if [[ "$ARCH" = i?86 || "$ARCH" = pentium[45] || "$ARCH" = "athlon" ]] ; then | |
249 | # %ix86 | |
f8b86fe2 | 250 | efi_arch=ia32 |
5b02c492 JK |
251 | elif [[ "$ARCH" = "x86_64" || "$ARCH" = "amd64" || "$ARCH" = "ia32e" ]] ; then |
252 | # %x8664 | |
253 | efi_arch=x64 | |
254 | else | |
255 | efi_arch="$ARCH" | |
256 | fi | |
257 | DESTDIR="/boot/efi/EFI/$(echo -n "$PLATFORM_DIR"|sed -e's/@ARCH@/'"$efi_arch"'/')" | |
7a63766a JK |
258 | mkdir -p "$DESTDIR" |
259 | ||
260 | verbose "Updating $LABEL..." | |
261 | install_files | |
262 | if [ -n "$BINARY" ] ; then | |
263 | bootnum="$(add_bootmgr_entry "$LABEL" "$BINARY" "$ARGS")" | |
fff9d424 | 264 | eval "_$(safe_string ${CONFIG_NAME})_bootnum=\"$bootnum\"" |
7a63766a JK |
265 | fi |
266 | done | |
267 | ||
da8a0db5 | 268 | if [ -n "$ORDER" -a "$EFIBOOTMGR" != "/bin/true" ] ; then |
7a63766a | 269 | # set up the configured boot order, not removing any existing entries |
da8a0db5 | 270 | tail="$($EFIBOOTMGR | awk '/^BootOrder:/ {gsub(/,/," ",$2); print $2}')" |
7a63766a JK |
271 | head="" |
272 | for config_name in $ORDER ; do | |
fff9d424 | 273 | eval "bootnum=\$_$(safe_string ${config_name})_bootnum" |
7a63766a | 274 | if [ -z "$bootnum" ] ; then |
fff9d424 | 275 | verbose "Cannot find '$config_name' config - won't add to boot order." |
7a63766a JK |
276 | continue |
277 | fi | |
278 | tail="$(list_remove "$tail" "$bootnum")" | |
279 | head="$head $bootnum" | |
280 | done | |
281 | bootorder="$(echo -n $head $tail | sed -e's/ /,/g')" | |
282 | if [ -n "$bootorder" ] ; then | |
283 | verbose_cmd $EFIBOOTMGR $EFIBOOTMGR_OPTS --quiet --bootorder "$bootorder" | |
284 | fi | |
285 | fi | |
286 | ||
287 | # vi: ft=sh sw=4 sts=4 et |