1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering, Kay Sievers
6 Copyright 2015 Zbigniew Jędrzejewski-Szmek
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/>.
35 #include <sys/xattr.h>
40 #include "alloc-util.h"
41 #include "btrfs-util.h"
42 #include "capability-util.h"
43 #include "chattr-util.h"
44 #include "conf-files.h"
47 #include "dirent-util.h"
51 #include "format-util.h"
53 #include "glob-util.h"
60 #include "mount-util.h"
61 #include "parse-util.h"
62 #include "path-util.h"
64 #include "selinux-util.h"
66 #include "specifier.h"
67 #include "stat-util.h"
68 #include "stdio-util.h"
69 #include "string-table.h"
70 #include "string-util.h"
72 #include "umask-util.h"
73 #include "user-util.h"
76 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
77 * them in the file system. This is intended to be used to create
78 * properly owned directories beneath /tmp, /var/tmp, /run, which are
79 * volatile and hence need to be recreated on bootup. */
81 typedef enum ItemType
{
82 /* These ones take file names */
85 CREATE_DIRECTORY
= 'd',
86 TRUNCATE_DIRECTORY
= 'D',
87 CREATE_SUBVOLUME
= 'v',
88 CREATE_SUBVOLUME_INHERIT_QUOTA
= 'q',
89 CREATE_SUBVOLUME_NEW_QUOTA
= 'Q',
92 CREATE_CHAR_DEVICE
= 'c',
93 CREATE_BLOCK_DEVICE
= 'b',
96 /* These ones take globs */
98 EMPTY_DIRECTORY
= 'e',
100 RECURSIVE_SET_XATTR
= 'T',
102 RECURSIVE_SET_ACL
= 'A',
104 RECURSIVE_SET_ATTRIBUTE
= 'H',
106 IGNORE_DIRECTORY_PATH
= 'X',
108 RECURSIVE_REMOVE_PATH
= 'R',
110 RECURSIVE_RELABEL_PATH
= 'Z',
111 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
114 typedef struct Item
{
130 unsigned attribute_value
;
131 unsigned attribute_mask
;
138 bool attribute_set
:1;
140 bool keep_first_level
:1;
147 typedef struct ItemArray
{
153 static bool arg_create
= false;
154 static bool arg_clean
= false;
155 static bool arg_remove
= false;
156 static bool arg_boot
= false;
158 static char **arg_include_prefixes
= NULL
;
159 static char **arg_exclude_prefixes
= NULL
;
160 static char *arg_root
= NULL
;
162 static const char conf_file_dirs
[] = CONF_PATHS_NULSTR("tmpfiles.d");
164 #define MAX_DEPTH 256
166 static OrderedHashmap
*items
= NULL
, *globs
= NULL
;
167 static Set
*unix_sockets
= NULL
;
169 static int specifier_machine_id_safe(char specifier
, void *data
, void *userdata
, char **ret
);
171 static const Specifier specifier_table
[] = {
172 { 'm', specifier_machine_id_safe
, NULL
},
173 { 'b', specifier_boot_id
, NULL
},
174 { 'H', specifier_host_name
, NULL
},
175 { 'v', specifier_kernel_release
, NULL
},
179 static int specifier_machine_id_safe(char specifier
, void *data
, void *userdata
, char **ret
) {
182 /* If /etc/machine_id is missing (e.g. in a chroot environment), returns
183 * a recognizable error so that the caller can skip the rule
186 r
= specifier_machine_id(specifier
, data
, userdata
, ret
);
193 static int log_unresolvable_specifier(const char *filename
, unsigned line
) {
194 static bool notified
= false;
196 /* This is called when /etc is not fully initialized (e.g. in a chroot
197 * environment) where some specifiers are unresolvable. These cases are
198 * not considered as an error so log at LOG_NOTICE only for the first
199 * time and then downgrade this to LOG_DEBUG for the rest. */
201 log_full(notified
? LOG_DEBUG
: LOG_NOTICE
,
202 "[%s:%u] Failed to resolve specifier: uninitialized /etc detected, skipping",
206 log_notice("All rules containing unresolvable specifiers will be skipped.");
212 static bool needs_glob(ItemType t
) {
216 IGNORE_DIRECTORY_PATH
,
218 RECURSIVE_REMOVE_PATH
,
222 RECURSIVE_RELABEL_PATH
,
228 RECURSIVE_SET_ATTRIBUTE
);
231 static bool takes_ownership(ItemType t
) {
239 CREATE_SUBVOLUME_INHERIT_QUOTA
,
240 CREATE_SUBVOLUME_NEW_QUOTA
,
248 IGNORE_DIRECTORY_PATH
,
250 RECURSIVE_REMOVE_PATH
);
253 static struct Item
* find_glob(OrderedHashmap
*h
, const char *match
) {
257 ORDERED_HASHMAP_FOREACH(j
, h
, i
) {
260 for (n
= 0; n
< j
->count
; n
++) {
261 Item
*item
= j
->items
+ n
;
263 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
271 static void load_unix_sockets(void) {
272 _cleanup_fclose_
FILE *f
= NULL
;
278 /* We maintain a cache of the sockets we found in
279 * /proc/net/unix to speed things up a little. */
281 unix_sockets
= set_new(&string_hash_ops
);
285 f
= fopen("/proc/net/unix", "re");
290 if (!fgets(line
, sizeof(line
), f
))
297 if (!fgets(line
, sizeof(line
), f
))
302 p
= strchr(line
, ':');
310 p
+= strspn(p
, WHITESPACE
);
311 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
312 p
+= strspn(p
, WHITESPACE
);
321 path_kill_slashes(s
);
323 k
= set_consume(unix_sockets
, s
);
324 if (k
< 0 && k
!= -EEXIST
)
331 set_free_free(unix_sockets
);
335 static bool unix_socket_alive(const char *fn
) {
341 return !!set_get(unix_sockets
, (char*) fn
);
343 /* We don't know, so assume yes */
347 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
349 int mount_id_parent
, mount_id
;
352 r_p
= name_to_handle_at_loop(dirfd(d
), ".", NULL
, &mount_id_parent
, 0);
356 r
= name_to_handle_at_loop(dirfd(d
), subdir
, NULL
, &mount_id
, 0);
360 /* got no handle; make no assumptions, return error */
361 if (r_p
< 0 && r
< 0)
364 /* got both handles; if they differ, it is a mount point */
365 if (r_p
>= 0 && r
>= 0)
366 return mount_id_parent
!= mount_id
;
368 /* got only one handle; assume different mount points if one
369 * of both queries was not supported by the filesystem */
370 if (IN_SET(r_p
, -ENOSYS
, -EOPNOTSUPP
) || IN_SET(r
, -ENOSYS
, -EOPNOTSUPP
))
379 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
382 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
386 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
390 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
392 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
397 static DIR* opendir_nomod(const char *path
) {
398 return xopendirat_nomod(AT_FDCWD
, path
);
401 static int dir_cleanup(
405 const struct stat
*ds
,
410 bool keep_this_level
) {
413 struct timespec times
[2];
414 bool deleted
= false;
417 FOREACH_DIRENT_ALL(dent
, d
, break) {
420 _cleanup_free_
char *sub_path
= NULL
;
422 if (dot_or_dot_dot(dent
->d_name
))
425 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
429 /* FUSE, NFS mounts, SELinux might return EACCES */
431 log_debug_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
433 log_error_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
438 /* Stay on the same filesystem */
439 if (s
.st_dev
!= rootdev
) {
440 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
444 /* Try to detect bind mounts of the same filesystem instance; they
445 * do not differ in device major/minors. This type of query is not
446 * supported on all kernels or filesystem types though. */
447 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
448 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
453 /* Do not delete read-only files owned by root */
454 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
)) {
455 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p
, dent
->d_name
);
459 sub_path
= strjoin(p
, "/", dent
->d_name
);
465 /* Is there an item configured for this path? */
466 if (ordered_hashmap_get(items
, sub_path
)) {
467 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
471 if (find_glob(globs
, sub_path
)) {
472 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
476 if (S_ISDIR(s
.st_mode
)) {
479 streq(dent
->d_name
, "lost+found") &&
481 log_debug("Ignoring \"%s\".", sub_path
);
486 log_warning("Reached max depth on \"%s\".", sub_path
);
488 _cleanup_closedir_
DIR *sub_dir
;
491 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
494 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
499 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
504 /* Note: if you are wondering why we don't
505 * support the sticky bit for excluding
506 * directories from cleaning like we do it for
507 * other file system objects: well, the sticky
508 * bit already has a meaning for directories,
509 * so we don't want to overload that. */
511 if (keep_this_level
) {
512 log_debug("Keeping \"%s\".", sub_path
);
516 /* Ignore ctime, we change it when deleting */
517 age
= timespec_load(&s
.st_mtim
);
519 char a
[FORMAT_TIMESTAMP_MAX
];
520 /* Follows spelling in stat(1). */
521 log_debug("Directory \"%s\": modify time %s is too new.",
523 format_timestamp_us(a
, sizeof(a
), age
));
527 age
= timespec_load(&s
.st_atim
);
529 char a
[FORMAT_TIMESTAMP_MAX
];
530 log_debug("Directory \"%s\": access time %s is too new.",
532 format_timestamp_us(a
, sizeof(a
), age
));
536 log_debug("Removing directory \"%s\".", sub_path
);
537 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
538 if (!IN_SET(errno
, ENOENT
, ENOTEMPTY
)) {
539 log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
544 /* Skip files for which the sticky bit is
545 * set. These are semantics we define, and are
546 * unknown elsewhere. See XDG_RUNTIME_DIR
547 * specification for details. */
548 if (s
.st_mode
& S_ISVTX
) {
549 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
553 if (mountpoint
&& S_ISREG(s
.st_mode
))
554 if (s
.st_uid
== 0 && STR_IN_SET(dent
->d_name
,
558 log_debug("Skipping \"%s\".", sub_path
);
562 /* Ignore sockets that are listed in /proc/net/unix */
563 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
564 log_debug("Skipping \"%s\": live socket.", sub_path
);
568 /* Ignore device nodes */
569 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
570 log_debug("Skipping \"%s\": a device.", sub_path
);
574 /* Keep files on this level around if this is
576 if (keep_this_level
) {
577 log_debug("Keeping \"%s\".", sub_path
);
581 age
= timespec_load(&s
.st_mtim
);
583 char a
[FORMAT_TIMESTAMP_MAX
];
584 /* Follows spelling in stat(1). */
585 log_debug("File \"%s\": modify time %s is too new.",
587 format_timestamp_us(a
, sizeof(a
), age
));
591 age
= timespec_load(&s
.st_atim
);
593 char a
[FORMAT_TIMESTAMP_MAX
];
594 log_debug("File \"%s\": access time %s is too new.",
596 format_timestamp_us(a
, sizeof(a
), age
));
600 age
= timespec_load(&s
.st_ctim
);
602 char a
[FORMAT_TIMESTAMP_MAX
];
603 log_debug("File \"%s\": change time %s is too new.",
605 format_timestamp_us(a
, sizeof(a
), age
));
609 log_debug("unlink \"%s\"", sub_path
);
611 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
613 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
622 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
624 /* Restore original directory timestamps */
625 times
[0] = ds
->st_atim
;
626 times
[1] = ds
->st_mtim
;
628 age1
= timespec_load(&ds
->st_atim
);
629 age2
= timespec_load(&ds
->st_mtim
);
630 log_debug("Restoring access and modification time on \"%s\": %s, %s",
632 format_timestamp_us(a
, sizeof(a
), age1
),
633 format_timestamp_us(b
, sizeof(b
), age2
));
634 if (futimens(dirfd(d
), times
) < 0)
635 log_error_errno(errno
, "utimensat(%s): %m", p
);
641 static int path_set_perms(Item
*i
, const char *path
) {
642 _cleanup_close_
int fd
= -1;
648 /* We open the file with O_PATH here, to make the operation
649 * somewhat atomic. Also there's unfortunately no fchmodat()
650 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
653 fd
= open(path
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
655 int level
= LOG_ERR
, r
= -errno
;
657 /* Option "e" operates only on existing objects. Do not
658 * print errors about non-existent files or directories */
659 if (i
->type
== EMPTY_DIRECTORY
&& errno
== ENOENT
) {
664 log_full_errno(level
, errno
, "Adjusting owner and mode for %s failed: %m", path
);
669 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
670 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
672 if (S_ISLNK(st
.st_mode
))
673 log_debug("Skipping mode an owner fix for symlink %s.", path
);
675 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
676 xsprintf(fn
, "/proc/self/fd/%i", fd
);
678 /* not using i->path directly because it may be a glob */
683 if (!(st
.st_mode
& 0111))
685 if (!(st
.st_mode
& 0222))
687 if (!(st
.st_mode
& 0444))
689 if (!S_ISDIR(st
.st_mode
))
690 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
693 if (m
== (st
.st_mode
& 07777))
694 log_debug("\"%s\" has right mode %o", path
, st
.st_mode
);
696 log_debug("chmod \"%s\" to mode %o", path
, m
);
697 if (chmod(fn
, m
) < 0)
698 return log_error_errno(errno
, "chmod() of %s via %s failed: %m", path
, fn
);
702 if ((i
->uid
!= st
.st_uid
|| i
->gid
!= st
.st_gid
) &&
703 (i
->uid_set
|| i
->gid_set
)) {
704 log_debug("chown \"%s\" to "UID_FMT
"."GID_FMT
,
706 i
->uid_set
? i
->uid
: UID_INVALID
,
707 i
->gid_set
? i
->gid
: GID_INVALID
);
709 i
->uid_set
? i
->uid
: UID_INVALID
,
710 i
->gid_set
? i
->gid
: GID_INVALID
) < 0)
711 return log_error_errno(errno
, "chown() of %s via %s failed: %m", path
, fn
);
717 return label_fix(path
, false, false);
720 static int parse_xattrs_from_arg(Item
*i
) {
730 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
;
732 r
= extract_first_word(&p
, &xattr
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
734 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
738 r
= split_pair(xattr
, "=", &name
, &value
);
740 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
744 if (isempty(name
) || isempty(value
)) {
745 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
749 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
758 static int path_set_xattrs(Item
*i
, const char *path
) {
759 char **name
, **value
;
764 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
768 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
769 if (lsetxattr(path
, *name
, *value
, n
, 0) < 0)
770 return log_error_errno(errno
, "Setting extended attribute %s=%s on %s failed: %m",
771 *name
, *value
, path
);
776 static int parse_acls_from_arg(Item
*item
) {
782 /* If force (= modify) is set, we will not modify the acl
783 * afterwards, so the mask can be added now if necessary. */
785 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
787 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
789 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
796 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
797 _cleanup_(acl_free_charpp
) char *t
= NULL
;
798 _cleanup_(acl_freep
) acl_t dup
= NULL
;
801 /* Returns 0 for success, positive error if already warned,
802 * negative error otherwise. */
805 r
= acls_for_file(path
, type
, acl
, &dup
);
809 r
= calc_acl_mask_if_needed(&dup
);
817 /* the mask was already added earlier if needed */
820 r
= add_base_acls_if_needed(&dup
, path
);
824 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
825 log_debug("Setting %s ACL %s on %s.",
826 type
== ACL_TYPE_ACCESS
? "access" : "default",
829 r
= acl_set_file(path
, type
, dup
);
831 /* Return positive to indicate we already warned */
832 return -log_error_errno(errno
,
833 "Setting %s ACL \"%s\" on %s failed: %m",
834 type
== ACL_TYPE_ACCESS
? "access" : "default",
841 static int path_set_acls(Item
*item
, const char *path
) {
844 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
845 _cleanup_close_
int fd
= -1;
851 fd
= open(path
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
853 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
855 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
856 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
858 if (S_ISLNK(st
.st_mode
)) {
859 log_debug("Skipping ACL fix for symlink %s.", path
);
863 xsprintf(fn
, "/proc/self/fd/%i", fd
);
865 if (item
->acl_access
)
866 r
= path_set_acl(fn
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
868 if (r
== 0 && item
->acl_default
)
869 r
= path_set_acl(fn
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
872 return -r
; /* already warned */
873 else if (r
== -EOPNOTSUPP
) {
874 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
877 log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
882 #define ATTRIBUTES_ALL \
891 FS_JOURNAL_DATA_FL | \
898 static int parse_attribute_from_arg(Item
*item
) {
900 static const struct {
904 { 'A', FS_NOATIME_FL
}, /* do not update atime */
905 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
906 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
907 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
908 { 'c', FS_COMPR_FL
}, /* Compress file */
909 { 'd', FS_NODUMP_FL
}, /* do not dump file */
910 { 'e', FS_EXTENT_FL
}, /* Extents */
911 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
912 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
913 { 's', FS_SECRM_FL
}, /* Secure deletion */
914 { 'u', FS_UNRM_FL
}, /* Undelete */
915 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
916 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies */
917 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
926 unsigned value
= 0, mask
= 0;
936 } else if (*p
== '-') {
939 } else if (*p
== '=') {
945 if (isempty(p
) && mode
!= MODE_SET
) {
946 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
950 for (; p
&& *p
; p
++) {
953 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
954 if (*p
== attributes
[i
].character
)
957 if (i
>= ELEMENTSOF(attributes
)) {
958 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
962 v
= attributes
[i
].value
;
964 SET_FLAG(value
, v
, IN_SET(mode
, MODE_ADD
, MODE_SET
));
969 if (mode
== MODE_SET
)
970 mask
|= ATTRIBUTES_ALL
;
974 item
->attribute_mask
= mask
;
975 item
->attribute_value
= value
;
976 item
->attribute_set
= true;
981 static int path_set_attribute(Item
*item
, const char *path
) {
982 _cleanup_close_
int fd
= -1;
987 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
990 fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
|O_NOATIME
|O_NOFOLLOW
);
993 return log_error_errno(errno
, "Skipping file attributes adjustment on symlink %s.", path
);
995 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
998 if (fstat(fd
, &st
) < 0)
999 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
1001 /* Issuing the file attribute ioctls on device nodes is not
1002 * safe, as that will be delivered to the drivers, not the
1003 * file system containing the device node. */
1004 if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
)) {
1005 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
1009 f
= item
->attribute_value
& item
->attribute_mask
;
1011 /* Mask away directory-specific flags */
1012 if (!S_ISDIR(st
.st_mode
))
1013 f
&= ~FS_DIRSYNC_FL
;
1015 r
= chattr_fd(fd
, f
, item
->attribute_mask
);
1017 log_full_errno(IN_SET(r
, -ENOTTY
, -EOPNOTSUPP
) ? LOG_DEBUG
: LOG_WARNING
,
1019 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
1020 path
, item
->attribute_value
, item
->attribute_mask
);
1025 static int write_one_file(Item
*i
, const char *path
) {
1026 _cleanup_close_
int fd
= -1;
1033 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
|O_NOFOLLOW
:
1034 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
1036 RUN_WITH_UMASK(0000) {
1037 mac_selinux_create_file_prepare(path
, S_IFREG
);
1038 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
1039 mac_selinux_create_file_clear();
1043 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
1044 log_debug_errno(errno
, "Not writing \"%s\": %m", path
);
1049 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
1050 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
1053 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1057 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1059 r
= loop_write(fd
, i
->argument
, strlen(i
->argument
), false);
1061 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1063 log_debug("\"%s\" has been created.", path
);
1065 fd
= safe_close(fd
);
1067 if (stat(path
, &st
) < 0)
1068 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1071 if (!S_ISREG(st
.st_mode
)) {
1072 log_error("%s is not a file.", path
);
1076 r
= path_set_perms(i
, path
);
1083 typedef int (*action_t
)(Item
*, const char *);
1085 static int item_do_children(Item
*i
, const char *path
, action_t action
) {
1086 _cleanup_closedir_
DIR *d
;
1093 /* This returns the first error we run into, but nevertheless
1096 d
= opendir_nomod(path
);
1098 return IN_SET(errno
, ENOENT
, ENOTDIR
, ELOOP
) ? 0 : -errno
;
1100 FOREACH_DIRENT_ALL(de
, d
, r
= -errno
) {
1101 _cleanup_free_
char *p
= NULL
;
1104 if (dot_or_dot_dot(de
->d_name
))
1107 p
= strjoin(path
, "/", de
->d_name
);
1112 if (q
< 0 && q
!= -ENOENT
&& r
== 0)
1115 if (IN_SET(de
->d_type
, DT_UNKNOWN
, DT_DIR
)) {
1116 q
= item_do_children(i
, p
, action
);
1117 if (q
< 0 && r
== 0)
1125 static int glob_item(Item
*i
, action_t action
, bool recursive
) {
1126 _cleanup_globfree_ glob_t g
= {
1127 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1132 k
= safe_glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
, &g
);
1133 if (k
< 0 && k
!= -ENOENT
)
1134 return log_error_errno(k
, "glob(%s) failed: %m", i
->path
);
1136 STRV_FOREACH(fn
, g
.gl_pathv
) {
1138 if (k
< 0 && r
== 0)
1142 k
= item_do_children(i
, *fn
, action
);
1143 if (k
< 0 && r
== 0)
1156 _CREATION_MODE_INVALID
= -1
1159 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1160 [CREATION_NORMAL
] = "Created",
1161 [CREATION_EXISTING
] = "Found existing",
1162 [CREATION_FORCE
] = "Created replacement",
1165 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1167 static int create_item(Item
*i
) {
1171 CreationMode creation
;
1175 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1180 case IGNORE_DIRECTORY_PATH
:
1182 case RECURSIVE_REMOVE_PATH
:
1187 r
= write_one_file(i
, i
->path
);
1193 log_debug("Copying tree \"%s\" to \"%s\".", i
->argument
, i
->path
);
1194 r
= copy_tree(i
->argument
, i
->path
, i
->uid_set
? i
->uid
: UID_INVALID
, i
->gid_set
? i
->gid
: GID_INVALID
, COPY_REFLINK
);
1196 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1203 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1205 if (stat(i
->argument
, &a
) < 0)
1206 return log_error_errno(errno
, "stat(%s) failed: %m", i
->argument
);
1208 if (stat(i
->path
, &b
) < 0)
1209 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1211 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1212 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1217 r
= path_set_perms(i
, i
->path
);
1224 r
= glob_item(i
, write_one_file
, false);
1230 case CREATE_DIRECTORY
:
1231 case TRUNCATE_DIRECTORY
:
1232 case CREATE_SUBVOLUME
:
1233 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1234 case CREATE_SUBVOLUME_NEW_QUOTA
:
1235 RUN_WITH_UMASK(0000)
1236 mkdir_parents_label(i
->path
, 0755);
1238 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1240 if (btrfs_is_subvol(isempty(arg_root
) ? "/" : arg_root
) <= 0)
1242 /* Don't create a subvolume unless the
1243 * root directory is one, too. We do
1244 * this under the assumption that if
1245 * the root directory is just a plain
1246 * directory (i.e. very light-weight),
1247 * we shouldn't try to split it up
1248 * into subvolumes (i.e. more
1249 * heavy-weight). Thus, chroot()
1250 * environments and suchlike will get
1251 * a full brtfs subvolume set up below
1252 * their tree only if they
1253 * specifically set up a btrfs
1254 * subvolume for the root dir too. */
1258 RUN_WITH_UMASK((~i
->mode
) & 0777)
1259 r
= btrfs_subvol_make(i
->path
);
1264 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1265 RUN_WITH_UMASK(0000)
1266 r
= mkdir_label(i
->path
, i
->mode
);
1271 if (!IN_SET(r
, -EEXIST
, -EROFS
))
1272 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1274 k
= is_dir(i
->path
, false);
1275 if (k
== -ENOENT
&& r
== -EROFS
)
1276 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1278 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1280 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1284 creation
= CREATION_EXISTING
;
1286 creation
= CREATION_NORMAL
;
1288 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1290 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1291 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1293 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i
->path
);
1294 else if (r
== -EROFS
)
1295 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i
->path
);
1296 else if (r
== -ENOPROTOOPT
)
1297 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i
->path
);
1299 q
= log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1301 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1303 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1307 case EMPTY_DIRECTORY
:
1308 r
= path_set_perms(i
, i
->path
);
1317 RUN_WITH_UMASK(0000) {
1318 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1319 r
= mkfifo(i
->path
, i
->mode
);
1320 mac_selinux_create_file_clear();
1324 if (errno
!= EEXIST
)
1325 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1327 if (lstat(i
->path
, &st
) < 0)
1328 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1330 if (!S_ISFIFO(st
.st_mode
)) {
1333 RUN_WITH_UMASK(0000) {
1334 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1335 r
= mkfifo_atomic(i
->path
, i
->mode
);
1336 mac_selinux_create_file_clear();
1340 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1341 creation
= CREATION_FORCE
;
1343 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1347 creation
= CREATION_EXISTING
;
1349 creation
= CREATION_NORMAL
;
1350 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1352 r
= path_set_perms(i
, i
->path
);
1359 case CREATE_SYMLINK
: {
1360 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1361 r
= symlink(i
->argument
, i
->path
);
1362 mac_selinux_create_file_clear();
1365 _cleanup_free_
char *x
= NULL
;
1367 if (errno
!= EEXIST
)
1368 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1370 r
= readlink_malloc(i
->path
, &x
);
1371 if (r
< 0 || !streq(i
->argument
, x
)) {
1374 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1375 r
= symlink_atomic(i
->argument
, i
->path
);
1376 mac_selinux_create_file_clear();
1378 if (IN_SET(r
, -EEXIST
, -ENOTEMPTY
)) {
1379 r
= rm_rf(i
->path
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
1381 return log_error_errno(r
, "rm -fr %s failed: %m", i
->path
);
1383 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1384 r
= symlink(i
->argument
, i
->path
) < 0 ? -errno
: 0;
1385 mac_selinux_create_file_clear();
1388 return log_error_errno(r
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1390 creation
= CREATION_FORCE
;
1392 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1396 creation
= CREATION_EXISTING
;
1399 creation
= CREATION_NORMAL
;
1400 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1404 case CREATE_BLOCK_DEVICE
:
1405 case CREATE_CHAR_DEVICE
: {
1408 if (have_effective_cap(CAP_MKNOD
) == 0) {
1409 /* In a container we lack CAP_MKNOD. We
1410 shouldn't attempt to create the device node in
1411 that case to avoid noise, and we don't support
1412 virtualized devices in containers anyway. */
1414 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1418 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1420 RUN_WITH_UMASK(0000) {
1421 mac_selinux_create_file_prepare(i
->path
, file_type
);
1422 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1423 mac_selinux_create_file_clear();
1427 if (errno
== EPERM
) {
1428 log_debug("We lack permissions, possibly because of cgroup configuration; "
1429 "skipping creation of device node %s.", i
->path
);
1433 if (errno
!= EEXIST
)
1434 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1436 if (lstat(i
->path
, &st
) < 0)
1437 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1439 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1443 RUN_WITH_UMASK(0000) {
1444 mac_selinux_create_file_prepare(i
->path
, file_type
);
1445 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1446 mac_selinux_create_file_clear();
1450 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1451 creation
= CREATION_FORCE
;
1453 log_debug("%s is not a device node.", i
->path
);
1457 creation
= CREATION_EXISTING
;
1459 creation
= CREATION_NORMAL
;
1461 log_debug("%s %s device node \"%s\" %u:%u.",
1462 creation_mode_verb_to_string(creation
),
1463 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1464 i
->path
, major(i
->mode
), minor(i
->mode
));
1466 r
= path_set_perms(i
, i
->path
);
1475 r
= glob_item(i
, path_set_perms
, false);
1480 case RECURSIVE_RELABEL_PATH
:
1481 r
= glob_item(i
, path_set_perms
, true);
1487 r
= glob_item(i
, path_set_xattrs
, false);
1492 case RECURSIVE_SET_XATTR
:
1493 r
= glob_item(i
, path_set_xattrs
, true);
1499 r
= glob_item(i
, path_set_acls
, false);
1504 case RECURSIVE_SET_ACL
:
1505 r
= glob_item(i
, path_set_acls
, true);
1511 r
= glob_item(i
, path_set_attribute
, false);
1516 case RECURSIVE_SET_ATTRIBUTE
:
1517 r
= glob_item(i
, path_set_attribute
, true);
1526 static int remove_item_instance(Item
*i
, const char *instance
) {
1534 if (remove(instance
) < 0 && errno
!= ENOENT
)
1535 return log_error_errno(errno
, "rm(%s): %m", instance
);
1539 case TRUNCATE_DIRECTORY
:
1540 case RECURSIVE_REMOVE_PATH
:
1541 /* FIXME: we probably should use dir_cleanup() here
1542 * instead of rm_rf() so that 'x' is honoured. */
1543 log_debug("rm -rf \"%s\"", instance
);
1544 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1545 if (r
< 0 && r
!= -ENOENT
)
1546 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1551 assert_not_reached("wut?");
1557 static int remove_item(Item
*i
) {
1560 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1565 case TRUNCATE_DIRECTORY
:
1566 case RECURSIVE_REMOVE_PATH
:
1567 return glob_item(i
, remove_item_instance
, false);
1574 static int clean_item_instance(Item
*i
, const char* instance
) {
1575 _cleanup_closedir_
DIR *d
= NULL
;
1579 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1586 n
= now(CLOCK_REALTIME
);
1590 cutoff
= n
- i
->age
;
1592 d
= opendir_nomod(instance
);
1594 if (IN_SET(errno
, ENOENT
, ENOTDIR
)) {
1595 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1599 return log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1602 if (fstat(dirfd(d
), &s
) < 0)
1603 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1605 if (!S_ISDIR(s
.st_mode
)) {
1606 log_error("%s is not a directory.", i
->path
);
1610 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1611 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1613 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1615 log_debug("Cleanup threshold for %s \"%s\" is %s",
1616 mountpoint
? "mount point" : "directory",
1618 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1620 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1621 MAX_DEPTH
, i
->keep_first_level
);
1624 static int clean_item(Item
*i
) {
1627 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1630 case CREATE_DIRECTORY
:
1631 case CREATE_SUBVOLUME
:
1632 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1633 case CREATE_SUBVOLUME_NEW_QUOTA
:
1634 case EMPTY_DIRECTORY
:
1635 case TRUNCATE_DIRECTORY
:
1638 clean_item_instance(i
, i
->path
);
1640 case IGNORE_DIRECTORY_PATH
:
1641 return glob_item(i
, clean_item_instance
, false);
1647 static int process_item_array(ItemArray
*array
);
1649 static int process_item(Item
*i
) {
1651 _cleanup_free_
char *prefix
= NULL
;
1660 prefix
= malloc(strlen(i
->path
) + 1);
1664 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1667 j
= ordered_hashmap_get(items
, prefix
);
1671 s
= process_item_array(j
);
1672 if (s
< 0 && t
== 0)
1677 if (chase_symlinks(i
->path
, NULL
, CHASE_NO_AUTOFS
, NULL
) == -EREMOTE
)
1680 r
= arg_create
? create_item(i
) : 0;
1681 q
= arg_remove
? remove_item(i
) : 0;
1682 p
= arg_clean
? clean_item(i
) : 0;
1690 static int process_item_array(ItemArray
*array
) {
1696 for (n
= 0; n
< array
->count
; n
++) {
1697 k
= process_item(array
->items
+ n
);
1698 if (k
< 0 && r
== 0)
1705 static void item_free_contents(Item
*i
) {
1709 strv_free(i
->xattrs
);
1712 acl_free(i
->acl_access
);
1713 acl_free(i
->acl_default
);
1717 static void item_array_free(ItemArray
*a
) {
1723 for (n
= 0; n
< a
->count
; n
++)
1724 item_free_contents(a
->items
+ n
);
1729 static int item_compare(const void *a
, const void *b
) {
1730 const Item
*x
= a
, *y
= b
;
1732 /* Make sure that the ownership taking item is put first, so
1733 * that we first create the node, and then can adjust it */
1735 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1737 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1740 return (int) x
->type
- (int) y
->type
;
1743 static bool item_compatible(Item
*a
, Item
*b
) {
1746 assert(streq(a
->path
, b
->path
));
1748 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1749 /* check if the items are the same */
1750 return streq_ptr(a
->argument
, b
->argument
) &&
1752 a
->uid_set
== b
->uid_set
&&
1755 a
->gid_set
== b
->gid_set
&&
1758 a
->mode_set
== b
->mode_set
&&
1759 a
->mode
== b
->mode
&&
1761 a
->age_set
== b
->age_set
&&
1764 a
->mask_perms
== b
->mask_perms
&&
1766 a
->keep_first_level
== b
->keep_first_level
&&
1768 a
->major_minor
== b
->major_minor
;
1773 static bool should_include_path(const char *path
) {
1776 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1777 if (path_startswith(path
, *prefix
)) {
1778 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1783 STRV_FOREACH(prefix
, arg_include_prefixes
)
1784 if (path_startswith(path
, *prefix
)) {
1785 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1789 /* no matches, so we should include this path only if we
1790 * have no whitelist at all */
1791 if (strv_length(arg_include_prefixes
) == 0)
1794 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1798 static int specifier_expansion_from_arg(Item
*i
) {
1799 _cleanup_free_
char *unescaped
= NULL
, *resolved
= NULL
;
1805 if (i
->argument
== NULL
)
1810 case CREATE_SYMLINK
:
1814 r
= cunescape(i
->argument
, 0, &unescaped
);
1816 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
1818 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &resolved
);
1822 free_and_replace(i
->argument
, resolved
);
1826 case RECURSIVE_SET_XATTR
:
1829 STRV_FOREACH (xattr
, i
->xattrs
) {
1830 r
= specifier_printf(*xattr
, specifier_table
, NULL
, &resolved
);
1834 free_and_replace(*xattr
, resolved
);
1844 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1846 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1847 _cleanup_(item_free_contents
) Item i
= {};
1848 ItemArray
*existing
;
1851 bool force
= false, boot
= false;
1857 r
= extract_many_words(
1869 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1871 log_error("[%s:%u] Syntax error.", fname
, line
);
1875 if (!isempty(buffer
) && !streq(buffer
, "-")) {
1876 i
.argument
= strdup(buffer
);
1881 if (isempty(action
)) {
1882 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1886 for (pos
= 1; action
[pos
]; pos
++) {
1887 if (action
[pos
] == '!' && !boot
)
1889 else if (action
[pos
] == '+' && !force
)
1892 log_error("[%s:%u] Unknown modifiers in command '%s'",
1893 fname
, line
, action
);
1898 if (boot
&& !arg_boot
) {
1899 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1907 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1909 return log_unresolvable_specifier(fname
, line
);
1911 return log_error_errno(r
, "[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1915 case CREATE_DIRECTORY
:
1916 case CREATE_SUBVOLUME
:
1917 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1918 case CREATE_SUBVOLUME_NEW_QUOTA
:
1919 case EMPTY_DIRECTORY
:
1920 case TRUNCATE_DIRECTORY
:
1923 case IGNORE_DIRECTORY_PATH
:
1925 case RECURSIVE_REMOVE_PATH
:
1928 case RECURSIVE_RELABEL_PATH
:
1930 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
1938 case CREATE_SYMLINK
:
1940 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1948 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1955 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1958 } else if (!path_is_absolute(i
.argument
)) {
1959 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1963 path_kill_slashes(i
.argument
);
1966 case CREATE_CHAR_DEVICE
:
1967 case CREATE_BLOCK_DEVICE
: {
1968 unsigned major
, minor
;
1971 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1975 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1976 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1980 i
.major_minor
= makedev(major
, minor
);
1985 case RECURSIVE_SET_XATTR
:
1987 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1990 r
= parse_xattrs_from_arg(&i
);
1996 case RECURSIVE_SET_ACL
:
1998 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
2001 r
= parse_acls_from_arg(&i
);
2007 case RECURSIVE_SET_ATTRIBUTE
:
2009 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
2012 r
= parse_attribute_from_arg(&i
);
2018 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
2022 if (!path_is_absolute(i
.path
)) {
2023 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
2027 path_kill_slashes(i
.path
);
2029 if (!should_include_path(i
.path
))
2032 r
= specifier_expansion_from_arg(&i
);
2034 return log_unresolvable_specifier(fname
, line
);
2036 return log_error_errno(r
, "[%s:%u] Failed to substitute specifiers in argument: %m",
2042 p
= prefix_root(arg_root
, i
.path
);
2050 if (!isempty(user
) && !streq(user
, "-")) {
2051 const char *u
= user
;
2053 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
2055 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
2062 if (!isempty(group
) && !streq(group
, "-")) {
2063 const char *g
= group
;
2065 r
= get_group_creds(&g
, &i
.gid
);
2067 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2074 if (!isempty(mode
) && !streq(mode
, "-")) {
2075 const char *mm
= mode
;
2079 i
.mask_perms
= true;
2083 if (parse_mode(mm
, &m
) < 0) {
2084 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2091 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2093 if (!isempty(age
) && !streq(age
, "-")) {
2094 const char *a
= age
;
2097 i
.keep_first_level
= true;
2101 if (parse_sec(a
, &i
.age
) < 0) {
2102 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2109 h
= needs_glob(i
.type
) ? globs
: items
;
2111 existing
= ordered_hashmap_get(h
, i
.path
);
2115 for (n
= 0; n
< existing
->count
; n
++) {
2116 if (!item_compatible(existing
->items
+ n
, &i
)) {
2117 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2118 fname
, line
, i
.path
);
2123 existing
= new0(ItemArray
, 1);
2124 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2129 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2132 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2134 /* Sort item array, to enforce stable ordering of application */
2135 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2141 static void help(void) {
2142 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2143 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2144 " -h --help Show this help\n"
2145 " --version Show package version\n"
2146 " --create Create marked files/directories\n"
2147 " --clean Clean up marked directories\n"
2148 " --remove Remove marked files/directories\n"
2149 " --boot Execute actions only safe at boot\n"
2150 " --prefix=PATH Only apply rules with the specified prefix\n"
2151 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2152 " --root=PATH Operate on an alternate filesystem root\n",
2153 program_invocation_short_name
);
2156 static int parse_argv(int argc
, char *argv
[]) {
2159 ARG_VERSION
= 0x100,
2169 static const struct option options
[] = {
2170 { "help", no_argument
, NULL
, 'h' },
2171 { "version", no_argument
, NULL
, ARG_VERSION
},
2172 { "create", no_argument
, NULL
, ARG_CREATE
},
2173 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2174 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2175 { "boot", no_argument
, NULL
, ARG_BOOT
},
2176 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2177 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2178 { "root", required_argument
, NULL
, ARG_ROOT
},
2187 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2215 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2219 case ARG_EXCLUDE_PREFIX
:
2220 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2225 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2234 assert_not_reached("Unhandled option");
2237 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2238 log_error("You need to specify at least one of --clean, --create or --remove.");
2245 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2246 _cleanup_fclose_
FILE *_f
= NULL
;
2248 char line
[LINE_MAX
];
2256 if (streq(fn
, "-")) {
2257 log_debug("Reading config from stdin.");
2261 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &_f
);
2263 if (ignore_enoent
&& r
== -ENOENT
) {
2264 log_debug_errno(r
, "Failed to open \"%s\", ignoring: %m", fn
);
2268 return log_error_errno(r
, "Failed to open '%s': %m", fn
);
2270 log_debug("Reading config file \"%s\".", fn
);
2274 FOREACH_LINE(line
, f
, break) {
2281 if (IN_SET(*l
, 0, '#'))
2284 k
= parse_line(fn
, v
, l
);
2285 if (k
< 0 && r
== 0)
2289 /* we have to determine age parameter for each entry of type X */
2290 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2292 Item
*j
, *candidate_item
= NULL
;
2294 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2297 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2298 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2301 if (path_equal(j
->path
, i
->path
)) {
2306 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2307 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2311 if (candidate_item
&& candidate_item
->age_set
) {
2312 i
->age
= candidate_item
->age
;
2318 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2326 int main(int argc
, char *argv
[]) {
2331 r
= parse_argv(argc
, argv
);
2335 log_set_target(LOG_TARGET_AUTO
);
2336 log_parse_environment();
2343 items
= ordered_hashmap_new(&string_hash_ops
);
2344 globs
= ordered_hashmap_new(&string_hash_ops
);
2346 if (!items
|| !globs
) {
2353 if (optind
< argc
) {
2356 for (j
= optind
; j
< argc
; j
++) {
2357 k
= read_config_file(argv
[j
], false);
2358 if (k
< 0 && r
== 0)
2363 _cleanup_strv_free_
char **files
= NULL
;
2366 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, 0, conf_file_dirs
);
2368 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2372 STRV_FOREACH(f
, files
) {
2373 k
= read_config_file(*f
, true);
2374 if (k
< 0 && r
== 0)
2379 /* The non-globbing ones usually create things, hence we apply
2381 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2382 k
= process_item_array(a
);
2383 if (k
< 0 && r
== 0)
2387 /* The globbing ones usually alter things, hence we apply them
2389 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2390 k
= process_item_array(a
);
2391 if (k
< 0 && r
== 0)
2396 while ((a
= ordered_hashmap_steal_first(items
)))
2399 while ((a
= ordered_hashmap_steal_first(globs
)))
2402 ordered_hashmap_free(items
);
2403 ordered_hashmap_free(globs
);
2405 free(arg_include_prefixes
);
2406 free(arg_exclude_prefixes
);
2409 set_free_free(unix_sockets
);
2411 mac_selinux_finish();
2413 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;