os-prober-btrfsfix.patch 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. diff --git a/common.sh b/common.sh
  2. index c2c5f46..8fb3c5f 100644
  3. --- a/common.sh
  4. +++ b/common.sh
  5. @@ -155,6 +155,7 @@ parse_proc_mounts () {
  6. done
  7. }
  8. +# add forth parameter to pickup btrfs subvol info
  9. parsefstab () {
  10. while read -r line; do
  11. case "$line" in
  12. @@ -165,12 +166,22 @@ parsefstab () {
  13. set -f
  14. set -- $line
  15. set +f
  16. - printf '%s %s %s\n' "$1" "$2" "$3"
  17. + printf '%s %s %s %s\n' "$1" "$2" "$3" "$4"
  18. ;;
  19. esac
  20. done
  21. }
  22. +#check_btrfs_mounted $bootsv $bootuuid)
  23. +check_btrfs_mounted () {
  24. + bootsv="$1"
  25. + bootuuid="$2"
  26. + bootdev=$(blkid | grep "$bootuuid" | cut -d ':' -f 1)
  27. + bindfrom=$(grep " btrfs " /proc/self/mountinfo |
  28. + grep " $bootdev " | grep " /$bootsv " | cut -d ' ' -f 5)
  29. + printf "%s" "$bindfrom"
  30. +}
  31. +
  32. unescape_mount () {
  33. printf %s "$1" | \
  34. sed 's/\\011/ /g; s/\\012/\n/g; s/\\040/ /g; s/\\134/\\/g'
  35. diff --git a/linux-boot-prober b/linux-boot-prober
  36. index e32dc84..2a60fa2 100755
  37. --- a/linux-boot-prober
  38. +++ b/linux-boot-prober
  39. @@ -5,16 +5,143 @@ set -e
  40. newns "$@"
  41. require_tmpdir
  42. +ERR="n"
  43. +
  44. +tmpmnt=/var/lib/os-prober/mount
  45. +if [ ! -d "$tmpmnt" ]; then
  46. + mkdir "$tmpmnt"
  47. +fi
  48. +
  49. +mounted=
  50. +bootmnt=
  51. +bootsv=
  52. +bootuuid=
  53. grep "^/dev/" /proc/mounts | parse_proc_mounts >"$OS_PROBER_TMP/mounted-map" || true
  54. -partition="$1"
  55. +if [ -z "$1" ]; then
  56. + ERR=y
  57. +elif [ "$1" = btrfs -a -z "$2" ]; then
  58. + ERR=y
  59. +elif [ "$1" = btrfs -a -z "$3" ]; then
  60. + ERR=y
  61. +elif [ "$1" = btrfs ]; then
  62. + type=btrfs
  63. + echo "$2" | grep -q "^UUID=" || ERR=y
  64. + echo "$3" | grep -q "^subvol=" || ERR=y
  65. + export "$2"
  66. + export "$3"
  67. + partition=$(blkid | grep "$UUID" | cut -d ':' -f 1 | tr '\n' ' ' | cut -d ' ' -f 1)
  68. + debug "btrfs: partition=$partition, UUID=$UUID, subvol=$subvol"
  69. +else
  70. + partition="$1"
  71. + type=other
  72. +fi
  73. -if [ -z "$partition" ]; then
  74. +if [ "x$ERR" != xn ]; then
  75. echo "usage: linux-boot-prober partition" >&2
  76. + echo " linux-boot-prober btrfs UUID=<> subvol=<>" >&2
  77. exit 1
  78. fi
  79. +if [ "$type" = btrfs ]; then
  80. + # handle all of the btrfs stuff here
  81. + if [ ! -e "/proc/self/mountinfo" ]; then
  82. + warn "/proc/self/mountinfo does not exist, exiting"
  83. + umount "$tmpmnt" 2>/dev/null
  84. + rmdir "$tmpmnt" 2>/dev/null
  85. + exit 1
  86. + fi
  87. + mpoint=$(grep "btrfs" /proc/self/mountinfo | grep " /$subvol " | grep " $partition " | cut -d ' ' -f 5)
  88. + if [ "$mpoint" = "/" ]; then
  89. + warn "specifying active root not valid, exiting"
  90. + umount "$tmpmnt" 2>/dev/null
  91. + rmdir "$tmpmnt" 2>/dev/null
  92. + exit 1
  93. + fi
  94. + if [ "$mpoint" = "$tmpmnt" ]; then
  95. + warn "btrfs subvol=$subvool, UUID=$UUID, already mounted on $tmpmnt **ERROR**"
  96. + umount "$tmpmnt" 2>/dev/null
  97. + rmdir "$tmpmnt" 2>/dev/null
  98. + exit 1
  99. + fi
  100. + if [ -z "$mpoint" ]; then
  101. + # mount the btrfs root
  102. + if ! mount -o subvol=$subvol -t btrfs -U $UUID "$tmpmnt" 2>/dev/null; then
  103. + warn "error mounting btrfs subvol=$subvol UUID=$UUID"
  104. + umount "$tmpmnt/boot" 2>/dev/null
  105. + umount "$tmpmnt" 2>/dev/null
  106. + rmdir "$tmpmnt" 2>/dev/null
  107. + exit 1
  108. + fi
  109. + else
  110. + # bind-mount
  111. + if ! mount -o bind "$mpoint" "$tmpmnt" 2>/dev/null; then
  112. + warn "error mounting btrfs bindfrom=$mpoint subvol=$subvol UUID=$UUID"
  113. + umount "$tmpmnt/boot" 2>/dev/null
  114. + umount "$tmpmnt" 2>/dev/null
  115. + rmdir "$tmpmnt" 2>/dev/null
  116. + exit 1
  117. + fi
  118. + fi
  119. + debug "mounted btrfs $partition, subvol=$subvol on $tmpmnt"
  120. + if [ ! -e "$tmpmnt/etc/fstab" ]; then
  121. + warn "btrfs subvol=$subvol not root"
  122. + umount "$tmpmnt" 2>/dev/null
  123. + rmdir "$tmpmnt" 2>/dev/null
  124. + exit 1
  125. + fi
  126. + bootmnt=$(parsefstab < "$tmpmnt/etc/fstab" | grep " /boot ") || true
  127. + if [ -z "$bootmnt" ]; then
  128. + # /boot is part of the root
  129. + bootpart="$partition"
  130. + bootsv="$subvol"
  131. + elif echo "$bootmnt" | cut -d ' ' -f 3 | grep -q "btrfs"; then
  132. + # separate btrfs /boot subvolume
  133. + bootsv=$(echo "$bootmnt" | cut -d ' ' -f 4 | grep "^subvol=" | sed "s/subvol=//" )
  134. + bootuuid=$(echo "$bootmnt" | cut -d ' ' -f 1 | grep "^UUID=" | sed "s/UUID=//" )
  135. + debug "mounting btrfs $tmpmnt/boot UUID=$bootuuid subvol=$bootsv"
  136. + bindfrom=$(check_btrfs_mounted $bootsv $bootuuid)
  137. + if [ -n "$bindfrom" ]; then
  138. + # already mounted some place
  139. + if ! mount -o bind $bindfrom "$tmpmnt/boot" 2>/dev/null; then
  140. + warn "error bind mounting btrfs boot subvol=$bootsv, from=$bindfrom"
  141. + umount "$tmpmnt/boot" 2>/dev/null
  142. + umount "$tmpmnt" 2>/dev/null
  143. + rmdir "$tmpmnt" 2>/dev/null
  144. + exit 1
  145. + fi
  146. + elif ! mount -o subvol=$bootsv -t btrfs -U $bootuuid "$tmpmnt/boot" 2>/dev/null; then
  147. + warn "error mounting btrfs boot partition subvol=$bootsv, UUID=$bootuuid"
  148. + umount "$tmpmnt/boot" 2>/dev/null
  149. + umount "$tmpmnt" 2>/dev/null
  150. + rmdir "$tmpmnt" 2>/dev/null
  151. + exit 1
  152. + fi
  153. + bootpart=$(grep " btrfs " /proc/self/mountinfo | grep " /$bootsv " | cut -d ' ' -f 10)
  154. + else
  155. + # non-btrfs partition or logical volume
  156. + linux_mount_boot $partition $tmpmnt
  157. + bootpart="${mountboot%% *}"
  158. + bootsv=
  159. + fi
  160. +
  161. + test="/usr/lib/linux-boot-probes/mounted/40grub2"
  162. + if [ -f $test ] && [ -x $test ]; then
  163. + debug "running $test $partition $bootpart $tmpmnt $type $subvol $bootsv"
  164. + if $test "$partition" "$bootpart" "$tmpmnt" "$type" "$subvol" "$bootsv"; then
  165. + debug "$test succeeded"
  166. + fi
  167. + fi
  168. + umount "$tmpmnt/boot" 2>/dev/null || true
  169. + if ! umount "$tmpmnt" 2>/dev/null; then
  170. + warn "problem umount $tmpmnt"
  171. + fi
  172. + rmdir "$tmpmnt" 2>/dev/null || true
  173. +
  174. + exit 0
  175. +fi
  176. +
  177. if ! mapped="$(mapdevfs "$partition")"; then
  178. log "Device '$partition' does not exist; skipping"
  179. continue
  180. @@ -22,8 +149,8 @@ fi
  181. if ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map"; then
  182. for test in /usr/lib/linux-boot-probes/*; do
  183. - debug "running $test"
  184. if [ -x $test ] && [ -f $test ]; then
  185. + debug "running $test"
  186. if $test "$partition"; then
  187. debug "linux detected by $test"
  188. break
  189. diff --git a/linux-boot-probes/mounted/common/40grub2 b/linux-boot-probes/mounted/common/40grub2
  190. index 885614e..db5cbfd 100755
  191. --- a/linux-boot-probes/mounted/common/40grub2
  192. +++ b/linux-boot-probes/mounted/common/40grub2
  193. @@ -2,17 +2,30 @@
  194. . /usr/share/os-prober/common.sh
  195. set -e
  196. +# add support for btrfs with no separate /boot
  197. +# that is, rootsv = bootsv
  198. partition="$1"
  199. bootpart="$2"
  200. mpoint="$3"
  201. type="$4"
  202. +rootsv="$5"
  203. +bootsv="$6"
  204. found_item=0
  205. entry_result () {
  206. + if [ "x$type" = "xbtrfs" -a "$partition" = "$bootpart" ]; then
  207. + # trim off the leading subvol
  208. + kernelfile=$(echo "$kernel" | cut -d '/' -f 2- | cut -d '/' -f 2-)
  209. + if [ "x$rootsv" != "x$bootsv" ]; then
  210. + kernelfile="/boot/$kernelfile"
  211. + fi
  212. + else
  213. + kernelfile=$kernel
  214. + fi
  215. if [ "$ignore_item" = 0 ] && \
  216. [ -n "$kernel" ] && \
  217. - [ -e "$mpoint/$kernel" ]; then
  218. + [ -e "$mpoint/$kernelfile" ]; then
  219. result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters"
  220. found_item=1
  221. fi
  222. diff --git a/os-prober b/os-prober
  223. index 8852887..482c3c2 100755
  224. --- a/os-prober
  225. +++ b/os-prober
  226. @@ -76,9 +76,12 @@ partitions () {
  227. # Also detect OSes on LVM volumes (assumes LVM is active)
  228. if type lvs >/dev/null 2>&1; then
  229. - echo "$(LVM_SUPPRESS_FD_WARNINGS=1 log_output lvs --noheadings --separator : -o vg_name,lv_name |
  230. + echo "$(LVM_SUPPRESS_FD_WARNINGS=1 log_output lvs --noheadings --separator : -o vg_name,lv_name 2>/dev/null |
  231. sed "s|-|--|g;s|^[[:space:]]*\(.*\):\(.*\)$|/dev/mapper/\1-\2|")"
  232. fi
  233. +
  234. + # now lets make sure we got all of the btrfs partitions and disks
  235. + blkid | grep 'TYPE="btrfs"' | cut -d ':' -f 1
  236. }
  237. parse_proc_swaps () {
  238. @@ -136,6 +139,8 @@ if [ -f /proc/mdstat ] ; then
  239. grep "^md" /proc/mdstat | cut -d: -f2- | parse_proc_mdstat >"$OS_PROBER_TMP/raided-map" || true
  240. fi
  241. +: >"$OS_PROBER_TMP/btrfs-vols"
  242. +
  243. for partition in $(partitions); do
  244. if ! mapped="$(mapdevfs "$partition")"; then
  245. log "Device '$partition' does not exist; skipping"
  246. @@ -154,7 +159,26 @@ for partition in $(partitions); do
  247. continue
  248. fi
  249. - if ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map" ; then
  250. + # do btrfs processing here; both mounted and unmounted will
  251. + # be handled by 50mounted-tests so we can do a subvol only once.
  252. + type=$(blkid -o value -s TYPE $mapped || true)
  253. + if [ "$type" = btrfs ]; then
  254. + uuid=$(blkid -o value -s UUID $mapped)
  255. + if grep -q "^$uuid" "$OS_PROBER_TMP/btrfs-vols" ; then
  256. + continue
  257. + fi
  258. + debug "btrfs volume uuid=$uuid partition=$partition"
  259. + echo "$uuid" >>"$OS_PROBER_TMP/btrfs-vols"
  260. + test="/usr/lib/os-probes/50mounted-tests"
  261. + if [ -f "$test" ] && [ -x "$test" ]; then
  262. + debug "running $test on btrfs $partition"
  263. + if "$test" btrfs "$uuid" "$partition"; then
  264. + debug "os detected by $test"
  265. + continue
  266. + fi
  267. + fi
  268. +
  269. + elif ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map" ; then
  270. for test in /usr/lib/os-probes/*; do
  271. if [ -f "$test" ] && [ -x "$test" ]; then
  272. debug "running $test on $partition"
  273. diff --git a/os-probes/common/50mounted-tests b/os-probes/common/50mounted-tests
  274. index 2951ef9..e33eb82 100755
  275. --- a/os-probes/common/50mounted-tests
  276. +++ b/os-probes/common/50mounted-tests
  277. @@ -19,19 +19,31 @@ do_unmount() {
  278. rmdir "$tmpmnt" || true
  279. }
  280. -types="$(fs_type "$partition")"
  281. +if [ "x$1" = xbtrfs ]; then
  282. + types=btrfs
  283. + if [ -z "$2" -o -z "$3" ]; then
  284. + debug "missing btrfs parameters, exiting"
  285. + exit 1
  286. + fi
  287. + UUID="$2"
  288. + BTRFSDEV="$3"
  289. +else
  290. + partition="$1"
  291. + types="$(fs_type "$partition")" || types=NOT-DETECTED
  292. +fi
  293. +
  294. if [ "$types" = NOT-DETECTED ]; then
  295. debug "$1 type not recognised; skipping"
  296. - exit 0
  297. + exit 1
  298. elif [ "$types" = swap ]; then
  299. debug "$1 is a swap partition; skipping"
  300. - exit 0
  301. + exit 1
  302. elif [ "$types" = crypto_LUKS ]; then
  303. debug "$1 is a LUKS partition; skipping"
  304. - exit 0
  305. + exit 1
  306. elif [ "$types" = LVM2_member ]; then
  307. debug "$1 is an LVM member; skipping"
  308. - exit 0
  309. + exit 1
  310. elif [ "$types" = ntfs ]; then
  311. if type ntfs-3g >/dev/null 2>&1; then
  312. types='ntfs-3g ntfs'
  313. @@ -40,7 +52,7 @@ elif [ -z "$types" ]; then
  314. if type cryptsetup >/dev/null 2>&1 && \
  315. cryptsetup luksDump "$partition" >/dev/null 2>&1; then
  316. debug "$1 is a LUKS partition; skipping"
  317. - exit 0
  318. + exit 1
  319. fi
  320. for type in $(grep -v nodev /proc/filesystems); do
  321. # hfsplus filesystems are mountable as hfs. Try hfs last so
  322. @@ -63,6 +75,108 @@ if [ ! -d "$tmpmnt" ]; then
  323. fi
  324. mounted=
  325. +
  326. +# all btrfs processing here. Handle both unmounted and
  327. +# mounted subvolumes.
  328. +if [ "$types" = btrfs ]; then
  329. + partition="$BTRFSDEV"
  330. + debug "begin btrfs processing for $UUID"
  331. + # note that the btrfs volume must not be mounted ro
  332. + if mount -t btrfs -U "$UUID" "$tmpmnt" 2>/dev/null; then
  333. + debug "btrfs volume $UUID mounted"
  334. + else
  335. + warn "cannot mount btrfs volume $UUID, exiting"
  336. + rmdir "$tmpmnt" || true
  337. + exit 1
  338. + fi
  339. + # besides regular subvols, get ro and snapshot so thet can be excluded
  340. + subvols=$(btrfs subvolume list "$tmpmnt" | cut -d ' ' -f 9)
  341. + rosubvols=$(btrfs subvolume list -r "$tmpmnt" | cut -d ' ' -f 9)
  342. + sssubvols=$(btrfs subvolume list -s "$tmpmnt" | cut -d ' ' -f 14)
  343. + if ! umount "$tmpmnt"; then
  344. + warn "failed to umount btrfs volume on $tmpmnt"
  345. + rmdir "$tmpmnt" || true
  346. + exit 1
  347. + fi
  348. +
  349. + found=
  350. + mounted=
  351. +
  352. + mpoint="$(grep btrfs /proc/self/mountinfo | grep "$partition " | cut -d ' ' -f 5)"
  353. + if [ -n "$mpoint" -a "x$mpoint" = "x/" ]; then
  354. + debug "This is the root for the running system" #running system must be done elsewhere
  355. + else
  356. + #partition was not root of running system, so lets look for bootable subvols
  357. + if [ -n "$mpoint" ] ; then
  358. + mounted=1 #partition was already mounted,so lets not unmount it when done
  359. + else
  360. + # again, do not mount btrfs ro
  361. + mount -t btrfs -U "$UUID" "$tmpmnt"
  362. + mpoint="$tmpmnt"
  363. + fi
  364. +
  365. + test="/usr/lib/os-probes/mounted/90linux-distro"
  366. + if [ -f "$test" ] && [ -x "$test" ]; then
  367. + debug "running subtest $test"
  368. + if "$test" "$partition" "$mpoint" btrfs "UUID=$UUID"; then
  369. + debug "os found by subtest $test on $partition"
  370. + found=1
  371. + fi
  372. + fi
  373. + if [ -z "$mounted" ]; then
  374. + if ! umount "$tmpmnt"; then
  375. + warn "failed to umount $tmpmnt"
  376. + fi
  377. + fi
  378. + fi
  379. +
  380. + if [ -z "$subvols" ]; then
  381. + debug "no subvols found on btrfs volume $UUID"
  382. + else
  383. + found=
  384. + for subvol in $subvols; do
  385. + debug "begin btrfs processing for $UUID subvol=$subvol"
  386. + if echo "$rosubvols" | grep -q -x "$subvol"; then
  387. + continue
  388. + fi
  389. + if echo "$sssubvols" | grep -q -x "$subvol"; then
  390. + continue
  391. + fi
  392. + mounted=
  393. + mpoint="$(grep btrfs /proc/self/mountinfo | grep "$partition " | grep "/$subvol " | cut -d ' ' -f 5)"
  394. + if [ -n "$mpoint" ]; then
  395. + if [ "x$mpoint" = "x/" ]; then
  396. + continue # this is the root for the running system
  397. + fi
  398. + mounted=1
  399. + else
  400. + # again, do not mount btrfs ro
  401. + mount -t btrfs -o subvol="$subvol" -U "$UUID" "$tmpmnt"
  402. + mpoint="$tmpmnt"
  403. + fi
  404. + test="/usr/lib/os-probes/mounted/90linux-distro"
  405. + if [ -f "$test" ] && [ -x "$test" ]; then
  406. + debug "running subtest $test"
  407. + if "$test" "$partition" "$mpoint" btrfs "UUID=$UUID" "subvol=$subvol"; then
  408. + debug "os found by subtest $test on subvol $subvol"
  409. + found=1
  410. + fi
  411. + fi
  412. + if [ -z "$mounted" ]; then
  413. + if ! umount "$tmpmnt"; then
  414. + warn "failed to umount $tmpmnt"
  415. + fi
  416. + fi
  417. + done
  418. + fi
  419. + rmdir "$tmpmnt" || true
  420. + if [ "$found" ]; then
  421. + exit 0
  422. + else
  423. + exit 1
  424. + fi
  425. +fi
  426. +
  427. if type grub-mount >/dev/null 2>&1 && \
  428. type grub-probe >/dev/null 2>&1 && \
  429. grub-mount "$partition" "$tmpmnt" 2>/dev/null; then
  430. diff --git a/os-probes/mounted/common/90linux-distro b/os-probes/mounted/common/90linux-distro
  431. index badfbb1..9bc5154 100755
  432. --- a/os-probes/mounted/common/90linux-distro
  433. +++ b/os-probes/mounted/common/90linux-distro
  434. @@ -7,6 +7,8 @@ set -e
  435. partition="$1"
  436. dir="$2"
  437. type="$3"
  438. +uuid="$4"
  439. +subvol="$5"
  440. # This test is inaccurate, but given separate / and /boot partitions and the
  441. # fact that only some architectures have ld-linux.so, I can't see anything
  442. @@ -143,7 +145,11 @@ if (ls "$dir"/lib*/ld*.so* && [ -d "$dir/boot" ] || ls "$dir"/usr/lib*/ld*.so*)
  443. fi
  444. label="$(count_next_label "$short")"
  445. - result "$partition:$long:$label:linux"
  446. + if [ "x$type" = "xbtrfs" -a "x$uuid" != "x" -a "x$subvol" != "x" ]; then
  447. + result "$partition:$long:$label:linux:$type:$uuid:$subvol"
  448. + else
  449. + result "$partition:$long:$label:linux"
  450. + fi
  451. exit 0
  452. else
  453. exit 1