113.0-1
[arch-packages.git] / syslinux / repos / core-x86_64 / syslinux-install_update
blob63bbd03c6699ccea13792640fabd2721b1a45c1a
1 #!/usr/bin/bash
3 # Syslinux Installer / Updater Script (for BIOS only)
4 # Copyright (C) 2011-2013 Matthew Gyurgyik <pyther@pyther.net>
5 # Copyright (C) 2013 Keshav Padram Amburay <(the) (ddoott) (ridikulus) (ddoott) (rat) (aatt) (gemmaeiil) (ddoott) (ccoomm)>
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License
9 # as published by the Free Software Foundation; either version 2
10 # of the License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #-----------------
22 # ChangeLog:
23 # 2013-10-23 : Keshav Padram Amburay : Updated script to work with Syslinux 6.02 Arch Linux pkg
24 #-----------------
25 # Exit Codes:
26 # 1 - get_boot_device or other function failed
27 # 2 - install/update failed
28 # 3 - set_active failed
29 # 4 - install_mbr failed
30 #-----------------
32 shopt -s nullglob
34 bios_libpath="/usr/lib/syslinux/bios"
35 bios_bootpath="/boot/syslinux"
36 EXTLINUX="/usr/bin/extlinux"
38 bios_autoupdate_file="/boot/syslinux/SYSLINUX_AUTOUPDATE"
39 pciids_file="/usr/share/hwdata/pci.ids"
41 ## Helper functions ##
42 # Taken from libui-sh
43 # $1 needle
44 # $2 set (array) haystack
45 check_is_in() {
46 local needle="$1" element
47 shift
48 for element; do
49 [[ $element = $needle ]] && return 0
50 done
51 return 1
54 get_disk() {
55 local part=$1
56 if [[ ! -b "${part}" ]]; then
57 echo >&2 "error: '$part' is not a valid block device!"
58 exit 1
61 case "$part" in
62 # catch cases like mmcblk0p1 and loop0p3
63 *[[:digit:]]p[[:digit:]]*)
64 local disk="${part%p[[:digit:]]}" # get everything before p1
67 local disk="${part%%[[:digit:]]*}"
69 esac
70 if [[ ! -b "${disk}" ]]; then
71 echo >&2 "error: '$disk' is not a valid block device!"
72 exit 1
74 echo $disk
77 # return true when blockdevice is an md raid, otherwise return a unset value
78 # get all devices that are part of raid device $1
79 device_is_raid() {
80 [[ $1 && -f /proc/mdstat ]] || return 1
81 local devmajor=$(stat -c %t "$1")
82 (( devmajor == 9 ))
85 mdraid_all_slaves() {
86 local slave slaves
87 for slave in /sys/class/block/${1##*/}/slaves/*; do
88 source "$slave/uevent"
89 slaves="$slaves/dev/$DEVNAME "
90 unset DEVNAME
91 done
92 echo $slaves
95 # Check /sys/block to see if device is partitioned
96 # If we have a partitioned block device (sda1) /sys/block/sda1/dev will not exist
97 # However, if we have an unpartitioned block device (sda) /sys/block/sda/dev will exist
98 dev_is_part() {
99 # $1 - blockdevice
100 local dev=$1
102 # If block device uevent file should be found
103 # If a partition is passed in path shouldn't exist
104 if [[ $dev = *cciss* ]]; then
105 [[ -f /sys/block/cciss\!${dev##*/}/dev ]] && return 1
106 elif [[ $dev = *ida* ]]; then
107 [[ -f /sys/block/ida\!${dev##*/}/dev ]] && return 1
108 else
109 [[ -f /sys/block/${dev##*/}/dev ]] && return 1
112 return 0
115 # If EFI PART is present in the first 8 bytes then it must be a GPT disk
116 device_is_gpt() {
117 local partsig=$(dd if="$1" skip=64 bs=8 count=1 2>/dev/null)
118 [[ $partsig = "EFI PART" ]]
121 clear_gpt_attr2() {
122 # $1 - Block Device, no partitions
123 local disk=$1
125 # Special Exception for cciss controllers
126 if [[ $disk = *cciss* ]]; then
127 for part in /dev/cciss/${disk##*/}*p*; do
128 local partnum="${part##*[[:alpha:]]}"
129 sgdisk "$disk" --attributes="$partnum":clear:2 &>/dev/null
130 done
131 # Smart 2 Controllers
132 elif [[ $disk = *ida* ]]; then
133 for part in /dev/ida/${disk##*/}*p*; do
134 local partnum="${part##*[[:alpha:]]}"
135 sgdisk "$disk" --attributes="$partnum":clear:2 &>/dev/null
136 done
137 else
138 for part in /sys/block/${disk##*/}/${disk##*/}*; do
139 local partnum="${part##*[[:alpha:]]}"
140 sgdisk "$disk" --attributes="$partnum":clear:2 &>/dev/null
141 done
143 return 0
146 usage() {
147 cat << EOF
148 usage: $0 options
150 This script will install or upgrade Syslinux (for BIOS only)
152 OPTIONS:
153 -h Show this message
154 -i Install Syslinux
155 -u Update Syslinux
156 -a Set Boot flag on boot partiton
157 -m Install Syslinux MBR
158 -s Updates Syslinux if /boot/syslinux/SYSLINUX_AUTOUPDATE exists
160 Arguments Required:
161 -c Chroot install (ex: -c /mnt)
163 Example Usage: $0 -i -a -m # (install, set boot flag, install mbr)
164 $0 -u # (update)
168 # Trys to find the partition that /boot resides on
169 # This will either be on /boot or / (root)
170 getBoot() {
171 if [[ ! -d "$bios_bootpath" ]]; then
172 echo "Could not find $bios_bootpath"
173 echo "Is boot mounted? Is Syslinux installed?"
174 exit 1
177 syslinux_fs=(ext2 ext3 ext4 btrfs vfat xfs)
179 # Use DATA from findmnt see rc.sysint for more info
180 if [[ -f /proc/self/mountinfo ]]; then
181 read rootdev rootfs < <(findmnt -run -t noautofs -o SOURCE,FSTYPE "$CHROOT/")
182 read bootdev bootfs < <(findmnt -run -t noautofs -o SOURCE,FSTYPE "$CHROOT/boot")
183 else
184 echo "Could not find /proc/self/mountinfo"
185 echo "Are you running a kernel greater than 2.6.24?"
186 exit 1
189 if [[ $bootfs ]]; then
190 if ! check_is_in "$bootfs" "${syslinux_fs[@]}"; then
191 echo "/boot file system is not supported by Syslinux"
192 exit 1
194 boot="boot"
195 bootpart="$(readlink -f "$bootdev")"
196 elif [[ $rootfs ]]; then
197 if ! check_is_in "$rootfs" "${syslinux_fs[@]}"; then
198 echo "/ (root) file system is not supported by Syslinux"
199 exit 1
201 boot="root"
202 bootpart="$(readlink -f "$rootdev")"
203 else
204 echo "Could not find filesystem on / (root) or /boot."
205 exit 1
209 # We store the partition table type either gpt or mbr in var ptb
210 # In rare cases a user could have one raid disk using mbr and another using gpt
211 # In such cases we accept that the output may be incomplete
213 # Calls get_ptb() for $bootpart or for all device in RAID
214 declare -A bootdevs
215 get_boot_devices() {
216 if device_is_raid "$bootpart"; then
217 slaves=$(mdraid_all_slaves "$bootpart")
219 for slave in ${slaves[@]}; do
220 local disk=$(get_disk "$slave")
221 device_is_gpt "$disk" && local ptb="GPT" || local ptb="MBR"
222 bootdevs[$slave]="$ptb"
223 done
224 else
225 local disk=$(get_disk "$bootpart")
226 device_is_gpt "$disk" && local ptb="GPT" || local ptb="MBR"
227 bootdevs[$bootpart]="$ptb"
231 # Function Assumes the boot partition should be marked as active
232 # All other partitions should not have the boot flag set
233 set_active() {
234 # If any bootdev is a block device without partitions bail
235 # we want to set the boot flag on partitioned disk
236 for dev in "${!bootdevs[@]}"; do
237 dev_is_part $dev || { echo "$dev does not contain partition table. Aborting set_active!"; return 1; }
238 done
240 # Clear BIOS Bootable Legacy Attribute for GPT drives
241 # In rare cases where a RAID device has slaves on the same block device
242 # Attribute 2 will be cleared for each partition multiple times
243 for dev in "${!bootdevs[@]}"; do
244 local ptb="${bootdevs[$dev]}"
245 if [[ "$ptb" = GPT ]]; then
246 local disk=$(get_disk "$dev")
247 clear_gpt_attr2 "$disk"
249 done
251 # Set the boot flag on bootdevs (generated from get_boot_devices)
252 for part in "${!bootdevs[@]}"; do
253 local ptb="${bootdevs[$part]}"
254 local partnum="${part##*[[:alpha:]]}"
255 local disk=$(get_disk "$part")
257 if [[ "$ptb" = MBR ]]; then
258 if sfdisk "$disk" --activate "$partnum" &>/dev/null; then
259 echo "Boot Flag Set - $part"
260 else
261 echo "FAILED to Set the boot flag on $part"
262 exit 3
264 elif [[ "$ptb" = GPT ]]; then
265 if [[ ! -e /usr/bin/sgdisk ]]; then
266 echo "FAILED to set attribute Legacy BIOS Bootable. sgdisk is not found - please install 'gptfdisk' package."
267 exit 3
270 if sgdisk "$disk" --attributes="$partnum":set:2 &>/dev/null; then
271 echo "Attribute Legacy Bios Bootable Set - $part"
272 else
273 echo "FAILED to set attribute Legacy BIOS Bootable on $part"
274 exit 3
277 done
278 return 0
281 install_mbr() {
282 # If any bootdev is a block device without partitions bail
283 # we want to install the mbr to a partitioned disk
284 for dev in "${!bootdevs[@]}"; do
285 dev_is_part "$dev" || { echo "$dev does not contain partition table. Aborting MBR install."; return 1; }
286 done
288 for part in "${!bootdevs[@]}"; do
289 local partnum="${part##*[[:alpha:]]}"
290 local disk=$(get_disk "$part")
291 local ptb="${bootdevs[$part]}"
293 # We want to install to the root of the block device
294 # If the device is a partition - ABORT!
295 dev_is_part "$disk" && \
296 { echo "ABORT! MBR installation to partition ($disk)!"; exit 4;}
298 if [[ "$ptb" = MBR ]]; then
299 mbrfile="$bios_libpath/mbr.bin"
300 elif [[ "$ptb" = GPT ]]; then
301 mbrfile="$bios_libpath/gptmbr.bin"
304 if dd bs=440 count=1 conv=notrunc if="$mbrfile" of="$disk" &> /dev/null; then
305 echo "Installed MBR ($mbrfile) to $disk"
306 else
307 echo "Error Installing MBR ($mbrfile) to $disk"
308 exit 4
310 done
311 return 0
314 install_modules() {
315 # Copy all syslinux *.c32 modules to /boot
316 rm "$bios_bootpath"/*.c32 &> /dev/null
317 cp "$bios_libpath"/*.c32 "$bios_bootpath"/ &> /dev/null
319 # Copy / Symlink pci.ids if pci.ids exists on the FS
320 if [[ -f "$pciids_file" ]]; then
321 rm "$bios_bootpath/pci.ids" &> /dev/null
322 cp "$pciids_file" "$bios_bootpath/pci.ids" &> /dev/null
326 _install() {
327 install_modules
329 if device_is_raid "$bootpart" ; then
330 echo "Detected RAID on /boot - installing Syslinux with --raid"
331 "$EXTLINUX" --install "$bios_bootpath" --raid &> /dev/null
332 else
333 "$EXTLINUX" --install "$bios_bootpath" &> /dev/null
336 if (( $? )); then
337 echo "Syslinux BIOS install failed"
338 exit 2
339 else
340 echo "Syslinux BIOS install successful"
343 touch "$CHROOT/$bios_autoupdate_file"
346 update() {
347 install_modules
349 if device_is_raid "$bootpart" ; then
350 echo "Detected RAID on /boot - updating Syslinux with --raid"
351 "$EXTLINUX" --update "$bios_bootpath" --raid &> /dev/null
352 else
353 "$EXTLINUX" --update "$bios_bootpath" &> /dev/null
356 if (($?)); then
357 echo "Syslinux BIOS update failed"
358 exit 2
359 else
360 echo "Syslinux BIOS update successful"
364 if (( $# == 0 )); then
365 usage
366 exit 1
369 while getopts "c:uihmas" opt; do
370 case $opt in
372 CHROOT=$(readlink -e "$OPTARG")
373 if [[ -z $CHROOT ]]; then
374 echo "error: chroot path ``$OPTARG does not exist";
375 exit 1
379 USAGE="True"
382 INSTALL="True"
385 UPDATE="True"
388 MBR="True"
391 SET_ACTIVE="True"
394 # If AUTOUPDATE_FILE does not exist exit the script
395 if [[ -f $bios_autoupdate_file ]]; then
396 UPDATE="True"
397 else
398 exit 0
402 usage
403 exit 1
405 esac
406 done
408 if [[ $USAGE ]]; then
409 usage
410 exit 0
413 # Display Usage Information if both Install and Update are passed
414 if [[ $INSTALL && $UPDATE ]]; then
415 usage
416 exit 1
419 # Make sure only root can run our script
420 if (( $(id -u) != 0 )); then
421 echo "This script must be run as root" 1>&2
422 exit 1
425 # If a chroot dir is path set variables to reflect chroot
426 if [[ "$CHROOT" ]]; then
427 bios_libpath="$CHROOT$bios_libpath"
428 bios_bootpath="$CHROOT$bios_bootpath"
429 EXTLINUX="$CHROOT$EXTLINUX"
432 # Exit if no /boot path exists
433 if ( f=("$bios_bootpath"/*); (( ! ${#f[@]} )) ); then
434 echo "Error: $bios_bootpath is empty!"
435 echo "Is /boot mounted?"
436 exit 1
439 # Get the boot device if any of these options are passed
440 if [[ $INSTALL || $UPDATE || $SET_ACTIVE || $MBR ]]; then
441 getBoot
444 # Install or Update
445 if [[ $INSTALL ]]; then
446 _install || exit
447 elif [[ $UPDATE ]]; then
448 update || exit
452 # SET_ACTIVE and MBR
453 if [[ $SET_ACTIVE ]] || [[ $MBR ]]; then
454 get_boot_devices
456 if [[ $SET_ACTIVE ]]; then
457 set_active || exit
460 if [[ $MBR ]]; then
461 install_mbr || exit
465 exit 0