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