Merge pull request #8824 from keszybz/analyze-show-config

systemd-analyze show-config
This commit is contained in:
Lennart Poettering 2018-05-10 11:14:23 -07:00 committed by GitHub
commit 81321f51cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 418 additions and 95 deletions

View file

@ -50,4 +50,13 @@
footer with hints.</para>
</listitem>
</varlistentry>
<varlistentry id='cat-config'>
<term><option>--cat-config</option></term>
<listitem>
<para>Copy the contents of config files to standard output.
Before each file, the filename is printed as a comment.</para>
</listitem>
</varlistentry>
</variablelist>

View file

@ -78,6 +78,12 @@
<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>|<replaceable>PATH</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
@ -184,6 +190,34 @@
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. Each argument must be either an absolute path including
the prefix (such as <filename>/etc/systemd/logind.conf</filename> or
<filename>/usr/lib/systemd/logind.conf</filename>), or a name
relative to the prefix (such as <filename>systemd/logind.conf</filename>).
</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
@ -341,6 +375,13 @@
generators enabled will generally result in some warnings.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--root=<replaceable>PATH</replaceable></option></term>
<listitem><para>With <command>cat-files</command>, show config files underneath
the specified root path <replaceable>PATH</replaceable>.</para></listitem>
</varlistentry>
<xi:include href="user-system-options.xml" xpointer="host" />
<xi:include href="user-system-options.xml" xpointer="machine" />

View file

@ -8,7 +8,8 @@
Copyright 2012 Lennart Poettering
-->
<refentry id="systemd-binfmt.service" conditional='ENABLE_BINFMT'>
<refentry id="systemd-binfmt.service" conditional='ENABLE_BINFMT'
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd-binfmt.service</title>
@ -52,6 +53,14 @@
for information about the configuration of this service.</para>
</refsect1>
<refsect1><title>Options</title>
<variablelist>
<xi:include href="standard-options.xml" xpointer="cat-config" />
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<para>

View file

@ -79,6 +79,7 @@
</listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="cat-config" />
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />

View file

@ -124,6 +124,7 @@
line instead of a file name.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="cat-config" />
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>

View file

@ -183,6 +183,7 @@
</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="cat-config" />
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>

View file

@ -19,12 +19,15 @@
#include "bus-unit-util.h"
#include "bus-util.h"
#include "calendarspec.h"
#include "def.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
@ -70,6 +73,7 @@ static const char *arg_host = NULL;
static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
static bool arg_man = true;
static bool arg_generators = false;
static const char *arg_root = NULL;
struct boot_times {
usec_t firmware_time;
@ -1308,6 +1312,45 @@ 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) {
const char *t = NULL;
if (arg != argv + 1)
printf("%s%*s%s\n\n",
ansi_underline(),
columns(), "",
ansi_normal());
if (path_is_absolute(*arg)) {
const char *dir;
NULSTR_FOREACH(dir, CONF_PATHS_NULSTR("")) {
t = path_startswith(*arg, dir);
if (t)
break;
}
if (!t) {
log_error("Path %s does not start with any known prefix.", *arg);
return -EINVAL;
}
} else
t = *arg;
r = conf_files_cat(arg_root, t);
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;
@ -1639,6 +1682,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"
@ -1658,6 +1702,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERSION = 0x100,
ARG_ORDER,
ARG_REQUIRE,
ARG_ROOT,
ARG_SYSTEM,
ARG_USER,
ARG_GLOBAL,
@ -1674,6 +1719,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "version", no_argument, NULL, ARG_VERSION },
{ "order", no_argument, NULL, ARG_ORDER },
{ "require", no_argument, NULL, ARG_REQUIRE },
{ "root", required_argument, NULL, ARG_ROOT },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "user", no_argument, NULL, ARG_USER },
{ "global", no_argument, NULL, ARG_GLOBAL },
@ -1702,6 +1748,10 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_VERSION:
return version();
case ARG_ROOT:
arg_root = optarg;
break;
case ARG_SYSTEM:
arg_scope = UNIT_FILE_SYSTEM;
break;
@ -1795,6 +1845,11 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
if (arg_root && !streq_ptr(argv[optind], "cat-config")) {
log_error("Option --root is only supported for cat-config right now.");
return -EINVAL;
}
return 1; /* work to do */
}
@ -1815,6 +1870,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 },

View 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,71 @@ 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_list_with_replacement(
const char *root,
char **config_dirs,
const char *replacement,
char ***files,
char **replace_file) {
_cleanup_strv_free_ char **f = NULL;
_cleanup_free_ char *p = NULL;
int r;
assert(config_dirs);
assert(files);
assert(replace_file || !replacement);
r = conf_files_list_strv(&f, ".conf", root, 0, (const char* const*) config_dirs);
if (r < 0)
return log_error_errno(r, "Failed to enumerate config files: %m");
if (replacement) {
r = conf_files_insert(&f, root, config_dirs, replacement);
if (r < 0)
return log_error_errno(r, "Failed to extend config file list: %m");
p = path_join(root, replacement, NULL);
if (!p)
return log_oom();
}
*files = TAKE_PTR(f);
if (replace_file)
*replace_file = TAKE_PTR(p);
return 0;
}
int conf_files_cat(const char *root, const char *name) {
_cleanup_strv_free_ char **dirs = NULL, **files = NULL;
_cleanup_free_ char *path = 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", root, 0, (const char* const*) dirs);
if (r < 0)
return log_error_errno(r, "Failed to query file list: %m");
path = path_join(root, "/etc", name);
if (!path)
return log_oom();
if (DEBUG_LOGGING) {
log_debug("Looking for configuration in:");
log_debug(" %s", path);
STRV_FOREACH(t, dirs)
log_debug(" %s/*.conf", *t);
}
/* show */
return cat_files(path, files, CAT_FLAGS_MAIN_FILE_OPTIONAL);
}

View file

@ -17,3 +17,10 @@ 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_list_with_replacement(
const char *root,
char **config_dirs,
const char *replacement,
char ***files,
char **replace_file);
int conf_files_cat(const char *root, const char *name);

View file

@ -54,8 +54,10 @@
#define NOTIFY_BUFFER_MAX PIPE_BUF
#if HAVE_SPLIT_USR
# define _CONF_PATHS_SPLIT_USR(n) "/lib/" n "\0"
# define _CONF_PATHS_SPLIT_USR_NULSTR(n) "/lib/" n "\0"
# define _CONF_PATHS_SPLIT_USR(n) , "/lib/" n
#else
# define _CONF_PATHS_SPLIT_USR_NULSTR(n)
# define _CONF_PATHS_SPLIT_USR(n)
#endif
@ -68,6 +70,14 @@
"/run/" n "\0" \
"/usr/local/lib/" n "\0" \
"/usr/lib/" n "\0" \
_CONF_PATHS_SPLIT_USR(n)
_CONF_PATHS_SPLIT_USR_NULSTR(n)
#define CONF_PATHS_STRV(n) \
STRV_MAKE( \
"/etc/" n, \
"/run/" n, \
"/usr/local/lib/" n, \
"/usr/lib/" n \
_CONF_PATHS_SPLIT_USR(n))
#define LONG_LINE_MAX (1U*1024U*1024U)

View file

@ -28,6 +28,8 @@
#include <unistd.h>
#include "alloc-util.h"
#include "copy.h"
#include "def.h"
#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
@ -1362,3 +1364,57 @@ int terminal_urlify_path(const char *path, const char *text, char **ret) {
return terminal_urlify(url, text, ret);
}
static int cat_file(const char *filename, bool newline) {
_cleanup_fclose_ FILE *f = NULL;
int r;
f = fopen(filename, "re");
if (!f)
return -errno;
printf("%s%s# %s%s\n",
newline ? "\n" : "",
ansi_highlight_blue(),
filename,
ansi_normal());
fflush(stdout);
for (;;) {
_cleanup_free_ char *line = NULL;
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return log_error_errno(r, "Failed to read \"%s\": %m", filename);
if (r == 0)
break;
puts(line);
}
return 0;
}
int cat_files(const char *file, char **dropins, CatFlags flags) {
char **path;
int r;
if (file) {
r = cat_file(file, false);
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);
}
STRV_FOREACH(path, dropins) {
r = cat_file(*path, file || path != dropins);
if (r < 0)
return log_warning_errno(r, "Failed to cat %s: %m", *path);
}
return 0;
}

View 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);
@ -159,3 +160,9 @@ 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);
typedef enum CatFlags {
CAT_FLAGS_MAIN_FILE_OPTIONAL = 1 << 1,
} CatFlags;
int cat_files(const char *file, char **dropins, CatFlags flags);

View file

@ -21,9 +21,10 @@
#include "log.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "util.h"
static const char conf_file_dirs[] = CONF_PATHS_NULSTR("binfmt.d");
static bool arg_cat_config = false;
static int delete_rule(const char *rule) {
_cleanup_free_ char *x = NULL, *fn = NULL;
@ -63,7 +64,7 @@ static int apply_file(const char *path, bool ignore_enoent) {
assert(path);
r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f);
r = search_and_fopen(path, "re", NULL, (const char**) CONF_PATHS_STRV("binfmt.d"), &f);
if (r < 0) {
if (ignore_enoent && r == -ENOENT)
return 0;
@ -102,6 +103,7 @@ static void help(void) {
"Registers binary formats.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --cat-config Show configuration files\n"
, program_invocation_short_name);
}
@ -109,11 +111,13 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_CAT_CONFIG,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
{}
};
@ -133,6 +137,10 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_VERSION:
return version();
case ARG_CAT_CONFIG:
arg_cat_config = true;
break;
case '?':
return -EINVAL;
@ -140,6 +148,11 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
if (arg_cat_config && argc > optind) {
log_error("Positional arguments are not allowed with --cat-config");
return -EINVAL;
}
return 1;
}
@ -170,12 +183,17 @@ int main(int argc, char *argv[]) {
_cleanup_strv_free_ char **files = NULL;
char **f;
r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) CONF_PATHS_STRV("binfmt.d"));
if (r < 0) {
log_error_errno(r, "Failed to enumerate binfmt.d files: %m");
goto finish;
}
if (arg_cat_config) {
r = cat_files(NULL, files, 0);
goto finish;
}
/* Flush out all rules */
write_string_file("/proc/sys/fs/binfmt_misc/status", "-1", 0);

View file

@ -23,11 +23,11 @@
#include "string-util.h"
#include "strv.h"
#include "sysctl-util.h"
#include "terminal-util.h"
#include "util.h"
static char **arg_prefixes = NULL;
static const char conf_file_dirs[] = CONF_PATHS_NULSTR("sysctl.d");
static bool arg_cat_config = false;
static int apply_all(OrderedHashmap *sysctl_options) {
char *property, *value;
@ -83,7 +83,7 @@ static int parse_file(OrderedHashmap *sysctl_options, const char *path, bool ign
assert(path);
r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f);
r = search_and_fopen(path, "re", NULL, (const char**) CONF_PATHS_STRV("sysctl.d"), &f);
if (r < 0) {
if (ignore_enoent && r == -ENOENT)
return 0;
@ -168,6 +168,7 @@ static void help(void) {
"Applies kernel sysctl settings.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --cat-config Show configuration files\n"
" --prefix=PATH Only apply rules with the specified prefix\n"
, program_invocation_short_name);
}
@ -176,13 +177,15 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_PREFIX
ARG_CAT_CONFIG,
ARG_PREFIX,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "prefix", required_argument, NULL, ARG_PREFIX },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
{ "prefix", required_argument, NULL, ARG_PREFIX },
{}
};
@ -202,6 +205,10 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_VERSION:
return version();
case ARG_CAT_CONFIG:
arg_cat_config = true;
break;
case ARG_PREFIX: {
char *p;
@ -231,6 +238,11 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
if (arg_cat_config && argc > optind) {
log_error("Positional arguments are not allowed with --cat-config");
return -EINVAL;
}
return 1;
}
@ -268,12 +280,17 @@ int main(int argc, char *argv[]) {
_cleanup_strv_free_ char **files = NULL;
char **f;
r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) CONF_PATHS_STRV("sysctl.d"));
if (r < 0) {
log_error_errno(r, "Failed to enumerate sysctl.d files: %m");
goto finish;
}
if (arg_cat_config) {
r = cat_files(NULL, files, 0);
goto finish;
}
STRV_FOREACH(f, files) {
k = parse_file(sysctl_options, *f, true);
if (k < 0 && r == 0)

View file

@ -5314,23 +5314,6 @@ static int show(int argc, char *argv[], void *userdata) {
return ret;
}
static int cat_file(const char *filename, bool newline) {
_cleanup_close_ int fd;
fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return -errno;
printf("%s%s# %s%s\n",
newline ? "\n" : "",
ansi_highlight_blue(),
filename,
ansi_normal());
fflush(stdout);
return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0);
}
static int cat(int argc, char *argv[], void *userdata) {
_cleanup_(lookup_paths_free) LookupPaths lp = {};
_cleanup_strv_free_ char **names = NULL;
@ -5361,7 +5344,6 @@ static int cat(int argc, char *argv[], void *userdata) {
STRV_FOREACH(name, names) {
_cleanup_free_ char *fragment_path = NULL;
_cleanup_strv_free_ char **dropin_paths = NULL;
char **path;
r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
if (r < 0)
@ -5388,17 +5370,9 @@ static int cat(int argc, char *argv[], void *userdata) {
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
ansi_normal());
if (fragment_path) {
r = cat_file(fragment_path, false);
if (r < 0)
return log_warning_errno(r, "Failed to cat %s: %m", fragment_path);
}
STRV_FOREACH(path, dropin_paths) {
r = cat_file(*path, path == dropin_paths);
if (r < 0)
return log_warning_errno(r, "Failed to cat %s: %m", *path);
}
r = cat_files(fragment_path, dropin_paths, 0);
if (r < 0)
return r;
}
return 0;

View file

@ -23,6 +23,7 @@
#include "specifier.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "uid-range.h"
#include "user-util.h"
#include "utf8.h"
@ -61,11 +62,10 @@ typedef struct Item {
} Item;
static char *arg_root = NULL;
static bool arg_cat_config = false;
static const char *arg_replace = NULL;
static bool arg_inline = false;
static const char conf_file_dirs[] = CONF_PATHS_NULSTR("sysusers.d");
static OrderedHashmap *users = NULL, *groups = NULL;
static OrderedHashmap *todo_uids = NULL, *todo_gids = NULL;
static OrderedHashmap *members = NULL;
@ -1688,7 +1688,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
if (streq(fn, "-"))
f = stdin;
else {
r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &rf);
r = search_and_fopen(fn, "re", arg_root, (const char**) CONF_PATHS_STRV("sysusers.d"), &rf);
if (r < 0) {
if (ignore_enoent && r == -ENOENT)
return 0;
@ -1744,11 +1744,24 @@ static void free_database(Hashmap *by_name, Hashmap *by_id) {
hashmap_free(by_id);
}
static int cat_config(void) {
_cleanup_strv_free_ char **files = NULL;
_cleanup_free_ char *replace_file = NULL;
int r;
r = conf_files_list_with_replacement(arg_root, CONF_PATHS_STRV("sysusers.d"), arg_replace, &files, NULL);
if (r < 0)
return r;
return cat_files(NULL, files, 0);
}
static void help(void) {
printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
"Creates system user accounts.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --cat-config Show configuration files\n"
" --root=PATH Operate on an alternate filesystem root\n"
" --replace=PATH Treat arguments as replacement for PATH\n"
" --inline Treat arguments as configuration lines\n"
@ -1759,17 +1772,19 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_CAT_CONFIG,
ARG_ROOT,
ARG_REPLACE,
ARG_INLINE,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "root", required_argument, NULL, ARG_ROOT },
{ "replace", required_argument, NULL, ARG_REPLACE },
{ "inline", no_argument, NULL, ARG_INLINE },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
{ "root", required_argument, NULL, ARG_ROOT },
{ "replace", required_argument, NULL, ARG_REPLACE },
{ "inline", no_argument, NULL, ARG_INLINE },
{}
};
@ -1789,6 +1804,10 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_VERSION:
return version();
case ARG_CAT_CONFIG:
arg_cat_config = true;
break;
case ARG_ROOT:
r = parse_path_argument_and_warn(optarg, true, &arg_root);
if (r < 0)
@ -1816,6 +1835,11 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
if (arg_replace && arg_cat_config) {
log_error("Option --replace= is not supported with --cat-config");
return -EINVAL;
}
if (arg_replace && optind >= argc) {
log_error("When --replace= is given, some configuration items must be specified");
return -EINVAL;
@ -1844,25 +1868,15 @@ static int parse_arguments(char **args) {
return 0;
}
static int read_config_files(const char* dirs, char **args) {
static int read_config_files(char **args) {
_cleanup_strv_free_ char **files = NULL;
_cleanup_free_ char *p = NULL;
char **f;
int r;
r = conf_files_list_nulstr(&files, ".conf", arg_root, 0, dirs);
r = conf_files_list_with_replacement(arg_root, CONF_PATHS_STRV("sysusers.d"), arg_replace, &files, &p);
if (r < 0)
return log_error_errno(r, "Failed to enumerate sysusers.d files: %m");
if (arg_replace) {
r = conf_files_insert_nulstr(&files, arg_root, dirs, arg_replace);
if (r < 0)
return log_error_errno(r, "Failed to extend sysusers.d file list: %m");
p = path_join(arg_root, arg_replace, NULL);
if (!p)
return log_oom();
}
return r;
STRV_FOREACH(f, files)
if (p && path_equal(*f, p)) {
@ -1882,7 +1896,6 @@ static int read_config_files(const char* dirs, char **args) {
}
int main(int argc, char *argv[]) {
_cleanup_close_ int lock = -1;
Iterator iterator;
int r;
@ -1897,6 +1910,11 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
if (arg_cat_config) {
r = cat_config();
goto finish;
}
umask(0022);
r = mac_selinux_init();
@ -1912,7 +1930,7 @@ int main(int argc, char *argv[]) {
* read configuration and execute it.
*/
if (arg_replace || optind >= argc)
r = read_config_files(conf_file_dirs, argv + optind);
r = read_config_files(argv + optind);
else
r = parse_arguments(argv + optind);
if (r < 0)

View file

@ -14,6 +14,7 @@
#include "fileio.h"
#include "log.h"
#include "macro.h"
#include "strv.h"
#include "terminal-util.h"
#include "util.h"
@ -76,6 +77,14 @@ static void test_terminal_urlify(void) {
printf("Or click on %s to have a look at it!\n", formatted);
}
static void test_cat_files(void) {
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) == 0);
}
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@ -83,6 +92,7 @@ int main(int argc, char *argv[]) {
test_default_term_for_tty();
test_read_one_char();
test_terminal_urlify();
test_cat_files();
return 0;
}

View file

@ -60,6 +60,7 @@
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "umask-util.h"
#include "user-util.h"
#include "util.h"
@ -149,6 +150,7 @@ typedef enum DirectoryType {
_DIRECTORY_TYPE_MAX,
} DirectoryType;
static bool arg_cat_config = false;
static bool arg_user = false;
static bool arg_create = false;
static bool arg_clean = false;
@ -2441,12 +2443,24 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
return 0;
}
static int cat_config(char **config_dirs, char **args) {
_cleanup_strv_free_ char **files = NULL;
int r;
r = conf_files_list_with_replacement(arg_root, config_dirs, arg_replace, &files, NULL);
if (r < 0)
return r;
return cat_files(NULL, files, 0);
}
static void help(void) {
printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
"Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
" -h --help Show this help\n"
" --user Execute user configuration\n"
" --version Show package version\n"
" --cat-config Show configuration files\n"
" --create Create marked files/directories\n"
" --clean Clean up marked directories\n"
" --remove Remove marked files/directories\n"
@ -2462,6 +2476,7 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_CAT_CONFIG,
ARG_USER,
ARG_CREATE,
ARG_CLEAN,
@ -2477,6 +2492,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "help", no_argument, NULL, 'h' },
{ "user", no_argument, NULL, ARG_USER },
{ "version", no_argument, NULL, ARG_VERSION },
{ "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
{ "create", no_argument, NULL, ARG_CREATE },
{ "clean", no_argument, NULL, ARG_CLEAN },
{ "remove", no_argument, NULL, ARG_REMOVE },
@ -2504,6 +2520,10 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_VERSION:
return version();
case ARG_CAT_CONFIG:
arg_cat_config = true;
break;
case ARG_USER:
arg_user = true;
break;
@ -2557,11 +2577,16 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
if (!arg_clean && !arg_create && !arg_remove) {
if (!arg_clean && !arg_create && !arg_remove && !arg_cat_config) {
log_error("You need to specify at least one of --clean, --create or --remove.");
return -EINVAL;
}
if (arg_replace && arg_cat_config) {
log_error("Option --replace= is not supported with --cat-config");
return -EINVAL;
}
if (arg_replace && optind >= argc) {
log_error("When --replace= is given, some configuration items must be specified");
return -EINVAL;
@ -2677,19 +2702,9 @@ static int read_config_files(char **config_dirs, char **args, bool *invalid_conf
char **f;
int r;
r = conf_files_list_strv(&files, ".conf", arg_root, 0, (const char* const*) config_dirs);
r = conf_files_list_with_replacement(arg_root, config_dirs, arg_replace, &files, &p);
if (r < 0)
return log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
if (arg_replace) {
r = conf_files_insert(&files, arg_root, config_dirs, arg_replace);
if (r < 0)
return log_error_errno(r, "Failed to extend tmpfiles.d file list: %m");
p = path_join(arg_root, arg_replace, NULL);
if (!p)
return log_oom();
}
return r;
STRV_FOREACH(f, files)
if (p && path_equal(*f, p)) {
@ -2721,20 +2736,6 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
umask(0022);
mac_selinux_init();
items = ordered_hashmap_new(&string_hash_ops);
globs = ordered_hashmap_new(&string_hash_ops);
if (!items || !globs) {
r = log_oom();
goto finish;
}
r = 0;
if (arg_user) {
r = user_config_paths(&config_dirs);
if (r < 0) {
@ -2757,6 +2758,23 @@ int main(int argc, char *argv[]) {
log_debug("Looking for configuration files in (higher priority first):\n\t%s", t);
}
if (arg_cat_config) {
r = cat_config(config_dirs, argv + optind);
goto finish;
}
umask(0022);
mac_selinux_init();
items = ordered_hashmap_new(&string_hash_ops);
globs = ordered_hashmap_new(&string_hash_ops);
if (!items || !globs) {
r = log_oom();
goto finish;
}
/* If command line arguments are specified along with --replace, read all
* configuration files and insert the positional arguments at the specified
* place. Otherwise, if command line arguments are specified, execute just