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
7 Copyright 2015 Zbigniew Jędrzejewski-Szmek
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
38 #include <sys/xattr.h>
46 #include "path-util.h"
50 #include "conf-files.h"
51 #include "capability.h"
52 #include "specifier.h"
56 #include "selinux-util.h"
57 #include "btrfs-util.h"
60 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
61 * them in the file system. This is intended to be used to create
62 * properly owned directories beneath /tmp, /var/tmp, /run, which are
63 * volatile and hence need to be recreated on bootup. */
65 typedef enum ItemType
{
66 /* These ones take file names */
69 CREATE_DIRECTORY
= 'd',
70 TRUNCATE_DIRECTORY
= 'D',
71 CREATE_SUBVOLUME
= 'v',
74 CREATE_CHAR_DEVICE
= 'c',
75 CREATE_BLOCK_DEVICE
= 'b',
78 /* These ones take globs */
80 RECURSIVE_SET_XATTR
= 'T',
82 RECURSIVE_SET_ACL
= 'A',
85 IGNORE_DIRECTORY_PATH
= 'X',
87 RECURSIVE_REMOVE_PATH
= 'R',
88 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
90 RECURSIVE_RELABEL_PATH
= 'Z',
92 RECURSIVE_SET_ATTRIB
= 'H',
111 unsigned long attrib_value
;
112 unsigned long attrib_mask
;
121 bool keep_first_level
:1;
128 typedef struct ItemArray
{
134 static bool arg_create
= false;
135 static bool arg_clean
= false;
136 static bool arg_remove
= false;
137 static bool arg_boot
= false;
139 static char **arg_include_prefixes
= NULL
;
140 static char **arg_exclude_prefixes
= NULL
;
141 static char *arg_root
= NULL
;
143 static const char conf_file_dirs
[] = CONF_DIRS_NULSTR("tmpfiles");
145 #define MAX_DEPTH 256
147 static Hashmap
*items
= NULL
, *globs
= NULL
;
148 static Set
*unix_sockets
= NULL
;
150 static bool needs_glob(ItemType t
) {
154 IGNORE_DIRECTORY_PATH
,
156 RECURSIVE_REMOVE_PATH
,
159 RECURSIVE_RELABEL_PATH
,
166 static bool takes_ownership(ItemType t
) {
180 IGNORE_DIRECTORY_PATH
,
182 RECURSIVE_REMOVE_PATH
);
185 static struct Item
* find_glob(Hashmap
*h
, const char *match
) {
189 HASHMAP_FOREACH(j
, h
, i
) {
192 for (n
= 0; n
< j
->count
; n
++) {
193 Item
*item
= j
->items
+ n
;
195 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
203 static void load_unix_sockets(void) {
204 _cleanup_fclose_
FILE *f
= NULL
;
210 /* We maintain a cache of the sockets we found in
211 * /proc/net/unix to speed things up a little. */
213 unix_sockets
= set_new(&string_hash_ops
);
217 f
= fopen("/proc/net/unix", "re");
222 if (!fgets(line
, sizeof(line
), f
))
229 if (!fgets(line
, sizeof(line
), f
))
234 p
= strchr(line
, ':');
242 p
+= strspn(p
, WHITESPACE
);
243 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
244 p
+= strspn(p
, WHITESPACE
);
253 path_kill_slashes(s
);
255 k
= set_consume(unix_sockets
, s
);
256 if (k
< 0 && k
!= -EEXIST
)
263 set_free_free(unix_sockets
);
267 static bool unix_socket_alive(const char *fn
) {
273 return !!set_get(unix_sockets
, (char*) fn
);
275 /* We don't know, so assume yes */
279 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
281 union file_handle_union h
= FILE_HANDLE_INIT
;
282 int mount_id_parent
, mount_id
;
285 r_p
= name_to_handle_at(dirfd(d
), ".", &h
.handle
, &mount_id_parent
, 0);
289 h
.handle
.handle_bytes
= MAX_HANDLE_SZ
;
290 r
= name_to_handle_at(dirfd(d
), subdir
, &h
.handle
, &mount_id
, 0);
294 /* got no handle; make no assumptions, return error */
295 if (r_p
< 0 && r
< 0)
298 /* got both handles; if they differ, it is a mount point */
299 if (r_p
>= 0 && r
>= 0)
300 return mount_id_parent
!= mount_id
;
302 /* got only one handle; assume different mount points if one
303 * of both queries was not supported by the filesystem */
304 if (r_p
== -ENOSYS
|| r_p
== -EOPNOTSUPP
|| r
== -ENOSYS
|| r
== -EOPNOTSUPP
)
313 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
316 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
320 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
324 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
326 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
331 static DIR* opendir_nomod(const char *path
) {
332 return xopendirat_nomod(AT_FDCWD
, path
);
335 static int dir_cleanup(
339 const struct stat
*ds
,
344 bool keep_this_level
) {
347 struct timespec times
[2];
348 bool deleted
= false;
351 while ((dent
= readdir(d
))) {
354 _cleanup_free_
char *sub_path
= NULL
;
356 if (STR_IN_SET(dent
->d_name
, ".", ".."))
359 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
363 /* FUSE, NFS mounts, SELinux might return EACCES */
365 log_debug_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
367 log_error_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
372 /* Stay on the same filesystem */
373 if (s
.st_dev
!= rootdev
) {
374 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
378 /* Try to detect bind mounts of the same filesystem instance; they
379 * do not differ in device major/minors. This type of query is not
380 * supported on all kernels or filesystem types though. */
381 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
382 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
387 /* Do not delete read-only files owned by root */
388 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
)) {
389 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p
, dent
->d_name
);
393 sub_path
= strjoin(p
, "/", dent
->d_name
, NULL
);
399 /* Is there an item configured for this path? */
400 if (hashmap_get(items
, sub_path
)) {
401 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
405 if (find_glob(globs
, sub_path
)) {
406 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
410 if (S_ISDIR(s
.st_mode
)) {
413 streq(dent
->d_name
, "lost+found") &&
415 log_debug("Ignoring \"%s\".", sub_path
);
420 log_warning("Reached max depth on \"%s\".", sub_path
);
422 _cleanup_closedir_
DIR *sub_dir
;
425 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
428 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
433 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
438 /* Note: if you are wondering why we don't
439 * support the sticky bit for excluding
440 * directories from cleaning like we do it for
441 * other file system objects: well, the sticky
442 * bit already has a meaning for directories,
443 * so we don't want to overload that. */
445 if (keep_this_level
) {
446 log_debug("Keeping \"%s\".", sub_path
);
450 /* Ignore ctime, we change it when deleting */
451 age
= timespec_load(&s
.st_mtim
);
453 char a
[FORMAT_TIMESTAMP_MAX
];
454 /* Follows spelling in stat(1). */
455 log_debug("Directory \"%s\": modify time %s is too new.",
457 format_timestamp_us(a
, sizeof(a
), age
));
461 age
= timespec_load(&s
.st_atim
);
463 char a
[FORMAT_TIMESTAMP_MAX
];
464 log_debug("Directory \"%s\": access time %s is too new.",
466 format_timestamp_us(a
, sizeof(a
), age
));
470 log_debug("Removing directory \"%s\".", sub_path
);
471 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
472 if (errno
!= ENOENT
&& errno
!= ENOTEMPTY
) {
473 log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
478 /* Skip files for which the sticky bit is
479 * set. These are semantics we define, and are
480 * unknown elsewhere. See XDG_RUNTIME_DIR
481 * specification for details. */
482 if (s
.st_mode
& S_ISVTX
) {
483 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
487 if (mountpoint
&& S_ISREG(s
.st_mode
))
488 if ((streq(dent
->d_name
, ".journal") && s
.st_uid
== 0) ||
489 streq(dent
->d_name
, "aquota.user") ||
490 streq(dent
->d_name
, "aquota.group")) {
491 log_debug("Skipping \"%s\".", sub_path
);
495 /* Ignore sockets that are listed in /proc/net/unix */
496 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
497 log_debug("Skipping \"%s\": live socket.", sub_path
);
501 /* Ignore device nodes */
502 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
503 log_debug("Skipping \"%s\": a device.", sub_path
);
507 /* Keep files on this level around if this is
509 if (keep_this_level
) {
510 log_debug("Keeping \"%s\".", sub_path
);
514 age
= timespec_load(&s
.st_mtim
);
516 char a
[FORMAT_TIMESTAMP_MAX
];
517 /* Follows spelling in stat(1). */
518 log_debug("File \"%s\": modify time %s is too new.",
520 format_timestamp_us(a
, sizeof(a
), age
));
524 age
= timespec_load(&s
.st_atim
);
526 char a
[FORMAT_TIMESTAMP_MAX
];
527 log_debug("File \"%s\": access time %s is too new.",
529 format_timestamp_us(a
, sizeof(a
), age
));
533 age
= timespec_load(&s
.st_ctim
);
535 char a
[FORMAT_TIMESTAMP_MAX
];
536 log_debug("File \"%s\": change time %s is too new.",
538 format_timestamp_us(a
, sizeof(a
), age
));
542 log_debug("unlink \"%s\"", sub_path
);
544 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
546 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
555 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
557 /* Restore original directory timestamps */
558 times
[0] = ds
->st_atim
;
559 times
[1] = ds
->st_mtim
;
561 age1
= timespec_load(&ds
->st_atim
);
562 age2
= timespec_load(&ds
->st_mtim
);
563 log_debug("Restoring access and modification time on \"%s\": %s, %s",
565 format_timestamp_us(a
, sizeof(a
), age1
),
566 format_timestamp_us(b
, sizeof(b
), age2
));
567 if (futimens(dirfd(d
), times
) < 0)
568 log_error_errno(errno
, "utimensat(%s): %m", p
);
574 static int path_set_perms(Item
*i
, const char *path
) {
581 st_valid
= stat(path
, &st
) == 0;
583 /* not using i->path directly because it may be a glob */
587 if (i
->mask_perms
&& st_valid
) {
588 if (!(st
.st_mode
& 0111))
590 if (!(st
.st_mode
& 0222))
592 if (!(st
.st_mode
& 0444))
594 if (!S_ISDIR(st
.st_mode
))
595 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
598 if (st_valid
&& m
== (st
.st_mode
& 07777))
599 log_debug("\"%s\" has right mode %o", path
, st
.st_mode
);
601 log_debug("chmod \"%s\" to mode %o", path
, m
);
602 if (chmod(path
, m
) < 0)
603 return log_error_errno(errno
, "chmod(%s) failed: %m", path
);
607 if ((!st_valid
|| i
->uid
!= st
.st_uid
|| i
->gid
!= st
.st_gid
) &&
608 (i
->uid_set
|| i
->gid_set
)) {
609 log_debug("chown \"%s\" to "UID_FMT
"."GID_FMT
,
611 i
->uid_set
? i
->uid
: UID_INVALID
,
612 i
->gid_set
? i
->gid
: GID_INVALID
);
614 i
->uid_set
? i
->uid
: UID_INVALID
,
615 i
->gid_set
? i
->gid
: GID_INVALID
) < 0)
617 return log_error_errno(errno
, "chown(%s) failed: %m", path
);
620 return label_fix(path
, false, false);
623 static int get_xattrs_from_arg(Item
*i
) {
633 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
;
635 r
= unquote_first_word(&p
, &xattr
, UNQUOTE_CUNESCAPE
);
637 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", p
);
641 r
= split_pair(xattr
, "=", &name
, &value
);
643 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
647 if (isempty(name
) || isempty(value
)) {
648 log_warning("Malformed xattr found, ignoring: %s", xattr
);
652 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
661 static int path_set_xattrs(Item
*i
, const char *path
) {
662 char **name
, **value
;
667 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
671 log_debug("\"%s\": setting xattr \"%s=%s\"", path
, *name
, *value
);
672 if (lsetxattr(path
, *name
, *value
, n
, 0) < 0) {
673 log_error("Setting extended attribute %s=%s on %s failed: %m",
674 *name
, *value
, path
);
681 static int get_acls_from_arg(Item
*item
) {
687 /* If force (= modify) is set, we will not modify the acl
688 * afterwards, so the mask can be added now if necessary. */
689 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
691 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
693 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
700 static int path_set_acl(const char *path
, acl_type_t type
, acl_t acl
, bool modify
) {
701 _cleanup_(acl_freep
) acl_t dup
= NULL
;
703 _cleanup_(acl_free_charpp
) char *t
= NULL
;
705 /* Returns 0 for success, positive error if already warned,
706 * negative error otherwise. */
709 r
= acls_for_file(path
, type
, acl
, &dup
);
713 r
= calc_acl_mask_if_needed(&dup
);
721 /* the mask was already added earlier if needed */
724 r
= add_base_acls_if_needed(&dup
, path
);
728 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
729 log_debug("\"%s\": setting %s ACL \"%s\"", path
,
730 type
== ACL_TYPE_ACCESS
? "access" : "default",
733 r
= acl_set_file(path
, type
, dup
);
735 return -log_error_errno(errno
,
736 "Setting %s ACL \"%s\" on %s failed: %m",
737 type
== ACL_TYPE_ACCESS
? "access" : "default",
744 static int path_set_acls(Item
*item
, const char *path
) {
750 if (item
->acl_access
)
751 r
= path_set_acl(path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
753 if (r
== 0 && item
->acl_default
)
754 r
= path_set_acl(path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
757 return -r
; /* already warned */
758 else if (r
== -EOPNOTSUPP
) {
759 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
762 log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
767 #define ALL_ATTRIBS \
776 FS_JOURNAL_DATA_FL | \
783 static int get_attrib_from_arg(Item
*item
) {
784 static const unsigned attributes
[] = {
785 [(uint8_t)'A'] = FS_NOATIME_FL
, /* do not update atime */
786 [(uint8_t)'S'] = FS_SYNC_FL
, /* Synchronous updates */
787 [(uint8_t)'D'] = FS_DIRSYNC_FL
, /* dirsync behaviour (directories only) */
788 [(uint8_t)'a'] = FS_APPEND_FL
, /* writes to file may only append */
789 [(uint8_t)'c'] = FS_COMPR_FL
, /* Compress file */
790 [(uint8_t)'d'] = FS_NODUMP_FL
, /* do not dump file */
791 [(uint8_t)'e'] = FS_EXTENT_FL
, /* Top of directory hierarchies*/
792 [(uint8_t)'i'] = FS_IMMUTABLE_FL
, /* Immutable file */
793 [(uint8_t)'j'] = FS_JOURNAL_DATA_FL
, /* Reserved for ext3 */
794 [(uint8_t)'s'] = FS_SECRM_FL
, /* Secure deletion */
795 [(uint8_t)'u'] = FS_UNRM_FL
, /* Undelete */
796 [(uint8_t)'t'] = FS_NOTAIL_FL
, /* file tail should not be merged */
797 [(uint8_t)'T'] = FS_TOPDIR_FL
, /* Top of directory hierarchies*/
798 [(uint8_t)'C'] = FS_NOCOW_FL
, /* Do not cow file */
800 char *p
= item
->argument
;
806 unsigned long value
= 0, mask
= 0;
809 log_error("\"%s\": setting ATTR need an argument", item
->path
);
816 } else if (*p
== '-') {
819 } else if (*p
== '=') {
824 if (!*p
&& mode
!= MODE_SET
) {
825 log_error("\"%s\": setting ATTR: argument is empty", item
->path
);
829 if ((uint8_t)*p
>= ELEMENTSOF(attributes
) || attributes
[(uint8_t)*p
] == 0) {
830 log_error("\"%s\": setting ATTR: unknown attr '%c'", item
->path
, *p
);
833 if (mode
== MODE_ADD
|| mode
== MODE_SET
)
834 value
|= attributes
[(uint8_t)*p
];
836 value
&= ~attributes
[(uint8_t)*p
];
837 mask
|= attributes
[(uint8_t)*p
];
840 if (mode
== MODE_SET
)
845 item
->attrib_mask
= mask
;
846 item
->attrib_value
= value
;
847 item
->attrib_set
= true;
853 static int path_set_attrib(Item
*item
, const char *path
) {
854 _cleanup_close_
int fd
= -1;
860 if (item
->attrib_mask
== 0 || !item
->attrib_set
)
863 * It is OK to ignore an lstat() error, because the error
864 * will be catch by the open() below anyway
866 if (lstat(path
, &st
) == 0 &&
867 !S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
)) {
871 fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
);
874 return log_error_errno(errno
, "Cannot open \"%s\": %m", path
);
876 f
= item
->attrib_value
& item
->attrib_mask
;
877 if (!S_ISDIR(st
.st_mode
))
879 r
= change_attr_fd(fd
, f
, item
->attrib_mask
);
881 return log_error_errno(errno
,
882 "Cannot set attrib for \"%s\", value=0x%08lx, mask=0x%08lx: %m",
883 path
, item
->attrib_value
, item
->attrib_mask
);
888 static int write_one_file(Item
*i
, const char *path
) {
889 _cleanup_close_
int fd
= -1;
896 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
|O_NOFOLLOW
:
897 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
899 RUN_WITH_UMASK(0000) {
900 mac_selinux_create_file_prepare(path
, S_IFREG
);
901 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
902 mac_selinux_create_file_clear();
906 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
907 log_debug_errno(errno
, "Not writing \"%s\": %m", path
);
911 log_error_errno(errno
, "Failed to create file %s: %m", path
);
916 _cleanup_free_
char *unescaped
= NULL
;
918 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
920 r
= cunescape(i
->argument
, 0, &unescaped
);
922 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
924 r
= loop_write(fd
, unescaped
, strlen(unescaped
), false);
926 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
928 log_debug("\"%s\" has been created.", path
);
932 if (stat(path
, &st
) < 0)
933 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
935 if (!S_ISREG(st
.st_mode
)) {
936 log_error("%s is not a file.", path
);
940 r
= path_set_perms(i
, path
);
947 typedef int (*action_t
)(Item
*, const char *);
949 static int item_do_children(Item
*i
, const char *path
, action_t action
) {
950 _cleanup_closedir_
DIR *d
;
956 /* This returns the first error we run into, but nevertheless
959 d
= opendir_nomod(path
);
961 return errno
== ENOENT
|| errno
== ENOTDIR
? 0 : -errno
;
964 _cleanup_free_
char *p
= NULL
;
971 if (errno
!= 0 && r
== 0)
977 if (STR_IN_SET(de
->d_name
, ".", ".."))
980 p
= strjoin(path
, "/", de
->d_name
, NULL
);
985 if (q
< 0 && q
!= -ENOENT
&& r
== 0)
988 if (IN_SET(de
->d_type
, DT_UNKNOWN
, DT_DIR
)) {
989 q
= item_do_children(i
, p
, action
);
998 static int glob_item(Item
*i
, action_t action
, bool recursive
) {
999 _cleanup_globfree_ glob_t g
= {
1000 .gl_closedir
= (void (*)(void *)) closedir
,
1001 .gl_readdir
= (struct dirent
*(*)(void *)) readdir
,
1002 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1010 k
= glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
|GLOB_ALTDIRFUNC
, NULL
, &g
);
1011 if (k
!= 0 && k
!= GLOB_NOMATCH
)
1012 return log_error_errno(errno
?: EIO
, "glob(%s) failed: %m", i
->path
);
1014 STRV_FOREACH(fn
, g
.gl_pathv
) {
1016 if (k
< 0 && r
== 0)
1020 k
= item_do_children(i
, *fn
, action
);
1021 if (k
< 0 && r
== 0)
1034 _CREATION_MODE_INVALID
= -1
1037 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1038 [CREATION_NORMAL
] = "Created",
1039 [CREATION_EXISTING
] = "Found existing",
1040 [CREATION_FORCE
] = "Created replacement",
1043 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1045 static int create_item(Item
*i
) {
1048 CreationMode creation
;
1052 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1057 case IGNORE_DIRECTORY_PATH
:
1059 case RECURSIVE_REMOVE_PATH
:
1064 r
= write_one_file(i
, i
->path
);
1070 log_debug("Copying tree \"%s\" to \"%s\".", i
->argument
, i
->path
);
1071 r
= copy_tree(i
->argument
, i
->path
, false);
1076 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1078 if (stat(i
->argument
, &a
) < 0)
1079 return log_error_errno(errno
, "stat(%s) failed: %m", i
->argument
);
1081 if (stat(i
->path
, &b
) < 0)
1082 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1084 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1085 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1090 r
= path_set_perms(i
, i
->path
);
1097 r
= glob_item(i
, write_one_file
, false);
1103 case CREATE_DIRECTORY
:
1104 case TRUNCATE_DIRECTORY
:
1105 case CREATE_SUBVOLUME
:
1107 RUN_WITH_UMASK(0000)
1108 mkdir_parents_label(i
->path
, 0755);
1110 if (i
->type
== CREATE_SUBVOLUME
)
1111 RUN_WITH_UMASK((~i
->mode
) & 0777) {
1112 r
= btrfs_subvol_make(i
->path
);
1113 log_debug_errno(r
, "Creating subvolume \"%s\": %m", i
->path
);
1118 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1119 RUN_WITH_UMASK(0000)
1120 r
= mkdir_label(i
->path
, i
->mode
);
1124 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1126 if (stat(i
->path
, &st
) < 0)
1127 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1129 if (!S_ISDIR(st
.st_mode
)) {
1130 log_debug("\"%s\" already exists and is not a directory.", i
->path
);
1134 creation
= CREATION_EXISTING
;
1136 creation
= CREATION_NORMAL
;
1137 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1139 r
= path_set_perms(i
, i
->path
);
1147 RUN_WITH_UMASK(0000) {
1148 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1149 r
= mkfifo(i
->path
, i
->mode
);
1150 mac_selinux_create_file_clear();
1154 if (errno
!= EEXIST
)
1155 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1157 if (stat(i
->path
, &st
) < 0)
1158 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1160 if (!S_ISFIFO(st
.st_mode
)) {
1164 RUN_WITH_UMASK(0000) {
1165 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1166 r
= mkfifo_atomic(i
->path
, i
->mode
);
1167 mac_selinux_create_file_clear();
1171 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1172 creation
= CREATION_FORCE
;
1174 log_debug("%s is not a fifo.", i
->path
);
1178 creation
= CREATION_EXISTING
;
1180 creation
= CREATION_NORMAL
;
1181 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1183 r
= path_set_perms(i
, i
->path
);
1189 case CREATE_SYMLINK
:
1191 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1192 r
= symlink(i
->argument
, i
->path
);
1193 mac_selinux_create_file_clear();
1196 _cleanup_free_
char *x
= NULL
;
1198 if (errno
!= EEXIST
)
1199 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1201 r
= readlink_malloc(i
->path
, &x
);
1202 if (r
< 0 || !streq(i
->argument
, x
)) {
1205 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1206 r
= symlink_atomic(i
->argument
, i
->path
);
1207 mac_selinux_create_file_clear();
1210 return log_error_errno(r
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1211 creation
= CREATION_FORCE
;
1213 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1217 creation
= CREATION_EXISTING
;
1219 creation
= CREATION_NORMAL
;
1220 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1224 case CREATE_BLOCK_DEVICE
:
1225 case CREATE_CHAR_DEVICE
: {
1228 if (have_effective_cap(CAP_MKNOD
) == 0) {
1229 /* In a container we lack CAP_MKNOD. We
1230 shouldn't attempt to create the device node in
1231 that case to avoid noise, and we don't support
1232 virtualized devices in containers anyway. */
1234 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1238 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1240 RUN_WITH_UMASK(0000) {
1241 mac_selinux_create_file_prepare(i
->path
, file_type
);
1242 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1243 mac_selinux_create_file_clear();
1247 if (errno
== EPERM
) {
1248 log_debug("We lack permissions, possibly because of cgroup configuration; "
1249 "skipping creation of device node %s.", i
->path
);
1253 if (errno
!= EEXIST
)
1254 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1256 if (stat(i
->path
, &st
) < 0)
1257 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1259 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1263 RUN_WITH_UMASK(0000) {
1264 mac_selinux_create_file_prepare(i
->path
, file_type
);
1265 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1266 mac_selinux_create_file_clear();
1270 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1271 creation
= CREATION_FORCE
;
1273 log_debug("%s is not a device node.", i
->path
);
1277 creation
= CREATION_EXISTING
;
1279 creation
= CREATION_NORMAL
;
1280 log_debug("%s %s device node \"%s\" %u:%u.",
1281 creation_mode_verb_to_string(creation
),
1282 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1283 i
->path
, major(i
->mode
), minor(i
->mode
));
1285 r
= path_set_perms(i
, i
->path
);
1294 r
= glob_item(i
, path_set_perms
, false);
1299 case RECURSIVE_RELABEL_PATH
:
1300 r
= glob_item(i
, path_set_perms
, true);
1306 r
= glob_item(i
, path_set_xattrs
, false);
1311 case RECURSIVE_SET_XATTR
:
1312 r
= glob_item(i
, path_set_xattrs
, true);
1318 r
= glob_item(i
, path_set_acls
, false);
1323 case RECURSIVE_SET_ACL
:
1324 r
= glob_item(i
, path_set_acls
, true);
1330 r
= glob_item(i
, path_set_attrib
, false);
1335 case RECURSIVE_SET_ATTRIB
:
1336 r
= glob_item(i
, path_set_attrib
, true);
1345 static int remove_item_instance(Item
*i
, const char *instance
) {
1353 if (remove(instance
) < 0 && errno
!= ENOENT
)
1354 return log_error_errno(errno
, "rm(%s): %m", instance
);
1358 case TRUNCATE_DIRECTORY
:
1359 case RECURSIVE_REMOVE_PATH
:
1360 /* FIXME: we probably should use dir_cleanup() here
1361 * instead of rm_rf() so that 'x' is honoured. */
1362 log_debug("rm -rf \"%s\"", instance
);
1363 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
: 0) | REMOVE_PHYSICAL
);
1364 if (r
< 0 && r
!= -ENOENT
)
1365 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1370 assert_not_reached("wut?");
1376 static int remove_item(Item
*i
) {
1381 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1387 case CREATE_DIRECTORY
:
1388 case CREATE_SUBVOLUME
:
1390 case CREATE_SYMLINK
:
1391 case CREATE_CHAR_DEVICE
:
1392 case CREATE_BLOCK_DEVICE
:
1394 case IGNORE_DIRECTORY_PATH
:
1397 case RECURSIVE_RELABEL_PATH
:
1401 case RECURSIVE_SET_XATTR
:
1403 case RECURSIVE_SET_ACL
:
1405 case RECURSIVE_SET_ATTRIB
:
1409 case TRUNCATE_DIRECTORY
:
1410 case RECURSIVE_REMOVE_PATH
:
1411 r
= glob_item(i
, remove_item_instance
, false);
1418 static int clean_item_instance(Item
*i
, const char* instance
) {
1419 _cleanup_closedir_
DIR *d
= NULL
;
1423 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1430 n
= now(CLOCK_REALTIME
);
1434 cutoff
= n
- i
->age
;
1436 d
= opendir_nomod(instance
);
1438 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
1439 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1443 log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1447 if (fstat(dirfd(d
), &s
) < 0)
1448 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1450 if (!S_ISDIR(s
.st_mode
)) {
1451 log_error("%s is not a directory.", i
->path
);
1455 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1456 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1458 mountpoint
= s
.st_dev
!= ps
.st_dev
||
1459 (s
.st_dev
== ps
.st_dev
&& s
.st_ino
== ps
.st_ino
);
1461 log_debug("Cleanup threshold for %s \"%s\" is %s",
1462 mountpoint
? "mount point" : "directory",
1464 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1466 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1467 MAX_DEPTH
, i
->keep_first_level
);
1470 static int clean_item(Item
*i
) {
1475 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1478 case CREATE_DIRECTORY
:
1479 case CREATE_SUBVOLUME
:
1480 case TRUNCATE_DIRECTORY
:
1483 clean_item_instance(i
, i
->path
);
1485 case IGNORE_DIRECTORY_PATH
:
1486 r
= glob_item(i
, clean_item_instance
, false);
1495 static int process_item_array(ItemArray
*array
);
1497 static int process_item(Item
*i
) {
1499 _cleanup_free_
char *prefix
= NULL
;
1508 prefix
= malloc(strlen(i
->path
) + 1);
1512 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1515 j
= hashmap_get(items
, prefix
);
1519 s
= process_item_array(j
);
1520 if (s
< 0 && t
== 0)
1525 r
= arg_create
? create_item(i
) : 0;
1526 q
= arg_remove
? remove_item(i
) : 0;
1527 p
= arg_clean
? clean_item(i
) : 0;
1535 static int process_item_array(ItemArray
*array
) {
1541 for (n
= 0; n
< array
->count
; n
++) {
1542 k
= process_item(array
->items
+ n
);
1543 if (k
< 0 && r
== 0)
1550 static void item_free_contents(Item
*i
) {
1554 strv_free(i
->xattrs
);
1557 acl_free(i
->acl_access
);
1558 acl_free(i
->acl_default
);
1562 static void item_array_free(ItemArray
*a
) {
1568 for (n
= 0; n
< a
->count
; n
++)
1569 item_free_contents(a
->items
+ n
);
1574 static bool item_compatible(Item
*a
, Item
*b
) {
1577 assert(streq(a
->path
, b
->path
));
1579 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1580 /* check if the items are the same */
1581 return streq_ptr(a
->argument
, b
->argument
) &&
1583 a
->uid_set
== b
->uid_set
&&
1586 a
->gid_set
== b
->gid_set
&&
1589 a
->mode_set
== b
->mode_set
&&
1590 a
->mode
== b
->mode
&&
1592 a
->age_set
== b
->age_set
&&
1595 a
->mask_perms
== b
->mask_perms
&&
1597 a
->keep_first_level
== b
->keep_first_level
&&
1599 a
->major_minor
== b
->major_minor
;
1604 static bool should_include_path(const char *path
) {
1607 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1608 if (path_startswith(path
, *prefix
)) {
1609 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1614 STRV_FOREACH(prefix
, arg_include_prefixes
)
1615 if (path_startswith(path
, *prefix
)) {
1616 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1620 /* no matches, so we should include this path only if we
1621 * have no whitelist at all */
1622 if (strv_length(arg_include_prefixes
) == 0)
1625 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1629 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1631 static const Specifier specifier_table
[] = {
1632 { 'm', specifier_machine_id
, NULL
},
1633 { 'b', specifier_boot_id
, NULL
},
1634 { 'H', specifier_host_name
, NULL
},
1635 { 'v', specifier_kernel_release
, NULL
},
1639 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1640 _cleanup_(item_free_contents
) Item i
= {};
1641 ItemArray
*existing
;
1644 bool force
= false, boot
= false;
1650 r
= unquote_many_words(
1661 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1663 log_error("[%s:%u] Syntax error.", fname
, line
);
1667 if (!isempty(buffer
)) {
1668 i
.argument
= strdup(buffer
);
1673 if (isempty(action
)) {
1674 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1678 for (pos
= 1; action
[pos
]; pos
++) {
1679 if (action
[pos
] == '!' && !boot
)
1681 else if (action
[pos
] == '+' && !force
)
1684 log_error("[%s:%u] Unknown modifiers in command '%s'",
1685 fname
, line
, action
);
1690 if (boot
&& !arg_boot
) {
1691 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1699 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1701 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1709 case CREATE_DIRECTORY
:
1710 case CREATE_SUBVOLUME
:
1711 case TRUNCATE_DIRECTORY
:
1714 case IGNORE_DIRECTORY_PATH
:
1716 case RECURSIVE_REMOVE_PATH
:
1719 case RECURSIVE_RELABEL_PATH
:
1722 case CREATE_SYMLINK
:
1724 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1732 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1739 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1742 } else if (!path_is_absolute(i
.argument
)) {
1743 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1747 path_kill_slashes(i
.argument
);
1750 case CREATE_CHAR_DEVICE
:
1751 case CREATE_BLOCK_DEVICE
: {
1752 unsigned major
, minor
;
1755 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1759 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1760 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1764 i
.major_minor
= makedev(major
, minor
);
1769 case RECURSIVE_SET_XATTR
:
1771 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1774 r
= get_xattrs_from_arg(&i
);
1780 case RECURSIVE_SET_ACL
:
1782 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
1785 r
= get_acls_from_arg(&i
);
1791 case RECURSIVE_SET_ATTRIB
:
1793 log_error("[%s:%u] Set attrib requires argument.", fname
, line
);
1796 r
= get_attrib_from_arg(&i
);
1802 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
1806 if (!path_is_absolute(i
.path
)) {
1807 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
1811 path_kill_slashes(i
.path
);
1813 if (!should_include_path(i
.path
))
1819 p
= strappend(arg_root
, i
.path
);
1827 if (user
&& !streq(user
, "-")) {
1828 const char *u
= user
;
1830 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
1832 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
1839 if (group
&& !streq(group
, "-")) {
1840 const char *g
= group
;
1842 r
= get_group_creds(&g
, &i
.gid
);
1844 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
1851 if (mode
&& !streq(mode
, "-")) {
1852 const char *mm
= mode
;
1856 i
.mask_perms
= true;
1860 if (sscanf(mm
, "%o", &m
) != 1) {
1861 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
1868 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, CREATE_SUBVOLUME
, TRUNCATE_DIRECTORY
)
1871 if (age
&& !streq(age
, "-")) {
1872 const char *a
= age
;
1875 i
.keep_first_level
= true;
1879 if (parse_sec(a
, &i
.age
) < 0) {
1880 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
1887 h
= needs_glob(i
.type
) ? globs
: items
;
1889 existing
= hashmap_get(h
, i
.path
);
1893 for (n
= 0; n
< existing
->count
; n
++) {
1894 if (!item_compatible(existing
->items
+ n
, &i
)) {
1895 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1896 fname
, line
, i
.path
);
1901 existing
= new0(ItemArray
, 1);
1902 r
= hashmap_put(h
, i
.path
, existing
);
1907 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
1910 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
1915 static void help(void) {
1916 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1917 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1918 " -h --help Show this help\n"
1919 " --version Show package version\n"
1920 " --create Create marked files/directories\n"
1921 " --clean Clean up marked directories\n"
1922 " --remove Remove marked files/directories\n"
1923 " --boot Execute actions only safe at boot\n"
1924 " --prefix=PATH Only apply rules with the specified prefix\n"
1925 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
1926 " --root=PATH Operate on an alternate filesystem root\n",
1927 program_invocation_short_name
);
1930 static int parse_argv(int argc
, char *argv
[]) {
1933 ARG_VERSION
= 0x100,
1943 static const struct option options
[] = {
1944 { "help", no_argument
, NULL
, 'h' },
1945 { "version", no_argument
, NULL
, ARG_VERSION
},
1946 { "create", no_argument
, NULL
, ARG_CREATE
},
1947 { "clean", no_argument
, NULL
, ARG_CLEAN
},
1948 { "remove", no_argument
, NULL
, ARG_REMOVE
},
1949 { "boot", no_argument
, NULL
, ARG_BOOT
},
1950 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
1951 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
1952 { "root", required_argument
, NULL
, ARG_ROOT
},
1961 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
1970 puts(PACKAGE_STRING
);
1971 puts(SYSTEMD_FEATURES
);
1991 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
1995 case ARG_EXCLUDE_PREFIX
:
1996 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2002 arg_root
= path_make_absolute_cwd(optarg
);
2006 path_kill_slashes(arg_root
);
2013 assert_not_reached("Unhandled option");
2016 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2017 log_error("You need to specify at least one of --clean, --create or --remove.");
2024 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2025 _cleanup_fclose_
FILE *f
= NULL
;
2026 char line
[LINE_MAX
];
2034 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &f
);
2036 if (ignore_enoent
&& r
== -ENOENT
) {
2037 log_debug_errno(r
, "Failed to open \"%s\": %m", fn
);
2041 return log_error_errno(r
, "Failed to open '%s', ignoring: %m", fn
);
2043 log_debug("Reading config file \"%s\".", fn
);
2045 FOREACH_LINE(line
, f
, break) {
2052 if (*l
== '#' || *l
== 0)
2055 k
= parse_line(fn
, v
, l
);
2056 if (k
< 0 && r
== 0)
2060 /* we have to determine age parameter for each entry of type X */
2061 HASHMAP_FOREACH(i
, globs
, iterator
) {
2063 Item
*j
, *candidate_item
= NULL
;
2065 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2068 HASHMAP_FOREACH(j
, items
, iter
) {
2069 if (j
->type
!= CREATE_DIRECTORY
&& j
->type
!= TRUNCATE_DIRECTORY
&& j
->type
!= CREATE_SUBVOLUME
)
2072 if (path_equal(j
->path
, i
->path
)) {
2077 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2078 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2082 if (candidate_item
&& candidate_item
->age_set
) {
2083 i
->age
= candidate_item
->age
;
2089 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2097 int main(int argc
, char *argv
[]) {
2102 r
= parse_argv(argc
, argv
);
2106 log_set_target(LOG_TARGET_AUTO
);
2107 log_parse_environment();
2112 mac_selinux_init(NULL
);
2114 items
= hashmap_new(&string_hash_ops
);
2115 globs
= hashmap_new(&string_hash_ops
);
2117 if (!items
|| !globs
) {
2124 if (optind
< argc
) {
2127 for (j
= optind
; j
< argc
; j
++) {
2128 k
= read_config_file(argv
[j
], false);
2129 if (k
< 0 && r
== 0)
2134 _cleanup_strv_free_
char **files
= NULL
;
2137 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, conf_file_dirs
);
2139 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2143 STRV_FOREACH(f
, files
) {
2144 k
= read_config_file(*f
, true);
2145 if (k
< 0 && r
== 0)
2150 HASHMAP_FOREACH(a
, globs
, iterator
) {
2151 k
= process_item_array(a
);
2152 if (k
< 0 && r
== 0)
2156 HASHMAP_FOREACH(a
, items
, iterator
) {
2157 k
= process_item_array(a
);
2158 if (k
< 0 && r
== 0)
2163 while ((a
= hashmap_steal_first(items
)))
2166 while ((a
= hashmap_steal_first(globs
)))
2169 hashmap_free(items
);
2170 hashmap_free(globs
);
2172 free(arg_include_prefixes
);
2173 free(arg_exclude_prefixes
);
2176 set_free_free(unix_sockets
);
2178 mac_selinux_finish();
2180 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;