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>
43 #include "alloc-util.h"
44 #include "btrfs-util.h"
45 #include "capability-util.h"
46 #include "chattr-util.h"
47 #include "conf-files.h"
50 #include "dirent-util.h"
54 #include "format-util.h"
56 #include "glob-util.h"
63 #include "mount-util.h"
64 #include "parse-util.h"
65 #include "path-lookup.h"
66 #include "path-util.h"
68 #include "selinux-util.h"
70 #include "specifier.h"
71 #include "stat-util.h"
72 #include "stdio-util.h"
73 #include "string-table.h"
74 #include "string-util.h"
76 #include "umask-util.h"
77 #include "user-util.h"
80 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
81 * them in the file system. This is intended to be used to create
82 * properly owned directories beneath /tmp, /var/tmp, /run, which are
83 * volatile and hence need to be recreated on bootup. */
85 typedef enum ItemType
{
86 /* These ones take file names */
89 CREATE_DIRECTORY
= 'd',
90 TRUNCATE_DIRECTORY
= 'D',
91 CREATE_SUBVOLUME
= 'v',
92 CREATE_SUBVOLUME_INHERIT_QUOTA
= 'q',
93 CREATE_SUBVOLUME_NEW_QUOTA
= 'Q',
96 CREATE_CHAR_DEVICE
= 'c',
97 CREATE_BLOCK_DEVICE
= 'b',
100 /* These ones take globs */
102 EMPTY_DIRECTORY
= 'e',
104 RECURSIVE_SET_XATTR
= 'T',
106 RECURSIVE_SET_ACL
= 'A',
108 RECURSIVE_SET_ATTRIBUTE
= 'H',
110 IGNORE_DIRECTORY_PATH
= 'X',
112 RECURSIVE_REMOVE_PATH
= 'R',
114 RECURSIVE_RELABEL_PATH
= 'Z',
115 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
118 typedef struct Item
{
134 unsigned attribute_value
;
135 unsigned attribute_mask
;
142 bool attribute_set
:1;
144 bool keep_first_level
:1;
151 typedef struct ItemArray
{
157 typedef enum DirectoryType
{
158 DIRECTORY_RUNTIME
= 0,
165 static bool arg_user
= false;
166 static bool arg_create
= false;
167 static bool arg_clean
= false;
168 static bool arg_remove
= false;
169 static bool arg_boot
= false;
171 static char **arg_include_prefixes
= NULL
;
172 static char **arg_exclude_prefixes
= NULL
;
173 static char *arg_root
= NULL
;
174 static char *arg_replace
= NULL
;
176 #define MAX_DEPTH 256
178 static OrderedHashmap
*items
= NULL
, *globs
= NULL
;
179 static Set
*unix_sockets
= NULL
;
181 static int specifier_machine_id_safe(char specifier
, void *data
, void *userdata
, char **ret
);
182 static int specifier_directory(char specifier
, void *data
, void *userdata
, char **ret
);
184 static const Specifier specifier_table
[] = {
185 { 'm', specifier_machine_id_safe
, NULL
},
186 { 'b', specifier_boot_id
, NULL
},
187 { 'H', specifier_host_name
, NULL
},
188 { 'v', specifier_kernel_release
, NULL
},
190 { 'U', specifier_user_id
, NULL
},
191 { 'u', specifier_user_name
, NULL
},
192 { 'h', specifier_user_home
, NULL
},
193 { 't', specifier_directory
, UINT_TO_PTR(DIRECTORY_RUNTIME
) },
194 { 'S', specifier_directory
, UINT_TO_PTR(DIRECTORY_STATE
) },
195 { 'C', specifier_directory
, UINT_TO_PTR(DIRECTORY_CACHE
) },
196 { 'L', specifier_directory
, UINT_TO_PTR(DIRECTORY_LOGS
) },
200 static int specifier_machine_id_safe(char specifier
, void *data
, void *userdata
, char **ret
) {
203 /* If /etc/machine_id is missing or empty (e.g. in a chroot environment)
204 * return a recognizable error so that the caller can skip the rule
207 r
= specifier_machine_id(specifier
, data
, userdata
, ret
);
208 if (IN_SET(r
, -ENOENT
, -ENOMEDIUM
))
214 static int specifier_directory(char specifier
, void *data
, void *userdata
, char **ret
) {
220 static const struct table_entry paths_system
[] = {
221 [DIRECTORY_RUNTIME
] = { SD_PATH_SYSTEM_RUNTIME
},
222 [DIRECTORY_STATE
] = { SD_PATH_SYSTEM_STATE_PRIVATE
},
223 [DIRECTORY_CACHE
] = { SD_PATH_SYSTEM_STATE_CACHE
},
224 [DIRECTORY_LOGS
] = { SD_PATH_SYSTEM_STATE_LOGS
},
227 static const struct table_entry paths_user
[] = {
228 [DIRECTORY_RUNTIME
] = { SD_PATH_USER_RUNTIME
},
229 [DIRECTORY_STATE
] = { SD_PATH_USER_CONFIGURATION
},
230 [DIRECTORY_CACHE
] = { SD_PATH_USER_STATE_CACHE
},
231 [DIRECTORY_LOGS
] = { SD_PATH_USER_CONFIGURATION
, "log" },
235 const struct table_entry
*paths
;
237 assert_cc(ELEMENTSOF(paths_system
) == ELEMENTSOF(paths_user
));
238 paths
= arg_user
? paths_user
: paths_system
;
240 i
= PTR_TO_UINT(data
);
241 assert(i
< ELEMENTSOF(paths_system
));
243 return sd_path_home(paths
[i
].type
, paths
[i
].suffix
, ret
);
246 static int log_unresolvable_specifier(const char *filename
, unsigned line
) {
247 static bool notified
= false;
249 /* In system mode, this is called when /etc is not fully initialized (e.g.
250 * in a chroot environment) where some specifiers are unresolvable. In user
251 * mode, this is called when some variables are not defined. These cases are
252 * not considered as an error so log at LOG_NOTICE only for the first time
253 * and then downgrade this to LOG_DEBUG for the rest. */
255 log_full(notified
? LOG_DEBUG
: LOG_NOTICE
,
256 "[%s:%u] Failed to resolve specifier: %s, skipping",
258 arg_user
? "Required $XDG_... variable not defined" : "uninitialized /etc detected");
261 log_notice("All rules containing unresolvable specifiers will be skipped.");
267 static int user_config_paths(char*** ret
) {
268 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
269 _cleanup_free_
char *persistent_config
= NULL
, *runtime_config
= NULL
, *data_home
= NULL
;
270 _cleanup_strv_free_
char **res
= NULL
;
273 r
= xdg_user_dirs(&config_dirs
, &data_dirs
);
277 r
= xdg_user_config_dir(&persistent_config
, "/user-tmpfiles.d");
278 if (r
< 0 && r
!= -ENXIO
)
281 r
= xdg_user_runtime_dir(&runtime_config
, "/user-tmpfiles.d");
282 if (r
< 0 && r
!= -ENXIO
)
285 r
= xdg_user_data_dir(&data_home
, "/user-tmpfiles.d");
286 if (r
< 0 && r
!= -ENXIO
)
289 r
= strv_extend_strv_concat(&res
, config_dirs
, "/user-tmpfiles.d");
293 r
= strv_extend(&res
, persistent_config
);
297 r
= strv_extend(&res
, runtime_config
);
301 r
= strv_extend(&res
, data_home
);
305 r
= strv_extend_strv_concat(&res
, data_dirs
, "/user-tmpfiles.d");
309 r
= path_strv_make_absolute_cwd(res
);
318 static bool needs_glob(ItemType t
) {
322 IGNORE_DIRECTORY_PATH
,
324 RECURSIVE_REMOVE_PATH
,
328 RECURSIVE_RELABEL_PATH
,
334 RECURSIVE_SET_ATTRIBUTE
);
337 static bool takes_ownership(ItemType t
) {
345 CREATE_SUBVOLUME_INHERIT_QUOTA
,
346 CREATE_SUBVOLUME_NEW_QUOTA
,
354 IGNORE_DIRECTORY_PATH
,
356 RECURSIVE_REMOVE_PATH
);
359 static struct Item
* find_glob(OrderedHashmap
*h
, const char *match
) {
363 ORDERED_HASHMAP_FOREACH(j
, h
, i
) {
366 for (n
= 0; n
< j
->count
; n
++) {
367 Item
*item
= j
->items
+ n
;
369 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
377 static void load_unix_sockets(void) {
378 _cleanup_fclose_
FILE *f
= NULL
;
384 /* We maintain a cache of the sockets we found in /proc/net/unix to speed things up a little. */
386 unix_sockets
= set_new(&string_hash_ops
);
390 f
= fopen("/proc/net/unix", "re");
392 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_WARNING
, errno
,
393 "Failed to open /proc/net/unix, ignoring: %m");
398 r
= read_line(f
, LONG_LINE_MAX
, NULL
);
400 log_warning_errno(r
, "Failed to skip /proc/net/unix header line: %m");
404 log_warning("Premature end of file reading /proc/net/unix.");
409 _cleanup_free_
char *line
= NULL
;
412 r
= read_line(f
, LONG_LINE_MAX
, &line
);
414 log_warning_errno(r
, "Failed to read /proc/net/unix line, ignoring: %m");
417 if (r
== 0) /* EOF */
420 p
= strchr(line
, ':');
428 p
+= strspn(p
, WHITESPACE
);
429 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
430 p
+= strspn(p
, WHITESPACE
);
441 path_kill_slashes(s
);
443 r
= set_consume(unix_sockets
, s
);
444 if (r
< 0 && r
!= -EEXIST
) {
445 log_warning_errno(r
, "Failed to add AF_UNIX socket to set, ignoring: %m");
453 unix_sockets
= set_free_free(unix_sockets
);
456 static bool unix_socket_alive(const char *fn
) {
462 return !!set_get(unix_sockets
, (char*) fn
);
464 /* We don't know, so assume yes */
468 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
470 int mount_id_parent
, mount_id
;
473 r_p
= name_to_handle_at_loop(dirfd(d
), ".", NULL
, &mount_id_parent
, 0);
477 r
= name_to_handle_at_loop(dirfd(d
), subdir
, NULL
, &mount_id
, 0);
481 /* got no handle; make no assumptions, return error */
482 if (r_p
< 0 && r
< 0)
485 /* got both handles; if they differ, it is a mount point */
486 if (r_p
>= 0 && r
>= 0)
487 return mount_id_parent
!= mount_id
;
489 /* got only one handle; assume different mount points if one
490 * of both queries was not supported by the filesystem */
491 if (IN_SET(r_p
, -ENOSYS
, -EOPNOTSUPP
) || IN_SET(r
, -ENOSYS
, -EOPNOTSUPP
))
500 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
503 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
507 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
511 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
513 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
518 static DIR* opendir_nomod(const char *path
) {
519 return xopendirat_nomod(AT_FDCWD
, path
);
522 static int dir_cleanup(
526 const struct stat
*ds
,
531 bool keep_this_level
) {
534 struct timespec times
[2];
535 bool deleted
= false;
538 FOREACH_DIRENT_ALL(dent
, d
, break) {
541 _cleanup_free_
char *sub_path
= NULL
;
543 if (dot_or_dot_dot(dent
->d_name
))
546 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
550 /* FUSE, NFS mounts, SELinux might return EACCES */
551 r
= log_full_errno(errno
== EACCES
? LOG_DEBUG
: LOG_ERR
, errno
,
552 "stat(%s/%s) failed: %m", p
, dent
->d_name
);
556 /* Stay on the same filesystem */
557 if (s
.st_dev
!= rootdev
) {
558 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
562 /* Try to detect bind mounts of the same filesystem instance; they
563 * do not differ in device major/minors. This type of query is not
564 * supported on all kernels or filesystem types though. */
565 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
566 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
571 sub_path
= strjoin(p
, "/", dent
->d_name
);
577 /* Is there an item configured for this path? */
578 if (ordered_hashmap_get(items
, sub_path
)) {
579 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
583 if (find_glob(globs
, sub_path
)) {
584 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
588 if (S_ISDIR(s
.st_mode
)) {
591 streq(dent
->d_name
, "lost+found") &&
593 log_debug("Ignoring \"%s\".", sub_path
);
598 log_warning("Reached max depth on \"%s\".", sub_path
);
600 _cleanup_closedir_
DIR *sub_dir
;
603 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
606 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
611 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
616 /* Note: if you are wondering why we don't
617 * support the sticky bit for excluding
618 * directories from cleaning like we do it for
619 * other file system objects: well, the sticky
620 * bit already has a meaning for directories,
621 * so we don't want to overload that. */
623 if (keep_this_level
) {
624 log_debug("Keeping \"%s\".", sub_path
);
628 /* Ignore ctime, we change it when deleting */
629 age
= timespec_load(&s
.st_mtim
);
631 char a
[FORMAT_TIMESTAMP_MAX
];
632 /* Follows spelling in stat(1). */
633 log_debug("Directory \"%s\": modify time %s is too new.",
635 format_timestamp_us(a
, sizeof(a
), age
));
639 age
= timespec_load(&s
.st_atim
);
641 char a
[FORMAT_TIMESTAMP_MAX
];
642 log_debug("Directory \"%s\": access time %s is too new.",
644 format_timestamp_us(a
, sizeof(a
), age
));
648 log_debug("Removing directory \"%s\".", sub_path
);
649 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
650 if (!IN_SET(errno
, ENOENT
, ENOTEMPTY
))
651 r
= log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
654 /* Skip files for which the sticky bit is
655 * set. These are semantics we define, and are
656 * unknown elsewhere. See XDG_RUNTIME_DIR
657 * specification for details. */
658 if (s
.st_mode
& S_ISVTX
) {
659 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
663 if (mountpoint
&& S_ISREG(s
.st_mode
))
664 if (s
.st_uid
== 0 && STR_IN_SET(dent
->d_name
,
668 log_debug("Skipping \"%s\".", sub_path
);
672 /* Ignore sockets that are listed in /proc/net/unix */
673 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
674 log_debug("Skipping \"%s\": live socket.", sub_path
);
678 /* Ignore device nodes */
679 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
680 log_debug("Skipping \"%s\": a device.", sub_path
);
684 /* Keep files on this level around if this is
686 if (keep_this_level
) {
687 log_debug("Keeping \"%s\".", sub_path
);
691 age
= timespec_load(&s
.st_mtim
);
693 char a
[FORMAT_TIMESTAMP_MAX
];
694 /* Follows spelling in stat(1). */
695 log_debug("File \"%s\": modify time %s is too new.",
697 format_timestamp_us(a
, sizeof(a
), age
));
701 age
= timespec_load(&s
.st_atim
);
703 char a
[FORMAT_TIMESTAMP_MAX
];
704 log_debug("File \"%s\": access time %s is too new.",
706 format_timestamp_us(a
, sizeof(a
), age
));
710 age
= timespec_load(&s
.st_ctim
);
712 char a
[FORMAT_TIMESTAMP_MAX
];
713 log_debug("File \"%s\": change time %s is too new.",
715 format_timestamp_us(a
, sizeof(a
), age
));
719 log_debug("unlink \"%s\"", sub_path
);
721 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
723 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
732 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
734 /* Restore original directory timestamps */
735 times
[0] = ds
->st_atim
;
736 times
[1] = ds
->st_mtim
;
738 age1
= timespec_load(&ds
->st_atim
);
739 age2
= timespec_load(&ds
->st_mtim
);
740 log_debug("Restoring access and modification time on \"%s\": %s, %s",
742 format_timestamp_us(a
, sizeof(a
), age1
),
743 format_timestamp_us(b
, sizeof(b
), age2
));
744 if (futimens(dirfd(d
), times
) < 0)
745 log_error_errno(errno
, "utimensat(%s): %m", p
);
751 static bool dangerous_hardlinks(void) {
752 _cleanup_free_
char *value
= NULL
;
753 static int cached
= -1;
756 /* Check whether the fs.protected_hardlinks sysctl is on. If we can't determine it we assume its off, as that's
757 * what the upstream default is. */
762 r
= read_one_line_file("/proc/sys/fs/protected_hardlinks", &value
);
764 log_debug_errno(r
, "Failed to read fs.protected_hardlinks sysctl: %m");
768 r
= parse_boolean(value
);
770 log_debug_errno(r
, "Failed to parse fs.protected_hardlinks sysctl: %m");
778 static bool hardlink_vulnerable(struct stat
*st
) {
781 return !S_ISDIR(st
->st_mode
) && st
->st_nlink
> 1 && dangerous_hardlinks();
784 static int path_set_perms(Item
*i
, const char *path
) {
785 char fn
[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
786 _cleanup_close_
int fd
= -1;
792 if (!i
->mode_set
&& !i
->uid_set
&& !i
->gid_set
)
795 /* We open the file with O_PATH here, to make the operation
796 * somewhat atomic. Also there's unfortunately no fchmodat()
797 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
800 fd
= open(path
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
802 int level
= LOG_ERR
, r
= -errno
;
804 /* Option "e" operates only on existing objects. Do not
805 * print errors about non-existent files or directories */
806 if (i
->type
== EMPTY_DIRECTORY
&& errno
== ENOENT
) {
811 log_full_errno(level
, errno
, "Adjusting owner and mode for %s failed: %m", path
);
815 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
816 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
818 if (hardlink_vulnerable(&st
)) {
819 log_error("Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path
);
823 xsprintf(fn
, "/proc/self/fd/%i", fd
);
826 if (S_ISLNK(st
.st_mode
))
827 log_debug("Skipping mode fix for symlink %s.", path
);
832 if (!(st
.st_mode
& 0111))
834 if (!(st
.st_mode
& 0222))
836 if (!(st
.st_mode
& 0444))
838 if (!S_ISDIR(st
.st_mode
))
839 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
842 if (m
== (st
.st_mode
& 07777))
843 log_debug("\"%s\" has correct mode %o already.", path
, st
.st_mode
);
845 log_debug("Changing \"%s\" to mode %o.", path
, m
);
847 if (chmod(fn
, m
) < 0)
848 return log_error_errno(errno
, "chmod() of %s via %s failed: %m", path
, fn
);
853 if ((i
->uid_set
&& i
->uid
!= st
.st_uid
) ||
854 (i
->gid_set
&& i
->gid
!= st
.st_gid
)) {
855 log_debug("Changing \"%s\" to owner "UID_FMT
":"GID_FMT
,
857 i
->uid_set
? i
->uid
: UID_INVALID
,
858 i
->gid_set
? i
->gid
: GID_INVALID
);
861 i
->uid_set
? i
->uid
: UID_INVALID
,
862 i
->gid_set
? i
->gid
: GID_INVALID
) < 0)
863 return log_error_errno(errno
, "chown() of %s via %s failed: %m", path
, fn
);
869 return label_fix(path
, false, false);
872 static int parse_xattrs_from_arg(Item
*i
) {
882 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
;
884 r
= extract_first_word(&p
, &xattr
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
886 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
890 r
= split_pair(xattr
, "=", &name
, &value
);
892 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
896 if (isempty(name
) || isempty(value
)) {
897 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
901 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
910 static int path_set_xattrs(Item
*i
, const char *path
) {
911 char **name
, **value
;
916 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
917 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
918 if (lsetxattr(path
, *name
, *value
, strlen(*value
), 0) < 0)
919 return log_error_errno(errno
, "Setting extended attribute %s=%s on %s failed: %m",
920 *name
, *value
, path
);
925 static int parse_acls_from_arg(Item
*item
) {
931 /* If force (= modify) is set, we will not modify the acl
932 * afterwards, so the mask can be added now if necessary. */
934 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
936 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
938 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
945 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
946 _cleanup_(acl_free_charpp
) char *t
= NULL
;
947 _cleanup_(acl_freep
) acl_t dup
= NULL
;
950 /* Returns 0 for success, positive error if already warned,
951 * negative error otherwise. */
954 r
= acls_for_file(path
, type
, acl
, &dup
);
958 r
= calc_acl_mask_if_needed(&dup
);
966 /* the mask was already added earlier if needed */
969 r
= add_base_acls_if_needed(&dup
, path
);
973 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
974 log_debug("Setting %s ACL %s on %s.",
975 type
== ACL_TYPE_ACCESS
? "access" : "default",
978 r
= acl_set_file(path
, type
, dup
);
980 /* Return positive to indicate we already warned */
981 return -log_error_errno(errno
,
982 "Setting %s ACL \"%s\" on %s failed: %m",
983 type
== ACL_TYPE_ACCESS
? "access" : "default",
990 static int path_set_acls(Item
*item
, const char *path
) {
993 char fn
[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
994 _cleanup_close_
int fd
= -1;
1000 fd
= open(path
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
1002 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
1004 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
1005 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
1007 if (hardlink_vulnerable(&st
)) {
1008 log_error("Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path
);
1012 if (S_ISLNK(st
.st_mode
)) {
1013 log_debug("Skipping ACL fix for symlink %s.", path
);
1017 xsprintf(fn
, "/proc/self/fd/%i", fd
);
1019 if (item
->acl_access
)
1020 r
= path_set_acl(fn
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
1022 if (r
== 0 && item
->acl_default
)
1023 r
= path_set_acl(fn
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
1026 return -r
; /* already warned */
1027 else if (r
== -EOPNOTSUPP
) {
1028 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
1031 log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
1036 #define ATTRIBUTES_ALL \
1045 FS_JOURNAL_DATA_FL | \
1052 static int parse_attribute_from_arg(Item
*item
) {
1054 static const struct {
1058 { 'A', FS_NOATIME_FL
}, /* do not update atime */
1059 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
1060 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
1061 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
1062 { 'c', FS_COMPR_FL
}, /* Compress file */
1063 { 'd', FS_NODUMP_FL
}, /* do not dump file */
1064 { 'e', FS_EXTENT_FL
}, /* Extents */
1065 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
1066 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
1067 { 's', FS_SECRM_FL
}, /* Secure deletion */
1068 { 'u', FS_UNRM_FL
}, /* Undelete */
1069 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
1070 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies */
1071 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
1080 unsigned value
= 0, mask
= 0;
1090 } else if (*p
== '-') {
1093 } else if (*p
== '=') {
1099 if (isempty(p
) && mode
!= MODE_SET
) {
1100 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
1104 for (; p
&& *p
; p
++) {
1107 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
1108 if (*p
== attributes
[i
].character
)
1111 if (i
>= ELEMENTSOF(attributes
)) {
1112 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
1116 v
= attributes
[i
].value
;
1118 SET_FLAG(value
, v
, IN_SET(mode
, MODE_ADD
, MODE_SET
));
1123 if (mode
== MODE_SET
)
1124 mask
|= ATTRIBUTES_ALL
;
1128 item
->attribute_mask
= mask
;
1129 item
->attribute_value
= value
;
1130 item
->attribute_set
= true;
1135 static int path_set_attribute(Item
*item
, const char *path
) {
1136 _cleanup_close_
int fd
= -1;
1141 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
1144 fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
|O_NOATIME
|O_NOFOLLOW
);
1147 return log_error_errno(errno
, "Skipping file attributes adjustment on symlink %s.", path
);
1149 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
1152 if (fstat(fd
, &st
) < 0)
1153 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
1155 /* Issuing the file attribute ioctls on device nodes is not
1156 * safe, as that will be delivered to the drivers, not the
1157 * file system containing the device node. */
1158 if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
)) {
1159 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
1163 f
= item
->attribute_value
& item
->attribute_mask
;
1165 /* Mask away directory-specific flags */
1166 if (!S_ISDIR(st
.st_mode
))
1167 f
&= ~FS_DIRSYNC_FL
;
1169 r
= chattr_fd(fd
, f
, item
->attribute_mask
);
1171 log_full_errno(IN_SET(r
, -ENOTTY
, -EOPNOTSUPP
) ? LOG_DEBUG
: LOG_WARNING
,
1173 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
1174 path
, item
->attribute_value
, item
->attribute_mask
);
1179 static int write_one_file(Item
*i
, const char *path
) {
1180 _cleanup_close_
int fd
= -1;
1187 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_EXCL
|O_NOFOLLOW
:
1188 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
1190 RUN_WITH_UMASK(0000) {
1191 mac_selinux_create_file_prepare(path
, S_IFREG
);
1192 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
1193 mac_selinux_create_file_clear();
1197 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
1198 log_debug_errno(errno
, "Not writing missing file \"%s\": %m", path
);
1201 if (i
->type
== CREATE_FILE
&& errno
== EEXIST
) {
1202 log_debug_errno(errno
, "Not writing to pre-existing file \"%s\": %m", path
);
1207 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
1208 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
1211 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1215 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1217 r
= loop_write(fd
, i
->argument
, strlen(i
->argument
), false);
1219 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1221 log_debug("\"%s\" has been created.", path
);
1223 fd
= safe_close(fd
);
1226 if (stat(path
, &st
) < 0)
1227 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1230 if (!S_ISREG(st
.st_mode
)) {
1231 log_error("%s is not a file.", path
);
1235 r
= path_set_perms(i
, path
);
1242 typedef int (*action_t
)(Item
*, const char *);
1244 static int item_do_children(Item
*i
, const char *path
, action_t action
) {
1245 _cleanup_closedir_
DIR *d
;
1252 /* This returns the first error we run into, but nevertheless
1255 d
= opendir_nomod(path
);
1257 return IN_SET(errno
, ENOENT
, ENOTDIR
, ELOOP
) ? 0 : -errno
;
1259 FOREACH_DIRENT_ALL(de
, d
, r
= -errno
) {
1260 _cleanup_free_
char *p
= NULL
;
1263 if (dot_or_dot_dot(de
->d_name
))
1266 p
= strjoin(path
, "/", de
->d_name
);
1271 if (q
< 0 && q
!= -ENOENT
&& r
== 0)
1274 if (IN_SET(de
->d_type
, DT_UNKNOWN
, DT_DIR
)) {
1275 q
= item_do_children(i
, p
, action
);
1276 if (q
< 0 && r
== 0)
1284 static int glob_item(Item
*i
, action_t action
, bool recursive
) {
1285 _cleanup_globfree_ glob_t g
= {
1286 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1291 k
= safe_glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
, &g
);
1292 if (k
< 0 && k
!= -ENOENT
)
1293 return log_error_errno(k
, "glob(%s) failed: %m", i
->path
);
1295 STRV_FOREACH(fn
, g
.gl_pathv
) {
1297 if (k
< 0 && r
== 0)
1301 k
= item_do_children(i
, *fn
, action
);
1302 if (k
< 0 && r
== 0)
1315 _CREATION_MODE_INVALID
= -1
1318 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1319 [CREATION_NORMAL
] = "Created",
1320 [CREATION_EXISTING
] = "Found existing",
1321 [CREATION_FORCE
] = "Created replacement",
1324 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1326 static int create_item(Item
*i
) {
1330 CreationMode creation
;
1334 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1339 case IGNORE_DIRECTORY_PATH
:
1341 case RECURSIVE_REMOVE_PATH
:
1346 RUN_WITH_UMASK(0000)
1347 (void) mkdir_parents_label(i
->path
, 0755);
1349 r
= write_one_file(i
, i
->path
);
1356 RUN_WITH_UMASK(0000)
1357 (void) mkdir_parents_label(i
->path
, 0755);
1359 log_debug("Copying tree \"%s\" to \"%s\".", i
->argument
, i
->path
);
1360 r
= copy_tree(i
->argument
, i
->path
,
1361 i
->uid_set
? i
->uid
: UID_INVALID
,
1362 i
->gid_set
? i
->gid
: GID_INVALID
,
1365 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1372 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1374 if (stat(i
->argument
, &a
) < 0)
1375 return log_error_errno(errno
, "stat(%s) failed: %m", i
->argument
);
1377 if (stat(i
->path
, &b
) < 0)
1378 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1380 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1381 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1386 r
= path_set_perms(i
, i
->path
);
1393 r
= glob_item(i
, write_one_file
, false);
1399 case CREATE_DIRECTORY
:
1400 case TRUNCATE_DIRECTORY
:
1401 case CREATE_SUBVOLUME
:
1402 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1403 case CREATE_SUBVOLUME_NEW_QUOTA
:
1404 RUN_WITH_UMASK(0000)
1405 (void) mkdir_parents_label(i
->path
, 0755);
1407 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1409 if (btrfs_is_subvol(isempty(arg_root
) ? "/" : arg_root
) <= 0)
1411 /* Don't create a subvolume unless the
1412 * root directory is one, too. We do
1413 * this under the assumption that if
1414 * the root directory is just a plain
1415 * directory (i.e. very light-weight),
1416 * we shouldn't try to split it up
1417 * into subvolumes (i.e. more
1418 * heavy-weight). Thus, chroot()
1419 * environments and suchlike will get
1420 * a full brtfs subvolume set up below
1421 * their tree only if they
1422 * specifically set up a btrfs
1423 * subvolume for the root dir too. */
1427 RUN_WITH_UMASK((~i
->mode
) & 0777)
1428 r
= btrfs_subvol_make(i
->path
);
1433 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1434 RUN_WITH_UMASK(0000)
1435 r
= mkdir_label(i
->path
, i
->mode
);
1440 if (!IN_SET(r
, -EEXIST
, -EROFS
))
1441 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1443 k
= is_dir(i
->path
, false);
1444 if (k
== -ENOENT
&& r
== -EROFS
)
1445 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1447 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1449 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1453 creation
= CREATION_EXISTING
;
1455 creation
= CREATION_NORMAL
;
1457 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1459 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1460 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1462 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i
->path
);
1463 else if (r
== -EROFS
)
1464 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i
->path
);
1465 else if (r
== -ENOPROTOOPT
)
1466 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i
->path
);
1468 q
= log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1470 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1472 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1476 case EMPTY_DIRECTORY
:
1477 r
= path_set_perms(i
, i
->path
);
1486 RUN_WITH_UMASK(0000) {
1487 (void) mkdir_parents_label(i
->path
, 0755);
1489 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1490 r
= mkfifo(i
->path
, i
->mode
);
1491 mac_selinux_create_file_clear();
1495 if (errno
!= EEXIST
)
1496 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1498 if (lstat(i
->path
, &st
) < 0)
1499 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1501 if (!S_ISFIFO(st
.st_mode
)) {
1504 RUN_WITH_UMASK(0000) {
1505 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1506 r
= mkfifo_atomic(i
->path
, i
->mode
);
1507 mac_selinux_create_file_clear();
1511 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1512 creation
= CREATION_FORCE
;
1514 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1518 creation
= CREATION_EXISTING
;
1520 creation
= CREATION_NORMAL
;
1521 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1523 r
= path_set_perms(i
, i
->path
);
1530 case CREATE_SYMLINK
: {
1531 RUN_WITH_UMASK(0000)
1532 (void) mkdir_parents_label(i
->path
, 0755);
1534 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1535 r
= symlink(i
->argument
, i
->path
);
1536 mac_selinux_create_file_clear();
1539 _cleanup_free_
char *x
= NULL
;
1541 if (errno
!= EEXIST
)
1542 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1544 r
= readlink_malloc(i
->path
, &x
);
1545 if (r
< 0 || !streq(i
->argument
, x
)) {
1548 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1549 r
= symlink_atomic(i
->argument
, i
->path
);
1550 mac_selinux_create_file_clear();
1552 if (IN_SET(r
, -EEXIST
, -ENOTEMPTY
)) {
1553 r
= rm_rf(i
->path
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
1555 return log_error_errno(r
, "rm -fr %s failed: %m", i
->path
);
1557 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1558 r
= symlink(i
->argument
, i
->path
) < 0 ? -errno
: 0;
1559 mac_selinux_create_file_clear();
1562 return log_error_errno(r
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1564 creation
= CREATION_FORCE
;
1566 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1570 creation
= CREATION_EXISTING
;
1573 creation
= CREATION_NORMAL
;
1574 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1578 case CREATE_BLOCK_DEVICE
:
1579 case CREATE_CHAR_DEVICE
: {
1582 if (have_effective_cap(CAP_MKNOD
) == 0) {
1583 /* In a container we lack CAP_MKNOD. We
1584 shouldn't attempt to create the device node in
1585 that case to avoid noise, and we don't support
1586 virtualized devices in containers anyway. */
1588 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1592 RUN_WITH_UMASK(0000)
1593 (void) mkdir_parents_label(i
->path
, 0755);
1595 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1597 RUN_WITH_UMASK(0000) {
1598 mac_selinux_create_file_prepare(i
->path
, file_type
);
1599 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1600 mac_selinux_create_file_clear();
1604 if (errno
== EPERM
) {
1605 log_debug("We lack permissions, possibly because of cgroup configuration; "
1606 "skipping creation of device node %s.", i
->path
);
1610 if (errno
!= EEXIST
)
1611 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1613 if (lstat(i
->path
, &st
) < 0)
1614 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1616 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1620 RUN_WITH_UMASK(0000) {
1621 mac_selinux_create_file_prepare(i
->path
, file_type
);
1622 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1623 mac_selinux_create_file_clear();
1627 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1628 creation
= CREATION_FORCE
;
1630 log_debug("%s is not a device node.", i
->path
);
1634 creation
= CREATION_EXISTING
;
1636 creation
= CREATION_NORMAL
;
1638 log_debug("%s %s device node \"%s\" %u:%u.",
1639 creation_mode_verb_to_string(creation
),
1640 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1641 i
->path
, major(i
->mode
), minor(i
->mode
));
1643 r
= path_set_perms(i
, i
->path
);
1652 r
= glob_item(i
, path_set_perms
, false);
1657 case RECURSIVE_RELABEL_PATH
:
1658 r
= glob_item(i
, path_set_perms
, true);
1664 r
= glob_item(i
, path_set_xattrs
, false);
1669 case RECURSIVE_SET_XATTR
:
1670 r
= glob_item(i
, path_set_xattrs
, true);
1676 r
= glob_item(i
, path_set_acls
, false);
1681 case RECURSIVE_SET_ACL
:
1682 r
= glob_item(i
, path_set_acls
, true);
1688 r
= glob_item(i
, path_set_attribute
, false);
1693 case RECURSIVE_SET_ATTRIBUTE
:
1694 r
= glob_item(i
, path_set_attribute
, true);
1703 static int remove_item_instance(Item
*i
, const char *instance
) {
1711 if (remove(instance
) < 0 && errno
!= ENOENT
)
1712 return log_error_errno(errno
, "rm(%s): %m", instance
);
1716 case TRUNCATE_DIRECTORY
:
1717 case RECURSIVE_REMOVE_PATH
:
1718 /* FIXME: we probably should use dir_cleanup() here
1719 * instead of rm_rf() so that 'x' is honoured. */
1720 log_debug("rm -rf \"%s\"", instance
);
1721 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1722 if (r
< 0 && r
!= -ENOENT
)
1723 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1728 assert_not_reached("wut?");
1734 static int remove_item(Item
*i
) {
1737 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1742 case TRUNCATE_DIRECTORY
:
1743 case RECURSIVE_REMOVE_PATH
:
1744 return glob_item(i
, remove_item_instance
, false);
1751 static int clean_item_instance(Item
*i
, const char* instance
) {
1752 _cleanup_closedir_
DIR *d
= NULL
;
1756 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1763 n
= now(CLOCK_REALTIME
);
1767 cutoff
= n
- i
->age
;
1769 d
= opendir_nomod(instance
);
1771 if (IN_SET(errno
, ENOENT
, ENOTDIR
)) {
1772 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1776 return log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1779 if (fstat(dirfd(d
), &s
) < 0)
1780 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1782 if (!S_ISDIR(s
.st_mode
)) {
1783 log_error("%s is not a directory.", i
->path
);
1787 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1788 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1790 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1792 log_debug("Cleanup threshold for %s \"%s\" is %s",
1793 mountpoint
? "mount point" : "directory",
1795 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1797 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1798 MAX_DEPTH
, i
->keep_first_level
);
1801 static int clean_item(Item
*i
) {
1804 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1807 case CREATE_DIRECTORY
:
1808 case CREATE_SUBVOLUME
:
1809 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1810 case CREATE_SUBVOLUME_NEW_QUOTA
:
1811 case TRUNCATE_DIRECTORY
:
1814 clean_item_instance(i
, i
->path
);
1816 case EMPTY_DIRECTORY
:
1817 case IGNORE_DIRECTORY_PATH
:
1818 return glob_item(i
, clean_item_instance
, false);
1824 static int process_item_array(ItemArray
*array
);
1826 static int process_item(Item
*i
) {
1828 _cleanup_free_
char *prefix
= NULL
;
1837 prefix
= malloc(strlen(i
->path
) + 1);
1841 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1844 j
= ordered_hashmap_get(items
, prefix
);
1848 s
= process_item_array(j
);
1849 if (s
< 0 && t
== 0)
1854 if (chase_symlinks(i
->path
, NULL
, CHASE_NO_AUTOFS
, NULL
) == -EREMOTE
)
1857 r
= arg_create
? create_item(i
) : 0;
1858 q
= arg_remove
? remove_item(i
) : 0;
1859 p
= arg_clean
? clean_item(i
) : 0;
1867 static int process_item_array(ItemArray
*array
) {
1873 for (n
= 0; n
< array
->count
; n
++) {
1874 k
= process_item(array
->items
+ n
);
1875 if (k
< 0 && r
== 0)
1882 static void item_free_contents(Item
*i
) {
1886 strv_free(i
->xattrs
);
1889 acl_free(i
->acl_access
);
1890 acl_free(i
->acl_default
);
1894 static void item_array_free(ItemArray
*a
) {
1900 for (n
= 0; n
< a
->count
; n
++)
1901 item_free_contents(a
->items
+ n
);
1906 static int item_compare(const void *a
, const void *b
) {
1907 const Item
*x
= a
, *y
= b
;
1909 /* Make sure that the ownership taking item is put first, so
1910 * that we first create the node, and then can adjust it */
1912 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1914 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1917 return (int) x
->type
- (int) y
->type
;
1920 static bool item_compatible(Item
*a
, Item
*b
) {
1923 assert(streq(a
->path
, b
->path
));
1925 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1926 /* check if the items are the same */
1927 return streq_ptr(a
->argument
, b
->argument
) &&
1929 a
->uid_set
== b
->uid_set
&&
1932 a
->gid_set
== b
->gid_set
&&
1935 a
->mode_set
== b
->mode_set
&&
1936 a
->mode
== b
->mode
&&
1938 a
->age_set
== b
->age_set
&&
1941 a
->mask_perms
== b
->mask_perms
&&
1943 a
->keep_first_level
== b
->keep_first_level
&&
1945 a
->major_minor
== b
->major_minor
;
1950 static bool should_include_path(const char *path
) {
1953 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1954 if (path_startswith(path
, *prefix
)) {
1955 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1960 STRV_FOREACH(prefix
, arg_include_prefixes
)
1961 if (path_startswith(path
, *prefix
)) {
1962 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1966 /* no matches, so we should include this path only if we
1967 * have no whitelist at all */
1968 if (strv_isempty(arg_include_prefixes
))
1971 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1975 static int specifier_expansion_from_arg(Item
*i
) {
1976 _cleanup_free_
char *unescaped
= NULL
, *resolved
= NULL
;
1982 if (i
->argument
== NULL
)
1987 case CREATE_SYMLINK
:
1991 r
= cunescape(i
->argument
, 0, &unescaped
);
1993 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
1995 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &resolved
);
1999 free_and_replace(i
->argument
, resolved
);
2003 case RECURSIVE_SET_XATTR
:
2006 STRV_FOREACH (xattr
, i
->xattrs
) {
2007 r
= specifier_printf(*xattr
, specifier_table
, NULL
, &resolved
);
2011 free_and_replace(*xattr
, resolved
);
2021 static int parse_line(const char *fname
, unsigned line
, const char *buffer
, bool *invalid_config
) {
2023 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
2024 _cleanup_(item_free_contents
) Item i
= {};
2025 ItemArray
*existing
;
2028 bool force
= false, boot
= false;
2034 r
= extract_many_words(
2046 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2047 /* invalid quoting and such or an unknown specifier */
2048 *invalid_config
= true;
2049 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
2053 *invalid_config
= true;
2054 log_error("[%s:%u] Syntax error.", fname
, line
);
2058 if (!isempty(buffer
) && !streq(buffer
, "-")) {
2059 i
.argument
= strdup(buffer
);
2064 if (isempty(action
)) {
2065 *invalid_config
= true;
2066 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
2070 for (pos
= 1; action
[pos
]; pos
++) {
2071 if (action
[pos
] == '!' && !boot
)
2073 else if (action
[pos
] == '+' && !force
)
2076 *invalid_config
= true;
2077 log_error("[%s:%u] Unknown modifiers in command '%s'",
2078 fname
, line
, action
);
2083 if (boot
&& !arg_boot
) {
2084 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
2092 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
2094 return log_unresolvable_specifier(fname
, line
);
2096 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2097 *invalid_config
= true;
2098 return log_error_errno(r
, "[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
2103 case CREATE_DIRECTORY
:
2104 case CREATE_SUBVOLUME
:
2105 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
2106 case CREATE_SUBVOLUME_NEW_QUOTA
:
2107 case EMPTY_DIRECTORY
:
2108 case TRUNCATE_DIRECTORY
:
2111 case IGNORE_DIRECTORY_PATH
:
2113 case RECURSIVE_REMOVE_PATH
:
2116 case RECURSIVE_RELABEL_PATH
:
2118 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
2126 case CREATE_SYMLINK
:
2128 i
.argument
= strappend("/usr/share/factory/", i
.path
);
2136 *invalid_config
= true;
2137 log_error("[%s:%u] Write file requires argument.", fname
, line
);
2144 i
.argument
= strappend("/usr/share/factory/", i
.path
);
2147 } else if (!path_is_absolute(i
.argument
)) {
2148 *invalid_config
= true;
2149 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
2153 path_kill_slashes(i
.argument
);
2156 case CREATE_CHAR_DEVICE
:
2157 case CREATE_BLOCK_DEVICE
: {
2158 unsigned major
, minor
;
2161 *invalid_config
= true;
2162 log_error("[%s:%u] Device file requires argument.", fname
, line
);
2166 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
2167 *invalid_config
= true;
2168 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
2172 i
.major_minor
= makedev(major
, minor
);
2177 case RECURSIVE_SET_XATTR
:
2179 *invalid_config
= true;
2180 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
2183 r
= parse_xattrs_from_arg(&i
);
2189 case RECURSIVE_SET_ACL
:
2191 *invalid_config
= true;
2192 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
2195 r
= parse_acls_from_arg(&i
);
2201 case RECURSIVE_SET_ATTRIBUTE
:
2203 *invalid_config
= true;
2204 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
2207 r
= parse_attribute_from_arg(&i
);
2208 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2209 *invalid_config
= true;
2215 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
2216 *invalid_config
= true;
2220 if (!path_is_absolute(i
.path
)) {
2221 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
2222 *invalid_config
= true;
2226 path_kill_slashes(i
.path
);
2228 if (!should_include_path(i
.path
))
2231 r
= specifier_expansion_from_arg(&i
);
2233 return log_unresolvable_specifier(fname
, line
);
2235 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2236 *invalid_config
= true;
2237 return log_error_errno(r
, "[%s:%u] Failed to substitute specifiers in argument: %m",
2244 p
= prefix_root(arg_root
, i
.path
);
2252 if (!isempty(user
) && !streq(user
, "-")) {
2253 const char *u
= user
;
2255 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
2257 *invalid_config
= true;
2258 return log_error_errno(r
, "[%s:%u] Unknown user '%s'.", fname
, line
, user
);
2264 if (!isempty(group
) && !streq(group
, "-")) {
2265 const char *g
= group
;
2267 r
= get_group_creds(&g
, &i
.gid
);
2269 *invalid_config
= true;
2270 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2277 if (!isempty(mode
) && !streq(mode
, "-")) {
2278 const char *mm
= mode
;
2282 i
.mask_perms
= true;
2286 if (parse_mode(mm
, &m
) < 0) {
2287 *invalid_config
= true;
2288 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2295 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2297 if (!isempty(age
) && !streq(age
, "-")) {
2298 const char *a
= age
;
2301 i
.keep_first_level
= true;
2305 if (parse_sec(a
, &i
.age
) < 0) {
2306 *invalid_config
= true;
2307 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2314 h
= needs_glob(i
.type
) ? globs
: items
;
2316 existing
= ordered_hashmap_get(h
, i
.path
);
2320 for (n
= 0; n
< existing
->count
; n
++) {
2321 if (!item_compatible(existing
->items
+ n
, &i
)) {
2322 log_notice("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2323 fname
, line
, i
.path
);
2328 existing
= new0(ItemArray
, 1);
2332 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2337 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2340 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2342 /* Sort item array, to enforce stable ordering of application */
2343 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2349 static void help(void) {
2350 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2351 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2352 " -h --help Show this help\n"
2353 " --user Execute user configuration\n"
2354 " --version Show package version\n"
2355 " --create Create marked files/directories\n"
2356 " --clean Clean up marked directories\n"
2357 " --remove Remove marked files/directories\n"
2358 " --boot Execute actions only safe at boot\n"
2359 " --prefix=PATH Only apply rules with the specified prefix\n"
2360 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2361 " --root=PATH Operate on an alternate filesystem root\n"
2362 " --replace=PATH Treat arguments as replacement for PATH\n"
2363 , program_invocation_short_name
);
2366 static int parse_argv(int argc
, char *argv
[]) {
2369 ARG_VERSION
= 0x100,
2381 static const struct option options
[] = {
2382 { "help", no_argument
, NULL
, 'h' },
2383 { "user", no_argument
, NULL
, ARG_USER
},
2384 { "version", no_argument
, NULL
, ARG_VERSION
},
2385 { "create", no_argument
, NULL
, ARG_CREATE
},
2386 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2387 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2388 { "boot", no_argument
, NULL
, ARG_BOOT
},
2389 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2390 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2391 { "root", required_argument
, NULL
, ARG_ROOT
},
2392 { "replace", required_argument
, NULL
, ARG_REPLACE
},
2401 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2433 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2437 case ARG_EXCLUDE_PREFIX
:
2438 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2443 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2449 if (!path_is_absolute(optarg
) ||
2450 !endswith(optarg
, ".conf")) {
2451 log_error("The argument to --replace= must an absolute path to a config file");
2455 arg_replace
= optarg
;
2462 assert_not_reached("Unhandled option");
2465 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2466 log_error("You need to specify at least one of --clean, --create or --remove.");
2470 if (arg_replace
&& optind
>= argc
) {
2471 log_error("When --replace= is given, some configuration items must be specified");
2478 static int read_config_file(char **config_dirs
, const char *fn
, bool ignore_enoent
, bool *invalid_config
) {
2479 _cleanup_fclose_
FILE *_f
= NULL
;
2481 char line
[LINE_MAX
];
2489 if (streq(fn
, "-")) {
2490 log_debug("Reading config from stdin…");
2494 r
= search_and_fopen(fn
, "re", arg_root
, (const char**) config_dirs
, &_f
);
2496 if (ignore_enoent
&& r
== -ENOENT
) {
2497 log_debug_errno(r
, "Failed to open \"%s\", ignoring: %m", fn
);
2501 return log_error_errno(r
, "Failed to open '%s': %m", fn
);
2503 log_debug("Reading config file \"%s\"…", fn
);
2507 FOREACH_LINE(line
, f
, break) {
2510 bool invalid_line
= false;
2515 if (IN_SET(*l
, 0, '#'))
2518 k
= parse_line(fn
, v
, l
, &invalid_line
);
2521 /* Allow reporting with a special code if the caller requested this */
2522 *invalid_config
= true;
2524 /* The first error becomes our return value */
2529 /* we have to determine age parameter for each entry of type X */
2530 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2532 Item
*j
, *candidate_item
= NULL
;
2534 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2537 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2538 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2541 if (path_equal(j
->path
, i
->path
)) {
2546 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2547 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2551 if (candidate_item
&& candidate_item
->age_set
) {
2552 i
->age
= candidate_item
->age
;
2558 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2566 static int parse_arguments(char **config_dirs
, char **args
, bool *invalid_config
) {
2570 STRV_FOREACH(arg
, args
) {
2571 r
= read_config_file(config_dirs
, *arg
, false, invalid_config
);
2579 static int read_config_files(char **config_dirs
, char **args
, bool *invalid_config
) {
2580 _cleanup_strv_free_
char **files
= NULL
;
2581 _cleanup_free_
char *p
= NULL
;
2585 r
= conf_files_list_strv(&files
, ".conf", arg_root
, 0, (const char* const*) config_dirs
);
2587 return log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2590 r
= conf_files_insert(&files
, arg_root
, config_dirs
, arg_replace
);
2592 return log_error_errno(r
, "Failed to extend tmpfiles.d file list: %m");
2594 p
= path_join(arg_root
, arg_replace
, NULL
);
2599 STRV_FOREACH(f
, files
)
2600 if (p
&& path_equal(*f
, p
)) {
2601 log_debug("Parsing arguments at position \"%s\"…", *f
);
2603 r
= parse_arguments(config_dirs
, args
, invalid_config
);
2607 /* Just warn, ignore result otherwise.
2608 * read_config_file() has some debug output, so no need to print anything. */
2609 (void) read_config_file(config_dirs
, *f
, true, invalid_config
);
2614 int main(int argc
, char *argv
[]) {
2618 _cleanup_strv_free_
char **config_dirs
= NULL
;
2619 bool invalid_config
= false;
2621 r
= parse_argv(argc
, argv
);
2625 log_set_target(LOG_TARGET_AUTO
);
2626 log_parse_environment();
2633 items
= ordered_hashmap_new(&string_hash_ops
);
2634 globs
= ordered_hashmap_new(&string_hash_ops
);
2636 if (!items
|| !globs
) {
2644 r
= user_config_paths(&config_dirs
);
2646 log_error_errno(r
, "Failed to initialize configuration directory list: %m");
2650 config_dirs
= strv_split_nulstr(CONF_PATHS_NULSTR("tmpfiles.d"));
2657 if (DEBUG_LOGGING
) {
2658 _cleanup_free_
char *t
= NULL
;
2660 t
= strv_join(config_dirs
, "\n\t");
2662 log_debug("Looking for configuration files in (higher priority first:\n\t%s", t
);
2665 /* If command line arguments are specified along with --replace, read all
2666 * configuration files and insert the positional arguments at the specified
2667 * place. Otherwise, if command line arguments are specified, execute just
2668 * them, and finally, without --replace= or any positional arguments, just
2669 * read configuration and execute it.
2671 if (arg_replace
|| optind
>= argc
)
2672 r
= read_config_files(config_dirs
, argv
+ optind
, &invalid_config
);
2674 r
= parse_arguments(config_dirs
, argv
+ optind
, &invalid_config
);
2680 /* The non-globbing ones usually create things, hence we apply
2682 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2683 k
= process_item_array(a
);
2684 if (k
< 0 && r
== 0)
2688 /* The globbing ones usually alter things, hence we apply them
2690 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2691 k
= process_item_array(a
);
2692 if (k
< 0 && r
== 0)
2697 ordered_hashmap_free_with_destructor(items
, item_array_free
);
2698 ordered_hashmap_free_with_destructor(globs
, item_array_free
);
2700 free(arg_include_prefixes
);
2701 free(arg_exclude_prefixes
);
2704 set_free_free(unix_sockets
);
2706 mac_selinux_finish();
2709 return EXIT_FAILURE
;
2710 else if (invalid_config
)
2713 return EXIT_SUCCESS
;