chiark / gitweb /
tmpfiles: introduce --exclude-prefix
[elogind.git] / src / tmpfiles / tmpfiles.c
index 4e2519d1b543d2e5ff82e932c30c5441190ce97a..5eca82ad26c423c3ca7320eb20eecb9e98c83de6 100644 (file)
@@ -105,7 +105,8 @@ static bool arg_create = false;
 static bool arg_clean = false;
 static bool arg_remove = false;
 
-static const char *arg_prefix = NULL;
+static char **include_prefixes = NULL;
+static char **exclude_prefixes = NULL;
 
 static const char conf_file_dirs[] =
         "/etc/tmpfiles.d\0"
@@ -135,7 +136,7 @@ static struct Item* find_glob(Hashmap *h, const char *match) {
 }
 
 static void load_unix_sockets(void) {
-        FILE _cleanup_fclose_ *f = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
         char line[LINE_MAX];
 
         if (unix_sockets)
@@ -186,13 +187,9 @@ static void load_unix_sockets(void) {
 
                 path_kill_slashes(s);
 
-                k = set_put(unix_sockets, s);
-                if (k < 0) {
-                        free(s);
-
-                        if (k != -EEXIST)
-                                goto fail;
-                }
+                k = set_consume(unix_sockets, s);
+                if (k < 0 && k != -EEXIST)
+                        goto fail;
         }
 
         return;
@@ -269,7 +266,7 @@ static int dir_cleanup(
         while ((dent = readdir(d))) {
                 struct stat s;
                 usec_t age;
-                char _cleanup_free_ *sub_path = NULL;
+                _cleanup_free_ char *sub_path = NULL;
 
                 if (streq(dent->d_name, ".") ||
                     streq(dent->d_name, ".."))
@@ -321,7 +318,7 @@ static int dir_cleanup(
                         if (maxdepth <= 0)
                                 log_warning("Reached max depth on %s.", sub_path);
                         else {
-                                DIR _cleanup_closedir_ *sub_dir;
+                                _cleanup_closedir_ DIR *sub_dir;
                                 int q;
 
                                 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
@@ -515,7 +512,7 @@ static int write_one_file(Item *i, const char *path) {
 }
 
 static int recursive_relabel_children(Item *i, const char *path) {
-        DIR _cleanup_closedir_ *d;
+        _cleanup_closedir_ DIR *d;
         int ret = 0;
 
         /* This returns the first error we run into, but nevertheless
@@ -530,7 +527,7 @@ static int recursive_relabel_children(Item *i, const char *path) {
                 union dirent_storage buf;
                 bool is_dir;
                 int r;
-                char _cleanup_free_ *entry_path = NULL;
+                _cleanup_free_ char *entry_path = NULL;
 
                 r = readdir_r(d, &buf.de, &de);
                 if (r != 0) {
@@ -601,14 +598,12 @@ static int recursive_relabel(Item *i, const char *path) {
 
 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
         int r = 0, k;
-        glob_t g;
+        _cleanup_globfree_ glob_t g = {};
         char **fn;
 
-        zero(g);
-
         errno = 0;
-        if ((k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g)) != 0) {
-
+        k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
+        if (k != 0)
                 if (k != GLOB_NOMATCH) {
                         if (errno > 0)
                                 errno = EIO;
@@ -616,13 +611,13 @@ static int glob_item(Item *i, int (*action)(Item *, const char *)) {
                         log_error("glob(%s) failed: %m", i->path);
                         return -errno;
                 }
-        }
 
-        STRV_FOREACH(fn, g.gl_pathv)
-                if ((k = action(i, *fn)) < 0)
+        STRV_FOREACH(fn, g.gl_pathv) {
+                k = action(i, *fn);
+                if (k < 0)
                         r = k;
+        }
 
-        globfree(&g);
         return r;
 }
 
@@ -745,7 +740,7 @@ static int create_item(Item *i) {
 
                 if (have_effective_cap(CAP_MKNOD) == 0) {
                         /* In a container we lack CAP_MKNOD. We
-                        shouldnt attempt to create the device node in
+                        shouldn't attempt to create the device node in
                         that case to avoid noise, and we don't support
                         virtualized devices in containers anyway. */
 
@@ -789,7 +784,7 @@ static int create_item(Item *i) {
 
                 r = glob_item(i, item_set_perms);
                 if (r < 0)
-                        return 0;
+                        return r;
                 break;
 
         case RECURSIVE_RELABEL_PATH:
@@ -881,7 +876,7 @@ static int remove_item(Item *i) {
 }
 
 static int clean_item_instance(Item *i, const char* instance) {
-        DIR _cleanup_closedir_ *d = NULL;
+        _cleanup_closedir_ DIR *d = NULL;
         struct stat s, ps;
         bool mountpoint;
         int r;
@@ -977,6 +972,12 @@ static void item_free(Item *i) {
         free(i);
 }
 
+static inline void item_freep(Item **i) {
+        if (*i)
+                item_free(*i);
+}
+#define _cleanup_item_free_ _cleanup_(item_freep)
+
 static bool item_equal(Item *a, Item *b) {
         assert(a);
         assert(b);
@@ -1018,10 +1019,28 @@ static bool item_equal(Item *a, Item *b) {
         return true;
 }
 
+static bool should_include_path(const char *path) {
+        char **prefix;
+
+        STRV_FOREACH(prefix, exclude_prefixes) {
+                if (path_startswith(path, *prefix))
+                        return false;
+        }
+
+        STRV_FOREACH(prefix, include_prefixes) {
+                if (path_startswith(path, *prefix))
+                        return true;
+        }
+
+        /* no matches, so we should include this path only if we
+         * have no whitelist at all */
+        return strv_length(include_prefixes) == 0;
+}
+
 static int parse_line(const char *fname, unsigned line, const char *buffer) {
-        Item _cleanup_free_ *i = NULL;
+        _cleanup_item_free_ Item *i = NULL;
         Item *existing;
-        char _cleanup_free_
+        _cleanup_free_ char
                 *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
         char type;
         Hashmap *h;
@@ -1119,7 +1138,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
 
         path_kill_slashes(i->path);
 
-        if (arg_prefix && !path_startswith(i->path, arg_prefix))
+        if (!should_include_path(i->path))
                 return 0;
 
         if (user && !streq(user, "-")) {
@@ -1204,11 +1223,12 @@ 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"
-               "     --create           Create marked files/directories\n"
-               "     --clean            Clean up marked directories\n"
-               "     --remove           Remove marked files/directories\n"
-               "     --prefix=PATH      Only apply rules that apply to paths with the specified prefix\n",
+               "  -h --help                 Show this help\n"
+               "     --create               Create marked files/directories\n"
+               "     --clean                Clean up marked directories\n"
+               "     --remove               Remove marked files/directories\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",
                program_invocation_short_name);
 
         return 0;
@@ -1220,16 +1240,18 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_CREATE,
                 ARG_CLEAN,
                 ARG_REMOVE,
-                ARG_PREFIX
+                ARG_PREFIX,
+                ARG_EXCLUDE_PREFIX,
         };
 
         static const struct option options[] = {
-                { "help",      no_argument,       NULL, 'h'           },
-                { "create",    no_argument,       NULL, ARG_CREATE    },
-                { "clean",     no_argument,       NULL, ARG_CLEAN     },
-                { "remove",    no_argument,       NULL, ARG_REMOVE    },
-                { "prefix",    required_argument, NULL, ARG_PREFIX    },
-                { NULL,        0,                 NULL, 0             }
+                { "help",           no_argument,         NULL, 'h'                },
+                { "create",         no_argument,         NULL, ARG_CREATE         },
+                { "clean",          no_argument,         NULL, ARG_CLEAN          },
+                { "remove",         no_argument,         NULL, ARG_REMOVE         },
+                { "prefix",         required_argument,   NULL, ARG_PREFIX         },
+                { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
+                { NULL,             0,                   NULL, 0                  }
         };
 
         int c;
@@ -1258,7 +1280,13 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_PREFIX:
-                        arg_prefix = optarg;
+                        if (strv_extend(&include_prefixes, optarg) < 0)
+                                return log_oom();
+                        break;
+
+                case ARG_EXCLUDE_PREFIX:
+                        if (strv_extend(&exclude_prefixes, optarg) < 0)
+                                return log_oom();
                         break;
 
                 case '?':
@@ -1423,6 +1451,8 @@ finish:
         hashmap_free(items);
         hashmap_free(globs);
 
+        strv_free(include_prefixes);
+
         set_free_free(unix_sockets);
 
         label_finish();