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"
44 static OutputMode arg_output
= OUTPUT_SHORT
;
45 static bool arg_follow
= false;
46 static bool arg_show_all
= false;
47 static bool arg_no_pager
= false;
48 static int arg_lines
= -1;
49 static bool arg_no_tail
= false;
50 static bool arg_new_id128
= false;
51 static bool arg_quiet
= false;
52 static bool arg_local
= false;
53 static bool arg_this_boot
= false;
54 static const char *arg_directory
= NULL
;
56 static int help(void) {
58 printf("%s [OPTIONS...] [MATCH]\n\n"
59 "Send control commands to or query the journal.\n\n"
60 " -h --help Show this help\n"
61 " --version Show package version\n"
62 " --no-pager Do not pipe output into a pager\n"
63 " -a --all Show all fields, including long and unprintable\n"
64 " -f --follow Follow journal\n"
65 " -n --lines=INTEGER Journal entries to show\n"
66 " --no-tail Show all lines, even in follow mode\n"
67 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
68 " verbose, export, json, cat)\n"
69 " -q --quiet Don't show privilege warning\n"
70 " -l --local Only local entries\n"
71 " -b --this-boot Show data only from current boot\n"
72 " -D --directory=PATH Show journal files from directory\n"
73 " --new-id128 Generate a new 128 Bit id\n",
74 program_invocation_short_name
);
79 static int parse_argv(int argc
, char *argv
[]) {
88 static const struct option options
[] = {
89 { "help", no_argument
, NULL
, 'h' },
90 { "version" , no_argument
, NULL
, ARG_VERSION
},
91 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
92 { "follow", no_argument
, NULL
, 'f' },
93 { "output", required_argument
, NULL
, 'o' },
94 { "all", no_argument
, NULL
, 'a' },
95 { "lines", required_argument
, NULL
, 'n' },
96 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
97 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
},
98 { "quiet", no_argument
, NULL
, 'q' },
99 { "local", no_argument
, NULL
, 'l' },
100 { "this-boot", no_argument
, NULL
, 'b' },
101 { "directory", required_argument
, NULL
, 'D' },
110 while ((c
= getopt_long(argc
, argv
, "hfo:an:qlbD:", options
, NULL
)) >= 0) {
119 puts(PACKAGE_STRING
);
121 puts(SYSTEMD_FEATURES
);
133 arg_output
= output_mode_from_string(optarg
);
134 if (arg_output
< 0) {
135 log_error("Unknown output '%s'.", optarg
);
146 r
= safe_atoi(optarg
, &arg_lines
);
147 if (r
< 0 || arg_lines
< 0) {
148 log_error("Failed to parse lines '%s'", optarg
);
158 arg_new_id128
= true;
170 arg_this_boot
= true;
174 arg_directory
= optarg
;
181 log_error("Unknown option code %c", c
);
186 if (arg_follow
&& !arg_no_tail
&& arg_lines
< 0)
192 static int generate_new_id128(void) {
197 r
= sd_id128_randomize(&id
);
199 log_error("Failed to generate ID: %s", strerror(-r
));
203 printf("As string:\n"
204 SD_ID128_FORMAT_STR
"\n\n"
206 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
208 "#define MESSAGE_XYZ SD_ID128_MAKE(",
209 SD_ID128_FORMAT_VAL(id
),
210 SD_ID128_FORMAT_VAL(id
));
212 for (i
= 0; i
< 16; i
++)
213 printf("%02x%s", id
.bytes
[i
], i
!= 15 ? "," : "");
215 fputs(")\n", stdout
);
220 static int add_matches(sd_journal
*j
, char **args
) {
226 STRV_FOREACH(i
, args
) {
228 if (path_is_absolute(*i
)) {
233 p
= canonicalize_file_name(*i
);
236 if (stat(path
, &st
) < 0) {
238 log_error("Couldn't stat file: %m");
242 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
245 t
= strappend("_EXE=", path
);
248 log_error("Out of memory");
252 r
= sd_journal_add_match(j
, t
, strlen(t
));
256 log_error("File is not a regular file or is not executable: %s", *i
);
262 r
= sd_journal_add_match(j
, *i
, strlen(*i
));
265 log_error("Failed to add match: %s", strerror(-r
));
273 static int add_this_boot(sd_journal
*j
) {
274 char match
[9+32+1] = "_BOOT_ID=";
281 r
= sd_id128_get_boot(&boot_id
);
283 log_error("Failed to get boot id: %s", strerror(-r
));
287 sd_id128_to_string(boot_id
, match
+ 9);
288 r
= sd_journal_add_match(j
, match
, strlen(match
));
290 log_error("Failed to add match: %s", strerror(-r
));
297 int main(int argc
, char *argv
[]) {
299 sd_journal
*j
= NULL
;
301 bool need_seek
= false;
303 log_parse_environment();
306 r
= parse_argv(argc
, argv
);
311 r
= generate_new_id128();
316 if (!arg_quiet
&& geteuid() != 0 && in_group("adm") <= 0)
317 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off.");
321 r
= sd_journal_open_directory(&j
, arg_directory
, 0);
323 r
= sd_journal_open(&j
, arg_local
? SD_JOURNAL_LOCAL_ONLY
: 0);
326 log_error("Failed to open journal: %s", strerror(-r
));
330 r
= add_this_boot(j
);
334 r
= add_matches(j
, argv
+ optind
);
340 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
342 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
344 log_error("Failed to get cutoff: %s", strerror(-r
));
350 printf("Logs begin at %s.\n", format_timestamp(start_buf
, sizeof(start_buf
), start
));
352 printf("Logs begin at %s, end at %s.\n",
353 format_timestamp(start_buf
, sizeof(start_buf
), start
),
354 format_timestamp(end_buf
, sizeof(end_buf
), end
));
358 if (arg_lines
>= 0) {
359 r
= sd_journal_seek_tail(j
);
361 log_error("Failed to seek to tail: %s", strerror(-r
));
365 r
= sd_journal_previous_skip(j
, arg_lines
);
367 r
= sd_journal_seek_head(j
);
369 log_error("Failed to seek to head: %s", strerror(-r
));
373 r
= sd_journal_next(j
);
377 log_error("Failed to iterate through journal: %s", strerror(-r
));
381 if (!arg_no_pager
&& !arg_follow
) {
386 if (arg_output
== OUTPUT_JSON
) {
394 r
= sd_journal_next(j
);
396 log_error("Failed to iterate through journal: %s", strerror(-r
));
406 r
= output_journal(j
, arg_output
, line
, 0, arg_show_all
);
416 r
= sd_journal_wait(j
, (uint64_t) -1);
418 log_error("Couldn't wait for log event: %s", strerror(-r
));
423 if (arg_output
== OUTPUT_JSON
)
424 fputs("\n]\n", stdout
);
432 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;