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
);
313 *ret
= TAKE_PTR(res
);
317 static bool needs_glob(ItemType t
) {
321 IGNORE_DIRECTORY_PATH
,
323 RECURSIVE_REMOVE_PATH
,
327 RECURSIVE_RELABEL_PATH
,
333 RECURSIVE_SET_ATTRIBUTE
);
336 static bool takes_ownership(ItemType t
) {
344 CREATE_SUBVOLUME_INHERIT_QUOTA
,
345 CREATE_SUBVOLUME_NEW_QUOTA
,
353 IGNORE_DIRECTORY_PATH
,
355 RECURSIVE_REMOVE_PATH
);
358 static struct Item
* find_glob(OrderedHashmap
*h
, const char *match
) {
362 ORDERED_HASHMAP_FOREACH(j
, h
, i
) {
365 for (n
= 0; n
< j
->count
; n
++) {
366 Item
*item
= j
->items
+ n
;
368 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
376 static void load_unix_sockets(void) {
377 _cleanup_fclose_
FILE *f
= NULL
;
383 /* We maintain a cache of the sockets we found in /proc/net/unix to speed things up a little. */
385 unix_sockets
= set_new(&path_hash_ops
);
391 f
= fopen("/proc/net/unix", "re");
393 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_WARNING
, errno
,
394 "Failed to open /proc/net/unix, ignoring: %m");
399 r
= read_line(f
, LONG_LINE_MAX
, NULL
);
401 log_warning_errno(r
, "Failed to skip /proc/net/unix header line: %m");
405 log_warning("Premature end of file reading /proc/net/unix.");
410 _cleanup_free_
char *line
= NULL
;
413 r
= read_line(f
, LONG_LINE_MAX
, &line
);
415 log_warning_errno(r
, "Failed to read /proc/net/unix line, ignoring: %m");
418 if (r
== 0) /* EOF */
421 p
= strchr(line
, ':');
429 p
+= strspn(p
, WHITESPACE
);
430 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
431 p
+= strspn(p
, WHITESPACE
);
442 path_kill_slashes(s
);
444 r
= set_consume(unix_sockets
, s
);
445 if (r
< 0 && r
!= -EEXIST
) {
446 log_warning_errno(r
, "Failed to add AF_UNIX socket to set, ignoring: %m");
454 unix_sockets
= set_free_free(unix_sockets
);
457 static bool unix_socket_alive(const char *fn
) {
463 return !!set_get(unix_sockets
, (char*) fn
);
465 /* We don't know, so assume yes */
469 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
471 int mount_id_parent
, mount_id
;
474 r_p
= name_to_handle_at_loop(dirfd(d
), ".", NULL
, &mount_id_parent
, 0);
478 r
= name_to_handle_at_loop(dirfd(d
), subdir
, NULL
, &mount_id
, 0);
482 /* got no handle; make no assumptions, return error */
483 if (r_p
< 0 && r
< 0)
486 /* got both handles; if they differ, it is a mount point */
487 if (r_p
>= 0 && r
>= 0)
488 return mount_id_parent
!= mount_id
;
490 /* got only one handle; assume different mount points if one
491 * of both queries was not supported by the filesystem */
492 if (IN_SET(r_p
, -ENOSYS
, -EOPNOTSUPP
) || IN_SET(r
, -ENOSYS
, -EOPNOTSUPP
))
501 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
504 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
508 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
512 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
514 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
519 static DIR* opendir_nomod(const char *path
) {
520 return xopendirat_nomod(AT_FDCWD
, path
);
523 static int dir_cleanup(
527 const struct stat
*ds
,
532 bool keep_this_level
) {
535 struct timespec times
[2];
536 bool deleted
= false;
539 FOREACH_DIRENT_ALL(dent
, d
, break) {
542 _cleanup_free_
char *sub_path
= NULL
;
544 if (dot_or_dot_dot(dent
->d_name
))
547 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
551 /* FUSE, NFS mounts, SELinux might return EACCES */
552 r
= log_full_errno(errno
== EACCES
? LOG_DEBUG
: LOG_ERR
, errno
,
553 "stat(%s/%s) failed: %m", p
, dent
->d_name
);
557 /* Stay on the same filesystem */
558 if (s
.st_dev
!= rootdev
) {
559 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
563 /* Try to detect bind mounts of the same filesystem instance; they
564 * do not differ in device major/minors. This type of query is not
565 * supported on all kernels or filesystem types though. */
566 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
567 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
572 sub_path
= strjoin(p
, "/", dent
->d_name
);
578 /* Is there an item configured for this path? */
579 if (ordered_hashmap_get(items
, sub_path
)) {
580 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
584 if (find_glob(globs
, sub_path
)) {
585 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
589 if (S_ISDIR(s
.st_mode
)) {
592 streq(dent
->d_name
, "lost+found") &&
594 log_debug("Ignoring \"%s\".", sub_path
);
599 log_warning("Reached max depth on \"%s\".", sub_path
);
601 _cleanup_closedir_
DIR *sub_dir
;
604 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
607 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
612 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
617 /* Note: if you are wondering why we don't
618 * support the sticky bit for excluding
619 * directories from cleaning like we do it for
620 * other file system objects: well, the sticky
621 * bit already has a meaning for directories,
622 * so we don't want to overload that. */
624 if (keep_this_level
) {
625 log_debug("Keeping \"%s\".", sub_path
);
629 /* Ignore ctime, we change it when deleting */
630 age
= timespec_load(&s
.st_mtim
);
632 char a
[FORMAT_TIMESTAMP_MAX
];
633 /* Follows spelling in stat(1). */
634 log_debug("Directory \"%s\": modify time %s is too new.",
636 format_timestamp_us(a
, sizeof(a
), age
));
640 age
= timespec_load(&s
.st_atim
);
642 char a
[FORMAT_TIMESTAMP_MAX
];
643 log_debug("Directory \"%s\": access time %s is too new.",
645 format_timestamp_us(a
, sizeof(a
), age
));
649 log_debug("Removing directory \"%s\".", sub_path
);
650 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
651 if (!IN_SET(errno
, ENOENT
, ENOTEMPTY
))
652 r
= log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
655 /* Skip files for which the sticky bit is
656 * set. These are semantics we define, and are
657 * unknown elsewhere. See XDG_RUNTIME_DIR
658 * specification for details. */
659 if (s
.st_mode
& S_ISVTX
) {
660 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
664 if (mountpoint
&& S_ISREG(s
.st_mode
))
665 if (s
.st_uid
== 0 && STR_IN_SET(dent
->d_name
,
669 log_debug("Skipping \"%s\".", sub_path
);
673 /* Ignore sockets that are listed in /proc/net/unix */
674 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
675 log_debug("Skipping \"%s\": live socket.", sub_path
);
679 /* Ignore device nodes */
680 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
681 log_debug("Skipping \"%s\": a device.", sub_path
);
685 /* Keep files on this level around if this is
687 if (keep_this_level
) {
688 log_debug("Keeping \"%s\".", sub_path
);
692 age
= timespec_load(&s
.st_mtim
);
694 char a
[FORMAT_TIMESTAMP_MAX
];
695 /* Follows spelling in stat(1). */
696 log_debug("File \"%s\": modify time %s is too new.",
698 format_timestamp_us(a
, sizeof(a
), age
));
702 age
= timespec_load(&s
.st_atim
);
704 char a
[FORMAT_TIMESTAMP_MAX
];
705 log_debug("File \"%s\": access time %s is too new.",
707 format_timestamp_us(a
, sizeof(a
), age
));
711 age
= timespec_load(&s
.st_ctim
);
713 char a
[FORMAT_TIMESTAMP_MAX
];
714 log_debug("File \"%s\": change time %s is too new.",
716 format_timestamp_us(a
, sizeof(a
), age
));
720 log_debug("unlink \"%s\"", sub_path
);
722 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
724 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
733 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
735 /* Restore original directory timestamps */
736 times
[0] = ds
->st_atim
;
737 times
[1] = ds
->st_mtim
;
739 age1
= timespec_load(&ds
->st_atim
);
740 age2
= timespec_load(&ds
->st_mtim
);
741 log_debug("Restoring access and modification time on \"%s\": %s, %s",
743 format_timestamp_us(a
, sizeof(a
), age1
),
744 format_timestamp_us(b
, sizeof(b
), age2
));
745 if (futimens(dirfd(d
), times
) < 0)
746 log_error_errno(errno
, "utimensat(%s): %m", p
);
752 static bool dangerous_hardlinks(void) {
753 _cleanup_free_
char *value
= NULL
;
754 static int cached
= -1;
757 /* Check whether the fs.protected_hardlinks sysctl is on. If we can't determine it we assume its off, as that's
758 * what the upstream default is. */
763 r
= read_one_line_file("/proc/sys/fs/protected_hardlinks", &value
);
765 log_debug_errno(r
, "Failed to read fs.protected_hardlinks sysctl: %m");
769 r
= parse_boolean(value
);
771 log_debug_errno(r
, "Failed to parse fs.protected_hardlinks sysctl: %m");
779 static bool hardlink_vulnerable(const struct stat
*st
) {
782 return !S_ISDIR(st
->st_mode
) && st
->st_nlink
> 1 && dangerous_hardlinks();
785 static int fd_set_perms(Item
*i
, int fd
, const struct stat
*st
) {
786 _cleanup_free_
char *path
= NULL
;
792 r
= fd_get_path(fd
, &path
);
796 if (!i
->mode_set
&& !i
->uid_set
&& !i
->gid_set
)
799 if (hardlink_vulnerable(st
)) {
800 log_error("Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path
);
805 if (S_ISLNK(st
->st_mode
))
806 log_debug("Skipping mode fix for symlink %s.", path
);
811 if (!(st
->st_mode
& 0111))
813 if (!(st
->st_mode
& 0222))
815 if (!(st
->st_mode
& 0444))
817 if (!S_ISDIR(st
->st_mode
))
818 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
821 if (m
== (st
->st_mode
& 07777))
822 log_debug("\"%s\" has correct mode %o already.", path
, st
->st_mode
);
824 char procfs_path
[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
826 log_debug("Changing \"%s\" to mode %o.", path
, m
);
828 /* fchmodat() still doesn't have AT_EMPTY_PATH flag. */
829 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
831 if (chmod(procfs_path
, m
) < 0)
832 return log_error_errno(errno
, "chmod() of %s via %s failed: %m", path
, procfs_path
);
837 if ((i
->uid_set
&& i
->uid
!= st
->st_uid
) ||
838 (i
->gid_set
&& i
->gid
!= st
->st_gid
)) {
839 log_debug("Changing \"%s\" to owner "UID_FMT
":"GID_FMT
,
841 i
->uid_set
? i
->uid
: UID_INVALID
,
842 i
->gid_set
? i
->gid
: GID_INVALID
);
846 i
->uid_set
? i
->uid
: UID_INVALID
,
847 i
->gid_set
? i
->gid
: GID_INVALID
,
849 return log_error_errno(errno
, "fchownat() of %s failed: %m", path
);
853 return label_fix(path
, 0);
856 static int path_set_perms(Item
*i
, const char *path
) {
857 _cleanup_close_
int fd
= -1;
863 fd
= open(path
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
865 int level
= LOG_ERR
, r
= -errno
;
867 /* Option "e" operates only on existing objects. Do not
868 * print errors about non-existent files or directories */
869 if (i
->type
== EMPTY_DIRECTORY
&& errno
== ENOENT
) {
874 log_full_errno(level
, errno
, "Adjusting owner and mode for %s failed: %m", path
);
878 if (fstat(fd
, &st
) < 0)
879 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
881 return fd_set_perms(i
, fd
, &st
);
884 static int parse_xattrs_from_arg(Item
*i
) {
894 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
;
896 r
= extract_first_word(&p
, &xattr
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
898 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
902 r
= split_pair(xattr
, "=", &name
, &value
);
904 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
908 if (isempty(name
) || isempty(value
)) {
909 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
913 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
922 static int fd_set_xattrs(Item
*i
, int fd
, const struct stat
*st
) {
923 char procfs_path
[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
924 _cleanup_free_
char *path
= NULL
;
925 char **name
, **value
;
931 r
= fd_get_path(fd
, &path
);
935 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
937 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
938 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
939 if (setxattr(procfs_path
, *name
, *value
, strlen(*value
), 0) < 0)
940 return log_error_errno(errno
, "Setting extended attribute %s=%s on %s failed: %m",
941 *name
, *value
, path
);
946 static int path_set_xattrs(Item
*i
, const char *path
) {
947 _cleanup_close_
int fd
= -1;
952 fd
= open(path
, O_CLOEXEC
|O_NOFOLLOW
|O_PATH
);
954 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
956 return fd_set_xattrs(i
, fd
, NULL
);
959 static int parse_acls_from_arg(Item
*item
) {
965 /* If force (= modify) is set, we will not modify the acl
966 * afterwards, so the mask can be added now if necessary. */
968 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
970 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
972 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
979 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
980 _cleanup_(acl_free_charpp
) char *t
= NULL
;
981 _cleanup_(acl_freep
) acl_t dup
= NULL
;
984 /* Returns 0 for success, positive error if already warned,
985 * negative error otherwise. */
988 r
= acls_for_file(path
, type
, acl
, &dup
);
992 r
= calc_acl_mask_if_needed(&dup
);
1000 /* the mask was already added earlier if needed */
1003 r
= add_base_acls_if_needed(&dup
, path
);
1007 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
1008 log_debug("Setting %s ACL %s on %s.",
1009 type
== ACL_TYPE_ACCESS
? "access" : "default",
1012 r
= acl_set_file(path
, type
, dup
);
1014 /* Return positive to indicate we already warned */
1015 return -log_error_errno(errno
,
1016 "Setting %s ACL \"%s\" on %s failed: %m",
1017 type
== ACL_TYPE_ACCESS
? "access" : "default",
1024 static int fd_set_acls(Item
*item
, int fd
, const struct stat
*st
) {
1027 char procfs_path
[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
1028 _cleanup_free_
char *path
= NULL
;
1034 r
= fd_get_path(fd
, &path
);
1038 if (hardlink_vulnerable(st
)) {
1039 log_error("Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path
);
1043 if (S_ISLNK(st
->st_mode
)) {
1044 log_debug("Skipping ACL fix for symlink %s.", path
);
1048 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
1050 if (item
->acl_access
)
1051 r
= path_set_acl(procfs_path
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
1053 if (r
== 0 && item
->acl_default
)
1054 r
= path_set_acl(procfs_path
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
1057 return -r
; /* already warned */
1058 if (r
== -EOPNOTSUPP
) {
1059 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
1063 return log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
1068 static int path_set_acls(Item
*item
, const char *path
) {
1071 _cleanup_close_
int fd
= -1;
1077 fd
= open(path
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
1079 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
1081 if (fstat(fd
, &st
) < 0)
1082 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
1084 r
= fd_set_acls(item
, fd
, &st
);
1089 #define ATTRIBUTES_ALL \
1098 FS_JOURNAL_DATA_FL | \
1105 static int parse_attribute_from_arg(Item
*item
) {
1107 static const struct {
1111 { 'A', FS_NOATIME_FL
}, /* do not update atime */
1112 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
1113 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
1114 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
1115 { 'c', FS_COMPR_FL
}, /* Compress file */
1116 { 'd', FS_NODUMP_FL
}, /* do not dump file */
1117 { 'e', FS_EXTENT_FL
}, /* Extents */
1118 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
1119 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
1120 { 's', FS_SECRM_FL
}, /* Secure deletion */
1121 { 'u', FS_UNRM_FL
}, /* Undelete */
1122 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
1123 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies */
1124 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
1133 unsigned value
= 0, mask
= 0;
1143 } else if (*p
== '-') {
1146 } else if (*p
== '=') {
1152 if (isempty(p
) && mode
!= MODE_SET
) {
1153 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
1157 for (; p
&& *p
; p
++) {
1160 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
1161 if (*p
== attributes
[i
].character
)
1164 if (i
>= ELEMENTSOF(attributes
)) {
1165 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
1169 v
= attributes
[i
].value
;
1171 SET_FLAG(value
, v
, IN_SET(mode
, MODE_ADD
, MODE_SET
));
1176 if (mode
== MODE_SET
)
1177 mask
|= ATTRIBUTES_ALL
;
1181 item
->attribute_mask
= mask
;
1182 item
->attribute_value
= value
;
1183 item
->attribute_set
= true;
1188 static int fd_set_attribute(Item
*item
, int fd
, const struct stat
*st
) {
1189 _cleanup_close_
int procfs_fd
= -1;
1190 _cleanup_free_
char *path
= NULL
;
1194 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
1197 r
= fd_get_path(fd
, &path
);
1201 /* Issuing the file attribute ioctls on device nodes is not
1202 * safe, as that will be delivered to the drivers, not the
1203 * file system containing the device node. */
1204 if (!S_ISREG(st
->st_mode
) && !S_ISDIR(st
->st_mode
)) {
1205 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
1209 f
= item
->attribute_value
& item
->attribute_mask
;
1211 /* Mask away directory-specific flags */
1212 if (!S_ISDIR(st
->st_mode
))
1213 f
&= ~FS_DIRSYNC_FL
;
1215 procfs_fd
= fd_reopen(fd
, O_RDONLY
|O_CLOEXEC
|O_NOATIME
);
1219 r
= chattr_fd(procfs_fd
, f
, item
->attribute_mask
);
1221 log_full_errno(IN_SET(r
, -ENOTTY
, -EOPNOTSUPP
) ? LOG_DEBUG
: LOG_WARNING
,
1223 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
1224 path
, item
->attribute_value
, item
->attribute_mask
);
1229 static int path_set_attribute(Item
*item
, const char *path
) {
1230 _cleanup_close_
int fd
= -1;
1233 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
1236 fd
= open(path
, O_CLOEXEC
|O_NOFOLLOW
|O_PATH
);
1238 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
1240 if (fstat(fd
, &st
) < 0)
1241 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
1243 return fd_set_attribute(item
, fd
, &st
);
1246 static int write_one_file(Item
*i
, const char *path
) {
1247 _cleanup_close_
int fd
= -1;
1254 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_EXCL
|O_NOFOLLOW
:
1255 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
1257 RUN_WITH_UMASK(0000) {
1258 mac_selinux_create_file_prepare(path
, S_IFREG
);
1259 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
1260 mac_selinux_create_file_clear();
1264 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
1265 log_debug_errno(errno
, "Not writing missing file \"%s\": %m", path
);
1268 if (i
->type
== CREATE_FILE
&& errno
== EEXIST
) {
1269 log_debug_errno(errno
, "Not writing to pre-existing file \"%s\": %m", path
);
1274 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
1275 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
1278 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1282 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1284 r
= loop_write(fd
, i
->argument
, strlen(i
->argument
), false);
1286 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1288 log_debug("\"%s\" has been created.", path
);
1290 fd
= safe_close(fd
);
1293 if (stat(path
, &st
) < 0)
1294 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1297 if (!S_ISREG(st
.st_mode
)) {
1298 log_error("%s is not a file.", path
);
1302 r
= path_set_perms(i
, path
);
1309 typedef int (*action_t
)(Item
*, const char *);
1310 typedef int (*fdaction_t
)(Item
*, int fd
, const struct stat
*st
);
1312 static int item_do(Item
*i
, int fd
, const struct stat
*st
, fdaction_t action
) {
1319 /* This returns the first error we run into, but nevertheless
1321 r
= action(i
, fd
, st
);
1323 if (S_ISDIR(st
->st_mode
)) {
1324 char procfs_path
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
1325 _cleanup_closedir_
DIR *d
= NULL
;
1328 /* The passed 'fd' was opened with O_PATH. We need to convert
1329 * it into a 'regular' fd before reading the directory content. */
1330 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
1332 d
= opendir(procfs_path
);
1338 FOREACH_DIRENT_ALL(de
, d
, q
= -errno
; goto finish
) {
1342 if (dot_or_dot_dot(de
->d_name
))
1345 de_fd
= openat(fd
, de
->d_name
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
1346 if (de_fd
>= 0 && fstat(de_fd
, &de_st
) >= 0)
1347 /* pass ownership of dirent fd over */
1348 q
= item_do(i
, de_fd
, &de_st
, action
);
1352 if (q
< 0 && r
== 0)
1361 static int glob_item(Item
*i
, action_t action
) {
1362 _cleanup_globfree_ glob_t g
= {
1363 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1368 k
= safe_glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
, &g
);
1369 if (k
< 0 && k
!= -ENOENT
)
1370 return log_error_errno(k
, "glob(%s) failed: %m", i
->path
);
1372 STRV_FOREACH(fn
, g
.gl_pathv
) {
1374 if (k
< 0 && r
== 0)
1381 static int glob_item_recursively(Item
*i
, fdaction_t action
) {
1382 _cleanup_globfree_ glob_t g
= {
1383 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1388 k
= safe_glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
, &g
);
1389 if (k
< 0 && k
!= -ENOENT
)
1390 return log_error_errno(k
, "glob(%s) failed: %m", i
->path
);
1392 STRV_FOREACH(fn
, g
.gl_pathv
) {
1393 _cleanup_close_
int fd
= -1;
1396 /* Make sure we won't trigger/follow file object (such as
1397 * device nodes, automounts, ...) pointed out by 'fn' with
1398 * O_PATH. Note, when O_PATH is used, flags other than
1399 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored. */
1401 fd
= open(*fn
, O_CLOEXEC
|O_NOFOLLOW
|O_PATH
);
1407 if (fstat(fd
, &st
) < 0) {
1412 k
= item_do(i
, fd
, &st
, action
);
1413 if (k
< 0 && r
== 0)
1416 /* we passed fd ownership to the previous call */
1428 _CREATION_MODE_INVALID
= -1
1431 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1432 [CREATION_NORMAL
] = "Created",
1433 [CREATION_EXISTING
] = "Found existing",
1434 [CREATION_FORCE
] = "Created replacement",
1437 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1439 static int create_item(Item
*i
) {
1443 CreationMode creation
;
1447 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1452 case IGNORE_DIRECTORY_PATH
:
1454 case RECURSIVE_REMOVE_PATH
:
1459 RUN_WITH_UMASK(0000)
1460 (void) mkdir_parents_label(i
->path
, 0755);
1462 r
= write_one_file(i
, i
->path
);
1469 RUN_WITH_UMASK(0000)
1470 (void) mkdir_parents_label(i
->path
, 0755);
1472 log_debug("Copying tree \"%s\" to \"%s\".", i
->argument
, i
->path
);
1473 r
= copy_tree(i
->argument
, i
->path
,
1474 i
->uid_set
? i
->uid
: UID_INVALID
,
1475 i
->gid_set
? i
->gid
: GID_INVALID
,
1478 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1485 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1487 if (stat(i
->argument
, &a
) < 0)
1488 return log_error_errno(errno
, "stat(%s) failed: %m", i
->argument
);
1490 if (stat(i
->path
, &b
) < 0)
1491 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1493 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1494 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1499 r
= path_set_perms(i
, i
->path
);
1506 r
= glob_item(i
, write_one_file
);
1512 case CREATE_DIRECTORY
:
1513 case TRUNCATE_DIRECTORY
:
1514 case CREATE_SUBVOLUME
:
1515 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1516 case CREATE_SUBVOLUME_NEW_QUOTA
:
1517 RUN_WITH_UMASK(0000)
1518 (void) mkdir_parents_label(i
->path
, 0755);
1520 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1522 if (btrfs_is_subvol(isempty(arg_root
) ? "/" : arg_root
) <= 0)
1524 /* Don't create a subvolume unless the
1525 * root directory is one, too. We do
1526 * this under the assumption that if
1527 * the root directory is just a plain
1528 * directory (i.e. very light-weight),
1529 * we shouldn't try to split it up
1530 * into subvolumes (i.e. more
1531 * heavy-weight). Thus, chroot()
1532 * environments and suchlike will get
1533 * a full brtfs subvolume set up below
1534 * their tree only if they
1535 * specifically set up a btrfs
1536 * subvolume for the root dir too. */
1540 RUN_WITH_UMASK((~i
->mode
) & 0777)
1541 r
= btrfs_subvol_make(i
->path
);
1546 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1547 RUN_WITH_UMASK(0000)
1548 r
= mkdir_label(i
->path
, i
->mode
);
1553 if (!IN_SET(r
, -EEXIST
, -EROFS
))
1554 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1556 k
= is_dir(i
->path
, false);
1557 if (k
== -ENOENT
&& r
== -EROFS
)
1558 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1560 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1562 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1566 creation
= CREATION_EXISTING
;
1568 creation
= CREATION_NORMAL
;
1570 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1572 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1573 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1575 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i
->path
);
1576 else if (r
== -EROFS
)
1577 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i
->path
);
1578 else if (r
== -ENOPROTOOPT
)
1579 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i
->path
);
1581 q
= log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1583 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1585 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1589 case EMPTY_DIRECTORY
:
1590 r
= path_set_perms(i
, i
->path
);
1599 RUN_WITH_UMASK(0000) {
1600 (void) mkdir_parents_label(i
->path
, 0755);
1602 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1603 r
= mkfifo(i
->path
, i
->mode
);
1604 mac_selinux_create_file_clear();
1608 if (errno
!= EEXIST
)
1609 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1611 if (lstat(i
->path
, &st
) < 0)
1612 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1614 if (!S_ISFIFO(st
.st_mode
)) {
1617 RUN_WITH_UMASK(0000) {
1618 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1619 r
= mkfifo_atomic(i
->path
, i
->mode
);
1620 mac_selinux_create_file_clear();
1624 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1625 creation
= CREATION_FORCE
;
1627 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1631 creation
= CREATION_EXISTING
;
1633 creation
= CREATION_NORMAL
;
1634 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1636 r
= path_set_perms(i
, i
->path
);
1643 case CREATE_SYMLINK
: {
1644 RUN_WITH_UMASK(0000)
1645 (void) mkdir_parents_label(i
->path
, 0755);
1647 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1648 r
= symlink(i
->argument
, i
->path
);
1649 mac_selinux_create_file_clear();
1652 _cleanup_free_
char *x
= NULL
;
1654 if (errno
!= EEXIST
)
1655 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1657 r
= readlink_malloc(i
->path
, &x
);
1658 if (r
< 0 || !streq(i
->argument
, x
)) {
1661 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1662 r
= symlink_atomic(i
->argument
, i
->path
);
1663 mac_selinux_create_file_clear();
1665 if (IN_SET(r
, -EEXIST
, -ENOTEMPTY
)) {
1666 r
= rm_rf(i
->path
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
1668 return log_error_errno(r
, "rm -fr %s failed: %m", i
->path
);
1670 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1671 r
= symlink(i
->argument
, i
->path
) < 0 ? -errno
: 0;
1672 mac_selinux_create_file_clear();
1675 return log_error_errno(r
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1677 creation
= CREATION_FORCE
;
1679 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1683 creation
= CREATION_EXISTING
;
1686 creation
= CREATION_NORMAL
;
1687 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1691 case CREATE_BLOCK_DEVICE
:
1692 case CREATE_CHAR_DEVICE
: {
1695 if (have_effective_cap(CAP_MKNOD
) == 0) {
1696 /* In a container we lack CAP_MKNOD. We
1697 shouldn't attempt to create the device node in
1698 that case to avoid noise, and we don't support
1699 virtualized devices in containers anyway. */
1701 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1705 RUN_WITH_UMASK(0000)
1706 (void) mkdir_parents_label(i
->path
, 0755);
1708 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1710 RUN_WITH_UMASK(0000) {
1711 mac_selinux_create_file_prepare(i
->path
, file_type
);
1712 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1713 mac_selinux_create_file_clear();
1717 if (errno
== EPERM
) {
1718 log_debug("We lack permissions, possibly because of cgroup configuration; "
1719 "skipping creation of device node %s.", i
->path
);
1723 if (errno
!= EEXIST
)
1724 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1726 if (lstat(i
->path
, &st
) < 0)
1727 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1729 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1733 RUN_WITH_UMASK(0000) {
1734 mac_selinux_create_file_prepare(i
->path
, file_type
);
1735 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1736 mac_selinux_create_file_clear();
1740 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1741 creation
= CREATION_FORCE
;
1743 log_debug("%s is not a device node.", i
->path
);
1747 creation
= CREATION_EXISTING
;
1749 creation
= CREATION_NORMAL
;
1751 log_debug("%s %s device node \"%s\" %u:%u.",
1752 creation_mode_verb_to_string(creation
),
1753 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1754 i
->path
, major(i
->mode
), minor(i
->mode
));
1756 r
= path_set_perms(i
, i
->path
);
1765 r
= glob_item(i
, path_set_perms
);
1770 case RECURSIVE_RELABEL_PATH
:
1771 r
= glob_item_recursively(i
, fd_set_perms
);
1777 r
= glob_item(i
, path_set_xattrs
);
1782 case RECURSIVE_SET_XATTR
:
1783 r
= glob_item_recursively(i
, fd_set_xattrs
);
1789 r
= glob_item(i
, path_set_acls
);
1794 case RECURSIVE_SET_ACL
:
1795 r
= glob_item_recursively(i
, fd_set_acls
);
1801 r
= glob_item(i
, path_set_attribute
);
1806 case RECURSIVE_SET_ATTRIBUTE
:
1807 r
= glob_item_recursively(i
, fd_set_attribute
);
1816 static int remove_item_instance(Item
*i
, const char *instance
) {
1824 if (remove(instance
) < 0 && errno
!= ENOENT
)
1825 return log_error_errno(errno
, "rm(%s): %m", instance
);
1829 case TRUNCATE_DIRECTORY
:
1830 case RECURSIVE_REMOVE_PATH
:
1831 /* FIXME: we probably should use dir_cleanup() here
1832 * instead of rm_rf() so that 'x' is honoured. */
1833 log_debug("rm -rf \"%s\"", instance
);
1834 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1835 if (r
< 0 && r
!= -ENOENT
)
1836 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1841 assert_not_reached("wut?");
1847 static int remove_item(Item
*i
) {
1850 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1855 case TRUNCATE_DIRECTORY
:
1856 case RECURSIVE_REMOVE_PATH
:
1857 return glob_item(i
, remove_item_instance
);
1864 static int clean_item_instance(Item
*i
, const char* instance
) {
1865 _cleanup_closedir_
DIR *d
= NULL
;
1869 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1876 n
= now(CLOCK_REALTIME
);
1880 cutoff
= n
- i
->age
;
1882 d
= opendir_nomod(instance
);
1884 if (IN_SET(errno
, ENOENT
, ENOTDIR
)) {
1885 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1889 return log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1892 if (fstat(dirfd(d
), &s
) < 0)
1893 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1895 if (!S_ISDIR(s
.st_mode
)) {
1896 log_error("%s is not a directory.", i
->path
);
1900 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1901 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1903 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1905 log_debug("Cleanup threshold for %s \"%s\" is %s",
1906 mountpoint
? "mount point" : "directory",
1908 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1910 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1911 MAX_DEPTH
, i
->keep_first_level
);
1914 static int clean_item(Item
*i
) {
1917 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1920 case CREATE_DIRECTORY
:
1921 case CREATE_SUBVOLUME
:
1922 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1923 case CREATE_SUBVOLUME_NEW_QUOTA
:
1924 case TRUNCATE_DIRECTORY
:
1927 clean_item_instance(i
, i
->path
);
1929 case EMPTY_DIRECTORY
:
1930 case IGNORE_DIRECTORY_PATH
:
1931 return glob_item(i
, clean_item_instance
);
1937 static int process_item_array(ItemArray
*array
);
1939 static int process_item(Item
*i
) {
1941 _cleanup_free_
char *prefix
= NULL
;
1950 prefix
= malloc(strlen(i
->path
) + 1);
1954 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1957 j
= ordered_hashmap_get(items
, prefix
);
1961 s
= process_item_array(j
);
1962 if (s
< 0 && t
== 0)
1967 if (chase_symlinks(i
->path
, NULL
, CHASE_NO_AUTOFS
, NULL
) == -EREMOTE
)
1970 r
= arg_create
? create_item(i
) : 0;
1971 q
= arg_remove
? remove_item(i
) : 0;
1972 p
= arg_clean
? clean_item(i
) : 0;
1980 static int process_item_array(ItemArray
*array
) {
1986 for (n
= 0; n
< array
->count
; n
++) {
1987 k
= process_item(array
->items
+ n
);
1988 if (k
< 0 && r
== 0)
1995 static void item_free_contents(Item
*i
) {
1999 strv_free(i
->xattrs
);
2002 acl_free(i
->acl_access
);
2003 acl_free(i
->acl_default
);
2007 static void item_array_free(ItemArray
*a
) {
2013 for (n
= 0; n
< a
->count
; n
++)
2014 item_free_contents(a
->items
+ n
);
2019 static int item_compare(const void *a
, const void *b
) {
2020 const Item
*x
= a
, *y
= b
;
2022 /* Make sure that the ownership taking item is put first, so
2023 * that we first create the node, and then can adjust it */
2025 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
2027 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
2030 return (int) x
->type
- (int) y
->type
;
2033 static bool item_compatible(Item
*a
, Item
*b
) {
2036 assert(streq(a
->path
, b
->path
));
2038 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
2039 /* check if the items are the same */
2040 return streq_ptr(a
->argument
, b
->argument
) &&
2042 a
->uid_set
== b
->uid_set
&&
2045 a
->gid_set
== b
->gid_set
&&
2048 a
->mode_set
== b
->mode_set
&&
2049 a
->mode
== b
->mode
&&
2051 a
->age_set
== b
->age_set
&&
2054 a
->mask_perms
== b
->mask_perms
&&
2056 a
->keep_first_level
== b
->keep_first_level
&&
2058 a
->major_minor
== b
->major_minor
;
2063 static bool should_include_path(const char *path
) {
2066 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
2067 if (path_startswith(path
, *prefix
)) {
2068 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
2073 STRV_FOREACH(prefix
, arg_include_prefixes
)
2074 if (path_startswith(path
, *prefix
)) {
2075 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
2079 /* no matches, so we should include this path only if we
2080 * have no whitelist at all */
2081 if (strv_isempty(arg_include_prefixes
))
2084 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
2088 static int specifier_expansion_from_arg(Item
*i
) {
2089 _cleanup_free_
char *unescaped
= NULL
, *resolved
= NULL
;
2095 if (i
->argument
== NULL
)
2100 case CREATE_SYMLINK
:
2104 r
= cunescape(i
->argument
, 0, &unescaped
);
2106 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
2108 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &resolved
);
2112 free_and_replace(i
->argument
, resolved
);
2116 case RECURSIVE_SET_XATTR
:
2119 STRV_FOREACH (xattr
, i
->xattrs
) {
2120 r
= specifier_printf(*xattr
, specifier_table
, NULL
, &resolved
);
2124 free_and_replace(*xattr
, resolved
);
2134 static int parse_line(const char *fname
, unsigned line
, const char *buffer
, bool *invalid_config
) {
2136 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
2137 _cleanup_(item_free_contents
) Item i
= {};
2138 ItemArray
*existing
;
2141 bool force
= false, boot
= false;
2147 r
= extract_many_words(
2159 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2160 /* invalid quoting and such or an unknown specifier */
2161 *invalid_config
= true;
2162 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
2166 *invalid_config
= true;
2167 log_error("[%s:%u] Syntax error.", fname
, line
);
2171 if (!isempty(buffer
) && !streq(buffer
, "-")) {
2172 i
.argument
= strdup(buffer
);
2177 if (isempty(action
)) {
2178 *invalid_config
= true;
2179 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
2183 for (pos
= 1; action
[pos
]; pos
++) {
2184 if (action
[pos
] == '!' && !boot
)
2186 else if (action
[pos
] == '+' && !force
)
2189 *invalid_config
= true;
2190 log_error("[%s:%u] Unknown modifiers in command '%s'",
2191 fname
, line
, action
);
2196 if (boot
&& !arg_boot
) {
2197 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
2205 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
2207 return log_unresolvable_specifier(fname
, line
);
2209 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2210 *invalid_config
= true;
2211 return log_error_errno(r
, "[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
2216 case CREATE_DIRECTORY
:
2217 case CREATE_SUBVOLUME
:
2218 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
2219 case CREATE_SUBVOLUME_NEW_QUOTA
:
2220 case EMPTY_DIRECTORY
:
2221 case TRUNCATE_DIRECTORY
:
2224 case IGNORE_DIRECTORY_PATH
:
2226 case RECURSIVE_REMOVE_PATH
:
2229 case RECURSIVE_RELABEL_PATH
:
2231 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
2239 case CREATE_SYMLINK
:
2241 i
.argument
= strappend("/usr/share/factory/", i
.path
);
2249 *invalid_config
= true;
2250 log_error("[%s:%u] Write file requires argument.", fname
, line
);
2257 i
.argument
= strappend("/usr/share/factory/", i
.path
);
2260 } else if (!path_is_absolute(i
.argument
)) {
2261 *invalid_config
= true;
2262 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
2266 path_kill_slashes(i
.argument
);
2269 case CREATE_CHAR_DEVICE
:
2270 case CREATE_BLOCK_DEVICE
: {
2271 unsigned major
, minor
;
2274 *invalid_config
= true;
2275 log_error("[%s:%u] Device file requires argument.", fname
, line
);
2279 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
2280 *invalid_config
= true;
2281 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
2285 i
.major_minor
= makedev(major
, minor
);
2290 case RECURSIVE_SET_XATTR
:
2292 *invalid_config
= true;
2293 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
2296 r
= parse_xattrs_from_arg(&i
);
2302 case RECURSIVE_SET_ACL
:
2304 *invalid_config
= true;
2305 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
2308 r
= parse_acls_from_arg(&i
);
2314 case RECURSIVE_SET_ATTRIBUTE
:
2316 *invalid_config
= true;
2317 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
2320 r
= parse_attribute_from_arg(&i
);
2321 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2322 *invalid_config
= true;
2328 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
2329 *invalid_config
= true;
2333 if (!path_is_absolute(i
.path
)) {
2334 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
2335 *invalid_config
= true;
2339 path_kill_slashes(i
.path
);
2341 if (!should_include_path(i
.path
))
2344 r
= specifier_expansion_from_arg(&i
);
2346 return log_unresolvable_specifier(fname
, line
);
2348 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2349 *invalid_config
= true;
2350 return log_error_errno(r
, "[%s:%u] Failed to substitute specifiers in argument: %m",
2357 p
= prefix_root(arg_root
, i
.path
);
2365 if (!isempty(user
) && !streq(user
, "-")) {
2366 const char *u
= user
;
2368 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
2370 *invalid_config
= true;
2371 return log_error_errno(r
, "[%s:%u] Unknown user '%s'.", fname
, line
, user
);
2377 if (!isempty(group
) && !streq(group
, "-")) {
2378 const char *g
= group
;
2380 r
= get_group_creds(&g
, &i
.gid
);
2382 *invalid_config
= true;
2383 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2390 if (!isempty(mode
) && !streq(mode
, "-")) {
2391 const char *mm
= mode
;
2395 i
.mask_perms
= true;
2399 if (parse_mode(mm
, &m
) < 0) {
2400 *invalid_config
= true;
2401 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2408 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2410 if (!isempty(age
) && !streq(age
, "-")) {
2411 const char *a
= age
;
2414 i
.keep_first_level
= true;
2418 if (parse_sec(a
, &i
.age
) < 0) {
2419 *invalid_config
= true;
2420 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2427 h
= needs_glob(i
.type
) ? globs
: items
;
2429 existing
= ordered_hashmap_get(h
, i
.path
);
2433 for (n
= 0; n
< existing
->count
; n
++) {
2434 if (!item_compatible(existing
->items
+ n
, &i
)) {
2435 log_notice("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2436 fname
, line
, i
.path
);
2441 existing
= new0(ItemArray
, 1);
2445 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2450 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2453 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2455 /* Sort item array, to enforce stable ordering of application */
2456 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2462 static void help(void) {
2463 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2464 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2465 " -h --help Show this help\n"
2466 " --user Execute user configuration\n"
2467 " --version Show package version\n"
2468 " --create Create marked files/directories\n"
2469 " --clean Clean up marked directories\n"
2470 " --remove Remove marked files/directories\n"
2471 " --boot Execute actions only safe at boot\n"
2472 " --prefix=PATH Only apply rules with the specified prefix\n"
2473 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2474 " --root=PATH Operate on an alternate filesystem root\n"
2475 " --replace=PATH Treat arguments as replacement for PATH\n"
2476 , program_invocation_short_name
);
2479 static int parse_argv(int argc
, char *argv
[]) {
2482 ARG_VERSION
= 0x100,
2494 static const struct option options
[] = {
2495 { "help", no_argument
, NULL
, 'h' },
2496 { "user", no_argument
, NULL
, ARG_USER
},
2497 { "version", no_argument
, NULL
, ARG_VERSION
},
2498 { "create", no_argument
, NULL
, ARG_CREATE
},
2499 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2500 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2501 { "boot", no_argument
, NULL
, ARG_BOOT
},
2502 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2503 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2504 { "root", required_argument
, NULL
, ARG_ROOT
},
2505 { "replace", required_argument
, NULL
, ARG_REPLACE
},
2514 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2546 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2550 case ARG_EXCLUDE_PREFIX
:
2551 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2556 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2562 if (!path_is_absolute(optarg
) ||
2563 !endswith(optarg
, ".conf")) {
2564 log_error("The argument to --replace= must an absolute path to a config file");
2568 arg_replace
= optarg
;
2575 assert_not_reached("Unhandled option");
2578 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2579 log_error("You need to specify at least one of --clean, --create or --remove.");
2583 if (arg_replace
&& optind
>= argc
) {
2584 log_error("When --replace= is given, some configuration items must be specified");
2591 static int read_config_file(char **config_dirs
, const char *fn
, bool ignore_enoent
, bool *invalid_config
) {
2592 _cleanup_fclose_
FILE *_f
= NULL
;
2594 char line
[LINE_MAX
];
2602 if (streq(fn
, "-")) {
2603 log_debug("Reading config from stdin…");
2607 r
= search_and_fopen(fn
, "re", arg_root
, (const char**) config_dirs
, &_f
);
2609 if (ignore_enoent
&& r
== -ENOENT
) {
2610 log_debug_errno(r
, "Failed to open \"%s\", ignoring: %m", fn
);
2614 return log_error_errno(r
, "Failed to open '%s': %m", fn
);
2616 log_debug("Reading config file \"%s\"…", fn
);
2620 FOREACH_LINE(line
, f
, break) {
2623 bool invalid_line
= false;
2628 if (IN_SET(*l
, 0, '#'))
2631 k
= parse_line(fn
, v
, l
, &invalid_line
);
2634 /* Allow reporting with a special code if the caller requested this */
2635 *invalid_config
= true;
2637 /* The first error becomes our return value */
2642 /* we have to determine age parameter for each entry of type X */
2643 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2645 Item
*j
, *candidate_item
= NULL
;
2647 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2650 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2651 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2654 if (path_equal(j
->path
, i
->path
)) {
2659 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2660 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2664 if (candidate_item
&& candidate_item
->age_set
) {
2665 i
->age
= candidate_item
->age
;
2671 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2679 static int parse_arguments(char **config_dirs
, char **args
, bool *invalid_config
) {
2683 STRV_FOREACH(arg
, args
) {
2684 r
= read_config_file(config_dirs
, *arg
, false, invalid_config
);
2692 static int read_config_files(char **config_dirs
, char **args
, bool *invalid_config
) {
2693 _cleanup_strv_free_
char **files
= NULL
;
2694 _cleanup_free_
char *p
= NULL
;
2698 r
= conf_files_list_strv(&files
, ".conf", arg_root
, 0, (const char* const*) config_dirs
);
2700 return log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2703 r
= conf_files_insert(&files
, arg_root
, config_dirs
, arg_replace
);
2705 return log_error_errno(r
, "Failed to extend tmpfiles.d file list: %m");
2707 p
= path_join(arg_root
, arg_replace
, NULL
);
2712 STRV_FOREACH(f
, files
)
2713 if (p
&& path_equal(*f
, p
)) {
2714 log_debug("Parsing arguments at position \"%s\"…", *f
);
2716 r
= parse_arguments(config_dirs
, args
, invalid_config
);
2720 /* Just warn, ignore result otherwise.
2721 * read_config_file() has some debug output, so no need to print anything. */
2722 (void) read_config_file(config_dirs
, *f
, true, invalid_config
);
2727 int main(int argc
, char *argv
[]) {
2731 _cleanup_strv_free_
char **config_dirs
= NULL
;
2732 bool invalid_config
= false;
2734 r
= parse_argv(argc
, argv
);
2738 log_set_target(LOG_TARGET_AUTO
);
2739 log_parse_environment();
2746 items
= ordered_hashmap_new(&string_hash_ops
);
2747 globs
= ordered_hashmap_new(&string_hash_ops
);
2749 if (!items
|| !globs
) {
2757 r
= user_config_paths(&config_dirs
);
2759 log_error_errno(r
, "Failed to initialize configuration directory list: %m");
2763 config_dirs
= strv_split_nulstr(CONF_PATHS_NULSTR("tmpfiles.d"));
2770 if (DEBUG_LOGGING
) {
2771 _cleanup_free_
char *t
= NULL
;
2773 t
= strv_join(config_dirs
, "\n\t");
2775 log_debug("Looking for configuration files in (higher priority first:\n\t%s", t
);
2778 /* If command line arguments are specified along with --replace, read all
2779 * configuration files and insert the positional arguments at the specified
2780 * place. Otherwise, if command line arguments are specified, execute just
2781 * them, and finally, without --replace= or any positional arguments, just
2782 * read configuration and execute it.
2784 if (arg_replace
|| optind
>= argc
)
2785 r
= read_config_files(config_dirs
, argv
+ optind
, &invalid_config
);
2787 r
= parse_arguments(config_dirs
, argv
+ optind
, &invalid_config
);
2793 /* The non-globbing ones usually create things, hence we apply
2795 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2796 k
= process_item_array(a
);
2797 if (k
< 0 && r
== 0)
2801 /* The globbing ones usually alter things, hence we apply them
2803 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2804 k
= process_item_array(a
);
2805 if (k
< 0 && r
== 0)
2810 ordered_hashmap_free_with_destructor(items
, item_array_free
);
2811 ordered_hashmap_free_with_destructor(globs
, item_array_free
);
2813 free(arg_include_prefixes
);
2814 free(arg_exclude_prefixes
);
2817 set_free_free(unix_sockets
);
2819 mac_selinux_finish();
2822 return EXIT_FAILURE
;
2823 else if (invalid_config
)
2826 return EXIT_SUCCESS
;