Posted on July 21, 2017

New job, new laptop -- More arch

One of the nice perks of having a new job is that with it comes a new laptop and an oportunity to redocument getting Arch in it. The people at Jodel were super kind and got me a brand new Thinkpad P51s and I spent the last week playing with it and learning a lot in the process.

But for me, this exercise is more than just installing the OS. One of the promises of Arch is to be your whatever you want it to be. After all, you install it and you only have the terminal and the root user. So for me, going through several iterations of installing Arch gives me a chance to add new features and remove old things that ended up not working so well.

For this iteration, here’s what I want to do:

These were all things which I did not focus on in my last build and so it’s time to set up a new baseline.

Preliminaries

The installation follows pretty much what the Arch Wiki says. I relied almost completely in it so in this document I mostly explain the things I changed.

EFI Boot and a bootloader

Turns out that the requirements to have the system boot from EFI are pretty straightforward, but do require you to read some stuff before jumping into the instalation. Besides guaranteeing that your system booted in UEFI mode, spend some time reading about the boot loaders you have available. I opted for systemd-boot and this was my reading list:

Note that in the instalation guide, this step comes at the end. However, there is quite a bit of reading and checking that needs to be done so spending the time upfront doing this is a good idea.

Network connection and system clock

It goes without saying that it’s better to be connected to the internet as you do all of this. You’ll also need to enable network time synchronization:

    timedatectl set-ntp true

Partitioning

Here’s my partitioning scheme:

Formatting and mounting

    mkfs.ext4 /dev/nvme0n1p2
    mkfs.fat -F32 /dev/nvme0n1p1
    mount /dev/nvme0n1p2 /mnt
    mkdir /mnt/boot
    mount /dev/nvme0n1p1 /mnt/boot

Installing

I followed the installation guide to the letter. I still leave the individual commands I issued here for completion:

Installing base system

    pacstrap /mnt base
    genfstab -U /mnt >> /mnt/etc/fstab

Chroot and System Configuration

    arch-chroot /mnt
    pacman -Syyu emacs-nox connman intel-ucode wpa_supplicant

Time zone

    ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime
    hwclock --hctosys

Confirm that the time is correct with date.

Locale and Console

Let’s emacs /etc/locale.gen and uncommented en_GB.UTF-8 UTF-8. After that:

    locale-gen
    echo 'LANG=en_GB.UTF-8' > /etc/locale.conf
    echo `KEYMAP=pt-latin9` > /etc/vconsole.conf
    echo `FONT=Lat2-Terminus16` >> /etc/vconsole.conf

Hostname

My new machine is called voyager.

    echo 'voyager' > /etc/hostname
    echo '127.0.1.1	voyager.localdomain voyager' >> /etc/hosts
    

Boot loader

As I mentioned before, there is a lot more to these steps. I went through some trial and error but this is, essentially, what you need:

    bootctl --path=/boot install
    cp /usr/share/systemd/bootctl/loader.conf /boot/loader/loader.conf
    cp /usr/share/systemd/bootctl/arch.conf /boot/loader/entries/arch.conf

With these files in place, you’ll have to run blkid -s PARTUUID -o value /dev/nvme0n1p2 to find out the UUID of the root partition and add it to /boot/loader/entries/arch.conf. That file will look something like this:

    title          Arch Linux
    linux          /vmlinuz-linux
    initrd         /initramfs-linux.img
    options        root=PARTUUID=14420948-2cea-4de7-b042-40f67c618660 rw

Initramfs

    mkinitcpio -p linux

Passwd and reboot

Finally we give a password to root, exit the chroot shell, unmount the system and reboot:

    passwd
    exit
    umount -R /mnt
    systemctl reboot

After rebot you should now be in your freshly installed Arch Linux. We’re ready to configure it.

Settinng up Wifi

Since connman and wpa_supplicant were already installed, it’s now time to play with it. Following the instructions in the connman page should be enough:

Use systemctl --type=service to check if there’s any other network service running and if so disable it. Then:

    systemctl enable connman.service
    systemctl reboot

After rebooting, the sequence of commands should be something like:

    connmanctl technologies
    connmanctl enable wifi
    connmanctl services
    

The last command should show you the nearby SSIDs. If that worked, it’s time to permanently connect, using connmanctl in interactive mode:

    connmanctl
    scan wifi
    services
    agent on
    connect wifi_...
    quit

Disconnect the wired connection and reboot. You should end up with wifi connected and in the SSID you chose.

I also added some configuration to /etc/connman/main.conf:

    [General]
    AllowHostnameUpdates=false
    PreferredTechnologies=ethernet,wifi
    SingleConnectedTechnology=true

Fish and adding a user

    pacman -S sudo

Let’s visudo and uncomment the wheel group line. Now let’s ge Fish and set it up for root and the new user:

    pacman -S fish
    chsh -s /usr/bin/fish

Exit and login again. If Fish is working fine for root, we add the new user:

    useradd --shell /usr/bin/fish --create-home -m -G wheel luis
    passwd luis

From now on, I’ll always assume the user is no longer root (and therefore will be sudoing everything which needs to be sudoed).

Graphics and Xorg

Since my system has dual graphics setup, we can’t go about this just by installing the nvidia package. We’re going to use bumblebee for Optimus:

    sudo pacman -S bumblebee mesa nvidia xf86-video-intel bbswitch
    sudo gpasswd -a luis bumblebee
    sudo gpasswd -a root bumblebee
    sudo systemctl enable bumblebeed.service
    sudo systemctl reboot

We’ll now verify this setup by installing Xorg and minimal window manager:

    sudo pacman -Syyu xorg xorg-xinit awesome
    echo 'exec awesome' > ~/.xinitrc
    localectl set-x11-keymap pt pc104 "" caps:ctrl_modifier,terminate:ctrl_alt_bksp
    startx
    

You should now see the awesome window manager and your mouse and keyboard should work fine.

Last thing we’ll do is to enable Early Kernel Mode Setting, by adding two modules to /etc/mkinitcpio.conf:

    MODULES="intel_agp i915"
    

After this, sudo mkinitcpio -p linux and reboot. You should notice the terminal with higher quality from way sooner in the boot process.

SSH-Agent

I have most of my config for xinit, awesome and many other things in my dot files repo but to eventually change it I need to have the SSH-Agent up and running.

There’s many ways to go about it. I went with adding it to my fish.config, which required some effort to export the environment variables which ssh-agent returns:

    ###############################################
    ## SSH Agent
    setenv SSH_ENV $HOME/.ssh/environment

    function start_agent
        ssh-agent -c | sed 's/^echo/#echo/' > $SSH_ENV
        chmod 600 $SSH_ENV 
        . $SSH_ENV > /dev/null
        ssh-add
    end

    function test_identities
        ssh-add -l | grep "The agent has no identities" > /dev/null
        if [ $status -eq 0 ]
            ssh-add
            if [ $status -eq 2 ]
                start_agent
            end
        end
    end

    if [ -n "$SSH_AGENT_PID" ] 
        ps -ef | grep $SSH_AGENT_PID | grep ssh-agent > /dev/null
        if [ $status -eq 0 ]
            test_identities
        end
    else
        if [ -f $SSH_ENV ]
            . $SSH_ENV > /dev/null
        end
        ps -ef | grep $SSH_AGENT_PID | grep -v grep | grep ssh-agent > /dev/null
        if [ $status -eq 0 ]
            test_identities
        else 
            start_agent
        end
    end

After this, you should be able to run ssh-add ~/.ssh/id_rsa from any terminal.

Swap file

Following the instructions is enough and I did nothing special to set up a swap file:

    sudo fallocate -l 32G /swapy
    sudo chmod 600 /swapy 
    sudo mkswap /swapy 
    sudo swapon /swapy 
    echo '/swapy none swap defaults 0 0' | sudo tee --append /etc/fstab 

Let’s also take the oportunity to set a lower swappiness setting:

    echo 'vm.swappiness=5' | sudo tee /etc/sysctl.d/99-sysctl.conf

Reboot and then confirm the new swapiness level with

    sudo cat /proc/sys/vm/swappiness

Power Management

For power management we’re going to rely completely on systemd, and not use the acpid service.

Enable hibernate to swap file

Following the instructions in the power management page was enough to make this work:

Use sudo filefrag -v /swapy to find the offset of the swap file. Then add it along with the partition UUID of the root partition to the boot loader arch entry file:

    echo 'resume=PARTUUID=3e44d3f3-d4c2-4347-9a87-8ac529c615f2 resume_offset=7421952..' | sudo tee --append /boot/loader/entries/arch.conf

Then add the resume hook to the hooks section in /etc/mkinitcpio.conf. Run sudo mkinitcpio -p linux, reboot and then try to force a hibernate:

    systemctl hibernate

Pressing the power button after hibernate should bring you back from hibernation.

Hibernate on lid down

By default, when I bring the lid down the laptop suspends, rather than hibernating. Here’s how to make it hibernate:

    echo 'HandleLidSwitch=hibernate' | tee --append /etc/systemd/logind.conf

Reboot and it should be working.

Lock screen when coming out of hibernate and suspend

    sudo pacman -S slock

Now we’ll sudo emacs /etc/systemd/system/slock@.service and add the following to it:

    [Unit]
    Description=Lock X session using slock for user %i
    Before=sleep.target

    [Service]
    User=%i
    Environment=DISPLAY=:0
    ExecStartPre=/usr/bin/xset dpms force suspend
    ExecStart=/usr/bin/slock

    [Install]
    WantedBy=sleep.target
    WantedBy=hibernate.target

Enable it with systemctl enable slock@luis.service.

Screen backlight control

    sudo pacman -S xorg-xbacklight xbindkeys

Then use xbacklight --help to learn how to use it and assign the appropriate keys to increasing and decreasing the screen luminosity in a ~/.xbindkeysrc.

Blacklist Bluetooth

    echo "blacklist bluetooth" | sudo tee /etc/modprobe.d/bluetooth.conf
    echo "blacklist btusb" | sudo tee /etc/modprobe.d/btusb.conf

Then we’ll sudo emacs /etc/mkinitcpio.conf and make the FILES section include our two new files:

    FILES="/etc/modprobe.d/btusb.conf /etc/modprobe.d/bluetooth.conf"

After this,

    sudo mkinitcpio -p linux
    reboot

Enabling powersave for the audio card

Use lspci -k to find out your sound card’s driver and then (maybe replacing snd_hda_intel):

    echo "options snd_hda_intel power_save=1" | sudo tee /etc/modprobe.d/audio_powersave.conf

Touchpad

    cp /usr/share/X11/xorg.conf.d/40-libinput.conf /etc/X11/xorg.conf.d/

And then change it accordingly:

    Section "InputClass"
            Identifier "Touchpad"
            MatchIsTouchpad "on"
            MatchDevicePath "/dev/input/event*"
            Option "Tapping" "on"
            Option "DisableWhileTyping" "true"
            Driver "libinput"
    EndSection

Sound

The only thing I had to do, to control the sound with the keyboard keys (and set them with xbindkeys), was to install alsa-utils.

Pacman

We’re going to use the reflector package to have an updated mirror list at all times.

    sudo pacman -S reflector

We now set it so that reflector runs on two occasions: when pacman updates its mirror list, and automatically, every week.

When pacman updates its mirror list

    sudo emacs /etc/pacman.d/hooks/mirrorupgrade.hook

and then use the following code:

    [Trigger]
    Operation = Upgrade
    Type = Package
    Target = pacman-mirrorlist

    [Action]
    Description = Updating pacman-mirrorlist with reflector and removing pacnew...
    When = PostTransaction
    Depends = reflector
    Exec = /usr/bin/env sh -c "reflector --sort score -c Germany -c Denmark -c Poland -c "Czech Republic" -c Switzerland -c Austria -c Netherlands -c France -c Luxembourg  -c Belgium  -a 24 -p https --save /etc/pacman.d/mirrorlist; if [[ -f /etc/pacman.d/mirrorlist.pacnew ]]; then rm /etc/pacman.d/mirrorlist.pacnew; fi"

Automatically, every week

We need two files, first the actual unit we’ll be running:

    sudo emacs /etc/systemd/system/reflector.service

with code:

    [Unit]
    Description=Pacman mirrorlist update

    [Service]
    Type=oneshot
    ExecStart=/usr/bin/reflector --sort score -c Germany -c Denmark -c Poland -c "Czech Republic" -c Switzerland -c Austria -c Netherlands -c France -c Luxembourg  -c Belgium -a 24 -p https --save /etc/pacman.d/mirrorlist

and then the systemd timer

    sudo emacs /etc/systemd/system/reflector.timer

with code:

    [Unit]
    Description=Run reflector daily

    [Timer]
    OnCalendar=weekly
    RandomizedDelaySec=2h
    Persistent=true

    [Install]
    WantedBy=timers.target

We enable and start the timer:

    sudo systemctl enable reflector.timer 
    sudo systemctl start reflector.timer 

Some closing remarks

It is clear that having a good command of systemd and udev is quite essential to do (local) system administration in (Arch) Linux. The nice thing is that they are both quite well documented and both are thought from the ground up as a base to build a lot of automation.

As I just went through this installation log, I cannot help but think that there’s already more things I would like to change:

But for now, what’s done is finished. :-)