chiark / gitweb /
logind: remove spurious include of <sys/capability.h>
[elogind.git] / src / journal-remote / journal-upload.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 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 <stdio.h>
23 #include <curl/curl.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <getopt.h>
27
28 #include "sd-daemon.h"
29
30 #include "log.h"
31 #include "util.h"
32 #include "build.h"
33 #include "fileio.h"
34 #include "mkdir.h"
35 #include "conf-parser.h"
36 #include "journal-upload.h"
37
38 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-upload.pem"
39 #define CERT_FILE     CERTIFICATE_ROOT "/certs/journal-upload.pem"
40 #define TRUST_FILE    CERTIFICATE_ROOT "/ca/trusted.pem"
41 #define DEFAULT_PORT  19532
42
43 static const char* arg_url;
44
45 static void close_fd_input(Uploader *u);
46
47 static const char *arg_key = NULL;
48 static const char *arg_cert = NULL;
49 static const char *arg_trust = NULL;
50
51 static const char *arg_directory = NULL;
52 static char **arg_file = NULL;
53 static const char *arg_cursor = NULL;
54 static bool arg_after_cursor = false;
55 static int arg_journal_type = 0;
56 static const char *arg_machine = NULL;
57 static bool arg_merge = false;
58 static int arg_follow = -1;
59 static const char *arg_save_state = NULL;
60
61 #define SERVER_ANSWER_KEEP 2048
62
63 #define STATE_FILE "/var/lib/systemd/journal-upload/state"
64
65 #define easy_setopt(curl, opt, value, level, cmd)                       \
66         do {                                                            \
67                 code = curl_easy_setopt(curl, opt, value);              \
68                 if (code) {                                             \
69                         log_full(level,                                 \
70                                  "curl_easy_setopt " #opt " failed: %s", \
71                                   curl_easy_strerror(code));            \
72                         cmd;                                            \
73                 }                                                       \
74         } while(0)
75
76 static size_t output_callback(char *buf,
77                               size_t size,
78                               size_t nmemb,
79                               void *userp) {
80         Uploader *u = userp;
81
82         assert(u);
83
84         log_debug("The server answers (%zu bytes): %.*s",
85                   size*nmemb, (int)(size*nmemb), buf);
86
87         if (nmemb && !u->answer) {
88                 u->answer = strndup(buf, size*nmemb);
89                 if (!u->answer)
90                         log_warning_errno(ENOMEM, "Failed to store server answer (%zu bytes): %m",
91                                           size*nmemb);
92         }
93
94         return size * nmemb;
95 }
96
97 static int check_cursor_updating(Uploader *u) {
98         _cleanup_free_ char *temp_path = NULL;
99         _cleanup_fclose_ FILE *f = NULL;
100         int r;
101
102         if (!u->state_file)
103                 return 0;
104
105         r = mkdir_parents(u->state_file, 0755);
106         if (r < 0)
107                 return log_error_errno(r, "Cannot create parent directory of state file %s: %m",
108                                        u->state_file);
109
110         r = fopen_temporary(u->state_file, &f, &temp_path);
111         if (r < 0)
112                 return log_error_errno(r, "Cannot save state to %s: %m",
113                                        u->state_file);
114         unlink(temp_path);
115
116         return 0;
117 }
118
119 static int update_cursor_state(Uploader *u) {
120         _cleanup_free_ char *temp_path = NULL;
121         _cleanup_fclose_ FILE *f = NULL;
122         int r;
123
124         if (!u->state_file || !u->last_cursor)
125                 return 0;
126
127         r = fopen_temporary(u->state_file, &f, &temp_path);
128         if (r < 0)
129                 goto finish;
130
131         fprintf(f,
132                 "# This is private data. Do not parse.\n"
133                 "LAST_CURSOR=%s\n",
134                 u->last_cursor);
135
136         fflush(f);
137
138         if (ferror(f) || rename(temp_path, u->state_file) < 0) {
139                 r = -errno;
140                 unlink(u->state_file);
141                 unlink(temp_path);
142         }
143
144 finish:
145         if (r < 0)
146                 log_error_errno(r, "Failed to save state %s: %m", u->state_file);
147
148         return r;
149 }
150
151 static int load_cursor_state(Uploader *u) {
152         int r;
153
154         if (!u->state_file)
155                 return 0;
156
157         r = parse_env_file(u->state_file, NEWLINE,
158                            "LAST_CURSOR",  &u->last_cursor,
159                            NULL);
160
161         if (r == -ENOENT)
162                 log_debug("State file %s is not present.", u->state_file);
163         else if (r < 0)
164                 return log_error_errno(r, "Failed to read state file %s: %m",
165                                        u->state_file);
166         else
167                 log_debug("Last cursor was %s", u->last_cursor);
168
169         return 0;
170 }
171
172
173
174 int start_upload(Uploader *u,
175                  size_t (*input_callback)(void *ptr,
176                                           size_t size,
177                                           size_t nmemb,
178                                           void *userdata),
179                  void *data) {
180         CURLcode code;
181
182         assert(u);
183         assert(input_callback);
184
185         if (!u->header) {
186                 struct curl_slist *h;
187
188                 h = curl_slist_append(NULL, "Content-Type: application/vnd.fdo.journal");
189                 if (!h)
190                         return log_oom();
191
192                 h = curl_slist_append(h, "Transfer-Encoding: chunked");
193                 if (!h) {
194                         curl_slist_free_all(h);
195                         return log_oom();
196                 }
197
198                 h = curl_slist_append(h, "Accept: text/plain");
199                 if (!h) {
200                         curl_slist_free_all(h);
201                         return log_oom();
202                 }
203
204                 u->header = h;
205         }
206
207         if (!u->easy) {
208                 CURL *curl;
209
210                 curl = curl_easy_init();
211                 if (!curl) {
212                         log_error("Call to curl_easy_init failed.");
213                         return -ENOSR;
214                 }
215
216                 /* tell it to POST to the URL */
217                 easy_setopt(curl, CURLOPT_POST, 1L,
218                             LOG_ERR, return -EXFULL);
219
220                 easy_setopt(curl, CURLOPT_ERRORBUFFER, u->error,
221                             LOG_ERR, return -EXFULL);
222
223                 /* set where to write to */
224                 easy_setopt(curl, CURLOPT_WRITEFUNCTION, output_callback,
225                             LOG_ERR, return -EXFULL);
226
227                 easy_setopt(curl, CURLOPT_WRITEDATA, data,
228                             LOG_ERR, return -EXFULL);
229
230                 /* set where to read from */
231                 easy_setopt(curl, CURLOPT_READFUNCTION, input_callback,
232                             LOG_ERR, return -EXFULL);
233
234                 easy_setopt(curl, CURLOPT_READDATA, data,
235                             LOG_ERR, return -EXFULL);
236
237                 /* use our special own mime type and chunked transfer */
238                 easy_setopt(curl, CURLOPT_HTTPHEADER, u->header,
239                             LOG_ERR, return -EXFULL);
240
241                 /* enable verbose for easier tracing */
242                 easy_setopt(curl, CURLOPT_VERBOSE, 1L, LOG_WARNING, );
243
244                 easy_setopt(curl, CURLOPT_USERAGENT,
245                             "systemd-journal-upload " PACKAGE_STRING,
246                             LOG_WARNING, );
247
248                 if (arg_key || startswith(u->url, "https://")) {
249                         easy_setopt(curl, CURLOPT_SSLKEY, arg_key ?: PRIV_KEY_FILE,
250                                     LOG_ERR, return -EXFULL);
251                         easy_setopt(curl, CURLOPT_SSLCERT, arg_cert ?: CERT_FILE,
252                                     LOG_ERR, return -EXFULL);
253                 }
254
255                 if (streq_ptr(arg_trust, "all"))
256                         easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0,
257                                     LOG_ERR, return -EUCLEAN);
258                 else if (arg_trust || startswith(u->url, "https://"))
259                         easy_setopt(curl, CURLOPT_CAINFO, arg_trust ?: TRUST_FILE,
260                                     LOG_ERR, return -EXFULL);
261
262                 if (arg_key || arg_trust)
263                         easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1,
264                                     LOG_WARNING, );
265
266                 u->easy = curl;
267         } else {
268                 /* truncate the potential old error message */
269                 u->error[0] = '\0';
270
271                 free(u->answer);
272                 u->answer = 0;
273         }
274
275         /* upload to this place */
276         code = curl_easy_setopt(u->easy, CURLOPT_URL, u->url);
277         if (code) {
278                 log_error("curl_easy_setopt CURLOPT_URL failed: %s",
279                           curl_easy_strerror(code));
280                 return -EXFULL;
281         }
282
283         u->uploading = true;
284
285         return 0;
286 }
287
288 static size_t fd_input_callback(void *buf, size_t size, size_t nmemb, void *userp) {
289         Uploader *u = userp;
290
291         ssize_t r;
292
293         assert(u);
294         assert(nmemb <= SSIZE_MAX / size);
295
296         if (u->input < 0)
297                 return 0;
298
299         r = read(u->input, buf, size * nmemb);
300         log_debug("%s: allowed %zu, read %zu", __func__, size*nmemb, r);
301
302         if (r > 0)
303                 return r;
304
305         u->uploading = false;
306         if (r == 0) {
307                 log_debug("Reached EOF");
308                 close_fd_input(u);
309                 return 0;
310         } else {
311                 log_error_errno(errno, "Aborting transfer after read error on input: %m.");
312                 return CURL_READFUNC_ABORT;
313         }
314 }
315
316 static void close_fd_input(Uploader *u) {
317         assert(u);
318
319         if (u->input >= 0)
320                 close_nointr(u->input);
321         u->input = -1;
322         u->timeout = 0;
323 }
324
325 static int dispatch_fd_input(sd_event_source *event,
326                              int fd,
327                              uint32_t revents,
328                              void *userp) {
329         Uploader *u = userp;
330
331         assert(u);
332         assert(fd >= 0);
333
334         if (revents & EPOLLHUP) {
335                 log_debug("Received HUP");
336                 close_fd_input(u);
337                 return 0;
338         }
339
340         if (!(revents & EPOLLIN)) {
341                 log_warning("Unexpected poll event %"PRIu32".", revents);
342                 return -EINVAL;
343         }
344
345         if (u->uploading) {
346                 log_warning("dispatch_fd_input called when uploading, ignoring.");
347                 return 0;
348         }
349
350         return start_upload(u, fd_input_callback, u);
351 }
352
353 static int open_file_for_upload(Uploader *u, const char *filename) {
354         int fd, r = 0;
355
356         if (streq(filename, "-"))
357                 fd = STDIN_FILENO;
358         else {
359                 fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
360                 if (fd < 0)
361                         return log_error_errno(errno, "Failed to open %s: %m", filename);
362         }
363
364         u->input = fd;
365
366         if (arg_follow) {
367                 r = sd_event_add_io(u->events, &u->input_event,
368                                     fd, EPOLLIN, dispatch_fd_input, u);
369                 if (r < 0) {
370                         if (r != -EPERM || arg_follow > 0)
371                                 return log_error_errno(r, "Failed to register input event: %m");
372
373                         /* Normal files should just be consumed without polling. */
374                         r = start_upload(u, fd_input_callback, u);
375                 }
376         }
377
378         return r;
379 }
380
381 static int dispatch_sigterm(sd_event_source *event,
382                             const struct signalfd_siginfo *si,
383                             void *userdata) {
384         Uploader *u = userdata;
385
386         assert(u);
387
388         log_received_signal(LOG_INFO, si);
389
390         close_fd_input(u);
391         close_journal_input(u);
392
393         sd_event_exit(u->events, 0);
394         return 0;
395 }
396
397 static int setup_signals(Uploader *u) {
398         sigset_t mask;
399         int r;
400
401         assert(u);
402
403         assert_se(sigemptyset(&mask) == 0);
404         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
405         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
406
407         r = sd_event_add_signal(u->events, &u->sigterm_event, SIGTERM, dispatch_sigterm, u);
408         if (r < 0)
409                 return r;
410
411         r = sd_event_add_signal(u->events, &u->sigint_event, SIGINT, dispatch_sigterm, u);
412         if (r < 0)
413                 return r;
414
415         return 0;
416 }
417
418 static int setup_uploader(Uploader *u, const char *url, const char *state_file) {
419         int r;
420         const char *host, *proto = "";
421
422         assert(u);
423         assert(url);
424
425         memzero(u, sizeof(Uploader));
426         u->input = -1;
427
428         if (!(host = startswith(url, "http://")) && !(host = startswith(url, "https://"))) {
429                 host = url;
430                 proto = "https://";
431         }
432
433         if (strchr(host, ':'))
434                 u->url = strjoin(proto, url, "/upload", NULL);
435         else {
436                 char *t;
437                 size_t x;
438
439                 t = strdupa(url);
440                 x = strlen(t);
441                 while (x > 0 && t[x - 1] == '/')
442                         t[x - 1] = '\0';
443
444                 u->url = strjoin(proto, t, ":" STRINGIFY(DEFAULT_PORT), "/upload", NULL);
445         }
446         if (!u->url)
447                 return log_oom();
448
449         u->state_file = state_file;
450
451         r = sd_event_default(&u->events);
452         if (r < 0)
453                 return log_error_errno(r, "sd_event_default failed: %m");
454
455         r = setup_signals(u);
456         if (r < 0)
457                 return log_error_errno(r, "Failed to set up signals: %m");
458
459         return load_cursor_state(u);
460 }
461
462 static void destroy_uploader(Uploader *u) {
463         assert(u);
464
465         curl_easy_cleanup(u->easy);
466         curl_slist_free_all(u->header);
467         free(u->answer);
468
469         free(u->last_cursor);
470         free(u->current_cursor);
471
472         free(u->url);
473
474         u->input_event = sd_event_source_unref(u->input_event);
475
476         close_fd_input(u);
477         close_journal_input(u);
478
479         sd_event_source_unref(u->sigterm_event);
480         sd_event_source_unref(u->sigint_event);
481         sd_event_unref(u->events);
482 }
483
484 static int perform_upload(Uploader *u) {
485         CURLcode code;
486         long status;
487
488         assert(u);
489
490         code = curl_easy_perform(u->easy);
491         if (code) {
492                 if (u->error[0])
493                         log_error("Upload to %s failed: %.*s",
494                                   u->url, (int) sizeof(u->error), u->error);
495                 else
496                         log_error("Upload to %s failed: %s",
497                                   u->url, curl_easy_strerror(code));
498                 return -EIO;
499         }
500
501         code = curl_easy_getinfo(u->easy, CURLINFO_RESPONSE_CODE, &status);
502         if (code) {
503                 log_error("Failed to retrieve response code: %s",
504                           curl_easy_strerror(code));
505                 return -EUCLEAN;
506         }
507
508         if (status >= 300) {
509                 log_error("Upload to %s failed with code %lu: %s",
510                           u->url, status, strna(u->answer));
511                 return -EIO;
512         } else if (status < 200) {
513                 log_error("Upload to %s finished with unexpected code %lu: %s",
514                           u->url, status, strna(u->answer));
515                 return -EIO;
516         } else
517                 log_debug("Upload finished successfully with code %lu: %s",
518                           status, strna(u->answer));
519
520         free(u->last_cursor);
521         u->last_cursor = u->current_cursor;
522         u->current_cursor = NULL;
523
524         return update_cursor_state(u);
525 }
526
527 static int parse_config(void) {
528         const ConfigTableItem items[] = {
529                 { "Upload",  "URL",                    config_parse_string, 0, &arg_url    },
530                 { "Upload",  "ServerKeyFile",          config_parse_path,   0, &arg_key    },
531                 { "Upload",  "ServerCertificateFile",  config_parse_path,   0, &arg_cert   },
532                 { "Upload",  "TrustedCertificateFile", config_parse_path,   0, &arg_trust  },
533                 {}};
534
535         return config_parse_many(PKGSYSCONFDIR "/journal-upload.conf",
536                                  CONF_DIRS_NULSTR("systemd/journal-upload.conf"),
537                                  "Upload\0", config_item_table_lookup, items,
538                                  false, NULL);
539 }
540
541 static void help(void) {
542         printf("%s -u URL {FILE|-}...\n\n"
543                "Upload journal events to a remote server.\n\n"
544                "  -h --help                 Show this help\n"
545                "     --version              Show package version\n"
546                "  -u --url=URL              Upload to this address (default port "
547                                             STRINGIFY(DEFAULT_PORT) ")\n"
548                "     --key=FILENAME         Specify key in PEM format (default:\n"
549                "                            \"" PRIV_KEY_FILE "\")\n"
550                "     --cert=FILENAME        Specify certificate in PEM format (default:\n"
551                "                            \"" CERT_FILE "\")\n"
552                "     --trust=FILENAME|all   Specify CA certificate or disable checking (default:\n"
553                "                            \"" TRUST_FILE "\")\n"
554                "     --system               Use the system journal\n"
555                "     --user                 Use the user journal for the current user\n"
556                "  -m --merge                Use  all available journals\n"
557                "  -M --machine=CONTAINER    Operate on local container\n"
558                "  -D --directory=PATH       Use journal files from directory\n"
559                "     --file=PATH            Use this journal file\n"
560                "     --cursor=CURSOR        Start at the specified cursor\n"
561                "     --after-cursor=CURSOR  Start after the specified cursor\n"
562                "     --follow[=BOOL]        Do [not] wait for input\n"
563                "     --save-state[=FILE]    Save uploaded cursors (default \n"
564                "                            " STATE_FILE ")\n"
565                "  -h --help                 Show this help and exit\n"
566                "     --version              Print version string and exit\n"
567                , program_invocation_short_name);
568 }
569
570 static int parse_argv(int argc, char *argv[]) {
571         enum {
572                 ARG_VERSION = 0x100,
573                 ARG_KEY,
574                 ARG_CERT,
575                 ARG_TRUST,
576                 ARG_USER,
577                 ARG_SYSTEM,
578                 ARG_FILE,
579                 ARG_CURSOR,
580                 ARG_AFTER_CURSOR,
581                 ARG_FOLLOW,
582                 ARG_SAVE_STATE,
583         };
584
585         static const struct option options[] = {
586                 { "help",         no_argument,       NULL, 'h'                },
587                 { "version",      no_argument,       NULL, ARG_VERSION        },
588                 { "url",          required_argument, NULL, 'u'                },
589                 { "key",          required_argument, NULL, ARG_KEY            },
590                 { "cert",         required_argument, NULL, ARG_CERT           },
591                 { "trust",        required_argument, NULL, ARG_TRUST          },
592                 { "system",       no_argument,       NULL, ARG_SYSTEM         },
593                 { "user",         no_argument,       NULL, ARG_USER           },
594                 { "merge",        no_argument,       NULL, 'm'                },
595                 { "machine",      required_argument, NULL, 'M'                },
596                 { "directory",    required_argument, NULL, 'D'                },
597                 { "file",         required_argument, NULL, ARG_FILE           },
598                 { "cursor",       required_argument, NULL, ARG_CURSOR         },
599                 { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR   },
600                 { "follow",       optional_argument, NULL, ARG_FOLLOW         },
601                 { "save-state",   optional_argument, NULL, ARG_SAVE_STATE     },
602                 {}
603         };
604
605         int c, r;
606
607         assert(argc >= 0);
608         assert(argv);
609
610         opterr = 0;
611
612         while ((c = getopt_long(argc, argv, "hu:mM:D:", options, NULL)) >= 0)
613                 switch(c) {
614                 case 'h':
615                         help();
616                         return 0 /* done */;
617
618                 case ARG_VERSION:
619                         puts(PACKAGE_STRING);
620                         puts(SYSTEMD_FEATURES);
621                         return 0 /* done */;
622
623                 case 'u':
624                         if (arg_url) {
625                                 log_error("cannot use more than one --url");
626                                 return -EINVAL;
627                         }
628
629                         arg_url = optarg;
630                         break;
631
632                 case ARG_KEY:
633                         if (arg_key) {
634                                 log_error("cannot use more than one --key");
635                                 return -EINVAL;
636                         }
637
638                         arg_key = optarg;
639                         break;
640
641                 case ARG_CERT:
642                         if (arg_cert) {
643                                 log_error("cannot use more than one --cert");
644                                 return -EINVAL;
645                         }
646
647                         arg_cert = optarg;
648                         break;
649
650                 case ARG_TRUST:
651                         if (arg_trust) {
652                                 log_error("cannot use more than one --trust");
653                                 return -EINVAL;
654                         }
655
656                         arg_trust = optarg;
657                         break;
658
659                 case ARG_SYSTEM:
660                         arg_journal_type |= SD_JOURNAL_SYSTEM;
661                         break;
662
663                 case ARG_USER:
664                         arg_journal_type |= SD_JOURNAL_CURRENT_USER;
665                         break;
666
667                 case 'm':
668                         arg_merge = true;
669                         break;
670
671                 case 'M':
672                         if (arg_machine) {
673                                 log_error("cannot use more than one --machine/-M");
674                                 return -EINVAL;
675                         }
676
677                         arg_machine = optarg;
678                         break;
679
680                 case 'D':
681                         if (arg_directory) {
682                                 log_error("cannot use more than one --directory/-D");
683                                 return -EINVAL;
684                         }
685
686                         arg_directory = optarg;
687                         break;
688
689                 case ARG_FILE:
690                         r = glob_extend(&arg_file, optarg);
691                         if (r < 0)
692                                 return log_error_errno(r, "Failed to add paths: %m");
693                         break;
694
695                 case ARG_CURSOR:
696                         if (arg_cursor) {
697                                 log_error("cannot use more than one --cursor/--after-cursor");
698                                 return -EINVAL;
699                         }
700
701                         arg_cursor = optarg;
702                         break;
703
704                 case ARG_AFTER_CURSOR:
705                         if (arg_cursor) {
706                                 log_error("cannot use more than one --cursor/--after-cursor");
707                                 return -EINVAL;
708                         }
709
710                         arg_cursor = optarg;
711                         arg_after_cursor = true;
712                         break;
713
714                 case ARG_FOLLOW:
715                         if (optarg) {
716                                 r = parse_boolean(optarg);
717                                 if (r < 0) {
718                                         log_error("Failed to parse --follow= parameter.");
719                                         return -EINVAL;
720                                 }
721
722                                 arg_follow = !!r;
723                         } else
724                                 arg_follow = true;
725
726                         break;
727
728                 case ARG_SAVE_STATE:
729                         arg_save_state = optarg ?: STATE_FILE;
730                         break;
731
732                 case '?':
733                         log_error("Unknown option %s.", argv[optind-1]);
734                         return -EINVAL;
735
736                 case ':':
737                         log_error("Missing argument to %s.", argv[optind-1]);
738                         return -EINVAL;
739
740                 default:
741                         assert_not_reached("Unhandled option code.");
742                 }
743
744         if (!arg_url) {
745                 log_error("Required --url/-u option missing.");
746                 return -EINVAL;
747         }
748
749         if (!!arg_key != !!arg_cert) {
750                 log_error("Options --key and --cert must be used together.");
751                 return -EINVAL;
752         }
753
754         if (optind < argc && (arg_directory || arg_file || arg_machine || arg_journal_type)) {
755                 log_error("Input arguments make no sense with journal input.");
756                 return -EINVAL;
757         }
758
759         return 1;
760 }
761
762 static int open_journal(sd_journal **j) {
763         int r;
764
765         if (arg_directory)
766                 r = sd_journal_open_directory(j, arg_directory, arg_journal_type);
767         else if (arg_file)
768                 r = sd_journal_open_files(j, (const char**) arg_file, 0);
769         else if (arg_machine)
770                 r = sd_journal_open_container(j, arg_machine, 0);
771         else
772                 r = sd_journal_open(j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
773         if (r < 0)
774                 log_error_errno(r, "Failed to open %s: %m",
775                                 arg_directory ? arg_directory : arg_file ? "files" : "journal");
776         return r;
777 }
778
779 int main(int argc, char **argv) {
780         Uploader u;
781         int r;
782         bool use_journal;
783
784         log_show_color(true);
785         log_parse_environment();
786
787         r = parse_config();
788         if (r < 0)
789                 goto finish;
790
791         r = parse_argv(argc, argv);
792         if (r <= 0)
793                 goto finish;
794
795         r = setup_uploader(&u, arg_url, arg_save_state);
796         if (r < 0)
797                 goto cleanup;
798
799         sd_event_set_watchdog(u.events, true);
800
801         r = check_cursor_updating(&u);
802         if (r < 0)
803                 goto cleanup;
804
805         log_debug("%s running as pid "PID_FMT,
806                   program_invocation_short_name, getpid());
807
808         use_journal = optind >= argc;
809         if (use_journal) {
810                 sd_journal *j;
811                 r = open_journal(&j);
812                 if (r < 0)
813                         goto finish;
814                 r = open_journal_for_upload(&u, j,
815                                             arg_cursor ?: u.last_cursor,
816                                             arg_cursor ? arg_after_cursor : true,
817                                             !!arg_follow);
818                 if (r < 0)
819                         goto finish;
820         }
821
822         sd_notify(false,
823                   "READY=1\n"
824                   "STATUS=Processing input...");
825
826         while (true) {
827                 r = sd_event_get_state(u.events);
828                 if (r < 0)
829                         break;
830                 if (r == SD_EVENT_FINISHED)
831                         break;
832
833                 if (use_journal) {
834                         if (!u.journal)
835                                 break;
836
837                         r = check_journal_input(&u);
838                 } else if (u.input < 0 && !use_journal) {
839                         if (optind >= argc)
840                                 break;
841
842                         log_debug("Using %s as input.", argv[optind]);
843                         r = open_file_for_upload(&u, argv[optind++]);
844                 }
845                 if (r < 0)
846                         goto cleanup;
847
848                 if (u.uploading) {
849                         r = perform_upload(&u);
850                         if (r < 0)
851                                 break;
852                 }
853
854                 r = sd_event_run(u.events, u.timeout);
855                 if (r < 0) {
856                         log_error_errno(r, "Failed to run event loop: %m");
857                         break;
858                 }
859         }
860
861 cleanup:
862         sd_notify(false,
863                   "STOPPING=1\n"
864                   "STATUS=Shutting down...");
865
866         destroy_uploader(&u);
867
868 finish:
869         return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
870 }