Skip to content

Instantly share code, notes, and snippets.

@pyther
Created January 9, 2011 23:25
Show Gist options
  • Save pyther/772138 to your computer and use it in GitHub Desktop.
Save pyther/772138 to your computer and use it in GitHub Desktop.
syslinux-install_update
#!/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