]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #29152 from poettering/pidref-more
authorLuca Boccassi <bluca@debian.org>
Tue, 19 Sep 2023 00:12:09 +0000 (01:12 +0100)
committerGitHub <noreply@github.com>
Tue, 19 Sep 2023 00:12:09 +0000 (01:12 +0100)
pid1: port more code over to PidRef (i.e. pidfd based operation)

13 files changed:
TODO
src/basic/pidref.c
src/basic/pidref.h
src/core/dbus-service.c
src/core/dbus-unit.c
src/core/mount.c
src/core/scope.c
src/core/service.c
src/core/slice.c
src/core/socket.c
src/core/swap.c
src/core/unit.c
src/core/unit.h

diff --git a/TODO b/TODO
index d54ff5cbb061ead0e865788eae0c522cbc62a6be..349e31f1f756d3bcb4fd587bb2c2b401db894710 100644 (file)
--- a/TODO
+++ b/TODO
@@ -174,14 +174,9 @@ Features:
   - pid_is_unwaited() → pidref_is_unwaited()
   - pid_is_alive() → pidref_is_alive()
   - unit_watch_pid() → unit_watch_pidref()
-  - unit_kill_common()
-  - unit_kill_context()
-  - service_set_main_pid()
-  - actually wait for POLLIN on piref's pidfd in service logic
-  - unit_main_pid() + unit_control_pid()
+  - actually wait for POLLIN on pidref's pidfd in service logic
   - exec_spawn()
   - serialization of control/main pid in service, socket, mount, swap units
-  - unit_fork_and_watch_rm_rf()
   - cg_pid_get_unit()
   - openpt_allocate_in_namespace()
   - scope dbus PIDs property needs to gain PIDFDs companion
index f41460938c1b96c7ae7af6376e738ba716b36a00..e1ad697af0cc8309b1e2cab82d5bb33e60728290 100644 (file)
@@ -6,6 +6,7 @@
 #include "parse-util.h"
 #include "pidref.h"
 #include "process-util.h"
+#include "signal-util.h"
 
 int pidref_set_pid(PidRef *pidref, pid_t pid) {
         int fd;
@@ -143,3 +144,30 @@ int pidref_kill_and_sigcont(PidRef *pidref, int sig) {
 
         return 0;
 }
+
+int pidref_sigqueue(PidRef *pidref, int sig, int value) {
+
+        if (!pidref)
+                return -ESRCH;
+
+        if (pidref->fd >= 0) {
+                siginfo_t si;
+
+                /* We can't use structured initialization here, since the structure contains various unions
+                 * and these fields lie in overlapping (carefully aligned) unions that LLVM is allergic to
+                 * allow assignments to */
+                zero(si);
+                si.si_signo = sig;
+                si.si_code = SI_QUEUE;
+                si.si_pid = getpid_cached();
+                si.si_uid = getuid();
+                si.si_value.sival_int = value;
+
+                return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, &si, 0));
+        }
+
+        if (pidref->pid > 0)
+                return RET_NERRNO(sigqueue(pidref->pid, sig, (const union sigval) { .sival_int = value }));
+
+        return -ESRCH;
+}
index 2411e510f13378d90460417535df9ac937ca2d92..6998a865e7fd65ebe83e6f7afcef90a978e867f2 100644 (file)
@@ -25,5 +25,6 @@ void pidref_done(PidRef *pidref);
 
 int pidref_kill(PidRef *pidref, int sig);
 int pidref_kill_and_sigcont(PidRef *pidref, int sig);
+int pidref_sigqueue(PidRef *pidfref, int sig, int value);
 
 #define TAKE_PIDREF(p) TAKE_GENERIC((p), PidRef, PIDREF_NULL)
index cc65a5599035d96689b559da1036025c3023ef1d..5bc487bc39925068f315caac6cd3ca089be11b6c 100644 (file)
@@ -134,7 +134,6 @@ static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_
         int read_only, make_file_or_directory;
         Unit *u = ASSERT_PTR(userdata);
         ExecContext *c;
-        pid_t unit_pid;
         int r;
 
         assert(message);
@@ -192,14 +191,14 @@ static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_
         if (!exec_needs_mount_namespace(c, NULL, unit_get_exec_runtime(u)))
                 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit not running in private mount namespace, cannot activate bind mount");
 
-        unit_pid = unit_main_pid(u);
-        if (unit_pid == 0 || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
+        PidRef* unit_pid = unit_main_pid(u);
+        if (!pidref_is_set(unit_pid) || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
                 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not running");
 
         propagate_directory = strjoina("/run/systemd/propagate/", u->id);
         if (is_image)
                 r = mount_image_in_namespace(
-                                unit_pid,
+                                unit_pid->pid,
                                 propagate_directory,
                                 "/run/systemd/incoming/",
                                 src, dest,
@@ -209,7 +208,7 @@ static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_
                                 c->mount_image_policy ?: &image_policy_service);
         else
                 r = bind_mount_in_namespace(
-                                unit_pid,
+                                unit_pid->pid,
                                 propagate_directory,
                                 "/run/systemd/incoming/",
                                 src, dest,
index 1f673fe26d2d72c47a3523f5527fee8515316961..e9b446945aaa60846b043973c8b3292bf6fac9b6 100644 (file)
@@ -1331,7 +1331,6 @@ int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bu
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_set_free_ Set *pids = NULL;
         Unit *u = userdata;
-        pid_t pid;
         int r;
 
         assert(message);
@@ -1359,16 +1358,16 @@ int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bu
         }
 
         /* The main and control pids might live outside of the cgroup, hence fetch them separately */
-        pid = unit_main_pid(u);
-        if (pid > 0) {
-                r = append_process(reply, NULL, pid, pids);
+        PidRef *pid = unit_main_pid(u);
+        if (pidref_is_set(pid)) {
+                r = append_process(reply, NULL, pid->pid, pids);
                 if (r < 0)
                         return r;
         }
 
         pid = unit_control_pid(u);
-        if (pid > 0) {
-                r = append_process(reply, NULL, pid, pids);
+        if (pidref_is_set(pid)) {
+                r = append_process(reply, NULL, pid->pid, pids);
                 if (r < 0)
                         return r;
         }
index 57045f3da4c0980c2ad9e9cc569c9f30871b9ddf..08c2ddf9156592185468b5a118a9776d0847e26d 100644 (file)
@@ -1036,9 +1036,9 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
                         UNIT(m),
                         &m->kill_context,
                         state_to_kill_operation(state),
-                        -1,
-                        m->control_pid.pid,
-                        false);
+                        /* main_pid= */ NULL,
+                        &m->control_pid,
+                        /* main_pid_alien= */ false);
         if (r < 0)
                 goto fail;
 
@@ -2213,26 +2213,13 @@ static void mount_reset_failed(Unit *u) {
         m->clean_result = MOUNT_SUCCESS;
 }
 
-static int mount_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
-        Mount *m = MOUNT(u);
-
-        assert(m);
-
-        return unit_kill_common(u, who, signo, code, value, -1, m->control_pid.pid, error);
-}
-
-static int mount_control_pid(Unit *u) {
-        Mount *m = MOUNT(u);
-
-        assert(m);
-
-        return m->control_pid.pid;
+static PidRef* mount_control_pid(Unit *u) {
+        return &ASSERT_PTR(MOUNT(u))->control_pid;
 }
 
 static int mount_clean(Unit *u, ExecCleanMask mask) {
         _cleanup_strv_free_ char **l = NULL;
         Mount *m = MOUNT(u);
-        pid_t pid;
         int r;
 
         assert(m);
@@ -2257,11 +2244,7 @@ static int mount_clean(Unit *u, ExecCleanMask mask) {
         if (r < 0)
                 goto fail;
 
-        r = unit_fork_and_watch_rm_rf(u, l, &pid);
-        if (r < 0)
-                goto fail;
-
-        r = pidref_set_pid(&m->control_pid, pid);
+        r = unit_fork_and_watch_rm_rf(u, l, &m->control_pid);
         if (r < 0)
                 goto fail;
 
@@ -2358,7 +2341,6 @@ const UnitVTable mount_vtable = {
         .stop = mount_stop,
         .reload = mount_reload,
 
-        .kill = mount_kill,
         .clean = mount_clean,
         .can_clean = mount_can_clean,
 
index a13c8ddf7a49f37cb22fe427ddefc5f94683dc27..eb3ffba084dcdaadaeb91ab0699e28dbed660cda 100644 (file)
@@ -345,7 +345,9 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
                                 state != SCOPE_STOP_SIGTERM ? KILL_KILL :
                                 s->was_abandoned            ? KILL_TERMINATE_AND_LOG :
                                                               KILL_TERMINATE,
-                                -1, -1, false);
+                                /* main_pid= */ NULL,
+                                /* control_pid= */ NULL,
+                                /* main_pid_alien= */ false);
                 if (r < 0)
                         goto fail;
         }
@@ -370,8 +372,8 @@ fail:
 }
 
 static int scope_enter_start_chown(Scope *s) {
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
         Unit *u = UNIT(s);
-        pid_t pid;
         int r;
 
         assert(s);
@@ -381,7 +383,7 @@ static int scope_enter_start_chown(Scope *s) {
         if (r < 0)
                 return r;
 
-        r = unit_fork_helper_process(u, "(sd-chown-cgroup)", &pid);
+        r = unit_fork_helper_process(u, "(sd-chown-cgroup)", &pidref);
         if (r < 0)
                 goto fail;
 
@@ -418,7 +420,7 @@ static int scope_enter_start_chown(Scope *s) {
                 _exit(EXIT_SUCCESS);
         }
 
-        r = unit_watch_pid(UNIT(s), pid, true);
+        r = unit_watch_pid(UNIT(s), pidref.pid, /* exclusive= */ true);
         if (r < 0)
                 goto fail;
 
@@ -531,10 +533,6 @@ static void scope_reset_failed(Unit *u) {
         s->result = SCOPE_SUCCESS;
 }
 
-static int scope_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
-        return unit_kill_common(u, who, signo, code, value, -1, -1, error);
-}
-
 static int scope_get_timeout(Unit *u, usec_t *timeout) {
         Scope *s = SCOPE(u);
         usec_t t;
@@ -828,8 +826,6 @@ const UnitVTable scope_vtable = {
         .start = scope_start,
         .stop = scope_stop,
 
-        .kill = scope_kill,
-
         .freeze = unit_freeze_vtable_common,
         .thaw = unit_thaw_vtable_common,
 
index ecaeea63cfdf90b984465661259d906d38924af4..05a2bb6ddf1a58ce6bc9620ae6acb0c49219e35e 100644 (file)
@@ -179,40 +179,53 @@ static void service_unwatch_pid_file(Service *s) {
         s->pid_file_pathspec = mfree(s->pid_file_pathspec);
 }
 
-static int service_set_main_pid(Service *s, pid_t pid) {
-        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
-        int r;
-
+static int service_set_main_pidref(Service *s, PidRef *pidref) {
         assert(s);
 
-        if (pid <= 1)
+        /* Takes ownership of the specified pidref on success, but not on failure. */
+
+        if (!pidref_is_set(pidref))
+                return -ESRCH;
+
+        if (pidref->pid <= 1)
                 return -EINVAL;
 
-        if (pid == getpid_cached())
+        if (pidref->pid == getpid_cached())
                 return -EINVAL;
 
-        if (s->main_pid.pid == pid && s->main_pid_known)
+        if (s->main_pid.pid == pidref->pid && s->main_pid_known) {
+                pidref_done(pidref);
                 return 0;
+        }
 
-        r = pidref_set_pid(&pidref, pid);
-        if (r < 0)
-                return r;
-
-        if (s->main_pid.pid != pid) {
+        if (s->main_pid.pid != pidref->pid) {
                 service_unwatch_main_pid(s);
-                exec_status_start(&s->main_exec_status, pid);
+                exec_status_start(&s->main_exec_status, pidref->pid);
         }
 
-        s->main_pid = TAKE_PIDREF(pidref);
+        s->main_pid = TAKE_PIDREF(*pidref);
         s->main_pid_known = true;
-        s->main_pid_alien = pid_is_my_child(pid) == 0;
+        s->main_pid_alien = pid_is_my_child(s->main_pid.pid) == 0;
 
         if (s->main_pid_alien)
-                log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid);
+                log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", s->main_pid.pid);
 
         return 0;
 }
 
+static int service_set_main_pid(Service *s, pid_t pid) {
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+        int r;
+
+        assert(s);
+
+        r = pidref_set_pid(&pidref, pid);
+        if (r < 0)
+                return r;
+
+        return service_set_main_pidref(s, &pidref);
+}
+
 void service_release_socket_fd(Service *s) {
         assert(s);
 
@@ -1108,6 +1121,7 @@ static int service_is_suitable_main_pid(Service *s, pid_t pid, int prio) {
 }
 
 static int service_load_pid_file(Service *s, bool may_warn) {
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
         bool questionable_pid_file = false;
         _cleanup_free_ char *k = NULL;
         _cleanup_close_ int fd = -EBADF;
@@ -1149,7 +1163,11 @@ static int service_load_pid_file(Service *s, bool may_warn) {
         if (s->main_pid_known && pid == s->main_pid.pid)
                 return 0;
 
-        r = service_is_suitable_main_pid(s, pid, prio);
+        r = pidref_set_pid(&pidref, pid);
+        if (r < 0)
+                return log_unit_full_errno(UNIT(s), prio, r, "Failed to pin PID " PID_FMT ": %m", pid);
+
+        r = service_is_suitable_main_pid(s, pidref.pid, prio);
         if (r < 0)
                 return r;
         if (r == 0) {
@@ -1166,26 +1184,26 @@ static int service_load_pid_file(Service *s, bool may_warn) {
 
                 if (st.st_uid != 0)
                         return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(EPERM),
-                                                    "New main PID "PID_FMT" does not belong to service, and PID file is not owned by root. Refusing.", pid);
+                                                    "New main PID "PID_FMT" does not belong to service, and PID file is not owned by root. Refusing.", pidref.pid);
 
-                log_unit_debug(UNIT(s), "New main PID "PID_FMT" does not belong to service, but we'll accept it since PID file is owned by root.", pid);
+                log_unit_debug(UNIT(s), "New main PID "PID_FMT" does not belong to service, but we'll accept it since PID file is owned by root.", pidref.pid);
         }
 
         if (s->main_pid_known) {
-                log_unit_debug(UNIT(s), "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid.pid, pid);
+                log_unit_debug(UNIT(s), "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid.pid, pidref.pid);
 
                 service_unwatch_main_pid(s);
                 s->main_pid_known = false;
         } else
-                log_unit_debug(UNIT(s), "Main PID loaded: "PID_FMT, pid);
+                log_unit_debug(UNIT(s), "Main PID loaded: "PID_FMT, pidref.pid);
 
-        r = service_set_main_pid(s, pid);
+        r = service_set_main_pidref(s, &pidref);
         if (r < 0)
                 return r;
 
-        r = unit_watch_pid(UNIT(s), pid, /* exclusive= */ false);
+        r = unit_watch_pid(UNIT(s), s->main_pid.pid, /* exclusive= */ false);
         if (r < 0) /* FIXME: we need to do something here */
-                return log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" for service: %m", pid);
+                return log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" for service: %m", s->main_pid.pid);
 
         return 1;
 }
@@ -1212,10 +1230,10 @@ static void service_search_main_pid(Service *s) {
         if (service_set_main_pid(s, pid) < 0)
                 return;
 
-        r = unit_watch_pid(UNIT(s), pid, /* exclusive= */ false);
+        r = unit_watch_pid(UNIT(s), s->main_pid.pid, /* exclusive= */ false);
         if (r < 0)
                 /* FIXME: we need to do something here */
-                log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid);
+                log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", s->main_pid.pid);
 }
 
 static void service_set_state(Service *s, ServiceState state) {
@@ -2148,8 +2166,8 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
                         UNIT(s),
                         &s->kill_context,
                         kill_operation,
-                        s->main_pid.pid,
-                        s->control_pid.pid,
+                        &s->main_pid,
+                        &s->control_pid,
                         s->main_pid_alien);
         if (r < 0)
                 goto fail;
@@ -2412,7 +2430,7 @@ static void service_enter_start(Service *s) {
                 /* For simple services we immediately start
                  * the START_POST binaries. */
 
-                (void) service_set_main_pid(s, pidref.pid);
+                (void) service_set_main_pidref(s, &pidref);
                 service_enter_start_post(s);
 
         } else  if (s->type == SERVICE_FORKING) {
@@ -2431,7 +2449,7 @@ static void service_enter_start(Service *s) {
                 /* For D-Bus services we know the main pid right away, but wait for the bus name to appear on the
                  * bus. 'notify' and 'exec' services are similar. */
 
-                (void) service_set_main_pid(s, pidref.pid);
+                (void) service_set_main_pidref(s, &pidref);
                 service_set_state(s, SERVICE_START);
         } else
                 assert_not_reached();
@@ -2700,8 +2718,7 @@ static void service_run_next_main(Service *s) {
         if (r < 0)
                 goto fail;
 
-        (void) service_set_main_pid(s, pidref.pid);
-
+        (void) service_set_main_pidref(s, &pidref);
         return;
 
 fail:
@@ -4808,28 +4825,12 @@ static void service_reset_failed(Unit *u) {
         s->flush_n_restarts = false;
 }
 
-static int service_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        return unit_kill_common(u, who, signo, code, value, s->main_pid.pid, s->control_pid.pid, error);
+static PidRef* service_main_pid(Unit *u) {
+        return &ASSERT_PTR(SERVICE(u))->main_pid;
 }
 
-static int service_main_pid(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        return s->main_pid.pid;
-}
-
-static int service_control_pid(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        return s->control_pid.pid;
+static PidRef* service_control_pid(Unit *u) {
+        return &ASSERT_PTR(SERVICE(u))->control_pid;
 }
 
 static bool service_needs_console(Unit *u) {
@@ -4889,7 +4890,6 @@ static int service_clean(Unit *u, ExecCleanMask mask) {
         _cleanup_strv_free_ char **l = NULL;
         bool may_clean_fdstore = false;
         Service *s = SERVICE(u);
-        pid_t pid;
         int r;
 
         assert(s);
@@ -4930,11 +4930,7 @@ static int service_clean(Unit *u, ExecCleanMask mask) {
         if (r < 0)
                 goto fail;
 
-        r = unit_fork_and_watch_rm_rf(u, l, &pid);
-        if (r < 0)
-                goto fail;
-
-        r = pidref_set_pid(&s->control_pid, pid);
+        r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid);
         if (r < 0)
                 goto fail;
 
@@ -5146,7 +5142,6 @@ const UnitVTable service_vtable = {
 
         .can_reload = service_can_reload,
 
-        .kill = service_kill,
         .clean = service_clean,
         .can_clean = service_can_clean,
 
index c6d142cebbaba7626b13bf57ebf8ce06cec35a90..c7701b4017faf90d7a3fd0ee404fd444f2c50340 100644 (file)
@@ -247,10 +247,6 @@ static int slice_stop(Unit *u) {
         return 1;
 }
 
-static int slice_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
-        return unit_kill_common(u, who, signo, code, value, -1, -1, error);
-}
-
 static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
         Slice *s = SLICE(u);
 
@@ -436,8 +432,6 @@ const UnitVTable slice_vtable = {
         .start = slice_start,
         .stop = slice_stop,
 
-        .kill = slice_kill,
-
         .freeze = slice_freeze,
         .thaw = slice_thaw,
         .can_freeze = slice_can_freeze,
index 9e7809721afd35fba6c18791f0f6e3cd5b51b349..3304af831dbe24ee2111b40940e1d8c4043d5527 100644 (file)
@@ -1503,9 +1503,9 @@ static int socket_address_listen_in_cgroup(
                 const SocketAddress *address,
                 const char *label) {
 
+        _cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
         _cleanup_close_pair_ int pair[2] = PIPE_EBADF;
         int fd, r;
-        pid_t pid;
 
         assert(s);
         assert(address);
@@ -1597,7 +1597,7 @@ static int socket_address_listen_in_cgroup(
         fd = receive_one_fd(pair[0], 0);
 
         /* We synchronously wait for the helper, as it shouldn't be slow */
-        r = wait_for_terminate_and_check("(sd-listen)", pid, WAIT_LOG_ABNORMAL);
+        r = wait_for_terminate_and_check("(sd-listen)", pid.pid, WAIT_LOG_ABNORMAL);
         if (r < 0) {
                 safe_close(fd);
                 return r;
@@ -1968,8 +1968,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, PidRef *ret_pid) {
 }
 
 static int socket_chown(Socket *s, PidRef *ret_pid) {
-        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
-        pid_t pid;
+        _cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
         int r;
 
         assert(s);
@@ -2030,15 +2029,11 @@ static int socket_chown(Socket *s, PidRef *ret_pid) {
                 _exit(EXIT_SUCCESS);
         }
 
-        r = pidref_set_pid(&pidref, pid);
-        if (r < 0)
-                return r;
-
-        r = unit_watch_pid(UNIT(s), pidref.pid, /* exclusive= */ true);
+        r = unit_watch_pid(UNIT(s), pid.pid, /* exclusive= */ true);
         if (r < 0)
                 return r;
 
-        *ret_pid = TAKE_PIDREF(pidref);
+        *ret_pid = TAKE_PIDREF(pid);
         return 0;
 }
 
@@ -2117,9 +2112,9 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
                         UNIT(s),
                         &s->kill_context,
                         state_to_kill_operation(s, state),
-                        -1,
-                        s->control_pid.pid,
-                        false);
+                        /* main_pid= */ NULL,
+                        &s->control_pid,
+                        /* main_pid_alien= */ false);
         if (r < 0)
                 goto fail;
 
@@ -2982,9 +2977,9 @@ static int socket_accept_do(Socket *s, int fd) {
 }
 
 static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
+        _cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
         _cleanup_close_pair_ int pair[2] = PIPE_EBADF;
         int cfd, r;
-        pid_t pid;
 
         assert(s);
         assert(p);
@@ -3034,7 +3029,7 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
         cfd = receive_one_fd(pair[0], 0);
 
         /* We synchronously wait for the helper, as it shouldn't be slow */
-        r = wait_for_terminate_and_check("(sd-accept)", pid, WAIT_LOG_ABNORMAL);
+        r = wait_for_terminate_and_check("(sd-accept)", pid.pid, WAIT_LOG_ABNORMAL);
         if (r < 0) {
                 safe_close(cfd);
                 return r;
@@ -3382,10 +3377,6 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
                 socket_set_state(s, SOCKET_RUNNING);
 }
 
-static int socket_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
-        return unit_kill_common(u, who, signo, code, value, -1, SOCKET(u)->control_pid.pid, error);
-}
-
 static int socket_get_timeout(Unit *u, usec_t *timeout) {
         Socket *s = SOCKET(u);
         usec_t t;
@@ -3414,18 +3405,13 @@ char *socket_fdname(Socket *s) {
         return s->fdname ?: UNIT(s)->id;
 }
 
-static int socket_control_pid(Unit *u) {
-        Socket *s = SOCKET(u);
-
-        assert(s);
-
-        return s->control_pid.pid;
+static PidRef *socket_control_pid(Unit *u) {
+        return &ASSERT_PTR(SOCKET(u))->control_pid;
 }
 
 static int socket_clean(Unit *u, ExecCleanMask mask) {
         _cleanup_strv_free_ char **l = NULL;
         Socket *s = SOCKET(u);
-        pid_t pid;
         int r;
 
         assert(s);
@@ -3450,11 +3436,7 @@ static int socket_clean(Unit *u, ExecCleanMask mask) {
         if (r < 0)
                 goto fail;
 
-        r = unit_fork_and_watch_rm_rf(u, l, &pid);
-        if (r < 0)
-                goto fail;
-
-        r = pidref_set_pid(&s->control_pid, pid);
+        r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid);
         if (r < 0)
                 goto fail;
 
@@ -3576,7 +3558,6 @@ const UnitVTable socket_vtable = {
         .start = socket_start,
         .stop = socket_stop,
 
-        .kill = socket_kill,
         .clean = socket_clean,
         .can_clean = socket_can_clean,
 
index c6b5f3471a26e303bb0074a0f6e30d18b24861ea..aa04b99462275948feaaf4b22cdf4a8f569d9da3 100644 (file)
@@ -763,12 +763,13 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
         if (s->result == SWAP_SUCCESS)
                 s->result = f;
 
-        r = unit_kill_context(UNIT(s),
-                              &s->kill_context,
-                              state_to_kill_operation(s, state),
-                              -1,
-                              s->control_pid.pid,
-                              false);
+        r = unit_kill_context(
+                        UNIT(s),
+                        &s->kill_context,
+                        state_to_kill_operation(s, state),
+                        /* main_pid= */ NULL,
+                        &s->control_pid,
+                        /* main_pid_alien= */ false);
         if (r < 0)
                 goto fail;
 
@@ -1475,10 +1476,6 @@ static void swap_reset_failed(Unit *u) {
         s->clean_result = SWAP_SUCCESS;
 }
 
-static int swap_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
-        return unit_kill_common(u, who, signo, code, value, -1, SWAP(u)->control_pid.pid, error);
-}
-
 static int swap_get_timeout(Unit *u, usec_t *timeout) {
         Swap *s = SWAP(u);
         usec_t t;
@@ -1515,18 +1512,13 @@ static bool swap_supported(void) {
         return supported;
 }
 
-static int swap_control_pid(Unit *u) {
-        Swap *s = SWAP(u);
-
-        assert(s);
-
-        return s->control_pid.pid;
+static PidRef* swap_control_pid(Unit *u) {
+        return &ASSERT_PTR(SWAP(u))->control_pid;
 }
 
 static int swap_clean(Unit *u, ExecCleanMask mask) {
         _cleanup_strv_free_ char **l = NULL;
         Swap *s = SWAP(u);
-        pid_t pid;
         int r;
 
         assert(s);
@@ -1551,11 +1543,7 @@ static int swap_clean(Unit *u, ExecCleanMask mask) {
         if (r < 0)
                 goto fail;
 
-        r = unit_fork_and_watch_rm_rf(u, l, &pid);
-        if (r < 0)
-                goto fail;
-
-        r = pidref_set_pid(&s->control_pid, pid);
+        r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid);
         if (r < 0)
                 goto fail;
 
@@ -1637,7 +1625,6 @@ const UnitVTable swap_vtable = {
         .start = swap_start,
         .stop = swap_stop,
 
-        .kill = swap_kill,
         .clean = swap_clean,
         .can_clean = swap_can_clean,
 
index 6f13348ebf5b0f6b23c3a77684d2c6c01b08876a..5fd66e7b6e042bde4759fe0e98e029a1fa07345e 100644 (file)
@@ -2943,7 +2943,7 @@ void unit_unwatch_all_pids(Unit *u) {
 }
 
 static void unit_tidy_watch_pids(Unit *u) {
-        pid_t except1, except2;
+        PidRef *except1, *except2;
         void *e;
 
         assert(u);
@@ -2956,7 +2956,8 @@ static void unit_tidy_watch_pids(Unit *u) {
         SET_FOREACH(e, u->pids) {
                 pid_t pid = PTR_TO_PID(e);
 
-                if (pid == except1 || pid == except2)
+                if ((pidref_is_set(except1) && pid == except1->pid) ||
+                    (pidref_is_set(except2) && pid == except2->pid))
                         continue;
 
                 if (!pid_is_unwaited(pid))
@@ -3958,18 +3959,6 @@ bool unit_will_restart(Unit *u) {
         return UNIT_VTABLE(u)->will_restart(u);
 }
 
-int unit_kill(Unit *u, KillWho w, int signo, int code, int value, sd_bus_error *error) {
-        assert(u);
-        assert(w >= 0 && w < _KILL_WHO_MAX);
-        assert(SIGNAL_VALID(signo));
-        assert(IN_SET(code, SI_USER, SI_QUEUE));
-
-        if (!UNIT_VTABLE(u)->kill)
-                return -EOPNOTSUPP;
-
-        return UNIT_VTABLE(u)->kill(u, w, signo, code, value, error);
-}
-
 void unit_notify_cgroup_oom(Unit *u, bool managed_oom) {
         assert(u);
 
@@ -4012,35 +4001,34 @@ static int kill_common_log(pid_t pid, int signo, void *userdata) {
         return 1;
 }
 
-static int kill_or_sigqueue(pid_t pid, int signo, int code, int value) {
-        assert(pid > 0);
+static int kill_or_sigqueue(PidRef* pidref, int signo, int code, int value) {
+        assert(pidref_is_set(pidref));
         assert(SIGNAL_VALID(signo));
 
         switch (code) {
 
         case SI_USER:
-                log_debug("Killing " PID_FMT " with signal SIG%s.", pid, signal_to_string(signo));
-                return RET_NERRNO(kill(pid, signo));
+                log_debug("Killing " PID_FMT " with signal SIG%s.", pidref->pid, signal_to_string(signo));
+                return pidref_kill(pidref, signo);
 
         case SI_QUEUE:
-                log_debug("Enqueuing value %i to " PID_FMT " on signal SIG%s.", value, pid, signal_to_string(signo));
-                return RET_NERRNO(sigqueue(pid, signo, (const union sigval) { .sival_int = value }));
+                log_debug("Enqueuing value %i to " PID_FMT " on signal SIG%s.", value, pidref->pid, signal_to_string(signo));
+                return pidref_sigqueue(pidref, signo, value);
 
         default:
                 assert_not_reached();
         }
 }
 
-int unit_kill_common(
+int unit_kill(
                 Unit *u,
                 KillWho who,
                 int signo,
                 int code,
                 int value,
-                pid_t main_pid,
-                pid_t control_pid,
                 sd_bus_error *error) {
 
+        PidRef *main_pid, *control_pid;
         bool killed = false;
         int ret = 0, r;
 
@@ -4054,24 +4042,30 @@ int unit_kill_common(
         assert(SIGNAL_VALID(signo));
         assert(IN_SET(code, SI_USER, SI_QUEUE));
 
+        main_pid = unit_main_pid(u);
+        control_pid = unit_control_pid(u);
+
+        if (!UNIT_HAS_CGROUP_CONTEXT(u) && !main_pid && !control_pid)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Unit type does not support process killing.");
+
         if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL)) {
-                if (main_pid < 0)
+                if (!main_pid)
                         return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
-                if (main_pid == 0)
+                if (!pidref_is_set(main_pid))
                         return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
         }
 
         if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL)) {
-                if (control_pid < 0)
+                if (!control_pid)
                         return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
-                if (control_pid == 0)
+                if (!pidref_is_set(control_pid))
                         return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
         }
 
-        if (control_pid > 0 &&
+        if (pidref_is_set(control_pid) &&
             IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL, KILL_ALL, KILL_ALL_FAIL)) {
                 _cleanup_free_ char *comm = NULL;
-                (void) get_process_comm(control_pid, &comm);
+                (void) get_process_comm(control_pid->pid, &comm);
 
                 r = kill_or_sigqueue(control_pid, signo, code, value);
                 if (r < 0) {
@@ -4081,23 +4075,23 @@ int unit_kill_common(
                         sd_bus_error_set_errnof(
                                         error, r,
                                         "Failed to send signal SIG%s to control process " PID_FMT " (%s): %m",
-                                        signal_to_string(signo), control_pid, strna(comm));
+                                        signal_to_string(signo), control_pid->pid, strna(comm));
                         log_unit_warning_errno(
                                         u, r,
                                         "Failed to send signal SIG%s to control process " PID_FMT " (%s) on client request: %m",
-                                        signal_to_string(signo), control_pid, strna(comm));
+                                        signal_to_string(signo), control_pid->pid, strna(comm));
                 } else {
                         log_unit_info(u, "Sent signal SIG%s to control process " PID_FMT " (%s) on client request.",
-                                      signal_to_string(signo), control_pid, strna(comm));
+                                      signal_to_string(signo), control_pid->pid, strna(comm));
                         killed = true;
                 }
         }
 
-        if (main_pid > 0 &&
+        if (pidref_is_set(main_pid) &&
             IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL, KILL_ALL, KILL_ALL_FAIL)) {
 
                 _cleanup_free_ char *comm = NULL;
-                (void) get_process_comm(main_pid, &comm);
+                (void) get_process_comm(main_pid->pid, &comm);
 
                 r = kill_or_sigqueue(main_pid, signo, code, value);
                 if (r < 0) {
@@ -4107,17 +4101,17 @@ int unit_kill_common(
                                 sd_bus_error_set_errnof(
                                                 error, r,
                                                 "Failed to send signal SIG%s to main process " PID_FMT " (%s): %m",
-                                                signal_to_string(signo), main_pid, strna(comm));
+                                                signal_to_string(signo), main_pid->pid, strna(comm));
                         }
 
                         log_unit_warning_errno(
                                         u, r,
                                         "Failed to send signal SIG%s to main process " PID_FMT " (%s) on client request: %m",
-                                        signal_to_string(signo), main_pid, strna(comm));
+                                        signal_to_string(signo), main_pid->pid, strna(comm));
 
                 } else {
                         log_unit_info(u, "Sent signal SIG%s to main process " PID_FMT " (%s) on client request.",
-                                      signal_to_string(signo), main_pid, strna(comm));
+                                      signal_to_string(signo), main_pid->pid, strna(comm));
                         killed = true;
                 }
         }
@@ -4129,7 +4123,7 @@ int unit_kill_common(
                 _cleanup_set_free_ Set *pid_set = NULL;
 
                 /* Exclude the main/control pids from being killed via the cgroup */
-                pid_set = unit_pid_set(main_pid, control_pid);
+                pid_set = unit_pid_set(main_pid ? main_pid->pid : 0, control_pid ? control_pid->pid : 0);
                 if (!pid_set)
                         return log_oom();
 
@@ -4775,8 +4769,8 @@ int unit_kill_context(
                 Unit *u,
                 KillContext *c,
                 KillOperation k,
-                pid_t main_pid,
-                pid_t control_pid,
+                PidRef* main_pid,
+                PidRef* control_pid,
                 bool main_pid_alien) {
 
         bool wait_for_exit = false, send_sighup;
@@ -4803,40 +4797,40 @@ int unit_kill_context(
                 IN_SET(k, KILL_TERMINATE, KILL_TERMINATE_AND_LOG) &&
                 sig != SIGHUP;
 
-        if (main_pid > 0) {
+        if (pidref_is_set(main_pid)) {
                 if (log_func)
-                        log_func(main_pid, sig, u);
+                        log_func(main_pid->pid, sig, u);
 
-                r = kill_and_sigcont(main_pid, sig);
+                r = pidref_kill_and_sigcont(main_pid, sig);
                 if (r < 0 && r != -ESRCH) {
                         _cleanup_free_ char *comm = NULL;
-                        (void) get_process_comm(main_pid, &comm);
+                        (void) get_process_comm(main_pid->pid, &comm);
 
-                        log_unit_warning_errno(u, r, "Failed to kill main process " PID_FMT " (%s), ignoring: %m", main_pid, strna(comm));
+                        log_unit_warning_errno(u, r, "Failed to kill main process " PID_FMT " (%s), ignoring: %m", main_pid->pid, strna(comm));
                 } else {
                         if (!main_pid_alien)
                                 wait_for_exit = true;
 
                         if (r != -ESRCH && send_sighup)
-                                (void) kill(main_pid, SIGHUP);
+                                (void) pidref_kill(main_pid, SIGHUP);
                 }
         }
 
-        if (control_pid > 0) {
+        if (pidref_is_set(control_pid)) {
                 if (log_func)
-                        log_func(control_pid, sig, u);
+                        log_func(control_pid->pid, sig, u);
 
-                r = kill_and_sigcont(control_pid, sig);
+                r = pidref_kill_and_sigcont(control_pid, sig);
                 if (r < 0 && r != -ESRCH) {
                         _cleanup_free_ char *comm = NULL;
-                        (void) get_process_comm(control_pid, &comm);
+                        (void) get_process_comm(control_pid->pid, &comm);
 
-                        log_unit_warning_errno(u, r, "Failed to kill control process " PID_FMT " (%s), ignoring: %m", control_pid, strna(comm));
+                        log_unit_warning_errno(u, r, "Failed to kill control process " PID_FMT " (%s), ignoring: %m", control_pid->pid, strna(comm));
                 } else {
                         wait_for_exit = true;
 
                         if (r != -ESRCH && send_sighup)
-                                (void) kill(control_pid, SIGHUP);
+                                (void) pidref_kill(control_pid, SIGHUP);
                 }
         }
 
@@ -4845,7 +4839,7 @@ int unit_kill_context(
                 _cleanup_set_free_ Set *pid_set = NULL;
 
                 /* Exclude the main/control pids from being killed via the cgroup */
-                pid_set = unit_pid_set(main_pid, control_pid);
+                pid_set = unit_pid_set(main_pid ? main_pid->pid : 0, control_pid ? control_pid->pid : 0);
                 if (!pid_set)
                         return -ENOMEM;
 
@@ -4874,7 +4868,7 @@ int unit_kill_context(
                         if (send_sighup) {
                                 set_free(pid_set);
 
-                                pid_set = unit_pid_set(main_pid, control_pid);
+                                pid_set = unit_pid_set(main_pid ? main_pid->pid : 0, control_pid ? control_pid->pid : 0);
                                 if (!pid_set)
                                         return -ENOMEM;
 
@@ -5120,22 +5114,22 @@ bool unit_is_pristine(Unit *u) {
                !u->merged_into;
 }
 
-pid_t unit_control_pid(Unit *u) {
+PidRef* unit_control_pid(Unit *u) {
         assert(u);
 
         if (UNIT_VTABLE(u)->control_pid)
                 return UNIT_VTABLE(u)->control_pid(u);
 
-        return 0;
+        return NULL;
 }
 
-pid_t unit_main_pid(Unit *u) {
+PidRef* unit_main_pid(Unit *u) {
         assert(u);
 
         if (UNIT_VTABLE(u)->main_pid)
                 return UNIT_VTABLE(u)->main_pid(u);
 
-        return 0;
+        return NULL;
 }
 
 static void unit_unref_uid_internal(
@@ -5325,7 +5319,8 @@ int unit_set_exec_params(Unit *u, ExecParameters *p) {
         return 0;
 }
 
-int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret) {
+int unit_fork_helper_process(Unit *u, const char *name, PidRef *ret) {
+        pid_t pid;
         int r;
 
         assert(u);
@@ -5336,9 +5331,24 @@ int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret) {
 
         (void) unit_realize_cgroup(u);
 
-        r = safe_fork(name, FORK_REOPEN_LOG|FORK_DEATHSIG, ret);
-        if (r != 0)
+        r = safe_fork(name, FORK_REOPEN_LOG|FORK_DEATHSIG, &pid);
+        if (r < 0)
                 return r;
+        if (r > 0) {
+                _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+                int q;
+
+                /* Parent */
+
+                q = pidref_set_pid(&pidref, pid);
+                if (q < 0)
+                        return q;
+
+                *ret = TAKE_PIDREF(pidref);
+                return r;
+        }
+
+        /* Child */
 
         (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE);
         (void) ignore_signals(SIGPIPE);
@@ -5354,8 +5364,8 @@ int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret) {
         return 0;
 }
 
-int unit_fork_and_watch_rm_rf(Unit *u, char **paths, pid_t *ret_pid) {
-        pid_t pid;
+int unit_fork_and_watch_rm_rf(Unit *u, char **paths, PidRef *ret_pid) {
+        _cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
         int r;
 
         assert(u);
@@ -5378,11 +5388,11 @@ int unit_fork_and_watch_rm_rf(Unit *u, char **paths, pid_t *ret_pid) {
                 _exit(ret);
         }
 
-        r = unit_watch_pid(u, pid, true);
+        r = unit_watch_pid(u, pid.pid, /* exclusive= */ true);
         if (r < 0)
                 return r;
 
-        *ret_pid = pid;
+        *ret_pid = TAKE_PIDREF(pid);
         return 0;
 }
 
index c0710299a54a964b68fb9284b97049876c8ddaa6..f1a80cc8912201ff896b0173b231286a8efc8fd0 100644 (file)
@@ -9,14 +9,15 @@
 #include "sd-id128.h"
 
 #include "bpf-program.h"
+#include "cgroup.h"
 #include "condition.h"
 #include "emergency-action.h"
 #include "install.h"
 #include "list.h"
-#include "show-status.h"
+#include "pidref.h"
 #include "set.h"
+#include "show-status.h"
 #include "unit-file.h"
-#include "cgroup.h"
 
 typedef struct UnitRef UnitRef;
 
@@ -624,8 +625,6 @@ typedef struct UnitVTable {
         int (*stop)(Unit *u);
         int (*reload)(Unit *u);
 
-        int (*kill)(Unit *u, KillWho w, int signo, int code, int value, sd_bus_error *error);
-
         /* Clear out the various runtime/state/cache/logs/configuration data */
         int (*clean)(Unit *u, ExecCleanMask m);
 
@@ -719,10 +718,10 @@ typedef struct UnitVTable {
         usec_t (*get_timeout_start_usec)(Unit *u);
 
         /* Returns the main PID if there is any defined, or 0. */
-        pid_t (*main_pid)(Unit *u);
+        PidRef* (*main_pid)(Unit *u);
 
-        /* Returns the main PID if there is any defined, or 0. */
-        pid_t (*control_pid)(Unit *u);
+        /* Returns the control PID if there is any defined, or 0. */
+        PidRef* (*control_pid)(Unit *u);
 
         /* Returns true if the unit currently needs access to the console */
         bool (*needs_console)(Unit *u);
@@ -913,7 +912,6 @@ int unit_stop(Unit *u);
 int unit_reload(Unit *u);
 
 int unit_kill(Unit *u, KillWho w, int signo, int code, int value, sd_bus_error *error);
-int unit_kill_common(Unit *u, KillWho who, int signo, int code, int value, pid_t main_pid, pid_t control_pid, sd_bus_error *error);
 
 void unit_notify_cgroup_oom(Unit *u, bool managed_oom);
 
@@ -992,7 +990,7 @@ char* unit_concat_strv(char **l, UnitWriteFlags flags);
 int unit_write_setting(Unit *u, UnitWriteFlags flags, const char *name, const char *data);
 int unit_write_settingf(Unit *u, UnitWriteFlags mode, const char *name, const char *format, ...) _printf_(4,5);
 
-int unit_kill_context(Unit *u, KillContext *c, KillOperation k, pid_t main_pid, pid_t control_pid, bool main_pid_alien);
+int unit_kill_context(Unit *u, KillContext *c, KillOperation k, PidRef *main_pid, PidRef *control_pid, bool main_pid_alien);
 
 int unit_make_transient(Unit *u);
 
@@ -1006,8 +1004,8 @@ bool unit_is_unneeded(Unit *u);
 bool unit_is_upheld_by_active(Unit *u, Unit **ret_culprit);
 bool unit_is_bound_by_inactive(Unit *u, Unit **ret_culprit);
 
-pid_t unit_control_pid(Unit *u);
-pid_t unit_main_pid(Unit *u);
+PidRef* unit_control_pid(Unit *u);
+PidRef* unit_main_pid(Unit *u);
 
 void unit_warn_if_dir_nonempty(Unit *u, const char* where);
 int unit_fail_if_noncanonical(Unit *u, const char* where);
@@ -1026,8 +1024,8 @@ bool unit_shall_confirm_spawn(Unit *u);
 
 int unit_set_exec_params(Unit *s, ExecParameters *p);
 
-int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret);
-int unit_fork_and_watch_rm_rf(Unit *u, char **paths, pid_t *ret_pid);
+int unit_fork_helper_process(Unit *u, const char *name, PidRef *ret);
+int unit_fork_and_watch_rm_rf(Unit *u, char **paths, PidRef *ret);
 
 void unit_remove_dependencies(Unit *u, UnitDependencyMask mask);