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, false);
675 log_error("Failed to copy files to %s: %s", i->path, strerror(-r));
679 if (stat(i->argument, &a) < 0) {
680 log_error("stat(%s) failed: %m", i->argument);
684 if (stat(i->path, &b) < 0) {
685 log_error("stat(%s) failed: %m", i->path);
689 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
690 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
695 r = item_set_perms(i, i->path);
702 r = glob_item(i, write_one_file);
708 case TRUNCATE_DIRECTORY:
709 case CREATE_DIRECTORY:
711 RUN_WITH_UMASK(0000) {
712 mkdir_parents_label(i->path, 0755);
713 r = mkdir_label(i->path, i->mode);
718 log_error("Failed to create directory %s: %s", i->path, strerror(-r));
722 if (stat(i->path, &st) < 0) {
723 log_error("stat(%s) failed: %m", i->path);
727 if (!S_ISDIR(st.st_mode)) {
728 log_debug("%s already exists and is not a directory.", i->path);
733 r = item_set_perms(i, i->path);
741 RUN_WITH_UMASK(0000) {
742 label_context_set(i->path, S_IFIFO);
743 r = mkfifo(i->path, i->mode);
744 label_context_clear();
748 if (errno != EEXIST) {
749 log_error("Failed to create fifo %s: %m", i->path);
753 if (stat(i->path, &st) < 0) {
754 log_error("stat(%s) failed: %m", i->path);
758 if (!S_ISFIFO(st.st_mode)) {
762 RUN_WITH_UMASK(0000) {
763 label_context_set(i->path, S_IFIFO);
764 r = mkfifo_atomic(i->path, i->mode);
765 label_context_clear();
769 log_error("Failed to create fifo %s: %s", i->path, strerror(-r));
773 log_debug("%s is not a fifo.", i->path);
779 r = item_set_perms(i, i->path);
787 label_context_set(i->path, S_IFLNK);
788 r = symlink(i->argument, i->path);
789 label_context_clear();
792 _cleanup_free_ char *x = NULL;
794 if (errno != EEXIST) {
795 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
799 r = readlink_malloc(i->path, &x);
800 if (r < 0 || !streq(i->argument, x)) {
803 label_context_set(i->path, S_IFLNK);
804 r = symlink_atomic(i->argument, i->path);
805 label_context_clear();
808 log_error("symlink(%s, %s) failed: %s", i->argument, i->path, strerror(-r));
812 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
820 case CREATE_BLOCK_DEVICE:
821 case CREATE_CHAR_DEVICE: {
824 if (have_effective_cap(CAP_MKNOD) == 0) {
825 /* In a container we lack CAP_MKNOD. We
826 shouldn't attempt to create the device node in
827 that case to avoid noise, and we don't support
828 virtualized devices in containers anyway. */
830 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
834 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
836 RUN_WITH_UMASK(0000) {
837 label_context_set(i->path, file_type);
838 r = mknod(i->path, i->mode | file_type, i->major_minor);
839 label_context_clear();
843 if (errno == EPERM) {
844 log_debug("We lack permissions, possibly because of cgroup configuration; "
845 "skipping creation of device node %s.", i->path);
849 if (errno != EEXIST) {
850 log_error("Failed to create device node %s: %m", i->path);
854 if (stat(i->path, &st) < 0) {
855 log_error("stat(%s) failed: %m", i->path);
859 if ((st.st_mode & S_IFMT) != file_type) {
863 RUN_WITH_UMASK(0000) {
864 label_context_set(i->path, file_type);
865 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
866 label_context_clear();
870 log_error("Failed to create device node %s: %s", i->path, strerror(-r));
874 log_debug("%s is not a device node.", i->path);
880 r = item_set_perms(i, i->path);
890 r = glob_item(i, item_set_perms);
895 case RECURSIVE_RELABEL_PATH:
897 r = glob_item(i, item_set_perms_recursive);
904 log_debug("%s created successfully.", i->path);
909 static int remove_item_instance(Item *i, const char *instance) {
918 case CREATE_DIRECTORY:
921 case CREATE_BLOCK_DEVICE:
922 case CREATE_CHAR_DEVICE:
924 case IGNORE_DIRECTORY_PATH:
927 case RECURSIVE_RELABEL_PATH:
933 if (remove(instance) < 0 && errno != ENOENT) {
934 log_error("remove(%s): %m", instance);
940 case TRUNCATE_DIRECTORY:
941 case RECURSIVE_REMOVE_PATH:
942 /* FIXME: we probably should use dir_cleanup() here
943 * instead of rm_rf() so that 'x' is honoured. */
944 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
945 if (r < 0 && r != -ENOENT) {
946 log_error("rm_rf(%s): %s", instance, strerror(-r));
956 static int remove_item(Item *i) {
965 case CREATE_DIRECTORY:
968 case CREATE_CHAR_DEVICE:
969 case CREATE_BLOCK_DEVICE:
971 case IGNORE_DIRECTORY_PATH:
974 case RECURSIVE_RELABEL_PATH:
980 case TRUNCATE_DIRECTORY:
981 case RECURSIVE_REMOVE_PATH:
982 r = glob_item(i, remove_item_instance);
989 static int clean_item_instance(Item *i, const char* instance) {
990 _cleanup_closedir_ DIR *d = NULL;
1001 n = now(CLOCK_REALTIME);
1005 cutoff = n - i->age;
1007 d = opendir(instance);
1009 if (errno == ENOENT || errno == ENOTDIR)
1012 log_error("Failed to open directory %s: %m", i->path);
1016 if (fstat(dirfd(d), &s) < 0) {
1017 log_error("stat(%s) failed: %m", i->path);
1021 if (!S_ISDIR(s.st_mode)) {
1022 log_error("%s is not a directory.", i->path);
1026 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
1027 log_error("stat(%s/..) failed: %m", i->path);
1031 mountpoint = s.st_dev != ps.st_dev ||
1032 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1034 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1035 MAX_DEPTH, i->keep_first_level);
1039 static int clean_item(Item *i) {
1045 case CREATE_DIRECTORY:
1046 case TRUNCATE_DIRECTORY:
1049 clean_item_instance(i, i->path);
1051 case IGNORE_DIRECTORY_PATH:
1052 r = glob_item(i, clean_item_instance);
1061 static int process_item(Item *i) {
1063 char prefix[PATH_MAX];
1072 PATH_FOREACH_PREFIX(prefix, i->path) {
1075 j = hashmap_get(items, prefix);
1080 r = arg_create ? create_item(i) : 0;
1081 q = arg_remove ? remove_item(i) : 0;
1082 p = arg_clean ? clean_item(i) : 0;
1093 static void item_free(Item *i) {
1103 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1105 static bool item_equal(Item *a, Item *b) {
1109 if (!streq_ptr(a->path, b->path))
1112 if (a->type != b->type)
1115 if (a->uid_set != b->uid_set ||
1116 (a->uid_set && a->uid != b->uid))
1119 if (a->gid_set != b->gid_set ||
1120 (a->gid_set && a->gid != b->gid))
1123 if (a->mode_set != b->mode_set ||
1124 (a->mode_set && a->mode != b->mode))
1127 if (a->age_set != b->age_set ||
1128 (a->age_set && a->age != b->age))
1131 if ((a->type == CREATE_FILE ||
1132 a->type == TRUNCATE_FILE ||
1133 a->type == WRITE_FILE ||
1134 a->type == CREATE_SYMLINK ||
1135 a->type == COPY_FILES) &&
1136 !streq_ptr(a->argument, b->argument))
1139 if ((a->type == CREATE_CHAR_DEVICE ||
1140 a->type == CREATE_BLOCK_DEVICE) &&
1141 a->major_minor != b->major_minor)
1147 static bool should_include_path(const char *path) {
1150 STRV_FOREACH(prefix, arg_exclude_prefixes)
1151 if (path_startswith(path, *prefix))
1154 STRV_FOREACH(prefix, arg_include_prefixes)
1155 if (path_startswith(path, *prefix))
1158 /* no matches, so we should include this path only if we
1159 * have no whitelist at all */
1160 return strv_length(arg_include_prefixes) == 0;
1163 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1165 static const Specifier specifier_table[] = {
1166 { 'm', specifier_machine_id, NULL },
1167 { 'b', specifier_boot_id, NULL },
1168 { 'H', specifier_host_name, NULL },
1169 { 'v', specifier_kernel_release, NULL },
1173 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1174 _cleanup_(item_freep) Item *i = NULL;
1185 "%ms %ms %ms %ms %ms %ms %n",
1194 log_error("[%s:%u] Syntax error.", fname, line);
1198 if (isempty(action)) {
1199 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1203 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1204 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1208 if (strchr(action+1, '!') && !arg_boot)
1217 i->force = !!strchr(action+1, '+');
1219 r = specifier_printf(path, specifier_table, NULL, &i->path);
1221 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1226 n += strspn(buffer+n, WHITESPACE);
1227 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1228 i->argument = unquote(buffer+n, "\"");
1238 case CREATE_DIRECTORY:
1239 case TRUNCATE_DIRECTORY:
1242 case IGNORE_DIRECTORY_PATH:
1244 case RECURSIVE_REMOVE_PATH:
1247 case RECURSIVE_RELABEL_PATH:
1250 case CREATE_SYMLINK:
1252 log_error("[%s:%u] Symlink file requires argument.", fname, line);
1260 log_error("[%s:%u] Write file requires argument.", fname, line);
1267 log_error("[%s:%u] Copy files requires argument.", fname, line);
1271 if (!path_is_absolute(i->argument)) {
1272 log_error("[%s:%u] Source path is not absolute.", fname, line);
1276 path_kill_slashes(i->argument);
1279 case CREATE_CHAR_DEVICE:
1280 case CREATE_BLOCK_DEVICE: {
1281 unsigned major, minor;
1284 log_error("[%s:%u] Device file requires argument.", fname, line);
1288 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1289 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1293 i->major_minor = makedev(major, minor);
1298 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1304 if (!path_is_absolute(i->path)) {
1305 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1309 path_kill_slashes(i->path);
1311 if (!should_include_path(i->path))
1317 p = strappend(arg_root, i->path);
1325 if (user && !streq(user, "-")) {
1326 const char *u = user;
1328 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1330 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1337 if (group && !streq(group, "-")) {
1338 const char *g = group;
1340 r = get_group_creds(&g, &i->gid);
1342 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1349 if (mode && !streq(mode, "-")) {
1350 const char *mm = mode;
1354 i->mask_perms = true;
1358 if (sscanf(mm, "%o", &m) != 1) {
1359 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1367 i->type == CREATE_DIRECTORY ||
1368 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1370 if (age && !streq(age, "-")) {
1371 const char *a = age;
1374 i->keep_first_level = true;
1378 if (parse_sec(a, &i->age) < 0) {
1379 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1386 h = needs_glob(i->type) ? globs : items;
1388 existing = hashmap_get(h, i->path);
1391 /* Two identical items are fine */
1392 if (!item_equal(existing, i))
1393 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1398 r = hashmap_put(h, i->path, i);
1400 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1404 i = NULL; /* avoid cleanup */
1409 static int help(void) {
1411 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1412 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1413 " -h --help Show this help\n"
1414 " --version Show package version\n"
1415 " --create Create marked files/directories\n"
1416 " --clean Clean up marked directories\n"
1417 " --remove Remove marked files/directories\n"
1418 " --boot Execute actions only safe at boot\n"
1419 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1420 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1421 " --root=PATH Operate on an alternate filesystem root\n",
1422 program_invocation_short_name);
1427 static int parse_argv(int argc, char *argv[]) {
1430 ARG_VERSION = 0x100,
1440 static const struct option options[] = {
1441 { "help", no_argument, NULL, 'h' },
1442 { "version", no_argument, NULL, ARG_VERSION },
1443 { "create", no_argument, NULL, ARG_CREATE },
1444 { "clean", no_argument, NULL, ARG_CLEAN },
1445 { "remove", no_argument, NULL, ARG_REMOVE },
1446 { "boot", no_argument, NULL, ARG_BOOT },
1447 { "prefix", required_argument, NULL, ARG_PREFIX },
1448 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1449 { "root", required_argument, NULL, ARG_ROOT },
1458 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1466 puts(PACKAGE_STRING);
1467 puts(SYSTEMD_FEATURES);
1487 if (strv_push(&arg_include_prefixes, optarg) < 0)
1491 case ARG_EXCLUDE_PREFIX:
1492 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1498 arg_root = path_make_absolute_cwd(optarg);
1502 path_kill_slashes(arg_root);
1509 assert_not_reached("Unhandled option");
1513 if (!arg_clean && !arg_create && !arg_remove) {
1514 log_error("You need to specify at least one of --clean, --create or --remove.");
1521 static int read_config_file(const char *fn, bool ignore_enoent) {
1522 _cleanup_fclose_ FILE *f = NULL;
1523 char line[LINE_MAX];
1531 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1533 if (ignore_enoent && r == -ENOENT)
1536 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1540 FOREACH_LINE(line, f, break) {
1547 if (*l == '#' || *l == 0)
1550 k = parse_line(fn, v, l);
1551 if (k < 0 && r == 0)
1555 /* we have to determine age parameter for each entry of type X */
1556 HASHMAP_FOREACH(i, globs, iterator) {
1558 Item *j, *candidate_item = NULL;
1560 if (i->type != IGNORE_DIRECTORY_PATH)
1563 HASHMAP_FOREACH(j, items, iter) {
1564 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1567 if (path_equal(j->path, i->path)) {
1572 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1573 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1577 if (candidate_item) {
1578 i->age = candidate_item->age;
1584 log_error("Failed to read from file %s: %m", fn);
1592 int main(int argc, char *argv[]) {
1597 r = parse_argv(argc, argv);
1601 log_set_target(LOG_TARGET_AUTO);
1602 log_parse_environment();
1609 items = hashmap_new(string_hash_func, string_compare_func);
1610 globs = hashmap_new(string_hash_func, string_compare_func);
1612 if (!items || !globs) {
1619 if (optind < argc) {
1622 for (j = optind; j < argc; j++) {
1623 k = read_config_file(argv[j], false);
1624 if (k < 0 && r == 0)
1629 _cleanup_strv_free_ char **files = NULL;
1632 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1634 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1638 STRV_FOREACH(f, files) {
1639 k = read_config_file(*f, true);
1640 if (k < 0 && r == 0)
1645 HASHMAP_FOREACH(i, globs, iterator)
1648 HASHMAP_FOREACH(i, items, iterator)
1652 while ((i = hashmap_steal_first(items)))
1655 while ((i = hashmap_steal_first(globs)))
1658 hashmap_free(items);
1659 hashmap_free(globs);
1661 free(arg_include_prefixes);
1662 free(arg_exclude_prefixes);
1665 set_free_free(unix_sockets);
1669 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;