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/capability.h>
42 #include <sys/xattr.h>
49 #include "path-util.h"
53 #include "conf-files.h"
54 #include "capability.h"
55 #include "specifier.h"
59 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
60 * them in the file system. This is intended to be used to create
61 * properly owned directories beneath /tmp, /var/tmp, /run, which are
62 * volatile and hence need to be recreated on bootup. */
64 typedef enum ItemType {
65 /* These ones take file names */
68 CREATE_DIRECTORY = 'd',
69 TRUNCATE_DIRECTORY = 'D',
72 CREATE_CHAR_DEVICE = 'c',
73 CREATE_BLOCK_DEVICE = 'b',
77 /* These ones take globs */
80 IGNORE_DIRECTORY_PATH = 'X',
82 RECURSIVE_REMOVE_PATH = 'R',
83 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
85 RECURSIVE_RELABEL_PATH = 'Z',
107 bool keep_first_level:1;
114 static bool arg_create = false;
115 static bool arg_clean = false;
116 static bool arg_remove = false;
117 static bool arg_boot = false;
119 static char **arg_include_prefixes = NULL;
120 static char **arg_exclude_prefixes = NULL;
121 static char *arg_root = NULL;
123 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
125 #define MAX_DEPTH 256
127 static Hashmap *items = NULL, *globs = NULL;
128 static Set *unix_sockets = NULL;
130 static bool needs_glob(ItemType t) {
134 IGNORE_DIRECTORY_PATH,
136 RECURSIVE_REMOVE_PATH,
139 RECURSIVE_RELABEL_PATH);
142 static struct Item* find_glob(Hashmap *h, const char *match) {
146 HASHMAP_FOREACH(j, h, i)
147 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
153 static void load_unix_sockets(void) {
154 _cleanup_fclose_ FILE *f = NULL;
160 /* We maintain a cache of the sockets we found in
161 * /proc/net/unix to speed things up a little. */
163 unix_sockets = set_new(&string_hash_ops);
167 f = fopen("/proc/net/unix", "re");
172 if (!fgets(line, sizeof(line), f))
179 if (!fgets(line, sizeof(line), f))
184 p = strchr(line, ':');
192 p += strspn(p, WHITESPACE);
193 p += strcspn(p, WHITESPACE); /* skip one more word */
194 p += strspn(p, WHITESPACE);
203 path_kill_slashes(s);
205 k = set_consume(unix_sockets, s);
206 if (k < 0 && k != -EEXIST)
213 set_free_free(unix_sockets);
217 static bool unix_socket_alive(const char *fn) {
223 return !!set_get(unix_sockets, (char*) fn);
225 /* We don't know, so assume yes */
229 static int dir_is_mount_point(DIR *d, const char *subdir) {
231 union file_handle_union h = {
232 .handle.handle_bytes = MAX_HANDLE_SZ
235 int mount_id_parent, mount_id;
238 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
242 h.handle.handle_bytes = MAX_HANDLE_SZ;
243 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
247 /* got no handle; make no assumptions, return error */
248 if (r_p < 0 && r < 0)
251 /* got both handles; if they differ, it is a mount point */
252 if (r_p >= 0 && r >= 0)
253 return mount_id_parent != mount_id;
255 /* got only one handle; assume different mount points if one
256 * of both queries was not supported by the filesystem */
257 if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
266 static int dir_cleanup(
270 const struct stat *ds,
275 bool keep_this_level) {
278 struct timespec times[2];
279 bool deleted = false;
282 while ((dent = readdir(d))) {
285 _cleanup_free_ char *sub_path = NULL;
287 if (streq(dent->d_name, ".") ||
288 streq(dent->d_name, ".."))
291 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
295 /* FUSE, NFS mounts, SELinux might return EACCES */
297 log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
299 log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
304 /* Stay on the same filesystem */
305 if (s.st_dev != rootdev)
308 /* Try to detect bind mounts of the same filesystem instance; they
309 * do not differ in device major/minors. This type of query is not
310 * supported on all kernels or filesystem types though. */
311 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
314 /* Do not delete read-only files owned by root */
315 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
318 sub_path = strjoin(p, "/", dent->d_name, NULL);
324 /* Is there an item configured for this path? */
325 if (hashmap_get(items, sub_path))
328 if (find_glob(globs, sub_path))
331 if (S_ISDIR(s.st_mode)) {
334 streq(dent->d_name, "lost+found") &&
339 log_warning("Reached max depth on %s.", sub_path);
341 _cleanup_closedir_ DIR *sub_dir;
344 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
346 if (errno != ENOENT) {
347 log_error_errno(errno, "opendir(%s/%s) failed: %m", p, dent->d_name);
354 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
359 /* Note: if you are wondering why we don't
360 * support the sticky bit for excluding
361 * directories from cleaning like we do it for
362 * other file system objects: well, the sticky
363 * bit already has a meaning for directories,
364 * so we don't want to overload that. */
369 /* Ignore ctime, we change it when deleting */
370 age = MAX(timespec_load(&s.st_mtim),
371 timespec_load(&s.st_atim));
375 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
376 log_debug("rmdir '%s'", sub_path);
378 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
379 if (errno != ENOENT && errno != ENOTEMPTY) {
380 log_error_errno(errno, "rmdir(%s): %m", sub_path);
387 /* Skip files for which the sticky bit is
388 * set. These are semantics we define, and are
389 * unknown elsewhere. See XDG_RUNTIME_DIR
390 * specification for details. */
391 if (s.st_mode & S_ISVTX)
394 if (mountpoint && S_ISREG(s.st_mode)) {
395 if (streq(dent->d_name, ".journal") &&
399 if (streq(dent->d_name, "aquota.user") ||
400 streq(dent->d_name, "aquota.group"))
404 /* Ignore sockets that are listed in /proc/net/unix */
405 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
408 /* Ignore device nodes */
409 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
412 /* Keep files on this level around if this is
417 age = MAX3(timespec_load(&s.st_mtim),
418 timespec_load(&s.st_atim),
419 timespec_load(&s.st_ctim));
424 log_debug("unlink '%s'", sub_path);
426 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
427 if (errno != ENOENT) {
428 log_error_errno(errno, "unlink(%s): %m", sub_path);
439 /* Restore original directory timestamps */
440 times[0] = ds->st_atim;
441 times[1] = ds->st_mtim;
443 if (futimens(dirfd(d), times) < 0)
444 log_error_errno(errno, "utimensat(%s): %m", p);
450 static int item_set_perms(Item *i, const char *path) {
457 st_valid = stat(path, &st) == 0;
459 /* not using i->path directly because it may be a glob */
463 if (i->mask_perms && st_valid) {
464 if (!(st.st_mode & 0111))
466 if (!(st.st_mode & 0222))
468 if (!(st.st_mode & 0444))
470 if (!S_ISDIR(st.st_mode))
471 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
474 if (!st_valid || m != (st.st_mode & 07777)) {
475 if (chmod(path, m) < 0)
476 return log_error_errno(errno, "chmod(%s) failed: %m", path);
480 if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
481 (i->uid_set || i->gid_set))
483 i->uid_set ? i->uid : UID_INVALID,
484 i->gid_set ? i->gid : GID_INVALID) < 0) {
486 log_error_errno(errno, "chown(%s) failed: %m", path);
490 return label_fix(path, false, false);
493 static int get_xattrs_from_arg(Item *i) {
501 log_error("%s: Argument can't be empty!", i->path);
506 while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
507 _cleanup_free_ char *tmp = NULL, *name = NULL, *value = NULL;
508 r = split_pair(xattr, "=", &name, &value);
510 log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
515 if (streq(name, "") || streq(value, "")) {
516 log_warning("Malformed xattr found: \"%s=%s\" - ignoring.", name, value);
519 tmp = unquote(value, "\"");
523 value = cunescape(tmp);
526 if (strv_consume_pair(&i->xattrs, name, value) < 0)
534 static int item_set_xattrs(Item *i, const char *path) {
535 char **name, **value;
540 if (strv_isempty(i->xattrs))
543 STRV_FOREACH_PAIR(name, value, i->xattrs) {
546 if (lsetxattr(path, *name, *value, n, 0) < 0) {
547 log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path);
554 static int write_one_file(Item *i, const char *path) {
555 _cleanup_close_ int fd = -1;
562 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
563 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
565 RUN_WITH_UMASK(0000) {
566 mac_selinux_create_file_prepare(path, S_IFREG);
567 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
568 mac_selinux_create_file_clear();
572 if (i->type == WRITE_FILE && errno == ENOENT)
575 log_error_errno(errno, "Failed to create file %s: %m", path);
580 _cleanup_free_ char *unescaped;
584 unescaped = cunescape(i->argument);
588 l = strlen(unescaped);
589 n = write(fd, unescaped, l);
591 if (n < 0 || (size_t) n < l) {
592 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
593 return n < 0 ? n : -EIO;
599 if (stat(path, &st) < 0)
600 return log_error_errno(errno, "stat(%s) failed: %m", path);
602 if (!S_ISREG(st.st_mode)) {
603 log_error("%s is not a file.", path);
607 r = item_set_perms(i, path);
611 r = item_set_xattrs(i, i->path);
618 static int item_set_perms_children(Item *i, const char *path) {
619 _cleanup_closedir_ DIR *d;
625 /* This returns the first error we run into, but nevertheless
630 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
633 _cleanup_free_ char *p = NULL;
640 if (errno != 0 && r == 0)
646 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
649 p = strjoin(path, "/", de->d_name, NULL);
653 q = item_set_perms(i, p);
654 if (q < 0 && q != -ENOENT && r == 0)
657 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
658 q = item_set_perms_children(i, p);
667 static int item_set_perms_recursive(Item *i, const char *path) {
673 r = item_set_perms(i, path);
677 q = item_set_perms_children(i, path);
684 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
685 _cleanup_globfree_ glob_t g = {};
690 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
691 if (k != 0 && k != GLOB_NOMATCH) {
695 log_error_errno(errno, "glob(%s) failed: %m", i->path);
699 STRV_FOREACH(fn, g.gl_pathv) {
708 static int create_item(Item *i) {
717 case IGNORE_DIRECTORY_PATH:
719 case RECURSIVE_REMOVE_PATH:
724 r = write_one_file(i, i->path);
730 r = copy_tree(i->argument, i->path, false);
735 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
737 if (stat(i->argument, &a) < 0)
738 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
740 if (stat(i->path, &b) < 0)
741 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
743 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
744 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
749 r = item_set_perms(i, i->path);
756 r = glob_item(i, write_one_file);
762 case TRUNCATE_DIRECTORY:
763 case CREATE_DIRECTORY:
765 RUN_WITH_UMASK(0000) {
766 mkdir_parents_label(i->path, 0755);
767 r = mkdir_label(i->path, i->mode);
772 return log_error_errno(r, "Failed to create directory %s: %m", i->path);
774 if (stat(i->path, &st) < 0)
775 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
777 if (!S_ISDIR(st.st_mode)) {
778 log_debug("%s already exists and is not a directory.", i->path);
783 r = item_set_perms(i, i->path);
787 r = item_set_xattrs(i, i->path);
795 RUN_WITH_UMASK(0000) {
796 mac_selinux_create_file_prepare(i->path, S_IFIFO);
797 r = mkfifo(i->path, i->mode);
798 mac_selinux_create_file_clear();
803 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
805 if (stat(i->path, &st) < 0)
806 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
808 if (!S_ISFIFO(st.st_mode)) {
812 RUN_WITH_UMASK(0000) {
813 mac_selinux_create_file_prepare(i->path, S_IFIFO);
814 r = mkfifo_atomic(i->path, i->mode);
815 mac_selinux_create_file_clear();
819 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
821 log_debug("%s is not a fifo.", i->path);
827 r = item_set_perms(i, i->path);
831 r = item_set_xattrs(i, i->path);
839 mac_selinux_create_file_prepare(i->path, S_IFLNK);
840 r = symlink(i->argument, i->path);
841 mac_selinux_create_file_clear();
844 _cleanup_free_ char *x = NULL;
847 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
849 r = readlink_malloc(i->path, &x);
850 if (r < 0 || !streq(i->argument, x)) {
853 mac_selinux_create_file_prepare(i->path, S_IFLNK);
854 r = symlink_atomic(i->argument, i->path);
855 mac_selinux_create_file_clear();
858 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
860 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
866 r = item_set_xattrs(i, i->path);
872 case CREATE_BLOCK_DEVICE:
873 case CREATE_CHAR_DEVICE: {
876 if (have_effective_cap(CAP_MKNOD) == 0) {
877 /* In a container we lack CAP_MKNOD. We
878 shouldn't attempt to create the device node in
879 that case to avoid noise, and we don't support
880 virtualized devices in containers anyway. */
882 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
886 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
888 RUN_WITH_UMASK(0000) {
889 mac_selinux_create_file_prepare(i->path, file_type);
890 r = mknod(i->path, i->mode | file_type, i->major_minor);
891 mac_selinux_create_file_clear();
895 if (errno == EPERM) {
896 log_debug("We lack permissions, possibly because of cgroup configuration; "
897 "skipping creation of device node %s.", i->path);
902 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
904 if (stat(i->path, &st) < 0)
905 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
907 if ((st.st_mode & S_IFMT) != file_type) {
911 RUN_WITH_UMASK(0000) {
912 mac_selinux_create_file_prepare(i->path, file_type);
913 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
914 mac_selinux_create_file_clear();
918 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
920 log_debug("%s is not a device node.", i->path);
926 r = item_set_perms(i, i->path);
930 r = item_set_xattrs(i, i->path);
940 r = glob_item(i, item_set_perms);
945 case RECURSIVE_RELABEL_PATH:
947 r = glob_item(i, item_set_perms_recursive);
953 r = item_set_xattrs(i, i->path);
959 log_debug("%s created successfully.", i->path);
964 static int remove_item_instance(Item *i, const char *instance) {
973 case CREATE_DIRECTORY:
976 case CREATE_BLOCK_DEVICE:
977 case CREATE_CHAR_DEVICE:
979 case IGNORE_DIRECTORY_PATH:
982 case RECURSIVE_RELABEL_PATH:
989 if (remove(instance) < 0 && errno != ENOENT)
990 return log_error_errno(errno, "remove(%s): %m", instance);
994 case TRUNCATE_DIRECTORY:
995 case RECURSIVE_REMOVE_PATH:
996 /* FIXME: we probably should use dir_cleanup() here
997 * instead of rm_rf() so that 'x' is honoured. */
998 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
999 if (r < 0 && r != -ENOENT)
1000 return log_error_errno(r, "rm_rf(%s): %m", instance);
1008 static int remove_item(Item *i) {
1017 case CREATE_DIRECTORY:
1019 case CREATE_SYMLINK:
1020 case CREATE_CHAR_DEVICE:
1021 case CREATE_BLOCK_DEVICE:
1023 case IGNORE_DIRECTORY_PATH:
1026 case RECURSIVE_RELABEL_PATH:
1033 case TRUNCATE_DIRECTORY:
1034 case RECURSIVE_REMOVE_PATH:
1035 r = glob_item(i, remove_item_instance);
1042 static int clean_item_instance(Item *i, const char* instance) {
1043 _cleanup_closedir_ DIR *d = NULL;
1054 n = now(CLOCK_REALTIME);
1058 cutoff = n - i->age;
1060 d = opendir(instance);
1062 if (errno == ENOENT || errno == ENOTDIR)
1065 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1069 if (fstat(dirfd(d), &s) < 0)
1070 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1072 if (!S_ISDIR(s.st_mode)) {
1073 log_error("%s is not a directory.", i->path);
1077 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1078 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1080 mountpoint = s.st_dev != ps.st_dev ||
1081 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1083 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1084 MAX_DEPTH, i->keep_first_level);
1088 static int clean_item(Item *i) {
1094 case CREATE_DIRECTORY:
1095 case TRUNCATE_DIRECTORY:
1098 clean_item_instance(i, i->path);
1100 case IGNORE_DIRECTORY_PATH:
1101 r = glob_item(i, clean_item_instance);
1110 static int process_item(Item *i) {
1112 _cleanup_free_ char *prefix = NULL;
1121 prefix = malloc(strlen(i->path) + 1);
1125 PATH_FOREACH_PREFIX(prefix, i->path) {
1128 j = hashmap_get(items, prefix);
1133 r = arg_create ? create_item(i) : 0;
1134 q = arg_remove ? remove_item(i) : 0;
1135 p = arg_clean ? clean_item(i) : 0;
1146 static void item_free(Item *i) {
1153 strv_free(i->xattrs);
1157 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1159 static bool item_equal(Item *a, Item *b) {
1163 if (!streq_ptr(a->path, b->path))
1166 if (a->type != b->type)
1169 if (a->uid_set != b->uid_set ||
1170 (a->uid_set && a->uid != b->uid))
1173 if (a->gid_set != b->gid_set ||
1174 (a->gid_set && a->gid != b->gid))
1177 if (a->mode_set != b->mode_set ||
1178 (a->mode_set && a->mode != b->mode))
1181 if (a->age_set != b->age_set ||
1182 (a->age_set && a->age != b->age))
1185 if ((a->type == CREATE_FILE ||
1186 a->type == TRUNCATE_FILE ||
1187 a->type == WRITE_FILE ||
1188 a->type == CREATE_SYMLINK ||
1189 a->type == COPY_FILES) &&
1190 !streq_ptr(a->argument, b->argument))
1193 if ((a->type == CREATE_CHAR_DEVICE ||
1194 a->type == CREATE_BLOCK_DEVICE) &&
1195 a->major_minor != b->major_minor)
1201 static bool should_include_path(const char *path) {
1204 STRV_FOREACH(prefix, arg_exclude_prefixes)
1205 if (path_startswith(path, *prefix))
1208 STRV_FOREACH(prefix, arg_include_prefixes)
1209 if (path_startswith(path, *prefix))
1212 /* no matches, so we should include this path only if we
1213 * have no whitelist at all */
1214 return strv_length(arg_include_prefixes) == 0;
1217 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1219 static const Specifier specifier_table[] = {
1220 { 'm', specifier_machine_id, NULL },
1221 { 'b', specifier_boot_id, NULL },
1222 { 'H', specifier_host_name, NULL },
1223 { 'v', specifier_kernel_release, NULL },
1227 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1228 _cleanup_(item_freep) Item *i = NULL;
1239 "%ms %ms %ms %ms %ms %ms %n",
1248 log_error("[%s:%u] Syntax error.", fname, line);
1252 if (isempty(action)) {
1253 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1257 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1258 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1262 if (strchr(action+1, '!') && !arg_boot)
1271 i->force = !!strchr(action+1, '+');
1273 r = specifier_printf(path, specifier_table, NULL, &i->path);
1275 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1280 n += strspn(buffer+n, WHITESPACE);
1281 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1282 i->argument = unquote(buffer+n, "\"");
1292 case CREATE_DIRECTORY:
1293 case TRUNCATE_DIRECTORY:
1296 case IGNORE_DIRECTORY_PATH:
1298 case RECURSIVE_REMOVE_PATH:
1301 case RECURSIVE_RELABEL_PATH:
1304 case CREATE_SYMLINK:
1306 i->argument = strappend("/usr/share/factory", i->path);
1314 log_error("[%s:%u] Write file requires argument.", fname, line);
1321 i->argument = strappend("/usr/share/factory", i->path);
1326 if (!path_is_absolute(i->argument)) {
1327 log_error("[%s:%u] Source path is not absolute.", fname, line);
1331 path_kill_slashes(i->argument);
1334 case CREATE_CHAR_DEVICE:
1335 case CREATE_BLOCK_DEVICE: {
1336 unsigned major, minor;
1339 log_error("[%s:%u] Device file requires argument.", fname, line);
1343 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1344 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1348 i->major_minor = makedev(major, minor);
1354 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1357 r = get_xattrs_from_arg(i);
1363 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1369 if (!path_is_absolute(i->path)) {
1370 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1374 path_kill_slashes(i->path);
1376 if (!should_include_path(i->path))
1382 p = strappend(arg_root, i->path);
1390 if (user && !streq(user, "-")) {
1391 const char *u = user;
1393 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1395 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1402 if (group && !streq(group, "-")) {
1403 const char *g = group;
1405 r = get_group_creds(&g, &i->gid);
1407 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1414 if (mode && !streq(mode, "-")) {
1415 const char *mm = mode;
1419 i->mask_perms = true;
1423 if (sscanf(mm, "%o", &m) != 1) {
1424 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1432 i->type == CREATE_DIRECTORY ||
1433 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1435 if (age && !streq(age, "-")) {
1436 const char *a = age;
1439 i->keep_first_level = true;
1443 if (parse_sec(a, &i->age) < 0) {
1444 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1451 h = needs_glob(i->type) ? globs : items;
1453 existing = hashmap_get(h, i->path);
1455 if (i->type == SET_XATTR) {
1456 r = strv_extend_strv(&existing->xattrs, i->xattrs);
1460 } else if (existing->type == SET_XATTR) {
1461 r = strv_extend_strv(&i->xattrs, existing->xattrs);
1464 r = hashmap_replace(h, i->path, i);
1466 log_error("Failed to replace item for %s.", i->path);
1469 item_free(existing);
1471 /* Two identical items are fine */
1472 if (!item_equal(existing, i))
1473 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1477 r = hashmap_put(h, i->path, i);
1479 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1484 i = NULL; /* avoid cleanup */
1489 static void help(void) {
1490 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1491 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1492 " -h --help Show this help\n"
1493 " --version Show package version\n"
1494 " --create Create marked files/directories\n"
1495 " --clean Clean up marked directories\n"
1496 " --remove Remove marked files/directories\n"
1497 " --boot Execute actions only safe at boot\n"
1498 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1499 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1500 " --root=PATH Operate on an alternate filesystem root\n",
1501 program_invocation_short_name);
1504 static int parse_argv(int argc, char *argv[]) {
1507 ARG_VERSION = 0x100,
1517 static const struct option options[] = {
1518 { "help", no_argument, NULL, 'h' },
1519 { "version", no_argument, NULL, ARG_VERSION },
1520 { "create", no_argument, NULL, ARG_CREATE },
1521 { "clean", no_argument, NULL, ARG_CLEAN },
1522 { "remove", no_argument, NULL, ARG_REMOVE },
1523 { "boot", no_argument, NULL, ARG_BOOT },
1524 { "prefix", required_argument, NULL, ARG_PREFIX },
1525 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1526 { "root", required_argument, NULL, ARG_ROOT },
1535 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1544 puts(PACKAGE_STRING);
1545 puts(SYSTEMD_FEATURES);
1565 if (strv_push(&arg_include_prefixes, optarg) < 0)
1569 case ARG_EXCLUDE_PREFIX:
1570 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1576 arg_root = path_make_absolute_cwd(optarg);
1580 path_kill_slashes(arg_root);
1587 assert_not_reached("Unhandled option");
1590 if (!arg_clean && !arg_create && !arg_remove) {
1591 log_error("You need to specify at least one of --clean, --create or --remove.");
1598 static int read_config_file(const char *fn, bool ignore_enoent) {
1599 _cleanup_fclose_ FILE *f = NULL;
1600 char line[LINE_MAX];
1608 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1610 if (ignore_enoent && r == -ENOENT)
1613 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1616 FOREACH_LINE(line, f, break) {
1623 if (*l == '#' || *l == 0)
1626 k = parse_line(fn, v, l);
1627 if (k < 0 && r == 0)
1631 /* we have to determine age parameter for each entry of type X */
1632 HASHMAP_FOREACH(i, globs, iterator) {
1634 Item *j, *candidate_item = NULL;
1636 if (i->type != IGNORE_DIRECTORY_PATH)
1639 HASHMAP_FOREACH(j, items, iter) {
1640 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1643 if (path_equal(j->path, i->path)) {
1648 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1649 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1653 if (candidate_item && candidate_item->age_set) {
1654 i->age = candidate_item->age;
1660 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1668 int main(int argc, char *argv[]) {
1673 r = parse_argv(argc, argv);
1677 log_set_target(LOG_TARGET_AUTO);
1678 log_parse_environment();
1683 mac_selinux_init(NULL);
1685 items = hashmap_new(&string_hash_ops);
1686 globs = hashmap_new(&string_hash_ops);
1688 if (!items || !globs) {
1695 if (optind < argc) {
1698 for (j = optind; j < argc; j++) {
1699 k = read_config_file(argv[j], false);
1700 if (k < 0 && r == 0)
1705 _cleanup_strv_free_ char **files = NULL;
1708 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1710 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1714 STRV_FOREACH(f, files) {
1715 k = read_config_file(*f, true);
1716 if (k < 0 && r == 0)
1721 HASHMAP_FOREACH(i, globs, iterator)
1724 HASHMAP_FOREACH(i, items, iterator)
1728 while ((i = hashmap_steal_first(items)))
1731 while ((i = hashmap_steal_first(globs)))
1734 hashmap_free(items);
1735 hashmap_free(globs);
1737 free(arg_include_prefixes);
1738 free(arg_exclude_prefixes);
1741 set_free_free(unix_sockets);
1743 mac_selinux_finish();
1745 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;