#!/bin/bash


# Zerocat Parabola Setup --- Get the Parabola Operating System installed.
#
# Copyright (C) 2021, 2022  Kai Mertens <kmx@posteo.net>
#
# This file is part of Zerocat Parabola Setup.
#
# Zerocat Parabola Setup is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# Zerocat Parabola Setup is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with Zerocat Parabola Setup.  If not, see <http://www.gnu.org/licenses/>.


# Usage
# =====
#
# This script will help you to install the Parabola GNU/Linux-libre
# System on a Corebooted Zerocat Machine with GRUB2 as a Payload:
#
# 1.  get the ISO-image
#     Website:   <https://wiki.parabola.nu/Get_Parabola#Parabola_OpenRC_LXDE_ISO>  
#     ISO file:  `parabola-dual-openrc-lxde-2020.08.03-netinstall.iso`  
# 2.  start the live session
# 3.  copy this script into the live account and grant permisson for execution
# 4.  run this script
# 5.  reboot
#
# This script is a reviewed and (hopefully) improved version of the
# original Parabola Installation CLI, checked out at:
#
# <git://git.parabola.nu/packages/parabolaiso.git>
#
#     tag name v46.1 (f29d8dafa7e2a3f2010909ffd96bb899f25ccacb)
#     tag date 2020-08-03 13:12:27 -0400
#     tagged by David P <megver83@parabola.nu>
#     commit 231f35c3c4ae7a1cf073e67f6ae091d1f1053a7c
#
# Within the parabolaiso repository, see AUTHORS.rst and LICENSE for
# proper authorship and license of the original sources, e.g.:
#
# <parabolaiso/configs/lxde-openrc/airootfs/root/.scriptsInstallation/language/en/install.sh>  
# <parabolaiso/configs/lxde-openrc/airootfs/root/.scriptsInstallation/language/en/systemConfig.sh>  
# <parabolaiso/configs/lxde-openrc/airootfs/root/.scriptsInstallation/language/en/userAccount.sh>  
# <parabolaiso/configs/lxde-openrc/airootfs/root/.scriptsInstallation/x11.sh>  


welcome() {

  $DIALOG ${FLAGS_DIALOG[@]} \
    --msgbox \
      "\
                                                                            \n\
# Welcome                                                                   \n\
                                                                            \n\
This is Zerocat’s install script for Parabola GNU/Linux-libre. \
It should be run on a fresh boot of the Parabola Live System \
instead of the original install scripts. Please activate an \
internet connection, first.                                                 \n\
                                                                            \n\
# WWW Resources                                                             \n\
                                                                            \n\
* Website:  https://wiki.parabola.nu/Get_Parabola#Parabola_OpenRC_LXDE_ISO  \n\
* ISO:      parabola-dual-openrc-lxde-2020.08.03-netinstall.iso             \n\
                                                                            \n\
Good Luck! – www.zerocat.org                                                \n\
" \
      ${WIDGET_DIM};
}

fillscreen() {
  # Fill stdout with empty lines such that dialog and script output
  # won't overlap.

  echo "Fill screen ..."
  echo -e \
    "\n\n\n\n\n\n\n\n\n\n" \
    "\n\n\n\n\n\n\n\n\n\n" \
    "\n\n\n\n\n\n\n\n\n\n" \
    "\n\n\n\n\n\n\n\n\n\n" \
    "\n\n\n\n\n\n\n\n\n\n";
  echo "... done."
}

checkperm() {
  echo "Check priviledges ..."
  if [ "$EUID" -ne 0 ]; then
    echo "This script requires root priviledges."
    exit 1
  fi
  echo "... done."
}

notool() {
  # $1: tool name
  # let’s use builtin echo command here:
  echo "Tool $1 is missing."
  exit 1
}

hitenter() {

  # positional parameter

  # locals
  local key=''

  read \
    -p'Hit any key to continue, <ESC> to abort: ' \
    -N1 \
    -r \
    -s \
      key
  [ "$key" == $'\e' ] && {
    echo
    return 1
  }
  echo
  echo
  return 0
}

sync_keyrings() {

  # positional parameter

  # locals
  local -i i=0
  local -a keys=(
    "parabola"
    "archlinux"
  )
  [ $(uname -m) = i686 ] && keys+=("archlinux32")

  pacman \
    -Syy ${keys[@]/%/-keyring} \
    --config "$config_pacman_alternate" \
    --noconfirm && \
  while [ $i -lt ${#config_pacman_keyserver[@]} ]; do
    pacman-key \
      --config "$config_pacman_alternate" \
      --keyserver "${config_pacman_keyserver[$i]}" \
      --init && \
    pacman-key \
      --config "$config_pacman_alternate" \
      --keyserver "${config_pacman_keyserver[$i]}" \
      --populate ${keys[@]} && \
    pacman-key \
      --config "$config_pacman_alternate" \
      --keyserver "${config_pacman_keyserver[$i]}" \
      --refresh-keys && \
    break 1;
    i+=1;
  done;

  return $?
}

set_DISK_SYSTEM() {

  # positional parameter

  # local vars
  local i
  local -i n=1
  local -a list_of_disks=()
  local -a menulist_disk=()
  local feedback

  # collect available disks
  list_of_disks=( \
    $( \
      udevadm settle && \
      lsblk -n --nodeps -oPATH,TYPE | \
      egrep disk | \
      cut -f1 -d' ' - \
    ) \
  )

  # select a disk
  for i in "${list_of_disks[@]}"; do
    menulist_disk+=("${n}" "${i}")
    n+=1
  done
  feedback=$( \
    $DIALOG ${FLAGS_DIALOG[@]} \
      --cancel-label "Abort" \
      --menu "Select Disk" ${MENUWIDGET_DIM} "${menulist_disk[@]}" \
  )
  case $? in
    0)
      DISK_SYSTEM=${menulist_disk[$((feedback*2-1))]}
      FLAG_DISK='on'
      $DIALOG ${FLAGS_DIALOG[@]} \
        --msgbox "Selected Disk is: ${DISK_SYSTEM}" ${WIDGET_DIM}
      ;;
    *)
      echo; echo;
      abort
      ;;
  esac
}

unset_DISK_SYSTEM() {

  # positional parameter

  # locals

  DISK_SYSTEM=''
  FLAG_DISK=''
}

open_encryption() {

  # positional parameter

  # locals
  local -r -a crypto_LUKS=( \
    $( \
      lsblk -n -oPATH,FSTYPE | \
      egrep ${DISK_SYSTEM} | \
      egrep crypto_LUKS | \
      cut -f1 -d' ' - \
    ) \
  )
  local n

  for n in "${crypto_LUKS[@]}"; do
    cryptsetup luksOpen "${n}" "${n##*/}${CRYPT_SUFFIX}"
  done
}

assign_mountpoints() {

  # positional parameter

  # locals
  local i
  local -i n
  local -a list_of_vol
  local -a menulist_vol
  local feedback
  local partition
  local mountpoint
  local device_cryptSWAP

  # dismount
  dismount_mountpoints

  while [ true ]; do
    # update list of volumes
    list_of_vol=( \
      $(echo \
"$( \
  udevadm settle && \
  lsblk -n -oPATH,TYPE,PARTTYPENAME,FSTYPE,MOUNTPOINT,SIZE | \
  egrep "${DISK_SYSTEM##*/}" | \
  egrep -v Extended | \
  egrep -v crypto_LUKS | \
  egrep -e 'part|crypt' | \
  $SED -r -e 's/ /·/g;' - \
)" ) \
    )

    # set menu list, add [cryptSWAP] marker
    n=1
    menulist_vol=()
    device_cryptSWAP=''
    get_device '[cryptSWAP]' mountpoints_assigned partitions_processed device_cryptSWAP
    for i in "${list_of_vol[@]}"; do
      [ -n "$(echo $i | grep ${device_cryptSWAP})" ] && \
        i="${i}·-->·[cryptSWAP]"
      menulist_vol+=("${n}" "${i//·/ }")
      n+=1
    done

    feedback=$( \
      $DIALOG ${FLAGS_DIALOG[@]} \
        --ok-label "Select" \
        --extra-button --extra-label "Done" \
        --cancel-label "Abort" \
        --menu "Select a Partition of Disk \`$DISK_SYSTEM' and assign a mountpoint ...\nFirst select one intended for mountpoint “/mnt/”, then optionally assign subordinary mountpoints to other partitions.\nNote swap formatted partitions can be used for [SWAP], whereas non-formatted Linux partitions shall be used for [cryptSWAP].\nPlease select your Swap carefully, the script does not yet provide a type check." ${MENUWIDGET_DIM} "${menulist_vol[@]}" \
    )
    case $? in
      0)
        partition="${menulist_vol[$((feedback*2-1))]%% *}"
        for i in ${partitions_processed[@]}; do
          [ "$i" == "$partition" ] && {
            $DIALOG ${FLAGS_DIALOG[@]} \
              --msgbox "Partition \`$i' is already used." ${WIDGET_DIM}
            continue 2
          }
        done
        feedback=$( \
          $DIALOG ${FLAGS_DIALOG[@]} \
            --menu "Assign a Mountpoint to Partition \`$partition'" ${MENUWIDGET_DIM} "${menulist_mountpoint[@]}" \
        )
        case $? in
          0)    # OK button
            mountpoint="${menulist_mountpoint[$((feedback*2-1))]}"
            for i in ${mountpoints_assigned[@]}; do
              [ "$i" == "$mountpoint" ] && {
                $DIALOG ${FLAGS_DIALOG[@]} \
                  --msgbox "Mountpoint \`$i' is already assigned." ${WIDGET_DIM}
                continue 2
              }
            done
            if [ "$mountpoint" == '/mnt/' -o -n "$FLAG_ROOT" ]; then
              case "$mountpoint" in
                '[SWAP]')
                  swapon $partition
                  ;;
                '[cryptSWAP]')
                  ;;
                '/mnt/')
                  parted -s $DISK_SYSTEM -- set $(echo $partition | $SED -r -e 's/([a-zA-Z_/-]*)([0-9]+)(.*)/\2/;' -) boot on &> /dev/null
                  mount $partition /mnt &> /dev/null
                  FLAG_ROOT='on'
                  ;;
                '/mnt/usr'|'/mnt/usr/local')
                  mkdir -p ${mountpoint%/} &> /dev/null
                  mount $partition ${mountpoint%/}
                  FLAG_USR='on'
                  ;;
                '/mnt/boot')
                  parted -s $DISK_SYSTEM -- set $(echo $partition | $SED -r -e 's/([a-zA-Z_/-]*)([0-9]+)(.*)/\2/;' -) boot on &> /dev/null
                  mkdir -p ${mountpoint%/} &> /dev/null
                  mount $partition ${mountpoint%/}
                  cd ${mountpoint%/} && ln -sf . boot && cd - &> /dev/null
                  ;;
                *)
                  mkdir -p ${mountpoint%/} &> /dev/null
                  mount $partition ${mountpoint%/}
                  ;;
              esac
              partitions_processed+=("$partition")
              mountpoints_assigned+=("$mountpoint")
              if [ "${partition##*_}" == 'crypt' ]; then
                FLAG_CRYPT='on'
                FLAG_PLAIN=''
              fi
            else
              $DIALOG ${FLAGS_DIALOG[@]} \
                --msgbox "You must assign a partition to the \`/mnt/' mountpoint, first." ${WIDGET_DIM}
            fi
            ;;
        esac
        ;;
      3)
        [ -n "$FLAG_ROOT" ] && {
          echo; echo;
          break
        }
        ;;
      *)
        echo; echo;
        abort
        ;;
    esac
  done
}

disk_operations() {

  # positional parameter

  # locals
  local feedback
  local -a menulist_operation=(
    1   "Wipe Disk with Zeros"
    2   "New Scheme: [MSDOS [2GB-SWAP] [xGB(ext4)]]"
    3   "New Scheme: [MSDOS [20GB(ext4)] [2GB-SWAP] [xGB(ext4)]]"
    4   "New Scheme: [MSDOS [20GB(ext4)] [10GB(ext4)] [2GB-SWAP] [xGB(ext4)]]"
    5   "New Scheme: [MSDOS [500MiB(ext4)] [20GB(ext4)] [2GB-SWAP] [xGB(ext4)]]"
    6   "New Scheme: [MSDOS [xGB(LUKS1(ext4))]]"
    7   "New Scheme: [MSDOS [20GB(LUKS1(ext4))] [xGB(LUKS1(ext4))]]"
    8   "New Scheme: [MSDOS [20GB(LUKS1(ext4))] [2GB-cryptSWAP] [xGB(LUKS1(ext4))]]"
    9   "New Scheme: [MSDOS [20GB(LUKS1(ext4))] [10GB(LUKS1(ext4))] [2GB-cryptSWAP] [xGB(LUKS1(ext4))]]"
    10  "New Scheme: [MSDOS [500MiB(LUKS1(ext4))] [20GB(LUKS1(ext4))] [2GB-cryptSWAP] [xGB(LUKS1(ext4))]]"
    11  "Select Partitions, assign Mountpoints"
  )

  # disk operations
  while [ true ]; do
    feedback=$( \
      $DIALOG ${FLAGS_DIALOG[@]} \
        --cancel-label "Abort" \
        ${FLAG_ROOT:+--extra-button --extra-label "Done"} \
        ${FLAG_ROOT:+--default-button extra} \
        --menu "Disk Operations on Disk \`$DISK_SYSTEM'\nATTENTION! Your data is likely to be erased!" ${MENUWIDGET_DIM} "${menulist_operation[@]}"
    )
    case $? in
      0)
        case $feedback in
          1)
            $DIALOG ${FLAGS_DIALOG[@]} \
              --default-button no \
              --yesno "Disk Operation on Disk \`$DISK_SYSTEM': \`${menulist_operation[$((feedback*2-1))]}'\n\nThis will take some time, sure to proceed?" ${WIDGET_DIM}
            case $? in
              0)
                # Add space on screen
                echo; echo;
                echo "Starting job \`${menulist_operation[$((feedback*2-1))]}' ..."
                sleep $PROCESS_DELAY

                # Free up mountpoints
                dismount_mountpoints

                # Wipe disk
                echo "Wiping disk with zeros ..." && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB status=progress || \
                  catch_error

                # Wait for user to acknowledge
                echo "... done with job \`${menulist_operation[$((feedback*2-1))]}'"
                hitenter || abort
                ;;
            esac
            ;;
          2)
            $DIALOG ${FLAGS_DIALOG[@]} \
              --default-button no \
              --yesno "Disk Operation on Disk \`$DISK_SYSTEM': \`${menulist_operation[$((feedback*2-1))]}'\n\nSure to proceed?" ${WIDGET_DIM}
            case $? in
              0)
                # Add space on screen
                echo; echo;
                echo "Starting job \`${menulist_operation[$((feedback*2-1))]}' ..."
                sleep $PROCESS_DELAY

                # Free up mountpoints
                dismount_mountpoints

                # Create msdos partition table
                # Create partitions, e.g.: [SWAP] + /
                # Format partitions
                echo "Wipe old partition headers ..." && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=1 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=2000 count=${MiB_initial_wipe} && \
                echo "Write MSDOS partition table ..." && \
                parted -s $DISK_SYSTEM -- mklabel msdos && \
                echo "Create partitions ..." && \
                parted -s $DISK_SYSTEM -- mkpart primary 1MiB 2000MiB mkpart primary 2000MiB -1s && \
                echo "Make swap space ..." && \
                (echo t; echo 1; echo 82; echo w) | fdisk $DISK_SYSTEM && \
                mkswap ${DISK_SYSTEM}1 && \
                echo "Create filesystem ..." && \
                mkfs.ext4 ${DISK_SYSTEM}2 && \
                echo "Partitions are now ready to be mounted." || \
                  catch_error

                # Wait for user to acknowledge
                echo "... done with job \`${menulist_operation[$((feedback*2-1))]}'"
                hitenter || abort
                ;;
            esac
            ;;
          3)
            $DIALOG ${FLAGS_DIALOG[@]} \
              --default-button no \
              --yesno "Disk Operation on \`$DISK_SYSTEM': \`${menulist_operation[$((feedback*2-1))]}'\n\nSure to proceed?" ${WIDGET_DIM}
            case $? in
              0)
                # Add space on screen
                echo; echo;
                echo "Starting job \`${menulist_operation[$((feedback*2-1))]}' ..."
                sleep $PROCESS_DELAY

                # Free up mountpoints
                dismount_mountpoints

                # Create msdos partition table
                # Format Disk, e.g.: / + [SWAP] + /home
                # Format partitions
                echo "Wipe old partition headers ..." && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=1 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=20000 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=22000 count=${MiB_initial_wipe} && \
                echo "Write MSDOS partition table ..." && \
                parted -s $DISK_SYSTEM -- mklabel msdos && \
                echo "Create partitions ..." && \
                parted -s $DISK_SYSTEM -- mkpart primary 1MiB 20000MiB mkpart primary 20000MiB 22000MiB mkpart primary 22000MiB -1s && \
                echo "Create swap space ..." && \
                (echo t; echo 2; echo 82; echo w) | fdisk $DISK_SYSTEM && \
                mkswap ${DISK_SYSTEM}2 && \
                echo "Create filesystems ..." && \
                mkfs.ext4 ${DISK_SYSTEM}1 && \
                mkfs.ext4 ${DISK_SYSTEM}3 && \
                echo "Partitions are now ready to be mounted." || \
                  catch_error

                # Hit key
                echo "... done with job \`${menulist_operation[$((feedback*2-1))]}'"
                hitenter || abort
            esac
            ;;
          4)
            $DIALOG ${FLAGS_DIALOG[@]} \
              --default-button no \
              --yesno "Disk Operation on \`$DISK_SYSTEM': \`${menulist_operation[$((feedback*2-1))]}'\n\nSure to proceed?" ${WIDGET_DIM}
            case $? in
              0)
                # Add space on screen
                echo; echo;
                echo "Starting job \`${menulist_operation[$((feedback*2-1))]}' ..."
                sleep $PROCESS_DELAY

                # Free /mnt
                dismount_mountpoints

                # Create msdos partition table
                # Format Disk, e.g.: / + /tmp + [SWAP] + /home
                # Format partitions
                echo "Wipe old partition headers ..." && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=1 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=20000 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=30000 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=32000 count=${MiB_initial_wipe} && \
                echo "Write MSDOS partition table ..." && \
                parted -s $DISK_SYSTEM -- mklabel msdos && \
                echo "Create partitions ..." && \
                parted -s $DISK_SYSTEM -- mkpart primary 1MiB 20000MiB mkpart primary 20000MiB 30000MiB mkpart primary 30000MiB 32000MiB mkpart primary 32000MiB -1s && \
                echo "Create swap space ..." && \
                (echo t; echo 3; echo 82; echo w) | fdisk $DISK_SYSTEM && \
                mkswap ${DISK_SYSTEM}3 && \
                echo "Create filesystems ..." && \
                mkfs.ext4 ${DISK_SYSTEM}1 && \
                mkfs.ext4 ${DISK_SYSTEM}2 && \
                mkfs.ext4 ${DISK_SYSTEM}4 && \
                echo "Partitions are now ready to be mounted." || \
                  catch_error

                # Hit key
                echo "... done with job \`${menulist_operation[$((feedback*2-1))]}'"
                hitenter || abort
            esac
            ;;
          5)
            $DIALOG ${FLAGS_DIALOG[@]} \
              --default-button no \
              --yesno "Disk Operation on \`$DISK_SYSTEM': \`${menulist_operation[$((feedback*2-1))]}'\n\nSure to proceed?" ${WIDGET_DIM}
            case $? in
              0)
                # Add space on screen
                echo; echo;
                echo "Starting job \`${menulist_operation[$((feedback*2-1))]}' ..."
                sleep $PROCESS_DELAY

                # Free /mnt
                dismount_mountpoints

                # Create msdos partition table
                # Format Disk, e.g.: /boot + / + [SWAP] + /home
                # Format partitions
                echo "Wipe old partition headers ..." && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=1 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=500 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=20500 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=22500 count=${MiB_initial_wipe} && \
                echo "Write MSDOS partition table ..." && \
                parted -s $DISK_SYSTEM -- mklabel msdos && \
                echo "Create partitions ..." && \
                parted -s $DISK_SYSTEM -- mkpart primary 1MiB 500MiB mkpart primary 500MiB 20500MiB mkpart primary 20500MiB 22500MiB mkpart primary 22500MiB -1s && \
                echo "Create swap space ..." && \
                (echo t; echo 3; echo 82; echo w) | fdisk $DISK_SYSTEM && \
                mkswap ${DISK_SYSTEM}3 && \
                echo "Create filesystems ..." && \
                mkfs.ext4 ${DISK_SYSTEM}1 && \
                mkfs.ext4 ${DISK_SYSTEM}2 && \
                mkfs.ext4 ${DISK_SYSTEM}4 && \
                echo "Partitions are now ready to be mounted." || \
                  catch_error

                # Hit key
                echo "... done with job \`${menulist_operation[$((feedback*2-1))]}'"
                hitenter || abort
            esac
            ;;
          6)
            $DIALOG ${FLAGS_DIALOG[@]} \
              --default-button no \
              --yesno "Disk Operation on \`$DISK_SYSTEM': \`${menulist_operation[$((feedback*2-1))]}'\n\nSure to proceed?" ${WIDGET_DIM}
            case $? in
              0)
                # Add space on screen
                echo; echo;
                echo "Starting job \`${menulist_operation[$((feedback*2-1))]}' ..."
                sleep $PROCESS_DELAY

                # Free /mnt
                dismount_mountpoints

                # Create msdos partition table
                # Format Disk, e.g.: /
                # Setup encryption
                # Open encryption
                # Format partition
                # Close encryption
                echo "Wipe old partition header ..." && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=1 count=${MiB_initial_wipe} && \
                echo "Write MSDOS partition table ..." && \
                parted -s $DISK_SYSTEM -- mklabel msdos && \
                echo "Create partition ..." && \
                parted -s $DISK_SYSTEM -- mkpart primary 1MiB -1s && \
                echo "Create LUKS header ..." && \
                cryptsetup -v --iter-time 500 --use-random --type luks1 luksFormat ${DISK_SYSTEM}1 && \
                echo "Open encryption ..." && \
                cryptsetup luksOpen ${DISK_SYSTEM}1 "${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                echo "Create filesystem ..." && \
                mkfs.ext4 /dev/mapper/"${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                echo "Store disk passphrase at a save place." && \
                sleep $PROCESS_DELAY && \
                cryptsetup luksClose "${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" || \
                  catch_error

                # Hit key
                echo "... done with job \`${menulist_operation[$((feedback*2-1))]}'"
                hitenter || abort
            esac
            ;;
          7)
            $DIALOG ${FLAGS_DIALOG[@]} \
              --default-button no \
              --yesno "Disk Operation on \`$DISK_SYSTEM': \`${menulist_operation[$((feedback*2-1))]}'\n\nSure to proceed?" ${WIDGET_DIM}
            case $? in
              0)
                # Add space on screen
                echo; echo;
                echo "Starting job \`${menulist_operation[$((feedback*2-1))]}' ..."
                sleep $PROCESS_DELAY

                # Free /mnt
                dismount_mountpoints

                # Write MSDOS partition table
                # Create Partitions, e.g.: / + /home
                # Setup encryption
                # Open encryption
                # Format partitions
                # Close encryption
                echo "Wipe old partition headers ..." && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=1 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=20000 count=${MiB_initial_wipe} && \
                echo "Write MSDOS partition table ..." && \
                parted -s $DISK_SYSTEM -- mklabel msdos && \
                echo "Create partitions ..." && \
                parted -s $DISK_SYSTEM -- mkpart primary 1MiB 20000MiB mkpart primary 20000MiB -1s && \
                echo "Create LUKS header ..." && \
                cryptsetup -v --iter-time 500 --use-random --type luks1 luksFormat ${DISK_SYSTEM}1 && \
                cryptsetup -v --iter-time 500 --use-random --type luks1 luksFormat ${DISK_SYSTEM}2 && \
                echo "Open encryption ..." && \
                cryptsetup luksOpen ${DISK_SYSTEM}1 "${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                cryptsetup luksOpen ${DISK_SYSTEM}2 "${DISK_SYSTEM##*/}2${CRYPT_SUFFIX}" && \
                echo "Create filesystems ..." && \
                mkfs.ext4 /dev/mapper/"${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                mkfs.ext4 /dev/mapper/"${DISK_SYSTEM##*/}2${CRYPT_SUFFIX}" && \
                echo "Store disk passphrases at a save place." && \
                sleep $PROCESS_DELAY && \
                cryptsetup luksClose "${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                cryptsetup luksClose "${DISK_SYSTEM##*/}2${CRYPT_SUFFIX}" || \
                  catch_error

                # Hit key
                echo "... done with job \`${menulist_operation[$((feedback*2-1))]}'"
                hitenter || abort
            esac
            ;;
          8)
            $DIALOG ${FLAGS_DIALOG[@]} \
              --default-button no \
              --yesno "Disk Operation on \`$DISK_SYSTEM': \`${menulist_operation[$((feedback*2-1))]}'\n\nSure to proceed?" ${WIDGET_DIM}
            case $? in
              0)
                # Add space on screen
                echo; echo;
                echo "Starting job \`${menulist_operation[$((feedback*2-1))]}' ..."
                sleep $PROCESS_DELAY

                # Free /mnt
                dismount_mountpoints

                # Write MSDOS partition table
                # Create Partitions, e.g.: / + [cryptSWAP] + /home
                # Setup encryption
                # Open encryption
                # Format partitions
                # Close encryption
                echo "Wipe old partition headers ..." && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=1 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=20000 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=22000 count=${MiB_initial_wipe} && \
                echo "Write MSDOS partition table ..." && \
                parted -s $DISK_SYSTEM -- mklabel msdos && \
                echo "Create partitions ..." && \
                parted -s $DISK_SYSTEM -- mkpart primary 1MiB 20000MiB mkpart primary 20000MiB 22000MiB mkpart primary 22000MiB -1s && \
                echo "Create LUKS header ..." && \
                cryptsetup -v --iter-time 500 --use-random --type luks1 luksFormat ${DISK_SYSTEM}1 && \
                cryptsetup -v --iter-time 500 --use-random --type luks1 luksFormat ${DISK_SYSTEM}3 && \
                echo "Open encryption ..." && \
                cryptsetup luksOpen ${DISK_SYSTEM}1 "${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                cryptsetup luksOpen ${DISK_SYSTEM}3 "${DISK_SYSTEM##*/}3${CRYPT_SUFFIX}" && \
                echo "Create filesystems ..." && \
                mkfs.ext4 /dev/mapper/"${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                mkfs.ext4 /dev/mapper/"${DISK_SYSTEM##*/}3${CRYPT_SUFFIX}" && \
                echo "Store disk passphrases at a save place." && \
                sleep $PROCESS_DELAY && \
                cryptsetup luksClose "${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                cryptsetup luksClose "${DISK_SYSTEM##*/}3${CRYPT_SUFFIX}" || \
                  catch_error

                # Hit key
                echo "... done with job \`${menulist_operation[$((feedback*2-1))]}'"
                hitenter || abort
            esac
            ;;
          9)
            $DIALOG ${FLAGS_DIALOG[@]} \
              --default-button no \
              --yesno "Disk Operation on \`$DISK_SYSTEM': \`${menulist_operation[$((feedback*2-1))]}'\n\nSure to proceed?" ${WIDGET_DIM}
            case $? in
              0)
                # Add space on screen
                echo; echo;
                echo "Starting job \`${menulist_operation[$((feedback*2-1))]}' ..."
                sleep $PROCESS_DELAY

                # Free /mnt
                dismount_mountpoints

                # Write MSDOS partition table
                # Create Partitions, e.g.: / + /tmp + [cryptSWAP] + /home
                # Setup encryption
                # Open encryption
                # Format partitions
                # Close encryption
                echo "Wipe old partition headers ..." && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=1 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=20000 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=30000 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=32000 count=${MiB_initial_wipe} && \
                echo "Write MSDOS partition table ..." && \
                parted -s $DISK_SYSTEM -- mklabel msdos && \
                echo "Create partitions ..." && \
                parted -s $DISK_SYSTEM -- mkpart primary 1MiB 20000MiB mkpart primary 20000MiB 30000MiB mkpart primary 30000MiB 32000MiB mkpart primary 32000MiB -1s && \
                echo "Create LUKS header ..." && \
                cryptsetup -v --iter-time 500 --use-random --type luks1 luksFormat ${DISK_SYSTEM}1 && \
                cryptsetup -v --iter-time 500 --use-random --type luks1 luksFormat ${DISK_SYSTEM}2 && \
                cryptsetup -v --iter-time 500 --use-random --type luks1 luksFormat ${DISK_SYSTEM}4 && \
                echo "Open encryption ..." && \
                cryptsetup luksOpen ${DISK_SYSTEM}1 "${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                cryptsetup luksOpen ${DISK_SYSTEM}2 "${DISK_SYSTEM##*/}2${CRYPT_SUFFIX}" && \
                cryptsetup luksOpen ${DISK_SYSTEM}4 "${DISK_SYSTEM##*/}4${CRYPT_SUFFIX}" && \
                echo "Create filesystems ..." && \
                mkfs.ext4 /dev/mapper/"${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                mkfs.ext4 /dev/mapper/"${DISK_SYSTEM##*/}2${CRYPT_SUFFIX}" && \
                mkfs.ext4 /dev/mapper/"${DISK_SYSTEM##*/}4${CRYPT_SUFFIX}" && \
                echo "Store disk passphrases at a save place." && \
                sleep $PROCESS_DELAY && \
                cryptsetup luksClose "${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                cryptsetup luksClose "${DISK_SYSTEM##*/}2${CRYPT_SUFFIX}" && \
                cryptsetup luksClose "${DISK_SYSTEM##*/}4${CRYPT_SUFFIX}" || \
                  catch_error

                # Hit key
                echo "... done with job \`${menulist_operation[$((feedback*2-1))]}'"
                hitenter || abort
            esac
            ;;
          10)
            $DIALOG ${FLAGS_DIALOG[@]} \
              --default-button no \
              --yesno "Disk Operation on \`$DISK_SYSTEM': \`${menulist_operation[$((feedback*2-1))]}'\n\nSure to proceed?" ${WIDGET_DIM}
            case $? in
              0)
                # Add space on screen
                echo; echo;
                echo "Starting job \`${menulist_operation[$((feedback*2-1))]}' ..."
                sleep $PROCESS_DELAY

                # Free /mnt
                dismount_mountpoints

                # Write MSDOS partition table
                # Create Partitions, e.g.: /boot + / + [cryptSWAP] + /home
                # Setup encryption
                # Open encryption
                # Format partitions
                # Close encryption
                echo "Wipe old partition headers ..." && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=1 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=500 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=20500 count=${MiB_initial_wipe} && \
                dd if=/dev/zero of=$DISK_SYSTEM bs=1MiB seek=22500 count=${MiB_initial_wipe} && \
                echo "Write MSDOS partition table ..." && \
                parted -s $DISK_SYSTEM -- mklabel msdos && \
                echo "Create partitions ..." && \
                parted -s $DISK_SYSTEM -- mkpart primary 1MiB 500MiB mkpart primary 500MiB 20500MiB mkpart primary 20500MiB 22500MiB mkpart primary 22500MiB -1s && \
                echo "Create LUKS header ..." && \
                cryptsetup -v --iter-time 500 --use-random --type luks1 luksFormat ${DISK_SYSTEM}1 && \
                cryptsetup -v --iter-time 500 --use-random --type luks1 luksFormat ${DISK_SYSTEM}2 && \
                cryptsetup -v --iter-time 500 --use-random --type luks1 luksFormat ${DISK_SYSTEM}4 && \
                echo "Open encryption ..." && \
                cryptsetup luksOpen ${DISK_SYSTEM}1 "${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                cryptsetup luksOpen ${DISK_SYSTEM}2 "${DISK_SYSTEM##*/}2${CRYPT_SUFFIX}" && \
                cryptsetup luksOpen ${DISK_SYSTEM}4 "${DISK_SYSTEM##*/}4${CRYPT_SUFFIX}" && \
                echo "Create filesystems ..." && \
                mkfs.ext4 /dev/mapper/"${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                mkfs.ext4 /dev/mapper/"${DISK_SYSTEM##*/}2${CRYPT_SUFFIX}" && \
                mkfs.ext4 /dev/mapper/"${DISK_SYSTEM##*/}4${CRYPT_SUFFIX}" && \
                echo "Store disk passphrases at a save place." && \
                sleep $PROCESS_DELAY && \
                cryptsetup luksClose "${DISK_SYSTEM##*/}1${CRYPT_SUFFIX}" && \
                cryptsetup luksClose "${DISK_SYSTEM##*/}2${CRYPT_SUFFIX}" && \
                cryptsetup luksClose "${DISK_SYSTEM##*/}4${CRYPT_SUFFIX}" || \
                  catch_error

                # Hit key
                echo "... done with job \`${menulist_operation[$((feedback*2-1))]}'"
                hitenter || abort
            esac
            ;;
          11)
            # Add space on screen
            echo; echo;
            echo "Starting job \`${menulist_operation[$((feedback*2-1))]}' ..."
            sleep $PROCESS_DELAY

            open_encryption
            assign_mountpoints

            # Hit key
            echo "... done with job \`${menulist_operation[$((feedback*2-1))]}'"
            hitenter || abort
            ;;
        esac
        ;;
      3)    # extra button
        [ -n "$FLAG_ROOT" ] && {
          echo; echo;
          break
        }
        ;;
      *)
        echo; echo;
        abort
        ;;
    esac
  done
}

set_system_wallpaper() {

  # Precondition: Folder /mnt must refer to a mounted partition.

  # Copy desktop's background
  #   Note this image is specific to OpenRC
  cp -a /etc/wallpaper.png /mnt/etc/wallpaper.png
}

set_system_config() {

  # positional parameter
  local -r desktop_environment="${1^^}"   # e.g.: LXDE, XFCE, MATE

  # locals
  local -r xkbmap="$(setxkbmap -query)"
  local -r xkbmap_rules=$(echo "${xkbmap}" | $SED -r -e '/rules/!d;s/^.*[ \t]//;' -)
  local -r xkbmap_model=$(echo "${xkbmap}" | $SED -r -e '/model/!d;s/^.*[ \t]//;' -)
  local -r xkbmap_layout=$(echo "${xkbmap}" | $SED -r -e '/layout/!d;s/^.*[ \t]//;' -)

  # Copy live system’s skel folder into the new system
  cp -a /etc/skel/ /mnt/etc/

  # Adjust /mnt/etc/sudoers
  $SED -r -i \
    -e '/^# %wheel ALL=\(ALL\) ALL/s/^# //;' \
      /mnt/etc/sudoers

  # Set up default .xinitrc
  echo "setxkbmap -rules ${xkbmap_rules} -model ${xkbmap_model} -layout ${xkbmap_layout}" > /mnt/etc/skel/.xinitrc
  case "${desktop_environment}" in
    'LXDE')
      echo "exec startlxde      " >> /mnt/etc/skel/.xinitrc
      ;;
    'XFCE')
      echo "exec startxfce4     " >> /mnt/etc/skel/.xinitrc
      ;;
    'MATE')
      echo "exec mate-session   " >> /mnt/etc/skel/.xinitrc
      ;;
  esac
  chmod +x /mnt/etc/skel/.xinitrc

  # Adjust default .bash_profile to start X automatically
  echo "startx" >> /mnt/etc/skel/.bash_profile
}

check_dbus_user() {

  # Precondition: Folder /mnt must refer to a mounted partition.

  # locals
  local tmpfile=/mnt/checkDBUS.sh

  # Create the dbus user if it doesn't exist
  echo "#!/bin/bash                                                               " >  "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "notool() {                                                                " >> "$tmpfile"
  echo "  local -r tool=\"\$1\"                                                   " >> "$tmpfile"
  echo "  echo \"Missing tool in chroot environment: \$tool\"                     " >> "$tmpfile"
  echo "  exit 1                                                                  " >> "$tmpfile"
  echo "}                                                                         " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "# tool check                                                              " >> "$tmpfile"
  echo "[ -z \"\$(command -v grep)\" ] && notool 'grep'                           " >> "$tmpfile"
  echo "[ -z \"\$(command -v groupadd)\" ] && notool 'groupadd'                   " >> "$tmpfile"
  echo "[ -z \"\$(command -v useradd)\" ] && notool 'useradd'                     " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "[ \$(grep dbus /etc/group) = \"\" ] &&                                  \\" >> "$tmpfile"
  echo "  groupadd -g 81 dbus                                                     " >> "$tmpfile"
  echo "[ \$(grep dbus /etc/passwd) = \"\" ] &&                                 \\" >> "$tmpfile"
  echo "  useradd -r -s /sbin/nologin -g 81 -u 81 dbus                            " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "# cancel error status                                                     " >> "$tmpfile"
  echo "true                                                                      " >> "$tmpfile"
  chroot_exec "$tmpfile" || catch_error
}

enable_services_OpenRC() {

  # Precondition: Folder /mnt must refer to a mounted partition.

  # locals
  local tmpfile=/mnt/servicesOpenRC.sh

  # Enable services with OpenRC
  echo "#!/bin/bash                                                               " >  "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "notool() {                                                                " >> "$tmpfile"
  echo "  local -r tool=\"\$1\"                                                   " >> "$tmpfile"
  echo "  echo \"Missing tool in chroot environment: \$tool\"                     " >> "$tmpfile"
  echo "  exit 1                                                                  " >> "$tmpfile"
  echo "}                                                                         " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "# tool check                                                              " >> "$tmpfile"
  echo "[ -z \"\$(command -v rc-update)\" ] && notool 'rc-update'                 " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "rc-update add NetworkManager default                                      " >> "$tmpfile"
  echo "rc-update add dbus default                                                " >> "$tmpfile"
  echo "rc-update add alsasound default                                           " >> "$tmpfile"
  chroot_exec "$tmpfile" || catch_error
}

enable_services_SystemD() {

  # Precondition: Folder /mnt must refer to a mounted partition.

  # locals
  local tmpfile=/mnt/servicesSystemD.sh

  # Enable services with OpenRC
  echo "#!/bin/bash                                                               " >  "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "notool() {                                                                " >> "$tmpfile"
  echo "  local -r tool=\"\$1\"                                                   " >> "$tmpfile"
  echo "  echo \"Missing tool in chroot environment: \$tool\"                     " >> "$tmpfile"
  echo "  exit 1                                                                  " >> "$tmpfile"
  echo "}                                                                         " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "# tool check                                                              " >> "$tmpfile"
  echo "[ -z \"\$(command -v systemctl)\" ] && notool 'systemctl'                 " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "systemctl enable NetworkManager                                           " >> "$tmpfile"

  # DBus is not meant to be started with SystemD?
  #echo "systemctl enable dbus               " >> "$tmpfile"

  # How to enable ALSA Services with SystemD?
  # See: https://wiki.archlinux.org/title/Advanced_Linux_Sound_Architecture#ALSA_and_systemd
  #echo "systemctl enable alsasound          " >> "$tmpfile"

  chroot_exec "$tmpfile" || catch_error
}

chroot_exec() {

  # Precondition: Folder /mnt must refer to a mounted partition.

  # positional parameter
  local -r scriptfile="$1"

  # locals
  local errstat

  chmod u+x "${scriptfile}"
  arch-chroot /mnt "/${scriptfile##*/}"
  errstat=$?
  rm -f "${scriptfile}"

  return $errstat
}

set_password() {

  # positional parameter
  local -r algo="$1"
  local -r user="$2"
  local -r priviledged="$3"

  # locals
  local -r tmpfile="/mnt/setPassword.sh"
  local feedback1
  local feedback2

  while [ true ]; do
    feedback1=$( \
      $DIALOG ${FLAGS_DIALOG[@]} \
        --cancel-label "Disable" \
        --quoted --passwordbox "Enter Password for User \`${user}'" ${WIDGET_DIM} \
    )
    case $? in
      0)
        feedback2=$( \
          $DIALOG ${FLAGS_DIALOG[@]} \
            --quoted --passwordbox "Repeat Password for User \`${user}'" ${WIDGET_DIM} \
        )
        case $? in
          0)
            if [ -z "${feedback1}" -o "${feedback1}" != "${feedback2}" ]; then
              $DIALOG ${FLAGS_DIALOG[@]} \
                --msgbox "Password not valid, try again!" ${WIDGET_DIM}
            else
              echo; echo;
              echo "#!/bin/bash                                                               " >  "$tmpfile"
              echo "                                                                          " >> "$tmpfile"
              echo "notool() {                                                                " >> "$tmpfile"
              echo "  local -r tool=\"\$1\"                                                   " >> "$tmpfile"
              echo "  echo \"Missing tool in chroot environment: \$tool\"                     " >> "$tmpfile"
              echo "  exit 1                                                                  " >> "$tmpfile"
              echo "}                                                                         " >> "$tmpfile"
              echo "                                                                          " >> "$tmpfile"
              echo "# tool check                                                              " >> "$tmpfile"
              echo "[ -z \"\$(command -v usermod)\" ] && notool 'usermod'                     " >> "$tmpfile"
              echo "                                                                          " >> "$tmpfile"
              echo "usermod                                                                 \\" >> "$tmpfile"
              echo "  -p \$(openssl passwd ${algo} \"${feedback1}\")                        \\" >> "$tmpfile"
              echo "    ${user}                                                               " >> "$tmpfile"
              chroot_exec "$tmpfile" || abort
              [ "$user" == "$user_root" -o -n "$priviledged" ] && FLAG_ADMIN='on'
              break
            fi
            ;;
          *)
            $DIALOG ${FLAGS_DIALOG[@]} \
              --msgbox "Try again!" ${WIDGET_DIM}
            ;;
        esac
        ;;
      *)
        $DIALOG ${FLAGS_DIALOG[@]} \
          --msgbox "Password disabled." ${WIDGET_DIM}
        echo; echo;
        break
        ;;
    esac
  done
}

add_user_account() {

  # positional parameter
  local -r algo="$1"

  # locals
  local feedback
  local tmpfile=/mnt/newUserAccount.sh
  local priviledged=''
  local -a list_of_new_users=()

  while [ true ]; do
    $DIALOG ${FLAGS_DIALOG[@]} \
      --extra-button \
      --extra-label "Standard" \
      --ok-label "Priviledged" \
      --cancel-label "No" \
      --yesno "Current List of New Users:\n\`${list_of_new_users[*]}'\n\nCreate a new User Account?" ${WIDGET_DIM}
    case $? in
      0)
        priviledged='on'
        ;&
      3)
        feedback=$(\
          $DIALOG ${FLAGS_DIALOG[@]} \
            --inputbox "Enter Username\nAllowed characters are: lower case letters, numbers, underscore, hyphen, a final dolar sign" ${WIDGET_DIM} \
        )
        case $? in
          0)
            echo; echo;
            if [  -z "${feedback}" -o \
                  -n "`echo ${feedback} | $SED -r -e '/.{33,}/!d;' -`" -o \
                  -n "`echo ${feedback} | $SED -r -e '/^[a-z_][0-9a-z_-]*[$]?$/d;' -`" \
            ]; then
              $DIALOG ${FLAGS_DIALOG[@]} \
                --msgbox "Not a valid username!" ${WIDGET_DIM}
            else
              ( \
                echo "#!/bin/bash                                                               " >  "$tmpfile"
                echo "                                                                          " >> "$tmpfile"
                echo "notool() {                                                                " >> "$tmpfile"
                echo "  local -r tool=\"\$1\"                                                   " >> "$tmpfile"
                echo "  echo \"Missing tool in chroot environment: \$tool\"                     " >> "$tmpfile"
                echo "  exit 1                                                                  " >> "$tmpfile"
                echo "}                                                                         " >> "$tmpfile"
                echo "                                                                          " >> "$tmpfile"
                echo "# tool check                                                              " >> "$tmpfile"
                echo "[ -z \"\$(command -v useradd)\" ] && notool 'useradd'                     " >> "$tmpfile"
                echo "                                                                          " >> "$tmpfile"
                echo "useradd                                                                 \\" >> "$tmpfile"
                echo "  --comment ${feedback^}                                                \\" >> "$tmpfile"
                echo "  --create-home                                                         \\" >> "$tmpfile"
                echo "  --no-user-group                                                       \\" >> "$tmpfile"
                echo "  --gid 984                                                             \\" >> "$tmpfile"
                echo "  ${priviledged:+--groups wheel}                                        \\" >> "$tmpfile"
                echo "    ${feedback};                                                          " >> "$tmpfile"
              ) && \
              chroot_exec "$tmpfile" && \
              list_of_new_users+=("${feedback}") && \
              $DIALOG ${FLAGS_DIALOG[@]} \
                --msgbox "User \`${feedback}'${priviledged:+, priviledged,} successfully created." ${WIDGET_DIM} && \
              set_password "${openssl_passwd_algo}" "${feedback}" "${priviledged}" || \
                catch_error
            fi
            priviledged=''
            ;;
          *)
            ;;
        esac
        ;;
      *)
        [ -n "$FLAG_ADMIN" ] && {
          echo; echo;
          break
        }
        $DIALOG ${FLAGS_DIALOG[@]} \
          --msgbox "At least one new, priviledged user must be set up." ${WIDGET_DIM}
        ;;
    esac
  done
}

set_hostname_OpenRC() {

  # positional parameter
  local -r new_hostname="$1"

  # edit /etc/conf.d/hostname
  $SED -r -i \
    -e "s|localhost|${new_hostname}|;" \
      /mnt/etc/conf.d/hostname;

  # delete SystemD configuration files (!)
  rm -f /mnt/etc/hostname
  rm -f /mnt/etc/hosts
}

set_hostname_SystemD() {

  # positional parameter
  local -r new_hostname="$1"

  # edit /etc/hostname
  echo "${new_hostname}" > /mnt/etc/hostname

  # edit /etc/hosts
  sed -r -i \
    -e '/^127\.0\.0\.1/d;' \
    -e '/^\:\:1      /d;' \
      /mnt/etc/hosts
  echo "127.0.0.1 localhost.localdomain localhost ${new_hostname}" >> /mnt/etc/hosts
  echo "::1       localhost.localdomain localhost ${new_hostname}" >> /mnt/etc/hosts

  # delete OpenRC configuration files (!)
  rm -f /mnt/etc/conf.d/hostname
}

set_localtime() {

  # positional parameter
  local -r new_timezone="$1"

  ln \
    -sf \
      /mnt/usr/share/zoneinfo/"${new_timezone}" /mnt/etc/localtime
}

install_packages() {

  # positional parameter
  local -r set_of_packages="$1"

  # locals
  local tmpfile=/mnt/installPackages.sh

  echo "#!/bin/bash                                                               " >  "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "notool() {                                                                " >> "$tmpfile"
  echo "  local -r tool=\"\$1\"                                                   " >> "$tmpfile"
  echo "  echo \"Missing tool in chroot environment: \$tool\"                     " >> "$tmpfile"
  echo "  exit 1                                                                  " >> "$tmpfile"
  echo "}                                                                         " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "# tool check                                                              " >> "$tmpfile"
  echo "[ -z \"\$(command -v pacman)\" ] && notool 'pacman'                       " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "pacman -S ${set_of_packages}                                            \\" >> "$tmpfile"
  echo "  --confirm                                                               " >> "$tmpfile"
  chroot_exec "$tmpfile" || catch_error
}

make_initramfs() {

  # locals
  local tmpfile=/mnt/makeInitramfs.sh

  echo "#!/bin/bash                                                               " >  "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "notool() {                                                                " >> "$tmpfile"
  echo "  local -r tool=\"\$1\"                                                   " >> "$tmpfile"
  echo "  echo \"Missing tool in chroot environment: \$tool\"                     " >> "$tmpfile"
  echo "  exit 1                                                                  " >> "$tmpfile"
  echo "}                                                                         " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "# tool check                                                              " >> "$tmpfile"
  echo "[ -z \"\$(command -v mkinitcpio)\" ] && notool 'mkinitcpio'               " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "mkinitcpio                                                              \\" >> "$tmpfile"
  echo "  -p linux-libre                                                          " >> "$tmpfile"
  chroot_exec "$tmpfile" || abort
}

gen_locales() {

  # positional parameter
  local -r -a default_locales=("$@")

  # locals
  local aux
  local i
  local -a checklist_locale=()
  local feedback
  local -a record=()
  local cfgfile=/mnt/etc/locale.gen
  local tmpfile=/mnt/genLocales.sh
  local bakfile="${cfgfile}.bak"

  cp "$cfgfile" "$bakfile"

  for i in $($SED -r -e '/^#[ ]|^#$/d;s/^#//;s/[ \t]*$//;s/ /#/g;' $cfgfile); do
    checklist_locale+=("${i//\#/ }" "${i//\#/ }" "off")
  done

  feedback=$( \
    $DIALOG ${FLAGS_DIALOG[@]} \
      --cancel-label "Abort" \
      --checklist \
        "Select Locales\nDefaulting to: \`${default_locales[*]/%/ }'" \
        ${MENUWIDGET_DIM} \
        "${checklist_locale[@]}" \
  )
  case $? in
    0)
      if [ -z "$feedback" ]; then
        $DIALOG ${FLAGS_DIALOG[@]} \
          --msgbox "Locales defaulting to: \`${default_locales[*]/%/ }'" ${WIDGET_DIM}
        record=("${default_locales[@]}")
      else
        record=("${feedback}")
      fi
      echo; echo;
      ;;
    *)
      echo; echo;
      abort
      ;;
  esac

  for i in "${record[@]}"; do
    $SED -r -i \
      -e "/^.$i/s/^#//;" \
        "$cfgfile"
  done

  echo "#!/bin/bash                                                               " >  "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "notool() {                                                                " >> "$tmpfile"
  echo "  local -r tool=\"\$1\"                                                   " >> "$tmpfile"
  echo "  echo \"Missing tool in chroot environment: \$tool\"                     " >> "$tmpfile"
  echo "  exit 1                                                                  " >> "$tmpfile"
  echo "}                                                                         " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "# tool check                                                              " >> "$tmpfile"
  echo "[ -z \"\$(command -v locale-gen)\" ] && notool 'locale-gen'               " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "locale-gen                                                                " >> "$tmpfile"
  chroot_exec "$tmpfile" || abort
}

set_language() {

  # positional parameter
  local -r default_language="$1"

  # locals
  local tmpfile=/mnt/setLanguage.sh

  echo "#!/bin/bash                                                               " >  "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "notool() {                                                                " >> "$tmpfile"
  echo "  local -r tool=\"\$1\"                                                   " >> "$tmpfile"
  echo "  echo \"Missing tool in chroot environment: \$tool\"                     " >> "$tmpfile"
  echo "  exit 1                                                                  " >> "$tmpfile"
  echo "}                                                                         " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "# tool check                                                              " >> "$tmpfile"
  echo "[ -z \"\$(command -v locale)\" ] && notool 'locale'                       " >> "$tmpfile"
  echo "[ -z \"\$(command -v dialog)\" ] && notool 'dialog'                       " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "declare i                                                                 " >> "$tmpfile"
  echo "declare -a radiolist_language=()                                          " >> "$tmpfile"
  echo "declare feedback                                                          " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "# collect available languages                                             " >> "$tmpfile"
  echo "for i in \$(locale --all-locales); do                                     " >> "$tmpfile"
  echo "  radiolist_language+=(\"\$i\" \"\$i\" \"off\")                           " >> "$tmpfile"
  echo "done                                                                      " >> "$tmpfile"
  echo "                                                                          " >> "$tmpfile"
  echo "# set language                                                            " >> "$tmpfile"
  echo "feedback=\$(                                                            \\" >> "$tmpfile"
  echo "  dialog ${FLAGS_DIALOG[@]}                                             \\" >> "$tmpfile"
  echo "    --radiolist                                                         \\" >> "$tmpfile"
  echo "      \"Select your Language\\nDefaulting to: $default_language\"       \\" >> "$tmpfile"
  echo "      ${MENUWIDGET_DIM}                                                 \\" >> "$tmpfile"
  echo "      \${radiolist_language[@]};                                        \\" >> "$tmpfile"
  echo ")                                                                         " >> "$tmpfile"
  echo "[ \$? -ne 0 -o -z \"\$feedback\" ] && {                                   " >> "$tmpfile"
  echo "  dialog ${FLAGS_DIALOG[@]}                                             \\" >> "$tmpfile"
  echo "    --msgbox \"Language defaulting to: $default_language\" ${WIDGET_DIM}  " >> "$tmpfile"
  echo "  feedback=\"$default_language\"                                          " >> "$tmpfile"
  echo "}                                                                         " >> "$tmpfile"
  echo "echo \"LANG=\$feedback\" > /etc/locale.conf                               " >> "$tmpfile"
  chroot_exec "$tmpfile" || abort
}

dismount_mountpoints() {

  # dismount
  umount \
    -R /mnt \
      &> /dev/null
  swapoff \
    -a \
      &> /dev/null

  # reset records
  mountpoints_assigned=()
  partitions_processed=()

  # clear flags
  FLAG_USR=''
  FLAG_LVM2=''
  FLAG_ROOT=''
  FLAG_CRYPT=''
  FLAG_PLAIN='on'

  # Wait for Update
  udevadm settle
}

close_encryption() {

  # positional parameter

  # locals
  local -r -a type_crypt=( \
    $( \
      lsblk -n -oPATH,TYPE | \
      egrep ${DISK_SYSTEM##*/} | \
      egrep crypt | \
      cut -f1 -d' ' - \
    ) \
  )
  local n

  for n in "${type_crypt[@]}"; do
    cryptsetup luksClose "${n}"
  done
}

catch_error() {

  # positional parameter

  echo "Oops, an error occured. Proceed anyway?"
  hitenter || abort
}

abort() {

  # positional parameter

  echo "Aborting ..."
  echo "Mountpoints are NOT dismounted."
  echo "Encryption is NOT closed."
  exit 1
}

get_device() {

  # positional parameter
  local -r mountpoint="$1"
  local -n parray1="$2"
  local -n parray2="$3"
  local -n presult="$4"

  # locals
  local i
  local -i n=0

  for i in "${parray1[@]}"; do
    [ "$i" == "$mountpoint" ] && {
      presult="${parray2[$n]##*\/}"
      return 0
    }
    n+=1
  done
  return 1
}

main() {

  # positional parameter

  # script wide variables
  declare -r WIDGET_DIM='-1 -1'
  declare -r MENUWIDGET_DIM='-1 -1 -1'
  declare -r PROCESS_DELAY=3
  declare -r CRYPT_SUFFIX='_crypt'
  declare DISK_SYSTEM=''
  declare FLAG_INTELGPU='on'
  declare FLAG_NVIDIAGPU=''
  declare FLAG_DISK=''
  declare FLAG_ROOT=''
  declare FLAG_USR=''
  declare FLAG_LVM2=''
  declare FLAG_CRYPT=''
  declare FLAG_PLAIN='on'
  declare FLAG_ADMIN=''
  declare -a partitions_processed=()
  declare -a mountpoints_assigned=()
  declare -r openssl_passwd_algo='-6'   # see `openssl passwd -help`
  declare -a -r config_pacman_keyserver=(
    'hkp://keys.openpgp.org'
    'hkp://pgpkeys.eu'
    'hkp://pgp.surf.nl'
    'hkp://pgp.circ.lu'
    'hkp://pgp.surfnet.nl'
    'hkp://sks.pgpkeys.eu'
    'hkp://sks.pyro.eu.org'
    'hkp://pgp.uni-mainz.de'
    'hkp://keyserver.computer42.org'
    'hkp://keyserver.spline.inf.fu-berlin.de'
  )
  declare -r user_root='root'
  declare -r MiB_initial_wipe=25

  # default settings, customizable
  local -r   default_consolefont="eurlatgr"
  local -r default_consolekeymap="de"
  local -r -a    default_locales=( \
    "en_US.UTF-8 UTF-8" \
    "en_GB.UTF-8 UTF-8" \
    "es_ES.UTF-8 UTF-8" \
    "it_IT.UTF-8 UTF-8" \
    "fr_FR.UTF-8 UTF-8" \
    "pt_PT.UTF-8 UTF-8" \
    "pl_PL.UTF-8 UTF-8" \
    "de_DE.UTF-8 UTF-8" \
  )
  local -r      default_language="de_DE.utf8"
  local -r      default_timezone="Europe/Berlin"
  local -r      default_hostname="zerocat-parabola-machine"

  # local constants
  local -r           config_pacman="/etc/pacman.conf"
  local -r config_pacman_alternate="/etc/alt-pacman.conf"
  local -r       config_pacman_gpg="/etc/pacman.d/gnupg/gpg.conf"
  local -r       config_mkinitcpio="/mnt/etc/mkinitcpio.conf"
  local -r -a checklist_mkinitcpio=(
    1 "Write Configuration File"                      on
    2 "Refine Configuration File with GNU Nano"       off
    3 "Generate Initial Ramdisk"                      on
  )
  local -r -a menulist_mountpoint=(
    1 "/mnt/"
    2 "/mnt/boot"
    3 "/mnt/usr"
    4 "/mnt/usr/local"
    5 "/mnt/var"
    6 "/mnt/tmp"
    7 "/mnt/home"
    8 "[SWAP]"
    9 "[cryptSWAP]"   # specific to SystemD
  )
  local -r -a checklist_tweak=(
    1   "Key Strengthening"                                     on
    2   "Restrict Access to important Directories"              on
    3   "Lockout User after three failed Login Attempts"        off
  )
  local -r -a radiolist_DE=(
    1   "LXDE"      on
    2   "XFCE"      off
    3   "MATE"      off
  )
  local -r -a checklist_main=(
    1   "Live System: Disable nonsystemd Repository"                          on
    2   "Live System: Update Package Database"                                on
    3   "Live System: Select Drive, open Encryption, mount Partitions"        on
    4   "Install GNU System with User \`$user_root'"                          on
    5   "Configure GNU System, set Password for User \`$user_root'"           on
    6   "Apply extra Security Tweaks ..."                                     on
    7   "Install Desktop Environment ..."                                     on
    8   "Install Desktop Applications"                                        on
    9   "Create User Accounts"                                                on
    10  "Install Kernel with default Initial Ramdisk Image"                   on
    11  "Configure Kernel Console"                                            on
    12  "Reconfigure & Remake Initial Ramdisk Image ..."                      on
    13  "GRUB Bootloader Options ..."                                         on
    14  "Live System: Dismount Partitions, close Encryption, deselect Drive"  on
  )
  local -r -a packages_Base_OpenRC=(
    "base-openrc"
    "grep"
  )
  local -r -a packages_Base_SystemD=(
    "base"
  )
  local -r -a packages_Base_Common=(
    "sudo"
    "nano"
    "dialog"
    "man-db"
    "pcurses"
    "gvfs-mtp"
    "gphoto2"
    "pulseaudio-alsa"
    "alsa-utils"
  )
  local -r -a packages_Kernel=(
    "linux-libre"
  )
  local -r -a packages_GRUB=(
    "grub"
  )
  local -r -a packages_X=(
    "xorg-server"
    "xf86-input-evdev"
    "xf86-input-synaptics"
    "xf86-video-ati"
    "xf86-video-dummy"
    "xf86-video-fbdev"
    "xf86-video-intel"
    "xf86-video-nouveau"
    "xf86-video-openchrome"
    "xf86-video-sisusb"
    "xf86-video-vesa"
    "xf86-video-vmware"
    "xf86-video-voodoo"
    "xf86-video-qxl"
    "xorg-xinit"
    "xlockmore"
    "xterm"
  )
  # LXDE: xscreensaver has unresolved dependencies?
  # LXDE: xterm is required to launch alsamixer from panel icon
  local -r -a packages_LXDE=(
    "lxde"
    "leafpad"
    "xarchiver"
    "xscreensaver"
    "gnome-screenshot"
    "galculator-gtk2"
    "epdfview"
  )
  local -r -a packages_XFCE=(
    "xfce4"
    "xfce4-goodies"
    "pavucontrol"
    "galculator-gtk2"
    "epdfview"
  )
  local -r -a packages_MATE=(
    "mate"
    "mate-extra"
  )
  local -r -a packages_DE_Common=(
    "network-manager-applet"
    "xdg-user-dirs"
  )
  local -r -a packages_OpenRC=(
    "openrc-desktop"
    "polkit-elogind"
    "networkmanager-elogind"
  )
  local -r -a packages_SystemD=(
    "polkit"
    "networkmanager"
  )
  local -r -a packages_User=(
    "gparted"
    "abiword"
    "smplayer"
    "gnumeric"
    "iceweasel"
    "claws-mail"
    "jami-gnome"
  )

  # locals
  local init_modules='i915 nouveau '
  local hooks_standard='base udev autodetect keyboard keymap consolefont modconf block encrypt lvm2 filesystems fsck usr shutdown '
  local hooks_systemd='base systemd autodetect keyboard sd-vconsole modconf block sd-encrypt lvm2 filesystems fsck usr sd-shutdown '
  local init_system
  local option
  local feedback
  local feedback2
  local swapvol
  local cryptdev
  local uuid
  local i
  local x
  local -i n
  local -a radiolist_timezone=()
  local -a radiolist_consolefont=()
  local -a radiolist_consolekeymaps=()
  local -a checklist_grub=()
  local -a radiolist_GRUB=()

  # welcome
  welcome

  # reset init system
  cp "$config_pacman" "$config_pacman_alternate";
  init_system="openrc"

  # start main checklist
  option=$( \
    $DIALOG ${FLAGS_DIALOG[@]} \
      --cancel-label "Abort" \
      --checklist \
        "Parabola Installation Checklist" \
        ${MENUWIDGET_DIM} \
        "${checklist_main[@]}"; \
  )
  case $? in
    0)
      echo; echo;
      [ -n "$option" ] && {
        # process main checklist
        echo "Process Main Checklist ..."
        sleep $PROCESS_DELAY
        echo
        for i in $option; do
          echo "Starting job $i: “${checklist_main[$((i*3-2))]}” ..."
          sleep $PROCESS_DELAY
          case $i in
            1)    # Live System: disable nonsystemd repository
              # Edit /etc/pacman.conf such that repository nonsystemd is disabled:
              $SED -r \
                -e '/^\[nonsystemd\]/,+1s/^/#/;' \
                  "$config_pacman" > "$config_pacman_alternate";
              init_system="systemd"
              ;;
            2)    # Live System: update package database
              sync_keyrings || abort
              ;;
            3)    # Live System: select drive, format, mount partitions
              set_DISK_SYSTEM
              dismount_mountpoints
              close_encryption
              disk_operations
              ;;
            4)    # install GNU system with user root
              [ -n "$FLAG_DISK" -a -n "$FLAG_ROOT" ] && {
                # Install base system
                case "$init_system" in
                  'openrc')
                    pacstrap \
                      -C "$config_pacman_alternate" \
                        /mnt ${packages_Base_OpenRC[@]} || \
                          catch_error
                    ;;
                  'systemd')
                    pacstrap \
                      -C "$config_pacman_alternate" \
                        /mnt ${packages_Base_SystemD[@]} || \
                          catch_error
                    ;;
                esac
                install_packages "${packages_Base_Common[*]}"
              }
              ;;
            5)    # configure GNU system, set password for user root
              [ -n "$FLAG_DISK" -a -n "$FLAG_ROOT" ] && {

                # generate crypttab (SystemD)
                [ "${init_system,,}" == 'systemd' -a -n "$FLAG_CRYPT" ] && {
                  n=0; uuid='';
                  while [ ${n} -lt ${#partitions_processed[@]} ]; do
                    x="${partitions_processed[$n]##*/}"
                    case "${mountpoints_assigned[$n]}" in
                      '/')
                        ;;
                      '[SWAP]')
                        ;;
                      '[cryptSWAP]')
                        echo "${x%${CRYPT_SUFFIX}}${CRYPT_SUFFIX} /dev/${x%${CRYPT_SUFFIX}} /dev/urandom swap" >> /mnt/etc/crypttab
                        ;;
                      *)
                        uuid="UUID=$( \
                          lsblk -n -oUUID,PATH | \
                          egrep /dev/${x%${CRYPT_SUFFIX}} | \
                          cut -f1 -d' ' - \
                        )"
                        echo "${x} ${uuid}" >> /mnt/etc/crypttab
                        ;;
                    esac
                    n+=1
                  done
                }

                # generate fstab, set swapvol variable for GRUB
                genfstab \
                  -U \
                  -p /mnt \
                    >> /mnt/etc/fstab
                n=0; uuid=''; swapvol='';
                while [ ${n} -lt ${#partitions_processed[@]} ]; do
                  x="${partitions_processed[$n]##*/}"
                  case "${mountpoints_assigned[$n]}" in
                    '[SWAP]')
                      x="/dev/${x%${CRYPT_SUFFIX}}"
                      swapvol="${x}"
                      ;;
                    '[cryptSWAP]')
                      if [ "${init_system,,}" == 'systemd' -a -n "$FLAG_CRYPT" ]; then
                        x="/dev/mapper/${x%${CRYPT_SUFFIX}}${CRYPT_SUFFIX}"
                        echo "# ${x}" >> /mnt/etc/fstab
                        echo "${uuid:-${x}} none swap defaults 0 0" >> /mnt/etc/fstab
                        echo >> /mnt/etc/fstab
                      fi
                      ;;
                  esac
                  n+=1
                done

                # set hostname
                while [ true ]; do
                  feedback=$( \
                    $DIALOG ${FLAGS_DIALOG[@]} \
                      --cancel-label "Abort" \
                      --inputbox \
                        "Enter Hostname" \
                        ${WIDGET_DIM} \
                        "$default_hostname"
                  )
                  case $? in
                    0)
                      if [  -z "$feedback" -o \
                            -n "`echo $feedback | $SED -r -e '/.{254,}/!d;' -`" -o \
                            -n "`echo $feedback | $SED -r -e '/^[.-]|[.][-]|[-][.]|[.-]$|[^a-zA-Z0-9.-]/!d;' -`" \
                      ]; then
                        $DIALOG ${FLAGS_DIALOG[@]} \
                          --msgbox "Not a valid hostname!" ${WIDGET_DIM}
                      else
                        if [ "$init_system" == 'openrc' ]; then
                          set_hostname_OpenRC "$feedback"
                        else
                          set_hostname_SystemD "$feedback"
                        fi
                        break 1
                      fi
                      ;;
                    *)
                      echo; echo;
                      abort
                      ;;
                  esac
                done

                # collect available timezones
                radiolist_timezone=( \
                  $( \
                    find /mnt/usr/share/ -wholename '*zoneinfo/[^posixright/]*/[^/]*' -print | \
                    sed -r -e 's/(^.*\/)(.*\/)(.*)/\2\3 \3 off/;' - | \
                    sort - \
                  ) \
                )

                # set local time
                feedback=$( \
                  $DIALOG ${FLAGS_DIALOG[@]} \
                    --cancel-label "Abort" \
                    --radiolist \
                      "Select your Timezone\nDefaulting to: $default_timezone" \
                      ${MENUWIDGET_DIM}  \
                      "${radiolist_timezone[@]}" \
                )
                case $? in
                  0)
                    [ -z "$feedback" ] && {
                      $DIALOG ${FLAGS_DIALOG[@]} \
                        --msgbox "Timezone defaulting to: \`$default_timezone'" ${WIDGET_DIM}
                      feedback="$default_timezone"
                    }
                    set_localtime "$feedback"
                    ;;
                  *)
                    echo; echo;
                    abort
                    ;;
                esac

                # set hardware clock type
                echo "#!/bin/bash               " > /mnt/setHWClock.sh
                echo "hwclock --systohc --utc   " >> /mnt/setHWClock.sh
                chroot_exec "/mnt/setHWClock.sh" || catch_error

                # select locales and generate
                gen_locales "${default_locales[@]}"

                # select and set language
                set_language "$default_language"

                # set password for user root
                set_password "$openssl_passwd_algo" "$user_root"
              }
              ;;
            6)    # apply extra security tweaks
              [ -n "$FLAG_DISK" -a -n "$FLAG_ROOT" ] && {
                feedback=$( \
                  $DIALOG ${FLAGS_DIALOG[@]} \
                    --checklist "Select Security Tweaks" ${MENUWIDGET_DIM} "${checklist_tweak[@]}"
                )
                case $? in
                  0)
                    echo; echo;
                    [ -n "$feedback" ] && {
                      echo "Process Security Tweak checklist ..."
                      sleep $PROCESS_DELAY
                      echo
                      for x in $feedback; do
                        echo "Starting job $x: “${checklist_tweak[$((x*3-2))]}” ...";
                        sleep $PROCESS_DELAY
                        case $x in
                          1)    # key strengthening
                            $SED -r -i \
                              -e '/^password/s/$/ rounds=65536/;' \
                                /etc/pam.d/passwd
                            ;;
                          2)    # restrict access
                            chmod 700 \
                              /boot \
                              /etc/{iptables,arptables} \
                                &> /dev/null
                            ;;
                          3)    # lockout 10min
                            $SED -r -i \
                              -e '/^auth.*required.*pam\_tally.so/s/(^.*)(onerr=succeed.*$)/\1 deny=2 unlock\_time=600 \2/;' \
                                /etc/pam.d/system-login
                            ;;
                        esac
                        echo "... done with job $x: “${checklist_tweak[$((x*3-2))]}”"
                        hitenter || abort
                      done
                      echo "... Security Tweak Checklist processed."
                      hitenter || abort
                    }
                    ;;
                  *)
                    echo; echo;
                    abort
                    ;;
                esac
              }
              ;;
            7)    # install Desktop Environment
              [ -n "$FLAG_DISK" -a -n "$FLAG_ROOT" ] && {
                # install common packages
                install_packages "${packages_X[*]}"
                install_packages "${packages_DE_Common[*]}"
                if [ "$init_system" == 'openrc' ]; then
                  install_packages "${packages_OpenRC[*]}"
                else
                  install_packages "${packages_SystemD[*]}"
                fi

                # retrieve user input
                feedback=$( \
                  $DIALOG ${FLAGS_DIALOG[@]} \
                    --cancel-label "Abort" \
                    --radiolist "Select your Desktop Environment" ${MENUWIDGET_DIM} "${radiolist_DE[@]}"
                )
                case $? in
                  0)
                    echo; echo;
                    case $feedback in
                      1)
                        # install packages
                        install_packages "${packages_LXDE[*]}"

                        # setup configuration files to get X started
                        [ "$init_system" == 'openrc' ] && \
                          set_system_wallpaper
                        set_system_config "LXDE"
                        ;;
                      2)
                        # install packages
                        install_packages "${packages_XFCE[*]}"

                        # setup configuration files to get X started
                        set_system_config "XFCE"
                        ;;
                      3)
                        # install packages
                        install_packages "${packages_MATE[*]}"

                        # setup configuration files to get X started
                        set_system_config "MATE"
                        ;;
                    esac

                    # check for existing dbus user
                    check_dbus_user

                    # enable services
                    if [ "$init_system" == 'openrc' ]; then
                      enable_services_OpenRC
                    else
                      enable_services_SystemD
                    fi
                    ;;
                  *)
                    echo; echo;
                    abort
                    ;;
                esac
              }
              ;;
            8)    # install extra User Applications
              [ -n "$FLAG_DISK" -a -n "$FLAG_ROOT" ] && {
                # Install packages
                install_packages "${packages_User[*]}"
              }
              ;;
            9)    # create user accounts
              [ -n "$FLAG_DISK" -a -n "$FLAG_ROOT" ] && {
                # Add new users
                add_user_account "$openssl_passwd_algo"
              }
              ;;
            10)   # install kernel with default initial ramdisk image
              [ -n "$FLAG_DISK" -a -n "$FLAG_ROOT" ] && {
                # Install kernel
                install_packages "${packages_Kernel[*]}"
              }
              ;;
            11)   # configure kernel console
              [ -n "$FLAG_DISK" -a -n "$FLAG_ROOT" ] && {
                # collect available console fonts
                radiolist_consolefont=( \
                  $( \
                    find /mnt/usr/share/kbd/consolefonts -name '*.psf*.gz' -print | \
                    sed -r -e 's/(^.*\/)(.*)(\..*)(\..*$)/\2 \2 off/;' - | \
                    sort - \
                  ) \
                )

                # set console font
                feedback=$( \
                  $DIALOG ${FLAGS_DIALOG[@]} \
                    --cancel-label "Abort" \
                    --radiolist \
                      "Pick your Font for the Kernel Console\nDefaulting to: $default_consolefont" \
                      ${MENUWIDGET_DIM} \
                      "${radiolist_consolefont[@]:-${default_consolefont} ${default_consolefont} on}" \
                )
                case $? in
                  0)
                    [ -z "$feedback" ] && {
                      $DIALOG ${FLAGS_DIALOG[@]} \
                        --msgbox "Console font defaulting to: \`$default_consolefont'" ${WIDGET_DIM}
                      feedback="$default_consolefont"
                    }
                    echo "FONT=\"$feedback\"" > "/mnt/etc/vconsole.conf"
                    ;;
                  *)
                    echo; echo;
                    abort
                    ;;
                esac

                # collect available console keymaps
                radiolist_consolekeymaps=( \
                  $( \
                    find /mnt/usr/share/kbd/keymaps -name '*.map.gz' -print | \
                    sed -r -e 's/(^.*\/)(.*)(\.map\.gz)/\2 \2 off/;' - | \
                    sort - \
                  ) \
                )

                # set console keymap
                feedback=$( \
                  $DIALOG ${FLAGS_DIALOG[@]} \
                    --cancel-label "Abort" \
                    --radiolist \
                      "Pick your Keymap for the Kernel Console\nDefaulting to: $default_consolekeymap" \
                      ${MENUWIDGET_DIM} \
                      "${radiolist_consolekeymaps[@]:-${default_consolekeymap} ${default_consolekeymap} on}" \
                )
                case $? in
                  0)
                    [ -z "$feedback" ] && {
                      $DIALOG ${FLAGS_DIALOG[@]} \
                        --msgbox "Console keymap defaulting to: \`$default_consolekeymap'" ${WIDGET_DIM}
                      feedback="$default_consolekeymap"
                    }
                    echo "KEYMAP=\"$feedback\"" >> "/mnt/etc/vconsole.conf"
                    echo; echo;
                    ;;
                  *)
                    echo; echo;
                    abort
                    ;;
                esac
              }
              ;;
            12)   # reconfigure and remake initial ramdisk image
              [ -n "$FLAG_DISK" -a -n "$FLAG_ROOT" ] && {
                feedback=$( \
                  $DIALOG ${FLAGS_DIALOG[@]} \
                    --cancel-label "Abort" \
                    --checklist "Mkinitcpio Configuration Options" ${MENUWIDGET_DIM} "${checklist_mkinitcpio[@]}" \
                )
                case $? in
                  0)
                    echo; echo;
                    [ -n "$feedback" ] && {
                      echo "Process Mkinitcpio Configuration Checklist ..."
                      sleep $PROCESS_DELAY
                      echo
                      for x in $feedback; do
                        echo "Starting job $x: “${checklist_mkinitcpio[$((x*3-2))]}” ...";
                        sleep $PROCESS_DELAY
                        case $x in
                          1)
                            [ -z "$FLAG_INTELGPU" ] && {
                              init_modules="${init_modules/i915 /}"
                            }
                            [ -z "$FLAG_NVIDEAGPU" ] && {
                              init_modules="${init_modules/nouveau /}"
                            }
                            sed -r -i \
                              -e "/^MODULES=/s/^/#/;" \
                              -e "/^# BINARIES$/i# Modules suggested by install script – select and refine as required\n# standard:\nMODULES=(${init_modules})\n" \
                                "$config_mkinitcpio"
                            [ -z "$FLAG_USR" ] && {
                              hooks_standard="${hooks_standard/usr /}"
                              hooks_systemd="${hooks_systemd/usr /}"
                            }
                            [ -z "$FLAG_LVM2" ] && {
                              hooks_standard="${hooks_standard/lvm2 /}"
                              hooks_systemd="${hooks_systemd/lvm2 /}"
                            }
                            [ -z "$FLAG_CRYPT" ] && {
                              hooks_standard="${hooks_standard/encrypt /}"
                              hooks_systemd="${hooks_systemd/sd-encrypt /}"
                            }
                            [ -z "$FLAG_CRYPT" -a -z "FLAG_USR" ] && {
                              hooks_standard="${hooks_standard/shutdown /}"
                              hooks_systemd="${hooks_systemd/sd-shutdown /}"
                            }
                            sed -r -i \
                              -e "/^HOOKS=/s/^/#/;" \
                              -e "/^# COMPRESSION$/i# Hooks suggested by install script – select and refine as required\n# standard:\nHOOKS=(${hooks_standard})\n# systemd:\n#HOOKS=(${hooks_systemd})\n" \
                                "$config_mkinitcpio"
                            ;;
                          2)
                            $DIALOG ${FLAGS_DIALOG[@]} \
                              --msgbox "\
Now edit the Initial Ramdisk Configuration File ...\n\
\n\
e.g. remove modules if not required:\n\
· i915        – Intel Graphics\n\
· nouveau     – nVIDEA Graphics\n\
\n\
e.g. remove hooks if not required:\n\
· keymap      – add console keymap to ramdisk image\n\
· consolefont – add console font to ramdisk image\n\
· encrypt     – support encrypted root device\n\
· usr         – support /usr and /usr/local on separate partitions\n\
· shutdown    – add dismount capabilities for usr and encrypt hook\n" ${WIDGET_DIM};
                            echo; echo;

                            # customize /mnt/etc/mkinitcpio.conf
                            #   e.g.: adjust MODULES and HOOKS as described in libreboot how-to:
                            #   https://libreboot.org/docs/gnulinux/encrypted_parabola.html#install-the-base-system
                            cp --backup=numbered "$config_mkinitcpio" "$config_mkinitcpio".bak
                            nano "$config_mkinitcpio"
                            ;;
                          3)
                            # make initramfs
                            make_initramfs
                            ;;
                        esac
                        echo "... done with job $x: “${checklist_mkinitcpio[$((x*3-2))]}”"
                        hitenter || abort
                      done
                      echo "... Mkinitcpio Configuration Checklist processed."
                      hitenter || abort
                    }
                    ;;
                  *)
                    echo; echo;
                    abort
                    ;;
                esac
              }
              ;;
            13)   # GRUB bootloader options
              [ -n "$FLAG_DISK" -a -n "$FLAG_ROOT" ] && {
                checklist_grub=(
                  1 "Install GRUB Package"                                      on
                  2 "Install GRUB Bootloader${DISK_SYSTEM:+ on $DISK_SYSTEM}"   off
                  3 "Generate GRUB Configuration File ..."                      on
                )
                feedback=$( \
                  $DIALOG ${FLAGS_DIALOG[@]} \
                    --cancel-label "Abort" \
                    --checklist \
                      "GRUB Bootloader Options" \
                      ${MENUWIDGET_DIM} \
                      "${checklist_grub[@]}"; \
                )
                case $? in
                  0)
                    echo; echo;
                    [ -n "$feedback" ] && {
                      echo "Process GRUB Checklist ..."
                      sleep $PROCESS_DELAY
                      echo
                      for x in $feedback; do
                        echo "Starting job $x: “${checklist_grub[$((x*3-2))]}” ...";
                        sleep $PROCESS_DELAY
                        case $x in
                          1)
                            install_packages "${packages_GRUB[*]}"
                            ;;
                          2)
                            echo "#!/bin/bash                                                               " >  /mnt/grubInstall.sh
                            echo "                                                                          " >> /mnt/grubInstall.sh
                            echo "notool() {                                                                " >> /mnt/grubInstall.sh
                            echo "  local -r tool=\"\$1\"                                                   " >> /mnt/grubInstall.sh
                            echo "  echo \"Missing tool in chroot environment: \$tool\"                     " >> /mnt/grubInstall.sh
                            echo "  exit 1                                                                  " >> /mnt/grubInstall.sh
                            echo "}                                                                         " >> /mnt/grubInstall.sh
                            echo "                                                                          " >> /mnt/grubInstall.sh
                            echo "# tool check                                                              " >> /mnt/grubInstall.sh
                            echo "[ -z \"\$(command -v grub-install)\" ] && notool 'grub-install'           " >> /mnt/grubInstall.sh
                            echo "                                                                          " >> /mnt/grubInstall.sh
                            echo "grub-install ${DISK_SYSTEM}                                               " >> /mnt/grubInstall.sh
                            chroot_exec "/mnt/grubInstall.sh" || abort
                            ;;
                          3)
                            radiolist_GRUB=(
                              1 "Generate GRUB Standard Configuration"           "${FLAG_PLAIN:-off}"
                              2 "Generate GRUB Configuration, Encrypted Disks"   "${FLAG_CRYPT:-off}"
                            )
                            feedback2=$( \
                              $DIALOG ${FLAGS_DIALOG[@]} \
                                --cancel-label "Abort" \
                                --radiolist "Type of GRUB Configuration File" ${MENUWIDGET_DIM} "${radiolist_GRUB[@]}"
                            )
                            case $? in
                              0)
                                echo; echo;
                                case $feedback2 in
                                  1)
                                    echo "#!/bin/bash                                                                                 " >  /mnt/grubConfig.sh
                                    echo "                                                                                            " >> /mnt/grubConfig.sh
                                    echo "notool() {                                                                                  " >> /mnt/grubConfig.sh
                                    echo "  local -r tool=\"\$1\"                                                                     " >> /mnt/grubConfig.sh
                                    echo "  echo \"Missing tool in chroot environment: \$tool\"                                       " >> /mnt/grubConfig.sh
                                    echo "  exit 1                                                                                    " >> /mnt/grubConfig.sh
                                    echo "}                                                                                           " >> /mnt/grubConfig.sh
                                    echo "                                                                                            " >> /mnt/grubConfig.sh
                                    echo "# tool check                                                                                " >> /mnt/grubConfig.sh
                                    echo "[ -z \"\$(command -v cp)\" ] && notool 'cp'                                                 " >> /mnt/grubConfig.sh
                                    echo "[ -z \"\$(command -v mv)\" ] && notool 'mv'                                                 " >> /mnt/grubConfig.sh
                                    echo "[ -z \"\$(command -v sed)\" ] && notool 'sed'                                               " >> /mnt/grubConfig.sh
                                    echo "[ -z \"\$(command -v mkdir)\" ] && notool 'mkdir'                                           " >> /mnt/grubConfig.sh
                                    echo "[ -z \"\$(command -v grub-mkconfig)\" ] && notool 'grub-mkconfig'                           " >> /mnt/grubConfig.sh
                                    echo "                                                                                            " >> /mnt/grubConfig.sh
                                    echo "cp /etc/default/grub /etc/default/grub.bak                                                  " >> /mnt/grubConfig.sh
                                    echo "mkdir -p /boot/grub                                                                         " >> /mnt/grubConfig.sh
                                    echo "sed -r -i                                                                                 \\" >> /mnt/grubConfig.sh
                                    echo "  -e \"/GRUB_CMDLINE_LINUX=/cGRUB_CMDLINE_LINUX=\\\"${swapvol:+resume=${swapvol}}\\\"\"   \\" >> /mnt/grubConfig.sh
                                    echo "    /etc/default/grub                                                                       " >> /mnt/grubConfig.sh
                                    echo "sed -r -i                                                                                 \\" >> /mnt/grubConfig.sh
                                    echo "  -e \"/GRUB_ENABLE_CRYPTODISK/s/^/#/;\"                                                  \\" >> /mnt/grubConfig.sh
                                    echo "    /etc/default/grub                                                                       " >> /mnt/grubConfig.sh
                                    echo "grub-mkconfig -o /boot/grub/grub.cfg                                                        " >> /mnt/grubConfig.sh
                                    echo "mv /etc/default/grub.bak /etc/default/grub                                                  " >> /mnt/grubConfig.sh
                                    chroot_exec "/mnt/grubConfig.sh" || abort
                                    ;;
                                  2)
                                    get_device '/mnt/' mountpoints_assigned partitions_processed cryptdev
                                    echo "#!/bin/bash                                                                                                                         " >  /mnt/grubConfig.sh
                                    echo "                                                                                                                                    " >> /mnt/grubConfig.sh
                                    echo "notool() {                                                                                                                          " >> /mnt/grubConfig.sh
                                    echo "  local -r tool=\"\$1\"                                                                                                             " >> /mnt/grubConfig.sh
                                    echo "  echo \"Missing tool in chroot environment: \$tool\"                                                                               " >> /mnt/grubConfig.sh
                                    echo "  exit 1                                                                                                                            " >> /mnt/grubConfig.sh
                                    echo "}                                                                                                                                   " >> /mnt/grubConfig.sh
                                    echo "                                                                                                                                    " >> /mnt/grubConfig.sh
                                    echo "# tool check                                                                                                                        " >> /mnt/grubConfig.sh
                                    echo "[ -z \"\$(command -v cp)\" ] && notool 'cp'                                                                                         " >> /mnt/grubConfig.sh
                                    echo "[ -z \"\$(command -v mv)\" ] && notool 'mv'                                                                                         " >> /mnt/grubConfig.sh
                                    echo "[ -z \"\$(command -v sed)\" ] && notool 'sed'                                                                                       " >> /mnt/grubConfig.sh
                                    echo "[ -z \"\$(command -v mkdir)\" ] && notool 'mkdir'                                                                                   " >> /mnt/grubConfig.sh
                                    echo "[ -z \"\$(command -v grub-mkconfig)\" ] && notool 'grub-mkconfig'                                                                   " >> /mnt/grubConfig.sh
                                    echo "                                                                                                                                    " >> /mnt/grubConfig.sh
                                    echo "cp /etc/default/grub /etc/default/grub.bak                                                                                          " >> /mnt/grubConfig.sh
                                    echo "mkdir -p /boot/grub                                                                                                                 " >> /mnt/grubConfig.sh
                                    echo "sed -r -i                                                                                                                         \\" >> /mnt/grubConfig.sh
                                    echo "  -e \"/GRUB_CMDLINE_LINUX=/cGRUB_CMDLINE_LINUX=\\\"cryptdevice=/dev/${cryptdev%${CRYPT_SUFFIX}}\:${cryptdev} hibernate=no\\\"\"  \\" >> /mnt/grubConfig.sh
                                    echo "    /etc/default/grub                                                                                                               " >> /mnt/grubConfig.sh
                                    echo "sed -r -i -e \"/GRUB_ENABLE_CRYPTODISK/s/^#//;\" /etc/default/grub                                                                  " >> /mnt/grubConfig.sh
                                    echo "grub-mkconfig -o /boot/grub/grub.cfg                                                                                                " >> /mnt/grubConfig.sh
                                    echo "mv /etc/default/grub.bak /etc/default/grub                                                                                          " >> /mnt/grubConfig.sh
                                    chroot_exec "/mnt/grubConfig.sh" || abort
                                    ;;
                                esac
                                ;;
                              *)
                                echo; echo;
                                abort
                                ;;
                            esac
                            ;;
                        esac
                        echo "... done with job $x: “${checklist_grub[$((x*3-2))]}”"
                        hitenter || abort
                      done
                      echo "... GRUB Checklist processed."
                      hitenter || abort
                    }
                    ;;
                  *)
                    echo; echo;
                    abort
                    ;;
                esac
              }
              ;;
            14)   # Live System: dismount partitions, close encryption
              dismount_mountpoints
              close_encryption
              unset_DISK_SYSTEM
              ;;
          esac
          echo "... done with job $i: “${checklist_main[$((i*3-2))]}”"
          hitenter || abort
        done
        echo "... Main Checklist processed."
        echo "Good Luck!"
        echo
      }
      ;;
    *)
      echo; echo;
      abort
      ;;
  esac
}

# check tools
declare -r SED=$(command -v sed);        [ -z "$SED" ] && notool 'sed';
declare -r DIALOG=$(command -v dialog);  [ -z "$DIALOG" ] && notool 'dialog';

# globals
declare -r -a FLAGS_DIALOG=("--stdout" "--no-shadow" "--title Parabola-Setup")

# start
fillscreen
checkperm
main "$@"
