1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering, Kay Sievers
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
37 #include <sys/types.h>
38 #include <sys/param.h>
41 #include <sys/capability.h>
48 #include "path-util.h"
52 #include "conf-files.h"
53 #include "capability.h"
54 #include "specifier.h"
57 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
58 * them in the file system. This is intended to be used to create
59 * properly owned directories beneath /tmp, /var/tmp, /run, which are
60 * volatile and hence need to be recreated on bootup. */
62 typedef enum ItemType {
63 /* These ones take file names */
67 CREATE_DIRECTORY = 'd',
68 TRUNCATE_DIRECTORY = 'D',
71 CREATE_CHAR_DEVICE = 'c',
72 CREATE_BLOCK_DEVICE = 'b',
75 /* These ones take globs */
77 IGNORE_DIRECTORY_PATH = 'X',
79 RECURSIVE_REMOVE_PATH = 'R',
81 RECURSIVE_RELABEL_PATH = 'Z'
101 bool keep_first_level:1;
104 static Hashmap *items = NULL, *globs = NULL;
105 static Set *unix_sockets = NULL;
107 static bool arg_create = false;
108 static bool arg_clean = false;
109 static bool arg_remove = false;
110 static bool arg_boot = false;
112 static char **include_prefixes = NULL;
113 static char **exclude_prefixes = NULL;
114 static char *arg_root = NULL;
116 static const char conf_file_dirs[] =
119 "/usr/local/lib/tmpfiles.d\0"
120 "/usr/lib/tmpfiles.d\0"
121 #ifdef HAVE_SPLIT_USR
126 #define MAX_DEPTH 256
128 static bool needs_glob(ItemType t) {
129 return t == IGNORE_PATH || t == IGNORE_DIRECTORY_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
132 static struct Item* find_glob(Hashmap *h, const char *match) {
136 HASHMAP_FOREACH(j, h, i)
137 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
143 static void load_unix_sockets(void) {
144 _cleanup_fclose_ FILE *f = NULL;
150 /* We maintain a cache of the sockets we found in
151 * /proc/net/unix to speed things up a little. */
153 unix_sockets = set_new(string_hash_func, string_compare_func);
157 f = fopen("/proc/net/unix", "re");
162 if (!fgets(line, sizeof(line), f))
169 if (!fgets(line, sizeof(line), f))
174 p = strchr(line, ':');
182 p += strspn(p, WHITESPACE);
183 p += strcspn(p, WHITESPACE); /* skip one more word */
184 p += strspn(p, WHITESPACE);
193 path_kill_slashes(s);
195 k = set_consume(unix_sockets, s);
196 if (k < 0 && k != -EEXIST)
203 set_free_free(unix_sockets);
207 static bool unix_socket_alive(const char *fn) {
213 return !!set_get(unix_sockets, (char*) fn);
215 /* We don't know, so assume yes */
219 static int dir_is_mount_point(DIR *d, const char *subdir) {
220 struct file_handle *h;
221 int mount_id_parent, mount_id;
224 h = alloca(MAX_HANDLE_SZ);
226 h->handle_bytes = MAX_HANDLE_SZ;
227 r_p = name_to_handle_at(dirfd(d), ".", h, &mount_id_parent, 0);
231 h->handle_bytes = MAX_HANDLE_SZ;
232 r = name_to_handle_at(dirfd(d), subdir, h, &mount_id, 0);
236 /* got no handle; make no assumptions, return error */
237 if (r_p < 0 && r < 0)
240 /* got both handles; if they differ, it is a mount point */
241 if (r_p >= 0 && r >= 0)
242 return mount_id_parent != mount_id;
244 /* got only one handle; assume different mount points if one
245 * of both queries was not supported by the filesystem */
246 if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
255 static int dir_cleanup(
259 const struct stat *ds,
264 bool keep_this_level) {
267 struct timespec times[2];
268 bool deleted = false;
271 while ((dent = readdir(d))) {
274 _cleanup_free_ char *sub_path = NULL;
276 if (streq(dent->d_name, ".") ||
277 streq(dent->d_name, ".."))
280 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
284 /* FUSE, NFS mounts, SELinux might return EACCES */
286 log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
288 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
293 /* Stay on the same filesystem */
294 if (s.st_dev != rootdev)
297 /* Try to detect bind mounts of the same filesystem instance; they
298 * do not differ in device major/minors. This type of query is not
299 * supported on all kernels or filesystem types though. */
300 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
303 /* Do not delete read-only files owned by root */
304 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
307 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
312 /* Is there an item configured for this path? */
313 if (hashmap_get(items, sub_path))
316 if (find_glob(globs, sub_path))
319 if (S_ISDIR(s.st_mode)) {
322 streq(dent->d_name, "lost+found") &&
327 log_warning("Reached max depth on %s.", sub_path);
329 _cleanup_closedir_ DIR *sub_dir;
332 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
333 if (sub_dir == NULL) {
334 if (errno != ENOENT) {
335 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
342 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
348 /* Note: if you are wondering why we don't
349 * support the sticky bit for excluding
350 * directories from cleaning like we do it for
351 * other file system objects: well, the sticky
352 * bit already has a meaning for directories,
353 * so we don't want to overload that. */
358 /* Ignore ctime, we change it when deleting */
359 age = MAX(timespec_load(&s.st_mtim),
360 timespec_load(&s.st_atim));
364 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
365 log_debug("rmdir '%s'", sub_path);
367 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
368 if (errno != ENOENT && errno != ENOTEMPTY) {
369 log_error("rmdir(%s): %m", sub_path);
376 /* Skip files for which the sticky bit is
377 * set. These are semantics we define, and are
378 * unknown elsewhere. See XDG_RUNTIME_DIR
379 * specification for details. */
380 if (s.st_mode & S_ISVTX)
383 if (mountpoint && S_ISREG(s.st_mode)) {
384 if (streq(dent->d_name, ".journal") &&
388 if (streq(dent->d_name, "aquota.user") ||
389 streq(dent->d_name, "aquota.group"))
393 /* Ignore sockets that are listed in /proc/net/unix */
394 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
397 /* Ignore device nodes */
398 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
401 /* Keep files on this level around if this is
406 age = MAX3(timespec_load(&s.st_mtim),
407 timespec_load(&s.st_atim),
408 timespec_load(&s.st_ctim));
413 log_debug("unlink '%s'", sub_path);
415 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
416 if (errno != ENOENT) {
417 log_error("unlink(%s): %m", sub_path);
428 /* Restore original directory timestamps */
429 times[0] = ds->st_atim;
430 times[1] = ds->st_mtim;
432 if (futimens(dirfd(d), times) < 0)
433 log_error("utimensat(%s): %m", p);
439 static int item_set_perms_full(Item *i, const char *path, bool ignore_enoent) {
440 /* not using i->path directly because it may be a glob */
442 if (chmod(path, i->mode) < 0) {
443 if (errno != ENOENT || !ignore_enoent) {
444 log_error("chmod(%s) failed: %m", path);
449 if (i->uid_set || i->gid_set)
451 i->uid_set ? i->uid : (uid_t) -1,
452 i->gid_set ? i->gid : (gid_t) -1) < 0) {
454 if (errno != ENOENT || !ignore_enoent) {
455 log_error("chown(%s) failed: %m", path);
460 return label_fix(path, ignore_enoent, false);
463 static int item_set_perms(Item *i, const char *path) {
464 return item_set_perms_full(i, path, false);
467 static int write_one_file(Item *i, const char *path) {
473 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
474 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
477 label_context_set(path, S_IFREG);
478 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
480 label_context_clear();
485 if (i->type == WRITE_FILE && errno == ENOENT)
488 log_error("Failed to create file %s: %m", path);
495 _cleanup_free_ char *unescaped;
497 unescaped = cunescape(i->argument);
498 if (unescaped == NULL) {
503 l = strlen(unescaped);
504 n = write(fd, unescaped, l);
506 if (n < 0 || (size_t) n < l) {
507 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
509 return n < 0 ? n : -EIO;
515 if (stat(path, &st) < 0) {
516 log_error("stat(%s) failed: %m", path);
520 if (!S_ISREG(st.st_mode)) {
521 log_error("%s is not a file.", path);
525 r = item_set_perms(i, path);
532 static int recursive_relabel_children(Item *i, const char *path) {
533 _cleanup_closedir_ DIR *d;
536 /* This returns the first error we run into, but nevertheless
541 return errno == ENOENT ? 0 : -errno;
547 _cleanup_free_ char *entry_path = NULL;
551 if (!de && errno != 0) {
560 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
563 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
569 if (de->d_type == DT_UNKNOWN) {
570 r = is_dir(entry_path);
572 if (ret == 0 && errno != ENOENT)
580 dir = de->d_type == DT_DIR;
582 r = item_set_perms(i, entry_path);
584 if (ret == 0 && r != -ENOENT)
590 r = recursive_relabel_children(i, entry_path);
591 if (r < 0 && ret == 0)
599 static int recursive_relabel(Item *i, const char *path) {
603 r = item_set_perms(i, path);
607 if (lstat(path, &st) < 0)
610 if (S_ISDIR(st.st_mode))
611 r = recursive_relabel_children(i, path);
616 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
618 _cleanup_globfree_ glob_t g = {};
622 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
624 if (k != GLOB_NOMATCH) {
628 log_error("glob(%s) failed: %m", i->path);
632 STRV_FOREACH(fn, g.gl_pathv) {
641 static int create_item(Item *i) {
651 case IGNORE_DIRECTORY_PATH:
653 case RECURSIVE_REMOVE_PATH:
658 r = write_one_file(i, i->path);
664 r = glob_item(i, write_one_file);
671 r = item_set_perms_full(i, i->path, true);
677 case TRUNCATE_DIRECTORY:
678 case CREATE_DIRECTORY:
680 RUN_WITH_UMASK(0000) {
681 mkdir_parents_label(i->path, 0755);
682 r = mkdir(i->path, i->mode);
685 if (r < 0 && errno != EEXIST) {
686 log_error("Failed to create directory %s: %m", i->path);
690 if (stat(i->path, &st) < 0) {
691 log_error("stat(%s) failed: %m", i->path);
695 if (!S_ISDIR(st.st_mode)) {
696 log_error("%s is not a directory.", i->path);
700 r = item_set_perms(i, i->path);
708 RUN_WITH_UMASK(0000) {
709 r = mkfifo(i->path, i->mode);
712 if (r < 0 && errno != EEXIST) {
713 log_error("Failed to create fifo %s: %m", i->path);
717 if (stat(i->path, &st) < 0) {
718 log_error("stat(%s) failed: %m", i->path);
722 if (!S_ISFIFO(st.st_mode)) {
723 log_error("%s is not a fifo.", i->path);
727 r = item_set_perms(i, i->path);
733 case CREATE_SYMLINK: {
734 _cleanup_free_ char *x = NULL;
736 label_context_set(i->path, S_IFLNK);
737 r = symlink(i->argument, i->path);
739 label_context_clear();
742 if (r < 0 && errno != EEXIST) {
743 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
747 r = readlink_malloc(i->path, &x);
749 log_error("readlink(%s) failed: %s", i->path, strerror(-r));
753 if (!streq(i->argument, x)) {
754 log_error("%s is not the right symlinks.", i->path);
761 case CREATE_BLOCK_DEVICE:
762 case CREATE_CHAR_DEVICE: {
765 if (have_effective_cap(CAP_MKNOD) == 0) {
766 /* In a container we lack CAP_MKNOD. We
767 shouldn't attempt to create the device node in
768 that case to avoid noise, and we don't support
769 virtualized devices in containers anyway. */
771 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
775 file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
777 RUN_WITH_UMASK(0000) {
778 label_context_set(i->path, file_type);
779 r = mknod(i->path, i->mode | file_type, i->major_minor);
781 label_context_clear();
785 if (r < 0 && errno != EEXIST) {
786 log_error("Failed to create device node %s: %m", i->path);
790 if (stat(i->path, &st) < 0) {
791 log_error("stat(%s) failed: %m", i->path);
795 if ((st.st_mode & S_IFMT) != file_type) {
796 log_error("%s is not a device node.", i->path);
800 r = item_set_perms(i, i->path);
809 r = glob_item(i, item_set_perms);
814 case RECURSIVE_RELABEL_PATH:
816 r = glob_item(i, recursive_relabel);
821 log_debug("%s created successfully.", i->path);
826 static int remove_item_instance(Item *i, const char *instance) {
835 case CREATE_DIRECTORY:
838 case CREATE_BLOCK_DEVICE:
839 case CREATE_CHAR_DEVICE:
841 case IGNORE_DIRECTORY_PATH:
843 case RECURSIVE_RELABEL_PATH:
849 if (remove(instance) < 0 && errno != ENOENT) {
850 log_error("remove(%s): %m", instance);
856 case TRUNCATE_DIRECTORY:
857 case RECURSIVE_REMOVE_PATH:
858 /* FIXME: we probably should use dir_cleanup() here
859 * instead of rm_rf() so that 'x' is honoured. */
860 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
861 if (r < 0 && r != -ENOENT) {
862 log_error("rm_rf(%s): %s", instance, strerror(-r));
872 static int remove_item(Item *i) {
881 case CREATE_DIRECTORY:
884 case CREATE_CHAR_DEVICE:
885 case CREATE_BLOCK_DEVICE:
887 case IGNORE_DIRECTORY_PATH:
889 case RECURSIVE_RELABEL_PATH:
895 case TRUNCATE_DIRECTORY:
896 case RECURSIVE_REMOVE_PATH:
897 r = glob_item(i, remove_item_instance);
904 static int clean_item_instance(Item *i, const char* instance) {
905 _cleanup_closedir_ DIR *d = NULL;
916 n = now(CLOCK_REALTIME);
922 d = opendir(instance);
924 if (errno == ENOENT || errno == ENOTDIR)
927 log_error("Failed to open directory %s: %m", i->path);
931 if (fstat(dirfd(d), &s) < 0) {
932 log_error("stat(%s) failed: %m", i->path);
936 if (!S_ISDIR(s.st_mode)) {
937 log_error("%s is not a directory.", i->path);
941 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
942 log_error("stat(%s/..) failed: %m", i->path);
946 mountpoint = s.st_dev != ps.st_dev ||
947 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
949 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
950 MAX_DEPTH, i->keep_first_level);
954 static int clean_item(Item *i) {
960 case CREATE_DIRECTORY:
961 case TRUNCATE_DIRECTORY:
963 clean_item_instance(i, i->path);
965 case IGNORE_DIRECTORY_PATH:
966 r = glob_item(i, clean_item_instance);
975 static int process_item(Item *i) {
980 r = arg_create ? create_item(i) : 0;
981 q = arg_remove ? remove_item(i) : 0;
982 p = arg_clean ? clean_item(i) : 0;
993 static void item_free(Item *i) {
1001 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1002 #define _cleanup_item_free_ _cleanup_(item_freep)
1004 static bool item_equal(Item *a, Item *b) {
1008 if (!streq_ptr(a->path, b->path))
1011 if (a->type != b->type)
1014 if (a->uid_set != b->uid_set ||
1015 (a->uid_set && a->uid != b->uid))
1018 if (a->gid_set != b->gid_set ||
1019 (a->gid_set && a->gid != b->gid))
1022 if (a->mode_set != b->mode_set ||
1023 (a->mode_set && a->mode != b->mode))
1026 if (a->age_set != b->age_set ||
1027 (a->age_set && a->age != b->age))
1030 if ((a->type == CREATE_FILE ||
1031 a->type == TRUNCATE_FILE ||
1032 a->type == WRITE_FILE ||
1033 a->type == CREATE_SYMLINK) &&
1034 !streq_ptr(a->argument, b->argument))
1037 if ((a->type == CREATE_CHAR_DEVICE ||
1038 a->type == CREATE_BLOCK_DEVICE) &&
1039 a->major_minor != b->major_minor)
1045 static bool should_include_path(const char *path) {
1048 STRV_FOREACH(prefix, exclude_prefixes) {
1049 if (path_startswith(path, *prefix))
1053 STRV_FOREACH(prefix, include_prefixes) {
1054 if (path_startswith(path, *prefix))
1058 /* no matches, so we should include this path only if we
1059 * have no whitelist at all */
1060 return strv_length(include_prefixes) == 0;
1063 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1065 static const Specifier specifier_table[] = {
1066 { 'm', specifier_machine_id, NULL },
1067 { 'b', specifier_boot_id, NULL },
1068 { 'H', specifier_host_name, NULL },
1069 { 'v', specifier_kernel_release, NULL },
1073 _cleanup_item_free_ Item *i = NULL;
1076 *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1086 "%ms %ms %ms %ms %ms %ms %n",
1095 log_error("[%s:%u] Syntax error.", fname, line);
1099 if (strlen(action) > 2 || (strlen(action) > 1 && action[1] != '!')) {
1100 log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
1102 } else if (strlen(action) > 1 && !arg_boot)
1111 r = specifier_printf(path, specifier_table, NULL, &i->path);
1113 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1118 n += strspn(buffer+n, WHITESPACE);
1119 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1120 i->argument = unquote(buffer+n, "\"");
1130 case CREATE_DIRECTORY:
1131 case TRUNCATE_DIRECTORY:
1134 case IGNORE_DIRECTORY_PATH:
1136 case RECURSIVE_REMOVE_PATH:
1138 case RECURSIVE_RELABEL_PATH:
1142 case CREATE_SYMLINK:
1144 log_error("[%s:%u] Symlink file requires argument.", fname, line);
1151 log_error("[%s:%u] Write file requires argument.", fname, line);
1156 case CREATE_CHAR_DEVICE:
1157 case CREATE_BLOCK_DEVICE: {
1158 unsigned major, minor;
1161 log_error("[%s:%u] Device file requires argument.", fname, line);
1165 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1166 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1170 i->major_minor = makedev(major, minor);
1175 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1181 if (!path_is_absolute(i->path)) {
1182 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1186 path_kill_slashes(i->path);
1188 if (!should_include_path(i->path))
1192 char *p = strappend(arg_root, i->path);
1200 if (user && !streq(user, "-")) {
1201 const char *u = user;
1203 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1205 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1212 if (group && !streq(group, "-")) {
1213 const char *g = group;
1215 r = get_group_creds(&g, &i->gid);
1217 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1224 if (mode && !streq(mode, "-")) {
1227 if (sscanf(mode, "%o", &m) != 1) {
1228 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1236 i->type == CREATE_DIRECTORY ||
1237 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1239 if (age && !streq(age, "-")) {
1240 const char *a = age;
1243 i->keep_first_level = true;
1247 if (parse_sec(a, &i->age) < 0) {
1248 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1255 h = needs_glob(i->type) ? globs : items;
1257 existing = hashmap_get(h, i->path);
1260 /* Two identical items are fine */
1261 if (!item_equal(existing, i))
1262 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1267 r = hashmap_put(h, i->path, i);
1269 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1273 i = NULL; /* avoid cleanup */
1278 static int help(void) {
1280 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1281 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1282 " -h --help Show this help\n"
1283 " --version Show package version\n"
1284 " --create Create marked files/directories\n"
1285 " --clean Clean up marked directories\n"
1286 " --remove Remove marked files/directories\n"
1287 " --boot Execute actions only safe at boot\n"
1288 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1289 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1290 " --root=PATH Operate on an alternate filesystem root\n",
1291 program_invocation_short_name);
1296 static int parse_argv(int argc, char *argv[]) {
1299 ARG_VERSION = 0x100,
1309 static const struct option options[] = {
1310 { "help", no_argument, NULL, 'h' },
1311 { "version", no_argument, NULL, ARG_VERSION },
1312 { "create", no_argument, NULL, ARG_CREATE },
1313 { "clean", no_argument, NULL, ARG_CLEAN },
1314 { "remove", no_argument, NULL, ARG_REMOVE },
1315 { "boot", no_argument, NULL, ARG_BOOT },
1316 { "prefix", required_argument, NULL, ARG_PREFIX },
1317 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1318 { "root", required_argument, NULL, ARG_ROOT },
1327 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1335 puts(PACKAGE_STRING);
1336 puts(SYSTEMD_FEATURES);
1356 if (strv_push(&include_prefixes, optarg) < 0)
1360 case ARG_EXCLUDE_PREFIX:
1361 if (strv_push(&exclude_prefixes, optarg) < 0)
1366 arg_root = path_make_absolute_cwd(optarg);
1369 path_kill_slashes(arg_root);
1376 assert_not_reached("Unhandled option");
1380 if (!arg_clean && !arg_create && !arg_remove) {
1381 log_error("You need to specify at least one of --clean, --create or --remove.");
1388 static int read_config_file(const char *fn, bool ignore_enoent) {
1389 _cleanup_fclose_ FILE *f = NULL;
1390 char line[LINE_MAX];
1398 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1400 if (ignore_enoent && r == -ENOENT)
1403 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1407 FOREACH_LINE(line, f, break) {
1414 if (*l == '#' || *l == 0)
1417 k = parse_line(fn, v, l);
1418 if (k < 0 && r == 0)
1422 /* we have to determine age parameter for each entry of type X */
1423 HASHMAP_FOREACH(i, globs, iterator) {
1425 Item *j, *candidate_item = NULL;
1427 if (i->type != IGNORE_DIRECTORY_PATH)
1430 HASHMAP_FOREACH(j, items, iter) {
1431 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1434 if (path_equal(j->path, i->path)) {
1439 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1440 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1444 if (candidate_item) {
1445 i->age = candidate_item->age;
1451 log_error("Failed to read from file %s: %m", fn);
1459 int main(int argc, char *argv[]) {
1464 r = parse_argv(argc, argv);
1466 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1468 log_set_target(LOG_TARGET_AUTO);
1469 log_parse_environment();
1476 items = hashmap_new(string_hash_func, string_compare_func);
1477 globs = hashmap_new(string_hash_func, string_compare_func);
1479 if (!items || !globs) {
1486 if (optind < argc) {
1489 for (j = optind; j < argc; j++) {
1490 k = read_config_file(argv[j], false);
1491 if (k < 0 && r == 0)
1496 _cleanup_strv_free_ char **files = NULL;
1499 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1501 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1505 STRV_FOREACH(f, files) {
1506 k = read_config_file(*f, true);
1507 if (k < 0 && r == 0)
1512 HASHMAP_FOREACH(i, globs, iterator)
1515 HASHMAP_FOREACH(i, items, iterator)
1519 while ((i = hashmap_steal_first(items)))
1522 while ((i = hashmap_steal_first(globs)))
1525 hashmap_free(items);
1526 hashmap_free(globs);
1528 free(include_prefixes);
1529 free(exclude_prefixes);
1532 set_free_free(unix_sockets);
1536 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;