Moving out live-helpers from initramfs-tools specifics.
[live-boot-grml.git] / scripts / boot.sh
1 #!/bin/sh
2
3 # set -e
4
5 for _SCRIPT in /lib/live/boot/*
6 do
7         if [ -e "${_SCRIPT}" ]
8         then
9                 . ${_SCRIPT}
10         fi
11 done
12
13 export PATH="/root/usr/bin:/root/usr/sbin:/root/bin:/root/sbin:/usr/bin:/usr/sbin:/bin:/sbin"
14
15 echo "/root/lib" >> /etc/ld.so.conf
16 echo "/root/usr/lib" >> /etc/ld.so.conf
17
18 mountpoint="/live/image"
19 alt_mountpoint="/media"
20 LIVE_MEDIA_PATH="live"
21
22 HOSTNAME="host"
23
24 mkdir -p "${mountpoint}"
25 tried="/tmp/tried"
26
27 # Create /etc/mtab for debug purpose and future syncs
28 if [ ! -d /etc ]
29 then
30         mkdir /etc/
31 fi
32
33 if [ ! -f /etc/mtab ]
34 then
35         touch /etc/mtab
36 fi
37
38 if [ ! -x "/bin/fstype" ]
39 then
40         # klibc not in path -> not in initramfs
41         export PATH="${PATH}:/usr/lib/klibc/bin"
42 fi
43
44 # handle upgrade path from old udev (using udevinfo) to
45 # recent versions of udev (using udevadm info)
46 if [ -x /sbin/udevadm ]
47 then
48         udevinfo='/sbin/udevadm info'
49 else
50         udevinfo='udevinfo'
51 fi
52
53 old_root_overlay_label="live-rw"
54 old_home_overlay_label="home-rw"
55 custom_overlay_label="custom-ov"
56 root_snapshot_label="live-sn"
57 old_root_snapshot_label="live-sn"
58 home_snapshot_label="home-sn"
59 persistence_list="live-persistence.conf"
60
61 if [ ! -f /live.vars ]
62 then
63         touch /live.vars
64 fi
65
66 is_live_path ()
67 {
68         DIRECTORY="${1}"
69
70         if [ -d "${DIRECTORY}"/"${LIVE_MEDIA_PATH}" ]
71         then
72                 for FILESYSTEM in squashfs ext2 ext3 ext4 xfs dir jffs2
73                 do
74                         if [ "$(echo ${DIRECTORY}/${LIVE_MEDIA_PATH}/*.${FILESYSTEM})" != "${DIRECTORY}/${LIVE_MEDIA_PATH}/*.${FILESYSTEM}" ]
75                         then
76                                 return 0
77                         fi
78                 done
79         fi
80
81         return 1
82 }
83
84 matches_uuid ()
85 {
86         if [ "${IGNORE_UUID}" ] || [ ! -e /conf/uuid.conf ]
87         then
88                 return 0
89         fi
90
91         path="${1}"
92         uuid="$(cat /conf/uuid.conf)"
93
94         for try_uuid_file in "${path}/.disk/live-uuid"*
95         do
96                 [ -e "${try_uuid_file}" ] || continue
97
98                 try_uuid="$(cat "${try_uuid_file}")"
99
100                 if [ "${uuid}" = "${try_uuid}" ]
101                 then
102                         return 0
103                 fi
104         done
105
106         return 1
107 }
108
109 get_backing_device ()
110 {
111         case "${1}" in
112                 *.squashfs|*.ext2|*.ext3|*.ext4|*.jffs2)
113                         echo $(setup_loop "${1}" "loop" "/sys/block/loop*" '0' "${LIVE_MEDIA_ENCRYPTION}" "${2}")
114                         ;;
115
116                 *.dir)
117                         echo "directory"
118                         ;;
119
120                 *)
121                         panic "Unrecognized live filesystem: ${1}"
122                         ;;
123         esac
124 }
125
126 match_files_in_dir ()
127 {
128         # Does any files match pattern ${1} ?
129         local pattern="${1}"
130
131         if [ "$(echo ${pattern})" != "${pattern}" ]
132         then
133                 return 0
134         fi
135
136         return 1
137 }
138
139 mount_images_in_directory ()
140 {
141         directory="${1}"
142         rootmnt="${2}"
143         mac="${3}"
144
145
146         if match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.squashfs" ||
147                 match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.ext2" ||
148                 match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.ext3" ||
149                 match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.ext4" ||
150                 match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.jffs2" ||
151                 match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.dir"
152         then
153                 [ -n "${mac}" ] && adddirectory="${directory}/${LIVE_MEDIA_PATH}/${mac}"
154                 setup_unionfs "${directory}/${LIVE_MEDIA_PATH}" "${rootmnt}" "${adddirectory}"
155         else
156                 panic "No supported filesystem images found at /${LIVE_MEDIA_PATH}."
157         fi
158 }
159
160 is_nice_device ()
161 {
162         sysfs_path="${1#/sys}"
163
164         if [ -e /lib/udev/path_id ]
165         then
166                 # squeeze
167                 PATH_ID="/lib/udev/path_id"
168         else
169                 # wheezy/sid (udev >= 174)
170                 PATH_ID="/sbin/udevadm test-builtin path_id"
171         fi
172
173         if ${PATH_ID} "${sysfs_path}" | egrep -q "ID_PATH=(usb|pci-[^-]*-(ide|sas|scsi|usb|virtio)|platform-sata_mv|platform-orion-ehci|platform-mmc|platform-mxsdhci)"
174         then
175                 return 0
176         elif echo "${sysfs_path}" | grep -q '^/block/vd[a-z]$'
177         then
178                 return 0
179         elif echo ${sysfs_path} | grep -q "^/block/dm-"
180         then
181                 return 0
182         elif echo ${sysfs_path} | grep -q "^/block/mtdblock"
183         then
184                 return 0
185         fi
186
187         return 1
188 }
189
190 check_dev ()
191 {
192         sysdev="${1}"
193         devname="${2}"
194         skip_uuid_check="${3}"
195
196         # support for fromiso=.../isofrom=....
197         if [ -n "$FROMISO" ]
198         then
199                 ISO_DEVICE=$(dirname $FROMISO)
200                 if ! [ -b $ISO_DEVICE ]
201                 then
202                         # to support unusual device names like /dev/cciss/c0d0p1
203                         # as well we have to identify the block device name, let's
204                         # do that for up to 15 levels
205                         i=15
206                         while [ -n "$ISO_DEVICE" ] && [ "$i" -gt 0 ]
207                         do
208                                 ISO_DEVICE=$(dirname ${ISO_DEVICE})
209                                 [ -b "$ISO_DEVICE" ] && break
210                                 i=$(($i -1))
211                         done
212                 fi
213
214                 if [ "$ISO_DEVICE" = "/" ]
215                 then
216                         echo "Warning: device for bootoption fromiso= ($FROMISO) not found.">>/boot.log
217                 else
218                         fs_type=$(get_fstype "${ISO_DEVICE}")
219                         if is_supported_fs ${fs_type}
220                         then
221                                 mkdir /live/fromiso
222                                 mount -t $fs_type "$ISO_DEVICE" /live/fromiso
223                                 ISO_NAME="$(echo $FROMISO | sed "s|$ISO_DEVICE||")"
224                                 loopdevname=$(setup_loop "/live/fromiso/${ISO_NAME}" "loop" "/sys/block/loop*" "" '')
225                                 devname="${loopdevname}"
226                         else
227                                 echo "Warning: unable to mount $ISO_DEVICE." >>/boot.log
228                         fi
229                 fi
230         fi
231
232         if [ -z "${devname}" ]
233         then
234                 devname=$(sys2dev "${sysdev}")
235         fi
236
237         if [ -d "${devname}" ]
238         then
239                 mount -o bind "${devname}" $mountpoint || continue
240
241                 if is_live_path $mountpoint
242                 then
243                         echo $mountpoint
244                         return 0
245                 else
246                         umount $mountpoint
247                 fi
248         fi
249
250         IFS=","
251         for device in ${devname}
252         do
253                 case "$device" in
254                         *mapper*)
255                                 # Adding lvm support
256                                 if [ -x /scripts/local-top/lvm2 ]
257                                 then
258                                         ROOT="$device" resume="" /scripts/local-top/lvm2
259                                 fi
260                                 ;;
261
262                         /dev/md*)
263                                 # Adding raid support
264                                 if [ -x /scripts/local-top/mdadm ]
265                                 then
266                                         cp /conf/conf.d/md /conf/conf.d/md.orig
267                                         echo "MD_DEVS=$device " >> /conf/conf.d/md
268                                         /scripts/local-top/mdadm
269                                         mv /conf/conf.d/md.orig /conf/conf.d/md
270                                 fi
271                                 ;;
272                 esac
273         done
274         unset IFS
275
276         [ -n "$device" ] && devname="$device"
277
278         [ -e "$devname" ] || continue
279
280         if [ -n "${LIVE_MEDIA_OFFSET}" ]
281         then
282                 loopdevname=$(setup_loop "${devname}" "loop" "/sys/block/loop*" "${LIVE_MEDIA_OFFSET}" '')
283                 devname="${loopdevname}"
284         fi
285
286         fstype=$(get_fstype "${devname}")
287
288         if is_supported_fs ${fstype}
289         then
290                 devuid=$(blkid -o value -s UUID "$devname")
291                 [ -n "$devuid" ] && grep -qs "\<$devuid\>" $tried && continue
292                 mount -t ${fstype} -o ro,noatime "${devname}" ${mountpoint} || continue
293                 [ -n "$devuid" ] && echo "$devuid" >> $tried
294
295                 if [ -n "${FINDISO}" ]
296                 then
297                         if [ -f ${mountpoint}/${FINDISO} ]
298                         then
299                                 umount ${mountpoint}
300                                 mkdir -p /live/findiso
301                                 mount -t ${fstype} -o ro,noatime "${devname}" /live/findiso
302                                 loopdevname=$(setup_loop "/live/findiso/${FINDISO}" "loop" "/sys/block/loop*" 0 "")
303                                 devname="${loopdevname}"
304                                 mount -t iso9660 -o ro,noatime "${devname}" ${mountpoint}
305                         else
306                                 umount ${mountpoint}
307                         fi
308                 fi
309
310                 if is_live_path ${mountpoint} && \
311                         ([ "${skip_uuid_check}" ] || matches_uuid ${mountpoint})
312                 then
313                         echo ${mountpoint}
314                         return 0
315                 else
316                         umount ${mountpoint} 2>/dev/null
317                 fi
318         fi
319
320         if [ -n "${LIVE_MEDIA_OFFSET}" ]
321         then
322                 losetup -d "${loopdevname}"
323         fi
324
325         return 1
326 }
327
328 find_livefs ()
329 {
330         timeout="${1}"
331
332         # don't start autodetection before timeout has expired
333         if [ -n "${LIVE_MEDIA_TIMEOUT}" ]
334         then
335                 if [ "${timeout}" -lt "${LIVE_MEDIA_TIMEOUT}" ]
336                 then
337                         return 1
338                 fi
339         fi
340
341         # first look at the one specified in the command line
342         case "${LIVE_MEDIA}" in
343                 removable-usb)
344                         for sysblock in $(removable_usb_dev "sys")
345                         do
346                                 for dev in $(subdevices "${sysblock}")
347                                 do
348                                         if check_dev "${dev}"
349                                         then
350                                                 return 0
351                                         fi
352                                 done
353                         done
354                         return 1
355                         ;;
356
357                 removable)
358                         for sysblock in $(removable_dev "sys")
359                         do
360                                 for dev in $(subdevices "${sysblock}")
361                                 do
362                                         if check_dev "${dev}"
363                                         then
364                                                 return 0
365                                         fi
366                                 done
367                         done
368                         return 1
369                         ;;
370
371                 *)
372                         if [ ! -z "${LIVE_MEDIA}" ]
373                         then
374                                 if check_dev "null" "${LIVE_MEDIA}" "skip_uuid_check"
375                                 then
376                                         return 0
377                                 fi
378                         fi
379                         ;;
380         esac
381
382         # or do the scan of block devices
383         # prefer removable devices over non-removable devices, so scan them first
384         devices_to_scan="$(removable_dev 'sys') $(non_removable_dev 'sys')"
385
386         for sysblock in $devices_to_scan
387         do
388                 devname=$(sys2dev "${sysblock}")
389                 [ -e "$devname" ] || continue
390                 fstype=$(get_fstype "${devname}")
391
392                 if /lib/udev/cdrom_id ${devname} > /dev/null
393                 then
394                         if check_dev "null" "${devname}"
395                         then
396                                 return 0
397                         fi
398                 elif is_nice_device "${sysblock}"
399                 then
400                         for dev in $(subdevices "${sysblock}")
401                         do
402                                 if check_dev "${dev}"
403                                 then
404                                         return 0
405                                 fi
406                         done
407                 elif [ "${fstype}" = "squashfs" -o \
408                         "${fstype}" = "btrfs" -o \
409                         "${fstype}" = "ext2" -o \
410                         "${fstype}" = "ext3" -o \
411                         "${fstype}" = "ext4" -o \
412                         "${fstype}" = "jffs2" ]
413                 then
414                         # This is an ugly hack situation, the block device has
415                         # an image directly on it.  It's hopefully
416                         # live-boot, so take it and run with it.
417                         ln -s "${devname}" "${devname}.${fstype}"
418                         echo "${devname}.${fstype}"
419                         return 0
420                 fi
421         done
422
423         return 1
424 }
425
426 integrity_check ()
427 {
428         media_mountpoint="${1}"
429
430         log_begin_msg "Checking media integrity"
431
432         cd ${media_mountpoint}
433         /bin/md5sum -c md5sum.txt < /dev/tty8 > /dev/tty8
434         RC="${?}"
435
436         log_end_msg
437
438         if [ "${RC}" -eq 0 ]
439         then
440                 log_success_msg "Everything ok, will reboot in 10 seconds."
441                 sleep 10
442                 cd /
443                 umount ${media_mountpoint}
444                 sync
445                 echo u > /proc/sysrq-trigger
446                 echo b > /proc/sysrq-trigger
447         else
448                 panic "Not ok, a media defect is likely, switch to VT8 for details."
449         fi
450 }
451
452 mountroot ()
453 {
454         if [ -x /scripts/local-top/cryptroot ]; then
455             /scripts/local-top/cryptroot
456         fi
457
458         exec 6>&1
459         exec 7>&2
460         exec > boot.log
461         exec 2>&1
462         tail -f boot.log >&7 &
463         tailpid="${!}"
464
465         # Ensure 'panic' function is overridden
466         . /scripts/live-functions
467
468         Arguments
469
470         maybe_break live-premount
471         log_begin_msg "Running /scripts/live-premount"
472         run_scripts /scripts/live-premount
473         log_end_msg
474
475         # Needed here too because some things (*cough* udev *cough*)
476         # changes the timeout
477
478         if [ ! -z "${NETBOOT}" ] || [ ! -z "${FETCH}" ] || [ ! -z "${HTTPFS}" ] || [ ! -z "${FTPFS}" ]
479         then
480                 if do_netmount
481                 then
482                         livefs_root="${mountpoint}"
483                 else
484                         panic "Unable to find a live file system on the network"
485                 fi
486         else
487                 if [ -n "${ISCSI_PORTAL}" ]
488                 then
489                         do_iscsi && livefs_root="${mountpoint}"
490                 elif [ -n "${PLAIN_ROOT}" ] && [ -n "${ROOT}" ]
491                 then
492                         # Do a local boot from hd
493                         livefs_root=${ROOT}
494                 else
495                         if [ -x /usr/bin/memdiskfind ]
496                         then
497                                 MEMDISK=$(/usr/bin/memdiskfind)
498
499                                 if [ $? -eq 0 ]
500                                 then
501                                         # We found a memdisk, set up phram
502                                         modprobe phram phram=memdisk,${MEMDISK}
503
504                                         # Load mtdblock, the memdisk will be /dev/mtdblock0
505                                         modprobe mtdblock
506                                 fi
507                         fi
508
509                         # Scan local devices for the image
510                         i=0
511                         while [ "$i" -lt 60 ]
512                         do
513                                 livefs_root=$(find_livefs ${i})
514
515                                 if [ -n "${livefs_root}" ]
516                                 then
517                                         break
518                                 fi
519
520                                 sleep 1
521                                 i="$(($i + 1))"
522                         done
523                 fi
524         fi
525
526         if [ -z "${livefs_root}" ]
527         then
528                 panic "Unable to find a medium containing a live file system"
529         fi
530
531         if [ "${INTEGRITY_CHECK}" ]
532         then
533                 integrity_check "${livefs_root}"
534         fi
535
536         if [ "${TORAM}" ]
537         then
538                 live_dest="ram"
539         elif [ "${TODISK}" ]
540         then
541                 live_dest="${TODISK}"
542         fi
543
544         if [ "${live_dest}" ]
545         then
546                 log_begin_msg "Copying live media to ${live_dest}"
547                 copy_live_to "${livefs_root}" "${live_dest}"
548                 log_end_msg
549         fi
550
551         # if we do not unmount the ISO we can't run "fsck /dev/ice" later on
552         # because the mountpoint is left behind in /proc/mounts, so let's get
553         # rid of it when running from RAM
554         if [ -n "$FROMISO" ] && [ "${TORAM}" ]
555         then
556                 losetup -d /dev/loop0
557
558                 if is_mountpoint /live/fromiso
559                 then
560                         umount /live/fromiso
561                         rmdir --ignore-fail-on-non-empty /live/fromiso \
562                                 >/dev/null 2>&1 || true
563                 fi
564         fi
565
566         if [ -n "${MODULETORAMFILE}" ] || [ -n "${PLAIN_ROOT}" ]
567         then
568                 setup_unionfs "${livefs_root}" "${rootmnt}"
569         else
570                 mac="$(get_mac)"
571                 mac="$(echo ${mac} | sed 's/-//g')"
572                 mount_images_in_directory "${livefs_root}" "${rootmnt}" "${mac}"
573         fi
574
575
576         if [ -n "${ROOT_PID}" ] ; then
577                 echo "${ROOT_PID}" > "${rootmnt}"/live/root.pid
578         fi
579
580         log_end_msg
581
582         # unionfs-fuse needs /dev to be bind-mounted for the duration of
583         # live-bottom; udev's init script will take care of things after that
584         if [ "${UNIONTYPE}" = unionfs-fuse ]
585         then
586                 mount -n -o bind /dev "${rootmnt}/dev"
587         fi
588
589         # Move to the new root filesystem so that programs there can get at it.
590         if [ ! -d /root/live/image ]
591         then
592                 mkdir -p /root/live/image
593                 mount --move /live/image /root/live/image
594         fi
595
596         # aufs2 in kernel versions around 2.6.33 has a regression:
597         # directories can't be accessed when read for the first the time,
598         # causing a failure for example when accessing /var/lib/fai
599         # when booting FAI, this simple workaround solves it
600         ls /root/* >/dev/null 2>&1
601
602         # Move findiso directory to the new root filesystem so that programs there can get at it.
603         if [ -d /live/findiso ] && [ ! -d /root/live/findiso ]
604         then
605                 mkdir -p /root/live/findiso
606                 mount -n --move /live/findiso /root/live/findiso
607         fi
608
609         # if we do not unmount the ISO we can't run "fsck /dev/ice" later on
610         # because the mountpoint is left behind in /proc/mounts, so let's get
611         # rid of it when running from RAM
612         if [ -n "$FINDISO" ] && [ "${TORAM}" ]
613         then
614                 losetup -d /dev/loop0
615
616                 if is_mountpoint /root/live/findiso
617                 then
618                         umount /root/live/findiso
619                         rmdir --ignore-fail-on-non-empty /root/live/findiso \
620                                 >/dev/null 2>&1 || true
621                 fi
622         fi
623
624         # copy snapshot configuration if exists
625         if [ -f snapshot.conf ]
626         then
627                 log_begin_msg "Copying snapshot.conf to ${rootmnt}/etc/live/boot.d"
628                 if [ ! -d "${rootmnt}/etc/live/boot.d" ]
629                 then
630                         mkdir -p "${rootmnt}/etc/live/boot.d"
631                 fi
632                 cp snapshot.conf "${rootmnt}/etc/live/boot.d/"
633                 log_end_msg
634         fi
635
636         if [ -f /etc/resolv.conf ] && [ ! -s ${rootmnt}/etc/resolv.conf ]
637         then
638                 log_begin_msg "Copying /etc/resolv.conf to ${rootmnt}/etc/resolv.conf"
639                 cp -v /etc/resolv.conf ${rootmnt}/etc/resolv.conf
640                 log_end_msg
641         fi
642
643         maybe_break live-bottom
644         log_begin_msg "Running /scripts/live-bottom\n"
645
646         run_scripts /scripts/live-bottom
647         log_end_msg
648
649         if [ "${UNIONFS}" = unionfs-fuse ]
650         then
651                 umount "${rootmnt}/dev"
652         fi
653
654         exec 1>&6 6>&-
655         exec 2>&7 7>&-
656         kill ${tailpid}
657         [ -w "${rootmnt}/var/log/" ] && mkdir -p /var/log/live && cp boot.log "${rootmnt}/var/log/live" 2>/dev/null
658 }