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