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>
40 #include "logs-show.h"
42 #define SD_JOURNALCTL_EXE "_EXE="
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;
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 " --new-id128 Generate a new 128 Bit id\n"
69 " -l --local Only local entries\n",
70 program_invocation_short_name);
75 static int parse_argv(int argc, char *argv[]) {
84 static const struct option options[] = {
85 { "help", no_argument, NULL, 'h' },
86 { "version" , no_argument, NULL, ARG_VERSION },
87 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
88 { "follow", no_argument, NULL, 'f' },
89 { "output", required_argument, NULL, 'o' },
90 { "all", no_argument, NULL, 'a' },
91 { "lines", required_argument, NULL, 'n' },
92 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
93 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
94 { "quiet", no_argument, NULL, 'q' },
95 { "local", no_argument, NULL, 'l' },
104 while ((c = getopt_long(argc, argv, "hfo:an:ql", options, NULL)) >= 0) {
113 puts(PACKAGE_STRING);
115 puts(SYSTEMD_FEATURES);
127 arg_output = output_mode_from_string(optarg);
128 if (arg_output < 0) {
129 log_error("Unknown output '%s'.", optarg);
140 r = safe_atoi(optarg, &arg_lines);
141 if (r < 0 || arg_lines < 0) {
142 log_error("Failed to parse lines '%s'", optarg);
152 arg_new_id128 = true;
167 log_error("Unknown option code %c", c);
172 if (arg_follow && !arg_no_tail && arg_lines < 0)
178 static int generate_new_id128(void) {
183 r = sd_id128_randomize(&id);
185 log_error("Failed to generate ID: %s", strerror(-r));
189 printf("As string:\n"
190 SD_ID128_FORMAT_STR "\n\n"
192 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
194 "#define MESSAGE_XYZ SD_ID128_MAKE(",
195 SD_ID128_FORMAT_VAL(id),
196 SD_ID128_FORMAT_VAL(id));
198 for (i = 0; i < 16; i++)
199 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
201 fputs(")\n", stdout);
206 int main(int argc, char *argv[]) {
208 sd_journal *j = NULL;
210 bool need_seek = false;
212 char* journal_exe_buff;
214 log_parse_environment();
217 r = parse_argv(argc, argv);
222 r = generate_new_id128();
227 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
228 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off.");
231 r = sd_journal_open(&j, arg_local ? SD_JOURNAL_LOCAL_ONLY : 0);
233 log_error("Failed to open journal: %s", strerror(-r));
237 for (i = optind; i < argc; i++) {
238 if (strchr(argv[i], '=')) {
239 r = sd_journal_add_match(j, argv[i], strlen(argv[i]));
241 if (stat(argv[i], &st) < 0) {
242 log_error("Failed to add match: %s", strerror(-r));
243 goto finish; /* maybe try sd_journal_add_match() when stat() fails,
244 * even thought we know there is no '=' ? */
245 } else if (S_ISREG(st.st_mode) &&
246 S_IXUSR & st.st_mode) {
247 journal_exe_buff = malloc(strlen(SD_JOURNALCTL_EXE) + strlen(argv[i]) + 1);
248 journal_exe_buff = strcpy(journal_exe_buff, SD_JOURNALCTL_EXE);
249 strncat(journal_exe_buff, argv[i], strlen(argv[i]));
250 r = sd_journal_add_match(j, journal_exe_buff, strlen(journal_exe_buff));
251 free(journal_exe_buff);
253 log_error("File is not a regular file or is not executable: %s", argv[i]);
258 log_error("Failed to add match: %s", strerror(-r));
263 fd = sd_journal_get_fd(j);
265 log_error("Failed to get wakeup fd: %s", strerror(-fd));
269 if (arg_lines >= 0) {
270 r = sd_journal_seek_tail(j);
272 log_error("Failed to seek to tail: %s", strerror(-r));
276 r = sd_journal_previous_skip(j, arg_lines);
278 r = sd_journal_seek_head(j);
280 log_error("Failed to seek to head: %s", strerror(-r));
284 r = sd_journal_next(j);
288 log_error("Failed to iterate through journal: %s", strerror(-r));
292 if (!arg_no_pager && !arg_follow) {
297 if (arg_output == OUTPUT_JSON) {
305 r = sd_journal_next(j);
307 log_error("Failed to iterate through journal: %s", strerror(-r));
317 r = output_journal(j, arg_output, line, 0, arg_show_all);
327 r = fd_wait_for_event(fd, POLLIN, (usec_t) -1);
329 log_error("Couldn't wait for event: %s", strerror(-r));
333 r = sd_journal_process(j);
335 log_error("Failed to process: %s", strerror(-r));
340 if (arg_output == OUTPUT_JSON)
341 fputs("\n]\n", stdout);
349 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;