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',
103 bool keep_first_level:1;
108 static bool arg_create = false;
109 static bool arg_clean = false;
110 static bool arg_remove = false;
111 static bool arg_boot = false;
113 static char **arg_include_prefixes = NULL;
114 static char **arg_exclude_prefixes = NULL;
115 static char *arg_root = NULL;
117 static const char conf_file_dirs[] =
120 "/usr/local/lib/tmpfiles.d\0"
121 "/usr/lib/tmpfiles.d\0"
122 #ifdef HAVE_SPLIT_USR
127 #define MAX_DEPTH 256
129 static Hashmap *items = NULL, *globs = NULL;
130 static Set *unix_sockets = NULL;
132 static bool needs_glob(ItemType t) {
136 IGNORE_DIRECTORY_PATH,
138 RECURSIVE_REMOVE_PATH,
141 RECURSIVE_RELABEL_PATH);
144 static struct Item* find_glob(Hashmap *h, const char *match) {
148 HASHMAP_FOREACH(j, h, i)
149 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
155 static void load_unix_sockets(void) {
156 _cleanup_fclose_ FILE *f = NULL;
162 /* We maintain a cache of the sockets we found in
163 * /proc/net/unix to speed things up a little. */
165 unix_sockets = set_new(string_hash_func, string_compare_func);
169 f = fopen("/proc/net/unix", "re");
174 if (!fgets(line, sizeof(line), f))
181 if (!fgets(line, sizeof(line), f))
186 p = strchr(line, ':');
194 p += strspn(p, WHITESPACE);
195 p += strcspn(p, WHITESPACE); /* skip one more word */
196 p += strspn(p, WHITESPACE);
205 path_kill_slashes(s);
207 k = set_consume(unix_sockets, s);
208 if (k < 0 && k != -EEXIST)
215 set_free_free(unix_sockets);
219 static bool unix_socket_alive(const char *fn) {
225 return !!set_get(unix_sockets, (char*) fn);
227 /* We don't know, so assume yes */
231 static int dir_is_mount_point(DIR *d, const char *subdir) {
233 union file_handle_union h = {
234 .handle.handle_bytes = MAX_HANDLE_SZ
237 int mount_id_parent, mount_id;
240 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
244 h.handle.handle_bytes = MAX_HANDLE_SZ;
245 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
249 /* got no handle; make no assumptions, return error */
250 if (r_p < 0 && r < 0)
253 /* got both handles; if they differ, it is a mount point */
254 if (r_p >= 0 && r >= 0)
255 return mount_id_parent != mount_id;
257 /* got only one handle; assume different mount points if one
258 * of both queries was not supported by the filesystem */
259 if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
268 static int dir_cleanup(
272 const struct stat *ds,
277 bool keep_this_level) {
280 struct timespec times[2];
281 bool deleted = false;
284 while ((dent = readdir(d))) {
287 _cleanup_free_ char *sub_path = NULL;
289 if (streq(dent->d_name, ".") ||
290 streq(dent->d_name, ".."))
293 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
297 /* FUSE, NFS mounts, SELinux might return EACCES */
299 log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
301 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
306 /* Stay on the same filesystem */
307 if (s.st_dev != rootdev)
310 /* Try to detect bind mounts of the same filesystem instance; they
311 * do not differ in device major/minors. This type of query is not
312 * supported on all kernels or filesystem types though. */
313 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
316 /* Do not delete read-only files owned by root */
317 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
320 sub_path = strjoin(p, "/", dent->d_name, NULL);
326 /* Is there an item configured for this path? */
327 if (hashmap_get(items, sub_path))
330 if (find_glob(globs, sub_path))
333 if (S_ISDIR(s.st_mode)) {
336 streq(dent->d_name, "lost+found") &&
341 log_warning("Reached max depth on %s.", sub_path);
343 _cleanup_closedir_ DIR *sub_dir;
346 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
348 if (errno != ENOENT) {
349 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
356 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
361 /* Note: if you are wondering why we don't
362 * support the sticky bit for excluding
363 * directories from cleaning like we do it for
364 * other file system objects: well, the sticky
365 * bit already has a meaning for directories,
366 * so we don't want to overload that. */
371 /* Ignore ctime, we change it when deleting */
372 age = MAX(timespec_load(&s.st_mtim),
373 timespec_load(&s.st_atim));
377 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
378 log_debug("rmdir '%s'", sub_path);
380 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
381 if (errno != ENOENT && errno != ENOTEMPTY) {
382 log_error("rmdir(%s): %m", sub_path);
389 /* Skip files for which the sticky bit is
390 * set. These are semantics we define, and are
391 * unknown elsewhere. See XDG_RUNTIME_DIR
392 * specification for details. */
393 if (s.st_mode & S_ISVTX)
396 if (mountpoint && S_ISREG(s.st_mode)) {
397 if (streq(dent->d_name, ".journal") &&
401 if (streq(dent->d_name, "aquota.user") ||
402 streq(dent->d_name, "aquota.group"))
406 /* Ignore sockets that are listed in /proc/net/unix */
407 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
410 /* Ignore device nodes */
411 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
414 /* Keep files on this level around if this is
419 age = MAX3(timespec_load(&s.st_mtim),
420 timespec_load(&s.st_atim),
421 timespec_load(&s.st_ctim));
426 log_debug("unlink '%s'", sub_path);
428 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
429 if (errno != ENOENT) {
430 log_error("unlink(%s): %m", sub_path);
441 /* Restore original directory timestamps */
442 times[0] = ds->st_atim;
443 times[1] = ds->st_mtim;
445 if (futimens(dirfd(d), times) < 0)
446 log_error("utimensat(%s): %m", p);
452 static int item_set_perms(Item *i, const char *path) {
456 /* not using i->path directly because it may be a glob */
458 if (chmod(path, i->mode) < 0) {
459 log_error("chmod(%s) failed: %m", path);
463 if (i->uid_set || i->gid_set)
465 i->uid_set ? i->uid : (uid_t) -1,
466 i->gid_set ? i->gid : (gid_t) -1) < 0) {
468 log_error("chown(%s) failed: %m", path);
472 return label_fix(path, false, false);
475 static int write_one_file(Item *i, const char *path) {
484 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
485 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
488 label_context_set(path, S_IFREG);
489 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
490 label_context_clear();
494 if (i->type == WRITE_FILE && errno == ENOENT)
497 log_error("Failed to create file %s: %m", path);
502 _cleanup_free_ char *unescaped;
506 unescaped = cunescape(i->argument);
507 if (unescaped == NULL) {
512 l = strlen(unescaped);
513 n = write(fd, unescaped, l);
515 if (n < 0 || (size_t) n < l) {
516 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
518 return n < 0 ? n : -EIO;
524 if (stat(path, &st) < 0) {
525 log_error("stat(%s) failed: %m", path);
529 if (!S_ISREG(st.st_mode)) {
530 log_error("%s is not a file.", path);
534 r = item_set_perms(i, path);
541 static int item_set_perms_children(Item *i, const char *path) {
542 _cleanup_closedir_ DIR *d;
548 /* This returns the first error we run into, but nevertheless
553 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
556 _cleanup_free_ char *p = NULL;
563 if (errno != 0 && r == 0)
569 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
572 p = strjoin(path, "/", de->d_name, NULL);
576 q = item_set_perms(i, p);
577 if (q < 0 && q != -ENOENT && r == 0)
580 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
581 q = item_set_perms_children(i, p);
590 static int item_set_perms_recursive(Item *i, const char *path) {
596 r = item_set_perms(i, path);
600 q = item_set_perms_children(i, path);
607 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
608 _cleanup_globfree_ glob_t g = {};
613 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
614 if (k != 0 && k != GLOB_NOMATCH) {
618 log_error("glob(%s) failed: %m", i->path);
622 STRV_FOREACH(fn, g.gl_pathv) {
631 static int create_item(Item *i) {
640 case IGNORE_DIRECTORY_PATH:
642 case RECURSIVE_REMOVE_PATH:
647 r = write_one_file(i, i->path);
653 r = copy_tree(i->argument, i->path);
655 log_error("Failed to copy files: %s", strerror(-r));
659 r = item_set_perms(i, i->path);
666 r = glob_item(i, write_one_file);
672 case TRUNCATE_DIRECTORY:
673 case CREATE_DIRECTORY:
675 RUN_WITH_UMASK(0000) {
676 mkdir_parents_label(i->path, 0755);
677 r = mkdir(i->path, i->mode);
680 if (r < 0 && errno != EEXIST) {
681 log_error("Failed to create directory %s: %m", i->path);
685 if (stat(i->path, &st) < 0) {
686 log_error("stat(%s) failed: %m", i->path);
690 if (!S_ISDIR(st.st_mode)) {
691 log_error("%s is not a directory.", i->path);
695 r = item_set_perms(i, i->path);
703 RUN_WITH_UMASK(0000) {
704 r = mkfifo(i->path, i->mode);
707 if (r < 0 && errno != EEXIST) {
708 log_error("Failed to create fifo %s: %m", i->path);
712 if (stat(i->path, &st) < 0) {
713 log_error("stat(%s) failed: %m", i->path);
717 if (!S_ISFIFO(st.st_mode)) {
718 log_error("%s is not a fifo.", i->path);
722 r = item_set_perms(i, i->path);
728 case CREATE_SYMLINK: {
729 _cleanup_free_ char *x = NULL;
731 label_context_set(i->path, S_IFLNK);
732 r = symlink(i->argument, i->path);
733 label_context_clear();
735 if (r < 0 && errno != EEXIST) {
736 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
740 r = readlink_malloc(i->path, &x);
742 log_error("readlink(%s) failed: %s", i->path, strerror(-r));
746 if (!streq(i->argument, x)) {
747 log_error("%s is not the right symlink.", i->path);
754 case CREATE_BLOCK_DEVICE:
755 case CREATE_CHAR_DEVICE: {
758 if (have_effective_cap(CAP_MKNOD) == 0) {
759 /* In a container we lack CAP_MKNOD. We
760 shouldn't attempt to create the device node in
761 that case to avoid noise, and we don't support
762 virtualized devices in containers anyway. */
764 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
768 file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
770 RUN_WITH_UMASK(0000) {
771 label_context_set(i->path, file_type);
772 r = mknod(i->path, i->mode | file_type, i->major_minor);
773 label_context_clear();
776 if (r < 0 && errno != EEXIST) {
777 log_error("Failed to create device node %s: %m", i->path);
781 if (stat(i->path, &st) < 0) {
782 log_error("stat(%s) failed: %m", i->path);
786 if ((st.st_mode & S_IFMT) != file_type) {
787 log_error("%s is not a device node.", i->path);
791 r = item_set_perms(i, i->path);
801 r = glob_item(i, item_set_perms);
806 case RECURSIVE_RELABEL_PATH:
808 r = glob_item(i, item_set_perms_recursive);
815 log_debug("%s created successfully.", i->path);
820 static int remove_item_instance(Item *i, const char *instance) {
829 case CREATE_DIRECTORY:
832 case CREATE_BLOCK_DEVICE:
833 case CREATE_CHAR_DEVICE:
835 case IGNORE_DIRECTORY_PATH:
838 case RECURSIVE_RELABEL_PATH:
844 if (remove(instance) < 0 && errno != ENOENT) {
845 log_error("remove(%s): %m", instance);
851 case TRUNCATE_DIRECTORY:
852 case RECURSIVE_REMOVE_PATH:
853 /* FIXME: we probably should use dir_cleanup() here
854 * instead of rm_rf() so that 'x' is honoured. */
855 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
856 if (r < 0 && r != -ENOENT) {
857 log_error("rm_rf(%s): %s", instance, strerror(-r));
867 static int remove_item(Item *i) {
876 case CREATE_DIRECTORY:
879 case CREATE_CHAR_DEVICE:
880 case CREATE_BLOCK_DEVICE:
882 case IGNORE_DIRECTORY_PATH:
885 case RECURSIVE_RELABEL_PATH:
891 case TRUNCATE_DIRECTORY:
892 case RECURSIVE_REMOVE_PATH:
893 r = glob_item(i, remove_item_instance);
900 static int clean_item_instance(Item *i, const char* instance) {
901 _cleanup_closedir_ DIR *d = NULL;
912 n = now(CLOCK_REALTIME);
918 d = opendir(instance);
920 if (errno == ENOENT || errno == ENOTDIR)
923 log_error("Failed to open directory %s: %m", i->path);
927 if (fstat(dirfd(d), &s) < 0) {
928 log_error("stat(%s) failed: %m", i->path);
932 if (!S_ISDIR(s.st_mode)) {
933 log_error("%s is not a directory.", i->path);
937 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
938 log_error("stat(%s/..) failed: %m", i->path);
942 mountpoint = s.st_dev != ps.st_dev ||
943 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
945 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
946 MAX_DEPTH, i->keep_first_level);
950 static int clean_item(Item *i) {
956 case CREATE_DIRECTORY:
957 case TRUNCATE_DIRECTORY:
960 clean_item_instance(i, i->path);
962 case IGNORE_DIRECTORY_PATH:
963 r = glob_item(i, clean_item_instance);
972 static int process_item(Item *i) {
974 char prefix[PATH_MAX];
983 PATH_FOREACH_PREFIX(prefix, i->path) {
986 j = hashmap_get(items, prefix);
991 r = arg_create ? create_item(i) : 0;
992 q = arg_remove ? remove_item(i) : 0;
993 p = arg_clean ? clean_item(i) : 0;
1004 static void item_free(Item *i) {
1012 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1014 static bool item_equal(Item *a, Item *b) {
1018 if (!streq_ptr(a->path, b->path))
1021 if (a->type != b->type)
1024 if (a->uid_set != b->uid_set ||
1025 (a->uid_set && a->uid != b->uid))
1028 if (a->gid_set != b->gid_set ||
1029 (a->gid_set && a->gid != b->gid))
1032 if (a->mode_set != b->mode_set ||
1033 (a->mode_set && a->mode != b->mode))
1036 if (a->age_set != b->age_set ||
1037 (a->age_set && a->age != b->age))
1040 if ((a->type == CREATE_FILE ||
1041 a->type == TRUNCATE_FILE ||
1042 a->type == WRITE_FILE ||
1043 a->type == CREATE_SYMLINK ||
1044 a->type == COPY_FILES) &&
1045 !streq_ptr(a->argument, b->argument))
1048 if ((a->type == CREATE_CHAR_DEVICE ||
1049 a->type == CREATE_BLOCK_DEVICE) &&
1050 a->major_minor != b->major_minor)
1056 static bool should_include_path(const char *path) {
1059 STRV_FOREACH(prefix, arg_exclude_prefixes) {
1060 if (path_startswith(path, *prefix))
1064 STRV_FOREACH(prefix, arg_include_prefixes) {
1065 if (path_startswith(path, *prefix))
1069 /* no matches, so we should include this path only if we
1070 * have no whitelist at all */
1071 return strv_length(arg_include_prefixes) == 0;
1074 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1076 static const Specifier specifier_table[] = {
1077 { 'm', specifier_machine_id, NULL },
1078 { 'b', specifier_boot_id, NULL },
1079 { 'H', specifier_host_name, NULL },
1080 { 'v', specifier_kernel_release, NULL },
1084 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1085 _cleanup_(item_freep) Item *i = NULL;
1096 "%ms %ms %ms %ms %ms %ms %n",
1105 log_error("[%s:%u] Syntax error.", fname, line);
1109 if (strlen(action) > 2 || (strlen(action) > 1 && action[1] != '!')) {
1110 log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
1112 } else if (strlen(action) > 1 && !arg_boot)
1121 r = specifier_printf(path, specifier_table, NULL, &i->path);
1123 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1128 n += strspn(buffer+n, WHITESPACE);
1129 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1130 i->argument = unquote(buffer+n, "\"");
1140 case CREATE_DIRECTORY:
1141 case TRUNCATE_DIRECTORY:
1144 case IGNORE_DIRECTORY_PATH:
1146 case RECURSIVE_REMOVE_PATH:
1149 case RECURSIVE_RELABEL_PATH:
1152 case CREATE_SYMLINK:
1154 log_error("[%s:%u] Symlink file requires argument.", fname, line);
1162 log_error("[%s:%u] Write file requires argument.", fname, line);
1169 log_error("[%s:%u] Copy files requires argument.", fname, line);
1173 if (!path_is_absolute(i->argument)) {
1174 log_error("[%s:%u] Source path is not absolute.", fname, line);
1178 path_kill_slashes(i->argument);
1181 case CREATE_CHAR_DEVICE:
1182 case CREATE_BLOCK_DEVICE: {
1183 unsigned major, minor;
1186 log_error("[%s:%u] Device file requires argument.", fname, line);
1190 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1191 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1195 i->major_minor = makedev(major, minor);
1200 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1206 if (!path_is_absolute(i->path)) {
1207 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1211 path_kill_slashes(i->path);
1213 if (!should_include_path(i->path))
1219 p = strappend(arg_root, i->path);
1227 if (user && !streq(user, "-")) {
1228 const char *u = user;
1230 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1232 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1239 if (group && !streq(group, "-")) {
1240 const char *g = group;
1242 r = get_group_creds(&g, &i->gid);
1244 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1251 if (mode && !streq(mode, "-")) {
1254 if (sscanf(mode, "%o", &m) != 1) {
1255 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1263 i->type == CREATE_DIRECTORY ||
1264 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1266 if (age && !streq(age, "-")) {
1267 const char *a = age;
1270 i->keep_first_level = true;
1274 if (parse_sec(a, &i->age) < 0) {
1275 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1282 h = needs_glob(i->type) ? globs : items;
1284 existing = hashmap_get(h, i->path);
1287 /* Two identical items are fine */
1288 if (!item_equal(existing, i))
1289 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1294 r = hashmap_put(h, i->path, i);
1296 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1300 i = NULL; /* avoid cleanup */
1305 static int help(void) {
1307 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1308 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1309 " -h --help Show this help\n"
1310 " --version Show package version\n"
1311 " --create Create marked files/directories\n"
1312 " --clean Clean up marked directories\n"
1313 " --remove Remove marked files/directories\n"
1314 " --boot Execute actions only safe at boot\n"
1315 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1316 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1317 " --root=PATH Operate on an alternate filesystem root\n",
1318 program_invocation_short_name);
1323 static int parse_argv(int argc, char *argv[]) {
1326 ARG_VERSION = 0x100,
1336 static const struct option options[] = {
1337 { "help", no_argument, NULL, 'h' },
1338 { "version", no_argument, NULL, ARG_VERSION },
1339 { "create", no_argument, NULL, ARG_CREATE },
1340 { "clean", no_argument, NULL, ARG_CLEAN },
1341 { "remove", no_argument, NULL, ARG_REMOVE },
1342 { "boot", no_argument, NULL, ARG_BOOT },
1343 { "prefix", required_argument, NULL, ARG_PREFIX },
1344 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1345 { "root", required_argument, NULL, ARG_ROOT },
1354 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1362 puts(PACKAGE_STRING);
1363 puts(SYSTEMD_FEATURES);
1383 if (strv_push(&arg_include_prefixes, optarg) < 0)
1387 case ARG_EXCLUDE_PREFIX:
1388 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1393 arg_root = path_make_absolute_cwd(optarg);
1396 path_kill_slashes(arg_root);
1403 assert_not_reached("Unhandled option");
1407 if (!arg_clean && !arg_create && !arg_remove) {
1408 log_error("You need to specify at least one of --clean, --create or --remove.");
1415 static int read_config_file(const char *fn, bool ignore_enoent) {
1416 _cleanup_fclose_ FILE *f = NULL;
1417 char line[LINE_MAX];
1425 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1427 if (ignore_enoent && r == -ENOENT)
1430 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1434 FOREACH_LINE(line, f, break) {
1441 if (*l == '#' || *l == 0)
1444 k = parse_line(fn, v, l);
1445 if (k < 0 && r == 0)
1449 /* we have to determine age parameter for each entry of type X */
1450 HASHMAP_FOREACH(i, globs, iterator) {
1452 Item *j, *candidate_item = NULL;
1454 if (i->type != IGNORE_DIRECTORY_PATH)
1457 HASHMAP_FOREACH(j, items, iter) {
1458 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1461 if (path_equal(j->path, i->path)) {
1466 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1467 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1471 if (candidate_item) {
1472 i->age = candidate_item->age;
1478 log_error("Failed to read from file %s: %m", fn);
1486 int main(int argc, char *argv[]) {
1491 r = parse_argv(argc, argv);
1493 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1495 log_set_target(LOG_TARGET_AUTO);
1496 log_parse_environment();
1503 items = hashmap_new(string_hash_func, string_compare_func);
1504 globs = hashmap_new(string_hash_func, string_compare_func);
1506 if (!items || !globs) {
1513 if (optind < argc) {
1516 for (j = optind; j < argc; j++) {
1517 k = read_config_file(argv[j], false);
1518 if (k < 0 && r == 0)
1523 _cleanup_strv_free_ char **files = NULL;
1526 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1528 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1532 STRV_FOREACH(f, files) {
1533 k = read_config_file(*f, true);
1534 if (k < 0 && r == 0)
1539 HASHMAP_FOREACH(i, globs, iterator)
1542 HASHMAP_FOREACH(i, items, iterator)
1546 while ((i = hashmap_steal_first(items)))
1549 while ((i = hashmap_steal_first(globs)))
1552 hashmap_free(items);
1553 hashmap_free(globs);
1555 free(arg_include_prefixes);
1556 free(arg_exclude_prefixes);
1559 set_free_free(unix_sockets);
1563 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;