mirror of
https://github.com/AuxXxilium/eudev.git
synced 2024-12-15 02:56:51 +07:00
various cleanups
This commit is contained in:
parent
75787bb713
commit
44d8db9e5a
@ -12,7 +12,6 @@
|
|||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#define WHITESPACE " \t\n"
|
|
||||||
#define COMMENTS "#;\n"
|
#define COMMENTS "#;\n"
|
||||||
#define LINE_MAX 4096
|
#define LINE_MAX 4096
|
||||||
|
|
||||||
|
69
execute.c
69
execute.c
@ -5,6 +5,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
@ -235,7 +236,7 @@ void exec_command_free_list(ExecCommand *c) {
|
|||||||
LIST_REMOVE(ExecCommand, command, c, i);
|
LIST_REMOVE(ExecCommand, command, c, i);
|
||||||
|
|
||||||
free(i->path);
|
free(i->path);
|
||||||
free(i->argv);
|
strv_free(i->argv);
|
||||||
free(i);
|
free(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,3 +277,69 @@ void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status) {
|
|||||||
s->status = status;
|
s->status = status;
|
||||||
s->timestamp = now(CLOCK_REALTIME);
|
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);
|
||||||
|
}
|
||||||
|
@ -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_list(ExecCommand *c);
|
||||||
void exec_command_free_array(ExecCommand **c, unsigned n);
|
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_init(ExecContext *c);
|
||||||
void exec_context_done(ExecContext *c);
|
void exec_context_done(ExecContext *c);
|
||||||
void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
|
void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
|
||||||
|
47
job.c
47
job.c
@ -61,22 +61,12 @@ JobDependency* job_dependency_new(Job *subject, Job *object, bool matters) {
|
|||||||
l->object = object;
|
l->object = object;
|
||||||
l->matters = matters;
|
l->matters = matters;
|
||||||
|
|
||||||
if (subject) {
|
if (subject)
|
||||||
l->subject_next = subject->subject_list;
|
LIST_PREPEND(JobDependency, subject, subject->subject_list, l);
|
||||||
subject->subject_list = l;
|
else
|
||||||
} else {
|
LIST_PREPEND(JobDependency, subject, object->manager->transaction_anchor, l);
|
||||||
l->subject_next = object->manager->transaction_anchor;
|
|
||||||
object->manager->transaction_anchor = l;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (l->subject_next)
|
LIST_PREPEND(JobDependency, object, object->object_list, l);
|
||||||
l->subject_next->subject_prev = l;
|
|
||||||
l->subject_prev = NULL;
|
|
||||||
|
|
||||||
if ((l->object_next = object->object_list))
|
|
||||||
l->object_next->object_prev = l;
|
|
||||||
l->object_prev = NULL;
|
|
||||||
object->object_list = l;
|
|
||||||
|
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
@ -84,23 +74,12 @@ JobDependency* job_dependency_new(Job *subject, Job *object, bool matters) {
|
|||||||
void job_dependency_free(JobDependency *l) {
|
void job_dependency_free(JobDependency *l) {
|
||||||
assert(l);
|
assert(l);
|
||||||
|
|
||||||
if (l->subject_prev)
|
if (l->subject)
|
||||||
l->subject_prev->subject_next = l->subject_next;
|
LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
|
||||||
else if (l->subject)
|
|
||||||
l->subject->subject_list = l->subject_next;
|
|
||||||
else
|
else
|
||||||
l->object->manager->transaction_anchor = l->subject_next;
|
LIST_REMOVE(JobDependency, subject, l->object->manager->transaction_anchor, l);
|
||||||
|
|
||||||
if (l->subject_next)
|
LIST_REMOVE(JobDependency, object, l->object->object_list, l);
|
||||||
l->subject_next->subject_prev = l->subject_prev;
|
|
||||||
|
|
||||||
if (l->object_prev)
|
|
||||||
l->object_prev->object_next = l->object_next;
|
|
||||||
else
|
|
||||||
l->object->object_list = l->object_next;
|
|
||||||
|
|
||||||
if (l->object_next)
|
|
||||||
l->object_next->object_prev = l->object_prev;
|
|
||||||
|
|
||||||
free(l);
|
free(l);
|
||||||
}
|
}
|
||||||
@ -110,7 +89,7 @@ void job_dependency_delete(Job *subject, Job *object, bool *matters) {
|
|||||||
|
|
||||||
assert(object);
|
assert(object);
|
||||||
|
|
||||||
for (l = object->object_list; l; l = l->object_next) {
|
LIST_FOREACH(object, l, object->object_list) {
|
||||||
assert(l->object == object);
|
assert(l->object == object);
|
||||||
|
|
||||||
if (l->subject == subject)
|
if (l->subject == subject)
|
||||||
@ -158,7 +137,7 @@ void job_dump(Job *j, FILE*f, const char *prefix) {
|
|||||||
assert(f);
|
assert(f);
|
||||||
|
|
||||||
fprintf(f,
|
fprintf(f,
|
||||||
"%sJob %u:\n"
|
"%s→ Job %u:\n"
|
||||||
"%s\tAction: %s → %s\n"
|
"%s\tAction: %s → %s\n"
|
||||||
"%s\tState: %s\n"
|
"%s\tState: %s\n"
|
||||||
"%s\tForced: %s\n",
|
"%s\tForced: %s\n",
|
||||||
@ -173,7 +152,7 @@ bool job_is_anchor(Job *j) {
|
|||||||
|
|
||||||
assert(j);
|
assert(j);
|
||||||
|
|
||||||
for (l = j->object_list; l; l = l->object_next)
|
LIST_FOREACH(object, l, j->object_list)
|
||||||
if (!l->subject)
|
if (!l->subject)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -401,7 +380,7 @@ int job_run_and_invalidate(Job *j) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
;
|
assert_not_reached("Unknown job type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r == -EALREADY)
|
if (r == -EALREADY)
|
||||||
|
4
job.h
4
job.h
@ -77,8 +77,8 @@ struct Job {
|
|||||||
LIST_FIELDS(Job, transaction);
|
LIST_FIELDS(Job, transaction);
|
||||||
LIST_FIELDS(Job, run_queue);
|
LIST_FIELDS(Job, run_queue);
|
||||||
|
|
||||||
JobDependency *subject_list;
|
LIST_HEAD(JobDependency, subject_list);
|
||||||
JobDependency *object_list;
|
LIST_HEAD(JobDependency, object_list);
|
||||||
|
|
||||||
/* Used for graph algs as a "I have been here" marker */
|
/* Used for graph algs as a "I have been here" marker */
|
||||||
Job* marker;
|
Job* marker;
|
||||||
|
@ -20,7 +20,7 @@ static int config_parse_deps(
|
|||||||
void *data,
|
void *data,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
Set **set = data;
|
NameDependency d = PTR_TO_UINT(data);
|
||||||
Name *name = userdata;
|
Name *name = userdata;
|
||||||
char *w;
|
char *w;
|
||||||
size_t l;
|
size_t l;
|
||||||
@ -29,7 +29,6 @@ static int config_parse_deps(
|
|||||||
assert(filename);
|
assert(filename);
|
||||||
assert(lvalue);
|
assert(lvalue);
|
||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
|
||||||
|
|
||||||
FOREACH_WORD(w, &l, rvalue, state) {
|
FOREACH_WORD(w, &l, rvalue, state) {
|
||||||
char *t;
|
char *t;
|
||||||
@ -45,10 +44,7 @@ static int config_parse_deps(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if ((r = set_ensure_allocated(set, trivial_hash_func, trivial_compare_func)) < 0)
|
if ((r = name_add_dependency(name, d, other)) < 0)
|
||||||
return r;
|
|
||||||
|
|
||||||
if ((r = set_put(*set, other)) < 0)
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,6 +329,7 @@ static int config_parse_exec(
|
|||||||
if (!(n = new(char*, k+1)))
|
if (!(n = new(char*, k+1)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
k = 0;
|
||||||
FOREACH_WORD_QUOTED(w, l, rvalue, state)
|
FOREACH_WORD_QUOTED(w, l, rvalue, state)
|
||||||
if (!(n[k++] = strndup(w, l)))
|
if (!(n[k++] = strndup(w, l)))
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -487,14 +484,14 @@ int name_load_fragment(Name *n) {
|
|||||||
const ConfigItem items[] = {
|
const ConfigItem items[] = {
|
||||||
{ "Names", config_parse_names, &n->meta.names, "Meta" },
|
{ "Names", config_parse_names, &n->meta.names, "Meta" },
|
||||||
{ "Description", config_parse_string, &n->meta.description, "Meta" },
|
{ "Description", config_parse_string, &n->meta.description, "Meta" },
|
||||||
{ "Requires", config_parse_deps, n->meta.dependencies+NAME_REQUIRES, "Meta" },
|
{ "Requires", config_parse_deps, UINT_TO_PTR(NAME_REQUIRES), "Meta" },
|
||||||
{ "SoftRequires", config_parse_deps, n->meta.dependencies+NAME_SOFT_REQUIRES, "Meta" },
|
{ "SoftRequires", config_parse_deps, UINT_TO_PTR(NAME_SOFT_REQUIRES), "Meta" },
|
||||||
{ "Wants", config_parse_deps, n->meta.dependencies+NAME_WANTS, "Meta" },
|
{ "Wants", config_parse_deps, UINT_TO_PTR(NAME_WANTS), "Meta" },
|
||||||
{ "Requisite", config_parse_deps, n->meta.dependencies+NAME_REQUISITE, "Meta" },
|
{ "Requisite", config_parse_deps, UINT_TO_PTR(NAME_REQUISITE), "Meta" },
|
||||||
{ "SoftRequisite", config_parse_deps, n->meta.dependencies+NAME_SOFT_REQUISITE, "Meta" },
|
{ "SoftRequisite", config_parse_deps, UINT_TO_PTR(NAME_SOFT_REQUISITE), "Meta" },
|
||||||
{ "Conflicts", config_parse_deps, n->meta.dependencies+NAME_CONFLICTS, "Meta" },
|
{ "Conflicts", config_parse_deps, UINT_TO_PTR(NAME_CONFLICTS), "Meta" },
|
||||||
{ "Before", config_parse_deps, n->meta.dependencies+NAME_BEFORE, "Meta" },
|
{ "Before", config_parse_deps, UINT_TO_PTR(NAME_BEFORE), "Meta" },
|
||||||
{ "After", config_parse_deps, n->meta.dependencies+NAME_AFTER, "Meta" },
|
{ "After", config_parse_deps, UINT_TO_PTR(NAME_AFTER), "Meta" },
|
||||||
|
|
||||||
{ "PIDFile", config_parse_path, &n->service.pid_file, "Service" },
|
{ "PIDFile", config_parse_path, &n->service.pid_file, "Service" },
|
||||||
{ "ExecStartPre", config_parse_exec, &n->service.exec_command[SERVICE_EXEC_START_PRE], "Service" },
|
{ "ExecStartPre", config_parse_exec, &n->service.exec_command[SERVICE_EXEC_START_PRE], "Service" },
|
||||||
|
6
main.c
6
main.c
@ -36,13 +36,13 @@ int main(int argc, char *argv[]) {
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("- By names:\n");
|
printf("→ By names:\n");
|
||||||
manager_dump_names(m, stdout, "\t");
|
manager_dump_names(m, stdout, "\t");
|
||||||
|
|
||||||
printf("- By jobs:\n");
|
printf("→ By jobs:\n");
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, "\t");
|
||||||
|
|
||||||
manager_loop(m);
|
/* manager_loop(m); */
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
||||||
|
11
manager.c
11
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
|
* indirectly a dependency of the anchor job via paths that
|
||||||
* are fully marked as mattering. */
|
* 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 */
|
/* This link does not matter */
|
||||||
if (!l->matters)
|
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 */
|
/* Patch us in as new owner of the JobDependency objects */
|
||||||
last = NULL;
|
last = NULL;
|
||||||
for (l = other->subject_list; l; l = l->subject_next) {
|
LIST_FOREACH(subject, l, other->subject_list) {
|
||||||
assert(l->subject == other);
|
assert(l->subject == other);
|
||||||
l->subject = j;
|
l->subject = j;
|
||||||
last = l;
|
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 */
|
/* Patch us in as new owner of the JobDependency objects */
|
||||||
last = NULL;
|
last = NULL;
|
||||||
for (l = other->object_list; l; l = l->object_next) {
|
LIST_FOREACH(object, l, other->object_list) {
|
||||||
assert(l->object == other);
|
assert(l->object == other);
|
||||||
l->object = j;
|
l->object = j;
|
||||||
last = l;
|
last = l;
|
||||||
|
138
name.c
138
name.c
@ -13,6 +13,7 @@
|
|||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "load-fragment.h"
|
#include "load-fragment.h"
|
||||||
#include "load-dropin.h"
|
#include "load-dropin.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
const NameVTable * const name_vtable[_NAME_TYPE_MAX] = {
|
const NameVTable * const name_vtable[_NAME_TYPE_MAX] = {
|
||||||
[NAME_SERVICE] = &service_vtable,
|
[NAME_SERVICE] = &service_vtable,
|
||||||
@ -183,12 +184,14 @@ static void bidi_set_free(Name *name, Set *s) {
|
|||||||
/* Frees the set and makes sure we are dropped from the
|
/* Frees the set and makes sure we are dropped from the
|
||||||
* inverse pointers */
|
* inverse pointers */
|
||||||
|
|
||||||
|
if (name->meta.linked) {
|
||||||
SET_FOREACH(other, s, i) {
|
SET_FOREACH(other, s, i) {
|
||||||
NameDependency d;
|
NameDependency d;
|
||||||
|
|
||||||
for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
|
for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
|
||||||
set_remove(other->meta.dependencies[d], name);
|
set_remove(other->meta.dependencies[d], name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
set_free(s);
|
set_free(s);
|
||||||
}
|
}
|
||||||
@ -211,6 +214,10 @@ void name_free(Name *name) {
|
|||||||
LIST_REMOVE(Meta, load_queue, name->meta.manager->load_queue, &name->meta);
|
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 */
|
/* Free data and next 'smaller' objects */
|
||||||
if (name->meta.job)
|
if (name->meta.job)
|
||||||
job_free(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++)
|
for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
|
||||||
bidi_set_free(name, name->meta.dependencies[d]);
|
bidi_set_free(name, name->meta.dependencies[d]);
|
||||||
|
|
||||||
if (NAME_VTABLE(name)->done)
|
|
||||||
NAME_VTABLE(name)->done(name);
|
|
||||||
|
|
||||||
free(name->meta.description);
|
free(name->meta.description);
|
||||||
|
|
||||||
while ((t = set_steal_first(name->meta.names)))
|
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);
|
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) {
|
static int ensure_merge(Set **s, Set *other) {
|
||||||
|
|
||||||
if (!other)
|
if (!other)
|
||||||
@ -292,6 +281,7 @@ int name_merge(Name *name, Name *other) {
|
|||||||
|
|
||||||
/* Merge dependencies */
|
/* Merge dependencies */
|
||||||
for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
|
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)
|
if ((r = ensure_merge(&name->meta.dependencies[d], other->meta.dependencies[d])) < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -307,46 +297,6 @@ int name_merge(Name *name, Name *other) {
|
|||||||
return 0;
|
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) {
|
int name_sanitize(Name *n) {
|
||||||
NameDependency d;
|
NameDependency d;
|
||||||
|
|
||||||
@ -356,7 +306,7 @@ int name_sanitize(Name *n) {
|
|||||||
for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
|
for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
|
||||||
set_remove(n->meta.dependencies[d], n);
|
set_remove(n->meta.dependencies[d], n);
|
||||||
|
|
||||||
return augment(n);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* name_id(Name *n) {
|
const char* name_id(Name *n) {
|
||||||
@ -409,14 +359,18 @@ void name_dump(Name *n, FILE *f, const char *prefix) {
|
|||||||
char *t;
|
char *t;
|
||||||
NameDependency d;
|
NameDependency d;
|
||||||
Iterator i;
|
Iterator i;
|
||||||
|
char *prefix2;
|
||||||
|
|
||||||
assert(n);
|
assert(n);
|
||||||
|
|
||||||
if (!prefix)
|
if (!prefix)
|
||||||
prefix = "";
|
prefix = "";
|
||||||
|
prefix2 = strappend(prefix, "\t");
|
||||||
|
if (!prefix2)
|
||||||
|
prefix2 = "";
|
||||||
|
|
||||||
fprintf(f,
|
fprintf(f,
|
||||||
"%sName %s:\n"
|
"%s→ Name %s:\n"
|
||||||
"%s\tDescription: %s\n"
|
"%s\tDescription: %s\n"
|
||||||
"%s\tName Load State: %s\n"
|
"%s\tName Load State: %s\n"
|
||||||
"%s\tName Active 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)
|
if (NAME_VTABLE(n)->dump)
|
||||||
NAME_VTABLE(n)->dump(n, f, prefix);
|
NAME_VTABLE(n)->dump(n, f, prefix2);
|
||||||
|
|
||||||
if (n->meta.job) {
|
if (n->meta.job)
|
||||||
char *p;
|
job_dump(n->meta.job, f, prefix2);
|
||||||
|
|
||||||
if (asprintf(&p, "%s\t", prefix) >= 0)
|
free(prefix2);
|
||||||
prefix = p;
|
|
||||||
else
|
|
||||||
p = NULL;
|
|
||||||
|
|
||||||
job_dump(n->meta.job, f, prefix);
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verify_type(Name *name) {
|
static int verify_type(Name *name) {
|
||||||
@ -521,14 +468,18 @@ int name_load(Name *name) {
|
|||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if ((r = name_sanitize(name)) < 0)
|
if ((r = name_sanitize(name)) < 0)
|
||||||
goto fail;
|
goto fail_undo_init;
|
||||||
|
|
||||||
if ((r = name_link_names(name, false)) < 0)
|
if ((r = name_link_names(name, false)) < 0)
|
||||||
goto fail;
|
goto fail_undo_init;
|
||||||
|
|
||||||
name->meta.load_state = NAME_LOADED;
|
name->meta.load_state = NAME_LOADED;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail_undo_init:
|
||||||
|
if (NAME_VTABLE(name)->done)
|
||||||
|
NAME_VTABLE(name)->done(name);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
name->meta.load_state = NAME_FAILED;
|
name->meta.load_state = NAME_FAILED;
|
||||||
return r;
|
return r;
|
||||||
@ -890,7 +841,7 @@ char *name_change_suffix(const char *t, const char *suffix) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memcpy(n, t, a);
|
memcpy(n, t, a);
|
||||||
memcpy(n+a, t, b+1);
|
memcpy(n+a, suffix, b+1);
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@ -919,3 +870,42 @@ bool name_job_is_applicable(Name *n, JobType j) {
|
|||||||
assert_not_reached("Invalid job type");
|
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;
|
||||||
|
}
|
||||||
|
8
name.h
8
name.h
@ -75,6 +75,8 @@ enum NameDependency {
|
|||||||
NAME_WANTS,
|
NAME_WANTS,
|
||||||
NAME_REQUISITE,
|
NAME_REQUISITE,
|
||||||
NAME_SOFT_REQUISITE,
|
NAME_SOFT_REQUISITE,
|
||||||
|
|
||||||
|
/* Inverse of the above */
|
||||||
NAME_REQUIRED_BY, /* inverse of 'requires' and 'requisite' is 'required_by' */
|
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_SOFT_REQUIRED_BY, /* inverse of 'soft_requires' and 'soft_requisite' is 'soft_required_by' */
|
||||||
NAME_WANTED_BY, /* inverse of 'wants' */
|
NAME_WANTED_BY, /* inverse of 'wants' */
|
||||||
@ -85,7 +87,9 @@ enum NameDependency {
|
|||||||
/* Order */
|
/* Order */
|
||||||
NAME_BEFORE, /* inverse of before is after and vice versa */
|
NAME_BEFORE, /* inverse of before is after and vice versa */
|
||||||
NAME_AFTER,
|
NAME_AFTER,
|
||||||
_NAME_DEPENDENCY_MAX
|
|
||||||
|
_NAME_DEPENDENCY_MAX,
|
||||||
|
_NAME_DEPENDENCY_INVALID = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Meta {
|
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);
|
bool name_job_is_applicable(Name *n, JobType j);
|
||||||
|
|
||||||
|
int name_add_dependency(Name *n, NameDependency d, Name *other);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
171
service.c
171
service.c
@ -26,6 +26,33 @@ static const NameActiveState state_table[_SERVICE_STATE_MAX] = {
|
|||||||
[SERVICE_AUTO_RESTART] = NAME_ACTIVATING,
|
[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) {
|
static int service_load_sysv(Service *s) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
@ -63,43 +90,20 @@ static int service_init(Name *n) {
|
|||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
r = service_load_sysv(s);
|
r = service_load_sysv(s);
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
|
service_done(n);
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/* Load dropin directory data */
|
/* Load dropin directory data */
|
||||||
if ((r = name_load_dropin(n)) < 0)
|
if ((r = name_load_dropin(n)) < 0) {
|
||||||
|
service_done(n);
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void service_dump(Name *n, FILE *f, const char *prefix) {
|
static void service_dump(Name *n, FILE *f, const char *prefix) {
|
||||||
|
|
||||||
static const char* const state_table[_SERVICE_STATE_MAX] = {
|
static const char* const state_table[_SERVICE_STATE_MAX] = {
|
||||||
@ -130,9 +134,14 @@ static void service_dump(Name *n, FILE *f, const char *prefix) {
|
|||||||
|
|
||||||
ServiceExecCommand c;
|
ServiceExecCommand c;
|
||||||
Service *s = SERVICE(n);
|
Service *s = SERVICE(n);
|
||||||
|
char *prefix2;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
|
prefix2 = strappend(prefix, "\t");
|
||||||
|
if (!prefix2)
|
||||||
|
prefix2 = "";
|
||||||
|
|
||||||
fprintf(f,
|
fprintf(f,
|
||||||
"%sService State: %s\n",
|
"%sService State: %s\n",
|
||||||
prefix, state_table[s->state]);
|
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);
|
exec_context_dump(&s->exec_context, f, prefix);
|
||||||
|
|
||||||
for (c = 0; c < _SERVICE_EXEC_MAX; c++) {
|
for (c = 0; c < _SERVICE_EXEC_MAX; c++) {
|
||||||
ExecCommand *i;
|
|
||||||
|
|
||||||
LIST_FOREACH(command, i, s->exec_command[c])
|
if (!s->exec_command[c])
|
||||||
fprintf(f, "%s%s: %s\n", prefix, command_table[c], i->path);
|
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) {
|
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]);
|
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;
|
pid_t pid;
|
||||||
int r;
|
int r;
|
||||||
|
int *fds = NULL;
|
||||||
|
unsigned n_fds = 0;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
assert(c);
|
assert(c);
|
||||||
assert(_pid);
|
assert(_pid);
|
||||||
|
|
||||||
|
if (pass_fds)
|
||||||
|
if ((r = service_collect_fds(s, &fds, &n_fds)) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
if ((r = name_watch_timer(NAME(s), s->timeout_usec, &s->timer_id)) < 0)
|
if ((r = name_watch_timer(NAME(s), s->timeout_usec, &s->timer_id)) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
} else
|
} else
|
||||||
name_unwatch_timer(NAME(s), &s->timer_id);
|
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;
|
goto fail;
|
||||||
|
|
||||||
if ((r = name_watch_pid(NAME(s), pid)) < 0)
|
if ((r = name_watch_pid(NAME(s), pid)) < 0)
|
||||||
/* FIXME: we need to do something here */
|
/* FIXME: we need to do something here */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
free(fds);
|
||||||
*_pid = pid;
|
*_pid = pid;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
free(fds);
|
||||||
|
|
||||||
if (timeout)
|
if (timeout)
|
||||||
name_unwatch_timer(NAME(s), &s->timer_id);
|
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 ((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;
|
goto fail;
|
||||||
|
|
||||||
service_set_state(s, SERVICE_STOP_POST);
|
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 ((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;
|
goto fail;
|
||||||
|
|
||||||
service_set_state(s, SERVICE_STOP);
|
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 ((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;
|
goto fail;
|
||||||
|
|
||||||
service_set_state(s, SERVICE_START_POST);
|
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]);
|
||||||
assert(!s->exec_command[SERVICE_EXEC_START]->command_next);
|
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;
|
goto fail;
|
||||||
|
|
||||||
if (s->type == SERVICE_SIMPLE) {
|
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 ((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;
|
goto fail;
|
||||||
|
|
||||||
service_set_state(s, SERVICE_START_PRE);
|
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 ((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;
|
goto fail;
|
||||||
|
|
||||||
service_set_state(s, SERVICE_RELOAD);
|
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;
|
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;
|
goto fail;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
105
socket.c
105
socket.c
@ -27,40 +27,6 @@ static const NameActiveState state_table[_SOCKET_STATE_MAX] = {
|
|||||||
[SOCKET_MAINTAINANCE] = NAME_INACTIVE,
|
[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) {
|
static void socket_done(Name *n) {
|
||||||
Socket *s = SOCKET(n);
|
Socket *s = SOCKET(n);
|
||||||
SocketPort *p;
|
SocketPort *p;
|
||||||
@ -90,6 +56,45 @@ static void socket_done(Name *n) {
|
|||||||
name_unwatch_timer(n, &s->timer_id);
|
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) {
|
static const char* listen_lookup(int type) {
|
||||||
|
|
||||||
if (type == SOCK_STREAM)
|
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 = {
|
const NameVTable socket_vtable = {
|
||||||
.suffix = ".socket",
|
.suffix = ".socket",
|
||||||
|
|
||||||
|
3
socket.h
3
socket.h
@ -75,6 +75,9 @@ struct Socket {
|
|||||||
int timer_id;
|
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;
|
extern const NameVTable socket_vtable;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,4 +4,4 @@ Description=Postfix Mail Server
|
|||||||
Requires=syslog.socket
|
Requires=syslog.socket
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Exec=/usr/bin/postfix
|
ExecStart=/usr/bin/postfix
|
||||||
|
@ -3,4 +3,4 @@ Description=Postfix SMTP Socket
|
|||||||
|
|
||||||
[Socket]
|
[Socket]
|
||||||
ListenStream=53333
|
ListenStream=53333
|
||||||
ListenFIFO=/tmp/systemd-fifo
|
ListenFIFO=/tmp/systemd-postfix-fifo
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
Description=System Logging Daemon
|
Description=System Logging Daemon
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Exec=/usr/bin/rsyslogd
|
ExecStart=/usr/bin/rsyslogd --foobar 'waldo'
|
||||||
|
@ -2,5 +2,5 @@
|
|||||||
Description=Syslog Socket
|
Description=Syslog Socket
|
||||||
|
|
||||||
[Socket]
|
[Socket]
|
||||||
ListenDatagram=/tmp/systemd-socket
|
ListenDatagram=/tmp/systemd-syslog-socket
|
||||||
ListenStream=eth0:3456
|
ListenStream=eth0:3456
|
||||||
|
30
util.c
30
util.c
@ -100,9 +100,9 @@ int close_nointr(int fd) {
|
|||||||
int parse_boolean(const char *v) {
|
int parse_boolean(const char *v) {
|
||||||
assert(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;
|
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 0;
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -216,9 +216,6 @@ int safe_atolli(const char *s, long long int *ret_lli) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* What is interpreted as whitespace? */
|
|
||||||
#define WHITESPACE " \t\n"
|
|
||||||
|
|
||||||
/* Split a string into words. */
|
/* Split a string into words. */
|
||||||
char *split_spaces(const char *c, size_t *l, char **state) {
|
char *split_spaces(const char *c, size_t *l, char **state) {
|
||||||
char *current;
|
char *current;
|
||||||
@ -266,6 +263,9 @@ char *split_quoted(const char *c, size_t *l, char **state) {
|
|||||||
*state = current+*l;
|
*state = current+*l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: Cannot deal with strings that have spaces AND ticks
|
||||||
|
* in them */
|
||||||
|
|
||||||
return (char*) current;
|
return (char*) current;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,3 +382,23 @@ finish:
|
|||||||
fclose(f);
|
fclose(f);
|
||||||
return r;
|
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;
|
||||||
|
}
|
||||||
|
5
util.h
5
util.h
@ -18,6 +18,9 @@ typedef uint64_t usec_t;
|
|||||||
#define NSEC_PER_MSEC 1000000ULL
|
#define NSEC_PER_MSEC 1000000ULL
|
||||||
#define NSEC_PER_USEC 1000ULL
|
#define NSEC_PER_USEC 1000ULL
|
||||||
|
|
||||||
|
/* What is interpreted as whitespace? */
|
||||||
|
#define WHITESPACE " \t\n"
|
||||||
|
|
||||||
usec_t now(clockid_t clock);
|
usec_t now(clockid_t clock);
|
||||||
|
|
||||||
usec_t timespec_load(const struct timespec *ts);
|
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 write_one_line_file(const char *fn, const char *line);
|
||||||
int read_one_line_file(const char *fn, char **line);
|
int read_one_line_file(const char *fn, char **line);
|
||||||
|
|
||||||
|
char *strappend(const char *s, const char *suffix);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user