]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
man: don't claim -f was short for --follow
[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
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
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
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
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>
87d2c1ff 32
81527be1
LP
33#include <systemd/sd-journal.h>
34
3fbf9cbb 35#include "log.h"
72f59706 36#include "util.h"
0d43c694
LP
37#include "build.h"
38#include "pager.h"
86aa7ba4 39#include "logs-show.h"
250d54b5 40
df50185b 41static OutputMode arg_output = OUTPUT_SHORT;
72f59706
LP
42static bool arg_follow = false;
43static bool arg_show_all = false;
0d43c694 44static bool arg_no_pager = false;
2100675e 45static int arg_lines = -1;
e91af489 46static bool arg_no_tail = false;
39f7f5c1 47static bool arg_new_id128 = false;
43673799 48static bool arg_quiet = false;
50f20cfd 49
0d43c694
LP
50static int help(void) {
51
52 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
df50185b 53 "Send control commands to or query the journal.\n\n"
0d43c694
LP
54 " -h --help Show this help\n"
55 " --version Show package version\n"
56 " --no-pager Do not pipe output into a pager\n"
2af777ba 57 " -a --all Show all fields, including long and unprintable\n"
0d43c694 58 " -f --follow Follow journal\n"
df50185b 59 " -n --lines=INTEGER Journal entries to show\n"
e91af489 60 " --no-tail Show all lines, even in follow mode\n"
d3f2bdbf
LP
61 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
62 " verbose, export, json, cat)\n"
43673799 63 " -q --quiet Don't show privilege warning\n"
39f7f5c1 64 " --new-id128 Generate a new 128 Bit id\n",
0d43c694
LP
65 program_invocation_short_name);
66
67 return 0;
68}
69
70static int parse_argv(int argc, char *argv[]) {
71
72 enum {
73 ARG_VERSION = 0x100,
e91af489 74 ARG_NO_PAGER,
55ee336c 75 ARG_NO_TAIL,
39f7f5c1 76 ARG_NEW_ID128
0d43c694
LP
77 };
78
79 static const struct option options[] = {
80 { "help", no_argument, NULL, 'h' },
81 { "version" , no_argument, NULL, ARG_VERSION },
82 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
83 { "follow", no_argument, NULL, 'f' },
84 { "output", required_argument, NULL, 'o' },
85 { "all", no_argument, NULL, 'a' },
2100675e 86 { "lines", required_argument, NULL, 'n' },
e91af489 87 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
39f7f5c1 88 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
43673799 89 { "quiet", no_argument, NULL, 'q' },
0d43c694
LP
90 { NULL, 0, NULL, 0 }
91 };
92
2100675e 93 int c, r;
0d43c694
LP
94
95 assert(argc >= 0);
96 assert(argv);
97
43673799 98 while ((c = getopt_long(argc, argv, "hfo:an:q", options, NULL)) >= 0) {
0d43c694
LP
99
100 switch (c) {
101
102 case 'h':
103 help();
104 return 0;
105
106 case ARG_VERSION:
107 puts(PACKAGE_STRING);
108 puts(DISTRIBUTION);
109 puts(SYSTEMD_FEATURES);
110 return 0;
111
112 case ARG_NO_PAGER:
113 arg_no_pager = true;
114 break;
115
116 case 'f':
117 arg_follow = true;
118 break;
119
120 case 'o':
df50185b
LP
121 arg_output = output_mode_from_string(optarg);
122 if (arg_output < 0) {
0d43c694
LP
123 log_error("Unknown output '%s'.", optarg);
124 return -EINVAL;
125 }
df50185b 126
0d43c694
LP
127 break;
128
129 case 'a':
130 arg_show_all = true;
131 break;
132
2100675e
LP
133 case 'n':
134 r = safe_atoi(optarg, &arg_lines);
e91af489 135 if (r < 0 || arg_lines < 0) {
2100675e
LP
136 log_error("Failed to parse lines '%s'", optarg);
137 return -EINVAL;
138 }
139 break;
140
e91af489
LP
141 case ARG_NO_TAIL:
142 arg_no_tail = true;
143 break;
144
39f7f5c1
LP
145 case ARG_NEW_ID128:
146 arg_new_id128 = true;
55ee336c
LP
147 break;
148
43673799
LP
149 case 'q':
150 arg_quiet = true;
490e567d 151 break;
43673799 152
0d43c694
LP
153 case '?':
154 return -EINVAL;
155
156 default:
157 log_error("Unknown option code %c", c);
158 return -EINVAL;
159 }
160 }
161
62f21ec9 162 if (arg_follow && !arg_no_tail && arg_lines < 0)
e91af489
LP
163 arg_lines = 10;
164
0d43c694
LP
165 return 1;
166}
167
39f7f5c1 168static int generate_new_id128(void) {
55ee336c
LP
169 sd_id128_t id;
170 int r;
171 unsigned i;
172
173 r = sd_id128_randomize(&id);
174 if (r < 0) {
175 log_error("Failed to generate ID: %s", strerror(-r));
176 return r;
177 }
178
179 printf("As string:\n"
180 SD_ID128_FORMAT_STR "\n\n"
181 "As UUID:\n"
182 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
183 "As macro:\n"
184 "#define MESSAGE_XYZ SD_ID128_MAKE(",
185 SD_ID128_FORMAT_VAL(id),
186 SD_ID128_FORMAT_VAL(id));
187
188 for (i = 0; i < 16; i++)
189 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
190
191 fputs(")\n", stdout);
192
193 return 0;
194}
195
87d2c1ff 196int main(int argc, char *argv[]) {
50f20cfd 197 int r, i, fd;
3fbf9cbb 198 sd_journal *j = NULL;
72f59706 199 unsigned line = 0;
6f003b43 200 bool need_seek = false;
3fbf9cbb 201
87d2c1ff
LP
202 log_parse_environment();
203 log_open();
204
0d43c694
LP
205 r = parse_argv(argc, argv);
206 if (r <= 0)
207 goto finish;
208
39f7f5c1
LP
209 if (arg_new_id128) {
210 r = generate_new_id128();
55ee336c
LP
211 goto finish;
212 }
213
4f4d6a70 214#ifdef HAVE_ACL
43673799
LP
215 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
216 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off.");
4f4d6a70 217#endif
43673799 218
cf244689 219 r = sd_journal_open(&j, 0);
87d2c1ff
LP
220 if (r < 0) {
221 log_error("Failed to open journal: %s", strerror(-r));
3fbf9cbb 222 goto finish;
87d2c1ff
LP
223 }
224
0d43c694 225 for (i = optind; i < argc; i++) {
de7b95cd
LP
226 r = sd_journal_add_match(j, argv[i], strlen(argv[i]));
227 if (r < 0) {
228 log_error("Failed to add match: %s", strerror(-r));
229 goto finish;
230 }
231 }
232
50f20cfd
LP
233 fd = sd_journal_get_fd(j);
234 if (fd < 0) {
235 log_error("Failed to get wakeup fd: %s", strerror(-fd));
236 goto finish;
237 }
8725d60a 238
2100675e
LP
239 if (arg_lines >= 0) {
240 r = sd_journal_seek_tail(j);
241 if (r < 0) {
242 log_error("Failed to seek to tail: %s", strerror(-r));
243 goto finish;
244 }
245
246 r = sd_journal_previous_skip(j, arg_lines);
2100675e
LP
247 } else {
248 r = sd_journal_seek_head(j);
249 if (r < 0) {
250 log_error("Failed to seek to head: %s", strerror(-r));
251 goto finish;
252 }
6f003b43
LP
253
254 r = sd_journal_next(j);
255 }
256
257 if (r < 0) {
258 log_error("Failed to iterate through journal: %s", strerror(-r));
259 goto finish;
50f20cfd 260 }
87d2c1ff 261
0d43c694
LP
262 if (!arg_no_pager && !arg_follow) {
263 columns();
264 pager_open();
265 }
266
267 if (arg_output == OUTPUT_JSON) {
72f59706 268 fputc('[', stdout);
0d43c694
LP
269 fflush(stdout);
270 }
72f59706 271
50f20cfd 272 for (;;) {
0d43c694 273 for (;;) {
6f003b43
LP
274 if (need_seek) {
275 r = sd_journal_next(j);
276 if (r < 0) {
277 log_error("Failed to iterate through journal: %s", strerror(-r));
278 goto finish;
279 }
0d43c694
LP
280 }
281
282 if (r == 0)
283 break;
284
72f59706 285 line ++;
50f20cfd 286
34a35ece 287 r = output_journal(j, arg_output, line, 0, arg_show_all);
72f59706
LP
288 if (r < 0)
289 goto finish;
6f003b43
LP
290
291 need_seek = true;
87d2c1ff
LP
292 }
293
50f20cfd
LP
294 if (!arg_follow)
295 break;
296
8f2d43a0 297 r = fd_wait_for_event(fd, POLLIN, (usec_t) -1);
df50185b
LP
298 if (r < 0) {
299 log_error("Couldn't wait for event: %s", strerror(-r));
50f20cfd
LP
300 goto finish;
301 }
8725d60a 302
50f20cfd
LP
303 r = sd_journal_process(j);
304 if (r < 0) {
305 log_error("Failed to process: %s", strerror(-r));
306 goto finish;
307 }
de190aef 308 }
87d2c1ff 309
72f59706
LP
310 if (arg_output == OUTPUT_JSON)
311 fputs("\n]\n", stdout);
312
87d2c1ff 313finish:
3fbf9cbb
LP
314 if (j)
315 sd_journal_close(j);
87d2c1ff 316
0d43c694
LP
317 pager_close();
318
3fbf9cbb 319 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 320}