]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2004,2011-2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | ||
25 | // | |
26 | // unix++ - C++ layer for basic UNIX facilities | |
27 | // | |
28 | #ifndef _H_UNIXPLUSPLUS | |
29 | #define _H_UNIXPLUSPLUS | |
30 | ||
31 | #include <security_utilities/utilities.h> | |
32 | #include <security_utilities/errors.h> | |
33 | #include <security_utilities/timeflow.h> | |
34 | #include <sys/types.h> | |
35 | #include <sys/ioctl.h> | |
36 | #include <sys/uio.h> | |
37 | #include <sys/stat.h> | |
38 | #include <sys/mman.h> | |
39 | #include <signal.h> | |
40 | #include <fcntl.h> | |
41 | #include <semaphore.h> | |
42 | #include <cstdio> | |
43 | #include <cstdarg> | |
44 | #include <map> | |
45 | ||
46 | ||
47 | namespace Security { | |
48 | namespace UnixPlusPlus { | |
49 | ||
50 | ||
51 | // | |
52 | // Check system call return and throw on error | |
53 | // | |
54 | template <class Result> | |
55 | inline Result checkError(Result result) | |
56 | { | |
57 | if (result == Result(-1)) | |
58 | UnixError::throwMe(); | |
59 | return result; | |
60 | } | |
61 | ||
62 | ||
63 | // | |
64 | // A UNIX standard 'struct iovec' wrapped | |
65 | // | |
66 | class IOVec : public iovec { | |
67 | public: | |
68 | IOVec() { } | |
69 | IOVec(const void *data, size_t length) { set(data, length); } | |
70 | IOVec(void *data, size_t length) { set(data, length); } | |
71 | ||
72 | void set(const void *data, size_t length) | |
73 | { iov_base = reinterpret_cast<char *>(const_cast<void *>(data)); iov_len = length; } | |
74 | ||
75 | // data-oid methods | |
76 | void *data() const { return iov_base; } | |
77 | size_t length() const { return iov_len; } | |
78 | }; | |
79 | ||
80 | ||
81 | // | |
82 | // Generic file descriptors | |
83 | // | |
84 | class FileDesc { | |
85 | protected: | |
86 | static const int invalidFd = -1; | |
87 | ||
88 | void setFd(int fd) { mFd = fd; mAtEnd = false; } | |
89 | void checkSetFd(int fd) { checkError(fd); mFd = fd; mAtEnd = false; } | |
90 | ||
91 | FileDesc(int fd, bool atEnd) : mFd(fd), mAtEnd(atEnd) { } | |
92 | ||
93 | public: | |
94 | FileDesc() : mFd(invalidFd), mAtEnd(false) { } | |
95 | FileDesc(int fd) : mFd(fd), mAtEnd(false) { } | |
96 | ||
97 | static const mode_t modeMissingOk = S_IFIFO; // in mode means "do not throw on ENOENT" | |
98 | ||
99 | // implicit file system open() construction | |
100 | explicit FileDesc(const char *path, int flag = O_RDONLY, mode_t mode = 0666) | |
101 | : mFd(invalidFd) { this->open(path, flag, mode); } | |
102 | explicit FileDesc(const std::string &path, int flag = O_RDONLY, mode_t mode = 0666) | |
103 | : mFd(invalidFd) { this->open(path.c_str(), flag, mode); } | |
104 | ||
105 | // assignment | |
106 | FileDesc &operator = (int fd) { mFd = fd; mAtEnd = false; return *this; } | |
107 | FileDesc &operator = (const FileDesc &fd) { mFd = fd.mFd; mAtEnd = fd.mAtEnd; return *this; } | |
108 | ||
109 | bool isOpen() const { return mFd != invalidFd; } | |
110 | operator bool() const { return isOpen(); } | |
111 | int fd() const { return mFd; } | |
112 | operator int() const { return fd(); } | |
113 | ||
114 | void clear() { mFd = invalidFd; } | |
115 | void close(); // close and clear | |
116 | ||
117 | void open(const char *path, int flag = O_RDONLY, mode_t mode = 0666); | |
118 | void open(const std::string &path, int flag = O_RDONLY, mode_t mode = 0666) | |
119 | { this->open(path.c_str(), flag, mode); } | |
120 | ||
121 | // basic I/O: this defines the "Filedescoid" pseudo-type | |
122 | size_t read(void *addr, size_t length); | |
123 | size_t write(const void *addr, size_t length); | |
124 | bool atEnd() const { return mAtEnd; } // valid after zero-length read only | |
125 | ||
126 | // basic I/O with positioning | |
427c49bc A |
127 | size_t read(void *addr, size_t length, size_t position); |
128 | size_t write(const void *addr, size_t length, size_t position); | |
b1ab9ed8 A |
129 | |
130 | // read/write all of a buffer, in pieces of necessary | |
131 | size_t readAll(void *addr, size_t length); | |
132 | size_t readAll(std::string &content); | |
133 | void writeAll(const void *addr, size_t length); | |
134 | void writeAll(char *s) { writeAll(s, strlen(s)); } | |
135 | void writeAll(const char *s) { writeAll(s, strlen(s)); } | |
136 | template <class Data> | |
137 | void writeAll(const Data &ds) { writeAll(ds.data(), ds.length()); } | |
138 | ||
139 | // more convenient I/O | |
140 | template <class T> size_t read(T &obj) { return read(&obj, sizeof(obj)); } | |
141 | template <class T> size_t write(const T &obj) { return write(&obj, sizeof(obj)); } | |
142 | ||
143 | // seeking | |
427c49bc | 144 | size_t seek(size_t position, int whence = SEEK_SET); |
b1ab9ed8 A |
145 | size_t position() const; |
146 | ||
147 | // mapping support | |
148 | void *mmap(int prot = PROT_READ, size_t length = 0, | |
427c49bc | 149 | int flags = MAP_FILE | MAP_PRIVATE, size_t offset = 0, void *addr = NULL); |
b1ab9ed8 A |
150 | |
151 | // fcntl support | |
152 | int fcntl(int cmd, void *arg = NULL) const; | |
153 | template <class T> int fcntl(int cmd, T arg) const | |
154 | { return fcntl(cmd, reinterpret_cast<void *>(arg)); } | |
155 | int flags() const { return fcntl(F_GETFL); } | |
156 | void flags(int flags) const { fcntl(F_SETFL, flags); } | |
157 | void setFlag(int flag, bool on = true) const; | |
158 | void clearFlag(int flag) const { setFlag(flag, false); } | |
159 | ||
160 | int openMode() const { return flags() & O_ACCMODE; } | |
161 | bool isWritable() const { return openMode() != O_RDONLY; } | |
162 | bool isReadable() const { return openMode() != O_WRONLY; } | |
163 | ||
164 | FileDesc dup() const; | |
165 | FileDesc dup(int newFd) const; | |
166 | ||
167 | // lock support (fcntl style) | |
168 | struct Pos { | |
427c49bc | 169 | Pos(size_t s = 0, int wh = SEEK_SET, size_t siz = 0) |
b1ab9ed8 A |
170 | : start(s), size(siz), whence(wh) { } |
171 | ||
427c49bc A |
172 | size_t start; |
173 | size_t size; | |
b1ab9ed8 A |
174 | int whence; |
175 | }; | |
176 | static Pos lockAll() { return Pos(0, SEEK_SET, 0); } | |
177 | ||
178 | void lock(struct flock &args); // raw form (fill in yourself) | |
179 | ||
180 | void lock(int type = F_WRLCK, const Pos &pos = lockAll()); | |
181 | bool tryLock(int type = F_WRLCK, const Pos &pos = lockAll()); | |
182 | void unlock(const Pos &pos = lockAll()) { lock(F_UNLCK, pos); } | |
183 | ||
184 | // ioctl support | |
185 | int ioctl(int cmd, void *arg) const; | |
186 | template <class Arg> Arg iocget(int cmd) const | |
187 | { Arg arg; ioctl(cmd, &arg); return arg; } | |
188 | template <class Arg> void iocget(int cmd, Arg &arg) const | |
189 | { ioctl(cmd, &arg); } | |
190 | template <class Arg> void iocset(int cmd, const Arg &arg) | |
191 | { ioctl(cmd, const_cast<Arg *>(&arg)); } | |
192 | ||
193 | // xattr support | |
194 | void setAttr(const char *name, const void *value, size_t length, | |
195 | u_int32_t position = 0, int options = 0); | |
196 | void setAttr(const std::string &name, const void *value, size_t length, | |
197 | u_int32_t position = 0, int options = 0) | |
198 | { return setAttr(name.c_str(), value, length, position, options); } | |
199 | ssize_t getAttr(const char *name, void *value, size_t length, | |
200 | u_int32_t position = 0, int options = 0); | |
201 | ssize_t getAttr(const std::string &name, void *value, size_t length, | |
202 | u_int32_t position = 0, int options = 0) | |
203 | { return getAttr(name.c_str(), value, length, position, options); } | |
204 | ssize_t getAttrLength(const char *name); | |
205 | ssize_t getAttrLength(const std::string &name) { return getAttrLength(name.c_str()); } | |
206 | // removeAttr ignore missing attributes. Pass XATTR_REPLACE to fail in that case | |
207 | void removeAttr(const char *name, int options = 0); | |
208 | void removeAttr(const std::string &name, int options = 0) | |
209 | { return removeAttr(name.c_str(), options); } | |
210 | size_t listAttr(char *value, size_t length, int options = 0); | |
b1ab9ed8 A |
211 | |
212 | // xattrs with string values (not including trailing null bytes) | |
213 | void setAttr(const std::string &name, const std::string &value, int options = 0); | |
214 | std::string getAttr(const std::string &name, int options = 0); | |
215 | ||
216 | // stat-related utilities. @@@ should cache?? | |
217 | typedef struct stat UnixStat; | |
218 | void fstat(UnixStat &st) const; | |
219 | size_t fileSize() const; | |
220 | bool isA(int type) const; | |
221 | ||
222 | // change various permissions-related features on the open file | |
223 | void chown(uid_t uid); | |
224 | void chown(uid_t uid, gid_t gid); | |
225 | void chgrp(gid_t gid); | |
226 | void chmod(mode_t mode); | |
227 | void chflags(u_int flags); | |
228 | ||
229 | // stdio interactions | |
230 | FILE *fdopen(const char *mode = NULL); // fdopen(3) | |
231 | ||
80e23899 A |
232 | // Is this a regular file? (not a symlink, fifo, etc.) |
233 | bool isPlainFile(const std::string &path); | |
234 | ||
d87e1158 A |
235 | // device characteristics |
236 | std::string mediumType(); | |
237 | ||
b1ab9ed8 A |
238 | private: |
239 | int mFd; // UNIX file descriptor | |
240 | ||
241 | private: | |
242 | struct LockArgs : public flock { | |
243 | LockArgs(int type, const Pos &pos) | |
244 | { l_start = pos.start; l_len = pos.size; l_type = type; l_whence = pos.whence; } | |
245 | IFDEBUG(void debug(int fd, const char *what)); | |
246 | }; | |
247 | ||
248 | protected: | |
249 | bool mAtEnd; // end-of-data indicator (after zero read) | |
250 | }; | |
251 | ||
252 | ||
253 | // | |
254 | // A (plain) FileDesc that auto-closes | |
255 | // | |
256 | class AutoFileDesc : public FileDesc { | |
257 | public: | |
258 | AutoFileDesc() { } | |
259 | AutoFileDesc(int fd) : FileDesc(fd) { } | |
260 | ||
261 | AutoFileDesc(const char *path, int flag = O_RDONLY, mode_t mode = 0666) | |
262 | : FileDesc(path, flag, mode) { } | |
263 | AutoFileDesc(const std::string &path, int flag = O_RDONLY, mode_t mode = 0666) | |
264 | : FileDesc(path, flag, mode) { } | |
265 | ||
266 | ~AutoFileDesc() { close(); } | |
267 | }; | |
268 | ||
269 | ||
270 | // | |
271 | // Signal sets | |
272 | // | |
273 | class SigSet { | |
274 | public: | |
275 | SigSet() { sigemptyset(&mValue); } | |
276 | SigSet(const sigset_t &s) : mValue(s) { } | |
277 | ||
278 | SigSet &operator += (int sig) | |
279 | { sigaddset(&mValue, sig); return *this; } | |
280 | SigSet &operator -= (int sig) | |
281 | { sigdelset(&mValue, sig); return *this; } | |
282 | ||
283 | bool contains(int sig) | |
284 | { return sigismember(&mValue, sig); } | |
285 | ||
286 | sigset_t &value() { return mValue; } | |
287 | operator sigset_t () const { return mValue; } | |
288 | ||
289 | private: | |
290 | sigset_t mValue; | |
291 | }; | |
292 | ||
293 | SigSet sigMask(SigSet set, int how = SIG_SETMASK); | |
294 | ||
295 | ||
296 | // | |
297 | // A ForkMonitor determines whether the current thread is a (fork) child of | |
298 | // the thread that last checked it. Essentially, it checks for pid changes. | |
299 | // | |
300 | class StaticForkMonitor { | |
301 | public: | |
302 | bool operator () () const | |
303 | { | |
304 | if (mLastPid == 0) { | |
305 | mLastPid = getpid(); | |
306 | return false; | |
307 | } else if (getpid() != mLastPid) { | |
308 | mLastPid = getpid(); | |
309 | return true; | |
310 | } | |
311 | return false; | |
312 | } | |
313 | ||
314 | protected: | |
315 | mutable pid_t mLastPid; | |
316 | }; | |
317 | ||
318 | class ForkMonitor : public StaticForkMonitor { | |
319 | public: | |
320 | ForkMonitor() { mLastPid = getpid(); } | |
321 | }; | |
322 | ||
323 | ||
324 | // | |
325 | // Miscellaneous functions to aid the intrepid UNIX hacker | |
326 | // | |
327 | void makedir(const char *path, int flags, mode_t mode = 0777); | |
328 | ||
329 | int ffprintf(const char *path, int flags, mode_t mode, const char *format, ...); | |
330 | int ffscanf(const char *path, const char *format, ...); | |
331 | ||
332 | ||
333 | } // end namespace UnixPlusPlus | |
334 | } // end namespace Security | |
335 | ||
336 | ||
337 | #endif //_H_UNIXPLUSPLUS |