]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
use "Out of memory." consistantly (or with "\n")
[thirdparty/systemd.git] / src / journal / journalctl.c
CommitLineData
87d2c1ff
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
87d2c1ff
LP
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
87d2c1ff 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
87d2c1ff
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <fcntl.h>
23#include <errno.h>
24#include <stddef.h>
3fbf9cbb
LP
25#include <string.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <stdlib.h>
50f20cfd 29#include <sys/poll.h>
72f59706 30#include <time.h>
0d43c694 31#include <getopt.h>
50940700 32#include <sys/stat.h>
87d2c1ff 33
81527be1
LP
34#include <systemd/sd-journal.h>
35
3fbf9cbb 36#include "log.h"
72f59706 37#include "util.h"
e5124088 38#include "path-util.h"
0d43c694
LP
39#include "build.h"
40#include "pager.h"
86aa7ba4 41#include "logs-show.h"
a963990f 42#include "strv.h"
dca6219e 43#include "journal-internal.h"
250d54b5 44
df50185b 45static OutputMode arg_output = OUTPUT_SHORT;
72f59706
LP
46static bool arg_follow = false;
47static bool arg_show_all = false;
0d43c694 48static bool arg_no_pager = false;
2100675e 49static int arg_lines = -1;
e91af489 50static bool arg_no_tail = false;
39f7f5c1 51static bool arg_new_id128 = false;
dca6219e 52static bool arg_print_header = false;
43673799 53static bool arg_quiet = false;
2bd3c38a 54static bool arg_local = false;
59cea26a 55static bool arg_this_boot = false;
a963990f 56static const char *arg_directory = NULL;
50f20cfd 57
0d43c694
LP
58static int help(void) {
59
89834a7c 60 printf("%s [OPTIONS...] [MATCH]\n\n"
df50185b 61 "Send control commands to or query the journal.\n\n"
0d43c694
LP
62 " -h --help Show this help\n"
63 " --version Show package version\n"
64 " --no-pager Do not pipe output into a pager\n"
2af777ba 65 " -a --all Show all fields, including long and unprintable\n"
0d43c694 66 " -f --follow Follow journal\n"
df50185b 67 " -n --lines=INTEGER Journal entries to show\n"
e91af489 68 " --no-tail Show all lines, even in follow mode\n"
d3f2bdbf
LP
69 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
70 " verbose, export, json, cat)\n"
43673799 71 " -q --quiet Don't show privilege warning\n"
59cea26a
LP
72 " -l --local Only local entries\n"
73 " -b --this-boot Show data only from current boot\n"
a963990f 74 " -D --directory=PATH Show journal files from directory\n"
dca6219e 75 " --header Show journal header information\n"
59cea26a 76 " --new-id128 Generate a new 128 Bit id\n",
0d43c694
LP
77 program_invocation_short_name);
78
79 return 0;
80}
81
82static int parse_argv(int argc, char *argv[]) {
83
84 enum {
85 ARG_VERSION = 0x100,
e91af489 86 ARG_NO_PAGER,
55ee336c 87 ARG_NO_TAIL,
dca6219e
LP
88 ARG_NEW_ID128,
89 ARG_HEADER
0d43c694
LP
90 };
91
92 static const struct option options[] = {
93 { "help", no_argument, NULL, 'h' },
94 { "version" , no_argument, NULL, ARG_VERSION },
95 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
96 { "follow", no_argument, NULL, 'f' },
97 { "output", required_argument, NULL, 'o' },
98 { "all", no_argument, NULL, 'a' },
2100675e 99 { "lines", required_argument, NULL, 'n' },
e91af489 100 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
39f7f5c1 101 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
43673799 102 { "quiet", no_argument, NULL, 'q' },
2bd3c38a 103 { "local", no_argument, NULL, 'l' },
59cea26a 104 { "this-boot", no_argument, NULL, 'b' },
a963990f 105 { "directory", required_argument, NULL, 'D' },
dca6219e 106 { "header", no_argument, NULL, ARG_HEADER },
0d43c694
LP
107 { NULL, 0, NULL, 0 }
108 };
109
2100675e 110 int c, r;
0d43c694
LP
111
112 assert(argc >= 0);
113 assert(argv);
114
a963990f 115 while ((c = getopt_long(argc, argv, "hfo:an:qlbD:", options, NULL)) >= 0) {
0d43c694
LP
116
117 switch (c) {
118
119 case 'h':
120 help();
121 return 0;
122
123 case ARG_VERSION:
124 puts(PACKAGE_STRING);
125 puts(DISTRIBUTION);
126 puts(SYSTEMD_FEATURES);
127 return 0;
128
129 case ARG_NO_PAGER:
130 arg_no_pager = true;
131 break;
132
133 case 'f':
134 arg_follow = true;
135 break;
136
137 case 'o':
df50185b
LP
138 arg_output = output_mode_from_string(optarg);
139 if (arg_output < 0) {
0d43c694
LP
140 log_error("Unknown output '%s'.", optarg);
141 return -EINVAL;
142 }
df50185b 143
0d43c694
LP
144 break;
145
146 case 'a':
147 arg_show_all = true;
148 break;
149
2100675e
LP
150 case 'n':
151 r = safe_atoi(optarg, &arg_lines);
e91af489 152 if (r < 0 || arg_lines < 0) {
2100675e
LP
153 log_error("Failed to parse lines '%s'", optarg);
154 return -EINVAL;
155 }
156 break;
157
e91af489
LP
158 case ARG_NO_TAIL:
159 arg_no_tail = true;
160 break;
161
39f7f5c1
LP
162 case ARG_NEW_ID128:
163 arg_new_id128 = true;
55ee336c
LP
164 break;
165
43673799
LP
166 case 'q':
167 arg_quiet = true;
490e567d 168 break;
43673799 169
2bd3c38a
LP
170 case 'l':
171 arg_local = true;
172 break;
173
59cea26a
LP
174 case 'b':
175 arg_this_boot = true;
176 break;
177
a963990f
LP
178 case 'D':
179 arg_directory = optarg;
180 break;
181
dca6219e
LP
182 case ARG_HEADER:
183 arg_print_header = true;
184 break;
185
0d43c694
LP
186 case '?':
187 return -EINVAL;
188
189 default:
190 log_error("Unknown option code %c", c);
191 return -EINVAL;
192 }
193 }
194
62f21ec9 195 if (arg_follow && !arg_no_tail && arg_lines < 0)
e91af489
LP
196 arg_lines = 10;
197
0d43c694
LP
198 return 1;
199}
200
39f7f5c1 201static int generate_new_id128(void) {
55ee336c
LP
202 sd_id128_t id;
203 int r;
204 unsigned i;
205
206 r = sd_id128_randomize(&id);
207 if (r < 0) {
208 log_error("Failed to generate ID: %s", strerror(-r));
209 return r;
210 }
211
212 printf("As string:\n"
213 SD_ID128_FORMAT_STR "\n\n"
214 "As UUID:\n"
215 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
216 "As macro:\n"
217 "#define MESSAGE_XYZ SD_ID128_MAKE(",
218 SD_ID128_FORMAT_VAL(id),
219 SD_ID128_FORMAT_VAL(id));
220
221 for (i = 0; i < 16; i++)
222 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
223
224 fputs(")\n", stdout);
225
226 return 0;
227}
228
a963990f
LP
229static int add_matches(sd_journal *j, char **args) {
230 char **i;
231 int r;
59cea26a 232
a963990f 233 assert(j);
59cea26a 234
a963990f 235 STRV_FOREACH(i, args) {
59cea26a 236
cbdca852
LP
237 if (streq(*i, "+"))
238 r = sd_journal_add_disjunction(j);
239 else if (path_is_absolute(*i)) {
a963990f 240 char *p;
e5124088 241 const char *path;
a963990f 242 struct stat st;
e5124088 243
a963990f
LP
244 p = canonicalize_file_name(*i);
245 path = p ? p : *i;
e5124088
LP
246
247 if (stat(path, &st) < 0) {
248 free(p);
249 log_error("Couldn't stat file: %m");
a963990f 250 return -errno;
e5124088
LP
251 }
252
253 if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
254 char *t;
255
256 t = strappend("_EXE=", path);
257 if (!t) {
258 free(p);
669241a0 259 log_error("Out of memory.");
a963990f 260 return -ENOMEM;
e5124088
LP
261 }
262
cbdca852 263 r = sd_journal_add_match(j, t, 0);
e5124088 264 free(t);
50940700 265 } else {
e5124088 266 free(p);
a963990f
LP
267 log_error("File is not a regular file or is not executable: %s", *i);
268 return -EINVAL;
50940700 269 }
e5124088
LP
270
271 free(p);
272 } else
cbdca852 273 r = sd_journal_add_match(j, *i, 0);
e5124088 274
de7b95cd 275 if (r < 0) {
cbdca852 276 log_error("Failed to add match '%s': %s", *i, strerror(-r));
a963990f 277 return r;
de7b95cd
LP
278 }
279 }
280
a963990f
LP
281 return 0;
282}
283
284static int add_this_boot(sd_journal *j) {
285 char match[9+32+1] = "_BOOT_ID=";
286 sd_id128_t boot_id;
287 int r;
288
289 if (!arg_this_boot)
290 return 0;
291
292 r = sd_id128_get_boot(&boot_id);
293 if (r < 0) {
294 log_error("Failed to get boot id: %s", strerror(-r));
295 return r;
296 }
297
298 sd_id128_to_string(boot_id, match + 9);
299 r = sd_journal_add_match(j, match, strlen(match));
300 if (r < 0) {
301 log_error("Failed to add match: %s", strerror(-r));
302 return r;
303 }
304
305 return 0;
306}
307
308int main(int argc, char *argv[]) {
309 int r;
310 sd_journal *j = NULL;
311 unsigned line = 0;
312 bool need_seek = false;
14a65d65
LP
313 sd_id128_t previous_boot_id;
314 bool previous_boot_id_valid = false;
92a1fd9e 315 bool have_pager;
a963990f
LP
316
317 log_parse_environment();
318 log_open();
319
320 r = parse_argv(argc, argv);
321 if (r <= 0)
322 goto finish;
323
324 if (arg_new_id128) {
325 r = generate_new_id128();
326 goto finish;
327 }
328
329#ifdef HAVE_ACL
330 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
331 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off.");
332#endif
333
334 if (arg_directory)
335 r = sd_journal_open_directory(&j, arg_directory, 0);
336 else
337 r = sd_journal_open(&j, arg_local ? SD_JOURNAL_LOCAL_ONLY : 0);
338
339 if (r < 0) {
340 log_error("Failed to open journal: %s", strerror(-r));
341 goto finish;
342 }
343
dca6219e
LP
344 if (arg_print_header) {
345 journal_print_header(j);
346 r = 0;
347 goto finish;
348 }
349
a963990f
LP
350 r = add_this_boot(j);
351 if (r < 0)
352 goto finish;
353
354 r = add_matches(j, argv + optind);
355 if (r < 0)
356 goto finish;
357
08984293
LP
358 if (!arg_quiet) {
359 usec_t start, end;
360 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
361
362 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
363 if (r < 0) {
364 log_error("Failed to get cutoff: %s", strerror(-r));
365 goto finish;
366 }
367
368 if (r > 0) {
369 if (arg_follow)
370 printf("Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start));
371 else
372 printf("Logs begin at %s, end at %s.\n",
373 format_timestamp(start_buf, sizeof(start_buf), start),
374 format_timestamp(end_buf, sizeof(end_buf), end));
375 }
376 }
377
2100675e
LP
378 if (arg_lines >= 0) {
379 r = sd_journal_seek_tail(j);
380 if (r < 0) {
381 log_error("Failed to seek to tail: %s", strerror(-r));
382 goto finish;
383 }
384
385 r = sd_journal_previous_skip(j, arg_lines);
2100675e
LP
386 } else {
387 r = sd_journal_seek_head(j);
388 if (r < 0) {
389 log_error("Failed to seek to head: %s", strerror(-r));
390 goto finish;
391 }
6f003b43
LP
392
393 r = sd_journal_next(j);
394 }
395
396 if (r < 0) {
397 log_error("Failed to iterate through journal: %s", strerror(-r));
398 goto finish;
50f20cfd 399 }
87d2c1ff 400
fafb6ecc 401 have_pager = !arg_no_pager && !arg_follow && pager_open();
0d43c694
LP
402
403 if (arg_output == OUTPUT_JSON) {
72f59706 404 fputc('[', stdout);
0d43c694
LP
405 fflush(stdout);
406 }
72f59706 407
50f20cfd 408 for (;;) {
0d43c694 409 for (;;) {
14a65d65 410 sd_id128_t boot_id;
92a1fd9e
ZJS
411 int flags = (arg_show_all*OUTPUT_SHOW_ALL |
412 have_pager*OUTPUT_FULL_WIDTH);
14a65d65 413
6f003b43
LP
414 if (need_seek) {
415 r = sd_journal_next(j);
416 if (r < 0) {
417 log_error("Failed to iterate through journal: %s", strerror(-r));
418 goto finish;
419 }
0d43c694
LP
420 }
421
422 if (r == 0)
423 break;
424
14a65d65
LP
425 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
426 if (r >= 0) {
427 if (previous_boot_id_valid &&
428 !sd_id128_equal(boot_id, previous_boot_id))
429 printf(ANSI_HIGHLIGHT_ON "----- Reboot -----" ANSI_HIGHLIGHT_OFF "\n");
430
431 previous_boot_id = boot_id;
432 previous_boot_id_valid = true;
433 }
434
72f59706 435 line ++;
50f20cfd 436
92a1fd9e 437 r = output_journal(j, arg_output, line, 0, flags);
72f59706
LP
438 if (r < 0)
439 goto finish;
6f003b43
LP
440
441 need_seek = true;
87d2c1ff
LP
442 }
443
50f20cfd
LP
444 if (!arg_follow)
445 break;
446
e02d1cf7 447 r = sd_journal_wait(j, (uint64_t) -1);
50f20cfd 448 if (r < 0) {
e02d1cf7 449 log_error("Couldn't wait for log event: %s", strerror(-r));
50f20cfd
LP
450 goto finish;
451 }
de190aef 452 }
87d2c1ff 453
72f59706
LP
454 if (arg_output == OUTPUT_JSON)
455 fputs("\n]\n", stdout);
456
87d2c1ff 457finish:
3fbf9cbb
LP
458 if (j)
459 sd_journal_close(j);
87d2c1ff 460
0d43c694
LP
461 pager_close();
462
3fbf9cbb 463 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 464}