From: Frederic Crozat <fcrozat@suse.com>
Date: Fri, 12 Apr 2013 16:56:26 +0200
Subject: Revert "service: drop support for SysV scripts for the early boot"

This reverts commit 3cdebc217c42c8529086f2965319b6a48eaaeabe.

Conflicts:
	src/core/service.c
---
 src/core/service.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 46 insertions(+), 5 deletions(-)

Index: systemd-208/src/core/service.c
===================================================================
--- systemd-208.orig/src/core/service.c
+++ systemd-208/src/core/service.c
@@ -51,7 +51,8 @@
 
 typedef enum RunlevelType {
         RUNLEVEL_UP,
-        RUNLEVEL_DOWN
+        RUNLEVEL_DOWN,
+        RUNLEVEL_SYSINIT
 } RunlevelType;
 
 static const struct {
@@ -66,6 +67,16 @@ static const struct {
         { "rc4.d",  SPECIAL_RUNLEVEL4_TARGET, RUNLEVEL_UP },
         { "rc5.d",  SPECIAL_RUNLEVEL5_TARGET, RUNLEVEL_UP },
 
+#ifdef HAVE_SYSV_COMPAT
+        /* SUSE style boot.d */
+        { "boot.d", SPECIAL_SYSINIT_TARGET,   RUNLEVEL_SYSINIT },
+#endif
+
+#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
+        /* Debian style rcS.d */
+        { "rcS.d",  SPECIAL_SYSINIT_TARGET,   RUNLEVEL_SYSINIT },
+#endif
+
         /* Standard SysV runlevels for shutdown */
         { "rc0.d",  SPECIAL_POWEROFF_TARGET,  RUNLEVEL_DOWN },
         { "rc6.d",  SPECIAL_REBOOT_TARGET,    RUNLEVEL_DOWN }
@@ -74,10 +85,12 @@ static const struct {
            directories in this order, and we want to make sure that
            sysv_start_priority is known when we first load the
            unit. And that value we only know from S links. Hence
-           UP must be read before DOWN */
+           UP/SYSINIT must be read before DOWN */
 };
 
 #define RUNLEVELS_UP "12345"
+/* #define RUNLEVELS_DOWN "06" */
+#define RUNLEVELS_BOOT "bBsS"
 #endif
 
 static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
@@ -340,6 +353,9 @@ static char *sysv_translate_name(const c
         if (endswith(name, ".sh"))
                 /* Drop .sh suffix */
                 strcpy(stpcpy(r, name) - 3, ".service");
+        if (startswith(name, "boot."))
+                /* Drop SuSE-style boot. prefix */
+                strcpy(stpcpy(r, name + 5), ".service");
         else
                 /* Normal init script name */
                 strcpy(stpcpy(r, name), ".service");
@@ -942,6 +958,13 @@ static int service_load_sysv_path(Servic
 
         if ((r = sysv_exec_commands(s, supports_reload)) < 0)
                 goto finish;
+        if (s->sysv_runlevels &&
+            chars_intersect(RUNLEVELS_BOOT, s->sysv_runlevels) &&
+            chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
+                /* Service has both boot and "up" runlevels
+                   configured.  Kill the "up" ones. */
+                delete_chars(s->sysv_runlevels, RUNLEVELS_UP);
+        }
 
         if (s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
                 /* If there a runlevels configured for this service
@@ -1023,6 +1046,9 @@ static int service_load_sysv_name(Servic
         if (endswith(name, ".sh.service"))
                 return -ENOENT;
 
+        if (startswith(name, "boot."))
+                return -ENOENT;
+
         STRV_FOREACH(p, UNIT(s)->manager->lookup_paths.sysvinit_path) {
                 char *path;
                 int r;
@@ -1043,6 +1069,18 @@ static int service_load_sysv_name(Servic
                 }
                 free(path);
 
+                if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
+                        /* Try SUSE style boot.* init scripts */
+
+                        path = strjoin(*p, "/boot.", name, NULL);
+                        if (!path)
+                                return -ENOMEM;
+
+                        /* Drop .service suffix */
+                        path[strlen(path)-8] = 0;
+                        r = service_load_sysv_path(s, path);
+                        free(path);
+                }
                 if (r < 0)
                         return r;
 
@@ -3574,7 +3612,7 @@ static int service_enumerate(Manager *m)
 
                                 if (de->d_name[0] == 'S')  {
 
-                                        if (rcnd_table[i].type == RUNLEVEL_UP) {
+                                        if (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_SYSINIT) {
                                                 SERVICE(service)->sysv_start_priority_from_rcnd =
                                                         MAX(a*10 + b, SERVICE(service)->sysv_start_priority_from_rcnd);
 
@@ -3591,7 +3629,8 @@ static int service_enumerate(Manager *m)
                                                 goto finish;
 
                                 } else if (de->d_name[0] == 'K' &&
-                                           (rcnd_table[i].type == RUNLEVEL_DOWN)) {
+                                           (rcnd_table[i].type == RUNLEVEL_DOWN ||
+                                            rcnd_table[i].type == RUNLEVEL_SYSINIT)) {
 
                                         r = set_ensure_allocated(&shutdown_services,
                                                                  trivial_hash_func, trivial_compare_func);
@@ -3631,7 +3670,9 @@ static int service_enumerate(Manager *m)
          * runlevels we assume the stop jobs will be implicitly added
          * by the core logic. Also, we don't really distinguish here
          * between the runlevels 0 and 6 and just add them to the
-         * special shutdown target. */
+         * special shutdown target. On SUSE the boot.d/ runlevel is
+         * also used for shutdown, so we add links for that too to the
+         * shutdown target.*/
         SET_FOREACH(service, shutdown_services, j) {
                 service = unit_follow_merge(service);
 
