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