X-Git-Url: http://git.grml.org/?a=blobdiff_plain;f=scripts%2Flive;h=a17eb423fca132f0aaf03c8ca6f956766eaef797;hb=52dcef518bdb95605670b8dc12257057bf7a2dc0;hp=8543cf13243fa99033734738b608d77e964b9199;hpb=505ccfa2ff092ac83e44acc8564dc2f5897456ed;p=live-boot-grml.git diff --git a/scripts/live b/scripts/live index 8543cf1..a17eb42 100755 --- a/scripts/live +++ b/scripts/live @@ -8,6 +8,7 @@ echo "/root/lib" >> /etc/ld.so.conf echo "/root/usr/lib" >> /etc/ld.so.conf mountpoint="/live/image" +alt_mountpoint="/media" LIVE_MEDIA_PATH="live" root_persistence="live-rw" @@ -20,6 +21,7 @@ USERFULLNAME="Live user" HOSTNAME="host" mkdir -p "${mountpoint}" +tried="/tmp/tried" # Create /etc/mtab for debug purpose and future syncs if [ ! -d /etc ] @@ -32,9 +34,6 @@ then touch /etc/mtab fi -[ -f /etc/live.conf ] && . /etc/live.conf -export USERNAME USERFULLNAME HOSTNAME - . /scripts/live-helpers if [ ! -f /live.vars ] @@ -45,10 +44,20 @@ fi Arguments () { PRESEEDS="" + LOCATIONS="" for ARGUMENT in $(cat /proc/cmdline) do case "${ARGUMENT}" in + skipconfig) + NOACCESSIBILITY="Yes" + NOFASTBOOT="Yes" + NOFSTAB="Yes" + NONETWORKING="Yes" + + export NOACCESSIBILITY NOFASTBOOT NOFSTAB NONETWORKING + ;; + access=*) ACCESS="${ARGUMENT#access=}" export ACCESS @@ -66,14 +75,36 @@ Arguments () set -x ;; + dhcp) + # Force dhcp even while netbooting + # Use for debugging in case somebody works on fixing dhclient + DHCP="Force"; + export DHCP + ;; + + nodhcp) + unset DHCP + ;; + + ethdevice=*) + DEVICE="${ARGUMENT#ethdevice=}" + ETHDEVICE="${DEVICE}" + export DEVICE ETHDEVICE + ;; + + ethdevice-timeout=*) + ETHDEV_TIMEOUT="${ARGUMENT#ethdevice-timeout=}" + export ETHDEV_TIMEOUT + ;; + fetch=*) FETCH="${ARGUMENT#fetch=}" export FETCH ;; - hook=*) - HOOK="${ARGUMENT#hook=}" - export HOOK + forcepersistentfsck) + FORCEPERSISTENTFSCK="Yes" + export FORCEPERSISTENTFSCK ;; ftpfs=*) @@ -84,24 +115,24 @@ Arguments () httpfs=*) HTTPFS="${ARGUMENT#httpfs=}" export HTTPFS - ;; - - hostname=*) - HOSTNAME="${ARGUMENT#hostname=}" - LIVECONF="changed" - export HOSTNAME LIVECONF - ;; + ;; - username=*) - USERNAME="${ARGUMENT#username=}" - LIVECONF="changed" - export USERNAME LIVECONF + iscsi=*) + ISCSI="${ARGUMENT#iscsi=}" + #ip:port - separated by ; + ISCSI_PORTAL="${ISCSI%;*}" + if echo "${ISCSI_PORTAL}" | grep -q , ; then + ISCSI_SERVER="${ISCSI_PORTAL%,*}" + ISCSI_PORT="${ISCSI_PORTAL#*,}" + fi + #target name + ISCSI_TARGET="${ISCSI#*;}" + export ISCSI ISCSI_PORTAL ISCSI_TARGET ISCSI_SERVER ISCSI_PORT ;; - userfullname=*) - USERFULLNAME="${ARGUMENT#userfullname=}" - LIVECONF="changed" - export USERFULLNAME LIVECONF + isofrom=*|fromiso=*) + FROMISO="${ARGUMENT#*=}" + export FROMISO ;; ignore_uuid) @@ -109,6 +140,11 @@ Arguments () export IGNORE_UUID ;; + integrity-check) + INTEGRITY_CHECK="Yes" + export INTEGRITY_CHECK + ;; + ip=*) STATICIP="${ARGUMENT#ip=}" @@ -120,31 +156,6 @@ Arguments () export STATICIP ;; - keyb=*|kbd-chooser/method=*) - KBD="${ARGUMENT#*=}" - export KBD - ;; - - klayout=*|console-setup/layoutcode=*) - KLAYOUT="${ARGUMENT#*=}" - export KLAYOUT - ;; - - kvariant=*|console-setup/variantcode=*) - KVARIANT="${ARGUMENT#*=}" - export KVARIANT - ;; - - kmodel=*|console-setup/modelcode=*) - KMODEL="${ARGUMENT#*=}" - export KMODEL - ;; - - koptions=*) - KOPTIONS="${ARGUMENT#koptions=}" - export KOPTIONS - ;; - live-getty) LIVE_GETTY="1" export LIVE_GETTY @@ -175,17 +186,6 @@ Arguments () export LIVE_MEDIA_TIMEOUT ;; - language=*|debian-installer/language=*) - language=${x#debian-installer/language=} - locale="$(lang2locale "$language")" - set_locale="true" - ;; - - locale=*|debian-installer/locale=*) - LOCALE="${ARGUMENT#*=}" - export LOCALE - ;; - module=*) MODULE="${ARGUMENT#module=}" export MODULE @@ -211,31 +211,6 @@ Arguments () export NOACCESSIBILITY ;; - noapparmor) - NOAPPARMOR="Yes" - export NOAPPARMOR - ;; - - noaptcdrom) - NOAPTCDROM="Yes" - export NOAPTCDROM - ;; - - noautologin) - NOAUTOLOGIN="Yes" - export NOAUTOLOGIN - ;; - - noxautologin) - NOXAUTOLOGIN="Yes" - export NOXAUTOLOGIN - ;; - - noconsolekeyboard) - NOCONSOLEKEYBOARD="Yes" - export NOCONSOLEKEYBOARD - ;; - nofastboot) NOFASTBOOT="Yes" export NOFASTBOOT @@ -246,81 +221,16 @@ Arguments () export NOFSTAB ;; - nognomepanel) - NOGNOMEPANEL="Yes" - export NOGNOMEPANEL - ;; - - nohosts) - NOHOSTS="Yes" - export NOHOSTS - ;; - - nokpersonalizer) - NOKPERSONALIZER="Yes" - export NOKPERSONALIZER - ;; - - nolanguageselector) - NOLANGUAGESELECTOR="Yes" - export NOLANGUAGESELECTOR - ;; - - nolocales) - NOLOCALES="Yes" - export NOLOCALES - ;; - nonetworking) NONETWORKING="Yes" export NONETWORKING ;; - nopowermanagement) - NOPOWERMANAGEMENT="Yes" - export NOPOWERMANAGEMENT - ;; - - noprogramcrashes) - NOPROGRAMCRASHES="Yes" - export NOPROGRAMCRASHES - ;; - - nojockey) - NOJOCKEY="Yes" - export NOJOCKEY - ;; - - nosudo) - NOSUDO="Yes" - export NOSUDO - ;; - swapon) SWAPON="Yes" export SWAPON ;; - noupdatenotifier) - NOUPDATENOTIFIER="Yes" - export NOUPDATENOTIFIER - ;; - - nouser) - NOUSER="Yes" - export NOUSER - ;; - - noxautoconfig) - NOXAUTOCONFIG="Yes" - export NOXAUTOCONFIG - ;; - - noxscreensaver) - NOXSCREENSAVER="Yes" - export NOXSCREENSAVER - ;; - persistent) PERSISTENT="Yes" export PERSISTENT @@ -335,14 +245,31 @@ Arguments () export PERSISTENT ;; + persistent-path=*) + PERSISTENT_PATH="${ARGUMENT#persistent-path=}" + export PERSISTENT_PATH + ;; + + persistent-subtext=*) + root_persistence="${root_persistence}-${ARGUMENT#persistent-subtext=}" + home_persistence="${home_persistence}-${ARGUMENT#persistent-subtext=}" + root_snapshot_label="${root_snapshot_label}-${ARGUMENT#persistent-subtext=}" + home_snapshot_label="${home_snapshot_label}-${ARGUMENT#persistent-subtext=}" + ;; + nopersistent) NOPERSISTENT="Yes" export NOPERSISTENT ;; + quickusbmodules) + QUICKUSBMODULES="Yes" + export QUICKUSBMODULES + ;; + preseed/file=*|file=*) - LOCATION="${ARGUMENT#*=}" - export LOCATION + LOCATIONS="${ARGUMENT#*=} ${LOCATIONS}" + export LOCATIONS ;; nopreseed) @@ -350,25 +277,6 @@ Arguments () export NOPRESEED ;; - 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 - chroot /root dhclient eth0 - chroot /root wget -P /tmp "${location}" - chroot /root ifconfig eth0 down - - umount /root/sys - umount /root/proc - umount /root/dev - - LOCATION="/tmp/$(basename "${location}")" - ;; - */*=*) question="${ARGUMENT%%=*}" value="${ARGUMENT#*=}" @@ -381,19 +289,9 @@ Arguments () export SHOWMOUNTS ;; - textonly) - TEXTONLY="Yes" - export TEXTONLY - ;; - - timezone=*) - TIMEZONE="${ARGUMENT#timezone=}" - export TIMEZONE - ;; - - notimezone) - NOTIMEZONE="Yes" - export NOTIMEZONE + silent) + SILENT="Yes" + export SILENT ;; todisk=*) @@ -422,6 +320,11 @@ Arguments () export PLAIN_ROOT ;; + skipunion) + SKIP_UNION_MOUNTS="Yes" + export SKIP_UNION_MOUNTS + ;; + root=*) ROOT="${ARGUMENT#root=}" export ROOT @@ -431,26 +334,6 @@ Arguments () UNIONTYPE="${ARGUMENT#union=}" export UNIONTYPE ;; - - utc=*) - UTC="${ARGUMENT#utc=}" - export UTC - ;; - - xdebconf) - XDEBCONF="Yes" - export XDEBCONF - ;; - - xdriver=*) - XDRIVER="${ARGUMENT#xdriver=}" - export XDRIVER - ;; - - xvideomode=*) - XVIDEOMODE="${ARGUMENT#xvideomode=}" - export XVIDEOMODE - ;; esac done @@ -487,7 +370,7 @@ is_live_path () if [ -d "${DIRECTORY}"/"${LIVE_MEDIA_PATH}" ] then - for FILESYSTEM in squashfs ext2 ext3 xfs dir jffs2 + for FILESYSTEM in squashfs ext2 ext3 ext4 xfs dir jffs2 do if [ "$(echo ${DIRECTORY}/${LIVE_MEDIA_PATH}/*.${FILESYSTEM})" != "${DIRECTORY}/${LIVE_MEDIA_PATH}/*.${FILESYSTEM}" ] then @@ -527,7 +410,7 @@ matches_uuid () get_backing_device () { case "${1}" in - *.squashfs|*.ext2|*.ext3|*.jffs2) + *.squashfs|*.ext2|*.ext3|*.ext4|*.jffs2) echo $(setup_loop "${1}" "loop" "/sys/block/loop*" '0' "${LIVE_MEDIA_ENCRYPTION}" "${2}") ;; @@ -564,6 +447,7 @@ mount_images_in_directory () if match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.squashfs" || match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.ext2" || match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.ext3" || + match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.ext4" || match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.jffs2" || match_files_in_dir "${directory}/${LIVE_MEDIA_PATH}/*.dir" then @@ -578,12 +462,15 @@ is_nice_device () { sysfs_path="${1#/sys}" - if /lib/udev/path_id "${sysfs_path}" | grep -E -q "ID_PATH=(usb|pci-[^-]*-(ide|scsi|usb))" + 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 @@ -597,7 +484,7 @@ copy_live_to () if [ -z "${MODULETORAM}" ] then - size=$(fs_size "" ${copyfrom} "used") + size=$(fs_size "" ${copyfrom}/${LIVE_MEDIA_PATH} "used") else MODULETORAMFILE="${copyfrom}/${LIVE_MEDIA_PATH}/${MODULETORAM}" @@ -613,7 +500,7 @@ copy_live_to () if [ "${copytodev}" = "ram" ] then # copying to ram: - freespace=$( expr $(awk '/MemFree/{print $2}' /proc/meminfo) + $( awk '/\/dev/console + rsync -a --progress ${MODULETORAMFILE} ${copyto} 1>/dev/console # copy only the filesystem module + else + cp ${MODULETORAMFILE} ${copyto} # copy only the filesystem module + fi else - cp -a ${copyfrom}/* ${copyto} # "cp -a" from busybox also copies hidden files + if [ -x /bin/rsync ] + then + echo " * Copying whole medium to RAM" 1>/dev/console + 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} + if [ -e ${copyfrom}/${LIVE_MEDIA_PATH}/.disk ] + then + cp -a ${copyfrom}/${LIVE_MEDIA_PATH}/.disk ${copyto} + fi + fi fi - livefs_root umount ${copyfrom} mount -r -o move ${copyto} ${copyfrom} fi @@ -667,24 +570,63 @@ copy_live_to () return 0 } -do_netmount () +do_netsetup () { - rc=1 - modprobe -q af_packet # For DHCP - if [ -x /sbin/udevadm ] + udevadm trigger + udevadm settle + + if [ -z "${NETBOOT}" ] && [ -z "${FETCH}" ] && \ + [ -z "${HTTPFS}" ] && [ -z "${FTPFS}" ] then - # lenny - udevadm trigger - udevadm settle - else - # etch - udevtrigger - udevsettle + + # 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} @@ -692,24 +634,53 @@ do_netmount () [ -z ${HOSTNAME} ] && HOSTNAME=${OLDHOSTNAME} export HOSTNAME + if [ -n "${DEVICE}" ] + then + HWADDR="$(cat /sys/class/net/${DEVICE}/address)" + fi + + if [ ! -e "/etc/resolv.conf" ] + then + echo "Creating /etc/resolv.conf" + + if [ -n "${DNSDOMAIN}" ] + then + echo "domain ${DNSDOMAIN}" > /etc/resolv.conf + echo "search ${DNSDOMAIN}" > /etc/resolv.conf + fi + + for i in ${IPV4DNS0} ${IPV4DNS1} ${IPV4DNS1} + do + echo "nameserver $i" >> /etc/resolv.conf + done + fi + # 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 then panic "No supported network device found, maybe a non-mainline driver is required." fi +} + +do_netmount() +{ + do_netsetup if [ "${NFSROOT}" = "auto" ] then NFSROOT=${ROOTSERVER}:${ROOTPATH} fi - if ( [ -n "${FETCH}" ] || [ -n "${HTTPFS}" ] || [ -n "${FTPFS}" ] ) && do_httpmount + rc=1 + + if ( [ -n "${FETCH}" ] || [ -n "${HTTPFS}" ] || [ -n "${FTPFS}" ] ) then - rc=0 - return ${rc} + do_httpmount + return $? fi if [ "${NFSROOT#*:}" = "${NFSROOT}" ] && [ "$NETBOOT" != "cifs" ] @@ -733,29 +704,85 @@ do_netmount () return ${rc} } +do_iscsi() +{ + do_netsetup + #modprobe ib_iser + modprobe iscsi_tcp + local debugopt="" + [ "${DEBUG}" == "Yes" ] && debugopt="-d 8" + #FIXME this name is supposed to be unique - some date + ifconfig hash? + ISCSI_INITIATORNAME="iqn.1993-08.org.debian.live:01:$(echo "${HWADDR}" | sed -e s/://g)" + export ISCSI_INITIATORNAME + if [ -n "${ISCSI_SERVER}" ] ; then + iscsistart $debugopt -i "${ISCSI_INITIATORNAME}" -t "${ISCSI_TARGET}" -g 1 -a "${ISCSI_SERVER}" -p "${ISCSI_PORT}" + else + iscsistart $debugopt -i "${ISCSI_INITIATORNAME}" -t "${ISCSI_TARGET}" -g 1 -a "${ISCSI_PORTAL}" -p 3260 + fi + if [ $? != 0 ] + then + panic "Failed to log into iscsi target" + fi + local host="$(ls -d /sys/class/scsi_host/host*/device/iscsi_host:host* \ + /sys/class/scsi_host/host*/device/iscsi_host/host* | sed -e 's:/device.*::' -e 's:.*host::')" + if [ -n "${host}" ] + then + local devices="" + local i=0 + while [ -z "${devices}" -a $i -lt 60 ] + do + sleep 1 + devices="$(ls -d /sys/class/scsi_device/${host}*/device/block:* \ + /sys/class/scsi_device/${host}*/device/block/* | sed -e 's!.*[:/]!!')" + i=$(expr $i + 1) + echo -ne $i\\r + done + for dev in $devices + do + if check_dev "null" "/dev/$dev" + then + NETBOOT="iscsi" + export NETBOOT + return 0; + fi + done + panic "Failed to locate a live device on iSCSI devices (tried: $devices)." + else + panic "Failed to locate iSCSI host in /sys" + fi +} + do_httpmount () { rc=1 - dest="${mountpoint}/${LIVE_MEDIA_PATH}" - mount -t ramfs ram "${mountpoint}" - mkdir -p "${dest}" for webfile in HTTPFS FTPFS FETCH do - url="$(eval echo \"\$\{${webfile}\}\")" - extension="$(echo "${url}" | sed 's/\(.*\)\.\(.*\)/\2/')" + local url="$(eval echo \"\$\{${webfile}\}\")" + local extension="$(echo "${url}" | sed 's/\(.*\)\.\(.*\)/\2/')" if [ -n "$url" ] then case "${extension}" in - squashfs|tgz|tar) + iso|squashfs|tgz|tar) + if [ "${extension}" = "iso" ] + then + mkdir -p "${alt_mountpoint}" + dest="${alt_mountpoint}" + else + local dest="${mountpoint}/${LIVE_MEDIA_PATH}" + mount -t ramfs ram "${mountpoint}" + mkdir -p "${dest}" + fi if [ "${webfile}" = "FETCH" ] then case "$url" in tftp*) - ip="$(dirname $url | sed -e 's|tftp://||g')" - log_begin_msg "Trying tftp -g -b 10240 -r $(basename ${url}) -l ${dest}/$(basename ${url}) $ip" - tftp -g -b 10240 -r $(basename ${url}) -l ${dest}/$(basename ${url}) $ip + ip="$(dirname $url | sed -e 's|tftp://||g' -e 's|/.*$||g')" + rfile="$(echo $url | sed -e "s|tftp://$ip||g")" + lfile="$(basename $url)" + log_begin_msg "Trying tftp -g -b 10240 -r $rfile -l ${dest}/$lfile $ip" + tftp -g -b 10240 -r $rfile -l ${dest}/$lfile $ip ;; *) @@ -774,9 +801,16 @@ do_httpmount () fi modprobe fuse $FUSE_MOUNT "${url}" "${dest}" + ROOT_PID="$(minips h -C "$FUSE_MOUNT" | { read x y ; echo "$x" ; } )" fi [ ${?} -eq 0 ] && rc=0 [ "${extension}" = "tgz" ] && live_dest="ram" + if [ "${extension}" = "iso" ] + then + isoloop=$(setup_loop "${dest}/$(basename "${url}")" "loop" "/sys/block/loop*" "" '') + mount -t iso9660 "${isoloop}" "${mountpoint}" + rc=${?} + fi break ;; @@ -789,7 +823,15 @@ do_httpmount () if [ ${rc} != 0 ] then - umount "${mountpoint}" + if [ -d "${alt_mountpoint}" ] + then + umount "${alt_mountpoint}" + rmdir "${alt_mountpoint}" + fi + umount "${mountpoint}" + elif [ "${webfile}" != "FETCH" ] ; then + NETBOOT="${webfile}" + export NETBOOT fi return ${rc} @@ -860,7 +902,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 '/\ /dev/null 2>&1 - RES=$? + + # 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 + + cd "${snap_mount}" && zcat "${snapback}/${snapfile}" | $cpiopath $cpioargs --extract --preserve-modification-time --no-absolute-filenames --sparse 2>/dev/null + RES="$?" + if [ "${RES}" != "0" ] 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} | $cpiopath $cpioargs --extract --preserve-modification-time --no-absolute-filenames --sparse\"" fi - cd "${OLDPWD}" fi umount "${snapback}" || log_warning_msg "failure to \"umount ${snapback}\"" @@ -963,12 +1018,11 @@ try_snap () log_warning_msg "Impossible to include the ${snapfile} Snapshot file" fi - elif [ -b "${snapdata}" ] then # Try to find if it could be a snapshot partition dev="${snapdata}" - log_success_msg "found snapshot device on ${dev}" + log_success_msg "found snapshot ${snap_type} device on ${dev}" if echo "${dev}" | grep -qs loop then # strange things happens, user confused? @@ -995,7 +1049,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 } @@ -1004,7 +1058,25 @@ setup_unionfs () image_directory="${1}" rootmnt="${2}" addimage_directory="${3}" - modprobe -q -b ${UNIONTYPE} + + case ${UNIONTYPE} in + aufs|unionfs) + modprobe -q -b ${UNIONTYPE} + + if ! cut -f2 /proc/filesystems | grep -q "^${UNIONTYPE}\$" && [ -x /bin/unionfs-fuse ] + then + echo "${UNIONTYPE} not available, falling back to unionfs-fuse." + echo "This might be really slow." + + UNIONTYPE="unionfs-fuse" + fi + ;; + esac + + if [ "${UNIONTYPE}" = unionfs-fuse ] + then + modprobe fuse + fi # run-init can't deal with images in a subdir, but we're going to # move all of these away before it runs anyway. No, we're not, @@ -1016,50 +1088,38 @@ setup_unionfs () # Let's just mount the read-only file systems first rofsstring="" rofslist="" - minor_kernel_version=$(uname -r|cut -c 5-|sed 's/[^0-9].*//') - if [ "${NETBOOT}" = "nfs" ] && [ "${minor_kernel_version}" -lt 22 ] - then - # go aroung a bug in nfs-unionfs locking for unionfs <= 1.4 - roopt="nfsro" - elif [ "${UNIONTYPE}" = "aufs" ] + if [ "${UNIONTYPE}" = "aufs" ] then roopt="rr" + noxino_opt="noxino," + elif [ "${UNIONTYPE}" = "unionfs-fuse" ] + then + roopt="RO" else roopt="ro" fi - # Read image names from ${MODULE}.module if it exists - if [ -e "${image_directory}/filesystem.${MODULE}.module" ] - then - for IMAGE in $(cat ${image_directory}/filesystem.${MODULE}.module) - do - image_string="${image_string} ${image_directory}/${IMAGE}" - done - elif [ -e "${image_directory}/${MODULE}.module" ] + if [ -z "${PLAIN_ROOT}" ] then - for IMAGE in $(cat ${image_directory}/${MODULE}.module) - do - image_string="${image_string} ${image_directory}/${IMAGE}" - done - else - # ${MODULE}.module does not exist, create a list of images - for FILESYSTEM in squashfs ext2 ext3 xfs jffs2 dir - do - for IMAGE in "${image_directory}"/*."${FILESYSTEM}" + # Read image names from ${MODULE}.module if it exists + if [ -e "${image_directory}/filesystem.${MODULE}.module" ] + then + for IMAGE in $(cat ${image_directory}/filesystem.${MODULE}.module) do - if [ -e "${IMAGE}" ] - then - image_string="${image_string} ${IMAGE}" - fi + image_string="${image_string} ${image_directory}/${IMAGE}" done - done - - if [ -n "${addimage_directory}" ] && [ -d "${addimage_directory}" ] + elif [ -e "${image_directory}/${MODULE}.module" ] then - for FILESYSTEM in squashfs ext2 ext3 xfs jffs2 dir + for IMAGE in $(cat ${image_directory}/${MODULE}.module) + do + image_string="${image_string} ${image_directory}/${IMAGE}" + done + else + # ${MODULE}.module does not exist, create a list of images + for FILESYSTEM in squashfs ext2 ext3 ext4 xfs jffs2 dir do - for IMAGE in "${addimage_directory}"/*."${FILESYSTEM}" + for IMAGE in "${image_directory}"/*."${FILESYSTEM}" do if [ -e "${IMAGE}" ] then @@ -1067,52 +1127,80 @@ setup_unionfs () fi done done - fi - # Now sort the list - image_string="$(echo ${image_string} | sed -e 's/ /\n/g' | sort )" - fi + if [ -n "${addimage_directory}" ] && [ -d "${addimage_directory}" ] + then + for FILESYSTEM in squashfs ext2 ext3 ext4 xfs jffs2 dir + do + for IMAGE in "${addimage_directory}"/*."${FILESYSTEM}" + do + if [ -e "${IMAGE}" ] + then + image_string="${image_string} ${IMAGE}" + fi + done + done + fi + + # Now sort the list + image_string="$(echo ${image_string} | sed -e 's/ /\n/g' | sort )" + fi [ -n "${MODULETORAMFILE}" ] && image_string="${image_directory}/$(basename ${MODULETORAMFILE})" - mkdir -p "${croot}" + mkdir -p "${croot}" - for image in ${image_string} - do - imagename=$(basename "${image}") + for image in ${image_string} + do + imagename=$(basename "${image}") - if [ -d "${image}" ] - then - # it is a plain directory: do nothing - rofsstring="${image}=${roopt}:${rofsstring}" - rofslist="${image} ${rofslist}" - elif [ -f "${image}" ] - then - if losetup --help 2>&1 | grep -q -- "-r\b" - then - backdev=$(get_backing_device "${image}" "-r") - else - backdev=$(get_backing_device "${image}") - fi - fstype=$(get_fstype "${backdev}") + export image devname + maybe_break live-realpremount + log_begin_msg "Running /scripts/live-realpremount" + run_scripts /scripts/live-realpremount + log_end_msg - if [ "${fstype}" = "unknown" ] + if [ -d "${image}" ] then - panic "Unknown file system type on ${backdev} (${image})" - fi - - if [ -z "${fstype}" ] + # it is a plain directory: do nothing + rofsstring="${image}=${roopt}:${rofsstring}" + rofslist="${image} ${rofslist}" + elif [ -f "${image}" ] then - fstype="${imagename##*.}" - log_warning_msg "Unknown file system type on ${backdev} (${image}), assuming ${fstype}." - fi + if losetup --help 2>&1 | grep -q -- "-r\b" + then + backdev=$(get_backing_device "${image}" "-r") + else + backdev=$(get_backing_device "${image}") + fi + fstype=$(get_fstype "${backdev}") - mkdir -p "${croot}/${imagename}" - log_begin_msg "Mounting \"${image}\" on \"${croot}${imagename}\" via \"${backdev}\"" - mount -t "${fstype}" -o ro,noatime "${backdev}" "${croot}/${imagename}" || panic "Can not mount ${backdev} (${image}) on ${croot}/${imagename}" && rofsstring="${croot}/${imagename}=${roopt}:${rofsstring}" && rofslist="${croot}/${imagename} ${rofslist}" - log_end_msg - fi - done + if [ "${fstype}" = "unknown" ] + then + panic "Unknown file system type on ${backdev} (${image})" + fi + + if [ -z "${fstype}" ] + then + fstype="${imagename##*.}" + log_warning_msg "Unknown file system type on ${backdev} (${image}), assuming ${fstype}." + fi + + mkdir -p "${croot}/${imagename}" + log_begin_msg "Mounting \"${image}\" on \"${croot}${imagename}\" via \"${backdev}\"" + mount -t "${fstype}" -o ro,noatime "${backdev}" "${croot}/${imagename}" || panic "Can not mount ${backdev} (${image}) on ${croot}/${imagename}" && rofsstring="${croot}/${imagename}=${roopt}:${rofsstring}" && rofslist="${croot}/${imagename} ${rofslist}" + log_end_msg + fi + done + else + # we have a plain root system + mkdir -p "${croot}/filesystem" + log_begin_msg "Mounting \"${image_directory}\" on \"${croot}/filesystem\"" + mount -t $(get_fstype "${image_directory}") -o ro,noatime "${image_directory}" "${croot}/filesystem" || panic "Can not mount ${image_directory} on ${croot}/filesystem" && rofsstring="${croot}/filesystem=${roopt}:${rofsstring}" && rofslist="${croot}/filesystem ${rofslist}" + # probably broken: + mount -o bind ${croot}/filesystem $mountpoint + log_end_msg + fi rofsstring=${rofsstring%:} @@ -1121,37 +1209,32 @@ setup_unionfs () # Looking for "${root_persistence}" device or file if [ -n "${PERSISTENT}" ] && [ -z "${NOPERSISTENT}" ] then - # Load USB modules - num_block=$(ls -l /sys/block | wc -l) - for module in sd_mod uhci-hcd ehci-hcd ohci-hcd usb-storage - do - modprobe -q -b ${module} - done - - if [ -x /sbin/udevadm ] + if [ -z "${QUICKUSBMODULES}" ] then - # lenny + # Load USB modules + num_block=$(ls -l /sys/block | wc -l) + for module in sd_mod uhci-hcd ehci-hcd ohci-hcd usb-storage + do + modprobe -q -b ${module} + done + udevadm trigger udevadm settle - else - # etch - udevtrigger - udevsettle - fi - # For some reason, udevsettle does not block in this scenario, - # so we sleep for a little while. - # - # See https://bugs.launchpad.net/ubuntu/+source/casper/+bug/84591 - for timeout in 5 4 3 2 1 - do - sleep 1 + # For some reason, udevsettle does not block in this scenario, + # so we sleep for a little while. + # + # See https://bugs.launchpad.net/ubuntu/+source/casper/+bug/84591 + for timeout in 5 4 3 2 1 + do + sleep 1 - if [ $(ls -l /sys/block | wc -l) -gt ${num_block} ] - then - break - fi - done + if [ $(ls -l /sys/block | wc -l) -gt ${num_block} ] + then + break + fi + done + fi # search for label and files (this could be hugely optimized) cowprobe=$(find_cow_device "${root_persistence}") @@ -1175,7 +1258,7 @@ setup_unionfs () root_snapdata=$(find_snap "${root_snapshot_label}" "${blacklistdev}") # This second type should be removed when snapshot will get smarter, # hence when "/etc/live-snapshot*list" will be supported also by - # ext2|ext3|jffs2 snapshot types. + # ext2|ext3|ext4|jffs2 snapshot types. home_snapdata=$(find_snap "${home_snapshot_label}" "${blacklistdev}") if [ -b "${cowprobe}" ] @@ -1183,6 +1266,11 @@ setup_unionfs () cowdevice=${cowprobe} cow_fstype=$(get_fstype "${cowprobe}") cow_mountopt="rw,noatime" + + if [ "${FORCEPERSISTENTFSCK}" = "Yes" ] + then + fsck -y ${cowdevice} + fi else log_warning_msg "Unable to find the persistent medium" cowdevice="tmpfs" @@ -1238,23 +1326,45 @@ setup_unionfs () mount --bind ${exposedrootfs} ${rootmnt} || \ panic "bind mount of ${exposedrootfs} failed" - cow_dirs='/var/tmp /var/lock /var/run /var/log /var/spool - /home /var/lib/live' + if [ -z "${SKIP_UNION_MOUNTS}" ] + then + cow_dirs='/var/tmp /var/lock /var/run /var/log /var/spool /home /var/lib/live' + else + cow_dirs='' + fi for dir in ${cow_dirs}; do mkdir -p /cow${dir} - mount -t ${UNIONTYPE} \ - -o rw,noatime,dirs=/cow${dir}=rw:${exposedrootfs}${dir}=ro \ - ${UNIONTYPE} "${rootmnt}${dir}" || \ - panic "mount ${UNIONTYPE} on ${rootmnt}${dir} failed with option \ - rw,noatime,dirs=/cow${dir}=rw:${exposedrootfs}${dir}=ro" + + 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 + ;; + + *) + mount -t ${UNIONTYPE} -o rw,noatime,dirs=/cow${dir}=rw:${exposedrootfs}${dir}=ro ${UNIONTYPE} "${rootmnt}${dir}" || panic "mount ${UNIONTYPE} on ${rootmnt}${dir} failed with option rw,noatime,dirs=/cow${dir}=rw:${exposedrootfs}${dir}=ro" + ;; + esac done else - mount -t ${UNIONTYPE} -o noatime,dirs=/cow=rw:${rofsstring} \ - ${UNIONTYPE} "${rootmnt}" || panic "mount ${UNIONTYPE} on \ - ${rootmnt} failed with option noatime,dirs=/cow=rw:${rofsstring}" + 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 + ;; + + *) + mount -t ${UNIONTYPE} -o noatime,${noxino_opt}dirs=/cow=rw:${rofsstring} ${UNIONTYPE} "${rootmnt}" || panic "mount ${UNIONTYPE} on ${rootmnt} failed with option noatime,${noxino_opt}dirs=/cow=rw:${rofsstring}" + ;; + esac fi + # Correct the permissions of /: + chmod 0755 "${rootmnt}" + # tmpfs file systems touch /etc/fstab mkdir -p "${rootmnt}/live" @@ -1292,7 +1402,15 @@ setup_unionfs () ;; *) - mount -o move "${d}" "${rootmnt}/live/${d##*/}" + case "${UNIONTYPE}" in + unionfs-fuse) + mount -o bind "${d}" "${rootmnt}/live/${d##*/}" + ;; + + *) + mount -o move "${d}" "${rootmnt}/live/${d##*/}" + ;; + esac ;; esac done @@ -1309,6 +1427,36 @@ check_dev () devname="${2}" skip_uuid_check="${3}" + # support for fromiso=.../isofrom=.... + if [ -n "$FROMISO" ] + then + 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}" ] then devname=$(sys2dev "${sysdev}") @@ -1326,6 +1474,7 @@ check_dev () umount $mountpoint fi fi + [ -e "$devname" ] || continue if [ -n "${LIVE_MEDIA_OFFSET}" ] then @@ -1337,7 +1486,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}) @@ -1361,15 +1513,6 @@ find_livefs () { timeout="${1}" - # first look at the one specified in the command line - if [ ! -z "${LIVE_MEDIA}" ] - then - if check_dev "null" "${LIVE_MEDIA}" "skip_uuid_check" - then - return 0 - fi - fi - # don't start autodetection before timeout has expired if [ -n "${LIVE_MEDIA_TIMEOUT}" ] then @@ -1379,10 +1522,74 @@ find_livefs () fi fi + # first look at the one specified in the command line + case "${LIVE_MEDIA}" in + removable-usb) + for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -vE "/(loop|ram|dm-|fd)") + do + if [ "$(cat ${sysblock}/removable)" = "1" ] + then + if readlink ${sysblock} | grep -q usb || + readlink ${sysblock}/device | grep -q usb # linux < 2.6.29 + then + for dev in $(subdevices "${sysblock}") + do + if check_dev "${dev}" + then + return 0 + fi + done + fi + fi + done + return 1 + ;; + + removable) + for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -vE "/(loop|ram|dm-|fd)") + do + if [ "$(cat ${sysblock}/removable)" = "1" ] + then + for dev in $(subdevices "${sysblock}") + do + if check_dev "${dev}" + then + return 0 + fi + done + fi + done + return 1 + ;; + + *) + if [ ! -z "${LIVE_MEDIA}" ] + then + if check_dev "null" "${LIVE_MEDIA}" "skip_uuid_check" + then + return 0 + fi + fi + ;; + 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 @@ -1401,13 +1608,15 @@ find_livefs () fi done elif [ "${fstype}" = "squashfs" -o \ + "${fstype}" = "btrfs" -o \ "${fstype}" = "ext2" -o \ "${fstype}" = "ext3" -o \ + "${fstype}" = "ext4" -o \ "${fstype}" = "jffs2" ] then # This is an ugly hack situation, the block device has # an image directly on it. It's hopefully - # live-initramfs, so take it and run with it. + # live-boot, so take it and run with it. ln -s "${devname}" "${devname}.${fstype}" echo "${devname}.${fstype}" return 0 @@ -1427,6 +1636,40 @@ set_usplash_timeout () fi ; fi } +integrity_check () +{ + media_mountpoint="${1}" + + log_begin_msg "Checking media integrity" + + cd ${media_mountpoint} + /bin/md5sum -c md5sum.txt < /dev/tty8 > /dev/tty8 + RC="${?}" + + log_end_msg + + if [ "${RC}" -eq 0 ] + then + log_success_msg "Everything ok, will reboot in 10 seconds." + sleep 10 + cd / + umount ${media_mountpoint} + sync + echo u > /proc/sysrq-trigger + echo b > /proc/sysrq-trigger + else + panic "Not ok, a media defect is likely, switch to VT8 for details." + fi +} + +start_usplash_pulse () +{ + if [ -x /sbin/usplash_write ] + then + /sbin/usplash_write "PULSELOGO" + fi +} + mountroot () { if [ -x /scripts/local-top/cryptroot ]; then @@ -1446,6 +1689,7 @@ mountroot () Arguments set_usplash_timeout + start_usplash_pulse maybe_break live-premount log_begin_msg "Running /scripts/live-premount" @@ -1466,11 +1710,28 @@ mountroot () panic "Unable to find a live file system on the network" fi else - if [ -n "${PLAIN_ROOT}" ] && [ -n "${ROOT}" ] + if [ -n "${ISCSI_PORTAL}" ] + then + do_iscsi && livefs_root="${mountpoint}" + elif [ -n "${PLAIN_ROOT}" ] && [ -n "${ROOT}" ] then # Do a local boot from hd livefs_root=${ROOT} else + if [ -x /usr/bin/memdiskfind ] + then + MEMDISK=$(/usr/bin/memdiskfind) + + if [ $? -eq 0 ] + then + # We found a memdisk, set up phram + modprobe phram phram=memdisk,${MEMDISK} + + # Load mtdblock, the memdisk will be /dev/mtdblock0 + modprobe mtdblock + fi + fi + # Scan local devices for the image i=0 while [ "$i" -lt 60 ] @@ -1493,6 +1754,11 @@ mountroot () panic "Unable to find a medium containing a live file system" fi + if [ "${INTEGRITY_CHECK}" ] + then + integrity_check "${livefs_root}" + fi + if [ "${TORAM}" ] then live_dest="ram" @@ -1508,7 +1774,16 @@ mountroot () log_end_msg fi - if [ -n "${MODULETORAMFILE}" ] + # if we do not unmount the ISO we can't run "fsck /dev/ice" later on + # because the mountpoint is left behind in /proc/mounts, so let's get + # rid of it when running from RAM + if [ -n "$FROMISO" ] && [ "${TORAM}" ] + then + losetup -d /dev/loop0 + grep -q /isofrom /proc/mounts && umount /isofrom + fi + + if [ -n "${MODULETORAMFILE}" ] || [ -n "${PLAIN_ROOT}" ] then setup_unionfs "${livefs_root}" "${rootmnt}" else @@ -1517,16 +1792,40 @@ mountroot () mount_images_in_directory "${livefs_root}" "${rootmnt}" "${mac}" fi + + if [ -n "${ROOT_PID}" ] ; then + echo "${ROOT_PID}" > "${rootmnt}"/live/root.pid + fi + log_end_msg + # unionfs-fuse needs /dev to be bind-mounted for the duration of + # live-bottom; udev's init script will take care of things after that + if [ "${UNIONTYPE}" = unionfs-fuse ] + then + mount -n -o bind /dev "${rootmnt}/dev" + fi + + # Move to the new root filesystem so that programs there can get at it. + if [ ! -d /root/live/image ] + then + mkdir -p /root/live/image + mount --move /live/image /root/live/image + fi + maybe_break live-bottom - log_begin_msg "Running /scripts/live-bottom" + log_begin_msg "Running /scripts/live-bottom\n" run_scripts /scripts/live-bottom log_end_msg + if [ "${UNIONFS}" = unionfs-fuse ] + then + umount "${rootmnt}/dev" + fi + exec 1>&6 6>&- exec 2>&7 7>&- kill ${tailpid} - cp live.log "${rootmnt}/var/log/" + [ -w "${rootmnt}/var/log/" ] && cp live.log "${rootmnt}/var/log/" 2>/dev/null }