int exec_spawn(Unit *unit,
               ExecCommand *command,
               const ExecContext *context,
               const ExecParameters *params,
               ExecRuntime *runtime,
               DynamicCreds *dcreds,
               pid_t *ret) {

        int socket_fd, r, named_iofds[3] = { -1, -1, -1 }, *fds = NULL;
        _cleanup_free_ char *subcgroup_path = NULL;
        _cleanup_strv_free_ char **files_env = NULL;
        size_t n_storage_fds = 0, n_socket_fds = 0;
        _cleanup_free_ char *line = NULL;
        pid_t pid;

        assert(unit);
        assert(command);
        assert(context);
        assert(ret);
        assert(params);
        assert(params->fds || (params->n_socket_fds + params->n_storage_fds <= 0));

        if (context->std_input == EXEC_INPUT_SOCKET ||
            context->std_output == EXEC_OUTPUT_SOCKET ||
            context->std_error == EXEC_OUTPUT_SOCKET) {

                if (params->n_socket_fds > 1) {
                        log_unit_error(unit, "Got more than one socket.");
                        return -EINVAL;
                }

                if (params->n_socket_fds == 0) {
                        log_unit_error(unit, "Got no socket.");
                        return -EINVAL;
                }

                socket_fd = params->fds[0];
        } else {
                socket_fd = -1;
                fds = params->fds;
                n_socket_fds = params->n_socket_fds;
                n_storage_fds = params->n_storage_fds;
        }

        r = exec_context_named_iofds(context, params, named_iofds);
        if (r < 0)
                return log_unit_error_errno(unit, r, "Failed to load a named file descriptor: %m");

        r = exec_context_load_environment(unit, context, &files_env);
        if (r < 0)
                return log_unit_error_errno(unit, r, "Failed to load environment files: %m");

        line = exec_command_line(command->argv);
        if (!line)
                return log_oom();

        log_struct(LOG_DEBUG,
                   LOG_UNIT_MESSAGE(unit, "About to execute: %s", line),
                   "EXECUTABLE=%s", command->path,
                   LOG_UNIT_ID(unit),
                   LOG_UNIT_INVOCATION_ID(unit));

        if (params->cgroup_path) {
                r = exec_parameters_get_cgroup_path(params, &subcgroup_path);
                if (r < 0)
                        return log_unit_error_errno(unit, r, "Failed to acquire subcgroup path: %m");
                if (r > 0) { /* We are using a child cgroup */
                        r = cg_create(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path);
                        if (r < 0)
                                return log_unit_error_errno(unit, r, "Failed to create control group '%s': %m", subcgroup_path);
                }
        }

        pid = fork();
        if (pid < 0)
                return log_unit_error_errno(unit, errno, "Failed to fork: %m");

        if (pid == 0) {
                int exit_status = EXIT_SUCCESS;

                r = exec_child(unit,
                               command,
                               context,
                               params,
                               runtime,
                               dcreds,
                               socket_fd,
                               named_iofds,
                               fds,
                               n_socket_fds,
                               n_storage_fds,
                               files_env,
                               unit->manager->user_lookup_fds[1],
                               &exit_status);

                if (r < 0)
                        log_struct_errno(LOG_ERR, r,
                                         "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
                                         LOG_UNIT_ID(unit),
                                         LOG_UNIT_INVOCATION_ID(unit),
                                         LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
                                                          exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
                                                          command->path),
                                         "EXECUTABLE=%s", command->path);

                _exit(exit_status);
        }

        log_unit_debug(unit, "Forked %s as "PID_FMT, command->path, 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 (subcgroup_path)
                (void) cg_attach(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path, pid);

        exec_status_start(&command->exec_status, pid);

        *ret = pid;
        return 0;
}