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
7 Copyright 2015 Zbigniew Jędrzejewski-Szmek
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/xattr.h>
49 #include "path-util.h"
53 #include "conf-files.h"
54 #include "capability.h"
55 #include "specifier.h"
58 #include "selinux-util.h"
59 #include "btrfs-util.h"
62 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
63 * them in the file system. This is intended to be used to create
64 * properly owned directories beneath /tmp, /var/tmp, /run, which are
65 * volatile and hence need to be recreated on bootup. */
67 typedef enum ItemType {
68 /* These ones take file names */
71 CREATE_DIRECTORY = 'd',
72 TRUNCATE_DIRECTORY = 'D',
73 CREATE_SUBVOLUME = 'v',
76 CREATE_CHAR_DEVICE = 'c',
77 CREATE_BLOCK_DEVICE = 'b',
80 /* These ones take globs */
82 RECURSIVE_SET_XATTR = 'T',
84 RECURSIVE_SET_ACL = 'A',
87 IGNORE_DIRECTORY_PATH = 'X',
89 RECURSIVE_REMOVE_PATH = 'R',
90 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
92 RECURSIVE_RELABEL_PATH = 'Z',
118 bool keep_first_level:1;
125 typedef struct ItemArray {
131 static bool arg_create = false;
132 static bool arg_clean = false;
133 static bool arg_remove = false;
134 static bool arg_boot = false;
136 static char **arg_include_prefixes = NULL;
137 static char **arg_exclude_prefixes = NULL;
138 static char *arg_root = NULL;
140 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
142 #define MAX_DEPTH 256
144 static Hashmap *items = NULL, *globs = NULL;
145 static Set *unix_sockets = NULL;
147 static bool needs_glob(ItemType t) {
151 IGNORE_DIRECTORY_PATH,
153 RECURSIVE_REMOVE_PATH,
156 RECURSIVE_RELABEL_PATH,
163 static bool takes_ownership(ItemType t) {
178 IGNORE_DIRECTORY_PATH,
180 RECURSIVE_REMOVE_PATH);
183 static struct Item* find_glob(Hashmap *h, const char *match) {
187 HASHMAP_FOREACH(j, h, i) {
190 for (n = 0; n < j->count; n++) {
191 Item *item = j->items + n;
193 if (fnmatch(item->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
201 static void load_unix_sockets(void) {
202 _cleanup_fclose_ FILE *f = NULL;
208 /* We maintain a cache of the sockets we found in
209 * /proc/net/unix to speed things up a little. */
211 unix_sockets = set_new(&string_hash_ops);
215 f = fopen("/proc/net/unix", "re");
220 if (!fgets(line, sizeof(line), f))
227 if (!fgets(line, sizeof(line), f))
232 p = strchr(line, ':');
240 p += strspn(p, WHITESPACE);
241 p += strcspn(p, WHITESPACE); /* skip one more word */
242 p += strspn(p, WHITESPACE);
251 path_kill_slashes(s);
253 k = set_consume(unix_sockets, s);
254 if (k < 0 && k != -EEXIST)
261 set_free_free(unix_sockets);
265 static bool unix_socket_alive(const char *fn) {
271 return !!set_get(unix_sockets, (char*) fn);
273 /* We don't know, so assume yes */
277 static int dir_is_mount_point(DIR *d, const char *subdir) {
279 union file_handle_union h = FILE_HANDLE_INIT;
280 int mount_id_parent, mount_id;
283 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
287 h.handle.handle_bytes = MAX_HANDLE_SZ;
288 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
292 /* got no handle; make no assumptions, return error */
293 if (r_p < 0 && r < 0)
296 /* got both handles; if they differ, it is a mount point */
297 if (r_p >= 0 && r >= 0)
298 return mount_id_parent != mount_id;
300 /* got only one handle; assume different mount points if one
301 * of both queries was not supported by the filesystem */
302 if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
311 static int dir_cleanup(
315 const struct stat *ds,
320 bool keep_this_level) {
323 struct timespec times[2];
324 bool deleted = false;
327 while ((dent = readdir(d))) {
330 _cleanup_free_ char *sub_path = NULL;
332 if (STR_IN_SET(dent->d_name, ".", ".."))
335 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
339 /* FUSE, NFS mounts, SELinux might return EACCES */
341 log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
343 log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
348 /* Stay on the same filesystem */
349 if (s.st_dev != rootdev)
352 /* Try to detect bind mounts of the same filesystem instance; they
353 * do not differ in device major/minors. This type of query is not
354 * supported on all kernels or filesystem types though. */
355 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
358 /* Do not delete read-only files owned by root */
359 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
362 sub_path = strjoin(p, "/", dent->d_name, NULL);
368 /* Is there an item configured for this path? */
369 if (hashmap_get(items, sub_path))
372 if (find_glob(globs, sub_path))
375 if (S_ISDIR(s.st_mode)) {
378 streq(dent->d_name, "lost+found") &&
383 log_warning("Reached max depth on %s.", sub_path);
385 _cleanup_closedir_ DIR *sub_dir;
388 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
390 if (errno != ENOENT) {
391 log_error_errno(errno, "opendir(%s/%s) failed: %m", p, dent->d_name);
398 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
403 /* Note: if you are wondering why we don't
404 * support the sticky bit for excluding
405 * directories from cleaning like we do it for
406 * other file system objects: well, the sticky
407 * bit already has a meaning for directories,
408 * so we don't want to overload that. */
413 /* Ignore ctime, we change it when deleting */
414 age = MAX(timespec_load(&s.st_mtim),
415 timespec_load(&s.st_atim));
419 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
420 log_debug("rmdir '%s'", sub_path);
422 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
423 if (errno != ENOENT && errno != ENOTEMPTY) {
424 log_error_errno(errno, "rmdir(%s): %m", sub_path);
431 /* Skip files for which the sticky bit is
432 * set. These are semantics we define, and are
433 * unknown elsewhere. See XDG_RUNTIME_DIR
434 * specification for details. */
435 if (s.st_mode & S_ISVTX)
438 if (mountpoint && S_ISREG(s.st_mode)) {
439 if (streq(dent->d_name, ".journal") &&
443 if (streq(dent->d_name, "aquota.user") ||
444 streq(dent->d_name, "aquota.group"))
448 /* Ignore sockets that are listed in /proc/net/unix */
449 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
452 /* Ignore device nodes */
453 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
456 /* Keep files on this level around if this is
461 age = MAX3(timespec_load(&s.st_mtim),
462 timespec_load(&s.st_atim),
463 timespec_load(&s.st_ctim));
468 log_debug("unlink '%s'", sub_path);
470 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
471 if (errno != ENOENT) {
472 log_error_errno(errno, "unlink(%s): %m", sub_path);
483 /* Restore original directory timestamps */
484 times[0] = ds->st_atim;
485 times[1] = ds->st_mtim;
487 if (futimens(dirfd(d), times) < 0)
488 log_error_errno(errno, "utimensat(%s): %m", p);
494 static int path_set_perms(Item *i, const char *path) {
501 st_valid = stat(path, &st) == 0;
503 /* not using i->path directly because it may be a glob */
507 if (i->mask_perms && st_valid) {
508 if (!(st.st_mode & 0111))
510 if (!(st.st_mode & 0222))
512 if (!(st.st_mode & 0444))
514 if (!S_ISDIR(st.st_mode))
515 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
518 if (!st_valid || m != (st.st_mode & 07777)) {
519 if (chmod(path, m) < 0)
520 return log_error_errno(errno, "chmod(%s) failed: %m", path);
524 if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
525 (i->uid_set || i->gid_set))
527 i->uid_set ? i->uid : UID_INVALID,
528 i->gid_set ? i->gid : GID_INVALID) < 0)
530 return log_error_errno(errno, "chown(%s) failed: %m", path);
532 return label_fix(path, false, false);
535 static int get_xattrs_from_arg(Item *i) {
545 while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
546 _cleanup_free_ char *tmp = NULL, *name = NULL,
547 *value = NULL, *value2 = NULL, *_xattr = xattr;
549 r = split_pair(xattr, "=", &name, &value);
551 log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
555 if (strempty(name) || strempty(value)) {
556 log_warning("Malformed xattr found: \"%s\" - ignoring.", xattr);
560 tmp = unquote(value, "\"");
564 value2 = cunescape(tmp);
568 if (strv_push_pair(&i->xattrs, name, value2) < 0)
570 name = value2 = NULL;
576 static int path_set_xattrs(Item *i, const char *path) {
577 char **name, **value;
582 STRV_FOREACH_PAIR(name, value, i->xattrs) {
586 if (lsetxattr(path, *name, *value, n, 0) < 0) {
587 log_error("Setting extended attribute %s=%s on %s failed: %m",
588 *name, *value, path);
595 static int get_acls_from_arg(Item *item) {
598 _cleanup_(acl_freep) acl_t a = NULL, d = NULL;
602 /* If force (= modify) is set, we will not modify the acl
603 * afterwards, so the mask can be added now if necessary. */
604 r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force);
606 log_warning_errno(errno, "Failed to parse ACL \"%s\": %m. Ignoring",
609 log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring");
615 static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) {
616 _cleanup_(acl_freep) acl_t dup = NULL;
620 r = acls_for_file(path, type, acl, &dup);
624 r = calc_acl_mask_if_needed(&dup);
632 /* the mask was already added earlier if needed */
635 r = add_base_acls_if_needed(&dup, path);
639 r = acl_set_file(path, type, dup);
641 _cleanup_(acl_free_charpp) char *t;
644 t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE);
646 "Setting %s ACL \"%s\" on %s failed: %m",
647 type == ACL_TYPE_ACCESS ? "access" : "default",
654 static int path_set_acls(Item *item, const char *path) {
661 if (item->acl_access) {
662 r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force);
667 if (item->acl_default) {
668 r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
677 static int write_one_file(Item *i, const char *path) {
678 _cleanup_close_ int fd = -1;
685 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
686 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
688 RUN_WITH_UMASK(0000) {
689 mac_selinux_create_file_prepare(path, S_IFREG);
690 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
691 mac_selinux_create_file_clear();
695 if (i->type == WRITE_FILE && errno == ENOENT)
698 log_error_errno(errno, "Failed to create file %s: %m", path);
703 _cleanup_free_ char *unescaped;
707 unescaped = cunescape(i->argument);
711 l = strlen(unescaped);
712 n = write(fd, unescaped, l);
714 if (n < 0 || (size_t) n < l) {
715 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
716 return n < 0 ? n : -EIO;
722 if (stat(path, &st) < 0)
723 return log_error_errno(errno, "stat(%s) failed: %m", path);
725 if (!S_ISREG(st.st_mode)) {
726 log_error("%s is not a file.", path);
730 r = path_set_perms(i, path);
737 typedef int (*action_t)(Item *, const char *);
739 static int item_do_children(Item *i, const char *path, action_t action) {
740 _cleanup_closedir_ DIR *d;
746 /* This returns the first error we run into, but nevertheless
751 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
754 _cleanup_free_ char *p = NULL;
761 if (errno != 0 && r == 0)
767 if (STR_IN_SET(de->d_name, ".", ".."))
770 p = strjoin(path, "/", de->d_name, NULL);
775 if (q < 0 && q != -ENOENT && r == 0)
778 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
779 q = item_do_children(i, p, action);
788 static int glob_item(Item *i, action_t action, bool recursive) {
789 _cleanup_globfree_ glob_t g = {};
794 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
795 if (k != 0 && k != GLOB_NOMATCH)
796 return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
798 STRV_FOREACH(fn, g.gl_pathv) {
804 k = item_do_children(i, *fn, action);
813 static int create_item(Item *i) {
822 case IGNORE_DIRECTORY_PATH:
824 case RECURSIVE_REMOVE_PATH:
829 r = write_one_file(i, i->path);
835 r = copy_tree(i->argument, i->path, false);
840 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
842 if (stat(i->argument, &a) < 0)
843 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
845 if (stat(i->path, &b) < 0)
846 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
848 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
849 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
854 r = path_set_perms(i, i->path);
861 r = glob_item(i, write_one_file, false);
867 case CREATE_DIRECTORY:
868 case TRUNCATE_DIRECTORY:
869 case CREATE_SUBVOLUME:
872 mkdir_parents_label(i->path, 0755);
874 if (i->type == CREATE_SUBVOLUME) {
875 RUN_WITH_UMASK((~i->mode) & 0777)
876 r = btrfs_subvol_make(i->path);
880 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY) {
882 r = mkdir_label(i->path, i->mode);
887 return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
889 if (stat(i->path, &st) < 0)
890 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
892 if (!S_ISDIR(st.st_mode)) {
893 log_debug("%s already exists and is not a directory.", i->path);
898 r = path_set_perms(i, i->path);
906 RUN_WITH_UMASK(0000) {
907 mac_selinux_create_file_prepare(i->path, S_IFIFO);
908 r = mkfifo(i->path, i->mode);
909 mac_selinux_create_file_clear();
914 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
916 if (stat(i->path, &st) < 0)
917 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
919 if (!S_ISFIFO(st.st_mode)) {
923 RUN_WITH_UMASK(0000) {
924 mac_selinux_create_file_prepare(i->path, S_IFIFO);
925 r = mkfifo_atomic(i->path, i->mode);
926 mac_selinux_create_file_clear();
930 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
932 log_debug("%s is not a fifo.", i->path);
938 r = path_set_perms(i, i->path);
946 mac_selinux_create_file_prepare(i->path, S_IFLNK);
947 r = symlink(i->argument, i->path);
948 mac_selinux_create_file_clear();
951 _cleanup_free_ char *x = NULL;
954 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
956 r = readlink_malloc(i->path, &x);
957 if (r < 0 || !streq(i->argument, x)) {
960 mac_selinux_create_file_prepare(i->path, S_IFLNK);
961 r = symlink_atomic(i->argument, i->path);
962 mac_selinux_create_file_clear();
965 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
967 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
975 case CREATE_BLOCK_DEVICE:
976 case CREATE_CHAR_DEVICE: {
979 if (have_effective_cap(CAP_MKNOD) == 0) {
980 /* In a container we lack CAP_MKNOD. We
981 shouldn't attempt to create the device node in
982 that case to avoid noise, and we don't support
983 virtualized devices in containers anyway. */
985 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
989 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
991 RUN_WITH_UMASK(0000) {
992 mac_selinux_create_file_prepare(i->path, file_type);
993 r = mknod(i->path, i->mode | file_type, i->major_minor);
994 mac_selinux_create_file_clear();
998 if (errno == EPERM) {
999 log_debug("We lack permissions, possibly because of cgroup configuration; "
1000 "skipping creation of device node %s.", i->path);
1004 if (errno != EEXIST)
1005 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
1007 if (stat(i->path, &st) < 0)
1008 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1010 if ((st.st_mode & S_IFMT) != file_type) {
1014 RUN_WITH_UMASK(0000) {
1015 mac_selinux_create_file_prepare(i->path, file_type);
1016 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
1017 mac_selinux_create_file_clear();
1021 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
1023 log_debug("%s is not a device node.", i->path);
1029 r = path_set_perms(i, i->path);
1038 r = glob_item(i, path_set_perms, false);
1043 case RECURSIVE_RELABEL_PATH:
1044 r = glob_item(i, path_set_perms, true);
1050 r = glob_item(i, path_set_xattrs, false);
1055 case RECURSIVE_SET_XATTR:
1056 r = glob_item(i, path_set_xattrs, true);
1062 r = glob_item(i, path_set_acls, false);
1067 case RECURSIVE_SET_ACL:
1068 r = glob_item(i, path_set_acls, true);
1074 log_debug("%s created successfully.", i->path);
1079 static int remove_item_instance(Item *i, const char *instance) {
1087 if (remove(instance) < 0 && errno != ENOENT)
1088 return log_error_errno(errno, "rm(%s): %m", instance);
1092 case TRUNCATE_DIRECTORY:
1093 case RECURSIVE_REMOVE_PATH:
1094 /* FIXME: we probably should use dir_cleanup() here
1095 * instead of rm_rf() so that 'x' is honoured. */
1096 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1097 if (r < 0 && r != -ENOENT)
1098 return log_error_errno(r, "rm_rf(%s): %m", instance);
1103 assert_not_reached("wut?");
1109 static int remove_item(Item *i) {
1118 case CREATE_DIRECTORY:
1119 case CREATE_SUBVOLUME:
1121 case CREATE_SYMLINK:
1122 case CREATE_CHAR_DEVICE:
1123 case CREATE_BLOCK_DEVICE:
1125 case IGNORE_DIRECTORY_PATH:
1128 case RECURSIVE_RELABEL_PATH:
1132 case RECURSIVE_SET_XATTR:
1134 case RECURSIVE_SET_ACL:
1138 case TRUNCATE_DIRECTORY:
1139 case RECURSIVE_REMOVE_PATH:
1140 r = glob_item(i, remove_item_instance, false);
1147 static int clean_item_instance(Item *i, const char* instance) {
1148 _cleanup_closedir_ DIR *d = NULL;
1159 n = now(CLOCK_REALTIME);
1163 cutoff = n - i->age;
1165 d = opendir(instance);
1167 if (errno == ENOENT || errno == ENOTDIR)
1170 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1174 if (fstat(dirfd(d), &s) < 0)
1175 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1177 if (!S_ISDIR(s.st_mode)) {
1178 log_error("%s is not a directory.", i->path);
1182 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1183 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1185 mountpoint = s.st_dev != ps.st_dev ||
1186 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1188 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1189 MAX_DEPTH, i->keep_first_level);
1193 static int clean_item(Item *i) {
1199 case CREATE_DIRECTORY:
1200 case CREATE_SUBVOLUME:
1201 case TRUNCATE_DIRECTORY:
1204 clean_item_instance(i, i->path);
1206 case IGNORE_DIRECTORY_PATH:
1207 r = glob_item(i, clean_item_instance, false);
1216 static int process_item_array(ItemArray *array);
1218 static int process_item(Item *i) {
1220 _cleanup_free_ char *prefix = NULL;
1229 prefix = malloc(strlen(i->path) + 1);
1233 PATH_FOREACH_PREFIX(prefix, i->path) {
1236 j = hashmap_get(items, prefix);
1240 s = process_item_array(j);
1241 if (s < 0 && t == 0)
1246 r = arg_create ? create_item(i) : 0;
1247 q = arg_remove ? remove_item(i) : 0;
1248 p = arg_clean ? clean_item(i) : 0;
1256 static int process_item_array(ItemArray *array) {
1262 for (n = 0; n < array->count; n++) {
1263 k = process_item(array->items + n);
1264 if (k < 0 && r == 0)
1271 static void item_free_contents(Item *i) {
1275 strv_free(i->xattrs);
1278 acl_free(i->acl_access);
1279 acl_free(i->acl_default);
1283 static void item_array_free(ItemArray *a) {
1289 for (n = 0; n < a->count; n++)
1290 item_free_contents(a->items + n);
1295 static bool item_compatible(Item *a, Item *b) {
1298 assert(streq(a->path, b->path));
1300 if (takes_ownership(a->type) && takes_ownership(b->type))
1301 /* check if the items are the same */
1302 return streq_ptr(a->argument, b->argument) &&
1304 a->uid_set == b->uid_set &&
1307 a->gid_set == b->gid_set &&
1310 a->mode_set == b->mode_set &&
1311 a->mode == b->mode &&
1313 a->age_set == b->age_set &&
1316 a->mask_perms == b->mask_perms &&
1318 a->keep_first_level == b->keep_first_level &&
1320 a->major_minor == b->major_minor;
1325 static bool should_include_path(const char *path) {
1328 STRV_FOREACH(prefix, arg_exclude_prefixes)
1329 if (path_startswith(path, *prefix))
1332 STRV_FOREACH(prefix, arg_include_prefixes)
1333 if (path_startswith(path, *prefix))
1336 /* no matches, so we should include this path only if we
1337 * have no whitelist at all */
1338 return strv_length(arg_include_prefixes) == 0;
1341 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1343 static const Specifier specifier_table[] = {
1344 { 'm', specifier_machine_id, NULL },
1345 { 'b', specifier_boot_id, NULL },
1346 { 'H', specifier_host_name, NULL },
1347 { 'v', specifier_kernel_release, NULL },
1351 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1352 _cleanup_(item_free_contents) Item i = {};
1353 ItemArray *existing;
1356 bool force = false, boot = false;
1363 "%ms %ms %ms %ms %ms %ms %n",
1372 log_error("[%s:%u] Syntax error.", fname, line);
1376 if (isempty(action)) {
1377 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1381 for (pos = 1; action[pos]; pos++) {
1382 if (action[pos] == '!' && !boot)
1384 else if (action[pos] == '+' && !force)
1387 log_error("[%s:%u] Unknown modifiers in command '%s'",
1388 fname, line, action);
1393 if (boot && !arg_boot)
1399 r = specifier_printf(path, specifier_table, NULL, &i.path);
1401 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1406 c += strspn(buffer+c, WHITESPACE);
1407 if (buffer[c] != 0 && (buffer[c] != '-' || buffer[c+1] != 0)) {
1408 i.argument = unquote(buffer+c, "\"");
1418 case CREATE_DIRECTORY:
1419 case CREATE_SUBVOLUME:
1420 case TRUNCATE_DIRECTORY:
1423 case IGNORE_DIRECTORY_PATH:
1425 case RECURSIVE_REMOVE_PATH:
1428 case RECURSIVE_RELABEL_PATH:
1431 case CREATE_SYMLINK:
1433 i.argument = strappend("/usr/share/factory/", i.path);
1441 log_error("[%s:%u] Write file requires argument.", fname, line);
1448 i.argument = strappend("/usr/share/factory/", i.path);
1451 } else if (!path_is_absolute(i.argument)) {
1452 log_error("[%s:%u] Source path is not absolute.", fname, line);
1456 path_kill_slashes(i.argument);
1459 case CREATE_CHAR_DEVICE:
1460 case CREATE_BLOCK_DEVICE: {
1461 unsigned major, minor;
1464 log_error("[%s:%u] Device file requires argument.", fname, line);
1468 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1469 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1473 i.major_minor = makedev(major, minor);
1478 case RECURSIVE_SET_XATTR:
1480 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1483 r = get_xattrs_from_arg(&i);
1489 case RECURSIVE_SET_ACL:
1491 log_error("[%s:%u] Set ACLs requires argument.", fname, line);
1494 r = get_acls_from_arg(&i);
1500 log_error("[%s:%u] Unknown command type '%c'.", fname, line, i.type);
1504 if (!path_is_absolute(i.path)) {
1505 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1509 path_kill_slashes(i.path);
1511 if (!should_include_path(i.path))
1517 p = strappend(arg_root, i.path);
1525 if (user && !streq(user, "-")) {
1526 const char *u = user;
1528 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1530 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1537 if (group && !streq(group, "-")) {
1538 const char *g = group;
1540 r = get_group_creds(&g, &i.gid);
1542 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1549 if (mode && !streq(mode, "-")) {
1550 const char *mm = mode;
1554 i.mask_perms = true;
1558 if (sscanf(mm, "%o", &m) != 1) {
1559 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1566 i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
1569 if (age && !streq(age, "-")) {
1570 const char *a = age;
1573 i.keep_first_level = true;
1577 if (parse_sec(a, &i.age) < 0) {
1578 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1585 h = needs_glob(i.type) ? globs : items;
1587 existing = hashmap_get(h, i.path);
1591 for (n = 0; n < existing->count; n++) {
1592 if (!item_compatible(existing->items + n, &i))
1593 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1594 fname, line, i.path);
1597 existing = new0(ItemArray, 1);
1598 r = hashmap_put(h, i.path, existing);
1603 if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
1606 memcpy(existing->items + existing->count++, &i, sizeof(i));
1611 static void help(void) {
1612 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1613 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1614 " -h --help Show this help\n"
1615 " --version Show package version\n"
1616 " --create Create marked files/directories\n"
1617 " --clean Clean up marked directories\n"
1618 " --remove Remove marked files/directories\n"
1619 " --boot Execute actions only safe at boot\n"
1620 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1621 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1622 " --root=PATH Operate on an alternate filesystem root\n",
1623 program_invocation_short_name);
1626 static int parse_argv(int argc, char *argv[]) {
1629 ARG_VERSION = 0x100,
1639 static const struct option options[] = {
1640 { "help", no_argument, NULL, 'h' },
1641 { "version", no_argument, NULL, ARG_VERSION },
1642 { "create", no_argument, NULL, ARG_CREATE },
1643 { "clean", no_argument, NULL, ARG_CLEAN },
1644 { "remove", no_argument, NULL, ARG_REMOVE },
1645 { "boot", no_argument, NULL, ARG_BOOT },
1646 { "prefix", required_argument, NULL, ARG_PREFIX },
1647 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1648 { "root", required_argument, NULL, ARG_ROOT },
1657 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1666 puts(PACKAGE_STRING);
1667 puts(SYSTEMD_FEATURES);
1687 if (strv_push(&arg_include_prefixes, optarg) < 0)
1691 case ARG_EXCLUDE_PREFIX:
1692 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1698 arg_root = path_make_absolute_cwd(optarg);
1702 path_kill_slashes(arg_root);
1709 assert_not_reached("Unhandled option");
1712 if (!arg_clean && !arg_create && !arg_remove) {
1713 log_error("You need to specify at least one of --clean, --create or --remove.");
1720 static int read_config_file(const char *fn, bool ignore_enoent) {
1721 _cleanup_fclose_ FILE *f = NULL;
1722 char line[LINE_MAX];
1730 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1732 if (ignore_enoent && r == -ENOENT)
1735 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1738 FOREACH_LINE(line, f, break) {
1745 if (*l == '#' || *l == 0)
1748 k = parse_line(fn, v, l);
1749 if (k < 0 && r == 0)
1753 /* we have to determine age parameter for each entry of type X */
1754 HASHMAP_FOREACH(i, globs, iterator) {
1756 Item *j, *candidate_item = NULL;
1758 if (i->type != IGNORE_DIRECTORY_PATH)
1761 HASHMAP_FOREACH(j, items, iter) {
1762 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1765 if (path_equal(j->path, i->path)) {
1770 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1771 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1775 if (candidate_item && candidate_item->age_set) {
1776 i->age = candidate_item->age;
1782 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1790 int main(int argc, char *argv[]) {
1795 r = parse_argv(argc, argv);
1799 log_set_target(LOG_TARGET_AUTO);
1800 log_parse_environment();
1805 mac_selinux_init(NULL);
1807 items = hashmap_new(&string_hash_ops);
1808 globs = hashmap_new(&string_hash_ops);
1810 if (!items || !globs) {
1817 if (optind < argc) {
1820 for (j = optind; j < argc; j++) {
1821 k = read_config_file(argv[j], false);
1822 if (k < 0 && r == 0)
1827 _cleanup_strv_free_ char **files = NULL;
1830 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1832 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1836 STRV_FOREACH(f, files) {
1837 k = read_config_file(*f, true);
1838 if (k < 0 && r == 0)
1843 HASHMAP_FOREACH(a, globs, iterator) {
1844 k = process_item_array(a);
1845 if (k < 0 && r == 0)
1849 HASHMAP_FOREACH(a, items, iterator) {
1850 k = process_item_array(a);
1851 if (k < 0 && r == 0)
1856 while ((a = hashmap_steal_first(items)))
1859 while ((a = hashmap_steal_first(globs)))
1862 hashmap_free(items);
1863 hashmap_free(globs);
1865 free(arg_include_prefixes);
1866 free(arg_exclude_prefixes);
1869 set_free_free(unix_sockets);
1871 mac_selinux_finish();
1873 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;