1
/****************************************************************************
2
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the QtCore module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
36
**
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
58
#ifndef Q_OS_UNIX
59
# error "qcore_unix_p.h included on a non-Unix system"
60
#endif
61
62
#include <sys/types.h>
63
#include <sys/stat.h>
64
#include <unistd.h>
65
66
#include <sys/wait.h>
67
#include <errno.h>
68
#include <fcntl.h>
69
70
#if defined(Q_OS_VXWORKS)
71
#  include <ioLib.h>
72
#endif
73
74
struct sockaddr;
75
76
#if defined(Q_OS_LINUX) && defined(O_CLOEXEC)
77
# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 1
78
QT_BEGIN_NAMESPACE
79
namespace QtLibcSupplement {
80
    inline int accept4(int, sockaddr *, QT_SOCKLEN_T *, int)
81
    { errno = ENOSYS; return -1; }
82
    inline int dup3(int, int, int)
83
    { errno = ENOSYS; return -1; }
84
    inline int pipe2(int [], int )
85
    { errno = ENOSYS; return -1; }
86
}
87
QT_END_NAMESPACE
88
using namespace QT_PREPEND_NAMESPACE(QtLibcSupplement);
89
90
#else
91
# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 0
92
#endif
93
94
#define EINTR_LOOP(var, cmd)                    \
95
    do {                                        \
96
        var = cmd;                              \
97
    } while (var == -1 && errno == EINTR)
98
99
QT_BEGIN_NAMESPACE
100
101
// Internal operator functions for timevals
102
inline timeval &normalizedTimeval(timeval &t)
103
{
104
    while (t.tv_usec > 1000000l) {
105
        ++t.tv_sec;
106
        t.tv_usec -= 1000000l;
107
    }
108
    while (t.tv_usec < 0l) {
109
        --t.tv_sec;
110
        t.tv_usec += 1000000l;
111
    }
112
    return t;
113
}
114
inline bool operator<(const timeval &t1, const timeval &t2)
115
{ return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec); }
116
inline bool operator==(const timeval &t1, const timeval &t2)
117
{ return t1.tv_sec == t2.tv_sec && t1.tv_usec == t2.tv_usec; }
118
inline timeval &operator+=(timeval &t1, const timeval &t2)
119
{
120
    t1.tv_sec += t2.tv_sec;
121
    t1.tv_usec += t2.tv_usec;
122
    return normalizedTimeval(t1);
123
}
124
inline timeval operator+(const timeval &t1, const timeval &t2)
125
{
126
    timeval tmp;
127
    tmp.tv_sec = t1.tv_sec + t2.tv_sec;
128
    tmp.tv_usec = t1.tv_usec + t2.tv_usec;
129
    return normalizedTimeval(tmp);
130
}
131
inline timeval operator-(const timeval &t1, const timeval &t2)
132
{
133
    timeval tmp;
134
    tmp.tv_sec = t1.tv_sec - (t2.tv_sec - 1);
135
    tmp.tv_usec = t1.tv_usec - (t2.tv_usec + 1000000);
136
    return normalizedTimeval(tmp);
137
}
138
inline timeval operator*(const timeval &t1, int mul)
139
{
140
    timeval tmp;
141
    tmp.tv_sec = t1.tv_sec * mul;
142
    tmp.tv_usec = t1.tv_usec * mul;
143
    return normalizedTimeval(tmp);
144
}
145
146
// don't call QT_OPEN or ::open
147
// call qt_safe_open
148
static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 0777)
149
{
150
#ifdef O_CLOEXEC
151
    flags |= O_CLOEXEC;
152
#endif
153
    register int fd;
154
    EINTR_LOOP(fd, QT_OPEN(pathname, flags, mode));
155
156
    // unknown flags are ignored, so we have no way of verifying if
157
    // O_CLOEXEC was accepted
158
    if (fd != -1)
159
        ::fcntl(fd, F_SETFD, FD_CLOEXEC);
160
    return fd;
161
}
162
#undef QT_OPEN
163
#define QT_OPEN         qt_safe_open
164
165
#ifndef Q_OS_VXWORKS // no POSIX pipes in VxWorks
166
// don't call ::pipe
167
// call qt_safe_pipe
168
static inline int qt_safe_pipe(int pipefd[2], int flags = 0)
169
{
170
#ifdef O_CLOEXEC
171
    Q_ASSERT((flags & ~(O_CLOEXEC | O_NONBLOCK)) == 0);
172
#else
173
    Q_ASSERT((flags & ~O_NONBLOCK) == 0);
174
#endif
175
176
    register int ret;
177
#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
178
    // use pipe2
179
    flags |= O_CLOEXEC;
180
    ret = ::pipe2(pipefd, flags); // pipe2 is Linux-specific and is documented not to return EINTR
181
    if (ret == 0 || errno != ENOSYS)
182
        return ret;
183
#endif
184
185
    ret = ::pipe(pipefd);
186
    if (ret == -1)
187
        return -1;
188
189
    ::fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);
190
    ::fcntl(pipefd[1], F_SETFD, FD_CLOEXEC);
191
192
    // set non-block too?
193
    if (flags & O_NONBLOCK) {
194
        ::fcntl(pipefd[0], F_SETFL, ::fcntl(pipefd[0], F_GETFL) | O_NONBLOCK);
195
        ::fcntl(pipefd[1], F_SETFL, ::fcntl(pipefd[1], F_GETFL) | O_NONBLOCK);
196
    }
197
198
    return 0;
199
}
200
201
#endif // Q_OS_VXWORKS
202
203
// don't call dup or fcntl(F_DUPFD)
204
static inline int qt_safe_dup(int oldfd, int atleast = 0, int flags = FD_CLOEXEC)
205
{
206
    Q_ASSERT(flags == FD_CLOEXEC || flags == 0);
207
208
    register int ret;
209
#ifdef F_DUPFD_CLOEXEC
210
    // use this fcntl
211
    if (flags & FD_CLOEXEC) {
212
        ret = ::fcntl(oldfd, F_DUPFD_CLOEXEC, atleast);
213
        if (ret != -1 || errno != EINVAL)
214
            return ret;
215
    }
216
#endif
217
218
    // use F_DUPFD
219
    ret = ::fcntl(oldfd, F_DUPFD, atleast);
220
221
    if (flags && ret != -1)
222
        ::fcntl(ret, F_SETFD, flags);
223
    return ret;
224
}
225
226
// don't call dup2
227
// call qt_safe_dup2
228
static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC)
229
{
230
    Q_ASSERT(flags == FD_CLOEXEC || flags == 0);
231
232
    register int ret;
233
#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
234
    // use dup3
235
    if (flags & FD_CLOEXEC) {
236
        EINTR_LOOP(ret, ::dup3(oldfd, newfd, O_CLOEXEC));
237
        if (ret == 0 || errno != ENOSYS)
238
            return ret;
239
    }
240
#endif
241
    EINTR_LOOP(ret, ::dup2(oldfd, newfd));
242
    if (ret == -1)
243
        return -1;
244
245
    if (flags)
246
        ::fcntl(newfd, F_SETFD, flags);
247
    return 0;
248
}
249
250
static inline qint64 qt_safe_read(int fd, void *data, qint64 maxlen)
251
{
252
    qint64 ret = 0;
253
    EINTR_LOOP(ret, QT_READ(fd, data, maxlen));
254
    return ret;
255
}
256
#undef QT_READ
257
#define QT_READ qt_safe_read
258
259
static inline qint64 qt_safe_write(int fd, const void *data, qint64 len)
260
{
261
    qint64 ret = 0;
262
    EINTR_LOOP(ret, QT_WRITE(fd, data, len));
263
    return ret;
264
}
265
#undef QT_WRITE
266
#define QT_WRITE qt_safe_write
267
268
static inline int qt_safe_close(int fd)
269
{
270
    register int ret;
271
    EINTR_LOOP(ret, QT_CLOSE(fd));
272
    return ret;
273
}
274
#undef QT_CLOSE
275
#define QT_CLOSE qt_safe_close
276
277
// - Open C does not (yet?) implement these on Symbian OS
278
// - VxWorks doesn't have processes
279
#if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_VXWORKS)
280
static inline int qt_safe_execve(const char *filename, char *const argv[],
281
                                 char *const envp[])
282
{
283
    register int ret;
284
    EINTR_LOOP(ret, ::execve(filename, argv, envp));
285
    return ret;
286
}
287
288
static inline int qt_safe_execv(const char *path, char *const argv[])
289
{
290
    register int ret;
291
    EINTR_LOOP(ret, ::execv(path, argv));
292
    return ret;
293
}
294
295
static inline int qt_safe_execvp(const char *file, char *const argv[])
296
{
297
    register int ret;
298
    EINTR_LOOP(ret, ::execvp(file, argv));
299
    return ret;
300
}
301
#endif
302
303
#ifndef Q_OS_VXWORKS // no processes on VxWorks
304
static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options)
305
{
306
    register int ret;
307
    EINTR_LOOP(ret, ::waitpid(pid, status, options));
308
    return ret;
309
}
310
311
#endif // Q_OS_VXWORKS
312
313
#if !defined(_POSIX_MONOTONIC_CLOCK)
314
#  define _POSIX_MONOTONIC_CLOCK -1
315
#endif
316
317
timeval qt_gettime(); // in qelapsedtimer_mac.cpp or qtimestamp_unix.cpp
318
319
Q_CORE_EXPORT int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
320
                                 const struct timeval *tv);
321
322
// according to X/OPEN we have to define semun ourselves
323
// we use prefix as on some systems sem.h will have it
324
struct semid_ds;
325
union qt_semun {
326
    int val;                    /* value for SETVAL */
327
    struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
328
    unsigned short *array;      /* array for GETALL, SETALL */
329
};
330
331
QT_END_NAMESPACE
332
333
#endif