| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
New, simpler suspend policy:
AC plugged in -> never auto-suspends (lid close ignored, idle no-op)
On battery only -> 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 -> close lid -> should suspend.
# Plug AC -> close lid -> nothing happens.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
fixed
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 -> /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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
snx-rs (Check Point VPN) doesn't notice that its tunnel died during
suspend: the IKE keepalive is interrupted and the SAML cookie may
expire, but the daemon happily sits on dead sockets after resume.
`snxctl status` keeps reporting "Connected" while no traffic
actually flows, so the user has to manually disconnect+reconnect.
Install an /etc/systemd/system-sleep/ hook that stops the user-scope
snx-rs.service before suspend and starts it on resume. The tunnel is
left disconnected after resume; the waybar toggle (or any
`snxctl connect`) re-establishes it, going through SAML only if the
cached cookie has actually expired.
The hook enumerates logged-in users via loginctl and skips any that
don't have snx-rs.service enabled, so it's a no-op on machines that
don't use the VPN.
Also teach run_onchange_after_deploy-etc.sh.tmpl to install files
under etc/systemd/system-sleep/ with mode 0755 (systemd ignores
sleep hooks that aren't executable).
|
| |
|
|
|
|
|
|
|
|
| |
Name= negation list was failing in practice — veth/waydroid interfaces
were still being enslaved into bond0, taking down host networking.
Switch to positive matching: Path=pci-*|platform-* AND Name=en* AND
Type=ether. Virtual interfaces (veth, virbr, waydroid0, docker0, ...)
have no udev ID_PATH and never start with 'en', so they're cleanly
excluded by the AND of all three keys.
|
| |
|
|
|
|
|
|
|
| |
systemd-networkd's Type=ether matcher was enslaving waydroid0 into
bond0 the moment 'waydroid session start' ran, taking down the host's
default route. Mirror the libvirt/docker negation pattern.
Also mirror the existing virbr0 forward accepts for waydroid0 so the
Android container can actually reach the internet through MASQUERADE.
|
| |
|
|
|
|
|
|
|
|
| |
Type=ether matches ALL L2 ethernet interfaces, including libvirt-created
vnet* tap devices. Without Name= negations, when a VM starts its tap is
pulled into bond0 instead of staying with virbr0, killing DHCP/NAT for
the guest (Windows ends up with a 169.254.x APIPA address).
Add Name= negations to skip libvirt taps/bridges, generic taps, and
common container engine virtual interfaces.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Upstream lostfiles has no extension mechanism; the weekly report ends
up dominated by files this repo intentionally deploys plus host-private
files we deliberately don't track plus regenerated GTK caches.
Add etc/lostfiles.ignore.tmpl which renders /etc/lostfiles.ignore from
two sources:
1. Every file under etc/ in the repo (auto-enumerated at chezmoi-apply
time, same find-sort pattern the etc deploy script uses). This
keeps the ignore list in sync with what we actually deploy with
zero manual maintenance.
2. A static block for: the sudo-i symlink, host-private
systemd-networkd units (99-hodor*, 99-mandibles*) which contain
WireGuard secrets, the getty@tty1 autologin override which
contains the username, and known pacman-hook-generated caches
under /usr/lib/{gdk-pixbuf-2.0,gtk-4.0}/.
Wrap /usr/bin/lostfiles in lostfiles.service via grep -vFxf, with a
fallback when /etc/lostfiles.ignore doesn't yet exist (first deploy).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Wiring (mirrors arch-audit, with weekly cadence and Nice=19/idle I/O):
lostfiles.timer (weekly, Persistent=true, RandomizedDelaySec=1h)
→ lostfiles.service
→ /run/lostfiles.txt (default mode — strict produces too many
false positives for a passive reminder)
→ custom/lostfiles waybar module (interval 600s)
→ mako 'normal' once/7d while count > 0
→ on-click: `ghostty -e nvim -R /run/lostfiles.txt`
Default mode (no `strict` argument) is intentional: it already filters
the package's curated false-positive list at /etc/lostfiles.conf, which
is what we want for a low-noise weekly nudge. Switching to `strict` is
a one-line change in lostfiles.service if signal-vs-noise tilts later.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Wiring:
arch-audit.timer (daily, RandomizedDelaySec=1h, Persistent=true)
→ arch-audit.service (After=network-online.target)
→ /run/arch-audit.txt ('--upgradable' output, atomic via .tmp+mv)
→ custom/arch-audit waybar module (interval 300s)
→ mako 'critical' once/24h while count > 0
→ on-click: `ghostty -e nvim -R /run/arch-audit.txt`
The bar entry stays hidden when there are no fixable CVEs, fades in as
red 'CVE N' the moment arch-audit finds at least one, and the throttled
mako means you'll see exactly one notification per day instead of one
per waybar poll. No -Sy refresh and no auto-update — this only reports
the gap between what's installed and what's already in the repos.
Why /run and not the user's runtime dir: the producer is a system unit
(needs the system's pacman db on the network-online path), the consumer
is a user-scope waybar that just reads it; /run is the canonical 'fast,
volatile, world-readable' system-tmpfs and survives the reboot cycle in
exactly the way we want — fresh empty file on every boot, repopulated
on the next timer fire.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Template service+timer that runs `btrfs balance start -dusage=50
-musage=50 %f` once a month on the instance's mount path. Mirrors the
shape of the stock btrfs-scrub@.{service,timer} so the operational
model is identical: enable btrfs-balance@-.timer for /, btrfs-balance@\
x2dhome.timer for /home, etc.
Why a partial balance and not a full one: full `btrfs balance start`
rewrites every block group, which on a multi-TB volume takes hours and
can chew through enormous amounts of CSUM/free-space-tree work.
`-dusage=50 -musage=50` only consolidates block groups that are less
than half full, which is exactly the operation that reclaims space
'lost' to fragmentation after lots of small writes — the only practical
reason a healthy single-disk btrfs needs balancing at all.
`Nice=19 IOSchedulingClass=idle` keeps it out of the way of foreground
work; `KillSignal=SIGINT` (same as btrfs-scrub) lets a graceful Ctrl-C
checkpoint the operation cleanly. Persistent=true catches the run on
next boot if the machine was off when the timer fired.
Enabled in systemd-units/system.txt as btrfs-balance@-.timer (root
volume only — /home isn't a separate subvolume on this machine).
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The Shokz dongle emits KEY_POWER press without a matching release on
USB disconnect; logind classified that as a long-press after 5s and
fired HandlePowerKeyLongPress=poweroff (confirmed in journal: 'Power
key pressed long. Powering off...').
There is no policy that distinguishes 'real 5s hold of power button'
from 'misbehaving device that never sends release'. Ignore both.
Clean shutdowns now require systemctl poweroff or GUI menus; a very
long hold of the physical power button still force-offs via firmware.
|
| |
|
|
|
|
| |
The drop-in is generic policy, not tied to one device. Reword the
comment to reflect that any USB device emitting spurious KEY_POWER
(headsets, KVM switches, cheap keyboards) is covered.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Shokz OpenMeet dongle (3511:2EF2) emits KEY_POWER on USB
enumeration and on headset power transitions, which logind handles
with HandlePowerKey=poweroff and immediately shuts the host down.
The previous attempt — an hwdb scancode remap of c0030 to reserved —
sets the udev property correctly but the kernel does not honor
EVIOCSKEYCODE for this device's HID consumer-page mapping (verified:
KEY_POWER 116 still appears in the evdev keymap after udevadm trigger
and libinput still reports it). Drop the hwdb file and the
systemd-hwdb hooks from the etc deploy script.
Replace with a logind drop-in that sets HandlePowerKey=ignore and
HandlePowerKeyLongPress=poweroff. Single-tap power events from any
source become no-ops; a 5s hold still shuts the machine down, so the
real hardware-power-button safety net is preserved. Add a HUP to
systemd-logind in the deploy script so the change takes effect
without restarting the daemon.
|
| |
|
|
|
| |
setterm only affects the Linux console (TERM=linux); sway's KMS/DRM
session is unaffected. Wakes on any keypress.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
- New dot_config/systemd/user/swayidle.service, pulled in by
sway-session.target alongside mako/display-watcher/poweralertd. Same
lifetime as the rest of the session: starts after graphical-session,
restarts on failure, stops on logout.
- Drop the swayidle exec from sway config (was unmanaged background
process with no restart, no logging hookup).
- Revert etc/systemd/logind.conf overrides: swayidle handles idle-lock
directly via Wayland ext-idle-notifier, so the logind IdleAction
belt-and-suspenders is redundant. Run just etc-reset
/etc/systemd/logind.conf on the host to restore pristine.
|
| |
|
|
|
|
|
|
|
|
|
| |
- logind: IdleAction=lock, IdleActionSec=5min. systemd emits a lock
signal at 5min idle (session becomes locked from logind PoV; swayidle
listens and invokes swaylock).
- swayidle: lock at 5min, blank display at 6min, lock before sleep.
Closes the gap where lid-close or manual suspend would wake to an
unlocked session.
- swaylock: add -i (--ignore-empty-password) to ignore accidental Enter.
- meta/wayland: add swayidle.
|
| |
|
|
|
|
| |
User scopes (e.g. ghostty surface containing zellij) inherit timeouts
from the user manager, not /etc/systemd/system.conf.d. Without this,
zellij sessions stall reboot for 90s before SIGKILL.
|
| |
|
|
|
| |
Cap at 8 GiB, zstd compression. Tune VM for RAM-backed swap:
high swappiness, no read-ahead clustering.
|
| |
|
|
|
|
|
|
|
| |
All 44 lines are comments/section headers — zero active settings.
Tracking was useless: no real state to preserve, and 'just etc'
would surface any future drift anyway.
The live /etc/systemd/resolved.conf on the host is unaffected;
chezmoi's deploy-etc script only installs files, never removes.
|
| |
|
|
|
|
|
| |
Type=ether and Type=wlan match every interface of that class.
Add comments pointing out that future USB/Thunderbolt dongles
would get auto-enslaved into bond0, and how to narrow the match
if that becomes undesirable.
|
| |
|
|
|
|
|
| |
Adopted via 'just etc-add' after 'just etc-drift' surfaced them:
locale.conf, locale.gen, mkinitcpio.conf, mkinitcpio.d/linux.preset,
pacman.conf, resolved.conf, systemd/network/30-bond*, and the shokz
udev blacklist rule.
|
| |
|