<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotfiles/etc, branch master</title>
<subtitle>My linux config and rc files</subtitle>
<id>https://git.sommerfeld.dev/dotfiles/atom/etc?h=master</id>
<link rel='self' href='https://git.sommerfeld.dev/dotfiles/atom/etc?h=master'/>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/'/>
<updated>2026-05-29T10:18:16Z</updated>
<entry>
<title>feat(kernel): swap stock linux for linux-lts as fallback kernel</title>
<updated>2026-05-29T10:18:16Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:16Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=a6f1e9026e5d19b50c7c522e30e6f216fc9f8180'/>
<id>urn:sha1:a6f1e9026e5d19b50c7c522e30e6f216fc9f8180</id>
<content type='text'>
Promotes linux-hardened to the sole primary kernel and replaces
linux with linux-lts as the safety-net fallback. Rationale:

- linux and linux-hardened track the same upstream major version
  and ship within days of each other, so 'linux' was a poor
  fallback for the regression class that historically takes out
  the hardened kernel on this hardware (e.g. checkpoint 026
  wake-from-suspend panic). linux-lts lags by weeks/months and is
  almost always known-good when hardened breaks.
- Drop etc/mkinitcpio.d/linux.preset, add linux-lts.preset.
  Hardened preset header + bootstrap.sh efibootmgr instructions
  updated accordingly (hardened registered first so it's the
  default; lts registered as the on-demand fallback).
- Also add mkinitcpio-firmware (AUR) to silence the spurious
  'missing firmware' warnings during initramfs builds.

Manual host-side steps after deploy:
  paru -S linux-lts linux-lts-headers mkinitcpio-firmware
  sudo pacman -Rsn linux  # or via 'just pkg-apply' undeclared flow
  sudo rm -f /etc/mkinitcpio.d/linux.preset  # chezmoi-deployed, not pkg-owned
  sudo mkinitcpio -P
  sudo efibootmgr  # add the Arch LTS entries, drop the stock linux ones

Note: meta/nvidia.txt still lists 'linux-headers' for nvidia-dkms.
That's a per-host concern; flagged for follow-up if any nvidia host
moves to the linux-lts world.
</content>
</entry>
<entry>
<title>feat(etc/resolved): forward single-label queries upstream</title>
<updated>2026-05-29T10:18:16Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:16Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=fdba57c9c05f321d3a75ae8f2e46e4053193744f'/>
<id>urn:sha1:fdba57c9c05f321d3a75ae8f2e46e4053193744f</id>
<content type='text'>
Enables ResolveUnicastSingleLabel=yes so non-FQDN names like
'sw-jenkins01' get sent to the configured DNS server instead of
being dropped to LLMNR/mDNS. Needed for corp shortname resolution
via Pi-hole CNAME records that point at *.xsight.ent (resolved by
unbound's forward-zone over the new WireGuard bridge).
</content>
</entry>
<entry>
<title>refactor(eer): install external-editor-revived via nix on the host</title>
<updated>2026-05-29T10:18:16Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:16Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=be3c6fda881bc11d5123d6b3a09ce9d250199b32'/>
<id>urn:sha1:be3c6fda881bc11d5123d6b3a09ce9d250199b32</id>
<content type='text'>
The AUR `external-editor-revived` PKGBUILD declares a hard `thunderbird`
dependency, which blocks removing the unused system Thunderbird binary
alongside the org.mozilla.thunderbird flatpak (and pacman's
`AssumeInstalled` is a CLI flag, not a pacman.conf directive, so the
previous workaround was nonfunctional).

Nixpkgs' `external-editor-revived` is just `rustPlatform.buildRustPackage`
plus a relocatable native-messaging manifest — zero mailer dep — so the
host gets it from nix instead.

* nix/host.nix: add `external-editor-revived` to `home.packages`. Kept
  out of `common.nix` so the remote-dev VM (which has no Thunderbird)
  doesn't carry the build closure.
* run_onchange_after_deploy-tb-eer.sh.tmpl: search
  `~/.nix-profile/{bin,lib/mozilla/native-messaging-hosts}` first and
  fall through to the legacy pacman paths. The chezmoi manifest-hash
  probe now checks the nix path too, so the hook re-runs cleanly when
  nix bumps the EER version.
* meta/base.txt: drop the `external-editor-revived` AUR entry and
  rewrite the comment to point at the nix declaration.
* etc/pacman.conf: revert the bogus `AssumeInstalled` directive
  (CLI-only, not pacman.conf).

On-host migration:

    home-manager switch --flake ~/dotfiles/nix#host    # picks up EER
    sudo pacman -Rns external-editor-revived thunderbird mpv
    chezmoi apply -v                                   # re-runs tb-eer hook
</content>
</entry>
<entry>
<title>refactor(flatpak): route mpv and thunderbird via flatpak; drop system pkgs</title>
<updated>2026-05-29T10:18:16Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:16Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=cd1c92b746a51a6994281f34a5f773c37d1d2dfe'/>
<id>urn:sha1:cd1c92b746a51a6994281f34a5f773c37d1d2dfe</id>
<content type='text'>
Both org.mozilla.thunderbird and io.mpv.Mpv are already installed via
flatpak, but several places still launched the system binaries (because
they were in PATH). Worse, `mpv` was kept on the host *only* for the
streamlink-launches-mpv path, and `thunderbird` was being pulled in as
a hard dep of external-editor-revived even though it was never the
mailer actually used. Untangle both.

Thunderbird
-----------
* dot_config/sway/executable_tb-toggle.sh,
  dot_config/sway/executable_tb-autostart.sh:
    swap `thunderbird` → `flatpak run org.mozilla.thunderbird`. The
    `app_id` matcher in sway config already targets the flatpak id, so
    the scratchpad-stash and Super+t toggle keep working unchanged.
* etc/pacman.conf:
    add `AssumeInstalled = thunderbird=999.0-1`. external-editor-revived
    (AUR) hard-depends on `thunderbird`; this satisfies the dep without
    installing the package. Run `sudo pacman -Rns thunderbird` after
    deploy to remove the now-unneeded system binary.
* meta/base.txt: document the AssumeInstalled trick next to the
  external-editor-revived entry.

mpv
---
* dot_config/streamlink/config: `player=mpv` → `player=flatpak run
  io.mpv.Mpv`. The flatpak already pulls in our ~/.config/mpv via the
  read-only filesystem override (see
  run_onchange_after_deploy-flatpak-overrides.sh.tmpl), so behavior is
  unchanged.
* dot_local/bin/executable_linkhandler: same swap for inline video URLs.
* dot_local/bin/executable_mpv: deleted. The wrapper only existed to
  bwrap /usr/bin/mpv into _sandbox-net-parser; flatpak's own sandbox
  supersedes that.
* dot_local/bin/executable__sandbox-net-parser,
  dot_local/bin/executable_streamlink: comment refresh — mpv is no
  longer one of the tools this wraps, and the streamlink wrapper now
  forwards to the flatpak player rather than nested-bwrap caveats.
* meta/base.txt: drop `mpv` from the host package list and update the
  surrounding comment.

README.md: refresh the media row of the stack table to match.

On-host steps:

    chezmoi apply -v
    sudo pacman -Syu                          # picks up AssumeInstalled
    sudo pacman -Rns thunderbird mpv          # safe now
    flatpak install -y flathub org.mozilla.thunderbird io.mpv.Mpv
    swaymsg reload                            # pick up new tb scripts
</content>
</entry>
<entry>
<title>refactor(suspend): gate suspend on AC, drop bespoke zellij inhibit</title>
<updated>2026-05-29T10:18:15Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:15Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=ec3734c5ef9fcfe97c21cd19f198ec779ab5f052'/>
<id>urn:sha1:ec3734c5ef9fcfe97c21cd19f198ec779ab5f052</id>
<content type='text'>
New, simpler suspend policy:

  AC plugged in   -&gt; never auto-suspends (lid close ignored, idle no-op)
  On battery only -&gt; lid close suspends, swayidle suspends at 30 min idle

This replaces the SSH/zellij-aware inhibit machinery with a rule that
matches the user's mental model: if you don't want the machine to
sleep, plug it in. Long-running tasks (builds, downloads, SSH
sessions, headless services) just need AC.

Changes:

* etc/systemd/logind.conf.d/20-lid-ac.conf: set
  HandleLidSwitchExternalPower=ignore so logind itself handles the AC
  case at the source. No userspace daemon, no race, no rate-limit risk.
* dot_local/bin/on-battery-suspend: tiny POSIX wrapper that exits 0
  when any /sys/class/power_supply/{AC,ADP}*/online == 1, else execs
  `systemctl suspend`.
* dot_config/systemd/user/swayidle.service: add
  `timeout 1800 on-battery-suspend`. Idle suspend now exists, but only
  when on battery.
* Delete zellij-inhibit-suspend.{path,service} + watcher script and
  remove the entry from systemd-units/user.txt. The .path
  re-trigger storm bug is moot because the whole mechanism is gone.

Manual suspends (sway XF86Sleep keybind, sway power submode `s`,
`systemctl suspend` over SSH) still always work regardless of AC --
explicit user intent wins.

Also drop /migrate-podman-to-btrfs.sh from .gitignore; the one-off
migration script has been deleted now that the user has switched their
podman storage to the btrfs driver.

On-host steps to apply:

  chezmoi apply -v
  systemctl --user daemon-reload
  systemctl --user reset-failed zellij-inhibit-suspend.service zellij-inhibit-suspend.path || true
  systemctl --user stop zellij-inhibit-suspend.path zellij-inhibit-suspend.service || true
  systemctl --user disable zellij-inhibit-suspend.path || true
  systemctl --user restart swayidle.service
  # logind drop-in is reloaded automatically by the etc deploy script.

Verify:

  systemctl status systemd-logind | grep -i lid
  loginctl show-session $XDG_SESSION_ID | grep -i lid
  # Unplug AC -&gt; close lid -&gt; should suspend.
  # Plug AC   -&gt; close lid -&gt; nothing happens.
</content>
</entry>
<entry>
<title>feat(suspend): re-enable suspend on s2idle, drop diagnostic scaffolding</title>
<updated>2026-05-29T10:18:15Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:15Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=6e0c5c33438e5e898bd075c33a45b3abf9d1b26b'/>
<id>urn:sha1:6e0c5c33438e5e898bd075c33a45b3abf9d1b26b</id>
<content type='text'>
Confirmed root cause: this hardware's S3 (deep) firmware path triggers a
fatal wake-from-suspend hang only on linux-hardened. INIT_ON_FREE + slab
hardening + tighter locking turn a latent driver race that stock linux
gets away with into an unrecoverable panic so early the journal isn't
even flushed. mem_sleep_default=s2idle bypasses the BIOS S3 path
entirely (s0ix is a pure-kernel low-power state) and suspends/resumes
reliably under hardened.

This is a widespread Lenovo S3 firmware issue across post-2018
ThinkPads (see Ubuntu T560, X1C9/10/11 reports). Lenovo themselves
moved newer firmwares to s2idle-only. Not a linux-hardened bug per se;
just hardened being a strict enough kernel to make the bug fatal.

Keep:
* mem_sleep_default=s2idle in etc/kernel/cmdline-linux-hardened.tmpl
  (only the hardened UKI; stock linux keeps unchanged shared cmdline)

Revert (all the diagnostic / speculative scaffolding from the last
few commits):
* MODULES=(intel_lpss_pci) → MODULES=()  — Arch wiki touchpad fix was
  not the cause here
* nmi_watchdog=panic softlockup_panic=1 panic=10 — only needed to
  auto-reboot during diagnosis
* no_console_suspend — diagnostic-only
* etc/systemd/logind.conf.d/20-no-suspend.conf  — masking workaround
* sleep-target masking block in run_onchange_after_deploy-etc.sh.tmpl,
  replaced with a one-shot cleanup that removes any leftover
  /dev/null symlinks from systems that ran the previous version
* systemd-pstore.service from systemd-units/system.txt — added only to
  catch the diagnostic panic
* diagnose-suspend.sh helper (and its .gitignore/.chezmoiignore entries)
* sway suspend → lock-session keybind workaround
* power-menu.sh Suspend entry restoration
* KEYBINDS.md docs
</content>
</entry>
<entry>
<title>fix(suspend): switch hardened to s2idle, keep console alive, archive pstore</title>
<updated>2026-05-29T10:18:14Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:14Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=ad8e14860fa0ca978f5ef6e02860d24f5e39c361'/>
<id>urn:sha1:ad8e14860fa0ca978f5ef6e02860d24f5e39c361</id>
<content type='text'>
Previous attempt (early-loading intel_lpss_pci) did not fix the wake-from-suspend
panic on linux-hardened. The journal of the failed boot ends cleanly at the
last sync with no panic, oops, or even 'PM: suspend entry' message — the kernel
dies so fast nothing is flushed, even with panic=10 + watchdog knobs.

Three changes to make progress:

* mem_sleep_default=s2idle: switch S3 'deep' (broken firmware path on Coffee
  Lake ThinkPads) to s2idle / s0ix. Many Lenovo machines only suspend reliably
  via s2idle; the stock linux kernel may be masking the issue elsewhere.
* no_console_suspend: keep console alive across the suspend/resume cycle so
  the panic actually prints somewhere visible, instead of being eaten when
  the framebuffer goes dark.
* systemd-pstore.service: archive /sys/fs/pstore/* to /var/lib/systemd/pstore/
  on every boot, so the next panic (if EFI variables capture it) survives.

Drop 'quiet' from hardened cmdline so console messages are visible.
</content>
</entry>
<entry>
<title>fix(suspend): load intel_lpss_pci from initramfs (Arch wiki touchpad fix)</title>
<updated>2026-05-29T10:18:14Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:14Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=be5f8a2e6be3af4963399bb7f994f76d76b3a239'/>
<id>urn:sha1:be5f8a2e6be3af4963399bb7f994f76d76b3a239</id>
<content type='text'>
Symptoms (Intel CPU + linux-hardened + blinking caps lock + hard
hang on resume from S3) are a direct match for the Arch wiki entry:

  https://wiki.archlinux.org/title/Power_management/Suspend_and_hibernate#Touchpad_causes_a_kernel_panic_on_resume
  https://bbs.archlinux.org/viewtopic.php?id=231881

When intel_lpss_pci is loaded late (via udev after userspace is up),
the touchpad/I2C controller it parents can be torn down by suspend
before the module's resume callback is registered, leading to a
NULL-deref panic during resume. The kernel never makes it far enough
to flush logs — which matches our 'PM: suspend entry (deep)' being
the last journal line.

Fix: load intel_lpss_pci from the initramfs so it's available before
the suspend/resume code path runs.

Why this only bites linux-hardened: the hardening config enables
INIT_ON_FREE, slab freelist hardening, page poisoning, and stricter
pointer validation, which turn what's a silent UAF on stock linux
into an immediate panic on hardened. Stock 'just works' by accident.

Also drop the speculative init_on_free=0 from the hardened cmdline
now that we have a targeted hypothesis. Keep nmi_watchdog=panic +
softlockup_panic=1 + panic=10 as belt-and-braces: if this fix is
wrong, the next hang will auto-reboot with a usable panic log in
'journalctl -b -1 -k' instead of needing the power button again.
</content>
</entry>
<entry>
<title>feat(suspend): hardened-only init_on_free=0 + hang-detection cmdline</title>
<updated>2026-05-29T10:18:14Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:14Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=e2a7a2fdb9ba66e777ec1a8c0d3c9301cc21bdab'/>
<id>urn:sha1:e2a7a2fdb9ba66e777ec1a8c0d3c9301cc21bdab</id>
<content type='text'>
Split the hardened UKI cmdline off the shared etc/kernel/cmdline.tmpl
so we can carry workarounds without poking the stock linux build.

Daily-driving linux-hardened on this hardware has reliably hung on
resume from S3: black screen, blinking caps-lock + power LED, only
the power button helps. The kernel journal stops at 'PM: suspend
entry (deep)' with nothing after, so the freeze is below the level
where logs can flush — characteristic of a hard hang inside a device
driver's suspend/resume callback rather than a userspace bug.

linux-hardened defaults init_on_free=1, which zeroes pages on free.
On Intel + iwlwifi/i915/nvme stacks this routinely surfaces latent
UAFs as suspend hangs that are invisible on stock linux. Drop that
knob to 0 for the hardened cmdline as the working hypothesis.

Add nmi_watchdog=panic, softlockup_panic=1, panic=10 so if the next
attempt still wedges, a stuck CPU self-panics and auto-reboots
within ~10s, giving us a 'journalctl -b -1 -k' trace to look at
instead of having to force-power-off blindly.

Stock linux is untouched.
</content>
</entry>
<entry>
<title>feat(suspend): disable system suspend until hardened kernel resume issue is fixed</title>
<updated>2026-05-29T10:18:14Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:14Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=3be68c032c864fa98ed85e54ea5af19976c55ed7'/>
<id>urn:sha1:3be68c032c864fa98ed85e54ea5af19976c55ed7</id>
<content type='text'>
linux-hardened wedges on resume from S3 (NVMe/i915/iwlwifi driver UAF
exposed by INIT_ON_FREE + slab hardening). Until root-caused, take
suspend off the table while keeping lock + DPMS intact.

- etc/systemd/logind.conf.d/20-no-suspend.conf: lid close, suspend
  key, hibernate key all map to 'lock'; IdleAction=ignore (swayidle
  drives DPMS+swaylock independently).
- run_onchange_after_deploy-etc.sh.tmpl: mask sleep.target,
  suspend.target, hibernate.target, hybrid-sleep.target,
  suspend-then-hibernate.target via /etc/systemd/system -&gt; /dev/null
  symlinks. Catches 'systemctl suspend' from any source.
- dot_config/sway/config: XF86Sleep and system-mode 's' now run
  loginctl lock-session instead of systemctl suspend.
- dot_config/sway/executable_power-menu.sh: drop Suspend entry.
- KEYBINDS.md: reflect new behaviour.

To re-enable later: remove the logind drop-in + symlink loop, then
sudo systemctl daemon-reload.
</content>
</entry>
</feed>
