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);
1342 } else if (!path_is_absolute(i->argument)) {
1343 log_error("[%s:%u] Source path is not absolute.", fname, line);
1347 path_kill_slashes(i->argument);
1350 case CREATE_CHAR_DEVICE:
1351 case CREATE_BLOCK_DEVICE: {
1352 unsigned major, minor;
1355 log_error("[%s:%u] Device file requires argument.", fname, line);
1359 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1360 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1364 i->major_minor = makedev(major, minor);
1370 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1373 r = get_xattrs_from_arg(i);
1379 log_error("[%s:%u] Unknown command type '%c'.", fname, line, i->type);
1383 if (!path_is_absolute(i->path)) {
1384 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1388 path_kill_slashes(i->path);
1390 if (!should_include_path(i->path))
1396 p = strappend(arg_root, i->path);
1404 if (user && !streq(user, "-")) {
1405 const char *u = user;
1407 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1409 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1416 if (group && !streq(group, "-")) {
1417 const char *g = group;
1419 r = get_group_creds(&g, &i->gid);
1421 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1428 if (mode && !streq(mode, "-")) {
1429 const char *mm = mode;
1433 i->mask_perms = true;
1437 if (sscanf(mm, "%o", &m) != 1) {
1438 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1446 i->type == CREATE_DIRECTORY ||
1447 i->type == CREATE_SUBVOLUME ||
1448 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1450 if (age && !streq(age, "-")) {
1451 const char *a = age;
1454 i->keep_first_level = true;
1458 if (parse_sec(a, &i->age) < 0) {
1459 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1466 h = needs_glob(i->type) ? globs : items;
1468 existing = hashmap_get(h, i->path);
1470 if (i->type == SET_XATTR) {
1471 r = strv_extend_strv(&existing->xattrs, i->xattrs);
1475 } else if (existing->type == SET_XATTR) {
1476 r = strv_extend_strv(&i->xattrs, existing->xattrs);
1479 r = hashmap_replace(h, i->path, i);
1481 log_error("Failed to replace item for %s.", i->path);
1484 item_free(existing);
1486 /* Two identical items are fine */
1487 if (!item_equal(existing, i))
1488 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1489 fname, line, i->path);
1493 r = hashmap_put(h, i->path, i);
1495 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1500 i = NULL; /* avoid cleanup */
1505 static void help(void) {
1506 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1507 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1508 " -h --help Show this help\n"
1509 " --version Show package version\n"
1510 " --create Create marked files/directories\n"
1511 " --clean Clean up marked directories\n"
1512 " --remove Remove marked files/directories\n"
1513 " --boot Execute actions only safe at boot\n"
1514 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1515 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1516 " --root=PATH Operate on an alternate filesystem root\n",
1517 program_invocation_short_name);
1520 static int parse_argv(int argc, char *argv[]) {
1523 ARG_VERSION = 0x100,
1533 static const struct option options[] = {
1534 { "help", no_argument, NULL, 'h' },
1535 { "version", no_argument, NULL, ARG_VERSION },
1536 { "create", no_argument, NULL, ARG_CREATE },
1537 { "clean", no_argument, NULL, ARG_CLEAN },
1538 { "remove", no_argument, NULL, ARG_REMOVE },
1539 { "boot", no_argument, NULL, ARG_BOOT },
1540 { "prefix", required_argument, NULL, ARG_PREFIX },
1541 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1542 { "root", required_argument, NULL, ARG_ROOT },
1551 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1560 puts(PACKAGE_STRING);
1561 puts(SYSTEMD_FEATURES);
1581 if (strv_push(&arg_include_prefixes, optarg) < 0)
1585 case ARG_EXCLUDE_PREFIX:
1586 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1592 arg_root = path_make_absolute_cwd(optarg);
1596 path_kill_slashes(arg_root);
1603 assert_not_reached("Unhandled option");
1606 if (!arg_clean && !arg_create && !arg_remove) {
1607 log_error("You need to specify at least one of --clean, --create or --remove.");
1614 static int read_config_file(const char *fn, bool ignore_enoent) {
1615 _cleanup_fclose_ FILE *f = NULL;
1616 char line[LINE_MAX];
1624 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1626 if (ignore_enoent && r == -ENOENT)
1629 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1632 FOREACH_LINE(line, f, break) {
1639 if (*l == '#' || *l == 0)
1642 k = parse_line(fn, v, l);
1643 if (k < 0 && r == 0)
1647 /* we have to determine age parameter for each entry of type X */
1648 HASHMAP_FOREACH(i, globs, iterator) {
1650 Item *j, *candidate_item = NULL;
1652 if (i->type != IGNORE_DIRECTORY_PATH)
1655 HASHMAP_FOREACH(j, items, iter) {
1656 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1659 if (path_equal(j->path, i->path)) {
1664 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1665 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1669 if (candidate_item && candidate_item->age_set) {
1670 i->age = candidate_item->age;
1676 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1684 int main(int argc, char *argv[]) {
1689 r = parse_argv(argc, argv);
1693 log_set_target(LOG_TARGET_AUTO);
1694 log_parse_environment();
1699 mac_selinux_init(NULL);
1701 items = hashmap_new(&string_hash_ops);
1702 globs = hashmap_new(&string_hash_ops);
1704 if (!items || !globs) {
1711 if (optind < argc) {
1714 for (j = optind; j < argc; j++) {
1715 k = read_config_file(argv[j], false);
1716 if (k < 0 && r == 0)
1721 _cleanup_strv_free_ char **files = NULL;
1724 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1726 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1730 STRV_FOREACH(f, files) {
1731 k = read_config_file(*f, true);
1732 if (k < 0 && r == 0)
1737 HASHMAP_FOREACH(i, globs, iterator) {
1738 k = process_item(i);
1739 if (k < 0 && r == 0)
1743 HASHMAP_FOREACH(i, items, iterator) {
1744 k = process_item(i);
1745 if (k < 0 && r == 0)
1750 while ((i = hashmap_steal_first(items)))
1753 while ((i = hashmap_steal_first(globs)))
1756 hashmap_free(items);
1757 hashmap_free(globs);
1759 free(arg_include_prefixes);
1760 free(arg_exclude_prefixes);
1763 set_free_free(unix_sockets);
1765 mac_selinux_finish();
1767 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;