GCC Code Coverage Report


Directory: src/gate/
File: src/gate/platform_posix.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 250 642 38.9%
Functions: 37 59 62.7%
Branches: 74 327 22.6%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28 #include "gate/platforms.h"
29
30 #if defined(GATE_SYS_POSIX) && !defined(GATE_SYS_BEOS)
31
32 #define __USE_GNU
33 #include <unistd.h>
34 #include <sys/time.h>
35 #include <time.h>
36 #if defined(GATE_SYS_ANDROID) || defined(GATE_SYS_BEOS)
37 # define GATE_SYS_USE_POSIX_SEMAPHORE
38 #endif
39
40 #if defined(HAVE_SEMTIMEDOP)
41 # define _GNU_SOURCE
42 # include <sys/sem.h>
43 #endif
44
45 #include <sys/ipc.h>
46 #include <sys/types.h>
47 #include <errno.h>
48 #include <pthread.h>
49 #include <sched.h>
50 #if defined(GATE_SYS_USE_POSIX_SEMAPHORE)
51 # include <fcntl.h>
52 # include <semaphore.h>
53 #else
54 # include <sys/shm.h>
55 # include <sys/sem.h>
56 #endif
57
58 #include <stdlib.h>
59 #include <stdarg.h>
60 #include <string.h>
61 #include <sys/stat.h>
62 #include <sys/ioctl.h>
63 #include <sys/wait.h>
64 #include <sys/file.h>
65 #include <fcntl.h>
66 #include <pwd.h>
67 #include <grp.h>
68 #include <signal.h>
69 #include <sys/select.h>
70 #include <dlfcn.h>
71
72 #include "gate/results.h"
73 #include "gate/atomics.h"
74 #include "gate/debugging.h"
75 #include "gate/strings.h"
76
77 #if defined(GATE_SYS_ANDROID)
78 # define GATE_SYS_POSIX_HAS_FLOCK
79 #else
80 # define GATE_SYS_POSIX_HAS_FLOCK
81 # define GATE_SYS_POSIX_HAS_LOCKF
82 #endif
83
84 static gate_atomic_int_t global_platform_mutex_usable = 0;
85 static gate_atomic_lock_t global_platform_mutex_init_lock = GATE_ATOMIC_LOCK_INIT;
86
87 static gate_atomic_flag_t global_platform_mutex_init_done = GATE_ATOMIC_FLAG_INIT;
88 static pthread_mutex_t global_platform_mutex;
89
90 168 static gate_result_t global_platform_mutex_init()
91 {
92 168 gate_result_t ret = GATE_RESULT_OK;
93 168 const gate_int32_t init_state = gate_atomic_int_get(&global_platform_mutex_usable);
94
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 152 times.
168 if (0 == init_state)
95 {
96 16 gate_atomic_lock_acquire(&global_platform_mutex_init_lock);
97 {
98
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 if (!gate_atomic_flag_set(&global_platform_mutex_init_done))
99 {
100
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if (0 != pthread_mutex_init(&global_platform_mutex, NULL))
101 {
102 ret = GATE_RESULT_FAILED;
103 gate_atomic_flag_clear(&global_platform_mutex_init_done);
104 }
105 else
106 {
107 16 gate_atomic_int_set(&global_platform_mutex_usable, 1);
108 }
109 }
110 }
111 16 gate_atomic_lock_release(&global_platform_mutex_init_lock);
112 }
113 168 return ret;
114 }
115
116 16 gate_result_t gate_platform_init(void)
117 {
118 16 gate_result_t ret = GATE_RESULT_OK;
119
120 16 global_platform_mutex_init();
121
122 16 return ret;
123 }
124
125 void gate_platform_exit(int exit_code)
126 {
127 exit(exit_code);
128 }
129
130 4 void gate_platform_atexit(void(*func)(void))
131 {
132 4 atexit(func);
133 4 }
134
135 76 gate_result_t gate_platform_lock()
136 {
137 76 gate_result_t ret = global_platform_mutex_init();
138
1/2
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
76 if (GATE_SUCCEEDED(ret))
139 {
140
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
76 if (0 != pthread_mutex_lock(&global_platform_mutex))
141 {
142 ret = GATE_RESULT_FAILED;
143 }
144 }
145 76 return ret;
146 }
147 76 gate_result_t gate_platform_unlock()
148 {
149 76 gate_result_t ret = global_platform_mutex_init();
150
1/2
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
76 if (GATE_SUCCEEDED(ret))
151 {
152
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
76 if (0 != pthread_mutex_unlock(&global_platform_mutex))
153 {
154 ret = GATE_RESULT_FAILED;
155 }
156 }
157 76 return ret;
158 }
159 23 gate_int32_t gate_platform_get_last_error()
160 {
161 23 return (gate_int32_t)errno;
162 }
163 gate_result_t gate_platform_set_last_error(gate_int32_t platform_error_code)
164 {
165 gate_result_t ret = GATE_RESULT_OK;
166 errno = (int)platform_error_code;
167 return ret;
168 }
169
170 15 static gate_result_t gate_posix_convert_errno(int error_code)
171 {
172 15 gate_result_t ret = GATE_RESULT_FAILED;
173
174
3/75
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✓ Branch 27 taken 1 times.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✓ Branch 43 taken 12 times.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
15 switch (error_code)
175 {
176 case 0: ret = GATE_RESULT_OK; break;
177 case E2BIG: ret = GATE_RESULT_OUTOFBOUNDS; break;
178 case EACCES: ret = GATE_RESULT_ACCESSDENIED; break;
179 case EADDRINUSE: ret = GATE_RESULT_NOTREADY; break;
180 case EADDRNOTAVAIL: ret = GATE_RESULT_NOTAVAILABLE; break;
181 case EAFNOSUPPORT: ret = GATE_RESULT_NOTSUPPORTED; break;
182 /*case EWOULDBLOCK: ret = GATE_RESULT_BLOCKED; break;*/
183 case EAGAIN: ret = GATE_RESULT_BLOCKED; break;
184 case EALREADY: ret = GATE_RESULT_ALREADYEXISTS; break;
185 2 case EBADF: ret = GATE_RESULT_INVALIDDATA; break;
186 case EBADMSG: ret = GATE_RESULT_INVALIDCONTENT; break;
187 case EBUSY: ret = GATE_RESULT_NOTREADY; break;
188 case ECANCELED: ret = GATE_RESULT_CANCELED; break;
189 case ECHILD: ret = GATE_RESULT_EXECUTIONFAILED; break;
190 case ECONNABORTED: ret = GATE_RESULT_CANCELED; break;
191 case ECONNREFUSED: ret = GATE_RESULT_ACCESSDENIED; break;
192 case ECONNRESET: ret = GATE_RESULT_INVALIDSTATE; break;
193 case EDEADLK: ret = GATE_RESULT_LOCKED; break;
194 case EDESTADDRREQ: ret = GATE_RESULT_INVALIDDATA; break;
195 case EDOM: ret = GATE_RESULT_ARITHMETICERROR; break;
196 /*case EDQUOT: ret = GATE_RESULT_FAILED; break;*/
197 case EEXIST: ret = GATE_RESULT_ALREADYEXISTS; break;
198 case EFAULT: ret = GATE_RESULT_BADADDRESS; break;
199 case EFBIG: ret = GATE_RESULT_OUTOFBOUNDS; break;
200 case EHOSTUNREACH: ret = GATE_RESULT_NOTAVAILABLE; break;
201 case EIDRM: ret = GATE_RESULT_NOTAVAILABLE; break;
202 case EILSEQ: ret = GATE_RESULT_INVALIDDATA; break;
203 case EINPROGRESS: ret = GATE_RESULT_LOCKED; break;
204 case EINTR: ret = GATE_RESULT_EXECUTIONINTERRUPTED; break;
205 1 case EINVAL: ret = GATE_RESULT_INVALIDARG; break;
206 case EIO: ret = GATE_RESULT_INVALIDDATA; break;
207 case EISCONN: ret = GATE_RESULT_INVALIDSTATE; break;
208 case EISDIR: ret = GATE_RESULT_INVALIDSTATE; break;
209 case ELOOP: ret = GATE_RESULT_OUTOFRESOURCES; break;
210 case EMFILE: ret = GATE_RESULT_OUTOFRESOURCES; break;
211 case EMLINK: ret = GATE_RESULT_OUTOFRESOURCES; break;
212 case EMSGSIZE: ret = GATE_RESULT_OUTOFBOUNDS; break;
213 /*case EMULTIHOP: ret = GATE_RESULT_FAILED; break;*/
214 case ENAMETOOLONG: ret = GATE_RESULT_OUTOFBOUNDS; break;
215 case ENETDOWN: ret = GATE_RESULT_NOTAVAILABLE; break;
216 case ENETRESET: ret = GATE_RESULT_CANCELED; break;
217 case ENETUNREACH: ret = GATE_RESULT_NOTAVAILABLE; break;
218 case ENFILE: ret = GATE_RESULT_OUTOFRESOURCES; break;
219 case ENOBUFS: ret = GATE_RESULT_OUTOFMEMORY; break;
220 #ifdef ENODATA
221 case ENODATA: ret = GATE_RESULT_INVALIDCONTENT; break;
222 #endif
223 case ENODEV: ret = GATE_RESULT_NOTAVAILABLE; break;
224 12 case ENOENT: ret = GATE_RESULT_NOTAVAILABLE; break;
225 case ENOEXEC: ret = GATE_RESULT_INVALIDHEADER; break;
226 case ENOLCK: ret = GATE_RESULT_NOTAVAILABLE; break;
227 /*case ENOLINK: ret = GATE_RESULT_; break;*/
228 case ENOMEM: ret = GATE_RESULT_OUTOFMEMORY; break;
229 case ENOMSG: ret = GATE_RESULT_OUTOFRESOURCES; break;
230 case ENOPROTOOPT: ret = GATE_RESULT_NOTAVAILABLE; break;
231 case ENOSPC: ret = GATE_RESULT_OUTOFRESOURCES; break;
232 #ifdef ENOSR
233 case ENOSR: ret = GATE_RESULT_NOTAVAILABLE; break;
234 #endif
235 #ifdef ENOSTR
236 case ENOSTR: ret = GATE_RESULT_NOTAVAILABLE; break;
237 #endif
238 case ENOSYS: ret = GATE_RESULT_NOTSUPPORTED; break;
239 case ENOTCONN: ret = GATE_RESULT_INVALIDSTATE; break;
240 case ENOTDIR: ret = GATE_RESULT_INVALIDSTATE; break;
241 case ENOTEMPTY: ret = GATE_RESULT_INVALIDSTATE; break;
242 case ENOTSOCK: ret = GATE_RESULT_INCORRECTTYPE; break;
243 case ENOTSUP: ret = GATE_RESULT_NOTSUPPORTED; break;
244 case ENOTTY: ret = GATE_RESULT_INCORRECTTYPE; break;
245 case ENXIO: ret = GATE_RESULT_NOTAVAILABLE; break;
246 case EOVERFLOW: ret = GATE_RESULT_OVERFLOW; break;
247 case EPERM: ret = GATE_RESULT_PERMISSIONDENIED; break;
248 case EPIPE: ret = GATE_RESULT_NOTREADY; break;
249 case EPROTO: ret = GATE_RESULT_INVALIDDATA; break;
250 case EPROTONOSUPPORT: ret = GATE_RESULT_NOTSUPPORTED; break;
251 case EPROTOTYPE: ret = GATE_RESULT_INCORRECTTYPE; break;
252 case ERANGE: ret = GATE_RESULT_OUTOFBOUNDS; break;
253 case EROFS: ret = GATE_RESULT_LOCKED; break;
254 case ESPIPE: ret = GATE_RESULT_INVALIDARG; break;
255 case ESRCH: ret = GATE_RESULT_NOMATCH; break;
256 /*case ESTALE: ret = GATE_RESULT_FAILED; break;*/
257 #ifdef ETIME
258 case ETIME: ret = GATE_RESULT_TIMEOUT; break;
259 #endif
260 case ETIMEDOUT: ret = GATE_RESULT_TIMEOUT; break;
261 case ETXTBSY: ret = GATE_RESULT_NOTREADY; break;
262 case EXDEV: ret = GATE_RESULT_NOTSUPPORTED; break;
263 default: ret = GATE_RESULT_FAILED; break;
264 }
265 15 return ret;
266 }
267
268 gate_result_t gate_platform_print_error(gate_int32_t platform_error_code, char* buffer, gate_size_t buffer_len)
269 {
270 gate_result_t result;
271 char* error_text = NULL;
272
273 if ((buffer != NULL) && (buffer_len != 0))
274 {
275 result = gate_platform_lock();
276 if (GATE_SUCCEEDED(result))
277 {
278 error_text = strerror((int)platform_error_code);
279 gate_str_print_text(buffer, buffer_len, error_text, gate_str_length(error_text));
280 gate_platform_unlock();
281 }
282 }
283 return gate_posix_convert_errno(platform_error_code);
284 }
285
286 17 int gate_posix_errno(gate_result_t* result)
287 {
288 17 int ret = errno;
289
290
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 2 times.
17 if (result != NULL)
291 {
292 15 *result = gate_posix_convert_errno(ret);
293 }
294 17 return ret;
295 }
296 void gate_posix_set_errno(int code)
297 {
298 errno = code;
299 }
300
301
302 28 gate_posix_sigblocker_t gate_posix_block_signals(int sig1, int sig2, ...)
303 {
304 gate_posix_sigblocker_t ret;
305 int arg;
306 va_list args;
307
308 28 sigemptyset(&ret.signals);
309 28 sigaddset(&ret.signals, sig1);
310
311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (sig2 != 0)
312 {
313 sigaddset(&ret.signals, sig2);
314 va_start(args, sig2);
315 while (0 != (arg = va_arg(args, int)))
316 {
317 sigaddset(&ret.signals, arg);
318 }
319 va_end(args);
320 }
321 28 ret.unblock_required = (pthread_sigmask(SIG_BLOCK, &ret.signals, &ret.signals) == 0);
322 28 return ret;
323 }
324
325 28 void gate_posix_unblock_signals(gate_posix_sigblocker_t blocker)
326 {
327
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (blocker.unblock_required)
328 {
329 28 pthread_sigmask(SIG_SETMASK, &blocker.signals, 0);
330 }
331 28 }
332
333 static int gate_posix_inheritable_fds[1024];
334 static gate_size_t gate_posix_inheritable_fd_count = 0;
335 static gate_atomic_lock_t gate_posix_inheritable_lock = GATE_ATOMIC_LOCK_INIT;
336
337 gate_result_t gate_posix_register_inheritable_fd(int fd)
338 {
339 gate_size_t ndx;
340 gate_atomic_lock_acquire(&gate_posix_inheritable_lock);
341
342 for (ndx = 0; ndx != gate_posix_inheritable_fd_count; ++ndx)
343 {
344 if (gate_posix_inheritable_fds[ndx] == fd)
345 {
346 --gate_posix_inheritable_fd_count;
347 break;
348 }
349 }
350 gate_posix_inheritable_fds[ndx] = fd;
351 ++gate_posix_inheritable_fd_count;
352
353 gate_atomic_lock_release(&gate_posix_inheritable_lock);
354 return GATE_RESULT_OK;
355 }
356 gate_result_t gate_posix_unregister_inheritable_fd(int fd)
357 {
358 gate_result_t ret = GATE_RESULT_NOMATCH;
359 gate_size_t ndx;
360
361 gate_atomic_lock_acquire(&gate_posix_inheritable_lock);
362 if (gate_posix_inheritable_fd_count != 0)
363 {
364 for (ndx = 0; ndx < gate_posix_inheritable_fd_count; ++ndx)
365 {
366 if (gate_posix_inheritable_fds[ndx] == fd)
367 {
368 gate_posix_inheritable_fds[ndx] = gate_posix_inheritable_fds[gate_posix_inheritable_fd_count - 1];
369 --gate_posix_inheritable_fd_count;
370 ret = GATE_RESULT_OK;
371 break;
372 }
373 }
374 }
375 gate_atomic_lock_release(&gate_posix_inheritable_lock);
376
377 return ret;
378 }
379 2 gate_size_t gate_posix_get_inheritable_fds(int* fdbuffer, gate_size_t fdbuffer_length)
380 {
381 2 gate_size_t used = 0;
382 2 gate_size_t ndx = 0;
383
384 2 gate_atomic_lock_acquire(&gate_posix_inheritable_lock);
385 2 used = fdbuffer_length < gate_posix_inheritable_fd_count ? fdbuffer_length : gate_posix_inheritable_fd_count;
386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 for (ndx = 0; ndx != used; ++ndx)
387 {
388 *fdbuffer = gate_posix_inheritable_fds[ndx];
389 ++fdbuffer;
390 }
391
392 2 gate_atomic_lock_release(&gate_posix_inheritable_lock);
393 2 return used;
394 }
395
396
397 6 int gate_posix_open(char const* path, int oflag, int mode)
398 {
399 6 return open(path, oflag, (mode_t)mode);
400 }
401 2097158 int gate_posix_close(int fd)
402 {
403 2097158 return close(fd);
404 }
405 11 ptrdiff_t gate_posix_read(int fd, void* buf, size_t nbyte)
406 {
407 ptrdiff_t result;
408 do
409 {
410 11 result = (ptrdiff_t)read(fd, buf, nbyte);
411
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
11 } while ((result == -1) && (errno == EINTR));
412 11 return result;
413 }
414 23 ptrdiff_t gate_posix_write(int fd, void const* buf, size_t nbyte)
415 {
416 ptrdiff_t result;
417 do
418 {
419 23 result = (ptrdiff_t)write(fd, buf, nbyte);
420
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
23 } while ((result == -1) && (errno == EINTR));
421 23 return result;
422 }
423 5 gate_result_t gate_posix_await_read(int fd, gate_uint32_t timeout_ms)
424 {
425 fd_set read_set;
426 struct timeval timeout;
427
428
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 if (timeout_ms != 0xffffffff)
429 {
430 3 timeout.tv_sec = timeout_ms / 1000;
431 3 timeout.tv_usec = (timeout_ms % 1000) * 1000;
432 }
433 else
434 {
435 2 timeout.tv_sec = 0x7fffffff;
436 2 timeout.tv_usec = 0;
437 }
438
439 5 FD_ZERO(&read_set);
440 5 FD_SET(fd, &read_set);
441
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (-1 == select(fd + 1, &read_set, NULL, NULL, &timeout))
442 {
443 return GATE_RESULT_FAILED;
444 }
445
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!FD_ISSET(fd, &read_set))
447 {
448 return GATE_RESULT_TIMEOUT;
449 }
450 else
451 {
452 5 return GATE_RESULT_OK;
453 }
454 }
455
456
457 int gate_posix_flock(int fd, gate_posix_flock_operation operation)
458 {
459 #if defined(GATE_SYS_POSIX_HAS_FLOCK)
460 /* standard flock implemenation: */
461 int result;
462 int op;
463 switch (operation)
464 {
465 case gate_posix_flock_shared: op = LOCK_SH; break;
466 case gate_posix_flock_exclusive: op = LOCK_EX; break;
467 case gate_posix_flock_exclusive_test: op = (LOCK_EX | LOCK_NB); break;
468 case gate_posix_flock_unlock: op = LOCK_UN; break;
469 default:
470 gate_posix_set_errno(EINVAL);
471 return -1;
472 }
473
474 do
475 {
476 result = flock(fd, op);
477 } while ((result == -1) && (errno == EINTR));
478 return result;
479 #elif defined(GATE_SYS_POSIX_HAS_LOCKF)
480 /* flock emulation using lockf for the whole file */
481 int result;
482 gate_posix_lockf_cmd op;
483
484 switch (operation)
485 {
486 case gate_posix_flock_exclusive: op = gate_posix_lockf_lock; break;
487 case gate_posix_flock_exclusive_test: op = gate_posix_lockf_test; break;
488 case gate_posix_flock_unlock: op = gate_posix_lockf_unlock; break;
489 default:
490 gate_posix_set_errno(EINVAL);
491 return -1;
492 }
493
494 do
495 {
496 result = gate_posix_lockf(fd, op, 0, 0);
497 } while ((result == -1) && (errno == EINTR));
498 return result;
499 #else
500 /* no flock support at all */
501 gate_posix_set_errno(EACCES);
502 return -1;
503 #endif
504 }
505
506
507 int gate_posix_lockf(int fd, gate_posix_lockf_cmd cmd, gate_int64_t start_from, gate_int64_t length)
508 {
509 #if defined(GATE_SYS_POSIX_HAS_LOCKF)
510 /* standard lockf implementation */
511 int ret;
512 off_t current_pos;
513 int lock_cmd;
514 int stored_error;
515
516 do
517 {
518 switch (cmd)
519 {
520 case gate_posix_lockf_lock: lock_cmd = F_LOCK; break;
521 case gate_posix_lockf_testlock: lock_cmd = F_TLOCK; break;
522 case gate_posix_lockf_unlock: lock_cmd = F_ULOCK; break;
523 case gate_posix_lockf_test: lock_cmd = F_TEST; break;
524 default:
525 {
526 gate_posix_set_errno(EINVAL);
527 return -1;
528 }
529 }
530
531 current_pos = lseek(fd, 0, SEEK_CUR);
532 if (current_pos == (off_t)-1)
533 {
534 ret = -1;
535 break;
536 }
537 if (lseek(fd, (off_t)start_from, SEEK_SET) == (off_t)-1)
538 {
539 ret = -1;
540 break;
541 }
542
543 ret = lockf(fd, lock_cmd, (off_t)length);
544 stored_error = errno;
545
546 lseek(fd, (off_t)current_pos, SEEK_SET);
547 errno = stored_error;
548 } while (0);
549 return ret;
550 #elif defined(GATE_SYS_POSIX_HAS_FLOCK)
551 /* partially simulate lockf by locking the whole file with flock */
552 int ret = -1;
553 do
554 {
555 switch (cmd)
556 {
557 case gate_posix_lockf_lock:
558 {
559 ret = gate_posix_flock(fd, gate_posix_flock_exclusive);
560 break;
561 }
562 case gate_posix_lockf_unlock:
563 {
564 ret = gate_posix_flock(fd, gate_posix_flock_unlock);
565 break;
566 }
567 case gate_posix_lockf_testlock:
568 /* TODO: LOCK_NB implementation */
569 default:
570 {
571 gate_posix_set_errno(EINVAL);
572 return -1;
573 }
574 }
575 } while (0);
576 return ret;
577 #else
578 /* no lockf support at all */
579 gate_posix_set_errno(EACCES);
580 return -1;
581 #endif
582 }
583
584
585 int gate_posix_ioctl(int fd, unsigned long request, void* param)
586 {
587 return ioctl(fd, request, param);
588 }
589 4 gate_bool_t gate_posix_path_exists(char const* path)
590 {
591 struct stat filestat;
592
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (0 == stat(path, &filestat))
593 {
594 4 return true;
595 }
596 return false;
597 }
598
599 #if defined(GATE_SYS_ANDROID)
600 gate_size_t gate_posix_enum_users(uid_t* uids, gate_size_t max_uids)
601 {
602 return 0;
603 }
604 gate_result_t gate_posix_get_user_info(uid_t uid, gate_posix_user_info_t* info)
605 {
606 return GATE_RESULT_NOMATCH;
607 }
608 gate_result_t gate_posix_resolve_user_info(char const* user_name, gate_posix_user_info_t* info)
609 {
610 return GATE_RESULT_NOMATCH;
611 }
612 gate_size_t gate_posix_enum_groups(gid_t* gids, gate_size_t max_gids)
613 {
614 return 0;
615 }
616 gate_result_t gate_posix_get_usergroup_info(gid_t gid, gate_posix_group_info_t* info)
617 {
618 return GATE_RESULT_NOMATCH;
619 }
620 gate_result_t gate_posix_resolve_usergroup_info(char const* group_name, gate_posix_group_info_t* info)
621 {
622 return GATE_RESULT_NOMATCH;
623 }
624 #else
625
626
627 1 gate_size_t gate_posix_enum_users(uid_t* uids, gate_size_t max_uids)
628 {
629 struct passwd* entry;
630 1 gate_size_t index = 0;
631 gate_result_t result;
632
633 do
634 {
635 1 result = gate_platform_lock();
636
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(result);
637 1 setpwent();
638
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 1 times.
22 while (NULL != (entry = getpwent()))
639 {
640
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 if (index < max_uids)
641 {
642 21 uids[index] = entry->pw_uid;
643 21 ++index;
644 }
645 }
646 1 endpwent();
647 1 gate_platform_unlock();
648 } while (0);
649 1 return index;
650 }
651
652
653
654 29 static void gate_posix_load_user_info(struct passwd const* entry, gate_posix_user_info_t* info)
655 {
656 29 info->uid = entry->pw_uid;
657 29 info->gid = entry->pw_gid;
658 29 gate_str_print_text(info->name, sizeof(info->name), entry->pw_name, gate_str_length(entry->pw_name));
659 29 gate_str_print_text(info->gecos, sizeof(info->gecos), entry->pw_gecos, gate_str_length(entry->pw_gecos));
660 29 gate_str_print_text(info->home, sizeof(info->home), entry->pw_dir, gate_str_length(entry->pw_dir));
661 29 gate_str_print_text(info->shell, sizeof(info->shell), entry->pw_shell, gate_str_length(entry->pw_shell));
662 29 }
663 29 gate_result_t gate_posix_get_user_info(uid_t uid, gate_posix_user_info_t* info)
664 {
665 29 gate_result_t ret = GATE_RESULT_NOMATCH;
666 struct passwd* entry;
667
668 do
669 {
670 29 gate_mem_clear(info, sizeof(gate_posix_user_info_t));
671 29 ret = gate_platform_lock();
672
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 GATE_BREAK_IF_FAILED(ret);
673
674 do
675 {
676 29 entry = getpwuid(uid);
677
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (!entry)
678 {
679 ret = GATE_RESULT_NOMATCH;
680 break;
681 }
682
683 29 gate_posix_load_user_info(entry, info);
684 29 ret = GATE_RESULT_OK;
685 } while (0);
686
687 29 gate_platform_unlock();
688 } while (0);
689 29 return ret;
690 }
691 gate_result_t gate_posix_resolve_user_info(char const* user_name, gate_posix_user_info_t* info)
692 {
693 gate_result_t ret = GATE_RESULT_NOMATCH;
694 struct passwd* entry;
695
696 do
697 {
698 gate_mem_clear(info, sizeof(gate_posix_user_info_t));
699
700 ret = gate_platform_lock();
701 GATE_BREAK_IF_FAILED(ret);
702
703 do
704 {
705 entry = getpwnam(user_name);
706 if (!entry)
707 {
708 ret = GATE_RESULT_NOMATCH;
709 break;
710 }
711
712 gate_posix_load_user_info(entry, info);
713 ret = GATE_RESULT_OK;
714 } while (0);
715
716 gate_platform_unlock();
717 } while (0);
718 return ret;
719 }
720 1 gate_size_t gate_posix_enum_groups(gid_t* gids, gate_size_t max_gids)
721 {
722 struct group* entry;
723 1 gate_size_t index = 0;
724 gate_result_t result;
725
726 do
727 {
728 1 result = gate_platform_lock();
729
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(result);
730
731 1 setgrent();
732
2/2
✓ Branch 1 taken 41 times.
✓ Branch 2 taken 1 times.
42 while (NULL != (entry = getgrent()))
733 {
734
1/2
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
41 if (index < max_gids)
735 {
736 41 gids[index] = entry->gr_gid;
737 41 ++index;
738 }
739 }
740 1 endgrent();
741 1 gate_platform_unlock();
742 } while (0);
743 1 return index;
744 }
745
746 41 static void gate_posix_load_group_info(struct group const* entry, gate_posix_group_info_t* info)
747 {
748 struct passwd const* user_entry;
749 char** ptr;
750 41 gate_size_t max_members = sizeof(info->members) / sizeof(info->members[0]);
751
752 41 info->gid = entry->gr_gid;
753 41 gate_str_print_text(info->name, sizeof(info->name), entry->gr_name, gate_str_length(entry->gr_name));
754 41 ptr = entry->gr_mem;
755
1/2
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
41 if (ptr)
756 {
757
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 while (*ptr)
758 {
759 if (info->members_count >= max_members)
760 {
761 break;
762 }
763 user_entry = getpwnam(*ptr);
764 if (user_entry)
765 {
766 info->members[info->members_count] = user_entry->pw_uid;
767 ++info->members_count;
768 }
769 ++ptr;
770 }
771 }
772 41 }
773
774 41 gate_result_t gate_posix_get_usergroup_info(gid_t gid, gate_posix_group_info_t* info)
775 {
776 41 gate_result_t ret = GATE_RESULT_NOMATCH;
777 struct group const* entry;
778
779 do
780 {
781 41 gate_mem_clear(info, sizeof(gate_posix_group_info_t));
782 41 ret = gate_platform_lock();
783
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 GATE_BREAK_IF_FAILED(ret);
784
785 do
786 {
787 41 entry = getgrgid(gid);
788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (!entry)
789 {
790 ret = GATE_RESULT_NOMATCH;
791 break;
792 }
793
794 41 gate_posix_load_group_info(entry, info);
795 41 ret = GATE_RESULT_OK;
796 } while (0);
797
798 41 gate_platform_unlock();
799 } while (0);
800 41 return ret;
801 }
802 gate_result_t gate_posix_resolve_usergroup_info(char const* group_name, gate_posix_group_info_t* info)
803 {
804 gate_result_t ret = GATE_RESULT_NOMATCH;
805 struct group const* entry;
806 struct passwd const* user_entry;
807 char const** ptr;
808 gate_size_t index;
809 gate_size_t max_members = sizeof(info->members) / sizeof(info->members[0]);
810
811 do
812 {
813 gate_mem_clear(info, sizeof(gate_posix_group_info_t));
814
815 ret = gate_platform_lock();
816 GATE_BREAK_IF_FAILED(ret);
817
818 do
819 {
820 entry = getgrnam(group_name);
821 if (!entry)
822 {
823 ret = GATE_RESULT_NOMATCH;
824 break;
825 }
826
827 gate_posix_load_group_info(entry, info);
828 ret = GATE_RESULT_OK;
829 } while (0);
830
831 gate_platform_unlock();
832 } while (0);
833 return ret;
834 }
835 #endif /* POSIX account info */
836
837
838
839 gate_bool_t gate_platform_stream_valid(gate_platform_stream_t strm)
840 {
841 int fd = (int)(gate_intptr_t)strm;
842 return (fd >= 0);
843 }
844 void gate_platform_stream_set_invalid(gate_platform_stream_t* ptr_strm)
845 {
846 *ptr_strm = (gate_platform_stream_t)(gate_intptr_t)(-1);
847 }
848
849
850 gate_result_t gate_platform_stream_open(char const* path, int open_flags, int native_flags, gate_platform_stream_t* strm)
851 {
852 int openflags = 0;
853 int fd;
854 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
855
856 switch (open_flags)
857 {
858 case GATE_PLATFORM_STREAM_OPEN_READ:
859 {
860 openflags = (O_RDONLY);
861 break;
862 }
863 case GATE_PLATFORM_STREAM_OPEN_WRITE:
864 {
865 openflags = (O_CREAT | O_WRONLY | O_TRUNC);
866 break;
867 }
868 case GATE_PLATFORM_STREAM_OPEN_READWRITE:
869 {
870 openflags = (O_CREAT | O_RDWR);
871 break;
872 }
873 }
874 #ifdef O_CLOEXEC
875 openflags |= O_CLOEXEC;
876 #endif
877
878 fd = open(path, openflags, mode);
879 if (fd < 0)
880 {
881 return gate_platform_print_last_error(NULL, 0);
882 }
883
884 *strm = (gate_platform_stream_t)(gate_intptr_t)fd;
885 return GATE_RESULT_OK;
886 }
887
888 gate_result_t gate_platform_stream_read(gate_platform_stream_t strm, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
889 {
890 gate_result_t ret = GATE_RESULT_FAILED;
891 int fd = (int)(gate_intptr_t)strm;
892 gate_int32_t error_code;
893
894 ptrdiff_t result = gate_posix_read(fd, buffer, bufferlength);
895
896
897 if (result == -1)
898 {
899 error_code = gate_platform_get_last_error();
900 ret = gate_platform_print_error(error_code, NULL, 0);
901 }
902 else
903 {
904 if (returned != NULL)
905 {
906 *returned = (gate_size_t)result;
907 }
908 ret = GATE_RESULT_OK;
909 }
910 return ret;
911 }
912 gate_result_t gate_platform_stream_write(gate_platform_stream_t strm, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
913 {
914 gate_result_t ret = GATE_RESULT_FAILED;
915 int fd = (int)(gate_intptr_t)strm;
916 gate_int32_t error_code;
917
918 ptrdiff_t result = gate_posix_write(fd, buffer, bufferlength);
919
920 if (result == -1)
921 {
922 error_code = gate_platform_get_last_error();
923 ret = gate_platform_print_error(error_code, NULL, 0);
924 }
925 else
926 {
927 if (written != NULL)
928 {
929 *written = (gate_size_t)result;
930 }
931 ret = GATE_RESULT_OK;
932 }
933 return ret;
934 }
935 gate_result_t gate_platform_stream_seek(gate_platform_stream_t strm, gate_int64_t position, int origin, gate_int64_t* final_position)
936 {
937 gate_result_t ret = GATE_RESULT_FAILED;
938 int fd = (int)(gate_intptr_t)strm;
939 gate_int32_t error_code;
940 int whence;
941 off_t result;
942
943 switch (origin)
944 {
945 case GATE_PLATFORM_STREAM_ORIGIN_BEGIN:
946 whence = SEEK_SET;
947 break;
948 case GATE_PLATFORM_STREAM_ORIGIN_CURRENT:
949 whence = SEEK_CUR;
950 break;
951 case GATE_PLATFORM_STREAM_ORIGIN_END:
952 whence = SEEK_END;
953 break;
954 default:
955 return GATE_RESULT_INVALIDARG;
956 }
957
958 result = lseek(fd, (off_t)position, whence);
959 if (result == (off_t)-1)
960 {
961 error_code = gate_platform_get_last_error();
962 ret = gate_platform_print_error(error_code, NULL, 0);
963 }
964 else
965 {
966 if (final_position != NULL)
967 {
968 *final_position = (gate_int64_t)result;
969 }
970 ret = GATE_RESULT_OK;
971 }
972 return ret;
973 }
974
975 gate_result_t gate_platform_stream_close(gate_platform_stream_t* strm)
976 {
977 gate_result_t ret = GATE_RESULT_OK;
978 if (strm != NULL)
979 {
980 if ((int)(gate_intptr_t)*strm != -1)
981 {
982 close((int)(gate_intptr_t)*strm);
983 *strm = (gate_platform_stream_t)(gate_intptr_t)-1;
984 }
985 }
986 return ret;
987 }
988
989 21 int gate_platform_convert_gate_signal(int gate_platform_signal)
990 {
991
1/7
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 21 times.
21 switch (gate_platform_signal)
992 {
993 case GATE_PLATFORM_SIGNAL_ABRT: return SIGABRT;
994 case GATE_PLATFORM_SIGNAL_FPE: return SIGFPE;
995 case GATE_PLATFORM_SIGNAL_ILL: return SIGILL;
996 case GATE_PLATFORM_SIGNAL_INT: return SIGINT;
997 case GATE_PLATFORM_SIGNAL_SEGV: return SIGSEGV;
998 case GATE_PLATFORM_SIGNAL_TERM: return SIGTERM;
999 21 default: return gate_platform_signal;
1000 }
1001 }
1002 int gate_platform_convert_native_signal(int native_signal)
1003 {
1004 switch (native_signal)
1005 {
1006 case SIGABRT: return GATE_PLATFORM_SIGNAL_ABRT;
1007 case SIGFPE: return GATE_PLATFORM_SIGNAL_FPE;
1008 case SIGILL: return GATE_PLATFORM_SIGNAL_ILL;
1009 case SIGINT: return GATE_PLATFORM_SIGNAL_INT;
1010 case SIGSEGV: return GATE_PLATFORM_SIGNAL_SEGV;
1011 case SIGTERM: return GATE_PLATFORM_SIGNAL_TERM;
1012 default: return native_signal;
1013 }
1014 }
1015
1016
1017 21 gate_result_t gate_platform_set_signal_handler(int sig,
1018 gate_platform_signal_handler_t new_handler,
1019 gate_platform_signal_handler_t* ptr_old_handler)
1020 {
1021 gate_platform_signal_handler_t ret;
1022 21 int native_signal = gate_platform_convert_gate_signal(sig);
1023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (native_signal == 0)
1024 {
1025 return GATE_RESULT_NOTSUPPORTED;
1026 }
1027 21 ret = signal(native_signal, new_handler);
1028
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (SIG_ERR == ret)
1029 {
1030 return GATE_RESULT_FAILED;
1031 }
1032 else
1033 {
1034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (ptr_old_handler)
1035 {
1036 *ptr_old_handler = ret;
1037 }
1038 21 return GATE_RESULT_OK;
1039 }
1040 }
1041
1042 gate_result_t gate_platform_raise_signal(int sig)
1043 {
1044 gate_result_t ret = GATE_RESULT_FAILED;
1045 int result;
1046 int native_signal = gate_platform_convert_gate_signal(sig);
1047 if (native_signal == 0)
1048 {
1049 return GATE_RESULT_NOTSUPPORTED;
1050 }
1051
1052 result = raise(native_signal);
1053 if (result == 0)
1054 {
1055 ret = GATE_RESULT_OK;
1056 }
1057 else
1058 {
1059 gate_posix_errno(&ret);
1060 }
1061 return ret;
1062 }
1063
1064 gate_result_t gate_posix_daemonize(pid_t* ptr_pid)
1065 {
1066 pid_t child_pid;
1067 pid_t daemon_pid;
1068 int fd[2];
1069 int result;
1070 ssize_t transferred;
1071 int daemon_fd;
1072
1073 result = pipe(fd);
1074 if (result < 0)
1075 {
1076 /* failed to create communication pipe */
1077 GATE_DEBUG_TRACE("daemonize: failed to create pipes");
1078 return GATE_RESULT_OUTOFRESOURCES;
1079 }
1080
1081 child_pid = fork();
1082
1083 if (child_pid < 0)
1084 {
1085 GATE_DEBUG_TRACE("daemonize: initial fork() failed");
1086 return GATE_RESULT_FAILED;
1087 }
1088
1089 if (child_pid > 0)
1090 {
1091 /* caller branch hosting the dispatcher */
1092 close(fd[1]); /* close the remote write-end */
1093 transferred = read(fd[0], &daemon_pid, sizeof(daemon_pid));
1094 close(fd[0]); /* close the local read-end */
1095 waitpid(child_pid, NULL, 0);
1096 if (transferred != sizeof(daemon_pid))
1097 {
1098 /* could not retrieve daemon-PID -> failed to create daemon */
1099 GATE_DEBUG_TRACE("daemonize: waitpid() completed - NO PID - failed");
1100 return GATE_RESULT_FAILED;
1101 }
1102
1103 GATE_DEBUG_TRACE("daemonize: waitpid() completed - PID received");
1104 GATE_DEBUG_TRACE_VALUE(daemon_pid);
1105 if (ptr_pid)
1106 {
1107 *ptr_pid = daemon_pid;
1108 }
1109 /* notify the caller, that the daemon process is running */
1110 return GATE_RESULT_OK;
1111 }
1112
1113 /* dispatcher child process */
1114 close(fd[0]); /* close read side of pipe*/
1115
1116 result = setsid();
1117 if (result < 0)
1118 {
1119 GATE_DEBUG_TRACE("daemonize: setsid() failed");
1120 _exit(1);
1121 }
1122
1123 signal(SIGHUP, SIG_IGN);
1124
1125 /* 2nd fork: */
1126 daemon_pid = fork();
1127 if (daemon_pid < 0)
1128 {
1129 GATE_DEBUG_TRACE("daemonize: final fork() failed");
1130 _exit(2);
1131 }
1132
1133 if (daemon_pid > 0)
1134 {
1135 /* dispatcher has retrieved the final daemon child PID: */
1136
1137 /* send daemon-PID to parent process */
1138 GATE_DEBUG_TRACE("daemonize: send daemon PID back to parent process");
1139 GATE_DEBUG_TRACE_VALUE(daemon_pid);
1140 transferred = write(fd[1], &daemon_pid, sizeof(daemon_pid));
1141 close(fd[1]); /* close write end */
1142 if (transferred == sizeof(daemon_pid))
1143 {
1144 GATE_DEBUG_TRACE("daemonize: dispatcher process succeeded");
1145 _exit(0); /* terminate dispatcher with success state */
1146 }
1147 else
1148 {
1149 GATE_DEBUG_TRACE("daemonize: dispatcher process failed");
1150 _exit(3); /* terminate dispatcher with error state*/
1151 }
1152 return GATE_RESULT_CRITICALERROR; /* this point should never be reached */
1153 }
1154
1155 /* this is the daemonized branch */
1156 GATE_DEBUG_TRACE("daemonize: daemon branch reached");
1157
1158 close(fd[1]); /* close write end */
1159
1160 /* prepare daemon environment */
1161 result = chdir("/");
1162 umask(0);
1163
1164 /* assign STDIN/OUT/ERR to null device: */
1165 daemon_fd = open("/dev/null", O_RDONLY);
1166 if ((daemon_fd != -1) && (daemon_fd != STDIN_FILENO))
1167 {
1168 dup2(daemon_fd, STDIN_FILENO);
1169 close(daemon_fd);
1170 }
1171
1172 daemon_fd = open("/dev/null", O_WRONLY);
1173 if (daemon_fd != -1)
1174 {
1175 if (daemon_fd != STDOUT_FILENO)
1176 {
1177 dup2(daemon_fd, STDOUT_FILENO);
1178 }
1179 if (daemon_fd != STDERR_FILENO)
1180 {
1181 dup2(daemon_fd, STDERR_FILENO);
1182 }
1183 close(daemon_fd);
1184 }
1185
1186 if (ptr_pid)
1187 {
1188 *ptr_pid = 0; /* mark as daemon-branch */
1189 }
1190 return GATE_RESULT_OK;
1191 }
1192
1193 7 void* gate_posix_dlopen(char const* libpath, int flags)
1194 {
1195 void* ret;
1196 7 dlerror(); /* clear previous error state */
1197 7 ret = dlopen(libpath, flags);
1198
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (NULL == ret)
1199 {
1200 3 char* last_errmsg = dlerror();
1201 3 GATE_DEBUG_TRACE("dlopen() failed");
1202
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (libpath)
1203 {
1204 3 GATE_DEBUG_TRACE(libpath);
1205 }
1206
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (last_errmsg)
1207 {
1208 3 GATE_DEBUG_TRACE(last_errmsg);
1209 }
1210 }
1211 7 return ret;
1212 }
1213
1214 4 int gate_posix_dlclose(void* handle)
1215 {
1216 4 int ret = dlclose(handle);
1217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret != 0)
1218 {
1219 char* last_errmsg = dlerror();
1220 GATE_DEBUG_TRACE("dlclose() failed");
1221 if (last_errmsg)
1222 {
1223 GATE_DEBUG_TRACE(last_errmsg);
1224 }
1225 }
1226 4 return ret;
1227 }
1228
1229 26 void* gate_posix_dlsym(void* handle, char const* symbol)
1230 {
1231 void* ret;
1232
1233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (!symbol)
1234 {
1235 GATE_DEBUG_TRACE("Invalid arg for dlsym()");
1236 return NULL;
1237 }
1238
1239 26 dlerror();
1240 26 ret = dlsym(handle, symbol);
1241
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
26 if (NULL == ret)
1242 {
1243 2 char* last_errmsg = dlerror();
1244 2 GATE_DEBUG_TRACE("dlsym() failed:");
1245 2 GATE_DEBUG_TRACE(symbol);
1246
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (last_errmsg)
1247 {
1248 2 GATE_DEBUG_TRACE(last_errmsg);
1249 }
1250 }
1251 26 return ret;
1252 }
1253
1254
1255 static void* volatile dl_global = NULL;
1256
1257 1 static void close_global_dlhandle_atexit()
1258 {
1259
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (NULL != dl_global)
1260 {
1261 1 void* handle = dl_global;
1262 1 dl_global = NULL;
1263 1 dlclose(handle);
1264 }
1265 1 }
1266
1267 4 void* gate_posix_global_sym(char const* symbol)
1268 {
1269 void* ret;
1270
1271
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (NULL == symbol)
1272 {
1273 return NULL;
1274 }
1275
1276 4 dlerror();
1277
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (dl_global == NULL)
1278 {
1279 1 dl_global = dlopen(NULL, RTLD_GLOBAL | RTLD_NOW);
1280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == dl_global)
1281 {
1282 char* last_errmsg = dlerror();
1283 if (last_errmsg)
1284 {
1285 GATE_DEBUG_TRACE(last_errmsg);
1286 }
1287 }
1288 else
1289 {
1290 1 gate_platform_atexit(&close_global_dlhandle_atexit);
1291 }
1292 }
1293
1294 4 ret = dlsym(dl_global, symbol);
1295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (NULL == ret)
1296 {
1297 char* last_errmsg = dlerror();
1298 GATE_DEBUG_TRACE("dlsym() failed to load global symbol");
1299 GATE_DEBUG_TRACE(symbol);
1300 if (last_errmsg)
1301 {
1302 GATE_DEBUG_TRACE(last_errmsg);
1303 }
1304 }
1305 4 return ret;
1306 }
1307
1308 4 static void create_semaphore_timeout(struct timespec* ptr_timeout, gate_uint32_t timeout_ms, gate_bool_t use_clocktime)
1309 {
1310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (use_clocktime)
1311 {
1312 clock_gettime(CLOCK_REALTIME, ptr_timeout);
1313 }
1314 else
1315 {
1316 4 ptr_timeout->tv_sec = 0;
1317 4 ptr_timeout->tv_nsec = 0;
1318 }
1319 4 ptr_timeout->tv_sec += timeout_ms / 1000;
1320 4 ptr_timeout->tv_nsec += (timeout_ms % 1000) * 1000000;
1321 4 ptr_timeout->tv_sec += ptr_timeout->tv_nsec / 1000000000;
1322 4 ptr_timeout->tv_nsec %= 1000000000;
1323 4 }
1324
1325 #if defined(GATE_SYS_USE_POSIX_SEMAPHORE)
1326
1327 gate_result_t gate_platform_semaphore_create(gate_platform_semaphore_t* ptr_sem, unsigned int count)
1328 {
1329 sem_t* s = NULL;
1330 int result;
1331
1332 if (!ptr_sem || (count == 0))
1333 {
1334 return GATE_RESULT_INVALIDARG;
1335 }
1336
1337 s = (sem_t*)gate_mem_alloc(sizeof(sem_t));
1338 if (!s)
1339 {
1340 return GATE_RESULT_OUTOFMEMORY;
1341 }
1342 result = sem_init(s, 0, (unsigned int)count);
1343 if (result != 0)
1344 {
1345 gate_mem_dealloc(s);
1346 return GATE_RESULT_FAILED;
1347 }
1348 else
1349 {
1350 *ptr_sem = (gate_platform_semaphore_t)s;
1351 return GATE_RESULT_OK;
1352 }
1353 }
1354 gate_result_t gate_platform_semaphore_acquire(gate_platform_semaphore_t* ptr_sem, gate_uint32_t const* ptr_timeout_ms)
1355 {
1356 sem_t** pps = (sem_t**)ptr_sem;
1357 if (!pps || !*pps)
1358 {
1359 return GATE_RESULT_INVALIDARG;
1360 }
1361
1362 if (!ptr_timeout_ms)
1363 {
1364 if (0 == sem_wait(*pps))
1365 {
1366 /* success case */
1367 return GATE_RESULT_OK;
1368 }
1369 }
1370 else
1371 {
1372 struct timespec timeout;
1373 int last_error;
1374
1375 create_semaphore_timeout(&timeout, *ptr_timeout_ms, true);
1376
1377 if (0 == sem_timedwait(*pps, &timeout))
1378 {
1379 /* success case */
1380 return GATE_RESULT_OK;
1381 }
1382 last_error = gate_posix_errno(NULL);
1383 if (last_error == ETIMEDOUT)
1384 {
1385 return GATE_RESULT_TIMEOUT;
1386 }
1387 }
1388
1389 /* generic error case */
1390 return GATE_RESULT_FAILED;
1391 }
1392 gate_result_t gate_platform_semaphore_release(gate_platform_semaphore_t* ptr_sem)
1393 {
1394 sem_t** pps = (sem_t**)ptr_sem;
1395 if (!pps || !*pps)
1396 {
1397 return GATE_RESULT_INVALIDARG;
1398 }
1399
1400 if (0 == sem_post(*pps))
1401 {
1402 return GATE_RESULT_OK;
1403 }
1404 return GATE_RESULT_FAILED;
1405 }
1406 gate_result_t gate_platform_semaphore_destroy(gate_platform_semaphore_t* ptr_sem)
1407 {
1408 sem_t** pps = (sem_t**)ptr_sem;
1409 if (!pps || !*pps)
1410 {
1411 return GATE_RESULT_INVALIDARG;
1412 }
1413 if (0 == sem_close(*pps))
1414 {
1415 gate_mem_dealloc(*pps);
1416 *pps = NULL;
1417 return GATE_RESULT_OK;
1418 }
1419 else
1420 {
1421 return GATE_RESULT_FAILED;
1422 }
1423 }
1424
1425 #else /* GATE_SYS_USE_POSIX_SEMAPHORE */
1426
1427 #if defined(GATE_SYS_LINUX) || defined(GATE_SYS_NETBSD) || defined(GATE_SYS_FREEBSD)
1428 union semun
1429 {
1430 int val;
1431 struct semid_ds* buf;
1432 unsigned short* array;
1433 };
1434 #endif
1435
1436 3 gate_result_t gate_platform_semaphore_create(gate_platform_semaphore_t* ptr_sem, unsigned int count)
1437 {
1438 3 int* s = (int*)ptr_sem;
1439 union semun arg;
1440
1441
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (!s || (count == 0))
1442 {
1443 return GATE_RESULT_INVALIDARG;
1444 }
1445
1446 3 *s = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | SHM_R | SHM_W);
1447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (*s == -1)
1448 {
1449 return GATE_RESULT_OUTOFRESOURCES;
1450 }
1451
1452 3 arg.val = (int)count;
1453 3 semctl(*s, 0, SETVAL, arg);
1454 3 return GATE_RESULT_OK;
1455 }
1456
1457 typedef int(*semtimedop_func_ptr)(int semid, struct sembuf* sops, unsigned nsops, struct timespec* timeout);
1458
1459 #if defined(HAVE_SEMTIMEDOP)
1460
1461 4 static int semtimedop_wrapper(int semid, struct sembuf* sops, unsigned nsops, struct timespec* timeout)
1462 {
1463 4 return semtimedop(semid, sops, nsops, timeout);
1464 }
1465
1466 4 static semtimedop_func_ptr get_semtimedop()
1467 {
1468 4 return &semtimedop_wrapper;
1469 }
1470
1471 #else
1472
1473 static int fallback_semtimedop(int semid, struct sembuf* sops, unsigned nsops, struct timespec* timeout)
1474 {
1475 int ret = -1;
1476 struct sembuf op[1024];
1477 unsigned index;
1478 struct timespec now;
1479
1480 clock_gettime(CLOCK_MONOTONIC, &now);
1481 do
1482 {
1483 int errcode = 0;
1484 const long nsec = (now.tv_nsec + timeout->tv_nsec);
1485 struct timespec end;
1486 struct timespec sleep_timeout;
1487 end.tv_sec = (now.tv_sec + timeout->tv_sec) + (nsec) / 1000000000;
1488 end.tv_nsec = nsec % 1000000000;
1489
1490 if (nsops > sizeof(op) / sizeof(op[0]))
1491 {
1492 nsops = sizeof(op) / sizeof(op[0]);
1493 }
1494
1495 for (index = 0; index != nsops; ++index)
1496 {
1497 op[index].sem_num = sops[index].sem_num;
1498 op[index].sem_op = sops[index].sem_op;
1499 op[index].sem_flg = sops[index].sem_flg | IPC_NOWAIT;
1500 }
1501
1502 sleep_timeout.tv_sec = 0;
1503 sleep_timeout.tv_nsec = 10;
1504 do
1505 {
1506 ret = semop(semid, &op[0], nsops);
1507 if (ret == 0)
1508 {
1509 /* operation succeeded, we are done (ret == 0) */
1510 break;
1511 }
1512 errcode = gate_posix_errno(NULL);
1513
1514 if (0 != clock_gettime(CLOCK_MONOTONIC, &now))
1515 {
1516 break;
1517 }
1518 if ((now.tv_sec > end.tv_sec) || ((now.tv_sec == end.tv_sec) && (now.tv_nsec > end.tv_nsec)))
1519 {
1520 /* timeout reached, (ret == -1) */
1521 gate_posix_set_errno(EAGAIN);
1522 break;
1523 }
1524 nanosleep(&sleep_timeout, NULL);
1525 if (sleep_timeout.tv_nsec < 50000000)
1526 {
1527 sleep_timeout.tv_nsec *= 2;
1528 }
1529 } while (errcode == EAGAIN);
1530 } while (0);
1531 return ret;
1532 }
1533
1534 static semtimedop_func_ptr get_semtimedop()
1535 {
1536 static semtimedop_func_ptr semtimedop_func = NULL;
1537 if (!semtimedop_func)
1538 {
1539 semtimedop_func = (semtimedop_func_ptr)gate_posix_global_sym("semtimedop");
1540 if (!semtimedop_func)
1541 {
1542 semtimedop_func = &fallback_semtimedop;
1543 }
1544 }
1545 return semtimedop_func;
1546 }
1547
1548 #endif
1549
1550 8 gate_result_t gate_platform_semaphore_acquire(gate_platform_semaphore_t* ptr_sem, gate_uint32_t const* ptr_timeout_ms)
1551 {
1552 8 int* s = (int*)ptr_sem;
1553 struct sembuf op;
1554
1555
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 if (!s || (*s == -1))
1556 {
1557 return GATE_RESULT_INVALIDARG;
1558 }
1559
1560 8 op.sem_num = 0;
1561 8 op.sem_op = -1;
1562 8 op.sem_flg = SEM_UNDO;
1563
1564
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (!ptr_timeout_ms)
1565 {
1566
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (-1 == semop(*s, &op, 1))
1567 {
1568 return GATE_RESULT_FAILED;
1569 }
1570 }
1571 else
1572 {
1573 struct timespec timeout;
1574 4 semtimedop_func_ptr semtimedop_func = get_semtimedop();
1575
1576
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (semtimedop_func == NULL)
1577 {
1578 2 return GATE_RESULT_NOTSUPPORTED;
1579 }
1580
1581 4 create_semaphore_timeout(&timeout, *ptr_timeout_ms, false);
1582
1583
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (-1 == semtimedop_func(*s, &op, 1, &timeout))
1584 {
1585
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (gate_posix_errno(NULL) == EAGAIN)
1586 {
1587 2 return GATE_RESULT_TIMEOUT;
1588 }
1589 else
1590 {
1591 return GATE_RESULT_FAILED;
1592 }
1593 }
1594 }
1595
1596 /* generic success case */
1597 6 return GATE_RESULT_OK;
1598 }
1599
1600 6 gate_result_t gate_platform_semaphore_release(gate_platform_semaphore_t* ptr_sem)
1601 {
1602 6 int* s = (int*)ptr_sem;
1603 struct sembuf op;
1604
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!s || (*s == -1))
1605 {
1606 return GATE_RESULT_INVALIDARG;
1607 }
1608
1609 6 op.sem_num = 0;
1610 6 op.sem_op = 1;
1611 6 op.sem_flg = SEM_UNDO;
1612
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (-1 == semop(*s, &op, 1))
1613 {
1614 return GATE_RESULT_FAILED;
1615 }
1616 6 return GATE_RESULT_OK;
1617 }
1618 3 gate_result_t gate_platform_semaphore_destroy(gate_platform_semaphore_t* ptr_sem)
1619 {
1620 3 int* s = (int*)ptr_sem;
1621
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (!s || (*s == -1))
1622 {
1623 return GATE_RESULT_INVALIDARG;
1624 }
1625
1626 3 semctl(*s, 0, IPC_RMID, NULL);
1627 3 *s = -1;
1628 3 return GATE_RESULT_OK;
1629 }
1630
1631 #endif /* GATE_SYS_USE_POSIX_SEMAPHORE*/
1632
1633 gate_bool_t gate_platform_yield()
1634 {
1635 sched_yield();
1636 return true;
1637 }
1638
1639 #endif /* GATE_SYS_POSIX */
1640