From 6bf35513c34d3fc3e74b749c4a39c87344399757 Mon Sep 17 00:00:00 2001 From: Aaron Andersen Date: Fri, 16 Jan 2026 16:42:09 -0500 Subject: [PATCH] tmpfiles: add support for config files on command line Allow specifying one or more configuration files as command line arguments instead of always processing all files in the standard tmpfiles.d directories. This enables targeted operations on specific config files: tmpfiles --create /etc/tmpfiles.d/myapp.conf tmpfiles --clean /tmp/test.conf /tmp/other.conf When no config files are specified, the existing behavior of processing all *.conf files in the standard directories is preserved. Also refactors file processing into a helper function to reduce code duplication. --- src/tmpfiles.c | 61 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/src/tmpfiles.c b/src/tmpfiles.c index 8e410aaf..3e307162 100644 --- a/src/tmpfiles.c +++ b/src/tmpfiles.c @@ -635,17 +635,44 @@ static void tmpfiles(char *line) warn("Failed %s operation on path %s", type, path); } +static void process_file(const char *fn) +{ + FILE *fp; + + fp = fopen(fn, "r"); + if (!fp) { + warn("Failed to open %s", fn); + return; + } + + while (!feof(fp)) { + char *line; + + line = fparseln(fp, NULL, NULL, NULL, FPARSELN_UNESCCOMM); + if (!line) + continue; + + tmpfiles(line); + free(line); + } + + fclose(fp); +} + static int usage(int rc) { fprintf(stderr, - "Usage: tmpfiles [COMMAND...]\n" + "Usage: tmpfiles [OPTIONS] [CONFIGFILE...]\n" "\n" - "Commands:\n" + "Options:\n" " -C, --clean Clean files and directories based on age\n" " -c, --create Create files and directories\n" " -d, --debug Show developer debug messages\n" " -r, --remove Remove files and directories marked for removal\n" " -h, --help This help text\n" + "\n" + "If no CONFIGFILE is specified, all *.conf files in the standard\n" + "tmpfiles.d directories are processed.\n" "\n"); return rc; @@ -696,7 +723,16 @@ int main(int argc, char *argv[]) return 1; } + /* If config files specified on command line, process only those */ + if (optind < argc) { + for (int i = optind; i < argc; i++) + process_file(argv[i]); + return 0; + } + /* + * No config files specified, process standard tmpfiles.d directories. + * * Only the three last tmpfiles.d/ directories are defined in * tmpfiles.d(5) as system search paths. Finit adds two more * before that to have Finit specific ones sorted first, and @@ -723,7 +759,6 @@ int main(int argc, char *argv[]) for (i = 0; i < gl.gl_pathc; i++) { char *fn = gl.gl_pathv[i]; size_t j; - FILE *fp; /* check for overrides */ for (j = i + 1; j < gl.gl_pathc; j++) { @@ -736,26 +771,12 @@ int main(int argc, char *argv[]) if (!fn) continue; /* skip, override exists */ - fp = fopen(fn, "r"); - if (!fp) - continue; - -// info("Parsing %s ...", fn); - while (!feof(fp)) { - char *line; - - line = fparseln(fp, NULL, NULL, NULL, FPARSELN_UNESCCOMM); - if (!line) - continue; - - tmpfiles(line); - free(line); - } - - fclose(fp); + process_file(fn); } globfree(&gl); + + return 0; } /**