Use trim_path when we compare paths.
[live-boot-grml.git] / scripts / live-helpers
index abdfd64..795de55 100644 (file)
@@ -514,12 +514,19 @@ get_fstype ()
 where_is_mounted ()
 {
        device=${1}
+       # return first found
+       grep -m1 "^${device} " /proc/mounts | cut -f2 -d ' '
+}
 
-       if grep -q "^${device} " /proc/mounts
-       then
-               # return the first found
-               grep -m1 "^${device} " /proc/mounts | cut -f2 -d ' '
-       fi
+trim_path () {
+    # remove all unnecessary /:s in the path, including last
+    echo ${1} | sed 's|//|/|g' | sed 's|/$||'
+}
+
+what_is_mounted_on ()
+{
+       local dir="$(trim_path ${1})"
+       grep -m1 "^[^ ]\+ ${dir} " /proc/mounts | cut -d' ' -f1
 }
 
 lastline ()
@@ -711,6 +718,52 @@ try_mount ()
        fi
 }
 
+mount_persistent_media ()
+{
+       local device=${1}
+       local backing=""
+
+       # We can't mount into ${rootmnt}/live before ${rootmnt} has been
+       # mounted since that would cover our mountpoint.
+       if [ -n "${rootmnt}" ] && [ -z "$(what_is_mounted_on ${rootmnt})" ]
+       then
+               backing="/$(basename ${device})-backing"
+       else
+               backing="${rootmnt}/live/persistent/$(basename ${device})"
+       fi
+
+       mkdir -p "${backing}"
+       local old_backing="$(where_is_mounted ${device})"
+       if [ -z "${old_backing}" ]
+       then
+               local fstype="$(get_fstype ${device})"
+               local mount_opts="rw,noatime"
+               if [ -n "${PERSISTENT_READONLY}" ]
+               then
+                       mount_opts="ro,noatime"
+               fi
+               if mount -t "${fstype}" -o "${mount_opts}" "${device}" "${backing}" >/dev/null
+               then
+                       echo ${backing}
+                       return 0
+               else
+                       log_warning_msg "Failed to mount persistent media ${device}"
+                       return 1
+               fi
+       elif [ "${backing}" != "${old_backing}" ]
+       then
+               if mount --move ${old_backing} ${backing} >/dev/null
+               then
+                       echo ${backing}
+                       return 0
+               else
+                       log_warning_msg "Failed to move persistent media ${device}"
+                       return 1
+               fi
+       fi
+       return 0
+}
+
 open_luks_device ()
 {
        dev="${1}"
@@ -721,6 +774,21 @@ open_luks_device ()
                opts="${opts} --readonly"
        fi
 
+       if /sbin/cryptsetup status "${name}" >/dev/null 2>&1
+       then
+               re="^[[:space:]]*device:[[:space:]]*\([^[:space:]]*\)$"
+               opened_dev=$(cryptsetup status ${name} 2>/dev/null | grep "${re}" | sed "s|${re}|\1|")
+               if [ "${opened_dev}" = "${dev}" ]
+               then
+                       luks_device="/dev/mapper/${name}"
+                       echo ${luks_device}
+                       return 0
+               else
+                       log_warning_msg "Cannot open luks device ${dev} since ${opened_dev} already is opened with its name"
+                       return 1
+               fi
+       fi
+
        load_keymap
 
        while true
@@ -746,12 +814,14 @@ open_luks_device ()
        done
 }
 
-get_gpt_name () {
+get_gpt_name ()
+{
     local dev="${1}"
     /sbin/blkid -s PART_ENTRY_NAME -p -o value ${dev} 2>/dev/null
 }
 
-is_gpt_device () {
+is_gpt_device ()
+{
     local dev="${1}"
     [ "$(/sbin/blkid -s PART_ENTRY_SCHEME -p -o value ${dev} 2>/dev/null)" = "gpt" ]
 }
@@ -777,7 +847,8 @@ probe_for_gpt_name ()
        done
 }
 
-probe_for_fs_label () {
+probe_for_fs_label ()
+{
        local overlays="${1}"
        local snapshots="${2}"
        local dev="${3}"
@@ -791,44 +862,45 @@ probe_for_fs_label () {
        done
 }
 
-probe_for_file_name () {
+probe_for_file_name ()
+{
        local overlays="${1}"
        local snapshots="${2}"
        local dev="${3}"
 
-       local devfstype="$(get_fstype ${dev})"
-       local backing="${rootmnt}/live/persistent/$(basename ${dev})"
        local ret=""
-       if is_supported_fs ${devfstype} && mkdir -p "${backing}" && \
-          try_mount "${dev}" "${backing}" "rw" "${devfstype}"
+       local backing="$(mount_persistent_media ${dev})"
+       if [ -z "${backing}" ]
        then
-               for label in ${overlays}
+           return
+       fi
+
+       for label in ${overlays}
+       do
+               path=${backing}/${PERSISTENT_PATH}${label}
+               if [ -f "${path}" ]
+               then
+                       local loopdev=$(setup_loop "${path}" "loop" "/sys/block/loop*")
+                       ret="${ret} ${label}=${loopdev}"
+               fi
+       done
+       for label in ${snapshots}
+       do
+               for ext in squashfs cpio.gz ext2 ext3 ext4 jffs2
                do
-                       path=${backing}/${PERSISTENT_PATH}${label}
-                       if [ -f "${path}" ]
+                       path="${PERSISTENT_PATH}${label}.${ext}"
+                       if [ -f "${backing}/${path}" ]
                        then
-                               local loopdev=$(setup_loop "${path}" "loop" "/sys/block/loop*")
-                               ret="${ret} ${label}=${loopdev}"
+                               ret="${ret} ${label}=${dev}:${backing}:${path}"
                        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
-                                       ret="${ret} ${label}=${dev}:${backing}:${path}"
-                               fi
-                       done
-               done
+       done
 
-               if [ -n "${ret}" ]
-               then
-                       echo ${ret}
-               else
-                       umount ${backing} > /dev/null 2>&1 || true
-               fi
+       if [ -n "${ret}" ]
+       then
+               echo ${ret}
+       else
+               umount ${backing} > /dev/null 2>&1 || true
        fi
 }
 
@@ -857,11 +929,10 @@ find_persistent_media ()
 
        local overlays="${1}"
        local snapshots="${2}"
-       local black_listed_devices="${3}"
-       local white_listed_devices="${4}"
+       local white_listed_devices="${3}"
        local ret=""
 
-       for dev in $(storage_devices "${black_listed_devices}" "${white_listed_devices}")
+       for dev in $(storage_devices "" "${white_listed_devices}")
        do
                local result=""
 
@@ -1055,22 +1126,21 @@ link_files ()
 
        # This check can only trigger on the inital, non-recursive call since
        # we create the destination before recursive calls
-       if [ ! -d "${dest_dir}" ];
+       if [ ! -d "${dest_dir}" ]
        then
                log_warning_msg "Must link_files into a directory"
                return
        fi
 
-       find "${src_dir}" -mindepth 1 -maxdepth 1 | while read x; do
-               local src="${x}"
-               local dest="${dest_dir}$(basename "${x}")"
-               if [ -d "${src}" ];
+       find "${src_dir}" -mindepth 1 -maxdepth 1 | while read src; do
+               local dest="${dest_dir}$(basename "${src}")"
+               if [ -d "${src}" ]
                then
-                       if [ -z "$(ls -A "${src}")" ];
+                       if [ -z "$(ls -A "${src}")" ]
                        then
                                continue
                        fi
-                       if [ ! -d "${dest}" ];
+                       if [ ! -d "${dest}" ]
                        then
                                mkdir -p "${dest}"
                                prev="$(dirname "${dest}")"
@@ -1089,7 +1159,8 @@ link_files ()
        done
 }
 
-do_union () {
+do_union ()
+{
        local unionmountpoint="${1}"    # directory where the union is mounted
        local unionrw="${2}"            # branch where the union changes are stored
        local unionro1="${3}"           # first underlying read-only branch (optional)
@@ -1149,18 +1220,17 @@ do_union () {
        esac
 }
 
-get_custom_mounts () {
+get_custom_mounts ()
+{
        # Side-effect: leaves $devices with live.persist mounted in ${rootmnt}/live/persistent
        # Side-effect: prints info to file $custom_mounts
 
        local devices="${1}"
        local custom_mounts="${2}" # print result to this file
-       local rootmnt="${3}"       # should be set empty post-live-boot
 
-       local bindings="/bindings.list"
-       local links="/links.list"
+       local bindings="/tmp/bindings.list"
+       local links="/tmp/links.list"
        rm -rf ${bindings} ${links} 2> /dev/null
-       local persistent_backing="${rootmnt}/live/persistent"
 
        for device in ${devices}
        do
@@ -1171,26 +1241,12 @@ get_custom_mounts () {
 
                local device_name="$(basename ${device})"
                local device_used=""
-               # $device may already have been mounted by
-               # probe_for_file_name() in find_persistent_media() ...
-               local backing=$(where_is_mounted ${device})
+               local backing=$(mount_persistent_media ${device})
                if [ -z "${backing}" ]
                then
-                       # ... otherwise we mount it now
-                       backing="${persistent_backing}/${device_name}"
-                       mkdir -p "${backing}"
-                       local device_fstype="$(get_fstype ${device})"
-                       if [ -z "${PERSISTENT_READONLY}" ]
-                       then
-                               device_mount_opts="rw,noatime"
-                       else
-                               device_mount_opts="ro,noatime"
-                       fi
-                       if ! mount -t "${device_fstype}" -o "${device_mount_opts}" "${device}" "${backing}" >/dev/null 2>&1
-                       then
-                               log_warning_msg "Could not mount persistent media ${device} (${device_fstype})"
-                       fi
+                       continue
                fi
+
                local include_list="${backing}/${persistence_list}"
                if [ ! -r "${include_list}" ]
                then
@@ -1203,7 +1259,11 @@ get_custom_mounts () {
                        continue
                fi
 
-               [ "${DEBUG}" = "Yes" ] && cp ${include_list} ${persistent_backing}/${persistence_list}.${device_name}
+               if [ -n "${DEBUG}" ] && [ -e "${include_list}" ]
+               then
+                       cp ${include_list} ${rootmnt}/live/persistent/${persistence_list}.${device_name}
+               fi
+
                while read source dest options # < ${include_list}
                do
                        if echo ${source} | grep -qe "^[[:space:]]*\(#.*\)\?$"
@@ -1221,10 +1281,15 @@ get_custom_mounts () {
                                dest="${source}"
                        fi
 
-                       if echo ${dest} | grep -qe "^/\+$\|^/\+live\(/.*\)\?$"
+                       if trim_path ${source} | grep -qe "^\(.*/\)\?\.\.\?\(/.*\)\?$"
                        then
-                               # mounting on / or /live could cause trouble
-                               log_warning_msg "Skipping unsafe custom mount on ${dest}"
+                               log_warning_msg "Skipping unsafe custom mount with source ${source}: the source is a relative or absolute path w.r.t. the persistent media root and cannot use \".\" or \"..\""
+                               continue
+                       fi
+
+                       if trim_path ${dest} | grep -q -e "^/$" -e "^/live\(/.*\)\?$" -e "^/\(.*/\)\?\.\.\?\(/.*\)\?$"
+                       then
+                               log_warning_msg "Skipping unsafe custom mount with desination ${dest}: the destination must be an absolute path using neither \".\" nor \"..\", and cannot be /live (or any sub-directory therein) or / (for the latter, use ${root_overlay_label}-type persistence instead)"
                                continue
                        fi
 
@@ -1240,18 +1305,9 @@ get_custom_mounts () {
                                esac
                        done
 
-                       # FIXME: handle case: we already have /a/b in
-                       # $bindings added from current $device, but
-                       # now we find /a -- /a should replace /a/b in
-                       # $bindings.
-
-                       # FIXME: handle case: we have /a in $bindings
-                       # from current $device, now we find /a/b, so
-                       # we skip /a/b
-
                        # ensure that no multiple-/ occur in paths
-                       local full_source="$(echo ${backing}/${source}/ | sed -e 's|/\+|/|g')"
-                       local full_dest="$(echo ${rootmnt}/${dest}/ | sed -e 's|/\+|/|g')"
+                       local full_source="$(trim_path ${backing}/${source})"
+                       local full_dest="$(trim_path ${rootmnt}/${dest})"
                        device_used="yes"
                        if echo ${options} | grep -qe "\<linkfiles\>";
                        then
@@ -1280,9 +1336,9 @@ get_custom_mounts () {
        [ -e "${links}" ] && sort -k2 -sbu ${links} >> ${custom_mounts} && rm ${links}
 }
 
-do_custom_mounts () {
+do_custom_mounts ()
+{
        local custom_mounts="${1}" # the ouput from get_custom_mounts()
-       local rootmnt="${2}"       # should be set empty post-live-boot
 
        while read source dest options # < ${custom_mounts}
        do
@@ -1300,9 +1356,9 @@ do_custom_mounts () {
                        esac
                done
 
-               if mountpoint -q "${dest}";
+               if [ -n "$(what_is_mounted_on "${dest}")" ]
                then
-                       log_warning_msg "Skipping custom mount ${source} on ${dest}: destination is already a mount point"
+                       log_warning_msg "Skipping custom mount ${source} on ${dest}: $(what_is_mounted_on "${dest}") is already mounted there"
                        continue
                fi
 
@@ -1317,7 +1373,7 @@ do_custom_mounts () {
                        # FIXME: this should really be handled by
                        # live-config since we don't know for sure
                        # which uid a certain user has until then
-                       if echo ${dest} | grep -qe "^${rootmnt}/*home/\+[^/]\+"
+                       if trim_path ${dest} | grep -qe "^${rootmnt}/*home/[^/]\+"
                        then
                                path="/"
                                for dir in $(echo ${dest} | sed -e 's|/\+| |g')
@@ -1363,7 +1419,6 @@ do_custom_mounts () {
                                rofs_dest_backing="${d}/$(echo ${dest} | sed -e "s|${rootmnt}||")"
                        else
                                rofs_dest_backing="${d}/${dest}"
-
                        fi
                        if [ -d "${rofs_dest_backing}" ]
                        then
@@ -1421,15 +1476,9 @@ fix_home_rw_compatibility ()
                return
        fi
 
-       local backing="$(where_is_mounted ${device})"
+       local backing="$(mount_persistent_media ${device})"
        if [ -z "${backing}" ]
        then
-               backing="${rootmnt}/live/persistent/$(basename ${device})"
-               mkdir -p "${backing}"
-               local device_fstype="$(get_fstype ${device})"
-       local device_mount_opts="rw,noatime"
-       if ! mount -t "${device_fstype}" -o "${device_mount_opts}" "${device}" "${backing}" >/dev/null 2>&1
-       then
                return
        fi
 
@@ -1437,6 +1486,6 @@ fix_home_rw_compatibility ()
        if [ ! -r "${include_list}" ]
        then
                echo "# home-rw backwards compatibility:
-. /home" > "${include_list}"
+/ /home" > "${include_list}"
        fi
 }