#include "strv.h"
#include "log.h"
-#define WHITESPACE " \t\n"
#define COMMENTS "#;\n"
#define LINE_MAX 4096
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
+#include <string.h>
#include "execute.h"
#include "strv.h"
LIST_REMOVE(ExecCommand, command, c, i);
free(i->path);
- free(i->argv);
+ strv_free(i->argv);
free(i);
}
}
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);
+}
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);
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;
}
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);
}
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)
assert(f);
fprintf(f,
- "%sJob %u:\n"
+ "%sā Job %u:\n"
"%s\tAction: %s ā %s\n"
"%s\tState: %s\n"
"%s\tForced: %s\n",
assert(j);
- for (l = j->object_list; l; l = l->object_next)
+ LIST_FOREACH(object, l, j->object_list)
if (!l->subject)
return true;
}
default:
- ;
+ assert_not_reached("Unknown job type");
}
if (r == -EALREADY)
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;
void *data,
void *userdata) {
- Set **set = data;
+ NameDependency d = PTR_TO_UINT(data);
Name *name = userdata;
char *w;
size_t l;
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(data);
FOREACH_WORD(w, &l, rvalue, state) {
char *t;
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;
}
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;
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" },
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;
* 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)
/* 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;
/* 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;
#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,
/* 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);
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);
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)))
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)
/* 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;
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;
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) {
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",
}
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) {
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;
return NULL;
memcpy(n, t, a);
- memcpy(n+a, t, b+1);
+ memcpy(n+a, suffix, b+1);
return n;
}
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;
+}
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' */
/* 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 {
bool name_job_is_applicable(Name *n, JobType j);
+int name_add_dependency(Name *n, NameDependency d, Name *other);
+
#endif
[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);
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) {
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]);
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) {
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);
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);
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);
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);
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) {
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);
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);
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;
[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;
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)
}
}
+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",
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
Requires=syslog.socket
[Service]
-Exec=/usr/bin/postfix
+ExecStart=/usr/bin/postfix
[Socket]
ListenStream=53333
-ListenFIFO=/tmp/systemd-fifo
+ListenFIFO=/tmp/systemd-postfix-fifo
Description=System Logging Daemon
[Service]
-Exec=/usr/bin/rsyslogd
+ExecStart=/usr/bin/rsyslogd --foobar 'waldo'
Description=Syslog Socket
[Socket]
-ListenDatagram=/tmp/systemd-socket
+ListenDatagram=/tmp/systemd-syslog-socket
ListenStream=eth0:3456
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;
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;
*state = current+*l;
}
+ /* FIXME: Cannot deal with strings that have spaces AND ticks
+ * in them */
+
return (char*) current;
}
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;
+}
#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);
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