tmpfiles,sysusers: rework path argument handling

Previously, if given an absolute path, we would open the file, but when given a
relative path, we'd attempt to search the directories. If the user wants to open
a file from the search path, allowing paths is very confusing. E.g. with a path
like 'sysusers/foo.conf', we'd try to open '/etc/sysusers.d/sysusers/foo.conf',
'/run/sysusers.d/sysusers/foo.conf', …, and with '../foo.conf', we'd try to open
'/etc/sysusers.d/../foo.conf', '/run/sysusers.d/../foo.conf', …. This just isn't
useful, and in fact for a scheme like sysusers.d and tmpfiles.d where there we
have a flat directory with config files, only searching for plain names can
result in success. When a user specifies a relative path, it's more likely that
they wanted to open some local file. OTOH, to correctly open a local file, e.g.
one that they're just writing, this interface is also awkward, because something
like '$PWD/file.conf' has to be used to open a file with a relative path.

This patch changes the interface so that any path (i.e. an argument with "/") is
used to open a file directly, and only plain basenames are used for searching.

(Note that tpmfiles and sysusers are somewhat special here: their "config files"
make sense without the other config and users are likely to want to test them
without the other config. I was trying to do just that when writing a spec file
for a package and attempting to convert the existing scripts to sysusers and
tmpfiles. The same logic wouldn't apply for example to units or udev rules,
because they generally can only be interpreted with the whole rest of config
also available.)
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2023-12-03 17:06:06 +01:00
parent 15d660fb41
commit ec3917d282
3 changed files with 45 additions and 26 deletions

View File

@ -40,17 +40,17 @@
<citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
<para>If invoked with no arguments, it applies all directives from all files found in the directories
<para>If invoked with no arguments, directives from the configuration files found in the directories
specified by
<citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>. When
invoked with positional arguments, if option <option>--replace=<replaceable>PATH</replaceable></option>
is specified, arguments specified on the command line are used instead of the configuration file
<replaceable>PATH</replaceable>. Otherwise, just the configuration specified by the command line
arguments is executed. The string <literal>-</literal> may be specified instead of a filename to instruct
<command>systemd-sysusers</command> to read the configuration from standard input. If the argument is a
relative path, all configuration directories are searched for a matching file and the file found that has
the highest priority is executed. If the argument is an absolute path, that file is used directly without
searching of the configuration directories.</para>
arguments is executed. If the string <literal>-</literal> is specified instead of a filename, the
configuration is read from standard input. If the argument is a file name (without any slashes), all
configuration directories are searched for a matching file and the file found that has the highest
priority is executed. If the argument is a path, that file is used directly without searching the
configuration directories for any other matching file.</para>
</refsect1>
<refsect1>

View File

@ -62,14 +62,17 @@
be invoked with one or more options <option>--create</option>, <option>--remove</option>, and
<option>--clean</option>, to select the respective subset of operations.</para>
<para>By default, directives from all configuration files are applied. When invoked with
<option>--replace=<replaceable>PATH</replaceable></option>, arguments specified on the command line are
used instead of the configuration file <replaceable>PATH</replaceable>. Otherwise, if one or more
absolute filenames are passed on the command line, only the directives in these files are applied. If
<literal>-</literal> is specified instead of a filename, directives are read from standard input. If only
the basename of a configuration file is specified, all configuration directories as specified in
<citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> are
searched for a matching file and the file found that has the highest priority is executed.</para>
<para>If invoked with no arguments, directives from the configuration files found in the directories
specified by
<citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>. When
invoked with positional arguments, if option <option>--replace=<replaceable>PATH</replaceable></option>
is specified, arguments specified on the command line are used instead of the configuration file
<replaceable>PATH</replaceable>. Otherwise, just the configuration specified by the command line
arguments is executed. If the string <literal>-</literal> is specified instead of a filename, the
configuration is read from standard input. If the argument is a file name (without any slashes), all
configuration directories are searched for a matching file and the file found that has the highest
priority is executed. If the argument is a path, that file is used directly without searching the
configuration directories for any other matching file.</para>
<para>System services (<filename>systemd-tmpfiles-setup.service</filename>,
<filename>systemd-tmpfiles-setup-dev-early.service</filename>,

View File

@ -381,8 +381,10 @@ int conf_files_list_dropins(
*
* The <fn> argument may be:
* - '-', meaning stdin.
* - a non-absolute path. In this case <config_dirs> are searched.
* - an absolute path. In this case <fn> is opened directly.
* - a file name without a path. In this case <config_dirs> are searched.
* - a path, either relative or absolute. In this case <fn> is opened directly.
*
* This method is only suitable for configuration files which have a flat layout without dropins.
*/
int conf_file_read(
const char *root,
@ -397,7 +399,7 @@ int conf_file_read(
_cleanup_free_ char *_fn = NULL;
unsigned v = 0;
FILE *f;
int r;
int r = 0;
assert(fn);
@ -407,20 +409,34 @@ int conf_file_read(
log_debug("Reading config from stdin%s", special_glyph(SPECIAL_GLYPH_ELLIPSIS));
} else if (is_path(fn)) {
r = path_make_absolute_cwd(fn, &_fn);
if (r < 0)
return log_error_errno(r, "Failed to make path absolute: %m");
fn = _fn;
f = _f = fopen(fn, "re");
if (!_f)
r = -errno;
else
log_debug("Reading config file \"%s\"%s", fn, special_glyph(SPECIAL_GLYPH_ELLIPSIS));
} else {
r = search_and_fopen(fn, "re", root, config_dirs, &_f, &_fn);
if (r == -ENOENT && ignore_enoent) {
log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn);
return 0; /* No error, but nothing happened. */
if (r >= 0) {
f = _f;
fn = _fn;
log_debug("Reading config file \"%s\"%s", fn, special_glyph(SPECIAL_GLYPH_ELLIPSIS));
}
if (r < 0)
return log_error_errno(r, "Failed to read '%s': %m", fn);
f = _f;
fn = _fn;
log_debug("Reading config file \"%s\"%s", fn, special_glyph(SPECIAL_GLYPH_ELLIPSIS));
}
if (r == -ENOENT && ignore_enoent) {
log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn);
return 0; /* No error, but nothing happened. */
}
if (r < 0)
return log_error_errno(r, "Failed to read '%s': %m", fn);
r = 1; /* We entered the part where we may modify state. */
for (;;) {