Adding upstream version 1.59+debian.
[live-boot-grml.git] / scripts / casper
1 #!/bin/sh
2
3 # set -e
4
5 mountpoint=/cdrom
6
7 mkdir -p $mountpoint
8
9 overlay_method=unionfs
10 if [ "${DPKG_ARCH}" = "ia64" ] || [ "${DPKG_ARCH}" = "hppa" ] || [ "${DPKG_ARCH}" = "sparc" ]; then
11     overlay_method=devmapper
12 fi
13
14 USERNAME=ubuntu
15 USERFULLNAME="Ubuntu LiveCD user"
16 HOST=ubuntu
17
18 [ -f /etc/casper.conf ] && . /etc/casper.conf
19
20 export USERNAME USERFULLNAME HOST
21
22 casper_path() {
23     path=$1
24     if [ -e "$path/casper/filesystem.cloop" ]; then
25         echo "$path/casper/filesystem.cloop"
26         return 0
27     elif [ -e "$path/casper/filesystem.squashfs" ]; then
28         echo "$path/casper/filesystem.squashfs"
29         return 0
30     fi
31     return 1
32 }
33
34 subdevices() {
35     sysblock=$1
36     r=""
37     for dev in "${sysblock}" "${sysblock}"/*; do
38         if [ -e "${dev}/dev" ]; then
39             r="${r} ${dev}"
40         fi
41     done
42     echo ${r}
43 }
44
45 get_backing_device() {
46         case "$1" in
47             *.cloop)
48                 echo $(setup_loop "$1" "cloop" "/sys/block/cloop*")
49                         ;;
50             *.squashfs)
51                 echo $(setup_loop "$1" "loop" "/sys/block/loop*")
52                 ;;
53             *)
54                 panic "Unrecognized casper filesystem: $1"
55                 ;;
56         esac
57 }
58
59 setup_cow() {
60         case "$1" in
61             unionfs)
62                 setup_unionfs "$2" "$rootmnt"
63                 ;;
64             devmapper)
65                 setup_devmapper "$2" "$rootmnt"
66         esac
67 }
68
69 sys2dev() {
70     sysdev=${1#/sys}
71     echo "/dev/$(udevinfo -q name -p ${sysdev} 2>/dev/null|| echo ${sysdev##*/})"
72 }
73
74 setup_loop() {
75     local fspath=$1
76     local module=$2
77     local pattern=$3
78
79     modprobe -Qb "$module"
80     udevplug -W
81  
82     for loopdev in $pattern; do
83         if [ "$(cat $loopdev/size)" -eq 0 ]; then
84             dev=$(sys2dev "${loopdev}")
85             losetup "$dev" "$fspath"
86             echo "$dev"
87             return 0
88         fi
89     done
90     panic "No loop devices available"
91 }
92
93 get_fstype() {
94     local FSTYPE
95     local FSSIZE
96     eval $(fstype < $1)
97     if [ "$FSTYPE" != "unknown" ]; then
98         echo $FSTYPE
99         return 0
100     fi
101     /lib/udev/vol_id -t $1 2>/dev/null
102 }
103
104 setup_devmapper() {
105     backdev="$1"
106     rootmnt="$2"
107
108     modprobe -Qb dm-mod
109     COW_DEVICE=/dev/ram1
110     COW_NAME="casper-cow"
111
112     BACKING_FILE_SIZE=$(blockdev --getsize "$backdev")
113     MAX_COW_SIZE=$(blockdev --getsize "$COW_DEVICE")
114     CHUNK_SIZE=8 # sectors
115
116     if [ -z "$COW_SIZE" -o "$COW_SIZE" -gt "$MAX_COW_SIZE" ]; then
117         COW_SIZE=$MAX_COW_SIZE
118     fi
119
120     echo "0 $COW_SIZE linear $COW_DEVICE 0" | dmsetup create $COW_NAME
121
122     echo "0 $BACKING_FILE_SIZE snapshot $backdev /dev/mapper/$COW_NAME p $CHUNK_SIZE" | \
123         dmsetup create casper-snapshot
124     if [ "$(get_fstype $backdev)" = "unknown" ]; then
125         panic "Unknown file system type on $backdev"
126     fi
127     mount -t $(get_fstype "$backdev") /dev/mapper/casper-snapshot $rootmnt || panic "Can not mount /dev/mapper/casper/snapshot on $rootmnt"
128
129     mkdir -p "$rootmnt/rofs"
130     echo "0 $BACKING_FILE_SIZE linear $backdev 0" | dmsetup create casper-backing
131     mount -t $(get_fstype "$backdev") /dev/mapper/casper-backing "$rootmnt/rofs"
132 }
133
134 where_is_mounted() {
135     device=$1
136     if grep -q "^$device " /proc/mounts; then
137         grep "^$device " /proc/mounts | read d mountpoint rest
138         echo $mountpoint
139         return 0
140     fi
141     return 1
142 }
143
144 find_cow_device() {
145     for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -v loop); do
146         for dev in $(subdevices "${sysblock}"); do
147             devname=$(sys2dev "${dev}")
148             if [ "$(/lib/udev/vol_id -l $devname 2>/dev/null)" = "casper-rw" ]; then
149                 echo "$devname"
150                 return
151             elif [ "$(get_fstype ${devname})" = "vfat" ]; then
152                 mkdir -p /cow-backing
153                 if where_is_mounted ${devname} > /dev/null; then
154                     mount -o remount,rw ${devname} $(where_is_mounted ${devname}) || panic "Remounting failed"
155                     mount -o bind $(where_is_mounted ${devname}) /cow-backing || panic "Cannot bind-mount"
156                 else
157                     mount -t $(get_fstype "${devname}") -o rw "${devname}" /cow-backing || panic "Cannot mount $devname on /cow-backing"
158                 fi
159
160                 if [ -e "/cow-backing/casper-rw" ]; then
161                     echo $(setup_loop "/cow-backing/casper-rw" "loop" "/sys/block/loop*")
162                     return 0
163                 else
164                     umount /cow-backing
165                 fi
166             fi
167             
168         done
169     done
170     return 1    
171 }
172
173 setup_unionfs() {
174         backdev="$1"
175         rootmnt="$2"
176         modprobe -Qb unionfs
177         mkdir -p /cow
178
179         if grep -q persistent /proc/cmdline; then
180             i=0
181             # We love udev and the kernel!
182             while [ "$i" -lt 300 ]; do
183                 cowdevice=$(find_cow_device) 
184                 if [ -b "$cowdevice" ]; then
185                     mount -t $(get_fstype "$cowdevice") -o rw "$cowdevice" /cow || panic "Can not mount $cowdevice on /cow"
186                     break
187                 fi
188                 sleep 5
189 #                sleep 0.1
190                 i=$(( $i + 1 ))
191             done
192         else
193             mount -t tmpfs tmpfs /cow
194         fi
195
196         mkdir -p /rofs
197     if [ "$(get_fstype $backdev)" = "unknown" ]; then
198         panic "Unknown file system type on $backdev"
199     fi
200         mount -t $(get_fstype "$backdev") -o ro "$backdev" /rofs || panic "Can not mount $backdev on /rofs"
201
202         mount -t unionfs -o dirs=/cow=rw:/rofs=ro unionfs "$rootmnt"
203         if grep -q show-cow /proc/cmdline; then
204             mkdir -p "$rootmnt/cow"
205             mount -o bind /cow "$rootmnt/cow"
206         fi
207         mkdir -p "$rootmnt/rofs"
208         mount -o bind /rofs "$rootmnt/rofs"
209 }
210
211 is_usb_device() {
212     sysfs_path="${1#/sys}"
213     if /lib/udev/path_id "${sysfs_path}" | grep -q "ID_PATH=usb"; then
214         return 0
215     fi
216     return 1
217 }
218
219 find_cd() {
220         mounted=
221         for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -v loop | grep -v ram); do
222             devname=$(sys2dev "${sysblock}")
223             fstype=$(get_fstype "${devname}")
224             if /lib/udev/cdrom_id ${devname} > /dev/null; then
225                 mount -t ${fstype} -o ro "$devname" $mountpoint || continue
226                 if casper_path $mountpoint; then
227                     echo $(casper_path $mountpoint)
228                     return
229                 else
230                     umount $mountpoint
231                 fi
232             elif is_usb_device "$sysblock"; then
233                 for dev in $(subdevices "${sysblock}"); do
234                     devname=$(sys2dev "${dev}")
235                     fstype=$(get_fstype "${devname}")
236                     case ${fstype} in
237                         vfat|iso9660|udf)
238                             mount -t ${fstype} -o ro "${devname}" $mountpoint || continue
239                             if casper_path $mountpoint; then
240                                 echo $(casper_path $mountpoint)
241                                 return
242                             else
243                                 umount $mountpoint
244                             fi
245                             ;;
246                     esac
247                 done
248             elif [ "${fstype}" = "squashfs" ]; then
249
250                 # This is an ugly hack situation, the block device has
251                 # a squashfs image directly on it.  It's hopefully
252                 # casper, so take it and run with it.
253
254                 ln -s "${devname}" "${devname}.${fstype}"
255                 echo "${devname}.${fstype}"
256                 return
257             fi
258         done
259 }
260
261 set_usplash_timeout() {
262     if [ -x /sbin/usplash_write ]; then
263         /sbin/usplash_write "TIMEOUT 120"
264     fi
265 }
266
267 mountroot() {
268     exec 6>&1
269     exec 7>&2
270     exec > casper.log
271     exec 2>&1
272
273     set_usplash_timeout
274     [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/casper-premount"
275     run_scripts /scripts/casper-premount
276     [ "$quiet" != "y" ] && log_end_msg
277
278     # Needed here too because some things (*cough* udev *cough*)
279     # changes the timeout
280
281     set_usplash_timeout
282
283     for i in 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13; do
284         live_image=$(find_cd)
285         if [ "${live_image}" ]; then
286             break
287         fi
288         sleep 1
289     done
290     if [ "$?" -gt 0 ]; then
291         panic "Unable to find a CD-ROM containing a live file system"
292     fi
293     
294     setup_cow "$overlay_method" "$(get_backing_device $live_image)" "$rootmnt"
295
296     log_end_msg
297
298     maybe_break casper-bottom
299     [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/casper-bottom"
300
301     PATH=/root/usr/bin:/root/usr/sbin:/root/bin:/root/sbin:$PATH run_scripts /scripts/casper-bottom
302     [ "$quiet" != "y" ] && log_end_msg
303
304     exec 1>&6 6>&-
305     exec 2>&7 7>&-
306     cp casper.log "${rootmnt}/var/log/"
307 }