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
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/xattr.h>
48 #include "path-util.h"
52 #include "conf-files.h"
53 #include "capability.h"
54 #include "specifier.h"
57 #include "selinux-util.h"
58 #include "btrfs-util.h"
60 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
61 * them in the file system. This is intended to be used to create
62 * properly owned directories beneath /tmp, /var/tmp, /run, which are
63 * volatile and hence need to be recreated on bootup. */
65 typedef enum ItemType {
66 /* These ones take file names */
69 CREATE_DIRECTORY = 'd',
70 TRUNCATE_DIRECTORY = 'D',
71 CREATE_SUBVOLUME = 'v',
74 CREATE_CHAR_DEVICE = 'c',
75 CREATE_BLOCK_DEVICE = 'b',
79 /* These ones take globs */
82 IGNORE_DIRECTORY_PATH = 'X',
84 RECURSIVE_REMOVE_PATH = 'R',
85 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
87 RECURSIVE_RELABEL_PATH = 'Z',
109 bool keep_first_level:1;
116 static bool arg_create = false;
117 static bool arg_clean = false;
118 static bool arg_remove = false;
119 static bool arg_boot = false;
121 static char **arg_include_prefixes = NULL;
122 static char **arg_exclude_prefixes = NULL;
123 static char *arg_root = NULL;
125 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
127 #define MAX_DEPTH 256
129 static Hashmap *items = NULL, *globs = NULL;
130 static Set *unix_sockets = NULL;
132 static bool needs_glob(ItemType t) {
136 IGNORE_DIRECTORY_PATH,
138 RECURSIVE_REMOVE_PATH,
141 RECURSIVE_RELABEL_PATH);
144 static struct Item* find_glob(Hashmap *h, const char *match) {
148 HASHMAP_FOREACH(j, h, i)
149 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
155 static void load_unix_sockets(void) {
156 _cleanup_fclose_ FILE *f = NULL;
162 /* We maintain a cache of the sockets we found in
163 * /proc/net/unix to speed things up a little. */
165 unix_sockets = set_new(&string_hash_ops);
169 f = fopen("/proc/net/unix", "re");
174 if (!fgets(line, sizeof(line), f))
181 if (!fgets(line, sizeof(line), f))
186 p = strchr(line, ':');
194 p += strspn(p, WHITESPACE);
195 p += strcspn(p, WHITESPACE); /* skip one more word */
196 p += strspn(p, WHITESPACE);
205 path_kill_slashes(s);
207 k = set_consume(unix_sockets, s);
208 if (k < 0 && k != -EEXIST)
215 set_free_free(unix_sockets);
219 static bool unix_socket_alive(const char *fn) {
225 return !!set_get(unix_sockets, (char*) fn);
227 /* We don't know, so assume yes */
231 static int dir_is_mount_point(DIR *d, const char *subdir) {
233 union file_handle_union h = FILE_HANDLE_INIT;
234 int mount_id_parent, mount_id;
237 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
241 h.handle.handle_bytes = MAX_HANDLE_SZ;
242 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
246 /* got no handle; make no assumptions, return error */
247 if (r_p < 0 && r < 0)
250 /* got both handles; if they differ, it is a mount point */
251 if (r_p >= 0 && r >= 0)
252 return mount_id_parent != mount_id;
254 /* got only one handle; assume different mount points if one
255 * of both queries was not supported by the filesystem */
256 if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
265 static int dir_cleanup(
269 const struct stat *ds,
274 bool keep_this_level) {
277 struct timespec times[2];
278 bool deleted = false;
281 while ((dent = readdir(d))) {
284 _cleanup_free_ char *sub_path = NULL;
286 if (streq(dent->d_name, ".") ||
287 streq(dent->d_name, ".."))
290 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
294 /* FUSE, NFS mounts, SELinux might return EACCES */
296 log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
298 log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
303 /* Stay on the same filesystem */
304 if (s.st_dev != rootdev)
307 /* Try to detect bind mounts of the same filesystem instance; they
308 * do not differ in device major/minors. This type of query is not
309 * supported on all kernels or filesystem types though. */
310 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
313 /* Do not delete read-only files owned by root */
314 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
317 sub_path = strjoin(p, "/", dent->d_name, NULL);
323 /* Is there an item configured for this path? */
324 if (hashmap_get(items, sub_path))
327 if (find_glob(globs, sub_path))
330 if (S_ISDIR(s.st_mode)) {
333 streq(dent->d_name, "lost+found") &&
338 log_warning("Reached max depth on %s.", sub_path);
340 _cleanup_closedir_ DIR *sub_dir;
343 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
345 if (errno != ENOENT) {
346 log_error_errno(errno, "opendir(%s/%s) failed: %m", p, dent->d_name);
353 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
358 /* Note: if you are wondering why we don't
359 * support the sticky bit for excluding
360 * directories from cleaning like we do it for
361 * other file system objects: well, the sticky
362 * bit already has a meaning for directories,
363 * so we don't want to overload that. */
368 /* Ignore ctime, we change it when deleting */
369 age = MAX(timespec_load(&s.st_mtim),
370 timespec_load(&s.st_atim));
374 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
375 log_debug("rmdir '%s'", sub_path);
377 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
378 if (errno != ENOENT && errno != ENOTEMPTY) {
379 log_error_errno(errno, "rmdir(%s): %m", sub_path);
386 /* Skip files for which the sticky bit is
387 * set. These are semantics we define, and are
388 * unknown elsewhere. See XDG_RUNTIME_DIR
389 * specification for details. */
390 if (s.st_mode & S_ISVTX)
393 if (mountpoint && S_ISREG(s.st_mode)) {
394 if (streq(dent->d_name, ".journal") &&
398 if (streq(dent->d_name, "aquota.user") ||
399 streq(dent->d_name, "aquota.group"))
403 /* Ignore sockets that are listed in /proc/net/unix */
404 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
407 /* Ignore device nodes */
408 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
411 /* Keep files on this level around if this is
416 age = MAX3(timespec_load(&s.st_mtim),
417 timespec_load(&s.st_atim),
418 timespec_load(&s.st_ctim));
423 log_debug("unlink '%s'", sub_path);
425 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
426 if (errno != ENOENT) {
427 log_error_errno(errno, "unlink(%s): %m", sub_path);
438 /* Restore original directory timestamps */
439 times[0] = ds->st_atim;
440 times[1] = ds->st_mtim;
442 if (futimens(dirfd(d), times) < 0)
443 log_error_errno(errno, "utimensat(%s): %m", p);
449 static int item_set_perms(Item *i, const char *path) {
456 st_valid = stat(path, &st) == 0;
458 /* not using i->path directly because it may be a glob */
462 if (i->mask_perms && st_valid) {
463 if (!(st.st_mode & 0111))
465 if (!(st.st_mode & 0222))
467 if (!(st.st_mode & 0444))
469 if (!S_ISDIR(st.st_mode))
470 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
473 if (!st_valid || m != (st.st_mode & 07777)) {
474 if (chmod(path, m) < 0)
475 return log_error_errno(errno, "chmod(%s) failed: %m", path);
479 if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
480 (i->uid_set || i->gid_set))
482 i->uid_set ? i->uid : UID_INVALID,
483 i->gid_set ? i->gid : GID_INVALID) < 0)
485 return log_error_errno(errno, "chown(%s) failed: %m", path);
487 return label_fix(path, false, false);
490 static int get_xattrs_from_arg(Item *i) {
500 while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
501 _cleanup_free_ char *tmp = NULL, *name = NULL,
502 *value = NULL, *value2 = NULL, *_xattr = xattr;
504 r = split_pair(xattr, "=", &name, &value);
506 log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
510 if (strempty(name) || strempty(value)) {
511 log_warning("Malformed xattr found: \"%s\" - ignoring.", xattr);
515 tmp = unquote(value, "\"");
519 value2 = cunescape(tmp);
523 if (strv_push_pair(&i->xattrs, name, value2) < 0)
525 name = value2 = NULL;
531 static int item_set_xattrs(Item *i, const char *path) {
532 char **name, **value;
537 STRV_FOREACH_PAIR(name, value, i->xattrs) {
541 if (lsetxattr(path, *name, *value, n, 0) < 0) {
542 log_error("Setting extended attribute %s=%s on %s failed: %m",
543 *name, *value, path);
550 static int write_one_file(Item *i, const char *path) {
551 _cleanup_close_ int fd = -1;
558 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
559 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
561 RUN_WITH_UMASK(0000) {
562 mac_selinux_create_file_prepare(path, S_IFREG);
563 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
564 mac_selinux_create_file_clear();
568 if (i->type == WRITE_FILE && errno == ENOENT)
571 log_error_errno(errno, "Failed to create file %s: %m", path);
576 _cleanup_free_ char *unescaped;
580 unescaped = cunescape(i->argument);
584 l = strlen(unescaped);
585 n = write(fd, unescaped, l);
587 if (n < 0 || (size_t) n < l) {
588 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
589 return n < 0 ? n : -EIO;
595 if (stat(path, &st) < 0)
596 return log_error_errno(errno, "stat(%s) failed: %m", path);
598 if (!S_ISREG(st.st_mode)) {
599 log_error("%s is not a file.", path);
603 r = item_set_perms(i, path);
607 r = item_set_xattrs(i, i->path);
614 static int item_set_perms_children(Item *i, const char *path) {
615 _cleanup_closedir_ DIR *d;
621 /* This returns the first error we run into, but nevertheless
626 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
629 _cleanup_free_ char *p = NULL;
636 if (errno != 0 && r == 0)
642 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
645 p = strjoin(path, "/", de->d_name, NULL);
649 q = item_set_perms(i, p);
650 if (q < 0 && q != -ENOENT && r == 0)
653 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
654 q = item_set_perms_children(i, p);
663 static int item_set_perms_recursive(Item *i, const char *path) {
669 r = item_set_perms(i, path);
673 q = item_set_perms_children(i, path);
680 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
681 _cleanup_globfree_ glob_t g = {};
686 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
687 if (k != 0 && k != GLOB_NOMATCH) {
691 log_error_errno(errno, "glob(%s) failed: %m", i->path);
695 STRV_FOREACH(fn, g.gl_pathv) {
704 static int create_item(Item *i) {
713 case IGNORE_DIRECTORY_PATH:
715 case RECURSIVE_REMOVE_PATH:
720 r = write_one_file(i, i->path);
726 r = copy_tree(i->argument, i->path, false);
731 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
733 if (stat(i->argument, &a) < 0)
734 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
736 if (stat(i->path, &b) < 0)
737 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
739 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
740 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
745 r = item_set_perms(i, i->path);
752 r = glob_item(i, write_one_file);
758 case CREATE_DIRECTORY:
759 case TRUNCATE_DIRECTORY:
760 case CREATE_SUBVOLUME:
763 mkdir_parents_label(i->path, 0755);
765 if (i->type == CREATE_SUBVOLUME) {
766 RUN_WITH_UMASK((~i->mode) & 0777)
767 r = btrfs_subvol_make(i->path);
771 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY) {
773 r = mkdir_label(i->path, i->mode);
778 return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
780 if (stat(i->path, &st) < 0)
781 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
783 if (!S_ISDIR(st.st_mode)) {
784 log_debug("%s already exists and is not a directory.", i->path);
789 r = item_set_perms(i, i->path);
793 r = item_set_xattrs(i, i->path);
801 RUN_WITH_UMASK(0000) {
802 mac_selinux_create_file_prepare(i->path, S_IFIFO);
803 r = mkfifo(i->path, i->mode);
804 mac_selinux_create_file_clear();
809 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
811 if (stat(i->path, &st) < 0)
812 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
814 if (!S_ISFIFO(st.st_mode)) {
818 RUN_WITH_UMASK(0000) {
819 mac_selinux_create_file_prepare(i->path, S_IFIFO);
820 r = mkfifo_atomic(i->path, i->mode);
821 mac_selinux_create_file_clear();
825 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
827 log_debug("%s is not a fifo.", i->path);
833 r = item_set_perms(i, i->path);
837 r = item_set_xattrs(i, i->path);
845 mac_selinux_create_file_prepare(i->path, S_IFLNK);
846 r = symlink(i->argument, i->path);
847 mac_selinux_create_file_clear();
850 _cleanup_free_ char *x = NULL;
853 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
855 r = readlink_malloc(i->path, &x);
856 if (r < 0 || !streq(i->argument, x)) {
859 mac_selinux_create_file_prepare(i->path, S_IFLNK);
860 r = symlink_atomic(i->argument, i->path);
861 mac_selinux_create_file_clear();
864 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
866 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
872 r = item_set_xattrs(i, i->path);
878 case CREATE_BLOCK_DEVICE:
879 case CREATE_CHAR_DEVICE: {
882 if (have_effective_cap(CAP_MKNOD) == 0) {
883 /* In a container we lack CAP_MKNOD. We
884 shouldn't attempt to create the device node in
885 that case to avoid noise, and we don't support
886 virtualized devices in containers anyway. */
888 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
892 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
894 RUN_WITH_UMASK(0000) {
895 mac_selinux_create_file_prepare(i->path, file_type);
896 r = mknod(i->path, i->mode | file_type, i->major_minor);
897 mac_selinux_create_file_clear();
901 if (errno == EPERM) {
902 log_debug("We lack permissions, possibly because of cgroup configuration; "
903 "skipping creation of device node %s.", i->path);
908 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
910 if (stat(i->path, &st) < 0)
911 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
913 if ((st.st_mode & S_IFMT) != file_type) {
917 RUN_WITH_UMASK(0000) {
918 mac_selinux_create_file_prepare(i->path, file_type);
919 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
920 mac_selinux_create_file_clear();
924 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
926 log_debug("%s is not a device node.", i->path);
932 r = item_set_perms(i, i->path);
936 r = item_set_xattrs(i, i->path);
946 r = glob_item(i, item_set_perms);
951 case RECURSIVE_RELABEL_PATH:
953 r = glob_item(i, item_set_perms_recursive);
959 r = item_set_xattrs(i, i->path);
965 log_debug("%s created successfully.", i->path);
970 static int remove_item_instance(Item *i, const char *instance) {
979 case CREATE_DIRECTORY:
980 case CREATE_SUBVOLUME:
983 case CREATE_BLOCK_DEVICE:
984 case CREATE_CHAR_DEVICE:
986 case IGNORE_DIRECTORY_PATH:
989 case RECURSIVE_RELABEL_PATH:
996 if (remove(instance) < 0 && errno != ENOENT)
997 return log_error_errno(errno, "remove(%s): %m", instance);
1001 case TRUNCATE_DIRECTORY:
1002 case RECURSIVE_REMOVE_PATH:
1003 /* FIXME: we probably should use dir_cleanup() here
1004 * instead of rm_rf() so that 'x' is honoured. */
1005 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1006 if (r < 0 && r != -ENOENT)
1007 return log_error_errno(r, "rm_rf(%s): %m", instance);
1015 static int remove_item(Item *i) {
1024 case CREATE_DIRECTORY:
1025 case CREATE_SUBVOLUME:
1027 case CREATE_SYMLINK:
1028 case CREATE_CHAR_DEVICE:
1029 case CREATE_BLOCK_DEVICE:
1031 case IGNORE_DIRECTORY_PATH:
1034 case RECURSIVE_RELABEL_PATH:
1041 case TRUNCATE_DIRECTORY:
1042 case RECURSIVE_REMOVE_PATH:
1043 r = glob_item(i, remove_item_instance);
1050 static int clean_item_instance(Item *i, const char* instance) {
1051 _cleanup_closedir_ DIR *d = NULL;
1062 n = now(CLOCK_REALTIME);
1066 cutoff = n - i->age;
1068 d = opendir(instance);
1070 if (errno == ENOENT || errno == ENOTDIR)
1073 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1077 if (fstat(dirfd(d), &s) < 0)
1078 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1080 if (!S_ISDIR(s.st_mode)) {
1081 log_error("%s is not a directory.", i->path);
1085 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1086 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1088 mountpoint = s.st_dev != ps.st_dev ||
1089 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1091 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1092 MAX_DEPTH, i->keep_first_level);
1096 static int clean_item(Item *i) {
1102 case CREATE_DIRECTORY:
1103 case CREATE_SUBVOLUME:
1104 case TRUNCATE_DIRECTORY:
1107 clean_item_instance(i, i->path);
1109 case IGNORE_DIRECTORY_PATH:
1110 r = glob_item(i, clean_item_instance);
1119 static int process_item(Item *i) {
1121 _cleanup_free_ char *prefix = NULL;
1130 prefix = malloc(strlen(i->path) + 1);
1134 PATH_FOREACH_PREFIX(prefix, i->path) {
1137 j = hashmap_get(items, prefix);
1141 s = process_item(j);
1142 if (s < 0 && t == 0)
1147 r = arg_create ? create_item(i) : 0;
1148 q = arg_remove ? remove_item(i) : 0;
1149 p = arg_clean ? clean_item(i) : 0;
1157 static void item_free(Item *i) {
1164 strv_free(i->xattrs);
1168 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1170 static bool item_equal(Item *a, Item *b) {
1174 if (!streq_ptr(a->path, b->path))
1177 if (a->type != b->type)
1180 if (a->uid_set != b->uid_set ||
1181 (a->uid_set && a->uid != b->uid))
1184 if (a->gid_set != b->gid_set ||
1185 (a->gid_set && a->gid != b->gid))
1188 if (a->mode_set != b->mode_set ||
1189 (a->mode_set && a->mode != b->mode))
1192 if (a->age_set != b->age_set ||
1193 (a->age_set && a->age != b->age))
1196 if ((a->type == CREATE_FILE ||
1197 a->type == TRUNCATE_FILE ||
1198 a->type == WRITE_FILE ||
1199 a->type == CREATE_SYMLINK ||
1200 a->type == COPY_FILES) &&
1201 !streq_ptr(a->argument, b->argument))
1204 if ((a->type == CREATE_CHAR_DEVICE ||
1205 a->type == CREATE_BLOCK_DEVICE) &&
1206 a->major_minor != b->major_minor)
1212 static bool should_include_path(const char *path) {
1215 STRV_FOREACH(prefix, arg_exclude_prefixes)
1216 if (path_startswith(path, *prefix))
1219 STRV_FOREACH(prefix, arg_include_prefixes)
1220 if (path_startswith(path, *prefix))
1223 /* no matches, so we should include this path only if we
1224 * have no whitelist at all */
1225 return strv_length(arg_include_prefixes) == 0;
1228 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1230 static const Specifier specifier_table[] = {
1231 { 'm', specifier_machine_id, NULL },
1232 { 'b', specifier_boot_id, NULL },
1233 { 'H', specifier_host_name, NULL },
1234 { 'v', specifier_kernel_release, NULL },
1238 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1239 _cleanup_(item_freep) Item *i = NULL;
1250 "%ms %ms %ms %ms %ms %ms %n",
1259 log_error("[%s:%u] Syntax error.", fname, line);
1263 if (isempty(action)) {
1264 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1268 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1269 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1273 if (strchr(action+1, '!') && !arg_boot)
1282 i->force = !!strchr(action+1, '+');
1284 r = specifier_printf(path, specifier_table, NULL, &i->path);
1286 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1291 n += strspn(buffer+n, WHITESPACE);
1292 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1293 i->argument = unquote(buffer+n, "\"");
1303 case CREATE_DIRECTORY:
1304 case CREATE_SUBVOLUME:
1305 case TRUNCATE_DIRECTORY:
1308 case IGNORE_DIRECTORY_PATH:
1310 case RECURSIVE_REMOVE_PATH:
1313 case RECURSIVE_RELABEL_PATH:
1316 case CREATE_SYMLINK:
1318 i->argument = strappend("/usr/share/factory", i->path);
1326 log_error("[%s:%u] Write file requires argument.", fname, line);
1333 i->argument = strappend("/usr/share/factory", i->path);
1338 if (!path_is_absolute(i->argument)) {
1339 log_error("[%s:%u] Source path is not absolute.", fname, line);
1343 path_kill_slashes(i->argument);
1346 case CREATE_CHAR_DEVICE:
1347 case CREATE_BLOCK_DEVICE: {
1348 unsigned major, minor;
1351 log_error("[%s:%u] Device file requires argument.", fname, line);
1355 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1356 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1360 i->major_minor = makedev(major, minor);
1366 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1369 r = get_xattrs_from_arg(i);
1375 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1381 if (!path_is_absolute(i->path)) {
1382 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1386 path_kill_slashes(i->path);
1388 if (!should_include_path(i->path))
1394 p = strappend(arg_root, i->path);
1402 if (user && !streq(user, "-")) {
1403 const char *u = user;
1405 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1407 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1414 if (group && !streq(group, "-")) {
1415 const char *g = group;
1417 r = get_group_creds(&g, &i->gid);
1419 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1426 if (mode && !streq(mode, "-")) {
1427 const char *mm = mode;
1431 i->mask_perms = true;
1435 if (sscanf(mm, "%o", &m) != 1) {
1436 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1444 i->type == CREATE_DIRECTORY ||
1445 i->type == CREATE_SUBVOLUME ||
1446 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1448 if (age && !streq(age, "-")) {
1449 const char *a = age;
1452 i->keep_first_level = true;
1456 if (parse_sec(a, &i->age) < 0) {
1457 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1464 h = needs_glob(i->type) ? globs : items;
1466 existing = hashmap_get(h, i->path);
1468 if (i->type == SET_XATTR) {
1469 r = strv_extend_strv(&existing->xattrs, i->xattrs);
1473 } else if (existing->type == SET_XATTR) {
1474 r = strv_extend_strv(&i->xattrs, existing->xattrs);
1477 r = hashmap_replace(h, i->path, i);
1479 log_error("Failed to replace item for %s.", i->path);
1482 item_free(existing);
1484 /* Two identical items are fine */
1485 if (!item_equal(existing, i))
1486 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1487 fname, line, i->path);
1491 r = hashmap_put(h, i->path, i);
1493 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1498 i = NULL; /* avoid cleanup */
1503 static void help(void) {
1504 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1505 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1506 " -h --help Show this help\n"
1507 " --version Show package version\n"
1508 " --create Create marked files/directories\n"
1509 " --clean Clean up marked directories\n"
1510 " --remove Remove marked files/directories\n"
1511 " --boot Execute actions only safe at boot\n"
1512 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1513 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1514 " --root=PATH Operate on an alternate filesystem root\n",
1515 program_invocation_short_name);
1518 static int parse_argv(int argc, char *argv[]) {
1521 ARG_VERSION = 0x100,
1531 static const struct option options[] = {
1532 { "help", no_argument, NULL, 'h' },
1533 { "version", no_argument, NULL, ARG_VERSION },
1534 { "create", no_argument, NULL, ARG_CREATE },
1535 { "clean", no_argument, NULL, ARG_CLEAN },
1536 { "remove", no_argument, NULL, ARG_REMOVE },
1537 { "boot", no_argument, NULL, ARG_BOOT },
1538 { "prefix", required_argument, NULL, ARG_PREFIX },
1539 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1540 { "root", required_argument, NULL, ARG_ROOT },
1549 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1558 puts(PACKAGE_STRING);
1559 puts(SYSTEMD_FEATURES);
1579 if (strv_push(&arg_include_prefixes, optarg) < 0)
1583 case ARG_EXCLUDE_PREFIX:
1584 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1590 arg_root = path_make_absolute_cwd(optarg);
1594 path_kill_slashes(arg_root);
1601 assert_not_reached("Unhandled option");
1604 if (!arg_clean && !arg_create && !arg_remove) {
1605 log_error("You need to specify at least one of --clean, --create or --remove.");
1612 static int read_config_file(const char *fn, bool ignore_enoent) {
1613 _cleanup_fclose_ FILE *f = NULL;
1614 char line[LINE_MAX];
1622 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1624 if (ignore_enoent && r == -ENOENT)
1627 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1630 FOREACH_LINE(line, f, break) {
1637 if (*l == '#' || *l == 0)
1640 k = parse_line(fn, v, l);
1641 if (k < 0 && r == 0)
1645 /* we have to determine age parameter for each entry of type X */
1646 HASHMAP_FOREACH(i, globs, iterator) {
1648 Item *j, *candidate_item = NULL;
1650 if (i->type != IGNORE_DIRECTORY_PATH)
1653 HASHMAP_FOREACH(j, items, iter) {
1654 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1657 if (path_equal(j->path, i->path)) {
1662 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1663 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1667 if (candidate_item && candidate_item->age_set) {
1668 i->age = candidate_item->age;
1674 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1682 int main(int argc, char *argv[]) {
1687 r = parse_argv(argc, argv);
1691 log_set_target(LOG_TARGET_AUTO);
1692 log_parse_environment();
1697 mac_selinux_init(NULL);
1699 items = hashmap_new(&string_hash_ops);
1700 globs = hashmap_new(&string_hash_ops);
1702 if (!items || !globs) {
1709 if (optind < argc) {
1712 for (j = optind; j < argc; j++) {
1713 k = read_config_file(argv[j], false);
1714 if (k < 0 && r == 0)
1719 _cleanup_strv_free_ char **files = NULL;
1722 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1724 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1728 STRV_FOREACH(f, files) {
1729 k = read_config_file(*f, true);
1730 if (k < 0 && r == 0)
1735 HASHMAP_FOREACH(i, globs, iterator) {
1736 k = process_item(i);
1737 if (k < 0 && r == 0)
1741 HASHMAP_FOREACH(i, items, iterator) {
1742 k = process_item(i);
1743 if (k < 0 && r == 0)
1748 while ((i = hashmap_steal_first(items)))
1751 while ((i = hashmap_steal_first(globs)))
1754 hashmap_free(items);
1755 hashmap_free(globs);
1757 free(arg_include_prefixes);
1758 free(arg_exclude_prefixes);
1761 set_free_free(unix_sockets);
1763 mac_selinux_finish();
1765 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;