]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #27053 from DaanDeMeyer/firstboot-followups
authorMike Yuan <me@yhndnzj.com>
Wed, 29 Mar 2023 20:22:16 +0000 (04:22 +0800)
committerGitHub <noreply@github.com>
Wed, 29 Mar 2023 20:22:16 +0000 (04:22 +0800)
Firstboot followups

20 files changed:
src/basic/unit-def.c
src/basic/unit-def.h
src/core/dynamic-user.c
src/core/dynamic-user.h
src/core/execute.c
src/core/execute.h
src/core/manager-serialize.c
src/core/manager.c
src/core/manager.h
src/core/mount.c
src/core/mount.h
src/core/service.c
src/core/service.h
src/core/socket.c
src/core/socket.h
src/core/swap.c
src/core/swap.h
src/core/unit-serialize.c
src/core/unit.c
src/core/unit.h

index bdb1860246fecba7c269a12912d2f893df6e6eff..a0fab46a193b3c6e62381425baad30335015398e 100644 (file)
@@ -180,27 +180,29 @@ static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
 
 static const char* const service_state_table[_SERVICE_STATE_MAX] = {
-        [SERVICE_DEAD]           = "dead",
-        [SERVICE_CONDITION]      = "condition",
-        [SERVICE_START_PRE]      = "start-pre",
-        [SERVICE_START]          = "start",
-        [SERVICE_START_POST]     = "start-post",
-        [SERVICE_RUNNING]        = "running",
-        [SERVICE_EXITED]         = "exited",
-        [SERVICE_RELOAD]         = "reload",
-        [SERVICE_RELOAD_SIGNAL]  = "reload-signal",
-        [SERVICE_RELOAD_NOTIFY]  = "reload-notify",
-        [SERVICE_STOP]           = "stop",
-        [SERVICE_STOP_WATCHDOG]  = "stop-watchdog",
-        [SERVICE_STOP_SIGTERM]   = "stop-sigterm",
-        [SERVICE_STOP_SIGKILL]   = "stop-sigkill",
-        [SERVICE_STOP_POST]      = "stop-post",
-        [SERVICE_FINAL_WATCHDOG] = "final-watchdog",
-        [SERVICE_FINAL_SIGTERM]  = "final-sigterm",
-        [SERVICE_FINAL_SIGKILL]  = "final-sigkill",
-        [SERVICE_FAILED]         = "failed",
-        [SERVICE_AUTO_RESTART]   = "auto-restart",
-        [SERVICE_CLEANING]       = "cleaning",
+        [SERVICE_DEAD]                       = "dead",
+        [SERVICE_CONDITION]                  = "condition",
+        [SERVICE_START_PRE]                  = "start-pre",
+        [SERVICE_START]                      = "start",
+        [SERVICE_START_POST]                 = "start-post",
+        [SERVICE_RUNNING]                    = "running",
+        [SERVICE_EXITED]                     = "exited",
+        [SERVICE_RELOAD]                     = "reload",
+        [SERVICE_RELOAD_SIGNAL]              = "reload-signal",
+        [SERVICE_RELOAD_NOTIFY]              = "reload-notify",
+        [SERVICE_STOP]                       = "stop",
+        [SERVICE_STOP_WATCHDOG]              = "stop-watchdog",
+        [SERVICE_STOP_SIGTERM]               = "stop-sigterm",
+        [SERVICE_STOP_SIGKILL]               = "stop-sigkill",
+        [SERVICE_STOP_POST]                  = "stop-post",
+        [SERVICE_FINAL_WATCHDOG]             = "final-watchdog",
+        [SERVICE_FINAL_SIGTERM]              = "final-sigterm",
+        [SERVICE_FINAL_SIGKILL]              = "final-sigkill",
+        [SERVICE_FAILED]                     = "failed",
+        [SERVICE_DEAD_BEFORE_AUTO_RESTART]   = "dead-before-auto-restart",
+        [SERVICE_FAILED_BEFORE_AUTO_RESTART] = "failed-before-auto-restart",
+        [SERVICE_AUTO_RESTART]               = "auto-restart",
+        [SERVICE_CLEANING]                   = "cleaning",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
index bae132ea097c185eca57a6576c35b2a089d1fd58..2fab42e9c7204adb66deca0cc380bea66df69d36 100644 (file)
@@ -144,6 +144,8 @@ typedef enum ServiceState {
         SERVICE_FINAL_SIGTERM,     /* In case the STOP_POST executable hangs, we shoot that down, too */
         SERVICE_FINAL_SIGKILL,
         SERVICE_FAILED,
+        SERVICE_DEAD_BEFORE_AUTO_RESTART,
+        SERVICE_FAILED_BEFORE_AUTO_RESTART,
         SERVICE_AUTO_RESTART,
         SERVICE_CLEANING,
         _SERVICE_STATE_MAX,
index 3824ae747fdfe28acf19fabb8d854ab4308f16a1..19cf3faca6c6ef664961bccea69e658b042c2a94 100644 (file)
@@ -739,18 +739,28 @@ int dynamic_user_lookup_name(Manager *m, const char *name, uid_t *ret) {
         return r;
 }
 
-int dynamic_creds_acquire(DynamicCreds *creds, Manager *m, const char *user, const char *group) {
+int dynamic_creds_make(Manager *m, const char *user, const char *group, DynamicCreds **ret) {
+        _cleanup_(dynamic_creds_unrefp) DynamicCreds *creds = NULL;
         bool acquired = false;
         int r;
 
-        assert(creds);
         assert(m);
+        assert(ret);
+
+        if (!user && !group) {
+                *ret = NULL;
+                return 0;
+        }
+
+        creds = new0(DynamicCreds, 1);
+        if (!creds)
+                return -ENOMEM;
 
         /* A DynamicUser object encapsulates an allocation of both a UID and a GID for a specific name. However, some
          * services use different user and groups. For cases like that there's DynamicCreds containing a pair of user
          * and group. This call allocates a pair. */
 
-        if (!creds->user && user) {
+        if (user) {
                 r = dynamic_user_acquire(m, user, &creds->user);
                 if (r < 0)
                         return r;
@@ -758,20 +768,19 @@ int dynamic_creds_acquire(DynamicCreds *creds, Manager *m, const char *user, con
                 acquired = true;
         }
 
-        if (!creds->group) {
-
-                if (creds->user && (!group || streq_ptr(user, group)))
-                        creds->group = dynamic_user_ref(creds->user);
-                else if (group) {
-                        r = dynamic_user_acquire(m, group, &creds->group);
-                        if (r < 0) {
-                                if (acquired)
-                                        creds->user = dynamic_user_unref(creds->user);
-                                return r;
-                        }
+        if (creds->user && (!group || streq_ptr(user, group)))
+                creds->group = dynamic_user_ref(creds->user);
+        else if (group) {
+                r = dynamic_user_acquire(m, group, &creds->group);
+                if (r < 0) {
+                        if (acquired)
+                                creds->user = dynamic_user_unref(creds->user);
+                        return r;
                 }
         }
 
+        *ret = TAKE_PTR(creds);
+
         return 0;
 }
 
@@ -803,16 +812,22 @@ int dynamic_creds_realize(DynamicCreds *creds, char **suggested_paths, uid_t *ui
         return 0;
 }
 
-void dynamic_creds_unref(DynamicCreds *creds) {
-        assert(creds);
+DynamicCreds* dynamic_creds_unref(DynamicCreds *creds) {
+        if (!creds)
+                return NULL;
 
         creds->user = dynamic_user_unref(creds->user);
         creds->group = dynamic_user_unref(creds->group);
+
+        return mfree(creds);
 }
 
-void dynamic_creds_destroy(DynamicCreds *creds) {
-        assert(creds);
+DynamicCreds* dynamic_creds_destroy(DynamicCreds *creds) {
+        if (!creds)
+                return NULL;
 
         creds->user = dynamic_user_destroy(creds->user);
         creds->group = dynamic_user_destroy(creds->group);
+
+        return mfree(creds);
 }
index 847ef475ca555d300a8a00a70a240d3ebdf430e6..6539d17571b2112afc2ca3e587a1caefdf4b3396 100644 (file)
@@ -33,8 +33,11 @@ int dynamic_user_current(DynamicUser *d, uid_t *ret);
 int dynamic_user_lookup_uid(Manager *m, uid_t uid, char **ret);
 int dynamic_user_lookup_name(Manager *m, const char *name, uid_t *ret);
 
-int dynamic_creds_acquire(DynamicCreds *creds, Manager *m, const char *user, const char *group);
+int dynamic_creds_make(Manager *m, const char *user, const char *group, DynamicCreds **ret);
 int dynamic_creds_realize(DynamicCreds *creds, char **suggested_paths, uid_t *uid, gid_t *gid);
 
-void dynamic_creds_unref(DynamicCreds *creds);
-void dynamic_creds_destroy(DynamicCreds *creds);
+DynamicCreds *dynamic_creds_unref(DynamicCreds *creds);
+DynamicCreds *dynamic_creds_destroy(DynamicCreds *creds);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(DynamicCreds*, dynamic_creds_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(DynamicCreds*, dynamic_creds_destroy);
index bfdd2026c673c89e05d78b70e3db0cae26b0ba29..81e48f12c6b5ac8d7f6f5dd08be29a32dd96bff8 100644 (file)
@@ -2210,7 +2210,7 @@ bool exec_needs_mount_namespace(
         if (!IN_SET(context->mount_propagation_flag, 0, MS_SHARED))
                 return true;
 
-        if (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir))
+        if (context->private_tmp && runtime && runtime->shared && (runtime->shared->tmp_dir || runtime->shared->var_tmp_dir))
                 return true;
 
         if (context->private_devices ||
@@ -3742,16 +3742,16 @@ static int apply_mount_namespace(
                  * that is sticky, and that's the one we want to use here.
                  * This does not apply when we are using /run/systemd/empty as fallback. */
 
-                if (context->private_tmp && runtime) {
-                        if (streq_ptr(runtime->tmp_dir, RUN_SYSTEMD_EMPTY))
-                                tmp_dir = runtime->tmp_dir;
-                        else if (runtime->tmp_dir)
-                                tmp_dir = strjoina(runtime->tmp_dir, "/tmp");
+                if (context->private_tmp && runtime && runtime->shared) {
+                        if (streq_ptr(runtime->shared->tmp_dir, RUN_SYSTEMD_EMPTY))
+                                tmp_dir = runtime->shared->tmp_dir;
+                        else if (runtime->shared->tmp_dir)
+                                tmp_dir = strjoina(runtime->shared->tmp_dir, "/tmp");
 
-                        if (streq_ptr(runtime->var_tmp_dir, RUN_SYSTEMD_EMPTY))
-                                var_tmp_dir = runtime->var_tmp_dir;
-                        else if (runtime->var_tmp_dir)
-                                var_tmp_dir = strjoina(runtime->var_tmp_dir, "/tmp");
+                        if (streq_ptr(runtime->shared->var_tmp_dir, RUN_SYSTEMD_EMPTY))
+                                var_tmp_dir = runtime->shared->var_tmp_dir;
+                        else if (runtime->shared->var_tmp_dir)
+                                var_tmp_dir = strjoina(runtime->shared->var_tmp_dir, "/tmp");
                 }
 
                 ns_info = (NamespaceInfo) {
@@ -4057,7 +4057,6 @@ static void append_socket_pair(int *array, size_t *n, const int pair[static 2])
 static int close_remaining_fds(
                 const ExecParameters *params,
                 const ExecRuntime *runtime,
-                const DynamicCreds *dcreds,
                 int user_lookup_fd,
                 int socket_fd,
                 const int *fds, size_t n_fds) {
@@ -4081,16 +4080,16 @@ static int close_remaining_fds(
                 n_dont_close += n_fds;
         }
 
-        if (runtime) {
-                append_socket_pair(dont_close, &n_dont_close, runtime->netns_storage_socket);
-                append_socket_pair(dont_close, &n_dont_close, runtime->ipcns_storage_socket);
+        if (runtime && runtime->shared) {
+                append_socket_pair(dont_close, &n_dont_close, runtime->shared->netns_storage_socket);
+                append_socket_pair(dont_close, &n_dont_close, runtime->shared->ipcns_storage_socket);
         }
 
-        if (dcreds) {
-                if (dcreds->user)
-                        append_socket_pair(dont_close, &n_dont_close, dcreds->user->storage_socket);
-                if (dcreds->group)
-                        append_socket_pair(dont_close, &n_dont_close, dcreds->group->storage_socket);
+        if (runtime && runtime->dynamic_creds) {
+                if (runtime->dynamic_creds->user)
+                        append_socket_pair(dont_close, &n_dont_close, runtime->dynamic_creds->user->storage_socket);
+                if (runtime->dynamic_creds->group)
+                        append_socket_pair(dont_close, &n_dont_close, runtime->dynamic_creds->group->storage_socket);
         }
 
         if (user_lookup_fd >= 0)
@@ -4404,7 +4403,6 @@ static int exec_child(
                 const ExecContext *context,
                 const ExecParameters *params,
                 ExecRuntime *runtime,
-                DynamicCreds *dcreds,
                 const CGroupContext *cgroup_context,
                 int socket_fd,
                 const int named_iofds[static 3],
@@ -4537,7 +4535,7 @@ static int exec_child(
         }
 #endif
 
-        r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, keep_fds, n_keep_fds);
+        r = close_remaining_fds(params, runtime, user_lookup_fd, socket_fd, keep_fds, n_keep_fds);
         if (r < 0) {
                 *exit_status = EXIT_FDS;
                 return log_unit_error_errno(unit, r, "Failed to close unwanted file descriptors: %m");
@@ -4583,7 +4581,7 @@ static int exec_child(
                 return log_unit_error_errno(unit, errno, "Failed to update environment: %m");
         }
 
-        if (context->dynamic_user && dcreds) {
+        if (context->dynamic_user && runtime && runtime->dynamic_creds) {
                 _cleanup_strv_free_ char **suggested_paths = NULL;
 
                 /* On top of that, make sure we bypass our own NSS module nss-systemd comprehensively for any NSS
@@ -4599,7 +4597,7 @@ static int exec_child(
                         return log_oom();
                 }
 
-                r = dynamic_creds_realize(dcreds, suggested_paths, &uid, &gid);
+                r = dynamic_creds_realize(runtime->dynamic_creds, suggested_paths, &uid, &gid);
                 if (r < 0) {
                         *exit_status = EXIT_USER;
                         if (r == -EILSEQ)
@@ -4618,8 +4616,8 @@ static int exec_child(
                         return log_unit_error_errno(unit, SYNTHETIC_ERRNO(ESRCH), "GID validation failed for \""GID_FMT"\"", gid);
                 }
 
-                if (dcreds->user)
-                        username = dcreds->user->name;
+                if (runtime->dynamic_creds->user)
+                        username = runtime->dynamic_creds->user->name;
 
         } else {
                 r = get_fixed_user(context, &username, &uid, &gid, &home, &shell);
@@ -4686,16 +4684,16 @@ static int exec_child(
                 }
         }
 
-        if (context->network_namespace_path && runtime && runtime->netns_storage_socket[0] >= 0) {
-                r = open_shareable_ns_path(runtime->netns_storage_socket, context->network_namespace_path, CLONE_NEWNET);
+        if (context->network_namespace_path && runtime && runtime->shared && runtime->shared->netns_storage_socket[0] >= 0) {
+                r = open_shareable_ns_path(runtime->shared->netns_storage_socket, context->network_namespace_path, CLONE_NEWNET);
                 if (r < 0) {
                         *exit_status = EXIT_NETWORK;
                         return log_unit_error_errno(unit, r, "Failed to open network namespace path %s: %m", context->network_namespace_path);
                 }
         }
 
-        if (context->ipc_namespace_path && runtime && runtime->ipcns_storage_socket[0] >= 0) {
-                r = open_shareable_ns_path(runtime->ipcns_storage_socket, context->ipc_namespace_path, CLONE_NEWIPC);
+        if (context->ipc_namespace_path && runtime && runtime->shared && runtime->shared->ipcns_storage_socket[0] >= 0) {
+                r = open_shareable_ns_path(runtime->shared->ipcns_storage_socket, context->ipc_namespace_path, CLONE_NEWIPC);
                 if (r < 0) {
                         *exit_status = EXIT_NAMESPACE;
                         return log_unit_error_errno(unit, r, "Failed to open IPC namespace path %s: %m", context->ipc_namespace_path);
@@ -5045,10 +5043,10 @@ static int exec_child(
                 }
         }
 
-        if (exec_needs_network_namespace(context) && runtime && runtime->netns_storage_socket[0] >= 0) {
+        if (exec_needs_network_namespace(context) && runtime && runtime->shared && runtime->shared->netns_storage_socket[0] >= 0) {
 
                 if (ns_type_supported(NAMESPACE_NET)) {
-                        r = setup_shareable_ns(runtime->netns_storage_socket, CLONE_NEWNET);
+                        r = setup_shareable_ns(runtime->shared->netns_storage_socket, CLONE_NEWNET);
                         if (r < 0) {
                                 if (ERRNO_IS_PRIVILEGE(r))
                                         log_unit_warning_errno(unit, r,
@@ -5066,10 +5064,10 @@ static int exec_child(
                         log_unit_warning(unit, "PrivateNetwork=yes is configured, but the kernel does not support network namespaces, ignoring.");
         }
 
-        if (exec_needs_ipc_namespace(context) && runtime && runtime->ipcns_storage_socket[0] >= 0) {
+        if (exec_needs_ipc_namespace(context) && runtime && runtime->shared && runtime->shared->ipcns_storage_socket[0] >= 0) {
 
                 if (ns_type_supported(NAMESPACE_IPC)) {
-                        r = setup_shareable_ns(runtime->ipcns_storage_socket, CLONE_NEWIPC);
+                        r = setup_shareable_ns(runtime->shared->ipcns_storage_socket, CLONE_NEWIPC);
                         if (r == -EPERM)
                                 log_unit_warning_errno(unit, r,
                                                        "PrivateIPC=yes is configured, but IPC namespace setup failed, ignoring: %m");
@@ -5550,7 +5548,6 @@ int exec_spawn(Unit *unit,
                const ExecContext *context,
                const ExecParameters *params,
                ExecRuntime *runtime,
-               DynamicCreds *dcreds,
                const CGroupContext *cgroup_context,
                pid_t *ret) {
 
@@ -5640,7 +5637,6 @@ int exec_spawn(Unit *unit,
                                context,
                                params,
                                runtime,
-                               dcreds,
                                cgroup_context,
                                socket_fd,
                                named_iofds,
@@ -6956,18 +6952,37 @@ static void *remove_tmpdir_thread(void *p) {
         return NULL;
 }
 
-static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) {
+static ExecSharedRuntime* exec_shared_runtime_free(ExecSharedRuntime *rt) {
+        if (!rt)
+                return NULL;
+
+        if (rt->manager)
+                (void) hashmap_remove(rt->manager->exec_shared_runtime_by_id, rt->id);
+
+        rt->id = mfree(rt->id);
+        rt->tmp_dir = mfree(rt->tmp_dir);
+        rt->var_tmp_dir = mfree(rt->var_tmp_dir);
+        safe_close_pair(rt->netns_storage_socket);
+        safe_close_pair(rt->ipcns_storage_socket);
+        return mfree(rt);
+}
+
+DEFINE_TRIVIAL_UNREF_FUNC(ExecSharedRuntime, exec_shared_runtime, exec_shared_runtime_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(ExecSharedRuntime*, exec_shared_runtime_free);
+
+ExecSharedRuntime* exec_shared_runtime_destroy(ExecSharedRuntime *rt) {
         int r;
 
         if (!rt)
                 return NULL;
 
-        if (rt->manager)
-                (void) hashmap_remove(rt->manager->exec_runtime_by_id, rt->id);
+        assert(rt->n_ref > 0);
+        rt->n_ref--;
 
-        /* When destroy is true, then rm_rf tmp_dir and var_tmp_dir. */
+        if (rt->n_ref > 0)
+                return NULL;
 
-        if (destroy && rt->tmp_dir && !streq(rt->tmp_dir, RUN_SYSTEMD_EMPTY)) {
+        if (rt->tmp_dir && !streq(rt->tmp_dir, RUN_SYSTEMD_EMPTY)) {
                 log_debug("Spawning thread to nuke %s", rt->tmp_dir);
 
                 r = asynchronous_job(remove_tmpdir_thread, rt->tmp_dir);
@@ -6977,7 +6992,7 @@ static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) {
                         rt->tmp_dir = NULL;
         }
 
-        if (destroy && rt->var_tmp_dir && !streq(rt->var_tmp_dir, RUN_SYSTEMD_EMPTY)) {
+        if (rt->var_tmp_dir && !streq(rt->var_tmp_dir, RUN_SYSTEMD_EMPTY)) {
                 log_debug("Spawning thread to nuke %s", rt->var_tmp_dir);
 
                 r = asynchronous_job(remove_tmpdir_thread, rt->var_tmp_dir);
@@ -6987,21 +7002,12 @@ static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) {
                         rt->var_tmp_dir = NULL;
         }
 
-        rt->id = mfree(rt->id);
-        rt->tmp_dir = mfree(rt->tmp_dir);
-        rt->var_tmp_dir = mfree(rt->var_tmp_dir);
-        safe_close_pair(rt->netns_storage_socket);
-        safe_close_pair(rt->ipcns_storage_socket);
-        return mfree(rt);
-}
-
-static void exec_runtime_freep(ExecRuntime **rt) {
-        (void) exec_runtime_free(*rt, false);
+        return exec_shared_runtime_free(rt);
 }
 
-static int exec_runtime_allocate(ExecRuntime **ret, const char *id) {
+static int exec_shared_runtime_allocate(ExecSharedRuntime **ret, const char *id) {
         _cleanup_free_ char *id_copy = NULL;
-        ExecRuntime *n;
+        ExecSharedRuntime *n;
 
         assert(ret);
 
@@ -7009,11 +7015,11 @@ static int exec_runtime_allocate(ExecRuntime **ret, const char *id) {
         if (!id_copy)
                 return -ENOMEM;
 
-        n = new(ExecRuntime, 1);
+        n = new(ExecSharedRuntime, 1);
         if (!n)
                 return -ENOMEM;
 
-        *n = (ExecRuntime) {
+        *n = (ExecSharedRuntime) {
                 .id = TAKE_PTR(id_copy),
                 .netns_storage_socket = PIPE_EBADF,
                 .ipcns_storage_socket = PIPE_EBADF,
@@ -7023,16 +7029,16 @@ static int exec_runtime_allocate(ExecRuntime **ret, const char *id) {
         return 0;
 }
 
-static int exec_runtime_add(
+static int exec_shared_runtime_add(
                 Manager *m,
                 const char *id,
                 char **tmp_dir,
                 char **var_tmp_dir,
                 int netns_storage_socket[2],
                 int ipcns_storage_socket[2],
-                ExecRuntime **ret) {
+                ExecSharedRuntime **ret) {
 
-        _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
+        _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt = NULL;
         int r;
 
         assert(m);
@@ -7040,11 +7046,11 @@ static int exec_runtime_add(
 
         /* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
 
-        r = exec_runtime_allocate(&rt, id);
+        r = exec_shared_runtime_allocate(&rt, id);
         if (r < 0)
                 return r;
 
-        r = hashmap_ensure_put(&m->exec_runtime_by_id, &string_hash_ops, rt->id, rt);
+        r = hashmap_ensure_put(&m->exec_shared_runtime_by_id, &string_hash_ops, rt->id, rt);
         if (r < 0)
                 return r;
 
@@ -7066,16 +7072,16 @@ static int exec_runtime_add(
 
         if (ret)
                 *ret = rt;
-        /* do not remove created ExecRuntime object when the operation succeeds. */
+        /* do not remove created ExecSharedRuntime object when the operation succeeds. */
         TAKE_PTR(rt);
         return 0;
 }
 
-static int exec_runtime_make(
+static int exec_shared_runtime_make(
                 Manager *m,
                 const ExecContext *c,
                 const char *id,
-                ExecRuntime **ret) {
+                ExecSharedRuntime **ret) {
 
         _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
         _cleanup_close_pair_ int netns_storage_socket[2] = PIPE_EBADF, ipcns_storage_socket[2] = PIPE_EBADF;
@@ -7085,7 +7091,7 @@ static int exec_runtime_make(
         assert(c);
         assert(id);
 
-        /* It is not necessary to create ExecRuntime object. */
+        /* It is not necessary to create ExecSharedRuntime object. */
         if (!exec_needs_network_namespace(c) && !exec_needs_ipc_namespace(c) && !c->private_tmp) {
                 *ret = NULL;
                 return 0;
@@ -7110,24 +7116,24 @@ static int exec_runtime_make(
                         return -errno;
         }
 
-        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret);
+        r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret);
         if (r < 0)
                 return r;
 
         return 1;
 }
 
-int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool create, ExecRuntime **ret) {
-        ExecRuntime *rt;
+int exec_shared_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool create, ExecSharedRuntime **ret) {
+        ExecSharedRuntime *rt;
         int r;
 
         assert(m);
         assert(id);
         assert(ret);
 
-        rt = hashmap_get(m->exec_runtime_by_id, id);
+        rt = hashmap_get(m->exec_shared_runtime_by_id, id);
         if (rt)
-                /* We already have an ExecRuntime object, let's increase the ref count and reuse it */
+                /* We already have an ExecSharedRuntime object, let's increase the ref count and reuse it */
                 goto ref;
 
         if (!create) {
@@ -7136,11 +7142,11 @@ int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool
         }
 
         /* If not found, then create a new object. */
-        r = exec_runtime_make(m, c, id, &rt);
+        r = exec_shared_runtime_make(m, c, id, &rt);
         if (r < 0)
                 return r;
         if (r == 0) {
-                /* When r == 0, it is not necessary to create ExecRuntime object. */
+                /* When r == 0, it is not necessary to create ExecSharedRuntime object. */
                 *ret = NULL;
                 return 0;
         }
@@ -7152,27 +7158,14 @@ ref:
         return 1;
 }
 
-ExecRuntime *exec_runtime_unref(ExecRuntime *rt, bool destroy) {
-        if (!rt)
-                return NULL;
-
-        assert(rt->n_ref > 0);
-
-        rt->n_ref--;
-        if (rt->n_ref > 0)
-                return NULL;
-
-        return exec_runtime_free(rt, destroy);
-}
-
-int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
-        ExecRuntime *rt;
+int exec_shared_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
+        ExecSharedRuntime *rt;
 
         assert(m);
         assert(f);
         assert(fds);
 
-        HASHMAP_FOREACH(rt, m->exec_runtime_by_id) {
+        HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
                 fprintf(f, "exec-runtime=%s", rt->id);
 
                 if (rt->tmp_dir)
@@ -7227,33 +7220,33 @@ int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
         return 0;
 }
 
-int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
-        _cleanup_(exec_runtime_freep) ExecRuntime *rt_create = NULL;
-        ExecRuntime *rt;
+int exec_shared_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
+        _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt_create = NULL;
+        ExecSharedRuntime *rt;
         int r;
 
         /* This is for the migration from old (v237 or earlier) deserialization text.
          * Due to the bug #7790, this may not work with the units that use JoinsNamespaceOf=.
-         * Even if the ExecRuntime object originally created by the other unit, we cannot judge
+         * Even if the ExecSharedRuntime object originally created by the other unit, we cannot judge
          * so or not from the serialized text, then we always creates a new object owned by this. */
 
         assert(u);
         assert(key);
         assert(value);
 
-        /* Manager manages ExecRuntime objects by the unit id.
+        /* Manager manages ExecSharedRuntime objects by the unit id.
          * So, we omit the serialized text when the unit does not have id (yet?)... */
         if (isempty(u->id)) {
                 log_unit_debug(u, "Invocation ID not found. Dropping runtime parameter.");
                 return 0;
         }
 
-        if (hashmap_ensure_allocated(&u->manager->exec_runtime_by_id, &string_hash_ops) < 0)
+        if (hashmap_ensure_allocated(&u->manager->exec_shared_runtime_by_id, &string_hash_ops) < 0)
                 return log_oom();
 
-        rt = hashmap_get(u->manager->exec_runtime_by_id, u->id);
+        rt = hashmap_get(u->manager->exec_shared_runtime_by_id, u->id);
         if (!rt) {
-                if (exec_runtime_allocate(&rt_create, u->id) < 0)
+                if (exec_shared_runtime_allocate(&rt_create, u->id) < 0)
                         return log_oom();
 
                 rt = rt_create;
@@ -7292,9 +7285,9 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
         } else
                 return 0;
 
-        /* If the object is newly created, then put it to the hashmap which manages ExecRuntime objects. */
+        /* If the object is newly created, then put it to the hashmap which manages ExecSharedRuntime objects. */
         if (rt_create) {
-                r = hashmap_put(u->manager->exec_runtime_by_id, rt_create->id, rt_create);
+                r = hashmap_put(u->manager->exec_shared_runtime_by_id, rt_create->id, rt_create);
                 if (r < 0) {
                         log_unit_debug_errno(u, r, "Failed to put runtime parameter to manager's storage: %m");
                         return 0;
@@ -7309,7 +7302,7 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
         return 1;
 }
 
-int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
+int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
         _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
         char *id = NULL;
         int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
@@ -7421,27 +7414,68 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
         }
 
 finalize:
-        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL);
+        r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL);
         if (r < 0)
                 return log_debug_errno(r, "Failed to add exec-runtime: %m");
         return 0;
 }
 
-void exec_runtime_vacuum(Manager *m) {
-        ExecRuntime *rt;
+void exec_shared_runtime_vacuum(Manager *m) {
+        ExecSharedRuntime *rt;
 
         assert(m);
 
-        /* Free unreferenced ExecRuntime objects. This is used after manager deserialization process. */
+        /* Free unreferenced ExecSharedRuntime objects. This is used after manager deserialization process. */
 
-        HASHMAP_FOREACH(rt, m->exec_runtime_by_id) {
+        HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
                 if (rt->n_ref > 0)
                         continue;
 
-                (void) exec_runtime_free(rt, false);
+                (void) exec_shared_runtime_free(rt);
         }
 }
 
+int exec_runtime_make(ExecSharedRuntime *shared, DynamicCreds *creds, ExecRuntime **ret) {
+        _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
+
+        assert(ret);
+
+        if (!shared && !creds) {
+                *ret = NULL;
+                return 0;
+        }
+
+        rt = new(ExecRuntime, 1);
+        if (!rt)
+                return -ENOMEM;
+
+        *rt = (ExecRuntime) {
+                .shared = shared,
+                .dynamic_creds = creds,
+        };
+
+        *ret = TAKE_PTR(rt);
+        return 1;
+}
+
+ExecRuntime* exec_runtime_free(ExecRuntime *rt) {
+        if (!rt)
+                return NULL;
+
+        exec_shared_runtime_unref(rt->shared);
+        dynamic_creds_unref(rt->dynamic_creds);
+        return mfree(rt);
+}
+
+ExecRuntime* exec_runtime_destroy(ExecRuntime *rt) {
+        if (!rt)
+                return NULL;
+
+        rt->shared = exec_shared_runtime_destroy(rt->shared);
+        rt->dynamic_creds = dynamic_creds_destroy(rt->dynamic_creds);
+        return exec_runtime_free(rt);
+}
+
 void exec_params_clear(ExecParameters *p) {
         if (!p)
                 return;
index ff537b77cb6df58453cc8d5de40dbed71a4256a9..254a1ee2d13a5eafc14c8fde9b0d1dd323ac8455 100644 (file)
@@ -4,6 +4,8 @@
 typedef struct ExecStatus ExecStatus;
 typedef struct ExecCommand ExecCommand;
 typedef struct ExecContext ExecContext;
+typedef struct ExecSharedRuntime ExecSharedRuntime;
+typedef struct DynamicCreds DynamicCreds;
 typedef struct ExecRuntime ExecRuntime;
 typedef struct ExecParameters ExecParameters;
 typedef struct Manager Manager;
@@ -106,7 +108,7 @@ struct ExecCommand {
  * invocations of commands. Specifically, this allows sharing of /tmp and /var/tmp data as well as network namespaces
  * between invocations of commands. This is a reference counted object, with one reference taken by each currently
  * active command invocation that wants to share this runtime. */
-struct ExecRuntime {
+struct ExecSharedRuntime {
         unsigned n_ref;
 
         Manager *manager;
@@ -124,6 +126,11 @@ struct ExecRuntime {
         int ipcns_storage_socket[2];
 };
 
+struct ExecRuntime {
+        ExecSharedRuntime *shared;
+        DynamicCreds *dynamic_creds;
+};
+
 typedef enum ExecDirectoryType {
         EXEC_DIRECTORY_RUNTIME = 0,
         EXEC_DIRECTORY_STATE,
@@ -440,7 +447,6 @@ int exec_spawn(Unit *unit,
                const ExecContext *context,
                const ExecParameters *exec_params,
                ExecRuntime *runtime,
-               DynamicCreds *dynamic_creds,
                const CGroupContext *cgroup_context,
                pid_t *ret);
 
@@ -483,13 +489,20 @@ void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int
 void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix);
 void exec_status_reset(ExecStatus *s);
 
-int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *name, bool create, ExecRuntime **ret);
-ExecRuntime *exec_runtime_unref(ExecRuntime *r, bool destroy);
+int exec_shared_runtime_acquire(Manager *m, const ExecContext *c, const char *name, bool create, ExecSharedRuntime **ret);
+ExecSharedRuntime *exec_shared_runtime_destroy(ExecSharedRuntime *r);
+ExecSharedRuntime *exec_shared_runtime_unref(ExecSharedRuntime *r);
+DEFINE_TRIVIAL_CLEANUP_FUNC(ExecSharedRuntime*, exec_shared_runtime_unref);
+
+int exec_shared_runtime_serialize(const Manager *m, FILE *f, FDSet *fds);
+int exec_shared_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds);
+int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds);
+void exec_shared_runtime_vacuum(Manager *m);
 
-int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds);
-int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds);
-int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds);
-void exec_runtime_vacuum(Manager *m);
+int exec_runtime_make(ExecSharedRuntime *shared, DynamicCreds *creds, ExecRuntime **ret);
+ExecRuntime* exec_runtime_free(ExecRuntime *rt);
+DEFINE_TRIVIAL_CLEANUP_FUNC(ExecRuntime*, exec_runtime_free);
+ExecRuntime* exec_runtime_destroy(ExecRuntime *rt);
 
 void exec_params_clear(ExecParameters *p);
 
index 61a464c06bfe041b652702e2ca9e6beb1a7e91d6..080383ced2b40ab9cb34ec7637ea9e39c6eec099 100644 (file)
@@ -174,7 +174,7 @@ int manager_serialize(
         manager_serialize_uid_refs(m, f);
         manager_serialize_gid_refs(m, f);
 
-        r = exec_runtime_serialize(m, f, fds);
+        r = exec_shared_runtime_serialize(m, f, fds);
         if (r < 0)
                 return r;
 
@@ -519,7 +519,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                 else if ((val = startswith(l, "destroy-ipc-gid=")))
                         manager_deserialize_gid_refs_one(m, val);
                 else if ((val = startswith(l, "exec-runtime=")))
-                        (void) exec_runtime_deserialize_one(m, val, fds);
+                        (void) exec_shared_runtime_deserialize_one(m, val, fds);
                 else if ((val = startswith(l, "subscribed="))) {
 
                         if (strv_extend(&m->deserialized_subscribed, val) < 0)
index 14fb2a0f1f890b89e52c07f7c921d28d00aeba98..dcc10266ac69d28de516491a2a6cc12ba1126fc6 100644 (file)
@@ -1555,8 +1555,8 @@ Manager* manager_free(Manager *m) {
         bus_done(m);
         manager_varlink_done(m);
 
-        exec_runtime_vacuum(m);
-        hashmap_free(m->exec_runtime_by_id);
+        exec_shared_runtime_vacuum(m);
+        hashmap_free(m->exec_shared_runtime_by_id);
 
         dynamic_user_vacuum(m, false);
         hashmap_free(m->dynamic_users);
@@ -3459,7 +3459,7 @@ int manager_reload(Manager *m) {
         manager_clear_jobs_and_units(m);
         lookup_paths_flush_generator(&m->lookup_paths);
         lookup_paths_free(&m->lookup_paths);
-        exec_runtime_vacuum(m);
+        exec_shared_runtime_vacuum(m);
         dynamic_user_vacuum(m, false);
         m->uid_refs = hashmap_free(m->uid_refs);
         m->gid_refs = hashmap_free(m->gid_refs);
@@ -4540,7 +4540,7 @@ static void manager_vacuum(Manager *m) {
         manager_vacuum_gid_refs(m);
 
         /* Release any runtimes no longer referenced */
-        exec_runtime_vacuum(m);
+        exec_shared_runtime_vacuum(m);
 }
 
 int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
index 25fcd275d4e647240bfd20ce754970d27840e9c3..fc95b751201c509ecc2fb52a2de2960506d8d25e 100644 (file)
@@ -429,8 +429,8 @@ struct Manager {
         Hashmap *uid_refs;
         Hashmap *gid_refs;
 
-        /* ExecRuntime, indexed by their owner unit id */
-        Hashmap *exec_runtime_by_id;
+        /* ExecSharedRuntime, indexed by their owner unit id */
+        Hashmap *exec_shared_runtime_by_id;
 
         /* When the user hits C-A-D more than 7 times per 2s, do something immediately... */
         RateLimit ctrl_alt_del_ratelimit;
index bbe22269469ffe77e641e16632f8cf31b6388067..586151bf67bbacdd30affef314dfedd23f7def65 100644 (file)
@@ -254,12 +254,10 @@ static void mount_done(Unit *u) {
         mount_parameters_done(&m->parameters_proc_self_mountinfo);
         mount_parameters_done(&m->parameters_fragment);
 
-        m->exec_runtime = exec_runtime_unref(m->exec_runtime, false);
+        m->exec_runtime = exec_runtime_free(m->exec_runtime);
         exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
         m->control_command = NULL;
 
-        dynamic_creds_unref(&m->dynamic_creds);
-
         mount_unwatch_control_pid(m);
 
         m->timer_event_source = sd_event_source_disable_unref(m->timer_event_source);
@@ -790,10 +788,8 @@ static int mount_coldplug(Unit *u) {
                         return r;
         }
 
-        if (!IN_SET(m->deserialized_state, MOUNT_DEAD, MOUNT_FAILED)) {
-                (void) unit_setup_dynamic_creds(u);
+        if (!IN_SET(m->deserialized_state, MOUNT_DEAD, MOUNT_FAILED))
                 (void) unit_setup_exec_runtime(u);
-        }
 
         mount_set_state(m, m->deserialized_state);
         return 0;
@@ -922,7 +918,6 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
                        &m->exec_context,
                        &exec_params,
                        m->exec_runtime,
-                       &m->dynamic_creds,
                        &m->cgroup_context,
                        &pid);
         if (r < 0)
@@ -948,14 +943,12 @@ static void mount_enter_dead(Mount *m, MountResult f) {
 
         mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
 
-        m->exec_runtime = exec_runtime_unref(m->exec_runtime, true);
+        m->exec_runtime = exec_runtime_destroy(m->exec_runtime);
 
         unit_destroy_runtime_data(UNIT(m), &m->exec_context);
 
         unit_unref_uid_gid(UNIT(m), true);
 
-        dynamic_creds_destroy(&m->dynamic_creds);
-
         /* Any dependencies based on /proc/self/mountinfo are now stale. Let's re-generate dependencies from
          * .mount unit. */
         (void) mount_add_non_exec_dependencies(m);
@@ -2268,7 +2261,6 @@ const UnitVTable mount_vtable = {
         .cgroup_context_offset = offsetof(Mount, cgroup_context),
         .kill_context_offset = offsetof(Mount, kill_context),
         .exec_runtime_offset = offsetof(Mount, exec_runtime),
-        .dynamic_creds_offset = offsetof(Mount, dynamic_creds),
 
         .sections =
                 "Unit\0"
index 1a0d9fc5e5921ece427617dd57dbaab32f1d1adb..d6d6d335a45d4879b898fb02428d0b801ebce631 100644 (file)
@@ -76,7 +76,6 @@ struct Mount {
         CGroupContext cgroup_context;
 
         ExecRuntime *exec_runtime;
-        DynamicCreds dynamic_creds;
 
         MountState state, deserialized_state;
 
index 02d514d56a869793291195743255e30119f092f2..d73feb363e10f2644b874e2fa14ec9455e330323 100644 (file)
@@ -66,6 +66,8 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
         [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
         [SERVICE_FAILED] = UNIT_FAILED,
+        [SERVICE_DEAD_BEFORE_AUTO_RESTART] = UNIT_INACTIVE,
+        [SERVICE_FAILED_BEFORE_AUTO_RESTART] = UNIT_FAILED,
         [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING,
         [SERVICE_CLEANING] = UNIT_MAINTENANCE,
 };
@@ -92,6 +94,8 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] =
         [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
         [SERVICE_FAILED] = UNIT_FAILED,
+        [SERVICE_DEAD_BEFORE_AUTO_RESTART] = UNIT_INACTIVE,
+        [SERVICE_FAILED_BEFORE_AUTO_RESTART] = UNIT_FAILED,
         [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING,
         [SERVICE_CLEANING] = UNIT_MAINTENANCE,
 };
@@ -267,6 +271,7 @@ static void service_start_watchdog(Service *s) {
 usec_t service_restart_usec(Service *s) {
         unsigned n_restarts;
         long double unit;
+        usec_t value;
 
         assert(s);
 
@@ -276,24 +281,26 @@ usec_t service_restart_usec(Service *s) {
          * between job enqueuing and running is usually neglectable compared to the time
          * we'll be sleeping. */
         n_restarts = s->n_restarts +
-                     (IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART) ? 1 : 0);
+                     (IN_SET(s->state, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART) ? 1 : 0);
 
         /* n_restarts can equal to 0 if no restart has happened nor planned */
         if (n_restarts <= 1 ||
             s->restart_steps == 0 ||
             s->restart_usec_max == USEC_INFINITY ||
-            s->restart_usec == s->restart_usec_max)
-                return s->restart_usec;
-
-        if (n_restarts > s->restart_steps)
-                return s->restart_usec_max;
-
-        /* Enforced in service_verify() and above */
-        assert(s->restart_usec_max > s->restart_usec);
+            s->restart_usec >= s->restart_usec_max)
+                value = s->restart_usec;
+        else if (n_restarts > s->restart_steps)
+                value = s->restart_usec_max;
+        else {
+                /* Enforced in service_verify() and above */
+                assert(s->restart_usec_max > s->restart_usec);
 
-        unit = powl(s->restart_usec_max - s->restart_usec, 1.0L / s->restart_steps);
+                unit = powl(s->restart_usec_max - s->restart_usec, 1.0L / s->restart_steps);
+                value = usec_add(s->restart_usec, (usec_t) powl(unit, n_restarts - 1));
+        }
 
-        return usec_add(s->restart_usec, (usec_t) powl(unit, n_restarts - 1));
+        log_unit_debug(UNIT(s), "Restart interval calculated as: %s", FORMAT_TIMESPAN(value, 0));
+        return value;
 }
 
 static void service_extend_event_source_timeout(Service *s, sd_event_source *source, usec_t extended) {
@@ -380,9 +387,6 @@ static void service_fd_store_unlink(ServiceFDStore *fs) {
 static void service_release_fd_store(Service *s) {
         assert(s);
 
-        if (s->n_keep_fd_store > 0)
-                return;
-
         log_unit_debug(UNIT(s), "Releasing all stored fds");
         while (s->fd_store)
                 service_fd_store_unlink(s->fd_store);
@@ -395,6 +399,10 @@ static void service_release_resources(Unit *u) {
 
         assert(s);
 
+        /* Don't release resources if this is a transitionary failed/dead state */
+        if (IN_SET(s->state, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART))
+                return;
+
         if (!s->fd_store && s->stdin_fd < 0 && s->stdout_fd < 0 && s->stderr_fd < 0)
                 return;
 
@@ -417,13 +425,11 @@ static void service_done(Unit *u) {
         s->pid_file = mfree(s->pid_file);
         s->status_text = mfree(s->status_text);
 
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
+        s->exec_runtime = exec_runtime_free(s->exec_runtime);
         exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
         s->control_command = NULL;
         s->main_command = NULL;
 
-        dynamic_creds_unref(&s->dynamic_creds);
-
         exit_status_set_free(&s->restart_prevent_status);
         exit_status_set_free(&s->restart_force_status);
         exit_status_set_free(&s->success_status);
@@ -1201,7 +1207,9 @@ static void service_set_state(Service *s, ServiceState state) {
                 s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
         }
 
-        if (IN_SET(state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) {
+        if (IN_SET(state,
+                   SERVICE_DEAD, SERVICE_FAILED,
+                   SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART)) {
                 unit_unwatch_all_pids(UNIT(s));
                 unit_dequeue_rewatch_pids(UNIT(s));
         }
@@ -1314,9 +1322,11 @@ static int service_coldplug(Unit *u) {
                         return r;
         }
 
-        if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART, SERVICE_CLEANING)) {
+        if (!IN_SET(s->deserialized_state,
+                    SERVICE_DEAD, SERVICE_FAILED,
+                    SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART,
+                    SERVICE_CLEANING)) {
                 (void) unit_enqueue_rewatch_pids(u);
-                (void) unit_setup_dynamic_creds(u);
                 (void) unit_setup_exec_runtime(u);
         }
 
@@ -1768,7 +1778,6 @@ static int service_spawn_internal(
                        &s->exec_context,
                        &exec_params,
                        s->exec_runtime,
-                       &s->dynamic_creds,
                        &s->cgroup_context,
                        &pid);
         if (r < 0)
@@ -1895,14 +1904,14 @@ static bool service_will_restart(Unit *u) {
 
         if (s->will_auto_restart)
                 return true;
-        if (s->state == SERVICE_AUTO_RESTART)
+        if (IN_SET(s->state, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART))
                 return true;
 
         return unit_will_restart_default(u);
 }
 
 static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
-        ServiceState end_state;
+        ServiceState end_state, restart_state;
         int r;
 
         assert(s);
@@ -1918,12 +1927,15 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
         if (s->result == SERVICE_SUCCESS) {
                 unit_log_success(UNIT(s));
                 end_state = SERVICE_DEAD;
+                restart_state = SERVICE_DEAD_BEFORE_AUTO_RESTART;
         } else if (s->result == SERVICE_SKIP_CONDITION) {
                 unit_log_skip(UNIT(s), service_result_to_string(s->result));
                 end_state = SERVICE_DEAD;
+                restart_state = SERVICE_DEAD_BEFORE_AUTO_RESTART;
         } else {
                 unit_log_failure(UNIT(s), service_result_to_string(s->result));
                 end_state = SERVICE_FAILED;
+                restart_state = SERVICE_FAILED_BEFORE_AUTO_RESTART;
         }
         unit_warn_leftover_processes(UNIT(s), unit_log_leftover_process_stop);
 
@@ -1941,30 +1953,33 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
                         s->will_auto_restart = true;
         }
 
-        /* Make sure service_release_resources() doesn't destroy our FD store, while we are changing through
-         * SERVICE_FAILED/SERVICE_DEAD before entering into SERVICE_AUTO_RESTART. */
-        s->n_keep_fd_store ++;
-
-        service_set_state(s, end_state);
-
         if (s->will_auto_restart) {
                 s->will_auto_restart = false;
 
+                /* We make two state changes here: one that maps to the high-level UNIT_INACTIVE/UNIT_FAILED
+                 * state (i.e. a state indicating deactivation), and then one that that maps to the
+                 * high-level UNIT_STARTING state (i.e. a state indicating activation). We do this so that
+                 * external software can watch the state changes and see all service failures, even if they
+                 * are only transitionary and followed by an automatic restart. We have fine-grained
+                 * low-level states for this though so that software can distinguish the permanent UNIT_INACTIVE
+                 * state from this transitionary UNIT_INACTIVE state by looking at the low-level states. */
+                service_set_state(s, restart_state);
+
                 r = service_arm_timer(s, /* relative= */ true, service_restart_usec(s));
-                if (r < 0) {
-                        s->n_keep_fd_store--;
+                if (r < 0)
                         goto fail;
-                }
 
                 service_set_state(s, SERVICE_AUTO_RESTART);
-        } else
+        } else {
+                service_set_state(s, end_state);
+
                 /* If we shan't restart, then flush out the restart counter. But don't do that immediately, so that the
                  * user can still introspect the counter. Do so on the next start. */
                 s->flush_n_restarts = true;
+        }
 
         /* The new state is in effect, let's decrease the fd store ref counter again. Let's also re-add us to the GC
          * queue, so that the fd store is possibly gc'ed again */
-        s->n_keep_fd_store--;
         unit_add_to_gc_queue(UNIT(s));
 
         /* The next restart might not be a manual stop, hence reset the flag indicating manual stops */
@@ -1974,7 +1989,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
         s->notify_access_override = _NOTIFY_ACCESS_INVALID;
 
         /* We want fresh tmpdirs in case service is started again immediately */
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
+        s->exec_runtime = exec_runtime_destroy(s->exec_runtime);
 
         /* Also, remove the runtime directory */
         unit_destroy_runtime_data(UNIT(s), &s->exec_context);
@@ -1982,9 +1997,6 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
         /* Get rid of the IPC bits of the user */
         unit_unref_uid_gid(UNIT(s), true);
 
-        /* Release the user, and destroy it if we are the only remaining owner */
-        dynamic_creds_destroy(&s->dynamic_creds);
-
         /* Try to delete the pid file. At this point it will be
          * out-of-date, and some software might be confused by it, so
          * let's remove it. */
@@ -2653,14 +2665,11 @@ static int service_start(Unit *u) {
         if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST))
                 return 0;
 
-        /* A service that will be restarted must be stopped first to
-         * trigger BindsTo and/or OnFailure dependencies. If a user
-         * does not want to wait for the holdoff time to elapse, the
-         * service should be manually restarted, not started. We
-         * simply return EAGAIN here, so that any start jobs stay
-         * queued, and assume that the auto restart timer will
-         * eventually trigger the restart. */
-        if (s->state == SERVICE_AUTO_RESTART)
+        /* A service that will be restarted must be stopped first to trigger BindsTo and/or OnFailure
+         * dependencies. If a user does not want to wait for the holdoff time to elapse, the service should
+         * be manually restarted, not started. We simply return EAGAIN here, so that any start jobs stay
+         * queued, and assume that the auto restart timer will eventually trigger the restart. */
+        if (IN_SET(s->state, SERVICE_AUTO_RESTART, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART))
                 return -EAGAIN;
 
         assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED));
@@ -2708,34 +2717,55 @@ static int service_stop(Unit *u) {
         /* Don't create restart jobs from manual stops. */
         s->forbid_restart = true;
 
-        /* Already on it */
-        if (IN_SET(s->state,
-                   SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                   SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
+        switch (s->state) {
+
+        case SERVICE_STOP:
+        case SERVICE_STOP_SIGTERM:
+        case SERVICE_STOP_SIGKILL:
+        case SERVICE_STOP_POST:
+        case SERVICE_FINAL_WATCHDOG:
+        case SERVICE_FINAL_SIGTERM:
+        case SERVICE_FINAL_SIGKILL:
+                /* Already on it */
                 return 0;
 
-        /* A restart will be scheduled or is in progress. */
-        if (s->state == SERVICE_AUTO_RESTART) {
+        case SERVICE_AUTO_RESTART:
+                /* A restart will be scheduled or is in progress. */
                 service_set_state(s, SERVICE_DEAD);
                 return 0;
-        }
 
-        /* If there's already something running we go directly into kill mode. */
-        if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_STOP_WATCHDOG)) {
+        case SERVICE_CONDITION:
+        case SERVICE_START_PRE:
+        case SERVICE_START:
+        case SERVICE_START_POST:
+        case SERVICE_RELOAD:
+        case SERVICE_RELOAD_SIGNAL:
+        case SERVICE_RELOAD_NOTIFY:
+        case SERVICE_STOP_WATCHDOG:
+                /* If there's already something running we go directly into kill mode. */
                 service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
                 return 0;
-        }
 
-        /* If we are currently cleaning, then abort it, brutally. */
-        if (s->state == SERVICE_CLEANING) {
+        case SERVICE_CLEANING:
+                /* If we are currently cleaning, then abort it, brutally. */
                 service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS);
                 return 0;
+
+        case SERVICE_RUNNING:
+        case SERVICE_EXITED:
+                service_enter_stop(s, SERVICE_SUCCESS);
+                return 1;
+
+        case SERVICE_DEAD_BEFORE_AUTO_RESTART:
+        case SERVICE_FAILED_BEFORE_AUTO_RESTART:
+        case SERVICE_DEAD:
+        case SERVICE_FAILED:
+        default:
+                /* Unknown state, or unit_stop() should already have handled these */
+                assert_not_reached();
         }
 
-        assert(IN_SET(s->state, SERVICE_RUNNING, SERVICE_EXITED));
 
-        service_enter_stop(s, SERVICE_SUCCESS);
-        return 1;
 }
 
 static int service_reload(Unit *u) {
@@ -3338,6 +3368,11 @@ static bool service_may_gc(Unit *u) {
             control_pid_good(s) > 0)
                 return false;
 
+        /* Only allow collection of actually dead services, i.e. not those that are in the transitionary
+         * SERVICE_DEAD_BEFORE_AUTO_RESTART/SERVICE_FAILED_BEFORE_AUTO_RESTART states. */
+        if (!IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED))
+                return false;
+
         return true;
 }
 
@@ -3499,11 +3534,9 @@ static void service_notify_cgroup_empty_event(Unit *u) {
 
         switch (s->state) {
 
-                /* Waiting for SIGCHLD is usually more interesting,
-                 * because it includes return codes/signals. Which is
-                 * why we ignore the cgroup events for most cases,
-                 * except when we don't know pid which to expect the
-                 * SIGCHLD for. */
+                /* Waiting for SIGCHLD is usually more interesting, because it includes return
+                 * codes/signals. Which is why we ignore the cgroup events for most cases, except when we
+                 * don't know pid which to expect the SIGCHLD for. */
 
         case SERVICE_START:
                 if (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) &&
@@ -3561,6 +3594,9 @@ static void service_notify_cgroup_empty_event(Unit *u) {
          * up the cgroup earlier and should do it now. */
         case SERVICE_DEAD:
         case SERVICE_FAILED:
+        case SERVICE_DEAD_BEFORE_AUTO_RESTART:
+        case SERVICE_FAILED_BEFORE_AUTO_RESTART:
+        case SERVICE_AUTO_RESTART:
                 unit_prune_cgroup(u);
                 break;
 
@@ -4943,7 +4979,6 @@ const UnitVTable service_vtable = {
         .cgroup_context_offset = offsetof(Service, cgroup_context),
         .kill_context_offset = offsetof(Service, kill_context),
         .exec_runtime_offset = offsetof(Service, exec_runtime),
-        .dynamic_creds_offset = offsetof(Service, dynamic_creds),
 
         .sections =
                 "Unit\0"
index 9d5b15d8c2e71a2b663408a5b0f86c37e6e360fd..156d32ca17143c44abf4e5ebf711a079b91a7ac4 100644 (file)
@@ -158,7 +158,6 @@ struct Service {
 
         /* Runtime data of the execution context */
         ExecRuntime *exec_runtime;
-        DynamicCreds dynamic_creds;
 
         pid_t main_pid, control_pid;
 
@@ -207,7 +206,6 @@ struct Service {
         ServiceFDStore *fd_store;
         size_t n_fd_store;
         unsigned n_fd_store_max;
-        unsigned n_keep_fd_store;
 
         char *usb_function_descriptors;
         char *usb_function_strings;
index 6b153a92faa7e005ea1c4b30e42d40aaf51037fd..c26daced1ac0bd902f14c8d892a34ec7a833dad0 100644 (file)
@@ -150,12 +150,10 @@ static void socket_done(Unit *u) {
 
         s->peers_by_address = set_free(s->peers_by_address);
 
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
+        s->exec_runtime = exec_runtime_free(s->exec_runtime);
         exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX);
         s->control_command = NULL;
 
-        dynamic_creds_unref(&s->dynamic_creds);
-
         socket_unwatch_control_pid(s);
 
         unit_ref_unset(&s->service);
@@ -1532,16 +1530,18 @@ static int socket_address_listen_in_cgroup(
 
         if (s->exec_context.network_namespace_path &&
             s->exec_runtime &&
-            s->exec_runtime->netns_storage_socket[0] >= 0) {
-                r = open_shareable_ns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path, CLONE_NEWNET);
+            s->exec_runtime->shared &&
+            s->exec_runtime->shared->netns_storage_socket[0] >= 0) {
+                r = open_shareable_ns_path(s->exec_runtime->shared->netns_storage_socket, s->exec_context.network_namespace_path, CLONE_NEWNET);
                 if (r < 0)
                         return log_unit_error_errno(UNIT(s), r, "Failed to open network namespace path %s: %m", s->exec_context.network_namespace_path);
         }
 
         if (s->exec_context.ipc_namespace_path &&
             s->exec_runtime &&
-            s->exec_runtime->ipcns_storage_socket[0] >= 0) {
-                r = open_shareable_ns_path(s->exec_runtime->ipcns_storage_socket, s->exec_context.ipc_namespace_path, CLONE_NEWIPC);
+            s->exec_runtime->shared &&
+            s->exec_runtime->shared->ipcns_storage_socket[0] >= 0) {
+                r = open_shareable_ns_path(s->exec_runtime->shared->ipcns_storage_socket, s->exec_context.ipc_namespace_path, CLONE_NEWIPC);
                 if (r < 0)
                         return log_unit_error_errno(UNIT(s), r, "Failed to open IPC namespace path %s: %m", s->exec_context.ipc_namespace_path);
         }
@@ -1559,10 +1559,11 @@ static int socket_address_listen_in_cgroup(
 
                 if (exec_needs_network_namespace(&s->exec_context) &&
                     s->exec_runtime &&
-                    s->exec_runtime->netns_storage_socket[0] >= 0) {
+                    s->exec_runtime->shared &&
+                    s->exec_runtime->shared->netns_storage_socket[0] >= 0) {
 
                         if (ns_type_supported(NAMESPACE_NET)) {
-                                r = setup_shareable_ns(s->exec_runtime->netns_storage_socket, CLONE_NEWNET);
+                                r = setup_shareable_ns(s->exec_runtime->shared->netns_storage_socket, CLONE_NEWNET);
                                 if (r < 0) {
                                         log_unit_error_errno(UNIT(s), r, "Failed to join network namespace: %m");
                                         _exit(EXIT_NETWORK);
@@ -1905,10 +1906,8 @@ static int socket_coldplug(Unit *u) {
                         return r;
         }
 
-        if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED, SOCKET_CLEANING)) {
-                (void) unit_setup_dynamic_creds(u);
+        if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED, SOCKET_CLEANING))
                 (void) unit_setup_exec_runtime(u);
-        }
 
         socket_set_state(s, s->deserialized_state);
         return 0;
@@ -1947,7 +1946,6 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
                        &s->exec_context,
                        &exec_params,
                        s->exec_runtime,
-                       &s->dynamic_creds,
                        &s->cgroup_context,
                        &pid);
         if (r < 0)
@@ -2049,13 +2047,11 @@ static void socket_enter_dead(Socket *s, SocketResult f) {
 
         socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
 
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
+        s->exec_runtime = exec_runtime_destroy(s->exec_runtime);
 
         unit_destroy_runtime_data(UNIT(s), &s->exec_context);
 
         unit_unref_uid_gid(UNIT(s), true);
-
-        dynamic_creds_destroy(&s->dynamic_creds);
 }
 
 static void socket_enter_signal(Socket *s, SocketState state, SocketResult f);
@@ -2488,7 +2484,7 @@ static int socket_start(Unit *u) {
 
                 /* If the service is already active we cannot start the
                  * socket */
-                if (!IN_SET(service->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
+                if (!IN_SET(service->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART))
                         return log_unit_error_errno(u, SYNTHETIC_ERRNO(EBUSY), "Socket service %s already active, refusing.", UNIT(service)->id);
         }
 
@@ -3291,7 +3287,7 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
                 return;
 
         if (IN_SET(SERVICE(other)->state,
-                   SERVICE_DEAD, SERVICE_FAILED,
+                   SERVICE_DEAD, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED, SERVICE_FAILED_BEFORE_AUTO_RESTART,
                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
                    SERVICE_AUTO_RESTART))
                socket_enter_listening(s);
@@ -3468,7 +3464,6 @@ const UnitVTable socket_vtable = {
         .cgroup_context_offset = offsetof(Socket, cgroup_context),
         .kill_context_offset = offsetof(Socket, kill_context),
         .exec_runtime_offset = offsetof(Socket, exec_runtime),
-        .dynamic_creds_offset = offsetof(Socket, dynamic_creds),
 
         .sections =
                 "Unit\0"
index 6813bdcf8c8e1faed413937db02d638e5b01ae5d..308a0727568991425a58791da77639287783f9c8 100644 (file)
@@ -91,7 +91,6 @@ struct Socket {
         CGroupContext cgroup_context;
 
         ExecRuntime *exec_runtime;
-        DynamicCreds dynamic_creds;
 
         /* For Accept=no sockets refers to the one service we'll
          * activate. For Accept=yes sockets is either NULL, or filled
index d0b557cf400c863ec105b051fbf7ac097df6760b..c6e2c8b1bd94536cd2d557bd78607acc491abf7b 100644 (file)
@@ -170,12 +170,10 @@ static void swap_done(Unit *u) {
         s->parameters_fragment.what = mfree(s->parameters_fragment.what);
         s->parameters_fragment.options = mfree(s->parameters_fragment.options);
 
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
+        s->exec_runtime = exec_runtime_free(s->exec_runtime);
         exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
         s->control_command = NULL;
 
-        dynamic_creds_unref(&s->dynamic_creds);
-
         swap_unwatch_control_pid(s);
 
         s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
@@ -593,10 +591,8 @@ static int swap_coldplug(Unit *u) {
                         return r;
         }
 
-        if (!IN_SET(new_state, SWAP_DEAD, SWAP_FAILED)) {
-                (void) unit_setup_dynamic_creds(u);
+        if (!IN_SET(new_state, SWAP_DEAD, SWAP_FAILED))
                 (void) unit_setup_exec_runtime(u);
-        }
 
         swap_set_state(s, new_state);
         return 0;
@@ -689,7 +685,6 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
                        &s->exec_context,
                        &exec_params,
                        s->exec_runtime,
-                       &s->dynamic_creds,
                        &s->cgroup_context,
                        &pid);
         if (r < 0)
@@ -719,13 +714,11 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
         unit_warn_leftover_processes(UNIT(s), unit_log_leftover_process_stop);
         swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
 
-        s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
+        s->exec_runtime = exec_runtime_destroy(s->exec_runtime);
 
         unit_destroy_runtime_data(UNIT(s), &s->exec_context);
 
         unit_unref_uid_gid(UNIT(s), true);
-
-        dynamic_creds_destroy(&s->dynamic_creds);
 }
 
 static void swap_enter_active(Swap *s, SwapResult f) {
@@ -1619,7 +1612,6 @@ const UnitVTable swap_vtable = {
         .cgroup_context_offset = offsetof(Swap, cgroup_context),
         .kill_context_offset = offsetof(Swap, kill_context),
         .exec_runtime_offset = offsetof(Swap, exec_runtime),
-        .dynamic_creds_offset = offsetof(Swap, dynamic_creds),
 
         .sections =
                 "Unit\0"
index c0e3f118e18da15333adc7917c388bddf0d02728..d61c7112cf6b4fc51412cc467edded4d81eac5a6 100644 (file)
@@ -68,7 +68,6 @@ struct Swap {
         CGroupContext cgroup_context;
 
         ExecRuntime *exec_runtime;
-        DynamicCreds dynamic_creds;
 
         SwapState state, deserialized_state;
 
index 21457dc6a5f6b3678e25f9b89981be3007be9e3d..8055d9e5335254bc187f7cad961c84ba67996b21 100644 (file)
@@ -522,7 +522,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
                         continue;
                 }
 
-                r = exec_runtime_deserialize_compat(u, l, v, fds);
+                r = exec_shared_runtime_deserialize_compat(u, l, v, fds);
                 if (r < 0) {
                         log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
                         continue;
index 0418593d251523ee317492d68f92ffa9df97467f..e3a57e3b843538d35f3b06b33c12c145c83a2af5 100644 (file)
@@ -4791,7 +4791,10 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask)
 }
 
 int unit_setup_exec_runtime(Unit *u) {
+        _cleanup_(exec_shared_runtime_unrefp) ExecSharedRuntime *esr = NULL;
+        _cleanup_(dynamic_creds_unrefp) DynamicCreds *dcreds = NULL;
         ExecRuntime **rt;
+        ExecContext *ec;
         size_t offset;
         Unit *other;
         int r;
@@ -4804,34 +4807,38 @@ int unit_setup_exec_runtime(Unit *u) {
         if (*rt)
                 return 0;
 
+        ec = unit_get_exec_context(u);
+        assert(ec);
+
         /* Try to get it from somebody else */
         UNIT_FOREACH_DEPENDENCY(other, u, UNIT_ATOM_JOINS_NAMESPACE_OF) {
-                r = exec_runtime_acquire(u->manager, NULL, other->id, false, rt);
-                if (r == 1)
-                        return 1;
+                r = exec_shared_runtime_acquire(u->manager, NULL, other->id, false, &esr);
+                if (r < 0)
+                        return r;
+                if (r > 0)
+                        break;
         }
 
-        return exec_runtime_acquire(u->manager, unit_get_exec_context(u), u->id, true, rt);
-}
-
-int unit_setup_dynamic_creds(Unit *u) {
-        ExecContext *ec;
-        DynamicCreds *dcreds;
-        size_t offset;
-
-        assert(u);
+        if (!esr) {
+                r = exec_shared_runtime_acquire(u->manager, ec, u->id, true, &esr);
+                if (r < 0)
+                        return r;
+        }
 
-        offset = UNIT_VTABLE(u)->dynamic_creds_offset;
-        assert(offset > 0);
-        dcreds = (DynamicCreds*) ((uint8_t*) u + offset);
+        if (ec->dynamic_user) {
+                r = dynamic_creds_make(u->manager, ec->user, ec->group, &dcreds);
+                if (r < 0)
+                        return r;
+        }
 
-        ec = unit_get_exec_context(u);
-        assert(ec);
+        r = exec_runtime_make(esr, dcreds, rt);
+        if (r < 0)
+                return r;
 
-        if (!ec->dynamic_user)
-                return 0;
+        TAKE_PTR(esr);
+        TAKE_PTR(dcreds);
 
-        return dynamic_creds_acquire(dcreds, u->manager, ec->user, ec->group);
+        return r;
 }
 
 bool unit_type_supported(UnitType t) {
@@ -5565,10 +5572,6 @@ int unit_prepare_exec(Unit *u) {
         if (r < 0)
                 return r;
 
-        r = unit_setup_dynamic_creds(u);
-        if (r < 0)
-                return r;
-
         return 0;
 }
 
index 8f53773a119816d5a5baa57e43480ce1e22a576d..513c8181f57e7422e034bd32ebe582e7d9ea51e7 100644 (file)
@@ -570,14 +570,10 @@ typedef struct UnitVTable {
         size_t kill_context_offset;
 
         /* If greater than 0, the offset into the object where the
-         * pointer to ExecRuntime is found, if the unit type has
+         * pointer to ExecSharedRuntime is found, if the unit type has
          * that */
         size_t exec_runtime_offset;
 
-        /* If greater than 0, the offset into the object where the pointer to DynamicCreds is found, if the unit type
-         * has that. */
-        size_t dynamic_creds_offset;
-
         /* The name of the configuration file section with the private settings of this unit */
         const char *private_section;
 
@@ -967,7 +963,6 @@ CGroupContext *unit_get_cgroup_context(Unit *u) _pure_;
 ExecRuntime *unit_get_exec_runtime(Unit *u) _pure_;
 
 int unit_setup_exec_runtime(Unit *u);
-int unit_setup_dynamic_creds(Unit *u);
 
 char* unit_escape_setting(const char *s, UnitWriteFlags flags, char **buf);
 char* unit_concat_strv(char **l, UnitWriteFlags flags);