1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering, Kay Sievers
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
37 #include <sys/types.h>
38 #include <sys/param.h>
41 #include <sys/capability.h>
48 #include "path-util.h"
52 #include "conf-files.h"
53 #include "capability.h"
54 #include "specifier.h"
58 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
59 * them in the file system. This is intended to be used to create
60 * properly owned directories beneath /tmp, /var/tmp, /run, which are
61 * volatile and hence need to be recreated on bootup. */
63 typedef enum ItemType {
64 /* These ones take file names */
67 CREATE_DIRECTORY = 'd',
68 TRUNCATE_DIRECTORY = 'D',
71 CREATE_CHAR_DEVICE = 'c',
72 CREATE_BLOCK_DEVICE = 'b',
75 /* These ones take globs */
78 IGNORE_DIRECTORY_PATH = 'X',
80 RECURSIVE_REMOVE_PATH = 'R',
81 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
83 RECURSIVE_RELABEL_PATH = 'Z',
104 bool keep_first_level:1;
109 static bool arg_create = false;
110 static bool arg_clean = false;
111 static bool arg_remove = false;
112 static bool arg_boot = false;
114 static char **arg_include_prefixes = NULL;
115 static char **arg_exclude_prefixes = NULL;
116 static char *arg_root = NULL;
118 static const char conf_file_dirs[] =
121 "/usr/local/lib/tmpfiles.d\0"
122 "/usr/lib/tmpfiles.d\0"
123 #ifdef HAVE_SPLIT_USR
128 #define MAX_DEPTH 256
130 static Hashmap *items = NULL, *globs = NULL;
131 static Set *unix_sockets = NULL;
133 static bool needs_glob(ItemType t) {
137 IGNORE_DIRECTORY_PATH,
139 RECURSIVE_REMOVE_PATH,
142 RECURSIVE_RELABEL_PATH);
145 static struct Item* find_glob(Hashmap *h, const char *match) {
149 HASHMAP_FOREACH(j, h, i)
150 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
156 static void load_unix_sockets(void) {
157 _cleanup_fclose_ FILE *f = NULL;
163 /* We maintain a cache of the sockets we found in
164 * /proc/net/unix to speed things up a little. */
166 unix_sockets = set_new(string_hash_func, string_compare_func);
170 f = fopen("/proc/net/unix", "re");
175 if (!fgets(line, sizeof(line), f))
182 if (!fgets(line, sizeof(line), f))
187 p = strchr(line, ':');
195 p += strspn(p, WHITESPACE);
196 p += strcspn(p, WHITESPACE); /* skip one more word */
197 p += strspn(p, WHITESPACE);
206 path_kill_slashes(s);
208 k = set_consume(unix_sockets, s);
209 if (k < 0 && k != -EEXIST)
216 set_free_free(unix_sockets);
220 static bool unix_socket_alive(const char *fn) {
226 return !!set_get(unix_sockets, (char*) fn);
228 /* We don't know, so assume yes */
232 static int dir_is_mount_point(DIR *d, const char *subdir) {
234 union file_handle_union h = {
235 .handle.handle_bytes = MAX_HANDLE_SZ
238 int mount_id_parent, mount_id;
241 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
245 h.handle.handle_bytes = MAX_HANDLE_SZ;
246 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
250 /* got no handle; make no assumptions, return error */
251 if (r_p < 0 && r < 0)
254 /* got both handles; if they differ, it is a mount point */
255 if (r_p >= 0 && r >= 0)
256 return mount_id_parent != mount_id;
258 /* got only one handle; assume different mount points if one
259 * of both queries was not supported by the filesystem */
260 if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
269 static int dir_cleanup(
273 const struct stat *ds,
278 bool keep_this_level) {
281 struct timespec times[2];
282 bool deleted = false;
285 while ((dent = readdir(d))) {
288 _cleanup_free_ char *sub_path = NULL;
290 if (streq(dent->d_name, ".") ||
291 streq(dent->d_name, ".."))
294 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
298 /* FUSE, NFS mounts, SELinux might return EACCES */
300 log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
302 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
307 /* Stay on the same filesystem */
308 if (s.st_dev != rootdev)
311 /* Try to detect bind mounts of the same filesystem instance; they
312 * do not differ in device major/minors. This type of query is not
313 * supported on all kernels or filesystem types though. */
314 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
317 /* Do not delete read-only files owned by root */
318 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
321 sub_path = strjoin(p, "/", dent->d_name, NULL);
327 /* Is there an item configured for this path? */
328 if (hashmap_get(items, sub_path))
331 if (find_glob(globs, sub_path))
334 if (S_ISDIR(s.st_mode)) {
337 streq(dent->d_name, "lost+found") &&
342 log_warning("Reached max depth on %s.", sub_path);
344 _cleanup_closedir_ DIR *sub_dir;
347 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
349 if (errno != ENOENT) {
350 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
357 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
362 /* Note: if you are wondering why we don't
363 * support the sticky bit for excluding
364 * directories from cleaning like we do it for
365 * other file system objects: well, the sticky
366 * bit already has a meaning for directories,
367 * so we don't want to overload that. */
372 /* Ignore ctime, we change it when deleting */
373 age = MAX(timespec_load(&s.st_mtim),
374 timespec_load(&s.st_atim));
378 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
379 log_debug("rmdir '%s'", sub_path);
381 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
382 if (errno != ENOENT && errno != ENOTEMPTY) {
383 log_error("rmdir(%s): %m", sub_path);
390 /* Skip files for which the sticky bit is
391 * set. These are semantics we define, and are
392 * unknown elsewhere. See XDG_RUNTIME_DIR
393 * specification for details. */
394 if (s.st_mode & S_ISVTX)
397 if (mountpoint && S_ISREG(s.st_mode)) {
398 if (streq(dent->d_name, ".journal") &&
402 if (streq(dent->d_name, "aquota.user") ||
403 streq(dent->d_name, "aquota.group"))
407 /* Ignore sockets that are listed in /proc/net/unix */
408 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
411 /* Ignore device nodes */
412 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
415 /* Keep files on this level around if this is
420 age = MAX3(timespec_load(&s.st_mtim),
421 timespec_load(&s.st_atim),
422 timespec_load(&s.st_ctim));
427 log_debug("unlink '%s'", sub_path);
429 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
430 if (errno != ENOENT) {
431 log_error("unlink(%s): %m", sub_path);
442 /* Restore original directory timestamps */
443 times[0] = ds->st_atim;
444 times[1] = ds->st_mtim;
446 if (futimens(dirfd(d), times) < 0)
447 log_error("utimensat(%s): %m", p);
453 static int item_set_perms(Item *i, const char *path) {
457 /* not using i->path directly because it may be a glob */
464 if (stat(path, &st) >= 0) {
465 if (!(st.st_mode & 0111))
467 if (!(st.st_mode & 0222))
469 if (!(st.st_mode & 0444))
471 if (!S_ISDIR(st.st_mode))
472 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
476 if (chmod(path, m) < 0) {
477 log_error("chmod(%s) failed: %m", path);
482 if (i->uid_set || i->gid_set)
484 i->uid_set ? i->uid : (uid_t) -1,
485 i->gid_set ? i->gid : (gid_t) -1) < 0) {
487 log_error("chown(%s) failed: %m", path);
491 return label_fix(path, false, false);
494 static int write_one_file(Item *i, const char *path) {
503 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
504 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
507 label_context_set(path, S_IFREG);
508 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
509 label_context_clear();
513 if (i->type == WRITE_FILE && errno == ENOENT)
516 log_error("Failed to create file %s: %m", path);
521 _cleanup_free_ char *unescaped;
525 unescaped = cunescape(i->argument);
526 if (unescaped == NULL) {
531 l = strlen(unescaped);
532 n = write(fd, unescaped, l);
534 if (n < 0 || (size_t) n < l) {
535 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
537 return n < 0 ? n : -EIO;
543 if (stat(path, &st) < 0) {
544 log_error("stat(%s) failed: %m", path);
548 if (!S_ISREG(st.st_mode)) {
549 log_error("%s is not a file.", path);
553 r = item_set_perms(i, path);
560 static int item_set_perms_children(Item *i, const char *path) {
561 _cleanup_closedir_ DIR *d;
567 /* This returns the first error we run into, but nevertheless
572 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
575 _cleanup_free_ char *p = NULL;
582 if (errno != 0 && r == 0)
588 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
591 p = strjoin(path, "/", de->d_name, NULL);
595 q = item_set_perms(i, p);
596 if (q < 0 && q != -ENOENT && r == 0)
599 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
600 q = item_set_perms_children(i, p);
609 static int item_set_perms_recursive(Item *i, const char *path) {
615 r = item_set_perms(i, path);
619 q = item_set_perms_children(i, path);
626 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
627 _cleanup_globfree_ glob_t g = {};
632 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
633 if (k != 0 && k != GLOB_NOMATCH) {
637 log_error("glob(%s) failed: %m", i->path);
641 STRV_FOREACH(fn, g.gl_pathv) {
650 static int create_item(Item *i) {
659 case IGNORE_DIRECTORY_PATH:
661 case RECURSIVE_REMOVE_PATH:
666 r = write_one_file(i, i->path);
672 r = copy_tree(i->argument, i->path);
674 log_error("Failed to copy files: %s", strerror(-r));
678 r = item_set_perms(i, i->path);
685 r = glob_item(i, write_one_file);
691 case TRUNCATE_DIRECTORY:
692 case CREATE_DIRECTORY:
694 RUN_WITH_UMASK(0000) {
695 mkdir_parents_label(i->path, 0755);
696 r = mkdir(i->path, i->mode);
699 if (r < 0 && errno != EEXIST) {
700 log_error("Failed to create directory %s: %m", i->path);
704 if (stat(i->path, &st) < 0) {
705 log_error("stat(%s) failed: %m", i->path);
709 if (!S_ISDIR(st.st_mode)) {
710 log_error("%s is not a directory.", i->path);
714 r = item_set_perms(i, i->path);
722 label_context_set(i->path, S_IFIFO);
723 RUN_WITH_UMASK(0000) {
724 r = mkfifo(i->path, i->mode);
726 label_context_clear();
728 if (r < 0 && errno != EEXIST) {
729 log_error("Failed to create fifo %s: %m", i->path);
733 if (stat(i->path, &st) < 0) {
734 log_error("stat(%s) failed: %m", i->path);
738 if (!S_ISFIFO(st.st_mode)) {
739 log_error("%s is not a fifo.", i->path);
743 r = item_set_perms(i, i->path);
749 case CREATE_SYMLINK: {
750 _cleanup_free_ char *x = NULL;
752 label_context_set(i->path, S_IFLNK);
753 r = symlink(i->argument, i->path);
754 label_context_clear();
756 if (r < 0 && errno != EEXIST) {
757 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
761 r = readlink_malloc(i->path, &x);
763 log_error("readlink(%s) failed: %s", i->path, strerror(-r));
767 if (!streq(i->argument, x)) {
768 log_error("%s is not the right symlink.", i->path);
775 case CREATE_BLOCK_DEVICE:
776 case CREATE_CHAR_DEVICE: {
779 if (have_effective_cap(CAP_MKNOD) == 0) {
780 /* In a container we lack CAP_MKNOD. We
781 shouldn't attempt to create the device node in
782 that case to avoid noise, and we don't support
783 virtualized devices in containers anyway. */
785 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
789 file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
791 RUN_WITH_UMASK(0000) {
792 label_context_set(i->path, file_type);
793 r = mknod(i->path, i->mode | file_type, i->major_minor);
794 label_context_clear();
798 if (errno == EPERM) {
799 log_debug("We lack permissions, possibly because of cgroup configuration; "
800 "skipping creation of device node %s.", i->path);
804 if (errno != EEXIST) {
805 log_error("Failed to create device node %s: %m", i->path);
810 if (stat(i->path, &st) < 0) {
811 log_error("stat(%s) failed: %m", i->path);
815 if ((st.st_mode & S_IFMT) != file_type) {
816 log_error("%s is not a device node.", i->path);
820 r = item_set_perms(i, i->path);
830 r = glob_item(i, item_set_perms);
835 case RECURSIVE_RELABEL_PATH:
837 r = glob_item(i, item_set_perms_recursive);
844 log_debug("%s created successfully.", i->path);
849 static int remove_item_instance(Item *i, const char *instance) {
858 case CREATE_DIRECTORY:
861 case CREATE_BLOCK_DEVICE:
862 case CREATE_CHAR_DEVICE:
864 case IGNORE_DIRECTORY_PATH:
867 case RECURSIVE_RELABEL_PATH:
873 if (remove(instance) < 0 && errno != ENOENT) {
874 log_error("remove(%s): %m", instance);
880 case TRUNCATE_DIRECTORY:
881 case RECURSIVE_REMOVE_PATH:
882 /* FIXME: we probably should use dir_cleanup() here
883 * instead of rm_rf() so that 'x' is honoured. */
884 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
885 if (r < 0 && r != -ENOENT) {
886 log_error("rm_rf(%s): %s", instance, strerror(-r));
896 static int remove_item(Item *i) {
905 case CREATE_DIRECTORY:
908 case CREATE_CHAR_DEVICE:
909 case CREATE_BLOCK_DEVICE:
911 case IGNORE_DIRECTORY_PATH:
914 case RECURSIVE_RELABEL_PATH:
920 case TRUNCATE_DIRECTORY:
921 case RECURSIVE_REMOVE_PATH:
922 r = glob_item(i, remove_item_instance);
929 static int clean_item_instance(Item *i, const char* instance) {
930 _cleanup_closedir_ DIR *d = NULL;
941 n = now(CLOCK_REALTIME);
947 d = opendir(instance);
949 if (errno == ENOENT || errno == ENOTDIR)
952 log_error("Failed to open directory %s: %m", i->path);
956 if (fstat(dirfd(d), &s) < 0) {
957 log_error("stat(%s) failed: %m", i->path);
961 if (!S_ISDIR(s.st_mode)) {
962 log_error("%s is not a directory.", i->path);
966 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
967 log_error("stat(%s/..) failed: %m", i->path);
971 mountpoint = s.st_dev != ps.st_dev ||
972 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
974 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
975 MAX_DEPTH, i->keep_first_level);
979 static int clean_item(Item *i) {
985 case CREATE_DIRECTORY:
986 case TRUNCATE_DIRECTORY:
989 clean_item_instance(i, i->path);
991 case IGNORE_DIRECTORY_PATH:
992 r = glob_item(i, clean_item_instance);
1001 static int process_item(Item *i) {
1003 char prefix[PATH_MAX];
1012 PATH_FOREACH_PREFIX(prefix, i->path) {
1015 j = hashmap_get(items, prefix);
1020 r = arg_create ? create_item(i) : 0;
1021 q = arg_remove ? remove_item(i) : 0;
1022 p = arg_clean ? clean_item(i) : 0;
1033 static void item_free(Item *i) {
1043 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1045 static bool item_equal(Item *a, Item *b) {
1049 if (!streq_ptr(a->path, b->path))
1052 if (a->type != b->type)
1055 if (a->uid_set != b->uid_set ||
1056 (a->uid_set && a->uid != b->uid))
1059 if (a->gid_set != b->gid_set ||
1060 (a->gid_set && a->gid != b->gid))
1063 if (a->mode_set != b->mode_set ||
1064 (a->mode_set && a->mode != b->mode))
1067 if (a->age_set != b->age_set ||
1068 (a->age_set && a->age != b->age))
1071 if ((a->type == CREATE_FILE ||
1072 a->type == TRUNCATE_FILE ||
1073 a->type == WRITE_FILE ||
1074 a->type == CREATE_SYMLINK ||
1075 a->type == COPY_FILES) &&
1076 !streq_ptr(a->argument, b->argument))
1079 if ((a->type == CREATE_CHAR_DEVICE ||
1080 a->type == CREATE_BLOCK_DEVICE) &&
1081 a->major_minor != b->major_minor)
1087 static bool should_include_path(const char *path) {
1090 STRV_FOREACH(prefix, arg_exclude_prefixes)
1091 if (path_startswith(path, *prefix))
1094 STRV_FOREACH(prefix, arg_include_prefixes)
1095 if (path_startswith(path, *prefix))
1098 /* no matches, so we should include this path only if we
1099 * have no whitelist at all */
1100 return strv_length(arg_include_prefixes) == 0;
1103 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1105 static const Specifier specifier_table[] = {
1106 { 'm', specifier_machine_id, NULL },
1107 { 'b', specifier_boot_id, NULL },
1108 { 'H', specifier_host_name, NULL },
1109 { 'v', specifier_kernel_release, NULL },
1113 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1114 _cleanup_(item_freep) Item *i = NULL;
1125 "%ms %ms %ms %ms %ms %ms %n",
1134 log_error("[%s:%u] Syntax error.", fname, line);
1138 if (strlen(action) > 2 || (strlen(action) > 1 && action[1] != '!')) {
1139 log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
1141 } else if (strlen(action) > 1 && !arg_boot)
1150 r = specifier_printf(path, specifier_table, NULL, &i->path);
1152 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1157 n += strspn(buffer+n, WHITESPACE);
1158 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1159 i->argument = unquote(buffer+n, "\"");
1169 case CREATE_DIRECTORY:
1170 case TRUNCATE_DIRECTORY:
1173 case IGNORE_DIRECTORY_PATH:
1175 case RECURSIVE_REMOVE_PATH:
1178 case RECURSIVE_RELABEL_PATH:
1181 case CREATE_SYMLINK:
1183 log_error("[%s:%u] Symlink file requires argument.", fname, line);
1191 log_error("[%s:%u] Write file requires argument.", fname, line);
1198 log_error("[%s:%u] Copy files requires argument.", fname, line);
1202 if (!path_is_absolute(i->argument)) {
1203 log_error("[%s:%u] Source path is not absolute.", fname, line);
1207 path_kill_slashes(i->argument);
1210 case CREATE_CHAR_DEVICE:
1211 case CREATE_BLOCK_DEVICE: {
1212 unsigned major, minor;
1215 log_error("[%s:%u] Device file requires argument.", fname, line);
1219 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1220 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1224 i->major_minor = makedev(major, minor);
1229 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1235 if (!path_is_absolute(i->path)) {
1236 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1240 path_kill_slashes(i->path);
1242 if (!should_include_path(i->path))
1248 p = strappend(arg_root, i->path);
1256 if (user && !streq(user, "-")) {
1257 const char *u = user;
1259 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1261 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1268 if (group && !streq(group, "-")) {
1269 const char *g = group;
1271 r = get_group_creds(&g, &i->gid);
1273 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1280 if (mode && !streq(mode, "-")) {
1281 const char *mm = mode;
1285 i->mask_perms = true;
1289 if (sscanf(mm, "%o", &m) != 1) {
1290 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1298 i->type == CREATE_DIRECTORY ||
1299 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1301 if (age && !streq(age, "-")) {
1302 const char *a = age;
1305 i->keep_first_level = true;
1309 if (parse_sec(a, &i->age) < 0) {
1310 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1317 h = needs_glob(i->type) ? globs : items;
1319 existing = hashmap_get(h, i->path);
1322 /* Two identical items are fine */
1323 if (!item_equal(existing, i))
1324 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1329 r = hashmap_put(h, i->path, i);
1331 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1335 i = NULL; /* avoid cleanup */
1340 static int help(void) {
1342 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1343 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1344 " -h --help Show this help\n"
1345 " --version Show package version\n"
1346 " --create Create marked files/directories\n"
1347 " --clean Clean up marked directories\n"
1348 " --remove Remove marked files/directories\n"
1349 " --boot Execute actions only safe at boot\n"
1350 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1351 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1352 " --root=PATH Operate on an alternate filesystem root\n",
1353 program_invocation_short_name);
1358 static int parse_argv(int argc, char *argv[]) {
1361 ARG_VERSION = 0x100,
1371 static const struct option options[] = {
1372 { "help", no_argument, NULL, 'h' },
1373 { "version", no_argument, NULL, ARG_VERSION },
1374 { "create", no_argument, NULL, ARG_CREATE },
1375 { "clean", no_argument, NULL, ARG_CLEAN },
1376 { "remove", no_argument, NULL, ARG_REMOVE },
1377 { "boot", no_argument, NULL, ARG_BOOT },
1378 { "prefix", required_argument, NULL, ARG_PREFIX },
1379 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1380 { "root", required_argument, NULL, ARG_ROOT },
1389 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1397 puts(PACKAGE_STRING);
1398 puts(SYSTEMD_FEATURES);
1418 if (strv_push(&arg_include_prefixes, optarg) < 0)
1422 case ARG_EXCLUDE_PREFIX:
1423 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1429 arg_root = path_make_absolute_cwd(optarg);
1433 path_kill_slashes(arg_root);
1440 assert_not_reached("Unhandled option");
1444 if (!arg_clean && !arg_create && !arg_remove) {
1445 log_error("You need to specify at least one of --clean, --create or --remove.");
1452 static int read_config_file(const char *fn, bool ignore_enoent) {
1453 _cleanup_fclose_ FILE *f = NULL;
1454 char line[LINE_MAX];
1462 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1464 if (ignore_enoent && r == -ENOENT)
1467 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1471 FOREACH_LINE(line, f, break) {
1478 if (*l == '#' || *l == 0)
1481 k = parse_line(fn, v, l);
1482 if (k < 0 && r == 0)
1486 /* we have to determine age parameter for each entry of type X */
1487 HASHMAP_FOREACH(i, globs, iterator) {
1489 Item *j, *candidate_item = NULL;
1491 if (i->type != IGNORE_DIRECTORY_PATH)
1494 HASHMAP_FOREACH(j, items, iter) {
1495 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1498 if (path_equal(j->path, i->path)) {
1503 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1504 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1508 if (candidate_item) {
1509 i->age = candidate_item->age;
1515 log_error("Failed to read from file %s: %m", fn);
1523 int main(int argc, char *argv[]) {
1528 r = parse_argv(argc, argv);
1532 log_set_target(LOG_TARGET_AUTO);
1533 log_parse_environment();
1540 items = hashmap_new(string_hash_func, string_compare_func);
1541 globs = hashmap_new(string_hash_func, string_compare_func);
1543 if (!items || !globs) {
1550 if (optind < argc) {
1553 for (j = optind; j < argc; j++) {
1554 k = read_config_file(argv[j], false);
1555 if (k < 0 && r == 0)
1560 _cleanup_strv_free_ char **files = NULL;
1563 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1565 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1569 STRV_FOREACH(f, files) {
1570 k = read_config_file(*f, true);
1571 if (k < 0 && r == 0)
1576 HASHMAP_FOREACH(i, globs, iterator)
1579 HASHMAP_FOREACH(i, items, iterator)
1583 while ((i = hashmap_steal_first(items)))
1586 while ((i = hashmap_steal_first(globs)))
1589 hashmap_free(items);
1590 hashmap_free(globs);
1592 free(arg_include_prefixes);
1593 free(arg_exclude_prefixes);
1596 set_free_free(unix_sockets);
1600 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;