Skip to content

Commit 2a1e0f2

Browse files
committed
journalctl: in --follow mode watch stdout for POLLHUP/POLLERR and exit
Fixes: systemd#9374
1 parent f86c1da commit 2a1e0f2

File tree

1 file changed

+48
-17
lines changed

1 file changed

+48
-17
lines changed

src/journal/journalctl.c

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,14 +2038,46 @@ static int sync_journal(void) {
20382038
return send_signal_and_wait(SIGRTMIN+1, "/run/systemd/journal/synced");
20392039
}
20402040

2041-
int main(int argc, char *argv[]) {
2041+
static int wait_for_change(sd_journal *j, int poll_fd) {
2042+
struct pollfd pollfds[] = {
2043+
{ .fd = poll_fd, .events = POLLIN },
2044+
{ .fd = STDOUT_FILENO },
2045+
};
2046+
2047+
struct timespec ts;
2048+
usec_t timeout;
20422049
int r;
2050+
2051+
assert(j);
2052+
assert(poll_fd >= 0);
2053+
2054+
/* Much like sd_journal_wait() but also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that,
2055+
* i.e. when it is closed. */
2056+
2057+
r = sd_journal_get_timeout(j, &timeout);
2058+
if (r < 0)
2059+
return log_error_errno(r, "Failed to determine journal waiting time: %m");
2060+
2061+
if (ppoll(pollfds, ELEMENTSOF(pollfds), timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0)
2062+
return log_error_errno(errno, "Couldn't wait for journal event: %m");
2063+
2064+
if (pollfds[1].revents & (POLLHUP|POLLERR)) { /* STDOUT has been closed? */
2065+
log_debug("Standard output has been closed.");
2066+
return -ECANCELED;
2067+
}
2068+
2069+
r = sd_journal_process(j);
2070+
if (r < 0)
2071+
return log_error_errno(r, "Failed to process journal events: %m");
2072+
2073+
return 0;
2074+
}
2075+
2076+
int main(int argc, char *argv[]) {
2077+
bool previous_boot_id_valid = false, first_line = true, ellipsized = false, need_seek = false;
20432078
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
2044-
bool need_seek = false;
20452079
sd_id128_t previous_boot_id;
2046-
bool previous_boot_id_valid = false, first_line = true;
2047-
int n_shown = 0;
2048-
bool ellipsized = false;
2080+
int n_shown = 0, r, poll_fd = -1;
20492081

20502082
setlocale(LC_ALL, "");
20512083
log_parse_environment();
@@ -2373,15 +2405,15 @@ int main(int argc, char *argv[]) {
23732405

23742406
/* Opening the fd now means the first sd_journal_wait() will actually wait */
23752407
if (arg_follow) {
2376-
r = sd_journal_get_fd(j);
2377-
if (r == -EMFILE) {
2378-
log_warning("Insufficent watch descriptors available. Reverting to -n.");
2408+
poll_fd = sd_journal_get_fd(j);
2409+
if (poll_fd == -EMFILE) {
2410+
log_warning_errno(poll_fd, "Insufficent watch descriptors available. Reverting to -n.");
23792411
arg_follow = false;
2380-
} else if (r == -EMEDIUMTYPE) {
2381-
log_error_errno(r, "The --follow switch is not supported in conjunction with reading from STDIN.");
2412+
} else if (poll_fd == -EMEDIUMTYPE) {
2413+
log_error_errno(poll_fd, "The --follow switch is not supported in conjunction with reading from STDIN.");
23822414
goto finish;
2383-
} else if (r < 0) {
2384-
log_error_errno(r, "Failed to get journal fd: %m");
2415+
} else if (poll_fd < 0) {
2416+
log_error_errno(poll_fd, "Failed to get journal fd: %m");
23852417
goto finish;
23862418
}
23872419
}
@@ -2603,7 +2635,7 @@ int main(int argc, char *argv[]) {
26032635
need_seek = true;
26042636
if (r == -EADDRNOTAVAIL)
26052637
break;
2606-
else if (r < 0 || ferror(stdout))
2638+
else if (r < 0)
26072639
goto finish;
26082640

26092641
n_shown++;
@@ -2641,11 +2673,10 @@ int main(int argc, char *argv[]) {
26412673
}
26422674

26432675
fflush(stdout);
2644-
r = sd_journal_wait(j, (uint64_t) -1);
2645-
if (r < 0) {
2646-
log_error_errno(r, "Couldn't wait for journal event: %m");
2676+
2677+
r = wait_for_change(j, poll_fd);
2678+
if (r < 0)
26472679
goto finish;
2648-
}
26492680

26502681
first_line = false;
26512682
}

0 commit comments

Comments
 (0)