From 84e3543ef4c4758621f8a304b14642072303ef82 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 15 Jun 2010 14:45:15 +0200 Subject: [PATCH] manager: split off path lookup logic into own .c file --- Makefile.am | 1 + src/load-dropin.c | 2 +- src/load-fragment.c | 2 +- src/manager.c | 244 +--------------------------------------- src/manager.h | 5 +- src/path-lookup.c | 269 ++++++++++++++++++++++++++++++++++++++++++++ src/path-lookup.h | 36 ++++++ src/service.c | 6 +- 8 files changed, 318 insertions(+), 247 deletions(-) create mode 100644 src/path-lookup.c create mode 100644 src/path-lookup.h diff --git a/Makefile.am b/Makefile.am index 03591bed..20fd06f8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -199,6 +199,7 @@ COMMON_SOURCES = \ src/unit.c \ src/job.c \ src/manager.c \ + src/path-lookup.c \ src/load-fragment.c \ src/service.c \ src/automount.c \ diff --git a/src/load-dropin.c b/src/load-dropin.c index 2101e330..bdf3dd2c 100644 --- a/src/load-dropin.c +++ b/src/load-dropin.c @@ -79,7 +79,7 @@ int unit_load_dropin(Unit *u) { char *path; char **p; - STRV_FOREACH(p, u->meta.manager->unit_path) { + STRV_FOREACH(p, u->meta.manager->lookup_paths.unit_path) { if (asprintf(&path, "%s/%s.wants", *p, t) < 0) return -ENOMEM; diff --git a/src/load-fragment.c b/src/load-fragment.c index b679fab4..79b0893a 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -1523,7 +1523,7 @@ static int load_from_path(Unit *u, const char *path) { } else { char **p; - STRV_FOREACH(p, u->meta.manager->unit_path) { + STRV_FOREACH(p, u->meta.manager->lookup_paths.unit_path) { /* Instead of opening the path right away, we manually * follow all symlinks and add their name to our unit diff --git a/src/manager.c b/src/manager.c index b4b963a6..4dcdf2e5 100644 --- a/src/manager.c +++ b/src/manager.c @@ -52,6 +52,7 @@ #include "dbus-unit.h" #include "dbus-job.h" #include "missing.h" +#include "path-lookup.h" /* As soon as 16 units are in our GC queue, make sure to run a gc sweep */ #define GC_QUEUE_ENTRIES_MAX 16 @@ -122,240 +123,6 @@ static int manager_setup_signals(Manager *m) { return 0; } -static char** session_dirs(void) { - const char *home, *e; - char *config_home = NULL, *data_home = NULL; - char **config_dirs = NULL, **data_dirs = NULL; - char **r = NULL, **t; - - /* Implement the mechanisms defined in - * - * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html - * - * We look in both the config and the data dirs because we - * want to encourage that distributors ship their unit files - * as data, and allow overriding as configuration. - */ - - home = getenv("HOME"); - - if ((e = getenv("XDG_CONFIG_HOME"))) { - if (asprintf(&config_home, "%s/systemd/session", e) < 0) - goto fail; - - } else if (home) { - if (asprintf(&config_home, "%s/.config/systemd/session", home) < 0) - goto fail; - } - - if ((e = getenv("XDG_CONFIG_DIRS"))) - if (!(config_dirs = strv_split(e, ":"))) - goto fail; - - /* We don't treat /etc/xdg/systemd here as the spec - * suggests because we assume that that is a link to - * /etc/systemd/ anyway. */ - - if ((e = getenv("XDG_DATA_HOME"))) { - if (asprintf(&data_home, "%s/systemd/session", e) < 0) - goto fail; - - } else if (home) { - if (asprintf(&data_home, "%s/.local/share/systemd/session", home) < 0) - goto fail; - - /* There is really no need for two unit dirs in $HOME, - * except to be fully compliant with the XDG spec. We - * now try to link the two dirs, so that we can - * minimize disk seeks a little. Further down we'll - * then filter out this link, if it is actually is - * one. */ - - mkdir_parents(data_home, 0777); - symlink("../../../.config/systemd/session", data_home); - } - - if ((e = getenv("XDG_DATA_DIRS"))) - data_dirs = strv_split(e, ":"); - else - data_dirs = strv_new("/usr/local/share", "/usr/share", NULL); - - if (!data_dirs) - goto fail; - - /* Now merge everything we found. */ - if (config_home) { - if (!(t = strv_append(r, config_home))) - goto fail; - strv_free(r); - r = t; - } - - if (!(t = strv_merge_concat(r, config_dirs, "/systemd/session"))) - goto finish; - strv_free(r); - r = t; - - if (!(t = strv_append(r, SESSION_CONFIG_UNIT_PATH))) - goto fail; - strv_free(r); - r = t; - - if (data_home) { - if (!(t = strv_append(r, data_home))) - goto fail; - strv_free(r); - r = t; - } - - if (!(t = strv_merge_concat(r, data_dirs, "/systemd/session"))) - goto fail; - strv_free(r); - r = t; - - if (!(t = strv_append(r, SESSION_DATA_UNIT_PATH))) - goto fail; - strv_free(r); - r = t; - - if (!strv_path_make_absolute_cwd(r)) - goto fail; - -finish: - free(config_home); - strv_free(config_dirs); - free(data_home); - strv_free(data_dirs); - - return r; - -fail: - strv_free(r); - r = NULL; - goto finish; -} - -static int manager_find_paths(Manager *m) { - const char *e; - char *t; - - assert(m); - - /* Unset previous data, in case we are called on reload */ - strv_free(m->unit_path); - strv_free(m->sysvinit_path); - strv_free(m->sysvrcnd_path); - m->unit_path = m->sysvinit_path = m->sysvrcnd_path = NULL; - - /* First priority is whatever has been passed to us via env - * vars */ - if ((e = getenv("SYSTEMD_UNIT_PATH"))) - if (!(m->unit_path = split_path_and_make_absolute(e))) - return -ENOMEM; - - if (strv_isempty(m->unit_path)) { - - /* Nothing is set, so let's figure something out. */ - strv_free(m->unit_path); - - if (m->running_as == MANAGER_SESSION) { - if (!(m->unit_path = session_dirs())) - return -ENOMEM; - } else - if (!(m->unit_path = strv_new( - SYSTEM_CONFIG_UNIT_PATH, /* /etc/systemd/system/ */ - SYSTEM_DATA_UNIT_PATH, /* /lib/systemd/system/ */ - NULL))) - return -ENOMEM; - } - - if (m->running_as == MANAGER_INIT) { - /* /etc/init.d/ compatibility does not matter to users */ - - if ((e = getenv("SYSTEMD_SYSVINIT_PATH"))) - if (!(m->sysvinit_path = split_path_and_make_absolute(e))) - return -ENOMEM; - - if (strv_isempty(m->sysvinit_path)) { - strv_free(m->sysvinit_path); - - if (!(m->sysvinit_path = strv_new( - SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */ - NULL))) - return -ENOMEM; - } - - if ((e = getenv("SYSTEMD_SYSVRCND_PATH"))) - if (!(m->sysvrcnd_path = split_path_and_make_absolute(e))) - return -ENOMEM; - - if (strv_isempty(m->sysvrcnd_path)) { - strv_free(m->sysvrcnd_path); - - if (!(m->sysvrcnd_path = strv_new( - SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */ - NULL))) - return -ENOMEM; - } - } - - if (m->unit_path) - if (!strv_path_canonicalize(m->unit_path)) - return -ENOMEM; - - if (m->sysvinit_path) - if (!strv_path_canonicalize(m->sysvinit_path)) - return -ENOMEM; - - if (m->sysvrcnd_path) - if (!strv_path_canonicalize(m->sysvrcnd_path)) - return -ENOMEM; - - strv_uniq(m->unit_path); - strv_uniq(m->sysvinit_path); - strv_uniq(m->sysvrcnd_path); - - if (!strv_isempty(m->unit_path)) { - - if (!(t = strv_join(m->unit_path, "\n\t"))) - return -ENOMEM; - log_debug("Looking for unit files in:\n\t%s", t); - free(t); - } else { - log_debug("Ignoring unit files."); - strv_free(m->unit_path); - m->unit_path = NULL; - } - - if (!strv_isempty(m->sysvinit_path)) { - - if (!(t = strv_join(m->sysvinit_path, "\n\t"))) - return -ENOMEM; - - log_debug("Looking for SysV init scripts in:\n\t%s", t); - free(t); - } else { - log_debug("Ignoring SysV init scripts."); - strv_free(m->sysvinit_path); - m->sysvinit_path = NULL; - } - - if (!strv_isempty(m->sysvrcnd_path)) { - - if (!(t = strv_join(m->sysvrcnd_path, "\n\t"))) - return -ENOMEM; - - log_debug("Looking for SysV rcN.d links in:\n\t%s", t); - free(t); - } else { - log_debug("Ignoring SysV rcN.d links."); - strv_free(m->sysvrcnd_path); - m->sysvrcnd_path = NULL; - } - - return 0; -} - int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **_m) { Manager *m; int r = -ENOMEM; @@ -401,7 +168,7 @@ int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **_m) { if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) goto fail; - if ((r = manager_find_paths(m)) < 0) + if ((r = lookup_paths_init(&m->lookup_paths, m->running_as)) < 0) goto fail; if ((r = manager_setup_signals(m)) < 0) @@ -598,9 +365,7 @@ void manager_free(Manager *m) { if (m->signal_watch.fd >= 0) close_nointr_nofail(m->signal_watch.fd); - strv_free(m->unit_path); - strv_free(m->sysvinit_path); - strv_free(m->sysvrcnd_path); + lookup_paths_free(&m->lookup_paths); strv_free(m->environment); free(m->cgroup_controller); @@ -2353,7 +2118,8 @@ int manager_reload(Manager *m) { manager_clear_jobs_and_units(m); /* Find new unit paths */ - if ((q = manager_find_paths(m)) < 0) + lookup_paths_free(&m->lookup_paths); + if ((q = lookup_paths_init(&m->lookup_paths, m->running_as)) < 0) r = q; /* First, enumerate what we can from all config files */ diff --git a/src/manager.h b/src/manager.h index a2084e92..d78bcf5d 100644 --- a/src/manager.h +++ b/src/manager.h @@ -82,6 +82,7 @@ struct Watch { #include "list.h" #include "set.h" #include "dbus.h" +#include "path-lookup.h" #define SPECIAL_DEFAULT_TARGET "default.target" @@ -176,9 +177,7 @@ struct Manager { unsigned n_snapshots; - char **unit_path; - char **sysvinit_path; - char **sysvrcnd_path; + LookupPaths lookup_paths; char **environment; diff --git a/src/path-lookup.c b/src/path-lookup.c new file mode 100644 index 00000000..1c4b5dc4 --- /dev/null +++ b/src/path-lookup.c @@ -0,0 +1,269 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "strv.h" + +#include "path-lookup.h" + +static char** session_dirs(void) { + const char *home, *e; + char *config_home = NULL, *data_home = NULL; + char **config_dirs = NULL, **data_dirs = NULL; + char **r = NULL, **t; + + /* Implement the mechanisms defined in + * + * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html + * + * We look in both the config and the data dirs because we + * want to encourage that distributors ship their unit files + * as data, and allow overriding as configuration. + */ + + home = getenv("HOME"); + + if ((e = getenv("XDG_CONFIG_HOME"))) { + if (asprintf(&config_home, "%s/systemd/session", e) < 0) + goto fail; + + } else if (home) { + if (asprintf(&config_home, "%s/.config/systemd/session", home) < 0) + goto fail; + } + + if ((e = getenv("XDG_CONFIG_DIRS"))) + if (!(config_dirs = strv_split(e, ":"))) + goto fail; + + /* We don't treat /etc/xdg/systemd here as the spec + * suggests because we assume that that is a link to + * /etc/systemd/ anyway. */ + + if ((e = getenv("XDG_DATA_HOME"))) { + if (asprintf(&data_home, "%s/systemd/session", e) < 0) + goto fail; + + } else if (home) { + if (asprintf(&data_home, "%s/.local/share/systemd/session", home) < 0) + goto fail; + + /* There is really no need for two unit dirs in $HOME, + * except to be fully compliant with the XDG spec. We + * now try to link the two dirs, so that we can + * minimize disk seeks a little. Further down we'll + * then filter out this link, if it is actually is + * one. */ + + mkdir_parents(data_home, 0777); + symlink("../../../.config/systemd/session", data_home); + } + + if ((e = getenv("XDG_DATA_DIRS"))) + data_dirs = strv_split(e, ":"); + else + data_dirs = strv_new("/usr/local/share", "/usr/share", NULL); + + if (!data_dirs) + goto fail; + + /* Now merge everything we found. */ + if (config_home) { + if (!(t = strv_append(r, config_home))) + goto fail; + strv_free(r); + r = t; + } + + if (!(t = strv_merge_concat(r, config_dirs, "/systemd/session"))) + goto finish; + strv_free(r); + r = t; + + if (!(t = strv_append(r, SESSION_CONFIG_UNIT_PATH))) + goto fail; + strv_free(r); + r = t; + + if (data_home) { + if (!(t = strv_append(r, data_home))) + goto fail; + strv_free(r); + r = t; + } + + if (!(t = strv_merge_concat(r, data_dirs, "/systemd/session"))) + goto fail; + strv_free(r); + r = t; + + if (!(t = strv_append(r, SESSION_DATA_UNIT_PATH))) + goto fail; + strv_free(r); + r = t; + + if (!strv_path_make_absolute_cwd(r)) + goto fail; + +finish: + free(config_home); + strv_free(config_dirs); + free(data_home); + strv_free(data_dirs); + + return r; + +fail: + strv_free(r); + r = NULL; + goto finish; +} + +int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as) { + const char *e; + char *t; + + assert(p); + + /* First priority is whatever has been passed to us via env + * vars */ + if ((e = getenv("SYSTEMD_UNIT_PATH"))) + if (!(p->unit_path = split_path_and_make_absolute(e))) + return -ENOMEM; + + if (strv_isempty(p->unit_path)) { + + /* Nothing is set, so let's figure something out. */ + strv_free(p->unit_path); + + if (running_as == MANAGER_SESSION) { + if (!(p->unit_path = session_dirs())) + return -ENOMEM; + } else + if (!(p->unit_path = strv_new( + SYSTEM_CONFIG_UNIT_PATH, /* /etc/systemd/system/ */ + SYSTEM_DATA_UNIT_PATH, /* /lib/systemd/system/ */ + NULL))) + return -ENOMEM; + } + + if (running_as == MANAGER_INIT) { + /* /etc/init.d/ compatibility does not matter to users */ + + if ((e = getenv("SYSTEMD_SYSVINIT_PATH"))) + if (!(p->sysvinit_path = split_path_and_make_absolute(e))) + return -ENOMEM; + + if (strv_isempty(p->sysvinit_path)) { + strv_free(p->sysvinit_path); + + if (!(p->sysvinit_path = strv_new( + SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */ + NULL))) + return -ENOMEM; + } + + if ((e = getenv("SYSTEMD_SYSVRCND_PATH"))) + if (!(p->sysvrcnd_path = split_path_and_make_absolute(e))) + return -ENOMEM; + + if (strv_isempty(p->sysvrcnd_path)) { + strv_free(p->sysvrcnd_path); + + if (!(p->sysvrcnd_path = strv_new( + SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */ + NULL))) + return -ENOMEM; + } + } + + if (p->unit_path) + if (!strv_path_canonicalize(p->unit_path)) + return -ENOMEM; + + if (p->sysvinit_path) + if (!strv_path_canonicalize(p->sysvinit_path)) + return -ENOMEM; + + if (p->sysvrcnd_path) + if (!strv_path_canonicalize(p->sysvrcnd_path)) + return -ENOMEM; + + strv_uniq(p->unit_path); + strv_uniq(p->sysvinit_path); + strv_uniq(p->sysvrcnd_path); + + if (!strv_isempty(p->unit_path)) { + + if (!(t = strv_join(p->unit_path, "\n\t"))) + return -ENOMEM; + log_debug("Looking for unit files in:\n\t%s", t); + free(t); + } else { + log_debug("Ignoring unit files."); + strv_free(p->unit_path); + p->unit_path = NULL; + } + + if (!strv_isempty(p->sysvinit_path)) { + + if (!(t = strv_join(p->sysvinit_path, "\n\t"))) + return -ENOMEM; + + log_debug("Looking for SysV init scripts in:\n\t%s", t); + free(t); + } else { + log_debug("Ignoring SysV init scripts."); + strv_free(p->sysvinit_path); + p->sysvinit_path = NULL; + } + + if (!strv_isempty(p->sysvrcnd_path)) { + + if (!(t = strv_join(p->sysvrcnd_path, "\n\t"))) + return -ENOMEM; + + log_debug("Looking for SysV rcN.d links in:\n\t%s", t); + free(t); + } else { + log_debug("Ignoring SysV rcN.d links."); + strv_free(p->sysvrcnd_path); + p->sysvrcnd_path = NULL; + } + + return 0; +} + +void lookup_paths_free(LookupPaths *p) { + assert(p); + + strv_free(p->unit_path); + strv_free(p->sysvinit_path); + strv_free(p->sysvrcnd_path); + + p->unit_path = p->sysvinit_path = p->sysvrcnd_path = NULL; +} diff --git a/src/path-lookup.h b/src/path-lookup.h new file mode 100644 index 00000000..a04d5a0f --- /dev/null +++ b/src/path-lookup.h @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foopathlookuphfoo +#define foopathlookuphfoo + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +typedef struct LookupPaths { + char **unit_path; + char **sysvinit_path; + char **sysvrcnd_path; +} LookupPaths; + +#include "manager.h" + +int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as); +void lookup_paths_free(LookupPaths *p); + +#endif diff --git a/src/service.c b/src/service.c index e1975eb1..82a18a43 100644 --- a/src/service.c +++ b/src/service.c @@ -675,7 +675,7 @@ static int service_load_sysv_name(Service *s, const char *name) { endswith(name, ".sh.service")) return -ENOENT; - STRV_FOREACH(p, UNIT(s)->meta.manager->sysvinit_path) { + STRV_FOREACH(p, UNIT(s)->meta.manager->lookup_paths.sysvinit_path) { char *path; int r; @@ -726,7 +726,7 @@ static int service_load_sysv(Service *s) { /* Load service data from SysV init scripts, preferably with * LSB headers ... */ - if (strv_isempty(UNIT(s)->meta.manager->sysvinit_path)) + if (strv_isempty(UNIT(s)->meta.manager->lookup_paths.sysvinit_path)) return 0; if ((t = UNIT(s)->meta.id)) @@ -2201,7 +2201,7 @@ static int service_enumerate(Manager *m) { assert(m); - STRV_FOREACH(p, m->sysvrcnd_path) + STRV_FOREACH(p, m->lookup_paths.sysvrcnd_path) for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) { struct dirent *de; -- 2.39.5