2022-07-30 03:36:33 -05:00
#!/bin/bash
set -eo pipefail
confirmation( ) {
local message
message = " ${ 1 } "
local choice
while :; do
printf "%s (Y/n) " " ${ message } "
read -r choice
case " ${ choice } " in
y | Y)
return 0
; ;
n | N)
return 1
; ;
2022-07-30 05:35:29 -05:00
*) printf "\nInput must be either y, Y, n, or N\n" ; ;
2022-07-30 03:36:33 -05:00
esac
done
}
print-break( ) {
2022-07-30 04:04:46 -05:00
local green
2022-07-30 03:36:33 -05:00
green = " $( tput setaf 2) "
local reset
reset = " $( tput sgr0) "
printf " ${ green } %.s─ ${ reset } " $( seq 1 " $( tput cols) " )
}
print-title( ) {
local title
title = " ${ * } "
local bold
bold = " $( tput bold) "
local underline
underline = " $( tput smul) "
local cyan
cyan = " $( tput setaf 6) "
local reset
reset = " $( tput sgr0) "
printf "%s%s%s%s%s\n" " ${ bold } " " ${ underline } " " ${ cyan } " " ${ title } " " ${ reset } " >& 2
}
echo-rgb( ) {
# Echo a colored string to the terminal based on rgb values
#
# Positional Arguments:
#
# message <type: string> <position: 1> <required: true>
# - The message to be printed to stdout
# red <type: int> <position: 2> <required: true>
# - The red value from 0 to 255
# green <type: int> <position: 3> <required: true>
# - The green value from 0 to 255
# blue <type: int> <position: 4> <required: true>
# - The blue value from 0 to 255
#
# Usage:
# echo-rgb "Yep" 10 8 30
#
# POSIX Compliant:
# N/A
#
local red
local green
local blue
local input
input = " ${ 1 } "
red = " ${ 2 } "
green = " ${ 3 } "
blue = " ${ 4 } "
printf "\e[0;38;2;%s;%s;%sm%s\e[m\n" " ${ red } " " ${ green } " " ${ blue } " " ${ input } "
}
important( ) {
echo-rgb " ${ 1 } " 135 195 255
}
log( ) {
# Print a message and send it to stdout or stderr depending upon log level, also configurable with debug etc.
#
# Arguments:
# level <type: string> <position: 1> <required: true>
# - The log level, defined within a case check in this function
# message <type: string> <position: 2> <required: true>
# - The info message
# line_number <type: int> <position: 3> <required: false>
# - The line number of the calling function (${LINNO})
#
# Usage:
# log "info" "Could not find that directory"
#
# POSIX Compliant:
# Yes
#
# Set debug status depending if a global debug variable has been set to either 1 or 0
local debug
if [ ${ DEBUG } ] ; then
debug = ${ DEBUG }
else
debug = 0
fi
local FORMAT
FORMAT = " [ $( echo-rgb " $( date +%Y-%m-%dT%H:%M:%S) " 180 140 255) ] "
# Convert the level to uppercase
local level
level = $( echo " ${ 1 } " | tr '[:lower:]' '[:upper:]' )
local message
message = " ${ 2 } "
case " ${ level } " in
INFO)
# Output all info log levels to stdout
printf " ${ FORMAT } [ $( echo-rgb "INFO" 0 140 255) ] %s\n " " ${ message } " >& 2
return 0
; ;
WARN | WARNING)
# Output all warning log levels to stdout
printf " ${ FORMAT } [ $( echo-rgb "WARNING" 255 255 0) ] %s\n " " ${ message } " >& 2
return 0
; ;
DEBUG)
# Output all debug log levels to stdout
if [ " ${ DEBUG } " ] ; then
printf " ${ FORMAT } [ $( echo-rgb "DEBUG" 0 160 110) ] %s\n " " ${ message } " >& 2
fi
return 0
; ;
ERROR)
# Output all error log levels to stderr
printf " ${ FORMAT } [ $( echo-rgb "ERROR" 255 0 0) ] %s\n " " ${ message } " >& 2
return 0
; ;
# Further log levels can be added by extending this switch statement with more comparisons
*) # Default case, no matches
# Returns non-zero code as an improper log option was passed, this helps with using `set -e`
printf " ${ FORMAT } [ERROR] %s\n " " Invalid log level passed, received level \" ${ level } \" with message \" ${ message } \" " >& 2
return 1
; ;
esac
}
get-available-disks( ) {
local available_disks = ( )
local disk_line
local disk
while read -r; do
# tr is used to change multiple whitespaces into a single space for processing by cut
disk_line = " $( printf "%s" " ${ REPLY } " | tr -s " " ) "
disk = $( printf "%s" " ${ disk_line } " | cut -d " " -f2)
if [ [ " ${ disk } " = "disk" ] ] ; then
available_disks += ( " $( printf "/dev/%s" " ${ disk_line } " | cut -d " " -f1) " )
fi
done <<< " $( lsblk --output NAME,TYPE) "
2022-07-30 05:31:04 -05:00
printf "%s" " ${ available_disks [*] } "
2022-07-30 03:36:33 -05:00
}
get-disk-partitions( ) {
local disk = " ${ 1 } "
if [ [ -z " ${ disk } " ] ] ; then
log "error" "No disk passed!"
return 1
fi
if ! blkid | grep " ${ disk } " >/dev/null; then
return 1
fi
local partitions
IFS = $'\n' partitions = ( " $( blkid -o device | grep " ${ disk } " ) " )
printf "%s" " ${ partitions [@] } "
}
check-connectivity( ) {
if ! host "google.com" >/dev/null; then
log "error" "Unable to reach google, network is down. This script requires network connectivity with active DNS resolution"
return 1
fi
}
select -item( ) {
local item_name = " ${ 1 } "
shift
local items
# shellcheck disable=2206
items = ( $@ )
local item_selected
while :; do
local count = 1
for item in " ${ items [@] } " ; do
printf "%s %s\n" " ${ count } .) " " $( important " ${ item } " ) " >& 2
count = $(( count + 1 ))
done
count = 1
read -rp " Select a ${ item_name } number: " item_selected
case " ${ item_selected } " in
'' | *[ !0-9] *)
log "error" "A number was not passed"
continue
; ;
esac
for item in " ${ items [@] } " ; do
# printf -- "--> %s | %s\n" "${item_selected}" "${count}"
if [ [ ${ count } -eq ${ item_selected } ] ] ; then
printf "%s" " ${ item } "
return 0
fi
count = " $(( count + 1 )) "
done
log "error" " Invalid selection made, received: \" ${ item_selected } \" "
done
}
partition-disk( ) {
local disk = " ${ 1 } "
(
echo n
echo " ${ BOOT_PARTITION_NUMBER } "
echo
echo +512M
echo ef00
echo n
echo " ${ ROOT_PARTITION_NUMBER } "
echo
echo
echo 8300
echo w
echo Y
) | gdisk " ${ disk } " >/dev/null
mkfs.vfat -F32 -n EFI " ${ disk } " *" ${ BOOT_PARTITION_NUMBER } "
}
main( ) {
local ARCH_TIMEZONE = "CST"
local LOCALE = "en_US.UTF-8 UTF-8"
local LANG = "en_US.UTF-8"
local DISK_PARTITION_LETTER = ""
local HOSTNAME = "Arch-Linux"
local MICROCODE = "amd"
clear
if ! check-connectivity; then
exit 1
fi
2022-07-30 04:06:11 -05:00
print-title "Install Needed PGP Keys"
2022-07-30 04:13:37 -05:00
pacman -Syy --noconfirm
pacman -S --noconfirm archlinux-keyring
2022-07-30 04:06:11 -05:00
print-break
2022-07-30 03:36:33 -05:00
local selected_disk
local i_selected_disk
while :; do
print-title "Select the installation disk"
selected_disk = " $( select -item "disk" " $( get-available-disks) " ) "
i_selected_disk = " $( important " ${ selected_disk } " ) "
if confirmation " Is ${ i_selected_disk } the correct disk to install to? " ; then
break
fi
done
printf "Disk set as %s\n" " ${ i_selected_disk } " >& 2
print-break
print-title "Partition Creation"
export BOOT_PARTITION_NUMBER = 120
export ROOT_PARTITION_NUMBER = 121
if ! confirmation " Begin installation of Arch Linux to ${ i_selected_disk } ? " ; then
printf "Install request denied, exiting..." >& 2
exit 0
fi
printf "Writing new partitions to %s\n" " ${ i_selected_disk } " >& 2
partition-disk " ${ selected_disk } "
local boot_partion = " ${ selected_disk } ${ DISK_PARTITION_LETTER } ${ BOOT_PARTITION_NUMBER } "
local root_partition = " ${ selected_disk } ${ DISK_PARTITION_LETTER } ${ ROOT_PARTITION_NUMBER } "
2022-07-30 04:04:46 -05:00
mkfs.vfat -F32 -n EFI " ${ boot_partion } "
printf "Successfully wrote partitions to %s\n" " ${ i_selected_disk } " >& 2
2022-07-30 03:36:33 -05:00
print-break
print-title "Partition Encryption"
printf "Encrypting %s\n" " $( important " ${ root_partition } " ) " >& 2
cryptsetup -y -v luksFormat " ${ root_partition } " || exit
printf "Opening encrypted device %s\n" \
2022-07-30 04:04:46 -05:00
" $( important " ${ root_partition } " ) " >& 2
2022-07-30 03:36:33 -05:00
cryptsetup open " ${ root_partition } " cryptroot || exit
2022-07-30 04:04:46 -05:00
printf "Configuring LVM\n" >& 2
pvcreate /dev/mapper/cryptroot
vgcreate vg0 /dev/mapper/cryptroot
lvcreate --size 16G vg0 --name swap
lvcreate -l +100%FREE vg0 --name root
printf "Writing filesystems\n" >& 2
mkfs.ext4 -L root "/dev/mapper/vg0-root"
mkswap /dev/mapper/vg0-swap
2022-07-30 03:36:33 -05:00
print-break
print-title "Install Arch Into Encrypted Volume"
printf "Mounting Needed Directores\n" >& 2
2022-07-30 04:04:46 -05:00
mount /dev/mapper/vg0-root /mnt
swapon /dev/mapper/vg0-swap
2022-07-30 03:36:33 -05:00
mkdir /mnt/boot
mount " ${ boot_partion } " /mnt/boot
printf "Doing Pacstrap\n" >& 2
pacstrap /mnt linux linux-firmware base base-devel grub efibootmgr vim git " ${ MICROCODE } " -ucode networkmanager
genfstab -U /mnt >>/mnt/etc/fstab
print-break
print-title "Configure System"
printf "Entering Chroot\n" >& 2
arch-chroot /mnt <<-__END_CHROOT_CMDS__
2022-07-30 04:26:07 -05:00
printf "Setting default password as toor\n"
2022-07-30 03:36:33 -05:00
printf "toor\ntoor\n" | passwd
printf "Linking timezone as %s\n" " $( important " ${ ARCH_TIMEZONE } " ) " >& 2
ln -sf " /usr/share/zoneinfo/ ${ ARCH_TIMEZONE } " "/etc/localtime"
printf "Setting Hardware Clock\n" >& 2
hwclock --systohc
printf "Setting LOCALE to %s\n" " $( important " ${ LOCALE } " ) " >& 2
printf "%s\n" " ${ LOCALE } " >/etc/locale.gen
printf "Generting Locale\n" >& 2
locale-gen
printf "Setting LANG to %s\n" " $( important " ${ LANG } " ) " >& 2
printf "%s\n" " ${ LANG } " >>/etc/locale.conf
printf "Setting HOSTNAME to %s\n" " $( important " ${ HOSTNAME } " ) "
printf "%s\n" " ${ HOSTNAME } " >>/etc/hostname
printf "Set mkinitcipio hooks\n" >& 2
sed -i 's/HOOKS=.*/HOOKS=(base udev autodetect keyboard modconf block encrypt filesystems fsck)/' /etc/mkinitcpio.conf
mkinitcpio -P
printf "Configure Grub\n" >& 2
yes | pacman -S grub efibootmgr intel-ucode amd-ucode
2022-07-30 05:40:03 -05:00
sed -i " s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"cryptdevice=UUID= $( blkid -s UUID -o value " ${ root_partition } " ) :cryptroot root=\/dev\/mapper\/cryptroot\"/ " /etc/default/grub
2022-07-30 04:44:55 -05:00
printf "GRUB_ENABLE_CRYPTO_DISK=y\n" >> /etc/default/grub
2022-07-30 03:36:33 -05:00
grub-install --target= x86_64-efi --efi-directory= /boot --bootloader-id= GRUB
grub-mkconfig -o /boot/grub/grub.cfg
printf "Setting up networkmanager\n" >& 2
yes | pacman -S networkmanager
systemctl enable NetworkManager
__END_CHROOT_CMDS__
print-break
2022-07-30 04:13:37 -05:00
printf "%s\n\tUsername: root\n\tPassword: toor\n" " $( important "Finished with installation, login is:" ) "
2022-07-30 03:36:33 -05:00
}
main