#include "special.h"
#include "bus-errors.h"
#include "label.h"
+#include "exit-status.h"
+#include "def.h"
static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
[SOCKET_DEAD] = UNIT_INACTIVE,
s->backlog = SOMAXCONN;
s->timeout_usec = DEFAULT_TIMEOUT_USEC;
s->directory_mode = 0755;
- s->socket_mode = 0666;
+ s->socket_mode = 0777;
s->max_connections = 64;
s->mark = -1;
exec_context_init(&s->exec_context);
+ s->exec_context.std_output = u->meta.manager->default_std_output;
+ s->exec_context.std_error = u->meta.manager->default_std_error;
s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
}
if (r < 0)
return r;
+#ifdef HAVE_SYSV_COMPAT
+ if (SERVICE(u)->sysv_path) {
+ log_error("Using SysV services for socket activation is not supported. Refusing.");
+ return -ENOENT;
+ }
+#endif
+
u->meta.no_gc = true;
s->service = SERVICE(u);
return 0;
int r;
assert(s);
- if (s->meta.manager->running_as == MANAGER_SYSTEM)
+ if (s->meta.manager->running_as == MANAGER_SYSTEM) {
+ if ((r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0)
+ return r;
+
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_CONFLICTED_BY, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
}
static int socket_load(Unit *u) {
if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
return r;
- if ((r = unit_add_default_cgroup(u)) < 0)
+ if ((r = unit_add_default_cgroups(u)) < 0)
return r;
if (s->meta.default_dependencies)
return socket_verify(s);
}
-static const char* listen_lookup(int type) {
+static const char* listen_lookup(int family, int type) {
+
+ if (family == AF_NETLINK)
+ return "ListenNetlink";
if (type == SOCK_STREAM)
return "ListenStream";
else
t = k;
- fprintf(f, "%s%s: %s\n", prefix, listen_lookup(p->address.type), t);
+ fprintf(f, "%s%s: %s\n", prefix, listen_lookup(socket_address_family(&p->address), p->address.type), t);
free(k);
} else
fprintf(f, "%sListenFIFO: %s\n", prefix, p->path);
if ((r = socket_instantiate_service(s)) < 0)
return r;
- if ((r = label_get_socket_label_from_exe(s->service->exec_command[SERVICE_EXEC_START]->path, &label)) < 0)
- return r;
+ if (s->service && s->service->exec_command[SERVICE_EXEC_START])
+ if ((r = label_get_socket_label_from_exe(s->service->exec_command[SERVICE_EXEC_START]->path, &label)) < 0) {
+ if (r != -EPERM)
+ return r;
+ }
know_label = true;
}
socket_state_to_string(old_state),
socket_state_to_string(state));
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
+ unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
}
static int socket_coldplug(Unit *u) {
int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
if (s->control_pid > 0) {
- if (kill(s->exec_context.kill_mode == KILL_PROCESS_GROUP ?
- -s->control_pid :
- s->control_pid, sig) < 0 && errno != ESRCH)
+ if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
else
if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
goto fail;
- if ((r = cgroup_bonding_kill_list(s->meta.cgroup_bondings, sig, pid_set)) < 0) {
+ if ((r = cgroup_bonding_kill_list(s->meta.cgroup_bondings, sig, true, pid_set)) < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_warning("Failed to kill control group: %s", strerror(-r));
} else if (r > 0)
wait_for_exit = true;
set_free(pid_set);
+ pid_set = NULL;
}
}
/* We don't take connections anymore if we are supposed to
* shut down anyway */
if (unit_pending_inactive(UNIT(s))) {
+ log_debug("Suppressing connection request on %s since unit stop is scheduled.", s->meta.id);
+
if (cfd >= 0)
close_nointr_nofail(cfd);
else {
/* Cannot run this without the service being around */
if (s->service) {
- if (s->service->meta.load_state != UNIT_LOADED)
+ if (s->service->meta.load_state != UNIT_LOADED) {
+ log_error("Socket service %s not loaded, refusing.", s->service->meta.id);
return -ENOENT;
+ }
- /* If the service is alredy actvie we cannot start the
+ /* If the service is already active we cannot start the
* socket */
if (s->service->state != SERVICE_DEAD &&
s->service->state != SERVICE_FAILED &&
- s->service->state != SERVICE_AUTO_RESTART)
+ s->service->state != SERVICE_AUTO_RESTART) {
+ log_error("Socket service %s already active, refusing.", s->service->meta.id);
return -EBUSY;
+ }
+
+#ifdef HAVE_SYSV_COMPAT
+ if (s->service->sysv_path) {
+ log_error("Using SysV services for socket activation is not supported. Refusing.");
+ return -ENOENT;
+ }
+#endif
}
assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED);
if ((r = socket_address_print(&p->address, &t)) < 0)
return r;
- unit_serialize_item_format(u, f, "socket", "%i %i %s", copy, p->address.type, t);
+ if (socket_address_family(&p->address) == AF_NETLINK)
+ unit_serialize_item_format(u, f, "netlink", "%i %s", copy, t);
+ else
+ unit_serialize_item_format(u, f, "socket", "%i %i %s", copy, p->address.type, t);
free(t);
} else {
assert(p->type == SOCKET_FIFO);
}
}
+ } else if (streq(key, "netlink")) {
+ 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 socket value %s", value);
+ else {
+
+ LIST_FOREACH(port, p, s->ports)
+ if (socket_address_is_netlink(&p->address, value+skip))
+ break;
+
+ if (p) {
+ if (p->fd >= 0)
+ close_nointr_nofail(p->fd);
+ p->fd = fdset_remove(fds, fd);
+ }
+ }
+
} else
log_debug("Unknown serialization key '%s'", key);
case SOCKET_START_PRE:
log_warning("%s starting timed out. Terminating.", u->meta.id);
socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
+ break;
case SOCKET_START_POST:
log_warning("%s starting timed out. Stopping.", u->meta.id);
break;
case SOCKET_STOP_PRE_SIGTERM:
- log_warning("%s stopping timed out. Killing.", u->meta.id);
- socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, false);
+ if (s->exec_context.send_sigkill) {
+ log_warning("%s stopping timed out. Killing.", u->meta.id);
+ socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, false);
+ } else {
+ log_warning("%s stopping timed out. Skipping SIGKILL. Ignoring.", u->meta.id);
+ socket_enter_stop_post(s, false);
+ }
break;
case SOCKET_STOP_PRE_SIGKILL:
break;
case SOCKET_FINAL_SIGTERM:
- log_warning("%s stopping timed out (2). Killing.", u->meta.id);
- socket_enter_signal(s, SOCKET_FINAL_SIGKILL, false);
+ if (s->exec_context.send_sigkill) {
+ log_warning("%s stopping timed out (2). Killing.", u->meta.id);
+ socket_enter_signal(s, SOCKET_FINAL_SIGKILL, false);
+ } else {
+ log_warning("%s stopping timed out (2). Skipping SIGKILL. Ignoring.", u->meta.id);
+ socket_enter_dead(s, false);
+ }
break;
case SOCKET_FINAL_SIGKILL:
/* The service is dead. Yay!
*
- * This is strictly for one-onstance-per-connection
+ * This is strictly for one-instance-per-connection
* services. */
assert(s->n_connections > 0);
}
if (s->control_pid > 0)
- if (kill(mode == KILL_PROCESS_GROUP ? -s->control_pid : s->control_pid, signo) < 0)
+ if (kill(s->control_pid, signo) < 0)
r = -errno;
if (mode == KILL_CONTROL_GROUP) {
goto finish;
}
- if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, pid_set)) < 0)
+ if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, false, pid_set)) < 0)
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
r = q;
}