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;
1243 bool force = false, boot = false;
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 for (pos = 1; action[pos]; pos++) {
1269 if (action[pos] == '!' && !boot)
1271 else if (action[pos] == '+' && !force)
1274 log_error("[%s:%u] Unknown modifiers in command '%s'",
1275 fname, line, action);
1280 if (boot && !arg_boot)
1287 i->type = action[0];
1290 r = specifier_printf(path, specifier_table, NULL, &i->path);
1292 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1297 n += strspn(buffer+n, WHITESPACE);
1298 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1299 i->argument = unquote(buffer+n, "\"");
1309 case CREATE_DIRECTORY:
1310 case CREATE_SUBVOLUME:
1311 case TRUNCATE_DIRECTORY:
1314 case IGNORE_DIRECTORY_PATH:
1316 case RECURSIVE_REMOVE_PATH:
1319 case RECURSIVE_RELABEL_PATH:
1322 case CREATE_SYMLINK:
1324 i->argument = strappend("/usr/share/factory", i->path);
1332 log_error("[%s:%u] Write file requires argument.", fname, line);
1339 i->argument = strappend("/usr/share/factory", i->path);
1344 if (!path_is_absolute(i->argument)) {
1345 log_error("[%s:%u] Source path is not absolute.", fname, line);
1349 path_kill_slashes(i->argument);
1352 case CREATE_CHAR_DEVICE:
1353 case CREATE_BLOCK_DEVICE: {
1354 unsigned major, minor;
1357 log_error("[%s:%u] Device file requires argument.", fname, line);
1361 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1362 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1366 i->major_minor = makedev(major, minor);
1372 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1375 r = get_xattrs_from_arg(i);
1381 log_error("[%s:%u] Unknown command type '%c'.", fname, line, i->type);
1385 if (!path_is_absolute(i->path)) {
1386 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1390 path_kill_slashes(i->path);
1392 if (!should_include_path(i->path))
1398 p = strappend(arg_root, i->path);
1406 if (user && !streq(user, "-")) {
1407 const char *u = user;
1409 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1411 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1418 if (group && !streq(group, "-")) {
1419 const char *g = group;
1421 r = get_group_creds(&g, &i->gid);
1423 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1430 if (mode && !streq(mode, "-")) {
1431 const char *mm = mode;
1435 i->mask_perms = true;
1439 if (sscanf(mm, "%o", &m) != 1) {
1440 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1448 i->type == CREATE_DIRECTORY ||
1449 i->type == CREATE_SUBVOLUME ||
1450 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1452 if (age && !streq(age, "-")) {
1453 const char *a = age;
1456 i->keep_first_level = true;
1460 if (parse_sec(a, &i->age) < 0) {
1461 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1468 h = needs_glob(i->type) ? globs : items;
1470 existing = hashmap_get(h, i->path);
1472 if (i->type == SET_XATTR) {
1473 r = strv_extend_strv(&existing->xattrs, i->xattrs);
1477 } else if (existing->type == SET_XATTR) {
1478 r = strv_extend_strv(&i->xattrs, existing->xattrs);
1481 r = hashmap_replace(h, i->path, i);
1483 log_error("Failed to replace item for %s.", i->path);
1486 item_free(existing);
1488 /* Two identical items are fine */
1489 if (!item_equal(existing, i))
1490 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1491 fname, line, i->path);
1495 r = hashmap_put(h, i->path, i);
1497 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1502 i = NULL; /* avoid cleanup */
1507 static void help(void) {
1508 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1509 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1510 " -h --help Show this help\n"
1511 " --version Show package version\n"
1512 " --create Create marked files/directories\n"
1513 " --clean Clean up marked directories\n"
1514 " --remove Remove marked files/directories\n"
1515 " --boot Execute actions only safe at boot\n"
1516 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1517 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1518 " --root=PATH Operate on an alternate filesystem root\n",
1519 program_invocation_short_name);
1522 static int parse_argv(int argc, char *argv[]) {
1525 ARG_VERSION = 0x100,
1535 static const struct option options[] = {
1536 { "help", no_argument, NULL, 'h' },
1537 { "version", no_argument, NULL, ARG_VERSION },
1538 { "create", no_argument, NULL, ARG_CREATE },
1539 { "clean", no_argument, NULL, ARG_CLEAN },
1540 { "remove", no_argument, NULL, ARG_REMOVE },
1541 { "boot", no_argument, NULL, ARG_BOOT },
1542 { "prefix", required_argument, NULL, ARG_PREFIX },
1543 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1544 { "root", required_argument, NULL, ARG_ROOT },
1553 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1562 puts(PACKAGE_STRING);
1563 puts(SYSTEMD_FEATURES);
1583 if (strv_push(&arg_include_prefixes, optarg) < 0)
1587 case ARG_EXCLUDE_PREFIX:
1588 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1594 arg_root = path_make_absolute_cwd(optarg);
1598 path_kill_slashes(arg_root);
1605 assert_not_reached("Unhandled option");
1608 if (!arg_clean && !arg_create && !arg_remove) {
1609 log_error("You need to specify at least one of --clean, --create or --remove.");
1616 static int read_config_file(const char *fn, bool ignore_enoent) {
1617 _cleanup_fclose_ FILE *f = NULL;
1618 char line[LINE_MAX];
1626 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1628 if (ignore_enoent && r == -ENOENT)
1631 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1634 FOREACH_LINE(line, f, break) {
1641 if (*l == '#' || *l == 0)
1644 k = parse_line(fn, v, l);
1645 if (k < 0 && r == 0)
1649 /* we have to determine age parameter for each entry of type X */
1650 HASHMAP_FOREACH(i, globs, iterator) {
1652 Item *j, *candidate_item = NULL;
1654 if (i->type != IGNORE_DIRECTORY_PATH)
1657 HASHMAP_FOREACH(j, items, iter) {
1658 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1661 if (path_equal(j->path, i->path)) {
1666 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1667 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1671 if (candidate_item && candidate_item->age_set) {
1672 i->age = candidate_item->age;
1678 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1686 int main(int argc, char *argv[]) {
1691 r = parse_argv(argc, argv);
1695 log_set_target(LOG_TARGET_AUTO);
1696 log_parse_environment();
1701 mac_selinux_init(NULL);
1703 items = hashmap_new(&string_hash_ops);
1704 globs = hashmap_new(&string_hash_ops);
1706 if (!items || !globs) {
1713 if (optind < argc) {
1716 for (j = optind; j < argc; j++) {
1717 k = read_config_file(argv[j], false);
1718 if (k < 0 && r == 0)
1723 _cleanup_strv_free_ char **files = NULL;
1726 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1728 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1732 STRV_FOREACH(f, files) {
1733 k = read_config_file(*f, true);
1734 if (k < 0 && r == 0)
1739 HASHMAP_FOREACH(i, globs, iterator) {
1740 k = process_item(i);
1741 if (k < 0 && r == 0)
1745 HASHMAP_FOREACH(i, items, iterator) {
1746 k = process_item(i);
1747 if (k < 0 && r == 0)
1752 while ((i = hashmap_steal_first(items)))
1755 while ((i = hashmap_steal_first(globs)))
1758 hashmap_free(items);
1759 hashmap_free(globs);
1761 free(arg_include_prefixes);
1762 free(arg_exclude_prefixes);
1765 set_free_free(unix_sockets);
1767 mac_selinux_finish();
1769 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;