Commit Graph
729684 Commits
Author SHA1 Message Date
Samuel Dionne-Riel 40fb9e7c5a switch-to-configuration-ng: Fix exit status on bootloader install error
The problem
-----------

When rebuilding a system, if `switch-to-configuration-ng` fails to install
bootloader files, it will (most likely) `exit(0)`.

```
/etc/nixos $ sudo nixos-rebuild --fast boot && reboot
[sudo] password for samuel:
building the system configuration...
updating GRUB 2 menu...
cannot copy /nix/store/.../initrd to /boot/kernels/...-initrd.tmp: No space left on device
Failed to install bootloader

Broadcast message from samuel@... on pts/1 (Tue 2024-12-31 16:48:26 EST):

The system will reboot now!
```

This is a quite awkward breaking change with the expected behaviour.

* * *

The investigation
-----------------

Compare:

 - https://github.com/NixOS/nixpkgs/blob/85b5f3e959327a3fa46f843848ebb8799069bb95/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs#L171-L179
 - https://github.com/NixOS/nixpkgs/blob/85b5f3e959327a3fa46f843848ebb8799069bb95/nixos/modules/system/activation/switch-to-configuration.pl#L115-L117

Let's see what `die()` is all about:

 - https://github.com/NixOS/nixpkgs/blob/85b5f3e959327a3fa46f843848ebb8799069bb95/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs#L121-L125

***sus.***

There are multiple issues converging here.

**Incorrect port**

The original implementation did not use `die`, but `exit 1`.

So porting from `perl` following the script's idiosyncrasies was not
done appropriately.

**Incorrect `die` fac-simile**

The `die` method is incomplete with regard to the semantics of perl.

 - https://perldoc.perl.org/5.40.0/functions/die

Of importance to us:

> If [die is called],  the exit code is determined from the values of
> `$!` and `$?` with this pseudocode:
>
> ```
> exit $! if $!;              # errno
> exit $? >> 8 if $? >> 8;    # child exit status
> exit 255;                   # last resort
> ```

The `die()` method in `switch-to-configuration-ng` *only* checks
`errno`, using its value directly to `exit()`.

It does not handle some form of implicit child process exit status.

And, due to incorrect assumptions, it will not fall back to anything.

**Incorrect implementation**

(Note that from this point on, I'm not a Rust expert, so bear with me if
some nuances are lost or incorrectly represented.)

The `die()` function implementation, as a port, might not even work
correctly.

Already, the `spawn` method does not mention it would be setting
`errno`, so any `die()` following a `status.success()` is *sus* and
should be investigated. Since it's not attempting to do anything "smart"
with child processes.

 - https://doc.rust-lang.org/1.83.0/std/process/struct.Command.html#method.spawn

And I'd argue that using *errno* in this manner in Rust is probably a
mistake, and should not be done.

> This should be called immediately after a call to a platform function,
> otherwise the state of the error value is indeterminate.

 - https://doc.rust-lang.org/1.83.0/std/io/struct.Error.html#method.last_os_error

Considering *platform function* is largely left undefined, I would
(probably wrongly) intuit that it should be considered undefined
behaviour to rely on it.

Note that `raw_os_error` might have a surprising interface.

> If this `Error` was constructed via `last_os_error` [...],
> then this function will return `Some`, otherwise it will return `None`.

 - https://doc.rust-lang.org/1.83.0/std/io/struct.Error.html#method.raw_os_error

Since it's used as `std::io::Error::last_os_error().raw_os_error()`,
AFAIUI it will always return `Some`.

Since this is exposing `errno`, the libc concept, it will behave the
same, and may be set to `0` by default, just like here:

```
$ printf '#include <stdlib.h>\n#include <errno.h>\nint main() { exit(errno); }' \
    | cc -x c - && ./a.out; echo $?
0
```

Which means that, since no *platform function*[sic] changed its value,
it will be zero, the `die()` function will be equivalent to `exit(errno)`,
and the program will have failed “successfully” wrongly.

* * *

The fix
-------

I've fixed the `do_pre_switch_check` and `do_install_bootloader` methods,
both of which share the same defects (the original script uses `exit 1`
for both).

They were the only `status.success()` checks using `die()`.

* * *

Reproducing the issue
---------------------

Remember how I said:

> Considering *platform function* is largely left undefined, I would
> (probably wrongly) intuit that it should be considered undefined
> behaviour to rely on it.

Here's why it's not some vague FUD.

First, make sure a `nixos-rebuild boot` would need to write new files to
the boot partition. Removing an older (but still alive) generation's
initrd can do that.

Fill the `/boot` partition to force an error.

```
 $ sudo dd if=/dev/zero of=/boot/BOGUS.FILLINGS
```

Then, and here's the fun part, observe:

```
~ $ sudo rm -r /run/nixos

~ $ sudo nixos-rebuild --fast boot ; echo $?
building the system configuration...
updating GRUB 2 menu...
cannot copy /nix/store/x91w4p91l7iclkdp38chvdxcw6nr5113-mobile-nixos-initrd-generic/initrd to /boot/kernels/x91w4p91l7iclkdp38chvdxcw6nr5113-mobile-nixos-initrd-generic-initrd.tmp: No space left on device
Failed to install bootloader
0

~ $ sudo nixos-rebuild --fast boot ; echo $?
building the system configuration...
updating GRUB 2 menu...
cannot copy /nix/store/x91w4p91l7iclkdp38chvdxcw6nr5113-mobile-nixos-initrd-generic/initrd to /boot/kernels/x91w4p91l7iclkdp38chvdxcw6nr5113-mobile-nixos-initrd-generic-initrd.tmp: No space left on device
Failed to install bootloader
warning: error(s) occurred while switching to the new configuration
1
```

So... What's the deal with /run/nixos? It's where the lock file will
reside. (And other transient files.)

 - https://github.com/NixOS/nixpkgs/blob/85b5f3e959327a3fa46f843848ebb8799069bb95/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs#L1018-L1027

But why does that matter here?

```
~ $ errno 17
EEXIST 17 File exists
```

This error is produced by some *platform functions*[sic] that create
either the directory, or the lockfile. The file already exists.

So the script would end-up failing this way *only for the first
invocation*. Which is why it's possible any of you all reviewing this
~~novel~~ PR haven't faced that issue.

* * *

Future work
-----------

I believe `die()` *probably* should be switched to check the value, and
`exit 255` if it's 0.

Though I also believe `die()` shouldn't try to port perl semantics into
Rust. I don't think it's working out.

Additionally, a NixOS test should be authored to ensure that errors in
these phases actually are handled appropriately.

Signed-off-by: Samuel Dionne-Riel <samuel@dionne-riel.com>
2025-01-01 00:32:55 -05:00
misuzuandGitHub 88195a94f3 nas: fix build with gcc14 (#368331) 2024-12-29 13:18:24 +02:00
misuzuandGitHub a7f519fda1 shipwright: fix build on gcc14 (#367988) 2024-12-29 13:11:23 +02:00
Sefa EyeogluandGitHub 388129ef19 qpwgraph: 0.8.0 -> 0.8.1 (#368815) 2024-12-29 12:01:45 +01:00
TomaandGitHub ce2e2c1555 portablemc: 4.4.0 -> 4.4.1 (#363815) 2024-12-29 11:57:13 +01:00
Gaétan LepageandGitHub e0cb1ceb41 pylyzer: 0.0.75 -> 0.0.76 (#369065) 2024-12-29 11:52:34 +01:00
Sefa EyeogluandGitHub 292976dc76 python312Packages.pydata-google-auth: 1.8.2 -> 1.9.0 (#358054) 2024-12-29 11:51:38 +01:00
Gaétan LepageandGitHub 6a97d508e4 catimg: fix compilation with gcc-14 (#369024) 2024-12-29 11:50:35 +01:00
Gaétan LepageandGitHub 4892c9db74 paper-clip: fix compilation error caused by glib (#369059) 2024-12-29 11:49:45 +01:00
Gaétan LepageandGitHub 9c730fca95 python312Packages.picos: fix build (#365343) 2024-12-29 11:46:02 +01:00
TomaandGitHub 9640018b22 makejinja: 2.6.2 -> 2.7.2 (#367762) 2024-12-29 11:33:19 +01:00
Gaetan Lepage 11bbeb48fb pylyzer: 0.0.75 -> 0.0.76
Diff: https://github.com/mtshiba/pylyzer/compare/None...v0.0.76

Changelog: https://github.com/mtshiba/pylyzer/releases/tag/v0.0.76
2024-12-29 11:31:50 +01:00
Fabian AffolterandGitHub 631d636ff4 python312Packages.mypy-boto3-*: updates (#369032) 2024-12-29 11:29:56 +01:00
Gaétan LepageandGitHub c35b54dbbe python312Packages.pmdarima: fix build (#365337) 2024-12-29 11:26:52 +01:00
Pratham Patel 42e57decdf paper-clip: fix compilation error caused by glib 2024-12-29 15:54:49 +05:30
7c6f434candGitHub a968249646 cuneiform: add patch for gcc 14 (#368870) 2024-12-29 10:07:52 +00:00
Pratham Patel 961b9e65e6 catimg: fix compilation with gcc-14 2024-12-29 15:32:22 +05:30
YorickandGitHub 2e30bda3fb mealie: 2.2.0 -> 2.3.0 (#361059) 2024-12-29 10:49:44 +01:00
Jon SeagerandGitHub 078fd58889 rockcraft: actually use sources for 1.7.0, add passthru.tests.version (#368933) 2024-12-29 09:47:57 +00:00
Azat BahawiandGitHub 617fb0e353 gzdoom: 4.13.2 -> 4.14.0 (#368993) 2024-12-29 12:46:17 +03:00
YorickandGitHub 87add4c78a victoriametrics: 1.108.0 -> 1.108.1 (#368893) 2024-12-29 10:40:12 +01:00
wxt 1186e7e8dd python312Packages.picos: 2.0 -> 2.5 2024-12-29 17:36:08 +08:00
misuzuandGitHub 1bdf3ca3ad nixos/wireguard-networkd: fix loading pre shared keys for peers without a custom name (#368684) 2024-12-29 11:33:22 +02:00
misuzuandGitHub 323d07e497 python312Packages.glfw: 2.7.0 -> 2.8.0 (#358230) 2024-12-29 11:30:24 +02:00
Gaétan LepageandGitHub b10f629831 gpufetch: init at 0.25 (#366983) 2024-12-29 10:30:07 +01:00
misuzuandGitHub 636420ee2d python312Packages.lib4sbom: 0.7.5 -> 0.8.1 (#365565) 2024-12-29 11:29:56 +02:00
misuzuandGitHub cabf7660b4 rain: 1.19.0 -> 1.20.2 (#365754) 2024-12-29 11:29:33 +02:00
misuzuandGitHub 354881d8ee python312Packages.coinmetrics-api-client: 2024.12.11.19 -> 2024.12.23.19 (#368386) 2024-12-29 11:29:14 +02:00
misuzuandGitHub 1c543a4d89 air: 1.61.4 -> 1.61.5 (#368548) 2024-12-29 11:28:22 +02:00
misuzuandGitHub 1ed1c80f0a python312Packages.manifestoo-core: 1.8.1 -> 1.8.2 (#368472) 2024-12-29 11:27:44 +02:00
misuzuandGitHub 65b1a033b2 signal-cli: 0.13.10 -> 0.13.11 (#368457) 2024-12-29 11:26:35 +02:00
misuzuandGitHub 9c0c9ba468 mainsail: 2.13.1 -> 2.13.2 (#368450) 2024-12-29 11:26:08 +02:00
misuzuandGitHub ea71188577 vscode-extensions.chenglou92.rescript-vscode: 1.58.0 -> 1.60.0 (#368253) 2024-12-29 11:25:34 +02:00
Gaétan LepageandGitHub c27edade7c peakperf: init at 1.17-unstable-2024-10-07 (#366989) 2024-12-29 10:25:22 +01:00
misuzuandGitHub ae41584780 linuxPackages.corefreq: 1.98.7 -> 2.0.0 (#368186) 2024-12-29 11:25:07 +02:00
misuzuandGitHub 4b4a85cb0f enzyme: 0.0.168 -> 0.0.170 (#368158) 2024-12-29 11:24:12 +02:00
misuzuandGitHub 257b6ff9b0 netbird: 0.34.1 -> 0.35.1 (#368945) 2024-12-29 11:23:43 +02:00
misuzuandGitHub fd67ee52c5 nushellPlugins.units: 0.1.3 -> 0.1.4 (#367724) 2024-12-29 11:23:10 +02:00
misuzuandGitHub 5b99f0b700 chirp: 0.4.0-unstable-2024-12-16 -> 0.4.0-unstable-2024-12-17 (#367477) 2024-12-29 11:22:52 +02:00
misuzuandGitHub 36541119da nanovna-saver: 0.6.5 -> 0.6.8 (#366881) 2024-12-29 11:22:20 +02:00
nixpkgs-merge-bot[bot]andGitHub 98572d9ad8 openapi-python-client: 0.22.0 -> 0.23.0 (#368889) 2024-12-29 09:21:59 +00:00
wxt 24543ec1cd gpufetch: init at 0.25 2024-12-29 17:21:34 +08:00
Doron BeharandGitHub 1ea28a7537 mympd: 19.0.1 -> 19.0.2 (#369045) 2024-12-29 11:21:14 +02:00
Florian KlinkandGitHub 23439d2761 rl-2411: add an entry for the new kmonad module (#368834) 2024-12-29 10:19:54 +01:00
Florian KlinkandGitHub 2b9a286555 nixos/movim: fixups (#364229) 2024-12-29 10:19:08 +01:00
Pol DellaieraandGitHub 2d3e86af3f jujutsu: update owner; change from rev to tag (#368985) 2024-12-29 10:09:55 +01:00
sethandGitHub 716c9419b0 ghostty: add nixos tests, add build options, fix x11 backend (#368726)
* ghostty: add nixos test

* ghostty: add nixosTests.allTerminfo to passthru.tests

* ghostty: factor out dependencies

This is meant to make cross platform support a bit easier. The options
are kept private as they aren't meant to be touched by end users

* ghostty: add optimizationLevel option

* ghostty: cleanup outputs

* ghostty: fix x11 backend

Forcing linkage isn't enough for Zig's `dlopen()` call. Let's just point
it towards the exact path instead

* ghostty: add darwin to meta.platforms
2024-12-29 04:09:33 -05:00
Pol DellaieraandGitHub b60fe11f2f Bump and rename siduck76-st > st-snazzy (#360236) 2024-12-29 10:06:20 +01:00
Sefa EyeogluandGitHub aaa570d6d3 godini: init at 1.0.0, treegen: init at 1.1.0 (#368704) 2024-12-29 10:04:08 +01:00
R. Ryantm 8a3157d3b9 mympd: 19.0.1 -> 19.0.2 2024-12-29 09:03:02 +00:00