]> git.pld-linux.org Git - packages/efi-boot-update.git/commitdiff
new package
authorJacek Konieczny <j.konieczny@eggsoft.pl>
Tue, 30 Oct 2012 15:19:14 +0000 (16:19 +0100)
committerJacek Konieczny <jajcus@jajcus.net>
Tue, 30 Oct 2012 15:19:14 +0000 (16:19 +0100)
I hope this is not useless.

README [new file with mode: 0644]
TODO [new file with mode: 0644]
efi-boot-update [new file with mode: 0755]
efi-boot-update.spec [new file with mode: 0644]
grub.conf [new file with mode: 0644]
shellx32.conf [new file with mode: 0644]
shellx64.conf [new file with mode: 0644]
update.conf [new file with mode: 0644]
xen.conf [new file with mode: 0644]

diff --git a/README b/README
new file mode 100644 (file)
index 0000000..f873e79
--- /dev/null
+++ b/README
@@ -0,0 +1,26 @@
+(U)EFI bootloaders updater
+==========================
+
+What is this for?
+-----------------
+
+(U)EFI systems boot using bootloaders on a special EFI System Partition.
+Many different bootloaders may be present at a time. These are not only
+traditional bootloaders like GRUB, but arbitrary 'EFI applications'.
+
+Xen or Linux kernel can be built as an EFI application too and booted directly
+from the EFI firmware. The problem is the kernels and data or config files
+needed for boot must be stored on the EFI System Partition, but that is not
+the place where they are installed on package upgrade. And it is hard to
+install files from RPM packages there directly.
+
+efi-boot-update script makes it easy to manage the files on the EFI system
+partition. Those files are to be installed in the regular Linux system and
+will be copied to the EFI system partition using rules defined in
+/etc/efi-boot/update.d/*.conf files.
+
+efi-boot-update will also manage EFI boot manager configuration, adding
+the configured bootloaders to the platform boot menu, provided the 'efibootmgr'
+package is installed and functional.
+
+
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..cb07a7e
--- /dev/null
+++ b/TODO
@@ -0,0 +1,5 @@
+
+TODO:
+   - complete the documentation
+   - support for boot entries for anything else that files in /boot/efi
+   - handle /dev/something0p1 partition devices
diff --git a/efi-boot-update b/efi-boot-update
new file mode 100755 (executable)
index 0000000..f2095ec
--- /dev/null
@@ -0,0 +1,273 @@
+#!/bin/sh
+
+_SCRIPT_NAME=efi-boot-update
+_SCRIPT_VERSION=0.0
+
+. /etc/rc.d/init.d/functions
+
+usage () {
+
+    echo "Usage: $0 OPTIONS"
+    echo "Update EFI boot loaders"
+    echo
+    echo "  --version      Show version number"
+    echo "  --help, -h     This help message"
+    echo "  --mount, -m    Try to mount /boot/efi first"
+    echo "  --verbose, -v  Verbose output"
+    echo "  --force        Force file updates"
+}
+
+msg () {
+    echo "efi-boot-update: $*" >&2
+}
+
+verbose () {
+    if is_yes "$VERBOSE" ; then 
+        echo "efi-boot-update: $*" >&2
+    fi
+}
+
+verbose_cmd () {
+    if is_yes "$VERBOSE" ; then
+        echo "+$*" >&2
+    fi
+    "$@"
+}
+
+
+list_remove () {
+
+    for item in $1 ; do
+        if [ "$item" = "$2" ] ; then
+            continue
+        fi
+        echo -n "$item "
+    done
+}
+
+update_file () {
+    local cmd
+    local src
+    local dest
+    while [ -n "$1" ] ; do
+        case $1 in 
+            --missingok)
+                shift
+                [ -e "$1" ] || return 0
+                ;;
+            --*)
+                msg "update_file: ignoring unknown option: $1"
+                shift
+                ;;
+            *)
+                break
+                ;;
+        esac
+    done
+    src="$1"; shift
+    dst="$2"; shift
+    if [ -n "$*" ] ; then
+        msg "update_file: unexpected arguments: $*"
+        return 1
+    fi
+    if [ "${dst#/}" = "${dst}" ] ; then
+        # relative path
+        dst="$DESTDIR/$dst"
+    fi
+    if is_yes "$FORCE_UPDATES" ; then
+        is_yes "$VERBOSE" && echo +cp --force --preserve=timestamps "$src" "$dst"
+        cp --force --preserve=timestamps "$src" "$dst"
+    else
+        is_yes "$VERBOSE" && echo +cp --update --preserve=timestamps "$src" "$dst"
+        cp --update --preserve=timestamps "$src" "$dst"
+    fi
+}
+
+get_efibootmgr_opts() {
+    local efi_disk
+    local efi_partnum
+    efi_disk=$(mount | awk '$3=="/boot/efi" {print $1}' 2>/dev/null)
+    EFIBOOTMGR_OPTS="--gpt"
+    if [ -n "$efi_disk" ] ; then
+        efi_partnum="$(echo $efi_disk|sed -e's;^.*[^0-9]\([0-9]\+\)$;\1;')"
+        efi_disk="$(echo $efi_disk|sed -e's;^\(.*\)[0-9]\+$;\1;')"
+        if [ -b "$efi_disk" -a -n "$efi_partnum" ] ; then 
+            EFIBOOTMGR_OPTS="$EFIBOOTMGR_OPTS --disk $efi_disk"
+            EFIBOOTMGR_OPTS="$EFIBOOTMGR_OPTS --part $efi_partnum"
+        fi
+    fi
+    echo -n $EFIBOOTMGR_OPTS
+}
+
+find_bootmgr_entry () {
+
+    $EFIBOOTMGR | awk -v find="$1" '
+/^Boot[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\*?/ { 
+                                sub(/^Boot/,""); 
+                                sub(/\*/,""); 
+                                num=$1; 
+                                $1=""; 
+                                gsub(/^[ \t]+|[ \t]+$/,""); 
+                                if ($0 == find) print num
+                            }'
+}
+        
+remove_bootmgr_entry () {
+    local bootnum
+    bootnum=$(find_bootmgr_entry "$1")
+    [ -n "$bootnum" ] || return 0
+    verbose_cmd $EFIBOOTMGR $EFIBOOTMGR_OPTS --delete-bootnum -b --quiet "$bootnum"
+    echo -n "$bootnum"
+}
+
+add_bootmgr_entry () {
+    local label=$1
+    local binary=$2
+    local args=$3
+    local bootnum
+    bootnum=$(find_bootmgr_entry "$label")
+
+    if [ "${binary#/}" = "${binary}" ] ; then
+        # relative path
+        binary="$DESTDIR/$binary"
+    fi
+    binary="${binary#/boot/efi}"
+    binary="$(echo -n "$binary"|sed -e's;/;\\;g')"
+
+    if [ -n "$bootnum" ] ; then
+        echo -n "$args" | verbose_cmd $EFIBOOTMGR $EFIBOOTMGR_OPTS --quiet \
+                            --bootnum "$bootnum" --loader "$binary" -@ -
+    else
+        echo -n "$args" | verbose_cmd $EFIBOOTMGR $EFIBOOTMGR_OPTS --create \
+                            --quiet --label "$label" --loader "$binary" -@ -
+        bootnum="$(find_bootmgr_entry "$label")"
+    fi
+    echo -n "$bootnum"
+}
+
+FORCE_UPDATES="no"
+MOUNT_EFI_PARTITION="no"
+LABEL_PREFIX=""
+DEFAULT=""
+VERBOSE="no"
+
+[ -e /etc/efi-boot/update.conf ] && . /etc/efi-boot/update.conf
+
+while [ -n "$*" ] ; do
+    local arg
+    arg="$1"
+    shift
+    case $arg in
+        --help|-h)
+            usage
+            exit 0
+            ;;
+        --version)
+            echo "$_SCRIPT_NAME $_SCRIPT_VERSION"
+            exit 0
+            ;;
+        --mount|-m)
+            MOUNT_EFI_PARTITION=yes
+            ;;
+        --verbose|-v)
+            VERBOSE=yes
+            ;;
+        --force)
+            FORCE_UPDATES="yes"
+            ;;
+        *)
+            usage >&2
+            exit 2
+            ;;
+    esac
+done
+
+if ! mountpoint -q /boot/efi ; then
+    mkdir -p /boot/efi
+    if is_yes "$MOUNT_EFI_PARTITION" ; then
+        # first try via fstab
+        if ! mount /boot/efi 2>/dev/null ; then
+            local efi_device
+            efi_device="$(/sbin/blkid -o device -l -t PARTUUID="54f69bcc-954d-4f97-8fef-80b359f9e4aa")"
+            if [ -z "$efi_device" ] ; then
+                msg "EFI system partition not found."
+                exit 1
+            fi
+            mount -t vfat "$efi_device" /boot/efi
+        fi
+    fi
+    if ! mountpoint -q /boot/efi ; then
+        msg "EFI system partition not mounted."
+        exit 1
+    fi
+fi
+
+if [ -x /usr/sbin/efibootmgr ] ; then
+    modprobe -q efivars
+    EFIBOOTMGR=/usr/sbin/efibootmgr
+    if ! $EFIBOOTMGR >/dev/null 2>&1 ; then
+        msg "efibootmgr does not work (efivars interface not available?)"
+        msg "won't update boot manager configuration"
+        EFIBOOTMGR=/bin/true
+    else
+        EFIBOOTMGR_OPTS="$(get_efibootmgr_opts)"
+    fi
+else
+    msg "efibootmgr missing, won't update the boot manager configuration"
+    EFIBOOTMGR=/bin/true
+fi
+
+
+for bootloader_conf in /etc/efi-boot/update.d/*.conf ; do
+    if [ ! -e "$bootloader_conf" ] ; then
+        continue
+    fi
+    ENABLED=yes
+    CONFIG_NAME="$(basename "$bootloader_conf" .conf)"
+    LABEL="$CONFIG_NAME"
+    ARCH="$(uname -m)"
+    BINARY=""
+    ARGS=""
+    install_files() {}
+
+    . "$bootloader_conf" || continue
+
+    LABEL="$LABEL_PREFIX$LABEL"
+
+    if ! is_yes "$ENABLED" ; then
+        remove_bootmgr_entry "$LABEL"
+        continue
+    fi
+
+    DESTDIR="/boot/efi/EFI/$(echo -n "$PLATFORM_DIR"|sed -e's/@ARCH@/'"$ARCH"'/')"
+    mkdir -p "$DESTDIR"
+
+    verbose "Updating $LABEL..."
+    install_files
+    if [ -n "$BINARY" ] ; then
+            bootnum="$(add_bootmgr_entry "$LABEL" "$BINARY" "$ARGS")"
+            eval "_${CONFIG_NAME}_bootnum=\"$bootnum\""
+    fi
+done
+
+if [ -n "$ORDER" ] ; then
+    set -x
+    # set up the configured boot order, not removing any existing entries
+    tail="$(efibootmgr | awk '/^BootOrder:/ {gsub(/,/," ",$2); print $2}')"
+    head=""
+    for config_name in $ORDER ; do
+        eval "bootnum=\$_${config_name}_bootnum"
+        if [ -z "$bootnum" ] ; then
+            msg "Cannot find '$config_name' config - won't add to boot order."
+            continue
+        fi
+        tail="$(list_remove "$tail" "$bootnum")"
+        head="$head $bootnum"
+    done
+    bootorder="$(echo -n $head $tail | sed -e's/ /,/g')"
+    if [ -n "$bootorder" ] ; then
+        verbose_cmd $EFIBOOTMGR $EFIBOOTMGR_OPTS --quiet --bootorder "$bootorder"
+    fi
+fi
+
+# vi: ft=sh sw=4 sts=4 et
diff --git a/efi-boot-update.spec b/efi-boot-update.spec
new file mode 100644 (file)
index 0000000..9b3fff1
--- /dev/null
@@ -0,0 +1,67 @@
+# $Revision: 1.81 $, $Date: 2012/04/20 10:52:52 $
+#
+Summary:       EFI bootloader updater
+Name:          efi-boot-update
+Version:       0.1
+Release:       0.1
+License:       GPL v2
+Group:         Applications
+Source0:       %{name}
+Source1:       update.conf
+Source2:       shellx64.conf
+Source3:       shellx32.conf
+Source4:       grub.conf
+Source10:      README
+Source11:      TODO
+URL:           http://www.pld-linux.org/
+BuildRequires: help2man
+Suggests:      efibootmgr
+BuildRoot:     %{tmpdir}/%{name}-%{version}-root-%(id -u -n)
+
+%define                _sbindir /sbin
+
+%description
+Script to update EFI bootloaders.
+
+%prep
+%setup -qcT
+cp %{SOURCE0} .
+cp %{SOURCE10} %{SOURCE11} .
+
+%build
+chmod a+x %{name}
+help2man --no-info ./%{name} > %{name}.8
+
+%install
+rm -rf $RPM_BUILD_ROOT
+install -d $RPM_BUILD_ROOT/etc/efi-boot/update.d
+install -d $RPM_BUILD_ROOT{%{_prefix}/lib{,64}/efi,%{_sbindir},%{_mandir}/man8}
+
+install %{name} $RPM_BUILD_ROOT%{_sbindir}/%{name}
+install %{name}.8 $RPM_BUILD_ROOT%{_mandir}/man8/%{name}.8
+install %{SOURCE1} $RPM_BUILD_ROOT/etc/efi-boot
+install %{SOURCE2} %{SOURCE3} %{SOURCE4} $RPM_BUILD_ROOT/etc/efi-boot/update.d
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+# Most efi-boot-update-managed loaders will use kernel files
+# even if the kernel itself is not build as EFI
+%triggerin -- kernel
+/sbin/efi-boot-update
+%triggerin -- kernel-longterm
+/sbin/efi-boot-update
+
+%files
+%defattr(644,root,root,755)
+%doc README TODO
+%attr(755,root,root) %{_sbindir}/%{name}
+%dir /etc/efi-boot
+%config(noreplace) %verify(not md5 mtime size) /etc/efi-boot/update.conf
+%config(noreplace) %verify(not md5 mtime size) /etc/efi-boot/update.d/*.conf
+%dir /etc/efi-boot/update.d
+%dir %{_libdir}/efi
+%if "%{_libdir}" != "%{_prefix}/lib"
+%dir %{_prefix}/lib/efi
+%endif
+%{_mandir}/man8/%{name}.8*
diff --git a/grub.conf b/grub.conf
new file mode 100644 (file)
index 0000000..1be3694
--- /dev/null
+++ b/grub.conf
@@ -0,0 +1,54 @@
+#
+# This is disabled by default, as GRUB does good job by itself
+#
+# This is rather a proof-of-concept example how such things can be implemented
+# here.
+#
+
+ENABLED=no
+LABEL=GRUB
+ARCH=x86_64
+BINARY=grub.efi
+
+GRUB_EXTRA_MODULES=""
+
+install_files() {
+    local target
+    local module
+    local modules
+    local final_modules
+    local drive
+    local prefix
+
+    modules=""
+    modules="$modules $(/sbin/grub-probe --target=fs /boot)"
+    modules="$modules $(/sbin/grub-probe --target=abstraction /boot)"
+    modules="$modules part_$(/sbin/grub-probe --target=partmap /boot)"
+    modules="$modules search_fs_file search_fs_uuid"
+    modules="$modules $GRUB_EXTRA_MODULES"
+    drive="$(/sbin/grub-probe --target=drive /boot)"
+
+    if [ "$ARCH" = "x86_64" ] ; then
+        target="x86_64-efi"
+    else
+        target="i386-efi"
+    fi
+
+    if /bin/mountpoint -q /boot  ; then
+        prefix="$drive/grub"
+    else
+        prefix="$drive/boot/grub"
+    fi
+
+    final_modules=""
+    for module in $modules ; do
+        [ -e "/lib/grub/$target/$module.mod" ] && final_modules="$final_modules $module"
+    done
+
+    is_yes $VERBOSE && set -x
+    /sbin/grub-mkimage -O "$target" -d /lib/grub/$target \
+                --output=$DESTDIR/grub.efi \
+                --prefix="$prefix" $final_modules
+}
+
+# vi: ft=sh
diff --git a/shellx32.conf b/shellx32.conf
new file mode 100644 (file)
index 0000000..49f4c9c
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Configure a 32-bit EFI Shell as a boot option
+#
+# Note: most UEFI systems are 64-bit, so shellx64 is the right choice
+#
+# The shell can be obtained from: 
+#    https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2/ShellBinPkg/UefiShell/Ia32/Shell.efi
+#
+# And should be manually placed at /boot/efi/EFI/SHELLX32.EFI
+#
+ENABLED=no
+LABEL="EFI Shell"
+BINARY=/EFI/SHELLX32.EFI
diff --git a/shellx64.conf b/shellx64.conf
new file mode 100644 (file)
index 0000000..00b7bfb
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Configure an EFI Shell as a boot option
+#
+# The shell can be obtained from: 
+#    https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2/ShellBinPkg/UefiShell/X64/Shell.efi
+#
+# And should be manually placed at /boot/efi/EFI/SHELLX64.EFI
+#
+ENABLED=yes
+LABEL="EFI Shell"
+BINARY=/EFI/SHELLX64.EFI
diff --git a/update.conf b/update.conf
new file mode 100644 (file)
index 0000000..4289c6b
--- /dev/null
@@ -0,0 +1,3 @@
+LABEL_PREFIX="PLD "
+ORDER="grub shellx64"
+PLATFORM_DIR="pld-linux/@ARCH@"
diff --git a/xen.conf b/xen.conf
new file mode 100644 (file)
index 0000000..5a4876d
--- /dev/null
+++ b/xen.conf
@@ -0,0 +1,17 @@
+ENABLED=yes
+LABEL="Xen native EFI"
+ARCH=x86_64
+BINARY=xen.efi
+ARGS=""
+
+install_files() {
+
+    update_file /usr/lib64/efi/xen.efi xen.efi
+    update_file /etc/efi-boot/xen.cfg xen.cfg
+
+    update_file /boot/kernel-axeos-initrd kernel-axeos-initrd
+    update_file /boot/kernel-axeos-vmlinuz kernel-axeos-vmlinuz
+
+    update_file --missingok /boot/kernel-axeos-initrd.old kernel-axeos-initrd.old
+    update_file --missingok /boot/kernel-axeos-vmlinuz.old kernel-axeos-vmlinuz.old
+}
This page took 0.152652 seconds and 4 git commands to generate.