1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
/*
* This source code is released into the public domain.
*/
#include "fd.hh"
namespace lfjail {
fd::fd(int fd_) noexcept
: _fd(fd_)
{}
fd::fd(fd &&other) noexcept
: _fd(std::exchange(other._fd, _invalid_fd))
{}
auto fd::operator=(fd &&other) noexcept -> fd & {
if (this != &other)
_fd = std::exchange(other._fd, _invalid_fd);
return *this;
}
fd::operator bool(this fd const &self) noexcept {
return self._fd != _invalid_fd;
}
fd::~fd() {
if (*this)
this->close();
}
auto fd::close(this fd &self) -> void {
(void)::close(self.get());
self._fd = _invalid_fd;
}
auto fd::get(this fd const &self) -> int {
if (!self)
std::abort();
return self._fd;
}
auto fd::release() && noexcept -> int {
if (!*this)
std::abort();
return std::exchange(_fd, _invalid_fd);
}
// Create a copy of this fd by calling dup().
auto dup(fd const &self) -> fd {
auto thisfd = self.get();
auto const newfd = ::dup(thisfd);
if (newfd == -1)
throw generic_error("dup({}): {}", thisfd,
std::strerror(errno));
return {newfd};
}
// Create a copy of this fd by calling dup2(). The second argument
// must not be managed by an instance of the fd class, or else it
// will be closed twice.
auto dup(fd const &self, int newfd) -> fd {
auto thisfd = self.get();
// dup2() allows the existing and new fd to be the same,
// but this is error-prone and usually a logic error, so
// we reject it.
if (thisfd == newfd)
std::abort();
auto const ret = ::dup2(thisfd, newfd);
if (ret == -1)
throw generic_error("dup({}): {}", thisfd,
std::strerror(errno));
return {newfd};
}
// Return the fnctl flags for this fd.
auto getflags(fd const &self) -> int {
auto const flags = ::fcntl(self.get(), F_GETFL);
if (flags == -1)
throw generic_error("fcntl({}, F_GETFL): {}",
self.get(), strerror(errno));
return flags;
}
// Replace the fnctl flags for this fd.
auto replaceflags(fd &self, int newflags) -> void {
auto const ret = ::fcntl(self.get(), F_SETFL, newflags);
if (ret == -1)
throw generic_error("fcntl({}, F_SETFL, {}): {}",
self.get(), newflags, strerror(errno));
}
// Add bits to the fcntl flags for this fd.
auto setflags(fd &self, int newflags) -> void {
auto flags = getflags(self);
flags |= newflags;
replaceflags(self, flags);
}
// Remove bits from the fcntl flags for this fd.
auto clearflags(fd &self, int clrflags) -> void {
auto flags = getflags(self);
flags &= ~clrflags;
replaceflags(self, flags);
}
// Create two fds by calling pipe() and return them.
auto pipe() -> std::pair<fd, fd> {
auto fds = std::array<int, 2>{};
if (auto const ret = ::pipe(fds.data()); ret != 0)
throw generic_error("pipe(): {}", std::strerror(errno));
return {fd(fds[0]), fd(fds[1])};
}
} // namespace lfjail
|