Bug#694668: A patch improve the performance of os-prober for systems with many partitions
Package: os-prober
Version: 1.56
Tags: patch
This bug is reported by one of our users, and also the patch is provided
by him. And this is his comments on the provided patch:
Here's a patch. The elapsed wall-clock times in seconds are:
os-prober linux-boot-prober
os-prober-1.56 12.9 3.6
patched 5.9 0.4
where os-prober analyzes all 43 partitions, but linux-boot-prober only 1.
So that is a factor of 9X for linux-boot-prober, but only 2.2X for
os-prober.
During os-prober, "vmstat 2" shows CPU time about:
10% user
9% system
20% idle
60% wait
and indeed the hardware LED for "disk active" is ON almost all the time.
I do not understand why the idle and wait times are not close to zero.
The internal documentation is lacking. I had to deduce the strategies.
Depending on usage, linux-boot-prober could be added to the os-prober
pipeline.
(I changed linux-boot-prober to read stdin instead of using $1.)
The overlap should be enough to hide the entire time for linux-boot-prober.
(That would give 7X faster for the whole task as seen by user of anaconda.)
Also, there is no comment about the reason for using "blockdev --setro"
when "mount -ro" is used already.
My box has 3GHz dual CPU, fedora-18-Beta-RC1, and these disks:
4 7200rpm SATA II drives; 2 GPT, 2 MSDOS
32 linux root partitions
5 data (non-root) partitions
3 swap partitions (one per drive except Windows)
2 not-formatted partitions
1 Windows partition
Overview of significant changes in the patch:
1. Factor out thouands of invocations of 'loggger' into a single process
which reads stdin.
2. Change strategy from serial tests to a shell pipeline where
success goes "out the side" while failure "falls through" to next
stage in pipeline.
3. Avoid 'grep' and 'sed' in favor of shell string processing, "set --"
under appropriate "IFS=", and 'eval'.
4. Avoid logging the whole contents of grub.cfg. Mine has 1955 lines,
and anyway the patched logging would suffer rate-limiting by syslog.
5. Use the -a (AND) operator to '[' (test) instead of multiple tests
with '&&'.
Because of its use by debian-installer, os-prober wants 'dash' as shell,
and not 'bash', This is unfortunate because bash has '=~' for string
maching,
"$(<" instead of "$(cat", and arrays. Dash can use
"case "$param" in; pattern) ... ;; ... esac" for most simple uses of
" [[ "$param" =~ pattern ]] ", but somehow I find 'case' cumbersome.
So I use "_tmp="${param##pattern}"; if [ ${#_tmp} -ne ${#param} ]"
(etc.) to detect a match by difference in length.
diff --git a/common.sh b/common.sh
index 82d019e..3c9b0cf 100644
--- a/common.sh
+++ b/common.sh
@@ -5,10 +5,9 @@ newns () {
cleanup_tmpdir=false
cleanup_ro_partitions=
cleanup () {
- local partition
- for partition in $cleanup_ro_partitions; do
- blockdev --setrw "$partition"
- done
+ if [ "$cleanup_ro_partitions" ]; then
+ blockdev --setrw $cleanup_ro_partitions
+ fi
if $cleanup_tmpdir; then
rm -rf "$OS_PROBER_TMP"
fi
@@ -57,16 +56,75 @@ progname=
cache_progname() {
case $progname in
'')
- progname="$(basename "$0")"
+ progname="${0##*/}"
;;
esac
}
-log() {
- cache_progname
- logger -t "$progname" "$@"
+path_lookup() {
+ local _t
+ unset $1 # default to failure
+ if _t=$(type "$1" 2>/dev/null); then
+ set -- $_t # "app is /path/to/app"
+ eval $1=\"$3\"
+ fi
+}
+
+strmid_extract() { # str left right; let str= a $2 b $3 c
+ local _b3c _b
+ eval '_b3c="${1#*'\\"$2"'}"'
+ eval '_b="${_b3c%'\\"$3"'*}"'
+ if [ "$_b3c" != "$1" -a "$_b" != "$_b3c" ]; then
+ # both prefix and suffix were removed
+ value="$_b"
+ else
+ value="" # one was missing
+ fi
+}
+
+strmid_delete() { # str left right; let str= a $2 b $3 c
+ local _a _c
+ eval '_a="${1%%'\\"$2"'*}"'
+ eval '_c="${1##*'\\"$3"'}"'
+ if [ ${#1} -ge $(( ${#_a} + 2 + ${#_c} )) ]; then
+ # there was a middle
+ value="$_a$_c"
+ else
+ value="$1" # one was missing
+ fi
+}
+
+strchar_delete() { # str char
+ _IFS="$IFS"
+ IFS="$2"; set -- $1
+ IFS=""; value="$*"
+ IFS="$_IFS"
+}
+
+strcat_sep_split() { # sep split str
+ local _sep _split
+ _sep="$1"; _split="$2"; shift 2
+ _IFS="$IFS"
+ IFS="$_split"; set -- $1 # adjacent splitters give only one cut
+ IFS="$_sep"; value="$*"
+ IFS="$_IFS"
+}
+
+# Single-quote "'" cannot be single quoted, because backslash does not escape.
+_PUNCT="'"'!"#$%&()*+,-./:;<=>?@[\]^`{|}~' # non-whitespace non-identifier
+
+str_tame() { # make $1 into an identifier
+ strcat_sep_split '_' "$_PUNCT" "$1" # result is $value
}
+# fd_logger: bind value now, possibly after assigning default.
+eval '
+ log() {
+ cache_progname
+ echo "$progname: $@" 1>&'${fd_logger:=9}'
+ }
+'
+
error() {
log "error: $@"
}
@@ -79,10 +137,14 @@ debug() {
log "debug: $@"
}
-result () {
- log "result:" "$@"
- echo "$@"
-}
+
+# fd_result: bind value now, possibly after assigning default.
+eval '
+ result() {
+ log "result:" "$@"
+ echo "$@" 1>&'${fd_result:=1}'
+ }
+'
# shim to make it easier to use os-prober outside d-i
if ! type mapdevfs >/dev/null 2>&1; then
@@ -106,21 +168,20 @@ item_in_dir () {
# We can't always tell the filesystem type up front, but if we have the
# information then we should use it. Note that we can't use block-attr here
# as it's only available in udebs.
-fs_type () {
- if (export PATH="/lib/udev:$PATH"; type vol_id) >/dev/null 2>&1; then
- PATH="/lib/udev:$PATH" vol_id --type "$1" 2>/dev/null
- elif type blkid >/dev/null 2>&1; then
- blkid -o value -s TYPE "$1" 2>/dev/null
- else
- return 0
- fi
+define__fs_type() { # needed so that "set --" does not change $1 of main program!
+ PATH="/lib/udev:$PATH" path_lookup vol_id; if [ "$vol_id" ]; then
+ eval 'fs_type() { '$vol_id' --type "$1" 2>/dev/null; }'
+ else path_lookup blkid; if [ "$blkid" ]; then
+ eval 'fs_type() { '$blkid' -o value -s TYPE "$1" 2>/dev/null; }'
+ else
+ fs_type() { return 0; }
+ fi; fi
}
+define__fs_type
parse_proc_mounts () {
while read -r line; do
- set -f
- set -- $line
- set +f
+ set -f; set -- $line; set +f
printf '%s %s %s\n' "$(mapdevfs "$1")" "$2" "$3"
done
}
@@ -132,56 +193,56 @@ parsefstab () {
:
;;
*)
- set -f
- set -- $line
- set +f
+ set -f; set -- $line; set +f
printf '%s %s %s\n' "$1" "$2" "$3"
;;
esac
done
}
+# Change encoded <tab><newline><space><backslash> back to actual characters.
unescape_mount () {
printf %s "$1" | \
sed 's/\\011/ /g; s/\\012/\n/g; s/\\040/ /g; s/\\134/\\/g'
}
-ro_partition () {
- if type blockdev >/dev/null 2>&1 && \
- [ "$(blockdev --getro "$1")" = 0 ] && \
- blockdev --setro "$1"; then
- cleanup_ro_partitions="${cleanup_ro_partitions:+$cleanup_ro_partitions }$1"
+define__ro_partition() {
+ path_lookup blockdev; if [ "$blockdev" ]; then eval '
+ ro_partition() {
+ if [ "$('$blockdev' --getro "$1")" = 0 ] \
+ && '$blockdev' --setro "$1"; then
+ cleanup_ro_partitions="$cleanup_ro_partitions $1"
trap cleanup EXIT HUP INT QUIT TERM
- fi
-}
-
-find_label () {
- local output
- if type blkid >/dev/null 2>&1; then
- # Hopefully everyone has blkid by now
- output="$(blkid -o device -t LABEL="$1")" || return 1
- echo "$output" | head -n1
- elif [ -h "/dev/disk/by-label/$1" ]; then
- # Last-ditch fallback
- readlink -f "/dev/disk/by-label/$1"
- else
- return 1
- fi
+ fi
+ }'
+ else
+ ro_partition() { :; } # ignore, for benefit of "set -e"
+ fi
}
+define__ro_partition
-find_uuid () {
- local output
- if type blkid >/dev/null 2>&1; then
- # Hopefully everyone has blkid by now
- output="$(blkid -o device -t UUID="$1")" || return 1
- echo "$output" | head -n1
- elif [ -h "/dev/disk/by-uuid/$1" ]; then
- # Last-ditch fallback
- readlink -f "/dev/disk/by-uuid/$1"
- else
- return 1
- fi
+define__find__kind() {
+ local name="$1"
+ local NAME="$2"
+ path_lookup blkid; if [ "$blkid" ]; then eval '
+ find_'$name'() {
+ local output
+ output="$('$blkid' -o device -t '$NAME'="$1")" || return 1
+ echo "$output" | head -n1
+ }'
+ else eval '
+ find_'$name'() {
+ if [ -h "/dev/disk/by-'$name'/$1" ]; then
+ readlink -f "/dev/disk/by-'$name'/$1"
+ else
+ return 1
+ fi
+ }'
+ fi
}
+define__find__kind label LABEL # find_label()
+define__find__kind uuid UUID # find_uuid()
+set +x
# Sets $mountboot as output variable. (We do this rather than requiring a
# subshell so that we can run ro_partition without the cleanup trap firing
@@ -196,9 +257,7 @@ linux_mount_boot () {
# Try to mount any /boot partition.
bootmnt=$(parsefstab < "$tmpmnt/etc/fstab" | grep " /boot ") || true
if [ -n "$bootmnt" ]; then
- set -f
- set -- $bootmnt
- set +f
+ set -f; set -- $bootmnt; set +f
boottomnt=""
# Try to map labels and UUIDs ourselves if possible,
@@ -283,3 +342,15 @@ linux_mount_boot () {
mountboot="$bootpart $mounted"
}
+
+linux_unmount_boot() {
+ mpoint="$1" um_root="$2" um_boot="$3"
+ if [ 1 == "$um_boot" ]; then
+ umount "$mpoint/boot"
+ rmdir "$mpoint/boot" 2>/dev/null || true
+ fi
+ if [ 1 == "$um_root" ]; then
+ umount "$mpoint"
+ rmdir "$mpoint"
+ fi
+}
diff --git a/linux-boot-prober b/linux-boot-prober
index ee8f2b9..4298c1b 100755
--- a/linux-boot-prober
+++ b/linux-boot-prober
@@ -1,14 +1,50 @@
#!/bin/sh
-. /usr/share/os-prober/common.sh
-
set -e
+# $1: optional alternate root for scripts in this package
+# (for testing without install, etc.)
+# Use the default directories if $1 is not supplied.
+export execpfx="${1:-/usr/share/os-prober}"
+export libexecpfx="${1:-/usr/libexec}/linux-boot-probes"
+
+# 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.
+# Therefore use fixed numbers.
+export fd_result=3 # file descriptor for external results
+export fd_logger=9 # file descriptor for input to logger
+
+. $execpfx/common.sh # note: binds fd_result and fd_logger
+
newns "$@"
require_tmpdir
+pipe_mounted=""
+for test in $libexecpfx/mounted/* \
+ $libexecpfx/mounted/x86/* \
+ $libexecpfx/mounted/common/* # last two lines: test without install
+do
+ if [ -r "$test" -a -x "$test" -a ! -d "$test" ]; then
+ pipe_mounted="$pipe_mounted|$test"
+ fi
+done
+pipe_mounted="${pipe_mounted#|}"
+# echo pipe_mounted= "$pipe_mounted" 1>&2
+
+pipe_not_yet=""
+for test in $libexecpfx/*; do
+ if [ -r "$test" -a -x "$test" -a ! -d "$test" ]; then
+ pipe_not_yet="$pipe_not_yet|$test"
+ fi
+done
+pipe_not_yet="${pipe_not_yet#|}"
+# echo pipe_not_yet= "$pipe_not_yet" 1>&2
+
grep "^/dev/" /proc/mounts | parse_proc_mounts >"$OS_PROBER_TMP/mounted-map" || true
-partition="$1"
+
+# READ partition FROM STDIN (THIS IS A CHANGE FROM PREVIOUS USAGE.)
+( ( ( while read partition; do
if [ -z "$partition" ]; then
echo "usage: linux-boot-prober partition" >&2
@@ -21,41 +57,31 @@ if ! mapped="$(mapdevfs "$partition")"; then
fi
if ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map"; then
- for test in /usr/libexec/linux-boot-probes/*; do
- debug "running $test"
- if [ -x $test ] && [ -f $test ]; then
- if $test "$partition"; then
- debug "linux detected by $test"
- break
- fi
- fi
- done
+ echo "$partition" # pipe_not_yet
else
mpoint=$(grep "^$mapped " "$OS_PROBER_TMP/mounted-map" | head -n1 | cut -d " " -f 2)
mpoint="$(unescape_mount "$mpoint")"
- if [ "$mpoint" != "/target/boot" ] && [ "$mpoint" != "/target" ] && [ "$mpoint" != "/" ]; then
+ if [ "$mpoint" != "/target/boot" \
+ -a "$mpoint" != "/target" \
+ -a "$mpoint" != "/" ]; then
type=$(grep "^$mapped " "$OS_PROBER_TMP/mounted-map" | head -n1 | cut -d " " -f 3)
if ! grep -q " $mpoint/boot " "$OS_PROBER_TMP/mounted-map"; then
- linux_mount_boot "$partition" "$mpoint"
+ linux_mount_boot "$partition" "$mpoint" # mountboot="$bootpart $mounted"
bootpart="${mountboot%% *}"
bootmounted="${mountboot#* }"
else
bootpart="$partition"
bootmounted=0
fi
- for test in /usr/libexec/linux-boot-probes/mounted/*; do
- if [ -f $test ] && [ -x $test ]; then
- debug "running $test on mounted $partition"
- if $test "$partition" "$bootpart" "$mpoint" "$type"; then
- debug "$test succeeded"
- break
- fi
- fi
- done
- if [ "$bootmounted" = 1 ]; then
- if ! umount "$mpoint/boot"; then
- warn "failed to umount $mpoint/boot"
- fi
- fi
+ echo "$partition $bootpart $mpoint $type 0 $bootmounted" 1>&8 # pipe_mounted
fi
fi
+
+done \
+ | eval "${pipe_not_yet}"
+) 8>&1 | eval "${pipe_mounted}" \
+ | while read line; do echo "\?unknown $line"; done 1>&2
+) 9>&1 | logger 1>&- # fd_logger
+) 3>&1 # fd_result
+
+# EOF linux-boot-prober
diff --git a/linux-boot-probes/common/50mounted-tests b/linux-boot-probes/common/50mounted-tests
index b649663..481255f 100755
--- a/linux-boot-probes/common/50mounted-tests
+++ b/linux-boot-probes/common/50mounted-tests
@@ -3,35 +3,45 @@
. /usr/share/os-prober/common.sh
set -e
-partition="$1"
+tmpmntdir=/var/lib/os-prober/mount
+mkdir "$tmpmntdir" >/dev/null 2>&1 || true
+(cd $tmpmntdir
+ umount -f lbp* >/dev/null 2>&1 || true
+ rmdir lbp* >/dev/null 2>&1 || true
+)
+while read partition; do
+
+tmpmnt=$tmpmntdir/lbp$(( mount_count+=1 ))
+mkdir $tmpmnt
+
+xtra_types=""
types="$(fs_type "$partition")" || types=NOT-DETECTED
-if [ "$types" = NOT-DETECTED ]; then
+case "$types" in
+ NOT-DETECTED)
debug "$1 type not recognised; skipping"
- exit 0
-elif [ "$types" = swap ]; then
+ continue ;;
+ swap)
debug "$1 is a swap partition; skipping"
- exit 0
-elif [ "$types" = crypto_LUKS ]; then
+ continue ;;
+ crypto_LUKS)
debug "$1 is a LUKS partition; skipping"
- exit 0
-elif [ "$types" = ntfs ]; then
+ continue ;;
+ ntfs)
if type ntfs-3g >/dev/null 2>&1; then
- types='ntfs-3g ntfs'
- fi
-elif [ -z "$types" ]; then
+ xtra_types='ntfs-3g ntfs'
+ fi ;;
+ ?*) # non-null
+ xtra_types="$types" ;; # guess this one first
+ '') # null
if type cryptsetup >/dev/null 2>&1 && \
cryptsetup luksDump "$partition" >/dev/null 2>&1; then
debug "$1 is a LUKS partition; skipping"
- exit 0
+ continue
fi
types="$(grep -v nodev /proc/filesystems)"
-fi
-
-tmpmnt=/var/lib/os-prober/mount
-if [ ! -d "$tmpmnt" ]; then
- mkdir "$tmpmnt"
-fi
+ ;;
+esac
mounted=
if type grub-mount >/dev/null 2>&1 && \
@@ -51,32 +61,13 @@ else
fi
if [ "$mounted" ]; then
- linux_mount_boot "$partition" "$tmpmnt"
+ linux_mount_boot "$partition" "$tmpmnt" # mountboot="$bootpart $mounted"
bootpart="${mountboot%% *}"
mounted="${mountboot#* }"
- for test in /usr/libexec/linux-boot-probes/mounted/*; do
- if [ -f "$test" ] && [ -x "$test" ]; then
- debug "running $test $partition $bootpart $tmpmnt $type"
- if $test "$partition" "$bootpart" "$tmpmnt" "$type"; then
- debug "$test succeeded"
- umount "$tmpmnt/boot" 2>/dev/null || true
- if ! umount "$tmpmnt"; then
- warn "failed to umount $tmpmnt"
- fi
- rmdir "$tmpmnt" || true
- exit 0
- fi
- fi
- done
-
- umount "$tmpmnt/boot" 2>/dev/null || true
- if ! umount "$tmpmnt"; then
- warn "failed to umount $tmpmnt"
- fi
+ echo "$partition $bootpart $tmpmnt $type 1 $mounted" # 1: must unmount
+else
+ rmdir "$tmpmnt" || :
fi
-rmdir "$tmpmnt" || true
-
-# No tests found anything.
-exit 1
+done
diff --git a/linux-boot-probes/mounted/common/40grub2 b/linux-boot-probes/mounted/common/40grub2
index 885614e..49acfd5 100755
--- a/linux-boot-probes/mounted/common/40grub2
+++ b/linux-boot-probes/mounted/common/40grub2
@@ -1,19 +1,12 @@
#!/bin/sh
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
set -e
-partition="$1"
-bootpart="$2"
-mpoint="$3"
-type="$4"
-
-found_item=0
-
entry_result () {
if [ "$ignore_item" = 0 ] && \
[ -n "$kernel" ] && \
[ -e "$mpoint/$kernel" ]; then
- result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters"
+ result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters" # success
found_item=1
fi
kernel=""
@@ -23,6 +16,11 @@ entry_result () {
ignore_item=0
}
+parse_done () {
+ debug "${0##*/}: $parse_part: $lineno lines from $parse_file"
+ debug "${0##*/}: $parse_part: $on_dev \"(on /dev/...)\" were ignored"
+}
+
parse_grub_menu () {
mpoint="$1"
rootpart="$2"
@@ -33,78 +31,158 @@ parse_grub_menu () {
initrd=""
title=""
ignore_item=0
+ lineno=0
+ on_dev=0
+ local OLDIFS="$IFS"
+ local _t
while read line; do
- debug "parsing: $line"
- set -f
- set -- $line
- set +f
+ (( ++lineno ))
+ # debug "parsing: $line"
+ set -f; set -- $line; set +f # apply IFS; do not expand filenames
case "$1" in
- menuentry)
- entry_result
- shift 1
- # The double-quoted string is the title.
- # Make sure to look at the text of the line
- # before 'set' mangled it.
- title="$(echo "$line" | sed -n 's/[^"]*"\(.*\)".*/\1/p' | sed 's/://g')"
- if [ -z "$title" ]; then
- # ... or single-quoted? Be careful
- # to handle constructions like
- # 'foo'\''bar' (which expands to
- # foo'bar, as in shell), and to
- # handle multiple single-quoted
- # strings on the same line.
- title="$(echo "$line" | sed -n "s/[^']*'\(\([^']\|'\\\\''\)*\)'.*/\1/p" | sed "s/'\\\\''/'/; s/://g")"
- fi
- if [ -z "$title" ]; then
- ignore_item=1
- elif echo "$title" | grep -q '(on /dev/[^)]*)$'; then
- log "Skipping entry '$title':"
- log "appears to be an automatic reference taken from another menu.lst"
- ignore_item=1
- fi
+ menuentry)
+ # In each case we remove : because we use a colon
+ # to separate fields in the output.
+ entry_result
+ shift 1
+
+# Shell should provide a "tokenize" operator much like 'set'. The output
+# for a literal string would be a prefix of '"', followed by the value.
+# The difficulty is handling escapes (backslashes).
+#
+# We cannot use 'eval' to tokenize, then take the second token:
+# set -f; eval 'IFS="" set -- '"${line}"; set +f # IFS: split no more!
+# echo $2 # the token after the key word
+# because 'eval' detects syntax errors. (Knowing where the quoting ends
+# is equivalent to lexing the string in the first place.)
+#
+# However, we can try the easy case first, before resorting to 'sed'.
+
+ case "$1" in
+ \"*) IFS='\'; set -f; set -- $line; set +f # detect backslash
+ IFS="$OLDIFS"
+ if (( 1 == $# )); then # no backslash
+ IFS='"'; set -f; set -- $line; set +f # split at double quote
+ IFS="$OLDIFS"
+ strchar_delete "$2" ':'; title="$value"
+ else # the hard case
+ title="$(echo "$line" |
+ $sed -n 's/[^"]*"\(\(\\[$`"\\]\|[^"]\)*\)".*/\1/p' |
+# The $sed above extracts the (longest) left-most double-quoted string, if any.
+# The outer \( \) delimit what will be remembered for \1 .
+# The inner \( \| \)* is a repeated alternation of two choices.
+# The first choice is backslash followed by dollar, backtick, double quote,
+# or backslash; those are the characters for which backslash retains its
+# meaning as an escape character within double quotes.
+# The second choice is any character other than a double quote.
+# A bare double quote would be the terminator.
+ $sed 's/\\\([$`"\\]\)/\1/g; s/://g' )"
+# The $sed above evaluates the double quoting by processing the backslash
+# escapes which are legal within double quotes.
+ fi
;;
- linux)
- # Hack alert: sed off any (hdn,n) but
- # assume the kernel is on the same
- # partition.
- kernel="$(echo "$2" | sed 's/(.*)//')"
- shift 2
- parameters="$@"
- # Systems with a separate /boot will not have
- # the path to the kernel in grub.cfg.
- if [ "$partition" != "$bootpart" ]; then
- kernel="/boot$kernel"
- fi
+ \'*) IFS='\'; set -f; set -- $line; set +f # detect backslash
+ IFS="$OLDIFS"
+ if (( 1 == $# )); then # no backslash
+ IFS="'"; set -f; set -- $line; set +f # split at single quote
+ IFS="$OLDIFS"
+ strchar_delete "$2" ':'; title="$value"
+ else # the hard case
+ title="$(echo "$line" |
+ $sed -n "s/[^']*'\(\([^']\|'\(\\\\'\)*'\)*\)'.*/\1/p" |
+# The $sed above extracts the (longest) left-most single-quoted string, if any.
+# The outer \( \) delimit what will be remembered for \1 .
+# The middle \( \| \)* is a repeated alternation of two choices.
+# The first choice is any character other than single quote.
+# The second choice is two single quotes which surround any number of \' ,
+# which reads as that number of embedded single quotes. 'a'\'\''b' => "a''b"
+ $sed "s/\\\\'/'/g; s/'\\('*\\)'/\\1/g; s/://g" )"
+# The $sed above evaluates the single quoting.
+# Any \' becomes that single quote.
+# Then a run of at least two single quotes becomes the interior of that run.
+ fi
;;
- initrd)
- initrd="$(echo "$2" | sed 's/(.*)//')"
- # Initrd same.
- if [ "$partition" != "$bootpart" ]; then
- initrd="/boot$initrd"
- fi
- ;;
- "}")
- entry_result
+ *) strchr_delete "$1" ':'; title="$value"
;;
+ esac
+
+ _t="${title%(on /dev/[!)]*)}" # speculative
+ if [ -z "$title" ]; then
+ ignore_item=1
+ elif [ ${#_t} -ne ${#title} ]; then # was "(on /dev/...)"
+ if (( ++on_dev <= 2 )); then
+log "Skipping entry '$title':"
+log "appears to be an automatic reference taken from another menu.lst"
+ if (( on_dev == 2)); then
+log "Further \"(on /dev/...)\" entries will be counted but not logged."
+ fi
+ fi
+ ignore_item=1
+ fi
+ ;;
+ linux)
+ # Hack alert: sed off any (hdn,n) but
+ # assume the kernel is on the same
+ # partition.
+ #kernel="$(echo "$2" | $sed 's/(.*)//')"
+ strmid_delete "$2" "(" ")"; kernel="$value"
+ shift 2
+ parameters="$@"
+ # Systems with a separate /boot will not have
+ # the path to the kernel in grub.cfg.
+ if [ "$partition" != "$bootpart" ]; then
+ kernel="/boot$kernel"
+ fi
+ ;;
+ initrd)
+ #initrd="$(echo "$2" | $sed 's/(.*)//')"
+ strmid_delete "$2" "(" ")"; initrd="$value"
+ # Initrd same.
+ if [ "$partition" != "$bootpart" ]; then
+ initrd="/boot$initrd"
+ fi
+ ;;
+ "}")
+ entry_result
+ ;;
esac
done
entry_result
}
-if [ -e "$mpoint/boot/grub/grub.cfg" ] && \
- ([ ! -e "$mpoint/boot/grub/menu.lst" ] || \
- [ "$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
- debug "parsing grub.cfg"
- parse_grub_menu "$mpoint" "$partition" "$bootpart" < "$mpoint/boot/grub2/grub.cfg"
+path_lookup sed # find 'sed' in $PATH; set $sed
+export sed # for sub-shells
+
+trap parse_done EXIT HUP INT QUIT TERM
+
+while read partition bootpart mpoint type um_root um_boot; do
+# echo $0: $read $partition $bootpart $mpoint $type $um_root $um_boot 1>&2
+
+found_item=0
+lineno=0
+
+parse_part="$partition"
+parse_file="$mpoint/boot/grub/menu.lst"
+if [ -e "$mpoint/boot/grub/grub.cfg" ] \
+&& [ ! -e "$mpoint/boot/grub/menu.lst" \
+ -o "$mpoint/boot/grub/grub.cfg" \
+ -nt "$mpoint/boot/grub/menu.lst" ]; then
+ parse_file="$mpoint/boot/grub/grub.cfg"
+elif [ -e "$mpoint/boot/grub2/grub.cfg" ]; then
+ parse_file="$mpoint/boot/grub2/grub.cfg"
+fi
+if [ "$parse_file" ]; then
+ debug "${0##*/}: $parse_part: parsing $parse_file"
+ parse_grub_menu "$mpoint" "$partition" "$bootpart" < "$parse_file"
+ parse_done
fi
if [ "$found_item" = 0 ]; then
- exit 1
+ echo "$partition $bootpart $mpoint $type $um_root $um_boot" # failure
else
- exit 0
+ linux_unmount_boot "$mpoint" "$um_root" "$um_boot"
fi
+
+done
diff --git a/linux-boot-probes/mounted/common/90fallback b/linux-boot-probes/mounted/common/90fallback
index 9ff78e1..dbc9700 100755
--- a/linux-boot-probes/mounted/common/90fallback
+++ b/linux-boot-probes/mounted/common/90fallback
@@ -1,13 +1,11 @@
#!/bin/sh
# Fallback in case nothing else works. Look for vmlinu[xz] file in root and
# /boot, see if there is a matching initrd, and wing it.
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
set -e
-partition="$1"
-bootpart="$2"
-mpoint="$3"
-type="$4"
+while read partition bootpart mpoint type um_root um_boot; do
+# echo $0: $read $partition $bootpart $mpoint $type $um_root $um_boot 1>&2
mappedpartition=$(mapdevfs "$partition" 2>/dev/null) || mappedpartition="$partition"
@@ -21,7 +19,7 @@ for kernpat in /vmlinuz /vmlinux /boot/vmlinuz /boot/vmlinux "/boot/vmlinuz*" \
fi
for kernfile in $(eval ls "$mpoint$kernpat" 2>/dev/null); do
kernbasefile=$(echo "$kernfile" | sed "s!^$mpoint!!")
- if [ -f "$kernfile" ] && [ ! -L "$kernfile" ]; then
+ if [ -f "$kernfile" -a ! -L "$kernfile" ]; then
initrdname=$(echo "$kernfile" | sed "s/vmlinu[zx]/initrd\*/")
# Yellow Dog Linux appends .img to it.
initrdname1="${initrdname}.img"
@@ -36,18 +34,28 @@ for kernpat in /vmlinuz /vmlinux /boot/vmlinuz /boot/vmlinux "/boot/vmlinuz*" \
initrdname4=$(echo "$kernfile" | sed "s/kernel/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
+ if [ "$initrd" != "$kernfile" -a -f "$initrd" -a ! -L "$initrd" ]; then
initrd=$(echo "$initrd" | sed "s!^$mpoint!!")
- result "$partition:$kernbootpart::$kernbasefile:$initrd:root=$mappedpartition"
+result "$partition:$kernbootpart::$kernbasefile:$initrd:root=$mappedpartition" # success
exitcode=0
foundinitrd=1
fi
done
if [ "$foundinitrd" = 0 ]; then
- result "$partition:$kernbootpart::$kernbasefile::root=$mappedpartition"
+result "$partition:$kernbootpart::$kernbasefile::root=$mappedpartition" # success
exitcode=0
fi
fi
done
done
-exit "$exitcode"
+
+if [ 0 != "$exitcode" ]; then
+ echo "$partition $bootpart $mpoint $type" # failure
+fi
+if [ 0 != "$exitcode" ]; then
+ echo "$partition $bootpart $mpoint $type $um_root $um_boot" # failure
+else
+ linux_unmount_boot "$mpoint" "$um_root" "$um_boot"
+fi
+
+done
diff --git a/linux-boot-probes/mounted/x86/40grub b/linux-boot-probes/mounted/x86/40grub
index 08f6605..8d501c7 100755
--- a/linux-boot-probes/mounted/x86/40grub
+++ b/linux-boot-probes/mounted/x86/40grub
@@ -1,19 +1,11 @@
#!/bin/sh
-. /usr/share/os-prober/common.sh
-set -e
-
-partition="$1"
-bootpart="$2"
-mpoint="$3"
-type="$4"
-found_item=0
+. $execpfx/common.sh
+set -e
entry_result () {
- if [ "$ignore_item" = 0 ] && \
- [ -n "$kernel" ] && \
- [ -e "$mpoint/$kernel" ]; then
- result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters"
+ if [ "$ignore_item" = 0 -a -n "$kernel" -a -e "$mpoint/$kernel" ]; then
+ result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters" # success
found_item=1
fi
kernel=""
@@ -23,6 +15,10 @@ entry_result () {
ignore_item=0
}
+parse_done () {
+ debug "${0##*/}: $parse_part: $lineno lines from $grubconf"
+}
+
parse_grub_menu () {
mpoint="$1"
rootpart="$2"
@@ -35,16 +31,18 @@ parse_grub_menu () {
ignore_item=0
while read line; do
+ (( ++lineno ))
#debug "parsing: $line"
- set -f
- set -- $line
- set +f
+ set -f; set -- $line; set +f
case "$1" in
title)
entry_result
shift 1
- title="$(echo "$@" | sed 's/://g')"
- if echo "$title" | grep -q '(on /dev/[^)]*)$'; then
+ #title="$(echo "$@" | sed 's/://g')"
+ strchar_delete "$*" ':'; title="$value"
+ #if echo "$title" | grep -q '(on /dev/[^)]*)$'; then
+ _t="${title%(on /dev/[!)]*)}"
+ if [ ${#_t} -ne ${#title} ]; then # was "(on /dev/...)"
log "Skipping entry '$title':"
log "appears to be an automatic reference taken from another menu.lst"
ignore_item=1
@@ -54,7 +52,8 @@ parse_grub_menu () {
# Hack alert: sed off any (hdn,n) but
# assume the kernel is on the same
# partition.
- kernel="$(echo "$2" | sed 's/(.*)//')"
+ #kernel="$(echo "$2" | sed 's/(.*)//')"
+ strmid_delete "$2" '(' ')'; kernel="$value"
shift 2
parameters="$@"
# Systems with a separate /boot will not have
@@ -66,7 +65,8 @@ parse_grub_menu () {
initrd)
# Hack alert take 2: sed off any (hdn,n)
# See #566102
- initrd="$(echo "$2" | sed 's/(.*)//')"
+ #initrd="$(echo "$2" | sed 's/(.*)//')"
+ strmid_delete "$2" '(' ')'; initrd="$value"
# Initrd same.
if [ "$partition" != "$bootpart" ]; then
initrd="/boot$initrd"
@@ -86,6 +86,14 @@ parse_grub_menu () {
entry_result
}
+trap parse_done EXIT HUP INT QUIT TERM
+
+while read partition bootpart mpoint type um_root um_boot; do
+# echo $0: $read $partition $bootpart $mpoint $type $um_root $um_boot 1>&2
+
+found_item=0
+lineno=0
+
grubconf=
if [ -e "$mpoint/boot/grub/menu.lst" ]; then
grubconf="menu.lst"
@@ -93,15 +101,19 @@ elif [ -e "$mpoint/boot/grub/grub.conf" ]; then
grubconf="grub.conf"
fi
-if [ "$grubconf" ] && \
- ([ ! -e "$mpoint/boot/grub/grub.cfg" ] || \
- [ "$mpoint/boot/grub/$grubconf" -nt "$mpoint/boot/grub/grub.cfg" ]); then
- debug "parsing $grubconf"
+# Parse now using grub1 format unless grub.cfg exists and is newer.
+if [ "$grubconf" -a ! -e "$mpoint/boot/grub/grub.cfg" \
+ -o "$mpoint/boot/grub/$grubconf" -nt "$mpoint/boot/grub/grub.cfg" ]; then
+ # debug "parsing $grubconf"
+ debug "${0##*/}: $parse_part: parsing $mpoint/boot/grub/$grubconf"
parse_grub_menu "$mpoint" "$partition" "$bootpart" < "$mpoint/boot/grub/$grubconf"
+ parse_done
fi
if [ "$found_item" = 0 ]; then
- exit 1
+ echo "$partition $bootpart $mpoint $type $um_root $um_boot" # failure
else
- exit 0
+ linux_unmount_boot "$mpoint" "$um_root" "$um_boot"
fi
+
+done
diff --git a/linux-boot-probes/mounted/x86/50lilo b/linux-boot-probes/mounted/x86/50lilo
index a011b56..6c30bde 100755
--- a/linux-boot-probes/mounted/x86/50lilo
+++ b/linux-boot-probes/mounted/x86/50lilo
@@ -1,27 +1,7 @@
#!/bin/sh
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
set -e
-partition="$1"
-bootpart="$2"
-mpoint="$3"
-type="$4"
-
-found_item=0
-
-title=""
-rootdev=""
-kernel=""
-parameters=""
-initrd=""
-read_only=""
-added_parameters=0
-default_rootdev=""
-default_kernel=""
-default_parameters=""
-default_initrd=""
-default_read_only=""
-
dequote () {
item="${1%\"}"
echo "${item#\"}"
@@ -48,7 +28,7 @@ recordstanza () {
parameters="root=$rootdev $parameters"
fi
parameters="${parameters% }"
- result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters"
+ result "$rootpart:$bootpart:$title:$kernel:$initrd:$parameters" # success
found_item=1
else
debug "cannot find $kernel or $initrd, not recording"
@@ -76,10 +56,8 @@ parse_lilo_conf () {
bootpart="$3"
IFS=" ="
while read line; do
- debug "parsing: $line"
- set -f
- set -- $line
- set +f
+ # debug "parsing: $line"
+ set -f; set -- $line; set +f
case "$1" in
root)
rootdev=$(dequote "$2")
@@ -114,13 +92,33 @@ parse_lilo_conf () {
recordstanza
}
+while read partition bootpart mpoint type um_root um_boot; do
+# echo $0: $read $partition $bootpart $mpoint $type $um_root $um_boot 1>&2
+
+found_item=0
+
+title=""
+rootdev=""
+kernel=""
+parameters=""
+initrd=""
+read_only=""
+added_parameters=0
+default_rootdev=""
+default_kernel=""
+default_parameters=""
+default_initrd=""
+default_read_only=""
+
if [ -e "$mpoint/etc/lilo.conf" ]; then
debug "parsing lilo.conf"
parse_lilo_conf "$mpoint" "$partition" "$bootpart" < "$mpoint/etc/lilo.conf"
fi
if [ "$found_item" = 0 ]; then
- exit 1
+ echo "$partition $bootpart $mpoint $type $um_root $um_boot" # failure
else
- exit 0
+ linux_unmount_boot "$mpoint" "$um_root" "$um_boot"
fi
+
+done
diff --git a/os-prober b/os-prober
index 54798ae..f821d5f 100755
--- a/os-prober
+++ b/os-prober
@@ -1,7 +1,22 @@
#!/bin/sh
set -e
-. /usr/share/os-prober/common.sh
+# $1: optional alternate root for scripts in this package
+# (for testing without install, etc.)
+# Use the default directories if $1 is not supplied.
+export execpfx="${1:-/usr/share/os-prober}"
+export libexecpfx="${1:-/usr/libexec}/os-probes"
+
+# 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.
+# Therefore use fixed numbers.
+export fd_result=3 # file descriptor for external results
+export fd_logger=9 # file descriptor for input to logger
+
+# export PS4=' ${FUNCNAME[0]}@$LINENO < ${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]} :'
+
+. $execpfx/common.sh # note: binds fd_result and fd_logger
newns "$@"
require_tmpdir
@@ -14,15 +29,19 @@ log_output () {
fi
}
-on_sataraid () {
- type dmraid >/dev/null 2>&1 || return 1
- local parent="${1%/*}"
- local device="/dev/${parent##*/}"
- if dmraid -r -c | grep -q "$device"; then
- return 0
- fi
- return 1
-}
+ on_sataraid() { return 1; } # default always returns false
+if type dmraid >/dev/null 2>&1; then
+ dmraid_r_c="$(dmraid -r -c)" || : # a constant!
+ on_sataraid () { # re-define
+ local parent="${1%/*}"
+ local device="/dev/${parent##*/}"
+ local t="${dmraid_r_c#*$device}" # Is $device in $dmraid_r_c ?
+ if [ ${#t} -ne ${#dmraid_r_c} ]; then # yes
+ return 0 # true
+ fi
+ return 1 # false
+ }
+fi
partitions () {
# Exclude partitions that have whole_disk sysfs attribute set.
@@ -30,9 +49,13 @@ partitions () {
# Exclude partitions on physical disks that are part of a
# Serial ATA RAID disk.
for part in /sys/block/*/*[0-9]; do
- if [ -f "$part/start" ] && \
- [ ! -f "$part/whole_disk" ] && ! on_sataraid $part; then
- name="$(echo "${part##*/}" | sed 's,[!.],/,g')"
+ if [ -f "$part/start" -a ! -f "$part/whole_disk" ] \
+ && ! on_sataraid $part; then
+ name="${part##*/}"
+ # An empty name designates a root.
+ if [ 0 -eq ${#name} ]; then
+ name='/'
+ fi
if [ -e "/dev/$name" ]; then
echo "/dev/$name"
fi
@@ -50,11 +73,11 @@ partitions () {
fi
elif [ "$(uname -s)" = Linux ]; then
echo "Cannot find list of partitions! (Try mounting /sys.)" >&2
- exit 1
+ return 1
else
# We don't know how to probe OSes on non-Linux kernels. For
# now, just don't get in the way.
- exit 0
+ return 0
fi
# Add MD RAID devices
@@ -64,41 +87,42 @@ 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 |
- sed "s|-|--|g;s|^[[:space:]]*\(.*\):\(.*\)$|/dev/mapper/\1-\2|")"
+ 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|"
+ # Double the original dashes to distinguish them from the
+ # single dash that will be added later. Ignore leading
+ # whitespace, then find two fields separated by a colon
+ # and replace using /dev/mapper with the fields separated
+ # by a dash.
fi
}
-parse_proc_swaps () {
- while read line; do
- set -f
- set -- $line
- set +f
- echo "$(mapdevfs $1) swap"
- done
-}
-
-parse_proc_mdstat () {
+parse_proc_mdstat () { # filters stdin
+ udevinfo () { return 1; } # default is false and empty
if type udevadm >/dev/null 2>&1; then
- udevinfo () {
- udevadm info "$@"
- }
+ udevinfo () { udevadm info "$@" 2>/dev/null; } # re-define
fi
+ local _udi _t
while read line; do
for word in $line; do
- dev="${word%%[*}"
+ dev="${word%%[*}" # ]
# TODO: factor this out to something in di-utils if
# it's needed elsewhere
- if [ -d /sys/block ] && type udevinfo >/dev/null 2>&1; then
- if ! udevinfo -q path -n "/dev/$dev" 2>/dev/null | \
- grep -q '/.*/.*/'; then
+ if [ -d /sys/block ]; then
+ _udi="$(udevinfo -q path -n "/dev/$dev")"
+ _t="${_udi%/*/*/*}" # trim any 3 '/' and suffix
+ if [ ${#_t} -eq ${#_udi} ]; then # no match
+ continue
+ fi
+ else
+ _t="${dev%/part*}" # trim "/part" and suffix
+ if [ ${#_t} -eq ${#dev} ]; then # no match
continue
fi
- elif ! echo "$dev" | grep -q "/part"; then
- continue
fi
raidpart="/dev/$dev"
- echo "$(mapdevfs "$raidpart")"
+ echo ":$(mapdevfs "$raidpart")" # ':' marks beginning
done
done
}
@@ -106,66 +130,110 @@ parse_proc_mdstat () {
# Needed for idempotency
rm -f /var/lib/os-prober/labels
-for prog in /usr/libexec/os-probes/init/*; do
- if [ -x "$prog" ] && [ -f "$prog" ]; then
+for prog in $libexecpfx/init/*; do
+ if [ -r "$prog" -a -x "$prog" -a ! -d "$prog" ]; then
"$prog" || true
fi
done
# We need to properly canonicalize partitions with mount points and partitions
# used in RAID
-grep "^/dev/" /proc/mounts | parse_proc_mounts >"$OS_PROBER_TMP/mounted-map" || true
-: >"$OS_PROBER_TMP/swaps-map"
-if [ -f /proc/swaps ]; then
- grep "^/dev/" /proc/swaps | parse_proc_swaps >"$OS_PROBER_TMP/swaps-map" || true
-fi
-: >"$OS_PROBER_TMP/raided-map"
-if [ -f /proc/mdstat ] ; then
- grep "^md" /proc/mdstat | cut -d: -f2- | parse_proc_mdstat >"$OS_PROBER_TMP/raided-map" || true
-fi
-for partition in $(partitions); do
+# Parse /proc/mounts.
+# bash would use two associative arrays, indexed by $part, to store results.
+# dash has no arrays, so use variables with stylized names.
+while read part mpoint fs_type _rest; do
+ _t="${part#/dev/}"; if [ ${#_t} -ne ${#part} -a "$mpoint" -a "$fs_type" ]; then
+ str_tame "$(mapdevfs "$part")"
+ eval 'MPOINT_'$value'="$mpoint" FS_TYPE_'$value'="$fs_type"'
+ fi
+done </proc/mounts
+
+# Parse /proc/swaps.
+# bash would use an associative array, indexed by $part, to store results.
+# dash has no arrays, so use variables with stylized names.
+while read part _rest; do
+ _t="${part#/dev/}"; if [ ${#_t} -ne ${#part} ]; then
+ # line from file begins with "/dev/"
+ str_tame "$(mapdevfs "$part")"
+ eval SWAP_$value=1
+ fi
+done </proc/swaps
+
+# Store results in a string, with $part marked by a prefix ':'.
+raided=""
+[[ -f /proc/mdstat ]] && raided=$(grep "^md" /proc/mdstat | cut -d: -f2- | parse_proc_mdstat )
+
+pipe_mounted=""
+for test in $libexecpfx/mounted/* \
+ $libexecpfx/mounted/x86/* \
+ $libexecpfx/mounted/common/* # last two lines: test without install
+do
+ if [ -r "$test" -a -x "$test" -a ! -d "$test" ]; then
+ pipe_mounted="$pipe_mounted|$test"
+ fi
+done
+pipe_mounted="${pipe_mounted#|}"
+# echo pipe_mounted= "$pipe_mounted" 1>&2
+
+pipe_not_yet=""
+for test in $libexecpfx/*; do
+ if [ -r "$test" -a -x "$test" -a ! -d "$test" ]; then
+ pipe_not_yet="$pipe_not_yet|$test"
+ fi
+done
+pipe_not_yet="${pipe_not_yet#|}"
+# echo pipe_not_yet= "$pipe_not_yet" 1>&2
+
+# Arrange the processing as a chain of filters, to enable parallelism.
+# When a filter recognizes a partition, then the filter uses the 'result'
+# function to write the details to the fd_result pipe. Each filter
+# passes any unrecognized partition on to the next filter by using stdout.
+# Logging is performed by writing to fd_logger, which goes to a single
+# logger process that reads its stdin. Stderr remains available for
+# debugging and emergencies.
+# Plumbing by John Reiser (jreiser bitwagon com), November 2012.
+
+partitions | ( ( (
+ while read partition ; do
+ # Distribute to proper entrypoint in pipeline of filters.
+
if ! mapped="$(mapdevfs "$partition")"; then
log "Device '$partition' does not exist; skipping"
continue
fi
-
- # Skip partitions used in software RAID arrays
- if grep -q "^$mapped" "$OS_PROBER_TMP/raided-map" ; then
+ str_tame "$mapped"; tamed="$value"
+ raid="${raided%:$mapped}"; if [ ${#raid} -ne ${#raided} ]; then
debug "$partition: part of software raid array"
continue
fi
-
- # Skip partitions used as active swap
- if grep -q "^$mapped " "$OS_PROBER_TMP/swaps-map" ; then
+ eval 'swap="$SWAP_'$tamed'"'; if [ -n "$swap" ]; then
debug "$partition: is active swap"
continue
fi
-
- if ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map" ; then
- for test in /usr/libexec/os-probes/*; do
- if [ -f "$test" ] && [ -x "$test" ]; then
- debug "running $test on $partition"
- if "$test" "$partition"; then
- debug "os detected by $test"
- break
- fi
- fi
- done
- else
- mpoint=$(grep "^$mapped " "$OS_PROBER_TMP/mounted-map" | head -n1 | cut -d " " -f 2)
+ eval 'mpoint="$MPOINT_'$tamed'"'; if [ -z "$mpoint" ]; then
+ echo "$partition" # not yet mounted
+ else # already mounted
mpoint="$(unescape_mount "$mpoint")"
- if [ "$mpoint" != "/target/boot" ] && [ "$mpoint" != "/target" ] && [ "$mpoint" != "/" ]; then
- type=$(grep "^$mapped " "$OS_PROBER_TMP/mounted-map" | head -n1 | cut -d " " -f 3)
- for test in /usr/libexec/os-probes/mounted/*; do
- if [ -f "$test" ] && [ -x "$test" ]; then
- debug "running $test on mounted $partition"
- if "$test" "$partition" "$mpoint" "$type"; then
- debug "os detected by $test"
- break
- fi
- fi
- done
+ if [ "$mpoint" != "/target/boot" \
+ -a "$mpoint" != "/target" \
+ -a "$mpoint" != "/" ]; then
+ eval 'type="$FS_TYPE_'$tamed'"'
+ echo "$partition $mpoint $type 0" 1>&8 # 0: do not unmount
fi
fi
-done
+ done \
+ | eval "${pipe_not_yet}"
+) 8>&1 | eval "${pipe_mounted}" | while read line; do
+ echo '?'unknown "$line"
+ set -f; set -- $line; set +f
+ part="$1"; dir="$2"; type="$3"; discard="$4"
+ if [ 1 == "$discard" ]; then
+ umount "$dir"
+ rmdir "$dir"
+ fi
+ done 1>&2
+) 9>&1 | logger 1>&- # fd_logger
+) 3>&1 # fd_result
+
+# EOF os-prober
diff --git a/os-probes/common/50mounted-tests b/os-probes/common/50mounted-tests
index 4e0f6d6..33824d5 100755
--- a/os-probes/common/50mounted-tests
+++ b/os-probes/common/50mounted-tests
@@ -1,49 +1,63 @@
#!/bin/sh
# Sub-tests that require a mounted partition.
set -e
-partition="$1"
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
+delay_types="" # file system types that should be checked last
+kfs_types="" # kernel file system types
+for mod_type in $(grep -v nodev /proc/filesystems); do
+ # hfsplus filesystems are mountable as hfs. Try hfs last so
+ # that we can tell the difference.
+ if [ "$mod_type" = hfs ]; then
+ delay_types="$delay_types $mod_type"
+ elif [ "$mod_type" = fuseblk ]; then
+ if type ntfs-3g >/dev/null 2>&1; then
+ kfs_types="$kfs_types ntfs-3g"
+ fi
+ else
+ kfs_types="$kfs_types $mod_type"
+ fi
+done
+
+tmpmntdir=/var/lib/os-prober/mount
+mkdir "$tmpmntdir" >/dev/null 2>&1 || true
+(cd $tmpmntdir
+ umount -f osp* >/dev/null 2>&1 || true
+ rmdir osp* >/dev/null 2>&1 || true
+)
+
+
+while read partition; do
+
+tmpmnt=$tmpmntdir/osp$(( mount_count+=1 ))
+mkdir $tmpmnt
+
+xtra_types=""
types="$(fs_type "$partition")" || types=NOT-DETECTED
-if [ "$types" = NOT-DETECTED ]; then
+case "$types" in
+NOT-DETECTED)
debug "$1 type not recognised; skipping"
- exit 0
-elif [ "$types" = swap ]; then
+ continue ;;
+swap)
debug "$1 is a swap partition; skipping"
- exit 0
-elif [ "$types" = crypto_LUKS ]; then
+ continue ;;
+crypto_LUKS)
debug "$1 is a LUKS partition; skipping"
- exit 0
-elif [ "$types" = ntfs ]; then
+ continue ;;
+ntfs)
if type ntfs-3g >/dev/null 2>&1; then
- types='ntfs-3g ntfs'
- fi
-elif [ -z "$types" ]; then
+ xtra_types='ntfs-3g ntfs'
+ fi ;;
+?*) # non-null
+ xtra_types="$types" ;; # guess this one first
+'') # null
if type cryptsetup >/dev/null 2>&1 && \
cryptsetup luksDump "$partition" >/dev/null 2>&1; then
debug "$1 is a LUKS partition; skipping"
- exit 0
- fi
- for type in $(grep -v nodev /proc/filesystems); do
- # hfsplus filesystems are mountable as hfs. Try hfs last so
- # that we can tell the difference.
- if [ "$type" = hfs ]; then
- delaytypes="${delaytypes:+$delaytypes }$type"
- elif [ "$type" = fuseblk ]; then
- if type ntfs-3g >/dev/null 2>&1; then
- types="${types:+$types }ntfs-3g"
- fi
- else
- types="${types:+$types }$type"
- fi
- done
-fi
-
-tmpmnt=/var/lib/os-prober/mount
-if [ ! -d "$tmpmnt" ]; then
- mkdir "$tmpmnt"
-fi
+ continue
+ fi ;;
+esac
mounted=
if type grub-mount >/dev/null 2>&1 && \
@@ -59,9 +73,9 @@ if type grub-mount >/dev/null 2>&1 && \
fi
else
ro_partition "$partition"
- for type in $types $delaytypes; do
+ for type in $xtra_types $kfs_types $delay_types; do
if mount -o ro -t "$type" "$partition" "$tmpmnt" 2>/dev/null; then
- debug "mounted as $type filesystem"
+ # debug "mounted as $type filesystem"
mounted=1
break
fi
@@ -69,25 +83,9 @@ else
fi
if [ "$mounted" ]; then
- for test in /usr/libexec/os-probes/mounted/*; do
- debug "running subtest $test"
- if [ -f "$test" ] && [ -x "$test" ]; then
- if "$test" "$partition" "$tmpmnt" "$type"; then
- debug "os found by subtest $test"
- if ! umount "$tmpmnt"; then
- warn "failed to umount $tmpmnt"
- fi
- rmdir "$tmpmnt" || true
- exit 0
- fi
- fi
- done
- if ! umount "$tmpmnt"; then
- warn "failed to umount $tmpmnt"
- fi
+ echo "$partition $tmpmnt $type 1" # 1: must unmount
+else
+ rmdir "$tmpmnt" || :
fi
-rmdir "$tmpmnt" || true
-
-# No tests found anything.
-exit 1
+done
diff --git a/os-probes/mounted/common/40lsb b/os-probes/mounted/common/40lsb
index ce8d4e1..2b7e576 100755
--- a/os-probes/mounted/common/40lsb
+++ b/os-probes/mounted/common/40lsb
@@ -2,30 +2,25 @@
# Test for LSB systems.
set -e
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
-partition="$1"
-dir="$2"
-type="$3"
-
-lsb_field () {
- file="$1"
- field="$2"
- grep ^"$field" "$file" | cut -d = -f 2 | sed 's/^"//' | sed 's/"$//' | sed 's/:/ /g'
-}
+while read partition dir type discard; do
file="$dir/etc/lsb-release"
if [ ! -e "$file" ]; then
- exit 1
+ echo "$partition $dir $type $discard"; continue # failure
fi
-release=$(lsb_field "$file" DISTRIB_RELEASE)
+while read line; do eval "$line"; done < $file
+
+release="$DISTRIB_RELEASE"
if [ -z "$release" ]; then
- release=$(lsb_field "$file" DISTRIB_CODENAME)
+ release="$DISTRIB_CODENAME"
fi
-description=$(lsb_field "$file" DISTRIB_DESCRIPTION)
+
+description="$DISTRIB_DESCRIPTION"
if [ -z "$description" ]; then
- description=$(lsb_field "$file" DISTRIB_CODENAME)
+ description="$DISTRIB_CODENAME"
fi
if [ -n "$description" ]; then
@@ -35,14 +30,19 @@ if [ -n "$description" ]; then
long="$description"
fi
else
- exit 1
+ echo "$partition $dir $type $discard"; continue # failure
fi
-short=$(lsb_field "$file" DISTRIB_ID | sed 's/ //g')
+strchar_delete "$DISTRIB_ID" ' '; short="$value"
if [ -z "$short" ]; then
short="UnknownLSB"
fi
-label="$(count_next_label "$short")"
-result "$partition:$long:$label:linux"
-exit 0
+result "$partition:$long:$short$((label += 1)):linux" # success
+
+if [ 1 == "$discard" ]; then
+ umount $dir
+ rmdir $dir
+fi
+
+done
diff --git a/os-probes/mounted/common/90linux-distro b/os-probes/mounted/common/90linux-distro
index fb56b61..87ec273 100755
--- a/os-probes/mounted/common/90linux-distro
+++ b/os-probes/mounted/common/90linux-distro
@@ -2,134 +2,196 @@
# Test for linux distributions.
set -e
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
+path_lookup cat; export cat # search once only
-partition="$1"
-dir="$2"
-type="$3"
+origdir=$PWD
+
+function fail() {
+ echo "$partition $dir $type $discard" 1>&7 # failure
+
+ cd $origdir
+}
+
+function succeed() {
+ echo "$partition:$long:$short" 1>&6 # success
+
+ cd $origdir
+ if [ 1 == "$discard" ]; then
+ umount "$dir"
+ rmdir "$dir"
+ fi
+}
+
+function filter() {
+ while read partition dir type discard; do
# 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
# better. Make sure this test has a high number so that more accurate tests
# can come first.
# TODO: look for ld-linux.so on arches that have it
-if ls "$dir"/lib*/ld*.so* >/dev/null 2>/dev/null && [ -d "$dir/boot" ] \
- || ls "$dir"/usr/libexec*/ld*.so* >/dev/null 2>/dev/null; then
- if [ -e "$dir/etc/debian_version" ]; then
+
+# Check for any actual file that matches the pattern.
+# If pathname expansion finds no matches then it returns the pattern itself,
+# and the '[ -r "$1" ]' fails.
+# If pathname expansion does find a match then the '[ -r "$1" ]' succeeds.
+# The syntax with braces avoids using a subprocess.
+# All that saves 0.02 seconds over using the exit code of /bin/ls.
+# It matters when you have several dozen partitions to check.
+ if { set -- "$dir"/lib*/ld*.so*; [ -r "$1" ]; } \
+ || { set -- "$dir"/usr/libexec*/ld*.so*; [ -r "$1" ]; } ; then
+ cd "$dir"/etc 2>/dev/null || { fail; continue; }
+ short=""
+ set -- *[_-]version
+
+ for file do case "$file" in
+ debian_version)
short="Debian"
- long="$(printf "Debian GNU/Linux (%s)\n" "$(cat "$dir/etc/debian_version")")"
+ long="$(printf "Debian GNU/Linux (%s)\n" "$($cat "$dir/etc/debian_version")")" ;;
+ kanotix-version)
+ short="Kanotix"
+ long="$($cat "$dir/etc/kanotix-version")" ;;
+ slackware-version)
+ short="Slackware"
+ long="$(printf "Slackware Linux (%s)\n" "$($cat "$dir/etc/slackware-version")")" ;;
+ esac; done
+ if [ -n "$short" ]; then succeed; continue; fi
+
# RPM derived distributions may also have a redhat-release or
- # mandrake-release, so check their files first.
- elif [ -e "$dir/etc/altlinux-release" ]; then
+ # mandrake-release. Set base first, then override using derived.
+ set -- *-release
+
+ for file do case "$file" in # base distro
+ redhat-release)
+ short="RedHat"
+ long="$($cat "$dir/etc/redhat-release")" ;;
+ esac; done
+
+ for file do case "$file" in # possible intermediate distro
+ fedora-release)
+ short="Fedora"
+ long="$($cat "$dir/etc/fedora-release")" ;;
+ esac; done
+
+ for file do case "$file" in # possible intermediate distro
+ mandrake-release)
+ short="Mandrake"
+ long="$($cat "$dir/etc/mandrake-release")" ;;
+ esac; done
+
+ for file do case "$file" in # possible derived distro
+ SuSE-release)
+ short="SuSE"
+ long="$(head -n 1 "$dir/etc/SuSE-release")" ;;
+ altlinux-release)
short="ALTLinux"
- long="$(cat "$dir/etc/altlinux-release")"
- elif [ -e "$dir/etc/magic-release" ]; then
+ long="$($cat "$dir/etc/altlinux-release")" ;;
+ magic-release)
short="Magic"
- long="$(cat "$dir/etc/magic-release")"
- elif [ -e "$dir/etc/blackPanther-release" ]; then
+ long="$($cat "$dir/etc/magic-release")" ;;
+ blackPanther-release)
short="blackPanther"
- long="$(cat "$dir/etc/blackPanther-release")"
- elif [ -e "$dir/etc/ark-release" ]; then
+ long="$($cat "$dir/etc/blackPanther-release")" ;;
+ ark-release)
short="Ark"
- long="$(cat "$dir/etc/ark-release")"
- elif [ -e "$dir/etc/arch-release" ]; then
+ long="$($cat "$dir/etc/ark-release")" ;;
+ arch-release)
short="Arch"
- long="$(cat "$dir/etc/arch-release")"
- elif [ -e "$dir/etc/asplinux-release" ]; then
+ long="$($cat "$dir/etc/arch-release")" ;;
+ asplinux-release)
short="ASPLinux"
- long="$(cat "$dir/etc/asplinux-release")"
- elif [ -e "$dir/etc/lvr-release" ]; then
+ long="$($cat "$dir/etc/asplinux-release")" ;;
+ lvr-release)
short="LvR"
- long="$(cat "$dir/etc/lvr-release")"
- elif [ -e "$dir/etc/caos-release" ]; then
+ long="$($cat "$dir/etc/lvr-release")" ;;
+ caos-release)
short="cAos"
- long="$(cat "$dir/etc/caos-release")"
- elif [ -e "$dir/etc/aurox-release" ]; then
+ long="$($cat "$dir/etc/caos-release")" ;;
+ aurox-release)
short="Aurox"
- long="$(cat "$dir/etc/aurox-release")"
- elif [ -e "$dir/etc/engarde-release" ]; then
+ long="$($cat "$dir/etc/aurox-release")" ;;
+ engarde-release)
short="EnGarde"
- long="$(cat "$dir/etc/engarde-release")"
- elif [ -e "$dir/etc/vine-release" ]; then
+ long="$($cat "$dir/etc/engarde-release")" ;;
+ vine-release)
short="Vine"
- long="$(cat "$dir/etc/vine-release")"
- elif [ -e "$dir/etc/whitebox-release" ]; then
+ long="$($cat "$dir/etc/vine-release")" ;;
+ whitebox-release)
short="WhiteBox"
- long="$(cat "$dir/etc/whitebox-release")"
- elif [ -e "$dir/etc/pld-release" ]; then
+ long="$($cat "$dir/etc/whitebox-release")" ;;
+ pld-release)
short="PLD"
- long="$(cat "$dir/etc/pld-release")"
- elif [ -e "$dir/etc/startcom-release" ]; then
+ long="$($cat "$dir/etc/pld-release")" ;;
+ startcom-release)
short="StartCom"
- long="$(cat "$dir/etc/startcom-release")"
- elif [ -e "$dir/etc/trustix-release" ]; then
+ long="$($cat "$dir/etc/startcom-release")" ;;
+ trustix-release)
short="Trustix"
- long="$(cat "$dir/etc/trustix-release")"
- elif [ -e "$dir/etc/openna-release" ]; then
+ long="$($cat "$dir/etc/trustix-release")" ;;
+ openna-release)
short="OpenNA"
- long="$(cat "$dir/etc/openna-release")"
- elif [ -e "$dir/etc/conectiva-release" ]; then
+ long="$($cat "$dir/etc/openna-release")" ;;
+ conectiva-release)
short="Conectiva"
- long="$(cat "$dir/etc/conectiva-release")"
- elif [ -e "$dir/etc/mandrake-release" ]; then
- short="Mandrake"
- long="$(cat "$dir/etc/mandrake-release")"
- elif [ -e "$dir/etc/fedora-release" ]; then
- short="Fedora"
- long="$(cat "$dir/etc/fedora-release")"
- elif [ -e "$dir/etc/redhat-release" ]; then
- short="RedHat"
- long="$(cat "$dir/etc/redhat-release")"
- elif [ -e "$dir/etc/SuSE-release" ]; then
- short="SuSE"
- long="$(head -n 1 "$dir/etc/SuSE-release")"
- elif [ -e "$dir/etc/gentoo-release" ]; then
+ long="$($cat "$dir/etc/conectiva-release")" ;;
+ gentoo-release)
short="Gentoo"
- long="$(cat "$dir/etc/gentoo-release")"
- elif [ -e "$dir/etc/cobalt-release" ]; then
+ long="$($cat "$dir/etc/gentoo-release")" ;;
+ cobalt-release)
short="Cobalt"
- long="$(cat "$dir/etc/cobalt-release")"
- elif [ -e "$dir/etc/yellowdog-release" ]; then
+ long="$($cat "$dir/etc/cobalt-release")" ;;
+ yellowdog-release)
short="YellowDog"
- long="$(cat "$dir/etc/yellowdog-release")"
- elif [ -e "$dir/etc/turbolinux-release" ]; then
+ long="$($cat "$dir/etc/yellowdog-release")" ;;
+ turbolinux-release)
short="Turbolinux"
- long="$(cat "$dir/etc/turbolinux-release")"
- elif [ -e "$dir/etc/pardus-release" ]; then
+ long="$($cat "$dir/etc/turbolinux-release")" ;;
+ pardus-release)
short="Pardus"
- long="$(cat "$dir/etc/pardus-release")"
- elif [ -e "$dir/etc/kanotix-version" ]; then
- short="Kanotix"
- long="$(cat "$dir/etc/kanotix-version")"
- elif [ -e "$dir/etc/slackware-version" ]; then
- short="Slackware"
- long="$(printf "Slackware Linux (%s)\n" "$(cat "$dir/etc/slackware-version")")"
- elif [ -e "$dir/sbin/pkgtool" ]; then
+ long="$($cat "$dir/etc/pardus-release")" ;;
+ frugalware-release)
+ short="Frugalware Linux"
+ long="$($cat "$dir/etc/frugalware-release")" ;;
+ kdemar-release)
+ short="K-DEMar"
+ long="$(printf "K-DEMar GNU/Linux (%s)\n" "$($cat "$dir/etc/kdemar-release")")" ;;
+ lfs-release)
+ short="LFS"
+ long="$(printf "Linux From Scratch (%s)\n" "$($cat "$dir/etc/lfs-release")")" ;;
+ meego-release)
+ short="MeeGo"
+ long="$(head -1 "$dir/etc/meego-release")" ;;
+ esac; done
+ if [ -n "$short" ]; then succeed; continue; fi
+
+ # The oddballs.
+ if [ -e "$dir/sbin/pkgtool" ]; then
short="Slackware"
long="Slackware Linux"
elif grep -qs OpenLinux "$dir/etc/issue"; then
short="Caldera"
long="Caldera OpenLinux"
- elif [ -e "$dir/etc/frugalware-release" ]; then
- short="Frugalware Linux"
- long="$(cat "$dir/etc/frugalware-release")"
- elif [ -e "$dir/etc/kdemar-release" ]; then
- short="K-DEMar"
- long="$(printf "K-DEMar GNU/Linux (%s)\n" "$(cat "$dir/etc/kdemar-release")")"
- elif [ -e "$dir/etc/lfs-release" ]; then
- short="LFS"
- long="$(printf "Linux From Scratch (%s)\n" "$(cat "$dir/etc/lfs-release")")"
- elif [ -e "$dir/etc/meego-release" ]; then
- short="MeeGo"
- long="$(head -1 "$dir/etc/meego-release")"
else
short="Linux"
long="unknown Linux distribution"
fi
-
- label="$(count_next_label "$short")"
- result "$partition:$long:$label:linux"
- exit 0
-else
- exit 1
-fi
+
+ succeed
+ else
+ fail
+ fi
+ done # read next partition
+}
+
+# Use two parallel streams to filter alternating partitions.
+# Count the over-all results to avoid a race when incrementing the label.
+( ( ( while read line; do echo "$line" 1>&5 # side2
+ if read line; then echo "$line" # side1
+ fi
+ done | filter 1>&- # side1
+) 5>&1 | filter 1>&- # side2
+) 6>&1 | while read line; do result "$line$((label += 1)):linux"; done
+) 7>&1
+
+# EOF
diff --git a/os-probes/mounted/powerpc/20macosx b/os-probes/mounted/powerpc/20macosx
index 16d9da6..e97f30d 100755
--- a/os-probes/mounted/powerpc/20macosx
+++ b/os-probes/mounted/powerpc/20macosx
@@ -6,10 +6,6 @@ partition="$1"
mpoint="$2"
type="$3"
-debug() {
- logger -t macosx-prober "debug: $@"
-}
-
# Weed out stuff that doesn't apply to us
case "$type" in
hfsplus) debug "$1 is an HFS+ partition" ;;
diff --git a/os-probes/mounted/powerpc/20macosx.macosxdummyfix b/os-probes/mounted/powerpc/20macosx.macosxdummyfix
index dd4207f..5ad29da 100755
--- a/os-probes/mounted/powerpc/20macosx.macosxdummyfix
+++ b/os-probes/mounted/powerpc/20macosx.macosxdummyfix
@@ -6,10 +6,6 @@ partition="$1"
mpoint="$2"
type="$3"
-debug() {
- logger -t macosx-prober "debug: $@"
-}
-
# Weed out stuff that doesn't apply to us
case "$type" in
hfsplus) debug "$1 is an HFS+ partition" ;;
diff --git a/os-probes/mounted/x86/10freedos b/os-probes/mounted/x86/10freedos
index 94388f3..a15a957 100755
--- a/os-probes/mounted/x86/10freedos
+++ b/os-probes/mounted/x86/10freedos
@@ -1,23 +1,26 @@
#!/bin/sh
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
-partition="$1"
-mpoint="$2"
-type="$3"
+while read partition dir type discard; do
# 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" ;;
fat) debug "$1 is a FAT partition (mounted by GRUB)" ;;
- *) debug "$1 is not a FAT partition: exiting"; exit 1 ;;
+ *) # debug "$1 is not a FAT partition"
+ echo "$partition $dir $type $discard"; continue ;; # failure
esac
if item_in_dir -q kernel.sys "$2" && item_in_dir -q command.com "$2"; then
- label="$(count_next_label FreeDOS)"
- result "$1:FreeDOS:$label:chain"
- exit 0
+ result "$1:FreeDOS:FreeDos$((label += 1)):chain" # success
+ if [ 1 == "$discard" ]; then
+ umount "$dir"
+ rmdir "$dir"
+ fi
else
- exit 1
+ echo "$partition $dir $type $discard"; continue # failure
fi
+
+done
diff --git a/os-probes/mounted/x86/10qnx b/os-probes/mounted/x86/10qnx
index 8d40398..6f1dc70 100755
--- a/os-probes/mounted/x86/10qnx
+++ b/os-probes/mounted/x86/10qnx
@@ -1,21 +1,25 @@
#!/bin/sh
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
-partition="$1"
-mpoint="$2"
-type="$3"
+while read partition dir type discard; do
# Weed out stuff that doesn't apply to us
case "$type" in
qnx4) debug "$partition is a QNX4 partition" ;;
- *) debug "$partition is not a QNX4 partition: exiting"; exit 1 ;;
+ *) # debug "$partition is not a QNX4 partition"
+ echo "$partition $dir $type $discard"; continue ;; # failure
esac
if [ -e "$mpoint/.boot" ]; then
- label="$(count_next_label QNX)"
- result "$partition:QNX:$label:chain"
- exit 0
+ result "$partition:QNX:QNX$((label += 1)):chain" # success
+
+ if [ 1 == "$discard" ]; then
+ umount "$dir"
+ rmdir "$dir"
+ fi
else
- exit 1
+ echo "$partition $dir $type $discard"; continue # failure
fi
+
+done
diff --git a/os-probes/mounted/x86/20microsoft b/os-probes/mounted/x86/20microsoft
index 644d63c..f68d453 100755
--- a/os-probes/mounted/x86/20microsoft
+++ b/os-probes/mounted/x86/20microsoft
@@ -1,43 +1,44 @@
#!/bin/sh
# Detects all Microsoft OSes on a collection of partitions.
-. /usr/share/os-prober/common.sh
+set -e
-partition="$1"
-mpoint="$2"
-type="$3"
+. $execpfx/common.sh
+
+while read partition dir type discard; do
# Weed out stuff that doesn't apply to us
case "$type" in
- ntfs|ntfs-3g) debug "$1 is a NTFS partition" ;;
- vfat) debug "$1 is a FAT32 partition" ;;
- msdos) debug "$1 is a FAT16 partition" ;;
- fat) debug "$1 is a FAT partition (mounted by GRUB)" ;;
- fuse|fuseblk) debug "$1 is a FUSE partition" ;; # might be ntfs-3g
- *) debug "$1 is not a MS partition: exiting"; exit 1 ;;
+ ntfs|ntfs-3g) debug "$partition is a NTFS partition" ;;
+ vfat) debug "$partition is a FAT32 partition" ;;
+ msdos) debug "$partition is a FAT16 partition" ;;
+ fat) debug "$partition is a FAT partition (mounted by GRUB)" ;;
+ fuse|fuseblk) debug "$partition is a FUSE partition" ;; # might be ntfs-3g
+ *) # debug "$partition is not a MS partition"
+ echo "$partition $dir $type $discard"; continue ;; # failure
esac
found=
# Vista (previously Longhorn)
-if item_in_dir -q bootmgr "$2"; then
+if item_in_dir -q bootmgr "$dir"; then
# there might be different boot directories in different case as:
# boot Boot BOOT
- for boot in $(item_in_dir boot "$2"); do
- bcd=$(item_in_dir bcd "$2/$boot")
+ for boot in $(item_in_dir boot "$dir"); do
+ bcd=$(item_in_dir bcd "$dir/$boot")
if [ -n "$bcd" ]; then
- if grep -qs "W.i.n.d.o.w.s. .8" "$2/$boot/$bcd"; then
+ if grep -qs "W.i.n.d.o.w.s. .8" "$dir/$boot/$bcd"; then
long="Windows 8 (loader)"
- elif grep -qs "W.i.n.d.o.w.s. .7" "$2/$boot/$bcd"; then
+ elif grep -qs "W.i.n.d.o.w.s. .7" "$dir/$boot/$bcd"; then
long="Windows 7 (loader)"
- elif grep -qs "W.i.n.d.o.w.s. .V.i.s.t.a" "$2/$boot/$bcd"; then
+ elif grep -qs "W.i.n.d.o.w.s. .V.i.s.t.a" "$dir/$boot/$bcd"; then
long="Windows Vista (loader)"
- elif grep -qs "W.i.n.d.o.w.s. .S.e.r.v.e.r. .2.0.0.8. .R.2." "$2/$boot/$bcd"; then
+ elif grep -qs "W.i.n.d.o.w.s. .S.e.r.v.e.r. .2.0.0.8. .R.2." "$dir/$boot/$bcd"; then
long="Windows Server 2008 R2 (loader)"
- elif grep -qs "W.i.n.d.o.w.s. .S.e.r.v.e.r. .2.0.0.8." "$2/$boot/$bcd"; then
+ elif grep -qs "W.i.n.d.o.w.s. .S.e.r.v.e.r. .2.0.0.8." "$dir/$boot/$bcd"; then
long="Windows Server 2008 (loader)"
- elif grep -qs "W.i.n.d.o.w.s. .R.e.c.o.v.e.r.y. .E.n.v.i.r.o.n.m.e.n.t" "$2/$boot/$bcd"; then
+ elif grep -qs "W.i.n.d.o.w.s. .R.e.c.o.v.e.r.y. .E.n.v.i.r.o.n.m.e.n.t" "$dir/$boot/$bcd"; then
long="Windows Recovery Environment (loader)"
- elif grep -qs "W.i.n.d.o.w.s. .S.e.t.u.p" "$2/$boot/$bcd"; then
+ elif grep -qs "W.i.n.d.o.w.s. .S.e.t.u.p" "$dir/$boot/$bcd"; then
long="Windows Recovery Environment (loader)"
else
long="Windows Vista (loader)"
@@ -52,25 +53,25 @@ if item_in_dir -q bootmgr "$2"; then
fi
# 2000/XP/NT4.0
-if [ -z "$found" ] && item_in_dir -q ntldr "$2" && item_in_dir -q ntdetect.com "$2"; then
+if [ -z "$found" ] && item_in_dir -q ntldr "$dir" && item_in_dir -q ntdetect.com "$dir"; then
long="Windows NT/2000/XP"
short=Windows
- ini=$(item_in_dir boot.ini "$2")
+ ini=$(item_in_dir boot.ini "$dir")
if [ -n "$ini" ]; then
- multicount="$(grep -e "^multi" "$2/$ini" | wc -l)"
- scsicount="$(grep -e "^scsi" "$2/$ini" | wc -l)"
+ multicount="$(grep -e "^multi" "$dir/$ini" | wc -l)"
+ scsicount="$(grep -e "^scsi" "$dir/$ini" | wc -l)"
msoscount="$(expr "${multicount}" + "${scsicount}")"
if [ "$msoscount" -eq 1 ]; then
# We need to remove a Carriage Return at the end of
# the line...
- defaultmspart="$(grep -e "^default=" "$2/$ini" | cut -d '=' -f2 | tr -d '\r')"
+ defaultmspart="$(grep -e "^default=" "$dir/$ini" | cut -d '=' -f2 | tr -d '\r')"
# Escape any backslashes in defaultmspart
grepexp="^$(echo "$defaultmspart" | sed -e 's/\\/\\\\/')="
# Colons not allowed; replace by spaces
# Accented characters (non UTF-8) cause debconf to
# hang, so we fall back to the default if the name
# contains any weird characters.
- long="$(grep -e "$grepexp" "$2/$ini" | cut -d '"' -f2 | \
+ long="$(grep -e "$grepexp" "$dir/$ini" | cut -d '"' -f2 | \
tr ':' ' ' | LC_ALL=C grep -v '[^a-zA-Z0-9 &()/_-]')"
if [ -z "$long" ]; then
long="Windows NT/2000/XP"
@@ -84,7 +85,7 @@ if [ -z "$found" ] && item_in_dir -q ntldr "$2" && item_in_dir -q ntdetect.com "
fi
# MS-DOS
-if [ -z "$found" ] && item_in_dir -q dos "$2"; then
+if [ -z "$found" ] && item_in_dir -q dos "$dir"; then
long="MS-DOS 5.x/6.x/Win3.1"
short=MS-DOS
@@ -92,8 +93,8 @@ if [ -z "$found" ] && item_in_dir -q dos "$2"; then
fi
# 95/98/Me
-if [ -z "$found" ] && item_in_dir -q windows "$2" &&
- item_in_dir -q win.com "$2"/"$(item_in_dir windows "$2")"; then
+if [ -z "$found" ] && item_in_dir -q windows "$dir" &&
+ item_in_dir -q win.com "$dir"/"$(item_in_dir windows "$dir")"; then
long="Windows 95/98/Me"
short=Windows9xMe
@@ -101,9 +102,13 @@ if [ -z "$found" ] && item_in_dir -q windows "$2" &&
fi
if [ -z "$found" ]; then
- exit 1
+ echo "$partition $dir $type $discard"; continue # failure
fi
-label="$(count_next_label "$short")"
-result "${partition}:${long}:${label}:chain"
-exit 0
+result "${partition}:${long}:${short}$((label += 1)):chain" # success
+
+ if [ 1 == "$discard" ]; then
+ umount "$dir"
+ rmdir "$dir"
+ fi
+done
diff --git a/os-probes/mounted/x86/30utility b/os-probes/mounted/x86/30utility
index af48d30..995e523 100755
--- a/os-probes/mounted/x86/30utility
+++ b/os-probes/mounted/x86/30utility
@@ -1,18 +1,19 @@
#!/bin/sh
# Detects utility (hw vendor recovery) partitions.
-. /usr/share/os-prober/common.sh
+set -e
-partition="$1"
-mpoint="$2"
-type="$3"
+. $execpfx/common.sh
+
+while read partition dir type discard; do
# 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" ;;
fat) debug "$1 is a FAT partition (mounted by GRUB)" ;;
- *) debug "$1 is not a FAT partition: exiting"; exit 1 ;;
+ *) # debug "$1 is not a FAT partition"
+ echo "$partition $dir $type $discard"; continue ;; # failure
esac
# Dell Utility partitions have partition type 0xde, but no idea how to
@@ -25,9 +26,14 @@ elif item_in_dir -q f11.sys "$2"; then
long="Acronis Secure Zone"
short=AcroneZone
else
- exit 1
+ echo "$partition $dir $type $discard"; continue # failure
fi
-label="$(count_next_label "$short")"
-result "${partition}:${long}:${label}:chain"
-exit 0
+result "${partition}:${long}:${short}$((label += 1)):chain" # success
+
+ if [ 1 == "$discard" ]; then
+ umount "$dir"
+ rmdir "$dir"
+ fi
+
+done
diff --git a/os-probes/mounted/x86/70hurd b/os-probes/mounted/x86/70hurd
index ffc0a44..3e23ee0 100755
--- a/os-probes/mounted/x86/70hurd
+++ b/os-probes/mounted/x86/70hurd
@@ -1,16 +1,19 @@
#!/bin/sh
set -e
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
-partition="$1"
-dir="$2"
-type="$3"
+while read partition dir type discard; do
if [ -e "$dir/servers/exec" ] && [ -x "$dir/hurd/init" ]; then
- label="$(count_next_label Hurd)"
- result "$partition:GNU/Hurd:$label:hurd"
- exit 0
+ result "$partition:GNU/Hurd:Hurd$((label += 1)):hurd" # success
+
+ if [ 1 == "$discard" ]; then
+ umount "$dir"
+ rmdir "$dir"
+ fi
else
- exit 1
+ echo "$partition $dir $type $discard"; continue # failure
fi
+
+done
diff --git a/os-probes/mounted/x86/80minix b/os-probes/mounted/x86/80minix
index e01f669..edb09ed 100755
--- a/os-probes/mounted/x86/80minix
+++ b/os-probes/mounted/x86/80minix
@@ -1,16 +1,14 @@
#!/bin/sh
set -e
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
-partition="$1"
-dir="$2"
-type="$3"
+while read partition dir type discard; do
# Weed out stuff that doesn't apply to us
case "$type" in
minix|minix2|ext2) ;;
- *) exit 1 ;;
+ *) echo "$partition $dir $type $discard"; continue ;; # failure
esac
if [ -f "$dir/minix" ] || [ -e "$dir/boot/image_big" ]; then
@@ -20,9 +18,13 @@ if [ -f "$dir/minix" ] || [ -e "$dir/boot/image_big" ]; then
boot="chain"
fi
- label="$(count_next_label Minix)"
- result "$partition:Minix:$label:$boot"
- exit 0
+ result "$partition:Minix:Minix$((label += 1)):$boot" # success
+ if [ 1 == "$discard" ]; then
+ umount "$dir"
+ rmdir "$dir"
+ fi
else
- exit 1
+ echo "$partition $dir $type $discard"; continue # failure
fi
+
+done
diff --git a/os-probes/mounted/x86/83haiku b/os-probes/mounted/x86/83haiku
index 6de7a1d..ccd1555 100755
--- a/os-probes/mounted/x86/83haiku
+++ b/os-probes/mounted/x86/83haiku
@@ -1,23 +1,22 @@
#!/bin/sh
# Detects Haiku on BeFS partitions.
+set -e
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
-partition="$1"
-mpoint="$2"
-type="$3"
+while read partition dir type discard; do
# Weed out stuff that doesn't apply to us
case "$type" in
befs|befs_be) debug "$partition is a BeFS partition" ;;
- *) debug "$partition is not a BeFS partition: exiting"; exit 1 ;;
+ *) # debug "$partition is not a BeFS partition"
+ echo "$partition $dir $type $discard"; continue ;; # failure
esac
if head -c 512 "$partition" | grep -qs "system.haiku_loader"; then
debug "Stage 1 bootloader found"
else
- debug "Stage 1 bootloader not found: exiting"
- exit 1
+ echo "$partition $dir $type $discard"; continue # failure
fi
if system="$(item_in_dir "system" "$mpoint")" &&
@@ -26,10 +25,14 @@ if system="$(item_in_dir "system" "$mpoint")" &&
item_in_dir -q "kernel_x86_64" "$mpoint/$system")
then
debug "Stage 2 bootloader and kernel found"
- label="$(count_next_label Haiku)"
- result "$partition:Haiku:$label:chain"
- exit 0
+ result "$partition:Haiku:Haiku$((label += 1)):chain" # success
+ if [ 1 == "$discard" ]; then
+ umount "$dir"
+ rmdir "$dir"
+ fi
else
- debug "Stage 2 bootloader and kernel not found: exiting"
- exit 1
+ debug "Stage 2 bootloader and kernel not found"
+ echo "$partition $dir $type $discard"; continue # failure
fi
+
+done
diff --git a/os-probes/mounted/x86/90solaris b/os-probes/mounted/x86/90solaris
index 0e9148c..00359ec 100755
--- a/os-probes/mounted/x86/90solaris
+++ b/os-probes/mounted/x86/90solaris
@@ -4,16 +4,19 @@
set -e
-. /usr/share/os-prober/common.sh
+. $execpfx/common.sh
-partition="$1"
-dir="$2"
-type="$3"
+while read partition dir type discard; do
if [ -f "$dir/etc/system" ] && [ -f "$dir/etc/vfstab" ]; then
- label="$(count_next_label Solaris)"
- result "$partition:Solaris/IA32:$label:chain"
- exit 0
+ result "$partition:Solaris/IA32:Solaris$((label += 1)):chain" # success
+
+ if [ 1 == "$discard" ]; then
+ umount "$dir"
+ rmdir "$dir"
+ fi
else
- exit 1
+ echo "$partition $dir $type $discard"; continue # failure
fi
+
+done
Reply to: