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 | |||
29 | #include "gate/processes.h" | ||
30 | |||
31 | #include "gate/platforms.h" | ||
32 | #include "gate/debugging.h" | ||
33 | #include "gate/results.h" | ||
34 | |||
35 | #if defined(GATE_SYS_POSIX) | ||
36 | |||
37 | #include <unistd.h> | ||
38 | #include <dirent.h> | ||
39 | #include <sys/wait.h> | ||
40 | #include <sys/resource.h> | ||
41 | #include <sys/types.h> | ||
42 | #include <sys/select.h> | ||
43 | #include <sys/wait.h> | ||
44 | #include <stdio.h> | ||
45 | #include <fcntl.h> | ||
46 | #include <grp.h> | ||
47 | |||
48 | #if defined(GATE_SYS_LINUX) | ||
49 | # include <pty.h> | ||
50 | #elif defined(GATE_SYS_BSD) | ||
51 | # include <termios.h> | ||
52 | # if defined(GATE_SYS_FREEBSD) | ||
53 | # include <libutil.h> | ||
54 | # else | ||
55 | # include <util.h> | ||
56 | # endif | ||
57 | #elif defined(GATE_SYS_DARWIN) | ||
58 | # include <util.h> | ||
59 | # include "gate/platform/darwin/darwin_gate.h" | ||
60 | #endif | ||
61 | |||
62 | #if !defined(GATE_SYS_BSD) | ||
63 | # include <utmp.h> | ||
64 | #endif | ||
65 | #include <dlfcn.h> | ||
66 | #include <errno.h> | ||
67 | |||
68 | #include "gate/times.h" | ||
69 | #include "gate/threading.h" | ||
70 | #include "gate/platforms.h" | ||
71 | #include "gate/platform/linux/procfs.h" | ||
72 | #include "gate/files.h" | ||
73 | |||
74 | |||
75 | typedef struct gate_process_stream_impl | ||
76 | { | ||
77 | GATE_INTERFACE_VTBL(gate_process_stream)* vbl; | ||
78 | gate_atomic_int_t ref_counter; | ||
79 | pid_t target_pid; | ||
80 | int fd_stdin_write; | ||
81 | int fd_stdout_read; | ||
82 | int fd_stderr_read; | ||
83 | char peek_buffer[1024]; | ||
84 | gate_size_t peek_buffer_used; | ||
85 | } gate_process_stream_impl_t; | ||
86 | |||
87 | 5 | static void gate_process_stream_release(void* thisptr) | |
88 | { | ||
89 | 5 | gate_process_stream_impl_t* stream = (gate_process_stream_impl_t*)thisptr; | |
90 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
|
5 | if (gate_atomic_int_dec(&stream->ref_counter) == 0) |
91 | { | ||
92 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (stream->fd_stdin_write >= 0) |
93 | { | ||
94 | 1 | close(stream->fd_stdin_write); | |
95 | 1 | stream->fd_stdin_write = -1; | |
96 | } | ||
97 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (stream->fd_stdout_read >= 0) |
98 | { | ||
99 | 1 | close(stream->fd_stdout_read); | |
100 | 1 | stream->fd_stdout_read = -1; | |
101 | } | ||
102 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (stream->fd_stderr_read >= 0) |
103 | { | ||
104 | 1 | close(stream->fd_stderr_read); | |
105 | 1 | stream->fd_stderr_read = -1; | |
106 | } | ||
107 | 1 | gate_mem_dealloc(stream); | |
108 | } | ||
109 | 5 | } | |
110 | ✗ | static char const* gate_process_stream_interface_name(void* thisptr) | |
111 | { | ||
112 | (void)thisptr; | ||
113 | ✗ | return GATE_INTERFACE_NAME_PROCESSSTREAM; | |
114 | } | ||
115 | 4 | static int gate_process_stream_retain(void* thisptr) | |
116 | { | ||
117 | 4 | gate_process_stream_impl_t* stream = (gate_process_stream_impl_t*)thisptr; | |
118 | 4 | return gate_atomic_int_inc(&stream->ref_counter); | |
119 | } | ||
120 | |||
121 | ✗ | static gate_result_t is_process_termined(pid_t pid, gate_bool_t* ptr_terminated) | |
122 | { | ||
123 | siginfo_t info; | ||
124 | int result; | ||
125 | |||
126 | ✗ | gate_mem_clear(&info, sizeof(info)); | |
127 | ✗ | result = waitid(P_PID, pid, &info, WEXITED | WNOHANG | WNOWAIT); | |
128 | ✗ | if (0 == result) | |
129 | { | ||
130 | ✗ | if ((info.si_code == CLD_EXITED) | |
131 | ✗ | || (info.si_code == CLD_KILLED) | |
132 | ✗ | || (info.si_code == CLD_DUMPED) | |
133 | ) | ||
134 | { | ||
135 | ✗ | *ptr_terminated = true; | |
136 | } | ||
137 | else | ||
138 | { | ||
139 | ✗ | *ptr_terminated = false; | |
140 | } | ||
141 | ✗ | return GATE_RESULT_OK; | |
142 | } | ||
143 | else | ||
144 | { | ||
145 | /* error */ | ||
146 | ✗ | return gate_platform_print_last_error(NULL, 0); | |
147 | } | ||
148 | } | ||
149 | |||
150 | ✗ | static gate_bool_t can_read_from_fd(int read_fd) | |
151 | { | ||
152 | fd_set read_set; | ||
153 | struct timeval timeout; | ||
154 | int result; | ||
155 | |||
156 | ✗ | timeout.tv_sec = 0; | |
157 | ✗ | timeout.tv_usec = 0; | |
158 | |||
159 | ✗ | FD_ZERO(&read_set); | |
160 | ✗ | FD_SET(read_fd, &read_set); | |
161 | |||
162 | ✗ | result = select(read_fd + 1, &read_set, NULL, NULL, &timeout); | |
163 | ✗ | if (result < 0) | |
164 | { | ||
165 | /* error */ | ||
166 | ✗ | return false; | |
167 | } | ||
168 | ✗ | if (FD_ISSET(read_fd, &read_set)) | |
169 | { | ||
170 | ✗ | return true; | |
171 | } | ||
172 | ✗ | return false; | |
173 | } | ||
174 | |||
175 | ✗ | static int await_read_fd_or_process_exit(pid_t pid, int read_fd) | |
176 | { | ||
177 | fd_set read_set; | ||
178 | fd_set err_set; | ||
179 | struct timeval timeout; | ||
180 | int result; | ||
181 | |||
182 | for (;;) | ||
183 | { | ||
184 | ✗ | timeout.tv_sec = 0; | |
185 | ✗ | timeout.tv_usec = 100000; | |
186 | |||
187 | ✗ | FD_ZERO(&read_set); | |
188 | ✗ | FD_ZERO(&err_set); | |
189 | ✗ | FD_SET(read_fd, &read_set); | |
190 | ✗ | FD_SET(read_fd, &err_set); | |
191 | |||
192 | ✗ | result = select(read_fd + 1, &read_set, NULL, &err_set, &timeout); | |
193 | ✗ | if (result < 0) | |
194 | { | ||
195 | /* error */ | ||
196 | ✗ | return -1; | |
197 | } | ||
198 | ✗ | if (FD_ISSET(read_fd, &err_set)) | |
199 | { | ||
200 | /* error */ | ||
201 | ✗ | return -1; | |
202 | } | ||
203 | ✗ | if (FD_ISSET(read_fd, &read_set)) | |
204 | { | ||
205 | /* can read */ | ||
206 | ✗ | return 1; | |
207 | } | ||
208 | |||
209 | ✗ | if (pid > 0) | |
210 | { | ||
211 | ✗ | gate_bool_t is_terminated = false; | |
212 | ✗ | gate_result_t wait_result = is_process_termined(pid, &is_terminated); | |
213 | |||
214 | ✗ | if (GATE_FAILED(wait_result)) | |
215 | { | ||
216 | /* failed to detect process state */ | ||
217 | ✗ | return -1; | |
218 | } | ||
219 | else | ||
220 | { | ||
221 | ✗ | if (is_terminated) | |
222 | { | ||
223 | /* process terminated, nothing else to read */ | ||
224 | ✗ | return 0; | |
225 | } | ||
226 | |||
227 | /* else: continue */ | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | |||
233 | ✗ | static gate_result_t gate_process_stream_read(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned) | |
234 | { | ||
235 | ✗ | gate_process_stream_impl_t* stream = (gate_process_stream_impl_t*)thisptr; | |
236 | ✗ | gate_result_t ret = GATE_RESULT_FAILED; | |
237 | gate_int32_t errcode; | ||
238 | ptrdiff_t result; | ||
239 | int wait_result; | ||
240 | |||
241 | ✗ | if (stream->peek_buffer_used > 0) | |
242 | { | ||
243 | /* there is something in the peek buffer */ | ||
244 | |||
245 | ✗ | if (bufferlength >= stream->peek_buffer_used) | |
246 | { | ||
247 | /* we can read the whole peek-buffer */ | ||
248 | ✗ | gate_mem_copy(buffer, stream->peek_buffer, stream->peek_buffer_used); | |
249 | ✗ | if (returned) *returned = stream->peek_buffer_used; | |
250 | ✗ | stream->peek_buffer_used = 0; | |
251 | } | ||
252 | else | ||
253 | { | ||
254 | /* we can only return a subset of the peek buffer */ | ||
255 | ✗ | gate_mem_copy(buffer, &stream->peek_buffer[0], bufferlength); | |
256 | ✗ | gate_mem_copy(&stream->peek_buffer[0], &stream->peek_buffer[bufferlength], stream->peek_buffer_used - bufferlength); | |
257 | ✗ | stream->peek_buffer_used -= bufferlength; | |
258 | ✗ | if (returned) *returned = bufferlength; | |
259 | } | ||
260 | ✗ | return GATE_RESULT_OK; | |
261 | } | ||
262 | |||
263 | ✗ | wait_result = await_read_fd_or_process_exit(stream->target_pid, stream->fd_stdout_read); | |
264 | ✗ | if (wait_result < 0) | |
265 | { | ||
266 | ✗ | return GATE_RESULT_FAILED; | |
267 | } | ||
268 | ✗ | else if (wait_result == 0) | |
269 | { | ||
270 | ✗ | if (returned) | |
271 | { | ||
272 | ✗ | *returned = 0; | |
273 | } | ||
274 | ✗ | return GATE_RESULT_OK; | |
275 | } | ||
276 | |||
277 | /* data available to read */ | ||
278 | ✗ | result = gate_posix_read(stream->fd_stdout_read, buffer, bufferlength); | |
279 | ✗ | if (result < 0) | |
280 | { | ||
281 | ✗ | errcode = gate_platform_get_last_error(); | |
282 | ✗ | if (errcode == EIO) | |
283 | { | ||
284 | ✗ | gate_bool_t terminated = false; | |
285 | ✗ | gate_result_t wait_result = is_process_termined(stream->target_pid, &terminated); | |
286 | ✗ | if (GATE_SUCCEEDED(wait_result) && terminated) | |
287 | { | ||
288 | /* signal end-of-stream, as process was terminated */ | ||
289 | ✗ | if (returned) | |
290 | { | ||
291 | ✗ | *returned = 0; | |
292 | } | ||
293 | ✗ | return GATE_RESULT_OK; | |
294 | } | ||
295 | } | ||
296 | ✗ | GATE_DEBUG_TRACE_MSG_VALUE("gate_process_stream_read() failed", errcode); | |
297 | ✗ | ret = gate_platform_print_error(errcode, NULL, 0); | |
298 | } | ||
299 | else | ||
300 | { | ||
301 | ✗ | if (returned) *returned = (gate_size_t)result; | |
302 | ✗ | ret = GATE_RESULT_OK; | |
303 | } | ||
304 | ✗ | return ret; | |
305 | } | ||
306 | ✗ | static gate_result_t gate_process_stream_peek(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned) | |
307 | { | ||
308 | ✗ | gate_process_stream_impl_t* stream = (gate_process_stream_impl_t*)thisptr; | |
309 | gate_size_t copylen; | ||
310 | ptrdiff_t result; | ||
311 | gate_int32_t errcode; | ||
312 | |||
313 | ✗ | if (stream->peek_buffer_used > 0) | |
314 | { | ||
315 | /* there is already something in the peek buffer */ | ||
316 | ✗ | copylen = bufferlength < stream->peek_buffer_used ? bufferlength : stream->peek_buffer_used; | |
317 | ✗ | gate_mem_copy(buffer, &stream->peek_buffer[0], copylen); | |
318 | ✗ | if (returned) *returned = copylen; | |
319 | ✗ | return GATE_RESULT_OK; | |
320 | } | ||
321 | |||
322 | ✗ | if (can_read_from_fd(stream->fd_stdout_read)) | |
323 | { | ||
324 | /* read some bytes into peek-buffer */ | ||
325 | ✗ | copylen = bufferlength < sizeof(stream->peek_buffer) ? bufferlength : sizeof(stream->peek_buffer); | |
326 | ✗ | result = gate_posix_read(stream->fd_stdout_read, &stream->peek_buffer[0], copylen); | |
327 | ✗ | if (result < 0) | |
328 | { | ||
329 | /* read error */ | ||
330 | ✗ | errcode = gate_platform_get_last_error(); | |
331 | ✗ | if (errcode == EIO) | |
332 | { | ||
333 | ✗ | gate_bool_t terminated = false; | |
334 | ✗ | gate_result_t wait_result = is_process_termined(stream->target_pid, &terminated); | |
335 | ✗ | if (GATE_SUCCEEDED(wait_result) && terminated) | |
336 | { | ||
337 | /* signal end-of-stream, as process was terminated */ | ||
338 | ✗ | if (returned) | |
339 | { | ||
340 | ✗ | *returned = 0; | |
341 | } | ||
342 | ✗ | return GATE_RESULT_ENDOFSTREAM; | |
343 | } | ||
344 | } | ||
345 | /* otherwise return native error info */ | ||
346 | ✗ | return gate_platform_print_last_error(NULL, 0); | |
347 | } | ||
348 | ✗ | else if (result > 0) | |
349 | { | ||
350 | /* peek-buffer is filled, return a copy via caller-supplied buffer */ | ||
351 | ✗ | stream->peek_buffer_used = copylen; | |
352 | ✗ | gate_mem_copy(buffer, &stream->peek_buffer[0], copylen); | |
353 | ✗ | if (returned) *returned = copylen; | |
354 | ✗ | return GATE_RESULT_OK; | |
355 | } | ||
356 | } | ||
357 | |||
358 | /* else: nothing available to read*/ | ||
359 | ✗ | if (returned) *returned = 0; | |
360 | ✗ | return GATE_RESULT_OK; | |
361 | } | ||
362 | ✗ | static gate_result_t gate_process_stream_write(void* thisptr, char const* buffer, gate_size_t bufferlength, gate_size_t* written) | |
363 | { | ||
364 | ✗ | gate_process_stream_impl_t* stream = (gate_process_stream_impl_t*)thisptr; | |
365 | ✗ | gate_result_t ret = GATE_RESULT_FAILED; | |
366 | gate_int32_t errcode; | ||
367 | ✗ | ptrdiff_t result = gate_posix_write(stream->fd_stdin_write, buffer, bufferlength); | |
368 | ✗ | if (result <= 0) | |
369 | { | ||
370 | ✗ | errcode = gate_platform_get_last_error(); | |
371 | ✗ | GATE_DEBUG_TRACE_MSG_VALUE("gate_process_stream_write() failed", errcode); | |
372 | ✗ | ret = gate_platform_print_error(errcode, NULL, 0); | |
373 | } | ||
374 | else | ||
375 | { | ||
376 | ✗ | if (written) *written = (gate_size_t)result; | |
377 | ✗ | ret = GATE_RESULT_OK; | |
378 | } | ||
379 | ✗ | return ret; | |
380 | } | ||
381 | ✗ | static gate_result_t gate_process_stream_flush(void* thisptr) | |
382 | { | ||
383 | ✗ | gate_process_stream_impl_t* stream = (gate_process_stream_impl_t*)thisptr; | |
384 | ✗ | fsync(stream->fd_stdin_write); | |
385 | ✗ | return GATE_RESULT_OK; | |
386 | } | ||
387 | ✗ | static gate_result_t gate_process_stream_read_err(void* thisptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned) | |
388 | { | ||
389 | ✗ | gate_process_stream_impl_t* stream = (gate_process_stream_impl_t*)thisptr; | |
390 | ✗ | gate_result_t ret = GATE_RESULT_FAILED; | |
391 | gate_int32_t errcode; | ||
392 | ✗ | ptrdiff_t result = gate_posix_read(stream->fd_stderr_read, buffer, bufferlength); | |
393 | ✗ | if (result < 0) | |
394 | { | ||
395 | ✗ | errcode = gate_platform_get_last_error(); | |
396 | ✗ | GATE_DEBUG_TRACE_MSG_VALUE("gate_process_stream_read() failed", errcode); | |
397 | ✗ | ret = gate_platform_print_error(errcode, NULL, 0); | |
398 | } | ||
399 | else | ||
400 | { | ||
401 | ✗ | if (returned) *returned = (gate_size_t)result; | |
402 | ✗ | ret = GATE_RESULT_OK; | |
403 | } | ||
404 | ✗ | return ret; | |
405 | } | ||
406 | ✗ | static gate_result_t gate_process_stream_get_resource(void* thisptr, gate_enumint_t resource_type, gate_uintptr_t* resource) | |
407 | { | ||
408 | ✗ | gate_process_stream_impl_t* stream = (gate_process_stream_impl_t*)thisptr; | |
409 | gate_result_t ret; | ||
410 | ✗ | switch (resource_type) | |
411 | { | ||
412 | ✗ | case GATE_STREAM_RESOURCE_INPUT: | |
413 | { | ||
414 | ✗ | *resource = (gate_uintptr_t)stream->fd_stdin_write; | |
415 | ✗ | ret = GATE_RESULT_OK; | |
416 | ✗ | break; | |
417 | } | ||
418 | ✗ | case GATE_STREAM_RESOURCE_OUTPUT: | |
419 | { | ||
420 | ✗ | *resource = (gate_uintptr_t)stream->fd_stdout_read; | |
421 | ✗ | ret = GATE_RESULT_OK; | |
422 | ✗ | break; | |
423 | } | ||
424 | ✗ | case GATE_STREAM_RESOURCE_ERROR: | |
425 | { | ||
426 | ✗ | *resource = (gate_uintptr_t)stream->fd_stderr_read; | |
427 | ✗ | ret = GATE_RESULT_OK; | |
428 | ✗ | break; | |
429 | } | ||
430 | ✗ | default: | |
431 | { | ||
432 | ✗ | ret = GATE_RESULT_NOTSUPPORTED; | |
433 | ✗ | break; | |
434 | } | ||
435 | } | ||
436 | ✗ | return ret; | |
437 | } | ||
438 | |||
439 | static GATE_INTERFACE_VTBL(gate_process_stream) gate_process_stream_vtbl; | ||
440 | 1 | static void gate_init_process_stream_vtbl() | |
441 | { | ||
442 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (!gate_process_stream_vtbl.get_interface_name) |
443 | { | ||
444 | GATE_INTERFACE_VTBL(gate_process_stream) const local_vtbl = | ||
445 | { | ||
446 | &gate_process_stream_interface_name, | ||
447 | &gate_process_stream_release, | ||
448 | &gate_process_stream_retain, | ||
449 | &gate_process_stream_read, | ||
450 | &gate_process_stream_peek, | ||
451 | &gate_process_stream_write, | ||
452 | &gate_process_stream_flush, | ||
453 | &gate_process_stream_get_resource, | ||
454 | &gate_process_stream_read_err | ||
455 | }; | ||
456 | 1 | gate_process_stream_vtbl = local_vtbl; | |
457 | } | ||
458 | 1 | } | |
459 | |||
460 | 1 | static gate_process_stream_t* gate_process_stream_create(int fd_stdin_write, int fd_stdout_read, int fd_stderr_read) | |
461 | { | ||
462 | 1 | gate_process_stream_impl_t* stream = gate_mem_alloc(sizeof(gate_process_stream_impl_t)); | |
463 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (stream) |
464 | { | ||
465 | 1 | gate_init_process_stream_vtbl(); | |
466 | 1 | stream->vbl = &gate_process_stream_vtbl; | |
467 | 1 | gate_atomic_int_set(&stream->ref_counter, 1); | |
468 | 1 | stream->target_pid = 0; | |
469 | 1 | stream->fd_stdin_write = fd_stdin_write; | |
470 | 1 | stream->fd_stdout_read = fd_stdout_read; | |
471 | 1 | stream->fd_stderr_read = fd_stderr_read; | |
472 | } | ||
473 | 1 | return (gate_process_stream_t*)stream; | |
474 | } | ||
475 | |||
476 | |||
477 | /* | ||
478 | typedef struct rlimit_setting | ||
479 | { | ||
480 | int setting; | ||
481 | struct rlimit limit; | ||
482 | } rlimit_setting_t; | ||
483 | |||
484 | typedef struct gate_process_exec_config | ||
485 | { | ||
486 | gate_bool_t set_uid; | ||
487 | uid_t uid; | ||
488 | gate_bool_t set_gid; | ||
489 | gid_t gid; | ||
490 | |||
491 | gate_bool_t new_session; | ||
492 | gate_bool_t new_terminal; | ||
493 | |||
494 | rlimit_setting_t limits[8]; | ||
495 | gate_size_t limit_count; | ||
496 | |||
497 | } gate_process_exec_config_t; | ||
498 | |||
499 | gate_result_t gate_process_apply_exec_config(gate_process_exec_config_t const* config) | ||
500 | { | ||
501 | gate_result_t ret = GATE_RESULT_OK; | ||
502 | gate_size_t ndx; | ||
503 | int result; | ||
504 | char user_name[512]; | ||
505 | gate_size_t user_name_used; | ||
506 | |||
507 | do | ||
508 | { | ||
509 | if(config == NULL) break; | ||
510 | |||
511 | for(ndx = 0; ndx != config->limit_count; ++ndx) | ||
512 | { | ||
513 | if(-1 == setrlimit(config->limits[ndx].setting, &config->limits[ndx].limit)) | ||
514 | { | ||
515 | ret = GATE_RESULT_PREPARATIONFAILED; | ||
516 | break; | ||
517 | } | ||
518 | } | ||
519 | GATE_BREAK_IF_FAILED(ret); | ||
520 | |||
521 | if(config->set_uid && config->set_gid) | ||
522 | { | ||
523 | user_name_used = gate_posix_get_user_name(config->set_uid, user_name, sizeof(user_name)); | ||
524 | if(user_name_used != 0) | ||
525 | { | ||
526 | result = initgroups(user_name, config->gid); | ||
527 | if(result != 0) | ||
528 | { | ||
529 | GATE_DEBUG_TRACE("Failed to initialize groups"); | ||
530 | GATE_DEBUG_TRACE_VALUE(gate_posix_errno(NULL)); | ||
531 | break; | ||
532 | } | ||
533 | } | ||
534 | } | ||
535 | |||
536 | if(config->set_gid) | ||
537 | { | ||
538 | result = setgid(config->gid); | ||
539 | if(result != 0) | ||
540 | { | ||
541 | GATE_DEBUG_TRACE("setgid() failed"); | ||
542 | GATE_DEBUG_TRACE_VALUE(gate_posix_errno(NULL)); | ||
543 | ret = GATE_RESULT_FAILED; | ||
544 | break; | ||
545 | } | ||
546 | } | ||
547 | |||
548 | if(config->set_uid) | ||
549 | { | ||
550 | result = setuid(config->uid); | ||
551 | if(result != 0) | ||
552 | { | ||
553 | GATE_DEBUG_TRACE("setuid() failed"); | ||
554 | GATE_DEBUG_TRACE_VALUE(gate_posix_errno(NULL)); | ||
555 | ret = GATE_RESULT_FAILED; | ||
556 | break; | ||
557 | } | ||
558 | } | ||
559 | |||
560 | if(config->new_session) | ||
561 | { | ||
562 | result = setsid(); | ||
563 | if(result != 0) | ||
564 | { | ||
565 | GATE_DEBUG_TRACE("setsid() failed"); | ||
566 | GATE_DEBUG_TRACE_VALUE(gate_posix_errno(NULL)); | ||
567 | ret = GATE_RESULT_FAILED; | ||
568 | break; | ||
569 | } | ||
570 | } | ||
571 | |||
572 | } while(0); | ||
573 | |||
574 | return ret; | ||
575 | } | ||
576 | */ | ||
577 | |||
578 | 8 | gate_result_t gate_process_get_id(gate_process_id_t* pid) | |
579 | { | ||
580 | gate_result_t ret; | ||
581 | 8 | pid_t p = getpid(); | |
582 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (pid == NULL) |
583 | { | ||
584 | ✗ | ret = GATE_RESULT_INVALIDARG; | |
585 | } | ||
586 | else | ||
587 | { | ||
588 | 8 | *pid = (gate_process_id_t)p; | |
589 | 8 | ret = GATE_RESULT_OK; | |
590 | } | ||
591 | 8 | return ret; | |
592 | } | ||
593 | ✗ | void gate_process_quit(int exitcode) | |
594 | { | ||
595 | ✗ | _exit(exitcode); | |
596 | } | ||
597 | |||
598 | #if defined(GATE_SYS_BSD) || defined(GATE_SYS_DARWIN) | ||
599 | |||
600 | #include <stdlib.h> | ||
601 | #include <sys/types.h> | ||
602 | #include <sys/sysctl.h> | ||
603 | |||
604 | #if defined(GATE_SYS_NETBSD) | ||
605 | /* NetBSD is special here and uses kinfo_proc2 for usermode, BSD's kinfo_proc is for kernel-mode only */ | ||
606 | |||
607 | # include <kvm.h> | ||
608 | |||
609 | typedef kvm_t* (*kvm_open_func_t)(char const* execfile, char const* corefile, char* swapfile, int flags, char* errstr); | ||
610 | typedef int (*kvm_close_func_t)(kvm_t* kd); | ||
611 | typedef struct kinfo_proc2* (*kvm_getproc2_func_t)(kvm_t* kd, int op, int arg, size_t elemsize, int* cnt); | ||
612 | |||
613 | static kvm_open_func_t kvm_open_func; | ||
614 | static kvm_close_func_t kvm_close_func; | ||
615 | static kvm_getproc2_func_t kvm_getproc2_func; | ||
616 | |||
617 | static void* volatile kvm_lib = NULL; | ||
618 | |||
619 | static void close_kvm_lib_atexit() | ||
620 | { | ||
621 | if (NULL != kvm_lib) | ||
622 | { | ||
623 | void* handle = kvm_lib; | ||
624 | kvm_lib = NULL; | ||
625 | gate_posix_dlclose(handle); | ||
626 | } | ||
627 | } | ||
628 | |||
629 | static gate_result_t load_kvm_library() | ||
630 | { | ||
631 | if (!kvm_lib) | ||
632 | { | ||
633 | kvm_lib = gate_posix_dlopen("libkvm.so", RTLD_GLOBAL); | ||
634 | if (kvm_lib == NULL) | ||
635 | { | ||
636 | return GATE_RESULT_NOTAVAILABLE; | ||
637 | } | ||
638 | gate_platform_atexit(&close_kvm_lib_atexit); | ||
639 | } | ||
640 | if (!kvm_open_func) | ||
641 | { | ||
642 | kvm_open_func = (kvm_open_func_t)gate_posix_dlsym(kvm_lib, "kvm_open"); | ||
643 | } | ||
644 | if (!kvm_close_func) | ||
645 | { | ||
646 | kvm_close_func = (kvm_close_func_t)gate_posix_dlsym(kvm_lib, "kvm_close"); | ||
647 | } | ||
648 | if (!kvm_getproc2_func) | ||
649 | { | ||
650 | kvm_getproc2_func = (kvm_getproc2_func_t)gate_posix_dlsym(kvm_lib, "kvm_getproc2"); | ||
651 | } | ||
652 | return (kvm_open_func && kvm_close_func && kvm_getproc2_func) ? GATE_RESULT_OK : GATE_RESULT_NOTAVAILABLE; | ||
653 | } | ||
654 | |||
655 | static gate_result_t load_process_infobuffer(gate_process_infobuffer_t* target, struct kinfo_proc2 const* src) | ||
656 | { | ||
657 | target->process.pid = src->p_pid; | ||
658 | target->process.parent_pid = src->p_ppid; | ||
659 | target->process.memory_used = src->p_vm_rssize; | ||
660 | target->process.uptime = src->p_ustart_sec * 1000; | ||
661 | target->process.cputime = src->p_uutime_sec * 1000; | ||
662 | target->process.resources = 1; | ||
663 | gate_str_print_text(target->namebuffer, sizeof(target->namebuffer), src->p_comm, gate_str_length(src->p_comm)); | ||
664 | target->process.name = target->namebuffer; | ||
665 | gate_str_print_int64(target->ownerbuffer, sizeof(target->ownerbuffer), src->p_ruid); | ||
666 | target->process.owner = target->ownerbuffer; | ||
667 | return GATE_RESULT_OK; | ||
668 | } | ||
669 | |||
670 | |||
671 | gate_result_t gate_process_getinfo(gate_process_infobuffer_t* infobuffer, gate_process_id_t proc_id, gate_enumint_t flags) | ||
672 | { | ||
673 | gate_result_t ret = GATE_RESULT_FAILED; | ||
674 | kvm_t* kvm = NULL; | ||
675 | struct kinfo_proc2* procs = NULL; | ||
676 | int procs_count = 0; | ||
677 | char errmsg[_POSIX2_LINE_MAX] = GATE_INIT_EMPTY; | ||
678 | |||
679 | do | ||
680 | { | ||
681 | ret = load_kvm_library(); | ||
682 | GATE_BREAK_IF_FAILED(ret); | ||
683 | |||
684 | kvm = kvm_open_func(NULL, NULL, NULL, O_RDONLY, errmsg); | ||
685 | if (kvm == NULL) | ||
686 | { | ||
687 | GATE_DEBUG_TRACE("kvm_open() failed"); | ||
688 | errmsg[_POSIX2_LINE_MAX - 1] = 0; | ||
689 | GATE_DEBUG_TRACE(errmsg); | ||
690 | ret = GATE_RESULT_NOTAVAILABLE; | ||
691 | break; | ||
692 | } | ||
693 | procs = kvm_getproc2_func(kvm, KERN_PROC_PID, (int)proc_id, sizeof(struct kinfo_proc2), &procs_count); | ||
694 | if ((procs == NULL) || (procs_count == 0)) | ||
695 | { | ||
696 | GATE_DEBUG_TRACE("kvm_getprocs(KERN_PROC_PID) failed"); | ||
697 | ret = GATE_RESULT_NOMATCH; | ||
698 | break; | ||
699 | } | ||
700 | |||
701 | ret = load_process_infobuffer(infobuffer, procs); | ||
702 | } while (0); | ||
703 | |||
704 | if (kvm != NULL) | ||
705 | { | ||
706 | kvm_close_func(kvm); | ||
707 | } | ||
708 | |||
709 | return ret; | ||
710 | } | ||
711 | |||
712 | #else /* OpenBSD and FreeBSD: */ | ||
713 | |||
714 | #include <sys/user.h> | ||
715 | |||
716 | static gate_result_t load_process_infobuffer(gate_process_infobuffer_t* target, struct kinfo_proc const* src) | ||
717 | { | ||
718 | gate_result_t ret = GATE_RESULT_OK; | ||
719 | gate_mem_clear(target, sizeof(gate_process_infobuffer_t)); | ||
720 | #if defined(GATE_SYS_OPENBSD) | ||
721 | target->process.pid = src->p_pid; | ||
722 | target->process.parent_pid = src->p_ppid; | ||
723 | target->process.memory_used = src->p_vm_rssize; | ||
724 | target->process.uptime = src->p_uutime_sec * 1000 + src->p_ustime_sec * 1000 + src->p_rtime_sec * 1000; | ||
725 | target->process.resources = src->p_tid; | ||
726 | gate_str_print_text(target->namebuffer, sizeof(target->namebuffer), src->p_comm, gate_str_length(src->p_comm)); | ||
727 | target->process.name = target->namebuffer; | ||
728 | gate_str_print_int64(target->ownerbuffer, sizeof(target->ownerbuffer), src->p_ruid); | ||
729 | target->process.owner = target->ownerbuffer; | ||
730 | #elif defined(GATE_SYS_DARWIN) | ||
731 | target->process.pid = src->kp_proc.p_pid; | ||
732 | target->process.parent_pid = src->kp_eproc.e_ppid; | ||
733 | target->process.memory_used = 1; /* TODO */ | ||
734 | target->process.uptime = src->kp_proc.p_swtime; | ||
735 | target->process.cputime = src->kp_proc.p_rtime.tv_sec * 1000 + src->kp_proc.p_rtime.tv_usec / 1000; | ||
736 | target->process.resources = 1; /* TODO */ | ||
737 | gate_str_print_text(target->namebuffer, sizeof(target->namebuffer), src->kp_proc.p_comm, gate_str_length(src->kp_proc.p_comm)); | ||
738 | target->process.name = target->namebuffer; | ||
739 | gate_str_print_text(target->ownerbuffer, sizeof(target->ownerbuffer), src->kp_eproc.e_login, gate_str_length(src->kp_eproc.e_login)); | ||
740 | target->process.owner = target->ownerbuffer; | ||
741 | #else | ||
742 | target->process.pid = src->ki_pid; | ||
743 | target->process.parent_pid = src->ki_ppid; | ||
744 | target->process.memory_used = src->ki_size; | ||
745 | target->process.uptime = src->ki_start.tv_sec * 1000 + src->ki_start.tv_usec / 1000; | ||
746 | target->process.cputime = src->ki_runtime; | ||
747 | target->process.resources = src->ki_numthreads; | ||
748 | gate_str_print_text(target->namebuffer, sizeof(target->namebuffer), src->ki_comm, gate_str_length(src->ki_comm)); | ||
749 | target->process.name = target->namebuffer; | ||
750 | gate_str_print_text(target->ownerbuffer, sizeof(target->ownerbuffer), src->ki_login, gate_str_length(src->ki_login)); | ||
751 | target->process.owner = target->ownerbuffer; | ||
752 | #endif | ||
753 | |||
754 | return ret; | ||
755 | } | ||
756 | |||
757 | gate_result_t gate_process_getinfo(gate_process_infobuffer_t* infobuffer, gate_process_id_t proc_id, gate_enumint_t flags) | ||
758 | { | ||
759 | gate_result_t ret = GATE_RESULT_FAILED; | ||
760 | int names[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)proc_id, sizeof(struct kinfo_proc), 1 }; | ||
761 | #if defined(GATE_SYS_OPENBSD) | ||
762 | unsigned name_len = 6; | ||
763 | #else | ||
764 | unsigned name_len = 4; | ||
765 | #endif | ||
766 | char buffer[8192 + 4096]; | ||
767 | size_t buffer_len = sizeof(buffer); | ||
768 | int result; | ||
769 | |||
770 | do | ||
771 | { | ||
772 | result = sysctl(names, name_len, &buffer[0], &buffer_len, NULL, 0); | ||
773 | if (result < 0) | ||
774 | { | ||
775 | GATE_DEBUG_TRACE_PLATFORM_ERROR("sysctl() failed"); | ||
776 | GATE_DEBUG_TRACE_MSG_VALUE("PID", proc_id); | ||
777 | ret = GATE_RESULT_FAILED; | ||
778 | break; | ||
779 | } | ||
780 | ret = load_process_infobuffer(infobuffer, (struct kinfo_proc const*)buffer); | ||
781 | } while (0); | ||
782 | return ret; | ||
783 | } | ||
784 | |||
785 | #endif /* NETBSD or OPEN/FREEBSD variants for gate_process_getinfo() */ | ||
786 | |||
787 | |||
788 | #if defined(GATE_SYS_DARWIN) | ||
789 | |||
790 | static gate_bool_t publish_process_info(int pid, gate_process_enum_callback_t callback, void* userparam, gate_enumint_t flags) | ||
791 | { | ||
792 | gate_process_infobuffer_t info; | ||
793 | |||
794 | int ppid = 0; | ||
795 | unsigned int uid = 0; | ||
796 | unsigned int gid = 0; | ||
797 | unsigned long long start_time = 0; | ||
798 | gate_result_t result; | ||
799 | |||
800 | gate_mem_clear(&info, sizeof(info)); | ||
801 | |||
802 | info.process.pid = pid; | ||
803 | |||
804 | result = gate_darwin_get_pid_info(pid, &ppid, &uid, &gid, &start_time, info.namebuffer, sizeof(info.namebuffer)); | ||
805 | if (GATE_SUCCEEDED(result)) | ||
806 | { | ||
807 | info.process.parent_pid = ppid; | ||
808 | info.process.uptime = (gate_int64_t)start_time; | ||
809 | info.process.cputime = (gate_int64_t)start_time; /* TODO */ | ||
810 | info.process.name = info.namebuffer; | ||
811 | } | ||
812 | |||
813 | if (GATE_FLAG_ENABLED(flags, GATE_PROCESS_ENUM_PATH)) | ||
814 | { | ||
815 | result = gate_darwin_get_pid_path(pid, info.pathbuffer, sizeof(info.pathbuffer), NULL); | ||
816 | if (GATE_SUCCEEDED(result)) | ||
817 | { | ||
818 | info.process.path = info.pathbuffer; | ||
819 | } | ||
820 | } | ||
821 | |||
822 | if (GATE_FLAG_ENABLED(flags, GATE_PROCESS_ENUM_MEMORY)) | ||
823 | { | ||
824 | /* TODO */ | ||
825 | } | ||
826 | |||
827 | if (GATE_FLAG_ENABLED(flags, GATE_PROCESS_ENUM_MEMORY)) | ||
828 | { | ||
829 | /* TODO */ | ||
830 | } | ||
831 | |||
832 | return callback(&info.process, userparam); | ||
833 | } | ||
834 | |||
835 | static gate_result_t darwin_process_enum(gate_process_enum_callback_t callback, void* userparam, gate_enumint_t flags) | ||
836 | { | ||
837 | int pids[1024 + 512 + 256]; | ||
838 | gate_size_t pids_used = 0; | ||
839 | gate_size_t ndx; | ||
840 | gate_result_t result = gate_darwin_list_pids(&pids[0], sizeof(pids) / sizeof(pids[0]), &pids_used); | ||
841 | GATE_RETURN_IF_FAILED(result); | ||
842 | if (callback) | ||
843 | { | ||
844 | for (ndx = 0; ndx != pids_used; ++ndx) | ||
845 | { | ||
846 | if (!publish_process_info(pids[ndx], callback, userparam, flags)) | ||
847 | { | ||
848 | break; | ||
849 | } | ||
850 | } | ||
851 | } | ||
852 | return GATE_RESULT_OK; | ||
853 | } | ||
854 | |||
855 | #elif defined(GATE_SYS_FREEBSD) | ||
856 | |||
857 | typedef struct kinfo_proc* (*kinfo_getallproc_func_t)(int* cntp); | ||
858 | |||
859 | static void* volatile libutil = NULL; | ||
860 | |||
861 | static void close_libutil_atexit() | ||
862 | { | ||
863 | if (NULL != libutil) | ||
864 | { | ||
865 | void* handle = libutil; | ||
866 | libutil = NULL; | ||
867 | gate_posix_dlclose(handle); | ||
868 | } | ||
869 | } | ||
870 | |||
871 | static kinfo_getallproc_func_t load_getallproc() | ||
872 | { | ||
873 | if (libutil == NULL) | ||
874 | { | ||
875 | libutil = gate_posix_dlopen("libutil.so", RTLD_GLOBAL); | ||
876 | if (NULL == libutil) | ||
877 | { | ||
878 | return NULL; | ||
879 | } | ||
880 | else | ||
881 | { | ||
882 | gate_platform_atexit(&close_libutil_atexit); | ||
883 | } | ||
884 | } | ||
885 | return (kinfo_getallproc_func_t)gate_posix_dlsym(libutil, "kinfo_getallproc"); | ||
886 | } | ||
887 | |||
888 | static gate_result_t freebsd_process_enum(gate_process_enum_callback_t callback, void* userparam, gate_enumint_t flags) | ||
889 | { | ||
890 | int procs_count = 0; | ||
891 | int ndx; | ||
892 | gate_process_infobuffer_t infobuffer; | ||
893 | struct kinfo_proc* procs; | ||
894 | kinfo_getallproc_func_t kinfo_getallproc_func = load_getallproc(); | ||
895 | |||
896 | if (!kinfo_getallproc_func) | ||
897 | { | ||
898 | return GATE_RESULT_NOTSUPPORTED; | ||
899 | } | ||
900 | |||
901 | procs = kinfo_getallproc_func(&procs_count); | ||
902 | |||
903 | if (procs == NULL) | ||
904 | { | ||
905 | return GATE_RESULT_FAILED; | ||
906 | } | ||
907 | |||
908 | for (ndx = 0; ndx < procs_count; ++ndx) | ||
909 | { | ||
910 | gate_result_t result = load_process_infobuffer(&infobuffer, &procs[ndx]); | ||
911 | if (GATE_FAILED(result)) | ||
912 | { | ||
913 | continue; | ||
914 | } | ||
915 | if (!callback(&infobuffer.process, userparam)) | ||
916 | { | ||
917 | break; | ||
918 | } | ||
919 | } | ||
920 | |||
921 | free(procs); | ||
922 | return GATE_RESULT_OK; | ||
923 | } | ||
924 | |||
925 | #elif defined(GATE_SYS_OPENBSD) | ||
926 | |||
927 | static gate_result_t openbsd_process_enum(gate_process_enum_callback_t callback, void* userparam, gate_enumint_t flags) | ||
928 | { | ||
929 | gate_result_t ret = GATE_RESULT_FAILED; | ||
930 | int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), 0 }; | ||
931 | unsigned mib_len = sizeof(mib) / sizeof(mib[0]); | ||
932 | gate_process_infobuffer_t info_buffer; | ||
933 | char buffer[8192 + 4096]; | ||
934 | char* ptr_buffer = &buffer[0]; | ||
935 | size_t bufferlen = 0; | ||
936 | struct kinfo_proc* procs; | ||
937 | size_t procs_count; | ||
938 | |||
939 | do | ||
940 | { | ||
941 | /* retrieve required buffer len */ | ||
942 | if (0 != sysctl(mib, mib_len, NULL, &bufferlen, NULL, 0)) | ||
943 | { | ||
944 | GATE_DEBUG_TRACE_PLATFORM_ERROR("sysctl() failed"); | ||
945 | ret = GATE_RESULT_NOTAVAILABLE; | ||
946 | break; | ||
947 | } | ||
948 | |||
949 | if (bufferlen > sizeof(buffer)) | ||
950 | { | ||
951 | ptr_buffer = gate_mem_alloc(bufferlen); | ||
952 | if (ptr_buffer == NULL) | ||
953 | { | ||
954 | GATE_DEBUG_TRACE_MSG_VALUE("Out of memory", bufferlen); | ||
955 | ret = GATE_RESULT_OUTOFMEMORY; | ||
956 | break; | ||
957 | } | ||
958 | } | ||
959 | |||
960 | procs_count = bufferlen / sizeof(struct kinfo_proc); | ||
961 | mib[5] = procs_count; | ||
962 | |||
963 | if (0 != sysctl(mib, mib_len, ptr_buffer, &bufferlen, NULL, 0)) | ||
964 | { | ||
965 | GATE_DEBUG_TRACE_PLATFORM_ERROR("sysctl() failed"); | ||
966 | ret = GATE_RESULT_FAILED; | ||
967 | break; | ||
968 | } | ||
969 | |||
970 | procs = (struct kinfo_proc*)ptr_buffer; | ||
971 | while (procs_count-- > 0) | ||
972 | { | ||
973 | gate_result_t result = load_process_infobuffer(&info_buffer, procs); | ||
974 | if (GATE_SUCCEEDED(result) && (callback != NULL)) | ||
975 | { | ||
976 | if (!callback(&info_buffer.process, userparam)) | ||
977 | { | ||
978 | break; | ||
979 | } | ||
980 | } | ||
981 | ++procs; | ||
982 | } | ||
983 | ret = GATE_RESULT_OK; | ||
984 | } while (0); | ||
985 | |||
986 | if ((ptr_buffer != NULL) && (ptr_buffer != &buffer[0])) | ||
987 | { | ||
988 | /* free allocated memory */ | ||
989 | gate_mem_dealloc(ptr_buffer); | ||
990 | } | ||
991 | return ret; | ||
992 | } | ||
993 | |||
994 | #elif defined(GATE_SYS_NETBSD) | ||
995 | |||
996 | static gate_result_t netbsd_process_enum(gate_process_enum_callback_t callback, void* userparam, gate_enumint_t flags) | ||
997 | { | ||
998 | gate_result_t ret = GATE_RESULT_FAILED; | ||
999 | kvm_t* kvm = NULL; | ||
1000 | struct kinfo_proc2* procs = NULL; | ||
1001 | int procs_count = 0; | ||
1002 | int ndx; | ||
1003 | gate_process_infobuffer_t infobuffer; | ||
1004 | char errbuf[_POSIX2_LINE_MAX]; | ||
1005 | |||
1006 | do | ||
1007 | { | ||
1008 | ret = load_kvm_library(); | ||
1009 | GATE_BREAK_IF_FAILED(ret); | ||
1010 | |||
1011 | kvm = kvm_open_func(NULL, NULL, NULL, O_RDONLY, errbuf); | ||
1012 | if (kvm == NULL) | ||
1013 | { | ||
1014 | GATE_DEBUG_TRACE("kvm_open() failed"); | ||
1015 | errbuf[_POSIX2_LINE_MAX - 1] = 0; | ||
1016 | GATE_DEBUG_TRACE(errbuf); | ||
1017 | ret = GATE_RESULT_NOTAVAILABLE; | ||
1018 | break; | ||
1019 | } | ||
1020 | |||
1021 | procs = kvm_getproc2_func(kvm, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &procs_count); | ||
1022 | if ((procs == NULL) || (procs_count == 0)) | ||
1023 | { | ||
1024 | /* finding no processes is an error, we should at least find our own process */ | ||
1025 | GATE_DEBUG_TRACE("kvm_getprocs(KERN_PROC_ALL) failed"); | ||
1026 | ret = GATE_RESULT_FAILED; | ||
1027 | } | ||
1028 | |||
1029 | /* success case: iterator over infos */ | ||
1030 | ret = GATE_RESULT_OK; | ||
1031 | for (ndx = 0; ndx != procs_count; ++ndx, ++procs) | ||
1032 | { | ||
1033 | gate_result_t result = load_process_infobuffer(&infobuffer, procs); | ||
1034 | if (GATE_FAILED(result)) | ||
1035 | { | ||
1036 | continue; | ||
1037 | } | ||
1038 | if (callback) | ||
1039 | { | ||
1040 | if (!callback(&infobuffer.process, userparam)) | ||
1041 | { | ||
1042 | break; | ||
1043 | } | ||
1044 | } | ||
1045 | } | ||
1046 | } while (0); | ||
1047 | |||
1048 | if (kvm != NULL) | ||
1049 | { | ||
1050 | kvm_close_func(kvm); | ||
1051 | } | ||
1052 | return ret; | ||
1053 | } | ||
1054 | |||
1055 | #endif | ||
1056 | |||
1057 | #else /* Linux PROCFS */ | ||
1058 | |||
1059 | 8 | gate_result_t gate_process_getinfo(gate_process_infobuffer_t* infobuffer, gate_process_id_t proc_id, gate_enumint_t flags) | |
1060 | { | ||
1061 | 8 | gate_result_t ret = GATE_RESULT_NOTAVAILABLE; | |
1062 | gate_size_t namepos; | ||
1063 | gate_procfs_proc_stat_t proc_stat; | ||
1064 | gate_procfs_memstat_t mem_stat; | ||
1065 | gate_uint64_t page_size; | ||
1066 | gate_uint64_t ticks_per_second; | ||
1067 | gate_uint64_t starttime_after_boot_ms; | ||
1068 | gate_int64_t system_up_time_ms; | ||
1069 | gate_posix_user_info_t user_info; | ||
1070 | gate_result_t result; | ||
1071 | int proc_uid; | ||
1072 | |||
1073 | 8 | gate_mem_clear(infobuffer, sizeof(gate_process_infobuffer_t)); | |
1074 | |||
1075 | 8 | infobuffer->process.pid = proc_id; | |
1076 | |||
1077 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | if (gate_procfs_get_exe_path(proc_id, infobuffer->pathbuffer, sizeof(infobuffer->pathbuffer))) |
1078 | { | ||
1079 | 8 | infobuffer->process.path = infobuffer->pathbuffer; | |
1080 | 8 | ret = GATE_RESULT_OK; | |
1081 | } | ||
1082 | |||
1083 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | if (gate_procfs_load_proc_stat(proc_id, &proc_stat)) |
1084 | { | ||
1085 | 8 | infobuffer->process.parent_pid = proc_stat.ppid; | |
1086 | |||
1087 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (GATE_FLAG_ENABLED(flags, GATE_PROCESS_ENUM_TIMES)) |
1088 | { | ||
1089 | 8 | ticks_per_second = (gate_uint64_t)sysconf(_SC_CLK_TCK); | |
1090 | 8 | starttime_after_boot_ms = (gate_int64_t)proc_stat.starttime * 1000ULL / ticks_per_second; | |
1091 | |||
1092 | 8 | system_up_time_ms = gate_procfs_get_uptime_ms(); | |
1093 | |||
1094 | 8 | infobuffer->process.uptime = system_up_time_ms - starttime_after_boot_ms; | |
1095 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (infobuffer->process.uptime < 0) infobuffer->process.uptime = 0; |
1096 | 8 | infobuffer->process.cputime = (gate_uint64_t)(proc_stat.utime + proc_stat.stime) * 1000ULL / ticks_per_second; | |
1097 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (infobuffer->process.cputime < 0) infobuffer->process.cputime = 0; |
1098 | } | ||
1099 | 8 | ret = GATE_RESULT_OK; | |
1100 | } | ||
1101 | |||
1102 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (GATE_FLAG_ENABLED(flags, GATE_PROCESS_ENUM_NAME)) |
1103 | { | ||
1104 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (infobuffer->process.path != NULL) |
1105 | { | ||
1106 | 8 | namepos = gate_str_char_pos_last(infobuffer->process.path, gate_str_length(infobuffer->process.path), '/'); | |
1107 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (namepos != GATE_STR_NPOS) |
1108 | { | ||
1109 | 8 | infobuffer->process.name = &infobuffer->process.path[namepos + 1]; | |
1110 | } | ||
1111 | } | ||
1112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (infobuffer->process.name == NULL) |
1113 | { | ||
1114 | ✗ | gate_str_print_uint64(infobuffer->namebuffer, sizeof(infobuffer->namebuffer), proc_id); | |
1115 | ✗ | infobuffer->process.name = infobuffer->namebuffer; | |
1116 | } | ||
1117 | } | ||
1118 | |||
1119 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (GATE_FLAG_ENABLED(flags, GATE_PROCESS_ENUM_OWNER)) |
1120 | { | ||
1121 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | if (gate_procfs_get_exe_owner(proc_id, &proc_uid, NULL)) |
1122 | { | ||
1123 | 8 | result = gate_posix_get_user_info(proc_uid, &user_info); | |
1124 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (GATE_SUCCEEDED(result)) |
1125 | { | ||
1126 | 8 | gate_str_print_text(infobuffer->ownerbuffer, sizeof(infobuffer->ownerbuffer), | |
1127 | user_info.name, gate_str_length(user_info.name)); | ||
1128 | 8 | infobuffer->process.owner = infobuffer->ownerbuffer; | |
1129 | } | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (GATE_FLAG_ENABLED(flags, GATE_PROCESS_ENUM_MEMORY)) |
1134 | { | ||
1135 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | if (gate_procfs_get_memstat(proc_id, &mem_stat)) |
1136 | { | ||
1137 | 8 | page_size = sysconf(_SC_PAGESIZE); | |
1138 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (page_size == 0) |
1139 | { | ||
1140 | ✗ | page_size = 4096; | |
1141 | } | ||
1142 | 8 | infobuffer->process.memory_used = (gate_uint64_t)mem_stat.resident * page_size; | |
1143 | } | ||
1144 | } | ||
1145 | |||
1146 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (GATE_FLAG_ENABLED(flags, GATE_PROCESS_ENUM_RESOURCES)) |
1147 | { | ||
1148 | 8 | infobuffer->process.resources = gate_procfs_get_open_fds(proc_id); | |
1149 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (infobuffer->process.resources < 0) infobuffer->process.resources = 0; |
1150 | } | ||
1151 | |||
1152 | 8 | return ret; | |
1153 | } | ||
1154 | |||
1155 | #endif | ||
1156 | |||
1157 | 1 | gate_result_t gate_process_enum(gate_process_enum_callback_t callback, void* userparam, gate_enumint_t flags) | |
1158 | { | ||
1159 | 1 | gate_result_t ret = GATE_RESULT_FAILED; | |
1160 | DIR* dir; | ||
1161 | |||
1162 | #if defined(GATE_SYS_DARWIN) | ||
1163 | ret = darwin_process_enum(callback, userparam, flags); | ||
1164 | #elif defined(GATE_SYS_BSD) | ||
1165 | |||
1166 | #if defined(GATE_SYS_FREEBSD) | ||
1167 | ret = freebsd_process_enum(callback, userparam, flags); | ||
1168 | #elif defined(GATE_SYS_OPENBSD) | ||
1169 | ret = openbsd_process_enum(callback, userparam, flags); | ||
1170 | #elif defined(GATE_SYS_NETBSD) | ||
1171 | ret = netbsd_process_enum(callback, userparam, flags); | ||
1172 | #endif | ||
1173 | |||
1174 | if (GATE_SUCCEEDED(ret)) | ||
1175 | { | ||
1176 | /* we have a result, we are done */ | ||
1177 | return GATE_RESULT_OK; | ||
1178 | } | ||
1179 | /* otherwise, continue with linux/procfs approach */ | ||
1180 | |||
1181 | #endif /* GATE_SYS_BSD */ | ||
1182 | |||
1183 | /* linux procfs: */ | ||
1184 | 1 | dir = opendir("/proc"); | |
1185 | |||
1186 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (dir != NULL) |
1187 | { | ||
1188 | struct dirent* entry; | ||
1189 |
2/2✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1 times.
|
66 | while (NULL != (entry = readdir(dir))) |
1190 | { | ||
1191 | gate_process_infobuffer_t proc_data; | ||
1192 | 65 | gate_uint64_t procid = 0; | |
1193 | 65 | gate_size_t entrylen = gate_str_length(entry->d_name); | |
1194 | 65 | gate_size_t parselen = gate_str_parse_uint64(entry->d_name, entrylen, &procid); | |
1195 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 58 times.
|
65 | if (parselen == entrylen) |
1196 | { | ||
1197 | /* seems to be a numeric process id */ | ||
1198 | 7 | ret = gate_process_getinfo(&proc_data, (gate_process_id_t)procid, flags); | |
1199 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | if (GATE_SUCCEEDED(ret)) |
1200 | { | ||
1201 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if (false == callback(&proc_data.process, userparam)) |
1202 | { | ||
1203 | ✗ | break; | |
1204 | } | ||
1205 | } | ||
1206 | } | ||
1207 | } | ||
1208 | 1 | closedir(dir); | |
1209 | 1 | ret = GATE_RESULT_OK; | |
1210 | } | ||
1211 | 1 | return ret; | |
1212 | } | ||
1213 | |||
1214 | |||
1215 | 2 | gate_result_t gate_process_start(gate_string_t const* executablepath, | |
1216 | gate_string_t const* args, gate_size_t argcount, | ||
1217 | gate_string_t const* workdir, gate_string_t const* envvars, gate_size_t envvarcount, gate_enumint_t flags, | ||
1218 | gate_process_handle_t* result_handle, | ||
1219 | gate_process_id_t* result_pid, | ||
1220 | gate_process_stream_t** result_stream | ||
1221 | ) | ||
1222 | { | ||
1223 | 2 | return gate_process_start_ex(executablepath, args, argcount, | |
1224 | workdir, envvars, envvarcount, flags, | ||
1225 | NULL, NULL, NULL, | ||
1226 | result_handle, result_pid, result_stream); | ||
1227 | } | ||
1228 | |||
1229 | |||
1230 | 4 | static char* gate_process_build_argarray(gate_string_t const* args, gate_size_t argcount, char** buffer, gate_size_t maxargs) | |
1231 | { | ||
1232 | char* ret; | ||
1233 | char* ptr; | ||
1234 | gate_size_t ndx; | ||
1235 | 4 | gate_size_t byte_size = 0; | |
1236 | gate_size_t len; | ||
1237 | 4 | gate_size_t buffer_ndx = 0; | |
1238 | |||
1239 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (argcount >= maxargs) argcount = maxargs - 1; |
1240 | |||
1241 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | for (ndx = 0; ndx < argcount; ++ndx) |
1242 | { | ||
1243 | 2 | byte_size += args[ndx].length + 1; | |
1244 | } | ||
1245 | 4 | byte_size += 2; | |
1246 | |||
1247 | 4 | ret = gate_mem_alloc(byte_size); | |
1248 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (ret != NULL) |
1249 | { | ||
1250 | 4 | ptr = ret; | |
1251 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | for (ndx = 0; ndx < argcount; ++ndx) |
1252 | { | ||
1253 | 2 | len = gate_str_print_text(ptr, args[ndx].length + 1, args[ndx].str, args[ndx].length); | |
1254 | 2 | buffer[buffer_ndx++] = ptr; | |
1255 | 2 | ptr += (len + 1); | |
1256 | } | ||
1257 | 4 | ptr[0] = 0; | |
1258 | 4 | buffer[buffer_ndx] = NULL; | |
1259 | } | ||
1260 | 4 | return ret; | |
1261 | } | ||
1262 | |||
1263 | 2 | static int gate_get_open_max(void) | |
1264 | { | ||
1265 | #ifdef OPEN_MAX | ||
1266 | return OPEN_MAX; | ||
1267 | #else | ||
1268 | static volatile int cached_max = 0; | ||
1269 | long cnf_open_max; | ||
1270 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (cached_max == 0) |
1271 | { | ||
1272 | 2 | cnf_open_max = sysconf(_SC_OPEN_MAX); | |
1273 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (cnf_open_max <= 0) |
1274 | { | ||
1275 | ✗ | cached_max = 1024; | |
1276 | } | ||
1277 | else | ||
1278 | { | ||
1279 | 2 | cached_max = (int)cnf_open_max; | |
1280 | } | ||
1281 | } | ||
1282 | 2 | return cached_max; | |
1283 | #endif | ||
1284 | } | ||
1285 | |||
1286 | |||
1287 | 2 | static void close_private_file_descriptor(gate_bool_t exclude_inheritable_fds, int preserved_fd) | |
1288 | { | ||
1289 | int inheritable_fds[1024]; | ||
1290 | 2 | gate_size_t inheritable_count = 0; | |
1291 | 2 | int fd_max = gate_get_open_max(); | |
1292 | int fd; | ||
1293 | size_t index; | ||
1294 | 2 | gate_bool_t exclude_fd = false; | |
1295 | |||
1296 | 2 | inheritable_fds[0] = preserved_fd; | |
1297 | 2 | inheritable_count = 1; | |
1298 | |||
1299 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (exclude_inheritable_fds) |
1300 | { | ||
1301 | 2 | inheritable_count = gate_posix_get_inheritable_fds( | |
1302 | &inheritable_fds[1], sizeof(inheritable_fds) / sizeof(inheritable_fds[0]) - 1); | ||
1303 | 2 | ++inheritable_count; | |
1304 | } | ||
1305 | |||
1306 | |||
1307 |
2/2✓ Branch 0 taken 2097146 times.
✓ Branch 1 taken 2 times.
|
2097148 | for (fd = STDERR_FILENO + 1; fd < fd_max; ++fd) |
1308 | { | ||
1309 | 2097146 | exclude_fd = false; | |
1310 |
2/2✓ Branch 0 taken 2097146 times.
✓ Branch 1 taken 2097144 times.
|
4194290 | for (index = 0; index != inheritable_count; ++index) |
1311 | { | ||
1312 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2097144 times.
|
2097146 | if (fd == inheritable_fds[index]) |
1313 | { | ||
1314 | 2 | exclude_fd = true; | |
1315 | 2 | break; | |
1316 | } | ||
1317 | } | ||
1318 |
2/2✓ Branch 0 taken 2097144 times.
✓ Branch 1 taken 2 times.
|
2097146 | if (!exclude_fd) |
1319 | { | ||
1320 | 2097144 | gate_posix_close(fd); | |
1321 | } | ||
1322 | } | ||
1323 | 2 | } | |
1324 | |||
1325 | ✗ | static gate_result_t gate_process_switch_user(char const* username) | |
1326 | { | ||
1327 | gate_result_t ret; | ||
1328 | gate_posix_user_info_t user_info; | ||
1329 | int result; | ||
1330 | |||
1331 | do | ||
1332 | { | ||
1333 | ✗ | ret = gate_posix_resolve_user_info(username, &user_info); | |
1334 | ✗ | GATE_BREAK_IF_FAILED(ret); | |
1335 | |||
1336 | ✗ | result = initgroups(user_info.name, user_info.gid); | |
1337 | ✗ | if (-1 == result) | |
1338 | { | ||
1339 | ✗ | GATE_DEBUG_TRACE_MSG_VALUE("initgroups failed()", gate_posix_errno(NULL)); | |
1340 | } | ||
1341 | |||
1342 | ✗ | result = setgid(user_info.gid); | |
1343 | ✗ | if (result != 0) | |
1344 | { | ||
1345 | ✗ | GATE_DEBUG_TRACE_MSG_VALUE("setgid failed()", gate_posix_errno(NULL)); | |
1346 | ✗ | ret = gate_platform_print_last_error(NULL, 0); | |
1347 | ✗ | break; | |
1348 | } | ||
1349 | |||
1350 | ✗ | result = setuid(user_info.uid); | |
1351 | ✗ | if (result != 0) | |
1352 | { | ||
1353 | ✗ | GATE_DEBUG_TRACE_MSG_VALUE("setuid failed()", gate_posix_errno(NULL)); | |
1354 | ✗ | ret = gate_platform_print_last_error(NULL, 0); | |
1355 | ✗ | break; | |
1356 | } | ||
1357 | ✗ | ret = GATE_RESULT_OK; | |
1358 | } while (0); | ||
1359 | |||
1360 | ✗ | return ret; | |
1361 | } | ||
1362 | |||
1363 | typedef int(*openpty_func_t)(int* amaster, int* aslave, char const* name, struct termios const* termp, struct winsize const* winp); | ||
1364 | typedef int(*login_tty_func_t)(int fd); | ||
1365 | |||
1366 | static openpty_func_t openpty_func; | ||
1367 | static login_tty_func_t login_tty_func; | ||
1368 | |||
1369 | ✗ | static gate_bool_t are_pty_functions_loaded() | |
1370 | { | ||
1371 | ✗ | return (openpty_func != NULL) && (login_tty_func != NULL); | |
1372 | } | ||
1373 | |||
1374 | ✗ | static gate_bool_t try_load_pty_functions(void* libhandle) | |
1375 | { | ||
1376 | ✗ | openpty_func = (openpty_func_t)gate_posix_dlsym(libhandle, "openpty"); | |
1377 | ✗ | login_tty_func = (login_tty_func_t)gate_posix_dlsym(libhandle, "login_tty"); | |
1378 | ✗ | return are_pty_functions_loaded(); | |
1379 | } | ||
1380 | |||
1381 | static char const* util_libs[] = | ||
1382 | { | ||
1383 | "libutil.so", | ||
1384 | "libutil.so.1" | ||
1385 | }; | ||
1386 | static unsigned const util_libs_count = sizeof(util_libs) / sizeof(util_libs[0]); | ||
1387 | |||
1388 | static void* volatile pty_lib_handle = NULL; | ||
1389 | |||
1390 | ✗ | static void close_pty_lib_atexit() | |
1391 | { | ||
1392 | ✗ | if (NULL != pty_lib_handle) | |
1393 | { | ||
1394 | ✗ | void* handle = pty_lib_handle; | |
1395 | ✗ | pty_lib_handle = NULL; | |
1396 | ✗ | gate_posix_dlclose(handle); | |
1397 | } | ||
1398 | ✗ | } | |
1399 | |||
1400 | ✗ | static gate_bool_t load_pty_functions() | |
1401 | { | ||
1402 | ✗ | if (are_pty_functions_loaded()) | |
1403 | { | ||
1404 | ✗ | return true; | |
1405 | } | ||
1406 | |||
1407 | ✗ | openpty_func = (openpty_func_t)gate_posix_global_sym("openpty"); | |
1408 | ✗ | login_tty_func = (login_tty_func_t)gate_posix_global_sym("login_tty"); | |
1409 | ✗ | if (are_pty_functions_loaded()) | |
1410 | { | ||
1411 | ✗ | return true; | |
1412 | } | ||
1413 | |||
1414 | unsigned ndx; | ||
1415 | ✗ | for (ndx = 0; ndx != util_libs_count; ++ndx) | |
1416 | { | ||
1417 | ✗ | void* lib_handle = gate_posix_dlopen(util_libs[ndx], RTLD_GLOBAL); | |
1418 | ✗ | if (lib_handle) | |
1419 | { | ||
1420 | ✗ | if (try_load_pty_functions(lib_handle)) | |
1421 | { | ||
1422 | ✗ | pty_lib_handle = lib_handle; | |
1423 | ✗ | gate_platform_atexit(&close_pty_lib_atexit); | |
1424 | ✗ | return true; | |
1425 | } | ||
1426 | else | ||
1427 | { | ||
1428 | ✗ | gate_posix_dlclose(lib_handle); | |
1429 | } | ||
1430 | } | ||
1431 | } | ||
1432 | ✗ | return false; | |
1433 | } | ||
1434 | |||
1435 | 2 | static gate_result_t gate_process_exec(gate_string_t const* executablepath, gate_string_t const* args, gate_size_t argcount, | |
1436 | gate_string_t const* workdir, gate_string_t const* envvars, gate_size_t envvarcount, gate_enumint_t flags, | ||
1437 | char const* sessionlocation, | ||
1438 | char const* username, char const* password, int preserved_fd, | ||
1439 | int* ptr_tty_fd, | ||
1440 | int* new_std_in, int* new_std_out, int* new_std_err | ||
1441 | ) | ||
1442 | { | ||
1443 | 2 | gate_result_t ret = GATE_RESULT_FAILED; | |
1444 | int result; | ||
1445 | char* process_args[256]; | ||
1446 | char* process_vars[256]; | ||
1447 | char new_work_dir[GATE_MAX_FILEPATH_LENGTH]; | ||
1448 | char exe_path[GATE_MAX_FILEPATH_LENGTH]; | ||
1449 | 2 | char* process_args_buffer = NULL; | |
1450 | 2 | char* process_vars_buffer = NULL; | |
1451 | |||
1452 | do | ||
1453 | { | ||
1454 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (!gate_string_is_empty(workdir)) |
1455 | { | ||
1456 | 2 | GATE_STRING_TO_BUFFER(workdir, new_work_dir); | |
1457 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (-1 == chdir(new_work_dir)) |
1458 | { | ||
1459 | ✗ | ret = GATE_RESULT_INVALIDINPUT; | |
1460 | ✗ | break; | |
1461 | } | ||
1462 | } | ||
1463 | |||
1464 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (!gate_str_is_empty(username)) |
1465 | { | ||
1466 | ✗ | ret = gate_process_switch_user(username); | |
1467 | ✗ | GATE_BREAK_IF_FAILED(ret); | |
1468 | } | ||
1469 | |||
1470 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (GATE_FLAG_ENABLED(flags, GATE_PROCESS_START_NEWSESSION)) |
1471 | { | ||
1472 | ✗ | result = setsid(); | |
1473 | ✗ | if (result != 0) | |
1474 | { | ||
1475 | ✗ | GATE_DEBUG_TRACE_MSG_VALUE("setsid() failed", gate_posix_errno(NULL)); | |
1476 | ✗ | ret = GATE_RESULT_FAILED; | |
1477 | ✗ | break; | |
1478 | } | ||
1479 | } | ||
1480 | |||
1481 | 2 | process_args_buffer = gate_process_build_argarray(args, argcount, &process_args[1], sizeof(process_args) / sizeof(process_args[0]) - 1); | |
1482 | 2 | process_vars_buffer = gate_process_build_argarray(envvars, envvarcount, process_vars, sizeof(process_vars) / sizeof(process_vars[0])); | |
1483 | |||
1484 | 2 | GATE_STRING_TO_BUFFER(executablepath, exe_path); | |
1485 | 2 | process_args[0] = exe_path; | |
1486 | |||
1487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ptr_tty_fd) |
1488 | { | ||
1489 | /* login to terminal and set STD* to terminal fd */ | ||
1490 | ✗ | if (login_tty_func(*ptr_tty_fd) == -1) | |
1491 | { | ||
1492 | ✗ | GATE_DEBUG_TRACE_MSG_VALUE("login_tty() failed", gate_posix_errno(NULL)); | |
1493 | ✗ | ret = GATE_RESULT_FAILED; | |
1494 | ✗ | break; | |
1495 | } | ||
1496 | } | ||
1497 | else | ||
1498 | { | ||
1499 | /* redirect parent-pipes to STD* fds */ | ||
1500 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (new_std_in) |
1501 | { | ||
1502 | 1 | dup2(*new_std_in, STDIN_FILENO); | |
1503 | 1 | close(*new_std_in); | |
1504 | } | ||
1505 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (new_std_out) |
1506 | { | ||
1507 | 1 | dup2(*new_std_out, STDOUT_FILENO); | |
1508 | 1 | close(*new_std_out); | |
1509 | } | ||
1510 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (new_std_err) |
1511 | { | ||
1512 | 1 | dup2(*new_std_err, STDERR_FILENO); | |
1513 | 1 | close(*new_std_err); | |
1514 | } | ||
1515 | } | ||
1516 | |||
1517 | 2 | close_private_file_descriptor(!GATE_FLAG_ENABLED(flags, GATE_PROCESS_START_NOINHERIT), preserved_fd); | |
1518 | |||
1519 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (envvars) |
1520 | { | ||
1521 | ✗ | execve(exe_path, process_args, process_vars); | |
1522 | } | ||
1523 | else | ||
1524 | { | ||
1525 | 2 | execv(exe_path, process_args); | |
1526 | } | ||
1527 | |||
1528 | 2 | ret = GATE_RESULT_UNKNOWNERROR; | |
1529 | |||
1530 | } while (0); | ||
1531 | |||
1532 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (process_args_buffer) |
1533 | { | ||
1534 | ✗ | gate_mem_dealloc(process_args_buffer); | |
1535 | } | ||
1536 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (process_vars_buffer) |
1537 | { | ||
1538 | ✗ | gate_mem_dealloc(process_vars_buffer); | |
1539 | } | ||
1540 | ✗ | return ret; | |
1541 | } | ||
1542 | |||
1543 | |||
1544 | #define INVALID_FD (-1) | ||
1545 | |||
1546 | 22 | static void close_valid_fd(int fd) | |
1547 | { | ||
1548 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 19 times.
|
22 | if (fd != INVALID_FD) |
1549 | { | ||
1550 | 3 | close(fd); | |
1551 | } | ||
1552 | 22 | } | |
1553 | |||
1554 | 2 | gate_result_t gate_process_start_ex(gate_string_t const* executablepath, | |
1555 | gate_string_t const* args, gate_size_t argcount, | ||
1556 | gate_string_t const* workdir, gate_string_t const* envvars, gate_size_t envvarcount, gate_enumint_t flags, | ||
1557 | char const* sessionlocation, | ||
1558 | char const* username, char const* password, | ||
1559 | gate_process_handle_t* result_handle, | ||
1560 | gate_process_id_t* result_pid, | ||
1561 | gate_process_stream_t** result_stream | ||
1562 | ) | ||
1563 | { | ||
1564 | 2 | gate_result_t ret = GATE_RESULT_FAILED; | |
1565 | 2 | int failpipes[2] = { INVALID_FD, INVALID_FD }; | |
1566 | 2 | int std_in_pipe[2] = { INVALID_FD, INVALID_FD }; /* stdin of child process */ | |
1567 | 2 | int std_out_pipe[2] = { INVALID_FD, INVALID_FD }; /* stdout of child process */ | |
1568 | 2 | int std_err_pipe[2] = { INVALID_FD, INVALID_FD }; /* stderr of child process */ | |
1569 | 2 | pid_t process_id = -1; | |
1570 | 2 | int term_master = INVALID_FD; | |
1571 | 2 | int term_slave = INVALID_FD; | |
1572 | char term_slave_name[1024]; | ||
1573 | 2 | char const* ptr_term_slave_name = NULL; | |
1574 | 2 | gate_process_stream_t* proc_stream = NULL; | |
1575 | |||
1576 | 2 | int status = 0; | |
1577 | ssize_t readlen; | ||
1578 | ssize_t writelen; | ||
1579 | 2 | gate_result_t process_exec_error = 0; | |
1580 | |||
1581 | do | ||
1582 | { | ||
1583 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (result_stream) |
1584 | { | ||
1585 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (GATE_FLAG_ENABLED(flags, GATE_PROCESS_START_NEWTERMINAL)) |
1586 | { | ||
1587 | /* child process will run in a pseudo terminal, parent controls master-side */ | ||
1588 | ✗ | if (!load_pty_functions()) | |
1589 | { | ||
1590 | ✗ | ret = GATE_RESULT_NOTSUPPORTED; | |
1591 | ✗ | break; | |
1592 | } | ||
1593 | ✗ | if (openpty_func(&term_master, &term_slave, term_slave_name, NULL, NULL) == -1) | |
1594 | { | ||
1595 | ✗ | ret = GATE_RESULT_OUTOFRESOURCES; | |
1596 | ✗ | break; | |
1597 | } | ||
1598 | ✗ | ptr_term_slave_name = &term_slave_name[0]; | |
1599 | |||
1600 | /* parent process read/write ends are set to terminal-master */ | ||
1601 | ✗ | std_in_pipe[1] = term_master; | |
1602 | ✗ | std_out_pipe[0] = dup(term_master); | |
1603 | ✗ | std_err_pipe[0] = dup(term_master); | |
1604 | ✗ | term_master = INVALID_FD; | |
1605 | } | ||
1606 | else | ||
1607 | { | ||
1608 | /* child process i/o will be directed to pipes controlled by parent */ | ||
1609 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (pipe(std_in_pipe) != 0) |
1610 | { | ||
1611 | ✗ | ret = GATE_RESULT_OUTOFRESOURCES; | |
1612 | ✗ | break; | |
1613 | } | ||
1614 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (pipe(std_out_pipe) != 0) |
1615 | { | ||
1616 | ✗ | ret = GATE_RESULT_OUTOFRESOURCES; | |
1617 | ✗ | break; | |
1618 | } | ||
1619 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (GATE_FLAG_ENABLED(flags, GATE_PROCESS_START_USESTDERR)) |
1620 | { | ||
1621 | ✗ | if (pipe(std_err_pipe) != 0) | |
1622 | { | ||
1623 | ✗ | ret = GATE_RESULT_OUTOFRESOURCES; | |
1624 | ✗ | break; | |
1625 | } | ||
1626 | } | ||
1627 | else | ||
1628 | { | ||
1629 | 1 | std_err_pipe[0] = dup(std_out_pipe[0]); | |
1630 | 1 | std_err_pipe[1] = dup(std_out_pipe[1]); | |
1631 | } | ||
1632 | } | ||
1633 | |||
1634 | 1 | proc_stream = gate_process_stream_create(std_in_pipe[1], std_out_pipe[0], std_err_pipe[0]); | |
1635 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!proc_stream) |
1636 | { | ||
1637 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
1638 | ✗ | break; | |
1639 | } | ||
1640 | /* fds are now handled by stream object */ | ||
1641 | 1 | std_in_pipe[1] = INVALID_FD; | |
1642 | 1 | std_out_pipe[0] = INVALID_FD; | |
1643 | 1 | std_err_pipe[0] = INVALID_FD; | |
1644 | } | ||
1645 | |||
1646 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (pipe(failpipes) != 0) |
1647 | { | ||
1648 | ✗ | ret = GATE_RESULT_OUTOFRESOURCES; | |
1649 | ✗ | break; | |
1650 | } | ||
1651 | |||
1652 | 2 | process_id = fork(); | |
1653 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (process_id == -1) |
1654 | { | ||
1655 | /* fork has failed */ | ||
1656 | ✗ | ret = GATE_RESULT_EXECUTIONFAILED; | |
1657 | ✗ | break; | |
1658 | } | ||
1659 | |||
1660 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (process_id == 0) |
1661 | { | ||
1662 | /* child process */ | ||
1663 | 2 | close(failpipes[0]); /* close read descriptor of fail-detector-pipe */ | |
1664 | 2 | failpipes[0] = INVALID_FD; | |
1665 | 2 | fcntl(failpipes[1], F_SETFD, FD_CLOEXEC); /* auto-close on-exec on write descriptor of fail-detector-pipe */ | |
1666 | |||
1667 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
|
4 | process_exec_error = gate_process_exec( |
1668 | executablepath, args, argcount, workdir, envvars, envvarcount, flags, | ||
1669 | sessionlocation, username, password, | ||
1670 | failpipes[1], /* exclude failpipe from auto-close */ | ||
1671 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | (term_slave != INVALID_FD) ? &term_slave : NULL, /* use terminal-slave fd if available */ |
1672 | result_stream ? &std_in_pipe[0] : NULL, /* redirect std-in */ | ||
1673 | result_stream ? &std_out_pipe[1] : NULL, /* redirect std-out */ | ||
1674 | result_stream ? &std_err_pipe[1] : NULL /* redirect std-err */ | ||
1675 | ); | ||
1676 | |||
1677 | ✗ | writelen = write(failpipes[1], &process_exec_error, sizeof(process_exec_error)); | |
1678 | ✗ | _exit(GATE_RESULT_TO_EXITCODE(process_exec_error)); | |
1679 | ret = GATE_RESULT_UNKNOWNERROR; | ||
1680 | break; | ||
1681 | } | ||
1682 | |||
1683 | /* parent process */ | ||
1684 | 2 | close_valid_fd(term_slave); | |
1685 | 2 | term_slave = INVALID_FD; | |
1686 | |||
1687 | 2 | close(failpipes[1]); /* close write descriptor of fail-detector-pipe*/ | |
1688 | 2 | failpipes[1] = INVALID_FD; | |
1689 | |||
1690 | 2 | readlen = read(failpipes[0], &process_exec_error, sizeof(process_exec_error)); | |
1691 | 2 | close(failpipes[0]); | |
1692 | 2 | failpipes[0] = INVALID_FD; | |
1693 | |||
1694 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (readlen > 0) |
1695 | { | ||
1696 | /* child process has failed to prepare exec */ | ||
1697 | ✗ | ret = process_exec_error; | |
1698 | } | ||
1699 | else | ||
1700 | { | ||
1701 | /* when reading from 'failpipe' fails, then everything seems to be OK */ | ||
1702 | |||
1703 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (result_stream) |
1704 | { | ||
1705 | 1 | *result_stream = proc_stream; | |
1706 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (proc_stream) |
1707 | { | ||
1708 | 1 | ((gate_process_stream_impl_t*)proc_stream)->target_pid = process_id; | |
1709 | 1 | gate_object_retain(proc_stream); | |
1710 | } | ||
1711 | } | ||
1712 | |||
1713 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (result_pid != NULL) |
1714 | { | ||
1715 | 1 | *result_pid = (gate_process_id_t)process_id; | |
1716 | } | ||
1717 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (result_handle != NULL) |
1718 | { | ||
1719 | 2 | *result_handle = (gate_process_handle_t)(gate_intptr_t)process_id; | |
1720 | 2 | process_id = 0; /* protect process_id from being cleaned up */ | |
1721 | } | ||
1722 | |||
1723 | 2 | ret = GATE_RESULT_OK; | |
1724 | } | ||
1725 | } while (0); | ||
1726 | |||
1727 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (process_id > 0) |
1728 | { | ||
1729 | /* detach process */ | ||
1730 | ✗ | waitpid(process_id, &status, WNOHANG); | |
1731 | } | ||
1732 | |||
1733 | 2 | close_valid_fd(failpipes[1]); | |
1734 | 2 | close_valid_fd(failpipes[0]); | |
1735 | 2 | close_valid_fd(std_in_pipe[1]); | |
1736 | 2 | close_valid_fd(std_in_pipe[0]); | |
1737 | 2 | close_valid_fd(std_out_pipe[1]); | |
1738 | 2 | close_valid_fd(std_out_pipe[0]); | |
1739 | 2 | close_valid_fd(std_err_pipe[1]); | |
1740 | 2 | close_valid_fd(std_err_pipe[0]); | |
1741 | 2 | close_valid_fd(term_master); | |
1742 | 2 | close_valid_fd(term_slave); | |
1743 | |||
1744 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (proc_stream) |
1745 | { | ||
1746 | 1 | gate_object_release(proc_stream); | |
1747 | } | ||
1748 | |||
1749 | 2 | return ret; | |
1750 | } | ||
1751 | 2 | gate_result_t gate_process_close(gate_process_handle_t* handle) | |
1752 | { | ||
1753 | gate_result_t ret; | ||
1754 | pid_t pid; | ||
1755 | int status; | ||
1756 | pid_t result; | ||
1757 | |||
1758 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (!handle || (*handle == GATE_PROCESS_HANDLE_INVALID)) |
1759 | { | ||
1760 | ✗ | ret = GATE_RESULT_OK; | |
1761 | } | ||
1762 | else | ||
1763 | { | ||
1764 | 2 | pid = (pid_t)(gate_intptr_t)*handle; | |
1765 | 2 | result = waitpid(pid, &status, WNOHANG); | |
1766 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (result == -1) |
1767 | { | ||
1768 | ✗ | ret = GATE_RESULT_FAILED; | |
1769 | } | ||
1770 | else | ||
1771 | { | ||
1772 | 2 | *handle = GATE_PROCESS_HANDLE_INVALID; | |
1773 | 2 | ret = GATE_RESULT_OK; | |
1774 | } | ||
1775 | } | ||
1776 | |||
1777 | 2 | return ret; | |
1778 | } | ||
1779 | 1 | gate_result_t gate_process_get_exitcode(gate_process_handle_t* handle, int* exitcode) | |
1780 | { | ||
1781 | 1 | gate_result_t ret = GATE_RESULT_FAILED; | |
1782 | pid_t pid; | ||
1783 | 1 | siginfo_t si = GATE_INIT_EMPTY; | |
1784 | int result; | ||
1785 | int status; | ||
1786 | gate_timecounter_t tcbegin, tcnow; | ||
1787 | gate_int64_t timediff; | ||
1788 | gate_int64_t timeoutus; | ||
1789 | gate_uint32_t sleepcounter; | ||
1790 | |||
1791 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!handle || (*handle == GATE_PROCESS_HANDLE_INVALID)) |
1792 | { | ||
1793 | ✗ | return GATE_RESULT_INVALIDSTATE; | |
1794 | } | ||
1795 | |||
1796 | 1 | pid = (pid_t)(gate_intptr_t)*handle; | |
1797 | |||
1798 | #if defined(GATE_SYS_OPENBSD) | ||
1799 | result = waitpid(pid, &status, WNOHANG); | ||
1800 | if (-1 == result) | ||
1801 | { | ||
1802 | return GATE_RESULT_FAILED; | ||
1803 | } | ||
1804 | if (!WIFEXITED(status)) | ||
1805 | { | ||
1806 | return GATE_RESULT_INVALIDSTATE; | ||
1807 | } | ||
1808 | if (exitcode) | ||
1809 | { | ||
1810 | *exitcode = WEXITSTATUS(status); | ||
1811 | } | ||
1812 | *handle = GATE_PROCESS_HANDLE_INVALID; | ||
1813 | return GATE_RESULT_OK; | ||
1814 | #else | ||
1815 | 1 | result = waitid(P_PID, pid, &si, WEXITED | WNOWAIT | WNOHANG); | |
1816 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (result != 0) |
1817 | { | ||
1818 | ✗ | return GATE_RESULT_NOTAVAILABLE; | |
1819 | } | ||
1820 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (si.si_pid != pid) |
1821 | { | ||
1822 | ✗ | return GATE_RESULT_NOTAVAILABLE; | |
1823 | } | ||
1824 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (exitcode) |
1825 | { | ||
1826 | 1 | *exitcode = si.si_status; | |
1827 | } | ||
1828 | 1 | return GATE_RESULT_OK; | |
1829 | #endif | ||
1830 | } | ||
1831 | |||
1832 | 1 | gate_result_t gate_process_wait(gate_process_handle_t* handle, gate_uint32_t timeoutms) | |
1833 | { | ||
1834 | 1 | gate_result_t ret = GATE_RESULT_FAILED; | |
1835 | pid_t pid; | ||
1836 | siginfo_t si; | ||
1837 | int result; | ||
1838 | int status; | ||
1839 | gate_timecounter_t tcbegin, tcnow; | ||
1840 | gate_int64_t timediff; | ||
1841 | gate_int64_t timeoutus; | ||
1842 | gate_uint32_t sleepcounter; | ||
1843 | |||
1844 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!handle || (*handle == GATE_PROCESS_HANDLE_INVALID)) |
1845 | { | ||
1846 | ✗ | return GATE_RESULT_INVALIDSTATE; | |
1847 | } | ||
1848 | |||
1849 | 1 | pid = (pid_t)(gate_intptr_t)*handle; | |
1850 | |||
1851 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (timeoutms == GATE_PROCESS_WAIT_INFINITE) |
1852 | { | ||
1853 | #if defined(GATE_SYS_OPENBSD) | ||
1854 | result = waitpid(pid, &status, 0); | ||
1855 | *handle = GATE_PROCESS_HANDLE_INVALID; | ||
1856 | #else | ||
1857 | 1 | result = waitid(P_PID, pid, &si, WEXITED | WNOWAIT); | |
1858 | #endif | ||
1859 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (result == 0) |
1860 | { | ||
1861 | 1 | ret = GATE_RESULT_OK; | |
1862 | } | ||
1863 | else | ||
1864 | { | ||
1865 | ✗ | gate_posix_errno(&ret); | |
1866 | } | ||
1867 | } | ||
1868 | else | ||
1869 | { | ||
1870 | ✗ | if (GATE_SUCCEEDED(gate_timecounter_now(&tcbegin))) | |
1871 | { | ||
1872 | ✗ | ret = GATE_RESULT_TIMEOUT; | |
1873 | ✗ | sleepcounter = 0; | |
1874 | ✗ | timeoutus = (gate_int64_t)timeoutms * 1000LL; | |
1875 | do | ||
1876 | { | ||
1877 | #if defined(GATE_SYS_OPENBSD) | ||
1878 | result = waitpid(pid, &status, WNOHANG); | ||
1879 | *handle = GATE_PROCESS_HANDLE_INVALID; | ||
1880 | #else | ||
1881 | ✗ | result = waitid(P_PID, pid, &si, WEXITED | WNOHANG | WNOWAIT); | |
1882 | #endif | ||
1883 | ✗ | if (result == 0) | |
1884 | { | ||
1885 | ✗ | if (si.si_pid == pid) | |
1886 | { | ||
1887 | ✗ | if ((si.si_code == CLD_KILLED) || (si.si_code == CLD_EXITED)) | |
1888 | { | ||
1889 | ✗ | ret = GATE_RESULT_OK; | |
1890 | ✗ | break; | |
1891 | } | ||
1892 | } | ||
1893 | } | ||
1894 | |||
1895 | { | ||
1896 | /* reduce long-time polling */ | ||
1897 | ✗ | gate_thread_sleep((sleepcounter)); | |
1898 | ✗ | if (sleepcounter < 100) | |
1899 | { | ||
1900 | ✗ | ++sleepcounter; | |
1901 | } | ||
1902 | } | ||
1903 | |||
1904 | ✗ | if (GATE_FAILED(gate_timecounter_now(&tcnow))) | |
1905 | { | ||
1906 | ✗ | break; | |
1907 | } | ||
1908 | ✗ | timediff = gate_timecounter_diff(tcnow, tcbegin); | |
1909 | ✗ | } while (timediff < timeoutus); | |
1910 | } | ||
1911 | } | ||
1912 | 1 | return ret; | |
1913 | } | ||
1914 | ✗ | gate_result_t gate_process_wait_pid(gate_process_id_t pid, gate_uint32_t timeoutms) | |
1915 | { | ||
1916 | ✗ | return GATE_RESULT_NOTIMPLEMENTED; | |
1917 | } | ||
1918 | ✗ | gate_result_t gate_process_terminate(gate_process_handle_t* handle, gate_bool_t system_request) | |
1919 | { | ||
1920 | gate_process_id_t pid; | ||
1921 | ✗ | if (!handle || (*handle == GATE_PROCESS_HANDLE_INVALID)) | |
1922 | { | ||
1923 | ✗ | return GATE_RESULT_INVALIDSTATE; | |
1924 | } | ||
1925 | ✗ | pid = (gate_process_id_t)(gate_intptr_t)*handle; | |
1926 | ✗ | return gate_process_terminate_pid(pid, system_request); | |
1927 | } | ||
1928 | ✗ | gate_result_t gate_process_terminate_pid(gate_process_id_t pid, gate_bool_t system_request) | |
1929 | { | ||
1930 | ✗ | gate_result_t ret = GATE_RESULT_FAILED; | |
1931 | ✗ | pid_t proc_id = (pid_t)pid; | |
1932 | ✗ | if (-1 == kill(proc_id, system_request ? SIGTERM : SIGINT)) | |
1933 | { | ||
1934 | ✗ | gate_posix_errno(&ret); | |
1935 | } | ||
1936 | else | ||
1937 | { | ||
1938 | ✗ | ret = GATE_RESULT_OK; | |
1939 | } | ||
1940 | ✗ | return ret; | |
1941 | } | ||
1942 | 1 | gate_result_t gate_process_kill(gate_process_handle_t* handle) | |
1943 | { | ||
1944 | gate_process_id_t pid; | ||
1945 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!handle || (*handle == GATE_PROCESS_HANDLE_INVALID)) |
1946 | { | ||
1947 | ✗ | return GATE_RESULT_INVALIDSTATE; | |
1948 | } | ||
1949 | 1 | pid = (gate_process_id_t)(gate_intptr_t)*handle; | |
1950 | 1 | return gate_process_kill_pid(pid); | |
1951 | } | ||
1952 | 1 | gate_result_t gate_process_kill_pid(gate_process_id_t pid) | |
1953 | { | ||
1954 | 1 | gate_result_t ret = GATE_RESULT_FAILED; | |
1955 | 1 | pid_t proc_id = (pid_t)pid; | |
1956 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (-1 == kill(proc_id, SIGKILL)) |
1957 | { | ||
1958 | ✗ | gate_posix_errno(&ret); | |
1959 | } | ||
1960 | else | ||
1961 | { | ||
1962 | 1 | ret = GATE_RESULT_OK; | |
1963 | } | ||
1964 | 1 | return ret; | |
1965 | } | ||
1966 | 1 | gate_result_t gate_process_suspend(gate_process_handle_t* handle) | |
1967 | { | ||
1968 | gate_process_id_t pid; | ||
1969 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!handle || (*handle == GATE_PROCESS_HANDLE_INVALID)) |
1970 | { | ||
1971 | ✗ | return GATE_RESULT_INVALIDSTATE; | |
1972 | } | ||
1973 | 1 | pid = (gate_process_id_t)(gate_intptr_t)*handle; | |
1974 | 1 | return gate_process_suspend_pid(pid); | |
1975 | } | ||
1976 | 1 | gate_result_t gate_process_suspend_pid(gate_process_id_t pid) | |
1977 | { | ||
1978 | 1 | gate_result_t ret = GATE_RESULT_FAILED; | |
1979 | 1 | pid_t proc_id = (pid_t)pid; | |
1980 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (-1 == kill(proc_id, SIGSTOP)) |
1981 | { | ||
1982 | ✗ | gate_posix_errno(&ret); | |
1983 | } | ||
1984 | else | ||
1985 | { | ||
1986 | 1 | ret = GATE_RESULT_OK; | |
1987 | } | ||
1988 | 1 | return ret; | |
1989 | } | ||
1990 | 1 | gate_result_t gate_process_resume(gate_process_handle_t* handle) | |
1991 | { | ||
1992 | gate_process_id_t pid; | ||
1993 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!handle || (*handle == GATE_PROCESS_HANDLE_INVALID)) |
1994 | { | ||
1995 | ✗ | return GATE_RESULT_INVALIDSTATE; | |
1996 | } | ||
1997 | 1 | pid = (gate_process_id_t)(gate_intptr_t)*handle; | |
1998 | 1 | return gate_process_resume_pid(pid); | |
1999 | } | ||
2000 | 1 | gate_result_t gate_process_resume_pid(gate_process_id_t pid) | |
2001 | { | ||
2002 | 1 | gate_result_t ret = GATE_RESULT_FAILED; | |
2003 | 1 | pid_t proc_id = (pid_t)pid; | |
2004 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (-1 == kill(proc_id, SIGCONT)) |
2005 | { | ||
2006 | ✗ | gate_posix_errno(&ret); | |
2007 | } | ||
2008 | else | ||
2009 | { | ||
2010 | 1 | ret = GATE_RESULT_OK; | |
2011 | } | ||
2012 | 1 | return ret; | |
2013 | } | ||
2014 | |||
2015 | #endif /* GATE_SYS_POSIX */ | ||
2016 |