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/>.
37 #include <sys/types.h>
38 #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 log_error_errno(errno, "chown(%s) failed: %m", path);
489 return label_fix(path, false, false);
492 static int get_xattrs_from_arg(Item *i) {
500 log_error("%s: Argument can't be empty!", i->path);
505 while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
506 _cleanup_free_ char *tmp = NULL, *name = NULL, *value = NULL;
507 r = split_pair(xattr, "=", &name, &value);
509 log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
514 if (streq(name, "") || streq(value, "")) {
515 log_warning("Malformed xattr found: \"%s=%s\" - ignoring.", name, value);
518 tmp = unquote(value, "\"");
522 value = cunescape(tmp);
525 if (strv_consume_pair(&i->xattrs, name, value) < 0)
533 static int item_set_xattrs(Item *i, const char *path) {
534 char **name, **value;
539 if (strv_isempty(i->xattrs))
542 STRV_FOREACH_PAIR(name, value, i->xattrs) {
545 if (lsetxattr(path, *name, *value, n, 0) < 0) {
546 log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path);
553 static int write_one_file(Item *i, const char *path) {
554 _cleanup_close_ int fd = -1;
561 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
562 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
564 RUN_WITH_UMASK(0000) {
565 mac_selinux_create_file_prepare(path, S_IFREG);
566 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
567 mac_selinux_create_file_clear();
571 if (i->type == WRITE_FILE && errno == ENOENT)
574 log_error_errno(errno, "Failed to create file %s: %m", path);
579 _cleanup_free_ char *unescaped;
583 unescaped = cunescape(i->argument);
587 l = strlen(unescaped);
588 n = write(fd, unescaped, l);
590 if (n < 0 || (size_t) n < l) {
591 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
592 return n < 0 ? n : -EIO;
598 if (stat(path, &st) < 0)
599 return log_error_errno(errno, "stat(%s) failed: %m", path);
601 if (!S_ISREG(st.st_mode)) {
602 log_error("%s is not a file.", path);
606 r = item_set_perms(i, path);
610 r = item_set_xattrs(i, i->path);
617 static int item_set_perms_children(Item *i, const char *path) {
618 _cleanup_closedir_ DIR *d;
624 /* This returns the first error we run into, but nevertheless
629 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
632 _cleanup_free_ char *p = NULL;
639 if (errno != 0 && r == 0)
645 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
648 p = strjoin(path, "/", de->d_name, NULL);
652 q = item_set_perms(i, p);
653 if (q < 0 && q != -ENOENT && r == 0)
656 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
657 q = item_set_perms_children(i, p);
666 static int item_set_perms_recursive(Item *i, const char *path) {
672 r = item_set_perms(i, path);
676 q = item_set_perms_children(i, path);
683 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
684 _cleanup_globfree_ glob_t g = {};
689 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
690 if (k != 0 && k != GLOB_NOMATCH) {
694 log_error_errno(errno, "glob(%s) failed: %m", i->path);
698 STRV_FOREACH(fn, g.gl_pathv) {
707 static int create_item(Item *i) {
716 case IGNORE_DIRECTORY_PATH:
718 case RECURSIVE_REMOVE_PATH:
723 r = write_one_file(i, i->path);
729 r = copy_tree(i->argument, i->path, false);
734 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
736 if (stat(i->argument, &a) < 0)
737 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
739 if (stat(i->path, &b) < 0)
740 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
742 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
743 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
748 r = item_set_perms(i, i->path);
755 r = glob_item(i, write_one_file);
761 case CREATE_DIRECTORY:
762 case TRUNCATE_DIRECTORY:
763 case CREATE_SUBVOLUME:
766 mkdir_parents_label(i->path, 0755);
768 if (i->type == CREATE_SUBVOLUME) {
769 RUN_WITH_UMASK((~i->mode) & 0777)
770 r = btrfs_subvol_make(i->path);
774 if (i->type == CREATE_DIRECTORY || i->type == TRUNCATE_DIRECTORY || r == -ENOTTY) {
776 r = mkdir_label(i->path, i->mode);
781 return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
783 if (stat(i->path, &st) < 0)
784 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
786 if (!S_ISDIR(st.st_mode)) {
787 log_debug("%s already exists and is not a directory.", i->path);
792 r = item_set_perms(i, i->path);
796 r = item_set_xattrs(i, i->path);
804 RUN_WITH_UMASK(0000) {
805 mac_selinux_create_file_prepare(i->path, S_IFIFO);
806 r = mkfifo(i->path, i->mode);
807 mac_selinux_create_file_clear();
812 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
814 if (stat(i->path, &st) < 0)
815 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
817 if (!S_ISFIFO(st.st_mode)) {
821 RUN_WITH_UMASK(0000) {
822 mac_selinux_create_file_prepare(i->path, S_IFIFO);
823 r = mkfifo_atomic(i->path, i->mode);
824 mac_selinux_create_file_clear();
828 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
830 log_debug("%s is not a fifo.", i->path);
836 r = item_set_perms(i, i->path);
840 r = item_set_xattrs(i, i->path);
848 mac_selinux_create_file_prepare(i->path, S_IFLNK);
849 r = symlink(i->argument, i->path);
850 mac_selinux_create_file_clear();
853 _cleanup_free_ char *x = NULL;
856 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
858 r = readlink_malloc(i->path, &x);
859 if (r < 0 || !streq(i->argument, x)) {
862 mac_selinux_create_file_prepare(i->path, S_IFLNK);
863 r = symlink_atomic(i->argument, i->path);
864 mac_selinux_create_file_clear();
867 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
869 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
875 r = item_set_xattrs(i, i->path);
881 case CREATE_BLOCK_DEVICE:
882 case CREATE_CHAR_DEVICE: {
885 if (have_effective_cap(CAP_MKNOD) == 0) {
886 /* In a container we lack CAP_MKNOD. We
887 shouldn't attempt to create the device node in
888 that case to avoid noise, and we don't support
889 virtualized devices in containers anyway. */
891 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
895 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
897 RUN_WITH_UMASK(0000) {
898 mac_selinux_create_file_prepare(i->path, file_type);
899 r = mknod(i->path, i->mode | file_type, i->major_minor);
900 mac_selinux_create_file_clear();
904 if (errno == EPERM) {
905 log_debug("We lack permissions, possibly because of cgroup configuration; "
906 "skipping creation of device node %s.", i->path);
911 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
913 if (stat(i->path, &st) < 0)
914 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
916 if ((st.st_mode & S_IFMT) != file_type) {
920 RUN_WITH_UMASK(0000) {
921 mac_selinux_create_file_prepare(i->path, file_type);
922 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
923 mac_selinux_create_file_clear();
927 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
929 log_debug("%s is not a device node.", i->path);
935 r = item_set_perms(i, i->path);
939 r = item_set_xattrs(i, i->path);
949 r = glob_item(i, item_set_perms);
954 case RECURSIVE_RELABEL_PATH:
956 r = glob_item(i, item_set_perms_recursive);
962 r = item_set_xattrs(i, i->path);
968 log_debug("%s created successfully.", i->path);
973 static int remove_item_instance(Item *i, const char *instance) {
982 case CREATE_DIRECTORY:
983 case CREATE_SUBVOLUME:
986 case CREATE_BLOCK_DEVICE:
987 case CREATE_CHAR_DEVICE:
989 case IGNORE_DIRECTORY_PATH:
992 case RECURSIVE_RELABEL_PATH:
999 if (remove(instance) < 0 && errno != ENOENT)
1000 return log_error_errno(errno, "remove(%s): %m", instance);
1004 case TRUNCATE_DIRECTORY:
1005 case RECURSIVE_REMOVE_PATH:
1006 /* FIXME: we probably should use dir_cleanup() here
1007 * instead of rm_rf() so that 'x' is honoured. */
1008 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1009 if (r < 0 && r != -ENOENT)
1010 return log_error_errno(r, "rm_rf(%s): %m", instance);
1018 static int remove_item(Item *i) {
1027 case CREATE_DIRECTORY:
1028 case CREATE_SUBVOLUME:
1030 case CREATE_SYMLINK:
1031 case CREATE_CHAR_DEVICE:
1032 case CREATE_BLOCK_DEVICE:
1034 case IGNORE_DIRECTORY_PATH:
1037 case RECURSIVE_RELABEL_PATH:
1044 case TRUNCATE_DIRECTORY:
1045 case RECURSIVE_REMOVE_PATH:
1046 r = glob_item(i, remove_item_instance);
1053 static int clean_item_instance(Item *i, const char* instance) {
1054 _cleanup_closedir_ DIR *d = NULL;
1065 n = now(CLOCK_REALTIME);
1069 cutoff = n - i->age;
1071 d = opendir(instance);
1073 if (errno == ENOENT || errno == ENOTDIR)
1076 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1080 if (fstat(dirfd(d), &s) < 0)
1081 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1083 if (!S_ISDIR(s.st_mode)) {
1084 log_error("%s is not a directory.", i->path);
1088 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1089 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1091 mountpoint = s.st_dev != ps.st_dev ||
1092 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1094 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1095 MAX_DEPTH, i->keep_first_level);
1099 static int clean_item(Item *i) {
1105 case CREATE_DIRECTORY:
1106 case CREATE_SUBVOLUME:
1107 case TRUNCATE_DIRECTORY:
1110 clean_item_instance(i, i->path);
1112 case IGNORE_DIRECTORY_PATH:
1113 r = glob_item(i, clean_item_instance);
1122 static int process_item(Item *i) {
1124 _cleanup_free_ char *prefix = NULL;
1133 prefix = malloc(strlen(i->path) + 1);
1137 PATH_FOREACH_PREFIX(prefix, i->path) {
1140 j = hashmap_get(items, prefix);
1144 s = process_item(j);
1145 if (s < 0 && t == 0)
1150 r = arg_create ? create_item(i) : 0;
1151 q = arg_remove ? remove_item(i) : 0;
1152 p = arg_clean ? clean_item(i) : 0;
1160 static void item_free(Item *i) {
1167 strv_free(i->xattrs);
1171 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1173 static bool item_equal(Item *a, Item *b) {
1177 if (!streq_ptr(a->path, b->path))
1180 if (a->type != b->type)
1183 if (a->uid_set != b->uid_set ||
1184 (a->uid_set && a->uid != b->uid))
1187 if (a->gid_set != b->gid_set ||
1188 (a->gid_set && a->gid != b->gid))
1191 if (a->mode_set != b->mode_set ||
1192 (a->mode_set && a->mode != b->mode))
1195 if (a->age_set != b->age_set ||
1196 (a->age_set && a->age != b->age))
1199 if ((a->type == CREATE_FILE ||
1200 a->type == TRUNCATE_FILE ||
1201 a->type == WRITE_FILE ||
1202 a->type == CREATE_SYMLINK ||
1203 a->type == COPY_FILES) &&
1204 !streq_ptr(a->argument, b->argument))
1207 if ((a->type == CREATE_CHAR_DEVICE ||
1208 a->type == CREATE_BLOCK_DEVICE) &&
1209 a->major_minor != b->major_minor)
1215 static bool should_include_path(const char *path) {
1218 STRV_FOREACH(prefix, arg_exclude_prefixes)
1219 if (path_startswith(path, *prefix))
1222 STRV_FOREACH(prefix, arg_include_prefixes)
1223 if (path_startswith(path, *prefix))
1226 /* no matches, so we should include this path only if we
1227 * have no whitelist at all */
1228 return strv_length(arg_include_prefixes) == 0;
1231 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1233 static const Specifier specifier_table[] = {
1234 { 'm', specifier_machine_id, NULL },
1235 { 'b', specifier_boot_id, NULL },
1236 { 'H', specifier_host_name, NULL },
1237 { 'v', specifier_kernel_release, NULL },
1241 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1242 _cleanup_(item_freep) Item *i = NULL;
1253 "%ms %ms %ms %ms %ms %ms %n",
1262 log_error("[%s:%u] Syntax error.", fname, line);
1266 if (isempty(action)) {
1267 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1271 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1272 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1276 if (strchr(action+1, '!') && !arg_boot)
1285 i->force = !!strchr(action+1, '+');
1287 r = specifier_printf(path, specifier_table, NULL, &i->path);
1289 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1294 n += strspn(buffer+n, WHITESPACE);
1295 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1296 i->argument = unquote(buffer+n, "\"");
1306 case CREATE_DIRECTORY:
1307 case CREATE_SUBVOLUME:
1308 case TRUNCATE_DIRECTORY:
1311 case IGNORE_DIRECTORY_PATH:
1313 case RECURSIVE_REMOVE_PATH:
1316 case RECURSIVE_RELABEL_PATH:
1319 case CREATE_SYMLINK:
1321 i->argument = strappend("/usr/share/factory", i->path);
1329 log_error("[%s:%u] Write file requires argument.", fname, line);
1336 i->argument = strappend("/usr/share/factory", i->path);
1341 if (!path_is_absolute(i->argument)) {
1342 log_error("[%s:%u] Source path is not absolute.", fname, line);
1346 path_kill_slashes(i->argument);
1349 case CREATE_CHAR_DEVICE:
1350 case CREATE_BLOCK_DEVICE: {
1351 unsigned major, minor;
1354 log_error("[%s:%u] Device file requires argument.", fname, line);
1358 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1359 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1363 i->major_minor = makedev(major, minor);
1369 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1372 r = get_xattrs_from_arg(i);
1378 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1384 if (!path_is_absolute(i->path)) {
1385 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1389 path_kill_slashes(i->path);
1391 if (!should_include_path(i->path))
1397 p = strappend(arg_root, i->path);
1405 if (user && !streq(user, "-")) {
1406 const char *u = user;
1408 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1410 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1417 if (group && !streq(group, "-")) {
1418 const char *g = group;
1420 r = get_group_creds(&g, &i->gid);
1422 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1429 if (mode && !streq(mode, "-")) {
1430 const char *mm = mode;
1434 i->mask_perms = true;
1438 if (sscanf(mm, "%o", &m) != 1) {
1439 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1447 i->type == CREATE_DIRECTORY ||
1448 i->type == CREATE_SUBVOLUME ||
1449 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1451 if (age && !streq(age, "-")) {
1452 const char *a = age;
1455 i->keep_first_level = true;
1459 if (parse_sec(a, &i->age) < 0) {
1460 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1467 h = needs_glob(i->type) ? globs : items;
1469 existing = hashmap_get(h, i->path);
1471 if (i->type == SET_XATTR) {
1472 r = strv_extend_strv(&existing->xattrs, i->xattrs);
1476 } else if (existing->type == SET_XATTR) {
1477 r = strv_extend_strv(&i->xattrs, existing->xattrs);
1480 r = hashmap_replace(h, i->path, i);
1482 log_error("Failed to replace item for %s.", i->path);
1485 item_free(existing);
1487 /* Two identical items are fine */
1488 if (!item_equal(existing, i))
1489 log_warning("Two or more conflicting lines for %s configured, ignoring.", 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;