1 #include <fcntl.h>
2
3 #include <gpioplus/internal/fd.hpp>
4
5 #include <cerrno>
6 #include <cstdlib>
7 #include <system_error>
8 #include <utility>
9
10 namespace gpioplus
11 {
12 namespace internal
13 {
14
Fd(const char * pathname,int flags,const Sys * sys)15 Fd::Fd(const char* pathname, int flags, const Sys* sys) :
16 sys(sys), fd(sys->open(pathname, flags))
17 {
18 if (fd < 0)
19 {
20 throw std::system_error(errno, std::generic_category(), "Opening FD");
21 }
22 }
23
dup(int oldfd,const Sys * sys)24 static int dup(int oldfd, const Sys* sys)
25 {
26 int fd = sys->dup(oldfd);
27 if (fd < 0)
28 {
29 throw std::system_error(errno, std::generic_category(), "Duping FD");
30 }
31 return fd;
32 }
33
Fd(int fd,const Sys * sys)34 Fd::Fd(int fd, const Sys* sys) : sys(sys), fd(dup(fd, sys)) {}
35
Fd(int fd,std::false_type,const Sys * sys)36 Fd::Fd(int fd, std::false_type, const Sys* sys) : sys(sys), fd(fd) {}
37
~Fd()38 Fd::~Fd()
39 {
40 try
41 {
42 reset();
43 }
44 catch (...)
45 {
46 std::abort();
47 }
48 }
49
Fd(const Fd & other)50 Fd::Fd(const Fd& other) : sys(other.sys), fd(dup(other.fd, sys)) {}
51
operator =(const Fd & other)52 Fd& Fd::operator=(const Fd& other)
53 {
54 if (this != &other)
55 {
56 reset();
57 sys = other.sys;
58 fd = dup(other.fd, sys);
59 }
60 return *this;
61 }
62
Fd(Fd && other)63 Fd::Fd(Fd&& other) : sys(other.sys), fd(std::move(other.fd))
64 {
65 other.fd = -1;
66 }
67
operator =(Fd && other)68 Fd& Fd::operator=(Fd&& other)
69 {
70 if (this != &other)
71 {
72 reset();
73 sys = other.sys;
74 fd = std::move(other.fd);
75 other.fd = -1;
76 }
77 return *this;
78 }
79
operator *() const80 int Fd::operator*() const
81 {
82 return fd;
83 }
84
getSys() const85 const Sys* Fd::getSys() const
86 {
87 return sys;
88 }
89
setBlocking(bool enabled) const90 void Fd::setBlocking(bool enabled) const
91 {
92 if (enabled)
93 {
94 setFlags(getFlags() & ~O_NONBLOCK);
95 }
96 else
97 {
98 setFlags(getFlags() | O_NONBLOCK);
99 }
100 }
101
setFlags(int flags) const102 void Fd::setFlags(int flags) const
103 {
104 int r = sys->fcntl_setfl(fd, flags);
105 if (r == -1)
106 {
107 throw std::system_error(errno, std::generic_category(), "fcntl_setfl");
108 }
109 }
110
getFlags() const111 int Fd::getFlags() const
112 {
113 int flags = sys->fcntl_getfl(fd);
114 if (flags == -1)
115 {
116 throw std::system_error(errno, std::generic_category(), "fcntl_getfl");
117 }
118 return flags;
119 }
120
reset()121 void Fd::reset()
122 {
123 if (fd < 0)
124 {
125 return;
126 }
127
128 int ret = sys->close(fd);
129 fd = -1;
130 if (ret != 0)
131 {
132 throw std::system_error(errno, std::generic_category(), "Closing FD");
133 }
134 }
135
136 } // namespace internal
137 } // namespace gpioplus
138