| /**************************************************************************** |
| ** |
| ** Copyright (C) 2019 Intel Corporation. |
| ** |
| ** Permission is hereby granted, free of charge, to any person obtaining a copy |
| ** of this software and associated documentation files (the "Software"), to deal |
| ** in the Software without restriction, including without limitation the rights |
| ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| ** copies of the Software, and to permit persons to whom the Software is |
| ** furnished to do so, subject to the following conditions: |
| ** |
| ** The above copyright notice and this permission notice shall be included in |
| ** all copies or substantial portions of the Software. |
| ** |
| ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| ** THE SOFTWARE. |
| ** |
| ****************************************************************************/ |
| |
| #include "forkfd.h" |
| |
| #include <sys/types.h> |
| #include <sys/procdesc.h> |
| |
| #include "forkfd_atomic.h" |
| |
| #if __FreeBSD__ >= 10 |
| /* On FreeBSD 10, PROCDESC was enabled by default. On v11, it's not an option |
| * anymore and can't be disabled. */ |
| static ffd_atomic_int system_forkfd_state = FFD_ATOMIC_INIT(1); |
| #else |
| static ffd_atomic_int system_forkfd_state = FFD_ATOMIC_INIT(0); |
| #endif |
| |
| int system_has_forkfd() |
| { |
| return ffd_atomic_load(&system_forkfd_state, FFD_ATOMIC_RELAXED) > 0; |
| } |
| |
| int system_forkfd(int flags, pid_t *ppid, int *system) |
| { |
| int ret; |
| pid_t pid; |
| |
| int state = ffd_atomic_load(&system_forkfd_state, FFD_ATOMIC_RELAXED); |
| *system = 0; |
| if (state < 0) |
| return -1; |
| |
| pid = pdfork(&ret, PD_DAEMON); |
| # if __FreeBSD__ == 9 |
| if (state == 0 && pid != 0) { |
| /* Parent process: remember whether PROCDESC was compiled into the kernel */ |
| state = (pid == -1 && errno == ENOSYS) ? -1 : 1; |
| ffd_atomic_store(&system_forkfd_state, state, FFD_ATOMIC_RELAXED); |
| } |
| if (state < 0) |
| return -1; |
| # endif |
| *system = 1; |
| if (__builtin_expect(pid == -1, 0)) |
| return -1; |
| |
| if (pid == 0) { |
| /* child process */ |
| return FFD_CHILD_PROCESS; |
| } |
| |
| /* parent process */ |
| if (flags & FFD_CLOEXEC) |
| fcntl(ret, F_SETFD, FD_CLOEXEC); |
| if (flags & FFD_NONBLOCK) |
| fcntl(ret, F_SETFL, fcntl(ret, F_GETFL) | O_NONBLOCK); |
| if (ppid) |
| *ppid = pid; |
| return ret; |
| } |
| |
| int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage) |
| { |
| pid_t pid; |
| int status; |
| int options = WEXITED; |
| |
| int ret = pdgetpid(ffd, &pid); |
| if (ret == -1) |
| return ret; |
| ret = fcntl(ffd, F_GETFL); |
| if (ret == -1) |
| return ret; |
| options |= (ret & O_NONBLOCK) ? WNOHANG : 0; |
| ret = wait4(pid, &status, options, rusage); |
| if (ret != -1 && info) |
| convertStatusToForkfdInfo(status, info); |
| return ret == -1 ? -1 : 0; |
| } |