Blob Blame History Raw
From 14f32b5e62d7f0973302080488a0f0fce897b2d0 Mon Sep 17 00:00:00 2001
From: Michael Marineau <michael.marineau@coreos.com>
Date: Thu, 13 Mar 2014 21:32:13 -0700
Subject: [PATCH] tmpfiles: add --root option to operate on an alternate fs
 tree

This makes it possible to initialize or cleanup an arbitrary filesystem
hierarchy in the same way that it would be during system boot.

Conflicts:
	src/tmpfiles/tmpfiles.c

(cherry picked from commit cf9a4abdc24c43565d0890fcb88c00169057c0c4)

Resolves: #1111199
---
 man/systemd-tmpfiles.xml | 12 ++++++++++--
 src/tmpfiles/tmpfiles.c  | 29 +++++++++++++++++++++++++----
 2 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml
index 64f9cf9..8d1db16 100644
--- a/man/systemd-tmpfiles.xml
+++ b/man/systemd-tmpfiles.xml
@@ -139,19 +139,27 @@
                                 </para></listitem>
                         </varlistentry>
                         <varlistentry>
-                                <term><option>--prefix=PATH</option></term>
+                                <term><option>--prefix=<replaceable>path</replaceable></option></term>
                                 <listitem><para>Only apply rules that
                                 apply to paths with the specified
                                 prefix. This option can be specified
                                 multiple times.</para></listitem>
                         </varlistentry>
                         <varlistentry>
-                                <term><option>--exclude-prefix=PATH</option></term>
+                                <term><option>--exclude-prefix=<replaceable>path</replaceable></option></term>
                                 <listitem><para>Ignore rules that
                                 apply to paths with the specified
                                 prefix. This option can be specified
                                 multiple times.</para></listitem>
                         </varlistentry>
+                        <varlistentry>
+                                <term><option>--root=<replaceable>root</replaceable></option></term>
+                                <listitem><para>Takes a directory path
+                                as an argument. All paths will be
+                                prefixed with the given alternate <replaceable>root</replaceable>
+                                path, including config search paths.
+                                </para></listitem>
+                        </varlistentry>
 
 
                         <varlistentry>
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 1337d02..ff51062 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -110,6 +110,7 @@ static bool arg_boot = false;
 
 static char **include_prefixes = NULL;
 static char **exclude_prefixes = NULL;
+static char *arg_root = NULL;
 
 static const char conf_file_dirs[] =
         "/etc/tmpfiles.d\0"
@@ -1186,6 +1187,15 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (!should_include_path(i->path))
                 return 0;
 
+        if (arg_root) {
+                char *p = strappend(arg_root, i->path);
+                if (!p)
+                        return log_oom();
+
+                free(i->path);
+                i->path = p;
+        }
+
         if (user && !streq(user, "-")) {
                 const char *u = user;
 
@@ -1274,7 +1284,8 @@ static int help(void) {
                "     --remove               Remove marked files/directories\n"
                "     --boot                 Execute actions only safe at boot\n"
                "     --prefix=PATH          Only apply rules that apply to paths with the specified prefix\n"
-               "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n",
+               "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n"
+               "     --root=PATH            Operate on an alternate filesystem root\n",
                program_invocation_short_name);
 
         return 0;
@@ -1289,6 +1300,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_BOOT,
                 ARG_PREFIX,
                 ARG_EXCLUDE_PREFIX,
+                ARG_ROOT,
         };
 
         static const struct option options[] = {
@@ -1299,7 +1311,8 @@ static int parse_argv(int argc, char *argv[]) {
                 { "boot",           no_argument,         NULL, ARG_BOOT           },
                 { "prefix",         required_argument,   NULL, ARG_PREFIX         },
                 { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
-                { NULL,             0,                   NULL, 0                  }
+                { "root",           required_argument,   NULL, ARG_ROOT           },
+                {}
         };
 
         int c;
@@ -1341,6 +1354,13 @@ static int parse_argv(int argc, char *argv[]) {
                                 return log_oom();
                         break;
 
+                case ARG_ROOT:
+                        arg_root = path_make_absolute_cwd(optarg);
+                        if (!arg_root)
+                                return log_oom();
+                        path_kill_slashes(arg_root);
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -1368,7 +1388,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
 
         assert(fn);
 
-        r = search_and_fopen_nulstr(fn, "re", NULL, conf_file_dirs, &f);
+        r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
         if (r < 0) {
                 if (ignore_enoent && r == -ENOENT)
                         return 0;
@@ -1469,7 +1489,7 @@ int main(int argc, char *argv[]) {
                 _cleanup_strv_free_ char **files = NULL;
                 char **f;
 
-                r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
+                r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
                 if (r < 0) {
                         log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
                         goto finish;
@@ -1500,6 +1520,7 @@ finish:
 
         free(include_prefixes);
         free(exclude_prefixes);
+        free(arg_root);
 
         set_free_free(unix_sockets);