]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal-remote/journal-upload.c
tree-wide: replace while(1) by for(;;) everywhere
[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 #include "log.h"
30 #include "util.h"
31 #include "build.h"
32 #include "fileio.h"
33 #include "mkdir.h"
34 #include "conf-parser.h"
35 #include "sigbus.h"
36 #include "formats-util.h"
37 #include "signal-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 puts(PACKAGE_STRING);
623 puts(SYSTEMD_FEATURES);
624 return 0 /* done */;
625
626 case 'u':
627 if (arg_url) {
628 log_error("cannot use more than one --url");
629 return -EINVAL;
630 }
631
632 arg_url = optarg;
633 break;
634
635 case ARG_KEY:
636 if (arg_key) {
637 log_error("cannot use more than one --key");
638 return -EINVAL;
639 }
640
641 arg_key = optarg;
642 break;
643
644 case ARG_CERT:
645 if (arg_cert) {
646 log_error("cannot use more than one --cert");
647 return -EINVAL;
648 }
649
650 arg_cert = optarg;
651 break;
652
653 case ARG_TRUST:
654 if (arg_trust) {
655 log_error("cannot use more than one --trust");
656 return -EINVAL;
657 }
658
659 arg_trust = optarg;
660 break;
661
662 case ARG_SYSTEM:
663 arg_journal_type |= SD_JOURNAL_SYSTEM;
664 break;
665
666 case ARG_USER:
667 arg_journal_type |= SD_JOURNAL_CURRENT_USER;
668 break;
669
670 case 'm':
671 arg_merge = true;
672 break;
673
674 case 'M':
675 if (arg_machine) {
676 log_error("cannot use more than one --machine/-M");
677 return -EINVAL;
678 }
679
680 arg_machine = optarg;
681 break;
682
683 case 'D':
684 if (arg_directory) {
685 log_error("cannot use more than one --directory/-D");
686 return -EINVAL;
687 }
688
689 arg_directory = optarg;
690 break;
691
692 case ARG_FILE:
693 r = glob_extend(&arg_file, optarg);
694 if (r < 0)
695 return log_error_errno(r, "Failed to add paths: %m");
696 break;
697
698 case ARG_CURSOR:
699 if (arg_cursor) {
700 log_error("cannot use more than one --cursor/--after-cursor");
701 return -EINVAL;
702 }
703
704 arg_cursor = optarg;
705 break;
706
707 case ARG_AFTER_CURSOR:
708 if (arg_cursor) {
709 log_error("cannot use more than one --cursor/--after-cursor");
710 return -EINVAL;
711 }
712
713 arg_cursor = optarg;
714 arg_after_cursor = true;
715 break;
716
717 case ARG_FOLLOW:
718 if (optarg) {
719 r = parse_boolean(optarg);
720 if (r < 0) {
721 log_error("Failed to parse --follow= parameter.");
722 return -EINVAL;
723 }
724
725 arg_follow = !!r;
726 } else
727 arg_follow = true;
728
729 break;
730
731 case ARG_SAVE_STATE:
732 arg_save_state = optarg ?: STATE_FILE;
733 break;
734
735 case '?':
736 log_error("Unknown option %s.", argv[optind-1]);
737 return -EINVAL;
738
739 case ':':
740 log_error("Missing argument to %s.", argv[optind-1]);
741 return -EINVAL;
742
743 default:
744 assert_not_reached("Unhandled option code.");
745 }
746
747 if (!arg_url) {
748 log_error("Required --url/-u option missing.");
749 return -EINVAL;
750 }
751
752 if (!!arg_key != !!arg_cert) {
753 log_error("Options --key and --cert must be used together.");
754 return -EINVAL;
755 }
756
757 if (optind < argc && (arg_directory || arg_file || arg_machine || arg_journal_type)) {
758 log_error("Input arguments make no sense with journal input.");
759 return -EINVAL;
760 }
761
762 return 1;
763 }
764
765 static int open_journal(sd_journal **j) {
766 int r;
767
768 if (arg_directory)
769 r = sd_journal_open_directory(j, arg_directory, arg_journal_type);
770 else if (arg_file)
771 r = sd_journal_open_files(j, (const char**) arg_file, 0);
772 else if (arg_machine)
773 r = sd_journal_open_container(j, arg_machine, 0);
774 else
775 r = sd_journal_open(j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
776 if (r < 0)
777 log_error_errno(r, "Failed to open %s: %m",
778 arg_directory ? arg_directory : arg_file ? "files" : "journal");
779 return r;
780 }
781
782 int main(int argc, char **argv) {
783 Uploader u;
784 int r;
785 bool use_journal;
786
787 log_show_color(true);
788 log_parse_environment();
789
790 r = parse_config();
791 if (r < 0)
792 goto finish;
793
794 r = parse_argv(argc, argv);
795 if (r <= 0)
796 goto finish;
797
798 sigbus_install();
799
800 r = setup_uploader(&u, arg_url, arg_save_state);
801 if (r < 0)
802 goto cleanup;
803
804 sd_event_set_watchdog(u.events, true);
805
806 r = check_cursor_updating(&u);
807 if (r < 0)
808 goto cleanup;
809
810 log_debug("%s running as pid "PID_FMT,
811 program_invocation_short_name, getpid());
812
813 use_journal = optind >= argc;
814 if (use_journal) {
815 sd_journal *j;
816 r = open_journal(&j);
817 if (r < 0)
818 goto finish;
819 r = open_journal_for_upload(&u, j,
820 arg_cursor ?: u.last_cursor,
821 arg_cursor ? arg_after_cursor : true,
822 !!arg_follow);
823 if (r < 0)
824 goto finish;
825 }
826
827 sd_notify(false,
828 "READY=1\n"
829 "STATUS=Processing input...");
830
831 for (;;) {
832 r = sd_event_get_state(u.events);
833 if (r < 0)
834 break;
835 if (r == SD_EVENT_FINISHED)
836 break;
837
838 if (use_journal) {
839 if (!u.journal)
840 break;
841
842 r = check_journal_input(&u);
843 } else if (u.input < 0 && !use_journal) {
844 if (optind >= argc)
845 break;
846
847 log_debug("Using %s as input.", argv[optind]);
848 r = open_file_for_upload(&u, argv[optind++]);
849 }
850 if (r < 0)
851 goto cleanup;
852
853 if (u.uploading) {
854 r = perform_upload(&u);
855 if (r < 0)
856 break;
857 }
858
859 r = sd_event_run(u.events, u.timeout);
860 if (r < 0) {
861 log_error_errno(r, "Failed to run event loop: %m");
862 break;
863 }
864 }
865
866 cleanup:
867 sd_notify(false,
868 "STOPPING=1\n"
869 "STATUS=Shutting down...");
870
871 destroy_uploader(&u);
872
873 finish:
874 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
875 }