Refactoring overlay and snapshot scanning code.
authorTails developers <amnesia@boum.org>
Thu, 10 Nov 2011 17:52:18 +0000 (18:52 +0100)
committerDaniel Baumann <daniel@debian.org>
Thu, 24 Nov 2011 08:42:08 +0000 (09:42 +0100)
Both overlays and snapshots are now scanned at the same time, and each
device is only mounted once. Passphrases for LUKS volumes are only
asked for once, and unused ones are closed. Also, snapshot files on
encrypted partitions are now supported.

scripts/live
scripts/live-helpers

index c3732fe..e0663b6 100755 (executable)
@@ -1059,26 +1059,6 @@ do_snap_copy ()
        fi
 }
 
-find_snap ()
-{
-       # Look for ${snap_label}.* in block devices
-       snap_label="${1}"
-       black_listed_devices="${2}"
-       white_listed_devices="${3}"
-
-       if echo ${PERSISTENT_STORAGE} | grep -qw file
-       then
-               # search for image files
-               snapdata=$(find_files "${PERSISTENT_PATH}${snap_label}.squashfs ${PERSISTENT_PATH}${snap_label}.cpio.gz ${PERSISTENT_PATH}${snap_label}.ext2 ${PERSISTENT_PATH}${snap_label}.ext3 ${PERSISTENT_PATH}${snap_label}.ext4 ${PERSISTENT_PATH}${snap_label}.jffs2" "${black_listed_devices}" "${white_listed_devices}")
-       fi
-
-       if echo ${PERSISTENT_STORAGE} | grep -qw filesystem && [ -z "${snapdata}" ]
-       then
-               snapdata=$(find_cow_device "${snap_label}" "${black_listed_devices}" "${white_listed_devices}")
-       fi
-       echo "${snapdata}"
-}
-
 try_snap ()
 {
        # copy the contents of previously found snapshot to ${snap_mount}
@@ -1397,34 +1377,43 @@ setup_unionfs ()
 
                if echo ${PERSISTENT_METHOD} | grep -qw overlay
                then
-                       # search for label and files (this could be hugely optimized)
-                       cowprobe=$(find_cow_device "${root_persistence}" "${blacklistdev}" "${whitelistdev}")
-                       if [ -b "${cowprobe}" ]
-                       then
-                               # Blacklist /cow device, to avoid inconsistent setups for overlapping snapshots
-                               # makes sense to have both persistence for /cow and /home mounted, maybe also with
-                               # snapshots to be sure to really store some e.g key config files,
-                               # but not on the same media
-                               blacklistdev="${cowprobe}"
-                               PERSISTENCE_IS_ON="1"
-                               export PERSISTENCE_IS_ON
-                       fi
-                       # homecow just mount something on /home, this should be generalized some way
-                       homecow=$(find_cow_device "${home_persistence}" "${blacklistdev}" "${whitelistdev}")
-                       if [ -b "${homecow}" ]
-                       then
-                               PERSISTENCE_IS_ON="1"
-                               export PERSISTENCE_IS_ON
-                       fi
+                       overlays="${root_persistence} ${home_persistence}"
                fi
 
                if echo ${PERSISTENT_METHOD} | grep -qw snapshot
                then
-                       root_snapdata=$(find_snap "${root_snapshot_label}" "${blacklistdev}" "${whitelistdev}")
-                       # This second type should be removed when snapshot will get smarter,
-                       # hence when "/etc/live-snapshot*list" will be supported also by
-                       # ext2|ext3|ext4|jffs2 snapshot types.
-                       home_snapdata=$(find_snap "${home_snapshot_label}" "${blacklistdev}" "${whitelistdev}")
+                       snapshots="${root_snapshot_label} ${home_snapshot_label}"
+               fi
+
+
+               for media in $(find_persistent_media "${overlays}" "${snapshots}" "${blacklistdev}" "${whitelistdev}")
+               do
+                       media="$(echo ${media} | tr ":" " ")"
+                       case ${media} in
+                               ${root_persistence}=*)
+                                       cowprobe="${media#*=}"
+                                       ;;
+                               ${home_persistence}=*)
+                                       homecow="${media#*=}"
+                                       ;;
+                               ${root_snapshot_label}=*)
+                                       root_snapdata="${media#*=}"
+                                       ;;
+                               ${home_snapshot_label}=*)
+                                       # This second type should be removed when snapshot will get smarter,
+                                       # hence when "/etc/live-snapshot*list" will be supported also by
+                                       # ext2|ext3|ext4|jffs2 snapshot types.
+                                       home_snapdata="${media#*=}"
+                                       ;;
+                               *)
+                                       ;;
+                        esac
+               done
+
+               if [ -b "${cowprobe}" ] || [ -b "${homecow}" ]
+               then
+                       PERSISTENCE_IS_ON="1"
+                       export PERSISTENCE_IS_ON
                fi
 
                if [ -b "${cowprobe}" ]
@@ -1438,7 +1427,6 @@ setup_unionfs ()
                                fsck -y ${cowdevice}
                        fi
                else
-                       log_warning_msg "Unable to find the persistent medium"
                        cowdevice="tmpfs"
                        cow_fstype="tmpfs"
                        cow_mountopt="rw,noatime,mode=755"
index a9c4fbe..b812979 100644 (file)
@@ -311,27 +311,38 @@ try_mount ()
        fi
 }
 
-find_cow_device ()
+find_persistent_media ()
 {
-       # Returns a device containing a partition labeled "${pers_label}" or containing a file named the same way
-       #  in the latter case the partition containing the file is left mounted
-       #  if is not in black_listed_devices.
-       #  Additionally, if the white_listed_devices list is non-empty, the
-       #  parent block device of the returned device must be part of this list.
-       pers_label="${1}"
-       cow_backing="/${pers_label}-backing"
-       black_listed_devices="${2}"
-       white_listed_devices="${3}"
-
-       if [ -z "${PERSISTENT_PATH}" ]
-       then
-               pers_fpath=${cow_backing}/${pers_label}
-       else
-               pers_fpath=${cow_backing}/${PERSISTENT_PATH}/${pers_label}
-       fi
+       # Scans devices for overlays and snapshots, and returns a whitespace
+       # separated list of how to use them. Only overlays with a partition
+       # label or file name in ${overlays} are returned, and ditto for
+       # snapshots with labels in ${snapshots}.
+       #
+       # When scanning a LUKS device, the user will be asked to enter the
+       # passphrase; on failure to enter it, or if no persistent partitions
+       # or files were found, the LUKS device is closed.
+       #
+       # For a snapshot file the return value is ${label}=${snapdata}", where
+       # ${snapdata} is the parameter used for try_snap().
+       #
+       # For all other cases (overlay/snapshot partition and overlay file) the
+       # return value is "${label}=${device}", where ${device} a device that
+       # can mount the content. In the case of an overlay file, the device
+       # containing the file will remain mounted as a side-effect.
+       #
+       # No devices in ${black_listed_devices} will be scanned, and if
+       # ${white_list_devices} is non-empty, only devices in it will be
+       # scanned.
+
+       overlays="${1}"
+       snapshots="${2}"
+       black_listed_devices="${3}"
+       white_listed_devices="${4}"
 
        for dev in $(storage_devices "${black_listed_devices}" "${white_listed_devices}")
        do
+               luks_device=""
+
                # Checking for a luks device
                if [ "${PERSISTENT_ENCRYPTION}" = "luks" ] && [ -e /sbin/cryptsetup ]
                then
@@ -341,24 +352,28 @@ find_cow_device ()
                                continue
                        fi
 
+                       if [ ! -x /lib/cryptsetup/askpass ] || [ ! -x /sbin/cryptsetup ]
+                       then
+                               log_warning_msg "cryptsetup in unavailable"
+                               continue
+                       fi
+
                        if ! /sbin/cryptsetup isLuks ${dev}
                        then
-                               # we only look for encrypted subdevices
+                               # skip device since we strictly want luks devices
                                continue
                        fi
 
+                       load_keymap
+
                        while true
                        do
-                               load_keymap
+                               /lib/cryptsetup/askpass "Enter passphrase for ${dev}: " | /sbin/cryptsetup -T 1 luksOpen ${dev} $(basename ${dev}) --key-file=-
 
-                               /lib/cryptsetup/askpass "Enter passphrase for ${pers_label} on ${dev}: " | /sbin/cryptsetup -T 1 luksOpen ${dev} $(basename ${dev}) --key-file=-
-                               error=${?}
-
-                               dev="/dev/mapper/$(basename ${dev})"
-
-                               if [ 0 -eq ${error} ]
+                               if [ 0 -eq ${?} ]
                                then
-                                       unset error
+                                       luks_device="/dev/mapper/$(basename ${dev})"
+                                       dev="${luks_device}"
                                        break
                                fi
 
@@ -368,80 +383,68 @@ find_cow_device ()
 
                                if [ "$(echo "${answer}" | cut -b1 | tr A-Z a-z)" = "n" ]
                                then
-                                       unset answer
-                                       # skip to next subdevice
-                                       continue 2
+                                       break
                                fi
                        done
                fi
 
-               if echo ${PERSISTENT_STORAGE} | grep -qw filesystem && [ "$(/sbin/blkid -s LABEL -o value $dev 2>/dev/null)" = "${pers_label}" ]
-               then
-                       echo "${dev}"
-                       return 0
-               fi
-
-               if ! echo ${PERSISTENT_STORAGE} | grep -qw file
-               then
-                       # do not mount the device to find for image files
-                       # just skip this
-                       continue
-               fi
-
-               devfstype="$(get_fstype ${dev})"
-
-               if is_supported_fs ${devfstype}
+               if echo ${PERSISTENT_STORAGE} | grep -qw filesystem
                then
-                       mkdir -p "${cow_backing}"
-                       if try_mount "${dev}" "${cow_backing}" "rw"
-                       then
-                               if [ -f "${pers_fpath}" ]
+                       for label in ${overlays} ${snapshots}
+                       do
+                               if [ "$(/sbin/blkid -s LABEL -o value $dev 2>/dev/null)" = "${label}" ]
                                then
-                                       echo $(setup_loop "${pers_fpath}" "loop" "/sys/block/loop*")
-                                       return 0
-                               else
-                                       umount ${cow_backing} > /dev/null 2>&1 || true
+                                       overlays=$(echo ${overlays} | sed -e "s|\<${label}\>||")
+                                       snapshots=$(echo ${snapshots} | sed -e "s|\<${label}\>||")
+                                       echo "${label}=${dev}"
+                                       # skip to the next device
+                                       continue 2
                                fi
-                       fi
+                       done
                fi
-       done
-       return 1
-}
-
-find_files ()
-{
-       # return the a string composed by device name, mountpoint an the first of ${filenames} found on a supported partition
-       #  if is not in black_listed_devices.
-       #  Additionally, if the white_listed_devices list is non-empty, the
-       #  parent block device of the returned device must be part of this list.
-       # FIXME: merge with above function
-
-       filenames="${1}"
-       snap_backing="/snap-backing"
-       black_listed_devices="${2}"
-       white_listed_devices="${3}"
 
-       for dev in $(storage_devices "${black_listed_devices}" "${white_listed_devices}")
-       do
-               devfstype="$(get_fstype ${dev})"
-
-               if is_supported_fs ${devfstype}
+               if echo ${PERSISTENT_STORAGE} | grep -qw file
                then
-                       mkdir -p "${snap_backing}"
-
-                       if try_mount "${dev}" "${snap_backing}" "ro" "${devfstype}"
+                       devfstype="$(get_fstype ${dev})"
+                       overlay_on_dev=""
+                       snapshot_on_dev=""
+                       backing="/$(basename ${dev})-backing"
+                       mkdir -p "${backing}"
+                       if is_supported_fs ${devfstype} && try_mount "${dev}" "${backing}" "rw" "${devfstype}"
                        then
-                               for filename in ${filenames}
+                               for label in ${overlays}
                                do
-                                       if [ -f "${snap_backing}/${filename}" ]
+                                       path=${backing}/${PERSISTENT_PATH}${label}
+                                       if [ -f "${path}" ]
                                        then
-                                               echo "${dev} ${snap_backing} ${filename}"
-                                               umount ${snap_backing}
-                                               return 0
+                                               overlays=$(echo ${overlays} | sed -e "s|\<${label}\>||")
+                                               overlay_on_dev="yes"
+                                               echo "${label}=$(setup_loop "${path}" "loop" "/sys/block/loop*")"
                                        fi
                                done
+
+                               for label in ${snapshots}
+                               do
+                                       for ext in squashfs cpio.gz ext2 ext3 ext4 jffs2
+                                       do
+                                               path="${PERSISTENT_PATH}${label}.${ext}"
+                                               if [ -f "${backing}/${path}" ]
+                                               then
+                                                       snapshots=$(echo ${snapshots} | sed -e "s|\<${label}\>||")
+                                                       snapshot_on_dev="yes"
+                                                       echo "${label}=${dev}:${backing}:${path}"
+                                               fi
+                                       done
+                               done
+                       fi
+                       if [ -z "${overlay_on_dev}" ]
+                       then
+                               umount ${backing} > /dev/null 2>&1 || true
+                               if [ -z "${snapshot_on_dev}" ] && [ -n "${luks_device}" ] && /sbin/cryptsetup status "${luks_device}" 1> /dev/null
+                               then
+                                       /sbin/cryptsetup luksClose "${luks_device}"
+                               fi
                        fi
-                       umount ${snap_backing}
                fi
        done
 }