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"
58 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
59 * them in the file system. This is intended to be used to create
60 * properly owned directories beneath /tmp, /var/tmp, /run, which are
61 * volatile and hence need to be recreated on bootup. */
63 typedef enum ItemType {
64 /* 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 */
78 IGNORE_DIRECTORY_PATH = 'X',
80 RECURSIVE_REMOVE_PATH = 'R',
81 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
83 RECURSIVE_RELABEL_PATH = 'Z',
104 bool keep_first_level:1;
111 static bool arg_create = false;
112 static bool arg_clean = false;
113 static bool arg_remove = false;
114 static bool arg_boot = false;
116 static char **arg_include_prefixes = NULL;
117 static char **arg_exclude_prefixes = NULL;
118 static char *arg_root = NULL;
120 static const char conf_file_dirs[] =
123 "/usr/local/lib/tmpfiles.d\0"
124 "/usr/lib/tmpfiles.d\0"
125 #ifdef HAVE_SPLIT_USR
130 #define MAX_DEPTH 256
132 static Hashmap *items = NULL, *globs = NULL;
133 static Set *unix_sockets = NULL;
135 static bool needs_glob(ItemType t) {
139 IGNORE_DIRECTORY_PATH,
141 RECURSIVE_REMOVE_PATH,
144 RECURSIVE_RELABEL_PATH);
147 static struct Item* find_glob(Hashmap *h, const char *match) {
151 HASHMAP_FOREACH(j, h, i)
152 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
158 static void load_unix_sockets(void) {
159 _cleanup_fclose_ FILE *f = NULL;
165 /* We maintain a cache of the sockets we found in
166 * /proc/net/unix to speed things up a little. */
168 unix_sockets = set_new(string_hash_func, string_compare_func);
172 f = fopen("/proc/net/unix", "re");
177 if (!fgets(line, sizeof(line), f))
184 if (!fgets(line, sizeof(line), f))
189 p = strchr(line, ':');
197 p += strspn(p, WHITESPACE);
198 p += strcspn(p, WHITESPACE); /* skip one more word */
199 p += strspn(p, WHITESPACE);
208 path_kill_slashes(s);
210 k = set_consume(unix_sockets, s);
211 if (k < 0 && k != -EEXIST)
218 set_free_free(unix_sockets);
222 static bool unix_socket_alive(const char *fn) {
228 return !!set_get(unix_sockets, (char*) fn);
230 /* We don't know, so assume yes */
234 static int dir_is_mount_point(DIR *d, const char *subdir) {
236 union file_handle_union h = {
237 .handle.handle_bytes = MAX_HANDLE_SZ
240 int mount_id_parent, mount_id;
243 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
247 h.handle.handle_bytes = MAX_HANDLE_SZ;
248 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
252 /* got no handle; make no assumptions, return error */
253 if (r_p < 0 && r < 0)
256 /* got both handles; if they differ, it is a mount point */
257 if (r_p >= 0 && r >= 0)
258 return mount_id_parent != mount_id;
260 /* got only one handle; assume different mount points if one
261 * of both queries was not supported by the filesystem */
262 if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
271 static int dir_cleanup(
275 const struct stat *ds,
280 bool keep_this_level) {
283 struct timespec times[2];
284 bool deleted = false;
287 while ((dent = readdir(d))) {
290 _cleanup_free_ char *sub_path = NULL;
292 if (streq(dent->d_name, ".") ||
293 streq(dent->d_name, ".."))
296 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
300 /* FUSE, NFS mounts, SELinux might return EACCES */
302 log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
304 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
309 /* Stay on the same filesystem */
310 if (s.st_dev != rootdev)
313 /* Try to detect bind mounts of the same filesystem instance; they
314 * do not differ in device major/minors. This type of query is not
315 * supported on all kernels or filesystem types though. */
316 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
319 /* Do not delete read-only files owned by root */
320 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
323 sub_path = strjoin(p, "/", dent->d_name, NULL);
329 /* Is there an item configured for this path? */
330 if (hashmap_get(items, sub_path))
333 if (find_glob(globs, sub_path))
336 if (S_ISDIR(s.st_mode)) {
339 streq(dent->d_name, "lost+found") &&
344 log_warning("Reached max depth on %s.", sub_path);
346 _cleanup_closedir_ DIR *sub_dir;
349 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
351 if (errno != ENOENT) {
352 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
359 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
364 /* Note: if you are wondering why we don't
365 * support the sticky bit for excluding
366 * directories from cleaning like we do it for
367 * other file system objects: well, the sticky
368 * bit already has a meaning for directories,
369 * so we don't want to overload that. */
374 /* Ignore ctime, we change it when deleting */
375 age = MAX(timespec_load(&s.st_mtim),
376 timespec_load(&s.st_atim));
380 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
381 log_debug("rmdir '%s'", sub_path);
383 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
384 if (errno != ENOENT && errno != ENOTEMPTY) {
385 log_error("rmdir(%s): %m", sub_path);
392 /* Skip files for which the sticky bit is
393 * set. These are semantics we define, and are
394 * unknown elsewhere. See XDG_RUNTIME_DIR
395 * specification for details. */
396 if (s.st_mode & S_ISVTX)
399 if (mountpoint && S_ISREG(s.st_mode)) {
400 if (streq(dent->d_name, ".journal") &&
404 if (streq(dent->d_name, "aquota.user") ||
405 streq(dent->d_name, "aquota.group"))
409 /* Ignore sockets that are listed in /proc/net/unix */
410 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
413 /* Ignore device nodes */
414 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
417 /* Keep files on this level around if this is
422 age = MAX3(timespec_load(&s.st_mtim),
423 timespec_load(&s.st_atim),
424 timespec_load(&s.st_ctim));
429 log_debug("unlink '%s'", sub_path);
431 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
432 if (errno != ENOENT) {
433 log_error("unlink(%s): %m", sub_path);
444 /* Restore original directory timestamps */
445 times[0] = ds->st_atim;
446 times[1] = ds->st_mtim;
448 if (futimens(dirfd(d), times) < 0)
449 log_error("utimensat(%s): %m", p);
455 static int item_set_perms(Item *i, const char *path) {
459 /* not using i->path directly because it may be a glob */
466 if (stat(path, &st) >= 0) {
467 if (!(st.st_mode & 0111))
469 if (!(st.st_mode & 0222))
471 if (!(st.st_mode & 0444))
473 if (!S_ISDIR(st.st_mode))
474 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
478 if (chmod(path, m) < 0) {
479 log_error("chmod(%s) failed: %m", path);
484 if (i->uid_set || i->gid_set)
486 i->uid_set ? i->uid : (uid_t) -1,
487 i->gid_set ? i->gid : (gid_t) -1) < 0) {
489 log_error("chown(%s) failed: %m", path);
493 return label_fix(path, false, false);
496 static int write_one_file(Item *i, const char *path) {
497 _cleanup_close_ int fd = -1;
504 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
505 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
507 RUN_WITH_UMASK(0000) {
508 label_context_set(path, S_IFREG);
509 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
510 label_context_clear();
514 if (i->type == WRITE_FILE && errno == ENOENT)
517 log_error("Failed to create file %s: %m", path);
522 _cleanup_free_ char *unescaped;
526 unescaped = cunescape(i->argument);
530 l = strlen(unescaped);
531 n = write(fd, unescaped, l);
533 if (n < 0 || (size_t) n < l) {
534 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
535 return n < 0 ? n : -EIO;
541 if (stat(path, &st) < 0) {
542 log_error("stat(%s) failed: %m", path);
546 if (!S_ISREG(st.st_mode)) {
547 log_error("%s is not a file.", path);
551 r = item_set_perms(i, path);
558 static int item_set_perms_children(Item *i, const char *path) {
559 _cleanup_closedir_ DIR *d;
565 /* This returns the first error we run into, but nevertheless
570 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
573 _cleanup_free_ char *p = NULL;
580 if (errno != 0 && r == 0)
586 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
589 p = strjoin(path, "/", de->d_name, NULL);
593 q = item_set_perms(i, p);
594 if (q < 0 && q != -ENOENT && r == 0)
597 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
598 q = item_set_perms_children(i, p);
607 static int item_set_perms_recursive(Item *i, const char *path) {
613 r = item_set_perms(i, path);
617 q = item_set_perms_children(i, path);
624 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
625 _cleanup_globfree_ glob_t g = {};
630 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
631 if (k != 0 && k != GLOB_NOMATCH) {
635 log_error("glob(%s) failed: %m", i->path);
639 STRV_FOREACH(fn, g.gl_pathv) {
648 static int create_item(Item *i) {
657 case IGNORE_DIRECTORY_PATH:
659 case RECURSIVE_REMOVE_PATH:
664 r = write_one_file(i, i->path);
670 r = copy_tree(i->argument, i->path);
672 log_error("Failed to copy files to %s: %s", i->path, strerror(-r));
676 r = item_set_perms(i, i->path);
683 r = glob_item(i, write_one_file);
689 case TRUNCATE_DIRECTORY:
690 case CREATE_DIRECTORY:
692 RUN_WITH_UMASK(0000) {
693 mkdir_parents_label(i->path, 0755);
694 r = mkdir_label(i->path, i->mode);
697 if (r < 0 && r != -EEXIST) {
698 log_error("Failed to create directory %s: %s", i->path, strerror(-r));
702 if (stat(i->path, &st) < 0) {
703 log_error("stat(%s) failed: %m", i->path);
707 if (!S_ISDIR(st.st_mode)) {
708 log_error("%s is not a directory.", i->path);
712 r = item_set_perms(i, i->path);
720 RUN_WITH_UMASK(0000) {
721 label_context_set(i->path, S_IFIFO);
722 r = mkfifo(i->path, i->mode);
723 label_context_clear();
727 if (errno != EEXIST) {
728 log_error("Failed to create fifo %s: %m", i->path);
732 if (stat(i->path, &st) < 0) {
733 log_error("stat(%s) failed: %m", i->path);
737 if (!S_ISFIFO(st.st_mode)) {
741 RUN_WITH_UMASK(0000) {
742 label_context_set(i->path, S_IFIFO);
743 r = mkfifo_atomic(i->path, i->mode);
744 label_context_clear();
748 log_error("Failed to create fifo %s: %s", i->path, strerror(-r));
752 log_debug("%s is not a fifo.", i->path);
758 r = item_set_perms(i, i->path);
766 label_context_set(i->path, S_IFLNK);
767 r = symlink(i->argument, i->path);
768 label_context_clear();
771 _cleanup_free_ char *x = NULL;
773 if (errno != EEXIST) {
774 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
778 r = readlink_malloc(i->path, &x);
779 if (r < 0 || !streq(i->argument, x)) {
782 label_context_set(i->path, S_IFLNK);
783 r = symlink_atomic(i->argument, i->path);
784 label_context_clear();
787 log_error("symlink(%s, %s) failed: %s", i->argument, i->path, strerror(-r));
791 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
799 case CREATE_BLOCK_DEVICE:
800 case CREATE_CHAR_DEVICE: {
803 if (have_effective_cap(CAP_MKNOD) == 0) {
804 /* In a container we lack CAP_MKNOD. We
805 shouldn't attempt to create the device node in
806 that case to avoid noise, and we don't support
807 virtualized devices in containers anyway. */
809 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
813 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
815 RUN_WITH_UMASK(0000) {
816 label_context_set(i->path, file_type);
817 r = mknod(i->path, i->mode | file_type, i->major_minor);
818 label_context_clear();
822 if (errno == EPERM) {
823 log_debug("We lack permissions, possibly because of cgroup configuration; "
824 "skipping creation of device node %s.", i->path);
828 if (errno != EEXIST) {
829 log_error("Failed to create device node %s: %m", i->path);
833 if (stat(i->path, &st) < 0) {
834 log_error("stat(%s) failed: %m", i->path);
838 if ((st.st_mode & S_IFMT) != file_type) {
842 RUN_WITH_UMASK(0000) {
843 label_context_set(i->path, file_type);
844 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
845 label_context_clear();
849 log_error("Failed to create device node %s: %s", i->path, strerror(-r));
853 log_debug("%s is not a device node.", i->path);
859 r = item_set_perms(i, i->path);
869 r = glob_item(i, item_set_perms);
874 case RECURSIVE_RELABEL_PATH:
876 r = glob_item(i, item_set_perms_recursive);
883 log_debug("%s created successfully.", i->path);
888 static int remove_item_instance(Item *i, const char *instance) {
897 case CREATE_DIRECTORY:
900 case CREATE_BLOCK_DEVICE:
901 case CREATE_CHAR_DEVICE:
903 case IGNORE_DIRECTORY_PATH:
906 case RECURSIVE_RELABEL_PATH:
912 if (remove(instance) < 0 && errno != ENOENT) {
913 log_error("remove(%s): %m", instance);
919 case TRUNCATE_DIRECTORY:
920 case RECURSIVE_REMOVE_PATH:
921 /* FIXME: we probably should use dir_cleanup() here
922 * instead of rm_rf() so that 'x' is honoured. */
923 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
924 if (r < 0 && r != -ENOENT) {
925 log_error("rm_rf(%s): %s", instance, strerror(-r));
935 static int remove_item(Item *i) {
944 case CREATE_DIRECTORY:
947 case CREATE_CHAR_DEVICE:
948 case CREATE_BLOCK_DEVICE:
950 case IGNORE_DIRECTORY_PATH:
953 case RECURSIVE_RELABEL_PATH:
959 case TRUNCATE_DIRECTORY:
960 case RECURSIVE_REMOVE_PATH:
961 r = glob_item(i, remove_item_instance);
968 static int clean_item_instance(Item *i, const char* instance) {
969 _cleanup_closedir_ DIR *d = NULL;
980 n = now(CLOCK_REALTIME);
986 d = opendir(instance);
988 if (errno == ENOENT || errno == ENOTDIR)
991 log_error("Failed to open directory %s: %m", i->path);
995 if (fstat(dirfd(d), &s) < 0) {
996 log_error("stat(%s) failed: %m", i->path);
1000 if (!S_ISDIR(s.st_mode)) {
1001 log_error("%s is not a directory.", i->path);
1005 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
1006 log_error("stat(%s/..) failed: %m", i->path);
1010 mountpoint = s.st_dev != ps.st_dev ||
1011 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1013 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1014 MAX_DEPTH, i->keep_first_level);
1018 static int clean_item(Item *i) {
1024 case CREATE_DIRECTORY:
1025 case TRUNCATE_DIRECTORY:
1028 clean_item_instance(i, i->path);
1030 case IGNORE_DIRECTORY_PATH:
1031 r = glob_item(i, clean_item_instance);
1040 static int process_item(Item *i) {
1042 char prefix[PATH_MAX];
1051 PATH_FOREACH_PREFIX(prefix, i->path) {
1054 j = hashmap_get(items, prefix);
1059 r = arg_create ? create_item(i) : 0;
1060 q = arg_remove ? remove_item(i) : 0;
1061 p = arg_clean ? clean_item(i) : 0;
1072 static void item_free(Item *i) {
1082 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1084 static bool item_equal(Item *a, Item *b) {
1088 if (!streq_ptr(a->path, b->path))
1091 if (a->type != b->type)
1094 if (a->uid_set != b->uid_set ||
1095 (a->uid_set && a->uid != b->uid))
1098 if (a->gid_set != b->gid_set ||
1099 (a->gid_set && a->gid != b->gid))
1102 if (a->mode_set != b->mode_set ||
1103 (a->mode_set && a->mode != b->mode))
1106 if (a->age_set != b->age_set ||
1107 (a->age_set && a->age != b->age))
1110 if ((a->type == CREATE_FILE ||
1111 a->type == TRUNCATE_FILE ||
1112 a->type == WRITE_FILE ||
1113 a->type == CREATE_SYMLINK ||
1114 a->type == COPY_FILES) &&
1115 !streq_ptr(a->argument, b->argument))
1118 if ((a->type == CREATE_CHAR_DEVICE ||
1119 a->type == CREATE_BLOCK_DEVICE) &&
1120 a->major_minor != b->major_minor)
1126 static bool should_include_path(const char *path) {
1129 STRV_FOREACH(prefix, arg_exclude_prefixes)
1130 if (path_startswith(path, *prefix))
1133 STRV_FOREACH(prefix, arg_include_prefixes)
1134 if (path_startswith(path, *prefix))
1137 /* no matches, so we should include this path only if we
1138 * have no whitelist at all */
1139 return strv_length(arg_include_prefixes) == 0;
1142 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1144 static const Specifier specifier_table[] = {
1145 { 'm', specifier_machine_id, NULL },
1146 { 'b', specifier_boot_id, NULL },
1147 { 'H', specifier_host_name, NULL },
1148 { 'v', specifier_kernel_release, NULL },
1152 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1153 _cleanup_(item_freep) Item *i = NULL;
1164 "%ms %ms %ms %ms %ms %ms %n",
1173 log_error("[%s:%u] Syntax error.", fname, line);
1177 if (isempty(action)) {
1178 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1182 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1183 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1187 if (strchr(action+1, '!') && !arg_boot)
1196 i->force = !!strchr(action+1, '+');
1198 r = specifier_printf(path, specifier_table, NULL, &i->path);
1200 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1205 n += strspn(buffer+n, WHITESPACE);
1206 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1207 i->argument = unquote(buffer+n, "\"");
1217 case CREATE_DIRECTORY:
1218 case TRUNCATE_DIRECTORY:
1221 case IGNORE_DIRECTORY_PATH:
1223 case RECURSIVE_REMOVE_PATH:
1226 case RECURSIVE_RELABEL_PATH:
1229 case CREATE_SYMLINK:
1231 log_error("[%s:%u] Symlink file requires argument.", fname, line);
1239 log_error("[%s:%u] Write file requires argument.", fname, line);
1246 log_error("[%s:%u] Copy files requires argument.", fname, line);
1250 if (!path_is_absolute(i->argument)) {
1251 log_error("[%s:%u] Source path is not absolute.", fname, line);
1255 path_kill_slashes(i->argument);
1258 case CREATE_CHAR_DEVICE:
1259 case CREATE_BLOCK_DEVICE: {
1260 unsigned major, minor;
1263 log_error("[%s:%u] Device file requires argument.", fname, line);
1267 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1268 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1272 i->major_minor = makedev(major, minor);
1277 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1283 if (!path_is_absolute(i->path)) {
1284 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1288 path_kill_slashes(i->path);
1290 if (!should_include_path(i->path))
1296 p = strappend(arg_root, i->path);
1304 if (user && !streq(user, "-")) {
1305 const char *u = user;
1307 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1309 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1316 if (group && !streq(group, "-")) {
1317 const char *g = group;
1319 r = get_group_creds(&g, &i->gid);
1321 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1328 if (mode && !streq(mode, "-")) {
1329 const char *mm = mode;
1333 i->mask_perms = true;
1337 if (sscanf(mm, "%o", &m) != 1) {
1338 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1346 i->type == CREATE_DIRECTORY ||
1347 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1349 if (age && !streq(age, "-")) {
1350 const char *a = age;
1353 i->keep_first_level = true;
1357 if (parse_sec(a, &i->age) < 0) {
1358 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1365 h = needs_glob(i->type) ? globs : items;
1367 existing = hashmap_get(h, i->path);
1370 /* Two identical items are fine */
1371 if (!item_equal(existing, i))
1372 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1377 r = hashmap_put(h, i->path, i);
1379 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1383 i = NULL; /* avoid cleanup */
1388 static int help(void) {
1390 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1391 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1392 " -h --help Show this help\n"
1393 " --version Show package version\n"
1394 " --create Create marked files/directories\n"
1395 " --clean Clean up marked directories\n"
1396 " --remove Remove marked files/directories\n"
1397 " --boot Execute actions only safe at boot\n"
1398 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1399 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1400 " --root=PATH Operate on an alternate filesystem root\n",
1401 program_invocation_short_name);
1406 static int parse_argv(int argc, char *argv[]) {
1409 ARG_VERSION = 0x100,
1419 static const struct option options[] = {
1420 { "help", no_argument, NULL, 'h' },
1421 { "version", no_argument, NULL, ARG_VERSION },
1422 { "create", no_argument, NULL, ARG_CREATE },
1423 { "clean", no_argument, NULL, ARG_CLEAN },
1424 { "remove", no_argument, NULL, ARG_REMOVE },
1425 { "boot", no_argument, NULL, ARG_BOOT },
1426 { "prefix", required_argument, NULL, ARG_PREFIX },
1427 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1428 { "root", required_argument, NULL, ARG_ROOT },
1437 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1445 puts(PACKAGE_STRING);
1446 puts(SYSTEMD_FEATURES);
1466 if (strv_push(&arg_include_prefixes, optarg) < 0)
1470 case ARG_EXCLUDE_PREFIX:
1471 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1477 arg_root = path_make_absolute_cwd(optarg);
1481 path_kill_slashes(arg_root);
1488 assert_not_reached("Unhandled option");
1492 if (!arg_clean && !arg_create && !arg_remove) {
1493 log_error("You need to specify at least one of --clean, --create or --remove.");
1500 static int read_config_file(const char *fn, bool ignore_enoent) {
1501 _cleanup_fclose_ FILE *f = NULL;
1502 char line[LINE_MAX];
1510 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1512 if (ignore_enoent && r == -ENOENT)
1515 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1519 FOREACH_LINE(line, f, break) {
1526 if (*l == '#' || *l == 0)
1529 k = parse_line(fn, v, l);
1530 if (k < 0 && r == 0)
1534 /* we have to determine age parameter for each entry of type X */
1535 HASHMAP_FOREACH(i, globs, iterator) {
1537 Item *j, *candidate_item = NULL;
1539 if (i->type != IGNORE_DIRECTORY_PATH)
1542 HASHMAP_FOREACH(j, items, iter) {
1543 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1546 if (path_equal(j->path, i->path)) {
1551 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1552 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1556 if (candidate_item) {
1557 i->age = candidate_item->age;
1563 log_error("Failed to read from file %s: %m", fn);
1571 int main(int argc, char *argv[]) {
1576 r = parse_argv(argc, argv);
1580 log_set_target(LOG_TARGET_AUTO);
1581 log_parse_environment();
1588 items = hashmap_new(string_hash_func, string_compare_func);
1589 globs = hashmap_new(string_hash_func, string_compare_func);
1591 if (!items || !globs) {
1598 if (optind < argc) {
1601 for (j = optind; j < argc; j++) {
1602 k = read_config_file(argv[j], false);
1603 if (k < 0 && r == 0)
1608 _cleanup_strv_free_ char **files = NULL;
1611 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1613 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1617 STRV_FOREACH(f, files) {
1618 k = read_config_file(*f, true);
1619 if (k < 0 && r == 0)
1624 HASHMAP_FOREACH(i, globs, iterator)
1627 HASHMAP_FOREACH(i, items, iterator)
1631 while ((i = hashmap_steal_first(items)))
1634 while ((i = hashmap_steal_first(globs)))
1637 hashmap_free(items);
1638 hashmap_free(globs);
1640 free(arg_include_prefixes);
1641 free(arg_exclude_prefixes);
1644 set_free_free(unix_sockets);
1648 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;