mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
fd-util: Add fd_is_writable() to check if FD is opened for writing
This checks whether a file descriptor is valid and opened in a mode that allows writing (O_WRONLY or O_RDWR). This is useful when we want to verify that inherited FDs can actually be used for output operations before dup'ing them. The helper explicitly handles O_PATH file descriptors, which cannot be used for I/O operations and thus are never writable.
This commit is contained in:
@@ -998,6 +998,21 @@ int fd_vet_accmode(int fd, int mode) {
|
||||
return -EPROTOTYPE;
|
||||
}
|
||||
|
||||
int fd_is_writable(int fd) {
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
r = fd_vet_accmode(fd, O_WRONLY);
|
||||
if (r >= 0)
|
||||
return true;
|
||||
|
||||
if (IN_SET(r, -EPROTOTYPE, -EBADFD, -EISDIR))
|
||||
return false;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int fd_verify_safe_flags_full(int fd, int extra_flags) {
|
||||
int flags, unexpected_flags;
|
||||
|
||||
|
||||
@@ -152,6 +152,7 @@ int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
|
||||
|
||||
int fd_is_opath(int fd);
|
||||
int fd_vet_accmode(int fd, int mode);
|
||||
int fd_is_writable(int fd);
|
||||
|
||||
int fd_verify_safe_flags_full(int fd, int extra_flags);
|
||||
static inline int fd_verify_safe_flags(int fd) {
|
||||
|
||||
@@ -903,4 +903,27 @@ TEST(fd_vet_accmode) {
|
||||
ASSERT_ERROR(fd_vet_accmode(fd_opath, O_RDWR), EBADFD);
|
||||
}
|
||||
|
||||
TEST(fd_is_writable) {
|
||||
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-fd-writable.XXXXXX";
|
||||
_cleanup_close_ int fd_ro = -EBADF, fd_wo = -EBADF, fd_rw = -EBADF, fd_path = -EBADF;
|
||||
|
||||
ASSERT_OK(fd_rw = mkostemp_safe(name));
|
||||
ASSERT_OK_POSITIVE(fd_is_writable(fd_rw));
|
||||
|
||||
ASSERT_OK(fd_ro = open(name, O_RDONLY | O_CLOEXEC));
|
||||
ASSERT_OK_ZERO(fd_is_writable(fd_ro));
|
||||
|
||||
ASSERT_OK(fd_wo = open(name, O_WRONLY | O_CLOEXEC));
|
||||
ASSERT_OK_POSITIVE(fd_is_writable(fd_wo));
|
||||
|
||||
ASSERT_OK(fd_path = open(name, O_PATH | O_CLOEXEC));
|
||||
ASSERT_OK_ZERO(fd_is_writable(fd_path));
|
||||
|
||||
ASSERT_SIGNAL(fd_is_writable(-1), SIGABRT);
|
||||
|
||||
safe_close(fd_ro);
|
||||
ASSERT_ERROR(fd_is_writable(fd_ro), EBADF);
|
||||
TAKE_FD(fd_ro);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
||||
Reference in New Issue
Block a user