diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 58d484280a..eb51139e51 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -534,6 +534,7 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd char buf[4096], *p; size_t size; ssize_t l; + int r; assert(spawn); assert(fd == spawn->fd_stdout || fd == spawn->fd_stderr); @@ -549,9 +550,11 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd l = read(fd, p, size - 1); if (l < 0) { - if (errno != EAGAIN) - log_device_error_errno(spawn->device, errno, - "Failed to read stdout of '%s': %m", spawn->cmd); + if (errno == EAGAIN) + goto reenable; + + log_device_error_errno(spawn->device, errno, + "Failed to read stdout of '%s': %m", spawn->cmd); return 0; } @@ -574,6 +577,16 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd fd == spawn->fd_stdout ? "out" : "err", *q); } + + if (l == 0) + return 0; + + /* Re-enable the event source if we did not encounter EOF */ +reenable: + r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT); + if (r < 0) + log_device_error_errno(spawn->device, r, + "Failed to reactivate IO source of '%s'", spawn->cmd); return 0; } @@ -634,6 +647,9 @@ static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userd static int spawn_wait(Spawn *spawn) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; + _cleanup_(sd_event_source_unrefp) sd_event_source *sigchld_source = NULL; + _cleanup_(sd_event_source_unrefp) sd_event_source *stdout_source = NULL; + _cleanup_(sd_event_source_unrefp) sd_event_source *stderr_source = NULL; int r; assert(spawn); @@ -670,20 +686,31 @@ static int spawn_wait(Spawn *spawn) { } if (spawn->fd_stdout >= 0) { - r = sd_event_add_io(e, NULL, spawn->fd_stdout, EPOLLIN, on_spawn_io, spawn); + r = sd_event_add_io(e, &stdout_source, spawn->fd_stdout, EPOLLIN, on_spawn_io, spawn); + if (r < 0) + return r; + r = sd_event_source_set_enabled(stdout_source, SD_EVENT_ONESHOT); if (r < 0) return r; } if (spawn->fd_stderr >= 0) { - r = sd_event_add_io(e, NULL, spawn->fd_stderr, EPOLLIN, on_spawn_io, spawn); + r = sd_event_add_io(e, &stderr_source, spawn->fd_stderr, EPOLLIN, on_spawn_io, spawn); + if (r < 0) + return r; + r = sd_event_source_set_enabled(stderr_source, SD_EVENT_ONESHOT); if (r < 0) return r; } - r = sd_event_add_child(e, NULL, spawn->pid, WEXITED, on_spawn_sigchld, spawn); + r = sd_event_add_child(e, &sigchld_source, spawn->pid, WEXITED, on_spawn_sigchld, spawn); if (r < 0) return r; + /* SIGCHLD should be processed after IO is complete */ + r = sd_event_source_set_priority(sigchld_source, SD_EVENT_PRIORITY_NORMAL + 1); + if (r < 0) + return r; + return sd_event_loop(e); }