X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fsocket.c;h=324ec1e34bd03f0333f33f9aa7260e1fd09f54e8;hp=5b24b3422b8e9a2de77344e4d14131c17d980798;hb=01e10de3c2b9c2944bd86b12fab83d1164d0b64a;hpb=b30e2f4c18ad81b04e4314fd191a5d458553773c
diff --git a/src/core/socket.c b/src/core/socket.c
index 5b24b3422..324ec1e34 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -6,16 +6,16 @@
Copyright 2010 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see .
***/
@@ -28,6 +28,9 @@
#include
#include
#include
+#ifdef HAVE_ATTR_XATTR_H
+#include
+#endif
#include "unit.h"
#include "socket.h"
@@ -37,7 +40,9 @@
#include "load-fragment.h"
#include "strv.h"
#include "mkdir.h"
+#include "path-util.h"
#include "unit-name.h"
+#include "unit-printf.h"
#include "dbus-socket.h"
#include "missing.h"
#include "special.h"
@@ -82,6 +87,7 @@ static void socket_init(Unit *u) {
exec_context_init(&s->exec_context);
s->exec_context.std_output = u->manager->default_std_output;
s->exec_context.std_error = u->manager->default_std_error;
+ kill_context_init(&s->kill_context);
s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
}
@@ -128,6 +134,10 @@ static void socket_done(Unit *u) {
free(s->bind_to_device);
s->bind_to_device = NULL;
+ free(s->smack);
+ free(s->smack_ip_in);
+ free(s->smack_ip_out);
+
unit_unwatch_timer(u, &s->timer_watch);
}
@@ -164,7 +174,7 @@ static int socket_instantiate_service(Socket *s) {
return r;
#ifdef HAVE_SYSV_COMPAT
- if (SERVICE(u)->sysv_path) {
+ if (SERVICE(u)->is_sysv) {
log_error("Using SysV services for socket activation is not supported. Refusing.");
return -ENOENT;
}
@@ -222,7 +232,7 @@ static int socket_verify(Socket *s) {
return -EINVAL;
}
- if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) {
+ if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
return -EINVAL;
}
@@ -262,7 +272,8 @@ int socket_add_one_mount_link(Socket *s, Mount *m) {
if (!socket_needs_mount(s, m->where))
return 0;
- if ((r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
+ r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true);
+ if (r < 0)
return r;
return 0;
@@ -274,9 +285,11 @@ static int socket_add_mount_links(Socket *s) {
assert(s);
- LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_type[UNIT_MOUNT])
- if ((r = socket_add_one_mount_link(s, MOUNT(other))) < 0)
+ LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_type[UNIT_MOUNT]) {
+ r = socket_add_one_mount_link(s, MOUNT(other));
+ if (r < 0)
return r;
+ }
return 0;
}
@@ -303,7 +316,7 @@ static int socket_add_default_dependencies(Socket *s) {
int r;
assert(s);
- if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
+ if (UNIT(s)->manager->running_as == SYSTEMD_SYSTEM) {
if ((r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0)
return r;
@@ -371,6 +384,10 @@ static int socket_load(Unit *u) {
if (UNIT(s)->default_dependencies)
if ((r = socket_add_default_dependencies(s)) < 0)
return r;
+
+ r = unit_exec_context_defaults(u, &s->exec_context);
+ if (r < 0)
+ return r;
}
return socket_verify(s);
@@ -498,6 +515,21 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
"%sMessageQueueMessageSize: %li\n",
prefix, s->mq_msgsize);
+ if (s->smack)
+ fprintf(f,
+ "%sSmackLabel: %s\n",
+ prefix, s->smack);
+
+ if (s->smack_ip_in)
+ fprintf(f,
+ "%sSmackLabelIPIn: %s\n",
+ prefix, s->smack_ip_in);
+
+ if (s->smack_ip_out)
+ fprintf(f,
+ "%sSmackLabelIPOut: %s\n",
+ prefix, s->smack_ip_out);
+
LIST_FOREACH(port, p, s->ports) {
if (p->type == SOCKET_SOCKET) {
@@ -521,6 +553,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
}
exec_context_dump(&s->exec_context, f, prefix);
+ kill_context_dump(&s->kill_context, f, prefix);
for (c = 0; c < _SOCKET_EXEC_COMMAND_MAX; c++) {
if (!s->exec_command[c])
@@ -577,7 +610,7 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) {
}
case AF_INET6: {
- static const char ipv4_prefix[] = {
+ static const unsigned char ipv4_prefix[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
};
@@ -736,6 +769,16 @@ static void socket_apply_socket_options(Socket *s, int fd) {
if (s->tcp_congestion)
if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0)
log_warning("TCP_CONGESTION failed: %m");
+
+#ifdef HAVE_ATTR_XATTR_H
+ if (s->smack_ip_in)
+ if (fsetxattr(fd, "security.SMACK64IPIN", s->smack_ip_in, strlen(s->smack_ip_in), 0) < 0)
+ log_error("fsetxattr(\"security.SMACK64IPIN\"): %m");
+
+ if (s->smack_ip_out)
+ if (fsetxattr(fd, "security.SMACK64IPOUT", s->smack_ip_out, strlen(s->smack_ip_out), 0) < 0)
+ log_error("fsetxattr(\"security.SMACK64IPOUT\"): %m");
+#endif
}
static void socket_apply_fifo_options(Socket *s, int fd) {
@@ -745,6 +788,12 @@ static void socket_apply_fifo_options(Socket *s, int fd) {
if (s->pipe_size > 0)
if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0)
log_warning("F_SETPIPE_SZ: %m");
+
+#ifdef HAVE_ATTR_XATTR_H
+ if (s->smack)
+ if (fsetxattr(fd, "security.SMACK64", s->smack, strlen(s->smack), 0) < 0)
+ log_error("fsetxattr(\"security.SMACK64\"): %m");
+#endif
}
static int fifo_address_create(
@@ -760,9 +809,10 @@ static int fifo_address_create(
assert(path);
assert(_fd);
- mkdir_parents(path, directory_mode);
+ mkdir_parents_label(path, directory_mode);
- if ((r = label_fifofile_set(path)) < 0)
+ r = label_context_set(path, S_IFIFO);
+ if (r < 0)
goto fail;
/* Enforce the right access mode for the fifo */
@@ -784,7 +834,7 @@ static int fifo_address_create(
goto fail;
}
- label_file_clear();
+ label_context_clear();
if (fstat(fd, &st) < 0) {
r = -errno;
@@ -804,7 +854,7 @@ static int fifo_address_create(
return 0;
fail:
- label_file_clear();
+ label_context_clear();
if (fd >= 0)
close_nointr_nofail(fd);
@@ -1096,10 +1146,12 @@ static int socket_coldplug(Unit *u) {
if (s->control_pid <= 0)
return -EBADMSG;
- if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0)
+ r = unit_watch_pid(UNIT(s), s->control_pid);
+ if (r < 0)
return r;
- if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+ r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch);
+ if (r < 0)
return r;
}
@@ -1131,10 +1183,12 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
assert(c);
assert(_pid);
- if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+ r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch);
+ if (r < 0)
goto fail;
- if (!(argv = unit_full_printf_strv(UNIT(s), c->argv))) {
+ argv = unit_full_printf_strv(UNIT(s), c->argv);
+ if (!argv) {
r = -ENOMEM;
goto fail;
}
@@ -1150,6 +1204,9 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
UNIT(s)->manager->confirm_spawn,
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
+ NULL,
+ UNIT(s)->id,
+ NULL,
&pid);
strv_free(argv);
@@ -1217,8 +1274,8 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
if (f != SOCKET_SUCCESS)
s->result = f;
- if (s->exec_context.kill_mode != KILL_NONE) {
- int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
+ if (s->kill_context.kill_mode != KILL_NONE) {
+ int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? s->kill_context.kill_signal : SIGKILL;
if (s->control_pid > 0) {
if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
@@ -1228,7 +1285,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
wait_for_exit = true;
}
- if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) {
+ if (s->kill_context.kill_mode == KILL_CONTROL_GROUP) {
if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
r = -ENOMEM;
@@ -1240,7 +1297,8 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
goto fail;
- if ((r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, pid_set)) < 0) {
+ r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, false, pid_set, NULL);
+ if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_warning("Failed to kill control group: %s", strerror(-r));
} else if (r > 0)
@@ -1252,7 +1310,8 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
}
if (wait_for_exit) {
- if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+ r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch);
+ if (r < 0)
goto fail;
socket_set_state(s, state);
@@ -1425,7 +1484,7 @@ static void socket_enter_running(Socket *s, int cfd) {
Service *service;
if (s->n_connections >= s->max_connections) {
- log_warning("Too many incoming connections (%u)", s->n_connections);
+ log_warning("%s: Too many incoming connections (%u)", UNIT(s)->id, s->n_connections);
close_nointr_nofail(cfd);
return;
}
@@ -1494,7 +1553,7 @@ static void socket_enter_running(Socket *s, int cfd) {
return;
fail:
- log_warning("%s failed to queue socket startup job: %s", UNIT(s)->id, bus_error(&error, r));
+ log_warning("%s failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s", UNIT(s)->id, cfd >= 0 ? "template" : "non-template", bus_error(&error, r));
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
if (cfd >= 0)
@@ -1570,7 +1629,7 @@ static int socket_start(Unit *u) {
}
#ifdef HAVE_SYSV_COMPAT
- if (service->sysv_path) {
+ if (service->is_sysv) {
log_error("Using SysV services for socket activation is not supported. Refusing.");
return -ENOENT;
}
@@ -1643,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)
@@ -1653,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);
@@ -1673,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;
@@ -1749,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;
@@ -1793,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);
@@ -1838,7 +1949,8 @@ static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
if (w->socket_accept) {
for (;;) {
- if ((cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK)) < 0) {
+ cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK);
+ if (cfd < 0) {
if (errno == EINTR)
continue;
@@ -1872,7 +1984,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_pid = 0;
- if (is_clean_exit(code, status))
+ if (is_clean_exit(code, status, NULL))
f = SOCKET_SUCCESS;
else if (code == CLD_EXITED)
f = SOCKET_FAILURE_EXIT_CODE;
@@ -1973,7 +2085,7 @@ static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
break;
case SOCKET_STOP_PRE_SIGTERM:
- if (s->exec_context.send_sigkill) {
+ if (s->kill_context.send_sigkill) {
log_warning("%s stopping timed out. Killing.", u->id);
socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_FAILURE_TIMEOUT);
} else {
@@ -1993,7 +2105,7 @@ static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
break;
case SOCKET_FINAL_SIGTERM:
- if (s->exec_context.send_sigkill) {
+ if (s->kill_context.send_sigkill) {
log_warning("%s stopping timed out (2). Killing.", u->id);
socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_FAILURE_TIMEOUT);
} else {
@@ -2092,7 +2204,7 @@ static void socket_reset_failed(Unit *u) {
s->result = SOCKET_SUCCESS;
}
-static int socket_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
+static int socket_kill(Unit *u, KillWho who, int signo, DBusError *error) {
Socket *s = SOCKET(u);
int r = 0;
Set *pid_set = NULL;
@@ -2114,22 +2226,25 @@ static int socket_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError
if (kill(s->control_pid, signo) < 0)
r = -errno;
- if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
+ if (who == KILL_ALL) {
int q;
- if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
+ pid_set = set_new(trivial_hash_func, trivial_compare_func);
+ if (!pid_set)
return -ENOMEM;
/* Exclude the control pid from being killed via the cgroup */
- if (s->control_pid > 0)
- if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) {
+ if (s->control_pid > 0) {
+ q = set_put(pid_set, LONG_TO_PTR(s->control_pid));
+ if (q < 0) {
r = q;
goto finish;
}
+ }
- if ((q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, pid_set)) < 0)
- if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
- r = q;
+ q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, false, pid_set, NULL);
+ if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+ r = q;
}
finish:
@@ -2178,8 +2293,9 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult);
const UnitVTable socket_vtable = {
- .suffix = ".socket",
.object_size = sizeof(Socket),
+ .exec_context_offset = offsetof(Socket, exec_context),
+
.sections =
"Unit\0"
"Socket\0"
@@ -2200,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,
@@ -2214,5 +2331,23 @@ const UnitVTable socket_vtable = {
.bus_interface = "org.freedesktop.systemd1.Socket",
.bus_message_handler = bus_socket_message_handler,
- .bus_invalidating_properties = bus_socket_invalidating_properties
+ .bus_invalidating_properties = bus_socket_invalidating_properties,
+
+ .status_message_formats = {
+ /*.starting_stopping = {
+ [0] = "Starting socket %s...",
+ [1] = "Stopping socket %s...",
+ },*/
+ .finished_start_job = {
+ [JOB_DONE] = "Listening on %s.",
+ [JOB_FAILED] = "Failed to listen on %s.",
+ [JOB_DEPENDENCY] = "Dependency failed for %s.",
+ [JOB_TIMEOUT] = "Timed out starting %s.",
+ },
+ .finished_stop_job = {
+ [JOB_DONE] = "Closed %s.",
+ [JOB_FAILED] = "Failed stopping %s.",
+ [JOB_TIMEOUT] = "Timed out stopping %s.",
+ },
+ },
};