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