Commit Graph
3 Commits
Author SHA1 Message Date
pastilhasandClaude Opus 5 716a6e2750 port the swap section, and size it against the disk
Four things the original got wrong, all of which only show up on a machine that
is not this one:

  It detected swap with `swapon --show | grep -q '/'` — a test for a swap FILE.
  A machine using zram or a swap partition reports no swap at all, and the step
  would add a swapfile beside working swap. Reads SwapTotal from /proc/meminfo
  now, which covers every kind.

  It never looked at free disk. On a VPS with 4G free and 16G of RAM it would
  fallocate 8G, fail, and take the run down under `set -e`. The recommendation is
  now capped by what is actually there, keeping 5G back, and refuses rather than
  shrinking to something useless.

  fallocate was assumed to work. It produces a file that btrfs and zfs will not
  swap on, so dd is the fallback — slow, but it always works.

  swappiness was written by sed'ing /etc/sysctl.conf in place, tangling it with
  whatever else lives there. It is a drop-in at /etc/sysctl.d now, so what this
  script set is visible as its own file.

Role-dependent, which is the first use of MACHINE_ROLE: swappiness 10 on a
server, where swapping is the emergency valve and a page fault on a request path
is latency somebody is waiting for; the kernel default of 60 on dev, where
swapping out an application nobody has touched in an hour is exactly what you
want.

WSL is left alone entirely — WSL2 runs its own managed swap inside the VM, and a
swapfile written here is wasted disk the kernel will not use.

Sizes are reported rounded rather than floored. A 4 GiB swapfile is 4194300 kB,
which floors to 3 and reads as though a gigabyte went missing. Free disk stays
floored, deliberately: it decides how much to allocate, and rounding up invents
space.

Verified on this host — 4G RAM, 4G existing swap correctly detected and left
alone — and with the disk check stubbed at 6G free (caps to 1G) and 3G free
(refuses).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 17:48:45 +00:00
pastilhasandClaude Opus 5 6480788979 port the timezone section
The original took whatever was typed and handed it straight to timedatectl. An
unknown zone — a typo, a guess at the spelling — fails there, and under `set -e`
that takes the whole run down four steps in. Names are now checked against
/usr/share/zoneinfo before use, and a bad one just re-asks.

It also never showed what the machine was already set to, and defaulted to option
1 (UTC) on Enter, so pressing return on a correctly-configured box silently moved
it. Now the current zone is printed, Enter keeps it, and a zone equal to the
current one reports nothing to do rather than setting it again.

timezone_current reads three sources — timedatectl, /etc/timezone, then the
/etc/localtime symlink — because they differ in availability rather than in
answer: timedatectl needs systemd, /etc/timezone is Debian's, and the symlink is
the one that is always there. timezone_set writes through timedatectl where
there is a systemd to talk to and the files directly otherwise, which is what it
would have written anyway; that is also the WSL path, where timedatectl exists
but does nothing.

Europe/Berlin added to the shortlist; TIMEZONE in the environment answers the
prompt ahead of time and is validated the same way, failing early with the bad
value named.

Verified detection (UTC here), validation of four names, and the env-var
rejection path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 17:43:20 +00:00
pastilhasandClaude Opus 5 163f8d5899 port the locale section
Was three unconditional lines that ran on every pass and reported success either
way. Now it checks, says what it found, and asks.

The original tracked one fact where there are two:

  what a new login shell is told to use   LANG in /etc/default/locale
  whether that locale actually exists     whether it has been generated

Setting the first without the second is what produces "setlocale: LC_ALL: cannot
change locale" on every ssh login and every perl invocation. They fail
differently, so the step names whichever one is actually missing rather than
reporting a flat "locale not set".

Also fixes two things the original would have hit on a minimal image:

  locale-gen comes from the `locales` package, which cloud base images do not
  ship and which is not in core utils. It is installed on demand rather than
  assumed, instead of failing with "locale-gen: command not found".

  The locale is uncommented in /etc/locale.gen rather than only passed to
  locale-gen as an argument. A locale generated by argument alone disappears the
  next time anything regenerates from that file.

`locale -a` prints en_US.utf8 where the configuration spells it en_US.UTF-8, so
both sides are folded before comparing — a literal match reports a working locale
as missing.

LOCALE in the environment overrides the default. pacman, dnf and brew branches
are written but unreachable while the pre-flight gate is apt-only; macOS has no
system locale to set and says so.

Verified both paths on this host: en_US.UTF-8 reports already set and generated,
pt_PT.UTF-8 correctly reports both facts missing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 17:41:49 +00:00