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