771b4bc
From 3e37501e12297f2ddd02d5cabb056166470c783a Mon Sep 17 00:00:00 2001
771b4bc
From: Gergely Nagy <algernon@balabit.hu>
771b4bc
Date: Wed, 16 May 2012 18:11:27 +0200
771b4bc
Subject: [PATCH] delta: Support filtering what type of deltas to show
771b4bc
771b4bc
Not everyone is interested in every kind of deltas (and some might
771b4bc
even be interested knowing which files do not have overrides), so this
771b4bc
here is an implementation of a --type=LIST... option for
771b4bc
systemd-delta, that makes it possible to filter what subset of deltas
771b4bc
we want.
771b4bc
771b4bc
The available modifiers are masked, equivalent, redirected, overriden,
771b4bc
and unchanged - they should be self explanatory, and the man page
771b4bc
explains them in a little more detail anyway.
771b4bc
771b4bc
As a side effect, in case of overriden files, the diff output was made
771b4bc
optional.
771b4bc
771b4bc
By default, everything is shown (with a diff, if appropriate) except
771b4bc
for completely unchanged files.
771b4bc
771b4bc
Signed-off-by: Gergely Nagy <algernon@balabit.hu>
771b4bc
(cherry picked from commit 807f46452202891731b2317ef9bc9a6bc7115f23)
771b4bc
---
771b4bc
 man/systemd-delta.xml |   60 +++++++++++++++++++++
771b4bc
 src/delta/delta.c     |  139 +++++++++++++++++++++++++++++++++++++++++++------
771b4bc
 2 files changed, 183 insertions(+), 16 deletions(-)
771b4bc
771b4bc
diff --git a/man/systemd-delta.xml b/man/systemd-delta.xml
771b4bc
index 0e06b48..03c7178 100644
771b4bc
--- a/man/systemd-delta.xml
771b4bc
+++ b/man/systemd-delta.xml
771b4bc
@@ -99,6 +99,66 @@
771b4bc
 				pager.</para></listitem>
771b4bc
 			</varlistentry>
771b4bc
 
771b4bc
+                        <varlistentry>
771b4bc
+                                <term><option>--type=</option></term>
771b4bc
+                                <term><option>-t</option></term>
771b4bc
+
771b4bc
+                                <listitem><para>When listing the
771b4bc
+                                differences, only list those that are
771b4bc
+                                asked for. The list itself is a
771b4bc
+                                comma-separated list of desired
771b4bc
+                                difference types.</para>
771b4bc
+
771b4bc
+                                <para>Recognised types are:
771b4bc
+
771b4bc
+                                        <variablelist>
771b4bc
+                                                <varlistentry>
771b4bc
+                                                        <term><varname>masked</varname></term>
771b4bc
+
771b4bc
+                                                        <listitem><para>Show masked files</para></listitem>
771b4bc
+                                                </varlistentry>
771b4bc
+
771b4bc
+                                                <varlistentry>
771b4bc
+                                                        <term><varname>equivalent</varname></term>
771b4bc
+
771b4bc
+                                                        <listitem><para>Show overriden
771b4bc
+                                                        files that while overriden, do
771b4bc
+                                                        not differ in content.</para></listitem>
771b4bc
+                                                </varlistentry>
771b4bc
+
771b4bc
+                                                <varlistentry>
771b4bc
+                                                        <term><varname>redirected</varname></term>
771b4bc
+
771b4bc
+                                                        <listitem><para>Show files that
771b4bc
+                                                        are redirected to another.</para></listitem>
771b4bc
+                                                </varlistentry>
771b4bc
+
771b4bc
+                                                <varlistentry>
771b4bc
+                                                        <term><varname>overriden</varname></term>
771b4bc
+
771b4bc
+                                                        <listitem><para>Show overriden,
771b4bc
+                                                        and changed files.</para></listitem>
771b4bc
+                                                </varlistentry>
771b4bc
+
771b4bc
+                                                <varlistentry>
771b4bc
+                                                        <term><varname>unchanged</varname></term>
771b4bc
+
771b4bc
+                                                        <listitem><para>Show unmodified
771b4bc
+                                                        files too.</para></listitem>
771b4bc
+                                                </varlistentry>
771b4bc
+                                        </variablelist>
771b4bc
+                                </para></listitem>
771b4bc
+                        </varlistentry>
771b4bc
+
771b4bc
+                        <varlistentry>
771b4bc
+                                <term><option>--diff=</option></term>
771b4bc
+
771b4bc
+                                <listitem><para>When showing modified
771b4bc
+                                files, when a file is overriden show a
771b4bc
+                                diff aswell. This option takes a
771b4bc
+                                boolean argument.</para></listitem>
771b4bc
+                        </varlistentry>
771b4bc
+
771b4bc
                 </variablelist>
771b4bc
 
771b4bc
         </refsect1>
771b4bc
diff --git a/src/delta/delta.c b/src/delta/delta.c
771b4bc
index 2e33759..585bb0c 100644
771b4bc
--- a/src/delta/delta.c
771b4bc
+++ b/src/delta/delta.c
771b4bc
@@ -55,7 +55,57 @@ static int equivalent(const char *a, const char *b) {
771b4bc
         return r;
771b4bc
 }
771b4bc
 
771b4bc
-static int found_override(const char *top, const char *bottom) {
771b4bc
+#define SHOW_MASKED		1 << 0
771b4bc
+#define SHOW_EQUIV		1 << 1
771b4bc
+#define SHOW_REDIR		1 << 2
771b4bc
+#define SHOW_OVERRIDEN		1 << 3
771b4bc
+#define SHOW_UNCHANGED		1 << 4
771b4bc
+#define SHOW_DIFF		1 << 5
771b4bc
+
771b4bc
+#define SHOW_DEFAULTS \
771b4bc
+        (SHOW_MASKED | SHOW_EQUIV | SHOW_REDIR | SHOW_OVERRIDEN | SHOW_DIFF)
771b4bc
+
771b4bc
+static int notify_override_masked(int flags, const char *top, const char *bottom) {
771b4bc
+        if (!(flags & SHOW_MASKED))
771b4bc
+                return 0;
771b4bc
+
771b4bc
+        printf(ANSI_HIGHLIGHT_RED_ON "[MASK]" ANSI_HIGHLIGHT_OFF "       %s → %s\n", top, bottom);
771b4bc
+        return 1;
771b4bc
+}
771b4bc
+
771b4bc
+static int notify_override_equiv(int flags, const char *top, const char *bottom) {
771b4bc
+        if (!(flags & SHOW_EQUIV))
771b4bc
+                return 0;
771b4bc
+
771b4bc
+        printf(ANSI_HIGHLIGHT_GREEN_ON "[EQUIVALENT]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
771b4bc
+        return 1;
771b4bc
+}
771b4bc
+
771b4bc
+static int notify_override_redir(int flags, const char *top, const char *bottom) {
771b4bc
+        if (!(flags & SHOW_REDIR))
771b4bc
+                return 0;
771b4bc
+
771b4bc
+        printf(ANSI_HIGHLIGHT_ON "[REDIRECT]" ANSI_HIGHLIGHT_OFF "   %s → %s\n", top, bottom);
771b4bc
+        return 1;
771b4bc
+}
771b4bc
+
771b4bc
+static int notify_override_overriden(int flags, const char *top, const char *bottom) {
771b4bc
+        if (!(flags & SHOW_OVERRIDEN))
771b4bc
+                return 0;
771b4bc
+
771b4bc
+        printf(ANSI_HIGHLIGHT_ON "[OVERRIDE]" ANSI_HIGHLIGHT_OFF "   %s → %s\n", top, bottom);
771b4bc
+        return 1;
771b4bc
+}
771b4bc
+
771b4bc
+static int notify_override_unchanged(int flags, const char *top, const char *bottom) {
771b4bc
+        if (!(flags & SHOW_UNCHANGED))
771b4bc
+                return 0;
771b4bc
+
771b4bc
+        printf(ANSI_HIGHLIGHT_ON "[UNCHANGED]" ANSI_HIGHLIGHT_OFF "   %s → %s\n", top, bottom);
771b4bc
+        return 1;
771b4bc
+}
771b4bc
+
771b4bc
+static int found_override(int flags, const char *top, const char *bottom) {
771b4bc
         char *dest;
771b4bc
         int k;
771b4bc
         pid_t pid;
771b4bc
@@ -64,22 +114,24 @@ static int found_override(const char *top, const char *bottom) {
771b4bc
         assert(bottom);
771b4bc
 
771b4bc
         if (null_or_empty_path(top) > 0) {
771b4bc
-                printf(ANSI_HIGHLIGHT_RED_ON "[MASK]" ANSI_HIGHLIGHT_OFF "       %s → %s\n", top, bottom);
771b4bc
+                notify_override_masked(flags, top, bottom);
771b4bc
                 goto finish;
771b4bc
         }
771b4bc
 
771b4bc
         k = readlink_malloc(top, &dest);
771b4bc
         if (k >= 0) {
771b4bc
                 if (equivalent(dest, bottom) > 0)
771b4bc
-                        printf(ANSI_HIGHLIGHT_GREEN_ON "[EQUIVALENT]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
771b4bc
+                        notify_override_equiv(flags, top, bottom);
771b4bc
                 else
771b4bc
-                        printf(ANSI_HIGHLIGHT_ON "[REDIRECT]" ANSI_HIGHLIGHT_OFF "   %s → %s\n", top, bottom);
771b4bc
+                        notify_override_redir(flags, top, bottom);
771b4bc
 
771b4bc
                 free(dest);
771b4bc
                 goto finish;
771b4bc
         }
771b4bc
 
771b4bc
-        printf(ANSI_HIGHLIGHT_ON "[OVERRIDE]" ANSI_HIGHLIGHT_OFF "   %s → %s\n", top, bottom);
771b4bc
+        notify_override_overriden(flags, top, bottom);
771b4bc
+        if (!(flags & SHOW_DIFF))
771b4bc
+                goto finish;
771b4bc
 
771b4bc
         putchar('\n');
771b4bc
 
771b4bc
@@ -174,7 +226,7 @@ finish:
771b4bc
         return r;
771b4bc
 }
771b4bc
 
771b4bc
-static int process_suffix(const char *prefixes, const char *suffix) {
771b4bc
+static int process_suffix(int flags, const char *prefixes, const char *suffix) {
771b4bc
         const char *p;
771b4bc
         char *f;
771b4bc
         Hashmap *top, *bottom;
771b4bc
@@ -220,10 +272,12 @@ static int process_suffix(const char *prefixes, const char *suffix) {
771b4bc
                 o = hashmap_get(bottom, path_get_file_name(f));
771b4bc
                 assert(o);
771b4bc
 
771b4bc
-                if (path_equal(o, f))
771b4bc
+                if (path_equal(o, f)) {
771b4bc
+                        notify_override_unchanged(flags, f, o);
771b4bc
                         continue;
771b4bc
+                }
771b4bc
 
771b4bc
-                k = found_override(f, o);
771b4bc
+                k = found_override(flags, f, o);
771b4bc
                 if (k < 0)
771b4bc
                         r = k;
771b4bc
 
771b4bc
@@ -239,21 +293,21 @@ finish:
771b4bc
         return r < 0 ? r : n_found;
771b4bc
 }
771b4bc
 
771b4bc
-static int process_suffix_chop(const char *prefixes, const char *suffix) {
771b4bc
+static int process_suffix_chop(int flags, const char *prefixes, const char *suffix) {
771b4bc
         const char *p;
771b4bc
 
771b4bc
         assert(prefixes);
771b4bc
         assert(suffix);
771b4bc
 
771b4bc
         if (!path_is_absolute(suffix))
771b4bc
-                return process_suffix(prefixes, suffix);
771b4bc
+                return process_suffix(flags, prefixes, suffix);
771b4bc
 
771b4bc
         /* Strip prefix from the suffix */
771b4bc
         NULSTR_FOREACH(p, prefixes) {
771b4bc
                 if (startswith(suffix, p)) {
771b4bc
                         suffix += strlen(p);;
771b4bc
                         suffix += strspn(suffix, "/");
771b4bc
-                        return process_suffix(prefixes, suffix);
771b4bc
+                        return process_suffix(flags, prefixes, suffix);
771b4bc
                 }
771b4bc
         }
771b4bc
 
771b4bc
@@ -267,14 +321,42 @@ static void help(void) {
771b4bc
                "Find overridden configuration files.\n\n"
771b4bc
                "  -h --help           Show this help\n"
771b4bc
                "     --version        Show package version\n"
771b4bc
-               "     --no-pager       Do not pipe output into a pager\n",
771b4bc
+               "     --no-pager       Do not pipe output into a pager\n"
771b4bc
+               "     --diff[=1|0]     Show a diff when overriden files differ\n"
771b4bc
+               "  -t --type=LIST...   Only display a selected set of override types\n",
771b4bc
                program_invocation_short_name);
771b4bc
 }
771b4bc
 
771b4bc
-static int parse_argv(int argc, char *argv[]) {
771b4bc
+static int parse_flags(int flags, const char *flag_str) {
771b4bc
+        char *w, *state;
771b4bc
+        size_t l;
771b4bc
+
771b4bc
+        FOREACH_WORD(w, l, flag_str, state) {
771b4bc
+                if (strncmp("masked", w, l) == 0) {
771b4bc
+                        flags |= SHOW_MASKED;
771b4bc
+                } else if (strncmp ("equivalent", w, l) == 0) {
771b4bc
+                        flags |= SHOW_EQUIV;
771b4bc
+                } else if (strncmp("redirected", w, l) == 0) {
771b4bc
+                        flags |= SHOW_REDIR;
771b4bc
+                } else if (strncmp("override", w, l) == 0) {
771b4bc
+                        flags |= SHOW_OVERRIDEN;
771b4bc
+                } else if (strncmp("unchanged", w, l) == 0) {
771b4bc
+                        flags |= SHOW_UNCHANGED;
771b4bc
+                } else if (strncmp("default", w, l) == 0) {
771b4bc
+                        flags |= SHOW_DEFAULTS;
771b4bc
+                } else {
771b4bc
+                        log_error("Unknown type filter: %s", w);
771b4bc
+                        return -1;
771b4bc
+                }
771b4bc
+        }
771b4bc
+        return flags;
771b4bc
+}
771b4bc
+
771b4bc
+static int parse_argv(int argc, char *argv[], int *flags) {
771b4bc
 
771b4bc
         enum {
771b4bc
                 ARG_NO_PAGER = 0x100,
771b4bc
+                ARG_DIFF,
771b4bc
                 ARG_VERSION
771b4bc
         };
771b4bc
 
771b4bc
@@ -282,6 +364,8 @@ static int parse_argv(int argc, char *argv[]) {
771b4bc
                 { "help",      no_argument,       NULL, 'h'          },
771b4bc
                 { "version",   no_argument,       NULL, ARG_VERSION  },
771b4bc
                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER },
771b4bc
+                { "diff",      optional_argument, NULL, ARG_DIFF     },
771b4bc
+                { "type",      required_argument, NULL, 't'          },
771b4bc
                 { NULL,        0,                 NULL, 0            }
771b4bc
         };
771b4bc
 
771b4bc
@@ -311,6 +395,23 @@ static int parse_argv(int argc, char *argv[]) {
771b4bc
                 case '?':
771b4bc
                         return -EINVAL;
771b4bc
 
771b4bc
+                case 't':
771b4bc
+                        *flags = parse_flags(*flags, optarg);
771b4bc
+                        if (*flags < 0)
771b4bc
+                                return -EINVAL;
771b4bc
+                        break;
771b4bc
+
771b4bc
+                case ARG_DIFF:
771b4bc
+                        if (!optarg) {
771b4bc
+                                *flags |= SHOW_DIFF;
771b4bc
+                        } else {
771b4bc
+                                if (parse_boolean(optarg))
771b4bc
+                                        *flags |= SHOW_DIFF;
771b4bc
+                                else
771b4bc
+                                        *flags &= ~SHOW_DIFF;
771b4bc
+                        }
771b4bc
+                        break;
771b4bc
+
771b4bc
                 default:
771b4bc
                         log_error("Unknown option code %c", c);
771b4bc
                         return -EINVAL;
771b4bc
@@ -348,14 +449,20 @@ int main(int argc, char *argv[]) {
771b4bc
 
771b4bc
         int r = 0, k;
771b4bc
         int n_found = 0;
771b4bc
+        int flags = 0;
771b4bc
 
771b4bc
         log_parse_environment();
771b4bc
         log_open();
771b4bc
 
771b4bc
-        r = parse_argv(argc, argv);
771b4bc
+        r = parse_argv(argc, argv, &flags);
771b4bc
         if (r <= 0)
771b4bc
                 goto finish;
771b4bc
 
771b4bc
+        if (flags == 0)
771b4bc
+                flags = SHOW_DEFAULTS;
771b4bc
+        if (flags == SHOW_DIFF)
771b4bc
+                flags |= SHOW_OVERRIDEN;
771b4bc
+
771b4bc
         if (!arg_no_pager)
771b4bc
                 pager_open();
771b4bc
 
771b4bc
@@ -363,7 +470,7 @@ int main(int argc, char *argv[]) {
771b4bc
                 int i;
771b4bc
 
771b4bc
                 for (i = optind; i < argc; i++) {
771b4bc
-                        k = process_suffix_chop(prefixes, argv[i]);
771b4bc
+                        k = process_suffix_chop(flags, prefixes, argv[i]);
771b4bc
                         if (k < 0)
771b4bc
                                 r = k;
771b4bc
                         else
771b4bc
@@ -374,7 +481,7 @@ int main(int argc, char *argv[]) {
771b4bc
                 const char *n;
771b4bc
 
771b4bc
                 NULSTR_FOREACH(n, suffixes) {
771b4bc
-                        k = process_suffix(prefixes, n);
771b4bc
+                        k = process_suffix(flags, prefixes, n);
771b4bc
                         if (k < 0)
771b4bc
                                 r = k;
771b4bc
                         else