mirror of
https://github.com/AuxXxilium/eudev.git
synced 2024-11-24 07:20:56 +07:00
implement drop-in directories
This commit is contained in:
parent
87f0e418cf
commit
0301abf48e
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
||||
CFLAGS=-Wall -Wextra -O0 -g -pipe -D_GNU_SOURCE -fdiagnostics-show-option -Wno-unused-parameter
|
||||
CFLAGS=-Wall -Wextra -O0 -g -pipe -D_GNU_SOURCE -fdiagnostics-show-option -Wno-unused-parameter -DUNIT_PATH=\"/tmp/does/not/exist\"
|
||||
LIBS=-lrt -lcap
|
||||
|
||||
COMMON= \
|
||||
|
@ -1,11 +1,72 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8 -*-*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "unit.h"
|
||||
#include "load-dropin.h"
|
||||
|
||||
int unit_load_dropin(Unit *u) {
|
||||
Iterator i;
|
||||
int r;
|
||||
char *t;
|
||||
|
||||
assert(u);
|
||||
|
||||
/* Load dependencies from supplementary drop-in directories */
|
||||
|
||||
SET_FOREACH(t, u->meta.names, i) {
|
||||
char *path;
|
||||
DIR *d;
|
||||
struct dirent *de;
|
||||
|
||||
if (asprintf(&path, "%s/%s.wants", unit_path(), t) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!(d = opendir(path))) {
|
||||
r = -errno;
|
||||
free(path);
|
||||
|
||||
if (r == -ENOENT)
|
||||
continue;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
free(path);
|
||||
|
||||
while ((de = readdir(d))) {
|
||||
Unit *other;
|
||||
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
assert(de->d_name[0]);
|
||||
|
||||
if (de->d_name[strlen(de->d_name)-1] == '~')
|
||||
continue;
|
||||
|
||||
if (asprintf(&path, "%s/%s.wants/%s", unit_path(), t, de->d_name) < 0) {
|
||||
closedir(d);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = manager_load_unit(u->meta.manager, path, &other);
|
||||
free(path);
|
||||
|
||||
if (r < 0) {
|
||||
closedir(d);
|
||||
return r;
|
||||
}
|
||||
|
||||
if ((r = unit_add_dependency(u, UNIT_WANTS, other)) < 0) {
|
||||
closedir(d);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
187
load-fragment.c
187
load-fragment.c
@ -328,7 +328,7 @@ static int config_parse_exec(
|
||||
|
||||
n[k] = NULL;
|
||||
|
||||
if (!n[0] || n[0][0] != '/') {
|
||||
if (!n[0] || !path_is_absolute(n[0])) {
|
||||
log_error("[%s:%u] Invalid executable path in command line: %s", filename, line, rvalue);
|
||||
strv_free(n);
|
||||
return -EINVAL;
|
||||
@ -463,7 +463,7 @@ static char *build_path(const char *path, const char *filename) {
|
||||
* filename, unless the latter is absolute anyway or the
|
||||
* former isn't */
|
||||
|
||||
if (filename[0] == '/')
|
||||
if (path_is_absolute(filename))
|
||||
return strdup(filename);
|
||||
|
||||
if (!(e = strrchr(path, '/')))
|
||||
@ -479,88 +479,73 @@ static char *build_path(const char *path, const char *filename) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int open_follow(const char **filename, FILE **_f, Set *names) {
|
||||
unsigned c;
|
||||
static int open_follow(char **filename, FILE **_f, Set *names, char **_id) {
|
||||
unsigned c = 0;
|
||||
int fd, r;
|
||||
FILE *f;
|
||||
char *n = NULL;
|
||||
const char *fn;
|
||||
char *id = NULL;
|
||||
|
||||
assert(filename);
|
||||
assert(*filename);
|
||||
assert(_f);
|
||||
assert(names);
|
||||
|
||||
fn = *filename;
|
||||
/* This will update the filename pointer if the loaded file is
|
||||
* reached by a symlink. The old string will be freed. */
|
||||
|
||||
for (c = 0; c < FOLLOW_MAX; c++) {
|
||||
for (;;) {
|
||||
char *target, *k, *name;
|
||||
|
||||
if (c++ >= FOLLOW_MAX)
|
||||
return -ELOOP;
|
||||
|
||||
/* Add the file name we are currently looking at to
|
||||
* the names of this unit */
|
||||
name = file_name_from_path(fn);
|
||||
if (!set_get(names, name)) {
|
||||
name = file_name_from_path(*filename);
|
||||
if (!(id = set_get(names, name))) {
|
||||
|
||||
if (!(name = strdup(name))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
if (!(id = strdup(name)))
|
||||
return -ENOMEM;
|
||||
|
||||
if ((r = set_put(names, id)) < 0) {
|
||||
free(id);
|
||||
return r;
|
||||
}
|
||||
|
||||
if ((r = set_put(names, name)) < 0) {
|
||||
free(name);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
free(name);
|
||||
}
|
||||
|
||||
/* Try to open the file name, but don' if its a symlink */
|
||||
fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
|
||||
if (fd >= 0 || errno != ELOOP)
|
||||
/* Try to open the file name, but don't if its a symlink */
|
||||
if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
|
||||
break;
|
||||
|
||||
/* Hmm, so this is a symlink. Let's read the name, and follow it manually */
|
||||
if ((r = readlink_malloc(fn, &target)) < 0)
|
||||
goto finish;
|
||||
if (errno != ELOOP)
|
||||
return -errno;
|
||||
|
||||
k = build_path(fn, target);
|
||||
/* Hmm, so this is a symlink. Let's read the name, and follow it manually */
|
||||
if ((r = readlink_malloc(*filename, &target)) < 0)
|
||||
return r;
|
||||
|
||||
k = build_path(*filename, target);
|
||||
free(target);
|
||||
|
||||
if (!k) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
free(n);
|
||||
fn = n = k;
|
||||
}
|
||||
|
||||
if (c >= FOLLOW_MAX) {
|
||||
r = -ELOOP;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
free(*filename);
|
||||
*filename = k;
|
||||
}
|
||||
|
||||
if (!(f = fdopen(fd, "r"))) {
|
||||
r = -errno;
|
||||
assert(close_nointr(fd) == 0);
|
||||
goto finish;
|
||||
return r;
|
||||
}
|
||||
|
||||
*_f = f;
|
||||
*filename = fn;
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
free(n);
|
||||
return r;
|
||||
*_id = id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_load_fragment(Unit *u) {
|
||||
static int load_from_path(Unit *u, const char *path) {
|
||||
|
||||
static const char* const section_table[_UNIT_TYPE_MAX] = {
|
||||
[UNIT_SERVICE] = "Service",
|
||||
@ -627,14 +612,12 @@ int unit_load_fragment(Unit *u) {
|
||||
|
||||
#undef EXEC_CONTEXT_CONFIG_ITEMS
|
||||
|
||||
char *t, *k;
|
||||
int r;
|
||||
const char *sections[3];
|
||||
Iterator i;
|
||||
char *k;
|
||||
int r;
|
||||
Set *symlink_names;
|
||||
|
||||
assert(u);
|
||||
assert(u->meta.load_state == UNIT_STUB);
|
||||
FILE *f;
|
||||
char *filename, *id;
|
||||
|
||||
sections[0] = "Meta";
|
||||
sections[1] = section_table[u->meta.type];
|
||||
@ -643,51 +626,69 @@ int unit_load_fragment(Unit *u) {
|
||||
if (!(symlink_names = set_new(string_hash_func, string_compare_func)))
|
||||
return -ENOMEM;
|
||||
|
||||
/* Try to find a name we can load this with */
|
||||
SET_FOREACH(t, u->meta.names, i) {
|
||||
FILE *f;
|
||||
char *fn;
|
||||
|
||||
/* Clear the symlink name set first */
|
||||
while ((k = set_steal_first(symlink_names)))
|
||||
free(k);
|
||||
|
||||
/* Instead of opening the path right away, we manually
|
||||
* follow all symlinks and add their name to our unit
|
||||
* name set while doing so */
|
||||
fn = t;
|
||||
if ((r = open_follow((const char**) &fn, &f, symlink_names)) < 0) {
|
||||
if (r == -ENOENT)
|
||||
continue;
|
||||
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Now, parse the file contents */
|
||||
r = config_parse(fn, f, sections, items, u);
|
||||
if (fn != t)
|
||||
free(fn);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
/* Let's try to add in all symlink names we found */
|
||||
while ((k = set_steal_first(symlink_names)))
|
||||
if ((r = unit_add_name(u, k)) < 0)
|
||||
goto finish;
|
||||
|
||||
/* Yay, we succeeded! Now let's call this our identifier */
|
||||
u->meta.id = t;
|
||||
/* Instead of opening the path right away, we manually
|
||||
* follow all symlinks and add their name to our unit
|
||||
* name set while doing so */
|
||||
if (!(filename = path_make_absolute(path, unit_path()))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
|
||||
if (r == -ENOENT)
|
||||
r = 0; /* returning 0 means: no suitable config file found */
|
||||
|
||||
r = -ENOENT;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Now, parse the file contents */
|
||||
r = config_parse(filename, f, sections, items, u);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
/* Let's try to add in all symlink names we found */
|
||||
while ((k = set_steal_first(symlink_names))) {
|
||||
if ((r = unit_add_name(u, k)) < 0)
|
||||
goto finish;
|
||||
|
||||
if (id == k)
|
||||
assert_se(u->meta.id = set_get(u->meta.names, k));
|
||||
|
||||
free(k);
|
||||
}
|
||||
|
||||
free(u->meta.load_path);
|
||||
u->meta.load_path = filename;
|
||||
filename = NULL;
|
||||
|
||||
r = 1; /* returning 1 means: suitable config file found and loaded */
|
||||
|
||||
finish:
|
||||
while ((k = set_steal_first(symlink_names)))
|
||||
free(k);
|
||||
|
||||
set_free(symlink_names);
|
||||
free(filename);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int unit_load_fragment(Unit *u) {
|
||||
int r = -ENOENT;
|
||||
|
||||
assert(u);
|
||||
assert(u->meta.load_state == UNIT_STUB);
|
||||
|
||||
if (u->meta.load_path)
|
||||
r = load_from_path(u, u->meta.load_path);
|
||||
else {
|
||||
Iterator i;
|
||||
char *t;
|
||||
|
||||
/* Try to find a name we can load this with */
|
||||
SET_FOREACH(t, u->meta.names, i)
|
||||
if ((r = load_from_path(u, t)) != 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
10
main.c
10
main.c
@ -14,7 +14,7 @@ int main(int argc, char *argv[]) {
|
||||
Job *job = NULL;
|
||||
int r, retval = 1;
|
||||
|
||||
assert_se(chdir("test1") == 0);
|
||||
assert_se(set_unit_path("test1") >= 0);
|
||||
|
||||
if (!(m = manager_new()) < 0) {
|
||||
log_error("Failed to allocate manager object: %s", strerror(ENOMEM));
|
||||
@ -26,10 +26,10 @@ int main(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if ((r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &job)) < 0) {
|
||||
log_error("Failed to start default target: %s", strerror(-r));
|
||||
goto finish;
|
||||
}
|
||||
/* if ((r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &job)) < 0) { */
|
||||
/* log_error("Failed to start default target: %s", strerror(-r)); */
|
||||
/* goto finish; */
|
||||
/* } */
|
||||
|
||||
printf("→ By units:\n");
|
||||
manager_dump_units(m, stdout, "\t");
|
||||
|
16
manager.c
16
manager.c
@ -830,16 +830,19 @@ static void dispatch_load_queue(Manager *m) {
|
||||
m->dispatching_load_queue = false;
|
||||
}
|
||||
|
||||
int manager_load_unit(Manager *m, const char *name, Unit **_ret) {
|
||||
int manager_load_unit(Manager *m, const char *path, Unit **_ret) {
|
||||
Unit *ret;
|
||||
int r;
|
||||
const char *name;
|
||||
|
||||
assert(m);
|
||||
assert(name);
|
||||
assert(path);
|
||||
assert(_ret);
|
||||
|
||||
/* This will load the service information files, but not actually
|
||||
* start any services or anything */
|
||||
* start any services or anything. */
|
||||
|
||||
name = file_name_from_path(path);
|
||||
|
||||
if ((ret = manager_get_unit(m, name))) {
|
||||
*_ret = ret;
|
||||
@ -849,6 +852,13 @@ int manager_load_unit(Manager *m, const char *name, Unit **_ret) {
|
||||
if (!(ret = unit_new(m)))
|
||||
return -ENOMEM;
|
||||
|
||||
if (is_path(path)) {
|
||||
if (!(ret->meta.load_path = strdup(path))) {
|
||||
unit_free(ret);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if ((r = unit_add_name(ret, name)) < 0) {
|
||||
unit_free(ret);
|
||||
return r;
|
||||
|
@ -58,7 +58,7 @@ void manager_free(Manager *m);
|
||||
Job *manager_get_job(Manager *m, uint32_t id);
|
||||
Unit *manager_get_unit(Manager *m, const char *name);
|
||||
|
||||
int manager_load_unit(Manager *m, const char *name, Unit **_ret);
|
||||
int manager_load_unit(Manager *m, const char *path_or_name, Unit **_ret);
|
||||
int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, Job **_ret);
|
||||
|
||||
void manager_dump_units(Manager *s, FILE *f, const char *prefix);
|
||||
|
2
target.c
2
target.c
@ -19,7 +19,7 @@ static UnitActiveState target_active_state(Unit *u) {
|
||||
const UnitVTable target_vtable = {
|
||||
.suffix = ".target",
|
||||
|
||||
.init = unit_load_fragment,
|
||||
.init = unit_load_fragment_and_dropin,
|
||||
.done = target_done,
|
||||
|
||||
.active_state = target_active_state
|
||||
|
@ -12,7 +12,7 @@ int main(int argc, char *argv[]) {
|
||||
Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL;
|
||||
Job *j;
|
||||
|
||||
assert_se(chdir("test2") == 0);
|
||||
assert_se(set_unit_path("test2") >= 0);
|
||||
|
||||
assert_se(m = manager_new());
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
[Meta]
|
||||
Names=multiuser.target
|
||||
Wants=postfix.socket syslog.socket
|
||||
Description=Default Target
|
1
test1/default.target
Symbolic link
1
test1/default.target
Symbolic link
@ -0,0 +1 @@
|
||||
multiuser.target
|
1
test1/mail-transfer-agent.service
Symbolic link
1
test1/mail-transfer-agent.service
Symbolic link
@ -0,0 +1 @@
|
||||
postfix.service
|
1
test1/mail-transfer-agent.socket
Symbolic link
1
test1/mail-transfer-agent.socket
Symbolic link
@ -0,0 +1 @@
|
||||
postfix.socket
|
3
test1/multiuser.target
Normal file
3
test1/multiuser.target
Normal file
@ -0,0 +1,3 @@
|
||||
[Meta]
|
||||
Wants=syslog.socket
|
||||
Description=Multi-User Target
|
1
test1/multiuser.target.wants/mail-transfer-agent.socket
Symbolic link
1
test1/multiuser.target.wants/mail-transfer-agent.socket
Symbolic link
@ -0,0 +1 @@
|
||||
../mail-transfer-agent.socket
|
45
unit.c
45
unit.c
@ -6,6 +6,8 @@
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "set.h"
|
||||
#include "unit.h"
|
||||
@ -206,6 +208,7 @@ void unit_free(Unit *u) {
|
||||
bidi_set_free(u, u->meta.dependencies[d]);
|
||||
|
||||
free(u->meta.description);
|
||||
free(u->meta.load_path);
|
||||
|
||||
while ((t = set_steal_first(u->meta.names)))
|
||||
free(t);
|
||||
@ -338,6 +341,9 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
prefix, load_state_table[u->meta.load_state],
|
||||
prefix, active_state_table[unit_active_state(u)]);
|
||||
|
||||
if (u->meta.load_path)
|
||||
fprintf(f, "%s\tLoad Path: %s\n", prefix, u->meta.load_path);
|
||||
|
||||
SET_FOREACH(t, u->meta.names, i)
|
||||
fprintf(f, "%s\tName: %s\n", prefix, t);
|
||||
|
||||
@ -805,3 +811,42 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *unit_path(void) {
|
||||
char *e;
|
||||
|
||||
if ((e = getenv("UNIT_PATH")))
|
||||
if (path_is_absolute(e))
|
||||
return e;
|
||||
|
||||
return UNIT_PATH;
|
||||
}
|
||||
|
||||
int set_unit_path(const char *p) {
|
||||
char *cwd, *c;
|
||||
int r;
|
||||
|
||||
/* This is mostly for debug purposes */
|
||||
|
||||
if (path_is_absolute(p)) {
|
||||
if (!(c = strdup(p)))
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
if (!(cwd = get_current_dir_name()))
|
||||
return -errno;
|
||||
|
||||
r = asprintf(&c, "%s/%s", cwd, p);
|
||||
free(cwd);
|
||||
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (setenv("UNIT_PATH", c, 0) < 0) {
|
||||
r = -errno;
|
||||
free(c);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
5
unit.h
5
unit.h
@ -103,6 +103,7 @@ struct Meta {
|
||||
Set *dependencies[_UNIT_DEPENDENCY_MAX];
|
||||
|
||||
char *description;
|
||||
char *load_path; /* if loaded from a config file this is the primary path to it */
|
||||
|
||||
/* If there is something to do with this unit, then this is
|
||||
* the job for it */
|
||||
@ -232,4 +233,8 @@ void unit_unwatch_timer(Unit *u, int *id);
|
||||
|
||||
bool unit_job_is_applicable(Unit *u, JobType j);
|
||||
|
||||
const char *unit_path(void);
|
||||
int set_unit_path(const char *p);
|
||||
|
||||
|
||||
#endif
|
||||
|
25
util.c
25
util.c
@ -443,3 +443,28 @@ char *file_name_from_path(const char *p) {
|
||||
|
||||
return (char*) p;
|
||||
}
|
||||
|
||||
bool path_is_absolute(const char *p) {
|
||||
assert(p);
|
||||
|
||||
return p[0] == '/';
|
||||
}
|
||||
|
||||
bool is_path(const char *p) {
|
||||
|
||||
return !!strchr(p, '/');
|
||||
}
|
||||
|
||||
char *path_make_absolute(const char *p, const char *prefix) {
|
||||
char *r;
|
||||
|
||||
assert(p);
|
||||
|
||||
if (path_is_absolute(p) || !prefix)
|
||||
return strdup(p);
|
||||
|
||||
if (asprintf(&r, "%s/%s", prefix, p) < 0)
|
||||
return NULL;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
4
util.h
4
util.h
@ -94,5 +94,9 @@ char *strappend(const char *s, const char *suffix);
|
||||
int readlink_malloc(const char *p, char **r);
|
||||
|
||||
char *file_name_from_path(const char *p);
|
||||
bool is_path(const char *p);
|
||||
|
||||
bool path_is_absolute(const char *p);
|
||||
char *path_make_absolute(const char *p, const char *prefix);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user