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/>.
37 #include <sys/xattr.h>
42 #include "btrfs-util.h"
43 #include "capability.h"
44 #include "conf-files.h"
48 #include "formats-util.h"
55 #include "path-util.h"
57 #include "selinux-util.h"
59 #include "specifier.h"
60 #include "string-util.h"
62 #include "user-util.h"
65 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
66 * them in the file system. This is intended to be used to create
67 * properly owned directories beneath /tmp, /var/tmp, /run, which are
68 * volatile and hence need to be recreated on bootup. */
70 typedef enum ItemType
{
71 /* These ones take file names */
74 CREATE_DIRECTORY
= 'd',
75 TRUNCATE_DIRECTORY
= 'D',
76 CREATE_SUBVOLUME
= 'v',
77 CREATE_SUBVOLUME_INHERIT_QUOTA
= 'q',
78 CREATE_SUBVOLUME_NEW_QUOTA
= 'Q',
81 CREATE_CHAR_DEVICE
= 'c',
82 CREATE_BLOCK_DEVICE
= 'b',
85 /* These ones take globs */
88 RECURSIVE_SET_XATTR
= 'T',
90 RECURSIVE_SET_ACL
= 'A',
92 RECURSIVE_SET_ATTRIBUTE
= 'H',
94 IGNORE_DIRECTORY_PATH
= 'X',
96 RECURSIVE_REMOVE_PATH
= 'R',
98 RECURSIVE_RELABEL_PATH
= 'Z',
99 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
102 typedef struct Item
{
118 unsigned attribute_value
;
119 unsigned attribute_mask
;
126 bool attribute_set
:1;
128 bool keep_first_level
:1;
135 typedef struct ItemArray
{
141 static bool arg_create
= false;
142 static bool arg_clean
= false;
143 static bool arg_remove
= false;
144 static bool arg_boot
= false;
146 static char **arg_include_prefixes
= NULL
;
147 static char **arg_exclude_prefixes
= NULL
;
148 static char *arg_root
= NULL
;
150 static const char conf_file_dirs
[] = CONF_DIRS_NULSTR("tmpfiles");
152 #define MAX_DEPTH 256
154 static OrderedHashmap
*items
= NULL
, *globs
= NULL
;
155 static Set
*unix_sockets
= NULL
;
157 static const Specifier specifier_table
[] = {
158 { 'm', specifier_machine_id
, NULL
},
159 { 'b', specifier_boot_id
, NULL
},
160 { 'H', specifier_host_name
, NULL
},
161 { 'v', specifier_kernel_release
, NULL
},
165 static bool needs_glob(ItemType t
) {
169 IGNORE_DIRECTORY_PATH
,
171 RECURSIVE_REMOVE_PATH
,
174 RECURSIVE_RELABEL_PATH
,
180 RECURSIVE_SET_ATTRIBUTE
);
183 static bool takes_ownership(ItemType t
) {
190 CREATE_SUBVOLUME_INHERIT_QUOTA
,
191 CREATE_SUBVOLUME_NEW_QUOTA
,
199 IGNORE_DIRECTORY_PATH
,
201 RECURSIVE_REMOVE_PATH
);
204 static struct Item
* find_glob(OrderedHashmap
*h
, const char *match
) {
208 ORDERED_HASHMAP_FOREACH(j
, h
, i
) {
211 for (n
= 0; n
< j
->count
; n
++) {
212 Item
*item
= j
->items
+ n
;
214 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
222 static void load_unix_sockets(void) {
223 _cleanup_fclose_
FILE *f
= NULL
;
229 /* We maintain a cache of the sockets we found in
230 * /proc/net/unix to speed things up a little. */
232 unix_sockets
= set_new(&string_hash_ops
);
236 f
= fopen("/proc/net/unix", "re");
241 if (!fgets(line
, sizeof(line
), f
))
248 if (!fgets(line
, sizeof(line
), f
))
253 p
= strchr(line
, ':');
261 p
+= strspn(p
, WHITESPACE
);
262 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
263 p
+= strspn(p
, WHITESPACE
);
272 path_kill_slashes(s
);
274 k
= set_consume(unix_sockets
, s
);
275 if (k
< 0 && k
!= -EEXIST
)
282 set_free_free(unix_sockets
);
286 static bool unix_socket_alive(const char *fn
) {
292 return !!set_get(unix_sockets
, (char*) fn
);
294 /* We don't know, so assume yes */
298 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
300 union file_handle_union h
= FILE_HANDLE_INIT
;
301 int mount_id_parent
, mount_id
;
304 r_p
= name_to_handle_at(dirfd(d
), ".", &h
.handle
, &mount_id_parent
, 0);
308 h
.handle
.handle_bytes
= MAX_HANDLE_SZ
;
309 r
= name_to_handle_at(dirfd(d
), subdir
, &h
.handle
, &mount_id
, 0);
313 /* got no handle; make no assumptions, return error */
314 if (r_p
< 0 && r
< 0)
317 /* got both handles; if they differ, it is a mount point */
318 if (r_p
>= 0 && r
>= 0)
319 return mount_id_parent
!= mount_id
;
321 /* got only one handle; assume different mount points if one
322 * of both queries was not supported by the filesystem */
323 if (r_p
== -ENOSYS
|| r_p
== -EOPNOTSUPP
|| r
== -ENOSYS
|| r
== -EOPNOTSUPP
)
332 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
335 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
339 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
343 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
345 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
350 static DIR* opendir_nomod(const char *path
) {
351 return xopendirat_nomod(AT_FDCWD
, path
);
354 static int dir_cleanup(
358 const struct stat
*ds
,
363 bool keep_this_level
) {
366 struct timespec times
[2];
367 bool deleted
= false;
370 while ((dent
= readdir(d
))) {
373 _cleanup_free_
char *sub_path
= NULL
;
375 if (STR_IN_SET(dent
->d_name
, ".", ".."))
378 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
382 /* FUSE, NFS mounts, SELinux might return EACCES */
384 log_debug_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
386 log_error_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
391 /* Stay on the same filesystem */
392 if (s
.st_dev
!= rootdev
) {
393 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
397 /* Try to detect bind mounts of the same filesystem instance; they
398 * do not differ in device major/minors. This type of query is not
399 * supported on all kernels or filesystem types though. */
400 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
401 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
406 /* Do not delete read-only files owned by root */
407 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
)) {
408 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p
, dent
->d_name
);
412 sub_path
= strjoin(p
, "/", dent
->d_name
, NULL
);
418 /* Is there an item configured for this path? */
419 if (ordered_hashmap_get(items
, sub_path
)) {
420 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
424 if (find_glob(globs
, sub_path
)) {
425 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
429 if (S_ISDIR(s
.st_mode
)) {
432 streq(dent
->d_name
, "lost+found") &&
434 log_debug("Ignoring \"%s\".", sub_path
);
439 log_warning("Reached max depth on \"%s\".", sub_path
);
441 _cleanup_closedir_
DIR *sub_dir
;
444 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
447 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
452 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
457 /* Note: if you are wondering why we don't
458 * support the sticky bit for excluding
459 * directories from cleaning like we do it for
460 * other file system objects: well, the sticky
461 * bit already has a meaning for directories,
462 * so we don't want to overload that. */
464 if (keep_this_level
) {
465 log_debug("Keeping \"%s\".", sub_path
);
469 /* Ignore ctime, we change it when deleting */
470 age
= timespec_load(&s
.st_mtim
);
472 char a
[FORMAT_TIMESTAMP_MAX
];
473 /* Follows spelling in stat(1). */
474 log_debug("Directory \"%s\": modify time %s is too new.",
476 format_timestamp_us(a
, sizeof(a
), age
));
480 age
= timespec_load(&s
.st_atim
);
482 char a
[FORMAT_TIMESTAMP_MAX
];
483 log_debug("Directory \"%s\": access time %s is too new.",
485 format_timestamp_us(a
, sizeof(a
), age
));
489 log_debug("Removing directory \"%s\".", sub_path
);
490 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
491 if (errno
!= ENOENT
&& errno
!= ENOTEMPTY
) {
492 log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
497 /* Skip files for which the sticky bit is
498 * set. These are semantics we define, and are
499 * unknown elsewhere. See XDG_RUNTIME_DIR
500 * specification for details. */
501 if (s
.st_mode
& S_ISVTX
) {
502 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
506 if (mountpoint
&& S_ISREG(s
.st_mode
))
507 if (s
.st_uid
== 0 && STR_IN_SET(dent
->d_name
,
511 log_debug("Skipping \"%s\".", sub_path
);
515 /* Ignore sockets that are listed in /proc/net/unix */
516 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
517 log_debug("Skipping \"%s\": live socket.", sub_path
);
521 /* Ignore device nodes */
522 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
523 log_debug("Skipping \"%s\": a device.", sub_path
);
527 /* Keep files on this level around if this is
529 if (keep_this_level
) {
530 log_debug("Keeping \"%s\".", sub_path
);
534 age
= timespec_load(&s
.st_mtim
);
536 char a
[FORMAT_TIMESTAMP_MAX
];
537 /* Follows spelling in stat(1). */
538 log_debug("File \"%s\": modify time %s is too new.",
540 format_timestamp_us(a
, sizeof(a
), age
));
544 age
= timespec_load(&s
.st_atim
);
546 char a
[FORMAT_TIMESTAMP_MAX
];
547 log_debug("File \"%s\": access time %s is too new.",
549 format_timestamp_us(a
, sizeof(a
), age
));
553 age
= timespec_load(&s
.st_ctim
);
555 char a
[FORMAT_TIMESTAMP_MAX
];
556 log_debug("File \"%s\": change time %s is too new.",
558 format_timestamp_us(a
, sizeof(a
), age
));
562 log_debug("unlink \"%s\"", sub_path
);
564 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
566 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
575 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
577 /* Restore original directory timestamps */
578 times
[0] = ds
->st_atim
;
579 times
[1] = ds
->st_mtim
;
581 age1
= timespec_load(&ds
->st_atim
);
582 age2
= timespec_load(&ds
->st_mtim
);
583 log_debug("Restoring access and modification time on \"%s\": %s, %s",
585 format_timestamp_us(a
, sizeof(a
), age1
),
586 format_timestamp_us(b
, sizeof(b
), age2
));
587 if (futimens(dirfd(d
), times
) < 0)
588 log_error_errno(errno
, "utimensat(%s): %m", p
);
594 static int path_set_perms(Item
*i
, const char *path
) {
595 _cleanup_close_
int fd
= -1;
601 /* We open the file with O_PATH here, to make the operation
602 * somewhat atomic. Also there's unfortunately no fchmodat()
603 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
606 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
608 return log_error_errno(errno
, "Adjusting owner and mode for %s failed: %m", path
);
610 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
611 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
613 if (S_ISLNK(st
.st_mode
))
614 log_debug("Skipping mode an owner fix for symlink %s.", path
);
616 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
617 xsprintf(fn
, "/proc/self/fd/%i", fd
);
619 /* not using i->path directly because it may be a glob */
624 if (!(st
.st_mode
& 0111))
626 if (!(st
.st_mode
& 0222))
628 if (!(st
.st_mode
& 0444))
630 if (!S_ISDIR(st
.st_mode
))
631 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
634 if (m
== (st
.st_mode
& 07777))
635 log_debug("\"%s\" has right mode %o", path
, st
.st_mode
);
637 log_debug("chmod \"%s\" to mode %o", path
, m
);
638 if (chmod(fn
, m
) < 0)
639 return log_error_errno(errno
, "chmod(%s) failed: %m", path
);
643 if ((i
->uid
!= st
.st_uid
|| i
->gid
!= st
.st_gid
) &&
644 (i
->uid_set
|| i
->gid_set
)) {
645 log_debug("chown \"%s\" to "UID_FMT
"."GID_FMT
,
647 i
->uid_set
? i
->uid
: UID_INVALID
,
648 i
->gid_set
? i
->gid
: GID_INVALID
);
650 i
->uid_set
? i
->uid
: UID_INVALID
,
651 i
->gid_set
? i
->gid
: GID_INVALID
) < 0)
652 return log_error_errno(errno
, "chown(%s) failed: %m", path
);
658 return label_fix(path
, false, false);
661 static int parse_xattrs_from_arg(Item
*i
) {
671 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
, *xattr_replaced
= NULL
;
673 r
= extract_first_word(&p
, &xattr
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
675 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
679 r
= specifier_printf(xattr
, specifier_table
, NULL
, &xattr_replaced
);
681 return log_error_errno(r
, "Failed to replace specifiers in extended attribute '%s': %m", xattr
);
683 r
= split_pair(xattr_replaced
, "=", &name
, &value
);
685 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
689 if (isempty(name
) || isempty(value
)) {
690 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
694 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
703 static int path_set_xattrs(Item
*i
, const char *path
) {
704 char **name
, **value
;
709 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
713 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
714 if (lsetxattr(path
, *name
, *value
, n
, 0) < 0) {
715 log_error("Setting extended attribute %s=%s on %s failed: %m", *name
, *value
, path
);
722 static int parse_acls_from_arg(Item
*item
) {
728 /* If force (= modify) is set, we will not modify the acl
729 * afterwards, so the mask can be added now if necessary. */
731 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
733 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
735 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
742 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
743 _cleanup_(acl_free_charpp
) char *t
= NULL
;
744 _cleanup_(acl_freep
) acl_t dup
= NULL
;
747 /* Returns 0 for success, positive error if already warned,
748 * negative error otherwise. */
751 r
= acls_for_file(path
, type
, acl
, &dup
);
755 r
= calc_acl_mask_if_needed(&dup
);
763 /* the mask was already added earlier if needed */
766 r
= add_base_acls_if_needed(&dup
, path
);
770 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
771 log_debug("Setting %s ACL %s on %s.",
772 type
== ACL_TYPE_ACCESS
? "access" : "default",
775 r
= acl_set_file(path
, type
, dup
);
777 /* Return positive to indicate we already warned */
778 return -log_error_errno(errno
,
779 "Setting %s ACL \"%s\" on %s failed: %m",
780 type
== ACL_TYPE_ACCESS
? "access" : "default",
787 static int path_set_acls(Item
*item
, const char *path
) {
790 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
791 _cleanup_close_
int fd
= -1;
797 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
799 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
801 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
802 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
804 if (S_ISLNK(st
.st_mode
)) {
805 log_debug("Skipping ACL fix for symlink %s.", path
);
809 xsprintf(fn
, "/proc/self/fd/%i", fd
);
811 if (item
->acl_access
)
812 r
= path_set_acl(fn
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
814 if (r
== 0 && item
->acl_default
)
815 r
= path_set_acl(fn
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
818 return -r
; /* already warned */
819 else if (r
== -EOPNOTSUPP
) {
820 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
823 log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
828 #define ATTRIBUTES_ALL \
837 FS_JOURNAL_DATA_FL | \
844 static int parse_attribute_from_arg(Item
*item
) {
846 static const struct {
850 { 'A', FS_NOATIME_FL
}, /* do not update atime */
851 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
852 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
853 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
854 { 'c', FS_COMPR_FL
}, /* Compress file */
855 { 'd', FS_NODUMP_FL
}, /* do not dump file */
856 { 'e', FS_EXTENT_FL
}, /* Top of directory hierarchies*/
857 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
858 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
859 { 's', FS_SECRM_FL
}, /* Secure deletion */
860 { 'u', FS_UNRM_FL
}, /* Undelete */
861 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
862 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies*/
863 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
872 unsigned value
= 0, mask
= 0;
882 } else if (*p
== '-') {
885 } else if (*p
== '=') {
891 if (isempty(p
) && mode
!= MODE_SET
) {
892 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
896 for (; p
&& *p
; p
++) {
899 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
900 if (*p
== attributes
[i
].character
)
903 if (i
>= ELEMENTSOF(attributes
)) {
904 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
908 v
= attributes
[i
].value
;
910 if (mode
== MODE_ADD
|| mode
== MODE_SET
)
918 if (mode
== MODE_SET
)
919 mask
|= ATTRIBUTES_ALL
;
923 item
->attribute_mask
= mask
;
924 item
->attribute_value
= value
;
925 item
->attribute_set
= true;
930 static int path_set_attribute(Item
*item
, const char *path
) {
931 _cleanup_close_
int fd
= -1;
936 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
939 fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
|O_NOATIME
|O_NOFOLLOW
);
942 return log_error_errno(errno
, "Skipping file attributes adjustment on symlink %s.", path
);
944 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
947 if (fstat(fd
, &st
) < 0)
948 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
950 /* Issuing the file attribute ioctls on device nodes is not
951 * safe, as that will be delivered to the drivers, not the
952 * file system containing the device node. */
953 if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
)) {
954 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
958 f
= item
->attribute_value
& item
->attribute_mask
;
960 /* Mask away directory-specific flags */
961 if (!S_ISDIR(st
.st_mode
))
964 r
= chattr_fd(fd
, f
, item
->attribute_mask
);
966 log_full_errno(r
== -ENOTTY
? LOG_DEBUG
: LOG_WARNING
,
968 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
969 path
, item
->attribute_value
, item
->attribute_mask
);
974 static int write_one_file(Item
*i
, const char *path
) {
975 _cleanup_close_
int fd
= -1;
982 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
|O_NOFOLLOW
:
983 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
985 RUN_WITH_UMASK(0000) {
986 mac_selinux_create_file_prepare(path
, S_IFREG
);
987 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
988 mac_selinux_create_file_clear();
992 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
993 log_debug_errno(errno
, "Not writing \"%s\": %m", path
);
998 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
999 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
1002 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1006 _cleanup_free_
char *unescaped
= NULL
, *replaced
= NULL
;
1008 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1010 r
= cunescape(i
->argument
, 0, &unescaped
);
1012 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
1014 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &replaced
);
1016 return log_error_errno(r
, "Failed to replace specifiers in parameter to write '%s': %m", unescaped
);
1018 r
= loop_write(fd
, replaced
, strlen(replaced
), false);
1020 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1022 log_debug("\"%s\" has been created.", path
);
1024 fd
= safe_close(fd
);
1026 if (stat(path
, &st
) < 0)
1027 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1030 if (!S_ISREG(st
.st_mode
)) {
1031 log_error("%s is not a file.", path
);
1035 r
= path_set_perms(i
, path
);
1042 typedef int (*action_t
)(Item
*, const char *);
1044 static int item_do_children(Item
*i
, const char *path
, action_t action
) {
1045 _cleanup_closedir_
DIR *d
;
1051 /* This returns the first error we run into, but nevertheless
1054 d
= opendir_nomod(path
);
1056 return errno
== ENOENT
|| errno
== ENOTDIR
? 0 : -errno
;
1059 _cleanup_free_
char *p
= NULL
;
1066 if (errno
!= 0 && r
== 0)
1072 if (STR_IN_SET(de
->d_name
, ".", ".."))
1075 p
= strjoin(path
, "/", de
->d_name
, NULL
);
1080 if (q
< 0 && q
!= -ENOENT
&& r
== 0)
1083 if (IN_SET(de
->d_type
, DT_UNKNOWN
, DT_DIR
)) {
1084 q
= item_do_children(i
, p
, action
);
1085 if (q
< 0 && r
== 0)
1093 static int glob_item(Item
*i
, action_t action
, bool recursive
) {
1094 _cleanup_globfree_ glob_t g
= {
1095 .gl_closedir
= (void (*)(void *)) closedir
,
1096 .gl_readdir
= (struct dirent
*(*)(void *)) readdir
,
1097 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1105 k
= glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
|GLOB_ALTDIRFUNC
, NULL
, &g
);
1106 if (k
!= 0 && k
!= GLOB_NOMATCH
)
1107 return log_error_errno(errno
?: EIO
, "glob(%s) failed: %m", i
->path
);
1109 STRV_FOREACH(fn
, g
.gl_pathv
) {
1111 if (k
< 0 && r
== 0)
1115 k
= item_do_children(i
, *fn
, action
);
1116 if (k
< 0 && r
== 0)
1129 _CREATION_MODE_INVALID
= -1
1132 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1133 [CREATION_NORMAL
] = "Created",
1134 [CREATION_EXISTING
] = "Found existing",
1135 [CREATION_FORCE
] = "Created replacement",
1138 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1140 static int create_item(Item
*i
) {
1141 _cleanup_free_
char *resolved
= NULL
;
1144 CreationMode creation
;
1148 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1153 case IGNORE_DIRECTORY_PATH
:
1155 case RECURSIVE_REMOVE_PATH
:
1160 r
= write_one_file(i
, i
->path
);
1166 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1168 return log_error_errno(r
, "Failed to substitute specifiers in copy source %s: %m", i
->argument
);
1170 log_debug("Copying tree \"%s\" to \"%s\".", resolved
, i
->path
);
1171 r
= copy_tree(resolved
, i
->path
, false);
1173 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1180 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1182 if (stat(resolved
, &a
) < 0)
1183 return log_error_errno(errno
, "stat(%s) failed: %m", resolved
);
1185 if (stat(i
->path
, &b
) < 0)
1186 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1188 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1189 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1194 r
= path_set_perms(i
, i
->path
);
1201 r
= glob_item(i
, write_one_file
, false);
1207 case CREATE_DIRECTORY
:
1208 case TRUNCATE_DIRECTORY
:
1209 case CREATE_SUBVOLUME
:
1210 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1211 case CREATE_SUBVOLUME_NEW_QUOTA
:
1213 RUN_WITH_UMASK(0000)
1214 mkdir_parents_label(i
->path
, 0755);
1216 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1217 RUN_WITH_UMASK((~i
->mode
) & 0777)
1218 r
= btrfs_subvol_make(i
->path
);
1222 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1223 RUN_WITH_UMASK(0000)
1224 r
= mkdir_label(i
->path
, i
->mode
);
1229 if (r
!= -EEXIST
&& r
!= -EROFS
)
1230 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1232 k
= is_dir(i
->path
, false);
1233 if (k
== -ENOENT
&& r
== -EROFS
)
1234 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1236 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1238 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1242 creation
= CREATION_EXISTING
;
1244 creation
= CREATION_NORMAL
;
1246 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1248 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1249 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1251 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i
->path
);
1255 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i
->path
);
1259 return log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1261 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1263 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1266 r
= path_set_perms(i
, i
->path
);
1274 RUN_WITH_UMASK(0000) {
1275 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1276 r
= mkfifo(i
->path
, i
->mode
);
1277 mac_selinux_create_file_clear();
1281 if (errno
!= EEXIST
)
1282 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1284 if (lstat(i
->path
, &st
) < 0)
1285 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1287 if (!S_ISFIFO(st
.st_mode
)) {
1290 RUN_WITH_UMASK(0000) {
1291 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1292 r
= mkfifo_atomic(i
->path
, i
->mode
);
1293 mac_selinux_create_file_clear();
1297 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1298 creation
= CREATION_FORCE
;
1300 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1304 creation
= CREATION_EXISTING
;
1306 creation
= CREATION_NORMAL
;
1307 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1309 r
= path_set_perms(i
, i
->path
);
1316 case CREATE_SYMLINK
: {
1317 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1319 return log_error_errno(r
, "Failed to substitute specifiers in symlink target %s: %m", i
->argument
);
1321 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1322 r
= symlink(resolved
, i
->path
);
1323 mac_selinux_create_file_clear();
1326 _cleanup_free_
char *x
= NULL
;
1328 if (errno
!= EEXIST
)
1329 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1331 r
= readlink_malloc(i
->path
, &x
);
1332 if (r
< 0 || !streq(resolved
, x
)) {
1335 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1336 r
= symlink_atomic(resolved
, i
->path
);
1337 mac_selinux_create_file_clear();
1340 return log_error_errno(r
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1342 creation
= CREATION_FORCE
;
1344 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1348 creation
= CREATION_EXISTING
;
1351 creation
= CREATION_NORMAL
;
1352 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1356 case CREATE_BLOCK_DEVICE
:
1357 case CREATE_CHAR_DEVICE
: {
1360 if (have_effective_cap(CAP_MKNOD
) == 0) {
1361 /* In a container we lack CAP_MKNOD. We
1362 shouldn't attempt to create the device node in
1363 that case to avoid noise, and we don't support
1364 virtualized devices in containers anyway. */
1366 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1370 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1372 RUN_WITH_UMASK(0000) {
1373 mac_selinux_create_file_prepare(i
->path
, file_type
);
1374 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1375 mac_selinux_create_file_clear();
1379 if (errno
== EPERM
) {
1380 log_debug("We lack permissions, possibly because of cgroup configuration; "
1381 "skipping creation of device node %s.", i
->path
);
1385 if (errno
!= EEXIST
)
1386 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1388 if (lstat(i
->path
, &st
) < 0)
1389 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1391 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1395 RUN_WITH_UMASK(0000) {
1396 mac_selinux_create_file_prepare(i
->path
, file_type
);
1397 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1398 mac_selinux_create_file_clear();
1402 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1403 creation
= CREATION_FORCE
;
1405 log_debug("%s is not a device node.", i
->path
);
1409 creation
= CREATION_EXISTING
;
1411 creation
= CREATION_NORMAL
;
1413 log_debug("%s %s device node \"%s\" %u:%u.",
1414 creation_mode_verb_to_string(creation
),
1415 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1416 i
->path
, major(i
->mode
), minor(i
->mode
));
1418 r
= path_set_perms(i
, i
->path
);
1427 r
= glob_item(i
, path_set_perms
, false);
1432 case RECURSIVE_RELABEL_PATH
:
1433 r
= glob_item(i
, path_set_perms
, true);
1439 r
= glob_item(i
, path_set_xattrs
, false);
1444 case RECURSIVE_SET_XATTR
:
1445 r
= glob_item(i
, path_set_xattrs
, true);
1451 r
= glob_item(i
, path_set_acls
, false);
1456 case RECURSIVE_SET_ACL
:
1457 r
= glob_item(i
, path_set_acls
, true);
1463 r
= glob_item(i
, path_set_attribute
, false);
1468 case RECURSIVE_SET_ATTRIBUTE
:
1469 r
= glob_item(i
, path_set_attribute
, true);
1478 static int remove_item_instance(Item
*i
, const char *instance
) {
1486 if (remove(instance
) < 0 && errno
!= ENOENT
)
1487 return log_error_errno(errno
, "rm(%s): %m", instance
);
1491 case TRUNCATE_DIRECTORY
:
1492 case RECURSIVE_REMOVE_PATH
:
1493 /* FIXME: we probably should use dir_cleanup() here
1494 * instead of rm_rf() so that 'x' is honoured. */
1495 log_debug("rm -rf \"%s\"", instance
);
1496 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1497 if (r
< 0 && r
!= -ENOENT
)
1498 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1503 assert_not_reached("wut?");
1509 static int remove_item(Item
*i
) {
1514 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1520 case CREATE_DIRECTORY
:
1521 case CREATE_SUBVOLUME
:
1522 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1523 case CREATE_SUBVOLUME_NEW_QUOTA
:
1525 case CREATE_SYMLINK
:
1526 case CREATE_CHAR_DEVICE
:
1527 case CREATE_BLOCK_DEVICE
:
1529 case IGNORE_DIRECTORY_PATH
:
1532 case RECURSIVE_RELABEL_PATH
:
1536 case RECURSIVE_SET_XATTR
:
1538 case RECURSIVE_SET_ACL
:
1540 case RECURSIVE_SET_ATTRIBUTE
:
1544 case TRUNCATE_DIRECTORY
:
1545 case RECURSIVE_REMOVE_PATH
:
1546 r
= glob_item(i
, remove_item_instance
, false);
1553 static int clean_item_instance(Item
*i
, const char* instance
) {
1554 _cleanup_closedir_
DIR *d
= NULL
;
1558 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1565 n
= now(CLOCK_REALTIME
);
1569 cutoff
= n
- i
->age
;
1571 d
= opendir_nomod(instance
);
1573 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
1574 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1578 log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1582 if (fstat(dirfd(d
), &s
) < 0)
1583 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1585 if (!S_ISDIR(s
.st_mode
)) {
1586 log_error("%s is not a directory.", i
->path
);
1590 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1591 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1593 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1595 log_debug("Cleanup threshold for %s \"%s\" is %s",
1596 mountpoint
? "mount point" : "directory",
1598 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1600 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1601 MAX_DEPTH
, i
->keep_first_level
);
1604 static int clean_item(Item
*i
) {
1609 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1612 case CREATE_DIRECTORY
:
1613 case CREATE_SUBVOLUME
:
1614 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1615 case CREATE_SUBVOLUME_NEW_QUOTA
:
1616 case TRUNCATE_DIRECTORY
:
1619 clean_item_instance(i
, i
->path
);
1621 case IGNORE_DIRECTORY_PATH
:
1622 r
= glob_item(i
, clean_item_instance
, false);
1631 static int process_item_array(ItemArray
*array
);
1633 static int process_item(Item
*i
) {
1635 _cleanup_free_
char *prefix
= NULL
;
1644 prefix
= malloc(strlen(i
->path
) + 1);
1648 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1651 j
= ordered_hashmap_get(items
, prefix
);
1655 s
= process_item_array(j
);
1656 if (s
< 0 && t
== 0)
1661 r
= arg_create
? create_item(i
) : 0;
1662 q
= arg_remove
? remove_item(i
) : 0;
1663 p
= arg_clean
? clean_item(i
) : 0;
1671 static int process_item_array(ItemArray
*array
) {
1677 for (n
= 0; n
< array
->count
; n
++) {
1678 k
= process_item(array
->items
+ n
);
1679 if (k
< 0 && r
== 0)
1686 static void item_free_contents(Item
*i
) {
1690 strv_free(i
->xattrs
);
1693 acl_free(i
->acl_access
);
1694 acl_free(i
->acl_default
);
1698 static void item_array_free(ItemArray
*a
) {
1704 for (n
= 0; n
< a
->count
; n
++)
1705 item_free_contents(a
->items
+ n
);
1710 static int item_compare(const void *a
, const void *b
) {
1711 const Item
*x
= a
, *y
= b
;
1713 /* Make sure that the ownership taking item is put first, so
1714 * that we first create the node, and then can adjust it */
1716 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1718 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1721 return (int) x
->type
- (int) y
->type
;
1724 static bool item_compatible(Item
*a
, Item
*b
) {
1727 assert(streq(a
->path
, b
->path
));
1729 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1730 /* check if the items are the same */
1731 return streq_ptr(a
->argument
, b
->argument
) &&
1733 a
->uid_set
== b
->uid_set
&&
1736 a
->gid_set
== b
->gid_set
&&
1739 a
->mode_set
== b
->mode_set
&&
1740 a
->mode
== b
->mode
&&
1742 a
->age_set
== b
->age_set
&&
1745 a
->mask_perms
== b
->mask_perms
&&
1747 a
->keep_first_level
== b
->keep_first_level
&&
1749 a
->major_minor
== b
->major_minor
;
1754 static bool should_include_path(const char *path
) {
1757 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1758 if (path_startswith(path
, *prefix
)) {
1759 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1764 STRV_FOREACH(prefix
, arg_include_prefixes
)
1765 if (path_startswith(path
, *prefix
)) {
1766 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1770 /* no matches, so we should include this path only if we
1771 * have no whitelist at all */
1772 if (strv_length(arg_include_prefixes
) == 0)
1775 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1779 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1781 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1782 _cleanup_(item_free_contents
) Item i
= {};
1783 ItemArray
*existing
;
1786 bool force
= false, boot
= false;
1792 r
= extract_many_words(
1804 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1806 log_error("[%s:%u] Syntax error.", fname
, line
);
1810 if (!isempty(buffer
) && !streq(buffer
, "-")) {
1811 i
.argument
= strdup(buffer
);
1816 if (isempty(action
)) {
1817 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1821 for (pos
= 1; action
[pos
]; pos
++) {
1822 if (action
[pos
] == '!' && !boot
)
1824 else if (action
[pos
] == '+' && !force
)
1827 log_error("[%s:%u] Unknown modifiers in command '%s'",
1828 fname
, line
, action
);
1833 if (boot
&& !arg_boot
) {
1834 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1842 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1844 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1850 case CREATE_DIRECTORY
:
1851 case CREATE_SUBVOLUME
:
1852 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1853 case CREATE_SUBVOLUME_NEW_QUOTA
:
1854 case TRUNCATE_DIRECTORY
:
1857 case IGNORE_DIRECTORY_PATH
:
1859 case RECURSIVE_REMOVE_PATH
:
1862 case RECURSIVE_RELABEL_PATH
:
1864 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
1872 case CREATE_SYMLINK
:
1874 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1882 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1889 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1892 } else if (!path_is_absolute(i
.argument
)) {
1893 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1897 path_kill_slashes(i
.argument
);
1900 case CREATE_CHAR_DEVICE
:
1901 case CREATE_BLOCK_DEVICE
: {
1902 unsigned major
, minor
;
1905 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1909 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1910 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1914 i
.major_minor
= makedev(major
, minor
);
1919 case RECURSIVE_SET_XATTR
:
1921 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1924 r
= parse_xattrs_from_arg(&i
);
1930 case RECURSIVE_SET_ACL
:
1932 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
1935 r
= parse_acls_from_arg(&i
);
1941 case RECURSIVE_SET_ATTRIBUTE
:
1943 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
1946 r
= parse_attribute_from_arg(&i
);
1952 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
1956 if (!path_is_absolute(i
.path
)) {
1957 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
1961 path_kill_slashes(i
.path
);
1963 if (!should_include_path(i
.path
))
1969 p
= prefix_root(arg_root
, i
.path
);
1977 if (!isempty(user
) && !streq(user
, "-")) {
1978 const char *u
= user
;
1980 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
1982 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
1989 if (!isempty(group
) && !streq(group
, "-")) {
1990 const char *g
= group
;
1992 r
= get_group_creds(&g
, &i
.gid
);
1994 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2001 if (!isempty(mode
) && !streq(mode
, "-")) {
2002 const char *mm
= mode
;
2006 i
.mask_perms
= true;
2010 if (parse_mode(mm
, &m
) < 0) {
2011 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2018 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2020 if (!isempty(age
) && !streq(age
, "-")) {
2021 const char *a
= age
;
2024 i
.keep_first_level
= true;
2028 if (parse_sec(a
, &i
.age
) < 0) {
2029 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2036 h
= needs_glob(i
.type
) ? globs
: items
;
2038 existing
= ordered_hashmap_get(h
, i
.path
);
2042 for (n
= 0; n
< existing
->count
; n
++) {
2043 if (!item_compatible(existing
->items
+ n
, &i
)) {
2044 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2045 fname
, line
, i
.path
);
2050 existing
= new0(ItemArray
, 1);
2051 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2056 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2059 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2061 /* Sort item array, to enforce stable ordering of application */
2062 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2068 static void help(void) {
2069 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2070 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2071 " -h --help Show this help\n"
2072 " --version Show package version\n"
2073 " --create Create marked files/directories\n"
2074 " --clean Clean up marked directories\n"
2075 " --remove Remove marked files/directories\n"
2076 " --boot Execute actions only safe at boot\n"
2077 " --prefix=PATH Only apply rules with the specified prefix\n"
2078 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2079 " --root=PATH Operate on an alternate filesystem root\n",
2080 program_invocation_short_name
);
2083 static int parse_argv(int argc
, char *argv
[]) {
2086 ARG_VERSION
= 0x100,
2096 static const struct option options
[] = {
2097 { "help", no_argument
, NULL
, 'h' },
2098 { "version", no_argument
, NULL
, ARG_VERSION
},
2099 { "create", no_argument
, NULL
, ARG_CREATE
},
2100 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2101 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2102 { "boot", no_argument
, NULL
, ARG_BOOT
},
2103 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2104 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2105 { "root", required_argument
, NULL
, ARG_ROOT
},
2114 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2142 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2146 case ARG_EXCLUDE_PREFIX
:
2147 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2152 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2161 assert_not_reached("Unhandled option");
2164 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2165 log_error("You need to specify at least one of --clean, --create or --remove.");
2172 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2173 _cleanup_fclose_
FILE *f
= NULL
;
2174 char line
[LINE_MAX
];
2182 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &f
);
2184 if (ignore_enoent
&& r
== -ENOENT
) {
2185 log_debug_errno(r
, "Failed to open \"%s\": %m", fn
);
2189 return log_error_errno(r
, "Failed to open '%s', ignoring: %m", fn
);
2191 log_debug("Reading config file \"%s\".", fn
);
2193 FOREACH_LINE(line
, f
, break) {
2200 if (*l
== '#' || *l
== 0)
2203 k
= parse_line(fn
, v
, l
);
2204 if (k
< 0 && r
== 0)
2208 /* we have to determine age parameter for each entry of type X */
2209 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2211 Item
*j
, *candidate_item
= NULL
;
2213 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2216 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2217 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2220 if (path_equal(j
->path
, i
->path
)) {
2225 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2226 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2230 if (candidate_item
&& candidate_item
->age_set
) {
2231 i
->age
= candidate_item
->age
;
2237 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2245 int main(int argc
, char *argv
[]) {
2250 r
= parse_argv(argc
, argv
);
2254 log_set_target(LOG_TARGET_AUTO
);
2255 log_parse_environment();
2260 mac_selinux_init(NULL
);
2262 items
= ordered_hashmap_new(&string_hash_ops
);
2263 globs
= ordered_hashmap_new(&string_hash_ops
);
2265 if (!items
|| !globs
) {
2272 if (optind
< argc
) {
2275 for (j
= optind
; j
< argc
; j
++) {
2276 k
= read_config_file(argv
[j
], false);
2277 if (k
< 0 && r
== 0)
2282 _cleanup_strv_free_
char **files
= NULL
;
2285 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, conf_file_dirs
);
2287 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2291 STRV_FOREACH(f
, files
) {
2292 k
= read_config_file(*f
, true);
2293 if (k
< 0 && r
== 0)
2298 /* The non-globbing ones usually create things, hence we apply
2300 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2301 k
= process_item_array(a
);
2302 if (k
< 0 && r
== 0)
2306 /* The globbing ones usually alter things, hence we apply them
2308 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2309 k
= process_item_array(a
);
2310 if (k
< 0 && r
== 0)
2315 while ((a
= ordered_hashmap_steal_first(items
)))
2318 while ((a
= ordered_hashmap_steal_first(globs
)))
2321 ordered_hashmap_free(items
);
2322 ordered_hashmap_free(globs
);
2324 free(arg_include_prefixes
);
2325 free(arg_exclude_prefixes
);
2328 set_free_free(unix_sockets
);
2330 mac_selinux_finish();
2332 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;