commit:     733c692eca0ad50591ccf11cfcf89e317291f35f
Author:     Peter Levine <plevine457 <AT> gmail <DOT> com>
AuthorDate: Fri Oct  8 01:13:01 2021 +0000
Commit:     Ben Kohler <bkohler <AT> gentoo <DOT> org>
CommitDate: Fri Oct  8 11:12:16 2021 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=733c692e

sys-boot/os-prober: replace os-prober-1.78-btrfsfix.patch

Replace os-prober-1.78-btrfsfix.patch with changes from OpenSUSE's
os-prober-btrfs-always-detect-default.patch to fix OS detection issues.

Closes: https://bugs.gentoo.org/790434
Package-Manager: Portage-3.0.26, Repoman-3.0.3
Signed-off-by: Peter Levine <plevine457 <AT> gmail.com>
Signed-off-by: Ben Kohler <bkohler <AT> gentoo.org>

 .../os-prober-1.79-btrfs-subvolume-detection.patch | 505 +++++++++++++++++++++
 sys-boot/os-prober/os-prober-9999.ebuild           |   2 +-
 2 files changed, 506 insertions(+), 1 deletion(-)

diff --git 
a/sys-boot/os-prober/files/os-prober-1.79-btrfs-subvolume-detection.patch 
b/sys-boot/os-prober/files/os-prober-1.79-btrfs-subvolume-detection.patch
new file mode 100644
index 00000000000..14cd794530e
--- /dev/null
+++ b/sys-boot/os-prober/files/os-prober-1.79-btrfs-subvolume-detection.patch
@@ -0,0 +1,505 @@
+Fixes detection of multiple linux installations on different subvolumes of the
+same partition.  Also contains changes from
+https://build.opensuse.org/package/view_file/openSUSE:Factory/os-prober/os-prober-btrfs-always-detect-default.patch
+to fix https://bugs.gentoo.org/790434.
+
+Bug: https://bugs.gentoo.org/790434
+     https://bugs.debian.org/688336
+     https://bugzilla.redhat.com/888341
+
+--- a/common.sh
++++ b/common.sh
+@@ -155,6 +155,7 @@
+       done
+ }
+ 
++# add forth parameter to pickup btrfs subvol info
+ parsefstab () {
+       while read -r line; do
+               case "$line" in
+@@ -165,12 +166,22 @@
+                               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'
+--- a/linux-boot-prober
++++ b/linux-boot-prober
+@@ -5,16 +5,148 @@
+ 
+ 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 [ -n "$subvol" ]; then
++                      opts="-o subvol=$subvol"
++              fi
++
++              if ! mount $opts -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 +154,8 @@
+ 
+ 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
+--- 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
+@@ -108,9 +121,9 @@
+     [ "$mpoint/boot/grub/grub.cfg" -nt "$mpoint/boot/grub/menu.lst" ]); then
+       debug "parsing grub.cfg"
+       parse_grub_menu "$mpoint" "$partition" "$bootpart" < 
"$mpoint/boot/grub/grub.cfg"
+-elif [ -e "$mpoint/boot/grub2/grub.cfg" ]; then
++elif [ -e "$mpoint/boot/grub/grub.cfg" ]; then
+       debug "parsing grub.cfg"
+-      parse_grub_menu "$mpoint" "$partition" "$bootpart" < 
"$mpoint/boot/grub2/grub.cfg"
++      parse_grub_menu "$mpoint" "$partition" "$bootpart" < 
"$mpoint/boot/grub/grub.cfg"
+ fi
+ 
+ if [ "$found_item" = 0 ]; then
+--- a/os-prober
++++ b/os-prober
+@@ -76,9 +76,12 @@
+ 
+       # 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 @@
+       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 @@
+               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"
+--- a/os-probes/common/50mounted-tests
++++ b/os-probes/common/50mounted-tests
+@@ -14,19 +14,31 @@
+       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'
+@@ -35,7 +47,7 @@
+       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
+@@ -58,6 +70,127 @@
+ fi
+ 
+ mounted=
++
++probe_subvol ()
++{
++      local subvol=$1
++      local partition=$2
++      local UUID=$3
++      local tmpmnt=$4
++
++      mounted=
++      mpoint="$(grep btrfs /proc/self/mountinfo | grep "$partition " | grep 
"/$subvol " | cut -d ' ' -f 5)"
++      ret=1
++
++      if [ -n "$subvol" ]; then
++              opts="-o subvol=$subvol"
++      fi
++
++      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 $opts -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"
++                      ret=0
++              fi
++      fi
++      if [ -z "$mounted" ]; then
++              if ! umount "$tmpmnt"; then
++                      warn "failed to umount $tmpmnt"
++              fi
++      fi
++      return $ret
++}
++
++# 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/libexec/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
++      found=
++      # Always probe subvol or root set as default
++      if probe_subvol "$defaultvol" "$partition" "$UUID" "$tmpmnt"; then
++              found=1
++      fi
++
++      # Probe any other OS on subvol
++      for subvol in $subvols; do
++              if echo "$rosubvols" | grep -q -x "$subvol" ||
++                 echo "$sssubvols" | grep -q -x "$subvol" ||
++                 echo "$defaultvol" | grep -q -x "$subvol"; then
++                      continue
++              fi
++              debug "begin btrfs processing for $UUID subvol=$subvol"
++              if probe_subvol "$subvol" "$partition" "$UUID" "$tmpmnt"; then
++                      found=1
++              fi
++      done
++      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
+--- a/os-probes/mounted/common/90linux-distro
++++ b/os-probes/mounted/common/90linux-distro
+@@ -7,6 +7,8 @@
+ 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 @@
+       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/sys-boot/os-prober/os-prober-9999.ebuild 
b/sys-boot/os-prober/os-prober-9999.ebuild
index 4feb1e2b320..5bd9e3b714c 100644
--- a/sys-boot/os-prober/os-prober-9999.ebuild
+++ b/sys-boot/os-prober/os-prober-9999.ebuild
@@ -27,7 +27,7 @@ QA_MULTILIB_PATHS="usr/lib/os-prober/.*"
 
 PATCHES=(
        "${FILESDIR}"/${PN}-1.79-mdraid-detection.patch
-       "${FILESDIR}"/${PN}-1.78-btrfsfix.patch
+       "${FILESDIR}"/${PN}-1.79-btrfs-subvolume-detection.patch
 )
 
 DOC_CONTENTS="

Reply via email to