chiark / gitweb /
Remove unnecessary casts in printfs
[elogind.git] / src / journal / journal-remote.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2012 Zbigniew JÄ™drzejewski-Szmek
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/prctl.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <getopt.h>
34
35 #include "sd-daemon.h"
36 #include "sd-event.h"
37 #include "journal-file.h"
38 #include "journald-native.h"
39 #include "socket-util.h"
40 #include "mkdir.h"
41 #include "build.h"
42 #include "macro.h"
43 #include "strv.h"
44 #include "fileio.h"
45 #include "microhttpd-util.h"
46
47 #ifdef HAVE_GNUTLS
48 #include <gnutls/gnutls.h>
49 #endif
50
51 #include "journal-remote-parse.h"
52 #include "journal-remote-write.h"
53
54 #define REMOTE_JOURNAL_PATH "/var/log/journal/" SD_ID128_FORMAT_STR "/remote-%s.journal"
55
56 static char* arg_output = NULL;
57 static char* arg_url = NULL;
58 static char* arg_getter = NULL;
59 static char* arg_listen_raw = NULL;
60 static char* arg_listen_http = NULL;
61 static char* arg_listen_https = NULL;
62 static char** arg_files = NULL;
63 static int arg_compress = true;
64 static int arg_seal = false;
65 static int http_socket = -1, https_socket = -1;
66
67 static char *key_pem = NULL;
68 static char *cert_pem = NULL;
69 static char *trust_pem = NULL;
70
71 /**********************************************************************
72  **********************************************************************
73  **********************************************************************/
74
75 static int spawn_child(const char* child, char** argv) {
76         int fd[2];
77         pid_t parent_pid, child_pid;
78         int r;
79
80         if (pipe(fd) < 0) {
81                 log_error("Failed to create pager pipe: %m");
82                 return -errno;
83         }
84
85         parent_pid = getpid();
86
87         child_pid = fork();
88         if (child_pid < 0) {
89                 r = -errno;
90                 log_error("Failed to fork: %m");
91                 safe_close_pair(fd);
92                 return r;
93         }
94
95         /* In the child */
96         if (child_pid == 0) {
97                 r = dup2(fd[1], STDOUT_FILENO);
98                 if (r < 0) {
99                         log_error("Failed to dup pipe to stdout: %m");
100                         _exit(EXIT_FAILURE);
101                 }
102
103                 safe_close_pair(fd);
104
105                 /* Make sure the child goes away when the parent dies */
106                 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
107                         _exit(EXIT_FAILURE);
108
109                 /* Check whether our parent died before we were able
110                  * to set the death signal */
111                 if (getppid() != parent_pid)
112                         _exit(EXIT_SUCCESS);
113
114                 execvp(child, argv);
115                 log_error("Failed to exec child %s: %m", child);
116                 _exit(EXIT_FAILURE);
117         }
118
119         r = close(fd[1]);
120         if (r < 0)
121                 log_warning("Failed to close write end of pipe: %m");
122
123         return fd[0];
124 }
125
126 static int spawn_curl(char* url) {
127         char **argv = STRV_MAKE("curl",
128                                 "-HAccept: application/vnd.fdo.journal",
129                                 "--silent",
130                                 "--show-error",
131                                 url);
132         int r;
133
134         r = spawn_child("curl", argv);
135         if (r < 0)
136                 log_error("Failed to spawn curl: %m");
137         return r;
138 }
139
140 static int spawn_getter(char *getter, char *url) {
141         int r;
142         char _cleanup_strv_free_ **words = NULL;
143
144         assert(getter);
145         words = strv_split_quoted(getter);
146         if (!words)
147                 return log_oom();
148
149         r = spawn_child(words[0], words);
150         if (r < 0)
151                 log_error("Failed to spawn getter %s: %m", getter);
152
153         return r;
154 }
155
156 static int open_output(Writer *s, const char* url) {
157         char _cleanup_free_ *name, *output = NULL;
158         char *c;
159         int r;
160
161         assert(url);
162         name = strdup(url);
163         if (!name)
164                 return log_oom();
165
166         for(c = name; *c; c++) {
167                 if (*c == '/' || *c == ':' || *c == ' ')
168                         *c = '~';
169                 else if (*c == '?') {
170                         *c = '\0';
171                         break;
172                 }
173         }
174
175         if (!arg_output) {
176                 sd_id128_t machine;
177                 r = sd_id128_get_machine(&machine);
178                 if (r < 0) {
179                         log_error("failed to determine machine ID128: %s", strerror(-r));
180                         return r;
181                 }
182
183                 r = asprintf(&output, REMOTE_JOURNAL_PATH,
184                              SD_ID128_FORMAT_VAL(machine), name);
185                 if (r < 0)
186                         return log_oom();
187         } else {
188                 r = is_dir(arg_output);
189                 if (r > 0) {
190                         r = asprintf(&output,
191                                      "%s/remote-%s.journal", arg_output, name);
192                         if (r < 0)
193                                 return log_oom();
194                 } else {
195                         output = strdup(arg_output);
196                         if (!output)
197                                 return log_oom();
198                 }
199         }
200
201         r = journal_file_open_reliably(output,
202                                        O_RDWR|O_CREAT, 0640,
203                                        arg_compress, arg_seal,
204                                        &s->metrics,
205                                        s->mmap,
206                                        NULL, &s->journal);
207         if (r < 0)
208                 log_error("Failed to open output journal %s: %s",
209                           arg_output, strerror(-r));
210         else
211                 log_info("Opened output file %s", s->journal->path);
212         return r;
213 }
214
215 /**********************************************************************
216  **********************************************************************
217  **********************************************************************/
218
219 typedef struct MHDDaemonWrapper {
220         uint64_t fd;
221         struct MHD_Daemon *daemon;
222
223         sd_event_source *event;
224 } MHDDaemonWrapper;
225
226 typedef struct RemoteServer {
227         RemoteSource **sources;
228         size_t sources_size;
229         size_t active;
230
231         sd_event *events;
232         sd_event_source *sigterm_event, *sigint_event, *listen_event;
233
234         Writer writer;
235
236         Hashmap *daemons;
237 } RemoteServer;
238
239 /* This should go away as soon as Âµhttpd allows state to be passed around. */
240 static RemoteServer *server;
241
242 static int dispatch_raw_source_event(sd_event_source *event,
243                                      int fd,
244                                      uint32_t revents,
245                                      void *userdata);
246 static int dispatch_raw_connection_event(sd_event_source *event,
247                                          int fd,
248                                          uint32_t revents,
249                                          void *userdata);
250 static int dispatch_http_event(sd_event_source *event,
251                                int fd,
252                                uint32_t revents,
253                                void *userdata);
254
255 static int get_source_for_fd(RemoteServer *s, int fd, RemoteSource **source) {
256         assert(fd >= 0);
257         assert(source);
258
259         if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
260                 return log_oom();
261
262         if (s->sources[fd] == NULL) {
263                 s->sources[fd] = new0(RemoteSource, 1);
264                 if (!s->sources[fd])
265                         return log_oom();
266                 s->sources[fd]->fd = -1;
267                 s->active++;
268         }
269
270         *source = s->sources[fd];
271         return 0;
272 }
273
274 static int remove_source(RemoteServer *s, int fd) {
275         RemoteSource *source;
276
277         assert(s);
278         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
279
280         source = s->sources[fd];
281         if (source) {
282                 source_free(source);
283                 s->sources[fd] = NULL;
284                 s->active--;
285         }
286
287         close(fd);
288
289         return 0;
290 }
291
292 static int add_source(RemoteServer *s, int fd, const char* name) {
293         RemoteSource *source = NULL;
294         char *realname;
295         int r;
296
297         assert(s);
298         assert(fd >= 0);
299
300         if (name) {
301                 realname = strdup(name);
302                 if (!realname)
303                         return log_oom();
304         } else {
305                 r = asprintf(&realname, "fd:%d", fd);
306                 if (r < 0)
307                         return log_oom();
308         }
309
310         log_debug("Creating source for fd:%d (%s)", fd, name);
311
312         r = get_source_for_fd(s, fd, &source);
313         if (r < 0) {
314                 log_error("Failed to create source for fd:%d (%s)", fd, name);
315                 return r;
316         }
317         assert(source);
318         assert(source->fd < 0);
319         source->fd = fd;
320
321         r = sd_event_add_io(s->events, &source->event,
322                             fd, EPOLLIN, dispatch_raw_source_event, s);
323         if (r < 0) {
324                 log_error("Failed to register event source for fd:%d: %s",
325                           fd, strerror(-r));
326                 goto error;
327         }
328
329         return 1; /* work to do */
330
331  error:
332         remove_source(s, fd);
333         return r;
334 }
335
336 static int add_raw_socket(RemoteServer *s, int fd) {
337         int r;
338
339         r = sd_event_add_io(s->events, &s->listen_event, fd, EPOLLIN,
340                             dispatch_raw_connection_event, s);
341         if (r < 0) {
342                 close(fd);
343                 return r;
344         }
345
346         s->active ++;
347         return 0;
348 }
349
350 static int setup_raw_socket(RemoteServer *s, const char *address) {
351         int fd;
352
353         fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
354         if (fd < 0)
355                 return fd;
356
357         return add_raw_socket(s, fd);
358 }
359
360 /**********************************************************************
361  **********************************************************************
362  **********************************************************************/
363
364 static RemoteSource *request_meta(void **connection_cls) {
365         RemoteSource *source;
366
367         assert(connection_cls);
368         if (*connection_cls)
369                 return *connection_cls;
370
371         source = new0(RemoteSource, 1);
372         if (!source)
373                 return NULL;
374         source->fd = -1;
375
376         log_debug("Added RemoteSource as connection metadata %p", source);
377
378         *connection_cls = source;
379         return source;
380 }
381
382 static void request_meta_free(void *cls,
383                               struct MHD_Connection *connection,
384                               void **connection_cls,
385                               enum MHD_RequestTerminationCode toe) {
386         RemoteSource *s;
387
388         assert(connection_cls);
389         s = *connection_cls;
390
391         log_debug("Cleaning up connection metadata %p", s);
392         source_free(s);
393         *connection_cls = NULL;
394 }
395
396 static int process_http_upload(
397                 struct MHD_Connection *connection,
398                 const char *upload_data,
399                 size_t *upload_data_size,
400                 RemoteSource *source) {
401
402         bool finished = false;
403         int r;
404
405         assert(source);
406
407         log_debug("request_handler_upload: connection %p, %zu bytes",
408                   connection, *upload_data_size);
409
410         if (*upload_data_size) {
411                 log_info("Received %zu bytes", *upload_data_size);
412
413                 r = push_data(source, upload_data, *upload_data_size);
414                 if (r < 0) {
415                         log_error("Failed to store received data of size %zu: %s",
416                                   *upload_data_size, strerror(-r));
417                         return mhd_respond_oom(connection);
418                 }
419                 *upload_data_size = 0;
420         } else
421                 finished = true;
422
423         while (true) {
424                 r = process_source(source, &server->writer, arg_compress, arg_seal);
425                 if (r == -E2BIG)
426                         log_warning("Entry too big, skipped");
427                 else if (r == -EAGAIN || r == -EWOULDBLOCK)
428                         break;
429                 else if (r < 0) {
430                         log_warning("Failed to process data for connection %p", connection);
431                         return mhd_respondf(connection, MHD_HTTP_UNPROCESSABLE_ENTITY,
432                                             "Processing failed: %s", strerror(-r));
433                 }
434         }
435
436         if (!finished)
437                 return MHD_YES;
438
439         /* The upload is finished */
440
441         if (source_non_empty(source)) {
442                 log_warning("EOF reached with incomplete data");
443                 return mhd_respond(connection, MHD_HTTP_EXPECTATION_FAILED,
444                                    "Trailing data not processed.");
445         }
446
447         return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
448 };
449
450 static int request_handler(
451                 void *cls,
452                 struct MHD_Connection *connection,
453                 const char *url,
454                 const char *method,
455                 const char *version,
456                 const char *upload_data,
457                 size_t *upload_data_size,
458                 void **connection_cls) {
459
460         const char *header;
461         int r ,code;
462
463         assert(connection);
464         assert(connection_cls);
465         assert(url);
466         assert(method);
467
468         log_debug("Handling a connection %s %s %s", method, url, version);
469
470         if (*connection_cls)
471                 return process_http_upload(connection,
472                                            upload_data, upload_data_size,
473                                            *connection_cls);
474
475         if (!streq(method, "POST"))
476                 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
477                                    "Unsupported method.\n");
478
479         if (!streq(url, "/upload"))
480                 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
481                                    "Not found.\n");
482
483         header = MHD_lookup_connection_value(connection,
484                                              MHD_HEADER_KIND, "Content-Type");
485         if (!header || !streq(header, "application/vnd.fdo.journal"))
486                 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
487                                    "Content-Type: application/vnd.fdo.journal"
488                                    " is required.\n");
489
490         if (trust_pem) {
491                 r = check_permissions(connection, &code);
492                 if (r < 0)
493                         return code;
494         }
495
496         if (!request_meta(connection_cls))
497                 return respond_oom(connection);
498         return MHD_YES;
499 }
500
501 static int setup_microhttpd_server(RemoteServer *s, int fd, bool https) {
502         struct MHD_OptionItem opts[] = {
503                 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
504                 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
505                 { MHD_OPTION_LISTEN_SOCKET, fd},
506                 { MHD_OPTION_END},
507                 { MHD_OPTION_END},
508                 { MHD_OPTION_END},
509                 { MHD_OPTION_END}};
510         int opts_pos = 3;
511         int flags =
512                 MHD_USE_DEBUG |
513                 MHD_USE_PEDANTIC_CHECKS |
514                 MHD_USE_EPOLL_LINUX_ONLY |
515                 MHD_USE_DUAL_STACK;
516
517         const union MHD_DaemonInfo *info;
518         int r, epoll_fd;
519         MHDDaemonWrapper *d;
520
521         assert(fd >= 0);
522
523         r = fd_nonblock(fd, true);
524         if (r < 0) {
525                 log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
526                 return r;
527         }
528
529         if (https) {
530                 opts[opts_pos++] = (struct MHD_OptionItem)
531                         {MHD_OPTION_HTTPS_MEM_KEY, 0, key_pem};
532                 opts[opts_pos++] = (struct MHD_OptionItem)
533                         {MHD_OPTION_HTTPS_MEM_CERT, 0, cert_pem};
534
535                 flags |= MHD_USE_SSL;
536
537                 if (trust_pem)
538                         opts[opts_pos++] = (struct MHD_OptionItem)
539                                 {MHD_OPTION_HTTPS_MEM_TRUST, 0, trust_pem};
540         }
541
542         d = new(MHDDaemonWrapper, 1);
543         if (!d)
544                 return log_oom();
545
546         d->fd = (uint64_t) fd;
547
548         d->daemon = MHD_start_daemon(flags, 0,
549                                      NULL, NULL,
550                                      request_handler, NULL,
551                                      MHD_OPTION_ARRAY, opts,
552                                      MHD_OPTION_END);
553         if (!d->daemon) {
554                 log_error("Failed to start Âµhttp daemon");
555                 r = -EINVAL;
556                 goto error;
557         }
558
559         log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
560                   https ? "HTTPS" : "HTTP", fd, d);
561
562
563         info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
564         if (!info) {
565                 log_error("µhttp returned NULL daemon info");
566                 r = -ENOTSUP;
567                 goto error;
568         }
569
570         epoll_fd = info->listen_fd;
571         if (epoll_fd < 0) {
572                 log_error("µhttp epoll fd is invalid");
573                 r = -EUCLEAN;
574                 goto error;
575         }
576
577         r = sd_event_add_io(s->events, &d->event,
578                             epoll_fd, EPOLLIN, dispatch_http_event, d);
579         if (r < 0) {
580                 log_error("Failed to add event callback: %s", strerror(-r));
581                 goto error;
582         }
583
584         r = hashmap_ensure_allocated(&s->daemons, uint64_hash_func, uint64_compare_func);
585         if (r < 0) {
586                 log_oom();
587                 goto error;
588         }
589
590         r = hashmap_put(s->daemons, &d->fd, d);
591         if (r < 0) {
592                 log_error("Failed to add daemon to hashmap: %s", strerror(-r));
593                 goto error;
594         }
595
596         s->active ++;
597         return 0;
598
599 error:
600         MHD_stop_daemon(d->daemon);
601         free(d->daemon);
602         free(d);
603         return r;
604 }
605
606 static int setup_microhttpd_socket(RemoteServer *s,
607                                    const char *address,
608                                    bool https) {
609         int fd;
610
611         fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
612         if (fd < 0)
613                 return fd;
614
615         return setup_microhttpd_server(s, fd, https);
616 }
617
618 static int dispatch_http_event(sd_event_source *event,
619                                int fd,
620                                uint32_t revents,
621                                void *userdata) {
622         MHDDaemonWrapper *d = userdata;
623         int r;
624
625         assert(d);
626
627         log_info("%s", __func__);
628
629         r = MHD_run(d->daemon);
630         if (r == MHD_NO) {
631                 log_error("MHD_run failed!");
632                 // XXX: unregister daemon
633                 return -EINVAL;
634         }
635
636         return 1; /* work to do */
637 }
638
639 /**********************************************************************
640  **********************************************************************
641  **********************************************************************/
642
643 static int dispatch_sigterm(sd_event_source *event,
644                             const struct signalfd_siginfo *si,
645                             void *userdata) {
646         RemoteServer *s = userdata;
647
648         assert(s);
649
650         log_received_signal(LOG_INFO, si);
651
652         sd_event_exit(s->events, 0);
653         return 0;
654 }
655
656 static int setup_signals(RemoteServer *s) {
657         sigset_t mask;
658         int r;
659
660         assert(s);
661
662         assert_se(sigemptyset(&mask) == 0);
663         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
664         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
665
666         r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, dispatch_sigterm, s);
667         if (r < 0)
668                 return r;
669
670         r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, dispatch_sigterm, s);
671         if (r < 0)
672                 return r;
673
674         return 0;
675 }
676
677 static int fd_fd(const char *spec) {
678         int fd, r;
679
680         r = safe_atoi(spec, &fd);
681         if (r < 0)
682                 return r;
683
684         if (fd >= 0)
685                 return -ENOENT;
686
687         return -fd;
688 }
689
690
691 static int remoteserver_init(RemoteServer *s) {
692         int r, n, fd;
693         const char *output_name = NULL;
694         char **file;
695
696         assert(s);
697
698         sd_event_default(&s->events);
699
700         setup_signals(s);
701
702         assert(server == NULL);
703         server = s;
704
705         n = sd_listen_fds(true);
706         if (n < 0) {
707                 log_error("Failed to read listening file descriptors from environment: %s",
708                           strerror(-n));
709                 return n;
710         } else
711                 log_info("Received %d descriptors", n);
712
713         if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
714                 log_error("Received fewer sockets than expected");
715                 return -EBADFD;
716         }
717
718         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
719                 if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
720                         log_info("Received a listening socket (fd:%d)", fd);
721
722                         if (fd == http_socket)
723                                 r = setup_microhttpd_server(s, fd, false);
724                         else if (fd == https_socket)
725                                 r = setup_microhttpd_server(s, fd, true);
726                         else
727                                 r = add_raw_socket(s, fd);
728                 } else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
729                         log_info("Received a connection socket (fd:%d)", fd);
730
731                         r = add_source(s, fd, NULL);
732                 } else {
733                         log_error("Unknown socket passed on fd:%d", fd);
734
735                         return -EINVAL;
736                 }
737
738                 if(r < 0) {
739                         log_error("Failed to register socket (fd:%d): %s",
740                                   fd, strerror(-r));
741                         return r;
742                 }
743
744                 output_name = "socket";
745         }
746
747         if (arg_url) {
748                 char _cleanup_free_ *url = NULL;
749                 char _cleanup_strv_free_ **urlv = strv_new(arg_url, "/entries", NULL);
750                 if (!urlv)
751                         return log_oom();
752                 url = strv_join(urlv, "");
753                 if (!url)
754                         return log_oom();
755
756                 if (arg_getter) {
757                         log_info("Spawning getter %s...", url);
758                         fd = spawn_getter(arg_getter, url);
759                 } else {
760                         log_info("Spawning curl %s...", url);
761                         fd = spawn_curl(url);
762                 }
763                 if (fd < 0)
764                         return fd;
765
766                 r = add_source(s, fd, arg_url);
767                 if (r < 0)
768                         return r;
769
770                 output_name = arg_url;
771         }
772
773         if (arg_listen_raw) {
774                 log_info("Listening on a socket...");
775                 r = setup_raw_socket(s, arg_listen_raw);
776                 if (r < 0)
777                         return r;
778
779                 output_name = arg_listen_raw;
780         }
781
782         if (arg_listen_http) {
783                 r = setup_microhttpd_socket(s, arg_listen_http, false);
784                 if (r < 0)
785                         return r;
786
787                 output_name = arg_listen_http;
788         }
789
790         if (arg_listen_https) {
791                 r = setup_microhttpd_socket(s, arg_listen_https, true);
792                 if (r < 0)
793                         return r;
794
795                 output_name = arg_listen_https;
796         }
797
798         STRV_FOREACH(file, arg_files) {
799                 if (streq(*file, "-")) {
800                         log_info("Reading standard input...");
801
802                         fd = STDIN_FILENO;
803                         output_name = "stdin";
804                 } else {
805                         log_info("Reading file %s...", *file);
806
807                         fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
808                         if (fd < 0) {
809                                 log_error("Failed to open %s: %m", *file);
810                                 return -errno;
811                         }
812                         output_name = *file;
813                 }
814
815                 r = add_source(s, fd, output_name);
816                 if (r < 0)
817                         return r;
818         }
819
820         if (s->active == 0) {
821                 log_error("Zarro sources specified");
822                 return -EINVAL;
823         }
824
825         if (!!n + !!arg_url + !!arg_listen_raw + !!arg_files)
826                 output_name = "multiple";
827
828         r = writer_init(&s->writer);
829         if (r < 0)
830                 return r;
831
832         r = open_output(&s->writer, output_name);
833         return r;
834 }
835
836 static int server_destroy(RemoteServer *s) {
837         int r;
838         size_t i;
839         MHDDaemonWrapper *d;
840
841         r = writer_close(&s->writer);
842
843         while ((d = hashmap_steal_first(s->daemons))) {
844                 MHD_stop_daemon(d->daemon);
845                 sd_event_source_unref(d->event);
846                 free(d);
847         }
848
849         hashmap_free(s->daemons);
850
851         assert(s->sources_size == 0 || s->sources);
852         for (i = 0; i < s->sources_size; i++)
853                 remove_source(s, i);
854
855         free(s->sources);
856
857         sd_event_source_unref(s->sigterm_event);
858         sd_event_source_unref(s->sigint_event);
859         sd_event_source_unref(s->listen_event);
860         sd_event_unref(s->events);
861
862         /* fds that we're listening on remain open... */
863
864         return r;
865 }
866
867 /**********************************************************************
868  **********************************************************************
869  **********************************************************************/
870
871 static int dispatch_raw_source_event(sd_event_source *event,
872                                      int fd,
873                                      uint32_t revents,
874                                      void *userdata) {
875
876         RemoteServer *s = userdata;
877         RemoteSource *source;
878         int r;
879
880         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
881         source = s->sources[fd];
882         assert(source->fd == fd);
883
884         r = process_source(source, &s->writer, arg_compress, arg_seal);
885         if (source->state == STATE_EOF) {
886                 log_info("EOF reached with source fd:%d (%s)",
887                          source->fd, source->name);
888                 if (source_non_empty(source))
889                         log_warning("EOF reached with incomplete data");
890                 remove_source(s, source->fd);
891                 log_info("%zd active source remaining", s->active);
892         } else if (r == -E2BIG) {
893                 log_error("Entry too big, skipped");
894                 r = 1;
895         }
896
897         return r;
898 }
899
900 static int accept_connection(const char* type, int fd, SocketAddress *addr) {
901         int fd2, r;
902
903         log_debug("Accepting new %s connection on fd:%d", type, fd);
904         fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
905         if (fd2 < 0) {
906                 log_error("accept() on fd:%d failed: %m", fd);
907                 return -errno;
908         }
909
910         switch(socket_address_family(addr)) {
911         case AF_INET:
912         case AF_INET6: {
913                 char* _cleanup_free_ a = NULL;
914
915                 r = socket_address_print(addr, &a);
916                 if (r < 0) {
917                         log_error("socket_address_print(): %s", strerror(-r));
918                         close(fd2);
919                         return r;
920                 }
921
922                 log_info("Accepted %s %s connection from %s",
923                          type,
924                          socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
925                          a);
926
927                 return fd2;
928         };
929         default:
930                 log_error("Rejected %s connection with unsupported family %d",
931                           type, socket_address_family(addr));
932                 close(fd2);
933
934                 return -EINVAL;
935         }
936 }
937
938 static int dispatch_raw_connection_event(sd_event_source *event,
939                                          int fd,
940                                          uint32_t revents,
941                                          void *userdata) {
942         RemoteServer *s = userdata;
943         int fd2;
944         SocketAddress addr = {
945                 .size = sizeof(union sockaddr_union),
946                 .type = SOCK_STREAM,
947         };
948
949         fd2 = accept_connection("raw", fd, &addr);
950         if (fd2 < 0)
951                 return fd2;
952
953         return add_source(s, fd2, NULL);
954 }
955
956 /**********************************************************************
957  **********************************************************************
958  **********************************************************************/
959
960 static int help(void) {
961         printf("%s [OPTIONS...] {FILE|-}...\n\n"
962                "Write external journal events to a journal file.\n\n"
963                "Options:\n"
964                "  --url=URL            Read events from systemd-journal-gatewayd at URL\n"
965                "  --getter=COMMAND     Read events from the output of COMMAND\n"
966                "  --listen-raw=ADDR    Listen for connections at ADDR\n"
967                "  --listen-http=ADDR   Listen for HTTP connections at ADDR\n"
968                "  --listen-https=ADDR  Listen for HTTPS connections at ADDR\n"
969                "  -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
970                "  --[no-]compress      Use XZ-compression in the output journal (default: yes)\n"
971                "  --[no-]seal          Use Event sealing in the output journal (default: no)\n"
972                "  -h --help            Show this help and exit\n"
973                "  --version            Print version string and exit\n"
974                "\n"
975                "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
976                , program_invocation_short_name);
977
978         return 0;
979 }
980
981 static int parse_argv(int argc, char *argv[]) {
982         enum {
983                 ARG_VERSION = 0x100,
984                 ARG_URL,
985                 ARG_LISTEN_RAW,
986                 ARG_LISTEN_HTTP,
987                 ARG_LISTEN_HTTPS,
988                 ARG_GETTER,
989                 ARG_COMPRESS,
990                 ARG_NO_COMPRESS,
991                 ARG_SEAL,
992                 ARG_NO_SEAL,
993                 ARG_KEY,
994                 ARG_CERT,
995                 ARG_TRUST,
996         };
997
998         static const struct option options[] = {
999                 { "help",         no_argument,       NULL, 'h'              },
1000                 { "version",      no_argument,       NULL, ARG_VERSION      },
1001                 { "url",          required_argument, NULL, ARG_URL          },
1002                 { "getter",       required_argument, NULL, ARG_GETTER       },
1003                 { "listen-raw",   required_argument, NULL, ARG_LISTEN_RAW   },
1004                 { "listen-http",  required_argument, NULL, ARG_LISTEN_HTTP  },
1005                 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1006                 { "output",       required_argument, NULL, 'o'              },
1007                 { "compress",     no_argument,       NULL, ARG_COMPRESS     },
1008                 { "no-compress",  no_argument,       NULL, ARG_NO_COMPRESS  },
1009                 { "seal",         no_argument,       NULL, ARG_SEAL         },
1010                 { "no-seal",      no_argument,       NULL, ARG_NO_SEAL      },
1011                 { "key",          required_argument, NULL, ARG_KEY          },
1012                 { "cert",         required_argument, NULL, ARG_CERT         },
1013                 { "trust",        required_argument, NULL, ARG_TRUST        },
1014                 {}
1015         };
1016
1017         int c, r;
1018
1019         assert(argc >= 0);
1020         assert(argv);
1021
1022         while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1023                 switch(c) {
1024                 case 'h':
1025                         help();
1026                         return 0 /* done */;
1027
1028                 case ARG_VERSION:
1029                         puts(PACKAGE_STRING);
1030                         puts(SYSTEMD_FEATURES);
1031                         return 0 /* done */;
1032
1033                 case ARG_URL:
1034                         if (arg_url) {
1035                                 log_error("cannot currently set more than one --url");
1036                                 return -EINVAL;
1037                         }
1038
1039                         arg_url = optarg;
1040                         break;
1041
1042                 case ARG_GETTER:
1043                         if (arg_getter) {
1044                                 log_error("cannot currently use --getter more than once");
1045                                 return -EINVAL;
1046                         }
1047
1048                         arg_getter = optarg;
1049                         break;
1050
1051                 case ARG_LISTEN_RAW:
1052                         if (arg_listen_raw) {
1053                                 log_error("cannot currently use --listen-raw more than once");
1054                                 return -EINVAL;
1055                         }
1056
1057                         arg_listen_raw = optarg;
1058                         break;
1059
1060                 case ARG_LISTEN_HTTP:
1061                         if (arg_listen_http || http_socket >= 0) {
1062                                 log_error("cannot currently use --listen-http more than once");
1063                                 return -EINVAL;
1064                         }
1065
1066                         r = fd_fd(optarg);
1067                         if (r >= 0)
1068                                 http_socket = r;
1069                         else if (r == -ENOENT)
1070                                 arg_listen_http = optarg;
1071                         else {
1072                                 log_error("Invalid port/fd specification %s: %s",
1073                                           optarg, strerror(-r));
1074                                 return -EINVAL;
1075                         }
1076
1077                         break;
1078
1079                 case ARG_LISTEN_HTTPS:
1080                         if (arg_listen_https || https_socket >= 0) {
1081                                 log_error("cannot currently use --listen-https more than once");
1082                                 return -EINVAL;
1083                         }
1084
1085                         r = fd_fd(optarg);
1086                         if (r >= 0)
1087                                 https_socket = r;
1088                         else if (r == -ENOENT)
1089                                 arg_listen_https = optarg;
1090                         else {
1091                                 log_error("Invalid port/fd specification %s: %s",
1092                                           optarg, strerror(-r));
1093                                 return -EINVAL;
1094                         }
1095
1096                         break;
1097
1098                 case ARG_KEY:
1099                         if (key_pem) {
1100                                 log_error("Key file specified twice");
1101                                 return -EINVAL;
1102                         }
1103                         r = read_full_file(optarg, &key_pem, NULL);
1104                         if (r < 0) {
1105                                 log_error("Failed to read key file: %s", strerror(-r));
1106                                 return r;
1107                         }
1108                         assert(key_pem);
1109                         break;
1110
1111                 case ARG_CERT:
1112                         if (cert_pem) {
1113                                 log_error("Certificate file specified twice");
1114                                 return -EINVAL;
1115                         }
1116                         r = read_full_file(optarg, &cert_pem, NULL);
1117                         if (r < 0) {
1118                                 log_error("Failed to read certificate file: %s", strerror(-r));
1119                                 return r;
1120                         }
1121                         assert(cert_pem);
1122                         break;
1123
1124                 case ARG_TRUST:
1125 #ifdef HAVE_GNUTLS
1126                         if (trust_pem) {
1127                                 log_error("CA certificate file specified twice");
1128                                 return -EINVAL;
1129                         }
1130                         r = read_full_file(optarg, &trust_pem, NULL);
1131                         if (r < 0) {
1132                                 log_error("Failed to read CA certificate file: %s", strerror(-r));
1133                                 return r;
1134                         }
1135                         assert(trust_pem);
1136                         break;
1137 #else
1138                         log_error("Option --trust is not available.");
1139 #endif
1140
1141                 case 'o':
1142                         if (arg_output) {
1143                                 log_error("cannot use --output/-o more than once");
1144                                 return -EINVAL;
1145                         }
1146
1147                         arg_output = optarg;
1148                         break;
1149
1150                 case ARG_COMPRESS:
1151                         arg_compress = true;
1152                         break;
1153                 case ARG_NO_COMPRESS:
1154                         arg_compress = false;
1155                         break;
1156                 case ARG_SEAL:
1157                         arg_seal = true;
1158                         break;
1159                 case ARG_NO_SEAL:
1160                         arg_seal = false;
1161                         break;
1162
1163                 case '?':
1164                         return -EINVAL;
1165
1166                 default:
1167                         log_error("Unknown option code %c", c);
1168                         return -EINVAL;
1169                 }
1170
1171         if (arg_listen_https && !(key_pem && cert_pem)) {
1172                 log_error("Options --key and --cert must be used when https sources are specified");
1173                 return -EINVAL;
1174         }
1175
1176         if (optind < argc)
1177                 arg_files = argv + optind;
1178
1179         return 1 /* work to do */;
1180 }
1181
1182 static int setup_gnutls_logger(void) {
1183         if (!arg_listen_http && !arg_listen_https)
1184                 return 0;
1185
1186 #ifdef HAVE_GNUTLS
1187         gnutls_global_set_log_function(log_func_gnutls);
1188         gnutls_global_set_log_level(GNUTLS_LOG_LEVEL);
1189 #endif
1190
1191         return 0;
1192 }
1193
1194 int main(int argc, char **argv) {
1195         RemoteServer s = {};
1196         int r, r2;
1197
1198         log_set_max_level(LOG_DEBUG);
1199         log_show_color(true);
1200         log_parse_environment();
1201
1202         r = parse_argv(argc, argv);
1203         if (r <= 0)
1204                 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1205
1206         r = setup_gnutls_logger();
1207         if (r < 0)
1208                 return EXIT_FAILURE;
1209
1210         if (remoteserver_init(&s) < 0)
1211                 return EXIT_FAILURE;
1212
1213         log_debug("%s running as pid "PID_FMT,
1214                   program_invocation_short_name, getpid());
1215         sd_notify(false,
1216                   "READY=1\n"
1217                   "STATUS=Processing requests...");
1218
1219         while (s.active) {
1220                 r = sd_event_get_state(s.events);
1221                 if (r < 0)
1222                         break;
1223                 if (r == SD_EVENT_FINISHED)
1224                         break;
1225
1226                 r = sd_event_run(s.events, -1);
1227                 if (r < 0) {
1228                         log_error("Failed to run event loop: %s", strerror(-r));
1229                         break;
1230                 }
1231         }
1232
1233         log_info("Finishing after writing %" PRIu64 " entries", s.writer.seqnum);
1234         r2 = server_destroy(&s);
1235
1236         sd_notify(false, "STATUS=Shutting down...");
1237
1238         return r >= 0 && r2 >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1239 }