#include "unit-name.h"
#include "dbus-socket.h"
#include "missing.h"
+#include "special.h"
+#include "bus-errors.h"
static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
[SOCKET_DEAD] = UNIT_INACTIVE,
s->max_connections = 64;
- s->keep_alive = false;
s->priority = -1;
- s->receive_buffer = 0;
- s->send_buffer = 0;
s->ip_tos = -1;
s->ip_ttl = -1;
- s->pipe_size = 0;
s->mark = -1;
- s->free_bind = false;
exec_context_init(&s->exec_context);
return -EINVAL;
}
- if (s->exec_context.pam_name && s->kill_mode != KILL_CONTROL_GROUP) {
+ if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) {
log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", s->meta.id);
return -EINVAL;
}
if (!socket_needs_mount(s, m->where))
return 0;
- if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(s), true)) < 0)
- return r;
-
- if ((r = unit_add_dependency(UNIT(s), UNIT_REQUIRES, UNIT(m), true)) < 0)
+ if ((r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
return r;
return 0;
return r;
}
+static int socket_add_default_dependencies(Socket *s) {
+ int r;
+ assert(s);
+
+ if (s->meta.manager->running_as == MANAGER_SYSTEM)
+ if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
+ return r;
+
+ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+}
+
static int socket_load(Unit *u) {
Socket *s = SOCKET(u);
int r;
if (u->meta.load_state == UNIT_LOADED) {
if (have_non_accept_socket(s)) {
- if ((r = unit_load_related_unit(u, ".service", (Unit**) &s->service)))
+ if ((r = unit_load_related_unit(u, ".service", (Unit**) &s->service)) < 0)
return r;
if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(s->service), true)) < 0)
if ((r = unit_add_default_cgroup(u)) < 0)
return r;
+
+ if (s->meta.default_dependencies)
+ if ((r = socket_add_default_dependencies(s)) < 0)
+ return r;
}
return socket_verify(s);
"%sSocket State: %s\n"
"%sBindIPv6Only: %s\n"
"%sBacklog: %u\n"
- "%sKillMode: %s\n"
"%sSocketMode: %04o\n"
"%sDirectoryMode: %04o\n"
"%sKeepAlive: %s\n"
prefix, socket_state_to_string(s->state),
prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only),
prefix, s->backlog,
- prefix, kill_mode_to_string(s->kill_mode),
prefix, s->socket_mode,
prefix, s->directory_mode,
prefix, yes_no(s->keep_alive),
if (setsockopt(fd, IPPROTO_IP, IP_TOS, &s->ip_tos, sizeof(s->ip_tos)) < 0)
log_warning("IP_TOS failed: %m");
- if (s->ip_ttl >= 0)
- if (setsockopt(fd, IPPROTO_IP, IP_TTL, &s->ip_ttl, sizeof(s->ip_ttl)) < 0)
- log_warning("IP_TTL failed: %m");
+ if (s->ip_ttl >= 0) {
+ int r, x;
+
+ r = setsockopt(fd, IPPROTO_IP, IP_TTL, &s->ip_ttl, sizeof(s->ip_ttl));
+ x = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &s->ip_ttl, sizeof(s->ip_ttl));
+
+ if (r < 0 && x < 0)
+ log_warning("IP_TTL/IPV6_UNICAST_HOPS failed: %m");
+ }
}
static void socket_apply_pipe_options(Socket *s, int fd) {
s->meta.manager->environment,
true,
true,
+ true,
s->meta.manager->confirm_spawn,
s->meta.cgroup_bondings,
&pid);
if (!success)
s->failure = true;
- if (s->kill_mode != KILL_NONE) {
- int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? SIGTERM : SIGKILL;
+ 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_mode == KILL_CONTROL_GROUP) {
+ if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) {
if ((r = cgroup_bonding_kill_list(s->meta.cgroup_bondings, sig)) < 0) {
if (r != -EAGAIN && r != -ESRCH)
}
if (!sent && s->control_pid > 0)
- if (kill(s->kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH) {
+ if (kill(s->exec_context.kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH) {
r = -errno;
goto fail;
}
static void socket_enter_running(Socket *s, int cfd) {
int r;
+ DBusError error;
assert(s);
+ dbus_error_init(&error);
if (cfd < 0) {
- if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, NULL)) < 0)
+ 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 {
Unit *u;
- char *prefix, *instance, *name;
+ char *prefix, *instance = NULL, *name;
if (s->n_connections >= s->max_connections) {
log_warning("Too many incoming connections (%u)", s->n_connections);
goto fail;
}
- r = manager_load_unit(s->meta.manager, name, NULL, &u);
+ r = manager_load_unit(s->meta.manager, name, NULL, NULL, &u);
free(name);
if (r < 0)
s->n_connections ++;
- if ((r = manager_add_job(u->meta.manager, JOB_START, u, JOB_REPLACE, true, NULL)) < 0)
+ if ((r = manager_add_job(u->meta.manager, JOB_START, u, JOB_REPLACE, true, &error, NULL)) < 0)
goto fail;
}
return;
fail:
- log_warning("%s failed to queue socket startup job: %s", s->meta.id, strerror(-r));
+ log_warning("%s failed to queue socket startup job: %s", s->meta.id, bus_error(&error, r));
socket_enter_stop_pre(s, false);
if (cfd >= 0)
close_nointr_nofail(cfd);
+
+ dbus_error_free(&error);
}
static void socket_run_next(Socket *s, bool success) {
assert(s);
- /* We cannot fulfill this request right now, try again later
- * please! */
- if (s->state == SOCKET_START_PRE ||
- s->state == SOCKET_START_POST)
- return -EAGAIN;
-
/* Already on it */
if (s->state == SOCKET_STOP_PRE ||
s->state == SOCKET_STOP_PRE_SIGTERM ||
s->state == SOCKET_STOP_PRE_SIGKILL ||
s->state == SOCKET_STOP_POST ||
s->state == SOCKET_FINAL_SIGTERM ||
- s->state == SOCKET_FINAL_SIGTERM)
+ s->state == SOCKET_FINAL_SIGKILL)
return 0;
+ /* If there's already something running we go directly into
+ * kill mode. */
+ if (s->state == SOCKET_START_PRE ||
+ s->state == SOCKET_START_POST) {
+ socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, true);
+ return -EAGAIN;
+ }
+
assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING);
socket_enter_stop_pre(s, true);
s->failure = s->failure || !success;
if (s->control_command)
- exec_status_fill(&s->control_command->exec_status, pid, code, status);
+ exec_status_exit(&s->control_command->exec_status, pid, code, status);
log_debug("%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);