chiark / gitweb /
treewide: simplify log_*_errno(r,...) immediately followed by "return r"
[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("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                         log_error("Failed to open %s: %m", filename);
362                         return -errno;
363                 }
364         }
365
366         u->input = fd;
367
368         if (arg_follow) {
369                 r = sd_event_add_io(u->events, &u->input_event,
370                                     fd, EPOLLIN, dispatch_fd_input, u);
371                 if (r < 0) {
372                         if (r != -EPERM || arg_follow > 0)
373                                 return log_error_errno(r, "Failed to register input event: %m");
374
375                         /* Normal files should just be consumed without polling. */
376                         r = start_upload(u, fd_input_callback, u);
377                 }
378         }
379
380         return r;
381 }
382
383 static int dispatch_sigterm(sd_event_source *event,
384                             const struct signalfd_siginfo *si,
385                             void *userdata) {
386         Uploader *u = userdata;
387
388         assert(u);
389
390         log_received_signal(LOG_INFO, si);
391
392         close_fd_input(u);
393         close_journal_input(u);
394
395         sd_event_exit(u->events, 0);
396         return 0;
397 }
398
399 static int setup_signals(Uploader *u) {
400         sigset_t mask;
401         int r;
402
403         assert(u);
404
405         assert_se(sigemptyset(&mask) == 0);
406         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
407         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
408
409         r = sd_event_add_signal(u->events, &u->sigterm_event, SIGTERM, dispatch_sigterm, u);
410         if (r < 0)
411                 return r;
412
413         r = sd_event_add_signal(u->events, &u->sigint_event, SIGINT, dispatch_sigterm, u);
414         if (r < 0)
415                 return r;
416
417         return 0;
418 }
419
420 static int setup_uploader(Uploader *u, const char *url, const char *state_file) {
421         int r;
422         const char *host, *proto = "";
423
424         assert(u);
425         assert(url);
426
427         memzero(u, sizeof(Uploader));
428         u->input = -1;
429
430         if (!(host = startswith(url, "http://")) && !(host = startswith(url, "https://"))) {
431                 host = url;
432                 proto = "https://";
433         }
434
435         if (strchr(host, ':'))
436                 u->url = strjoin(proto, url, "/upload", NULL);
437         else {
438                 char *t;
439                 size_t x;
440
441                 t = strdupa(url);
442                 x = strlen(t);
443                 while (x > 0 && t[x - 1] == '/')
444                         t[x - 1] = '\0';
445
446                 u->url = strjoin(proto, t, ":" STRINGIFY(DEFAULT_PORT), "/upload", NULL);
447         }
448         if (!u->url)
449                 return log_oom();
450
451         u->state_file = state_file;
452
453         r = sd_event_default(&u->events);
454         if (r < 0)
455                 return log_error_errno(r, "sd_event_default failed: %m");
456
457         r = setup_signals(u);
458         if (r < 0)
459                 return log_error_errno(r, "Failed to set up signals: %m");
460
461         return load_cursor_state(u);
462 }
463
464 static void destroy_uploader(Uploader *u) {
465         assert(u);
466
467         curl_easy_cleanup(u->easy);
468         curl_slist_free_all(u->header);
469         free(u->answer);
470
471         free(u->last_cursor);
472         free(u->current_cursor);
473
474         free(u->url);
475
476         u->input_event = sd_event_source_unref(u->input_event);
477
478         close_fd_input(u);
479         close_journal_input(u);
480
481         sd_event_source_unref(u->sigterm_event);
482         sd_event_source_unref(u->sigint_event);
483         sd_event_unref(u->events);
484 }
485
486 static int perform_upload(Uploader *u) {
487         CURLcode code;
488         long status;
489
490         assert(u);
491
492         code = curl_easy_perform(u->easy);
493         if (code) {
494                 if (u->error[0])
495                         log_error("Upload to %s failed: %.*s",
496                                   u->url, (int) sizeof(u->error), u->error);
497                 else
498                         log_error("Upload to %s failed: %s",
499                                   u->url, curl_easy_strerror(code));
500                 return -EIO;
501         }
502
503         code = curl_easy_getinfo(u->easy, CURLINFO_RESPONSE_CODE, &status);
504         if (code) {
505                 log_error("Failed to retrieve response code: %s",
506                           curl_easy_strerror(code));
507                 return -EUCLEAN;
508         }
509
510         if (status >= 300) {
511                 log_error("Upload to %s failed with code %lu: %s",
512                           u->url, status, strna(u->answer));
513                 return -EIO;
514         } else if (status < 200) {
515                 log_error("Upload to %s finished with unexpected code %lu: %s",
516                           u->url, status, strna(u->answer));
517                 return -EIO;
518         } else
519                 log_debug("Upload finished successfully with code %lu: %s",
520                           status, strna(u->answer));
521
522         free(u->last_cursor);
523         u->last_cursor = u->current_cursor;
524         u->current_cursor = NULL;
525
526         return update_cursor_state(u);
527 }
528
529 static int parse_config(void) {
530         const ConfigTableItem items[] = {
531                 { "Upload",  "URL",                    config_parse_string, 0, &arg_url    },
532                 { "Upload",  "ServerKeyFile",          config_parse_path,   0, &arg_key    },
533                 { "Upload",  "ServerCertificateFile",  config_parse_path,   0, &arg_cert   },
534                 { "Upload",  "TrustedCertificateFile", config_parse_path,   0, &arg_trust  },
535                 {}};
536
537         return config_parse(NULL, PKGSYSCONFDIR "/journal-upload.conf", NULL,
538                             "Upload\0",
539                             config_item_table_lookup, items,
540                             false, false, true, NULL);
541 }
542
543 static void help(void) {
544         printf("%s -u URL {FILE|-}...\n\n"
545                "Upload journal events to a remote server.\n\n"
546                "  -h --help                 Show this help\n"
547                "     --version              Show package version\n"
548                "  -u --url=URL              Upload to this address (default port "
549                                             STRINGIFY(DEFAULT_PORT) ")\n"
550                "     --key=FILENAME         Specify key in PEM format (default:\n"
551                "                            \"" PRIV_KEY_FILE "\")\n"
552                "     --cert=FILENAME        Specify certificate in PEM format (default:\n"
553                "                            \"" CERT_FILE "\")\n"
554                "     --trust=FILENAME|all   Specify CA certificate or disable checking (default:\n"
555                "                            \"" TRUST_FILE "\")\n"
556                "     --system               Use the system journal\n"
557                "     --user                 Use the user journal for the current user\n"
558                "  -m --merge                Use  all available journals\n"
559                "  -M --machine=CONTAINER    Operate on local container\n"
560                "  -D --directory=PATH       Use journal files from directory\n"
561                "     --file=PATH            Use this journal file\n"
562                "     --cursor=CURSOR        Start at the specified cursor\n"
563                "     --after-cursor=CURSOR  Start after the specified cursor\n"
564                "     --follow[=BOOL]        Do [not] wait for input\n"
565                "     --save-state[=FILE]    Save uploaded cursors (default \n"
566                "                            " STATE_FILE ")\n"
567                "  -h --help                 Show this help and exit\n"
568                "     --version              Print version string and exit\n"
569                , program_invocation_short_name);
570 }
571
572 static int parse_argv(int argc, char *argv[]) {
573         enum {
574                 ARG_VERSION = 0x100,
575                 ARG_KEY,
576                 ARG_CERT,
577                 ARG_TRUST,
578                 ARG_USER,
579                 ARG_SYSTEM,
580                 ARG_FILE,
581                 ARG_CURSOR,
582                 ARG_AFTER_CURSOR,
583                 ARG_FOLLOW,
584                 ARG_SAVE_STATE,
585         };
586
587         static const struct option options[] = {
588                 { "help",         no_argument,       NULL, 'h'                },
589                 { "version",      no_argument,       NULL, ARG_VERSION        },
590                 { "url",          required_argument, NULL, 'u'                },
591                 { "key",          required_argument, NULL, ARG_KEY            },
592                 { "cert",         required_argument, NULL, ARG_CERT           },
593                 { "trust",        required_argument, NULL, ARG_TRUST          },
594                 { "system",       no_argument,       NULL, ARG_SYSTEM         },
595                 { "user",         no_argument,       NULL, ARG_USER           },
596                 { "merge",        no_argument,       NULL, 'm'                },
597                 { "machine",      required_argument, NULL, 'M'                },
598                 { "directory",    required_argument, NULL, 'D'                },
599                 { "file",         required_argument, NULL, ARG_FILE           },
600                 { "cursor",       required_argument, NULL, ARG_CURSOR         },
601                 { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR   },
602                 { "follow",       optional_argument, NULL, ARG_FOLLOW         },
603                 { "save-state",   optional_argument, NULL, ARG_SAVE_STATE     },
604                 {}
605         };
606
607         int c, r;
608
609         assert(argc >= 0);
610         assert(argv);
611
612         opterr = 0;
613
614         while ((c = getopt_long(argc, argv, "hu:mM:D:", options, NULL)) >= 0)
615                 switch(c) {
616                 case 'h':
617                         help();
618                         return 0 /* done */;
619
620                 case ARG_VERSION:
621                         puts(PACKAGE_STRING);
622                         puts(SYSTEMD_FEATURES);
623                         return 0 /* done */;
624
625                 case 'u':
626                         if (arg_url) {
627                                 log_error("cannot use more than one --url");
628                                 return -EINVAL;
629                         }
630
631                         arg_url = optarg;
632                         break;
633
634                 case ARG_KEY:
635                         if (arg_key) {
636                                 log_error("cannot use more than one --key");
637                                 return -EINVAL;
638                         }
639
640                         arg_key = optarg;
641                         break;
642
643                 case ARG_CERT:
644                         if (arg_cert) {
645                                 log_error("cannot use more than one --cert");
646                                 return -EINVAL;
647                         }
648
649                         arg_cert = optarg;
650                         break;
651
652                 case ARG_TRUST:
653                         if (arg_trust) {
654                                 log_error("cannot use more than one --trust");
655                                 return -EINVAL;
656                         }
657
658                         arg_trust = optarg;
659                         break;
660
661                 case ARG_SYSTEM:
662                         arg_journal_type |= SD_JOURNAL_SYSTEM;
663                         break;
664
665                 case ARG_USER:
666                         arg_journal_type |= SD_JOURNAL_CURRENT_USER;
667                         break;
668
669                 case 'm':
670                         arg_merge = true;
671                         break;
672
673                 case 'M':
674                         if (arg_machine) {
675                                 log_error("cannot use more than one --machine/-M");
676                                 return -EINVAL;
677                         }
678
679                         arg_machine = optarg;
680                         break;
681
682                 case 'D':
683                         if (arg_directory) {
684                                 log_error("cannot use more than one --directory/-D");
685                                 return -EINVAL;
686                         }
687
688                         arg_directory = optarg;
689                         break;
690
691                 case ARG_FILE:
692                         r = glob_extend(&arg_file, optarg);
693                         if (r < 0)
694                                 return log_error_errno(r, "Failed to add paths: %m");
695                         break;
696
697                 case ARG_CURSOR:
698                         if (arg_cursor) {
699                                 log_error("cannot use more than one --cursor/--after-cursor");
700                                 return -EINVAL;
701                         }
702
703                         arg_cursor = optarg;
704                         break;
705
706                 case ARG_AFTER_CURSOR:
707                         if (arg_cursor) {
708                                 log_error("cannot use more than one --cursor/--after-cursor");
709                                 return -EINVAL;
710                         }
711
712                         arg_cursor = optarg;
713                         arg_after_cursor = true;
714                         break;
715
716                 case ARG_FOLLOW:
717                         if (optarg) {
718                                 r = parse_boolean(optarg);
719                                 if (r < 0) {
720                                         log_error("Failed to parse --follow= parameter.");
721                                         return -EINVAL;
722                                 }
723
724                                 arg_follow = !!r;
725                         } else
726                                 arg_follow = true;
727
728                         break;
729
730                 case ARG_SAVE_STATE:
731                         arg_save_state = optarg ?: STATE_FILE;
732                         break;
733
734                 case '?':
735                         log_error("Unknown option %s.", argv[optind-1]);
736                         return -EINVAL;
737
738                 case ':':
739                         log_error("Missing argument to %s.", argv[optind-1]);
740                         return -EINVAL;
741
742                 default:
743                         assert_not_reached("Unhandled option code.");
744                 }
745
746         if (!arg_url) {
747                 log_error("Required --url/-u option missing.");
748                 return -EINVAL;
749         }
750
751         if (!!arg_key != !!arg_cert) {
752                 log_error("Options --key and --cert must be used together.");
753                 return -EINVAL;
754         }
755
756         if (optind < argc && (arg_directory || arg_file || arg_machine || arg_journal_type)) {
757                 log_error("Input arguments make no sense with journal input.");
758                 return -EINVAL;
759         }
760
761         return 1;
762 }
763
764 static int open_journal(sd_journal **j) {
765         int r;
766
767         if (arg_directory)
768                 r = sd_journal_open_directory(j, arg_directory, arg_journal_type);
769         else if (arg_file)
770                 r = sd_journal_open_files(j, (const char**) arg_file, 0);
771         else if (arg_machine)
772                 r = sd_journal_open_container(j, arg_machine, 0);
773         else
774                 r = sd_journal_open(j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
775         if (r < 0)
776                 log_error_errno(r, "Failed to open %s: %m",
777                                 arg_directory ? arg_directory : arg_file ? "files" : "journal");
778         return r;
779 }
780
781 int main(int argc, char **argv) {
782         Uploader u;
783         int r;
784         bool use_journal;
785
786         log_show_color(true);
787         log_parse_environment();
788
789         r = parse_config();
790         if (r < 0)
791                 goto finish;
792
793         r = parse_argv(argc, argv);
794         if (r <= 0)
795                 goto finish;
796
797         r = setup_uploader(&u, arg_url, arg_save_state);
798         if (r < 0)
799                 goto cleanup;
800
801         sd_event_set_watchdog(u.events, true);
802
803         r = check_cursor_updating(&u);
804         if (r < 0)
805                 goto cleanup;
806
807         log_debug("%s running as pid "PID_FMT,
808                   program_invocation_short_name, getpid());
809
810         use_journal = optind >= argc;
811         if (use_journal) {
812                 sd_journal *j;
813                 r = open_journal(&j);
814                 if (r < 0)
815                         goto finish;
816                 r = open_journal_for_upload(&u, j,
817                                             arg_cursor ?: u.last_cursor,
818                                             arg_cursor ? arg_after_cursor : true,
819                                             !!arg_follow);
820                 if (r < 0)
821                         goto finish;
822         }
823
824         sd_notify(false,
825                   "READY=1\n"
826                   "STATUS=Processing input...");
827
828         while (true) {
829                 r = sd_event_get_state(u.events);
830                 if (r < 0)
831                         break;
832                 if (r == SD_EVENT_FINISHED)
833                         break;
834
835                 if (use_journal) {
836                         if (!u.journal)
837                                 break;
838
839                         r = check_journal_input(&u);
840                 } else if (u.input < 0 && !use_journal) {
841                         if (optind >= argc)
842                                 break;
843
844                         log_debug("Using %s as input.", argv[optind]);
845                         r = open_file_for_upload(&u, argv[optind++]);
846                 }
847                 if (r < 0)
848                         goto cleanup;
849
850                 if (u.uploading) {
851                         r = perform_upload(&u);
852                         if (r < 0)
853                                 break;
854                 }
855
856                 r = sd_event_run(u.events, u.timeout);
857                 if (r < 0) {
858                         log_error_errno(r, "Failed to run event loop: %m");
859                         break;
860                 }
861         }
862
863 cleanup:
864         sd_notify(false,
865                   "STOPPING=1\n"
866                   "STATUS=Shutting down...");
867
868         destroy_uploader(&u);
869
870 finish:
871         return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
872 }