]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
update TODO
[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"
57 " -a --all Show all properties, including long and unprintable\n"
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;
151
0d43c694
LP
152 case '?':
153 return -EINVAL;
154
155 default:
156 log_error("Unknown option code %c", c);
157 return -EINVAL;
158 }
159 }
160
62f21ec9 161 if (arg_follow && !arg_no_tail && arg_lines < 0)
e91af489
LP
162 arg_lines = 10;
163
0d43c694
LP
164 return 1;
165}
166
39f7f5c1 167static int generate_new_id128(void) {
55ee336c
LP
168 sd_id128_t id;
169 int r;
170 unsigned i;
171
172 r = sd_id128_randomize(&id);
173 if (r < 0) {
174 log_error("Failed to generate ID: %s", strerror(-r));
175 return r;
176 }
177
178 printf("As string:\n"
179 SD_ID128_FORMAT_STR "\n\n"
180 "As UUID:\n"
181 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
182 "As macro:\n"
183 "#define MESSAGE_XYZ SD_ID128_MAKE(",
184 SD_ID128_FORMAT_VAL(id),
185 SD_ID128_FORMAT_VAL(id));
186
187 for (i = 0; i < 16; i++)
188 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
189
190 fputs(")\n", stdout);
191
192 return 0;
193}
194
87d2c1ff 195int main(int argc, char *argv[]) {
50f20cfd 196 int r, i, fd;
3fbf9cbb 197 sd_journal *j = NULL;
72f59706 198 unsigned line = 0;
6f003b43 199 bool need_seek = false;
3fbf9cbb 200
87d2c1ff
LP
201 log_parse_environment();
202 log_open();
203
0d43c694
LP
204 r = parse_argv(argc, argv);
205 if (r <= 0)
206 goto finish;
207
39f7f5c1
LP
208 if (arg_new_id128) {
209 r = generate_new_id128();
55ee336c
LP
210 goto finish;
211 }
212
4f4d6a70 213#ifdef HAVE_ACL
43673799
LP
214 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
215 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off.");
4f4d6a70 216#endif
43673799 217
cf244689 218 r = sd_journal_open(&j, 0);
87d2c1ff
LP
219 if (r < 0) {
220 log_error("Failed to open journal: %s", strerror(-r));
3fbf9cbb 221 goto finish;
87d2c1ff
LP
222 }
223
0d43c694 224 for (i = optind; i < argc; i++) {
de7b95cd
LP
225 r = sd_journal_add_match(j, argv[i], strlen(argv[i]));
226 if (r < 0) {
227 log_error("Failed to add match: %s", strerror(-r));
228 goto finish;
229 }
230 }
231
50f20cfd
LP
232 fd = sd_journal_get_fd(j);
233 if (fd < 0) {
234 log_error("Failed to get wakeup fd: %s", strerror(-fd));
235 goto finish;
236 }
8725d60a 237
2100675e
LP
238 if (arg_lines >= 0) {
239 r = sd_journal_seek_tail(j);
240 if (r < 0) {
241 log_error("Failed to seek to tail: %s", strerror(-r));
242 goto finish;
243 }
244
245 r = sd_journal_previous_skip(j, arg_lines);
2100675e
LP
246 } else {
247 r = sd_journal_seek_head(j);
248 if (r < 0) {
249 log_error("Failed to seek to head: %s", strerror(-r));
250 goto finish;
251 }
6f003b43
LP
252
253 r = sd_journal_next(j);
254 }
255
256 if (r < 0) {
257 log_error("Failed to iterate through journal: %s", strerror(-r));
258 goto finish;
50f20cfd 259 }
87d2c1ff 260
0d43c694
LP
261 if (!arg_no_pager && !arg_follow) {
262 columns();
263 pager_open();
264 }
265
266 if (arg_output == OUTPUT_JSON) {
72f59706 267 fputc('[', stdout);
0d43c694
LP
268 fflush(stdout);
269 }
72f59706 270
50f20cfd 271 for (;;) {
0d43c694 272 for (;;) {
6f003b43
LP
273 if (need_seek) {
274 r = sd_journal_next(j);
275 if (r < 0) {
276 log_error("Failed to iterate through journal: %s", strerror(-r));
277 goto finish;
278 }
0d43c694
LP
279 }
280
281 if (r == 0)
282 break;
283
72f59706 284 line ++;
50f20cfd 285
86aa7ba4 286 r = output_journal(j, arg_output, line, arg_show_all);
72f59706
LP
287 if (r < 0)
288 goto finish;
6f003b43
LP
289
290 need_seek = true;
87d2c1ff
LP
291 }
292
50f20cfd
LP
293 if (!arg_follow)
294 break;
295
8f2d43a0 296 r = fd_wait_for_event(fd, POLLIN, (usec_t) -1);
df50185b
LP
297 if (r < 0) {
298 log_error("Couldn't wait for event: %s", strerror(-r));
50f20cfd
LP
299 goto finish;
300 }
8725d60a 301
50f20cfd
LP
302 r = sd_journal_process(j);
303 if (r < 0) {
304 log_error("Failed to process: %s", strerror(-r));
305 goto finish;
306 }
de190aef 307 }
87d2c1ff 308
72f59706
LP
309 if (arg_output == OUTPUT_JSON)
310 fputs("\n]\n", stdout);
311
87d2c1ff 312finish:
3fbf9cbb
LP
313 if (j)
314 sd_journal_close(j);
87d2c1ff 315
0d43c694
LP
316 pager_close();
317
3fbf9cbb 318 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 319}