1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
34 #include <systemd/sd-journal.h>
38 #include "path-util.h"
41 #include "logs-show.h"
43 static OutputMode arg_output = OUTPUT_SHORT;
44 static bool arg_follow = false;
45 static bool arg_show_all = false;
46 static bool arg_no_pager = false;
47 static int arg_lines = -1;
48 static bool arg_no_tail = false;
49 static bool arg_new_id128 = false;
50 static bool arg_quiet = false;
51 static bool arg_local = false;
52 static bool arg_this_boot = false;
54 static int help(void) {
56 printf("%s [OPTIONS...] [MATCH]\n\n"
57 "Send control commands to or query the journal.\n\n"
58 " -h --help Show this help\n"
59 " --version Show package version\n"
60 " --no-pager Do not pipe output into a pager\n"
61 " -a --all Show all fields, including long and unprintable\n"
62 " -f --follow Follow journal\n"
63 " -n --lines=INTEGER Journal entries to show\n"
64 " --no-tail Show all lines, even in follow mode\n"
65 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
66 " verbose, export, json, cat)\n"
67 " -q --quiet Don't show privilege warning\n"
68 " -l --local Only local entries\n"
69 " -b --this-boot Show data only from current boot\n"
70 " --new-id128 Generate a new 128 Bit id\n",
71 program_invocation_short_name);
76 static int parse_argv(int argc, char *argv[]) {
85 static const struct option options[] = {
86 { "help", no_argument, NULL, 'h' },
87 { "version" , no_argument, NULL, ARG_VERSION },
88 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
89 { "follow", no_argument, NULL, 'f' },
90 { "output", required_argument, NULL, 'o' },
91 { "all", no_argument, NULL, 'a' },
92 { "lines", required_argument, NULL, 'n' },
93 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
94 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
95 { "quiet", no_argument, NULL, 'q' },
96 { "local", no_argument, NULL, 'l' },
97 { "this-boot", no_argument, NULL, 'b' },
106 while ((c = getopt_long(argc, argv, "hfo:an:qlb", options, NULL)) >= 0) {
115 puts(PACKAGE_STRING);
117 puts(SYSTEMD_FEATURES);
129 arg_output = output_mode_from_string(optarg);
130 if (arg_output < 0) {
131 log_error("Unknown output '%s'.", optarg);
142 r = safe_atoi(optarg, &arg_lines);
143 if (r < 0 || arg_lines < 0) {
144 log_error("Failed to parse lines '%s'", optarg);
154 arg_new_id128 = true;
166 arg_this_boot = true;
173 log_error("Unknown option code %c", c);
178 if (arg_follow && !arg_no_tail && arg_lines < 0)
184 static int generate_new_id128(void) {
189 r = sd_id128_randomize(&id);
191 log_error("Failed to generate ID: %s", strerror(-r));
195 printf("As string:\n"
196 SD_ID128_FORMAT_STR "\n\n"
198 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
200 "#define MESSAGE_XYZ SD_ID128_MAKE(",
201 SD_ID128_FORMAT_VAL(id),
202 SD_ID128_FORMAT_VAL(id));
204 for (i = 0; i < 16; i++)
205 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
207 fputs(")\n", stdout);
212 int main(int argc, char *argv[]) {
214 sd_journal *j = NULL;
216 bool need_seek = false;
219 log_parse_environment();
222 r = parse_argv(argc, argv);
227 r = generate_new_id128();
232 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
233 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off.");
236 r = sd_journal_open(&j, arg_local ? SD_JOURNAL_LOCAL_ONLY : 0);
238 log_error("Failed to open journal: %s", strerror(-r));
243 char match[9+32+1] = "_BOOT_ID=";
246 r = sd_id128_get_boot(&boot_id);
248 log_error("Failed to get boot id: %s", strerror(-r));
252 sd_id128_to_string(boot_id, match + 9);
254 r = sd_journal_add_match(j, match, strlen(match));
256 log_error("Failed to add match: %s", strerror(-r));
261 for (i = optind; i < argc; i++) {
262 if (path_is_absolute(argv[i])) {
266 p = canonicalize_file_name(argv[i]);
267 path = p ? p : argv[i];
269 if (stat(path, &st) < 0) {
271 log_error("Couldn't stat file: %m");
276 if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
279 t = strappend("_EXE=", path);
282 log_error("Out of memory");
286 r = sd_journal_add_match(j, t, strlen(t));
290 log_error("File is not a regular file or is not executable: %s", argv[i]);
296 r = sd_journal_add_match(j, argv[i], strlen(argv[i]));
299 log_error("Failed to add match: %s", strerror(-r));
304 fd = sd_journal_get_fd(j);
306 log_error("Failed to get wakeup fd: %s", strerror(-fd));
312 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
314 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
316 log_error("Failed to get cutoff: %s", strerror(-r));
322 printf("Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start));
324 printf("Logs begin at %s, end at %s.\n",
325 format_timestamp(start_buf, sizeof(start_buf), start),
326 format_timestamp(end_buf, sizeof(end_buf), end));
330 if (arg_lines >= 0) {
331 r = sd_journal_seek_tail(j);
333 log_error("Failed to seek to tail: %s", strerror(-r));
337 r = sd_journal_previous_skip(j, arg_lines);
339 r = sd_journal_seek_head(j);
341 log_error("Failed to seek to head: %s", strerror(-r));
345 r = sd_journal_next(j);
349 log_error("Failed to iterate through journal: %s", strerror(-r));
353 if (!arg_no_pager && !arg_follow) {
358 if (arg_output == OUTPUT_JSON) {
366 r = sd_journal_next(j);
368 log_error("Failed to iterate through journal: %s", strerror(-r));
378 r = output_journal(j, arg_output, line, 0, arg_show_all);
388 r = fd_wait_for_event(fd, POLLIN, (usec_t) -1);
390 log_error("Couldn't wait for event: %s", strerror(-r));
394 r = sd_journal_process(j);
396 log_error("Failed to process: %s", strerror(-r));
401 if (arg_output == OUTPUT_JSON)
402 fputs("\n]\n", stdout);
410 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;