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