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:
parent
d9ff321ad9
commit
f976f3f67c
13
fixme
13
fixme
@ -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.
|
||||||
|
@ -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" },
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
25
src/socket.c
25
src/socket.c
@ -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;
|
||||||
|
|
||||||
|
17
src/unit.c
17
src/unit.c
@ -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",
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user