From a40eb73224e237f758d38847ae216c019425ebac Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 3 Jul 2010 19:48:33 +0200 Subject: [PATCH] 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) --- src/load-fragment.c | 1 + src/path.c | 6 ++++++ src/service.c | 42 ++++++++++++++++++++++++++++++++++++------ src/socket.c | 16 ++++++++++++++++ src/special.h | 2 ++ src/target.c | 42 +++++++++++++++++++++++++++++++++++++++++- src/timer.c | 6 ++++++ src/unit.c | 15 +++++++++------ src/unit.h | 9 ++++++--- 9 files changed, 123 insertions(+), 16 deletions(-) diff --git a/src/load-fragment.c b/src/load-fragment.c index 49b577fb2..e5c7ba24a 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -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" }, diff --git a/src/path.c b/src/path.c index 56936fd67..30d946d78 100644 --- a/src/path.c +++ b/src/path.c @@ -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); diff --git a/src/service.c b/src/service.c index cbc9c9551..04ed68439 100644 --- a/src/service.c +++ b/src/service.c @@ -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); diff --git a/src/socket.c b/src/socket.c index 91eea7d29..03e556c30 100644 --- a/src/socket.c +++ b/src/socket.c @@ -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); diff --git a/src/special.h b/src/special.h index 2d5bc7b89..8cb500b8a 100644 --- a/src/special.h +++ b/src/special.h @@ -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" diff --git a/src/target.c b/src/target.c index fba99568a..f8df6fb75 100644 --- a/src/target.c +++ b/src/target.c @@ -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, diff --git a/src/timer.c b/src/timer.c index f0005f55c..e3c916bb0 100644 --- a/src/timer.c +++ b/src/timer.c @@ -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); diff --git a/src/unit.c b/src/unit.c index 8c495b46e..8f5ae8af3 100644 --- a/src/unit.c +++ b/src/unit.c @@ -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", diff --git a/src/unit.h b/src/unit.h index d3dd5decd..b6351d554 100644 --- a/src/unit.h +++ b/src/unit.h @@ -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 */ -- 2.30.2