1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QCORE_UNIX_P_H
43 #define QCORE_UNIX_P_H
44
45 //
46 // W A R N I N G
47 // -------------
48 //
49 // This file is not part of the Qt API. It exists for the convenience
50 // of Qt code on Unix. This header file may change from version to
51 // version without notice, or even be removed.
52 //
53 // We mean it.
54 //
55
56 #include "qplatformdefs.h"
57 #include "qatomic.h"
58
59 #ifndef Q_OS_UNIX
60 # error "qcore_unix_p.h included on a non-Unix system"
61 #endif
62
63 #include <string.h>
64 #include <sys/types.h>
65 #include <sys/stat.h>
66 #include <unistd.h>
67
68 #include <sys/wait.h>
69 #include <errno.h>
70 #include <fcntl.h>
71
72 #if defined(Q_OS_VXWORKS)
73 # include <ioLib.h>
74 #endif
75
76 struct sockaddr;
77
78 #if defined(Q_OS_LINUX) && defined(O_CLOEXEC)
79 # define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 1
80 QT_BEGIN_NAMESPACE
81 namespace QtLibcSupplement {
accept4(int,sockaddr *,QT_SOCKLEN_T *,int)82 inline int accept4(int, sockaddr *, QT_SOCKLEN_T *, int)
83 { errno = ENOSYS; return -1; }
dup3(int,int,int)84 inline int dup3(int, int, int)
85 { errno = ENOSYS; return -1; }
pipe2(int[],int)86 inline int pipe2(int [], int )
87 { errno = ENOSYS; return -1; }
88 }
89 QT_END_NAMESPACE
90 using namespace QT_PREPEND_NAMESPACE(QtLibcSupplement);
91
92 #else
93 # define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 0
94 #endif
95
96 #define EINTR_LOOP(var, cmd) \
97 do { \
98 var = cmd; \
99 } while (var == -1 && errno == EINTR)
100
101 QT_BEGIN_NAMESPACE
102
103 // Internal operator functions for timevals
normalizedTimeval(timeval & t)104 inline timeval &normalizedTimeval(timeval &t)
105 {
106 while (t.tv_usec > 1000000l) {
107 ++t.tv_sec;
108 t.tv_usec -= 1000000l;
109 }
110 while (t.tv_usec < 0l) {
111 --t.tv_sec;
112 t.tv_usec += 1000000l;
113 }
114 return t;
115 }
116 inline bool operator<(const timeval &t1, const timeval &t2)
117 { return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec); }
118 inline bool operator==(const timeval &t1, const timeval &t2)
119 { return t1.tv_sec == t2.tv_sec && t1.tv_usec == t2.tv_usec; }
120 inline timeval &operator+=(timeval &t1, const timeval &t2)
121 {
122 t1.tv_sec += t2.tv_sec;
123 t1.tv_usec += t2.tv_usec;
124 return normalizedTimeval(t1);
125 }
126 inline timeval operator+(const timeval &t1, const timeval &t2)
127 {
128 timeval tmp;
129 tmp.tv_sec = t1.tv_sec + t2.tv_sec;
130 tmp.tv_usec = t1.tv_usec + t2.tv_usec;
131 return normalizedTimeval(tmp);
132 }
133 inline timeval operator-(const timeval &t1, const timeval &t2)
134 {
135 timeval tmp;
136 tmp.tv_sec = t1.tv_sec - (t2.tv_sec - 1);
137 tmp.tv_usec = t1.tv_usec - (t2.tv_usec + 1000000);
138 return normalizedTimeval(tmp);
139 }
140 inline timeval operator*(const timeval &t1, int mul)
141 {
142 timeval tmp;
143 tmp.tv_sec = t1.tv_sec * mul;
144 tmp.tv_usec = t1.tv_usec * mul;
145 return normalizedTimeval(tmp);
146 }
147
qt_ignore_sigpipe()148 inline void qt_ignore_sigpipe()
149 {
150 #ifndef Q_NO_POSIX_SIGNALS
151 // Set to ignore SIGPIPE once only.
152 static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
153 if (!atom) {
154 // More than one thread could turn off SIGPIPE at the same time
155 // But that's acceptable because they all would be doing the same
156 // action
157 struct sigaction noaction;
158 memset(&noaction, 0, sizeof(noaction));
159 noaction.sa_handler = SIG_IGN;
160 ::sigaction(SIGPIPE, &noaction, 0);
161 atom = 1;
162 }
163 #else
164 // Posix signals are not supported by the underlying platform
165 // so we don't need to ignore sigpipe signal explicitly
166 #endif
167 }
168
169 // don't call QT_OPEN or ::open
170 // call qt_safe_open
171 static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 0777)
172 {
173 #ifdef O_CLOEXEC
174 flags |= O_CLOEXEC;
175 #endif
176 int fd;
177 EINTR_LOOP(fd, QT_OPEN(pathname, flags, mode));
178
179 // unknown flags are ignored, so we have no way of verifying if
180 // O_CLOEXEC was accepted
181 if (fd != -1)
182 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
183 return fd;
184 }
185 #undef QT_OPEN
186 #define QT_OPEN qt_safe_open
187
188 #ifndef Q_OS_VXWORKS // no POSIX pipes in VxWorks
189 // don't call ::pipe
190 // call qt_safe_pipe
191 static inline int qt_safe_pipe(int pipefd[2], int flags = 0)
192 {
193 #ifdef O_CLOEXEC
194 Q_ASSERT((flags & ~(O_CLOEXEC | O_NONBLOCK)) == 0);
195 #else
196 Q_ASSERT((flags & ~O_NONBLOCK) == 0);
197 #endif
198
199 int ret;
200 #if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
201 // use pipe2
202 flags |= O_CLOEXEC;
203 ret = ::pipe2(pipefd, flags); // pipe2 is Linux-specific and is documented not to return EINTR
204 if (ret == 0 || errno != ENOSYS)
205 return ret;
206 #endif
207
208 ret = ::pipe(pipefd);
209 if (ret == -1)
210 return -1;
211
212 ::fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);
213 ::fcntl(pipefd[1], F_SETFD, FD_CLOEXEC);
214
215 // set non-block too?
216 if (flags & O_NONBLOCK) {
217 ::fcntl(pipefd[0], F_SETFL, ::fcntl(pipefd[0], F_GETFL) | O_NONBLOCK);
218 ::fcntl(pipefd[1], F_SETFL, ::fcntl(pipefd[1], F_GETFL) | O_NONBLOCK);
219 }
220
221 return 0;
222 }
223
224 #endif // Q_OS_VXWORKS
225
226 // don't call dup or fcntl(F_DUPFD)
227 static inline int qt_safe_dup(int oldfd, int atleast = 0, int flags = FD_CLOEXEC)
228 {
229 Q_ASSERT(flags == FD_CLOEXEC || flags == 0);
230
231 int ret;
232 #ifdef F_DUPFD_CLOEXEC
233 // use this fcntl
234 if (flags & FD_CLOEXEC) {
235 ret = ::fcntl(oldfd, F_DUPFD_CLOEXEC, atleast);
236 if (ret != -1 || errno != EINVAL)
237 return ret;
238 }
239 #endif
240
241 // use F_DUPFD
242 ret = ::fcntl(oldfd, F_DUPFD, atleast);
243
244 if (flags && ret != -1)
245 ::fcntl(ret, F_SETFD, flags);
246 return ret;
247 }
248
249 // don't call dup2
250 // call qt_safe_dup2
251 static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC)
252 {
253 Q_ASSERT(flags == FD_CLOEXEC || flags == 0);
254
255 int ret;
256 #if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
257 // use dup3
258 if (flags & FD_CLOEXEC) {
259 EINTR_LOOP(ret, ::dup3(oldfd, newfd, O_CLOEXEC));
260 if (ret == 0 || errno != ENOSYS)
261 return ret;
262 }
263 #endif
264 EINTR_LOOP(ret, ::dup2(oldfd, newfd));
265 if (ret == -1)
266 return -1;
267
268 if (flags)
269 ::fcntl(newfd, F_SETFD, flags);
270 return 0;
271 }
272
qt_safe_read(int fd,void * data,qint64 maxlen)273 static inline qint64 qt_safe_read(int fd, void *data, qint64 maxlen)
274 {
275 qint64 ret = 0;
276 EINTR_LOOP(ret, QT_READ(fd, data, maxlen));
277 return ret;
278 }
279 #undef QT_READ
280 #define QT_READ qt_safe_read
281
qt_safe_write(int fd,const void * data,qint64 len)282 static inline qint64 qt_safe_write(int fd, const void *data, qint64 len)
283 {
284 qint64 ret = 0;
285 EINTR_LOOP(ret, QT_WRITE(fd, data, len));
286 return ret;
287 }
288 #undef QT_WRITE
289 #define QT_WRITE qt_safe_write
290
qt_safe_write_nosignal(int fd,const void * data,qint64 len)291 static inline qint64 qt_safe_write_nosignal(int fd, const void *data, qint64 len)
292 {
293 qt_ignore_sigpipe();
294 return qt_safe_write(fd, data, len);
295 }
296
qt_safe_close(int fd)297 static inline int qt_safe_close(int fd)
298 {
299 int ret;
300 EINTR_LOOP(ret, QT_CLOSE(fd));
301 return ret;
302 }
303 #undef QT_CLOSE
304 #define QT_CLOSE qt_safe_close
305
306 // - Open C does not (yet?) implement these on Symbian OS
307 // - VxWorks doesn't have processes
308 #if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_VXWORKS)
qt_safe_execve(const char * filename,char * const argv[],char * const envp[])309 static inline int qt_safe_execve(const char *filename, char *const argv[],
310 char *const envp[])
311 {
312 register int ret;
313 EINTR_LOOP(ret, ::execve(filename, argv, envp));
314 return ret;
315 }
316
qt_safe_execv(const char * path,char * const argv[])317 static inline int qt_safe_execv(const char *path, char *const argv[])
318 {
319 register int ret;
320 EINTR_LOOP(ret, ::execv(path, argv));
321 return ret;
322 }
323
qt_safe_execvp(const char * file,char * const argv[])324 static inline int qt_safe_execvp(const char *file, char *const argv[])
325 {
326 register int ret;
327 EINTR_LOOP(ret, ::execvp(file, argv));
328 return ret;
329 }
330 #endif
331
332 #ifndef Q_OS_VXWORKS // no processes on VxWorks
qt_safe_waitpid(pid_t pid,int * status,int options)333 static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options)
334 {
335 register int ret;
336 EINTR_LOOP(ret, ::waitpid(pid, status, options));
337 return ret;
338 }
339
340 #endif // Q_OS_VXWORKS
341
342 #if !defined(_POSIX_MONOTONIC_CLOCK)
343 # define _POSIX_MONOTONIC_CLOCK -1
344 #endif
345
346 timeval qt_gettime(); // in qelapsedtimer_mac.cpp or qtimestamp_unix.cpp
347
348 Q_CORE_EXPORT int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
349 const struct timeval *tv);
350
351 // according to X/OPEN we have to define semun ourselves
352 // we use prefix as on some systems sem.h will have it
353 struct semid_ds;
354 union qt_semun {
355 int val; /* value for SETVAL */
356 struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
357 unsigned short *array; /* array for GETALL, SETALL */
358 };
359
360 QT_END_NAMESPACE
361
362 #endif
363