[systemd-commits] 7 commits - Makefile.am TODO src/core src/nspawn src/shared

Lennart Poettering lennart at kemper.freedesktop.org
Sat Dec 22 13:18:11 PST 2012


 Makefile.am              |    4 +
 TODO                     |    2 
 src/core/fdset.c         |   83 +++++++++++++++++++++++++++--
 src/core/fdset.h         |   12 ++++
 src/core/main.c          |   38 +++++++------
 src/core/manager.c       |   41 +++++++++++++-
 src/core/manager.h       |    1 
 src/core/socket.c        |   57 +++++++++++++++++++-
 src/core/unit.h          |    3 +
 src/nspawn/nspawn.c      |  132 ++++++++++++++++++++++++++++++++++++-----------
 src/shared/socket-util.c |   49 +++++++++++++++++
 src/shared/socket-util.h |    2 
 src/shared/util.h        |    1 
 13 files changed, 365 insertions(+), 60 deletions(-)

New commits:
commit 2d0b0528ace89d378051c280bf3be367b2a7d2de
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Dec 22 22:17:37 2012 +0100

    update TODO

diff --git a/TODO b/TODO
index 8de8560..86f90ea 100644
--- a/TODO
+++ b/TODO
@@ -19,6 +19,8 @@ F18:
 
 Features:
 
+* service: when killing a service with SIGKILL always kill all processes
+
 * rewrite #!/usr/bin/python line in python scripts to use @PYTHON@ instead
 
 * exec: when deinitializating a tty device fix the perms and group, too, not only when initializing. Set access mode/gid to 0620/tty.

commit 57cb4adf4ed61ab9eeb7f190f94d700a56bafad0
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Dec 22 21:21:09 2012 +0100

    nspawn: try to orderly shutdown container when receiving SIGTERM

diff --git a/src/core/manager.c b/src/core/manager.c
index ac11ce1..a3839e1 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1176,7 +1176,8 @@ static int manager_process_signal_fd(Manager *m) {
         assert(m);
 
         for (;;) {
-                if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
+                n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi));
+                if (n != sizeof(sfsi)) {
 
                         if (n >= 0)
                                 return -EIO;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index f5fb59d..1f3bda5 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -817,13 +817,18 @@ static int is_os_tree(const char *path) {
         return r < 0 ? 0 : 1;
 }
 
-static int process_pty(int master, sigset_t *mask) {
+static int process_pty(int master, pid_t pid, sigset_t *mask) {
 
         char in_buffer[LINE_MAX], out_buffer[LINE_MAX];
         size_t in_buffer_full = 0, out_buffer_full = 0;
         struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev;
         bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false;
         int ep = -1, signal_fd = -1, r;
+        bool tried_orderly_shutdown = false;
+
+        assert(master >= 0);
+        assert(pid > 0);
+        assert(mask);
 
         fd_nonblock(STDIN_FILENO, 1);
         fd_nonblock(STDOUT_FILENO, 1);
@@ -940,6 +945,14 @@ static int process_pty(int master, sigset_t *mask) {
                                                 /* The window size changed, let's forward that. */
                                                 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
                                                         ioctl(master, TIOCSWINSZ, &ws);
+                                        } else if (sfsi.ssi_signo == SIGTERM && arg_boot && !tried_orderly_shutdown) {
+
+                                                log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination.");
+
+                                                /* This only works for systemd... */
+                                                tried_orderly_shutdown = true;
+                                                kill(pid, SIGRTMIN+3);
+
                                         } else {
                                                 r = 0;
                                                 goto finish;
@@ -1451,7 +1464,7 @@ int main(int argc, char *argv[]) {
                 fdset_free(fds);
                 fds = NULL;
 
-                if (process_pty(master, &mask) < 0)
+                if (process_pty(master, pid, &mask) < 0)
                         goto finish;
 
                 if (saved_attr_valid)

commit 01e10de3c2b9c2944bd86b12fab83d1164d0b64a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Dec 22 19:30:07 2012 +0100

    socket: support socket activation of containers

diff --git a/src/core/main.c b/src/core/main.c
index 2fcd63d..dfb53a8 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 1ddd8ba..ac11ce1 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 e9de496..cc4edf8 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 18b8176..324ec1e 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 b40f034..790d3d7 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);
diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c
index 42ea545..56ec99f 100644
--- a/src/shared/socket-util.c
+++ b/src/shared/socket-util.c
@@ -515,6 +515,55 @@ bool socket_ipv6_is_supported(void) {
         return enabled;
 }
 
+bool socket_address_matches_fd(const SocketAddress *a, int fd) {
+        union sockaddr_union sa;
+        socklen_t salen = sizeof(sa), solen;
+        int protocol, type;
+
+        assert(a);
+        assert(fd >= 0);
+
+        if (getsockname(fd, &sa.sa, &salen) < 0)
+                return false;
+
+        if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
+                return false;
+
+        solen = sizeof(type);
+        if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
+                return false;
+
+        if (type != a->type)
+                return false;
+
+        if (a->protocol != 0)  {
+                solen = sizeof(protocol);
+                if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
+                        return false;
+
+                if (protocol != a->protocol)
+                        return false;
+        }
+
+        switch (sa.sa.sa_family) {
+
+        case AF_INET:
+                return sa.in4.sin_port == a->sockaddr.in4.sin_port &&
+                        sa.in4.sin_addr.s_addr == a->sockaddr.in4.sin_addr.s_addr;
+
+        case AF_INET6:
+                return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
+                        memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
+
+        case AF_UNIX:
+                return salen == a->size &&
+                        memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
+
+        }
+
+        return false;
+}
+
 static const char* const netlink_family_table[] = {
         [NETLINK_ROUTE] = "route",
         [NETLINK_FIREWALL] = "firewall",
diff --git a/src/shared/socket-util.h b/src/shared/socket-util.h
index 04cfb83..771765d 100644
--- a/src/shared/socket-util.h
+++ b/src/shared/socket-util.h
@@ -86,6 +86,8 @@ int socket_address_listen(
 bool socket_address_is(const SocketAddress *a, const char *s, int type);
 bool socket_address_is_netlink(const SocketAddress *a, const char *s);
 
+bool socket_address_matches_fd(const SocketAddress *a, int fd);
+
 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b);
 
 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix);

commit 842f3b0fc983d9161e152da5b765008e3e6942a8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Dec 22 19:29:04 2012 +0100

    nspawn: allow passing socket activation fds through nspawn

diff --git a/Makefile.am b/Makefile.am
index 429da59..8021c9d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1662,7 +1662,9 @@ systemd_nspawn_SOURCES = \
 	src/core/mount-setup.c \
 	src/core/mount-setup.h \
 	src/core/loopback-setup.c \
-	src/core/loopback-setup.h
+	src/core/loopback-setup.h \
+	src/core/fdset.c \
+	src/core/fdset.h
 
 systemd_nspawn_LDADD = \
 	libsystemd-label.la \
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 4e4c560..f5fb59d 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -55,6 +55,7 @@
 #include "loopback-setup.h"
 #include "sd-id128.h"
 #include "dev-setup.h"
+#include "fdset.h"
 
 typedef enum LinkJournal {
         LINK_NO,
@@ -1041,13 +1042,14 @@ int main(int argc, char *argv[]) {
         int r = EXIT_FAILURE, k;
         char *oldcg = NULL, *newcg = NULL;
         char **controller = NULL;
-        int master = -1;
+        int master = -1, n_fd_passed;
         const char *console = NULL;
         struct termios saved_attr, raw_attr;
         sigset_t mask;
         bool saved_attr_valid = false;
         struct winsize ws;
         int kmsg_socket_pair[2] = { -1, -1 };
+        FDSet *fds = NULL;
 
         log_parse_environment();
         log_open();
@@ -1092,6 +1094,18 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
+        log_close();
+        n_fd_passed = sd_listen_fds(false);
+        if (n_fd_passed > 0) {
+                k = fdset_new_listen_fds(&fds, false);
+                if (k < 0) {
+                        log_error("Failed to collect file descriptors: %s", strerror(-k));
+                        goto finish;
+                }
+        }
+        fdset_close_others(fds);
+        log_open();
+
         k = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &oldcg);
         if (k < 0) {
                 log_error("Failed to determine current cgroup: %s", strerror(-k));
@@ -1180,6 +1194,7 @@ int main(int argc, char *argv[]) {
                         const char *home = NULL;
                         uid_t uid = (uid_t) -1;
                         gid_t gid = (gid_t) -1;
+                        unsigned n_env = 0;
                         const char *envp[] = {
                                 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                                 "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */
@@ -1188,28 +1203,45 @@ int main(int argc, char *argv[]) {
                                 NULL, /* USER */
                                 NULL, /* LOGNAME */
                                 NULL, /* container_uuid */
+                                NULL, /* LISTEN_FDS */
+                                NULL, /* LISTEN_PID */
                                 NULL
                         };
 
                         envp[2] = strv_find_prefix(environ, "TERM=");
+                        n_env = 3;
 
                         close_nointr_nofail(master);
+                        master = -1;
 
                         close_nointr(STDIN_FILENO);
                         close_nointr(STDOUT_FILENO);
                         close_nointr(STDERR_FILENO);
 
-                        close_all_fds(&kmsg_socket_pair[1], 1);
+                        close_nointr_nofail(kmsg_socket_pair[0]);
+                        kmsg_socket_pair[0] = -1;
 
                         reset_all_signal_handlers();
 
                         assert_se(sigemptyset(&mask) == 0);
                         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
 
-                        if (open_terminal(console, O_RDWR) != STDIN_FILENO ||
-                            dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO ||
-                            dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO)
+                        k = open_terminal(console, O_RDWR);
+                        if (k != STDIN_FILENO) {
+                                if (k >= 0) {
+                                        close_nointr_nofail(k);
+                                        k = -EINVAL;
+                                }
+
+                                log_error("Failed to open console: %s", strerror(-k));
+                                goto child_fail;
+                        }
+
+                        if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO ||
+                            dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) {
+                                log_error("Failed to duplicate console: %m");
                                 goto child_fail;
+                        }
 
                         if (setsid() < 0) {
                                 log_error("setsid() failed: %m");
@@ -1256,6 +1288,7 @@ int main(int argc, char *argv[]) {
                                 goto child_fail;
 
                         close_nointr_nofail(kmsg_socket_pair[1]);
+                        kmsg_socket_pair[1] = -1;
 
                         if (setup_boot_id(arg_directory) < 0)
                                 goto child_fail;
@@ -1354,15 +1387,29 @@ int main(int argc, char *argv[]) {
                                 }
                         }
 
-                        if ((asprintf((char**)(envp + 3), "HOME=%s", home ? home: "/root") < 0) ||
-                            (asprintf((char**)(envp + 4), "USER=%s", arg_user ? arg_user : "root") < 0) ||
-                            (asprintf((char**)(envp + 5), "LOGNAME=%s", arg_user ? arg_user : "root") < 0)) {
+                        if ((asprintf((char**)(envp + n_env++), "HOME=%s", home ? home: "/root") < 0) ||
+                            (asprintf((char**)(envp + n_env++), "USER=%s", arg_user ? arg_user : "root") < 0) ||
+                            (asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0)) {
                                 log_oom();
                                 goto child_fail;
                         }
 
                         if (arg_uuid) {
-                                if (asprintf((char**)(envp + 6), "container_uuid=%s", arg_uuid) < 0) {
+                                if (asprintf((char**)(envp + n_env++), "container_uuid=%s", arg_uuid) < 0) {
+                                        log_oom();
+                                        goto child_fail;
+                                }
+                        }
+
+                        if (fdset_size(fds) > 0) {
+                                k = fdset_cloexec(fds, false);
+                                if (k < 0) {
+                                        log_error("Failed to unset O_CLOEXEC for file descriptors.");
+                                        goto child_fail;
+                                }
+
+                                if ((asprintf((char **)(envp + n_env++), "LISTEN_FDS=%u", n_fd_passed) < 0) ||
+                                    (asprintf((char **)(envp + n_env++), "LISTEN_PID=%lu", (unsigned long) getpid()) < 0)) {
                                         log_oom();
                                         goto child_fail;
                                 }
@@ -1401,10 +1448,12 @@ int main(int argc, char *argv[]) {
                         _exit(EXIT_FAILURE);
                 }
 
+                fdset_free(fds);
+                fds = NULL;
+
                 if (process_pty(master, &mask) < 0)
                         goto finish;
 
-
                 if (saved_attr_valid)
                         tcsetattr(STDIN_FILENO, TCSANOW, &saved_attr);
 
@@ -1465,5 +1514,7 @@ finish:
         free(oldcg);
         free(newcg);
 
+        fdset_free(fds);
+
         return r;
 }
diff --git a/src/shared/util.h b/src/shared/util.h
index af18d0b..bf24272 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -46,7 +46,6 @@ union dirent_storage {
                         ((NAME_MAX + 1 + sizeof(long)) & ~(sizeof(long) - 1))];
 };
 
-
 /* What is interpreted as whitespace? */
 #define WHITESPACE " \t\n\r"
 #define NEWLINE "\n\r"

commit e83c71637eb3158ad84e1d4f7c4a1ea37f15c55a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Dec 22 19:28:19 2012 +0100

    fdset: add calls for initializing fdset from socket activation fds

diff --git a/src/core/fdset.c b/src/core/fdset.c
index fe918cd..fd27398 100644
--- a/src/core/fdset.c
+++ b/src/core/fdset.c
@@ -28,6 +28,7 @@
 #include "util.h"
 #include "macro.h"
 #include "fdset.h"
+#include "sd-daemon.h"
 
 #define MAKE_SET(s) ((Set*) s)
 #define MAKE_FDSET(s) ((FDSet*) s)
@@ -75,10 +76,12 @@ int fdset_put_dup(FDSet *s, int fd) {
         assert(s);
         assert(fd >= 0);
 
-        if ((copy = fcntl(fd, F_DUPFD_CLOEXEC, 3)) < 0)
+        copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+        if (copy < 0)
                 return -errno;
 
-        if ((r = fdset_put(s, copy)) < 0) {
+        r = fdset_put(s, copy);
+        if (r < 0) {
                 close_nointr_nofail(copy);
                 return r;
         }
@@ -108,13 +111,15 @@ int fdset_new_fill(FDSet **_s) {
 
         assert(_s);
 
-        /* Creates an fdsets and fills in all currently open file
+        /* Creates an fdset and fills in all currently open file
          * descriptors. */
 
-        if (!(d = opendir("/proc/self/fd")))
+        d = opendir("/proc/self/fd");
+        if (!d)
                 return -errno;
 
-        if (!(s = fdset_new())) {
+        s = fdset_new();
+        if (!s) {
                 r = -ENOMEM;
                 goto finish;
         }
@@ -125,7 +130,8 @@ int fdset_new_fill(FDSet **_s) {
                 if (ignore_file(de->d_name))
                         continue;
 
-                if ((r = safe_atoi(de->d_name, &fd)) < 0)
+                r = safe_atoi(de->d_name, &fd);
+                if (r < 0)
                         goto finish;
 
                 if (fd < 3)
@@ -134,7 +140,8 @@ int fdset_new_fill(FDSet **_s) {
                 if (fd == dirfd(d))
                         continue;
 
-                if ((r = fdset_put(s, fd)) < 0)
+                r = fdset_put(s, fd);
+                if (r < 0)
                         goto finish;
         }
 
@@ -165,3 +172,65 @@ int fdset_cloexec(FDSet *fds, bool b) {
 
         return 0;
 }
+
+int fdset_new_listen_fds(FDSet **_s, bool unset) {
+        int n, fd, r;
+        FDSet *s;
+
+        assert(_s);
+
+        /* Creates an fdset and fills in all passed file descriptors */
+
+        s = fdset_new();
+        if (!s) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        n = sd_listen_fds(unset);
+        for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
+                r = fdset_put(s, fd);
+                if (r < 0)
+                        goto fail;
+        }
+
+        *_s = s;
+        return 0;
+
+
+fail:
+        if (s)
+                set_free(MAKE_SET(s));
+
+        return r;
+}
+
+int fdset_close_others(FDSet *fds) {
+        void *e;
+        Iterator i;
+        int *a;
+        unsigned j, m;
+
+        j = 0, m = fdset_size(fds);
+        a = alloca(sizeof(int) * m);
+        SET_FOREACH(e, MAKE_SET(fds), i)
+                a[j++] = PTR_TO_FD(e);
+
+        assert(j == m);
+
+        return close_all_fds(a, j);
+}
+
+unsigned fdset_size(FDSet *fds) {
+        return set_size(MAKE_SET(fds));
+}
+
+int fdset_iterate(FDSet *s, Iterator *i) {
+        void *p;
+
+        p = set_iterate(MAKE_SET(s), i);
+        if (!p)
+                return -ENOENT;
+
+        return PTR_TO_FD(p);
+}
diff --git a/src/core/fdset.h b/src/core/fdset.h
index c3e408c..a7bd5e2 100644
--- a/src/core/fdset.h
+++ b/src/core/fdset.h
@@ -21,6 +21,8 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "set.h"
+
 typedef struct FDSet FDSet;
 
 FDSet* fdset_new(void);
@@ -33,5 +35,15 @@ bool fdset_contains(FDSet *s, int fd);
 int fdset_remove(FDSet *s, int fd);
 
 int fdset_new_fill(FDSet **_s);
+int fdset_new_listen_fds(FDSet **_s, bool unset);
 
 int fdset_cloexec(FDSet *fds, bool b);
+
+int fdset_close_others(FDSet *fds);
+
+unsigned fdset_size(FDSet *fds);
+
+int fdset_iterate(FDSet *s, Iterator *i);
+
+#define FDSET_FOREACH(fd, fds, i) \
+        for ((i) = ITERATOR_FIRST, (fd) = fdset_iterate((fds), &(i)); (fd) >= 0; (fd) = fdset_iterate((fds), &(i)))

commit ee09281729588900edc06152032a0cc09557f998
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Dec 22 19:25:10 2012 +0100

    socket: properly serialize/desrialize mqueue fds

diff --git a/src/core/socket.c b/src/core/socket.c
index 49e795e..18b8176 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1702,7 +1702,8 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
                 if (p->type == SOCKET_SOCKET) {
                         char *t;
 
-                        if ((r = socket_address_print(&p->address, &t)) < 0)
+                        r = socket_address_print(&p->address, &t);
+                        if (r < 0)
                                 return r;
 
                         if (socket_address_family(&p->address) == AF_NETLINK)
@@ -1712,6 +1713,8 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
                         free(t);
                 } else if (p->type == SOCKET_SPECIAL)
                         unit_serialize_item_format(u, f, "special", "%i %s", copy, p->path);
+                else if (p->type == SOCKET_MQUEUE)
+                        unit_serialize_item_format(u, f, "mqueue", "%i %s", copy, p->path);
                 else {
                         assert(p->type == SOCKET_FIFO);
                         unit_serialize_item_format(u, f, "fifo", "%i %s", copy, p->path);
@@ -1732,7 +1735,8 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
         if (streq(key, "state")) {
                 SocketState state;
 
-                if ((state = socket_state_from_string(value)) < 0)
+                state = socket_state_from_string(value);
+                if (state < 0)
                         log_debug("Failed to parse state value %s", value);
                 else
                         s->deserialized_state = state;
@@ -1808,6 +1812,26 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
                         }
                 }
 
+        } else if (streq(key, "mqueue")) {
+                int fd, skip = 0;
+                SocketPort *p;
+
+                if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
+                        log_debug("Failed to parse mqueue value %s", value);
+                else {
+
+                        LIST_FOREACH(port, p, s->ports)
+                                if (p->type == SOCKET_MQUEUE &&
+                                    streq_ptr(p->path, value+skip))
+                                        break;
+
+                        if (p) {
+                                if (p->fd >= 0)
+                                        close_nointr_nofail(p->fd);
+                                p->fd = fdset_remove(fds, fd);
+                        }
+                }
+
         } else if (streq(key, "socket")) {
                 int fd, type, skip = 0;
                 SocketPort *p;

commit 51d88d1b4fb4ba7c2ecbc72cbbcababb21e4925f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Dec 22 13:11:17 2012 +0100

    nspawn: allow nspawn to be invoked without tty
    
    This allows invoking nspawn containers as systemd services, to create a
    minimal, light-weight OS container solution for servers.

diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 59171ab..4e4c560 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -842,9 +842,19 @@ static int process_pty(int master, sigset_t *mask) {
                 goto finish;
         }
 
-        zero(stdin_ev);
-        stdin_ev.events = EPOLLIN|EPOLLET;
-        stdin_ev.data.fd = STDIN_FILENO;
+        /* We read from STDIN only if this is actually a TTY,
+         * otherwise we assume non-interactivity. */
+        if (isatty(STDIN_FILENO)) {
+                zero(stdin_ev);
+                stdin_ev.events = EPOLLIN|EPOLLET;
+                stdin_ev.data.fd = STDIN_FILENO;
+
+                if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0) {
+                        log_error("Failed to register STDIN in epoll: %m");
+                        r = -errno;
+                        goto finish;
+                }
+        }
 
         zero(stdout_ev);
         stdout_ev.events = EPOLLOUT|EPOLLET;
@@ -858,11 +868,10 @@ static int process_pty(int master, sigset_t *mask) {
         signal_ev.events = EPOLLIN;
         signal_ev.data.fd = signal_fd;
 
-        if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0 ||
-            epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0 ||
+        if (epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0 ||
             epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 ||
             epoll_ctl(ep, EPOLL_CTL_ADD, signal_fd, &signal_ev) < 0) {
-                log_error("Failed to regiser fds in epoll: %m");
+                log_error("Failed to register fds in epoll: %m");
                 r = -errno;
                 goto finish;
         }
@@ -1128,16 +1137,13 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        if (tcgetattr(STDIN_FILENO, &saved_attr) < 0) {
-                log_error("Failed to get terminal attributes: %m");
-                goto finish;
-        }
-
-        saved_attr_valid = true;
+        if (tcgetattr(STDIN_FILENO, &saved_attr) >= 0) {
+                saved_attr_valid = true;
 
-        raw_attr = saved_attr;
-        cfmakeraw(&raw_attr);
-        raw_attr.c_lflag &= ~ECHO;
+                raw_attr = saved_attr;
+                cfmakeraw(&raw_attr);
+                raw_attr.c_lflag &= ~ECHO;
+        }
 
         if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, kmsg_socket_pair) < 0) {
                 log_error("Failed to create kmsg socket pair");
@@ -1151,9 +1157,11 @@ int main(int argc, char *argv[]) {
         for (;;) {
                 siginfo_t status;
 
-                if (tcsetattr(STDIN_FILENO, TCSANOW, &raw_attr) < 0) {
-                        log_error("Failed to set terminal attributes: %m");
-                        goto finish;
+                if (saved_attr_valid) {
+                        if (tcsetattr(STDIN_FILENO, TCSANOW, &raw_attr) < 0) {
+                                log_error("Failed to set terminal attributes: %m");
+                                goto finish;
+                        }
                 }
 
                 pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWIPC|CLONE_NEWNS|CLONE_NEWPID|CLONE_NEWUTS|(arg_private_network ? CLONE_NEWNET : 0), NULL);



More information about the systemd-commits mailing list