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 |