Patch by Steven Shiau <steven@nchc.org.tw>. The only changes so far are:
[live-boot-grml.git] / components / 9990-misc-helpers.sh
index 9312381..315e3b1 100755 (executable)
@@ -2,17 +2,12 @@
 
 #set -e
 
-file_pattern_matches()
-{
-       [ -e "$1" ]
-}
-
 is_live_path()
 {
        DIRECTORY="${1}/${LIVE_MEDIA_PATH}"
        for FILESYSTEM in squashfs ext2 ext3 ext4 xfs dir jffs
        do
-               if file_pattern_matches "${DIRECTORY}/"*.${FILESYSTEM}
+               if ls "${DIRECTORY}/"*.${FILESYSTEM} > /dev/null 2>&1
                then
                        return 0
                fi
@@ -81,7 +76,7 @@ is_nice_device ()
 {
        sysfs_path="${1#/sys}"
 
-       if udevadm test-builtin 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)"
+       if udevadm info --query=all --path="${sysfs_path}" | egrep -q "DEVTYPE=disk"
        then
                return 0
        elif echo "${sysfs_path}" | grep -q '^/block/vd[a-z]$'
@@ -166,7 +161,7 @@ check_dev ()
                                # Adding lvm support
                                if [ -x /scripts/local-top/lvm2 ]
                                then
-                                       ROOT="$device" resume="" /scripts/local-top/lvm2
+                                       ROOT="$device" resume="" /scripts/local-top/lvm2 >>/boot.log
                                fi
                                ;;
 
@@ -174,10 +169,10 @@ check_dev ()
                                # Adding raid support
                                if [ -x /scripts/local-top/mdadm ]
                                then
-                                       cp /conf/conf.d/md /conf/conf.d/md.orig
+                                       [ -r /conf/conf.d/md ] && cp /conf/conf.d/md /conf/conf.d/md.orig
                                        echo "MD_DEVS=$device " >> /conf/conf.d/md
-                                       /scripts/local-top/mdadm
-                                       mv /conf/conf.d/md.orig /conf/conf.d/md
+                                       /scripts/local-top/mdadm >>/boot.log
+                                       [ -r /conf/conf.d/md.orig ] && mv /conf/conf.d/md.orig /conf/conf.d/md
                                fi
                                ;;
                esac
@@ -199,9 +194,9 @@ check_dev ()
        if is_supported_fs ${fstype}
        then
                devuid=$(blkid -o value -s UUID "$devname")
-               [ -n "$devuid" ] && grep -qs "\<$devuid\>" $tried && continue
+               [ -n "$devuid" ] && grep -qs "\<$devuid\>" /var/lib/live/boot/devices-already-tried-to-mount && continue
                mount -t ${fstype} -o ro,noatime "${devname}" ${mountpoint} || continue
-               [ -n "$devuid" ] && echo "$devuid" >> $tried
+               [ -n "$devuid" ] && echo "$devuid" >> /var/lib/live/boot/devices-already-tried-to-mount
 
                if [ -n "${FINDISO}" ]
                then
@@ -334,21 +329,6 @@ find_livefs ()
        return 1
 }
 
-really_export ()
-{
-       STRING="${1}"
-       VALUE="$(eval echo -n \${$STRING})"
-
-       if [ -f /live.vars ] && grep -sq "export ${STRING}" /live.vars
-       then
-               sed -i -e 's/\('${STRING}'=\).*$/\1'${VALUE}'/' /live.vars
-       else
-               echo "export ${STRING}=\"${VALUE}\"" >> /live.vars
-       fi
-
-       eval export "${STRING}"="${VALUE}"
-}
-
 is_in_list_separator_helper ()
 {
        local sep element list
@@ -446,7 +426,7 @@ is_supported_fs ()
                return 0
        else
                # Then try to add support for it the gentle way using the initramfs capabilities
-               modprobe ${fstype}
+               modprobe -q -b ${fstype}
                if grep -q ${fstype} /proc/filesystems
                then
                        return 0
@@ -704,8 +684,9 @@ try_mount ()
 }
 
 # Try to mount $device to the place expected by live-boot. If $device
-# is already mounted somewhere, move it to the expected place. If
-# we're only probing $device (to check if it has custom persistence)
+# is already mounted somewhere, move it to the expected place. If $device
+# ends with a "/" this is a directory path.
+# If we're only probing $device (to check if it has custom persistence)
 # $probe should be set, which suppresses warnings upon failure. On
 # success, print the mount point for $device.
 mount_persistence_media ()
@@ -714,6 +695,20 @@ mount_persistence_media ()
        device=${1}
        probe=${2}
 
+       # get_custom_mounts() might call this with a directory path instead
+       # of a block device path. This means we have found sub-directory path
+       # underneath /lib/live/mounts/persistence, so we're done
+       if [ -d "${device}" ]
+       then
+               echo "${device}"
+               return 0
+       fi
+
+       if [ ! -b "${device}" ]
+       then
+               return 1
+       fi
+
        backing="/live/persistence/$(basename ${device})"
 
        mkdir -p "${backing}"
@@ -737,15 +732,24 @@ mount_persistence_media ()
                fi
        elif [ "${backing}" != "${old_backing}" ]
        then
-               if mount --move ${old_backing} ${backing} >/dev/null
+               if mount --move ${old_backing} ${backing} >/dev/null
                then
-                       echo ${backing}
-                       return 0
-               else
                        [ -z "${probe}" ] && log_warning_msg "Failed to move persistence media ${device}"
                        rmdir "${backing}"
                        return 1
                fi
+               mount_opts="rw,noatime"
+               if [ -n "${PERSISTENCE_READONLY}" ]
+               then
+                       mount_opts="ro,noatime"
+               fi
+               if ! mount -o "remount,${mount_opts}" "${backing}" >/dev/null
+               then
+                       log_warning_msg "Failed to remount persistence media ${device} writable"
+                       # Don't unmount or rmdir the new mountpoint in this case
+               fi
+               echo ${backing}
+               return 0
        else
                # This means that $device has already been mounted on
                # the place expected by live-boot, so we're done.
@@ -799,9 +803,30 @@ open_luks_device ()
 
        load_keymap
 
+       # check for plymouth
+       if [ -x /bin/plymouth ]
+       then
+               _PLYMOUTH="true"
+       fi
+
+       case "${_PLYMOUTH}" in
+               true)
+                       plymouth --ping
+
+                       cryptkeyscript="plymouth ask-for-password --prompt"
+                       # Plymouth will add a : if it is a non-graphical prompt
+                       cryptkeyprompt="Please unlock disk ${dev}"
+                       ;;
+
+               *)
+                       cryptkeyscript="/lib/cryptsetup/askpass"
+                       cryptkeyprompt="Please unlock disk ${dev}: "
+                       ;;
+       esac
+
        while true
        do
-               /lib/cryptsetup/askpass "Enter passphrase for ${dev}: " | \
+               $cryptkeyscript "$cryptkeyprompt" | \
                        /sbin/cryptsetup -T 1 luksOpen ${dev} ${name} ${opts}
 
                if [ 0 -eq ${?} ]
@@ -812,11 +837,28 @@ open_luks_device ()
                fi
 
                echo >&6
-               echo -n "There was an error decrypting ${dev} ... Retry? [Y/n] " >&6
-               read answer
+               retryprompt="There was an error decrypting ${dev} ... Retry? [Y/n]"
+
+               case "${_PLYMOUTH}" in
+                       true)
+                               plymouth display-message --text "${retryprompt}"
+                               answer=$(plymouth watch-keystroke --keys="YNyn")
+                               ;;
+
+                       *)
+                               echo -n "${retryprompt} " >&6
+                               read answer
+                               ;;
+               esac
 
                if [ "$(echo "${answer}" | cut -b1 | tr A-Z a-z)" = "n" ]
                then
+                       case "${_PLYMOUTH}" in
+                               true)
+                                       plymouth display-message --text ""
+                                       ;;
+                       esac
+
                        return 2
                fi
        done
@@ -895,7 +937,7 @@ probe_for_file_name ()
 
        for label in ${overlays}
        do
-               path=${backing}/${PERSISTENCE_PATH}${label}
+               path=${backing}/${PERSISTENCE_PATH}/${label}
                if [ -f "${path}" ]
                then
                        local loopdev
@@ -914,6 +956,39 @@ probe_for_file_name ()
        fi
 }
 
+probe_for_directory_name ()
+{
+       local overlays dev ret backing
+       overlays="${1}"
+       dev="${2}"
+
+       ret=""
+       backing="$(mount_persistence_media ${dev} probe)"
+       if [ -z "${backing}" ]
+       then
+           return
+       fi
+
+       for label in ${overlays}
+       do
+               path=${backing}/${PERSISTENCE_PATH}/${label}
+               if [ -d "${path}" ]
+               then
+                       # in this case the "device" ends with a "/"
+                       ret="${ret} ${label}=${backing}/${PERSISTENCE_PATH}/${label%%/}/"
+               fi
+       done
+
+       if [ -n "${ret}" ]
+       then
+               echo ${ret}
+       else
+               # unmount and remove mountpoint
+               umount ${backing} > /dev/null 2>&1 || true
+               rmdir ${backing} > /dev/null 2>&1 || true
+       fi
+}
+
 find_persistence_media ()
 {
        # Scans devices for overlays, and returns a whitespace
@@ -938,7 +1013,17 @@ find_persistence_media ()
        white_listed_devices="${2}"
        ret=""
 
-       black_listed_devices="$(what_is_mounted_on /live/medium) $(what_is_mounted_on /live/findiso) $(what_is_mounted_on /live/fromiso)"
+       #
+       # The devices that are hosting the actual live rootfs should not be
+       # used for persistence storage since otherwise you might mount a
+       # parent directory on top of a sub-directory of the same filesystem
+       # in one union together.
+       #
+       black_listed_devices=""
+       for d in /live/rootfs/* /live/findiso /live/fromiso
+       do
+               black_listed_devices="${black_listed_devices} $(what_is_mounted_on d)"
+       done
 
        for dev in $(storage_devices "${black_listed_devices}" "${white_listed_devices}")
        do
@@ -1009,6 +1094,17 @@ find_persistence_media ()
                        fi
                fi
 
+               # Probe for directory with matching name on mounted partition
+               if is_in_comma_sep_list directory ${PERSISTENCE_STORAGE}
+               then
+                       result=$(probe_for_directory_name "${overlays}" ${dev})
+                       if [ -n "${result}" ]
+                       then
+                               ret="${ret} ${result}"
+                               continue
+                       fi
+               fi
+
                # Close luks device if it isn't used
                if [ -z "${result}" ] && [ -n "${luks_device}" ] && is_active_luks_mapping "${luks_device}"
                then
@@ -1196,23 +1292,8 @@ do_union ()
                        rw_opt="rw"
                        ro_opt="rr+wh"
                        noxino_opt="noxino"
-                       ;;
 
-               unionfs-fuse)
-                       rw_opt="RW"
-                       ro_opt="RO"
-                       ;;
-
-               *)
-                       rw_opt="rw"
-                       ro_opt="ro"
-                       ;;
-       esac
-
-       case "${UNIONTYPE}" in
-               unionfs-fuse)
-                       unionmountopts="-o cow -o noinitgroups -o default_permissions -o allow_other -o use_ino -o suid"
-                       unionmountopts="${unionmountopts} ${unionrw}=${rw_opt}"
+                       unionmountopts="-o noatime,${noxino_opt},dirs=${unionrw}=${rw_opt}"
                        if [ -n "${unionro}" ]
                        then
                                for rofs in ${unionro}
@@ -1220,36 +1301,36 @@ do_union ()
                                        unionmountopts="${unionmountopts}:${rofs}=${ro_opt}"
                                done
                        fi
-                       ( sysctl -w fs.file-max=391524 ; ulimit -HSn 16384
-                       unionfs-fuse ${unionmountopts} "${unionmountpoint}" ) && \
-                       ( mkdir -p /run/sendsigs.omit.d
-                       pidof unionfs-fuse >> /run/sendsigs.omit.d/unionfs-fuse || true )
+                       mount -t ${UNIONTYPE} ${unionmountopts} ${UNIONTYPE} "${unionmountpoint}"
                        ;;
 
-               overlayfs)
-                       # XXX: can multiple unionro be used? (overlayfs only handles two dirs, but perhaps they can be chained?)
-                       # XXX: and can unionro be optional? i.e. can overlayfs skip lowerdir?
+               overlay)
+                       rw_opt="rw"
+                       ro_opt="ro"
+
+                       # XXX: can multiple unionro be used? (overlay only handles two dirs, but perhaps they can be chained?)
+                       # XXX: and can unionro be optional? i.e. can overlay skip lowerdir?
                        if echo ${unionro} | grep -q " "
                        then
-                               panic "Multiple lower filesystems are currently not supported with overlayfs (unionro = ${unionro})."
+                               panic "Multiple lower filesystems are currently not supported with overlay (unionro = ${unionro})."
                        elif [ -z "${unionro}"  ]
                        then
-                               panic "Overlayfs needs at least one lower filesystem (read-only branch)."
+                               panic "overlay needs at least one lower filesystem (read-only branch)."
                        fi
                        unionmountopts="-o noatime,lowerdir=${unionro},upperdir=${unionrw}"
-                       mount -t ${UNIONTYPE} ${unionmountopts} ${UNIONTYPE} "${unionmountpoint}"
-                       ;;
-
-               *)
-                       unionmountopts="-o noatime,${noxino_opt},dirs=${unionrw}=${rw_opt}"
-                       if [ -n "${unionro}" ]
+                       if ! mount -t ${UNIONTYPE} ${unionmountopts} ${UNIONTYPE} "${unionmountpoint}" 2>/dev/null
                        then
-                               for rofs in ${unionro}
-                               do
-                                       unionmountopts="${unionmountopts}:${rofs}=${ro_opt}"
-                               done
+                               # Ref: kiwi from OpenSuse kiwi-7.02.18-1.1
+                               # overlayfs in version >= v22 behaves differently
+                               # + renamed from overlayfs to overlay
+                               # + requires a workdir to become mounted
+                               # + requires workdir and upperdir to reside under the same mount
+                               # + requires workdir and upperdir to be in separate subdirs
+                               mkdir ${unionrw}/rw
+                               mkdir ${unionrw}/work
+                               unionmountopts="-o noatime,lowerdir=${unionro},upperdir=${unionrw}/rw,workdir=${unionrw}/work"
+                               mount -t ${UNIONTYPE} ${unionmountopts} ${UNIONTYPE} "${unionmountpoint}"
                        fi
-                       mount -t ${UNIONTYPE} ${unionmountopts} ${UNIONTYPE} "${unionmountpoint}"
                        ;;
        esac
 }
@@ -1270,11 +1351,6 @@ get_custom_mounts ()
 
        for device in ${devices}
        do
-               if [ ! -b "${device}" ]
-               then
-                       continue
-               fi
-
                local device_name backing include_list
                device_name="$(basename ${device})"
                backing=$(mount_persistence_media ${device})
@@ -1324,7 +1400,7 @@ get_custom_mounts ()
                                        union|bind)
                                                ;;
                                        *)
-                                               log_warning_msg "Skipping custom mount with unkown option: ${opt}"
+                                               log_warning_msg "Skipping custom mount with unknown option: ${opt}"
                                                continue 2
                                                ;;
                                esac
@@ -1369,7 +1445,7 @@ get_custom_mounts ()
        prev_dest=""
        # This sort will ensure that a source /a comes right before a source
        # /a/b so we only need to look at the previous source
-       sort -k2 -b ${custom_mounts} |
+       [ -e ${custom_mounts} ] && sort -k2 -b ${custom_mounts} |
        while read device source dest options
        do
                if echo ${source} | grep -qe "^${prev_source}\(/.*\)\?$"