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) {
505 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
506 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
509 label_context_set(path, S_IFREG);
510 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
511 label_context_clear();
515 if (i->type == WRITE_FILE && errno == ENOENT)
518 log_error("Failed to create file %s: %m", path);
523 _cleanup_free_ char *unescaped;
527 unescaped = cunescape(i->argument);
528 if (unescaped == NULL) {
533 l = strlen(unescaped);
534 n = write(fd, unescaped, l);
536 if (n < 0 || (size_t) n < l) {
537 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
539 return n < 0 ? n : -EIO;
545 if (stat(path, &st) < 0) {
546 log_error("stat(%s) failed: %m", path);
550 if (!S_ISREG(st.st_mode)) {
551 log_error("%s is not a file.", path);
555 r = item_set_perms(i, path);
562 static int item_set_perms_children(Item *i, const char *path) {
563 _cleanup_closedir_ DIR *d;
569 /* This returns the first error we run into, but nevertheless
574 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
577 _cleanup_free_ char *p = NULL;
584 if (errno != 0 && r == 0)
590 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
593 p = strjoin(path, "/", de->d_name, NULL);
597 q = item_set_perms(i, p);
598 if (q < 0 && q != -ENOENT && r == 0)
601 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
602 q = item_set_perms_children(i, p);
611 static int item_set_perms_recursive(Item *i, const char *path) {
617 r = item_set_perms(i, path);
621 q = item_set_perms_children(i, path);
628 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
629 _cleanup_globfree_ glob_t g = {};
634 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
635 if (k != 0 && k != GLOB_NOMATCH) {
639 log_error("glob(%s) failed: %m", i->path);
643 STRV_FOREACH(fn, g.gl_pathv) {
652 static int create_item(Item *i) {
661 case IGNORE_DIRECTORY_PATH:
663 case RECURSIVE_REMOVE_PATH:
668 r = write_one_file(i, i->path);
674 r = copy_tree(i->argument, i->path);
676 log_error("Failed to copy files: %s", strerror(-r));
680 r = item_set_perms(i, i->path);
687 r = glob_item(i, write_one_file);
693 case TRUNCATE_DIRECTORY:
694 case CREATE_DIRECTORY:
696 RUN_WITH_UMASK(0000) {
697 mkdir_parents_label(i->path, 0755);
698 r = mkdir(i->path, i->mode);
701 if (r < 0 && errno != EEXIST) {
702 log_error("Failed to create directory %s: %m", i->path);
706 if (stat(i->path, &st) < 0) {
707 log_error("stat(%s) failed: %m", i->path);
711 if (!S_ISDIR(st.st_mode)) {
712 log_error("%s is not a directory.", i->path);
716 r = item_set_perms(i, i->path);
724 RUN_WITH_UMASK(0000) {
725 label_context_set(i->path, S_IFIFO);
726 r = mkfifo(i->path, i->mode);
727 label_context_clear();
731 if (errno != EEXIST) {
732 log_error("Failed to create fifo %s: %m", i->path);
736 if (stat(i->path, &st) < 0) {
737 log_error("stat(%s) failed: %m", i->path);
741 if (!S_ISFIFO(st.st_mode)) {
745 RUN_WITH_UMASK(0000) {
746 label_context_set(i->path, S_IFIFO);
747 r = mkfifo_atomic(i->path, i->mode);
748 label_context_clear();
752 log_error("Failed to create fifo %s: %s", i->path, strerror(-r));
756 log_debug("%s is not a fifo.", i->path);
762 r = item_set_perms(i, i->path);
770 label_context_set(i->path, S_IFLNK);
771 r = symlink(i->argument, i->path);
772 label_context_clear();
775 _cleanup_free_ char *x = NULL;
777 if (errno != EEXIST) {
778 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
782 r = readlink_malloc(i->path, &x);
783 if (r < 0 || !streq(i->argument, x)) {
786 label_context_set(i->path, S_IFLNK);
787 r = symlink_atomic(i->argument, i->path);
788 label_context_clear();
791 log_error("symlink(%s, %s) failed: %s", i->argument, i->path, strerror(-r));
795 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
803 case CREATE_BLOCK_DEVICE:
804 case CREATE_CHAR_DEVICE: {
807 if (have_effective_cap(CAP_MKNOD) == 0) {
808 /* In a container we lack CAP_MKNOD. We
809 shouldn't attempt to create the device node in
810 that case to avoid noise, and we don't support
811 virtualized devices in containers anyway. */
813 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
817 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
819 RUN_WITH_UMASK(0000) {
820 label_context_set(i->path, file_type);
821 r = mknod(i->path, i->mode | file_type, i->major_minor);
822 label_context_clear();
826 if (errno == EPERM) {
827 log_debug("We lack permissions, possibly because of cgroup configuration; "
828 "skipping creation of device node %s.", i->path);
832 if (errno != EEXIST) {
833 log_error("Failed to create device node %s: %m", i->path);
837 if (stat(i->path, &st) < 0) {
838 log_error("stat(%s) failed: %m", i->path);
842 if ((st.st_mode & S_IFMT) != file_type) {
846 RUN_WITH_UMASK(0000) {
847 label_context_set(i->path, file_type);
848 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
849 label_context_clear();
853 log_error("Failed to create device node %s: %s", i->path, strerror(-r));
857 log_debug("%s is not a device node.", i->path);
863 r = item_set_perms(i, i->path);
873 r = glob_item(i, item_set_perms);
878 case RECURSIVE_RELABEL_PATH:
880 r = glob_item(i, item_set_perms_recursive);
887 log_debug("%s created successfully.", i->path);
892 static int remove_item_instance(Item *i, const char *instance) {
901 case CREATE_DIRECTORY:
904 case CREATE_BLOCK_DEVICE:
905 case CREATE_CHAR_DEVICE:
907 case IGNORE_DIRECTORY_PATH:
910 case RECURSIVE_RELABEL_PATH:
916 if (remove(instance) < 0 && errno != ENOENT) {
917 log_error("remove(%s): %m", instance);
923 case TRUNCATE_DIRECTORY:
924 case RECURSIVE_REMOVE_PATH:
925 /* FIXME: we probably should use dir_cleanup() here
926 * instead of rm_rf() so that 'x' is honoured. */
927 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
928 if (r < 0 && r != -ENOENT) {
929 log_error("rm_rf(%s): %s", instance, strerror(-r));
939 static int remove_item(Item *i) {
948 case CREATE_DIRECTORY:
951 case CREATE_CHAR_DEVICE:
952 case CREATE_BLOCK_DEVICE:
954 case IGNORE_DIRECTORY_PATH:
957 case RECURSIVE_RELABEL_PATH:
963 case TRUNCATE_DIRECTORY:
964 case RECURSIVE_REMOVE_PATH:
965 r = glob_item(i, remove_item_instance);
972 static int clean_item_instance(Item *i, const char* instance) {
973 _cleanup_closedir_ DIR *d = NULL;
984 n = now(CLOCK_REALTIME);
990 d = opendir(instance);
992 if (errno == ENOENT || errno == ENOTDIR)
995 log_error("Failed to open directory %s: %m", i->path);
999 if (fstat(dirfd(d), &s) < 0) {
1000 log_error("stat(%s) failed: %m", i->path);
1004 if (!S_ISDIR(s.st_mode)) {
1005 log_error("%s is not a directory.", i->path);
1009 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
1010 log_error("stat(%s/..) failed: %m", i->path);
1014 mountpoint = s.st_dev != ps.st_dev ||
1015 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1017 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1018 MAX_DEPTH, i->keep_first_level);
1022 static int clean_item(Item *i) {
1028 case CREATE_DIRECTORY:
1029 case TRUNCATE_DIRECTORY:
1032 clean_item_instance(i, i->path);
1034 case IGNORE_DIRECTORY_PATH:
1035 r = glob_item(i, clean_item_instance);
1044 static int process_item(Item *i) {
1046 char prefix[PATH_MAX];
1055 PATH_FOREACH_PREFIX(prefix, i->path) {
1058 j = hashmap_get(items, prefix);
1063 r = arg_create ? create_item(i) : 0;
1064 q = arg_remove ? remove_item(i) : 0;
1065 p = arg_clean ? clean_item(i) : 0;
1076 static void item_free(Item *i) {
1086 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1088 static bool item_equal(Item *a, Item *b) {
1092 if (!streq_ptr(a->path, b->path))
1095 if (a->type != b->type)
1098 if (a->uid_set != b->uid_set ||
1099 (a->uid_set && a->uid != b->uid))
1102 if (a->gid_set != b->gid_set ||
1103 (a->gid_set && a->gid != b->gid))
1106 if (a->mode_set != b->mode_set ||
1107 (a->mode_set && a->mode != b->mode))
1110 if (a->age_set != b->age_set ||
1111 (a->age_set && a->age != b->age))
1114 if ((a->type == CREATE_FILE ||
1115 a->type == TRUNCATE_FILE ||
1116 a->type == WRITE_FILE ||
1117 a->type == CREATE_SYMLINK ||
1118 a->type == COPY_FILES) &&
1119 !streq_ptr(a->argument, b->argument))
1122 if ((a->type == CREATE_CHAR_DEVICE ||
1123 a->type == CREATE_BLOCK_DEVICE) &&
1124 a->major_minor != b->major_minor)
1130 static bool should_include_path(const char *path) {
1133 STRV_FOREACH(prefix, arg_exclude_prefixes)
1134 if (path_startswith(path, *prefix))
1137 STRV_FOREACH(prefix, arg_include_prefixes)
1138 if (path_startswith(path, *prefix))
1141 /* no matches, so we should include this path only if we
1142 * have no whitelist at all */
1143 return strv_length(arg_include_prefixes) == 0;
1146 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1148 static const Specifier specifier_table[] = {
1149 { 'm', specifier_machine_id, NULL },
1150 { 'b', specifier_boot_id, NULL },
1151 { 'H', specifier_host_name, NULL },
1152 { 'v', specifier_kernel_release, NULL },
1156 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1157 _cleanup_(item_freep) Item *i = NULL;
1168 "%ms %ms %ms %ms %ms %ms %n",
1177 log_error("[%s:%u] Syntax error.", fname, line);
1181 if (isempty(action)) {
1182 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1186 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1187 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1191 if (strchr(action+1, '!') && !arg_boot)
1200 i->force = !!strchr(action+1, '+');
1202 r = specifier_printf(path, specifier_table, NULL, &i->path);
1204 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1209 n += strspn(buffer+n, WHITESPACE);
1210 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1211 i->argument = unquote(buffer+n, "\"");
1221 case CREATE_DIRECTORY:
1222 case TRUNCATE_DIRECTORY:
1225 case IGNORE_DIRECTORY_PATH:
1227 case RECURSIVE_REMOVE_PATH:
1230 case RECURSIVE_RELABEL_PATH:
1233 case CREATE_SYMLINK:
1235 log_error("[%s:%u] Symlink file requires argument.", fname, line);
1243 log_error("[%s:%u] Write file requires argument.", fname, line);
1250 log_error("[%s:%u] Copy files requires argument.", fname, line);
1254 if (!path_is_absolute(i->argument)) {
1255 log_error("[%s:%u] Source path is not absolute.", fname, line);
1259 path_kill_slashes(i->argument);
1262 case CREATE_CHAR_DEVICE:
1263 case CREATE_BLOCK_DEVICE: {
1264 unsigned major, minor;
1267 log_error("[%s:%u] Device file requires argument.", fname, line);
1271 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1272 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1276 i->major_minor = makedev(major, minor);
1281 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1287 if (!path_is_absolute(i->path)) {
1288 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1292 path_kill_slashes(i->path);
1294 if (!should_include_path(i->path))
1300 p = strappend(arg_root, i->path);
1308 if (user && !streq(user, "-")) {
1309 const char *u = user;
1311 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1313 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1320 if (group && !streq(group, "-")) {
1321 const char *g = group;
1323 r = get_group_creds(&g, &i->gid);
1325 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1332 if (mode && !streq(mode, "-")) {
1333 const char *mm = mode;
1337 i->mask_perms = true;
1341 if (sscanf(mm, "%o", &m) != 1) {
1342 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1350 i->type == CREATE_DIRECTORY ||
1351 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1353 if (age && !streq(age, "-")) {
1354 const char *a = age;
1357 i->keep_first_level = true;
1361 if (parse_sec(a, &i->age) < 0) {
1362 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1369 h = needs_glob(i->type) ? globs : items;
1371 existing = hashmap_get(h, i->path);
1374 /* Two identical items are fine */
1375 if (!item_equal(existing, i))
1376 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1381 r = hashmap_put(h, i->path, i);
1383 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1387 i = NULL; /* avoid cleanup */
1392 static int help(void) {
1394 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1395 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1396 " -h --help Show this help\n"
1397 " --version Show package version\n"
1398 " --create Create marked files/directories\n"
1399 " --clean Clean up marked directories\n"
1400 " --remove Remove marked files/directories\n"
1401 " --boot Execute actions only safe at boot\n"
1402 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1403 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1404 " --root=PATH Operate on an alternate filesystem root\n",
1405 program_invocation_short_name);
1410 static int parse_argv(int argc, char *argv[]) {
1413 ARG_VERSION = 0x100,
1423 static const struct option options[] = {
1424 { "help", no_argument, NULL, 'h' },
1425 { "version", no_argument, NULL, ARG_VERSION },
1426 { "create", no_argument, NULL, ARG_CREATE },
1427 { "clean", no_argument, NULL, ARG_CLEAN },
1428 { "remove", no_argument, NULL, ARG_REMOVE },
1429 { "boot", no_argument, NULL, ARG_BOOT },
1430 { "prefix", required_argument, NULL, ARG_PREFIX },
1431 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1432 { "root", required_argument, NULL, ARG_ROOT },
1441 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1449 puts(PACKAGE_STRING);
1450 puts(SYSTEMD_FEATURES);
1470 if (strv_push(&arg_include_prefixes, optarg) < 0)
1474 case ARG_EXCLUDE_PREFIX:
1475 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1481 arg_root = path_make_absolute_cwd(optarg);
1485 path_kill_slashes(arg_root);
1492 assert_not_reached("Unhandled option");
1496 if (!arg_clean && !arg_create && !arg_remove) {
1497 log_error("You need to specify at least one of --clean, --create or --remove.");
1504 static int read_config_file(const char *fn, bool ignore_enoent) {
1505 _cleanup_fclose_ FILE *f = NULL;
1506 char line[LINE_MAX];
1514 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1516 if (ignore_enoent && r == -ENOENT)
1519 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1523 FOREACH_LINE(line, f, break) {
1530 if (*l == '#' || *l == 0)
1533 k = parse_line(fn, v, l);
1534 if (k < 0 && r == 0)
1538 /* we have to determine age parameter for each entry of type X */
1539 HASHMAP_FOREACH(i, globs, iterator) {
1541 Item *j, *candidate_item = NULL;
1543 if (i->type != IGNORE_DIRECTORY_PATH)
1546 HASHMAP_FOREACH(j, items, iter) {
1547 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1550 if (path_equal(j->path, i->path)) {
1555 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1556 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1560 if (candidate_item) {
1561 i->age = candidate_item->age;
1567 log_error("Failed to read from file %s: %m", fn);
1575 int main(int argc, char *argv[]) {
1580 r = parse_argv(argc, argv);
1584 log_set_target(LOG_TARGET_AUTO);
1585 log_parse_environment();
1592 items = hashmap_new(string_hash_func, string_compare_func);
1593 globs = hashmap_new(string_hash_func, string_compare_func);
1595 if (!items || !globs) {
1602 if (optind < argc) {
1605 for (j = optind; j < argc; j++) {
1606 k = read_config_file(argv[j], false);
1607 if (k < 0 && r == 0)
1612 _cleanup_strv_free_ char **files = NULL;
1615 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1617 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1621 STRV_FOREACH(f, files) {
1622 k = read_config_file(*f, true);
1623 if (k < 0 && r == 0)
1628 HASHMAP_FOREACH(i, globs, iterator)
1631 HASHMAP_FOREACH(i, items, iterator)
1635 while ((i = hashmap_steal_first(items)))
1638 while ((i = hashmap_steal_first(globs)))
1641 hashmap_free(items);
1642 hashmap_free(globs);
1644 free(arg_include_prefixes);
1645 free(arg_exclude_prefixes);
1648 set_free_free(unix_sockets);
1652 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;