1 #pragma once
2 
3 #include <unistd.h> // for close()
4 
5 namespace phosphor::power::util
6 {
7 
8 /**
9  * @class FileDescriptor
10  *
11  * This class manages an open file descriptor.
12  *
13  * The file descriptor can be closed by calling close().  Otherwise it will be
14  * closed by the destructor.
15  *
16  * FileDescriptor objects cannot be copied, but they can be moved.  This enables
17  * them to be stored in containers like std::vector.
18  */
19 class FileDescriptor
20 {
21   public:
22     FileDescriptor() = default;
23     FileDescriptor(const FileDescriptor&) = delete;
24     FileDescriptor& operator=(const FileDescriptor&) = delete;
25 
26     /**
27      * Constructor.
28      *
29      * @param[in] fd - File descriptor
30      */
31     FileDescriptor(int fd) : fd(fd)
32     {}
33 
34     /**
35      * Move constructor.
36      *
37      * Transfers ownership of a file descriptor.
38      *
39      * @param other - FileDescriptor object being moved
40      */
41     FileDescriptor(FileDescriptor&& other) : fd(other.fd)
42     {
43         other.fd = -1;
44     }
45 
46     /**
47      * Move assignment operator.
48      *
49      * Closes the file descriptor owned by this object, if any.  Then transfers
50      * ownership of the file descriptor owned by the other object.
51      *
52      * @param other - FileDescriptor object being moved
53      */
54     FileDescriptor& operator=(FileDescriptor&& other)
55     {
56         // Verify not assigning object to itself (a = std::move(a))
57         if (this != &other)
58         {
59             set(other.fd);
60             other.fd = -1;
61         }
62         return *this;
63     }
64 
65     /**
66      * Destructor.
67      *
68      * Closes the file descriptor if necessary.
69      */
70     ~FileDescriptor()
71     {
72         close();
73     }
74 
75     /**
76      * Returns the file descriptor.
77      *
78      * @return File descriptor.  Returns -1 if this object does not contain an
79      *         open file descriptor.
80      */
81     int operator()()
82     {
83         return fd;
84     }
85 
86     /**
87      * Returns whether this object contains an open file descriptor.
88      *
89      * @return true if object contains an open file descriptor, false otherwise.
90      */
91     operator bool() const
92     {
93         return fd != -1;
94     }
95 
96     /**
97      * Closes the file descriptor.
98      *
99      * Does nothing if the file descriptor was not set or was already closed.
100      *
101      * @return 0 if descriptor was successfully closed.  Returns -1 if an error
102      *         occurred; errno will be set appropriately.
103      */
104     int close()
105     {
106         int rc = 0;
107         if (fd >= 0)
108         {
109             rc = ::close(fd);
110             fd = -1;
111         }
112         return rc;
113     }
114 
115     /**
116      * Sets the file descriptor.
117      *
118      * Closes the previous file descriptor if necessary.
119      *
120      * @param[in] descriptor - File descriptor
121      */
122     void set(int descriptor)
123     {
124         close();
125         fd = descriptor;
126     }
127 
128   private:
129     /**
130      * File descriptor.
131      */
132     int fd = -1;
133 };
134 
135 } // namespace phosphor::power::util
136