File: | build-scan/../src/journal/journalctl.c |
Warning: | line 1126, column 17 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <errno(*__errno_location ()).h> | |||
4 | #include <fcntl.h> | |||
5 | #include <fnmatch.h> | |||
6 | #include <getopt.h> | |||
7 | #include <linux1/fs.h> | |||
8 | #include <locale.h> | |||
9 | #include <poll.h> | |||
10 | #include <signal.h> | |||
11 | #include <stddef.h> | |||
12 | #include <stdio.h> | |||
13 | #include <stdlib.h> | |||
14 | #include <string.h> | |||
15 | #include <sys/inotify.h> | |||
16 | #include <sys/stat.h> | |||
17 | #include <unistd.h> | |||
18 | ||||
19 | #if HAVE_PCRE21 | |||
20 | # define PCRE2_CODE_UNIT_WIDTH8 8 | |||
21 | # include <pcre2.h> | |||
22 | #endif | |||
23 | ||||
24 | #include "sd-bus.h" | |||
25 | #include "sd-journal.h" | |||
26 | ||||
27 | #include "acl-util.h" | |||
28 | #include "alloc-util.h" | |||
29 | #include "bus-error.h" | |||
30 | #include "bus-util.h" | |||
31 | #include "catalog.h" | |||
32 | #include "chattr-util.h" | |||
33 | #include "fd-util.h" | |||
34 | #include "fileio.h" | |||
35 | #include "fs-util.h" | |||
36 | #include "fsprg.h" | |||
37 | #include "glob-util.h" | |||
38 | #include "hostname-util.h" | |||
39 | #include "io-util.h" | |||
40 | #include "journal-def.h" | |||
41 | #include "journal-internal.h" | |||
42 | #include "journal-qrcode.h" | |||
43 | #include "journal-util.h" | |||
44 | #include "journal-vacuum.h" | |||
45 | #include "journal-verify.h" | |||
46 | #include "locale-util.h" | |||
47 | #include "log.h" | |||
48 | #include "logs-show.h" | |||
49 | #include "mkdir.h" | |||
50 | #include "pager.h" | |||
51 | #include "parse-util.h" | |||
52 | #include "path-util.h" | |||
53 | #include "rlimit-util.h" | |||
54 | #include "set.h" | |||
55 | #include "sigbus.h" | |||
56 | #include "string-table.h" | |||
57 | #include "strv.h" | |||
58 | #include "syslog-util.h" | |||
59 | #include "terminal-util.h" | |||
60 | #include "udev-util.h" | |||
61 | #include "udev.h" | |||
62 | #include "unit-name.h" | |||
63 | #include "user-util.h" | |||
64 | ||||
65 | #define DEFAULT_FSS_INTERVAL_USEC(15*((usec_t) (60ULL*((usec_t) 1000000ULL)))) (15*USEC_PER_MINUTE((usec_t) (60ULL*((usec_t) 1000000ULL)))) | |||
66 | ||||
67 | #define PROCESS_INOTIFY_INTERVAL1024 1024 /* Every 1,024 messages processed */ | |||
68 | ||||
69 | #if HAVE_PCRE21 | |||
70 | DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data*, pcre2_match_data_free)static inline void pcre2_match_data_freep(pcre2_match_data_8* *p) { if (*p) pcre2_match_data_free_8(*p); }; | |||
71 | DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code*, pcre2_code_free)static inline void pcre2_code_freep(pcre2_code_8* *p) { if (* p) pcre2_code_free_8(*p); }; | |||
72 | ||||
73 | static int pattern_compile(const char *pattern, unsigned flags, pcre2_codepcre2_code_8 **out) { | |||
74 | int errorcode, r; | |||
75 | PCRE2_SIZEsize_t erroroffset; | |||
76 | pcre2_codepcre2_code_8 *p; | |||
77 | ||||
78 | p = pcre2_compilepcre2_compile_8((PCRE2_SPTR8) pattern, | |||
79 | PCRE2_ZERO_TERMINATED(~(size_t)0), flags, &errorcode, &erroroffset, NULL((void*)0)); | |||
80 | if (!p) { | |||
81 | unsigned char buf[LINE_MAX2048]; | |||
82 | ||||
83 | r = pcre2_get_error_messagepcre2_get_error_message_8(errorcode, buf, sizeof buf); | |||
84 | ||||
85 | log_error("Bad pattern \"%s\": %s",({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 87, __func__, "Bad pattern \"%s\": %s" , pattern, r < 0 ? "unknown error" : (char*) buf) : -abs(_e ); }) | |||
86 | pattern,({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 87, __func__, "Bad pattern \"%s\": %s" , pattern, r < 0 ? "unknown error" : (char*) buf) : -abs(_e ); }) | |||
87 | r < 0 ? "unknown error" : (char*) buf)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 87, __func__, "Bad pattern \"%s\": %s" , pattern, r < 0 ? "unknown error" : (char*) buf) : -abs(_e ); }); | |||
88 | return -EINVAL22; | |||
89 | } | |||
90 | ||||
91 | *out = p; | |||
92 | return 0; | |||
93 | } | |||
94 | ||||
95 | #endif | |||
96 | ||||
97 | enum { | |||
98 | /* Special values for arg_lines */ | |||
99 | ARG_LINES_DEFAULT = -2, | |||
100 | ARG_LINES_ALL = -1, | |||
101 | }; | |||
102 | ||||
103 | static OutputMode arg_output = OUTPUT_SHORT; | |||
104 | static bool_Bool arg_utc = false0; | |||
105 | static bool_Bool arg_pager_end = false0; | |||
106 | static bool_Bool arg_follow = false0; | |||
107 | static bool_Bool arg_full = true1; | |||
108 | static bool_Bool arg_all = false0; | |||
109 | static bool_Bool arg_no_pager = false0; | |||
110 | static int arg_lines = ARG_LINES_DEFAULT; | |||
111 | static bool_Bool arg_no_tail = false0; | |||
112 | static bool_Bool arg_quiet = false0; | |||
113 | static bool_Bool arg_merge = false0; | |||
114 | static bool_Bool arg_boot = false0; | |||
115 | static sd_id128_t arg_boot_id = {}; | |||
116 | static int arg_boot_offset = 0; | |||
117 | static bool_Bool arg_dmesg = false0; | |||
118 | static bool_Bool arg_no_hostname = false0; | |||
119 | static const char *arg_cursor = NULL((void*)0); | |||
120 | static const char *arg_after_cursor = NULL((void*)0); | |||
121 | static bool_Bool arg_show_cursor = false0; | |||
122 | static const char *arg_directory = NULL((void*)0); | |||
123 | static char **arg_file = NULL((void*)0); | |||
124 | static bool_Bool arg_file_stdin = false0; | |||
125 | static int arg_priorities = 0xFF; | |||
126 | static char *arg_verify_key = NULL((void*)0); | |||
127 | #if HAVE_GCRYPT1 | |||
128 | static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC(15*((usec_t) (60ULL*((usec_t) 1000000ULL)))); | |||
129 | static bool_Bool arg_force = false0; | |||
130 | #endif | |||
131 | static usec_t arg_since, arg_until; | |||
132 | static bool_Bool arg_since_set = false0, arg_until_set = false0; | |||
133 | static char **arg_syslog_identifier = NULL((void*)0); | |||
134 | static char **arg_system_units = NULL((void*)0); | |||
135 | static char **arg_user_units = NULL((void*)0); | |||
136 | static const char *arg_field = NULL((void*)0); | |||
137 | static bool_Bool arg_catalog = false0; | |||
138 | static bool_Bool arg_reverse = false0; | |||
139 | static int arg_journal_type = 0; | |||
140 | static char *arg_root = NULL((void*)0); | |||
141 | static const char *arg_machine = NULL((void*)0); | |||
142 | static uint64_t arg_vacuum_size = 0; | |||
143 | static uint64_t arg_vacuum_n_files = 0; | |||
144 | static usec_t arg_vacuum_time = 0; | |||
145 | static char **arg_output_fields = NULL((void*)0); | |||
146 | ||||
147 | #if HAVE_PCRE21 | |||
148 | static const char *arg_pattern = NULL((void*)0); | |||
149 | static pcre2_codepcre2_code_8 *arg_compiled_pattern = NULL((void*)0); | |||
150 | static int arg_case_sensitive = -1; /* -1 means be smart */ | |||
151 | #endif | |||
152 | ||||
153 | static enum { | |||
154 | ACTION_SHOW, | |||
155 | ACTION_NEW_ID128, | |||
156 | ACTION_PRINT_HEADER, | |||
157 | ACTION_SETUP_KEYS, | |||
158 | ACTION_VERIFY, | |||
159 | ACTION_DISK_USAGE, | |||
160 | ACTION_LIST_CATALOG, | |||
161 | ACTION_DUMP_CATALOG, | |||
162 | ACTION_UPDATE_CATALOG, | |||
163 | ACTION_LIST_BOOTS, | |||
164 | ACTION_FLUSH, | |||
165 | ACTION_SYNC, | |||
166 | ACTION_ROTATE, | |||
167 | ACTION_VACUUM, | |||
168 | ACTION_LIST_FIELDS, | |||
169 | ACTION_LIST_FIELD_NAMES, | |||
170 | } arg_action = ACTION_SHOW; | |||
171 | ||||
172 | typedef struct BootId { | |||
173 | sd_id128_t id; | |||
174 | uint64_t first; | |||
175 | uint64_t last; | |||
176 | LIST_FIELDS(struct BootId, boot_list)struct BootId *boot_list_next, *boot_list_prev; | |||
177 | } BootId; | |||
178 | ||||
179 | static int add_matches_for_device(sd_journal *j, const char *devpath) { | |||
180 | _cleanup_(udev_unrefp)__attribute__((cleanup(udev_unrefp))) struct udev *udev = NULL((void*)0); | |||
181 | _cleanup_(udev_device_unrefp)__attribute__((cleanup(udev_device_unrefp))) struct udev_device *device = NULL((void*)0); | |||
182 | struct udev_device *d = NULL((void*)0); | |||
183 | struct stat st; | |||
184 | int r; | |||
185 | ||||
186 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/journal/journalctl.c", 186 , __PRETTY_FUNCTION__); } while (0); | |||
187 | assert(devpath)do { if ((__builtin_expect(!!(!(devpath)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("devpath"), "../src/journal/journalctl.c" , 187, __PRETTY_FUNCTION__); } while (0); | |||
188 | ||||
189 | if (!path_startswith(devpath, "/dev/")) { | |||
190 | log_error("Devpath does not start with /dev/")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 190, __func__, "Devpath does not start with /dev/" ) : -abs(_e); }); | |||
191 | return -EINVAL22; | |||
192 | } | |||
193 | ||||
194 | udev = udev_new(); | |||
195 | if (!udev) | |||
196 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 196, __func__); | |||
197 | ||||
198 | if (stat(devpath, &st) < 0) | |||
199 | return log_error_errno(errno, "Couldn't stat file: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 199, __func__ , "Couldn't stat file: %m") : -abs(_e); }); | |||
200 | ||||
201 | r = udev_device_new_from_stat_rdev(udev, &st, &device); | |||
202 | if (r < 0) | |||
203 | return log_error_errno(r, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 203, __func__, "Failed to get udev device from devnum %u:%u: %m" , gnu_dev_major (st.st_rdev), gnu_dev_minor (st.st_rdev)) : - abs(_e); }); | |||
204 | ||||
205 | d = device; | |||
206 | while (d) { | |||
207 | _cleanup_free___attribute__((cleanup(freep))) char *match = NULL((void*)0); | |||
208 | const char *subsys, *sysname, *devnode; | |||
209 | ||||
210 | subsys = udev_device_get_subsystem(d); | |||
211 | if (!subsys) { | |||
212 | d = udev_device_get_parent(d); | |||
213 | continue; | |||
214 | } | |||
215 | ||||
216 | sysname = udev_device_get_sysname(d); | |||
217 | if (!sysname) { | |||
218 | d = udev_device_get_parent(d); | |||
219 | continue; | |||
220 | } | |||
221 | ||||
222 | match = strjoin("_KERNEL_DEVICE=+", subsys, ":", sysname)strjoin_real(("_KERNEL_DEVICE=+"), subsys, ":", sysname, ((void *)0)); | |||
223 | if (!match) | |||
224 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 224, __func__); | |||
225 | ||||
226 | r = sd_journal_add_match(j, match, 0); | |||
227 | if (r < 0) | |||
228 | return log_error_errno(r, "Failed to add match: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 228, __func__, "Failed to add match: %m" ) : -abs(_e); }); | |||
229 | ||||
230 | devnode = udev_device_get_devnode(d); | |||
231 | if (devnode) { | |||
232 | _cleanup_free___attribute__((cleanup(freep))) char *match1 = NULL((void*)0); | |||
233 | ||||
234 | r = stat(devnode, &st); | |||
235 | if (r < 0) | |||
236 | return log_error_errno(r, "Failed to stat() device node \"%s\": %m", devnode)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 236, __func__, "Failed to stat() device node \"%s\": %m" , devnode) : -abs(_e); }); | |||
237 | ||||
238 | r = asprintf(&match1, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st.st_mode)((((st.st_mode)) & 0170000) == (0060000)) ? 'b' : 'c', major(st.st_rdev)gnu_dev_major (st.st_rdev), minor(st.st_rdev)gnu_dev_minor (st.st_rdev)); | |||
239 | if (r < 0) | |||
240 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 240, __func__); | |||
241 | ||||
242 | r = sd_journal_add_match(j, match1, 0); | |||
243 | if (r < 0) | |||
244 | return log_error_errno(r, "Failed to add match: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 244, __func__, "Failed to add match: %m" ) : -abs(_e); }); | |||
245 | } | |||
246 | ||||
247 | d = udev_device_get_parent(d); | |||
248 | } | |||
249 | ||||
250 | r = add_match_this_boot(j, arg_machine); | |||
251 | if (r < 0) | |||
252 | return log_error_errno(r, "Failed to add match for the current boot: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 252, __func__, "Failed to add match for the current boot: %m" ) : -abs(_e); }); | |||
253 | ||||
254 | return 0; | |||
255 | } | |||
256 | ||||
257 | static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) { | |||
258 | ||||
259 | if (arg_utc) | |||
260 | return format_timestamp_utc(buf, l, t); | |||
261 | ||||
262 | return format_timestamp(buf, l, t); | |||
263 | } | |||
264 | ||||
265 | static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset) { | |||
266 | sd_id128_t id = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }}); | |||
267 | int off = 0, r; | |||
268 | ||||
269 | if (strlen(x) >= 32) { | |||
270 | char *t; | |||
271 | ||||
272 | t = strndupa(x, 32)(__extension__ ({ const char *__old = (x); size_t __len = strnlen (__old, (32)); char *__new = (char *) __builtin_alloca (__len + 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len ); })); | |||
273 | r = sd_id128_from_string(t, &id); | |||
274 | if (r >= 0) | |||
275 | x += 32; | |||
276 | ||||
277 | if (!IN_SET(*x, 0, '-', '+')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){0, '-', '+'})/sizeof(int)]; switch(*x) { case 0: case '-': case '+': _found = 1; break; default: break ; } _found; })) | |||
278 | return -EINVAL22; | |||
279 | ||||
280 | if (*x != 0) { | |||
281 | r = safe_atoi(x, &off); | |||
282 | if (r < 0) | |||
283 | return r; | |||
284 | } | |||
285 | } else { | |||
286 | r = safe_atoi(x, &off); | |||
287 | if (r < 0) | |||
288 | return r; | |||
289 | } | |||
290 | ||||
291 | if (boot_id) | |||
292 | *boot_id = id; | |||
293 | ||||
294 | if (offset) | |||
295 | *offset = off; | |||
296 | ||||
297 | return 0; | |||
298 | } | |||
299 | ||||
300 | static void help(void) { | |||
301 | ||||
302 | (void) pager_open(arg_no_pager, arg_pager_end); | |||
303 | ||||
304 | printf("%s [OPTIONS...] [MATCHES...]\n\n" | |||
305 | "Query the journal.\n\n" | |||
306 | "Options:\n" | |||
307 | " --system Show the system journal\n" | |||
308 | " --user Show the user journal for the current user\n" | |||
309 | " -M --machine=CONTAINER Operate on local container\n" | |||
310 | " -S --since=DATE Show entries not older than the specified date\n" | |||
311 | " -U --until=DATE Show entries not newer than the specified date\n" | |||
312 | " -c --cursor=CURSOR Show entries starting at the specified cursor\n" | |||
313 | " --after-cursor=CURSOR Show entries after the specified cursor\n" | |||
314 | " --show-cursor Print the cursor after all the entries\n" | |||
315 | " -b --boot[=ID] Show current boot or the specified boot\n" | |||
316 | " --list-boots Show terse information about recorded boots\n" | |||
317 | " -k --dmesg Show kernel message log from the current boot\n" | |||
318 | " -u --unit=UNIT Show logs from the specified unit\n" | |||
319 | " --user-unit=UNIT Show logs from the specified user unit\n" | |||
320 | " -t --identifier=STRING Show entries with the specified syslog identifier\n" | |||
321 | " -p --priority=RANGE Show entries with the specified priority\n" | |||
322 | " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n" | |||
323 | " --case-sensitive[=BOOL] Force case sensitive or insenstive matching\n" | |||
324 | " -e --pager-end Immediately jump to the end in the pager\n" | |||
325 | " -f --follow Follow the journal\n" | |||
326 | " -n --lines[=INTEGER] Number of journal entries to show\n" | |||
327 | " --no-tail Show all lines, even in follow mode\n" | |||
328 | " -r --reverse Show the newest entries first\n" | |||
329 | " -o --output=STRING Change journal output mode (short, short-precise,\n" | |||
330 | " short-iso, short-iso-precise, short-full,\n" | |||
331 | " short-monotonic, short-unix, verbose, export,\n" | |||
332 | " json, json-pretty, json-sse, cat, with-unit)\n" | |||
333 | " --output-fields=LIST Select fields to print in verbose/export/json modes\n" | |||
334 | " --utc Express time in Coordinated Universal Time (UTC)\n" | |||
335 | " -x --catalog Add message explanations where available\n" | |||
336 | " --no-full Ellipsize fields\n" | |||
337 | " -a --all Show all fields, including long and unprintable\n" | |||
338 | " -q --quiet Do not show info messages and privilege warning\n" | |||
339 | " --no-pager Do not pipe output into a pager\n" | |||
340 | " --no-hostname Suppress output of hostname field\n" | |||
341 | " -m --merge Show entries from all available journals\n" | |||
342 | " -D --directory=PATH Show journal files from directory\n" | |||
343 | " --file=PATH Show journal file\n" | |||
344 | " --root=ROOT Operate on files below a root directory\n" | |||
345 | #if HAVE_GCRYPT1 | |||
346 | " --interval=TIME Time interval for changing the FSS sealing key\n" | |||
347 | " --verify-key=KEY Specify FSS verification key\n" | |||
348 | " --force Override of the FSS key pair with --setup-keys\n" | |||
349 | #endif | |||
350 | "\nCommands:\n" | |||
351 | " -h --help Show this help text\n" | |||
352 | " --version Show package version\n" | |||
353 | " -N --fields List all field names currently used\n" | |||
354 | " -F --field=FIELD List all values that a specified field takes\n" | |||
355 | " --disk-usage Show total disk usage of all journal files\n" | |||
356 | " --vacuum-size=BYTES Reduce disk usage below specified size\n" | |||
357 | " --vacuum-files=INT Leave only the specified number of journal files\n" | |||
358 | " --vacuum-time=TIME Remove journal files older than specified time\n" | |||
359 | " --verify Verify journal file consistency\n" | |||
360 | " --sync Synchronize unwritten journal messages to disk\n" | |||
361 | " --flush Flush all journal data from /run into /var\n" | |||
362 | " --rotate Request immediate rotation of the journal files\n" | |||
363 | " --header Show journal header information\n" | |||
364 | " --list-catalog Show all message IDs in the catalog\n" | |||
365 | " --dump-catalog Show entries in the message catalog\n" | |||
366 | " --update-catalog Update the message catalog database\n" | |||
367 | " --new-id128 Generate a new 128-bit ID\n" | |||
368 | #if HAVE_GCRYPT1 | |||
369 | " --setup-keys Generate a new FSS key pair\n" | |||
370 | #endif | |||
371 | , program_invocation_short_name); | |||
372 | } | |||
373 | ||||
374 | static int parse_argv(int argc, char *argv[]) { | |||
375 | ||||
376 | enum { | |||
377 | ARG_VERSION = 0x100, | |||
378 | ARG_NO_PAGER, | |||
379 | ARG_NO_FULL, | |||
380 | ARG_NO_TAIL, | |||
381 | ARG_NEW_ID128, | |||
382 | ARG_THIS_BOOT, | |||
383 | ARG_LIST_BOOTS, | |||
384 | ARG_USER, | |||
385 | ARG_SYSTEM, | |||
386 | ARG_ROOT, | |||
387 | ARG_HEADER, | |||
388 | ARG_SETUP_KEYS, | |||
389 | ARG_FILE, | |||
390 | ARG_INTERVAL, | |||
391 | ARG_VERIFY, | |||
392 | ARG_VERIFY_KEY, | |||
393 | ARG_DISK_USAGE, | |||
394 | ARG_AFTER_CURSOR, | |||
395 | ARG_SHOW_CURSOR, | |||
396 | ARG_USER_UNIT, | |||
397 | ARG_LIST_CATALOG, | |||
398 | ARG_DUMP_CATALOG, | |||
399 | ARG_UPDATE_CATALOG, | |||
400 | ARG_FORCE, | |||
401 | ARG_CASE_SENSITIVE, | |||
402 | ARG_UTC, | |||
403 | ARG_SYNC, | |||
404 | ARG_FLUSH, | |||
405 | ARG_ROTATE, | |||
406 | ARG_VACUUM_SIZE, | |||
407 | ARG_VACUUM_FILES, | |||
408 | ARG_VACUUM_TIME, | |||
409 | ARG_NO_HOSTNAME, | |||
410 | ARG_OUTPUT_FIELDS, | |||
411 | }; | |||
412 | ||||
413 | static const struct option options[] = { | |||
414 | { "help", no_argument0, NULL((void*)0), 'h' }, | |||
415 | { "version" , no_argument0, NULL((void*)0), ARG_VERSION }, | |||
416 | { "no-pager", no_argument0, NULL((void*)0), ARG_NO_PAGER }, | |||
417 | { "pager-end", no_argument0, NULL((void*)0), 'e' }, | |||
418 | { "follow", no_argument0, NULL((void*)0), 'f' }, | |||
419 | { "force", no_argument0, NULL((void*)0), ARG_FORCE }, | |||
420 | { "output", required_argument1, NULL((void*)0), 'o' }, | |||
421 | { "all", no_argument0, NULL((void*)0), 'a' }, | |||
422 | { "full", no_argument0, NULL((void*)0), 'l' }, | |||
423 | { "no-full", no_argument0, NULL((void*)0), ARG_NO_FULL }, | |||
424 | { "lines", optional_argument2, NULL((void*)0), 'n' }, | |||
425 | { "no-tail", no_argument0, NULL((void*)0), ARG_NO_TAIL }, | |||
426 | { "new-id128", no_argument0, NULL((void*)0), ARG_NEW_ID128 }, | |||
427 | { "quiet", no_argument0, NULL((void*)0), 'q' }, | |||
428 | { "merge", no_argument0, NULL((void*)0), 'm' }, | |||
429 | { "this-boot", no_argument0, NULL((void*)0), ARG_THIS_BOOT }, /* deprecated */ | |||
430 | { "boot", optional_argument2, NULL((void*)0), 'b' }, | |||
431 | { "list-boots", no_argument0, NULL((void*)0), ARG_LIST_BOOTS }, | |||
432 | { "dmesg", no_argument0, NULL((void*)0), 'k' }, | |||
433 | { "system", no_argument0, NULL((void*)0), ARG_SYSTEM }, | |||
434 | { "user", no_argument0, NULL((void*)0), ARG_USER }, | |||
435 | { "directory", required_argument1, NULL((void*)0), 'D' }, | |||
436 | { "file", required_argument1, NULL((void*)0), ARG_FILE }, | |||
437 | { "root", required_argument1, NULL((void*)0), ARG_ROOT }, | |||
438 | { "header", no_argument0, NULL((void*)0), ARG_HEADER }, | |||
439 | { "identifier", required_argument1, NULL((void*)0), 't' }, | |||
440 | { "priority", required_argument1, NULL((void*)0), 'p' }, | |||
441 | { "grep", required_argument1, NULL((void*)0), 'g' }, | |||
442 | { "case-sensitive", optional_argument2, NULL((void*)0), ARG_CASE_SENSITIVE }, | |||
443 | { "setup-keys", no_argument0, NULL((void*)0), ARG_SETUP_KEYS }, | |||
444 | { "interval", required_argument1, NULL((void*)0), ARG_INTERVAL }, | |||
445 | { "verify", no_argument0, NULL((void*)0), ARG_VERIFY }, | |||
446 | { "verify-key", required_argument1, NULL((void*)0), ARG_VERIFY_KEY }, | |||
447 | { "disk-usage", no_argument0, NULL((void*)0), ARG_DISK_USAGE }, | |||
448 | { "cursor", required_argument1, NULL((void*)0), 'c' }, | |||
449 | { "after-cursor", required_argument1, NULL((void*)0), ARG_AFTER_CURSOR }, | |||
450 | { "show-cursor", no_argument0, NULL((void*)0), ARG_SHOW_CURSOR }, | |||
451 | { "since", required_argument1, NULL((void*)0), 'S' }, | |||
452 | { "until", required_argument1, NULL((void*)0), 'U' }, | |||
453 | { "unit", required_argument1, NULL((void*)0), 'u' }, | |||
454 | { "user-unit", required_argument1, NULL((void*)0), ARG_USER_UNIT }, | |||
455 | { "field", required_argument1, NULL((void*)0), 'F' }, | |||
456 | { "fields", no_argument0, NULL((void*)0), 'N' }, | |||
457 | { "catalog", no_argument0, NULL((void*)0), 'x' }, | |||
458 | { "list-catalog", no_argument0, NULL((void*)0), ARG_LIST_CATALOG }, | |||
459 | { "dump-catalog", no_argument0, NULL((void*)0), ARG_DUMP_CATALOG }, | |||
460 | { "update-catalog", no_argument0, NULL((void*)0), ARG_UPDATE_CATALOG }, | |||
461 | { "reverse", no_argument0, NULL((void*)0), 'r' }, | |||
462 | { "machine", required_argument1, NULL((void*)0), 'M' }, | |||
463 | { "utc", no_argument0, NULL((void*)0), ARG_UTC }, | |||
464 | { "flush", no_argument0, NULL((void*)0), ARG_FLUSH }, | |||
465 | { "sync", no_argument0, NULL((void*)0), ARG_SYNC }, | |||
466 | { "rotate", no_argument0, NULL((void*)0), ARG_ROTATE }, | |||
467 | { "vacuum-size", required_argument1, NULL((void*)0), ARG_VACUUM_SIZE }, | |||
468 | { "vacuum-files", required_argument1, NULL((void*)0), ARG_VACUUM_FILES }, | |||
469 | { "vacuum-time", required_argument1, NULL((void*)0), ARG_VACUUM_TIME }, | |||
470 | { "no-hostname", no_argument0, NULL((void*)0), ARG_NO_HOSTNAME }, | |||
471 | { "output-fields", required_argument1, NULL((void*)0), ARG_OUTPUT_FIELDS }, | |||
472 | {} | |||
473 | }; | |||
474 | ||||
475 | int c, r; | |||
476 | ||||
477 | assert(argc >= 0)do { if ((__builtin_expect(!!(!(argc >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argc >= 0"), "../src/journal/journalctl.c" , 477, __PRETTY_FUNCTION__); } while (0); | |||
478 | assert(argv)do { if ((__builtin_expect(!!(!(argv)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argv"), "../src/journal/journalctl.c", 478 , __PRETTY_FUNCTION__); } while (0); | |||
479 | ||||
480 | while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:g:c:S:U:t:u:NF:xrM:", options, NULL((void*)0))) >= 0) | |||
481 | ||||
482 | switch (c) { | |||
483 | ||||
484 | case 'h': | |||
485 | help(); | |||
486 | return 0; | |||
487 | ||||
488 | case ARG_VERSION: | |||
489 | return version(); | |||
490 | ||||
491 | case ARG_NO_PAGER: | |||
492 | arg_no_pager = true1; | |||
493 | break; | |||
494 | ||||
495 | case 'e': | |||
496 | arg_pager_end = true1; | |||
497 | ||||
498 | if (arg_lines == ARG_LINES_DEFAULT) | |||
499 | arg_lines = 1000; | |||
500 | ||||
501 | break; | |||
502 | ||||
503 | case 'f': | |||
504 | arg_follow = true1; | |||
505 | break; | |||
506 | ||||
507 | case 'o': | |||
508 | if (streq(optarg, "help")(strcmp((optarg),("help")) == 0)) { | |||
509 | DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX)do { OutputMode _k; flockfile(stdout); for (_k = 0; _k < ( _OUTPUT_MODE_MAX); _k++) { const char *_t; _t = output_mode_to_string (_k); if (!_t) continue; fputs_unlocked(_t, stdout); fputc_unlocked ('\n', stdout); } funlockfile(stdout); } while(0); | |||
510 | return 0; | |||
511 | } | |||
512 | ||||
513 | arg_output = output_mode_from_string(optarg); | |||
514 | if (arg_output < 0) { | |||
515 | log_error("Unknown output format '%s'.", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 515, __func__, "Unknown output format '%s'." , optarg) : -abs(_e); }); | |||
516 | return -EINVAL22; | |||
517 | } | |||
518 | ||||
519 | if (IN_SET(arg_output, OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_CAT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY , OUTPUT_JSON_SSE, OUTPUT_CAT})/sizeof(int)]; switch(arg_output ) { case OUTPUT_EXPORT: case OUTPUT_JSON: case OUTPUT_JSON_PRETTY : case OUTPUT_JSON_SSE: case OUTPUT_CAT: _found = 1; break; default : break; } _found; })) | |||
520 | arg_quiet = true1; | |||
521 | ||||
522 | break; | |||
523 | ||||
524 | case 'l': | |||
525 | arg_full = true1; | |||
526 | break; | |||
527 | ||||
528 | case ARG_NO_FULL: | |||
529 | arg_full = false0; | |||
530 | break; | |||
531 | ||||
532 | case 'a': | |||
533 | arg_all = true1; | |||
534 | break; | |||
535 | ||||
536 | case 'n': | |||
537 | if (optarg) { | |||
538 | if (streq(optarg, "all")(strcmp((optarg),("all")) == 0)) | |||
539 | arg_lines = ARG_LINES_ALL; | |||
540 | else { | |||
541 | r = safe_atoi(optarg, &arg_lines); | |||
542 | if (r < 0 || arg_lines < 0) { | |||
543 | log_error("Failed to parse lines '%s'", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 543, __func__, "Failed to parse lines '%s'" , optarg) : -abs(_e); }); | |||
544 | return -EINVAL22; | |||
545 | } | |||
546 | } | |||
547 | } else { | |||
548 | arg_lines = 10; | |||
549 | ||||
550 | /* Hmm, no argument? Maybe the next | |||
551 | * word on the command line is | |||
552 | * supposed to be the argument? Let's | |||
553 | * see if there is one, and is | |||
554 | * parsable. */ | |||
555 | if (optind < argc) { | |||
556 | int n; | |||
557 | if (streq(argv[optind], "all")(strcmp((argv[optind]),("all")) == 0)) { | |||
558 | arg_lines = ARG_LINES_ALL; | |||
559 | optind++; | |||
560 | } else if (safe_atoi(argv[optind], &n) >= 0 && n >= 0) { | |||
561 | arg_lines = n; | |||
562 | optind++; | |||
563 | } | |||
564 | } | |||
565 | } | |||
566 | ||||
567 | break; | |||
568 | ||||
569 | case ARG_NO_TAIL: | |||
570 | arg_no_tail = true1; | |||
571 | break; | |||
572 | ||||
573 | case ARG_NEW_ID128: | |||
574 | arg_action = ACTION_NEW_ID128; | |||
575 | break; | |||
576 | ||||
577 | case 'q': | |||
578 | arg_quiet = true1; | |||
579 | break; | |||
580 | ||||
581 | case 'm': | |||
582 | arg_merge = true1; | |||
583 | break; | |||
584 | ||||
585 | case ARG_THIS_BOOT: | |||
586 | arg_boot = true1; | |||
587 | break; | |||
588 | ||||
589 | case 'b': | |||
590 | arg_boot = true1; | |||
591 | ||||
592 | if (optarg) { | |||
593 | r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset); | |||
594 | if (r < 0) { | |||
595 | log_error("Failed to parse boot descriptor '%s'", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 595, __func__, "Failed to parse boot descriptor '%s'" , optarg) : -abs(_e); }); | |||
596 | return -EINVAL22; | |||
597 | } | |||
598 | } else { | |||
599 | ||||
600 | /* Hmm, no argument? Maybe the next | |||
601 | * word on the command line is | |||
602 | * supposed to be the argument? Let's | |||
603 | * see if there is one and is parsable | |||
604 | * as a boot descriptor... */ | |||
605 | ||||
606 | if (optind < argc && | |||
607 | parse_boot_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset) >= 0) | |||
608 | optind++; | |||
609 | } | |||
610 | ||||
611 | break; | |||
612 | ||||
613 | case ARG_LIST_BOOTS: | |||
614 | arg_action = ACTION_LIST_BOOTS; | |||
615 | break; | |||
616 | ||||
617 | case 'k': | |||
618 | arg_boot = arg_dmesg = true1; | |||
619 | break; | |||
620 | ||||
621 | case ARG_SYSTEM: | |||
622 | arg_journal_type |= SD_JOURNAL_SYSTEM; | |||
623 | break; | |||
624 | ||||
625 | case ARG_USER: | |||
626 | arg_journal_type |= SD_JOURNAL_CURRENT_USER; | |||
627 | break; | |||
628 | ||||
629 | case 'M': | |||
630 | arg_machine = optarg; | |||
631 | break; | |||
632 | ||||
633 | case 'D': | |||
634 | arg_directory = optarg; | |||
635 | break; | |||
636 | ||||
637 | case ARG_FILE: | |||
638 | if (streq(optarg, "-")(strcmp((optarg),("-")) == 0)) | |||
639 | /* An undocumented feature: we can read journal files from STDIN. We don't document | |||
640 | * this though, since after all we only support this for mmap-able, seekable files, and | |||
641 | * not for example pipes which are probably the primary usecase for reading things from | |||
642 | * STDIN. To avoid confusion we hence don't document this feature. */ | |||
643 | arg_file_stdin = true1; | |||
644 | else { | |||
645 | r = glob_extend(&arg_file, optarg); | |||
646 | if (r < 0) | |||
647 | return log_error_errno(r, "Failed to add paths: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 647, __func__, "Failed to add paths: %m" ) : -abs(_e); }); | |||
648 | } | |||
649 | break; | |||
650 | ||||
651 | case ARG_ROOT: | |||
652 | r = parse_path_argument_and_warn(optarg, true1, &arg_root); | |||
653 | if (r < 0) | |||
654 | return r; | |||
655 | break; | |||
656 | ||||
657 | case 'c': | |||
658 | arg_cursor = optarg; | |||
659 | break; | |||
660 | ||||
661 | case ARG_AFTER_CURSOR: | |||
662 | arg_after_cursor = optarg; | |||
663 | break; | |||
664 | ||||
665 | case ARG_SHOW_CURSOR: | |||
666 | arg_show_cursor = true1; | |||
667 | break; | |||
668 | ||||
669 | case ARG_HEADER: | |||
670 | arg_action = ACTION_PRINT_HEADER; | |||
671 | break; | |||
672 | ||||
673 | case ARG_VERIFY: | |||
674 | arg_action = ACTION_VERIFY; | |||
675 | break; | |||
676 | ||||
677 | case ARG_DISK_USAGE: | |||
678 | arg_action = ACTION_DISK_USAGE; | |||
679 | break; | |||
680 | ||||
681 | case ARG_VACUUM_SIZE: | |||
682 | r = parse_size(optarg, 1024, &arg_vacuum_size); | |||
683 | if (r < 0) { | |||
684 | log_error("Failed to parse vacuum size: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 684, __func__, "Failed to parse vacuum size: %s" , optarg) : -abs(_e); }); | |||
685 | return r; | |||
686 | } | |||
687 | ||||
688 | arg_action = ACTION_VACUUM; | |||
689 | break; | |||
690 | ||||
691 | case ARG_VACUUM_FILES: | |||
692 | r = safe_atou64(optarg, &arg_vacuum_n_files); | |||
693 | if (r < 0) { | |||
694 | log_error("Failed to parse vacuum files: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 694, __func__, "Failed to parse vacuum files: %s" , optarg) : -abs(_e); }); | |||
695 | return r; | |||
696 | } | |||
697 | ||||
698 | arg_action = ACTION_VACUUM; | |||
699 | break; | |||
700 | ||||
701 | case ARG_VACUUM_TIME: | |||
702 | r = parse_sec(optarg, &arg_vacuum_time); | |||
703 | if (r < 0) { | |||
704 | log_error("Failed to parse vacuum time: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 704, __func__, "Failed to parse vacuum time: %s" , optarg) : -abs(_e); }); | |||
705 | return r; | |||
706 | } | |||
707 | ||||
708 | arg_action = ACTION_VACUUM; | |||
709 | break; | |||
710 | ||||
711 | #if HAVE_GCRYPT1 | |||
712 | case ARG_FORCE: | |||
713 | arg_force = true1; | |||
714 | break; | |||
715 | ||||
716 | case ARG_SETUP_KEYS: | |||
717 | arg_action = ACTION_SETUP_KEYS; | |||
718 | break; | |||
719 | ||||
720 | case ARG_VERIFY_KEY: | |||
721 | arg_action = ACTION_VERIFY; | |||
722 | r = free_and_strdup(&arg_verify_key, optarg); | |||
723 | if (r < 0) | |||
724 | return r; | |||
725 | /* Use memset not string_erase so this doesn't look confusing | |||
726 | * in ps or htop output. */ | |||
727 | memset(optarg, 'x', strlen(optarg)); | |||
728 | ||||
729 | arg_merge = false0; | |||
730 | break; | |||
731 | ||||
732 | case ARG_INTERVAL: | |||
733 | r = parse_sec(optarg, &arg_interval); | |||
734 | if (r < 0 || arg_interval <= 0) { | |||
735 | log_error("Failed to parse sealing key change interval: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 735, __func__, "Failed to parse sealing key change interval: %s" , optarg) : -abs(_e); }); | |||
736 | return -EINVAL22; | |||
737 | } | |||
738 | break; | |||
739 | #else | |||
740 | case ARG_SETUP_KEYS: | |||
741 | case ARG_VERIFY_KEY: | |||
742 | case ARG_INTERVAL: | |||
743 | case ARG_FORCE: | |||
744 | log_error("Forward-secure sealing not available.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 744, __func__, "Forward-secure sealing not available." ) : -abs(_e); }); | |||
745 | return -EOPNOTSUPP95; | |||
746 | #endif | |||
747 | ||||
748 | case 'p': { | |||
749 | const char *dots; | |||
750 | ||||
751 | dots = strstr(optarg, ".."); | |||
752 | if (dots) { | |||
753 | char *a; | |||
754 | int from, to, i; | |||
755 | ||||
756 | /* a range */ | |||
757 | a = strndup(optarg, dots - optarg); | |||
758 | if (!a) | |||
759 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 759, __func__); | |||
760 | ||||
761 | from = log_level_from_string(a); | |||
762 | to = log_level_from_string(dots + 2); | |||
763 | free(a); | |||
764 | ||||
765 | if (from < 0 || to < 0) { | |||
766 | log_error("Failed to parse log level range %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 766, __func__, "Failed to parse log level range %s" , optarg) : -abs(_e); }); | |||
767 | return -EINVAL22; | |||
768 | } | |||
769 | ||||
770 | arg_priorities = 0; | |||
771 | ||||
772 | if (from < to) { | |||
773 | for (i = from; i <= to; i++) | |||
774 | arg_priorities |= 1 << i; | |||
775 | } else { | |||
776 | for (i = to; i <= from; i++) | |||
777 | arg_priorities |= 1 << i; | |||
778 | } | |||
779 | ||||
780 | } else { | |||
781 | int p, i; | |||
782 | ||||
783 | p = log_level_from_string(optarg); | |||
784 | if (p < 0) { | |||
785 | log_error("Unknown log level %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 785, __func__, "Unknown log level %s" , optarg) : -abs(_e); }); | |||
786 | return -EINVAL22; | |||
787 | } | |||
788 | ||||
789 | arg_priorities = 0; | |||
790 | ||||
791 | for (i = 0; i <= p; i++) | |||
792 | arg_priorities |= 1 << i; | |||
793 | } | |||
794 | ||||
795 | break; | |||
796 | } | |||
797 | ||||
798 | #if HAVE_PCRE21 | |||
799 | case 'g': | |||
800 | arg_pattern = optarg; | |||
801 | break; | |||
802 | ||||
803 | case ARG_CASE_SENSITIVE: | |||
804 | if (optarg) { | |||
805 | r = parse_boolean(optarg); | |||
806 | if (r < 0) | |||
807 | return log_error_errno(r, "Bad --case-sensitive= argument \"%s\": %m", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 807, __func__, "Bad --case-sensitive= argument \"%s\": %m" , optarg) : -abs(_e); }); | |||
808 | arg_case_sensitive = r; | |||
809 | } else | |||
810 | arg_case_sensitive = true1; | |||
811 | ||||
812 | break; | |||
813 | #else | |||
814 | case 'g': | |||
815 | case ARG_CASE_SENSITIVE: | |||
816 | return log_error("Compiled without pattern matching support")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 816, __func__, "Compiled without pattern matching support" ) : -abs(_e); }); | |||
817 | #endif | |||
818 | ||||
819 | case 'S': | |||
820 | r = parse_timestamp(optarg, &arg_since); | |||
821 | if (r < 0) { | |||
822 | log_error("Failed to parse timestamp: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 822, __func__, "Failed to parse timestamp: %s" , optarg) : -abs(_e); }); | |||
823 | return -EINVAL22; | |||
824 | } | |||
825 | arg_since_set = true1; | |||
826 | break; | |||
827 | ||||
828 | case 'U': | |||
829 | r = parse_timestamp(optarg, &arg_until); | |||
830 | if (r < 0) { | |||
831 | log_error("Failed to parse timestamp: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 831, __func__, "Failed to parse timestamp: %s" , optarg) : -abs(_e); }); | |||
832 | return -EINVAL22; | |||
833 | } | |||
834 | arg_until_set = true1; | |||
835 | break; | |||
836 | ||||
837 | case 't': | |||
838 | r = strv_extend(&arg_syslog_identifier, optarg); | |||
839 | if (r < 0) | |||
840 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 840, __func__); | |||
841 | break; | |||
842 | ||||
843 | case 'u': | |||
844 | r = strv_extend(&arg_system_units, optarg); | |||
845 | if (r < 0) | |||
846 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 846, __func__); | |||
847 | break; | |||
848 | ||||
849 | case ARG_USER_UNIT: | |||
850 | r = strv_extend(&arg_user_units, optarg); | |||
851 | if (r < 0) | |||
852 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 852, __func__); | |||
853 | break; | |||
854 | ||||
855 | case 'F': | |||
856 | arg_action = ACTION_LIST_FIELDS; | |||
857 | arg_field = optarg; | |||
858 | break; | |||
859 | ||||
860 | case 'N': | |||
861 | arg_action = ACTION_LIST_FIELD_NAMES; | |||
862 | break; | |||
863 | ||||
864 | case ARG_NO_HOSTNAME: | |||
865 | arg_no_hostname = true1; | |||
866 | break; | |||
867 | ||||
868 | case 'x': | |||
869 | arg_catalog = true1; | |||
870 | break; | |||
871 | ||||
872 | case ARG_LIST_CATALOG: | |||
873 | arg_action = ACTION_LIST_CATALOG; | |||
874 | break; | |||
875 | ||||
876 | case ARG_DUMP_CATALOG: | |||
877 | arg_action = ACTION_DUMP_CATALOG; | |||
878 | break; | |||
879 | ||||
880 | case ARG_UPDATE_CATALOG: | |||
881 | arg_action = ACTION_UPDATE_CATALOG; | |||
882 | break; | |||
883 | ||||
884 | case 'r': | |||
885 | arg_reverse = true1; | |||
886 | break; | |||
887 | ||||
888 | case ARG_UTC: | |||
889 | arg_utc = true1; | |||
890 | break; | |||
891 | ||||
892 | case ARG_FLUSH: | |||
893 | arg_action = ACTION_FLUSH; | |||
894 | break; | |||
895 | ||||
896 | case ARG_ROTATE: | |||
897 | arg_action = ACTION_ROTATE; | |||
898 | break; | |||
899 | ||||
900 | case ARG_SYNC: | |||
901 | arg_action = ACTION_SYNC; | |||
902 | break; | |||
903 | ||||
904 | case ARG_OUTPUT_FIELDS: { | |||
905 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **v = NULL((void*)0); | |||
906 | ||||
907 | v = strv_split(optarg, ","); | |||
908 | if (!v) | |||
909 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 909, __func__); | |||
910 | ||||
911 | if (!arg_output_fields) | |||
912 | arg_output_fields = TAKE_PTR(v)({ typeof(v) _ptr_ = (v); (v) = ((void*)0); _ptr_; }); | |||
913 | else { | |||
914 | r = strv_extend_strv(&arg_output_fields, v, true1); | |||
915 | if (r < 0) | |||
916 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 916, __func__); | |||
917 | } | |||
918 | break; | |||
919 | } | |||
920 | ||||
921 | case '?': | |||
922 | return -EINVAL22; | |||
923 | ||||
924 | default: | |||
925 | assert_not_reached("Unhandled option")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unhandled option"), "../src/journal/journalctl.c", 925, __PRETTY_FUNCTION__ ); } while (0); | |||
926 | } | |||
927 | ||||
928 | if (arg_follow && !arg_no_tail && !arg_since && arg_lines == ARG_LINES_DEFAULT) | |||
929 | arg_lines = 10; | |||
930 | ||||
931 | if (!!arg_directory + !!arg_file + !!arg_machine + !!arg_root > 1) { | |||
932 | log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 932, __func__, "Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root." ) : -abs(_e); }); | |||
933 | return -EINVAL22; | |||
934 | } | |||
935 | ||||
936 | if (arg_since_set && arg_until_set && arg_since > arg_until) { | |||
937 | log_error("--since= must be before --until=.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 937, __func__, "--since= must be before --until=." ) : -abs(_e); }); | |||
938 | return -EINVAL22; | |||
939 | } | |||
940 | ||||
941 | if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) { | |||
942 | log_error("Please specify only one of --since=, --cursor=, and --after-cursor.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 942, __func__, "Please specify only one of --since=, --cursor=, and --after-cursor." ) : -abs(_e); }); | |||
943 | return -EINVAL22; | |||
944 | } | |||
945 | ||||
946 | if (arg_follow && arg_reverse) { | |||
947 | log_error("Please specify either --reverse= or --follow=, not both.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 947, __func__, "Please specify either --reverse= or --follow=, not both." ) : -abs(_e); }); | |||
948 | return -EINVAL22; | |||
949 | } | |||
950 | ||||
951 | if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG })/sizeof(int)]; switch(arg_action) { case ACTION_SHOW: case ACTION_DUMP_CATALOG : case ACTION_LIST_CATALOG: _found = 1; break; default: break ; } _found; }) && optind < argc) { | |||
952 | log_error("Extraneous arguments starting with '%s'", argv[optind])({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 952, __func__, "Extraneous arguments starting with '%s'" , argv[optind]) : -abs(_e); }); | |||
953 | return -EINVAL22; | |||
954 | } | |||
955 | ||||
956 | if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && arg_merge) { | |||
957 | log_error("Using --boot or --list-boots with --merge is not supported.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 957, __func__, "Using --boot or --list-boots with --merge is not supported." ) : -abs(_e); }); | |||
958 | return -EINVAL22; | |||
959 | } | |||
960 | ||||
961 | if (!strv_isempty(arg_system_units) && arg_journal_type == SD_JOURNAL_CURRENT_USER) { | |||
962 | /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user | |||
963 | * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice | |||
964 | * to users, and automatically turn --unit= into --user-unit= if combined with --user. */ | |||
965 | r = strv_extend_strv(&arg_user_units, arg_system_units, true1); | |||
966 | if (r < 0) | |||
967 | return r; | |||
968 | ||||
969 | arg_system_units = strv_free(arg_system_units); | |||
970 | } | |||
971 | ||||
972 | #if HAVE_PCRE21 | |||
973 | if (arg_pattern) { | |||
974 | unsigned flags; | |||
975 | ||||
976 | if (arg_case_sensitive >= 0) | |||
977 | flags = !arg_case_sensitive * PCRE2_CASELESS0x00000008u; | |||
978 | else { | |||
979 | _cleanup_(pcre2_match_data_freep)__attribute__((cleanup(pcre2_match_data_freep))) pcre2_match_datapcre2_match_data_8 *md = NULL((void*)0); | |||
980 | bool_Bool has_case; | |||
981 | _cleanup_(pcre2_code_freep)__attribute__((cleanup(pcre2_code_freep))) pcre2_codepcre2_code_8 *cs = NULL((void*)0); | |||
982 | ||||
983 | md = pcre2_match_data_createpcre2_match_data_create_8(1, NULL((void*)0)); | |||
984 | if (!md) | |||
985 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 985, __func__); | |||
986 | ||||
987 | r = pattern_compile("[[:upper:]]", 0, &cs); | |||
988 | if (r < 0) | |||
989 | return r; | |||
990 | ||||
991 | r = pcre2_matchpcre2_match_8(cs, (PCRE2_SPTR8) arg_pattern, PCRE2_ZERO_TERMINATED(~(size_t)0), 0, 0, md, NULL((void*)0)); | |||
992 | has_case = r >= 0; | |||
993 | ||||
994 | flags = !has_case * PCRE2_CASELESS0x00000008u; | |||
995 | } | |||
996 | ||||
997 | log_debug("Doing case %s matching based on %s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 999, __func__, "Doing case %s matching based on %s" , flags & 0x00000008u ? "insensitive" : "sensitive", arg_case_sensitive >= 0 ? "request" : "pattern casing") : -abs(_e); }) | |||
998 | flags & PCRE2_CASELESS ? "insensitive" : "sensitive",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 999, __func__, "Doing case %s matching based on %s" , flags & 0x00000008u ? "insensitive" : "sensitive", arg_case_sensitive >= 0 ? "request" : "pattern casing") : -abs(_e); }) | |||
999 | arg_case_sensitive >= 0 ? "request" : "pattern casing")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 999, __func__, "Doing case %s matching based on %s" , flags & 0x00000008u ? "insensitive" : "sensitive", arg_case_sensitive >= 0 ? "request" : "pattern casing") : -abs(_e); }); | |||
1000 | ||||
1001 | r = pattern_compile(arg_pattern, flags, &arg_compiled_pattern); | |||
1002 | if (r < 0) | |||
1003 | return r; | |||
1004 | } | |||
1005 | #endif | |||
1006 | ||||
1007 | return 1; | |||
1008 | } | |||
1009 | ||||
1010 | static int generate_new_id128(void) { | |||
1011 | sd_id128_t id; | |||
1012 | int r; | |||
1013 | unsigned i; | |||
1014 | ||||
1015 | r = sd_id128_randomize(&id); | |||
1016 | if (r < 0) | |||
1017 | return log_error_errno(r, "Failed to generate ID: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1017, __func__, "Failed to generate ID: %m" ) : -abs(_e); }); | |||
1018 | ||||
1019 | printf("As string:\n" | |||
1020 | SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" "\n\n" | |||
1021 | "As UUID:\n" | |||
1022 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n" | |||
1023 | "As man:sd-id128(3) macro:\n" | |||
1024 | "#define MESSAGE_XYZ SD_ID128_MAKE(", | |||
1025 | SD_ID128_FORMAT_VAL(id)(id).bytes[0], (id).bytes[1], (id).bytes[2], (id).bytes[3], ( id).bytes[4], (id).bytes[5], (id).bytes[6], (id).bytes[7], (id ).bytes[8], (id).bytes[9], (id).bytes[10], (id).bytes[11], (id ).bytes[12], (id).bytes[13], (id).bytes[14], (id).bytes[15], | |||
1026 | SD_ID128_FORMAT_VAL(id)(id).bytes[0], (id).bytes[1], (id).bytes[2], (id).bytes[3], ( id).bytes[4], (id).bytes[5], (id).bytes[6], (id).bytes[7], (id ).bytes[8], (id).bytes[9], (id).bytes[10], (id).bytes[11], (id ).bytes[12], (id).bytes[13], (id).bytes[14], (id).bytes[15]); | |||
1027 | for (i = 0; i < 16; i++) | |||
1028 | printf("%02x%s", id.bytes[i], i != 15 ? "," : ""); | |||
1029 | fputs(")\n\n", stdoutstdout); | |||
1030 | ||||
1031 | printf("As Python constant:\n" | |||
1032 | ">>> import uuid\n" | |||
1033 | ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" "')\n", | |||
1034 | SD_ID128_FORMAT_VAL(id)(id).bytes[0], (id).bytes[1], (id).bytes[2], (id).bytes[3], ( id).bytes[4], (id).bytes[5], (id).bytes[6], (id).bytes[7], (id ).bytes[8], (id).bytes[9], (id).bytes[10], (id).bytes[11], (id ).bytes[12], (id).bytes[13], (id).bytes[14], (id).bytes[15]); | |||
1035 | ||||
1036 | return 0; | |||
1037 | } | |||
1038 | ||||
1039 | static int add_matches(sd_journal *j, char **args) { | |||
1040 | char **i; | |||
1041 | bool_Bool have_term = false0; | |||
1042 | ||||
1043 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/journal/journalctl.c", 1043 , __PRETTY_FUNCTION__); } while (0); | |||
1044 | ||||
1045 | STRV_FOREACH(i, args)for ((i) = (args); (i) && *(i); (i)++) { | |||
1046 | int r; | |||
1047 | ||||
1048 | if (streq(*i, "+")(strcmp((*i),("+")) == 0)) { | |||
1049 | if (!have_term) | |||
1050 | break; | |||
1051 | r = sd_journal_add_disjunction(j); | |||
1052 | have_term = false0; | |||
1053 | ||||
1054 | } else if (path_is_absolute(*i)) { | |||
1055 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0), *t = NULL((void*)0), *t2 = NULL((void*)0), *interpreter = NULL((void*)0); | |||
1056 | struct stat st; | |||
1057 | ||||
1058 | r = chase_symlinks(*i, NULL((void*)0), CHASE_TRAIL_SLASH, &p); | |||
1059 | if (r < 0) | |||
1060 | return log_error_errno(r, "Couldn't canonicalize path: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1060, __func__, "Couldn't canonicalize path: %m" ) : -abs(_e); }); | |||
1061 | ||||
1062 | if (lstat(p, &st) < 0) | |||
1063 | return log_error_errno(errno, "Couldn't stat file: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 1063, __func__ , "Couldn't stat file: %m") : -abs(_e); }); | |||
1064 | ||||
1065 | if (S_ISREG(st.st_mode)((((st.st_mode)) & 0170000) == (0100000)) && (0111 & st.st_mode)) { | |||
1066 | if (executable_is_script(p, &interpreter) > 0) { | |||
1067 | _cleanup_free___attribute__((cleanup(freep))) char *comm; | |||
1068 | ||||
1069 | comm = strndup(basename(p), 15); | |||
1070 | if (!comm) | |||
1071 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 1071, __func__); | |||
1072 | ||||
1073 | t = strappend("_COMM=", comm); | |||
1074 | if (!t) | |||
1075 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 1075, __func__); | |||
1076 | ||||
1077 | /* Append _EXE only if the interpreter is not a link. | |||
1078 | Otherwise, it might be outdated often. */ | |||
1079 | if (lstat(interpreter, &st) == 0 && !S_ISLNK(st.st_mode)((((st.st_mode)) & 0170000) == (0120000))) { | |||
1080 | t2 = strappend("_EXE=", interpreter); | |||
1081 | if (!t2) | |||
1082 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 1082, __func__); | |||
1083 | } | |||
1084 | } else { | |||
1085 | t = strappend("_EXE=", p); | |||
1086 | if (!t) | |||
1087 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 1087, __func__); | |||
1088 | } | |||
1089 | ||||
1090 | r = sd_journal_add_match(j, t, 0); | |||
1091 | ||||
1092 | if (r >=0 && t2) | |||
1093 | r = sd_journal_add_match(j, t2, 0); | |||
1094 | ||||
1095 | } else if (S_ISCHR(st.st_mode)((((st.st_mode)) & 0170000) == (0020000)) || S_ISBLK(st.st_mode)((((st.st_mode)) & 0170000) == (0060000))) { | |||
1096 | r = add_matches_for_device(j, p); | |||
1097 | if (r < 0) | |||
1098 | return r; | |||
1099 | } else { | |||
1100 | log_error("File is neither a device node, nor regular file, nor executable: %s", *i)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1100, __func__, "File is neither a device node, nor regular file, nor executable: %s" , *i) : -abs(_e); }); | |||
1101 | return -EINVAL22; | |||
1102 | } | |||
1103 | ||||
1104 | have_term = true1; | |||
1105 | } else { | |||
1106 | r = sd_journal_add_match(j, *i, 0); | |||
1107 | have_term = true1; | |||
1108 | } | |||
1109 | ||||
1110 | if (r < 0) | |||
1111 | return log_error_errno(r, "Failed to add match '%s': %m", *i)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1111, __func__, "Failed to add match '%s': %m" , *i) : -abs(_e); }); | |||
1112 | } | |||
1113 | ||||
1114 | if (!strv_isempty(args) && !have_term) { | |||
1115 | log_error("\"+\" can only be used between terms")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1115, __func__, "\"+\" can only be used between terms" ) : -abs(_e); }); | |||
1116 | return -EINVAL22; | |||
1117 | } | |||
1118 | ||||
1119 | return 0; | |||
1120 | } | |||
1121 | ||||
1122 | static void boot_id_free_all(BootId *l) { | |||
1123 | ||||
1124 | while (l) { | |||
1125 | BootId *i = l; | |||
1126 | LIST_REMOVE(boot_list, l, i)do { typeof(*(l)) **_head = &(l), *_item = (i); do { if ( (__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("_item"), "../src/journal/journalctl.c", 1126, __PRETTY_FUNCTION__ ); } while (0); if (_item->boot_list_next) _item->boot_list_next ->boot_list_prev = _item->boot_list_prev; if (_item-> boot_list_prev) _item->boot_list_prev->boot_list_next = _item->boot_list_next; else { do { if ((__builtin_expect( !!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("*_head == _item"), "../src/journal/journalctl.c", 1126, __PRETTY_FUNCTION__ ); } while (0); *_head = _item->boot_list_next; } _item-> boot_list_next = _item->boot_list_prev = ((void*)0); } while (0); | |||
| ||||
1127 | free(i); | |||
1128 | } | |||
1129 | } | |||
1130 | ||||
1131 | static int discover_next_boot(sd_journal *j, | |||
1132 | sd_id128_t previous_boot_id, | |||
1133 | bool_Bool advance_older, | |||
1134 | BootId **ret) { | |||
1135 | ||||
1136 | _cleanup_free___attribute__((cleanup(freep))) BootId *next_boot = NULL((void*)0); | |||
1137 | char match[9+32+1] = "_BOOT_ID="; | |||
1138 | sd_id128_t boot_id; | |||
1139 | int r; | |||
1140 | ||||
1141 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/journal/journalctl.c", 1141 , __PRETTY_FUNCTION__); } while (0); | |||
1142 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/journal/journalctl.c", 1142 , __PRETTY_FUNCTION__); } while (0); | |||
1143 | ||||
1144 | /* We expect the journal to be on the last position of a boot | |||
1145 | * (in relation to the direction we are going), so that the next | |||
1146 | * invocation of sd_journal_next/previous will be from a different | |||
1147 | * boot. We then collect any information we desire and then jump | |||
1148 | * to the last location of the new boot by using a _BOOT_ID match | |||
1149 | * coming from the other journal direction. */ | |||
1150 | ||||
1151 | /* Make sure we aren't restricted by any _BOOT_ID matches, so that | |||
1152 | * we can actually advance to a *different* boot. */ | |||
1153 | sd_journal_flush_matches(j); | |||
1154 | ||||
1155 | do { | |||
1156 | if (advance_older) | |||
1157 | r = sd_journal_previous(j); | |||
1158 | else | |||
1159 | r = sd_journal_next(j); | |||
1160 | if (r < 0) | |||
1161 | return r; | |||
1162 | else if (r == 0) | |||
1163 | return 0; /* End of journal, yay. */ | |||
1164 | ||||
1165 | r = sd_journal_get_monotonic_usec(j, NULL((void*)0), &boot_id); | |||
1166 | if (r < 0) | |||
1167 | return r; | |||
1168 | ||||
1169 | /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that | |||
1170 | * normally, this will only require a single iteration, as we seeked to the last entry of the previous | |||
1171 | * boot entry already. However, it might happen that the per-journal-field entry arrays are less | |||
1172 | * complete than the main entry array, and hence might reference an entry that's not actually the last | |||
1173 | * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to | |||
1174 | * speed things up, but let's not trust that it is complete, and hence, manually advance as | |||
1175 | * necessary. */ | |||
1176 | ||||
1177 | } while (sd_id128_equal(boot_id, previous_boot_id)); | |||
1178 | ||||
1179 | next_boot = new0(BootId, 1)((BootId*) calloc((1), sizeof(BootId))); | |||
1180 | if (!next_boot) | |||
1181 | return -ENOMEM12; | |||
1182 | ||||
1183 | next_boot->id = boot_id; | |||
1184 | ||||
1185 | r = sd_journal_get_realtime_usec(j, &next_boot->first); | |||
1186 | if (r < 0) | |||
1187 | return r; | |||
1188 | ||||
1189 | /* Now seek to the last occurrence of this boot ID. */ | |||
1190 | sd_id128_to_string(next_boot->id, match + 9); | |||
1191 | r = sd_journal_add_match(j, match, sizeof(match) - 1); | |||
1192 | if (r < 0) | |||
1193 | return r; | |||
1194 | ||||
1195 | if (advance_older) | |||
1196 | r = sd_journal_seek_head(j); | |||
1197 | else | |||
1198 | r = sd_journal_seek_tail(j); | |||
1199 | if (r < 0) | |||
1200 | return r; | |||
1201 | ||||
1202 | if (advance_older) | |||
1203 | r = sd_journal_next(j); | |||
1204 | else | |||
1205 | r = sd_journal_previous(j); | |||
1206 | if (r < 0) | |||
1207 | return r; | |||
1208 | else if (r == 0) { | |||
1209 | log_debug("Whoopsie! We found a boot ID but can't read its last entry.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1209, __func__, "Whoopsie! We found a boot ID but can't read its last entry." ) : -abs(_e); }); | |||
1210 | return -ENODATA61; /* This shouldn't happen. We just came from this very boot ID. */ | |||
1211 | } | |||
1212 | ||||
1213 | r = sd_journal_get_realtime_usec(j, &next_boot->last); | |||
1214 | if (r < 0) | |||
1215 | return r; | |||
1216 | ||||
1217 | *ret = TAKE_PTR(next_boot)({ typeof(next_boot) _ptr_ = (next_boot); (next_boot) = ((void *)0); _ptr_; }); | |||
1218 | ||||
1219 | return 0; | |||
1220 | } | |||
1221 | ||||
1222 | static int get_boots( | |||
1223 | sd_journal *j, | |||
1224 | BootId **boots, | |||
1225 | sd_id128_t *boot_id, | |||
1226 | int offset) { | |||
1227 | ||||
1228 | bool_Bool skip_once; | |||
1229 | int r, count = 0; | |||
1230 | BootId *head = NULL((void*)0), *tail = NULL((void*)0), *id; | |||
1231 | const bool_Bool advance_older = boot_id && offset <= 0; | |||
1232 | sd_id128_t previous_boot_id; | |||
1233 | ||||
1234 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/journal/journalctl.c", 1234 , __PRETTY_FUNCTION__); } while (0); | |||
1235 | ||||
1236 | /* Adjust for the asymmetry that offset 0 is | |||
1237 | * the last (and current) boot, while 1 is considered the | |||
1238 | * (chronological) first boot in the journal. */ | |||
1239 | skip_once = boot_id && sd_id128_is_null(*boot_id) && offset <= 0; | |||
1240 | ||||
1241 | /* Advance to the earliest/latest occurrence of our reference | |||
1242 | * boot ID (taking our lookup direction into account), so that | |||
1243 | * discover_next_boot() can do its job. | |||
1244 | * If no reference is given, the journal head/tail will do, | |||
1245 | * they're "virtual" boots after all. */ | |||
1246 | if (boot_id && !sd_id128_is_null(*boot_id)) { | |||
1247 | char match[9+32+1] = "_BOOT_ID="; | |||
1248 | ||||
1249 | sd_journal_flush_matches(j); | |||
1250 | ||||
1251 | sd_id128_to_string(*boot_id, match + 9); | |||
1252 | r = sd_journal_add_match(j, match, sizeof(match) - 1); | |||
1253 | if (r < 0) | |||
1254 | return r; | |||
1255 | ||||
1256 | if (advance_older) | |||
1257 | r = sd_journal_seek_head(j); /* seek to oldest */ | |||
1258 | else | |||
1259 | r = sd_journal_seek_tail(j); /* seek to newest */ | |||
1260 | if (r < 0) | |||
1261 | return r; | |||
1262 | ||||
1263 | if (advance_older) | |||
1264 | r = sd_journal_next(j); /* read the oldest entry */ | |||
1265 | else | |||
1266 | r = sd_journal_previous(j); /* read the most recently added entry */ | |||
1267 | if (r < 0) | |||
1268 | return r; | |||
1269 | else if (r == 0) | |||
1270 | goto finish; | |||
1271 | else if (offset == 0) { | |||
1272 | count = 1; | |||
1273 | goto finish; | |||
1274 | } | |||
1275 | ||||
1276 | /* At this point the read pointer is positioned at the oldest/newest occurence of the reference boot | |||
1277 | * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at | |||
1278 | * the following entry, which must then have an older/newer boot ID */ | |||
1279 | } else { | |||
1280 | ||||
1281 | if (advance_older) | |||
1282 | r = sd_journal_seek_tail(j); /* seek to newest */ | |||
1283 | else | |||
1284 | r = sd_journal_seek_head(j); /* seek to oldest */ | |||
1285 | if (r < 0) | |||
1286 | return r; | |||
1287 | ||||
1288 | /* No sd_journal_next()/_previous() here. | |||
1289 | * | |||
1290 | * At this point the read pointer is positioned after the newest/before the oldest entry in the whole | |||
1291 | * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest | |||
1292 | * entry we have. */ | |||
1293 | } | |||
1294 | ||||
1295 | previous_boot_id = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }}); | |||
1296 | for (;;) { | |||
1297 | _cleanup_free___attribute__((cleanup(freep))) BootId *current = NULL((void*)0); | |||
1298 | ||||
1299 | r = discover_next_boot(j, previous_boot_id, advance_older, ¤t); | |||
1300 | if (r < 0) { | |||
1301 | boot_id_free_all(head); | |||
1302 | return r; | |||
1303 | } | |||
1304 | ||||
1305 | if (!current) | |||
1306 | break; | |||
1307 | ||||
1308 | previous_boot_id = current->id; | |||
1309 | ||||
1310 | if (boot_id) { | |||
1311 | if (!skip_once) | |||
1312 | offset += advance_older ? 1 : -1; | |||
1313 | skip_once = false0; | |||
1314 | ||||
1315 | if (offset == 0) { | |||
1316 | count = 1; | |||
1317 | *boot_id = current->id; | |||
1318 | break; | |||
1319 | } | |||
1320 | } else { | |||
1321 | LIST_FOREACH(boot_list, id, head)for ((id) = (head); (id); (id) = (id)->boot_list_next) { | |||
1322 | if (sd_id128_equal(id->id, current->id)) { | |||
1323 | /* boot id already stored, something wrong with the journal files */ | |||
1324 | /* exiting as otherwise this problem would cause forever loop */ | |||
1325 | goto finish; | |||
1326 | } | |||
1327 | } | |||
1328 | LIST_INSERT_AFTER(boot_list, head, tail, current)do { typeof(*(head)) **_head = &(head), *_a = (tail), *_b = (current); do { if ((__builtin_expect(!!(!(_b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_b"), "../src/journal/journalctl.c", 1328 , __PRETTY_FUNCTION__); } while (0); if (!_a) { if ((_b->boot_list_next = *_head)) _b->boot_list_next->boot_list_prev = _b; _b ->boot_list_prev = ((void*)0); *_head = _b; } else { if (( _b->boot_list_next = _a->boot_list_next)) _b->boot_list_next ->boot_list_prev = _b; _b->boot_list_prev = _a; _a-> boot_list_next = _b; } } while (0); | |||
1329 | tail = TAKE_PTR(current)({ typeof(current) _ptr_ = (current); (current) = ((void*)0); _ptr_; }); | |||
1330 | count++; | |||
1331 | } | |||
1332 | } | |||
1333 | ||||
1334 | finish: | |||
1335 | if (boots) | |||
1336 | *boots = head; | |||
1337 | ||||
1338 | sd_journal_flush_matches(j); | |||
1339 | ||||
1340 | return count; | |||
1341 | } | |||
1342 | ||||
1343 | static int list_boots(sd_journal *j) { | |||
1344 | int w, i, count; | |||
1345 | BootId *id, *all_ids; | |||
1346 | ||||
1347 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/journal/journalctl.c", 1347 , __PRETTY_FUNCTION__); } while (0); | |||
| ||||
1348 | ||||
1349 | count = get_boots(j, &all_ids, NULL((void*)0), 0); | |||
1350 | if (count < 0) | |||
1351 | return log_error_errno(count, "Failed to determine boots: %m")({ int _level = ((3)), _e = ((count)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1351, __func__, "Failed to determine boots: %m" ) : -abs(_e); }); | |||
1352 | if (count == 0) | |||
1353 | return count; | |||
1354 | ||||
1355 | (void) pager_open(arg_no_pager, arg_pager_end); | |||
1356 | ||||
1357 | /* numbers are one less, but we need an extra char for the sign */ | |||
1358 | w = DECIMAL_STR_WIDTH(count - 1)({ typeof(count - 1) _x_ = (count - 1); unsigned ans = 1; while ((_x_ /= 10) != 0) ans++; ans; }) + 1; | |||
1359 | ||||
1360 | i = 0; | |||
1361 | LIST_FOREACH(boot_list, id, all_ids)for ((id) = (all_ids); (id); (id) = (id)->boot_list_next) { | |||
1362 | char a[FORMAT_TIMESTAMP_MAX(3+1+10+1+8+1+6+1+6+1)], b[FORMAT_TIMESTAMP_MAX(3+1+10+1+8+1+6+1+6+1)]; | |||
1363 | ||||
1364 | printf("% *i " SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" " %s—%s\n", | |||
1365 | w, i - count + 1, | |||
1366 | SD_ID128_FORMAT_VAL(id->id)(id->id).bytes[0], (id->id).bytes[1], (id->id).bytes [2], (id->id).bytes[3], (id->id).bytes[4], (id->id). bytes[5], (id->id).bytes[6], (id->id).bytes[7], (id-> id).bytes[8], (id->id).bytes[9], (id->id).bytes[10], (id ->id).bytes[11], (id->id).bytes[12], (id->id).bytes[ 13], (id->id).bytes[14], (id->id).bytes[15], | |||
1367 | format_timestamp_maybe_utc(a, sizeof(a), id->first), | |||
1368 | format_timestamp_maybe_utc(b, sizeof(b), id->last)); | |||
1369 | i++; | |||
1370 | } | |||
1371 | ||||
1372 | boot_id_free_all(all_ids); | |||
1373 | ||||
1374 | return 0; | |||
1375 | } | |||
1376 | ||||
1377 | static int add_boot(sd_journal *j) { | |||
1378 | char match[9+32+1] = "_BOOT_ID="; | |||
1379 | sd_id128_t boot_id; | |||
1380 | int r; | |||
1381 | ||||
1382 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/journal/journalctl.c", 1382 , __PRETTY_FUNCTION__); } while (0); | |||
1383 | ||||
1384 | if (!arg_boot) | |||
1385 | return 0; | |||
1386 | ||||
1387 | /* Take a shortcut and use the current boot_id, which we can do very quickly. | |||
1388 | * We can do this only when we logs are coming from the current machine, | |||
1389 | * so take the slow path if log location is specified. */ | |||
1390 | if (arg_boot_offset == 0 && sd_id128_is_null(arg_boot_id) && | |||
1391 | !arg_directory && !arg_file && !arg_root) | |||
1392 | ||||
1393 | return add_match_this_boot(j, arg_machine); | |||
1394 | ||||
1395 | boot_id = arg_boot_id; | |||
1396 | r = get_boots(j, NULL((void*)0), &boot_id, arg_boot_offset); | |||
1397 | assert(r <= 1)do { if ((__builtin_expect(!!(!(r <= 1)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("r <= 1"), "../src/journal/journalctl.c" , 1397, __PRETTY_FUNCTION__); } while (0); | |||
1398 | if (r <= 0) { | |||
1399 | const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r); | |||
1400 | ||||
1401 | if (sd_id128_is_null(arg_boot_id)) | |||
1402 | log_error("Data from the specified boot (%+i) is not available: %s",({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1403, __func__, "Data from the specified boot (%+i) is not available: %s" , arg_boot_offset, reason) : -abs(_e); }) | |||
1403 | arg_boot_offset, reason)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1403, __func__, "Data from the specified boot (%+i) is not available: %s" , arg_boot_offset, reason) : -abs(_e); }); | |||
1404 | else | |||
1405 | log_error("Data from the specified boot ("SD_ID128_FORMAT_STR") is not available: %s",({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1406, __func__, "Data from the specified boot (" "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ") is not available: %s", (arg_boot_id).bytes[0], (arg_boot_id ).bytes[1], (arg_boot_id).bytes[2], (arg_boot_id).bytes[3], ( arg_boot_id).bytes[4], (arg_boot_id).bytes[5], (arg_boot_id). bytes[6], (arg_boot_id).bytes[7], (arg_boot_id).bytes[8], (arg_boot_id ).bytes[9], (arg_boot_id).bytes[10], (arg_boot_id).bytes[11], (arg_boot_id).bytes[12], (arg_boot_id).bytes[13], (arg_boot_id ).bytes[14], (arg_boot_id).bytes[15], reason) : -abs(_e); }) | |||
1406 | SD_ID128_FORMAT_VAL(arg_boot_id), reason)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1406, __func__, "Data from the specified boot (" "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ") is not available: %s", (arg_boot_id).bytes[0], (arg_boot_id ).bytes[1], (arg_boot_id).bytes[2], (arg_boot_id).bytes[3], ( arg_boot_id).bytes[4], (arg_boot_id).bytes[5], (arg_boot_id). bytes[6], (arg_boot_id).bytes[7], (arg_boot_id).bytes[8], (arg_boot_id ).bytes[9], (arg_boot_id).bytes[10], (arg_boot_id).bytes[11], (arg_boot_id).bytes[12], (arg_boot_id).bytes[13], (arg_boot_id ).bytes[14], (arg_boot_id).bytes[15], reason) : -abs(_e); }); | |||
1407 | ||||
1408 | return r == 0 ? -ENODATA61 : r; | |||
1409 | } | |||
1410 | ||||
1411 | sd_id128_to_string(boot_id, match + 9); | |||
1412 | ||||
1413 | r = sd_journal_add_match(j, match, sizeof(match) - 1); | |||
1414 | if (r < 0) | |||
1415 | return log_error_errno(r, "Failed to add match: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1415, __func__, "Failed to add match: %m" ) : -abs(_e); }); | |||
1416 | ||||
1417 | r = sd_journal_add_conjunction(j); | |||
1418 | if (r < 0) | |||
1419 | return log_error_errno(r, "Failed to add conjunction: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1419, __func__, "Failed to add conjunction: %m" ) : -abs(_e); }); | |||
1420 | ||||
1421 | return 0; | |||
1422 | } | |||
1423 | ||||
1424 | static int add_dmesg(sd_journal *j) { | |||
1425 | int r; | |||
1426 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/journal/journalctl.c", 1426 , __PRETTY_FUNCTION__); } while (0); | |||
1427 | ||||
1428 | if (!arg_dmesg) | |||
1429 | return 0; | |||
1430 | ||||
1431 | r = sd_journal_add_match(j, "_TRANSPORT=kernel", | |||
1432 | STRLEN("_TRANSPORT=kernel")(sizeof("""_TRANSPORT=kernel""") - 1)); | |||
1433 | if (r < 0) | |||
1434 | return log_error_errno(r, "Failed to add match: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1434, __func__, "Failed to add match: %m" ) : -abs(_e); }); | |||
1435 | ||||
1436 | r = sd_journal_add_conjunction(j); | |||
1437 | if (r < 0) | |||
1438 | return log_error_errno(r, "Failed to add conjunction: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1438, __func__, "Failed to add conjunction: %m" ) : -abs(_e); }); | |||
1439 | ||||
1440 | return 0; | |||
1441 | } | |||
1442 | ||||
1443 | static int get_possible_units( | |||
1444 | sd_journal *j, | |||
1445 | const char *fields, | |||
1446 | char **patterns, | |||
1447 | Set **units) { | |||
1448 | ||||
1449 | _cleanup_set_free_free___attribute__((cleanup(set_free_freep))) Set *found; | |||
1450 | const char *field; | |||
1451 | int r; | |||
1452 | ||||
1453 | found = set_new(&string_hash_ops)internal_set_new(&string_hash_ops ); | |||
1454 | if (!found) | |||
1455 | return -ENOMEM12; | |||
1456 | ||||
1457 | NULSTR_FOREACH(field, fields)for ((field) = (fields); (field) && *(field); (field) = strchr((field), 0)+1) { | |||
1458 | const void *data; | |||
1459 | size_t size; | |||
1460 | ||||
1461 | r = sd_journal_query_unique(j, field); | |||
1462 | if (r < 0) | |||
1463 | return r; | |||
1464 | ||||
1465 | SD_JOURNAL_FOREACH_UNIQUE(j, data, size)for (sd_journal_restart_unique(j); sd_journal_enumerate_unique ((j), &(data), &(size)) > 0; ) { | |||
1466 | char **pattern, *eq; | |||
1467 | size_t prefix; | |||
1468 | _cleanup_free___attribute__((cleanup(freep))) char *u = NULL((void*)0); | |||
1469 | ||||
1470 | eq = memchr(data, '=', size); | |||
1471 | if (eq) | |||
1472 | prefix = eq - (char*) data + 1; | |||
1473 | else | |||
1474 | prefix = 0; | |||
1475 | ||||
1476 | u = strndup((char*) data + prefix, size - prefix); | |||
1477 | if (!u) | |||
1478 | return -ENOMEM12; | |||
1479 | ||||
1480 | STRV_FOREACH(pattern, patterns)for ((pattern) = (patterns); (pattern) && *(pattern); (pattern)++) | |||
1481 | if (fnmatch(*pattern, u, FNM_NOESCAPE(1 << 1)) == 0) { | |||
1482 | log_debug("Matched %s with pattern %s=%s", u, field, *pattern)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1482, __func__, "Matched %s with pattern %s=%s" , u, field, *pattern) : -abs(_e); }); | |||
1483 | ||||
1484 | r = set_consume(found, u); | |||
1485 | u = NULL((void*)0); | |||
1486 | if (r < 0 && r != -EEXIST17) | |||
1487 | return r; | |||
1488 | ||||
1489 | break; | |||
1490 | } | |||
1491 | } | |||
1492 | } | |||
1493 | ||||
1494 | *units = TAKE_PTR(found)({ typeof(found) _ptr_ = (found); (found) = ((void*)0); _ptr_ ; }); | |||
1495 | ||||
1496 | return 0; | |||
1497 | } | |||
1498 | ||||
1499 | /* This list is supposed to return the superset of unit names | |||
1500 | * possibly matched by rules added with add_matches_for_unit... */ | |||
1501 | #define SYSTEM_UNITS"_SYSTEMD_UNIT\0" "COREDUMP_UNIT\0" "UNIT\0" "OBJECT_SYSTEMD_UNIT\0" "_SYSTEMD_SLICE\0" \ | |||
1502 | "_SYSTEMD_UNIT\0" \ | |||
1503 | "COREDUMP_UNIT\0" \ | |||
1504 | "UNIT\0" \ | |||
1505 | "OBJECT_SYSTEMD_UNIT\0" \ | |||
1506 | "_SYSTEMD_SLICE\0" | |||
1507 | ||||
1508 | /* ... and add_matches_for_user_unit */ | |||
1509 | #define USER_UNITS"_SYSTEMD_USER_UNIT\0" "USER_UNIT\0" "COREDUMP_USER_UNIT\0" "OBJECT_SYSTEMD_USER_UNIT\0" \ | |||
1510 | "_SYSTEMD_USER_UNIT\0" \ | |||
1511 | "USER_UNIT\0" \ | |||
1512 | "COREDUMP_USER_UNIT\0" \ | |||
1513 | "OBJECT_SYSTEMD_USER_UNIT\0" | |||
1514 | ||||
1515 | static int add_units(sd_journal *j) { | |||
1516 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **patterns = NULL((void*)0); | |||
1517 | int r, count = 0; | |||
1518 | char **i; | |||
1519 | ||||
1520 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/journal/journalctl.c", 1520 , __PRETTY_FUNCTION__); } while (0); | |||
1521 | ||||
1522 | STRV_FOREACH(i, arg_system_units)for ((i) = (arg_system_units); (i) && *(i); (i)++) { | |||
1523 | _cleanup_free___attribute__((cleanup(freep))) char *u = NULL((void*)0); | |||
1524 | ||||
1525 | r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN), &u); | |||
1526 | if (r < 0) | |||
1527 | return r; | |||
1528 | ||||
1529 | if (string_is_glob(u)) { | |||
1530 | r = strv_push(&patterns, u); | |||
1531 | if (r < 0) | |||
1532 | return r; | |||
1533 | u = NULL((void*)0); | |||
1534 | } else { | |||
1535 | r = add_matches_for_unit(j, u); | |||
1536 | if (r < 0) | |||
1537 | return r; | |||
1538 | r = sd_journal_add_disjunction(j); | |||
1539 | if (r < 0) | |||
1540 | return r; | |||
1541 | count++; | |||
1542 | } | |||
1543 | } | |||
1544 | ||||
1545 | if (!strv_isempty(patterns)) { | |||
1546 | _cleanup_set_free_free___attribute__((cleanup(set_free_freep))) Set *units = NULL((void*)0); | |||
1547 | Iterator it; | |||
1548 | char *u; | |||
1549 | ||||
1550 | r = get_possible_units(j, SYSTEM_UNITS"_SYSTEMD_UNIT\0" "COREDUMP_UNIT\0" "UNIT\0" "OBJECT_SYSTEMD_UNIT\0" "_SYSTEMD_SLICE\0", patterns, &units); | |||
1551 | if (r < 0) | |||
1552 | return r; | |||
1553 | ||||
1554 | SET_FOREACH(u, units, it)for ((it) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); set_iterate((units), &(it), (void **)&(u)); ) { | |||
1555 | r = add_matches_for_unit(j, u); | |||
1556 | if (r < 0) | |||
1557 | return r; | |||
1558 | r = sd_journal_add_disjunction(j); | |||
1559 | if (r < 0) | |||
1560 | return r; | |||
1561 | count++; | |||
1562 | } | |||
1563 | } | |||
1564 | ||||
1565 | patterns = strv_free(patterns); | |||
1566 | ||||
1567 | STRV_FOREACH(i, arg_user_units)for ((i) = (arg_user_units); (i) && *(i); (i)++) { | |||
1568 | _cleanup_free___attribute__((cleanup(freep))) char *u = NULL((void*)0); | |||
1569 | ||||
1570 | r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN), &u); | |||
1571 | if (r < 0) | |||
1572 | return r; | |||
1573 | ||||
1574 | if (string_is_glob(u)) { | |||
1575 | r = strv_push(&patterns, u); | |||
1576 | if (r < 0) | |||
1577 | return r; | |||
1578 | u = NULL((void*)0); | |||
1579 | } else { | |||
1580 | r = add_matches_for_user_unit(j, u, getuid()); | |||
1581 | if (r < 0) | |||
1582 | return r; | |||
1583 | r = sd_journal_add_disjunction(j); | |||
1584 | if (r < 0) | |||
1585 | return r; | |||
1586 | count++; | |||
1587 | } | |||
1588 | } | |||
1589 | ||||
1590 | if (!strv_isempty(patterns)) { | |||
1591 | _cleanup_set_free_free___attribute__((cleanup(set_free_freep))) Set *units = NULL((void*)0); | |||
1592 | Iterator it; | |||
1593 | char *u; | |||
1594 | ||||
1595 | r = get_possible_units(j, USER_UNITS"_SYSTEMD_USER_UNIT\0" "USER_UNIT\0" "COREDUMP_USER_UNIT\0" "OBJECT_SYSTEMD_USER_UNIT\0", patterns, &units); | |||
1596 | if (r < 0) | |||
1597 | return r; | |||
1598 | ||||
1599 | SET_FOREACH(u, units, it)for ((it) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); set_iterate((units), &(it), (void **)&(u)); ) { | |||
1600 | r = add_matches_for_user_unit(j, u, getuid()); | |||
1601 | if (r < 0) | |||
1602 | return r; | |||
1603 | r = sd_journal_add_disjunction(j); | |||
1604 | if (r < 0) | |||
1605 | return r; | |||
1606 | count++; | |||
1607 | } | |||
1608 | } | |||
1609 | ||||
1610 | /* Complain if the user request matches but nothing whatsoever was | |||
1611 | * found, since otherwise everything would be matched. */ | |||
1612 | if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0) | |||
1613 | return -ENODATA61; | |||
1614 | ||||
1615 | r = sd_journal_add_conjunction(j); | |||
1616 | if (r < 0) | |||
1617 | return r; | |||
1618 | ||||
1619 | return 0; | |||
1620 | } | |||
1621 | ||||
1622 | static int add_priorities(sd_journal *j) { | |||
1623 | char match[] = "PRIORITY=0"; | |||
1624 | int i, r; | |||
1625 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/journal/journalctl.c", 1625 , __PRETTY_FUNCTION__); } while (0); | |||
1626 | ||||
1627 | if (arg_priorities == 0xFF) | |||
1628 | return 0; | |||
1629 | ||||
1630 | for (i = LOG_EMERG0; i <= LOG_DEBUG7; i++) | |||
1631 | if (arg_priorities & (1 << i)) { | |||
1632 | match[sizeof(match)-2] = '0' + i; | |||
1633 | ||||
1634 | r = sd_journal_add_match(j, match, strlen(match)); | |||
1635 | if (r < 0) | |||
1636 | return log_error_errno(r, "Failed to add match: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1636, __func__, "Failed to add match: %m" ) : -abs(_e); }); | |||
1637 | } | |||
1638 | ||||
1639 | r = sd_journal_add_conjunction(j); | |||
1640 | if (r < 0) | |||
1641 | return log_error_errno(r, "Failed to add conjunction: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1641, __func__, "Failed to add conjunction: %m" ) : -abs(_e); }); | |||
1642 | ||||
1643 | return 0; | |||
1644 | } | |||
1645 | ||||
1646 | static int add_syslog_identifier(sd_journal *j) { | |||
1647 | int r; | |||
1648 | char **i; | |||
1649 | ||||
1650 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/journal/journalctl.c", 1650 , __PRETTY_FUNCTION__); } while (0); | |||
1651 | ||||
1652 | STRV_FOREACH(i, arg_syslog_identifier)for ((i) = (arg_syslog_identifier); (i) && *(i); (i)++ ) { | |||
1653 | char *u; | |||
1654 | ||||
1655 | u = strjoina("SYSLOG_IDENTIFIER=", *i)({ const char *_appendees_[] = { "SYSLOG_IDENTIFIER=", *i }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
1656 | r = sd_journal_add_match(j, u, 0); | |||
1657 | if (r < 0) | |||
1658 | return r; | |||
1659 | r = sd_journal_add_disjunction(j); | |||
1660 | if (r < 0) | |||
1661 | return r; | |||
1662 | } | |||
1663 | ||||
1664 | r = sd_journal_add_conjunction(j); | |||
1665 | if (r < 0) | |||
1666 | return r; | |||
1667 | ||||
1668 | return 0; | |||
1669 | } | |||
1670 | ||||
1671 | static int setup_keys(void) { | |||
1672 | #if HAVE_GCRYPT1 | |||
1673 | size_t mpk_size, seed_size, state_size, i; | |||
1674 | uint8_t *mpk, *seed, *state; | |||
1675 | int fd = -1, r; | |||
1676 | sd_id128_t machine, boot; | |||
1677 | char *p = NULL((void*)0), *k = NULL((void*)0); | |||
1678 | struct FSSHeader h; | |||
1679 | uint64_t n; | |||
1680 | struct stat st; | |||
1681 | ||||
1682 | r = stat("/var/log/journal", &st); | |||
1683 | if (r < 0 && !IN_SET(errno, ENOENT, ENOTDIR)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){2, 20})/sizeof(int)]; switch((*__errno_location ())) { case 2: case 20: _found = 1; break; default: break; } _found; })) | |||
1684 | return log_error_errno(errno, "stat(\"%s\") failed: %m", "/var/log/journal")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 1684, __func__ , "stat(\"%s\") failed: %m", "/var/log/journal") : -abs(_e); } ); | |||
1685 | ||||
1686 | if (r < 0 || !S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) { | |||
1687 | log_error("%s is not a directory, must be using persistent logging for FSS.",({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1688, __func__, "%s is not a directory, must be using persistent logging for FSS." , "/var/log/journal") : -abs(_e); }) | |||
1688 | "/var/log/journal")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1688, __func__, "%s is not a directory, must be using persistent logging for FSS." , "/var/log/journal") : -abs(_e); }); | |||
1689 | return r < 0 ? -errno(*__errno_location ()) : -ENOTDIR20; | |||
1690 | } | |||
1691 | ||||
1692 | r = sd_id128_get_machine(&machine); | |||
1693 | if (r < 0) | |||
1694 | return log_error_errno(r, "Failed to get machine ID: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1694, __func__, "Failed to get machine ID: %m" ) : -abs(_e); }); | |||
1695 | ||||
1696 | r = sd_id128_get_boot(&boot); | |||
1697 | if (r < 0) | |||
1698 | return log_error_errno(r, "Failed to get boot ID: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1698, __func__, "Failed to get boot ID: %m" ) : -abs(_e); }); | |||
1699 | ||||
1700 | if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" "/fss", | |||
1701 | SD_ID128_FORMAT_VAL(machine)(machine).bytes[0], (machine).bytes[1], (machine).bytes[2], ( machine).bytes[3], (machine).bytes[4], (machine).bytes[5], (machine ).bytes[6], (machine).bytes[7], (machine).bytes[8], (machine) .bytes[9], (machine).bytes[10], (machine).bytes[11], (machine ).bytes[12], (machine).bytes[13], (machine).bytes[14], (machine ).bytes[15]) < 0) | |||
1702 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 1702, __func__); | |||
1703 | ||||
1704 | if (arg_force) { | |||
1705 | r = unlink(p); | |||
1706 | if (r < 0 && errno(*__errno_location ()) != ENOENT2) { | |||
1707 | r = log_error_errno(errno, "unlink(\"%s\") failed: %m", p)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 1707, __func__ , "unlink(\"%s\") failed: %m", p) : -abs(_e); }); | |||
1708 | goto finish; | |||
1709 | } | |||
1710 | } else if (access(p, F_OK0) >= 0) { | |||
1711 | log_error("Sealing key file %s exists already. Use --force to recreate.", p)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1711, __func__, "Sealing key file %s exists already. Use --force to recreate." , p) : -abs(_e); }); | |||
1712 | r = -EEXIST17; | |||
1713 | goto finish; | |||
1714 | } | |||
1715 | ||||
1716 | if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" "/fss.tmp.XXXXXX", | |||
1717 | SD_ID128_FORMAT_VAL(machine)(machine).bytes[0], (machine).bytes[1], (machine).bytes[2], ( machine).bytes[3], (machine).bytes[4], (machine).bytes[5], (machine ).bytes[6], (machine).bytes[7], (machine).bytes[8], (machine) .bytes[9], (machine).bytes[10], (machine).bytes[11], (machine ).bytes[12], (machine).bytes[13], (machine).bytes[14], (machine ).bytes[15]) < 0) { | |||
1718 | r = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 1718, __func__); | |||
1719 | goto finish; | |||
1720 | } | |||
1721 | ||||
1722 | mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR1536); | |||
1723 | mpk = alloca(mpk_size)__builtin_alloca (mpk_size); | |||
1724 | ||||
1725 | seed_size = FSPRG_RECOMMENDED_SEEDLEN(96/8); | |||
1726 | seed = alloca(seed_size)__builtin_alloca (seed_size); | |||
1727 | ||||
1728 | state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR1536); | |||
1729 | state = alloca(state_size)__builtin_alloca (state_size); | |||
1730 | ||||
1731 | fd = open("/dev/random", O_RDONLY00|O_CLOEXEC02000000|O_NOCTTY0400); | |||
1732 | if (fd < 0) { | |||
1733 | r = log_error_errno(errno, "Failed to open /dev/random: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 1733, __func__ , "Failed to open /dev/random: %m") : -abs(_e); }); | |||
1734 | goto finish; | |||
1735 | } | |||
1736 | ||||
1737 | log_info("Generating seed...")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1737, __func__, "Generating seed..." ) : -abs(_e); }); | |||
1738 | r = loop_read_exact(fd, seed, seed_size, true1); | |||
1739 | if (r < 0) { | |||
1740 | log_error_errno(r, "Failed to read random seed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1740, __func__, "Failed to read random seed: %m" ) : -abs(_e); }); | |||
1741 | goto finish; | |||
1742 | } | |||
1743 | ||||
1744 | log_info("Generating key pair...")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1744, __func__, "Generating key pair..." ) : -abs(_e); }); | |||
1745 | FSPRG_GenMK(NULL((void*)0), mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR1536); | |||
1746 | ||||
1747 | log_info("Generating sealing key...")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1747, __func__, "Generating sealing key..." ) : -abs(_e); }); | |||
1748 | FSPRG_GenState0(state, mpk, seed, seed_size); | |||
1749 | ||||
1750 | assert(arg_interval > 0)do { if ((__builtin_expect(!!(!(arg_interval > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("arg_interval > 0"), "../src/journal/journalctl.c" , 1750, __PRETTY_FUNCTION__); } while (0); | |||
1751 | ||||
1752 | n = now(CLOCK_REALTIME0); | |||
1753 | n /= arg_interval; | |||
1754 | ||||
1755 | safe_close(fd); | |||
1756 | fd = mkostemp_safe(k); | |||
1757 | if (fd < 0) { | |||
1758 | r = log_error_errno(fd, "Failed to open %s: %m", k)({ int _level = ((3)), _e = ((fd)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1758, __func__, "Failed to open %s: %m" , k) : -abs(_e); }); | |||
1759 | goto finish; | |||
1760 | } | |||
1761 | ||||
1762 | /* Enable secure remove, exclusion from dump, synchronous | |||
1763 | * writing and in-place updating */ | |||
1764 | r = chattr_fd(fd, FS_SECRM_FL0x00000001|FS_NODUMP_FL0x00000040|FS_SYNC_FL0x00000008|FS_NOCOW_FL0x00800000, FS_SECRM_FL0x00000001|FS_NODUMP_FL0x00000040|FS_SYNC_FL0x00000008|FS_NOCOW_FL0x00800000); | |||
1765 | if (r < 0) | |||
1766 | log_warning_errno(r, "Failed to set file attributes: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1766, __func__, "Failed to set file attributes: %m" ) : -abs(_e); }); | |||
1767 | ||||
1768 | zero(h)(({ size_t _l_ = (sizeof(h)); void *_x_ = (&(h)); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | |||
1769 | memcpy(h.signature, "KSHHRHLP", 8); | |||
1770 | h.machine_id = machine; | |||
1771 | h.boot_id = boot; | |||
1772 | h.header_size = htole64(sizeof(h)); | |||
1773 | h.start_usec = htole64(n * arg_interval); | |||
1774 | h.interval_usec = htole64(arg_interval); | |||
1775 | h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR1536); | |||
1776 | h.fsprg_state_size = htole64(state_size); | |||
1777 | ||||
1778 | r = loop_write(fd, &h, sizeof(h), false0); | |||
1779 | if (r < 0) { | |||
1780 | log_error_errno(r, "Failed to write header: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1780, __func__, "Failed to write header: %m" ) : -abs(_e); }); | |||
1781 | goto finish; | |||
1782 | } | |||
1783 | ||||
1784 | r = loop_write(fd, state, state_size, false0); | |||
1785 | if (r < 0) { | |||
1786 | log_error_errno(r, "Failed to write state: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1786, __func__, "Failed to write state: %m" ) : -abs(_e); }); | |||
1787 | goto finish; | |||
1788 | } | |||
1789 | ||||
1790 | if (link(k, p) < 0) { | |||
1791 | r = log_error_errno(errno, "Failed to link file: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 1791, __func__ , "Failed to link file: %m") : -abs(_e); }); | |||
1792 | goto finish; | |||
1793 | } | |||
1794 | ||||
1795 | if (on_tty()) { | |||
1796 | fprintf(stderrstderr, | |||
1797 | "\n" | |||
1798 | "The new key pair has been generated. The %ssecret sealing key%s has been written to\n" | |||
1799 | "the following local file. This key file is automatically updated when the\n" | |||
1800 | "sealing key is advanced. It should not be used on multiple hosts.\n" | |||
1801 | "\n" | |||
1802 | "\t%s\n" | |||
1803 | "\n" | |||
1804 | "Please write down the following %ssecret verification key%s. It should be stored\n" | |||
1805 | "at a safe location and should not be saved locally on disk.\n" | |||
1806 | "\n\t%s", | |||
1807 | ansi_highlight(), ansi_normal(), | |||
1808 | p, | |||
1809 | ansi_highlight(), ansi_normal(), | |||
1810 | ansi_highlight_red()); | |||
1811 | fflush(stderrstderr); | |||
1812 | } | |||
1813 | for (i = 0; i < seed_size; i++) { | |||
1814 | if (i > 0 && i % 3 == 0) | |||
1815 | putchar('-'); | |||
1816 | printf("%02x", ((uint8_t*) seed)[i]); | |||
1817 | } | |||
1818 | ||||
1819 | printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval); | |||
1820 | ||||
1821 | if (on_tty()) { | |||
1822 | char tsb[FORMAT_TIMESPAN_MAX64], *hn; | |||
1823 | ||||
1824 | fprintf(stderrstderr, | |||
1825 | "%s\n" | |||
1826 | "The sealing key is automatically changed every %s.\n", | |||
1827 | ansi_normal(), | |||
1828 | format_timespan(tsb, sizeof(tsb), arg_interval, 0)); | |||
1829 | ||||
1830 | hn = gethostname_malloc(); | |||
1831 | ||||
1832 | if (hn) { | |||
1833 | hostname_cleanup(hn); | |||
1834 | fprintf(stderrstderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ".\n", hn, SD_ID128_FORMAT_VAL(machine)(machine).bytes[0], (machine).bytes[1], (machine).bytes[2], ( machine).bytes[3], (machine).bytes[4], (machine).bytes[5], (machine ).bytes[6], (machine).bytes[7], (machine).bytes[8], (machine) .bytes[9], (machine).bytes[10], (machine).bytes[11], (machine ).bytes[12], (machine).bytes[13], (machine).bytes[14], (machine ).bytes[15]); | |||
1835 | } else | |||
1836 | fprintf(stderrstderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ".\n", SD_ID128_FORMAT_VAL(machine)(machine).bytes[0], (machine).bytes[1], (machine).bytes[2], ( machine).bytes[3], (machine).bytes[4], (machine).bytes[5], (machine ).bytes[6], (machine).bytes[7], (machine).bytes[8], (machine) .bytes[9], (machine).bytes[10], (machine).bytes[11], (machine ).bytes[12], (machine).bytes[13], (machine).bytes[14], (machine ).bytes[15]); | |||
1837 | ||||
1838 | #if HAVE_QRENCODE1 | |||
1839 | /* If this is not an UTF-8 system don't print any QR codes */ | |||
1840 | if (is_locale_utf8()) { | |||
1841 | fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderrstderr); | |||
1842 | print_qr_code(stderrstderr, seed, seed_size, n, arg_interval, hn, machine); | |||
1843 | } | |||
1844 | #endif | |||
1845 | free(hn); | |||
1846 | } | |||
1847 | ||||
1848 | r = 0; | |||
1849 | ||||
1850 | finish: | |||
1851 | safe_close(fd); | |||
1852 | ||||
1853 | if (k) { | |||
1854 | unlink(k); | |||
1855 | free(k); | |||
1856 | } | |||
1857 | ||||
1858 | free(p); | |||
1859 | ||||
1860 | return r; | |||
1861 | #else | |||
1862 | log_error("Forward-secure sealing not available.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1862, __func__, "Forward-secure sealing not available." ) : -abs(_e); }); | |||
1863 | return -EOPNOTSUPP95; | |||
1864 | #endif | |||
1865 | } | |||
1866 | ||||
1867 | static int verify(sd_journal *j) { | |||
1868 | int r = 0; | |||
1869 | Iterator i; | |||
1870 | JournalFile *f; | |||
1871 | ||||
1872 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/journal/journalctl.c", 1872 , __PRETTY_FUNCTION__); } while (0); | |||
1873 | ||||
1874 | log_show_color(true1); | |||
1875 | ||||
1876 | ORDERED_HASHMAP_FOREACH(f, j->files, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); ordered_hashmap_iterate((j->files ), &(i), (void**)&(f), ((void*)0)); ) { | |||
1877 | int k; | |||
1878 | usec_t first = 0, validated = 0, last = 0; | |||
1879 | ||||
1880 | #if HAVE_GCRYPT1 | |||
1881 | if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header)(!!(le32toh((f->header)->compatible_flags) & HEADER_COMPATIBLE_SEALED ))) | |||
1882 | log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path)({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1882, __func__, "Journal file %s has sealing enabled but verification key has not been passed using --verify-key=." , f->path) : -abs(_e); }); | |||
1883 | #endif | |||
1884 | ||||
1885 | k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true1); | |||
1886 | if (k == -EINVAL22) { | |||
1887 | /* If the key was invalid give up right-away. */ | |||
1888 | return k; | |||
1889 | } else if (k < 0) { | |||
1890 | log_warning_errno(k, "FAIL: %s (%m)", f->path)({ int _level = ((4)), _e = ((k)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1890, __func__, "FAIL: %s (%m)" , f->path) : -abs(_e); }); | |||
1891 | r = k; | |||
1892 | } else { | |||
1893 | char a[FORMAT_TIMESTAMP_MAX(3+1+10+1+8+1+6+1+6+1)], b[FORMAT_TIMESTAMP_MAX(3+1+10+1+8+1+6+1+6+1)], c[FORMAT_TIMESPAN_MAX64]; | |||
1894 | log_info("PASS: %s", f->path)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1894, __func__, "PASS: %s", f ->path) : -abs(_e); }); | |||
1895 | ||||
1896 | if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)(!!(le32toh((f->header)->compatible_flags) & HEADER_COMPATIBLE_SEALED ))) { | |||
1897 | if (validated > 0) { | |||
1898 | log_info("=> Validated from %s to %s, final %s entries not sealed.",({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1901, __func__, "=> Validated from %s to %s, final %s entries not sealed." , format_timestamp_maybe_utc(a, sizeof(a), first), format_timestamp_maybe_utc (b, sizeof(b), validated), format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0)) : -abs(_e); }) | |||
1899 | format_timestamp_maybe_utc(a, sizeof(a), first),({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1901, __func__, "=> Validated from %s to %s, final %s entries not sealed." , format_timestamp_maybe_utc(a, sizeof(a), first), format_timestamp_maybe_utc (b, sizeof(b), validated), format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0)) : -abs(_e); }) | |||
1900 | format_timestamp_maybe_utc(b, sizeof(b), validated),({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1901, __func__, "=> Validated from %s to %s, final %s entries not sealed." , format_timestamp_maybe_utc(a, sizeof(a), first), format_timestamp_maybe_utc (b, sizeof(b), validated), format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0)) : -abs(_e); }) | |||
1901 | format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0))({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1901, __func__, "=> Validated from %s to %s, final %s entries not sealed." , format_timestamp_maybe_utc(a, sizeof(a), first), format_timestamp_maybe_utc (b, sizeof(b), validated), format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0)) : -abs(_e); }); | |||
1902 | } else if (last > 0) | |||
1903 | log_info("=> No sealing yet, %s of entries not sealed.",({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1904, __func__, "=> No sealing yet, %s of entries not sealed." , format_timespan(c, sizeof(c), last - first, 0)) : -abs(_e); }) | |||
1904 | format_timespan(c, sizeof(c), last - first, 0))({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1904, __func__, "=> No sealing yet, %s of entries not sealed." , format_timespan(c, sizeof(c), last - first, 0)) : -abs(_e); }); | |||
1905 | else | |||
1906 | log_info("=> No sealing yet, no entries in file.")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1906, __func__, "=> No sealing yet, no entries in file." ) : -abs(_e); }); | |||
1907 | } | |||
1908 | } | |||
1909 | } | |||
1910 | ||||
1911 | return r; | |||
1912 | } | |||
1913 | ||||
1914 | static int flush_to_var(void) { | |||
1915 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
1916 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
1917 | _cleanup_close___attribute__((cleanup(closep))) int watch_fd = -1; | |||
1918 | int r; | |||
1919 | ||||
1920 | if (arg_machine) { | |||
1921 | log_error("--flush is not supported in conjunction with --machine=.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1921, __func__, "--flush is not supported in conjunction with --machine=." ) : -abs(_e); }); | |||
1922 | return -EOPNOTSUPP95; | |||
1923 | } | |||
1924 | ||||
1925 | /* Quick exit */ | |||
1926 | if (access("/run/systemd/journal/flushed", F_OK0) >= 0) | |||
1927 | return 0; | |||
1928 | ||||
1929 | /* OK, let's actually do the full logic, send SIGUSR1 to the | |||
1930 | * daemon and set up inotify to wait for the flushed file to appear */ | |||
1931 | r = bus_connect_system_systemd(&bus); | |||
1932 | if (r < 0) | |||
1933 | return log_error_errno(r, "Failed to get D-Bus connection: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1933, __func__, "Failed to get D-Bus connection: %m" ) : -abs(_e); }); | |||
1934 | ||||
1935 | r = sd_bus_call_method( | |||
1936 | bus, | |||
1937 | "org.freedesktop.systemd1", | |||
1938 | "/org/freedesktop/systemd1", | |||
1939 | "org.freedesktop.systemd1.Manager", | |||
1940 | "KillUnit", | |||
1941 | &error, | |||
1942 | NULL((void*)0), | |||
1943 | "ssi", "systemd-journald.service", "main", SIGUSR110); | |||
1944 | if (r < 0) | |||
1945 | return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1945, __func__, "Failed to kill journal service: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
1946 | ||||
1947 | mkdir_p("/run/systemd/journal", 0755); | |||
1948 | ||||
1949 | watch_fd = inotify_init1(IN_NONBLOCKIN_NONBLOCK|IN_CLOEXECIN_CLOEXEC); | |||
1950 | if (watch_fd < 0) | |||
1951 | return log_error_errno(errno, "Failed to create inotify watch: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 1951, __func__ , "Failed to create inotify watch: %m") : -abs(_e); }); | |||
1952 | ||||
1953 | r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE0x00000100|IN_DONT_FOLLOW0x02000000|IN_ONLYDIR0x01000000); | |||
1954 | if (r < 0) | |||
1955 | return log_error_errno(errno, "Failed to watch journal directory: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 1955, __func__ , "Failed to watch journal directory: %m") : -abs(_e); }); | |||
1956 | ||||
1957 | for (;;) { | |||
1958 | if (access("/run/systemd/journal/flushed", F_OK0) >= 0) | |||
1959 | break; | |||
1960 | ||||
1961 | if (errno(*__errno_location ()) != ENOENT2) | |||
1962 | return log_error_errno(errno, "Failed to check for existence of /run/systemd/journal/flushed: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 1962, __func__ , "Failed to check for existence of /run/systemd/journal/flushed: %m" ) : -abs(_e); }); | |||
1963 | ||||
1964 | r = fd_wait_for_event(watch_fd, POLLIN0x001, USEC_INFINITY((usec_t) -1)); | |||
1965 | if (r < 0) | |||
1966 | return log_error_errno(r, "Failed to wait for event: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1966, __func__, "Failed to wait for event: %m" ) : -abs(_e); }); | |||
1967 | ||||
1968 | r = flush_fd(watch_fd); | |||
1969 | if (r < 0) | |||
1970 | return log_error_errno(r, "Failed to flush inotify events: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1970, __func__, "Failed to flush inotify events: %m" ) : -abs(_e); }); | |||
1971 | } | |||
1972 | ||||
1973 | return 0; | |||
1974 | } | |||
1975 | ||||
1976 | static int send_signal_and_wait(int sig, const char *watch_path) { | |||
1977 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
1978 | _cleanup_close___attribute__((cleanup(closep))) int watch_fd = -1; | |||
1979 | usec_t start; | |||
1980 | int r; | |||
1981 | ||||
1982 | if (arg_machine) { | |||
1983 | log_error("--sync and --rotate are not supported in conjunction with --machine=.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 1983, __func__, "--sync and --rotate are not supported in conjunction with --machine=." ) : -abs(_e); }); | |||
1984 | return -EOPNOTSUPP95; | |||
1985 | } | |||
1986 | ||||
1987 | start = now(CLOCK_MONOTONIC1); | |||
1988 | ||||
1989 | /* This call sends the specified signal to journald, and waits | |||
1990 | * for acknowledgment by watching the mtime of the specified | |||
1991 | * flag file. This is used to trigger syncing or rotation and | |||
1992 | * then wait for the operation to complete. */ | |||
1993 | ||||
1994 | for (;;) { | |||
1995 | usec_t tstamp; | |||
1996 | ||||
1997 | /* See if a sync happened by now. */ | |||
1998 | r = read_timestamp_file(watch_path, &tstamp); | |||
1999 | if (r < 0 && r != -ENOENT2) | |||
2000 | return log_error_errno(errno, "Failed to read %s: %m", watch_path)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 2000, __func__ , "Failed to read %s: %m", watch_path) : -abs(_e); }); | |||
2001 | if (r >= 0 && tstamp >= start) | |||
2002 | return 0; | |||
2003 | ||||
2004 | /* Let's ask for a sync, but only once. */ | |||
2005 | if (!bus) { | |||
2006 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
2007 | ||||
2008 | r = bus_connect_system_systemd(&bus); | |||
2009 | if (r < 0) | |||
2010 | return log_error_errno(r, "Failed to get D-Bus connection: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2010, __func__, "Failed to get D-Bus connection: %m" ) : -abs(_e); }); | |||
2011 | ||||
2012 | r = sd_bus_call_method( | |||
2013 | bus, | |||
2014 | "org.freedesktop.systemd1", | |||
2015 | "/org/freedesktop/systemd1", | |||
2016 | "org.freedesktop.systemd1.Manager", | |||
2017 | "KillUnit", | |||
2018 | &error, | |||
2019 | NULL((void*)0), | |||
2020 | "ssi", "systemd-journald.service", "main", sig); | |||
2021 | if (r < 0) | |||
2022 | return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2022, __func__, "Failed to kill journal service: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
2023 | ||||
2024 | continue; | |||
2025 | } | |||
2026 | ||||
2027 | /* Let's install the inotify watch, if we didn't do that yet. */ | |||
2028 | if (watch_fd < 0) { | |||
2029 | ||||
2030 | mkdir_p("/run/systemd/journal", 0755); | |||
2031 | ||||
2032 | watch_fd = inotify_init1(IN_NONBLOCKIN_NONBLOCK|IN_CLOEXECIN_CLOEXEC); | |||
2033 | if (watch_fd < 0) | |||
2034 | return log_error_errno(errno, "Failed to create inotify watch: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 2034, __func__ , "Failed to create inotify watch: %m") : -abs(_e); }); | |||
2035 | ||||
2036 | r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_MOVED_TO0x00000080|IN_DONT_FOLLOW0x02000000|IN_ONLYDIR0x01000000); | |||
2037 | if (r < 0) | |||
2038 | return log_error_errno(errno, "Failed to watch journal directory: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 2038, __func__ , "Failed to watch journal directory: %m") : -abs(_e); }); | |||
2039 | ||||
2040 | /* Recheck the flag file immediately, so that we don't miss any event since the last check. */ | |||
2041 | continue; | |||
2042 | } | |||
2043 | ||||
2044 | /* OK, all preparatory steps done, let's wait until | |||
2045 | * inotify reports an event. */ | |||
2046 | ||||
2047 | r = fd_wait_for_event(watch_fd, POLLIN0x001, USEC_INFINITY((usec_t) -1)); | |||
2048 | if (r < 0) | |||
2049 | return log_error_errno(r, "Failed to wait for event: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2049, __func__, "Failed to wait for event: %m" ) : -abs(_e); }); | |||
2050 | ||||
2051 | r = flush_fd(watch_fd); | |||
2052 | if (r < 0) | |||
2053 | return log_error_errno(r, "Failed to flush inotify events: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2053, __func__, "Failed to flush inotify events: %m" ) : -abs(_e); }); | |||
2054 | } | |||
2055 | ||||
2056 | return 0; | |||
2057 | } | |||
2058 | ||||
2059 | static int rotate(void) { | |||
2060 | return send_signal_and_wait(SIGUSR212, "/run/systemd/journal/rotated"); | |||
2061 | } | |||
2062 | ||||
2063 | static int sync_journal(void) { | |||
2064 | return send_signal_and_wait(SIGRTMIN(__libc_current_sigrtmin ())+1, "/run/systemd/journal/synced"); | |||
2065 | } | |||
2066 | ||||
2067 | int main(int argc, char *argv[]) { | |||
2068 | int r; | |||
2069 | _cleanup_(sd_journal_closep)__attribute__((cleanup(sd_journal_closep))) sd_journal *j = NULL((void*)0); | |||
2070 | bool_Bool need_seek = false0; | |||
2071 | sd_id128_t previous_boot_id; | |||
2072 | bool_Bool previous_boot_id_valid = false0, first_line = true1; | |||
2073 | int n_shown = 0; | |||
2074 | bool_Bool ellipsized = false0; | |||
2075 | ||||
2076 | setlocale(LC_ALL6, ""); | |||
2077 | log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD); | |||
2078 | log_open(); | |||
2079 | ||||
2080 | r = parse_argv(argc, argv); | |||
2081 | if (r <= 0) | |||
2082 | goto finish; | |||
2083 | ||||
2084 | signal(SIGWINCH28, columns_lines_cache_reset); | |||
2085 | sigbus_install(); | |||
2086 | ||||
2087 | /* Increase max number of open files to 16K if we can, we | |||
2088 | * might needs this when browsing journal files, which might | |||
2089 | * be split up into many files. */ | |||
2090 | setrlimit_closest(RLIMIT_NOFILERLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384)((struct rlimit) { 16384, 16384 })); | |||
2091 | ||||
2092 | switch (arg_action) { | |||
2093 | ||||
2094 | case ACTION_NEW_ID128: | |||
2095 | r = generate_new_id128(); | |||
2096 | goto finish; | |||
2097 | ||||
2098 | case ACTION_SETUP_KEYS: | |||
2099 | r = setup_keys(); | |||
2100 | goto finish; | |||
2101 | ||||
2102 | case ACTION_LIST_CATALOG: | |||
2103 | case ACTION_DUMP_CATALOG: | |||
2104 | case ACTION_UPDATE_CATALOG: { | |||
2105 | _cleanup_free___attribute__((cleanup(freep))) char *database; | |||
2106 | ||||
2107 | database = path_join(arg_root, CATALOG_DATABASE"/var/lib/systemd/catalog/database", NULL((void*)0)); | |||
2108 | if (!database) { | |||
2109 | r = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 2109, __func__); | |||
2110 | goto finish; | |||
2111 | } | |||
2112 | ||||
2113 | if (arg_action == ACTION_UPDATE_CATALOG) { | |||
2114 | r = catalog_update(database, arg_root, catalog_file_dirs); | |||
2115 | if (r < 0) | |||
2116 | log_error_errno(r, "Failed to list catalog: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2116, __func__, "Failed to list catalog: %m" ) : -abs(_e); }); | |||
2117 | } else { | |||
2118 | bool_Bool oneline = arg_action == ACTION_LIST_CATALOG; | |||
2119 | ||||
2120 | (void) pager_open(arg_no_pager, arg_pager_end); | |||
2121 | ||||
2122 | if (optind < argc) | |||
2123 | r = catalog_list_items(stdoutstdout, database, oneline, argv + optind); | |||
2124 | else | |||
2125 | r = catalog_list(stdoutstdout, database, oneline); | |||
2126 | if (r < 0) | |||
2127 | log_error_errno(r, "Failed to list catalog: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2127, __func__, "Failed to list catalog: %m" ) : -abs(_e); }); | |||
2128 | } | |||
2129 | ||||
2130 | goto finish; | |||
2131 | } | |||
2132 | ||||
2133 | case ACTION_FLUSH: | |||
2134 | r = flush_to_var(); | |||
2135 | goto finish; | |||
2136 | ||||
2137 | case ACTION_SYNC: | |||
2138 | r = sync_journal(); | |||
2139 | goto finish; | |||
2140 | ||||
2141 | case ACTION_ROTATE: | |||
2142 | r = rotate(); | |||
2143 | goto finish; | |||
2144 | ||||
2145 | case ACTION_SHOW: | |||
2146 | case ACTION_PRINT_HEADER: | |||
2147 | case ACTION_VERIFY: | |||
2148 | case ACTION_DISK_USAGE: | |||
2149 | case ACTION_LIST_BOOTS: | |||
2150 | case ACTION_VACUUM: | |||
2151 | case ACTION_LIST_FIELDS: | |||
2152 | case ACTION_LIST_FIELD_NAMES: | |||
2153 | /* These ones require access to the journal files, continue below. */ | |||
2154 | break; | |||
2155 | ||||
2156 | default: | |||
2157 | assert_not_reached("Unknown action")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unknown action"), "../src/journal/journalctl.c", 2157, __PRETTY_FUNCTION__ ); } while (0); | |||
2158 | } | |||
2159 | ||||
2160 | if (arg_directory) | |||
2161 | r = sd_journal_open_directory(&j, arg_directory, arg_journal_type); | |||
2162 | else if (arg_root) | |||
2163 | r = sd_journal_open_directory(&j, arg_root, arg_journal_type | SD_JOURNAL_OS_ROOT); | |||
2164 | else if (arg_file_stdin) { | |||
2165 | int ifd = STDIN_FILENO0; | |||
2166 | r = sd_journal_open_files_fd(&j, &ifd, 1, 0); | |||
2167 | } else if (arg_file) | |||
2168 | r = sd_journal_open_files(&j, (const char**) arg_file, 0); | |||
2169 | else if (arg_machine) { | |||
2170 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
2171 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL((void*)0); | |||
2172 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
2173 | int fd; | |||
2174 | ||||
2175 | if (geteuid() != 0) { | |||
2176 | /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of | |||
2177 | * the container, thus we need root privileges to override them. */ | |||
2178 | log_error("Using the --machine= switch requires root privileges.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2178, __func__, "Using the --machine= switch requires root privileges." ) : -abs(_e); }); | |||
2179 | r = -EPERM1; | |||
2180 | goto finish; | |||
2181 | } | |||
2182 | ||||
2183 | r = sd_bus_open_system(&bus); | |||
2184 | if (r < 0) { | |||
2185 | log_error_errno(r, "Failed to open system bus: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2185, __func__, "Failed to open system bus: %m" ) : -abs(_e); }); | |||
2186 | goto finish; | |||
2187 | } | |||
2188 | ||||
2189 | r = sd_bus_call_method( | |||
2190 | bus, | |||
2191 | "org.freedesktop.machine1", | |||
2192 | "/org/freedesktop/machine1", | |||
2193 | "org.freedesktop.machine1.Manager", | |||
2194 | "OpenMachineRootDirectory", | |||
2195 | &error, | |||
2196 | &reply, | |||
2197 | "s", arg_machine); | |||
2198 | if (r < 0) { | |||
2199 | log_error_errno(r, "Failed to open root directory: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2199, __func__, "Failed to open root directory: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
2200 | goto finish; | |||
2201 | } | |||
2202 | ||||
2203 | r = sd_bus_message_read(reply, "h", &fd); | |||
2204 | if (r < 0) { | |||
2205 | bus_log_parse_error(r); | |||
2206 | goto finish; | |||
2207 | } | |||
2208 | ||||
2209 | fd = fcntl(fd, F_DUPFD_CLOEXEC1030, 3); | |||
2210 | if (fd < 0) { | |||
2211 | r = log_error_errno(errno, "Failed to duplicate file descriptor: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/journalctl.c", 2211, __func__ , "Failed to duplicate file descriptor: %m") : -abs(_e); }); | |||
2212 | goto finish; | |||
2213 | } | |||
2214 | ||||
2215 | r = sd_journal_open_directory_fd(&j, fd, SD_JOURNAL_OS_ROOT); | |||
2216 | if (r < 0) | |||
2217 | safe_close(fd); | |||
2218 | } else | |||
2219 | r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type); | |||
2220 | if (r < 0) { | |||
2221 | log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2221, __func__, "Failed to open %s: %m" , arg_directory ?: arg_file ? "files" : "journal") : -abs(_e) ; }); | |||
2222 | goto finish; | |||
2223 | } | |||
2224 | ||||
2225 | r = journal_access_check_and_warn(j, arg_quiet, | |||
2226 | !(arg_journal_type == SD_JOURNAL_CURRENT_USER || arg_user_units)); | |||
2227 | if (r < 0) | |||
2228 | goto finish; | |||
2229 | ||||
2230 | switch (arg_action) { | |||
2231 | ||||
2232 | case ACTION_NEW_ID128: | |||
2233 | case ACTION_SETUP_KEYS: | |||
2234 | case ACTION_LIST_CATALOG: | |||
2235 | case ACTION_DUMP_CATALOG: | |||
2236 | case ACTION_UPDATE_CATALOG: | |||
2237 | case ACTION_FLUSH: | |||
2238 | case ACTION_SYNC: | |||
2239 | case ACTION_ROTATE: | |||
2240 | assert_not_reached("Unexpected action.")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unexpected action."), "../src/journal/journalctl.c", 2240, __PRETTY_FUNCTION__ ); } while (0); | |||
2241 | ||||
2242 | case ACTION_PRINT_HEADER: | |||
2243 | journal_print_header(j); | |||
2244 | r = 0; | |||
2245 | goto finish; | |||
2246 | ||||
2247 | case ACTION_VERIFY: | |||
2248 | r = verify(j); | |||
2249 | goto finish; | |||
2250 | ||||
2251 | case ACTION_DISK_USAGE: { | |||
2252 | uint64_t bytes = 0; | |||
2253 | char sbytes[FORMAT_BYTES_MAX8]; | |||
2254 | ||||
2255 | r = sd_journal_get_usage(j, &bytes); | |||
2256 | if (r < 0) | |||
2257 | goto finish; | |||
2258 | ||||
2259 | printf("Archived and active journals take up %s in the file system.\n", | |||
2260 | format_bytes(sbytes, sizeof(sbytes), bytes)); | |||
2261 | goto finish; | |||
2262 | } | |||
2263 | ||||
2264 | case ACTION_LIST_BOOTS: | |||
2265 | r = list_boots(j); | |||
2266 | goto finish; | |||
2267 | ||||
2268 | case ACTION_VACUUM: { | |||
2269 | Directory *d; | |||
2270 | Iterator i; | |||
2271 | ||||
2272 | HASHMAP_FOREACH(d, j->directories_by_path, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((j->directories_by_path ), &(i), (void**)&(d), ((void*)0)); ) { | |||
2273 | int q; | |||
2274 | ||||
2275 | if (d->is_root) | |||
2276 | continue; | |||
2277 | ||||
2278 | q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL((void*)0), !arg_quiet); | |||
2279 | if (q < 0) { | |||
2280 | log_error_errno(q, "Failed to vacuum %s: %m", d->path)({ int _level = ((3)), _e = ((q)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2280, __func__, "Failed to vacuum %s: %m" , d->path) : -abs(_e); }); | |||
2281 | r = q; | |||
2282 | } | |||
2283 | } | |||
2284 | ||||
2285 | goto finish; | |||
2286 | } | |||
2287 | ||||
2288 | case ACTION_LIST_FIELD_NAMES: { | |||
2289 | const char *field; | |||
2290 | ||||
2291 | SD_JOURNAL_FOREACH_FIELD(j, field)for (sd_journal_restart_fields(j); sd_journal_enumerate_fields ((j), &(field)) > 0; ) { | |||
2292 | printf("%s\n", field); | |||
2293 | n_shown++; | |||
2294 | } | |||
2295 | ||||
2296 | r = 0; | |||
2297 | goto finish; | |||
2298 | } | |||
2299 | ||||
2300 | case ACTION_SHOW: | |||
2301 | case ACTION_LIST_FIELDS: | |||
2302 | break; | |||
2303 | ||||
2304 | default: | |||
2305 | assert_not_reached("Unknown action")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unknown action"), "../src/journal/journalctl.c", 2305, __PRETTY_FUNCTION__ ); } while (0); | |||
2306 | } | |||
2307 | ||||
2308 | if (arg_boot_offset != 0 && | |||
2309 | sd_journal_has_runtime_files(j) > 0 && | |||
2310 | sd_journal_has_persistent_files(j) == 0) { | |||
2311 | log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2311, __func__, "Specifying boot ID or boot offset has no effect, no persistent journal was found." ) : -abs(_e); }); | |||
2312 | r = 0; | |||
2313 | goto finish; | |||
2314 | } | |||
2315 | /* add_boot() must be called first! | |||
2316 | * It may need to seek the journal to find parent boot IDs. */ | |||
2317 | r = add_boot(j); | |||
2318 | if (r < 0) | |||
2319 | goto finish; | |||
2320 | ||||
2321 | r = add_dmesg(j); | |||
2322 | if (r < 0) | |||
2323 | goto finish; | |||
2324 | ||||
2325 | r = add_units(j); | |||
2326 | if (r < 0) { | |||
2327 | log_error_errno(r, "Failed to add filter for units: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2327, __func__, "Failed to add filter for units: %m" ) : -abs(_e); }); | |||
2328 | goto finish; | |||
2329 | } | |||
2330 | ||||
2331 | r = add_syslog_identifier(j); | |||
2332 | if (r < 0) { | |||
2333 | log_error_errno(r, "Failed to add filter for syslog identifiers: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2333, __func__, "Failed to add filter for syslog identifiers: %m" ) : -abs(_e); }); | |||
2334 | goto finish; | |||
2335 | } | |||
2336 | ||||
2337 | r = add_priorities(j); | |||
2338 | if (r < 0) | |||
2339 | goto finish; | |||
2340 | ||||
2341 | r = add_matches(j, argv + optind); | |||
2342 | if (r < 0) | |||
2343 | goto finish; | |||
2344 | ||||
2345 | if (DEBUG_LOGGING(__builtin_expect(!!(log_get_max_level_realm(LOG_REALM_SYSTEMD ) >= 7),0))) { | |||
2346 | _cleanup_free___attribute__((cleanup(freep))) char *filter; | |||
2347 | ||||
2348 | filter = journal_make_match_string(j); | |||
2349 | if (!filter) | |||
2350 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 2350, __func__); | |||
2351 | ||||
2352 | log_debug("Journal filter: %s", filter)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2352, __func__, "Journal filter: %s" , filter) : -abs(_e); }); | |||
2353 | } | |||
2354 | ||||
2355 | if (arg_action == ACTION_LIST_FIELDS) { | |||
2356 | const void *data; | |||
2357 | size_t size; | |||
2358 | ||||
2359 | assert(arg_field)do { if ((__builtin_expect(!!(!(arg_field)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("arg_field"), "../src/journal/journalctl.c" , 2359, __PRETTY_FUNCTION__); } while (0); | |||
2360 | ||||
2361 | r = sd_journal_set_data_threshold(j, 0); | |||
2362 | if (r < 0) { | |||
2363 | log_error_errno(r, "Failed to unset data size threshold: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2363, __func__, "Failed to unset data size threshold: %m" ) : -abs(_e); }); | |||
2364 | goto finish; | |||
2365 | } | |||
2366 | ||||
2367 | r = sd_journal_query_unique(j, arg_field); | |||
2368 | if (r < 0) { | |||
2369 | log_error_errno(r, "Failed to query unique data objects: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2369, __func__, "Failed to query unique data objects: %m" ) : -abs(_e); }); | |||
2370 | goto finish; | |||
2371 | } | |||
2372 | ||||
2373 | SD_JOURNAL_FOREACH_UNIQUE(j, data, size)for (sd_journal_restart_unique(j); sd_journal_enumerate_unique ((j), &(data), &(size)) > 0; ) { | |||
2374 | const void *eq; | |||
2375 | ||||
2376 | if (arg_lines >= 0 && n_shown >= arg_lines) | |||
2377 | break; | |||
2378 | ||||
2379 | eq = memchr(data, '=', size); | |||
2380 | if (eq) | |||
2381 | printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1); | |||
2382 | else | |||
2383 | printf("%.*s\n", (int) size, (const char*) data); | |||
2384 | ||||
2385 | n_shown++; | |||
2386 | } | |||
2387 | ||||
2388 | r = 0; | |||
2389 | goto finish; | |||
2390 | } | |||
2391 | ||||
2392 | /* Opening the fd now means the first sd_journal_wait() will actually wait */ | |||
2393 | if (arg_follow) { | |||
2394 | r = sd_journal_get_fd(j); | |||
2395 | if (r == -EMFILE24) { | |||
2396 | log_warning("Insufficent watch descriptors available. Reverting to -n.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2396, __func__, "Insufficent watch descriptors available. Reverting to -n." ) : -abs(_e); }); | |||
2397 | arg_follow = false0; | |||
2398 | } else if (r == -EMEDIUMTYPE124) { | |||
2399 | log_error_errno(r, "The --follow switch is not supported in conjunction with reading from STDIN.")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2399, __func__, "The --follow switch is not supported in conjunction with reading from STDIN." ) : -abs(_e); }); | |||
2400 | goto finish; | |||
2401 | } else if (r < 0) { | |||
2402 | log_error_errno(r, "Failed to get journal fd: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2402, __func__, "Failed to get journal fd: %m" ) : -abs(_e); }); | |||
2403 | goto finish; | |||
2404 | } | |||
2405 | } | |||
2406 | ||||
2407 | if (arg_cursor || arg_after_cursor) { | |||
2408 | r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor); | |||
2409 | if (r < 0) { | |||
2410 | log_error_errno(r, "Failed to seek to cursor: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2410, __func__, "Failed to seek to cursor: %m" ) : -abs(_e); }); | |||
2411 | goto finish; | |||
2412 | } | |||
2413 | ||||
2414 | if (!arg_reverse) | |||
2415 | r = sd_journal_next_skip(j, 1 + !!arg_after_cursor); | |||
2416 | else | |||
2417 | r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor); | |||
2418 | ||||
2419 | if (arg_after_cursor && r < 2) { | |||
2420 | /* We couldn't find the next entry after the cursor. */ | |||
2421 | if (arg_follow) | |||
2422 | need_seek = true1; | |||
2423 | else | |||
2424 | arg_lines = 0; | |||
2425 | } | |||
2426 | ||||
2427 | } else if (arg_since_set && !arg_reverse) { | |||
2428 | r = sd_journal_seek_realtime_usec(j, arg_since); | |||
2429 | if (r < 0) { | |||
2430 | log_error_errno(r, "Failed to seek to date: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2430, __func__, "Failed to seek to date: %m" ) : -abs(_e); }); | |||
2431 | goto finish; | |||
2432 | } | |||
2433 | r = sd_journal_next(j); | |||
2434 | ||||
2435 | } else if (arg_until_set && arg_reverse) { | |||
2436 | r = sd_journal_seek_realtime_usec(j, arg_until); | |||
2437 | if (r < 0) { | |||
2438 | log_error_errno(r, "Failed to seek to date: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2438, __func__, "Failed to seek to date: %m" ) : -abs(_e); }); | |||
2439 | goto finish; | |||
2440 | } | |||
2441 | r = sd_journal_previous(j); | |||
2442 | ||||
2443 | } else if (arg_lines >= 0) { | |||
2444 | r = sd_journal_seek_tail(j); | |||
2445 | if (r < 0) { | |||
2446 | log_error_errno(r, "Failed to seek to tail: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2446, __func__, "Failed to seek to tail: %m" ) : -abs(_e); }); | |||
2447 | goto finish; | |||
2448 | } | |||
2449 | ||||
2450 | r = sd_journal_previous_skip(j, arg_lines); | |||
2451 | ||||
2452 | } else if (arg_reverse) { | |||
2453 | r = sd_journal_seek_tail(j); | |||
2454 | if (r < 0) { | |||
2455 | log_error_errno(r, "Failed to seek to tail: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2455, __func__, "Failed to seek to tail: %m" ) : -abs(_e); }); | |||
2456 | goto finish; | |||
2457 | } | |||
2458 | ||||
2459 | r = sd_journal_previous(j); | |||
2460 | ||||
2461 | } else { | |||
2462 | r = sd_journal_seek_head(j); | |||
2463 | if (r < 0) { | |||
2464 | log_error_errno(r, "Failed to seek to head: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2464, __func__, "Failed to seek to head: %m" ) : -abs(_e); }); | |||
2465 | goto finish; | |||
2466 | } | |||
2467 | ||||
2468 | r = sd_journal_next(j); | |||
2469 | } | |||
2470 | ||||
2471 | if (r < 0) { | |||
2472 | log_error_errno(r, "Failed to iterate through journal: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2472, __func__, "Failed to iterate through journal: %m" ) : -abs(_e); }); | |||
2473 | goto finish; | |||
2474 | } | |||
2475 | if (r == 0) | |||
2476 | need_seek = true1; | |||
2477 | ||||
2478 | if (!arg_follow) | |||
2479 | (void) pager_open(arg_no_pager, arg_pager_end); | |||
2480 | ||||
2481 | if (!arg_quiet && (arg_lines != 0 || arg_follow)) { | |||
2482 | usec_t start, end; | |||
2483 | char start_buf[FORMAT_TIMESTAMP_MAX(3+1+10+1+8+1+6+1+6+1)], end_buf[FORMAT_TIMESTAMP_MAX(3+1+10+1+8+1+6+1+6+1)]; | |||
2484 | ||||
2485 | r = sd_journal_get_cutoff_realtime_usec(j, &start, &end); | |||
2486 | if (r < 0) { | |||
2487 | log_error_errno(r, "Failed to get cutoff: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2487, __func__, "Failed to get cutoff: %m" ) : -abs(_e); }); | |||
2488 | goto finish; | |||
2489 | } | |||
2490 | ||||
2491 | if (r > 0) { | |||
2492 | if (arg_follow) | |||
2493 | printf("-- Logs begin at %s. --\n", | |||
2494 | format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start)); | |||
2495 | else | |||
2496 | printf("-- Logs begin at %s, end at %s. --\n", | |||
2497 | format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start), | |||
2498 | format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end)); | |||
2499 | } | |||
2500 | } | |||
2501 | ||||
2502 | for (;;) { | |||
2503 | while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) { | |||
2504 | int flags; | |||
2505 | size_t highlight[2] = {}; | |||
2506 | ||||
2507 | if (need_seek) { | |||
2508 | if (!arg_reverse) | |||
2509 | r = sd_journal_next(j); | |||
2510 | else | |||
2511 | r = sd_journal_previous(j); | |||
2512 | if (r < 0) { | |||
2513 | log_error_errno(r, "Failed to iterate through journal: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2513, __func__, "Failed to iterate through journal: %m" ) : -abs(_e); }); | |||
2514 | goto finish; | |||
2515 | } | |||
2516 | if (r == 0) | |||
2517 | break; | |||
2518 | } | |||
2519 | ||||
2520 | if (arg_until_set && !arg_reverse) { | |||
2521 | usec_t usec; | |||
2522 | ||||
2523 | r = sd_journal_get_realtime_usec(j, &usec); | |||
2524 | if (r < 0) { | |||
2525 | log_error_errno(r, "Failed to determine timestamp: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2525, __func__, "Failed to determine timestamp: %m" ) : -abs(_e); }); | |||
2526 | goto finish; | |||
2527 | } | |||
2528 | if (usec > arg_until) | |||
2529 | goto finish; | |||
2530 | } | |||
2531 | ||||
2532 | if (arg_since_set && arg_reverse) { | |||
2533 | usec_t usec; | |||
2534 | ||||
2535 | r = sd_journal_get_realtime_usec(j, &usec); | |||
2536 | if (r < 0) { | |||
2537 | log_error_errno(r, "Failed to determine timestamp: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2537, __func__, "Failed to determine timestamp: %m" ) : -abs(_e); }); | |||
2538 | goto finish; | |||
2539 | } | |||
2540 | if (usec < arg_since) | |||
2541 | goto finish; | |||
2542 | } | |||
2543 | ||||
2544 | if (!arg_merge && !arg_quiet) { | |||
2545 | sd_id128_t boot_id; | |||
2546 | ||||
2547 | r = sd_journal_get_monotonic_usec(j, NULL((void*)0), &boot_id); | |||
2548 | if (r >= 0) { | |||
2549 | if (previous_boot_id_valid && | |||
2550 | !sd_id128_equal(boot_id, previous_boot_id)) | |||
2551 | printf("%s-- Reboot --%s\n", | |||
2552 | ansi_highlight(), ansi_normal()); | |||
2553 | ||||
2554 | previous_boot_id = boot_id; | |||
2555 | previous_boot_id_valid = true1; | |||
2556 | } | |||
2557 | } | |||
2558 | ||||
2559 | #if HAVE_PCRE21 | |||
2560 | if (arg_compiled_pattern) { | |||
2561 | _cleanup_(pcre2_match_data_freep)__attribute__((cleanup(pcre2_match_data_freep))) pcre2_match_datapcre2_match_data_8 *md = NULL((void*)0); | |||
2562 | const void *message; | |||
2563 | size_t len; | |||
2564 | PCRE2_SIZEsize_t *ovec; | |||
2565 | ||||
2566 | md = pcre2_match_data_createpcre2_match_data_create_8(1, NULL((void*)0)); | |||
2567 | if (!md) | |||
2568 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/journalctl.c" , 2568, __func__); | |||
2569 | ||||
2570 | r = sd_journal_get_data(j, "MESSAGE", &message, &len); | |||
2571 | if (r < 0) { | |||
2572 | if (r == -ENOENT2) { | |||
2573 | need_seek = true1; | |||
2574 | continue; | |||
2575 | } | |||
2576 | ||||
2577 | log_error_errno(r, "Failed to get MESSAGE field: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2577, __func__, "Failed to get MESSAGE field: %m" ) : -abs(_e); }); | |||
2578 | goto finish; | |||
2579 | } | |||
2580 | ||||
2581 | assert_se(message = startswith(message, "MESSAGE="))do { if ((__builtin_expect(!!(!(message = startswith(message, "MESSAGE="))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("message = startswith(message, \"MESSAGE=\")"), "../src/journal/journalctl.c" , 2581, __PRETTY_FUNCTION__); } while (0); | |||
2582 | ||||
2583 | r = pcre2_matchpcre2_match_8(arg_compiled_pattern, | |||
2584 | message, | |||
2585 | len - strlen("MESSAGE="), | |||
2586 | 0, /* start at offset 0 in the subject */ | |||
2587 | 0, /* default options */ | |||
2588 | md, | |||
2589 | NULL((void*)0)); | |||
2590 | if (r == PCRE2_ERROR_NOMATCH(-1)) { | |||
2591 | need_seek = true1; | |||
2592 | continue; | |||
2593 | } | |||
2594 | if (r < 0) { | |||
2595 | unsigned char buf[LINE_MAX2048]; | |||
2596 | int r2; | |||
2597 | ||||
2598 | r2 = pcre2_get_error_messagepcre2_get_error_message_8(r, buf, sizeof buf); | |||
2599 | log_error("Pattern matching failed: %s",({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2600, __func__, "Pattern matching failed: %s" , r2 < 0 ? "unknown error" : (char*) buf) : -abs(_e); }) | |||
2600 | r2 < 0 ? "unknown error" : (char*) buf)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2600, __func__, "Pattern matching failed: %s" , r2 < 0 ? "unknown error" : (char*) buf) : -abs(_e); }); | |||
2601 | r = -EINVAL22; | |||
2602 | goto finish; | |||
2603 | } | |||
2604 | ||||
2605 | ovec = pcre2_get_ovector_pointerpcre2_get_ovector_pointer_8(md); | |||
2606 | highlight[0] = ovec[0]; | |||
2607 | highlight[1] = ovec[1]; | |||
2608 | } | |||
2609 | #endif | |||
2610 | ||||
2611 | flags = | |||
2612 | arg_all * OUTPUT_SHOW_ALL | | |||
2613 | arg_full * OUTPUT_FULL_WIDTH | | |||
2614 | colors_enabled() * OUTPUT_COLOR | | |||
2615 | arg_catalog * OUTPUT_CATALOG | | |||
2616 | arg_utc * OUTPUT_UTC | | |||
2617 | arg_no_hostname * OUTPUT_NO_HOSTNAME; | |||
2618 | ||||
2619 | r = show_journal_entry(stdoutstdout, j, arg_output, 0, flags, | |||
2620 | arg_output_fields, highlight, &ellipsized); | |||
2621 | need_seek = true1; | |||
2622 | if (r == -EADDRNOTAVAIL99) | |||
2623 | break; | |||
2624 | else if (r < 0 || ferror(stdoutstdout)) | |||
2625 | goto finish; | |||
2626 | ||||
2627 | n_shown++; | |||
2628 | ||||
2629 | /* If journalctl take a long time to process messages, and during that time journal file | |||
2630 | * rotation occurs, a journalctl client will keep those rotated files open until it calls | |||
2631 | * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below | |||
2632 | * in the "following" case. By periodically calling sd_journal_process() during the processing | |||
2633 | * loop we shrink the window of time a client instance has open file descriptors for rotated | |||
2634 | * (deleted) journal files. */ | |||
2635 | if ((n_shown % PROCESS_INOTIFY_INTERVAL1024) == 0) { | |||
2636 | r = sd_journal_process(j); | |||
2637 | if (r < 0) { | |||
2638 | log_error_errno(r, "Failed to process inotify events: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2638, __func__, "Failed to process inotify events: %m" ) : -abs(_e); }); | |||
2639 | goto finish; | |||
2640 | } | |||
2641 | } | |||
2642 | } | |||
2643 | ||||
2644 | if (!arg_follow) { | |||
2645 | if (n_shown == 0 && !arg_quiet) | |||
2646 | printf("-- No entries --\n"); | |||
2647 | ||||
2648 | if (arg_show_cursor) { | |||
2649 | _cleanup_free___attribute__((cleanup(freep))) char *cursor = NULL((void*)0); | |||
2650 | ||||
2651 | r = sd_journal_get_cursor(j, &cursor); | |||
2652 | if (r < 0 && r != -EADDRNOTAVAIL99) | |||
2653 | log_error_errno(r, "Failed to get cursor: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2653, __func__, "Failed to get cursor: %m" ) : -abs(_e); }); | |||
2654 | else if (r >= 0) | |||
2655 | printf("-- cursor: %s\n", cursor); | |||
2656 | } | |||
2657 | ||||
2658 | break; | |||
2659 | } | |||
2660 | ||||
2661 | fflush(stdoutstdout); | |||
2662 | r = sd_journal_wait(j, (uint64_t) -1); | |||
2663 | if (r < 0) { | |||
2664 | log_error_errno(r, "Couldn't wait for journal event: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/journalctl.c", 2664, __func__, "Couldn't wait for journal event: %m" ) : -abs(_e); }); | |||
2665 | goto finish; | |||
2666 | } | |||
2667 | ||||
2668 | first_line = false0; | |||
2669 | } | |||
2670 | ||||
2671 | finish: | |||
2672 | fflush(stdoutstdout); | |||
2673 | pager_close(); | |||
2674 | ||||
2675 | strv_free(arg_file); | |||
2676 | ||||
2677 | strv_free(arg_syslog_identifier); | |||
2678 | strv_free(arg_system_units); | |||
2679 | strv_free(arg_user_units); | |||
2680 | strv_free(arg_output_fields); | |||
2681 | ||||
2682 | free(arg_root); | |||
2683 | free(arg_verify_key); | |||
2684 | ||||
2685 | #if HAVE_PCRE21 | |||
2686 | if (arg_compiled_pattern) | |||
2687 | pcre2_code_freepcre2_code_free_8(arg_compiled_pattern); | |||
2688 | #endif | |||
2689 | ||||
2690 | return r < 0 ? EXIT_FAILURE1 : EXIT_SUCCESS0; | |||
2691 | } |