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