mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-26 10:03:40 +03:00
udev: Ensure udev_event_spawn reads stdout
When running the program with udev_event_spawn it is possible to miss output in stdout when the program exits causing the result to be empty which can cause rules using the result to not function correctly. This is due to the on_spawn_sigchld callback being processed while IO is still pending and causing the event loop to exit. To correct this the sigchld event source is made a lower priority than the other event sources to ensure it is processed after IO. This requires changing the IO event source to oneshot and re-enabling it when valid data is read but not for EOF, this prevents the empty pipes constantly generating IO events.
This commit is contained in:
parent
eaadc03d61
commit
9f537ae310
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user