dotfiles/arch_install

708 rindas
15 KiB
Bash
Executable File

#!/bin/bash
#
set -e
echo (){
/bin/echo "#########################################"
/bin/echo "$@"
/bin/echo "#########################################"
}
#LICENSE#{{{
# Copyright (c) 2012 Tom Wambold
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#}}}
# CONFIGURE THESE VARIABLES{{{
# Drive to install to.
DRIVE='/dev/sda'
# Hostname of the installed machine.
HOSTNAME='arch'
# Encrypt everything (except /boot). true or false
ENCRYPT_DRIVE=true
# Passphrase used to encrypt the drive (leave blank to be prompted).
DRIVE_PASSPHRASE=''
# Root password (leave blank to be prompted).
ROOT_PASSWORD=''
# Main user to create (by default, added to wheel group, and others).
USER_NAME='lelgenio'
# Link to users dotfiles repo(git)
# Assumed to have stow-able modules on its root(cd .dotfiles;stow*/)
DOTFILES_URL="https://gitlab.com/$USER_NAME/dotfiles"
USER_SHELL='fish'
# The main user's password (leave blank to be prompted).
USER_PASSWORD=''
# System timezone.
TIMEZONE='America/Sao_Paulo'
# Country code for pacman repos
COUNTRY='brazil'
# Have /tmp on a tmpfs or not. Leave blank to disable.
# Only leave this blank on systems with very little RAM.
TMP_ON_TMPFS='TRUE'
KEYMAP='br-abnt2'
# KEYMAP='dvorak'
LANG=pt_BR.UTF-8
#}}}
# Initial Setup{{{
# Base install{{{
setup() {
local boot_dev="$DRIVE"1
if "$ENCRYPT_DRIVE"
then
local crypt_dev="$DRIVE"2
local lvm_dev="/dev/mapper/lvm"
else
local lvm_dev="$DRIVE"2
fi
echo 'Cleaning disk'
disk_clean "$lvm_dev" "$DRIVE"2
echo 'Creating partitions'
partition_drive "$DRIVE"
if "$ENCRYPT_DRIVE"
then
if [ -z "$DRIVE_PASSPHRASE" ];then
echo 'Enter a passphrase to encrypt the disk:'
read -s DRIVE_PASSPHRASE
fi
echo 'Encrypting partition'
encrypt_drive "$crypt_dev" "$DRIVE_PASSPHRASE" lvm
fi
echo 'Setting up LVM'
setup_lvm "$lvm_dev" vg00
echo 'Formatting filesystems'
format_filesystems "$boot_dev"
echo 'Mounting filesystems'
mount_filesystems "$boot_dev"
echo 'Setting repos'
set_repos
echo 'Installing base system'
install_base
echo 'Setting fstab'
set_fstab
echo 'Chrooting into installed system to continue setup...'
cp "$0" "/mnt/setup.sh"
chmod +x "/mnt/setup.sh"
arch-chroot /mnt "./setup.sh"
if [ -f "/mnt/setup.sh" ];then
echo 'ERROR: Something failed inside the chroot, not unmounting filesystems so you can investigate.'
echo 'Make sure you unmount everything before you try to run this script again.'
else
echo 'Unmounting filesystems'
unmount_filesystems
echo 'Done! Reboot system.'
fi
}
#}}}
# Remove old LVMs{{{
disk_clean(){
local lvm_dev="$1"
local disk="$2"
echo 'cleaning disk'
umount --recursive --quiet /mnt || true
swapoff -a
pvs "$lvm_dev" || return 0
for vg in $(pvs -o vg_name --nohead "$lvm_dev")
do
vgremove "$vg" --yes
done
pvremove "$lvm_dev"
if "$ENCRYPT_DRIVE"
then
cryptsetup close lvm
fi
wipefs -a "$disk"
}
#}}}
# Partition Drive{{{
partition_drive() {
local dev="$1"; shift
# 100 MB /boot partition, everything else under LVM
if $IS_BIOS;then
parted \
--align optimal \
--script "$dev" \
mklabel msdos \
mkpart primary fat32 1M 100M \
mkpart primary ext4 100M 100% \
set 1 boot on \
set 2 lvm on
else
parted \
--align optimal \
--script "$dev" \
mklabel gpt \
mkpart boot 1 100M \
mkpart lvm 100M 100% \
set 1 boot on \
set 2 lvm on
fi
}
#}}}
# Encrypt_drive {{{
encrypt_drive() {
local dev="$1"; shift
local passphrase="$1"; shift
local name="$1"; shift
/bin/echo -en "$passphrase" | cryptsetup luksFormat "$dev"
/bin/echo -en "$passphrase" | cryptsetup luksOpen "$dev" lvm
}
#}}}
# setup_lvm{{{
setup_lvm() {
local partition="$1"; shift
local volgroup="$1"; shift
local d_size=$(lsblk --noheadings --nodeps --bytes --raw --output SIZE $DRIVE)
local swap_size=$(free -b | awk '/^Mem/ { printf "%.0fG", 2*$2*10**-9}')
pvcreate "$partition"
vgcreate "$volgroup" "$partition"
# Create a swap partition that is twice the amount of RAM
lvcreate --yes -L$swap_size "$volgroup" -n swap
# if the disk has more than 100Gb
if [ "$d_size" -gt $( echo "100*10^9" | bc ) ]
then
# Create a 50GB root partition
lvcreate --yes -L '50G' "$volgroup" -n root
else
# Create root partition on 50% of free space
lvcreate --yes -l '+50%FREE' "$volgroup" -n root
fi
# Use the rest of the space for home
lvcreate --yes -l '+100%FREE' "$volgroup" -n home
# Enable the new volumes
vgchange -ay
}
#}}}
# format_filesystems #{{{
format_filesystems() {
local boot_dev="$1"; shift
mkfs.fat "$boot_dev"
mkfs.ext4 -L root /dev/vg00/root
mkfs.ext4 -L home /dev/vg00/home
mkswap /dev/vg00/swap
}
#}}}
# mount_filesystems #{{{
mount_filesystems() {
local boot_dev="$1"; shift
mount /dev/vg00/root /mnt
mkdir /mnt/home
mount /dev/vg00/home /mnt/home
mkdir /mnt/boot
mount "$boot_dev" /mnt/boot
swapon /dev/vg00/swap
}
#}}}
# set_repos() {{{{
set_repos() {
# /etc/pacman.conf{{{
cat > /etc/pacman.conf <<EOF
#
# GENERAL OPTIONS
#
[options]
HoldPkg = pacman glibc
Architecture = auto
# Misc options
#UseSyslog
Color
ILoveCandy
#TotalDownload
CheckSpace
#VerbosePkgLists
SigLevel = Required DatabaseOptional
LocalFileSigLevel = Optional
#RemoteFileSigLevel = Required
#
# REPOSITORIES
#
#[testing]
#Include = /etc/pacman.d/mirrorlist
[core]
Include = /etc/pacman.d/mirrorlist
[extra]
Include = /etc/pacman.d/mirrorlist
#[community-testing]
#Include = /etc/pacman.d/mirrorlist
[community]
Include = /etc/pacman.d/mirrorlist
#[multilib-testing]
#Include = /etc/pacman.d/mirrorlist
[multilib]
Include = /etc/pacman.d/mirrorlist
EOF
#}}}
# /etc/pacman.d/mirrorlist{{{
pacman -Sy reflector --noconfirm --needed
reflector -c $COUNTRY -f 10 -p http -p https
#}}}
mkdir -p /mnt/etc/pacman.d
cp -r /mnt/etc/pacman* /etc/
}
#}}}
# install_base #{{{
install_base() {
pacstrap /mnt \
base base-devel linux-zen linux-firmware intel-ucode grub \
fish bluez cronie git man-db \
iwd dhcpcd
}
#}}}
# Set fstab {{{
set_fstab() {
genfstab -Up /mnt > /mnt/etc/fstab
}
#}}}
# Unmount filesystems #{{{
unmount_filesystems() {
umount -R /mnt
swapoff /dev/vg00/swap
vgchange -an
if $ENCRYPT_DRIVE
then
cryptsetup luksClose lvm
fi
}
#}}}
# is_bios{{{
if ls /sys/firmware/efi/efivars/ &> /dev/null
then
IS_BIOS=false
else
IS_BIOS=true
fi
#}}}
#}}}
# Configuration{{{
# configure() {#{{{
configure() {
local boot_dev="$DRIVE"1
local lvm_dev="$DRIVE"2
echo 'Setting hostname'
set_hostname "$HOSTNAME"
echo 'Setting timezone'
set_timezone "$TIMEZONE"
echo 'Setting locale'
set_locale
echo 'Setting console keymap'
set_inputs
echo 'Configuring initial ramdisk'
set_initcpio
echo 'Configuring Bluetooth'
set_bluetooth
echo 'Configuring bootloader'
set_bootctl "$boot_dev" "$lvm_dev"
echo 'Configuring sudo'
set_sudoers
echo 'Configuring PAM'
set_pam
echo 'Configuring logind'
set_logind
if [ -z "$ROOT_PASSWORD" ];then
echo 'Enter the root password:'
read -s ROOT_PASSWORD
fi
echo 'Setting root password'
set_root_password "$ROOT_PASSWORD"
if [ -z "$USER_PASSWORD" ];then
echo "Enter the password for user $USER_NAME"
read -s USER_PASSWORD
fi
echo 'Creating initial user'
create_user "$USER_NAME" "$USER_PASSWORD"
echo 'setting up user'
cp $0 "/home/$USER_NAME/setup.sh"
chown $USER_NAME "/home/$USER_NAME/setup.sh"
su $USER_NAME -c "/home/$USER_NAME/setup.sh"
shred "/home/$USER_NAME/setup.sh"
rm "/home/$USER_NAME/setup.sh"
echo 'Setting initial daemons'
set_daemons "$TMP_ON_TMPFS"
echo 'Updating pkgfile database'
update_pkgfile
}
#}}}
# set_hostname() {#{{{
set_hostname() {
local hostname="$1"; shift
/bin/echo "$hostname" > /etc/hostname
cat > /etc/hosts <<EOF
127.0.0.1 localhost.localdomain localhost $hostname
::1 localhost.localdomain localhost $hostname
EOF
}
#}}}
# set_timezone() {#{{{
set_timezone() {
local timezone="$1"; shift
ln -sfT "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime
timedatectl set-ntp on
hwclock --systohc || echo FAILED TO SET HW CLOCK
}
#}}}
# set_locale() {#{{{
set_locale() {
cat > /etc/locale.conf <<EOF
LANG=$LANG
LC_COLLATE=C
EOF
cat > /etc/locale.gen <<EOF
en_US.UTF-8 UTF-8
$LANG UTF-8
EOF
locale-gen
}
#}}}
# set_inputs() {#{{{
set_inputs() {
localectl set-keymap $KEYMAP
mkdir -p /etc/X11/xorg.conf.d/
cat > /etc/X11/xorg.conf.d/30-touchpad.conf <<EOF
Section "InputClass"
MatchIsTouchpad "on"
Identifier "devname"
Driver "libinput"
Option "Tapping" "on"
Option "ClickMethod" "clickfinger"
Option "NaturalScrolling" "true"
EndSection
EOF
}
#}}}
# set_initcpio() {#{{{
set_initcpio() {
local vid
if [ "$VIDEO_DRIVER" = "i915" ];then
vid='i915'
elif [ "$VIDEO_DRIVER" = "nouveau" ];then
vid='nouveau'
elif [ "$VIDEO_DRIVER" = "radeon" ];then
vid='radeon'
fi
local encrypt=""
if $ENCRYPT_DRIVE
then
encrypt="encrypt keyboard"
fi
cat > /etc/mkinitcpio.conf <<EOF
# vim:set ft=sh
MODULES=(ext4 $vid)
BINARIES=()
FILES=()
HOOKS=(base udev autodetect block $encrypt lvm2 filesystems fsck)
EOF
# Intall kernel, if necessary
[ -f /boot/vmlinuz-linux-zen ] ||
mkinitcpio -P
}
#}}}
# set_daemons() {#{{{
set_daemons() {
local tmp_on_tmpfs="$1"; shift
if [ -z "$tmp_on_tmpfs" ];then
systemctl mask tmp.mount
fi
systemctl enable \
cronie.service \
iwd.service \
dhcpcd.service \
ly.service \
# Ly{{{
mkdir -p /etc/ly/
cat > /etc/ly/config.ini << EOF
animate = true
blank_box = true
hide_borders = true
lang = br
EOF
#}}}
}
#}}}
# set_bluetooth{{{
set_bluetooth() {
mkdir -p /etc/bluetooth/
cat > /etc/bluetooth/main.conf <<EOF
[General]
DiscoverableTimeout = 0
Discoverable = true
AlwaysPairable = true
[Policy]
AutoEnable=true
EOF
}
#}}}
# set_boot_loader() {{{
set_bootctl() {
local boot_dev="$1"; shift
local lvm_dev="$1"; shift
local lvm_uuid=$(get_uuid "/dev/vg00/root")
local k_args="root=UUID=$lvm_uuid"
if $IS_BIOS;then
cat >> /etc/default/grub <<EOF
GRUB_CMDLINE_LINUX_DEFAULT="$k_args"
# GRUB_CMDLINE_LINUX_DEFAULT="quiet splash loglevel=3 vga=current rd.udev.log_priority=3 rd.systemd.show_status=auto vt.global_cursor_default=0 nmi_watchdog=0 $k_args"
EOF
grub-install "$DRIVE"
grub-mkconfig -o /boot/grub/grub.cfg
else
bootctl install
cat > /boot/loader/entries/arch.conf <<EOF
title arch
linux vmlinuz-linux-zen
initrd intel-ucode.img
initrd initramfs-linux-zen.img
options $k_args
# options quiet splash loglevel=3 vga=current rd.udev.log_priority=3 rd.systemd.show_status=auto vt.global_cursor_default=0 nmi_watchdog=0
EOF
fi
}
#}}}
# set_sudoers() {#{{{
set_sudoers() {
cat > /etc/sudoers <<EOF
##
## User privilege specification
##
root ALL=(ALL) ALL
## Uncomment to allow members of group wheel to execute any command
# %wheel ALL=(ALL) ALL
## Same thing without a password
%wheel ALL=(ALL) NOPASSWD: ALL
## Read drop-in files from /etc/sudoers.d
## (the '#' here does not indicate a comment)
#includedir /etc/sudoers.d
EOF
chmod 440 /etc/sudoers
}
#}}}
# set_pam{{{
set_pam() {
cat > /etc/pam.d/system-local-login <<EOF
auth include system-login
account include system-login
password include system-login
session include system-login
auth optional pam_gnupg.so
session optional pam_gnupg.so
EOF
}
#}}}
# set_logind{{{
set_logind(){
mkdir -p /etc/systemd
cat > /etc/systemd/logind.conf <<EOF
[Login]
HandlePowerKey=suspend
HandleSuspendKey=suspend
HandleLidSwitch=ignore
EOF
}
#}}}
# set_root_password() {#{{{
set_root_password() {
local password="$1"; shift
/bin/echo -en "$password\n$password" | passwd
}
#}}}
# create_user() {#{{{
create_user() {
local name="$1"; shift
local password="$1"; shift
grep "^$name" /etc/passwd ||
useradd -m -s /usr/bin/$USER_SHELL -G adm,systemd-journal,wheel,rfkill,games,network,video,audio,optical,floppy,storage,scanner,power,input "$name"
/bin/echo -en "$password\n$password" | passwd "$name"
}
#}}}
# update_pkgfile() {#{{{
update_pkgfile() {
pkgfile -u
}
#}}}
# get_uuid() {#{{{
get_uuid() {
lsblk --noheadings --nodeps --output UUID "$1"
}
#}}}
# is_chroot(){{{{
is_chroot(){
test "$(ls -id / | cut -d' ' -f1)" == "2"
}
#}}}
#}}}
# User setup{{{
user_setup() {
echo 'Installing packages'
install_aur_packages
echo 'Installing dotfiles'
install_dots
}
# Install AUR helper #{{{
install_aur_packages() {
sudo pacman -S --needed git
# getting yay
if ! command -v yay
then
git clone http://aur.archlinux.org/yay.git ~/yay
cd ~/yay
makepkg -si --noconfirm
cd -
fi
}
#}}}
# Install dotfiles{{{
install_dots() {
if [ ! -d ~/.dotfiles ];then
git clone $DOTFILES_URL ~/.dotfiles
fi
if [ -f ~/.dotfiles/config.y*ml ]; then
dotdrop --cfg ~/.dotfiles/config.y*ml install --force --no-banner
fi
}
#}}}
#}}}
if [ ! "$USER" == "root" ];then
user_setup
elif is_chroot;then
configure
else
setup
fi
# vim:foldmethod=marker