***/
#include <time.h>
-#include <assert.h>
#include <errno.h>
-#include <sys/poll.h>
#include <sys/socket.h>
#include <string.h>
#include <fcntl.h>
#include "util.h"
#include "utf8.h"
#include "hashmap.h"
-#include "fileio.h"
#include "journal-internal.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
/* up to three lines (each up to 100 characters),
or 300 characters, whichever is less */
}
}
+ /* A special case: make sure that we print a newline when
+ the message is empty. */
+ if (message_len == 0)
+ fputs("\n", f);
+
for (pos = message;
pos < message + message_len;
pos = end + 1, line++) {
}
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to get journal fields: %m");
if (!message)
return 0;
if (r < 0)
r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
- if (r < 0) {
- log_error("Failed to get monotonic timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get monotonic timestamp: %m");
fprintf(f, "[%5llu.%06llu]",
(unsigned long long) (t / USEC_PER_SEC),
uint64_t x;
time_t t;
struct tm tm;
+ struct tm *(*gettime_r)(const time_t *, struct tm *);
r = -ENOENT;
+ gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
if (realtime)
r = safe_atou64(realtime, &x);
if (r < 0)
r = sd_journal_get_realtime_usec(j, &x);
- if (r < 0) {
- log_error("Failed to get realtime timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get realtime timestamp: %m");
t = (time_t) (x / USEC_PER_SEC);
switch(mode) {
case OUTPUT_SHORT_ISO:
- r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&t, &tm));
+ r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
break;
case OUTPUT_SHORT_PRECISE:
- r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm));
+ r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
if (r > 0) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
- ".%06llu", x % USEC_PER_SEC);
+ ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
}
break;
default:
- r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm));
+ r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
}
if (r <= 0) {
fprintf(f, " %.*s", (int) comm_len, comm);
n += comm_len + 1;
} else
- fputc(' ', f);
+ fputs(" unknown", f);
if (pid && shall_print(pid, pid_len, flags)) {
fprintf(f, "[%.*s]", (int) pid_len, pid);
r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
if (r == -ENOENT)
log_debug("Source realtime timestamp not found");
- else if (r < 0) {
- log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
- "Failed to get source realtime timestamp: %s", strerror(-r));
- return r;
- } else {
+ else if (r < 0)
+ return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get source realtime timestamp: %m");
+ else {
_cleanup_free_ char *value = NULL;
size_t size;
r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
if (r < 0)
- log_debug("_SOURCE_REALTIME_TIMESTAMP invalid: %s", strerror(-r));
+ log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
else {
r = safe_atou64(value, &realtime);
if (r < 0)
- log_debug("Failed to parse realtime timestamp: %s",
- strerror(-r));
+ log_debug_errno(r, "Failed to parse realtime timestamp: %m");
}
}
if (r < 0) {
r = sd_journal_get_realtime_usec(j, &realtime);
- if (r < 0) {
- log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
- "Failed to get realtime timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get realtime timestamp: %m");
}
r = sd_journal_get_cursor(j, &cursor);
- if (r < 0) {
- log_error("Failed to get cursor: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get cursor: %m");
fprintf(f, "%s [%s]\n",
+ flags & OUTPUT_UTC ?
+ format_timestamp_us_utc(ts, sizeof(ts), realtime) :
format_timestamp_us(ts, sizeof(ts), realtime),
cursor);
sd_journal_set_data_threshold(j, 0);
r = sd_journal_get_realtime_usec(j, &realtime);
- if (r < 0) {
- log_error("Failed to get realtime timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get realtime timestamp: %m");
r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
- if (r < 0) {
- log_error("Failed to get monotonic timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get monotonic timestamp: %m");
r = sd_journal_get_cursor(j, &cursor);
- if (r < 0) {
- log_error("Failed to get cursor: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get cursor: %m");
fprintf(f,
"__CURSOR=%s\n"
- "__REALTIME_TIMESTAMP=%llu\n"
- "__MONOTONIC_TIMESTAMP=%llu\n"
+ "__REALTIME_TIMESTAMP="USEC_FMT"\n"
+ "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
"_BOOT_ID=%s\n",
cursor,
- (unsigned long long) realtime,
- (unsigned long long) monotonic,
+ realtime,
+ monotonic,
sd_id128_to_string(boot_id, sid));
JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
startswith(data, "_BOOT_ID="))
continue;
- if (!utf8_is_printable(data, length)) {
+ if (utf8_is_printable_newline(data, length, false))
+ fwrite(data, length, 1, f);
+ else {
const char *c;
uint64_t le64;
le64 = htole64(length - (c - (const char*) data) - 1);
fwrite(&le64, sizeof(le64), 1, f);
fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
- } else
- fwrite(data, length, 1, f);
+ }
fputc('\n', f);
}
sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
r = sd_journal_get_realtime_usec(j, &realtime);
- if (r < 0) {
- log_error("Failed to get realtime timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get realtime timestamp: %m");
r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
- if (r < 0) {
- log_error("Failed to get monotonic timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get monotonic timestamp: %m");
r = sd_journal_get_cursor(j, &cursor);
- if (r < 0) {
- log_error("Failed to get cursor: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get cursor: %m");
if (mode == OUTPUT_JSON_PRETTY)
fprintf(f,
"{\n"
"\t\"__CURSOR\" : \"%s\",\n"
- "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
- "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
+ "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
+ "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
"\t\"_BOOT_ID\" : \"%s\"",
cursor,
- (unsigned long long) realtime,
- (unsigned long long) monotonic,
+ realtime,
+ monotonic,
sd_id128_to_string(boot_id, sid));
else {
if (mode == OUTPUT_JSON_SSE)
fprintf(f,
"{ \"__CURSOR\" : \"%s\", "
- "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
- "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
+ "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
+ "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
"\"_BOOT_ID\" : \"%s\"",
cursor,
- (unsigned long long) realtime,
- (unsigned long long) monotonic,
+ realtime,
+ monotonic,
sd_id128_to_string(boot_id, sid));
}
- h = hashmap_new(string_hash_func, string_compare_func);
+ h = hashmap_new(&string_hash_ops);
if (!h)
- return -ENOMEM;
+ return log_oom();
/* First round, iterate through the entry and count how often each field appears */
JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
n = strndup(data, eq - (const char*) data);
if (!n) {
- r = -ENOMEM;
+ r = log_oom();
goto finish;
}
r = hashmap_put(h, n, UINT_TO_PTR(1));
if (r < 0) {
free(n);
+ log_oom();
goto finish;
}
} else {
r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
free(n);
- if (r < 0)
+ if (r < 0) {
+ log_oom();
goto finish;
+ }
}
}
n = strndup(data, m);
if (!n) {
- r = -ENOMEM;
+ r = log_oom();
goto finish;
}
if (r == -ENOENT)
return 0;
- log_error("Failed to get data: %s", strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to get data: %m");
}
assert(l >= 8);
return ret;
}
+static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
+ assert(f);
+ assert(flags);
+
+ if (!(*flags & OUTPUT_BEGIN_NEWLINE))
+ return 0;
+
+ /* Print a beginning new line if that's request, but only once
+ * on the first line we print. */
+
+ fputc('\n', f);
+ *flags &= ~OUTPUT_BEGIN_NEWLINE;
+ return 0;
+}
+
static int show_journal(FILE *f,
sd_journal *j,
OutputMode mode,
/* Seek to end */
r = sd_journal_seek_tail(j);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to seek to tail: %m");
r = sd_journal_previous_skip(j, how_many);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to skip previous: %m");
for (;;) {
for (;;) {
if (need_seek) {
r = sd_journal_next(j);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to iterate through journal: %m");
}
if (r == 0)
if (r == -ESTALE)
continue;
else if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to get journal time: %m");
if (usec < not_before)
continue;
}
line ++;
+ maybe_print_begin_newline(f, &flags);
r = output_journal(f, j, mode, n_columns, flags, ellipsized);
if (r < 0)
- goto finish;
+ return r;
}
if (warn_cutoff && line < how_many && not_before > 0) {
sd_id128_t boot_id;
- usec_t cutoff;
+ usec_t cutoff = 0;
/* Check whether the cutoff line is too early */
r = sd_id128_get_boot(&boot_id);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to get boot id: %m");
r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to get journal cutoff time: %m");
- if (r > 0 && not_before < cutoff)
+ if (r > 0 && not_before < cutoff) {
+ maybe_print_begin_newline(f, &flags);
fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
+ }
warn_cutoff = false;
}
if (!(flags & OUTPUT_FOLLOW))
break;
- r = sd_journal_wait(j, (usec_t) -1);
+ r = sd_journal_wait(j, USEC_INFINITY);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to wait for journal: %m");
}
-finish:
- return r;
+ return 0;
}
int add_matches_for_unit(sd_journal *j, const char *unit) {
assert(j);
assert(unit);
- m1 = strappenda("_SYSTEMD_UNIT=", unit);
- m2 = strappenda("COREDUMP_UNIT=", unit);
- m3 = strappenda("UNIT=", unit);
- m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit);
+ m1 = strjoina("_SYSTEMD_UNIT=", unit);
+ m2 = strjoina("COREDUMP_UNIT=", unit);
+ m3 = strjoina("UNIT=", unit);
+ m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
(void)(
/* Look for messages from the service itself */
assert(j);
assert(unit);
- m1 = strappenda("_SYSTEMD_USER_UNIT=", unit);
- m2 = strappenda("USER_UNIT=", unit);
- m3 = strappenda("COREDUMP_USER_UNIT=", unit);
- m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit);
- sprintf(muid, "_UID=%lu", (unsigned long) uid);
+ m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
+ m2 = strjoina("USER_UNIT=", unit);
+ m3 = strjoina("COREDUMP_USER_UNIT=", unit);
+ m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
+ sprintf(muid, "_UID="UID_FMT, uid);
(void) (
/* Look for messages from the user service itself */
}
static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
- _cleanup_close_pipe_ int pair[2] = { -1, -1 };
+ _cleanup_close_pair_ int pair[2] = { -1, -1 };
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
pid_t pid, child;
siginfo_t si;
assert(machine);
assert(boot_id);
- if (!filename_is_safe(machine))
+ if (!machine_name_is_valid(machine))
return -EINVAL;
r = container_get_leader(machine, &pid);
if (r < 0)
return r;
- r = namespace_open(pid, &pidnsfd, &mntnsfd, &rootfd);
+ r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
if (r < 0)
return r;
if (child == 0) {
int fd;
- close_nointr_nofail(pair[0]);
- pair[0] = -1;
+ pair[0] = safe_close(pair[0]);
- r = namespace_enter(pidnsfd, mntnsfd, rootfd);
+ r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
if (r < 0)
_exit(EXIT_FAILURE);
if (fd < 0)
_exit(EXIT_FAILURE);
- k = loop_read(fd, buf, 36, false);
- close_nointr_nofail(fd);
- if (k != 36)
+ r = loop_read_exact(fd, buf, 36, false);
+ safe_close(fd);
+ if (r < 0)
_exit(EXIT_FAILURE);
k = send(pair[1], buf, 36, MSG_NOSIGNAL);
_exit(EXIT_SUCCESS);
}
- close_nointr_nofail(pair[1]);
- pair[1] = -1;
+ pair[1] = safe_close(pair[1]);
r = wait_for_terminate(child, &si);
if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
if (machine) {
r = get_boot_id_for_machine(machine, &boot_id);
- if (r < 0) {
- log_error("Failed to get boot id of container %s: %s", machine, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
} else {
r = sd_id128_get_boot(&boot_id);
- if (r < 0) {
- log_error("Failed to get boot id: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get boot id: %m");
}
sd_id128_to_string(boot_id, match + 9);
r = sd_journal_add_match(j, match, strlen(match));
- if (r < 0) {
- log_error("Failed to add match: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match: %m");
r = sd_journal_add_conjunction(j);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to add conjunction: %m");
return 0;
}
unsigned how_many,
uid_t uid,
OutputFlags flags,
- bool system,
+ int journal_open_flags,
+ bool system_unit,
bool *ellipsized) {
_cleanup_journal_close_ sd_journal*j = NULL;
int r;
- int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM;
assert(mode >= 0);
assert(mode < _OUTPUT_MODE_MAX);
if (how_many <= 0)
return 0;
- r = sd_journal_open(&j, jflags);
+ r = sd_journal_open(&j, journal_open_flags);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to open journal: %m");
r = add_match_this_boot(j, NULL);
if (r < 0)
return r;
- if (system)
+ if (system_unit)
r = add_matches_for_unit(j, unit);
else
r = add_matches_for_user_unit(j, unit, uid);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to add unit matches: %m");
- if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
+ if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
_cleanup_free_ char *filter;
filter = journal_make_match_string(j);
+ if (!filter)
+ return log_oom();
+
log_debug("Journal filter: %s", filter);
}