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!
* 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.
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;
}
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,
#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" },
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) {
service_close_socket_fd(s);
service_connection_unref(s);
+ set_free(s->configured_sockets);
+
unit_unwatch_timer(u, &s->timer_watch);
}
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. */
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;
}
int r;
int *rfds = NULL;
unsigned rn_fds = 0;
- Set *set;
+ Set *set, *free_set = NULL;
Socket *sock;
assert(s);
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;
*fds = rfds;
*n_fds = rn_fds;
- set_free(set);
+ set_free(free_set);
return 0;
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;
s->socket_fd = fd;
s->got_socket_fd = true;
- s->socket = sock;
+ s->accept_socket = sock;
return 0;
}
RateLimit ratelimit;
- struct Socket *socket;
+ struct Socket *accept_socket;
+ Set *configured_sockets;
Watch timer_watch;
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);
}
}
}
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 {
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",
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);