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;
111 static char **include_prefixes = NULL;
112 static char **exclude_prefixes = NULL;
114 static const char conf_file_dirs[] =
117 "/usr/local/lib/tmpfiles.d\0"
118 "/usr/lib/tmpfiles.d\0"
119 #ifdef HAVE_SPLIT_USR
124 #define MAX_DEPTH 256
126 static bool needs_glob(ItemType t) {
127 return t == IGNORE_PATH || t == IGNORE_DIRECTORY_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
130 static struct Item* find_glob(Hashmap *h, const char *match) {
134 HASHMAP_FOREACH(j, h, i)
135 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
141 static void load_unix_sockets(void) {
142 _cleanup_fclose_ FILE *f = NULL;
148 /* We maintain a cache of the sockets we found in
149 * /proc/net/unix to speed things up a little. */
151 unix_sockets = set_new(string_hash_func, string_compare_func);
155 f = fopen("/proc/net/unix", "re");
160 if (!fgets(line, sizeof(line), f))
167 if (!fgets(line, sizeof(line), f))
172 p = strchr(line, ':');
180 p += strspn(p, WHITESPACE);
181 p += strcspn(p, WHITESPACE); /* skip one more word */
182 p += strspn(p, WHITESPACE);
191 path_kill_slashes(s);
193 k = set_consume(unix_sockets, s);
194 if (k < 0 && k != -EEXIST)
201 set_free_free(unix_sockets);
205 static bool unix_socket_alive(const char *fn) {
211 return !!set_get(unix_sockets, (char*) fn);
213 /* We don't know, so assume yes */
217 static int dir_is_mount_point(DIR *d, const char *subdir) {
218 struct file_handle *h;
219 int mount_id_parent, mount_id;
222 h = alloca(MAX_HANDLE_SZ);
224 h->handle_bytes = MAX_HANDLE_SZ;
225 r_p = name_to_handle_at(dirfd(d), ".", h, &mount_id_parent, 0);
229 h->handle_bytes = MAX_HANDLE_SZ;
230 r = name_to_handle_at(dirfd(d), subdir, h, &mount_id, 0);
234 /* got no handle; make no assumptions, return error */
235 if (r_p < 0 && r < 0)
238 /* got both handles; if they differ, it is a mount point */
239 if (r_p >= 0 && r >= 0)
240 return mount_id_parent != mount_id;
242 /* got only one handle; assume different mount points if one
243 * of both queries was not supported by the filesystem */
244 if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
253 static int dir_cleanup(
257 const struct stat *ds,
262 bool keep_this_level) {
265 struct timespec times[2];
266 bool deleted = false;
269 while ((dent = readdir(d))) {
272 _cleanup_free_ char *sub_path = NULL;
274 if (streq(dent->d_name, ".") ||
275 streq(dent->d_name, ".."))
278 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
282 /* FUSE, NFS mounts, SELinux might return EACCES */
284 log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
286 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
291 /* Stay on the same filesystem */
292 if (s.st_dev != rootdev)
295 /* Try to detect bind mounts of the same filesystem instance; they
296 * do not differ in device major/minors. This type of query is not
297 * supported on all kernels or filesystem types though. */
298 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
301 /* Do not delete read-only files owned by root */
302 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
305 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
310 /* Is there an item configured for this path? */
311 if (hashmap_get(items, sub_path))
314 if (find_glob(globs, sub_path))
317 if (S_ISDIR(s.st_mode)) {
320 streq(dent->d_name, "lost+found") &&
325 log_warning("Reached max depth on %s.", sub_path);
327 _cleanup_closedir_ DIR *sub_dir;
330 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
331 if (sub_dir == NULL) {
332 if (errno != ENOENT) {
333 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
340 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
346 /* Note: if you are wondering why we don't
347 * support the sticky bit for excluding
348 * directories from cleaning like we do it for
349 * other file system objects: well, the sticky
350 * bit already has a meaning for directories,
351 * so we don't want to overload that. */
356 /* Ignore ctime, we change it when deleting */
357 age = MAX(timespec_load(&s.st_mtim),
358 timespec_load(&s.st_atim));
362 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
363 log_debug("rmdir '%s'\n", sub_path);
365 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
366 if (errno != ENOENT && errno != ENOTEMPTY) {
367 log_error("rmdir(%s): %m", sub_path);
374 /* Skip files for which the sticky bit is
375 * set. These are semantics we define, and are
376 * unknown elsewhere. See XDG_RUNTIME_DIR
377 * specification for details. */
378 if (s.st_mode & S_ISVTX)
381 if (mountpoint && S_ISREG(s.st_mode)) {
382 if (streq(dent->d_name, ".journal") &&
386 if (streq(dent->d_name, "aquota.user") ||
387 streq(dent->d_name, "aquota.group"))
391 /* Ignore sockets that are listed in /proc/net/unix */
392 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
395 /* Ignore device nodes */
396 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
399 /* Keep files on this level around if this is
404 age = MAX3(timespec_load(&s.st_mtim),
405 timespec_load(&s.st_atim),
406 timespec_load(&s.st_ctim));
411 log_debug("unlink '%s'\n", sub_path);
413 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
414 if (errno != ENOENT) {
415 log_error("unlink(%s): %m", sub_path);
426 /* Restore original directory timestamps */
427 times[0] = ds->st_atim;
428 times[1] = ds->st_mtim;
430 if (futimens(dirfd(d), times) < 0)
431 log_error("utimensat(%s): %m", p);
437 static int item_set_perms_full(Item *i, const char *path, bool ignore_enoent) {
440 /* not using i->path directly because it may be a glob */
442 if (chmod(path, i->mode) < 0) {
443 if (errno != ENOENT || !ignore_enoent) {
444 log_error("chmod(%s) failed: %m", path);
449 if (i->uid_set || i->gid_set)
451 i->uid_set ? i->uid : (uid_t) -1,
452 i->gid_set ? i->gid : (gid_t) -1) < 0) {
454 if (errno != ENOENT || !ignore_enoent) {
455 log_error("chown(%s) failed: %m", path);
460 r = label_fix(path, false, false);
461 return r == -ENOENT && ignore_enoent ? 0 : r;
464 static int item_set_perms(Item *i, const char *path) {
465 return item_set_perms_full(i, path, false);
468 static int write_one_file(Item *i, const char *path) {
474 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
475 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
478 label_context_set(path, S_IFREG);
479 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
481 label_context_clear();
486 if (i->type == WRITE_FILE && errno == ENOENT)
489 log_error("Failed to create file %s: %m", path);
496 _cleanup_free_ char *unescaped;
498 unescaped = cunescape(i->argument);
499 if (unescaped == NULL) {
500 close_nointr_nofail(fd);
504 l = strlen(unescaped);
505 n = write(fd, unescaped, l);
507 if (n < 0 || (size_t) n < l) {
508 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
509 close_nointr_nofail(fd);
510 return n < 0 ? n : -EIO;
514 close_nointr_nofail(fd);
516 if (stat(path, &st) < 0) {
517 log_error("stat(%s) failed: %m", path);
521 if (!S_ISREG(st.st_mode)) {
522 log_error("%s is not a file.", path);
526 r = item_set_perms(i, path);
533 static int recursive_relabel_children(Item *i, const char *path) {
534 _cleanup_closedir_ DIR *d;
537 /* This returns the first error we run into, but nevertheless
542 return errno == ENOENT ? 0 : -errno;
546 union dirent_storage buf;
549 _cleanup_free_ char *entry_path = NULL;
551 r = readdir_r(d, &buf.de, &de);
561 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
564 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
570 if (de->d_type == DT_UNKNOWN) {
573 if (lstat(entry_path, &st) < 0) {
574 if (ret == 0 && errno != ENOENT)
579 is_dir = S_ISDIR(st.st_mode);
582 is_dir = de->d_type == DT_DIR;
584 r = item_set_perms(i, entry_path);
586 if (ret == 0 && r != -ENOENT)
592 r = recursive_relabel_children(i, entry_path);
593 if (r < 0 && ret == 0)
601 static int recursive_relabel(Item *i, const char *path) {
605 r = item_set_perms(i, path);
609 if (lstat(path, &st) < 0)
612 if (S_ISDIR(st.st_mode))
613 r = recursive_relabel_children(i, path);
618 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
620 _cleanup_globfree_ glob_t g = {};
624 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
626 if (k != GLOB_NOMATCH) {
630 log_error("glob(%s) failed: %m", i->path);
634 STRV_FOREACH(fn, g.gl_pathv) {
643 static int create_item(Item *i) {
653 case IGNORE_DIRECTORY_PATH:
655 case RECURSIVE_REMOVE_PATH:
660 r = write_one_file(i, i->path);
666 r = glob_item(i, write_one_file);
673 r = item_set_perms_full(i, i->path, true);
679 case TRUNCATE_DIRECTORY:
680 case CREATE_DIRECTORY:
682 RUN_WITH_UMASK(0000) {
683 mkdir_parents_label(i->path, 0755);
684 r = mkdir(i->path, i->mode);
687 if (r < 0 && errno != EEXIST) {
688 log_error("Failed to create directory %s: %m", i->path);
692 if (stat(i->path, &st) < 0) {
693 log_error("stat(%s) failed: %m", i->path);
697 if (!S_ISDIR(st.st_mode)) {
698 log_error("%s is not a directory.", i->path);
702 r = item_set_perms(i, i->path);
710 RUN_WITH_UMASK(0000) {
711 r = mkfifo(i->path, i->mode);
714 if (r < 0 && errno != EEXIST) {
715 log_error("Failed to create fifo %s: %m", i->path);
719 if (stat(i->path, &st) < 0) {
720 log_error("stat(%s) failed: %m", i->path);
724 if (!S_ISFIFO(st.st_mode)) {
725 log_error("%s is not a fifo.", i->path);
729 r = item_set_perms(i, i->path);
735 case CREATE_SYMLINK: {
738 label_context_set(i->path, S_IFLNK);
739 r = symlink(i->argument, i->path);
741 label_context_clear();
744 if (r < 0 && errno != EEXIST) {
745 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
749 r = readlink_malloc(i->path, &x);
751 log_error("readlink(%s) failed: %s", i->path, strerror(-r));
755 if (!streq(i->argument, x)) {
757 log_error("%s is not the right symlinks.", i->path);
765 case CREATE_BLOCK_DEVICE:
766 case CREATE_CHAR_DEVICE: {
769 if (have_effective_cap(CAP_MKNOD) == 0) {
770 /* In a container we lack CAP_MKNOD. We
771 shouldn't attempt to create the device node in
772 that case to avoid noise, and we don't support
773 virtualized devices in containers anyway. */
775 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
779 file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
781 RUN_WITH_UMASK(0000) {
782 label_context_set(i->path, file_type);
783 r = mknod(i->path, i->mode | file_type, i->major_minor);
785 label_context_clear();
789 if (r < 0 && errno != EEXIST) {
790 log_error("Failed to create device node %s: %m", i->path);
794 if (stat(i->path, &st) < 0) {
795 log_error("stat(%s) failed: %m", i->path);
799 if ((st.st_mode & S_IFMT) != file_type) {
800 log_error("%s is not a device node.", i->path);
804 r = item_set_perms(i, i->path);
813 r = glob_item(i, item_set_perms);
818 case RECURSIVE_RELABEL_PATH:
820 r = glob_item(i, recursive_relabel);
825 log_debug("%s created successfully.", i->path);
830 static int remove_item_instance(Item *i, const char *instance) {
839 case CREATE_DIRECTORY:
842 case CREATE_BLOCK_DEVICE:
843 case CREATE_CHAR_DEVICE:
845 case IGNORE_DIRECTORY_PATH:
847 case RECURSIVE_RELABEL_PATH:
853 if (remove(instance) < 0 && errno != ENOENT) {
854 log_error("remove(%s): %m", instance);
860 case TRUNCATE_DIRECTORY:
861 case RECURSIVE_REMOVE_PATH:
862 /* FIXME: we probably should use dir_cleanup() here
863 * instead of rm_rf() so that 'x' is honoured. */
864 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
865 if (r < 0 && r != -ENOENT) {
866 log_error("rm_rf(%s): %s", instance, strerror(-r));
876 static int remove_item(Item *i) {
885 case CREATE_DIRECTORY:
888 case CREATE_CHAR_DEVICE:
889 case CREATE_BLOCK_DEVICE:
891 case IGNORE_DIRECTORY_PATH:
893 case RECURSIVE_RELABEL_PATH:
899 case TRUNCATE_DIRECTORY:
900 case RECURSIVE_REMOVE_PATH:
901 r = glob_item(i, remove_item_instance);
908 static int clean_item_instance(Item *i, const char* instance) {
909 _cleanup_closedir_ DIR *d = NULL;
920 n = now(CLOCK_REALTIME);
926 d = opendir(instance);
928 if (errno == ENOENT || errno == ENOTDIR)
931 log_error("Failed to open directory %s: %m", i->path);
935 if (fstat(dirfd(d), &s) < 0) {
936 log_error("stat(%s) failed: %m", i->path);
940 if (!S_ISDIR(s.st_mode)) {
941 log_error("%s is not a directory.", i->path);
945 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
946 log_error("stat(%s/..) failed: %m", i->path);
950 mountpoint = s.st_dev != ps.st_dev ||
951 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
953 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
954 MAX_DEPTH, i->keep_first_level);
958 static int clean_item(Item *i) {
964 case CREATE_DIRECTORY:
965 case TRUNCATE_DIRECTORY:
967 clean_item_instance(i, i->path);
969 case IGNORE_DIRECTORY_PATH:
970 r = glob_item(i, clean_item_instance);
979 static int process_item(Item *i) {
984 r = arg_create ? create_item(i) : 0;
985 q = arg_remove ? remove_item(i) : 0;
986 p = arg_clean ? clean_item(i) : 0;
997 static void item_free(Item *i) {
1005 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1006 #define _cleanup_item_free_ _cleanup_(item_freep)
1008 static bool item_equal(Item *a, Item *b) {
1012 if (!streq_ptr(a->path, b->path))
1015 if (a->type != b->type)
1018 if (a->uid_set != b->uid_set ||
1019 (a->uid_set && a->uid != b->uid))
1022 if (a->gid_set != b->gid_set ||
1023 (a->gid_set && a->gid != b->gid))
1026 if (a->mode_set != b->mode_set ||
1027 (a->mode_set && a->mode != b->mode))
1030 if (a->age_set != b->age_set ||
1031 (a->age_set && a->age != b->age))
1034 if ((a->type == CREATE_FILE ||
1035 a->type == TRUNCATE_FILE ||
1036 a->type == WRITE_FILE ||
1037 a->type == CREATE_SYMLINK) &&
1038 !streq_ptr(a->argument, b->argument))
1041 if ((a->type == CREATE_CHAR_DEVICE ||
1042 a->type == CREATE_BLOCK_DEVICE) &&
1043 a->major_minor != b->major_minor)
1049 static bool should_include_path(const char *path) {
1052 STRV_FOREACH(prefix, exclude_prefixes) {
1053 if (path_startswith(path, *prefix))
1057 STRV_FOREACH(prefix, include_prefixes) {
1058 if (path_startswith(path, *prefix))
1062 /* no matches, so we should include this path only if we
1063 * have no whitelist at all */
1064 return strv_length(include_prefixes) == 0;
1067 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1069 static const Specifier specifier_table[] = {
1070 { 'm', specifier_machine_id, NULL },
1071 { 'b', specifier_boot_id, NULL },
1072 { 'H', specifier_host_name, NULL },
1073 { 'v', specifier_kernel_release, NULL },
1077 _cleanup_item_free_ Item *i = NULL;
1080 *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1090 "%c %ms %ms %ms %ms %ms %n",
1099 log_error("[%s:%u] Syntax error.", fname, line);
1107 r = specifier_printf(path, specifier_table, NULL, &i->path);
1109 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1114 n += strspn(buffer+n, WHITESPACE);
1115 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1116 i->argument = unquote(buffer+n, "\"");
1126 case CREATE_DIRECTORY:
1127 case TRUNCATE_DIRECTORY:
1130 case IGNORE_DIRECTORY_PATH:
1132 case RECURSIVE_REMOVE_PATH:
1134 case RECURSIVE_RELABEL_PATH:
1138 case CREATE_SYMLINK:
1140 log_error("[%s:%u] Symlink file requires argument.", fname, line);
1147 log_error("[%s:%u] Write file requires argument.", fname, line);
1152 case CREATE_CHAR_DEVICE:
1153 case CREATE_BLOCK_DEVICE: {
1154 unsigned major, minor;
1157 log_error("[%s:%u] Device file requires argument.", fname, line);
1161 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1162 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1166 i->major_minor = makedev(major, minor);
1171 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1177 if (!path_is_absolute(i->path)) {
1178 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1182 path_kill_slashes(i->path);
1184 if (!should_include_path(i->path))
1187 if (user && !streq(user, "-")) {
1188 const char *u = user;
1190 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1192 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1199 if (group && !streq(group, "-")) {
1200 const char *g = group;
1202 r = get_group_creds(&g, &i->gid);
1204 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1211 if (mode && !streq(mode, "-")) {
1214 if (sscanf(mode, "%o", &m) != 1) {
1215 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1223 i->type == CREATE_DIRECTORY ||
1224 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1226 if (age && !streq(age, "-")) {
1227 const char *a = age;
1230 i->keep_first_level = true;
1234 if (parse_sec(a, &i->age) < 0) {
1235 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1242 h = needs_glob(i->type) ? globs : items;
1244 existing = hashmap_get(h, i->path);
1247 /* Two identical items are fine */
1248 if (!item_equal(existing, i))
1249 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1254 r = hashmap_put(h, i->path, i);
1256 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1260 i = NULL; /* avoid cleanup */
1265 static int help(void) {
1267 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1268 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1269 " -h --help Show this help\n"
1270 " --version Show package version\n"
1271 " --create Create marked files/directories\n"
1272 " --clean Clean up marked directories\n"
1273 " --remove Remove marked files/directories\n"
1274 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1275 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n",
1276 program_invocation_short_name);
1281 static int parse_argv(int argc, char *argv[]) {
1284 ARG_VERSION = 0x100,
1292 static const struct option options[] = {
1293 { "help", no_argument, NULL, 'h' },
1294 { "version", no_argument, NULL, ARG_VERSION },
1295 { "create", no_argument, NULL, ARG_CREATE },
1296 { "clean", no_argument, NULL, ARG_CLEAN },
1297 { "remove", no_argument, NULL, ARG_REMOVE },
1298 { "prefix", required_argument, NULL, ARG_PREFIX },
1299 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1308 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1316 puts(PACKAGE_STRING);
1317 puts(SYSTEMD_FEATURES);
1333 if (strv_extend(&include_prefixes, optarg) < 0)
1337 case ARG_EXCLUDE_PREFIX:
1338 if (strv_extend(&exclude_prefixes, optarg) < 0)
1346 assert_not_reached("Unhandled option");
1350 if (!arg_clean && !arg_create && !arg_remove) {
1351 log_error("You need to specify at least one of --clean, --create or --remove.");
1358 static int read_config_file(const char *fn, bool ignore_enoent) {
1359 _cleanup_fclose_ FILE *f = NULL;
1360 char line[LINE_MAX];
1368 r = search_and_fopen_nulstr(fn, "re", conf_file_dirs, &f);
1370 if (ignore_enoent && r == -ENOENT)
1373 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1377 FOREACH_LINE(line, f, break) {
1384 if (*l == '#' || *l == 0)
1387 k = parse_line(fn, v, l);
1388 if (k < 0 && r == 0)
1392 /* we have to determine age parameter for each entry of type X */
1393 HASHMAP_FOREACH(i, globs, iterator) {
1395 Item *j, *candidate_item = NULL;
1397 if (i->type != IGNORE_DIRECTORY_PATH)
1400 HASHMAP_FOREACH(j, items, iter) {
1401 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1404 if (path_equal(j->path, i->path)) {
1409 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1410 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1414 if (candidate_item) {
1415 i->age = candidate_item->age;
1421 log_error("Failed to read from file %s: %m", fn);
1429 int main(int argc, char *argv[]) {
1434 r = parse_argv(argc, argv);
1436 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1438 log_set_target(LOG_TARGET_AUTO);
1439 log_parse_environment();
1446 items = hashmap_new(string_hash_func, string_compare_func);
1447 globs = hashmap_new(string_hash_func, string_compare_func);
1449 if (!items || !globs) {
1456 if (optind < argc) {
1459 for (j = optind; j < argc; j++) {
1460 k = read_config_file(argv[j], false);
1461 if (k < 0 && r == 0)
1466 _cleanup_strv_free_ char **files = NULL;
1469 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
1471 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1475 STRV_FOREACH(f, files) {
1476 k = read_config_file(*f, true);
1477 if (k < 0 && r == 0)
1482 HASHMAP_FOREACH(i, globs, iterator)
1485 HASHMAP_FOREACH(i, items, iterator)
1489 while ((i = hashmap_steal_first(items)))
1492 while ((i = hashmap_steal_first(globs)))
1495 hashmap_free(items);
1496 hashmap_free(globs);
1498 strv_free(include_prefixes);
1500 set_free_free(unix_sockets);
1504 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;