The list of supported filesytems goes dynamic.
[live-boot-grml.git] / scripts / live-helpers
1 #!/bin/sh
2 # live-initramfs helper functions, used by live-initramfs on boot and by live-snapshot
3
4 if [ ! -x "/bin/fstype" ]
5 then
6         # klibc not in path -> not in initramfs
7         export PATH="${PATH}:/usr/lib/klibc/bin"
8 fi
9
10 sys2dev ()
11 {
12         sysdev=${1#/sys}
13         echo "/dev/$(udevinfo -q name -p ${sysdev} 2>/dev/null|| echo ${sysdev##*/})"
14 }
15
16 subdevices ()
17 {
18         sysblock=${1}
19         r=""
20
21         for dev in "${sysblock}" "${sysblock}"/*
22         do
23                 if [ -e "${dev}/dev" ]
24                 then
25                         r="${r} ${dev}"
26                 fi
27         done
28
29         echo ${r}
30 }
31
32 is_supported_fs ()
33 {
34         fstype="${1}"
35
36         # Try to look if it is already supported by the kernel
37         if grep -q ${fstype} /proc/filesystems
38         then
39                 return 0
40         else
41                 # Then try to add support for it the gentle way using the initramfs capabilities
42                 modprobe ${fstype}
43                 if grep -q ${fstype} /proc/filesystems
44                 then
45                         return 0
46                 # Then try the hard way if /root is already reachable
47                 else
48                         kmodule="/root/lib/modules/`uname -r`/${fstype}/${fstype}.ko"
49                         if [ -e "${kmodule}" ]
50                         then
51                                 insmod "${kmodule}"
52                                 if grep -q ${fstype} /proc/filesystems
53                                 then
54                                         return 0
55                                 fi
56                         fi
57                 fi
58         fi
59
60         return 1
61 }
62
63 get_fstype ()
64 {
65         local FSTYPE
66         local FSSIZE
67
68         # fstype misreports LUKS devices
69         if is_luks "${1}"
70         then
71             /lib/udev/vol_id -t ${1} 2>/dev/null
72             return
73         fi
74
75         eval $(fstype < ${1})
76
77         if [ "${FSTYPE}" != "unknown" ]
78         then
79                 echo ${FSTYPE}
80                 return 0
81         fi
82
83         /lib/udev/vol_id -t ${1} 2>/dev/null
84 }
85
86 where_is_mounted ()
87 {
88         device=${1}
89
90         if grep -q "^${device} " /proc/mounts
91         then
92                 # return the first found
93                 grep "^${device} " /proc/mounts | cut -f2 -d ' '
94         fi
95 }
96
97 lastline ()
98 {
99         while read lines
100         do
101                 line=${lines}
102         done
103
104         echo "${line}"
105 }
106
107 base_path ()
108 {
109         testpath="${1}"
110         mounts="$(awk '{print $2}' /proc/mounts)"
111         testpath="$(busybox realpath ${testpath})"
112
113         while true
114         do
115                 if echo "${mounts}" | grep -qs "^${testpath}"
116                 then
117                         set -- $(echo "${mounts}" | grep "^${testpath}" | lastline)
118                         echo ${1}
119                         break
120                 else
121                         testpath=$(dirname $testpath)
122                 fi
123         done
124 }
125
126 fs_size ()
127 {
128         # Returns used/free fs kbytes + 5% more
129         # You could pass a block device as ${1} or the mount point as ${2}
130
131         dev="${1}"
132         mountp="${2}"
133         used="${3}"
134
135         if [ -z "${mountp}" ]
136         then
137                 mountp="$(where_is_mounted ${dev})"
138
139                 if [ -z "${mountp}" ]
140                 then
141                         mountp="/mnt/tmp_fs_size"
142
143                         mkdir -p "${mountp}"
144                         mount -t $(get_fstype "${dev}") -o ro "${dev}" "${mountp}"
145
146                         doumount=1
147                 fi
148         fi
149
150         if [ "${used}" = "used" ]
151         then
152                 size=$(du -ks ${mountp} | cut -f1)
153                 size=$(expr ${size} + ${size} / 20 ) # FIXME: 5% more to be sure
154         else
155                 # free space
156                 size="$(df -k | grep -s ${mountp} | awk '{print $4}')"
157         fi
158
159         if [ -n "${doumount}" ]
160         then
161                 umount "${mountp}"
162                 rmdir "${mountp}"
163         fi
164
165         echo "${size}"
166 }
167
168 load_keymap ()
169 {
170         # Load custom keymap
171         if [ -x /bin/loadkeys -a -r /etc/boottime.kmap.gz ]
172         then
173                 loadkeys /etc/boottime.kmap.gz
174         fi
175 }
176
177 setup_loop ()
178 {
179         local fspath=${1}
180         local module=${2}
181         local pattern=${3}
182         local offset=${4}
183         local encryption=${5}
184         local readonly=${6}
185
186         modprobe -q -b "${module}"
187         udevsettle
188
189         for loopdev in ${pattern}
190         do
191                 if [ "$(cat ${loopdev}/size)" -eq 0 ]
192                 then
193                         dev=$(sys2dev "${loopdev}")
194                         options=''
195
196                         if [ -n ${readonly} ]
197                         then
198                                 if losetup --help 2>&1 | grep -q -- "-r\b"
199                                 then
200                                         options="${options} -r"
201                                 fi
202                         fi
203
204                         if [ 0 -lt "${offset}" ]
205                         then
206                                 options="${options} -o ${offset}"
207                         fi
208
209                         if [ -z "${encryption}" ]
210                         then
211                                 losetup ${options} "${dev}" "${fspath}"
212                         else
213                                 # Loop AES encryption
214                                 while true
215                                 do
216                                         load_keymap
217
218                                         echo -n "Enter passphrase for root filesystem: " >&6
219                                         read -s passphrase
220                                         echo "${passphrase}" > /tmp/passphrase
221                                         unset passphrase
222                                         exec 9</tmp/passphrase
223                                         /sbin/losetup ${options} -e "${encryption}" -p 9 "${dev}" "${fspath}"
224                                         error=${?}
225                                         exec 9<&-
226                                         rm -f /tmp/passphrase
227
228                                         if [ 0 -eq ${error} ]
229                                         then
230                                                 unset error
231                                                 break
232                                         fi
233
234                                         echo
235                                         echo -n "There was an error decrypting the root filesystem ... Retry? [Y/n] " >&6
236                                         read answer
237
238                                         if [ "$(echo "${answer}" | cut -b1 | tr A-Z a-z)" = "n" ]
239                                         then
240                                                 unset answer
241                                                 break
242                                         fi
243                                 done
244                         fi
245
246                         echo "${dev}"
247                         return 0
248                 fi
249         done
250
251         panic "No loop devices available"
252 }
253
254 try_mount ()
255 {
256         dev="${1}"
257         mountp="${2}"
258         opts="${3}"
259
260         old_mountp="$(where_is_mounted ${dev})"
261
262         if [ -n "${old_mountp}" ]
263         then
264                 mount -o remount,"${opts}" "${dev}" "${old_mountp}" || panic "Remounting ${dev} ${opts} on ${old_mountp} failed"
265                 mount -o bind "${old_mountp}" "${mountp}" || panic "Cannot bind-mount ${old_mountp} on ${mountp}"
266         else
267                 mount -t $(get_fstype "${dev}") -o "${opts}" "${dev}" "${mountp}" || panic "Cannot mount ${dev} on ${mountp}"
268         fi
269 }
270
271 find_cow_device ()
272 {
273         pers_label="${1}"
274         cow_backing="/${pers_label}-backing"
275
276         for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -v loop | grep -v ram | grep -v fd)
277         do
278                 for dev in $(subdevices "${sysblock}")
279                 do
280                         devname=$(sys2dev "${dev}")
281
282                         if [ "$(/lib/udev/vol_id -l ${devname} 2>/dev/null)" = "${pers_label}" ]
283                         then
284                                 echo "${devname}"
285                                 return
286                         fi
287
288                         case "$(get_fstype ${devname})" in
289                                 vfat|ext2|ext3|jffs2)
290                                         mkdir -p "${cow_backing}"
291                                         try_mount "${devname}" "${cow_backing}" "rw"
292
293                                         if [ -f "${cow_backing}/${pers_label}" ]
294                                         then
295                                                 echo $(setup_loop "${cow_backing}/${pers_label}" "loop" "/sys/block/loop*")
296                                                 return 0
297                                         else
298                                                 umount ${cow_backing}
299                                         fi
300                                         ;;
301                                 *)
302                                         ;;
303                         esac
304                 done
305         done
306 }
307
308 find_files ()
309 {
310         # return the first of ${filenames} found on vfat and ext2/ext3 devices
311         # FIXME: merge with above function
312
313         filenames="${1}"
314         snap_backing="/snap-backing"
315
316         for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -v loop | grep -v ram | grep -v fd)
317         do
318                 for dev in $(subdevices "${sysblock}")
319                 do
320                         devname=$(sys2dev "${dev}")
321                         devfstype="$(get_fstype ${devname})"
322
323                         if is_supported_fs ${devfstype}
324                         then
325                                 mkdir -p "${snap_backing}"
326                                 try_mount "${devname}" "${snap_backing}" "ro"
327
328                                 for filename in ${filenames}
329                                         do
330                                         if [ -f "${snap_backing}/${filename}" ]
331                                         then
332                                                 echo "${devname} ${snap_backing} ${filename}"
333                                                 return 0
334                                         fi
335                                 done
336
337                                 umount ${snap_backing}
338                         fi
339                 done
340         done
341 }
342
343 get_mac ()
344 {
345         mac=""
346
347         for adaptor in /sys/class/net/*
348         do
349                 status="$(cat ${adaptor}/iflink)"
350
351                 if [ "${status}" -eq 2 ]
352                 then
353                         mac="$(cat ${adaptor}/address)"
354                         mac="$(echo ${mac} | sed 's/:/-/g' | tr '[a-z]' '[A-Z]')"
355                 fi
356         done
357
358         echo ${mac}
359 }
360
361 is_luks()
362 {
363     devname="${1}"
364     if [ -x /sbin/cryptsetup ]
365     then
366         /sbin/cryptsetup isLuks "${devname}" 2>/dev/null || ret=${?}
367         return ${ret}
368     else
369         return 1
370     fi
371
372 }