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