Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion board/mister/de10nano/rootfs-overlay/etc/profile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ done
unset i

export LC_ALL=en_US.UTF-8
resize >/dev/null
# Stock runs a bare `resize` here. That is the BusyBox applet: it writes a
# cursor-position query to STDERR and reads the terminal's reply from STDIN
# under a 3 s alarm. On the serial console that is how the shell ever learns
# the window size. On an SSH login it is at best redundant (sshd propagates the
# client's window size through the pty) and at worst harmful: a client that
# opens the login shell WITHOUT a pty (WinSCP's SCP mode and its terminal
# window) gets the escape bytes on stderr and loses its first command to
# resize's scanf, which WinSCP reports as "Error skipping startup message".
# Stock has the identical defect (verified on release_20250402). Deliberate
# deviation: only run resize for an interactive, non-SSH shell. SSH_CONNECTION
# is set by sshd for every session, pty or not (SSH_TTY is not). Issue #142.
[ "$PS1" ] && [ -z "$SSH_CONNECTION" ] && resize >/dev/null
mount -o remount,rw /

2 changes: 1 addition & 1 deletion docs/init-parity.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ regardless, so the worst case is slow, never weak.
| `/etc/network/interfaces` | **adapted (v9)** (1 additive deviation) | `lo` + `wlan0`/`wlan1` with the `wpa_supplicant -D nl80211,wext` pre-up hooks, all of stock's directives reproduced unchanged. No `eth0` stanza β€” matches stock exactly; wired ethernet is handled by dhcpcd's own default (manage-everything-not-explicitly-excluded) behavior, not ifupdown. **This row said "identical / byte-for-byte" until now and was stale:** P2.3 authored it byte-identical, but `4cf2fc7` (v9) added a 9-line header comment plus one `pre-up i=0; while [ $i -lt 20 ] && ! iw dev $IFACE info >/dev/null 2>&1; do sleep 1; i=$((i+1)); done` line per `wlan` stanza, because USB WiFi drivers that register `nl80211` asynchronously (mainline `rtw88`/`rtw89`) otherwise lose the race and `wpa_supplicant` fails with "interface not found" on a cold boot. `diff` against `work/imgroot/etc/network/interfaces` now exits 1 with exactly those 11 added lines and zero removals (re-verified). See `docs/wifi-parity.md` Β§1 and Β§9 β€” Β§9's hotplug rule depends on that loop existing. |
| `/etc/dhcpcd.conf` | **identical** | Byte-for-byte match. The package's own default differs meaningfully (`#hostname`/`#clientid` instead of stock's enabled `hostname`/`clientid`, `duid` instead of stock's `#duid`, and is missing the `option rapid_commit` block) β€” all reverted to stock via the overlay. |
| `/etc/inittab` | **adapted** (3 documented deviations) | Full stock shape reproduced (`::sysinit:/media/fat/MiSTer &`, `/etc/resync &`, `rcS`, shutdown sequence) with: **(1)** the remount-rw sysinit line kept **commented out**, exactly as stock has it β€” Buildroot's own skeleton default inittab ships this line **uncommented**, which would remount `/` rw at every sysinit and defeat the whole read-only-root design (ADR 0011); confirmed this project's own finalize hook tries to uncomment it too (see below) and is overridden by the overlay running last. **(2)** the serial console runs `ttyS0::respawn:/sbin/agetty --nohostname -L ttyS0 115200 vt100` β€” util-linux `agetty`, matching stock (whose inittab also uses `agetty --nohostname`), now that `BR2_PACKAGE_UTIL_LINUX_AGETTY` is enabled (see `docs/util-linux-parity.md`). It still targets `ttyS0` explicitly rather than stock's `console` alias, because this board's actual cmdline is `console=ttyS0,115200` (`docs/boot-chain.md`). agetty treats a numeric positional argument as the baud rate, so `ttyS0 115200` and `115200 ttyS0` are equivalent; the port-first order is kept for continuity with the previous BusyBox `getty` line. (Earlier revisions used BusyBox `getty` because `BR2_PACKAGE_UTIL_LINUX_BINARIES` was not selected β€” that constraint no longer holds; the overlapping BusyBox `getty` applet is now disabled so `agetty` is the console.) **(3)** `gpm` is invoked at `/usr/sbin/gpm`, not stock's `/sbin/gpm` β€” originally **a real bug caught during acceptance verification**: gpm is a real package (not a BusyBox applet, which lands under `/sbin` regardless of usr-merge), and when this row was first written (P2.3) the rootfs was **not** usr-merged β€” `/sbin` was a real directory, not `-> /usr/sbin` the way stock's `work/imgroot/sbin` is β€” so `/sbin/gpm` genuinely did not exist in the image. An inittab `sysinit` line is an **absolute path**, so unlike `/etc/profile`'s `PATH` it gets no shell search at all; it would have silently failed to spawn on every single boot. Caught by exhaustively grep'ing every absolute path referenced anywhere in the overlay against the actually-built image (see the task report) β€” first build had this wrong; fixed and rebuilt before acceptance. **Since P2.9 v2** (`7be9ee5`) set `BR2_ROOTFS_MERGED_USR=y`, that premise no longer holds: this build is now usr-merged like stock (verified: `output/target/sbin -> usr/sbin`), so `/sbin/gpm` *would* resolve today. **The deviation is kept anyway, deliberately.** Buildroot builds gpm with `--prefix=/usr`, so the binary's real path is `/usr/sbin/gpm` in *either* layout (gpm's own file list: `gpm,./usr/sbin/gpm`) β€” stock's binary is at that same physical path, and stock's inittab only reaches it through the `/sbin -> usr/sbin` compat symlink that exists solely because stock is usr-merged. So our path is correct in both layouts and stock's is correct in only one; ours survives an unmerge, stock's would break on one. Given P2.3 already got bitten by exactly that (the unmerged build had no `/sbin/gpm` at all), pointing at the real path rather than a merge-dependent alias is the more durable choice, even though a future unmerge is unlikely. This is an **accepted permanent deviation from stock**, not a cleanup waiting to happen. **Also dropped β€” later RESTORED, guarded (T3, 2026-07-27):** `loadkeys /etc/kbd.map` and `setfont` were dropped by P2.3 because this BusyBox build has no `loadkeys` applet at all and `CONFIG_SETFONT` is explicitly not set (still true β€” re-verified in `output/build/busybox-1.38.0/.config`; busybox's `loadkmap` applet is not a substitute, it reads binary bkeymap, not stock's text keymap); keeping either line verbatim would just fail every boot. T3 vendored stock's `etc/kbd.map` (it blanks the F12/Mute/VolΒ± keycodes Main_MiSTer consumes via evdev) and restored both lines wrapped in `[ -x /usr/bin/... ]` guards: with the parallel T5 task's `BR2_PACKAGE_KBD` (the same package stock's own loadkeys/setfont came from) the lines do stock's exact job, without it they are silent no-ops instead of boot errors. See the inittab's own note 3 and `docs/stock-reconciliation.md` Β§3c. `gpm -m /dev/input/mice -t imps2` itself **is** kept (just at the corrected path) β€” `BR2_PACKAGE_GPM=y` was deliberately selected in P2.1 for this, and the binary is present. |
| `/etc/profile` | **adapted** (1 documented deviation) | Full stock content reproduced (PATH, `PS1='$(pwd)# '`, `EDITOR=/bin/vi`, `/etc/profile.d/*.sh` sourcing, `LC_ALL=en_US.UTF-8`, and critically the login-time `mount -o remount,rw /` β€” this is how `/` ever becomes writable at all, matching stock and ADR 0011's own description of the mechanism). **Deviation:** `PATH` gains an explicit `/bin:/sbin:` prefix stock's literal string doesn't have. Stock's rootfs is usr-merged (`work/imgroot`: `/bin -> usr/bin`, `/sbin -> usr/sbin`), so its `PATH="/usr/bin:/usr/sbin"` already covered `/bin`/`/sbin` for free. When this deviation was introduced (P2.3) *this* build was a plain (non-merged) skeleton layout, so omitting `/bin:/sbin` from `PATH` would have silently dropped most BusyBox applets from every interactive shell; changing `BR2_ROOTFS_MERGED_USR` was then out of P2.3's scope ("do NOT disturb ... the package set"), making the overlay `PATH` the correct-altitude fix. **Since P2.9 v2** (`7be9ee5`) set `BR2_ROOTFS_MERGED_USR=y` β€” the change that fixed the `/lib/security/pam_unix.so` SSH lockout β€” this build is usr-merged too, so the `/bin:/sbin:` prefix is now redundant. It is kept because it is harmless (the paths resolve to the same directories) and matches Buildroot's own skeleton default profile. The file's own header comment records the same history. |
| `/etc/profile` | **adapted** (2 documented deviations) | Full stock content reproduced (PATH, `PS1='$(pwd)# '`, `EDITOR=/bin/vi`, `/etc/profile.d/*.sh` sourcing, `LC_ALL=en_US.UTF-8`, and critically the login-time `mount -o remount,rw /` β€” this is how `/` ever becomes writable at all, matching stock and ADR 0011's own description of the mechanism). **Deviation:** `PATH` gains an explicit `/bin:/sbin:` prefix stock's literal string doesn't have. Stock's rootfs is usr-merged (`work/imgroot`: `/bin -> usr/bin`, `/sbin -> usr/sbin`), so its `PATH="/usr/bin:/usr/sbin"` already covered `/bin`/`/sbin` for free. When this deviation was introduced (P2.3) *this* build was a plain (non-merged) skeleton layout, so omitting `/bin:/sbin` from `PATH` would have silently dropped most BusyBox applets from every interactive shell; changing `BR2_ROOTFS_MERGED_USR` was then out of P2.3's scope ("do NOT disturb ... the package set"), making the overlay `PATH` the correct-altitude fix. **Since P2.9 v2** (`7be9ee5`) set `BR2_ROOTFS_MERGED_USR=y` β€” the change that fixed the `/lib/security/pam_unix.so` SSH lockout β€” this build is usr-merged too, so the `/bin:/sbin:` prefix is now redundant. It is kept because it is harmless (the paths resolve to the same directories) and matches Buildroot's own skeleton default profile. The file's own header comment records the same history. **Deviation 2 (2026-09-03, issue #142):** stock's trailing bare `resize >/dev/null` is guarded as `[ "$PS1" ] && [ -z "$SSH_CONNECTION" ] && resize >/dev/null`. `resize` is the BusyBox applet: it writes a cursor-position query to stderr and reads the reply from stdin under a 3 s alarm. On the serial console that is the only way the shell learns the window size, so it stays. Over SSH it is redundant (sshd propagates the client's window size through the pty) and, for a client that opens the login shell **without** a pty, actively broken: WinSCP's SCP mode and its terminal window receive the escape bytes on stderr and lose their first command to `resize`'s `scanf`, which WinSCP reports as "Error skipping startup message. Your shell is probably incompatible with the application" (forum report: https://misterfpga.org/viewtopic.php?p=113698#p113698). SFTP, PuTTY and command-line scp were never affected. Stock has the identical defect β€” verified on `release_20250402`'s `linux.img` (same profile line, `resize -> busybox` 1.33.1) by running stock's own busybox under `qemu-arm` on a pty: identical bytes, next input line swallowed. `SSH_CONNECTION` rather than `SSH_TTY` because sshd sets the former for every session and the latter only when a pty is allocated. Verified on a board: no-pty login shell, pty login shell and `bash -l` are all clean; a simulated console login (SSH vars cleared) still runs `resize`. |
| `/usr/lib/dhcpcd/dhcpcd-hooks/90-timezone` | **added (divergence, [ADR 0025](decisions/0025-first-boot-timezone-autodetect.md))** | Stock has no equivalent, and that is the gap it closes: `/etc/localtime` points at `/media/fat/linux/timezone`, which **does not exist on a fresh card**, so glibc falls back to UTC silently and permanently. The first time dhcpcd brings an interface up with an address, this asks `ip-api.com` for the zone of the box's public IP and copies `/usr/share/zoneinfo/posix/<Zone>` to that path β€” the *same* provider, destination and file format as the community `Scripts_MiSTer/timezone.sh` "Automatic" mode, so the two are interchangeable. No new package (`curl` and tzdata were already in the image). **Note this adds no init script**: an earlier revision had an `S48timezone` as well, but on a DHCP box the lease has usually not landed by S48, so it was near-redundant with this hook β€” and it carried a `/proc/net/route` check whose IPv6 arm silently matched the kernel's own `ip6_null_entry`. A static-IP box configured only in `/etc/network/interfaces` never runs dhcpcd and so never autodetects; accepted deliberately, since setting a static address is already a by-hand act. Properties worth stating because they are the design: the guess is spent **once, and only when it was actually made** (gated on the timezone file *and* on a `timezone.autodetect` stamp written only when a provider answered *with a zone name*, so neither being offline nor a captive portal's HTTP 200 burns it), it **never overwrites** a timezone anyone has already set (re-checked immediately before the write, not only at the gate), and it **delays nothing** β€” the body is a backgrounded subshell, which also keeps it from leaking a single variable or function into dhcpcd's shell. Sourced, not executed (`dhcpcd-run-hooks`: `. "$hook"`), hence no shebang, no exec bit, and no `exit` β€” an `exit` here would end dhcpcd's whole hook run and take `20-resolv.conf`/`30-hostname` with it. Zone names arrive off the network, so they are validated against the shipped zoneinfo before being used as a path; `scripts/test-timezone.sh` asserts each rejection, and mutation-checks the two that could otherwise pass vacuously. |
| `/usr/lib/dhcpcd/dhcpcd-hooks/` (the set) | **pinned (build-host independence)** | dhcpcd's `configure` chooses which hooks to install by probing the **build host** for `ntpd`/`chronyd`/`systemd-timesyncd`/`ypbind`, and Buildroot's `dhcpcd.mk` passes no `--with-hooks`, so the image inherited whatever daemons the build machine happened to have: a GitHub runner produced `50-ntp.conf`, a developer box with timesyncd produced `50-timesyncd.conf` β€” with a green build both times (found 2026-09-02 by diffing a CI image against a local one). `external.mk` now appends `--with-hooks=ntp.conf --with-eghooks=yp.conf` to `DHCPCD_CONFIG_OPTS`, which reproduces the canonical CI image exactly (`01-test`, `20-resolv.conf`, `30-hostname`, `50-ntp.conf`, plus our `90-timezone`; `50-yp.conf` stays an example under `/usr/share/dhcpcd/hooks`), and `scripts/check-linux-img.sh` asserts that exact set. `50-ntp.conf` is the right hook: we ship classic `ntpd` (stock parity) and it writes DHCP-offered servers into `/etc/ntp.conf`. Upstream-worthy: Buildroot's `dhcpcd.mk` should pass `--with-hooks` itself. |
| `/etc/resync` | **identical** | Byte-for-byte match (53 bytes: `( while [ 1 ]; do sync; sleep 5; done ) &`). Executable bit set. |
Expand Down
Loading