]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal-remote/journal-remote.c
journal: Introduce journald-file.c for journal file write related logic
[thirdparty/systemd.git] / src / journal-remote / journal-remote.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
fdfccdbc
ZJS
2
3#include <errno.h>
4#include <fcntl.h>
fdfccdbc 5#include <stdlib.h>
fdfccdbc 6#include <sys/prctl.h>
5e38eb93 7#include <stdint.h>
3f6fd1ba 8
fdfccdbc 9#include "sd-daemon.h"
3f6fd1ba 10
a4817536 11#include "af-list.h"
b5efdb8a 12#include "alloc-util.h"
a0f29c76 13#include "def.h"
4ff9bc2e 14#include "errno-util.h"
4f5dd394 15#include "escape.h"
3ffd4af2 16#include "fd-util.h"
035b0f8f 17#include "journald-file.h"
4f5dd394 18#include "journal-remote-write.h"
3ffd4af2 19#include "journal-remote.h"
fdfccdbc 20#include "journald-native.h"
fdfccdbc 21#include "macro.h"
6bedfcbb 22#include "parse-util.h"
dccca82b 23#include "process-util.h"
3f6fd1ba 24#include "socket-util.h"
15a5e950 25#include "stdio-util.h"
07630cea 26#include "string-util.h"
fdfccdbc 27#include "strv.h"
fdfccdbc 28
8201af08 29#define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
fdfccdbc 30
9ff48d09 31#define filename_escape(s) xescape((s), "/ ")
8201af08 32
c064d8db
ZJS
33static int open_output(RemoteServer *s, Writer *w, const char* host) {
34 _cleanup_free_ char *_filename = NULL;
35 const char *filename;
fdfccdbc
ZJS
36 int r;
37
c064d8db 38 switch (s->split_mode) {
8201af08 39 case JOURNAL_WRITE_SPLIT_NONE:
c064d8db 40 filename = s->output;
8201af08 41 break;
fdfccdbc 42
8201af08 43 case JOURNAL_WRITE_SPLIT_HOST: {
c2b2df60 44 _cleanup_free_ char *name = NULL;
fdfccdbc 45
8201af08 46 assert(host);
fdfccdbc 47
8201af08
ZJS
48 name = filename_escape(host);
49 if (!name)
50 return log_oom();
51
c064d8db 52 r = asprintf(&_filename, "%s/remote-%s.journal", s->output, name);
fdfccdbc
ZJS
53 if (r < 0)
54 return log_oom();
8201af08 55
c064d8db 56 filename = _filename;
8201af08
ZJS
57 break;
58 }
59
60 default:
04499a70 61 assert_not_reached();
fdfccdbc
ZJS
62 }
63
035b0f8f
DDM
64 r = journald_file_open_reliably(filename,
65 O_RDWR|O_CREAT, 0640,
66 s->compress, UINT64_MAX, s->seal,
67 &w->metrics,
68 w->mmap, NULL,
69 NULL, &w->journal);
fdfccdbc 70 if (r < 0)
c064d8db
ZJS
71 return log_error_errno(r, "Failed to open output journal %s: %m", filename);
72
035b0f8f 73 log_debug("Opened output file %s", w->journal->file->path);
c064d8db 74 return 0;
fdfccdbc
ZJS
75}
76
cc64d017
ZJS
77/**********************************************************************
78 **********************************************************************
79 **********************************************************************/
80
9ff48d09 81static int init_writer_hashmap(RemoteServer *s) {
c064d8db 82 static const struct hash_ops* const hash_ops[] = {
d5099efc
MS
83 [JOURNAL_WRITE_SPLIT_NONE] = NULL,
84 [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
9ff48d09
ZJS
85 };
86
c064d8db
ZJS
87 assert(s);
88 assert(s->split_mode >= 0 && s->split_mode < (int) ELEMENTSOF(hash_ops));
cc64d017 89
c064d8db 90 s->writers = hashmap_new(hash_ops[s->split_mode]);
9ff48d09
ZJS
91 if (!s->writers)
92 return log_oom();
93
94 return 0;
95}
96
c064d8db 97int journal_remote_get_writer(RemoteServer *s, const char *host, Writer **writer) {
8e766630 98 _cleanup_(writer_unrefp) Writer *w = NULL;
9ff48d09 99 const void *key;
9ff48d09
ZJS
100 int r;
101
c064d8db 102 switch(s->split_mode) {
9ff48d09
ZJS
103 case JOURNAL_WRITE_SPLIT_NONE:
104 key = "one and only";
105 break;
106
107 case JOURNAL_WRITE_SPLIT_HOST:
108 assert(host);
109 key = host;
110 break;
111
112 default:
04499a70 113 assert_not_reached();
9ff48d09
ZJS
114 }
115
116 w = hashmap_get(s->writers, key);
117 if (w)
118 writer_ref(w);
119 else {
120 w = writer_new(s);
121 if (!w)
122 return log_oom();
123
c064d8db 124 if (s->split_mode == JOURNAL_WRITE_SPLIT_HOST) {
9ff48d09
ZJS
125 w->hashmap_key = strdup(key);
126 if (!w->hashmap_key)
127 return log_oom();
128 }
cc64d017 129
c064d8db 130 r = open_output(s, w, host);
9ff48d09
ZJS
131 if (r < 0)
132 return r;
fdfccdbc 133
9ff48d09
ZJS
134 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
135 if (r < 0)
136 return r;
137 }
fdfccdbc 138
1cc6c93a
YW
139 *writer = TAKE_PTR(w);
140
9ff48d09
ZJS
141 return 0;
142}
cc64d017 143
9ff48d09
ZJS
144/**********************************************************************
145 **********************************************************************
146 **********************************************************************/
fdfccdbc 147
cc64d017 148/* This should go away as soon as µhttpd allows state to be passed around. */
c064d8db 149RemoteServer *journal_remote_server_global;
cc64d017 150
fdfccdbc
ZJS
151static int dispatch_raw_source_event(sd_event_source *event,
152 int fd,
153 uint32_t revents,
154 void *userdata);
043945b9
ZJS
155static int dispatch_raw_source_until_block(sd_event_source *event,
156 void *userdata);
70f1b2dd
ZJS
157static int dispatch_blocking_source_event(sd_event_source *event,
158 void *userdata);
fdfccdbc
ZJS
159static int dispatch_raw_connection_event(sd_event_source *event,
160 int fd,
161 uint32_t revents,
162 void *userdata);
163
9ff48d09
ZJS
164static int get_source_for_fd(RemoteServer *s,
165 int fd, char *name, RemoteSource **source) {
166 Writer *writer;
167 int r;
168
1f8af042
ZJS
169 /* This takes ownership of name, but only on success. */
170
fdfccdbc
ZJS
171 assert(fd >= 0);
172 assert(source);
173
319a4f4b 174 if (!GREEDY_REALLOC0(s->sources, fd + 1))
fdfccdbc
ZJS
175 return log_oom();
176
c064d8db 177 r = journal_remote_get_writer(s, name, &writer);
eb56eb9b
MS
178 if (r < 0)
179 return log_warning_errno(r, "Failed to get writer for source %s: %m",
180 name);
9ff48d09 181
4e361acc 182 if (!s->sources[fd]) {
9ff48d09
ZJS
183 s->sources[fd] = source_new(fd, false, name, writer);
184 if (!s->sources[fd]) {
185 writer_unref(writer);
fdfccdbc 186 return log_oom();
9ff48d09
ZJS
187 }
188
fdfccdbc
ZJS
189 s->active++;
190 }
191
192 *source = s->sources[fd];
193 return 0;
194}
195
196static int remove_source(RemoteServer *s, int fd) {
197 RemoteSource *source;
198
199 assert(s);
319a4f4b 200 assert(fd >= 0 && fd < (ssize_t) MALLOC_ELEMENTSOF(s->sources));
fdfccdbc
ZJS
201
202 source = s->sources[fd];
203 if (source) {
8201af08 204 /* this closes fd too */
fdfccdbc
ZJS
205 source_free(source);
206 s->sources[fd] = NULL;
207 s->active--;
208 }
209
fdfccdbc
ZJS
210 return 0;
211}
212
c064d8db 213int journal_remote_add_source(RemoteServer *s, int fd, char* name, bool own_name) {
a7f7d1bd 214 RemoteSource *source = NULL;
fdfccdbc
ZJS
215 int r;
216
1f8af042
ZJS
217 /* This takes ownership of name, even on failure, if own_name is true. */
218
fdfccdbc
ZJS
219 assert(s);
220 assert(fd >= 0);
9ff48d09 221 assert(name);
fdfccdbc 222
9ff48d09
ZJS
223 if (!own_name) {
224 name = strdup(name);
225 if (!name)
226 return log_oom();
227 }
fdfccdbc 228
9ff48d09 229 r = get_source_for_fd(s, fd, name, &source);
fdfccdbc 230 if (r < 0) {
c33b3297
MS
231 log_error_errno(r, "Failed to create source for fd:%d (%s): %m",
232 fd, name);
1f8af042 233 free(name);
fdfccdbc
ZJS
234 return r;
235 }
8201af08 236
fdfccdbc 237 r = sd_event_add_io(s->events, &source->event,
8201af08 238 fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
043945b9
ZJS
239 dispatch_raw_source_event, source);
240 if (r == 0) {
241 /* Add additional source for buffer processing. It will be
242 * enabled later. */
243 r = sd_event_add_defer(s->events, &source->buffer_event,
244 dispatch_raw_source_until_block, source);
245 if (r == 0)
c3c50474 246 r = sd_event_source_set_enabled(source->buffer_event, SD_EVENT_OFF);
043945b9 247 } else if (r == -EPERM) {
70f1b2dd
ZJS
248 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
249 r = sd_event_add_defer(s->events, &source->event,
250 dispatch_blocking_source_event, source);
251 if (r == 0)
c3c50474 252 r = sd_event_source_set_enabled(source->event, SD_EVENT_ON);
70f1b2dd 253 }
fdfccdbc 254 if (r < 0) {
c33b3297
MS
255 log_error_errno(r, "Failed to register event source for fd:%d: %m",
256 fd);
fdfccdbc
ZJS
257 goto error;
258 }
259
356779df 260 r = sd_event_source_set_description(source->event, name);
43300d9d 261 if (r < 0) {
da927ba9 262 log_error_errno(r, "Failed to set source name for fd:%d: %m", fd);
43300d9d
ZJS
263 goto error;
264 }
265
fdfccdbc
ZJS
266 return 1; /* work to do */
267
268 error:
269 remove_source(s, fd);
270 return r;
271}
272
c064d8db 273int journal_remote_add_raw_socket(RemoteServer *s, int fd) {
8a8d55f2 274 int r;
d7ac0952 275 _unused_ _cleanup_close_ int fd_ = fd;
fbd0b64f 276 char name[STRLEN("raw-socket-") + DECIMAL_STR_MAX(int) + 1];
43300d9d
ZJS
277
278 assert(fd >= 0);
fdfccdbc 279
8201af08
ZJS
280 r = sd_event_add_io(s->events, &s->listen_event,
281 fd, EPOLLIN,
fdfccdbc 282 dispatch_raw_connection_event, s);
43300d9d 283 if (r < 0)
fdfccdbc 284 return r;
fdfccdbc 285
5ffa8c81 286 xsprintf(name, "raw-socket-%d", fd);
43300d9d 287
356779df 288 r = sd_event_source_set_description(s->listen_event, name);
43300d9d
ZJS
289 if (r < 0)
290 return r;
291
292 fd_ = -1;
313cefa1 293 s->active++;
fdfccdbc
ZJS
294 return 0;
295}
296
8201af08
ZJS
297/**********************************************************************
298 **********************************************************************
299 **********************************************************************/
300
c064d8db
ZJS
301int journal_remote_server_init(
302 RemoteServer *s,
303 const char *output,
304 JournalWriteSplitMode split_mode,
305 bool compress,
306 bool seal) {
cc64d017 307
fdfccdbc
ZJS
308 int r;
309
310 assert(s);
311
c064d8db
ZJS
312 assert(journal_remote_server_global == NULL);
313 journal_remote_server_global = s;
fdfccdbc 314
c064d8db
ZJS
315 s->split_mode = split_mode;
316 s->compress = compress;
317 s->seal = seal;
43300d9d 318
c064d8db
ZJS
319 if (output)
320 s->output = output;
321 else if (split_mode == JOURNAL_WRITE_SPLIT_NONE)
322 s->output = REMOTE_JOURNAL_PATH "/remote.journal";
323 else if (split_mode == JOURNAL_WRITE_SPLIT_HOST)
324 s->output = REMOTE_JOURNAL_PATH;
42b6bf75 325 else
04499a70 326 assert_not_reached();
ad95fd1d 327
b1604b34 328 r = sd_event_default(&s->events);
23bbb0de
MS
329 if (r < 0)
330 return log_error_errno(r, "Failed to allocate event loop: %m");
fdfccdbc 331
22259a00
JL
332 r = init_writer_hashmap(s);
333 if (r < 0)
334 return r;
335
8201af08 336 return 0;
fdfccdbc
ZJS
337}
338
63e2ebcd 339#if HAVE_MICROHTTPD
1599f593
ZJS
340static void MHDDaemonWrapper_free(MHDDaemonWrapper *d) {
341 MHD_stop_daemon(d->daemon);
342 sd_event_source_unref(d->io_event);
343 sd_event_source_unref(d->timer_event);
344 free(d);
345}
63e2ebcd 346#endif
1599f593 347
94952201 348void journal_remote_server_destroy(RemoteServer *s) {
ca2d3784 349 size_t i;
cc64d017 350
63e2ebcd 351#if HAVE_MICROHTTPD
1599f593 352 hashmap_free_with_destructor(s->daemons, MHDDaemonWrapper_free);
63e2ebcd 353#endif
cc64d017 354
319a4f4b 355 for (i = 0; i < MALLOC_ELEMENTSOF(s->sources); i++)
fdfccdbc 356 remove_source(s, i);
fdfccdbc
ZJS
357 free(s->sources);
358
9ff48d09
ZJS
359 writer_unref(s->_single_writer);
360 hashmap_free(s->writers);
361
fdfccdbc
ZJS
362 sd_event_source_unref(s->sigterm_event);
363 sd_event_source_unref(s->sigint_event);
364 sd_event_source_unref(s->listen_event);
365 sd_event_unref(s->events);
366
c064d8db
ZJS
367 if (s == journal_remote_server_global)
368 journal_remote_server_global = NULL;
369
fdfccdbc 370 /* fds that we're listening on remain open... */
fdfccdbc
ZJS
371}
372
373/**********************************************************************
374 **********************************************************************
375 **********************************************************************/
376
864876ec
ZJS
377int journal_remote_handle_raw_source(
378 sd_event_source *event,
379 int fd,
380 uint32_t revents,
381 RemoteServer *s) {
fdfccdbc 382
fdfccdbc
ZJS
383 RemoteSource *source;
384 int r;
385
043945b9
ZJS
386 /* Returns 1 if there might be more data pending,
387 * 0 if data is currently exhausted, negative on error.
388 */
389
319a4f4b 390 assert(fd >= 0 && fd < (ssize_t) MALLOC_ELEMENTSOF(s->sources));
fdfccdbc 391 source = s->sources[fd];
b18453ed 392 assert(source->importer.fd == fd);
fdfccdbc 393
c064d8db 394 r = process_source(source, s->compress, s->seal);
b18453ed 395 if (journal_importer_eof(&source->importer)) {
4a0a6ac0
ZJS
396 size_t remaining;
397
b18453ed
ZJS
398 log_debug("EOF reached with source %s (fd=%d)",
399 source->importer.name, source->importer.fd);
4a0a6ac0 400
b18453ed 401 remaining = journal_importer_bytes_remaining(&source->importer);
4a0a6ac0 402 if (remaining > 0)
0e72da6f 403 log_notice("Premature EOF. %zu bytes lost.", remaining);
b18453ed 404 remove_source(s, source->importer.fd);
0e72da6f 405 log_debug("%zu active sources remaining", s->active);
8201af08 406 return 0;
fdfccdbc 407 } else if (r == -E2BIG) {
ef4d6abe
ZJS
408 log_notice("Entry with too many fields, skipped");
409 return 1;
410 } else if (r == -ENOBUFS) {
d4e98880 411 log_notice("Entry too big, skipped");
8201af08 412 return 1;
ff55c3c7 413 } else if (r == -EAGAIN) {
8201af08
ZJS
414 return 0;
415 } else if (r < 0) {
0e72da6f 416 log_debug_errno(r, "Closing connection: %m");
c064d8db 417 remove_source(s, fd);
8201af08
ZJS
418 return 0;
419 } else
420 return 1;
fdfccdbc
ZJS
421}
422
043945b9
ZJS
423static int dispatch_raw_source_until_block(sd_event_source *event,
424 void *userdata) {
425 RemoteSource *source = userdata;
426 int r;
427
428 /* Make sure event stays around even if source is destroyed */
429 sd_event_source_ref(event);
430
864876ec 431 r = journal_remote_handle_raw_source(event, source->importer.fd, EPOLLIN, journal_remote_server_global);
25bb459e
LB
432 if (r != 1) {
433 int k;
434
043945b9 435 /* No more data for now */
25bb459e
LB
436 k = sd_event_source_set_enabled(event, SD_EVENT_OFF);
437 if (k < 0)
438 r = k;
439 }
043945b9
ZJS
440
441 sd_event_source_unref(event);
442
443 return r;
444}
445
446static int dispatch_raw_source_event(sd_event_source *event,
447 int fd,
448 uint32_t revents,
449 void *userdata) {
450 RemoteSource *source = userdata;
451 int r;
452
453 assert(source->event);
454 assert(source->buffer_event);
455
864876ec 456 r = journal_remote_handle_raw_source(event, fd, EPOLLIN, journal_remote_server_global);
25bb459e
LB
457 if (r == 1) {
458 int k;
459
043945b9
ZJS
460 /* Might have more data. We need to rerun the handler
461 * until we are sure the buffer is exhausted. */
25bb459e
LB
462 k = sd_event_source_set_enabled(source->buffer_event, SD_EVENT_ON);
463 if (k < 0)
464 r = k;
465 }
043945b9
ZJS
466
467 return r;
468}
469
70f1b2dd
ZJS
470static int dispatch_blocking_source_event(sd_event_source *event,
471 void *userdata) {
472 RemoteSource *source = userdata;
473
864876ec 474 return journal_remote_handle_raw_source(event, source->importer.fd, EPOLLIN, journal_remote_server_global);
70f1b2dd
ZJS
475}
476
4ff9bc2e
LP
477static int accept_connection(
478 const char* type,
479 int fd,
480 SocketAddress *addr,
481 char **hostname) {
482
483 _cleanup_close_ int fd2 = -1;
484 int r;
fdfccdbc 485
cc64d017
ZJS
486 log_debug("Accepting new %s connection on fd:%d", type, fd);
487 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
4ff9bc2e
LP
488 if (fd2 < 0) {
489 if (ERRNO_IS_ACCEPT_AGAIN(errno))
490 return -EAGAIN;
491
4a62c710 492 return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
4ff9bc2e 493 }
fdfccdbc 494
cc64d017 495 switch(socket_address_family(addr)) {
fdfccdbc
ZJS
496 case AF_INET:
497 case AF_INET6: {
8201af08
ZJS
498 _cleanup_free_ char *a = NULL;
499 char *b;
fdfccdbc 500
cc64d017 501 r = socket_address_print(addr, &a);
4ff9bc2e
LP
502 if (r < 0)
503 return log_error_errno(r, "socket_address_print(): %m");
fdfccdbc 504
8201af08 505 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
4ff9bc2e
LP
506 if (r < 0)
507 return log_error_errno(r, "Resolving hostname failed: %m");
8201af08 508
0e72da6f
ZJS
509 log_debug("Accepted %s %s connection from %s",
510 type,
a4817536 511 af_to_ipv4_ipv6(socket_address_family(addr)),
0e72da6f 512 a);
cc64d017 513
8201af08 514 *hostname = b;
4ff9bc2e
LP
515 return TAKE_FD(fd2);
516 }
8201af08 517
fdfccdbc 518 default:
4ff9bc2e
LP
519 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
520 "Rejected %s connection with unsupported family %d",
521 type, socket_address_family(addr));
fdfccdbc 522 }
cc64d017 523}
fdfccdbc 524
4ff9bc2e
LP
525static int dispatch_raw_connection_event(
526 sd_event_source *event,
527 int fd,
528 uint32_t revents,
529 void *userdata) {
530
cc64d017 531 RemoteServer *s = userdata;
1f8af042 532 int fd2;
cc64d017
ZJS
533 SocketAddress addr = {
534 .size = sizeof(union sockaddr_union),
535 .type = SOCK_STREAM,
536 };
a7f7d1bd 537 char *hostname = NULL;
fdfccdbc 538
8201af08 539 fd2 = accept_connection("raw", fd, &addr, &hostname);
4ff9bc2e
LP
540 if (fd2 == -EAGAIN)
541 return 0;
cc64d017
ZJS
542 if (fd2 < 0)
543 return fd2;
fdfccdbc 544
c064d8db 545 return journal_remote_add_source(s, fd2, hostname, true);
fdfccdbc 546}