chiark / gitweb /
socket: make sockets to pass to a service configurable
authorLennart Poettering <lennart@poettering.net>
Tue, 5 Oct 2010 17:49:15 +0000 (19:49 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 5 Oct 2010 17:50:00 +0000 (19:50 +0200)
fixme
src/load-fragment.c
src/service.c
src/service.h
src/socket.c
src/unit.c
src/unit.h

diff --git a/fixme b/fixme
index 0ba02a2..24fb169 100644 (file)
--- a/fixme
+++ b/fixme
@@ -1,12 +1,5 @@
 v11:
 
-* have a simple syslog bridge providing /dev/log and forward messages
-  to /dev/kmsg. at the moment the real syslog can be started, the bridge
-  is stopped and the open /dev/log fd to the real syslog. that way we
-  don't lose any early log message, and simple systems have full syslog
-  support in the kernel ringbuffer, without any syslog service or disk
-  access
-
 * emergency.service should start default.target after C-d. synchronize from fedora's initscripts package
 
 * verify ordering of random-seed-load and base.target!
@@ -108,6 +101,12 @@ later:
 
 * beefed up tmpwatch that reads tmpfiles.d
 
+* /lib/systemd/system/systemd-readahead-replay.service
+
+* use /sbin/swapon
+
+* enable syslog.socket by default, activating our kmsg bridge
+
 External:
 
 * place /etc/inittab with explaining blurb.
index eba3fdb..1685c4a 100644 (file)
@@ -1246,8 +1246,8 @@ static int config_parse_socket_service(
 
         dbus_error_init(&error);
 
-        if (endswith(rvalue, ".service")) {
-                log_error("[%s:%u] Unit must be of type serivce, ignoring: %s", filename, line, rvalue);
+        if (!endswith(rvalue, ".service")) {
+                log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
                 return 0;
         }
 
@@ -1260,6 +1260,60 @@ static int config_parse_socket_service(
         return 0;
 }
 
+static int config_parse_service_sockets(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Service *s = data;
+        int r;
+        DBusError error;
+        char *state, *w;
+        size_t l;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        dbus_error_init(&error);
+
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                char *t;
+                Unit *sock;
+
+                if (!(t = strndup(w, l)))
+                        return -ENOMEM;
+
+                if (!endswith(t, ".socket")) {
+                        log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
+                        free(t);
+                        continue;
+                }
+
+                r = manager_load_unit(s->meta.manager, t, NULL, &error, &sock);
+                free(t);
+
+                if (r < 0) {
+                        log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
+                        dbus_error_free(&error);
+                        continue;
+                }
+
+                if ((r = set_ensure_allocated(&s->configured_sockets, trivial_hash_func, trivial_compare_func)) < 0)
+                        return r;
+
+                if ((r = set_put(s->configured_sockets, sock)) < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
 static int config_parse_env_file(
                 const char *filename,
                 unsigned line,
@@ -1655,11 +1709,12 @@ static int load_from_path(Unit *u, const char *path) {
 #ifdef HAVE_SYSV_COMPAT
                 { "SysVStartPriority",      config_parse_sysv_priority,   &u->service.sysv_start_priority,                 "Service" },
 #else
-                { "SysVStartPriority",      config_parse_warn_compat,     NULL,                                           "Service" },
+                { "SysVStartPriority",      config_parse_warn_compat,     NULL,                                            "Service" },
 #endif
                 { "NonBlocking",            config_parse_bool,            &u->service.exec_context.non_blocking,           "Service" },
                 { "BusName",                config_parse_string_printf,   &u->service.bus_name,                            "Service" },
                 { "NotifyAccess",           config_parse_notify_access,   &u->service.notify_access,                       "Service" },
+                { "Sockets",                config_parse_service_sockets, &u->service,                                     "Service" },
                 EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"),
 
                 { "ListenStream",           config_parse_listen,          &u->socket,                                      "Socket"  },
index b18c950..301633e 100644 (file)
@@ -178,11 +178,11 @@ static void service_close_socket_fd(Service *s) {
 static void service_connection_unref(Service *s) {
         assert(s);
 
-        if (!s->socket)
+        if (!s->accept_socket)
                 return;
 
-        socket_connection_unref(s->socket);
-        s->socket = NULL;
+        socket_connection_unref(s->accept_socket);
+        s->accept_socket = NULL;
 }
 
 static void service_done(Unit *u) {
@@ -222,6 +222,8 @@ static void service_done(Unit *u) {
         service_close_socket_fd(s);
         service_connection_unref(s);
 
+        set_free(s->configured_sockets);
+
         unit_unwatch_timer(u, &s->timer_watch);
 }
 
@@ -1177,6 +1179,9 @@ static int service_get_sockets(Service *s, Set **_set) {
         if (s->socket_fd >= 0)
                 return 0;
 
+        if (!set_isempty(s->configured_sockets))
+                return 0;
+
         /* Collects all Socket objects that belong to this
          * service. Note that a service might have multiple sockets
          * via multiple names. */
@@ -1216,23 +1221,30 @@ fail:
 
 static int service_notify_sockets_dead(Service *s) {
         Iterator i;
-        Set *set;
+        Set *set, *free_set = NULL;
         Socket *sock;
         int r;
 
         assert(s);
 
+        /* Notifies all our sockets when we die */
+
         if (s->socket_fd >= 0)
                 return 0;
 
-        /* Notifies all our sockets when we die */
-        if ((r = service_get_sockets(s, &set)) < 0)
-                return r;
+        if (!set_isempty(s->configured_sockets))
+                set = s->configured_sockets;
+        else {
+                if ((r = service_get_sockets(s, &free_set)) < 0)
+                        return r;
+
+                set = free_set;
+        }
 
         SET_FOREACH(sock, set, i)
                 socket_notify_service_dead(sock);
 
-        set_free(set);
+        set_free(free_set);
 
         return 0;
 }
@@ -1390,7 +1402,7 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
         int r;
         int *rfds = NULL;
         unsigned rn_fds = 0;
-        Set *set;
+        Set *set, *free_set = NULL;
         Socket *sock;
 
         assert(s);
@@ -1400,8 +1412,14 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
         if (s->socket_fd >= 0)
                 return 0;
 
-        if ((r = service_get_sockets(s, &set)) < 0)
-                return r;
+        if (!set_isempty(s->configured_sockets))
+                set = s->configured_sockets;
+        else {
+                if ((r = service_get_sockets(s, &free_set)) < 0)
+                        return r;
+
+                set = free_set;
+        }
 
         SET_FOREACH(sock, set, i) {
                 int *cfds;
@@ -1438,7 +1456,7 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
         *fds = rfds;
         *n_fds = rn_fds;
 
-        set_free(set);
+        set_free(free_set);
 
         return 0;
 
@@ -2084,14 +2102,6 @@ static int service_start(Unit *u) {
                 return -ECANCELED;
         }
 
-        if ((s->exec_context.std_input == EXEC_INPUT_SOCKET ||
-             s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
-             s->exec_context.std_error == EXEC_OUTPUT_SOCKET) &&
-            s->socket_fd < 0) {
-                log_warning("%s can only be started with a per-connection socket.", u->meta.id);
-                return -EINVAL;
-        }
-
         s->failure = false;
         s->main_pid_known = false;
         s->forbid_restart = false;
@@ -3062,7 +3072,7 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock) {
 
         s->socket_fd = fd;
         s->got_socket_fd = true;
-        s->socket = sock;
+        s->accept_socket = sock;
 
         return 0;
 }
index 39bd1b3..e2b11db 100644 (file)
@@ -133,7 +133,8 @@ struct Service {
 
         RateLimit ratelimit;
 
-        struct Socket *socket;
+        struct Socket *accept_socket;
+        Set *configured_sockets;
 
         Watch timer_watch;
 
index bbb54f6..2567d0f 100644 (file)
@@ -129,8 +129,10 @@ static void socket_done(Unit *u) {
         LIST_FOREACH(units_per_type, i, u->meta.manager->units_per_type[UNIT_SERVICE]) {
                 Service *service = (Service *) i;
 
-                if (service->socket == s)
-                        service->socket = NULL;
+                if (service->accept_socket == s)
+                        service->accept_socket = NULL;
+
+                set_remove(service->configured_sockets, s);
         }
 }
 
@@ -1197,8 +1199,27 @@ static void socket_enter_running(Socket *s, int cfd) {
         }
 
         if (cfd < 0) {
-                if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, &error, NULL)) < 0)
-                        goto fail;
+                bool pending = false;
+                Meta *i;
+
+                /* If there's already a start pending don't bother to
+                 * do anything */
+                LIST_FOREACH(units_per_type, i, s->meta.manager->units_per_type[UNIT_SERVICE]) {
+                        Service *service = (Service *) i;
+
+                        if (!set_get(service->configured_sockets, s))
+                                continue;
+
+                        if (!unit_pending_active(UNIT(service)))
+                                continue;
+
+                        pending = true;
+                        break;
+                }
+
+                if (!pending)
+                        if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, &error, NULL)) < 0)
+                                goto fail;
 
                 socket_set_state(s, SOCKET_RUNNING);
         } else {
index 0a8ee61..fefa0eb 100644 (file)
@@ -2190,6 +2190,23 @@ bool unit_pending_inactive(Unit *u) {
         return false;
 }
 
+bool unit_pending_active(Unit *u) {
+        assert(u);
+
+        /* Returns true if the unit is inactive or going down */
+
+        if (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
+                return true;
+
+        if (u->meta.job &&
+            (u->meta.job->type == JOB_START ||
+             u->meta.job->type == JOB_RELOAD_OR_START ||
+             u->meta.job->type == JOB_RESTART))
+                return true;
+
+        return false;
+}
+
 static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
         [UNIT_STUB] = "stub",
         [UNIT_LOADED] = "loaded",
index 20bb6a2..47a1eb6 100644 (file)
@@ -500,6 +500,7 @@ void unit_reset_failed(Unit *u);
 Unit *unit_following(Unit *u);
 
 bool unit_pending_inactive(Unit *u);
+bool unit_pending_active(Unit *u);
 
 int unit_add_default_target_dependency(Unit *u, Unit *target);