From 01e10de3c2b9c2944bd86b12fab83d1164d0b64a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Dec 2012 19:30:07 +0100 Subject: socket: support socket activation of containers --- src/core/main.c | 38 ++++++++++++++++++++++---------------- src/core/manager.c | 38 ++++++++++++++++++++++++++++++++++++-- src/core/manager.h | 1 + src/core/socket.c | 29 +++++++++++++++++++++++++++++ src/core/unit.h | 3 +++ 5 files changed, 91 insertions(+), 18 deletions(-) (limited to 'src/core') diff --git a/src/core/main.c b/src/core/main.c index 2fcd63d3e2..dfb53a8438 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -934,14 +934,18 @@ static int parse_argv(int argc, char *argv[]) { int fd; FILE *f; - if ((r = safe_atoi(optarg, &fd)) < 0 || fd < 0) { + r = safe_atoi(optarg, &fd); + if (r < 0 || fd < 0) { log_error("Failed to parse deserialize option %s.", optarg); - return r; + return r < 0 ? r : -EINVAL; } - if (!(f = fdopen(fd, "r"))) { + fd_cloexec(fd, true); + + f = fdopen(fd, "r"); + if (!f) { log_error("Failed to open serialization fd: %m"); - return r; + return -errno; } if (serialization) @@ -1474,16 +1478,15 @@ int main(int argc, char *argv[]) { log_close(); /* Remember open file descriptors for later deserialization */ - if (serialization) { - r = fdset_new_fill(&fds); - if (r < 0) { - log_error("Failed to allocate fd set: %s", strerror(-r)); - goto finish; - } + r = fdset_new_fill(&fds); + if (r < 0) { + log_error("Failed to allocate fd set: %s", strerror(-r)); + goto finish; + } else + fdset_cloexec(fds, true); + if (serialization) assert_se(fdset_remove(fds, fileno(serialization)) >= 0); - } else - close_all_fds(NULL, 0); /* Set up PATH unless it is already set */ setenv("PATH", @@ -1518,6 +1521,12 @@ int main(int argc, char *argv[]) { unsetenv("USER"); unsetenv("LOGNAME"); + /* We suppress the socket activation env vars, as + * we'll try to match *any* open fd to units if + * possible. */ + unsetenv("LISTEN_FDS"); + unsetenv("LISTEN_PID"); + /* All other variables are left as is, so that clients * can still read them via /proc/1/environ */ } @@ -1653,10 +1662,7 @@ int main(int argc, char *argv[]) { /* This will close all file descriptors that were opened, but * not claimed by any unit. */ - if (fds) { - fdset_free(fds); - fds = NULL; - } + fdset_free(fds); if (serialization) { fclose(serialization); diff --git a/src/core/manager.c b/src/core/manager.c index 1ddd8bae62..ac11ce1806 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -706,6 +706,16 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { r = q; } + /* Any fds left? Find some unit which wants them. This is + * useful to allow container managers to pass some file + * descriptors to us pre-initialized. This enables + * socket-based activation of entire containers. */ + if (fdset_size(fds) > 0) { + q = manager_distribute_fds(m, fds); + if (q < 0) + r = q; + } + /* Third, fire things up! */ q = manager_coldplug(m); if (q < 0) @@ -1807,7 +1817,8 @@ int manager_open_serialization(Manager *m, FILE **_f) { log_debug("Serializing state to %s", path); free(path); - if (!(f = fdopen(fd, "w+"))) + f = fdopen(fd, "w+"); + if (!f) return -errno; *_f = f; @@ -1965,7 +1976,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { if ((r = manager_load_unit(m, strstrip(name), NULL, NULL, &u)) < 0) goto finish; - if ((r = unit_deserialize(u, f, fds)) < 0) + r = unit_deserialize(u, f, fds); + if (r < 0) goto finish; } @@ -1981,6 +1993,28 @@ finish: return r; } +int manager_distribute_fds(Manager *m, FDSet *fds) { + Unit *u; + Iterator i; + int r; + + assert(m); + + HASHMAP_FOREACH(u, m->units, i) { + + if (fdset_size(fds) <= 0) + break; + + if (UNIT_VTABLE(u)->distribute_fds) { + r = UNIT_VTABLE(u)->distribute_fds(u, fds); + if (r < 0) + return r; + } + } + + return 0; +} + int manager_reload(Manager *m) { int r, q; FILE *f; diff --git a/src/core/manager.h b/src/core/manager.h index e9de4969b4..cc4edf8f1e 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -272,6 +272,7 @@ int manager_open_serialization(Manager *m, FILE **_f); int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool serialize_jobs); int manager_deserialize(Manager *m, FILE *f, FDSet *fds); +int manager_distribute_fds(Manager *m, FDSet *fds); int manager_reload(Manager *m); diff --git a/src/core/socket.c b/src/core/socket.c index 18b81761c5..324ec1e34b 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1876,6 +1876,34 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value, return 0; } +static int socket_distribute_fds(Unit *u, FDSet *fds) { + Socket *s = SOCKET(u); + SocketPort *p; + + assert(u); + + LIST_FOREACH(port, p, s->ports) { + Iterator i; + int fd; + + if (p->type != SOCKET_SOCKET) + continue; + + if (p->fd >= 0) + continue; + + FDSET_FOREACH(fd, fds, i) { + if (socket_address_matches_fd(&p->address, fd)) { + p->fd = fdset_remove(fds, fd); + s->deserialized_state = SOCKET_LISTENING; + break; + } + } + } + + return 0; +} + static UnitActiveState socket_active_state(Unit *u) { assert(u); @@ -2288,6 +2316,7 @@ const UnitVTable socket_vtable = { .serialize = socket_serialize, .deserialize_item = socket_deserialize_item, + .distribute_fds = socket_distribute_fds, .active_state = socket_active_state, .sub_state_to_string = socket_sub_state_to_string, diff --git a/src/core/unit.h b/src/core/unit.h index b40f034de1..790d3d758e 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -310,6 +310,9 @@ struct UnitVTable { /* Restore one item from the serialization */ int (*deserialize_item)(Unit *u, const char *key, const char *data, FDSet *fds); + /* Try to match up fds with what we need for this unit */ + int (*distribute_fds)(Unit *u, FDSet *fds); + /* Boils down the more complex internal state of this unit to * a simpler one that the engine can understand */ UnitActiveState (*active_state)(Unit *u); -- cgit v1.2.3-54-g00ecf