Synchronize with Debian.
[live-initramfs-grml.git] / scripts / live-helpers
1 # live-initramfs helper functions, used by live-initramfs on boot and by live-snapshot
2
3 if [ ! -x "/bin/fstype" ]
4 then
5         # klibc not in path -> not in initramfs
6         export PATH="${PATH}:/usr/lib/klibc/bin"
7 fi
8
9 # handle upgrade path from old udev (using udevinfo) to
10 # recent versions of udev (using udevadm info)
11 if [ -x /sbin/udevadm ]
12 then
13         udevinfo='/sbin/udevadm info'
14 else
15         udevinfo='udevinfo'
16 fi
17
18 sys2dev ()
19 {
20         sysdev=${1#/sys}
21         echo "/dev/$($udevinfo -q name -p ${sysdev} 2>/dev/null|| echo ${sysdev##*/})"
22 }
23
24 subdevices ()
25 {
26         sysblock=${1}
27         r=""
28
29         for dev in "${sysblock}" "${sysblock}"/*
30         do
31                 if [ -e "${dev}/dev" ]
32                 then
33                         r="${r} ${dev}"
34                 fi
35         done
36
37         echo ${r}
38 }
39
40 is_supported_fs ()
41 {
42         fstype="${1}"
43
44         # Validate input first
45         if [ -z "${fstype}" ]
46         then
47                 return 1
48         fi
49
50         # Try to look if it is already supported by the kernel
51         if grep -q ${fstype} /proc/filesystems
52         then
53                 return 0
54         else
55                 # Then try to add support for it the gentle way using the initramfs capabilities
56                 modprobe ${fstype}
57                 if grep -q ${fstype} /proc/filesystems
58                 then
59                         return 0
60                 # Then try the hard way if /root is already reachable
61                 else
62                         kmodule="/root/lib/modules/`uname -r`/${fstype}/${fstype}.ko"
63                         if [ -e "${kmodule}" ]
64                         then
65                                 insmod "${kmodule}"
66                                 if grep -q ${fstype} /proc/filesystems
67                                 then
68                                         return 0
69                                 fi
70                         fi
71                 fi
72         fi
73
74         return 1
75 }
76
77 get_fstype ()
78 {
79         # udev (>= 146) no longer provides vol_id
80         if [ -x /lib/udev/vol_id ]
81         then
82                 # lenny
83                 /lib/udev/vol_id -t ${1} 2>/dev/null
84         else
85                 # squeeze
86                 /sbin/blkid -s TYPE -o value $1 2>/dev/null
87         fi
88 }
89
90 where_is_mounted ()
91 {
92         device=${1}
93
94         if grep -q "^${device} " /proc/mounts
95         then
96                 # return the first found
97                 grep -m1 "^${device} " /proc/mounts | cut -f2 -d ' '
98         fi
99 }
100
101 lastline ()
102 {
103         while read lines
104         do
105                 line=${lines}
106         done
107
108         echo "${line}"
109 }
110
111 base_path ()
112 {
113         testpath="${1}"
114         mounts="$(awk '{print $2}' /proc/mounts)"
115         testpath="$(busybox realpath ${testpath})"
116
117         while true
118         do
119                 if echo "${mounts}" | grep -qs "^${testpath}"
120                 then
121                         set -- $(echo "${mounts}" | grep "^${testpath}" | lastline)
122                         echo ${1}
123                         break
124                 else
125                         testpath=$(dirname $testpath)
126                 fi
127         done
128 }
129
130 fs_size ()
131 {
132         # Returns used/free fs kbytes + 5% more
133         # You could pass a block device as ${1} or the mount point as ${2}
134
135         dev="${1}"
136         mountp="${2}"
137         used="${3}"
138
139         if [ -z "${mountp}" ]
140         then
141                 mountp="$(where_is_mounted ${dev})"
142
143                 if [ -z "${mountp}" ]
144                 then
145                         mountp="/mnt/tmp_fs_size"
146
147                         mkdir -p "${mountp}"
148                         mount -t $(get_fstype "${dev}") -o ro "${dev}" "${mountp}" || log_warning_msg "cannot mount -t $(get_fstype ${dev}) -o ro ${dev} ${mountp}"
149
150                         doumount=1
151                 fi
152         fi
153
154         if [ "${used}" = "used" ]
155         then
156                 size=$(du -ks ${mountp} | cut -f1)
157                 size=$(expr ${size} + ${size} / 20 ) # FIXME: 5% more to be sure
158         else
159                 # free space
160                 size="$(df -k | grep -s ${mountp} | awk '{print $4}')"
161         fi
162
163         if [ -n "${doumount}" ]
164         then
165                 umount "${mountp}" || log_warning_msg "cannot umount ${mountp}"
166                 rmdir "${mountp}"
167         fi
168
169         echo "${size}"
170 }
171
172 load_keymap ()
173 {
174         # Load custom keymap
175         if [ -x /bin/loadkeys -a -r /etc/boottime.kmap.gz ]
176         then
177                 loadkeys /etc/boottime.kmap.gz
178         fi
179 }
180
181 setup_loop ()
182 {
183         local fspath=${1}
184         local module=${2}
185         local pattern=${3}
186         local offset=${4}
187         local encryption=${5}
188         local readonly=${6}
189
190         modprobe -q -b "${module}"
191
192         udevadm settle
193
194         for loopdev in ${pattern}
195         do
196                 if [ "$(cat ${loopdev}/size)" -eq 0 ]
197                 then
198                         dev=$(sys2dev "${loopdev}")
199                         options=''
200
201                         if [ -n "${readonly}" ]
202                         then
203                                 if losetup --help 2>&1 | grep -q -- "-r\b"
204                                 then
205                                         options="${options} -r"
206                                 fi
207                         fi
208
209                         if [ 0 -lt "${offset}" ]
210                         then
211                                 options="${options} -o ${offset}"
212                         fi
213
214                         if [ -z "${encryption}" ]
215                         then
216                                 losetup ${options} "${dev}" "${fspath}"
217                         else
218                                 # Loop AES encryption
219                                 while true
220                                 do
221                                         load_keymap
222
223                                         echo -n "Enter passphrase for root filesystem: " >&6
224                                         read -s passphrase
225                                         echo "${passphrase}" > /tmp/passphrase
226                                         unset passphrase
227                                         exec 9</tmp/passphrase
228                                         /sbin/losetup ${options} -e "${encryption}" -p 9 "${dev}" "${fspath}"
229                                         error=${?}
230                                         exec 9<&-
231                                         rm -f /tmp/passphrase
232
233                                         if [ 0 -eq ${error} ]
234                                         then
235                                                 unset error
236                                                 break
237                                         fi
238
239                                         echo
240                                         echo -n "There was an error decrypting the root filesystem ... Retry? [Y/n] " >&6
241                                         read answer
242
243                                         if [ "$(echo "${answer}" | cut -b1 | tr A-Z a-z)" = "n" ]
244                                         then
245                                                 unset answer
246                                                 break
247                                         fi
248                                 done
249                         fi
250
251                         echo "${dev}"
252                         return 0
253                 fi
254         done
255
256         panic "No loop devices available"
257 }
258
259 try_mount ()
260 {
261         dev="${1}"
262         mountp="${2}"
263         opts="${3}"
264         fstype="${4}"
265
266         old_mountp="$(where_is_mounted ${dev})"
267
268         if [ -n "${old_mountp}" ]
269         then
270                 if [ "${opts}" != "ro" ]
271                 then
272                         mount -o remount,"${opts}" "${dev}" "${old_mountp}" || panic "Remounting ${dev} ${opts} on ${old_mountp} failed"
273                 fi
274
275                 mount -o bind "${old_mountp}" "${mountp}" || panic "Cannot bind-mount ${old_mountp} on ${mountp}"
276         else
277                 if [ -z "${fstype}" ]
278                 then
279                         fstype=$(get_fstype "${dev}")
280                 fi
281                 mount -t "${fstype}" -o "${opts}" "${dev}" "${mountp}" || \
282                 ( echo "SKIPPING: Cannot mount ${dev} on ${mountp}, fstype=${fstype}, options=${opts}" > live.log && return 0 )
283         fi
284 }
285
286 find_cow_device ()
287 {
288         # Returns a device containing a partition labeled "${pers_label}" or containing a file named the same way
289         #  in the latter case the partition containing the file is left mounted
290         #  if is not in black_listed_devices
291         pers_label="${1}"
292         cow_backing="/${pers_label}-backing"
293         black_listed_devices="${2}"
294
295         if [ -z "${PERSISTENT_PATH}" ]
296         then
297                 pers_fpath=${cow_backing}/${pers_label}
298         else
299                 pers_fpath=${cow_backing}/${PERSISTENT_PATH}/${pers_label}
300         fi
301
302         for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -v loop | grep -v ram | grep -v fd)
303         do
304                 for dev in $(subdevices "${sysblock}")
305                 do
306                         devname=$(sys2dev "${dev}")
307
308                         if echo "${black_listed_devices}" | grep -q "${devname}"
309                         then
310                                 # skip this device enterely
311                                 break
312                         fi
313
314                         # Checking for a luks device
315                         if [ "${PERSISTENT}" = "cryptsetup" ] && [ -e /sbin/cryptsetup ] && /sbin/cryptsetup isLuks ${devname}
316                         then
317                                 while true
318                                 do
319                                         load_keymap
320
321                                         /lib/cryptsetup/askpass "Enter passphrase for ${pers_label} on ${devname}: " | /sbin/cryptsetup -T 1 luksOpen ${devname} $(basename ${devname}) --key-file=-
322                                         error=${?}
323
324                                         devname="/dev/mapper/$(basename ${devname})"
325
326                                         if [ 0 -eq ${error} ]
327                                         then
328                                                 unset error
329                                                 break
330                                         fi
331
332                                         echo
333                                         echo -n "There was an error decrypting ${devname} ... Retry? [Y/n] " >&6
334                                         read answer
335
336                                         if [ "$(echo "${answer}" | cut -b1 | tr A-Z a-z)" = "n" ]
337                                         then
338                                                 unset answer
339                                                 break
340                                         fi
341                                 done
342                         fi
343
344                         # udev (>= 146) no longer provides vol_id
345                         if [ -x /lib/udev/vol_id ]
346                         then
347                                 # lenny
348                                 if [ "$(/lib/udev/vol_id -l ${devname} 2>/dev/null)" = "${pers_label}" ]
349                                 then
350                                         echo "${devname}"
351                                         return 0
352                                 fi
353                         else
354                                 # squeeze
355                                 if [ "$(/sbin/blkid -s LABEL -o value $devname 2>/dev/null)" = "${pers_label}" ]
356                                 then
357                                         echo "${devname}"
358                                         return 0
359                                 fi
360                         fi
361
362                         if [ "${PERSISTENT}" = "nofiles" ]
363                         then
364                                 # do not mount the device to find for image files
365                                 # just skip this
366                                 continue
367                         fi
368
369                         case "$(get_fstype ${devname})" in
370                                 vfat|ext2|ext3|ext4|jffs2)
371                                         mkdir -p "${cow_backing}"
372                                         if try_mount "${devname}" "${cow_backing}" "rw"
373                                         then
374                                                 if [ -f "${pers_fpath}" ]
375                                                 then
376                                                         echo $(setup_loop "${pers_fpath}" "loop" "/sys/block/loop*")
377                                                         return 0
378                                                 else
379                                                         umount ${cow_backing} > /dev/null 2>&1 || true
380                                                 fi
381                                         fi
382                                         ;;
383                                 *)
384                                         ;;
385                         esac
386                 done
387         done
388         return 1
389 }
390
391 find_files ()
392 {
393         # return the a string composed by device name, mountpoint an the first of ${filenames} found on a supported partition
394         # FIXME: merge with above function
395
396         filenames="${1}"
397         snap_backing="/snap-backing"
398         black_listed_devices="${2}"
399
400         for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -v loop | grep -v ram | grep -v fd)
401         do
402                 for dev in $(subdevices "${sysblock}")
403                 do
404                         devname=$(sys2dev "${dev}")
405                         devfstype="$(get_fstype ${devname})"
406
407                         if echo "${black_listed_devices}" | grep -q "${devname}"
408                         then
409                                 # skip this device enterely
410                                 break
411                         fi
412
413                         if is_supported_fs ${devfstype}
414                         then
415                                 mkdir -p "${snap_backing}"
416
417                                 if try_mount "${devname}" "${snap_backing}" "ro" "${devfstype}"
418                                 then
419                                         for filename in ${filenames}
420                                         do
421                                                 if [ -f "${snap_backing}/${filename}" ]
422                                                 then
423                                                         echo "${devname} ${snap_backing} ${filename}"
424                                                         umount ${snap_backing}
425                                                         return 0
426                                                 fi
427                                         done
428                                 fi
429
430                                 umount ${snap_backing}
431                         fi
432                 done
433         done
434 }
435
436 get_mac ()
437 {
438         mac=""
439
440         for adaptor in /sys/class/net/*
441         do
442                 status="$(cat ${adaptor}/iflink)"
443
444                 if [ "${status}" -eq 2 ]
445                 then
446                         mac="$(cat ${adaptor}/address)"
447                         mac="$(echo ${mac} | sed 's/:/-/g' | tr '[a-z]' '[A-Z]')"
448                 fi
449         done
450
451         echo ${mac}
452 }
453
454 is_luks()
455 {
456     devname="${1}"
457     if [ -x /sbin/cryptsetup ]
458     then
459         /sbin/cryptsetup isLuks "${devname}" 2>/dev/null || ret=${?}
460         return ${ret}
461     else
462         return 1
463     fi
464
465 }