diff options
Diffstat (limited to 'src/journal')
-rw-r--r-- | src/journal/journalctl.c | 122 |
1 files changed, 71 insertions, 51 deletions
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 0f1a738fa5..9bfeb121ee 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -2121,41 +2121,6 @@ static int update_cursor(sd_journal *j) { return 0; } -static int wait_for_change(sd_journal *j, int poll_fd) { - struct pollfd pollfds[] = { - { .fd = poll_fd, .events = POLLIN }, - { .fd = STDOUT_FILENO }, - }; - usec_t timeout; - int r; - - assert(j); - assert(poll_fd >= 0); - - /* Much like sd_journal_wait() but also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that, - * i.e. when it is closed. */ - - r = sd_journal_get_timeout(j, &timeout); - if (r < 0) - return log_error_errno(r, "Failed to determine journal waiting time: %m"); - - r = ppoll_usec(pollfds, ELEMENTSOF(pollfds), timeout); - if (r == -EINTR) - return 0; - if (r < 0) - return log_error_errno(r, "Couldn't wait for journal event: %m"); - - if (pollfds[1].revents & (POLLHUP|POLLERR)) /* STDOUT has been closed? */ - return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED), - "Standard output has been closed."); - - r = sd_journal_process(j); - if (r < 0) - return log_error_errno(r, "Failed to process journal events: %m"); - - return 0; -} - typedef struct Context { sd_journal *journal; bool need_seek; @@ -2305,6 +2270,71 @@ static int show(Context *c) { return n_shown; } +static int show_and_fflush(Context *c, sd_event_source *s) { + int r; + + assert(c); + assert(s); + + r = show(c); + if (r < 0) + return sd_event_exit(sd_event_source_get_event(s), r); + + fflush(stdout); + return 0; +} + +static int on_journal_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + Context *c = ASSERT_PTR(userdata); + int r; + + assert(s); + + r = sd_journal_process(c->journal); + if (r < 0) { + log_error_errno(r, "Failed to process journal events: %m"); + return sd_event_exit(sd_event_source_get_event(s), r); + } + + return show_and_fflush(c, s); +} + +static int on_first_event(sd_event_source *s, void *userdata) { + return show_and_fflush(userdata, s); +} + +static int setup_event(Context *c, int fd, sd_event **ret) { + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + int r; + + assert(arg_follow); + assert(c); + assert(fd >= 0); + assert(ret); + + r = sd_event_default(&e); + if (r < 0) + return log_error_errno(r, "Failed to allocate sd_event object: %m"); + + r = sd_event_add_io(e, NULL, fd, EPOLLIN, &on_journal_event, c); + if (r < 0) + return log_error_errno(r, "Failed to add io event source for journal: %m"); + + /* Also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that, i.e. when it is closed. */ + r = sd_event_add_io(e, NULL, STDOUT_FILENO, EPOLLHUP|EPOLLERR, NULL, INT_TO_PTR(-ECANCELED)); + if (r < 0) + return log_error_errno(r, "Failed to add io event source for stdout: %m"); + + if (arg_lines != 0 || arg_since_set) { + r = sd_event_add_defer(e, NULL, on_first_event, c); + if (r < 0) + return log_error_errno(r, "Failed to add defer event source: %m"); + } + + *ret = TAKE_PTR(e); + return 0; +} + static int run(int argc, char *argv[]) { bool need_seek = false, since_seeked = false, use_cursor = false, after_cursor = false; _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL; @@ -2727,25 +2757,15 @@ static int run(int argc, char *argv[]) { }; if (arg_follow) { - if (arg_lines != 0 || arg_since_set) { - r = show(&c); - if (r < 0) - return r; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; - fflush(stdout); - } + assert(poll_fd >= 0); - for (;;) { - r = wait_for_change(j, poll_fd); - if (r < 0) - return r; - - r = show(&c); - if (r < 0) - return r; + r = setup_event(&c, poll_fd, &e); + if (r < 0) + return r; - fflush(stdout); - } + return sd_event_loop(e); } r = show(&c); |