chiark / gitweb /
sysusers: fix uninitialized warning
[elogind.git] / src / journal / journal-remote.c
index 1a1ca2c4801a15b7735195f2abc280a994f275ab..a31dc2c9801137ff44457aa1505319323e9bf579 100644 (file)
@@ -42,7 +42,6 @@
 #include "macro.h"
 #include "strv.h"
 #include "fileio.h"
-#include "socket-util.h"
 #include "microhttpd-util.h"
 
 #ifdef HAVE_GNUTLS
 static char* arg_output = NULL;
 static char* arg_url = NULL;
 static char* arg_getter = NULL;
-static bool arg_stdin = false;
 static char* arg_listen_raw = NULL;
 static char* arg_listen_http = NULL;
 static char* arg_listen_https = NULL;
+static char** arg_files = NULL;
 static int arg_compress = true;
 static int arg_seal = false;
+static int http_socket = -1, https_socket = -1;
 
 static char *key_pem = NULL;
 static char *cert_pem = NULL;
@@ -88,7 +88,7 @@ static int spawn_child(const char* child, char** argv) {
         if (child_pid < 0) {
                 r = -errno;
                 log_error("Failed to fork: %m");
-                close_pipe(fd);
+                safe_close_pair(fd);
                 return r;
         }
 
@@ -100,9 +100,7 @@ static int spawn_child(const char* child, char** argv) {
                         _exit(EXIT_FAILURE);
                 }
 
-                r = close_pipe(fd);
-                if (r < 0)
-                        log_warning("Failed to close pipe fds: %m");
+                safe_close_pair(fd);
 
                 /* Make sure the child goes away when the parent dies */
                 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
@@ -141,7 +139,7 @@ static int spawn_curl(char* url) {
 
 static int spawn_getter(char *getter, char *url) {
         int r;
-        char _cleanup_strv_free_ **words = NULL, **words2 = NULL;
+        _cleanup_strv_free_ char **words = NULL;
 
         assert(getter);
         words = strv_split_quoted(getter);
@@ -156,7 +154,7 @@ static int spawn_getter(char *getter, char *url) {
 }
 
 static int open_output(Writer *s, const char* url) {
-        char _cleanup_free_ *name, *output = NULL;
+        _cleanup_free_ char *name, *output = NULL;
         char *c;
         int r;
 
@@ -187,7 +185,7 @@ static int open_output(Writer *s, const char* url) {
                 if (r < 0)
                         return log_oom();
         } else {
-                r = is_dir(arg_output);
+                r = is_dir(arg_output, true);
                 if (r > 0) {
                         r = asprintf(&output,
                                      "%s/remote-%s.journal", arg_output, name);
@@ -227,8 +225,8 @@ typedef struct MHDDaemonWrapper {
 
 typedef struct RemoteServer {
         RemoteSource **sources;
-        ssize_t sources_size;
-        ssize_t active;
+        size_t sources_size;
+        size_t active;
 
         sd_event *events;
         sd_event_source *sigterm_event, *sigint_event, *listen_event;
@@ -258,7 +256,7 @@ static int get_source_for_fd(RemoteServer *s, int fd, RemoteSource **source) {
         assert(fd >= 0);
         assert(source);
 
-        if (!GREEDY_REALLOC0_T(s->sources, s->sources_size, fd + 1))
+        if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
                 return log_oom();
 
         if (s->sources[fd] == NULL) {
@@ -277,8 +275,7 @@ static int remove_source(RemoteServer *s, int fd) {
         RemoteSource *source;
 
         assert(s);
-        assert(fd >= 0);
-        assert(fd < s->sources_size);
+        assert(fd >= 0 && fd < (ssize_t) s->sources_size);
 
         source = s->sources[fd];
         if (source) {
@@ -294,7 +291,7 @@ static int remove_source(RemoteServer *s, int fd) {
 
 static int add_source(RemoteServer *s, int fd, const char* name) {
         RemoteSource *source = NULL;
-        char *realname;
+        _cleanup_free_ char *realname = NULL;
         int r;
 
         assert(s);
@@ -310,11 +307,11 @@ static int add_source(RemoteServer *s, int fd, const char* name) {
                         return log_oom();
         }
 
-        log_debug("Creating source for fd:%d (%s)", fd, name);
+        log_debug("Creating source for fd:%d (%s)", fd, realname);
 
         r = get_source_for_fd(s, fd, &source);
         if (r < 0) {
-                log_error("Failed to create source for fd:%d (%s)", fd, name);
+                log_error("Failed to create source for fd:%d (%s)", fd, realname);
                 return r;
         }
         assert(source);
@@ -336,12 +333,8 @@ static int add_source(RemoteServer *s, int fd, const char* name) {
         return r;
 }
 
-static int setup_raw_socket(RemoteServer *s, const char *address) {
-        int fd, r;
-
-        fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
-        if (fd < 0)
-                return fd;
+static int add_raw_socket(RemoteServer *s, int fd) {
+        int r;
 
         r = sd_event_add_io(s->events, &s->listen_event, fd, EPOLLIN,
                             dispatch_raw_connection_event, s);
@@ -354,6 +347,16 @@ static int setup_raw_socket(RemoteServer *s, const char *address) {
         return 0;
 }
 
+static int setup_raw_socket(RemoteServer *s, const char *address) {
+        int fd;
+
+        fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
+        if (fd < 0)
+                return fd;
+
+        return add_raw_socket(s, fd);
+}
+
 /**********************************************************************
  **********************************************************************
  **********************************************************************/
@@ -411,7 +414,7 @@ static int process_http_upload(
                 if (r < 0) {
                         log_error("Failed to store received data of size %zu: %s",
                                   *upload_data_size, strerror(-r));
-                        return respond_oom_internal(connection);
+                        return mhd_respond_oom(connection);
                 }
                 *upload_data_size = 0;
         } else
@@ -425,8 +428,8 @@ static int process_http_upload(
                         break;
                 else if (r < 0) {
                         log_warning("Failed to process data for connection %p", connection);
-                        return respond_error(connection, MHD_HTTP_UNPROCESSABLE_ENTITY,
-                                             "Processing failed: %s", strerror(-r));
+                        return mhd_respondf(connection, MHD_HTTP_UNPROCESSABLE_ENTITY,
+                                            "Processing failed: %s", strerror(-r));
                 }
         }
 
@@ -437,11 +440,11 @@ static int process_http_upload(
 
         if (source_non_empty(source)) {
                 log_warning("EOF reached with incomplete data");
-                return respond_error(connection, MHD_HTTP_EXPECTATION_FAILED,
-                                     "Trailing data not processed.");
+                return mhd_respond(connection, MHD_HTTP_EXPECTATION_FAILED,
+                                   "Trailing data not processed.");
         }
 
-        return respond_error(connection, MHD_HTTP_ACCEPTED, "OK.\n");
+        return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
 };
 
 static int request_handler(
@@ -470,19 +473,19 @@ static int request_handler(
                                            *connection_cls);
 
         if (!streq(method, "POST"))
-                return respond_error(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
-                                     "Unsupported method.\n");
+                return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
+                                   "Unsupported method.\n");
 
         if (!streq(url, "/upload"))
-                return respond_error(connection, MHD_HTTP_NOT_FOUND,
-                                     "Not found.\n");
+                return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
+                                   "Not found.\n");
 
         header = MHD_lookup_connection_value(connection,
                                              MHD_HEADER_KIND, "Content-Type");
         if (!header || !streq(header, "application/vnd.fdo.journal"))
-                return respond_error(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
-                                     "Content-Type: application/vnd.fdo.journal"
-                                     " is required.\n");
+                return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
+                                   "Content-Type: application/vnd.fdo.journal"
+                                   " is required.\n");
 
         if (trust_pem) {
                 r = check_permissions(connection, &code);
@@ -671,9 +674,24 @@ static int setup_signals(RemoteServer *s) {
         return 0;
 }
 
+static int fd_fd(const char *spec) {
+        int fd, r;
+
+        r = safe_atoi(spec, &fd);
+        if (r < 0)
+                return r;
+
+        if (fd >= 0)
+                return -ENOENT;
+
+        return -fd;
+}
+
+
 static int remoteserver_init(RemoteServer *s) {
         int r, n, fd;
         const char *output_name = NULL;
+        char **file;
 
         assert(s);
 
@@ -692,23 +710,43 @@ static int remoteserver_init(RemoteServer *s) {
         } else
                 log_info("Received %d descriptors", n);
 
+        if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
+                log_error("Received fewer sockets than expected");
+                return -EBADFD;
+        }
+
         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
                 if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
-                        assert_not_reached("not implemented");
+                        log_info("Received a listening socket (fd:%d)", fd);
+
+                        if (fd == http_socket)
+                                r = setup_microhttpd_server(s, fd, false);
+                        else if (fd == https_socket)
+                                r = setup_microhttpd_server(s, fd, true);
+                        else
+                                r = add_raw_socket(s, fd);
                 } else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
                         log_info("Received a connection socket (fd:%d)", fd);
 
                         r = add_source(s, fd, NULL);
-                        output_name = "socket";
                 } else {
                         log_error("Unknown socket passed on fd:%d", fd);
+
                         return -EINVAL;
                 }
+
+                if(r < 0) {
+                        log_error("Failed to register socket (fd:%d): %s",
+                                  fd, strerror(-r));
+                        return r;
+                }
+
+                output_name = "socket";
         }
 
         if (arg_url) {
-                char _cleanup_free_ *url = NULL;
-                char _cleanup_strv_free_ **urlv = strv_new(arg_url, "/entries", NULL);
+                _cleanup_free_ char *url = NULL;
+                _cleanup_strv_free_ char **urlv = strv_new(arg_url, "/entries", NULL);
                 if (!urlv)
                         return log_oom();
                 url = strv_join(urlv, "");
@@ -757,13 +795,26 @@ static int remoteserver_init(RemoteServer *s) {
                 output_name = arg_listen_https;
         }
 
-        if (arg_stdin) {
-                log_info("Reading standard input...");
-                r = add_source(s, STDIN_FILENO, "stdin");
+        STRV_FOREACH(file, arg_files) {
+                if (streq(*file, "-")) {
+                        log_info("Reading standard input...");
+
+                        fd = STDIN_FILENO;
+                        output_name = "stdin";
+                } else {
+                        log_info("Reading file %s...", *file);
+
+                        fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
+                        if (fd < 0) {
+                                log_error("Failed to open %s: %m", *file);
+                                return -errno;
+                        }
+                        output_name = *file;
+                }
+
+                r = add_source(s, fd, output_name);
                 if (r < 0)
                         return r;
-
-                output_name = "stdin";
         }
 
         if (s->active == 0) {
@@ -771,7 +822,7 @@ static int remoteserver_init(RemoteServer *s) {
                 return -EINVAL;
         }
 
-        if (!!n + !!arg_url + !!arg_listen_raw + !!arg_stdin > 1)
+        if (!!n + !!arg_url + !!arg_listen_raw + !!arg_files)
                 output_name = "multiple";
 
         r = writer_init(&s->writer);
@@ -784,7 +835,7 @@ static int remoteserver_init(RemoteServer *s) {
 
 static int server_destroy(RemoteServer *s) {
         int r;
-        ssize_t i;
+        size_t i;
         MHDDaemonWrapper *d;
 
         r = writer_close(&s->writer);
@@ -826,7 +877,7 @@ static int dispatch_raw_source_event(sd_event_source *event,
         RemoteSource *source;
         int r;
 
-        assert(fd < s->sources_size);
+        assert(fd >= 0 && fd < (ssize_t) s->sources_size);
         source = s->sources[fd];
         assert(source->fd == fd);
 
@@ -907,7 +958,7 @@ static int dispatch_raw_connection_event(sd_event_source *event,
  **********************************************************************/
 
 static int help(void) {
-        printf("%s [OPTIONS...]\n\n"
+        printf("%s [OPTIONS...] {FILE|-}...\n\n"
                "Write external journal events to a journal file.\n\n"
                "Options:\n"
                "  --url=URL            Read events from systemd-journal-gatewayd at URL\n"
@@ -915,7 +966,6 @@ static int help(void) {
                "  --listen-raw=ADDR    Listen for connections at ADDR\n"
                "  --listen-http=ADDR   Listen for HTTP connections at ADDR\n"
                "  --listen-https=ADDR  Listen for HTTPS connections at ADDR\n"
-               "  --stdin              Read events from standard input\n"
                "  -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
                "  --[no-]compress      Use XZ-compression in the output journal (default: yes)\n"
                "  --[no-]seal          Use Event sealing in the output journal (default: no)\n"
@@ -935,7 +985,6 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_LISTEN_RAW,
                 ARG_LISTEN_HTTP,
                 ARG_LISTEN_HTTPS,
-                ARG_STDIN,
                 ARG_GETTER,
                 ARG_COMPRESS,
                 ARG_NO_COMPRESS,
@@ -954,7 +1003,6 @@ static int parse_argv(int argc, char *argv[]) {
                 { "listen-raw",   required_argument, NULL, ARG_LISTEN_RAW   },
                 { "listen-http",  required_argument, NULL, ARG_LISTEN_HTTP  },
                 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
-                { "stdin",        no_argument,       NULL, ARG_STDIN        },
                 { "output",       required_argument, NULL, 'o'              },
                 { "compress",     no_argument,       NULL, ARG_COMPRESS     },
                 { "no-compress",  no_argument,       NULL, ARG_NO_COMPRESS  },
@@ -1010,21 +1058,41 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_LISTEN_HTTP:
-                        if (arg_listen_http) {
+                        if (arg_listen_http || http_socket >= 0) {
                                 log_error("cannot currently use --listen-http more than once");
                                 return -EINVAL;
                         }
 
-                        arg_listen_http = optarg;
+                        r = fd_fd(optarg);
+                        if (r >= 0)
+                                http_socket = r;
+                        else if (r == -ENOENT)
+                                arg_listen_http = optarg;
+                        else {
+                                log_error("Invalid port/fd specification %s: %s",
+                                          optarg, strerror(-r));
+                                return -EINVAL;
+                        }
+
                         break;
 
                 case ARG_LISTEN_HTTPS:
-                        if (arg_listen_https) {
+                        if (arg_listen_https || https_socket >= 0) {
                                 log_error("cannot currently use --listen-https more than once");
                                 return -EINVAL;
                         }
 
-                        arg_listen_https = optarg;
+                        r = fd_fd(optarg);
+                        if (r >= 0)
+                                https_socket = r;
+                        else if (r == -ENOENT)
+                                arg_listen_https = optarg;
+                        else {
+                                log_error("Invalid port/fd specification %s: %s",
+                                          optarg, strerror(-r));
+                                return -EINVAL;
+                        }
+
                         break;
 
                 case ARG_KEY:
@@ -1070,10 +1138,6 @@ static int parse_argv(int argc, char *argv[]) {
                         log_error("Option --trust is not available.");
 #endif
 
-                case ARG_STDIN:
-                        arg_stdin = true;
-                        break;
-
                 case 'o':
                         if (arg_output) {
                                 log_error("cannot use --output/-o more than once");
@@ -1109,10 +1173,8 @@ static int parse_argv(int argc, char *argv[]) {
                 return -EINVAL;
         }
 
-        if (optind < argc) {
-                log_error("This program takes no positional arguments");
-                return -EINVAL;
-        }
+        if (optind < argc)
+                arg_files = argv + optind;
 
         return 1 /* work to do */;
 }
@@ -1148,8 +1210,8 @@ int main(int argc, char **argv) {
         if (remoteserver_init(&s) < 0)
                 return EXIT_FAILURE;
 
-        log_debug("%s running as pid %lu",
-                  program_invocation_short_name, (unsigned long) getpid());
+        log_debug("%s running as pid "PID_FMT,
+                  program_invocation_short_name, getpid());
         sd_notify(false,
                   "READY=1\n"
                   "STATUS=Processing requests...");