#!/bin/bash set -o 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}")")" } export GENTOO_INSTALL_REPO_DIR="$(get_source_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" ################################################ # 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 # https://stackoverflow.com/questions/12521114/getting-the-canonical-time-zone-name-in-shell-script#comment88637393_12523283 find /usr/share/zoneinfo -type f ! -regex ".*/Etc/.*" -exec \ cmp -s {} /etc/localtime \; -print | sed -e 's@.*/zoneinfo/@@' | head -n1 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" } ################################################ # Configuration constants 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 }; get_all_keymaps INIT_SYSTEMS=("systemd" "OpenRC") readarray -t SUPPORTED_LOCALES < /usr/share/i18n/SUPPORTED ################################################ # Load/Default configuration function load_config() { # Load settings source "$1" || die "Could not load given 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 # 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="" LOCALES="" LOCALE="C.utf8" GENTOO_MIRROR="https://mirror.eu.oneandone.net/linux/distributions/gentoo/gentoo" GENTOO_ARCH="amd64" STAGE3_BASENAME="stage3-$GENTOO_ARCH-systemd" SELECT_MIRRORS=true SELECT_MIRRORS_LARGE_FILE=false ADDITIONAL_PACKAGES=("app-editors/neovim") INSTALL_SSHD=true ROOT_SSH_AUTHORIZED_KEYS="" INIT_SYSTEM="systemd" KEYMAP_INITRAMFS_OTHER=false # 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 ################################################ # Menu helpers and constants function clear_and_exit() { dialog --clear clear -x exit 0 } function ellipsis() { if [[ "${#2}" -gt "$1" ]]; then echo "${2:0:$1}…" else echo "$2" fi } function on_off_toggle() { if [[ "${!1}" == true ]]; then declare -g "$1"=false else declare -g "$1"=true fi } function on_off_label() { if [[ "$1" == true ]]; then echo -n "[*]" else echo -n "[ ]" fi } function is_on() { [[ "$1" == true ]] } function is_off() { [[ "$1" != true ]] } SELECTED_MENU_ITEM="" MENU_SIZE="20 76 12" INPUTBOX_SIZE="8 76" RADIOLIST_SIZE="20 76 8" BUILDLIST_SIZE="20 76 8" HELP_POPUP_SIZE="8 66" CONFIRM_SIZE="8 66" ################################################ # Menu definition MENU_ITEMS=( "HOSTNAME" "TIMEZONE" "KEYMAP" "KEYMAP_INITRAMFS_OTHER" "KEYMAP_INITRAMFS" "--------" "LOCALES" "LOCALE" "--------" "INIT_SYSTEM" "KEYFILE" ) function --------_tag() { echo "────────────────────────────"; } function --------_label() { echo "────────────────────────────"; } function --------_show() { return 0; } function --------_help() { echo "Congratulations, you found a separator."; } function --------_menu() { true; } 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() { local sel # shellcheck disable=SC2086 sel="$(dialog \ --title "Select hostname" \ --inputbox "Enter the hostname for your new system." \ $INPUTBOX_SIZE "$HOSTNAME" 3>&2 2>&1 1>&3 3>&-)" 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() { true } # $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 for item in "$@"; do items+=("$((i++))" "$item" "off") done # Show selection dialog local sel # shellcheck disable=SC2086 sel="$(dialog \ --title "$title" \ --buildlist "$description\nUse ^ to focus the list of unselected items and $ to focus the list of selected items. Use to select/deselect an item and select by pressing when finished." \ $BUILDLIST_SIZE "${items[@]}" 3>&2 2>&1 1>&3 3>&-)" local diag_exit="$?" if [[ $diag_exit == 0 ]]; then # echo -n "$sel" return 0 elif [[ $diag_exit == 1 ]]; then # return 1 elif [[ $diag_exit == 2 ]]; then # to select the option under the cursor, or to use the option which is selected with an asterisk." \ $RADIOLIST_SIZE "${items[@]}" 3>&2 2>&1 1>&3 3>&-)" local diag_exit="$?" if [[ $diag_exit == 0 ]]; then # echo -n "$sel" return 0 elif [[ $diag_exit == 1 ]]; then # return 1 elif [[ $diag_exit == 2 ]]; then # SELECTED_MENU_ITEM="$sel" "${reverse_lookup[$SELECTED_MENU_ITEM]}_menu" elif [[ $diag_exit == 1 ]]; then # SELECTED_MENU_ITEM="$sel" menu_save_as elif [[ $diag_exit == 2 ]]; then # SELECTED_MENU_ITEM="${sel#HELP }" msgbox_help "$("${reverse_lookup[$SELECTED_MENU_ITEM]}_help")" else # Exit (, ) SELECTED_MENU_ITEM="${sel-$SELECTED_MENU_ITEM}" menu_exit true fi } # Begin menu loop. Exit will be called to end this loop where it is appropriate. while true; do menu done