chiark / gitweb /
conf-files: include root in returned file paths
[elogind.git] / src / shared / install.c
index a6a9f19e75b38b773dd8b7b25f614399665e8243..190c554347ac200f3d9462e82d94552e002fb5e5 100644 (file)
@@ -47,6 +47,19 @@ typedef struct {
 
 #define _cleanup_install_context_done_ _cleanup_(install_context_done)
 
+static int in_search_path(const char *path, char **search) {
+        _cleanup_free_ char *parent = NULL;
+        int r;
+
+        assert(path);
+
+        r = path_get_parent(path, &parent);
+        if (r < 0)
+                return r;
+
+        return strv_contains(search, parent);
+}
+
 static int lookup_paths_init_from_scope(LookupPaths *paths,
                                         UnitFileScope scope,
                                         const char *root_dir) {
@@ -147,12 +160,16 @@ static int add_file_change(
         if (!c[i].path)
                 return -ENOMEM;
 
+        path_kill_slashes(c[i].path);
+
         if (source) {
                 c[i].source = strdup(source);
                 if (!c[i].source) {
                         free(c[i].path);
                         return -ENOMEM;
                 }
+
+                path_kill_slashes(c[i].path);
         } else
                 c[i].source = NULL;
 
@@ -266,8 +283,22 @@ static int remove_marked_symlinks_fd(
 
                         if (unit_name_is_instance(de->d_name) &&
                             instance_whitelist &&
-                            !strv_contains(instance_whitelist, de->d_name))
-                                continue;
+                            !strv_contains(instance_whitelist, de->d_name)) {
+
+                                _cleanup_free_ char *w;
+
+                                /* OK, the file is not listed directly
+                                 * in the whitelist, so let's check if
+                                 * the template of it might be
+                                 * listed. */
+
+                                w = unit_name_template(de->d_name);
+                                if (!w)
+                                        return -ENOMEM;
+
+                                if (!strv_contains(instance_whitelist, w))
+                                        continue;
+                        }
 
                         p = path_make_absolute(de->d_name, path);
                         if (!p)
@@ -290,18 +321,14 @@ static int remove_marked_symlinks_fd(
                         if (!found)
                                 continue;
 
-
                         if (unlink(p) < 0 && errno != ENOENT) {
-
                                 if (r == 0)
                                         r = -errno;
                                 continue;
                         }
 
-                        rmdir_parents(p, config_path);
-
                         path_kill_slashes(p);
-
+                        rmdir_parents(p, config_path);
                         add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
 
                         if (!set_get(remove_symlinks_to, p)) {
@@ -603,13 +630,9 @@ int unit_file_mask(
                                 continue;
 
                         if (force) {
-                                unlink(path);
-
-                                if (symlink("/dev/null", path) >= 0) {
-
+                                if (symlink_atomic("/dev/null", path) >= 0) {
                                         add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
                                         add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
-
                                         continue;
                                 }
                         }
@@ -770,13 +793,9 @@ int unit_file_link(
                                 continue;
 
                         if (force) {
-                                unlink(path);
-
-                                if (symlink(*i, path) >= 0) {
-
+                                if (symlink_atomic(*i, path) >= 0) {
                                         add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
                                         add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
-
                                         continue;
                                 }
                         }
@@ -827,6 +846,7 @@ static void install_info_free(InstallInfo *i) {
         strv_free(i->aliases);
         strv_free(i->wanted_by);
         strv_free(i->required_by);
+        free(i->default_instance);
         free(i);
 }
 
@@ -919,16 +939,17 @@ static int install_info_add_auto(
                 return install_info_add(c, name_or_path, NULL);
 }
 
-static int config_parse_also(const char *unit,
-                             const char *filename,
-                             unsigned line,
-                             const char *section,
-                             unsigned section_line,
-                             const char *lvalue,
-                             int ltype,
-                             const char *rvalue,
-                             void *data,
-                             void *userdata) {
+static int config_parse_also(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
 
         char *w;
         size_t l;
@@ -955,19 +976,20 @@ static int config_parse_also(const char *unit,
         return 0;
 }
 
-static int config_parse_user(const char *unit,
-                             const char *filename,
-                             unsigned line,
-                             const char *section,
-                             unsigned section_line,
-                             const char *lvalue,
-                             int ltype,
-                             const char *rvalue,
-                             void *data,
-                             void *userdata) {
+static int config_parse_user(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
 
         InstallInfo *i = data;
-        charprinted;
+        char *printed;
         int r;
 
         assert(filename);
@@ -984,29 +1006,66 @@ static int config_parse_user(const char *unit,
         return 0;
 }
 
+static int config_parse_default_instance(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        InstallInfo *i = data;
+        char *printed;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        r = install_full_printf(i, rvalue, &printed);
+        if (r < 0)
+                return r;
+
+        if (!unit_instance_is_valid(printed))
+                return -EINVAL;
+
+        free(i->default_instance);
+        i->default_instance = printed;
+
+        return 0;
+}
+
 static int unit_file_load(
                 InstallContext *c,
                 InstallInfo *info,
                 const char *path,
+                const char *root_dir,
                 bool allow_symlink) {
 
         const ConfigTableItem items[] = {
-                { "Install", "Alias",      config_parse_strv, 0, &info->aliases     },
-                { "Install", "WantedBy",   config_parse_strv, 0, &info->wanted_by   },
-                { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
-                { "Install", "Also",       config_parse_also, 0, c                  },
-                { "Exec",    "User",       config_parse_user, 0, info               },
-                { NULL, NULL, NULL, 0, NULL }
+                { "Install", "Alias",           config_parse_strv,             0, &info->aliases           },
+                { "Install", "WantedBy",        config_parse_strv,             0, &info->wanted_by         },
+                { "Install", "RequiredBy",      config_parse_strv,             0, &info->required_by       },
+                { "Install", "DefaultInstance", config_parse_default_instance, 0, info                     },
+                { "Install", "Also",            config_parse_also,             0, c                        },
+                { "Exec",    "User",            config_parse_user,             0, info                     },
+                {}
         };
 
-        int fd;
         _cleanup_fclose_ FILE *f = NULL;
-        int r;
+        int fd, r;
 
         assert(c);
         assert(info);
         assert(path);
 
+        if (!isempty(root_dir))
+                path = strappenda3(root_dir, "/", path);
+
         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
         if (fd < 0)
                 return -errno;
@@ -1017,8 +1076,7 @@ static int unit_file_load(
                 return -ENOMEM;
         }
 
-        r = config_parse(NULL, path, f, NULL,
-                         config_item_table_lookup, (void*) items, true, true, info);
+        r = config_parse(NULL, path, f, NULL, config_item_table_lookup, (void*) items, true, true, info);
         if (r < 0)
                 return r;
 
@@ -1042,68 +1100,56 @@ static int unit_file_search(
         assert(info);
         assert(paths);
 
-        if (info->path) {
-                char *full_path = NULL;
-
-                if (!isempty(root_dir))
-                        full_path = strappenda(root_dir, info->path);
-
-                return unit_file_load(c, info, full_path ?: info->path, allow_symlink);
-        }
+        if (info->path)
+                return unit_file_load(c, info, info->path, root_dir, allow_symlink);
 
         assert(info->name);
 
         STRV_FOREACH(p, paths->unit_path) {
-                _cleanup_free_ char *path = NULL, *full_path = NULL;
+                _cleanup_free_ char *path = NULL;
 
                 path = strjoin(*p, "/", info->name, NULL);
                 if (!path)
                         return -ENOMEM;
 
-                if (!isempty(root_dir)) {
-                        full_path = strappend(root_dir, path);
-                        if (!full_path)
-                                return -ENOMEM;
-                }
-
-                r = unit_file_load(c, info, full_path ?: path, allow_symlink);
+                r = unit_file_load(c, info, path, root_dir, allow_symlink);
                 if (r >= 0) {
                         info->path = path;
                         path = NULL;
-                } else if (r == -ENOENT && unit_name_is_instance(info->name)) {
-                        /* Unit file doesn't exist, however instance enablement was requested.
-                         * We will check if it is possible to load template unit file. */
-                        _cleanup_free_ char *template = NULL, *template_dir = NULL;
+                        return r;
+                }
+                if (r != -ENOENT && r != -ELOOP)
+                        return r;
+        }
 
-                        template = unit_name_template(info->name);
-                        if (!template)
-                                return -ENOMEM;
+        if (unit_name_is_instance(info->name)) {
+
+                /* Unit file doesn't exist, however instance
+                 * enablement was requested.  We will check if it is
+                 * possible to load template unit file. */
 
-                        /* We will reuse path variable since we don't need it anymore. */
-                        template_dir = path;
-                        *(strrchr(template_dir, '/') + 1) = '\0';
+                _cleanup_free_ char *template = NULL;
 
-                        path = strappend(template_dir, template);
+                template = unit_name_template(info->name);
+                if (!template)
+                        return -ENOMEM;
+
+                STRV_FOREACH(p, paths->unit_path) {
+                        _cleanup_free_ char *path = NULL;
+
+                        path = strjoin(*p, "/", template, NULL);
                         if (!path)
                                 return -ENOMEM;
 
-                        if (!isempty(root_dir)) {
-                                free(full_path);
-                                full_path = strappend(root_dir, path);
-                                if (!full_path)
-                                        return -ENOMEM;
-                        }
-
-                        /* Let's try to load template unit. */
-                        r = unit_file_load(c, info, full_path ?: path, allow_symlink);
+                        r = unit_file_load(c, info, path, root_dir, allow_symlink);
                         if (r >= 0) {
                                 info->path = path;
                                 path = NULL;
+                                return r;
                         }
+                        if (r != -ENOENT && r != -ELOOP)
+                                return r;
                 }
-
-                if (r != -ENOENT && r != -ELOOP)
-                        return r;
         }
 
         return -ENOENT;
@@ -1172,17 +1218,14 @@ static int create_symlink(
         if (!force)
                 return -EEXIST;
 
-        r = unlink(new_path);
-        if (r < 0 && errno != ENOENT)
-                return -errno;
+        r = symlink_atomic(old_path, new_path);
+        if (r < 0)
+                return r;
 
-        if (symlink(old_path, new_path) >= 0) {
-                add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
-                add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
-                return 0;
-        }
+        add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
+        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
 
-        return -errno;
+        return 0;
 }
 
 static int install_info_symlink_alias(
@@ -1220,54 +1263,37 @@ static int install_info_symlink_alias(
 static int install_info_symlink_wants(
                 InstallInfo *i,
                 const char *config_path,
+                char **list,
+                const char *suffix,
                 bool force,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
+        _cleanup_free_ char *buf = NULL;
+        const char *n;
         char **s;
         int r = 0, q;
 
         assert(i);
         assert(config_path);
 
-        STRV_FOREACH(s, i->wanted_by) {
-                _cleanup_free_ char *path = NULL, *dst = NULL;
+        if (unit_name_is_template(i->name)) {
 
-                q = install_full_printf(i, *s, &dst);
-                if (q < 0)
-                        return q;
+                /* Don't install any symlink if there's no default
+                 * instance configured */
 
-                if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
-                        r = -EINVAL;
-                        continue;
-                }
+                if (!i->default_instance)
+                        return 0;
 
-                if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0)
+                buf = unit_name_replace_instance(i->name, i->default_instance);
+                if (!buf)
                         return -ENOMEM;
 
-                q = create_symlink(i->path, path, force, changes, n_changes);
-
-                if (r == 0)
-                        r = q;
-        }
-
-        return r;
-}
-
-static int install_info_symlink_requires(
-                InstallInfo *i,
-                const char *config_path,
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        char **s;
-        int r = 0, q;
-
-        assert(i);
-        assert(config_path);
+                n = buf;
+        } else
+                n = i->name;
 
-        STRV_FOREACH(s, i->required_by) {
+        STRV_FOREACH(s, list) {
                 _cleanup_free_ char *path = NULL, *dst = NULL;
 
                 q = install_full_printf(i, *s, &dst);
@@ -1279,11 +1305,11 @@ static int install_info_symlink_requires(
                         continue;
                 }
 
-                if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0)
+                path = strjoin(config_path, "/", dst, suffix, n, NULL);
+                if (!path)
                         return -ENOMEM;
 
                 q = create_symlink(i->path, path, force, changes, n_changes);
-
                 if (r == 0)
                         r = q;
         }
@@ -1295,6 +1321,7 @@ static int install_info_symlink_link(
                 InstallInfo *i,
                 LookupPaths *paths,
                 const char *config_path,
+                const char *root_dir,
                 bool force,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
@@ -1322,6 +1349,7 @@ static int install_info_apply(
                 InstallInfo *i,
                 LookupPaths *paths,
                 const char *config_path,
+                const char *root_dir,
                 bool force,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
@@ -1334,15 +1362,15 @@ static int install_info_apply(
 
         r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
 
-        q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
+        q = install_info_symlink_wants(i, config_path, i->wanted_by, ".wants/", force, changes, n_changes);
         if (r == 0)
                 r = q;
 
-        q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
+        q = install_info_symlink_wants(i, config_path, i->required_by, ".requires/", force, changes, n_changes);
         if (r == 0)
                 r = q;
 
-        q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
+        q = install_info_symlink_link(i, paths, config_path, root_dir, force, changes, n_changes);
         if (r == 0)
                 r = q;
 
@@ -1382,7 +1410,7 @@ static int install_context_apply(
                 } else if (r >= 0)
                         r += q;
 
-                q = install_info_apply(i, paths, config_path, force, changes, n_changes);
+                q = install_info_apply(i, paths, config_path, root_dir, force, changes, n_changes);
                 if (r >= 0 && q < 0)
                         r = q;
         }
@@ -1748,7 +1776,7 @@ UnitFileState unit_file_get_state(
 
 int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
         _cleanup_strv_free_ char **files = NULL;
-        char **i;
+        char **p;
         int r;
 
         assert(scope >= 0);
@@ -1776,17 +1804,10 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
         if (r < 0)
                 return r;
 
-        STRV_FOREACH(i, files) {
-                _cleanup_free_ char *buf = NULL;
+        STRV_FOREACH(p, files) {
                 _cleanup_fclose_ FILE *f;
-                const char *p;
-
-                if (root_dir)
-                        p = buf = strjoin(root_dir, "/", *i, NULL);
-                else
-                        p = *i;
 
-                f = fopen(p, "re");
+                f = fopen(*p, "re");
                 if (!f) {
                         if (errno == ENOENT)
                                 continue;