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