File: | build-scan/../src/coredump/coredumpctl.c |
Warning: | line 374, column 17 Potential leak of memory pointed to by 'coredump' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | ||||||||||||||||
2 | |||||||||||||||||
3 | #include <fcntl.h> | ||||||||||||||||
4 | #include <getopt.h> | ||||||||||||||||
5 | #include <locale.h> | ||||||||||||||||
6 | #include <stdio.h> | ||||||||||||||||
7 | #include <string.h> | ||||||||||||||||
8 | #include <unistd.h> | ||||||||||||||||
9 | |||||||||||||||||
10 | #include "sd-bus.h" | ||||||||||||||||
11 | #include "sd-journal.h" | ||||||||||||||||
12 | #include "sd-messages.h" | ||||||||||||||||
13 | |||||||||||||||||
14 | #include "alloc-util.h" | ||||||||||||||||
15 | #include "bus-error.h" | ||||||||||||||||
16 | #include "bus-util.h" | ||||||||||||||||
17 | #include "compress.h" | ||||||||||||||||
18 | #include "fd-util.h" | ||||||||||||||||
19 | #include "fileio.h" | ||||||||||||||||
20 | #include "fs-util.h" | ||||||||||||||||
21 | #include "journal-internal.h" | ||||||||||||||||
22 | #include "journal-util.h" | ||||||||||||||||
23 | #include "log.h" | ||||||||||||||||
24 | #include "macro.h" | ||||||||||||||||
25 | #include "pager.h" | ||||||||||||||||
26 | #include "parse-util.h" | ||||||||||||||||
27 | #include "path-util.h" | ||||||||||||||||
28 | #include "process-util.h" | ||||||||||||||||
29 | #include "sigbus.h" | ||||||||||||||||
30 | #include "signal-util.h" | ||||||||||||||||
31 | #include "string-util.h" | ||||||||||||||||
32 | #include "strv.h" | ||||||||||||||||
33 | #include "terminal-util.h" | ||||||||||||||||
34 | #include "user-util.h" | ||||||||||||||||
35 | #include "util.h" | ||||||||||||||||
36 | #include "verbs.h" | ||||||||||||||||
37 | |||||||||||||||||
38 | #define SHORT_BUS_CALL_TIMEOUT_USEC(3 * ((usec_t) 1000000ULL)) (3 * USEC_PER_SEC((usec_t) 1000000ULL)) | ||||||||||||||||
39 | |||||||||||||||||
40 | static usec_t arg_since = USEC_INFINITY((usec_t) -1), arg_until = USEC_INFINITY((usec_t) -1); | ||||||||||||||||
41 | static const char* arg_field = NULL((void*)0); | ||||||||||||||||
42 | static const char *arg_debugger = NULL((void*)0); | ||||||||||||||||
43 | static const char *arg_directory = NULL((void*)0); | ||||||||||||||||
44 | static bool_Bool arg_no_pager = false0; | ||||||||||||||||
45 | static int arg_no_legend = false0; | ||||||||||||||||
46 | static int arg_one = false0; | ||||||||||||||||
47 | static FILE* arg_output = NULL((void*)0); | ||||||||||||||||
48 | static bool_Bool arg_reverse = false0; | ||||||||||||||||
49 | static bool_Bool arg_quiet = false0; | ||||||||||||||||
50 | |||||||||||||||||
51 | static int add_match(sd_journal *j, const char *match) { | ||||||||||||||||
52 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); | ||||||||||||||||
53 | const char* prefix, *pattern; | ||||||||||||||||
54 | pid_t pid; | ||||||||||||||||
55 | int r; | ||||||||||||||||
56 | |||||||||||||||||
57 | if (strchr(match, '=')) | ||||||||||||||||
58 | prefix = ""; | ||||||||||||||||
59 | else if (strchr(match, '/')) { | ||||||||||||||||
60 | r = path_make_absolute_cwd(match, &p); | ||||||||||||||||
61 | if (r < 0) | ||||||||||||||||
62 | return log_error_errno(r, "path_make_absolute_cwd(\"%s\"): %m", match)({ 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/coredump/coredumpctl.c", 62, __func__, "path_make_absolute_cwd(\"%s\"): %m" , match) : -abs(_e); }); | ||||||||||||||||
63 | |||||||||||||||||
64 | match = p; | ||||||||||||||||
65 | prefix = "COREDUMP_EXE="; | ||||||||||||||||
66 | } else if (parse_pid(match, &pid) >= 0) | ||||||||||||||||
67 | prefix = "COREDUMP_PID="; | ||||||||||||||||
68 | else | ||||||||||||||||
69 | prefix = "COREDUMP_COMM="; | ||||||||||||||||
70 | |||||||||||||||||
71 | pattern = strjoina(prefix, match)({ const char *_appendees_[] = { prefix, match }; 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_; }); | ||||||||||||||||
72 | log_debug("Adding match: %s", 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/coredump/coredumpctl.c", 72, __func__, "Adding match: %s" , pattern) : -abs(_e); }); | ||||||||||||||||
73 | r = sd_journal_add_match(j, pattern, 0); | ||||||||||||||||
74 | if (r < 0) | ||||||||||||||||
75 | return log_error_errno(r, "Failed to add match \"%s\": %m", match)({ 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/coredump/coredumpctl.c", 75, __func__, "Failed to add match \"%s\": %m" , match) : -abs(_e); }); | ||||||||||||||||
76 | |||||||||||||||||
77 | return 0; | ||||||||||||||||
78 | } | ||||||||||||||||
79 | |||||||||||||||||
80 | static int add_matches(sd_journal *j, char **matches) { | ||||||||||||||||
81 | char **match; | ||||||||||||||||
82 | int r; | ||||||||||||||||
83 | |||||||||||||||||
84 | r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR"fc" "2e" "22" "bc" "6e" "e6" "47" "b6" "b9" "07" "29" "ab" "34" "a2" "50" "b1", 0); | ||||||||||||||||
85 | if (r < 0) | ||||||||||||||||
86 | return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR)({ 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/coredump/coredumpctl.c", 86, __func__, "Failed to add match \"%s\": %m" , "MESSAGE_ID=" "fc" "2e" "22" "bc" "6e" "e6" "47" "b6" "b9" "07" "29" "ab" "34" "a2" "50" "b1") : -abs(_e); }); | ||||||||||||||||
87 | |||||||||||||||||
88 | r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR"1f" "4e" "0a" "44" "a8" "86" "49" "93" "9a" "ae" "a3" "4f" "c6" "da" "8c" "95", 0); | ||||||||||||||||
89 | if (r < 0) | ||||||||||||||||
90 | return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR)({ 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/coredump/coredumpctl.c", 90, __func__, "Failed to add match \"%s\": %m" , "MESSAGE_ID=" "1f" "4e" "0a" "44" "a8" "86" "49" "93" "9a" "ae" "a3" "4f" "c6" "da" "8c" "95") : -abs(_e); }); | ||||||||||||||||
91 | |||||||||||||||||
92 | STRV_FOREACH(match, matches)for ((match) = (matches); (match) && *(match); (match )++) { | ||||||||||||||||
93 | r = add_match(j, *match); | ||||||||||||||||
94 | if (r < 0) | ||||||||||||||||
95 | return r; | ||||||||||||||||
96 | } | ||||||||||||||||
97 | |||||||||||||||||
98 | return 0; | ||||||||||||||||
99 | } | ||||||||||||||||
100 | |||||||||||||||||
101 | static int acquire_journal(sd_journal **ret, char **matches) { | ||||||||||||||||
102 | _cleanup_(sd_journal_closep)__attribute__((cleanup(sd_journal_closep))) sd_journal *j = NULL((void*)0); | ||||||||||||||||
103 | int r; | ||||||||||||||||
104 | |||||||||||||||||
105 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/coredump/coredumpctl.c", 105, __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
106 | |||||||||||||||||
107 | if (arg_directory) { | ||||||||||||||||
108 | r = sd_journal_open_directory(&j, arg_directory, 0); | ||||||||||||||||
109 | if (r < 0) | ||||||||||||||||
110 | return log_error_errno(r, "Failed to open journals in directory: %s: %m", arg_directory)({ 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/coredump/coredumpctl.c", 110, __func__, "Failed to open journals in directory: %s: %m" , arg_directory) : -abs(_e); }); | ||||||||||||||||
111 | } else { | ||||||||||||||||
112 | r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); | ||||||||||||||||
113 | if (r < 0) | ||||||||||||||||
114 | return log_error_errno(r, "Failed to open 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/coredump/coredumpctl.c", 114, __func__, "Failed to open journal: %m" ) : -abs(_e); }); | ||||||||||||||||
115 | } | ||||||||||||||||
116 | |||||||||||||||||
117 | r = journal_access_check_and_warn(j, arg_quiet, true1); | ||||||||||||||||
118 | if (r < 0) | ||||||||||||||||
119 | return r; | ||||||||||||||||
120 | |||||||||||||||||
121 | r = add_matches(j, matches); | ||||||||||||||||
122 | if (r < 0) | ||||||||||||||||
123 | return r; | ||||||||||||||||
124 | |||||||||||||||||
125 | if (DEBUG_LOGGING(__builtin_expect(!!(log_get_max_level_realm(LOG_REALM_SYSTEMD ) >= 7),0))) { | ||||||||||||||||
126 | _cleanup_free___attribute__((cleanup(freep))) char *filter; | ||||||||||||||||
127 | |||||||||||||||||
128 | filter = journal_make_match_string(j); | ||||||||||||||||
129 | 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/coredump/coredumpctl.c", 129, __func__, "Journal filter: %s" , filter) : -abs(_e); }); | ||||||||||||||||
130 | } | ||||||||||||||||
131 | |||||||||||||||||
132 | *ret = TAKE_PTR(j)({ typeof(j) _ptr_ = (j); (j) = ((void*)0); _ptr_; }); | ||||||||||||||||
133 | |||||||||||||||||
134 | return 0; | ||||||||||||||||
135 | } | ||||||||||||||||
136 | |||||||||||||||||
137 | static int help(void) { | ||||||||||||||||
138 | printf("%s [OPTIONS...]\n\n" | ||||||||||||||||
139 | "List or retrieve coredumps from the journal.\n\n" | ||||||||||||||||
140 | "Flags:\n" | ||||||||||||||||
141 | " -h --help Show this help\n" | ||||||||||||||||
142 | " --version Print version string\n" | ||||||||||||||||
143 | " --no-pager Do not pipe output into a pager\n" | ||||||||||||||||
144 | " --no-legend Do not print the column headers\n" | ||||||||||||||||
145 | " --debugger=DEBUGGER Use the given debugger\n" | ||||||||||||||||
146 | " -1 Show information about most recent entry only\n" | ||||||||||||||||
147 | " -S --since=DATE Only print coredumps since the date\n" | ||||||||||||||||
148 | " -U --until=DATE Only print coredumps until the date\n" | ||||||||||||||||
149 | " -r --reverse Show the newest entries first\n" | ||||||||||||||||
150 | " -F --field=FIELD List all values a certain field takes\n" | ||||||||||||||||
151 | " -o --output=FILE Write output to FILE\n" | ||||||||||||||||
152 | " -D --directory=DIR Use journal files from directory\n\n" | ||||||||||||||||
153 | " -q --quiet Do not show info messages and privilege warning\n" | ||||||||||||||||
154 | "Commands:\n" | ||||||||||||||||
155 | " list [MATCHES...] List available coredumps (default)\n" | ||||||||||||||||
156 | " info [MATCHES...] Show detailed information about one or more coredumps\n" | ||||||||||||||||
157 | " dump [MATCHES...] Print first matching coredump to stdout\n" | ||||||||||||||||
158 | " debug [MATCHES...] Start a debugger for the first matching coredump\n" | ||||||||||||||||
159 | , program_invocation_short_name); | ||||||||||||||||
160 | |||||||||||||||||
161 | return 0; | ||||||||||||||||
162 | } | ||||||||||||||||
163 | |||||||||||||||||
164 | static int parse_argv(int argc, char *argv[]) { | ||||||||||||||||
165 | enum { | ||||||||||||||||
166 | ARG_VERSION = 0x100, | ||||||||||||||||
167 | ARG_NO_PAGER, | ||||||||||||||||
168 | ARG_NO_LEGEND, | ||||||||||||||||
169 | ARG_DEBUGGER, | ||||||||||||||||
170 | }; | ||||||||||||||||
171 | |||||||||||||||||
172 | int c, r; | ||||||||||||||||
173 | |||||||||||||||||
174 | static const struct option options[] = { | ||||||||||||||||
175 | { "help", no_argument0, NULL((void*)0), 'h' }, | ||||||||||||||||
176 | { "version" , no_argument0, NULL((void*)0), ARG_VERSION }, | ||||||||||||||||
177 | { "no-pager", no_argument0, NULL((void*)0), ARG_NO_PAGER }, | ||||||||||||||||
178 | { "no-legend", no_argument0, NULL((void*)0), ARG_NO_LEGEND }, | ||||||||||||||||
179 | { "debugger", required_argument1, NULL((void*)0), ARG_DEBUGGER }, | ||||||||||||||||
180 | { "output", required_argument1, NULL((void*)0), 'o' }, | ||||||||||||||||
181 | { "field", required_argument1, NULL((void*)0), 'F' }, | ||||||||||||||||
182 | { "directory", required_argument1, NULL((void*)0), 'D' }, | ||||||||||||||||
183 | { "reverse", no_argument0, NULL((void*)0), 'r' }, | ||||||||||||||||
184 | { "since", required_argument1, NULL((void*)0), 'S' }, | ||||||||||||||||
185 | { "until", required_argument1, NULL((void*)0), 'U' }, | ||||||||||||||||
186 | { "quiet", no_argument0, NULL((void*)0), 'q' }, | ||||||||||||||||
187 | {} | ||||||||||||||||
188 | }; | ||||||||||||||||
189 | |||||||||||||||||
190 | assert(argc >= 0)do { if ((__builtin_expect(!!(!(argc >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argc >= 0"), "../src/coredump/coredumpctl.c" , 190, __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
191 | assert(argv)do { if ((__builtin_expect(!!(!(argv)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argv"), "../src/coredump/coredumpctl.c" , 191, __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
192 | |||||||||||||||||
193 | while ((c = getopt_long(argc, argv, "ho:F:1D:rS:U:q", options, NULL((void*)0))) >= 0) | ||||||||||||||||
194 | switch(c) { | ||||||||||||||||
195 | case 'h': | ||||||||||||||||
196 | return help(); | ||||||||||||||||
197 | |||||||||||||||||
198 | case ARG_VERSION: | ||||||||||||||||
199 | return version(); | ||||||||||||||||
200 | |||||||||||||||||
201 | case ARG_NO_PAGER: | ||||||||||||||||
202 | arg_no_pager = true1; | ||||||||||||||||
203 | break; | ||||||||||||||||
204 | |||||||||||||||||
205 | case ARG_NO_LEGEND: | ||||||||||||||||
206 | arg_no_legend = true1; | ||||||||||||||||
207 | break; | ||||||||||||||||
208 | |||||||||||||||||
209 | case ARG_DEBUGGER: | ||||||||||||||||
210 | arg_debugger = optarg; | ||||||||||||||||
211 | break; | ||||||||||||||||
212 | |||||||||||||||||
213 | case 'o': | ||||||||||||||||
214 | if (arg_output) { | ||||||||||||||||
215 | log_error("Cannot set output more than once.")({ 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/coredump/coredumpctl.c", 215, __func__, "Cannot set output more than once." ) : -abs(_e); }); | ||||||||||||||||
216 | return -EINVAL22; | ||||||||||||||||
217 | } | ||||||||||||||||
218 | |||||||||||||||||
219 | arg_output = fopen(optarg, "we"); | ||||||||||||||||
220 | if (!arg_output) | ||||||||||||||||
221 | return log_error_errno(errno, "writing to '%s': %m", optarg)({ 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/coredump/coredumpctl.c", 221, __func__ , "writing to '%s': %m", optarg) : -abs(_e); }); | ||||||||||||||||
222 | |||||||||||||||||
223 | break; | ||||||||||||||||
224 | |||||||||||||||||
225 | case 'S': | ||||||||||||||||
226 | r = parse_timestamp(optarg, &arg_since); | ||||||||||||||||
227 | if (r < 0) | ||||||||||||||||
228 | return log_error_errno(r, "Failed to parse timestamp: %s", 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/coredump/coredumpctl.c", 228, __func__, "Failed to parse timestamp: %s" , optarg) : -abs(_e); }); | ||||||||||||||||
229 | break; | ||||||||||||||||
230 | |||||||||||||||||
231 | case 'U': | ||||||||||||||||
232 | r = parse_timestamp(optarg, &arg_until); | ||||||||||||||||
233 | if (r < 0) | ||||||||||||||||
234 | return log_error_errno(r, "Failed to parse timestamp: %s", 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/coredump/coredumpctl.c", 234, __func__, "Failed to parse timestamp: %s" , optarg) : -abs(_e); }); | ||||||||||||||||
235 | break; | ||||||||||||||||
236 | |||||||||||||||||
237 | case 'F': | ||||||||||||||||
238 | if (arg_field) { | ||||||||||||||||
239 | log_error("Cannot use --field/-F more than once.")({ 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/coredump/coredumpctl.c", 239, __func__, "Cannot use --field/-F more than once." ) : -abs(_e); }); | ||||||||||||||||
240 | return -EINVAL22; | ||||||||||||||||
241 | } | ||||||||||||||||
242 | arg_field = optarg; | ||||||||||||||||
243 | break; | ||||||||||||||||
244 | |||||||||||||||||
245 | case '1': | ||||||||||||||||
246 | arg_one = true1; | ||||||||||||||||
247 | break; | ||||||||||||||||
248 | |||||||||||||||||
249 | case 'D': | ||||||||||||||||
250 | arg_directory = optarg; | ||||||||||||||||
251 | break; | ||||||||||||||||
252 | |||||||||||||||||
253 | case 'r': | ||||||||||||||||
254 | arg_reverse = true1; | ||||||||||||||||
255 | break; | ||||||||||||||||
256 | |||||||||||||||||
257 | case 'q': | ||||||||||||||||
258 | arg_quiet = true1; | ||||||||||||||||
259 | break; | ||||||||||||||||
260 | |||||||||||||||||
261 | case '?': | ||||||||||||||||
262 | return -EINVAL22; | ||||||||||||||||
263 | |||||||||||||||||
264 | default: | ||||||||||||||||
265 | assert_not_reached("Unhandled option")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unhandled option"), "../src/coredump/coredumpctl.c", 265, __PRETTY_FUNCTION__ ); } while (0); | ||||||||||||||||
266 | } | ||||||||||||||||
267 | |||||||||||||||||
268 | if (arg_since != USEC_INFINITY((usec_t) -1) && arg_until != USEC_INFINITY((usec_t) -1) && | ||||||||||||||||
269 | arg_since > arg_until) { | ||||||||||||||||
270 | 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/coredump/coredumpctl.c", 270, __func__, "--since= must be before --until=." ) : -abs(_e); }); | ||||||||||||||||
271 | return -EINVAL22; | ||||||||||||||||
272 | } | ||||||||||||||||
273 | |||||||||||||||||
274 | return 1; | ||||||||||||||||
275 | } | ||||||||||||||||
276 | |||||||||||||||||
277 | static int retrieve(const void *data, | ||||||||||||||||
278 | size_t len, | ||||||||||||||||
279 | const char *name, | ||||||||||||||||
280 | char **var) { | ||||||||||||||||
281 | |||||||||||||||||
282 | size_t ident; | ||||||||||||||||
283 | char *v; | ||||||||||||||||
284 | |||||||||||||||||
285 | ident = strlen(name) + 1; /* name + "=" */ | ||||||||||||||||
286 | |||||||||||||||||
287 | if (len
| ||||||||||||||||
288 | return 0; | ||||||||||||||||
289 | |||||||||||||||||
290 | if (memcmp(data, name, ident - 1) != 0) | ||||||||||||||||
291 | return 0; | ||||||||||||||||
292 | |||||||||||||||||
293 | if (((const char*) data)[ident - 1] != '=') | ||||||||||||||||
294 | return 0; | ||||||||||||||||
295 | |||||||||||||||||
296 | v = strndup((const char*)data + ident, len - ident); | ||||||||||||||||
297 | if (!v) | ||||||||||||||||
298 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/coredump/coredumpctl.c" , 298, __func__); | ||||||||||||||||
299 | |||||||||||||||||
300 | free(*var); | ||||||||||||||||
301 | *var = v; | ||||||||||||||||
302 | |||||||||||||||||
303 | return 1; | ||||||||||||||||
304 | } | ||||||||||||||||
305 | |||||||||||||||||
306 | static int print_field(FILE* file, sd_journal *j) { | ||||||||||||||||
307 | const void *d; | ||||||||||||||||
308 | size_t l; | ||||||||||||||||
309 | |||||||||||||||||
310 | assert(file)do { if ((__builtin_expect(!!(!(file)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("file"), "../src/coredump/coredumpctl.c" , 310, __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
311 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/coredump/coredumpctl.c", 311 , __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
312 | |||||||||||||||||
313 | assert(arg_field)do { if ((__builtin_expect(!!(!(arg_field)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("arg_field"), "../src/coredump/coredumpctl.c" , 313, __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
314 | |||||||||||||||||
315 | /* A (user-specified) field may appear more than once for a given entry. | ||||||||||||||||
316 | * We will print all of the occurences. | ||||||||||||||||
317 | * This is different below for fields that systemd-coredump uses, | ||||||||||||||||
318 | * because they cannot meaningfully appear more than once. | ||||||||||||||||
319 | */ | ||||||||||||||||
320 | SD_JOURNAL_FOREACH_DATA(j, d, l)for (sd_journal_restart_data(j); sd_journal_enumerate_data((j ), &(d), &(l)) > 0; ) { | ||||||||||||||||
321 | _cleanup_free___attribute__((cleanup(freep))) char *value = NULL((void*)0); | ||||||||||||||||
322 | int r; | ||||||||||||||||
323 | |||||||||||||||||
324 | r = retrieve(d, l, arg_field, &value); | ||||||||||||||||
325 | if (r < 0) | ||||||||||||||||
326 | return r; | ||||||||||||||||
327 | if (r > 0) | ||||||||||||||||
328 | fprintf(file, "%s\n", value); | ||||||||||||||||
329 | } | ||||||||||||||||
330 | |||||||||||||||||
331 | return 0; | ||||||||||||||||
332 | } | ||||||||||||||||
333 | |||||||||||||||||
334 | #define RETRIEVE(d, l, name, arg){ int _r = retrieve(d, l, name, &arg); if (_r < 0) return _r; if (_r > 0) continue; } \ | ||||||||||||||||
335 | { \ | ||||||||||||||||
336 | int _r = retrieve(d, l, name, &arg); \ | ||||||||||||||||
337 | if (_r < 0) \ | ||||||||||||||||
338 | return _r; \ | ||||||||||||||||
339 | if (_r > 0) \ | ||||||||||||||||
340 | continue; \ | ||||||||||||||||
341 | } | ||||||||||||||||
342 | |||||||||||||||||
343 | static int print_list(FILE* file, sd_journal *j, int had_legend) { | ||||||||||||||||
344 | _cleanup_free___attribute__((cleanup(freep))) char | ||||||||||||||||
345 | *mid = NULL((void*)0), *pid = NULL((void*)0), *uid = NULL((void*)0), *gid = NULL((void*)0), | ||||||||||||||||
346 | *sgnl = NULL((void*)0), *exe = NULL((void*)0), *comm = NULL((void*)0), *cmdline = NULL((void*)0), | ||||||||||||||||
347 | *filename = NULL((void*)0), *truncated = NULL((void*)0), *coredump = NULL((void*)0); | ||||||||||||||||
348 | const void *d; | ||||||||||||||||
349 | size_t l; | ||||||||||||||||
350 | usec_t t; | ||||||||||||||||
351 | char buf[FORMAT_TIMESTAMP_MAX(3+1+10+1+8+1+6+1+6+1)]; | ||||||||||||||||
352 | int r; | ||||||||||||||||
353 | const char *present; | ||||||||||||||||
354 | bool_Bool normal_coredump; | ||||||||||||||||
355 | |||||||||||||||||
356 | assert(file)do { if ((__builtin_expect(!!(!(file)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("file"), "../src/coredump/coredumpctl.c" , 356, __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
| |||||||||||||||||
357 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/coredump/coredumpctl.c", 357 , __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
358 | |||||||||||||||||
359 | SD_JOURNAL_FOREACH_DATA(j, d, l)for (sd_journal_restart_data(j); sd_journal_enumerate_data((j ), &(d), &(l)) > 0; ) { | ||||||||||||||||
360 | RETRIEVE(d, l, "MESSAGE_ID", mid){ int _r = retrieve(d, l, "MESSAGE_ID", &mid); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
361 | RETRIEVE(d, l, "COREDUMP_PID", pid){ int _r = retrieve(d, l, "COREDUMP_PID", &pid); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
362 | RETRIEVE(d, l, "COREDUMP_UID", uid){ int _r = retrieve(d, l, "COREDUMP_UID", &uid); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
363 | RETRIEVE(d, l, "COREDUMP_GID", gid){ int _r = retrieve(d, l, "COREDUMP_GID", &gid); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
364 | RETRIEVE(d, l, "COREDUMP_SIGNAL", sgnl){ int _r = retrieve(d, l, "COREDUMP_SIGNAL", &sgnl); if ( _r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
365 | RETRIEVE(d, l, "COREDUMP_EXE", exe){ int _r = retrieve(d, l, "COREDUMP_EXE", &exe); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
366 | RETRIEVE(d, l, "COREDUMP_COMM", comm){ int _r = retrieve(d, l, "COREDUMP_COMM", &comm); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
367 | RETRIEVE(d, l, "COREDUMP_CMDLINE", cmdline){ int _r = retrieve(d, l, "COREDUMP_CMDLINE", &cmdline); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
368 | RETRIEVE(d, l, "COREDUMP_FILENAME", filename){ int _r = retrieve(d, l, "COREDUMP_FILENAME", &filename) ; if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
369 | RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated){ int _r = retrieve(d, l, "COREDUMP_TRUNCATED", &truncated ); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
370 | RETRIEVE(d, l, "COREDUMP", coredump){ int _r = retrieve(d, l, "COREDUMP", &coredump); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
371 | } | ||||||||||||||||
372 | |||||||||||||||||
373 | if (!pid
| ||||||||||||||||
374 | log_warning("Empty coredump log entry")({ 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/coredump/coredumpctl.c", 374, __func__, "Empty coredump log entry" ) : -abs(_e); }); | ||||||||||||||||
| |||||||||||||||||
375 | return -EINVAL22; | ||||||||||||||||
376 | } | ||||||||||||||||
377 | |||||||||||||||||
378 | r = sd_journal_get_realtime_usec(j, &t); | ||||||||||||||||
379 | if (r < 0) | ||||||||||||||||
380 | return log_error_errno(r, "Failed to get realtime 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/coredump/coredumpctl.c", 380, __func__, "Failed to get realtime timestamp: %m" ) : -abs(_e); }); | ||||||||||||||||
381 | |||||||||||||||||
382 | format_timestamp(buf, sizeof(buf), t); | ||||||||||||||||
383 | |||||||||||||||||
384 | if (!had_legend && !arg_no_legend) | ||||||||||||||||
385 | fprintf(file, "%-*s %*s %*s %*s %*s %-*s %s\n", | ||||||||||||||||
386 | FORMAT_TIMESTAMP_WIDTH28, "TIME", | ||||||||||||||||
387 | 6, "PID", | ||||||||||||||||
388 | 5, "UID", | ||||||||||||||||
389 | 5, "GID", | ||||||||||||||||
390 | 3, "SIG", | ||||||||||||||||
391 | 9, "COREFILE", | ||||||||||||||||
392 | "EXE"); | ||||||||||||||||
393 | |||||||||||||||||
394 | normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR"fc" "2e" "22" "bc" "6e" "e6" "47" "b6" "b9" "07" "29" "ab" "34" "a2" "50" "b1"); | ||||||||||||||||
395 | |||||||||||||||||
396 | if (filename) | ||||||||||||||||
397 | if (access(filename, R_OK4) == 0) | ||||||||||||||||
398 | present = "present"; | ||||||||||||||||
399 | else if (errno(*__errno_location ()) == ENOENT2) | ||||||||||||||||
400 | present = "missing"; | ||||||||||||||||
401 | else | ||||||||||||||||
402 | present = "error"; | ||||||||||||||||
403 | else if (coredump) | ||||||||||||||||
404 | present = "journal"; | ||||||||||||||||
405 | else if (normal_coredump) | ||||||||||||||||
406 | present = "none"; | ||||||||||||||||
407 | else | ||||||||||||||||
408 | present = "-"; | ||||||||||||||||
409 | |||||||||||||||||
410 | if (STR_IN_SET(present, "present", "journal")(!!strv_find((((char**) ((const char*[]) { "present", "journal" , ((void*)0) }))), (present))) && truncated && parse_boolean(truncated) > 0) | ||||||||||||||||
411 | present = "truncated"; | ||||||||||||||||
412 | |||||||||||||||||
413 | fprintf(file, "%-*s %*s %*s %*s %*s %-*s %s\n", | ||||||||||||||||
414 | FORMAT_TIMESTAMP_WIDTH28, buf, | ||||||||||||||||
415 | 6, strna(pid), | ||||||||||||||||
416 | 5, strna(uid), | ||||||||||||||||
417 | 5, strna(gid), | ||||||||||||||||
418 | 3, normal_coredump ? strna(sgnl) : "-", | ||||||||||||||||
419 | 9, present, | ||||||||||||||||
420 | strna(exe ?: (comm ?: cmdline))); | ||||||||||||||||
421 | |||||||||||||||||
422 | return 0; | ||||||||||||||||
423 | } | ||||||||||||||||
424 | |||||||||||||||||
425 | static int print_info(FILE *file, sd_journal *j, bool_Bool need_space) { | ||||||||||||||||
426 | _cleanup_free___attribute__((cleanup(freep))) char | ||||||||||||||||
427 | *mid = NULL((void*)0), *pid = NULL((void*)0), *uid = NULL((void*)0), *gid = NULL((void*)0), | ||||||||||||||||
428 | *sgnl = NULL((void*)0), *exe = NULL((void*)0), *comm = NULL((void*)0), *cmdline = NULL((void*)0), | ||||||||||||||||
429 | *unit = NULL((void*)0), *user_unit = NULL((void*)0), *session = NULL((void*)0), | ||||||||||||||||
430 | *boot_id = NULL((void*)0), *machine_id = NULL((void*)0), *hostname = NULL((void*)0), | ||||||||||||||||
431 | *slice = NULL((void*)0), *cgroup = NULL((void*)0), *owner_uid = NULL((void*)0), | ||||||||||||||||
432 | *message = NULL((void*)0), *timestamp = NULL((void*)0), *filename = NULL((void*)0), | ||||||||||||||||
433 | *truncated = NULL((void*)0), *coredump = NULL((void*)0); | ||||||||||||||||
434 | const void *d; | ||||||||||||||||
435 | size_t l; | ||||||||||||||||
436 | bool_Bool normal_coredump; | ||||||||||||||||
437 | int r; | ||||||||||||||||
438 | |||||||||||||||||
439 | assert(file)do { if ((__builtin_expect(!!(!(file)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("file"), "../src/coredump/coredumpctl.c" , 439, __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
440 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/coredump/coredumpctl.c", 440 , __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
441 | |||||||||||||||||
442 | SD_JOURNAL_FOREACH_DATA(j, d, l)for (sd_journal_restart_data(j); sd_journal_enumerate_data((j ), &(d), &(l)) > 0; ) { | ||||||||||||||||
443 | RETRIEVE(d, l, "MESSAGE_ID", mid){ int _r = retrieve(d, l, "MESSAGE_ID", &mid); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
444 | RETRIEVE(d, l, "COREDUMP_PID", pid){ int _r = retrieve(d, l, "COREDUMP_PID", &pid); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
445 | RETRIEVE(d, l, "COREDUMP_UID", uid){ int _r = retrieve(d, l, "COREDUMP_UID", &uid); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
446 | RETRIEVE(d, l, "COREDUMP_GID", gid){ int _r = retrieve(d, l, "COREDUMP_GID", &gid); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
447 | RETRIEVE(d, l, "COREDUMP_SIGNAL", sgnl){ int _r = retrieve(d, l, "COREDUMP_SIGNAL", &sgnl); if ( _r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
448 | RETRIEVE(d, l, "COREDUMP_EXE", exe){ int _r = retrieve(d, l, "COREDUMP_EXE", &exe); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
449 | RETRIEVE(d, l, "COREDUMP_COMM", comm){ int _r = retrieve(d, l, "COREDUMP_COMM", &comm); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
450 | RETRIEVE(d, l, "COREDUMP_CMDLINE", cmdline){ int _r = retrieve(d, l, "COREDUMP_CMDLINE", &cmdline); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
451 | RETRIEVE(d, l, "COREDUMP_UNIT", unit){ int _r = retrieve(d, l, "COREDUMP_UNIT", &unit); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
452 | RETRIEVE(d, l, "COREDUMP_USER_UNIT", user_unit){ int _r = retrieve(d, l, "COREDUMP_USER_UNIT", &user_unit ); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
453 | RETRIEVE(d, l, "COREDUMP_SESSION", session){ int _r = retrieve(d, l, "COREDUMP_SESSION", &session); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
454 | RETRIEVE(d, l, "COREDUMP_OWNER_UID", owner_uid){ int _r = retrieve(d, l, "COREDUMP_OWNER_UID", &owner_uid ); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
455 | RETRIEVE(d, l, "COREDUMP_SLICE", slice){ int _r = retrieve(d, l, "COREDUMP_SLICE", &slice); if ( _r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
456 | RETRIEVE(d, l, "COREDUMP_CGROUP", cgroup){ int _r = retrieve(d, l, "COREDUMP_CGROUP", &cgroup); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
457 | RETRIEVE(d, l, "COREDUMP_TIMESTAMP", timestamp){ int _r = retrieve(d, l, "COREDUMP_TIMESTAMP", ×tamp ); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
458 | RETRIEVE(d, l, "COREDUMP_FILENAME", filename){ int _r = retrieve(d, l, "COREDUMP_FILENAME", &filename) ; if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
459 | RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated){ int _r = retrieve(d, l, "COREDUMP_TRUNCATED", &truncated ); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
460 | RETRIEVE(d, l, "COREDUMP", coredump){ int _r = retrieve(d, l, "COREDUMP", &coredump); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
461 | RETRIEVE(d, l, "_BOOT_ID", boot_id){ int _r = retrieve(d, l, "_BOOT_ID", &boot_id); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
462 | RETRIEVE(d, l, "_MACHINE_ID", machine_id){ int _r = retrieve(d, l, "_MACHINE_ID", &machine_id); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
463 | RETRIEVE(d, l, "_HOSTNAME", hostname){ int _r = retrieve(d, l, "_HOSTNAME", &hostname); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
464 | RETRIEVE(d, l, "MESSAGE", message){ int _r = retrieve(d, l, "MESSAGE", &message); if (_r < 0) return _r; if (_r > 0) continue; }; | ||||||||||||||||
465 | } | ||||||||||||||||
466 | |||||||||||||||||
467 | if (need_space) | ||||||||||||||||
468 | fputs("\n", file); | ||||||||||||||||
469 | |||||||||||||||||
470 | normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR"fc" "2e" "22" "bc" "6e" "e6" "47" "b6" "b9" "07" "29" "ab" "34" "a2" "50" "b1"); | ||||||||||||||||
471 | |||||||||||||||||
472 | if (comm) | ||||||||||||||||
473 | fprintf(file, | ||||||||||||||||
474 | " PID: %s%s%s (%s)\n", | ||||||||||||||||
475 | ansi_highlight(), strna(pid), ansi_normal(), comm); | ||||||||||||||||
476 | else | ||||||||||||||||
477 | fprintf(file, | ||||||||||||||||
478 | " PID: %s%s%s\n", | ||||||||||||||||
479 | ansi_highlight(), strna(pid), ansi_normal()); | ||||||||||||||||
480 | |||||||||||||||||
481 | if (uid) { | ||||||||||||||||
482 | uid_t n; | ||||||||||||||||
483 | |||||||||||||||||
484 | if (parse_uid(uid, &n) >= 0) { | ||||||||||||||||
485 | _cleanup_free___attribute__((cleanup(freep))) char *u = NULL((void*)0); | ||||||||||||||||
486 | |||||||||||||||||
487 | u = uid_to_name(n); | ||||||||||||||||
488 | fprintf(file, | ||||||||||||||||
489 | " UID: %s (%s)\n", | ||||||||||||||||
490 | uid, u); | ||||||||||||||||
491 | } else { | ||||||||||||||||
492 | fprintf(file, | ||||||||||||||||
493 | " UID: %s\n", | ||||||||||||||||
494 | uid); | ||||||||||||||||
495 | } | ||||||||||||||||
496 | } | ||||||||||||||||
497 | |||||||||||||||||
498 | if (gid) { | ||||||||||||||||
499 | gid_t n; | ||||||||||||||||
500 | |||||||||||||||||
501 | if (parse_gid(gid, &n) >= 0) { | ||||||||||||||||
502 | _cleanup_free___attribute__((cleanup(freep))) char *g = NULL((void*)0); | ||||||||||||||||
503 | |||||||||||||||||
504 | g = gid_to_name(n); | ||||||||||||||||
505 | fprintf(file, | ||||||||||||||||
506 | " GID: %s (%s)\n", | ||||||||||||||||
507 | gid, g); | ||||||||||||||||
508 | } else { | ||||||||||||||||
509 | fprintf(file, | ||||||||||||||||
510 | " GID: %s\n", | ||||||||||||||||
511 | gid); | ||||||||||||||||
512 | } | ||||||||||||||||
513 | } | ||||||||||||||||
514 | |||||||||||||||||
515 | if (sgnl) { | ||||||||||||||||
516 | int sig; | ||||||||||||||||
517 | const char *name = normal_coredump ? "Signal" : "Reason"; | ||||||||||||||||
518 | |||||||||||||||||
519 | if (normal_coredump && safe_atoi(sgnl, &sig) >= 0) | ||||||||||||||||
520 | fprintf(file, " %s: %s (%s)\n", name, sgnl, signal_to_string(sig)); | ||||||||||||||||
521 | else | ||||||||||||||||
522 | fprintf(file, " %s: %s\n", name, sgnl); | ||||||||||||||||
523 | } | ||||||||||||||||
524 | |||||||||||||||||
525 | if (timestamp) { | ||||||||||||||||
526 | usec_t u; | ||||||||||||||||
527 | |||||||||||||||||
528 | r = safe_atou64(timestamp, &u); | ||||||||||||||||
529 | if (r >= 0) { | ||||||||||||||||
530 | char absolute[FORMAT_TIMESTAMP_MAX(3+1+10+1+8+1+6+1+6+1)], relative[FORMAT_TIMESPAN_MAX64]; | ||||||||||||||||
531 | |||||||||||||||||
532 | fprintf(file, | ||||||||||||||||
533 | " Timestamp: %s (%s)\n", | ||||||||||||||||
534 | format_timestamp(absolute, sizeof(absolute), u), | ||||||||||||||||
535 | format_timestamp_relative(relative, sizeof(relative), u)); | ||||||||||||||||
536 | |||||||||||||||||
537 | } else | ||||||||||||||||
538 | fprintf(file, " Timestamp: %s\n", timestamp); | ||||||||||||||||
539 | } | ||||||||||||||||
540 | |||||||||||||||||
541 | if (cmdline) | ||||||||||||||||
542 | fprintf(file, " Command Line: %s\n", cmdline); | ||||||||||||||||
543 | if (exe) | ||||||||||||||||
544 | fprintf(file, " Executable: %s%s%s\n", ansi_highlight(), exe, ansi_normal()); | ||||||||||||||||
545 | if (cgroup) | ||||||||||||||||
546 | fprintf(file, " Control Group: %s\n", cgroup); | ||||||||||||||||
547 | if (unit) | ||||||||||||||||
548 | fprintf(file, " Unit: %s\n", unit); | ||||||||||||||||
549 | if (user_unit) | ||||||||||||||||
550 | fprintf(file, " User Unit: %s\n", user_unit); | ||||||||||||||||
551 | if (slice) | ||||||||||||||||
552 | fprintf(file, " Slice: %s\n", slice); | ||||||||||||||||
553 | if (session) | ||||||||||||||||
554 | fprintf(file, " Session: %s\n", session); | ||||||||||||||||
555 | if (owner_uid) { | ||||||||||||||||
556 | uid_t n; | ||||||||||||||||
557 | |||||||||||||||||
558 | if (parse_uid(owner_uid, &n) >= 0) { | ||||||||||||||||
559 | _cleanup_free___attribute__((cleanup(freep))) char *u = NULL((void*)0); | ||||||||||||||||
560 | |||||||||||||||||
561 | u = uid_to_name(n); | ||||||||||||||||
562 | fprintf(file, | ||||||||||||||||
563 | " Owner UID: %s (%s)\n", | ||||||||||||||||
564 | owner_uid, u); | ||||||||||||||||
565 | } else { | ||||||||||||||||
566 | fprintf(file, | ||||||||||||||||
567 | " Owner UID: %s\n", | ||||||||||||||||
568 | owner_uid); | ||||||||||||||||
569 | } | ||||||||||||||||
570 | } | ||||||||||||||||
571 | if (boot_id) | ||||||||||||||||
572 | fprintf(file, " Boot ID: %s\n", boot_id); | ||||||||||||||||
573 | if (machine_id) | ||||||||||||||||
574 | fprintf(file, " Machine ID: %s\n", machine_id); | ||||||||||||||||
575 | if (hostname) | ||||||||||||||||
576 | fprintf(file, " Hostname: %s\n", hostname); | ||||||||||||||||
577 | |||||||||||||||||
578 | if (filename) { | ||||||||||||||||
579 | bool_Bool inacc, trunc; | ||||||||||||||||
580 | |||||||||||||||||
581 | inacc = access(filename, R_OK4) < 0; | ||||||||||||||||
582 | trunc = truncated && parse_boolean(truncated) > 0; | ||||||||||||||||
583 | |||||||||||||||||
584 | if (inacc || trunc) | ||||||||||||||||
585 | fprintf(file, " Storage: %s%s (%s%s%s)%s\n", | ||||||||||||||||
586 | ansi_highlight_red(), | ||||||||||||||||
587 | filename, | ||||||||||||||||
588 | inacc ? "inaccessible" : "", | ||||||||||||||||
589 | inacc && trunc ? ", " : "", | ||||||||||||||||
590 | trunc ? "truncated" : "", | ||||||||||||||||
591 | ansi_normal()); | ||||||||||||||||
592 | else | ||||||||||||||||
593 | fprintf(file, " Storage: %s\n", filename); | ||||||||||||||||
594 | } | ||||||||||||||||
595 | |||||||||||||||||
596 | else if (coredump) | ||||||||||||||||
597 | fprintf(file, " Storage: journal\n"); | ||||||||||||||||
598 | else | ||||||||||||||||
599 | fprintf(file, " Storage: none\n"); | ||||||||||||||||
600 | |||||||||||||||||
601 | if (message) { | ||||||||||||||||
602 | _cleanup_free___attribute__((cleanup(freep))) char *m = NULL((void*)0); | ||||||||||||||||
603 | |||||||||||||||||
604 | m = strreplace(message, "\n", "\n "); | ||||||||||||||||
605 | |||||||||||||||||
606 | fprintf(file, " Message: %s\n", strstrip(m ?: message)); | ||||||||||||||||
607 | } | ||||||||||||||||
608 | |||||||||||||||||
609 | return 0; | ||||||||||||||||
610 | } | ||||||||||||||||
611 | |||||||||||||||||
612 | static int focus(sd_journal *j) { | ||||||||||||||||
613 | int r; | ||||||||||||||||
614 | |||||||||||||||||
615 | r = sd_journal_seek_tail(j); | ||||||||||||||||
616 | if (r == 0) | ||||||||||||||||
617 | r = sd_journal_previous(j); | ||||||||||||||||
618 | if (r < 0) | ||||||||||||||||
619 | return log_error_errno(r, "Failed to search 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/coredump/coredumpctl.c", 619, __func__, "Failed to search journal: %m" ) : -abs(_e); }); | ||||||||||||||||
620 | if (r == 0) { | ||||||||||||||||
621 | log_error("No match found.")({ 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/coredump/coredumpctl.c", 621, __func__, "No match found." ) : -abs(_e); }); | ||||||||||||||||
622 | return -ESRCH3; | ||||||||||||||||
623 | } | ||||||||||||||||
624 | return r; | ||||||||||||||||
625 | } | ||||||||||||||||
626 | |||||||||||||||||
627 | static int print_entry(sd_journal *j, unsigned n_found, bool_Bool verb_is_info) { | ||||||||||||||||
628 | assert(j)do { if ((__builtin_expect(!!(!(j)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("j"), "../src/coredump/coredumpctl.c", 628 , __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
629 | |||||||||||||||||
630 | if (verb_is_info) | ||||||||||||||||
631 | return print_info(stdoutstdout, j, n_found); | ||||||||||||||||
632 | else if (arg_field) | ||||||||||||||||
633 | return print_field(stdoutstdout, j); | ||||||||||||||||
634 | else | ||||||||||||||||
635 | return print_list(stdoutstdout, j, n_found); | ||||||||||||||||
636 | } | ||||||||||||||||
637 | |||||||||||||||||
638 | static int dump_list(int argc, char **argv, void *userdata) { | ||||||||||||||||
639 | _cleanup_(sd_journal_closep)__attribute__((cleanup(sd_journal_closep))) sd_journal *j = NULL((void*)0); | ||||||||||||||||
640 | unsigned n_found = 0; | ||||||||||||||||
641 | bool_Bool verb_is_info; | ||||||||||||||||
642 | int r; | ||||||||||||||||
643 | |||||||||||||||||
644 | verb_is_info = (argc >= 1 && streq(argv[0], "info")(strcmp((argv[0]),("info")) == 0)); | ||||||||||||||||
645 | |||||||||||||||||
646 | r = acquire_journal(&j, argv + 1); | ||||||||||||||||
647 | if (r < 0) | ||||||||||||||||
648 | return r; | ||||||||||||||||
649 | |||||||||||||||||
650 | (void) pager_open(arg_no_pager, false0); | ||||||||||||||||
651 | |||||||||||||||||
652 | /* The coredumps are likely to compressed, and for just | ||||||||||||||||
653 | * listing them we don't need to decompress them, so let's | ||||||||||||||||
654 | * pick a fairly low data threshold here */ | ||||||||||||||||
655 | sd_journal_set_data_threshold(j, 4096); | ||||||||||||||||
656 | |||||||||||||||||
657 | if (arg_one) { | ||||||||||||||||
658 | r = focus(j); | ||||||||||||||||
659 | if (r < 0) | ||||||||||||||||
660 | return r; | ||||||||||||||||
661 | |||||||||||||||||
662 | return print_entry(j, 0, verb_is_info); | ||||||||||||||||
663 | } else { | ||||||||||||||||
664 | if (arg_since != USEC_INFINITY((usec_t) -1) && !arg_reverse) | ||||||||||||||||
665 | r = sd_journal_seek_realtime_usec(j, arg_since); | ||||||||||||||||
666 | else if (arg_until != USEC_INFINITY((usec_t) -1) && arg_reverse) | ||||||||||||||||
667 | r = sd_journal_seek_realtime_usec(j, arg_until); | ||||||||||||||||
668 | else if (arg_reverse) | ||||||||||||||||
669 | r = sd_journal_seek_tail(j); | ||||||||||||||||
670 | else | ||||||||||||||||
671 | r = sd_journal_seek_head(j); | ||||||||||||||||
672 | if (r < 0) | ||||||||||||||||
673 | return 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/coredump/coredumpctl.c", 673, __func__, "Failed to seek to date: %m" ) : -abs(_e); }); | ||||||||||||||||
674 | |||||||||||||||||
675 | for (;;) { | ||||||||||||||||
676 | if (!arg_reverse) | ||||||||||||||||
677 | r = sd_journal_next(j); | ||||||||||||||||
678 | else | ||||||||||||||||
679 | r = sd_journal_previous(j); | ||||||||||||||||
680 | |||||||||||||||||
681 | if (r < 0) | ||||||||||||||||
682 | return 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/coredump/coredumpctl.c", 682, __func__, "Failed to iterate through journal: %m" ) : -abs(_e); }); | ||||||||||||||||
683 | |||||||||||||||||
684 | if (r == 0) | ||||||||||||||||
685 | break; | ||||||||||||||||
686 | |||||||||||||||||
687 | if (arg_until != USEC_INFINITY((usec_t) -1) && !arg_reverse) { | ||||||||||||||||
688 | usec_t usec; | ||||||||||||||||
689 | |||||||||||||||||
690 | r = sd_journal_get_realtime_usec(j, &usec); | ||||||||||||||||
691 | if (r < 0) | ||||||||||||||||
692 | return 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/coredump/coredumpctl.c", 692, __func__, "Failed to determine timestamp: %m" ) : -abs(_e); }); | ||||||||||||||||
693 | if (usec > arg_until) | ||||||||||||||||
694 | continue; | ||||||||||||||||
695 | } | ||||||||||||||||
696 | |||||||||||||||||
697 | if (arg_since != USEC_INFINITY((usec_t) -1) && arg_reverse) { | ||||||||||||||||
698 | usec_t usec; | ||||||||||||||||
699 | |||||||||||||||||
700 | r = sd_journal_get_realtime_usec(j, &usec); | ||||||||||||||||
701 | if (r < 0) | ||||||||||||||||
702 | return 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/coredump/coredumpctl.c", 702, __func__, "Failed to determine timestamp: %m" ) : -abs(_e); }); | ||||||||||||||||
703 | if (usec < arg_since) | ||||||||||||||||
704 | continue; | ||||||||||||||||
705 | } | ||||||||||||||||
706 | |||||||||||||||||
707 | r = print_entry(j, n_found++, verb_is_info); | ||||||||||||||||
708 | if (r < 0) | ||||||||||||||||
709 | return r; | ||||||||||||||||
710 | } | ||||||||||||||||
711 | |||||||||||||||||
712 | if (!arg_field && n_found <= 0) { | ||||||||||||||||
713 | if (!arg_quiet) | ||||||||||||||||
714 | log_notice("No coredumps found.")({ 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/coredump/coredumpctl.c", 714, __func__, "No coredumps found." ) : -abs(_e); }); | ||||||||||||||||
715 | return -ESRCH3; | ||||||||||||||||
716 | } | ||||||||||||||||
717 | } | ||||||||||||||||
718 | |||||||||||||||||
719 | return 0; | ||||||||||||||||
720 | } | ||||||||||||||||
721 | |||||||||||||||||
722 | static int save_core(sd_journal *j, FILE *file, char **path, bool_Bool *unlink_temp) { | ||||||||||||||||
723 | const char *data; | ||||||||||||||||
724 | _cleanup_free___attribute__((cleanup(freep))) char *filename = NULL((void*)0); | ||||||||||||||||
725 | size_t len; | ||||||||||||||||
726 | int r, fd; | ||||||||||||||||
727 | _cleanup_close___attribute__((cleanup(closep))) int fdt = -1; | ||||||||||||||||
728 | char *temp = NULL((void*)0); | ||||||||||||||||
729 | |||||||||||||||||
730 | assert(!(file && path))do { if ((__builtin_expect(!!(!(!(file && path))),0)) ) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!(file && path)" ), "../src/coredump/coredumpctl.c", 730, __PRETTY_FUNCTION__) ; } while (0); /* At most one can be specified */ | ||||||||||||||||
731 | assert(!!path == !!unlink_temp)do { if ((__builtin_expect(!!(!(!!path == !!unlink_temp)),0)) ) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!!path == !!unlink_temp" ), "../src/coredump/coredumpctl.c", 731, __PRETTY_FUNCTION__) ; } while (0); /* Those must be specified together */ | ||||||||||||||||
732 | |||||||||||||||||
733 | /* Look for a coredump on disk first. */ | ||||||||||||||||
734 | r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len); | ||||||||||||||||
735 | if (r == 0) | ||||||||||||||||
736 | retrieve(data, len, "COREDUMP_FILENAME", &filename); | ||||||||||||||||
737 | else { | ||||||||||||||||
738 | if (r != -ENOENT2) | ||||||||||||||||
739 | return log_error_errno(r, "Failed to retrieve COREDUMP_FILENAME 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/coredump/coredumpctl.c", 739, __func__, "Failed to retrieve COREDUMP_FILENAME field: %m" ) : -abs(_e); }); | ||||||||||||||||
740 | /* Check that we can have a COREDUMP field. We still haven't set a high | ||||||||||||||||
741 | * data threshold, so we'll get a few kilobytes at most. | ||||||||||||||||
742 | */ | ||||||||||||||||
743 | |||||||||||||||||
744 | r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len); | ||||||||||||||||
745 | if (r == -ENOENT2) | ||||||||||||||||
746 | return log_error_errno(r, "Coredump entry has no core attached (neither internally in the journal nor externally on disk).")({ 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/coredump/coredumpctl.c", 746, __func__, "Coredump entry has no core attached (neither internally in the journal nor externally on disk)." ) : -abs(_e); }); | ||||||||||||||||
747 | if (r < 0) | ||||||||||||||||
748 | return log_error_errno(r, "Failed to retrieve COREDUMP 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/coredump/coredumpctl.c", 748, __func__, "Failed to retrieve COREDUMP field: %m" ) : -abs(_e); }); | ||||||||||||||||
749 | } | ||||||||||||||||
750 | |||||||||||||||||
751 | if (filename) { | ||||||||||||||||
752 | if (access(filename, R_OK4) < 0) | ||||||||||||||||
753 | return log_error_errno(errno, "File \"%s\" is not readable: %m", filename)({ 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/coredump/coredumpctl.c", 753, __func__ , "File \"%s\" is not readable: %m", filename) : -abs(_e); }); | ||||||||||||||||
754 | |||||||||||||||||
755 | if (path && !endswith(filename, ".xz") && !endswith(filename, ".lz4")) { | ||||||||||||||||
756 | *path = TAKE_PTR(filename)({ typeof(filename) _ptr_ = (filename); (filename) = ((void*) 0); _ptr_; }); | ||||||||||||||||
757 | |||||||||||||||||
758 | return 0; | ||||||||||||||||
759 | } | ||||||||||||||||
760 | } | ||||||||||||||||
761 | |||||||||||||||||
762 | if (path) { | ||||||||||||||||
763 | const char *vt; | ||||||||||||||||
764 | |||||||||||||||||
765 | /* Create a temporary file to write the uncompressed core to. */ | ||||||||||||||||
766 | |||||||||||||||||
767 | r = var_tmp_dir(&vt); | ||||||||||||||||
768 | if (r < 0) | ||||||||||||||||
769 | return log_error_errno(r, "Failed to acquire temporary directory 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/coredump/coredumpctl.c", 769, __func__, "Failed to acquire temporary directory path: %m" ) : -abs(_e); }); | ||||||||||||||||
770 | |||||||||||||||||
771 | temp = strjoin(vt, "/coredump-XXXXXX")strjoin_real((vt), "/coredump-XXXXXX", ((void*)0)); | ||||||||||||||||
772 | if (!temp) | ||||||||||||||||
773 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/coredump/coredumpctl.c" , 773, __func__); | ||||||||||||||||
774 | |||||||||||||||||
775 | fdt = mkostemp_safe(temp); | ||||||||||||||||
776 | if (fdt < 0) | ||||||||||||||||
777 | return log_error_errno(fdt, "Failed to create temporary file: %m")({ int _level = ((3)), _e = ((fdt)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/coredump/coredumpctl.c", 777, __func__, "Failed to create temporary file: %m" ) : -abs(_e); }); | ||||||||||||||||
778 | log_debug("Created temporary file %s", temp)({ 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/coredump/coredumpctl.c", 778, __func__, "Created temporary file %s" , temp) : -abs(_e); }); | ||||||||||||||||
779 | |||||||||||||||||
780 | fd = fdt; | ||||||||||||||||
781 | } else { | ||||||||||||||||
782 | /* If neither path or file are specified, we will write to stdout. Let's now check | ||||||||||||||||
783 | * if stdout is connected to a tty. We checked that the file exists, or that the | ||||||||||||||||
784 | * core might be stored in the journal. In this second case, if we found the entry, | ||||||||||||||||
785 | * in all likelyhood we will be able to access the COREDUMP= field. In either case, | ||||||||||||||||
786 | * we stop before doing any "real" work, i.e. before starting decompression or | ||||||||||||||||
787 | * reading from the file or creating temporary files. | ||||||||||||||||
788 | */ | ||||||||||||||||
789 | if (!file) { | ||||||||||||||||
790 | if (on_tty()) | ||||||||||||||||
791 | return log_error_errno(ENOTTY, "Refusing to dump core to tty"({ int _level = ((3)), _e = ((25)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/coredump/coredumpctl.c", 792, __func__, "Refusing to dump core to tty" " (use shell redirection or specify --output).") : -abs(_e); }) | ||||||||||||||||
792 | " (use shell redirection or specify --output).")({ int _level = ((3)), _e = ((25)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/coredump/coredumpctl.c", 792, __func__, "Refusing to dump core to tty" " (use shell redirection or specify --output).") : -abs(_e); }); | ||||||||||||||||
793 | file = stdoutstdout; | ||||||||||||||||
794 | } | ||||||||||||||||
795 | |||||||||||||||||
796 | fd = fileno(file); | ||||||||||||||||
797 | } | ||||||||||||||||
798 | |||||||||||||||||
799 | if (filename) { | ||||||||||||||||
800 | #if HAVE_XZ1 || HAVE_LZ41 | ||||||||||||||||
801 | _cleanup_close___attribute__((cleanup(closep))) int fdf; | ||||||||||||||||
802 | |||||||||||||||||
803 | fdf = open(filename, O_RDONLY00 | O_CLOEXEC02000000); | ||||||||||||||||
804 | if (fdf < 0) { | ||||||||||||||||
805 | r = log_error_errno(errno, "Failed to open %s: %m", filename)({ 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/coredump/coredumpctl.c", 805, __func__ , "Failed to open %s: %m", filename) : -abs(_e); }); | ||||||||||||||||
806 | goto error; | ||||||||||||||||
807 | } | ||||||||||||||||
808 | |||||||||||||||||
809 | r = decompress_stream(filename, fdf, fd, -1); | ||||||||||||||||
810 | if (r < 0) { | ||||||||||||||||
811 | log_error_errno(r, "Failed to decompress %s: %m", filename)({ 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/coredump/coredumpctl.c", 811, __func__, "Failed to decompress %s: %m" , filename) : -abs(_e); }); | ||||||||||||||||
812 | goto error; | ||||||||||||||||
813 | } | ||||||||||||||||
814 | #else | ||||||||||||||||
815 | log_error("Cannot decompress file. Compiled without compression 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/coredump/coredumpctl.c", 815, __func__, "Cannot decompress file. Compiled without compression support." ) : -abs(_e); }); | ||||||||||||||||
816 | r = -EOPNOTSUPP95; | ||||||||||||||||
817 | goto error; | ||||||||||||||||
818 | #endif | ||||||||||||||||
819 | } else { | ||||||||||||||||
820 | ssize_t sz; | ||||||||||||||||
821 | |||||||||||||||||
822 | /* We want full data, nothing truncated. */ | ||||||||||||||||
823 | sd_journal_set_data_threshold(j, 0); | ||||||||||||||||
824 | |||||||||||||||||
825 | r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len); | ||||||||||||||||
826 | if (r < 0) | ||||||||||||||||
827 | return log_error_errno(r, "Failed to retrieve COREDUMP 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/coredump/coredumpctl.c", 827, __func__, "Failed to retrieve COREDUMP field: %m" ) : -abs(_e); }); | ||||||||||||||||
828 | |||||||||||||||||
829 | assert(len >= 9)do { if ((__builtin_expect(!!(!(len >= 9)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("len >= 9"), "../src/coredump/coredumpctl.c" , 829, __PRETTY_FUNCTION__); } while (0); | ||||||||||||||||
830 | data += 9; | ||||||||||||||||
831 | len -= 9; | ||||||||||||||||
832 | |||||||||||||||||
833 | sz = write(fd, data, len); | ||||||||||||||||
834 | if (sz < 0) { | ||||||||||||||||
835 | r = log_error_errno(errno, "Failed to write output: %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/coredump/coredumpctl.c", 835, __func__ , "Failed to write output: %m") : -abs(_e); }); | ||||||||||||||||
836 | goto error; | ||||||||||||||||
837 | } | ||||||||||||||||
838 | if (sz != (ssize_t) len) { | ||||||||||||||||
839 | log_error("Short write to output.")({ 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/coredump/coredumpctl.c", 839, __func__, "Short write to output." ) : -abs(_e); }); | ||||||||||||||||
840 | r = -EIO5; | ||||||||||||||||
841 | goto error; | ||||||||||||||||
842 | } | ||||||||||||||||
843 | } | ||||||||||||||||
844 | |||||||||||||||||
845 | if (temp) { | ||||||||||||||||
846 | *path = temp; | ||||||||||||||||
847 | *unlink_temp = true1; | ||||||||||||||||
848 | } | ||||||||||||||||
849 | return 0; | ||||||||||||||||
850 | |||||||||||||||||
851 | error: | ||||||||||||||||
852 | if (temp) { | ||||||||||||||||
853 | unlink(temp); | ||||||||||||||||
854 | log_debug("Removed temporary file %s", temp)({ 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/coredump/coredumpctl.c", 854, __func__, "Removed temporary file %s" , temp) : -abs(_e); }); | ||||||||||||||||
855 | } | ||||||||||||||||
856 | return r; | ||||||||||||||||
857 | } | ||||||||||||||||
858 | |||||||||||||||||
859 | static int dump_core(int argc, char **argv, void *userdata) { | ||||||||||||||||
860 | _cleanup_(sd_journal_closep)__attribute__((cleanup(sd_journal_closep))) sd_journal *j = NULL((void*)0); | ||||||||||||||||
861 | int r; | ||||||||||||||||
862 | |||||||||||||||||
863 | if (arg_field) { | ||||||||||||||||
864 | log_error("Option --field/-F only makes sense with list")({ 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/coredump/coredumpctl.c", 864, __func__, "Option --field/-F only makes sense with list" ) : -abs(_e); }); | ||||||||||||||||
865 | return -EINVAL22; | ||||||||||||||||
866 | } | ||||||||||||||||
867 | |||||||||||||||||
868 | r = acquire_journal(&j, argv + 1); | ||||||||||||||||
869 | if (r < 0) | ||||||||||||||||
870 | return r; | ||||||||||||||||
871 | |||||||||||||||||
872 | r = focus(j); | ||||||||||||||||
873 | if (r < 0) | ||||||||||||||||
874 | return r; | ||||||||||||||||
875 | |||||||||||||||||
876 | print_info(arg_output ? stdoutstdout : stderrstderr, j, false0); | ||||||||||||||||
877 | |||||||||||||||||
878 | r = save_core(j, arg_output, NULL((void*)0), NULL((void*)0)); | ||||||||||||||||
879 | if (r < 0) | ||||||||||||||||
880 | return r; | ||||||||||||||||
881 | |||||||||||||||||
882 | r = sd_journal_previous(j); | ||||||||||||||||
883 | if (r > 0 && !arg_quiet) | ||||||||||||||||
884 | log_notice("More than one entry matches, ignoring rest.")({ 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/coredump/coredumpctl.c", 884, __func__, "More than one entry matches, ignoring rest." ) : -abs(_e); }); | ||||||||||||||||
885 | |||||||||||||||||
886 | return 0; | ||||||||||||||||
887 | } | ||||||||||||||||
888 | |||||||||||||||||
889 | static int run_debug(int argc, char **argv, void *userdata) { | ||||||||||||||||
890 | _cleanup_(sd_journal_closep)__attribute__((cleanup(sd_journal_closep))) sd_journal *j = NULL((void*)0); | ||||||||||||||||
891 | _cleanup_free___attribute__((cleanup(freep))) char *exe = NULL((void*)0), *path = NULL((void*)0); | ||||||||||||||||
892 | bool_Bool unlink_path = false0; | ||||||||||||||||
893 | const char *data, *fork_name; | ||||||||||||||||
894 | size_t len; | ||||||||||||||||
895 | pid_t pid; | ||||||||||||||||
896 | int r; | ||||||||||||||||
897 | |||||||||||||||||
898 | if (!arg_debugger) { | ||||||||||||||||
899 | char *env_debugger; | ||||||||||||||||
900 | |||||||||||||||||
901 | env_debugger = getenv("SYSTEMD_DEBUGGER"); | ||||||||||||||||
902 | if (env_debugger) | ||||||||||||||||
903 | arg_debugger = env_debugger; | ||||||||||||||||
904 | else | ||||||||||||||||
905 | arg_debugger = "gdb"; | ||||||||||||||||
906 | } | ||||||||||||||||
907 | |||||||||||||||||
908 | if (arg_field) { | ||||||||||||||||
909 | log_error("Option --field/-F only makes sense with list")({ 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/coredump/coredumpctl.c", 909, __func__, "Option --field/-F only makes sense with list" ) : -abs(_e); }); | ||||||||||||||||
910 | return -EINVAL22; | ||||||||||||||||
911 | } | ||||||||||||||||
912 | |||||||||||||||||
913 | r = acquire_journal(&j, argv + 1); | ||||||||||||||||
914 | if (r < 0) | ||||||||||||||||
915 | return r; | ||||||||||||||||
916 | |||||||||||||||||
917 | r = focus(j); | ||||||||||||||||
918 | if (r < 0) | ||||||||||||||||
919 | return r; | ||||||||||||||||
920 | |||||||||||||||||
921 | print_info(stdoutstdout, j, false0); | ||||||||||||||||
922 | fputs("\n", stdoutstdout); | ||||||||||||||||
923 | |||||||||||||||||
924 | r = sd_journal_get_data(j, "COREDUMP_EXE", (const void**) &data, &len); | ||||||||||||||||
925 | if (r < 0) | ||||||||||||||||
926 | return log_error_errno(r, "Failed to retrieve COREDUMP_EXE 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/coredump/coredumpctl.c", 926, __func__, "Failed to retrieve COREDUMP_EXE field: %m" ) : -abs(_e); }); | ||||||||||||||||
927 | |||||||||||||||||
928 | assert(len > STRLEN("COREDUMP_EXE="))do { if ((__builtin_expect(!!(!(len > (sizeof("""COREDUMP_EXE=" "") - 1))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("len > STRLEN(\"COREDUMP_EXE=\")" ), "../src/coredump/coredumpctl.c", 928, __PRETTY_FUNCTION__) ; } while (0); | ||||||||||||||||
929 | data += STRLEN("COREDUMP_EXE=")(sizeof("""COREDUMP_EXE=""") - 1); | ||||||||||||||||
930 | len -= STRLEN("COREDUMP_EXE=")(sizeof("""COREDUMP_EXE=""") - 1); | ||||||||||||||||
931 | |||||||||||||||||
932 | exe = strndup(data, len); | ||||||||||||||||
933 | if (!exe) | ||||||||||||||||
934 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/coredump/coredumpctl.c" , 934, __func__); | ||||||||||||||||
935 | |||||||||||||||||
936 | if (endswith(exe, " (deleted)")) { | ||||||||||||||||
937 | log_error("Binary already deleted.")({ 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/coredump/coredumpctl.c", 937, __func__, "Binary already deleted." ) : -abs(_e); }); | ||||||||||||||||
938 | return -ENOENT2; | ||||||||||||||||
939 | } | ||||||||||||||||
940 | |||||||||||||||||
941 | if (!path_is_absolute(exe)) { | ||||||||||||||||
942 | log_error("Binary is not an absolute path.")({ 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/coredump/coredumpctl.c", 942, __func__, "Binary is not an absolute path." ) : -abs(_e); }); | ||||||||||||||||
943 | return -ENOENT2; | ||||||||||||||||
944 | } | ||||||||||||||||
945 | |||||||||||||||||
946 | r = save_core(j, NULL((void*)0), &path, &unlink_path); | ||||||||||||||||
947 | if (r < 0) | ||||||||||||||||
948 | return r; | ||||||||||||||||
949 | |||||||||||||||||
950 | /* Don't interfere with gdb and its handling of SIGINT. */ | ||||||||||||||||
951 | (void) ignore_signals(SIGINT2, -1); | ||||||||||||||||
952 | |||||||||||||||||
953 | fork_name = strjoina("(", arg_debugger, ")")({ const char *_appendees_[] = { "(", arg_debugger, ")" }; 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_; }); | ||||||||||||||||
954 | |||||||||||||||||
955 | r = safe_fork(fork_name, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_LOG, &pid); | ||||||||||||||||
956 | if (r < 0) | ||||||||||||||||
957 | goto finish; | ||||||||||||||||
958 | if (r == 0) { | ||||||||||||||||
959 | execlp(arg_debugger, arg_debugger, exe, "-c", path, NULL((void*)0)); | ||||||||||||||||
960 | log_open(); | ||||||||||||||||
961 | log_error_errno(errno, "Failed to invoke %s: %m", arg_debugger)({ 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/coredump/coredumpctl.c", 961, __func__ , "Failed to invoke %s: %m", arg_debugger) : -abs(_e); }); | ||||||||||||||||
962 | _exit(EXIT_FAILURE1); | ||||||||||||||||
963 | } | ||||||||||||||||
964 | |||||||||||||||||
965 | r = wait_for_terminate_and_check(arg_debugger, pid, WAIT_LOG_ABNORMAL); | ||||||||||||||||
966 | |||||||||||||||||
967 | finish: | ||||||||||||||||
968 | (void) default_signals(SIGINT2, -1); | ||||||||||||||||
969 | |||||||||||||||||
970 | if (unlink_path) { | ||||||||||||||||
971 | log_debug("Removed temporary file %s", path)({ 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/coredump/coredumpctl.c", 971, __func__, "Removed temporary file %s" , path) : -abs(_e); }); | ||||||||||||||||
972 | unlink(path); | ||||||||||||||||
973 | } | ||||||||||||||||
974 | |||||||||||||||||
975 | return r; | ||||||||||||||||
976 | } | ||||||||||||||||
977 | |||||||||||||||||
978 | static int check_units_active(void) { | ||||||||||||||||
979 | _cleanup_(sd_bus_unrefp)__attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus = NULL((void*)0); | ||||||||||||||||
980 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *m = NULL((void*)0); | ||||||||||||||||
981 | _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}); | ||||||||||||||||
982 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL((void*)0); | ||||||||||||||||
983 | int c = 0, r; | ||||||||||||||||
984 | const char *id, *state, *substate; | ||||||||||||||||
985 | |||||||||||||||||
986 | if (arg_quiet) | ||||||||||||||||
987 | return false0; | ||||||||||||||||
988 | |||||||||||||||||
989 | r = sd_bus_default_system(&bus); | ||||||||||||||||
990 | if (r < 0) | ||||||||||||||||
991 | return log_error_errno(r, "Failed to acquire 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/coredump/coredumpctl.c", 991, __func__, "Failed to acquire bus: %m" ) : -abs(_e); }); | ||||||||||||||||
992 | |||||||||||||||||
993 | r = sd_bus_message_new_method_call( | ||||||||||||||||
994 | bus, | ||||||||||||||||
995 | &m, | ||||||||||||||||
996 | "org.freedesktop.systemd1", | ||||||||||||||||
997 | "/org/freedesktop/systemd1", | ||||||||||||||||
998 | "org.freedesktop.systemd1.Manager", | ||||||||||||||||
999 | "ListUnitsByPatterns"); | ||||||||||||||||
1000 | if (r < 0) | ||||||||||||||||
1001 | return bus_log_create_error(r); | ||||||||||||||||
1002 | |||||||||||||||||
1003 | r = sd_bus_message_append_strv(m, NULL((void*)0)); | ||||||||||||||||
1004 | if (r < 0) | ||||||||||||||||
1005 | return bus_log_create_error(r); | ||||||||||||||||
1006 | |||||||||||||||||
1007 | r = sd_bus_message_append_strv(m, STRV_MAKE("systemd-coredump@*.service")((char**) ((const char*[]) { "systemd-coredump@*.service", (( void*)0) }))); | ||||||||||||||||
1008 | if (r < 0) | ||||||||||||||||
1009 | return bus_log_create_error(r); | ||||||||||||||||
1010 | |||||||||||||||||
1011 | r = sd_bus_call(bus, m, SHORT_BUS_CALL_TIMEOUT_USEC(3 * ((usec_t) 1000000ULL)), &error, &reply); | ||||||||||||||||
1012 | if (r < 0) | ||||||||||||||||
1013 | return log_error_errno(r, "Failed to check if any systemd-coredump@.service units are running: %s",({ 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/coredump/coredumpctl.c", 1014, __func__, "Failed to check if any systemd-coredump@.service units are running: %s" , bus_error_message(&error, r)) : -abs(_e); }) | ||||||||||||||||
1014 | 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/coredump/coredumpctl.c", 1014, __func__, "Failed to check if any systemd-coredump@.service units are running: %s" , bus_error_message(&error, r)) : -abs(_e); }); | ||||||||||||||||
1015 | |||||||||||||||||
1016 | r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)"); | ||||||||||||||||
1017 | if (r < 0) | ||||||||||||||||
1018 | return bus_log_parse_error(r); | ||||||||||||||||
1019 | |||||||||||||||||
1020 | while ((r = sd_bus_message_read( | ||||||||||||||||
1021 | reply, "(ssssssouso)", | ||||||||||||||||
1022 | &id, NULL((void*)0), NULL((void*)0), &state, &substate, | ||||||||||||||||
1023 | NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0))) > 0) { | ||||||||||||||||
1024 | bool_Bool found = !STR_IN_SET(state, "inactive", "dead", "failed")(!!strv_find((((char**) ((const char*[]) { "inactive", "dead" , "failed", ((void*)0) }))), (state))); | ||||||||||||||||
1025 | log_debug("Unit %s is %s/%s, %scounting it.", id, state, substate, found ? "" : "not ")({ 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/coredump/coredumpctl.c", 1025, __func__, "Unit %s is %s/%s, %scounting it." , id, state, substate, found ? "" : "not ") : -abs(_e); }); | ||||||||||||||||
1026 | c += found; | ||||||||||||||||
1027 | } | ||||||||||||||||
1028 | if (r < 0) | ||||||||||||||||
1029 | return bus_log_parse_error(r); | ||||||||||||||||
1030 | |||||||||||||||||
1031 | r = sd_bus_message_exit_container(reply); | ||||||||||||||||
1032 | if (r < 0) | ||||||||||||||||
1033 | return bus_log_parse_error(r); | ||||||||||||||||
1034 | |||||||||||||||||
1035 | return c; | ||||||||||||||||
1036 | } | ||||||||||||||||
1037 | |||||||||||||||||
1038 | static int coredumpctl_main(int argc, char *argv[]) { | ||||||||||||||||
1039 | |||||||||||||||||
1040 | static const Verb verbs[] = { | ||||||||||||||||
1041 | { "list", VERB_ANY((unsigned) -1), VERB_ANY((unsigned) -1), VERB_DEFAULT, dump_list }, | ||||||||||||||||
1042 | { "info", VERB_ANY((unsigned) -1), VERB_ANY((unsigned) -1), 0, dump_list }, | ||||||||||||||||
1043 | { "dump", VERB_ANY((unsigned) -1), VERB_ANY((unsigned) -1), 0, dump_core }, | ||||||||||||||||
1044 | { "debug", VERB_ANY((unsigned) -1), VERB_ANY((unsigned) -1), 0, run_debug }, | ||||||||||||||||
1045 | { "gdb", VERB_ANY((unsigned) -1), VERB_ANY((unsigned) -1), 0, run_debug }, | ||||||||||||||||
1046 | {} | ||||||||||||||||
1047 | }; | ||||||||||||||||
1048 | |||||||||||||||||
1049 | return dispatch_verb(argc, argv, verbs, NULL((void*)0)); | ||||||||||||||||
1050 | } | ||||||||||||||||
1051 | |||||||||||||||||
1052 | int main(int argc, char *argv[]) { | ||||||||||||||||
1053 | int r, units_active; | ||||||||||||||||
1054 | |||||||||||||||||
1055 | setlocale(LC_ALL6, ""); | ||||||||||||||||
1056 | log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD); | ||||||||||||||||
1057 | log_open(); | ||||||||||||||||
1058 | |||||||||||||||||
1059 | r = parse_argv(argc, argv); | ||||||||||||||||
1060 | if (r <= 0) | ||||||||||||||||
1061 | goto end; | ||||||||||||||||
1062 | |||||||||||||||||
1063 | sigbus_install(); | ||||||||||||||||
1064 | |||||||||||||||||
1065 | units_active = check_units_active(); /* error is treated the same as 0 */ | ||||||||||||||||
1066 | |||||||||||||||||
1067 | r = coredumpctl_main(argc, argv); | ||||||||||||||||
1068 | |||||||||||||||||
1069 | if (units_active > 0) | ||||||||||||||||
1070 | printf("%s-- Notice: %d systemd-coredump@.service %s, output may be incomplete.%s\n", | ||||||||||||||||
1071 | ansi_highlight_red(), | ||||||||||||||||
1072 | units_active, units_active == 1 ? "unit is running" : "units are running", | ||||||||||||||||
1073 | ansi_normal()); | ||||||||||||||||
1074 | end: | ||||||||||||||||
1075 | pager_close(); | ||||||||||||||||
1076 | |||||||||||||||||
1077 | safe_fclose(arg_output); | ||||||||||||||||
1078 | |||||||||||||||||
1079 | return r >= 0 ? r : EXIT_FAILURE1; | ||||||||||||||||
1080 | } |