DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(posix_spawnattr_t*, posix_spawnattr_destroy, NULL);
-int posix_spawn_wrapper(const char *path, char *const *argv, char *const *envp, const char *cgroup, PidRef *ret_pidref) {
+int posix_spawn_wrapper(
+ const char *path,
+ char * const *argv,
+ char * const *envp,
+ const char *cgroup,
+ PidRef *ret_pidref) {
+
short flags = POSIX_SPAWN_SETSIGMASK|POSIX_SPAWN_SETSIGDEF;
posix_spawnattr_t attr;
sigset_t mask;
/* Forks and invokes 'path' with 'argv' and 'envp' using CLONE_VM and CLONE_VFORK, which means the
* caller will be blocked until the child either exits or exec's. The memory of the child will be
* fully shared with the memory of the parent, so that there are no copy-on-write or memory.max
- * issues. */
+ * issues.
+ *
+ * Also, move the newly-created process into 'cgroup' through POSIX_SPAWN_SETCGROUP (clone3())
+ * if available. Note that CLONE_INTO_CGROUP is only supported on cgroup v2.
+ * returns 1: We're already in the right cgroup
+ * 0: 'cgroup' not specified or POSIX_SPAWN_SETCGROUP is not supported. The caller
+ * needs to call 'cg_attach' on their own */
assert(path);
assert(argv);
if (r < 0)
return r;
- if (cgroup_fd == -EBADF)
- return 0; /* We managed to use the new API but we are running under cgroupv1 */
-
- return 1; /* We managed to use the new API and we are already in the new cgroup */
+ return FLAGS_SET(flags, POSIX_SPAWN_SETCGROUP);
}
if (!(ERRNO_IS_NOT_SUPPORTED(r) || ERRNO_IS_PRIVILEGE(r)))
return -r;
int is_reaper_process(void);
int make_reaper_process(bool b);
-int posix_spawn_wrapper(const char *path, char *const *argv, char *const *envp, const char *cgroup, PidRef *ret_pidref);
+int posix_spawn_wrapper(
+ const char *path,
+ char * const *argv,
+ char * const *envp,
+ const char *cgroup,
+ PidRef *ret_pidref);
int proc_dir_open(DIR **ret);
int proc_dir_read(DIR *d, pid_t *ret);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
_cleanup_fdset_free_ FDSet *fdset = NULL;
_cleanup_fclose_ FILE *f = NULL;
- bool move_child = true;
int r;
assert(unit);
assert(unit->manager->executor_fd >= 0);
assert(command);
assert(context);
- assert(ret);
assert(params);
assert(params->fds || (params->n_socket_fds + params->n_storage_fds <= 0));
assert(!params->files_env); /* We fill this field, ensure it comes NULL-initialized to us */
+ assert(ret);
LOG_CONTEXT_PUSH_UNIT(unit);
&pidref);
if (r < 0)
return log_unit_error_errno(unit, r, "Failed to spawn executor: %m");
- if (r > 0)
- move_child = false; /* Already in the right cgroup thanks to CLONE_INTO_CGROUP */
-
- log_unit_debug(unit, "Forked %s as "PID_FMT, command->path, pidref.pid);
-
/* We add the new process to the cgroup both in the child (so that we can be sure that no user code is ever
* executed outside of the cgroup) and in the parent (so that we can be sure that when we kill the cgroup the
* process will be killed too). */
- if (move_child && subcgroup_path)
+ if (r == 0 && subcgroup_path)
(void) cg_attach(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path, pidref.pid);
+ /* r > 0: Already in the right cgroup thanks to CLONE_INTO_CGROUP */
+
+ log_unit_debug(unit, "Forked %s as " PID_FMT " (%s CLONE_INTO_CGROUP)",
+ command->path, pidref.pid, r > 0 ? "via" : "without");
exec_status_start(&command->exec_status, pidref.pid);