Last active
March 5, 2020 14:00
-
-
Save gazorby/e3589c05e3cef8516a21f37114645b09 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# This script assumes networking is up | |
############################################################ | |
# CONFIGURATION START | |
############################################################ | |
############ | |
# MANDATORY | |
############ | |
_HOSTNAME="smallbox" | |
_KEYMAP="fr" | |
_SYSTEM_LANGUAGE="en_US" # Only UTF-8 variant will be used | |
_TIMEZONE="Europe/Paris" | |
_CPU="intel !amd" | |
_DISPLAY_DRIVER="intel !nvidia !amdgpu !ati !nouveau" | |
_BOOTLOADER="refind-efi" | |
_CRYPT_PASSWD="archlinux" | |
_CRYPT_PASSWD_RETYPE="archlinux" | |
_ERASE_DRIVE="true" | |
# required if _ERASE_DRIVE is false, ignored otherwise | |
_PART_EFI=/dev/sda1 | |
_PART_SWAP=/dev/sda2 | |
_PART_SYSTEM=/dev/sda3 | |
# required if _ERASE_DRIVE is true, ignored otherwise | |
_DRIVE=/dev/sda | |
_PART_EFI_SIZE="550" # EFI partition size in MiB | |
_PART_SWAP_SIZE="12" # Size in GiB | |
_PART_SYSTEM_LABEL="cryptsystem" # label of system partition | |
_PART_SWAP_LABEL="cryptswap" # label of swap partition | |
o=defaults,x-mount.mkdir | |
o_btrfs=$o,compress=lzo,ssd,noatime | |
########### | |
#OPTIONNAL | |
########### | |
_DESKTOP="false" | |
_BLUETOOTH="true" | |
_AUR="false" | |
# Will be ignored if _DESKTOP is false | |
_DE="!gnome !kde !xfce" | |
# Will be ignored if _DESKTOP is false | |
_WINDOW_MANAGER="!gdm !sddm !lightdm" | |
# System language may not be included. Only UTF-8 variant will be used | |
_AVAILABLE_LANGUAGES="en_US fr_FR" | |
# If empty, no new user will be created | |
_USER="gazorby" | |
# Change the default shell for the new user (if empty, bash will be used) | |
_SHELL="fish" | |
# Change this! | |
_ROOT_PASSWD="archlinux" | |
_ROOT_PASSWD_RETYPE="archlinux" | |
_USER_PASSWD="archlinux" | |
_USER_PASSWD_RETYPE="archlinux" | |
# Extra systems packages | |
_PKGS_SYSTEM="openssh git man-db man-pages texinfo sudo vim curl ufw ripgrep fd exa highlight yarn $_SHELL" | |
# Will be installed if _DESKTOP is '1' | |
_PKGS_DESKTOP_BASE="xorg-server xorg-xinit xdg-user-dirs mesa xterm otf-fira-sans noto-fonts-emoji ttf-croscore ttf-roboto vlc firefox" | |
_PKGS_AUR_PKGS="protonmail-bridge authy bitwarden-bin direnv jetbrains-toolbox spotify ttf-roboto-slab visual-studio-code-bin starship-bin" | |
# Will be installed if _DE is set to 'gnome' | |
_PKGS_GNOME_EXTRAS="gvfs chrome-gnome-shell gnome-tweaks evolution materia-gtk-theme tilix" | |
# Will be installed if _DE is set to 'kde' | |
_PKGS_KDE_EXTRAS="kde-applications materia-kde" | |
# Will be installed if _DE is set to 'xfce' | |
_PKGS_XFCE_EXTAS="gvfs materia-gtk-theme" | |
# Other packages | |
_PKGS_CUSTOM="gdm gnome-shell tilix gnome-control-center" | |
############################################################ | |
# CONFIGURATION END | |
############################################################ | |
############################################################ | |
# Global variables | |
############################################################ | |
_PKGS="$_PKGS_SYSTEM $_PKGS_CUSTOM" | |
CHROOT_RUN="arch-chroot /mnt" | |
START_DATE="$(date '+%Y-%m-%d--%H:%M:%S')" | |
PROGNAME=${0##*/} # ./name.sh ==> name.sh | |
TEMP_DIR="$(mktemp -d /tmp/XXXXXXX)" # Temporary directory | |
LOG_FILE=/tmp/log_"$PROGNAME"_["$START_DATE"].txt # Store logs | |
DEBUG_LOG_FILE=/tmp/log_debug_"$PROGNAME"_["$START_DATE"].txt # Store logs | |
OUT_END="$TEMP_DIR/out_end.txt" # Store output to display after script execution | |
OUT_TMP="$TEMP_DIR/out_tmp.txt" | |
LOCKFILE=/tmp/script_lockfile.lock | |
LOCKFD=99 | |
_SERVER_TEST=google.com | |
# COLORS used in output | |
NORMAL="\e[0m" | |
GREEN="\e[32m" | |
YELLOW="\e[33m" | |
RED="\e[31m" | |
BLUE="\e[34m" | |
CYAN="\e[36m" | |
BOLD="\e[1m" | |
# Options | |
QUIET="false" | |
LOCK="false" | |
LOG="true" | |
NOCONFIRM="false" | |
priority_options_pattern='@(--debug|-h|--help|--strict|--lock|--logs)' | |
############################################################ | |
# PRIVATE FUNCTIONS | |
############################################################ | |
_lock() { flock -$1 $LOCKFD; } | |
_no_more_locking() { _lock u; _lock xn && rm -f $LOCKFILE; } | |
_prepare_locking() { eval "exec $LOCKFD>\"$LOCKFILE\""; } | |
# PRIVATE (better to use use shortcuts) | |
# Display logs | |
# | |
# Arguments : | |
# | |
# $1 (required): loglevel | |
# - info, warning, error, step and info will be | |
# displayed like this : " [colored loglevel] message " | |
# - title will show " ==> bold title " | |
# - none will only show the message | |
# Any other loglevel (except title and none) will be green | |
# | |
# $2 (required): where to write log message | |
# - out : display the log immediatly | |
# - exit : log will be displayed on script exit | |
# - persist : write to a log file | |
# - tmp : write logs to a temporary file used to display them later | |
function _log () { | |
local message="$3" | |
local loglevel="$1" | |
local where="$2" | |
local loglevel_format | |
case "$loglevel" in | |
warning) | |
loglevel_format="[${YELLOW}warning${NORMAL}]" | |
;; | |
error) | |
loglevel_format="[${RED}error${NORMAL}]" | |
;; | |
none) | |
loglevel_format="" | |
;; | |
info|*) | |
loglevel_format="[${GREEN}info${NORMAL}]" | |
;; | |
esac | |
if [[ $loglevel = title && $where != persist ]]; then | |
# ==> title | |
loglevel_format="\n$BLUE==> ${NORMAL}${BOLD}%s${NORMAL}" | |
fi | |
# output - [loglevel] message | |
if [[ $where = now && $QUIET = false ]]; then | |
# No newline if info is a step | |
if [[ $loglevel = step ]]; then | |
printf "$loglevel_format %s" "$message" | |
else | |
printf "$loglevel_format %s\n" "$message" | |
fi | |
# Write logs in temp file which is read on script exit | |
elif [[ $where =~ exit|tmp && $QUIET = false ]]; then | |
message="$(str_add_prefix "$message" ' ')" | |
local out="" | |
case "$where" in | |
exit) | |
out="$OUT_END" | |
;; | |
tmp) | |
out="$OUT_TMP" | |
;; | |
esac | |
printf "$loglevel_format\n%s\n" "$message" >> "$out" | |
fi | |
if [[ $LOG = true ]]; then | |
loglevel=${loglevel//title/info} | |
local date="[$(date '+%Y-%m-%d %H:%M:%S')]" | |
printf "%s\t%s\n" "$date[$loglevel]" "${@:3}" >> $LOG_FILE | |
fi | |
} | |
############################################################ | |
# PUBLIC FUNCTIONS | |
############################################################ | |
# display script usage | |
# | |
# Arguments : | |
# $1 (optionnmal): Cause that showing up this help | |
function usage() { | |
# Empty string if param 1 empty | |
local error=${1:-""} | |
printf "" | |
printf "\e[31m%s\e[0m\n\n" "$error" | |
printf "%s\n\n" "Usage :" | |
printf "\e[1m\e[33m%s\e[0m\n" "./$PROGNAME.sh [option]" | |
printf "%s\n" "" | |
printf "\t\e[1m%s\e[0m\t%s\n" "--debug " "Run script in debug mode (All executed commands are displayed)" | |
printf "\t\e[1m%s\e[0m\t%s\n" "--lock " "Lock the script (only one instance can be executed)" | |
printf "\t\e[1m%s\e[0m\t%s\n" "--no-logs " "Don't write logs" | |
printf "\t\e[1m%s\e[0m\t%s\n" "--check | -c " "Run sanity checks" | |
printf "\t\e[1m%s\e[0m\t%s\n" "--noconfirm " "No prompts" | |
printf "\t\e[1m%s\e[0m\t%s\n" "--partition | -p" "Create partitions" | |
printf "\t\e[1m%s\e[0m\t%s\n" "--format | -f " "Format partitions" | |
printf "\t\e[1m%s\e[0m\t%s\n" "--mount | -m " "Mount partitions" | |
printf "\t\e[1m%s\e[0m\t%s\n" "--strict " "Run script in scrict mode (enable error when trying to expand an unset parameter)" | |
printf "\t\e[1m%s\e[0m\t%s\n" "-h --help " "Show this help" | |
} | |
# Log shortcut functions | |
info () { _log info now "$*"; } | |
error () { _log error now "$*"; } | |
warning () { _log warning now "$*"; } | |
warning_keep () { _log warning tmp "$*"; } | |
error_keep () { _log error tmp "$*"; } | |
title () { _log title now "$*"; } | |
on_exit () { _log "$1" exit "${@:2}"; } | |
print_kept_logs () { cat "$OUT_TMP"; } | |
clear_kept_logs () { truncate -s 0 "$OUT_TMP"; } | |
# Trim whitespace from a string | |
# | |
# Arguments : | |
# $* (required): String to be trimmed | |
function trim() { | |
local var="$*" | |
# remove leading whitespace characters | |
var="${var#"${var%%[![:space:]]*}"}" | |
# remove trailing whitespace characters | |
var="${var%"${var##*[![:space:]]}"}" | |
# remove space whitespace inside string | |
var="${var// /}" | |
printf "$var" | |
} | |
function str_add_brefore_match() { | |
local value="$2" | |
local match="$3" | |
printf "${1%%${match}*}${value}${match}${1##*${match}}" | |
} | |
function str_add_prefix() { | |
local string="____ ____$1" | |
local value="$2" | |
printf "${string%%____ ____*}${2}${string##*____ ____}" | |
} | |
# Obtain an exclusive lock immediately or exit | |
function exlock_now() { | |
if ! _lock xn; then | |
on_exit error "Couldn't acquire the lock!" | |
exit 1 | |
fi | |
} | |
# Locking shortcuts | |
exlock() { _lock x; } # obtain an exclusive lock | |
shlock() { _lock s; } # obtain a shared lock | |
unlock() { _lock u; } # drop a lock | |
function check_var_value() { | |
local SEVERITY="$1" | |
local NAME="$2" | |
local VALUE="$3" | |
local MESSAGE="${4}" | |
if [ -z "$VALUE" ]; then | |
if [[ $SEVERITY = error ]]; then | |
on_exit error "$NAME variable must have a value. -- $MESSAGE" | |
exit 1 | |
elif [[ $SEVERITY = warning ]]; then | |
warning_keep "$NAME variable is no set. -- $MESSAGE" | |
fi | |
return 1 | |
fi | |
} | |
function check_var_equals() { | |
local SEVERITY=$1 | |
local NAME1=$2 | |
local NAME2=$3 | |
local VALUE1=$4 | |
local VALUE2=$5 | |
if [[ $VALUE1 != $VALUE2 ]]; then | |
if [[ $SEVERITY = error ]]; then | |
on_exit error "$NAME1 and $NAME2 must be equal [$VALUE1, $VALUE2]." | |
exit 1 | |
elif [[ $SEVERITY = warning ]]; then | |
warning_keep "$NAME1 and $NAME2 are not equal [$VALUE1, $VALUE2]." | |
fi | |
return 1 | |
fi | |
} | |
function check_var_match() { | |
local SEVERITY=$1 | |
local NAME=$2 | |
local VALUE=$3 | |
local PATTERN=$4 | |
if ! [[ $VALUE =~ $PATTERN ]]; then | |
if [[ $SEVERITY = error ]]; then | |
on_exit error "$NAME doesn't match the required pattern [$PATTERN]" | |
exit 1 | |
elif [[ $SEVERITY = warning ]]; then | |
warning_keep "$NAME doesn't match the required pattern [$PATTERN]" | |
fi | |
return 1 | |
fi | |
} | |
function check_var_bool() { | |
local SEVERITY=$1 | |
local NAME=$2 | |
local VALUE=$3 | |
check_var_match "$SEVERITY" "$NAME" "$VALUE" "(^true$)|(^false$)" | |
if [[ $? != 0 ]]; then | |
return 1 | |
else | |
return 0 | |
fi | |
} | |
function sanitize_var() { | |
var="$1" | |
# remove disabled | |
var="${var//\!+([![:space:]])/}" | |
# remove leading whitespace characters | |
var="${var#"${var%%[![:space:]]*}"}" | |
# remove trailing whitespace characters | |
var="${var%"${var##*[![:space:]]}"}" | |
printf "$var" | |
} | |
function uncomment() { | |
local file="$2" | |
local pattern="$1" | |
sed -i "/$pattern/s/^#//" $file | |
} | |
function prompt_yes_no() { | |
local message=$1 | |
local default=${2:-"none"} | |
if [[ $NOCONFIRM = true ]]; then | |
return | |
fi | |
printf "$message [yes/no] default=$default\n" | |
read res | |
if [[ -z $res && $default != none ]]; then | |
if [[ $default = yes ]]; then | |
return 0 | |
else | |
return 1 | |
fi | |
fi | |
while ! [[ $res =~ (^yes$)|(^no$) ]]; do | |
printf "please, type \"yes\" or \"no\"" | |
read res | |
done | |
if [[ $res = yes ]]; then | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
function pacman_install() { | |
local PACKAGES=$1 | |
for VARIABLE in {1..5} | |
do | |
arch-chroot /mnt pacman -Syu --noconfirm --needed $PACKAGES | |
if [ $? == 0 ]; then | |
break | |
else | |
info "Waiting before retrying" | |
sleep 10 | |
fi | |
done | |
} | |
function part_prepare() { | |
if [[ -e /dev/mapper/system ]]; then | |
cryptsetup close /dev/mapper/system | |
fi | |
if [[ -e /dev/mapper/swap ]]; then | |
cryptsetup remove "$_PART_SWAP_LABEL" | |
fi | |
umount -R /mnt | |
} | |
function part_create() { | |
if [[ $_ERASE_DRIVE = true ]]; then | |
sgdisk --zap-all $_DRIVE | |
wipefs --all $_DRIVE | |
sgdisk --clear \ | |
--new=1:0:+"$_PART_EFI_SIZE"MiB --typecode=1:ef00 --change-name=1:EFI \ | |
--new=2:0:+"$_PART_SWAP_SIZE"GiB --typecode=2:8200 --change-name=2:"$_PART_SWAP_LABEL" \ | |
--new=3:0:0 --typecode=3:8300 --change-name=3:"$_PART_SYSTEM_LABEL" \ | |
$_DRIVE | |
fi | |
} | |
function part_format() { | |
title "Format partitions" | |
if [[ $_ERASE_DRIVE = true ]]; then | |
mkfs.fat -F32 -n EFI /dev/disk/by-partlabel/EFI | |
printf "$_CRYPT_PASSWD\n$_CRYPT_PASSWD_RETYPE" | cryptsetup luksFormat --align-payload=8192 -s 256 -c aes-xts-plain64 /dev/disk/by-partlabel/"$_PART_SYSTEM_LABEL" | |
printf "$_CRYPT_PASSWD\n$_CRYPT_PASSWD_RETYPE" | cryptsetup open /dev/disk/by-partlabel/"$_PART_SYSTEM_LABEL" system | |
cryptsetup open --type plain --key-file /dev/urandom /dev/disk/by-partlabel/"$_PART_SWAP_LABEL" swap | |
# create the swap partition | |
mkswap -L swap /dev/mapper/swap | |
swapon -L swap | |
# format the system partition with btrfs. Inside we will use subvolumes | |
mkfs.btrfs --force --label system /dev/mapper/system | |
# mount the newly created partition | |
mount -t btrfs LABEL=system /mnt | |
else | |
printf "$_CRYPT_PASSWD\n$_CRYPT_PASSWD_RETYPE" | cryptsetup luksFormat --align-payload=8192 -s 256 -c aes-xts-plain64 "$_PART_SYSTEM" | |
printf "$_CRYPT_PASSWD\n$_CRYPT_PASSWD_RETYPE" | cryptsetup open "$_PART_SYSTEM" system | |
cryptsetup open --type plain --key-file /dev/urandom "$_PART_SWAP" swap | |
fi | |
# open the encrypted partition with label system | |
# If something fails and you need to restart your system this is the line you need to open your partition again later on. | |
# I'l mark those commands with an asterisk should you need to reboot and start over with eg. the boot option. | |
# * | |
# open the swap partition with a random key | |
# create the swap partition | |
mkswap -L swap /dev/mapper/swap | |
swapon -L swap | |
# format the system partition with btrfs. Inside we will use subvolumes | |
mkfs.btrfs --force --label system /dev/mapper/system | |
# mount the newly created partition | |
mount -t btrfs LABEL=system /mnt | |
# and create the neccessary subvolumes | |
btrfs subvolume create /mnt/root | |
btrfs subvolume create /mnt/home | |
btrfs subvolume create /mnt/snapshots | |
} | |
function part_mount() { | |
title "Mount partitions" | |
# then unmount to mount again with subvolumes | |
umount -R /mnt | |
mount -t btrfs -o subvol=root,$o_btrfs LABEL=system /mnt | |
mount -t btrfs -o subvol=home,$o_btrfs LABEL=system /mnt/home | |
mount -t btrfs -o subvol=snapshots,$o_btrfs LABEL=system /mnt/.snapshots | |
# create a boot partition and mount as well | |
mkdir /mnt/boot | |
if [[ $_ERASE_DRIVE = true ]]; then | |
mount LABEL=EFI /mnt/boot; | |
else | |
mount $_PART_EFI /mnt/boot | |
fi | |
} | |
function part_umount() { | |
cryptsetup close /dev/mapper/system | |
umount -R /mnt | |
} | |
function set_packages() { | |
title "Set package list" | |
_PKGS="$_PKGS $_BOOTLOADER" | |
if [[ $_CPU =~ ^(intel|amd)$ ]]; then | |
_PKGS="$_PKGS ${_CPU}-ucode" | |
fi | |
if [[ $_BLUETOOTH = true ]]; then | |
_PKGS="$_PKGS bluez" | |
fi | |
if [[ $_DESKTOP = true ]]; then | |
_PKGS="$_PKGS $_PKGS_DESKTOP_BASE" | |
if [[ $_DE = gnome ]]; then | |
_PKGS="$_PKGS gnome $_PKGS_GNOME_EXTRAS" | |
elif [[ $_DE = kde ]]; then | |
_PKGS="$_PKGS plasma $_PKGS_KDE_EXTRAS" | |
elif [[ $_DE = xfce ]]; then | |
_PKGS="$_PKGS xfce4 $_PKGS_XFCE_EXTAS" | |
fi | |
_PKGS="$_PKGS $_WINDOW_MANAGER" | |
fi | |
case "$_DISPLAY_DRIVER" in | |
"nvidia" ) | |
_PKGS="$_PKGS nvidia" | |
;; | |
"nvidia-lts" ) | |
_PKGS="$_PKGS nvidia-lts" | |
;; | |
"nvidia-dkms" ) | |
_PKGS="$_PKGS nvidia-dkms" | |
;; | |
"nvidia-390xx" ) | |
_PKGS="$_PKGS nvidia-390xx" | |
;; | |
"nvidia-390xx-lts" ) | |
_PKGS="$_PKGS nvidia-390xx-lts" | |
;; | |
"nvidia-390xx-dkms" ) | |
_PKGS="$_PKGS nvidia-390xx-dkms" | |
;; | |
esac | |
} | |
function packages_aur() { | |
if [[ $_AUR = true ]]; then | |
pacman_install "git" | |
arch-chroot /mnt sed -i 's/%wheel ALL=(ALL:ALL) ALL/%wheel ALL=(ALL) NOPASSWD: ALL/' /etc/sudoers | |
arch-chroot /mnt bash -c "printf \"$_USER_PASSWD\n$_USER_PASSWD\n$_USER_PASSWD\n$_USER_PASSWD\n\" | su $_USER -s /bin/bash -c \"cd /home/$_USER && git clone https://aur.archlinux.org/yay.git && (cd yay && makepkg -si --noconfirm) && rm -rf yay\"" | |
arch-chroot /mnt sed -i 's/%wheel ALL=(ALL) NOPASSWD: ALL/%wheel ALL=(ALL:ALL) ALL/' /etc/sudoers | |
if [[ -n "$_AUR_PKGS" ]]; then | |
aur_install "$_AUR_PKGS" | |
fi | |
fi | |
} | |
function aur_install() { | |
local packages=$1 | |
for VARIABLE in {1..5} | |
do | |
arch-chroot /mnt bash -c "printf \"$_USER_PASSWD\n$_USER_PASSWD\n$_USER_PASSWD\n$_USER_PASSWD\n\" | su $_USER -c \"yay -Syu --noconfirm --needed $packages\"" | |
if [ $? == 0 ]; then | |
break | |
else | |
sleep 10 | |
fi | |
done | |
} | |
function conf_locale() { | |
info "Uncommenting in /etc/locale.gen [$_AVAILABLE_LANGUAGES]" | |
for lang in $_AVAILABLE_LANGUAGES; do | |
uncomment "${lang}.UTF-8 UTF-8" /mnt/etc/locale.gen | |
done | |
# be sure to have system language available | |
uncomment "${_SYSTEM_LANGUAGE}.UTF-8 UTF-8" /mnt/etc/locale.gen | |
arch-chroot /mnt locale-gen | |
arch-chroot /mnt localectl set-locale "LANG=${_SYSTEM_LANGUAGE}.UTF-8" | |
} | |
function conf_time_date() { | |
info "Enable network time synchronization" | |
arch-chroot /mnt timedatectl set-ntp 1 | |
info "Set timezone to $_TIMEZONE" | |
arch-chroot /mnt timedatectl set-timezone $_TIMEZONE | |
} | |
function conf_hostname() { | |
info "Set hostname to $_HOSTNAME" | |
arch-chroot /mnt hostnamectl set-hostname $_HOSTNAME | |
} | |
function conf_keymap() { | |
info "Set keymap to $_KEYMAP" | |
arch-chroot /mnt printf "%s" "KEYMAP=$_KEYMAP" > /etc/vconsole.conf | |
} | |
function conf_hosts() { | |
info "Write hosts file" | |
arch-chroot /mnt printf "%s\n" \ | |
"127.0.0.1 localhost" \ | |
"::1 localhost" \ | |
"127.0.1.1 $_HOSTNAME.localdomain $_HOSTNAME" \ | |
>> /etc/hosts | |
} | |
function conf_mkinitcpio() { | |
title "Edit mkinitcpio configuration" | |
local mkinitcpio_hooks="base systemd sd-vconsole modconf keyboard keymap block filesystems btrfs sd-encrypt fsck" | |
arch-chroot /mnt sed -i "s/MODULES=()/MODULES=($MODULES)/" /etc/mkinitcpio.conf | |
# set hooks | |
arch-chroot /mnt sed -i "s/HOOKS=.*/HOOKS=\"$mkinitcpio_hooks\"/g" /etc/mkinitcpio.conf | |
# recreate initramfs image | |
arch-chroot /mnt mkinitcpio -P | |
} | |
function conf_custom() { | |
info "Edit pacman.conf to colorize output" | |
uncomment "Color" /mnt/etc/pacman.conf | |
} | |
function new_user() { | |
title "Add new user $_USER" | |
if [[ -n $_USER ]]; then | |
arch-chroot /mnt useradd -m -G wheel,storage,optical $_USER | |
if ! [[ -z $_SHELL ]]; then | |
arch-chroot /mnt usermod -s /usr/bin/$_SHELL $_USER | |
fi | |
printf "$_USER_PASSWD\n$_USER_PASSWD_RETYPE" | arch-chroot /mnt passwd $_USER | |
printf "%s" "%wheel ALL=(ALL:ALL) ALL" >> /mnt/etc/sudoers | |
fi | |
} | |
function enable_services() { | |
title "Enabling systemd services" | |
arch-chroot /mnt systemctl enable NetworkManager.service | |
if [[ -n $_WINDOW_MANAGER ]]; then | |
info "Enabling $_WINDOW_MANAGER" | |
case "$_WINDOW_MANAGER" in | |
gdm) | |
arch-chroot /mnt systemctl enable gdm.service | |
;; | |
lightdm) | |
arch-chroot /mnt systemctl enable lightdm.service | |
;; | |
sddm) | |
arch-chroot /mnt systemctl enable sddm.service | |
;; | |
esac | |
fi | |
if [[ $_BLUETOOTH = true ]]; then | |
info "Enabling bluetooth" | |
arch-chroot /mnt systemctl enable bluetooth.service | |
fi | |
} | |
function bootloader_refind() { | |
title "installing refind bootloader" | |
local part_system_uuid="" | |
if [[ $_ERASE_DRIVE = false ]]; then | |
part_system_uuid=$(trim $(lsblk -fsno UUID $_PART_SYSTEM)) | |
else | |
part_system_uuid=$(trim $(lsblk -fsno UUID ${_DRIVE}3)) | |
fi | |
local subvol_root_uuid=$(trim $(blkid --output value --match-tag UUID /dev/mapper/system)) | |
# backup existing conf | |
mv /mnt/boot/EFI/refind/refind.conf /mnt/boot/EFI/refind/refind.bak | |
arch-chroot /mnt refind-install | |
printf "%s\n" \ | |
"timeout 20" \ | |
"use_graphics_for windows # Specify the simpler mac-style behaviour" \ | |
"also_scan_dirs +,@/ # Search for boot loaders in the specified directory" \ | |
> /mnt/boot/EFI/refind/refind.conf | |
printf "%s" "\"Boot with standard options\" \"rd.luks.name=$part_system_uuid=cryptsystem root=UUID=$subvol_root_uuid rootflags=subvol=root initrd=/${_CPU}-ucode.img initrd=/initramfs-linux.img\"" \ | |
> /mnt/boot/refind_linux.conf | |
} | |
function fstab() { | |
title "Generating fstab" | |
# Identify partition with labels | |
genfstab -L -p /mnt >> /mnt/etc/fstab | |
# fix fstab so swap partition can be found again | |
arch-root /mnt sed -i s+LABEL=swap+/dev/mapper/swap+ /etc/fstab | |
# tell crypttab which partition to mount | |
printf "\n%s" "swap /dev/disk/by-partlabel/cryptswap /dev/urandom swap,cipher=aes-cbc-essiv:sha256,size=256" >> /mnt/etc/crypttab | |
} | |
function check_internet() { | |
if nc -zw1 $_SERVER_TEST 443 && printf | openssl s_client -connect $_SERVER_TEST:443 2>&1 |awk ' | |
handshake && $1 == "Verification" { if ($2=="OK") exit; exit 1 } | |
$1 $2 == "SSLhandshake" { handshake = 1 }' | |
then | |
info "Connected to internet!" | |
return 0 | |
fi | |
} | |
function check_packages_exists() { | |
title "Check if packages exists" | |
pacman -Sy | |
for package in $_PKGS; do | |
info "Checking for $package in packages" | |
if ! pacman -Si $package >/dev/null; then | |
info "Checking for $package in groups" | |
if ! pacman -Sg $package >/dev/null; then | |
on_exit error "Package $package was not found in repositories!" | |
printf "\n" | |
exit 1 | |
fi | |
fi | |
done | |
printf "\n" | |
} | |
function sanitize() { | |
title "Sanitize variables" | |
_PART_EFI_SIZE=$(sanitize_var "$_PART_EFI_SIZE") | |
_PART_SWAP_SIZE=$(sanitize_var "$_PART_SWAP_SIZE") | |
_PART_SYSTEM_LABEL=$(sanitize_var "$_PART_SYSTEM_LABEL") | |
_PART_SWAP_LABEL=$(sanitize_var "$_PART_SWAP_LABEL") | |
_DRIVE=$(sanitize_var "$_DRIVE") | |
_AVAILABLE_LANGUAGES=$(sanitize_var "$_AVAILABLE_LANGUAGES") | |
_SYSTEM_LANGUAGE=$(sanitize_var "$_SYSTEM_LANGUAGE") | |
_HOSTNAME=$(sanitize_var "$_HOSTNAME") | |
_PART_SWAP_SIZE=$(sanitize_var "$_PART_SWAP_SIZE") | |
_ROOT_PASSWD=$(sanitize_var "$_ROOT_PASSWD") | |
_BOOTLOADER=$(sanitize_var "$_BOOTLOADER") | |
_USER=$(sanitize_var "$_USER") | |
_DESKTOP=$(sanitize_var "$_DESKTOP") | |
_WINDOW_MANAGER=$(sanitize_var "$_WINDOW_MANAGER") | |
_DISPLAY_DRIVER=$(sanitize_var "$_DISPLAY_DRIVER") | |
_CPU=$(sanitize_var "$_CPU") | |
_DE=$(sanitize_var "$_DE") | |
} | |
function check() { | |
title "Check variables" | |
# if ! check_internet; then | |
# on_exit error "No internet connection!" | |
# exit 1 | |
# fi | |
check_var_value error "_AVAILABLE_LANGUAGES" "$_AVAILABLE_LANGUAGES" | |
check_var_value error "_SYSTEM_LANGUAGE" "$_SYSTEM_LANGUAGE" | |
check_var_value error "_HOSTNAME" "$_HOSTNAME" | |
check_var_value error "_PART_SWAP_SIZE" "$_PART_SWAP_SIZE" | |
check_var_value error "_ROOT_PASSWD" "$_ROOT_PASSWD" | |
check_var_value error "_CRYPT_PASSWD" "$_CRYPT_PASSWD" "Partition must be encrypted" | |
check_var_value error "_BOOTLOADER" "$_BOOTLOADER" | |
check_var_value error "_DISPLAY_DRIVER" "$_DISPLAY_DRIVER" | |
check_var_bool error "_ERASE_DRIVE" "$_ERASE_DRIVE" | |
check_var_bool error "_BLUETOOTH" "$_BLUETOOTH" | |
check_var_bool error "_AUR" "$_AUR" | |
check_var_bool error "_DESKTOP" "$_DESKTOP" | |
if [[ $_ERASE_DRIVE = false ]]; then | |
check_var_value error "_PART_EFI" "$_PART_EFI" "EFI partition needed since _ERASE_DRIVE is false" | |
check_var_value error "_PART_SWAP" "$_PART_SWAP" "swap partition needed since _ERASE_DRIVE is false" | |
check_var_value error "_PART_SYSTEM" "$_PART_SYSTEM" "system partition needed since _ERASE_DRIVE is false" | |
else | |
check_var_value error "_PART_EFI_SIZE" "$_PART_EFI_SIZE" "EFI partition size needed since _ERASE_DRIVE is true" | |
check_var_value error "_PART_SWAP_SIZE" "$_PART_SWAP_SIZE" "swap partition size needed since _ERASE_DRIVE is true" | |
check_var_value error "_PART_SYSTEM_LABEL" "$_PART_SYSTEM_LABEL" "system partition label size needed since _ERASE_DRIVE is true" | |
check_var_value error "_PART_SWAP_LABEL" "$_PART_SWAP_SIZE" "swap partition label size needed since _ERASE_DRIVE is true" | |
check_var_value error "_DRIVE" "$_DRIVE" "drive needed since _ERASE_DRIVE is true" | |
fi | |
if ! check_var_value warning "_USER" "$_USER" "No new user will be created (not recommended)"; then | |
check_var_value error "_USER_PASSWD" " "$_USER_PASSWD"" | |
check_var_equals error "_USER_PASSWD" "_USER_PASSWD_RETYPE" "$_USER_PASSWD" "$_USER_PASSWD_RETYPE" | |
fi | |
check_var_equals error "_CRYPT_PASSWD" "_CRYPT_PASSWD_RETYPE" "$_CRYPT_PASSWD" "$_CRYPT_PASSWD_RETYPE" | |
check_var_match error "_CPU" "$_CPU" "^(intel|amd)$" | |
check_var_match error "_BOOTLOADER" "$_BOOTLOADER" "^refind-efi$" | |
if [[ $_DESKTOP = true ]]; then | |
check_var_match warning "_DE" "$_DE" "^(kde|gnome|xfce)$" | |
if [[ -z $_WINDOW_MANAGER ]]; then | |
warning_keep "You installed a desktop environment without a window manager" | |
fi | |
fi | |
check_packages_exists | |
} | |
# Called first in entry point. Set all necessary things | |
# No arguments | |
function init () { | |
# Bash will remember & return the highest exitcode in a chain of pipes. | |
# This way you can catch the error in case mysqldump fails in `mysqldump | gzip`, for example. | |
set -o pipefail | |
# Enable extended globbing (used in option parsing) | |
shopt -s extglob | |
# Call finalize when script exit (whatever the return code) | |
trap 'finalize' EXIT INT TERM | |
touch "$OUT_END" "$OUT_TMP" "$LOG_FILE" | |
# variables sanitizer | |
sanitize | |
_prepare_locking | |
exlock_now | |
} | |
# Called on EXIT | |
# Used to print messages on exit | |
# Arguments : Exit cause | |
function finalize () { | |
title "Script complete!" | |
if [[ -f "$OUT_END" ]]; then | |
cat "$OUT_END" | |
fi | |
if [[ $LOG = true ]]; then | |
printf "\n" | |
info "See logs in ${LOG_FILE}" | |
info "See all output in ${DEBUG_LOG_FILE}" | |
else | |
rm --force "$LOG_FILE" | |
fi | |
rm --recursive --force --dir "$TEMP_DIR" | |
_no_more_locking | |
} | |
############################################################ | |
# Entry point | |
############################################################ | |
PROGNAME="$(trim ${PROGNAME%.*})" # name.sh ==> name, and then trim the string | |
############### | |
# Parsing | |
############### | |
# First parsing to priority options | |
for option in $@; do | |
case $option in | |
--debug) | |
set -x | |
;; | |
--strict) | |
set -o nounset | |
;; | |
--no-logs) | |
LOG="false" | |
;; | |
--quiet) | |
QUIET="true" | |
;; | |
--noconfirm) | |
NOCONFIRM="true" | |
;; | |
--lock) | |
LOCK="true" | |
;; | |
-h|--help) | |
usage | |
exit | |
;; | |
--) # End of all options. | |
shift | |
break | |
;; | |
*) # Default case: No more options, so break out of the loop. | |
continue | |
esac | |
done | |
# Drop lock if not wanted | |
if [[ $LOCK = false ]]; then | |
unlock | |
fi | |
init | |
# Second parsing | |
while :; do | |
case $1 in | |
# Catch unknow options except all priority options (require extended globbing). | |
$priority_options_pattern) | |
shift | |
continue | |
;; | |
--check|-c) | |
set_packages | |
check | |
print_kept_logs | |
clear_kept_logs | |
exit | |
;; | |
--partition|-p) | |
part_create | |
exit | |
;; | |
--format|-f) | |
part_format | |
exit | |
;; | |
--mount|-m) | |
part_mount | |
exit | |
;; | |
--umount|u) | |
part_umount | |
exit | |
;; | |
-?*) | |
usage "Invalid option $1" | |
exit | |
;; | |
# End of all options. | |
--) | |
shift | |
break | |
;; | |
# Default case: No more options, so break out of the loop. | |
*) | |
break | |
esac | |
shift | |
done | |
############### | |
# Installation | |
############### | |
# checks | |
set_packages | |
check | |
print_kept_logs | |
prompt_yes_no "Do you want to continue?" || exit 1 | |
# partitions | |
part_prepare | |
part_create | |
part_format | |
part_mount | |
title "Install base packages" | |
pacstrap /mnt base base-devel linux linux-firmware | |
# base configuration | |
title "Base configuration" | |
info "Set root password" | |
printf "$_ROOT_PASSWD\n$_ROOT_PASSWD_RETYPE" | arch-chroot /mnt passwd | |
conf_locale | |
conf_time_date | |
conf_hostname | |
conf_keymap | |
conf_hosts | |
conf_custom | |
# Install packages | |
title "Installing packages" | |
pacman_install "btrfs-progs networkmanager $_PKGS" | |
# post install config | |
new_user | |
enable_services | |
bootloader_refind | |
packages_aur | |
conf_mkinitcpio |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment