chiark / gitweb /
sysv: require sysinit.service from all sysv services
[elogind.git] / service.c
index a693c3339249ed6bd09d23988bdcba0ae433fc93..53d5505c2ea16b007607291f7e32faf54b3d8763 100644 (file)
--- a/service.c
+++ b/service.c
@@ -370,7 +370,13 @@ static int service_load_sysv_path(Service *s, const char *path) {
                                         if (r == 0)
                                                 continue;
 
-                                        r = unit_add_name(u, m);
+                                        if (unit_name_to_type(m) == UNIT_SERVICE)
+                                                r = unit_add_name(u, m);
+                                        else {
+                                                if ((r = unit_add_dependency_by_name_inverse(u, UNIT_REQUIRES, m)) >= 0)
+                                                        r = unit_add_dependency_by_name(u, UNIT_BEFORE, m);
+                                        }
+
                                         free(m);
 
                                         if (r < 0)
@@ -475,6 +481,10 @@ static int service_load_sysv_path(Service *s, const char *path) {
         if ((r = sysv_exec_commands(s)) < 0)
                 goto finish;
 
+        if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_SYSINIT_SERVICE)) < 0 ||
+            (r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_SYSINIT_SERVICE)) < 0)
+                goto finish;
+
         r = 1;
 
 finish:
@@ -504,7 +514,7 @@ static int service_load_sysv_name(Service *s, const char *name) {
                 r = service_load_sysv_path(s, path);
                 free(path);
 
-                if (r >= 0)
+                if (r != 0)
                         return r;
         }
 
@@ -568,7 +578,7 @@ static int service_init(Unit *u) {
                 return r;
         }
 
-        /* Load a classic init script as a fallback, if we couldn*t find anything */
+        /* Load a classic init script as a fallback, if we couldn't find anything */
         if (r == 0)
                 if ((r = service_load_sysv(s)) <= 0) {
                         service_done(u);
@@ -581,6 +591,12 @@ static int service_init(Unit *u) {
                 return r;
         }
 
+        /* Add default cgroup */
+        if ((r = unit_add_default_cgroup(u)) < 0) {
+                service_done(u);
+                return r;
+        }
+
         return 0;
 }
 
@@ -599,10 +615,14 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
         fprintf(f,
                 "%sService State: %s\n"
                 "%sPermissionsStartOnly: %s\n"
-                "%sRootDirectoryStartOnly: %s\n",
+                "%sRootDirectoryStartOnly: %s\n"
+                "%sValidNoProcess: %s\n"
+                "%sType: %s\n",
                 prefix, service_state_to_string(s->state),
                 prefix, yes_no(s->permissions_start_only),
-                prefix, yes_no(s->root_directory_start_only));
+                prefix, yes_no(s->root_directory_start_only),
+                prefix, yes_no(s->valid_no_process),
+                prefix, service_type_to_string(s->type));
 
         if (s->pid_file)
                 fprintf(f,
@@ -898,6 +918,7 @@ static int service_spawn(
                             fds, n_fds,
                             apply_permissions,
                             apply_chroot,
+                            UNIT(s)->meta.cgroup_bondings,
                             &pid)) < 0)
                 goto fail;
 
@@ -1336,7 +1357,7 @@ static int main_pid_good(Service *s) {
                 return s->main_pid > 0;
 
         /* We don't know the pid */
-        return -1;
+        return -EAGAIN;
 }
 
 static bool control_pid_good(Service *s) {
@@ -1345,6 +1366,15 @@ static bool control_pid_good(Service *s) {
         return s->control_pid > 0;
 }
 
+static int cgroup_good(Service *s) {
+        assert(s);
+
+        if (s->valid_no_process)
+                return -EAGAIN;
+
+        return cgroup_bonding_is_empty_list(UNIT(s)->meta.cgroup_bondings);
+}
+
 static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         Service *s = SERVICE(u);
         bool success;
@@ -1418,7 +1448,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                  * don't care about failing commands. */
 
                 if (s->control_command->command_next &&
-                    (success || (s->state == SERVICE_EXEC_STOP || s->state == SERVICE_EXEC_STOP_POST)))
+                    (success || (s->state == SERVICE_STOP || s->state == SERVICE_STOP_POST)))
 
                         /* There is another command to *
                          * execute, so let's do that. */
@@ -1477,7 +1507,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
 
                         case SERVICE_RELOAD:
                                 if (success) {
-                                        if (main_pid_good(s) != 0)
+                                        if (main_pid_good(s) != 0 && cgroup_good(s) != 0)
                                                 service_set_state(s, SERVICE_RUNNING);
                                         else
                                                 service_enter_stop(s, true);
@@ -1580,6 +1610,33 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
         }
 }
 
+static void service_cgroup_notify_event(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(u);
+
+        log_debug("%s: cgroup is empty", unit_id(u));
+
+        switch (s->state) {
+
+                /* Waiting for SIGCHLD is usually more interesting,
+                 * because it includes return codes/signals. Which is
+                 * why we ignore the cgroup events for most cases,
+                 * except when we don't know pid which to expect the
+                 * SIGCHLD for. */
+
+        case SERVICE_RUNNING:
+
+                if (!s->valid_no_process && main_pid_good(s) <= 0)
+                        service_enter_stop(s, true);
+
+                break;
+
+        default:
+                ;
+        }
+}
+
 static int service_enumerate(Manager *m) {
 
         static const char * const rcnd[] = {
@@ -1753,5 +1810,7 @@ const UnitVTable service_vtable = {
         .sigchld_event = service_sigchld_event,
         .timer_event = service_timer_event,
 
+        .cgroup_notify_empty = service_cgroup_notify_event,
+
         .enumerate = service_enumerate
 };