chiark / gitweb /
log: bump up a number of log messages so that they are shown even if debug logging...
[elogind.git] / src / service.c
index e1dab70f816eb2a9ccb8b67e4ad0e2455c1d8440..ccc83128be6277e9a4a8e8c2d75be9c328356be2 100644 (file)
@@ -36,7 +36,6 @@
 
 #define COMMENTS "#;\n"
 #define NEWLINES "\n\r"
-#define LINE_MAX 4096
 
 typedef enum RunlevelType {
         RUNLEVEL_UP,
@@ -76,15 +75,15 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
         [SERVICE_START_POST] = UNIT_ACTIVATING,
         [SERVICE_RUNNING] = UNIT_ACTIVE,
         [SERVICE_EXITED] = UNIT_ACTIVE,
-        [SERVICE_RELOAD] = UNIT_ACTIVE_RELOADING,
+        [SERVICE_RELOAD] = UNIT_RELOADING,
         [SERVICE_STOP] = UNIT_DEACTIVATING,
         [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
         [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
-        [SERVICE_MAINTENANCE] = UNIT_INACTIVE,
-        [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING,
+        [SERVICE_MAINTENANCE] = UNIT_MAINTENANCE,
+        [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING
 };
 
 static void service_init(Unit *u) {
@@ -144,6 +143,8 @@ static int service_set_main_pid(Service *s, pid_t pid) {
         s->main_pid = pid;
         s->main_pid_known = true;
 
+        exec_status_start(&s->main_exec_status, pid);
+
         return 0;
 }
 
@@ -455,7 +456,8 @@ static int service_load_sysv_path(Service *s, const char *path) {
                                         s->sysv_runlevels = d;
                                 }
 
-                        } else if (startswith_no_case(t, "description:")) {
+                        } else if (startswith_no_case(t, "description:") &&
+                                   !u->meta.description) {
 
                                 size_t k = strlen(t);
                                 char *d;
@@ -543,10 +545,8 @@ static int service_load_sysv_path(Service *s, const char *path) {
 
                                         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, NULL, true)) >= 0)
-                                                        r = unit_add_dependency_by_name(u, UNIT_BEFORE, m, NULL, true);
-                                        }
+                                        else
+                                                r = unit_add_two_dependencies_by_name_inverse(u, UNIT_AFTER, UNIT_REQUIRES, m, NULL, true);
 
                                         free(m);
 
@@ -603,9 +603,13 @@ static int service_load_sysv_path(Service *s, const char *path) {
                                         s->sysv_runlevels = d;
                                 }
 
-                        } else if (startswith_no_case(t, "Description:")) {
+                        } else if (startswith_no_case(t, "Description:") &&
+                                   !u->meta.description) {
                                 char *d;
 
+                                /* We use the long description only if
+                                 * no short description is set. */
+
                                 state = LSB_DESCRIPTION;
 
                                 if (!(d = strdup(strstrip(t+12)))) {
@@ -616,13 +620,9 @@ static int service_load_sysv_path(Service *s, const char *path) {
                                 free(u->meta.description);
                                 u->meta.description = d;
 
-                        } else if (startswith_no_case(t, "Short-Description:") &&
-                                   !u->meta.description) {
+                        } else if (startswith_no_case(t, "Short-Description:")) {
                                 char *d;
 
-                                /* We use the short description only
-                                 * if no long description is set. */
-
                                 state = LSB;
 
                                 if (!(d = strdup(strstrip(t+18)))) {
@@ -667,26 +667,25 @@ 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;
         s->valid_no_process = true;
         s->kill_mode = KILL_PROCESS_GROUP;
         s->restart = SERVICE_ONCE;
+        s->exec_context.std_output = EXEC_OUTPUT_TTY;
 
         u->meta.load_state = UNIT_LOADED;
         r = 0;
@@ -829,6 +828,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);
@@ -869,11 +892,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);
@@ -1941,6 +1972,28 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
                 unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
         }
 
+        if (s->main_exec_status.pid > 0) {
+                unit_serialize_item_format(u, f, "main-exec-status-pid", "%lu", (unsigned long) s->main_exec_status.pid);
+
+                if (s->main_exec_status.start_timestamp.realtime > 0) {
+                        unit_serialize_item_format(u, f, "main-exec-status-start-realtime",
+                                                   "%llu", (unsigned long long) s->main_exec_status.start_timestamp.realtime);
+
+                        unit_serialize_item_format(u, f, "main-exec-status-start-monotonic",
+                                                   "%llu", (unsigned long long) s->main_exec_status.start_timestamp.monotonic);
+                }
+
+                if (s->main_exec_status.exit_timestamp.realtime > 0) {
+                        unit_serialize_item_format(u, f, "main-exec-status-exit-realtime",
+                                                   "%llu", (unsigned long long) s->main_exec_status.exit_timestamp.realtime);
+                        unit_serialize_item_format(u, f, "main-exec-status-exit-monotonic",
+                                                   "%llu", (unsigned long long) s->main_exec_status.exit_timestamp.monotonic);
+
+                        unit_serialize_item_format(u, f, "main-exec-status-code", "%i", s->main_exec_status.code);
+                        unit_serialize_item_format(u, f, "main-exec-status-status", "%i", s->main_exec_status.status);
+                }
+        }
+
         return 0;
 }
 
@@ -2008,6 +2061,55 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
                                 close_nointr_nofail(s->socket_fd);
                         s->socket_fd = fdset_remove(fds, fd);
                 }
+        } else if (streq(key, "main-exec-status-pid")) {
+                pid_t pid;
+
+                if ((r = parse_pid(value, &pid)) < 0)
+                        log_debug("Failed to parse main-exec-status-pid value %s", value);
+                else
+                        s->main_exec_status.pid = pid;
+        } else if (streq(key, "main-exec-status-code")) {
+                int i;
+
+                if ((r = safe_atoi(value, &i)) < 0)
+                        log_debug("Failed to parse main-exec-status-code value %s", value);
+                else
+                        s->main_exec_status.code = i;
+        } else if (streq(key, "main-exec-status-status")) {
+                int i;
+
+                if ((r = safe_atoi(value, &i)) < 0)
+                        log_debug("Failed to parse main-exec-status-status value %s", value);
+                else
+                        s->main_exec_status.status = i;
+        } else if (streq(key, "main-exec-status-start-realtime")) {
+                uint64_t k;
+
+                if ((r = safe_atou64(value, &k)) < 0)
+                        log_debug("Failed to parse main-exec-status-start-realtime value %s", value);
+                else
+                        s->main_exec_status.start_timestamp.realtime = (usec_t) k;
+        } else if (streq(key, "main-exec-status-start-monotonic")) {
+                uint64_t k;
+
+                if ((r = safe_atou64(value, &k)) < 0)
+                        log_debug("Failed to parse main-exec-status-start-monotonic value %s", value);
+                else
+                        s->main_exec_status.start_timestamp.monotonic = (usec_t) k;
+        } else if (streq(key, "main-exec-status-exit-realtime")) {
+                uint64_t k;
+
+                if ((r = safe_atou64(value, &k)) < 0)
+                        log_debug("Failed to parse main-exec-status-exit-realtime value %s", value);
+                else
+                        s->main_exec_status.exit_timestamp.realtime = (usec_t) k;
+        } else if (streq(key, "main-exec-status-exit-monotonic")) {
+                uint64_t k;
+
+                if ((r = safe_atou64(value, &k)) < 0)
+                        log_debug("Failed to parse main-exec-status-exit-monotonic value %s", value);
+                else
+                        s->main_exec_status.exit_timestamp.monotonic = (usec_t) k;
         } else
                 log_debug("Unknown serialization key '%s'", key);
 
@@ -2054,7 +2156,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
 
         if (s->main_pid == pid) {
 
-                exec_status_fill(&s->main_exec_status, pid, code, status);
+                exec_status_exit(&s->main_exec_status, pid, code, status);
                 s->main_pid = 0;
 
                 if (s->type != SERVICE_FORKING) {
@@ -2110,7 +2212,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         } else if (s->control_pid == pid) {
 
                 if (s->control_command)
-                        exec_status_fill(&s->control_command->exec_status, pid, code, status);
+                        exec_status_exit(&s->control_command->exec_status, pid, code, status);
 
                 s->control_pid = 0;
 
@@ -2272,7 +2374,7 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
                 break;
 
         case SERVICE_AUTO_RESTART:
-                log_debug("%s holdoff time over, scheduling restart.", u->meta.id);
+                log_info("%s holdoff time over, scheduling restart.", u->meta.id);
                 service_enter_restart(s);
                 break;
 
@@ -2449,21 +2551,13 @@ static int service_enumerate(Manager *m) {
                                 service = unit_follow_merge(service);
 
                                 if (de->d_name[0] == 'S') {
-                                        Unit *runlevel_target;
-
-                                        if ((r = manager_load_unit(m, rcnd_table[i].target, NULL, &runlevel_target)) < 0)
-                                                goto finish;
 
-                                        if ((r = unit_add_dependency(runlevel_target, UNIT_WANTS, service, true)) < 0)
-                                                goto finish;
-
-                                        if ((r = unit_add_dependency(service, UNIT_BEFORE, runlevel_target, true)) < 0)
+                                        if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_WANTS, rcnd_table[i].target, NULL, true)) < 0)
                                                 goto finish;
 
                                 } else if (de->d_name[0] == 'K' &&
                                            (rcnd_table[i].type == RUNLEVEL_DOWN ||
                                             rcnd_table[i].type == RUNLEVEL_SYSINIT)) {
-                                        Unit *shutdown_target;
 
                                         /* We honour K links only for
                                          * halt/reboot. For the normal
@@ -2481,13 +2575,7 @@ static int service_enumerate(Manager *m) {
                                          * too to the shutdown
                                          * target.*/
 
-                                        if ((r = manager_load_unit(m, SPECIAL_SHUTDOWN_TARGET, NULL, &shutdown_target)) < 0)
-                                                goto finish;
-
-                                        if ((r = unit_add_dependency(service, UNIT_CONFLICTS, shutdown_target, true)) < 0)
-                                                goto finish;
-
-                                        if ((r = unit_add_dependency(service, UNIT_BEFORE, shutdown_target, true)) < 0)
+                                        if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true)) < 0)
                                                 goto finish;
                                 }
                         }
@@ -2625,8 +2713,8 @@ static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
 
 static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
-        [SERVICE_FORKING] = "forking",
         [SERVICE_SIMPLE] = "simple",
+        [SERVICE_FORKING] = "forking",
         [SERVICE_FINISH] = "finish",
         [SERVICE_DBUS] = "dbus",
         [SERVICE_NOTIFY] = "notify"
@@ -2655,6 +2743,7 @@ DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess);
 
 const UnitVTable service_vtable = {
         .suffix = ".service",
+        .show_status = true,
 
         .init = service_init,
         .done = service_done,