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) {
350 log_debug("Ignoring \"%s/%s\": different filesystem.", p, dent->d_name);
354 /* Try to detect bind mounts of the same filesystem instance; they
355 * do not differ in device major/minors. This type of query is not
356 * supported on all kernels or filesystem types though. */
357 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0) {
358 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
363 /* Do not delete read-only files owned by root */
364 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR)) {
365 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p, dent->d_name);
369 sub_path = strjoin(p, "/", dent->d_name, NULL);
375 /* Is there an item configured for this path? */
376 if (hashmap_get(items, sub_path)) {
377 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path);
381 if (find_glob(globs, sub_path)) {
382 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path);
386 if (S_ISDIR(s.st_mode)) {
389 streq(dent->d_name, "lost+found") &&
391 log_debug("Ignoring \"%s\".", sub_path);
396 log_warning("Reached max depth on \"%s\".", sub_path);
398 _cleanup_closedir_ DIR *sub_dir;
401 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
404 r = log_error_errno(errno, "opendir(%s) failed: %m", sub_path);
409 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
414 /* Note: if you are wondering why we don't
415 * support the sticky bit for excluding
416 * directories from cleaning like we do it for
417 * other file system objects: well, the sticky
418 * bit already has a meaning for directories,
419 * so we don't want to overload that. */
421 if (keep_this_level) {
422 log_debug("Keeping \"%s\".", sub_path);
426 /* Ignore ctime, we change it when deleting */
427 age = timespec_load(&s.st_mtim);
429 char a[FORMAT_TIMESTAMP_MAX];
430 /* Follows spelling in stat(1). */
431 log_debug("Directory \"%s\": modify time %s is too new.",
433 format_timestamp_us(a, sizeof(a), age));
437 age = timespec_load(&s.st_atim);
439 char a[FORMAT_TIMESTAMP_MAX];
440 log_debug("Directory \"%s\": access time %s is too new.",
442 format_timestamp_us(a, sizeof(a), age));
446 if (i->type == IGNORE_DIRECTORY_PATH && streq(dent->d_name, p))
447 log_debug("Ignoring directory \"%s\"", sub_path);
449 log_debug("Removing directory \"%s\".", sub_path);
451 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
452 if (errno != ENOENT && errno != ENOTEMPTY) {
453 log_error_errno(errno, "rmdir(%s): %m", sub_path);
460 /* Skip files for which the sticky bit is
461 * set. These are semantics we define, and are
462 * unknown elsewhere. See XDG_RUNTIME_DIR
463 * specification for details. */
464 if (s.st_mode & S_ISVTX) {
465 log_debug("Skipping \"%s\": sticky bit set.", sub_path);
469 if (mountpoint && S_ISREG(s.st_mode))
470 if ((streq(dent->d_name, ".journal") && s.st_uid == 0) ||
471 streq(dent->d_name, "aquota.user") ||
472 streq(dent->d_name, "aquota.group")) {
473 log_debug("Skipping \"%s\".", sub_path);
477 /* Ignore sockets that are listed in /proc/net/unix */
478 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path)) {
479 log_debug("Skipping \"%s\": live socket.", sub_path);
483 /* Ignore device nodes */
484 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode)) {
485 log_debug("Skipping \"%s\": a device.", sub_path);
489 /* Keep files on this level around if this is
491 if (keep_this_level) {
492 log_debug("Keeping \"%s\".", sub_path);
496 age = timespec_load(&s.st_mtim);
498 char a[FORMAT_TIMESTAMP_MAX];
499 /* Follows spelling in stat(1). */
500 log_debug("File \"%s\": modify time %s is too new.",
502 format_timestamp_us(a, sizeof(a), age));
506 age = timespec_load(&s.st_atim);
508 char a[FORMAT_TIMESTAMP_MAX];
509 log_debug("File \"%s\": access time %s is too new.",
511 format_timestamp_us(a, sizeof(a), age));
515 age = timespec_load(&s.st_ctim);
517 char a[FORMAT_TIMESTAMP_MAX];
518 log_debug("File \"%s\": change time %s is too new.",
520 format_timestamp_us(a, sizeof(a), age));
524 log_debug("unlink \"%s\"", sub_path);
526 if (unlinkat(dirfd(d), dent->d_name, 0) < 0)
528 r = log_error_errno(errno, "unlink(%s): %m", sub_path);
537 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
539 /* Restore original directory timestamps */
540 times[0] = ds->st_atim;
541 times[1] = ds->st_mtim;
543 age1 = timespec_load(&ds->st_atim);
544 age2 = timespec_load(&ds->st_mtim);
545 log_debug("Restoring access and modification time on \"%s\": %s, %s",
547 format_timestamp_us(a, sizeof(a), age1),
548 format_timestamp_us(b, sizeof(b), age2));
549 if (futimens(dirfd(d), times) < 0)
550 log_error_errno(errno, "utimensat(%s): %m", p);
556 static int path_set_perms(Item *i, const char *path) {
563 st_valid = stat(path, &st) == 0;
565 /* not using i->path directly because it may be a glob */
569 if (i->mask_perms && st_valid) {
570 if (!(st.st_mode & 0111))
572 if (!(st.st_mode & 0222))
574 if (!(st.st_mode & 0444))
576 if (!S_ISDIR(st.st_mode))
577 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
580 if (st_valid && m == (st.st_mode & 07777))
581 log_debug("\"%s\" has right mode %o", path, st.st_mode);
583 log_debug("chmod \"%s\" to mode %o", path, m);
584 if (chmod(path, m) < 0)
585 return log_error_errno(errno, "chmod(%s) failed: %m", path);
589 if ((!st_valid || i->uid != st.st_uid || i->gid != st.st_gid) &&
590 (i->uid_set || i->gid_set)) {
591 log_debug("chown \"%s\" to "UID_FMT"."GID_FMT,
593 i->uid_set ? i->uid : UID_INVALID,
594 i->gid_set ? i->gid : GID_INVALID);
596 i->uid_set ? i->uid : UID_INVALID,
597 i->gid_set ? i->gid : GID_INVALID) < 0)
599 return log_error_errno(errno, "chown(%s) failed: %m", path);
602 return label_fix(path, false, false);
605 static int get_xattrs_from_arg(Item *i) {
615 while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
616 _cleanup_free_ char *tmp = NULL, *name = NULL,
617 *value = NULL, *value2 = NULL, *_xattr = xattr;
619 r = split_pair(xattr, "=", &name, &value);
621 log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
625 if (strempty(name) || strempty(value)) {
626 log_warning("Malformed xattr found: \"%s\" - ignoring.", xattr);
630 tmp = unquote(value, "\"");
634 value2 = cunescape(tmp);
638 if (strv_push_pair(&i->xattrs, name, value2) < 0)
640 name = value2 = NULL;
646 static int path_set_xattrs(Item *i, const char *path) {
647 char **name, **value;
652 STRV_FOREACH_PAIR(name, value, i->xattrs) {
656 log_debug("\"%s\": setting xattr \"%s=%s\"", path, *name, *value);
657 if (lsetxattr(path, *name, *value, n, 0) < 0) {
658 log_error("Setting extended attribute %s=%s on %s failed: %m",
659 *name, *value, path);
666 static int get_acls_from_arg(Item *item) {
669 _cleanup_(acl_freep) acl_t a = NULL, d = NULL;
673 /* If force (= modify) is set, we will not modify the acl
674 * afterwards, so the mask can be added now if necessary. */
675 r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force);
677 log_warning_errno(errno, "Failed to parse ACL \"%s\": %m. Ignoring",
680 log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring");
686 static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) {
687 _cleanup_(acl_freep) acl_t dup = NULL;
689 _cleanup_(acl_free_charpp) char *t = NULL;
692 r = acls_for_file(path, type, acl, &dup);
696 r = calc_acl_mask_if_needed(&dup);
704 /* the mask was already added earlier if needed */
707 r = add_base_acls_if_needed(&dup, path);
711 t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE);
712 log_debug("\"%s\": setting %s ACL \"%s\"", path,
713 type == ACL_TYPE_ACCESS ? "access" : "default",
716 r = acl_set_file(path, type, dup);
718 return log_error_errno(-errno,
719 "Setting %s ACL \"%s\" on %s failed: %m",
720 type == ACL_TYPE_ACCESS ? "access" : "default",
725 static int path_set_acls(Item *item, const char *path) {
732 if (item->acl_access) {
733 r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force);
738 if (item->acl_default) {
739 r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
748 static int write_one_file(Item *i, const char *path) {
749 _cleanup_close_ int fd = -1;
756 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
757 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
759 RUN_WITH_UMASK(0000) {
760 mac_selinux_create_file_prepare(path, S_IFREG);
761 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
762 mac_selinux_create_file_clear();
766 if (i->type == WRITE_FILE && errno == ENOENT) {
767 log_debug_errno(errno, "Not writing \"%s\": %m", path);
771 log_error_errno(errno, "Failed to create file %s: %m", path);
776 _cleanup_free_ char *unescaped;
778 log_debug("%s to \"%s\".",
779 i->type == CREATE_FILE ? "Appending" : "Writing", path);
781 unescaped = cunescape(i->argument);
785 r = loop_write(fd, unescaped, strlen(unescaped), false);
787 return log_error_errno(r, "Failed to write file \"%s\": %m", path);
789 log_debug("\"%s\" has been created.", path);
793 if (stat(path, &st) < 0)
794 return log_error_errno(errno, "stat(%s) failed: %m", path);
796 if (!S_ISREG(st.st_mode)) {
797 log_error("%s is not a file.", path);
801 r = path_set_perms(i, path);
808 typedef int (*action_t)(Item *, const char *);
810 static int item_do_children(Item *i, const char *path, action_t action) {
811 _cleanup_closedir_ DIR *d;
817 /* This returns the first error we run into, but nevertheless
822 log_debug_errno(errno, "Cannot open directory \"%s\": %m", path);
823 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
827 _cleanup_free_ char *p = NULL;
834 if (errno != 0 && r == 0)
840 if (STR_IN_SET(de->d_name, ".", ".."))
843 p = strjoin(path, "/", de->d_name, NULL);
848 if (q < 0 && q != -ENOENT && r == 0)
851 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
852 q = item_do_children(i, p, action);
861 static int glob_item(Item *i, action_t action, bool recursive) {
862 _cleanup_globfree_ glob_t g = {};
867 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
868 if (k != 0 && k != GLOB_NOMATCH)
869 return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
871 STRV_FOREACH(fn, g.gl_pathv) {
877 k = item_do_children(i, *fn, action);
886 static int create_item(Item *i) {
892 log_debug("Running create action for entry %c %s", (char) i->type, i->path);
897 case IGNORE_DIRECTORY_PATH:
899 case RECURSIVE_REMOVE_PATH:
904 r = write_one_file(i, i->path);
910 log_debug("Copying tree \"%s\" to \"%s\".", i->argument, i->path);
911 r = copy_tree(i->argument, i->path, false);
916 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
918 if (stat(i->argument, &a) < 0)
919 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
921 if (stat(i->path, &b) < 0)
922 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
924 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
925 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
930 r = path_set_perms(i, i->path);
937 r = glob_item(i, write_one_file, false);
943 case CREATE_DIRECTORY:
944 case TRUNCATE_DIRECTORY:
945 case CREATE_SUBVOLUME:
948 mkdir_parents_label(i->path, 0755);
950 if (i->type == CREATE_SUBVOLUME)
951 RUN_WITH_UMASK((~i->mode) & 0777) {
952 r = btrfs_subvol_make(i->path);
953 log_debug_errno(r, "Creating subvolume \"%s\": %m", i->path);
958 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY)
960 r = mkdir_label(i->path, i->mode);
964 return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path);
966 if (stat(i->path, &st) < 0)
967 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
969 if (!S_ISDIR(st.st_mode)) {
970 log_debug("\"%s\" already exists and is not a directory.", i->path);
974 log_debug("Created directory \"%s\".", i->path);
976 r = path_set_perms(i, i->path);
984 RUN_WITH_UMASK(0000) {
985 mac_selinux_create_file_prepare(i->path, S_IFIFO);
986 r = mkfifo(i->path, i->mode);
987 mac_selinux_create_file_clear();
992 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
994 if (stat(i->path, &st) < 0)
995 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
997 if (!S_ISFIFO(st.st_mode)) {
1001 RUN_WITH_UMASK(0000) {
1002 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1003 r = mkfifo_atomic(i->path, i->mode);
1004 mac_selinux_create_file_clear();
1008 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
1010 log_debug("%s is not a fifo.", i->path);
1015 log_debug("Created fifo \"%s\".", i->path);
1017 r = path_set_perms(i, i->path);
1023 case CREATE_SYMLINK:
1025 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1026 r = symlink(i->argument, i->path);
1027 mac_selinux_create_file_clear();
1030 _cleanup_free_ char *x = NULL;
1032 if (errno != EEXIST)
1033 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
1035 r = readlink_malloc(i->path, &x);
1036 if (r < 0 || !streq(i->argument, x)) {
1039 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1040 r = symlink_atomic(i->argument, i->path);
1041 mac_selinux_create_file_clear();
1044 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
1046 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i->path);
1051 log_debug("Created symlink \"%s\".", i->path);
1055 case CREATE_BLOCK_DEVICE:
1056 case CREATE_CHAR_DEVICE: {
1059 if (have_effective_cap(CAP_MKNOD) == 0) {
1060 /* In a container we lack CAP_MKNOD. We
1061 shouldn't attempt to create the device node in
1062 that case to avoid noise, and we don't support
1063 virtualized devices in containers anyway. */
1065 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
1069 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
1071 RUN_WITH_UMASK(0000) {
1072 mac_selinux_create_file_prepare(i->path, file_type);
1073 r = mknod(i->path, i->mode | file_type, i->major_minor);
1074 mac_selinux_create_file_clear();
1078 if (errno == EPERM) {
1079 log_debug("We lack permissions, possibly because of cgroup configuration; "
1080 "skipping creation of device node %s.", i->path);
1084 if (errno != EEXIST)
1085 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
1087 if (stat(i->path, &st) < 0)
1088 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1090 if ((st.st_mode & S_IFMT) != file_type) {
1094 RUN_WITH_UMASK(0000) {
1095 mac_selinux_create_file_prepare(i->path, file_type);
1096 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
1097 mac_selinux_create_file_clear();
1101 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
1103 log_debug("%s is not a device node.", i->path);
1108 log_debug("Created %s device node \"%s\" %u:%u.",
1109 i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
1110 i->path, major(i->mode), minor(i->mode));
1112 r = path_set_perms(i, i->path);
1121 r = glob_item(i, path_set_perms, false);
1126 case RECURSIVE_RELABEL_PATH:
1127 r = glob_item(i, path_set_perms, true);
1133 r = glob_item(i, path_set_xattrs, false);
1138 case RECURSIVE_SET_XATTR:
1139 r = glob_item(i, path_set_xattrs, true);
1145 r = glob_item(i, path_set_acls, false);
1150 case RECURSIVE_SET_ACL:
1151 r = glob_item(i, path_set_acls, true);
1157 log_debug("%s created successfully.", i->path);
1162 static int remove_item_instance(Item *i, const char *instance) {
1170 if (remove(instance) < 0 && errno != ENOENT)
1171 return log_error_errno(errno, "rm(%s): %m", instance);
1175 case TRUNCATE_DIRECTORY:
1176 case RECURSIVE_REMOVE_PATH:
1177 /* FIXME: we probably should use dir_cleanup() here
1178 * instead of rm_rf() so that 'x' is honoured. */
1179 log_debug("rm -rf \"%s\"", instance);
1180 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1181 if (r < 0 && r != -ENOENT)
1182 return log_error_errno(r, "rm_rf(%s): %m", instance);
1187 assert_not_reached("wut?");
1193 static int remove_item(Item *i) {
1198 log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
1204 case CREATE_DIRECTORY:
1205 case CREATE_SUBVOLUME:
1207 case CREATE_SYMLINK:
1208 case CREATE_CHAR_DEVICE:
1209 case CREATE_BLOCK_DEVICE:
1211 case IGNORE_DIRECTORY_PATH:
1214 case RECURSIVE_RELABEL_PATH:
1218 case RECURSIVE_SET_XATTR:
1220 case RECURSIVE_SET_ACL:
1224 case TRUNCATE_DIRECTORY:
1225 case RECURSIVE_REMOVE_PATH:
1226 r = glob_item(i, remove_item_instance, false);
1233 static int clean_item_instance(Item *i, const char* instance) {
1234 _cleanup_closedir_ DIR *d = NULL;
1238 char timestamp[FORMAT_TIMESTAMP_MAX];
1245 n = now(CLOCK_REALTIME);
1249 cutoff = n - i->age;
1251 d = opendir(instance);
1253 if (errno == ENOENT || errno == ENOTDIR) {
1254 log_debug_errno(errno, "Directory \"%s\": %m", instance);
1258 log_error_errno(errno, "Failed to open directory %s: %m", instance);
1262 if (fstat(dirfd(d), &s) < 0)
1263 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1265 if (!S_ISDIR(s.st_mode)) {
1266 log_error("%s is not a directory.", i->path);
1270 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1271 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1273 mountpoint = s.st_dev != ps.st_dev ||
1274 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1276 log_debug("Cleanup threshold for %s \"%s\" is %s",
1277 mountpoint ? "mount point" : "directory",
1279 format_timestamp_us(timestamp, sizeof(timestamp), cutoff));
1281 return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1282 MAX_DEPTH, i->keep_first_level);
1285 static int clean_item(Item *i) {
1290 log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
1293 case CREATE_DIRECTORY:
1294 case CREATE_SUBVOLUME:
1295 case TRUNCATE_DIRECTORY:
1298 clean_item_instance(i, i->path);
1300 case IGNORE_DIRECTORY_PATH:
1301 r = glob_item(i, clean_item_instance, false);
1310 static int process_item_array(ItemArray *array);
1312 static int process_item(Item *i) {
1314 _cleanup_free_ char *prefix = NULL;
1323 prefix = malloc(strlen(i->path) + 1);
1327 PATH_FOREACH_PREFIX(prefix, i->path) {
1330 j = hashmap_get(items, prefix);
1334 s = process_item_array(j);
1335 if (s < 0 && t == 0)
1340 r = arg_create ? create_item(i) : 0;
1341 q = arg_remove ? remove_item(i) : 0;
1342 p = arg_clean ? clean_item(i) : 0;
1350 static int process_item_array(ItemArray *array) {
1356 for (n = 0; n < array->count; n++) {
1357 k = process_item(array->items + n);
1358 if (k < 0 && r == 0)
1365 static void item_free_contents(Item *i) {
1369 strv_free(i->xattrs);
1372 acl_free(i->acl_access);
1373 acl_free(i->acl_default);
1377 static void item_array_free(ItemArray *a) {
1383 for (n = 0; n < a->count; n++)
1384 item_free_contents(a->items + n);
1389 static bool item_compatible(Item *a, Item *b) {
1392 assert(streq(a->path, b->path));
1394 if (takes_ownership(a->type) && takes_ownership(b->type))
1395 /* check if the items are the same */
1396 return streq_ptr(a->argument, b->argument) &&
1398 a->uid_set == b->uid_set &&
1401 a->gid_set == b->gid_set &&
1404 a->mode_set == b->mode_set &&
1405 a->mode == b->mode &&
1407 a->age_set == b->age_set &&
1410 a->mask_perms == b->mask_perms &&
1412 a->keep_first_level == b->keep_first_level &&
1414 a->major_minor == b->major_minor;
1419 static bool should_include_path(const char *path) {
1422 STRV_FOREACH(prefix, arg_exclude_prefixes)
1423 if (path_startswith(path, *prefix)) {
1424 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1429 STRV_FOREACH(prefix, arg_include_prefixes)
1430 if (path_startswith(path, *prefix)) {
1431 log_debug("Entry \"%s\" matches include prefix \"%s\".", path, *prefix);
1435 /* no matches, so we should include this path only if we
1436 * have no whitelist at all */
1437 if (strv_length(arg_include_prefixes) == 0)
1440 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path);
1444 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1446 static const Specifier specifier_table[] = {
1447 { 'm', specifier_machine_id, NULL },
1448 { 'b', specifier_boot_id, NULL },
1449 { 'H', specifier_host_name, NULL },
1450 { 'v', specifier_kernel_release, NULL },
1454 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1455 _cleanup_(item_free_contents) Item i = {};
1456 ItemArray *existing;
1459 bool force = false, boot = false;
1466 "%ms %ms %ms %ms %ms %ms %n",
1475 log_error("[%s:%u] Syntax error.", fname, line);
1479 if (isempty(action)) {
1480 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1484 for (pos = 1; action[pos]; pos++) {
1485 if (action[pos] == '!' && !boot)
1487 else if (action[pos] == '+' && !force)
1490 log_error("[%s:%u] Unknown modifiers in command '%s'",
1491 fname, line, action);
1496 if (boot && !arg_boot) {
1497 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1505 r = specifier_printf(path, specifier_table, NULL, &i.path);
1507 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1512 c += strspn(buffer+c, WHITESPACE);
1513 if (buffer[c] != 0 && (buffer[c] != '-' || buffer[c+1] != 0)) {
1514 i.argument = unquote(buffer+c, "\"");
1524 case CREATE_DIRECTORY:
1525 case CREATE_SUBVOLUME:
1526 case TRUNCATE_DIRECTORY:
1529 case IGNORE_DIRECTORY_PATH:
1531 case RECURSIVE_REMOVE_PATH:
1534 case RECURSIVE_RELABEL_PATH:
1537 case CREATE_SYMLINK:
1539 i.argument = strappend("/usr/share/factory/", i.path);
1547 log_error("[%s:%u] Write file requires argument.", fname, line);
1554 i.argument = strappend("/usr/share/factory/", i.path);
1557 } else if (!path_is_absolute(i.argument)) {
1558 log_error("[%s:%u] Source path is not absolute.", fname, line);
1562 path_kill_slashes(i.argument);
1565 case CREATE_CHAR_DEVICE:
1566 case CREATE_BLOCK_DEVICE: {
1567 unsigned major, minor;
1570 log_error("[%s:%u] Device file requires argument.", fname, line);
1574 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1575 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1579 i.major_minor = makedev(major, minor);
1584 case RECURSIVE_SET_XATTR:
1586 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1589 r = get_xattrs_from_arg(&i);
1595 case RECURSIVE_SET_ACL:
1597 log_error("[%s:%u] Set ACLs requires argument.", fname, line);
1600 r = get_acls_from_arg(&i);
1606 log_error("[%s:%u] Unknown command type '%c'.", fname, line, (char) i.type);
1610 if (!path_is_absolute(i.path)) {
1611 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1615 path_kill_slashes(i.path);
1617 if (!should_include_path(i.path))
1623 p = strappend(arg_root, i.path);
1631 if (user && !streq(user, "-")) {
1632 const char *u = user;
1634 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1636 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1643 if (group && !streq(group, "-")) {
1644 const char *g = group;
1646 r = get_group_creds(&g, &i.gid);
1648 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1655 if (mode && !streq(mode, "-")) {
1656 const char *mm = mode;
1660 i.mask_perms = true;
1664 if (sscanf(mm, "%o", &m) != 1) {
1665 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1672 i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
1675 if (age && !streq(age, "-")) {
1676 const char *a = age;
1679 i.keep_first_level = true;
1683 if (parse_sec(a, &i.age) < 0) {
1684 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1691 h = needs_glob(i.type) ? globs : items;
1693 existing = hashmap_get(h, i.path);
1697 for (n = 0; n < existing->count; n++) {
1698 if (!item_compatible(existing->items + n, &i))
1699 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1700 fname, line, i.path);
1703 existing = new0(ItemArray, 1);
1704 r = hashmap_put(h, i.path, existing);
1709 if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
1712 memcpy(existing->items + existing->count++, &i, sizeof(i));
1717 static void help(void) {
1718 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1719 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1720 " -h --help Show this help\n"
1721 " --version Show package version\n"
1722 " --create Create marked files/directories\n"
1723 " --clean Clean up marked directories\n"
1724 " --remove Remove marked files/directories\n"
1725 " --boot Execute actions only safe at boot\n"
1726 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1727 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1728 " --root=PATH Operate on an alternate filesystem root\n",
1729 program_invocation_short_name);
1732 static int parse_argv(int argc, char *argv[]) {
1735 ARG_VERSION = 0x100,
1745 static const struct option options[] = {
1746 { "help", no_argument, NULL, 'h' },
1747 { "version", no_argument, NULL, ARG_VERSION },
1748 { "create", no_argument, NULL, ARG_CREATE },
1749 { "clean", no_argument, NULL, ARG_CLEAN },
1750 { "remove", no_argument, NULL, ARG_REMOVE },
1751 { "boot", no_argument, NULL, ARG_BOOT },
1752 { "prefix", required_argument, NULL, ARG_PREFIX },
1753 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1754 { "root", required_argument, NULL, ARG_ROOT },
1763 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1772 puts(PACKAGE_STRING);
1773 puts(SYSTEMD_FEATURES);
1793 if (strv_push(&arg_include_prefixes, optarg) < 0)
1797 case ARG_EXCLUDE_PREFIX:
1798 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1804 arg_root = path_make_absolute_cwd(optarg);
1808 path_kill_slashes(arg_root);
1815 assert_not_reached("Unhandled option");
1818 if (!arg_clean && !arg_create && !arg_remove) {
1819 log_error("You need to specify at least one of --clean, --create or --remove.");
1826 static int read_config_file(const char *fn, bool ignore_enoent) {
1827 _cleanup_fclose_ FILE *f = NULL;
1828 char line[LINE_MAX];
1836 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1838 if (ignore_enoent && r == -ENOENT) {
1839 log_debug_errno(r, "Failed to open \"%s\": %m", fn);
1843 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1845 log_debug("Reading config file \"%s\".", fn);
1847 FOREACH_LINE(line, f, break) {
1854 if (*l == '#' || *l == 0)
1857 k = parse_line(fn, v, l);
1858 if (k < 0 && r == 0)
1862 /* we have to determine age parameter for each entry of type X */
1863 HASHMAP_FOREACH(i, globs, iterator) {
1865 Item *j, *candidate_item = NULL;
1867 if (i->type != IGNORE_DIRECTORY_PATH)
1870 HASHMAP_FOREACH(j, items, iter) {
1871 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1874 if (path_equal(j->path, i->path)) {
1879 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1880 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1884 if (candidate_item && candidate_item->age_set) {
1885 i->age = candidate_item->age;
1891 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1899 int main(int argc, char *argv[]) {
1904 r = parse_argv(argc, argv);
1908 log_set_target(LOG_TARGET_AUTO);
1909 log_parse_environment();
1914 mac_selinux_init(NULL);
1916 items = hashmap_new(&string_hash_ops);
1917 globs = hashmap_new(&string_hash_ops);
1919 if (!items || !globs) {
1926 if (optind < argc) {
1929 for (j = optind; j < argc; j++) {
1930 k = read_config_file(argv[j], false);
1931 if (k < 0 && r == 0)
1936 _cleanup_strv_free_ char **files = NULL;
1939 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1941 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1945 STRV_FOREACH(f, files) {
1946 k = read_config_file(*f, true);
1947 if (k < 0 && r == 0)
1952 HASHMAP_FOREACH(a, globs, iterator) {
1953 k = process_item_array(a);
1954 if (k < 0 && r == 0)
1958 HASHMAP_FOREACH(a, items, iterator) {
1959 k = process_item_array(a);
1960 if (k < 0 && r == 0)
1965 while ((a = hashmap_steal_first(items)))
1968 while ((a = hashmap_steal_first(globs)))
1971 hashmap_free(items);
1972 hashmap_free(globs);
1974 free(arg_include_prefixes);
1975 free(arg_exclude_prefixes);
1978 set_free_free(unix_sockets);
1980 mac_selinux_finish();
1982 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;