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