1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-25 23:21:33 +03:00

socket: make sockets to pass to a service configurable

This commit is contained in:
Lennart Poettering 2010-10-05 19:49:15 +02:00
parent d9ff321ad9
commit f976f3f67c
7 changed files with 140 additions and 36 deletions

13
fixme
View File

@ -1,12 +1,5 @@
v11: 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 * emergency.service should start default.target after C-d. synchronize from fedora's initscripts package
* verify ordering of random-seed-load and base.target! * verify ordering of random-seed-load and base.target!
@ -108,6 +101,12 @@ later:
* beefed up tmpwatch that reads tmpfiles.d * 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: External:
* place /etc/inittab with explaining blurb. * place /etc/inittab with explaining blurb.

View File

@ -1246,8 +1246,8 @@ static int config_parse_socket_service(
dbus_error_init(&error); dbus_error_init(&error);
if (endswith(rvalue, ".service")) { if (!endswith(rvalue, ".service")) {
log_error("[%s:%u] Unit must be of type serivce, ignoring: %s", filename, line, rvalue); log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
return 0; return 0;
} }
@ -1260,6 +1260,60 @@ static int config_parse_socket_service(
return 0; 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( static int config_parse_env_file(
const char *filename, const char *filename,
unsigned line, unsigned line,
@ -1660,6 +1714,7 @@ static int load_from_path(Unit *u, const char *path) {
{ "NonBlocking", config_parse_bool, &u->service.exec_context.non_blocking, "Service" }, { "NonBlocking", config_parse_bool, &u->service.exec_context.non_blocking, "Service" },
{ "BusName", config_parse_string_printf, &u->service.bus_name, "Service" }, { "BusName", config_parse_string_printf, &u->service.bus_name, "Service" },
{ "NotifyAccess", config_parse_notify_access, &u->service.notify_access, "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"), EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"),
{ "ListenStream", config_parse_listen, &u->socket, "Socket" }, { "ListenStream", config_parse_listen, &u->socket, "Socket" },

View File

@ -178,11 +178,11 @@ static void service_close_socket_fd(Service *s) {
static void service_connection_unref(Service *s) { static void service_connection_unref(Service *s) {
assert(s); assert(s);
if (!s->socket) if (!s->accept_socket)
return; return;
socket_connection_unref(s->socket); socket_connection_unref(s->accept_socket);
s->socket = NULL; s->accept_socket = NULL;
} }
static void service_done(Unit *u) { static void service_done(Unit *u) {
@ -222,6 +222,8 @@ static void service_done(Unit *u) {
service_close_socket_fd(s); service_close_socket_fd(s);
service_connection_unref(s); service_connection_unref(s);
set_free(s->configured_sockets);
unit_unwatch_timer(u, &s->timer_watch); 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) if (s->socket_fd >= 0)
return 0; return 0;
if (!set_isempty(s->configured_sockets))
return 0;
/* Collects all Socket objects that belong to this /* Collects all Socket objects that belong to this
* service. Note that a service might have multiple sockets * service. Note that a service might have multiple sockets
* via multiple names. */ * via multiple names. */
@ -1216,23 +1221,30 @@ fail:
static int service_notify_sockets_dead(Service *s) { static int service_notify_sockets_dead(Service *s) {
Iterator i; Iterator i;
Set *set; Set *set, *free_set = NULL;
Socket *sock; Socket *sock;
int r; int r;
assert(s); assert(s);
/* Notifies all our sockets when we die */
if (s->socket_fd >= 0) if (s->socket_fd >= 0)
return 0; return 0;
/* Notifies all our sockets when we die */ if (!set_isempty(s->configured_sockets))
if ((r = service_get_sockets(s, &set)) < 0) set = s->configured_sockets;
else {
if ((r = service_get_sockets(s, &free_set)) < 0)
return r; return r;
set = free_set;
}
SET_FOREACH(sock, set, i) SET_FOREACH(sock, set, i)
socket_notify_service_dead(sock); socket_notify_service_dead(sock);
set_free(set); set_free(free_set);
return 0; return 0;
} }
@ -1390,7 +1402,7 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
int r; int r;
int *rfds = NULL; int *rfds = NULL;
unsigned rn_fds = 0; unsigned rn_fds = 0;
Set *set; Set *set, *free_set = NULL;
Socket *sock; Socket *sock;
assert(s); assert(s);
@ -1400,9 +1412,15 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
if (s->socket_fd >= 0) if (s->socket_fd >= 0)
return 0; return 0;
if ((r = service_get_sockets(s, &set)) < 0) if (!set_isempty(s->configured_sockets))
set = s->configured_sockets;
else {
if ((r = service_get_sockets(s, &free_set)) < 0)
return r; return r;
set = free_set;
}
SET_FOREACH(sock, set, i) { SET_FOREACH(sock, set, i) {
int *cfds; int *cfds;
unsigned cn_fds; unsigned cn_fds;
@ -1438,7 +1456,7 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
*fds = rfds; *fds = rfds;
*n_fds = rn_fds; *n_fds = rn_fds;
set_free(set); set_free(free_set);
return 0; return 0;
@ -2084,14 +2102,6 @@ static int service_start(Unit *u) {
return -ECANCELED; 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->failure = false;
s->main_pid_known = false; s->main_pid_known = false;
s->forbid_restart = 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->socket_fd = fd;
s->got_socket_fd = true; s->got_socket_fd = true;
s->socket = sock; s->accept_socket = sock;
return 0; return 0;
} }

View File

@ -133,7 +133,8 @@ struct Service {
RateLimit ratelimit; RateLimit ratelimit;
struct Socket *socket; struct Socket *accept_socket;
Set *configured_sockets;
Watch timer_watch; Watch timer_watch;

View File

@ -129,8 +129,10 @@ static void socket_done(Unit *u) {
LIST_FOREACH(units_per_type, i, u->meta.manager->units_per_type[UNIT_SERVICE]) { LIST_FOREACH(units_per_type, i, u->meta.manager->units_per_type[UNIT_SERVICE]) {
Service *service = (Service *) i; Service *service = (Service *) i;
if (service->socket == s) if (service->accept_socket == s)
service->socket = NULL; service->accept_socket = NULL;
set_remove(service->configured_sockets, s);
} }
} }
@ -1197,6 +1199,25 @@ static void socket_enter_running(Socket *s, int cfd) {
} }
if (cfd < 0) { if (cfd < 0) {
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) if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, &error, NULL)) < 0)
goto fail; goto fail;

View File

@ -2190,6 +2190,23 @@ bool unit_pending_inactive(Unit *u) {
return false; 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] = { static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
[UNIT_STUB] = "stub", [UNIT_STUB] = "stub",
[UNIT_LOADED] = "loaded", [UNIT_LOADED] = "loaded",

View File

@ -500,6 +500,7 @@ void unit_reset_failed(Unit *u);
Unit *unit_following(Unit *u); Unit *unit_following(Unit *u);
bool unit_pending_inactive(Unit *u); bool unit_pending_inactive(Unit *u);
bool unit_pending_active(Unit *u);
int unit_add_default_target_dependency(Unit *u, Unit *target); int unit_add_default_target_dependency(Unit *u, Unit *target);