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 (streq(dent->d_name, ".") ||
333 streq(dent->d_name, ".."))
336 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
340 /* FUSE, NFS mounts, SELinux might return EACCES */
342 log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
344 log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
349 /* Stay on the same filesystem */
350 if (s.st_dev != rootdev)
353 /* Try to detect bind mounts of the same filesystem instance; they
354 * do not differ in device major/minors. This type of query is not
355 * supported on all kernels or filesystem types though. */
356 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
359 /* Do not delete read-only files owned by root */
360 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
363 sub_path = strjoin(p, "/", dent->d_name, NULL);
369 /* Is there an item configured for this path? */
370 if (hashmap_get(items, sub_path))
373 if (find_glob(globs, sub_path))
376 if (S_ISDIR(s.st_mode)) {
379 streq(dent->d_name, "lost+found") &&
384 log_warning("Reached max depth on %s.", sub_path);
386 _cleanup_closedir_ DIR *sub_dir;
389 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
391 if (errno != ENOENT) {
392 log_error_errno(errno, "opendir(%s/%s) failed: %m", p, dent->d_name);
399 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
404 /* Note: if you are wondering why we don't
405 * support the sticky bit for excluding
406 * directories from cleaning like we do it for
407 * other file system objects: well, the sticky
408 * bit already has a meaning for directories,
409 * so we don't want to overload that. */
414 /* Ignore ctime, we change it when deleting */
415 age = MAX(timespec_load(&s.st_mtim),
416 timespec_load(&s.st_atim));
420 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
421 log_debug("rmdir '%s'", sub_path);
423 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
424 if (errno != ENOENT && errno != ENOTEMPTY) {
425 log_error_errno(errno, "rmdir(%s): %m", sub_path);
432 /* Skip files for which the sticky bit is
433 * set. These are semantics we define, and are
434 * unknown elsewhere. See XDG_RUNTIME_DIR
435 * specification for details. */
436 if (s.st_mode & S_ISVTX)
439 if (mountpoint && S_ISREG(s.st_mode)) {
440 if (streq(dent->d_name, ".journal") &&
444 if (streq(dent->d_name, "aquota.user") ||
445 streq(dent->d_name, "aquota.group"))
449 /* Ignore sockets that are listed in /proc/net/unix */
450 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
453 /* Ignore device nodes */
454 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
457 /* Keep files on this level around if this is
462 age = MAX3(timespec_load(&s.st_mtim),
463 timespec_load(&s.st_atim),
464 timespec_load(&s.st_ctim));
469 log_debug("unlink '%s'", sub_path);
471 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
472 if (errno != ENOENT) {
473 log_error_errno(errno, "unlink(%s): %m", sub_path);
484 /* Restore original directory timestamps */
485 times[0] = ds->st_atim;
486 times[1] = ds->st_mtim;
488 if (futimens(dirfd(d), times) < 0)
489 log_error_errno(errno, "utimensat(%s): %m", p);
495 static int path_set_perms(Item *i, const char *path) {
502 st_valid = stat(path, &st) == 0;
504 /* not using i->path directly because it may be a glob */
508 if (i->mask_perms && st_valid) {
509 if (!(st.st_mode & 0111))
511 if (!(st.st_mode & 0222))
513 if (!(st.st_mode & 0444))
515 if (!S_ISDIR(st.st_mode))
516 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
519 if (!st_valid || m != (st.st_mode & 07777)) {
520 if (chmod(path, m) < 0)
521 return log_error_errno(errno, "chmod(%s) failed: %m", path);
525 if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
526 (i->uid_set || i->gid_set))
528 i->uid_set ? i->uid : UID_INVALID,
529 i->gid_set ? i->gid : GID_INVALID) < 0)
531 return log_error_errno(errno, "chown(%s) failed: %m", path);
533 return label_fix(path, false, false);
536 static int get_xattrs_from_arg(Item *i) {
546 while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
547 _cleanup_free_ char *tmp = NULL, *name = NULL,
548 *value = NULL, *value2 = NULL, *_xattr = xattr;
550 r = split_pair(xattr, "=", &name, &value);
552 log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
556 if (strempty(name) || strempty(value)) {
557 log_warning("Malformed xattr found: \"%s\" - ignoring.", xattr);
561 tmp = unquote(value, "\"");
565 value2 = cunescape(tmp);
569 if (strv_push_pair(&i->xattrs, name, value2) < 0)
571 name = value2 = NULL;
577 static int path_set_xattrs(Item *i, const char *path) {
578 char **name, **value;
583 STRV_FOREACH_PAIR(name, value, i->xattrs) {
587 if (lsetxattr(path, *name, *value, n, 0) < 0) {
588 log_error("Setting extended attribute %s=%s on %s failed: %m",
589 *name, *value, path);
596 static int get_acls_from_arg(Item *item) {
599 _cleanup_(acl_freep) acl_t a = NULL, d = NULL;
603 r = parse_acl(item->argument, &item->acl_access, &item->acl_default);
605 log_warning_errno(errno, "Failed to parse ACL \"%s\": %m. Ignoring",
608 log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring");
614 static int path_set_acls(Item *item, const char *path) {
621 if (item->acl_access) {
622 r = acl_set_file(path, ACL_TYPE_ACCESS, item->acl_access);
624 _cleanup_(acl_free_charpp) char *t;
626 t = acl_to_any_text(item->acl_access, NULL, ',', TEXT_ABBREVIATE);
627 return log_error_errno(errno,
628 "Setting access ACL \"%s\" on %s failed: %m",
633 if (item->acl_default) {
634 r = acl_set_file(path, ACL_TYPE_DEFAULT, item->acl_default);
636 _cleanup_(acl_free_charpp) char *t;
638 t = acl_to_any_text(item->acl_default, NULL, ',', TEXT_ABBREVIATE);
639 return log_error_errno(errno,
640 "Setting default ACL \"%s\" on %s failed: %m",
649 static int write_one_file(Item *i, const char *path) {
650 _cleanup_close_ int fd = -1;
657 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
658 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
660 RUN_WITH_UMASK(0000) {
661 mac_selinux_create_file_prepare(path, S_IFREG);
662 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
663 mac_selinux_create_file_clear();
667 if (i->type == WRITE_FILE && errno == ENOENT)
670 log_error_errno(errno, "Failed to create file %s: %m", path);
675 _cleanup_free_ char *unescaped;
679 unescaped = cunescape(i->argument);
683 l = strlen(unescaped);
684 n = write(fd, unescaped, l);
686 if (n < 0 || (size_t) n < l) {
687 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
688 return n < 0 ? n : -EIO;
694 if (stat(path, &st) < 0)
695 return log_error_errno(errno, "stat(%s) failed: %m", path);
697 if (!S_ISREG(st.st_mode)) {
698 log_error("%s is not a file.", path);
702 r = path_set_perms(i, path);
709 typedef int (*action_t)(Item *, const char *);
711 static int item_do_children(Item *i, const char *path, action_t action) {
712 _cleanup_closedir_ DIR *d;
718 /* This returns the first error we run into, but nevertheless
723 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
726 _cleanup_free_ char *p = NULL;
733 if (errno != 0 && r == 0)
739 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
742 p = strjoin(path, "/", de->d_name, NULL);
747 if (q < 0 && q != -ENOENT && r == 0)
750 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
751 q = item_do_children(i, p, action);
760 static int glob_item(Item *i, action_t action, bool recursive) {
761 _cleanup_globfree_ glob_t g = {};
766 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
767 if (k != 0 && k != GLOB_NOMATCH)
768 return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
770 STRV_FOREACH(fn, g.gl_pathv) {
776 k = item_do_children(i, *fn, action);
785 static int create_item(Item *i) {
794 case IGNORE_DIRECTORY_PATH:
796 case RECURSIVE_REMOVE_PATH:
801 r = write_one_file(i, i->path);
807 r = copy_tree(i->argument, i->path, false);
812 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
814 if (stat(i->argument, &a) < 0)
815 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
817 if (stat(i->path, &b) < 0)
818 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
820 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
821 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
826 r = path_set_perms(i, i->path);
833 r = glob_item(i, write_one_file, false);
839 case CREATE_DIRECTORY:
840 case TRUNCATE_DIRECTORY:
841 case CREATE_SUBVOLUME:
844 mkdir_parents_label(i->path, 0755);
846 if (i->type == CREATE_SUBVOLUME) {
847 RUN_WITH_UMASK((~i->mode) & 0777)
848 r = btrfs_subvol_make(i->path);
852 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY) {
854 r = mkdir_label(i->path, i->mode);
859 return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
861 if (stat(i->path, &st) < 0)
862 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
864 if (!S_ISDIR(st.st_mode)) {
865 log_debug("%s already exists and is not a directory.", i->path);
870 r = path_set_perms(i, i->path);
878 RUN_WITH_UMASK(0000) {
879 mac_selinux_create_file_prepare(i->path, S_IFIFO);
880 r = mkfifo(i->path, i->mode);
881 mac_selinux_create_file_clear();
886 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
888 if (stat(i->path, &st) < 0)
889 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
891 if (!S_ISFIFO(st.st_mode)) {
895 RUN_WITH_UMASK(0000) {
896 mac_selinux_create_file_prepare(i->path, S_IFIFO);
897 r = mkfifo_atomic(i->path, i->mode);
898 mac_selinux_create_file_clear();
902 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
904 log_debug("%s is not a fifo.", i->path);
910 r = path_set_perms(i, i->path);
918 mac_selinux_create_file_prepare(i->path, S_IFLNK);
919 r = symlink(i->argument, i->path);
920 mac_selinux_create_file_clear();
923 _cleanup_free_ char *x = NULL;
926 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
928 r = readlink_malloc(i->path, &x);
929 if (r < 0 || !streq(i->argument, x)) {
932 mac_selinux_create_file_prepare(i->path, S_IFLNK);
933 r = symlink_atomic(i->argument, i->path);
934 mac_selinux_create_file_clear();
937 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
939 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
947 case CREATE_BLOCK_DEVICE:
948 case CREATE_CHAR_DEVICE: {
951 if (have_effective_cap(CAP_MKNOD) == 0) {
952 /* In a container we lack CAP_MKNOD. We
953 shouldn't attempt to create the device node in
954 that case to avoid noise, and we don't support
955 virtualized devices in containers anyway. */
957 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
961 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
963 RUN_WITH_UMASK(0000) {
964 mac_selinux_create_file_prepare(i->path, file_type);
965 r = mknod(i->path, i->mode | file_type, i->major_minor);
966 mac_selinux_create_file_clear();
970 if (errno == EPERM) {
971 log_debug("We lack permissions, possibly because of cgroup configuration; "
972 "skipping creation of device node %s.", i->path);
977 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
979 if (stat(i->path, &st) < 0)
980 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
982 if ((st.st_mode & S_IFMT) != file_type) {
986 RUN_WITH_UMASK(0000) {
987 mac_selinux_create_file_prepare(i->path, file_type);
988 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
989 mac_selinux_create_file_clear();
993 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
995 log_debug("%s is not a device node.", i->path);
1001 r = path_set_perms(i, i->path);
1010 r = glob_item(i, path_set_perms, false);
1015 case RECURSIVE_RELABEL_PATH:
1016 r = glob_item(i, path_set_perms, true);
1022 r = glob_item(i, path_set_xattrs, false);
1027 case RECURSIVE_SET_XATTR:
1028 r = glob_item(i, path_set_xattrs, true);
1034 r = glob_item(i, path_set_acls, false);
1039 case RECURSIVE_SET_ACL:
1040 r = glob_item(i, path_set_acls, true);
1046 log_debug("%s created successfully.", i->path);
1051 static int remove_item_instance(Item *i, const char *instance) {
1060 case CREATE_DIRECTORY:
1061 case CREATE_SUBVOLUME:
1063 case CREATE_SYMLINK:
1064 case CREATE_BLOCK_DEVICE:
1065 case CREATE_CHAR_DEVICE:
1067 case IGNORE_DIRECTORY_PATH:
1070 case RECURSIVE_RELABEL_PATH:
1074 case RECURSIVE_SET_XATTR:
1076 case RECURSIVE_SET_ACL:
1080 if (remove(instance) < 0 && errno != ENOENT)
1081 return log_error_errno(errno, "rm(%s): %m", instance);
1085 case TRUNCATE_DIRECTORY:
1086 case RECURSIVE_REMOVE_PATH:
1087 /* FIXME: we probably should use dir_cleanup() here
1088 * instead of rm_rf() so that 'x' is honoured. */
1089 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1090 if (r < 0 && r != -ENOENT)
1091 return log_error_errno(r, "rm_rf(%s): %m", instance);
1099 static int remove_item(Item *i) {
1108 case CREATE_DIRECTORY:
1109 case CREATE_SUBVOLUME:
1111 case CREATE_SYMLINK:
1112 case CREATE_CHAR_DEVICE:
1113 case CREATE_BLOCK_DEVICE:
1115 case IGNORE_DIRECTORY_PATH:
1118 case RECURSIVE_RELABEL_PATH:
1122 case RECURSIVE_SET_XATTR:
1124 case RECURSIVE_SET_ACL:
1128 case TRUNCATE_DIRECTORY:
1129 case RECURSIVE_REMOVE_PATH:
1130 r = glob_item(i, remove_item_instance, false);
1137 static int clean_item_instance(Item *i, const char* instance) {
1138 _cleanup_closedir_ DIR *d = NULL;
1149 n = now(CLOCK_REALTIME);
1153 cutoff = n - i->age;
1155 d = opendir(instance);
1157 if (errno == ENOENT || errno == ENOTDIR)
1160 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1164 if (fstat(dirfd(d), &s) < 0)
1165 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1167 if (!S_ISDIR(s.st_mode)) {
1168 log_error("%s is not a directory.", i->path);
1172 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1173 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1175 mountpoint = s.st_dev != ps.st_dev ||
1176 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1178 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1179 MAX_DEPTH, i->keep_first_level);
1183 static int clean_item(Item *i) {
1189 case CREATE_DIRECTORY:
1190 case CREATE_SUBVOLUME:
1191 case TRUNCATE_DIRECTORY:
1194 clean_item_instance(i, i->path);
1196 case IGNORE_DIRECTORY_PATH:
1197 r = glob_item(i, clean_item_instance, false);
1206 static int process_item_array(ItemArray *array);
1208 static int process_item(Item *i) {
1210 _cleanup_free_ char *prefix = NULL;
1219 prefix = malloc(strlen(i->path) + 1);
1223 PATH_FOREACH_PREFIX(prefix, i->path) {
1226 j = hashmap_get(items, prefix);
1230 s = process_item_array(j);
1231 if (s < 0 && t == 0)
1236 r = arg_create ? create_item(i) : 0;
1237 q = arg_remove ? remove_item(i) : 0;
1238 p = arg_clean ? clean_item(i) : 0;
1246 static int process_item_array(ItemArray *array) {
1252 for (n = 0; n < array->count; n++) {
1253 k = process_item(array->items + n);
1254 if (k < 0 && r == 0)
1261 static void item_free_contents(Item *i) {
1265 strv_free(i->xattrs);
1268 acl_free(i->acl_access);
1269 acl_free(i->acl_default);
1273 static void item_array_free(ItemArray *a) {
1279 for (n = 0; n < a->count; n++)
1280 item_free_contents(a->items + n);
1285 static bool item_compatible(Item *a, Item *b) {
1288 assert(streq(a->path, b->path));
1290 if (takes_ownership(a->type) && takes_ownership(b->type))
1291 /* check if the items are the same */
1292 return streq_ptr(a->argument, b->argument) &&
1294 a->uid_set == b->uid_set &&
1297 a->gid_set == b->gid_set &&
1300 a->mode_set == b->mode_set &&
1301 a->mode == b->mode &&
1303 a->age_set == b->age_set &&
1306 a->mask_perms == b->mask_perms &&
1308 a->keep_first_level == b->keep_first_level &&
1310 a->major_minor == b->major_minor;
1315 static bool should_include_path(const char *path) {
1318 STRV_FOREACH(prefix, arg_exclude_prefixes)
1319 if (path_startswith(path, *prefix))
1322 STRV_FOREACH(prefix, arg_include_prefixes)
1323 if (path_startswith(path, *prefix))
1326 /* no matches, so we should include this path only if we
1327 * have no whitelist at all */
1328 return strv_length(arg_include_prefixes) == 0;
1331 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1333 static const Specifier specifier_table[] = {
1334 { 'm', specifier_machine_id, NULL },
1335 { 'b', specifier_boot_id, NULL },
1336 { 'H', specifier_host_name, NULL },
1337 { 'v', specifier_kernel_release, NULL },
1341 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1342 _cleanup_(item_free_contents) Item i = {};
1343 ItemArray *existing;
1346 bool force = false, boot = false;
1353 "%ms %ms %ms %ms %ms %ms %n",
1362 log_error("[%s:%u] Syntax error.", fname, line);
1366 if (isempty(action)) {
1367 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1371 for (pos = 1; action[pos]; pos++) {
1372 if (action[pos] == '!' && !boot)
1374 else if (action[pos] == '+' && !force)
1377 log_error("[%s:%u] Unknown modifiers in command '%s'",
1378 fname, line, action);
1383 if (boot && !arg_boot)
1389 r = specifier_printf(path, specifier_table, NULL, &i.path);
1391 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1396 c += strspn(buffer+c, WHITESPACE);
1397 if (buffer[c] != 0 && (buffer[c] != '-' || buffer[c+1] != 0)) {
1398 i.argument = unquote(buffer+c, "\"");
1408 case CREATE_DIRECTORY:
1409 case CREATE_SUBVOLUME:
1410 case TRUNCATE_DIRECTORY:
1413 case IGNORE_DIRECTORY_PATH:
1415 case RECURSIVE_REMOVE_PATH:
1418 case RECURSIVE_RELABEL_PATH:
1421 case CREATE_SYMLINK:
1423 i.argument = strappend("/usr/share/factory/", i.path);
1431 log_error("[%s:%u] Write file requires argument.", fname, line);
1438 i.argument = strappend("/usr/share/factory/", i.path);
1441 } else if (!path_is_absolute(i.argument)) {
1442 log_error("[%s:%u] Source path is not absolute.", fname, line);
1446 path_kill_slashes(i.argument);
1449 case CREATE_CHAR_DEVICE:
1450 case CREATE_BLOCK_DEVICE: {
1451 unsigned major, minor;
1454 log_error("[%s:%u] Device file requires argument.", fname, line);
1458 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1459 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1463 i.major_minor = makedev(major, minor);
1468 case RECURSIVE_SET_XATTR:
1470 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1473 r = get_xattrs_from_arg(&i);
1479 case RECURSIVE_SET_ACL:
1481 log_error("[%s:%u] Set ACLs requires argument.", fname, line);
1484 r = get_acls_from_arg(&i);
1490 log_error("[%s:%u] Unknown command type '%c'.", fname, line, i.type);
1494 if (!path_is_absolute(i.path)) {
1495 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1499 path_kill_slashes(i.path);
1501 if (!should_include_path(i.path))
1507 p = strappend(arg_root, i.path);
1515 if (user && !streq(user, "-")) {
1516 const char *u = user;
1518 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1520 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1527 if (group && !streq(group, "-")) {
1528 const char *g = group;
1530 r = get_group_creds(&g, &i.gid);
1532 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1539 if (mode && !streq(mode, "-")) {
1540 const char *mm = mode;
1544 i.mask_perms = true;
1548 if (sscanf(mm, "%o", &m) != 1) {
1549 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1556 i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
1559 if (age && !streq(age, "-")) {
1560 const char *a = age;
1563 i.keep_first_level = true;
1567 if (parse_sec(a, &i.age) < 0) {
1568 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1575 h = needs_glob(i.type) ? globs : items;
1577 existing = hashmap_get(h, i.path);
1581 for (n = 0; n < existing->count; n++) {
1582 if (!item_compatible(existing->items + n, &i))
1583 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1584 fname, line, i.path);
1587 existing = new0(ItemArray, 1);
1588 r = hashmap_put(h, i.path, existing);
1593 if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
1596 memcpy(existing->items + existing->count++, &i, sizeof(i));
1601 static void help(void) {
1602 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1603 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1604 " -h --help Show this help\n"
1605 " --version Show package version\n"
1606 " --create Create marked files/directories\n"
1607 " --clean Clean up marked directories\n"
1608 " --remove Remove marked files/directories\n"
1609 " --boot Execute actions only safe at boot\n"
1610 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1611 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1612 " --root=PATH Operate on an alternate filesystem root\n",
1613 program_invocation_short_name);
1616 static int parse_argv(int argc, char *argv[]) {
1619 ARG_VERSION = 0x100,
1629 static const struct option options[] = {
1630 { "help", no_argument, NULL, 'h' },
1631 { "version", no_argument, NULL, ARG_VERSION },
1632 { "create", no_argument, NULL, ARG_CREATE },
1633 { "clean", no_argument, NULL, ARG_CLEAN },
1634 { "remove", no_argument, NULL, ARG_REMOVE },
1635 { "boot", no_argument, NULL, ARG_BOOT },
1636 { "prefix", required_argument, NULL, ARG_PREFIX },
1637 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1638 { "root", required_argument, NULL, ARG_ROOT },
1647 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1656 puts(PACKAGE_STRING);
1657 puts(SYSTEMD_FEATURES);
1677 if (strv_push(&arg_include_prefixes, optarg) < 0)
1681 case ARG_EXCLUDE_PREFIX:
1682 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1688 arg_root = path_make_absolute_cwd(optarg);
1692 path_kill_slashes(arg_root);
1699 assert_not_reached("Unhandled option");
1702 if (!arg_clean && !arg_create && !arg_remove) {
1703 log_error("You need to specify at least one of --clean, --create or --remove.");
1710 static int read_config_file(const char *fn, bool ignore_enoent) {
1711 _cleanup_fclose_ FILE *f = NULL;
1712 char line[LINE_MAX];
1720 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1722 if (ignore_enoent && r == -ENOENT)
1725 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1728 FOREACH_LINE(line, f, break) {
1735 if (*l == '#' || *l == 0)
1738 k = parse_line(fn, v, l);
1739 if (k < 0 && r == 0)
1743 /* we have to determine age parameter for each entry of type X */
1744 HASHMAP_FOREACH(i, globs, iterator) {
1746 Item *j, *candidate_item = NULL;
1748 if (i->type != IGNORE_DIRECTORY_PATH)
1751 HASHMAP_FOREACH(j, items, iter) {
1752 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1755 if (path_equal(j->path, i->path)) {
1760 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1761 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1765 if (candidate_item && candidate_item->age_set) {
1766 i->age = candidate_item->age;
1772 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1780 int main(int argc, char *argv[]) {
1785 r = parse_argv(argc, argv);
1789 log_set_target(LOG_TARGET_AUTO);
1790 log_parse_environment();
1795 mac_selinux_init(NULL);
1797 items = hashmap_new(&string_hash_ops);
1798 globs = hashmap_new(&string_hash_ops);
1800 if (!items || !globs) {
1807 if (optind < argc) {
1810 for (j = optind; j < argc; j++) {
1811 k = read_config_file(argv[j], false);
1812 if (k < 0 && r == 0)
1817 _cleanup_strv_free_ char **files = NULL;
1820 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1822 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1826 STRV_FOREACH(f, files) {
1827 k = read_config_file(*f, true);
1828 if (k < 0 && r == 0)
1833 HASHMAP_FOREACH(a, globs, iterator) {
1834 k = process_item_array(a);
1835 if (k < 0 && r == 0)
1839 HASHMAP_FOREACH(a, items, iterator) {
1840 k = process_item_array(a);
1841 if (k < 0 && r == 0)
1846 while ((a = hashmap_steal_first(items)))
1849 while ((a = hashmap_steal_first(globs)))
1852 hashmap_free(items);
1853 hashmap_free(globs);
1855 free(arg_include_prefixes);
1856 free(arg_exclude_prefixes);
1859 set_free_free(unix_sockets);
1861 mac_selinux_finish();
1863 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;