]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
analyze/cat-config: add switch to print only "interesting" parts of config files
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 12 Oct 2023 14:33:01 +0000 (16:33 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 24 Oct 2023 13:59:34 +0000 (15:59 +0200)
When looking at configuration, often a user wants to suppress the comments and
just look at the parts that actually configure something, roughly equivalent to
  systemd-analyze cat-config … | rg -v '^(#|;|$)
This switch implements this natively, skipping lines that start with a comment
character or only contain whitespace.

For formats that have section headers, section headers are skipped, if only
followed by stuff that would be skipped. (The last section header is printed
when we're about to print some actual output.)

Note that the caller doesn't know if the format has headers or not. We do format
type detection in pretty-print.c. So the caller only specifies tldr=true|false, and
conf_files_cat() figures out if the format has headers and whether those should
be handled specially.

The comments that show the file name are always printed, even if all of the file
is suppressed.

This is a partial answer to the discussions in
https://github.com/systemd/systemd/pull/28919,
https://github.com/systemd/systemd/pull/29248. If the default config is shown in
config files, the user can conveniently use '--tldr' to show the relevant parts.

13 files changed:
man/systemd-analyze.xml
src/analyze/analyze-cat-config.c
src/analyze/analyze.c
src/analyze/analyze.h
src/binfmt/binfmt.c
src/machine/machinectl.c
src/network/networkctl.c
src/shared/pretty-print.c
src/shared/pretty-print.h
src/sysctl/sysctl.c
src/systemctl/systemctl-edit.c
src/sysusers/sysusers.c
test/units/testsuite-65.sh

index d3a1de9a91bf3ed84dd8d68d955fb99f07c809af..5b7f22c87c321c7cc97c203563156bcdb27de586 100644 (file)
@@ -1470,6 +1470,16 @@ NR NAME                SHA256
         <xi:include href="version-info.xml" xpointer="v250"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--tldr</option></term>
+
+        <listitem><para>With <command>cat-config</command>, only print the "interesting" parts of the
+        configuration files, skipping comments and empty lines and section headers followed only by
+        comments and empty lines.</para>
+
+        <xi:include href="version-info.xml" xpointer="v255"/></listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
       <xi:include href="standard-options.xml" xpointer="no-pager" />
index 08184cedfe2fc8f8ff57efae451d94fbae246499..66bbbc11028a5219090d9a21e372a97b17ea4e38 100644 (file)
@@ -35,7 +35,7 @@ int verb_cat_config(int argc, char *argv[], void *userdata) {
                 } else
                         t = *arg;
 
-                r = conf_files_cat(arg_root, t);
+                r = conf_files_cat(arg_root, t, arg_cat_flags);
                 if (r < 0)
                         return r;
         }
index b7c852a08c87ded81214d145d2f815db07b98629..1b96e8b69a4b6d22a6067196c0c7744888f82b27 100644 (file)
@@ -91,6 +91,7 @@ DotMode arg_dot = DEP_ALL;
 char **arg_dot_from_patterns = NULL, **arg_dot_to_patterns = NULL;
 usec_t arg_fuzz = 0;
 PagerFlags arg_pager_flags = 0;
+CatFlags arg_cat_flags = 0;
 BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
 const char *arg_host = NULL;
 RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
@@ -270,6 +271,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  -h --help                  Show this help\n"
                "     --version               Show package version\n"
                "  -q --quiet                 Do not emit hints\n"
+               "     --tldr                  Skip comments and empty lines\n"
                "     --root=PATH             Operate on an alternate filesystem root\n"
                "     --image=PATH            Operate on disk image as filesystem root\n"
                "     --image-policy=POLICY   Specify disk image dissection policy\n"
@@ -313,6 +315,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_PROFILE,
                 ARG_TABLE,
                 ARG_NO_LEGEND,
+                ARG_TLDR,
         };
 
         static const struct option options[] = {
@@ -346,6 +349,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "profile",          required_argument, NULL, ARG_PROFILE          },
                 { "table",            optional_argument, NULL, ARG_TABLE            },
                 { "no-legend",        optional_argument, NULL, ARG_NO_LEGEND        },
+                { "tldr",             no_argument,       NULL, ARG_TLDR             },
                 {}
         };
 
@@ -535,6 +539,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_legend = false;
                         break;
 
+                case ARG_TLDR:
+                        arg_cat_flags = CAT_TLDR;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
index 84575cd9a9d258f4cf2de7a66b4d2fd5396dd53b..8a9528c0d3bbbcca2ee8f21147116817f3762360 100644 (file)
@@ -7,6 +7,7 @@
 #include "bus-util.h"
 #include "json.h"
 #include "pager.h"
+#include "pretty-print.h"
 #include "time-util.h"
 #include "unit-file.h"
 
@@ -20,6 +21,7 @@ extern DotMode arg_dot;
 extern char **arg_dot_from_patterns, **arg_dot_to_patterns;
 extern usec_t arg_fuzz;
 extern PagerFlags arg_pager_flags;
+extern CatFlags arg_cat_flags;
 extern BusTransport arg_transport;
 extern const char *arg_host;
 extern RuntimeScope arg_runtime_scope;
index 675ae185e2486ce57cef82844b020ab22b01c297..fa3d6b0e26df90c9bad3ec0af08d69b826dc9358 100644 (file)
@@ -232,7 +232,7 @@ static int run(int argc, char *argv[]) {
                 if (arg_cat_config) {
                         pager_open(arg_pager_flags);
 
-                        return cat_files(NULL, files, 0);
+                        return cat_files(NULL, files, /* flags= */ 0);
                 }
 
                 r = binfmt_mounted_warn();
index 9b6a6cebda74fbe1b9d84e211b6aab4da716babf..e8e0c3299aa72ddc9dab915d8c42d45a70b82324 100644 (file)
@@ -1537,7 +1537,7 @@ static int cat_settings(int argc, char *argv[], void *userdata) {
                                                        "Invalid settings file path '%s'.",
                                                        *name);
 
-                        q = cat_files(*name, /* dropins = */ NULL, /* flags = */ 0);
+                        q = cat_files(*name, /* dropins = */ NULL, /* flags = */ CAT_FORMAT_HAS_SECTIONS);
                         if (q < 0)
                                 return r < 0 ? r : q;
                         continue;
@@ -1558,7 +1558,7 @@ static int cat_settings(int argc, char *argv[], void *userdata) {
                         return r < 0 ? r : q;
                 }
 
-                q = cat_files(path, /* dropins = */ NULL, /* flags = */ 0);
+                q = cat_files(path, /* dropins = */ NULL, /* flags = */ CAT_FORMAT_HAS_SECTIONS);
                 if (q < 0)
                         return r < 0 ? r : q;
         }
index 5d961b6c8313ad109bb2773b9ea6240e9e796462..48b0f2eca0eed310b64c32c2725c30cd9c444ca9 100644 (file)
@@ -3298,7 +3298,7 @@ static int verb_cat(int argc, char *argv[], void *userdata) {
                         }
                 }
 
-                r = cat_files(path, dropins, /* flags = */ 0);
+                r = cat_files(path, dropins, /* flags = */ CAT_FORMAT_HAS_SECTIONS);
                 if (r < 0)
                         return ret < 0 ? ret : r;
         }
index 55a2570ddf51cc9417208f24147b54dff23dfd01..ae5b9d8604503b792345785e6a38f184968e2483 100644 (file)
@@ -131,9 +131,9 @@ int terminal_urlify_man(const char *page, const char *section, char **ret) {
         return terminal_urlify(url, text, ret);
 }
 
-static int cat_file(const char *filename, bool newline) {
+static int cat_file(const char *filename, bool newline, CatFlags flags) {
         _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *urlified = NULL;
+        _cleanup_free_ char *urlified = NULL, *section = NULL;
         int r;
 
         f = fopen(filename, "re");
@@ -160,6 +160,25 @@ static int cat_file(const char *filename, bool newline) {
                 if (r == 0)
                         break;
 
+                if (flags & CAT_TLDR) {
+                        const char *t = skip_leading_chars(line, WHITESPACE);
+
+                        if ((flags & CAT_FORMAT_HAS_SECTIONS) && *t == '[') {
+                                /* The start of a section, let's not print it yet. */
+                                free_and_replace(section, line);
+                                continue;
+                        }
+
+                        if (IN_SET(*t, '#', ';', '\0'))
+                                continue;
+
+                        /* Before we print the actual line, print the last section header */
+                        if (section) {
+                                puts(section);
+                                section = mfree(section);
+                        }
+                }
+
                 puts(line);
         }
 
@@ -170,13 +189,13 @@ int cat_files(const char *file, char **dropins, CatFlags flags) {
         int r;
 
         if (file) {
-                r = cat_file(file, false);
+                r = cat_file(file, /* newline= */ false, flags);
                 if (r < 0)
                         return log_warning_errno(r, "Failed to cat %s: %m", file);
         }
 
         STRV_FOREACH(path, dropins) {
-                r = cat_file(*path, file || path != dropins);
+                r = cat_file(*path, /* newline= */ file || path != dropins, flags);
                 if (r < 0)
                         return log_warning_errno(r, "Failed to cat %s: %m", *path);
         }
@@ -208,7 +227,10 @@ void print_separator(void) {
 
 static int guess_type(const char **name, char ***prefixes, bool *is_collection, const char **extension) {
         /* Try to figure out if name is like tmpfiles.d/ or systemd/system-presets/,
-         * i.e. a collection of directories without a main config file. */
+         * i.e. a collection of directories without a main config file.
+         * Incidentally, all those formats don't use sections. So we return a single
+         * is_collection boolean, which also means that the format doesn't use sections.
+         */
 
         _cleanup_free_ char *n = NULL;
         bool usr = false, run = false, coll = false;
@@ -274,7 +296,7 @@ static int guess_type(const char **name, char ***prefixes, bool *is_collection,
         return 0;
 }
 
-int conf_files_cat(const char *root, const char *name) {
+int conf_files_cat(const char *root, const char *name, CatFlags flags) {
         _cleanup_strv_free_ char **dirs = NULL, **files = NULL;
         _cleanup_free_ char *path = NULL;
         char **prefixes = NULL; /* explicit initialization to appease gcc */
@@ -330,5 +352,8 @@ int conf_files_cat(const char *root, const char *name) {
                 return log_error_errno(r, "Failed to query file list: %m");
 
         /* Show */
-        return cat_files(path, files, 0);
+        if (is_collection)
+                flags |= CAT_FORMAT_HAS_SECTIONS;
+
+        return cat_files(path, files, flags);
 }
index 0012dc88353e6cf9176c187d46113121ddb66ba9..aef74cac2fafa22b86a0afe6fc07c16c38b90322 100644 (file)
@@ -15,11 +15,12 @@ int terminal_urlify_path(const char *path, const char *text, char **ret);
 int terminal_urlify_man(const char *page, const char *section, char **ret);
 
 typedef enum CatFlags {
-        CAT_DUMMY_FLAG,  // This flag only exists a as a placeholder because empty enums are not allowed
+        CAT_FORMAT_HAS_SECTIONS = 1 << 0,  /* Sections are meaningful for this file format */
+        CAT_TLDR                = 1 << 1,  /* Only print comments and relevant section headers */
 } CatFlags;
 
 int cat_files(const char *file, char **dropins, CatFlags flags);
-int conf_files_cat(const char *root, const char *name);
+int conf_files_cat(const char *root, const char *name, CatFlags flags);
 
 #define RED_CROSS_MARK_MAX (STRLEN(ANSI_HIGHLIGHT_RED) + STRLEN("✗") + STRLEN(ANSI_NORMAL) + 1)
 #define GREEN_CHECK_MARK_MAX (STRLEN(ANSI_HIGHLIGHT_GREEN) + STRLEN("✓") + STRLEN(ANSI_NORMAL) + 1)
index ca41f02fdd53cc400b73719090b7633c244945b0..bf078ac6e14a61185ba7ddc651d946edb4234bca 100644 (file)
@@ -464,7 +464,7 @@ static int run(int argc, char *argv[]) {
                 if (arg_cat_config) {
                         pager_open(arg_pager_flags);
 
-                        return cat_files(NULL, files, 0);
+                        return cat_files(NULL, files, /* flags= */ 0);
                 }
 
                 STRV_FOREACH(f, files)
index ac0bbb454297bba5c2fd1890ecc25689a10fb779..367afa20f7af44f0e4fc3d2df0ca0db17021b512 100644 (file)
@@ -93,7 +93,7 @@ int verb_cat(int argc, char *argv[], void *userdata) {
                                 arg_runtime_scope == RUNTIME_SCOPE_SYSTEM ? "" : " --user",
                                 ansi_normal());
 
-                r = cat_files(fragment_path, dropin_paths, 0);
+                r = cat_files(fragment_path, dropin_paths, /* flags= */ CAT_FORMAT_HAS_SECTIONS);
                 if (r < 0)
                         return r;
         }
index 0fcbf261c115744060d73aa167cead6ac01ca459..d996583cbd753d6fdf24be47cc662fe128a6c4b8 100644 (file)
@@ -2044,7 +2044,7 @@ static int cat_config(void) {
 
         pager_open(arg_pager_flags);
 
-        return cat_files(NULL, files, 0);
+        return cat_files(NULL, files, /* flags= */ 0);
 }
 
 static int help(void) {
index 66db42d759390e5f11774f6c915f162c82d64532..9bd2c0b3bd125969a3863e44bb776e3278828d04 100755 (executable)
@@ -165,6 +165,11 @@ systemd-analyze cat-config /etc/systemd/system.conf >/dev/null
 systemd-analyze cat-config systemd/system.conf systemd/journald.conf >/dev/null
 systemd-analyze cat-config systemd/system.conf foo/bar systemd/journald.conf >/dev/null
 systemd-analyze cat-config foo/bar
+systemd-analyze cat-config --tldr systemd/system.conf >/dev/null
+systemd-analyze cat-config --tldr /etc/systemd/system.conf >/dev/null
+systemd-analyze cat-config --tldr systemd/system.conf systemd/journald.conf >/dev/null
+systemd-analyze cat-config --tldr systemd/system.conf foo/bar systemd/journald.conf >/dev/null
+systemd-analyze cat-config --tldr foo/bar
 # security
 systemd-analyze security
 systemd-analyze security --json=off