chiark / gitweb /
various cleanups
authorLennart Poettering <lennart@poettering.net>
Tue, 26 Jan 2010 06:02:51 +0000 (07:02 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 26 Jan 2010 06:02:51 +0000 (07:02 +0100)
19 files changed:
conf-parser.c
execute.c
execute.h
job.c
job.h
load-fragment.c
main.c
manager.c
name.c
name.h
service.c
socket.c
socket.h
test1/postfix.service
test1/postfix.socket
test1/syslog.service
test1/syslog.socket
util.c
util.h

index 2618858..c7f48ea 100644 (file)
@@ -12,7 +12,6 @@
 #include "strv.h"
 #include "log.h"
 
-#define WHITESPACE " \t\n"
 #define COMMENTS "#;\n"
 #define LINE_MAX 4096
 
index 8cd4f60..bcaa4e9 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -5,6 +5,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <string.h>
 
 #include "execute.h"
 #include "strv.h"
@@ -235,7 +236,7 @@ void exec_command_free_list(ExecCommand *c) {
                 LIST_REMOVE(ExecCommand, command, c, i);
 
                 free(i->path);
-                free(i->argv);
+                strv_free(i->argv);
                 free(i);
         }
 }
@@ -276,3 +277,69 @@ void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status) {
         s->status = status;
         s->timestamp = now(CLOCK_REALTIME);
 }
+
+char *exec_command_line(ExecCommand *c) {
+        size_t k;
+        char *n, *p, **a;
+        bool first = true;
+
+        assert(c);
+        assert(c->argv);
+
+        k = 0;
+        STRV_FOREACH(a, c->argv)
+                k += strlen(*a)+3;
+
+        if (!(n = new(char, k)))
+                return NULL;
+
+        p = n;
+        STRV_FOREACH(a, c->argv) {
+
+                if (!first)
+                        *(p++) = ' ';
+                else
+                        first = false;
+
+                if (strpbrk(*a, WHITESPACE)) {
+                        *(p++) = '\'';
+                        p = stpcpy(p, *a);
+                        *(p++) = '\'';
+                } else
+                        p = stpcpy(p, *a);
+
+        }
+
+        /* FIXME: this doesn't really handle arguments that have
+         * spaces and ticks in them */
+
+        return n;
+}
+
+void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
+        char *cmd;
+
+        assert(c);
+        assert(f);
+
+        if (!prefix)
+                prefix = "";
+
+        cmd = exec_command_line(c);
+
+        fprintf(f,
+                "%sCommand Line: %s\n",
+                prefix, cmd ? cmd : strerror(ENOMEM));
+
+        free(cmd);
+}
+
+void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
+        assert(f);
+
+        if (!prefix)
+                prefix = "";
+
+        LIST_FOREACH(command, c, c)
+                exec_command_dump(c, f, prefix);
+}
index e9bd686..d339af9 100644 (file)
--- a/execute.h
+++ b/execute.h
@@ -79,6 +79,10 @@ int exec_spawn(const ExecCommand *command, const ExecContext *context, int *fds,
 void exec_command_free_list(ExecCommand *c);
 void exec_command_free_array(ExecCommand **c, unsigned n);
 
+char *exec_command_line(ExecCommand *c);
+void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix);
+void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix);
+
 void exec_context_init(ExecContext *c);
 void exec_context_done(ExecContext *c);
 void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
diff --git a/job.c b/job.c
index 81d7a19..a2100e3 100644 (file)
--- a/job.c
+++ b/job.c
@@ -61,22 +61,12 @@ JobDependency* job_dependency_new(Job *subject, Job *object, bool matters) {
         l->object = object;
         l->matters = matters;
 
-        if (subject) {
-                l->subject_next = subject->subject_list;
-                subject->subject_list = l;
-        } else {
-                l->subject_next = object->manager->transaction_anchor;
-                object->manager->transaction_anchor = l;
-        }
-
-        if (l->subject_next)
-                l->subject_next->subject_prev = l;
-        l->subject_prev = NULL;
+        if (subject)
+                LIST_PREPEND(JobDependency, subject, subject->subject_list, l);
+        else
+                LIST_PREPEND(JobDependency, subject, object->manager->transaction_anchor, l);
 
-        if ((l->object_next = object->object_list))
-                l->object_next->object_prev = l;
-        l->object_prev = NULL;
-        object->object_list = l;
+        LIST_PREPEND(JobDependency, object, object->object_list, l);
 
         return l;
 }
@@ -84,23 +74,12 @@ JobDependency* job_dependency_new(Job *subject, Job *object, bool matters) {
 void job_dependency_free(JobDependency *l) {
         assert(l);
 
-        if (l->subject_prev)
-                l->subject_prev->subject_next = l->subject_next;
-        else if (l->subject)
-                l->subject->subject_list = l->subject_next;
-        else
-                l->object->manager->transaction_anchor = l->subject_next;
-
-        if (l->subject_next)
-                l->subject_next->subject_prev = l->subject_prev;
-
-        if (l->object_prev)
-                l->object_prev->object_next = l->object_next;
+        if (l->subject)
+                LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
         else
-                l->object->object_list = l->object_next;
+                LIST_REMOVE(JobDependency, subject, l->object->manager->transaction_anchor, l);
 
-        if (l->object_next)
-                l->object_next->object_prev = l->object_prev;
+        LIST_REMOVE(JobDependency, object, l->object->object_list, l);
 
         free(l);
 }
@@ -110,7 +89,7 @@ void job_dependency_delete(Job *subject, Job *object, bool *matters) {
 
         assert(object);
 
-        for (l = object->object_list; l; l = l->object_next) {
+        LIST_FOREACH(object, l, object->object_list) {
                 assert(l->object == object);
 
                 if (l->subject == subject)
@@ -158,7 +137,7 @@ void job_dump(Job *j, FILE*f, const char *prefix) {
         assert(f);
 
         fprintf(f,
-                "%sJob %u:\n"
+                "%s→ Job %u:\n"
                 "%s\tAction: %s → %s\n"
                 "%s\tState: %s\n"
                 "%s\tForced: %s\n",
@@ -173,7 +152,7 @@ bool job_is_anchor(Job *j) {
 
         assert(j);
 
-        for (l = j->object_list; l; l = l->object_next)
+        LIST_FOREACH(object, l, j->object_list)
                 if (!l->subject)
                         return true;
 
@@ -401,7 +380,7 @@ int job_run_and_invalidate(Job *j) {
                 }
 
                 default:
-                        ;
+                        assert_not_reached("Unknown job type");
         }
 
         if (r == -EALREADY)
diff --git a/job.h b/job.h
index 165feb6..1296011 100644 (file)
--- a/job.h
+++ b/job.h
@@ -77,8 +77,8 @@ struct Job {
         LIST_FIELDS(Job, transaction);
         LIST_FIELDS(Job, run_queue);
 
-        JobDependency *subject_list;
-        JobDependency *object_list;
+        LIST_HEAD(JobDependency, subject_list);
+        LIST_HEAD(JobDependency, object_list);
 
         /* Used for graph algs as a "I have been here" marker */
         Job* marker;
index 5570ae5..aa1ae78 100644 (file)
@@ -20,7 +20,7 @@ static int config_parse_deps(
                 void *data,
                 void *userdata) {
 
-        Set **set = data;
+        NameDependency d = PTR_TO_UINT(data);
         Name *name = userdata;
         char *w;
         size_t l;
@@ -29,7 +29,6 @@ static int config_parse_deps(
         assert(filename);
         assert(lvalue);
         assert(rvalue);
-        assert(data);
 
         FOREACH_WORD(w, &l, rvalue, state) {
                 char *t;
@@ -45,10 +44,7 @@ static int config_parse_deps(
                 if (r < 0)
                         return r;
 
-                if ((r = set_ensure_allocated(set, trivial_hash_func, trivial_compare_func)) < 0)
-                        return r;
-
-                if ((r = set_put(*set, other)) < 0)
+                if ((r = name_add_dependency(name, d, other)) < 0)
                         return r;
         }
 
@@ -333,6 +329,7 @@ static int config_parse_exec(
         if (!(n = new(char*, k+1)))
                 return -ENOMEM;
 
+        k = 0;
         FOREACH_WORD_QUOTED(w, l, rvalue, state)
                 if (!(n[k++] = strndup(w, l)))
                         goto fail;
@@ -487,14 +484,14 @@ int name_load_fragment(Name *n) {
         const ConfigItem items[] = {
                 { "Names",                  config_parse_names,           &n->meta.names,                                    "Meta"    },
                 { "Description",            config_parse_string,          &n->meta.description,                              "Meta"    },
-                { "Requires",               config_parse_deps,            n->meta.dependencies+NAME_REQUIRES,                "Meta"    },
-                { "SoftRequires",           config_parse_deps,            n->meta.dependencies+NAME_SOFT_REQUIRES,           "Meta"    },
-                { "Wants",                  config_parse_deps,            n->meta.dependencies+NAME_WANTS,                   "Meta"    },
-                { "Requisite",              config_parse_deps,            n->meta.dependencies+NAME_REQUISITE,               "Meta"    },
-                { "SoftRequisite",          config_parse_deps,            n->meta.dependencies+NAME_SOFT_REQUISITE,          "Meta"    },
-                { "Conflicts",              config_parse_deps,            n->meta.dependencies+NAME_CONFLICTS,               "Meta"    },
-                { "Before",                 config_parse_deps,            n->meta.dependencies+NAME_BEFORE,                  "Meta"    },
-                { "After",                  config_parse_deps,            n->meta.dependencies+NAME_AFTER,                   "Meta"    },
+                { "Requires",               config_parse_deps,            UINT_TO_PTR(NAME_REQUIRES),                        "Meta"    },
+                { "SoftRequires",           config_parse_deps,            UINT_TO_PTR(NAME_SOFT_REQUIRES),                   "Meta"    },
+                { "Wants",                  config_parse_deps,            UINT_TO_PTR(NAME_WANTS),                           "Meta"    },
+                { "Requisite",              config_parse_deps,            UINT_TO_PTR(NAME_REQUISITE),                       "Meta"    },
+                { "SoftRequisite",          config_parse_deps,            UINT_TO_PTR(NAME_SOFT_REQUISITE),                  "Meta"    },
+                { "Conflicts",              config_parse_deps,            UINT_TO_PTR(NAME_CONFLICTS),                       "Meta"    },
+                { "Before",                 config_parse_deps,            UINT_TO_PTR(NAME_BEFORE),                          "Meta"    },
+                { "After",                  config_parse_deps,            UINT_TO_PTR(NAME_AFTER),                           "Meta"    },
 
                 { "PIDFile",                config_parse_path,            &n->service.pid_file,                              "Service" },
                 { "ExecStartPre",           config_parse_exec,            &n->service.exec_command[SERVICE_EXEC_START_PRE],  "Service" },
diff --git a/main.c b/main.c
index a7738f0..e10c57b 100644 (file)
--- a/main.c
+++ b/main.c
@@ -36,13 +36,13 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        printf("- By names:\n");
+        printf(" By names:\n");
         manager_dump_names(m, stdout, "\t");
 
-        printf("- By jobs:\n");
+        printf(" By jobs:\n");
         manager_dump_jobs(m, stdout, "\t");
 
-        manager_loop(m);
+        /* manager_loop(m); */
 
         retval = 0;
 
index 7d24494..90e17b2 100644 (file)
--- a/manager.c
+++ b/manager.c
@@ -134,7 +134,12 @@ static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsi
          * indirectly a dependency of the anchor job via paths that
          * are fully marked as mattering. */
 
-        for (l = j ? j->subject_list : m->transaction_anchor; l; l = l->subject_next) {
+        if (j)
+                l = j->subject_list;
+        else
+                l = m->transaction_anchor;
+
+        LIST_FOREACH(subject, l, l) {
 
                 /* This link does not matter */
                 if (!l->matters)
@@ -169,7 +174,7 @@ static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, Job
 
         /* Patch us in as new owner of the JobDependency objects */
         last = NULL;
-        for (l = other->subject_list; l; l = l->subject_next) {
+        LIST_FOREACH(subject, l, other->subject_list) {
                 assert(l->subject == other);
                 l->subject = j;
                 last = l;
@@ -185,7 +190,7 @@ static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, Job
 
         /* Patch us in as new owner of the JobDependency objects */
         last = NULL;
-        for (l = other->object_list; l; l = l->object_next) {
+        LIST_FOREACH(object, l, other->object_list) {
                 assert(l->object == other);
                 l->object = j;
                 last = l;
diff --git a/name.c b/name.c
index dae2a3f..6352a8e 100644 (file)
--- a/name.c
+++ b/name.c
@@ -13,6 +13,7 @@
 #include "strv.h"
 #include "load-fragment.h"
 #include "load-dropin.h"
+#include "log.h"
 
 const NameVTable * const name_vtable[_NAME_TYPE_MAX] = {
         [NAME_SERVICE] = &service_vtable,
@@ -183,11 +184,13 @@ static void bidi_set_free(Name *name, Set *s) {
         /* Frees the set and makes sure we are dropped from the
          * inverse pointers */
 
-        SET_FOREACH(other, s, i) {
-                NameDependency d;
+        if (name->meta.linked) {
+                SET_FOREACH(other, s, i) {
+                        NameDependency d;
 
-                for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
-                        set_remove(other->meta.dependencies[d], name);
+                        for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
+                                set_remove(other->meta.dependencies[d], name);
+                }
         }
 
         set_free(s);
@@ -211,6 +214,10 @@ void name_free(Name *name) {
                         LIST_REMOVE(Meta, load_queue, name->meta.manager->load_queue, &name->meta);
         }
 
+        if (name->meta.load_state == NAME_LOADED)
+                if (NAME_VTABLE(name)->done)
+                        NAME_VTABLE(name)->done(name);
+
         /* Free data and next 'smaller' objects */
         if (name->meta.job)
                 job_free(name->meta.job);
@@ -218,9 +225,6 @@ void name_free(Name *name) {
         for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
                 bidi_set_free(name, name->meta.dependencies[d]);
 
-        if (NAME_VTABLE(name)->done)
-                NAME_VTABLE(name)->done(name);
-
         free(name->meta.description);
 
         while ((t = set_steal_first(name->meta.names)))
@@ -239,21 +243,6 @@ NameActiveState name_active_state(Name *name) {
         return NAME_VTABLE(name)->active_state(name);
 }
 
-static int ensure_in_set(Set **s, void *data) {
-        int r;
-
-        assert(s);
-        assert(data);
-
-        if ((r = set_ensure_allocated(s, trivial_hash_func, trivial_compare_func)) < 0)
-                return r;
-
-        if ((r = set_put(*s, data)) < 0)
-                return r;
-
-        return 0;
-}
-
 static int ensure_merge(Set **s, Set *other) {
 
         if (!other)
@@ -292,6 +281,7 @@ int name_merge(Name *name, Name *other) {
 
         /* Merge dependencies */
         for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
+                /* fixme, the inverse mapping is missing */
                 if ((r = ensure_merge(&name->meta.dependencies[d], other->meta.dependencies[d])) < 0)
                         return r;
 
@@ -307,46 +297,6 @@ int name_merge(Name *name, Name *other) {
         return 0;
 }
 
-/* FIXME: Does not rollback on failure! */
-static int augment(Name *n) {
-        int r;
-        Iterator i;
-        Name *other;
-
-        assert(n);
-
-        /* Adds in the missing links to make all dependencies
-         * bidirectional. */
-
-        SET_FOREACH(other, n->meta.dependencies[NAME_BEFORE], i)
-                if ((r = ensure_in_set(&other->meta.dependencies[NAME_AFTER], n)) < 0)
-                        return r;
-        SET_FOREACH(other, n->meta.dependencies[NAME_AFTER], i)
-                if ((r = ensure_in_set(&other->meta.dependencies[NAME_BEFORE], n)) < 0)
-                        return r;
-
-        SET_FOREACH(other, n->meta.dependencies[NAME_CONFLICTS], i)
-                if ((r = ensure_in_set(&other->meta.dependencies[NAME_CONFLICTS], n)) < 0)
-                        return r;
-
-        SET_FOREACH(other, n->meta.dependencies[NAME_REQUIRES], i)
-                if ((r = ensure_in_set(&other->meta.dependencies[NAME_REQUIRED_BY], n)) < 0)
-                        return r;
-        SET_FOREACH(other, n->meta.dependencies[NAME_REQUISITE], i)
-                if ((r = ensure_in_set(&other->meta.dependencies[NAME_REQUIRED_BY], n)) < 0)
-                        return r;
-
-        SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUIRES], i)
-                if ((r = ensure_in_set(&other->meta.dependencies[NAME_SOFT_REQUIRED_BY], n)) < 0)
-                        return r;
-
-        SET_FOREACH(other, n->meta.dependencies[NAME_WANTS], i)
-                if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n)) < 0)
-                        return r;
-
-        return 0;
-}
-
 int name_sanitize(Name *n) {
         NameDependency d;
 
@@ -356,7 +306,7 @@ int name_sanitize(Name *n) {
         for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
                 set_remove(n->meta.dependencies[d], n);
 
-        return augment(n);
+        return 0;
 }
 
 const char* name_id(Name *n) {
@@ -409,14 +359,18 @@ void name_dump(Name *n, FILE *f, const char *prefix) {
         char *t;
         NameDependency d;
         Iterator i;
+        char *prefix2;
 
         assert(n);
 
         if (!prefix)
                 prefix = "";
+        prefix2 = strappend(prefix, "\t");
+        if (!prefix2)
+                prefix2 = "";
 
         fprintf(f,
-                "%sName %s:\n"
+                "%s→ Name %s:\n"
                 "%s\tDescription: %s\n"
                 "%s\tName Load State: %s\n"
                 "%s\tName Active State: %s\n",
@@ -439,19 +393,12 @@ void name_dump(Name *n, FILE *f, const char *prefix) {
         }
 
         if (NAME_VTABLE(n)->dump)
-                NAME_VTABLE(n)->dump(n, f, prefix);
+                NAME_VTABLE(n)->dump(n, f, prefix2);
 
-        if (n->meta.job) {
-                char *p;
-
-                if (asprintf(&p, "%s\t", prefix) >= 0)
-                        prefix = p;
-                else
-                        p = NULL;
+        if (n->meta.job)
+                job_dump(n->meta.job, f, prefix2);
 
-                job_dump(n->meta.job, f, prefix);
-                free(p);
-        }
+        free(prefix2);
 }
 
 static int verify_type(Name *name) {
@@ -521,14 +468,18 @@ int name_load(Name *name) {
                         goto fail;
 
         if ((r = name_sanitize(name)) < 0)
-                goto fail;
+                goto fail_undo_init;
 
         if ((r = name_link_names(name, false)) < 0)
-                goto fail;
+                goto fail_undo_init;
 
         name->meta.load_state = NAME_LOADED;
         return 0;
 
+fail_undo_init:
+        if (NAME_VTABLE(name)->done)
+                NAME_VTABLE(name)->done(name);
+
 fail:
         name->meta.load_state = NAME_FAILED;
         return r;
@@ -890,7 +841,7 @@ char *name_change_suffix(const char *t, const char *suffix) {
                 return NULL;
 
         memcpy(n, t, a);
-        memcpy(n+a, t, b+1);
+        memcpy(n+a, suffix, b+1);
 
         return n;
 }
@@ -919,3 +870,42 @@ bool name_job_is_applicable(Name *n, JobType j) {
                         assert_not_reached("Invalid job type");
         }
 }
+
+int name_add_dependency(Name *n, NameDependency d, Name *other) {
+
+        static const NameDependency inverse_table[_NAME_DEPENDENCY_MAX] = {
+                [NAME_REQUIRES] = NAME_REQUIRED_BY,
+                [NAME_SOFT_REQUIRES] = NAME_SOFT_REQUIRED_BY,
+                [NAME_WANTS] = NAME_WANTED_BY,
+                [NAME_REQUISITE] = NAME_REQUIRED_BY,
+                [NAME_SOFT_REQUISITE] = NAME_SOFT_REQUIRED_BY,
+                [NAME_REQUIRED_BY] = _NAME_DEPENDENCY_INVALID,
+                [NAME_SOFT_REQUIRED_BY] = _NAME_DEPENDENCY_INVALID,
+                [NAME_WANTED_BY] = _NAME_DEPENDENCY_INVALID,
+                [NAME_CONFLICTS] = NAME_CONFLICTS,
+                [NAME_BEFORE] = NAME_AFTER,
+                [NAME_AFTER] = NAME_BEFORE
+        };
+        int r;
+
+        assert(n);
+        assert(d >= 0 && d < _NAME_DEPENDENCY_MAX);
+        assert(inverse_table[d] != _NAME_DEPENDENCY_INVALID);
+        assert(other);
+
+        if ((r = set_ensure_allocated(&n->meta.dependencies[d], trivial_hash_func, trivial_compare_func)) < 0)
+                return r;
+
+        if ((r = set_ensure_allocated(&other->meta.dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0)
+                return r;
+
+        if ((r = set_put(n->meta.dependencies[d], other)) < 0)
+                return r;
+
+        if ((r = set_put(other->meta.dependencies[inverse_table[d]], n)) < 0) {
+                set_remove(n->meta.dependencies[d], other);
+                return r;
+        }
+
+        return 0;
+}
diff --git a/name.h b/name.h
index 9c638f3..8a4c174 100644 (file)
--- a/name.h
+++ b/name.h
@@ -75,6 +75,8 @@ enum NameDependency {
         NAME_WANTS,
         NAME_REQUISITE,
         NAME_SOFT_REQUISITE,
+
+        /* Inverse of the above */
         NAME_REQUIRED_BY,       /* inverse of 'requires' and 'requisite' is 'required_by' */
         NAME_SOFT_REQUIRED_BY,  /* inverse of 'soft_requires' and 'soft_requisite' is 'soft_required_by' */
         NAME_WANTED_BY,         /* inverse of 'wants' */
@@ -85,7 +87,9 @@ enum NameDependency {
         /* Order */
         NAME_BEFORE,            /* inverse of before is after and vice versa */
         NAME_AFTER,
-        _NAME_DEPENDENCY_MAX
+
+        _NAME_DEPENDENCY_MAX,
+        _NAME_DEPENDENCY_INVALID = -1
 };
 
 struct Meta {
@@ -230,4 +234,6 @@ char *name_change_suffix(const char *t, const char *suffix);
 
 bool name_job_is_applicable(Name *n, JobType j);
 
+int name_add_dependency(Name *n, NameDependency d, Name *other);
+
 #endif
index e661dc7..1e4824d 100644 (file)
--- a/service.c
+++ b/service.c
@@ -26,6 +26,33 @@ static const NameActiveState state_table[_SERVICE_STATE_MAX] = {
         [SERVICE_AUTO_RESTART] = NAME_ACTIVATING,
 };
 
+static void service_done(Name *n) {
+        Service *s = SERVICE(n);
+
+        assert(s);
+
+        free(s->pid_file);
+        s->pid_file = NULL;
+
+        exec_context_done(&s->exec_context);
+        exec_command_free_array(s->exec_command, _SERVICE_EXEC_MAX);
+        s->control_command = NULL;
+
+        /* This will leak a process, but at least no memory or any of
+         * our resources */
+        if (s->main_pid > 0) {
+                name_unwatch_pid(n, s->main_pid);
+                s->main_pid = 0;
+        }
+
+        if (s->control_pid > 0) {
+                name_unwatch_pid(n, s->control_pid);
+                s->control_pid = 0;
+        }
+
+        name_unwatch_timer(n, &s->timer_id);
+}
+
 static int service_load_sysv(Service *s) {
         assert(s);
 
@@ -63,41 +90,18 @@ static int service_init(Name *n) {
         if (r == -ENOENT)
                 r = service_load_sysv(s);
 
-        if (r < 0)
+        if (r < 0) {
+                service_done(n);
                 return r;
+        }
 
         /* Load dropin directory data */
-        if ((r = name_load_dropin(n)) < 0)
+        if ((r = name_load_dropin(n)) < 0) {
+                service_done(n);
                 return r;
-
-        return 0;
-}
-
-static void service_done(Name *n) {
-        Service *s = SERVICE(n);
-
-        assert(s);
-
-        free(s->pid_file);
-        s->pid_file = NULL;
-
-        exec_context_done(&s->exec_context);
-        exec_command_free_array(s->exec_command, _SERVICE_EXEC_MAX);
-        s->control_command = NULL;
-
-        /* This will leak a process, but at least no memory or any of
-         * our resources */
-        if (s->main_pid > 0) {
-                name_unwatch_pid(n, s->main_pid);
-                s->main_pid = 0;
-        }
-
-        if (s->control_pid > 0) {
-                name_unwatch_pid(n, s->control_pid);
-                s->control_pid = 0;
         }
 
-        name_unwatch_timer(n, &s->timer_id);
+        return 0;
 }
 
 static void service_dump(Name *n, FILE *f, const char *prefix) {
@@ -130,9 +134,14 @@ static void service_dump(Name *n, FILE *f, const char *prefix) {
 
         ServiceExecCommand c;
         Service *s = SERVICE(n);
+        char *prefix2;
 
         assert(s);
 
+        prefix2 = strappend(prefix, "\t");
+        if (!prefix2)
+                prefix2 = "";
+
         fprintf(f,
                 "%sService State: %s\n",
                 prefix, state_table[s->state]);
@@ -146,11 +155,17 @@ static void service_dump(Name *n, FILE *f, const char *prefix) {
         exec_context_dump(&s->exec_context, f, prefix);
 
         for (c = 0; c < _SERVICE_EXEC_MAX; c++) {
-                ExecCommand *i;
 
-                LIST_FOREACH(command, i, s->exec_command[c])
-                        fprintf(f, "%s%s: %s\n", prefix, command_table[c], i->path);
+                if (!s->exec_command[c])
+                        continue;
+
+                fprintf(f, "%s→ %s:\n",
+                        prefix, command_table[c]);
+
+                exec_command_dump_list(s->exec_command[c], f, prefix2);
         }
+
+        free(prefix2);
 }
 
 static int service_load_pid_file(Service *s) {
@@ -240,32 +255,106 @@ static void service_set_state(Service *s, ServiceState state) {
         name_notify(NAME(s), state_table[old_state], state_table[s->state]);
 }
 
-static int service_spawn(Service *s, ExecCommand *c, bool timeout, pid_t *_pid) {
+static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
+        Iterator i;
+        int r;
+        int *rfds = NULL;
+        unsigned rn_fds = 0;
+        char *t;
+
+        assert(s);
+        assert(fds);
+        assert(n_fds);
+
+        SET_FOREACH(t, NAME(s)->meta.names, i) {
+                char *k;
+                Name *p;
+                int *cfds;
+                unsigned cn_fds;
+
+                /* Look for all socket objects that go by any of our
+                 * names and collect their fds */
+
+                if (!(k = name_change_suffix(t, ".socket"))) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                p = manager_get_name(NAME(s)->meta.manager, k);
+                free(k);
+
+                if ((r = socket_collect_fds(SOCKET(p), &cfds, &cn_fds)) < 0)
+                        goto fail;
+
+                if (!cfds)
+                        continue;
+
+                if (!rfds) {
+                        rfds = cfds;
+                        rn_fds = cn_fds;
+                } else {
+                        int *t;
+
+                        if (!(t = new(int, rn_fds+cn_fds))) {
+                                free(cfds);
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+
+                        memcpy(t, rfds, rn_fds);
+                        memcpy(t+rn_fds, cfds, cn_fds);
+                        free(rfds);
+                        free(cfds);
+
+                        rfds = t;
+                        rn_fds = rn_fds+cn_fds;
+                }
+        }
+
+        *fds = rfds;
+        *n_fds = rn_fds;
+        return 0;
+
+fail:
+        free(rfds);
+        return r;
+}
+
+static int service_spawn(Service *s, ExecCommand *c, bool timeout, bool pass_fds, pid_t *_pid) {
         pid_t pid;
         int r;
+        int *fds = NULL;
+        unsigned n_fds = 0;
 
         assert(s);
         assert(c);
         assert(_pid);
 
+        if (pass_fds)
+                if ((r = service_collect_fds(s, &fds, &n_fds)) < 0)
+                        goto fail;
+
         if (timeout) {
                 if ((r = name_watch_timer(NAME(s), s->timeout_usec, &s->timer_id)) < 0)
                         goto fail;
         } else
                 name_unwatch_timer(NAME(s), &s->timer_id);
 
-        if ((r = exec_spawn(c, &s->exec_context, NULL, 0, &pid)) < 0)
+        if ((r = exec_spawn(c, &s->exec_context, fds, n_fds, &pid)) < 0)
                 goto fail;
 
         if ((r = name_watch_pid(NAME(s), pid)) < 0)
                 /* FIXME: we need to do something here */
                 goto fail;
 
+        free(fds);
         *_pid = pid;
 
         return 0;
 
 fail:
+        free(fds);
+
         if (timeout)
                 name_unwatch_timer(NAME(s), &s->timer_id);
 
@@ -308,7 +397,7 @@ static void service_enter_stop_post(Service *s, bool success) {
 
         if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) {
 
-                if ((r = service_spawn(s, s->control_command, true, &s->control_pid)) < 0)
+                if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0)
                         goto fail;
 
                 service_set_state(s, SERVICE_STOP_POST);
@@ -381,7 +470,7 @@ static void service_enter_stop(Service *s, bool success) {
 
         if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) {
 
-                if ((r = service_spawn(s, s->control_command, true, &s->control_pid)) < 0)
+                if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0)
                         goto fail;
 
                 service_set_state(s, SERVICE_STOP);
@@ -401,7 +490,7 @@ static void service_enter_start_post(Service *s) {
 
         if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) {
 
-                if ((r = service_spawn(s, s->control_command, true, &s->control_pid)) < 0)
+                if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0)
                         goto fail;
 
                 service_set_state(s, SERVICE_START_POST);
@@ -424,7 +513,7 @@ static void service_enter_start(Service *s) {
         assert(s->exec_command[SERVICE_EXEC_START]);
         assert(!s->exec_command[SERVICE_EXEC_START]->command_next);
 
-        if ((r = service_spawn(s, s->exec_command[SERVICE_EXEC_START], s->type == SERVICE_FORKING, &pid)) < 0)
+        if ((r = service_spawn(s, s->exec_command[SERVICE_EXEC_START], s->type == SERVICE_FORKING, true, &pid)) < 0)
                 goto fail;
 
         if (s->type == SERVICE_SIMPLE) {
@@ -460,7 +549,7 @@ static void service_enter_start_pre(Service *s) {
 
         if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) {
 
-                if ((r = service_spawn(s, s->control_command, true, &s->control_pid)) < 0)
+                if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0)
                         goto fail;
 
                 service_set_state(s, SERVICE_START_PRE);
@@ -498,7 +587,7 @@ static void service_enter_reload(Service *s) {
 
         if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) {
 
-                if ((r = service_spawn(s, s->control_command, true, &s->control_pid)) < 0)
+                if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0)
                         goto fail;
 
                 service_set_state(s, SERVICE_RELOAD);
@@ -524,7 +613,7 @@ static void service_run_next(Service *s, bool success) {
 
         s->control_command = s->control_command->command_next;
 
-        if ((r = service_spawn(s, s->control_command, true, &s->control_pid)) < 0)
+        if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0)
                 goto fail;
 
         return;
index a8a1914..23e347d 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -27,40 +27,6 @@ static const NameActiveState state_table[_SOCKET_STATE_MAX] = {
         [SOCKET_MAINTAINANCE] = NAME_INACTIVE,
 };
 
-static int socket_init(Name *n) {
-        Socket *s = SOCKET(n);
-        char *t;
-        int r;
-
-        /* First, reset everything to the defaults, in case this is a
-         * reload */
-
-        s->bind_ipv6_only = false;
-        s->backlog = SOMAXCONN;
-        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
-        exec_context_init(&s->exec_context);
-
-        if ((r = name_load_fragment_and_dropin(n)) < 0)
-                return r;
-
-        if (!(t = name_change_suffix(name_id(n), ".service")))
-                return -ENOMEM;
-
-        r = manager_load_name(n->meta.manager, t, (Name**) &s->service);
-        free(t);
-
-        if (r < 0)
-                return r;
-
-        if ((r = set_ensure_allocated(n->meta.dependencies + NAME_BEFORE, trivial_hash_func, trivial_compare_func)) < 0)
-                return r;
-
-        if ((r = set_put(n->meta.dependencies[NAME_BEFORE], s->service)) < 0)
-                return r;
-
-        return 0;
-}
-
 static void socket_done(Name *n) {
         Socket *s = SOCKET(n);
         SocketPort *p;
@@ -90,6 +56,45 @@ static void socket_done(Name *n) {
         name_unwatch_timer(n, &s->timer_id);
 }
 
+static int socket_init(Name *n) {
+        Socket *s = SOCKET(n);
+        char *t;
+        int r;
+
+        /* First, reset everything to the defaults, in case this is a
+         * reload */
+
+        s->state = 0;
+        s->timer_id = -1;
+        s->bind_ipv6_only = false;
+        s->backlog = SOMAXCONN;
+        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
+        exec_context_init(&s->exec_context);
+
+        if ((r = name_load_fragment_and_dropin(n)) < 0)
+                goto fail;
+
+        if (!(t = name_change_suffix(name_id(n), ".service"))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        r = manager_load_name(n->meta.manager, t, (Name**) &s->service);
+        free(t);
+
+        if (r < 0)
+                goto fail;
+
+        if ((r = name_add_dependency(n, NAME_BEFORE, NAME(s->service))) < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        socket_done(n);
+        return r;
+}
+
 static const char* listen_lookup(int type) {
 
         if (type == SOCK_STREAM)
@@ -705,6 +710,38 @@ static void socket_timer_event(Name *n, int id, uint64_t elapsed) {
         }
 }
 
+int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
+        int *rfds;
+        unsigned rn_fds, k;
+        SocketPort *p;
+
+        assert(s);
+        assert(fds);
+        assert(n_fds);
+
+        /* Called from the service code for requesting our fds */
+
+        rn_fds = 0;
+        LIST_FOREACH(port, p, s->ports)
+                if (p->fd >= 0)
+                        rn_fds++;
+
+        if (!(rfds = new(int, rn_fds)) < 0)
+                return -ENOMEM;
+
+        k = 0;
+        LIST_FOREACH(port, p, s->ports)
+                if (p->fd >= 0)
+                        rfds[k++] = p->fd;
+
+        assert(k == rn_fds);
+
+        *fds = rfds;
+        *n_fds = rn_fds;
+
+        return 0;
+}
+
 const NameVTable socket_vtable = {
         .suffix = ".socket",
 
index a8821f6..1e651c6 100644 (file)
--- a/socket.h
+++ b/socket.h
@@ -75,6 +75,9 @@ struct Socket {
         int timer_id;
 };
 
+/* Called from the service code when collecting fds */
+int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds);
+
 extern const NameVTable socket_vtable;
 
 #endif
index 77fdc76..fbf39ec 100644 (file)
@@ -4,4 +4,4 @@ Description=Postfix Mail Server
 Requires=syslog.socket
 
 [Service]
-Exec=/usr/bin/postfix
+ExecStart=/usr/bin/postfix
index 1baae5b..4c97218 100644 (file)
@@ -3,4 +3,4 @@ Description=Postfix SMTP Socket
 
 [Socket]
 ListenStream=53333
-ListenFIFO=/tmp/systemd-fifo
+ListenFIFO=/tmp/systemd-postfix-fifo
index e262809..8fe47ae 100644 (file)
@@ -2,4 +2,4 @@
 Description=System Logging Daemon
 
 [Service]
-Exec=/usr/bin/rsyslogd
+ExecStart=/usr/bin/rsyslogd --foobar 'waldo'
index 8d7baa5..56c903c 100644 (file)
@@ -2,5 +2,5 @@
 Description=Syslog Socket
 
 [Socket]
-ListenDatagram=/tmp/systemd-socket
+ListenDatagram=/tmp/systemd-syslog-socket
 ListenStream=eth0:3456
diff --git a/util.c b/util.c
index 2e310f9..b4b07e9 100644 (file)
--- a/util.c
+++ b/util.c
@@ -100,9 +100,9 @@ int close_nointr(int fd) {
 int parse_boolean(const char *v) {
         assert(v);
 
-        if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
+        if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
                 return 1;
-        else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
+        else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
                 return 0;
 
         return -EINVAL;
@@ -216,9 +216,6 @@ int safe_atolli(const char *s, long long int *ret_lli) {
         return 0;
 }
 
-/* What is interpreted as whitespace? */
-#define WHITESPACE " \t\n"
-
 /* Split a string into words. */
 char *split_spaces(const char *c, size_t *l, char **state) {
         char *current;
@@ -266,6 +263,9 @@ char *split_quoted(const char *c, size_t *l, char **state) {
                 *state = current+*l;
         }
 
+        /* FIXME: Cannot deal with strings that have spaces AND ticks
+         * in them */
+
         return (char*) current;
 }
 
@@ -382,3 +382,23 @@ finish:
         fclose(f);
         return r;
 }
+
+char *strappend(const char *s, const char *suffix) {
+        size_t a, b;
+        char *r;
+
+        assert(s);
+        assert(suffix);
+
+        a = strlen(s);
+        b = strlen(suffix);
+
+        if (!(r = new(char, a+b+1)))
+                return NULL;
+
+        memcpy(r, s, a);
+        memcpy(r+a, suffix, b);
+        r[a+b] = 0;
+
+        return r;
+}
diff --git a/util.h b/util.h
index 86fd7bb..3e86b29 100644 (file)
--- a/util.h
+++ b/util.h
@@ -18,6 +18,9 @@ typedef uint64_t usec_t;
 #define NSEC_PER_MSEC 1000000ULL
 #define NSEC_PER_USEC 1000ULL
 
+/* What is interpreted as whitespace? */
+#define WHITESPACE " \t\n"
+
 usec_t now(clockid_t clock);
 
 usec_t timespec_load(const struct timespec *ts);
@@ -86,4 +89,6 @@ pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
 int write_one_line_file(const char *fn, const char *line);
 int read_one_line_file(const char *fn, char **line);
 
+char *strappend(const char *s, const char *suffix);
+
 #endif