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',
82 /* These ones take globs */
85 IGNORE_DIRECTORY_PATH = 'X',
87 RECURSIVE_REMOVE_PATH = 'R',
88 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
90 RECURSIVE_RELABEL_PATH = 'Z',
116 bool keep_first_level:1;
123 typedef struct ItemArray {
129 static bool arg_create = false;
130 static bool arg_clean = false;
131 static bool arg_remove = false;
132 static bool arg_boot = false;
134 static char **arg_include_prefixes = NULL;
135 static char **arg_exclude_prefixes = NULL;
136 static char *arg_root = NULL;
138 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
140 #define MAX_DEPTH 256
142 static Hashmap *items = NULL, *globs = NULL;
143 static Set *unix_sockets = NULL;
145 static bool needs_glob(ItemType t) {
149 IGNORE_DIRECTORY_PATH,
151 RECURSIVE_REMOVE_PATH,
154 RECURSIVE_RELABEL_PATH);
157 static bool takes_ownership(ItemType t) {
172 IGNORE_DIRECTORY_PATH,
174 RECURSIVE_REMOVE_PATH);
177 static struct Item* find_glob(Hashmap *h, const char *match) {
181 HASHMAP_FOREACH(j, h, i) {
184 for (n = 0; n < j->count; n++) {
185 Item *item = j->items + n;
187 if (fnmatch(item->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
195 static void load_unix_sockets(void) {
196 _cleanup_fclose_ FILE *f = NULL;
202 /* We maintain a cache of the sockets we found in
203 * /proc/net/unix to speed things up a little. */
205 unix_sockets = set_new(&string_hash_ops);
209 f = fopen("/proc/net/unix", "re");
214 if (!fgets(line, sizeof(line), f))
221 if (!fgets(line, sizeof(line), f))
226 p = strchr(line, ':');
234 p += strspn(p, WHITESPACE);
235 p += strcspn(p, WHITESPACE); /* skip one more word */
236 p += strspn(p, WHITESPACE);
245 path_kill_slashes(s);
247 k = set_consume(unix_sockets, s);
248 if (k < 0 && k != -EEXIST)
255 set_free_free(unix_sockets);
259 static bool unix_socket_alive(const char *fn) {
265 return !!set_get(unix_sockets, (char*) fn);
267 /* We don't know, so assume yes */
271 static int dir_is_mount_point(DIR *d, const char *subdir) {
273 union file_handle_union h = FILE_HANDLE_INIT;
274 int mount_id_parent, mount_id;
277 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
281 h.handle.handle_bytes = MAX_HANDLE_SZ;
282 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
286 /* got no handle; make no assumptions, return error */
287 if (r_p < 0 && r < 0)
290 /* got both handles; if they differ, it is a mount point */
291 if (r_p >= 0 && r >= 0)
292 return mount_id_parent != mount_id;
294 /* got only one handle; assume different mount points if one
295 * of both queries was not supported by the filesystem */
296 if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
305 static int dir_cleanup(
309 const struct stat *ds,
314 bool keep_this_level) {
317 struct timespec times[2];
318 bool deleted = false;
321 while ((dent = readdir(d))) {
324 _cleanup_free_ char *sub_path = NULL;
326 if (streq(dent->d_name, ".") ||
327 streq(dent->d_name, ".."))
330 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
334 /* FUSE, NFS mounts, SELinux might return EACCES */
336 log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
338 log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
343 /* Stay on the same filesystem */
344 if (s.st_dev != rootdev)
347 /* Try to detect bind mounts of the same filesystem instance; they
348 * do not differ in device major/minors. This type of query is not
349 * supported on all kernels or filesystem types though. */
350 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
353 /* Do not delete read-only files owned by root */
354 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
357 sub_path = strjoin(p, "/", dent->d_name, NULL);
363 /* Is there an item configured for this path? */
364 if (hashmap_get(items, sub_path))
367 if (find_glob(globs, sub_path))
370 if (S_ISDIR(s.st_mode)) {
373 streq(dent->d_name, "lost+found") &&
378 log_warning("Reached max depth on %s.", sub_path);
380 _cleanup_closedir_ DIR *sub_dir;
383 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
385 if (errno != ENOENT) {
386 log_error_errno(errno, "opendir(%s/%s) failed: %m", p, dent->d_name);
393 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
398 /* Note: if you are wondering why we don't
399 * support the sticky bit for excluding
400 * directories from cleaning like we do it for
401 * other file system objects: well, the sticky
402 * bit already has a meaning for directories,
403 * so we don't want to overload that. */
408 /* Ignore ctime, we change it when deleting */
409 age = MAX(timespec_load(&s.st_mtim),
410 timespec_load(&s.st_atim));
414 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
415 log_debug("rmdir '%s'", sub_path);
417 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
418 if (errno != ENOENT && errno != ENOTEMPTY) {
419 log_error_errno(errno, "rmdir(%s): %m", sub_path);
426 /* Skip files for which the sticky bit is
427 * set. These are semantics we define, and are
428 * unknown elsewhere. See XDG_RUNTIME_DIR
429 * specification for details. */
430 if (s.st_mode & S_ISVTX)
433 if (mountpoint && S_ISREG(s.st_mode)) {
434 if (streq(dent->d_name, ".journal") &&
438 if (streq(dent->d_name, "aquota.user") ||
439 streq(dent->d_name, "aquota.group"))
443 /* Ignore sockets that are listed in /proc/net/unix */
444 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
447 /* Ignore device nodes */
448 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
451 /* Keep files on this level around if this is
456 age = MAX3(timespec_load(&s.st_mtim),
457 timespec_load(&s.st_atim),
458 timespec_load(&s.st_ctim));
463 log_debug("unlink '%s'", sub_path);
465 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
466 if (errno != ENOENT) {
467 log_error_errno(errno, "unlink(%s): %m", sub_path);
478 /* Restore original directory timestamps */
479 times[0] = ds->st_atim;
480 times[1] = ds->st_mtim;
482 if (futimens(dirfd(d), times) < 0)
483 log_error_errno(errno, "utimensat(%s): %m", p);
489 static int item_set_perms(Item *i, const char *path) {
496 st_valid = stat(path, &st) == 0;
498 /* not using i->path directly because it may be a glob */
502 if (i->mask_perms && st_valid) {
503 if (!(st.st_mode & 0111))
505 if (!(st.st_mode & 0222))
507 if (!(st.st_mode & 0444))
509 if (!S_ISDIR(st.st_mode))
510 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
513 if (!st_valid || m != (st.st_mode & 07777)) {
514 if (chmod(path, m) < 0)
515 return log_error_errno(errno, "chmod(%s) failed: %m", path);
519 if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
520 (i->uid_set || i->gid_set))
522 i->uid_set ? i->uid : UID_INVALID,
523 i->gid_set ? i->gid : GID_INVALID) < 0)
525 return log_error_errno(errno, "chown(%s) failed: %m", path);
527 return label_fix(path, false, false);
530 static int get_xattrs_from_arg(Item *i) {
540 while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
541 _cleanup_free_ char *tmp = NULL, *name = NULL,
542 *value = NULL, *value2 = NULL, *_xattr = xattr;
544 r = split_pair(xattr, "=", &name, &value);
546 log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
550 if (strempty(name) || strempty(value)) {
551 log_warning("Malformed xattr found: \"%s\" - ignoring.", xattr);
555 tmp = unquote(value, "\"");
559 value2 = cunescape(tmp);
563 if (strv_push_pair(&i->xattrs, name, value2) < 0)
565 name = value2 = NULL;
571 static int item_set_xattrs(Item *i, const char *path) {
572 char **name, **value;
577 STRV_FOREACH_PAIR(name, value, i->xattrs) {
581 if (lsetxattr(path, *name, *value, n, 0) < 0) {
582 log_error("Setting extended attribute %s=%s on %s failed: %m",
583 *name, *value, path);
590 static int get_acls_from_arg(Item *item) {
593 _cleanup_(acl_freep) acl_t a = NULL, d = NULL;
597 r = parse_acl(item->argument, &item->acl_access, &item->acl_default);
599 log_warning_errno(errno, "Failed to parse ACL \"%s\": %m. Ignoring",
602 log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring");
608 static int item_set_acl(Item *item, const char *path) {
615 if (item->acl_access) {
616 r = acl_set_file(path, ACL_TYPE_ACCESS, item->acl_access);
618 _cleanup_(acl_free_charpp) char *t;
620 t = acl_to_any_text(item->acl_access, NULL, ',', TEXT_ABBREVIATE);
621 return log_error_errno(errno,
622 "Setting access ACL \"%s\" on %s failed: %m",
627 if (item->acl_default) {
628 r = acl_set_file(path, ACL_TYPE_DEFAULT, item->acl_default);
630 _cleanup_(acl_free_charpp) char *t;
632 t = acl_to_any_text(item->acl_default, NULL, ',', TEXT_ABBREVIATE);
633 return log_error_errno(errno,
634 "Setting default ACL \"%s\" on %s failed: %m",
643 static int write_one_file(Item *i, const char *path) {
644 _cleanup_close_ int fd = -1;
651 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
652 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
654 RUN_WITH_UMASK(0000) {
655 mac_selinux_create_file_prepare(path, S_IFREG);
656 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
657 mac_selinux_create_file_clear();
661 if (i->type == WRITE_FILE && errno == ENOENT)
664 log_error_errno(errno, "Failed to create file %s: %m", path);
669 _cleanup_free_ char *unescaped;
673 unescaped = cunescape(i->argument);
677 l = strlen(unescaped);
678 n = write(fd, unescaped, l);
680 if (n < 0 || (size_t) n < l) {
681 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
682 return n < 0 ? n : -EIO;
688 if (stat(path, &st) < 0)
689 return log_error_errno(errno, "stat(%s) failed: %m", path);
691 if (!S_ISREG(st.st_mode)) {
692 log_error("%s is not a file.", path);
696 r = item_set_perms(i, path);
703 static int item_set_perms_children(Item *i, const char *path) {
704 _cleanup_closedir_ DIR *d;
710 /* This returns the first error we run into, but nevertheless
715 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
718 _cleanup_free_ char *p = NULL;
725 if (errno != 0 && r == 0)
731 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
734 p = strjoin(path, "/", de->d_name, NULL);
738 q = item_set_perms(i, p);
739 if (q < 0 && q != -ENOENT && r == 0)
742 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
743 q = item_set_perms_children(i, p);
752 static int item_set_perms_recursive(Item *i, const char *path) {
758 r = item_set_perms(i, path);
762 q = item_set_perms_children(i, path);
769 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
770 _cleanup_globfree_ glob_t g = {};
775 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
776 if (k != 0 && k != GLOB_NOMATCH) {
780 log_error_errno(errno, "glob(%s) failed: %m", i->path);
784 STRV_FOREACH(fn, g.gl_pathv) {
793 static int create_item(Item *i) {
802 case IGNORE_DIRECTORY_PATH:
804 case RECURSIVE_REMOVE_PATH:
809 r = write_one_file(i, i->path);
815 r = copy_tree(i->argument, i->path, false);
820 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
822 if (stat(i->argument, &a) < 0)
823 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
825 if (stat(i->path, &b) < 0)
826 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
828 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
829 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
834 r = item_set_perms(i, i->path);
841 r = glob_item(i, write_one_file);
847 case CREATE_DIRECTORY:
848 case TRUNCATE_DIRECTORY:
849 case CREATE_SUBVOLUME:
852 mkdir_parents_label(i->path, 0755);
854 if (i->type == CREATE_SUBVOLUME) {
855 RUN_WITH_UMASK((~i->mode) & 0777)
856 r = btrfs_subvol_make(i->path);
860 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY) {
862 r = mkdir_label(i->path, i->mode);
867 return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
869 if (stat(i->path, &st) < 0)
870 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
872 if (!S_ISDIR(st.st_mode)) {
873 log_debug("%s already exists and is not a directory.", i->path);
878 r = item_set_perms(i, i->path);
886 RUN_WITH_UMASK(0000) {
887 mac_selinux_create_file_prepare(i->path, S_IFIFO);
888 r = mkfifo(i->path, i->mode);
889 mac_selinux_create_file_clear();
894 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
896 if (stat(i->path, &st) < 0)
897 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
899 if (!S_ISFIFO(st.st_mode)) {
903 RUN_WITH_UMASK(0000) {
904 mac_selinux_create_file_prepare(i->path, S_IFIFO);
905 r = mkfifo_atomic(i->path, i->mode);
906 mac_selinux_create_file_clear();
910 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
912 log_debug("%s is not a fifo.", i->path);
918 r = item_set_perms(i, i->path);
926 mac_selinux_create_file_prepare(i->path, S_IFLNK);
927 r = symlink(i->argument, i->path);
928 mac_selinux_create_file_clear();
931 _cleanup_free_ char *x = NULL;
934 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
936 r = readlink_malloc(i->path, &x);
937 if (r < 0 || !streq(i->argument, x)) {
940 mac_selinux_create_file_prepare(i->path, S_IFLNK);
941 r = symlink_atomic(i->argument, i->path);
942 mac_selinux_create_file_clear();
945 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
947 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
955 case CREATE_BLOCK_DEVICE:
956 case CREATE_CHAR_DEVICE: {
959 if (have_effective_cap(CAP_MKNOD) == 0) {
960 /* In a container we lack CAP_MKNOD. We
961 shouldn't attempt to create the device node in
962 that case to avoid noise, and we don't support
963 virtualized devices in containers anyway. */
965 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
969 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
971 RUN_WITH_UMASK(0000) {
972 mac_selinux_create_file_prepare(i->path, file_type);
973 r = mknod(i->path, i->mode | file_type, i->major_minor);
974 mac_selinux_create_file_clear();
978 if (errno == EPERM) {
979 log_debug("We lack permissions, possibly because of cgroup configuration; "
980 "skipping creation of device node %s.", i->path);
985 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
987 if (stat(i->path, &st) < 0)
988 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
990 if ((st.st_mode & S_IFMT) != file_type) {
994 RUN_WITH_UMASK(0000) {
995 mac_selinux_create_file_prepare(i->path, file_type);
996 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
997 mac_selinux_create_file_clear();
1001 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
1003 log_debug("%s is not a device node.", i->path);
1009 r = item_set_perms(i, i->path);
1019 r = glob_item(i, item_set_perms);
1024 case RECURSIVE_RELABEL_PATH:
1026 r = glob_item(i, item_set_perms_recursive);
1032 r = item_set_xattrs(i, i->path);
1038 r = item_set_acl(i, i->path);
1043 log_debug("%s created successfully.", i->path);
1048 static int remove_item_instance(Item *i, const char *instance) {
1057 case CREATE_DIRECTORY:
1058 case CREATE_SUBVOLUME:
1060 case CREATE_SYMLINK:
1061 case CREATE_BLOCK_DEVICE:
1062 case CREATE_CHAR_DEVICE:
1064 case IGNORE_DIRECTORY_PATH:
1067 case RECURSIVE_RELABEL_PATH:
1075 if (remove(instance) < 0 && errno != ENOENT)
1076 return log_error_errno(errno, "rm(%s): %m", instance);
1080 case TRUNCATE_DIRECTORY:
1081 case RECURSIVE_REMOVE_PATH:
1082 /* FIXME: we probably should use dir_cleanup() here
1083 * instead of rm_rf() so that 'x' is honoured. */
1084 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1085 if (r < 0 && r != -ENOENT)
1086 return log_error_errno(r, "rm_rf(%s): %m", instance);
1094 static int remove_item(Item *i) {
1103 case CREATE_DIRECTORY:
1104 case CREATE_SUBVOLUME:
1106 case CREATE_SYMLINK:
1107 case CREATE_CHAR_DEVICE:
1108 case CREATE_BLOCK_DEVICE:
1110 case IGNORE_DIRECTORY_PATH:
1113 case RECURSIVE_RELABEL_PATH:
1121 case TRUNCATE_DIRECTORY:
1122 case RECURSIVE_REMOVE_PATH:
1123 r = glob_item(i, remove_item_instance);
1130 static int clean_item_instance(Item *i, const char* instance) {
1131 _cleanup_closedir_ DIR *d = NULL;
1142 n = now(CLOCK_REALTIME);
1146 cutoff = n - i->age;
1148 d = opendir(instance);
1150 if (errno == ENOENT || errno == ENOTDIR)
1153 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1157 if (fstat(dirfd(d), &s) < 0)
1158 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1160 if (!S_ISDIR(s.st_mode)) {
1161 log_error("%s is not a directory.", i->path);
1165 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1166 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1168 mountpoint = s.st_dev != ps.st_dev ||
1169 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1171 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1172 MAX_DEPTH, i->keep_first_level);
1176 static int clean_item(Item *i) {
1182 case CREATE_DIRECTORY:
1183 case CREATE_SUBVOLUME:
1184 case TRUNCATE_DIRECTORY:
1187 clean_item_instance(i, i->path);
1189 case IGNORE_DIRECTORY_PATH:
1190 r = glob_item(i, clean_item_instance);
1199 static int process_item_array(ItemArray *array);
1201 static int process_item(Item *i) {
1203 _cleanup_free_ char *prefix = NULL;
1212 prefix = malloc(strlen(i->path) + 1);
1216 PATH_FOREACH_PREFIX(prefix, i->path) {
1219 j = hashmap_get(items, prefix);
1223 s = process_item_array(j);
1224 if (s < 0 && t == 0)
1229 r = arg_create ? create_item(i) : 0;
1230 q = arg_remove ? remove_item(i) : 0;
1231 p = arg_clean ? clean_item(i) : 0;
1239 static int process_item_array(ItemArray *array) {
1245 for (n = 0; n < array->count; n++) {
1246 k = process_item(array->items + n);
1247 if (k < 0 && r == 0)
1254 static void item_free_contents(Item *i) {
1258 strv_free(i->xattrs);
1261 acl_free(i->acl_access);
1262 acl_free(i->acl_default);
1266 static void item_array_free(ItemArray *a) {
1272 for (n = 0; n < a->count; n++)
1273 item_free_contents(a->items + n);
1278 static bool item_compatible(Item *a, Item *b) {
1281 assert(streq(a->path, b->path));
1283 if (takes_ownership(a->type) && takes_ownership(b->type))
1284 /* check if the items are the same */
1285 return streq_ptr(a->argument, b->argument) &&
1287 a->uid_set == b->uid_set &&
1290 a->gid_set == b->gid_set &&
1293 a->mode_set == b->mode_set &&
1294 a->mode == b->mode &&
1296 a->age_set == b->age_set &&
1299 a->mask_perms == b->mask_perms &&
1301 a->keep_first_level == b->keep_first_level &&
1303 a->major_minor == b->major_minor;
1308 static bool should_include_path(const char *path) {
1311 STRV_FOREACH(prefix, arg_exclude_prefixes)
1312 if (path_startswith(path, *prefix))
1315 STRV_FOREACH(prefix, arg_include_prefixes)
1316 if (path_startswith(path, *prefix))
1319 /* no matches, so we should include this path only if we
1320 * have no whitelist at all */
1321 return strv_length(arg_include_prefixes) == 0;
1324 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1326 static const Specifier specifier_table[] = {
1327 { 'm', specifier_machine_id, NULL },
1328 { 'b', specifier_boot_id, NULL },
1329 { 'H', specifier_host_name, NULL },
1330 { 'v', specifier_kernel_release, NULL },
1334 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1335 _cleanup_(item_free_contents) Item i = {};
1336 ItemArray *existing;
1339 bool force = false, boot = false;
1346 "%ms %ms %ms %ms %ms %ms %n",
1355 log_error("[%s:%u] Syntax error.", fname, line);
1359 if (isempty(action)) {
1360 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1364 for (pos = 1; action[pos]; pos++) {
1365 if (action[pos] == '!' && !boot)
1367 else if (action[pos] == '+' && !force)
1370 log_error("[%s:%u] Unknown modifiers in command '%s'",
1371 fname, line, action);
1376 if (boot && !arg_boot)
1382 r = specifier_printf(path, specifier_table, NULL, &i.path);
1384 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1389 c += strspn(buffer+c, WHITESPACE);
1390 if (buffer[c] != 0 && (buffer[c] != '-' || buffer[c+1] != 0)) {
1391 i.argument = unquote(buffer+c, "\"");
1401 case CREATE_DIRECTORY:
1402 case CREATE_SUBVOLUME:
1403 case TRUNCATE_DIRECTORY:
1406 case IGNORE_DIRECTORY_PATH:
1408 case RECURSIVE_REMOVE_PATH:
1411 case RECURSIVE_RELABEL_PATH:
1414 case CREATE_SYMLINK:
1416 i.argument = strappend("/usr/share/factory/", i.path);
1424 log_error("[%s:%u] Write file requires argument.", fname, line);
1431 i.argument = strappend("/usr/share/factory/", i.path);
1434 } else if (!path_is_absolute(i.argument)) {
1435 log_error("[%s:%u] Source path is not absolute.", fname, line);
1439 path_kill_slashes(i.argument);
1442 case CREATE_CHAR_DEVICE:
1443 case CREATE_BLOCK_DEVICE: {
1444 unsigned major, minor;
1447 log_error("[%s:%u] Device file requires argument.", fname, line);
1451 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1452 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1456 i.major_minor = makedev(major, minor);
1462 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1465 r = get_xattrs_from_arg(&i);
1472 log_error("[%s:%u] Set ACLs requires argument.", fname, line);
1475 r = get_acls_from_arg(&i);
1481 log_error("[%s:%u] Unknown command type '%c'.", fname, line, i.type);
1485 if (!path_is_absolute(i.path)) {
1486 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1490 path_kill_slashes(i.path);
1492 if (!should_include_path(i.path))
1498 p = strappend(arg_root, i.path);
1506 if (user && !streq(user, "-")) {
1507 const char *u = user;
1509 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1511 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1518 if (group && !streq(group, "-")) {
1519 const char *g = group;
1521 r = get_group_creds(&g, &i.gid);
1523 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1530 if (mode && !streq(mode, "-")) {
1531 const char *mm = mode;
1535 i.mask_perms = true;
1539 if (sscanf(mm, "%o", &m) != 1) {
1540 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1547 i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
1550 if (age && !streq(age, "-")) {
1551 const char *a = age;
1554 i.keep_first_level = true;
1558 if (parse_sec(a, &i.age) < 0) {
1559 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1566 h = needs_glob(i.type) ? globs : items;
1568 existing = hashmap_get(h, i.path);
1572 for (n = 0; n < existing->count; n++) {
1573 if (!item_compatible(existing->items + n, &i))
1574 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1575 fname, line, i.path);
1578 existing = new0(ItemArray, 1);
1579 r = hashmap_put(h, i.path, existing);
1584 if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
1587 memcpy(existing->items + existing->count++, &i, sizeof(i));
1592 static void help(void) {
1593 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1594 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1595 " -h --help Show this help\n"
1596 " --version Show package version\n"
1597 " --create Create marked files/directories\n"
1598 " --clean Clean up marked directories\n"
1599 " --remove Remove marked files/directories\n"
1600 " --boot Execute actions only safe at boot\n"
1601 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1602 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1603 " --root=PATH Operate on an alternate filesystem root\n",
1604 program_invocation_short_name);
1607 static int parse_argv(int argc, char *argv[]) {
1610 ARG_VERSION = 0x100,
1620 static const struct option options[] = {
1621 { "help", no_argument, NULL, 'h' },
1622 { "version", no_argument, NULL, ARG_VERSION },
1623 { "create", no_argument, NULL, ARG_CREATE },
1624 { "clean", no_argument, NULL, ARG_CLEAN },
1625 { "remove", no_argument, NULL, ARG_REMOVE },
1626 { "boot", no_argument, NULL, ARG_BOOT },
1627 { "prefix", required_argument, NULL, ARG_PREFIX },
1628 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1629 { "root", required_argument, NULL, ARG_ROOT },
1638 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1647 puts(PACKAGE_STRING);
1648 puts(SYSTEMD_FEATURES);
1668 if (strv_push(&arg_include_prefixes, optarg) < 0)
1672 case ARG_EXCLUDE_PREFIX:
1673 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1679 arg_root = path_make_absolute_cwd(optarg);
1683 path_kill_slashes(arg_root);
1690 assert_not_reached("Unhandled option");
1693 if (!arg_clean && !arg_create && !arg_remove) {
1694 log_error("You need to specify at least one of --clean, --create or --remove.");
1701 static int read_config_file(const char *fn, bool ignore_enoent) {
1702 _cleanup_fclose_ FILE *f = NULL;
1703 char line[LINE_MAX];
1711 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1713 if (ignore_enoent && r == -ENOENT)
1716 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1719 FOREACH_LINE(line, f, break) {
1726 if (*l == '#' || *l == 0)
1729 k = parse_line(fn, v, l);
1730 if (k < 0 && r == 0)
1734 /* we have to determine age parameter for each entry of type X */
1735 HASHMAP_FOREACH(i, globs, iterator) {
1737 Item *j, *candidate_item = NULL;
1739 if (i->type != IGNORE_DIRECTORY_PATH)
1742 HASHMAP_FOREACH(j, items, iter) {
1743 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1746 if (path_equal(j->path, i->path)) {
1751 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1752 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1756 if (candidate_item && candidate_item->age_set) {
1757 i->age = candidate_item->age;
1763 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1771 int main(int argc, char *argv[]) {
1776 r = parse_argv(argc, argv);
1780 log_set_target(LOG_TARGET_AUTO);
1781 log_parse_environment();
1786 mac_selinux_init(NULL);
1788 items = hashmap_new(&string_hash_ops);
1789 globs = hashmap_new(&string_hash_ops);
1791 if (!items || !globs) {
1798 if (optind < argc) {
1801 for (j = optind; j < argc; j++) {
1802 k = read_config_file(argv[j], false);
1803 if (k < 0 && r == 0)
1808 _cleanup_strv_free_ char **files = NULL;
1811 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1813 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1817 STRV_FOREACH(f, files) {
1818 k = read_config_file(*f, true);
1819 if (k < 0 && r == 0)
1824 HASHMAP_FOREACH(a, globs, iterator) {
1825 k = process_item_array(a);
1826 if (k < 0 && r == 0)
1830 HASHMAP_FOREACH(a, items, iterator) {
1831 k = process_item_array(a);
1832 if (k < 0 && r == 0)
1837 while ((a = hashmap_steal_first(items)))
1840 while ((a = hashmap_steal_first(globs)))
1843 hashmap_free(items);
1844 hashmap_free(globs);
1846 free(arg_include_prefixes);
1847 free(arg_exclude_prefixes);
1850 set_free_free(unix_sockets);
1852 mac_selinux_finish();
1854 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;