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"
58 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
59 * them in the file system. This is intended to be used to create
60 * properly owned directories beneath /tmp, /var/tmp, /run, which are
61 * volatile and hence need to be recreated on bootup. */
63 typedef enum ItemType {
64 /* These ones take file names */
67 CREATE_DIRECTORY = 'd',
68 TRUNCATE_DIRECTORY = 'D',
71 CREATE_CHAR_DEVICE = 'c',
72 CREATE_BLOCK_DEVICE = 'b',
76 /* These ones take globs */
79 IGNORE_DIRECTORY_PATH = 'X',
81 RECURSIVE_REMOVE_PATH = 'R',
82 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
84 RECURSIVE_RELABEL_PATH = 'Z',
106 bool keep_first_level:1;
113 static bool arg_create = false;
114 static bool arg_clean = false;
115 static bool arg_remove = false;
116 static bool arg_boot = false;
118 static char **arg_include_prefixes = NULL;
119 static char **arg_exclude_prefixes = NULL;
120 static char *arg_root = NULL;
122 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
124 #define MAX_DEPTH 256
126 static Hashmap *items = NULL, *globs = NULL;
127 static Set *unix_sockets = NULL;
129 static bool needs_glob(ItemType t) {
133 IGNORE_DIRECTORY_PATH,
135 RECURSIVE_REMOVE_PATH,
138 RECURSIVE_RELABEL_PATH);
141 static struct Item* find_glob(Hashmap *h, const char *match) {
145 HASHMAP_FOREACH(j, h, i)
146 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
152 static void load_unix_sockets(void) {
153 _cleanup_fclose_ FILE *f = NULL;
159 /* We maintain a cache of the sockets we found in
160 * /proc/net/unix to speed things up a little. */
162 unix_sockets = set_new(&string_hash_ops);
166 f = fopen("/proc/net/unix", "re");
171 if (!fgets(line, sizeof(line), f))
178 if (!fgets(line, sizeof(line), f))
183 p = strchr(line, ':');
191 p += strspn(p, WHITESPACE);
192 p += strcspn(p, WHITESPACE); /* skip one more word */
193 p += strspn(p, WHITESPACE);
202 path_kill_slashes(s);
204 k = set_consume(unix_sockets, s);
205 if (k < 0 && k != -EEXIST)
212 set_free_free(unix_sockets);
216 static bool unix_socket_alive(const char *fn) {
222 return !!set_get(unix_sockets, (char*) fn);
224 /* We don't know, so assume yes */
228 static int dir_is_mount_point(DIR *d, const char *subdir) {
230 union file_handle_union h = {
231 .handle.handle_bytes = MAX_HANDLE_SZ
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 TRUNCATE_DIRECTORY:
762 case CREATE_DIRECTORY:
764 RUN_WITH_UMASK(0000) {
765 mkdir_parents_label(i->path, 0755);
766 r = mkdir_label(i->path, i->mode);
771 return log_error_errno(r, "Failed to create directory %s: %m", i->path);
773 if (stat(i->path, &st) < 0)
774 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
776 if (!S_ISDIR(st.st_mode)) {
777 log_debug("%s already exists and is not a directory.", i->path);
782 r = item_set_perms(i, i->path);
786 r = item_set_xattrs(i, i->path);
794 RUN_WITH_UMASK(0000) {
795 mac_selinux_create_file_prepare(i->path, S_IFIFO);
796 r = mkfifo(i->path, i->mode);
797 mac_selinux_create_file_clear();
802 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
804 if (stat(i->path, &st) < 0)
805 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
807 if (!S_ISFIFO(st.st_mode)) {
811 RUN_WITH_UMASK(0000) {
812 mac_selinux_create_file_prepare(i->path, S_IFIFO);
813 r = mkfifo_atomic(i->path, i->mode);
814 mac_selinux_create_file_clear();
818 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
820 log_debug("%s is not a fifo.", i->path);
826 r = item_set_perms(i, i->path);
830 r = item_set_xattrs(i, i->path);
838 mac_selinux_create_file_prepare(i->path, S_IFLNK);
839 r = symlink(i->argument, i->path);
840 mac_selinux_create_file_clear();
843 _cleanup_free_ char *x = NULL;
846 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
848 r = readlink_malloc(i->path, &x);
849 if (r < 0 || !streq(i->argument, x)) {
852 mac_selinux_create_file_prepare(i->path, S_IFLNK);
853 r = symlink_atomic(i->argument, i->path);
854 mac_selinux_create_file_clear();
857 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
859 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
865 r = item_set_xattrs(i, i->path);
871 case CREATE_BLOCK_DEVICE:
872 case CREATE_CHAR_DEVICE: {
875 if (have_effective_cap(CAP_MKNOD) == 0) {
876 /* In a container we lack CAP_MKNOD. We
877 shouldn't attempt to create the device node in
878 that case to avoid noise, and we don't support
879 virtualized devices in containers anyway. */
881 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
885 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
887 RUN_WITH_UMASK(0000) {
888 mac_selinux_create_file_prepare(i->path, file_type);
889 r = mknod(i->path, i->mode | file_type, i->major_minor);
890 mac_selinux_create_file_clear();
894 if (errno == EPERM) {
895 log_debug("We lack permissions, possibly because of cgroup configuration; "
896 "skipping creation of device node %s.", i->path);
901 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
903 if (stat(i->path, &st) < 0)
904 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
906 if ((st.st_mode & S_IFMT) != file_type) {
910 RUN_WITH_UMASK(0000) {
911 mac_selinux_create_file_prepare(i->path, file_type);
912 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
913 mac_selinux_create_file_clear();
917 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
919 log_debug("%s is not a device node.", i->path);
925 r = item_set_perms(i, i->path);
929 r = item_set_xattrs(i, i->path);
939 r = glob_item(i, item_set_perms);
944 case RECURSIVE_RELABEL_PATH:
946 r = glob_item(i, item_set_perms_recursive);
952 r = item_set_xattrs(i, i->path);
958 log_debug("%s created successfully.", i->path);
963 static int remove_item_instance(Item *i, const char *instance) {
972 case CREATE_DIRECTORY:
975 case CREATE_BLOCK_DEVICE:
976 case CREATE_CHAR_DEVICE:
978 case IGNORE_DIRECTORY_PATH:
981 case RECURSIVE_RELABEL_PATH:
988 if (remove(instance) < 0 && errno != ENOENT)
989 return log_error_errno(errno, "remove(%s): %m", instance);
993 case TRUNCATE_DIRECTORY:
994 case RECURSIVE_REMOVE_PATH:
995 /* FIXME: we probably should use dir_cleanup() here
996 * instead of rm_rf() so that 'x' is honoured. */
997 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
998 if (r < 0 && r != -ENOENT)
999 return log_error_errno(r, "rm_rf(%s): %m", instance);
1007 static int remove_item(Item *i) {
1016 case CREATE_DIRECTORY:
1018 case CREATE_SYMLINK:
1019 case CREATE_CHAR_DEVICE:
1020 case CREATE_BLOCK_DEVICE:
1022 case IGNORE_DIRECTORY_PATH:
1025 case RECURSIVE_RELABEL_PATH:
1032 case TRUNCATE_DIRECTORY:
1033 case RECURSIVE_REMOVE_PATH:
1034 r = glob_item(i, remove_item_instance);
1041 static int clean_item_instance(Item *i, const char* instance) {
1042 _cleanup_closedir_ DIR *d = NULL;
1053 n = now(CLOCK_REALTIME);
1057 cutoff = n - i->age;
1059 d = opendir(instance);
1061 if (errno == ENOENT || errno == ENOTDIR)
1064 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1068 if (fstat(dirfd(d), &s) < 0)
1069 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1071 if (!S_ISDIR(s.st_mode)) {
1072 log_error("%s is not a directory.", i->path);
1076 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1077 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1079 mountpoint = s.st_dev != ps.st_dev ||
1080 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1082 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1083 MAX_DEPTH, i->keep_first_level);
1087 static int clean_item(Item *i) {
1093 case CREATE_DIRECTORY:
1094 case TRUNCATE_DIRECTORY:
1097 clean_item_instance(i, i->path);
1099 case IGNORE_DIRECTORY_PATH:
1100 r = glob_item(i, clean_item_instance);
1109 static int process_item(Item *i) {
1111 _cleanup_free_ char *prefix = NULL;
1120 prefix = malloc(strlen(i->path) + 1);
1124 PATH_FOREACH_PREFIX(prefix, i->path) {
1127 j = hashmap_get(items, prefix);
1132 r = arg_create ? create_item(i) : 0;
1133 q = arg_remove ? remove_item(i) : 0;
1134 p = arg_clean ? clean_item(i) : 0;
1145 static void item_free(Item *i) {
1152 strv_free(i->xattrs);
1156 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1158 static bool item_equal(Item *a, Item *b) {
1162 if (!streq_ptr(a->path, b->path))
1165 if (a->type != b->type)
1168 if (a->uid_set != b->uid_set ||
1169 (a->uid_set && a->uid != b->uid))
1172 if (a->gid_set != b->gid_set ||
1173 (a->gid_set && a->gid != b->gid))
1176 if (a->mode_set != b->mode_set ||
1177 (a->mode_set && a->mode != b->mode))
1180 if (a->age_set != b->age_set ||
1181 (a->age_set && a->age != b->age))
1184 if ((a->type == CREATE_FILE ||
1185 a->type == TRUNCATE_FILE ||
1186 a->type == WRITE_FILE ||
1187 a->type == CREATE_SYMLINK ||
1188 a->type == COPY_FILES) &&
1189 !streq_ptr(a->argument, b->argument))
1192 if ((a->type == CREATE_CHAR_DEVICE ||
1193 a->type == CREATE_BLOCK_DEVICE) &&
1194 a->major_minor != b->major_minor)
1200 static bool should_include_path(const char *path) {
1203 STRV_FOREACH(prefix, arg_exclude_prefixes)
1204 if (path_startswith(path, *prefix))
1207 STRV_FOREACH(prefix, arg_include_prefixes)
1208 if (path_startswith(path, *prefix))
1211 /* no matches, so we should include this path only if we
1212 * have no whitelist at all */
1213 return strv_length(arg_include_prefixes) == 0;
1216 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1218 static const Specifier specifier_table[] = {
1219 { 'm', specifier_machine_id, NULL },
1220 { 'b', specifier_boot_id, NULL },
1221 { 'H', specifier_host_name, NULL },
1222 { 'v', specifier_kernel_release, NULL },
1226 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1227 _cleanup_(item_freep) Item *i = NULL;
1238 "%ms %ms %ms %ms %ms %ms %n",
1247 log_error("[%s:%u] Syntax error.", fname, line);
1251 if (isempty(action)) {
1252 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1256 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1257 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1261 if (strchr(action+1, '!') && !arg_boot)
1270 i->force = !!strchr(action+1, '+');
1272 r = specifier_printf(path, specifier_table, NULL, &i->path);
1274 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1279 n += strspn(buffer+n, WHITESPACE);
1280 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1281 i->argument = unquote(buffer+n, "\"");
1291 case CREATE_DIRECTORY:
1292 case TRUNCATE_DIRECTORY:
1295 case IGNORE_DIRECTORY_PATH:
1297 case RECURSIVE_REMOVE_PATH:
1300 case RECURSIVE_RELABEL_PATH:
1303 case CREATE_SYMLINK:
1305 i->argument = strappend("/usr/share/factory", i->path);
1313 log_error("[%s:%u] Write file requires argument.", fname, line);
1320 i->argument = strappend("/usr/share/factory", i->path);
1325 if (!path_is_absolute(i->argument)) {
1326 log_error("[%s:%u] Source path is not absolute.", fname, line);
1330 path_kill_slashes(i->argument);
1333 case CREATE_CHAR_DEVICE:
1334 case CREATE_BLOCK_DEVICE: {
1335 unsigned major, minor;
1338 log_error("[%s:%u] Device file requires argument.", fname, line);
1342 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1343 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1347 i->major_minor = makedev(major, minor);
1353 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1356 r = get_xattrs_from_arg(i);
1362 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1368 if (!path_is_absolute(i->path)) {
1369 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1373 path_kill_slashes(i->path);
1375 if (!should_include_path(i->path))
1381 p = strappend(arg_root, i->path);
1389 if (user && !streq(user, "-")) {
1390 const char *u = user;
1392 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1394 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1401 if (group && !streq(group, "-")) {
1402 const char *g = group;
1404 r = get_group_creds(&g, &i->gid);
1406 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1413 if (mode && !streq(mode, "-")) {
1414 const char *mm = mode;
1418 i->mask_perms = true;
1422 if (sscanf(mm, "%o", &m) != 1) {
1423 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1431 i->type == CREATE_DIRECTORY ||
1432 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1434 if (age && !streq(age, "-")) {
1435 const char *a = age;
1438 i->keep_first_level = true;
1442 if (parse_sec(a, &i->age) < 0) {
1443 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1450 h = needs_glob(i->type) ? globs : items;
1452 existing = hashmap_get(h, i->path);
1454 if (i->type == SET_XATTR) {
1455 r = strv_extend_strv(&existing->xattrs, i->xattrs);
1459 } else if (existing->type == SET_XATTR) {
1460 r = strv_extend_strv(&i->xattrs, existing->xattrs);
1463 r = hashmap_replace(h, i->path, i);
1465 log_error("Failed to replace item for %s.", i->path);
1468 item_free(existing);
1470 /* Two identical items are fine */
1471 if (!item_equal(existing, i))
1472 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1476 r = hashmap_put(h, i->path, i);
1478 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1483 i = NULL; /* avoid cleanup */
1488 static void help(void) {
1489 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1490 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1491 " -h --help Show this help\n"
1492 " --version Show package version\n"
1493 " --create Create marked files/directories\n"
1494 " --clean Clean up marked directories\n"
1495 " --remove Remove marked files/directories\n"
1496 " --boot Execute actions only safe at boot\n"
1497 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1498 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1499 " --root=PATH Operate on an alternate filesystem root\n",
1500 program_invocation_short_name);
1503 static int parse_argv(int argc, char *argv[]) {
1506 ARG_VERSION = 0x100,
1516 static const struct option options[] = {
1517 { "help", no_argument, NULL, 'h' },
1518 { "version", no_argument, NULL, ARG_VERSION },
1519 { "create", no_argument, NULL, ARG_CREATE },
1520 { "clean", no_argument, NULL, ARG_CLEAN },
1521 { "remove", no_argument, NULL, ARG_REMOVE },
1522 { "boot", no_argument, NULL, ARG_BOOT },
1523 { "prefix", required_argument, NULL, ARG_PREFIX },
1524 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1525 { "root", required_argument, NULL, ARG_ROOT },
1534 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1543 puts(PACKAGE_STRING);
1544 puts(SYSTEMD_FEATURES);
1564 if (strv_push(&arg_include_prefixes, optarg) < 0)
1568 case ARG_EXCLUDE_PREFIX:
1569 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1575 arg_root = path_make_absolute_cwd(optarg);
1579 path_kill_slashes(arg_root);
1586 assert_not_reached("Unhandled option");
1589 if (!arg_clean && !arg_create && !arg_remove) {
1590 log_error("You need to specify at least one of --clean, --create or --remove.");
1597 static int read_config_file(const char *fn, bool ignore_enoent) {
1598 _cleanup_fclose_ FILE *f = NULL;
1599 char line[LINE_MAX];
1607 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1609 if (ignore_enoent && r == -ENOENT)
1612 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1615 FOREACH_LINE(line, f, break) {
1622 if (*l == '#' || *l == 0)
1625 k = parse_line(fn, v, l);
1626 if (k < 0 && r == 0)
1630 /* we have to determine age parameter for each entry of type X */
1631 HASHMAP_FOREACH(i, globs, iterator) {
1633 Item *j, *candidate_item = NULL;
1635 if (i->type != IGNORE_DIRECTORY_PATH)
1638 HASHMAP_FOREACH(j, items, iter) {
1639 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1642 if (path_equal(j->path, i->path)) {
1647 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1648 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1652 if (candidate_item && candidate_item->age_set) {
1653 i->age = candidate_item->age;
1659 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1667 int main(int argc, char *argv[]) {
1672 r = parse_argv(argc, argv);
1676 log_set_target(LOG_TARGET_AUTO);
1677 log_parse_environment();
1682 mac_selinux_init(NULL);
1684 items = hashmap_new(&string_hash_ops);
1685 globs = hashmap_new(&string_hash_ops);
1687 if (!items || !globs) {
1694 if (optind < argc) {
1697 for (j = optind; j < argc; j++) {
1698 k = read_config_file(argv[j], false);
1699 if (k < 0 && r == 0)
1704 _cleanup_strv_free_ char **files = NULL;
1707 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1709 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1713 STRV_FOREACH(f, files) {
1714 k = read_config_file(*f, true);
1715 if (k < 0 && r == 0)
1720 HASHMAP_FOREACH(i, globs, iterator)
1723 HASHMAP_FOREACH(i, items, iterator)
1727 while ((i = hashmap_steal_first(items)))
1730 while ((i = hashmap_steal_first(globs)))
1733 hashmap_free(items);
1734 hashmap_free(globs);
1736 free(arg_include_prefixes);
1737 free(arg_exclude_prefixes);
1740 set_free_free(unix_sockets);
1742 mac_selinux_finish();
1744 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;