1/*
2 * Copyright (c) 2000-2004,2011-2012,2014 Apple Inc. All Rights Reserved.
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
47namespace Security {
48namespace UnixPlusPlus {
49
50
51//
52// Check system call return and throw on error
53//
54template <class Result>
55inline 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//
66class IOVec : public iovec {
67public:
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//
84class FileDesc {
85protected:
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
93public:
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
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);
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
144    size_t seek(size_t position, int whence = SEEK_SET);
145	size_t position() const;
146
147    // mapping support
148    void *mmap(int prot = PROT_READ, size_t length = 0,
149		int flags = MAP_FILE | MAP_PRIVATE, size_t offset = 0, void *addr = NULL);
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 {
169		Pos(size_t s = 0, int wh = SEEK_SET, size_t siz = 0)
170			: start(s), size(siz), whence(wh) { }
171
172		size_t start;
173		size_t size;
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);
211	size_t listAttr(const std::string &name, size_t length, int options = 0)
212	{ return listAttr(name.c_str(), length, options); }
213
214	// xattrs with string values (not including trailing null bytes)
215	void setAttr(const std::string &name, const std::string &value, int options = 0);
216	std::string getAttr(const std::string &name, int options = 0);
217
218    // stat-related utilities. @@@ should cache??
219    typedef struct stat UnixStat;
220    void fstat(UnixStat &st) const;
221    size_t fileSize() const;
222	bool isA(int type) const;
223
224	// change various permissions-related features on the open file
225	void chown(uid_t uid);
226	void chown(uid_t uid, gid_t gid);
227	void chgrp(gid_t gid);
228	void chmod(mode_t mode);
229	void chflags(u_int flags);
230
231    // stdio interactions
232    FILE *fdopen(const char *mode = NULL);	// fdopen(3)
233
234	// Is this a regular file? (not a symlink, fifo, etc.)
235	bool isPlainFile(const std::string &path);
236
237private:
238    int mFd;				// UNIX file descriptor
239
240private:
241	struct LockArgs : public flock {
242		LockArgs(int type, const Pos &pos)
243		{ l_start = pos.start; l_len = pos.size; l_type = type; l_whence = pos.whence; }
244		IFDEBUG(void debug(int fd, const char *what));
245	};
246
247protected:
248    bool mAtEnd;			// end-of-data indicator (after zero read)
249};
250
251
252//
253// A (plain) FileDesc that auto-closes
254//
255class AutoFileDesc : public FileDesc {
256public:
257    AutoFileDesc() { }
258    AutoFileDesc(int fd) : FileDesc(fd) { }
259
260    AutoFileDesc(const char *path, int flag = O_RDONLY, mode_t mode = 0666)
261        : FileDesc(path, flag, mode) { }
262	AutoFileDesc(const std::string &path, int flag = O_RDONLY, mode_t mode = 0666)
263		: FileDesc(path, flag, mode) { }
264
265    ~AutoFileDesc()		{ close(); }
266};
267
268
269//
270// Signal sets
271//
272class SigSet {
273public:
274	SigSet() { sigemptyset(&mValue); }
275	SigSet(const sigset_t &s) : mValue(s) { }
276
277	SigSet &operator += (int sig)
278		{ sigaddset(&mValue, sig); return *this; }
279	SigSet &operator -= (int sig)
280		{ sigdelset(&mValue, sig); return *this; }
281
282	bool contains(int sig)
283		{ return sigismember(&mValue, sig); }
284
285	sigset_t &value()			{ return mValue; }
286	operator sigset_t () const	{ return mValue; }
287
288private:
289	sigset_t mValue;
290};
291
292SigSet sigMask(SigSet set, int how = SIG_SETMASK);
293
294
295//
296// A ForkMonitor determines whether the current thread is a (fork) child of
297// the thread that last checked it. Essentially, it checks for pid changes.
298//
299class StaticForkMonitor {
300public:
301	bool operator () () const
302	{
303		if (mLastPid == 0) {
304			mLastPid = getpid();
305			return false;
306		} else if (getpid() != mLastPid) {
307			mLastPid = getpid();
308			return true;
309		}
310		return false;
311	}
312
313protected:
314	mutable pid_t mLastPid;
315};
316
317class ForkMonitor : public StaticForkMonitor {
318public:
319	ForkMonitor()		{ mLastPid = getpid(); }
320};
321
322
323//
324// Miscellaneous functions to aid the intrepid UNIX hacker
325//
326void makedir(const char *path, int flags, mode_t mode = 0777);
327
328int ffprintf(const char *path, int flags, mode_t mode, const char *format, ...);
329int ffscanf(const char *path, const char *format, ...);
330
331
332}	// end namespace UnixPlusPlus
333}	// end namespace Security
334
335
336#endif //_H_UNIXPLUSPLUS
337