X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fjournal%2Fjournalctl.c;h=8543adfb8a1d2d52ac65e72545fe505d552fce4d;hp=4c9862fa6ce5a83c080c189bcae6febf09feb753;hb=478c82693c386e7a6e8e4b37cc99fb19b12e7186;hpb=d89d6c86d9f141e0fb6939b7fc4f5ea068750690 diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 4c9862fa6..8543adfb8 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -35,9 +35,15 @@ #include #include +#ifdef HAVE_ACL +#include +#include "acl-util.h" +#endif + #include #include "log.h" +#include "logs-show.h" #include "util.h" #include "path-util.h" #include "build.h" @@ -56,6 +62,7 @@ #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) static OutputMode arg_output = OUTPUT_SHORT; +static bool arg_pager_end = false; static bool arg_follow = false; static bool arg_full = false; static bool arg_all = false; @@ -75,6 +82,7 @@ static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC; static usec_t arg_since, arg_until; static bool arg_since_set = false, arg_until_set = false; static const char *arg_unit = NULL; +static bool arg_unit_system; static const char *arg_field = NULL; static bool arg_catalog = false; static bool arg_reverse = false; @@ -87,6 +95,7 @@ static enum { ACTION_VERIFY, ACTION_DISK_USAGE, ACTION_LIST_CATALOG, + ACTION_DUMP_CATALOG, ACTION_UPDATE_CATALOG } arg_action = ACTION_SHOW; @@ -100,7 +109,9 @@ static int help(void) { " -c --cursor=CURSOR Start showing entries from specified cursor\n" " -b --this-boot Show data only from current boot\n" " -u --unit=UNIT Show data only from the specified unit\n" + " --user-unit=UNIT Show data only from the specified user session unit\n" " -p --priority=RANGE Show only messages within the specified priority range\n" + " -e --pager-end Immediately jump to end of the journal in the pager\n" " -f --follow Follow journal\n" " -n --lines[=INTEGER] Number of journal entries to show\n" " --no-tail Show all lines, even in follow mode\n" @@ -126,6 +137,7 @@ static int help(void) { " --disk-usage Show total disk usage\n" " -F --field=FIELD List all values a certain field takes\n" " --list-catalog Show message IDs of all entries in the message catalog\n" + " --dump-catalog Show entries in the message catalog\n" " --update-catalog Update the message catalog database\n" #ifdef HAVE_GCRYPT " --setup-keys Generate new FSS key pair\n" @@ -152,7 +164,9 @@ static int parse_argv(int argc, char *argv[]) { ARG_DISK_USAGE, ARG_SINCE, ARG_UNTIL, + ARG_USER_UNIT, ARG_LIST_CATALOG, + ARG_DUMP_CATALOG, ARG_UPDATE_CATALOG }; @@ -160,6 +174,7 @@ static int parse_argv(int argc, char *argv[]) { { "help", no_argument, NULL, 'h' }, { "version" , no_argument, NULL, ARG_VERSION }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "pager-end", no_argument, NULL, 'e' }, { "follow", no_argument, NULL, 'f' }, { "output", required_argument, NULL, 'o' }, { "all", no_argument, NULL, 'a' }, @@ -182,9 +197,11 @@ static int parse_argv(int argc, char *argv[]) { { "since", required_argument, NULL, ARG_SINCE }, { "until", required_argument, NULL, ARG_UNTIL }, { "unit", required_argument, NULL, 'u' }, + { "user-unit", required_argument, NULL, ARG_USER_UNIT }, { "field", required_argument, NULL, 'F' }, { "catalog", no_argument, NULL, 'x' }, { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG }, + { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG }, { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG }, { "reverse", no_argument, NULL, 'r' }, { NULL, 0, NULL, 0 } @@ -195,7 +212,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:u:F:xr", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "hefo:an::qmbD:p:c:u:F:xr", options, NULL)) >= 0) { switch (c) { @@ -212,6 +229,14 @@ static int parse_argv(int argc, char *argv[]) { arg_no_pager = true; break; + case 'e': + arg_pager_end = true; + + if (arg_lines < 0) + arg_lines = 1000; + + break; + case 'f': arg_follow = true; break; @@ -406,6 +431,12 @@ static int parse_argv(int argc, char *argv[]) { case 'u': arg_unit = optarg; + arg_unit_system = true; + break; + + case ARG_USER_UNIT: + arg_unit = optarg; + arg_unit_system = false; break; case '?': @@ -423,6 +454,10 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_LIST_CATALOG; break; + case ARG_DUMP_CATALOG: + arg_action = ACTION_DUMP_CATALOG; + break; + case ARG_UPDATE_CATALOG: arg_action = ACTION_UPDATE_CATALOG; break; @@ -491,16 +526,16 @@ static int generate_new_id128(void) { static int add_matches(sd_journal *j, char **args) { char **i; - int r; assert(j); STRV_FOREACH(i, args) { + int r; if (streq(*i, "+")) r = sd_journal_add_disjunction(j); else if (path_is_absolute(*i)) { - char *p, *t = NULL; + char _cleanup_free_ *p, *t = NULL; const char *path; struct stat st; @@ -508,7 +543,6 @@ static int add_matches(sd_journal *j, char **args) { path = p ? p : *i; if (stat(path, &st) < 0) { - free(p); log_error("Couldn't stat file: %m"); return -errno; } @@ -520,18 +554,14 @@ static int add_matches(sd_journal *j, char **args) { else if (S_ISBLK(st.st_mode)) asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev)); else { - free(p); log_error("File is not a device node, regular file or is not executable: %s", *i); return -EINVAL; } - free(p); - if (!t) return log_oom(); r = sd_journal_add_match(j, t, 0); - free(t); } else r = sd_journal_add_match(j, *i, 0); @@ -571,7 +601,7 @@ static int add_this_boot(sd_journal *j) { } static int add_unit(sd_journal *j) { - _cleanup_free_ char *m = NULL, *u = NULL; + _cleanup_free_ char *u = NULL; int r; assert(j); @@ -583,15 +613,12 @@ static int add_unit(sd_journal *j) { if (!u) return log_oom(); - m = strappend("_SYSTEMD_UNIT=", u); - if (!m) - return log_oom(); - - r = sd_journal_add_match(j, m, strlen(m)); - if (r < 0) { - log_error("Failed to add match: %s", strerror(-r)); + if (arg_unit_system) + r = add_matches_for_unit(j, u); + else + r = add_matches_for_user_unit(j, u, getuid()); + if (r < 0) return r; - } return 0; } @@ -859,16 +886,55 @@ static int verify(sd_journal *j) { static int access_check(void) { #ifdef HAVE_ACL - if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) { - log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages."); + /* If /var/log/journal doesn't even exist, unprivileged users have no access at all */ + if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("systemd-journal") <= 0) { + log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'systemd-journal' can always see messages."); return -EACCES; } - if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0) - log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off."); + /* If /var/log/journal exists, try to pring a nice notice if the user lacks access to it */ + if (!arg_quiet && geteuid() != 0) { + _cleanup_strv_free_ char **g = NULL; + bool have_access; + int r; + + have_access = in_group("systemd-journal") > 0; + + if (!have_access) { + /* Let's enumerate all groups from the default + * ACL of the directory, which generally + * should allow access to most journal + * files too */ + r = search_acl_groups(&g, "/var/log/journal/", &have_access); + if (r < 0) + return r; + } + + if (!have_access) { + + if (strv_isempty(g)) + log_notice("Hint: You are currently not seeing messages from other users and the system. Users in the group 'systemd-journal' can see all messages. Pass -q to turn this notice off."); + else { + _cleanup_free_ char *s = NULL; + + r = strv_extend(&g, "systemd-journal"); + if (r < 0) + return log_oom(); + + strv_sort(g); + strv_uniq(g); + + s = strv_join(g, "', '"); + if (!s) + return log_oom(); + + log_notice("Hint: You are currently not seeing messages from other users and the system. Users in the groups '%s' can see all messages. Pass -q to turn this notice off.", s); + } + } + } #else - if (geteuid() != 0 && in_group("adm") <= 0) { - log_error("No access to messages. Only users in the group 'adm' can see messages."); + if (geteuid() != 0 && in_group("systemd-journal") <= 0) { + log_error("No access to messages. Only users in the group 'systemd-journal' can see messages."); return -EACCES; } #endif @@ -878,7 +944,7 @@ static int access_check(void) { int main(int argc, char *argv[]) { int r; - sd_journal *j = NULL; + sd_journal _cleanup_journal_close_ *j = NULL; bool need_seek = false; sd_id128_t previous_boot_id; bool previous_boot_id_valid = false, first_line = true; @@ -904,8 +970,13 @@ int main(int argc, char *argv[]) { goto finish; } - if (arg_action == ACTION_LIST_CATALOG) { - r = catalog_list(stdout); + if (arg_action == ACTION_LIST_CATALOG || + arg_action == ACTION_DUMP_CATALOG) { + bool oneline = arg_action == ACTION_LIST_CATALOG; + if (optind < argc) + r = catalog_list_items(stdout, oneline, argv + optind); + else + r = catalog_list(stdout, oneline); if (r < 0) log_error("Failed to list catalog: %s", strerror(-r)); goto finish; @@ -918,7 +989,7 @@ int main(int argc, char *argv[]) { r = access_check(); if (r < 0) - goto finish; + return EXIT_FAILURE; if (arg_directory) r = sd_journal_open_directory(&j, arg_directory, 0); @@ -926,7 +997,7 @@ int main(int argc, char *argv[]) { r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY); if (r < 0) { log_error("Failed to open journal: %s", strerror(-r)); - goto finish; + return EXIT_FAILURE; } if (arg_action == ACTION_VERIFY) { @@ -936,8 +1007,7 @@ int main(int argc, char *argv[]) { if (arg_action == ACTION_PRINT_HEADER) { journal_print_header(j); - r = 0; - goto finish; + return EXIT_SUCCESS; } if (arg_action == ACTION_DISK_USAGE) { @@ -946,33 +1016,33 @@ int main(int argc, char *argv[]) { r = sd_journal_get_usage(j, &bytes); if (r < 0) - goto finish; + return EXIT_FAILURE; - printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes)); - r = 0; - goto finish; + printf("Journals take up %s on disk.\n", + format_bytes(sbytes, sizeof(sbytes), bytes)); + return EXIT_SUCCESS; } r = add_this_boot(j); if (r < 0) - goto finish; + return EXIT_FAILURE; r = add_unit(j); if (r < 0) - goto finish; + return EXIT_FAILURE; r = add_matches(j, argv + optind); if (r < 0) - goto finish; + return EXIT_FAILURE; r = add_priorities(j); if (r < 0) - goto finish; + return EXIT_FAILURE; /* Opening the fd now means the first sd_journal_wait() will actually wait */ r = sd_journal_get_fd(j); if (r < 0) - goto finish; + return EXIT_FAILURE; if (arg_field) { const void *data; @@ -981,7 +1051,7 @@ int main(int argc, char *argv[]) { r = sd_journal_query_unique(j, arg_field); if (r < 0) { log_error("Failed to query unique data objects: %s", strerror(-r)); - goto finish; + return EXIT_FAILURE; } SD_JOURNAL_FOREACH_UNIQUE(j, data, size) { @@ -999,15 +1069,14 @@ int main(int argc, char *argv[]) { n_shown ++; } - r = 0; - goto finish; + return EXIT_SUCCESS; } if (arg_cursor) { r = sd_journal_seek_cursor(j, arg_cursor); if (r < 0) { log_error("Failed to seek to cursor: %s", strerror(-r)); - goto finish; + return EXIT_FAILURE; } if (!arg_reverse) r = sd_journal_next(j); @@ -1018,7 +1087,7 @@ int main(int argc, char *argv[]) { r = sd_journal_seek_realtime_usec(j, arg_since); if (r < 0) { log_error("Failed to seek to date: %s", strerror(-r)); - goto finish; + return EXIT_FAILURE; } r = sd_journal_next(j); @@ -1026,7 +1095,7 @@ int main(int argc, char *argv[]) { r = sd_journal_seek_realtime_usec(j, arg_until); if (r < 0) { log_error("Failed to seek to date: %s", strerror(-r)); - goto finish; + return EXIT_FAILURE; } r = sd_journal_previous(j); @@ -1034,7 +1103,7 @@ int main(int argc, char *argv[]) { r = sd_journal_seek_tail(j); if (r < 0) { log_error("Failed to seek to tail: %s", strerror(-r)); - goto finish; + return EXIT_FAILURE; } r = sd_journal_previous_skip(j, arg_lines); @@ -1043,7 +1112,7 @@ int main(int argc, char *argv[]) { r = sd_journal_seek_tail(j); if (r < 0) { log_error("Failed to seek to tail: %s", strerror(-r)); - goto finish; + return EXIT_FAILURE; } r = sd_journal_previous(j); @@ -1052,7 +1121,7 @@ int main(int argc, char *argv[]) { r = sd_journal_seek_head(j); if (r < 0) { log_error("Failed to seek to head: %s", strerror(-r)); - goto finish; + return EXIT_FAILURE; } r = sd_journal_next(j); @@ -1060,11 +1129,11 @@ int main(int argc, char *argv[]) { if (r < 0) { log_error("Failed to iterate through journal: %s", strerror(-r)); - goto finish; + return EXIT_FAILURE; } if (!arg_no_pager && !arg_follow) - pager_open(); + pager_open(arg_pager_end); if (!arg_quiet) { usec_t start, end; @@ -1092,7 +1161,7 @@ int main(int argc, char *argv[]) { int flags; if (need_seek) { - if(!arg_reverse) + if (!arg_reverse) r = sd_journal_next(j); else r = sd_journal_previous(j); @@ -1170,9 +1239,6 @@ int main(int argc, char *argv[]) { } finish: - if (j) - sd_journal_close(j); - pager_close(); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;