summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/systemd-analyze.xml30
-rw-r--r--src/analyze/analyze.c27
-rw-r--r--src/basic/conf-files.c32
-rw-r--r--src/basic/conf-files.h1
-rw-r--r--src/basic/terminal-util.c9
-rw-r--r--src/basic/terminal-util.h7
-rw-r--r--src/systemctl/systemctl.c2
-rw-r--r--src/test/test-terminal-util.c5
8 files changed, 107 insertions, 6 deletions
diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml
index de14a7e3ce..70f87f4786 100644
--- a/man/systemd-analyze.xml
+++ b/man/systemd-analyze.xml
@@ -81,6 +81,12 @@
<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>
<arg choice="plain">unit-paths</arg>
</cmdsynopsis>
<cmdsynopsis>
@@ -180,6 +186,30 @@
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
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 06add1171d..0b0925d18c 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -19,12 +19,14 @@
#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 },
diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c
index 8e0fb06ad9..4c5ecb5cbb 100644
--- a/src/basic/conf-files.c
+++ b/src/basic/conf-files.c
@@ -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);
+}
diff --git a/src/basic/conf-files.h b/src/basic/conf-files.h
index b902c3a3b3..3d1feadf03 100644
--- a/src/basic/conf-files.h
+++ b/src/basic/conf-files.h
@@ -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);
diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c
index 5624c03bce..c2b7cd799e 100644
--- a/src/basic/terminal-util.c
+++ b/src/basic/terminal-util.c
@@ -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);
}
diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h
index d2d3ad5127..ea7eb2d63b 100644
--- a/src/basic/terminal-util.h
+++ b/src/basic/terminal-util.h
@@ -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);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 23ce6acd6a..a1938bc91b 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -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;
}
diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c
index 92add77531..61a3ea5e56 100644
--- a/src/test/test-terminal-util.c
+++ b/src/test/test-terminal-util.c
@@ -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[]) {