chiark / gitweb /
unit: add DefaultDependencies= setting
authorLennart Poettering <lennart@poettering.net>
Sat, 3 Jul 2010 17:48:33 +0000 (19:48 +0200)
committerLennart Poettering <lennart@poettering.net>
Sat, 3 Jul 2010 17:48:33 +0000 (19:48 +0200)
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
src/path.c
src/service.c
src/socket.c
src/special.h
src/target.c
src/timer.c
src/unit.c
src/unit.h

index 49b577fb2f51d1b894864ca9ba829c2b66dd87df..e5c7ba24ab8e45117f968372848bab994ecdcde6 100644 (file)
@@ -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" },
index 56936fd673fd76d427c18eb8fdce7f2105279be5..30d946d788a66cb58bbd4b971c10f456fa78c0f4 100644 (file)
@@ -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);
index cbc9c9551ab092a7478149c2a5bba81d306437b6..04ed6843935e6b719cc74c06b49463646574435a 100644 (file)
@@ -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);
index 91eea7d294895bca43d481d68c2949a62929546f..03e556c30e18012cb53cb15a8cdf1e5df7b2b78c 100644 (file)
@@ -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);
index 2d5bc7b89d7f6cc3be07bf038df710f5f42edb67..8cb500b8ad3575ec95199bc70b5a51d02fe44d87 100644 (file)
@@ -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"
index fba99568a3007e53df0665c540106481167f0b98..f8df6fb757742d3cb8f166d63c582ef3f563e8a1 100644 (file)
@@ -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,
index f0005f55ce364a9378f0e7d6800a5d39cb010e8d..e3c916bb0faf717b9f5e63e78c433b6d10aecc24 100644 (file)
@@ -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);
index 8c495b46ebe069fa578e95973f0914e6206f56f8..8f5ae8af3f8610ce10abdea7c8a85c853baaf141 100644 (file)
@@ -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",
index d3dd5decd25348dea9c8fd094517557be8378ea0..b6351d55419f2a477a6c35aed1e2be8247730abd 100644 (file)
@@ -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 */