[systemd-devel] [RFC/PATCH] tmpfiles: implement --transform=rpm

Zbigniew Jędrzejewski-Szmek zbyszek at in.waw.pl
Sat Mar 1 18:06:14 PST 2014


---

I'm not sure if this can be actually as useful as I envisioned. At
least in case of systemd.spec there's a lot of special-casing
required, which partially destroys the usefulness of this. Configuration
for "normal" packages will hopefully be more straighforward.

I made the switch name generic, so that other "transforms" can
be added later without complicating the command-line api.

Zbyszek

 src/tmpfiles/tmpfiles.c | 144 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 107 insertions(+), 37 deletions(-)

diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 6e36dc7..008bc16 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -101,6 +101,10 @@ typedef struct Item {
         bool keep_first_level:1;
 } Item;
 
+enum {
+        TRANSFORM_RPM = 1,
+};
+
 static Hashmap *items = NULL, *globs = NULL;
 static Set *unix_sockets = NULL;
 
@@ -108,6 +112,7 @@ static bool arg_create = false;
 static bool arg_clean = false;
 static bool arg_remove = false;
 static bool arg_boot = false;
+static int arg_transform = 0;
 
 static char **include_prefixes = NULL;
 static char **exclude_prefixes = NULL;
@@ -125,7 +130,13 @@ static const char conf_file_dirs[] =
 #define MAX_DEPTH 256
 
 static bool needs_glob(ItemType t) {
-        return t == IGNORE_PATH || t == IGNORE_DIRECTORY_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
+        return IN_SET(t,
+                      IGNORE_PATH,
+                      IGNORE_DIRECTORY_PATH,
+                      REMOVE_PATH,
+                      RECURSIVE_REMOVE_PATH,
+                      RELABEL_PATH,
+                      RECURSIVE_RELABEL_PATH);
 }
 
 static struct Item* find_glob(Hashmap *h, const char *match) {
@@ -972,22 +983,55 @@ static int clean_item(Item *i) {
         return r;
 }
 
+static int transform_item(Item *i, int transform) {
+        assert(i);
+        assert(transform == TRANSFORM_RPM);
+
+        switch (i->type) {
+
+        case IGNORE_PATH:
+        case IGNORE_DIRECTORY_PATH:
+        case REMOVE_PATH:
+        case RECURSIVE_REMOVE_PATH:
+        case ADJUST_MODE:
+        case TRUNCATE_DIRECTORY:
+        case RELABEL_PATH:
+        case RECURSIVE_RELABEL_PATH:
+                log_debug("%s ignored.", i->path);
+                return 0;
+
+        case CREATE_FILE:
+        case TRUNCATE_FILE:
+        case WRITE_FILE:
+        case CREATE_FIFO:
+        case CREATE_SYMLINK:
+        case CREATE_BLOCK_DEVICE:
+        case CREATE_CHAR_DEVICE:
+                printf("%%ghost %s\n", i->path);
+                break;
+
+        case CREATE_DIRECTORY:
+                printf("%%ghost %%dir %s\n", i->path);
+                break;
+        }
+
+        return 0;
+}
+
 static int process_item(Item *i) {
-        int r, q, p;
+        int r, q, p, s;
 
         assert(i);
 
         r = arg_create ? create_item(i) : 0;
         q = arg_remove ? remove_item(i) : 0;
         p = arg_clean ? clean_item(i) : 0;
+        s = arg_transform ? transform_item(i, arg_transform) : 0;
 
-        if (r < 0)
-                return r;
-
-        if (q < 0)
-                return q;
-
-        return p;
+        return r < 0 ? r :
+                q < 0 ? q :
+                p < 0 ? p :
+                s;
 }
 
 static void item_free(Item *i) {
@@ -1270,14 +1314,15 @@ static int 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"
-               "     --version              Show package version\n"
-               "     --create               Create marked files/directories\n"
-               "     --clean                Clean up marked directories\n"
-               "     --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",
+               "  -h --help                Show this help\n"
+               "     --version             Show package version\n"
+               "     --create              Create marked files/directories\n"
+               "     --clean               Clean up marked directories\n"
+               "     --remove              Remove marked files/directories\n"
+               "     --boot                Execute actions only safe at boot\n"
+               "     --transform=rpm       Create files list suitable for RPM %%files section\n"
+               "     --prefix=PATH         Only apply rules that match the specified prefix\n"
+               "     --exclude-prefix=PATH Ignore rules that match the specified prefix\n",
                program_invocation_short_name);
 
         return 0;
@@ -1291,19 +1336,21 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_CLEAN,
                 ARG_REMOVE,
                 ARG_BOOT,
+                ARG_TRANSFORM,
                 ARG_PREFIX,
                 ARG_EXCLUDE_PREFIX,
         };
 
         static const struct option options[] = {
-                { "help",           no_argument,         NULL, 'h'                },
-                { "version",        no_argument,         NULL, ARG_VERSION        },
-                { "create",         no_argument,         NULL, ARG_CREATE         },
-                { "clean",          no_argument,         NULL, ARG_CLEAN          },
-                { "remove",         no_argument,         NULL, ARG_REMOVE         },
-                { "boot",           no_argument,         NULL, ARG_BOOT           },
-                { "prefix",         required_argument,   NULL, ARG_PREFIX         },
-                { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
+                { "help",             no_argument,       NULL, 'h'                },
+                { "version",          no_argument,       NULL, ARG_VERSION        },
+                { "create",           no_argument,       NULL, ARG_CREATE         },
+                { "clean",            no_argument,       NULL, ARG_CLEAN          },
+                { "remove",           no_argument,       NULL, ARG_REMOVE         },
+                { "transform",        required_argument, NULL, ARG_TRANSFORM      },
+                { "boot",             no_argument,       NULL, ARG_BOOT           },
+                { "prefix",           required_argument, NULL, ARG_PREFIX         },
+                { "exclude-prefix",   required_argument, NULL, ARG_EXCLUDE_PREFIX },
                 {}
         };
 
@@ -1336,6 +1383,16 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_remove = true;
                         break;
 
+                case ARG_TRANSFORM:
+                        if (streq(optarg, "rpm")) {
+                                arg_transform = TRANSFORM_RPM;
+                                arg_boot = true;
+                        } else {
+                                log_error("Unknown transformation '%s'", optarg);
+                                return -EINVAL;
+                        }
+                        break;
+
                 case ARG_BOOT:
                         arg_boot = true;
                         break;
@@ -1358,31 +1415,44 @@ static int parse_argv(int argc, char *argv[]) {
                 }
         }
 
-        if (!arg_clean && !arg_create && !arg_remove) {
-                log_error("You need to specify at least one of --clean, --create or --remove.");
+        if ((arg_clean || arg_create || arg_remove) + !!arg_transform != 1) {
+                log_error("You must specify at least one of --clean/--create/--remove, or only --transform.");
+                return -EINVAL;
+        }
+
+        if (arg_transform && optind >= argc) {
+                log_error("Configuration file must be specified with --transform");
                 return -EINVAL;
         }
 
         return 1;
 }
 
-static int read_config_file(const char *fn, bool ignore_enoent) {
+static int read_config_file(const char *fn, bool ignore_enoent, bool real_path) {
         _cleanup_fclose_ FILE *f = NULL;
         char line[LINE_MAX];
         Iterator iterator;
         unsigned v = 0;
         Item *i;
-        int r;
+        int r = 0;
 
         assert(fn);
 
-        r = search_and_fopen_nulstr(fn, "re", conf_file_dirs, &f);
-        if (r < 0) {
-                if (ignore_enoent && r == -ENOENT)
-                        return 0;
+        if (real_path) {
+                f = fopen(fn, "re");
+                if (!f) {
+                        log_error("Failed to open '%s': %m", fn);
+                        return -errno;
+                }
+        } else {
+                r = search_and_fopen_nulstr(fn, "re", conf_file_dirs, &f);
+                if (r < 0) {
+                        if (ignore_enoent && r == -ENOENT)
+                                return 0;
 
-                log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
-                return r;
+                        log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
+                        return r;
+                }
         }
 
         FOREACH_LINE(line, f, break) {
@@ -1468,7 +1538,7 @@ int main(int argc, char *argv[]) {
                 int j;
 
                 for (j = optind; j < argc; j++) {
-                        k = read_config_file(argv[j], false);
+                        k = read_config_file(argv[j], false, !!arg_transform);
                         if (k < 0 && r == 0)
                                 r = k;
                 }
@@ -1484,7 +1554,7 @@ int main(int argc, char *argv[]) {
                 }
 
                 STRV_FOREACH(f, files) {
-                        k = read_config_file(*f, true);
+                        k = read_config_file(*f, true, false);
                         if (k < 0 && r == 0)
                                 r = k;
                 }
-- 
1.8.5.3



More information about the systemd-devel mailing list