Merging casper 1.233.
[live-boot-grml.git] / scripts / live
index d05080d..ec3a639 100755 (executable)
@@ -20,6 +20,7 @@ USERFULLNAME="Live user"
 HOSTNAME="host"
 
 mkdir -p "${mountpoint}"
+tried="/tmp/tried"
 
 # Create /etc/mtab for debug purpose and future syncs
 if [ ! -d /etc ]
@@ -42,9 +43,39 @@ then
        touch /live.vars
 fi
 
+network_started=
+
+start_network ()
+{
+       [ -z "$network_started" ] || return
+       [ -z "$NETBOOT" ] || return
+
+       mount -n -o bind /sys /root/sys
+       mount -n -o bind /proc /root/proc
+       mount -n -o bind /dev /root/dev
+       mkdir -p /root/var/run/network
+
+       # Close inherited fd's to prevent debconf-communicate from
+       # continuing to run post-live-initramfs.
+       chroot /root dhclient eth0 3>&- 4<&-
+
+       network_started=1
+}
+
+stop_network ()
+{
+       [ "$network_started" ] || return
+
+       chroot /root ifconfig eth0 down
+       umount /root/sys
+       umount /root/proc
+       umount /root/dev
+}
+
 Arguments ()
 {
        PRESEEDS=""
+       LOCATIONS=""
 
        for ARGUMENT in $(cat /proc/cmdline)
        do
@@ -100,6 +131,16 @@ Arguments ()
                                export DEVICE
                                ;;
 
+                       ethdevice=*)
+                               ETHDEVICE="${ARGUMENT#ethdevice=}"
+                               export ETHDEVICE
+                               ;;
+
+                       ethdevice-timeout=*)
+                               ETHDEV_TIMEOUT="${ARGUMENT#ethdevice-timeout=}"
+                               export ETHDEV_TIMEOUT
+                               ;;
+
                        fetch=*)
                                 FETCH="${ARGUMENT#fetch=}"
                                 export FETCH
@@ -407,8 +448,8 @@ Arguments ()
                                ;;
 
                        preseed/file=*|file=*)
-                               LOCATION="${ARGUMENT#*=}"
-                               export LOCATION
+                               LOCATIONS="${ARGUMENT#*=} ${LOCATIONS}"
+                               export LOCATIONS
                                ;;
 
                        nopreseed)
@@ -417,22 +458,11 @@ Arguments ()
                                ;;
 
                        url=*)
-                               location="${ARGUMENT#url=}"
-
-                               mount -o bind /sys /root/sys
-                               mount -o bind /proc /root/proc
-                               mount -o bind /dev /root/dev
-
-                               mkdir -p /root/var/run/network
-                               [ "${NETBOOT}" ] || chroot /root dhclient eth0
-                               chroot /root wget -P /tmp "${location}"
-                               [ "${NETBOOT}" ] || chroot /root ifconfig eth0 down
-
-                               umount /root/sys
-                               umount /root/proc
-                               umount /root/dev
+                               URL_LOCATION="${ARGUMENT#url=}"
 
-                               LOCATION="/tmp/$(basename "${location}")"
+                               start_network
+                               chroot /root wget -P /tmp "${URL_LOCATION}"
+                               LOCATIONS="/tmp/$(basename ${URL_LOCATION}) ${LOCATIONS}"
                                ;;
 
                        */*=*)
@@ -655,12 +685,15 @@ is_nice_device ()
 {
        sysfs_path="${1#/sys}"
 
-       if /lib/udev/path_id "${sysfs_path}" | grep -E -q "ID_PATH=(usb|pci-|platform-mmc)"
+       if /lib/udev/path_id "${sysfs_path}" | egrep -q "ID_PATH=(usb|pci-|platform-orion-ehci|platform-mmc|platform-mxsdhci|)"
        then
                return 0
        elif echo "${sysfs_path}" | grep -q '^/block/vd[a-z]$'
        then
                return 0
+       elif echo ${sysfs_path} | grep -q "^/block/dm-"
+       then
+               return 0
        fi
 
        return 1
@@ -690,7 +723,7 @@ copy_live_to ()
        if [ "${copytodev}" = "ram" ]
        then
                # copying to ram:
-               freespace=$( expr $(awk '/MemFree/{print $2}' /proc/meminfo) + $( awk '/\<Cached/{print $2}' /proc/meminfo ) )
+               freespace=$(awk '/^MemFree:/{f=$2} /^Cached:/{c=$2} END{print f+c}' /proc/meminfo)
                mount_options="-o size=${size}k"
                free_string="memory"
                fstype="tmpfs"
@@ -744,7 +777,11 @@ copy_live_to ()
                                rsync -a --progress ${copyfrom}/* ${copyto} 1>/dev/console  # "cp -a" from busybox also copies hidden files
                        else
                                mkdir -p ${copyto}/${LIVE_MEDIA_PATH}
-                               cp -a ${copyfrom}/${LIVE_MEDIA_PATH}/* ${copyto}/${LIVE_MEDIA_PATH}   # "cp -a" from busybox also copies hidden files
+                               cp -a ${copyfrom}/${LIVE_MEDIA_PATH}/* ${copyto}/${LIVE_MEDIA_PATH}
+                               if [ -e ${copyfrom}/${LIVE_MEDIA_PATH}/.disk ]
+                               then
+                                       cp -a ${copyfrom}/${LIVE_MEDIA_PATH}/.disk ${copyto}
+                               fi
                        fi
                fi
 
@@ -765,7 +802,56 @@ do_netmount ()
        udevadm trigger
        udevadm settle
 
+       if [ -z "${NETBOOT}" ] && [ -z "${FETCH}" ] && \
+          [ -z "${HTTPFS}" ] && [ -z "${FTPFS}" ]
+       then
+
+       # if ethdevice was not specified on the kernel command line
+       # make sure we try to get a working network configuration
+       # for *every* present network device (except for loopback of course)
+       if [ -z "$ETHDEVICE" ] ; then
+               echo "If you want to boot from a specific device use bootoption ethdevice=..."
+               for device in /sys/class/net/*; do
+                       dev=${device##*/} ;
+                       if [ "$dev" != "lo" ] ; then
+                               ETHDEVICE="$ETHDEVICE $dev"
+                       fi
+               done
+       fi
+
+       # split args of ethdevice=eth0,eth1 into "eth0 eth1"
+       for device in $(echo $ETHDEVICE | sed 's/,/ /g') ; do
+               devlist="$devlist $device"
+       done
+
+       [ -n "$ETHDEV_TIMEOUT" ] || ETHDEV_TIMEOUT=15
+       echo "Using timeout of $ETHDEV_TIMEOUT seconds for network configuration."
+
+       # this is tricky (and ugly) because ipconfig sometimes just hangs/runs into
+       # an endless loop; iff execution fails give it two further tries, that's
+       # why we use '$devlist $devlist $devlist' for the other for loop
+       for dev in $devlist $devlist $devlist ; do
+               echo "Executing ipconfig -t $ETHDEV_TIMEOUT $dev"
+               ipconfig -t "$ETHDEV_TIMEOUT" $dev | tee -a /netboot.config &
+               jobid=$!
+               sleep "$ETHDEV_TIMEOUT" ; sleep 1
+               if [ -r /proc/"$jobid"/status ] ; then
+                       echo "Killing job $jobid for device $dev as ipconfig ran into recursion..."
+                       kill -9 $jobid
+               fi
+
+               # if configuration of device worked we should have an assigned
+               # IP address, iff so let's use the according as $DEVICE for later usage
+               # simple and primitive approach which seems to work fine
+               if ifconfig $dev | grep -q 'inet.*addr:' ; then
+                       export DEVICE="$dev"
+                       break
+               fi
+       done
+
+       else
        ipconfig ${DEVICE} | tee /netboot.config
+       fi
 
        # source relevant ipconfig output
        OLDHOSTNAME=${HOSTNAME}
@@ -774,7 +860,8 @@ do_netmount ()
        export HOSTNAME
 
        # Check if we have a network device at all
-       if ! ls /sys/class/net/eth0 > /dev/null 2>&1 && \
+       if ! ls /sys/class/net/"$DEVICE" > /dev/null 2>&1 && \
+          ! ls /sys/class/net/eth0 > /dev/null 2>&1 && \
           ! ls /sys/class/net/wlan0 > /dev/null 2>&1 && \
           ! ls /sys/class/net/ath0 > /dev/null 2>&1 && \
           ! ls /sys/class/net/ra0 > /dev/null 2>&1
@@ -943,7 +1030,7 @@ do_snap_copy ()
                        todev=$(awk -v pat="$(base_path ${todir})" '$2 == pat { print $1 }' /proc/mounts)
                        freespace=$(df -k | awk '/'${todev}'/{print $4}')
                else
-                       freespace=$( expr $(awk '/MemFree/{print $2}' /proc/meminfo) + $( awk '/\<Cached/{print $2}' /proc/meminfo))
+                       freespace=$(awk '/^MemFree:/{f=$2} /^Cached:/{c=$2} END{print f+c}' /proc/meminfo)
                fi
 
                tomount="/mnt/tmpsnap"
@@ -1029,14 +1116,23 @@ try_snap ()
                        RES=$?
                else
                        # cpio.gz snapshot
-                       cd "${snap_mount}"
-                       zcat "${snapback}/${snapfile}" | /bin/cpio --extract --preserve-modification-time --no-absolute-filenames --sparse --unconditional --make-directories > /dev/null 2>&1
-                       RES=$?
-                       if [ "${RES}" != "0" ]
+
+                       # Unfortunately klibc's cpio is incompatible with the
+                       # rest of the world; everything else requires -u -d,
+                       # while klibc doesn't implement them. Try to detect
+                       # whether it's in use.
+                       cpiopath="$(which cpio)" || true
+                       if [ "$cpiopath" ] && grep -aq /lib/klibc "$cpiopath"
+                       then
+                               cpioargs=
+                       else
+                               cpioargs='--unconditional --make-directories'
+                       fi
+
+                       if ! (cd "${snap_mount}" && zcat "${snapback}/${snapfile}" | cpio $cpioargs --extract --preserve-modification-time --no-absolute-filenames --sparse 2>/dev/null)
                        then
-                               log_warning_msg "failure to \"zcat ${snapback}/${snapfile} | /bin/cpio --extract --preserve-modification-time --no-absolute-filenames --sparse --unconditional --make-directories\""
+                               log_warning_msg "failure to \"zcat ${snapback}/${snapfile} | cpio $cpioargs --extract --preserve-modification-time --no-absolute-filenames --sparse\""
                        fi
-                       cd "${OLDPWD}"
                fi
 
                umount "${snapback}" ||  log_warning_msg "failure to \"umount ${snapback}\""
@@ -1077,7 +1173,7 @@ try_snap ()
                return 1
        fi
 
-       echo "export ${snap_type}SNAP="${snap_mount}":${snapdev}:${snapfile}" >> /etc/live.conf # for resync on reboot/halt
+       echo "export ${snap_type}SNAP="/cow${snap_mount#$rootmnt}":${snapdev}:${snapfile}" >> /etc/live.conf # for resync on reboot/halt
        return 0
 }
 
@@ -1367,6 +1463,8 @@ setup_unionfs ()
                        case "${UNIONTYPE}" in
                                unionfs-fuse)
                                        (ulimit -n 16384; unionfs-fuse -o cow -o noinitgroups -o default_permissions -o allow_other -o use_ino -o suid /cow=RW:${exposedrootfs}${dir} "${rootmnt}${dir}" || panic "mount ${UNIONTYPE} on ${rootmnt}${dir} failed with option cow,noinitgroups,default_permissions,allow_other,use_ino,suid=/cow=RW:${exposedrootfs}${dir}")
+                                       mkdir -p /dev/.initramfs/varrun
+                                       pidof unionfs-fuse >> /dev/.initramfs/varrun/sendsigs.omit || true
                                        ;;
 
                                *)
@@ -1378,6 +1476,8 @@ setup_unionfs ()
                case "${UNIONTYPE}" in
                        unionfs-fuse)
                                (ulimit -n 16384; unionfs-fuse -o cow -o noinitgroups -o default_permissions -o allow_other -o use_ino -o suid /cow=RW:${rofsstring} "${rootmnt}" || panic "mount ${UNIONTYPE} on ${rootmnt} failed with option cow,noinitgroups,default_permissions,allow_other,use_ino,suid=/cow:RW:${rofsstring}")
+                               mkdir -p /dev/.initramfs/varrun
+                               pidof unionfs-fuse >> /dev/.initramfs/varrun/sendsigs.omit || true
                                ;;
 
                        *)
@@ -1454,12 +1554,31 @@ check_dev ()
        # support for fromiso=.../isofrom=....
        if [ -n "$FROMISO" ]
        then
-               mkdir /isofrom
-               ISO_DEVICE="$(echo $FROMISO | sed 's|\(/dev/[a-z]*[0-9]*\).*|\1|')"
-               mount "$ISO_DEVICE" /isofrom
-               ISO_NAME="$(echo $FROMISO | sed 's|/dev/[a-z]*[0-9]*/||')"
-               loopdevname=$(setup_loop "/isofrom/${ISO_NAME}" "loop" "/sys/block/loop*" "" '')
-               devname="${loopdevname}"
+               ISO_DEVICE=$(dirname $FROMISO)
+               if ! [ -b $ISO_DEVICE ]
+               then
+                       # to support unusual device names like /dev/cciss/c0d0p1
+                       # as well we have to identify the block device name, let's
+                       # do that for up to 15 levels
+                       i=15
+                       while [ -n "$ISO_DEVICE" ] && [ "$i" -gt 0 ]
+                       do
+                               ISO_DEVICE=$(dirname ${ISO_DEVICE})
+                               [ -b "$ISO_DEVICE" ] && break
+                               i=$(($i -1))
+                       done
+               fi
+
+               if [ "$ISO_DEVICE" = "/" ]
+               then
+                       echo "Warning: device for bootoption isofrom= ($FROMISO) not found.">>/live.log
+               else
+                       mkdir /isofrom
+                       mount "$ISO_DEVICE" /isofrom
+                       ISO_NAME="$(echo $FROMISO | sed "s|$ISO_DEVICE||")"
+                       loopdevname=$(setup_loop "/isofrom/${ISO_NAME}" "loop" "/sys/block/loop*" "" '')
+                       devname="${loopdevname}"
+               fi
        fi
 
        if [ -z "${devname}" ]
@@ -1479,6 +1598,7 @@ check_dev ()
                        umount $mountpoint
                fi
        fi
+       [ -e "$devname" ] || continue
 
        if [ -n "${LIVE_MEDIA_OFFSET}" ]
        then
@@ -1490,7 +1610,10 @@ check_dev ()
 
        if is_supported_fs ${fstype}
        then
+               devuid=$(blkid -o value -s UUID "$devname")
+               [ -n "$devuid" ] && grep -qs "\<$devuid\>" $tried && continue
                mount -t ${fstype} -o ro,noatime "${devname}" ${mountpoint} || continue
+               [ -n "$devuid" ] && echo "$devuid" >> $tried
 
                if is_live_path ${mountpoint} && \
                        ([ "${skip_uuid_check}" ] || matches_uuid ${mountpoint})
@@ -1575,9 +1698,22 @@ find_livefs ()
        esac
 
        # or do the scan of block devices
-       for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -vE "/(loop|ram|dm-|fd)")
+       # prefer removable devices over non-removable devices, so scan them first
+       for sysblock in $(echo /sys/block/* | tr ' ' '\n' | egrep -v "/(loop|ram|dm-|fd)")
+       do
+               if [ "$(cat ${sysblock}/removable)" = "1" ]
+               then
+                       removable_devices_to_scan="$removable_devices_to_scan $sysblock"
+               else
+                       nonremovable_devices_to_scan="$nonremovable_devices_to_scan $sysblock"
+               fi
+       done
+       devices_to_scan="$removable_devices_to_scan $nonremovable_devices_to_scan"
+
+       for sysblock in $devices_to_scan
        do
                devname=$(sys2dev "${sysblock}")
+               [ -e "$devname" ] || continue
                fstype=$(get_fstype "${devname}")
 
                if /lib/udev/cdrom_id ${devname} > /dev/null
@@ -1649,6 +1785,14 @@ integrity_check ()
        fi
 }
 
+start_usplash_pulse ()
+{
+       if [ -x /sbin/usplash_write ]
+       then
+               /sbin/usplash_write "PULSELOGO"
+       fi
+}
+
 mountroot ()
 {
         if [ -x /scripts/local-top/cryptroot ]; then
@@ -1668,6 +1812,7 @@ mountroot ()
        Arguments
 
        set_usplash_timeout
+       start_usplash_pulse
 
        maybe_break live-premount
        log_begin_msg "Running /scripts/live-premount"
@@ -1762,6 +1907,36 @@ mountroot ()
                mount -n -o bind /dev "${rootmnt}/dev"
        fi
 
+       # Open up two fifo's fd's for debconf-communicate to use. Speeds up
+       # the live-initramfs process considerably.
+       log_begin_msg "Creating debconf-communicate fifo mechanism"
+       mkfifo /tmp/debconf-in.fifo
+       mkfifo /tmp/debconf-out.fifo
+
+       # Make the template database read-only, so that passthrough debconf
+       # instances can write to it directly; otherwise templates are only
+       # passed through when necessary.  Use temporary config databases as
+       # well; we'll copy their contents back at the end.
+       DEBCONF_TMPDIR="$(chroot /root mktemp -dt debconf.XXXXXX)"
+       cp -a /root/var/cache/debconf/config.dat "/root$DEBCONF_TMPDIR/"
+       cp -a /root/var/cache/debconf/passwords.dat "/root$DEBCONF_TMPDIR/"
+       sed "s,^Filename: /var/cache/debconf/\(config\|passwords\).dat$,Filename: $DEBCONF_TMPDIR/\1.dat,; /^Name: templatedb/a\
++Readonly: true" /root/etc/debconf.conf >"/root$DEBCONF_TMPDIR/debconf.conf"
+
+       # Save the PID so it can be killed later.
+       DEBCONF_SYSTEMRC="$DEBCONF_TMPDIR/debconf.conf" chroot /root debconf-communicate -fnoninteractive live-initramfs > /tmp/debconf-out.fifo < /tmp/debconf-in.fifo &
+
+       if [ ! -p /tmp/debconf-in.fifo ] || [ ! -p /tmp/debconf-out.fifo ]
+       then
+               log_warning_msg "failed to setup debconf-communicate channel"
+       fi
+       log_end_msg
+
+       # Order matters!
+       # These file descriptors must stay open until we're finished with
+       # debconf-communicate.
+       exec 4</tmp/debconf-out.fifo 3>/tmp/debconf-in.fifo
+
        maybe_break live-bottom
        log_begin_msg "Running /scripts/live-bottom\n"
 
@@ -1773,8 +1948,26 @@ mountroot ()
                umount "${rootmnt}/dev"
        fi
 
+       # Close the fd's associated with debconf-communicate
+       exec 3>&- 4<&-
+       rm -f /tmp/debconf-in.fifo
+       rm -f /tmp/debconf-out.fifo
+
+       # Copy config database changes back to the master files.
+       chroot /root debconf-copydb tmpdb config \
+               --config=Name:tmpdb --config=Driver:File \
+               --config="Filename:$DEBCONF_TMPDIR/config.dat"
+       chroot /root debconf-copydb tmpdb passwords \
+               --config=Name:tmpdb --config=Driver:File \
+               --config="Filename:$DEBCONF_TMPDIR/passwords.dat"
+       rm -rf "$DEBCONF_TMPDIR"
+
        exec 1>&6 6>&-
        exec 2>&7 7>&-
        kill ${tailpid}
        [ -w "${rootmnt}/var/log/" ] && cp live.log "${rootmnt}/var/log/" 2>/dev/null
+       if [ -f /etc/live.conf ]
+       then
+               cp /etc/live.conf "${rootmnt}/etc/"
+       fi
 }