From: Zbigniew Jędrzejewski-Szmek Date: Thu, 12 Oct 2023 14:33:01 +0000 (+0200) Subject: analyze/cat-config: add switch to print only "interesting" parts of config files X-Git-Tag: v255-rc1~147^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=063c8382068b4cb8661aa5a77b6c7d117d0bd117;p=thirdparty%2Fsystemd.git analyze/cat-config: add switch to print only "interesting" parts of config files 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. --- diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index d3a1de9a91b..5b7f22c87c3 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -1470,6 +1470,16 @@ NR NAME SHA256 + + + + With cat-config, only print the "interesting" parts of the + configuration files, skipping comments and empty lines and section headers followed only by + comments and empty lines. + + + + diff --git a/src/analyze/analyze-cat-config.c b/src/analyze/analyze-cat-config.c index 08184cedfe2..66bbbc11028 100644 --- a/src/analyze/analyze-cat-config.c +++ b/src/analyze/analyze-cat-config.c @@ -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; } diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index b7c852a08c8..1b96e8b69a4 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -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; diff --git a/src/analyze/analyze.h b/src/analyze/analyze.h index 84575cd9a9d..8a9528c0d3b 100644 --- a/src/analyze/analyze.h +++ b/src/analyze/analyze.h @@ -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; diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c index 675ae185e24..fa3d6b0e26d 100644 --- a/src/binfmt/binfmt.c +++ b/src/binfmt/binfmt.c @@ -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(); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 9b6a6cebda7..e8e0c3299aa 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -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; } diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 5d961b6c831..48b0f2eca0e 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -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; } diff --git a/src/shared/pretty-print.c b/src/shared/pretty-print.c index 55a2570ddf5..ae5b9d86045 100644 --- a/src/shared/pretty-print.c +++ b/src/shared/pretty-print.c @@ -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); } diff --git a/src/shared/pretty-print.h b/src/shared/pretty-print.h index 0012dc88353..aef74cac2fa 100644 --- a/src/shared/pretty-print.h +++ b/src/shared/pretty-print.h @@ -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) diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index ca41f02fdd5..bf078ac6e14 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -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) diff --git a/src/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c index ac0bbb45429..367afa20f7a 100644 --- a/src/systemctl/systemctl-edit.c +++ b/src/systemctl/systemctl-edit.c @@ -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; } diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 0fcbf261c11..d996583cbd7 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -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) { diff --git a/test/units/testsuite-65.sh b/test/units/testsuite-65.sh index 66db42d7593..9bd2c0b3bd1 100755 --- a/test/units/testsuite-65.sh +++ b/test/units/testsuite-65.sh @@ -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