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 */
66 CREATE_DIRECTORY = 'd',
67 TRUNCATE_DIRECTORY = 'D',
70 CREATE_CHAR_DEVICE = 'c',
71 CREATE_BLOCK_DEVICE = 'b',
74 /* 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;
114 static char *arg_root = NULL;
116 static const char conf_file_dirs[] =
119 "/usr/local/lib/tmpfiles.d\0"
120 "/usr/lib/tmpfiles.d\0"
121 #ifdef HAVE_SPLIT_USR
126 #define MAX_DEPTH 256
128 static bool needs_glob(ItemType t) {
132 IGNORE_DIRECTORY_PATH,
134 RECURSIVE_REMOVE_PATH,
136 RECURSIVE_RELABEL_PATH);
139 static struct Item* find_glob(Hashmap *h, const char *match) {
143 HASHMAP_FOREACH(j, h, i)
144 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
150 static void load_unix_sockets(void) {
151 _cleanup_fclose_ FILE *f = NULL;
157 /* We maintain a cache of the sockets we found in
158 * /proc/net/unix to speed things up a little. */
160 unix_sockets = set_new(string_hash_func, string_compare_func);
164 f = fopen("/proc/net/unix", "re");
169 if (!fgets(line, sizeof(line), f))
176 if (!fgets(line, sizeof(line), f))
181 p = strchr(line, ':');
189 p += strspn(p, WHITESPACE);
190 p += strcspn(p, WHITESPACE); /* skip one more word */
191 p += strspn(p, WHITESPACE);
200 path_kill_slashes(s);
202 k = set_consume(unix_sockets, s);
203 if (k < 0 && k != -EEXIST)
210 set_free_free(unix_sockets);
214 static bool unix_socket_alive(const char *fn) {
220 return !!set_get(unix_sockets, (char*) fn);
222 /* We don't know, so assume yes */
226 static int dir_is_mount_point(DIR *d, const char *subdir) {
228 union file_handle_union h = {
229 .handle.handle_bytes = MAX_HANDLE_SZ
232 int mount_id_parent, mount_id;
235 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
239 h.handle.handle_bytes = MAX_HANDLE_SZ;
240 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
244 /* got no handle; make no assumptions, return error */
245 if (r_p < 0 && r < 0)
248 /* got both handles; if they differ, it is a mount point */
249 if (r_p >= 0 && r >= 0)
250 return mount_id_parent != mount_id;
252 /* got only one handle; assume different mount points if one
253 * of both queries was not supported by the filesystem */
254 if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
263 static int dir_cleanup(
267 const struct stat *ds,
272 bool keep_this_level) {
275 struct timespec times[2];
276 bool deleted = false;
279 while ((dent = readdir(d))) {
282 _cleanup_free_ char *sub_path = NULL;
284 if (streq(dent->d_name, ".") ||
285 streq(dent->d_name, ".."))
288 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
292 /* FUSE, NFS mounts, SELinux might return EACCES */
294 log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
296 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
301 /* Stay on the same filesystem */
302 if (s.st_dev != rootdev)
305 /* Try to detect bind mounts of the same filesystem instance; they
306 * do not differ in device major/minors. This type of query is not
307 * supported on all kernels or filesystem types though. */
308 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
311 /* Do not delete read-only files owned by root */
312 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
315 sub_path = strjoin(p, "/", dent->d_name, NULL);
321 /* Is there an item configured for this path? */
322 if (hashmap_get(items, sub_path))
325 if (find_glob(globs, sub_path))
328 if (S_ISDIR(s.st_mode)) {
331 streq(dent->d_name, "lost+found") &&
336 log_warning("Reached max depth on %s.", sub_path);
338 _cleanup_closedir_ DIR *sub_dir;
341 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
343 if (errno != ENOENT) {
344 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
351 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
356 /* Note: if you are wondering why we don't
357 * support the sticky bit for excluding
358 * directories from cleaning like we do it for
359 * other file system objects: well, the sticky
360 * bit already has a meaning for directories,
361 * so we don't want to overload that. */
366 /* Ignore ctime, we change it when deleting */
367 age = MAX(timespec_load(&s.st_mtim),
368 timespec_load(&s.st_atim));
372 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
373 log_debug("rmdir '%s'", sub_path);
375 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
376 if (errno != ENOENT && errno != ENOTEMPTY) {
377 log_error("rmdir(%s): %m", sub_path);
384 /* Skip files for which the sticky bit is
385 * set. These are semantics we define, and are
386 * unknown elsewhere. See XDG_RUNTIME_DIR
387 * specification for details. */
388 if (s.st_mode & S_ISVTX)
391 if (mountpoint && S_ISREG(s.st_mode)) {
392 if (streq(dent->d_name, ".journal") &&
396 if (streq(dent->d_name, "aquota.user") ||
397 streq(dent->d_name, "aquota.group"))
401 /* Ignore sockets that are listed in /proc/net/unix */
402 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
405 /* Ignore device nodes */
406 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
409 /* Keep files on this level around if this is
414 age = MAX3(timespec_load(&s.st_mtim),
415 timespec_load(&s.st_atim),
416 timespec_load(&s.st_ctim));
421 log_debug("unlink '%s'", sub_path);
423 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
424 if (errno != ENOENT) {
425 log_error("unlink(%s): %m", sub_path);
436 /* Restore original directory timestamps */
437 times[0] = ds->st_atim;
438 times[1] = ds->st_mtim;
440 if (futimens(dirfd(d), times) < 0)
441 log_error("utimensat(%s): %m", p);
447 static int item_set_perms_full(Item *i, const char *path, bool ignore_enoent) {
451 /* not using i->path directly because it may be a glob */
453 if (chmod(path, i->mode) < 0) {
454 if (errno != ENOENT || !ignore_enoent) {
455 log_error("chmod(%s) failed: %m", path);
460 if (i->uid_set || i->gid_set)
462 i->uid_set ? i->uid : (uid_t) -1,
463 i->gid_set ? i->gid : (gid_t) -1) < 0) {
465 if (errno != ENOENT || !ignore_enoent) {
466 log_error("chown(%s) failed: %m", path);
471 return label_fix(path, ignore_enoent, false);
474 static int item_set_perms(Item *i, const char *path) {
475 return item_set_perms_full(i, path, false);
478 static int write_one_file(Item *i, const char *path) {
487 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
488 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
491 label_context_set(path, S_IFREG);
492 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
493 label_context_clear();
497 if (i->type == WRITE_FILE && errno == ENOENT)
500 log_error("Failed to create file %s: %m", path);
505 _cleanup_free_ char *unescaped;
509 unescaped = cunescape(i->argument);
510 if (unescaped == NULL) {
515 l = strlen(unescaped);
516 n = write(fd, unescaped, l);
518 if (n < 0 || (size_t) n < l) {
519 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
521 return n < 0 ? n : -EIO;
527 if (stat(path, &st) < 0) {
528 log_error("stat(%s) failed: %m", path);
532 if (!S_ISREG(st.st_mode)) {
533 log_error("%s is not a file.", path);
537 r = item_set_perms(i, path);
544 static int recursive_relabel_children(Item *i, const char *path) {
545 _cleanup_closedir_ DIR *d;
548 /* This returns the first error we run into, but nevertheless
553 return errno == ENOENT ? 0 : -errno;
559 _cleanup_free_ char *entry_path = NULL;
563 if (!de && errno != 0) {
572 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
575 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
581 if (de->d_type == DT_UNKNOWN) {
582 r = is_dir(entry_path);
584 if (ret == 0 && errno != ENOENT)
592 dir = de->d_type == DT_DIR;
594 r = item_set_perms(i, entry_path);
596 if (ret == 0 && r != -ENOENT)
602 r = recursive_relabel_children(i, entry_path);
603 if (r < 0 && ret == 0)
611 static int recursive_relabel(Item *i, const char *path) {
615 r = item_set_perms(i, path);
619 if (lstat(path, &st) < 0)
622 if (S_ISDIR(st.st_mode))
623 r = recursive_relabel_children(i, path);
628 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
630 _cleanup_globfree_ glob_t g = {};
634 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
636 if (k != GLOB_NOMATCH) {
640 log_error("glob(%s) failed: %m", i->path);
644 STRV_FOREACH(fn, g.gl_pathv) {
653 static int create_item(Item *i) {
662 case IGNORE_DIRECTORY_PATH:
664 case RECURSIVE_REMOVE_PATH:
669 r = write_one_file(i, i->path);
675 r = glob_item(i, write_one_file);
682 r = item_set_perms_full(i, i->path, true);
688 case TRUNCATE_DIRECTORY:
689 case CREATE_DIRECTORY:
691 RUN_WITH_UMASK(0000) {
692 mkdir_parents_label(i->path, 0755);
693 r = mkdir(i->path, i->mode);
696 if (r < 0 && errno != EEXIST) {
697 log_error("Failed to create directory %s: %m", i->path);
701 if (stat(i->path, &st) < 0) {
702 log_error("stat(%s) failed: %m", i->path);
706 if (!S_ISDIR(st.st_mode)) {
707 log_error("%s is not a directory.", i->path);
711 r = item_set_perms(i, i->path);
719 RUN_WITH_UMASK(0000) {
720 r = mkfifo(i->path, i->mode);
723 if (r < 0 && errno != EEXIST) {
724 log_error("Failed to create fifo %s: %m", i->path);
728 if (stat(i->path, &st) < 0) {
729 log_error("stat(%s) failed: %m", i->path);
733 if (!S_ISFIFO(st.st_mode)) {
734 log_error("%s is not a fifo.", i->path);
738 r = item_set_perms(i, i->path);
744 case CREATE_SYMLINK: {
745 _cleanup_free_ char *x = NULL;
747 label_context_set(i->path, S_IFLNK);
748 r = symlink(i->argument, i->path);
749 label_context_clear();
751 if (r < 0 && errno != EEXIST) {
752 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
756 r = readlink_malloc(i->path, &x);
758 log_error("readlink(%s) failed: %s", i->path, strerror(-r));
762 if (!streq(i->argument, x)) {
763 log_error("%s is not the right symlinks.", i->path);
770 case CREATE_BLOCK_DEVICE:
771 case CREATE_CHAR_DEVICE: {
774 if (have_effective_cap(CAP_MKNOD) == 0) {
775 /* In a container we lack CAP_MKNOD. We
776 shouldn't attempt to create the device node in
777 that case to avoid noise, and we don't support
778 virtualized devices in containers anyway. */
780 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
784 file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
786 RUN_WITH_UMASK(0000) {
787 label_context_set(i->path, file_type);
788 r = mknod(i->path, i->mode | file_type, i->major_minor);
789 label_context_clear();
792 if (r < 0 && errno != EEXIST) {
793 log_error("Failed to create device node %s: %m", i->path);
797 if (stat(i->path, &st) < 0) {
798 log_error("stat(%s) failed: %m", i->path);
802 if ((st.st_mode & S_IFMT) != file_type) {
803 log_error("%s is not a device node.", i->path);
807 r = item_set_perms(i, i->path);
816 r = glob_item(i, item_set_perms);
821 case RECURSIVE_RELABEL_PATH:
823 r = glob_item(i, recursive_relabel);
828 log_debug("%s created successfully.", i->path);
833 static int remove_item_instance(Item *i, const char *instance) {
842 case CREATE_DIRECTORY:
845 case CREATE_BLOCK_DEVICE:
846 case CREATE_CHAR_DEVICE:
848 case IGNORE_DIRECTORY_PATH:
850 case RECURSIVE_RELABEL_PATH:
856 if (remove(instance) < 0 && errno != ENOENT) {
857 log_error("remove(%s): %m", instance);
863 case TRUNCATE_DIRECTORY:
864 case RECURSIVE_REMOVE_PATH:
865 /* FIXME: we probably should use dir_cleanup() here
866 * instead of rm_rf() so that 'x' is honoured. */
867 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
868 if (r < 0 && r != -ENOENT) {
869 log_error("rm_rf(%s): %s", instance, strerror(-r));
879 static int remove_item(Item *i) {
888 case CREATE_DIRECTORY:
891 case CREATE_CHAR_DEVICE:
892 case CREATE_BLOCK_DEVICE:
894 case IGNORE_DIRECTORY_PATH:
896 case RECURSIVE_RELABEL_PATH:
902 case TRUNCATE_DIRECTORY:
903 case RECURSIVE_REMOVE_PATH:
904 r = glob_item(i, remove_item_instance);
911 static int clean_item_instance(Item *i, const char* instance) {
912 _cleanup_closedir_ DIR *d = NULL;
923 n = now(CLOCK_REALTIME);
929 d = opendir(instance);
931 if (errno == ENOENT || errno == ENOTDIR)
934 log_error("Failed to open directory %s: %m", i->path);
938 if (fstat(dirfd(d), &s) < 0) {
939 log_error("stat(%s) failed: %m", i->path);
943 if (!S_ISDIR(s.st_mode)) {
944 log_error("%s is not a directory.", i->path);
948 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
949 log_error("stat(%s/..) failed: %m", i->path);
953 mountpoint = s.st_dev != ps.st_dev ||
954 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
956 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
957 MAX_DEPTH, i->keep_first_level);
961 static int clean_item(Item *i) {
967 case CREATE_DIRECTORY:
968 case TRUNCATE_DIRECTORY:
970 clean_item_instance(i, i->path);
972 case IGNORE_DIRECTORY_PATH:
973 r = glob_item(i, clean_item_instance);
982 static int process_item(Item *i) {
987 r = arg_create ? create_item(i) : 0;
988 q = arg_remove ? remove_item(i) : 0;
989 p = arg_clean ? clean_item(i) : 0;
1000 static void item_free(Item *i) {
1008 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1010 static bool item_equal(Item *a, Item *b) {
1014 if (!streq_ptr(a->path, b->path))
1017 if (a->type != b->type)
1020 if (a->uid_set != b->uid_set ||
1021 (a->uid_set && a->uid != b->uid))
1024 if (a->gid_set != b->gid_set ||
1025 (a->gid_set && a->gid != b->gid))
1028 if (a->mode_set != b->mode_set ||
1029 (a->mode_set && a->mode != b->mode))
1032 if (a->age_set != b->age_set ||
1033 (a->age_set && a->age != b->age))
1036 if ((a->type == CREATE_FILE ||
1037 a->type == TRUNCATE_FILE ||
1038 a->type == WRITE_FILE ||
1039 a->type == CREATE_SYMLINK) &&
1040 !streq_ptr(a->argument, b->argument))
1043 if ((a->type == CREATE_CHAR_DEVICE ||
1044 a->type == CREATE_BLOCK_DEVICE) &&
1045 a->major_minor != b->major_minor)
1051 static bool should_include_path(const char *path) {
1054 STRV_FOREACH(prefix, exclude_prefixes) {
1055 if (path_startswith(path, *prefix))
1059 STRV_FOREACH(prefix, include_prefixes) {
1060 if (path_startswith(path, *prefix))
1064 /* no matches, so we should include this path only if we
1065 * have no whitelist at all */
1066 return strv_length(include_prefixes) == 0;
1069 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1071 static const Specifier specifier_table[] = {
1072 { 'm', specifier_machine_id, NULL },
1073 { 'b', specifier_boot_id, NULL },
1074 { 'H', specifier_host_name, NULL },
1075 { 'v', specifier_kernel_release, NULL },
1079 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1080 _cleanup_(item_freep) Item *i = 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);
1157 log_error("[%s:%u] Write file requires argument.", fname, line);
1162 case CREATE_CHAR_DEVICE:
1163 case CREATE_BLOCK_DEVICE: {
1164 unsigned major, minor;
1167 log_error("[%s:%u] Device file requires argument.", fname, line);
1171 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1172 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1176 i->major_minor = makedev(major, minor);
1181 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1187 if (!path_is_absolute(i->path)) {
1188 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1192 path_kill_slashes(i->path);
1194 if (!should_include_path(i->path))
1200 p = strappend(arg_root, i->path);
1208 if (user && !streq(user, "-")) {
1209 const char *u = user;
1211 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1213 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1220 if (group && !streq(group, "-")) {
1221 const char *g = group;
1223 r = get_group_creds(&g, &i->gid);
1225 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1232 if (mode && !streq(mode, "-")) {
1235 if (sscanf(mode, "%o", &m) != 1) {
1236 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1244 i->type == CREATE_DIRECTORY ||
1245 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1247 if (age && !streq(age, "-")) {
1248 const char *a = age;
1251 i->keep_first_level = true;
1255 if (parse_sec(a, &i->age) < 0) {
1256 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1263 h = needs_glob(i->type) ? globs : items;
1265 existing = hashmap_get(h, i->path);
1268 /* Two identical items are fine */
1269 if (!item_equal(existing, i))
1270 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1275 r = hashmap_put(h, i->path, i);
1277 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1281 i = NULL; /* avoid cleanup */
1286 static int help(void) {
1288 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1289 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1290 " -h --help Show this help\n"
1291 " --version Show package version\n"
1292 " --create Create marked files/directories\n"
1293 " --clean Clean up marked directories\n"
1294 " --remove Remove marked files/directories\n"
1295 " --boot Execute actions only safe at boot\n"
1296 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1297 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1298 " --root=PATH Operate on an alternate filesystem root\n",
1299 program_invocation_short_name);
1304 static int parse_argv(int argc, char *argv[]) {
1307 ARG_VERSION = 0x100,
1317 static const struct option options[] = {
1318 { "help", no_argument, NULL, 'h' },
1319 { "version", no_argument, NULL, ARG_VERSION },
1320 { "create", no_argument, NULL, ARG_CREATE },
1321 { "clean", no_argument, NULL, ARG_CLEAN },
1322 { "remove", no_argument, NULL, ARG_REMOVE },
1323 { "boot", no_argument, NULL, ARG_BOOT },
1324 { "prefix", required_argument, NULL, ARG_PREFIX },
1325 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1326 { "root", required_argument, NULL, ARG_ROOT },
1335 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1343 puts(PACKAGE_STRING);
1344 puts(SYSTEMD_FEATURES);
1364 if (strv_push(&include_prefixes, optarg) < 0)
1368 case ARG_EXCLUDE_PREFIX:
1369 if (strv_push(&exclude_prefixes, optarg) < 0)
1374 arg_root = path_make_absolute_cwd(optarg);
1377 path_kill_slashes(arg_root);
1384 assert_not_reached("Unhandled option");
1388 if (!arg_clean && !arg_create && !arg_remove) {
1389 log_error("You need to specify at least one of --clean, --create or --remove.");
1396 static int read_config_file(const char *fn, bool ignore_enoent) {
1397 _cleanup_fclose_ FILE *f = NULL;
1398 char line[LINE_MAX];
1406 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1408 if (ignore_enoent && r == -ENOENT)
1411 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1415 FOREACH_LINE(line, f, break) {
1422 if (*l == '#' || *l == 0)
1425 k = parse_line(fn, v, l);
1426 if (k < 0 && r == 0)
1430 /* we have to determine age parameter for each entry of type X */
1431 HASHMAP_FOREACH(i, globs, iterator) {
1433 Item *j, *candidate_item = NULL;
1435 if (i->type != IGNORE_DIRECTORY_PATH)
1438 HASHMAP_FOREACH(j, items, iter) {
1439 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1442 if (path_equal(j->path, i->path)) {
1447 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1448 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1452 if (candidate_item) {
1453 i->age = candidate_item->age;
1459 log_error("Failed to read from file %s: %m", fn);
1467 int main(int argc, char *argv[]) {
1472 r = parse_argv(argc, argv);
1474 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1476 log_set_target(LOG_TARGET_AUTO);
1477 log_parse_environment();
1484 items = hashmap_new(string_hash_func, string_compare_func);
1485 globs = hashmap_new(string_hash_func, string_compare_func);
1487 if (!items || !globs) {
1494 if (optind < argc) {
1497 for (j = optind; j < argc; j++) {
1498 k = read_config_file(argv[j], false);
1499 if (k < 0 && r == 0)
1504 _cleanup_strv_free_ char **files = NULL;
1507 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1509 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1513 STRV_FOREACH(f, files) {
1514 k = read_config_file(*f, true);
1515 if (k < 0 && r == 0)
1520 HASHMAP_FOREACH(i, globs, iterator)
1523 HASHMAP_FOREACH(i, items, iterator)
1527 while ((i = hashmap_steal_first(items)))
1530 while ((i = hashmap_steal_first(globs)))
1533 hashmap_free(items);
1534 hashmap_free(globs);
1536 free(include_prefixes);
1537 free(exclude_prefixes);
1540 set_free_free(unix_sockets);
1544 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;