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
, false, false);
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 char procfs_path
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
1190 _cleanup_close_
int procfs_fd
= -1;
1191 _cleanup_free_
char *path
= NULL
;
1195 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
1198 r
= fd_get_path(fd
, &path
);
1202 /* Issuing the file attribute ioctls on device nodes is not
1203 * safe, as that will be delivered to the drivers, not the
1204 * file system containing the device node. */
1205 if (!S_ISREG(st
->st_mode
) && !S_ISDIR(st
->st_mode
)) {
1206 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
1210 f
= item
->attribute_value
& item
->attribute_mask
;
1212 /* Mask away directory-specific flags */
1213 if (!S_ISDIR(st
->st_mode
))
1214 f
&= ~FS_DIRSYNC_FL
;
1216 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
1218 procfs_fd
= open(procfs_path
, O_RDONLY
|O_CLOEXEC
|O_NOATIME
);
1222 r
= chattr_fd(procfs_fd
, f
, item
->attribute_mask
);
1224 log_full_errno(IN_SET(r
, -ENOTTY
, -EOPNOTSUPP
) ? LOG_DEBUG
: LOG_WARNING
,
1226 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
1227 path
, item
->attribute_value
, item
->attribute_mask
);
1232 static int path_set_attribute(Item
*item
, const char *path
) {
1233 _cleanup_close_
int fd
= -1;
1236 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
1239 fd
= open(path
, O_CLOEXEC
|O_NOFOLLOW
|O_PATH
);
1241 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
1243 if (fstat(fd
, &st
) < 0)
1244 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
1246 return fd_set_attribute(item
, fd
, &st
);
1249 static int write_one_file(Item
*i
, const char *path
) {
1250 _cleanup_close_
int fd
= -1;
1257 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_EXCL
|O_NOFOLLOW
:
1258 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
1260 RUN_WITH_UMASK(0000) {
1261 mac_selinux_create_file_prepare(path
, S_IFREG
);
1262 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
1263 mac_selinux_create_file_clear();
1267 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
1268 log_debug_errno(errno
, "Not writing missing file \"%s\": %m", path
);
1271 if (i
->type
== CREATE_FILE
&& errno
== EEXIST
) {
1272 log_debug_errno(errno
, "Not writing to pre-existing file \"%s\": %m", path
);
1277 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
1278 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
1281 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1285 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1287 r
= loop_write(fd
, i
->argument
, strlen(i
->argument
), false);
1289 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1291 log_debug("\"%s\" has been created.", path
);
1293 fd
= safe_close(fd
);
1296 if (stat(path
, &st
) < 0)
1297 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1300 if (!S_ISREG(st
.st_mode
)) {
1301 log_error("%s is not a file.", path
);
1305 r
= path_set_perms(i
, path
);
1312 typedef int (*action_t
)(Item
*, const char *);
1313 typedef int (*fdaction_t
)(Item
*, int fd
, const struct stat
*st
);
1315 static int item_do(Item
*i
, int fd
, const struct stat
*st
, fdaction_t action
) {
1322 /* This returns the first error we run into, but nevertheless
1324 r
= action(i
, fd
, st
);
1326 if (S_ISDIR(st
->st_mode
)) {
1327 char procfs_path
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
1328 _cleanup_closedir_
DIR *d
= NULL
;
1331 /* The passed 'fd' was opened with O_PATH. We need to convert
1332 * it into a 'regular' fd before reading the directory content. */
1333 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
1335 d
= opendir(procfs_path
);
1341 FOREACH_DIRENT_ALL(de
, d
, q
= -errno
; goto finish
) {
1345 if (dot_or_dot_dot(de
->d_name
))
1348 de_fd
= openat(fd
, de
->d_name
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
1349 if (de_fd
>= 0 && fstat(de_fd
, &de_st
) >= 0)
1350 /* pass ownership of dirent fd over */
1351 q
= item_do(i
, de_fd
, &de_st
, action
);
1355 if (q
< 0 && r
== 0)
1364 static int glob_item(Item
*i
, action_t action
) {
1365 _cleanup_globfree_ glob_t g
= {
1366 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1371 k
= safe_glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
, &g
);
1372 if (k
< 0 && k
!= -ENOENT
)
1373 return log_error_errno(k
, "glob(%s) failed: %m", i
->path
);
1375 STRV_FOREACH(fn
, g
.gl_pathv
) {
1377 if (k
< 0 && r
== 0)
1384 static int glob_item_recursively(Item
*i
, fdaction_t action
) {
1385 _cleanup_globfree_ glob_t g
= {
1386 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1391 k
= safe_glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
, &g
);
1392 if (k
< 0 && k
!= -ENOENT
)
1393 return log_error_errno(k
, "glob(%s) failed: %m", i
->path
);
1395 STRV_FOREACH(fn
, g
.gl_pathv
) {
1396 _cleanup_close_
int fd
= -1;
1399 /* Make sure we won't trigger/follow file object (such as
1400 * device nodes, automounts, ...) pointed out by 'fn' with
1401 * O_PATH. Note, when O_PATH is used, flags other than
1402 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored. */
1404 fd
= open(*fn
, O_CLOEXEC
|O_NOFOLLOW
|O_PATH
);
1410 if (fstat(fd
, &st
) < 0) {
1415 k
= item_do(i
, fd
, &st
, action
);
1416 if (k
< 0 && r
== 0)
1419 /* we passed fd ownership to the previous call */
1431 _CREATION_MODE_INVALID
= -1
1434 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1435 [CREATION_NORMAL
] = "Created",
1436 [CREATION_EXISTING
] = "Found existing",
1437 [CREATION_FORCE
] = "Created replacement",
1440 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1442 static int create_item(Item
*i
) {
1446 CreationMode creation
;
1450 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1455 case IGNORE_DIRECTORY_PATH
:
1457 case RECURSIVE_REMOVE_PATH
:
1462 RUN_WITH_UMASK(0000)
1463 (void) mkdir_parents_label(i
->path
, 0755);
1465 r
= write_one_file(i
, i
->path
);
1472 RUN_WITH_UMASK(0000)
1473 (void) mkdir_parents_label(i
->path
, 0755);
1475 log_debug("Copying tree \"%s\" to \"%s\".", i
->argument
, i
->path
);
1476 r
= copy_tree(i
->argument
, i
->path
,
1477 i
->uid_set
? i
->uid
: UID_INVALID
,
1478 i
->gid_set
? i
->gid
: GID_INVALID
,
1481 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1488 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1490 if (stat(i
->argument
, &a
) < 0)
1491 return log_error_errno(errno
, "stat(%s) failed: %m", i
->argument
);
1493 if (stat(i
->path
, &b
) < 0)
1494 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1496 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1497 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1502 r
= path_set_perms(i
, i
->path
);
1509 r
= glob_item(i
, write_one_file
);
1515 case CREATE_DIRECTORY
:
1516 case TRUNCATE_DIRECTORY
:
1517 case CREATE_SUBVOLUME
:
1518 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1519 case CREATE_SUBVOLUME_NEW_QUOTA
:
1520 RUN_WITH_UMASK(0000)
1521 (void) mkdir_parents_label(i
->path
, 0755);
1523 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1525 if (btrfs_is_subvol(isempty(arg_root
) ? "/" : arg_root
) <= 0)
1527 /* Don't create a subvolume unless the
1528 * root directory is one, too. We do
1529 * this under the assumption that if
1530 * the root directory is just a plain
1531 * directory (i.e. very light-weight),
1532 * we shouldn't try to split it up
1533 * into subvolumes (i.e. more
1534 * heavy-weight). Thus, chroot()
1535 * environments and suchlike will get
1536 * a full brtfs subvolume set up below
1537 * their tree only if they
1538 * specifically set up a btrfs
1539 * subvolume for the root dir too. */
1543 RUN_WITH_UMASK((~i
->mode
) & 0777)
1544 r
= btrfs_subvol_make(i
->path
);
1549 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1550 RUN_WITH_UMASK(0000)
1551 r
= mkdir_label(i
->path
, i
->mode
);
1556 if (!IN_SET(r
, -EEXIST
, -EROFS
))
1557 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1559 k
= is_dir(i
->path
, false);
1560 if (k
== -ENOENT
&& r
== -EROFS
)
1561 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1563 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1565 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1569 creation
= CREATION_EXISTING
;
1571 creation
= CREATION_NORMAL
;
1573 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1575 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1576 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1578 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i
->path
);
1579 else if (r
== -EROFS
)
1580 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i
->path
);
1581 else if (r
== -ENOPROTOOPT
)
1582 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i
->path
);
1584 q
= log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1586 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1588 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1592 case EMPTY_DIRECTORY
:
1593 r
= path_set_perms(i
, i
->path
);
1602 RUN_WITH_UMASK(0000) {
1603 (void) mkdir_parents_label(i
->path
, 0755);
1605 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1606 r
= mkfifo(i
->path
, i
->mode
);
1607 mac_selinux_create_file_clear();
1611 if (errno
!= EEXIST
)
1612 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1614 if (lstat(i
->path
, &st
) < 0)
1615 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1617 if (!S_ISFIFO(st
.st_mode
)) {
1620 RUN_WITH_UMASK(0000) {
1621 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1622 r
= mkfifo_atomic(i
->path
, i
->mode
);
1623 mac_selinux_create_file_clear();
1627 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1628 creation
= CREATION_FORCE
;
1630 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1634 creation
= CREATION_EXISTING
;
1636 creation
= CREATION_NORMAL
;
1637 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1639 r
= path_set_perms(i
, i
->path
);
1646 case CREATE_SYMLINK
: {
1647 RUN_WITH_UMASK(0000)
1648 (void) mkdir_parents_label(i
->path
, 0755);
1650 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1651 r
= symlink(i
->argument
, i
->path
);
1652 mac_selinux_create_file_clear();
1655 _cleanup_free_
char *x
= NULL
;
1657 if (errno
!= EEXIST
)
1658 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1660 r
= readlink_malloc(i
->path
, &x
);
1661 if (r
< 0 || !streq(i
->argument
, x
)) {
1664 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1665 r
= symlink_atomic(i
->argument
, i
->path
);
1666 mac_selinux_create_file_clear();
1668 if (IN_SET(r
, -EEXIST
, -ENOTEMPTY
)) {
1669 r
= rm_rf(i
->path
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
1671 return log_error_errno(r
, "rm -fr %s failed: %m", i
->path
);
1673 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1674 r
= symlink(i
->argument
, i
->path
) < 0 ? -errno
: 0;
1675 mac_selinux_create_file_clear();
1678 return log_error_errno(r
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1680 creation
= CREATION_FORCE
;
1682 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1686 creation
= CREATION_EXISTING
;
1689 creation
= CREATION_NORMAL
;
1690 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1694 case CREATE_BLOCK_DEVICE
:
1695 case CREATE_CHAR_DEVICE
: {
1698 if (have_effective_cap(CAP_MKNOD
) == 0) {
1699 /* In a container we lack CAP_MKNOD. We
1700 shouldn't attempt to create the device node in
1701 that case to avoid noise, and we don't support
1702 virtualized devices in containers anyway. */
1704 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1708 RUN_WITH_UMASK(0000)
1709 (void) mkdir_parents_label(i
->path
, 0755);
1711 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1713 RUN_WITH_UMASK(0000) {
1714 mac_selinux_create_file_prepare(i
->path
, file_type
);
1715 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1716 mac_selinux_create_file_clear();
1720 if (errno
== EPERM
) {
1721 log_debug("We lack permissions, possibly because of cgroup configuration; "
1722 "skipping creation of device node %s.", i
->path
);
1726 if (errno
!= EEXIST
)
1727 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1729 if (lstat(i
->path
, &st
) < 0)
1730 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1732 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1736 RUN_WITH_UMASK(0000) {
1737 mac_selinux_create_file_prepare(i
->path
, file_type
);
1738 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1739 mac_selinux_create_file_clear();
1743 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1744 creation
= CREATION_FORCE
;
1746 log_debug("%s is not a device node.", i
->path
);
1750 creation
= CREATION_EXISTING
;
1752 creation
= CREATION_NORMAL
;
1754 log_debug("%s %s device node \"%s\" %u:%u.",
1755 creation_mode_verb_to_string(creation
),
1756 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1757 i
->path
, major(i
->mode
), minor(i
->mode
));
1759 r
= path_set_perms(i
, i
->path
);
1768 r
= glob_item(i
, path_set_perms
);
1773 case RECURSIVE_RELABEL_PATH
:
1774 r
= glob_item_recursively(i
, fd_set_perms
);
1780 r
= glob_item(i
, path_set_xattrs
);
1785 case RECURSIVE_SET_XATTR
:
1786 r
= glob_item_recursively(i
, fd_set_xattrs
);
1792 r
= glob_item(i
, path_set_acls
);
1797 case RECURSIVE_SET_ACL
:
1798 r
= glob_item_recursively(i
, fd_set_acls
);
1804 r
= glob_item(i
, path_set_attribute
);
1809 case RECURSIVE_SET_ATTRIBUTE
:
1810 r
= glob_item_recursively(i
, fd_set_attribute
);
1819 static int remove_item_instance(Item
*i
, const char *instance
) {
1827 if (remove(instance
) < 0 && errno
!= ENOENT
)
1828 return log_error_errno(errno
, "rm(%s): %m", instance
);
1832 case TRUNCATE_DIRECTORY
:
1833 case RECURSIVE_REMOVE_PATH
:
1834 /* FIXME: we probably should use dir_cleanup() here
1835 * instead of rm_rf() so that 'x' is honoured. */
1836 log_debug("rm -rf \"%s\"", instance
);
1837 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1838 if (r
< 0 && r
!= -ENOENT
)
1839 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1844 assert_not_reached("wut?");
1850 static int remove_item(Item
*i
) {
1853 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1858 case TRUNCATE_DIRECTORY
:
1859 case RECURSIVE_REMOVE_PATH
:
1860 return glob_item(i
, remove_item_instance
);
1867 static int clean_item_instance(Item
*i
, const char* instance
) {
1868 _cleanup_closedir_
DIR *d
= NULL
;
1872 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1879 n
= now(CLOCK_REALTIME
);
1883 cutoff
= n
- i
->age
;
1885 d
= opendir_nomod(instance
);
1887 if (IN_SET(errno
, ENOENT
, ENOTDIR
)) {
1888 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1892 return log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1895 if (fstat(dirfd(d
), &s
) < 0)
1896 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1898 if (!S_ISDIR(s
.st_mode
)) {
1899 log_error("%s is not a directory.", i
->path
);
1903 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1904 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1906 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1908 log_debug("Cleanup threshold for %s \"%s\" is %s",
1909 mountpoint
? "mount point" : "directory",
1911 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1913 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1914 MAX_DEPTH
, i
->keep_first_level
);
1917 static int clean_item(Item
*i
) {
1920 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1923 case CREATE_DIRECTORY
:
1924 case CREATE_SUBVOLUME
:
1925 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1926 case CREATE_SUBVOLUME_NEW_QUOTA
:
1927 case TRUNCATE_DIRECTORY
:
1930 clean_item_instance(i
, i
->path
);
1932 case EMPTY_DIRECTORY
:
1933 case IGNORE_DIRECTORY_PATH
:
1934 return glob_item(i
, clean_item_instance
);
1940 static int process_item_array(ItemArray
*array
);
1942 static int process_item(Item
*i
) {
1944 _cleanup_free_
char *prefix
= NULL
;
1953 prefix
= malloc(strlen(i
->path
) + 1);
1957 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1960 j
= ordered_hashmap_get(items
, prefix
);
1964 s
= process_item_array(j
);
1965 if (s
< 0 && t
== 0)
1970 if (chase_symlinks(i
->path
, NULL
, CHASE_NO_AUTOFS
, NULL
) == -EREMOTE
)
1973 r
= arg_create
? create_item(i
) : 0;
1974 q
= arg_remove
? remove_item(i
) : 0;
1975 p
= arg_clean
? clean_item(i
) : 0;
1983 static int process_item_array(ItemArray
*array
) {
1989 for (n
= 0; n
< array
->count
; n
++) {
1990 k
= process_item(array
->items
+ n
);
1991 if (k
< 0 && r
== 0)
1998 static void item_free_contents(Item
*i
) {
2002 strv_free(i
->xattrs
);
2005 acl_free(i
->acl_access
);
2006 acl_free(i
->acl_default
);
2010 static void item_array_free(ItemArray
*a
) {
2016 for (n
= 0; n
< a
->count
; n
++)
2017 item_free_contents(a
->items
+ n
);
2022 static int item_compare(const void *a
, const void *b
) {
2023 const Item
*x
= a
, *y
= b
;
2025 /* Make sure that the ownership taking item is put first, so
2026 * that we first create the node, and then can adjust it */
2028 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
2030 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
2033 return (int) x
->type
- (int) y
->type
;
2036 static bool item_compatible(Item
*a
, Item
*b
) {
2039 assert(streq(a
->path
, b
->path
));
2041 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
2042 /* check if the items are the same */
2043 return streq_ptr(a
->argument
, b
->argument
) &&
2045 a
->uid_set
== b
->uid_set
&&
2048 a
->gid_set
== b
->gid_set
&&
2051 a
->mode_set
== b
->mode_set
&&
2052 a
->mode
== b
->mode
&&
2054 a
->age_set
== b
->age_set
&&
2057 a
->mask_perms
== b
->mask_perms
&&
2059 a
->keep_first_level
== b
->keep_first_level
&&
2061 a
->major_minor
== b
->major_minor
;
2066 static bool should_include_path(const char *path
) {
2069 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
2070 if (path_startswith(path
, *prefix
)) {
2071 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
2076 STRV_FOREACH(prefix
, arg_include_prefixes
)
2077 if (path_startswith(path
, *prefix
)) {
2078 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
2082 /* no matches, so we should include this path only if we
2083 * have no whitelist at all */
2084 if (strv_isempty(arg_include_prefixes
))
2087 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
2091 static int specifier_expansion_from_arg(Item
*i
) {
2092 _cleanup_free_
char *unescaped
= NULL
, *resolved
= NULL
;
2098 if (i
->argument
== NULL
)
2103 case CREATE_SYMLINK
:
2107 r
= cunescape(i
->argument
, 0, &unescaped
);
2109 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
2111 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &resolved
);
2115 free_and_replace(i
->argument
, resolved
);
2119 case RECURSIVE_SET_XATTR
:
2122 STRV_FOREACH (xattr
, i
->xattrs
) {
2123 r
= specifier_printf(*xattr
, specifier_table
, NULL
, &resolved
);
2127 free_and_replace(*xattr
, resolved
);
2137 static int parse_line(const char *fname
, unsigned line
, const char *buffer
, bool *invalid_config
) {
2139 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
2140 _cleanup_(item_free_contents
) Item i
= {};
2141 ItemArray
*existing
;
2144 bool force
= false, boot
= false;
2150 r
= extract_many_words(
2162 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2163 /* invalid quoting and such or an unknown specifier */
2164 *invalid_config
= true;
2165 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
2169 *invalid_config
= true;
2170 log_error("[%s:%u] Syntax error.", fname
, line
);
2174 if (!isempty(buffer
) && !streq(buffer
, "-")) {
2175 i
.argument
= strdup(buffer
);
2180 if (isempty(action
)) {
2181 *invalid_config
= true;
2182 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
2186 for (pos
= 1; action
[pos
]; pos
++) {
2187 if (action
[pos
] == '!' && !boot
)
2189 else if (action
[pos
] == '+' && !force
)
2192 *invalid_config
= true;
2193 log_error("[%s:%u] Unknown modifiers in command '%s'",
2194 fname
, line
, action
);
2199 if (boot
&& !arg_boot
) {
2200 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
2208 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
2210 return log_unresolvable_specifier(fname
, line
);
2212 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2213 *invalid_config
= true;
2214 return log_error_errno(r
, "[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
2219 case CREATE_DIRECTORY
:
2220 case CREATE_SUBVOLUME
:
2221 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
2222 case CREATE_SUBVOLUME_NEW_QUOTA
:
2223 case EMPTY_DIRECTORY
:
2224 case TRUNCATE_DIRECTORY
:
2227 case IGNORE_DIRECTORY_PATH
:
2229 case RECURSIVE_REMOVE_PATH
:
2232 case RECURSIVE_RELABEL_PATH
:
2234 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
2242 case CREATE_SYMLINK
:
2244 i
.argument
= strappend("/usr/share/factory/", i
.path
);
2252 *invalid_config
= true;
2253 log_error("[%s:%u] Write file requires argument.", fname
, line
);
2260 i
.argument
= strappend("/usr/share/factory/", i
.path
);
2263 } else if (!path_is_absolute(i
.argument
)) {
2264 *invalid_config
= true;
2265 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
2269 path_kill_slashes(i
.argument
);
2272 case CREATE_CHAR_DEVICE
:
2273 case CREATE_BLOCK_DEVICE
: {
2274 unsigned major
, minor
;
2277 *invalid_config
= true;
2278 log_error("[%s:%u] Device file requires argument.", fname
, line
);
2282 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
2283 *invalid_config
= true;
2284 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
2288 i
.major_minor
= makedev(major
, minor
);
2293 case RECURSIVE_SET_XATTR
:
2295 *invalid_config
= true;
2296 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
2299 r
= parse_xattrs_from_arg(&i
);
2305 case RECURSIVE_SET_ACL
:
2307 *invalid_config
= true;
2308 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
2311 r
= parse_acls_from_arg(&i
);
2317 case RECURSIVE_SET_ATTRIBUTE
:
2319 *invalid_config
= true;
2320 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
2323 r
= parse_attribute_from_arg(&i
);
2324 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2325 *invalid_config
= true;
2331 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
2332 *invalid_config
= true;
2336 if (!path_is_absolute(i
.path
)) {
2337 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
2338 *invalid_config
= true;
2342 path_kill_slashes(i
.path
);
2344 if (!should_include_path(i
.path
))
2347 r
= specifier_expansion_from_arg(&i
);
2349 return log_unresolvable_specifier(fname
, line
);
2351 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2352 *invalid_config
= true;
2353 return log_error_errno(r
, "[%s:%u] Failed to substitute specifiers in argument: %m",
2360 p
= prefix_root(arg_root
, i
.path
);
2368 if (!isempty(user
) && !streq(user
, "-")) {
2369 const char *u
= user
;
2371 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
2373 *invalid_config
= true;
2374 return log_error_errno(r
, "[%s:%u] Unknown user '%s'.", fname
, line
, user
);
2380 if (!isempty(group
) && !streq(group
, "-")) {
2381 const char *g
= group
;
2383 r
= get_group_creds(&g
, &i
.gid
);
2385 *invalid_config
= true;
2386 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2393 if (!isempty(mode
) && !streq(mode
, "-")) {
2394 const char *mm
= mode
;
2398 i
.mask_perms
= true;
2402 if (parse_mode(mm
, &m
) < 0) {
2403 *invalid_config
= true;
2404 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2411 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2413 if (!isempty(age
) && !streq(age
, "-")) {
2414 const char *a
= age
;
2417 i
.keep_first_level
= true;
2421 if (parse_sec(a
, &i
.age
) < 0) {
2422 *invalid_config
= true;
2423 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2430 h
= needs_glob(i
.type
) ? globs
: items
;
2432 existing
= ordered_hashmap_get(h
, i
.path
);
2436 for (n
= 0; n
< existing
->count
; n
++) {
2437 if (!item_compatible(existing
->items
+ n
, &i
)) {
2438 log_notice("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2439 fname
, line
, i
.path
);
2444 existing
= new0(ItemArray
, 1);
2448 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2453 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2456 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2458 /* Sort item array, to enforce stable ordering of application */
2459 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2465 static void help(void) {
2466 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2467 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2468 " -h --help Show this help\n"
2469 " --user Execute user configuration\n"
2470 " --version Show package version\n"
2471 " --create Create marked files/directories\n"
2472 " --clean Clean up marked directories\n"
2473 " --remove Remove marked files/directories\n"
2474 " --boot Execute actions only safe at boot\n"
2475 " --prefix=PATH Only apply rules with the specified prefix\n"
2476 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2477 " --root=PATH Operate on an alternate filesystem root\n"
2478 " --replace=PATH Treat arguments as replacement for PATH\n"
2479 , program_invocation_short_name
);
2482 static int parse_argv(int argc
, char *argv
[]) {
2485 ARG_VERSION
= 0x100,
2497 static const struct option options
[] = {
2498 { "help", no_argument
, NULL
, 'h' },
2499 { "user", no_argument
, NULL
, ARG_USER
},
2500 { "version", no_argument
, NULL
, ARG_VERSION
},
2501 { "create", no_argument
, NULL
, ARG_CREATE
},
2502 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2503 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2504 { "boot", no_argument
, NULL
, ARG_BOOT
},
2505 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2506 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2507 { "root", required_argument
, NULL
, ARG_ROOT
},
2508 { "replace", required_argument
, NULL
, ARG_REPLACE
},
2517 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2549 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2553 case ARG_EXCLUDE_PREFIX
:
2554 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2559 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2565 if (!path_is_absolute(optarg
) ||
2566 !endswith(optarg
, ".conf")) {
2567 log_error("The argument to --replace= must an absolute path to a config file");
2571 arg_replace
= optarg
;
2578 assert_not_reached("Unhandled option");
2581 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2582 log_error("You need to specify at least one of --clean, --create or --remove.");
2586 if (arg_replace
&& optind
>= argc
) {
2587 log_error("When --replace= is given, some configuration items must be specified");
2594 static int read_config_file(char **config_dirs
, const char *fn
, bool ignore_enoent
, bool *invalid_config
) {
2595 _cleanup_fclose_
FILE *_f
= NULL
;
2597 char line
[LINE_MAX
];
2605 if (streq(fn
, "-")) {
2606 log_debug("Reading config from stdin…");
2610 r
= search_and_fopen(fn
, "re", arg_root
, (const char**) config_dirs
, &_f
);
2612 if (ignore_enoent
&& r
== -ENOENT
) {
2613 log_debug_errno(r
, "Failed to open \"%s\", ignoring: %m", fn
);
2617 return log_error_errno(r
, "Failed to open '%s': %m", fn
);
2619 log_debug("Reading config file \"%s\"…", fn
);
2623 FOREACH_LINE(line
, f
, break) {
2626 bool invalid_line
= false;
2631 if (IN_SET(*l
, 0, '#'))
2634 k
= parse_line(fn
, v
, l
, &invalid_line
);
2637 /* Allow reporting with a special code if the caller requested this */
2638 *invalid_config
= true;
2640 /* The first error becomes our return value */
2645 /* we have to determine age parameter for each entry of type X */
2646 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2648 Item
*j
, *candidate_item
= NULL
;
2650 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2653 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2654 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2657 if (path_equal(j
->path
, i
->path
)) {
2662 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2663 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2667 if (candidate_item
&& candidate_item
->age_set
) {
2668 i
->age
= candidate_item
->age
;
2674 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2682 static int parse_arguments(char **config_dirs
, char **args
, bool *invalid_config
) {
2686 STRV_FOREACH(arg
, args
) {
2687 r
= read_config_file(config_dirs
, *arg
, false, invalid_config
);
2695 static int read_config_files(char **config_dirs
, char **args
, bool *invalid_config
) {
2696 _cleanup_strv_free_
char **files
= NULL
;
2697 _cleanup_free_
char *p
= NULL
;
2701 r
= conf_files_list_strv(&files
, ".conf", arg_root
, 0, (const char* const*) config_dirs
);
2703 return log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2706 r
= conf_files_insert(&files
, arg_root
, config_dirs
, arg_replace
);
2708 return log_error_errno(r
, "Failed to extend tmpfiles.d file list: %m");
2710 p
= path_join(arg_root
, arg_replace
, NULL
);
2715 STRV_FOREACH(f
, files
)
2716 if (p
&& path_equal(*f
, p
)) {
2717 log_debug("Parsing arguments at position \"%s\"…", *f
);
2719 r
= parse_arguments(config_dirs
, args
, invalid_config
);
2723 /* Just warn, ignore result otherwise.
2724 * read_config_file() has some debug output, so no need to print anything. */
2725 (void) read_config_file(config_dirs
, *f
, true, invalid_config
);
2730 int main(int argc
, char *argv
[]) {
2734 _cleanup_strv_free_
char **config_dirs
= NULL
;
2735 bool invalid_config
= false;
2737 r
= parse_argv(argc
, argv
);
2741 log_set_target(LOG_TARGET_AUTO
);
2742 log_parse_environment();
2749 items
= ordered_hashmap_new(&string_hash_ops
);
2750 globs
= ordered_hashmap_new(&string_hash_ops
);
2752 if (!items
|| !globs
) {
2760 r
= user_config_paths(&config_dirs
);
2762 log_error_errno(r
, "Failed to initialize configuration directory list: %m");
2766 config_dirs
= strv_split_nulstr(CONF_PATHS_NULSTR("tmpfiles.d"));
2773 if (DEBUG_LOGGING
) {
2774 _cleanup_free_
char *t
= NULL
;
2776 t
= strv_join(config_dirs
, "\n\t");
2778 log_debug("Looking for configuration files in (higher priority first:\n\t%s", t
);
2781 /* If command line arguments are specified along with --replace, read all
2782 * configuration files and insert the positional arguments at the specified
2783 * place. Otherwise, if command line arguments are specified, execute just
2784 * them, and finally, without --replace= or any positional arguments, just
2785 * read configuration and execute it.
2787 if (arg_replace
|| optind
>= argc
)
2788 r
= read_config_files(config_dirs
, argv
+ optind
, &invalid_config
);
2790 r
= parse_arguments(config_dirs
, argv
+ optind
, &invalid_config
);
2796 /* The non-globbing ones usually create things, hence we apply
2798 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2799 k
= process_item_array(a
);
2800 if (k
< 0 && r
== 0)
2804 /* The globbing ones usually alter things, hence we apply them
2806 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2807 k
= process_item_array(a
);
2808 if (k
< 0 && r
== 0)
2813 ordered_hashmap_free_with_destructor(items
, item_array_free
);
2814 ordered_hashmap_free_with_destructor(globs
, item_array_free
);
2816 free(arg_include_prefixes
);
2817 free(arg_exclude_prefixes
);
2820 set_free_free(unix_sockets
);
2822 mac_selinux_finish();
2825 return EXIT_FAILURE
;
2826 else if (invalid_config
)
2829 return EXIT_SUCCESS
;