chiark / gitweb /
path_lookup: moved _cleanup_lookup_paths_free_ from install.c to path-lookup.h
[elogind.git] / src / shared / install.c
index b368b9f9ab1eae2fa952b458669b500f633ab2d1..987b36d40b4eba187dc2e11d435d10be3344b1c9 100644 (file)
@@ -44,10 +44,7 @@ typedef struct {
         Hashmap *have_installed;
 } InstallContext;
 
-#define _cleanup_lookup_paths_free_ \
-        __attribute__((cleanup(lookup_paths_free)))
-#define _cleanup_install_context_done_ \
-        __attribute__((cleanup(install_context_done)))
+#define _cleanup_install_context_done_ _cleanup_(install_context_done)
 
 static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
         assert(paths);
@@ -178,11 +175,9 @@ static int mark_symlink_for_removal(
 
         path_kill_slashes(n);
 
-        r = set_put(*remove_symlinks_to, n);
-        if (r < 0) {
-                free(n);
+        r = set_consume(*remove_symlinks_to, n);
+        if (r < 0)
                 return r == -EEXIST ? 0 : r;
-        }
 
         return 0;
 }
@@ -198,7 +193,7 @@ static int remove_marked_symlinks_fd(
                 char** files) {
 
         int r = 0;
-        DIR _cleanup_closedir_ *d = NULL;
+        _cleanup_closedir_ DIR *d = NULL;
 
         assert(remove_symlinks_to);
         assert(fd >= 0);
@@ -235,7 +230,7 @@ static int remove_marked_symlinks_fd(
 
                 if (de->d_type == DT_DIR) {
                         int nfd, q;
-                        char _cleanup_free_ *p = NULL;
+                        _cleanup_free_ char *p = NULL;
 
                         nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
                         if (nfd < 0) {
@@ -260,7 +255,7 @@ static int remove_marked_symlinks_fd(
                                 r = q;
 
                 } else if (de->d_type == DT_LNK) {
-                        char _cleanup_free_ *p = NULL, *dest = NULL;
+                        _cleanup_free_ char *p = NULL, *dest = NULL;
                         int q;
                         bool found;
 
@@ -362,7 +357,7 @@ static int find_symlinks_fd(
                 bool *same_name_link) {
 
         int r = 0;
-        DIR _cleanup_closedir_ *d = NULL;
+        _cleanup_closedir_ DIR *d = NULL;
 
         assert(name);
         assert(fd >= 0);
@@ -395,7 +390,7 @@ static int find_symlinks_fd(
 
                 if (de->d_type == DT_DIR) {
                         int nfd, q;
-                        char _cleanup_free_ *p = NULL;
+                        _cleanup_free_ char *p = NULL;
 
                         nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
                         if (nfd < 0) {
@@ -423,7 +418,7 @@ static int find_symlinks_fd(
                                 r = q;
 
                 } else if (de->d_type == DT_LNK) {
-                        char _cleanup_free_ *p = NULL, *dest = NULL;
+                        _cleanup_free_ char *p = NULL, *dest = NULL;
                         bool found_path, found_dest, b = false;
                         int q;
 
@@ -458,7 +453,7 @@ static int find_symlinks_fd(
                                 found_dest = streq(path_get_file_name(dest), name);
 
                         if (found_path && found_dest) {
-                                char _cleanup_free_ *t = NULL;
+                                _cleanup_free_ char *t = NULL;
 
                                 /* Filter out same name links in the main
                                  * config path */
@@ -508,7 +503,7 @@ static int find_symlinks_in_scope(
                 UnitFileState *state) {
 
         int r;
-        char _cleanup_free_ *path = NULL;
+        _cleanup_free_ char *path2 = NULL;
         bool same_name_link_runtime = false, same_name_link = false;
 
         assert(scope >= 0);
@@ -516,6 +511,7 @@ static int find_symlinks_in_scope(
         assert(name);
 
         if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
+                _cleanup_free_ char *path = NULL;
 
                 /* First look in runtime config path */
                 r = get_config_path(scope, true, root_dir, &path);
@@ -532,11 +528,11 @@ static int find_symlinks_in_scope(
         }
 
         /* Then look in the normal config path */
-        r = get_config_path(scope, false, root_dir, &path);
+        r = get_config_path(scope, false, root_dir, &path2);
         if (r < 0)
                 return r;
 
-        r = find_symlinks(name, path, &same_name_link);
+        r = find_symlinks(name, path2, &same_name_link);
         if (r < 0)
                 return r;
         else if (r > 0) {
@@ -567,7 +563,7 @@ int unit_file_mask(
                 unsigned *n_changes) {
 
         char **i;
-        char _cleanup_free_ *prefix;
+        _cleanup_free_ char *prefix;
         int r;
 
         assert(scope >= 0);
@@ -578,7 +574,7 @@ int unit_file_mask(
                 return r;
 
         STRV_FOREACH(i, files) {
-                char _cleanup_free_ *path = NULL;
+                _cleanup_free_ char *path = NULL;
 
                 if (!unit_name_is_valid(*i, true)) {
                         if (r == 0)
@@ -700,9 +696,9 @@ int unit_file_link(
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
-        LookupPaths _cleanup_lookup_paths_free_ paths = {};
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
         char **i;
-        char _cleanup_free_ *config_path = NULL;
+        _cleanup_free_ char *config_path = NULL;
         int r, q;
 
         assert(scope >= 0);
@@ -717,7 +713,7 @@ int unit_file_link(
                 return r;
 
         STRV_FOREACH(i, files) {
-                char _cleanup_free_ *path = NULL;
+                _cleanup_free_ char *path = NULL;
                 char *fn;
                 struct stat st;
 
@@ -758,7 +754,7 @@ int unit_file_link(
                 }
 
                 if (errno == EEXIST) {
-                        char _cleanup_free_ *dest = NULL;
+                        _cleanup_free_ char *dest = NULL;
 
                         q = readlink_and_make_absolute(path, &dest);
 
@@ -921,15 +917,15 @@ static int install_info_add_auto(
                 return install_info_add(c, name_or_path, NULL);
 }
 
-static int config_parse_also(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                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,
+                             const char *lvalue,
+                             int ltype,
+                             const char *rvalue,
+                             void *data,
+                             void *userdata) {
 
         char *w;
         size_t l;
@@ -941,7 +937,7 @@ static int config_parse_also(
         assert(rvalue);
 
         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                char _cleanup_free_ *n;
+                _cleanup_free_ char *n;
                 int r;
 
                 n = strndup(w, l);
@@ -956,26 +952,27 @@ static int config_parse_also(
         return 0;
 }
 
-static int config_parse_user(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                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,
+                             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);
 
-        printed = install_full_printf(i, rvalue);
-        if (!printed)
-                return -ENOMEM;
+        r = install_full_printf(i, rvalue, &printed);
+        if (r < 0)
+                return r;
 
         free(i->user);
         i->user = printed;
@@ -999,7 +996,7 @@ static int unit_file_load(
         };
 
         int fd;
-        FILE _cleanup_fclose_ *f = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
         int r;
 
         assert(c);
@@ -1016,7 +1013,8 @@ static int unit_file_load(
                 return -ENOMEM;
         }
 
-        r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
+        r = config_parse(NULL, path, f, NULL,
+                         config_item_table_lookup, (void*) items, true, true, info);
         if (r < 0)
                 return r;
 
@@ -1062,8 +1060,8 @@ static int unit_file_search(
                         info->path = path;
                 else {
                         if (r == -ENOENT && unit_name_is_instance(info->name)) {
-                                /* unit file doesn't exist, however instance enablement was request */
-                                /* we will check if it is possible to load template unit file */
+                                /* Unit file doesn't exist, however instance enablement was requested.
+                                 * We will check if it is possible to load template unit file. */
                                 char *template = NULL,
                                      *template_path = NULL,
                                      *template_dir = NULL;
@@ -1074,7 +1072,7 @@ static int unit_file_search(
                                         return -ENOMEM;
                                 }
 
-                                /* we will reuse path variable since we don't need it anymore */
+                                /* We will reuse path variable since we don't need it anymore. */
                                 template_dir = path;
                                 *(strrchr(path, '/') + 1) = '\0';
 
@@ -1085,7 +1083,7 @@ static int unit_file_search(
                                         return -ENOMEM;
                                 }
 
-                                /* let's try to load template unit */
+                                /* Let's try to load template unit. */
                                 r = unit_file_load(c, info, template_path, allow_symlink);
                                 if (r >= 0) {
                                         info->path = strdup(template_path);
@@ -1116,7 +1114,7 @@ static int unit_file_can_install(
                 const char *name,
                 bool allow_symlink) {
 
-        InstallContext _cleanup_install_context_done_ c = {};
+        _cleanup_install_context_done_ InstallContext c = {};
         InstallInfo *i;
         int r;
 
@@ -1147,7 +1145,7 @@ static int create_symlink(
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
-        char _cleanup_free_ *dest = NULL;
+        _cleanup_free_ char *dest = NULL;
         int r;
 
         assert(old_path);
@@ -1198,11 +1196,11 @@ static int install_info_symlink_alias(
         assert(config_path);
 
         STRV_FOREACH(s, i->aliases) {
-                char _cleanup_free_ *alias_path = NULL, *dst = NULL;
+                _cleanup_free_ char *alias_path = NULL, *dst = NULL;
 
-                dst = install_full_printf(i, *s);
-                if (!dst)
-                        return -ENOMEM;
+                q = install_full_printf(i, *s, &dst);
+                if (q < 0)
+                        return q;
 
                 alias_path = path_make_absolute(dst, config_path);
                 if (!alias_path)
@@ -1230,11 +1228,11 @@ static int install_info_symlink_wants(
         assert(config_path);
 
         STRV_FOREACH(s, i->wanted_by) {
-                char _cleanup_free_ *path = NULL, *dst = NULL;
+                _cleanup_free_ char *path = NULL, *dst = NULL;
 
-                dst = install_full_printf(i, *s);
-                if (!dst)
-                        return -ENOMEM;
+                q = install_full_printf(i, *s, &dst);
+                if (q < 0)
+                        return q;
 
                 if (!unit_name_is_valid(dst, true)) {
                         r = -EINVAL;
@@ -1267,11 +1265,11 @@ static int install_info_symlink_requires(
         assert(config_path);
 
         STRV_FOREACH(s, i->required_by) {
-                char _cleanup_free_ *path = NULL, *dst = NULL;
+                _cleanup_free_ char *path = NULL, *dst = NULL;
 
-                dst = install_full_printf(i, *s);
-                if (!dst)
-                        return -ENOMEM;
+                q = install_full_printf(i, *s, &dst);
+                if (q < 0)
+                        return q;
 
                 if (!unit_name_is_valid(dst, true)) {
                         r = -EINVAL;
@@ -1299,7 +1297,7 @@ static int install_info_symlink_link(
                 unsigned *n_changes) {
 
         int r;
-        char _cleanup_free_ *path = NULL;
+        _cleanup_free_ char *path = NULL;
 
         assert(i);
         assert(paths);
@@ -1414,7 +1412,9 @@ static int install_context_mark_for_removal(
                 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
 
                 q = unit_file_search(c, i, paths, root_dir, false);
-                if (q < 0) {
+                if (q == -ENOENT) {
+                        /* do nothing */
+                } else if (q < 0) {
                         if (r >= 0)
                                 r = q;
 
@@ -1423,16 +1423,30 @@ static int install_context_mark_for_removal(
                         r += q;
 
                 if (unit_name_is_instance(i->name)) {
-                        char *unit_file = NULL;
+                        char *unit_file;
+
+                        if (i->path) {
+                                unit_file = path_get_file_name(i->path);
+
+                                if (unit_name_is_instance(unit_file))
+                                        /* unit file named as instance exists, thus all symlinks
+                                         * pointing to it will be removed */
+                                        q = mark_symlink_for_removal(remove_symlinks_to, i->name);
+                                else
+                                        /* does not exist, thus we will mark for removal symlinks
+                                         * to template unit file */
+                                        q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
+                        } else {
+                                /* If i->path is not set, it means that we didn't actually find
+                                 * the unit file. But we can still remove symlinks to the
+                                 * nonexistent template. */
+                                unit_file = unit_name_template(i->name);
+                                if (!unit_file)
+                                        return log_oom();
 
-                        unit_file = path_get_file_name(i->path);
-
-                        if (unit_name_is_instance(unit_file))
-                                /* unit file named as instance exists, thus all symlinks pointing to it, will be removed */
-                                q = mark_symlink_for_removal(remove_symlinks_to, i->name);
-                        else
-                                /* does not exist, thus we will mark for removal symlinks to template unit file */
                                 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
+                                free(unit_file);
+                        }
                 } else
                         q = mark_symlink_for_removal(remove_symlinks_to, i->name);
 
@@ -1452,10 +1466,10 @@ int unit_file_enable(
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
-        LookupPaths _cleanup_lookup_paths_free_ paths = {};
-        InstallContext _cleanup_install_context_done_ c = {};
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
+        _cleanup_install_context_done_ InstallContext c = {};
         char **i;
-        char _cleanup_free_ *config_path = NULL;
+        _cleanup_free_ char *config_path = NULL;
         int r;
 
         assert(scope >= 0);
@@ -1491,11 +1505,11 @@ int unit_file_disable(
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
-        LookupPaths _cleanup_lookup_paths_free_ paths = {};
-        InstallContext _cleanup_install_context_done_ c = {};
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
+        _cleanup_install_context_done_ InstallContext c = {};
         char **i;
-        char _cleanup_free_ *config_path = NULL;
-        Set _cleanup_set_free_free_ *remove_symlinks_to = NULL;
+        _cleanup_free_ char *config_path = NULL;
+        _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
         int r, q;
 
         assert(scope >= 0);
@@ -1532,43 +1546,101 @@ int unit_file_reenable(
                 bool force,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
+        int r;
 
-        LookupPaths _cleanup_lookup_paths_free_ paths = {};
-        InstallContext _cleanup_install_context_done_ c = {};
-        char **i;
-        char _cleanup_free_ *config_path = NULL;
-        Set _cleanup_set_free_free_ *remove_symlinks_to = NULL;
-        int r, q;
+        r = unit_file_disable(scope, runtime, root_dir, files,
+                              changes, n_changes);
+        if (r < 0)
+                return r;
+
+        return unit_file_enable(scope, runtime, root_dir, files, force,
+                                changes, n_changes);
+}
+
+int unit_file_set_default(
+                UnitFileScope scope,
+                const char *root_dir,
+                char *file,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
+        _cleanup_install_context_done_ InstallContext c = {};
+        _cleanup_free_ char *config_path = NULL;
+        char *path;
+        int r;
+        InstallInfo *i = NULL;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
 
+        if (unit_name_to_type(file) != UNIT_TARGET)
+                return -EINVAL;
+
         r = lookup_paths_init_from_scope(&paths, scope);
         if (r < 0)
                 return r;
 
-        r = get_config_path(scope, runtime, root_dir, &config_path);
+        r = get_config_path(scope, false, root_dir, &config_path);
         if (r < 0)
                 return r;
 
-        STRV_FOREACH(i, files) {
-                r = mark_symlink_for_removal(&remove_symlinks_to, *i);
-                if (r < 0)
-                        return r;
+        r = install_info_add_auto(&c, file);
+        if (r < 0)
+                return r;
 
-                r = install_info_add_auto(&c, *i);
-                if (r < 0)
+        i = (InstallInfo*)hashmap_first(c.will_install);
+
+        r = unit_file_search(&c, i, &paths, root_dir, false);
+        if (r < 0)
+                return r;
+
+        path = strappenda(config_path, "/default.target");
+        r = create_symlink(i->path, path, true, changes, n_changes);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int unit_file_get_default(
+                UnitFileScope scope,
+                const char *root_dir,
+                char **name) {
+
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
+        char **p;
+        int r;
+
+        r = lookup_paths_init_from_scope(&paths, scope);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(p, paths.unit_path) {
+                _cleanup_free_ char *path = NULL, *tmp = NULL;
+
+                if (isempty(root_dir))
+                        path = strappend(*p, "/default.target");
+                else
+                        path = strjoin(root_dir, "/", *p, "/default.target", NULL);
+
+                if (!path)
+                        return -ENOMEM;
+
+                r = readlink_malloc(path, &tmp);
+                if (r == -ENOENT)
+                        continue;
+                else if (r < 0)
                         return r;
-        }
 
-        r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
+                *name = strdup(path_get_file_name(tmp));
+                if (!*name)
+                        return -ENOMEM;
 
-        /* Returns number of symlinks that where supposed to be installed. */
-        q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
-        if (r == 0)
-                r = q;
+                return 0;
+        }
 
-        return r;
+        return -ENOENT;
 }
 
 UnitFileState unit_file_get_state(
@@ -1576,10 +1648,10 @@ UnitFileState unit_file_get_state(
                 const char *root_dir,
                 const char *name) {
 
-        LookupPaths _cleanup_lookup_paths_free_ paths = {};
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
         UnitFileState state = _UNIT_FILE_STATE_INVALID;
         char **i;
-        char _cleanup_free_ *path = NULL;
+        _cleanup_free_ char *path = NULL;
         int r;
 
         assert(scope >= 0);
@@ -1610,24 +1682,29 @@ UnitFileState unit_file_get_state(
                 if (!path)
                         return -ENOMEM;
 
+                /*
+                 * Search for a unit file in our default paths, to
+                 * be sure, that there are no broken symlinks.
+                 */
                 if (lstat(path, &st) < 0) {
                         r = -errno;
-                        if (errno == ENOENT)
-                                continue;
-
-                        return -errno;
-                }
+                        if (errno != ENOENT)
+                                return r;
 
-                if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
-                        return -ENOENT;
+                        if (!unit_name_is_instance(name))
+                                continue;
+                } else {
+                        if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
+                                return -ENOENT;
 
-                r = null_or_empty_path(path);
-                if (r < 0 && r != -ENOENT)
-                        return r;
-                else if (r > 0) {
-                        state = path_startswith(*i, "/run") ?
-                                UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
-                        return state;
+                        r = null_or_empty_path(path);
+                        if (r < 0 && r != -ENOENT)
+                                return r;
+                        else if (r > 0) {
+                                state = path_startswith(*i, "/run") ?
+                                        UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
+                                return state;
+                        }
                 }
 
                 r = find_symlinks_in_scope(scope, root_dir, name, &state);
@@ -1649,7 +1726,7 @@ UnitFileState unit_file_get_state(
 }
 
 int unit_file_query_preset(UnitFileScope scope, const char *name) {
-        char _cleanup_strv_free_ **files = NULL;
+        _cleanup_strv_free_ char **files = NULL;
         char **i;
         int r;
 
@@ -1679,7 +1756,7 @@ int unit_file_query_preset(UnitFileScope scope, const char *name) {
                 return r;
 
         STRV_FOREACH(i, files) {
-                FILE _cleanup_fclose_ *f;
+                _cleanup_fclose_ FILE *f;
 
                 f = fopen(*i, "re");
                 if (!f) {
@@ -1699,7 +1776,7 @@ int unit_file_query_preset(UnitFileScope scope, const char *name) {
                         if (!*l)
                                 continue;
 
-                        if (strchr(COMMENTS, *l))
+                        if (strchr(COMMENTS "\n", *l))
                                 continue;
 
                         if (first_word(l, "enable")) {
@@ -1734,11 +1811,11 @@ int unit_file_preset(
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
-        LookupPaths _cleanup_lookup_paths_free_ paths = {};
-        InstallContext _cleanup_install_context_done_ plus = {}, minus = {NULL};
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
+        _cleanup_install_context_done_ InstallContext plus = {}, minus = {};
         char **i;
-        char _cleanup_free_ *config_path = NULL;
-        Set _cleanup_set_free_free_ *remove_symlinks_to = NULL;
+        _cleanup_free_ char *config_path = NULL;
+        _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
         int r, q;
 
         assert(scope >= 0);
@@ -1794,16 +1871,17 @@ static void unitfilelist_free(UnitFileList **f) {
         free((*f)->path);
         free(*f);
 }
+#define _cleanup_unitfilelist_free_ _cleanup_(unitfilelist_free)
 
 int unit_file_get_list(
                 UnitFileScope scope,
                 const char *root_dir,
                 Hashmap *h) {
 
-        LookupPaths _cleanup_lookup_paths_free_ paths = {};
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
         char **i;
-        char _cleanup_free_ *buf = NULL;
-        DIR _cleanup_closedir_ *d = NULL;
+        _cleanup_free_ char *buf = NULL;
+        _cleanup_closedir_ DIR *d = NULL;
         int r;
 
         assert(scope >= 0);
@@ -1845,8 +1923,7 @@ int unit_file_get_list(
                 for (;;) {
                         struct dirent *de;
                         union dirent_storage buffer;
-                        UnitFileList __attribute__((cleanup(unitfilelist_free)))
-                                *f = NULL;
+                        _cleanup_unitfilelist_free_ UnitFileList *f = NULL;
 
                         r = readdir_r(d, &buffer.de, &de);
                         if (r != 0)