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