updated on Sun Jan 15 16:02:00 UTC 2012
[aur-mirror.git] / syslinux-git / syslinux-install_update
blobf7cd123e18838be956319e7d8f6dcc120fd5f9d1
1 #!/bin/bash
3 # Sylinux Installer / Updater Scripts
4 # Copyright (C) 2011 Matthew Gyurgyik <pyther@pyther.net>
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #-----------------
21 # Exit Codes:
22 # 1 - get_boot_device or other function failed
23 # 2 - install/update failed
24 # 3 - set_active failed
25 # 4 - install_mbr failed
27 shopt -s nullglob
29 libpath="/usr/lib/syslinux"
30 bootpath="/boot/syslinux"
31 extlinux="/sbin/extlinux"
33 autoupdate_file=/boot/syslinux/SYSLINUX_AUTOUPDATE
34 com32_files=(menu.c32 vesamenu.c32 chain.c32 hdt.c32 reboot.c32 poweroff.com)
35 pciids_file=/usr/share/hwdata/pci.ids
37 ## Helper functions ##
38 # Taken from libui-sh
39 # $1 needle
40 # $2 set (array) haystack
41 check_is_in() {
42 local needle="$1" element
43 shift
44 for element; do
45 [[ $element = $needle ]] && return 0
46 done
47 return 1
50 # return true when blockdevice is an md raid, otherwise return a unset value
51 # get all devices that are part of raid device $1
52 device_is_raid() {
53 [[ $1 && -f /proc/mdstat ]] || return 1
54 local devmajor=$(stat -c %t "$1")
55 (( devmajor == 9 ))
58 mdraid_all_slaves() {
59 local slave slaves
60 for slave in /sys/class/block/${1##*/}/slaves/*; do
61 source "$slave/uevent"
62 slaves="$slaves/dev/$DEVNAME "
63 unset DEVNAME
64 done
65 echo $slaves
68 # Check /sys/block to see if device is partitioned
69 # If we have a partitioned block device (sda1) /sys/block/sda1/dev will not exist
70 # However, if we have an unpartitioned block device (sda) /sys/block/sda/dev will exist
71 dev_is_part() {
72 # $1 - blockdevice
73 local dev=$1
75 # If block device uevent file should be found
76 # If a partition is passed in path shouldn't exist
77 if [[ $dev = *cciss* ]]; then
78 [[ -f /sys/block/cciss\!${dev##*/}/dev ]] && return 1
79 elif [[ $dev = *ida* ]]; then
80 [[ -f /sys/block/ida\!${dev##*/}/dev ]] && return 1
81 else
82 [[ -f /sys/block/${dev##*/}/dev ]] && return 1
85 return 0
88 # If EFI PART is present in the first 8 bytes then it must be a GPT disk
89 device_is_gpt() {
90 local partsig=$(dd if="$1" skip=64 bs=8 count=1 2>/dev/null)
91 [[ $partsig = "EFI PART" ]]
94 clear_gpt_attr2() {
95 # $1 - Block Device, no partitions
96 local disk=$1
98 # Special Exception for cciss controllers
99 if [[ $disk = *cciss* ]]; then
100 for part in /dev/cciss/${disk##*/}*p*; do
101 local partnum="${part##*[[:alpha:]]}"
102 sgdisk "$disk" --attributes="$partnum":clear:2 &>/dev/null
103 done
104 # Smart 2 Controllers
105 elif [[ $disk = *ida* ]]; then
106 for part in /dev/ida/${disk##*/}*p*; do
107 local partnum="${part##*[[:alpha:]]}"
108 sgdisk "$disk" --attributes="$partnum":clear:2 &>/dev/null
109 done
110 else
111 for part in /sys/block/${disk##*/}/${disk##*/}*; do
112 local partnum="${part##*[[:alpha:]]}"
113 sgdisk "$disk" --attributes="$partnum":clear:2 &>/dev/null
114 done
116 return 0
119 usage() {
120 cat << EOF
121 usage: $0 options
123 This script will install or upgrade Syslinux
125 OPTIONS:
126 -h Show this message
127 -i Install Syslinux
128 -u Update Syslinux
129 -a Set Boot flag on boot partiton
130 -m Install Syslinux MBR
131 -s Updates Syslinux if /boot/syslinux/SYSLINUX_AUTOUPDATE exists
133 Arguments Required:
134 -c Chroot install (ex: -c /mnt)
136 Example Usage: syslinux-install_update.sh -i -a -m (install, set boot flag, install mbr)
137 syslinux-install_update.sh -u (update)
141 # Trys to find the partition that /boot resides on
142 # This will either be on /boot or / (root)
143 getBoot() {
144 if [[ ! -d "$bootpath" ]]; then
145 echo "Could not find $bootpath"
146 echo "Is boot mounted? Is Syslinux installed?"
147 exit 1
150 syslinux_fs=(ext2 ext3 ext4 btrfs vfat)
152 # Use DATA from findmnt see rc.sysint for more info
153 if [[ -f /proc/self/mountinfo ]]; then
154 read rootdev rootfs < <(findmnt -run -t noautofs -o SOURCE,FSTYPE "$CHROOT/")
155 read bootdev bootfs < <(findmnt -run -t noautofs -o SOURCE,FSTYPE "$CHROOT/boot")
156 else
157 echo "Could not find /proc/self/mountinfo"
158 echo "Are you running a kernel greater than 2.6.24?"
159 exit 1
162 if [[ $bootfs ]]; then
163 if ! check_is_in "$bootfs" "${syslinux_fs[@]}"; then
164 echo "/boot file system is not supported by Syslinux"
165 exit 1
167 boot="boot"
168 bootpart="$bootdev"
169 elif [[ $rootfs ]]; then
170 if ! check_is_in "$rootfs" "${syslinux_fs[@]}"; then
171 echo "/ (root) file system is not supported by Syslinux"
172 exit 1
174 boot="root"
175 bootpart="$rootdev"
176 else
177 echo "Could not find filesystem on / (root) or /boot."
178 exit 1
182 # We store the partition table type either gpt or mbr in var ptb
183 # In rare cases a user could have one raid disk using mbr and another using gpt
184 # In such cases we accept that the output may be incomplete
186 # Calls get_ptb() for $bootpart or for all device in RAID
187 declare -A bootdevs
188 get_boot_devices() {
189 if device_is_raid "$bootpart"; then
190 slaves=$(mdraid_all_slaves "$bootpart")
192 for slave in ${slaves[@]}; do
193 local disk="${slave%%[[:digit:]]*}"
194 device_is_gpt "$disk" && local ptb="GPT" || local ptb="MBR"
195 bootdevs[$slave]="$ptb"
196 done
197 else
198 local disk="${bootpart%%[[:digit:]]*}"
199 device_is_gpt "$disk" && local ptb="GPT" || local ptb="MBR"
200 bootdevs[$bootpart]="$ptb"
204 # Function Assumes the boot partition should be marked as active
205 # All other partitions should not have the boot flag set
206 set_active() {
207 # If any bootdev is a block device without partitions bail
208 # we want to set the boot flag on partitioned disk
209 for dev in "${!bootdevs[@]}"; do
210 dev_is_part $dev || { echo "$dev - is a block device. Aborting set_active!"; return 1; }
211 done
213 # Clear BIOS Bootable Legacy Attribute for GPT drives
214 # In rare cases where a RAID device has slaves on the same block device
215 # Attribute 2 will be cleared for each partition multiple times
216 for dev in "${!bootdevs[@]}"; do
217 local ptb="${bootdevs[$dev]}"
218 if [[ "$ptb" = GPT ]]; then
219 local disk="${dev%%[[:digit:]]*}" #ex: /dev/sda
220 clear_gpt_attr2 "$disk"
222 done
224 # Set the boot flag on bootdevs (generated from get_boot_devices)
225 for part in "${!bootdevs[@]}"; do
226 local ptb="${bootdevs[$part]}"
227 local partnum="${part##*[[:alpha:]]}"
228 case "$part" in
229 *[[:digit:]]p[[:digit:]]*)
230 local disk="${part%%p$partnum}" # get everything before p1
233 local disk="${part%%[[:digit:]]*}"
235 esac
237 if [[ "$ptb" = MBR ]]; then
238 if sfdisk "$disk" -A "$partnum" &>/dev/null; then
239 echo "Boot Flag Set - $part"
240 else
241 echo "FAILED to Set the boot flag on $part"
242 exit 3
244 elif [[ "$ptb" = GPT ]]; then
245 if sgdisk "$disk" --attributes="$partnum":set:2 &>/dev/null; then
246 echo "Attribute Legacy Bios Bootable Set - $part"
247 else
248 echo "FAILED to set attribute Legacy BIOS Bootable on $part"
249 exit 3
252 done
253 return 0
256 install_mbr() {
257 # If any bootdev is a block device without partitions bail
258 # we want to install the mbr to a partitioned disk
259 for dev in "${!bootdevs[@]}"; do
260 dev_is_part "$dev" || { echo "$dev - is a block device. Aborting MBR install"; return 1; }
261 done
263 for part in "${!bootdevs[@]}"; do
264 local partnum="${part##*[[:alpha:]]}"
265 case "$part" in
266 *[[:digit:]]p[[:digit:]]*)
267 local disk="${part%%p$partnum}" # get everything before p1
270 local disk="${part%%[[:digit:]]*}"
272 esac
273 local ptb="${bootdevs[$part]}"
275 # We want to install to the root of the block device
276 # If the device is a partition - ABORT!
277 dev_is_part "$disk" && \
278 { echo "ABORT! MBR installation to partition ($disk)!"; exit 4;}
280 if [[ "$ptb" = MBR ]]; then
281 mbrfile="$libpath/mbr.bin"
282 elif [[ "$ptb" = GPT ]]; then
283 mbrfile="$libpath/gptmbr.bin"
286 if dd bs=440 count=1 conv=notrunc if="$mbrfile" of="$disk" &> /dev/null; then
287 echo "Installed MBR ($mbrfile) to $disk"
288 else
289 echo "Error Installing MBR ($mbrfile) to $disk"
290 exit 4
292 done
293 return 0
296 _install() {
297 # Copy files to /boot
298 for file in "${com32_files[@]}"; do
299 # Symlink files even if links exist
300 if [[ "$boot" = root ]]; then
301 ln -s "${libpath#$CHROOT}/$file" "$bootpath/$file" &> /dev/null
302 elif [[ "$boot" = boot ]]; then
303 cp "$libpath/$file" "$bootpath/$file"
305 done
307 # Copy / Symlink pci.ids if we copy the com32 module and if pci.ids exists in the FS
308 if check_is_in "hdt.c32" "${com32_files[@]}" && [[ -f $pciids_file ]]; then
309 if [[ "$boot" = root ]]; then
310 ln -s "$pciids_file" "$bootpath/pci.ids" &> /dev/null
311 elif [[ "$boot" = boot ]]; then
312 cp "$pciids_file" "$bootpath/pci.ids" &> /dev/null
316 if device_is_raid "$bootpart"; then
317 echo "Detected RAID on /boot - installing Syslinux with --raid"
318 "$extlinux" --install "$bootpath" -r > /dev/null 2>&1
319 else
320 "$extlinux" --install "$bootpath" > /dev/null 2>&1
323 if (( $? )); then
324 echo "Syslinux install failed"
325 exit 2
326 else
327 echo "Syslinux install successful"
330 touch "$CHROOT/$autoupdate_file"
333 update() {
334 # Update any com and c32 files in /boot
335 if [[ "$boot" = boot ]]; then
336 for file in "$bootpath"/*.{c32,com}; do
337 file=$(basename "$file")
338 cp "$libpath/$file" "$bootpath/$file" &> /dev/null
339 done
340 if [[ -f "$bootpath/pci.ids" ]]; then
341 cp "$pciids_file" "$bootpath/pci.ids" &> /dev/null
345 if device_is_raid $bootpart; then
346 echo "Detected RAID on /boot - installing Syslinux with --raid"
347 "$extlinux" --update "$bootpath" -r &> /dev/null
348 else
349 "$extlinux" --update "$bootpath" &> /dev/null
352 if (($?)); then
353 echo "Syslinux update failed"
354 exit 2
355 else
356 echo "Syslinux update successful"
360 # Make sure only root can run our script
361 if (( $(id -u) != 0 )); then
362 echo "This script must be run as root" 1>&2
363 exit 1
366 if (( $# == 0 )); then
367 usage
368 exit 1
371 while getopts "c:uihmas" opt; do
372 case $opt in
374 CHROOT=$(readlink -e "$OPTARG")
375 if [[ -z $CHROOT ]]; then
376 echo "error: chroot path ``$OPTARG does not exist";
377 exit 1
381 usage
382 exit 0
385 INSTALL="True"
388 UPDATE="True"
391 MBR="True"
394 SET_ACTIVE="True"
397 # If AUTOUPDATE_FILE does not exist exit the script
398 if [[ -f $autoupdate_file ]]; then
399 UPDATE="True"
400 else
401 exit 0
405 usage
406 exit 1
408 esac
409 done
411 # Display Usage Information if both Install and Update are passed
412 if [[ $INSTALL && $UPDATE ]]; then
413 usage
414 exit 1
417 # If a chroot dir is path set variables to reflect chroot
418 if [[ "$CHROOT" ]]; then
419 libpath="$CHROOT$libpath"
420 bootpath="$CHROOT$bootpath"
421 extlinux="$CHROOT$extlinux"
424 # Exit if no /boot path exists
425 if ( f=("$bootpath"/*); (( ! ${#f[@]} )) ); then
426 echo "Error: $bootpath is empty!"
427 echo "Is /boot mounted?"
428 exit 1
431 # Get the boot device if any of these options are passed
432 if [[ $INSTALL || $UPDATE || $SET_ACTIVE || $MBR ]]; then
433 getBoot
436 # Install or Update
437 if [[ $INSTALL ]]; then
438 _install || exit
439 elif [[ $UPDATE ]]; then
440 update || exit
444 # SET_ACTIVE and MBR
445 if [[ $SET_ACTIVE ]] || [[ $MBR ]]; then
446 get_boot_devices
448 if [[ $SET_ACTIVE ]]; then
449 set_active || exit
452 if [[ $MBR ]]; then
453 install_mbr || exit
457 exit 0
459 # vim: set et sw=4: