The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=bec5a3c046ba2bd970679a31f7227f260bef4935
commit bec5a3c046ba2bd970679a31f7227f260bef4935 Author: Warner Losh <i...@freebsd.org> AuthorDate: 2025-01-14 17:32:01 +0000 Commit: Warner Losh <i...@freebsd.org> CommitDate: 2025-01-14 17:52:54 +0000 nextboot: Smarter warning about deleting nextboot Read only filesystems always error when trying to remove something with EROFS. However, that's true even if the file isn't there. The code assumed it would always get a ENOENT if the file wasn't there, but produced a gross message on read only systems. This message was harmless, but annoying. Instead, stat the file first and return if it's already not there. Some readings of POSIX require that the ENOENT error take precidence over the EROFS error. Linux made this change years ago, and we should too. POSIX.1-2024 isn't explicit, but does say for unlink() does say "[EROFS] The directory entry to be unlinked is part of a read-only file system" and "[ENOENT] A component of path does not name an existing file" implying that EROFS should only be returned for an existing file. FreeBSD doesn't implement this, so this workaround is necessary. Ideally, we'd fix this in the kernel in the future. Sponsored by: Netflix Discussed with: jrtc23 Differential Revision: https://reviews.freebsd.org/D48425 --- sbin/reboot/reboot.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sbin/reboot/reboot.c b/sbin/reboot/reboot.c index c6b0e0980c88..9825d4f96319 100644 --- a/sbin/reboot/reboot.c +++ b/sbin/reboot/reboot.c @@ -308,7 +308,22 @@ main(int argc, char *argv[]) errx(1, "-r and -k cannot be used together, there is no next kernel"); if (Dflag) { - if (unlink(PATH_NEXTBOOT) != 0 && errno != ENOENT) + struct stat sb; + + /* + * Break the rule about stat then doing + * something. When we're booting, there's no + * race. When we're a read-only root, though, the + * read-only error takes priority over the file not + * there error in unlink. So stat it first and exit + * with success if it isn't there. Otherwise, let + * unlink sort error reporting. POSIX-1.2024 suggests + * ENOENT should be preferred to EROFS for unlink, + * but FreeBSD historically has preferred EROFS. + */ + if (stat(PATH_NEXTBOOT, &sb) != 0 && errno == ENOENT) + exit(0); + if (unlink(PATH_NEXTBOOT) != 0) warn("unlink " PATH_NEXTBOOT); exit(0); }