| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef UTIL_FD_H | ||
| 2 | #define UTIL_FD_H | ||
| 3 | |||
| 4 | #include <errno.h> | ||
| 5 | #include <fcntl.h> | ||
| 6 | #include <stdbool.h> | ||
| 7 | #include <sys/types.h> | ||
| 8 | #include <unistd.h> | ||
| 9 | #include "macros.h" | ||
| 10 | |||
| 11 | #define IS_STD_FD(fd) ((fd) >= STDIN_FILENO && (fd) <= STDERR_FILENO) | ||
| 12 | |||
| 13 | /* | ||
| 14 | * "The arg values to F_GETFD, F_SETFD, F_GETFL, and F_SETFL all | ||
| 15 | * represent flag values to allow for future growth. Applications | ||
| 16 | * using these functions should do a read-modify-write operation on | ||
| 17 | * them, rather than assuming that only the values defined by this | ||
| 18 | * volume of POSIX.1-2017 are valid. It is a common error to forget | ||
| 19 | * this, particularly in the case of F_SETFD." | ||
| 20 | * | ||
| 21 | * https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html#tag_16_122_07 | ||
| 22 | */ | ||
| 23 | WARN_UNUSED_RESULT | ||
| 24 | 27 | static inline bool fd_set_flag(int fd, int flag, int get_cmd, int set_cmd, bool state) | |
| 25 | { | ||
| 26 | 27 | int flags = fcntl(fd, get_cmd); | |
| 27 |
1/2✓ Branch 0 (3→4) taken 27 times.
✗ Branch 1 (3→12) not taken.
|
27 | if (unlikely(flags < 0)) { |
| 28 | return false; | ||
| 29 | } | ||
| 30 |
2/2✓ Branch 0 (4→5) taken 23 times.
✓ Branch 1 (4→6) taken 4 times.
|
27 | int new_flags = state ? (flags | flag) : (flags & ~flag); |
| 31 |
3/4✓ Branch 0 (7→8) taken 25 times.
✓ Branch 1 (7→11) taken 2 times.
✓ Branch 2 (9→10) taken 25 times.
✗ Branch 3 (9→11) not taken.
|
52 | return new_flags == flags || fcntl(fd, set_cmd, new_flags) != -1; |
| 32 | } | ||
| 33 | |||
| 34 | WARN_UNUSED_RESULT | ||
| 35 | 3 | static inline bool fd_set_cloexec(int fd, bool cloexec) | |
| 36 | { | ||
| 37 | 3 | return fd_set_flag(fd, FD_CLOEXEC, F_GETFD, F_SETFD, cloexec); | |
| 38 | } | ||
| 39 | |||
| 40 | WARN_UNUSED_RESULT | ||
| 41 | 24 | static inline bool fd_set_nonblock(int fd, bool nonblock) | |
| 42 | { | ||
| 43 | 24 | return fd_set_flag(fd, O_NONBLOCK, F_GETFL, F_SETFL, nonblock); | |
| 44 | } | ||
| 45 | |||
| 46 | WARN_UNUSED_RESULT | ||
| 47 | 9 | static inline bool fd_is_valid(int fd) | |
| 48 | { | ||
| 49 |
1/4✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→6) taken 9 times.
✗ Branch 2 (4→5) not taken.
✗ Branch 3 (4→6) not taken.
|
9 | return fcntl(fd, F_GETFD) != -1 || errno != EBADF; |
| 50 | } | ||
| 51 | |||
| 52 | WARN_UNUSED_RESULT | ||
| 53 | 3 | static inline bool is_controlling_tty(int fd) | |
| 54 | { | ||
| 55 | /* | ||
| 56 | * POSIX requires tcgetpgrp() to return -1 and set errno to ENOTTY if | ||
| 57 | * `fd` isn't the controlling terminal, so this check alone should be | ||
| 58 | * sufficient here. However, OpenBSD 7.5 and FreeBSD 14.0 don't seem | ||
| 59 | * to conform to this requirement, so as a best-effort workaround we | ||
| 60 | * also check isatty(). This means that the function name used here | ||
| 61 | * isn't entirely accurate on those platforms, although it'd take a | ||
| 62 | * very unusual set of stdio(3) redirections for it to be a problem | ||
| 63 | * in practice (for the use cases in this codebase). | ||
| 64 | * | ||
| 65 | * See also: https://gitlab.com/craigbarnes/dte/-/issues/216#note_1939534295 | ||
| 66 | */ | ||
| 67 |
1/4✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→7) taken 3 times.
✗ Branch 2 (5→6) not taken.
✗ Branch 3 (5→7) not taken.
|
3 | return isatty(fd) && tcgetpgrp(fd) != -1; |
| 68 | } | ||
| 69 | |||
| 70 | int xpipe2(int fd[static 2], int flags) WARN_UNUSED_RESULT; | ||
| 71 | int xdup3(int oldfd, int newfd, int flags) WARN_UNUSED_RESULT; | ||
| 72 | int xfchown(int fd, uid_t owner, gid_t group) WARN_UNUSED_RESULT; | ||
| 73 | int xfchmod(int fd, mode_t mode) WARN_UNUSED_RESULT; | ||
| 74 | int xftruncate(int fd, off_t length) WARN_UNUSED_RESULT; | ||
| 75 | int xfsync(int fd) WARN_UNUSED_RESULT; | ||
| 76 | |||
| 77 | #endif | ||
| 78 |