]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
journalctl: fix counting of -n parameter
[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
3fbf9cbb
LP
33#include "sd-journal.h"
34#include "log.h"
72f59706 35#include "util.h"
0d43c694
LP
36#include "build.h"
37#include "pager.h"
86aa7ba4 38#include "logs-show.h"
250d54b5 39
86aa7ba4 40static output_mode arg_output = OUTPUT_SHORT;
72f59706
LP
41
42static bool arg_follow = false;
43static bool arg_show_all = false;
0d43c694 44static bool arg_no_pager = false;
2100675e 45static int arg_lines = -1;
50f20cfd 46
0d43c694
LP
47static int help(void) {
48
49 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
50 "Send control commands to or query the login manager.\n\n"
51 " -h --help Show this help\n"
52 " --version Show package version\n"
53 " --no-pager Do not pipe output into a pager\n"
54 " -a --all Show all properties, including long and unprintable\n"
55 " -f --follow Follow journal\n"
2100675e 56 " -n --lines=INTEGER Lines to show\n"
0d43c694
LP
57 " -o --output=STRING Change output mode (short, verbose, export, json)\n",
58 program_invocation_short_name);
59
60 return 0;
61}
62
63static int parse_argv(int argc, char *argv[]) {
64
65 enum {
66 ARG_VERSION = 0x100,
67 ARG_NO_PAGER
68 };
69
70 static const struct option options[] = {
71 { "help", no_argument, NULL, 'h' },
72 { "version" , no_argument, NULL, ARG_VERSION },
73 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
74 { "follow", no_argument, NULL, 'f' },
75 { "output", required_argument, NULL, 'o' },
76 { "all", no_argument, NULL, 'a' },
2100675e 77 { "lines", required_argument, NULL, 'n' },
0d43c694
LP
78 { NULL, 0, NULL, 0 }
79 };
80
2100675e 81 int c, r;
0d43c694
LP
82
83 assert(argc >= 0);
84 assert(argv);
85
2100675e 86 while ((c = getopt_long(argc, argv, "hfo:an:", options, NULL)) >= 0) {
0d43c694
LP
87
88 switch (c) {
89
90 case 'h':
91 help();
92 return 0;
93
94 case ARG_VERSION:
95 puts(PACKAGE_STRING);
96 puts(DISTRIBUTION);
97 puts(SYSTEMD_FEATURES);
98 return 0;
99
100 case ARG_NO_PAGER:
101 arg_no_pager = true;
102 break;
103
104 case 'f':
105 arg_follow = true;
106 break;
107
108 case 'o':
109 if (streq(optarg, "short"))
110 arg_output = OUTPUT_SHORT;
111 else if (streq(optarg, "verbose"))
112 arg_output = OUTPUT_VERBOSE;
113 else if (streq(optarg, "export"))
114 arg_output = OUTPUT_EXPORT;
115 else if (streq(optarg, "json"))
116 arg_output = OUTPUT_JSON;
117 else {
118 log_error("Unknown output '%s'.", optarg);
119 return -EINVAL;
120 }
121 break;
122
123 case 'a':
124 arg_show_all = true;
125 break;
126
2100675e
LP
127 case 'n':
128 r = safe_atoi(optarg, &arg_lines);
129 if (r < 0) {
130 log_error("Failed to parse lines '%s'", optarg);
131 return -EINVAL;
132 }
133 break;
134
0d43c694
LP
135 case '?':
136 return -EINVAL;
137
138 default:
139 log_error("Unknown option code %c", c);
140 return -EINVAL;
141 }
142 }
143
144 return 1;
145}
146
87d2c1ff 147int main(int argc, char *argv[]) {
50f20cfd 148 int r, i, fd;
3fbf9cbb 149 sd_journal *j = NULL;
72f59706 150 unsigned line = 0;
6f003b43 151 bool need_seek = false;
3fbf9cbb 152
87d2c1ff
LP
153 log_parse_environment();
154 log_open();
155
0d43c694
LP
156 r = parse_argv(argc, argv);
157 if (r <= 0)
158 goto finish;
159
cf244689 160 r = sd_journal_open(&j, 0);
87d2c1ff
LP
161 if (r < 0) {
162 log_error("Failed to open journal: %s", strerror(-r));
3fbf9cbb 163 goto finish;
87d2c1ff
LP
164 }
165
0d43c694 166 for (i = optind; i < argc; i++) {
de7b95cd
LP
167 r = sd_journal_add_match(j, argv[i], strlen(argv[i]));
168 if (r < 0) {
169 log_error("Failed to add match: %s", strerror(-r));
170 goto finish;
171 }
172 }
173
50f20cfd
LP
174 fd = sd_journal_get_fd(j);
175 if (fd < 0) {
176 log_error("Failed to get wakeup fd: %s", strerror(-fd));
177 goto finish;
178 }
8725d60a 179
2100675e
LP
180 if (arg_lines >= 0) {
181 r = sd_journal_seek_tail(j);
182 if (r < 0) {
183 log_error("Failed to seek to tail: %s", strerror(-r));
184 goto finish;
185 }
186
187 r = sd_journal_previous_skip(j, arg_lines);
2100675e
LP
188 } else {
189 r = sd_journal_seek_head(j);
190 if (r < 0) {
191 log_error("Failed to seek to head: %s", strerror(-r));
192 goto finish;
193 }
6f003b43
LP
194
195 r = sd_journal_next(j);
196 }
197
198 if (r < 0) {
199 log_error("Failed to iterate through journal: %s", strerror(-r));
200 goto finish;
50f20cfd 201 }
87d2c1ff 202
0d43c694
LP
203 if (!arg_no_pager && !arg_follow) {
204 columns();
205 pager_open();
206 }
207
208 if (arg_output == OUTPUT_JSON) {
72f59706 209 fputc('[', stdout);
0d43c694
LP
210 fflush(stdout);
211 }
72f59706 212
50f20cfd
LP
213 for (;;) {
214 struct pollfd pollfd;
215
0d43c694 216 for (;;) {
6f003b43
LP
217 if (need_seek) {
218 r = sd_journal_next(j);
219 if (r < 0) {
220 log_error("Failed to iterate through journal: %s", strerror(-r));
221 goto finish;
222 }
0d43c694
LP
223 }
224
225 if (r == 0)
226 break;
227
72f59706 228 line ++;
50f20cfd 229
86aa7ba4 230 r = output_journal(j, arg_output, line, arg_show_all);
72f59706
LP
231 if (r < 0)
232 goto finish;
6f003b43
LP
233
234 need_seek = true;
87d2c1ff
LP
235 }
236
50f20cfd
LP
237 if (!arg_follow)
238 break;
239
240 zero(pollfd);
241 pollfd.fd = fd;
242 pollfd.events = POLLIN;
87d2c1ff 243
50f20cfd
LP
244 if (poll(&pollfd, 1, -1) < 0) {
245 if (errno == EINTR)
246 break;
c2373f84 247
50f20cfd
LP
248 log_error("poll(): %m");
249 r = -errno;
250 goto finish;
251 }
8725d60a 252
50f20cfd
LP
253 r = sd_journal_process(j);
254 if (r < 0) {
255 log_error("Failed to process: %s", strerror(-r));
256 goto finish;
257 }
de190aef 258 }
87d2c1ff 259
72f59706
LP
260 if (arg_output == OUTPUT_JSON)
261 fputs("\n]\n", stdout);
262
87d2c1ff 263finish:
3fbf9cbb
LP
264 if (j)
265 sd_journal_close(j);
87d2c1ff 266
0d43c694
LP
267 pager_close();
268
3fbf9cbb 269 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 270}