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>
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',
75 /* These ones take globs */
78 IGNORE_DIRECTORY_PATH = 'X',
80 RECURSIVE_REMOVE_PATH = 'R',
81 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
83 RECURSIVE_RELABEL_PATH = 'Z',
104 bool keep_first_level:1;
111 static bool arg_create = false;
112 static bool arg_clean = false;
113 static bool arg_remove = false;
114 static bool arg_boot = false;
116 static char **arg_include_prefixes = NULL;
117 static char **arg_exclude_prefixes = NULL;
118 static char *arg_root = NULL;
120 static const char conf_file_dirs[] =
123 "/usr/local/lib/tmpfiles.d\0"
124 "/usr/lib/tmpfiles.d\0"
125 #ifdef HAVE_SPLIT_USR
130 #define MAX_DEPTH 256
132 static Hashmap *items = NULL, *globs = NULL;
133 static Set *unix_sockets = NULL;
135 static bool needs_glob(ItemType t) {
139 IGNORE_DIRECTORY_PATH,
141 RECURSIVE_REMOVE_PATH,
144 RECURSIVE_RELABEL_PATH);
147 static struct Item* find_glob(Hashmap *h, const char *match) {
151 HASHMAP_FOREACH(j, h, i)
152 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
158 static void load_unix_sockets(void) {
159 _cleanup_fclose_ FILE *f = NULL;
165 /* We maintain a cache of the sockets we found in
166 * /proc/net/unix to speed things up a little. */
168 unix_sockets = set_new(&string_hash_ops);
172 f = fopen("/proc/net/unix", "re");
177 if (!fgets(line, sizeof(line), f))
184 if (!fgets(line, sizeof(line), f))
189 p = strchr(line, ':');
197 p += strspn(p, WHITESPACE);
198 p += strcspn(p, WHITESPACE); /* skip one more word */
199 p += strspn(p, WHITESPACE);
208 path_kill_slashes(s);
210 k = set_consume(unix_sockets, s);
211 if (k < 0 && k != -EEXIST)
218 set_free_free(unix_sockets);
222 static bool unix_socket_alive(const char *fn) {
228 return !!set_get(unix_sockets, (char*) fn);
230 /* We don't know, so assume yes */
234 static int dir_is_mount_point(DIR *d, const char *subdir) {
236 union file_handle_union h = {
237 .handle.handle_bytes = MAX_HANDLE_SZ
240 int mount_id_parent, mount_id;
243 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
247 h.handle.handle_bytes = MAX_HANDLE_SZ;
248 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
252 /* got no handle; make no assumptions, return error */
253 if (r_p < 0 && r < 0)
256 /* got both handles; if they differ, it is a mount point */
257 if (r_p >= 0 && r >= 0)
258 return mount_id_parent != mount_id;
260 /* got only one handle; assume different mount points if one
261 * of both queries was not supported by the filesystem */
262 if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
271 static int dir_cleanup(
275 const struct stat *ds,
280 bool keep_this_level) {
283 struct timespec times[2];
284 bool deleted = false;
287 while ((dent = readdir(d))) {
290 _cleanup_free_ char *sub_path = NULL;
292 if (streq(dent->d_name, ".") ||
293 streq(dent->d_name, ".."))
296 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
300 /* FUSE, NFS mounts, SELinux might return EACCES */
302 log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
304 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
309 /* Stay on the same filesystem */
310 if (s.st_dev != rootdev)
313 /* Try to detect bind mounts of the same filesystem instance; they
314 * do not differ in device major/minors. This type of query is not
315 * supported on all kernels or filesystem types though. */
316 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
319 /* Do not delete read-only files owned by root */
320 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
323 sub_path = strjoin(p, "/", dent->d_name, NULL);
329 /* Is there an item configured for this path? */
330 if (hashmap_get(items, sub_path))
333 if (find_glob(globs, sub_path))
336 if (S_ISDIR(s.st_mode)) {
339 streq(dent->d_name, "lost+found") &&
344 log_warning("Reached max depth on %s.", sub_path);
346 _cleanup_closedir_ DIR *sub_dir;
349 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
351 if (errno != ENOENT) {
352 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
359 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
364 /* Note: if you are wondering why we don't
365 * support the sticky bit for excluding
366 * directories from cleaning like we do it for
367 * other file system objects: well, the sticky
368 * bit already has a meaning for directories,
369 * so we don't want to overload that. */
374 /* Ignore ctime, we change it when deleting */
375 age = MAX(timespec_load(&s.st_mtim),
376 timespec_load(&s.st_atim));
380 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
381 log_debug("rmdir '%s'", sub_path);
383 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
384 if (errno != ENOENT && errno != ENOTEMPTY) {
385 log_error("rmdir(%s): %m", sub_path);
392 /* Skip files for which the sticky bit is
393 * set. These are semantics we define, and are
394 * unknown elsewhere. See XDG_RUNTIME_DIR
395 * specification for details. */
396 if (s.st_mode & S_ISVTX)
399 if (mountpoint && S_ISREG(s.st_mode)) {
400 if (streq(dent->d_name, ".journal") &&
404 if (streq(dent->d_name, "aquota.user") ||
405 streq(dent->d_name, "aquota.group"))
409 /* Ignore sockets that are listed in /proc/net/unix */
410 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
413 /* Ignore device nodes */
414 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
417 /* Keep files on this level around if this is
422 age = MAX3(timespec_load(&s.st_mtim),
423 timespec_load(&s.st_atim),
424 timespec_load(&s.st_ctim));
429 log_debug("unlink '%s'", sub_path);
431 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
432 if (errno != ENOENT) {
433 log_error("unlink(%s): %m", sub_path);
444 /* Restore original directory timestamps */
445 times[0] = ds->st_atim;
446 times[1] = ds->st_mtim;
448 if (futimens(dirfd(d), times) < 0)
449 log_error("utimensat(%s): %m", p);
455 static int item_set_perms(Item *i, const char *path) {
462 st_valid = stat(path, &st) == 0;
464 /* not using i->path directly because it may be a glob */
468 if (i->mask_perms && st_valid) {
469 if (!(st.st_mode & 0111))
471 if (!(st.st_mode & 0222))
473 if (!(st.st_mode & 0444))
475 if (!S_ISDIR(st.st_mode))
476 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
479 if (!st_valid || m != (st.st_mode & 07777)) {
480 if (chmod(path, m) < 0) {
481 log_error("chmod(%s) failed: %m", path);
487 if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
488 (i->uid_set || i->gid_set))
490 i->uid_set ? i->uid : (uid_t) -1,
491 i->gid_set ? i->gid : (gid_t) -1) < 0) {
493 log_error("chown(%s) failed: %m", path);
497 return label_fix(path, false, false);
500 static int write_one_file(Item *i, const char *path) {
501 _cleanup_close_ int fd = -1;
508 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
509 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
511 RUN_WITH_UMASK(0000) {
512 mac_selinux_create_file_prepare(path, S_IFREG);
513 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
514 mac_selinux_create_file_clear();
518 if (i->type == WRITE_FILE && errno == ENOENT)
521 log_error("Failed to create file %s: %m", path);
526 _cleanup_free_ char *unescaped;
530 unescaped = cunescape(i->argument);
534 l = strlen(unescaped);
535 n = write(fd, unescaped, l);
537 if (n < 0 || (size_t) n < l) {
538 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
539 return n < 0 ? n : -EIO;
545 if (stat(path, &st) < 0) {
546 log_error("stat(%s) failed: %m", path);
550 if (!S_ISREG(st.st_mode)) {
551 log_error("%s is not a file.", path);
555 r = item_set_perms(i, path);
562 static int item_set_perms_children(Item *i, const char *path) {
563 _cleanup_closedir_ DIR *d;
569 /* This returns the first error we run into, but nevertheless
574 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
577 _cleanup_free_ char *p = NULL;
584 if (errno != 0 && r == 0)
590 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
593 p = strjoin(path, "/", de->d_name, NULL);
597 q = item_set_perms(i, p);
598 if (q < 0 && q != -ENOENT && r == 0)
601 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
602 q = item_set_perms_children(i, p);
611 static int item_set_perms_recursive(Item *i, const char *path) {
617 r = item_set_perms(i, path);
621 q = item_set_perms_children(i, path);
628 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
629 _cleanup_globfree_ glob_t g = {};
634 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
635 if (k != 0 && k != GLOB_NOMATCH) {
639 log_error("glob(%s) failed: %m", i->path);
643 STRV_FOREACH(fn, g.gl_pathv) {
652 static int create_item(Item *i) {
661 case IGNORE_DIRECTORY_PATH:
663 case RECURSIVE_REMOVE_PATH:
668 r = write_one_file(i, i->path);
674 r = copy_tree(i->argument, i->path, false);
679 log_error("Failed to copy files to %s: %s", i->path, strerror(-r));
683 if (stat(i->argument, &a) < 0) {
684 log_error("stat(%s) failed: %m", i->argument);
688 if (stat(i->path, &b) < 0) {
689 log_error("stat(%s) failed: %m", i->path);
693 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
694 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
699 r = item_set_perms(i, i->path);
706 r = glob_item(i, write_one_file);
712 case TRUNCATE_DIRECTORY:
713 case CREATE_DIRECTORY:
715 RUN_WITH_UMASK(0000) {
716 mkdir_parents_label(i->path, 0755);
717 r = mkdir_label(i->path, i->mode);
722 log_error("Failed to create directory %s: %s", i->path, strerror(-r));
726 if (stat(i->path, &st) < 0) {
727 log_error("stat(%s) failed: %m", i->path);
731 if (!S_ISDIR(st.st_mode)) {
732 log_debug("%s already exists and is not a directory.", i->path);
737 r = item_set_perms(i, i->path);
745 RUN_WITH_UMASK(0000) {
746 mac_selinux_create_file_prepare(i->path, S_IFIFO);
747 r = mkfifo(i->path, i->mode);
748 mac_selinux_create_file_clear();
752 if (errno != EEXIST) {
753 log_error("Failed to create fifo %s: %m", i->path);
757 if (stat(i->path, &st) < 0) {
758 log_error("stat(%s) failed: %m", i->path);
762 if (!S_ISFIFO(st.st_mode)) {
766 RUN_WITH_UMASK(0000) {
767 mac_selinux_create_file_prepare(i->path, S_IFIFO);
768 r = mkfifo_atomic(i->path, i->mode);
769 mac_selinux_create_file_clear();
773 log_error("Failed to create fifo %s: %s", i->path, strerror(-r));
777 log_debug("%s is not a fifo.", i->path);
783 r = item_set_perms(i, i->path);
791 mac_selinux_create_file_prepare(i->path, S_IFLNK);
792 r = symlink(i->argument, i->path);
793 mac_selinux_create_file_clear();
796 _cleanup_free_ char *x = NULL;
798 if (errno != EEXIST) {
799 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
803 r = readlink_malloc(i->path, &x);
804 if (r < 0 || !streq(i->argument, x)) {
807 mac_selinux_create_file_prepare(i->path, S_IFLNK);
808 r = symlink_atomic(i->argument, i->path);
809 mac_selinux_create_file_clear();
812 log_error("symlink(%s, %s) failed: %s", i->argument, i->path, strerror(-r));
816 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
824 case CREATE_BLOCK_DEVICE:
825 case CREATE_CHAR_DEVICE: {
828 if (have_effective_cap(CAP_MKNOD) == 0) {
829 /* In a container we lack CAP_MKNOD. We
830 shouldn't attempt to create the device node in
831 that case to avoid noise, and we don't support
832 virtualized devices in containers anyway. */
834 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
838 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
840 RUN_WITH_UMASK(0000) {
841 mac_selinux_create_file_prepare(i->path, file_type);
842 r = mknod(i->path, i->mode | file_type, i->major_minor);
843 mac_selinux_create_file_clear();
847 if (errno == EPERM) {
848 log_debug("We lack permissions, possibly because of cgroup configuration; "
849 "skipping creation of device node %s.", i->path);
853 if (errno != EEXIST) {
854 log_error("Failed to create device node %s: %m", i->path);
858 if (stat(i->path, &st) < 0) {
859 log_error("stat(%s) failed: %m", i->path);
863 if ((st.st_mode & S_IFMT) != file_type) {
867 RUN_WITH_UMASK(0000) {
868 mac_selinux_create_file_prepare(i->path, file_type);
869 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
870 mac_selinux_create_file_clear();
874 log_error("Failed to create device node %s: %s", i->path, strerror(-r));
878 log_debug("%s is not a device node.", i->path);
884 r = item_set_perms(i, i->path);
894 r = glob_item(i, item_set_perms);
899 case RECURSIVE_RELABEL_PATH:
901 r = glob_item(i, item_set_perms_recursive);
908 log_debug("%s created successfully.", i->path);
913 static int remove_item_instance(Item *i, const char *instance) {
922 case CREATE_DIRECTORY:
925 case CREATE_BLOCK_DEVICE:
926 case CREATE_CHAR_DEVICE:
928 case IGNORE_DIRECTORY_PATH:
931 case RECURSIVE_RELABEL_PATH:
937 if (remove(instance) < 0 && errno != ENOENT) {
938 log_error("remove(%s): %m", instance);
944 case TRUNCATE_DIRECTORY:
945 case RECURSIVE_REMOVE_PATH:
946 /* FIXME: we probably should use dir_cleanup() here
947 * instead of rm_rf() so that 'x' is honoured. */
948 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
949 if (r < 0 && r != -ENOENT) {
950 log_error("rm_rf(%s): %s", instance, strerror(-r));
960 static int remove_item(Item *i) {
969 case CREATE_DIRECTORY:
972 case CREATE_CHAR_DEVICE:
973 case CREATE_BLOCK_DEVICE:
975 case IGNORE_DIRECTORY_PATH:
978 case RECURSIVE_RELABEL_PATH:
984 case TRUNCATE_DIRECTORY:
985 case RECURSIVE_REMOVE_PATH:
986 r = glob_item(i, remove_item_instance);
993 static int clean_item_instance(Item *i, const char* instance) {
994 _cleanup_closedir_ DIR *d = NULL;
1005 n = now(CLOCK_REALTIME);
1009 cutoff = n - i->age;
1011 d = opendir(instance);
1013 if (errno == ENOENT || errno == ENOTDIR)
1016 log_error("Failed to open directory %s: %m", i->path);
1020 if (fstat(dirfd(d), &s) < 0) {
1021 log_error("stat(%s) failed: %m", i->path);
1025 if (!S_ISDIR(s.st_mode)) {
1026 log_error("%s is not a directory.", i->path);
1030 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
1031 log_error("stat(%s/..) failed: %m", i->path);
1035 mountpoint = s.st_dev != ps.st_dev ||
1036 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1038 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1039 MAX_DEPTH, i->keep_first_level);
1043 static int clean_item(Item *i) {
1049 case CREATE_DIRECTORY:
1050 case TRUNCATE_DIRECTORY:
1053 clean_item_instance(i, i->path);
1055 case IGNORE_DIRECTORY_PATH:
1056 r = glob_item(i, clean_item_instance);
1065 static int process_item(Item *i) {
1067 _cleanup_free_ char *prefix = NULL;
1076 prefix = malloc(strlen(i->path) + 1);
1080 PATH_FOREACH_PREFIX(prefix, i->path) {
1083 j = hashmap_get(items, prefix);
1088 r = arg_create ? create_item(i) : 0;
1089 q = arg_remove ? remove_item(i) : 0;
1090 p = arg_clean ? clean_item(i) : 0;
1101 static void item_free(Item *i) {
1111 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1113 static bool item_equal(Item *a, Item *b) {
1117 if (!streq_ptr(a->path, b->path))
1120 if (a->type != b->type)
1123 if (a->uid_set != b->uid_set ||
1124 (a->uid_set && a->uid != b->uid))
1127 if (a->gid_set != b->gid_set ||
1128 (a->gid_set && a->gid != b->gid))
1131 if (a->mode_set != b->mode_set ||
1132 (a->mode_set && a->mode != b->mode))
1135 if (a->age_set != b->age_set ||
1136 (a->age_set && a->age != b->age))
1139 if ((a->type == CREATE_FILE ||
1140 a->type == TRUNCATE_FILE ||
1141 a->type == WRITE_FILE ||
1142 a->type == CREATE_SYMLINK ||
1143 a->type == COPY_FILES) &&
1144 !streq_ptr(a->argument, b->argument))
1147 if ((a->type == CREATE_CHAR_DEVICE ||
1148 a->type == CREATE_BLOCK_DEVICE) &&
1149 a->major_minor != b->major_minor)
1155 static bool should_include_path(const char *path) {
1158 STRV_FOREACH(prefix, arg_exclude_prefixes)
1159 if (path_startswith(path, *prefix))
1162 STRV_FOREACH(prefix, arg_include_prefixes)
1163 if (path_startswith(path, *prefix))
1166 /* no matches, so we should include this path only if we
1167 * have no whitelist at all */
1168 return strv_length(arg_include_prefixes) == 0;
1171 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1173 static const Specifier specifier_table[] = {
1174 { 'm', specifier_machine_id, NULL },
1175 { 'b', specifier_boot_id, NULL },
1176 { 'H', specifier_host_name, NULL },
1177 { 'v', specifier_kernel_release, NULL },
1181 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1182 _cleanup_(item_freep) Item *i = NULL;
1193 "%ms %ms %ms %ms %ms %ms %n",
1202 log_error("[%s:%u] Syntax error.", fname, line);
1206 if (isempty(action)) {
1207 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1211 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1212 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1216 if (strchr(action+1, '!') && !arg_boot)
1225 i->force = !!strchr(action+1, '+');
1227 r = specifier_printf(path, specifier_table, NULL, &i->path);
1229 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1234 n += strspn(buffer+n, WHITESPACE);
1235 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1236 i->argument = unquote(buffer+n, "\"");
1246 case CREATE_DIRECTORY:
1247 case TRUNCATE_DIRECTORY:
1250 case IGNORE_DIRECTORY_PATH:
1252 case RECURSIVE_REMOVE_PATH:
1255 case RECURSIVE_RELABEL_PATH:
1258 case CREATE_SYMLINK:
1260 i->argument = strappend("/usr/share/factory", i->path);
1268 log_error("[%s:%u] Write file requires argument.", fname, line);
1275 i->argument = strappend("/usr/share/factory", i->path);
1280 if (!path_is_absolute(i->argument)) {
1281 log_error("[%s:%u] Source path is not absolute.", fname, line);
1285 path_kill_slashes(i->argument);
1288 case CREATE_CHAR_DEVICE:
1289 case CREATE_BLOCK_DEVICE: {
1290 unsigned major, minor;
1293 log_error("[%s:%u] Device file requires argument.", fname, line);
1297 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1298 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1302 i->major_minor = makedev(major, minor);
1307 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1313 if (!path_is_absolute(i->path)) {
1314 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1318 path_kill_slashes(i->path);
1320 if (!should_include_path(i->path))
1326 p = strappend(arg_root, i->path);
1334 if (user && !streq(user, "-")) {
1335 const char *u = user;
1337 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1339 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1346 if (group && !streq(group, "-")) {
1347 const char *g = group;
1349 r = get_group_creds(&g, &i->gid);
1351 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1358 if (mode && !streq(mode, "-")) {
1359 const char *mm = mode;
1363 i->mask_perms = true;
1367 if (sscanf(mm, "%o", &m) != 1) {
1368 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1376 i->type == CREATE_DIRECTORY ||
1377 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1379 if (age && !streq(age, "-")) {
1380 const char *a = age;
1383 i->keep_first_level = true;
1387 if (parse_sec(a, &i->age) < 0) {
1388 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1395 h = needs_glob(i->type) ? globs : items;
1397 existing = hashmap_get(h, i->path);
1400 /* Two identical items are fine */
1401 if (!item_equal(existing, i))
1402 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1407 r = hashmap_put(h, i->path, i);
1409 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1413 i = NULL; /* avoid cleanup */
1418 static void help(void) {
1419 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1420 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1421 " -h --help Show this help\n"
1422 " --version Show package version\n"
1423 " --create Create marked files/directories\n"
1424 " --clean Clean up marked directories\n"
1425 " --remove Remove marked files/directories\n"
1426 " --boot Execute actions only safe at boot\n"
1427 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1428 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1429 " --root=PATH Operate on an alternate filesystem root\n",
1430 program_invocation_short_name);
1433 static int parse_argv(int argc, char *argv[]) {
1436 ARG_VERSION = 0x100,
1446 static const struct option options[] = {
1447 { "help", no_argument, NULL, 'h' },
1448 { "version", no_argument, NULL, ARG_VERSION },
1449 { "create", no_argument, NULL, ARG_CREATE },
1450 { "clean", no_argument, NULL, ARG_CLEAN },
1451 { "remove", no_argument, NULL, ARG_REMOVE },
1452 { "boot", no_argument, NULL, ARG_BOOT },
1453 { "prefix", required_argument, NULL, ARG_PREFIX },
1454 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1455 { "root", required_argument, NULL, ARG_ROOT },
1464 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1473 puts(PACKAGE_STRING);
1474 puts(SYSTEMD_FEATURES);
1494 if (strv_push(&arg_include_prefixes, optarg) < 0)
1498 case ARG_EXCLUDE_PREFIX:
1499 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1505 arg_root = path_make_absolute_cwd(optarg);
1509 path_kill_slashes(arg_root);
1516 assert_not_reached("Unhandled option");
1519 if (!arg_clean && !arg_create && !arg_remove) {
1520 log_error("You need to specify at least one of --clean, --create or --remove.");
1527 static int read_config_file(const char *fn, bool ignore_enoent) {
1528 _cleanup_fclose_ FILE *f = NULL;
1529 char line[LINE_MAX];
1537 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1539 if (ignore_enoent && r == -ENOENT)
1542 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1546 FOREACH_LINE(line, f, break) {
1553 if (*l == '#' || *l == 0)
1556 k = parse_line(fn, v, l);
1557 if (k < 0 && r == 0)
1561 /* we have to determine age parameter for each entry of type X */
1562 HASHMAP_FOREACH(i, globs, iterator) {
1564 Item *j, *candidate_item = NULL;
1566 if (i->type != IGNORE_DIRECTORY_PATH)
1569 HASHMAP_FOREACH(j, items, iter) {
1570 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1573 if (path_equal(j->path, i->path)) {
1578 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1579 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1583 if (candidate_item && candidate_item->age_set) {
1584 i->age = candidate_item->age;
1590 log_error("Failed to read from file %s: %m", fn);
1598 int main(int argc, char *argv[]) {
1603 r = parse_argv(argc, argv);
1607 log_set_target(LOG_TARGET_AUTO);
1608 log_parse_environment();
1613 mac_selinux_init(NULL);
1615 items = hashmap_new(&string_hash_ops);
1616 globs = hashmap_new(&string_hash_ops);
1618 if (!items || !globs) {
1625 if (optind < argc) {
1628 for (j = optind; j < argc; j++) {
1629 k = read_config_file(argv[j], false);
1630 if (k < 0 && r == 0)
1635 _cleanup_strv_free_ char **files = NULL;
1638 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1640 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1644 STRV_FOREACH(f, files) {
1645 k = read_config_file(*f, true);
1646 if (k < 0 && r == 0)
1651 HASHMAP_FOREACH(i, globs, iterator)
1654 HASHMAP_FOREACH(i, items, iterator)
1658 while ((i = hashmap_steal_first(items)))
1661 while ((i = hashmap_steal_first(globs)))
1664 hashmap_free(items);
1665 hashmap_free(globs);
1667 free(arg_include_prefixes);
1668 free(arg_exclude_prefixes);
1671 set_free_free(unix_sockets);
1673 mac_selinux_finish();
1675 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;