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:
* 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.

View File

@ -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" },

View File

@ -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;
}

View File

@ -133,7 +133,8 @@ struct Service {
RateLimit ratelimit;
struct Socket *socket;
struct Socket *accept_socket;
Set *configured_sockets;
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]) {
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 {

View File

@ -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",

View File

@ -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);