Commit a40eb732 authored by Lennart Poettering's avatar Lennart Poettering
Browse files

unit: add DefaultDependencies= setting

In order to simplify writing of unit files introduce default
dependencies that are added to all units unless explictly disabled in a
unit. This option can be switched off for select units that are involved
in early boot-up ot late system shutdown,

This should simplify service files for most normal daemons, but breaks
existing service files for software involved in early boot (notably
udev), which need to be updated for a DefaultDependencies=no setting)
parent 2c966c03
......@@ -1506,6 +1506,7 @@ static int load_from_path(Unit *u, const char *path) {
{ "RecursiveStop", config_parse_bool, &u->meta.recursive_stop, "Unit" },
{ "StopWhenUnneeded", config_parse_bool, &u->meta.stop_when_unneeded, "Unit" },
{ "OnlyByDependency", config_parse_bool, &u->meta.only_by_dependency, "Unit" },
{ "DefaultDependencies", config_parse_bool, &u->meta.default_dependencies, "Unit" },
{ "PIDFile", config_parse_path, &u->service.pid_file, "Service" },
{ "ExecStartPre", config_parse_exec, u->service.exec_command+SERVICE_EXEC_START_PRE, "Service" },
......
......@@ -29,6 +29,7 @@
#include "unit-name.h"
#include "path.h"
#include "dbus-path.h"
#include "special.h"
static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
[PATH_DEAD] = UNIT_INACTIVE,
......@@ -120,6 +121,11 @@ static int path_load(Unit *u) {
if ((r = path_add_mount_links(p)) < 0)
return r;
/* Path units shouldn't stay around on shutdown */
if (p->meta.default_dependencies)
if ((r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true)) < 0)
return r;
}
return path_verify(p);
......
......@@ -665,20 +665,18 @@ static int service_load_sysv_path(Service *s, const char *path) {
if ((r = sysv_exec_commands(s)) < 0)
goto finish;
if (!s->sysv_runlevels || chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
if (s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
/* If there a runlevels configured for this service
* but none of the standard ones, then we assume this
* is some special kind of service (which might be
* needed for early boot) and don't create any links
* to it. */
if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0 ||
(r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
goto finish;
s->meta.default_dependencies = false;
} else
/* Don't timeout special services during boot (like fsck) */
s->timeout_usec = 0;
}
/* Special setting for all SysV services */
s->type = SERVICE_FORKING;
......@@ -827,6 +825,30 @@ static int service_verify(Service *s) {
return 0;
}
static int service_add_default_dependencies(Service *s) {
int r;
assert(s);
/* Add a number of automatic dependencies useful for the
* majority of services. */
/* First, pull in base system */
if (s->meta.manager->running_as == MANAGER_SYSTEM) {
if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
return r;
} else if (s->meta.manager->running_as == MANAGER_SESSION) {
if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0)
return r;
}
/* Second, activate normal shutdown */
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
}
static int service_load(Unit *u) {
int r;
Service *s = SERVICE(u);
......@@ -867,11 +889,19 @@ static int service_load(Unit *u) {
return r;
if ((r = unit_watch_bus_name(u, s->bus_name)) < 0)
return r;
return r;
}
if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE)
s->notify_access = NOTIFY_MAIN;
if (s->type == SERVICE_DBUS || s->bus_name)
if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_TARGET, NULL, true)) < 0)
return r;
if (s->meta.default_dependencies)
if ((r = service_add_default_dependencies(s)) < 0)
return r;
}
return service_verify(s);
......
......@@ -37,6 +37,7 @@
#include "unit-name.h"
#include "dbus-socket.h"
#include "missing.h"
#include "special.h"
static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
[SOCKET_DEAD] = UNIT_INACTIVE,
......@@ -241,6 +242,17 @@ static int socket_add_device_link(Socket *s) {
return r;
}
static int socket_add_default_dependencies(Socket *s) {
int r;
assert(s);
if (s->meta.manager->running_as == MANAGER_SYSTEM)
if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
return r;
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
}
static int socket_load(Unit *u) {
Socket *s = SOCKET(u);
int r;
......@@ -273,6 +285,10 @@ static int socket_load(Unit *u) {
if ((r = unit_add_default_cgroup(u)) < 0)
return r;
if (s->meta.default_dependencies)
if ((r = socket_add_default_dependencies(s)) < 0)
return r;
}
return socket_verify(s);
......
......@@ -46,7 +46,9 @@
#define SPECIAL_RTC_SET_TARGET "rtc-set.target" /* LSB's $time */
#define SPECIAL_DISPLAY_MANAGER_SERVICE "display-manager.service" /* Debian's $x-display-manager */
#define SPECIAL_MAIL_TRANSFER_AGENT_TARGET "mail-transfer-agent.target" /* Debian's $mail-{transport|transfer-agent */
#define SPECIAL_DBUS_TARGET "dbus.target"
#define SPECIAL_BASIC_TARGET "basic.target"
#define SPECIAL_SOCKETS_TARGET "sockets.target"
#define SPECIAL_SYSINIT_TARGET "sysinit.target"
#define SPECIAL_RESCUE_TARGET "rescue.target"
#define SPECIAL_EXIT_SERVICE "exit.service"
......
......@@ -50,6 +50,46 @@ static void target_set_state(Target *t, TargetState state) {
unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state]);
}
static int target_add_default_dependencies(Target *t) {
Iterator i;
Unit *other;
int r;
/* Imply ordering for requirement dependencies
* on target units. */
SET_FOREACH(other, t->meta.dependencies[UNIT_REQUIRES], i)
if ((r = unit_add_dependency(UNIT(t), UNIT_AFTER, other, true)) < 0)
return r;
SET_FOREACH(other, t->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
if ((r = unit_add_dependency(UNIT(t), UNIT_AFTER, other, true)) < 0)
return r;
SET_FOREACH(other, t->meta.dependencies[UNIT_WANTS], i)
if ((r = unit_add_dependency(UNIT(t), UNIT_AFTER, other, true)) < 0)
return r;
return 0;
}
static int target_load(Unit *u) {
Target *t = TARGET(u);
int r;
assert(t);
if ((r = unit_load_fragment_and_dropin(u)) < 0)
return r;
/* This is a new unit? Then let's add in some extras */
if (u->meta.load_state == UNIT_LOADED) {
if (u->meta.default_dependencies)
if ((r = target_add_default_dependencies(t)) < 0)
return r;
}
return 0;
}
static int target_coldplug(Unit *u) {
Target *t = TARGET(u);
......@@ -177,7 +217,7 @@ DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
const UnitVTable target_vtable = {
.suffix = ".target",
.load = unit_load_fragment_and_dropin,
.load = target_load,
.coldplug = target_coldplug,
.dump = target_dump,
......
......@@ -25,6 +25,7 @@
#include "unit-name.h"
#include "timer.h"
#include "dbus-timer.h"
#include "special.h"
static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
[TIMER_DEAD] = UNIT_INACTIVE,
......@@ -89,6 +90,11 @@ static int timer_load(Unit *u) {
if ((r = unit_add_dependency(u, UNIT_BEFORE, t->unit, true)) < 0)
return r;
/* Timers shouldn't stay around on shutdown */
if (t->meta.default_dependencies)
if ((r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true)) < 0)
return r;
}
return timer_verify(t);
......
......@@ -69,6 +69,7 @@ Unit *unit_new(Manager *m) {
u->meta.manager = m;
u->meta.type = _UNIT_TYPE_INVALID;
u->meta.deserialized_job = _JOB_TYPE_INVALID;
u->meta.default_dependencies = true;
return u;
}
......@@ -593,8 +594,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
"%s\tActive Enter Timestamp: %s\n"
"%s\tActive Exit Timestamp: %s\n"
"%s\tInactive Enter Timestamp: %s\n"
"%s\tGC Check Good: %s\n"
"%s\tOnly By Dependency: %s\n",
"%s\tGC Check Good: %s\n",
prefix, u->meta.id,
prefix, unit_description(u),
prefix, strna(u->meta.instance),
......@@ -604,8 +604,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->meta.active_enter_timestamp.realtime)),
prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->meta.active_exit_timestamp.realtime)),
prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->meta.inactive_enter_timestamp.realtime)),
prefix, yes_no(unit_check_gc(u)),
prefix, yes_no(u->meta.only_by_dependency));
prefix, yes_no(unit_check_gc(u)));
SET_FOREACH(t, u->meta.names, i)
fprintf(f, "%s\tName: %s\n", prefix, t);
......@@ -623,9 +622,13 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
if (u->meta.load_state == UNIT_LOADED) {
fprintf(f,
"%s\tRecursive Stop: %s\n"
"%s\tStop When Unneeded: %s\n",
"%s\tStopWhenUnneeded: %s\n"
"%s\tOnlyByDependency: %s\n"
"%s\tDefaultDependencies: %s\n",
prefix, yes_no(u->meta.recursive_stop),
prefix, yes_no(u->meta.stop_when_unneeded));
prefix, yes_no(u->meta.stop_when_unneeded),
prefix, yes_no(u->meta.only_by_dependency),
prefix, yes_no(u->meta.default_dependencies));
LIST_FOREACH(by_unit, b, u->meta.cgroup_bondings)
fprintf(f, "%s\tControlGroup: %s:%s\n",
......
......@@ -142,9 +142,6 @@ struct Meta {
UnitLoadState load_state;
Unit *merged_into;
/* Refuse manual starting, allow starting only indirectly via dependency. */
bool only_by_dependency;
char *id; /* One name is special because we use it for identification. Points to an entry in the names set */
char *instance;
......@@ -190,6 +187,12 @@ struct Meta {
/* Garbage collect us we nobody wants or requires us anymore */
bool stop_when_unneeded;
/* Refuse manual starting, allow starting only indirectly via dependency. */
bool only_by_dependency;
/* Create default depedencies */
bool default_dependencies;
/* When deserializing, temporarily store the job type for this
* unit here, if there was a job scheduled */
int deserialized_job; /* This is actually of type JobType */
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment