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 typedef int (*action_t)(Item *, const char *);
705 static int item_do_children(Item *i, const char *path, action_t action) {
706 _cleanup_closedir_ DIR *d;
712 /* This returns the first error we run into, but nevertheless
717 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
720 _cleanup_free_ char *p = NULL;
727 if (errno != 0 && r == 0)
733 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
736 p = strjoin(path, "/", de->d_name, NULL);
741 if (q < 0 && q != -ENOENT && r == 0)
744 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
745 q = item_do_children(i, p, action);
754 static int glob_item(Item *i, action_t action, bool recursive) {
755 _cleanup_globfree_ glob_t g = {};
760 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
761 if (k != 0 && k != GLOB_NOMATCH)
762 return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
764 STRV_FOREACH(fn, g.gl_pathv) {
770 k = item_do_children(i, *fn, action);
779 static int create_item(Item *i) {
788 case IGNORE_DIRECTORY_PATH:
790 case RECURSIVE_REMOVE_PATH:
795 r = write_one_file(i, i->path);
801 r = copy_tree(i->argument, i->path, false);
806 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
808 if (stat(i->argument, &a) < 0)
809 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
811 if (stat(i->path, &b) < 0)
812 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
814 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
815 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
820 r = item_set_perms(i, i->path);
827 r = glob_item(i, write_one_file, false);
833 case CREATE_DIRECTORY:
834 case TRUNCATE_DIRECTORY:
835 case CREATE_SUBVOLUME:
838 mkdir_parents_label(i->path, 0755);
840 if (i->type == CREATE_SUBVOLUME) {
841 RUN_WITH_UMASK((~i->mode) & 0777)
842 r = btrfs_subvol_make(i->path);
846 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY) {
848 r = mkdir_label(i->path, i->mode);
853 return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
855 if (stat(i->path, &st) < 0)
856 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
858 if (!S_ISDIR(st.st_mode)) {
859 log_debug("%s already exists and is not a directory.", i->path);
864 r = item_set_perms(i, i->path);
872 RUN_WITH_UMASK(0000) {
873 mac_selinux_create_file_prepare(i->path, S_IFIFO);
874 r = mkfifo(i->path, i->mode);
875 mac_selinux_create_file_clear();
880 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
882 if (stat(i->path, &st) < 0)
883 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
885 if (!S_ISFIFO(st.st_mode)) {
889 RUN_WITH_UMASK(0000) {
890 mac_selinux_create_file_prepare(i->path, S_IFIFO);
891 r = mkfifo_atomic(i->path, i->mode);
892 mac_selinux_create_file_clear();
896 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
898 log_debug("%s is not a fifo.", i->path);
904 r = item_set_perms(i, i->path);
912 mac_selinux_create_file_prepare(i->path, S_IFLNK);
913 r = symlink(i->argument, i->path);
914 mac_selinux_create_file_clear();
917 _cleanup_free_ char *x = NULL;
920 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
922 r = readlink_malloc(i->path, &x);
923 if (r < 0 || !streq(i->argument, x)) {
926 mac_selinux_create_file_prepare(i->path, S_IFLNK);
927 r = symlink_atomic(i->argument, i->path);
928 mac_selinux_create_file_clear();
931 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
933 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
941 case CREATE_BLOCK_DEVICE:
942 case CREATE_CHAR_DEVICE: {
945 if (have_effective_cap(CAP_MKNOD) == 0) {
946 /* In a container we lack CAP_MKNOD. We
947 shouldn't attempt to create the device node in
948 that case to avoid noise, and we don't support
949 virtualized devices in containers anyway. */
951 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
955 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
957 RUN_WITH_UMASK(0000) {
958 mac_selinux_create_file_prepare(i->path, file_type);
959 r = mknod(i->path, i->mode | file_type, i->major_minor);
960 mac_selinux_create_file_clear();
964 if (errno == EPERM) {
965 log_debug("We lack permissions, possibly because of cgroup configuration; "
966 "skipping creation of device node %s.", i->path);
971 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
973 if (stat(i->path, &st) < 0)
974 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
976 if ((st.st_mode & S_IFMT) != file_type) {
980 RUN_WITH_UMASK(0000) {
981 mac_selinux_create_file_prepare(i->path, file_type);
982 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
983 mac_selinux_create_file_clear();
987 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
989 log_debug("%s is not a device node.", i->path);
995 r = item_set_perms(i, i->path);
1005 r = glob_item(i, item_set_perms, false);
1010 case RECURSIVE_RELABEL_PATH:
1012 r = glob_item(i, item_set_perms, true);
1018 r = item_set_xattrs(i, i->path);
1024 r = item_set_acl(i, i->path);
1029 log_debug("%s created successfully.", i->path);
1034 static int remove_item_instance(Item *i, const char *instance) {
1043 case CREATE_DIRECTORY:
1044 case CREATE_SUBVOLUME:
1046 case CREATE_SYMLINK:
1047 case CREATE_BLOCK_DEVICE:
1048 case CREATE_CHAR_DEVICE:
1050 case IGNORE_DIRECTORY_PATH:
1053 case RECURSIVE_RELABEL_PATH:
1061 if (remove(instance) < 0 && errno != ENOENT)
1062 return log_error_errno(errno, "rm(%s): %m", instance);
1066 case TRUNCATE_DIRECTORY:
1067 case RECURSIVE_REMOVE_PATH:
1068 /* FIXME: we probably should use dir_cleanup() here
1069 * instead of rm_rf() so that 'x' is honoured. */
1070 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1071 if (r < 0 && r != -ENOENT)
1072 return log_error_errno(r, "rm_rf(%s): %m", instance);
1080 static int remove_item(Item *i) {
1089 case CREATE_DIRECTORY:
1090 case CREATE_SUBVOLUME:
1092 case CREATE_SYMLINK:
1093 case CREATE_CHAR_DEVICE:
1094 case CREATE_BLOCK_DEVICE:
1096 case IGNORE_DIRECTORY_PATH:
1099 case RECURSIVE_RELABEL_PATH:
1107 case TRUNCATE_DIRECTORY:
1108 case RECURSIVE_REMOVE_PATH:
1109 r = glob_item(i, remove_item_instance, false);
1116 static int clean_item_instance(Item *i, const char* instance) {
1117 _cleanup_closedir_ DIR *d = NULL;
1128 n = now(CLOCK_REALTIME);
1132 cutoff = n - i->age;
1134 d = opendir(instance);
1136 if (errno == ENOENT || errno == ENOTDIR)
1139 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1143 if (fstat(dirfd(d), &s) < 0)
1144 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1146 if (!S_ISDIR(s.st_mode)) {
1147 log_error("%s is not a directory.", i->path);
1151 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1152 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1154 mountpoint = s.st_dev != ps.st_dev ||
1155 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1157 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1158 MAX_DEPTH, i->keep_first_level);
1162 static int clean_item(Item *i) {
1168 case CREATE_DIRECTORY:
1169 case CREATE_SUBVOLUME:
1170 case TRUNCATE_DIRECTORY:
1173 clean_item_instance(i, i->path);
1175 case IGNORE_DIRECTORY_PATH:
1176 r = glob_item(i, clean_item_instance, false);
1185 static int process_item_array(ItemArray *array);
1187 static int process_item(Item *i) {
1189 _cleanup_free_ char *prefix = NULL;
1198 prefix = malloc(strlen(i->path) + 1);
1202 PATH_FOREACH_PREFIX(prefix, i->path) {
1205 j = hashmap_get(items, prefix);
1209 s = process_item_array(j);
1210 if (s < 0 && t == 0)
1215 r = arg_create ? create_item(i) : 0;
1216 q = arg_remove ? remove_item(i) : 0;
1217 p = arg_clean ? clean_item(i) : 0;
1225 static int process_item_array(ItemArray *array) {
1231 for (n = 0; n < array->count; n++) {
1232 k = process_item(array->items + n);
1233 if (k < 0 && r == 0)
1240 static void item_free_contents(Item *i) {
1244 strv_free(i->xattrs);
1247 acl_free(i->acl_access);
1248 acl_free(i->acl_default);
1252 static void item_array_free(ItemArray *a) {
1258 for (n = 0; n < a->count; n++)
1259 item_free_contents(a->items + n);
1264 static bool item_compatible(Item *a, Item *b) {
1267 assert(streq(a->path, b->path));
1269 if (takes_ownership(a->type) && takes_ownership(b->type))
1270 /* check if the items are the same */
1271 return streq_ptr(a->argument, b->argument) &&
1273 a->uid_set == b->uid_set &&
1276 a->gid_set == b->gid_set &&
1279 a->mode_set == b->mode_set &&
1280 a->mode == b->mode &&
1282 a->age_set == b->age_set &&
1285 a->mask_perms == b->mask_perms &&
1287 a->keep_first_level == b->keep_first_level &&
1289 a->major_minor == b->major_minor;
1294 static bool should_include_path(const char *path) {
1297 STRV_FOREACH(prefix, arg_exclude_prefixes)
1298 if (path_startswith(path, *prefix))
1301 STRV_FOREACH(prefix, arg_include_prefixes)
1302 if (path_startswith(path, *prefix))
1305 /* no matches, so we should include this path only if we
1306 * have no whitelist at all */
1307 return strv_length(arg_include_prefixes) == 0;
1310 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1312 static const Specifier specifier_table[] = {
1313 { 'm', specifier_machine_id, NULL },
1314 { 'b', specifier_boot_id, NULL },
1315 { 'H', specifier_host_name, NULL },
1316 { 'v', specifier_kernel_release, NULL },
1320 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1321 _cleanup_(item_free_contents) Item i = {};
1322 ItemArray *existing;
1325 bool force = false, boot = false;
1332 "%ms %ms %ms %ms %ms %ms %n",
1341 log_error("[%s:%u] Syntax error.", fname, line);
1345 if (isempty(action)) {
1346 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1350 for (pos = 1; action[pos]; pos++) {
1351 if (action[pos] == '!' && !boot)
1353 else if (action[pos] == '+' && !force)
1356 log_error("[%s:%u] Unknown modifiers in command '%s'",
1357 fname, line, action);
1362 if (boot && !arg_boot)
1368 r = specifier_printf(path, specifier_table, NULL, &i.path);
1370 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1375 c += strspn(buffer+c, WHITESPACE);
1376 if (buffer[c] != 0 && (buffer[c] != '-' || buffer[c+1] != 0)) {
1377 i.argument = unquote(buffer+c, "\"");
1387 case CREATE_DIRECTORY:
1388 case CREATE_SUBVOLUME:
1389 case TRUNCATE_DIRECTORY:
1392 case IGNORE_DIRECTORY_PATH:
1394 case RECURSIVE_REMOVE_PATH:
1397 case RECURSIVE_RELABEL_PATH:
1400 case CREATE_SYMLINK:
1402 i.argument = strappend("/usr/share/factory/", i.path);
1410 log_error("[%s:%u] Write file requires argument.", fname, line);
1417 i.argument = strappend("/usr/share/factory/", i.path);
1420 } else if (!path_is_absolute(i.argument)) {
1421 log_error("[%s:%u] Source path is not absolute.", fname, line);
1425 path_kill_slashes(i.argument);
1428 case CREATE_CHAR_DEVICE:
1429 case CREATE_BLOCK_DEVICE: {
1430 unsigned major, minor;
1433 log_error("[%s:%u] Device file requires argument.", fname, line);
1437 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1438 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1442 i.major_minor = makedev(major, minor);
1448 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1451 r = get_xattrs_from_arg(&i);
1458 log_error("[%s:%u] Set ACLs requires argument.", fname, line);
1461 r = get_acls_from_arg(&i);
1467 log_error("[%s:%u] Unknown command type '%c'.", fname, line, i.type);
1471 if (!path_is_absolute(i.path)) {
1472 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1476 path_kill_slashes(i.path);
1478 if (!should_include_path(i.path))
1484 p = strappend(arg_root, i.path);
1492 if (user && !streq(user, "-")) {
1493 const char *u = user;
1495 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1497 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1504 if (group && !streq(group, "-")) {
1505 const char *g = group;
1507 r = get_group_creds(&g, &i.gid);
1509 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1516 if (mode && !streq(mode, "-")) {
1517 const char *mm = mode;
1521 i.mask_perms = true;
1525 if (sscanf(mm, "%o", &m) != 1) {
1526 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1533 i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
1536 if (age && !streq(age, "-")) {
1537 const char *a = age;
1540 i.keep_first_level = true;
1544 if (parse_sec(a, &i.age) < 0) {
1545 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1552 h = needs_glob(i.type) ? globs : items;
1554 existing = hashmap_get(h, i.path);
1558 for (n = 0; n < existing->count; n++) {
1559 if (!item_compatible(existing->items + n, &i))
1560 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1561 fname, line, i.path);
1564 existing = new0(ItemArray, 1);
1565 r = hashmap_put(h, i.path, existing);
1570 if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
1573 memcpy(existing->items + existing->count++, &i, sizeof(i));
1578 static void help(void) {
1579 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1580 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1581 " -h --help Show this help\n"
1582 " --version Show package version\n"
1583 " --create Create marked files/directories\n"
1584 " --clean Clean up marked directories\n"
1585 " --remove Remove marked files/directories\n"
1586 " --boot Execute actions only safe at boot\n"
1587 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1588 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1589 " --root=PATH Operate on an alternate filesystem root\n",
1590 program_invocation_short_name);
1593 static int parse_argv(int argc, char *argv[]) {
1596 ARG_VERSION = 0x100,
1606 static const struct option options[] = {
1607 { "help", no_argument, NULL, 'h' },
1608 { "version", no_argument, NULL, ARG_VERSION },
1609 { "create", no_argument, NULL, ARG_CREATE },
1610 { "clean", no_argument, NULL, ARG_CLEAN },
1611 { "remove", no_argument, NULL, ARG_REMOVE },
1612 { "boot", no_argument, NULL, ARG_BOOT },
1613 { "prefix", required_argument, NULL, ARG_PREFIX },
1614 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1615 { "root", required_argument, NULL, ARG_ROOT },
1624 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1633 puts(PACKAGE_STRING);
1634 puts(SYSTEMD_FEATURES);
1654 if (strv_push(&arg_include_prefixes, optarg) < 0)
1658 case ARG_EXCLUDE_PREFIX:
1659 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1665 arg_root = path_make_absolute_cwd(optarg);
1669 path_kill_slashes(arg_root);
1676 assert_not_reached("Unhandled option");
1679 if (!arg_clean && !arg_create && !arg_remove) {
1680 log_error("You need to specify at least one of --clean, --create or --remove.");
1687 static int read_config_file(const char *fn, bool ignore_enoent) {
1688 _cleanup_fclose_ FILE *f = NULL;
1689 char line[LINE_MAX];
1697 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1699 if (ignore_enoent && r == -ENOENT)
1702 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1705 FOREACH_LINE(line, f, break) {
1712 if (*l == '#' || *l == 0)
1715 k = parse_line(fn, v, l);
1716 if (k < 0 && r == 0)
1720 /* we have to determine age parameter for each entry of type X */
1721 HASHMAP_FOREACH(i, globs, iterator) {
1723 Item *j, *candidate_item = NULL;
1725 if (i->type != IGNORE_DIRECTORY_PATH)
1728 HASHMAP_FOREACH(j, items, iter) {
1729 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1732 if (path_equal(j->path, i->path)) {
1737 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1738 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1742 if (candidate_item && candidate_item->age_set) {
1743 i->age = candidate_item->age;
1749 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1757 int main(int argc, char *argv[]) {
1762 r = parse_argv(argc, argv);
1766 log_set_target(LOG_TARGET_AUTO);
1767 log_parse_environment();
1772 mac_selinux_init(NULL);
1774 items = hashmap_new(&string_hash_ops);
1775 globs = hashmap_new(&string_hash_ops);
1777 if (!items || !globs) {
1784 if (optind < argc) {
1787 for (j = optind; j < argc; j++) {
1788 k = read_config_file(argv[j], false);
1789 if (k < 0 && r == 0)
1794 _cleanup_strv_free_ char **files = NULL;
1797 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1799 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1803 STRV_FOREACH(f, files) {
1804 k = read_config_file(*f, true);
1805 if (k < 0 && r == 0)
1810 HASHMAP_FOREACH(a, globs, iterator) {
1811 k = process_item_array(a);
1812 if (k < 0 && r == 0)
1816 HASHMAP_FOREACH(a, items, iterator) {
1817 k = process_item_array(a);
1818 if (k < 0 && r == 0)
1823 while ((a = hashmap_steal_first(items)))
1826 while ((a = hashmap_steal_first(globs)))
1829 hashmap_free(items);
1830 hashmap_free(globs);
1832 free(arg_include_prefixes);
1833 free(arg_exclude_prefixes);
1836 set_free_free(unix_sockets);
1838 mac_selinux_finish();
1840 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;