1058 lines
29 KiB
Bash
Executable File
1058 lines
29 KiB
Bash
Executable File
#!/bin/bash
|
|
set -uo pipefail
|
|
|
|
|
|
################################################
|
|
# Initialize script environment
|
|
|
|
# Find the directory this script is stored in. (from: http://stackoverflow.com/questions/59895)
|
|
function get_source_dir() {
|
|
local source="${BASH_SOURCE[0]}"
|
|
while [[ -h $source ]]
|
|
do
|
|
local tmp
|
|
tmp="$(cd -P "$(dirname "${source}")" && pwd)"
|
|
source="$(readlink "${source}")"
|
|
[[ $source != /* ]] && source="${tmp}/${source}"
|
|
done
|
|
|
|
echo -n "$(realpath "$(dirname "${source}")")"
|
|
}
|
|
|
|
GENTOO_INSTALL_REPO_DIR="$(get_source_dir)"
|
|
export GENTOO_INSTALL_REPO_DIR
|
|
export GENTOO_INSTALL_REPO_SCRIPT_ACTIVE=true
|
|
|
|
source "$GENTOO_INSTALL_REPO_DIR/scripts/utils.sh"
|
|
|
|
# Remember actual config file path
|
|
CONFIG_FILE="$(realpath "${1-"gentoo.conf"}" 2>/dev/null)"
|
|
RELA_CONFIG_FILE="$(realpath --relative-to="$(pwd)" "$CONFIG_FILE" 2>/dev/null)"
|
|
|
|
# Check if help is requested
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
""|"help"|"--help"|"-help"|"-h")
|
|
echo "Usage: $0 [config]"
|
|
echo "Starts the gentoo configurator. If no file is given, it defaults to 'gentoo.conf'."
|
|
echo "If the file doesn't exist, the configurator loads default values, otherwise, the"
|
|
echo "the configuration is loaded into the configurator."
|
|
exit 0
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# TODO check install dialog
|
|
echo "Please install dialog on your system to use the configurator"
|
|
|
|
# Wrap dialog in two functions to prevent it from cluttering stderr.
|
|
function dialog_wrapper() { dialog_out=$(command dialog "$@" 3>&2 2>&1 1>&3 3>&-); }
|
|
function dialog() { dialog_wrapper "$@" 2>&1; }
|
|
|
|
|
|
################################################
|
|
# Configuration helper functions
|
|
|
|
function get_timezone() {
|
|
local file
|
|
if file="$(readlink /etc/localtime)"; then
|
|
# /etc/localtime is a symlink as expected
|
|
local timezone
|
|
timezone=${file#*zoneinfo/}
|
|
if [[ $timezone = "$file" || ! $timezone =~ ^[^/]+/[^/]+$ ]]; then
|
|
# not pointing to expected location or not Region/City
|
|
echo "Europe/London"
|
|
fi
|
|
echo "$timezone"
|
|
else
|
|
# compare files by contents
|
|
find /usr/share/zoneinfo -type f -exec cmp -s {} /etc/localtime \; -print \
|
|
| sed -e 's,.*/zoneinfo/,,' \
|
|
| head -1
|
|
fi
|
|
}
|
|
|
|
function get_default_keymap() {
|
|
local keymap
|
|
keymap="$(grep KEYMAP /etc/vconsole.conf)"
|
|
keymap="${keymap#KEYMAP=}"
|
|
|
|
local map
|
|
for map in "${ALL_KEYMAPS[@]}"; do
|
|
if [[ $map == "$keymap" ]]; then
|
|
echo -n "${keymap}"
|
|
return
|
|
fi
|
|
done
|
|
|
|
# Fallback to us
|
|
echo -n "us"
|
|
}
|
|
|
|
function get_all_keymaps() {
|
|
ALL_KEYMAPS=()
|
|
local map
|
|
for map in $(find /usr/share/keymaps/ /usr/share/kbd/keymaps/ -type f -iname '*.map.gz' -printf "%f\n" 2>/dev/null | sort -u); do
|
|
ALL_KEYMAPS+=("${map%%.map.gz}")
|
|
done
|
|
}
|
|
|
|
function get_all_timezones() {
|
|
readarray -t ALL_TIMEZONES < <(find /usr/share/zoneinfo -type f -printf "%P\n" | sort -u)
|
|
}
|
|
|
|
function recalculate_locales() {
|
|
LOCALES=""
|
|
N_LOCALES=0
|
|
|
|
local selected_index_list="$SELECTED_LOCALES"
|
|
local next_selected
|
|
next_selected="${selected_index_list%% *}"
|
|
selected_index_list="${selected_index_list#* }"
|
|
|
|
local i=0
|
|
for item in "${SUPPORTED_LOCALES[@]}"; do
|
|
if [[ "$i" == "$next_selected" ]]; then
|
|
LOCALES="$LOCALES"$'\n'"$item"
|
|
next_selected="${selected_index_list%% *}"
|
|
selected_index_list="${selected_index_list#* }"
|
|
((++N_LOCALES))
|
|
fi
|
|
((++i))
|
|
done
|
|
|
|
LOCALES="${LOCALES:1}"
|
|
}
|
|
|
|
function define_disk_layout() {
|
|
# Show function declaration, trim trailing whitespace
|
|
declare -f disk_configuration \
|
|
| sed -e 's/\s*$//'
|
|
}
|
|
|
|
ALL_PARTITIONING_SCHEMES=(
|
|
"classic_single_disk" "Classic single disk layout (boot, swap, root)"
|
|
"zfs_centric" "ZFS centric (optional raid0/1 and encryption via zfs)"
|
|
"btrfs_centric" "Btrfs centric (optional raid0/1 via btrfs)"
|
|
"raid0_luks" "Raid0 (N>=2 disks) and luks for root"
|
|
"custom" "Custom (edit the config manually later)"
|
|
)
|
|
|
|
PARTITIONING_ROOT_FS_TYPES=("ext4" "btrfs")
|
|
PARTITIONING_RAID_TYPES=("raid0" "raid1")
|
|
PARTITIONING_ZFS_POOL_TYPES=("stripe" "mirror")
|
|
|
|
function create_single_disk_layout() {
|
|
create_classic_single_disk_layout
|
|
}
|
|
|
|
function parse_swap() {
|
|
if [[ $1 == "false" ]]; then
|
|
PARTITIONING_USE_SWAP=false
|
|
PARTITIONING_SWAP=0
|
|
else
|
|
PARTITIONING_USE_SWAP=true
|
|
PARTITIONING_SWAP="$1"
|
|
fi
|
|
}
|
|
|
|
function create_classic_single_disk_layout() {
|
|
PARTITIONING_SCHEME="classic_single_disk"
|
|
|
|
local known_arguments=('+swap' '?type' '?luks' '?root_fs')
|
|
local extra_arguments=()
|
|
declare -A arguments; parse_arguments "$@"
|
|
|
|
PARTITIONING_DEVICE="${extra_arguments[0]}"
|
|
parse_swap "${arguments[swap]}"
|
|
PARTITIONING_BOOT_TYPE="${arguments[type]}"
|
|
PARTITIONING_USE_LUKS="${arguments[luks]:-false}"
|
|
PARTITIONING_ROOT_FS="${arguments[root_fs]:-ext4}"
|
|
}
|
|
|
|
function create_raid0_luks_layout() {
|
|
PARTITIONING_SCHEME="classic_single_disk"
|
|
|
|
local known_arguments=('+swap' '?type' '?root_fs')
|
|
local extra_arguments=()
|
|
declare -A arguments; parse_arguments "$@"
|
|
|
|
PARTITIONING_DEVICES=("${extra_arguments[@]}")
|
|
parse_swap "${arguments[swap]}"
|
|
PARTITIONING_BOOT_TYPE="${arguments[type]}"
|
|
PARTITIONING_ROOT_FS="${arguments[root_fs]:-ext4}"
|
|
}
|
|
|
|
function create_zfs_centric_layout() {
|
|
PARTITIONING_SCHEME="zfs_centric"
|
|
|
|
local known_arguments=('+swap' '?type' '?pool_type' '?encrypt')
|
|
local extra_arguments=()
|
|
declare -A arguments; parse_arguments "$@"
|
|
|
|
PARTITIONING_DEVICES=("${extra_arguments[@]}")
|
|
parse_swap "${arguments[swap]}"
|
|
PARTITIONING_BOOT_TYPE="${arguments[type]}"
|
|
PARTITIONING_ZFS_POOL_TYPE="${arguments[pool_type]:-stripe}"
|
|
PARTITIONING_ZFS_ENCRYPTION="${arguments[encrypt]:-false}"
|
|
}
|
|
|
|
function create_btrfs_raid_layout() {
|
|
create_btrfs_centric_layout
|
|
}
|
|
|
|
function create_btrfs_centric_layout() {
|
|
PARTITIONING_SCHEME="btrfs_centric"
|
|
|
|
local known_arguments=('+swap' '?type' '?raid_type' '?luks')
|
|
local extra_arguments=()
|
|
declare -A arguments; parse_arguments "$@"
|
|
|
|
PARTITIONING_DEVICES=("${extra_arguments[@]}")
|
|
parse_swap "${arguments[swap]}"
|
|
PARTITIONING_BOOT_TYPE="${arguments[type]}"
|
|
PARTITIONING_USE_LUKS="${arguments[luks]:-false}"
|
|
PARTITIONING_RAID_TYPE="${arguments[raid_type]:-raid0}"
|
|
}
|
|
|
|
|
|
################################################
|
|
# Configuration constants
|
|
|
|
get_all_keymaps
|
|
get_all_timezones
|
|
INIT_SYSTEMS=("systemd" "OpenRC")
|
|
ALL_GENTOO_ARCHS=("x86" "amd64" "arm" "arm64")
|
|
readarray -t SUPPORTED_LOCALES < /usr/share/i18n/SUPPORTED
|
|
readarray -t LOCALE_A < <(locale -a)
|
|
|
|
|
|
################################################
|
|
# Load/Default configuration
|
|
|
|
function load_selected_locales() {
|
|
local sel_locales=()
|
|
local IFS=$'\n'
|
|
declare -A selected_by_name
|
|
for i in $LOCALES; do
|
|
selected_by_name["$i"]=true
|
|
done
|
|
|
|
local i=0
|
|
for item in "${SUPPORTED_LOCALES[@]}"; do
|
|
[[ "${selected_by_name[$item]:-}" == true ]] \
|
|
&& sel_locales+=("$i")
|
|
((++i))
|
|
done
|
|
|
|
SELECTED_LOCALES="${sel_locales[*]}"
|
|
}
|
|
|
|
function process_config() {
|
|
disk_configuration
|
|
|
|
if [[ "$SYSTEMD" == true ]]; then
|
|
INIT_SYSTEM="systemd"
|
|
else
|
|
INIT_SYSTEM="OpenRC"
|
|
fi
|
|
|
|
if [[ "$KEYMAP" == "$KEYMAP_INITRAMFS" ]]; then
|
|
KEYMAP_INITRAMFS_OTHER=false
|
|
else
|
|
KEYMAP_INITRAMFS_OTHER=true
|
|
fi
|
|
|
|
load_selected_locales
|
|
recalculate_locales
|
|
}
|
|
|
|
function load_config() {
|
|
# First load defaults, then replace by sourcing config.
|
|
load_default_config
|
|
|
|
# Fallback to custom partitioning scheme if it isn't set in the actual config
|
|
PARTITIONING_SCHEME="custom"
|
|
|
|
# Load settings
|
|
source "$1" || die "Could not load given configuration."
|
|
|
|
# After loading a config no unsaved changes exist.
|
|
UNSAVED_CHANGES=false
|
|
}
|
|
|
|
function load_default_config() {
|
|
HOSTNAME="gentoo"
|
|
TIMEZONE="$(get_timezone)"
|
|
KEYMAP="$(get_default_keymap)"
|
|
KEYMAP_INITRAMFS="$KEYMAP"
|
|
LOCALES="C.UTF-8 UTF-8"
|
|
LOCALE="C.utf8"
|
|
|
|
function disk_configuration() {
|
|
create_zfs_centric_layout swap=8GiB type=efi encrypt=true pool_type=stripe /dev/sdX
|
|
}
|
|
|
|
SYSTEMD=true
|
|
|
|
GENTOO_MIRROR="https://mirror.eu.oneandone.net/linux/distributions/gentoo/gentoo"
|
|
GENTOO_ARCH="amd64"
|
|
|
|
SELECT_MIRRORS=true
|
|
SELECT_MIRRORS_LARGE_FILE=false
|
|
|
|
ADDITIONAL_PACKAGES=()
|
|
INSTALL_SSHD=true
|
|
ROOT_SSH_AUTHORIZED_KEYS=""
|
|
|
|
# All settings are unsaved.
|
|
UNSAVED_CHANGES=true
|
|
}
|
|
|
|
SAVE_AS_FILENAME="$RELA_CONFIG_FILE"
|
|
if [[ -e "$CONFIG_FILE" ]]; then
|
|
load_config "$CONFIG_FILE"
|
|
else
|
|
load_default_config
|
|
fi
|
|
process_config
|
|
|
|
|
|
################################################
|
|
# Menu helpers and constants
|
|
|
|
# $1: exit code
|
|
function clear_and_exit() {
|
|
dialog --clear
|
|
clear -x
|
|
exit "$1"
|
|
}
|
|
|
|
function ellipsis() {
|
|
local len="$1"
|
|
shift
|
|
local str="$*"
|
|
if [[ "${#str}" -gt "$len" ]]; then
|
|
echo "${str:0:$len}…"
|
|
else
|
|
echo "$str"
|
|
fi
|
|
}
|
|
|
|
function on_off_toggle() {
|
|
if [[ "${!1}" == true ]]; then
|
|
declare -g "$1"=false
|
|
else
|
|
declare -g "$1"=true
|
|
fi
|
|
}
|
|
|
|
function on_off_str() {
|
|
if [[ "$1" == true ]]; then
|
|
echo -n "$2"
|
|
else
|
|
echo -n "$3"
|
|
fi
|
|
}
|
|
|
|
function on_off_label() {
|
|
local prefix="${2:-}"
|
|
on_off_str "$1" "${prefix}[*]" "${prefix}[ ]"
|
|
}
|
|
|
|
function is_on() {
|
|
[[ "$1" == true ]]
|
|
}
|
|
|
|
function is_off() {
|
|
[[ "$1" != true ]]
|
|
}
|
|
|
|
# if $1 is in $2..
|
|
function one_of() {
|
|
local what="$1"
|
|
shift
|
|
for i in "$@"; do
|
|
[[ "$i" == "$what" ]] \
|
|
&& return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# $1: title
|
|
# $2: description
|
|
# $3: space separated index list of selected items (e.g. "0 1 5 6")
|
|
# $@: all items
|
|
function menu_splitlist() {
|
|
local title="$1"
|
|
local description="$2"
|
|
local selected_index_list="$3"
|
|
shift 3
|
|
|
|
# Build option array
|
|
local items=()
|
|
local item
|
|
local i=0
|
|
local next_selected="${selected_index_list%% *}"
|
|
local selected_index_list="${selected_index_list#* }"
|
|
for item in "$@"; do
|
|
if [[ "$i" == "$next_selected" ]]; then
|
|
items+=("$i" "$item" "on")
|
|
next_selected="${selected_index_list%% *}"
|
|
selected_index_list="${selected_index_list#* }"
|
|
else
|
|
items+=("$i" "$item" "off")
|
|
fi
|
|
((++i))
|
|
done
|
|
|
|
# Show selection dialog
|
|
dialog \
|
|
--title "$title" \
|
|
--buildlist "$description\nUse ^ to focus the list of unselected items and $ to focus the list of selected items. Use <Space> to select/deselect an item and select <OK> by pressing <Enter> when finished." \
|
|
"${BUILDLIST_SIZE[@]}" "${items[@]}"
|
|
|
|
local diag_exit=$?
|
|
if [[ $diag_exit == 0 ]]; then
|
|
# <OK>
|
|
return 0
|
|
elif [[ $diag_exit == 1 ]]; then
|
|
# <Cancel>
|
|
return 1
|
|
else
|
|
# <ESC><ESC>
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# $1: title
|
|
# $2: description
|
|
# $3: default item
|
|
# $@: [tag label]...
|
|
function menu_radiolist_labeled() {
|
|
local title="$1"
|
|
local description="$2"
|
|
local default_item="$3"
|
|
shift 3
|
|
|
|
# Build option array
|
|
local items=()
|
|
local tag
|
|
local label
|
|
while [[ "$#" -gt 0 ]]; do
|
|
tag="$1"
|
|
label="$2"
|
|
shift 2
|
|
|
|
if [[ $tag == "$default_item" ]]; then
|
|
items+=("$tag" "$label" "on")
|
|
else
|
|
items+=("$tag" "$label" "off")
|
|
fi
|
|
done
|
|
|
|
# Show selection dialog
|
|
dialog \
|
|
--no-tags \
|
|
--title "$title" \
|
|
--help-button \
|
|
--help-label "Select" \
|
|
--help-status \
|
|
--ok-label "OK" \
|
|
--default-item "$default_item" \
|
|
--default-button help \
|
|
--radiolist "$description\nUse <Select> to select the option under the cursor, or <OK> to use the option which is selected with an asterisk." \
|
|
"${RADIOLIST_SIZE[@]}" "${items[@]}"
|
|
|
|
local diag_exit=$?
|
|
if [[ $diag_exit == 0 ]]; then
|
|
# <OK>
|
|
return 0
|
|
elif [[ $diag_exit == 1 ]]; then
|
|
# <Cancel>
|
|
return 1
|
|
elif [[ $diag_exit == 2 ]]; then
|
|
# <Select>
|
|
local sel="${dialog_out#HELP }"
|
|
local sel_cur="${sel% *}"
|
|
#local sel_radio="${sel#* }"
|
|
dialog_out="$sel_cur"
|
|
return 0
|
|
else
|
|
# <ESC><ESC>
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# $1: title
|
|
# $2: description
|
|
# $3: default item
|
|
# $@: items
|
|
function menu_radiolist() {
|
|
local title="$1"
|
|
local description="$2"
|
|
local default_item="$3"
|
|
shift 3
|
|
|
|
# Build option array
|
|
local items=()
|
|
local item
|
|
for item in "$@"; do
|
|
if [[ $item == "$default_item" ]]; then
|
|
items+=("$item" "on")
|
|
else
|
|
items+=("$item" "off")
|
|
fi
|
|
done
|
|
|
|
# Show selection dialog
|
|
dialog \
|
|
--no-items \
|
|
--title "$title" \
|
|
--help-button \
|
|
--help-label "Select" \
|
|
--help-status \
|
|
--ok-label "OK" \
|
|
--default-item "$default_item" \
|
|
--default-button help \
|
|
--radiolist "$description\nUse <Select> to select the option under the cursor, or <OK> to use the option which is selected with an asterisk." \
|
|
"${RADIOLIST_SIZE[@]}" "${items[@]}"
|
|
|
|
local diag_exit="$?"
|
|
if [[ $diag_exit == 0 ]]; then
|
|
# <OK>
|
|
return 0
|
|
elif [[ $diag_exit == 1 ]]; then
|
|
# <Cancel>
|
|
return 1
|
|
elif [[ $diag_exit == 2 ]]; then
|
|
# <Select>
|
|
local sel="${dialog_out#HELP }"
|
|
local sel_cur="${sel% *}"
|
|
#local sel_radio="${sel#* }"
|
|
dialog_out="$sel_cur"
|
|
return 0
|
|
else
|
|
# <ESC><ESC>
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function msgbox_help() {
|
|
dialog --msgbox "$1" "${HELP_POPUP_SIZE[@]}"
|
|
}
|
|
|
|
function menu_exit() {
|
|
if [[ $UNSAVED_CHANGES == "true" ]]; then
|
|
dialog \
|
|
--help-button --help-label "Back" \
|
|
--yes-label "Save" --no-label "Discard" \
|
|
--yesno "Do you want to save your configuration?\n(Press <ESC><ESC>, or choose <Back> to continue gentoo configuration)." \
|
|
"${CONFIRM_SIZE[@]}"
|
|
|
|
local diag_exit="$?"
|
|
if [[ $diag_exit == 0 ]]; then
|
|
# <Save>
|
|
save "$CONFIG_FILE"
|
|
clear_and_exit 0
|
|
elif [[ $diag_exit == 1 ]]; then
|
|
# <Discard>
|
|
clear_and_exit 0
|
|
else
|
|
# Back to menu (<ESC><ESC>, <Back>)
|
|
true
|
|
fi
|
|
else
|
|
# Nothing was changed. Exit immediately.
|
|
clear_and_exit 0
|
|
fi
|
|
}
|
|
|
|
function menu_save_as() {
|
|
dialog \
|
|
--ok-label "Save" \
|
|
--inputbox "Enter a filename to which this configuration should be saved.\n(Press <ESC><ESC>, or choose <Cancel> to abort)." \
|
|
"${INPUTBOX_SIZE[@]}" "$SAVE_AS_FILENAME"
|
|
|
|
local diag_exit="$?"
|
|
if [[ $diag_exit == 0 ]]; then
|
|
# <Save>
|
|
SAVE_AS_FILENAME="$dialog_out"
|
|
save "$SAVE_AS_FILENAME"
|
|
UNSAVED_CHANGES=false
|
|
else
|
|
# Back to menu (<ESC><ESC>, <Cancel>)
|
|
true
|
|
fi
|
|
}
|
|
|
|
function menu() {
|
|
local item
|
|
local item_tag
|
|
local tag_item_list=()
|
|
declare -A reverse_lookup
|
|
|
|
# Create menu list
|
|
for item in "${MENU_ITEMS[@]}"; do
|
|
# Only if item is visible
|
|
"${item}_show" || continue
|
|
|
|
item_tag="$("${item}_tag")"
|
|
tag_item_list+=("$item_tag" "$("${item}_label")")
|
|
reverse_lookup["$item_tag"]="$item"
|
|
done
|
|
|
|
dialog --colors \
|
|
--title "Gentoo configuration ($RELA_CONFIG_FILE)" \
|
|
--extra-button --extra-label "Exit" \
|
|
--help-button \
|
|
--default-item "$SELECTED_MENU_ITEM" \
|
|
--ok-label "Select" --cancel-label "Save" \
|
|
--menu "This is the gentoo configuration menu. Read and adjust all options below carefully. Save your desired configuration and run ./install afterwards. Use <Help> if you want further information on any option." \
|
|
"${MENU_SIZE[@]}" "${tag_item_list[@]}"
|
|
|
|
local diag_exit="$?"
|
|
if [[ $diag_exit == 0 ]]; then
|
|
# <Select>
|
|
SELECTED_MENU_ITEM="$dialog_out"
|
|
[[ -z "$SELECTED_MENU_ITEM" ]] \
|
|
|| "${reverse_lookup[$SELECTED_MENU_ITEM]}_menu"
|
|
elif [[ $diag_exit == 1 ]]; then
|
|
# <Save>
|
|
SELECTED_MENU_ITEM="$dialog_out"
|
|
menu_save_as
|
|
elif [[ $diag_exit == 2 ]]; then
|
|
# <Help>
|
|
SELECTED_MENU_ITEM="${dialog_out#HELP }"
|
|
msgbox_help "$("${reverse_lookup[$SELECTED_MENU_ITEM]}_help")"
|
|
else
|
|
# Exit (<ESC><ESC>, <Exit>)
|
|
SELECTED_MENU_ITEM="${dialog_out:-$SELECTED_MENU_ITEM}"
|
|
menu_exit
|
|
true
|
|
fi
|
|
}
|
|
|
|
SELECTED_MENU_ITEM=""
|
|
MENU_SIZE=("20" "76" "12")
|
|
INPUTBOX_SIZE=("8" "76")
|
|
EDITTEXT_SIZE=("16" "76")
|
|
RADIOLIST_SIZE=("20" "76" "8")
|
|
BUILDLIST_SIZE=("20" "76" "8")
|
|
HELP_POPUP_SIZE=("8" "66")
|
|
CONFIRM_SIZE=("8" "66")
|
|
|
|
|
|
################################################
|
|
# Menu definition
|
|
|
|
MENU_ITEMS=(
|
|
"PARTITIONING_SCHEME"
|
|
"PARTITIONING_BOOT_TYPE"
|
|
"PARTITIONING_USE_SWAP"
|
|
"PARTITIONING_SWAP"
|
|
"PARTITIONING_ROOT_FS"
|
|
"PARTITIONING_USE_LUKS"
|
|
"PARTITIONING_DEVICE"
|
|
"PARTITIONING_DEVICES"
|
|
"PARTITIONING_ZFS_ENCRYPTION"
|
|
"PARTITIONING_ZFS_POOL_TYPE"
|
|
"PARTITIONING_RAID_TYPE"
|
|
"--------"
|
|
"HOSTNAME"
|
|
"TIMEZONE"
|
|
"KEYMAP"
|
|
"KEYMAP_INITRAMFS_OTHER"
|
|
"KEYMAP_INITRAMFS"
|
|
"LOCALES"
|
|
"LOCALE"
|
|
"--------"
|
|
"INIT_SYSTEM"
|
|
"GENTOO_MIRROR"
|
|
"GENTOO_ARCH"
|
|
"SELECT_MIRRORS"
|
|
"SELECT_MIRRORS_LARGE_FILE"
|
|
"--------"
|
|
"INSTALL_SSHD"
|
|
"ROOT_SSH_AUTHORIZED_KEYS"
|
|
"ADDITIONAL_PACKAGES"
|
|
)
|
|
|
|
function --------_tag() { echo "────────────────────────────"; }
|
|
function --------_label() { echo "────────────────────────────"; }
|
|
function --------_show() { return 0; }
|
|
function --------_help() { echo "Congratulations, you found a separator."; }
|
|
function --------_menu() { true; }
|
|
|
|
function PARTITIONING_SCHEME_tag() { echo "Partitioning scheme"; }
|
|
function PARTITIONING_SCHEME_label() { echo "($PARTITIONING_SCHEME)"; }
|
|
function PARTITIONING_SCHEME_show() { return 0; }
|
|
function PARTITIONING_SCHEME_help() { echo "Select the desired partitioning scheme."; }
|
|
function PARTITIONING_SCHEME_menu() {
|
|
if menu_radiolist_labeled \
|
|
"Select partitioning scheme" \
|
|
"Select which partitioning scheme you want to follow. Have a look at the help text for this option (available in the menu) for more details.\n\nAll options support EFI/BIOS, swap and some form of encryption (luks/zfs).\n" \
|
|
"$PARTITIONING_SCHEME" \
|
|
"${ALL_PARTITIONING_SCHEMES[@]}"
|
|
then
|
|
# Set disk scheme
|
|
case "$dialog_out" in
|
|
"classic_single_disk") create_classic_single_disk_layout swap=8GiB type=efi luks=false root_fs=ext4 /dev/sdX ;;
|
|
"zfs_centric") ;;
|
|
"btrfs_centric") ;;
|
|
"raid0_luks") ;;
|
|
"custom") PARTITIONING_SCHEME="$dialog_out" ;;
|
|
esac
|
|
UNSAVED_CHANGES=true
|
|
else
|
|
# Return to menu
|
|
true
|
|
fi
|
|
}
|
|
|
|
function PARTITIONING_USE_SWAP_tag() { echo " ├ Use swap"; }
|
|
function PARTITIONING_USE_SWAP_label() { on_off_label "$PARTITIONING_USE_SWAP" " ├ "; }
|
|
function PARTITIONING_USE_SWAP_show() { [[ $PARTITIONING_SCHEME != "custom" ]]; }
|
|
function PARTITIONING_USE_SWAP_help() { echo "Select whether or not to create a swap partition."; }
|
|
function PARTITIONING_USE_SWAP_menu() {
|
|
on_off_toggle "PARTITIONING_USE_SWAP"
|
|
UNSAVED_CHANGES=true
|
|
}
|
|
|
|
function PARTITIONING_SWAP_tag() { echo " │ └ Swap amount"; }
|
|
function PARTITIONING_SWAP_label() { echo " │ └ ($PARTITIONING_SWAP)"; }
|
|
function PARTITIONING_SWAP_show() { [[ $PARTITIONING_SCHEME != "custom" ]] && is_on "$PARTITIONING_USE_SWAP"; }
|
|
function PARTITIONING_SWAP_help() { echo "Select the amount of swap to use."; }
|
|
function PARTITIONING_SWAP_menu() {
|
|
dialog \
|
|
--title "Select swap amount" \
|
|
--inputbox "Enter the amount of swap for the new system. Use the correct suffix (e.g. 16GiB, 1000MB)." \
|
|
"${INPUTBOX_SIZE[@]}" "$PARTITIONING_SWAP"
|
|
PARTITIONING_SWAP="$dialog_out"
|
|
UNSAVED_CHANGES=true
|
|
}
|
|
|
|
function PARTITIONING_ROOT_FS_tag() { echo " ├ Root filesystem"; }
|
|
function PARTITIONING_ROOT_FS_label() { echo " ├ ($PARTITIONING_ROOT_FS)"; }
|
|
function PARTITIONING_ROOT_FS_show() { [[ $PARTITIONING_SCHEME != "custom" ]] && one_of "$PARTITIONING_SCHEME" "classic_single_disk" "raid0_luks"; }
|
|
function PARTITIONING_ROOT_FS_help() { echo "Select the amount of swap to use."; }
|
|
function PARTITIONING_ROOT_FS_menu() {
|
|
if menu_radiolist \
|
|
"Select root fstype" \
|
|
"Select which filesystem to use on the root partition." \
|
|
"$PARTITIONING_ROOT_FS" \
|
|
"${PARTITIONING_ROOT_FS_TYPES[@]}"
|
|
then
|
|
# Set timezone
|
|
PARTITIONING_ROOT_FS="$dialog_out"
|
|
UNSAVED_CHANGES=true
|
|
else
|
|
# Return to menu
|
|
true
|
|
fi
|
|
}
|
|
|
|
function HOSTNAME_tag() { echo "Hostname"; }
|
|
function HOSTNAME_label() { echo "($HOSTNAME)"; }
|
|
function HOSTNAME_show() { return 0; }
|
|
function HOSTNAME_help() { echo "Enter the desired system hostname here. Be aware that when creating mdadm raid arrays, this value will be recorded in metadata block. If you change it later, you should also update the metadata."; }
|
|
function HOSTNAME_menu() {
|
|
dialog \
|
|
--title "Select hostname" \
|
|
--inputbox "Enter the hostname for your new system." \
|
|
"${INPUTBOX_SIZE[@]}" "$HOSTNAME"
|
|
HOSTNAME="$dialog_out"
|
|
UNSAVED_CHANGES=true
|
|
}
|
|
|
|
function TIMEZONE_tag() { echo "Timezone"; }
|
|
function TIMEZONE_label() { echo "($TIMEZONE)"; }
|
|
function TIMEZONE_show() { return 0; }
|
|
function TIMEZONE_help() { echo "The timezone for the new system."; }
|
|
function TIMEZONE_menu() {
|
|
if menu_radiolist \
|
|
"Select timezone" \
|
|
"Select which timezone to use." \
|
|
"$TIMEZONE" \
|
|
"${ALL_TIMEZONES[@]}"
|
|
then
|
|
# Set timezone
|
|
TIMEZONE="$dialog_out"
|
|
UNSAVED_CHANGES=true
|
|
else
|
|
# Return to menu
|
|
true
|
|
fi
|
|
}
|
|
|
|
function KEYMAP_tag() { echo "Keymap"; }
|
|
function KEYMAP_label() { echo "($KEYMAP)"; }
|
|
function KEYMAP_show() { return 0; }
|
|
function KEYMAP_help() { echo "The default vconsole keymap for the system."; }
|
|
function KEYMAP_menu() {
|
|
if menu_radiolist \
|
|
"Select initramfs keymap" \
|
|
"Select which keymap to use in the vconsole." \
|
|
"$KEYMAP" \
|
|
"${ALL_KEYMAPS[@]}"
|
|
then
|
|
# Set keymap
|
|
KEYMAP="$dialog_out"
|
|
UNSAVED_CHANGES=true
|
|
else
|
|
# Return to menu
|
|
true
|
|
fi
|
|
}
|
|
|
|
function KEYMAP_INITRAMFS_OTHER_tag() { echo "Different initramfs keymap"; }
|
|
function KEYMAP_INITRAMFS_OTHER_label() { on_off_label "$KEYMAP_INITRAMFS_OTHER"; }
|
|
function KEYMAP_INITRAMFS_OTHER_show() { return 0; }
|
|
function KEYMAP_INITRAMFS_OTHER_help() { echo "Whether another keymap should be used for the initramfs. If enabled, you will be able to choose a separate keymap below."; }
|
|
function KEYMAP_INITRAMFS_OTHER_menu() {
|
|
on_off_toggle "KEYMAP_INITRAMFS_OTHER"
|
|
UNSAVED_CHANGES=true
|
|
[[ -z $KEYMAP_INITRAMFS ]] \
|
|
&& KEYMAP_INITRAMFS="$KEYMAP"
|
|
}
|
|
|
|
function KEYMAP_INITRAMFS_tag() { echo " └ Keymap (initramfs)"; }
|
|
function KEYMAP_INITRAMFS_label() { echo " └ ($KEYMAP_INITRAMFS)"; }
|
|
function KEYMAP_INITRAMFS_show() { is_on "$KEYMAP_INITRAMFS_OTHER"; }
|
|
function KEYMAP_INITRAMFS_help() { echo "The default vconsole keymap for the initrams. This is important if need to unlock an encrypted partition when booting."; }
|
|
function KEYMAP_INITRAMFS_menu() {
|
|
if menu_radiolist \
|
|
"Select initramfs keymap" \
|
|
"Select which keymap to use in the initramfs vconsole." \
|
|
"$KEYMAP_INITRAMFS" \
|
|
"${ALL_KEYMAPS[@]}"
|
|
then
|
|
# Set keymap
|
|
KEYMAP_INITRAMFS="$dialog_out"
|
|
UNSAVED_CHANGES=true
|
|
else
|
|
# Return to menu
|
|
true
|
|
fi
|
|
}
|
|
|
|
function LOCALES_tag() { echo "Locales"; }
|
|
function LOCALES_label() { echo "$N_LOCALES selected"; }
|
|
function LOCALES_show() { return 0; }
|
|
function LOCALES_help() { echo "The locales to generate for the new system. Be careful that the syntax for locales is a different from the resulting name of the genereated locales of locale-gen. For example the locale 'en_US.utf8' is enabled via 'en_US.UTF-8 UTF-8')."; }
|
|
function LOCALES_menu() {
|
|
if menu_splitlist "Select locales" "Select which locales to generate." "$SELECTED_LOCALES" "${SUPPORTED_LOCALES[@]}"; then
|
|
# Set locales
|
|
SELECTED_LOCALES="$dialog_out"
|
|
recalculate_locales
|
|
UNSAVED_CHANGES=true
|
|
else
|
|
# Return to menu
|
|
true
|
|
fi
|
|
}
|
|
|
|
function LOCALE_tag() { echo "Default locale"; }
|
|
function LOCALE_label() { echo "($LOCALE)"; }
|
|
function LOCALE_show() { return 0; }
|
|
function LOCALE_help() { echo "The locale to use for the new system. See \`locale -a\` for available options, and be sure to generate the locale by adding it to the list of locales above."; }
|
|
function LOCALE_menu() {
|
|
if menu_radiolist \
|
|
"Select default locale" \
|
|
"Select which locale to use as the default. Remember to also add the desired locale to the list of locales above." \
|
|
"$LOCALE" \
|
|
"${LOCALE_A[@]}"
|
|
then
|
|
# Set locale
|
|
LOCALE="$dialog_out"
|
|
UNSAVED_CHANGES=true
|
|
else
|
|
# Return to menu
|
|
true
|
|
fi
|
|
}
|
|
|
|
function INIT_SYSTEM_tag() { echo "Init system"; }
|
|
function INIT_SYSTEM_label() { echo "($INIT_SYSTEM)"; }
|
|
function INIT_SYSTEM_show() { return 0; }
|
|
function INIT_SYSTEM_help() { echo ""; }
|
|
function INIT_SYSTEM_menu() {
|
|
if menu_radiolist \
|
|
"Select init system" \
|
|
"Select the init system you want to use." \
|
|
"$INIT_SYSTEM" \
|
|
"${INIT_SYSTEMS[@]}"
|
|
then
|
|
# Set init system
|
|
INIT_SYSTEM="$dialog_out"
|
|
UNSAVED_CHANGES=true
|
|
else
|
|
# Return to menu
|
|
true
|
|
fi
|
|
}
|
|
|
|
function GENTOO_MIRROR_tag() { echo "Gentoo mirror"; }
|
|
function GENTOO_MIRROR_label() { echo "($(ellipsis 20 "$GENTOO_MIRROR"))"; }
|
|
function GENTOO_MIRROR_show() { return 0; }
|
|
function GENTOO_MIRROR_help() { echo "Enter the primary gentoo mirror that should be used for the installation process (until mirrorselect is run)."; }
|
|
function GENTOO_MIRROR_menu() {
|
|
dialog \
|
|
--title "Select gentoo mirror" \
|
|
--inputbox "Enter the desired gentoo mirror location." \
|
|
"${INPUTBOX_SIZE[@]}" "$GENTOO_MIRROR"
|
|
UNSAVED_CHANGES=true
|
|
}
|
|
|
|
function GENTOO_ARCH_tag() { echo "Gentoo arch"; }
|
|
function GENTOO_ARCH_label() { echo "($GENTOO_ARCH)"; }
|
|
function GENTOO_ARCH_show() { return 0; }
|
|
function GENTOO_ARCH_help() { echo "Select gentoo's architecture tag for the new system."; }
|
|
function GENTOO_ARCH_menu() {
|
|
if menu_radiolist \
|
|
"Select architecture" \
|
|
"Select the architecture for the new system." \
|
|
"$GENTOO_ARCH" \
|
|
"${ALL_GENTOO_ARCHS[@]}"
|
|
then
|
|
# Set arch
|
|
GENTOO_ARCH="$dialog_out"
|
|
UNSAVED_CHANGES=true
|
|
else
|
|
# Return to menu
|
|
true
|
|
fi
|
|
}
|
|
|
|
function SELECT_MIRRORS_tag() { echo "Run mirrorselect"; }
|
|
function SELECT_MIRRORS_label() { on_off_label "$SELECT_MIRRORS"; }
|
|
function SELECT_MIRRORS_show() { return 0; }
|
|
function SELECT_MIRRORS_help() { echo "Determines if mirrorselect will be used to determine the best gentoo mirror for the new system."; }
|
|
function SELECT_MIRRORS_menu() {
|
|
on_off_toggle "SELECT_MIRRORS"
|
|
UNSAVED_CHANGES=true
|
|
}
|
|
|
|
function SELECT_MIRRORS_LARGE_FILE_tag() { echo " └ Use large files"; }
|
|
function SELECT_MIRRORS_LARGE_FILE_label() { on_off_label "$SELECT_MIRRORS_LARGE_FILE" " └ "; }
|
|
function SELECT_MIRRORS_LARGE_FILE_show() { is_on "$SELECT_MIRRORS"; }
|
|
function SELECT_MIRRORS_LARGE_FILE_help() { echo "Determines if mirrorselect uses large files (~10MB) to test mirrors."; }
|
|
function SELECT_MIRRORS_LARGE_FILE_menu() {
|
|
on_off_toggle "SELECT_MIRRORS_LARGE_FILE"
|
|
UNSAVED_CHANGES=true
|
|
}
|
|
|
|
function INSTALL_SSHD_tag() { echo "Install sshd"; }
|
|
function INSTALL_SSHD_label() { on_off_label "$INSTALL_SSHD"; }
|
|
function INSTALL_SSHD_show() { return 0; }
|
|
function INSTALL_SSHD_help() { echo "Install and enable sshd on the new system. A reasonably secure sshd configuration will be provided. It will by default only allow ed25519 keys, restrict key exchange algorithms to a reasonable subset, disable any password based authentication, and only allow root to login."; }
|
|
function INSTALL_SSHD_menu() {
|
|
on_off_toggle "INSTALL_SSHD"
|
|
UNSAVED_CHANGES=true
|
|
}
|
|
|
|
function ROOT_SSH_AUTHORIZED_KEYS_tag() { echo "Authorized keys (root)"; }
|
|
function ROOT_SSH_AUTHORIZED_KEYS_label() { echo "$(sed '/^\s*#/d;/^\s*$/d' <<< "$ROOT_SSH_AUTHORIZED_KEYS" | wc -l) keys"; }
|
|
function ROOT_SSH_AUTHORIZED_KEYS_show() { return 0; }
|
|
function ROOT_SSH_AUTHORIZED_KEYS_help() { echo "The authorized keys for ssh root login, one per line."; }
|
|
function ROOT_SSH_AUTHORIZED_KEYS_menu() {
|
|
# Prepare file to edit in dialog,
|
|
# unfortunately <() won't work (probably EOF is encountered before content is available).
|
|
local tmpfile
|
|
tmpfile="$(mktemp)" || die "Could not create temporary file."
|
|
cat > "$tmpfile" <<EOF
|
|
# Enter all authorized keys for ssh root login.
|
|
# Use <Tab> to navigate between the inputbox, <OK> and <Cancel>.
|
|
#
|
|
# All comments will be removed from the final file.
|
|
# If you are on a vconsole and have no means of entering this now,
|
|
# simply edit the final configuration later with a text editor.
|
|
|
|
#ssh-ed25519 ......
|
|
$ROOT_SSH_AUTHORIZED_KEYS
|
|
EOF
|
|
|
|
dialog \
|
|
--title "Enter authorized keys" \
|
|
--editbox "$tmpfile" "${EDITTEXT_SIZE[@]}"
|
|
ROOT_SSH_AUTHORIZED_KEYS="$(sed '/^\s*#/d;/^\s*$/d' <<< "$dialog_out")"
|
|
UNSAVED_CHANGES=true
|
|
}
|
|
|
|
function ADDITIONAL_PACKAGES_tag() { echo "Additional packages"; }
|
|
function ADDITIONAL_PACKAGES_label() { echo "${#ADDITIONAL_PACKAGES[@]} packages"; }
|
|
function ADDITIONAL_PACKAGES_show() { return 0; }
|
|
function ADDITIONAL_PACKAGES_help() { echo "Enter additional packages that should be installed. It is recommended to keep this to a minimum, because of the quite \"interactive\" nature of gentoo package management ;)"; }
|
|
function ADDITIONAL_PACKAGES_menu() {
|
|
dialog \
|
|
--title "Additional packages" \
|
|
--inputbox "Enter additional packages (portage package ATOMs) to install. Delimited by space." \
|
|
"${INPUTBOX_SIZE[@]}" "${ADDITIONAL_PACKAGES[*]}"
|
|
# shellcheck disable=SC2206
|
|
ADDITIONAL_PACKAGES=($dialog_out)
|
|
UNSAVED_CHANGES=true
|
|
}
|
|
|
|
|
|
################################################
|
|
# Menu functions
|
|
|
|
# $1: filename
|
|
function save() {
|
|
cat > "$1" <<EOF
|
|
# vim: set ft=sh ts=4 sw=4 sts=-1 noet:
|
|
# This file will be interpreted by /bin/bash.
|
|
|
|
|
|
################################################
|
|
# Disk configuration
|
|
|
|
$(define_disk_layout)
|
|
|
|
|
|
################################################
|
|
# System configuration
|
|
|
|
HOSTNAME=${HOSTNAME@Q}
|
|
TIMEZONE=${TIMEZONE@Q}
|
|
KEYMAP=${KEYMAP@Q}
|
|
KEYMAP_INITRAMFS=${KEYMAP_INITRAMFS@Q}
|
|
|
|
LOCALES=${LOCALES@Q}
|
|
LOCALE=${LOCALE@Q}
|
|
|
|
|
|
################################################
|
|
# Gentoo configuration
|
|
|
|
GENTOO_MIRROR=${GENTOO_MIRROR@Q}
|
|
GENTOO_ARCH=${GENTOO_ARCH@Q}
|
|
STAGE3_BASENAME="stage3-\$GENTOO_ARCH$([[ $SYSTEMD == true ]] && echo -n "-systemd")"
|
|
SELECT_MIRRORS=${SELECT_MIRRORS@Q}
|
|
SELECT_MIRRORS_LARGE_FILE=${SELECT_MIRRORS_LARGE_FILE@Q}
|
|
SYSTEMD=${SYSTEMD@Q}
|
|
|
|
|
|
################################################
|
|
# Additional (optional) configuration
|
|
|
|
ADDITIONAL_PACKAGES=(${ADDITIONAL_PACKAGES[@]@Q})
|
|
INSTALL_SSHD=${INSTALL_SSHD@Q}
|
|
ROOT_SSH_AUTHORIZED_KEYS=${ROOT_SSH_AUTHORIZED_KEYS@Q}
|
|
|
|
|
|
################################################
|
|
# Prove that you have read the config
|
|
|
|
I_HAVE_READ_AND_EDITED_THE_CONFIG_PROPERLY=true
|
|
EOF
|
|
}
|
|
|
|
trap 'clear_and_exit 130' SIGINT
|
|
|
|
# Begin menu loop. Exit will be called to end this loop where it is appropriate.
|
|
while true; do
|
|
menu
|
|
done
|