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 i->argument = strappend("/usr/share/factory", i->path);
1260 log_error("[%s:%u] Write file requires argument.", fname, line);
1267 i->argument = strappend("/usr/share/factory", i->path);
1272 if (!path_is_absolute(i->argument)) {
1273 log_error("[%s:%u] Source path is not absolute.", fname, line);
1277 path_kill_slashes(i->argument);
1280 case CREATE_CHAR_DEVICE:
1281 case CREATE_BLOCK_DEVICE: {
1282 unsigned major, minor;
1285 log_error("[%s:%u] Device file requires argument.", fname, line);
1289 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1290 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1294 i->major_minor = makedev(major, minor);
1299 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1305 if (!path_is_absolute(i->path)) {
1306 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1310 path_kill_slashes(i->path);
1312 if (!should_include_path(i->path))
1318 p = strappend(arg_root, i->path);
1326 if (user && !streq(user, "-")) {
1327 const char *u = user;
1329 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1331 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1338 if (group && !streq(group, "-")) {
1339 const char *g = group;
1341 r = get_group_creds(&g, &i->gid);
1343 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1350 if (mode && !streq(mode, "-")) {
1351 const char *mm = mode;
1355 i->mask_perms = true;
1359 if (sscanf(mm, "%o", &m) != 1) {
1360 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1368 i->type == CREATE_DIRECTORY ||
1369 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1371 if (age && !streq(age, "-")) {
1372 const char *a = age;
1375 i->keep_first_level = true;
1379 if (parse_sec(a, &i->age) < 0) {
1380 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1387 h = needs_glob(i->type) ? globs : items;
1389 existing = hashmap_get(h, i->path);
1392 /* Two identical items are fine */
1393 if (!item_equal(existing, i))
1394 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1399 r = hashmap_put(h, i->path, i);
1401 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1405 i = NULL; /* avoid cleanup */
1410 static void 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);
1425 static int parse_argv(int argc, char *argv[]) {
1428 ARG_VERSION = 0x100,
1438 static const struct option options[] = {
1439 { "help", no_argument, NULL, 'h' },
1440 { "version", no_argument, NULL, ARG_VERSION },
1441 { "create", no_argument, NULL, ARG_CREATE },
1442 { "clean", no_argument, NULL, ARG_CLEAN },
1443 { "remove", no_argument, NULL, ARG_REMOVE },
1444 { "boot", no_argument, NULL, ARG_BOOT },
1445 { "prefix", required_argument, NULL, ARG_PREFIX },
1446 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1447 { "root", required_argument, NULL, ARG_ROOT },
1456 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1465 puts(PACKAGE_STRING);
1466 puts(SYSTEMD_FEATURES);
1486 if (strv_push(&arg_include_prefixes, optarg) < 0)
1490 case ARG_EXCLUDE_PREFIX:
1491 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1497 arg_root = path_make_absolute_cwd(optarg);
1501 path_kill_slashes(arg_root);
1508 assert_not_reached("Unhandled option");
1511 if (!arg_clean && !arg_create && !arg_remove) {
1512 log_error("You need to specify at least one of --clean, --create or --remove.");
1519 static int read_config_file(const char *fn, bool ignore_enoent) {
1520 _cleanup_fclose_ FILE *f = NULL;
1521 char line[LINE_MAX];
1529 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1531 if (ignore_enoent && r == -ENOENT)
1534 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1538 FOREACH_LINE(line, f, break) {
1545 if (*l == '#' || *l == 0)
1548 k = parse_line(fn, v, l);
1549 if (k < 0 && r == 0)
1553 /* we have to determine age parameter for each entry of type X */
1554 HASHMAP_FOREACH(i, globs, iterator) {
1556 Item *j, *candidate_item = NULL;
1558 if (i->type != IGNORE_DIRECTORY_PATH)
1561 HASHMAP_FOREACH(j, items, iter) {
1562 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1565 if (path_equal(j->path, i->path)) {
1570 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1571 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1575 if (candidate_item) {
1576 i->age = candidate_item->age;
1582 log_error("Failed to read from file %s: %m", fn);
1590 int main(int argc, char *argv[]) {
1595 r = parse_argv(argc, argv);
1599 log_set_target(LOG_TARGET_AUTO);
1600 log_parse_environment();
1607 items = hashmap_new(string_hash_func, string_compare_func);
1608 globs = hashmap_new(string_hash_func, string_compare_func);
1610 if (!items || !globs) {
1617 if (optind < argc) {
1620 for (j = optind; j < argc; j++) {
1621 k = read_config_file(argv[j], false);
1622 if (k < 0 && r == 0)
1627 _cleanup_strv_free_ char **files = NULL;
1630 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1632 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1636 STRV_FOREACH(f, files) {
1637 k = read_config_file(*f, true);
1638 if (k < 0 && r == 0)
1643 HASHMAP_FOREACH(i, globs, iterator)
1646 HASHMAP_FOREACH(i, items, iterator)
1650 while ((i = hashmap_steal_first(items)))
1653 while ((i = hashmap_steal_first(globs)))
1656 hashmap_free(items);
1657 hashmap_free(globs);
1659 free(arg_include_prefixes);
1660 free(arg_exclude_prefixes);
1663 set_free_free(unix_sockets);
1667 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;