]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/delta/delta.c
build-sys: use #if Y instead of #ifdef Y everywhere
[thirdparty/systemd.git] / src / delta / delta.c
index 6c25b185ed88d63713fce492122a082ec6eaf131..605bea57bbe6dbc524e5e3f5feefe4aecc37448d 100644 (file)
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
 /***
   This file is part of systemd.
 
@@ -51,7 +49,7 @@ static const char prefixes[] =
         "/usr/local/share\0"
         "/usr/lib\0"
         "/usr/share\0"
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
         "/lib\0"
 #endif
         ;
@@ -87,24 +85,17 @@ static enum {
         (SHOW_MASKED | SHOW_EQUIVALENT | SHOW_REDIRECTED | SHOW_OVERRIDDEN | SHOW_EXTENDED)
 } arg_flags = 0;
 
-static void pager_open_if_enabled(void) {
-
-        if (arg_no_pager)
-                return;
-
-        pager_open(false);
-}
-
 static int equivalent(const char *a, const char *b) {
         _cleanup_free_ char *x = NULL, *y = NULL;
+        int r;
 
-        x = canonicalize_file_name(a);
-        if (!x)
-                return -errno;
+        r = chase_symlinks(a, NULL, 0, &x);
+        if (r < 0)
+                return r;
 
-        y = canonicalize_file_name(b);
-        if (!y)
-                return -errno;
+        r = chase_symlinks(b, NULL, 0, &y);
+        if (r < 0)
+                return r;
 
         return path_equal(x, y);
 }
@@ -115,7 +106,7 @@ static int notify_override_masked(const char *top, const char *bottom) {
 
         printf("%s%s%s     %s %s %s\n",
                ansi_highlight_red(), "[MASKED]", ansi_normal(),
-               top, draw_special_char(DRAW_ARROW), bottom);
+               top, special_glyph(ARROW), bottom);
         return 1;
 }
 
@@ -125,7 +116,7 @@ static int notify_override_equivalent(const char *top, const char *bottom) {
 
         printf("%s%s%s %s %s %s\n",
                ansi_highlight_green(), "[EQUIVALENT]", ansi_normal(),
-               top, draw_special_char(DRAW_ARROW), bottom);
+               top, special_glyph(ARROW), bottom);
         return 1;
 }
 
@@ -135,7 +126,7 @@ static int notify_override_redirected(const char *top, const char *bottom) {
 
         printf("%s%s%s %s %s %s\n",
                ansi_highlight(), "[REDIRECTED]", ansi_normal(),
-               top, draw_special_char(DRAW_ARROW), bottom);
+               top, special_glyph(ARROW), bottom);
         return 1;
 }
 
@@ -145,7 +136,7 @@ static int notify_override_overridden(const char *top, const char *bottom) {
 
         printf("%s%s%s %s %s %s\n",
                ansi_highlight(), "[OVERRIDDEN]", ansi_normal(),
-               top, draw_special_char(DRAW_ARROW), bottom);
+               top, special_glyph(ARROW), bottom);
         return 1;
 }
 
@@ -155,7 +146,7 @@ static int notify_override_extended(const char *top, const char *bottom) {
 
         printf("%s%s%s   %s %s %s\n",
                ansi_highlight(), "[EXTENDED]", ansi_normal(),
-               top, draw_special_char(DRAW_ARROW), bottom);
+               top, special_glyph(ARROW), bottom);
         return 1;
 }
 
@@ -214,7 +205,12 @@ static int found_override(const char *top, const char *bottom) {
         return k;
 }
 
-static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const char *toppath, const char *drop) {
+static int enumerate_dir_d(
+                OrderedHashmap *top,
+                OrderedHashmap *bottom,
+                OrderedHashmap *drops,
+                const char *toppath, const char *drop) {
+
         _cleanup_free_ char *unit = NULL;
         _cleanup_free_ char *path = NULL;
         _cleanup_strv_free_ char **list = NULL;
@@ -224,7 +220,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
 
         assert(!endswith(drop, "/"));
 
-        path = strjoin(toppath, "/", drop, NULL);
+        path = strjoin(toppath, "/", drop);
         if (!path)
                 return -ENOMEM;
 
@@ -243,8 +239,10 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate %s: %m", path);
 
+        strv_sort(list);
+
         STRV_FOREACH(file, list) {
-                Hashmap *h;
+                OrderedHashmap *h;
                 int k;
                 char *p;
                 char *d;
@@ -252,13 +250,13 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
                 if (!endswith(*file, ".conf"))
                         continue;
 
-                p = strjoin(path, "/", *file, NULL);
+                p = strjoin(path, "/", *file);
                 if (!p)
                         return -ENOMEM;
                 d = p + strlen(toppath) + 1;
 
-                log_debug("Adding at top: %s %s %s", d, draw_special_char(DRAW_ARROW), p);
-                k = hashmap_put(top, d, p);
+                log_debug("Adding at top: %s %s %s", d, special_glyph(ARROW), p);
+                k = ordered_hashmap_put(top, d, p);
                 if (k >= 0) {
                         p = strdup(p);
                         if (!p)
@@ -269,20 +267,20 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
                         return k;
                 }
 
-                log_debug("Adding at bottom: %s %s %s", d, draw_special_char(DRAW_ARROW), p);
-                free(hashmap_remove(bottom, d));
-                k = hashmap_put(bottom, d, p);
+                log_debug("Adding at bottom: %s %s %s", d, special_glyph(ARROW), p);
+                free(ordered_hashmap_remove(bottom, d));
+                k = ordered_hashmap_put(bottom, d, p);
                 if (k < 0) {
                         free(p);
                         return k;
                 }
 
-                h = hashmap_get(drops, unit);
+                h = ordered_hashmap_get(drops, unit);
                 if (!h) {
-                        h = hashmap_new(&string_hash_ops);
+                        h = ordered_hashmap_new(&string_hash_ops);
                         if (!h)
                                 return -ENOMEM;
-                        hashmap_put(drops, unit, h);
+                        ordered_hashmap_put(drops, unit, h);
                         unit = strdup(unit);
                         if (!unit)
                                 return -ENOMEM;
@@ -293,8 +291,8 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
                         return -ENOMEM;
 
                 log_debug("Adding to drops: %s %s %s %s %s",
-                          unit, draw_special_char(DRAW_ARROW), basename(p), draw_special_char(DRAW_ARROW), p);
-                k = hashmap_put(h, basename(p), p);
+                          unit, special_glyph(ARROW), basename(p), special_glyph(ARROW), p);
+                k = ordered_hashmap_put(h, basename(p), p);
                 if (k < 0) {
                         free(p);
                         if (k != -EEXIST)
@@ -304,8 +302,18 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
         return 0;
 }
 
-static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const char *path, bool dropins) {
-        _cleanup_closedir_ DIR *d;
+static int enumerate_dir(
+                OrderedHashmap *top,
+                OrderedHashmap *bottom,
+                OrderedHashmap *drops,
+                const char *path, bool dropins) {
+
+        _cleanup_closedir_ DIR *d = NULL;
+        struct dirent *de;
+        _cleanup_strv_free_ char **files = NULL, **dirs = NULL;
+        size_t n_files = 0, allocated_files = 0, n_dirs = 0, allocated_dirs = 0;
+        char **t;
+        int r;
 
         assert(top);
         assert(bottom);
@@ -319,58 +327,90 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch
                 if (errno == ENOENT)
                         return 0;
 
-                log_error_errno(errno, "Failed to open %s: %m", path);
-                return -errno;
+                return log_error_errno(errno, "Failed to open %s: %m", path);
         }
 
-        for (;;) {
-                struct dirent *de;
-                int k;
-                char *p;
-
-                errno = 0;
-                de = readdir(d);
-                if (!de)
-                        return -errno;
-
+        FOREACH_DIRENT_ALL(de, d, return -errno) {
                 dirent_ensure_type(d, de);
 
-                if (dropins && de->d_type == DT_DIR && endswith(de->d_name, ".d"))
-                        enumerate_dir_d(top, bottom, drops, path, de->d_name);
+                if (dropins && de->d_type == DT_DIR && endswith(de->d_name, ".d")) {
+                        if (!GREEDY_REALLOC0(dirs, allocated_dirs, n_dirs + 2))
+                                return -ENOMEM;
+
+                        dirs[n_dirs] = strdup(de->d_name);
+                        if (!dirs[n_dirs])
+                                return -ENOMEM;
+                        n_dirs ++;
+                }
 
                 if (!dirent_is_file(de))
                         continue;
 
-                p = strjoin(path, "/", de->d_name, NULL);
+                if (!GREEDY_REALLOC0(files, allocated_files, n_files + 2))
+                        return -ENOMEM;
+
+                files[n_files] = strdup(de->d_name);
+                if (!files[n_files])
+                        return -ENOMEM;
+                n_files ++;
+        }
+
+        strv_sort(dirs);
+        strv_sort(files);
+
+        STRV_FOREACH(t, dirs) {
+                r = enumerate_dir_d(top, bottom, drops, path, *t);
+                if (r < 0)
+                        return r;
+        }
+
+        STRV_FOREACH(t, files) {
+                _cleanup_free_ char *p = NULL;
+
+                p = strjoin(path, "/", *t);
                 if (!p)
                         return -ENOMEM;
 
-                log_debug("Adding at top: %s %s %s", basename(p), draw_special_char(DRAW_ARROW), p);
-                k = hashmap_put(top, basename(p), p);
-                if (k >= 0) {
+                log_debug("Adding at top: %s %s %s", basename(p), special_glyph(ARROW), p);
+                r = ordered_hashmap_put(top, basename(p), p);
+                if (r >= 0) {
                         p = strdup(p);
                         if (!p)
                                 return -ENOMEM;
-                } else if (k != -EEXIST) {
-                        free(p);
-                        return k;
-                }
+                } else if (r != -EEXIST)
+                        return r;
 
-                log_debug("Adding at bottom: %s %s %s", basename(p), draw_special_char(DRAW_ARROW), p);
-                free(hashmap_remove(bottom, basename(p)));
-                k = hashmap_put(bottom, basename(p), p);
-                if (k < 0) {
-                        free(p);
-                        return k;
-                }
+                log_debug("Adding at bottom: %s %s %s", basename(p), special_glyph(ARROW), p);
+                free(ordered_hashmap_remove(bottom, basename(p)));
+                r = ordered_hashmap_put(bottom, basename(p), p);
+                if (r < 0)
+                        return r;
+                p = NULL;
         }
+
+        return 0;
+}
+
+static int should_skip_prefix(const char* p) {
+#if HAVE_SPLIT_USR
+        int r;
+        _cleanup_free_ char *target = NULL;
+
+        r = chase_symlinks(p, NULL, 0, &target);
+        if (r < 0)
+                return r;
+
+        return !streq(p, target) && nulstr_contains(prefixes, target);
+#else
+        return 0;
+#endif
 }
 
 static int process_suffix(const char *suffix, const char *onlyprefix) {
         const char *p;
         char *f;
-        Hashmap *top, *bottom, *drops;
-        Hashmap *h;
+        OrderedHashmap *top, *bottom, *drops;
+        OrderedHashmap *h;
         char *key;
         int r = 0, k;
         Iterator i, j;
@@ -383,9 +423,9 @@ static int process_suffix(const char *suffix, const char *onlyprefix) {
 
         dropins = nulstr_contains(have_dropins, suffix);
 
-        top = hashmap_new(&string_hash_ops);
-        bottom = hashmap_new(&string_hash_ops);
-        drops = hashmap_new(&string_hash_ops);
+        top = ordered_hashmap_new(&string_hash_ops);
+        bottom = ordered_hashmap_new(&string_hash_ops);
+        drops = ordered_hashmap_new(&string_hash_ops);
         if (!top || !bottom || !drops) {
                 r = -ENOMEM;
                 goto finish;
@@ -393,8 +433,17 @@ static int process_suffix(const char *suffix, const char *onlyprefix) {
 
         NULSTR_FOREACH(p, prefixes) {
                 _cleanup_free_ char *t = NULL;
+                int skip;
 
-                t = strjoin(p, "/", suffix, NULL);
+                skip = should_skip_prefix(p);
+                if (skip < 0) {
+                        r = skip;
+                        goto finish;
+                }
+                if (skip)
+                        continue;
+
+                t = strjoin(p, "/", suffix);
                 if (!t) {
                         r = -ENOMEM;
                         goto finish;
@@ -405,10 +454,10 @@ static int process_suffix(const char *suffix, const char *onlyprefix) {
                         r = k;
         }
 
-        HASHMAP_FOREACH_KEY(f, key, top, i) {
+        ORDERED_HASHMAP_FOREACH_KEY(f, key, top, i) {
                 char *o;
 
-                o = hashmap_get(bottom, key);
+                o = ordered_hashmap_get(bottom, key);
                 assert(o);
 
                 if (!onlyprefix || startswith(o, onlyprefix)) {
@@ -423,26 +472,24 @@ static int process_suffix(const char *suffix, const char *onlyprefix) {
                         }
                 }
 
-                h = hashmap_get(drops, key);
+                h = ordered_hashmap_get(drops, key);
                 if (h)
-                        HASHMAP_FOREACH(o, h, j)
+                        ORDERED_HASHMAP_FOREACH(o, h, j)
                                 if (!onlyprefix || startswith(o, onlyprefix))
                                         n_found += notify_override_extended(f, o);
         }
 
 finish:
-        if (top)
-                hashmap_free_free(top);
-        if (bottom)
-                hashmap_free_free(bottom);
-        if (drops) {
-                HASHMAP_FOREACH_KEY(h, key, drops, i){
-                        hashmap_free_free(hashmap_remove(drops, key));
-                        hashmap_remove(drops, key);
-                        free(key);
-                }
-                hashmap_free(drops);
+        ordered_hashmap_free_free(top);
+        ordered_hashmap_free_free(bottom);
+
+        ORDERED_HASHMAP_FOREACH_KEY(h, key, drops, i) {
+                ordered_hashmap_free_free(ordered_hashmap_remove(drops, key));
+                ordered_hashmap_remove(drops, key);
+                free(key);
         }
+        ordered_hashmap_free(drops);
+
         return r < 0 ? r : n_found;
 }
 
@@ -454,9 +501,10 @@ static int process_suffixes(const char *onlyprefix) {
                 r = process_suffix(n, onlyprefix);
                 if (r < 0)
                         return r;
-                else
-                        n_found += r;
+
+                n_found += r;
         }
+
         return n_found;
 }
 
@@ -470,7 +518,16 @@ static int process_suffix_chop(const char *arg) {
 
         /* Strip prefix from the suffix */
         NULSTR_FOREACH(p, prefixes) {
-                const char *suffix = startswith(arg, p);
+                const char *suffix;
+                int skip;
+
+                skip = should_skip_prefix(p);
+                if (skip < 0)
+                        return skip;
+                if (skip)
+                        continue;
+
+                suffix = startswith(arg, p);
                 if (suffix) {
                         suffix += strspn(suffix, "/");
                         if (*suffix)
@@ -578,10 +635,9 @@ static int parse_argv(int argc, char *argv[]) {
                                 if (b < 0) {
                                         log_error("Failed to parse diff boolean.");
                                         return -EINVAL;
-                                } else if (b)
-                                        arg_diff = 1;
-                                else
-                                        arg_diff = 0;
+                                }
+
+                                arg_diff = b;
                         }
                         break;
 
@@ -596,8 +652,7 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 int main(int argc, char *argv[]) {
-        int r = 0, k;
-        int n_found = 0;
+        int r, k, n_found = 0;
 
         log_parse_environment();
         log_open();
@@ -614,13 +669,14 @@ int main(int argc, char *argv[]) {
         else if (arg_diff)
                 arg_flags |= SHOW_OVERRIDDEN;
 
-        pager_open_if_enabled();
+        pager_open(arg_no_pager, false);
 
         if (optind < argc) {
                 int i;
 
                 for (i = optind; i < argc; i++) {
                         path_kill_slashes(argv[i]);
+
                         k = process_suffix_chop(argv[i]);
                         if (k < 0)
                                 r = k;
@@ -637,8 +693,7 @@ int main(int argc, char *argv[]) {
         }
 
         if (r >= 0)
-                printf("%s%i overridden configuration files found.\n",
-                       n_found ? "\n" : "", n_found);
+                printf("%s%i overridden configuration files found.\n", n_found ? "\n" : "", n_found);
 
 finish:
         pager_close();