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