File: | build-scan/../src/journal-remote/journal-gatewayd.c |
Warning: | line 311, column 27 Potential leak of memory pointed to by 't' |
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 <microhttpd.h> | |||
6 | #include <stdlib.h> | |||
7 | #include <string.h> | |||
8 | #include <unistd.h> | |||
9 | ||||
10 | #include "sd-bus.h" | |||
11 | #include "sd-daemon.h" | |||
12 | #include "sd-journal.h" | |||
13 | ||||
14 | #include "alloc-util.h" | |||
15 | #include "bus-util.h" | |||
16 | #include "fd-util.h" | |||
17 | #include "fileio.h" | |||
18 | #include "hostname-util.h" | |||
19 | #include "log.h" | |||
20 | #include "logs-show.h" | |||
21 | #include "microhttpd-util.h" | |||
22 | #include "os-util.h" | |||
23 | #include "parse-util.h" | |||
24 | #include "sigbus.h" | |||
25 | #include "util.h" | |||
26 | ||||
27 | #define JOURNAL_WAIT_TIMEOUT(10*((usec_t) 1000000ULL)) (10*USEC_PER_SEC((usec_t) 1000000ULL)) | |||
28 | ||||
29 | static char *arg_key_pem = NULL((void*)0); | |||
30 | static char *arg_cert_pem = NULL((void*)0); | |||
31 | static char *arg_trust_pem = NULL((void*)0); | |||
32 | static char *arg_directory = NULL((void*)0); | |||
33 | ||||
34 | typedef struct RequestMeta { | |||
35 | sd_journal *journal; | |||
36 | ||||
37 | OutputMode mode; | |||
38 | ||||
39 | char *cursor; | |||
40 | int64_t n_skip; | |||
41 | uint64_t n_entries; | |||
42 | bool_Bool n_entries_set; | |||
43 | ||||
44 | FILE *tmp; | |||
45 | uint64_t delta, size; | |||
46 | ||||
47 | int argument_parse_error; | |||
48 | ||||
49 | bool_Bool follow; | |||
50 | bool_Bool discrete; | |||
51 | ||||
52 | uint64_t n_fields; | |||
53 | bool_Bool n_fields_set; | |||
54 | } RequestMeta; | |||
55 | ||||
56 | static const char* const mime_types[_OUTPUT_MODE_MAX] = { | |||
57 | [OUTPUT_SHORT] = "text/plain", | |||
58 | [OUTPUT_JSON] = "application/json", | |||
59 | [OUTPUT_JSON_SSE] = "text/event-stream", | |||
60 | [OUTPUT_EXPORT] = "application/vnd.fdo.journal", | |||
61 | }; | |||
62 | ||||
63 | static RequestMeta *request_meta(void **connection_cls) { | |||
64 | RequestMeta *m; | |||
65 | ||||
66 | assert(connection_cls)do { if ((__builtin_expect(!!(!(connection_cls)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("connection_cls"), "../src/journal-remote/journal-gatewayd.c" , 66, __PRETTY_FUNCTION__); } while (0); | |||
67 | if (*connection_cls) | |||
68 | return *connection_cls; | |||
69 | ||||
70 | m = new0(RequestMeta, 1)((RequestMeta*) calloc((1), sizeof(RequestMeta))); | |||
71 | if (!m) | |||
72 | return NULL((void*)0); | |||
73 | ||||
74 | *connection_cls = m; | |||
75 | return m; | |||
76 | } | |||
77 | ||||
78 | static void request_meta_free( | |||
79 | void *cls, | |||
80 | struct MHD_Connection *connection, | |||
81 | void **connection_cls, | |||
82 | enum MHD_RequestTerminationCode toe) { | |||
83 | ||||
84 | RequestMeta *m = *connection_cls; | |||
85 | ||||
86 | if (!m) | |||
87 | return; | |||
88 | ||||
89 | sd_journal_close(m->journal); | |||
90 | ||||
91 | safe_fclose(m->tmp); | |||
92 | ||||
93 | free(m->cursor); | |||
94 | free(m); | |||
95 | } | |||
96 | ||||
97 | static int open_journal(RequestMeta *m) { | |||
98 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal-remote/journal-gatewayd.c" , 98, __PRETTY_FUNCTION__); } while (0); | |||
99 | ||||
100 | if (m->journal) | |||
101 | return 0; | |||
102 | ||||
103 | if (arg_directory) | |||
104 | return sd_journal_open_directory(&m->journal, arg_directory, 0); | |||
105 | else | |||
106 | return sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM); | |||
107 | } | |||
108 | ||||
109 | static int request_meta_ensure_tmp(RequestMeta *m) { | |||
110 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal-remote/journal-gatewayd.c" , 110, __PRETTY_FUNCTION__); } while (0); | |||
111 | ||||
112 | if (m->tmp) | |||
113 | rewind(m->tmp); | |||
114 | else { | |||
115 | int fd; | |||
116 | ||||
117 | fd = open_tmpfile_unlinkable("/tmp", O_RDWR02|O_CLOEXEC02000000); | |||
118 | if (fd < 0) | |||
119 | return fd; | |||
120 | ||||
121 | m->tmp = fdopen(fd, "w+"); | |||
122 | if (!m->tmp) { | |||
123 | safe_close(fd); | |||
124 | return -errno(*__errno_location ()); | |||
125 | } | |||
126 | } | |||
127 | ||||
128 | return 0; | |||
129 | } | |||
130 | ||||
131 | static ssize_t request_reader_entries( | |||
132 | void *cls, | |||
133 | uint64_t pos, | |||
134 | char *buf, | |||
135 | size_t max) { | |||
136 | ||||
137 | RequestMeta *m = cls; | |||
138 | int r; | |||
139 | size_t n, k; | |||
140 | ||||
141 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal-remote/journal-gatewayd.c" , 141, __PRETTY_FUNCTION__); } while (0); | |||
142 | assert(buf)do { if ((__builtin_expect(!!(!(buf)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("buf"), "../src/journal-remote/journal-gatewayd.c" , 142, __PRETTY_FUNCTION__); } while (0); | |||
143 | assert(max > 0)do { if ((__builtin_expect(!!(!(max > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("max > 0"), "../src/journal-remote/journal-gatewayd.c" , 143, __PRETTY_FUNCTION__); } while (0); | |||
144 | assert(pos >= m->delta)do { if ((__builtin_expect(!!(!(pos >= m->delta)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("pos >= m->delta"), "../src/journal-remote/journal-gatewayd.c" , 144, __PRETTY_FUNCTION__); } while (0); | |||
145 | ||||
146 | pos -= m->delta; | |||
147 | ||||
148 | while (pos >= m->size) { | |||
149 | off_t sz; | |||
150 | ||||
151 | /* End of this entry, so let's serialize the next | |||
152 | * one */ | |||
153 | ||||
154 | if (m->n_entries_set && | |||
155 | m->n_entries <= 0) | |||
156 | return MHD_CONTENT_READER_END_OF_STREAM(18446744073709551615UL); | |||
157 | ||||
158 | if (m->n_skip < 0) | |||
159 | r = sd_journal_previous_skip(m->journal, (uint64_t) -m->n_skip + 1); | |||
160 | else if (m->n_skip > 0) | |||
161 | r = sd_journal_next_skip(m->journal, (uint64_t) m->n_skip + 1); | |||
162 | else | |||
163 | r = sd_journal_next(m->journal); | |||
164 | ||||
165 | if (r < 0) { | |||
166 | log_error_errno(r, "Failed to advance journal pointer: %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-remote/journal-gatewayd.c", 166, __func__, "Failed to advance journal pointer: %m" ) : -abs(_e); }); | |||
167 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
168 | } else if (r == 0) { | |||
169 | ||||
170 | if (m->follow) { | |||
171 | r = sd_journal_wait(m->journal, (uint64_t) JOURNAL_WAIT_TIMEOUT(10*((usec_t) 1000000ULL))); | |||
172 | if (r < 0) { | |||
173 | 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-remote/journal-gatewayd.c", 173, __func__, "Couldn't wait for journal event: %m" ) : -abs(_e); }); | |||
174 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
175 | } | |||
176 | if (r == SD_JOURNAL_NOP) | |||
177 | break; | |||
178 | ||||
179 | continue; | |||
180 | } | |||
181 | ||||
182 | return MHD_CONTENT_READER_END_OF_STREAM(18446744073709551615UL); | |||
183 | } | |||
184 | ||||
185 | if (m->discrete) { | |||
186 | assert(m->cursor)do { if ((__builtin_expect(!!(!(m->cursor)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m->cursor"), "../src/journal-remote/journal-gatewayd.c" , 186, __PRETTY_FUNCTION__); } while (0); | |||
187 | ||||
188 | r = sd_journal_test_cursor(m->journal, m->cursor); | |||
189 | if (r < 0) { | |||
190 | log_error_errno(r, "Failed to test 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-remote/journal-gatewayd.c", 190, __func__, "Failed to test cursor: %m" ) : -abs(_e); }); | |||
191 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
192 | } | |||
193 | ||||
194 | if (r == 0) | |||
195 | return MHD_CONTENT_READER_END_OF_STREAM(18446744073709551615UL); | |||
196 | } | |||
197 | ||||
198 | pos -= m->size; | |||
199 | m->delta += m->size; | |||
200 | ||||
201 | if (m->n_entries_set) | |||
202 | m->n_entries -= 1; | |||
203 | ||||
204 | m->n_skip = 0; | |||
205 | ||||
206 | r = request_meta_ensure_tmp(m); | |||
207 | if (r < 0) { | |||
208 | log_error_errno(r, "Failed to create temporary file: %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-remote/journal-gatewayd.c", 208, __func__, "Failed to create temporary file: %m" ) : -abs(_e); }); | |||
209 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
210 | } | |||
211 | ||||
212 | r = show_journal_entry(m->tmp, m->journal, m->mode, 0, OUTPUT_FULL_WIDTH, | |||
213 | NULL((void*)0), NULL((void*)0), NULL((void*)0)); | |||
214 | if (r < 0) { | |||
215 | log_error_errno(r, "Failed to serialize item: %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-remote/journal-gatewayd.c", 215, __func__, "Failed to serialize item: %m" ) : -abs(_e); }); | |||
216 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
217 | } | |||
218 | ||||
219 | sz = ftello(m->tmp); | |||
220 | if (sz == (off_t) -1) { | |||
221 | log_error_errno(errno, "Failed to retrieve file position: %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-remote/journal-gatewayd.c" , 221, __func__, "Failed to retrieve file position: %m") : -abs (_e); }); | |||
222 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
223 | } | |||
224 | ||||
225 | m->size = (uint64_t) sz; | |||
226 | } | |||
227 | ||||
228 | if (m->tmp == NULL((void*)0) && m->follow) | |||
229 | return 0; | |||
230 | ||||
231 | if (fseeko(m->tmp, pos, SEEK_SET0) < 0) { | |||
232 | log_error_errno(errno, "Failed to seek to position: %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-remote/journal-gatewayd.c" , 232, __func__, "Failed to seek to position: %m") : -abs(_e) ; }); | |||
233 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
234 | } | |||
235 | ||||
236 | n = m->size - pos; | |||
237 | if (n < 1) | |||
238 | return 0; | |||
239 | if (n > max) | |||
240 | n = max; | |||
241 | ||||
242 | errno(*__errno_location ()) = 0; | |||
243 | k = fread(buf, 1, n, m->tmp); | |||
244 | if (k != n) { | |||
245 | log_error("Failed to read from file: %s", errno ? strerror(errno) : "Premature EOF")({ 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-remote/journal-gatewayd.c", 245, __func__, "Failed to read from file: %s" , (*__errno_location ()) ? strerror((*__errno_location ())) : "Premature EOF") : -abs(_e); }); | |||
246 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
247 | } | |||
248 | ||||
249 | return (ssize_t) k; | |||
250 | } | |||
251 | ||||
252 | static int request_parse_accept( | |||
253 | RequestMeta *m, | |||
254 | struct MHD_Connection *connection) { | |||
255 | ||||
256 | const char *header; | |||
257 | ||||
258 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal-remote/journal-gatewayd.c" , 258, __PRETTY_FUNCTION__); } while (0); | |||
259 | assert(connection)do { if ((__builtin_expect(!!(!(connection)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("connection"), "../src/journal-remote/journal-gatewayd.c" , 259, __PRETTY_FUNCTION__); } while (0); | |||
260 | ||||
261 | header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Accept"); | |||
262 | if (!header) | |||
263 | return 0; | |||
264 | ||||
265 | if (streq(header, mime_types[OUTPUT_JSON])(strcmp((header),(mime_types[OUTPUT_JSON])) == 0)) | |||
266 | m->mode = OUTPUT_JSON; | |||
267 | else if (streq(header, mime_types[OUTPUT_JSON_SSE])(strcmp((header),(mime_types[OUTPUT_JSON_SSE])) == 0)) | |||
268 | m->mode = OUTPUT_JSON_SSE; | |||
269 | else if (streq(header, mime_types[OUTPUT_EXPORT])(strcmp((header),(mime_types[OUTPUT_EXPORT])) == 0)) | |||
270 | m->mode = OUTPUT_EXPORT; | |||
271 | else | |||
272 | m->mode = OUTPUT_SHORT; | |||
273 | ||||
274 | return 0; | |||
275 | } | |||
276 | ||||
277 | static int request_parse_range( | |||
278 | RequestMeta *m, | |||
279 | struct MHD_Connection *connection) { | |||
280 | ||||
281 | const char *range, *colon, *colon2; | |||
282 | int r; | |||
283 | ||||
284 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal-remote/journal-gatewayd.c" , 284, __PRETTY_FUNCTION__); } while (0); | |||
285 | assert(connection)do { if ((__builtin_expect(!!(!(connection)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("connection"), "../src/journal-remote/journal-gatewayd.c" , 285, __PRETTY_FUNCTION__); } while (0); | |||
286 | ||||
287 | range = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Range"); | |||
288 | if (!range) | |||
289 | return 0; | |||
290 | ||||
291 | if (!startswith(range, "entries=")) | |||
292 | return 0; | |||
293 | ||||
294 | range += 8; | |||
295 | range += strspn(range, WHITESPACE" \t\n\r"); | |||
296 | ||||
297 | colon = strchr(range, ':'); | |||
298 | if (!colon) | |||
299 | m->cursor = strdup(range); | |||
300 | else { | |||
301 | const char *p; | |||
302 | ||||
303 | colon2 = strchr(colon + 1, ':'); | |||
304 | if (colon2) { | |||
305 | _cleanup_free___attribute__((cleanup(freep))) char *t; | |||
306 | ||||
307 | t = strndup(colon + 1, colon2 - colon - 1); | |||
308 | if (!t) | |||
309 | return -ENOMEM12; | |||
310 | ||||
311 | r = safe_atoi64(t, &m->n_skip); | |||
| ||||
312 | if (r < 0) | |||
313 | return r; | |||
314 | } | |||
315 | ||||
316 | p = (colon2 ? colon2 : colon) + 1; | |||
317 | if (*p) { | |||
318 | r = safe_atou64(p, &m->n_entries); | |||
319 | if (r < 0) | |||
320 | return r; | |||
321 | ||||
322 | if (m->n_entries <= 0) | |||
323 | return -EINVAL22; | |||
324 | ||||
325 | m->n_entries_set = true1; | |||
326 | } | |||
327 | ||||
328 | m->cursor = strndup(range, colon - range); | |||
329 | } | |||
330 | ||||
331 | if (!m->cursor) | |||
332 | return -ENOMEM12; | |||
333 | ||||
334 | m->cursor[strcspn(m->cursor, WHITESPACE" \t\n\r")] = 0; | |||
335 | if (isempty(m->cursor)) | |||
336 | m->cursor = mfree(m->cursor); | |||
337 | ||||
338 | return 0; | |||
339 | } | |||
340 | ||||
341 | static mhd_resultenum MHD_Result request_parse_arguments_iterator( | |||
342 | void *cls, | |||
343 | enum MHD_ValueKind kind, | |||
344 | const char *key, | |||
345 | const char *value) { | |||
346 | ||||
347 | RequestMeta *m = cls; | |||
348 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); | |||
349 | int r; | |||
350 | ||||
351 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal-remote/journal-gatewayd.c" , 351, __PRETTY_FUNCTION__); } while (0); | |||
352 | ||||
353 | if (isempty(key)) { | |||
354 | m->argument_parse_error = -EINVAL22; | |||
355 | return MHD_NO; | |||
356 | } | |||
357 | ||||
358 | if (streq(key, "follow")(strcmp((key),("follow")) == 0)) { | |||
359 | if (isempty(value)) { | |||
360 | m->follow = true1; | |||
361 | return MHD_YES; | |||
362 | } | |||
363 | ||||
364 | r = parse_boolean(value); | |||
365 | if (r < 0) { | |||
366 | m->argument_parse_error = r; | |||
367 | return MHD_NO; | |||
368 | } | |||
369 | ||||
370 | m->follow = r; | |||
371 | return MHD_YES; | |||
372 | } | |||
373 | ||||
374 | if (streq(key, "discrete")(strcmp((key),("discrete")) == 0)) { | |||
375 | if (isempty(value)) { | |||
376 | m->discrete = true1; | |||
377 | return MHD_YES; | |||
378 | } | |||
379 | ||||
380 | r = parse_boolean(value); | |||
381 | if (r < 0) { | |||
382 | m->argument_parse_error = r; | |||
383 | return MHD_NO; | |||
384 | } | |||
385 | ||||
386 | m->discrete = r; | |||
387 | return MHD_YES; | |||
388 | } | |||
389 | ||||
390 | if (streq(key, "boot")(strcmp((key),("boot")) == 0)) { | |||
391 | if (isempty(value)) | |||
392 | r = true1; | |||
393 | else { | |||
394 | r = parse_boolean(value); | |||
395 | if (r < 0) { | |||
396 | m->argument_parse_error = r; | |||
397 | return MHD_NO; | |||
398 | } | |||
399 | } | |||
400 | ||||
401 | if (r) { | |||
402 | char match[9 + 32 + 1] = "_BOOT_ID="; | |||
403 | sd_id128_t bid; | |||
404 | ||||
405 | r = sd_id128_get_boot(&bid); | |||
406 | if (r < 0) { | |||
407 | 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-remote/journal-gatewayd.c", 407, __func__, "Failed to get boot ID: %m" ) : -abs(_e); }); | |||
408 | return MHD_NO; | |||
409 | } | |||
410 | ||||
411 | sd_id128_to_string(bid, match + 9); | |||
412 | r = sd_journal_add_match(m->journal, match, sizeof(match)-1); | |||
413 | if (r < 0) { | |||
414 | m->argument_parse_error = r; | |||
415 | return MHD_NO; | |||
416 | } | |||
417 | } | |||
418 | ||||
419 | return MHD_YES; | |||
420 | } | |||
421 | ||||
422 | p = strjoin(key, "=", strempty(value))strjoin_real((key), "=", strempty(value), ((void*)0)); | |||
423 | if (!p) { | |||
424 | m->argument_parse_error = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal-remote/journal-gatewayd.c" , 424, __func__); | |||
425 | return MHD_NO; | |||
426 | } | |||
427 | ||||
428 | r = sd_journal_add_match(m->journal, p, 0); | |||
429 | if (r < 0) { | |||
430 | m->argument_parse_error = r; | |||
431 | return MHD_NO; | |||
432 | } | |||
433 | ||||
434 | return MHD_YES; | |||
435 | } | |||
436 | ||||
437 | static int request_parse_arguments( | |||
438 | RequestMeta *m, | |||
439 | struct MHD_Connection *connection) { | |||
440 | ||||
441 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal-remote/journal-gatewayd.c" , 441, __PRETTY_FUNCTION__); } while (0); | |||
442 | assert(connection)do { if ((__builtin_expect(!!(!(connection)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("connection"), "../src/journal-remote/journal-gatewayd.c" , 442, __PRETTY_FUNCTION__); } while (0); | |||
443 | ||||
444 | m->argument_parse_error = 0; | |||
445 | MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, request_parse_arguments_iterator, m); | |||
446 | ||||
447 | return m->argument_parse_error; | |||
448 | } | |||
449 | ||||
450 | static int request_handler_entries( | |||
451 | struct MHD_Connection *connection, | |||
452 | void *connection_cls) { | |||
453 | ||||
454 | _cleanup_(MHD_destroy_responsep)__attribute__((cleanup(MHD_destroy_responsep))) struct MHD_Response *response = NULL((void*)0); | |||
455 | RequestMeta *m = connection_cls; | |||
456 | int r; | |||
457 | ||||
458 | assert(connection)do { if ((__builtin_expect(!!(!(connection)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("connection"), "../src/journal-remote/journal-gatewayd.c" , 458, __PRETTY_FUNCTION__); } while (0); | |||
459 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal-remote/journal-gatewayd.c" , 459, __PRETTY_FUNCTION__); } while (0); | |||
460 | ||||
461 | r = open_journal(m); | |||
462 | if (r
| |||
463 | return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR500, "Failed to open journal: %m"); | |||
464 | ||||
465 | if (request_parse_accept(m, connection) < 0) | |||
466 | return mhd_respond(connection, MHD_HTTP_BAD_REQUEST400, "Failed to parse Accept header."); | |||
467 | ||||
468 | if (request_parse_range(m, connection) < 0) | |||
469 | return mhd_respond(connection, MHD_HTTP_BAD_REQUEST400, "Failed to parse Range header."); | |||
470 | ||||
471 | if (request_parse_arguments(m, connection) < 0) | |||
472 | return mhd_respond(connection, MHD_HTTP_BAD_REQUEST400, "Failed to parse URL arguments."); | |||
473 | ||||
474 | if (m->discrete) { | |||
475 | if (!m->cursor) | |||
476 | return mhd_respond(connection, MHD_HTTP_BAD_REQUEST400, "Discrete seeks require a cursor specification."); | |||
477 | ||||
478 | m->n_entries = 1; | |||
479 | m->n_entries_set = true1; | |||
480 | } | |||
481 | ||||
482 | if (m->cursor) | |||
483 | r = sd_journal_seek_cursor(m->journal, m->cursor); | |||
484 | else if (m->n_skip >= 0) | |||
485 | r = sd_journal_seek_head(m->journal); | |||
486 | else if (m->n_skip < 0) | |||
487 | r = sd_journal_seek_tail(m->journal); | |||
488 | if (r < 0) | |||
489 | return mhd_respond(connection, MHD_HTTP_BAD_REQUEST400, "Failed to seek in journal."); | |||
490 | ||||
491 | response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN(18446744073709551615UL), 4*1024, request_reader_entries, m, NULL((void*)0)); | |||
492 | if (!response) | |||
493 | return respond_oom(connection)log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal-remote/journal-gatewayd.c" , 493, __func__), mhd_respond_oom(connection); | |||
494 | ||||
495 | MHD_add_response_header(response, "Content-Type", mime_types[m->mode]); | |||
496 | return MHD_queue_response(connection, MHD_HTTP_OK200, response); | |||
497 | } | |||
498 | ||||
499 | static int output_field(FILE *f, OutputMode m, const char *d, size_t l) { | |||
500 | const char *eq; | |||
501 | size_t j; | |||
502 | ||||
503 | eq = memchr(d, '=', l); | |||
504 | if (!eq) | |||
505 | return -EINVAL22; | |||
506 | ||||
507 | j = l - (eq - d + 1); | |||
508 | ||||
509 | if (m == OUTPUT_JSON) { | |||
510 | fprintf(f, "{ \"%.*s\" : ", (int) (eq - d), d); | |||
511 | json_escape(f, eq+1, j, OUTPUT_FULL_WIDTH); | |||
512 | fputs(" }\n", f); | |||
513 | } else { | |||
514 | fwrite(eq+1, 1, j, f); | |||
515 | fputc('\n', f); | |||
516 | } | |||
517 | ||||
518 | return 0; | |||
519 | } | |||
520 | ||||
521 | static ssize_t request_reader_fields( | |||
522 | void *cls, | |||
523 | uint64_t pos, | |||
524 | char *buf, | |||
525 | size_t max) { | |||
526 | ||||
527 | RequestMeta *m = cls; | |||
528 | int r; | |||
529 | size_t n, k; | |||
530 | ||||
531 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal-remote/journal-gatewayd.c" , 531, __PRETTY_FUNCTION__); } while (0); | |||
532 | assert(buf)do { if ((__builtin_expect(!!(!(buf)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("buf"), "../src/journal-remote/journal-gatewayd.c" , 532, __PRETTY_FUNCTION__); } while (0); | |||
533 | assert(max > 0)do { if ((__builtin_expect(!!(!(max > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("max > 0"), "../src/journal-remote/journal-gatewayd.c" , 533, __PRETTY_FUNCTION__); } while (0); | |||
534 | assert(pos >= m->delta)do { if ((__builtin_expect(!!(!(pos >= m->delta)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("pos >= m->delta"), "../src/journal-remote/journal-gatewayd.c" , 534, __PRETTY_FUNCTION__); } while (0); | |||
535 | ||||
536 | pos -= m->delta; | |||
537 | ||||
538 | while (pos >= m->size) { | |||
539 | off_t sz; | |||
540 | const void *d; | |||
541 | size_t l; | |||
542 | ||||
543 | /* End of this field, so let's serialize the next | |||
544 | * one */ | |||
545 | ||||
546 | if (m->n_fields_set && | |||
547 | m->n_fields <= 0) | |||
548 | return MHD_CONTENT_READER_END_OF_STREAM(18446744073709551615UL); | |||
549 | ||||
550 | r = sd_journal_enumerate_unique(m->journal, &d, &l); | |||
551 | if (r < 0) { | |||
552 | log_error_errno(r, "Failed to advance field index: %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-remote/journal-gatewayd.c", 552, __func__, "Failed to advance field index: %m" ) : -abs(_e); }); | |||
553 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
554 | } else if (r == 0) | |||
555 | return MHD_CONTENT_READER_END_OF_STREAM(18446744073709551615UL); | |||
556 | ||||
557 | pos -= m->size; | |||
558 | m->delta += m->size; | |||
559 | ||||
560 | if (m->n_fields_set) | |||
561 | m->n_fields -= 1; | |||
562 | ||||
563 | r = request_meta_ensure_tmp(m); | |||
564 | if (r < 0) { | |||
565 | log_error_errno(r, "Failed to create temporary file: %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-remote/journal-gatewayd.c", 565, __func__, "Failed to create temporary file: %m" ) : -abs(_e); }); | |||
566 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
567 | } | |||
568 | ||||
569 | r = output_field(m->tmp, m->mode, d, l); | |||
570 | if (r < 0) { | |||
571 | log_error_errno(r, "Failed to serialize item: %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-remote/journal-gatewayd.c", 571, __func__, "Failed to serialize item: %m" ) : -abs(_e); }); | |||
572 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
573 | } | |||
574 | ||||
575 | sz = ftello(m->tmp); | |||
576 | if (sz == (off_t) -1) { | |||
577 | log_error_errno(errno, "Failed to retrieve file position: %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-remote/journal-gatewayd.c" , 577, __func__, "Failed to retrieve file position: %m") : -abs (_e); }); | |||
578 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
579 | } | |||
580 | ||||
581 | m->size = (uint64_t) sz; | |||
582 | } | |||
583 | ||||
584 | if (fseeko(m->tmp, pos, SEEK_SET0) < 0) { | |||
585 | log_error_errno(errno, "Failed to seek to position: %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-remote/journal-gatewayd.c" , 585, __func__, "Failed to seek to position: %m") : -abs(_e) ; }); | |||
586 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
587 | } | |||
588 | ||||
589 | n = m->size - pos; | |||
590 | if (n > max) | |||
591 | n = max; | |||
592 | ||||
593 | errno(*__errno_location ()) = 0; | |||
594 | k = fread(buf, 1, n, m->tmp); | |||
595 | if (k != n) { | |||
596 | log_error("Failed to read from file: %s", errno ? strerror(errno) : "Premature EOF")({ 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-remote/journal-gatewayd.c", 596, __func__, "Failed to read from file: %s" , (*__errno_location ()) ? strerror((*__errno_location ())) : "Premature EOF") : -abs(_e); }); | |||
597 | return MHD_CONTENT_READER_END_WITH_ERROR((18446744073709551615UL) - 1); | |||
598 | } | |||
599 | ||||
600 | return (ssize_t) k; | |||
601 | } | |||
602 | ||||
603 | static int request_handler_fields( | |||
604 | struct MHD_Connection *connection, | |||
605 | const char *field, | |||
606 | void *connection_cls) { | |||
607 | ||||
608 | _cleanup_(MHD_destroy_responsep)__attribute__((cleanup(MHD_destroy_responsep))) struct MHD_Response *response = NULL((void*)0); | |||
609 | RequestMeta *m = connection_cls; | |||
610 | int r; | |||
611 | ||||
612 | assert(connection)do { if ((__builtin_expect(!!(!(connection)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("connection"), "../src/journal-remote/journal-gatewayd.c" , 612, __PRETTY_FUNCTION__); } while (0); | |||
613 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal-remote/journal-gatewayd.c" , 613, __PRETTY_FUNCTION__); } while (0); | |||
614 | ||||
615 | r = open_journal(m); | |||
616 | if (r < 0) | |||
617 | return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR500, "Failed to open journal: %m"); | |||
618 | ||||
619 | if (request_parse_accept(m, connection) < 0) | |||
620 | return mhd_respond(connection, MHD_HTTP_BAD_REQUEST400, "Failed to parse Accept header."); | |||
621 | ||||
622 | r = sd_journal_query_unique(m->journal, field); | |||
623 | if (r < 0) | |||
624 | return mhd_respond(connection, MHD_HTTP_BAD_REQUEST400, "Failed to query unique fields."); | |||
625 | ||||
626 | response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN(18446744073709551615UL), 4*1024, request_reader_fields, m, NULL((void*)0)); | |||
627 | if (!response) | |||
628 | return respond_oom(connection)log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal-remote/journal-gatewayd.c" , 628, __func__), mhd_respond_oom(connection); | |||
629 | ||||
630 | MHD_add_response_header(response, "Content-Type", mime_types[m->mode == OUTPUT_JSON ? OUTPUT_JSON : OUTPUT_SHORT]); | |||
631 | return MHD_queue_response(connection, MHD_HTTP_OK200, response); | |||
632 | } | |||
633 | ||||
634 | static int request_handler_redirect( | |||
635 | struct MHD_Connection *connection, | |||
636 | const char *target) { | |||
637 | ||||
638 | char *page; | |||
639 | _cleanup_(MHD_destroy_responsep)__attribute__((cleanup(MHD_destroy_responsep))) struct MHD_Response *response = NULL((void*)0); | |||
640 | ||||
641 | assert(connection)do { if ((__builtin_expect(!!(!(connection)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("connection"), "../src/journal-remote/journal-gatewayd.c" , 641, __PRETTY_FUNCTION__); } while (0); | |||
642 | assert(target)do { if ((__builtin_expect(!!(!(target)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("target"), "../src/journal-remote/journal-gatewayd.c" , 642, __PRETTY_FUNCTION__); } while (0); | |||
643 | ||||
644 | if (asprintf(&page, "<html><body>Please continue to the <a href=\"%s\">journal browser</a>.</body></html>", target) < 0) | |||
645 | return respond_oom(connection)log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal-remote/journal-gatewayd.c" , 645, __func__), mhd_respond_oom(connection); | |||
646 | ||||
647 | response = MHD_create_response_from_buffer(strlen(page), page, MHD_RESPMEM_MUST_FREE); | |||
648 | if (!response) { | |||
649 | free(page); | |||
650 | return respond_oom(connection)log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal-remote/journal-gatewayd.c" , 650, __func__), mhd_respond_oom(connection); | |||
651 | } | |||
652 | ||||
653 | MHD_add_response_header(response, "Content-Type", "text/html"); | |||
654 | MHD_add_response_header(response, "Location", target); | |||
655 | return MHD_queue_response(connection, MHD_HTTP_MOVED_PERMANENTLY301, response); | |||
656 | } | |||
657 | ||||
658 | static int request_handler_file( | |||
659 | struct MHD_Connection *connection, | |||
660 | const char *path, | |||
661 | const char *mime_type) { | |||
662 | ||||
663 | _cleanup_(MHD_destroy_responsep)__attribute__((cleanup(MHD_destroy_responsep))) struct MHD_Response *response = NULL((void*)0); | |||
664 | _cleanup_close___attribute__((cleanup(closep))) int fd = -1; | |||
665 | struct stat st; | |||
666 | ||||
667 | assert(connection)do { if ((__builtin_expect(!!(!(connection)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("connection"), "../src/journal-remote/journal-gatewayd.c" , 667, __PRETTY_FUNCTION__); } while (0); | |||
668 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/journal-remote/journal-gatewayd.c" , 668, __PRETTY_FUNCTION__); } while (0); | |||
669 | assert(mime_type)do { if ((__builtin_expect(!!(!(mime_type)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("mime_type"), "../src/journal-remote/journal-gatewayd.c" , 669, __PRETTY_FUNCTION__); } while (0); | |||
670 | ||||
671 | fd = open(path, O_RDONLY00|O_CLOEXEC02000000); | |||
672 | if (fd < 0) | |||
673 | return mhd_respondf(connection, errno(*__errno_location ()), MHD_HTTP_NOT_FOUND404, "Failed to open file %s: %m", path); | |||
674 | ||||
675 | if (fstat(fd, &st) < 0) | |||
676 | return mhd_respondf(connection, errno(*__errno_location ()), MHD_HTTP_INTERNAL_SERVER_ERROR500, "Failed to stat file: %m"); | |||
677 | ||||
678 | response = MHD_create_response_from_fd_at_offset64(st.st_size, fd, 0); | |||
679 | if (!response) | |||
680 | return respond_oom(connection)log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal-remote/journal-gatewayd.c" , 680, __func__), mhd_respond_oom(connection); | |||
681 | TAKE_FD(fd)({ int _fd_ = (fd); (fd) = -1; _fd_; }); | |||
682 | ||||
683 | MHD_add_response_header(response, "Content-Type", mime_type); | |||
684 | return MHD_queue_response(connection, MHD_HTTP_OK200, response); | |||
685 | } | |||
686 | ||||
687 | static int get_virtualization(char **v) { | |||
688 | _cleanup_(sd_bus_unrefp)__attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus = NULL((void*)0); | |||
689 | char *b = NULL((void*)0); | |||
690 | int r; | |||
691 | ||||
692 | r = sd_bus_default_system(&bus); | |||
693 | if (r < 0) | |||
694 | return r; | |||
695 | ||||
696 | r = sd_bus_get_property_string( | |||
697 | bus, | |||
698 | "org.freedesktop.systemd1", | |||
699 | "/org/freedesktop/systemd1", | |||
700 | "org.freedesktop.systemd1.Manager", | |||
701 | "Virtualization", | |||
702 | NULL((void*)0), | |||
703 | &b); | |||
704 | if (r < 0) | |||
705 | return r; | |||
706 | ||||
707 | if (isempty(b)) { | |||
708 | free(b); | |||
709 | *v = NULL((void*)0); | |||
710 | return 0; | |||
711 | } | |||
712 | ||||
713 | *v = b; | |||
714 | return 1; | |||
715 | } | |||
716 | ||||
717 | static int request_handler_machine( | |||
718 | struct MHD_Connection *connection, | |||
719 | void *connection_cls) { | |||
720 | ||||
721 | _cleanup_(MHD_destroy_responsep)__attribute__((cleanup(MHD_destroy_responsep))) struct MHD_Response *response = NULL((void*)0); | |||
722 | RequestMeta *m = connection_cls; | |||
723 | int r; | |||
724 | _cleanup_free___attribute__((cleanup(freep))) char* hostname = NULL((void*)0), *os_name = NULL((void*)0); | |||
725 | uint64_t cutoff_from = 0, cutoff_to = 0, usage = 0; | |||
726 | sd_id128_t mid, bid; | |||
727 | _cleanup_free___attribute__((cleanup(freep))) char *v = NULL((void*)0), *json = NULL((void*)0); | |||
728 | ||||
729 | assert(connection)do { if ((__builtin_expect(!!(!(connection)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("connection"), "../src/journal-remote/journal-gatewayd.c" , 729, __PRETTY_FUNCTION__); } while (0); | |||
730 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal-remote/journal-gatewayd.c" , 730, __PRETTY_FUNCTION__); } while (0); | |||
731 | ||||
732 | r = open_journal(m); | |||
733 | if (r < 0) | |||
734 | return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR500, "Failed to open journal: %m"); | |||
735 | ||||
736 | r = sd_id128_get_machine(&mid); | |||
737 | if (r < 0) | |||
738 | return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR500, "Failed to determine machine ID: %m"); | |||
739 | ||||
740 | r = sd_id128_get_boot(&bid); | |||
741 | if (r < 0) | |||
742 | return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR500, "Failed to determine boot ID: %m"); | |||
743 | ||||
744 | hostname = gethostname_malloc(); | |||
745 | if (!hostname) | |||
746 | return respond_oom(connection)log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal-remote/journal-gatewayd.c" , 746, __func__), mhd_respond_oom(connection); | |||
747 | ||||
748 | r = sd_journal_get_usage(m->journal, &usage); | |||
749 | if (r < 0) | |||
750 | return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR500, "Failed to determine disk usage: %m"); | |||
751 | ||||
752 | r = sd_journal_get_cutoff_realtime_usec(m->journal, &cutoff_from, &cutoff_to); | |||
753 | if (r < 0) | |||
754 | return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR500, "Failed to determine disk usage: %m"); | |||
755 | ||||
756 | (void) parse_os_release(NULL((void*)0), "PRETTY_NAME", &os_name, NULL((void*)0)); | |||
757 | (void) get_virtualization(&v); | |||
758 | ||||
759 | r = asprintf(&json, | |||
760 | "{ \"machine_id\" : \"" SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" "\"," | |||
761 | "\"boot_id\" : \"" SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" "\"," | |||
762 | "\"hostname\" : \"%s\"," | |||
763 | "\"os_pretty_name\" : \"%s\"," | |||
764 | "\"virtualization\" : \"%s\"," | |||
765 | "\"usage\" : \"%"PRIu64"l" "u""\"," | |||
766 | "\"cutoff_from_realtime\" : \"%"PRIu64"l" "u""\"," | |||
767 | "\"cutoff_to_realtime\" : \"%"PRIu64"l" "u""\" }\n", | |||
768 | SD_ID128_FORMAT_VAL(mid)(mid).bytes[0], (mid).bytes[1], (mid).bytes[2], (mid).bytes[3 ], (mid).bytes[4], (mid).bytes[5], (mid).bytes[6], (mid).bytes [7], (mid).bytes[8], (mid).bytes[9], (mid).bytes[10], (mid).bytes [11], (mid).bytes[12], (mid).bytes[13], (mid).bytes[14], (mid ).bytes[15], | |||
769 | SD_ID128_FORMAT_VAL(bid)(bid).bytes[0], (bid).bytes[1], (bid).bytes[2], (bid).bytes[3 ], (bid).bytes[4], (bid).bytes[5], (bid).bytes[6], (bid).bytes [7], (bid).bytes[8], (bid).bytes[9], (bid).bytes[10], (bid).bytes [11], (bid).bytes[12], (bid).bytes[13], (bid).bytes[14], (bid ).bytes[15], | |||
770 | hostname_cleanup(hostname), | |||
771 | os_name ? os_name : "Linux", | |||
772 | v ? v : "bare", | |||
773 | usage, | |||
774 | cutoff_from, | |||
775 | cutoff_to); | |||
776 | if (r < 0) | |||
777 | return respond_oom(connection)log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal-remote/journal-gatewayd.c" , 777, __func__), mhd_respond_oom(connection); | |||
778 | ||||
779 | response = MHD_create_response_from_buffer(strlen(json), json, MHD_RESPMEM_MUST_FREE); | |||
780 | if (!response) | |||
781 | return respond_oom(connection)log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal-remote/journal-gatewayd.c" , 781, __func__), mhd_respond_oom(connection); | |||
782 | TAKE_PTR(json)({ typeof(json) _ptr_ = (json); (json) = ((void*)0); _ptr_; } ); | |||
783 | ||||
784 | MHD_add_response_header(response, "Content-Type", "application/json"); | |||
785 | return MHD_queue_response(connection, MHD_HTTP_OK200, response); | |||
786 | } | |||
787 | ||||
788 | static mhd_resultenum MHD_Result request_handler( | |||
789 | void *cls, | |||
790 | struct MHD_Connection *connection, | |||
791 | const char *url, | |||
792 | const char *method, | |||
793 | const char *version, | |||
794 | const char *upload_data, | |||
795 | size_t *upload_data_size, | |||
796 | void **connection_cls) { | |||
797 | int r, code; | |||
798 | ||||
799 | assert(connection)do { if ((__builtin_expect(!!(!(connection)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("connection"), "../src/journal-remote/journal-gatewayd.c" , 799, __PRETTY_FUNCTION__); } while (0); | |||
| ||||
800 | assert(connection_cls)do { if ((__builtin_expect(!!(!(connection_cls)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("connection_cls"), "../src/journal-remote/journal-gatewayd.c" , 800, __PRETTY_FUNCTION__); } while (0); | |||
801 | assert(url)do { if ((__builtin_expect(!!(!(url)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("url"), "../src/journal-remote/journal-gatewayd.c" , 801, __PRETTY_FUNCTION__); } while (0); | |||
802 | assert(method)do { if ((__builtin_expect(!!(!(method)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("method"), "../src/journal-remote/journal-gatewayd.c" , 802, __PRETTY_FUNCTION__); } while (0); | |||
803 | ||||
804 | if (!streq(method, "GET")(strcmp((method),("GET")) == 0)) | |||
805 | return mhd_respond(connection, MHD_HTTP_NOT_ACCEPTABLE406, "Unsupported method."); | |||
806 | ||||
807 | if (!*connection_cls) { | |||
808 | if (!request_meta(connection_cls)) | |||
809 | return respond_oom(connection)log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal-remote/journal-gatewayd.c" , 809, __func__), mhd_respond_oom(connection); | |||
810 | return MHD_YES; | |||
811 | } | |||
812 | ||||
813 | if (arg_trust_pem) { | |||
814 | r = check_permissions(connection, &code, NULL((void*)0)); | |||
815 | if (r < 0) | |||
816 | return code; | |||
817 | } | |||
818 | ||||
819 | if (streq(url, "/")(strcmp((url),("/")) == 0)) | |||
820 | return request_handler_redirect(connection, "/browse"); | |||
821 | ||||
822 | if (streq(url, "/entries")(strcmp((url),("/entries")) == 0)) | |||
823 | return request_handler_entries(connection, *connection_cls); | |||
824 | ||||
825 | if (startswith(url, "/fields/")) | |||
826 | return request_handler_fields(connection, url + 8, *connection_cls); | |||
827 | ||||
828 | if (streq(url, "/browse")(strcmp((url),("/browse")) == 0)) | |||
829 | return request_handler_file(connection, DOCUMENT_ROOT"/usr/share/systemd/gatewayd" "/browse.html", "text/html"); | |||
830 | ||||
831 | if (streq(url, "/machine")(strcmp((url),("/machine")) == 0)) | |||
832 | return request_handler_machine(connection, *connection_cls); | |||
833 | ||||
834 | return mhd_respond(connection, MHD_HTTP_NOT_FOUND404, "Not found."); | |||
835 | } | |||
836 | ||||
837 | static void help(void) { | |||
838 | printf("%s [OPTIONS...] ...\n\n" | |||
839 | "HTTP server for journal events.\n\n" | |||
840 | " -h --help Show this help\n" | |||
841 | " --version Show package version\n" | |||
842 | " --cert=CERT.PEM Server certificate in PEM format\n" | |||
843 | " --key=KEY.PEM Server key in PEM format\n" | |||
844 | " --trust=CERT.PEM Certificate authority certificate in PEM format\n" | |||
845 | " -D --directory=PATH Serve journal files in directory\n", | |||
846 | program_invocation_short_name); | |||
847 | } | |||
848 | ||||
849 | static int parse_argv(int argc, char *argv[]) { | |||
850 | enum { | |||
851 | ARG_VERSION = 0x100, | |||
852 | ARG_KEY, | |||
853 | ARG_CERT, | |||
854 | ARG_TRUST, | |||
855 | }; | |||
856 | ||||
857 | int r, c; | |||
858 | ||||
859 | static const struct option options[] = { | |||
860 | { "help", no_argument0, NULL((void*)0), 'h' }, | |||
861 | { "version", no_argument0, NULL((void*)0), ARG_VERSION }, | |||
862 | { "key", required_argument1, NULL((void*)0), ARG_KEY }, | |||
863 | { "cert", required_argument1, NULL((void*)0), ARG_CERT }, | |||
864 | { "trust", required_argument1, NULL((void*)0), ARG_TRUST }, | |||
865 | { "directory", required_argument1, NULL((void*)0), 'D' }, | |||
866 | {} | |||
867 | }; | |||
868 | ||||
869 | assert(argc >= 0)do { if ((__builtin_expect(!!(!(argc >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argc >= 0"), "../src/journal-remote/journal-gatewayd.c" , 869, __PRETTY_FUNCTION__); } while (0); | |||
870 | assert(argv)do { if ((__builtin_expect(!!(!(argv)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argv"), "../src/journal-remote/journal-gatewayd.c" , 870, __PRETTY_FUNCTION__); } while (0); | |||
871 | ||||
872 | while ((c = getopt_long(argc, argv, "hD:", options, NULL((void*)0))) >= 0) | |||
873 | ||||
874 | switch(c) { | |||
875 | ||||
876 | case 'h': | |||
877 | help(); | |||
878 | return 0; | |||
879 | ||||
880 | case ARG_VERSION: | |||
881 | return version(); | |||
882 | ||||
883 | case ARG_KEY: | |||
884 | if (arg_key_pem) { | |||
885 | log_error("Key file specified twice")({ 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-remote/journal-gatewayd.c", 885, __func__, "Key file specified twice" ) : -abs(_e); }); | |||
886 | return -EINVAL22; | |||
887 | } | |||
888 | r = read_full_file(optarg, &arg_key_pem, NULL((void*)0)); | |||
889 | if (r < 0) | |||
890 | return log_error_errno(r, "Failed to read key file: %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-remote/journal-gatewayd.c", 890, __func__, "Failed to read key file: %m" ) : -abs(_e); }); | |||
891 | assert(arg_key_pem)do { if ((__builtin_expect(!!(!(arg_key_pem)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("arg_key_pem"), "../src/journal-remote/journal-gatewayd.c" , 891, __PRETTY_FUNCTION__); } while (0); | |||
892 | break; | |||
893 | ||||
894 | case ARG_CERT: | |||
895 | if (arg_cert_pem) { | |||
896 | log_error("Certificate file specified twice")({ 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-remote/journal-gatewayd.c", 896, __func__, "Certificate file specified twice" ) : -abs(_e); }); | |||
897 | return -EINVAL22; | |||
898 | } | |||
899 | r = read_full_file(optarg, &arg_cert_pem, NULL((void*)0)); | |||
900 | if (r < 0) | |||
901 | return log_error_errno(r, "Failed to read certificate file: %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-remote/journal-gatewayd.c", 901, __func__, "Failed to read certificate file: %m" ) : -abs(_e); }); | |||
902 | assert(arg_cert_pem)do { if ((__builtin_expect(!!(!(arg_cert_pem)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("arg_cert_pem"), "../src/journal-remote/journal-gatewayd.c" , 902, __PRETTY_FUNCTION__); } while (0); | |||
903 | break; | |||
904 | ||||
905 | case ARG_TRUST: | |||
906 | #if HAVE_GNUTLS1 | |||
907 | if (arg_trust_pem) { | |||
908 | log_error("CA certificate file specified twice")({ 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-remote/journal-gatewayd.c", 908, __func__, "CA certificate file specified twice" ) : -abs(_e); }); | |||
909 | return -EINVAL22; | |||
910 | } | |||
911 | r = read_full_file(optarg, &arg_trust_pem, NULL((void*)0)); | |||
912 | if (r < 0) | |||
913 | return log_error_errno(r, "Failed to read CA certificate file: %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-remote/journal-gatewayd.c", 913, __func__, "Failed to read CA certificate file: %m" ) : -abs(_e); }); | |||
914 | assert(arg_trust_pem)do { if ((__builtin_expect(!!(!(arg_trust_pem)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("arg_trust_pem"), "../src/journal-remote/journal-gatewayd.c" , 914, __PRETTY_FUNCTION__); } while (0); | |||
915 | break; | |||
916 | #else | |||
917 | log_error("Option --trust is 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-remote/journal-gatewayd.c", 917, __func__, "Option --trust is not available." ) : -abs(_e); }); | |||
918 | return -EINVAL22; | |||
919 | #endif | |||
920 | case 'D': | |||
921 | arg_directory = optarg; | |||
922 | break; | |||
923 | ||||
924 | case '?': | |||
925 | return -EINVAL22; | |||
926 | ||||
927 | default: | |||
928 | assert_not_reached("Unhandled option")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unhandled option"), "../src/journal-remote/journal-gatewayd.c" , 928, __PRETTY_FUNCTION__); } while (0); | |||
929 | } | |||
930 | ||||
931 | if (optind < argc) { | |||
932 | log_error("This program does not take arguments.")({ 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-remote/journal-gatewayd.c", 932, __func__, "This program does not take arguments." ) : -abs(_e); }); | |||
933 | return -EINVAL22; | |||
934 | } | |||
935 | ||||
936 | if (!!arg_key_pem != !!arg_cert_pem) { | |||
937 | log_error("Certificate and key files must be specified together")({ 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-remote/journal-gatewayd.c", 937, __func__, "Certificate and key files must be specified together" ) : -abs(_e); }); | |||
938 | return -EINVAL22; | |||
939 | } | |||
940 | ||||
941 | if (arg_trust_pem && !arg_key_pem) { | |||
942 | log_error("CA certificate can only be used with certificate file")({ 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-remote/journal-gatewayd.c", 942, __func__, "CA certificate can only be used with certificate file" ) : -abs(_e); }); | |||
943 | return -EINVAL22; | |||
944 | } | |||
945 | ||||
946 | return 1; | |||
947 | } | |||
948 | ||||
949 | int main(int argc, char *argv[]) { | |||
950 | struct MHD_Daemon *d = NULL((void*)0); | |||
951 | int r, n; | |||
952 | ||||
953 | log_set_target(LOG_TARGET_AUTO); | |||
954 | log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD); | |||
955 | log_open(); | |||
956 | ||||
957 | r = parse_argv(argc, argv); | |||
958 | if (r < 0) | |||
959 | return EXIT_FAILURE1; | |||
960 | if (r == 0) | |||
961 | return EXIT_SUCCESS0; | |||
962 | ||||
963 | sigbus_install(); | |||
964 | ||||
965 | r = setup_gnutls_logger(NULL((void*)0)); | |||
966 | if (r < 0) | |||
967 | return EXIT_FAILURE1; | |||
968 | ||||
969 | n = sd_listen_fds(1); | |||
970 | if (n < 0) { | |||
971 | log_error_errno(n, "Failed to determine passed sockets: %m")({ int _level = ((3)), _e = ((n)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal-remote/journal-gatewayd.c", 971, __func__, "Failed to determine passed sockets: %m" ) : -abs(_e); }); | |||
972 | goto finish; | |||
973 | } else if (n > 1) { | |||
974 | log_error("Can't listen on more than one socket.")({ 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-remote/journal-gatewayd.c", 974, __func__, "Can't listen on more than one socket." ) : -abs(_e); }); | |||
975 | goto finish; | |||
976 | } else { | |||
977 | struct MHD_OptionItem opts[] = { | |||
978 | { MHD_OPTION_NOTIFY_COMPLETED, | |||
979 | (intptr_t) request_meta_free, NULL((void*)0) }, | |||
980 | { MHD_OPTION_EXTERNAL_LOGGER, | |||
981 | (intptr_t) microhttpd_logger, NULL((void*)0) }, | |||
982 | { MHD_OPTION_END, 0, NULL((void*)0) }, | |||
983 | { MHD_OPTION_END, 0, NULL((void*)0) }, | |||
984 | { MHD_OPTION_END, 0, NULL((void*)0) }, | |||
985 | { MHD_OPTION_END, 0, NULL((void*)0) }, | |||
986 | { MHD_OPTION_END, 0, NULL((void*)0) }}; | |||
987 | int opts_pos = 2; | |||
988 | ||||
989 | /* We force MHD_USE_ITC here, in order to make sure | |||
990 | * libmicrohttpd doesn't use shutdown() on our listening | |||
991 | * socket, which would break socket re-activation. See | |||
992 | * | |||
993 | * https://lists.gnu.org/archive/html/libmicrohttpd/2015-09/msg00014.html | |||
994 | * https://github.com/systemd/systemd/pull/1286 | |||
995 | */ | |||
996 | ||||
997 | int flags = | |||
998 | MHD_USE_DEBUG | | |||
999 | MHD_USE_DUAL_STACK | | |||
1000 | MHD_USE_ITCMHD_USE_PIPE_FOR_SHUTDOWN | | |||
1001 | MHD_USE_POLL_INTERNAL_THREADMHD_USE_POLL_INTERNALLY | | |||
1002 | MHD_USE_THREAD_PER_CONNECTION; | |||
1003 | ||||
1004 | if (n > 0) | |||
1005 | opts[opts_pos++] = (struct MHD_OptionItem) | |||
1006 | {MHD_OPTION_LISTEN_SOCKET, SD_LISTEN_FDS_START3}; | |||
1007 | if (arg_key_pem) { | |||
1008 | assert(arg_cert_pem)do { if ((__builtin_expect(!!(!(arg_cert_pem)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("arg_cert_pem"), "../src/journal-remote/journal-gatewayd.c" , 1008, __PRETTY_FUNCTION__); } while (0); | |||
1009 | opts[opts_pos++] = (struct MHD_OptionItem) | |||
1010 | {MHD_OPTION_HTTPS_MEM_KEY, 0, arg_key_pem}; | |||
1011 | opts[opts_pos++] = (struct MHD_OptionItem) | |||
1012 | {MHD_OPTION_HTTPS_MEM_CERT, 0, arg_cert_pem}; | |||
1013 | flags |= MHD_USE_TLSMHD_USE_SSL; | |||
1014 | } | |||
1015 | if (arg_trust_pem) { | |||
1016 | assert(flags & MHD_USE_TLS)do { if ((__builtin_expect(!!(!(flags & MHD_USE_SSL)),0)) ) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("flags & MHD_USE_TLS" ), "../src/journal-remote/journal-gatewayd.c", 1016, __PRETTY_FUNCTION__ ); } while (0); | |||
1017 | opts[opts_pos++] = (struct MHD_OptionItem) | |||
1018 | {MHD_OPTION_HTTPS_MEM_TRUST, 0, arg_trust_pem}; | |||
1019 | } | |||
1020 | ||||
1021 | d = MHD_start_daemon(flags, 19531, | |||
1022 | NULL((void*)0), NULL((void*)0), | |||
1023 | request_handler, NULL((void*)0), | |||
1024 | MHD_OPTION_ARRAY, opts, | |||
1025 | MHD_OPTION_END); | |||
1026 | } | |||
1027 | ||||
1028 | if (!d) { | |||
1029 | log_error("Failed to start daemon!")({ 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-remote/journal-gatewayd.c", 1029, __func__, "Failed to start daemon!") : -abs(_e); }); | |||
1030 | goto finish; | |||
1031 | } | |||
1032 | ||||
1033 | pause(); | |||
1034 | ||||
1035 | r = EXIT_SUCCESS0; | |||
1036 | ||||
1037 | finish: | |||
1038 | if (d) | |||
1039 | MHD_stop_daemon(d); | |||
1040 | ||||
1041 | return r; | |||
1042 | } |