When the extensions for the final system are already set up from the
initrd we should avoid disrupting the boot process with the remount
(which currently isn't atomic) and the daemon reload for
systemd-confext and systemd-sysext. Similarly, when sysupdate ran and
updated extensions it's best to avoid the remount and daemon reload if
no changes are found.
To do this, encode the current extension state in more detail than
before where only the names of the extensions where encoded in the
overlay mount. This can also be used to provide more details about the
extension origin in "systemd-sysext status (--json=)". During the
refresh add a check whether the old state matches the new state and in
this case skip the refresh unless the user provides a flag to always
refresh. Besides the extension name and the resolved path the best
method for identification is the verity hash but that is not available
for plain image files or directories. Therefore, also include data to
check for file/directory replacements. The creation/modification times
are not always real on reproducible images or extracted archive content.
The file handle together with the unique mount ID is the next best
identifier we can use when we have no verity hash. Fall back to an inode
when we get no handle. With the creation/modification time and the path
this should be good enough. Using a unique mount ID is important (with
a fallback to the regular non-unique mount ID) instead of st_dev because
st_dev gets reused too easily, e.g., by a loop device mount and the
mount ID helps to catch this. For the mount ID to be valid it has to be
resolved before we enter the new mount namespace. Thus, it gets provided
by the image dissect logic and handed over to the sysext subprocess
which runs in a new mount namespace.
Luckily, we can rule out online modification of directories or image
files because this is anyway not well supported with overlay mounts, so
we don't do a file checksum nor do we recurse into a directory to look
for the most recently touched files. But, as said, with the
always-refresh flag one can force a reload.
This also effectively reverts eb2e91b981,
as now the object is only used as input, and kernel would need to handle
input with only ID no matter whether the struct later gets extended.
The current code assumes that FILEID_KERNFS filehandles will never grow
in size. This is not a safe assumption and userland shouldn't be trying
to guess the size of the filehandle it'll get.
We have a macro for that: MAX_HANDLE_SZ.
Follow-up for af718e0535
The commit changed the documentation, but the actual impl
was apparently not updated. And the documented behavior
feels a bit off. I think generally "auto"/true should
override $NO_COLOR.
Plus, the test for auto-24bit is at odds with the logic
we merged. I guess it was overlooked after applying
https://github.com/systemd/systemd/pull/40303#discussion_r2720450393
This is useful in tools such as system-repart where we show the
definition file paths a lot in our output, but if prefixed with the root
path we'd show a temporary mount dir when operating on a image file.
Hence, let's drop the prefix here, and show only the path within the
image.
Let's make sure we can safely load configuration files based on a root
fd, including XAT_FDROOT.
(While we are at it, always pass path to root fs before fd to root fs,
following our recently updated CODING_STYLE)
Typically, proc_mounted() is used in error handling. Hence, it is better
to make it not update the original errno.
Currently, there are two places that returns wrong error code:
- pidref_get_capability() in src/basic/capability-util.c
```c
_cleanup_fclose_ FILE *f = fopen(path, "re");
if (!f) {
if (errno == ENOENT && proc_mounted() == 0)
return -ENOSYS;
return -errno;
}
```
- fdset_new_fill() in src/shared/fdset.c
```c
d = opendir("/proc/self/fd");
if (!d) {
if (errno == ENOENT && proc_mounted() == 0)
return -ENOSYS;
return -errno;
}
```
Rather than fixing them, let's make proc_mounted() not update errno,
otherwise we may make a similar failure in a future.
Calling mlockall in an unprivileged process most notably had the effect
of making systemd-cryptenroll OOM while trying to open a normal-sized
argon2 keyslot due to it hitting RLIMIT_MEMLOCK.
Now that we can recognize the root dir in chaseat() sanely, let's use it
top optimize the very common special case where we have no root dir to
consider, and directly call open_tree().
This takes inspiration from AT_FDCWD, but always references the root dir
rather than the cwd. This allows various convenience uses, as we can now
reference the root dir without actually allocating an fd for chaseat(),
fd_get_path() and various others.
The value of XAT_FDROOT is chosen so that it is not a valid fd (essential,
because we do not intend to hook this up everywhere, just where we need
it, just like AT_FCWD only works in some syscalls), and we want uses at
the wrong places to fail cleanly. It also uses a valud outside of the
range where we usually return negative errnos, i.e. < -ERRNO_MAX.
Since 6eabe9f2ff we generate sequences
with ":", hence we better also know how to strip them.
(Without this patch we'd strip simple ANSI colors, but not RGB ones that
use ":" syntax).
(While we are at it, also drop a duplicate "0" in the list of valid
chars)