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"
57 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
58 * them in the file system. This is intended to be used to create
59 * properly owned directories beneath /tmp, /var/tmp, /run, which are
60 * volatile and hence need to be recreated on bootup. */
62 typedef enum ItemType {
63 /* 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 */
77 IGNORE_DIRECTORY_PATH = 'X',
79 RECURSIVE_REMOVE_PATH = 'R',
81 RECURSIVE_RELABEL_PATH = 'Z'
101 bool keep_first_level:1;
104 static Hashmap *items = NULL, *globs = NULL;
105 static Set *unix_sockets = NULL;
107 static bool arg_create = false;
108 static bool arg_clean = false;
109 static bool arg_remove = false;
110 static bool arg_boot = false;
112 static char **include_prefixes = NULL;
113 static char **exclude_prefixes = NULL;
115 static const char conf_file_dirs[] =
118 "/usr/local/lib/tmpfiles.d\0"
119 "/usr/lib/tmpfiles.d\0"
120 #ifdef HAVE_SPLIT_USR
125 #define MAX_DEPTH 256
127 static bool needs_glob(ItemType t) {
128 return t == IGNORE_PATH || t == IGNORE_DIRECTORY_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
131 static struct Item* find_glob(Hashmap *h, const char *match) {
135 HASHMAP_FOREACH(j, h, i)
136 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
142 static void load_unix_sockets(void) {
143 _cleanup_fclose_ FILE *f = NULL;
149 /* We maintain a cache of the sockets we found in
150 * /proc/net/unix to speed things up a little. */
152 unix_sockets = set_new(string_hash_func, string_compare_func);
156 f = fopen("/proc/net/unix", "re");
161 if (!fgets(line, sizeof(line), f))
168 if (!fgets(line, sizeof(line), f))
173 p = strchr(line, ':');
181 p += strspn(p, WHITESPACE);
182 p += strcspn(p, WHITESPACE); /* skip one more word */
183 p += strspn(p, WHITESPACE);
192 path_kill_slashes(s);
194 k = set_consume(unix_sockets, s);
195 if (k < 0 && k != -EEXIST)
202 set_free_free(unix_sockets);
206 static bool unix_socket_alive(const char *fn) {
212 return !!set_get(unix_sockets, (char*) fn);
214 /* We don't know, so assume yes */
218 static int dir_is_mount_point(DIR *d, const char *subdir) {
219 struct file_handle *h;
220 int mount_id_parent, mount_id;
223 h = alloca(MAX_HANDLE_SZ);
225 h->handle_bytes = MAX_HANDLE_SZ;
226 r_p = name_to_handle_at(dirfd(d), ".", h, &mount_id_parent, 0);
230 h->handle_bytes = MAX_HANDLE_SZ;
231 r = name_to_handle_at(dirfd(d), subdir, h, &mount_id, 0);
235 /* got no handle; make no assumptions, return error */
236 if (r_p < 0 && r < 0)
239 /* got both handles; if they differ, it is a mount point */
240 if (r_p >= 0 && r >= 0)
241 return mount_id_parent != mount_id;
243 /* got only one handle; assume different mount points if one
244 * of both queries was not supported by the filesystem */
245 if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
254 static int dir_cleanup(
258 const struct stat *ds,
263 bool keep_this_level) {
266 struct timespec times[2];
267 bool deleted = false;
270 while ((dent = readdir(d))) {
273 _cleanup_free_ char *sub_path = NULL;
275 if (streq(dent->d_name, ".") ||
276 streq(dent->d_name, ".."))
279 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
283 /* FUSE, NFS mounts, SELinux might return EACCES */
285 log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
287 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
292 /* Stay on the same filesystem */
293 if (s.st_dev != rootdev)
296 /* Try to detect bind mounts of the same filesystem instance; they
297 * do not differ in device major/minors. This type of query is not
298 * supported on all kernels or filesystem types though. */
299 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
302 /* Do not delete read-only files owned by root */
303 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
306 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
311 /* Is there an item configured for this path? */
312 if (hashmap_get(items, sub_path))
315 if (find_glob(globs, sub_path))
318 if (S_ISDIR(s.st_mode)) {
321 streq(dent->d_name, "lost+found") &&
326 log_warning("Reached max depth on %s.", sub_path);
328 _cleanup_closedir_ DIR *sub_dir;
331 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
332 if (sub_dir == NULL) {
333 if (errno != ENOENT) {
334 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
341 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
347 /* Note: if you are wondering why we don't
348 * support the sticky bit for excluding
349 * directories from cleaning like we do it for
350 * other file system objects: well, the sticky
351 * bit already has a meaning for directories,
352 * so we don't want to overload that. */
357 /* Ignore ctime, we change it when deleting */
358 age = MAX(timespec_load(&s.st_mtim),
359 timespec_load(&s.st_atim));
363 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
364 log_debug("rmdir '%s'", sub_path);
366 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
367 if (errno != ENOENT && errno != ENOTEMPTY) {
368 log_error("rmdir(%s): %m", sub_path);
375 /* Skip files for which the sticky bit is
376 * set. These are semantics we define, and are
377 * unknown elsewhere. See XDG_RUNTIME_DIR
378 * specification for details. */
379 if (s.st_mode & S_ISVTX)
382 if (mountpoint && S_ISREG(s.st_mode)) {
383 if (streq(dent->d_name, ".journal") &&
387 if (streq(dent->d_name, "aquota.user") ||
388 streq(dent->d_name, "aquota.group"))
392 /* Ignore sockets that are listed in /proc/net/unix */
393 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
396 /* Ignore device nodes */
397 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
400 /* Keep files on this level around if this is
405 age = MAX3(timespec_load(&s.st_mtim),
406 timespec_load(&s.st_atim),
407 timespec_load(&s.st_ctim));
412 log_debug("unlink '%s'", sub_path);
414 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
415 if (errno != ENOENT) {
416 log_error("unlink(%s): %m", sub_path);
427 /* Restore original directory timestamps */
428 times[0] = ds->st_atim;
429 times[1] = ds->st_mtim;
431 if (futimens(dirfd(d), times) < 0)
432 log_error("utimensat(%s): %m", p);
438 static int item_set_perms_full(Item *i, const char *path, bool ignore_enoent) {
441 /* not using i->path directly because it may be a glob */
443 if (chmod(path, i->mode) < 0) {
444 if (errno != ENOENT || !ignore_enoent) {
445 log_error("chmod(%s) failed: %m", path);
450 if (i->uid_set || i->gid_set)
452 i->uid_set ? i->uid : (uid_t) -1,
453 i->gid_set ? i->gid : (gid_t) -1) < 0) {
455 if (errno != ENOENT || !ignore_enoent) {
456 log_error("chown(%s) failed: %m", path);
461 r = label_fix(path, false, false);
462 return r == -ENOENT && ignore_enoent ? 0 : r;
465 static int item_set_perms(Item *i, const char *path) {
466 return item_set_perms_full(i, path, false);
469 static int write_one_file(Item *i, const char *path) {
475 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
476 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
479 label_context_set(path, S_IFREG);
480 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
482 label_context_clear();
487 if (i->type == WRITE_FILE && errno == ENOENT)
490 log_error("Failed to create file %s: %m", path);
497 _cleanup_free_ char *unescaped;
499 unescaped = cunescape(i->argument);
500 if (unescaped == NULL) {
501 close_nointr_nofail(fd);
505 l = strlen(unescaped);
506 n = write(fd, unescaped, l);
508 if (n < 0 || (size_t) n < l) {
509 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
510 close_nointr_nofail(fd);
511 return n < 0 ? n : -EIO;
515 close_nointr_nofail(fd);
517 if (stat(path, &st) < 0) {
518 log_error("stat(%s) failed: %m", path);
522 if (!S_ISREG(st.st_mode)) {
523 log_error("%s is not a file.", path);
527 r = item_set_perms(i, path);
534 static int recursive_relabel_children(Item *i, const char *path) {
535 _cleanup_closedir_ DIR *d;
538 /* This returns the first error we run into, but nevertheless
543 return errno == ENOENT ? 0 : -errno;
549 _cleanup_free_ char *entry_path = NULL;
553 if (!de && errno != 0) {
562 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
565 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
571 if (de->d_type == DT_UNKNOWN) {
574 if (lstat(entry_path, &st) < 0) {
575 if (ret == 0 && errno != ENOENT)
580 is_dir = S_ISDIR(st.st_mode);
583 is_dir = de->d_type == DT_DIR;
585 r = item_set_perms(i, entry_path);
587 if (ret == 0 && r != -ENOENT)
593 r = recursive_relabel_children(i, entry_path);
594 if (r < 0 && ret == 0)
602 static int recursive_relabel(Item *i, const char *path) {
606 r = item_set_perms(i, path);
610 if (lstat(path, &st) < 0)
613 if (S_ISDIR(st.st_mode))
614 r = recursive_relabel_children(i, path);
619 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
621 _cleanup_globfree_ glob_t g = {};
625 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
627 if (k != GLOB_NOMATCH) {
631 log_error("glob(%s) failed: %m", i->path);
635 STRV_FOREACH(fn, g.gl_pathv) {
644 static int create_item(Item *i) {
654 case IGNORE_DIRECTORY_PATH:
656 case RECURSIVE_REMOVE_PATH:
661 r = write_one_file(i, i->path);
667 r = glob_item(i, write_one_file);
674 r = item_set_perms_full(i, i->path, true);
680 case TRUNCATE_DIRECTORY:
681 case CREATE_DIRECTORY:
683 RUN_WITH_UMASK(0000) {
684 mkdir_parents_label(i->path, 0755);
685 r = mkdir(i->path, i->mode);
688 if (r < 0 && errno != EEXIST) {
689 log_error("Failed to create directory %s: %m", i->path);
693 if (stat(i->path, &st) < 0) {
694 log_error("stat(%s) failed: %m", i->path);
698 if (!S_ISDIR(st.st_mode)) {
699 log_error("%s is not a directory.", i->path);
703 r = item_set_perms(i, i->path);
711 RUN_WITH_UMASK(0000) {
712 r = mkfifo(i->path, i->mode);
715 if (r < 0 && errno != EEXIST) {
716 log_error("Failed to create fifo %s: %m", i->path);
720 if (stat(i->path, &st) < 0) {
721 log_error("stat(%s) failed: %m", i->path);
725 if (!S_ISFIFO(st.st_mode)) {
726 log_error("%s is not a fifo.", i->path);
730 r = item_set_perms(i, i->path);
736 case CREATE_SYMLINK: {
739 label_context_set(i->path, S_IFLNK);
740 r = symlink(i->argument, i->path);
742 label_context_clear();
745 if (r < 0 && errno != EEXIST) {
746 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
750 r = readlink_malloc(i->path, &x);
752 log_error("readlink(%s) failed: %s", i->path, strerror(-r));
756 if (!streq(i->argument, x)) {
758 log_error("%s is not the right symlinks.", i->path);
766 case CREATE_BLOCK_DEVICE:
767 case CREATE_CHAR_DEVICE: {
770 if (have_effective_cap(CAP_MKNOD) == 0) {
771 /* In a container we lack CAP_MKNOD. We
772 shouldn't attempt to create the device node in
773 that case to avoid noise, and we don't support
774 virtualized devices in containers anyway. */
776 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
780 file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
782 RUN_WITH_UMASK(0000) {
783 label_context_set(i->path, file_type);
784 r = mknod(i->path, i->mode | file_type, i->major_minor);
786 label_context_clear();
790 if (r < 0 && errno != EEXIST) {
791 log_error("Failed to create device node %s: %m", i->path);
795 if (stat(i->path, &st) < 0) {
796 log_error("stat(%s) failed: %m", i->path);
800 if ((st.st_mode & S_IFMT) != file_type) {
801 log_error("%s is not a device node.", i->path);
805 r = item_set_perms(i, i->path);
814 r = glob_item(i, item_set_perms);
819 case RECURSIVE_RELABEL_PATH:
821 r = glob_item(i, recursive_relabel);
826 log_debug("%s created successfully.", i->path);
831 static int remove_item_instance(Item *i, const char *instance) {
840 case CREATE_DIRECTORY:
843 case CREATE_BLOCK_DEVICE:
844 case CREATE_CHAR_DEVICE:
846 case IGNORE_DIRECTORY_PATH:
848 case RECURSIVE_RELABEL_PATH:
854 if (remove(instance) < 0 && errno != ENOENT) {
855 log_error("remove(%s): %m", instance);
861 case TRUNCATE_DIRECTORY:
862 case RECURSIVE_REMOVE_PATH:
863 /* FIXME: we probably should use dir_cleanup() here
864 * instead of rm_rf() so that 'x' is honoured. */
865 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
866 if (r < 0 && r != -ENOENT) {
867 log_error("rm_rf(%s): %s", instance, strerror(-r));
877 static int remove_item(Item *i) {
886 case CREATE_DIRECTORY:
889 case CREATE_CHAR_DEVICE:
890 case CREATE_BLOCK_DEVICE:
892 case IGNORE_DIRECTORY_PATH:
894 case RECURSIVE_RELABEL_PATH:
900 case TRUNCATE_DIRECTORY:
901 case RECURSIVE_REMOVE_PATH:
902 r = glob_item(i, remove_item_instance);
909 static int clean_item_instance(Item *i, const char* instance) {
910 _cleanup_closedir_ DIR *d = NULL;
921 n = now(CLOCK_REALTIME);
927 d = opendir(instance);
929 if (errno == ENOENT || errno == ENOTDIR)
932 log_error("Failed to open directory %s: %m", i->path);
936 if (fstat(dirfd(d), &s) < 0) {
937 log_error("stat(%s) failed: %m", i->path);
941 if (!S_ISDIR(s.st_mode)) {
942 log_error("%s is not a directory.", i->path);
946 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
947 log_error("stat(%s/..) failed: %m", i->path);
951 mountpoint = s.st_dev != ps.st_dev ||
952 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
954 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
955 MAX_DEPTH, i->keep_first_level);
959 static int clean_item(Item *i) {
965 case CREATE_DIRECTORY:
966 case TRUNCATE_DIRECTORY:
968 clean_item_instance(i, i->path);
970 case IGNORE_DIRECTORY_PATH:
971 r = glob_item(i, clean_item_instance);
980 static int process_item(Item *i) {
985 r = arg_create ? create_item(i) : 0;
986 q = arg_remove ? remove_item(i) : 0;
987 p = arg_clean ? clean_item(i) : 0;
998 static void item_free(Item *i) {
1006 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1007 #define _cleanup_item_free_ _cleanup_(item_freep)
1009 static bool item_equal(Item *a, Item *b) {
1013 if (!streq_ptr(a->path, b->path))
1016 if (a->type != b->type)
1019 if (a->uid_set != b->uid_set ||
1020 (a->uid_set && a->uid != b->uid))
1023 if (a->gid_set != b->gid_set ||
1024 (a->gid_set && a->gid != b->gid))
1027 if (a->mode_set != b->mode_set ||
1028 (a->mode_set && a->mode != b->mode))
1031 if (a->age_set != b->age_set ||
1032 (a->age_set && a->age != b->age))
1035 if ((a->type == CREATE_FILE ||
1036 a->type == TRUNCATE_FILE ||
1037 a->type == WRITE_FILE ||
1038 a->type == CREATE_SYMLINK) &&
1039 !streq_ptr(a->argument, b->argument))
1042 if ((a->type == CREATE_CHAR_DEVICE ||
1043 a->type == CREATE_BLOCK_DEVICE) &&
1044 a->major_minor != b->major_minor)
1050 static bool should_include_path(const char *path) {
1053 STRV_FOREACH(prefix, exclude_prefixes) {
1054 if (path_startswith(path, *prefix))
1058 STRV_FOREACH(prefix, include_prefixes) {
1059 if (path_startswith(path, *prefix))
1063 /* no matches, so we should include this path only if we
1064 * have no whitelist at all */
1065 return strv_length(include_prefixes) == 0;
1068 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1070 static const Specifier specifier_table[] = {
1071 { 'm', specifier_machine_id, NULL },
1072 { 'b', specifier_boot_id, NULL },
1073 { 'H', specifier_host_name, NULL },
1074 { 'v', specifier_kernel_release, NULL },
1078 _cleanup_item_free_ Item *i = NULL;
1081 *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1091 "%ms %ms %ms %ms %ms %ms %n",
1100 log_error("[%s:%u] Syntax error.", fname, line);
1104 if (strlen(action) > 2 || (strlen(action) > 1 && action[1] != '!')) {
1105 log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
1107 } else if (strlen(action) > 1 && !arg_boot)
1116 r = specifier_printf(path, specifier_table, NULL, &i->path);
1118 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1123 n += strspn(buffer+n, WHITESPACE);
1124 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1125 i->argument = unquote(buffer+n, "\"");
1135 case CREATE_DIRECTORY:
1136 case TRUNCATE_DIRECTORY:
1139 case IGNORE_DIRECTORY_PATH:
1141 case RECURSIVE_REMOVE_PATH:
1143 case RECURSIVE_RELABEL_PATH:
1147 case CREATE_SYMLINK:
1149 log_error("[%s:%u] Symlink file requires argument.", fname, line);
1156 log_error("[%s:%u] Write file requires argument.", fname, line);
1161 case CREATE_CHAR_DEVICE:
1162 case CREATE_BLOCK_DEVICE: {
1163 unsigned major, minor;
1166 log_error("[%s:%u] Device file requires argument.", fname, line);
1170 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1171 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1175 i->major_minor = makedev(major, minor);
1180 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1186 if (!path_is_absolute(i->path)) {
1187 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1191 path_kill_slashes(i->path);
1193 if (!should_include_path(i->path))
1196 if (user && !streq(user, "-")) {
1197 const char *u = user;
1199 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1201 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1208 if (group && !streq(group, "-")) {
1209 const char *g = group;
1211 r = get_group_creds(&g, &i->gid);
1213 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1220 if (mode && !streq(mode, "-")) {
1223 if (sscanf(mode, "%o", &m) != 1) {
1224 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1232 i->type == CREATE_DIRECTORY ||
1233 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1235 if (age && !streq(age, "-")) {
1236 const char *a = age;
1239 i->keep_first_level = true;
1243 if (parse_sec(a, &i->age) < 0) {
1244 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1251 h = needs_glob(i->type) ? globs : items;
1253 existing = hashmap_get(h, i->path);
1256 /* Two identical items are fine */
1257 if (!item_equal(existing, i))
1258 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1263 r = hashmap_put(h, i->path, i);
1265 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1269 i = NULL; /* avoid cleanup */
1274 static int help(void) {
1276 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1277 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1278 " -h --help Show this help\n"
1279 " --version Show package version\n"
1280 " --create Create marked files/directories\n"
1281 " --clean Clean up marked directories\n"
1282 " --remove Remove marked files/directories\n"
1283 " --boot Execute actions only safe at boot\n"
1284 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1285 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n",
1286 program_invocation_short_name);
1291 static int parse_argv(int argc, char *argv[]) {
1294 ARG_VERSION = 0x100,
1303 static const struct option options[] = {
1304 { "help", no_argument, NULL, 'h' },
1305 { "version", no_argument, NULL, ARG_VERSION },
1306 { "create", no_argument, NULL, ARG_CREATE },
1307 { "clean", no_argument, NULL, ARG_CLEAN },
1308 { "remove", no_argument, NULL, ARG_REMOVE },
1309 { "boot", no_argument, NULL, ARG_BOOT },
1310 { "prefix", required_argument, NULL, ARG_PREFIX },
1311 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1320 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1328 puts(PACKAGE_STRING);
1329 puts(SYSTEMD_FEATURES);
1349 if (strv_extend(&include_prefixes, optarg) < 0)
1353 case ARG_EXCLUDE_PREFIX:
1354 if (strv_extend(&exclude_prefixes, optarg) < 0)
1362 assert_not_reached("Unhandled option");
1366 if (!arg_clean && !arg_create && !arg_remove) {
1367 log_error("You need to specify at least one of --clean, --create or --remove.");
1374 static int read_config_file(const char *fn, bool ignore_enoent) {
1375 _cleanup_fclose_ FILE *f = NULL;
1376 char line[LINE_MAX];
1384 r = search_and_fopen_nulstr(fn, "re", conf_file_dirs, &f);
1386 if (ignore_enoent && r == -ENOENT)
1389 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1393 FOREACH_LINE(line, f, break) {
1400 if (*l == '#' || *l == 0)
1403 k = parse_line(fn, v, l);
1404 if (k < 0 && r == 0)
1408 /* we have to determine age parameter for each entry of type X */
1409 HASHMAP_FOREACH(i, globs, iterator) {
1411 Item *j, *candidate_item = NULL;
1413 if (i->type != IGNORE_DIRECTORY_PATH)
1416 HASHMAP_FOREACH(j, items, iter) {
1417 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1420 if (path_equal(j->path, i->path)) {
1425 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1426 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1430 if (candidate_item) {
1431 i->age = candidate_item->age;
1437 log_error("Failed to read from file %s: %m", fn);
1445 int main(int argc, char *argv[]) {
1450 r = parse_argv(argc, argv);
1452 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1454 log_set_target(LOG_TARGET_AUTO);
1455 log_parse_environment();
1462 items = hashmap_new(string_hash_func, string_compare_func);
1463 globs = hashmap_new(string_hash_func, string_compare_func);
1465 if (!items || !globs) {
1472 if (optind < argc) {
1475 for (j = optind; j < argc; j++) {
1476 k = read_config_file(argv[j], false);
1477 if (k < 0 && r == 0)
1482 _cleanup_strv_free_ char **files = NULL;
1485 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
1487 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1491 STRV_FOREACH(f, files) {
1492 k = read_config_file(*f, true);
1493 if (k < 0 && r == 0)
1498 HASHMAP_FOREACH(i, globs, iterator)
1501 HASHMAP_FOREACH(i, items, iterator)
1505 while ((i = hashmap_steal_first(items)))
1508 while ((i = hashmap_steal_first(globs)))
1511 hashmap_free(items);
1512 hashmap_free(globs);
1514 strv_free(include_prefixes);
1516 set_free_free(unix_sockets);
1520 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;