chiark / gitweb /
service: set env var for stop/reload commands
[elogind.git] / src / service.c
index d6897341645c057d0ff2cb01670a0d777e9b7d5e..35f2e9ad2c8931484f7697f77ce5de0e46a76384 100644 (file)
@@ -36,7 +36,6 @@
 
 #define COMMENTS "#;\n"
 #define NEWLINES "\n\r"
-#define LINE_MAX 4096
 
 typedef enum RunlevelType {
         RUNLEVEL_UP,
@@ -457,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;
@@ -526,7 +526,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
 
                                 state = LSB;
 
-                                FOREACH_WORD(w, z, t+9, i) {
+                                FOREACH_WORD_QUOTED(w, z, t+9, i) {
                                         char *n, *m;
 
                                         if (!(n = strndup(w, z))) {
@@ -563,7 +563,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
 
                                 state = LSB;
 
-                                FOREACH_WORD(w, z, strchr(t, ':')+1, i) {
+                                FOREACH_WORD_QUOTED(w, z, strchr(t, ':')+1, i) {
                                         char *n, *m;
 
                                         if (!(n = strndup(w, z))) {
@@ -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)))) {
@@ -685,6 +685,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
         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;
@@ -1327,8 +1328,8 @@ static int service_spawn(
         pid_t pid;
         int r;
         int *fds = NULL, *fdsbuf = NULL;
-        unsigned n_fds = 0;
-        char **argv = NULL, **env = NULL;
+        unsigned n_fds = 0, n_env = 0;
+        char **argv = NULL, **final_env = NULL, **our_env = NULL;
 
         assert(s);
         assert(c);
@@ -1361,63 +1362,64 @@ static int service_spawn(
                 goto fail;
         }
 
-        if (set_notify_socket) {
-                char *t;
+        if (!(our_env = new0(char*, 3))) {
+                r = -ENOMEM;
+                goto fail;
+        }
 
-                if (asprintf(&t, "NOTIFY_SOCKET=@%s", s->meta.manager->notify_socket) < 0) {
+        if (set_notify_socket)
+                if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=@%s", s->meta.manager->notify_socket) < 0) {
                         r = -ENOMEM;
                         goto fail;
                 }
 
-                env = strv_env_set(s->meta.manager->environment, t);
-                free(t);
-
-                if (!env) {
+        if (s->main_pid > 0)
+                if (asprintf(our_env + n_env++, "MAINPID=%lu", (unsigned long) s->main_pid) < 0) {
                         r = -ENOMEM;
                         goto fail;
                 }
-        } else
-                env = s->meta.manager->environment;
+
+        if (!(final_env = strv_env_merge(2,
+                                         s->meta.manager->environment,
+                                         our_env,
+                                         NULL))) {
+                r = -ENOMEM;
+                goto fail;
+        }
 
         r = exec_spawn(c,
                        argv,
                        &s->exec_context,
                        fds, n_fds,
-                       env,
+                       final_env,
                        apply_permissions,
                        apply_chroot,
                        s->meta.manager->confirm_spawn,
                        s->meta.cgroup_bondings,
                        &pid);
 
-        strv_free(argv);
-        argv = NULL;
-
-        if (set_notify_socket)
-                strv_free(env);
-        env = NULL;
-
         if (r < 0)
                 goto fail;
 
-        if (fdsbuf)
-                free(fdsbuf);
 
         if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
                 /* FIXME: we need to do something here */
                 goto fail;
 
+        free(fdsbuf);
+        strv_free(argv);
+        strv_free(our_env);
+        strv_free(final_env);
+
         *_pid = pid;
 
         return 0;
 
 fail:
-        free(fds);
-
+        free(fdsbuf);
         strv_free(argv);
-
-        if (set_notify_socket)
-                strv_free(env);
+        strv_free(our_env);
+        strv_free(final_env);
 
         if (timeout)
                 unit_unwatch_timer(UNIT(s), &s->timer_watch);
@@ -1971,6 +1973,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;
 }
 
@@ -2038,6 +2062,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);
 
@@ -2302,7 +2375,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;