We may want to propagate O_APPEND, or (try to) keep the current file position,
even if we use fd_reopen() to re-initialize (and "unshare") other file
description status.
For now, used only with --pty to keep/propagate O_APPEND (and/or) position
if set on stdin/stdout.
If we re-open stdout and "drop" the O_APPEND,
we get rather "unexpected" behavior,
for example with repeated "systemd-run --pty >> some-log".
If someone carefully pre-positioned the passed in original file descriptors,
we avoid surprises if we do not reset file postition to zero.
fcntl F_GETFL first, and propagate O_APPEND if present in the existing flags.
Then use lseek to propagate the file position.
Let's make fd_verify_safe_flags() even more useful:
1. let's return the cleaned up flags (i.e. just the access mode) after
validation, hiding all the noise, such as O_NOFOLLOW, O_LARGEFILE and
similar.
2. let's add a "full" version of the call that allows passing additional
flags that are OK to be set.
This is useful for situations where an array of FDs is to be passed into
a child process (i.e. by passing it through safe_fork). This function
can be called in the child (before calling exec) to pack the FDs to all
be next to each-other starting from SD_LISTEN_FDS_START (i.e. 3)
So glibc exposes a close_range() syscall wrapper now, but they decided
to use "unsigned" as type for the fds. Which is a bit weird, because fds
are universally understood to be "int". The kernel internally uses
"unsigned", both for close() and for close_range(), but weirdly,
userspace didn't fix that for close_range() unlike what they did for
close()... Weird.
But anyway, let's follow suit, and make our wrapper match glibc's.
Fixes#31270
O_CREAT doesn't make sense for fd_reopen, since we're
working on an already opened fd. Also, in fd_reopen
we don't handle the mode parameter of open(2), which
means we may get runtime error like #29938.
This is just like FORMAT_PROC_FD_PATH() but goes via the PID number
rather than the "self" symlink.
This is useful whenever we want to generate a path that is useful
outside of our local scope.
We use it for more than just pipe() arrays. For example also for
socketpair(). Hence let's give it a generic name.
Also add EBADF_TRIPLET to mirror this for things like
stdin/stdout/stderr arrays, which we use a bunch of times.
This is supposed to be a help for compilers to apply optimizations on
functions where they can't determine whether they are const/pure on
their own. For static, local functions the compiler can do this on its
own easily however, hence the decoration with pure/const is just noise.
Let's drop it, and let the compiler to its thing better.
(Use it for exported functions, since compilers can't 'reach-over' into
other modules to determine if they are pure, except if LTO is used)
Previously, in path_is_root_at(), if statx() does not provide mount ID,
path_get_mnt_id_at() was called, but it also calls statx(). Let's avoid
the second trial.
Now, dir_fd_is_root() is heavily used in chaseat(), which is used at
various places. If the kernel is too old and /proc is not mounted, then
there is no way to get the mount ID of a directory. In that case, let's
silently skip the mount ID check.
Fixes https://github.com/systemd/systemd/pull/27299#issuecomment-1511403680.
The /proc/self/fd/ interface cannot be used to follow symlinks pinned
via O_PATH. Add a comment + test for that. Moreover, using fd_reopen()
with O_NOFOLLOW cannot work. Add an explicit check and test for that, to
make behaviour uniform.
-1 was used everywhere, but -EBADF or -EBADFD started being used in various
places. Let's make things consistent in the new style.
Note that there are two candidates:
EBADF 9 Bad file descriptor
EBADFD 77 File descriptor in bad state
Since we're initializating the fd, we're just assigning a value that means
"no fd yet", so it's just a bad file descriptor, and the first errno fits
better. If instead we had a valid file descriptor that became invalid because
of some operation or state change, the other errno would fit better.
In some places, initialization is dropped if unnecessary.
This is a wrapper around fd_reopen() that will reopen an fd if the
F_GETFL flags indicate this is necessary, and otherwise not.
This is useful for various utility calls that shall be able to operate
on O_PATH and without it, and might need to convert between the two
depending on what's passed in.
We have free_and_replace() and friends, they are all named with lower
letters, even they are macros, not functions.
For consistency, let's rename CLOSE_AND_REPLACE() with lower letters.
This also mekes the macro used more places.