Skip to content

Instantly share code, notes, and snippets.

@redeemed2011
Last active January 2, 2022 12:21
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save redeemed2011/3387d18d5e8f0274b0e3 to your computer and use it in GitHub Desktop.
Save redeemed2011/3387d18d5e8f0274b0e3 to your computer and use it in GitHub Desktop.
Arch Linux LUKS Encrypted / on Btrfs Raid 0 (Stripe) of 2 Drives

General

Info

!ATTENTION! This script is intentionally designed to completely wipe all data on at least two drives! !ATTENTION!

I used standard Arch Linux on two NVME drives. The goal was as much encryption as possible with the smallest performance impact possible.

Why did I make a script? Because I tire of typing these commands manually through this experiment.

Should you try it? That is up to you. The installer.sh is designed to wipe all data on two drives. This script is designed specifically for my personal laptop. Most likely one or more scripts in this gist are broken even on my personal laptop, because this is an experiment.

Why then is this gist public? GitHub's CDN started returning 404 errors on the raw source links for my gist's scripts. Making the gist public solved the issue.

Notes

At the time of this writing GRUB does not boot on NVME & EFI.

The Plan

  • NVMe drives should be aligned to 4KiB, which all partitioners seem to do now.
  • EFI partition on primary drive.
  • EXT4 boot partition on primary drive.
  • BTFS, RAID 0 (stripe).
  • Encrypted Swap on both drives, without hibernate because I'm unsure how to avoid dbl password entry at boot/resume (NYI).
  • dm_crypt for encryption, using AES-XTS, 256bit key, because benchmarks:
    • aes-xts 256b 3449.7 MiB/s 3435.7 MiB/s
    • aes-xts 512b 2732.7 MiB/s 2757.1 MiB/s
  • Only enter password once on boot, so use a modified mkinitcpio.

Sources

How To Use

Installer

  1. Boot your arch linux install media.
  2. Connect to the internet.
# View your connections.
ip link

# The dhcpcd daemon is enabled on boot for wired devices, and will attempt to start a connection.
# https://wiki.archlinux.org/index.php/beginners'_guide#Connect_to_the_Internet

# If not using wired, connect to wifi.
wifi-menu
  1. Download & run the script.
# Download and run the script.
wget https://gist.githubusercontent.com/redeemed2011/3387d18d5e8f0274b0e3/raw/ad6cad46e418e6eb2593612ba90a8028e9ce60bc/installer.sh -O setup.sh && sh setup.sh

Add WiFi

There is no gui for how we use wifi in this configuration. Currently you must do the following:

wpa_passphrase WIFI_SSID PASSWORD | sudo tee -a /etc/wpa_supplicant/wpa_supplicant.conf

Snapshot/Maintenance Script

Whenever you need to boot to a live arch disk or similar so that you may, say, rollback the root btrfs subvol to an earlier snapshot, download and run this script.

  1. Boot your arch linux install media.
  2. Connect to the internet.
# View your connections.
ip link

# The dhcpcd daemon is enabled on boot for wired devices, and will attempt to start a connection.
# https://wiki.archlinux.org/index.php/beginners'_guide#Connect_to_the_Internet

# If not using wired, connect to wifi.
wifi-menu
  1. Download & run the script.
# Download and run the script.
# NOTE: Short URL resolves to https://gist.github.com/redeemed2011/3387d18d5e8f0274b0e3/raw/open-btrfs-pool.sh
wget https://goo.gl/o7m4A9 -O open.sh && sh open.sh
  1. Delete the root subvolume (or rename it).
cd /mnt/btrfs-pool
btrfs subvol delete root
  1. Pick your snapshot. Snapshot info is available via the info.xml in each snapshot's root folder.
cat snapshots/root/1/info.xml
  1. Snapshots are read only, so make a new snapshot pointing to the now-non-existant root subvol.
btrfs subvol snapshot snapshots/root/1 root

KVM & VFIO

The follow options will need to be added the QEMU virtual machine script.

-enable-kvm \
-device vfio-pci,host=01:00.0,x-vga=on,multifunction=on \
-device vfio-pci,host=01:00.1 \

The host= will need to be set to the bus addresses of the devices being passed through. The video device will need x-vga=on in order to display video.

Because the video of the VM is on separate hardware, seemless keyboard/mouse integration will not work.

There are ways around losing the keyboard and mouse integration, like Synergy. Another option is to setup a dumb video device on the QEMU VM.

-device qxl \
-vga none \

This will create a qxl video device but not connected to any video driver. When kicking off the QEMU VM, QEMU will start up a blank video screen window. Clicking on the window will pass the keyboard and mouse to the VM. The mouse cursor will seem choppy in the VM but input is registered as normal.

KVM Example GPU VM

General KVM Script

#!/bin/bash

# QEMU name and PID
OPTS="-name windows-10-pro"
OPTS="$OPTS -pidfile /tmp/windows-10-pro.pid"

# Processor core2duo qemu64 host
OPTS="$OPTS -cpu qemu64,kvm=off"
OPTS="$OPTS -smp 8,sockets=1,cores=4,threads=2"
OPTS="$OPTS -enable-kvm"

# Machine
OPTS="$OPTS -machine type=pc-i440fx-2.1,accel=kvm"
#OPTS="$OPTS -machine type=q35,accel=kvm"

# The following setting enables S3 (suspend to RAM). OVMF supports S3
# suspend/resume. Disable when using Q35
OPTS="$OPTS -global PIIX4_PM.disable_s3=0"

# Memory
OPTS="$OPTS -m 8G"
OPTS="$OPTS -mem-path /dev/hugepages"
OPTS="$OPTS -mem-prealloc"
OPTS="$OPTS -balloon none"

# Hardware clock
OPTS="$OPTS -rtc clock=host,base=utc"

# Sound hardware
QEMU_PA_SAMPLES=128
export QEMU_AUDIO_DRV=pa
OPTS="$OPTS -soundhw hda"

# Graphic card passthrough (Gigabyte GeForce GTX 980 G1 Gaming)
OPTS="$OPTS -device vfio-pci,host=02:00.0,multifunction=on"
OPTS="$OPTS -device vfio-pci,host=02:00.1"

# USB 3.0 passthrough (NEC/Renesas)
#OPTS="$OPTS -usb -usbdevice host:0x03f0:0xd407"
#OPTS="$OPTS -usb -usbdevice host:0x1d6b:0x0003"
#OPTS="$OPTS -usb -usbdevice host:0x1a40:0x0101"

#OPTS="$OPTS -device vfio-pci,host=03:00.0"

# Keyboard layout
OPTS="$OPTS -k en-us"

# Boot priority
OPTS="$OPTS -boot order=c"

# OVMF
cp /usr/share/edk2.git/ovmf-x64/OVMF_VARS-pure-efi.fd /home/tanasaki/qemu/VMs/windows10/my_vars.fd
OPTS="$OPTS -drive if=pflash,format=raw,readonly,file=/usr/share/edk2.git/ovmf-x64/OVMF_CODE-pure-efi.fd"
OPTS="$OPTS -drive if=pflash,format=raw,file=/home/tanasaki/qemu/VMs/windows10/my_vars.fd"

# System drive
OPTS="$OPTS -drive id=disk0,if=none,cache=unsafe,format=raw,file=/home/tanasaki/qemu/VMs/windows10/windows10.img"
OPTS="$OPTS -device driver=virtio-scsi-pci,id=scsi0"
OPTS="$OPTS -device scsi-hd,drive=disk0"

# Other drive
#OPTS="$OPTS -drive id=disk1,if=none,cache=none,aio=native,format=raw,file=/dev/disk/by-id/ata-Hitachi_HDS721050CLA660_JP1570FR1ZWP7K"
#OPTS="$OPTS -device driver=virtio-scsi-pci,id=scsi1"
#OPTS="$OPTS -device scsi-hd,drive=disk1"

# Other drive 2
#OPTS="$OPTS -drive id=disk2,if=none,cache=none,aio=native,format=raw,file=/dev/disk/by-id/ata-Hitachi_HDS5C3020ALA632_ML0220F30NX2DD"
#OPTS="$OPTS -device driver=virtio-scsi-pci,id=scsi2"
#OPTS="$OPTS -device scsi-hd,drive=disk2"

# Windows 10 Pro installer
OPTS="$OPTS -drive id=cd0,if=none,format=raw,readonly,file=/home/tanasaki/qemu/OS_ISOs/Windows10/Windows10.iso"
OPTS="$OPTS -device driver=ide-cd,bus=ide.0,drive=cd0"

# Virtio driver
OPTS="$OPTS -drive id=virtiocd,if=none,format=raw,file=/home/tanasaki/qemu/OS_ISOs/virtio-win.iso"
OPTS="$OPTS -device driver=ide-cd,bus=ide.1,drive=virtiocd"

# OVMF emits a number of info / debug messages to the QEMU debug console, at
# ioport 0x402. We configure qemu so that the debug console is indeed
# available at that ioport. We redirect the host side of the debug console to
# a file.
#OPTS="$OPTS -global isa-debugcon.iobase=0x402 -debugcon file:/tmp/windows_10_pro.ovmf.log"

# QEMU accepts various commands and queries from the user on the monitor
# interface. Connect the monitor with the qemu process's standard input and
# output.
#OPTS="$OPTS -monitor stdio"

# A USB tablet device in the guest allows for accurate pointer tracking
# between the host and the guest.
#OPTS="$OPTS -device piix3-usb-uhci -device usb-tablet"

# Network
#OPTS="$OPTS -netdev tap,vhost=on,ifname=$VM,script=/usr/local/bin/vm_ifup_brlan,id=brlan"
#OPTS="$OPTS -device virtio-net-pci,mac=52:54:00:xx:xx:xx,netdev=brlan"

# Disable display
#OPTS="$OPTS -vga qxl"
#OPTS="$OPTS -vga none"
#OPTS="$OPTS -serial null"
#OPTS="$OPTS -parallel null"
#OPTS="$OPTS -monitor none"
#OPTS="$OPTS -display none"
#OPTS="$OPTS -daemonize"

# QEMU Guest Agent
#OPTS="$OPTS -chardev socket,path=/tmp/qga.sock,server,nowait,id=qga0"
#OPTS="$OPTS -device virtio-serial"
#OPTS="$OPTS -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0"

sudo taskset -c 0-7 qemu-system-x86_64 $OPTS

Define the VM

mkdir -p ~/Documents/
tee ~/Documents/gamingvm.xml <<'EOF' > /dev/null
<?xml version="1.0" encoding="UTF-8"?>
<domain xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0" type="kvm">
  <name>gamingvm</name>
  <uuid>01bd2ed1-b465-4eba-b6e4-47c6ac8171c6</uuid>
  <memory unit="GB">16</memory>
  <currentMemory unit="GB">16</currentMemory>
  <vcpu placement="static">6</vcpu>
  <cpu mode="host-passthrough">
  <topology sockets="1" cores="3" threads="2" />
  </cpu>
  <os>
  <type arch="x86_64" machine="q35">hvm</type>
  <loader>/usr/share/qemu/bios.bin</loader>
  <bootmenu enable="yes" />
  </os>
  <features>
  <hyperv>
  <relaxed state="on" />
  <vapic state="on" />
  <spinlocks state="on" retries="8191" />
  </hyperv>
  <acpi />
  </features>
  <clock offset="localtime">
  <timer name="hypervclock" present="yes" />
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <devices>
  <emulator>/usr/bin/qemu-system-x86_64</emulator>
  <interface type='bridge'>
  <mac address='52:54:00:a0:41:92'/>
  <source bridge='br0'/>
  <model type='rtl8139'/>
  <rom bar='off'/>
  </interface>
  <sound model='ich6'/>
  <controller type="usb" index="0" />
  <controller type="usb" index="1" />
  <controller type="usb" index="2" />
  <controller type="usb" index="3" />
  <controller type="sata" index="0" />
  <controller type="pci" index="0" model="pcie-root" />
  <controller type="pci" index="1" model="dmi-to-pci-bridge" />
  <controller type="pci" index="2" model="pci-bridge" />
  <memballoon model="none" />
  <sound model="ich6" />
  <disk type="file" device="cdrom">
  <driver name="qemu" type="raw" />
  <source file="[OS disc image]" />
  <target dev="hdc" bus="ide" />
  <readonly />
  <address type="drive" controller="0" bus="1" unit="0" />
  </disk>
  <disk type="file" device="disk">
  <source file="[Primary HDD image]" />
  <target dev="vda" bus="ide" />
  <address type="drive" bus="0" />
  </disk>
  <!--
  <disk type="file" device="disk">
  <source file="[Secondary HDD image]" />
  <target dev="vdb" bus="ide" />
  <address type="drive" bus="1" />
  </disk>
  -->
  </devices>
  <qemu:commandline>
  <qemu:env name="QEMU_PA_SAMPLES" value="4096" />
  <qemu:env name="QEMU_AUDIO_DRV" value="pa" />
  <qemu:arg value="-device" />
  <qemu:arg value="ioh3420,bus=pcie.0,addr=1c.0,multifunction=on,port=1,chassis=1,id=root.1" />
  <qemu:arg value="-device" />
  <qemu:arg value="vfio-pci,host=[GPU],bus=root.1,addr=00.0,multifunction=on,x-vga=on" />
  <!-- DISABLING AUDIO FOR THE TIME BEING
  <qemu:arg value="-device" />
  <qemu:arg value="vfio-pci,host=[Audio],bus=root.1,addr=00.1" />
  -->
  <qemu:arg value="-cpu" />
  <qemu:arg value="host" />
  </qemu:commandline>
</domain>
EOF

sed -i "s/\[GPU\]/${NVIDIA_SLOT}/" ~/Documents/gamingvm.xml
sed -i 's@\[Primary HDD image\]@\~/Documents/disk.img@' ~/Documents/gamingvm.xml

qemu-img create -f raw -o size=50G ~/Documents/disk.img

5b. Replace [OS disc image] with the path to an .iso for an install disc. I highly recommend using Windows 10 considering it's future support for dx12 and it has given me far less problems than Windows 8. This tutorial is also written for Win10, but Windows 8 is practically the same.

5c. Replace [Memory] with the amount of memory you want the VM to have. Note the value is in Gigabytes. Be sure not to give more than your system ram amount and leave some space for the host.

5d. Replace [Primary HDD Image] with the path to the image you created in step four. You can also add the path for a second hdd where [Secondary HDD Image]. You can also add more HDDs by copying the elements and increasing the number of bus and increasing the letter on vdx (so third disk would be bus=2 vdc, fourth would be bus=3, vdd, etc.).

5e. Choose the amount of cores and threads you want your VM to have. If you're on a processor with 8 threads, I recommend 3 cores and 2 threads (2 threads per core). In this instance, I would change [Cores*Threads] to 6, [Cores] to 3, and [Threads] to 2.

5f. Change [GPU] and [Audio] to the slot/function numbers from lspci. For example, I would use "01:00.0" and "01:00.1"

5f. Terminal: "virsh define [Path to XML file]". The terminal should return this if everything is correct. Code:

Domain gamingvm defined from [Path to XML file]

Setting up input devices

6a. Create a new XML file like the following

<hostdev mode='subsystem' type='usb' managed='no'>
<source>
<vendor id='0x[Before Colon]'/>
<product id='0x[After Colon]'/>
</source>
</hostdev>

6b. Terminal: "lsusb". Identify which device is your keyboard. Then look at the numbers after "ID" from the output. In the XML file, replace [Before Colon] with the set of numbers/letters before the colon, then replace [After Colon] with the set of numbers/letters after the colon. Be sure to keep the 0x. It sounds a bit confusing, but here is an example:

My keyboard from lsusb

Bus 002 Device 005: ID 413c:2011 Dell Computer Corp. Multimedia Pro Keyboard

My XML file would to look like this

<hostdev mode='subsystem' type='usb' managed='no'>
<source>
<vendor id='0x413c'/>
<product id='0x2011'/>
</source>
</hostdev>

Note: You could just add the hostdev element in the devices element in the XML file you created in step four and define the vm again. However, putting the USB devices in separate files allows you to attach/detach much easier. This is especially useful if the VM fails to boot and you have no way of interacting with your host OS.

6c. Repeat that for your mouse. If your mouse/keyboard has multiple entries, be sure to do it all of them (for instance, a wireless mouse would show up twice. Once for the USB cord, and once for the wireless adapter).

6d. Create a file with the following content

#!/bin/bash
if [[ $(virsh list | grep gamingvm) != "" ]]
then
vm=gamingvm
fi

virsh attach-device $vm [Mouse]
virsh attach-device $vm [Keyboard]

6e. Replace [Mouse] and [Keyboard] with paths to the files you created in the previous steps. If you had to make more than two files, just add lines with the path to those at the end

6f. Make this file executable by either right clicking it and going into the properties or using "chmod +x".

6g. Make a copy of the file from 6d, except replace the word attach with detach so it says virsh detach-device $vm .... This script can be used for detaching your input devices. Make sure it is executable.

Preparing virtual machine

7a. Create the following file

#!/bin/bash
if [[ $EUID -ne 0 ]]; then
  echo "This script must be run as root" 1>&2
  su
  exit 0
fi

set -x

echo 1 > /sys/module/kvm/parameters/ignore_msrs
virsh start gamingvm

if [[ $(virsh list | grep gamingvm) == "" ]]
then
  exit 0
fi

set +x

exit 0

7b. Terminal:

sudo gedit /etc/libvirt/qemu.conf

7c. Add the following lines (or find them and uncomment them)

user = "root"
group = "root"
cgroup_device_acl = [
  "/dev/null", "/dev/full", "/dev/zero",
  "/dev/random", "/dev/urandom",
  "/dev/ptmx", "/dev/kvm", "/dev/kqemu",
  "/dev/rtc","/dev/hpet", "/dev/vfio/vfio",
  "/dev/vfio/[GROUP]"
]
clear_emulator_capabilities = 0

7d. Terminal:

find /sys/kernel/iommu_groups/ -type l

Now look for what directory the GPU you are passing through is in. Replace [GROUP] with whatever number group your device is in.

Preparing PulseAudio

Note: If you are going to use HDMI audio, you do not need to follow these steps.

8a. Terminal:

cp /etc/pulse/default.pa ~/.pulse/

8b. Terminal:

gedit ~/.pulse/

8c. Add the following to the end of the file load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1

8d. Terminal:

su

8d. Terminal:

mkdir ~/.pulse/

8e. Terminal:

echo "default-server = 127.0.0.1" > ~/.pulse/client.conf

Networking

Note: This uses netctl which should already be installed. If for some reason it's not, install it via "pacman -S netctl" and configure it by referring to the [Click here to view the link]

9a. Terminal:

cd /etc/netctl

9b. Terminal:

sudo gedit [profile name]

[profile name] is the profile for the device that you use to get your interenet connection. It is likely called wired. If you are unsure run the command ls to view the available profiles.

9c. Change the IP=... line to IP=no. If the Address, DNS, or Gateway lines are present, delete them. Take note of the Interface=... line for future reference.

9d. Terminal:

sudo gedit bridge

This will create a new bridge profile.

9e. Add the following to file

Description="Bridge connection"
Interface=br0
Connection=bridge
BindsToInterfaces=([Interface])
IP=static
Address='192.168.1.202/24'
Gateway='192.168.1.1'
## Ignore (R)STP and immediately activate the bridge
SkipForwardingDelay=yes

9e. Change [Interface] to the name of the interface you took note of in step 10c. Also feel free to change the IP address to what you want it to be.

9f. Terminal:

netctl enable bridge

9g. Reboot to ensure networking on the host is still working.​

Install The OS

10a. Look at the "Kernel Patches" section of this tutorial below. Check to see if you need to enable those patches. If you do, enable the patches before you procede.​

10b. Make the file from step seven executable and run it. If everything goes smoothly, switching to the input of your GPU should display the installation screen. If not, scroll down to the troubleshooting portion of the thread.

10c. Run the file you made in step six to enable keyboard and mouse.

10d. Install the OS like usual.

10e. You now (hopefully) have a VM capable of playing Windows games!

#!/usr/bin/env sh
#
# TODO:
# * Suspend/resume to/from swap: https://wiki.archlinux.org/index.php/Power_management/Suspend_and_hibernate#Required_kernel_parameters
# * Emojis? http://www.omgubuntu.co.uk/2016/03/enable-color-emoji-linux-svg-font
set -e
# set -x
#-----------------------------------------------------------------------------------------------------------------------
# Config.
#--YOUR-CUSTOMIZATIONS-BELOW--------------------------------------------------------------------------------------------
# General.
DESIRED_COUNTRY='US'
DESIRED_TIMEZONE='America/Chicago'
DESIRED_LOCALE='en_US.UTF-8 UTF-8'
DESIRED_LOCALE2='en_US.UTF-8'
DESIRED_LANGUAGE='en_US'
DESIRED_HOSTNAME='bo-laptop'
DESIRED_USERNAME='bo'
# Cipher Strength.
CIPHER_STRENGTH=256
# Key file.
KEYFILE_NAME='multikeyfile'
# If these devs are not found, will default to /dev/sda & /dev/sdb.
DEV_DRIVE1='/dev/nvme0n1'
DEV_DRIVE2='/dev/nvme1n1'
# Partition numbers.
PARTNUM_EFI='1'
PARTNUM_SWAP1='2'
PARTNUM_DATA1='3'
PARTNUM_SWAP2='1'
PARTNUM_DATA2='2'
# Swap size in harddrive sectors.
SWAP_SIZE=34603007
#--DO-NOT-MODIFY-ANYTHING-BEYOND-THIS-LINE-UNLESS-NECESSARY-------------------------------------------------------------
KERNEL_PARAMS=''
# Key file.
KEYFILE="/mnt/boot/${KEYFILE_NAME}"
KEYFILE_MAPPED="/dev/mapper/${KEYFILE_NAME}"
# /dev/mapper/* related.
DATA1_MAPNAME='container1'
DATA2_MAPNAME='container2'
DATA1_MAPPED="/dev/mapper/${DATA1_MAPNAME}"
DATA2_MAPPED="/dev/mapper/${DATA2_MAPNAME}"
SWAP1_MAPNAME='swap1'
SWAP2_MAPNAME='swap2'
SWAP1_MAPPED="/dev/mapper/${SWAP1_MAPNAME}"
SWAP2_MAPPED="/dev/mapper/${SWAP2_MAPNAME}"
SWAP_RAID='/dev/md1'
# Used later.
PART_EFI=''
PART_SWAP1=''
PART_DATA1=''
PART_SWAP2=''
PART_DATA2=''
SWAP_UUID=''
ROOT_UUID=''
INTEL_DEV_ID="$(lspci -nn | grep -Ei "(VGA|3D).+ Intel .*" | sed -E 's/.*\[([a-fA-F0-9]+:[a-fA-F0-9]+)\].*/\1/g')"
NVIDIA_DEV_ID="$(lspci -nn | grep -Ei "(VGA|3D).+ nVidia .*" | sed -E 's/.*\[([a-fA-F0-9]+:[a-fA-F0-9]+)\].*/\1/g')"
NVIDIA_BUS_ID="$(lspci | grep -Ei "(VGA|3D).+ nVidia .*" | cut -b1-7)"
#-----------------------------------------------------------------------------------------------------------------------
# General Methods.
wait_for_user_input() {
printf "\nPress ENTER to continue.\n"
read
}
# Chopped up version of armrr.
# https://github.com/Gen2ly/armrr
dld_mirror_list() {
# "sh" shell doesn't support local variables so these will be global. :/
# TODO: test this install script in bash.
url="https://www.archlinux.org/mirrorlist/?country=${DESIRED_COUNTRY}&protocol=http&ip_version=4&use_mirror_status=on"
tmp_ml=$(mktemp --suffix=-mirrorlist)
if curl -s "${url}" -o "${tmp_ml}"; then
if ! grep "^## Arch Linux repository mirrorlist" "${tmp_ml}" > /dev/null; then
echo 'Warning: Downloaded mirrorlist invalid. Not using.'
return
fi
else
echo 'Warning: Download of mirrorlist failed. Not using.'
return
fi
# Enable all servers.
sed -i 's/^#Server/Server/g' "${tmp_ml}"
# Copy over the new mirror list.
install -Dm644 "${tmp_ml}" /etc/pacman.d/mirrorlist
}
# Attempts to find a device for our work. If passing a unix-style dev, like "nvme" drives, pass the full dev; e.g.
# '/dev/nvme0n1' rather than '/dev/nvme0'.
#
# Takes two arguments:
# 1. our desired dev; e.g. '/dev/nvme0'
# 2. our allowable fallback dev; e.g. '/dev/sda'
find_proper_drive() {
ourdev="$1"
defaultdev="$2"
returndev="${ourdev}"
if [ ! -e "${ourdev}" ]; then
returndev="${defaultdev}"
fi
# Is the device NVME? Does it not end in "n1"? If both are true, then append "n1" to the dev name.
if [ "${returndev#*nvme}" != "${returndev}" -a "${returndev%n1}" == "${returndev}" ]; then
returndev="${returndev}n1"
fi
printf "%s" "${returndev}"
}
find_proper_partition() {
ourdev="$1"
ourpart="$2"
if [ "${ourdev#*nvme}" != "${ourdev}" ]; then
ourdev="${ourdev}p"
fi
printf "%s%s" "${ourdev}" "${ourpart}"
}
unmount_all() {
set +e
swapoff "${SWAP_RAID}"
mdadm --stop --force "${SWAP_RAID}"
cryptsetup close "${SWAP1_MAPNAME}"
cryptsetup close "${SWAP2_MAPNAME}"
umount -R /mnt/arch/home
umount -R /mnt/arch
umount -R /mnt/btrfs-pool
cryptsetup close "${DATA1_MAPNAME}"
cryptsetup close "${DATA2_MAPNAME}"
umount -R "${DATA1_MAPPED}"
umount -R "${DATA2_MAPPED}"
cryptsetup close "${KEYFILE_NAME}"
umount -R "${KEYFILE_MAPPED}"
umount -R /mnt/boot
set -e
}
#-----------------------------------------------------------------------------------------------------------------------
# Confirm Execution of This Script.
clear
echo '
WARNING! WARNING! WARNING! WARNING!
WARNING! WARNING! WARNING! WARNING!
THIS SCRIPT WILL ABSOLUTELY WIPE OUT YOUR DATA ON AT LEAST THE FIRST TWO DRIVES AND WILL REPLACE YOUR BOOT LOADER!
YOU ALONE CARRY THE RESPONSIBILITY FOR ANY DATA LOSS BY USING THIS SCRIPT.
THERE WILL BE NO CONFIRMATION BEFORE DATA DESTRUCTION BEYOND THIS POINT!
WARNING! WARNING! WARNING! WARNING!
WARNING! WARNING! WARNING! WARNING!
Do you acknowledge you alone carry the responsibility for any data loss and want to continue?
* If so, press enter three times.
* If not, press CTRL+C to cancel this script.
'
wait_for_user_input
wait_for_user_input
wait_for_user_input
#-----------------------------------------------------------------------------------------------------------------------
# General Prep.
# https://wiki.archlinux.org/index.php/beginners'_guide#Update_the_system_clock
# https://wiki.archlinux.org/index.php/beginners'_guide#Select_the_mirrors
# https://wiki.archlinux.org/index.php/Mirrors
# Ensure nothing is mounted that we intend to mount later.
unmount_all
printf "\n\nActivating network time to ensure the system's time is correct.\n"
sudo tee /etc/systemd/timesyncd.conf <<-'EOF' > /dev/null
[Time]
#NTP=0.north-america.pool.ntp.org 1.north-america.pool.ntp.org 2.north-america.pool.ntp.org 3.north-america.pool.ntp.org
NTP=time1.google.com time2.google.com time3.google.com time4.google.com
FallbackNTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org
EOF
timedatectl set-ntp true
printf "\n\nRanking pacman mirrors.\n"
dld_mirror_list
printf "\n\nEnabling multilib.\n"
sed -i '/[#]*\[multilib\]/ { N; d; }' /etc/pacman.conf
sed -i '/[#]*\[archlinuxfr\]/ { N; N; d; }' /etc/pacman.conf
tee -a /etc/pacman.conf <<'EOF' > /dev/null
[multilib]
Include = /etc/pacman.d/mirrorlist
[archlinuxfr]
SigLevel = Never
Server = http://repo.archlinux.fr/$arch
EOF
printf "\n\nInstalling latest utils.\n"
pacman -Sy --noconfirm btrfs-progs parallel
# Figure out if we have devices to raid.
DEV_DRIVE1="$(find_proper_drive "${DEV_DRIVE1}" "/dev/sda")"
DEV_DRIVE2="$(find_proper_drive "${DEV_DRIVE2}" "/dev/sdb")"
#-----------------------------------------------------------------------------------------------------------------------
# Partition Drives.
# https://wiki.archlinux.org/index.php/beginners'_guide#Prepare_the_storage_devices
# Reset the drive's partition table to a fresh GPT.
sgdisk --zap "${DEV_DRIVE1}"
sgdisk --clear --mbrtogpt "${DEV_DRIVE1}"
# Calculate sectors for drive 1's EFI boot partition.
EFI_SECT_START=2048
EFI_SECT_END=$((EFI_SECT_END=EFI_SECT_START+2097151))
# Calculate sectors for drive 1's swap.
SWAP_SECT_START=$((SWAP_SECT_START=EFI_SECT_END+1))
SWAP_SECT_END=$((SWAP_SECT_END=SWAP_SECT_START+SWAP_SIZE))
# Calculate sectors for drive 1's data.
DATA_SECT_START=$((DATA_SECT_START=SWAP_SECT_END+1))
DATA_SECT_END=$(sgdisk -E ${DEV_DRIVE1})
# Create a 1024MB EFI boot partition.
sgdisk --new ${PARTNUM_EFI}:${EFI_SECT_START}:${EFI_SECT_END} \
--change-name ${PARTNUM_EFI}:'EFI System Partition' \
--typecode ${PARTNUM_EFI}:ef00 "${DEV_DRIVE1}"
# Create a SWAP partition.
sgdisk --new ${PARTNUM_SWAP1}:${SWAP_SECT_START}:${SWAP_SECT_END} \
--change-name ${PARTNUM_SWAP1}:'SWAP1' \
--typecode ${PARTNUM_SWAP1}:8200 "${DEV_DRIVE1}"
# Create the root partition.
sgdisk --new ${PARTNUM_DATA1}:${DATA_SECT_START}:${DATA_SECT_END} \
--change-name ${PARTNUM_DATA1}:'DATA1' \
--typecode ${PARTNUM_DATA1}:8300 "${DEV_DRIVE1}"
# Print out the partition table for the first drive.
sgdisk --print "${DEV_DRIVE1}"
# Reset the drive's partition table to a fresh GPT.
sgdisk --zap "${DEV_DRIVE2}"
sgdisk --clear --mbrtogpt "${DEV_DRIVE2}"
# Calculate sectors for drive 2's swap.
SWAP_SECT_START=2048
SWAP_SECT_END=$((SWAP_SECT_END=SWAP_SECT_START+SWAP_SIZE))
# Calculate sectors for drive 2's data.
DATA_SECT_START=$((DATA_SECT_START=SWAP_SECT_END+1))
DATA_SECT_END=$(sgdisk -E ${DEV_DRIVE2})
# Create a 16.5GB SWAP partition.
sgdisk --new ${PARTNUM_SWAP2}:${SWAP_SECT_START}:${SWAP_SECT_END} \
--change-name ${PARTNUM_SWAP2}:'SWAP2' \
--typecode ${PARTNUM_SWAP2}:8200 "${DEV_DRIVE2}"
# Create the root partition.
sgdisk --new ${PARTNUM_DATA2}:${DATA_SECT_START}:${DATA_SECT_END} \
--change-name ${PARTNUM_DATA2}:'DATA2' \
--typecode ${PARTNUM_DATA2}:8300 "${DEV_DRIVE2}"
# Print out the partition table for the first drive.
sgdisk --print "${DEV_DRIVE2}"
#-----------------------------------------------------------------------------------------------------------------------
# Discover proper partition names.
PART_EFI="$(find_proper_partition "${DEV_DRIVE1}" "${PARTNUM_EFI}")"
PART_SWAP1="$(find_proper_partition "${DEV_DRIVE1}" "${PARTNUM_SWAP1}")"
PART_DATA1="$(find_proper_partition "${DEV_DRIVE1}" "${PARTNUM_DATA1}")"
PART_SWAP2="$(find_proper_partition "${DEV_DRIVE2}" "${PARTNUM_SWAP2}")"
PART_DATA2="$(find_proper_partition "${DEV_DRIVE2}" "${PARTNUM_DATA2}")"
#-----------------------------------------------------------------------------------------------------------------------
# Setup The Key.
# https://bbs.archlinux.org/viewtopic.php?id=196840
echo "
Creating keyfile used to decrypt each drive in the array. This key is encrypted and will be what you unlock when
entering the proper password on boot.
When prompted, please provide a password you can remember.
"
# wait_for_user_input
# Format the EFI+BOOT partition and mount it.
printf "\n\nBuilding /mnt/boot (EFI).\n"
mkfs.fat -F32 "${PART_EFI}"
[ ! -d /mnt/boot ] && mkdir -p /mnt/boot
mount "${PART_EFI}" /mnt/boot
# Generate a blank keyfile -- apparently the LUKS header is 2MB, so we'll need 2MB + the 2MB for keys.
dd if=/dev/zero of="${KEYFILE}" bs=4M count=1
# Format our keyfile.
cryptsetup --batch-mode --verbose --verify-passphrase \
--cipher aes-xts-plain64 --key-size 512 --hash sha512 --iter-time 800 --use-random \
luksFormat "${KEYFILE}"
# Decrypt and open the keyfile.
printf "\n\nEnter your encrypt password when prompted below.\n"
cryptsetup open --type luks "${KEYFILE}" "${KEYFILE_NAME}"
set +e
# Write zeros to the keyfile.
dd if=/dev/zero of="${KEYFILE_MAPPED}"
# Want 4 keys. (4 * 4096 / 8) = 2048 bytes".
dd iflag=fullblock if=/dev/random of="${KEYFILE_MAPPED}" bs=2048 count=1
set -e
printf "\n\nVerify there is enough random content in the keyfile:\n"
hexdump -C "${KEYFILE_MAPPED}"
#-----------------------------------------------------------------------------------------------------------------------
# Create Encrypted Swap.
# https://wiki.archlinux.org/index.php/Dm-crypt/Swap_encryption
printf "\n\nCreating the containers for our swap.\n"
cryptsetup --batch-mode --verbose \
--cipher aes-xts-plain64 --key-size 512 --hash sha512 --iter-time 800 --use-random \
--key-file "${KEYFILE_MAPPED}" --keyfile-offset 0 --keyfile-size 512 \
luksFormat "${PART_SWAP1}"
cryptsetup --batch-mode --verbose \
--cipher aes-xts-plain64 --key-size 512 --hash sha512 --iter-time 800 --use-random \
--key-file "${KEYFILE_MAPPED}" --keyfile-offset 512 --keyfile-size 512 \
luksFormat "${PART_SWAP2}"
printf "\n\nOpening the containers for our swap.\n"
cryptsetup open --type luks \
--key-file "${KEYFILE_MAPPED}" --keyfile-offset 0 --keyfile-size 512 "${PART_SWAP1}" "${SWAP1_MAPNAME}" # swapDevice
cryptsetup open --type luks \
--key-file "${KEYFILE_MAPPED}" --keyfile-offset 512 --keyfile-size 512 "${PART_SWAP2}" "${SWAP2_MAPNAME}" # swapDevice
# Wipe 999MB of each drive (for testing of a full disk wipe).
# printf "%s\n%s\n" "${SWAP1_MAPPED}" "${SWAP2_MAPPED}" | parallel "dd if=/dev/zero of='{}' bs=1M count=999 status=progress"
# TODO: remove the above parallel command and uncomment the below.
# Fully wipe both drives to fill them with encrypted "garbage" making it near impossible to discern where new encrypted
# data is stored.
# printf "%s\n%s\n" "${SWAP1_MAPPED}" "${SWAP2_MAPPED}" | parallel "dd if=/dev/zero of='{}' bs=1M status=progress"
# Create raid for swap. Why? Only because of resume. I intend to use VMs for most of my memory and am uncertain that the
# memory used by VMs can be compressed to the default 2/5ths to fit all 32GBs of system memory into a single swap
# partition. On top of that, I want my swap partitions to be used evenly, which can either be done via setting their
# priority to exactly the same (kernel will then "stripe" them) or mdadm'ing them. If I let the kernel decide what swap
# partition to prioritize for hibernation, I will not be able to reliably resume because the kernel "resume" parameter
# does not consider multiple swap devices! Therefore we must raid them.
mdadm --create "${SWAP_RAID}" --force --level=0 --raid-devices=2 "${SWAP1_MAPPED}" "${SWAP2_MAPPED}"
# Make the swap partition.
mkswap "${SWAP_RAID}"
# Start using the swap partition.
swapon "${SWAP_RAID}"
#-----------------------------------------------------------------------------------------------------------------------
# Create Encrypted BTRFS.
# https://wiki.archlinux.org/index.php/beginners'_guide#Format_the_file_systems_and_enable_swap
# http://kneit.in/2015/09/17/brtfs-raid-on-dmcrypt.html#planning-your-disk-layout
printf "\n\nCreating the containers for our array.\n"
cryptsetup --batch-mode --verbose \
--cipher aes-xts-plain64 --key-size 512 --hash sha512 --iter-time 800 --use-random \
--key-file "${KEYFILE_MAPPED}" --keyfile-offset 1024 --keyfile-size 512 \
luksFormat "${PART_DATA1}"
cryptsetup --batch-mode --verbose \
--cipher aes-xts-plain64 --key-size 512 --hash sha512 --iter-time 800 --use-random \
--key-file "${KEYFILE_MAPPED}" --keyfile-offset 1536 --keyfile-size 512 \
luksFormat "${PART_DATA2}"
printf "\n\nOpening the containers for our array.\n"
cryptsetup open --type luks \
--key-file "${KEYFILE_MAPPED}" --keyfile-offset 1024 --keyfile-size 512 "${PART_DATA1}" \
"${DATA1_MAPNAME}"
cryptsetup open --type luks \
--key-file "${KEYFILE_MAPPED}" --keyfile-offset 1536 --keyfile-size 512 "${PART_DATA2}" \
"${DATA2_MAPNAME}"
# Close the no longer needed cryptkey.
cryptsetup close "${KEYFILE_NAME}"
# Wipe 999MB of each drive (for testing of a full disk wipe).
# printf "%s\n%s\n" "${DATA1_MAPPED}" "${DATA2_MAPPED}" | parallel "dd if=/dev/zero of='{}' bs=1M count=999 status=progress"
# TODO: remove the above parallel command and uncomment the below.
# Fully wipe both drives to fill them with encrypted "garbage" making it near impossible to discern where new encrypted
# data is stored.
# printf "%s\n%s\n" "${DATA1_MAPPED}" "${DATA2_MAPPED}" | parallel "dd if=/dev/zero of='{}' bs=1M status=progress"
# Make the BTRFS RAID 0 (stripe) for data & RAID 1 (mirror) for meta data, the latter helps detect & avoid corruption.
printf "\n\nFormatting the containers with btrfs.\n"
mkfs.btrfs -m raid1 -d raid0 "${DATA1_MAPPED}" "${DATA2_MAPPED}"
# Mount our BTRFS RAID--defaults for mounting on NVME are fine, just add compression cause it's good stuff.
# WARNING: Do not add "discard" to mounting NVME SSDs! Btrfs does not do this by default, which is good.
[ ! -d /mnt/btrfs-pool ] && mkdir /mnt/btrfs-pool
mount -t btrfs -o defaults,compress=lzo "${DATA1_MAPPED}" /mnt/btrfs-pool
# Change our working dir.
pushd /mnt/btrfs-pool
# Create desired subvolumes for easy snapshots.
btrfs sub create @
btrfs sub create @home
btrfs sub create @snapshots
# Paths we do not want to include in snapshots.
btrfs sub create @var-cache-pacman-pkg
btrfs sub create @var-abs
btrfs sub create @var-tmp
btrfs sub create @tmp
btrfs sub create @srv
# List our subvols.
btrfs sub list .
# Reset our current working folder.
popd
#-----------------------------------------------------------------------------------------------------------------------
# Mount Our Partitions.
# https://wiki.archlinux.org/index.php/beginners'_guide#Format_the_file_systems_and_enable_swap
# Mount our root subvolume.
[ ! -d /mnt/arch ] && mkdir /mnt/arch
mount -t btrfs -o defaults,compress=lzo,subvol=@ "${DATA1_MAPPED}" /mnt/arch
# Make some system dirs.
[ ! -d /mnt/arch/boot ] && mkdir -p /mnt/arch/boot
[ ! -d /mnt/arch/home ] && mkdir -p /mnt/arch/home
[ ! -d /mnt/arch/etc ] && mkdir -p /mnt/arch/etc
[ ! -d /mnt/arch/var/log ] && mkdir -p /mnt/arch/var/log
# Paths we do not want to include in snapshots.
[ ! -d /mnt/arch/var/cache/pacman/pkg ] && mkdir -p /mnt/arch/var/cache/pacman/pkg
[ ! -d /mnt/arch/var/abs ] && mkdir -p /mnt/arch/var/abs
[ ! -d /mnt/arch/var/tmp ] && mkdir -p /mnt/arch/var/tmp
[ ! -d /mnt/arch/tmp ] && mkdir -p /mnt/arch/tmp
[ ! -d /mnt/arch/srv ] && mkdir -p /mnt/arch/srv
# Bind boot to two locations since a symlink cannot be used within /mnt/arch once we get into arch-chroot or mkinitcpio.
mount --bind /mnt/boot /mnt/arch/boot
# Disable copy-on-write to avoid fragmentation.
chattr +C /mnt/arch/var/log
# Mount our subvols.
# We keep them as subvols not nested under root so that rolling back the subvol named "@" will be easy, again, due to
# not having nested subvols under "@".
mount -t btrfs -o defaults,compress=lzo,subvol=@home "${DATA1_MAPPED}" /mnt/arch/home
mount -t btrfs -o defaults,compress=lzo,subvol=@var-cache-pacman-pkg "${DATA1_MAPPED}" /mnt/arch/var/cache/pacman/pkg
mount -t btrfs -o defaults,compress=lzo,subvol=@var-abs "${DATA1_MAPPED}" /mnt/arch/var/abs
mount -t btrfs -o defaults,compress=lzo,subvol=@var-tmp "${DATA1_MAPPED}" /mnt/arch/var/tmp
mount -t btrfs -o defaults,compress=lzo,subvol=@tmp "${DATA1_MAPPED}" /mnt/arch/tmp
mount -t btrfs -o defaults,compress=lzo,subvol=@srv "${DATA1_MAPPED}" /mnt/arch/srv
# Mount our btrfs pool, without specifying subvolumes, to make it easier to manage subvols.
[ ! -d /mnt/arch/mnt/btrfs-pool ] && mkdir -p /mnt/arch/mnt/btrfs-pool
mount -t btrfs -o defaults,compress=lzo "${DATA1_MAPPED}" /mnt/arch/mnt/btrfs-pool
#-----------------------------------------------------------------------------------------------------------------------
# Install Arch Linux.
# https://wiki.archlinux.org/index.php/beginners'_guide#Installation
# Package descriptions:
# * intel-ucode: updated microcode for intel CPUs. AMDs do not need an extra pkg for updates.
# * mesa-libgl, lib32-mesa-libgl: adds OpenGL support to intel gpu.
# * mesa: an open-source implementation of the OpenGL specification.
# * vulkan-intel: adds Vulkan, replacement for OpenGL, to intel gpu.
# * xf86-video-*: hybrid graphics cards drivers (nvidia + intel, or amd + intel);
# see https://wiki.archlinux.org/index.php/PRIME
# * nvidia*, lib32-nvidia-libgl: nVidia supplied linux video drivers--very performant.
# see https://wiki.archlinux.org/index.php/NVIDIA_Optimus
# * xorg-xrandr: required by nvidia* packages, according to the wiki.
# * iw: CLI WIFI configuration util.
# * netctl: installed with "base"; recommended for networking control. https://wiki.archlinux.org/index.php/Netctl
# * ifplugd: starts & stops DHCP profiles when network cable is plugged in or unplugged.
# * wpa_actiond: same concept as ifplugd but for wifi.
# * wpa_supplicant: A utility providing key negotiation for WPA wireless networks.
# * dialog: A tool to display dialog boxes from shell scripts.
# * libva-intel-driver, libva-vdpau-driver (req. nouveau-fw), nvidia-utils: "Video Acceleration API" (VA-API) for hw
# accel video encoding and decoding. https://wiki.archlinux.org/index.php/VA-API
# * libvdpau-va-gl, mesa-vdpau (req. nouveau-fw), nvidia-utils: "Video Decode and Presentation API for Unix" (VDPAU) is
# an open source library and API to offload portions of the video decoding process and video post-processing to the
# GPU video-hardware. https://wiki.archlinux.org/index.php/VDPAU
# * qemu, libvirt, bridge-utils: KVM & VFIO related.
#
# Dependencies for future packages/apps:
# * python3: snapper gui
# * gtk3: snapper gui
# * python-dbus: snapper gui
# * python-gobject: snapper gui
# * python-setuptools: snapper gui
# * gtksourceview3: snapper gui
printf "\n\nInstalling Arch Linux.\n"
pacstrap /mnt/arch \
alsa-utils \
alsa-oss \
alsa-lib \
base \
base-devel \
mtr \
bash-completion \
btrfs-progs \
dialog \
downgrade \
efibootmgr \
gtk3 \
qt4 \
gtksourceview3 \
htop \
intel-ucode \
iotop \
iw \
lib32-alsa-plugins \
lib32-mesa-libgl \
libvdpau-va-gl \
linux-headers \
libva-intel-driver \
mesa \
mesa-libgl \
mesa-vdpau \
pulseaudio \
pulseaudio-alsa \
pulseaudio-bluetooth \
pulseaudio-equalizer \
pulseaudio-gconf \
python \
python-dbus \
python-gobject \
python-setuptools \
python2 \
snapper \
vulkan-icd-loader \
vulkan-intel \
wget \
wpa_supplicant \
wpa_supplicant_gui \
xf86-input-evdev \
xf86-input-synaptics \
yaourt \
qemu libvirt bridge-utils \
# ifplugd \
# wpa_actiond \
# nvidia \
# nvidia-utils \
# nvidia-libgl \
# lib32-nvidia-libgl \
# xorg-xrandr \
# xf86-video-intel \ # apparently has poor performance. https://www.reddit.com/r/archlinux/comments/4cojj9/it_is_probably_time_to_ditch_xf86videointel/
# xf86-video-nouveau \
# xf86-video-vesa \
# xf86-video-ati \
#-----------------------------------------------------------------------------------------------------------------------
# Configure Arch.
printf "\n\nGenerating fstab.\n"
genfstab -pU /mnt/arch > /mnt/arch/etc/fstab
cat /mnt/arch/etc/fstab
# Set the hostname.
echo "${DESIRED_HOSTNAME}" > /mnt/arch/etc/hostname
# Copy files that do not seem to be copied by pacstrap.
install -Dm644 /etc/pacman.d/mirrorlist /mnt/arch/etc/pacman.d/mirrorlist
install -Dm644 /etc/pacman.conf /mnt/arch/etc/pacman.conf
cp /etc/locale.gen /etc/locale.conf /mnt/arch/etc/
printf "\n\nConfiguring arch.\n"
arch-chroot /mnt/arch /bin/bash <<-EOC
loadkeys us
printf "\n\nGenerating locale config.\n"
echo "${DESIRED_LOCALE}" > /etc/locale.gen
locale-gen
echo "LANG=${DESIRED_LOCALE2}" > /etc/locale.conf
# echo "LANGUAGE=${DESIRED_LANGUAGE}" >> /etc/locale.conf
# # echo 'LC_ALL=C' >> /etc/locale.conf
export LANG="${DESIRED_LOCALE2}"
localectl set-locale LANG="${DESIRED_LOCALE2}"
printf "\n\nSet timezone.\n"
ln -s "/usr/share/zoneinfo/${DESIRED_TIMEZONE}" /etc/localtime
# Adjust time skew.
hwclock --systohc --utc
printf "\n\nActivating network time to ensure the system's time is correct.\n"
tee /etc/systemd/timesyncd.conf <<-'EOF' > /dev/null
[Time]
NTP=0.north-america.pool.ntp.org 1.north-america.pool.ntp.org 2.north-america.pool.ntp.org 3.north-america.pool.ntp.org
FallbackNTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org
EOF
# Download latest pacman package list.
pacman -Sy
# Install python pip.
wget https://bootstrap.pypa.io/get-pip.py
python get-pip.py
rm -f get-pip.py
EOC
# Enable "LLMNR" for systemd-resolved so that we may resolve hosts on the LAN without needing a DNS server.
sed -i 's/^[#]*\s*LLMNR=.*/LLMNR=yes/g' /mnt/arch/etc/systemd/resolved.conf
# Add systemd-resolved to the host lookup order to act as a local DNS middle-man or cache.
sed -i 's/^hosts:.*/hosts: files mymachines resolve myhostname dns/g' /mnt/arch/etc/nsswitch.conf
#-----------------------------------------------------------------------------------------------------------------------
# Configure Xorg.
printf "\n\nConfiguring Xorg.\n"
# TODO: CODE NEEDS TO DOWNLOAD AND INSTALL THIS INTEL GUC FIRMWARE UNTIL IT MAKES IT INTO THE NEXT KERNEL OR WHATEVER:
# https://01.org/sites/default/files/downloads/intelr-graphics-linux/sklgucver61.tar.bz2
# probably can have it replace the v4 guc:
# ln -sf /lib/firmware/i915/skl_guc_ver6_1.bin /lib/firmware/i915/skl_guc_ver4.bin
# have to rebuild init:
# mkinitcpio -p linux
tee /mnt/arch/etc/X11/xorg.conf <<EOF > /dev/null
Section "Module"
Load "modesetting"
EndSection
# Section "Device"
# Identifier "nvidia"
# Driver "nvidia"
# BusID "${NVIDIA_DEV_ID}"
# Option "AllowEmptyInitialConfiguration"
# EndSection
# If not use xf86-video-intel but kernel provided mesa for intel gfx, then you need this config.
Section "Device"
Identifier "Intel Graphics"
# Driver "intel"
Driver "modesetting"
# BusID "${INTEL_DEV_ID}"
Option "AccelMethod" "sna"
Option "TearFree" "True"
Option "DRI" "3"
# Option "Tiling" "True"
# Option "SwapbuffersWait" "True"
EndSection
# Section "ServerLayout"
# Identifier "layout"
# Screen 1 "nvidia"
# Inactive "intel"
# EndSection
EOF
# tee /mnt/arch/etc/X11/xorg.conf.d/20-intel.conf <<EOF > /dev/null
# EOF
# tee /mnt/arch/etc/X11/xinit/xinitrc.d/nvidia-optimus.sh <<EOF > /dev/null
# #!/bin/sh
# xrandr --setprovideroutputsource modesetting NVIDIA-0
# xrandr --auto
# EOF
# chmod +x /mnt/arch/etc/X11/xinit/xinitrc.d/nvidia-optimus.sh
# Monitor Scale related.
sudo tee /mnt/arch/etc/X11/xinit/xinitrc.d/70-xrandr-scale.sh <<'EOF' > /dev/null
#!/usr/bin/env sh
set -e
# Set the gnome scale to something larger than what we really want so we can scale it down.
gsettings set org.gnome.desktop.interface scaling-factor 2
# Get the name of the first connected display's port.
PRI_PORT="$(xrandr | grep -v disconnected | grep connected | cut -d' ' -f1)"
# Set the scale.
xrandr --output ${PRI_PORT} --scale 1.35x1.35
# Reset "panning" so xrandr will tell us the virtual resolution of the screen.
xrandr --output ${PRI_PORT} --panning 0x0
# Get the virtual resolution of the screen.
SCALED_RES="$(xrandr | grep ${PRI_PORT} | sed -E 's/.* ([0-9]+x[0-9]+).*/\1/')"
# Set the panning size to the virtual resolution of the screen to force it to properly fill the screen & avoid improper mou$
xrandr --output ${PRI_PORT} --panning ${SCALED_RES}
EOF
sudo chmod +x /mnt/arch/etc/X11/xinit/xinitrc.d/70-xrandr-scale.sh
# #-----------------------------------------------------------------------------------------------------------------------
# # KVM + VFIO + libvirt + qemu -- GPU passthrough.
# # Older guide:
# # http://www.se7ensins.com/forums/threads/how-to-setup-a-gaming-virtual-machine-with-gpu-passthrough-qemu-kvm-libvirt-and-vfio.1371980/
# # Newer guide:
# # http://chanster.net/article/2016/03/05/qemu-gpu-passthrough/
# printf "\n\nConfiguring mkinitcpio to load the vfio related modules.\n"
# sed -Ei 's/^MODULES=".*/MODULES="i915 vfio vfio_iommu_type1 vfio_pci vfio_virqfd"/' /mnt/arch/etc/mkinitcpio.conf
# # DETACH GPU FROM HOST
# if [ -e /mnt/arch/etc/modprobe.d/vfio.conf ]; then
# cp -b --preserve /mnt/arch/etc/modprobe.d/vfio.conf{,-bak}
# sed -Ei '/^options/d' /mnt/arch/etc/modprobe.d/vfio.conf
# fi
# echo "options vfio-pci ids=${NVIDIA_DEV_ID}" | tee /mnt/arch/etc/modprobe.d/vfio.conf
# tee /mnt/arch/etc/modprobe.d/00-modprobe.conf <<'EOF' > /dev/null
# blacklist radeon
# blacklist nvidia
# EOF
# # Bind the addon GPU to VFIO.
# # ls /sys/bus/pci/devices | grep -i '01:00.0\|01:00.1'
# echo "DEVICES=\"0000:${NVIDIA_BUS_ID}\"" > /mnt/arch/usr/local/etc/vfio-devices
# tee /mnt/arch/usr/local/bin/vfio-bind <<'EOF' > /dev/null
# #!/bin/sh
# # This script loads the vfio-pci module, locates the devices passed in as arguments and rebinds them to vfio-pci.
# # http://chanster.net/article/2016/03/05/qemu-gpu-passthrough/
# modprobe vfio-pci
# for dev in "$@"; do
# vendor=$(cat /sys/bus/pci/devices/${dev}/vendor)
# device=$(cat /sys/bus/pci/devices/${dev}/device)
# if [ -e /sys/bus/pci/devices/${dev}/driver ]; then
# echo ${dev} > /sys/bus/pci/devices/${dev}/driver/unbind
# fi
# echo ${vendor} ${device} > /sys/bus/pci/drivers/vfio-pci/new_id
# done
# EOF
# chmod +x /mnt/arch/usr/local/bin/vfio-bind
# tee /mnt/arch/usr/lib/systemd/system/vfio-bind.service <<'EOF' > /dev/null
# [Unit]
# Description=Binds devices to vfio-pci
# After=syslog.target
# [Service]
# EnvironmentFile=-/usr/local/etc/vfio-bind
# Type=oneshot
# RemainAfterExit=yes
# ExecStart=-/usr/local/bin/vfio-bind $DEVICES
# [Install]
# WantedBy=multi-user.target
# EOF
#-----------------------------------------------------------------------------------------------------------------------
# Configure Boot.
printf "\n\nAdding the multidecrypt mkinitcpio hook.\n"
tee /etc/initcpio/hooks/multidecrypt <<EOF > /dev/null
#!/usr/bin/ash
run_hook() {
# set -x
modprobe -a -q dm-crypt >/dev/null 2>&1
modprobe -a -q loop >/dev/null 2>&1
[ "\${quiet}" = "y" ] && CSQUIET=">/dev/null"
if [ -z "\${multidecrypt}" ]; then
err "No dm-crypt luks devices specified for multidecrypt, aborting..."
exit 1
fi
# Loop until the user provides a valid password.
while ! eval cryptsetup open --type luks "/${KEYFILE_NAME}" "${KEYFILE_NAME}" \${CSQUIET}; do
sleep 2;
done
if [ ! -e "${KEYFILE_MAPPED}" ]; then
err "${KEYFILE_NAME} decryption failed, aborting..."
exit 1
fi
luksdevnum=1
mapdevnum=1
for luksdev in \${multidecryptswap//:/ }; do
if resolved=\$(resolve_device "\${luksdev}" \${rootdelay}); then
eval cryptsetup open --type luks \
--key-file "${KEYFILE_MAPPED}" \
--keyfile-offset \$(((\$luksdevnum-1)*512)) \
--keyfile-size 512 \
\${resolved} \
swap\${mapdevnum} \
\${CSQUIET}
# swapDevice \
if [ ! -e "/dev/mapper/swap\${mapdevnum}" ]; then
err "swap\${mapdevnum} creation failed, continuing with other specified devices..."
fi
else
err "Could not resolve \${luksdev}, continuing with other specified devices..."
fi
let luksdevnum++
let mapdevnum++
done
mapdevnum=1
for luksdev in \${multidecrypt//:/ }; do
if resolved=\$(resolve_device "\${luksdev}" \${rootdelay}); then
eval cryptsetup open --type luks \
--key-file "${KEYFILE_MAPPED}" \
--keyfile-offset \$(((\$luksdevnum-1)*512)) \
--keyfile-size 512 \
\${resolved} \
container\${mapdevnum} \
\${CSQUIET}
if [ ! -e "/dev/mapper/container\${mapdevnum}" ]; then
err "container\${mapdevnum} creation failed, continuing with other specified devices..."
fi
else
err "Could not resolve \${luksdev}, continuing with other specified devices..."
fi
let luksdevnum++
let mapdevnum++
done
# Clean up.
cryptsetup close "${KEYFILE_NAME}"
}
# vim: set ft=sh ts=4 sw=4 et:
EOF
printf "\n\nAdding the multidecrypt mkinitcpio install.\n"
tee /etc/initcpio/install/multidecrypt <<EOF > /dev/null
#!/bin/bash
build() {
local mod
add_module dm-crypt
if [[ \${CRYPTO_MODULES} ]]; then
for mod in \${CRYPTO_MODULES}; do
add_module "\$mod"
done
else
add_all_modules '/crypto/'
fi
# add loop module for mounting of keyfile
add_module loop
add_binary "cryptsetup"
add_binary "dmsetup"
add_file "/usr/lib/udev/rules.d/10-dm.rules"
add_file "/usr/lib/udev/rules.d/13-dm-disk.rules"
add_file "/usr/lib/udev/rules.d/95-dm-notify.rules"
add_file "/usr/lib/initcpio/udev/11-dm-initramfs.rules" "/usr/lib/udev/rules.d/11-dm-initramfs.rules"
add_file "/boot/${KEYFILE_NAME}" "/${KEYFILE_NAME}"
add_runscript
}
help() {
cat <<HELPEOF
This hook allows for startup decryption of multiple dm-crypt luks encrypted
devices. Users should specify the devices to be unlocked using:
'multidecrypt=device[[:device]...]'
on the kernel command line, where 'device' is the path to the raw device,
specified using PARTUUID or some other means. Devices will be available as
/dev/mapper/container[1,2,3...] etc.
The hook expects a dm-crypt luks encrypted file called /boot/${KEYFILE_NAME} to
exist. This keyfile contains a concatenation of 4096 bit keys for each
encrypted device in the same order as specified in the multidecrypt kernel
command line argument.
If decryption of one of the devices fails, the hook will attempt to continue
to decrypt any other specified devices. This is useful for btrfs software
raid if a device has failed as an example.
You will be prompted for the password to the ${KEYFILE_NAME} container at runtime.
This means you must have a keyboard available to input it, and you may need the
keymap hook as well to ensure that the keyboard is using the layout you expect.
HELPEOF
}
# vim: set ft=sh ts=4 sw=4 et:
EOF
cp -Rf /etc/initcpio/{hooks,install} /mnt/arch/etc/initcpio/
printf "\n\nConfiguring mkinitcpio to use multidecrypt hook.\n"
sed -i 's/^HOOKS=.*/HOOKS="base udev multidecrypt mdadm_udev resume modconf block filesystems fsck btrfs keyboard autodetect"/' \
/mnt/arch/etc/mkinitcpio.conf
printf "\n\nGathering partition UUIDs for both btrfs partitions used in RAID 0 (stripe)."
# Will be mounted by multidecrypt.
PART_DATA1_PARTUUID="$(blkid -s PARTUUID -o value "${PART_DATA1}")"
PART_DATA2_PARTUUID="$(blkid -s PARTUUID -o value "${PART_DATA2}")"
PART_SWAP1_PARTUUID="$(blkid -s PARTUUID -o value "${PART_SWAP1}")"
PART_SWAP2_PARTUUID="$(blkid -s PARTUUID -o value "${PART_SWAP2}")"
SWAP_UUID="$(blkid -s UUID -o value "${SWAP_RAID}")"
# Will be mounted by BTRFS.
ROOT_UUID="$(blkid -s UUID -o value "${DATA1_MAPPED}")"
# Get rid fo the mkinitcpio error, "ERROR: file not found: 'fsck.btrfs'".
rm -f /bin/fsck.btrfs
printf "\n\nInstalling boot control.\n"
arch-chroot /mnt/arch /bin/bash <<EOF
# set -x
# Make sure efivars are loaded.
mount -t efivarfs efivarfs /sys/firmware/efi/efivars
# Regenerate initrd image
mkinitcpio -p linux
# Prune linux boot entries.
set +e
IFS='
'
for ITEM in \$(efibootmgr); do
echo "scanning \${ITEM}..."
# If statements with []'s are not working properly here so we'll just use "test" directly.
test "\${ITEM#*inux}" == "\${ITEM}" && continue
BOOTNUM="\$(echo "\${ITEM}" | sed -e 's/^[Bb]oot\([a-zA-Z0-9]*\).*/\1/')"
echo "Removing boot num \${BOOTNUM}, entry: \${ITEM}."
efibootmgr --bootnum "\${BOOTNUM}" --delete-bootnum
echo "Done removing boot entry: \${ITEM}."
done
set -e
# # Install EFI boot image.
# efibootmgr \
# --create \
# --disk ${DEV_DRIVE1} \
# --part ${PARTNUM_EFI} \
# --label "Arch Linux" \
# --loader /vmlinuz-linux \
# --timeout 2 \
# --unicode "multidecryptswap=PARTUUID=${PART_SWAP1_PARTUUID}:PARTUUID=${PART_SWAP2_PARTUUID} multidecrypt=PARTUUID=${PART_DATA1_PARTUUID}:PARTUUID=${PART_DATA2_PARTUUID} root=UUID=${ROOT_UUID} rw rootflags=subvol=@ resume=UUID=${SWAP_UUID} initrd=\\intel-ucode.img initrd=\\initramfs-linux.img"
bootctl install
exit 0
EOF
# systemd-boot arch linux config.
tee /mnt/arch/boot/loader/entries/arch.conf <<EOF > /dev/null
title Arch Linux
linux /vmlinuz-linux
initrd /intel-ucode.img
initrd /initramfs-linux.img
# "iommu=pt" : to avoid DMAR errors.
# "i915.enable_hd_vgaarb=1" : use this if you're not getting monitor sync when the VM starts, because there's probably a
# problem with VGA arbitration or the device ROM; this addresses the former. You may need to use linux-vfio kernel.
options multidecryptswap=PARTUUID=${PART_SWAP1_PARTUUID}:PARTUUID=${PART_SWAP2_PARTUUID} multidecrypt=PARTUUID=${PART_DATA1_PARTUUID}:PARTUUID=${PART_DATA2_PARTUUID} root=UUID=${ROOT_UUID} rw rootflags=subvol=@ resume=UUID=${SWAP_UUID} quiet pcie_acs_override=downstream rd.modules-load=vfio-pci iommu=pt intel_iommu=on
EOF
# systemd-boot loader config.
tee /mnt/arch/boot/loader/loader.conf <<EOF > /dev/null
timeout 0
default arch
EOF
#-----------------------------------------------------------------------------------------------------------------------
# Setup snapshot system.
# http://ramsdenj.com/2016/04/05/Using-Btrfs-for-Easy-Backup-and-Rollback.html
printf "\n\nSetup btrfs snapshot management.\n"
arch-chroot /mnt/arch /bin/bash <<-EOC
# Remove unwanted grub hook since we do not use grub, which will avoid a safe-to-ignore error that will show up each
# time snap-pac is updated.
rm -f /usr/share/libalpm/hooks/99_grub-config.hook
# Create the snapper configuration files for root and home.
snapper --no-dbus -c root create-config /
snapper --no-dbus -c home create-config /home
# Snapper makes unwanted subvols.
btrfs sub delete /.snapshots
btrfs sub delete /home/.snapshots
# Create desirable snapshot subvols for root & home.
btrfs sub create /mnt/btrfs-pool/@snapshots/root
btrfs sub create /mnt/btrfs-pool/@snapshots/home
# Create the paths snapper will be looking for & mount the above subvols to them.
mkdir /home/.snapshots
mkdir /.snapshots
mount -t btrfs -o defaults,compress=lzo,subvol=@snapshots/home "${DATA1_MAPPED}" /home/.snapshots
mount -t btrfs -o defaults,compress=lzo,subvol=@snapshots/root "${DATA1_MAPPED}" /.snapshots
EOC
# Regen fstab, pruning out efivars, gvfsd-fuse & external media.
printf "\n\nRegenerating fstab.\n"
# # Breakdown of actions:
# # 1. Generates the new fstab.
# # 2. Inverse the file.
# # 3. Removes all lines containing "efivars", "gvfsd-fuse" or "/run/media", as well as the line below them.
# # 4. Inverse the file again.
# # 5. Write the file to /etc/fstab.
# genfstab -pU /mnt/arch | tac | sed '/(efivarfs|gvfsd-fuse|\/run\/media)/I,+2 d' | tac | tee /mnt/arch/etc/fstab
genfstab -pU /mnt/arch > /mnt/arch/etc/fstab
cat /mnt/arch/etc/fstab
#-----------------------------------------------------------------------------------------------------------------------
# Setup the users.
printf "\n\nPlease enter below the desired root password.\n"
arch-chroot /mnt/arch /bin/bash -c 'passwd'
printf "\n\nAdding user '%s'.\n" "${DESIRED_USERNAME}"
arch-chroot /mnt/arch /bin/bash -c "groups '${DESIRED_USERNAME}' > /dev/null 2>&1 || useradd --create-home --groups wheel,storage,power,users,audio,video,optical --shell /bin/bash ${DESIRED_USERNAME}"
printf "\n\nPlease enter below the desired password for ${DESIRED_USERNAME}.\n"
arch-chroot /mnt/arch /bin/bash -c "passwd ${DESIRED_USERNAME}"
printf "\n\nAllowing ${DESIRED_USERNAME} to sudo without a password.\n"
sudo tee "/mnt/arch/etc/sudoers.d/${DESIRED_USERNAME}" <<EOF > /dev/null
${DESIRED_USERNAME} ALL=NOPASSWD: ALL
EOF
#-----------------------------------------------------------------------------------------------------------------------
# Add a convenience script.
# NOTE: Short URL resolves to: https://gist.github.com/redeemed2011/3387d18d5e8f0274b0e3/raw/post-install-additions.sh
wget https://goo.gl/HGlSC3 -O "/mnt/arch/home/${DESIRED_USERNAME}/post-install-additions.sh"
arch-chroot /mnt/arch /bin/bash <<EOC
chown '${DESIRED_USERNAME}:${DESIRED_USERNAME}' '/home/${DESIRED_USERNAME}/post-install-additions.sh'
chmod +x '/home/${DESIRED_USERNAME}/post-install-additions.sh'
EOC
#-----------------------------------------------------------------------------------------------------------------------
# Cleanup.
unmount_all
#!/usr/bin/env sh
#
# TODO:
# * ...
set -e
# set -x
#-----------------------------------------------------------------------------------------------------------------------
# Config.
#--YOUR-CUSTOMIZATIONS-BELOW--------------------------------------------------------------------------------------------
# General.
DESIRED_COUNTRY='US'
DESIRED_TIMEZONE='America/Chicago'
DESIRED_LOCALE='en_US.UTF-8 UTF-8'
DESIRED_LOCALE2='en_US.UTF-8'
DESIRED_LANGUAGE='en_US'
DESIRED_HOSTNAME='bo-laptop'
DESIRED_USERNAME='bo'
# If these devs are not found, will default to /dev/sda & /dev/sdb.
DEV_DRIVE1='/dev/nvme0n1'
DEV_DRIVE2='/dev/nvme1n1'
# Partition numbers.
PARTNUM_EFI='1'
PARTNUM_SWAP1='2'
PARTNUM_DATA1='3'
PARTNUM_SWAP2='1'
PARTNUM_DATA2='2'
# Swap size in harddrive sectors.
SWAP_SIZE=34603007
#--DO-NOT-MODIFY-ANYTHING-BEYOND-THIS-LINE-UNLESS-NECESSARY-------------------------------------------------------------
# Key file.
KEYFILE_NAME='multikeyfile'
KEYFILE="/mnt/boot/${KEYFILE_NAME}"
KEYFILE_MAPPED="/dev/mapper/${KEYFILE_NAME}"
# /dev/mapper/* related.
DATA1_MAPNAME='container1'
DATA2_MAPNAME='container2'
DATA1_MAPPED="/dev/mapper/${DATA1_MAPNAME}"
DATA2_MAPPED="/dev/mapper/${DATA2_MAPNAME}"
SWAP1_MAPNAME='swap1'
SWAP2_MAPNAME='swap2'
SWAP1_MAPPED="/dev/mapper/${SWAP1_MAPNAME}"
SWAP2_MAPPED="/dev/mapper/${SWAP2_MAPNAME}"
SWAP_RAID='/dev/md1'
# Used later.
PART_EFI=''
PART_SWAP1=''
PART_DATA1=''
PART_SWAP2=''
PART_DATA2=''
SWAP_UUID=''
ROOT_UUID=''
#-----------------------------------------------------------------------------------------------------------------------
# General Methods.
wait_for_user_input() {
printf "\nPress ENTER to continue.\n"
read
}
# Chopped up version of armrr.
# https://github.com/Gen2ly/armrr
dld_mirror_list() {
# "sh" shell doesn't support local variables so these will be global. :/
# TODO: test this install script in bash.
url="https://www.archlinux.org/mirrorlist/?country=${DESIRED_COUNTRY}&protocol=http&ip_version=4&use_mirror_status=on"
tmp_ml=$(mktemp --suffix=-mirrorlist)
if curl -s "${url}" -o "${tmp_ml}"; then
if ! grep "^## Arch Linux repository mirrorlist" "${tmp_ml}" > /dev/null; then
echo 'Warning: Downloaded mirrorlist invalid. Not using.'
return
fi
else
echo 'Warning: Download of mirrorlist failed. Not using.'
return
fi
# Enable all servers.
sed -i 's/^#Server/Server/g' "${tmp_ml}"
# Copy over the new mirror list.
install -Dm644 "${tmp_ml}" /etc/pacman.d/mirrorlist
}
# Attempts to find a device for our work. If passing a unix-style dev, like "nvme" drives, pass the full dev; e.g.
# '/dev/nvme0n1' rather than '/dev/nvme0'.
#
# Takes two arguments:
# 1. our desired dev; e.g. '/dev/nvme0'
# 2. our allowable fallback dev; e.g. '/dev/sda'
find_proper_drive() {
ourdev="$1"
defaultdev="$2"
returndev="${ourdev}"
if [ ! -e "${ourdev}" ]; then
returndev="${defaultdev}"
fi
# Is the device NVME? Does it not end in "n1"? If both are true, then append "n1" to the dev name.
if [ "${returndev#*nvme}" != "${returndev}" -a "${returndev%n1}" == "${returndev}" ]; then
returndev="${returndev}n1"
fi
printf "%s" "${returndev}"
}
find_proper_partition() {
ourdev="$1"
ourpart="$2"
if [ "${ourdev#*nvme}" != "${ourdev}" ]; then
ourdev="${ourdev}p"
fi
printf "%s%s" "${ourdev}" "${ourpart}"
}
unmount_all() {
set +e
swapoff "${SWAP_RAID}"
mdadm --stop --force "${SWAP_RAID}"
cryptsetup close "${SWAP1_MAPNAME}"
cryptsetup close "${SWAP2_MAPNAME}"
umount -R /mnt/arch/home
umount -R /mnt/arch
umount -R /mnt/btrfs-pool
cryptsetup close "${DATA1_MAPNAME}"
cryptsetup close "${DATA2_MAPNAME}"
umount -R "${DATA1_MAPPED}"
umount -R "${DATA2_MAPPED}"
cryptsetup close "${KEYFILE_NAME}"
umount -R "${KEYFILE_MAPPED}"
umount -R /mnt/boot
set -e
}
#-----------------------------------------------------------------------------------------------------------------------
# General Prep.
# https://wiki.archlinux.org/index.php/beginners'_guide#Update_the_system_clock
# https://wiki.archlinux.org/index.php/beginners'_guide#Select_the_mirrors
# https://wiki.archlinux.org/index.php/Mirrors
# Ensure nothing is mounted that we intend to mount later.
unmount_all
printf "\n\nActivating network time to ensure the system's time is correct.\n"
sudo tee /etc/systemd/timesyncd.conf <<-'EOF' > /dev/null
[Time]
NTP=0.north-america.pool.ntp.org 1.north-america.pool.ntp.org 2.north-america.pool.ntp.org 3.north-america.pool.ntp.org
FallbackNTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org
EOF
timedatectl set-ntp true
printf "\n\nRanking pacman mirrors.\n"
dld_mirror_list
printf "\n\nEnabling multilib.\n"
sed -i '/[#]*\[multilib\]/ { N; d; }' /etc/pacman.conf
sed -i '/[#]*\[archlinuxfr\]/ { N; N; d; }' /etc/pacman.conf
tee -a /etc/pacman.conf <<'EOF' > /dev/null
[multilib]
Include = /etc/pacman.d/mirrorlist
[archlinuxfr]
SigLevel = Never
Server = http://repo.archlinux.fr/$arch
EOF
printf "\n\nInstalling latest utils.\n"
pacman -Sy --noconfirm btrfs-progs
# Figure out if we have devices to raid.
DEV_DRIVE1="$(find_proper_drive "${DEV_DRIVE1}" "/dev/sda")"
DEV_DRIVE2="$(find_proper_drive "${DEV_DRIVE2}" "/dev/sdb")"
#-----------------------------------------------------------------------------------------------------------------------
# Discover proper partition names.
PART_EFI="$(find_proper_partition "${DEV_DRIVE1}" "${PARTNUM_EFI}")"
PART_SWAP1="$(find_proper_partition "${DEV_DRIVE1}" "${PARTNUM_SWAP1}")"
PART_DATA1="$(find_proper_partition "${DEV_DRIVE1}" "${PARTNUM_DATA1}")"
PART_SWAP2="$(find_proper_partition "${DEV_DRIVE2}" "${PARTNUM_SWAP2}")"
PART_DATA2="$(find_proper_partition "${DEV_DRIVE2}" "${PARTNUM_DATA2}")"
#-----------------------------------------------------------------------------------------------------------------------
# The Key.
# https://bbs.archlinux.org/viewtopic.php?id=196840
[ ! -d /mnt/boot ] && mkdir -p /mnt/boot
mount "${PART_EFI}" /mnt/boot
# Decrypt and open the keyfile.
printf "\n\nEnter your encrypt password when prompted below.\n"
cryptsetup open --type luks "${KEYFILE}" "${KEYFILE_NAME}"
#-----------------------------------------------------------------------------------------------------------------------
# Encrypted BTRFS.
# https://wiki.archlinux.org/index.php/beginners'_guide#Format_the_file_systems_and_enable_swap
# http://kneit.in/2015/09/17/brtfs-raid-on-dmcrypt.html#planning-your-disk-layout
printf "\n\nOpening the containers for our array.\n"
cryptsetup open --type luks \
--key-file "${KEYFILE_MAPPED}" --keyfile-offset 1024 --keyfile-size 512 "${PART_DATA1}" \
"${DATA1_MAPNAME}"
cryptsetup open --type luks \
--key-file "${KEYFILE_MAPPED}" --keyfile-offset 1536 --keyfile-size 512 "${PART_DATA2}" \
"${DATA2_MAPNAME}"
# Close the no longer needed cryptkey.
cryptsetup close "${KEYFILE_NAME}"
# Mount our BTRFS RAID--defaults for mounting on NVME are fine, just add compression cause it's good stuff.
# WARNING: Do not add "discard" to mounting NVME SSDs! Btrfs does not do this by default, which is good.
[ ! -d /mnt/btrfs-pool ] && mkdir /mnt/btrfs-pool
mount -t btrfs -o compress=lzo "${DATA1_MAPPED}" /mnt/btrfs-pool
# Change our working dir.
pushd /mnt/btrfs-pool
# List our subvols.
btrfs sub list .
# Reset our current working folder.
popd
#!/usr/bin/env sh
#
# TODO:
# * ...
set -e
set -x
#-----------------------------------------------------------------------------------------------------------------------
# Config.
#-----------------------------------------------------------------------------------------------------------------------
# General Methods.
wait_for_user_input() {
printf "\nPress ENTER to continue.\n"
read
}
#-----------------------------------------------------------------------------------------------------------------------
# Main.
# # Enable a key VMWare service if using VMWare.
# # TODO: COMMENT OUT VMWARE.
# sudo systemctl enable vmware-vmblock-fuse.service
# sudo systemctl start vmware-vmblock-fuse.service
printf "\n\nEnabling network services.\n"
sudo rm -f /etc/resolv.conf
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl enable systemd-networkd
# sudo systemctl enable wpa_supplicant
sudo systemctl enable systemd-resolved
sudo systemctl enable systemd-timesyncd
# Backup the wpa_supplicant.conf file.
[ -e '/etc/wpa_supplicant/wpa_supplicant.conf' ] && \
sudo mv /etc/wpa_supplicant/wpa_supplicant.conf{,-orig}
# Create a pruned config using what was the defaults at the time of this script's creation.
sudo tee /etc/wpa_supplicant/wpa_supplicant.conf <<'EOF' > /dev/null
ctrl_interface=/var/run/wpa_supplicant
eapol_version=1
ap_scan=1
fast_reauth=1
EOF
# https://wiki.archlinux.org/index.php/systemd-networkd#Wired_and_wireless_adapters_on_the_same_machine
# http://lukeluo.blogspot.com/2015/04/the-best-way-to-configure-network.html
printf "\n\nConfiguring networking to use DHCP for wired and wireless connections.\n"
tee cfg-net.sh <<'EOF' > /dev/null
#!/usr/bin/env sh
# Trim off any pathing in the NIC name.
NIC="$1"
NIC="${NIC##*/}"
# Don't create a network configuration file for the loopback device.
if [ "${NIC#*lo}" != "${NIC}" ]; then
echo 'Skipping loop-back device.'
exit 0
fi
# Ensure the path exists.
[ ! -d '/etc/systemd/network' ] && mkdir -p /etc/systemd/network
# "Calculate" the NIC's metric (priority) by multiplying the current number of network configuration files by 10.
# Lower value is higher priority.
NIC_METRIC="$(ls -1 /etc/systemd/network/ | wc -l)"
# Increase the route metric for all devs that start with a "w", which usually are wifi adapters.
case "${NIC}" in
w*)
NIC_METRIC="1${NIC_METRIC}"
;;
*)
NIC_METRIC="0${NIC_METRIC}"
;;
esac
# Create the NIC's configuration file for systemd-network.
sudo tee /etc/systemd/network/${NIC}.network <<EON > /dev/null
[Match]
Name=${NIC}
[Network]
DHCP=ipv4
IPv6PrivacyExtensions=true
# defaults to true but adding it here to help us connect the dots to /etc/systemd/resolved.conf
LLMNR=true
# Add the device to the default bridge so that any VMs we run may run with bridge networking!
Bridge=br0
[DHCP]
# "Metric The 'distance' to the target (usually counted in hops)." from route man page. So lower is higher priority.
RouteMetric=${NIC_METRIC}
EON
# # Enable automatic DHCP for our interface.
# set +e
# sudo systemctl enable netctl-ifplugd@${NIC}.service
# sudo systemctl start netctl-ifplugd@${NIC}.service
# sudo systemctl enable netctl-auto@${NIC}.service
# sudo systemctl start netctl-auto@${NIC}.service
# set -e
EOF
chmod +x cfg-net.sh
sudo find -P /sys/class/net -type l -exec ./cfg-net.sh '{}' \;
rm -f cfg-net.sh
# # Create a wildcard NIC configuration file for systemd-network.
# sudo tee /etc/systemd/network/wildcard-dhcpd.network <<EON > /dev/null
# [Match]
# Name=*
# [Network]
# DHCP=ipv4
# IPv6PrivacyExtensions=true
# Bridge=br0
# EON
# Network bridge.
# https://major.io/2015/03/26/creating-a-bridge-for-virtual-machines-using-systemd-networkd/
sudo tee /etc/systemd/network/br0.netdev <<'EOF' > /dev/null
[NetDev]
Name=br0
Kind=bridge
EOF
sudo tee /etc/systemd/network/br0.network <<'EOF' > /dev/null
[Match]
Name=br0
[Network]
# DNS=192.168.149.1
# Address=192.168.149.33/24
# Gateway=192.168.149.1
DHCP=ipv4
IPv6PrivacyExtensions=true
# defaults to true but adding it here to help us connect the dots to /etc/systemd/resolved.conf
LLMNR=true
EOF
sudo modprobe br_netfilter
echo 'br_netfilter' | sudo tee /etc/modules-load.d/br_netfilter.conf
# Disable the firewall on the bridge.
sudo tee /etc/sysctl.d/10-disable-firewall-on-bridge.conf <<'EOF' > /dev/null
net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0
EOF
sudo sysctl -p /etc/sysctl.d/10-disable-firewall-on-bridge.conf
# Enable IPv4 forwarding.
sudo sysctl net.ipv4.ip_forward=1
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-sysctl.conf
# Load tun module.
sudo modprobe tun
echo 'tun' | sudo tee /etc/modules-load.d/tun.conf
sudo systemctl restart systemd-networkd
# sudo systemctl restart wpa_supplicant
sudo systemctl restart systemd-resolved
sudo systemctl restart systemd-timesyncd
tee cfg-net.sh <<'EOF' > /dev/null
#!/usr/bin/env sh
# Trim off any pathing in the NIC name.
NIC="$1"
NIC="${NIC##*/}"
if [ "${NIC#w*}" == "${NIC}" ]; then
echo "Skipping ${NIC}."
exit 0
fi
# Create a wpa_supplicant profile for wifi adapters & enable them.
sudo ln -sf /etc/wpa_supplicant/wpa_supplicant.conf "/etc/wpa_supplicant/wpa_supplicant-${NIC}.conf"
sudo systemctl enable wpa_supplicant@${NIC}
sudo systemctl restart wpa_supplicant@${NIC}
EOF
chmod +x cfg-net.sh
sudo find -P /sys/class/net -type l -exec ./cfg-net.sh '{}' \;
rm -f cfg-net.sh
# Give the NIC(s) time to "spin up".
sleep 6
printf "\n\nEnabling NTP (network time).\n"
sudo timedatectl set-ntp true
printf "\n\nUpdating package index and install package updates.\n"
sudo pacman -Syu
# Temporarily configure yaourt to suppress build & edit prompts.
tee ~/.yaourtrc <<'EOF' > /dev/null
BUILD_NOCONFIRM=1
EDITFILES=0
EOF
# moka-icon-theme-git: needed by vertex-icons-git.
# ttf-liberation: fix fonts for some PDFs in Google Chrome.
# displaylink: allows display link external monitor support.
printf "\n\nInstalling packages from user repo.\n"
yaourt -Sy --noconfirm \
gitg \
google-chrome \
hibernate-script \
insync \
snap-pac \
sublime-text-nightly \
ttf-liberation \
vagrant \
virtualbox \
virtualbox-guest-iso \
virtualbox-ext-oracle \
chrome-gnome-shell-git \
moka-icon-theme-git \
seahorse \
cheese \
file-roller \
gdm \
gedit \
gedit-code-assistance \
gksu \
gnome \
gnome-characters \
gnome-color-manager \
gnome-documents \
gnome-logs \
gnome-nettool \
gnome-photos \
gnome-software \
gnome-sound-recorder \
gnome-tweak-tool \
vertex-icons-git \
vertex-themes \
vinagre \
# plasma-meta kde-applications-meta plasma-wayland-session \
# Not sure if these are useful at this time.
# displaylink \
# systemd-vgaswitcheroo-units \
# steam related:
# lib32-libjpeg6-turbo \
# steam-libs \
# xorg-server \
# xorg-server-utils \
#-----------------------------------------------------------------------------------------------------------------------
# KVM + VFIO + libvirt + qemu -- GPU passthrough.
# Older guide:
# http://www.se7ensins.com/forums/threads/how-to-setup-a-gaming-virtual-machine-with-gpu-passthrough-qemu-kvm-libvirt-and-vfio.1371980/
# Newer guide:
# http://chanster.net/article/2016/03/05/qemu-gpu-passthrough/
# # Enable the "service" that will bind the GPU to VFIO on boot.
# sudo systemctl enable vfio-bind.service
#-----------------------------------------------------------------------------------------------------------------------
# Restore the yaourt config to safe settings.
# Change our yaourtrc config.
tee ~/.yaourtrc <<'EOF' > /dev/null
# To suppress build prompts.
#BUILD_NOCONFIRM=1
# To suppress edit prompts.
#EDITFILES=0
EOF
#-----------------------------------------------------------------------------------------------------------------------
# Multi-monitor related.
# https://wiki.archlinux.org/index.php/DisplayLink
# sudo systemctl enable displaylink.service
# sudo systemctl restart displaylink.service
# sudo systemctl enable vgaswitcheroo.service
#-----------------------------------------------------------------------------------------------------------------------
# VirtualBox related.
# https://wiki.archlinux.org/index.php/VirtualBox
# Install the virtualbox kernel modules.
# NOTE: this steps to be automated now by a virtualbox related package listed above.
# sudo dkms install vboxhost/$(sudo pacman -Q virtualbox|awk '{print $2}'|sed 's/\-.\+//') -k $(uname -rm|sed 's/\ /\//')
# Add the user to the vboxusers group.
sudo gpasswd -a ${USER} vboxusers
#-----------------------------------------------------------------------------------------------------------------------
# Snapper related.
# https://wiki.archlinux.org/index.php/Snapper
printf "\n\nEnable Snapper for snapshots.\n"
sudo systemctl start snapper-timeline.timer snapper-cleanup.timer
sudo systemctl enable snapper-timeline.timer snapper-cleanup.timer
# Install snapper gui.
sudo git clone https://github.com/ricardo-vieira/snapper-gui/ /opt/snapper-gui
pushd /opt/snapper-gui
sudo python3 setup.py install
popd
# Fix snapper gui to launch with sudo.
sudo sed -i 's/^Exec=.*/Exec=gksudo snapper-gui/i' /usr/share/applications/snapper-gui.desktop
#-----------------------------------------------------------------------------------------------------------------------
# General.
# Install "ps_mem" util which accurrately gathers memory used by each running program.
sudo pip install ps_mem
# printf "\n\nEnable gnome display manager (graphical interface).\n"
# sudo systemctl enable gdm.service
sudo systemctl enable sddm.service
printf "\n\nNo errors, so rebooting.\n"
sudo reboot
@redeemed2011
Copy link
Author

redeemed2011 commented Aug 27, 2021

@redeemed2011
Copy link
Author

I expect that every time I try to update the URL for wget ... installer.sh, that the hash will change. Just know that at this time the link in the document is correct.

I've not updated this code in years.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment