chiark / gitweb /
journal-remote: process events without delay
[elogind.git] / src / journal-remote / 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 <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/prctl.h>
28 #include <sys/socket.h>
29 #include <unistd.h>
30 #include <getopt.h>
31
32 #include "sd-daemon.h"
33 #include "journal-file.h"
34 #include "journald-native.h"
35 #include "socket-util.h"
36 #include "build.h"
37 #include "macro.h"
38 #include "strv.h"
39 #include "fileio.h"
40 #include "conf-parser.h"
41
42 #ifdef HAVE_GNUTLS
43 #include <gnutls/gnutls.h>
44 #endif
45
46 #include "journal-remote.h"
47 #include "journal-remote-write.h"
48
49 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
50
51 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
52 #define CERT_FILE     CERTIFICATE_ROOT "/certs/journal-remote.pem"
53 #define TRUST_FILE    CERTIFICATE_ROOT "/ca/trusted.pem"
54
55 static char* arg_url = NULL;
56 static char* arg_getter = NULL;
57 static char* arg_listen_raw = NULL;
58 static char* arg_listen_http = NULL;
59 static char* arg_listen_https = NULL;
60 static char** arg_files = NULL;
61 static int arg_compress = true;
62 static int arg_seal = false;
63 static int http_socket = -1, https_socket = -1;
64 static char** arg_gnutls_log = NULL;
65
66 static JournalWriteSplitMode arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
67 static char* arg_output = NULL;
68
69 static char *arg_key = NULL;
70 static char *arg_cert = NULL;
71 static char *arg_trust = NULL;
72 static bool arg_trust_all = false;
73
74 /**********************************************************************
75  **********************************************************************
76  **********************************************************************/
77
78 static int spawn_child(const char* child, char** argv) {
79         int fd[2];
80         pid_t parent_pid, child_pid;
81         int r;
82
83         if (pipe(fd) < 0)
84                 return log_error_errno(errno, "Failed to create pager pipe: %m");
85
86         parent_pid = getpid();
87
88         child_pid = fork();
89         if (child_pid < 0) {
90                 r = -errno;
91                 log_error_errno(errno, "Failed to fork: %m");
92                 safe_close_pair(fd);
93                 return r;
94         }
95
96         /* In the child */
97         if (child_pid == 0) {
98                 r = dup2(fd[1], STDOUT_FILENO);
99                 if (r < 0) {
100                         log_error_errno(errno, "Failed to dup pipe to stdout: %m");
101                         _exit(EXIT_FAILURE);
102                 }
103
104                 safe_close_pair(fd);
105
106                 /* Make sure the child goes away when the parent dies */
107                 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
108                         _exit(EXIT_FAILURE);
109
110                 /* Check whether our parent died before we were able
111                  * to set the death signal */
112                 if (getppid() != parent_pid)
113                         _exit(EXIT_SUCCESS);
114
115                 execvp(child, argv);
116                 log_error_errno(errno, "Failed to exec child %s: %m", child);
117                 _exit(EXIT_FAILURE);
118         }
119
120         r = close(fd[1]);
121         if (r < 0)
122                 log_warning_errno(errno, "Failed to close write end of pipe: %m");
123
124         return fd[0];
125 }
126
127 static int spawn_curl(const char* url) {
128         char **argv = STRV_MAKE("curl",
129                                 "-HAccept: application/vnd.fdo.journal",
130                                 "--silent",
131                                 "--show-error",
132                                 url);
133         int r;
134
135         r = spawn_child("curl", argv);
136         if (r < 0)
137                 log_error_errno(errno, "Failed to spawn curl: %m");
138         return r;
139 }
140
141 static int spawn_getter(const char *getter, const char *url) {
142         int r;
143         _cleanup_strv_free_ char **words = NULL;
144
145         assert(getter);
146         r = strv_split_quoted(&words, getter, false);
147         if (r < 0)
148                 return log_error_errno(r, "Failed to split getter option: %m");
149
150         r = strv_extend(&words, url);
151         if (r < 0)
152                 return log_error_errno(r, "Failed to create command line: %m");
153
154         r = spawn_child(words[0], words);
155         if (r < 0)
156                 log_error_errno(errno, "Failed to spawn getter %s: %m", getter);
157
158         return r;
159 }
160
161 #define filename_escape(s) xescape((s), "/ ")
162
163 static int open_output(Writer *w, const char* host) {
164         _cleanup_free_ char *_output = NULL;
165         const char *output;
166         int r;
167
168         switch (arg_split_mode) {
169         case JOURNAL_WRITE_SPLIT_NONE:
170                 output = arg_output ?: REMOTE_JOURNAL_PATH "/remote.journal";
171                 break;
172
173         case JOURNAL_WRITE_SPLIT_HOST: {
174                 _cleanup_free_ char *name;
175
176                 assert(host);
177
178                 name = filename_escape(host);
179                 if (!name)
180                         return log_oom();
181
182                 r = asprintf(&_output, "%s/remote-%s.journal",
183                              arg_output ?: REMOTE_JOURNAL_PATH,
184                              name);
185                 if (r < 0)
186                         return log_oom();
187
188                 output = _output;
189                 break;
190         }
191
192         default:
193                 assert_not_reached("what?");
194         }
195
196         r = journal_file_open_reliably(output,
197                                        O_RDWR|O_CREAT, 0640,
198                                        arg_compress, arg_seal,
199                                        &w->metrics,
200                                        w->mmap,
201                                        NULL, &w->journal);
202         if (r < 0)
203                 log_error_errno(r, "Failed to open output journal %s: %m",
204                                 output);
205         else
206                 log_debug("Opened output file %s", w->journal->path);
207         return r;
208 }
209
210 /**********************************************************************
211  **********************************************************************
212  **********************************************************************/
213
214 static int init_writer_hashmap(RemoteServer *s) {
215         static const struct hash_ops *hash_ops[] = {
216                 [JOURNAL_WRITE_SPLIT_NONE] = NULL,
217                 [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
218         };
219
220         assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(hash_ops));
221
222         s->writers = hashmap_new(hash_ops[arg_split_mode]);
223         if (!s->writers)
224                 return log_oom();
225
226         return 0;
227 }
228
229 static int get_writer(RemoteServer *s, const char *host,
230                       Writer **writer) {
231         const void *key;
232         _cleanup_writer_unref_ Writer *w = NULL;
233         int r;
234
235         switch(arg_split_mode) {
236         case JOURNAL_WRITE_SPLIT_NONE:
237                 key = "one and only";
238                 break;
239
240         case JOURNAL_WRITE_SPLIT_HOST:
241                 assert(host);
242                 key = host;
243                 break;
244
245         default:
246                 assert_not_reached("what split mode?");
247         }
248
249         w = hashmap_get(s->writers, key);
250         if (w)
251                 writer_ref(w);
252         else {
253                 w = writer_new(s);
254                 if (!w)
255                         return log_oom();
256
257                 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
258                         w->hashmap_key = strdup(key);
259                         if (!w->hashmap_key)
260                                 return log_oom();
261                 }
262
263                 r = open_output(w, host);
264                 if (r < 0)
265                         return r;
266
267                 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
268                 if (r < 0)
269                         return r;
270         }
271
272         *writer = w;
273         w = NULL;
274         return 0;
275 }
276
277 /**********************************************************************
278  **********************************************************************
279  **********************************************************************/
280
281 /* This should go away as soon as µhttpd allows state to be passed around. */
282 static RemoteServer *server;
283
284 static int dispatch_raw_source_event(sd_event_source *event,
285                                      int fd,
286                                      uint32_t revents,
287                                      void *userdata);
288 static int dispatch_raw_source_until_block(sd_event_source *event,
289                                            void *userdata);
290 static int dispatch_blocking_source_event(sd_event_source *event,
291                                           void *userdata);
292 static int dispatch_raw_connection_event(sd_event_source *event,
293                                          int fd,
294                                          uint32_t revents,
295                                          void *userdata);
296 static int dispatch_http_event(sd_event_source *event,
297                                int fd,
298                                uint32_t revents,
299                                void *userdata);
300
301 static int get_source_for_fd(RemoteServer *s,
302                              int fd, char *name, RemoteSource **source) {
303         Writer *writer;
304         int r;
305
306         /* This takes ownership of name, but only on success. */
307
308         assert(fd >= 0);
309         assert(source);
310
311         if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
312                 return log_oom();
313
314         r = get_writer(s, name, &writer);
315         if (r < 0)
316                 return log_warning_errno(r, "Failed to get writer for source %s: %m",
317                                          name);
318
319         if (s->sources[fd] == NULL) {
320                 s->sources[fd] = source_new(fd, false, name, writer);
321                 if (!s->sources[fd]) {
322                         writer_unref(writer);
323                         return log_oom();
324                 }
325
326                 s->active++;
327         }
328
329         *source = s->sources[fd];
330         return 0;
331 }
332
333 static int remove_source(RemoteServer *s, int fd) {
334         RemoteSource *source;
335
336         assert(s);
337         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
338
339         source = s->sources[fd];
340         if (source) {
341                 /* this closes fd too */
342                 source_free(source);
343                 s->sources[fd] = NULL;
344                 s->active--;
345         }
346
347         return 0;
348 }
349
350 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
351
352         RemoteSource *source;
353         int r;
354
355         /* This takes ownership of name, even on failure, if own_name is true. */
356
357         assert(s);
358         assert(fd >= 0);
359         assert(name);
360
361         if (!own_name) {
362                 name = strdup(name);
363                 if (!name)
364                         return log_oom();
365         }
366
367         r = get_source_for_fd(s, fd, name, &source);
368         if (r < 0) {
369                 log_error_errno(r, "Failed to create source for fd:%d (%s): %m",
370                                 fd, name);
371                 free(name);
372                 return r;
373         }
374
375         r = sd_event_add_io(s->events, &source->event,
376                             fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
377                             dispatch_raw_source_event, source);
378         if (r == 0) {
379                 /* Add additional source for buffer processing. It will be
380                  * enabled later. */
381                 r = sd_event_add_defer(s->events, &source->buffer_event,
382                                        dispatch_raw_source_until_block, source);
383                 if (r == 0)
384                         sd_event_source_set_enabled(source->buffer_event, SD_EVENT_OFF);
385         } else if (r == -EPERM) {
386                 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
387                 r = sd_event_add_defer(s->events, &source->event,
388                                        dispatch_blocking_source_event, source);
389                 if (r == 0)
390                         sd_event_source_set_enabled(source->event, SD_EVENT_ON);
391         }
392         if (r < 0) {
393                 log_error_errno(r, "Failed to register event source for fd:%d: %m",
394                                 fd);
395                 goto error;
396         }
397
398         r = sd_event_source_set_description(source->event, name);
399         if (r < 0) {
400                 log_error_errno(r, "Failed to set source name for fd:%d: %m", fd);
401                 goto error;
402         }
403
404         return 1; /* work to do */
405
406  error:
407         remove_source(s, fd);
408         return r;
409 }
410
411 static int add_raw_socket(RemoteServer *s, int fd) {
412         int r;
413         _cleanup_close_ int fd_ = fd;
414         char name[sizeof("raw-socket-")-1 + DECIMAL_STR_MAX(int) + 1];
415
416         assert(fd >= 0);
417
418         r = sd_event_add_io(s->events, &s->listen_event,
419                             fd, EPOLLIN,
420                             dispatch_raw_connection_event, s);
421         if (r < 0)
422                 return r;
423
424         xsprintf(name, "raw-socket-%d", fd);
425
426         r = sd_event_source_set_description(s->listen_event, name);
427         if (r < 0)
428                 return r;
429
430         fd_ = -1;
431         s->active ++;
432         return 0;
433 }
434
435 static int setup_raw_socket(RemoteServer *s, const char *address) {
436         int fd;
437
438         fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
439         if (fd < 0)
440                 return fd;
441
442         return add_raw_socket(s, fd);
443 }
444
445 /**********************************************************************
446  **********************************************************************
447  **********************************************************************/
448
449 static int request_meta(void **connection_cls, int fd, char *hostname) {
450         RemoteSource *source;
451         Writer *writer;
452         int r;
453
454         assert(connection_cls);
455         if (*connection_cls)
456                 return 0;
457
458         r = get_writer(server, hostname, &writer);
459         if (r < 0)
460                 return log_warning_errno(r, "Failed to get writer for source %s: %m",
461                                          hostname);
462
463         source = source_new(fd, true, hostname, writer);
464         if (!source) {
465                 writer_unref(writer);
466                 return log_oom();
467         }
468
469         log_debug("Added RemoteSource as connection metadata %p", source);
470
471         *connection_cls = source;
472         return 0;
473 }
474
475 static void request_meta_free(void *cls,
476                               struct MHD_Connection *connection,
477                               void **connection_cls,
478                               enum MHD_RequestTerminationCode toe) {
479         RemoteSource *s;
480
481         assert(connection_cls);
482         s = *connection_cls;
483
484         if (s) {
485                 log_debug("Cleaning up connection metadata %p", s);
486                 source_free(s);
487                 *connection_cls = NULL;
488         }
489 }
490
491 static int process_http_upload(
492                 struct MHD_Connection *connection,
493                 const char *upload_data,
494                 size_t *upload_data_size,
495                 RemoteSource *source) {
496
497         bool finished = false;
498         size_t remaining;
499         int r;
500
501         assert(source);
502
503         log_trace("%s: connection %p, %zu bytes",
504                   __func__, connection, *upload_data_size);
505
506         if (*upload_data_size) {
507                 log_trace("Received %zu bytes", *upload_data_size);
508
509                 r = push_data(source, upload_data, *upload_data_size);
510                 if (r < 0)
511                         return mhd_respond_oom(connection);
512
513                 *upload_data_size = 0;
514         } else
515                 finished = true;
516
517         while (true) {
518                 r = process_source(source, arg_compress, arg_seal);
519                 if (r == -EAGAIN || r == -EWOULDBLOCK)
520                         break;
521                 else if (r < 0) {
522                         log_warning("Failed to process data for connection %p", connection);
523                         if (r == -E2BIG)
524                                 return mhd_respondf(connection,
525                                                     MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
526                                                     "Entry is too large, maximum is %u bytes.\n",
527                                                     DATA_SIZE_MAX);
528                         else
529                                 return mhd_respondf(connection,
530                                                     MHD_HTTP_UNPROCESSABLE_ENTITY,
531                                                     "Processing failed: %s.", strerror(-r));
532                 }
533         }
534
535         if (!finished)
536                 return MHD_YES;
537
538         /* The upload is finished */
539
540         remaining = source_non_empty(source);
541         if (remaining > 0) {
542                 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
543                 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
544                                     "Premature EOF. %zu bytes of trailing data not processed.",
545                                     remaining);
546         }
547
548         return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
549 };
550
551 static int request_handler(
552                 void *cls,
553                 struct MHD_Connection *connection,
554                 const char *url,
555                 const char *method,
556                 const char *version,
557                 const char *upload_data,
558                 size_t *upload_data_size,
559                 void **connection_cls) {
560
561         const char *header;
562         int r, code, fd;
563         _cleanup_free_ char *hostname = NULL;
564
565         assert(connection);
566         assert(connection_cls);
567         assert(url);
568         assert(method);
569
570         log_trace("Handling a connection %s %s %s", method, url, version);
571
572         if (*connection_cls)
573                 return process_http_upload(connection,
574                                            upload_data, upload_data_size,
575                                            *connection_cls);
576
577         if (!streq(method, "POST"))
578                 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
579                                    "Unsupported method.\n");
580
581         if (!streq(url, "/upload"))
582                 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
583                                    "Not found.\n");
584
585         header = MHD_lookup_connection_value(connection,
586                                              MHD_HEADER_KIND, "Content-Type");
587         if (!header || !streq(header, "application/vnd.fdo.journal"))
588                 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
589                                    "Content-Type: application/vnd.fdo.journal"
590                                    " is required.\n");
591
592         {
593                 const union MHD_ConnectionInfo *ci;
594
595                 ci = MHD_get_connection_info(connection,
596                                              MHD_CONNECTION_INFO_CONNECTION_FD);
597                 if (!ci) {
598                         log_error("MHD_get_connection_info failed: cannot get remote fd");
599                         return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
600                                            "Cannot check remote address");
601                 }
602
603                 fd = ci->connect_fd;
604                 assert(fd >= 0);
605         }
606
607         if (server->check_trust) {
608                 r = check_permissions(connection, &code, &hostname);
609                 if (r < 0)
610                         return code;
611         } else {
612                 r = getnameinfo_pretty(fd, &hostname);
613                 if (r < 0) {
614                         return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
615                                            "Cannot check remote hostname");
616                 }
617         }
618
619         assert(hostname);
620
621         r = request_meta(connection_cls, fd, hostname);
622         if (r == -ENOMEM)
623                 return respond_oom(connection);
624         else if (r < 0)
625                 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
626                                    strerror(-r));
627
628         hostname = NULL;
629         return MHD_YES;
630 }
631
632 static int setup_microhttpd_server(RemoteServer *s,
633                                    int fd,
634                                    const char *key,
635                                    const char *cert,
636                                    const char *trust) {
637         struct MHD_OptionItem opts[] = {
638                 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
639                 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
640                 { MHD_OPTION_LISTEN_SOCKET, fd},
641                 { MHD_OPTION_END},
642                 { MHD_OPTION_END},
643                 { MHD_OPTION_END},
644                 { MHD_OPTION_END}};
645         int opts_pos = 3;
646         int flags =
647                 MHD_USE_DEBUG |
648                 MHD_USE_PEDANTIC_CHECKS |
649                 MHD_USE_EPOLL_LINUX_ONLY |
650                 MHD_USE_DUAL_STACK;
651
652         const union MHD_DaemonInfo *info;
653         int r, epoll_fd;
654         MHDDaemonWrapper *d;
655
656         assert(fd >= 0);
657
658         r = fd_nonblock(fd, true);
659         if (r < 0)
660                 return log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);
661
662         if (key) {
663                 assert(cert);
664
665                 opts[opts_pos++] = (struct MHD_OptionItem)
666                         {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
667                 opts[opts_pos++] = (struct MHD_OptionItem)
668                         {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
669
670                 flags |= MHD_USE_SSL;
671
672                 if (trust)
673                         opts[opts_pos++] = (struct MHD_OptionItem)
674                                 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
675         }
676
677         d = new(MHDDaemonWrapper, 1);
678         if (!d)
679                 return log_oom();
680
681         d->fd = (uint64_t) fd;
682
683         d->daemon = MHD_start_daemon(flags, 0,
684                                      NULL, NULL,
685                                      request_handler, NULL,
686                                      MHD_OPTION_ARRAY, opts,
687                                      MHD_OPTION_END);
688         if (!d->daemon) {
689                 log_error("Failed to start µhttp daemon");
690                 r = -EINVAL;
691                 goto error;
692         }
693
694         log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
695                   key ? "HTTPS" : "HTTP", fd, d);
696
697
698         info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
699         if (!info) {
700                 log_error("µhttp returned NULL daemon info");
701                 r = -ENOTSUP;
702                 goto error;
703         }
704
705         epoll_fd = info->listen_fd;
706         if (epoll_fd < 0) {
707                 log_error("µhttp epoll fd is invalid");
708                 r = -EUCLEAN;
709                 goto error;
710         }
711
712         r = sd_event_add_io(s->events, &d->event,
713                             epoll_fd, EPOLLIN,
714                             dispatch_http_event, d);
715         if (r < 0) {
716                 log_error_errno(r, "Failed to add event callback: %m");
717                 goto error;
718         }
719
720         r = sd_event_source_set_description(d->event, "epoll-fd");
721         if (r < 0) {
722                 log_error_errno(r, "Failed to set source name: %m");
723                 goto error;
724         }
725
726         r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
727         if (r < 0) {
728                 log_oom();
729                 goto error;
730         }
731
732         r = hashmap_put(s->daemons, &d->fd, d);
733         if (r < 0) {
734                 log_error_errno(r, "Failed to add daemon to hashmap: %m");
735                 goto error;
736         }
737
738         s->active ++;
739         return 0;
740
741 error:
742         MHD_stop_daemon(d->daemon);
743         free(d->daemon);
744         free(d);
745         return r;
746 }
747
748 static int setup_microhttpd_socket(RemoteServer *s,
749                                    const char *address,
750                                    const char *key,
751                                    const char *cert,
752                                    const char *trust) {
753         int fd;
754
755         fd = make_socket_fd(LOG_DEBUG, address, SOCK_STREAM | SOCK_CLOEXEC);
756         if (fd < 0)
757                 return fd;
758
759         return setup_microhttpd_server(s, fd, key, cert, trust);
760 }
761
762 static int dispatch_http_event(sd_event_source *event,
763                                int fd,
764                                uint32_t revents,
765                                void *userdata) {
766         MHDDaemonWrapper *d = userdata;
767         int r;
768
769         assert(d);
770
771         r = MHD_run(d->daemon);
772         if (r == MHD_NO) {
773                 log_error("MHD_run failed!");
774                 // XXX: unregister daemon
775                 return -EINVAL;
776         }
777
778         return 1; /* work to do */
779 }
780
781 /**********************************************************************
782  **********************************************************************
783  **********************************************************************/
784
785 static int setup_signals(RemoteServer *s) {
786         sigset_t mask;
787         int r;
788
789         assert(s);
790
791         assert_se(sigemptyset(&mask) == 0);
792         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
793         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
794
795         r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
796         if (r < 0)
797                 return r;
798
799         r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
800         if (r < 0)
801                 return r;
802
803         return 0;
804 }
805
806 static int negative_fd(const char *spec) {
807         /* Return a non-positive number as its inverse, -EINVAL otherwise. */
808
809         int fd, r;
810
811         r = safe_atoi(spec, &fd);
812         if (r < 0)
813                 return r;
814
815         if (fd > 0)
816                 return -EINVAL;
817         else
818                 return -fd;
819 }
820
821 static int remoteserver_init(RemoteServer *s,
822                              const char* key,
823                              const char* cert,
824                              const char* trust) {
825         int r, n, fd;
826         char **file;
827
828         assert(s);
829
830         if ((arg_listen_raw || arg_listen_http) && trust) {
831                 log_error("Option --trust makes all non-HTTPS connections untrusted.");
832                 return -EINVAL;
833         }
834
835         r = sd_event_default(&s->events);
836         if (r < 0)
837                 return log_error_errno(r, "Failed to allocate event loop: %m");
838
839         setup_signals(s);
840
841         assert(server == NULL);
842         server = s;
843
844         r = init_writer_hashmap(s);
845         if (r < 0)
846                 return r;
847
848         n = sd_listen_fds(true);
849         if (n < 0)
850                 return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
851         else
852                 log_debug("Received %d descriptors", n);
853
854         if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
855                 log_error("Received fewer sockets than expected");
856                 return -EBADFD;
857         }
858
859         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
860                 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
861                         log_debug("Received a listening socket (fd:%d)", fd);
862
863                         if (fd == http_socket)
864                                 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
865                         else if (fd == https_socket)
866                                 r = setup_microhttpd_server(s, fd, key, cert, trust);
867                         else
868                                 r = add_raw_socket(s, fd);
869                 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
870                         char *hostname;
871
872                         r = getnameinfo_pretty(fd, &hostname);
873                         if (r < 0)
874                                 return log_error_errno(r, "Failed to retrieve remote name: %m");
875
876                         log_debug("Received a connection socket (fd:%d) from %s", fd, hostname);
877
878                         r = add_source(s, fd, hostname, true);
879                 } else {
880                         log_error("Unknown socket passed on fd:%d", fd);
881
882                         return -EINVAL;
883                 }
884
885                 if (r < 0)
886                         return log_error_errno(r, "Failed to register socket (fd:%d): %m",
887                                                fd);
888         }
889
890         if (arg_url) {
891                 const char *url, *hostname;
892
893                 url = strjoina(arg_url, "/entries");
894
895                 if (arg_getter) {
896                         log_info("Spawning getter %s...", url);
897                         fd = spawn_getter(arg_getter, url);
898                 } else {
899                         log_info("Spawning curl %s...", url);
900                         fd = spawn_curl(url);
901                 }
902                 if (fd < 0)
903                         return fd;
904
905                 hostname =
906                         startswith(arg_url, "https://") ?:
907                         startswith(arg_url, "http://") ?:
908                         arg_url;
909
910                 r = add_source(s, fd, (char*) hostname, false);
911                 if (r < 0)
912                         return r;
913         }
914
915         if (arg_listen_raw) {
916                 log_debug("Listening on a socket...");
917                 r = setup_raw_socket(s, arg_listen_raw);
918                 if (r < 0)
919                         return r;
920         }
921
922         if (arg_listen_http) {
923                 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
924                 if (r < 0)
925                         return r;
926         }
927
928         if (arg_listen_https) {
929                 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
930                 if (r < 0)
931                         return r;
932         }
933
934         STRV_FOREACH(file, arg_files) {
935                 const char *output_name;
936
937                 if (streq(*file, "-")) {
938                         log_debug("Using standard input as source.");
939
940                         fd = STDIN_FILENO;
941                         output_name = "stdin";
942                 } else {
943                         log_debug("Reading file %s...", *file);
944
945                         fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
946                         if (fd < 0)
947                                 return log_error_errno(errno, "Failed to open %s: %m", *file);
948                         output_name = *file;
949                 }
950
951                 r = add_source(s, fd, (char*) output_name, false);
952                 if (r < 0)
953                         return r;
954         }
955
956         if (s->active == 0) {
957                 log_error("Zarro sources specified");
958                 return -EINVAL;
959         }
960
961         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
962                 /* In this case we know what the writer will be
963                    called, so we can create it and verify that we can
964                    create output as expected. */
965                 r = get_writer(s, NULL, &s->_single_writer);
966                 if (r < 0)
967                         return r;
968         }
969
970         return 0;
971 }
972
973 static void server_destroy(RemoteServer *s) {
974         size_t i;
975         MHDDaemonWrapper *d;
976
977         while ((d = hashmap_steal_first(s->daemons))) {
978                 MHD_stop_daemon(d->daemon);
979                 sd_event_source_unref(d->event);
980                 free(d);
981         }
982
983         hashmap_free(s->daemons);
984
985         assert(s->sources_size == 0 || s->sources);
986         for (i = 0; i < s->sources_size; i++)
987                 remove_source(s, i);
988         free(s->sources);
989
990         writer_unref(s->_single_writer);
991         hashmap_free(s->writers);
992
993         sd_event_source_unref(s->sigterm_event);
994         sd_event_source_unref(s->sigint_event);
995         sd_event_source_unref(s->listen_event);
996         sd_event_unref(s->events);
997
998         /* fds that we're listening on remain open... */
999 }
1000
1001 /**********************************************************************
1002  **********************************************************************
1003  **********************************************************************/
1004
1005 static int handle_raw_source(sd_event_source *event,
1006                              int fd,
1007                              uint32_t revents,
1008                              RemoteServer *s) {
1009
1010         RemoteSource *source;
1011         int r;
1012
1013         /* Returns 1 if there might be more data pending,
1014          * 0 if data is currently exhausted, negative on error.
1015          */
1016
1017         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1018         source = s->sources[fd];
1019         assert(source->fd == fd);
1020
1021         r = process_source(source, arg_compress, arg_seal);
1022         if (source->state == STATE_EOF) {
1023                 size_t remaining;
1024
1025                 log_debug("EOF reached with source fd:%d (%s)",
1026                           source->fd, source->name);
1027
1028                 remaining = source_non_empty(source);
1029                 if (remaining > 0)
1030                         log_notice("Premature EOF. %zu bytes lost.", remaining);
1031                 remove_source(s, source->fd);
1032                 log_debug("%zu active sources remaining", s->active);
1033                 return 0;
1034         } else if (r == -E2BIG) {
1035                 log_notice_errno(E2BIG, "Entry too big, skipped");
1036                 return 1;
1037         } else if (r == -EAGAIN || r == -EWOULDBLOCK) {
1038                 return 0;
1039         } else if (r < 0) {
1040                 log_debug_errno(r, "Closing connection: %m");
1041                 remove_source(server, fd);
1042                 return 0;
1043         } else
1044                 return 1;
1045 }
1046
1047 static int dispatch_raw_source_until_block(sd_event_source *event,
1048                                            void *userdata) {
1049         RemoteSource *source = userdata;
1050         int r;
1051
1052         /* Make sure event stays around even if source is destroyed */
1053         sd_event_source_ref(event);
1054
1055         r = handle_raw_source(event, source->fd, EPOLLIN, server);
1056         if (r != 1)
1057                 /* No more data for now */
1058                 sd_event_source_set_enabled(event, SD_EVENT_OFF);
1059
1060         sd_event_source_unref(event);
1061
1062         return r;
1063 }
1064
1065 static int dispatch_raw_source_event(sd_event_source *event,
1066                                      int fd,
1067                                      uint32_t revents,
1068                                      void *userdata) {
1069         RemoteSource *source = userdata;
1070         int r;
1071
1072         assert(source->event);
1073         assert(source->buffer_event);
1074
1075         r = handle_raw_source(event, fd, EPOLLIN, server);
1076         if (r == 1)
1077                 /* Might have more data. We need to rerun the handler
1078                  * until we are sure the buffer is exhausted. */
1079                 sd_event_source_set_enabled(source->buffer_event, SD_EVENT_ON);
1080
1081         return r;
1082 }
1083
1084 static int dispatch_blocking_source_event(sd_event_source *event,
1085                                           void *userdata) {
1086         RemoteSource *source = userdata;
1087
1088         return handle_raw_source(event, source->fd, EPOLLIN, server);
1089 }
1090
1091 static int accept_connection(const char* type, int fd,
1092                              SocketAddress *addr, char **hostname) {
1093         int fd2, r;
1094
1095         log_debug("Accepting new %s connection on fd:%d", type, fd);
1096         fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1097         if (fd2 < 0)
1098                 return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
1099
1100         switch(socket_address_family(addr)) {
1101         case AF_INET:
1102         case AF_INET6: {
1103                 _cleanup_free_ char *a = NULL;
1104                 char *b;
1105
1106                 r = socket_address_print(addr, &a);
1107                 if (r < 0) {
1108                         log_error_errno(r, "socket_address_print(): %m");
1109                         close(fd2);
1110                         return r;
1111                 }
1112
1113                 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1114                 if (r < 0) {
1115                         close(fd2);
1116                         return r;
1117                 }
1118
1119                 log_debug("Accepted %s %s connection from %s",
1120                           type,
1121                           socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1122                           a);
1123
1124                 *hostname = b;
1125
1126                 return fd2;
1127         };
1128         default:
1129                 log_error("Rejected %s connection with unsupported family %d",
1130                           type, socket_address_family(addr));
1131                 close(fd2);
1132
1133                 return -EINVAL;
1134         }
1135 }
1136
1137 static int dispatch_raw_connection_event(sd_event_source *event,
1138                                          int fd,
1139                                          uint32_t revents,
1140                                          void *userdata) {
1141         RemoteServer *s = userdata;
1142         int fd2;
1143         SocketAddress addr = {
1144                 .size = sizeof(union sockaddr_union),
1145                 .type = SOCK_STREAM,
1146         };
1147         char *hostname;
1148
1149         fd2 = accept_connection("raw", fd, &addr, &hostname);
1150         if (fd2 < 0)
1151                 return fd2;
1152
1153         return add_source(s, fd2, hostname, true);
1154 }
1155
1156 /**********************************************************************
1157  **********************************************************************
1158  **********************************************************************/
1159
1160 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1161         [JOURNAL_WRITE_SPLIT_NONE] = "none",
1162         [JOURNAL_WRITE_SPLIT_HOST] = "host",
1163 };
1164
1165 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1166 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1167                                 journal_write_split_mode,
1168                                 JournalWriteSplitMode,
1169                                 "Failed to parse split mode setting");
1170
1171 static int parse_config(void) {
1172         const ConfigTableItem items[] = {
1173                 { "Remote",  "SplitMode",              config_parse_write_split_mode, 0, &arg_split_mode },
1174                 { "Remote",  "ServerKeyFile",          config_parse_path,             0, &arg_key        },
1175                 { "Remote",  "ServerCertificateFile",  config_parse_path,             0, &arg_cert       },
1176                 { "Remote",  "TrustedCertificateFile", config_parse_path,             0, &arg_trust      },
1177                 {}};
1178
1179         return config_parse_many(PKGSYSCONFDIR "/journal-remote.conf",
1180                                  CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
1181                                  "Remote\0", config_item_table_lookup, items,
1182                                  false, NULL);
1183 }
1184
1185 static void help(void) {
1186         printf("%s [OPTIONS...] {FILE|-}...\n\n"
1187                "Write external journal events to journal file(s).\n\n"
1188                "  -h --help                 Show this help\n"
1189                "     --version              Show package version\n"
1190                "     --url=URL              Read events from systemd-journal-gatewayd at URL\n"
1191                "     --getter=COMMAND       Read events from the output of COMMAND\n"
1192                "     --listen-raw=ADDR      Listen for connections at ADDR\n"
1193                "     --listen-http=ADDR     Listen for HTTP connections at ADDR\n"
1194                "     --listen-https=ADDR    Listen for HTTPS connections at ADDR\n"
1195                "  -o --output=FILE|DIR      Write output to FILE or DIR/external-*.journal\n"
1196                "     --compress[=BOOL]      XZ-compress the output journal (default: yes)\n"
1197                "     --seal[=BOOL]          Use event sealing (default: no)\n"
1198                "     --key=FILENAME         SSL key in PEM format (default:\n"
1199                "                            \"" PRIV_KEY_FILE "\")\n"
1200                "     --cert=FILENAME        SSL certificate in PEM format (default:\n"
1201                "                            \"" CERT_FILE "\")\n"
1202                "     --trust=FILENAME|all   SSL CA certificate or disable checking (default:\n"
1203                "                            \"" TRUST_FILE "\")\n"
1204                "     --gnutls-log=CATEGORY...\n"
1205                "                            Specify a list of gnutls logging categories\n"
1206                "     --split-mode=none|host How many output files to create\n"
1207                "\n"
1208                "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1209                , program_invocation_short_name);
1210 }
1211
1212 static int parse_argv(int argc, char *argv[]) {
1213         enum {
1214                 ARG_VERSION = 0x100,
1215                 ARG_URL,
1216                 ARG_LISTEN_RAW,
1217                 ARG_LISTEN_HTTP,
1218                 ARG_LISTEN_HTTPS,
1219                 ARG_GETTER,
1220                 ARG_SPLIT_MODE,
1221                 ARG_COMPRESS,
1222                 ARG_SEAL,
1223                 ARG_KEY,
1224                 ARG_CERT,
1225                 ARG_TRUST,
1226                 ARG_GNUTLS_LOG,
1227         };
1228
1229         static const struct option options[] = {
1230                 { "help",         no_argument,       NULL, 'h'              },
1231                 { "version",      no_argument,       NULL, ARG_VERSION      },
1232                 { "url",          required_argument, NULL, ARG_URL          },
1233                 { "getter",       required_argument, NULL, ARG_GETTER       },
1234                 { "listen-raw",   required_argument, NULL, ARG_LISTEN_RAW   },
1235                 { "listen-http",  required_argument, NULL, ARG_LISTEN_HTTP  },
1236                 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1237                 { "output",       required_argument, NULL, 'o'              },
1238                 { "split-mode",   required_argument, NULL, ARG_SPLIT_MODE   },
1239                 { "compress",     optional_argument, NULL, ARG_COMPRESS     },
1240                 { "seal",         optional_argument, NULL, ARG_SEAL         },
1241                 { "key",          required_argument, NULL, ARG_KEY          },
1242                 { "cert",         required_argument, NULL, ARG_CERT         },
1243                 { "trust",        required_argument, NULL, ARG_TRUST        },
1244                 { "gnutls-log",   required_argument, NULL, ARG_GNUTLS_LOG   },
1245                 {}
1246         };
1247
1248         int c, r;
1249         bool type_a, type_b;
1250
1251         assert(argc >= 0);
1252         assert(argv);
1253
1254         while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1255                 switch(c) {
1256                 case 'h':
1257                         help();
1258                         return 0 /* done */;
1259
1260                 case ARG_VERSION:
1261                         puts(PACKAGE_STRING);
1262                         puts(SYSTEMD_FEATURES);
1263                         return 0 /* done */;
1264
1265                 case ARG_URL:
1266                         if (arg_url) {
1267                                 log_error("cannot currently set more than one --url");
1268                                 return -EINVAL;
1269                         }
1270
1271                         arg_url = optarg;
1272                         break;
1273
1274                 case ARG_GETTER:
1275                         if (arg_getter) {
1276                                 log_error("cannot currently use --getter more than once");
1277                                 return -EINVAL;
1278                         }
1279
1280                         arg_getter = optarg;
1281                         break;
1282
1283                 case ARG_LISTEN_RAW:
1284                         if (arg_listen_raw) {
1285                                 log_error("cannot currently use --listen-raw more than once");
1286                                 return -EINVAL;
1287                         }
1288
1289                         arg_listen_raw = optarg;
1290                         break;
1291
1292                 case ARG_LISTEN_HTTP:
1293                         if (arg_listen_http || http_socket >= 0) {
1294                                 log_error("cannot currently use --listen-http more than once");
1295                                 return -EINVAL;
1296                         }
1297
1298                         r = negative_fd(optarg);
1299                         if (r >= 0)
1300                                 http_socket = r;
1301                         else
1302                                 arg_listen_http = optarg;
1303                         break;
1304
1305                 case ARG_LISTEN_HTTPS:
1306                         if (arg_listen_https || https_socket >= 0) {
1307                                 log_error("cannot currently use --listen-https more than once");
1308                                 return -EINVAL;
1309                         }
1310
1311                         r = negative_fd(optarg);
1312                         if (r >= 0)
1313                                 https_socket = r;
1314                         else
1315                                 arg_listen_https = optarg;
1316
1317                         break;
1318
1319                 case ARG_KEY:
1320                         if (arg_key) {
1321                                 log_error("Key file specified twice");
1322                                 return -EINVAL;
1323                         }
1324
1325                         arg_key = strdup(optarg);
1326                         if (!arg_key)
1327                                 return log_oom();
1328
1329                         break;
1330
1331                 case ARG_CERT:
1332                         if (arg_cert) {
1333                                 log_error("Certificate file specified twice");
1334                                 return -EINVAL;
1335                         }
1336
1337                         arg_cert = strdup(optarg);
1338                         if (!arg_cert)
1339                                 return log_oom();
1340
1341                         break;
1342
1343                 case ARG_TRUST:
1344                         if (arg_trust || arg_trust_all) {
1345                                 log_error("Confusing trusted CA configuration");
1346                                 return -EINVAL;
1347                         }
1348
1349                         if (streq(optarg, "all"))
1350                                 arg_trust_all = true;
1351                         else {
1352 #ifdef HAVE_GNUTLS
1353                                 arg_trust = strdup(optarg);
1354                                 if (!arg_trust)
1355                                         return log_oom();
1356 #else
1357                                 log_error("Option --trust is not available.");
1358                                 return -EINVAL;
1359 #endif
1360                         }
1361
1362                         break;
1363
1364                 case 'o':
1365                         if (arg_output) {
1366                                 log_error("cannot use --output/-o more than once");
1367                                 return -EINVAL;
1368                         }
1369
1370                         arg_output = optarg;
1371                         break;
1372
1373                 case ARG_SPLIT_MODE:
1374                         arg_split_mode = journal_write_split_mode_from_string(optarg);
1375                         if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1376                                 log_error("Invalid split mode: %s", optarg);
1377                                 return -EINVAL;
1378                         }
1379                         break;
1380
1381                 case ARG_COMPRESS:
1382                         if (optarg) {
1383                                 r = parse_boolean(optarg);
1384                                 if (r < 0) {
1385                                         log_error("Failed to parse --compress= parameter.");
1386                                         return -EINVAL;
1387                                 }
1388
1389                                 arg_compress = !!r;
1390                         } else
1391                                 arg_compress = true;
1392
1393                         break;
1394
1395                 case ARG_SEAL:
1396                         if (optarg) {
1397                                 r = parse_boolean(optarg);
1398                                 if (r < 0) {
1399                                         log_error("Failed to parse --seal= parameter.");
1400                                         return -EINVAL;
1401                                 }
1402
1403                                 arg_seal = !!r;
1404                         } else
1405                                 arg_seal = true;
1406
1407                         break;
1408
1409                 case ARG_GNUTLS_LOG: {
1410 #ifdef HAVE_GNUTLS
1411                         const char *word, *state;
1412                         size_t size;
1413
1414                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1415                                 char *cat;
1416
1417                                 cat = strndup(word, size);
1418                                 if (!cat)
1419                                         return log_oom();
1420
1421                                 if (strv_consume(&arg_gnutls_log, cat) < 0)
1422                                         return log_oom();
1423                         }
1424                         break;
1425 #else
1426                         log_error("Option --gnutls-log is not available.");
1427                         return -EINVAL;
1428 #endif
1429                 }
1430
1431                 case '?':
1432                         return -EINVAL;
1433
1434                 default:
1435                         assert_not_reached("Unknown option code.");
1436                 }
1437
1438         if (optind < argc)
1439                 arg_files = argv + optind;
1440
1441         type_a = arg_getter || !strv_isempty(arg_files);
1442         type_b = arg_url
1443                 || arg_listen_raw
1444                 || arg_listen_http || arg_listen_https
1445                 || sd_listen_fds(false) > 0;
1446         if (type_a && type_b) {
1447                 log_error("Cannot use file input or --getter with "
1448                           "--arg-listen-... or socket activation.");
1449                 return -EINVAL;
1450         }
1451         if (type_a) {
1452                 if (!arg_output) {
1453                         log_error("Option --output must be specified with file input or --getter.");
1454                         return -EINVAL;
1455                 }
1456
1457                 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1458         }
1459
1460         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1461             && arg_output && is_dir(arg_output, true) > 0) {
1462                 log_error("For SplitMode=none, output must be a file.");
1463                 return -EINVAL;
1464         }
1465
1466         if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1467             && arg_output && is_dir(arg_output, true) <= 0) {
1468                 log_error("For SplitMode=host, output must be a directory.");
1469                 return -EINVAL;
1470         }
1471
1472         log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1473                   journal_write_split_mode_to_string(arg_split_mode),
1474                   strna(arg_key),
1475                   strna(arg_cert),
1476                   strna(arg_trust));
1477
1478         return 1 /* work to do */;
1479 }
1480
1481 static int load_certificates(char **key, char **cert, char **trust) {
1482         int r;
1483
1484         r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1485         if (r < 0)
1486                 return log_error_errno(r, "Failed to read key from file '%s': %m",
1487                                        arg_key ?: PRIV_KEY_FILE);
1488
1489         r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1490         if (r < 0)
1491                 return log_error_errno(r, "Failed to read certificate from file '%s': %m",
1492                                        arg_cert ?: CERT_FILE);
1493
1494         if (arg_trust_all)
1495                 log_info("Certificate checking disabled.");
1496         else {
1497                 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1498                 if (r < 0)
1499                         return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
1500                                                arg_trust ?: TRUST_FILE);
1501         }
1502
1503         return 0;
1504 }
1505
1506 static int setup_gnutls_logger(char **categories) {
1507         if (!arg_listen_http && !arg_listen_https)
1508                 return 0;
1509
1510 #ifdef HAVE_GNUTLS
1511         {
1512                 char **cat;
1513                 int r;
1514
1515                 gnutls_global_set_log_function(log_func_gnutls);
1516
1517                 if (categories) {
1518                         STRV_FOREACH(cat, categories) {
1519                                 r = log_enable_gnutls_category(*cat);
1520                                 if (r < 0)
1521                                         return r;
1522                         }
1523                 } else
1524                         log_reset_gnutls_level();
1525         }
1526 #endif
1527
1528         return 0;
1529 }
1530
1531 int main(int argc, char **argv) {
1532         RemoteServer s = {};
1533         int r;
1534         _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1535
1536         log_show_color(true);
1537         log_parse_environment();
1538
1539         r = parse_config();
1540         if (r < 0)
1541                 return EXIT_FAILURE;
1542
1543         r = parse_argv(argc, argv);
1544         if (r <= 0)
1545                 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1546
1547         r = setup_gnutls_logger(arg_gnutls_log);
1548         if (r < 0)
1549                 return EXIT_FAILURE;
1550
1551         if (arg_listen_https || https_socket >= 0)
1552                 if (load_certificates(&key, &cert, &trust) < 0)
1553                         return EXIT_FAILURE;
1554
1555         if (remoteserver_init(&s, key, cert, trust) < 0)
1556                 return EXIT_FAILURE;
1557
1558         r = sd_event_set_watchdog(s.events, true);
1559         if (r < 0)
1560                 log_error_errno(r, "Failed to enable watchdog: %m");
1561         else
1562                 log_debug("Watchdog is %s.", r > 0 ? "enabled" : "disabled");
1563
1564         log_debug("%s running as pid "PID_FMT,
1565                   program_invocation_short_name, getpid());
1566         sd_notify(false,
1567                   "READY=1\n"
1568                   "STATUS=Processing requests...");
1569
1570         while (s.active) {
1571                 r = sd_event_get_state(s.events);
1572                 if (r < 0)
1573                         break;
1574                 if (r == SD_EVENT_FINISHED)
1575                         break;
1576
1577                 r = sd_event_run(s.events, -1);
1578                 if (r < 0) {
1579                         log_error_errno(r, "Failed to run event loop: %m");
1580                         break;
1581                 }
1582         }
1583
1584         sd_notifyf(false,
1585                    "STOPPING=1\n"
1586                    "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1587         log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1588
1589         server_destroy(&s);
1590
1591         free(arg_key);
1592         free(arg_cert);
1593         free(arg_trust);
1594
1595         return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1596 }