#!/bin/bash

#==============================================================================
# LiveCD/USB/HD init script for antiX/MX
#
# (C) 2009-2019 Paul Banham <antiX@operamail.com>
# Inspired by the work of Klaus Knopper
#
# License: GPLv3 or later
#==============================================================================

# SUFFIX NOTE: _MP     absolute mountpoint
#              _NAME   filename with no path
#              _PATH   relative path but no filename
#              _FILE   relative path with filename
#              _FULL   absolute mountpoint and path and filename
#              _DIR    varies
#
# CUSTOMIZATION:
# Customize to your distro using /etc/initrd-release.  Add further
# customization if needed with scripts at /live/custom/$DISTRO/[1-9].sh.
# These scripts are run at the respective breakpoints.  So 1.sh is run
# at breakpoint 1 and so on.  The script 0.sh is run before we read the
# boot parameters.  You can use this to set defaults that can be
# over-ridden by boot parameters.  Use 1.sh to override boot parameters
# that you don't want users to be able to adjust.

                     ME="initrd init"
                VERSION="8.30.14-x14"
           VERSION_DATE="Mon, 27 Feb 2023 07:46:20 -0500"
              DEVELOPER="BitJam"
         BUG_REPORT_URL="liveboot@antixlinux.org"

# These are all times in seconds, not attempts
             BOOT_RETRY=15
           FRUGAL_RETRY=10
          PERSIST_RETRY=10
    FAILSAFE_BOOT_RETRY=30

    DISABLE_SERVICES_OPTS="[aABcdFgkilLmnNPrsSvVwWxY]+"

           RW_MODE="ro"
            PRINTK=0

          LIVE_DIR="/live"
         FINAL_DIR="/run/initramfs"
          LIVE_BIN="/bin"

          AUFS_DIR="aufs"

       EXTRA_FILES="deb xtra xtra.tgz"
 TORAM_ALL_BDIR_FILES="vmlinuz vmlinuz1 initrd.gz"
TORAM_ALL_OTHER_FILES="boot EFI version"

       MIN_SYS_RAM=80
      MIN_AUFS_RAM=80

           LOG_DIR="/var/log/live"
          LOG_FILE="$LOG_DIR/initrd.log"

            MY_LOG=/init.log
           VID_DIR="/etc/live/version"
          VID_FILE="$VID_DIR/linuxfs.ver"
          MAKE_OLD="rootfs xtra deb xtra.tgz linuxfs.md5 state"
           MOD_DIR="/lib/modules/$(uname -r)"

     DEF_FROM_TYPE="usb,cd"
     FROM_TYPE_ALL="usb,cd,hd,mmc"

      FRUGAL_FILES="linuxfs vmlinuz vmlinuz1 initrd.gz xtra xtra.tgz esp-uuid"
      FRUGAL_FILES="$FRUGAL_FILES ../boot ../efi ../EFI ../cdrom.ico ../version"
       FRUGAL_NAME="antiX"
  DEFAULT_BOOT_DIR="antiX"


 ADDITIONAL_FILES="initrd1.gz vmlinuz.ver vmlinuz1.ver"
 ADDITIONAL_FILES="$ADDITIONAL_FILES vmlinuz2 vmlinuz2.ver initrd2.gz"
 ADDITIONAL_FILES="$ADDITIONAL_FILES vmlinuz3 vmlinuz3.ver initrd3.gz"
 ADDITIONAL_FILES="$ADDITIONAL_FILES vmlinuz4 vmlinuz4.ver initrd4.gz"
 ADDITIONAL_FILES="$ADDITIONAL_FILES vmlinuz5 vmlinuz5.ver initrd5.gz"
 ADDITIONAL_FILES="$ADDITIONAL_FILES vmlinuz6 vmlinuz6.ver initrd6.gz"
 ADDITIONAL_FILES="$ADDITIONAL_FILES vmlinuz7 vmlinuz7.ver initrd7.gz"
 ADDITIONAL_FILES="$ADDITIONAL_FILES vmlinuz8 vmlinuz8.ver initrd8.gz"
 ADDITIONAL_FILES="$ADDITIONAL_FILES vmlinuz9 vmlinuz9.ver initrd9.gz"

         FRUGAL_FILES="$FRUGAL_FILES $ADDITIONAL_FILES"
 TORAM_ALL_BDIR_FILES="$TORAM_ALL_BDIR_FILES $ADDITIONAL_FILES"
    
     MAX_MOUNT_CNT=30
       RETRY_DELAY=50               # in hundredths of a second
           VERBOSE=5

       DO_COLDPLUG=true
    COLDPLUG_DELAY=
          USER_UID=1000
          USER_GID=1000

            DO_DEB=true

   PLUG_LOOP_DELAY=50   # In 100ths of a second

        # Note: adding "crc32c-generic" works around a bug in the kernel:
        # https://github.com/manjaro/packages-core/issues/8
        LOAD_FIRST="usb-common usbcore ehci-hcd fusbh200-hcd fotg210-hcd battery aufs overlay crc32c-generic mmc-block dm-crypt"

          VID_NAME=VID
      LINUXFS_NAME=linuxfs
       CRYPT_FNAME=encrypted
   OLD_CRYPT_FNAME=crypt
         LUKS_NAME=liveb

 ENCRYPT_MODE_FILE=/etc/encrypt
   ENCRYPT_DISABLE=disable
      ENCRYPT_BOTH=both
      ENCRYPT_ONLY=enable

      PHRASE_FNAME=passphrase
        SEED_FNAME=random-seed

        BLACK_LIST=
   BLACK_LIST_FILE=/etc/modprobe.d/live-blacklist.conf
KMS_VIDEO_MODULES="amdgpu,analogix-anx78xx,ast,bochs-drm,ch7006,cirrus,gma500_gfx,hibmc-drm,i915,mgag200,nvidia,nouveau,qxl,radeon,tda998x,udl,vboxvideo,virtio-gpu,vkms,vmwgfx"

    DEFAULT_SQFILE=/antiX/linuxfs
  DEFAULT_ISO_FILE=/antiX/antiX.iso

  LIVE_X64_LD_PATH="/lib:/lib/x86_64-linux-gnu:/usr/lib"
  LIVE_386_LD_PATH="/lib:/lib/i386-linux-gnu:/usr/lib"

   MKFS_FREE_MARGIN=10
  rootfs_SIZE_PARAM="min_size=250 mid_size=100 max_size=8192  factor=50"
  homefs_SIZE_PARAM="min_size=10  mid_size=100 max_size=10240 factor=25"
        MKFS_SIZES="5 10 50 100 150 200 250 300 400 500 750 1024 1536 2048 2560 3072 4096
                    5120 6144 8192 10240 12288 14336 16384 18432 20480 25600 30720 35840 40960
                    46080  51200 61440 71680 81920 102400  128000 153600 179200 204800 256000
                    307200 358400 409600 460800 512000"

   MAX_ROOTFS_SIZE="40960"  # 40 GiB
   MIN_ROOTFS_SIZE="100"

        SWAP_SIZES="200 250 300 400 500 750 1024 1536 2048 2560 3072 4096 5120 6144 8192 10240"

      LIVE_SCRIPTS="live-L10n live-init"
      LAST_BP_TIME=0
          NO_PLINK=""
   DEFAULT_UNIONFS="overlay"
   OPTIONS_ENTRIES="toram|from=usb|password|nousb2"

          LAZYTIME=""
      MADE_BY_FILE="made-by-live-usb-maker"
    PROG_BAR_WIDTH=100

  MIN_SCREEN_WIDTH=80
  DEF_SCREEN_WIDTH=120
         CON_WIDTH=120

      DID_EFI_FILE="boot/grub/config/did-efi-grub"
     EFI_GRUB_CONF="boot/grub/config/efi-grub.cfg"
    UEFI_UUID_FILE="antiX/esp-uuid"
         SWAP_FILE="/live/boot-dev/swap-file"
   USB_DIRTY_BYTES=20000000

     LIVE_LOGS_DIR="live-logs"

       TSPLASH_TTY=10
            MY_TTY=1
   VCARD_CONF_FILE="/live/config/vcard-cmd"

         CRYPT_TAB=""

    #           HUP INT QUIT SEGV TERM
    SIGNAL_LIST="1   2   3    11   15"


set_live_dirs() {
    local dir=$1

         FRUGAL_MP="$dir/frugal"
           BOOT_MP="$dir/boot-dev"
           BIOS_MP="$dir/bios-dev"
        ISO_DEV_MP="$dir/iso-dev"
       ISO_FILE_MP="$dir/iso-file"
          TORAM_MP="$dir/to-ram"
       AUFS_RAM_MP="$dir/aufs-ram"
           AUFS_MP="$dir/$AUFS_DIR"
         ROOTFS_MP="$dir/persist-root"
        PERSIST_MP="$dir/persist-dev"
           SQFS_MP="$dir/linux"         # where the linuxfs file gets *mounted*
      WRAP_FILE_MP="$dir/wrapper"
          PLAIN_MP="$dir/plain"
        OUTPUT_DIR="$dir/config"
        LOCALE_DIR="$dir/locale"
        CUSTOM_DIR="$dir/custom"
 DISABLED_USB_FILE="$OUTPUT_DIR/usb-disabled"
}


hbar="======================================================================"
tbar="----------------------------------------------------------------------"
rbar=">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
lbar="<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"


main_wrapper() {
    local black blue green cyan red purple brown lt_gray dk_gray lt_blue
    local lt_green lt_cyan lt_red magenta yellow white rev_red
    local cheat_co cmd_co dev_co err_co from_co to_co head_co
    local hi_co mp_co m_co nc_co num_co ok_co bold_co

    PATH=$LIVE_BIN
    HOME=/
    TERM=linux
    PWD=/

    set_live_dirs $LIVE_DIR
    mkdir -p $OUTPUT_DIR

    trap "" $SIGNAL_LIST

    umask 022

    system_mount
    local time_0=$(cut -d" " -f22 /proc/$$/stat)

    make_nodes /dev

    local initrd_release=/etc/initrd_release
    [ -r $initrd_release ] || initrd_release=/etc/initrd-release

    read_distro_release $initrd_release
    : ${DISTRO_BUG_REPORT_URL:=$BUG_REPORT_URL}
    : ${DISTRO_NAME:=antiX}
    : ${DISTRO_BASE:=$DISTRO_NAME}
    : ${DISTRO_PRETTY_NAME:=antiX-17 (generic)}

    custom_code 0 'before reading boot codes'

    clear_env
    read_cmdline_params
    select_breakpoints

    FREE_MEM=$(mem_info MemFree)

    #[ -z "$NO_MODESET" -a -z "$LOW_COLOR" -a -z "$HIGH_COLOR" ] && NO_COLOR=true
    set_colors "$NO_COLOR" "$LOW_COLOR"

    read_xlat init $LANG
    set_console_width "$CON_WIDTH" "$LANG" 6

    echo "$LANG" > $OUTPUT_DIR/lang
    # Do this after we set the console font/width
    tsplash_start

    # disable console screen blanking
    printf "\e[9;0]\e[14;0]"

    echo "$PRINTK" > /proc/sys/kernel/printk

    # Just in case it didn't get set in set_console_width
    SCREEN_WIDTH=$(stty size 2>/dev/null | cut -d" " -f2)

    [ -z "${FINAL_DIR##/*}" ] || FINAL_DIR="/$FINAL_DIR"
    NEW_ROOT=$AUFS_MP

    if [ "$NO_ERR_LOG" ]; then
        main_core
    else
        # Evaluate redirects RIGHT TO LEFT:
        #
        #  stdout  1 -------.        .---> while, sed, tee ---> screen (stdout)
        #                    \      /
        #  stderr  2 ---.     `--- / -------------------------> screen (stderr)
        #                \        /
        #         17      `------'

        main_core  17>&1  1>&2  2>&17  | while read line; do echo "$line" \
            | sed -e "s/^/${yellow}Error: $red/" -e "s/$/$nc_co/" | tee -a $MY_LOG; done
    fi

    read LAST_BP_TIME < /LAST_BP_TIME

    start_hotplug

    # Nota Bene: when error log is enabled, main_core() runs in a subshell
    # so it cannot affect our variables.

    # Need to run persist-password outside of our error catching

    tsplash_progress  "$_run_live_scripts_"

    breakpoint 8      "before running live init.d scripts"
    breakpoint b8     "Bash shell before running live init.d scripts"

    #ensure symlink exists before running init.d scripts
    if [ "/${FINAL_DIR#/}" != "/live" ]; then
        #remove leftover /live directory
        test -d "$NEW_ROOT/live" && rm -R $NEW_ROOT/live
        #symlink relative /live to FINAL_DIR location after switch_root
        ln -s ${FINAL_DIR#/} $NEW_ROOT/live
    fi

    # I hope this is no longer needed
    # remove_from_runlevel lightdm 3

    # Try running live-usb-save first so it can restore an xorg.conf machine-state file
    # We run live-vcard 2nd, right after live-usb-save
    confile vcard-cmd    && LIVE_SCRIPTS="live-vcard    $LIVE_SCRIPTS"
    confile remasterable && LIVE_SCRIPTS="live-usb-save $LIVE_SCRIPTS"
    confile hwclock      && LIVE_SCRIPTS="$LIVE_SCRIPTS live-hwclock"
    confile persist-root force-passwd && LIVE_SCRIPTS="$LIVE_SCRIPTS persist-password"
    confile save-persist && LIVE_SCRIPTS="$LIVE_SCRIPTS persist-autosave"
    # Do this after the above so the changes aren't saved until after a "real" persist-save
    confile systemd      || LIVE_SCRIPTS="$LIVE_SCRIPTS live-disable-services"
    confile toram-eject  && LIVE_SCRIPTS="$LIVE_SCRIPTS live-toram-eject"
    confile bootsave     && LIVE_SCRIPTS="$LIVE_SCRIPTS live-bootsave"
    confile deb-install  && LIVE_SCRIPTS="$LIVE_SCRIPTS live-deb-install"

    unset CMDLINE
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin
    run_init_scripts $NEW_ROOT $LIVE_SCRIPTS
    PATH=$LIVE_BIN

    decolor_file $NEW_ROOT/var/log/live/live-init.log.color

    test -r /late-umount.sh && . /late-umount.sh
    sync
    prep_seed_dev_random "$SEED_FILE"
    late_umount $PERSIST_DEVICE

    [ -z "$TORAM_STORE" ] && late_umount $SQFILE_DEV

    late_umount $BIOS_DEV

    #tsplash_progress "start init"

    if [ -z "$DISABLE_STORE" ]; then
        if detect_old_persist_scripts $NEW_ROOT; then
            warn  "$_X_disabled_due_to_outdated_persistence_scripts_and_libs_" "$(pqw Live-usb-storage)"
        else
            confile remasterable && run_init_scripts $NEW_ROOT live-usb-storage

            local dir new_dir
            for dir in config bin; do
                local new_dir=$NEW_ROOT/etc/live/$dir
                mkdir -p $new_dir
                mount --bind /live/aufs/live/$dir $new_dir
            done

            # Leave ext2/3/4 as read-write
            echo "BOOT_MP is " "$BOOT_MP"
            case $(mntpnt_fstype $NEW_ROOT$FINAL_DIR/boot-dev) in
                ext[234]|iso9660) ;;
                   btrfs|xfs|jfs) ;;
                               *) chmod 755 $NEW_ROOT$FINAL_DIR ;;
            esac
        fi
    fi

    local f rm_list
    for f in $NEW_ROOT/live/menus/*; do
        case $f in *tz.*) continue;; esac
        rm_list="$rm_list $f"
    done
    rm -f $rm_list

    if [ -e $BLACK_LIST_FILE ]; then
        local modprobe_d=$NEW_ROOT/etc/modprobe.d
        mkdir -p $modprobe_d
        cp $BLACK_LIST_FILE $modprobe_d
    fi

    dmesg > $NEW_ROOT$FINAL_DIR/config/dmesg.out

    [ "$DO_TSPLASH" ] && openvt -w -c $TSPLASH_TTY /live/bin/tsplash progress  "$_start_init_"

    breakpoint 9     "right before starting init"

    stop_hotplug

    local time_1=$(get_time)
    local dt=$((time_1 - time_0))
    vmsg 6
    vmsg 5  "$_The_X_program_took_Y_seconds_" "$ME" $(nq $(get_seconds $dt))
    vmsg 6 $hbar

    #tsplash_progress init

    tsplash_copy_config $NEW_ROOT

    write_log_files $MY_LOG $NEW_ROOT/$LOG_FILE
    MY_LOG=$NEW_ROOT/$LOG_FILE.color
    [ "$NO_SAVE_LOGS" ] || copy_live_logs "$NEW_ROOT" "$LOG_DIR"

    breakpoint b9    "Bash shell right before starting init"

    #free -m >> $MY_LOG
    echo 3 > /proc/sys/vm/drop_caches
    vmsg 6 'drop caches'
    #free -m >> $MY_LOG

    if  ! confile init-prog && find_init_prog INIT_PROG $NEW_ROOT; then

        vmsg 4 'Run %s instead of %s' $white$INIT_PROG$m_co $white/sbin/init$m_co
        vmsg 5 "${hi_co}%s" 'Please exit shells normally to allow for a clean unmount'

        CHROOT_BIN=$FINAL_DIR/bin
        $SET_ARCH chroot $NEW_ROOT $CHROOT_BIN/setsid $CHROOT_BIN/cttyhack $INIT_PROG
        #breakpoint i "after init= chroot"

        MY_LOG=/dev/null
        safe_shutdown poweroff ask

    else
        : ${INIT_COMMAND:=${INIT_PROG:=/sbin/init}}
        breakpoint i "befor switch root"
        vmsg 6  "Start %s process" $(pq $INIT_COMMAND)

        # Note that "nomodeset" is yet again unreliable!
        # [ "$NO_CLEAR" ] || [ "$NO_MODESET" ] || clear
        [ "$NO_CLEAR" ] || clear
        #exec $LIVE_BIN/switch_root -c /dev/tty1 $NEW_ROOT $INIT_COMMAND "$@"
        exec $LIVE_BIN/switch_root $NEW_ROOT /usr/bin/env CONSOLE=/dev/tty1 $INIT_COMMAND "$@"
    fi
}

#------------------------------------------------------------------------------
# Any stderr in this code is colored red on the screen and in the log file
#------------------------------------------------------------------------------
main_core() {
    [ "$NO_CLEAR" ] || clear       # Clear and reset screen
    vmsg 6 "=== initrd bootstrap =================================================="

    vmsg 6 '%s started at %s seconds' "$ME" $(nq $(get_seconds $time_0))

    mkdir -p $MOD_DIR
    depmod &>/dev/null
    blacklist_modules "$BLACK_LIST" "$BLACK_LIST_FILE"

    breakpoint 1 "before welcome"

    [ "$TSPLASH_ERROR" ] && non_fatal  "$_The_X_feature_requires_the_Y_boot_parameter_" 'tsplash' 'console=tty1'

    # These ones must be loaded before the others
    # Add a cheap black-lister
    if [ ${#BLACK_LIST} -gt 0 ]; then
        local bl_regex=${BLACK_LIST#,}
        bl_regex=${bl_regex%,}
        bl_regex=${bl_regex//,/|}
        echo $LOAD_FIRST | tr " " "\n" | egrep -v "^($bl_regex)$" | xargs modprobe -q -a 2>/dev/null
    else
        echo $LOAD_FIRST | xargs modprobe -q -a 2>/dev/null
    fi

    start_hotplug

    do_welcome "$DISTRO_PRETTY_NAME" "$VERSION" "$VERSION_DATE"
    show_bootcodes "$(live_param_filter $UNKNOWN_BOOTCODES)"
    show_integer_errors "$INTEGER_ERRORS"
    show_disable_errors "$DISABLE_SERVICES" "$DS_PARAM"

    breakpoint 2 "before coldplug"

    check_unionfs
    coldplug_delay
    coldplug_modules

    # local orig_fb_name
    # read orig_fb_name 2>/dev/null </sys/class/graphics/fb0/name
    load_kernel_modules "$MODULE_LIST"
    # set_fbcondecor "$SPLASH_PARAM" "$orig_fb_name"

    initialize_cmdline2

    local p
    PROC_CMDLINE=$(for p in $(cat /proc/cmdline 2>/dev/null); do echo $p; done)

    [ "$DO_MENUS" ] && do_early_menus

    read_late_cmdline_params "$PROC_CMDLINE $(cat /live/config/cmdline)"
    echo "$PROC_CMDLINE" > /live/config/proc-cmdline

    clean_xlat

    : ${SQFILE_FILE:=$DEFAULT_SQFILE}
    : ${SQFILE_NAME:=${SQFILE_FILE##*/}}

    [ -z "${SQFILE_FILE##*/*}" ] && : ${BOOT_DIR:=${SQFILE_FILE%/*}}

    [ "$SQFILE_EXT" ] && SQFILE_NAME="$SQFILE_NAME.$SQFILE_EXT"
    SQFILE_FILE="$BOOT_DIR/$SQFILE_NAME"
    SQFILE_FILE=${SQFILE_FILE#/}

    # Wait and only do this in the find_files() loop so the usb report
    # will always work
    #[ "$NO_EHCI" ] && disable_hcd ehci

    #[ "$SET_CRYPT" -a -z "$NO_CRYPT" ] && setup_crypt "$CRYPT_ID" "$BOOT_DIR/$CRYPT_FNAME" "$BOOT_MP"

    tsplash_progress  "$_search_for_boot_device_"
    breakpoint 3 "before looking for linuxfs file"

    RW_MODE=ro

    if [ "$FRUGAL_ID" ]; then
        find_frugal_file "$FRUGAL_ID" || frugal_error $?

        # This is not perfect but we don't want to flash back and forth quickly
        # if we do a frugal install with persistence
        [ -z "$PERSIST" ] || tsplash_on
    else
        find_linuxfs_file
    fi

    mount -o remount,rw $BOOT_MP &>/dev/null
    dir_has_param "$BOOT_MP" rw && REMASTERABLE=true
    [ "$DID_ISO" ] && REMASTERABLE=

    BOOT_FSTYPE=$(mntpnt_fstype $BOOT_MP)
    case $BOOT_FSTYPE in
        iso9660|udf) REMASTERABLE= ;;
    esac

    BOOT_UUID=$(device_uuid $SQFILE_DEV)
    [ "$BOOT_UUID" ] && vmsg 6 "boot device uuid: $BOOT_UUID"

    vmsg 7 "BOOT_MP:    $BOOT_MP"
    vmsg 7 "SQFILE_DEV: $SQFILE_DEV"
    vmsg 7 "SQFILE_MP   $SQFILE_MP"

    SEED_FULL=$(dirname "$SQFILE_FULL")/$SEED_FNAME
    seed_dev_random "$SEED_FULL"

    tsplash_progress  "$_found_boot_device_"

    breakpoint 4 "after mounting boot device"
    mount -o remount,rw $SQFILE_DEV 2>/dev/null
    dir_has_param "$SQFILE_MP" rw || REMASTERABLE=

    detect_vga_menu "$CMD_VGA" "$GFX_SAVE"
    tsplash_on

    if remasterable; then
        do_remaster "$SQFILE_FULL"
        prep_seed_dev_random "$SEED_FULL"
        echo "$SEED_FILE" > /live/config/seed-file
    fi

    mount_linuxfs "$SQFS_MP" "$SQFILE_FULL" "$WRAP_FILE_MP"

    fix_old_lum "$BOOT_MP" "${BIOS_UUID:-$BOOT_UUID}"

    if [ "$LOAD_ALL_MODULES" ]; then
        debug_cmd find /sys/devices -name uevent -exec sed -n 's/^MODALIAS=//p' '{}' + 2>/dev/null | sort -u
        debug_cmd lsmod
    fi

    prep_ld_path

    RW_MODE=rw
    # FIXME: this makes debugging persist_makefs simpler
    #[ "$PERSIST_FILES" ] && mount -o remount,rw $SQFILE_DEV
    mount -o remount,rw $SQFILE_DEV

    #breakpoint 4 "after mounting linuxfs file"

    prepare_persistence

    mount_persist_device "$PERSIST_FILES" "$FROM_PERSIST"

    # Check for ehci warning
    dmesg | grep 'Warning.*ehci' >&2


    if [ -n "$MADE_PERSIST_FILE" -a ! -e $SWAP_FILE ]; then
        # FIXME check free space
        YES_no  "$_Create_a_live_usb_swap_file_" && : ${SWAP_FILE_SIZE:=choose}
    fi

    make_swap_file "$SWAP_FILE"  "$SWAP_FILE_SIZE"

    tsplash_on
    list_modules

    breakpoint 5 "after mounting persistence device"

    fsck_any_device "$SQFILE_DEV" "$SQFILE_MP" boot
    fsck_any_device "$BIOS_DEV"   "$BIOS_MP"   bios

    ORIG_SQFILE_MP=$SQFILE_MP
    ORIG_SQFILE_DIR=$SQFILE_PATH
    ORIG_SQFILE_FULL=$ORIG_SQFILE_DIR/$SQFILE_NAME

    test -d $SQFILE_MP/$SQFILE_PATH/deb || DO_DEB=

    # Check md5 of files in directory containing linuxfs file
    # 'fromiso' causes us to check md5sums in two places
    if [ "$CHECK_MD5" ]; then
        check_md5 $SQFILE_DIR
        [ "$ENCRYPTED" ] && check_md5 $BIOS_MP/$(dirname $SQFILE_FILE)
    fi

    [ "$TO_RAM" ] && copy_to_ram "$SQFILE_FULL" $TORAM_MP

    check_kernel_version $SQFS_MP

    mount -o remount,rw $SQFILE_DEV 2>/dev/null
    fsck_persist_dev "$PERSIST_FILES" "$PERSIST_DEVICE" "$PERSIST_MP"

    [ "$WANT_ROOTFS" ] && remaster_rootfs "$PERSIST_MP" "$PERSIST_FULL_PATH"

    mount_aufs_ram "$AUFS_RAM_MP" "$MIN_AUFS_RAM" "$FREE_MEM"

    mount_and_copy_rootfs

    [ "$STATIC_ROOT" ] && log_cmd umount $AUFS_RAM_MP

    mount_unionfs "$AUFS_MP" "$SQFS_MP" "$AUFS_RAM_MP" "$ROOTFS_MP"

    breakpoint 6 "after mounting aufs"

    # SYSTEM_D=
    local init_cmd=${INIT_PROG:=/sbin/init}
    [ -h $NEW_ROOT/${init_cmd} ] && init_cmd=$(chroot $NEW_ROOT readlink -f "${init_cmd}")
    if [ -x "$NEW_ROOT/${init_cmd#/}" ] && [ -n "${init_cmd##*/}" ]; then
        case "${init_cmd##*/}" in
            init|init*|*init|runit*|*runit|s6-66*|*s6-66|s6-rc*|*s6-rc|openrc*|*openrc|*systemd)
            echo  ${init_cmd} > /live/config/init-prog
            ;;
        esac
        [ -z "${init_cmd##*/init}"   ] || msg  "$_Detected_X_init_system_" $(cq "${init_cmd##*/}")
        [ -z "${init_cmd##*systemd}" ] && touch /live/config/systemd
    fi

    load_microcode

    [ "$WANT_HOMEFS" ] \
        && mount_homefs $PERSIST_FULL_PATH/homefs $NEW_ROOT/home "$WANT_HOMEFS" "$NEED_HOMEFS"

    tsplash_on

    [ "$DO_XTRA"       ] && copy_xtra    $DEFAULT_DIR
    [ "$DO_XTRA"       ] && delete_files $DEFAULT_DIR
    [ "$DO_AUTO_LOGIN" ] && auto_login   "$AUTO_LOGIN_PROG" "$AUTO_LOGIN_TERMS" "$NEW_ROOT"
    [ "$DO_FANCY"      ] && fancy_prompt "$FANCY_PROMPT" "$NEW_ROOT"
    [ "$DB_PLUS"       ] && page_updown_keys "$NEW_ROOT"
    [ "$TTY1_OFF"      ] && disable_tty1 "$NEW_ROOT"

    # FIXME: do this after copy_xtra for easy testing (for now) (????)
    PROC_CMDLINE=$(cat /live/config/proc-cmdline)

    prep_vcard $VCARD_CMD

    [ "$DO_MENUS" ] && do_late_menus
    echo "$PROC_CMDLINE" > /live/config/proc-cmdline

    # In case it got turned off while doing menus
    tsplash_on

    write_output_files $OUTPUT_DIR
    update_store_file "$NO_STORE" "$DO_STORE"

    #ensure certain direcotries exist, including FINAL_DIR
    mkdir -p $NEW_ROOT/etc/live $NEW_ROOT$FINAL_DIR

    echo $FINAL_DIR > $NEW_ROOT/etc/live/live-dir

    # FIXME: since we are using the real persist-save we can do these either
    # before or after we run the init scripts!  But we lose some of the variables
    # when not run inside of main_core().

    #sync
    #late_umount $PERSIST_DEVICE
    #late_umount $SQFILE_DEV

    stop_hotplug

    breakpoint 7 "before prepare switch_root"

    prepare_switch_root $NEW_ROOT $LIVE_DIR $FINAL_DIR

    breakpoint 7 "after prepare switch_root"

    write_ntfs_pids $FINAL_DIR/aufs/run/sendsigs.omit.d/initrd-ntfs-3g

    echo $LAST_BP_TIME > /LAST_BP_TIME

    cat<<Late_Umount > late-umount.sh
PERSIST_DEVICE="$PERSIST_DEVICE"
SQFILE_DEV="$SQFILE_DEV"
HOMEFS_DEV="$HOMEFS_DEV"
ROOTFS_DEV="$ROOTFS_DEV"
LINUXFS_DEV="$LINUXFS_DEV"
BIOS_DEV="$BIOS_DEV"
CRYPT_DEV="$CRYPT_DEV"
SEED_FILE="$SEED_FILE"
TORAM_STORE="$TORAM_STORE"
Late_Umount
}

#------------------------------------------------------------------------------
# Getting started
#------------------------------------------------------------------------------

system_mount() {
    dir=$1

    mkdir -p $dir/proc $dir/sys $dir/dev

    mount -t proc   proc  $dir/proc
    mount -t sysfs  sys   $dir/sys

    mount -t devtmpfs devtmpfs $dir/dev
    mkdir -p $dir/dev/pts
    mount -t devpts devpts $dir/dev/pts
}

#------------------------------------------------------------------------------
# Make the barest devs we need to get started.  FIXME?  This may no longer
# be needed.
#------------------------------------------------------------------------------
make_nodes() {
    local dir=$1
    mkdir -p $dir

    [ -e $dir/console ] || mknod $dir/console c 5 1
    [ -e $dir/null    ] || mknod $dir/null    c 1 3
    [ -e $dir/tty0    ] || mknod $dir/tty0    c 4 0
}

#------------------------------------------------------------------------------
# For every VAR="value"  in the file make a DISTRO_VAR variable that contains
# that value
#
# additonally set DISTRO_BASE (either antiX or MX)
#------------------------------------------------------------------------------
read_distro_release() {
    local file=$1
    #sed -r -n 's/^\s*([A-Z0-9_]+=)/DISTRO_\1/p' $file >> $MY_LOG
    eval $(sed -r -n 's/^\s*([A-Z0-9_]+=)/DISTRO_\1/p' $file)

    if [ -z "$DISTRO_BASE" -a -n "$DISTRO_NAME" ] ; then
       [ -z "${DISTRO_NAME##*antiX*}" ] && DISTRO_BASE="antiX"
       [ -z "${DISTRO_NAME##*MX*}"    ] && DISTRO_BASE="MX"
    fi
    [ -z "$DISTRO_BASE" ] && DISTRO_BASE="$DISTRO_NAME"

}

#------------------------------------------------------------------------------
# Clear out all extraneous environment variables
#------------------------------------------------------------------------------
clear_env() {
    local ev
    # unset almost all env variables
    for ev in $(printenv | sed 's/=.*//'); do
        case $ev in
            HOME|PATH|PWD|TERM) continue;;
        esac
        unset $ev
    done
}

#------------------------------------------------------------------------------
# We do this late so the text menus can over-ride boot parameters
#------------------------------------------------------------------------------
read_late_cmdline_params() {
    #vmsg 6 "read_late_cmdline_params: $*"
    local param value cmdline=${1:-$(cat /proc/cmdline)}

    for param in $cmdline; do
        value=${param#*=}

        case $param in
                         frugal) set_frugal                           ;;
                       frugal=*) set_frugal $value                    ;;
                hwclock=*|hwc=*) DO_HWCLOCK=true                      ;;
                         from=*) FROM_BOOT=$value ; BOOT_FILTER=true  ;;
                  persist=*|p=*) PERSIST=$PERSIST,$value              ;;
                        persist) PERSIST=$PERSIST,root,home           ;;
                         lang=*) LANG=$value                          ;;
                   md5|checkmd5) CHECK_MD5=true                       ;;
                        checkfs) FORCE_FSCK=true                      ;;

                          bluks) BOOT_ID=fstype=crypto_LUKS    ; BLUKS_ASK=true                          ;;
                         bluks1) BOOT_ID=fstype=crypto_LUKS                                              ;;
                        bluks=*) BOOT_ID=fstype=crypto_LUKS    ; BLUKS_ASK=true  ;  FROM_BOOT=$value     ;;
                       bluks1=*) BOOT_ID=fstype=crypto_LUKS                      ;  FROM_BOOT=$value     ;;

                          fluks) FRUGAL_ID=fstype=crypto_LUKS  ; FLUKS_ASK=true                          ;;
                         fluks1) FRUGAL_ID=fstype=crypto_LUKS                                            ;;
                        fluks=*) FRUGAL_ID=fstype=crypto_LUKS  ; FLUKS_ASK=true  ;  FROM_FRUGAL=$value   ;;
                       fluks1=*) FRUGAL_ID=fstype=crypto_LUKS                    ;  FROM_FRUGAL=$value   ;;

                          pluks) PERSIST_ID=fstype=crypto_LUKS ; PLUKS_ASK=true                          ;;
                         pluks1) PERSIST_ID=fstype=crypto_LUKS                                           ;;
                        pluks=*) PERSIST_ID=fstype=crypto_LUKS ; PLUKS_ASK=true  ;  FROM_PERSIST=$value  ;;
                       pluks1=*) PERSIST_ID=fstype=crypto_LUKS                   ;  FROM_PERSIST=$value  ;;

                      fstype=*) BOOT_ID=fstype=$value                 ;;

                  nousb2|noehci) NO_EHCI=true                         ;;
              private|private=*) FORCE_PASSWD=true                    ;;
                          toram) TO_RAM=true ; TORAM_ALL=true         ;;
                      toram=min) TO_RAM=true                          ;;
                    toram=store) TO_RAM=true ; TORAM_STORE=true       ;;

        # Convenience short cuts from our menus
                    persist_all) PERSIST='root!,home!'                ;;
                   persist_root) PERSIST='root!'                      ;;
                 persist_static) PERSIST='root!,home!,static'         ;;
            persist_static_root) PERSIST='root!,static'               ;;
                  p_static_root) PERSIST='root!,static'               ;;
                   persist_home) PERSIST='home!'                      ;;

                 frugal_persist) set_frugal 'root!,home!'             ;;
                    frugal_root) set_frugal 'root!'                   ;;
                  frugal_static) set_frugal 'root!,home!,static'      ;;
             frugal_static_root) set_frugal 'root!,static'            ;;
                  f_static_root) set_frugal 'root!,static'            ;;
                    frugal_home) set_frugal 'home!'                   ;;
                    frugal_only) set_frugal                           ;;

                        nostore) NO_STORE=true                        ;;
                        dostore) DO_STORE=true                        ;;

                   mk_swap_file) SWAP_FILE_SIZE=choose                ;;
                 mk_swap_file=*) SWAP_FILE_SIZE=$value                ;;
        esac
    done
}

#------------------------------------------------------------------------------
#  A convenience routine to process frugal= boot params
#------------------------------------------------------------------------------
set_frugal() {
    : ${FRUGAL_ID:=label=$FRUGAL_NAME-Frugal}
    [ "$NO_LABEL_FRUGAL" ] || LABEL_FRUGAL=true
    PERSIST=$1
}

#------------------------------------------------------------------------------
# Function read_cmdline_params
#
# Gather all boot codes
#------------------------------------------------------------------------------
read_cmdline_params()
{
    local param value cmdline=${1:-$(cat /proc/cmdline)}

    for param in $cmdline; do
        value=${param#*=}

        case $param in
                           aufs) WANT_UNIONFS=aufs                               ;;
                      overlayfs) WANT_UNIONFS=overlay                            ;;
                          menus) DO_MENUS=${MENUS_LIST:-cltopfsv}                ;;
                        menus=*) DO_MENUS=$DO_MENUS$value                        ;;
             vcard=on|vcard=off) VCARD_CMD=$value                                ;;
         vcard=menu|vcard=clear) VCARD_CMD=$value                                ;;
            rootdelay=*|delay=*) small_int COLDPLUG_DELAY $param                 ;;
                         splash) SPLASH_PARAM=v                                  ;;
                       splash=*) SPLASH_PARAM=$value                             ;;
                        splasht) DO_TSPLASH=Z                                    ;;
                      splasht=*) DO_TSPLASH=$value                               ;;
                      console=*) CMD_MY_TTY=${value#tty}                         ;;
                        tty1off) TTY1_OFF=true                                   ;;
                      CONSOLE=*) CMD_MY_TTY=${value#tty}                         ;;
                       poweroff) poweroff -f -n                                  ;;
                         reboot) reboot -f -n                                    ;;
                         fdir=*) FRUGAL_DIR=$value                               ;;
               bootdir=*|bdir=*) BOOT_DIR=$value                                 ;;
    bootlabel=*|blabel=*|blab=*) BOOT_ID=label=$value                            ;;
             bootuuid=*|buuid=*) BOOT_ID=uuid=$value                             ;;
               bootdev=*|bdev=*) BOOT_ID=name=$value                             ;;

                  try=*|retry=*) small_int CMD_RETRY $param                      ;;

            persistdir=*|pdir=*) PERSIST_PATH=${value#/}                         ;;

 persistlabel=*|plabel=*|plab=*) PERSIST_ID=label=$value  ;  SET_PERSIST=true    ;;
          persistuuid=*|puuid=*) PERSIST_ID=uuid=$value   ;  SET_PERSIST=true    ;;
            persistdev=*|pdev=*) PERSIST_ID=name=$value   ;  SET_PERSIST=true    ;;

                     passphrase) CHANGE_PASSPHRASE=true                          ;;
                        nocrypt) ENCRYPT_MODE=$ENCRYPT_DISABLE                   ;;
                      encrypt=*) ENCRYPT_MODE=$value                             ;;
                        encrypt) ENCRYPT_MODE=$ENCRYPT_ONLY                      ;;
                    encrypt=off) ENCRYPT_MODE=$ENCRYPT_DISABLE                   ;;
                     encrypt=on) ENCRYPT_MODE=$ENCRYPT_ONLY                      ;;

                         btry=*) small_int CMD_BOOT_RETRY $param                 ;;
                         ftry=*) small_int CMD_FRUGAL_RETRY $param               ;;
                         ptry=*) small_int CMD_PERSIST_RETRY $param              ;;

                        fneed=*) FRUGAL_NEEDED=$value                            ;;
                         fforce) FORCE_FRUGAL=true                               ;;
                         flab=*) FRUGAL_ID=label=$value ; NO_LABEL_FRUGAL=true   ;;
                         fdev=*) FRUGAL_ID=name=$value  ; NO_LABEL_FRUGAL=true   ;;
                        fuuid=*) FRUGAL_ID=uuid=$value  ; NO_LABEL_FRUGAL=true   ;;

                iso=*|fromiso=*) ISO_FILE=${value/#}                             ;;
                    iso|fromiso) FROM_ISO=true                                   ;;

                        sqext=*) SQFILE_EXT=$value                               ;;
                       sqname=*) SQFILE_NAME=${value#/}                          ;;
                           sq=*) SQFILE_FILE=$value                              ;;

           verbose=*|verb=*|v=*) small_int VERBOSE $param                        ;;
                           bp=*) BREAK_POINTS=$BREAK_POINTS,$value               ;;
                           pk=*) PRINTK=$value                                   ;;

                 hico|highcolor) HI_COLOR=true                                   ;;
                  loco|lowcolor) LOW_COLOR=true                                  ;;
                   noco|nocolor) NO_COLOR=true                                   ;;

                         noxtra) DO_XTRA=                                        ;;
                         doxtra) DO_XTRA=true                                    ;;

                       fdb+|db+) DO_AUTO_LOGIN=true; DO_FANCY=true; DB_PLUS=true ;;
                           db++)                                                 ;;

            fancyprompt|fprompt) DO_FANCY=true                                   ;;
               autologin|alogin) DO_AUTO_LOGIN=true                              ;;

                          nodeb) DO_DEB=                                         ;;
                    #toram-eject) TO_RAM=true ; TO_RAM_EJECT=true                 ;;

                     noremaster) NO_REMASTER=true                                ;;
                       rollback) ROLLBACK=true                                   ;;
                         lang=*) LANG=$value                                     ;;

                        noclear) NO_CLEAR=true                                   ;;

                      gfxsave=*) GFX_SAVE=$value ; BOOT_SAVE=true                ;;
                   save|gfxsave) GFX_SAVE=both   ; BOOT_SAVE=true                ;;
                       bootsave) BOOT_SAVE=true                                  ;;
                       grubsave) BOOT_SAVE=true                                  ;;
                          vga=*) CMD_VGA=$value                                  ;;

                      nocheckfs) DO_FSCK=                                        ;;

                       failsafe) MODULE_LIST=all
                                 BLACK_LIST=$BLACK_LIST,VIDEO
                                 BOOT_RETRY=$FAILSAFE_BOOT_RETRY
                                 FROM_BOOT=all                                   ;;

                         load=*) MODULE_LIST=$MODULE_LIST,$value                 ;;
               bl=*|blacklist=*) BLACK_LIST=$BLACK_LIST,$value                   ;;

                     nocoldplug) DO_COLDPLUG=                                    ;;
                      nohotplug) FORCE_COLDPLUG_LOOP=true                        ;;
                      traceload) TRACE_LOAD=true                                 ;;
                 autoload|aload) FULL_AUTOLOAD=true                              ;;

                         init=*) INIT_PROG=$value ; export INIT_PROG         ;;

                       noerrlog) NO_ERR_LOG=true                                 ;;
                        noerr=*) NO_ERROR=$value                                 ;;

                      # Not used here see live-init
                      vtblank=*) small_int VT_BLANK $param                       ;;

               livedir=*|ldir=*) FINAL_DIR=$value                                ;;
    pw|password|pw=*|password=*) FORCE_PASSWD=true                               ;;
                      bootchart) INIT_COMMAND=/sbin/bootchartd ; BOOT_CHART=true ;;
                        noplink) NO_PLINK=,noplink                               ;;
                          plink) NO_PLINK=                                       ;;

                       fatuid=*) any_int USER_UID $param                         ;;
                       fatgid=*) any_int USER_GID $param                         ;;

             disable=*|nosysv=*) DISABLE_SERVICES="$DISABLE_SERVICES$value" ; DS_PARAM=$param  ;;

                   disablestore) DISABLE_STORE=true                              ;;
                         nolazy) LAZYTIME=                                       ;;
                       lazytime) LAZYTIME=,lazytime                              ;;

                          issue) FORCE_ISSUE=true                                ;;

                         noprog) NO_PROGRESS=true                                ;;

                     #confont=*) CON_FONT=$value                                 ;;
                     conwidth=*) CON_WIDTH=$value                                ;;
                      nomodeset) NO_MODESET=true                                 ;;
            noumount|noumnt|noU) NO_UMOUNT=true                                  ;;
                          [1-6]) RUN_LEVEL=$val                                  ;;
                     nosavelogs) NO_SAVE_LOGS=true                               ;;
                       notmptmp) $NO_TMP_TMP=true                                ;;

        #----- These get interpreted late but we don't want them to be unknown
                hwclock=*|hwc=*)  ;;
                         frugal)  ;;
                       frugal=*)  ;;
                         from=*)  ;;
                  persist=*|p=*)  ;;
                        persist)  ;;
                         lang=*)  ;;
                   md5|checkmd5)  ;;
                        checkfs)  ;;
                  nousb2|noehci)  ;;
              private|private=*)  ;;
                          toram)  ;;
                        toram=*)  ;;
                      toram_all)  ;;

                          bluks)  ;;
                         bluks1)  ;;
                        bluks=*)  ;;
                       bluks1=*)  ;;

                          fluks)  ;;
                         fluks1)  ;;
                        fluks=*)  ;;
                       fluks1=*)  ;;

                          pluks)  ;;
                         pluks1)  ;;
                        pluks=*)  ;;
                       pluks1=*)  ;;

                       fstype=*)  ;;

                   mk_swap_file)  ;;
                 mk_swap_file=*)  ;;

        # Convenience short cuts from our menus
                    persist_all)  ;;
                   persist_root)  ;;
                 persist_static)  ;;
            persist_static_root)  ;;
                  p_static_root)  ;;
                   persist_home)  ;;
                 frugal_persist)  ;;
                    frugal_root)  ;;
                  frugal_static)  ;;
             frugal_static_root)  ;;
                  f_static_root)  ;;
                    frugal_home)  ;;
                    frugal_only)  ;;
                        nostore)  ;;
                        dostore)  ;;

                    i915_invert)  ;;
                 no_i915_invert)  ;;

                         nuke=*)  ;;
                         nonuke)  ;;

        #----- Some known codes -------------------------

        [sS1-6]|BOOT_IMAGE=*);;

        #------------------------------------------------------------------------
        # NOTE: see /live/custom/$DISTRO_NAME/0.sh for distro specific boot codes
        # and a massive list of known kernel and module parameters
        #------------------------------------------------------------------------

        *) UNKNOWN_BOOTCODES="$UNKNOWN_BOOTCODES $param"
        esac
    done

       BOOT_RETRY=${CMD_RETRY:-$BOOT_RETRY}
     FRUGAL_RETRY=${CMD_RETRY:-$FRUGAL_RETRY}
    PERSIST_RETRY=${CMD_RETRY:-$PERSIST_RETRY}

       BOOT_RETRY=${CMD_BOOT_RETRY:-$BOOT_RETRY}
     FRUGAL_RETRY=${CMD_FRUGAL_RETRY:-$FRUGAL_RETRY}
    PERSIST_RETRY=${CMD_PERSIST_RETRY:-$PERSIST_RETRY}

    MY_TTY=${CMD_MY_TTY:-$MY_TTY}

    if [ "$DISABLE_STORE" ]; then
        USER_UID=0
        USER_GID=0
    fi

    case $CMD_VGA in
        ask+save) GFX_SAVE=both ; BOOT_SAVE=true ;;
    esac
}

#------------------------------------------------------------------------------
# Make sure in input value is an integer between 0 and 99
#------------------------------------------------------------------------------
small_int() {
    local var=$1 val=${2#*=} name=${2%%=*} param=$2

    case $val in
                      "")                   return ;;
        [0-9]|[0-9][0-9]) eval $var=\$val;  return ;;

    esac
    INTEGER_ERRORS="$INTEGER_ERRORS $param"
}

#------------------------------------------------------------------------------
# Make sure an input value is an integer
#------------------------------------------------------------------------------
any_int() {
    local var=$1 val=${2#*=} name=${2%%=*} param=$2

    if echo $val | egrep -q "^[0-9]+$"; then
        eval $var=\$val
        return
    fi
    INTEGER_ERRORS="$INTEGER_ERRORS $param"
}

coldplug_delay() {
    [ "$COLDPLUG_DELAY" ] || return
    msg  "$_Waiting_X_seconds_for_buses_to_settle_"  $(nq $COLDPLUG_DELAY)
    sleep $COLDPLUG_DELAY
}

#------------------------------------------------------------------------------
# Run a loop in the background that is constantly "cold-plugging" i.e. scanning
# /sys/ for alias devices and loading the modules associated with them.
#------------------------------------------------------------------------------
start_coldplug_loop() {
    coldplug-loop $PLUG_LOOP_DELAY &>/dev/null 17>/dev/null &
    COLDPLUG_LOOP_PID=$!
    vmsg 6 'Coldplug loop pid: %s' $(nq $COLDPLUG_LOOP_PID)
    echo $COLDPLUG_LOOP_PID > /COLDPLUG_LOOP_PID
}

#------------------------------------------------------------------------------
# This is much more efficient than the cold-plug loop but it seems to be less
# than 100% reliable.
#------------------------------------------------------------------------------
start_hotplug() {
    local trace_load=$1  targ=/proc/sys/kernel/hotplug

    # Set up file for recording sequence of kernel events sent to mdev
    echo > /dev/mdev.seq

    if [ ! -e $targ -o -n "$FORCE_COLDPLUG_LOOP" ]; then
        start_coldplug_loop
        return
    fi

    if [ "$trace_load" ]; then
        echo $LIVE_BIN/mdev-trace   | tee $targ &>/dev/null
    else
        echo $LIVE_BIN/mdev-hotplug | tee $targ &>/dev/null
    fi
}

#------------------------------------------------------------------------------
# Stop hotplugging.
#------------------------------------------------------------------------------
stop_hotplug() {
    local targ=/proc/sys/kernel/hotplug
    test -e $targ && echo | tee $targ &>/dev/null

    test -r /COLDPLUG_LOOP_PID || return
    read COLDPLUG_LOOP_PID < /COLDPLUG_LOOP_PID
    vmsg 6 'kill coldplug loop pid: %s' $(nq $COLDPLUG_LOOP_PID)
    rm /COLDPLUG_LOOP_PID
    kill -9 $COLDPLUG_LOOP_PID
}

#------------------------------------------------------------------------------
# No longer useed
#------------------------------------------------------------------------------
old_stop_hotplug() {
    local targ=/proc/sys/kernel/hotplug
    test -e $targ && echo | tee $targ &>/dev/null
}

#------------------------------------------------------------------------------
# List all loaded modules
#------------------------------------------------------------------------------
list_modules() {
    local mod list cnt=0
    list=$( echo $(lsmod | grep "^[a-z]" | cut -d" " -f1) | sort)
    cnt=$(echo $list | wc -w)

    # loaded <count> modules(s)
    vmsg 6 'Loaded %s module(s)' $(nq $cnt)

    [ "$list" ] && vmsg 7 "$white$list"

    [ "$ERR_MODULES" ] || return
    local ecnt=$(echo "$ERR_MODULES" | wc -w)

    vmsg 6 '%s module(s) failed to load' $(nq $ecnt)

    vmsg 7 "$white$ERR_MODULES"
}

#------------------------------------------------------------------------------
# Allow the user to select which breakpoints to use
#------------------------------------------------------------------------------
select_breakpoints() {
    case $BREAK_POINTS in
        *\?*|*ask*)
            echo
            echo "${m_co}Remaining ${hi_co}$ME$m_co breakpoints:$nc_co"
            echo
            sed -rn 's/^\s*breakpoint ([1-9a-z])\> */  \1) /p' $0 | sed "s/['\"]//g" | sort
            echo
            echo "${m_co}Use \"a\" to set most breakpoints$nc_co"
            echo "${m_co}Use \"A\" to set all breakpoints$nc_co"
            echo "${m_co}Use \"bash\" to enter a Bash shell before system starts$nc_co"
            echo
            printf "${ok_co}%s$m_co: $nc_co"  "$_Enter_breakpoint_s_separated_by_commas_"
            setsid cttyhack > /dev/null
            read BREAK_POINTS;;
    esac
}

#------------------------------------------------------------------------------
# A nice display of the memory
#------------------------------------------------------------------------------
mem_info() {
    local info amt kb
    while read info amt kb; do
        [ ! "$info" = "$1:" ] && continue
        echo $((amt / 1024))
        return
    done </proc/meminfo
}

#------------------------------------------------------------------------------
# Only remove init.xlat files because they are big and some of the others
# are used later and/or at shutdown.
#------------------------------------------------------------------------------
clean_xlat() {
    find $LOCALE_DIR/xlat -name init.xlat -delete
    #rm -rf $LOCALE_DIR/fonts
}

#------------------------------------------------------------------------------
# Source the $LANG/$PROG.xlat file to handle translation.  We also source the
# English one first in case some translated strings are missing.
#------------------------------------------------------------------------------
read_xlat() {
    local prog=$1  lang=${2%%_*}
    local xdir=$LOCALE_DIR/xlat

    local xlat=$xdir/en/$prog.xlat
    [ -r $xlat ] && . $xlat

    local alt=$DISTRO_ASCII_PRETTY_NAME
    [ -n "$lang" -a -e $fdir/$lang -a -n "$alt" ] && DISTRO_PRETTY_NAME=$alt

    [ "$lang" ] || return

    xlat=$xdir/$lang/$prog.xlat
    [ -r "$xlat" ] || return
    . $xlat
    vmsg 7 'Translate to %s' $(pq $lang)
}

#------------------------------------------------------------------------------
# Set the font size based on language and screen resolution so we get roughly
# X columns of text across the screen.  Default value of X is 120.
#------------------------------------------------------------------------------
set_console_width() {
    local width=${1:-$DEF_SCREEN_WIDTH}  lang=$2  verb=${3:-5} dir=${4:-$LOCALE_DIR/fonts}
    local def_size=8  name=Terminus  ext=.psf

    # allow conwidth=aa,bb
    width=${width%%,*}

    local code
    case ${lang%%_*} in
                     kk|ky|tj) code='CyrAsia'  ;;
                        ru|uk) code='CyrKoi'   ;;
                  bg|mk|ru|sr) code='CyrSlav'  ;;
      bs|hr|cs|hu|pl|ro|sk|sl) code='Lat2'     ;;
        af|sq|ast|da|nl|et|fr) code='Lat15'    ;;
    'fi'|de|is|id|pt|es|sv|tr) code='Lat15'    ;;
                        lt|lv) code='Lat7'     ;;
                           el) code='Greek'    ;;
                            *) code='Uni2'     ;;
    esac

    local font file
    # This loop only runs at most once.  Use "break" for control flow
    while true; do
        test -e /dev/fb0 || break

        case $width in
            [1-9][0-9]|[1-9][0-9][0-9]) ;;
            off) break ;;
              *) warn  "$_Invalid_X_value_Y_" "$(pqw conwidth)" "$(pqw $width)"
                 break ;;
          esac

        # Make sure we have at least 80 chars per line
        local min_width=${MIN_SCREEN_WIDTH:-80}
        [ $width -lt $min_width ] && width=$min_width

        local pixel_width=$(get_fbcondecor_width)
        [ -z "$pixel_width" ] && break
        local cmd_size=$((pixel_width / width))

        vmsg 6 'Width of screen in pixels %s'  "$(pq $pixel_width)"
        vmsg 6 'Try to set line length to %s'  "$(pq $width)"
        vmsg 6 'Using size %s'                 "$(pq $cmd_size)"

        local size
        case $cmd_size in
                  [1-7]) size=12x6                ;;
                   [89]) size=16                  ;;
                     10) size=20x10               ;;
                     11) size=22x11               ;;
                  1[23]) size=24x12               ;;
                  1[45]) size=28x14               ;;
                1[6789]) size=32x16               ;;
           [23456][0-9]) size=32x16               ;;
        esac

        local try  f_size  f_face
        for f_size in $size $def_size; do
            for f_face in ${name}Bold VGA $name; do
                try=$code-$f_face$f_size
                file=$dir/$try$ext
                test -e $file || continue
                font=$try
                break
            done
            [ "$font" ] && break
        done

        break
    done

    # If we didn't find a font, fall back to VGA16 so we still
    # get the right unicode chars for the chosen language
    if [ -z "$font" ]; then
        font=$code-VGA16
        file=$dir/$font$ext
        test -e $file || return 2
    fi

    [ "$NO_CLEAR" ] || clear
    vmsg $verb  "$_Set_font_to_X_" "$(pq $font)"

    log_cmd setfont $file -C $(tty)

    SCREEN_WIDTH=$(stty size 2>/dev/null | cut -d" " -f2)
    vmsg 7  "$_New_screen_width_X_"  "$(pq $SCREEN_WIDTH)"
}

#------------------------------------------------------------------------------
# Create a pretty welcome messag that contains more info at higher verbosity
#------------------------------------------------------------------------------
do_welcome() {

    [ "$NO_CLEAR" ] || clear   # Clear and reset screen

    local pretty_name=$1 version=$2  v_date=$3  arch
    case $(uname -m) in
          i686) arch=" 32-bit" ;;
        x86_64) arch=" 64-bit" ;;
    esac

    case $(uname -r) in
        *[pP][aA][eE]) arch="$arch pae" ;;
    esac

    pretty_name="$pretty_name$arch"
    vmsg 2  "$_Welcome_to_X_" "$(pq $pretty_name)!"

    echo "$pretty_name" > /live/config/pretty-name

    if lspci -n | grep -iqE " 80ee:(beef|cafe)"; then
        vmsg 7 'VirtualBox detected'
        touch /live/config/virtualbox
    fi

    local bat_stat=$(battery-status | sed "s/:/:$hi_co/" )
    [ -n "$DB_PLUS" -a -n "$bat_stat" ] && msg %s "$bat_stat"

    # Get total ramsize, and available real ram in MB. We need this later.

    local total_mem=$(mem_info MemTotal)
    local used_mem=$((total_mem - FREE_MEM))

    vmsg 8 "$white  $(busybox | head -n 1)"

    [ -x /bin/ntfs-3g ] && vmsg 8 "$white  $(ntfs-3g --version 2>&1)"

    vmsg 6 "%25s: $white%s"  'initrd version' "$version"
    vmsg 6 "%25s: $white%s"  'initrd built'   "$v_date"

    # Print meminfo.
    local mem_format="${m_co}%s: $num_co%5d${m_co} M"
    vmsg 8 "$mem_format"  '             Total Memory' $total_mem
    # vmsg 6 "$mem_format"  '              Free Memory'  $FREE_MEM
    vmsg 8 "$mem_format"  '              Used Memory'  $used_mem

    local cpu_format="%s:$white %s"
    vmsg 5 "$cpu_format"  '             Linux kernel' "$(uname -r)"
    vmsg 8 "$cpu_format"  '             Screen width' "$SCREEN_WIDTH"
    vmsg 8 "$cpu_format"  '              Kernel arch' "$(uname -m)"

    local product_name board_vendor id_dir=/sys/class/dmi/id
    read product_name 2>/dev/null  < $id_dir/product_name
    read board_vendor 2>/dev/null  < $id_dir/board_vendor
    vmsg 8 "$cpu_format"  '                 Hardware' "$board_vendor $product_name"
    # vmsg 6  "$cpu_format" '                      CPU' "$(cpu_param 'model name' unknown)"
    # vmsg 6  "$cpu_format" '                    Cores' "$num_co$(cpu_param 'cpu cores'  1)"
    # vmsg 6  "$cpu_format" '                    Cache' "$(cpu_param 'cache size' unknown)"
}

#------------------------------------------------------------------------------
# Show the boot parameters and flag possbily mispelled ones.
#------------------------------------------------------------------------------
show_bootcodes() {
    local unknown=$1

    vmsg 5 "%s:"  "$_Current_boot_codes_"
    vmsg 5 "    %s" "$white $(cat /proc/cmdline)"

    [ -n "$unknown"  -a -n "$CHECK_BOOTCODES" ] || return

    vmsg 4
    vmsg 4 "$warn_co%s:"  "$_Possibly_unknown_or_misspelled_boot_codes_"
    vmsg 4 "(%s)"  "$_dont_take_this_too_seriously_"
    local code
    for code in $unknown; do
        vmsg 4 "%s" "$hi_co    $code"
    done
    vmsg 4
}

#------------------------------------------------------------------------------
# Show all the integer errors. It is easier for the user if we lump them
# together in one warning.
#------------------------------------------------------------------------------
show_integer_errors() {
    local param name value params=$1

    # Only small integer values are allowed for <name>.  Will ignore <name=value>
    for param in $params; do
        name=${param%%=*}
        value=${param#*=}
        warn 'Only small integer values are allowed for %s.  Will ignore %s' \
            $(pqw $name) $(pqw $param)
    done
}

#------------------------------------------------------------------------------
# Show errors if the disable=XXXX letters do not match a known flag.
# (We seem to be close to using the entire alphabet already)
#------------------------------------------------------------------------------
show_disable_errors() {
    local codes=$1  ds_param=$2
    [ -n "$codes" ] || return
    local bad=$(echo "$codes" | sed -r "s/$DISABLE_SERVICES_OPTS//g")
    [ -n "$bad" ] || return
    #. Unknown options in <disable=abcRxyz>.  Unknown options(s): <R>
    warn  "$_Unknown_option_s_in_X_Unknown_option_s_Y_" "$(pqw $ds_param)" "$(pqw $bad)"
}

#------------------------------------------------------------------------------
# Not used
#------------------------------------------------------------------------------
cpu_param() {
    local result=$(grep "^$1" /proc/cpuinfo | head -n 1 | sed 's/.*\t: //')
    [ "$result" ] || result=$2
    echo "$result"
}

#------------------------------------------------------------------------------
# Used to disable ehci via "nousb2" or "noehci".  This was for old hardware
# and I doubt it is currently being used.
#------------------------------------------------------------------------------
disable_hcd() {
    local type=$1
    local dir=/sys/bus/pci/drivers/${type}_hcd
    local symlink kmsg=/dev/kmsg
    test -d $dir || return

    for symlink in $(find $dir -name "0*" | sed 's=.*/=='); do
        echo $symlink >> $DISABLED_USB_FILE.$type
        msg 'disable %s bus: %s' $(nq $type) $(pq $symlink)
        [ -e $kmsg ] && echo "initrd disabled $type: $symlink" >> $kmsg
        echo $symlink > $dir/unbind
    done
}

#------------------------------------------------------------------------------
# Get the width of the screen when fbcondecor is active.  A bit of a kludge.
#------------------------------------------------------------------------------
get_fbcondecor_width() {
    local theme=${1:-default}  res
    local res=$(cat /sys/class/graphics/fb0/virtual_size 2>/dev/null)
    [ -z "$res" ] && return
    if test -e /dev/fbcondecor; then
        local file=/etc/splash/$theme/${res/,/x}.cfg
        test -r $file || return
        sed -rn "s/^\s*tw=([0-9]+).*/\1/p" $file | tail -n1
    else
        echo ${res%%,*}
    fi
}

#------------------------------------------------------------------------------
# Not used
#------------------------------------------------------------------------------
get_fbcondecor_theme() {

    local boot_param=${1:-$SPLASH_PARAM}
    local param theme
    for param in ${boot_param//,/ }; do
        case $param in
          t=*|theme=*) theme=${param#*=} ;;
        esac
    done
    test -d /etc/$theme/ || theme=default
    test -d /etc/$theme/ || return 1
    echo $theme
    return 0
}

#------------------------------------------------------------------------------
# Not used
#------------------------------------------------------------------------------
set_fbcondecor() {
    local boot_param=$1 orig_name=$2 param verbose theme=default
    #vmsg 5 "set_fbcondecor('$1' '$2')"
    [ "$orig_name"  ] || return
    [ "$boot_param" ] || return
    #vmsg 5 "Got boot param: $param"

    local prog=/bin/fbcondecor_ctl.static
    test -x $prog || return
    #vmsg 5 "found $prog"
    local new_name
    read new_name 2>/dev/null </sys/class/graphics/fb0/name
    [ "$orig_name" = "$new_name" ] && return

    vmsg 6 "Found new fb driver:$white $new_name"

    for param in ${boot_param//,/ }; do
        case $param in
            v|verbose) verbose=true ;;
          t=*|theme=*) theme=${param#*=} ;;
        esac
    done

    [ "$verbose" ] || return
    vmsg 6 "set fbcondecor to: $theme"

    $prog -t $theme -c setcfg 2>/dev/null
    $prog -t $theme -c setpic 2>/dev/null
    $prog -c on 2>/dev/null
}

#------------------------------------------------------------------------------
# Create a file to blacklist modules when the initrd and when the main
# system boots.  Specified by blacklist=xxx or bl=xxxx.
#------------------------------------------------------------------------------
blacklist_modules() {
    local black_list=$1  local file=$2
    [ "$black_list" ] || return

    black_list=$(echo $black_list | sed -r "s/(VIDEO|KMS)/$KMS_VIDEO_MODULES/");
    mkdir -p /etc/modprobe.d/
    cat << Black_List_File
#------------------------------------------------------------------------------
# file ${file##*/} created around $(date)
#
# Created by the antiX/MX live initrd.  This file will be erased on every
# live boot.  Please rename it if you want to keep it.
#------------------------------------------------------------------------------

Black_List_File
    echo $black_list | sed 's/,/\n/g' | sed -r 's/^([a-z])/blacklist \1/' >> $BLACK_LIST_FILE
}

#------------------------------------------------------------------------------
# Load kernel modules giving by load=xxx
#------------------------------------------------------------------------------
load_kernel_modules() {
    local list=$1 file=$2

    # if [ -r $file ]; then
    #     vmsg 7 'Load modules from file %s' "$(fq $file)"
    #     grep -v "^\s*#" $file | sed 's/\s*#.*//' | xargs modprobe -a -q -b
    # fi

    coldplug_modules 5

    for module in ${list//,/ }; do
        case $module in
            all) load_all_modules ;;
              *) modprobe -q $module || warn   "Could not load module %s" $(pqw $module);;
        esac
    done
}

#------------------------------------------------------------------------------
# A Hail Mary when load=all is used (sigh)
#------------------------------------------------------------------------------
load_all_modules() {
    local subdir=$1
    msg  "$_Loading_all_modules_"
    debug_cmd lsmod
    debug_cmd lspci
    LOAD_ALL_MODULES=true
    find $MOD_DIR/$subdir -type f -name "*.ko*" | sed -nr "s=.*/==; s/\.ko(|\.[[:alpha:]]+)$//p" \
        | xargs modprobe -q -a -b 2>/dev/null
}

#------------------------------------------------------------------------------
# Used to put lots of output into the log file when "load=all" is given
#------------------------------------------------------------------------------
debug_cmd() {
    echo "==== $*"                        >> $MY_LOG
    "$@"                                  >> $MY_LOG
    echo "==============================" >> $MY_LOG
}

#------------------------------------------------------------------------------
# scan /sys/devices for alias files and load their associated modules If doing
# hotplugging we first enable hotplugging and then do one coldplug to make sure
# everything is loaded
#------------------------------------------------------------------------------
coldplug_modules() {
    local verb=$1

    [ "$verb" ] && vmsg $verb  "$_Loading_hardware_specific_modules_"

    #find /sys/devices -name uevent -exec sed -n 's/^MODALIAS=//p' '{}' + 2>/dev/null \
    #    | sort -u | xargs modprobe -a -q -b
    #return

    #find /sys/devices -name modalias -exec cat '{}' + 2>/dev/null | sort -u \
    #    | xargs modprobe -a -q -b 2>/dev/null

    find /sys/devices -name modalias -print0 | xargs -0 sort -u \
        | tr '\n' '\0' | xargs -0 modprobe -a -q -b 2>/dev/null
    return

    # local alias_file alias
    # find /sys/devices -name modalias | while read alias_file; do
    #     alias=$(cat $alias_file 2>/dev/null)
    #     modprobe -q -b $alias 2>/dev/null
    # done
}

#==============================================================================
# Find the squashfs file
#==============================================================================

#------------------------------------------------------------------------------
# Function: is_usb_or_removable <device>
#------------------------------------------------------------------------------

is_usb_or_removable() {
    local drive=$(get_drive $1)
    local dir=/sys/block/$drive flag
    read flag 2>/dev/null < $dir/removable
    [ "$flag" = 1 ] && return 0
    local devpath=$(readlink -f $dir/device)
    [ "$devpath" ] || return 1
    echo $devpath | grep -q /usb
    return $?
}

#------------------------------------------------------------------------------
# Not used
#------------------------------------------------------------------------------
is_removable() {
    local drive=$(get_drive $1)
    local dir=/sys/block/$drive flag
    read flag 2>/dev/null < $dir/removable
    [ "$flag" = 1 ]
    return $?
}

#------------------------------------------------------------------------------
# Function: get_drive <partition>
#------------------------------------------------------------------------------
get_drive() {
    local drive part=${1##*/}
    case $part in
                  mmcblk*p[0-9]|nvme*p[0-9]) echo ${part%p[0-9]}      ;;
        mmcblk*p[0-9][0-9]|nvme*p[0-9][0-9]) echo ${part%p[0-9][0-9]} ;;
                                          *) drive=${part%[0-9][0-9]}
                                             echo ${drive%[0-9]}      ;;
    esac
}

#------------------------------------------------------------------------------
# Not used
#------------------------------------------------------------------------------
next_partition() {
    local device=$1  dev=${1##*/}
    local pre=${device%%$dev}
    local root  part
    case $dev in
        mmcblk*p[1-9]) root=${dev%[1-9]}  ; part=${dev#${root}}  ;;
          nvme*p[1-9]) root=${dev%[1-9]}  ; part=${dev#${root}}  ;;
                    *) root=${dev%[0-9]}  ; root=${root%[0-9]}
                       part=${dev#$root}                         ;;
    esac
    part=$((part + 1))
    echo "$pre$root$part"
}

#------------------------------------------------------------------------------
# Function: from_filter <device-list>
#
# Filter and order devices in list according to types listed in $FROM_TYPE.
# Output goes into FILTERED_LIST so we can give error messages from within.
# Return true if there is at least one item in the FILTERED_LIST otherwise
# return false.  Error out if there is an invalid from= type.
#
# See LINUX ALLOCATED DEVICES for device numbers
# https://www.kernel.org/doc/Documentation/devices.txt
#
#   3 block First MFM, RLL and IDE hard disk/CD-ROM interface   hda, hdb
#   8 block SCSI disk devices (0-15)                            sda, sdb, ... sdp
#  22 block Second IDE hard disk/CD-ROM interface               hdc, hdd
# 179 block MMC block devices                                   mmcblk0, mmcblk1, ... mmcblk7
#------------------------------------------------------------------------------

from_filter() {

    FILTERED_LIST=

    local from_type invalid_scan
    case ,$FROM_TYPE, in
        *,all,*) from_type=$FROM_TYPE_ALL;;
              *) from_type=$FROM_TYPE;;
    esac

    # First segregate devices by type
    local dev cd_devs hd_devs usb_devs mmc_devs
    for dev; do
        [ -b "$dev" ] || continue

        case $(stat -c %t $dev) in

            b) cd_devs="$cd_devs $dev" ;;

            3|8|16|b3|ca|fe|103)
                if is_usb_or_removable $dev; then
                    usb_devs="$usb_devs $dev"
                else
                    hd_devs="$hd_devs $dev"
                fi ;;
        esac
    done

    local type
    for type in ${from_type//,/ }; do
        case $type in

            cd) FILTERED_LIST="$FILTERED_LIST$cd_devs"
                cd_devs= ;;

           usb) FILTERED_LIST="$FILTERED_LIST$usb_devs"
                usb_devs= ;;

            hd) FILTERED_LIST="$FILTERED_LIST$hd_devs"
                hd_devs= ;;

           mmc) FILTERED_LIST="$FILTERED_LIST$mmc_devs"
                mmc_devs= ;;

           "") ;;

            *) invalid_scan="$invalid_scan $type";;
        esac
    done

    # Invalid <parameter-name> value(s) <bad values>
    [ "$invalid_scan" ] \
        && _fatal "$(printf 'Invalid %s values(s) %s' "$(pqh from=)" "$(pqh $invalid_scan)")" \
        "$(printf 'Valid values are %s' "$(cq cd hd mmc usb all)")"

    [ "$FILTERED_LIST" ]

    return $?
}

#------------------------------------------------------------------------------
# Set some global variables for the find_files() routine.
#------------------------------------------------------------------------------
prep_find_files() {
    unset ALWAYS_FILTER  TRIED_LUKS

    FROM_TYPE=${1:-$DEF_FROM_TYPE}
    [ -n "$1" ] && ALWAYS_FILTER=true
    DECRYPT_ASK=$2
}

#------------------------------------------------------------------------------
# Wrapper to find_files() when we are looking for boot files.  This provides
# the proper messaging and error message for that case
#------------------------------------------------------------------------------
find_boot_file() {
    local ret
    prep_find_files "$FROM_BOOT"  "$BLUKS_ASK"
    find_files boot "$@"
    ret=$?
    local file=$1

    case $ret in
        10) fatal  "$_No_X_devices_found_" block             ;;
        20) fatal  "$_No_X_devices_found_" $(pqh $FROM_TYPE) ;;
        30) _fatal "" \
            "$(printf  "$_The_X_parameter_is_blocking_device_Y_" \
            $(pqh from=$FROM_TYPE) "$(pqh $DEVICE_LIST)")"     \
            "$(printf  "$_Even_though_device_X_has_Y_" "$(pqh $DEVICE_LIST)" "$(pqh $device_id)")" \
            "$(printf  "$_Remove_the_X_boot_parameter_to_allow_that_device_to_be_scanned_" \
            $(cq $FROM_TYPE))" ;;
        40) fatal  "$_Device_found_but_could_not_find_X_file_on_device_"  $(pqh $file) ;;
    esac

    return $ret
}

#------------------------------------------------------------------------------
# Function: find_files <type> <files> <mntpnt> <device_id> <retry_time>
#
# The outer wrapper lets us show the loop times regardless of how we left the
# main code in _find_files().
#------------------------------------------------------------------------------

find_files() {
    local ret loop_times start_t=$(get_time) t2 elapsed  find_type=$1 files=$2 device_id=$4
    _find_files "$@"
    ret=$?
    t2=$(get_time)
    elapsed=$(get_seconds $((t2 - start_t)))
    # Spent <15> seconds looking for <boot> file(s) <linuxfs>
    vmsg 6  "Spent %s seconds looking for %s file(s) %s" $(nq $elapsed) $(fq $find_type) "$(fq $files)"
    [ "$loop_times" ] && vmsg 6 "loop times:$num_co$loop_times"

    [ "$find_type" != boot ] && return $ret

    return $ret
}

_find_files() {
    local find_type=$1 files=$2  mp_orig=$3  device_id=$4  retry_time=$5

    local TRY_LUKS
    [ -n "$device_id" ] && TRY_LUKS=$find_type

    local short_files f
    if [ ${#files} -gt 20 ]; then
        for f in $files; do
            short_files="$short_files$(basename $f) "
        done
    else
        short_files=$files
    fi

    local last_list  # disk_device partition partition_error

    # Find disk device if we are looking for a named partition.
    # This lets us bail early if the disk is found but the partition is not.

    # The disk device can appear before the partition appears so this is not reliable
    # if [ -n "$device_id" -a -z "${device_id##name=*}" ]; then
    #     partition=${device_id##name=}
    #     partition=${partition##*/}
    #     disk_device=/dev/$(get_drive $partition)
    #     partition=/dev/$partition
    # fi

    unset FOUND_DEV FOUND_MP

    local be_verbose vthresh=8
    [ "$VERBOSE" -ge $vthresh ] && be_verbose=true

    mkdir -p "$mp_orig"

    local end_t  loop_t1  usleep  dt
    local start_t=$(get_time)  current_t=0
    local try=-1  have_devices  final_try  dot=.  dt_secs

    # Stay in loop until success or time goal_t is reached
    local goal_t=$((start_t + retry_time * 100))

    local do_delay said_retry mounted_device

    while [ -z "$final_try" ]; do

        try=$((try + 1))
         [ "$be_verbose" ] && cnt_up=$(nq "$(printf "%2d" $try)")

        #-- delay every time except inside first second
        if [ "$do_delay" ]; then
            if [ -z "$said_retry" ]; then
                #. Retry for <N> seconds <...>
                vmsgN 4  "$_Retry_for_X_seconds_Y_" $(nq $retry_time) ""
                vmsg_if $vthresh " ..."
                said_retry=true
            fi

            [ "$DO_COLDPLUG" ] && coldplug_modules

            # Normally just print out a dot for each iteration
            [ "$be_verbose" ] || vmsgN 3 $dot

            # Adjust sleep time dynamically to account for previous time
            # through the loop

            current_t=$(get_time)
            dt=$((current_t - loop_t1))
            usleep=$(( ($RETRY_DELAY - dt ) * 10000))
            dt_secs=$(get_seconds $dt)
            loop_times="$loop_times $dt_secs"
            vmsg_if 9 "loop time:$num_co $dt_secs"

            # Once we have exceeded the time limit we go through the
            # loop one final time.
            [ $current_t -gt $goal_t ] && final_try=true

            # Only sleep long enough so total time through loop is constant
            [ $usleep -gt 0 ] && usleep $usleep
        else
            [ $(($(get_time) - start_t)) -gt 99 ] && do_delay=true
        fi

        loop_t1=$(get_time)

        # This disables usb-2
        [ "$NO_EHCI" ] && disable_hcd ehci

        unset DEVICE_LIST FILTERED_LIST

        #----------------------------------------------------------------------
        # Either scan all available block devices because no uuid, label, or
        # device was specified ...
        #----------------------------------------------------------------------
        if [ -z "$device_id" ]; then
            #. Scan <type> devices.  Look for <type> file(s) <file-names>
            [ "$try" = "0" ] \
                && vmsg 4  "$_Scan_X_devices_Look_for_Y_file_s_Z_"  $(dq $FROM_TYPE) $find_type "$(fq $short_files)"

            DEVICE_LIST=$(most_block_devices)

            if [ -z "$DEVICE_LIST" ]; then
                [ "$final_try" ] && return 10

                vmsg_if $vthresh "%s No %s devices found" "$cnt_up" block
                continue
            fi

            # Filter and order devices according to from= parameter
            if ! from_filter $DEVICE_LIST; then
                [ "$final_try" ] && return 20

                vmsg_if $vthresh "%s No %s devices found" "$cnt_up" $(pq $FROM_TYPE)
                continue
            fi

            DEVICE_LIST=$FILTERED_LIST

            # pure window dressing
            if [ -z "$have_devices" ]; then
                [ $try -gt 0 ] && vmsg 4
                vmsg 5  "$_Filtered_devices_X_" "$white$DEVICE_LIST"
            else
                vmsg_if $vthresh "%s Filtered devices %s" "$cnt_up" "$(pq $DEVICE_LIST)"
            fi

        #----------------------------------------------------------------------
        # ... Or look for specific devices because a uuid, label, or device was
        # specified
        #----------------------------------------------------------------------
        else
            if [ "$mounted_device" ]; then
                ORIG_FOUND_ID_DEVICE=$mounted_device
                FOUND_ID_DEVICE=${DECRYPT_DEV:-$mounted_device}
                return 40
            fi

            # Give up early if the root device is found but the partition is not
            # But wait a second in case there is a delay for the partitions to show
            # if [ "$partition_error" ]; then
            #     warn "Found root device %s but not partition %s" "$(pqw $disk_device)" "$(pqw $partition)"
            #     sleep 1
            #     final_try=true
            # fi

            # [ "$disk_device" -a -e "$disk_device" -a ! -e $partition ] && partition_error=true

            find_device "$find_type" "$try" "$final_try" "$device_id" || return $?
            if [ -z "$DEVICE_LIST" ]; then
                vmsg_if $vthresh "%s No %s devices yet found" "$cnt_up" $(pq $FROM_TYPE)
                continue
            fi

            #------------------------------------------------------------------
            # When a device has been specified via label, uuid, or /dev/node
            # then only filter and order if from= parameter is given explicitly
            #------------------------------------------------------------------
            if [ "$ALWAYS_FILTER" ]; then
                if ! from_filter $DEVICE_LIST; then
                    [ "$final_try" ] && return 30
                    continue
                fi

                DEVICE_LIST=$FILTERED_LIST
            fi

            # pure window dressing
            if [ -z "$have_devices" ]; then
                [ "$try" != "0" ] && msg
                #. Look for files(s) <file-list> on device(s) <device-list>
                vmsg 4  "$_Look_for_file_s_X_on_device_s_Y_" "$(pq $short_files)" "$(dq $DEVICE_LIST)"
            else
                #vmsg_if $vthresh
                vmsg_if $vthresh "%s Look for %s on %s" "$cnt_up" "$(pq $short_files)" "$(dq $DEVICE_LIST)"
            fi
        fi

        #----------------------------------------------------------------------
        # Now we have some device or devices to mount and search
        #----------------------------------------------------------------------

        # more window dressing
        if [ -n "$have_devices" -a "$last_list" != "$DEVICE_LIST" ]; then
            msg
            msg  "$_Found_new_device_s_X_" "$(hq $DEVICE_LIST)"
        fi
        last_list=$DEVICE_LIST

        have_devices=true

        #-- now try to mount each device and find at least one of the $files ...
        local dev fname mntpnt mounted already
        for dev in $DEVICE_LIST; do
            # use existing mountpoint if device is already mounted
            mntpnt="$(get_mountpoint $dev)"
            if [ "$mntpnt" ]; then
                mounted=
                mounted_device=$dev
                [ "$already" ] || vmsg 5  "$_Device_X_is_already_mounted_at_Y_"  "$(dq $dev)" "$(mpq $mntpnt)"
                already=true
            else
                try_mount $dev $mp_orig || continue
                mounted_device=$dev
                mounted=true
                mntpnt=$mp_orig

            fi
            if [ -n "$device_id" -a "$find_type" = persist ]; then
                if [ "$DID_FRUGAL" ]; then
                    create_persist_files "$mntpnt" "$PERSIST_PATH" "$WANT_ROOTFS" "$WANT_HOMEFS"
                else
                    create_persist_files "$mntpnt" "$PERSIST_PATH" "$NEED_ROOTFS" "$NEED_HOMEFS"
                fi
            fi

            # After possibly running persist_makefs
            tsplash_on

            for fname in $files; do
                [ -f "$mntpnt/$fname" ] || continue
                #[ "$said_retry" ] && echo
                if [ "$mntpnt" = "$mp_orig" ]; then
                    #. Mounted <type> device at <mount point>
                    vmsg 4  "$_Mounted_X_device_Mounted_device_Y_at_Z_" \
                        $find_type "$(fq $dev)" "${to_co}$mntpnt${m_co}"

                    local fstype=$(mntpnt_fstype $mntpnt)
                    #. <type> device filesystem: <filesystem-name>
                    vmsg 6  "$_X_device_filesystem_Y_" $find_type \
                        "$(cq $fstype)"

                    case $find_type in
                        boot) BOOT_FSTYPE=$fstype ;;
                    esac

                    local drive=$(get_drive $dev)
                    local model
                    read model 2>/dev/null </sys/block/$drive/device/model

                    # <type> device model: <model-name>
                    [ "$model" ] && vmsg 6 '%s device model: %s' $find_type "$(cq $model)"

                else
                    rmdir $mp_orig
                fi
                ORIG_FOUND_DEV=$dev
                FOUND_DEV=${DECRYPT_DEV:-$dev}
                FOUND_MP=$mntpnt
                FOUND_FNAME=$fname
                return 0
            done
            [ "$mounted" ] && mountpoint -q $mp_orig && umount $mp_orig
        done
    done
    [ "$try" != "0" ] && msg
    return 90
}

#------------------------------------------------------------------------------
# Function find_device: <type> <try> <final_try> <device_id>
#
# Find the device(s) associated with a device name, a label, or a uuid.  Puts
# the result in $DEVICE_LIST so are free to echo error messages.  Returns true
# on success or if we need to retry.  Returns false if there was a final error.
#------------------------------------------------------------------------------

find_device() {
    local err_ret find_type=$1  try=$2  final_try=$3  type=${4%%=*}  value=${4#*=}

    DEVICE_LIST=

    #. Look for <type> devices with <attribute X>
    [ "$try" = 0 ] && tsplash_alert  "$_Look_for_X_device_with_Y_" "$(fq $find_type)" "$type $(cq $value)"

    case $type in
        name) DEVICE_LIST=$(cleanse_dev   $value) ; err_ret=1 ;;
       label) DEVICE_LIST=$(label_to_dev  $value) ; err_ret=2 ;;
        uuid) DEVICE_LIST=$(uuid_to_dev   $value) ; err_ret=3 ;;
      fstype) DEVICE_LIST=$(fstype_to_dev $value) ; err_ret=4 ;;
           *) fatal 'Internal error: find_device() type=%s value=%s' "$type" "$value" ;;
    esac

    [ "$DEVICE_LIST" ] && return 0
    [ "$final_try" ]   || return 0

    [ "$try" != 0 ] && msg

    if [ "$find_type" != boot ]; then
        return 100
    fi

    [ "$AUTO_PERSIST"       ] && return 100
    [ "$find_type" = frugal ] && return 100

    general_device_error "$find_type" "$type" "$value"
    return $err_ret
}

#------------------------------------------------------------------------------
# Create a grub entry file that can be added to a grub.cfg for booting into
# a frugal system
#------------------------------------------------------------------------------
create_grub_entry() {
    local bdir=$1  uuid=$2 crypt_flag=$3 fstype=$4
    local insmod
    case "$fstype" in 
           btrfs) insmod=btrfs    ;;
        ext[234]) insmod=ext2     ;;
           exfat) insmod=exfat    ;;
    fat|dos|vfat) insmod=fat      ;;
            f2fs) insmod=f2fs     ;;
             jfs) insmod=jfs      ;;
            ntfs) insmod=ntfs     ;;
        reiserfs) insmod=reiserfs ;;
             xfs) insmod=xfs      ;;
               *) insmod=         ;;
    esac

    if [ -n "$insmod" ]; then
        insmod="insmod $insmod" 
    fi

    if [ -n "$crypt_flag" ]; then
    
        cat <<Crypt_Entry
menuentry "$DISTRO_PRETTY_NAME Encrypted Frugal Install" {
    insmod part_msdos
    insmod part_gpt
    $insmod
    insmod luks
    cryptomount -u ${uuid//-/}
    set root=(crypto0)
    linux /$bdir/vmlinuz bdir=$bdir buuid=$uuid $(gather_frugal_cmdline)
    initrd /$bdir/initrd.gz
}
Crypt_Entry

    else
        cat <<Grub_Entry
menuentry "$DISTRO_PRETTY_NAME Frugal Install" {
    insmod part_msdos
    insmod part_gpt
    $insmod
    search --no-floppy --set=root --fs-uuid $uuid
    linux /$bdir/vmlinuz bdir=$bdir buuid=$uuid $(gather_frugal_cmdline)
    initrd /$bdir/initrd.gz
}
Grub_Entry
    fi
}

#------------------------------------------------------------------------------
# Print the UUID of a partition
#------------------------------------------------------------------------------
device_uuid() {
    local device=$1
    blkid $device | sed -n -r 's/.* UUID="([^"]*)"( |$).*/\1/p'
}

#------------------------------------------------------------------------------
# Print the label of a partition
#------------------------------------------------------------------------------
device_label() {
    local device=$1
    blkid $device | sed -n -r -e 's/" (UUID=|TYPE=)".*//' -e 's/[^:]*: LABEL="//p'
}

#------------------------------------------------------------------------------
# Print the file system type of a partition
#------------------------------------------------------------------------------
device_fstype() {
    local device=$1
    blkid $device | sed -n -r 's/.* TYPE="([^"]*)"$/\1/p' | tail -n 1
}

#------------------------------------------------------------------------------
# Print the file system type based on a mount point
#------------------------------------------------------------------------------
mntpnt_fstype() {
    local dev=$(df -P $1 | tail -n1 | cut -d" " -f1)
    device_fstype $dev
}

#------------------------------------------------------------------------------
# Clean things up after a failed attempt to find the frugal device
#------------------------------------------------------------------------------
frugal_error() {

    # Disable persistence if frugal fails or is aborted
    PERSIST=

    local mp
    for mp in $FRUGAL_MP $SQFS_MP; do
        mountpoint -q $mp && umount $mp
        [ -d $mp ] && rmdir $mp
    done

    non_fatal  "Frugal install failed (or was teminated)"
}

#------------------------------------------------------------------------------
# A wrapper for find_files() to look for a frugal install.
#------------------------------------------------------------------------------
find_frugal_file() {
    local frugal_id=$1  bdir=$FRUGAL_DIR
    : ${bdir:=$FRUGAL_NAME-Frugal-$(uname -r)}

    tsplash_alert  "$_Search_for_X_partition_" frugal
    local sqfile=$bdir/$SQFILE_NAME need_to_ask
    local device  orig_device  name=${frugal_id%%=*}  value=${frugal_id#*=}
    prep_find_files  "$FROM_FRUGAL"  "$FLUKS_ASK"
    find_files frugal "$sqfile" "$BOOT_MP" "$frugal_id" "$FRUGAL_RETRY"
    local ret=$?

    if [ $ret -eq 0  -a  -z "$FORCE_FRUGAL" ]; then
        #. Found existing <frugal> install
        tsplash_alert  "$_Found_existing_X_install_" frugal
        SQFILE_MP=$BOOT_MP
        SQFILE_DEV=$FOUND_DEV

        SQFILE_FULL=$BOOT_MP/$sqfile
        SQFILE_PATH=${sqfile%/*}
        DEFAULT_PERSIST_PATH=$SQFILE_PATH
        SQFILE_DIR=$(dirname $SQFILE_FULL)
        DEFAULT_DIR=$SQFILE_DIR
        return 0

    elif [ $ret -eq 40 ]; then
        orig_device=$ORIG_FOUND_ID_DEVICE
        device=$FOUND_ID_DEVICE
        msg "$found_id_device: '$found_id_device'"
        need_to_ask=true

        warn
        # Found <frugal> device with <label=xxxx>
        warn  "Found %s device with %s" $(cqw frugal) "$name=$(cqw $value)"
        warn  "But did not find file %s on the device" "$(cqw $sqfile)"
        warn  "Will start normal boot to do frugal install"
        warn

    elif [ "$FORCE_FRUGAL" ]; then
        msg 'Force frugal install'
        if [ $ret -eq 0  ]; then
            device=$FOUND_DEV
            log_cmd umount $FOUND_DEV
        fi

    else
        warn
        warn  "Could not find %s device with %s" $(cqw frugal) "$name=$(cqw $value)"
        warn  "Will start normal boot to do frugal install"
        warn
    fi

    find_crypt_or_linuxfs

    BIOS_DEV=$FOUND_DEV
    SQFILE_MP=$BOOT_MP
    SQFILE_DEV=$FOUND_DEV

    SQFILE_FULL=$BOOT_MP/$SQFILE_FILE
    SQFILE_PATH=${SQFILE_FILE%/*}
    DEFAULT_PERSIST_PATH=$SQFILE_PATH

    mount_linuxfs "$SQFS_MP" "$SQFILE_FULL" "$WRAP_FILE_MP"

    check_kernel_version $SQFS_MP

    prep_ld_path

    local old_dir=$(dirname $SQFILE_FULL)
    local actual=$(file_usage_m $old_dir $FRUGAL_FILES)

    # Safety first!
    local needed=${FRUGAL_NEEDED:=$((actual + 100))}

    if  [ -z "$device" ]; then

        tsplash_alert  "$_Looking_for_partitions_with_at_least_X_free_Please_wait_" "$(nq $(size_label_m $needed))"
        select_device 'frugal' device $needed not_mounted
        local ret=$?
        [ $ret -eq 0 ] || return 2
        [ -z "$device" -o "$device" = "$_quit_" ] && return 1

        [ "$LABEL_FRUGAL" ] && label_device $device "$FRUGAL_NAME-Frugal"
    fi

    if ! mkdir -p $FRUGAL_MP; then
        err  "Could not make frugal directory"
        return 10
    fi

    TRY_LUKS=frugal
    if ! try_mount $device $FRUGAL_MP rw; then
        err  "Could not mount frugal device %s" $(pqe $device)
        return 20
    fi
    local orig_device=$device
    device=${DECRYPT_DEV:-$device}

    local sqfile_full=$FRUGAL_MP/$sqfile
    local sqfile_dir=$(dirname $sqfile_full)

    [ "$FORCE_FRUGAL" ] && rm -rf $sqfile_dir

    #breakpoint f "in frugal install"

    if [ -e $sqfile_full ]; then
        msg  "$_Found_existing_X_install_" frugal
    else

        local free=$(free_space $FRUGAL_MP)

        vmsg 5 'Device %s has %s free' $(pq $device) "$(nq $(size_label_m $free))"

        if [ $free -lt $needed ]; then
            err  "Not enough free space on device %s to do install" $(pqe $device)
            return 20
        fi

        if [ "$need_to_ask" ]; then
            #. Do you want to do a <frugal> install on the <name> device?
            YES_no  "$_Do_you_want_to_do_a_X_install_on_the_Y_device_" frugal $(pq $device) || return 2
        fi

        #. Doing <frugal> install, please be patient ...
        heading  "$_Doing_X_install_please_be_patient_" frugal
        log_cmd mkdir -p $sqfile_dir || return 30

        msg  "$_copy_X_to_Y_" $(pq $(size_label_m $actual)) $(pq $sqfile_dir/)

        if ! tsplash_prog_copy_md5 frugal_install $sqfile_dir $old_dir $FRUGAL_FILES; then
            tsplash_warn  "Copy failed.  Erasing partial copy"
            log_cmd rm -f $sqfile_full
            return 40
        fi

        create_grub_entry "$bdir" "$(device_uuid ${orig_device:-$device})" "$DECRYPT_DEV"  "$(device_fstype ${orig_device:-$device})" >  $sqfile_dir/grub.entry

        case $(device_fstype $BIOS_DEV) in
            vfat|ext[234]) device_uuid $BIOS_DEV > $sqfile_dir/bios-dev-uuid
        esac

        #. The <frugal> install succeeded
        warn  "$_The_X_install_succeeded_" frugal
        DID_FRUGAL=true
    fi

    lazy_umount $SQFS_MP
    lazy_umount $BOOT_MP

    mount --move $FRUGAL_MP $BOOT_MP
    rmdir $FRUGAL_MP

    SQFILE_MP=$BOOT_MP
    SQFILE_DEV=$device

    SQFILE_FULL=$BOOT_MP/$sqfile
    SQFILE_PATH=${sqfile%/*}
    DEFAULT_PERSIST_PATH=$SQFILE_PATH
    SQFILE_DIR=$(dirname $SQFILE_FULL)
    DEFAULT_DIR=$SQFILE_DIR

    return 0
}

#------------------------------------------------------------------------------
# A wrapper for find_boot_file() or find_crypt_or_linuxfs
#------------------------------------------------------------------------------
find_linuxfs_file() {

    if [ -n "$ISO_FILE" -o -n "$FROM_ISO" ]; then

        : ${ISO_FILE:=$DEFAULT_ISO_FILE}
        ISO_FILE=${ISO_FILE#/}

        heading "${cheat_co}fromiso"

        #. Could not find <type> file <file-name>
        find_boot_file "$ISO_FILE" "$ISO_DEV_MP" "$BOOT_ID" "$BOOT_RETRY" \
            || fatal  "$_Could_not_find_X_file_Y_" iso "$(pqh $ISO_FILE)"

        local iso_full=$ISO_DEV_MP/$ISO_FILE
        DEFAULT_PERSIST_PATH=${ISO_FILE%/*}

        # Check md5 of files in directory containing iso file
        [ "$CHECK_MD5" ] && check_md5 $iso_full

        # Mount the iso file
        # Could not mount <file-name> as a <iso> file
        mkdir -p $ISO_FILE_MP
        mount -t iso9660 -o loop,ro $iso_full $ISO_FILE_MP \
            || mount -t udf -o loop,ro $iso_full $ISO_FILE_MP \
            || fatal_dmesg  "$_Could_not_mount_X_as_a_Y_file_" "$(pqh $iso_full)" 'iso'

        # Find the linuxfs file
        SQFILE_FULL="$ISO_FILE_MP/$SQFILE_FILE"
        [ -f "$SQFILE_FULL" ] \
            || linuxfs_error  "$_File_X_not_found_on_device_Y_" "$SQFILE_FULL" "$FOUND_DEV"

        SQFILE_MP=$ISO_FILE_MP
        BOOT_MP=$SQFILE_MP
        SQFILE_DEV=$FOUND_DEV   # Used for toram-eject
        SQFILE_PATH=${SQFILE_FILE%/*}

        DID_ISO=true

    else

        find_crypt_or_linuxfs
        tsplash_on

        SQFILE_MP=$BOOT_MP
        SQFILE_DEV=$FOUND_DEV

        SQFILE_FULL=$BOOT_MP/$SQFILE_FILE
        SQFILE_PATH=${SQFILE_FILE%/*}
        DEFAULT_PERSIST_PATH=$SQFILE_PATH

    fi

    SQFILE_DIR=$(dirname $SQFILE_FULL)
    DEFAULT_DIR=$SQFILE_DIR
}

#------------------------------------------------------------------------------
# Make sure the mode is valid and if encryption is enabled then make sure that
# we have all of the tools needed, otherwise disable it.
#------------------------------------------------------------------------------
validate_encryption_mode() {

    : ${ENCRYPT_MODE:=$(head -n1 $ENCRYPT_MODE_FILE 2>/dev/null)}
    : ${ENCRYPT_MODE:=$ENCRYPT_DISABLE}

    # Default to enable or disabled depending on existence of cryptsetup program
    if [ "$ENCRYPT_MODE" = "$ENCRYPT_ONLY" -a ! -x /bin/cryptsetup ]; then
        non_fatal "encrypted live-usb requested but the %s program was not found" "cryptsetup"
        ENCRYPT_MODE=$ENCRYPT_DISABLE
    fi

    case $ENCRYPT_MODE in
                   $ENCRYPT_DISABLE) return ;;
        $ENCRYPT_BOTH|$ENCRYPT_ONLY)        ;;
                             uuid=*)        ;;
        *) fatal  "$_Invalid_encryption_mode_X_" "$mode" ;;
    esac

    test -d /sys/module/dm_crypt  || fatal  "$_Required_encryption_kernel_module_X_not_found_"      "$(pqh dm-crypt)"
    test -e /bin/cryptsetup       || fatal  "$_The_X_program_was_not_found_Cannot_do_encryption_" "$(pqh cryptsetup)"
    cryptsetup --help &>/dev/null || fatal  "$_The_X_program_is_broken_Cannot_do_encryption_"     "$(pqh cryptsetup)"
}

#------------------------------------------------------------------------------
# This code is used in 2 places.  Very yuck right now.
#------------------------------------------------------------------------------
find_crypt_or_linuxfs() {

    # If user specifies a boot device then don't assume we are doing a "normal"
    # encrypted boot
    [ -n "$BOOT_ID" ] && ENCRYPT_MODE=$ENCRYPT_DISABLE

    validate_encryption_mode

    local boot_dir=$(dirname $SQFILE_FILE)  fname=$(basename $SQFILE_FILE)
    local crypt_full="$boot_dir/$CRYPT_FNAME"

    CRYPT_UUID=
    local files
    case $ENCRYPT_MODE in
        $ENCRYPT_DISABLE) files="$SQFILE_FILE"              ;;
           $ENCRYPT_BOTH) files="$crypt_full $SQFILE_FILE"  ;;
           $ENCRYPT_ONLY) files="$crypt_full"               ;;
                  uuid=*) CRYPT_UUID=${ENCRYPT_MODE#uuid=}  ;;
                       *) fatal 'Unknown encryption mode %s' "$ENCRYPT_MODE" ;;
    esac

    local crypt_dev

    # Perhaps this can be improved.  Maybe we should grep on the fstype?
    if [ "$CRYPT_UUID" ]; then
        local try devs
        msg  "$_Looking_for_encrypted_device_with_uuid_X_" "$(pq "$CRYPT_UUID")"
        for try in $(seq 1 $BOOT_RETRY); do

            devs=$(uuid_to_dev $CRYPT_UUID 'TYPE=.crypto_LUKS')
            [ -n "$devs" ] && break
            echo -n "."
            sleep 1
        done
        echo
        # Take just the first found device for now :(
        crypt_dev=${devs%% *}
    else

        if ! find_boot_file "$files" "$BOOT_MP" "$BOOT_ID" "$BOOT_RETRY"; then
            case $ENCRYPT_MODE in
                $ENCRYPT_DISABLE) linuxfs_error  "$_Could_not_find_file_X_" "$(fqe $SQFILE_FILE)"                             ;;
                   $ENCRYPT_BOTH) linuxfs_error  "$_Could_not_find_files_X_or_Y_" "$(fqe $SQFILE_FILE)" "$(fqe $crypt_full)" ;;
                   $ENCRYPT_ONLY) linuxfs_error  "$_Could_not_find_file_X_" "$(fqe $crypt_full)"                              ;;
            esac
        fi

        [ "$FOUND_FNAME" != "$crypt_full" ] && return

        BIOS_UUID=$(device_uuid $FOUND_DEV)
        BIOS_DEV=$FOUND_DEV

        # Move mounted "bios" device out of the way
        mkdir -p $BIOS_MP
        log_cmd mount --move $BOOT_MP $BIOS_MP

        local crypt_file="$BIOS_MP/${crypt_full#/}"

        CRYPT_UUID=$(head -n1 $crypt_file 2>/dev/null)
        [ -n "$CRYPT_UUID" ] && crypt_dev=$(blkid | grep "UUID=.$CRYPT_UUID." | cut -d: -f1)
    fi

    vmsg 7 'crypt_uuid %s   crypt_dev %s' "$(pq "$CRYPT_UUID")" "$(pq $crypt_dev)"

    [ -z "$crypt_dev" ] && fatal  "$_No_encrypted_device_with_uuid_X_was_found_" "$(pqh "$CRYPT_UUID")"

    : ${CRYPT_UUID:=$(device_uuid $crypt_dev)}

    BOOT_UUID=$CRYPT_UUID

    tsplash_clear

    mkdir -p /run/cryptsetup

    msg  "$_Checking_for_encrypted_partition_on_device_X_" "$crypt_dev"

    test -e "$crypt_dev" || fatal  "$_Encrypted_device_X_does_not_exist_"                 "$(dqe $crypt_dev)"
    test -b "$crypt_dev" || fatal  "$_Encrypted_device_X_is_not_a_block_device_"          "$(dqe $crypt_dev)"
    cryptsetup isLuks "$crypt_dev" || fatal  "$_Encrypted_device_X_is_not_a_LUKS_device_" "$(dqe $crypt_dev)"

    #check_luks_version "$crypt_dev"

    mount -o remount,rw $BIOS_DEV

    local phrase_full=$BIOS_MP/$boot_dir/$PHRASE_FNAME
    if test -f $phrase_full; then
        reset_passphrase $phrase_full $crypt_dev
    elif [ "$CHANGE_PASSPHRASE" ]; then
        change_passphrase $crypt_dev
    fi

    warn  "$_Found_encrypted_device_You_will_be_asked_to_enter_your_passphrase_below_"
    cttyhack cryptsetup open $crypt_dev $LUKS_NAME || fatal  "$_Could_not_open_LUKS_device_X_" $crypt_dev

    CRYPT_TAB="$CRYPT_TAB$crypt_dev:$LUKS_NAME:\n"
    local mapper_dev=/dev/mapper/$LUKS_NAME
    msg  "$_Opened_encrypted_device_X_at_Y_" "$crypt_dev" "$mapper_dev"
    TRY_LUKS='encrypted'
    try_mount "$mapper_dev" "$BOOT_MP" || fatal_dmesg  "$_Could_not_mount_encrypted_device_"
    test -e "$BOOT_MP/$SQFILE_FILE" || fatal  "$_Could_not_find_file_X_on_encrypted_partition_" "$SQFILE_FILE"
    BOOT_FSTYPE=$(mntpnt_fstype $BOOT_MP)
    ENCRYPTED=true
    CRYPT_DEV=$mapper_dev
    FOUND_DEV=$mapper_dev
    if [ "$HAVE_SET_PASSPHRASE" ]; then
        warn  "$_Are_you_sure_you_have_written_down_or_memorized_the_new_passphrase_"
        msg  "$_press_X_to_continue_" "<$(bq  "$_Enter_")>"
        local xxxx
        read xxxx
    fi
}

#------------------------------------------------------------------------------
# Note: od is giving us leading whitespace which I remove with echo
# FIXME: busybox od does not have the --endian optiont
#------------------------------------------------------------------------------
check_luks_version() {
    local part=$1

    if ! test -b "$part"; then
        warn  "$_Encrypted_partition_X_is_not_a_block_device_" "$(pqw $part)"
        return 1
    fi
    local luks=$(echo $(dd status=none if=$part bs=1 count=4 | od -An -t x4 --endian=big))
    if [ "$luks" != '4c554b53' ]; then
        warn  "$_X_does_not_look_like_a_Luks_partition_Found_Y_" "$(pqw $part)" "$(pqw $luks)"
        return 2
    fi
    local type=$(echo $(dd status=none if=$part bs=1 skip=6 count=2 | od -An -t x2 --endian=big))
    msg  "$_Luks_type_X_" "$(nq $(printf "%d" "0x$type"))"
    return 0
}

#------------------------------------------------------------------------------
# Allow the user to change the encryption passphrase based on the "passphrase"
# boot parameter.  Peraps it is silly to have this here.
#------------------------------------------------------------------------------
change_passphrase() {
    local dev=$1

    warn  "$_Changing_encryption_passphrase_"

    local old file=/passphrase
    while true; do
        echo -e  "$_Please_enter_current_passphrase_in_clear_text_"
        echo -n "> "
        read old
        echo -n "$old" > $file
        cryptsetup open --test-passphrase --key-file $file $dev &>/dev/null && break

        warn  "$_The_entered_passphrase_does_not_match_"
        YES_no  "$_Do_you_want_to_try_again_" && continue
        warn  "$_Passphrase_change_aborted_"
        return 3
    done

    if ! set_new_passphrase "$file" "$dev"; then
        err  "$_Passphrase_was_not_changed_"
        return 3
    fi

    rm $file
}

#------------------------------------------------------------------------------
# Force user to reset the passphrase based on a passphrase that already
# exists in the "passphrase file.  Useful for distributing an encrypted
# live-usb.  The recipient sets their own passphrase on first boot.
#------------------------------------------------------------------------------
reset_passphrase() {
    local file=$1  dev=$2
    test -f $file || return
    local size=$(wc -c $file | cut -d" " -f1)

    warn  "$_Preparing_for_passphrase_first_boot_reset_"

    if [ $size -eq 0 ]; then
        warn  "$_Reset_aborted_passphrase_file_is_empty_"
        return 1
    fi

    if ! cryptsetup open --test-passphrase --key-file $file $dev &>/dev/null; then
        warn  "$_Reset_aborted_wrong_passphrase_in_passphrase_file_"
        return 2
    fi

    if ! set_new_passphrase "$file" "$dev"; then
        err  "$_Passphrase_was_not_changed_"
        return 3
    fi

    mv $file $file.old
}

#------------------------------------------------------------------------------
# ?????
#------------------------------------------------------------------------------
set_new_passphrase() {
    local file=$1  dev=$2
    [ "$DB_PLUS" ] && msg  "$_current_phrase_X_" "$(pq $(cat $file))"
    while true; do
        warn  "$_You_will_be_asked_to_enter_a_new_passphrase_twice_"
        cttyhack cryptsetup luksChangeKey --key-file $file $dev 2>&1 && return 0
        YES_no  "$_Do_you_want_to_try_again_" || return 2
    done
}

#------------------------------------------------------------------------------
# These version offers the choice of several randomly generated passphrases
# as well as setting your own.  The problem is there is almost zero entropy
# this early in the boot process so the "random" phrases are really not very
# random at all.  Someday we could offer a generated passphrase as an option
# and then ask the user to generate entropy by typing or something like that.
# But even that can be tricky because address randomization can eat up more
# entropy than we generate.
#------------------------------------------------------------------------------
fancy_set_new_passphrase() {
    local file=$1  dev=$2

    local phrase  phrase_2  phrase_3   phrase_4   phrase_5
    local fmt="$m_co %2s$to_co)$m_co %s$nc_co\n"

    warn 'Please select a passphrase or create your own'

    local i=1
    printf "$fmt" "$i" 'Create your own passphrase (default)'

    local len=4  max_len=8 seq=$(seq 2 5)
    for i in $seq; do
        phrase=$(mkpassphrase $len)
        eval phrase_$i=\$phrase
        printf "$fmt" "$i" "$(bq "$phrase")"

        len=$((len + 2))
        [ $len -gt $max_len ] && len=$max_len

    done
    i=$((i + 1))
    printf "$fmt" "$i" 'Reboot'
    i=$((i + 1))
    printf "$fmt" "$i" 'Poweroff'

    local ans  create_own use_phrase
    while true; do
        read ans
        case $ans in
         1|"") create_own=true               ;;
        [2-5]) eval use_phrase=\$phrase_$ans ;;
            6) safe-reboot                   ;;
            7) safe-poweroff                 ;;
            *) warn 'Invalid selection, please try again' ; continue ;;
        esac
        break
    done

    if [ "$create_own" ]; then
        warn 'You will be asked to enter a new passphrase twice'
        cttyhack cryptsetup luksChangeKey --key-file $file $dev 2>&1 || return $?

    elif [ "$use_phrase" ]; then
        msg 'Using passphrase %s' "$(bq "$use_phrase")"
        [ "$DB_PLUS" ] && echo -n "$use_phrase" > /live/config/passphrase
        printf "%s" "$use_phrase" | cryptsetup luksChangeKey --key-file $file $dev 2>&1 || return $?
    else
        fatal 'Internal error setting new passphrase'
    fi

    warn 'Please DO NOT forget your new passphrase! You will need it every time you boot'
    #warn "You will be asked for the new passphrase to mount the encrypted partition"
    warn
    HAVE_SET_PASSPHRASE=true
    return 0
}

# FIXME: mention failsafe option or load=all.

#------------------------------------------------------------------------------
# Get error message from args and then print extra info about our search in a
# fatal error message.
#------------------------------------------------------------------------------
linuxfs_error() {
    local msg=$(printf "$@")  device_list=$(echo $DEVICE_LIST)
    local all_devices=$(echo $(most_block_devices));

    _fatal "$msg" \
        "$(printf  "$_Searched_devices_X_" "${hi_co}$device_list")" \
        "$(printf  "$_Searched_types_X_" "${hi_co}$FROM_TYPE")"   \
        "$(printf  "$_All_block_devices_X_" "${hi_co}$all_devices")" \
        "" \
        "$(printf  "$_Please_contact_X_at_Y_" "$DEVELOPER" "$DISTRO_BUG_REPORT_URL")"
}

#------------------------------------------------------------------------------
# Make sure the running kernel has a /lib/modules/$KERNEL directory inside the
# linuxfs file
#------------------------------------------------------------------------------
check_kernel_version() {
    local mp=${1%/}  fatal=$2
    local kversion=$(uname -r)
    local mod_dir=/lib/modules/$kversion

    [ -d $mp$mod_dir ] && return

    if [ "$fatal" ]; then
        _fatal  "$_Kernel_version_mismatch_" \
            "$(printf  "$_Kernel_version_X_" $(pqh $kversion))" \
            "$(printf  "$_The_module_directory_X_is_missing_" $(pqh $mp$mod_dir))"
    else
        _non_fatal  "$_Kernel_version_mismatch_" \
            "$(printf  "$_Kernel_version_X_" $(pqh $kversion))" \
            "$(printf  "$_The_module_directory_X_is_missing_" $(pqh $mp$mod_dir))"
    fi
}

#------------------------------------------------------------------------------
# Load microcode by bind mounting /lib/firmware/.  For some reason this fails
# to work inside a chroot.
#------------------------------------------------------------------------------
load_microcode() {
    local mc_file=/sys/devices/system/cpu/microcode/reload

    [ -z "$NO_MICRO_CODE" -a -e "$mc_file" ] || return
    msg "Load microcode"
    mkdir /lib/firmware
    mount --bind /live/aufs/lib/firmware /lib/firmware
    echo 1 > $mc_file
    #sleep 0.1
    umount /lib/firmware
}

#------------------------------------------------------------------------------
# Seed the random device as best we can
#------------------------------------------------------------------------------
seed_dev_random() {
    local file=$1
    test -r "$file" || return
    vmsg 5  "$_Initializing_random_number_generator_"
    (date +%s.%N ; cat $file 2>/dev/null) >/dev/urandom
}

#------------------------------------------------------------------------------
# Create a new random seed file
#------------------------------------------------------------------------------
prep_seed_dev_random() {
    local i  file=$1  cnt=${2:-32}
    [ -z "$file" ]   && return
    test -e "$file"  || touch $file 2>/dev/null
    test -w "$file"  || return
    # A random seed is used to start the random number generator differently each boot
    msg  "$_Saving_random_seed_"
    dd if=/dev/urandom bs=1 count=512 2>/dev/null > $file
    chmod 600 $file 2>/dev/null
}

#==============================================================================
# Mount things
#==============================================================================

mount_linuxfs() {

    local sqfs_mp=${1:-$SQFS_MP}  sqfile_full=${2:-$SQFILE_FULL}
    local wrap_mp=${3:-$WRAP_FILE_MP}  vid_file=$1$VID_FILE

    mkdir -p $sqfs_mp
    vmsg 6  "Mount file %s at %s" "$(fq $sqfile_full)" "$(fq $sqfs_mp)"
    #. Could not mount <file name> as a <type> filesystem
    log_cmd mount -t squashfs -o loop,ro $sqfile_full $sqfs_mp \
        || fatal_dmesg  "$_Could_not_mount_X_as_a_Y_filesystem_" $sqfile_full squashfs

    if [ -n "$wrap_mp" -a -e "$sqfs_mp/$SQFILE_NAME" -a ! -d "$sqfs_mp/usr" ]; then
        msg 'Found wrapped filesystem. Move wrapper ...'
        mkdir -p $wrap_mp
        mount --move $sqfs_mp $wrap_mp

        try_file_mount  $wrap_mp/$SQFILE_NAME $sqfs_mp ro \
            || fatal_dmesg  "$_Could_not_mount_X_as_a_Y_file_" $sqfile_full 'filesystem'
    fi
    # btrfs subvolume fix
    #LINUXFS_DEV=$(df -P $sqfile_full | tail -n1 | cut -d" " -f1)
    #------------------------
    local P="$sqfile_full" DF x
    set ${sqfile_full//// }
    for x; do 
        P=$(dirname $P)
        if DF="$(df -P $P 2>/dev/null)"; then
           LINUXFS_DEV=$(echo "$DF" | tail -n1 | cut -d" " -f1)
           break
        fi
    done

    #------------------------
    SQFS_VID=$(get_vid $vid_file)

    if [ "$SQFS_VID" ]; then
        vmsg 7 'sqfs_vid: %s' "$nc_co$SQFS_VID"
    else
        #. No <VID> found in <file-name>
        vmsg 7  "$_No_X_found_in_Y_" "$VID_NAME" "$white$vid_file$m_co"
    fi
    SQFS_VID_FILE=$vid_file
}

#------------------------------------------------------------------------------
# Mount the tmpfs part of the union file system
#------------------------------------------------------------------------------
mount_aufs_ram() {
    local aufs_ram_mp=$1  min_aufs_ram=$2  free_mem=$3
    # Default tempfs size for tempfs = 80% of FREE_MEM
    AUFS_RAM_SIZE=$((8 * free_mem / 10))

    [ "$AUFS_RAM_SIZE" -lt "$MIN_AUFS_RAM" ] && AUFS_RAM_SIZE=$MIN_AUFS_RAM
    mkdir -p $aufs_ram_mp

    mount_tmpfs $aufs_ram_mp $AUFS_RAM_SIZE 'aufs ram' || fatal  "$_Create_X_failed_" 'aufs tmpfs'
}

#------------------------------------------------------------------------------
# Sanity checks for the union file system
#------------------------------------------------------------------------------
check_unionfs() {
    test -d /sys/module/aufs    && AUFS_OKAY=true
    test -d /sys/module/overlay && OVERLAY_OKAY=true
    [ "$AUFS_OKAY" ]    && vmsg 6  "$_Found_X_" aufs
    [ "$OVERLAY_OKAY" ] && vmsg 6  "$_Found_X_" overlay

    case $AUFS_OKAY:$OVERLAY_OKAY in
            :)  check_kernel_version / fatal
                fatal  "$_Neither_X_nor_Y_is_available_" aufs overlayfs ;;
    esac

    case $WANT_UNIONFS in
           aufs) want_unionfs "$AUFS_OKAY"     aufs    overlay ;;
        overlay) want_unionfs "$OVERLAY_OKAY"  overlay aufs    ;;
    esac

    [ "$USE_UNIONFS" ] && return

    case  $AUFS_OKAY:$OVERLAY_OKAY in
        true:) USE_UNIONFS=aufs              ;;
        :true) USE_UNIONFS=overlay           ;;
    true:true) USE_UNIONFS=$DEFAULT_UNIONFS  ;;
    esac
}

#------------------------------------------------------------------------------
# Let user specify the type of union file system to use.  This was mostly
# for debugging and may no longer be needed
#------------------------------------------------------------------------------
want_unionfs() {
    local okay=$1  this=$2  other=$3
    if [ "$okay" ]; then
        USE_UNIONFS=$this
    else
        USE_UNIONFS=$other
        non_fatal  "$_The_X_filesystem_is_not_available_Using_Y_" "$this" "$other"
    fi
}

#------------------------------------------------------------------------------
# If a root persistence file already exists then we need to use the same
# type of union file system that was already used on it.
#------------------------------------------------------------------------------
need_unionfs() {
    local okay=$1  this=$2
    if [ "$okay" ]; then
        [ "$USE_UNIONFS" != "$this" ] && warn  "$_Forcing_use_of_X_to_match_existing_rootfs_file_" $(pqw $this)
        USE_UNIONFS=$this
        return 0
    else
        non_fatal  "$_The_X_filesystem_is_not_available_Cant_use_this_Y_file_" "$this" 'rootfs'
        return 1
    fi
}

#------------------------------------------------------------------------------
# Make sure we have the union file system we need based on what was already
# used in the rootfs file.
#------------------------------------------------------------------------------
check_existing_unionfs() {
    local mp=$1  type
    if test -d $mp/etc; then
        need_unionfs "$AUFS_OKAY" aufs || return 1
    elif test -d $mp/upper; then
        need_unionfs "$OVERLAY_OKAY" overlay || return 1
    fi

    case $USE_UNIONFS in
           aufs) ROOTFS_BASE=$ROOTFS_MP                        ;;
        overlay) ROOTFS_BASE=$ROOTFS_MP/upper                  ;;
              *) fatal "Unknown unionfs type: $USE_UNIONFS"    ;;
    esac

    return 0
}

#------------------------------------------------------------------------------
# Mount the union file system
#------------------------------------------------------------------------------
mount_unionfs() {
    local upper_mp aufs_mp=$1  aufs_ram_mp=$3  rootfs_mp=$4

    if [ -n "$PERSIST_ROOT" -a -n "$STATIC_ROOT" ]; then
        #. Enable <type> persistence
        msg  "$_Enable_X_persistence_" "$(pq static rootfs)"
        upper_mp=$rootfs_mp
    else
        STATIC_ROOT=
        upper_mp=$aufs_ram_mp
    fi

    case $USE_UNIONFS in
        overlay) mount_overlayfs "$1" "$2" $upper_mp  ;;
           aufs) mount_aufs      "$1" "$2" $upper_mp  ;;
              *) fatal "Unknown unionfs type: $USE_UNIONFS"
    esac

    # Grab what we need from /etc before it gets nuked
    cp -a /etc/mtab $aufs_mp/etc/

    # Always a good idea
    mkdir -p   $aufs_mp/tmp $aufs_mp/var/tmp
    chmod 1777 $aufs_mp/tmp $aufs_mp/var/tmp
}

#------------------------------------------------------------------------------
# Mount an overlay(fs) file system
#------------------------------------------------------------------------------
mount_overlayfs() {
    local  aufs_mp=$1  sqfs_mp=$2  upper_mp=$3

    local upper=$upper_mp/upper work=$upper_mp/work
    mkdir -p $aufs_mp $upper $work

    # Do the actual mount
    vmsg 6 'Mount %s at %s' 'overlayfs' "$(fq $aufs_mp)"

    log_cmd mount -t overlay overlay -o "lowerdir=$sqfs_mp,upperdir=$upper,workdir=$work" $aufs_mp \
        || fatal_dmesg  "$_Could_not_mount_X_" overlayfs
}


mount_aufs() {
    local  aufs_arg  aufs_mp=$1  sqfs_mp=$2  upper_mp=$3

    mkdir -p $aufs_mp
    local aufs_arg="br:$upper_mp:$sqfs_mp=ro$NO_PLINK"

    # Do the actual aufs mount
    vmsg 5  "Mount %s at %s" 'aufs' "$(fq $aufs_mp)"

    log_cmd mount -t aufs -o "$aufs_arg",noatime $aufs_mp $aufs_mp \
        || fatal_dmesg  "$_Could_not_mount_X_" aufs
}

#------------------------------------------------------------------------------
# Not used (very old)
#------------------------------------------------------------------------------
link_top_dirs() {
    local mp=$1  dir  mp_dir
    shift
    vmsgN 7 'symlink: '
    for dir; do
        mp_dir=$mp/$dir
        [ -d $mp_dir ] || continue
        rm -rf /$dir
        ln -s $mp_dir /$dir
        vmsgN 7 "$white/$dir "
    done
    vmsg 7
}

#------------------------------------------------------------------------------
# Try to mount a device.  Ignore error messages.  Using blkid to find the
# fstype makes this faster and more effient.  I wonder if the busybox mount
# command can figure out the file system type now?
#------------------------------------------------------------------------------
try_mount() {
    unset DECRYPT_DEV
    _try_mount "$@"
}

_try_mount() {
    local dev=$1  mp=$2  rw=${3:-$RW_MODE}
    local type=${4:-$(blkid $dev | sed -n -r 's/.* TYPE="([^"]*)"$/\1/p' | tail -n 1)}
    [ "$type" ] || return 1
    local opts=$rw,noatime
    local winopts=umask=000,dmask=002,fmask=113
    local ntfsopts=recover,rw,$winopts,uid=$USER_UID,gid=$USER_GID
    local fatopts=$winopts,shortname=winnt,uid=$USER_UID,gid=$USER_GID
    local exfatopts=$winopts

    case $type in
     crypto_LUKS) try_luks_mount "$@" ;;
            ext4) log_cmd mount -t $type   -o $opts$LAZYTIME  $dev "$mp" 2>/dev/null ;;
        ext[234]) log_cmd mount -t $type   -o $opts           $dev "$mp" 2>/dev/null ;;
           exfat) modprobe -q exfat                                      2>/dev/null
                  log_cmd mount -t $type   -o $exfatopts      $dev "$mp" 2>/dev/null ;;
            f2fs) modprobe -q f2fs                                       2>/dev/null
                  log_cmd mount -t $type   -o $opts           $dev "$mp" 2>/dev/null ;;
            vfat) modprobe -q nls-cp437                                  
                  log_cmd mount -t vfat    -o $fatopts        $dev "$mp" 2>/dev/null ;;
         iso9660) log_cmd mount -t iso9660 -o ro              $dev "$mp" 2>/dev/null ;;
             udf) log_cmd mount -t udf     -o ro              $dev "$mp" 2>/dev/null ;;
            ntfs) log_cmd ntfs-3g          -o $ntfsopts       $dev "$mp" 2>/dev/null 17>/dev/null || \
                  log_cmd mount -t ntfs    -o umask=000,ro    $dev "$mp" 2>/dev/null ;;
               *) log_cmd mount -t $type   -o $opts           $dev "$mp" 2>/dev/null ;;
    esac
    local ret=$?
    return $ret
}

#------------------------------------------------------------------------------
# Mount a LUKS encrypted partition.  Call _try_mount recursively.  But only do
# this if TRY_LUKS is non-empty to avoid asking for a password for every LUKS
# partition when we're scanning.
#------------------------------------------------------------------------------
try_luks_mount() {
    [ -z "$TRY_LUKS" ] && return 1
    local dev=$1  mp=$2  rw=${3:-$RW_MODE}
    test -x /bin/cryptsetup || fatal "Could not find the %s program for device %s" "cryptsetup" "$dev"
    msg "try_luks_mount(%s)" "$(pq $*)"
    # Don't decrypt the same device twice
    if echo -e "$CRYPT_TAB" | grep -q "^$dev:"; then
        local map_name=$(echo -e "$CRYPT_TAB" | sed -rn "s|^$dev:([^:]+):?.*|\1|p")
        msg "Device %s already decrypted at %s" "$(cqw $dev)" "$(cqw $map_name)"
        local map_dev=/dev/mapper/$map_name
        _try_mount "$map_dev" "$mp" "$rw"
        return $?
    fi

    echo -e "$TRIED_LUKS" | grep -q "^$dev$" && return 3
    TRIED_LUKS="$TRIED_LUKS$dev\n"

    local i map_dev map_name
    for i in $(seq 1 20); do
        map_name=live-$(printf "%02d" $i)
        map_dev=/dev/mapper/$map_name
        test -e $map_dev || break
    done
    test -e $map_dev && fatal "Could not mount yet another encrypted partition"

    tsplash_off
    if [ -n "$DECRYPT_ASK" -a -n "${TRY_LUKS#nested*}" ]; then
        YES_no "Do you want to decrypt %s device %s" "$(pq $TRY_LUKS)" "$(pq ${dev##*/})" || return 2
    fi
    warn "You will be asked for the passphrase of the %s partition" "$(cqw $TRY_LUKS)"
    cttyhack cryptsetup open $dev $map_name || fatal "$_Could_not_open_LUKS_device_X_" $dev
    test -e $map_dev || fatal "Was unable to mount encrypted device %s" "$dev"
    CRYPT_TAB="$CRYPT_TAB$dev:$map_name:$mp\n"
    DECRYPT_DEV=$map_dev
    TRY_LUKS=$(printf "nested %s" "$TRY_LUKS")
    msg "_try_mount($map_dev $mp $rw)"
    _try_mount "$map_dev" "$mp" "$rw"
    local ret=$?

    tsplash_on

    return $ret
}

#------------------------------------------------------------------------------
# Try to mount a filesystem-on-a-file.  Only try ext[234} and try 4 first
#------------------------------------------------------------------------------
try_file_mount() {
    local file=$1  mp=$2  rw=${3:-$RW_MODE}
    local opts=loop,$rw,noatime

    #mount -t reiserfs         -o loop,$rw,noatime "$file" "$mp"  2>/dev/null || \
        mount -t ext4 -o $opts$LAZYTIME "$file" "$mp"  2>/dev/null || \
        mount -t ext3 -o $opts          "$file" "$mp"  2>/dev/null || \
        mount -t ext2 -o $opts          "$file" "$mp"  2>/dev/null
    return $?
}

#------------------------------------------------------------------------------
# Function: mount_tmpfs <mountpoint> <size> <name> <mode>
#------------------------------------------------------------------------------
mount_tmpfs() {
    local mp=$1  size=$2  name=$3  opts=${4+,}$4
    mkdir -p $mp
    local full_name=$(printf "%14s" "$name tmpfs")
    local   full_mp=$(printf "%-20s" "$mp")
    #. Create <something tmpfs> at <directory> <(size)>
    vmsg 8  "$_Create_X_at_Y_Z_" "${hi_co}$full_name${m_co}" "$(fq "$full_mp")" "(${num_co}$size ${m_co}MB)"
    log_cmd $LIVE_BIN/mount -t tmpfs -o size=${size}m$opts,noatime tmpfs $mp
    return $?
}

#------------------------------------------------------------------------------
# Try a lazy umount and throw an error if the mp is still mounted.  Use with
# caution.
#------------------------------------------------------------------------------
lazy_umount() {
    local mp=$1
    log_cmd umount -l $mp
    mountpoint -q $mp && non_fatal "Was not able to unmount $mp"
}

#==============================================================================
# Check Filesystems
#==============================================================================

read_superblock() {
    local dev=$1
    local word_size=$((2**16))
    local addr f1 f2 f3 f4 f5 f6 f7 f8

    while read addr f1 f2 f3 f4 f5 f6 f7 f8; do
        case $addr in
            0000030)
                echo SB_MOUNT_CNT=$f3
                echo SB_MAX_MOUNT_CNT=$f4
                echo SB_MAGIC=$f5
                echo SB_STATE=$f6
                ;;
            0000040)
                echo SB_LASTCHECK=$((    f2 * word_size + f1))
                echo SB_CHECKINTERVAL=$((f4 * word_size + f3))
                ;;
        esac
    done <<DD_Hexdump
$(dd if=$dev bs=1 skip=1024 count=128 2>/dev/null| hexdump -d | sed -r "s/ 0+([0-9])/ \1/g")
DD_Hexdump
}

#------------------------------------------------------------------------------
# See if it is time to run our regular fsck
#------------------------------------------------------------------------------
should_fsck() {
    local dev=$1  sdev=${1##*/}  name=$2  max_count=$MAX_MOUNT_CNT
    [ "$DO_FSCK" ] || return 1

    case ,$DID_FSCK, in
        *,$dev,*) return 1
    esac

    DID_FSCK=$DID_FSCK,$dev

    local SB_MOUNT_CNT SB_MAX_MOUNT_CNT SB_MAGIC SB_STATE SB_LASTCHECK SB_CHECKINTERVAL

    eval $(read_superblock $dev)

    if [ "$SB_MAGIC" != 61267 ]; then
        [ "$FORCE_FSCK" ] \
            && msg 'Cannot check %s filesystem on device %s.  Not an ext2/3/4 filesystem.' \
                "$(pq $name)" "$(pq $sdev)"
        return 1
    fi

    local days=$((SB_CHECKINTERVAL /60/60/24))

    vmsg 7  "precheck filesystem on %s"                     $(dq $dev)
    if [ "$DB_PLUS" ]; then
        vmsg 9 "${green}         Device:$white %s"             $dev
        vmsg 9 "${green}    Mount count:$white %s"             $SB_MOUNT_CNT
        vmsg 9 "${green}Max mount count:$white %s"             $SB_MAX_MOUNT_CNT
        vmsg 9 "${green}   Last checked:$white %s"             "$(date --date=@$SB_LASTCHECK)"
        vmsg 9 "${green}   Magic number:$white 0x%04X"         $SB_MAGIC
        vmsg 9 "${green} Check interval:$white %d$m_co (days)" $days
    fi

    [ "$FORCE_FSCK" ] && return 0

    if [ $SB_STATE != 1 ]; then
        # <boot> device <device-name> not cleanly unmounted.  Check forced.
        warn  "%s device %s not cleanly unmounted.  Check forced." "$(pqw $name)" $(pqw $sdev)
        return 0
    fi

    [ "$SB_MAX_MOUNT_CNT" != 65535 ] && max_count=$SB_MAX_MOUNT_CNT

    if [ $SB_MOUNT_CNT -ge $max_count ]; then
        # <boot> device <device-name> has not been checked in <32> mounts.  Check forced.
        warn  "%s device %s has not been checked in %s mounts.  Check forced." \
            "$(pqw $name)" $sdev "$(nq $SB_MOUNT_CNT)"
        return 0
    fi

    [ $SB_CHECKINTERVAL -gt 0 ] || return 1

    [ $((SB_LASTCHECK + SB_CHECKINTERVAL)) -ge $(date +%s) ] || return 1

    # <boot> device <device-name> has not been checked in <100> days.  Check forced.
    warn  "%s device %s has not been checked in %s days.  Check forced." \
        $(pqw $name) $(pqw $sdev) "$(nqw $days)"
    return 1
    return 0
}

#------------------------------------------------------------------------------
# Peform fsck when asked or when we think we are ready.
#------------------------------------------------------------------------------
do_fsck() {
    local err ret  name=$1 dev=$2  sdev=$(pq ${2##*/}) opts=${3:--n} filefs=$4

    # Use a fifo so we can get the return status and tee the output
    local fifo=/tmp/pipe
    rm -f $fifo
    mkdir -p $(dirname $fifo)
    mkfifo $fifo
    tee -a $MY_LOG < $fifo &

    msg  "$_check_X_filesystem_" "$(pq $name)"

    #breakpoint F "Before fsck"

    vmsg 2 "fsck$white $dev"
    ld_path /sbin/e2fsck $opts $dev &> $fifo
    ret=$?

    rm -f $fifo

    ld_path /sbin/tune2fs -C 1 $dev

    #breakpoint F "After fsck"

    case $ret in
	    0) vmsg 1     "$_There_were_no_errors_on_X_"            "$sdev" ; err=0 ;;
	    1) vmsg 1    'Filesystem %s repaired'                "$sdev" ; err=0 ;;
	  2|3) vmsg 1    'Filesystem %s repaired'                "$sdev" ; err=0 ;;
	    4) non_fatal 'Errors on %s left uncorrected'         "$sdev" ; err=1 ;;
	    8) non_fatal '%s operational error on %s'       fsck "$sdev" ; err=1 ;;
	   12) non_fatal '%s interrupted on %s'             fsck "$sdev" ; err=1 ;;
	   32) non_fatal '%s cancelled on %s'               fsck "$sdev" ; err=1 ;;
	    *) non_fatal 'Filesystem %s could not be fixed'      "$sdev" ; err=1 ;;
	esac

    return $err
}

#------------------------------------------------------------------------------
# ?????????????????
#------------------------------------------------------------------------------
fsck_any_device() {
    local dev=$(readlink -f "$1")  mp=$2  lab=$3
    [ -n "$mp" -a -n "$dev" ] || return

    local type=$(grep "^$dev " /proc/mounts | cut -d" " -f3)

    if [ -n "$FORCE_FSCK" -a -n "${type##ext[234]}" ]; then
        msg 'Cannot check %s device filesystem of type %s' "$(pq $lab)" "$(pq $type)"
        return
    fi

    should_fsck $dev $lab || return

    log_cmd mount -o remount,ro $dev
    do_fsck "$lab device" $dev -n
}

#==============================================================================
#   Misc Functions
#==============================================================================

set_path() {
    PATH=$1
    hash -r
}

#------------------------------------------------------------------------------
# See if this break point was specified in the bp= boot parameter
#------------------------------------------------------------------------------
should_break_at() {
    local bp=$1
    case ,$BREAK_POINTS, in
        *,$bp,*) return 0 ;;
          *,A,*) return 0 ;;
          *,a,*)          ;;
              *) return 1 ;;
    esac
    case $bp in
        [e1-9]) return 0 ;;
             *) return 1 ;;
    esac
}

#------------------------------------------------------------------------------
# Run custom code labeled by breakpoint
#------------------------------------------------------------------------------
custom_code() {
    local file=$1  desc=$2
    local base=${DISTRO_BASE:=$DISTRO_NAME}
    local distro=${DISTRO_NAME}

    if [ "${#file}" -eq 1 ]; then
        if [ -r $CUSTOM_DIR/$base/$file.sh ]; then
           file=$CUSTOM_DIR/$base/$file.sh
        else
           file=$CUSTOM_DIR/$distro/$file.sh
        fi
    fi
    [ -r $file ] || return

    if $LIVE_BIN/sh -n $file; then
        [ "$desc" ] && vmsg 7 'Run custom code %s: %s' "$white$desc$m_co" "$(fq $file)"
        . $file
    else
        non_fatal 'Errors found in custom code: %s.  Skipping' "$(pqh $file)"
    fi
}

#------------------------------------------------------------------------------
# Actually do the break point as specified in "bp=x,y,z"
# Try to account for time spent inside the breakpoint (may not always work)
#------------------------------------------------------------------------------
breakpoint() {
    local bp=$1  desc=$2

    custom_code "$bp" "$desc"

    if [ "$DB_PLUS" -a -n "${bp##b*}" ]; then
        local now=$(get_time)
        local delta=$(get_seconds $((now - LAST_BP_TIME)))
        vmsg 8 "$green@bp$cyan[$num_co$bp$m_co]$hi_co %5ss (%5s)$m_co: %s" "$(get_seconds $now)" "$delta" "$desc"
        #vmsg 8 'Available entropy %s' "$(pq $(cat /proc/sys/kernel/random/entropy_avail 2>/dev/null))"
        LAST_BP_TIME=$now
    fi

    should_break_at $bp || return

    tsplash_off

    case $bp in
        bash*|b[1-9]) do_bash_chroot $bp ; tsplash_on; return ;;
    esac

    echo "$green$tbar$nc_co"
    echo "$green==>$cyan limited shell @ breakpoint [$num_co$bp$cyan]$white $desc"
    echo "$green    Use the$white exit$green command or press$white Ctrl-d$green to continue"
    echo "$green    Use$white safe-poweroff$green and$white safe-reboot$green to poweroff and reboot"

    local bp_time_1=$(get_time)

    sync

    trap - $SIGNAL_LIST

    env PS1="${green}bp $red$bp$cyan>$nc_co " BP=$bp PATH=$LIVE_BIN:$PATH \
        setsid cttyhack sh 17>/dev/null

    trap "" $SIGNAL_LIST

    [ "$bp" != 'e' ] && tsplash_on

    bp_time_2=$(get_time)

    time_0=$((time_0 + bp_time_2 - bp_time_1))
    echo
}

#------------------------------------------------------------------------------
# Do a "bash" breakpoint which entails chrooting into the system and running
# Bash.  We do some "clever" things so "shutdown" and "reboot" commands do
# the right thing, which is to exit the shell and signal us to either run
# safe-shutdown or safe-reboot.
#------------------------------------------------------------------------------
do_bash_chroot() {

    local rc_file=/root/chrootrc bp=${1:-bash} root_dir=${2:-$NEW_ROOT}

    cat<<Chroot_RC > $root_dir$rc_file
alias shutdown="touch /poweroff; exit &>/dev/null"
alias poweroff="touch /poweroff; exit &>/dev/null"
alias reboot="touch /reboot; exit &>/dev/null"
source /root/.bashrc
rm $rc_file
Chroot_RC

    echo "$green$tbar$nc_co"
    echo "$green==>$cyan Bash shell @ breakpoint [$num_co$bp$cyan]$white $desc"
    echo "$green    Use the$white exit$green command or press$white Ctrl-d$green to boot"
    echo "$green    Use$white poweroff$green and$white reboot$green to poweroff and reboot"

    rm -f $root_dir/poweroff $/root_dir/reboot

    trap - $SIGNAL_LIST

    setsid cttyhack aufs-chroot bash --init-file $rc_file

    trap "" $SIGNAL_LIST

    local do_poweroff do_reboot
    test -e $root_dir/poweroff && do_poweroff=true
    test -e $root_dir/reboot   && do_reboot=true
    rm -f $root_dir/poweroff $root_dir/reboot
    [ "$do_poweroff" ] && safe-poweroff
    [ "$do_reboot" ]   && safe-reboot
}

db_msg() { vmsg 5 "${green}db+:$hi_co $@" ;}
err()    { vmsg 1 "$err_co$@"             ;}
msg()    { vmsg 5 "$@"                    ;}
msgN()   { vmsgN 5 "$@"                   ;}
msg_nc() { vmsg 5 "$nc_co$@"              ;}
warn()   { vmsg 3 "$warn_co$@"            ;}

bq()     { echo "$yellow$*$m_co"          ;}
cq()     { echo "$cheat_co$*$m_co"        ;}
cqw()    { echo "$cheat_co$*$warn_co"     ;}
cqe()    { echo "$cheat_co$*$err_co"      ;}
dq()     { echo "$dev_co$*$m_co"          ;}
dqe()    { echo "$dev_co$*$err_co"        ;}
fq()     { echo "$from_co$*$m_co"         ;}
fqe()    { echo "$from_co$*$err_co"       ;}
mpq()    { echo "$mp_co$*$m_co"           ;}
nq()     { echo "$num_co$*$m_co"          ;}
nqw()    { echo "$num_co$*$warn_co"       ;}
pq()     { echo "$hi_co$*$m_co"           ;}
pqe()    { echo "$bold_co$*$err_co"       ;}
pqw()    { echo "$hi_co$*$warn_co"        ;}
pqh()    { echo "$m_co$*$hi_co"           ;}
hq()     { echo "$hi_co$*$m_co"           ;}
ncq()    { echo "$hi_co$*$nc_co"          ;}
gq()     { echo "$hi_co$*$lt_green"       ;}

#------------------------------------------------------------------------------
# vmsg N "fmt" <params>
# Always put the message in the log file.  Display on screen only if the
# Current verbosity is N or greater.
#------------------------------------------------------------------------------
vmsg() {
    local level=$1  fmt=$2
    shift 2

    msg=$(printf "$m_co$fmt$nc_co" "$@")

    [ "$level" -le "$VERBOSE" ] && echo -e "$msg"
    echo -e "$msg" >> $MY_LOG
    return 0
}

#------------------------------------------------------------------------------
# Do not add the final "\n" to the message
#------------------------------------------------------------------------------
vmsgN() {
    local level=$1  fmt=$2
    shift 2

    msg=$(printf "$m_co$fmt$nc_co" "$@")

    [ "$level" -le "$VERBOSE" ] && printf "$msg"
    echo -ne "$msg" >> $MY_LOG
    return 0
}

#------------------------------------------------------------------------------
# Only add it to the log file if verbosity is >= N
#------------------------------------------------------------------------------
vmsg_if() {
    local level=$1; shift
    [ "$VERBOSE" -ge "$level" ] || return
    vmsg $level "$@"
}

#------------------------------------------------------------------------------
# Start the message out without color
#------------------------------------------------------------------------------
vmsg_nc() {
    local level=$1; shift
    vmsg $level "$nc_co$@"
}

#------------------------------------------------------------------------------
# Set a bunch of lowercase global variables for handling ANSI color.
#------------------------------------------------------------------------------
set_colors() {
    local noco=$1  loco=$2

    [ "$noco" ] && return

    local e=$(printf "\e")
     black="$e[0;30m";    blue="$e[0;34m";    green="$e[0;32m";    cyan="$e[0;36m";
       red="$e[0;31m";  purple="$e[0;35m";    brown="$e[0;33m"; lt_gray="$e[0;37m";
   dk_gray="$e[1;30m"; lt_blue="$e[1;34m"; lt_green="$e[1;32m"; lt_cyan="$e[1;36m";
    lt_red="$e[1;31m"; magenta="$e[1;35m";   yellow="$e[1;33m";   white="$e[1;37m";
     nc_co="$e[0m";

    cheat_co=$white;      err_co=$red;       hi_co=$white;
      cmd_co=$white;     from_co=$lt_green;  mp_co=$magenta;   num_co=$magenta;
      dev_co=$magenta;   head_co=$yellow;     m_co=$lt_cyan;    ok_co=$lt_green;
       to_co=$lt_green;  warn_co=$yellow;  bold_co=$yellow;

    [ "$loco" ] || return

    from_co=$brown
      hi_co=$white
       m_co=$nc_co
     num_co=$white
}

#------------------------------------------------------------------------------
# Get the time since the kernel started in hundredths of secondes
#------------------------------------------------------------------------------
get_time() { cut -d" " -f22 /proc/self/stat ;}

show_time() {
    msg "$(printf "$green%ss$yellow %s" $(get_seconds) "$*")"
}

#------------------------------------------------------------------------------
#  Add the decimal point to convert the above to seconds
#------------------------------------------------------------------------------
get_seconds() {
    local dt=${1:-$(get_time)}
    printf "%03d" $dt | sed -r 's/(..)$/.\1/'
}

#------------------------------------------------------------------------------
# Marching dots (sigh)
#------------------------------------------------------------------------------
bogo_meter() {
    local width=${1:-$SCREEN_WIDTH} delay=60  dot=.
    local cnt=$(( width * 80 / 100 ))
    local sleep=$(( 1000000 * delay / cnt ))
    while true; do
        for s in $(seq 1 $cnt); do
            usleep $sleep
            echo -n "$dot"
        done
        echo
    done
}

#------------------------------------------------------------------------------
# Run a command, show marching dots and record how long the command took.
#------------------------------------------------------------------------------
time_cmd() {
    local t0=$(get_time)
    (bogo_meter)&
    local pid=$!
    "$@"
    local ret=$?
    sync
    local t1=$(get_time)
    local secs=$(get_seconds $((t1 - t0)))
    kill -9 $pid
    echo
    vmsg 6  "command %s took %s seconds" "$(pq $*)" "$(nq $secs)"
    return $ret
}

#------------------------------------------------------------------------------
# Not used
#------------------------------------------------------------------------------
vmsg_old() {
    local msg nflag  level=$1; shift

    [ "$1" = "-n" ] && nflag=true && shift
    local fmt=$1; shift

    if [ "$nflag" ]; then
        msg="$(printf "$m_co$fmt$nc_co" "$@")"
    else
        msg="$(printf "$m_co$fmt$nc_co" "$@")\n"
    fi

    [ "$level" -le "$VERBOSE" ] && printf "$msg"
    echo -ne "$msg" >> $MY_LOG

    return 0
}

#------------------------------------------------------------------------------
# Print a nice heading when we are doing something major
#------------------------------------------------------------------------------
heading() {
    vmsg 6 $head_co$tbar
    #. Begin [doing some sub process]
    vmsgN 3 "$hi_co%s "  "$_Begin_"
    vmsg 3 "$@"
}

#------------------------------------------------------------------------------
# Add command to log file, show it to screen a v=8 or greater
#------------------------------------------------------------------------------
log_cmd() {
    vmsg_nc 8 "$*"
    #"$@" >/dev/null
    "$@"
    return $?
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
_error() {
    local type=$1  cmsg1=$2  cmsg2=$3  msg=$4
    shift 3
    tsplash_clear

    local match="$(echo $NO_ERROR | sed 's/_/ /g')"
    if [ "$NO_ERROR" -a -z ${msg##$match*} ]; then
        msg  "$_Skip_Error_X_" "$(bq $msg)"
        return
    fi

    if [ "$type" ]; then
        warn
        #warn $hbar
        err "$type"
        #warn $hbar
        [ "$1" ] && vmsg 1 "${hi_co}$1"
        shift
        for arg; do
            vmsg 1 "${hi_co}$arg"
        done
        ### warn $hbar
        err
    fi

    breakpoint e "On possibly fatal error"

    local prompt="${green}Select ${yellow}$cmsg1 p$green or$yellow r$green then press <enter>"


    local fmt="    $yellow%s$cyan =$white %s$nc_co\n"
    local reply
    while [ true ]; do
        ### echo $m_co$tbar$nc_co

        [ "$cmsg1" ] && printf "$fmt" "$cmsg1" "$cmsg2"
        printf "$fmt" p  "$_power_off_"
        printf "$fmt" r  "$_reboot_"

        ### echo $m_co$tbar$nc_co
        echo -n "$prompt$nc_co "
        read reply
        case $reply in
            p*|P*)
                echo  "$_power_off_" " ..."
                safe_shutdown poweroff;;

            r*|R*)
                echo  "$_reboot_"  " ..."
                safe_shutdown reboot;;

             c*|C*)
                 if [ "$cmsg1" ]; then
                     tsplash_on
                     return
                 fi ;;
        esac
        printf "\n${m_co} %s: >>$yellow$reply$m_co<<. %s:$nc_co\n" \
             "$_Unknown_command_"  "$_Please_try_again_"
    done
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
move_mountpoints() {
    local dir mp old aufs_live=/live/aufs$FINAL_DIR

    [ -d $aufs_live ] || return

    for dir in $(ls $aufs_live); do
        [ "$dir" = aufs ] && continue
        mp=$aufs_live/$dir
        mountpoint -q $mp || continue
        old=/live/$dir
        mkdir -p $old
        # echo mount --move $mp $old
        mount --move $mp $old
    done
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
mountpoint_list() {
    local dev mp other ret=1

    while read dev mp other; do
        case $mp in /|/dev|/dev/*|/proc|/sys) continue;; esac
        echo -n "$mp "
        ret=0
    done << Read_Mounts
$(tac /proc/mounts)
Read_Mounts
    return $ret
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
final_umount() {
    local mp list i
    move_mountpoints

    for i in $(seq 1 4); do
        list=$(mountpoint_list) || return 0
        for mp in $list; do
            umount $mp
        done
    done
    list=$(mountpoint_list) || return 0
    err  "Unable to unmount %s" "$(pq $list)"
    return 1
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
safe_shutdown() {
    local cmd=$1  ask=$2

    set_path $LIVE_BIN

    final_umount && vmsg 1  "$_Unmount_successful_"
    #breakpoint u "final umount"
    if [ "$ask" ]; then
        vmsgN 1  "$_Press_X_to_Y_" "<$(bq  "$_Enter_")>" "$(hq $cmd)"
        read x
    fi
    vmsg -1  "$_Will_now_X_the_system_" "$(hq $cmd)"
    exec $cmd -f -n
}

_fatal()     { _error  "$_Fatal_Error_"     ""  ""          "$@" ;}
_non_fatal() { _error  "$_Non_Fatal_Error_" "c"  "$_continue_"  "$@" ;}
fatal()      { _fatal     "$(printf "$@")"                   ;}
non_fatal()  { _non_fatal "$(printf "$@")"                   ;}


#------------------------------------------------------------------------------
# Show last 10 lines of dmesg before the error message
#------------------------------------------------------------------------------
fatal_dmesg() {
    tsplash_only_clear
    local lines=10
    printf 'Last %s lines of the dmesg output:\n' "$lines"
    printf "%s\n" "$rbar"
    dmesg | tail -n$lines
    printf "%s\n" "$lbar"
    printf 'Kernel: %s\n' "$(uname -r)"

    fatal "$@"
}

YES_no() {  _yes_no 0  "$_yes_" "$@" ;}
yes_NO() {  _yes_no 1  "$_no_"  "$@" ;}

_yes_no() {
    tsplash_clear
    local def_ret=$1  def_lab=$(cq $2)
    shift 2
    local ans title=$(printf "$m_co$@")
    local yes=$(cq  "$_yes_")  no=$(cq  "$_no_")  y_lett=$(bq y) n_lett=$(bq n)

    local err_msg=$(printf  "$_You_must_answer_X_or_Y_Please_try_again_" $(pqe y) $(pqe n))
    while true; do
        echo -e "$title"
        printf "${m_co}$y_lett=$yes. $n_lett=$no. %s $def_lab\n"  "$_The_default_is_"
        echo -n "$green>$nc_co "

        read ans
        case x$ans in
            x[Yy]*) return 0;;
            x[Nn]*) return 1;;
        esac

        [ -z "$ans" ] && return $def_ret
        printf "$err_co%s$nc_co\n" "$err_msg"
    done
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
my_select() {
    local title=$1  var=$2  width=${3:-0}  default=$4
    shift 4

    local data display lab cnt=0 dcnt
    for lab; do
        cnt=$((cnt+1))
        dcnt=$cnt

        [ "$lab" =  "$_quit_" ] && dcnt=0
        data="${data}$dcnt:$lab\n"

        [ "$lab" =  "$_quit_" ] && lab=$bold_co$lab$nc_co

        # Highlight "G" and "M" numerical suffix
        if echo "$lab" | egrep -q "^[0-9]+[GM]iB$"; then
            local num=${lab%[GM]iB}
            local suffix=${lab#$num}
            lab="$num $suffix"
        fi
        [ $cnt = "$default" ] && lab=$(printf "%${width}s (%s)" "$lab" "$(cq  "$_default_")")
        display="${display}$(printf "$green%2d$white)$cyan %${width}s" $dcnt "$lab")\n"
    done

    my_select_2 "$title" $var "$default" "$data" "$display"
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
my_select_2() {
    local title=$1  var=$2  default=$3  data=$4  display=$5
    local def_prompt=$(printf  "$_Press_X_for_the_default_selection_" "$(cq  "$_Enter_")")

    local val input err_msg
    while [ -z "$val" ]; do

        echo -e "$hi_co$title$nc_co"
        #printf "$display\n" | sed -r -e "s/(^|\t)( ?[0-9]+)(\))/\t$green\2$white\3$cyan/g" -e "s/$/$nc_co/"
        #printf "$display" | sed -r -e "s/(^|\t| )( ?[0-9]+)(\))/\t$green\2$white\3$cyan/g" -e "s/$/$nc_co/"
        printf "$display\n" | sed "s/$/$nc_co/"
        [ "$err_msg" ] && printf "$err_co%s$nc_co\n" "$err_msg"
        [ "$default" ] && printf "$m_co%s$nc_co\n" "$def_prompt"
        echo -n "$green>$nc_co "

        read input
        err_msg=
        [ -z "$input" -a -n "$default" ] && input=$default

        if ! echo "$input" | grep -q "^[0-9]\+$"; then
            err_msg="You must enter a number"
            [ "$default" ] && err_msg="You must enter a number or press <enter>"
            continue
        fi

        val=$(echo -e "$data" | sed -n "s/^$input://p" | cut -d: -f1)

        if [ -z "$val" ]; then
            err_msg=$(printf  "$_The_number_X_is_out_of_range_" "$(pqe $input)")
            continue
        fi

        eval $var=\$val
        break
    done
}

# Note: we use cmdline2 for non-menu cmdline additions so they don't get used
# by the grub2-save program and inserted into grub.cfg.
initialize_cmdline2() {
    touch /live/config/cmdline /live/config/cmdline2

    local cmdline
    if [ ${#DISABLE_SERVICES} -gt 0 ]; then
        [ -z "${DISABLE_SERVICES##*S*}" ] && cmdline="$cmdline${cmdline:+ }savestate"
        [ -z "${DISABLE_SERVICES##*s*}" ] && cmdline="$cmdline${cmdline:+ }nosavestate"
        [ -z "${DISABLE_SERVICES##*r*}" ] && cmdline="$cmdline${cmdline:+ }norepo"
        [ -z "${DISABLE_SERVICES##*k*}" ] && cmdline="$cmdline${cmdline:+ }noloadkeys"
        [ -z "${DISABLE_SERVICES##*V*}" ] && cmdline="$cmdline${cmdline:+ }vboxdecor"
        # if [ -z "${DISABLE_SERVICES##*c*}" ]; then
        #     local desk_delay=$(echo $DISABLE_SERVICES | sed -r 's/[^c]*c([0-9]+(\.[0-9]*)?|\.[0-9]+|).*/\1/')
        #     cmdline="$cmdline${cmdline:+ }deskdelay=${desk_delay:-0}"
        # fi
        [ "$cmdline" ] && echo "$cmdline" >> /live/config/cmdline2
    fi
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
my_select_menu() {
    local dir=$BOOT_MENU_DIR do_menu=$DO_MENUS
    unset MENU_VALUE
    [ "$do_menu" ] || return

    local title=$1  blurb=$2  cheat=$3  dfile=$dir/$4.data mfile=$dir/$4.menu  label=$5  fields=$6

    [ -z "${do_menu##*$cheat*}" ] || return

    tsplash_clear

    local def_label
    local data=$(cat $dfile)

    if [ ! -e $dfile ]; then
        [ "$BOOT_MENU_WARN" ] && warn "Missing $dfile"
        return
    fi

    local menu=$(read_menu_file $mfile)
    [ -z "$menu" ] && return

    [ "$blurb"     ] && title="$title\n$blurb"
    [ "$fields"    ] && def_label=$(get_default_label "$fields" $dfile)

    if [ "$def_label" ]; then
        title=$(printf "$title\n%s:$bold_co %s"  "$_Current_default_" "$def_label")
        data="0:reset\n$data"
        menu="$(printf "  ${green}0$white)$cyan %s\n%s"  "$_Reset_" "$menu")"
    fi

    my_select_2 "$title" MENU_VALUE 1 "$data" "$menu"

    local new_label
    [ "$MENU_VALUE" ] && new_label=$(egrep "^[0-9]+:$MENU_VALUE[: ]" $dfile | cut -d: -f3)

    case $MENU_VALUE in
        default) [ -n "$def_label" ] && msg  "$_Keeping_default_X_" "$(bq $def_label)"          ;;
              *) [ -n "$def_label" ] && msg  "$_Previous_default_X_erased_" "$(bq $def_label)"
                 PROC_CMDLINE=$(filter_cmdline "$fields" $PROC_CMDLINE)                      ;;
    esac

    #. <Timezone> set to <Denver>
    case $MENU_VALUE in
        default|none|reset)                            ;;
                   *) [ -n "$new_label" ] && msg  "$_X_set_to_Y_" "$label" "$(bq $new_label)"
                      cmdline="$cmdline $MENU_VALUE"   ;;
    esac
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
read_menu_file() {
    local name=$1
    local mfile=$(xlat_mfile "$mfile" $LANG)

    if [ ! -e $dfile -o  ! -e $mfile ]; then
        [ "$BOOT_MENU_WARN" ] && warn "Missing $dfile or $mfile"
        return 1
    fi

    local default_str=$(rpad 16  "$_Default_")

    cat $mfile | sed -r \
        -e "s/Default( {8}| *$)/$default_str/" \
        -e "s/( [0-9]+)(\))/$green\1$white\2$cyan/g" \
        -e "s/\*/$bold_co*$cyan/g" \
        -e "s/\(([^)]+)\)/$nc_co(\1)$cyan/g"

    return 0
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
rpad() {
    local width=$1  str=$2
    local pad=$((width - $(echo $str | wc -m)))
    [ $pad -le 0 ] && pad=0
    printf "%s%${pad}s" "$str" ""
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
get_default_label() {
    local fields=$1 file=$2
    local cheat=$(extract_from_cmdline "$fields")
    [ -n "$cheat" -o -z "$file" ] || return
    value=$(egrep "^[0-9]+:$cheat[: ]" $file | cut -d: -f3)
    echo ${value:-$cheat}
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
extract_from_cmdline() {
    local p fields=$1
    [ "$fields" ] || return
    for p in $(cat /proc/cmdline); do
        eval "case \$p in
        $fields) echo \$p; break ;;
        esac"
    done
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
filter_cmdline() {
    local p fields=$1
    shift

    if [ -z "$fields" ]; then
        echo "$*"
        return
    fi

    for p; do
        eval "case \$p in
        $fields) ;;
              *) echo \$p ;;
        esac"
    done
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
gather_frugal_cmdline() {
    local p out value
    for p in $(cat /live/config/proc-cmdline /live/config/cmdline 2>/dev/null) $*; do
        value=${p#*=}
        case $p in
                frugal=*) p=persist=$value      ;;
          frugal_persist) p=persist_all         ;;
             frugal_root) p=persist_root        ;;
           frugal_static) p=persist_static      ;;
             frugal_home) p=persist_home        ;;
        esac

        case $p in
   bdir=*|bdev=*|blab=*|buuid=*)                ;;
   fdir=*|fdev=*|flab=*|fuuid=*)                ;;
                         frugal)                ;;
                    frugal_only)                ;;
                  menus|menus=*)                ;;
                     bp=*|upb=*)                ;;
              gfxsave|gfxsave=*)                ;;
            bootsave|bootsave=*)                ;;
                   BOOT_IMAGE=*)                ;;
          savestate|nosavestate)                ;;
                nostore|dostore)                ;;
           md5|checkmd5|checkfs)                ;;
              automount|mount=*)                ;;
                    noautomount)                ;;
                        fstab=*)                ;;
                      hwclock=*)                ;;
                      desktop=*)                ;;
                              *) out=$out${out:+ }$p ;;
        esac
    done
    echo $out
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
xlat_mfile() {
    local file=$1 lang=${2%%_*}
    echo "xlat_mfile: $lang $file" >> /mfile.log
    test -e $file.$lang && echo found >> /mfile.log
    if [ -n "$lang" -a -e $file.$lang ]; then
        echo $file.$lang
        return
    fi
    echo $file
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
do_early_menus() {
    local BOOT_MENU_DIR=/live/menus
    local MENU_VALUE BOOT_MENU_WARN=true
    local lang time_zone option persist desktop
    local cmdline
    my_select_menu  "$_Select_Language_"            "$_Languages_are_listed_alphabetically_"   l lang      "$_Language_"           'lang=*'

    local need_font
    case $MENU_VALUE in
        lang=*) LANG=${MENU_VALUE#lang=}
                need_font=true
                echo "$LANG" > $OUTPUT_DIR/lang
                read_xlat init $LANG       ;;
    esac

    vmsg 1  "$_Console_columns_is_currently_set_to_X_" "$(pq $CON_WIDTH)"
    my_select_menu  "$_Select_number_of_console_columns_"   "$_Wider_means_a_smaller_font_"    w conwidth  "$_Console_columns_"  'conwidth=*'

    case $MENU_VALUE in
        conwidth=*) CON_WIDTH=${MENU_VALUE#conwidth=}
                    set_console_width "$CON_WIDTH" "$LANG";;
                 *) [ "$need_font" ] && \
                    set_console_width "$CON_WIDTH" "$LANG" ;;
    esac

    # my_select_menu "Select Console Font size"  "The default size is 8"                c confont  "Console font size"  'confont=*'

    # case $MENU_VALUE in
    #     confont=*) CON_FONT=${MENU_VALUE#confont=}
    #                set_console_font "$LANG" "$CON_FONT" ;;
    #             *) [ "$need_font" ] && \
    #                set_console_font "$LANG" "$CON_FONT" ;;
    # esac

    my_select_menu  "$_Select_Timezone_"            "$_Timezones_are_listed_by_longitude_"     t tz        "$_Timezone_"      'tz=*'
    my_select_menu  "$_Select_Option_"              "$_Only_one_option_can_be_selected_"       o options   "$_Options_"       "$OPTIONS_ENTRIES"
    my_select_menu  "$_Select_Mounting_Option_"     "$_Automounting_is_enabled_by_default_"    m mount     "$_Mount_"          "$_automount_mount_"
    my_select_menu  "$_Select_Persistence_Option_" ""                                      p persist   "$_Persistence_"   'persist_*|frugal_*'
    my_select_menu  "$_Select_font_size_"           "$_Scale_fonts_in_graphics_display_Default_is_1_0_"  f fontsize "X font size" 'fontsize=*'
    #vmsg 6 "cmdline:$white $cmdline"
    [ ${#cmdline} -gt 0 ] && echo "$cmdline" >> /live/config/cmdline
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
do_late_menus() {
    local BOOT_MENU_DIR=/live/aufs/usr/share/boot-menus
    if [ -d "/live/aufs/usr/local/share/boot-menus" ]; then
		BOOT_MENU_DIR=/live/aufs/usr/local/share/boot-menus
	fi
    local BOOT_MENU_WARN=
    local lang time_zone option persist desktop
    local cmdline
    my_select_menu  "$_Select_Desktop_" "" d desktop  "$_Desktop_" 'desktheme=*'

    if remasterable; then
        BOOT_MENU_DIR=/live/menus
        my_select_menu  "$_Save_these_changes_" "" s save  "$_Save_"
        echo "$cmdline" | grep -q bootsave && BOOT_SAVE=true
    fi

    #vmsg 6 "cmdline:$white $cmdline"
    [ ${#cmdline} -gt 0 ] && echo "$cmdline" >> /live/config/cmdline
}


#------------------------------------------------------------------------------
# Label sizes given in Megs (MiB)
#------------------------------------------------------------------------------
label_meg() { label_any_size "$1" " " MiB GiB TiB PiB EiB; }

#------------------------------------------------------------------------------
# More compact horizontally, for tables
#------------------------------------------------------------------------------
size_label_m() { label_any_size "$1" "" M G T P E; }

#------------------------------------------------------------------------------
# Bite the bullet and do it "right"
#------------------------------------------------------------------------------
label_any_size() {
    local size=$1  sep=$2  u0=$3  unit=$4  meg=$((1024 * 1024))  new_unit ; shift 4

    for new_unit; do
        [ $size -lt $meg ] && break
        size=$((size / 1024))
        unit=$new_unit
    done

    if [ $size -ge 102400 ]; then
        awk "BEGIN {printf \"%d$sep$unit\n\", $size / 1024}"
    elif [ $size -ge 10240 ]; then
        awk "BEGIN {printf \"%0.1f$sep$unit\n\", $size / 1024}"
    elif [ $size -ge 1024 ]; then
        awk "BEGIN {printf \"%0.2f$sep$unit\n\", $size / 1024}"
    else
        awk "BEGIN {printf \"%d$sep$u0\n\", $size}"
    fi
}

nq_label_meg() { nq $(label_meg $1); }

#------------------------------------------------------------------------------
#  Allow user to select a partition from a menu of choices
#------------------------------------------------------------------------------
select_device() {
    local title_type=$1  var=$2  min_size=${3:-0} not_mounted=$4
    local title=$(printf  "$_Please_select_X_device_" "$title_type")

    tsplash_only_clear

    local cnt=1 cnt_lab rtype mp=/tmp/mnt
    local size_lab free free_lab
    local line pretty skip data display
    local free_rev type_rev name_rev size_rev
    #local format="$green%3s $lt_cyan%-5s $magenta%8s $yellow%8s $lt_blue%10s $lt_gray%9s $white%-16s $lt_gray%s\n"
    local format="$green%3s $lt_cyan%s%-9s$nc_co $magenta%s%5s$nc_co $yellow%s%5s$nc_co $lt_blue%s%10s$nc_co $lt_gray%6s $lt_gray%-16s $white%s\n"
    local head_fmt="${hi_co}%3s %-9s %5s %5s %10s %6s %-16s %s\n"
    local header=$(printf "$head_fmt" "" Name Size Free FS-type Remove Model Label)
    local title="$title\n$header"

    mkdir -p $mp
    local rev=$(printf "\e[0;4;7;31m")
    #local rev=$(printf "\e[5;7;31m")
    #local rev=$(printf "\e[1;7m")

    (bogo_meter)&
    local pid=$!

    local name
    while read -r name line ; do

        [ ${#name} -eq 0 -o ${#name} -gt 10 ] && continue

        local type=$(echo "$line" | sed -n -r 's/.* TYPE="([^"]*)"$/\1/p' | tail -n 1)
        #uuid=$(echo "$line" | sed -n -r -e 's/" (UUID=|TYPE=)".*//' -e 's/[^:]*: LABEL="//p')
        case $type in
            ""|udf|iso9660|swap|squashfs) continue
        esac

        local disk_name=$(get_drive $name)

        local sys_dir=/sys/block/$disk_name
        local model=$(head -c 16  $sys_dir/device/model 2>/dev/null)
        local remove=$(cat        $sys_dir/removable    2>/dev/null)
        local reado=$(cat         $sys_dir/$name/ro     2>/dev/null)
        local size=$(cat          $sys_dir/$name/size   2>/dev/null)
        [ "$reado" = 1 ] && continue
        [ -z "$size" ] && continue
        size=$((size / 2 / 1024))

        local dev=/dev/$name

        local label=$(echo "$line" | sed -n -r -e 's/" (UUID=|TYPE=)".*//' -e 's/^LABEL="//p')

        size_rev=
        name_rev=
        free_rev=
        type_rev=
        free=

        cnt_lab="$cnt)"
        size_lab=$(size_label_m $size)

        if [ $min_size -gt 0 -a $min_size -gt $size ]; then
            size_rev=$rev
            cnt_lab=
            skip=true
        fi

        local exist_mp=$(get_mountpoint $dev)
        if [ "$exist_mp" ]; then
            free=$(free_space $exist_mp)
            if [ "$not_mounted" ]; then
                name_rev=$rev
                cnt_lab=
                skip=true
            fi

        elif try_mount $dev $mp "" $type; then
            free=$(free_space $mp)
            free_lab=$(size_label_m $free)
            umount $mp
        fi

        type=${type#crypto_}

        if [ "$type" = "LUKS" ]; then
            free_lab="??"

        elif [ "$free" ]; then
            free_lab=$(size_label_m $free)
            if [ $min_size -gt 0 -a $min_size -gt $free ]; then
                free_rev=$rev
                cnt_lab=
                skip=true
            fi
        else
            free_lab="?"
            type_rev=$rev
            cnt_lab=
            skip=true
        fi

        rtype="no"
        [ "$remove" = 1 ] && rtype="yes"

        pretty=$(printf "$format" "$cnt_lab" "$name_rev" "$name" "$size_rev" "$size_lab" \
            "$free_rev" "$free_lab" "$type_rev" "$type" "$rtype" "$model" "$label")

        local display="${display}$pretty\n"

        [ -z "$cnt_lab" ] && continue

        data="${data}$cnt:$dev\n"
        cnt=$((cnt + 1))

    done <<Blkid
$(sorted_blkid)
Blkid
    kill -9 $pid
    echo

    if [ $cnt -le 1 ]; then
        #display="$header\n$display"
        #msg_nc "$display"
        warn  "No suitable devices were found."
        press_enter
        return 1
    fi

    pretty=$(printf "$format" "0)" "${bold_co}quit " "$m_co($(cq default))")

    display="${display}$pretty\n"
    data="${data}0:quit\n"
    if [ "$skip" ]; then
        local rev_video=$(printf "$rev%s$nc_co"  "$_reverse_video_")
        display="${display}$(printf  "$_Partitions_that_cant_be_used_are_listed_but_not_selectable_")\n"
        display="${display}$(printf  "$_The_limiting_factors_are_highlighted_in_X_" "$rev_video")\n"
        display="${display}$(printf "A hightlighted name means the device is already mounted")\n"
    fi

    tsplash_off
    tsplash_alert ""

    my_select_2 "$title" $var "0" "$data" "$display"
    echo -e "$display" >> $MY_LOG
    return 0
}

#------------------------------------------------------------------------------
# sort blkid output by device name, including a numerical sort when the
# partition numbers have two-digits. Strip off leading "/dev/" and the ":".
#------------------------------------------------------------------------------
sorted_blkid() {
    blkid  |
    sed -r '
         s=^/dev/==
         s=^([^:]+):=\1:\1=
         s=^([^:]+[^0-9])([0-9]):=\10\2:=
         ' |
     sort  |
     sed -r 's=^[^:]+:=='
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
label_device() {
    local dev=$1  new=$2
    local type=$(device_fstype $dev)

    local pre post
    case $type in
         ext[234]) pre="tune2fs -L"                  ; post="$dev"   ;;
              xfs) pre="xfs_admin -L"                ; post="$dev"   ;;
              jfs) pre="jfs_tune -L"                 ; post="$dev"   ;;
             ntfs) pre="ntfslabel $dev"              ; post=""       ;;
         vfat|dos) pre="dosfslabel $dev"             ; post=""       ;;
            btrfs) pre="btrfs filesystem label $dev" ; post=""       ;;
         reiserfs) pre="reiserfstune --label"        ; post="$dev"   ;;
      crypto_LUKS) return 3                                          ;;
               "") warn  "Could not determine filesystem on %s" $(pqw $dev)
                   return 1                                          ;;

                *) warn  "Cannot label a %s filesystem" $(pqw $type)
                   return 2                                          ;;
    esac

    local cmd=$(echo $pre | cut -d" " -f1)
    local full=$(ld_path_which $cmd)

    if [ -z "$full" ]; then
        # Don't have the <command-name> tool to label a <fat32> filesystem
        warn  "Don't have the %s tool to label a %s filesystem" $(pqw $cmd) $(pqw $type)
        return 3
    fi

    local old=$(device_label $dev)

    if [ "$old" ]; then
        vmsg 1  "$_The_device_X_already_has_label_Y_" $(pq $dev) "$(pq $old)"
        yes_NO  "$_Update_label_on_X_from_Y_to_Z_" $(pq $dev) "$(pq "$old")" "$(pq "$new")" || return
    else
        vmsg 1  "$_The_device_X_has_no_label_" $(pq $dev)
        yes_NO  "$_Give_X_the_label_Y_" $(pq $dev) "$(pq "$new")" || return
    fi

    log_cmd ld_path $pre "$new" $post 2>&1 || return

    msg  "$_Label_updated_to_X_" $(pq $new)
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
label_to_dev() {
    local label=$1 devices
    local dev line lab
    while read dev line; do
        lab=$(echo "$line" | sed -n -r -e 's/" (UUID=|TYPE=)".*//' -e 's/^LABEL="//p')
        [ "$lab" = "$label" ] && devices="$devices${devices:+ }${dev%:}"
    done <<EOT
$(blkid)
EOT
    echo $devices
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
uuid_to_dev() {
    local uuid=$1  grep_for=${2:-.} devices
    local dev line id
    while read dev line; do
        id=$(echo "$line" | sed -n -r 's/(^|.* )UUID="([^"]*)"( |$).*/\2/p')
        [ ${#id} -gt 0 -a -z "${id##$uuid}" ] && devices="$devices${devices:+ }${dev%:}"
    done <<EOT
$(blkid | grep "$grep_for")
EOT
    echo $devices
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
fstype_to_dev() {
    local fstype=$1
    blkid | egrep "\<TYPE=\"($fstype)\"" | cut -d: -f1 | tr '\n' ' '
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
cleanse_dev() {
    case $1 in
        /dev/*)  [ -b "$1"      ] && echo "$1";;
         dev/*)  [ -b "/$1"     ] && echo "/$1";;
            /*)  [ -b "/dev$1"  ] && echo "/dev$1";;
             *)  [ -b "/dev/$1" ] && echo "/dev/$1";;
    esac
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
general_device_error() {
    case $2 in
        uuid|label) label_error  "$@" ;;
              name) device_error "$@" ;;
    esac
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
label_error() {
    local find_type=$1  param=$2  name=$2  value=$3
    [ "$param" = label ] && param=lab
    param=${1:0:1}$param

    ##warn "$hbar"
    warn
    err  "$_Fatal_Error_"
    err  "No device with %s was found" "$name $(cqe $value)"

    vmsg_nc 3  "$_Valid_X_" "${name}s:"
    local dev val
    while read dev val; do
        [ "$val" ] && printf "  %-10s $white $param=$val$nc_co\n" $dev
    done <<Label_Error
$(
case $name in
    label)
        sorted_blkid | sed -n -r -e 's/" (UUID=|TYPE=)".*//' -e 's/ LABEL="/ /p' ;;
     uuid)
        sorted_blkid | sed -n -r 's/^([^ ]*).* UUID="([^"]*)"( |$).*/\1 \2/p' ;;
esac
)
Label_Error
    #warn "$hbar"
    warn
    case $from_type in
        persist) _error "" c  "$_continue_" ;;
              *) _error                 ;;
    esac
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
device_error() {
    local find_type=$1  type=$2  value=$3
    local valid_devs=$(echo $(most_block_devices) | sed "s/^/$white    /");
    if [ "$find_type" = 'persist' ]; then
        _non_fatal "$(printf  "$_Could_not_find_device_X_" "$(pqh $value)")"  "$_Valid_devices_": "$valid_devs"
    else
        _fatal "$(printf  "$_Could_not_find_device_X_" "$(pqh $value)")"  "$_Valid_devices_": "$valid_devs"
    fi
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
cp_file() {
    local src=$1  name=$2  dest=$3  file=$1/$2
    mkdir -p $dest
    echo -n $hi_co
    local tar=$LIVE_BIN/tar
    local progress=$LIVE_BIN/pipe_progress

    if [ ! -d "$src" ]; then
        err 'Source directory %s does not exist' $(pqe $src)
        return 2
    fi

    if [ ! -f "$file" ]; then
        err 'Source file %s does not exist' $(pqe $file)
        return 3
    fi

    $tar -C "$src" -hcf - "$name" | $progress | $tar -C "$dest" -xpf -
    local ret=$?
    echo -n $nc_co
    vmsg 8 "cp_file returned:$num_co $ret"
    return $ret
}

#------------------------------------------------------------------------------
# Function: cp_rm_dest <src> <dest>
#
# Emulate cp --remove-destination in busybox
#------------------------------------------------------------------------------
cp_rm_dest() {
    local src=$1 dest=$2
    rm -f "$dest"
    cp "$src" "$dest"
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
find_md5_files() {
    local dir=$1  ; shift
    local file
    for file; do
        test -e "$dir/$file"     && echo "$dir/$file"
        test -e "$dir/$file.md5" && echo "$dir/$file.md5"
    done
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
prog_copy_md5() {
    local dest=$1  src=$2 ; shift 2
    prog_copy $dest $(find_md5_files $src "$@")
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
tsplash_prog_copy_md5() {
    local label=$1 dest=$2  src=$3 ; shift 3
    tsplash_prog_copy "$label" $dest $(find_md5_files $src "$@")
}


#------------------------------------------------------------------------------
# prog_copy <dest> <src1> <src2> ...
# Copy source files to destination directory and display a bar indicating the
# progress.
#------------------------------------------------------------------------------
prog_copy() {
    local dest=$1 ; shift
    local err_file=/prog-copy-failed
    # TEST directories or fatal error

    if [ "$NO_PROGRESS" ]; then
        cp -a "$@" "$dest"
        return $?
    fi

    local final_size=$(du_size "$@")
    local base_size=$(du_size "$dest")

    local dirty_ratio dirty_bytes
    read dirty_ratio < /proc/sys/vm/dirty_ratio
    read dirty_bytes < /proc/sys/vm/dirty_bytes
    echo $USB_DIRTY_BYTES > /proc/sys/vm/dirty_bytes

    mkdir -p "$dest"
    rm -f $err_file
    (cp -a "$@" $dest/ || echo $? > $err_file) &
    COPY_PID=$!
    #echo "copy pid: $COPY_PID" >> $LOG_FILE

    # Disable cursor
    printf "\e[?25l"

    local cur_size=$base_size cur_pct last_pct=0
    while true; do
        if ! test -d /proc/$COPY_PID; then
            echo 1000
            break
        fi
        sleep 0.1

        cur_size=$(du_size $dest)
        cur_pct=$((cur_size * 1000 / final_size))
        [ $cur_pct -gt $last_pct ] || continue
        echo $cur_pct
        last_pct=$cur_pct

    done | text_progress

    echo

    sync ; sync

    # Enable cursor
    printf "\e[?25h"

    [ ${dirty_bytes:-0} -gt 0 ] 2>/dev/null && echo $dirty_bytes > /proc/sys/vm/dirty_bytes
    [ ${dirty_ratio:-0} -gt 0 ] 2>/dev/null && echo $dirty_ratio > /proc/sys/vm/dirty_ratio

    # Use err_file as a semaphore from (...)& process
    if test -e $err_file; then
        rm -f $err_file
        return 2
    fi

    test -d /proc/$COPY_PID && wait $COPY_PID

    return 0
}

#------------------------------------------------------------------------------
# Use tsplash to do the copy if it is enabled.
#------------------------------------------------------------------------------
tsplash_prog_copy() {
    local label=$1 ; shift
    if tsplash_enabled; then
        tsplash_wait "$label" "$@"
    else
        prog_copy "$@"
    fi
}
#------------------------------------------------------------------------------
# Show a progress arrow while doing "dd" command
#------------------------------------------------------------------------------
prog_dd() {
    local dest=$1  cnt=$2  src=${3:-/dev/zero}  bs=${4:-1M}

    local err_file=/dd-copy-failed
    # TEST directories or fatal error

    mkdir -p "$(dirname "$dest")"
    if [ "$NO_PROGRESS" ]; then
        dd if=$src of=$dest bs=$bs count=$cnt status=none
        return $?
    fi

    rm -f "$file"
    local final_size=$cnt  base_size=0

    local dirty_ratio dirty_bytes
    read dirty_ratio < /proc/sys/vm/dirty_ratio
    read dirty_bytes < /proc/sys/vm/dirty_bytes
    echo $USB_DIRTY_BYTES > /proc/sys/vm/dirty_bytes

    rm -f $err_file
    (dd if=$src of=$dest bs=$bs count=$cnt status=none || echo $? > $err_file)  &
    COPY_PID=$!
    #echo "copy pid: $COPY_PID" >> $LOG_FILE

    # Disable cursor
    printf "\e[?25l"

    local cur_size=$base_size cur_pct last_pct=0
    while true; do
        if ! test -d /proc/$COPY_PID; then
            echo 1000
            break
        fi
        sleep 0.1

        cur_size=$(du_size $dest)
        cur_pct=$((cur_size * 1000 / final_size))
        [ $cur_pct -gt $last_pct ] || continue
        echo $cur_pct
        last_pct=$cur_pct

    done | text_progress

    echo

    sync ; sync

    # Enable cursor
    printf "\e[?25h"

    [ ${dirty_bytes:-0} -gt 0 ] 2>/dev/null && echo $dirty_bytes > /proc/sys/vm/dirty_bytes
    [ ${dirty_ratio:-0} -gt 0 ] 2>/dev/null && echo $dirty_ratio > /proc/sys/vm/dirty_ratio

    # Use err_file as a semaphore from (...)& process
    if test -e $err_file; then
        rm -f $err_file
        return 2
    fi

    test -d /proc/$COPY_PID && wait $COPY_PID

    return 0
}

#------------------------------------------------------------------------------
# chreat a zeroed out swap file, if it doesn't exist and if a size is given
# and the size is reasonable.  We let live-init run the mkswap command if
# if needed since it is aleady in a chroot.
#------------------------------------------------------------------------------
make_swap_file() {
    local file=$1  swap_size=$(echo $2 | tr 'mg' 'MG')  raw_size=$2
    [ -z "$swap_size" ]  && return

    if test -e "$file"; then
        warn  "$_Swap_file_X_already_exists_" "$(pqw $file)"
        return
    fi

    local dir=$(dirname "$file")
    local free_space=$(free_space "$dir")

    case $swap_size in
        choose)  select_swap_file_size 'swap_size' $free_space $dir ;;
    esac

    [ "$swap_size" =  "$_quit_" ] && return 1

    vmsg 1  "$_Swap_file_size_X_" "$(nq_label_meg $swap_size)"

    local megs  factor=
    case $swap_size in
        [0-9]*[0-9]) megs=${swap_size%M} ; factor=1    ;;
                 *M) megs=${swap_size%M} ; factor=1    ;;
                 *G) megs=${swap_size%G} ; factor=1024 ;;
    esac

    # msg "Freespace: $free_space"

    if [ -z "$factor" ] || ! echo "$megs" | grep -q "^[0-9]\+$"; then
        warn  "$_Invalid_X_option_Y_" 'mk_swap_file=' "$(pqw $raw_size)"
        return
    fi
    megs=$((megs * factor))

    # msg "Megs: $megs"

    if [ $((free_space - megs)) -lt 10 ]; then
        non_fatal  "$_Not_enough_space_to_create_a_X_swap_file_" "$(pqw $raw_size)"
        return
    fi

    #. Creating <size> swap file at <filename>.  Please be patient ...
    msg  "$_Creating_X_swap_file_at_Y_Please_be_patient_" "$(pq $raw_size)" "$(pq $file)"

    if tsplash_enabled; then
        tsplash_wait mk_swap_file "$file" "$megs"
    else
        prog_dd "$file" "$megs"
    fi
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
select_swap_file_size() {
    local var=$1  free=$2  dir=$3  size  sizes
    local title=$(printf  "$_Please_select_size_of_X_file_" $(pqw 'swap'))

    local avail=$((free - MKFS_FREE_MARGIN))

    local part_fstype=$(mntpnt_fstype $dir)  is_vfat
    case $part_fstype in
        vfat) is_vfat=true ;;
    esac

    # Set the maximum size for this menu
    local max_size=$avail  min_size=0
    [ -n "$is_vfat" -a "$max_size" -gt 4095 ] && max_size=4095
    if [ "$base_file" = rootfs ]; then
        [ "$max_size" -gt "$MAX_ROOTFS_SIZE" ] && max_size=$MAX_ROOTFS_SIZE
        min_size=$MIN_ROOTFS_SIZE
    fi

    # Create a menu of sizes, stop when the sizes are too big
    local size sizes
    for size in $SWAP_SIZES; do
        [ $size -gt $max_size ] && break
        [ $size -lt $min_size ] && continue
        sizes="$sizes $size"
    done

    tsplash_clear
    size_menu $var "$title" "" $sizes
}

#------------------------------------------------------------------------------
# This acts like an external program to draw a progress bar on the screen.
# It expects integer percentages as input on stdin to move the bar.
# Now using 1/10th percent steps which seems to reduce jitteriness/jaggedness.
# Yes, because there was aliasing between 100 steps and width of screen.
#------------------------------------------------------------------------------
text_progress() {
    local abs_max_x=$((SCREEN_WIDTH * PROG_BAR_WIDTH / 100))

    # length of ">100%" plus one = 6 (??)
    max_x=$((abs_max_x - 7))

    # Create end-points and save our location on the screen
    printf "\e[s$from_co|$nc_co\e[u"
    #printf "\e[u\e[$((max_x + 2))C$from_co|$nc_co\e[u"

    local cur_x last_x=0
    while read input; do
        case $input in
            [0-9]|[0-9][0-9]|[0-9][0-9][0-9]) ;;
                        [0-9][0-9][0-9][0-9]) ;;
            *) break;;
        esac

        [ $input -gt 1000 ] && input=1000
        cur_x=$((max_x * input / 1000))
        # Note we always draw entire bar to avoid problems when switching
        # virtual terminals while the bar is being drawn

        [ $cur_x -le $last_x ] && continue
        # Draw the bar
        printf "\e[u\e[0C$m_co%${cur_x}s$bold_co>$nc_co\e[u" | tr ' ' '='
        # Show the percentage
        printf "\e[$((max_x + 2))C%3s%%" "$((input / 10))"

        last_x=$cur_x

        [ $input -ge 1000 ] && break
    done
}

#------------------------------------------------------------------------------
# Draw progress arrow
#------------------------------------------------------------------------------
progbar_draw() {
    local x=$1  prev=$2
    local diff=$((x - prev))
    local bar=$(printf "$m_co%${diff}s$bold_co>$nc_co" "" | tr ' ' '=')
    printf "\e[u\e[$((prev))C$bar\e[u"
}

#------------------------------------------------------------------------------
# Function: cp_dir <sorc> <dest>
#------------------------------------------------------------------------------
cp_dir() {
    local from=$1  to=$2
    mkdir -p "$to"
    [ -z "$(ls $from)" ] && return 0
    time_cmd cp -a $from/* $to
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
old_cp_dir() {
    mkdir -p "$2"
    echo -n $hi_co
    local tar=$LIVE_BIN/tar
    local progress=$LIVE_BIN/pipe_progress
    $tar -C "$1" -cf - . | $progress | $tar -C "$2" -xpf -
    local ret=$?
    echo -n $nc_co
    return $ret
}

# FIXME: should use ld_path and --apparent-size so we aren't fooled by sparseness
file_usage_m() {
    local f file dir=$1
    shift

    [ "$dir" -a "${dir##*/}" ] && dir=$dir/
    for f; do
        file=$dir$f
        [ -e $file ] && list="$list $file"
    done
    du -scxm $list >> $MY_LOG
    du -scxm $list | tail -n 1 | cut -f1
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
copy_files_md5() {
    local f file sorc=$1  dest=$2
    shift 2
    [ "$sorc" -a "${sorc##*/}" ] && sorc=$sorc/
    for f; do
        for file in $sorc$f $sorc$f.md5; do
            [ -e $file ] || continue
            cp -a $sorc$f $dest/ || return $?
        done
    done
    return 0
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
copy_files() {
    local f file sorc=$1  dest=$2
    shift 2
    [ "$sorc" -a "${sorc##*/}" ] && sorc=$sorc/
    for f; do
        file=$sorc$f
        [ -e $file ] || continue
        cp -a $sorc$f $dest/ || return $?
    done
    return 0
}

all_space()      { $LIVE_BIN/df -Pm "$1" | awk '{size=$2}END{print size}' ;}
used_space()     { $LIVE_BIN/df -Pm "$1" | awk '{size=$3}END{print size}' ;}
avail_space()    { $LIVE_BIN/df -Pm "$1" | awk '{size=$4}END{print size}' ;}
du_size()        { du -scm "$@"          | tail -n1 | cut -f1             ;}
get_mountpoint() { grep "^$1 " /proc/mounts | cut -d" " -f2               ;}

#------------------------------------------------------------------------------
# This compensates for sparse rootfs and homefs files one directory down from
# the mountpoint.  This is far from perfect but I hope it is a reasonable
# compromise that will work well for most people in most situations.
#------------------------------------------------------------------------------
free_space() {
    local mp=$1
    local free=$($LIVE_BIN/df -Pm $mp | awk '{size=$4}END{print size}')
    local sparse new_free
    for sparse in $mp/*/rootfs $mp/*/homefs; do
        test -e $sparse || continue
        real=$(( $(stat -c %s $sparse) / 1024 / 1024))
        orig=$(du -m $sparse | cut -f1)
        new_free=$((free - $real + $orig))
        printf 'sparse: r=%4s o=%4s of=%5s nf=%5s %s\n' $real $orig $free $new_free $sparse >> $MY_LOG
        free=$new_free
    done
    [ $free -lt 0 ] && free=0
    echo $free
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
dir_has_param() {
    local dir=$1  want_param=$2

    [ -d "$dir" ] || return 1

    local dev=$(df -P $dir | tail -n1 | cut -d" " -f1)
    local params=$(grep "^$dev " /proc/mounts | cut -d" " -f4)
    case ,$params, in
        *,$want_param,*) return 0;;
    esac
    return 1
}

#------------------------------------------------------------------------------
# Function: get_vid <file>
#------------------------------------------------------------------------------
get_vid()   { [ -r "$1" ] && grep ^=== $1 | tail -n 1 ;}

vid_error() {
    VID_ERROR=$(printf "$@")
    err "$@"
    WANT_ROOTFS=
    NEED_ROOTfS=
    STATIC_ROOT=
    log_cmd umount $ROOTFS_MP
}

#------------------------------------------------------------------------------
# Function: check_vid <sqfs_vid> <mp> <fname>
#------------------------------------------------------------------------------

check_vid() {
    local sqfs_vid=$1  base=$2  fname=$3

    local vid_file=$base$VID_DIR/$fname
    #breakpoint v "before check VID"

    local rootfs_vid
    [ "$vid_file" ] && rootfs_vid=$(get_vid $vid_file)

    if [ -n "$sqfs_vid" -a -n "$rootfs_vid" ]; then

        if [ "$rootfs_vid" = "$sqfs_vid" ]; then
            vmsg 6 'Matching %s found in %s' "$VID_NAME" "$(fq $vid_file)"
            return 0
        else
            #. "<VID> mismatch between <linuxfs> and <rootfs>
            vid_error  "$_X_mismatch_between_Y_and_Z_" "$VID_NAME" linuxfs rootfs
            vmsg 1 "linuxfs:$white $sqfs_vid"
            vmsg 1 " rootfs:$white $rootfs_vid"
            return 1
        fi

    elif [ "$sqfs_vid" ]; then

        # This is a hack but it prevents a warning message from the ls command
        mkdir -p $base
        # Pass test and create new rootfs version file if rootfs is empty
        # This is funky but if we don't do it here then there will be problems
        # when "toram" is used.
        if ! ls $base | egrep -q 'etc|bin|lib|var|usr'; then
            #. Copy <linuxfs VID> to empty <rootfs>
            msg  "$_Copy_X_to_empty_Y_" "$LINUXFS_NAME $VID_NAME" rootfs

            log_cmd mkdir -p $(dirname $vid_file)  || return 1
            log_cmd cp $SQFS_VID_FILE $vid_file    || return 2
            sync
            return 0

        elif ! [ -f "$vid_file" ]; then
            #. <type> file not found <file-name>
            vid_error  "$_X_file_not_found_Y_" "$VID_NAME" "$vid_file"
            return 1

        else
            vid_error  "$_No_X_found_in_file_Y_" "$VID_NAME" "$vid_file"
            return 1
        fi

    elif [ "$rootfs_vid" ]; then
        vid_error  "$_No_X_found_but_there_is_a_Y_" "$LINUXFS_NAME $VID_NAME" "rootfs $VID_NAME"
        return 1
    else
        vmsg 6  "No %s or %s found" "$LINUXFS_NAME $VID_NAME" "rootfs $VID_NAME"
        return 0
    fi
}

#------------------------------------------------------------------------------
# Function: check_md5 <dir>
#
# Checks the md5 sum of all files in <dir> that have a <name>.md5 file.
#------------------------------------------------------------------------------
check_md5()
{
    local dir=$1 passed="passed"  failed="failed"
    [ ! -d "$dir" ] && dir=$(echo $1 | sed 's|\(.*\)/.*|\1|')
    dir=$(echo $dir | sed 's|/$||')
    if ! [ -d "$dir" ]; then
        msg $tbar
        err  "Directory %s does not exist" "$(fqe $1)"
        err  "Can't perform %s check" md5
        msg $tbar
        return 0
    fi

    local fcnt=0

    vmsg 2 $tbar
    #. Check <md5> of files in <some> directory
    tsplash_alert_nc  "$_Check_X_of_files_in_Y_directory_Please_be_patient_" md5 "$(fq $dir)"

    local file fname md5_file file_md5 true_md5 error
    for fname in $(ls $dir); do
        file=$dir/$fname
        local size=$(du -sm $file | cut -f1)
        md5_file="$file.md5"
        [ -f "$md5_file" -a -f "$file" ] || continue

        local size_str="$nc_co($num_co$size$nc_co M)"
        # vmsg 1
        vmsg 1 $tbar
        vmsg_nc 1  "$_file_X_" "${nc_co}$fname $size_str"
        fcnt=$(( fcnt + 1 ))
        true_md5="$(head -n 1 $md5_file | cut -d" " -f1)"

        (bogo_meter)&
        local pid=$!
        file_md5=$(md5sum $file | cut -d" " -f1)
        kill -9 $pid

        if [ "$file_md5" == "$true_md5" ]; then
            vmsg_nc 1  "$_result_X_" "${ok_co}$passed"
        else
            vmsg_nc 1  "$_result_X_" "${err_co}$failed"
            error=true
        fi

        vmsg 6  "         wanted: %s" "$num_co$true_md5"
        vmsg 6  "            got: %s" "$num_co$file_md5"
    done

    vmsg 1
    if [ "$fcnt" = 0 ]; then
        #. No <md5> checksums were found in <directory>.  Can't do any <md5> checks.
        err  "$_No_X_checksums_were_found_in_Y_Cant_do_any_Z_checks_" md5 "$(fqe $dir)" md5
    elif [ "$error" ]; then
        non_fatal  "$_At_least_one_X_checksum_did_not_match_" md5
    elif [ "$fcnt" = 1 ]; then
        tsplash_alert  "$_Success_The_file_passed_"
    else
        #. Success! All <count> file(s) passed
        tsplash_alert  "$_Success_All_X_files_passed_" $(nq $fcnt)
    fi
    vmsg 2 $tbar
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
do_delay() {
    local cnt=$1; shift
    [ -z "$cnt" -o "$cnt" = "0" ] && return
    [ $# -gt 0 ] && msg "$@"
    while [ "$cnt" -gt "0" ]; do
        msgN "$hi_co$cnt "
        cnt=$((cnt - 1))
        sleep 1
    done
    msg
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
next_device() {
    local base=$(echo $1 | sed 's/[0-9]*$//')
    local num=$(echo $1 | sed 's/^[^0-9]*//')
    while [ "$num" -lt "20" ]; do
        num=$((num + 1))
        device=$base$num
        [ -b "$device" ] || continue
        echo $device
        return 0
    done
    return 1
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
will_remaster() {
    [ -n "$NO_REMASTER" -o "$ROLLBACK" ] && return 1

    local sqfile_path=${1:-$SQFILE_MP/$SQFILE_PATH}
    local sqfile=$sqfile_path/$SQFILE_NAME
    local old_file=$sqfile.old new_file=$sqfile.new bad_file=$sqfile.bad
    [ -e $old_file -o -e $bad_file ] && return 1
    [ -e $new_file ]
    return $?
}

#------------------------------------------------------------------------------
# Function: do_remaster <dir>
#
# If <dir>/linuxfs.new exists we move:
#       linuxfs     -->  linuxfs.old
#       linuxfs.new -->  linuxfs
#
# If the "rollback" cheatcode is used, we instead move:
#       linuxfs     -->  linuxfs.bad
#       linuxfs.old -->  linuxfs
#------------------------------------------------------------------------------
do_remaster() {
    [ "$NO_REMASTER" ] && return 0
    local sqfile_path=$(dirname $1)
    local sqfile="$sqfile_path/$SQFILE_NAME"
    local old_file="$sqfile.old" new_file="$sqfile.new" bad_file="$sqfile.bad"

    if [ "$ROLLBACK" ]; then
        heading 'remaster %s' "$(cq rollback)"

        if ! [ -f "$old_file" ]; then
            err -n  "The boot parameter %s was given but no %s was found" \
                "$(cqe rollback)" "$(fqe $SQFILE_NAME.old)"

            do_delay 10  "$_Wait_X_seconds_" "${num_co}10$m_co"
            return 1
        fi
        msg $tbar
        #warn "Roll back file %s to %s" "$SQFILE_NAME.old" "$SQFILE_NAME"
        tsplash_warn  "Roll back file %s to %s" "$SQFILE_NAME.old" "$SQFILE_NAME"
        msg $tbar

        local file full
        rm -rf $sqfile_path/xtra.bak $sqfile_path/xtra.bad
        for file in $SQFILE_NAME $MAKE_OLD; do
            full=$sqfile_path/$file
            [ -e $full.bad -a -e $full.bak ] && log_cmd rm -rf $full.bak
            [ -e $full.bad ] && log_cmd mv -f $full.bad $full.bak
            [ -e $full     ] && log_cmd mv -f $full     $full.bad
            [ -e $full.old ] && log_cmd mv -f $full.old $full
        done

        DID_ROLLBACK=true
        sync
        sleep 2
        return 0
    fi

    [ -e $new_file ] || return 0

    heading 'remaster'

    if [ -e $old_file -o -e $bad_file ]; then
        warn  "$m_co$tbar"
        warn   "Will not remaster"
        warn   "In directory %s one or more of these files already exist"  "$sqfile_path"
        warn  "    $SQFILE_NAME.old"
        warn  "    $SQFILE_NAME.bad"
        warn
        warn   "Run the %s program to fix this problem" 'remaster-live'
        warn  "$m_co$tbar"

        non_fatal
        return 2
    fi
    msg $tbar
    tsplash_warn  "Remaster the file %s to %s" "$SQFILE_NAME.new" "$SQFILE_NAME"
    msg $tbar

    local file full
    rm -rf $sqfile_path/xtra.old
    for file in $SQFILE_NAME $MAKE_OLD; do
        full=$sqfile_path/$file
        [ -e $full -a -e $full.old ] && log_cmd rm -rf $full.old
        [ -e $full     ] && log_cmd mv -f $full $full.old
        [ -e $full.new ] && log_cmd mv -f $full.new $full
    done

    DID_REMASTER=true
    sync
    sleep 2
    return 0
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
most_block_devices() { find /dev -type b | egrep -v "/ram|/loop|/fd" ; }

#------------------------------------------------------------------------------
# Function: copy_to_ram
#
# Copies the linuxfs file (and a few other files) to RAM
#------------------------------------------------------------------------------
copy_to_ram() {
    local name=$(basename $1) toram_mp=$2

    if _copy_to_ram "$@"; then

        local bdir=$toram_mp/$DEFAULT_BOOT_DIR
        LINUXFS_DEV=
        SQFILE_MP=$toram_mp
        SQFILE_DIR=$bdir
        SQFILE_FULL=$bdir/$name
        DEFAULT_DIR=$SQFILE_DIR

        log_cmd umount $SQFS_MP
        mount_linuxfs "$SQFS_MP" "$SQFILE_FULL"
        [ "$DID_ISO" ] && log_cmd umount $ISO_FILE_MP

    else
        mountpoint -q $toram_mp && log_cmd umount $toram_mp
        [ -d $toram_mp ]        && rmdir $toram_mp
        non_fatal  "$_Copy_to_RAM_failed_"
    fi
    #breakpoint t "After copy to ram"
}

_copy_to_ram() {
    local from=$1 toram_mp=$2  err_toram=$(cqe toram)
    local name=$(basename $from) dir=$(dirname $from)
    local dir_dir=$(dirname $dir)

    heading  "$_copy_X_file_to_RAM_" "$(fq $name)"
    local real_sq_file=$(readlink -f $from)
    local sq_size_k=$(du -sk $real_sq_file | cut -f 1)

    local format="%15s: %10d k"
    local format2="%s: %10d k"
    vmsg 8 "$format" "$name" $sq_size_k

    local extra_files="$EXTRA_FILES $name.md5"

    local extra ex_full size_k
    
    local extra_dir=$dir_dir
    if [ -f $dir/boot/grub/config/bootmenu.cfg ]; then
        extra_dir="$dir"
    fi
    
    if [ "$TORAM_ALL" ]; then
        extra_files="$extra_files $TORAM_ALL_BDIR_FILES"

        # Get the size of the additional files/dirs we are going to copy
        for extra in $TORAM_ALL_OTHER_FILES; do
            ex_full="$(readlink -f $extra_dir/$extra)"
            [ -e "$ex_full" ] || continue
            size_k="$(du -sk $ex_full | cut -f 1)"
            sq_size_k=$((sq_size_k + size_k))
            vmsg 8 "$format" $extra $size_k
            # Total [RAM needed]
            vmsg 8 "$format2" '          Total'  $sq_size_k
        done
    fi

    # Get the size of all extra files/dirs we are going to copy
    for extra in $extra_files; do
        ex_full="$(readlink -f $dir/$extra)"
        [ -e "$ex_full" ] || continue
        size_k="$(du -sk $ex_full | cut -f 1)"
        sq_size_k=$((sq_size_k + size_k))
        vmsg 8 "$format" $extra $size_k
        # Total [RAM needed]
        vmsg 8 "$format2" '          Total'  $sq_size_k
    done

    # Extra space here does not waste ram
    local sq_size_m=$((sq_size_k/1000 + 10))

    local ram_needed=$((sq_size_m + MIN_SYS_RAM));

    if [ "$sq_size_m" -gt "$FREE_MEM" ]; then
        err  "Not enough RAM available to do %s" $err_toram
        # Have <size> RAM, needed <size>
        err 'have %s RAM, needed %s' "${num_co}$FREE_MEM ${m_co}M${err_co}" \
            "${num_co}$sq_size_m ${m_co}M"
        return 1
    fi
    if ! mount_tmpfs $toram_mp $sq_size_m toram; then
        err  "Unable to mount %s.  Will not do %s" tmpfs $err_toram
        return 2
    fi

    local orig=$dir
    local dest=$toram_mp/$DEFAULT_BOOT_DIR

    mkdir -p $dest

    vmsg 3  "$_Will_copy_files_from_X_to_Y_Please_be_patient_" \
        "$(dq $orig)" "$(dq $dest)"

    local from_list
    local feh
    if [ "$TORAM_ALL" ]; then
        for extra in $TORAM_ALL_OTHER_FILES; do
            from_list="$from_list $(readlink -f $extra_dir/$extra)"
        done
        for feh in $from_list; do
            if [ -e $feh ]; then
               vmsg 3  "$_Will_copy_files_from_X_to_Y_Please_be_patient_" \
                   "$(dq $feh)" "$(dq $toram_mp)"
                   log_cmd cp -a $feh $toram_mp
            fi
        done
    fi

    local from_list=$orig/$name
    for extra in $extra_files; do
        local full=$(readlink -f $dir/$extra)
        [ -e "$full" ] && from_list="$from_list $full"
        [ -e "$full.md5" ] && from_list="$from_list $full.md5"
    done

    #if ! cp_file $orig $name $dest 2>&1; then

    if ! tsplash_prog_copy copy_toram $dest $from_list; then
        err  "Copy failed.  Cannot do %s" $err_toram
        return 3
    fi

    if ! [ -f "$dest/$name" ]; then
        err  "The destination file is missing. The %s has failed." $err_toram
        return 4
    fi

    # Rely on file size in bytes to check for errors
    local orig_bytes=$(stat -c "%s" $real_sq_file)
    local dest_bytes=$(stat -c "%s" $dest/$name)

    if [ "$orig_bytes" -ne "$dest_bytes" ]; then
        err  "Copy was incomplete. The %s failed" $err_toram
        format="%s: ${num_co}%12d${m_co} bytes"
        vmsg 1  "$_Size_of_original_X_" $orig_bytes
        vmsg 1  "$_Size_of_copy_X_" $dest_bytes
        vmsg_nc 1 "$(df -Pm | grep $toram_mp)"
        return 5
    fi

    msg "${ok_co}%s"  "$_Copy_to_RAM_succeeded_"

    # Reduce FREE_MEM by size of tmpfs
    FREE_MEM=$((FREE_MEM - sq_size_m))

    vmsg 6 '    persistence device: %s' $(pq $PERSIST_DEVICE)
    vmsg 6 '           boot device: %s' $(pq $SQFILE_DEV)

    if ! [ "$PERSIST_DEVICE" -a "$PERSIST_DEVICE" = "$SQFILE_DEV" ]; then
        # remount ro to be on the safe side
        log_cmd mount -o remount,ro $toram_mp
    fi

    DID_TORAM=true
    return 0
}

#------------------------------------------------------------------------------
# Function: prepare_persistence
#
# Parse the persist= bootcode but first set defaults.
#------------------------------------------------------------------------------
prepare_persistence() {
    local param persist_files auto_persist=true

    # pdev= and pdir= etc enable persistence even with no persist= bootcode.
    if [ "$PERSIST_ID" ]; then
        : ${PERSIST:=root,home}
        auto_persist=
    fi

    PERSIST_PATH=${PERSIST_PATH:-$DEFAULT_PERSIST_PATH}

    [ "$PERSIST" ] && ! echo $PERSIST | egrep -q 'home|root|r(,|!|$)|h(,|!|$)' && PERSIST="$PERSIST,home,root"

    will_remaster && WILL_REMASTER=true

    local rootfs_file=rootfs
    [ "$WILL_REMASTER" ] && rootfs_file=rootfs.new

    #----- Parse persist= ---------------------------------------------------------

    for param in ${PERSIST//,/ }; do

        case $param in
            s|static) STATIC_ROOT=true;;
        esac

        # You can't always get what you want ...
        case $param in
            home|home!|h|h!)
                persist_files="$PERSIST_PATH/homefs $persist_files"
                persist_files="$PERSIST_PATH/homefs.new $persist_files"
                WANT_HOMEFS=true ;;

            root|root!|r|r!)
                persist_files="$PERSIST_PATH/$rootfs_file $persist_files"
                WANT_ROOTFS=true ;;

            auto|a)
                AUTO_MAKE_FS=true;;

            usb|hd)
                FROM_PERSIST="$FROM_PERSIST,$param" ;;

            static|s) ;;

            *)
                warn
                #. Invalid <persist> value(s) <bad-values>
                warn  "Invalid %s values(s) %s"  $(cqw persist) "$(cqw $param)"
                warn  "Valid values: %s" "$(cqw auto home home! root root! static usb hd a h h! r r! s)" ;;
        esac

        # And if you try sometime ...
        case $param in
            home!|h!)
                NEED_HOMEFS=true;  NEED_PERSIST=true ;;
            root!|r!)
                NEED_ROOTFS=true;  NEED_PERSIST=true ;;
        esac
    done
    PERSIST_FILES=$persist_files

    [ "$auto_persist" ] || return

    # if we are on a read-only device and persist was set then set default
    # persist label if persist device was not explicitly given
    [ -z "$REMASTERABLE" -a -n "$NEED_PERSIST" ] || return

    AUTO_PERSIST="$DISTRO_NAME-Persist"
    tsplash_warn "Persistence was requested on a read-only boot device"
    sleep 3
    warn
    warn  "Persistence was requested on a read-only boot device"
    warn  "Will search for a persistence device with the label %s" "$(pqw $AUTO_PERSIST)"
    warn
    PERSIST_ID=label="$AUTO_PERSIST"

}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
mount_persist_device() {
    local persist_files=$1  from_persist=$2

    [ "$persist_files" ] || return

    # Set persist device to boot device if appropriate
    if [ -z "$from_persist" -a -z "$PERSIST_ID" ]; then

        case $(stat -c %t $(readlink -f $SQFILE_DEV)) in
         [38]|22|b3|fd|fe|103) ;;
            *) warn  "Can't use %s as a persistence device" $(pqw $SQFILE_DEV)
               return 20 ;;
        esac
        : ${PERSIST_ID:=name=$SQFILE_DEV}
    fi

    heading  "$_Mount_persistence_device_if_needed_"

    prep_find_files "$FROM_PERSIST"  "$PLUKS_ASK"
    find_files persist "$persist_files" "$PERSIST_MP" "$PERSIST_ID" "$PERSIST_RETRY"
    local ret=$?

    # FIXME: select persist device here and then run find_files again.
    if [ "$AUTO_PERSIST" -a $ret -ne 0 -a $ret -ne 40 ]; then
        if select_persist_device "$AUTO_PERSIST"; then
            msg "persist-files: $persist_files  id=$PERSIST_ID"
            find_files persist "$persist_files" "$PERSIST_MP" "$PERSIST_ID" "$PERSIST_RETRY"
            ret=$?
        else
            warn  "Disable persistence"
            unset WANT_ROOTFS WANT_HOMEFS NEED_ROOTFS NEED_HOMEFS
            return
        fi
    fi

    if [ $ret -eq 0 ]; then

        PERSIST_MP=$FOUND_MP
        PERSIST_DEVICE=$FOUND_DEV
        PERSIST_UUID=$(device_uuid $PERSIST_DEVICE)
        vmsg 7 "       persist_mp: $PERSIST_MP"
        vmsg 7 "   persist_device: $PERSIST_DEVICE"
        vmsg 7 "     persist_uuid: $PERSIST_UUID"
        PERSIST_FULL_PATH="$PERSIST_MP/$PERSIST_PATH"

    else

        case $ret in
           40) warn  "Could not find any persistence files"  ;;
            *) warn  "Could not find persistence device"     ;;
        esac

        # Could not enable required <type> persistence
        [ "$NEED_ROOTFS" ] && non_fatal 'Could not enable required %s persistence' $(pqh 'root!')
        [ "$NEED_HOMEFS" ] && non_fatal 'Could not enable required %s persistence' $(pqh 'home!')

        unset WANT_ROOTFS WANT_HOMEFS NEED_ROOTFS NEED_HOMEFS
    fi
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
create_persist_files() {
    local mp=$1 path=$2 dir=$1/$2 need_rootfs=$3  need_homefs=$4
    mount -o remount,rw $mp 2>/dev/null
    dir_has_param "$mp" rw || return

    local make_homefs
    if [ "$need_rootfs" ]; then

        # Do we also make the homefs file?
        make_homefs=$WANT_HOMEFS
        [ -e $dir/rootfs -o -e $dir/rootfs.new ] && make_homefs=

        # Default size for rootfs.new is size of rootfs
        local default_size rootfs_file=rootfs
        if [ "$WILL_REMASTER" ]; then
            default_size=$(stat -c %s $dir/rootfs 2>/dev/null)
            if [ -n "$default_size" ]; then
                default_size=$((default_size / 1024 / 1024))
                msg 'default size: %s' "$(nq_label_meg $default_size)"
            fi
            rootfs_file=rootfs.new
        fi

        persist_makefs root $mp $dir $rootfs_file NEED_ROOTFS $default_size

    fi
    #msg "need_homefs:$need_homefs  make_homefs:$make_homefs"
    [ -n "$need_homefs" -o -n "$make_homefs" ] \
        && persist_makefs home $mp $dir homefs NEED_HOMEFS
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
persist_makefs() {
    local type=$1
    tsplash_clear
    _persist_makefs "$@" && return

    warn  "Disable %s persistence" $(pqw $type)

}

_persist_makefs() {
    local type=$1  mp=$2  dir=$3  file=$4  needed_var=$5  orig_def_size=$6  full_file=$3/$4

    local wanted_var=WANT${needed_var#NEED}

    [ -e $full_file ] && return 0

    warn
    warn  "%s persistence was requested but no %s file was found" $(pqw $type) $(pqw $file)
    warn

    eval local needed=\$$needed_var wanted=\$$wanted_var
    unset $needed_var $wanted_var

    local free=$(free_space $mp)
    local avail=$((free - MKFS_FREE_MARGIN))

    vmsg 6 '      Free space: %s' "$(nq_label_meg $free)"
    vmsg 6 ' Available space: %s' "$(nq_label_meg $avail)"


    [ "$orig_def_size" ] && [ $orig_def_size -gt $avail ] \
        && warn  "$_Not_enough_room_on_Live_device_to_create_X_file_of_size_Y_" \
            $(fq $file) "$(nq_label_meg $orig_def_size)"

    local base_file=${file%%.*}
    local default_size=$(default_makefs_size $avail ${base_file}_SIZE_PARAM $orig_def_size)

    vmsg 6 '    Default size: %s' "$(nq_label_meg $default_size)"

    : ${default_size:=-1}

    mkfs_size=
    # Make sure we don't exceed max size of 4G - 1 on vfat file systems
    mkdir -p $dir
    local part_fstype=$(mntpnt_fstype $dir)  is_vfat

    case $part_fstype in
        vfat) is_vfat=true ;;
    esac

    # Set the maximum size for this menu
    local max_size=$avail  min_size=0
    [ -n "$is_vfat" -a "$max_size" -gt 4095 ] && max_size=4095
    if [ "$base_file" = rootfs ]; then
        [ "$max_size" -gt "$MAX_ROOTFS_SIZE" ] && max_size=$MAX_ROOTFS_SIZE
        min_size=$MIN_ROOTFS_SIZE
    fi

    # Create a menu of sizes, stop when the sizes are too big
    local size sizes
    for size in $MKFS_SIZES; do
        [ $size -gt $max_size ] && break
        [ $size -lt $min_size ] && continue
        sizes="$sizes $size"
    done

    if [ -z "$sizes" -o "$default_size" = -1 ]; then
        if [ "$needed" ]; then
            non_fatal  "Not enough space on device to create %s file" "$(pqh $file)"
        else
            warn  "Not enough space on device to create %s file" "$(pqw $file)"
        fi
        return 1
    fi

   # Include all available space as last entry in menu if it is appropriate
    local max=$(echo "$sizes" | sed 's/.* //')
    [ $max -lt $max_size ] && sizes="$sizes $max_size"

    local fs_type fs_size auto_mode create_mode quit=$(printf  "$_quit_")

    heading  "$_create_X_persistence_file_" "$(fq $file)"
    vmsg 1  "$_Default_size_X_Filesystem_type_Y_" "$(nq_label_meg $default_size)" "$(pq ext4)"
    vmsg 1  "$_This_default_size_will_leave_X_free_" "$(nq_label_meg $((avail - default_size)))"
    [ "$is_vfat" ] &&  warn  "Warning: this can take several minutes per Gig on a %s file system" $(pqw $part_fstype)

    if [ "$AUTO_MAKE_FS" ]; then
        auto_mode=true
    else
        local title=$(printf  "$_Create_X_file_manually_or_automatically_" $(fq $file))
        my_select "$title" create_mode 0 1  "$_create_automatically_"  "$_create_custom_" "$quit"
        case $create_mode in
                             "$_quit_") return 1 ;;
             "$_create_automatically_") auto_mode=true ;;
        esac
    fi

    if [ "$auto_mode" ]; then
        fs_type=ext4
        fs_size=$default_size

    else
        local title=$(printf  "$_Please_select_size_of_X_file_" $(pqw $file))

        echo
        vmsg 1  "$_There_is_X_available_on_the_device_" "$(nq_label_meg $avail)"

        size_menu fs_size "$title" "" $sizes
        [ "$fs_size" =  "$_quit_" ] && return 1

        vmsg 1  "$_Filesystem_size_X_" "$(nq_label_meg $fs_size)"
        fs_type=ext4
    fi

    vmsg 1  "$_Create_X_file_of_type_Y_and_size_Z_" "$(fq $file)" "$(pq $fs_type)" "$(nq_label_meg $fs_size)"

    # Now do the actual work

    mount -o remount,rw $SQFILE_DEV 2>/dev/null

    #breakpoint m "before makefs"

    [ "$is_vfat" ] &&  warn  "$_Warning_this_can_take_several_minutes_per_Gigabyte_on_a_X_file_system_" $(pqw $part_fstype)
    if ! time_cmd makefs $full_file $fs_type $fs_size $part_fstype; then
        err  "Failed to create filesystem.  Deleting %s file" $(pqe $file)
        rm -f $full_file
        return 3
    fi

    do_fsck "new $file file" $full_file -p filefs || return 1

    MADE_PERSIST_FILE=true

    eval $needed_var=\$needed
    eval $wanted_var=\$wanted

    return 0
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
makefs() {
    local file=$1  fstype=$2  size=$3  part_fstype=$4  dir=$(dirname $file)
    local base_file=${file##*/}
    base_file=${base_file%%.*}
    local fs_label=""
    case $fstype in
        ext*) fs_label="-L $base_file" ;;
    esac

    mkdir -p $dir || return 1
    local fallocate=$(ld_path_which fallocate)
    [ "$fallocate" ] || part_fstype=other

    case $part_fstype in
        ext4|btrfs) ld_path $fallocate --length ${size}M $file        1>> $MY_LOG 2>>$MY_LOG || return 2 ;;
                 *) dd if=/dev/zero of=$file bs=1M count=0 seek=$size 1>> $MY_LOG 2>>$MY_LOG || return 2 ;;
    esac
    sync
    ld_path /sbin/mkfs.$fstype -q -F $fs_label $file 1>> $MY_LOG 2>> $MY_LOG || return 3
    return 0
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
default_makefs_size() {
    local avail=$1  size=$3  params
    eval params=\$$2
    eval local $params
    [ "$avail" -lt $mid_size ] && factor=100
    [ "$size" ] || size=$((mid_size + factor * ( avail - mid_size ) / 100))
    [ $size -gt $max_size ] && size=$max_size
    [ $size -gt $avail    ] && size=$avail
    [ $size -lt $min_size ] && return 1

    # Round
    if [ $size -gt $((3 * 1024)) ]; then
        size=$(((size/1024) * 1024))
    elif [ $size -gt 500 ]; then
        size=$(((size/100) * 100))
    fi

    echo $size
    return 0
}

#------------------------------------------------------------------------------
# Let user select from a wide range of sizes
#------------------------------------------------------------------------------
size_menu() {
    local var=$1 title=$2  max_s=${3:-12} ; shift 3

    # create a variable for each row
    local i
    for i in $(seq 1 $max_s); do
        eval local s_$i
    done

    # Fill the rows with  "cnt) label"
    local cnt=0  scnt=0  size  data label  s
    for size in $* quit ; do
        cnt=$((cnt + 1))
        scnt=$((scnt + 1))

        case $size in
                quit) label=$(bq  "$_quit_")       ;;
            *[^0-9]*) label=$(bq "$size")      ;;
                   *) label=$(label_meg $size) ;;
        esac

        data="$data$cnt:$size\n"
        eval s=\$s_$scnt
        s="$s$(printf "%3s) %-12s" "$cnt" "$label")"
        eval s_$scnt=\$s
        [ $scnt -ge $max_s ] && scnt=0
    done
    [ $cnt -lt $max_s ] && max_s=$cnt

    local display
    for cnt in $(seq 1 $max_s); do
        eval s=\$s_$cnt
        display="$display$s\n"
    done

    display=$(echo -e "$display" | sed -r -e "s/( [0-9]+)(\))/ $green\1$white\2$cyan/g" -e "s/$/$nc_co/")

    my_select_2 "$title"  $var  "" "$data" "$display"
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
select_persist_device() {
    tsplash_clear
    local device label=$1
    warn
    warn  "Could not find a partition with label %s" "$(pqw $label)"
    warn
    msg  "$_Please_wait_while_existing_partitions_are_found_"

    select_device  "$_persistence_" device 100 || return 1
    local ret=$?

    [ -z "$device" -o "$device" =  "$_quit_" ] && return 1

    label_device $device "$AUTO_PERSIST"
    PERSIST_ID=name=$device
    return $ret
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
fsck_persist_dev() {
    local persist_files=$1; shift
    [ "$persist_files" ] || return
    if ! _fsck_persist_dev "$@"; then
        unset WANT_ROOTFS WANT_HOMEFS
    fi
}

_fsck_persist_dev() {
    local dev=$1  mp=$2

    should_fsck $dev persist || return 0

    if ! umount $mp &> /dev/null; then
        vmsg 6  "Not checking persist filesystem because it can't be unmounted"
        return 0
    fi

    do_fsck  "$_persist_device_" $dev -p
    try_mount $dev $mp && return 0

    non_fatal  "Could not remount the persistence device"
    return 1
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
mount_and_copy_rootfs() {
    if _mount_and_copy_rootfs "$@"; then
        PERSIST_ROOT=true
        if [ "$STATIC_ROOT" ]; then
            ROOTFS_DEV=$PERSIST_DEVICE
            msg  "$_Enabled_X_persistence_" "$(cq static root)"
            PERSISTENCE="root,static"
        else
            msg  "$_Enabled_X_persistence_" "$(cq dynamic root)"
            PERSISTENCE="root,dynamic"
        fi
    else

        STATIC_ROOT=
        [ "$NEED_ROOTFS" ] && non_fatal  "Could not enable required %s persistence" "$(pqh root!)"
    fi
}

_mount_and_copy_rootfs() {
    mount_persist_file rootfs "$ROOTFS_MP" root "$WANT_ROOTFS" "$NEED_ROOTFS" || return 1
    PERSIST_ROOT_FULL="$PERSIST_FULL_PATH/rootfs"
    check_existing_unionfs $ROOTFS_MP                                         || return 1
    check_vid "$SQFS_VID" "$ROOTFS_BASE" rootfs.ver                           || return 1
    [ "$STATIC_ROOT" ] || copy_persist_to_ram                                 || return 1

    return 0
}

#------------------------------------------------------------------------------
# Function: copy_persist_to_ram
#------------------------------------------------------------------------------

copy_persist_to_ram() {

    vmsg 6  "Put persistent root in RAM (from %s)"  "$ROOTFS_MP"

    local persist_used_k=$(du -sk $ROOTFS_MP | awk '{print $1}')
    local persist_used=$((persist_used_k / 1024))
    local format="%s: $num_co%5d ${m_co}M"

    vmsg 7 "$format" '              Persistence uses' $persist_used

    if [ "$persist_used" -ge "$AUFS_RAM_SIZE" ]; then
        vmsg_nc 3 $tbar
        err   "Not enough RAM to hold persistent root"
        # You need to <live-remaster> or use <static root> persistence
        warn  "You need to %s or use %s persistence" live-remaster "$(cq static root)"
        vmsg_nc 3 $tbar
        return 1
    fi
    vmsg 5  "$_Copy_X_to_RAM_" "$(nq_label_meg $persist_used)"
    if ! cp_dir $ROOTFS_MP $AUFS_RAM_MP 2>&1; then
         err  "Copy persistent root to RAM failed!  Will erase partial copy ..."
         rm -rf $AUFS_RAM_MP/*
         return 2
    fi
    local ram_used=$(used_space $AUFS_RAM_MP)
    # AUFS uses [this much RAM]
    vmsg 7 "$format" '                     AUFS uses' $ram_used
    vmsg 7 "$format" '              Persistence uses' $persist_used
    vmsg 6 "${hi_co}%s"  "Copy persistent root to RAM succeeded"

    DF_ROOTFS=$(df -Pm $ROOTFS_MP | tail -n 1 | sed 's/ \+/ /g')
    sync
    log_cmd umount $ROOTFS_MP
    return 0
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
mount_persist_file() {
    local file=$1  mpnt=$2  type=$3  want=$4  need=$5

    [ "$want" ]              || return 1
    [ "$PERSIST_FULL_PATH" ] || return 1

    local full=$(readlink -f $PERSIST_FULL_PATH/$file)

    if ! [ -f "$full" ]; then
        [ "$need" ] && err  "Could not find file %s for required %s persistence" \
            "$(pqh $file)" "$type"
        return 3
    fi

    if should_fsck $full "$type file"; then
        do_fsck "$file file" $full -p filefs || return 1
    fi

    heading  "$_mount_persistence_file_X_at_Y_" "$(fq $file)" "$(fq $mpnt)"

    mkdir -p $mpnt
    if ! try_file_mount $full $mpnt; then
        #. Could not mount file <filename> for <type> persistence
        err  "Could not mount file %s for %s persistence" "$full" "$type"
        err  "Did not enable %s persistence" "$type"
        return 4
    fi

    return 0
}

#------------------------------------------------------------------------------
# Function: remaster_rootfs <mountpoint> <full_path>
#
# If we did a remaster or rollback on linuxfs then we perform a similar
# operation on the rootfs file if it exists.  We have already remastered
# the rootfs file in the boot directory so if that is the same as this
# (persist) directory we do nothing here.
#------------------------------------------------------------------------------
remaster_rootfs() {
    local mp=$1  path=$2

    if [ "$DID_REMASTER" -o "$DID_ROLLBACK" ]; then
        if [ "$path" = "$BOOT_MP/$SQFILE_PATH" ]; then
            vmsg 6  "Will not remaster %s twice" rootfs
            return
        fi
    fi

    if [ "$DID_REMASTER" ]; then
        [ -e "$path/rootfs"  ]    && mv $path/rootfs     $path/rootfs.old
        [ -e "$path/rootfs.new" ] && mv $path/rootfs.new $path/rootfs
    fi

    if [ "$DID_ROLLBACK" ]; then
        [ -e "$path/rootfs"  ]    && mv $path/rootfs     $path/rootfs.bad
        [ -e "$path/rootfs.old" ] && mv $path/rootfs.old $path/rootfs
    fi
}

#------------------------------------------------------------------------------
# Do the dirty work in addition to mounting homefs: copy homefs to homefs.new
# for easy re-sizing; offer to copy /home files that would be hidden by
# mounting homefs.
#------------------------------------------------------------------------------
mount_homefs() {
    local homefs=$1  real_home=$2  want=$3  need=$4  temp_home=/tmp/home
    [ "$want" ] || return

    # First do the resize copy
    local new=$homefs.new
    if [ -e "$new" ]; then
        copy_homefs "$homefs" || mv $new $homefs.bad
    fi

    mkdir -p $temp_home $real_home
    # Now mount the homefs at a temporary mount point
    if ! mount_persist_file 'homefs' $temp_home 'home' "$want" "$need"; then
        [ "$need" ] && non_fatal  "Could not enable required %s persistence" "$(pqh home!)"
        return
    fi

    if ! offer_copy_home_dir  $real_home  $temp_home; then
        if ! YES_no  "$_Do_you_want_to_enable_home_persistence_anyway_"; then
            log_cmd umount $temp_home
            return
        fi
    fi

    # Move the homefs mount to its real location
    if mount -o move $temp_home $real_home; then
        HOMEFS_DEV=$PERSIST_DEVICE
        msg  "$_Enabled_X_persistence_" "$(cq home)"
        PERSISTENCE="$PERSISTENCE${PERSISTENCE:+,}home"
    else
        err  "$_Strange_couldnt_move_the_homefs_mountpoint_"
        [ "$need" ] && non_fatal  "Could not enable required %s persistence" "$(pqh home!)"
    fi
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
offer_copy_home_dir() {
    local real=$1  temp=$2

    empty_dir $real && return 0
    empty_dir $temp || return 0

    local needed=$(du_size $real)
    local avail=$(avail_space $temp)
    local margin=$((avail - needed))
    msg  "$_There_are_X_MiB_of_files_that_will_get_hidden_by_home_persistence_"  $(nq $needed)
    msg  "$_There_are_X_MiB_free_on_the_home_persistence_device_"                $(nq $avail)

    if [ $margin -lt 50 ]; then
        msg  "$_Theres_not_enough_space_to_copy_all_the_files_"
        return 1
    fi

    YES_no  "$_Do_you_want_to_copy_the_files_to_the_home_persistence_device_" \
        || return 2

    # copy files here
    time_cmd ld_path rsync -aq --delete $real/ $temp/
    local ret=$?

    # FIXME:  Then offer to erase if extra not in linuxfs?
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
empty_dir() {
    local dir=$1
    local cnt=$(ls "$dir" | grep -v "^lost+found$" | wc -l)
    msg "files in $dir: $cnt"

    [ $cnt -eq 0 ]
    return $?
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
copy_homefs() {
    local homefs=$1

    if ! [ -e "$homefs" ]; then
        msg  "$_No_X_file_found_Rename_Y_to_Z_" homefs homefs.new homefs
        mv $homefs.new $homefs
        return 0
    fi

    local cur_home_mp=/tmp/homefs  new_home_mp=/tmp/homefs.new

    log_cmd mkdir -p $cur_home_mp $new_home_mp

    if ! log_cmd mount -o loop $homefs $cur_home_mp; then
        err  "Could not mount %s for copy" homefs
        return 1
    fi

    if ! log_cmd mount -o loop $homefs.new $new_home_mp; then
        err  "Could not mount %s for copy" homefs.new
        return 1
    fi

    local need_meg=$(used_space $cur_home_mp)
    local have_meg=$(all_space $new_home_mp)
    need_meg=$((need_meg + 10))
    vmsg 6  "$_Have_X_MiB_free_Need_Y_" "$(nq $have_meg)" "$(nq $need_meg)"
    if [ "$need_meg" -gt "$have_meg" ]; then
        err  "Not enough room to copy home filesystem"
        return 1
    fi

    msg  "$_Resize_homefs_Copy_contents_of_X_to_Y_" $(pq homefs) $(pq homefs.new)

    msg  "$_Copy_home_filesystem_Please_be_patient_"

    #breakpoint r "Before resize homefs rsync"

    time_cmd ld_path rsync -aq --delete $cur_home_mp/ $new_home_mp/
    local ret=$?

    #breakpoint r "After resize homefs rsync"

    if [ "$ret" -ne 0 ]; then
        err  "The %s program failed.  Will not resize %s" $(pqe rsync) $(pqe homefs)
        return 1
    fi

    log_cmd umount $cur_home_mp
    log_cmd umount $new_home_mp

    log_cmd mv -f $homefs $homefs.old
    log_cmd mv -f $homefs.new $homefs

    return 0
}

#------------------------------------------------------------------------------
# Disable login on tty1
#------------------------------------------------------------------------------
disable_tty1() {
    local dir=$1
    sed -r -i "s/^\s*(1:2345:respawn)/# \1/" $dir/etc/inittab
}

#------------------------------------------------------------------------------
# Automatically log in on given set of virtual consoles
#------------------------------------------------------------------------------
auto_login() {
    local dir file full prog=$1  terms=$2 root=$3
    [ -n "$prog" -a -n "$terms" ] || return

    db_msg "Enable autologin"

    if ! confile systemd; then
        sed -i.bak -r "/autologin/! s=^([$terms]:[0-9]+:respawn:[^ ]+)=\1 --autologin root=" $root/etc/inittab
        return
    fi

    local term dir sysd_dir=$root/etc/systemd/system
    [ -d $sysd_dir ] || return
    for term in $(echo $terms | sed -r 's/(.)/\1 /g'); do
        dir=$sysd_dir/getty@tty$term.service.d/
        mkdir -p $dir
        cat << AutoLogin > $dir/autologin.conf
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin root --noclear %I 38400 linux
AutoLogin

    done
    return
}

#------------------------------------------------------------------------------
# Bind page-up and page-down to history searches in Bash
#------------------------------------------------------------------------------
page_updown_keys() {
    local file=$1/etc/inputrc
    test -e $file || return
    sed -i "/history-search/ s/^#\s*//" $file
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
fancy_prompt() {
    local prompt=${1:-prompt-fancy}  dir=$2
    local bashrc=$dir/etc/skel/.bashrc  fp_prog=/usr/bin/fancy-prompts.bash
    if [ -e "/usr/local/bin/fancy-prompts.bash" ]; then
		fp_prog=/usr/local/bin/fancy-prompts.bash
	fi

    local cmd=${prompt%%\ *}
    [ -r $dir/$fp_prog -a -n "$prompt" ] || return

    if grep -q $cmd $bashrc; then
        db_msg 'fancy prompts were already enabled'
    else
        db_msg 'Enable fancy prompts and other goodies'
        cat << Fancy_Stuff >> $bashrc

#----- Added by live initrd init script
LESS="-R -i"
[ -r $fp_prog ] && source $fp_prog
[ -n "\$(alias $cmd)" ] && $prompt
echo \$PATH | grep -q /live/bin || PATH=\$PATH:/etc/live/bin
Fancy_Stuff

    fi

    sync

    local file full_file
    for file in .bashrc .profile; do
        full_file=$dir/etc/skel/$file
        [ -f "$full_file" ] && cp $full_file $dir/root
    done
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
copy_xtra() {
    local dir bdir=$1 xtra_dir=$1/xtra tarball=$1/xtra.tgz

    if [ -e $tarball ]; then
        msg 'Unpack xtra tarball'
        gunzip -c "$tarball" | tar x -C $NEW_ROOT/
    fi

    local live_xtra='/live/xtra'

    if  [ -d "$live_xtra" -a ! -d "$xtra_dir" ]; then
        msg 'Copy xtra file(s) from %s' "$(fq "$live_xtra")"

        # Copy into the antiX/xtra dir if we can,
        # otherwise copy directly to the aufs from the initrd
        if remasterable; then
            mkdir -p "$xtra_dir"
            (cd "$live_xtra" && tar cf - *) | tar x -C "$xtra_dir"
        else
            xtra_dir="$live_xtra"
        fi
    fi

    [ -d "$xtra_dir" ] || return

    local list=$(ls $xtra_dir)
    [ -n "$list" ] || return

    msg 'Copy xtra file(s) to: %s' "$(fq $list)"

    # Use tar because cp stumbles on some symlinks in target directory
    (cd "$xtra_dir" && tar cf - *) | tar x -C "$NEW_ROOT"
    
    # Create a symlink to the /antiX/xtra directory if it exists
    local r_dir="$NEW_ROOT/root"
    local x_dir="$DEFAULT_DIR/xtra"

    test -e $r_dir/xtra && return
    test -d $r_dir && test -d $x_dir && log_cmd ln -s $x_dir $r_dir/xtra
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
prep_vcard() {
    local vcard_cmd=$1  file=$VCARD_CONF_FILE
    local vcard_cnt=$(lspci | grep  "$_Class_03_" | wc -l)
    case $vcard_cnt in
        0) msg  "$_Found_no_video_display_devices_"                    ;;
        1) msg  "$_Found_one_video_display_device_"                    ;;
        *) msg  "$_Found_X_video_display_devices_" "$(nq $vcard_cnt)" ;;
    esac

    case $vcard_cmd in
                   on|"") [ $vcard_cnt -gt 1 ] && touch $file                         ;;
          off|menu|clear) echo $vcard_cmd > $file                                     ;;
                       *) warn  "$_Unexpected_X_value_Y_" "$(pqw vcard)" "$(vcard_cmd)" ;;
    esac
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
delete_files() {
    local bdir=$1
    local dfile=$bdir/delete.list
    test -e $dfile || return
    msg 'Deleting files listed in %s' $(pq $dfile)
    grep -v "^\s*#" $dfile | sed "s=^\s*/=$NEW_ROOT/=" | grep "/[a-z]" >> $MY_LOG
    rm -rf $(grep -v "^\s*#" $dfile | sed "s=^\s*/=$NEW_ROOT/=" | grep "/[a-z]")
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
ld_path_which() {
    local xdir prog=$1
    for xdir in /sbin /bin /usr/sbin /usr/bin /usr/local/bin; do
        [ -x $LD_ROOT_DIR$xdir/$prog ] || continue
        echo $xdir/$prog
        return 0
    done
    return 1
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
ld_path() {
    local xdir found prog=$1

    [ -n "${prog##/*}" ] && prog=$(ld_path_which $prog)

    if [ -z "$prog" ]; then
        echo "${err_co}Program %s not found under $LD_ROOT_DIR" "$(pqe $1)"  >&2
        return 1
    fi

    shift
    LD_LIBRARY_PATH=$LD_PATH $SET_ARCH $LD_ROOT_DIR$prog "$@"
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
prep_ld_path() {
    local ld_path arch=$(uname -m)  dir=${1:-$SQFS_MP}

    LD_ROOT_DIR=$dir

    SET_ARCH=
    case $arch in
          x86_64) ld_path=$LIVE_X64_LD_PATH
                  SET_ARCH=linux64           ;;

        i[3-8]86) ld_path=$LIVE_386_LD_PATH
                  SET_ARCH=linux32           ;;

               *) warn 'unknown architecture %s. Assuming %s' $(pqw $arch) $(pqw i686)
                  ld_path=$LIVE_386_LD_PATH;;
    esac

    LD_PATH=$(echo $ld_path | sed -r "s=(^|:)=\\1$dir=g")

    vmsg 8 "LD_PATH: $LD_PATH"
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
prep_lib64() {
    local dir=$1
    mkdir -p /lib64
    local loader name dest
    for loader in $dir/lib64/ld-linux-x86-64*; do
        name=$(basename $loader)
        dest=$(readlink $loader)
        ln -sf $dir$dest /lib64/$name
    done
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
mountpoints_under() {
    local dev mp other ret=1 dir=$1

    while read dev mp other; do
        case $mp in $dir/*)
            echo -n "$mp "
            ret=0 ;;
        esac
    done << Read_Mounts
$(tac /proc/mounts)
Read_Mounts
    return $ret
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
chroot_umount() {
    local mp list i  dir=${1:-$LD_ROOT_DIR}

    [ "$dir" ] || return

    for i in $(seq 1 4); do
        list=$(mountpoints_under $dir) || return 0
        vmsg 7 'umount %s' "$(pq $list)"
        for mp in $list; do
            umount $mp
        done
    done
    list=$(mountpoints_under $dir) || return 0
    err  "Unable to unmount %s" "$(hq $list)"
    return 1
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
confile() {
    local file dir=/live/config
    for file; do
        test -e $dir/$file && return 0
    done
    return 1
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
write_output_files() {
    local dir=$1  out_file=$1/initrd.out pattern1="$LIVE_DIR" pattern2="$FINAL_DIR"
    mkdir -p $dir
    #rm -f $dir/* 2>/dev/null

    [ true ] && cat > $out_file <<Initrd_Out
#$tbar
#              file: $out_file
#      generated by: $ME script
#   sometime around: $(date)
#$tbar
AUFS_MP="${AUFS_MP/"$pattern1"/"$pattern2"}"
AUFS_RAM_MP="${AUFS_RAM_MP/"$pattern1"/"$pattern2"}"
AUFS_VID_FILE="${AUFS_MP/"$pattern1"/"$pattern2"}$VID_FILE"
BIOS_DEV="${BIOS_DEV/"$pattern1"/"$pattern2"}"
BIOS_MP="${BIOS_MP/"$pattern1"/"$pattern2"}"
BIOS_UUID="$BIOS_UUID"
BOOT_DEV="$SQFILE_DEV"
BOOT_FSTYPE="$BOOT_FSTYPE"
BOOT_MP="${ORIG_SQFILE_MP/"$pattern1"/"$pattern2"}"
BOOT_UUID="$BOOT_UUID"
CRYPT_UUID="$CRYPT_UUID"
DF_ROOTFS="$DF_ROOTFS"
DID_REMASTER="$DID_REMASTER"
DID_ROLLBACK="$DID_ROLLBACK"
DID_TORAM="$DID_TORAM"
DISTRO="$DISTRO_NAME"
DISTRO_BASE="$DISTRO_BASE"
DISTRO_CODENAME="$DISTRO_CODENAME"
DISTRO_VERSION="$DISTRO_VERSION"
ENCRYPTED="$ENCRYPTED"
FULL_DISTRO="$DISTRO_NAME-$DISTRO_VERSION"
INITRD_DATE="$VERSION_DATE"
INITRD_VERSION="$VERSION"
LIVE_DIR="$FINAL_DIR"
PERSISTENCE="$PERSISTENCE"
PERSIST_DEV="${PERSIST_DEVICE/"$pattern1"/"$pattern2"}"
PERSIST_DIR="${PERSIST_FULL_PATH/"$pattern1"/"$pattern2"}"
PERSIST_FILE="${PERSIST_ROOT_FULL/"$pattern1"/"$pattern2"}"
PERSIST_MP="${PERSIST_MP/"$pattern1"/"$pattern2"}"
PERSIST_PATH="${PERSIST_PATH/"$pattern1"/"$pattern2"}"
PERSIST_UUID="$PERSIST_UUID"
REMASTERABLE="$REMASTERABLE"
ROOTFS_MP="${ROOTFS_MP/"$pattern1"/"$pattern2"}"
RW_MODE="$RW_MODE"
SQFILE_DIR="${ORIG_SQFILE_MP/"$pattern1"/"$pattern2"}/$ORIG_SQFILE_DIR"
SQFILE_FULL="${ORIG_SQFILE_MP/"$pattern1"/"$pattern2"}/$ORIG_SQFILE_FULL"
SQFILE_NAME="$SQFILE_NAME"
SQFILE_PATH="$SQFILE_PATH"
SQFS_MP="${SQFS_MP/"$pattern1"/"$pattern2"}"
SQFS_VID_FILE="${SQFS_VID_FILE/"$pattern1"/"$pattern2"}"
STATIC_ROOT="$STATIC_ROOT"
TORAM_MP="${TORAM_MP/"$pattern1"/"$pattern2"}"
TORAM_STORE="${TORAM_STORE/"$pattern1"/"$pattern2"}"
TORAM_ALL="$TORAM_ALL"
USER_GID="$USER_GID"
USER_UID="$USER_UID"
VID_ERROR="$VID_ERROR"
VID_FILE="${VID_FILE}"
Initrd_Out

    echo "$SQFILE_DEV" > $dir/boot-device

    [ -e /sys/firmware/efi ]                 && touch $dir/uefi
    [ "$DID_TORAM"    ]                      && touch $dir/did-toram
    [ "$TORAM_ALL"    ]                      && touch $dir/toram-all
    [ "$TORAM_STORE"  ]                      && touch $dir/toram-store
    [ "$REMASTERABLE" ]                      && touch $dir/remasterable
    [ "$PERSIST_ROOT" ]                      && touch $dir/persist-root
    [ "$PERSIST_ROOT" -a -z "$STATIC_ROOT" ] && touch $dir/save-persist
    [ "$PERSIST_ROOT" -a -n "$STATIC_ROOT" ] && touch $dir/static-root
    [ "$FORCE_PASSWD" ]                      && touch $dir/force-passwd
    [ "$DB_PLUS"      ]                      && touch $dir/db+
    [ -n "$BOOT_SAVE" ]                      && touch $dir/bootsave
    [ "$BOOT_CHART"   ]                      && touch $dir/bootchart
    [ "$DO_HWCLOCK"   ]                      && touch $dir/hwclock
    [ "$DO_DEB"       ]                      && touch $dir/deb-install
    [ "$LOW_COLOR"    ]                      && touch $dir/low-color
    [ "$NO_COLOR"     ]                      && touch $dir/no-color
    [ "$ENCRYPTED"    ]                      && touch $dir/encrypted

    echo "$DISTRO_NAME"                             > $dir/distro
    echo "$DISTRO_BASE"                             > $dir/distro-base

    [ "$DID_TORAM" ] && [ "$(stat -c %t $SQFILE_DEV)" = b ] \
        && echo "BOOT_DEV=$SQFILE_DEV" > $dir/toram-eject

    is_laptop && touch $dir/laptop

    local f full
    for f in version $MADE_BY_FILE; do
        full=$BOOT_MP/$f
        test -e $full && cp $full $dir/
    done
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
update_store_file() {
    local disable=$1  enable=$2
    remasterable || return

    local no_store_file=$ORIG_SQFILE_MP/$ORIG_SQFILE_DIR/state/nostore
    if [ "$disable" ]; then
        test -e $no_store_file && return
        mkdir -p $(dirname $no_store_file)
        touch $no_store_file

    elif [ "$enable" ]; then
        rm -f $no_store_file
    fi
}


#------------------------------------------------------------------------------
# Is this a laptop?  For the first test see:
# https://superuser.com/questions/877677/programatically-determine-if-an-script-is-being-executed-on-laptop-or-desktop/877796
#------------------------------------------------------------------------------
is_laptop() {
    local chassis=$(cat /sys/class/dmi/id/chassis_type 2>/dev/null)
    case $chassis in
        9|10|14) return 0 ;;
    esac

    grep -q Battery /sys/class/power_supply/BAT*/type 2>/dev/null
    return $?
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
write_log_files() {
    local my_log=$1 color_log=$2.color
    mkdir -p $(dirname $color_log)
    cp $my_log $color_log
    decolor_file $color_log
}

#------------------------------------------------------------------------------
# Make a copy of /var/log/live/ at /root/Live-usb-storage/live-logs
# Backup the previous version with a .old extension.
#------------------------------------------------------------------------------
copy_live_logs() {
    local new_root=$1  log_dir=$2
    local targ_dir=$new_root/root/Live-usb-storage
    test -d $targ_dir || return
    local targ_live=$targ_dir/$LIVE_LOGS_DIR
    local targ_old=$targ_live.old

    # Make room for new .old directory
    [ -e $targ_live -a -e $targ_old ] && rm -rf $targ_old

    # Save current to .old
    [ -e $targ_live ] && mv $targ_live $targ_old

    cp -r $new_root$log_dir $targ_live
    [ "$DB_PLUS" ] && cp -r $new_root/live/config $targ_live/
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
decolor_file() {
    local file=$1  new=${1%.color}  e=$(printf "\e")

    test -r $file || return
    [ "$file" = "$new" ] && return
    sed -r "s/$e\[[0-9;]+[mK]//g" $file > $new
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
find_init_prog() {
    local d prog  full_prog prog_var=$1  dir=$2
    eval prog=\$$prog_var
    [ "$prog" ] || return 1

    for d in "" /sbin/ /bin/ /usr/sbin/ /usr/bin/ /usr/local/bin/; do
        [ -e $dir$d$prog ] || continue
        full_prog=$dir$d$prog
        eval $prog_var=\$d\$prog
        break
    done

    if [ -z "$full_prog" ]; then
        err 'Could not find program %s. Will use %s' $prog "/sbin/init"
        return 1
    fi

    if [ ! -x $full_prog ]; then
        err 'Program %s is not executable.  Will use %s'  $d$prog "/sbin/init"
        return 1
    fi
    return 0
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
run_init_scripts() {
    local new_root=$1; shift

    mkdir -p $new_root/etc/live/protect $new_root/run/lock

    local script full now last_time=$(get_time)
    for script; do
        full=$FINAL_DIR/etc/init.d/$script
        test -x $new_root/$full || continue
        $SET_ARCH chroot $new_root $full start
        [ "$DB_PLUS" ] || continue
        now=$(get_time)
        vmsg 8 "%25s @ %s seconds" $script $(pq $(get_seconds $((now - last_time))))
        last_time=$now
    done

    #-jbb # Do a persist-save to save new passwords and persist save mode
    #-jbb [ -f $new_root/live/config/new-passwords       ] || return
    #-jbb [ -f $new_root/live/config/persist-save.conf   ] || return

    #-jbb local persist_save=/usr/local/bin/persist-save
    #-jbb [ -x $new_root$persist_save                    ] || return
    #-jbb msg "Do persist-save"
    #-jbb chroot $new_root $persist_save --cli --nolog --quiet
}

# Copy src to dest if they are different
update_file() {
    local src=$1  dest=$2  if_exists=$3
    [ ${#if_exists} -gt 0 -a ! -e $dest ] && return
    test -e $src || return
    diff -q $src $dest &>/dev/null && return
    cp -a $src $dest
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
press_enter() {
    # As in:  Press Enter to continue
    local ans enter="Enter"
    msg  "$_Press_X_to_continue_" "$(pq "$enter")"
    read ans
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
detect_vga_menu() {
    local cmd_code=$1
    unset NEW_VGA_CODE

    [ -z  "$cmd_code" ] && return

    # Convert hex to decimal
    [ -z "${cmd_code##0[xX]*}" ] && cmd_code=$(printf "%d" $cmd_code)

    local cmd_res
    case $cmd_code in
        # Standard resolution codes
            769|785|786) cmd_res=640,480   ;;
            771|788|789) cmd_res=800,600   ;;
            773|791|792) cmd_res=1024,768  ;;
            775|794|795) cmd_res=1280,1024 ;;

        # do nothing with non-standard resolution codes
        [0-9][0-9][0-9]) return            ;;

        # We will skip asking of they want to save if they used "ask"
                    ask) cmd_res=ask       ;;

        # Everything else is treated as "other" (which is not used)
                      *) cmd_res=other     ;;
    esac

    local sdir="/sys/class/graphics"
    local cur_res=$(cat $sdir/fb0/virtual_size 2>/dev/null)

    [ -z "$cur_res" ]            && return
    [ "$cmd_res" == "$cur_res" ] && return

    warn  "$_It_appears_you_selected_VGA_resolution_X_" "$(pq $cur_res)"

    remasterable                || return
    [ "$cmd_res" == 'ask' ]     && return
    [ -n "$GFX_SAVE" ]          && return

    # We should only get here if saving makes sense, if they didn't didn't
    # already tell us to save, if there is a framebuffer and if a standard
    # resolution was specified but does not match the current resolution.
    #
    # NOTE: we only check for the "true" vga code when saving when either
    # "vga=ask" or "vga=ask+save" was used.  Therefore we still miss the
    # case where someone uses a non-standard vga=code and gets the VGA menu.
    YES_no  "$_Would_you_like_to_save_this_resolution_for_subsequent_boots_" || return

    sed -i -r "s/(^| )vga=[^ ]*/\1vga=ask+save/" /live/config/proc-cmdline
    PROC_CMDLINE=$(cat /live/config/proc-cmdline)
    GFX_SAVE=both
    BOOT_SAVE=true
    msg  "$_Will_save_the_new_VGA_setting_and_your_other_boot_parameters_"
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
detect_old_persist_scripts() {
    local root=$1
    local lib_file=$root/usr/lib/antiX/antiX-common.sh
    if [ -e "$root/usr/lib/antiX/antiX-commons.sh" ]; then
		lib_file=$root/usr/local/lib/antiX/antiX-common.sh
	fi
	local enabled_file=$root/usr/bin/persist-enabled
	if [ -e "$root/usr/local/bin/persist-enabled" ]; then
		enabled_file=$root/usr/local/bin/persist-enabled
	fi

    if [ -e $lib_file ]; then
        head -n 20 $lib_file | grep -q /etc/live/config || return 0
    fi

    if [ -e $enabled_file ]; then
        grep -q /etc/live/config $enabled_file || return 0
    fi

    return 1
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
late_umount() {
    local dev=$1

    [ "$dev" ]       || return
    [ "$NO_UMOUNT" ] && return

    ## It does not suffice to only disable the liveCD (see below)
    #[ "$TO_RAM_EJECT" ] || return

    local dep
    # Don't umount these devcies because they are actively used
    for dep in $HOMEFS_DEV $ROOTFS_DEV $LINUXFS_DEV; do
        [ "$dep" = "$dev" ] && return
    done

    # Don't umount if not mounted
    cut -d" " -f1 /proc/mounts | grep -q "^$dev$" || return

    msg  "$_umount_X_" $(pq $dev)
    local success
    for i in $(seq 1 5); do
        log_cmd umount $dev 2>/dev/null
        if cut -d" " -f1 /proc/mounts | grep -q "^$dev$"; then
            usleep 500000
            continue
        fi
        success=true
        break
    done
    [ "$success" ] || err  "$_umount_of_X_failed_" $(pqe $dev)

    # If this was the encrypted device then close the mapping
    [ "$dev" = "$CRYPT_DEV" ] || return
    log_cmd $SET_ARCH chroot /live/aufs /sbin/cryptsetup close "$LUKS_NAME"
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
write_ntfs_pids() {
    local file=$1  ntfs_pids=$(pgrep ntfs-3g)
    [ "$ntfs_pids" ] || return
    mkdir -p $(dirname $file)
    echo "$ntfs_pids" > $file
}


#------------------------------------------------------------------------------
# This makes old live-usb-maker acting on a new iso just like the new LUM.
#------------------------------------------------------------------------------
fix_old_lum() {
    boot_mp=$1  bios_uuid=$2

    test -e $boot_mp/$DID_EFI_FILE  && return 0
    test -e $boot_mp/$EFI_GRUB_CONF || return 0

    msg  "$_Updating_grub_config_to_X_" "$(pq 2.0)"

    vmsg 7 'Using BIOS UUID: %s' "$(pq $bios_uuid)"

    [ -z "$bios_uuid" ] && return 1

    local efi_uuid efi_uuid_file=$boot_mp/$UEFI_UUID_FILE
    test -r $efi_uuid_file || return 1
    read efi_uuid 2>/dev/null <$efi_uuid_file

    vmsg 7 'EFI UUID: %s' "$efi_uuid"
    [ ${#efi_uuid} -gt 0 ] || return 1

    local efi_mp=/live/efi
    mkdir -p $efi_mp
    local dev=$(uuid_to_dev $efi_uuid)
    vmsg 7 'EFI device; %s'  "$dev"
    test -b "$dev" || return 1

    log_cmd mount "$dev" "$efi_mp"
    mountpoint -q $efi_mp || return 1

    local efi_grub_dir="$efi_mp/boot/grub"
    log_cmd rm -rf   "$efi_grub_dir"
    log_cmd mkdir -p "$efi_grub_dir"

    local efi_grub_cfg="$efi_grub_dir/grub.cfg"
    log_cmd cp $boot_mp/$EFI_GRUB_CONF $efi_grub_cfg

    sed -i "/^\s*#/! s/%UUID%/$bios_uuid/" $efi_grub_cfg

    if grep -q "^[^#]*%ID_FILE%" $efi_grub_cfg ; then
        local rand_file=/boot/grub/config/$(random_string).id
        log_cmd touch $boot_mp$rand_file
        sed -i "/^\s*#/! s|%ID_FILE%|$rand_file|" $efi_grub_cfg
    fi

    sync

    breakpoint F "After updating grub config from old LUM"

    umount $efi_mp

    touch $boot_mp/$DID_EFI_FILE
    return 0
}

#------------------------------------------------------------------------------
# Create a random hex string $cnt * 2 chars long
#------------------------------------------------------------------------------
random_string() {
    local cnt=${1:-16}
    dd if=/dev/urandom status=none bs=1 count=$cnt | od -An -x | tr -d " "
}

#------------------------------------------------------------------------------
# Start up the tsplash screen on its on tty
# Modify our scripts so we all use the same tty
#------------------------------------------------------------------------------
tsplash_start() {
    tsplash_enabled || return

    # This does nothing now
    case $CMD_MY_TTY in
        [1-9]|1[0-2]) ;;
     #   *) DO_TSPLASH= ; TSPLASH_ERROR=true ; return ;;
    esac

    vmsg 6 "@ %s starting %s" "$(get_seconds)" "$(pq tsplash)"

    # change the tty used in these 3 scripts
    sed -r -i "s/^(tty)=.*/\1=$TSPLASH_TTY/" /bin/tell-tsplash   /bin/tsplash-on
    sed -r -i "s/tty[0-9]+/tty$TSPLASH_TTY/" /bin/clear-tsplash

    openvt -s -c $TSPLASH_TTY tsplash start "$DO_TSPLASH"
}

#------------------------------------------------------------------------------
# Convenience routine
#------------------------------------------------------------------------------
tsplash_enabled()  {
    [ -n "$DO_TSPLASH" ]
    return $?
}

#------------------------------------------------------------------------------
# Switch to the boot screen
#------------------------------------------------------------------------------
tsplash_off() {
    tsplash_enabled || return
    echo 'tsplash off' >> $MY_LOG
    TSPLASH_OFF=true
    chvt $MY_TTY
}

#------------------------------------------------------------------------------
# Clear screen, wait briefly and then chvt back here.
# Will only clear the screen once until we move back to the tsplash screen.
#------------------------------------------------------------------------------
tsplash_clear() {
    tsplash_enabled || return
    if [ -z "$TSPLASH_CLEARED" -a -z "$NO_CLEAR" ]; then
        clear
        echo 'tsplash clear' >> $MY_LOG
        sleep .2
        TSPLASH_CLEARED=true
    fi

    TSPLASH_OFF=true
    chvt $MY_TTY
}

#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
tsplash_only_clear() {
    tsplash_enabled || return
    if [ -z "$TSPLASH_CLEARED" -a -z "$NO_CLEAR" ]; then
        clear
        echo 'tsplash clear' >> $MY_LOG
        sleep .1
        TSPLASH_CLEARED=true
    fi
}
#------------------------------------------------------------------------------
# Go back to the tsplash screen and reset the TSPLASH_CLEARED flag
#------------------------------------------------------------------------------
tsplash_on() {
    tsplash_enabled    || return
    [ "$TSPLASH_OFF" ] || return
    unset TSPLASH_OFF
    echo 'tsplash on' >> $MY_LOG
    chvt $TSPLASH_TTY
    unset TSPLASH_CLEARED
}

#------------------------------------------------------------------------------
# Advance the tsplash progress
#------------------------------------------------------------------------------
tsplash_progress() { tsplash_enabled && /live/bin/tell-tsplash progress "$*" ; }

#------------------------------------------------------------------------------
# Display a message in the tsplash progress bar area AND show it here
#------------------------------------------------------------------------------
tsplash_alert() {
    vmsg 1  "$@"
    tsplash_enabled || return
    local fmt=$1 ; shift
    /live/bin/tell-tsplash alert "$(printf "$m_co$fmt$nc_co" "$@")"
}

#------------------------------------------------------------------------------
# *sigh* this is for the no-color alert in init.
#------------------------------------------------------------------------------
tsplash_alert_nc() {
    vmsg_nc 1  "$@"
    tsplash_enabled || return
    local fmt=$1 ; shift
    /live/bin/tell-tsplash alert "$(printf "$nc_co$fmt$nc_co" "$@")"
}

#------------------------------------------------------------------------------
# Note we call "alert" because we take care of the colors here
#------------------------------------------------------------------------------
tsplash_warn() {
    warn "$@"
    tsplash_enabled || return
    local fmt=$1 ; shift
    /live/bin/tell-tsplash alert "$(printf "$warn_co$fmt$nc_co" "$@")"
}

#------------------------------------------------------------------------------
# Wait for the tsplash program to finish before moving on
# We use this for progress bars
#------------------------------------------------------------------------------
tsplash_wait() {
    # Yes I could do this iwth -s but that sometimes causes problems
    chvt $TSPLASH_TTY
    openvt -w -c $TSPLASH_TTY /live/bin/tsplash "$@"
}

#------------------------------------------------------------------------------
# Copy the tsplash config to the "real" file system.  We need to do this as
# last as possible, I think.  Perhaps we can improve this.
#------------------------------------------------------------------------------
tsplash_copy_config() {
    tsplash_enabled || return
    local new_dir=$1

    local f  dir=/live/config/tsplash
    for f in progress tsplash.log; do
        log_cmd cp $dir/$f $new_dir$dir/$f
    done
}

#------------------------------------------------------------------------------
# Get the new "root" filesystem ready before we switch_root to it
#------------------------------------------------------------------------------
prepare_switch_root() {
    local new_root=$1  live_dir=$2  final_live=$3
    local new_live=$new_root${final_live:-$live_dir}
    local root_dir=""

    # FIXME!
    # new_live=$new_root/run/initramfs

    # Now tell kernel where the real modprobe lives
    echo "/sbin/modprobe" > /proc/sys/kernel/modprobe

    # Avoid PID wrap by setting a large max
    echo 4000000 > /proc/sys/kernel/pid_max 2>/dev/null

    mount_tmpfs $new_root/media  10 /media
    mount_tmpfs $new_root/run    1111 /run        mode=755,nodev
    mount_tmpfs $new_live        100 $live_dir   mode=755

    mkdir -p -m 777 $new_root/run/lock

    ##Move this to custom 8.sh files
    #rm -f $new_root/etc/resolv.conf
    #ln -s ../run/resolvconf/resolv.conf $new_root/etc/resolv.conf

    [ -z "$NO_TMP_TMP" ] && $LIVE_BIN/mount -t tmpfs -o noatime tmpfs $new_root/tmp

    ln -s . $new_live/live

    local f
    for f in README LICENSE; do
        local from=/live/$f  to=$new_live/$f
        test -e $from || continue
        test -e $to   && continue
        cp $from $to
    done

    breakpoint 0 before move

    # cp -a /bin/shutdown $new_live/

    cp /init $new_live

    mkdir -p $new_live/oldroot

    local mp new
    for mp in $live_dir/*; do
        [ $mp = $new_root ] && continue
        mountpoint -q $mp   || continue
        new=$new_live/$(basename $mp)
        mkdir -p $new
        log_cmd mount --move $mp $new

        # ignore error on read-only filesystems
        # I'm not sure why the chmod is needed on the others but it is.
        chmod 755 $new 2>/dev/null
    done

    breakpoint 0 after move

    # Remove libs, modules, and programs we won't need to save a little RAM
    rm -f $(find $root_dir/lib -type f -o -type l | egrep -v "/(x86_64-linux-gnu|live-init|ld|libc|libm|libdl|libmount|libblkid|libselinux|libpcre2|libpthread)[.-][^/]*$")

    (cd $root_dir/bin && rm -rf fbcondecor_helper ntfs-3g)
    rm -rf /$root_dir/etc/splash

    #tsplash_enabled && cp /etc/udev/rules.d/*-tsplash.rules $new_root/etc/udev/rules.d/

    # Work around a bug in fbcondecor_helper
    local fbsys=$root_dir/lib/splash/sys
    mountpoint $fbsys &>/dev/null && umount $fbsys

    local dir old new
    for dir in bin config etc lib64 lib locale custom menus share; do
        old=$root_dir/$dir
        test -e $old || old=$live_dir/$dir
        test -e $old || continue
        new=$new_live/$dir
        mkdir -p $new
        cp -a $old/* $new
    done

    system_mount $new_root

    umount /dev/pts

    # Create $live_dir/aufs mount in new_root (for historical reasons)
    mkdir -p $new_live/$AUFS_DIR
    mount --bind $new_root $new_live/$AUFS_DIR

    PATH=$new_live/bin:$PATH

    (cd $new_root && mkdir -p sys proc dev/pts)
}

#------------------------------------------------------------------------------
# Removes service symlinks from a given runlevel.  Used to get lightdm out of
# runlevel 3.
#------------------------------------------------------------------------------
remove_from_runlevel() {
    local prog=$1  level=${2:-3}  root=${3:-/live/aufs}
    test -d $root || root=
    local file=$root/etc/init.d/$prog
    msg "file: $file"
    test -e $file || return
    local links=$(ls $root/etc/rc$level.d/S*$prog)
    msg "links: $links"
    test -z "$links" && return
    sed -r -i "/^#\s+Default-Start:/ s/\<$level\>//" $file
    rm -f $links
}

#------------------------------------------------------------------------------
# Convenience routine
#------------------------------------------------------------------------------
remasterable() { [ -n "$REMASTERABLE" ];  return $?; }

#------------------------------------------------------------------------------
#  This is done elsewhere now FIXME?
#------------------------------------------------------------------------------
live_param_filter() { echo $*; }

#==============================================================================
# What was last shall be first
main_wrapper "$@"
#==============================================================================
