Created
January 9, 2011 23:25
-
-
Save pyther/772138 to your computer and use it in GitHub Desktop.
syslinux-install_update
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# Sylinux Installer / Updater Scripts | |
# Copyright (C) 2011 Matthew Gyurgyik <pyther@pyther.net> | |
# | |
# This program is free software; you can redistribute it and/or | |
# modify it under the terms of the GNU General Public License | |
# as published by the Free Software Foundation; either version 2 | |
# of the License, or (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program; if not, write to the Free Software | |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
# | |
# | |
shopt -s nullglob | |
libpath="/usr/lib/syslinux" | |
bootpath="/boot/syslinux" | |
extlinux="/sbin/extlinux" | |
autoupdate_file=/boot/syslinux/SYSLINUX_AUTOUPDATE | |
com32_files=(menu.c32 vesamenu.c32 chain.c32 hdt.c32 reboot.c32 poweroff.com) | |
# Stolen from AIF (Arch Linux Installer Framework) | |
# $1 blockdevice (ex: /dev/md0 or /dev/sda1) | |
# return true when blockdevice is an md raid, otherwise return a unset value | |
mdraid_is_raid() | |
{ | |
if [[ "$(mdadm --query "$1" | cut -d':' -f2)" == " is not an md array" ]]; then | |
return 1 | |
fi | |
return 0 | |
} | |
# Stolen from AIF (Archlinux Installer Framework) | |
# Simply gets all the device that are part of the raid | |
mdraid_all_slaves () | |
{ | |
local slave= | |
local slaves= | |
for slave in /sys/class/block/$(basename "$1")/slaves/*; do | |
slaves+="/dev/$(basename $slave) " | |
done | |
echo "$slaves" | |
} | |
## Helper functions ## | |
# Taken from libui-sh | |
# $1 needle | |
# $2 set (array) haystack | |
check_is_in () | |
{ | |
local needle="$1" element | |
shift | |
for element; do | |
[[ $element = $needle ]] && return 0 | |
done | |
return 1 | |
} | |
usage() { | |
cat << EOF | |
usage: $0 options | |
This script will install or upgrade Syslinux | |
OPTIONS: | |
-h Show this message | |
-i Install Syslinux | |
-u Update Syslinux | |
-a Set Boot flag on boot partiton | |
-m Install Syslinux MBR | |
-s Updates Syslinux if /boot/syslinux/SYSLINUX_AUTOUPDATE exists | |
Arguments Required: | |
-c Chroot install (ex: -c /mnt) | |
Example Usage: syslinux-install_update.sh -i -m -a (install) | |
syslinux-install_update.sh -u (update) | |
EOF | |
} | |
# Trys to find the partition that /boot resides on | |
# This will either be on /boot or / (root) | |
getBoot() { | |
if [[ ! -d "$bootpath" ]]; then | |
echo "Could not find $bootpath" | |
echo "Is boot mounted? Is Syslinux installed?" | |
exit 1 | |
fi | |
syslinux_fs=(ext2 ext3 ext4 btrfs) | |
# Use DATA from findmnt see rc.sysint for more info | |
# fallback on /etc/mtab | |
if [[ -f /proc/self/mountinfo ]]; then | |
read rootdev rootfs < <(findmnt -run -o SOURCE,FSTYPE "$CHROOT/") | |
read bootdev bootfs < <(findmnt -run -o SOURCE,FSTYPE "$CHROOT/boot") | |
fi | |
if [[ $bootfs ]]; then | |
if ! check_is_in "$bootfs" "${syslinux_fs[@]}"; then | |
echo "/boot file system is not supported by Syslinux" | |
exit 1 | |
fi | |
boot="boot" | |
bootpart="$bootdev" | |
elif [[ $rootfs ]]; then | |
if ! check_is_in "$rootfs" "${syslinux_fs[@]}"; then | |
echo "/ (root) file system is not supported by Syslinux" | |
exit 1 | |
fi | |
boot="root" | |
bootpart="$rootdev" | |
else | |
echo "Could not find filesystem on / (root) or /boot." | |
exit 1 | |
fi | |
} | |
# We store the partition table type either gpt or mbr in var ptb | |
# In rare cases a user could have one raid disk using mbr and another using gpt | |
# In such cases we accept that the output may be incomplete | |
# Detects if a partition is using the GPT or MBR Partiton Layout | |
# $1 = disk partition (/dev/sdxY) | |
get_ptb() { | |
part=$1 | |
local disk=$(sed '$s/.$//' <<<"$part") | |
gptwarn=$(fdisk -l "$disk" 2>&1 | grep 'WARNING: GPT') | |
if [[ "$gptwarn" ]]; then | |
ptb="GPT" | |
else | |
ptb="MBR" | |
fi | |
} | |
# Calls get_ptb() for $bootpart or for all device in RAID | |
declare -A partptb | |
detect_ptb() { | |
if mdraid_is_raid "$bootpart"; then | |
slaves=$(mdraid_all_slaves "$bootpart") | |
for slave in $slaves; do | |
get_ptb "$slave" | |
partptb[$slave]="$ptb" | |
done | |
else | |
get_ptb "$bootpart" | |
partptb[$bootpart]="$ptb" | |
fi | |
} | |
# Checks to see if a specific partition is active | |
is_part_active() { | |
local part=$1 | |
local ptb=$2 | |
local disk=$(sed '$s/.$//' <<<"$part") | |
local partnum=$(sed 's/^.*\(.\)$/\1/' <<<"$part") | |
if [[ "$ptb" == "GPT" ]]; then | |
activepart=$(sgdisk $disk --attributes=$partnum:show) | |
elif [[ "$ptb" == "MBR" ]]; then | |
activepart=$(fdisk -l $disk | grep '^/' | awk '/ \* /{print $1}') | |
fi | |
if [[ -z "$activepart" ]]; then | |
return 1 | |
fi | |
return 0 | |
} | |
# Looks at $bootpart or all device in RAID | |
# Stores all nonactive partitions in array | |
# Also displays warning if user didn't pass -a | |
declare -A nonactive | |
detect_active() { | |
detect_ptb | |
for part in "${!partptb[@]}"; do | |
local ptb="${partptb[$part]}" | |
is_part_active "$part" "$ptb" || nonactive[$part]="$ptb" | |
done | |
if [[ -z "$SET_ACTIVE" ]]; then | |
if (( ${#nonactive[@]} )); then | |
echo "" | |
echo "*** WARNING: The boot flag is not set!!! ***" | |
echo "Set the boot flag for the following partitions:" | |
for x in "${!nonactive[@]}"; do | |
echo " $x - ${nonactive[$x]}" | |
done | |
echo -e "\nFAILURE to do so will make your system unbootable!" | |
echo "Run $0 -a to automatically set the boot flag" | |
echo "GPT USERS: The boot flag is known as the Legacy Bios Bootable attribute" | |
fi | |
fi | |
} | |
# Sets the boot flag or gpt attribute for all nonactive partitions | |
set_active() { | |
for part in "${!nonactive[@]}"; do | |
local ptb="${nonactive[$part]}" | |
local disk=$(sed '$s/.$//' <<<"$part") | |
local partnum=$(sed 's/^.*\(.\)$/\1/' <<<"$part") | |
if [[ "$ptb" == "MBR" ]]; then | |
# Setting the bootable flag on a live disk should not be a problem | |
sfdisk "$disk" -N"$partnum" --force &> /dev/null << EOF | |
,,,* | |
y | |
EOF | |
if (( $? )); then | |
echo "FAILED to set boot flag on $part" | |
else | |
echo "Successfully set boot flag on $part" | |
fi | |
elif [[ "$ptb" == "GPT" ]]; then | |
if sgdisk "$disk" --attributes="$partnum":set:2; then | |
echo "Successfully set attribute Legacy BIOS Bootable on $part" | |
else | |
echo "FAILED to set attribute Legacy BIOS Bootable on $part" | |
fi | |
fi | |
done | |
} | |
_install() { | |
# Find which device contains /boot | |
getBoot | |
# Copy files to /boot | |
for file in "${com32_files[@]}"; do | |
# Symlink files even if links exist | |
# File list may change | |
if [[ "$boot" = "root" ]]; then | |
ln -s "$libpath/$file" "$bootpath/$file" &> /dev/null | |
elif [[ "$boot" = "boot" ]]; then | |
cp "$libpath/$file" "$bootpath/$file" | |
fi | |
done | |
if mdraid_is_raid "$bootpart"; then | |
echo "Detected RAID on /boot - installing Syslinux with --raid" | |
"$extlinux" --install "$bootpath" -r > /dev/null 2>&1 | |
else | |
"$extlinux" --install "$bootpath" > /dev/null 2>&1 | |
fi | |
touch "$CHROOT$autoupdate_file" | |
if (( $? )); then | |
echo "Syslinux install failed" | |
exit | |
else | |
echo "Syslinux install successful" | |
fi | |
detect_active | |
if [[ ! $MBR ]]; then | |
echo "" | |
echo "*** WARNING: Install the appropriate syslinux MBR to your disk(s) ***" | |
echo "Example:" | |
for x in "${!partptb[@]}"; do | |
local part="$x" | |
local disk=$(sed '$s/.$//' <<<"$part") | |
local ptb="${partptb[$x]}" | |
if [[ "$ptb" == "MBR" ]]; then | |
echo -e " dd bs=440 count=1 conv=notrunc if=$libpath/mbr.bin of=$disk" | |
elif [[ "$ptb" == "GPT" ]]; then | |
echo -e " dd bs=440 count=1 conv=notrunc if=$libpath/gptmbr.bin of=$disk" | |
fi | |
done | |
fi | |
} | |
install_mbr() { | |
for x in "${!partptb[@]}"; do | |
local part="$x" | |
local disk=$(sed '$s/.$//' <<<"$part") | |
local ptb="${partptb[$x]}" | |
if [[ "$ptb" == "MBR" ]]; then | |
mbrfile="$libpath/mbr.bin" | |
elif [[ "$ptb" == "GPT" ]]; then | |
mbrfile="$libpath/gptmbr.bin" | |
fi | |
if dd bs=440 count=1 conv=notrunc if="$mbrfile" of="$disk" &> /dev/null; then | |
echo "Installed MBR ($mbrfile) to $disk" | |
else | |
echo "Error Installing MBR ($mbrfile) to $disk" | |
return 1 | |
fi | |
done | |
} | |
update() { | |
if (f=("$bootpath"/*); ((! ${#f[@]}))); then | |
echo "Error: $bootpath is empty!" | |
echo "Is /boot mounted?" | |
exit 1 | |
fi | |
getBoot | |
# Update any com and c32 files in /boot | |
if [[ "$boot" = "boot" ]]; then | |
for file in "$bootpath"/*.{c32,com}; do | |
file=$(basename "$file") | |
cp "$libpath/$file" "$bootpath/$file" &> /dev/null | |
done | |
fi | |
if mdraid_is_raid $bootpart; then | |
echo "Detected RAID on /boot - installing Syslinux with --raid" | |
"$extlinux" --update "$bootpath" -r &> /dev/null | |
else | |
"$extlinux" --update "$bootpath" &> /dev/null | |
fi | |
if (($?)); then | |
echo "Syslinux update failed" | |
else | |
echo "Syslinux update successful" | |
fi | |
} | |
# Make sure only root can run our script | |
if (( $(id -u) != 0 )); then | |
echo "This script must be run as root" 1>&2 | |
exit 1 | |
fi | |
if (( $# == 0 )); then | |
usage | |
exit 1 | |
fi | |
while getopts "c:uihmas" opt; do | |
case $opt in | |
c) | |
CHROOT="$OPTARG" | |
;; | |
h) | |
usage | |
exit 0 | |
;; | |
i) | |
INSTALL="True" | |
;; | |
u) | |
UPDATE="True" | |
;; | |
m) | |
MBR="True" | |
;; | |
a) | |
SET_ACTIVE="True" | |
;; | |
s) | |
AUTOUPDATE="True" | |
;; | |
*) | |
usage | |
exit 1 | |
;; | |
esac | |
done | |
if [[ "$INSTALL" ]] && [[ "$UPDATE" ]]; then | |
usage | |
exit 1 | |
fi | |
if [[ "$CHROOT" ]]; then | |
libpath="$CHROOT$libpath" | |
bootpath="$CHROOT$bootpath" | |
extlinux="$CHROOT$extlinux" | |
fi | |
if [[ "AUTOUPDATE" ]]; then | |
if [[ -f "$autoupdate_file" ]]; then | |
update | |
fi | |
fi | |
if [[ "$INSTALL" ]]; then _install; elif [[ "$UPDATE" ]]; then update; fi | |
if [[ "$SET_ACTIVE" ]]; then | |
if [[ ! "$INSTALL" ]] && [[ ! "$UPDATE" ]]; then | |
getBoot | |
fi | |
if [[ ! "$INSTALL" ]]; then | |
detect_active | |
fi | |
set_active | |
fi | |
if [[ "$MBR" ]]; then | |
# If we are only installing the mbr then try to detect boot device | |
if [[ ! "$INSTALL" ]] && [[ ! "$UPDATE" ]]; then | |
getBoot | |
fi | |
if [[ ! "$INSTALL" ]]; then | |
detect_ptb | |
fi | |
install_mbr | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment