#!/bin/bash
SOURCE="$0"
source /usr/lib/elive-tools/functions
EL_REPORTS="1"
el_make_environment
# gettext functions
if [[ -x "/usr/bin/gettext.sh" ]] ; then
    . gettext.sh
else
    # make it compatible
    eval_gettext(){
        echo "$@"
    }
fi
TEXTDOMAIN="deliver"
export TEXTDOMAIN


# distro version
case "$( cat /etc/debian_version )" in
    12.*|"bookworm"*)
        is_bookworm=1
        ;;
    11.*|"bullseye"*)
        is_bullseye=1
        ;;
    10.*|"buster"*)
        is_buster=1
        ;;
    7.*|"wheezy"*)
        is_wheezy=1
        ;;
esac

# determine the mount version
if grep -qsE "(^7\.|wheezy)" /etc/debian_version ; then
    is_wheezy=1
    LIVE_MOUNT_MAIN_d="/lib/live/mount"
else
    LIVE_MOUNT_MAIN_d="/run/live"
fi

#set -e

error_happened(){

    NOREPORTS=1  el_error "error happened in $(basename $0): $*"
    if [[ -z "$*" ]] ; then
        zenity --error
    else
        zenity --error --text="Error: $*"
    fi
    killall zenity
    exit 1
}

refresh(){
    partprobe "$medium_dev"

    sync
    sleep 1
}


main(){
    # pre {{{
    local medium_dev TMP_PROGRESS_CONFIGURING_f

    # Usage
    if [[ -z "${1}" ]] ; then
        echo -e "Usage: $(basename $BASH_SOURCE) /dev/sdX (device where to create extra persistence partition)"
        exit 1
    fi

    medium_dev="$1"
    if [[ "$medium_dev" = "/dev/nvme"* ]] || [[ "$medium_dev" = "/dev/mmcblk"* ]] ; then
        medium_dev="${medium_dev%%p[0-9]*}"
    else
        medium_dev="${medium_dev%%[0-9]*}"
    fi

    TMP_PROGRESS_CONFIGURING_f="/tmp/.$(basename $0 )-${USER}-progress"

    if ! [[ -b "$medium_dev" ]] ; then
        el_error "$medium_dev is not a block device"
        #echo -e "# $medium_dev is not a block device" ; sleep 4
        exit 1
    fi

    # clean the possible luks opened partition (only at the start of the script, not from the refresh one)
    # correctly reload partitions before to use them
    cryptsetup luksClose "/dev/mapper/${medium_dev##*/}_crypt" 2>/dev/null || true
    cryptsetup luksClose "/dev/mapper/${medium_dev##*/}3_crypt" 2>/dev/null || true
    cryptsetup luksClose "/dev/mapper/${medium_dev##*/}" 2>/dev/null || true
    cryptsetup luksClose "/dev/mapper/${medium_dev##*/}3" 2>/dev/null || true
    cryptsetup luksClose "${medium_dev}" 2>/dev/null || true
    cryptsetup luksClose "${medium_dev}3" 2>/dev/null || true

    # and just to make sure
    #if el_check_dir_has_files "/dev/mapper/" 2>/dev/null ; then
        #dmsetup remove_all
    #fi

    refresh

    # we need to know specially the max performance so try to get this value first
    CPU_MHZ_CORE_v="$( cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq 2>/dev/null | grep "[[:digit:]]" | sort -ugr | head -1 )"
    if [[ -n "$CPU_MHZ_CORE_v" ]] ; then
        CPU_MHZ_CORE_v="${CPU_MHZ_CORE_v:0:-3}"
    fi

    if [[ -z "$CPU_MHZ_CORE_v" ]] ; then
        CPU_MHZ_CORE_v="$( cat /proc/cpuinfo | grep -i "cpu Mhz" | sed -e 's|^.*:||g' -e 's|\..*$||g' | tr ' ' '\n' | awk '{print $1}' | grep "[[:digit:]]" | sort -ugr | head -1 )"
    fi


    medium_part="$( cat /proc/mounts | grep "^/dev/.*${LIVE_MOUNT_MAIN_d}/medium" | awk '{print $1}' | grep -Fv "/dev/mapper/" | tail -1 )"
    if [[ ! -b "$medium_part" ]] ; then
        if ls $LIVE_MOUNT_MAIN_d/persistence/*/live/filesystem.*  1>/dev/null 2>&1 ; then
            medium_part="$( ls $LIVE_MOUNT_MAIN_d/persistence/*/live/filesystem.* | sed -e 's|/live/filesystem\..*$||g' | sort -u | head -1 )"
            medium_part="$( cat /proc/mounts | grep -F "${medium_part}" | awk '{print $1}' | tail -1 )"
        fi
        if [[ ! -b "$medium_part" ]] ; then
            medium_part="$( cat /proc/mounts | grep "^/dev/.*${LIVE_MOUNT_MAIN_d}/persistence/sd.3" | awk '{print $1}' | grep -Fv "/dev/mapper/" | tail -1 )"
            if [[ ! -b "$medium_part" ]] ; then
                medium_part="$( cat /proc/mounts | grep "^/dev/.*${LIVE_MOUNT_MAIN_d}/persistence/sd.2" | awk '{print $1}' | grep -Fv "/dev/mapper/" | tail -1 )"
                if [[ ! -b "$medium_part" ]] ; then
                    medium_part="$( cat /proc/mounts | grep "^/dev/.*${LIVE_MOUNT_MAIN_d}/persistence/sd.1" | awk '{print $1}' | grep -Fv "/dev/mapper/" | tail -1 )"
                    if [[ ! -b "$medium_part" ]] ; then
                        medium_part="$( cat /proc/mounts | grep "^/dev/.*${LIVE_MOUNT_MAIN_d}/persistence/sd.4" | awk '{print $1}' | grep -Fv "/dev/mapper/" | tail -1 )"
                        if [[ ! -b "$medium_part" ]] ; then
                            medium_part="$( cat /proc/mounts | grep "^/dev/.*${LIVE_MOUNT_MAIN_d}/persistence/sd.5" | awk '{print $1}' | grep -Fv "/dev/mapper/" | tail -1 )"
                            if [[ ! -b "$medium_part" ]] ; then
                                # nvme ?
                                medium_part="$( cat /proc/mounts | grep "^/dev/.*${LIVE_MOUNT_MAIN_d}/persistence/nvme" | awk '{print $1}' | grep -Fv "/dev/mapper/" | tail -1 )"
                                if [[ ! -b "$medium_part" ]] ; then
                                    medium_part="$( cat /proc/mounts | grep "^/dev/.*${LIVE_MOUNT_MAIN_d}/persistence/mmcblk" | awk '{print $1}' | grep -Fv "/dev/mapper/" | tail -1 )"
                                fi
                            fi
                        fi
                    fi
                fi
            fi
        fi
        # try to detect systems like /dev/mapper/ventoy that doesn't exist on /dev/mapper/ later
        if [[ ! -b "$medium_part" ]] ; then
            medium_part="$( cat /proc/mounts | grep "^/dev/.*${LIVE_MOUNT_MAIN_d}/medium" | awk '{print $1}' | tail -1 )"
            if [[ "$medium_part" = "/dev/mapper/"* ]] ; then
                medium_part="${medium_part#/dev/mapper/}"
                if [[ -n "$medium_part" ]] ; then
                    medium_part="$( NOREPORTS=1 EL_DEBUG=0 timeout 120 partitions-list --show-all 2>/dev/null | grep -i "$medium_part" |  awk -v FS="::" '{print $1}' | tail -1 )"
                fi
            fi
        fi
    fi

    #medium_disk="${medium_part%%[0-9]*}"

    if [[ ! -b "$medium_part" ]] ; then
        # this is like a strange buggy useless remount that happens here, replacing the previous one
        if [[ ! -b "$medium_part" ]] ; then
            medium_part="$( cat /proc/mounts | grep -F "/mount/persistence/sd.3" | awk '{print $1}' | grep "^/dev/" | grep -Fv "/dev/mapper/" | tail -1 )"
            if [[ ! -b "$medium_part" ]] ; then
                medium_part="$( cat /proc/mounts | grep -F "/mount/persistence/sd.2" | awk '{print $1}' | grep "^/dev/" | grep -Fv "/dev/mapper/" | tail -1 )"
                if [[ ! -b "$medium_part" ]] ; then
                    medium_part="$( cat /proc/mounts | grep -F "/mount/persistence/sd.1" | awk '{print $1}' | grep "^/dev/" | grep -Fv "/dev/mapper/" | tail -1 )"
                    if [[ ! -b "$medium_part" ]] ; then
                        medium_part="$( cat /proc/mounts | grep -F "/mount/persistence/sd.4" | awk '{print $1}' | grep "^/dev/" | grep -Fv "/dev/mapper/" | tail -1 )"
                        if [[ ! -b "$medium_part" ]] ; then
                            medium_part="$( cat /proc/mounts | grep -F "/mount/persistence/sd.5" | awk '{print $1}' | grep "^/dev/" | grep -Fv "/dev/mapper/" | tail -1 )"
                            if [[ ! -b "$medium_part" ]] ; then
                                # nvme ?
                                medium_part="$( cat /proc/mounts | grep -F "/mount/persistence/nvme" | awk '{print $1}' | grep "^/dev/" | grep -Fv "/dev/mapper/" | tail -1 )"
                                if [[ ! -b "$medium_part" ]] ; then
                                    medium_part="$( cat /proc/mounts | grep -F "/mount/persistence/mmcblk" | awk '{print $1}' | grep "^/dev/" | grep -Fv "/dev/mapper/" | tail -1 )"
                                fi
                            fi
                        fi
                    fi
                fi
            fi
        fi
    fi

    medium_part_fs="$( NOREPORTS=1 EL_DEBUG=0 timeout 120 partitions-list --show-only="$medium_part" | awk -v FS="::" '{print $3}' )"

    if [[ "$medium_part" = "/dev/sr"* ]] ; then
        is_cdrom=1
        is_usb=0
    fi
    if [[ "$medium_part" = "/dev/nvme"* ]] || [[ "$medium_part" = "/dev/mmcblk"* ]] ; then
        is_usb=1
        is_cdrom=0
        medium_dev="${medium_part%%p[0-9]*}"
    fi
    if [[ "$medium_part" = "/dev/sd"* ]] ; then
        is_usb=1
        is_cdrom=0
        medium_dev="${medium_part%%[0-9]*}"
    fi
    if [[ "$medium_part_fs" = "iso9660" ]] ; then
        is_image_hybrid=1
        # can be usb (hybrid)
    fi
    # ventoy cases
    if [[ "$medium_part_fs" = "exfat" ]] && [[ -b /dev/mapper/ventoy ]] ; then
        is_image_hybrid=1
        is_cdrom=0
        is_usb=1
    fi

    if [[ "$medium_part_fs" = "vfat" ]] ; then
        is_image_img=1
        is_cdrom=0
    fi


    # }}}

    # check if we have already a persistence partition {{{

    medium_partition_prev_last="$( NOREPORTS=1 EL_DEBUG=0 timeout 120 partitions-list --show-all --show-raw --show-disks | grep "^${medium_dev}" | awk -v FS="::" '{print $1}' | grep "[[:digit:]]$" | sort -uV | tail -1 )"
    medium_partition_prev_last="${medium_partition_prev_last##*[^0-9]}"

    if ((is_image_hybrid)) || ((is_usb)) ; then
        if [[ "$medium_partition_prev_last" = 3 ]] ; then
            _part="${medium_dev}3"
        fi
        if [[ "$medium_partition_prev_last" = 4 ]] ; then
            _part="${medium_dev}4"
        fi
        if [[ "$medium_partition_prev_last" = 5 ]] ; then
            _part="${medium_dev}5"
        fi
    fi

    if NOREPORTS=1 EL_DEBUG=0 timeout 120 partitions-list --show-all --show-raw --show-disks 2>/dev/null | grep -qsE "^${medium_dev}.*::(persistence)::" ; then
        _part="$( NOREPORTS=1 EL_DEBUG=0 timeout 120 partitions-list --show-all --show-raw --show-disks | grep -E "^${medium_dev}.*::(persistence)::" | awk -v FS="::" '{print $1}' | psort -- -p "persistence" | head -1 )"
    fi


    if [[ -n "$_part" ]] ; then

        local message_detected_persistence
        message_detected_persistence="$( printf "$( eval_gettext "You already have a Persistence partition." )" "" )"

        local message_recreate_persistence
        message_recreate_persistence="$( printf "$( eval_gettext "Do you want to delete and recreate partition %s? This will erase all its content and reset persistence to a fresh state." )" "$_part" )"

        if $guitool --question --text="$message_detected_persistence $message_recreate_persistence" ; then
            medium_partition_number="${_part##*[^0-9]}"

            #if ((is_wheezy)) ; then
                #parted -ms -a optimal "${medium_dev}" rm "$medium_partition_number"
            #else
                #if ! echo -e "d\n${medium_partition_number}\nw\nq" | fdisk --wipe never --wipe-partitions never "${medium_dev}" ; then
                    #error_happened "when deleting partition number '${medium_partition_number}' from disk '${medium_dev}' "
                #fi
            #fi
            is_reformat_wanted=1

        else
            error_happened "$( eval_gettext "Aborting creation of persistence since a partition already exists for it. Run this tool again if you wish to recreate persistence for your USB." )"
        fi
    fi

    # }}}

    # check if we have enough free space to use {{{
    if ((is_wheezy)) ; then
        medium_size_used_last="$( LC_ALL=C parted -s -a optimal "$medium_dev" unit MB print 2>&1 | tail -n "+5" | awk '{print $3}' | grep "^[[:digit:]]" | sort -V | tail -1 )"

        # check last position of size
        if [[ -z "$medium_size_used_last" ]] ; then
            #el_error "unable to get last size used in your USB"
            #echo -e "# Unable to know the last size used in your USB" ; sleep 4
            if ((is_image_hybrid)) ; then
                $guitool --error --text="$( eval_gettext "This hybrid image of Elive is not compatible with persistence. For persistence functionality, please download the USB version." )" || true
            else
                $guitool --error --text="$( eval_gettext "Unable to determine the last partition size used on your USB." )" || true
            fi
            error_happened
        fi

        # check amount of free space
        medium_free_space="$( LC_ALL=C parted -s "$medium_dev" unit MB print free | grep -F "Free Space" | tail -1 | awk '{print $3}' | sed -e 's|MB$||g' | sed -e 's|\..*$||g' )"
        el_debug "free space on medium is '$medium_free_space' "

        if [[ -z "$medium_free_space" ]] ; then
            $guitool --error --text="$( eval_gettext "Unable to know the amount of free space on your USB thumb drive." )"
            error_happened
        fi

        if [[ "$medium_free_space" -lt 60 ]] ; then
            el_debug "free space on medium ($medium_free_space) is less than the one needed (60)"
            $guitool --error --text="$( eval_gettext "You don't have enough free space or partitions left to use Persistence, check if you have an older persistence partition to remove, acquire a bigger USB, or repartition it to give some free space." )"
            error_happened
        fi
        # TODO: if we can calculate the free space here, we need to do it later after to have created the filesystem
        if [[ "$medium_free_space" -lt 500 ]] ; then
            $guitool --warning --text="$( eval_gettext "Your USB thumb drive has less than 500MB of free space, which may cause the system to fill up rapidly. While this is not a critical issue, we suggest using a larger drive for a better experience." )"
            is_persistence_small=1
        fi
    fi

    # }}}

    # know the number of our partition
    if ((is_reformat_wanted)) ; then
        medium_partition_number="$medium_partition_number"
    else

        # create new partition
        if ((is_interactive)) ; then
            local message_confirm
            message_confirm="$( printf "$( eval_gettext "You are going to create a partition in your device '%s'. Continue?" )" "$medium_dev" )"
            if ! $guitool --question --text="$message_confirm" ; then
                killall zenity
                exit 1
            fi
        fi

        medium_partition_number="$(( $medium_partition_prev_last + 1 ))"

        # create partition
        if ((is_wheezy)) ; then
            el_debug "Creating extra partition from $medium_size_used_last to the end"
            parted -ms -a optimal "${medium_dev}" mkpart primary reiserfs "$medium_size_used_last" 100%
        else
            if ! echo -e "n\n\n\n\n\nw\nq" | fdisk --wipe never --wipe-partitions never "${medium_dev}" ; then
                error_happened "when creating the new partition with fdisk in disk '${medium_dev}', do you have enough free space on your USB media?"
            fi
        fi
        refresh
    fi

    # check if enough speeds {{{
    # get speeds, for this machine (so, always)
    #if [[ -z "$persistence_speed_ro" ]] ; then
        $guitool --info --text="$( eval_gettext "Verifying your USB thumb drive's speed is crucial as the persistence feature works best with high writing speeds." )" &
        pid="$!"

        sync
        persistence_speed_ro="$( LC_ALL=C hdparm -t "$medium_dev" 2>&1 | grep -F "buffered disk read" | sed -e 's|^.* = ||g' )"
        # remove extra leading blank chars
        read -r persistence_speed_ro <<< "$persistence_speed_ro"
    #fi

    #if [[ -z "$persistence_speed_rw" ]] ; then
        # first we need to create an image because urandom is not enough fast for the real test
        if LC_ALL=C dd if=/dev/urandom of=/tmp/speedtest-temp.img bs=4M count=15 oflag=sync 2>/dev/null ; then
            sync
            persistence_speed_rw="$( LC_ALL=C dd if=/tmp/speedtest-temp.img of="${medium_dev}${medium_partition_number}" bs=4M oflag=sync 2>&1 | tr ' ' '\n' | tail -n "-2" | tr '\n' ' ' )"
        fi
        rm -f "/tmp/speedtest-temp.img"
        # remove extra leading blank chars
        read -r persistence_speed_rw <<< "$persistence_speed_rw"
    #fi

    kill "$pid" 2>/dev/null || kill -9 "$pid" 2>/dev/null || true

    if ((is_wheezy)) ; then
        # remove the temporal partition, or we could not create a new one!
        parted -ms -a optimal "${medium_dev}" rm "$medium_partition_number"
    fi


    # machine readable value (in KB)
    if [[ -n "$persistence_speed_ro" ]] ; then
        case "$persistence_speed_ro" in
            *GB*)
                persistence_speed_ro_kb="$( echo "${persistence_speed_ro%% *} * 1024 * 1024" | LC_ALL=C bc -l | sed 's|\..*$||g' )"
                ;;
            *MB*)
                persistence_speed_ro_kb="$( echo "${persistence_speed_ro%% *} * 1024" | LC_ALL=C bc -l | sed 's|\..*$||g' )"
                ;;
            *KB*)
                persistence_speed_ro_kb="$( echo "${persistence_speed_ro%% *} + 0 " | LC_ALL=C bc -l | sed 's|\..*$||g' )"
                ;;
            *)
                # this should be bytes :/
                persistence_speed_ro_kb="$( echo "${persistence_speed_ro%% *} / 1024" | LC_ALL=C bc -l | sed 's|\..*$||g' )"
                ;;
        esac
    fi
    if [[ -n "$persistence_speed_rw" ]] ; then
        case "$persistence_speed_rw" in
            *GB*)
                persistence_speed_rw_kb="$( echo "${persistence_speed_rw%% *} * 1024 * 1024" | LC_ALL=C bc -l | sed 's|\..*$||g' )"
                ;;
            *MB*)
                persistence_speed_rw_kb="$( echo "${persistence_speed_rw%% *} * 1024" | LC_ALL=C bc -l | sed 's|\..*$||g' )"
                ;;
            *KB*)
                persistence_speed_rw_kb="$( echo "${persistence_speed_rw%% *} + 0 " | LC_ALL=C bc -l | sed 's|\..*$||g' )"
                ;;
            *)
                # this should be bytes :/
                persistence_speed_rw_kb="$( echo "${persistence_speed_rw%% *} / 1024" | LC_ALL=C bc -l | sed 's|\..*$||g' )"
                ;;
        esac
    fi

    local message_6
    message_6="$( printf "$( eval_gettext "Your persistence media's reading speed is %s" )" "$persistence_speed_ro" )"

    local message_7
    message_7="$( printf "$( eval_gettext "And the write speed is %s" )" "$persistence_speed_rw" )"


    if [[ -n "$persistence_speed_rw_kb" ]] ; then
        persistence_speed_rw_kb="$( echo "$persistence_speed_rw_kb" | sed -e 's|\..*$||g' )"

        local message_8

        # USB's 2.0 still fast enough, so their max. limitation is probably 30mb/s
        # Sandisk Ultra Flair cz73 stats:
        # Thinkpad x201s: 27 MB/s ro, 15 MB/s rw
        # Thinkpad t460s: 98 MB/s ro, 38 MB/s rw
        if [[ "$persistence_speed_ro_kb" -lt 23000 ]] || [[ "$persistence_speed_rw_kb" -lt 9000 ]] ; then
            message_8="$( printf "$( eval_gettext "This speed is not sufficient for a smooth experience with persistence. We suggest acquiring a faster USB memory, such as SanDisk Ultra or Extreme models, which are proven to work very well with Elive." )" "" )"

            local message_9
            message_9="$( printf "$( eval_gettext "Do you want to use persistence with this device, even if it can be a painfully slow experience?" )" "" )"


            if ! $guitool --question --text="Warning: ${message_6}. ${message_7}. ${message_8} - ${message_9}" ; then
                exit
            fi
        fi
    fi



    # }}}

    if ((is_wheezy)) ; then
        # create (again) the partition, (was deleted by the previous test)
        parted -ms -a optimal "${medium_dev}" mkpart primary reiserfs "$medium_size_used_last" 100%
    fi



    if ((is_wheezy)) ; then
        if ((is_image_hybrid)) ; then
            # this doesn't works with these modes
            $guitool --info --text="$( eval_gettext "To encrypt your persistence partition, which is highly recommended, download and use the USB version of Elive. We will proceed without encryption for now." )" 1>/dev/null 2>&1 || true
        else
            if $guitool --question --text="$( eval_gettext "Do you want to encrypt your persistence partition? This will protect your personal information. You will need to unlock your data at every boot." )" ; then
                is_encryption_wanted=1
            fi
        fi
    else
        # we always want encryption, set it to default for newer versions:
        is_encryption_wanted=1
    fi

    echo 10 > "$TMP_PROGRESS_CONFIGURING_f"
    { ( while test -s "$TMP_PROGRESS_CONFIGURING_f" ; do echo 10 ; cat "$TMP_PROGRESS_CONFIGURING_f" 2>/dev/null || true ; sleep 1 ; done | $guitool --progress --text="$( eval_gettext "Creating magic..." )" --pulsate --auto-close ) & disown ; } 2>/dev/null


    if ((is_encryption_wanted)) ; then

        # make sure that the window popups after our progress-one:
        sync ; sleep 2

        # medium_partition_password="$( $guitool --entry --hide-text --text="$( eval_gettext "Insert a password to protect your personal data. You will be asked on every boot. Press cancel if you don't want to use it." )" )"
        medium_partition_password="$( $guitool --entry --hide-text --text="$( eval_gettext "Set a password to protect your personal data. You will be prompted for it on each boot. A password is necessary to use Persistence." )" )"
        # request valid chars {{{
        if [[ -z "$medium_partition_password" ]] ; then
            $guitool --error --text="$( eval_gettext "Enter a valid password to protect your data (mandatory)" )"" (\")."
            medium_partition_password="$( $guitool --entry --hide-text --text="$( eval_gettext "Insert a password." )" )"
        fi

        if printf "%s" "$medium_partition_password" | grep -qs '\\' ; then
            $guitool --error --text="$( eval_gettext "Sorry, you cannot use the backslash character, use a different password" )"" (\\)."
            medium_partition_password="$( $guitool --entry --hide-text --text="$( eval_gettext "Insert a password." )" )"
        fi
        if printf "%s" "$medium_partition_password" | grep -qs '\\' ; then
            unset medium_partition_password
        fi

        if printf "%s" "$medium_partition_password" | grep -qs "'" ; then
            $guitool --error --text="$( eval_gettext "Sorry, you cannot use the single quote character, use a different password" )"" (')."
            medium_partition_password="$( $guitool --entry --hide-text --text="$( eval_gettext "Insert a password." )" )"
        fi
        if printf "%s" "$medium_partition_password" | grep -qs "'" ; then
            unset medium_partition_password
        fi

        if printf "%s" "$medium_partition_password" | grep -qs '"' ; then
            $guitool --error --text="$( eval_gettext "Sorry, you cannot use the double quote character, use a different password" )"" (\")."
            medium_partition_password="$( $guitool --entry --hide-text --text="$( eval_gettext "Insert a password." )" )"
        fi
        if printf "%s" "$medium_partition_password" | grep -qs '"' ; then
            unset medium_partition_password
        fi

        # }}}

        # twofish is not supported, only AES
        if [[ -n "$medium_partition_password" ]] ; then

            # encrypt partition
            if ! dd if=/dev/zero of="${medium_dev}${medium_partition_number}" bs=4M count=14 ; then
                if LC_ALL=C dd if=/dev/zero of="${medium_dev}${medium_partition_number}" bs=4M count=14 2>&1 | grep -i "No space left"  ; then
                    $guitool --error --text="$( eval_gettext "The Persistence partition is too small. You need more free space on your USB. Refer to the Elive website for recommended tools to avoid issues. Aborting..." )"
                else
                    $guitool --error --text="$( eval_gettext "An error occurred while creating the Persistence partition. Ensure you have sufficient free space on your USB or resize other partitions. Refer to Elive's website for recommended tools to avoid issues. If using other tools, try re-creating your USB with more free space. Aborting..." )"
                fi

                killall zenity
                exit 1
            fi

            printf "%s" "$medium_partition_password" | cryptsetup --label persistence -s 256 --pbkdf pbkdf2 --use-urandom --batch-mode luksFormat "${medium_dev}${medium_partition_number}"

            hd_part_luks_name="${medium_dev#/dev/}${medium_partition_number}_crypt"
            printf "%s" "$medium_partition_password" | cryptsetup luksOpen "$medium_dev${medium_partition_number}" "$hd_part_luks_name"

            if ! dd if=/dev/zero of=/dev/mapper/$hd_part_luks_name bs=4M count=20 ; then
                $guitool --error --text="$( eval_gettext "Failed to create a Persistence partition. You may need to reboot or ensure your USB thumb drive has at least 200MB free." )"
                $guitool --warning --text="$( eval_gettext "IMPORTANT: It appears the kernel cannot read the new partition structure on your USB. Reboot your computer and rerun this tool to finish setting up your persistence partition. If this continues to fail, try booting with a different kernel." )"
                killall zenity

                if $guitool --question --text="$( eval_gettext "Do you want to reboot now and try to create your persistence partition again?" )" ; then
                    cryptsetup luksClose "$hd_part_luks_name"
                    sync
                    sleep 2
                    reboot
                else
                    exit
                fi
            fi

            # know the partition that we are going to use
            medium_partition="/dev/mapper/$hd_part_luks_name"

            # also change the password of root:
            printf "%s:%s\n" "root" "${medium_partition_password}" | chpasswd -m

        else
            # wrong password, fallback
            # know the partition that we are going to use
            medium_partition="${medium_dev}${medium_partition_number}"
        fi
    else

        # know the partition that we are going to use
        medium_partition="${medium_dev}${medium_partition_number}"
    fi

    refresh

    if ! [[ -b "$medium_partition" ]] ; then
        if ((is_reformat_wanted)) ; then
            $guitool --error --text="$( eval_gettext "The previous Persistence partition has been deleted. You must boot again now in Persistence mode to create a new one." )"
            reboot
        else
            $guitool --error --text="$( eval_gettext "The newly created partition does not exist. Reboot the computer and try again in Live mode. Aborting." )"
            error_happened
        fi
    fi

    # Format
    #echo -e "# Formating partition $medium_partition_number in JFS for optimal size"
    mounts-manager --umount "${medium_partition}" 1>/dev/null 2>&1 || true
    #if ! mounts-manager --umount "${medium_partition}" ; then
        #$guitool --error --text="Unable to umount $medium_partition ?"
        #error_happened
    #fi

    # NOTES:
    # JFS is not a good option: sometimes it fails to mount (fsck stuff?), yes, verified twice, is problematic
    # reiserfs (3) is not too:  mounts very slow at boot, if used on a USB
    # btrfs:  should be a good option, but is not tested (still olds in wheezy)
    # ext4:  good option: it is widely used and mounts very fast

    # format partition with the best FS for this purpose
    if ! $guitool --question --text="$( eval_gettext "Do you want to format your Persistence using Journaling features? This is the default and safer option, but you can disable it to make it slightly faster." )" ; then
        mkfs_ext4_opts="-O '^has_journal,^huge_file,^uninit_bg,^ext_attr,^64bit'"
    fi
    # if ! mkfs.ext4 -q -F -L "persistence" "${medium_partition}" ; then
    if ! mkfs.ext4 -q $mkfs_ext4_opts -F -L "persistence" "${medium_partition}" ; then
        $guitool --error --text="$( eval_gettext "Failed formatting the persistence partition" )"
        exit 1
    fi

    refresh


    # Mount
    mounts-manager --mount "${medium_partition}"

    medium_mount="$( mounts-manager --get-mountpoint "${medium_partition}" 2>/dev/null )"
    if [[ -z "$medium_mount" ]] ; then
        sync
        sleep 1
        mounts-manager --mount "${medium_partition}"
        medium_mount="$( mounts-manager --get-mountpoint "${medium_partition}" 2>/dev/null )"
    fi

    if [[ -z "$medium_mount" ]] ; then
        $guitool --error --text="$( eval_gettext "Unable to determine the mount point for your Persistence device. Please report this bug to Elive so we can address it." )"
        error_happened
    fi

    # get new free space
    medium_free_space="$( df -m "${medium_partition}" 2>/dev/null | grep "^${medium_partition}" | awk '{print $4}' | tail -1 )"

    # make overlay readable
    if grep -qsE "(^7\.|wheezy)" /etc/debian_version ; then
        LIVE_MOUNT_MAIN_d="/lib/live/mount"
    else
        LIVE_MOUNT_MAIN_d="/run/live"
    fi
    if ! [[ -d "$LIVE_MOUNT_MAIN_d" ]] ; then
        if grep -qs "live-media-path=" /proc/cmdline ; then
            LIVE_MOUNT_MAIN_d="$( cat /proc/cmdline | tr ' ' '\n' | grep "^live-media-path=" | sed -e 's|live-media-path=||g' | tail -1 )"
            if ! [[ -d "$LIVE_MOUNT_MAIN_d" ]] ; then
                unset LIVE_MOUNT_MAIN_d
            fi
        fi
    fi
    if [[ -d "$LIVE_MOUNT_MAIN_d/overlay/rw" ]] ; then
        LIVE_MOUNT_OVERLAY_d="$LIVE_MOUNT_MAIN_d/overlay/rw"
    else
        LIVE_MOUNT_OVERLAY_d="$LIVE_MOUNT_MAIN_d/overlay"
    fi

    if ! el_check_dir_has_files "${LIVE_MOUNT_OVERLAY_d}"  2>/dev/null ; then
        umount "${LIVE_MOUNT_OVERLAY_d}"  2>/dev/null
        if ! el_check_dir_has_files "${LIVE_MOUNT_OVERLAY_d}"  2>/dev/null ; then
            umount "${LIVE_MOUNT_OVERLAY_d}"  2>/dev/null
        fi
    fi

    # get the ID of the machine
    #machine_id="$( el_get_machine_id )"

    # save system configuration
    #if [[ "/var/lib/alsa/asound.state" ]] ; then
        #cp -a --parents "/var/lib/alsa/asound.state" "${medium_mount}"
        #mv "${medium_mount}/var/lib/alsa/asound.state" "${medium_mount}/var/lib/alsa/asound.state${machine_id}"
    #fi

    ## save user's configurations
    # update: we should not want to copy here since everything else (home files) are not included)
    #for userdir in /home/* /root
    #do
        #[[ ! -d "${userdir}" ]] && continue
        #[[ "${userdir}" = "/home/*" ]] && continue

        ## XXX: do not use a match that can be inside another match! (or just use the parent for all), ex.: .config/ vs .config/elive/
        ## forced ones (originals must be deleted)
        #for config in \
            #.e \
            #.config/elive/elive-tools/%%usr%%bin%%elive-multiscreens_conf.sh \
            #.config/elive/elive-tools/%%usr%%bin%%e_wrapper_conf.sh \
            #.asoundrc \
            #.gconf/apps/gnome-volume-control \
            #$NULL
        #do

            #if [[ -n "$machine_id" ]] ; then
                ## we really need to only save confs for id's here, not deleting needs here
                #if [[ -e "${userdir}/${config}" ]] ; then
                    #rm -rf "${medium_mount}${userdir}/${config}${machine_id}" 2>/dev/null || true
                    #cp -a --parents "${userdir}/${config}" "${medium_mount}"
                    #mv "${medium_mount}${userdir}/${config}" "${medium_mount}${userdir}/${config}${machine_id}"
                #fi
            #fi
        #done
    #done


    # add persistence configuration
    if [[ -n "$medium_free_space" ]] && [[ "$medium_free_space" -lt 1400 ]] ; then
        el_debug "free space $medium_free_space"
        $guitool --warning --text="$( eval_gettext "Your USB thumb drive has limited free space, which can cause issues and restrict your options. We recommend upgrading to a SanDisk Ultra or Extreme model, which are affordable and fast enough for use with Persistence." )"
    fi

    # include all, /home is unsupported and in any case persistence is useless on small devices
    echo -e "/ union" >> "${medium_mount}/persistence.conf"

    # add elive references that are also needed for the first boot (saving confs at its shutdown):
    if ((is_wheezy)) || grep -Fqs "union=aufs" /proc/cmdline ; then
        mkdir -p "${medium_mount}/etc/default"
        rm -f "${medium_mount}/etc/default/persistence-elive.sh"
        echo "counter_times_persistence_booted=\"0\"" >> "${medium_mount}/etc/default/persistence-elive.sh"
    else
        mkdir -p "${medium_mount}/rw/etc/default"
        rm -f "${medium_mount}/rw/etc/default/persistence-elive.sh"
        echo "counter_times_persistence_booted=\"0\"" >> "${medium_mount}/rw/etc/default/persistence-elive.sh"
    fi

    if ((is_bookworm)) ; then
        # disable smartmontools daemon because it stucks the boot in persistence
        mkdir -p "${medium_mount}/rw/etc/"rc{2,3,4,5}.d
        mkdir -p "${medium_mount}/rw/etc/systemd/system/multi-user.target.wants"
        mkdir -p "${medium_mount}/rw/var/lib"
        ln -fs /dev/null "${medium_mount}/rw/etc/systemd/system/smartmontools.service"
        for file in \
            "${medium_mount}/rw/etc/systemd/system/multi-user.target.wants/smartmontools.service" \
            "${medium_mount}/rw/etc/rc2.d/S04smartmontools" \
            "${medium_mount}/rw/etc/rc3.d/S04smartmontools" \
            "${medium_mount}/rw/etc/rc4.d/S04smartmontools" \
            "${medium_mount}/rw/etc/rc5.d/S04smartmontools" \
            $NULL
        do
            rm -f "$file"
            mkdir -p "$( dirname "$file" )"
            mknod "$file" c 0 0
            chmod a-rwx "$file"
        done
    fi

    # copy network configurations
    mkdir -p "${medium_mount}/rw/etc/NetworkManager/system-connections"
    rsync -a --delete /etc/NetworkManager/system-connections/ "${medium_mount}/rw/etc/NetworkManager/system-connections/"

    # enable ssh passwords
    local message_ssh_passwords
    message_ssh_passwords="$( printf "$( eval_gettext "Would you like to enable SSH login with passwords? This allows you to easily log into your machine as:" )" "" )"

    if $guitool --question --text="${message_ssh_passwords} ssh $(hostname).local" ; then
        sed -i -e 's|\(#\)*\(PermitRootLogin\).*$|\2 yes|' /etc/ssh/sshd_config
        sed -i -e 's|\(#\)*\(PasswordAuthentication\).*$|\2 yes|' /etc/ssh/sshd_config

        #if [[ -x "$( which ssh-keygen )" ]] ; then
            # rm -f /etc/ssh/ssh_host_rsa_key* || true
            # ssh-keygen -q -f /etc/ssh/ssh_host_rsa_key -N "" -t rsa
            ## start the daemon
            #systemctl unmask ssh.service 1>/dev/null 2>&1 || true
            #systemctl enable ssh.service 1>/dev/null 2>&1 || true
            #systemctl start ssh.service 1>/dev/null 2>&1 || true
        #fi

        case "$( cat /etc/debian_version )" in
            7.*|"wheezy/"*)
                _PROTOCOLS="dsa rsa ecdsa"
                ;;
            10.*|"buster/"|11.*|"bullseye"*|12.*|"bookworm"*)
                _PROTOCOLS="dsa rsa ecdsa ed25519"
                ;;
            *)
                _PROTOCOLS="dsa rsa ecdsa ed25519"
                # el_warning "unknown debian version in $0"
                ;;
        esac

        # regenerate ssh seeds, always
        for _PROTOCOL in $_PROTOCOLS
        do
            # if [ ! -e /etc/ssh/ssh_host_${_PROTOCOL}_key ] &&
            #     grep -Fqs "ssh_host_${_PROTOCOL}_key" /etc/ssh/sshd_config
            # then
                rm -f /etc/ssh/ssh_host_${_PROTOCOL}_key
                yes | sudo -H ssh-keygen -q -f /etc/ssh/ssh_host_${_PROTOCOL}_key -N "" -t ${_PROTOCOL}
            # fi
        done

        rsync -a --delete /etc/ssh/ "${medium_mount}/rw/etc/ssh/"
    fi

    # copy needed modified files
    cp -a /etc/{hosts,hostname,passwd,shadow} "${medium_mount}/rw/etc/"



    # make a backup copy for the full prepared root, useful for restoring
    cp -a "${medium_mount}/rw" "${medium_mount}/rw-backup"


    sync


    #echo -e "/bin union" >> "${medium_mount}/persistence.conf"
    #echo -e "/etc union" >> "${medium_mount}/persistence.conf"
    #echo -e "/home union" >> "${medium_mount}/persistence.conf"
    #echo -e "/lib union" >> "${medium_mount}/persistence.conf"
    #echo -e "/opt union" >> "${medium_mount}/persistence.conf"
    #echo -e "/root union" >> "${medium_mount}/persistence.conf"
    #echo -e "/sbin union" >> "${medium_mount}/persistence.conf"
    #echo -e "/srv union" >> "${medium_mount}/persistence.conf"
    #echo -e "/usr union" >> "${medium_mount}/persistence.conf"
    #if ! ((is_persistence_small)) ; then
        #echo -e "/var union" >> "${medium_mount}/persistence.conf"
    #fi

    # finished, flush
    sync
    mounts-manager --umount "${medium_partition}" 1>/dev/null 2>&1

    if ((is_encryption_wanted)) ; then
        cryptsetup luksClose "$hd_part_luks_name"
    fi

    # improve / edit the bootable entries
    if ! ((is_cdrom)) && ! ((is_image_hybrid)) ; then
        if ((is_usb)) ; then

            # this is not correct but is fixed later with a shift - 1
            usb_boot_partition="$( LC_ALL=C mount | grep -F "$LIVE_MOUNT_MAIN_d/medium" | awk '{print $1}' )"
            if [[ -z "$usb_boot_partition" ]] ; then
                # this is like a strange buggy useless remount that happens here, replacing the previous one
                if ls $LIVE_MOUNT_MAIN_d/persistence/*/live/filesystem.*  1>/dev/null 2>&1 ; then
                    usb_boot_partition="$( ls $LIVE_MOUNT_MAIN_d/persistence/*/live/filesystem.* | sed -e 's|/live/filesystem\..*$||g' | sort -u | head -1 )"
                    usb_boot_partition="$( cat /proc/mounts | grep "^/dev/.*${usb_boot_partition}" | awk '{print $1}' | tail -1 )"
                fi
                if [[ -z "$usb_boot_partition" ]] ; then
                    usb_boot_partition="$( cat /proc/mounts | grep "^/dev/.*/mount/persistence/sd.2" | awk '{print $1}' | tail -1 )"
                    if [[ -z "$usb_boot_partition" ]] ; then
                        usb_boot_partition="$( cat /proc/mounts | grep "^/dev/.*/mount/persistence/sd.1" | awk '{print $1}' | tail -1 )"
                    fi
                fi
            fi
            # partition 2 doesn't include syslinux bootfiles, only the first one
            if [[ "${usb_boot_partition}" = *"2" ]] ; then
                usb_boot_partition="${usb_boot_partition%2}1"
            fi

            # mount bootable partition
            mounts-manager --mount "$usb_boot_partition"
            usb_boot_mountpoint="$( mounts-manager --get-mountpoint "$usb_boot_partition" )"

            # make sure that is RW
            if [[ -d "$usb_boot_mountpoint" ]] ; then
                # set the default menu entry {{{
                mount -o remount -o rw "$usb_boot_mountpoint"

                while read -ru 3 line
                do
                    # rename the first entry to faster (than persistence)
                    if ! ((is_menu_fast_added)) && ! ((is_using_kernel_reached)) ; then
                        if [[ "${line}" = *"Live and Install"* ]] ; then
                            echo "$line" | sed -e 's|Install --|Install (Faster) --|g'
                            is_menu_fast_added=1

                            # we want to continue here to not get a duplicated line, we have nothing more to do now
                            continue
                        fi
                        # this message has been renamed to:
                        if [[ "${line}" = *"Live with Install Option"* ]] ; then
                            echo "$line" | sed -e 's|Option --|Option (Faster Live) --|g'
                            is_menu_fast_added=1

                            # we want to continue here to not get a duplicated line, we have nothing more to do now
                            continue
                        fi
                    fi

                    # disable default
                    if [[ "${line}" = *"menu default"* ]] ; then
                        #continue
                        true
                    fi

                    # set our new "default" for the persistence entry
                    if [[ "${line}" = "label"*"persistence"* ]] && ! ((is_using_kernel_reached)) ; then
                        echo "$line"
                        echo "    menu default"
                        is_menu_default_added=1
                        # do not continue here, we need to mark is_using_kernel_reached
                        #continue
                    else
                        # ident / beautify lines
                        if [[ "${line}" = "label"* ]] ; then
                            echo "$line"
                        else
                            echo "    $line"
                        fi
                        #continue
                    fi

                    # this is our desired / using kernel, so after this we have finished to set our default menu value
                    if [[ "${line}" = *"initrd"* ]] ; then
                        if echo "${line##*initrd}" | grep -qs "$( cat /proc/cmdline | sed -e 's|^.*initrd=||g' -e 's|.*$||g' )" ; then
                            if ((is_menu_default_added)) ; then
                                is_using_kernel_reached=1
                            fi
                        fi
                    fi
                done 3<<< "$( cat "$usb_boot_mountpoint/syslinux/live.cfg")" > "${usb_boot_mountpoint}"/syslinux/live.cfg.tmp

                mv "${usb_boot_mountpoint}"/syslinux/live.cfg.tmp "${usb_boot_mountpoint}"/syslinux/live.cfg
                # }}}
                # not needed anymore {{{
                # remove any "menu default" entry
                #sed -i "s|menu default|#menu default|g" "${usb_boot_mountpoint}"/syslinux/live.cfg

                ## create the new menu with persistence
                #cat "${usb_boot_mountpoint}"/syslinux/live.cfg.tmp "${usb_boot_mountpoint}"/syslinux/live.cfg > "${usb_boot_mountpoint}"/syslinux/live.cfg.new
                #mv "${usb_boot_mountpoint}"/syslinux/live.cfg.new "${usb_boot_mountpoint}"/syslinux/live.cfg

                ## cleanup
                #rm -f "${usb_boot_mountpoint}"/syslinux/live.cfg.new "${usb_boot_mountpoint}"/syslinux/live.cfg.tmp

            # }}}
            fi

            # get the desired boot arguments to include too:
            if ((is_wheezy)) ; then
                # only wheezy requires change the entries
                cmdargs="$( echo "$( cat /proc/cmdline | tr ' ' '\n' | grep -E "(blacklist=|^no|vga=|modeset=|intel)" | grep -Fv "blacklist=nouveau" | tr '\n' ' '  )" )"
                # remove extra leading blank chars
                read -r cmdargs <<< "$cmdargs"

                # modify 'isolinux' or 'syslinux' boot entries
                if ((is_encryption_wanted)) ; then
                    # add the entry needed for luks:
                    if ! grep -Fqs "persistence-encryption" "${usb_boot_mountpoint}"/*linux/live.cfg ; then

                        # versions up to 3.0 (or at least 2017+, but we only use 3.0 in wheezy so...), doesn't deal correctly with encryption
                        # UPDATE: there's a bug in wheezy + new live-boot + old-plymouth: so just disable plymouth if we need to insert a password:
                            # note: if you want to re-enable plymouth for this you need to update plymouth (newer than wheezy) AND remove the temporal patch in live-boot that forces-disable plytmouth
                        #if ((is_live_boot_newer)) ; then
                            #sed -i "/^\s*append\s*/s|persistence.*$|persistence persistence-encryption=luks persistence-media=removable-usb $cmdargs|g" "${usb_boot_mountpoint}"/*linux/live.cfg
                        #else
                            sed -i "/^\s*append\s*/s|splash persistence.*$|persistence persistence-encryption=luks persistence-media=removable-usb $cmdargs|g" "${usb_boot_mountpoint}"/*linux/live.cfg
                            sed -i "s|splash persistence.*$|persistence persistence-encryption=luks persistence-media=removable-usb $cmdargs|g" "${usb_boot_mountpoint}"/boot/grub/grub.cfg
                        #fi

                        # in case that we don't have the splash entry:
                        if ! grep -Fqs "persistence-encryption" "${usb_boot_mountpoint}"/*linux/live.cfg ; then
                            sed -i "/^\s*append\s*/s|persistence.*$|persistence persistence-encryption=luks persistence-media=removable-usb $cmdargs|g" "${usb_boot_mountpoint}"/*linux/live.cfg
                            sed -i "s|persistence.*$|persistence persistence-encryption=luks persistence-media=removable-usb $cmdargs|g" "${usb_boot_mountpoint}"/boot/grub/grub.cfg
                        fi
                    fi
                else
                    # not encrypted options editing:
                    sed -i "/^\s*append\s*/s|persistence.*$|persistence persistence-media=removable-usb $cmdargs|g" "${usb_boot_mountpoint}"/*linux/live.cfg
                    sed -i "s|persistence.*$|persistence persistence-media=removable-usb $cmdargs|g" "${usb_boot_mountpoint}"/boot/grub/grub.cfg
                fi

                # remove trailing space
                sed -i "/^\s*append\s*/s| $||g" "${usb_boot_mountpoint}"/*linux/live.cfg
            fi

            # umount
            mounts-manager --umount "$usb_boot_partition"
        fi
    fi

    #partitions-list --show-only="$medium_dev"

    rm -f "$TMP_PROGRESS_CONFIGURING_f"

    #$guitool --warning --text="$( eval_gettext "Warning: Persistence is an awesome feature, but it can be REALLY SLOW if you don't use a reliable trademark fast usb stick. If you have that slow experience, we recommend to use a Sandisk Ultra or Extreme model, which we have verified that is not slow at all." )"
    if [[ "$( NOREPORTS=1 EL_DEBUG=0 timeout 120 partitions-list --show-all --show-disks --show-raw | grep -F "crypto_LUKS" | wc -l )" -ge 2 ]] ; then
        $guitool --warning --text="$( eval_gettext "You have multiple encrypted partitions on your computer. When you boot in persistence mode, it will ask you to unlock all of them. However, you only need to unlock your persistence partition, and you can skip the others." ) Persistence partition is: ${medium_dev}"
    fi

    # Done
    $guitool --info --text="$( eval_gettext "Congratulations! Your USB is now ready with Persistence. Reboot with the Persistence option to start saving your sessions after the next boot." )" 1>/dev/null 2>&1 || true
    if $guitool --question --text="$( eval_gettext "Do you want to reboot now and start using Persistence mode to save your sessions?" )" ; then
        sync
        sleep 1
        reboot
    fi

    #$guitool --info --text="$( eval_gettext "Note: Persistence is an awesome feature to have your Elive portable but is slower than having Elive installed in your computer, consider installing Elive too." )" 1>/dev/null 2>&1 || true
}

#
#  MAIN
#
main "$@"

# vim: set foldmethod=marker :
