chiark / gitweb /
udev: do not selinux label files in /run/udev
[elogind.git] / src / journal / journalctl.c
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 Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 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   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser 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>
25 #include <string.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <sys/poll.h>
30 #include <time.h>
31 #include <getopt.h>
32 #include <sys/stat.h>
33
34 #include <systemd/sd-journal.h>
35
36 #include "log.h"
37 #include "util.h"
38 #include "path-util.h"
39 #include "build.h"
40 #include "pager.h"
41 #include "logs-show.h"
42
43 static OutputMode arg_output = OUTPUT_SHORT;
44 static bool arg_follow = false;
45 static bool arg_show_all = false;
46 static bool arg_no_pager = false;
47 static int arg_lines = -1;
48 static bool arg_no_tail = false;
49 static bool arg_new_id128 = false;
50 static bool arg_quiet = false;
51 static bool arg_local = false;
52
53 static int help(void) {
54
55         printf("%s [OPTIONS...] [MATCH]\n\n"
56                "Send control commands to or query the journal.\n\n"
57                "  -h --help           Show this help\n"
58                "     --version        Show package version\n"
59                "     --no-pager       Do not pipe output into a pager\n"
60                "  -a --all            Show all fields, including long and unprintable\n"
61                "  -f --follow         Follow journal\n"
62                "  -n --lines=INTEGER  Journal entries to show\n"
63                "     --no-tail        Show all lines, even in follow mode\n"
64                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
65                "                      verbose, export, json, cat)\n"
66                "  -q --quiet          Don't show privilege warning\n"
67                "     --new-id128      Generate a new 128 Bit id\n"
68                "  -l --local          Only local entries\n",
69                program_invocation_short_name);
70
71         return 0;
72 }
73
74 static int parse_argv(int argc, char *argv[]) {
75
76         enum {
77                 ARG_VERSION = 0x100,
78                 ARG_NO_PAGER,
79                 ARG_NO_TAIL,
80                 ARG_NEW_ID128
81         };
82
83         static const struct option options[] = {
84                 { "help",      no_argument,       NULL, 'h'           },
85                 { "version" ,  no_argument,       NULL, ARG_VERSION   },
86                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
87                 { "follow",    no_argument,       NULL, 'f'           },
88                 { "output",    required_argument, NULL, 'o'           },
89                 { "all",       no_argument,       NULL, 'a'           },
90                 { "lines",     required_argument, NULL, 'n'           },
91                 { "no-tail",   no_argument,       NULL, ARG_NO_TAIL   },
92                 { "new-id128", no_argument,       NULL, ARG_NEW_ID128 },
93                 { "quiet",     no_argument,       NULL, 'q'           },
94                 { "local",     no_argument,       NULL, 'l'           },
95                 { NULL,        0,                 NULL, 0             }
96         };
97
98         int c, r;
99
100         assert(argc >= 0);
101         assert(argv);
102
103         while ((c = getopt_long(argc, argv, "hfo:an:ql", options, NULL)) >= 0) {
104
105                 switch (c) {
106
107                 case 'h':
108                         help();
109                         return 0;
110
111                 case ARG_VERSION:
112                         puts(PACKAGE_STRING);
113                         puts(DISTRIBUTION);
114                         puts(SYSTEMD_FEATURES);
115                         return 0;
116
117                 case ARG_NO_PAGER:
118                         arg_no_pager = true;
119                         break;
120
121                 case 'f':
122                         arg_follow = true;
123                         break;
124
125                 case 'o':
126                         arg_output =  output_mode_from_string(optarg);
127                         if (arg_output < 0) {
128                                 log_error("Unknown output '%s'.", optarg);
129                                 return -EINVAL;
130                         }
131
132                         break;
133
134                 case 'a':
135                         arg_show_all = true;
136                         break;
137
138                 case 'n':
139                         r = safe_atoi(optarg, &arg_lines);
140                         if (r < 0 || arg_lines < 0) {
141                                 log_error("Failed to parse lines '%s'", optarg);
142                                 return -EINVAL;
143                         }
144                         break;
145
146                 case ARG_NO_TAIL:
147                         arg_no_tail = true;
148                         break;
149
150                 case ARG_NEW_ID128:
151                         arg_new_id128 = true;
152                         break;
153
154                 case 'q':
155                         arg_quiet = true;
156                         break;
157
158                 case 'l':
159                         arg_local = true;
160                         break;
161
162                 case '?':
163                         return -EINVAL;
164
165                 default:
166                         log_error("Unknown option code %c", c);
167                         return -EINVAL;
168                 }
169         }
170
171         if (arg_follow && !arg_no_tail && arg_lines < 0)
172                 arg_lines = 10;
173
174         return 1;
175 }
176
177 static int generate_new_id128(void) {
178         sd_id128_t id;
179         int r;
180         unsigned i;
181
182         r = sd_id128_randomize(&id);
183         if (r < 0) {
184                 log_error("Failed to generate ID: %s", strerror(-r));
185                 return r;
186         }
187
188         printf("As string:\n"
189                SD_ID128_FORMAT_STR "\n\n"
190                "As UUID:\n"
191                "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
192                "As macro:\n"
193               "#define MESSAGE_XYZ SD_ID128_MAKE(",
194                SD_ID128_FORMAT_VAL(id),
195                SD_ID128_FORMAT_VAL(id));
196
197         for (i = 0; i < 16; i++)
198                 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
199
200         fputs(")\n", stdout);
201
202         return 0;
203 }
204
205 int main(int argc, char *argv[]) {
206         int r, i, fd;
207         sd_journal *j = NULL;
208         unsigned line = 0;
209         bool need_seek = false;
210         struct stat st;
211
212         log_parse_environment();
213         log_open();
214
215         r = parse_argv(argc, argv);
216         if (r <= 0)
217                 goto finish;
218
219         if (arg_new_id128) {
220                 r = generate_new_id128();
221                 goto finish;
222         }
223
224 #ifdef HAVE_ACL
225         if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
226                 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off.");
227 #endif
228
229         r = sd_journal_open(&j, arg_local ? SD_JOURNAL_LOCAL_ONLY : 0);
230         if (r < 0) {
231                 log_error("Failed to open journal: %s", strerror(-r));
232                 goto finish;
233         }
234
235         for (i = optind; i < argc; i++) {
236                 if (path_is_absolute(argv[i])) {
237                         char *p = NULL;
238                         const char *path;
239
240                         p = canonicalize_file_name(argv[i]);
241                         path = p ? p : argv[i];
242
243                         if (stat(path, &st) < 0)  {
244                                 free(p);
245                                 log_error("Couldn't stat file: %m");
246                                 r = -errno;
247                                 goto finish;
248                         }
249
250                         if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
251                                 char *t;
252
253                                 t = strappend("_EXE=", path);
254                                 if (!t) {
255                                         free(p);
256                                         log_error("Out of memory");
257                                         goto finish;
258                                 }
259
260                                 r = sd_journal_add_match(j, t, strlen(t));
261                                 free(t);
262                         } else {
263                                 free(p);
264                                 log_error("File is not a regular file or is not executable: %s", argv[i]);
265                                 goto finish;
266                         }
267
268                         free(p);
269                 } else
270                         r = sd_journal_add_match(j, argv[i], strlen(argv[i]));
271
272                 if (r < 0) {
273                         log_error("Failed to add match: %s", strerror(-r));
274                         goto finish;
275                 }
276         }
277
278         fd = sd_journal_get_fd(j);
279         if (fd < 0) {
280                 log_error("Failed to get wakeup fd: %s", strerror(-fd));
281                 goto finish;
282         }
283
284         if (arg_lines >= 0) {
285                 r = sd_journal_seek_tail(j);
286                 if (r < 0) {
287                         log_error("Failed to seek to tail: %s", strerror(-r));
288                         goto finish;
289                 }
290
291                 r = sd_journal_previous_skip(j, arg_lines);
292         } else {
293                 r = sd_journal_seek_head(j);
294                 if (r < 0) {
295                         log_error("Failed to seek to head: %s", strerror(-r));
296                         goto finish;
297                 }
298
299                 r = sd_journal_next(j);
300         }
301
302         if (r < 0) {
303                 log_error("Failed to iterate through journal: %s", strerror(-r));
304                 goto finish;
305         }
306
307         if (!arg_no_pager && !arg_follow) {
308                 columns();
309                 pager_open();
310         }
311
312         if (arg_output == OUTPUT_JSON) {
313                 fputc('[', stdout);
314                 fflush(stdout);
315         }
316
317         for (;;) {
318                 for (;;) {
319                         if (need_seek) {
320                                 r = sd_journal_next(j);
321                                 if (r < 0) {
322                                         log_error("Failed to iterate through journal: %s", strerror(-r));
323                                         goto finish;
324                                 }
325                         }
326
327                         if (r == 0)
328                                 break;
329
330                         line ++;
331
332                         r = output_journal(j, arg_output, line, 0, arg_show_all);
333                         if (r < 0)
334                                 goto finish;
335
336                         need_seek = true;
337                 }
338
339                 if (!arg_follow)
340                         break;
341
342                 r = fd_wait_for_event(fd, POLLIN, (usec_t) -1);
343                 if (r < 0) {
344                         log_error("Couldn't wait for event: %s", strerror(-r));
345                         goto finish;
346                 }
347
348                 r = sd_journal_process(j);
349                 if (r < 0) {
350                         log_error("Failed to process: %s", strerror(-r));
351                         goto finish;
352                 }
353         }
354
355         if (arg_output == OUTPUT_JSON)
356                 fputs("\n]\n", stdout);
357
358 finish:
359         if (j)
360                 sd_journal_close(j);
361
362         pager_close();
363
364         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
365 }