[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH] add UEFI support to os-prober



It seems that Windows sometimes installs legacy bootloader even on UEFI
systems. This causes os-prober to put chainload entry for legacy boot in
grub2 menu, which fails to boot on UEFI.

Attached are suggested patches, which

- skip legacy MS loader detection on UEFI platform
- add framework for searching EFI System Partition
- add scripts that detect Microsoft bootloader and ELILO (Agnelo).

These scripts need patched for 30_os-prober (attached).

Patches are included in unofficial os-prober package for openSUSE
maintained by Agnelo and tested on UEFI systems.

Thank you

-andrey
Index: b/os-probes/mounted/x86/20microsoft
===================================================================
--- a/os-probes/mounted/x86/20microsoft
+++ b/os-probes/mounted/x86/20microsoft
@@ -7,6 +7,12 @@ partition="$1"
 mpoint="$2"
 type="$3"
 
+# This script looks for legacy BIOS bootloaders only. Skip if running UEFI
+if [ -d /sys/firmware/efi ]; then
+	debug "Skipping legacy bootloaders on UEFI system"
+	exit 1
+fi
+
 # Weed out stuff that doesn't apply to us
 case "$type" in
 	ntfs|ntfs-3g) debug "$1 is a NTFS partition" ;;
Index: os-prober-1.56/os-probes/mounted/x86/05efi
===================================================================
--- /dev/null	2012-10-10 10:42:25.367517060 -0700
+++ os-prober-1.56/os-probes/mounted/x86/05efi	2012-10-10 16:29:49.000000000 -0700
@@ -0,0 +1,70 @@
+#!/bin/sh
+# Detects all Microsoft OSes on a collection of partitions.
+
+. /usr/share/os-prober/common.sh
+
+partition="$1"
+mpoint="$2"
+type="$3"
+
+# This file is for UEFI platform only
+if [ ! -d /sys/firmware/efi ]; then
+	debug "Not on UEFI platform"
+	exit 1
+fi
+
+# Weed out stuff that doesn't apply to us
+case "$type" in
+	vfat) debug "$1 is a FAT32 partition" ;;
+	msdos) debug "$1 is a FAT16 partition" ;;
+	*) debug "$1 is $type partition: exiting"; exit 1 ;;
+esac
+
+if type udevadm > /dev/null 2>&1; then
+	udevinfo () {
+		udevadm info "$@"
+	}
+fi
+
+if type udevinfo > /dev/null 2>&1; then
+	# Skip virtual devices
+	if udevinfo -q path -n $partition | grep -q /virtual/; then
+		debug "$1 is virtual device: exiting"
+		exit 1
+	fi
+
+	eval "$(udevinfo -q property -n "$partition" | grep -E '^ID_PART_ENTRY_(TYPE|SCHEME)=')"
+	debug "$partition partition scheme is $ID_PART_ENTRY_SCHEME"
+	debug "$partition partition type is $ID_PART_ENTRY_TYPE"
+
+	if [ -z "$ID_PART_ENTRY_TYPE" -o -z "$ID_PART_ENTRY_SCHEME" -o \
+		\( "$ID_PART_ENTRY_SCHEME" != gpt -a "$ID_PART_ENTRY_SCHEME" != msdos \) -o \
+		\( "$ID_PART_ENTRY_SCHEME" = gpt -a "$ID_PART_ENTRY_TYPE" != c12a7328-f81f-11d2-ba4b-00a0c93ec93b \) -o \
+		\( "$ID_PART_ENTRY_SCHEME" = msdos -a "$ID_PART_ENTRY_TYPE" != 0xef \) ]; then
+		debug "$partition is not a ESP partition: exiting"
+		exit 1
+	fi
+else
+	debug "udevinfo and udevadm missing - cannot check partition type"
+fi
+
+efi=$(item_in_dir efi "$mpoint")
+if [ -z "$efi" ]; then
+	debug "$mpoint does not have /EFI directory: exiting"
+	exit 1
+fi
+
+ret=1
+for test in /usr/lib/os-probes/mounted/efi/*; do
+	debug "running subtest $test"
+	if [ -f "$test" ] && [ -x "$test" ]; then
+		entry=$("$test" "$mpoint/$efi")
+		if [ -n "$entry" ]; then
+			debug "bootloader $entry found by subtest $test"
+			ret=0
+			result "${partition}@/$efi/${entry}:efi"
+		fi
+	fi
+done
+
+exit $ret
Index: os-prober-1.56/os-probes/mounted/x86/efi/20microsoft
===================================================================
--- /dev/null	2012-10-10 10:42:25.367517060 -0700
+++ os-prober-1.56/os-probes/mounted/x86/efi/20microsoft	2012-10-10 16:29:49.000000000 -0700
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Detects Microsoft bootloader on a EFI System Partition
+
+. /usr/share/os-prober/common.sh
+
+efi="$1"
+
+found=
+for microsoft in $(item_in_dir microsoft "$efi"); do
+	for boot in $(item_in_dir boot "$efi/$microsoft"); do
+		bcd=$(item_in_dir bcd "$efi/$microsoft/$boot")
+		bootmgfw=$(item_in_dir bootmgfw.efi "$efi/$microsoft/$boot")
+		if [ -n "$bcd" -a -n "$bootmgfw" ]; then
+			long="Windows Boot Manager"
+			short=Windows
+			path="$microsoft/$boot/$bootmgfw"
+			found=true
+			break
+		fi
+	done
+done
+
+
+if [ -n "$found" ]; then
+	label="$(count_next_label "$short")"
+	result "${path}:${long}:${label}"
+fi
+exit 0
Index: os-prober-1.56/os-probes/mounted/x86/efi/10elilo
===================================================================
--- /dev/null	2012-10-10 10:42:25.367517060 -0700
+++ os-prober-1.56/os-probes/mounted/x86/efi/10elilo	2012-10-10 18:28:55.000000000 -0700
@@ -0,0 +1,24 @@
+#!/bin/sh
+# Detects ELILO bootloader on a EFI System Partition
+
+. /usr/share/os-prober/common.sh
+
+efi="$1"
+
+found=
+
+elilo=`find $1 -name "elilo.efi"`
+if [ -n "$elilo" ]; then
+	bdir=`dirname $elilo`
+	bdir=`basename $bdir`
+	long="ELILO Boot Manager"
+	short="ELILO"
+	path=${bdir}/elilo.efi
+	found=true
+fi  
+
+if [ -n "$found" ]; then
+	label="$(count_next_label "$short")"
+	result "${path}:${long}:${label}"
+fi
+exit 0
--- /etc/grub.d/30_os-prober.orig	2012-09-28 22:12:51.047085849 +0400
+++ /etc/grub.d/30_os-prober	2012-09-29 18:35:25.949036128 +0400
@@ -144,6 +144,22 @@ EOF
 }
 EOF
     ;;
+    efi)
+
+	EFIPATH=${DEVICE#*@}
+	DEVICE=${DEVICE%@*}
+	onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+      cat << EOF
+menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class windows --class os \$menuentry_id_option 'osprober-efi-$(grub_get_device_id "${DEVICE}")' {
+EOF
+      save_default_entry | sed -e "s/^/\t/"
+      prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/"
+
+      cat <<EOF
+	chainloader ${EFIPATH}
+}
+EOF
+    ;;
     linux)
       LINUXPROBED="`linux-boot-prober ${DEVICE} 2> /dev/null | tr ' ' '^' | paste -s -d ' '`"
       prepare_boot_cache=

Reply to: