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