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>
45 #include "path-util.h"
49 #include "conf-files.h"
51 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
52 * them in the file system. This is intended to be used to create
53 * properly owned directories beneath /tmp, /var/tmp, /run, which are
54 * volatile and hence need to be recreated on bootup. */
56 typedef enum ItemType
{
57 /* These ones take file names */
61 CREATE_DIRECTORY
= 'd',
62 TRUNCATE_DIRECTORY
= 'D',
65 CREATE_CHAR_DEVICE
= 'c',
66 CREATE_BLOCK_DEVICE
= 'b',
68 /* These ones take globs */
71 RECURSIVE_REMOVE_PATH
= 'R',
73 RECURSIVE_RELABEL_PATH
= 'Z'
93 bool keep_first_level
:1;
96 static Hashmap
*items
= NULL
, *globs
= NULL
;
97 static Set
*unix_sockets
= NULL
;
99 static bool arg_create
= false;
100 static bool arg_clean
= false;
101 static bool arg_remove
= false;
103 static const char *arg_prefix
= NULL
;
105 static const char * const conf_file_dirs
[] = {
108 "/usr/local/lib/tmpfiles.d",
109 "/usr/lib/tmpfiles.d",
110 #ifdef HAVE_SPLIT_USR
116 #define MAX_DEPTH 256
118 static bool needs_glob(ItemType t
) {
119 return t
== IGNORE_PATH
|| t
== REMOVE_PATH
|| t
== RECURSIVE_REMOVE_PATH
|| t
== RELABEL_PATH
|| t
== RECURSIVE_RELABEL_PATH
;
122 static struct Item
* find_glob(Hashmap
*h
, const char *match
) {
126 HASHMAP_FOREACH(j
, h
, i
)
127 if (fnmatch(j
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
133 static void load_unix_sockets(void) {
140 /* We maintain a cache of the sockets we found in
141 * /proc/net/unix to speed things up a little. */
143 unix_sockets
= set_new(string_hash_func
, string_compare_func
);
147 f
= fopen("/proc/net/unix", "re");
152 if (!fgets(line
, sizeof(line
), f
))
159 if (!fgets(line
, sizeof(line
), f
))
164 p
= strchr(line
, ':');
172 p
+= strspn(p
, WHITESPACE
);
173 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
174 p
+= strspn(p
, WHITESPACE
);
183 path_kill_slashes(s
);
185 k
= set_put(unix_sockets
, s
);
198 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_cleanup(
220 const struct stat
*ds
,
225 bool keep_this_level
)
228 struct timespec times
[2];
229 bool deleted
= false;
230 char *sub_path
= NULL
;
233 while ((dent
= readdir(d
))) {
237 if (streq(dent
->d_name
, ".") ||
238 streq(dent
->d_name
, ".."))
241 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
243 if (errno
!= ENOENT
) {
244 log_error("stat(%s/%s) failed: %m", p
, dent
->d_name
);
251 /* Stay on the same filesystem */
252 if (s
.st_dev
!= rootdev
)
255 /* Do not delete read-only files owned by root */
256 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
))
262 if (asprintf(&sub_path
, "%s/%s", p
, dent
->d_name
) < 0) {
267 /* Is there an item configured for this path? */
268 if (hashmap_get(items
, sub_path
))
271 if (find_glob(globs
, sub_path
))
274 if (S_ISDIR(s
.st_mode
)) {
277 streq(dent
->d_name
, "lost+found") &&
282 log_warning("Reached max depth on %s.", sub_path
);
287 sub_dir
= xopendirat(dirfd(d
), dent
->d_name
, O_NOFOLLOW
|O_NOATIME
);
288 if (sub_dir
== NULL
) {
289 if (errno
!= ENOENT
) {
290 log_error("opendir(%s/%s) failed: %m", p
, dent
->d_name
);
297 q
= dir_cleanup(sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
304 /* Note: if you are wondering why we don't
305 * support the sticky bit for excluding
306 * directories from cleaning like we do it for
307 * other file system objects: well, the sticky
308 * bit already has a meaning for directories,
309 * so we don't want to overload that. */
314 /* Ignore ctime, we change it when deleting */
315 age
= MAX(timespec_load(&s
.st_mtim
),
316 timespec_load(&s
.st_atim
));
320 log_debug("rmdir '%s'\n", sub_path
);
322 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0) {
323 if (errno
!= ENOENT
&& errno
!= ENOTEMPTY
) {
324 log_error("rmdir(%s): %m", sub_path
);
330 /* Skip files for which the sticky bit is
331 * set. These are semantics we define, and are
332 * unknown elsewhere. See XDG_RUNTIME_DIR
333 * specification for details. */
334 if (s
.st_mode
& S_ISVTX
)
337 if (mountpoint
&& S_ISREG(s
.st_mode
)) {
338 if (streq(dent
->d_name
, ".journal") &&
342 if (streq(dent
->d_name
, "aquota.user") ||
343 streq(dent
->d_name
, "aquota.group"))
347 /* Ignore sockets that are listed in /proc/net/unix */
348 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
))
351 /* Ignore device nodes */
352 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
))
355 /* Keep files on this level around if this is
360 age
= MAX3(timespec_load(&s
.st_mtim
),
361 timespec_load(&s
.st_atim
),
362 timespec_load(&s
.st_ctim
));
367 log_debug("unlink '%s'\n", sub_path
);
369 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0) {
370 if (errno
!= ENOENT
) {
371 log_error("unlink(%s): %m", sub_path
);
382 /* Restore original directory timestamps */
383 times
[0] = ds
->st_atim
;
384 times
[1] = ds
->st_mtim
;
386 if (futimens(dirfd(d
), times
) < 0)
387 log_error("utimensat(%s): %m", p
);
395 static int clean_item(Item
*i
) {
404 if (i
->type
!= CREATE_DIRECTORY
&&
405 i
->type
!= TRUNCATE_DIRECTORY
&&
406 i
->type
!= IGNORE_PATH
)
409 if (!i
->age_set
|| i
->age
<= 0)
412 n
= now(CLOCK_REALTIME
);
418 d
= opendir(i
->path
);
423 log_error("Failed to open directory %s: %m", i
->path
);
427 if (fstat(dirfd(d
), &s
) < 0) {
428 log_error("stat(%s) failed: %m", i
->path
);
433 if (!S_ISDIR(s
.st_mode
)) {
434 log_error("%s is not a directory.", i
->path
);
439 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0) {
440 log_error("stat(%s/..) failed: %m", i
->path
);
445 mountpoint
= s
.st_dev
!= ps
.st_dev
||
446 (s
.st_dev
== ps
.st_dev
&& s
.st_ino
== ps
.st_ino
);
448 r
= dir_cleanup(i
->path
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
, MAX_DEPTH
, i
->keep_first_level
);
457 static int item_set_perms(Item
*i
, const char *path
) {
458 /* not using i->path directly because it may be a glob */
460 if (chmod(path
, i
->mode
) < 0) {
461 log_error("chmod(%s) failed: %m", path
);
465 if (i
->uid_set
|| i
->gid_set
)
467 i
->uid_set
? i
->uid
: (uid_t
) -1,
468 i
->gid_set
? i
->gid
: (gid_t
) -1) < 0) {
470 log_error("chown(%s) failed: %m", path
);
474 return label_fix(path
, false, false);
477 static int recursive_relabel_children(Item
*i
, const char *path
) {
481 /* This returns the first error we run into, but nevertheless
486 return errno
== ENOENT
? 0 : -errno
;
489 struct dirent buf
, *de
;
494 r
= readdir_r(d
, &buf
, &de
);
504 if (streq(de
->d_name
, ".") || streq(de
->d_name
, ".."))
507 if (asprintf(&entry_path
, "%s/%s", path
, de
->d_name
) < 0) {
513 if (de
->d_type
== DT_UNKNOWN
) {
516 if (lstat(entry_path
, &st
) < 0) {
517 if (ret
== 0 && errno
!= ENOENT
)
523 is_dir
= S_ISDIR(st
.st_mode
);
526 is_dir
= de
->d_type
== DT_DIR
;
528 r
= item_set_perms(i
, entry_path
);
530 if (ret
== 0 && r
!= -ENOENT
)
537 r
= recursive_relabel_children(i
, entry_path
);
538 if (r
< 0 && ret
== 0)
550 static int recursive_relabel(Item
*i
, const char *path
) {
554 r
= item_set_perms(i
, path
);
558 if (lstat(path
, &st
) < 0)
561 if (S_ISDIR(st
.st_mode
))
562 r
= recursive_relabel_children(i
, path
);
567 static int glob_item(Item
*i
, int (*action
)(Item
*, const char *)) {
575 if ((k
= glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
, NULL
, &g
)) != 0) {
577 if (k
!= GLOB_NOMATCH
) {
581 log_error("glob(%s) failed: %m", i
->path
);
586 STRV_FOREACH(fn
, g
.gl_pathv
)
587 if ((k
= action(i
, *fn
)) < 0)
594 static int create_item(Item
*i
) {
605 case RECURSIVE_REMOVE_PATH
:
613 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
:
614 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
: 0;
617 label_context_set(i
->path
, S_IFREG
);
618 fd
= open(i
->path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
|O_NOFOLLOW
, i
->mode
);
620 label_context_clear();
625 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
)
628 log_error("Failed to create file %s: %m", i
->path
);
635 struct iovec iovec
[2];
636 static const char new_line
= '\n';
638 l
= strlen(i
->argument
);
641 iovec
[0].iov_base
= i
->argument
;
642 iovec
[0].iov_len
= l
;
644 iovec
[1].iov_base
= (void*) &new_line
;
645 iovec
[1].iov_len
= 1;
647 n
= writev(fd
, iovec
, 2);
649 /* It's OK if we don't write the trailing
650 * newline, hence we check for l, instead of
651 * l+1 here. Files in /sys often refuse
652 * writing of the trailing newline. */
653 if (n
< 0 || (size_t) n
< l
) {
654 log_error("Failed to write file %s: %s", i
->path
, n
< 0 ? strerror(-n
) : "Short write");
655 close_nointr_nofail(fd
);
656 return n
< 0 ? n
: -EIO
;
660 close_nointr_nofail(fd
);
662 if (stat(i
->path
, &st
) < 0) {
663 log_error("stat(%s) failed: %m", i
->path
);
667 if (!S_ISREG(st
.st_mode
)) {
668 log_error("%s is not a file.", i
->path
);
672 r
= item_set_perms(i
, i
->path
);
679 case TRUNCATE_DIRECTORY
:
680 case CREATE_DIRECTORY
:
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
);
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
: {
767 mode_t file_type
= (i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
);
770 label_context_set(i
->path
, file_type
);
771 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
773 label_context_clear();
777 if (r
< 0 && errno
!= EEXIST
) {
778 log_error("Failed to create device node %s: %m", i
->path
);
782 if (stat(i
->path
, &st
) < 0) {
783 log_error("stat(%s) failed: %m", i
->path
);
787 if ((st
.st_mode
& S_IFMT
) != file_type
) {
788 log_error("%s is not a device node.", i
->path
);
792 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
, recursive_relabel
);
813 log_debug("%s created successfully.", i
->path
);
818 static int remove_item_instance(Item
*i
, const char *instance
) {
827 case CREATE_DIRECTORY
:
830 case CREATE_BLOCK_DEVICE
:
831 case CREATE_CHAR_DEVICE
:
834 case RECURSIVE_RELABEL_PATH
:
839 if (remove(instance
) < 0 && errno
!= ENOENT
) {
840 log_error("remove(%s): %m", instance
);
846 case TRUNCATE_DIRECTORY
:
847 case RECURSIVE_REMOVE_PATH
:
848 /* FIXME: we probably should use dir_cleanup() here
849 * instead of rm_rf() so that 'x' is honoured. */
850 r
= rm_rf_dangerous(instance
, false, i
->type
== RECURSIVE_REMOVE_PATH
, false);
851 if (r
< 0 && r
!= -ENOENT
) {
852 log_error("rm_rf(%s): %s", instance
, strerror(-r
));
862 static int remove_item(Item
*i
) {
871 case CREATE_DIRECTORY
:
874 case CREATE_CHAR_DEVICE
:
875 case CREATE_BLOCK_DEVICE
:
878 case RECURSIVE_RELABEL_PATH
:
883 case TRUNCATE_DIRECTORY
:
884 case RECURSIVE_REMOVE_PATH
:
885 r
= glob_item(i
, remove_item_instance
);
892 static int process_item(Item
*i
) {
897 r
= arg_create
? create_item(i
) : 0;
898 q
= arg_remove
? remove_item(i
) : 0;
899 p
= arg_clean
? clean_item(i
) : 0;
910 static void item_free(Item
*i
) {
918 static bool item_equal(Item
*a
, Item
*b
) {
922 if (!streq_ptr(a
->path
, b
->path
))
925 if (a
->type
!= b
->type
)
928 if (a
->uid_set
!= b
->uid_set
||
929 (a
->uid_set
&& a
->uid
!= b
->uid
))
932 if (a
->gid_set
!= b
->gid_set
||
933 (a
->gid_set
&& a
->gid
!= b
->gid
))
936 if (a
->mode_set
!= b
->mode_set
||
937 (a
->mode_set
&& a
->mode
!= b
->mode
))
940 if (a
->age_set
!= b
->age_set
||
941 (a
->age_set
&& a
->age
!= b
->age
))
944 if ((a
->type
== CREATE_FILE
||
945 a
->type
== TRUNCATE_FILE
||
946 a
->type
== WRITE_FILE
||
947 a
->type
== CREATE_SYMLINK
) &&
948 !streq_ptr(a
->argument
, b
->argument
))
951 if ((a
->type
== CREATE_CHAR_DEVICE
||
952 a
->type
== CREATE_BLOCK_DEVICE
) &&
953 a
->major_minor
!= b
->major_minor
)
959 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
961 char *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
;
989 log_error("[%s:%u] Syntax error.", fname
, line
);
995 n
+= strspn(buffer
+n
, WHITESPACE
);
996 if (buffer
[n
] != 0 && (buffer
[n
] != '-' || buffer
[n
+1] != 0)) {
997 i
->argument
= unquote(buffer
+n
, "\"");
1007 case CREATE_DIRECTORY
:
1008 case TRUNCATE_DIRECTORY
:
1012 case RECURSIVE_REMOVE_PATH
:
1014 case RECURSIVE_RELABEL_PATH
:
1017 case CREATE_SYMLINK
:
1019 log_error("[%s:%u] Symlink file requires argument.", fname
, line
);
1027 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1033 case CREATE_CHAR_DEVICE
:
1034 case CREATE_BLOCK_DEVICE
: {
1035 unsigned major
, minor
;
1038 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1043 if (sscanf(i
->argument
, "%u:%u", &major
, &minor
) != 2) {
1044 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
->argument
);
1049 i
->major_minor
= makedev(major
, minor
);
1054 log_error("[%s:%u] Unknown file type '%c'.", fname
, line
, type
);
1061 if (!path_is_absolute(i
->path
)) {
1062 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
->path
);
1067 path_kill_slashes(i
->path
);
1069 if (arg_prefix
&& !path_startswith(i
->path
, arg_prefix
)) {
1074 if (user
&& !streq(user
, "-")) {
1075 const char *u
= user
;
1077 r
= get_user_creds(&u
, &i
->uid
, NULL
, NULL
, NULL
);
1079 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
1086 if (group
&& !streq(group
, "-")) {
1087 const char *g
= group
;
1089 r
= get_group_creds(&g
, &i
->gid
);
1091 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
1098 if (mode
&& !streq(mode
, "-")) {
1101 if (sscanf(mode
, "%o", &m
) != 1) {
1102 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
1111 i
->type
== CREATE_DIRECTORY
||
1112 i
->type
== TRUNCATE_DIRECTORY
? 0755 : 0644;
1114 if (age
&& !streq(age
, "-")) {
1115 const char *a
= age
;
1118 i
->keep_first_level
= true;
1122 if (parse_usec(a
, &i
->age
) < 0) {
1123 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
1131 h
= needs_glob(i
->type
) ? globs
: items
;
1133 existing
= hashmap_get(h
, i
->path
);
1136 /* Two identical items are fine */
1137 if (!item_equal(existing
, i
))
1138 log_warning("Two or more conflicting lines for %s configured, ignoring.", i
->path
);
1144 r
= hashmap_put(h
, i
->path
, i
);
1146 log_error("Failed to insert item %s: %s", i
->path
, strerror(-r
));
1165 static int help(void) {
1167 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1168 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1169 " -h --help Show this help\n"
1170 " --create Create marked files/directories\n"
1171 " --clean Clean up marked directories\n"
1172 " --remove Remove marked files/directories\n"
1173 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n",
1174 program_invocation_short_name
);
1179 static int parse_argv(int argc
, char *argv
[]) {
1188 static const struct option options
[] = {
1189 { "help", no_argument
, NULL
, 'h' },
1190 { "create", no_argument
, NULL
, ARG_CREATE
},
1191 { "clean", no_argument
, NULL
, ARG_CLEAN
},
1192 { "remove", no_argument
, NULL
, ARG_REMOVE
},
1193 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
1194 { NULL
, 0, NULL
, 0 }
1202 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0) {
1223 arg_prefix
= optarg
;
1230 log_error("Unknown option code %c", c
);
1235 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
1236 log_error("You need to specify at least one of --clean, --create or --remove.");
1243 static int read_config_file(const char *fn
, bool ignore_enoent
) {
1250 f
= fopen(fn
, "re");
1253 if (ignore_enoent
&& errno
== ENOENT
)
1256 log_error("Failed to open %s: %m", fn
);
1260 log_debug("apply: %s\n", fn
);
1262 char line
[LINE_MAX
], *l
;
1265 if (!(fgets(line
, sizeof(line
), f
)))
1271 if (*l
== '#' || *l
== 0)
1274 if ((k
= parse_line(fn
, v
, l
)) < 0)
1280 log_error("Failed to read from file %s: %m", fn
);
1290 static char *resolve_fragment(const char *fragment
, const char **search_paths
) {
1292 char *resolved_path
;
1294 if (is_path(fragment
))
1295 return strdup(fragment
);
1297 STRV_FOREACH(p
, search_paths
) {
1298 resolved_path
= strjoin(*p
, "/", fragment
, NULL
);
1299 if (resolved_path
== NULL
) {
1304 if (access(resolved_path
, F_OK
) == 0)
1305 return resolved_path
;
1307 free(resolved_path
);
1314 int main(int argc
, char *argv
[]) {
1319 r
= parse_argv(argc
, argv
);
1321 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;
1323 log_set_target(LOG_TARGET_AUTO
);
1324 log_parse_environment();
1331 items
= hashmap_new(string_hash_func
, string_compare_func
);
1332 globs
= hashmap_new(string_hash_func
, string_compare_func
);
1334 if (!items
|| !globs
) {
1342 if (optind
< argc
) {
1345 for (j
= optind
; j
< argc
; j
++) {
1348 fragment
= resolve_fragment(argv
[j
], (const char**) conf_file_dirs
);
1350 log_error("Failed to find a %s file: %m", argv
[j
]);
1354 if (read_config_file(fragment
, false) < 0)
1362 r
= conf_files_list_strv(&files
, ".conf",
1363 (const char **) conf_file_dirs
);
1365 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r
));
1370 STRV_FOREACH(f
, files
) {
1371 if (read_config_file(*f
, true) < 0)
1378 HASHMAP_FOREACH(i
, globs
, iterator
)
1381 HASHMAP_FOREACH(i
, items
, iterator
)
1385 while ((i
= hashmap_steal_first(items
)))
1388 while ((i
= hashmap_steal_first(globs
)))
1391 hashmap_free(items
);
1392 hashmap_free(globs
);
1394 set_free_free(unix_sockets
);