]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev-spawn: manage spawned processes by PidRef
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 1 Apr 2025 06:54:24 +0000 (15:54 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 1 Apr 2025 09:25:29 +0000 (18:25 +0900)
src/udev/udev-spawn.c

index 22cb0089a44684a7ead2d141959a3e279f322f75..9a0e242a81bbeb6e42be578d03fc2fdb209ea337 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "device-private.h"
 #include "device-util.h"
+#include "event-util.h"
 #include "fd-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -19,7 +20,7 @@
 typedef struct Spawn {
         sd_device *device;
         const char *cmd;
-        pid_t pid;
+        PidRef pidref;
         usec_t timeout_warn_usec;
         usec_t timeout_usec;
         int timeout_signal;
@@ -108,10 +109,10 @@ static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
         DEVICE_TRACE_POINT(spawn_timeout, spawn->device, spawn->cmd);
 
         log_device_error(spawn->device, "Spawned process '%s' ["PID_FMT"] timed out after %s, killing.",
-                         spawn->cmd, spawn->pid,
+                         spawn->cmd, spawn->pidref.pid,
                          FORMAT_TIMESPAN(spawn->timeout_usec, USEC_PER_SEC));
 
-        kill_and_sigcont(spawn->pid, spawn->timeout_signal);
+        pidref_kill_and_sigcont(&spawn->pidref, spawn->timeout_signal);
         return 1;
 }
 
@@ -119,7 +120,7 @@ static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *use
         Spawn *spawn = ASSERT_PTR(userdata);
 
         log_device_warning(spawn->device, "Spawned process '%s' ["PID_FMT"] is taking longer than %s to complete.",
-                           spawn->cmd, spawn->pid,
+                           spawn->cmd, spawn->pidref.pid,
                            FORMAT_TIMESPAN(spawn->timeout_warn_usec, USEC_PER_SEC));
 
         return 1;
@@ -199,7 +200,7 @@ static int spawn_wait(Spawn *spawn) {
                         return log_device_debug_errno(spawn->device, r, "Failed to enable stderr event source: %m");
         }
 
-        r = sd_event_add_child(e, &sigchld_source, spawn->pid, WEXITED, on_spawn_sigchld, spawn);
+        r = event_add_child_pidref(e, &sigchld_source, &spawn->pidref, WEXITED, on_spawn_sigchld, spawn);
         if (r < 0)
                 return log_device_debug_errno(spawn->device, r, "Failed to create sigchild event source: %m");
         /* SIGCHLD should be processed after IO is complete */
@@ -218,11 +219,6 @@ int udev_event_spawn(
                 size_t result_size,
                 bool *ret_truncated) {
 
-        _cleanup_close_pair_ int outpipe[2] = EBADF_PAIR, errpipe[2] = EBADF_PAIR;
-        _cleanup_strv_free_ char **argv = NULL;
-        char **envp = NULL;
-        Spawn spawn;
-        pid_t pid;
         int r;
 
         assert(event);
@@ -251,16 +247,19 @@ int udev_event_spawn(
                                                 FORMAT_TIMESPAN(age_usec, 1), FORMAT_TIMESPAN(timeout_usec, 1), cmd);
 
         /* pipes from child to parent */
+        _cleanup_close_pair_ int outpipe[2] = EBADF_PAIR;
         if (result || log_get_max_level() >= LOG_INFO)
                 if (pipe2(outpipe, O_NONBLOCK|O_CLOEXEC) != 0)
                         return log_device_error_errno(event->dev, errno,
                                                       "Failed to create pipe for command '%s': %m", cmd);
 
+        _cleanup_close_pair_ int errpipe[2] = EBADF_PAIR;
         if (log_get_max_level() >= LOG_INFO)
                 if (pipe2(errpipe, O_NONBLOCK|O_CLOEXEC) != 0)
                         return log_device_error_errno(event->dev, errno,
                                                       "Failed to create pipe for command '%s': %m", cmd);
 
+        _cleanup_strv_free_ char **argv = NULL;
         r = strv_split_full(&argv, cmd, NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_RETAIN_ESCAPE);
         if (r < 0)
                 return log_device_error_errno(event->dev, r, "Failed to split command: %m");
@@ -280,17 +279,20 @@ int udev_event_spawn(
                 free_and_replace(argv[0], program);
         }
 
+        char **envp;
         r = device_get_properties_strv(event->dev, &envp);
         if (r < 0)
                 return log_device_error_errno(event->dev, r, "Failed to get device properties");
 
         log_device_debug(event->dev, "Starting '%s'", cmd);
 
-        r = safe_fork_full("(spawn)",
-                           (int[]) { -EBADF, outpipe[WRITE_END], errpipe[WRITE_END] },
-                           NULL, 0,
-                           FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE,
-                           &pid);
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+        r = pidref_safe_fork_full(
+                        "(spawn)",
+                        (int[]) { -EBADF, outpipe[WRITE_END], errpipe[WRITE_END] },
+                        NULL, 0,
+                        FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE,
+                        &pidref);
         if (r < 0)
                 return log_device_error_errno(event->dev, r,
                                               "Failed to fork() to execute command '%s': %m", cmd);
@@ -304,10 +306,10 @@ int udev_event_spawn(
         outpipe[WRITE_END] = safe_close(outpipe[WRITE_END]);
         errpipe[WRITE_END] = safe_close(errpipe[WRITE_END]);
 
-        spawn = (Spawn) {
+        Spawn spawn = {
                 .device = event->dev,
                 .cmd = cmd,
-                .pid = pid,
+                .pidref = pidref, /* Do not take ownership */
                 .accept_failure = accept_failure,
                 .timeout_warn_usec = udev_warn_timeout(cmd_timeout_usec),
                 .timeout_usec = cmd_timeout_usec,