+++ /dev/null
-# live-boot helper functions, used by live-boot on boot and by live-snapshot
-
-if [ ! -x "/bin/fstype" ]
-then
- # klibc not in path -> not in initramfs
- export PATH="${PATH}:/usr/lib/klibc/bin"
-fi
-
-# handle upgrade path from old udev (using udevinfo) to
-# recent versions of udev (using udevadm info)
-if [ -x /sbin/udevadm ]
-then
- udevinfo='/sbin/udevadm info'
-else
- udevinfo='udevinfo'
-fi
-
-old_root_overlay_label="live-rw"
-old_home_overlay_label="home-rw"
-custom_overlay_label="custom-ov"
-root_snapshot_label="live-sn"
-old_root_snapshot_label="live-sn"
-home_snapshot_label="home-sn"
-persistence_list="live-persistence.conf"
-
-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
- ;;
-
- console=*)
- DEFCONSOLE="${ARGUMENT#*=}"
- export DEFCONSOLE
- ;;
-
- BOOTIF=*)
- BOOTIF="${x#BOOTIF=}"
- ;;
-
- debug)
- DEBUG="Yes"
- export DEBUG
-
- 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
- ;;
-
- findiso=*)
- FINDISO="${ARGUMENT#findiso=}"
- export FINDISO
- ;;
-
- forcepersistencefsck)
- FORCEPERSISTENCEFSCK="Yes"
- export FORCEPERSISTENCEFSCK
- ;;
-
- ftpfs=*)
- FTPFS="${ARGUMENT#ftpfs=}"
- export FTPFS
- ;;
-
- httpfs=*)
- HTTPFS="${ARGUMENT#httpfs=}"
- export HTTPFS
- ;;
-
- 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
- ;;
-
- isofrom=*|fromiso=*)
- FROMISO="${ARGUMENT#*=}"
- export FROMISO
- ;;
-
- ignore_uuid)
- IGNORE_UUID="Yes"
- export IGNORE_UUID
- ;;
-
- integrity-check)
- INTEGRITY_CHECK="Yes"
- export INTEGRITY_CHECK
- ;;
-
- ip=*)
- STATICIP="${ARGUMENT#ip=}"
-
- if [ -z "${STATICIP}" ]
- then
- STATICIP="frommedia"
- fi
-
- export STATICIP
- ;;
-
- live-getty)
- LIVE_GETTY="1"
- export LIVE_GETTY
- ;;
-
- live-media=*|bootfrom=*)
- LIVE_MEDIA="${ARGUMENT#*=}"
- export LIVE_MEDIA
- ;;
-
- live-media-encryption=*|encryption=*)
- LIVE_MEDIA_ENCRYPTION="${ARGUMENT#*=}"
- export LIVE_MEDIA_ENCRYPTION
- ;;
-
- live-media-offset=*)
- LIVE_MEDIA_OFFSET="${ARGUMENT#live-media-offset=}"
- export LIVE_MEDIA_OFFSET
- ;;
-
- live-media-path=*)
- LIVE_MEDIA_PATH="${ARGUMENT#live-media-path=}"
- export LIVE_MEDIA_PATH
- ;;
-
- live-media-timeout=*)
- LIVE_MEDIA_TIMEOUT="${ARGUMENT#live-media-timeout=}"
- export LIVE_MEDIA_TIMEOUT
- ;;
-
- module=*)
- MODULE="${ARGUMENT#module=}"
- export MODULE
- ;;
-
- netboot=*)
- NETBOOT="${ARGUMENT#netboot=}"
- export NETBOOT
- ;;
-
- nfsopts=*)
- NFSOPTS="${ARGUMENT#nfsopts=}"
- export NFSOPTS
- ;;
-
- nfsoverlay=*)
- NFS_COW="${ARGUMENT#nfsoverlay=}"
- export NFS_COW
- ;;
-
- noaccessibility)
- NOACCESSIBILITY="Yes"
- export NOACCESSIBILITY
- ;;
-
- nofastboot)
- NOFASTBOOT="Yes"
- export NOFASTBOOT
- ;;
-
- nofstab)
- NOFSTAB="Yes"
- export NOFSTAB
- ;;
-
- nonetworking)
- NONETWORKING="Yes"
- export NONETWORKING
- ;;
-
- ramdisk-size=*)
- ramdisk_size="${ARGUMENT#ramdisk-size=}"
- ;;
-
- swapon)
- SWAPON="Yes"
- export SWAPON
- ;;
-
- persistence)
- PERSISTENCE="Yes"
- export PERSISTENCE
- ;;
-
- persistence-encryption=*)
- PERSISTENCE_ENCRYPTION="${ARGUMENT#*=}"
- export PERSISTENCE_ENCRYPTION
- ;;
-
- persistence-media=*)
- PERSISTENCE_MEDIA="${ARGUMENT#*=}"
- export PERSISTENCE_MEDIA
- ;;
- persistence-method=*)
- PERSISTENCE_METHOD="${ARGUMENT#*=}"
- export PERSISTENCE_METHOD
- ;;
-
- persistence-path=*)
- PERSISTENCE_PATH="${ARGUMENT#persistence-path=}"
- export PERSISTENCE_PATH
- ;;
- persistence-read-only)
- PERSISTENCE_READONLY="Yes"
- export PERSISTENCE_READONLY
- ;;
-
- persistence-storage=*)
- PERSISTENCE_STORAGE="${ARGUMENT#persistence-storage=}"
- export PERSISTENCE_STORAGE
- ;;
-
- persistence-subtext=*)
- old_root_overlay_label="${old_root_overlay_label}-${ARGUMENT#persistence-subtext=}"
- old_home_overlay_label="${old_home_overlay_label}-${ARGUMENT#persistence-subtext=}"
- custom_overlay_label="${custom_overlay_label}-${ARGUMENT#persistence-subtext=}"
- root_snapshot_label="${root_snapshot_label}-${ARGUMENT#persistence-subtext=}"
- old_root_snapshot_label="${root_snapshot_label}-${ARGUMENT#persistence-subtext=}"
- home_snapshot_label="${home_snapshot_label}-${ARGUMENT#persistence-subtext=}"
- ;;
-
- nopersistence)
- NOPERSISTENCE="Yes"
- export NOPERSISTENCE
- ;;
-
- noprompt)
- NOPROMPT="Yes"
- export NOPROMPT
- ;;
-
- noprompt=*)
- NOPROMPT="${ARGUMENT#noprompt=}"
- export NOPROMPT
- ;;
-
- quickusbmodules)
- QUICKUSBMODULES="Yes"
- export QUICKUSBMODULES
- ;;
-
- preseed/file=*|file=*)
- LOCATIONS="${ARGUMENT#*=} ${LOCATIONS}"
- export LOCATIONS
- ;;
-
- nopreseed)
- NOPRESEED="Yes"
- export NOPRESEED
- ;;
-
- */*=*)
- question="${ARGUMENT%%=*}"
- value="${ARGUMENT#*=}"
- PRESEEDS="${PRESEEDS}\"${question}=${value}\" "
- export PRESEEDS
- ;;
-
- showmounts)
- SHOWMOUNTS="Yes"
- export SHOWMOUNTS
- ;;
-
- silent)
- SILENT="Yes"
- export SILENT
- ;;
-
- todisk=*)
- TODISK="${ARGUMENT#todisk=}"
- export TODISK
- ;;
-
- toram)
- TORAM="Yes"
- export TORAM
- ;;
-
- toram=*)
- TORAM="Yes"
- MODULETORAM="${ARGUMENT#toram=}"
- export TORAM MODULETORAM
- ;;
-
- exposedroot)
- EXPOSED_ROOT="Yes"
- export EXPOSED_ROOT
- ;;
-
- plainroot)
- PLAIN_ROOT="Yes"
- export PLAIN_ROOT
- ;;
-
- skipunion)
- SKIP_UNION_MOUNTS="Yes"
- export SKIP_UNION_MOUNTS
- ;;
-
- root=*)
- ROOT="${ARGUMENT#root=}"
- export ROOT
- ;;
-
- union=*)
- UNIONTYPE="${ARGUMENT#union=}"
- export UNIONTYPE
- ;;
- esac
- done
-
- # sort of compatibility with netboot.h from linux docs
- if [ -z "${NETBOOT}" ]
- then
- if [ "${ROOT}" = "/dev/nfs" ]
- then
- NETBOOT="nfs"
- export NETBOOT
- elif [ "${ROOT}" = "/dev/cifs" ]
- then
- NETBOOT="cifs"
- export NETBOOT
- fi
- fi
-
- if [ -z "${MODULE}" ]
- then
- MODULE="filesystem"
- export MODULE
- fi
-
- if [ -z "${UNIONTYPE}" ]
- then
- UNIONTYPE="aufs"
- export UNIONTYPE
- fi
-
- if [ -z "${PERSISTENCE_ENCRYPTION}" ]
- then
- PERSISTENCE_ENCRYPTION="none"
- export PERSISTENCE_ENCRYPTION
- elif is_in_comma_sep_list luks ${PERSISTENCE_ENCRYPTION}
- then
- if ! modprobe dm-crypt
- then
- log_warning_msg "Unable to load module dm-crypt"
- PERSISTENCE_ENCRYPTION=$(echo ${PERSISTENCE_ENCRYPTION} | sed -e 's/\<luks,\|,\?luks$//g')
- export PERSISTENCE_ENCRYPTION
- fi
-
- if [ ! -x /lib/cryptsetup/askpass ] || [ ! -x /sbin/cryptsetup ]
- then
- log_warning_msg "cryptsetup in unavailable"
- PERSISTENCE_ENCRYPTION=$(echo ${PERSISTENCE_ENCRYPTION} | sed -e 's/\<luks,\|,\?luks$//g')
- export PERSISTENCE_ENCRYPTION
- fi
- fi
-
- if [ -z "${PERSISTENCE_METHOD}" ]
- then
- PERSISTENCE_METHOD="snapshot,overlay"
- export PERSISTENCE_METHOD
- fi
-
- if [ -z "${PERSISTENCE_STORAGE}" ]
- then
- PERSISTENCE_STORAGE="filesystem,file"
- export PERSISTENCE_STORAGE
- fi
-}
-
-is_in_list_separator_helper () {
- local sep=${1}
- shift
- local element=${1}
- shift
- local list=${*}
- echo ${list} | grep -qe "^\(.*${sep}\)\?${element}\(${sep}.*\)\?$"
-}
-
-is_in_space_sep_list () {
- local element=${1}
- shift
- is_in_list_separator_helper "[[:space:]]" "${element}" "${*}"
-}
-
-is_in_comma_sep_list () {
- local element=${1}
- shift
- is_in_list_separator_helper "," "${element}" "${*}"
-}
-
-sys2dev ()
-{
- sysdev=${1#/sys}
- echo "/dev/$($udevinfo -q name -p ${sysdev} 2>/dev/null|| echo ${sysdev##*/})"
-}
-
-subdevices ()
-{
- sysblock=${1}
- r=""
-
- for dev in "${sysblock}"/* "${sysblock}"
- do
- if [ -e "${dev}/dev" ]
- then
- r="${r} ${dev}"
- fi
- done
-
- echo ${r}
-}
-
-storage_devices()
-{
- black_listed_devices="${1}"
- white_listed_devices="${2}"
-
- for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -vE "loop|ram|fd")
- do
- fulldevname=$(sys2dev "${sysblock}")
-
- if is_in_space_sep_list ${fulldevname} ${black_listed_devices} || \
- [ -n "${white_listed_devices}" ] && \
- ! is_in_space_sep_list ${fulldevname} ${white_listed_devices}
- then
- # skip this device entirely
- continue
- fi
-
- for dev in $(subdevices "${sysblock}")
- do
- devname=$(sys2dev "${dev}")
-
- if is_in_space_sep_list ${devname} ${black_listed_devices}
- then
- # skip this subdevice
- continue
- else
- echo "${devname}"
- fi
- done
- done
-}
-
-is_supported_fs ()
-{
- fstype="${1}"
-
- # Validate input first
- if [ -z "${fstype}" ]
- then
- return 1
- fi
-
- # Try to look if it is already supported by the kernel
- if grep -q ${fstype} /proc/filesystems
- then
- return 0
- else
- # Then try to add support for it the gentle way using the initramfs capabilities
- modprobe ${fstype}
- if grep -q ${fstype} /proc/filesystems
- then
- return 0
- # Then try the hard way if /root is already reachable
- else
- kmodule="/root/lib/modules/`uname -r`/${fstype}/${fstype}.ko"
- if [ -e "${kmodule}" ]
- then
- insmod "${kmodule}"
- if grep -q ${fstype} /proc/filesystems
- then
- return 0
- fi
- fi
- fi
- fi
-
- return 1
-}
-
-get_fstype ()
-{
- /sbin/blkid -s TYPE -o value $1 2>/dev/null
-}
-
-where_is_mounted ()
-{
- device=${1}
- # return first found
- grep -m1 "^${device} " /proc/mounts | cut -f2 -d ' '
-}
-
-trim_path () {
- # remove all unnecessary /:s in the path, including last one (except
- # if path is just "/")
- echo ${1} | sed 's|//\+|/|g' | sed 's|^\(.*[^/]\)/$|\1|'
-}
-
-what_is_mounted_on ()
-{
- local dir="$(trim_path ${1})"
- grep -m1 "^[^ ]\+ ${dir} " /proc/mounts | cut -d' ' -f1
-}
-
-chown_ref ()
-{
- local reference="${1}"
- shift
- local targets=${@}
- local owner=$(stat -c %u:%g "${reference}")
- chown -h ${owner} ${targets}
-}
-
-chmod_ref ()
-{
- local reference="${1}"
- shift
- local targets=${@}
- local rights=$(stat -c %a "${reference}")
- chmod ${rights} ${targets}
-}
-
-lastline ()
-{
- while read lines
- do
- line=${lines}
- done
-
- echo "${line}"
-}
-
-base_path ()
-{
- testpath="${1}"
- mounts="$(awk '{print $2}' /proc/mounts)"
- testpath="$(busybox realpath ${testpath})"
-
- while true
- do
- if echo "${mounts}" | grep -qs "^${testpath}"
- then
- set -- $(echo "${mounts}" | grep "^${testpath}" | lastline)
- echo ${1}
- break
- else
- testpath=$(dirname $testpath)
- fi
- done
-}
-
-fs_size ()
-{
- # Returns used/free fs kbytes + 5% more
- # You could pass a block device as ${1} or the mount point as ${2}
-
- dev="${1}"
- mountp="${2}"
- used="${3}"
-
- if [ -z "${mountp}" ]
- then
- mountp="$(where_is_mounted ${dev})"
-
- if [ -z "${mountp}" ]
- then
- mountp="/mnt/tmp_fs_size"
-
- mkdir -p "${mountp}"
- mount -t $(get_fstype "${dev}") -o ro "${dev}" "${mountp}" || log_warning_msg "cannot mount -t $(get_fstype ${dev}) -o ro ${dev} ${mountp}"
-
- doumount=1
- fi
- fi
-
- if [ "${used}" = "used" ]
- then
- size=$(du -ks ${mountp} | cut -f1)
- size=$(expr ${size} + ${size} / 20 ) # FIXME: 5% more to be sure
- else
- # free space
- size="$(df -k | grep -s ${mountp} | awk '{print $4}')"
- fi
-
- if [ -n "${doumount}" ]
- then
- umount "${mountp}" || log_warning_msg "cannot umount ${mountp}"
- rmdir "${mountp}"
- fi
-
- echo "${size}"
-}
-
-load_keymap ()
-{
- # Load custom keymap
- if [ -x /bin/loadkeys -a -r /etc/boottime.kmap.gz ]
- then
- loadkeys /etc/boottime.kmap.gz
- fi
-}
-
-setup_loop ()
-{
- local fspath=${1}
- local module=${2}
- local pattern=${3}
- local offset=${4}
- local encryption=${5}
- local readonly=${6}
-
- # the output of setup_loop is evaluated in other functions,
- # modprobe leaks kernel options like "libata.dma=0"
- # as "options libata dma=0" on stdout, causing serious
- # problems therefor, so instead always avoid output to stdout
- modprobe -q -b "${module}" 1>/dev/null
-
- udevadm settle
-
- for loopdev in ${pattern}
- do
- if [ "$(cat ${loopdev}/size)" -eq 0 ]
- then
- dev=$(sys2dev "${loopdev}")
- options=''
-
- if [ -n "${readonly}" ]
- then
- if losetup --help 2>&1 | grep -q -- "-r\b"
- then
- options="${options} -r"
- fi
- fi
-
- if [ -n "${offset}" ] && [ 0 -lt "${offset}" ]
- then
- options="${options} -o ${offset}"
- fi
-
- if [ -z "${encryption}" ]
- then
- losetup ${options} "${dev}" "${fspath}"
- else
- # Loop AES encryption
- while true
- do
- load_keymap
-
- echo -n "Enter passphrase for root filesystem: " >&6
- read -s passphrase
- echo "${passphrase}" > /tmp/passphrase
- unset passphrase
- exec 9</tmp/passphrase
- /sbin/losetup ${options} -e "${encryption}" -p 9 "${dev}" "${fspath}"
- error=${?}
- exec 9<&-
- rm -f /tmp/passphrase
-
- if [ 0 -eq ${error} ]
- then
- unset error
- break
- fi
-
- echo
- echo -n "There was an error decrypting the root filesystem ... Retry? [Y/n] " >&6
- read answer
-
- if [ "$(echo "${answer}" | cut -b1 | tr A-Z a-z)" = "n" ]
- then
- unset answer
- break
- fi
- done
- fi
-
- echo "${dev}"
- return 0
- fi
- done
-
- panic "No loop devices available"
-}
-
-try_mount ()
-{
- dev="${1}"
- mountp="${2}"
- opts="${3}"
- fstype="${4}"
-
- old_mountp="$(where_is_mounted ${dev})"
-
- if [ -n "${old_mountp}" ]
- then
- if [ "${opts}" != "ro" ]
- then
- mount -o remount,"${opts}" "${dev}" "${old_mountp}" || panic "Remounting ${dev} ${opts} on ${old_mountp} failed"
- fi
-
- mount -o bind "${old_mountp}" "${mountp}" || panic "Cannot bind-mount ${old_mountp} on ${mountp}"
- else
- if [ -z "${fstype}" ]
- then
- fstype=$(get_fstype "${dev}")
- fi
- mount -t "${fstype}" -o "${opts}" "${dev}" "${mountp}" || \
- ( echo "SKIPPING: Cannot mount ${dev} on ${mountp}, fstype=${fstype}, options=${opts}" > boot.log && return 0 )
- fi
-}
-
-mount_persistence_media ()
-{
- local device=${1}
- local probe=${2}
-
- local backing="/live/persistence/$(basename ${device})"
-
- 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 "${PERSISTENCE_READONLY}" ]
- then
- mount_opts="ro,noatime"
- fi
- if mount -t "${fstype}" -o "${mount_opts}" "${device}" "${backing}" >/dev/null
- then
- echo ${backing}
- return 0
- else
- [ -z "${probe}" ] && log_warning_msg "Failed to mount persistence media ${device}"
- rmdir "${backing}"
- return 1
- fi
- elif [ "${backing}" != "${old_backing}" ]
- then
- 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
- fi
- return 0
-}
-
-close_persistence_media () {
- local device=${1}
- local backing="$(where_is_mounted ${device})"
-
- if [ -d "${backing}" ]
- then
- umount "${backing}" >/dev/null 2>&1
- rmdir "${backing}" >/dev/null 2>&1
- fi
-
- if is_active_luks_mapping ${device}
- then
- /sbin/cryptsetup luksClose ${device}
- fi
-}
-
-open_luks_device ()
-{
- dev="${1}"
- name="$(basename ${dev})"
- opts="--key-file=-"
- if [ -n "${PERSISTENCE_READONLY}" ]
- then
- 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
- do
- /lib/cryptsetup/askpass "Enter passphrase for ${dev}: " | \
- /sbin/cryptsetup -T 1 luksOpen ${dev} ${name} ${opts}
-
- if [ 0 -eq ${?} ]
- then
- luks_device="/dev/mapper/${name}"
- echo ${luks_device}
- return 0
- fi
-
- echo >&6
- echo -n "There was an error decrypting ${dev} ... Retry? [Y/n] " >&6
- read answer
-
- if [ "$(echo "${answer}" | cut -b1 | tr A-Z a-z)" = "n" ]
- then
- return 2
- fi
- done
-}
-
-get_gpt_name ()
-{
- local dev="${1}"
- /sbin/blkid -s PART_ENTRY_NAME -p -o value ${dev} 2>/dev/null
-}
-
-is_gpt_device ()
-{
- local dev="${1}"
- [ "$(/sbin/blkid -s PART_ENTRY_SCHEME -p -o value ${dev} 2>/dev/null)" = "gpt" ]
-}
-
-probe_for_gpt_name ()
-{
- local overlays="${1}"
- local snapshots="${2}"
- local dev="${3}"
-
- local gpt_dev="${dev}"
- if is_active_luks_mapping ${dev}
- then
- # if $dev is an opened luks device, we need to check
- # GPT stuff on the backing device
- gpt_dev=$(get_luks_backing_device "${dev}")
- fi
-
- if ! is_gpt_device ${gpt_dev}
- then
- return
- fi
-
- local gpt_name=$(get_gpt_name ${gpt_dev})
- for label in ${overlays} ${snapshots}
- do
- if [ "${gpt_name}" = "${label}" ]
- then
- echo "${label}=${dev}"
- fi
- done
-}
-
-probe_for_fs_label ()
-{
- local overlays="${1}"
- local snapshots="${2}"
- local dev="${3}"
-
- for label in ${overlays} ${snapshots}
- do
- if [ "$(/sbin/blkid -s LABEL -o value $dev 2>/dev/null)" = "${label}" ]
- then
- echo "${label}=${dev}"
- fi
- done
-}
-
-probe_for_file_name ()
-{
- local overlays="${1}"
- local snapshots="${2}"
- local dev="${3}"
-
- local ret=""
- local backing="$(mount_persistence_media ${dev} probe)"
- if [ -z "${backing}" ]
- then
- return
- fi
-
- for label in ${overlays}
- do
- path=${backing}/${PERSISTENCE_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="${PERSISTENCE_PATH}${label}.${ext}"
- if [ -f "${backing}/${path}" ]
- then
- ret="${ret} ${label}=${dev}:${backing}:${path}"
- fi
- done
- done
-
- if [ -n "${ret}" ]
- then
- echo ${ret}
- else
- umount ${backing} > /dev/null 2>&1 || true
- fi
-}
-
-find_persistence_media ()
-{
- # 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 persistence 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.
-
- local overlays="${1}"
- local snapshots="${2}"
- local white_listed_devices="${3}"
- local ret=""
-
- local black_listed_devices="$(what_is_mounted_on /live/image)"
-
- for dev in $(storage_devices "${black_listed_devices}" "${white_listed_devices}")
- do
- local result=""
-
- local luks_device=""
- # Check if it's a luks device; we'll have to open the device
- # in order to probe any filesystem it contains, like we do
- # below. activate_custom_mounts() also depends on that any luks
- # device already has been opened.
- if is_in_comma_sep_list luks ${PERSISTENCE_ENCRYPTION} && \
- is_luks_partition ${dev}
- then
- if luks_device=$(open_luks_device "${dev}")
- then
- dev="${luks_device}"
- else
- # skip $dev since we failed/chose not to open it
- continue
- fi
- elif ! is_in_comma_sep_list none ${PERSISTENCE_ENCRYPTION}
- then
- # skip $dev since we don't allow unencrypted storage
- continue
- fi
-
- # Probe for matching GPT partition names or filesystem labels
- if is_in_comma_sep_list filesystem ${PERSISTENCE_STORAGE}
- then
- result=$(probe_for_gpt_name "${overlays}" "${snapshots}" ${dev})
- if [ -n "${result}" ]
- then
- ret="${ret} ${result}"
- continue
- fi
-
- result=$(probe_for_fs_label "${overlays}" "${snapshots}" ${dev})
- if [ -n "${result}" ]
- then
- ret="${ret} ${result}"
- continue
- fi
- fi
-
- # Probe for files with matching name on mounted partition
- if is_in_comma_sep_list file ${PERSISTENCE_STORAGE}
- then
- result=$(probe_for_file_name "${overlays}" "${snapshots}" ${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
- /sbin/cryptsetup luksClose "${luks_device}"
- fi
- done
-
- if [ -n "${ret}" ]
- then
- echo ${ret}
- fi
-}
-
-get_mac ()
-{
- mac=""
-
- for adaptor in /sys/class/net/*
- do
- status="$(cat ${adaptor}/iflink)"
-
- if [ "${status}" -eq 2 ]
- then
- mac="$(cat ${adaptor}/address)"
- mac="$(echo ${mac} | sed 's/:/-/g' | tr '[a-z]' '[A-Z]')"
- fi
- done
-
- echo ${mac}
-}
-
-is_luks_partition ()
-{
- device="${1}"
- /sbin/cryptsetup isLuks "${device}" 1>/dev/null 2>&1
-}
-
-is_active_luks_mapping ()
-{
- device="${1}"
- /sbin/cryptsetup status "${device}" 1>/dev/null 2>&1
-}
-
-get_luks_backing_device () {
- device=${1}
- cryptsetup status ${device} 2> /dev/null | \
- awk '{if ($1 == "device:") print $2}'
-}
-
-removable_dev ()
-{
- output_format="${1}"
- want_usb="${2}"
- ret=
-
- for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -vE "/(loop|ram|dm-|fd)")
- do
- dev_ok=
- if [ "$(cat ${sysblock}/removable)" = "1" ]
- then
- if [ -z "${want_usb}" ]
- then
- dev_ok="yes"
- else
- if readlink ${sysblock} | grep -q usb
- then
- dev_ok="yes"
- fi
- fi
- fi
-
- if [ "${dev_ok}" = "yes" ]
- then
- case "${output_format}" in
- sys)
- ret="${ret} ${sysblock}"
- ;;
- *)
- devname=$(sys2dev "${sysblock}")
- ret="${ret} ${devname}"
- ;;
- esac
- fi
- done
-
- echo "${ret}"
-}
-
-removable_usb_dev ()
-{
- output_format="${1}"
-
- removable_dev "${output_format}" "want_usb"
-}
-
-non_removable_dev ()
-{
- output_format="${1}"
- ret=
-
- for sysblock in $(echo /sys/block/* | tr ' ' '\n' | grep -vE "/(loop|ram|dm-|fd)")
- do
- if [ "$(cat ${sysblock}/removable)" = "0" ]
- then
- case "${output_format}" in
- sys)
- ret="${ret} ${sysblock}"
- ;;
- *)
- devname=$(sys2dev "${sysblock}")
- ret="${ret} ${devname}"
- ;;
- esac
- fi
- done
-
- echo "${ret}"
-}
-
-link_files ()
-{
- # create source's directory structure in dest, and recursively
- # create symlinks in dest to to all files in source. if mask
- # is non-empty, remove mask from all source paths when
- # creating links (will be necessary if we change root, which
- # live-boot normally does (into $rootmnt)).
-
- # remove multiple /:s and ensure ending on /
- local src_dir="$(trim_path ${1})/"
- local dest_dir="$(trim_path ${2})/"
- local src_mask="${3}"
-
- # This check can only trigger on the inital, non-recursive call since
- # we create the destination before recursive calls
- 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 src; do
- local dest="${dest_dir}$(basename "${src}")"
- if [ -d "${src}" ]
- then
- if [ -z "$(ls -A "${src}")" ]
- then
- continue
- fi
- if [ ! -d "${dest}" ]
- then
- mkdir -p "${dest}"
- chown_ref "${src}" "${dest}"
- chmod_ref "${src}" "${dest}"
- fi
- link_files "${src}" "${dest}" "${src_mask}"
- else
- local final_src=${src}
- if [ -n "${src_mask}" ]
- then
- final_src="$(echo ${final_src} | sed "s|^${src_mask}||")"
- fi
- rm -rf "${dest}" 2> /dev/null
- ln -s "${final_src}" "${dest}"
- chown_ref "${src}" "${dest}"
- fi
- done
-}
-
-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)
- local unionro2="${4}" # second underlying read-only branch (optional)
-
- if [ "${UNIONTYPE}" = "aufs" ]
- then
- rw_opt="rw"
- ro_opt="rr+wh"
- noxino_opt="noxino"
- elif [ "${UNIONTYPE}" = "unionfs-fuse" ]
- then
- rw_opt="RW"
- ro_opt="RO"
- else
- rw_opt="rw"
- ro_opt="ro"
- fi
-
- 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}"
- if [ -n "${unionro1}" ]
- then
- unionmountopts="${unionmountopts}:${unionro1}=${ro_opt}"
- fi
- if [ -n "${unionro2}" ]
- then
- unionmountopts="${unionmountopts}:${unionro2}=${ro_opt}"
- 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 )
- ;;
-
- overlayfs)
- # XXX: can unionro2 be used? (overlayfs only handles two dirs, but perhaps they can be chained?)
- # XXX: and can unionro1 be optional? i.e. can overlayfs skip lowerdir?
- unionmountopts="-o noatime,lowerdir=${unionro1},upperdir=${unionrw}"
- mount -t ${UNIONTYPE} ${unionmountopts} ${UNIONTYPE} "${unionmountpoint}"
- ;;
-
- *)
- unionmountopts="-o noatime,${noxino_opt},dirs=${unionrw}=${rw_opt}"
- if [ -n "${unionro1}" ]
- then
- unionmountopts="${unionmountopts}:${unionro1}=${ro_opt}"
- fi
- if [ -n "${unionro2}" ]
- then
- unionmountopts="${unionmountopts}:${unionro2}=${ro_opt}"
- fi
- mount -t ${UNIONTYPE} ${unionmountopts} ${UNIONTYPE} "${unionmountpoint}"
- ;;
- esac
-}
-
-get_custom_mounts ()
-{
- # Side-effect: leaves $devices with live-persistence.conf mounted in /live/persistence
- # Side-effect: prints info to file $custom_mounts
-
- local custom_mounts=${1}
- shift
- local devices=${@}
-
- local bindings="/tmp/bindings.list"
- local links="/tmp/links.list"
- rm -rf ${bindings} ${links} 2> /dev/null
-
- for device in ${devices}
- do
- if [ ! -b "${device}" ]
- then
- continue
- fi
-
- local device_name="$(basename ${device})"
- local backing=$(mount_persistence_media ${device})
- if [ -z "${backing}" ]
- then
- continue
- fi
-
- local include_list="${backing}/${persistence_list}"
- if [ ! -r "${include_list}" ]
- then
- continue
- fi
-
- if [ -n "${DEBUG}" ] && [ -e "${include_list}" ]
- then
- cp ${include_list} /live/persistence/${persistence_list}.${device_name}
- fi
-
- while read dir options # < ${include_list}
- do
- if echo ${dir} | grep -qe "^[[:space:]]*\(#.*\)\?$"
- then
- # skipping empty or commented lines
- continue
- fi
-
- if trim_path ${dir} | grep -q -e "^[^/]" -e "^/live\(/.*\)\?$" -e "^/\(.*/\)\?\.\.\?\(/.*\)\?$"
- then
- log_warning_msg "Skipping unsafe custom mount ${dir}: must be an absolute path containing neither the \".\" nor \"..\" special dirs, and cannot be \"/live\" or any sub-directory therein."
- continue
- fi
-
- local opt_source=""
- local opt_link=""
- for opt in $(echo ${options} | tr ',' ' ');
- do
- case "${opt}" in
- source=*)
- opt_source=${opt#source=}
- ;;
- link)
- opt_link="yes"
- ;;
- union|bind)
- ;;
- *)
- log_warning_msg "Skipping custom mount with unkown option: ${opt}"
- continue 2
- ;;
- esac
- done
-
- local source="${dir}"
- if [ -n "${opt_source}" ]
- then
- if echo ${opt_source} | grep -q -e "^/" -e "^\(.*/\)\?\.\.\?\(/.*\)\?$" && [ "${source}" != "." ]
- then
- log_warning_msg "Skipping unsafe custom mount with option source=${opt_source}: must be either \".\" (the media root) or a relative path w.r.t. the media root that contains neither comas, nor the special \".\" and \"..\" path components"
- continue
- else
- source="${opt_source}"
- fi
- fi
-
- local full_source="$(trim_path ${backing}/${source})"
- local full_dest="$(trim_path ${rootmnt}/${dir})"
- if [ -n "${opt_link}" ]
- then
- echo "${device} ${full_source} ${full_dest} ${options}" >> ${links}
- else
- echo "${device} ${full_source} ${full_dest} ${options}" >> ${bindings}
- fi
- done < ${include_list}
- done
-
- # We sort the list according to destination so we're sure that
- # we won't hide a previous mount. We also ignore duplicate
- # destinations in a more or less arbitrary way.
- [ -e "${bindings}" ] && sort -k3 -sbu ${bindings} >> ${custom_mounts} && rm ${bindings}
-
- # After all mounts are considered we add symlinks so they
- # won't be hidden by some mount.
- [ -e "${links}" ] && cat ${links} >> ${custom_mounts} && rm ${links}
-
- # We need to make sure that no two custom mounts have the same sources
- # or are nested; if that is the case, too much weird stuff can happen.
- local prev_source="impossible source" # first iteration must not match
- local 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} |
- while read device source dest options
- do
- if echo ${source} | grep -qe "^${prev_source}\(/.*\)\?$"
- then
- panic "Two persistence mounts have the same or nested sources: ${source} on ${dest}, and ${prev_source} on ${prev_dest}"
- fi
- prev_source=${source}
- prev_dest=${dest}
- done
-}
-
-activate_custom_mounts ()
-{
- local custom_mounts="${1}" # the ouput from get_custom_mounts()
- local used_devices=""
-
- while read device source dest options # < ${custom_mounts}
- do
- local opt_bind="yes"
- local opt_link=""
- local opt_union=""
- for opt in $(echo ${options} | tr ',' ' ');
- do
- case "${opt}" in
- bind)
- opt_bind="yes"
- unset opt_link opt_union
- ;;
- link)
- opt_link="yes"
- unset opt_bind opt_union
- ;;
- union)
- opt_union="yes"
- unset opt_bind opt_link
- ;;
- esac
- done
-
- if [ -n "$(what_is_mounted_on "${dest}")" ]
- then
- if [ "${dest}" = "${rootmnt}" ]
- then
- umount "${dest}"
- else
- log_warning_msg "Skipping custom mount ${dest}: $(what_is_mounted_on "${dest}") is already mounted there"
- continue
- fi
- fi
-
- if [ ! -d "${dest}" ]
- then
- # create the destination and delete existing files in
- # its path that are in the way
- path="/"
- for dir in $(echo ${dest} | sed -e 's|/\+| |g')
- do
- path=$(trim_path ${path}/${dir})
- if [ -f ${path} ]
- then
- rm -f ${path}
- fi
- if [ ! -e ${path} ]
- then
- mkdir -p ${path}
- if echo ${path} | grep -qe "^${rootmnt}/*home/[^/]\+"
- then
- # if ${dest} is in /home try fixing proper ownership by assuming that the intended user is the first, which is usually the case
- # FIXME: this should really be handled by live-config since we don't know for sure which uid a certain user has until then
- chown 1000:1000 ${path}
- fi
- fi
- done
- fi
-
- # if ${source} doesn't exist on our persistence media
- # we bootstrap it with $dest from the live filesystem.
- # this both makes sense and is critical if we're
- # dealing with /etc or other system dir.
- if [ ! -d "${source}" ]
- then
- if [ -n "${PERSISTENCE_READONLY}" ]
- then
- continue
- elif [ -n "${opt_union}" ] || [ -n "${opt_link}" ]
- then
- # unions and don't need to be bootstrapped
- # link dirs can't be bootstrapped in a sensible way
- mkdir -p "${source}"
- chown_ref "${dest}" "${source}"
- chmod_ref "${dest}" "${source}"
- elif [ -n "${opt_bind}" ]
- then
- # ensure that $dest is not copied *into* $source
- mkdir -p "$(dirname ${source})"
- cp -a "${dest}" "${source}"
- fi
- fi
-
- # XXX: If CONFIG_AUFS_ROBR is added to the Debian kernel we can
- # ignore the loop below and set rofs_dest_backing=$dest
- local rofs_dest_backing=""
- if [ -n "${opt_link}"]
- then
- for d in /live/rofs/*
- do
- if [ -n "${rootmnt}" ]
- then
- rofs_dest_backing="${d}/$(echo ${dest} | sed -e "s|${rootmnt}||")"
- else
- rofs_dest_backing="${d}/${dest}"
- fi
- if [ -d "${rofs_dest_backing}" ]
- then
- break
- else
- rofs_dest_backing=""
- fi
- done
- fi
-
- if [ -n "${opt_link}" ] && [ -z "${PERSISTENCE_READONLY}" ]
- then
- link_files ${source} ${dest} ${rootmnt}
- elif [ -n "${opt_link}" ] && [ -n "${PERSISTENCE_READONLY}" ]
- then
- mkdir -p /live/persistence
- local links_source=$(mktemp -d /live/persistence/links-source-XXXXXX)
- chown_ref ${source} ${links_source}
- chmod_ref ${source} ${links_source}
- # We put the cow dir in the below strange place to
- # make it absolutely certain that the link source
- # has its own directory and isn't nested with some
- # other custom mount (if so that mount's files would
- # be linked, causing breakage.
- local cow_dir="/live/overlay/live/persistence/$(basename ${links_source})"
- mkdir -p ${cow_dir}
- chown_ref "${source}" "${cow_dir}"
- chmod_ref "${source}" "${cow_dir}"
- do_union ${links_source} ${cow_dir} ${source} ${rofs_dest_backing}
- link_files ${links_source} ${dest} ${rootmnt}
- elif [ -n "${opt_union}" ] && [ -z "${PERSISTENCE_READONLY}" ]
- then
- do_union ${dest} ${source} ${rofs_dest_backing}
- elif [ -n "${opt_bind}" ] && [ -z "${PERSISTENCE_READONLY}" ]
- then
- mount --bind "${source}" "${dest}"
- elif [ -n "${opt_bind}" -o -n "${opt_union}" ] && [ -n "${PERSISTENCE_READONLY}" ]
- then
- # bind-mount and union mount are handled the same
- # in read-only mode, but note that rofs_dest_backing
- # is non-empty (and necessary) only for unions
- if [ -n "${rootmnt}" ]
- then
- local cow_dir="$(echo ${dest} | sed -e "s|^${rootmnt}|/live/overlay/|")"
- else
- # This is happens if persistence is activated
- # post boot
- local cow_dir="/live/overlay/${dest}"
- fi
- if [ -e "${cow_dir}" ] && [ -z "${opt_link}" ]
- then
- # If an earlier custom mount has files here
- # it will "block" the current mount's files
- # which is undesirable
- rm -rf "${cow_dir}"
- fi
- mkdir -p ${cow_dir}
- chown_ref "${source}" "${cow_dir}"
- chmod_ref "${source}" "${cow_dir}"
- do_union ${dest} ${cow_dir} ${source} ${rofs_dest_backing}
- fi
-
- PERSISTENCE_IS_ON="1"
- export PERSISTENCE_IS_ON
-
- if echo ${used_devices} | grep -qve "^\(.* \)\?${device}\( .*\)\?$"
- then
- used_devices="${used_devices} ${device}"
- fi
- done < ${custom_mounts}
-
- echo ${used_devices}
-}
-
-fix_backwards_compatibility ()
-{
- local device=${1}
- local dir=${2}
- local opt=${3}
-
- if [ -n "${PERSISTENCE_READONLY}" ]
- then
- return
- fi
-
- local backing="$(mount_persistence_media ${device})"
- if [ -z "${backing}" ]
- then
- return
- fi
-
- local include_list="${backing}/${persistence_list}"
- if [ ! -r "${include_list}" ]
- then
- echo "# persistence backwards compatibility:
-${dir} ${opt},source=." > "${include_list}"
- fi
-}
-
-is_mountpoint ()
-{
- directory="$1"
-
- [ $(stat -fc%d:%D "${directory}") != $(stat -fc%d:%D "${directory}/..") ]
-}