[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