diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 9a0b72aca9..48c1ea15b1 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -782,15 +782,14 @@ NonBlocking= - Set the O_NONBLOCK flag - for all file descriptors passed via socket-based activation. - If true, all file descriptors >= 3 (i.e. all except stdin, - stdout, and stderr) will have the - O_NONBLOCK flag set and hence are in - non-blocking mode. This option is only useful in conjunction - with a socket unit, as described in - systemd.socket5. - Defaults to false. + Set the O_NONBLOCK flag for all file descriptors passed via socket-based + activation. If true, all file descriptors >= 3 (i.e. all except stdin, stdout, stderr), excluding those passed + in via the file descriptor storage logic (see FileDescriptorStoreMax= for details), will + have the O_NONBLOCK flag set and hence are in non-blocking mode. This option is only + useful in conjunction with a socket unit, as described in + systemd.socket5 and has no + effect on file descriptors which were previously saved in the file-descriptor store for example. Defaults to + false. diff --git a/src/core/execute.c b/src/core/execute.c index e97651105e..7d9fc037b9 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -157,7 +157,7 @@ static int shift_fds(int fds[], unsigned n_fds) { return 0; } -static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) { +static int flags_fds(const int fds[], unsigned n_fds, unsigned n_socket_fds, bool nonblock) { unsigned i; int r; @@ -166,13 +166,16 @@ static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) { assert(fds); - /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */ + /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags. + * O_NONBLOCK only applies to socket activation though. */ for (i = 0; i < n_fds; i++) { - r = fd_nonblock(fds[i], nonblock); - if (r < 0) - return r; + if (i < n_socket_fds) { + r = fd_nonblock(fds[i], nonblock); + if (r < 0) + return r; + } /* We unconditionally drop FD_CLOEXEC from the fds, * since after all we want to pass these fds to our @@ -2242,6 +2245,7 @@ static int exec_child( int socket_fd, int named_iofds[3], int *fds, unsigned n_fds, + unsigned n_socket_fds, char **files_env, int user_lookup_fd, int *exit_status, @@ -2669,7 +2673,7 @@ static int exec_child( if (r >= 0) r = shift_fds(fds, n_fds); if (r >= 0) - r = flags_fds(fds, n_fds, context->non_blocking); + r = flags_fds(fds, n_fds, n_socket_fds, context->non_blocking); if (r < 0) { *exit_status = EXIT_FDS; return r; @@ -2909,7 +2913,8 @@ int exec_spawn(Unit *unit, pid_t *ret) { _cleanup_strv_free_ char **files_env = NULL; - int *fds = NULL; unsigned n_fds = 0; + int *fds = NULL; + unsigned n_fds = 0, n_socket_fds = 0; _cleanup_free_ char *line = NULL; int socket_fd, r; int named_iofds[3] = { -1, -1, -1 }; @@ -2942,6 +2947,7 @@ int exec_spawn(Unit *unit, socket_fd = -1; fds = params->fds; n_fds = params->n_fds; + n_socket_fds = params->n_socket_fds; } r = exec_context_named_iofds(unit, context, params, named_iofds); @@ -2980,6 +2986,7 @@ int exec_spawn(Unit *unit, socket_fd, named_iofds, fds, n_fds, + n_socket_fds, files_env, unit->manager->user_lookup_fds[1], &exit_status, diff --git a/src/core/execute.h b/src/core/execute.h index 9f2b6fd39e..dee7af1423 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -247,6 +247,7 @@ struct ExecParameters { int *fds; char **fd_names; unsigned n_fds; + unsigned n_socket_fds; ExecFlags flags; bool selinux_context_net:1; diff --git a/src/core/service.c b/src/core/service.c index b45929e535..370a6316e7 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1068,14 +1068,16 @@ static int service_coldplug(Unit *u) { return 0; } -static int service_collect_fds(Service *s, int **fds, char ***fd_names) { +static int service_collect_fds(Service *s, int **fds, char ***fd_names, unsigned *n_socket_fds) { _cleanup_strv_free_ char **rfd_names = NULL; _cleanup_free_ int *rfds = NULL; - int rn_fds = 0, r; + unsigned rn_socket_fds = 0; + int rn_fds = 0, r; assert(s); assert(fds); assert(fd_names); + assert(n_socket_fds); if (s->socket_fd >= 0) { @@ -1138,6 +1140,8 @@ static int service_collect_fds(Service *s, int **fds, char ***fd_names) { } } + rn_socket_fds = rn_fds; + if (s->n_fd_store > 0) { ServiceFDStore *fs; char **nl; @@ -1169,6 +1173,7 @@ static int service_collect_fds(Service *s, int **fds, char ***fd_names) { *fds = rfds; *fd_names = rfd_names; + *n_socket_fds = rn_socket_fds; rfds = NULL; rfd_names = NULL; @@ -1204,7 +1209,7 @@ static int service_spawn( _cleanup_strv_free_ char **final_env = NULL, **our_env = NULL, **fd_names = NULL; _cleanup_free_ int *fds = NULL; - unsigned n_fds = 0, n_env = 0; + unsigned n_fds = 0, n_socket_fds = 0, n_env = 0; const char *path; pid_t pid; @@ -1248,7 +1253,7 @@ static int service_spawn( s->exec_context.std_output == EXEC_OUTPUT_SOCKET || s->exec_context.std_error == EXEC_OUTPUT_SOCKET) { - r = service_collect_fds(s, &fds, &fd_names); + r = service_collect_fds(s, &fds, &fd_names, &n_socket_fds); if (r < 0) return r; @@ -1348,6 +1353,7 @@ static int service_spawn( exec_params.fds = fds; exec_params.fd_names = fd_names; exec_params.n_fds = n_fds; + exec_params.n_socket_fds = n_socket_fds; exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager); exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported; exec_params.cgroup_path = path;