linux-boot-probe: mounted/40grub2 add tests for handling escaped $ " \
[os-prober.git] / os-prober
1 #!/bin/sh
2 set -e
3
4 . /usr/share/os-prober/common.sh
5
6 newns "$@"
7 require_tmpdir
8
9 log_output () {
10         if type log-output >/dev/null 2>&1; then
11                 log-output -t os-prober --pass-stdout $@
12         else
13                 $@
14         fi
15 }
16
17 : >"$OS_PROBER_TMP/dmraid-map"
18 DMRAID=$(type dmraid >/dev/null 2>&1 || true)
19 if [ "$DMRAID" ]; then
20         dmraid -r -c >"$OS_PROBER_TMP/dmraid-map"
21 fi
22
23 on_sataraid () {
24         local parent="${1%/*}"
25         local device="/dev/${parent##*/}"
26         if grep -q "$device" "$OS_PROBER_TMP/dmraid-map"; then
27                 return 0
28         fi
29         return 1
30 }
31
32 partitions () {
33         os_name="$(uname -s)"
34         # Exclude partitions that have whole_disk sysfs attribute set.
35         if [ -d /sys/block ]; then
36                 # Exclude partitions on physical disks that are part of a
37                 # Serial ATA RAID disk.
38                 for part in /sys/block/*/*[0-9]; do
39                         if [ -f "$part/start" ] && \
40                            [ ! -f "$part/whole_disk" ] && ! on_sataraid $part; then
41                                 name="$(echo "${part##*/}" | sed 's,[!.],/,g')"
42                                 if [ -e "/dev/$name" ]; then
43                                         echo "/dev/$name"
44                                 fi
45                         fi
46                 done
47
48                 # Add Serial ATA RAID devices
49                 if type dmraid >/dev/null 2>&1 && \
50                    dmraid -s -c >/dev/null 2>&1; then
51                         for raidset in $(dmraid -sa -c); do
52                                 for part in /dev/mapper/"$raidset"*[0-9]; do
53                                         echo "$part"
54                                 done
55                         done
56                 fi
57         elif [ "$os_name" = Linux ]; then
58                 echo "Cannot find list of partitions!  (Try mounting /sys.)" >&2
59                 exit 1
60         elif [ "$os_name" = GNU ]; then
61                 for part in /dev/hd*s*[0-9] /dev/sd*s*[0-9]; do
62                         if [ -s "$part" ]; then
63                                 echo "$part"
64                         fi
65                 done
66         else
67                 # We don't know how to probe OSes on non-Linux and non-GNU kernels.
68                 # For now, just don't get in the way.
69                 exit 0
70         fi
71
72         # Also detect OSes on LVM volumes (assumes LVM is active)
73         if type lvs >/dev/null 2>&1; then
74                 echo "$(LVM_SUPPRESS_FD_WARNINGS=1 log_output lvs --noheadings --separator : -o vg_name,lv_name |
75                         sed "s|-|--|g;s|^[[:space:]]*\(.*\):\(.*\)$|/dev/mapper/\1-\2|")"
76         fi
77 }
78
79 parse_proc_swaps () {
80         while read line; do
81                 set -f
82                 set -- $line
83                 set +f
84                 echo "$(mapdevfs $1) swap"
85         done
86 }
87
88 parse_proc_mdstat () {
89         if type udevadm >/dev/null 2>&1; then
90                 udevinfo () {
91                         udevadm info "$@"
92                 }
93         fi
94         while read line; do
95                 for word in $line; do
96                         dev="${word%%\[*}"
97                         # TODO: factor this out to something in di-utils if
98                         # it's needed elsewhere
99                         if [ -d /sys/block ] && type udevinfo >/dev/null 2>&1; then
100                                 if ! udevinfo -q path -n "/dev/$dev" 2>/dev/null | \
101                                      grep -q '/.*/.*/'; then
102                                         continue
103                                 fi
104                         elif ! echo "$dev" | grep -q "/part"; then
105                                 continue
106                         fi
107                         raidpart="/dev/$dev"
108                         echo "$(mapdevfs "$raidpart")"
109                 done
110         done
111 }
112
113 # Needed for idempotency
114 rm -f /var/lib/os-prober/labels
115
116 for prog in /usr/lib/os-probes/init/*; do
117         if [ -x "$prog" ] && [ -f "$prog" ]; then
118                 "$prog" || true
119         fi
120 done
121
122 # We need to properly canonicalize partitions with mount points and partitions
123 # used in RAID
124 grep "^/dev/" /proc/mounts | parse_proc_mounts >"$OS_PROBER_TMP/mounted-map" || true
125 : >"$OS_PROBER_TMP/swaps-map"
126 if [ -f /proc/swaps ]; then
127         grep "^/dev/" /proc/swaps | parse_proc_swaps >"$OS_PROBER_TMP/swaps-map" || true
128 fi
129 : >"$OS_PROBER_TMP/raided-map"
130 if [ -f /proc/mdstat ] ; then
131         grep "^md" /proc/mdstat | parse_proc_mdstat >"$OS_PROBER_TMP/raided-map" || true
132 fi
133
134 for partition in $(partitions); do
135         if ! mapped="$(mapdevfs "$partition")"; then
136                 log "Device '$partition' does not exist; skipping"
137                 continue
138         fi
139
140         # Skip partitions used in software RAID arrays
141         if grep -q "^$mapped" "$OS_PROBER_TMP/raided-map" ; then
142                 debug "$partition: part of software raid array"
143                 continue
144         fi
145
146         # Skip partitions used as active swap
147         if grep -q "^$mapped " "$OS_PROBER_TMP/swaps-map" ; then
148                 debug "$partition: is active swap"
149                 continue
150         fi
151
152         if ! grep -q "^$mapped " "$OS_PROBER_TMP/mounted-map" ; then
153                 for test in /usr/lib/os-probes/*; do
154                         if [ -f "$test" ] && [ -x "$test" ]; then
155                                 debug "running $test on $partition"
156                                 if "$test" "$partition"; then
157                                         debug "os detected by $test"
158                                         break
159                                 fi
160                         fi
161                 done
162         else
163                 mpoint=$(grep "^$mapped " "$OS_PROBER_TMP/mounted-map" | head -n1 | cut -d " " -f 2)
164                 mpoint="$(unescape_mount "$mpoint")"
165                 if [ "$mpoint" != "/target/boot" ] && [ "$mpoint" != "/target" ] && [ "$mpoint" != "/" ]; then
166                         type=$(grep "^$mapped " "$OS_PROBER_TMP/mounted-map" | head -n1 | cut -d " " -f 3)
167                         for test in /usr/lib/os-probes/mounted/*; do
168                                 if [ -f "$test" ] && [ -x "$test" ]; then
169                                         debug "running $test on mounted $partition"
170                                         if "$test" "$partition" "$mpoint" "$type"; then
171                                                 debug "os detected by $test"
172                                                 break
173                                         fi
174                                 fi
175                         done
176                 fi
177         fi
178 done