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