chiark / gitweb /
sysv: properly handle Provides LSB header
[elogind.git] / service.c
index a693c3339249ed6bd09d23988bdcba0ae433fc93..1aeb5fbf2b637cec04661b081500db891f8bc26e 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)
@@ -568,7 +574,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 +587,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 +611,12 @@ 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",
                 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));
 
         if (s->pid_file)
                 fprintf(f,
@@ -898,6 +912,7 @@ static int service_spawn(
                             fds, n_fds,
                             apply_permissions,
                             apply_chroot,
+                            UNIT(s)->meta.cgroup_bondings,
                             &pid)) < 0)
                 goto fail;
 
@@ -1336,7 +1351,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 +1360,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 +1442,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 +1501,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 +1604,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 +1804,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
 };