Linux to my taste

2026-03-26

Linux

In this post I’ll document some of the tweaks I made to customize Linux to my taste. It is the third part of a series about installing Linux on my work laptop.

Living without NetworkManager

This time I decided not to install NetworkManager. I’ll try to only use command-line tools and configuration to manually achieve internet connectivity.

WiFi

I saw iwd for the first time in the Arch Linux installation ISO, which uses it for WiFi connectivity. In the past, when I installed Arch, I was always plugged to an ethernet cable, so I didn’t even notice this tool. I found the experience quite enjoyable, so I installed it in my main system, too. At every boot, I run:

sudo systemctl start iwd systemd-resolved

The very first time I also had to run iwctl and follow the instructions, but then iwd will remember the networks and passwords previously entered. I also enabled its DHCP client.

While iwd can do DHCP if enabled, it doesn’t have a built-in DNS resolver, so I use systemd-resolved. Perhaps in the future I’ll replace both the built-in DHCP client and systemd-resolved with dnsmasq.

Further reading for my future self:

  • https://tailscale.com/blog/sisyphean-dns-client-linux
  • https://zwischenzugs.com/2018/06/08/anatomy-of-a-linux-dns-lookup-part-i/
Ethernet

I haven’t had the chance to connect to a wired network yet.

VPN

I use either openconnect or openvpn to connect to my workplace’s VPNs. For my home lab, I use wireguard. Everything happens over the command line.

Power saving

In case you have missed the previous chapter, my laptop configuration tries hard to copy a MacBook. One of the best features of Apple hardware is the long battery life, so I had to do something about that. My initial idea was to scale down the CPU frequency, or even try to underprioritize some of the cores. I did a bit of research and I tried auto-cpufreq, but I wasn’t enthusiastic at the idea of having a daemon constantly running in the background. My requirement was much simpler: I didn’t care about fine-tuning and optimization, I just wanted to completely obliterate the CPU frequency when running on battery.

Accomplishing this is quite easy with udev rules. This is an event-driven system that reacts to changes in the peripherals of the computer. Users and administrators can define rules that are triggered upon such events. Initially I wrote my own rules1, but then, after a bit more research, I decided to install TLP. Basically, it does the same thing, but with more care and thought than I could ever hope to put into this project. Not only can it tune the CPU frequency, but it also does other things to prevent power leaks, such as turning off unused USB devices and network interfaces. Here is how I installed it:

sudo pacman -S tlp
sudo systemctl mask systemd-rfkill.service systemd-rfkill.socket
sudo systemctl enable --now tlp

And this is the custom configuration file that I dropped under /etc/tlp.d/:

DEVICES_TO_ENABLE_ON_STARTUP="wifi"

PLATFORM_PROFILE_ON_AC=balanced
PLATFORM_PROFILE_ON_BAT=low-power
PLATFORM_PROFILE_ON_SAV=low-power

CPU_ENERGY_PERF_POLICY_ON_AC=balance_performance
CPU_ENERGY_PERF_POLICY_ON_BAT=power
CPU_ENERGY_PERF_POLICY_ON_SAV=power
CPU_SCALING_MIN_FREQ_ON_AC=0
CPU_SCALING_MAX_FREQ_ON_AC=4972435
CPU_SCALING_MIN_FREQ_ON_BAT=0
CPU_SCALING_MAX_FREQ_ON_BAT=405914
CPU_SCALING_MIN_FREQ_ON_SAV=0
CPU_SCALING_MAX_FREQ_ON_SAV=405914

On battery, besides enabling the power saving mode, the maximum CPU frequency is nailed down to 405914 kHz (which is the absolute minimum my CPU can stand), while on AC power it the limit is brought back to 4972435 kHz. Unfortunately, I couldn’t find a way to set these values dynamically, but I used tlp-stat -p to find out about the min and max frequency limits of my CPU.

It is particularly cool to watch the CPU frequency change happen in real time. Under normal usage, I wouldn’t even notice that anything changed, but I can run

watch -n1 "grep MHz /proc/cpuinfo"

to follow the CPU frequency, and see what happens when I unplug the laptop. Another useful command to debug udev rules is

udevadm control --log-priority=debug; journalctl -f

which shows the events in the system log.

Another thing I tried to do was to set custom charge intervals, so that, for example, the battery only starts to recharge when it’s level goes under a given threshold.

smbios-battery-ctl --set-custom-charge-interval=95 100`

It seems however that my Dell laptop doesn’t support this.

Last but not least, I made sure that hibernation and suspend worked. I didn’t even have to do anything, they just worked out of the box, even with disk encryption and logical volume management. Now if I close my laptop’s lid, it goes into hibernation. At the next startup, I enter the password to decrypt the partition and am immediately brought back to where I was.

Keyboard shortcuts

This section attempts to tracks my shortcuts and how they were set.2

Copying and pasting
  • Alt+C: copy
  • Alt+V: paste
  • Shift+Alt+V: show clipboard
# File: hypr.conf
# Ref: https://satya164.page/posts/macos-like-shortcuts-in-hyprland
exec-once = wl-paste --primary --watch cliphist store
bind = $mainMod SHIFT, V, exec, cliphist list | wofi --dmenu --pre-display-cmd "echo '%s' | cut -f 2 | tr -d '\n'" | cliphist decode | wl-copy
bind = $mainMod, C, sendshortcut, CTRL, INSERT,
bind = $mainMod, V, sendshortcut, SHIFT, INSERT,

Miscellanea

Virtual console

At boot, I am asked for the password to decrypt the SSD. This prompt changes the resolution of the screen, for some reason. What is even weirder is that resolution appears to change 1 second after the prompt appears, and after I press enter, the resolution goes back to the original. I found this post which suggests to disable early KMS start, and it did improve somewhat: now the resolution changes immediately when the prompt is shown, not after 1 second. The same user here suggested that this might just be a bug in the sd-encrypt hook.

I installed Plymouth and added the corresponding HOOK to /etc/mkinitcpio.conf, and it did kind of improve the display. There are still some flickers, though.

I wonder if using a different virtual console, such as KMSCON, would help.


  1. Here they are, for reference:

    SUBSYSTEM=="power_supply", KERNEL=="AC", ATTR{online}=="0", RUN+="/bin/sh -c 'for policy in `ls /sys/devices/system/cpu/cpufreq/policy*/energy_performance_preference`; do echo power > $$policy; done'"
    SUBSYSTEM=="power_supply", KERNEL=="AC", ATTR{online}=="0", RUN+="/bin/sh -c 'for policy in `ls /sys/devices/system/cpu/cpufreq/`; do cat /sys/devices/system/cpu/cpufreq/$${policy}/cpuinfo_min_freq > /sys/devices/system/cpu/cpufreq/$${policy}/scaling_max_freq; done'"
    SUBSYSTEM=="power_supply", KERNEL=="AC", ATTR{online}=="0", RUN+="/bin/sh -c 'echo 0 > /sys/devices/system/cpu/cpufreq/boost'"
    
    SUBSYSTEM=="power_supply", KERNEL=="AC", ATTR{online}=="1", RUN+="/bin/sh -c 'for policy in `ls /sys/devices/system/cpu/cpufreq/policy*/energy_performance_preference`; do echo balance_performance > $$policy; done'"
    SUBSYSTEM=="power_supply", KERNEL=="AC", ATTR{online}=="1", RUN+="/bin/sh -c 'for policy in `ls /sys/devices/system/cpu/cpufreq/`; do cat /sys/devices/system/cpu/cpufreq/$${policy}/cpuinfo_max_freq > /sys/devices/system/cpu/cpufreq/$${policy}/scaling_max_freq; done'"
    SUBSYSTEM=="power_supply", KERNEL=="AC", ATTR{online}=="1", RUN+="/bin/sh -c 'echo 1 > /sys/devices/system/cpu/cpufreq/boost'"
    ↩︎
  2. Sometimes, if I don’t use a shortcut for an extended period of time, I forget that I had already set it.↩︎

 Marginalia

Leave a comment