Commit f976f3f6 authored by Lennart Poettering's avatar Lennart Poettering
Browse files

socket: make sockets to pass to a service configurable

parent d9ff321a
v11:
* have a simple syslog bridge providing /dev/log and forward messages
to /dev/kmsg. at the moment the real syslog can be started, the bridge
is stopped and the open /dev/log fd to the real syslog. that way we
don't lose any early log message, and simple systems have full syslog
support in the kernel ringbuffer, without any syslog service or disk
access
* emergency.service should start default.target after C-d. synchronize from fedora's initscripts package
* verify ordering of random-seed-load and base.target!
......@@ -108,6 +101,12 @@ later:
* beefed up tmpwatch that reads tmpfiles.d
* /lib/systemd/system/systemd-readahead-replay.service
* use /sbin/swapon
* enable syslog.socket by default, activating our kmsg bridge
External:
* place /etc/inittab with explaining blurb.
......
......@@ -1246,8 +1246,8 @@ static int config_parse_socket_service(
dbus_error_init(&error);
if (endswith(rvalue, ".service")) {
log_error("[%s:%u] Unit must be of type serivce, ignoring: %s", filename, line, rvalue);
if (!endswith(rvalue, ".service")) {
log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
return 0;
}
......@@ -1260,6 +1260,60 @@ static int config_parse_socket_service(
return 0;
}
static int config_parse_service_sockets(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
const char *rvalue,
void *data,
void *userdata) {
Service *s = data;
int r;
DBusError error;
char *state, *w;
size_t l;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
dbus_error_init(&error);
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
char *t;
Unit *sock;
if (!(t = strndup(w, l)))
return -ENOMEM;
if (!endswith(t, ".socket")) {
log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
free(t);
continue;
}
r = manager_load_unit(s->meta.manager, t, NULL, &error, &sock);
free(t);
if (r < 0) {
log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
dbus_error_free(&error);
continue;
}
if ((r = set_ensure_allocated(&s->configured_sockets, trivial_hash_func, trivial_compare_func)) < 0)
return r;
if ((r = set_put(s->configured_sockets, sock)) < 0)
return r;
}
return 0;
}
static int config_parse_env_file(
const char *filename,
unsigned line,
......@@ -1655,11 +1709,12 @@ static int load_from_path(Unit *u, const char *path) {
#ifdef HAVE_SYSV_COMPAT
{ "SysVStartPriority", config_parse_sysv_priority, &u->service.sysv_start_priority, "Service" },
#else
{ "SysVStartPriority", config_parse_warn_compat, NULL, "Service" },
{ "SysVStartPriority", config_parse_warn_compat, NULL, "Service" },
#endif
{ "NonBlocking", config_parse_bool, &u->service.exec_context.non_blocking, "Service" },
{ "BusName", config_parse_string_printf, &u->service.bus_name, "Service" },
{ "NotifyAccess", config_parse_notify_access, &u->service.notify_access, "Service" },
{ "Sockets", config_parse_service_sockets, &u->service, "Service" },
EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"),
{ "ListenStream", config_parse_listen, &u->socket, "Socket" },
......
......@@ -178,11 +178,11 @@ static void service_close_socket_fd(Service *s) {
static void service_connection_unref(Service *s) {
assert(s);
if (!s->socket)
if (!s->accept_socket)
return;
socket_connection_unref(s->socket);
s->socket = NULL;
socket_connection_unref(s->accept_socket);
s->accept_socket = NULL;
}
static void service_done(Unit *u) {
......@@ -222,6 +222,8 @@ static void service_done(Unit *u) {
service_close_socket_fd(s);
service_connection_unref(s);
set_free(s->configured_sockets);
unit_unwatch_timer(u, &s->timer_watch);
}
......@@ -1177,6 +1179,9 @@ static int service_get_sockets(Service *s, Set **_set) {
if (s->socket_fd >= 0)
return 0;
if (!set_isempty(s->configured_sockets))
return 0;
/* Collects all Socket objects that belong to this
* service. Note that a service might have multiple sockets
* via multiple names. */
......@@ -1216,23 +1221,30 @@ fail:
static int service_notify_sockets_dead(Service *s) {
Iterator i;
Set *set;
Set *set, *free_set = NULL;
Socket *sock;
int r;
assert(s);
/* Notifies all our sockets when we die */
if (s->socket_fd >= 0)
return 0;
/* Notifies all our sockets when we die */
if ((r = service_get_sockets(s, &set)) < 0)
return r;
if (!set_isempty(s->configured_sockets))
set = s->configured_sockets;
else {
if ((r = service_get_sockets(s, &free_set)) < 0)
return r;
set = free_set;
}
SET_FOREACH(sock, set, i)
socket_notify_service_dead(sock);
set_free(set);
set_free(free_set);
return 0;
}
......@@ -1390,7 +1402,7 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
int r;
int *rfds = NULL;
unsigned rn_fds = 0;
Set *set;
Set *set, *free_set = NULL;
Socket *sock;
assert(s);
......@@ -1400,8 +1412,14 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
if (s->socket_fd >= 0)
return 0;
if ((r = service_get_sockets(s, &set)) < 0)
return r;
if (!set_isempty(s->configured_sockets))
set = s->configured_sockets;
else {
if ((r = service_get_sockets(s, &free_set)) < 0)
return r;
set = free_set;
}
SET_FOREACH(sock, set, i) {
int *cfds;
......@@ -1438,7 +1456,7 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
*fds = rfds;
*n_fds = rn_fds;
set_free(set);
set_free(free_set);
return 0;
......@@ -2084,14 +2102,6 @@ static int service_start(Unit *u) {
return -ECANCELED;
}
if ((s->exec_context.std_input == EXEC_INPUT_SOCKET ||
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
s->exec_context.std_error == EXEC_OUTPUT_SOCKET) &&
s->socket_fd < 0) {
log_warning("%s can only be started with a per-connection socket.", u->meta.id);
return -EINVAL;
}
s->failure = false;
s->main_pid_known = false;
s->forbid_restart = false;
......@@ -3062,7 +3072,7 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock) {
s->socket_fd = fd;
s->got_socket_fd = true;
s->socket = sock;
s->accept_socket = sock;
return 0;
}
......
......@@ -133,7 +133,8 @@ struct Service {
RateLimit ratelimit;
struct Socket *socket;
struct Socket *accept_socket;
Set *configured_sockets;
Watch timer_watch;
......
......@@ -129,8 +129,10 @@ static void socket_done(Unit *u) {
LIST_FOREACH(units_per_type, i, u->meta.manager->units_per_type[UNIT_SERVICE]) {
Service *service = (Service *) i;
if (service->socket == s)
service->socket = NULL;
if (service->accept_socket == s)
service->accept_socket = NULL;
set_remove(service->configured_sockets, s);
}
}
......@@ -1197,8 +1199,27 @@ static void socket_enter_running(Socket *s, int cfd) {
}
if (cfd < 0) {
if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, &error, NULL)) < 0)
goto fail;
bool pending = false;
Meta *i;
/* If there's already a start pending don't bother to
* do anything */
LIST_FOREACH(units_per_type, i, s->meta.manager->units_per_type[UNIT_SERVICE]) {
Service *service = (Service *) i;
if (!set_get(service->configured_sockets, s))
continue;
if (!unit_pending_active(UNIT(service)))
continue;
pending = true;
break;
}
if (!pending)
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 {
......
......@@ -2190,6 +2190,23 @@ bool unit_pending_inactive(Unit *u) {
return false;
}
bool unit_pending_active(Unit *u) {
assert(u);
/* Returns true if the unit is inactive or going down */
if (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
return true;
if (u->meta.job &&
(u->meta.job->type == JOB_START ||
u->meta.job->type == JOB_RELOAD_OR_START ||
u->meta.job->type == JOB_RESTART))
return true;
return false;
}
static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
[UNIT_STUB] = "stub",
[UNIT_LOADED] = "loaded",
......
......@@ -500,6 +500,7 @@ void unit_reset_failed(Unit *u);
Unit *unit_following(Unit *u);
bool unit_pending_inactive(Unit *u);
bool unit_pending_active(Unit *u);
int unit_add_default_target_dependency(Unit *u, Unit *target);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment