mirror of
https://github.com/AuxXxilium/eudev.git
synced 2024-12-20 21:50:23 +07: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:
|
||||
|
||||
* 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,
|
||||
@ -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" },
|
||||
{ "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)
|
||||
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,9 +1412,15 @@ 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)
|
||||
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;
|
||||
unsigned cn_fds;
|
||||
@ -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;
|
||||
|
||||
|
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]) {
|
||||
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,6 +1199,25 @@ static void socket_enter_running(Socket *s, int cfd) {
|
||||
}
|
||||
|
||||
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)
|
||||
goto fail;
|
||||
|
||||
|
17
src/unit.c
17
src/unit.c
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user