1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering, Kay Sievers
7 Copyright 2015 Zbigniew Jędrzejewski-Szmek
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
37 #include <sys/xattr.h>
42 #include "btrfs-util.h"
43 #include "capability.h"
44 #include "chattr-util.h"
45 #include "conf-files.h"
50 #include "formats-util.h"
57 #include "parse-util.h"
58 #include "path-util.h"
60 #include "selinux-util.h"
62 #include "specifier.h"
63 #include "string-util.h"
65 #include "user-util.h"
68 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
69 * them in the file system. This is intended to be used to create
70 * properly owned directories beneath /tmp, /var/tmp, /run, which are
71 * volatile and hence need to be recreated on bootup. */
73 typedef enum ItemType
{
74 /* These ones take file names */
77 CREATE_DIRECTORY
= 'd',
78 TRUNCATE_DIRECTORY
= 'D',
79 CREATE_SUBVOLUME
= 'v',
80 CREATE_SUBVOLUME_INHERIT_QUOTA
= 'q',
81 CREATE_SUBVOLUME_NEW_QUOTA
= 'Q',
84 CREATE_CHAR_DEVICE
= 'c',
85 CREATE_BLOCK_DEVICE
= 'b',
88 /* These ones take globs */
91 RECURSIVE_SET_XATTR
= 'T',
93 RECURSIVE_SET_ACL
= 'A',
95 RECURSIVE_SET_ATTRIBUTE
= 'H',
97 IGNORE_DIRECTORY_PATH
= 'X',
99 RECURSIVE_REMOVE_PATH
= 'R',
101 RECURSIVE_RELABEL_PATH
= 'Z',
102 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
105 typedef struct Item
{
121 unsigned attribute_value
;
122 unsigned attribute_mask
;
129 bool attribute_set
:1;
131 bool keep_first_level
:1;
138 typedef struct ItemArray
{
144 static bool arg_create
= false;
145 static bool arg_clean
= false;
146 static bool arg_remove
= false;
147 static bool arg_boot
= false;
149 static char **arg_include_prefixes
= NULL
;
150 static char **arg_exclude_prefixes
= NULL
;
151 static char *arg_root
= NULL
;
153 static const char conf_file_dirs
[] = CONF_DIRS_NULSTR("tmpfiles");
155 #define MAX_DEPTH 256
157 static OrderedHashmap
*items
= NULL
, *globs
= NULL
;
158 static Set
*unix_sockets
= NULL
;
160 static const Specifier specifier_table
[] = {
161 { 'm', specifier_machine_id
, NULL
},
162 { 'b', specifier_boot_id
, NULL
},
163 { 'H', specifier_host_name
, NULL
},
164 { 'v', specifier_kernel_release
, NULL
},
168 static bool needs_glob(ItemType t
) {
172 IGNORE_DIRECTORY_PATH
,
174 RECURSIVE_REMOVE_PATH
,
177 RECURSIVE_RELABEL_PATH
,
183 RECURSIVE_SET_ATTRIBUTE
);
186 static bool takes_ownership(ItemType t
) {
193 CREATE_SUBVOLUME_INHERIT_QUOTA
,
194 CREATE_SUBVOLUME_NEW_QUOTA
,
202 IGNORE_DIRECTORY_PATH
,
204 RECURSIVE_REMOVE_PATH
);
207 static struct Item
* find_glob(OrderedHashmap
*h
, const char *match
) {
211 ORDERED_HASHMAP_FOREACH(j
, h
, i
) {
214 for (n
= 0; n
< j
->count
; n
++) {
215 Item
*item
= j
->items
+ n
;
217 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
225 static void load_unix_sockets(void) {
226 _cleanup_fclose_
FILE *f
= NULL
;
232 /* We maintain a cache of the sockets we found in
233 * /proc/net/unix to speed things up a little. */
235 unix_sockets
= set_new(&string_hash_ops
);
239 f
= fopen("/proc/net/unix", "re");
244 if (!fgets(line
, sizeof(line
), f
))
251 if (!fgets(line
, sizeof(line
), f
))
256 p
= strchr(line
, ':');
264 p
+= strspn(p
, WHITESPACE
);
265 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
266 p
+= strspn(p
, WHITESPACE
);
275 path_kill_slashes(s
);
277 k
= set_consume(unix_sockets
, s
);
278 if (k
< 0 && k
!= -EEXIST
)
285 set_free_free(unix_sockets
);
289 static bool unix_socket_alive(const char *fn
) {
295 return !!set_get(unix_sockets
, (char*) fn
);
297 /* We don't know, so assume yes */
301 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
303 union file_handle_union h
= FILE_HANDLE_INIT
;
304 int mount_id_parent
, mount_id
;
307 r_p
= name_to_handle_at(dirfd(d
), ".", &h
.handle
, &mount_id_parent
, 0);
311 h
.handle
.handle_bytes
= MAX_HANDLE_SZ
;
312 r
= name_to_handle_at(dirfd(d
), subdir
, &h
.handle
, &mount_id
, 0);
316 /* got no handle; make no assumptions, return error */
317 if (r_p
< 0 && r
< 0)
320 /* got both handles; if they differ, it is a mount point */
321 if (r_p
>= 0 && r
>= 0)
322 return mount_id_parent
!= mount_id
;
324 /* got only one handle; assume different mount points if one
325 * of both queries was not supported by the filesystem */
326 if (r_p
== -ENOSYS
|| r_p
== -EOPNOTSUPP
|| r
== -ENOSYS
|| r
== -EOPNOTSUPP
)
335 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
338 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
342 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
346 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
348 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
353 static DIR* opendir_nomod(const char *path
) {
354 return xopendirat_nomod(AT_FDCWD
, path
);
357 static int dir_cleanup(
361 const struct stat
*ds
,
366 bool keep_this_level
) {
369 struct timespec times
[2];
370 bool deleted
= false;
373 while ((dent
= readdir(d
))) {
376 _cleanup_free_
char *sub_path
= NULL
;
378 if (STR_IN_SET(dent
->d_name
, ".", ".."))
381 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
385 /* FUSE, NFS mounts, SELinux might return EACCES */
387 log_debug_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
389 log_error_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
394 /* Stay on the same filesystem */
395 if (s
.st_dev
!= rootdev
) {
396 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
400 /* Try to detect bind mounts of the same filesystem instance; they
401 * do not differ in device major/minors. This type of query is not
402 * supported on all kernels or filesystem types though. */
403 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
404 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
409 /* Do not delete read-only files owned by root */
410 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
)) {
411 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p
, dent
->d_name
);
415 sub_path
= strjoin(p
, "/", dent
->d_name
, NULL
);
421 /* Is there an item configured for this path? */
422 if (ordered_hashmap_get(items
, sub_path
)) {
423 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
427 if (find_glob(globs
, sub_path
)) {
428 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
432 if (S_ISDIR(s
.st_mode
)) {
435 streq(dent
->d_name
, "lost+found") &&
437 log_debug("Ignoring \"%s\".", sub_path
);
442 log_warning("Reached max depth on \"%s\".", sub_path
);
444 _cleanup_closedir_
DIR *sub_dir
;
447 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
450 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
455 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
460 /* Note: if you are wondering why we don't
461 * support the sticky bit for excluding
462 * directories from cleaning like we do it for
463 * other file system objects: well, the sticky
464 * bit already has a meaning for directories,
465 * so we don't want to overload that. */
467 if (keep_this_level
) {
468 log_debug("Keeping \"%s\".", sub_path
);
472 /* Ignore ctime, we change it when deleting */
473 age
= timespec_load(&s
.st_mtim
);
475 char a
[FORMAT_TIMESTAMP_MAX
];
476 /* Follows spelling in stat(1). */
477 log_debug("Directory \"%s\": modify time %s is too new.",
479 format_timestamp_us(a
, sizeof(a
), age
));
483 age
= timespec_load(&s
.st_atim
);
485 char a
[FORMAT_TIMESTAMP_MAX
];
486 log_debug("Directory \"%s\": access time %s is too new.",
488 format_timestamp_us(a
, sizeof(a
), age
));
492 log_debug("Removing directory \"%s\".", sub_path
);
493 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
494 if (errno
!= ENOENT
&& errno
!= ENOTEMPTY
) {
495 log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
500 /* Skip files for which the sticky bit is
501 * set. These are semantics we define, and are
502 * unknown elsewhere. See XDG_RUNTIME_DIR
503 * specification for details. */
504 if (s
.st_mode
& S_ISVTX
) {
505 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
509 if (mountpoint
&& S_ISREG(s
.st_mode
))
510 if (s
.st_uid
== 0 && STR_IN_SET(dent
->d_name
,
514 log_debug("Skipping \"%s\".", sub_path
);
518 /* Ignore sockets that are listed in /proc/net/unix */
519 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
520 log_debug("Skipping \"%s\": live socket.", sub_path
);
524 /* Ignore device nodes */
525 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
526 log_debug("Skipping \"%s\": a device.", sub_path
);
530 /* Keep files on this level around if this is
532 if (keep_this_level
) {
533 log_debug("Keeping \"%s\".", sub_path
);
537 age
= timespec_load(&s
.st_mtim
);
539 char a
[FORMAT_TIMESTAMP_MAX
];
540 /* Follows spelling in stat(1). */
541 log_debug("File \"%s\": modify time %s is too new.",
543 format_timestamp_us(a
, sizeof(a
), age
));
547 age
= timespec_load(&s
.st_atim
);
549 char a
[FORMAT_TIMESTAMP_MAX
];
550 log_debug("File \"%s\": access time %s is too new.",
552 format_timestamp_us(a
, sizeof(a
), age
));
556 age
= timespec_load(&s
.st_ctim
);
558 char a
[FORMAT_TIMESTAMP_MAX
];
559 log_debug("File \"%s\": change time %s is too new.",
561 format_timestamp_us(a
, sizeof(a
), age
));
565 log_debug("unlink \"%s\"", sub_path
);
567 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
569 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
578 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
580 /* Restore original directory timestamps */
581 times
[0] = ds
->st_atim
;
582 times
[1] = ds
->st_mtim
;
584 age1
= timespec_load(&ds
->st_atim
);
585 age2
= timespec_load(&ds
->st_mtim
);
586 log_debug("Restoring access and modification time on \"%s\": %s, %s",
588 format_timestamp_us(a
, sizeof(a
), age1
),
589 format_timestamp_us(b
, sizeof(b
), age2
));
590 if (futimens(dirfd(d
), times
) < 0)
591 log_error_errno(errno
, "utimensat(%s): %m", p
);
597 static int path_set_perms(Item
*i
, const char *path
) {
598 _cleanup_close_
int fd
= -1;
604 /* We open the file with O_PATH here, to make the operation
605 * somewhat atomic. Also there's unfortunately no fchmodat()
606 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
609 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
611 return log_error_errno(errno
, "Adjusting owner and mode for %s failed: %m", path
);
613 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
614 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
616 if (S_ISLNK(st
.st_mode
))
617 log_debug("Skipping mode an owner fix for symlink %s.", path
);
619 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
620 xsprintf(fn
, "/proc/self/fd/%i", fd
);
622 /* not using i->path directly because it may be a glob */
627 if (!(st
.st_mode
& 0111))
629 if (!(st
.st_mode
& 0222))
631 if (!(st
.st_mode
& 0444))
633 if (!S_ISDIR(st
.st_mode
))
634 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
637 if (m
== (st
.st_mode
& 07777))
638 log_debug("\"%s\" has right mode %o", path
, st
.st_mode
);
640 log_debug("chmod \"%s\" to mode %o", path
, m
);
641 if (chmod(fn
, m
) < 0)
642 return log_error_errno(errno
, "chmod(%s) failed: %m", path
);
646 if ((i
->uid
!= st
.st_uid
|| i
->gid
!= st
.st_gid
) &&
647 (i
->uid_set
|| i
->gid_set
)) {
648 log_debug("chown \"%s\" to "UID_FMT
"."GID_FMT
,
650 i
->uid_set
? i
->uid
: UID_INVALID
,
651 i
->gid_set
? i
->gid
: GID_INVALID
);
653 i
->uid_set
? i
->uid
: UID_INVALID
,
654 i
->gid_set
? i
->gid
: GID_INVALID
) < 0)
655 return log_error_errno(errno
, "chown(%s) failed: %m", path
);
661 return label_fix(path
, false, false);
664 static int parse_xattrs_from_arg(Item
*i
) {
674 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
, *xattr_replaced
= NULL
;
676 r
= extract_first_word(&p
, &xattr
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
678 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
682 r
= specifier_printf(xattr
, specifier_table
, NULL
, &xattr_replaced
);
684 return log_error_errno(r
, "Failed to replace specifiers in extended attribute '%s': %m", xattr
);
686 r
= split_pair(xattr_replaced
, "=", &name
, &value
);
688 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
692 if (isempty(name
) || isempty(value
)) {
693 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
697 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
706 static int path_set_xattrs(Item
*i
, const char *path
) {
707 char **name
, **value
;
712 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
716 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
717 if (lsetxattr(path
, *name
, *value
, n
, 0) < 0) {
718 log_error("Setting extended attribute %s=%s on %s failed: %m", *name
, *value
, path
);
725 static int parse_acls_from_arg(Item
*item
) {
731 /* If force (= modify) is set, we will not modify the acl
732 * afterwards, so the mask can be added now if necessary. */
734 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
736 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
738 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
745 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
746 _cleanup_(acl_free_charpp
) char *t
= NULL
;
747 _cleanup_(acl_freep
) acl_t dup
= NULL
;
750 /* Returns 0 for success, positive error if already warned,
751 * negative error otherwise. */
754 r
= acls_for_file(path
, type
, acl
, &dup
);
758 r
= calc_acl_mask_if_needed(&dup
);
766 /* the mask was already added earlier if needed */
769 r
= add_base_acls_if_needed(&dup
, path
);
773 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
774 log_debug("Setting %s ACL %s on %s.",
775 type
== ACL_TYPE_ACCESS
? "access" : "default",
778 r
= acl_set_file(path
, type
, dup
);
780 /* Return positive to indicate we already warned */
781 return -log_error_errno(errno
,
782 "Setting %s ACL \"%s\" on %s failed: %m",
783 type
== ACL_TYPE_ACCESS
? "access" : "default",
790 static int path_set_acls(Item
*item
, const char *path
) {
793 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
794 _cleanup_close_
int fd
= -1;
800 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
802 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
804 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
805 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
807 if (S_ISLNK(st
.st_mode
)) {
808 log_debug("Skipping ACL fix for symlink %s.", path
);
812 xsprintf(fn
, "/proc/self/fd/%i", fd
);
814 if (item
->acl_access
)
815 r
= path_set_acl(fn
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
817 if (r
== 0 && item
->acl_default
)
818 r
= path_set_acl(fn
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
821 return -r
; /* already warned */
822 else if (r
== -EOPNOTSUPP
) {
823 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
826 log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
831 #define ATTRIBUTES_ALL \
840 FS_JOURNAL_DATA_FL | \
847 static int parse_attribute_from_arg(Item
*item
) {
849 static const struct {
853 { 'A', FS_NOATIME_FL
}, /* do not update atime */
854 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
855 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
856 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
857 { 'c', FS_COMPR_FL
}, /* Compress file */
858 { 'd', FS_NODUMP_FL
}, /* do not dump file */
859 { 'e', FS_EXTENT_FL
}, /* Top of directory hierarchies*/
860 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
861 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
862 { 's', FS_SECRM_FL
}, /* Secure deletion */
863 { 'u', FS_UNRM_FL
}, /* Undelete */
864 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
865 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies*/
866 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
875 unsigned value
= 0, mask
= 0;
885 } else if (*p
== '-') {
888 } else if (*p
== '=') {
894 if (isempty(p
) && mode
!= MODE_SET
) {
895 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
899 for (; p
&& *p
; p
++) {
902 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
903 if (*p
== attributes
[i
].character
)
906 if (i
>= ELEMENTSOF(attributes
)) {
907 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
911 v
= attributes
[i
].value
;
913 if (mode
== MODE_ADD
|| mode
== MODE_SET
)
921 if (mode
== MODE_SET
)
922 mask
|= ATTRIBUTES_ALL
;
926 item
->attribute_mask
= mask
;
927 item
->attribute_value
= value
;
928 item
->attribute_set
= true;
933 static int path_set_attribute(Item
*item
, const char *path
) {
934 _cleanup_close_
int fd
= -1;
939 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
942 fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
|O_NOATIME
|O_NOFOLLOW
);
945 return log_error_errno(errno
, "Skipping file attributes adjustment on symlink %s.", path
);
947 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
950 if (fstat(fd
, &st
) < 0)
951 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
953 /* Issuing the file attribute ioctls on device nodes is not
954 * safe, as that will be delivered to the drivers, not the
955 * file system containing the device node. */
956 if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
)) {
957 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
961 f
= item
->attribute_value
& item
->attribute_mask
;
963 /* Mask away directory-specific flags */
964 if (!S_ISDIR(st
.st_mode
))
967 r
= chattr_fd(fd
, f
, item
->attribute_mask
);
969 log_full_errno(r
== -ENOTTY
? LOG_DEBUG
: LOG_WARNING
,
971 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
972 path
, item
->attribute_value
, item
->attribute_mask
);
977 static int write_one_file(Item
*i
, const char *path
) {
978 _cleanup_close_
int fd
= -1;
985 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
|O_NOFOLLOW
:
986 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
988 RUN_WITH_UMASK(0000) {
989 mac_selinux_create_file_prepare(path
, S_IFREG
);
990 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
991 mac_selinux_create_file_clear();
995 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
996 log_debug_errno(errno
, "Not writing \"%s\": %m", path
);
1001 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
1002 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
1005 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1009 _cleanup_free_
char *unescaped
= NULL
, *replaced
= NULL
;
1011 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1013 r
= cunescape(i
->argument
, 0, &unescaped
);
1015 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
1017 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &replaced
);
1019 return log_error_errno(r
, "Failed to replace specifiers in parameter to write '%s': %m", unescaped
);
1021 r
= loop_write(fd
, replaced
, strlen(replaced
), false);
1023 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1025 log_debug("\"%s\" has been created.", path
);
1027 fd
= safe_close(fd
);
1029 if (stat(path
, &st
) < 0)
1030 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1033 if (!S_ISREG(st
.st_mode
)) {
1034 log_error("%s is not a file.", path
);
1038 r
= path_set_perms(i
, path
);
1045 typedef int (*action_t
)(Item
*, const char *);
1047 static int item_do_children(Item
*i
, const char *path
, action_t action
) {
1048 _cleanup_closedir_
DIR *d
;
1054 /* This returns the first error we run into, but nevertheless
1057 d
= opendir_nomod(path
);
1059 return errno
== ENOENT
|| errno
== ENOTDIR
? 0 : -errno
;
1062 _cleanup_free_
char *p
= NULL
;
1069 if (errno
!= 0 && r
== 0)
1075 if (STR_IN_SET(de
->d_name
, ".", ".."))
1078 p
= strjoin(path
, "/", de
->d_name
, NULL
);
1083 if (q
< 0 && q
!= -ENOENT
&& r
== 0)
1086 if (IN_SET(de
->d_type
, DT_UNKNOWN
, DT_DIR
)) {
1087 q
= item_do_children(i
, p
, action
);
1088 if (q
< 0 && r
== 0)
1096 static int glob_item(Item
*i
, action_t action
, bool recursive
) {
1097 _cleanup_globfree_ glob_t g
= {
1098 .gl_closedir
= (void (*)(void *)) closedir
,
1099 .gl_readdir
= (struct dirent
*(*)(void *)) readdir
,
1100 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1108 k
= glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
|GLOB_ALTDIRFUNC
, NULL
, &g
);
1109 if (k
!= 0 && k
!= GLOB_NOMATCH
)
1110 return log_error_errno(errno
?: EIO
, "glob(%s) failed: %m", i
->path
);
1112 STRV_FOREACH(fn
, g
.gl_pathv
) {
1114 if (k
< 0 && r
== 0)
1118 k
= item_do_children(i
, *fn
, action
);
1119 if (k
< 0 && r
== 0)
1132 _CREATION_MODE_INVALID
= -1
1135 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1136 [CREATION_NORMAL
] = "Created",
1137 [CREATION_EXISTING
] = "Found existing",
1138 [CREATION_FORCE
] = "Created replacement",
1141 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1143 static int create_item(Item
*i
) {
1144 _cleanup_free_
char *resolved
= NULL
;
1147 CreationMode creation
;
1151 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1156 case IGNORE_DIRECTORY_PATH
:
1158 case RECURSIVE_REMOVE_PATH
:
1163 r
= write_one_file(i
, i
->path
);
1169 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1171 return log_error_errno(r
, "Failed to substitute specifiers in copy source %s: %m", i
->argument
);
1173 log_debug("Copying tree \"%s\" to \"%s\".", resolved
, i
->path
);
1174 r
= copy_tree(resolved
, i
->path
, false);
1176 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1183 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1185 if (stat(resolved
, &a
) < 0)
1186 return log_error_errno(errno
, "stat(%s) failed: %m", resolved
);
1188 if (stat(i
->path
, &b
) < 0)
1189 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1191 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1192 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1197 r
= path_set_perms(i
, i
->path
);
1204 r
= glob_item(i
, write_one_file
, false);
1210 case CREATE_DIRECTORY
:
1211 case TRUNCATE_DIRECTORY
:
1212 case CREATE_SUBVOLUME
:
1213 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1214 case CREATE_SUBVOLUME_NEW_QUOTA
:
1216 RUN_WITH_UMASK(0000)
1217 mkdir_parents_label(i
->path
, 0755);
1219 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1220 RUN_WITH_UMASK((~i
->mode
) & 0777)
1221 r
= btrfs_subvol_make(i
->path
);
1225 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1226 RUN_WITH_UMASK(0000)
1227 r
= mkdir_label(i
->path
, i
->mode
);
1232 if (r
!= -EEXIST
&& r
!= -EROFS
)
1233 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1235 k
= is_dir(i
->path
, false);
1236 if (k
== -ENOENT
&& r
== -EROFS
)
1237 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1239 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1241 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1245 creation
= CREATION_EXISTING
;
1247 creation
= CREATION_NORMAL
;
1249 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1251 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1252 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1254 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i
->path
);
1258 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i
->path
);
1262 return log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1264 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1266 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1269 r
= path_set_perms(i
, i
->path
);
1277 RUN_WITH_UMASK(0000) {
1278 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1279 r
= mkfifo(i
->path
, i
->mode
);
1280 mac_selinux_create_file_clear();
1284 if (errno
!= EEXIST
)
1285 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1287 if (lstat(i
->path
, &st
) < 0)
1288 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1290 if (!S_ISFIFO(st
.st_mode
)) {
1293 RUN_WITH_UMASK(0000) {
1294 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1295 r
= mkfifo_atomic(i
->path
, i
->mode
);
1296 mac_selinux_create_file_clear();
1300 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1301 creation
= CREATION_FORCE
;
1303 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1307 creation
= CREATION_EXISTING
;
1309 creation
= CREATION_NORMAL
;
1310 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1312 r
= path_set_perms(i
, i
->path
);
1319 case CREATE_SYMLINK
: {
1320 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1322 return log_error_errno(r
, "Failed to substitute specifiers in symlink target %s: %m", i
->argument
);
1324 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1325 r
= symlink(resolved
, i
->path
);
1326 mac_selinux_create_file_clear();
1329 _cleanup_free_
char *x
= NULL
;
1331 if (errno
!= EEXIST
)
1332 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1334 r
= readlink_malloc(i
->path
, &x
);
1335 if (r
< 0 || !streq(resolved
, x
)) {
1338 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1339 r
= symlink_atomic(resolved
, i
->path
);
1340 mac_selinux_create_file_clear();
1343 return log_error_errno(r
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1345 creation
= CREATION_FORCE
;
1347 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1351 creation
= CREATION_EXISTING
;
1354 creation
= CREATION_NORMAL
;
1355 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1359 case CREATE_BLOCK_DEVICE
:
1360 case CREATE_CHAR_DEVICE
: {
1363 if (have_effective_cap(CAP_MKNOD
) == 0) {
1364 /* In a container we lack CAP_MKNOD. We
1365 shouldn't attempt to create the device node in
1366 that case to avoid noise, and we don't support
1367 virtualized devices in containers anyway. */
1369 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1373 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1375 RUN_WITH_UMASK(0000) {
1376 mac_selinux_create_file_prepare(i
->path
, file_type
);
1377 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1378 mac_selinux_create_file_clear();
1382 if (errno
== EPERM
) {
1383 log_debug("We lack permissions, possibly because of cgroup configuration; "
1384 "skipping creation of device node %s.", i
->path
);
1388 if (errno
!= EEXIST
)
1389 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1391 if (lstat(i
->path
, &st
) < 0)
1392 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1394 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1398 RUN_WITH_UMASK(0000) {
1399 mac_selinux_create_file_prepare(i
->path
, file_type
);
1400 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1401 mac_selinux_create_file_clear();
1405 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1406 creation
= CREATION_FORCE
;
1408 log_debug("%s is not a device node.", i
->path
);
1412 creation
= CREATION_EXISTING
;
1414 creation
= CREATION_NORMAL
;
1416 log_debug("%s %s device node \"%s\" %u:%u.",
1417 creation_mode_verb_to_string(creation
),
1418 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1419 i
->path
, major(i
->mode
), minor(i
->mode
));
1421 r
= path_set_perms(i
, i
->path
);
1430 r
= glob_item(i
, path_set_perms
, false);
1435 case RECURSIVE_RELABEL_PATH
:
1436 r
= glob_item(i
, path_set_perms
, true);
1442 r
= glob_item(i
, path_set_xattrs
, false);
1447 case RECURSIVE_SET_XATTR
:
1448 r
= glob_item(i
, path_set_xattrs
, true);
1454 r
= glob_item(i
, path_set_acls
, false);
1459 case RECURSIVE_SET_ACL
:
1460 r
= glob_item(i
, path_set_acls
, true);
1466 r
= glob_item(i
, path_set_attribute
, false);
1471 case RECURSIVE_SET_ATTRIBUTE
:
1472 r
= glob_item(i
, path_set_attribute
, true);
1481 static int remove_item_instance(Item
*i
, const char *instance
) {
1489 if (remove(instance
) < 0 && errno
!= ENOENT
)
1490 return log_error_errno(errno
, "rm(%s): %m", instance
);
1494 case TRUNCATE_DIRECTORY
:
1495 case RECURSIVE_REMOVE_PATH
:
1496 /* FIXME: we probably should use dir_cleanup() here
1497 * instead of rm_rf() so that 'x' is honoured. */
1498 log_debug("rm -rf \"%s\"", instance
);
1499 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1500 if (r
< 0 && r
!= -ENOENT
)
1501 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1506 assert_not_reached("wut?");
1512 static int remove_item(Item
*i
) {
1517 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1523 case CREATE_DIRECTORY
:
1524 case CREATE_SUBVOLUME
:
1525 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1526 case CREATE_SUBVOLUME_NEW_QUOTA
:
1528 case CREATE_SYMLINK
:
1529 case CREATE_CHAR_DEVICE
:
1530 case CREATE_BLOCK_DEVICE
:
1532 case IGNORE_DIRECTORY_PATH
:
1535 case RECURSIVE_RELABEL_PATH
:
1539 case RECURSIVE_SET_XATTR
:
1541 case RECURSIVE_SET_ACL
:
1543 case RECURSIVE_SET_ATTRIBUTE
:
1547 case TRUNCATE_DIRECTORY
:
1548 case RECURSIVE_REMOVE_PATH
:
1549 r
= glob_item(i
, remove_item_instance
, false);
1556 static int clean_item_instance(Item
*i
, const char* instance
) {
1557 _cleanup_closedir_
DIR *d
= NULL
;
1561 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1568 n
= now(CLOCK_REALTIME
);
1572 cutoff
= n
- i
->age
;
1574 d
= opendir_nomod(instance
);
1576 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
1577 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1581 log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1585 if (fstat(dirfd(d
), &s
) < 0)
1586 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1588 if (!S_ISDIR(s
.st_mode
)) {
1589 log_error("%s is not a directory.", i
->path
);
1593 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1594 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1596 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1598 log_debug("Cleanup threshold for %s \"%s\" is %s",
1599 mountpoint
? "mount point" : "directory",
1601 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1603 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1604 MAX_DEPTH
, i
->keep_first_level
);
1607 static int clean_item(Item
*i
) {
1612 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1615 case CREATE_DIRECTORY
:
1616 case CREATE_SUBVOLUME
:
1617 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1618 case CREATE_SUBVOLUME_NEW_QUOTA
:
1619 case TRUNCATE_DIRECTORY
:
1622 clean_item_instance(i
, i
->path
);
1624 case IGNORE_DIRECTORY_PATH
:
1625 r
= glob_item(i
, clean_item_instance
, false);
1634 static int process_item_array(ItemArray
*array
);
1636 static int process_item(Item
*i
) {
1638 _cleanup_free_
char *prefix
= NULL
;
1647 prefix
= malloc(strlen(i
->path
) + 1);
1651 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1654 j
= ordered_hashmap_get(items
, prefix
);
1658 s
= process_item_array(j
);
1659 if (s
< 0 && t
== 0)
1664 r
= arg_create
? create_item(i
) : 0;
1665 q
= arg_remove
? remove_item(i
) : 0;
1666 p
= arg_clean
? clean_item(i
) : 0;
1674 static int process_item_array(ItemArray
*array
) {
1680 for (n
= 0; n
< array
->count
; n
++) {
1681 k
= process_item(array
->items
+ n
);
1682 if (k
< 0 && r
== 0)
1689 static void item_free_contents(Item
*i
) {
1693 strv_free(i
->xattrs
);
1696 acl_free(i
->acl_access
);
1697 acl_free(i
->acl_default
);
1701 static void item_array_free(ItemArray
*a
) {
1707 for (n
= 0; n
< a
->count
; n
++)
1708 item_free_contents(a
->items
+ n
);
1713 static int item_compare(const void *a
, const void *b
) {
1714 const Item
*x
= a
, *y
= b
;
1716 /* Make sure that the ownership taking item is put first, so
1717 * that we first create the node, and then can adjust it */
1719 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1721 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1724 return (int) x
->type
- (int) y
->type
;
1727 static bool item_compatible(Item
*a
, Item
*b
) {
1730 assert(streq(a
->path
, b
->path
));
1732 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1733 /* check if the items are the same */
1734 return streq_ptr(a
->argument
, b
->argument
) &&
1736 a
->uid_set
== b
->uid_set
&&
1739 a
->gid_set
== b
->gid_set
&&
1742 a
->mode_set
== b
->mode_set
&&
1743 a
->mode
== b
->mode
&&
1745 a
->age_set
== b
->age_set
&&
1748 a
->mask_perms
== b
->mask_perms
&&
1750 a
->keep_first_level
== b
->keep_first_level
&&
1752 a
->major_minor
== b
->major_minor
;
1757 static bool should_include_path(const char *path
) {
1760 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1761 if (path_startswith(path
, *prefix
)) {
1762 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1767 STRV_FOREACH(prefix
, arg_include_prefixes
)
1768 if (path_startswith(path
, *prefix
)) {
1769 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1773 /* no matches, so we should include this path only if we
1774 * have no whitelist at all */
1775 if (strv_length(arg_include_prefixes
) == 0)
1778 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1782 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1784 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1785 _cleanup_(item_free_contents
) Item i
= {};
1786 ItemArray
*existing
;
1789 bool force
= false, boot
= false;
1795 r
= extract_many_words(
1807 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1809 log_error("[%s:%u] Syntax error.", fname
, line
);
1813 if (!isempty(buffer
) && !streq(buffer
, "-")) {
1814 i
.argument
= strdup(buffer
);
1819 if (isempty(action
)) {
1820 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1824 for (pos
= 1; action
[pos
]; pos
++) {
1825 if (action
[pos
] == '!' && !boot
)
1827 else if (action
[pos
] == '+' && !force
)
1830 log_error("[%s:%u] Unknown modifiers in command '%s'",
1831 fname
, line
, action
);
1836 if (boot
&& !arg_boot
) {
1837 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1845 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1847 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1853 case CREATE_DIRECTORY
:
1854 case CREATE_SUBVOLUME
:
1855 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1856 case CREATE_SUBVOLUME_NEW_QUOTA
:
1857 case TRUNCATE_DIRECTORY
:
1860 case IGNORE_DIRECTORY_PATH
:
1862 case RECURSIVE_REMOVE_PATH
:
1865 case RECURSIVE_RELABEL_PATH
:
1867 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
1875 case CREATE_SYMLINK
:
1877 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1885 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1892 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1895 } else if (!path_is_absolute(i
.argument
)) {
1896 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1900 path_kill_slashes(i
.argument
);
1903 case CREATE_CHAR_DEVICE
:
1904 case CREATE_BLOCK_DEVICE
: {
1905 unsigned major
, minor
;
1908 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1912 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1913 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1917 i
.major_minor
= makedev(major
, minor
);
1922 case RECURSIVE_SET_XATTR
:
1924 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1927 r
= parse_xattrs_from_arg(&i
);
1933 case RECURSIVE_SET_ACL
:
1935 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
1938 r
= parse_acls_from_arg(&i
);
1944 case RECURSIVE_SET_ATTRIBUTE
:
1946 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
1949 r
= parse_attribute_from_arg(&i
);
1955 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
1959 if (!path_is_absolute(i
.path
)) {
1960 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
1964 path_kill_slashes(i
.path
);
1966 if (!should_include_path(i
.path
))
1972 p
= prefix_root(arg_root
, i
.path
);
1980 if (!isempty(user
) && !streq(user
, "-")) {
1981 const char *u
= user
;
1983 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
1985 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
1992 if (!isempty(group
) && !streq(group
, "-")) {
1993 const char *g
= group
;
1995 r
= get_group_creds(&g
, &i
.gid
);
1997 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2004 if (!isempty(mode
) && !streq(mode
, "-")) {
2005 const char *mm
= mode
;
2009 i
.mask_perms
= true;
2013 if (parse_mode(mm
, &m
) < 0) {
2014 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2021 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2023 if (!isempty(age
) && !streq(age
, "-")) {
2024 const char *a
= age
;
2027 i
.keep_first_level
= true;
2031 if (parse_sec(a
, &i
.age
) < 0) {
2032 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2039 h
= needs_glob(i
.type
) ? globs
: items
;
2041 existing
= ordered_hashmap_get(h
, i
.path
);
2045 for (n
= 0; n
< existing
->count
; n
++) {
2046 if (!item_compatible(existing
->items
+ n
, &i
)) {
2047 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2048 fname
, line
, i
.path
);
2053 existing
= new0(ItemArray
, 1);
2054 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2059 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2062 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2064 /* Sort item array, to enforce stable ordering of application */
2065 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2071 static void help(void) {
2072 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2073 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2074 " -h --help Show this help\n"
2075 " --version Show package version\n"
2076 " --create Create marked files/directories\n"
2077 " --clean Clean up marked directories\n"
2078 " --remove Remove marked files/directories\n"
2079 " --boot Execute actions only safe at boot\n"
2080 " --prefix=PATH Only apply rules with the specified prefix\n"
2081 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2082 " --root=PATH Operate on an alternate filesystem root\n",
2083 program_invocation_short_name
);
2086 static int parse_argv(int argc
, char *argv
[]) {
2089 ARG_VERSION
= 0x100,
2099 static const struct option options
[] = {
2100 { "help", no_argument
, NULL
, 'h' },
2101 { "version", no_argument
, NULL
, ARG_VERSION
},
2102 { "create", no_argument
, NULL
, ARG_CREATE
},
2103 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2104 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2105 { "boot", no_argument
, NULL
, ARG_BOOT
},
2106 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2107 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2108 { "root", required_argument
, NULL
, ARG_ROOT
},
2117 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2145 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2149 case ARG_EXCLUDE_PREFIX
:
2150 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2155 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2164 assert_not_reached("Unhandled option");
2167 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2168 log_error("You need to specify at least one of --clean, --create or --remove.");
2175 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2176 _cleanup_fclose_
FILE *f
= NULL
;
2177 char line
[LINE_MAX
];
2185 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &f
);
2187 if (ignore_enoent
&& r
== -ENOENT
) {
2188 log_debug_errno(r
, "Failed to open \"%s\": %m", fn
);
2192 return log_error_errno(r
, "Failed to open '%s', ignoring: %m", fn
);
2194 log_debug("Reading config file \"%s\".", fn
);
2196 FOREACH_LINE(line
, f
, break) {
2203 if (*l
== '#' || *l
== 0)
2206 k
= parse_line(fn
, v
, l
);
2207 if (k
< 0 && r
== 0)
2211 /* we have to determine age parameter for each entry of type X */
2212 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2214 Item
*j
, *candidate_item
= NULL
;
2216 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2219 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2220 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2223 if (path_equal(j
->path
, i
->path
)) {
2228 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2229 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2233 if (candidate_item
&& candidate_item
->age_set
) {
2234 i
->age
= candidate_item
->age
;
2240 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2248 int main(int argc
, char *argv
[]) {
2253 r
= parse_argv(argc
, argv
);
2257 log_set_target(LOG_TARGET_AUTO
);
2258 log_parse_environment();
2263 mac_selinux_init(NULL
);
2265 items
= ordered_hashmap_new(&string_hash_ops
);
2266 globs
= ordered_hashmap_new(&string_hash_ops
);
2268 if (!items
|| !globs
) {
2275 if (optind
< argc
) {
2278 for (j
= optind
; j
< argc
; j
++) {
2279 k
= read_config_file(argv
[j
], false);
2280 if (k
< 0 && r
== 0)
2285 _cleanup_strv_free_
char **files
= NULL
;
2288 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, conf_file_dirs
);
2290 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2294 STRV_FOREACH(f
, files
) {
2295 k
= read_config_file(*f
, true);
2296 if (k
< 0 && r
== 0)
2301 /* The non-globbing ones usually create things, hence we apply
2303 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2304 k
= process_item_array(a
);
2305 if (k
< 0 && r
== 0)
2309 /* The globbing ones usually alter things, hence we apply them
2311 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2312 k
= process_item_array(a
);
2313 if (k
< 0 && r
== 0)
2318 while ((a
= ordered_hashmap_steal_first(items
)))
2321 while ((a
= ordered_hashmap_steal_first(globs
)))
2324 ordered_hashmap_free(items
);
2325 ordered_hashmap_free(globs
);
2327 free(arg_include_prefixes
);
2328 free(arg_exclude_prefixes
);
2331 set_free_free(unix_sockets
);
2333 mac_selinux_finish();
2335 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;