chiark / gitweb /
journald-remote,journal-upload: Support .d directories in the usual search paths
[elogind.git] / src / journal-remote / journal-upload.c
index 5a30a29427189f405c6d3e15bcc090a729a0d542..62853b636782c432c55bfac6f8db299534938fcd 100644 (file)
 #include "util.h"
 #include "build.h"
 #include "fileio.h"
+#include "mkdir.h"
 #include "conf-parser.h"
 #include "journal-upload.h"
 
 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-upload.pem"
 #define CERT_FILE     CERTIFICATE_ROOT "/certs/journal-upload.pem"
 #define TRUST_FILE    CERTIFICATE_ROOT "/ca/trusted.pem"
+#define DEFAULT_PORT  19532
 
 static const char* arg_url;
 
@@ -61,7 +63,7 @@ static const char *arg_save_state = NULL;
 #define STATE_FILE "/var/lib/systemd/journal-upload/state"
 
 #define easy_setopt(curl, opt, value, level, cmd)                       \
-        {                                                               \
+        do {                                                            \
                 code = curl_easy_setopt(curl, opt, value);              \
                 if (code) {                                             \
                         log_full(level,                                 \
@@ -69,7 +71,7 @@ static const char *arg_save_state = NULL;
                                   curl_easy_strerror(code));            \
                         cmd;                                            \
                 }                                                       \
-        }
+        } while(0)
 
 static size_t output_callback(char *buf,
                               size_t size,
@@ -85,13 +87,35 @@ static size_t output_callback(char *buf,
         if (nmemb && !u->answer) {
                 u->answer = strndup(buf, size*nmemb);
                 if (!u->answer)
-                        log_warning("Failed to store server answer (%zu bytes): %s",
-                                    size*nmemb, strerror(ENOMEM));
+                        log_warning_errno(ENOMEM, "Failed to store server answer (%zu bytes): %m",
+                                          size*nmemb);
         }
 
         return size * nmemb;
 }
 
+static int check_cursor_updating(Uploader *u) {
+        _cleanup_free_ char *temp_path = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        if (!u->state_file)
+                return 0;
+
+        r = mkdir_parents(u->state_file, 0755);
+        if (r < 0)
+                return log_error_errno(r, "Cannot create parent directory of state file %s: %m",
+                                       u->state_file);
+
+        r = fopen_temporary(u->state_file, &f, &temp_path);
+        if (r < 0)
+                return log_error_errno(r, "Cannot save state to %s: %m",
+                                       u->state_file);
+        unlink(temp_path);
+
+        return 0;
+}
+
 static int update_cursor_state(Uploader *u) {
         _cleanup_free_ char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
@@ -119,7 +143,7 @@ static int update_cursor_state(Uploader *u) {
 
 finish:
         if (r < 0)
-                log_error("Failed to save state %s: %s", u->state_file, strerror(-r));
+                log_error_errno(r, "Failed to save state %s: %m", u->state_file);
 
         return r;
 }
@@ -134,11 +158,13 @@ static int load_cursor_state(Uploader *u) {
                            "LAST_CURSOR",  &u->last_cursor,
                            NULL);
 
-        if (r < 0 && r != -ENOENT) {
-                log_error("Failed to read state file %s: %s",
-                          u->state_file, strerror(-r));
-                return r;
-        }
+        if (r == -ENOENT)
+                log_debug("State file %s is not present.", u->state_file);
+        else if (r < 0)
+                return log_error_errno(r, "Failed to read state file %s: %m",
+                                       u->state_file);
+        else
+                log_debug("Last cursor was %s", u->last_cursor);
 
         return 0;
 }
@@ -191,7 +217,7 @@ int start_upload(Uploader *u,
                 easy_setopt(curl, CURLOPT_POST, 1L,
                             LOG_ERR, return -EXFULL);
 
-                easy_setopt(curl, CURLOPT_ERRORBUFFER, &u->error,
+                easy_setopt(curl, CURLOPT_ERRORBUFFER, u->error,
                             LOG_ERR, return -EXFULL);
 
                 /* set where to write to */
@@ -220,15 +246,16 @@ int start_upload(Uploader *u,
                             LOG_WARNING, );
 
                 if (arg_key || startswith(u->url, "https://")) {
-                        assert(arg_cert);
-
                         easy_setopt(curl, CURLOPT_SSLKEY, arg_key ?: PRIV_KEY_FILE,
                                     LOG_ERR, return -EXFULL);
                         easy_setopt(curl, CURLOPT_SSLCERT, arg_cert ?: CERT_FILE,
                                     LOG_ERR, return -EXFULL);
                 }
 
-                if (arg_trust || startswith(u->url, "https://"))
+                if (streq_ptr(arg_trust, "all"))
+                        easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0,
+                                    LOG_ERR, return -EUCLEAN);
+                else if (arg_trust || startswith(u->url, "https://"))
                         easy_setopt(curl, CURLOPT_CAINFO, arg_trust ?: TRUST_FILE,
                                     LOG_ERR, return -EXFULL);
 
@@ -281,7 +308,7 @@ static size_t fd_input_callback(void *buf, size_t size, size_t nmemb, void *user
                 close_fd_input(u);
                 return 0;
         } else {
-                log_error("Aborting transfer after read error on input: %m.");
+                log_error_errno(errno, "Aborting transfer after read error on input: %m.");
                 return CURL_READFUNC_ABORT;
         }
 }
@@ -324,16 +351,14 @@ static int dispatch_fd_input(sd_event_source *event,
 }
 
 static int open_file_for_upload(Uploader *u, const char *filename) {
-        int fd, r;
+        int fd, r = 0;
 
         if (streq(filename, "-"))
                 fd = STDIN_FILENO;
         else {
                 fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                if (fd < 0) {
-                        log_error("Failed to open %s: %m", filename);
-                        return -errno;
-                }
+                if (fd < 0)
+                        return log_error_errno(errno, "Failed to open %s: %m", filename);
         }
 
         u->input = fd;
@@ -342,10 +367,8 @@ static int open_file_for_upload(Uploader *u, const char *filename) {
                 r = sd_event_add_io(u->events, &u->input_event,
                                     fd, EPOLLIN, dispatch_fd_input, u);
                 if (r < 0) {
-                        if (r != -EPERM || arg_follow > 0) {
-                                log_error("Failed to register input event: %s", strerror(-r));
-                                return r;
-                        }
+                        if (r != -EPERM || arg_follow > 0)
+                                return log_error_errno(r, "Failed to register input event: %m");
 
                         /* Normal files should just be consumed without polling. */
                         r = start_upload(u, fd_input_callback, u);
@@ -394,6 +417,7 @@ static int setup_signals(Uploader *u) {
 
 static int setup_uploader(Uploader *u, const char *url, const char *state_file) {
         int r;
+        const char *host, *proto = "";
 
         assert(u);
         assert(url);
@@ -401,26 +425,36 @@ static int setup_uploader(Uploader *u, const char *url, const char *state_file)
         memzero(u, sizeof(Uploader));
         u->input = -1;
 
-        if (!startswith(url, "http://") && !startswith(url, "https://"))
-                url = strappenda("https://", url);
+        if (!(host = startswith(url, "http://")) && !(host = startswith(url, "https://"))) {
+                host = url;
+                proto = "https://";
+        }
+
+        if (strchr(host, ':'))
+                u->url = strjoin(proto, url, "/upload", NULL);
+        else {
+                char *t;
+                size_t x;
+
+                t = strdupa(url);
+                x = strlen(t);
+                while (x > 0 && t[x - 1] == '/')
+                        t[x - 1] = '\0';
 
-        u->url = strappend(url, "/upload");
+                u->url = strjoin(proto, t, ":" STRINGIFY(DEFAULT_PORT), "/upload", NULL);
+        }
         if (!u->url)
                 return log_oom();
 
         u->state_file = state_file;
 
         r = sd_event_default(&u->events);
-        if (r < 0) {
-                log_error("sd_event_default failed: %s", strerror(-r));
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "sd_event_default failed: %m");
 
         r = setup_signals(u);
-        if (r < 0) {
-                log_error("Failed to set up signals: %s", strerror(-r));
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to set up signals: %m");
 
         return load_cursor_state(u);
 }
@@ -455,10 +489,12 @@ static int perform_upload(Uploader *u) {
 
         code = curl_easy_perform(u->easy);
         if (code) {
-                log_error("Upload to %s failed: %.*s",
-                          u->url,
-                          u->error[0] ? (int) sizeof(u->error) : INT_MAX,
-                          u->error[0] ? u->error : curl_easy_strerror(code));
+                if (u->error[0])
+                        log_error("Upload to %s failed: %.*s",
+                                  u->url, (int) sizeof(u->error), u->error);
+                else
+                        log_error("Upload to %s failed: %s",
+                                  u->url, curl_easy_strerror(code));
                 return -EIO;
         }
 
@@ -496,10 +532,10 @@ static int parse_config(void) {
                 { "Upload",  "TrustedCertificateFile", config_parse_path,   0, &arg_trust  },
                 {}};
 
-        return config_parse(NULL, PKGSYSCONFDIR "/journal-upload.conf", NULL,
-                            "Upload\0",
-                            config_item_table_lookup, items,
-                            false, false, true, NULL);
+        return config_parse_many(PKGSYSCONFDIR "/journal-upload.conf",
+                                 CONF_DIRS_NULSTR("systemd/journal-upload.conf"),
+                                 "Upload\0", config_item_table_lookup, items,
+                                 false, NULL);
 }
 
 static void help(void) {
@@ -507,10 +543,14 @@ static void help(void) {
                "Upload journal events to a remote server.\n\n"
                "  -h --help                 Show this help\n"
                "     --version              Show package version\n"
-               "  -u --url=URL              Upload to this address\n"
-               "     --key=FILENAME         Specify key in PEM format\n"
-               "     --cert=FILENAME        Specify certificate in PEM format\n"
-               "     --trust=FILENAME       Specify CA certificate in PEM format\n"
+               "  -u --url=URL              Upload to this address (default port "
+                                            STRINGIFY(DEFAULT_PORT) ")\n"
+               "     --key=FILENAME         Specify key in PEM format (default:\n"
+               "                            \"" PRIV_KEY_FILE "\")\n"
+               "     --cert=FILENAME        Specify certificate in PEM format (default:\n"
+               "                            \"" CERT_FILE "\")\n"
+               "     --trust=FILENAME|all   Specify CA certificate or disable checking (default:\n"
+               "                            \"" TRUST_FILE "\")\n"
                "     --system               Use the system journal\n"
                "     --user                 Use the user journal for the current user\n"
                "  -m --merge                Use  all available journals\n"
@@ -648,10 +688,8 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_FILE:
                         r = glob_extend(&arg_file, optarg);
-                        if (r < 0) {
-                                log_error("Failed to add paths: %s", strerror(-r));
-                                return r;
-                        };
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to add paths: %m");
                         break;
 
                 case ARG_CURSOR:
@@ -733,9 +771,8 @@ static int open_journal(sd_journal **j) {
         else
                 r = sd_journal_open(j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
         if (r < 0)
-                log_error("Failed to open %s: %s",
-                          arg_directory ? arg_directory : arg_file ? "files" : "journal",
-                          strerror(-r));
+                log_error_errno(r, "Failed to open %s: %m",
+                                arg_directory ? arg_directory : arg_file ? "files" : "journal");
         return r;
 }
 
@@ -748,7 +785,7 @@ int main(int argc, char **argv) {
         log_parse_environment();
 
         r = parse_config();
-        if (r <= 0)
+        if (r < 0)
                 goto finish;
 
         r = parse_argv(argc, argv);
@@ -761,6 +798,10 @@ int main(int argc, char **argv) {
 
         sd_event_set_watchdog(u.events, true);
 
+        r = check_cursor_updating(&u);
+        if (r < 0)
+                goto cleanup;
+
         log_debug("%s running as pid "PID_FMT,
                   program_invocation_short_name, getpid());
 
@@ -783,6 +824,12 @@ int main(int argc, char **argv) {
                   "STATUS=Processing input...");
 
         while (true) {
+                r = sd_event_get_state(u.events);
+                if (r < 0)
+                        break;
+                if (r == SD_EVENT_FINISHED)
+                        break;
+
                 if (use_journal) {
                         if (!u.journal)
                                 break;
@@ -798,12 +845,6 @@ int main(int argc, char **argv) {
                 if (r < 0)
                         goto cleanup;
 
-                r = sd_event_get_state(u.events);
-                if (r < 0)
-                        break;
-                if (r == SD_EVENT_FINISHED)
-                        break;
-
                 if (u.uploading) {
                         r = perform_upload(&u);
                         if (r < 0)
@@ -812,15 +853,18 @@ int main(int argc, char **argv) {
 
                 r = sd_event_run(u.events, u.timeout);
                 if (r < 0) {
-                        log_error("Failed to run event loop: %s", strerror(-r));
+                        log_error_errno(r, "Failed to run event loop: %m");
                         break;
                 }
         }
 
 cleanup:
-        sd_notify(false, "STATUS=Shutting down...");
+        sd_notify(false,
+                  "STOPPING=1\n"
+                  "STATUS=Shutting down...");
+
         destroy_uploader(&u);
 
 finish:
-        return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+        return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }