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