]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: reference main/control pid of .service units via PidRef
authorLennart Poettering <lennart@poettering.net>
Sat, 9 Sep 2023 07:49:22 +0000 (09:49 +0200)
committerLennart Poettering <lennart@poettering.net>
Sat, 9 Sep 2023 12:03:31 +0000 (14:03 +0200)
The first conversion to PidRef. It's mostly an excercise of
search/replace, but with some special care taken for life-cycle (i.e. we
need to destroy the structure properly once done, to release the pidfd).

It also uses pidfd based killing for some of the killing but leaves most
as it is to make the conversion minimal.

src/core/dbus-service.c
src/core/service.c
src/core/service.h

index 6068c742cad5fe44d58fb4b6ff605347ef200272..cc65a5599035d96689b559da1036025c3023ef1d 100644 (file)
@@ -346,8 +346,8 @@ const sd_bus_vtable bus_service_vtable[] = {
         SD_BUS_PROPERTY("RestartPreventExitStatus", "(aiai)", property_get_exit_status_set, offsetof(Service, restart_prevent_status), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RestartForceExitStatus", "(aiai)", property_get_exit_status_set, offsetof(Service, restart_force_status), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SuccessExitStatus", "(aiai)", property_get_exit_status_set, offsetof(Service, success_status), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid.pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid.pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("NFileDescriptorStore", "u", property_get_size_as_uint32, offsetof(Service, n_fd_store), 0),
index 2a02279f5653986bda758094d34d9e36da3676e6..9aee6bca079c05335817a6432385297045876ea9 100644 (file)
@@ -131,7 +131,8 @@ static void service_init(Unit *u) {
         s->socket_fd = -EBADF;
         s->stdin_fd = s->stdout_fd = s->stderr_fd = -EBADF;
         s->guess_main_pid = true;
-
+        s->main_pid = PIDREF_NULL;
+        s->control_pid = PIDREF_NULL;
         s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
 
         s->exec_context.keyring_mode = MANAGER_IS_SYSTEM(u->manager) ?
@@ -151,19 +152,21 @@ static void service_init(Unit *u) {
 static void service_unwatch_control_pid(Service *s) {
         assert(s);
 
-        if (s->control_pid <= 0)
+        if (!pidref_is_set(&s->control_pid))
                 return;
 
-        unit_unwatch_pid(UNIT(s), TAKE_PID(s->control_pid));
+        unit_unwatch_pid(UNIT(s), s->control_pid.pid);
+        pidref_done(&s->control_pid);
 }
 
 static void service_unwatch_main_pid(Service *s) {
         assert(s);
 
-        if (s->main_pid <= 0)
+        if (!pidref_is_set(&s->main_pid))
                 return;
 
-        unit_unwatch_pid(UNIT(s), TAKE_PID(s->main_pid));
+        unit_unwatch_pid(UNIT(s), s->main_pid.pid);
+        pidref_done(&s->main_pid);
 }
 
 static void service_unwatch_pid_file(Service *s) {
@@ -177,6 +180,9 @@ static void service_unwatch_pid_file(Service *s) {
 }
 
 static int service_set_main_pid(Service *s, pid_t pid) {
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+        int r;
+
         assert(s);
 
         if (pid <= 1)
@@ -185,15 +191,19 @@ static int service_set_main_pid(Service *s, pid_t pid) {
         if (pid == getpid_cached())
                 return -EINVAL;
 
-        if (s->main_pid == pid && s->main_pid_known)
+        if (s->main_pid.pid == pid && s->main_pid_known)
                 return 0;
 
-        if (s->main_pid != pid) {
+        r = pidref_set_pid(&pidref, pid);
+        if (r < 0)
+                return r;
+
+        if (s->main_pid.pid != pid) {
                 service_unwatch_main_pid(s);
                 exec_status_start(&s->main_exec_status, pid);
         }
 
-        s->main_pid = pid;
+        s->main_pid = TAKE_PIDREF(pidref);
         s->main_pid_known = true;
         s->main_pid_alien = pid_is_my_child(pid) == 0;
 
@@ -446,8 +456,7 @@ static void service_done(Unit *u) {
         exit_status_set_free(&s->restart_force_status);
         exit_status_set_free(&s->success_status);
 
-        /* This will leak a process, but at least no memory or any of
-         * our resources */
+        /* This will leak a process, but at least no memory or any of our resources */
         service_unwatch_main_pid(s);
         service_unwatch_control_pid(s);
         service_unwatch_pid_file(s);
@@ -964,17 +973,17 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
                 prefix, oom_policy_to_string(s->oom_policy),
                 prefix, signal_to_string(s->reload_signal));
 
-        if (s->control_pid > 0)
+        if (pidref_is_set(&s->control_pid))
                 fprintf(f,
                         "%sControl PID: "PID_FMT"\n",
-                        prefix, s->control_pid);
+                        prefix, s->control_pid.pid);
 
-        if (s->main_pid > 0)
+        if (pidref_is_set(&s->main_pid))
                 fprintf(f,
                         "%sMain PID: "PID_FMT"\n"
                         "%sMain PID Known: %s\n"
                         "%sMain PID Alien: %s\n",
-                        prefix, s->main_pid,
+                        prefix, s->main_pid.pid,
                         prefix, yes_no(s->main_pid_known),
                         prefix, yes_no(s->main_pid_alien));
 
@@ -1083,7 +1092,7 @@ static int service_is_suitable_main_pid(Service *s, pid_t pid, int prio) {
         if (pid == getpid_cached() || pid == 1)
                 return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the manager, refusing.", pid);
 
-        if (pid == s->control_pid)
+        if (pid == s->control_pid.pid)
                 return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the control process, refusing.", pid);
 
         if (!pid_is_alive(pid))
@@ -1137,7 +1146,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
         if (r < 0)
                 return log_unit_full_errno(UNIT(s), prio, r, "Failed to parse PID from file %s: %m", s->pid_file);
 
-        if (s->main_pid_known && pid == s->main_pid)
+        if (s->main_pid_known && pid == s->main_pid.pid)
                 return 0;
 
         r = service_is_suitable_main_pid(s, pid, prio);
@@ -1163,7 +1172,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
         }
 
         if (s->main_pid_known) {
-                log_unit_debug(UNIT(s), "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid, pid);
+                log_unit_debug(UNIT(s), "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid.pid, pid);
 
                 service_unwatch_main_pid(s);
                 s->main_pid_known = false;
@@ -1174,7 +1183,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
         if (r < 0)
                 return r;
 
-        r = unit_watch_pid(UNIT(s), pid, false);
+        r = unit_watch_pid(UNIT(s), 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);
 
@@ -1187,15 +1196,14 @@ static void service_search_main_pid(Service *s) {
 
         assert(s);
 
-        /* If we know it anyway, don't ever fall back to unreliable
-         * heuristics */
+        /* If we know it anyway, don't ever fall back to unreliable heuristics */
         if (s->main_pid_known)
                 return;
 
         if (!s->guess_main_pid)
                 return;
 
-        assert(s->main_pid <= 0);
+        assert(!pidref_is_set(&s->main_pid));
 
         if (unit_search_main_pid(UNIT(s), &pid) < 0)
                 return;
@@ -1204,7 +1212,7 @@ static void service_search_main_pid(Service *s) {
         if (service_set_main_pid(s, pid) < 0)
                 return;
 
-        r = unit_watch_pid(UNIT(s), pid, false);
+        r = unit_watch_pid(UNIT(s), 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);
@@ -1336,28 +1344,28 @@ static int service_coldplug(Unit *u) {
         if (r < 0)
                 return r;
 
-        if (s->main_pid > 0 &&
-            pid_is_unwaited(s->main_pid) &&
+        if (pidref_is_set(&s->main_pid) &&
+            pid_is_unwaited(s->main_pid.pid) &&
             (IN_SET(s->deserialized_state,
                     SERVICE_START, SERVICE_START_POST,
                     SERVICE_RUNNING,
                     SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
                     SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
-                r = unit_watch_pid(UNIT(s), s->main_pid, false);
+                r = unit_watch_pid(UNIT(s), s->main_pid.pid, /* exclusive= */ false);
                 if (r < 0)
                         return r;
         }
 
-        if (s->control_pid > 0 &&
-            pid_is_unwaited(s->control_pid) &&
+        if (pidref_is_set(&s->control_pid) &&
+            pid_is_unwaited(s->control_pid.pid) &&
             IN_SET(s->deserialized_state,
                    SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
                    SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
                    SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
                    SERVICE_CLEANING)) {
-                r = unit_watch_pid(UNIT(s), s->control_pid, false);
+                r = unit_watch_pid(UNIT(s), s->control_pid.pid, /* exclusive= */ false);
                 if (r < 0)
                         return r;
         }
@@ -1620,7 +1628,7 @@ static int service_spawn_internal(
                 ExecCommand *c,
                 usec_t timeout,
                 ExecFlags flags,
-                pid_t *ret_pid) {
+                PidRef *ret_pid) {
 
         _cleanup_(exec_params_clear) ExecParameters exec_params = {
                 .flags     = flags,
@@ -1631,6 +1639,7 @@ static int service_spawn_internal(
         };
         _cleanup_(sd_event_source_unrefp) sd_event_source *exec_fd_source = NULL;
         _cleanup_strv_free_ char **final_env = NULL, **our_env = NULL;
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
         size_t n_env = 0;
         pid_t pid;
         int r;
@@ -1699,8 +1708,8 @@ static int service_spawn_internal(
                                 return -ENOMEM;
         }
 
-        if (s->main_pid > 0)
-                if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
+        if (pidref_is_set(&s->main_pid))
+                if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid.pid) < 0)
                         return -ENOMEM;
 
         if (MANAGER_IS_USER(UNIT(s)->manager))
@@ -1830,12 +1839,15 @@ static int service_spawn_internal(
         s->exec_fd_event_source = TAKE_PTR(exec_fd_source);
         s->exec_fd_hot = false;
 
-        r = unit_watch_pid(UNIT(s), pid, true);
+        r = pidref_set_pid(&pidref, pid);
         if (r < 0)
                 return r;
 
-        *ret_pid = pid;
+        r = unit_watch_pid(UNIT(s), pidref.pid, /* exclusive= */ true);
+        if (r < 0)
+                return r;
 
+        *ret_pid = TAKE_PIDREF(pidref);
         return 0;
 }
 
@@ -1844,19 +1856,16 @@ static int main_pid_good(Service *s) {
 
         /* Returns 0 if the pid is dead, > 0 if it is good, < 0 if we don't know */
 
-        /* If we know the pid file, then let's just check if it is
-         * still valid */
+        /* If we know the pid file, then let's just check if it is still valid */
         if (s->main_pid_known) {
 
-                /* If it's an alien child let's check if it is still
-                 * alive ... */
-                if (s->main_pid_alien && s->main_pid > 0)
-                        return pid_is_alive(s->main_pid);
+                /* If it's an alien child let's check if it is still alive ... */
+                if (s->main_pid_alien && pidref_is_set(&s->main_pid))
+                        return pid_is_alive(s->main_pid.pid);
 
-                /* .. otherwise assume we'll get a SIGCHLD for it,
-                 * which we really should wait for to collect exit
-                 * status and code */
-                return s->main_pid > 0;
+                /* .. otherwise assume we'll get a SIGCHLD for it, which we really should wait for to collect
+                 * exit status and code */
+                return pidref_is_set(&s->main_pid);
         }
 
         /* We don't know the pid */
@@ -1870,7 +1879,7 @@ static int control_pid_good(Service *s) {
          * make this function as similar as possible to main_pid_good() and cgroup_good(), we pretend that < 0 also
          * means: we can't figure it out. */
 
-        return s->control_pid > 0;
+        return pidref_is_set(&s->control_pid);
 }
 
 static int cgroup_good(Service *s) {
@@ -2074,6 +2083,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
         s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST];
         if (s->control_command) {
                 s->control_command_id = SERVICE_EXEC_STOP_POST;
+                pidref_done(&s->control_pid);
 
                 r = service_spawn(s,
                                   s->control_command,
@@ -2138,8 +2148,8 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
                         UNIT(s),
                         &s->kill_context,
                         kill_operation,
-                        s->main_pid,
-                        s->control_pid,
+                        s->main_pid.pid,
+                        s->control_pid.pid,
                         s->main_pid_alien);
         if (r < 0)
                 goto fail;
@@ -2196,6 +2206,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
         s->control_command = s->exec_command[SERVICE_EXEC_STOP];
         if (s->control_command) {
                 s->control_command_id = SERVICE_EXEC_STOP;
+                pidref_done(&s->control_pid);
 
                 r = service_spawn(s,
                                   s->control_command,
@@ -2274,6 +2285,7 @@ static void service_enter_start_post(Service *s) {
         s->control_command = s->exec_command[SERVICE_EXEC_START_POST];
         if (s->control_command) {
                 s->control_command_id = SERVICE_EXEC_START_POST;
+                pidref_done(&s->control_pid);
 
                 r = service_spawn(s,
                                   s->control_command,
@@ -2299,17 +2311,17 @@ static void service_kill_control_process(Service *s) {
 
         assert(s);
 
-        if (s->control_pid <= 0)
+        if (!pidref_is_set(&s->control_pid))
                 return;
 
-        r = kill_and_sigcont(s->control_pid, SIGKILL);
+        r = pidref_kill_and_sigcont(&s->control_pid, SIGKILL);
         if (r < 0) {
                 _cleanup_free_ char *comm = NULL;
 
-                (void) get_process_comm(s->control_pid, &comm);
+                (void) get_process_comm(s->control_pid.pid, &comm);
 
                 log_unit_debug_errno(UNIT(s), r, "Failed to kill control process " PID_FMT " (%s), ignoring: %m",
-                                     s->control_pid, strna(comm));
+                                     s->control_pid.pid, strna(comm));
         }
 }
 
@@ -2336,9 +2348,9 @@ static int service_adverse_to_leftover_processes(Service *s) {
 }
 
 static void service_enter_start(Service *s) {
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
         ExecCommand *c;
         usec_t timeout;
-        pid_t pid;
         int r;
 
         assert(s);
@@ -2392,7 +2404,7 @@ static void service_enter_start(Service *s) {
                           c,
                           timeout,
                           EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_WRITE_CREDENTIALS|EXEC_SETENV_MONITOR_RESULT,
-                          &pid);
+                          &pidref);
         if (r < 0)
                 goto fail;
 
@@ -2400,7 +2412,7 @@ static void service_enter_start(Service *s) {
                 /* For simple services we immediately start
                  * the START_POST binaries. */
 
-                (void) service_set_main_pid(s, pid);
+                (void) service_set_main_pid(s, pidref.pid);
                 service_enter_start_post(s);
 
         } else  if (s->type == SERVICE_FORKING) {
@@ -2408,7 +2420,8 @@ static void service_enter_start(Service *s) {
                 /* For forking services we wait until the start
                  * process exited. */
 
-                s->control_pid = pid;
+                pidref_done(&s->control_pid);
+                s->control_pid = TAKE_PIDREF(pidref);
                 service_set_state(s, SERVICE_START);
 
         } else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD, SERVICE_EXEC)) {
@@ -2418,7 +2431,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, pid);
+                (void) service_set_main_pid(s, pidref.pid);
                 service_set_state(s, SERVICE_START);
         } else
                 assert_not_reached();
@@ -2480,6 +2493,7 @@ static void service_enter_condition(Service *s) {
                         goto fail;
 
                 s->control_command_id = SERVICE_EXEC_CONDITION;
+                pidref_done(&s->control_pid);
 
                 r = service_spawn(s,
                                   s->control_command,
@@ -2571,8 +2585,8 @@ static void service_enter_reload(Service *s) {
 
         usec_t ts = now(CLOCK_MONOTONIC);
 
-        if (s->type == SERVICE_NOTIFY_RELOAD && s->main_pid > 0) {
-                r = kill_and_sigcont(s->main_pid, s->reload_signal);
+        if (s->type == SERVICE_NOTIFY_RELOAD && pidref_is_set(&s->main_pid)) {
+                r = pidref_kill_and_sigcont(&s->main_pid, s->reload_signal);
                 if (r < 0) {
                         log_unit_warning_errno(UNIT(s), r, "Failed to send reload signal: %m");
                         goto fail;
@@ -2584,6 +2598,7 @@ static void service_enter_reload(Service *s) {
         s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
         if (s->control_command) {
                 s->control_command_id = SERVICE_EXEC_RELOAD;
+                pidref_done(&s->control_pid);
 
                 r = service_spawn(s,
                                   s->control_command,
@@ -2634,6 +2649,8 @@ static void service_run_next_control(Service *s) {
         else
                 timeout = s->timeout_stop_usec;
 
+        pidref_done(&s->control_pid);
+
         r = service_spawn(s,
                           s->control_command,
                           timeout,
@@ -2664,7 +2681,7 @@ fail:
 }
 
 static void service_run_next_main(Service *s) {
-        pid_t pid;
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
         int r;
 
         assert(s);
@@ -2679,11 +2696,11 @@ static void service_run_next_main(Service *s) {
                           s->main_command,
                           s->timeout_start_usec,
                           EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_SETENV_MONITOR_RESULT|EXEC_WRITE_CREDENTIALS,
-                          &pid);
+                          &pidref);
         if (r < 0)
                 goto fail;
 
-        (void) service_set_main_pid(s, pid);
+        (void) service_set_main_pid(s, pidref.pid);
 
         return;
 
@@ -2930,11 +2947,11 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
         (void) serialize_item(f, "result", service_result_to_string(s->result));
         (void) serialize_item(f, "reload-result", service_result_to_string(s->reload_result));
 
-        if (s->control_pid > 0)
-                (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid);
+        if (pidref_is_set(&s->control_pid))
+                (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid.pid);
 
-        if (s->main_pid_known && s->main_pid > 0)
-                (void) serialize_item_format(f, "main-pid", PID_FMT, s->main_pid);
+        if (s->main_pid_known && pidref_is_set(&s->main_pid))
+                (void) serialize_item_format(f, "main-pid", PID_FMT, s->main_pid.pid);
 
         (void) serialize_bool(f, "main-pid-known", s->main_pid_known);
         (void) serialize_bool(f, "bus-name-good", s->bus_name_good);
@@ -3168,12 +3185,10 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
                         s->reload_result = f;
 
         } else if (streq(key, "control-pid")) {
-                pid_t pid;
-
-                if (parse_pid(value, &pid) < 0)
-                        log_unit_debug(u, "Failed to parse control-pid value: %s", value);
-                else
-                        s->control_pid = pid;
+                pidref_done(&s->control_pid);
+                r = pidref_set_pidstr(&s->control_pid, value);
+                if (r < 0)
+                        log_unit_debug_errno(u, r, "Failed to initialize control PID '%s' from serialization, ignoring.", value);
         } else if (streq(key, "main-pid")) {
                 pid_t pid;
 
@@ -3723,7 +3738,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
 
         /* Oneshot services and non-SERVICE_EXEC_START commands should not be
          * considered daemons as they are typically not long running. */
-        if (s->type == SERVICE_ONESHOT || (s->control_pid == pid && s->control_command_id != SERVICE_EXEC_START))
+        if (s->type == SERVICE_ONESHOT || (s->control_pid.pid == pid && s->control_command_id != SERVICE_EXEC_START))
                 clean_mode = EXIT_CLEAN_COMMAND;
         else
                 clean_mode = EXIT_CLEAN_DAEMON;
@@ -3739,7 +3754,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         else
                 assert_not_reached();
 
-        if (s->main_pid == pid) {
+        if (s->main_pid.pid == pid) {
                 /* Clean up the exec_fd event source. We want to do this here, not later in
                  * service_set_state(), because service_enter_stop_post() calls service_spawn().
                  * The source owns its end of the pipe, so this will close that too. */
@@ -3751,7 +3766,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                 if (service_load_pid_file(s, false) > 0)
                         return;
 
-                s->main_pid = 0;
+                pidref_done(&s->main_pid);
                 exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status);
 
                 if (s->main_command) {
@@ -3882,11 +3897,11 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                 service_enter_start_post(s);
                 }
 
-        } else if (s->control_pid == pid) {
+        } else if (s->control_pid.pid == pid) {
                 const char *kind;
                 bool success;
 
-                s->control_pid = 0;
+                pidref_done(&s->control_pid);
 
                 if (s->control_command) {
                         exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
@@ -4314,23 +4329,23 @@ static bool service_notify_message_authorized(Service *s, pid_t pid, FDSet *fds)
                 return false;
         }
 
-        if (notify_access == NOTIFY_MAIN && pid != s->main_pid) {
-                if (s->main_pid != 0)
-                        log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid);
+        if (notify_access == NOTIFY_MAIN && pid != s->main_pid.pid) {
+                if (pidref_is_set(&s->main_pid))
+                        log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid.pid);
                 else
                         log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", pid);
 
                 return false;
         }
 
-        if (notify_access == NOTIFY_EXEC && pid != s->main_pid && pid != s->control_pid) {
-                if (s->main_pid != 0 && s->control_pid != 0)
+        if (notify_access == NOTIFY_EXEC && pid != s->main_pid.pid && pid != s->control_pid.pid) {
+                if (pidref_is_set(&s->main_pid) && pidref_is_set(&s->control_pid))
                         log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT" and control PID "PID_FMT,
-                                         pid, s->main_pid, s->control_pid);
-                else if (s->main_pid != 0)
-                        log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid);
-                else if (s->control_pid != 0)
-                        log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for control PID "PID_FMT, pid, s->control_pid);
+                                         pid, s->main_pid.pid, s->control_pid.pid);
+                else if (pidref_is_set(&s->main_pid))
+                        log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid.pid);
+                else if (pidref_is_set(&s->control_pid))
+                        log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for control PID "PID_FMT, pid, s->control_pid.pid);
                 else
                         log_unit_warning(UNIT(s), "Got notification message from PID "PID_FMT", but reception only permitted for main PID and control PID which are currently not known", pid);
 
@@ -4382,7 +4397,7 @@ static void service_notify_message(
 
                 if (parse_pid(e, &new_main_pid) < 0)
                         log_unit_warning(u, "Failed to parse MAINPID= field in notification message, ignoring: %s", e);
-                else if (!s->main_pid_known || new_main_pid != s->main_pid) {
+                else if (!s->main_pid_known || new_main_pid != s->main_pid.pid) {
 
                         r = service_is_suitable_main_pid(s, new_main_pid, LOG_WARNING);
                         if (r == 0) {
@@ -4397,7 +4412,7 @@ static void service_notify_message(
                         if (r > 0) {
                                 (void) service_set_main_pid(s, new_main_pid);
 
-                                r = unit_watch_pid(UNIT(s), new_main_pid, false);
+                                r = unit_watch_pid(UNIT(s), new_main_pid, /* exclusive= */ false);
                                 if (r < 0)
                                         log_unit_warning_errno(UNIT(s), r, "Failed to watch new main PID "PID_FMT" for service: %m", new_main_pid);
 
@@ -4621,7 +4636,7 @@ static bool pick_up_pid_from_bus_name(Service *s) {
 
         /* If the service is running but we have no main PID yet, get it from the owner of the D-Bus name */
 
-        return !pid_is_valid(s->main_pid) &&
+        return !pidref_is_set(&s->main_pid) &&
                 IN_SET(s->state,
                        SERVICE_START,
                        SERVICE_START_POST,
@@ -4667,7 +4682,7 @@ static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, s
         log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, (pid_t) pid);
 
         (void) service_set_main_pid(s, pid);
-        (void) unit_watch_pid(UNIT(s), pid, false);
+        (void) unit_watch_pid(UNIT(s), pid, /* exclusive= */ false);
         return 1;
 }
 
@@ -4798,7 +4813,7 @@ static int service_kill(Unit *u, KillWho who, int signo, int code, int value, sd
 
         assert(s);
 
-        return unit_kill_common(u, who, signo, code, value, s->main_pid, s->control_pid, error);
+        return unit_kill_common(u, who, signo, code, value, s->main_pid.pid, s->control_pid.pid, error);
 }
 
 static int service_main_pid(Unit *u) {
@@ -4806,7 +4821,7 @@ static int service_main_pid(Unit *u) {
 
         assert(s);
 
-        return s->main_pid;
+        return s->main_pid.pid;
 }
 
 static int service_control_pid(Unit *u) {
@@ -4814,7 +4829,7 @@ static int service_control_pid(Unit *u) {
 
         assert(s);
 
-        return s->control_pid;
+        return s->control_pid.pid;
 }
 
 static bool service_needs_console(Unit *u) {
@@ -4874,6 +4889,7 @@ 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);
@@ -4914,12 +4930,15 @@ static int service_clean(Unit *u, ExecCleanMask mask) {
         if (r < 0)
                 goto fail;
 
-        r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid);
+        r = unit_fork_and_watch_rm_rf(u, l, &pid);
         if (r < 0)
                 goto fail;
 
-        service_set_state(s, SERVICE_CLEANING);
+        r = pidref_set_pid(&s->control_pid, pid);
+        if (r < 0)
+                goto fail;
 
+        service_set_state(s, SERVICE_CLEANING);
         return 0;
 
 fail:
index 3bf5fb1e141c7f19dccc7caeef053f89cb5f6287..e85302e616663cad2ef5c7a0ab12e5b41f2f0cba 100644 (file)
@@ -8,6 +8,7 @@ typedef struct ServiceFDStore ServiceFDStore;
 #include "kill.h"
 #include "open-file.h"
 #include "path.h"
+#include "pidref.h"
 #include "ratelimit.h"
 #include "socket.h"
 #include "unit.h"
@@ -167,7 +168,7 @@ struct Service {
         /* Runtime data of the execution context */
         ExecRuntime *exec_runtime;
 
-        pid_t main_pid, control_pid;
+        PidRef main_pid, control_pid;
 
         /* if we are a socket activated service instance, store information of the connection/peer/socket */
         int socket_fd;