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