]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
analyze: add 'cat-config' verb
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 26 Apr 2018 11:49:50 +0000 (13:49 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 27 Apr 2018 08:06:24 +0000 (10:06 +0200)
This is used as 'systemd-analyze show-config systemd/logind.conf', which
will dump
   /etc/systemd/system/user@.service
   /etc/systemd/system/user@.service.d/*.conf
   /run/systemd/system/user@.service.d/*.conf
   /usr/local/lib/systemd/system/user@.service.d/*.conf
   /usr/lib/systemd/system/user@.service.d/*.conf

The idea is to make it easy to dump the configuration using the same locations
and order that systemd programs use themselves (including masking, in the right
order, etc.). This is the generic variant that works with any configuration
scheme that follows the same general rules:

$ systemd-analyze cat-config systemd/system.conf
$ systemd-analyze cat-config systemd/user.conf
$ systemd-analyze cat-config systemd/logind.conf
$ systemd-analyze cat-config systemd/sleep.conf
$ systemd-analyze cat-config systemd/journald.conf
$ systemd-analyze cat-config systemd/journal-remote.conf
$ systemd-analyze cat-config systemd/journal-upload.conf
$ systemd-analyze cat-config systemd/coredump.conf
$ systemd-analyze cat-config systemd/resolved.conf
$ systemd-analyze cat-config systemd/timesyncd.conf
$ systemd-analyze cat-config udev/udev.conf

man/systemd-analyze.xml
src/analyze/analyze.c
src/basic/conf-files.c
src/basic/conf-files.h
src/basic/terminal-util.c
src/basic/terminal-util.h
src/systemctl/systemctl.c
src/test/test-terminal-util.c

index de14a7e3ce9debbbcb775a16427bf8996d3b5493..70f87f47862bcf7711e256327ce797018b17950d 100644 (file)
       <arg choice="opt" rep="repeat">OPTIONS</arg>
       <arg choice="plain">dump</arg>
     </cmdsynopsis>
+    <cmdsynopsis>
+      <command>systemd-analyze</command>
+      <arg choice="opt" rep="repeat">OPTIONS</arg>
+      <arg choice="plain">cat-config</arg>
+      <arg choice="plain" rep="repeat"><replaceable>NAME</replaceable></arg>
+    </cmdsynopsis>
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
     state. Its format is subject to change without notice and should
     not be parsed by applications.</para>
 
+    <para><command>systemd-analyze cat-config</command> is similar
+    to <command>systemctl cat</command>, but operates on config files.
+    It will copy the contents of a config file and any drop-ins to standard
+    output, using the usual systemd set of directories and rules for
+    precedence.</para>
+
+    <example>
+      <title>Showing logind configuration</title>
+      <programlisting>$ systemd-analyze cat-config systemd/logind.conf
+# /etc/systemd/logind.conf
+#  This file is part of systemd.
+...
+[Login]
+NAutoVTs=8
+...
+
+# /usr/lib/systemd/logind.conf.d/20-test.conf
+... some override from another package
+
+# /etc/systemd/logind.conf.d/50-override.conf
+... some adminstrator override
+      </programlisting>
+    </example>
+
     <para><command>systemd-analyze unit-paths</command> outputs a list of all
     directories from which unit files, <filename>.d</filename> overrides, and
     <filename>.wants</filename>, <filename>.requires</filename> symlinks may be
index 06add1171de23937554c587fe1c1ae9b2c0d35f6..0b0925d18c2cad9bd0f9afe275ef9ba672834fed 100644 (file)
 #include "bus-unit-util.h"
 #include "bus-util.h"
 #include "calendarspec.h"
+#include "conf-files.h"
 #include "glob-util.h"
 #include "hashmap.h"
 #include "locale-util.h"
 #include "log.h"
 #include "pager.h"
 #include "parse-util.h"
+#include "path-util.h"
 #if HAVE_SECCOMP
 #include "seccomp-util.h"
 #endif
@@ -1312,6 +1314,29 @@ static int dump(int argc, char *argv[], void *userdata) {
         return 0;
 }
 
+static int cat_config(int argc, char *argv[], void *userdata) {
+        char **arg;
+        int r;
+
+        (void) pager_open(arg_no_pager, false);
+
+        STRV_FOREACH(arg, argv + 1) {
+                if (arg != argv + 1)
+                        puts("");
+
+                if (path_is_absolute(*arg)) {
+                        log_error("Arguments must be config file names (relative to /etc/");
+                        return -EINVAL;
+                }
+
+                r = conf_files_cat(*arg);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
 static int set_log_level(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
@@ -1643,6 +1668,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  log-level [LEVEL]        Get/set logging threshold for manager\n"
                "  log-target [TARGET]      Get/set logging target for manager\n"
                "  dump                     Output state serialization of service manager\n"
+               "  cat-config               Show configuration file and drop-ins\n"
                "  unit-paths               List load directories for units\n"
                "  syscall-filter [NAME...] Print list of syscalls in seccomp filter\n"
                "  verify FILE...           Check unit files for correctness\n"
@@ -1819,6 +1845,7 @@ int main(int argc, char *argv[]) {
                 { "set-log-target",    2,        2,        0,            set_log_target         },
                 { "get-log-target",    VERB_ANY, 1,        0,            get_log_target         },
                 { "dump",              VERB_ANY, 1,        0,            dump                   },
+                { "cat-config",        2,        VERB_ANY, 0,            cat_config             },
                 { "unit-paths",        1,        1,        0,            dump_unit_paths        },
                 { "syscall-filter",    VERB_ANY, VERB_ANY, 0,            dump_syscall_filters   },
                 { "verify",            2,        VERB_ANY, 0,            do_verify              },
index 8e0fb06ad9096bf2a324144da1efb37c6ce97fc3..4c5ecb5cbb604aaaf1dfdb4d3923f9beab556eb3 100644 (file)
@@ -13,6 +13,7 @@
 #include <string.h>
 
 #include "conf-files.h"
+#include "def.h"
 #include "dirent-util.h"
 #include "fd-util.h"
 #include "hashmap.h"
@@ -23,6 +24,7 @@
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "terminal-util.h"
 #include "util.h"
 
 static int files_add(Hashmap *h, const char *suffix, const char *root, unsigned flags, const char *path) {
@@ -256,3 +258,33 @@ int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, u
 
         return conf_files_list_strv_internal(strv, suffix, root, flags, d);
 }
+
+int conf_files_cat(const char *name) {
+        _cleanup_strv_free_ char **dirs = NULL, **files = NULL;
+        const char *dir;
+        char **t;
+        int r;
+
+        NULSTR_FOREACH(dir, CONF_PATHS_NULSTR("")) {
+                assert(endswith(dir, "/"));
+                r = strv_extendf(&dirs, "%s%s.d", dir, name);
+                if (r < 0)
+                        return log_error("Failed to build directory list: %m");
+        }
+
+        r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dirs);
+        if (r < 0)
+                return log_error_errno(r, "Failed to query file list: %m");
+
+        name = strjoina("/etc/", name);
+
+        if (DEBUG_LOGGING) {
+                log_debug("Looking for configuration in:");
+                log_debug("   %s", name);
+                STRV_FOREACH(t, dirs)
+                        log_debug("   %s/*.conf", *t);
+        }
+
+        /* show */
+        return cat_files(name, files, CAT_FLAGS_MAIN_FILE_OPTIONAL);
+}
index b902c3a3b35aae5b32416fc00c383d8a31755619..3d1feadf030f2cae58af646e3ad23cfbb4b1c3cd 100644 (file)
@@ -17,3 +17,4 @@ int conf_files_list_strv(char ***ret, const char *suffix, const char *root, unsi
 int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dirs);
 int conf_files_insert(char ***strv, const char *root, char **dirs, const char *path);
 int conf_files_insert_nulstr(char ***strv, const char *root, const char *dirs, const char *path);
+int conf_files_cat(const char *name);
index 5624c03bced650d2364e832add043ebf2a0feaa9..c2b7cd799eccfa7cc0589e0c88d422607b5d3638 100644 (file)
@@ -1381,13 +1381,18 @@ static int cat_file(const char *filename, bool newline) {
         return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0);
 }
 
-int cat_files(const char *file, char **dropins) {
+int cat_files(const char *file, char **dropins, CatFlags flags) {
         char **path;
         int r;
 
         if (file) {
                 r = cat_file(file, false);
-                if (r < 0)
+                if (r == -ENOENT && (flags & CAT_FLAGS_MAIN_FILE_OPTIONAL))
+                        printf("%s# config file %s not found%s\n",
+                               ansi_highlight_magenta(),
+                               file,
+                               ansi_normal());
+                else if (r < 0)
                         return log_warning_errno(r, "Failed to cat %s: %m", file);
         }
 
index d2d3ad5127ef4b81be4ccc7a28ce78125006a8e1..ea7eb2d63b59e12b1bd45bc7362c9089291fd9b5 100644 (file)
@@ -133,6 +133,7 @@ DEFINE_ANSI_FUNC(highlight_red,              HIGHLIGHT_RED);
 DEFINE_ANSI_FUNC(highlight_green,            HIGHLIGHT_GREEN);
 DEFINE_ANSI_FUNC(highlight_yellow,           HIGHLIGHT_YELLOW);
 DEFINE_ANSI_FUNC(highlight_blue,             HIGHLIGHT_BLUE);
+DEFINE_ANSI_FUNC(highlight_magenta,          HIGHLIGHT_MAGENTA);
 DEFINE_ANSI_FUNC(normal,                     NORMAL);
 
 DEFINE_ANSI_FUNC_UNDERLINE(underline,                  UNDERLINE, NORMAL);
@@ -160,4 +161,8 @@ int vt_reset_keyboard(int fd);
 int terminal_urlify(const char *url, const char *text, char **ret);
 int terminal_urlify_path(const char *path, const char *text, char **ret);
 
-int cat_files(const char *file, char **files);
+typedef enum CatFlags {
+        CAT_FLAGS_MAIN_FILE_OPTIONAL = 1 << 1,
+} CatFlags;
+
+int cat_files(const char *file, char **dropins, CatFlags flags);
index 23ce6acd6a0132155e3b033386138eff575efe6b..a1938bc91b44588420971f06dacf0f5f07fd0097 100644 (file)
@@ -5376,7 +5376,7 @@ static int cat(int argc, char *argv[], void *userdata) {
                                 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
                                 ansi_normal());
 
-                r = cat_files(fragment_path, dropin_paths);
+                r = cat_files(fragment_path, dropin_paths, 0);
                 if (r < 0)
                         return r;
         }
index 92add77531ac39f6f14c8d040608a67500d812ad..61a3ea5e56f08214e10c9033b80eae4bc3fea38a 100644 (file)
@@ -78,10 +78,11 @@ static void test_terminal_urlify(void) {
 }
 
 static void test_cat_files(void) {
-        assert_se(cat_files("/no/such/file", NULL) == -ENOENT);
+        assert_se(cat_files("/no/such/file", NULL, 0) == -ENOENT);
+        assert_se(cat_files("/no/such/file", NULL, CAT_FLAGS_MAIN_FILE_OPTIONAL) == 0);
 
         if (access("/etc/fstab", R_OK) >= 0)
-                assert_se(cat_files("/etc/fstab", STRV_MAKE("/etc/fstab", "/etc/fstab")) == 0);
+                assert_se(cat_files("/etc/fstab", STRV_MAKE("/etc/fstab", "/etc/fstab"), 0) == 0);
 }
 
 int main(int argc, char *argv[]) {