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