1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering, Kay Sievers
6 Copyright 2015 Zbigniew Jędrzejewski-Szmek
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
35 #include <sys/xattr.h>
43 #include "alloc-util.h"
44 #include "btrfs-util.h"
45 #include "capability-util.h"
46 #include "chattr-util.h"
47 #include "conf-files.h"
50 #include "dirent-util.h"
54 #include "format-util.h"
56 #include "glob-util.h"
63 #include "mount-util.h"
64 #include "parse-util.h"
65 #include "path-lookup.h"
66 #include "path-util.h"
68 #include "selinux-util.h"
70 #include "specifier.h"
71 #include "stat-util.h"
72 #include "stdio-util.h"
73 #include "string-table.h"
74 #include "string-util.h"
76 #include "umask-util.h"
77 #include "user-util.h"
80 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
81 * them in the file system. This is intended to be used to create
82 * properly owned directories beneath /tmp, /var/tmp, /run, which are
83 * volatile and hence need to be recreated on bootup. */
85 typedef enum ItemType
{
86 /* These ones take file names */
89 CREATE_DIRECTORY
= 'd',
90 TRUNCATE_DIRECTORY
= 'D',
91 CREATE_SUBVOLUME
= 'v',
92 CREATE_SUBVOLUME_INHERIT_QUOTA
= 'q',
93 CREATE_SUBVOLUME_NEW_QUOTA
= 'Q',
96 CREATE_CHAR_DEVICE
= 'c',
97 CREATE_BLOCK_DEVICE
= 'b',
100 /* These ones take globs */
102 EMPTY_DIRECTORY
= 'e',
104 RECURSIVE_SET_XATTR
= 'T',
106 RECURSIVE_SET_ACL
= 'A',
108 RECURSIVE_SET_ATTRIBUTE
= 'H',
110 IGNORE_DIRECTORY_PATH
= 'X',
112 RECURSIVE_REMOVE_PATH
= 'R',
114 RECURSIVE_RELABEL_PATH
= 'Z',
115 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
118 typedef struct Item
{
134 unsigned attribute_value
;
135 unsigned attribute_mask
;
142 bool attribute_set
:1;
144 bool keep_first_level
:1;
151 typedef struct ItemArray
{
157 typedef enum DirectoryType
{
158 DIRECTORY_RUNTIME
= 0,
165 static bool arg_user
= false;
166 static bool arg_create
= false;
167 static bool arg_clean
= false;
168 static bool arg_remove
= false;
169 static bool arg_boot
= false;
171 static char **arg_include_prefixes
= NULL
;
172 static char **arg_exclude_prefixes
= NULL
;
173 static char *arg_root
= NULL
;
174 static char *arg_replace
= NULL
;
176 #define MAX_DEPTH 256
178 static OrderedHashmap
*items
= NULL
, *globs
= NULL
;
179 static Set
*unix_sockets
= NULL
;
181 static int specifier_machine_id_safe(char specifier
, void *data
, void *userdata
, char **ret
);
182 static int specifier_directory(char specifier
, void *data
, void *userdata
, char **ret
);
184 static const Specifier specifier_table
[] = {
185 { 'm', specifier_machine_id_safe
, NULL
},
186 { 'b', specifier_boot_id
, NULL
},
187 { 'H', specifier_host_name
, NULL
},
188 { 'v', specifier_kernel_release
, NULL
},
190 { 'U', specifier_user_id
, NULL
},
191 { 'u', specifier_user_name
, NULL
},
192 { 'h', specifier_user_home
, NULL
},
193 { 't', specifier_directory
, UINT_TO_PTR(DIRECTORY_RUNTIME
) },
194 { 'S', specifier_directory
, UINT_TO_PTR(DIRECTORY_STATE
) },
195 { 'C', specifier_directory
, UINT_TO_PTR(DIRECTORY_CACHE
) },
196 { 'L', specifier_directory
, UINT_TO_PTR(DIRECTORY_LOGS
) },
200 static int specifier_machine_id_safe(char specifier
, void *data
, void *userdata
, char **ret
) {
203 /* If /etc/machine_id is missing or empty (e.g. in a chroot environment)
204 * return a recognizable error so that the caller can skip the rule
207 r
= specifier_machine_id(specifier
, data
, userdata
, ret
);
208 if (IN_SET(r
, -ENOENT
, -ENOMEDIUM
))
214 static int specifier_directory(char specifier
, void *data
, void *userdata
, char **ret
) {
220 static const struct table_entry paths_system
[] = {
221 [DIRECTORY_RUNTIME
] = { SD_PATH_SYSTEM_RUNTIME
},
222 [DIRECTORY_STATE
] = { SD_PATH_SYSTEM_STATE_PRIVATE
},
223 [DIRECTORY_CACHE
] = { SD_PATH_SYSTEM_STATE_CACHE
},
224 [DIRECTORY_LOGS
] = { SD_PATH_SYSTEM_STATE_LOGS
},
227 static const struct table_entry paths_user
[] = {
228 [DIRECTORY_RUNTIME
] = { SD_PATH_USER_RUNTIME
},
229 [DIRECTORY_STATE
] = { SD_PATH_USER_CONFIGURATION
},
230 [DIRECTORY_CACHE
] = { SD_PATH_USER_STATE_CACHE
},
231 [DIRECTORY_LOGS
] = { SD_PATH_USER_CONFIGURATION
, "log" },
235 const struct table_entry
*paths
;
237 assert_cc(ELEMENTSOF(paths_system
) == ELEMENTSOF(paths_user
));
238 paths
= arg_user
? paths_user
: paths_system
;
240 i
= PTR_TO_UINT(data
);
241 assert(i
< ELEMENTSOF(paths_system
));
243 return sd_path_home(paths
[i
].type
, paths
[i
].suffix
, ret
);
246 static int log_unresolvable_specifier(const char *filename
, unsigned line
) {
247 static bool notified
= false;
249 /* In system mode, this is called when /etc is not fully initialized (e.g.
250 * in a chroot environment) where some specifiers are unresolvable. In user
251 * mode, this is called when some variables are not defined. These cases are
252 * not considered as an error so log at LOG_NOTICE only for the first time
253 * and then downgrade this to LOG_DEBUG for the rest. */
255 log_full(notified
? LOG_DEBUG
: LOG_NOTICE
,
256 "[%s:%u] Failed to resolve specifier: %s, skipping",
258 arg_user
? "Required $XDG_... variable not defined" : "uninitialized /etc detected");
261 log_notice("All rules containing unresolvable specifiers will be skipped.");
267 static int user_config_paths(char*** ret
) {
268 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
269 _cleanup_free_
char *persistent_config
= NULL
, *runtime_config
= NULL
, *data_home
= NULL
;
270 _cleanup_strv_free_
char **res
= NULL
;
273 r
= xdg_user_dirs(&config_dirs
, &data_dirs
);
277 r
= xdg_user_config_dir(&persistent_config
, "/user-tmpfiles.d");
278 if (r
< 0 && r
!= -ENXIO
)
281 r
= xdg_user_runtime_dir(&runtime_config
, "/user-tmpfiles.d");
282 if (r
< 0 && r
!= -ENXIO
)
285 r
= xdg_user_data_dir(&data_home
, "/user-tmpfiles.d");
286 if (r
< 0 && r
!= -ENXIO
)
289 r
= strv_extend_strv_concat(&res
, config_dirs
, "/user-tmpfiles.d");
293 r
= strv_extend(&res
, persistent_config
);
297 r
= strv_extend(&res
, runtime_config
);
301 r
= strv_extend(&res
, data_home
);
305 r
= strv_extend_strv_concat(&res
, data_dirs
, "/user-tmpfiles.d");
309 r
= path_strv_make_absolute_cwd(res
);
318 static bool needs_glob(ItemType t
) {
322 IGNORE_DIRECTORY_PATH
,
324 RECURSIVE_REMOVE_PATH
,
328 RECURSIVE_RELABEL_PATH
,
334 RECURSIVE_SET_ATTRIBUTE
);
337 static bool takes_ownership(ItemType t
) {
345 CREATE_SUBVOLUME_INHERIT_QUOTA
,
346 CREATE_SUBVOLUME_NEW_QUOTA
,
354 IGNORE_DIRECTORY_PATH
,
356 RECURSIVE_REMOVE_PATH
);
359 static struct Item
* find_glob(OrderedHashmap
*h
, const char *match
) {
363 ORDERED_HASHMAP_FOREACH(j
, h
, i
) {
366 for (n
= 0; n
< j
->count
; n
++) {
367 Item
*item
= j
->items
+ n
;
369 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
377 static void load_unix_sockets(void) {
378 _cleanup_fclose_
FILE *f
= NULL
;
384 /* We maintain a cache of the sockets we found in /proc/net/unix to speed things up a little. */
386 unix_sockets
= set_new(&path_hash_ops
);
392 f
= fopen("/proc/net/unix", "re");
394 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_WARNING
, errno
,
395 "Failed to open /proc/net/unix, ignoring: %m");
400 r
= read_line(f
, LONG_LINE_MAX
, NULL
);
402 log_warning_errno(r
, "Failed to skip /proc/net/unix header line: %m");
406 log_warning("Premature end of file reading /proc/net/unix.");
411 _cleanup_free_
char *line
= NULL
;
414 r
= read_line(f
, LONG_LINE_MAX
, &line
);
416 log_warning_errno(r
, "Failed to read /proc/net/unix line, ignoring: %m");
419 if (r
== 0) /* EOF */
422 p
= strchr(line
, ':');
430 p
+= strspn(p
, WHITESPACE
);
431 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
432 p
+= strspn(p
, WHITESPACE
);
443 path_kill_slashes(s
);
445 r
= set_consume(unix_sockets
, s
);
446 if (r
< 0 && r
!= -EEXIST
) {
447 log_warning_errno(r
, "Failed to add AF_UNIX socket to set, ignoring: %m");
455 unix_sockets
= set_free_free(unix_sockets
);
458 static bool unix_socket_alive(const char *fn
) {
464 return !!set_get(unix_sockets
, (char*) fn
);
466 /* We don't know, so assume yes */
470 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
472 int mount_id_parent
, mount_id
;
475 r_p
= name_to_handle_at_loop(dirfd(d
), ".", NULL
, &mount_id_parent
, 0);
479 r
= name_to_handle_at_loop(dirfd(d
), subdir
, NULL
, &mount_id
, 0);
483 /* got no handle; make no assumptions, return error */
484 if (r_p
< 0 && r
< 0)
487 /* got both handles; if they differ, it is a mount point */
488 if (r_p
>= 0 && r
>= 0)
489 return mount_id_parent
!= mount_id
;
491 /* got only one handle; assume different mount points if one
492 * of both queries was not supported by the filesystem */
493 if (IN_SET(r_p
, -ENOSYS
, -EOPNOTSUPP
) || IN_SET(r
, -ENOSYS
, -EOPNOTSUPP
))
502 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
505 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
509 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
513 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
515 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
520 static DIR* opendir_nomod(const char *path
) {
521 return xopendirat_nomod(AT_FDCWD
, path
);
524 static int dir_cleanup(
528 const struct stat
*ds
,
533 bool keep_this_level
) {
536 struct timespec times
[2];
537 bool deleted
= false;
540 FOREACH_DIRENT_ALL(dent
, d
, break) {
543 _cleanup_free_
char *sub_path
= NULL
;
545 if (dot_or_dot_dot(dent
->d_name
))
548 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
552 /* FUSE, NFS mounts, SELinux might return EACCES */
553 r
= log_full_errno(errno
== EACCES
? LOG_DEBUG
: LOG_ERR
, errno
,
554 "stat(%s/%s) failed: %m", p
, dent
->d_name
);
558 /* Stay on the same filesystem */
559 if (s
.st_dev
!= rootdev
) {
560 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
564 /* Try to detect bind mounts of the same filesystem instance; they
565 * do not differ in device major/minors. This type of query is not
566 * supported on all kernels or filesystem types though. */
567 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
568 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
573 sub_path
= strjoin(p
, "/", dent
->d_name
);
579 /* Is there an item configured for this path? */
580 if (ordered_hashmap_get(items
, sub_path
)) {
581 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
585 if (find_glob(globs
, sub_path
)) {
586 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
590 if (S_ISDIR(s
.st_mode
)) {
593 streq(dent
->d_name
, "lost+found") &&
595 log_debug("Ignoring \"%s\".", sub_path
);
600 log_warning("Reached max depth on \"%s\".", sub_path
);
602 _cleanup_closedir_
DIR *sub_dir
;
605 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
608 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
613 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
618 /* Note: if you are wondering why we don't
619 * support the sticky bit for excluding
620 * directories from cleaning like we do it for
621 * other file system objects: well, the sticky
622 * bit already has a meaning for directories,
623 * so we don't want to overload that. */
625 if (keep_this_level
) {
626 log_debug("Keeping \"%s\".", sub_path
);
630 /* Ignore ctime, we change it when deleting */
631 age
= timespec_load(&s
.st_mtim
);
633 char a
[FORMAT_TIMESTAMP_MAX
];
634 /* Follows spelling in stat(1). */
635 log_debug("Directory \"%s\": modify time %s is too new.",
637 format_timestamp_us(a
, sizeof(a
), age
));
641 age
= timespec_load(&s
.st_atim
);
643 char a
[FORMAT_TIMESTAMP_MAX
];
644 log_debug("Directory \"%s\": access time %s is too new.",
646 format_timestamp_us(a
, sizeof(a
), age
));
650 log_debug("Removing directory \"%s\".", sub_path
);
651 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
652 if (!IN_SET(errno
, ENOENT
, ENOTEMPTY
))
653 r
= log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
656 /* Skip files for which the sticky bit is
657 * set. These are semantics we define, and are
658 * unknown elsewhere. See XDG_RUNTIME_DIR
659 * specification for details. */
660 if (s
.st_mode
& S_ISVTX
) {
661 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
665 if (mountpoint
&& S_ISREG(s
.st_mode
))
666 if (s
.st_uid
== 0 && STR_IN_SET(dent
->d_name
,
670 log_debug("Skipping \"%s\".", sub_path
);
674 /* Ignore sockets that are listed in /proc/net/unix */
675 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
676 log_debug("Skipping \"%s\": live socket.", sub_path
);
680 /* Ignore device nodes */
681 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
682 log_debug("Skipping \"%s\": a device.", sub_path
);
686 /* Keep files on this level around if this is
688 if (keep_this_level
) {
689 log_debug("Keeping \"%s\".", sub_path
);
693 age
= timespec_load(&s
.st_mtim
);
695 char a
[FORMAT_TIMESTAMP_MAX
];
696 /* Follows spelling in stat(1). */
697 log_debug("File \"%s\": modify time %s is too new.",
699 format_timestamp_us(a
, sizeof(a
), age
));
703 age
= timespec_load(&s
.st_atim
);
705 char a
[FORMAT_TIMESTAMP_MAX
];
706 log_debug("File \"%s\": access time %s is too new.",
708 format_timestamp_us(a
, sizeof(a
), age
));
712 age
= timespec_load(&s
.st_ctim
);
714 char a
[FORMAT_TIMESTAMP_MAX
];
715 log_debug("File \"%s\": change time %s is too new.",
717 format_timestamp_us(a
, sizeof(a
), age
));
721 log_debug("unlink \"%s\"", sub_path
);
723 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
725 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
734 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
736 /* Restore original directory timestamps */
737 times
[0] = ds
->st_atim
;
738 times
[1] = ds
->st_mtim
;
740 age1
= timespec_load(&ds
->st_atim
);
741 age2
= timespec_load(&ds
->st_mtim
);
742 log_debug("Restoring access and modification time on \"%s\": %s, %s",
744 format_timestamp_us(a
, sizeof(a
), age1
),
745 format_timestamp_us(b
, sizeof(b
), age2
));
746 if (futimens(dirfd(d
), times
) < 0)
747 log_error_errno(errno
, "utimensat(%s): %m", p
);
753 static bool dangerous_hardlinks(void) {
754 _cleanup_free_
char *value
= NULL
;
755 static int cached
= -1;
758 /* Check whether the fs.protected_hardlinks sysctl is on. If we can't determine it we assume its off, as that's
759 * what the upstream default is. */
764 r
= read_one_line_file("/proc/sys/fs/protected_hardlinks", &value
);
766 log_debug_errno(r
, "Failed to read fs.protected_hardlinks sysctl: %m");
770 r
= parse_boolean(value
);
772 log_debug_errno(r
, "Failed to parse fs.protected_hardlinks sysctl: %m");
780 static bool hardlink_vulnerable(const struct stat
*st
) {
783 return !S_ISDIR(st
->st_mode
) && st
->st_nlink
> 1 && dangerous_hardlinks();
786 static int fd_set_perms(Item
*i
, int fd
, const struct stat
*st
) {
787 _cleanup_free_
char *path
= NULL
;
793 r
= fd_get_path(fd
, &path
);
797 if (!i
->mode_set
&& !i
->uid_set
&& !i
->gid_set
)
800 if (hardlink_vulnerable(st
)) {
801 log_error("Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path
);
806 if (S_ISLNK(st
->st_mode
))
807 log_debug("Skipping mode fix for symlink %s.", path
);
812 if (!(st
->st_mode
& 0111))
814 if (!(st
->st_mode
& 0222))
816 if (!(st
->st_mode
& 0444))
818 if (!S_ISDIR(st
->st_mode
))
819 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
822 if (m
== (st
->st_mode
& 07777))
823 log_debug("\"%s\" has correct mode %o already.", path
, st
->st_mode
);
825 char procfs_path
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
827 log_debug("Changing \"%s\" to mode %o.", path
, m
);
829 /* fchmodat() still doesn't have AT_EMPTY_PATH flag. */
830 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
832 if (chmod(procfs_path
, m
) < 0)
833 return log_error_errno(errno
, "chmod() of %s via %s failed: %m", path
, procfs_path
);
838 if ((i
->uid_set
&& i
->uid
!= st
->st_uid
) ||
839 (i
->gid_set
&& i
->gid
!= st
->st_gid
)) {
840 log_debug("Changing \"%s\" to owner "UID_FMT
":"GID_FMT
,
842 i
->uid_set
? i
->uid
: UID_INVALID
,
843 i
->gid_set
? i
->gid
: GID_INVALID
);
847 i
->uid_set
? i
->uid
: UID_INVALID
,
848 i
->gid_set
? i
->gid
: GID_INVALID
,
850 return log_error_errno(errno
, "fchownat() of %s failed: %m", path
);
854 return label_fix(path
, false, false);
857 static int path_set_perms(Item
*i
, const char *path
) {
858 _cleanup_close_
int fd
= -1;
864 fd
= open(path
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
866 int level
= LOG_ERR
, r
= -errno
;
868 /* Option "e" operates only on existing objects. Do not
869 * print errors about non-existent files or directories */
870 if (i
->type
== EMPTY_DIRECTORY
&& errno
== ENOENT
) {
875 log_full_errno(level
, errno
, "Adjusting owner and mode for %s failed: %m", path
);
879 if (fstat(fd
, &st
) < 0)
880 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
882 return fd_set_perms(i
, fd
, &st
);
885 static int parse_xattrs_from_arg(Item
*i
) {
895 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
;
897 r
= extract_first_word(&p
, &xattr
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
899 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
903 r
= split_pair(xattr
, "=", &name
, &value
);
905 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
909 if (isempty(name
) || isempty(value
)) {
910 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
914 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
923 static int fd_set_xattrs(Item
*i
, int fd
, const struct stat
*st
) {
924 char procfs_path
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
925 _cleanup_free_
char *path
= NULL
;
926 char **name
, **value
;
932 r
= fd_get_path(fd
, &path
);
936 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
938 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
939 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
940 if (setxattr(procfs_path
, *name
, *value
, strlen(*value
), 0) < 0)
941 return log_error_errno(errno
, "Setting extended attribute %s=%s on %s failed: %m",
942 *name
, *value
, path
);
947 static int path_set_xattrs(Item
*i
, const char *path
) {
948 _cleanup_close_
int fd
= -1;
953 fd
= open(path
, O_CLOEXEC
|O_NOFOLLOW
|O_PATH
);
955 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
957 return fd_set_xattrs(i
, fd
, NULL
);
960 static int parse_acls_from_arg(Item
*item
) {
966 /* If force (= modify) is set, we will not modify the acl
967 * afterwards, so the mask can be added now if necessary. */
969 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
971 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
973 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
980 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
981 _cleanup_(acl_free_charpp
) char *t
= NULL
;
982 _cleanup_(acl_freep
) acl_t dup
= NULL
;
985 /* Returns 0 for success, positive error if already warned,
986 * negative error otherwise. */
989 r
= acls_for_file(path
, type
, acl
, &dup
);
993 r
= calc_acl_mask_if_needed(&dup
);
1001 /* the mask was already added earlier if needed */
1004 r
= add_base_acls_if_needed(&dup
, path
);
1008 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
1009 log_debug("Setting %s ACL %s on %s.",
1010 type
== ACL_TYPE_ACCESS
? "access" : "default",
1013 r
= acl_set_file(path
, type
, dup
);
1015 /* Return positive to indicate we already warned */
1016 return -log_error_errno(errno
,
1017 "Setting %s ACL \"%s\" on %s failed: %m",
1018 type
== ACL_TYPE_ACCESS
? "access" : "default",
1025 static int fd_set_acls(Item
*item
, int fd
, const struct stat
*st
) {
1028 char procfs_path
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
1029 _cleanup_free_
char *path
= NULL
;
1035 r
= fd_get_path(fd
, &path
);
1039 if (hardlink_vulnerable(st
)) {
1040 log_error("Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path
);
1044 if (S_ISLNK(st
->st_mode
)) {
1045 log_debug("Skipping ACL fix for symlink %s.", path
);
1049 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
1051 if (item
->acl_access
)
1052 r
= path_set_acl(procfs_path
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
1054 if (r
== 0 && item
->acl_default
)
1055 r
= path_set_acl(procfs_path
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
1058 return -r
; /* already warned */
1059 if (r
== -EOPNOTSUPP
) {
1060 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
1064 return log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
1069 static int path_set_acls(Item
*item
, const char *path
) {
1072 _cleanup_close_
int fd
= -1;
1078 fd
= open(path
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
1080 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
1082 if (fstat(fd
, &st
) < 0)
1083 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
1085 r
= fd_set_acls(item
, fd
, &st
);
1090 #define ATTRIBUTES_ALL \
1099 FS_JOURNAL_DATA_FL | \
1106 static int parse_attribute_from_arg(Item
*item
) {
1108 static const struct {
1112 { 'A', FS_NOATIME_FL
}, /* do not update atime */
1113 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
1114 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
1115 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
1116 { 'c', FS_COMPR_FL
}, /* Compress file */
1117 { 'd', FS_NODUMP_FL
}, /* do not dump file */
1118 { 'e', FS_EXTENT_FL
}, /* Extents */
1119 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
1120 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
1121 { 's', FS_SECRM_FL
}, /* Secure deletion */
1122 { 'u', FS_UNRM_FL
}, /* Undelete */
1123 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
1124 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies */
1125 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
1134 unsigned value
= 0, mask
= 0;
1144 } else if (*p
== '-') {
1147 } else if (*p
== '=') {
1153 if (isempty(p
) && mode
!= MODE_SET
) {
1154 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
1158 for (; p
&& *p
; p
++) {
1161 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
1162 if (*p
== attributes
[i
].character
)
1165 if (i
>= ELEMENTSOF(attributes
)) {
1166 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
1170 v
= attributes
[i
].value
;
1172 SET_FLAG(value
, v
, IN_SET(mode
, MODE_ADD
, MODE_SET
));
1177 if (mode
== MODE_SET
)
1178 mask
|= ATTRIBUTES_ALL
;
1182 item
->attribute_mask
= mask
;
1183 item
->attribute_value
= value
;
1184 item
->attribute_set
= true;
1189 static int fd_set_attribute(Item
*item
, int fd
, const struct stat
*st
) {
1190 char procfs_path
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
1191 _cleanup_close_
int procfs_fd
= -1;
1192 _cleanup_free_
char *path
= NULL
;
1196 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
1199 r
= fd_get_path(fd
, &path
);
1203 /* Issuing the file attribute ioctls on device nodes is not
1204 * safe, as that will be delivered to the drivers, not the
1205 * file system containing the device node. */
1206 if (!S_ISREG(st
->st_mode
) && !S_ISDIR(st
->st_mode
)) {
1207 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
1211 f
= item
->attribute_value
& item
->attribute_mask
;
1213 /* Mask away directory-specific flags */
1214 if (!S_ISDIR(st
->st_mode
))
1215 f
&= ~FS_DIRSYNC_FL
;
1217 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
1219 procfs_fd
= open(procfs_path
, O_RDONLY
|O_CLOEXEC
|O_NOATIME
);
1223 r
= chattr_fd(procfs_fd
, f
, item
->attribute_mask
);
1225 log_full_errno(IN_SET(r
, -ENOTTY
, -EOPNOTSUPP
) ? LOG_DEBUG
: LOG_WARNING
,
1227 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
1228 path
, item
->attribute_value
, item
->attribute_mask
);
1233 static int path_set_attribute(Item
*item
, const char *path
) {
1234 _cleanup_close_
int fd
= -1;
1237 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
1240 fd
= open(path
, O_CLOEXEC
|O_NOFOLLOW
|O_PATH
);
1242 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
1244 if (fstat(fd
, &st
) < 0)
1245 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
1247 return fd_set_attribute(item
, fd
, &st
);
1250 static int write_one_file(Item
*i
, const char *path
) {
1251 _cleanup_close_
int fd
= -1;
1258 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_EXCL
|O_NOFOLLOW
:
1259 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
1261 RUN_WITH_UMASK(0000) {
1262 mac_selinux_create_file_prepare(path
, S_IFREG
);
1263 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
1264 mac_selinux_create_file_clear();
1268 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
1269 log_debug_errno(errno
, "Not writing missing file \"%s\": %m", path
);
1272 if (i
->type
== CREATE_FILE
&& errno
== EEXIST
) {
1273 log_debug_errno(errno
, "Not writing to pre-existing file \"%s\": %m", path
);
1278 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
1279 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
1282 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1286 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1288 r
= loop_write(fd
, i
->argument
, strlen(i
->argument
), false);
1290 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1292 log_debug("\"%s\" has been created.", path
);
1294 fd
= safe_close(fd
);
1297 if (stat(path
, &st
) < 0)
1298 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1301 if (!S_ISREG(st
.st_mode
)) {
1302 log_error("%s is not a file.", path
);
1306 r
= path_set_perms(i
, path
);
1313 typedef int (*action_t
)(Item
*, const char *);
1314 typedef int (*fdaction_t
)(Item
*, int fd
, const struct stat
*st
);
1316 static int item_do(Item
*i
, int fd
, const struct stat
*st
, fdaction_t action
) {
1323 /* This returns the first error we run into, but nevertheless
1325 r
= action(i
, fd
, st
);
1327 if (S_ISDIR(st
->st_mode
)) {
1328 char procfs_path
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
1329 _cleanup_closedir_
DIR *d
= NULL
;
1332 /* The passed 'fd' was opened with O_PATH. We need to convert
1333 * it into a 'regular' fd before reading the directory content. */
1334 xsprintf(procfs_path
, "/proc/self/fd/%i", fd
);
1336 d
= opendir(procfs_path
);
1342 FOREACH_DIRENT_ALL(de
, d
, q
= -errno
; goto finish
) {
1346 if (dot_or_dot_dot(de
->d_name
))
1349 de_fd
= openat(fd
, de
->d_name
, O_NOFOLLOW
|O_CLOEXEC
|O_PATH
);
1350 if (de_fd
>= 0 && fstat(de_fd
, &de_st
) >= 0)
1351 /* pass ownership of dirent fd over */
1352 q
= item_do(i
, de_fd
, &de_st
, action
);
1356 if (q
< 0 && r
== 0)
1365 static int glob_item(Item
*i
, action_t action
) {
1366 _cleanup_globfree_ glob_t g
= {
1367 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1372 k
= safe_glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
, &g
);
1373 if (k
< 0 && k
!= -ENOENT
)
1374 return log_error_errno(k
, "glob(%s) failed: %m", i
->path
);
1376 STRV_FOREACH(fn
, g
.gl_pathv
) {
1378 if (k
< 0 && r
== 0)
1385 static int glob_item_recursively(Item
*i
, fdaction_t action
) {
1386 _cleanup_globfree_ glob_t g
= {
1387 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1392 k
= safe_glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
, &g
);
1393 if (k
< 0 && k
!= -ENOENT
)
1394 return log_error_errno(k
, "glob(%s) failed: %m", i
->path
);
1396 STRV_FOREACH(fn
, g
.gl_pathv
) {
1397 _cleanup_close_
int fd
= -1;
1400 /* Make sure we won't trigger/follow file object (such as
1401 * device nodes, automounts, ...) pointed out by 'fn' with
1402 * O_PATH. Note, when O_PATH is used, flags other than
1403 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored. */
1405 fd
= open(*fn
, O_CLOEXEC
|O_NOFOLLOW
|O_PATH
);
1411 if (fstat(fd
, &st
) < 0) {
1416 k
= item_do(i
, fd
, &st
, action
);
1417 if (k
< 0 && r
== 0)
1420 /* we passed fd ownership to the previous call */
1432 _CREATION_MODE_INVALID
= -1
1435 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1436 [CREATION_NORMAL
] = "Created",
1437 [CREATION_EXISTING
] = "Found existing",
1438 [CREATION_FORCE
] = "Created replacement",
1441 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1443 static int create_item(Item
*i
) {
1447 CreationMode creation
;
1451 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1456 case IGNORE_DIRECTORY_PATH
:
1458 case RECURSIVE_REMOVE_PATH
:
1463 RUN_WITH_UMASK(0000)
1464 (void) mkdir_parents_label(i
->path
, 0755);
1466 r
= write_one_file(i
, i
->path
);
1473 RUN_WITH_UMASK(0000)
1474 (void) mkdir_parents_label(i
->path
, 0755);
1476 log_debug("Copying tree \"%s\" to \"%s\".", i
->argument
, i
->path
);
1477 r
= copy_tree(i
->argument
, i
->path
,
1478 i
->uid_set
? i
->uid
: UID_INVALID
,
1479 i
->gid_set
? i
->gid
: GID_INVALID
,
1482 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1489 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1491 if (stat(i
->argument
, &a
) < 0)
1492 return log_error_errno(errno
, "stat(%s) failed: %m", i
->argument
);
1494 if (stat(i
->path
, &b
) < 0)
1495 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1497 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1498 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1503 r
= path_set_perms(i
, i
->path
);
1510 r
= glob_item(i
, write_one_file
);
1516 case CREATE_DIRECTORY
:
1517 case TRUNCATE_DIRECTORY
:
1518 case CREATE_SUBVOLUME
:
1519 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1520 case CREATE_SUBVOLUME_NEW_QUOTA
:
1521 RUN_WITH_UMASK(0000)
1522 (void) mkdir_parents_label(i
->path
, 0755);
1524 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1526 if (btrfs_is_subvol(isempty(arg_root
) ? "/" : arg_root
) <= 0)
1528 /* Don't create a subvolume unless the
1529 * root directory is one, too. We do
1530 * this under the assumption that if
1531 * the root directory is just a plain
1532 * directory (i.e. very light-weight),
1533 * we shouldn't try to split it up
1534 * into subvolumes (i.e. more
1535 * heavy-weight). Thus, chroot()
1536 * environments and suchlike will get
1537 * a full brtfs subvolume set up below
1538 * their tree only if they
1539 * specifically set up a btrfs
1540 * subvolume for the root dir too. */
1544 RUN_WITH_UMASK((~i
->mode
) & 0777)
1545 r
= btrfs_subvol_make(i
->path
);
1550 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1551 RUN_WITH_UMASK(0000)
1552 r
= mkdir_label(i
->path
, i
->mode
);
1557 if (!IN_SET(r
, -EEXIST
, -EROFS
))
1558 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1560 k
= is_dir(i
->path
, false);
1561 if (k
== -ENOENT
&& r
== -EROFS
)
1562 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1564 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1566 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1570 creation
= CREATION_EXISTING
;
1572 creation
= CREATION_NORMAL
;
1574 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1576 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1577 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1579 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i
->path
);
1580 else if (r
== -EROFS
)
1581 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i
->path
);
1582 else if (r
== -ENOPROTOOPT
)
1583 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i
->path
);
1585 q
= log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1587 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1589 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1593 case EMPTY_DIRECTORY
:
1594 r
= path_set_perms(i
, i
->path
);
1603 RUN_WITH_UMASK(0000) {
1604 (void) mkdir_parents_label(i
->path
, 0755);
1606 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1607 r
= mkfifo(i
->path
, i
->mode
);
1608 mac_selinux_create_file_clear();
1612 if (errno
!= EEXIST
)
1613 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1615 if (lstat(i
->path
, &st
) < 0)
1616 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1618 if (!S_ISFIFO(st
.st_mode
)) {
1621 RUN_WITH_UMASK(0000) {
1622 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1623 r
= mkfifo_atomic(i
->path
, i
->mode
);
1624 mac_selinux_create_file_clear();
1628 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1629 creation
= CREATION_FORCE
;
1631 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1635 creation
= CREATION_EXISTING
;
1637 creation
= CREATION_NORMAL
;
1638 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1640 r
= path_set_perms(i
, i
->path
);
1647 case CREATE_SYMLINK
: {
1648 RUN_WITH_UMASK(0000)
1649 (void) mkdir_parents_label(i
->path
, 0755);
1651 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1652 r
= symlink(i
->argument
, i
->path
);
1653 mac_selinux_create_file_clear();
1656 _cleanup_free_
char *x
= NULL
;
1658 if (errno
!= EEXIST
)
1659 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1661 r
= readlink_malloc(i
->path
, &x
);
1662 if (r
< 0 || !streq(i
->argument
, x
)) {
1665 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1666 r
= symlink_atomic(i
->argument
, i
->path
);
1667 mac_selinux_create_file_clear();
1669 if (IN_SET(r
, -EEXIST
, -ENOTEMPTY
)) {
1670 r
= rm_rf(i
->path
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
1672 return log_error_errno(r
, "rm -fr %s failed: %m", i
->path
);
1674 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1675 r
= symlink(i
->argument
, i
->path
) < 0 ? -errno
: 0;
1676 mac_selinux_create_file_clear();
1679 return log_error_errno(r
, "symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
1681 creation
= CREATION_FORCE
;
1683 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1687 creation
= CREATION_EXISTING
;
1690 creation
= CREATION_NORMAL
;
1691 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1695 case CREATE_BLOCK_DEVICE
:
1696 case CREATE_CHAR_DEVICE
: {
1699 if (have_effective_cap(CAP_MKNOD
) == 0) {
1700 /* In a container we lack CAP_MKNOD. We
1701 shouldn't attempt to create the device node in
1702 that case to avoid noise, and we don't support
1703 virtualized devices in containers anyway. */
1705 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1709 RUN_WITH_UMASK(0000)
1710 (void) mkdir_parents_label(i
->path
, 0755);
1712 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1714 RUN_WITH_UMASK(0000) {
1715 mac_selinux_create_file_prepare(i
->path
, file_type
);
1716 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1717 mac_selinux_create_file_clear();
1721 if (errno
== EPERM
) {
1722 log_debug("We lack permissions, possibly because of cgroup configuration; "
1723 "skipping creation of device node %s.", i
->path
);
1727 if (errno
!= EEXIST
)
1728 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1730 if (lstat(i
->path
, &st
) < 0)
1731 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1733 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1737 RUN_WITH_UMASK(0000) {
1738 mac_selinux_create_file_prepare(i
->path
, file_type
);
1739 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1740 mac_selinux_create_file_clear();
1744 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1745 creation
= CREATION_FORCE
;
1747 log_debug("%s is not a device node.", i
->path
);
1751 creation
= CREATION_EXISTING
;
1753 creation
= CREATION_NORMAL
;
1755 log_debug("%s %s device node \"%s\" %u:%u.",
1756 creation_mode_verb_to_string(creation
),
1757 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1758 i
->path
, major(i
->mode
), minor(i
->mode
));
1760 r
= path_set_perms(i
, i
->path
);
1769 r
= glob_item(i
, path_set_perms
);
1774 case RECURSIVE_RELABEL_PATH
:
1775 r
= glob_item_recursively(i
, fd_set_perms
);
1781 r
= glob_item(i
, path_set_xattrs
);
1786 case RECURSIVE_SET_XATTR
:
1787 r
= glob_item_recursively(i
, fd_set_xattrs
);
1793 r
= glob_item(i
, path_set_acls
);
1798 case RECURSIVE_SET_ACL
:
1799 r
= glob_item_recursively(i
, fd_set_acls
);
1805 r
= glob_item(i
, path_set_attribute
);
1810 case RECURSIVE_SET_ATTRIBUTE
:
1811 r
= glob_item_recursively(i
, fd_set_attribute
);
1820 static int remove_item_instance(Item
*i
, const char *instance
) {
1828 if (remove(instance
) < 0 && errno
!= ENOENT
)
1829 return log_error_errno(errno
, "rm(%s): %m", instance
);
1833 case TRUNCATE_DIRECTORY
:
1834 case RECURSIVE_REMOVE_PATH
:
1835 /* FIXME: we probably should use dir_cleanup() here
1836 * instead of rm_rf() so that 'x' is honoured. */
1837 log_debug("rm -rf \"%s\"", instance
);
1838 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1839 if (r
< 0 && r
!= -ENOENT
)
1840 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1845 assert_not_reached("wut?");
1851 static int remove_item(Item
*i
) {
1854 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1859 case TRUNCATE_DIRECTORY
:
1860 case RECURSIVE_REMOVE_PATH
:
1861 return glob_item(i
, remove_item_instance
);
1868 static int clean_item_instance(Item
*i
, const char* instance
) {
1869 _cleanup_closedir_
DIR *d
= NULL
;
1873 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1880 n
= now(CLOCK_REALTIME
);
1884 cutoff
= n
- i
->age
;
1886 d
= opendir_nomod(instance
);
1888 if (IN_SET(errno
, ENOENT
, ENOTDIR
)) {
1889 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1893 return log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1896 if (fstat(dirfd(d
), &s
) < 0)
1897 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1899 if (!S_ISDIR(s
.st_mode
)) {
1900 log_error("%s is not a directory.", i
->path
);
1904 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1905 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1907 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1909 log_debug("Cleanup threshold for %s \"%s\" is %s",
1910 mountpoint
? "mount point" : "directory",
1912 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1914 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1915 MAX_DEPTH
, i
->keep_first_level
);
1918 static int clean_item(Item
*i
) {
1921 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1924 case CREATE_DIRECTORY
:
1925 case CREATE_SUBVOLUME
:
1926 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1927 case CREATE_SUBVOLUME_NEW_QUOTA
:
1928 case TRUNCATE_DIRECTORY
:
1931 clean_item_instance(i
, i
->path
);
1933 case EMPTY_DIRECTORY
:
1934 case IGNORE_DIRECTORY_PATH
:
1935 return glob_item(i
, clean_item_instance
);
1941 static int process_item_array(ItemArray
*array
);
1943 static int process_item(Item
*i
) {
1945 _cleanup_free_
char *prefix
= NULL
;
1954 prefix
= malloc(strlen(i
->path
) + 1);
1958 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1961 j
= ordered_hashmap_get(items
, prefix
);
1965 s
= process_item_array(j
);
1966 if (s
< 0 && t
== 0)
1971 if (chase_symlinks(i
->path
, NULL
, CHASE_NO_AUTOFS
, NULL
) == -EREMOTE
)
1974 r
= arg_create
? create_item(i
) : 0;
1975 q
= arg_remove
? remove_item(i
) : 0;
1976 p
= arg_clean
? clean_item(i
) : 0;
1984 static int process_item_array(ItemArray
*array
) {
1990 for (n
= 0; n
< array
->count
; n
++) {
1991 k
= process_item(array
->items
+ n
);
1992 if (k
< 0 && r
== 0)
1999 static void item_free_contents(Item
*i
) {
2003 strv_free(i
->xattrs
);
2006 acl_free(i
->acl_access
);
2007 acl_free(i
->acl_default
);
2011 static void item_array_free(ItemArray
*a
) {
2017 for (n
= 0; n
< a
->count
; n
++)
2018 item_free_contents(a
->items
+ n
);
2023 static int item_compare(const void *a
, const void *b
) {
2024 const Item
*x
= a
, *y
= b
;
2026 /* Make sure that the ownership taking item is put first, so
2027 * that we first create the node, and then can adjust it */
2029 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
2031 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
2034 return (int) x
->type
- (int) y
->type
;
2037 static bool item_compatible(Item
*a
, Item
*b
) {
2040 assert(streq(a
->path
, b
->path
));
2042 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
2043 /* check if the items are the same */
2044 return streq_ptr(a
->argument
, b
->argument
) &&
2046 a
->uid_set
== b
->uid_set
&&
2049 a
->gid_set
== b
->gid_set
&&
2052 a
->mode_set
== b
->mode_set
&&
2053 a
->mode
== b
->mode
&&
2055 a
->age_set
== b
->age_set
&&
2058 a
->mask_perms
== b
->mask_perms
&&
2060 a
->keep_first_level
== b
->keep_first_level
&&
2062 a
->major_minor
== b
->major_minor
;
2067 static bool should_include_path(const char *path
) {
2070 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
2071 if (path_startswith(path
, *prefix
)) {
2072 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
2077 STRV_FOREACH(prefix
, arg_include_prefixes
)
2078 if (path_startswith(path
, *prefix
)) {
2079 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
2083 /* no matches, so we should include this path only if we
2084 * have no whitelist at all */
2085 if (strv_isempty(arg_include_prefixes
))
2088 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
2092 static int specifier_expansion_from_arg(Item
*i
) {
2093 _cleanup_free_
char *unescaped
= NULL
, *resolved
= NULL
;
2099 if (i
->argument
== NULL
)
2104 case CREATE_SYMLINK
:
2108 r
= cunescape(i
->argument
, 0, &unescaped
);
2110 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
2112 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &resolved
);
2116 free_and_replace(i
->argument
, resolved
);
2120 case RECURSIVE_SET_XATTR
:
2123 STRV_FOREACH (xattr
, i
->xattrs
) {
2124 r
= specifier_printf(*xattr
, specifier_table
, NULL
, &resolved
);
2128 free_and_replace(*xattr
, resolved
);
2138 static int parse_line(const char *fname
, unsigned line
, const char *buffer
, bool *invalid_config
) {
2140 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
2141 _cleanup_(item_free_contents
) Item i
= {};
2142 ItemArray
*existing
;
2145 bool force
= false, boot
= false;
2151 r
= extract_many_words(
2163 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2164 /* invalid quoting and such or an unknown specifier */
2165 *invalid_config
= true;
2166 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
2170 *invalid_config
= true;
2171 log_error("[%s:%u] Syntax error.", fname
, line
);
2175 if (!isempty(buffer
) && !streq(buffer
, "-")) {
2176 i
.argument
= strdup(buffer
);
2181 if (isempty(action
)) {
2182 *invalid_config
= true;
2183 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
2187 for (pos
= 1; action
[pos
]; pos
++) {
2188 if (action
[pos
] == '!' && !boot
)
2190 else if (action
[pos
] == '+' && !force
)
2193 *invalid_config
= true;
2194 log_error("[%s:%u] Unknown modifiers in command '%s'",
2195 fname
, line
, action
);
2200 if (boot
&& !arg_boot
) {
2201 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
2209 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
2211 return log_unresolvable_specifier(fname
, line
);
2213 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2214 *invalid_config
= true;
2215 return log_error_errno(r
, "[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
2220 case CREATE_DIRECTORY
:
2221 case CREATE_SUBVOLUME
:
2222 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
2223 case CREATE_SUBVOLUME_NEW_QUOTA
:
2224 case EMPTY_DIRECTORY
:
2225 case TRUNCATE_DIRECTORY
:
2228 case IGNORE_DIRECTORY_PATH
:
2230 case RECURSIVE_REMOVE_PATH
:
2233 case RECURSIVE_RELABEL_PATH
:
2235 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
2243 case CREATE_SYMLINK
:
2245 i
.argument
= strappend("/usr/share/factory/", i
.path
);
2253 *invalid_config
= true;
2254 log_error("[%s:%u] Write file requires argument.", fname
, line
);
2261 i
.argument
= strappend("/usr/share/factory/", i
.path
);
2264 } else if (!path_is_absolute(i
.argument
)) {
2265 *invalid_config
= true;
2266 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
2270 path_kill_slashes(i
.argument
);
2273 case CREATE_CHAR_DEVICE
:
2274 case CREATE_BLOCK_DEVICE
: {
2275 unsigned major
, minor
;
2278 *invalid_config
= true;
2279 log_error("[%s:%u] Device file requires argument.", fname
, line
);
2283 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
2284 *invalid_config
= true;
2285 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
2289 i
.major_minor
= makedev(major
, minor
);
2294 case RECURSIVE_SET_XATTR
:
2296 *invalid_config
= true;
2297 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
2300 r
= parse_xattrs_from_arg(&i
);
2306 case RECURSIVE_SET_ACL
:
2308 *invalid_config
= true;
2309 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
2312 r
= parse_acls_from_arg(&i
);
2318 case RECURSIVE_SET_ATTRIBUTE
:
2320 *invalid_config
= true;
2321 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
2324 r
= parse_attribute_from_arg(&i
);
2325 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2326 *invalid_config
= true;
2332 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
2333 *invalid_config
= true;
2337 if (!path_is_absolute(i
.path
)) {
2338 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
2339 *invalid_config
= true;
2343 path_kill_slashes(i
.path
);
2345 if (!should_include_path(i
.path
))
2348 r
= specifier_expansion_from_arg(&i
);
2350 return log_unresolvable_specifier(fname
, line
);
2352 if (IN_SET(r
, -EINVAL
, -EBADSLT
))
2353 *invalid_config
= true;
2354 return log_error_errno(r
, "[%s:%u] Failed to substitute specifiers in argument: %m",
2361 p
= prefix_root(arg_root
, i
.path
);
2369 if (!isempty(user
) && !streq(user
, "-")) {
2370 const char *u
= user
;
2372 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
2374 *invalid_config
= true;
2375 return log_error_errno(r
, "[%s:%u] Unknown user '%s'.", fname
, line
, user
);
2381 if (!isempty(group
) && !streq(group
, "-")) {
2382 const char *g
= group
;
2384 r
= get_group_creds(&g
, &i
.gid
);
2386 *invalid_config
= true;
2387 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2394 if (!isempty(mode
) && !streq(mode
, "-")) {
2395 const char *mm
= mode
;
2399 i
.mask_perms
= true;
2403 if (parse_mode(mm
, &m
) < 0) {
2404 *invalid_config
= true;
2405 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2412 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2414 if (!isempty(age
) && !streq(age
, "-")) {
2415 const char *a
= age
;
2418 i
.keep_first_level
= true;
2422 if (parse_sec(a
, &i
.age
) < 0) {
2423 *invalid_config
= true;
2424 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2431 h
= needs_glob(i
.type
) ? globs
: items
;
2433 existing
= ordered_hashmap_get(h
, i
.path
);
2437 for (n
= 0; n
< existing
->count
; n
++) {
2438 if (!item_compatible(existing
->items
+ n
, &i
)) {
2439 log_notice("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2440 fname
, line
, i
.path
);
2445 existing
= new0(ItemArray
, 1);
2449 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2454 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2457 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2459 /* Sort item array, to enforce stable ordering of application */
2460 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2466 static void help(void) {
2467 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2468 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2469 " -h --help Show this help\n"
2470 " --user Execute user configuration\n"
2471 " --version Show package version\n"
2472 " --create Create marked files/directories\n"
2473 " --clean Clean up marked directories\n"
2474 " --remove Remove marked files/directories\n"
2475 " --boot Execute actions only safe at boot\n"
2476 " --prefix=PATH Only apply rules with the specified prefix\n"
2477 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2478 " --root=PATH Operate on an alternate filesystem root\n"
2479 " --replace=PATH Treat arguments as replacement for PATH\n"
2480 , program_invocation_short_name
);
2483 static int parse_argv(int argc
, char *argv
[]) {
2486 ARG_VERSION
= 0x100,
2498 static const struct option options
[] = {
2499 { "help", no_argument
, NULL
, 'h' },
2500 { "user", no_argument
, NULL
, ARG_USER
},
2501 { "version", no_argument
, NULL
, ARG_VERSION
},
2502 { "create", no_argument
, NULL
, ARG_CREATE
},
2503 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2504 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2505 { "boot", no_argument
, NULL
, ARG_BOOT
},
2506 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2507 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2508 { "root", required_argument
, NULL
, ARG_ROOT
},
2509 { "replace", required_argument
, NULL
, ARG_REPLACE
},
2518 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2550 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2554 case ARG_EXCLUDE_PREFIX
:
2555 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2560 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2566 if (!path_is_absolute(optarg
) ||
2567 !endswith(optarg
, ".conf")) {
2568 log_error("The argument to --replace= must an absolute path to a config file");
2572 arg_replace
= optarg
;
2579 assert_not_reached("Unhandled option");
2582 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2583 log_error("You need to specify at least one of --clean, --create or --remove.");
2587 if (arg_replace
&& optind
>= argc
) {
2588 log_error("When --replace= is given, some configuration items must be specified");
2595 static int read_config_file(char **config_dirs
, const char *fn
, bool ignore_enoent
, bool *invalid_config
) {
2596 _cleanup_fclose_
FILE *_f
= NULL
;
2598 char line
[LINE_MAX
];
2606 if (streq(fn
, "-")) {
2607 log_debug("Reading config from stdin…");
2611 r
= search_and_fopen(fn
, "re", arg_root
, (const char**) config_dirs
, &_f
);
2613 if (ignore_enoent
&& r
== -ENOENT
) {
2614 log_debug_errno(r
, "Failed to open \"%s\", ignoring: %m", fn
);
2618 return log_error_errno(r
, "Failed to open '%s': %m", fn
);
2620 log_debug("Reading config file \"%s\"…", fn
);
2624 FOREACH_LINE(line
, f
, break) {
2627 bool invalid_line
= false;
2632 if (IN_SET(*l
, 0, '#'))
2635 k
= parse_line(fn
, v
, l
, &invalid_line
);
2638 /* Allow reporting with a special code if the caller requested this */
2639 *invalid_config
= true;
2641 /* The first error becomes our return value */
2646 /* we have to determine age parameter for each entry of type X */
2647 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2649 Item
*j
, *candidate_item
= NULL
;
2651 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2654 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2655 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2658 if (path_equal(j
->path
, i
->path
)) {
2663 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2664 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2668 if (candidate_item
&& candidate_item
->age_set
) {
2669 i
->age
= candidate_item
->age
;
2675 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2683 static int parse_arguments(char **config_dirs
, char **args
, bool *invalid_config
) {
2687 STRV_FOREACH(arg
, args
) {
2688 r
= read_config_file(config_dirs
, *arg
, false, invalid_config
);
2696 static int read_config_files(char **config_dirs
, char **args
, bool *invalid_config
) {
2697 _cleanup_strv_free_
char **files
= NULL
;
2698 _cleanup_free_
char *p
= NULL
;
2702 r
= conf_files_list_strv(&files
, ".conf", arg_root
, 0, (const char* const*) config_dirs
);
2704 return log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2707 r
= conf_files_insert(&files
, arg_root
, config_dirs
, arg_replace
);
2709 return log_error_errno(r
, "Failed to extend tmpfiles.d file list: %m");
2711 p
= path_join(arg_root
, arg_replace
, NULL
);
2716 STRV_FOREACH(f
, files
)
2717 if (p
&& path_equal(*f
, p
)) {
2718 log_debug("Parsing arguments at position \"%s\"…", *f
);
2720 r
= parse_arguments(config_dirs
, args
, invalid_config
);
2724 /* Just warn, ignore result otherwise.
2725 * read_config_file() has some debug output, so no need to print anything. */
2726 (void) read_config_file(config_dirs
, *f
, true, invalid_config
);
2731 int main(int argc
, char *argv
[]) {
2735 _cleanup_strv_free_
char **config_dirs
= NULL
;
2736 bool invalid_config
= false;
2738 r
= parse_argv(argc
, argv
);
2742 log_set_target(LOG_TARGET_AUTO
);
2743 log_parse_environment();
2750 items
= ordered_hashmap_new(&string_hash_ops
);
2751 globs
= ordered_hashmap_new(&string_hash_ops
);
2753 if (!items
|| !globs
) {
2761 r
= user_config_paths(&config_dirs
);
2763 log_error_errno(r
, "Failed to initialize configuration directory list: %m");
2767 config_dirs
= strv_split_nulstr(CONF_PATHS_NULSTR("tmpfiles.d"));
2774 if (DEBUG_LOGGING
) {
2775 _cleanup_free_
char *t
= NULL
;
2777 t
= strv_join(config_dirs
, "\n\t");
2779 log_debug("Looking for configuration files in (higher priority first:\n\t%s", t
);
2782 /* If command line arguments are specified along with --replace, read all
2783 * configuration files and insert the positional arguments at the specified
2784 * place. Otherwise, if command line arguments are specified, execute just
2785 * them, and finally, without --replace= or any positional arguments, just
2786 * read configuration and execute it.
2788 if (arg_replace
|| optind
>= argc
)
2789 r
= read_config_files(config_dirs
, argv
+ optind
, &invalid_config
);
2791 r
= parse_arguments(config_dirs
, argv
+ optind
, &invalid_config
);
2797 /* The non-globbing ones usually create things, hence we apply
2799 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2800 k
= process_item_array(a
);
2801 if (k
< 0 && r
== 0)
2805 /* The globbing ones usually alter things, hence we apply them
2807 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2808 k
= process_item_array(a
);
2809 if (k
< 0 && r
== 0)
2814 ordered_hashmap_free_with_destructor(items
, item_array_free
);
2815 ordered_hashmap_free_with_destructor(globs
, item_array_free
);
2817 free(arg_include_prefixes
);
2818 free(arg_exclude_prefixes
);
2821 set_free_free(unix_sockets
);
2823 mac_selinux_finish();
2826 return EXIT_FAILURE
;
2827 else if (invalid_config
)
2830 return EXIT_SUCCESS
;