SIGKILL;
}
-int safe_fork_full(
+int pidref_safe_fork_full(
const char *name,
const int stdio_fds[3],
int except_fds[],
size_t n_except_fds,
ForkFlags flags,
- pid_t *ret_pid) {
+ PidRef *ret_pid) {
pid_t original_pid, pid;
sigset_t saved_ss, ss;
assert(!FLAGS_SET(flags, FORK_DETACH) ||
(!ret_pid && (flags & (FORK_WAIT|FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGINT|FORK_DEATHSIG_SIGKILL)) == 0));
- /* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always
- * returns the child's PID in *ret_pid. Returns == 0 in the child, and > 0 in the parent. */
+ /* A wrapper around fork(), that does a couple of important initializations in addition to mere
+ * forking. If provided, ret_pid is initialized in both the parent and the child process, both times
+ * referencing the child process. Returns == 0 in the child and > 0 in the parent. */
prio = flags & FORK_LOG ? LOG_ERR : LOG_DEBUG;
return r;
if (r != EXIT_SUCCESS) /* exit status > 0 should be treated as failure, too */
return -EPROTO;
+
+ /* If we are in the parent and successfully waited, then the process doesn't exist anymore. */
+ if (ret_pid)
+ *ret_pid = PIDREF_NULL;
+
+ return 1;
}
- if (ret_pid)
- *ret_pid = pid;
+ if (ret_pid) {
+ if (FLAGS_SET(flags, FORK_PID_ONLY))
+ *ret_pid = PIDREF_MAKE_FROM_PID(pid);
+ else {
+ r = pidref_set_pid(ret_pid, pid);
+ if (r < 0) /* Let's not fail for this, no matter what, the process exists after all, and that's key */
+ *ret_pid = PIDREF_MAKE_FROM_PID(pid);
+ }
+ }
return 1;
}
if (FLAGS_SET(flags, FORK_FREEZE))
freeze();
- if (ret_pid)
- *ret_pid = getpid_cached();
+ if (ret_pid) {
+ if (FLAGS_SET(flags, FORK_PID_ONLY))
+ *ret_pid = PIDREF_MAKE_FROM_PID(getpid_cached());
+ else {
+ r = pidref_set_self(ret_pid);
+ if (r < 0) {
+ log_full_errno(prio, r, "Failed to acquire PID reference on ourselves: %m");
+ _exit(EXIT_FAILURE);
+ }
+ }
+ }
return 0;
}
-int pidref_safe_fork_full(
+int safe_fork_full(
const char *name,
const int stdio_fds[3],
int except_fds[],
size_t n_except_fds,
ForkFlags flags,
- PidRef *ret_pid) {
+ pid_t *ret_pid) {
- pid_t pid;
- int r, q;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ int r;
- r = safe_fork_full(name, stdio_fds, except_fds, n_except_fds, flags, &pid);
- if (r < 0 || !ret_pid)
- return r;
+ /* Getting the detached child process pid without pidfd is racy, so don't allow it if not returning
+ * a pidref to the caller. */
+ assert(!FLAGS_SET(flags, FORK_DETACH) || !ret_pid);
- if (r > 0 && FLAGS_SET(flags, FORK_WAIT)) {
- /* If we are in the parent and successfully waited, then the process doesn't exist anymore */
- *ret_pid = PIDREF_NULL;
+ r = pidref_safe_fork_full(name, stdio_fds, except_fds, n_except_fds, flags|FORK_PID_ONLY, ret_pid ? &pidref : NULL);
+ if (r < 0 || !ret_pid)
return r;
- }
- q = pidref_set_pid(ret_pid, pid);
- if (q < 0) /* Let's not fail for this, no matter what, the process exists after all, and that's key */
- *ret_pid = PIDREF_MAKE_FROM_PID(pid);
+ *ret_pid = pidref.pid;
return r;
}
FORK_NEW_NETNS = 1 << 20, /* Run child in its own network namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
FORK_NEW_PIDNS = 1 << 21, /* Run child in its own PID namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
FORK_FREEZE = 1 << 22, /* Don't return in child, just call freeze() instead */
+ FORK_PID_ONLY = 1 << 23, /* Don't open a pidfd referencing the child process */
} ForkFlags;
-int safe_fork_full(
+int pidref_safe_fork_full(
const char *name,
const int stdio_fds[3],
int except_fds[],
size_t n_except_fds,
ForkFlags flags,
- pid_t *ret_pid);
+ PidRef *ret_pid);
-static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
- return safe_fork_full(name, NULL, NULL, 0, flags, ret_pid);
+static inline int pidref_safe_fork(const char *name, ForkFlags flags, PidRef *ret_pid) {
+ return pidref_safe_fork_full(name, NULL, NULL, 0, flags, ret_pid);
}
-int pidref_safe_fork_full(
+int safe_fork_full(
const char *name,
const int stdio_fds[3],
int except_fds[],
size_t n_except_fds,
ForkFlags flags,
- PidRef *ret_pid);
+ pid_t *ret_pid);
-static inline int pidref_safe_fork(const char *name, ForkFlags flags, PidRef *ret_pid) {
- return pidref_safe_fork_full(name, NULL, NULL, 0, flags, ret_pid);
+static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
+ return safe_fork_full(name, NULL, NULL, 0, flags, ret_pid);
}
int namespace_fork(