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