From 1d03e2f5da5b37ace2b442530550d1b237423069 Mon Sep 17 00:00:00 2001 From: overweight <5324761+overweight@user.noreply.gitee.com> Date: Mon, 30 Sep 2019 11:11:10 -0400 Subject: [PATCH] Package init --- ...-for-device-mapper-device-is-created.patch | 46 ++ os-prober-bootpart-name-fix.patch | 29 ++ os-prober-btrfsfix.patch | 472 ++++++++++++++++++ os-prober-factor-out-logger.patch | 107 ++++ os-prober-factored-logger-efi-fix.patch | 16 + os-prober-gentoo-fix.patch | 13 + os-prober-grepfix.patch | 13 + os-prober-grub2-parsefix.patch | 22 + os-prober-mdraidfix.patch | 25 + os-prober-mounted-partitions-fix.patch | 26 + os-prober-no-dummy-mach-kernel.patch | 22 + os-prober-umount-fix.patch | 18 + os-prober.spec | 97 ++++ os-prober_1.74.tar.xz | Bin 0 -> 26692 bytes 14 files changed, 906 insertions(+) create mode 100644 bugfix-wait-for-device-mapper-device-is-created.patch create mode 100644 os-prober-bootpart-name-fix.patch create mode 100644 os-prober-btrfsfix.patch create mode 100644 os-prober-factor-out-logger.patch create mode 100644 os-prober-factored-logger-efi-fix.patch create mode 100644 os-prober-gentoo-fix.patch create mode 100644 os-prober-grepfix.patch create mode 100644 os-prober-grub2-parsefix.patch create mode 100644 os-prober-mdraidfix.patch create mode 100644 os-prober-mounted-partitions-fix.patch create mode 100644 os-prober-no-dummy-mach-kernel.patch create mode 100644 os-prober-umount-fix.patch create mode 100644 os-prober.spec create mode 100644 os-prober_1.74.tar.xz diff --git a/bugfix-wait-for-device-mapper-device-is-created.patch b/bugfix-wait-for-device-mapper-device-is-created.patch new file mode 100644 index 0000000..9a00dc5 --- /dev/null +++ b/bugfix-wait-for-device-mapper-device-is-created.patch @@ -0,0 +1,46 @@ +From 4811d40604f58696ddd738cea336d3af53248329 Mon Sep 17 00:00:00 2001 +From: Wang shuo +Date: Thu, 20 Jun 2019 11:17:28 +0800 +Subject: [PATCH] os-prober: wait for device mapper device is created + +reason: wait for device mapper device is created + +Signed-off-by: Wang shuo +--- + common.sh | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/common.sh b/common.sh +index 8030efa..0980208 100644 +--- a/common.sh ++++ b/common.sh +@@ -225,9 +225,11 @@ find_uuid () { + + do_dmsetup () { + local prefix partition dm_device partition_name size_p ++ local int + prefix="$1" + partition="$2" + dm_device= ++ int=1 + + if type dmsetup >/dev/null 2>&1 && \ + type blockdev >/dev/null 2>&1; then +@@ -240,6 +242,14 @@ do_dmsetup () { + else + debug "creating device mapper device $dm_device" + echo "0 $size_p linear $partition 0" | dmsetup create -r $partition_name ++ while(( $int<=3 )) ++ do ++ if [ -e "$dm_device" ]; then ++ break ++ fi ++ let "int++" ++ sleep 1 ++ done + fi + fi + echo "$dm_device" +-- +2.19.1 + diff --git a/os-prober-bootpart-name-fix.patch b/os-prober-bootpart-name-fix.patch new file mode 100644 index 0000000..40a909d --- /dev/null +++ b/os-prober-bootpart-name-fix.patch @@ -0,0 +1,29 @@ +Index: os-prober/common.sh +=================================================================== +--- os-prober.orig/common.sh ++++ os-prober/common.sh +@@ -269,7 +269,7 @@ linux_mount_boot () { + if [ "$bindfrom" != "$tmpmnt/boot" ]; then + if mount --bind "$bindfrom" "$tmpmnt/boot"; then + mounted=1 +- bootpart="$1" ++ bootpart="$tmppart" + else + debug "failed to bind-mount $bindfrom onto $tmpmnt/boot" + fi +@@ -277,6 +277,15 @@ linux_mount_boot () { + fi + if [ "$mounted" ]; then + : ++ elif [ -e "$tmppart" ]; then ++ bootpart="$tmppart" ++ boottomnt="$tmppart" ++ elif [ -e "$tmpmnt/$tmppart" ]; then ++ bootpart="$tmppart" ++ boottomnt="$tmpmnt/$tmppart" ++ elif [ -e "/target/$tmppart" ]; then ++ bootpart="$tmppart" ++ boottomnt="/target/$tmppart" + elif [ -e "$1" ]; then + bootpart="$1" + boottomnt="$1" diff --git a/os-prober-btrfsfix.patch b/os-prober-btrfsfix.patch new file mode 100644 index 0000000..1047d24 --- /dev/null +++ b/os-prober-btrfsfix.patch @@ -0,0 +1,472 @@ +diff --git a/common.sh b/common.sh +index c2c5f46..8fb3c5f 100644 +--- a/common.sh ++++ b/common.sh +@@ -155,6 +155,7 @@ parse_proc_mounts () { + done + } + ++# add forth parameter to pickup btrfs subvol info + parsefstab () { + while read -r line; do + case "$line" in +@@ -165,12 +166,22 @@ parsefstab () { + set -f + set -- $line + set +f +- printf '%s %s %s\n' "$1" "$2" "$3" ++ printf '%s %s %s %s\n' "$1" "$2" "$3" "$4" + ;; + esac + done + } + ++#check_btrfs_mounted $bootsv $bootuuid) ++check_btrfs_mounted () { ++ bootsv="$1" ++ bootuuid="$2" ++ bootdev=$(blkid | grep "$bootuuid" | cut -d ':' -f 1) ++ bindfrom=$(grep " btrfs " /proc/self/mountinfo | ++ grep " $bootdev " | grep " /$bootsv " | cut -d ' ' -f 5) ++ printf "%s" "$bindfrom" ++} ++ + unescape_mount () { + printf %s "$1" | \ + sed 's/\\011/ /g; s/\\012/\n/g; s/\\040/ /g; s/\\134/\\/g' +diff --git a/linux-boot-prober b/linux-boot-prober +index e32dc84..2a60fa2 100755 +--- a/linux-boot-prober ++++ b/linux-boot-prober +@@ -5,16 +5,143 @@ set -e + + newns "$@" + require_tmpdir ++ERR="n" ++ ++tmpmnt=/var/lib/os-prober/mount ++if [ ! -d "$tmpmnt" ]; then ++ mkdir "$tmpmnt" ++fi ++ ++mounted= ++bootmnt= ++bootsv= ++bootuuid= + + grep "^/dev/" /proc/mounts | parse_proc_mounts >"$OS_PROBER_TMP/mounted-map" || true + +-partition="$1" ++if [ -z "$1" ]; then ++ ERR=y ++elif [ "$1" = btrfs -a -z "$2" ]; then ++ ERR=y ++elif [ "$1" = btrfs -a -z "$3" ]; then ++ ERR=y ++elif [ "$1" = btrfs ]; then ++ type=btrfs ++ echo "$2" | grep -q "^UUID=" || ERR=y ++ echo "$3" | grep -q "^subvol=" || ERR=y ++ export "$2" ++ export "$3" ++ partition=$(blkid | grep "$UUID" | cut -d ':' -f 1 | tr '\n' ' ' | cut -d ' ' -f 1) ++ debug "btrfs: partition=$partition, UUID=$UUID, subvol=$subvol" ++else ++ partition="$1" ++ type=other ++fi + +-if [ -z "$partition" ]; then ++if [ "x$ERR" != xn ]; then + echo "usage: linux-boot-prober partition" >&2 ++ echo " linux-boot-prober btrfs UUID=<> subvol=<>" >&2 + exit 1 + fi + ++if [ "$type" = btrfs ]; then ++ # handle all of the btrfs stuff here ++ if [ ! -e "/proc/self/mountinfo" ]; then ++ warn "/proc/self/mountinfo does not exist, exiting" ++ umount "$tmpmnt" 2>/dev/null ++ rmdir "$tmpmnt" 2>/dev/null ++ exit 1 ++ fi ++ mpoint=$(grep "btrfs" /proc/self/mountinfo | grep " /$subvol " | grep " $partition " | cut -d ' ' -f 5) ++ if [ "$mpoint" = "/" ]; then ++ warn "specifying active root not valid, exiting" ++ umount "$tmpmnt" 2>/dev/null ++ rmdir "$tmpmnt" 2>/dev/null ++ exit 1 ++ fi ++ if [ "$mpoint" = "$tmpmnt" ]; then ++ warn "btrfs subvol=$subvool, UUID=$UUID, already mounted on $tmpmnt **ERROR**" ++ umount "$tmpmnt" 2>/dev/null ++ rmdir "$tmpmnt" 2>/dev/null ++ exit 1 ++ fi ++ if [ -z "$mpoint" ]; then ++ # mount the btrfs root ++ if ! mount -o subvol=$subvol -t btrfs -U $UUID "$tmpmnt" 2>/dev/null; then ++ warn "error mounting btrfs subvol=$subvol UUID=$UUID" ++ umount "$tmpmnt/boot" 2>/dev/null ++ umount "$tmpmnt" 2>/dev/null ++ rmdir "$tmpmnt" 2>/dev/null ++ exit 1 ++ fi ++ else ++ # bind-mount ++ if ! mount -o bind "$mpoint" "$tmpmnt" 2>/dev/null; then ++ warn "error mounting btrfs bindfrom=$mpoint subvol=$subvol UUID=$UUID" ++ umount "$tmpmnt/boot" 2>/dev/null ++ umount "$tmpmnt" 2>/dev/null ++ rmdir "$tmpmnt" 2>/dev/null ++ exit 1 ++ fi ++ fi ++ debug "mounted btrfs $partition, subvol=$subvol on $tmpmnt" ++ if [ ! -e "$tmpmnt/etc/fstab" ]; then ++ warn "btrfs subvol=$subvol not root" ++ umount "$tmpmnt" 2>/dev/null ++ rmdir "$tmpmnt" 2>/dev/null ++ exit 1 ++ fi ++ bootmnt=$(parsefstab < "$tmpmnt/etc/fstab" | grep " /boot ") || true ++ if [ -z "$bootmnt" ]; then ++ # /boot is part of the root ++ bootpart="$partition" ++ bootsv="$subvol" ++ elif echo "$bootmnt" | cut -d ' ' -f 3 | grep -q "btrfs"; then ++ # separate btrfs /boot subvolume ++ bootsv=$(echo "$bootmnt" | cut -d ' ' -f 4 | grep "^subvol=" | sed "s/subvol=//" ) ++ bootuuid=$(echo "$bootmnt" | cut -d ' ' -f 1 | grep "^UUID=" | sed "s/UUID=//" ) ++ debug "mounting btrfs $tmpmnt/boot UUID=$bootuuid subvol=$bootsv" ++ bindfrom=$(check_btrfs_mounted $bootsv $bootuuid) ++ if [ -n "$bindfrom" ]; then ++ # already mounted some place ++ if ! mount -o bind $bindfrom "$tmpmnt/boot" 2>/dev/null; then ++ warn "error bind mounting btrfs boot subvol=$bootsv, from=$bindfrom" ++ umount "$tmpmnt/boot" 2>/dev/null ++ umount "$tmpmnt" 2>/dev/null ++ rmdir "$tmpmnt" 2>/dev/null ++ exit 1 ++ fi ++ elif ! mount -o subvol=$bootsv -t btrfs -U $bootuuid "$tmpmnt/boot" 2>/dev/null; then ++ warn "error mounting btrfs boot partition subvol=$bootsv, UUID=$bootuuid" ++ umount "$tmpmnt/boot" 2>/dev/null ++ umount "$tmpmnt" 2>/dev/null ++ rmdir "$tmpmnt" 2>/dev/null ++ exit 1 ++ fi ++ bootpart=$(grep " btrfs " /proc/self/mountinfo | grep " /$bootsv " | cut -d ' ' -f 10) ++ else ++ # non-btrfs partition or logical volume ++ linux_mount_boot $partition $tmpmnt ++ bootpart="${mountboot%% *}" ++ bootsv= ++ fi ++ ++ test="/usr/lib/linux-boot-probes/mounted/40grub2" ++ if [ -f $test ] && [ -x $test ]; then ++ debug "running $test $partition $bootpart $tmpmnt $type $subvol $bootsv" ++ if $test "$partition" "$bootpart" "$tmpmnt" "$type" "$subvol" "$bootsv"; then ++ debug "$test succeeded" ++ fi ++ fi ++ umount "$tmpmnt/boot" 2>/dev/null || true ++ if ! umount "$tmpmnt" 2>/dev/null; then ++ warn "problem umount $tmpmnt" ++ fi ++ rmdir "$tmpmnt" 2>/dev/null || true ++ ++ exit 0 ++fi ++ + if ! mapped="$(mapdevfs "$partition")"; then + log "Device '$partition' does not exist; skipping" + continue +@@ -22,8 +149,8 @@ fi + + if ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map"; then + for test in /usr/lib/linux-boot-probes/*; do +- debug "running $test" + if [ -x $test ] && [ -f $test ]; then ++ debug "running $test" + if $test "$partition"; then + debug "linux detected by $test" + break +diff --git a/linux-boot-probes/mounted/common/40grub2 b/linux-boot-probes/mounted/common/40grub2 +index 885614e..db5cbfd 100755 +--- a/linux-boot-probes/mounted/common/40grub2 ++++ b/linux-boot-probes/mounted/common/40grub2 +@@ -2,17 +2,30 @@ + . /usr/share/os-prober/common.sh + set -e + ++# add support for btrfs with no separate /boot ++# that is, rootsv = bootsv + partition="$1" + bootpart="$2" + mpoint="$3" + type="$4" ++rootsv="$5" ++bootsv="$6" + + found_item=0 + + entry_result () { ++ if [ "x$type" = "xbtrfs" -a "$partition" = "$bootpart" ]; then ++ # trim off the leading subvol ++ kernelfile=$(echo "$kernel" | cut -d '/' -f 2- | cut -d '/' -f 2-) ++ if [ "x$rootsv" != "x$bootsv" ]; then ++ kernelfile="/boot/$kernelfile" ++ fi ++ else ++ kernelfile=$kernel ++ fi + if [ "$ignore_item" = 0 ] && \ + [ -n "$kernel" ] && \ +- [ -e "$mpoint/$kernel" ]; then ++ [ -e "$mpoint/$kernelfile" ]; then + result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters" + found_item=1 + fi +diff --git a/os-prober b/os-prober +index 8852887..482c3c2 100755 +--- a/os-prober ++++ b/os-prober +@@ -76,9 +76,12 @@ partitions () { + + # Also detect OSes on LVM volumes (assumes LVM is active) + if type lvs >/dev/null 2>&1; then +- echo "$(LVM_SUPPRESS_FD_WARNINGS=1 log_output lvs --noheadings --separator : -o vg_name,lv_name | ++ echo "$(LVM_SUPPRESS_FD_WARNINGS=1 log_output lvs --noheadings --separator : -o vg_name,lv_name 2>/dev/null | + sed "s|-|--|g;s|^[[:space:]]*\(.*\):\(.*\)$|/dev/mapper/\1-\2|")" + fi ++ ++ # now lets make sure we got all of the btrfs partitions and disks ++ blkid | grep 'TYPE="btrfs"' | cut -d ':' -f 1 + } + + parse_proc_swaps () { +@@ -136,6 +139,8 @@ if [ -f /proc/mdstat ] ; then + grep "^md" /proc/mdstat | cut -d: -f2- | parse_proc_mdstat >"$OS_PROBER_TMP/raided-map" || true + fi + ++: >"$OS_PROBER_TMP/btrfs-vols" ++ + for partition in $(partitions); do + if ! mapped="$(mapdevfs "$partition")"; then + log "Device '$partition' does not exist; skipping" +@@ -154,7 +159,26 @@ for partition in $(partitions); do + continue + fi + +- if ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map" ; then ++ # do btrfs processing here; both mounted and unmounted will ++ # be handled by 50mounted-tests so we can do a subvol only once. ++ type=$(blkid -o value -s TYPE $mapped || true) ++ if [ "$type" = btrfs ]; then ++ uuid=$(blkid -o value -s UUID $mapped) ++ if grep -q "^$uuid" "$OS_PROBER_TMP/btrfs-vols" ; then ++ continue ++ fi ++ debug "btrfs volume uuid=$uuid partition=$partition" ++ echo "$uuid" >>"$OS_PROBER_TMP/btrfs-vols" ++ test="/usr/lib/os-probes/50mounted-tests" ++ if [ -f "$test" ] && [ -x "$test" ]; then ++ debug "running $test on btrfs $partition" ++ if "$test" btrfs "$uuid" "$partition"; then ++ debug "os detected by $test" ++ continue ++ fi ++ fi ++ ++ elif ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map" ; then + for test in /usr/lib/os-probes/*; do + if [ -f "$test" ] && [ -x "$test" ]; then + debug "running $test on $partition" +diff --git a/os-probes/common/50mounted-tests b/os-probes/common/50mounted-tests +index 2951ef9..e33eb82 100755 +--- a/os-probes/common/50mounted-tests ++++ b/os-probes/common/50mounted-tests +@@ -19,19 +19,31 @@ do_unmount() { + rmdir "$tmpmnt" || true + } + +-types="$(fs_type "$partition")" ++if [ "x$1" = xbtrfs ]; then ++ types=btrfs ++ if [ -z "$2" -o -z "$3" ]; then ++ debug "missing btrfs parameters, exiting" ++ exit 1 ++ fi ++ UUID="$2" ++ BTRFSDEV="$3" ++else ++ partition="$1" ++ types="$(fs_type "$partition")" || types=NOT-DETECTED ++fi ++ + if [ "$types" = NOT-DETECTED ]; then + debug "$1 type not recognised; skipping" +- exit 0 ++ exit 1 + elif [ "$types" = swap ]; then + debug "$1 is a swap partition; skipping" +- exit 0 ++ exit 1 + elif [ "$types" = crypto_LUKS ]; then + debug "$1 is a LUKS partition; skipping" +- exit 0 ++ exit 1 + elif [ "$types" = LVM2_member ]; then + debug "$1 is an LVM member; skipping" +- exit 0 ++ exit 1 + elif [ "$types" = ntfs ]; then + if type ntfs-3g >/dev/null 2>&1; then + types='ntfs-3g ntfs' +@@ -40,7 +52,7 @@ elif [ -z "$types" ]; then + if type cryptsetup >/dev/null 2>&1 && \ + cryptsetup luksDump "$partition" >/dev/null 2>&1; then + debug "$1 is a LUKS partition; skipping" +- exit 0 ++ exit 1 + fi + for type in $(grep -v nodev /proc/filesystems); do + # hfsplus filesystems are mountable as hfs. Try hfs last so +@@ -63,6 +75,108 @@ if [ ! -d "$tmpmnt" ]; then + fi + + mounted= ++ ++# all btrfs processing here. Handle both unmounted and ++# mounted subvolumes. ++if [ "$types" = btrfs ]; then ++ partition="$BTRFSDEV" ++ debug "begin btrfs processing for $UUID" ++ # note that the btrfs volume must not be mounted ro ++ if mount -t btrfs -U "$UUID" "$tmpmnt" 2>/dev/null; then ++ debug "btrfs volume $UUID mounted" ++ else ++ warn "cannot mount btrfs volume $UUID, exiting" ++ rmdir "$tmpmnt" || true ++ exit 1 ++ fi ++ # besides regular subvols, get ro and snapshot so thet can be excluded ++ subvols=$(btrfs subvolume list "$tmpmnt" | cut -d ' ' -f 9) ++ rosubvols=$(btrfs subvolume list -r "$tmpmnt" | cut -d ' ' -f 9) ++ sssubvols=$(btrfs subvolume list -s "$tmpmnt" | cut -d ' ' -f 14) ++ if ! umount "$tmpmnt"; then ++ warn "failed to umount btrfs volume on $tmpmnt" ++ rmdir "$tmpmnt" || true ++ exit 1 ++ fi ++ ++ found= ++ mounted= ++ ++ mpoint="$(grep btrfs /proc/self/mountinfo | grep "$partition " | cut -d ' ' -f 5)" ++ if [ -n "$mpoint" -a "x$mpoint" = "x/" ]; then ++ debug "This is the root for the running system" #running system must be done elsewhere ++ else ++ #partition was not root of running system, so lets look for bootable subvols ++ if [ -n "$mpoint" ] ; then ++ mounted=1 #partition was already mounted,so lets not unmount it when done ++ else ++ # again, do not mount btrfs ro ++ mount -t btrfs -U "$UUID" "$tmpmnt" ++ mpoint="$tmpmnt" ++ fi ++ ++ test="/usr/lib/os-probes/mounted/90linux-distro" ++ if [ -f "$test" ] && [ -x "$test" ]; then ++ debug "running subtest $test" ++ if "$test" "$partition" "$mpoint" btrfs "UUID=$UUID"; then ++ debug "os found by subtest $test on $partition" ++ found=1 ++ fi ++ fi ++ if [ -z "$mounted" ]; then ++ if ! umount "$tmpmnt"; then ++ warn "failed to umount $tmpmnt" ++ fi ++ fi ++ fi ++ ++ if [ -z "$subvols" ]; then ++ debug "no subvols found on btrfs volume $UUID" ++ else ++ found= ++ for subvol in $subvols; do ++ debug "begin btrfs processing for $UUID subvol=$subvol" ++ if echo "$rosubvols" | grep -q -x "$subvol"; then ++ continue ++ fi ++ if echo "$sssubvols" | grep -q -x "$subvol"; then ++ continue ++ fi ++ mounted= ++ mpoint="$(grep btrfs /proc/self/mountinfo | grep "$partition " | grep "/$subvol " | cut -d ' ' -f 5)" ++ if [ -n "$mpoint" ]; then ++ if [ "x$mpoint" = "x/" ]; then ++ continue # this is the root for the running system ++ fi ++ mounted=1 ++ else ++ # again, do not mount btrfs ro ++ mount -t btrfs -o subvol="$subvol" -U "$UUID" "$tmpmnt" ++ mpoint="$tmpmnt" ++ fi ++ test="/usr/lib/os-probes/mounted/90linux-distro" ++ if [ -f "$test" ] && [ -x "$test" ]; then ++ debug "running subtest $test" ++ if "$test" "$partition" "$mpoint" btrfs "UUID=$UUID" "subvol=$subvol"; then ++ debug "os found by subtest $test on subvol $subvol" ++ found=1 ++ fi ++ fi ++ if [ -z "$mounted" ]; then ++ if ! umount "$tmpmnt"; then ++ warn "failed to umount $tmpmnt" ++ fi ++ fi ++ done ++ fi ++ rmdir "$tmpmnt" || true ++ if [ "$found" ]; then ++ exit 0 ++ else ++ exit 1 ++ fi ++fi ++ + if type grub-mount >/dev/null 2>&1 && \ + type grub-probe >/dev/null 2>&1 && \ + grub-mount "$partition" "$tmpmnt" 2>/dev/null; then +diff --git a/os-probes/mounted/common/90linux-distro b/os-probes/mounted/common/90linux-distro +index badfbb1..9bc5154 100755 +--- a/os-probes/mounted/common/90linux-distro ++++ b/os-probes/mounted/common/90linux-distro +@@ -7,6 +7,8 @@ set -e + partition="$1" + dir="$2" + type="$3" ++uuid="$4" ++subvol="$5" + + # This test is inaccurate, but given separate / and /boot partitions and the + # fact that only some architectures have ld-linux.so, I can't see anything +@@ -143,7 +145,11 @@ if (ls "$dir"/lib*/ld*.so* && [ -d "$dir/boot" ] || ls "$dir"/usr/lib*/ld*.so*) + fi + + label="$(count_next_label "$short")" +- result "$partition:$long:$label:linux" ++ if [ "x$type" = "xbtrfs" -a "x$uuid" != "x" -a "x$subvol" != "x" ]; then ++ result "$partition:$long:$label:linux:$type:$uuid:$subvol" ++ else ++ result "$partition:$long:$label:linux" ++ fi + exit 0 + else + exit 1 diff --git a/os-prober-factor-out-logger.patch b/os-prober-factor-out-logger.patch new file mode 100644 index 0000000..52cb7ce --- /dev/null +++ b/os-prober-factor-out-logger.patch @@ -0,0 +1,107 @@ +Index: os-prober/common.sh +=================================================================== +--- os-prober.orig/common.sh ++++ os-prober/common.sh +@@ -62,10 +62,14 @@ cache_progname() { + esac + } + +-log() { +- cache_progname +- logger -t "$progname" "$@" +-} ++# fd_logger: bind value now, possibly after assigning default. ++eval ' ++ log() { ++ cache_progname ++ echo "$progname: $@" 1>&'${fd_logger:=9}' ++ } ++' ++export fd_logger # so subshells inherit current value by default + + error() { + log "error: $@" +@@ -81,10 +85,14 @@ debug() { + fi + } + +-result () { +- log "result:" "$@" +- echo "$@" +-} ++# fd_result: bind value now, possibly after assigning default. ++eval ' ++ result() { ++ log "result:" "$@" ++ echo "$@" 1>&'${fd_result:=1}' ++ } ++' ++export fd_result # so subshells inherit current value by default + + # shim to make it easier to use os-prober outside d-i + if ! type mapdevfs >/dev/null 2>&1; then +Index: os-prober/linux-boot-prober +=================================================================== +--- os-prober.orig/linux-boot-prober ++++ os-prober/linux-boot-prober +@@ -1,4 +1,12 @@ + #!/bin/sh ++ ++# dash shell does not have "{varname}>&1" feature that bash shell has ++# for auto-assignment of new filedescriptors. ++# It is cumbersome to write the 'eval' to use our own variables in redirections. ++# Therefore use fixed numbers. ++export fd_result=3 # file descriptor for external results ++export fd_logger=9 # file descriptor for input to logger ++ + . /usr/share/os-prober/common.sh + + set -e +@@ -19,6 +27,7 @@ bootuuid= + + grep "^/dev/" /proc/mounts | parse_proc_mounts >"$OS_PROBER_TMP/mounted-map" || true + ++( ( + if [ -z "$1" ]; then + ERR=y + elif [ "$1" = btrfs -a -z "$2" ]; then +@@ -186,3 +195,5 @@ else + fi + fi + fi ++) 9>&1 | logger 1>&- # fd_logger ++) 3>&1 # fd_result +Index: os-prober/os-prober +=================================================================== +--- os-prober.orig/os-prober ++++ os-prober/os-prober +@@ -1,7 +1,14 @@ + #!/bin/sh + set -e + +-. /usr/share/os-prober/common.sh ++# dash shell does not have "{varname}>&1" feature that bash shell has ++# for auto-assignment of new filedescriptors. ++# It is cumbersome to write the 'eval' to use our own variables in redirections. ++# Therefore use fixed numbers. ++export fd_result=3 # file descriptor for external results ++export fd_logger=9 # file descriptor for input to logger ++ ++ . /usr/share/os-prober/common.sh + + newns "$@" + require_tmpdir +@@ -136,6 +143,7 @@ fi + + : >"$OS_PROBER_TMP/btrfs-vols" + ++( ( + for partition in $(partitions); do + if ! mapped="$(mapdevfs "$partition")"; then + log "Device '$partition' does not exist; skipping" +@@ -200,3 +208,5 @@ for partition in $(partitions); do + fi + fi + done ++) 9>&1 | logger 1>&- # fd_logger ++) 3>&1 # fd_result diff --git a/os-prober-factored-logger-efi-fix.patch b/os-prober-factored-logger-efi-fix.patch new file mode 100644 index 0000000..5c66fa0 --- /dev/null +++ b/os-prober-factored-logger-efi-fix.patch @@ -0,0 +1,16 @@ +Index: os-prober/os-probes/mounted/x86/05efi +=================================================================== +--- os-prober.orig/os-probes/mounted/x86/05efi ++++ os-prober/os-probes/mounted/x86/05efi +@@ -59,7 +59,11 @@ ret=1 + for test in /usr/lib/os-probes/mounted/efi/*; do + debug "running subtest $test" + if [ -f "$test" ] && [ -x "$test" ]; then ++ # we need results of subtest in stdout ++ orig_fd_res=$fd_result ++ export fd_result=1 + entry=$("$test" "$mpoint/$efi") ++ export fd_result=$orig_fd_res + if [ -n "$entry" ]; then + debug "bootloader $entry found by subtest $test" + ret=0 diff --git a/os-prober-gentoo-fix.patch b/os-prober-gentoo-fix.patch new file mode 100644 index 0000000..8545db2 --- /dev/null +++ b/os-prober-gentoo-fix.patch @@ -0,0 +1,13 @@ +Index: os-prober/linux-boot-probes/mounted/common/90fallback +=================================================================== +--- os-prober.orig/linux-boot-probes/mounted/common/90fallback ++++ os-prober/linux-boot-probes/mounted/common/90fallback +@@ -33,7 +33,7 @@ for kernpat in /vmlinuz /vmlinux /boot/v + # Dracut initramfses are named differently again. + initrdname3=$(echo "$kernfile" | sed "s/vmlinu[zx]/initramfs\*/" | sed 's/$/.img/') + # And Gentoo's also +- initrdname4=$(echo "$kernfile" | sed "s/kernel/initramfs\*/") ++ initrdname4=$(echo "$kernfile" | sed "s/kernel\|vmlinu[zx]/initramfs\*/") + foundinitrd=0 + for initrd in $(eval ls "$initrdname" "$initrdname1" "$initrdname2" "$initrdname3" "$initrdname4" 2>/dev/null); do + if [ "$initrd" != "$kernfile" ] && [ -f "$initrd" ] && [ ! -L "$initrd" ]; then diff --git a/os-prober-grepfix.patch b/os-prober-grepfix.patch new file mode 100644 index 0000000..4dadd4f --- /dev/null +++ b/os-prober-grepfix.patch @@ -0,0 +1,13 @@ +Index: os-prober/os-probes/mounted/x86/83haiku +=================================================================== +--- os-prober.orig/os-probes/mounted/x86/83haiku ++++ os-prober/os-probes/mounted/x86/83haiku +@@ -13,7 +13,7 @@ case "$type" in + *) debug "$partition is not a BeFS partition: exiting"; exit 1 ;; + esac + +-if head -c 512 "$partition" | grep -qs "system.haiku_loader"; then ++if head -c 512 "$partition" | grep -aqs "system.haiku_loader"; then + debug "Stage 1 bootloader found" + else + debug "Stage 1 bootloader not found: exiting" diff --git a/os-prober-grub2-parsefix.patch b/os-prober-grub2-parsefix.patch new file mode 100644 index 0000000..0ef8bda --- /dev/null +++ b/os-prober-grub2-parsefix.patch @@ -0,0 +1,22 @@ +Index: os-prober-1.58/linux-boot-probes/mounted/common/40grub2 +=================================================================== +--- os-prober-1.58.orig/linux-boot-probes/mounted/common/40grub2 ++++ os-prober-1.58/linux-boot-probes/mounted/common/40grub2 +@@ -77,7 +77,7 @@ parse_grub_menu () { + ignore_item=1 + fi + ;; +- linux) ++ linux*) + # Hack alert: sed off any (hdn,n) but + # assume the kernel is on the same + # partition. +@@ -90,7 +90,7 @@ parse_grub_menu () { + kernel="/boot$kernel" + fi + ;; +- initrd) ++ initrd*) + initrd="$(echo "$2" | sed 's/(.*)//')" + # Initrd same. + if [ "$partition" != "$bootpart" ]; then diff --git a/os-prober-mdraidfix.patch b/os-prober-mdraidfix.patch new file mode 100644 index 0000000..33a432d --- /dev/null +++ b/os-prober-mdraidfix.patch @@ -0,0 +1,25 @@ +Index: os-prober/os-prober +=================================================================== +--- os-prober.orig/os-prober ++++ os-prober/os-prober +@@ -64,6 +64,11 @@ partitions () { + exit 0 + fi + ++ # Add MD RAID devices ++ if [ -f /proc/mdstat ] ; then ++ awk '/^md/ {printf "/dev/"$1"\n"}' /proc/mdstat ++ fi ++ + # Also detect OSes on LVM volumes (assumes LVM is active) + if type lvs >/dev/null 2>&1; then + echo "$(LVM_SUPPRESS_FD_WARNINGS=1 log_output lvs --noheadings --separator : -o vg_name,lv_name | +@@ -123,7 +128,7 @@ if [ -f /proc/swaps ]; then + fi + : >"$OS_PROBER_TMP/raided-map" + if [ -f /proc/mdstat ] ; then +- grep "^md" /proc/mdstat | parse_proc_mdstat >"$OS_PROBER_TMP/raided-map" || true ++ grep "^md" /proc/mdstat | cut -d: -f2- | parse_proc_mdstat >"$OS_PROBER_TMP/raided-map" || true + fi + + for partition in $(partitions); do diff --git a/os-prober-mounted-partitions-fix.patch b/os-prober-mounted-partitions-fix.patch new file mode 100644 index 0000000..aecfc9f --- /dev/null +++ b/os-prober-mounted-partitions-fix.patch @@ -0,0 +1,26 @@ +Index: os-prober/common.sh +=================================================================== +--- os-prober.orig/common.sh ++++ os-prober/common.sh +@@ -146,7 +146,7 @@ parse_proc_mounts () { + set -f + set -- $line + set +f +- printf '%s %s %s\n' "$(mapdevfs "$1")" "$2" "$3" ++ printf '%s %s %s %s\n' "$(mapdevfs "$1")" "$2" "$3" "$1" + done + } + +Index: os-prober/linux-boot-prober +=================================================================== +--- os-prober.orig/linux-boot-prober ++++ os-prober/linux-boot-prober +@@ -167,7 +167,7 @@ else + bootpart="${mountboot%% *}" + bootmounted="${mountboot#* }" + else +- bootpart="$partition" ++ bootpart="$(grep " $mpoint/boot " "$OS_PROBER_TMP/mounted-map" | head -n1 | cut -d " " -f 4)" + bootmounted=0 + fi + for test in /usr/lib/linux-boot-probes/mounted/*; do diff --git a/os-prober-no-dummy-mach-kernel.patch b/os-prober-no-dummy-mach-kernel.patch new file mode 100644 index 0000000..b9e1254 --- /dev/null +++ b/os-prober-no-dummy-mach-kernel.patch @@ -0,0 +1,22 @@ +From f71f7eb5c492720c24033901ef8c6c420e188ff2 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 10 May 2012 14:47:35 -0400 +Subject: [PATCH] Don't count our dummy mach_kernel as real MacOS X. + +--- + os-probes/mounted/powerpc/20macosx | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: b/os-probes/mounted/powerpc/20macosx +=================================================================== +--- a/os-probes/mounted/powerpc/20macosx ++++ b/os-probes/mounted/powerpc/20macosx +@@ -21,7 +21,7 @@ esac + # but I don't think it exists on Mac OS <= 9, and it's XML so parsing in + # shell will be nasty. + +-if [ -e "$2/mach_kernel" ]; then ++if [ -e "$2/mach_kernel" ] && ! dd if="$2/mach_kernel" count=1 bs=5 2>/dev/null | grep -aq Dummy ; then + label="$(count_next_label MacOSX)" + result "$1:Mac OS X:$label:macosx" + exit 0 diff --git a/os-prober-umount-fix.patch b/os-prober-umount-fix.patch new file mode 100644 index 0000000..6e7937c --- /dev/null +++ b/os-prober-umount-fix.patch @@ -0,0 +1,18 @@ +Index: os-prober/common.sh +=================================================================== +--- os-prober.orig/common.sh ++++ os-prober/common.sh +@@ -336,3 +336,13 @@ linux_mount_boot () { + + mountboot="$bootpart $mounted" + } ++ ++umount_exec=$(which umount) ++umount() { ++ if ! $umount_exec $@ 2> /dev/null; then ++ error "umount error, retrying after 1 sec" ++ sleep 1 ++ $umount_exec $@ ++ fi ++} ++ diff --git a/os-prober.spec b/os-prober.spec new file mode 100644 index 0000000..3c823f8 --- /dev/null +++ b/os-prober.spec @@ -0,0 +1,97 @@ +Name: os-prober +Version: 1.74 +Release: 9 +Summary: Probe disks on the system for other operating systems +License: GPLv2+ and GPL+ +URL: http://kitenet.net/~joey/code/os-prober/ +Source0: http://ftp.us.debian.org/debian/pool/main/o/os-prober/%{name}_%{version}.tar.xz + +Patch0: os-prober-no-dummy-mach-kernel.patch +Patch1: os-prober-mdraidfix.patch +Patch2: os-prober-btrfsfix.patch +Patch3: os-prober-bootpart-name-fix.patch +Patch4: os-prober-mounted-partitions-fix.patch +Patch5: os-prober-factor-out-logger.patch +Patch6: os-prober-factored-logger-efi-fix.patch +Patch7: os-prober-umount-fix.patch +Patch8: os-prober-grub2-parsefix.patch +Patch9: os-prober-grepfix.patch +Patch10: os-prober-gentoo-fix.patch +Patch9000: bugfix-wait-for-device-mapper-device-is-created.patch + +BuildRequires: gcc git +Requires: udev coreutils util-linux grep /bin/sed /sbin/modprobe device-mapper + +%description +Os-prober can probe disks on the system for other operating systems, +and add them to the boot loader, so that installing current OS doesn't +make your other installed OS hard to boot. + +%prep +%autosetup -n %{name} -Sgit + +sed -i -e 's|grub-probe|grub2-probe|g' os-probes/common/50mounted-tests \ + linux-boot-probes/common/50mounted-tests + +%build +%make_build + +%install +install -m 0755 -d $RPM_BUILD_ROOT%{_bindir} +install -m 0755 -d $RPM_BUILD_ROOT%{_var}/lib/%{name} + +install -m 0755 -p os-prober linux-boot-prober $RPM_BUILD_ROOT%{_bindir} +install -m 0755 -Dp newns $RPM_BUILD_ROOT%{_libexecdir}/os-prober/newns +install -m 0644 -Dp common.sh $RPM_BUILD_ROOT%{_datadir}/%{name}/common.sh + +%ifarch m68k +ARCH=m68k +%endif +%ifarch ppc ppc64 +ARCH=powerpc +%endif +%ifarch sparc sparc64 +ARCH=sparc +%endif +%ifarch %{ix86} x86_64 +ARCH=x86 +%endif + +for probes in os-probes os-probes/mounted os-probes/init \ + linux-boot-probes linux-boot-probes/mounted; do + install -m 755 -d $RPM_BUILD_ROOT%{_libexecdir}/$probes + cp -a $probes/common/* $RPM_BUILD_ROOT%{_libexecdir}/$probes + if [ -e "$probes/$ARCH" ]; then + cp -a $probes/$ARCH/* $RPM_BUILD_ROOT%{_libexecdir}/$probes + fi +done +if [ "$ARCH" = x86 ]; then + install -m 755 -p os-probes/mounted/powerpc/20macosx \ + $RPM_BUILD_ROOT%{_libexecdir}/os-probes/mounted +fi + +%pre + +%preun + +%post + +%postun + +%files +%doc README TODO debian/changelog +%license debian/copyright +%{_bindir}/* +%{_datadir}/%{name} +%{_var}/lib/%{name} +%{_libexecdir}/* + +%changelog +* Fri Sep 27 2019 chengquan - 1.74-9 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:fix spec rule in openeuler + +* Thu Sep 05 2019 openEuler Buildteam - 1.74-8 +- Package init diff --git a/os-prober_1.74.tar.xz b/os-prober_1.74.tar.xz new file mode 100644 index 0000000000000000000000000000000000000000..55755439eb83d9f4a0fe6f74a9ca2f4fb367958d GIT binary patch literal 26692 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

vO4V>^xd77 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 (m&(PdN;xN`5=IY{fPVFWwJaX|Q`d8L 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 literal 0 HcmV?d00001