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-util.h"
44 #include "chattr-util.h"
45 #include "conf-files.h"
50 #include "formats-util.h"
58 #include "parse-util.h"
59 #include "path-util.h"
61 #include "selinux-util.h"
63 #include "specifier.h"
64 #include "stat-util.h"
65 #include "string-table.h"
66 #include "string-util.h"
68 #include "umask-util.h"
69 #include "user-util.h"
72 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
73 * them in the file system. This is intended to be used to create
74 * properly owned directories beneath /tmp, /var/tmp, /run, which are
75 * volatile and hence need to be recreated on bootup. */
77 typedef enum ItemType
{
78 /* These ones take file names */
81 CREATE_DIRECTORY
= 'd',
82 TRUNCATE_DIRECTORY
= 'D',
83 CREATE_SUBVOLUME
= 'v',
84 CREATE_SUBVOLUME_INHERIT_QUOTA
= 'q',
85 CREATE_SUBVOLUME_NEW_QUOTA
= 'Q',
88 CREATE_CHAR_DEVICE
= 'c',
89 CREATE_BLOCK_DEVICE
= 'b',
92 /* These ones take globs */
95 RECURSIVE_SET_XATTR
= 'T',
97 RECURSIVE_SET_ACL
= 'A',
99 RECURSIVE_SET_ATTRIBUTE
= 'H',
101 IGNORE_DIRECTORY_PATH
= 'X',
103 RECURSIVE_REMOVE_PATH
= 'R',
105 RECURSIVE_RELABEL_PATH
= 'Z',
106 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
109 typedef struct Item
{
125 unsigned attribute_value
;
126 unsigned attribute_mask
;
133 bool attribute_set
:1;
135 bool keep_first_level
:1;
142 typedef struct ItemArray
{
148 static bool arg_create
= false;
149 static bool arg_clean
= false;
150 static bool arg_remove
= false;
151 static bool arg_boot
= false;
153 static char **arg_include_prefixes
= NULL
;
154 static char **arg_exclude_prefixes
= NULL
;
155 static char *arg_root
= NULL
;
157 static const char conf_file_dirs
[] = CONF_DIRS_NULSTR("tmpfiles");
159 #define MAX_DEPTH 256
161 static OrderedHashmap
*items
= NULL
, *globs
= NULL
;
162 static Set
*unix_sockets
= NULL
;
164 static const Specifier specifier_table
[] = {
165 { 'm', specifier_machine_id
, NULL
},
166 { 'b', specifier_boot_id
, NULL
},
167 { 'H', specifier_host_name
, NULL
},
168 { 'v', specifier_kernel_release
, NULL
},
172 static bool needs_glob(ItemType t
) {
176 IGNORE_DIRECTORY_PATH
,
178 RECURSIVE_REMOVE_PATH
,
181 RECURSIVE_RELABEL_PATH
,
187 RECURSIVE_SET_ATTRIBUTE
);
190 static bool takes_ownership(ItemType t
) {
197 CREATE_SUBVOLUME_INHERIT_QUOTA
,
198 CREATE_SUBVOLUME_NEW_QUOTA
,
206 IGNORE_DIRECTORY_PATH
,
208 RECURSIVE_REMOVE_PATH
);
211 static struct Item
* find_glob(OrderedHashmap
*h
, const char *match
) {
215 ORDERED_HASHMAP_FOREACH(j
, h
, i
) {
218 for (n
= 0; n
< j
->count
; n
++) {
219 Item
*item
= j
->items
+ n
;
221 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
229 static void load_unix_sockets(void) {
230 _cleanup_fclose_
FILE *f
= NULL
;
236 /* We maintain a cache of the sockets we found in
237 * /proc/net/unix to speed things up a little. */
239 unix_sockets
= set_new(&string_hash_ops
);
243 f
= fopen("/proc/net/unix", "re");
248 if (!fgets(line
, sizeof(line
), f
))
255 if (!fgets(line
, sizeof(line
), f
))
260 p
= strchr(line
, ':');
268 p
+= strspn(p
, WHITESPACE
);
269 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
270 p
+= strspn(p
, WHITESPACE
);
279 path_kill_slashes(s
);
281 k
= set_consume(unix_sockets
, s
);
282 if (k
< 0 && k
!= -EEXIST
)
289 set_free_free(unix_sockets
);
293 static bool unix_socket_alive(const char *fn
) {
299 return !!set_get(unix_sockets
, (char*) fn
);
301 /* We don't know, so assume yes */
305 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
307 union file_handle_union h
= FILE_HANDLE_INIT
;
308 int mount_id_parent
, mount_id
;
311 r_p
= name_to_handle_at(dirfd(d
), ".", &h
.handle
, &mount_id_parent
, 0);
315 h
.handle
.handle_bytes
= MAX_HANDLE_SZ
;
316 r
= name_to_handle_at(dirfd(d
), subdir
, &h
.handle
, &mount_id
, 0);
320 /* got no handle; make no assumptions, return error */
321 if (r_p
< 0 && r
< 0)
324 /* got both handles; if they differ, it is a mount point */
325 if (r_p
>= 0 && r
>= 0)
326 return mount_id_parent
!= mount_id
;
328 /* got only one handle; assume different mount points if one
329 * of both queries was not supported by the filesystem */
330 if (r_p
== -ENOSYS
|| r_p
== -EOPNOTSUPP
|| r
== -ENOSYS
|| r
== -EOPNOTSUPP
)
339 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
342 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
346 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
350 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
352 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
357 static DIR* opendir_nomod(const char *path
) {
358 return xopendirat_nomod(AT_FDCWD
, path
);
361 static int dir_cleanup(
365 const struct stat
*ds
,
370 bool keep_this_level
) {
373 struct timespec times
[2];
374 bool deleted
= false;
377 while ((dent
= readdir(d
))) {
380 _cleanup_free_
char *sub_path
= NULL
;
382 if (STR_IN_SET(dent
->d_name
, ".", ".."))
385 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
389 /* FUSE, NFS mounts, SELinux might return EACCES */
391 log_debug_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
393 log_error_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
398 /* Stay on the same filesystem */
399 if (s
.st_dev
!= rootdev
) {
400 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
404 /* Try to detect bind mounts of the same filesystem instance; they
405 * do not differ in device major/minors. This type of query is not
406 * supported on all kernels or filesystem types though. */
407 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
408 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
413 /* Do not delete read-only files owned by root */
414 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
)) {
415 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p
, dent
->d_name
);
419 sub_path
= strjoin(p
, "/", dent
->d_name
, NULL
);
425 /* Is there an item configured for this path? */
426 if (ordered_hashmap_get(items
, sub_path
)) {
427 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
431 if (find_glob(globs
, sub_path
)) {
432 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
436 if (S_ISDIR(s
.st_mode
)) {
439 streq(dent
->d_name
, "lost+found") &&
441 log_debug("Ignoring \"%s\".", sub_path
);
446 log_warning("Reached max depth on \"%s\".", sub_path
);
448 _cleanup_closedir_
DIR *sub_dir
;
451 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
454 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
459 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
464 /* Note: if you are wondering why we don't
465 * support the sticky bit for excluding
466 * directories from cleaning like we do it for
467 * other file system objects: well, the sticky
468 * bit already has a meaning for directories,
469 * so we don't want to overload that. */
471 if (keep_this_level
) {
472 log_debug("Keeping \"%s\".", sub_path
);
476 /* Ignore ctime, we change it when deleting */
477 age
= timespec_load(&s
.st_mtim
);
479 char a
[FORMAT_TIMESTAMP_MAX
];
480 /* Follows spelling in stat(1). */
481 log_debug("Directory \"%s\": modify time %s is too new.",
483 format_timestamp_us(a
, sizeof(a
), age
));
487 age
= timespec_load(&s
.st_atim
);
489 char a
[FORMAT_TIMESTAMP_MAX
];
490 log_debug("Directory \"%s\": access time %s is too new.",
492 format_timestamp_us(a
, sizeof(a
), age
));
496 log_debug("Removing directory \"%s\".", sub_path
);
497 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
498 if (errno
!= ENOENT
&& errno
!= ENOTEMPTY
) {
499 log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
504 /* Skip files for which the sticky bit is
505 * set. These are semantics we define, and are
506 * unknown elsewhere. See XDG_RUNTIME_DIR
507 * specification for details. */
508 if (s
.st_mode
& S_ISVTX
) {
509 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
513 if (mountpoint
&& S_ISREG(s
.st_mode
))
514 if (s
.st_uid
== 0 && STR_IN_SET(dent
->d_name
,
518 log_debug("Skipping \"%s\".", sub_path
);
522 /* Ignore sockets that are listed in /proc/net/unix */
523 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
524 log_debug("Skipping \"%s\": live socket.", sub_path
);
528 /* Ignore device nodes */
529 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
530 log_debug("Skipping \"%s\": a device.", sub_path
);
534 /* Keep files on this level around if this is
536 if (keep_this_level
) {
537 log_debug("Keeping \"%s\".", sub_path
);
541 age
= timespec_load(&s
.st_mtim
);
543 char a
[FORMAT_TIMESTAMP_MAX
];
544 /* Follows spelling in stat(1). */
545 log_debug("File \"%s\": modify time %s is too new.",
547 format_timestamp_us(a
, sizeof(a
), age
));
551 age
= timespec_load(&s
.st_atim
);
553 char a
[FORMAT_TIMESTAMP_MAX
];
554 log_debug("File \"%s\": access time %s is too new.",
556 format_timestamp_us(a
, sizeof(a
), age
));
560 age
= timespec_load(&s
.st_ctim
);
562 char a
[FORMAT_TIMESTAMP_MAX
];
563 log_debug("File \"%s\": change time %s is too new.",
565 format_timestamp_us(a
, sizeof(a
), age
));
569 log_debug("unlink \"%s\"", sub_path
);
571 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
573 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
582 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
584 /* Restore original directory timestamps */
585 times
[0] = ds
->st_atim
;
586 times
[1] = ds
->st_mtim
;
588 age1
= timespec_load(&ds
->st_atim
);
589 age2
= timespec_load(&ds
->st_mtim
);
590 log_debug("Restoring access and modification time on \"%s\": %s, %s",
592 format_timestamp_us(a
, sizeof(a
), age1
),
593 format_timestamp_us(b
, sizeof(b
), age2
));
594 if (futimens(dirfd(d
), times
) < 0)
595 log_error_errno(errno
, "utimensat(%s): %m", p
);
601 static int path_set_perms(Item
*i
, const char *path
) {
602 _cleanup_close_
int fd
= -1;
608 /* We open the file with O_PATH here, to make the operation
609 * somewhat atomic. Also there's unfortunately no fchmodat()
610 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
613 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
615 return log_error_errno(errno
, "Adjusting owner and mode for %s failed: %m", path
);
617 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
618 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
620 if (S_ISLNK(st
.st_mode
))
621 log_debug("Skipping mode an owner fix for symlink %s.", path
);
623 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
624 xsprintf(fn
, "/proc/self/fd/%i", fd
);
626 /* not using i->path directly because it may be a glob */
631 if (!(st
.st_mode
& 0111))
633 if (!(st
.st_mode
& 0222))
635 if (!(st
.st_mode
& 0444))
637 if (!S_ISDIR(st
.st_mode
))
638 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
641 if (m
== (st
.st_mode
& 07777))
642 log_debug("\"%s\" has right mode %o", path
, st
.st_mode
);
644 log_debug("chmod \"%s\" to mode %o", path
, m
);
645 if (chmod(fn
, m
) < 0)
646 return log_error_errno(errno
, "chmod(%s) failed: %m", path
);
650 if ((i
->uid
!= st
.st_uid
|| i
->gid
!= st
.st_gid
) &&
651 (i
->uid_set
|| i
->gid_set
)) {
652 log_debug("chown \"%s\" to "UID_FMT
"."GID_FMT
,
654 i
->uid_set
? i
->uid
: UID_INVALID
,
655 i
->gid_set
? i
->gid
: GID_INVALID
);
657 i
->uid_set
? i
->uid
: UID_INVALID
,
658 i
->gid_set
? i
->gid
: GID_INVALID
) < 0)
659 return log_error_errno(errno
, "chown(%s) failed: %m", path
);
665 return label_fix(path
, false, false);
668 static int parse_xattrs_from_arg(Item
*i
) {
678 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
, *xattr_replaced
= NULL
;
680 r
= extract_first_word(&p
, &xattr
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
682 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
686 r
= specifier_printf(xattr
, specifier_table
, NULL
, &xattr_replaced
);
688 return log_error_errno(r
, "Failed to replace specifiers in extended attribute '%s': %m", xattr
);
690 r
= split_pair(xattr_replaced
, "=", &name
, &value
);
692 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
696 if (isempty(name
) || isempty(value
)) {
697 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
701 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
710 static int path_set_xattrs(Item
*i
, const char *path
) {
711 char **name
, **value
;
716 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
720 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
721 if (lsetxattr(path
, *name
, *value
, n
, 0) < 0) {
722 log_error("Setting extended attribute %s=%s on %s failed: %m", *name
, *value
, path
);
729 static int parse_acls_from_arg(Item
*item
) {
735 /* If force (= modify) is set, we will not modify the acl
736 * afterwards, so the mask can be added now if necessary. */
738 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
740 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
742 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
749 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
750 _cleanup_(acl_free_charpp
) char *t
= NULL
;
751 _cleanup_(acl_freep
) acl_t dup
= NULL
;
754 /* Returns 0 for success, positive error if already warned,
755 * negative error otherwise. */
758 r
= acls_for_file(path
, type
, acl
, &dup
);
762 r
= calc_acl_mask_if_needed(&dup
);
770 /* the mask was already added earlier if needed */
773 r
= add_base_acls_if_needed(&dup
, path
);
777 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
778 log_debug("Setting %s ACL %s on %s.",
779 type
== ACL_TYPE_ACCESS
? "access" : "default",
782 r
= acl_set_file(path
, type
, dup
);
784 /* Return positive to indicate we already warned */
785 return -log_error_errno(errno
,
786 "Setting %s ACL \"%s\" on %s failed: %m",
787 type
== ACL_TYPE_ACCESS
? "access" : "default",
794 static int path_set_acls(Item
*item
, const char *path
) {
797 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
798 _cleanup_close_
int fd
= -1;
804 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
806 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
808 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
809 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
811 if (S_ISLNK(st
.st_mode
)) {
812 log_debug("Skipping ACL fix for symlink %s.", path
);
816 xsprintf(fn
, "/proc/self/fd/%i", fd
);
818 if (item
->acl_access
)
819 r
= path_set_acl(fn
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
821 if (r
== 0 && item
->acl_default
)
822 r
= path_set_acl(fn
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
825 return -r
; /* already warned */
826 else if (r
== -EOPNOTSUPP
) {
827 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
830 log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
835 #define ATTRIBUTES_ALL \
844 FS_JOURNAL_DATA_FL | \
851 static int parse_attribute_from_arg(Item
*item
) {
853 static const struct {
857 { 'A', FS_NOATIME_FL
}, /* do not update atime */
858 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
859 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
860 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
861 { 'c', FS_COMPR_FL
}, /* Compress file */
862 { 'd', FS_NODUMP_FL
}, /* do not dump file */
863 { 'e', FS_EXTENT_FL
}, /* Top of directory hierarchies*/
864 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
865 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
866 { 's', FS_SECRM_FL
}, /* Secure deletion */
867 { 'u', FS_UNRM_FL
}, /* Undelete */
868 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
869 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies*/
870 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
879 unsigned value
= 0, mask
= 0;
889 } else if (*p
== '-') {
892 } else if (*p
== '=') {
898 if (isempty(p
) && mode
!= MODE_SET
) {
899 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
903 for (; p
&& *p
; p
++) {
906 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
907 if (*p
== attributes
[i
].character
)
910 if (i
>= ELEMENTSOF(attributes
)) {
911 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
915 v
= attributes
[i
].value
;
917 if (mode
== MODE_ADD
|| mode
== MODE_SET
)
925 if (mode
== MODE_SET
)
926 mask
|= ATTRIBUTES_ALL
;
930 item
->attribute_mask
= mask
;
931 item
->attribute_value
= value
;
932 item
->attribute_set
= true;
937 static int path_set_attribute(Item
*item
, const char *path
) {
938 _cleanup_close_
int fd
= -1;
943 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
946 fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
|O_NOATIME
|O_NOFOLLOW
);
949 return log_error_errno(errno
, "Skipping file attributes adjustment on symlink %s.", path
);
951 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
954 if (fstat(fd
, &st
) < 0)
955 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
957 /* Issuing the file attribute ioctls on device nodes is not
958 * safe, as that will be delivered to the drivers, not the
959 * file system containing the device node. */
960 if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
)) {
961 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
965 f
= item
->attribute_value
& item
->attribute_mask
;
967 /* Mask away directory-specific flags */
968 if (!S_ISDIR(st
.st_mode
))
971 r
= chattr_fd(fd
, f
, item
->attribute_mask
);
973 log_full_errno(r
== -ENOTTY
? LOG_DEBUG
: LOG_WARNING
,
975 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
976 path
, item
->attribute_value
, item
->attribute_mask
);
981 static int write_one_file(Item
*i
, const char *path
) {
982 _cleanup_close_
int fd
= -1;
989 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
|O_NOFOLLOW
:
990 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
992 RUN_WITH_UMASK(0000) {
993 mac_selinux_create_file_prepare(path
, S_IFREG
);
994 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
995 mac_selinux_create_file_clear();
999 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
1000 log_debug_errno(errno
, "Not writing \"%s\": %m", path
);
1005 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
1006 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
1009 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1013 _cleanup_free_
char *unescaped
= NULL
, *replaced
= NULL
;
1015 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1017 r
= cunescape(i
->argument
, 0, &unescaped
);
1019 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
1021 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &replaced
);
1023 return log_error_errno(r
, "Failed to replace specifiers in parameter to write '%s': %m", unescaped
);
1025 r
= loop_write(fd
, replaced
, strlen(replaced
), false);
1027 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1029 log_debug("\"%s\" has been created.", path
);
1031 fd
= safe_close(fd
);
1033 if (stat(path
, &st
) < 0)
1034 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1037 if (!S_ISREG(st
.st_mode
)) {
1038 log_error("%s is not a file.", path
);
1042 r
= path_set_perms(i
, path
);
1049 typedef int (*action_t
)(Item
*, const char *);
1051 static int item_do_children(Item
*i
, const char *path
, action_t action
) {
1052 _cleanup_closedir_
DIR *d
;
1058 /* This returns the first error we run into, but nevertheless
1061 d
= opendir_nomod(path
);
1063 return errno
== ENOENT
|| errno
== ENOTDIR
? 0 : -errno
;
1066 _cleanup_free_
char *p
= NULL
;
1073 if (errno
!= 0 && r
== 0)
1079 if (STR_IN_SET(de
->d_name
, ".", ".."))
1082 p
= strjoin(path
, "/", de
->d_name
, NULL
);
1087 if (q
< 0 && q
!= -ENOENT
&& r
== 0)
1090 if (IN_SET(de
->d_type
, DT_UNKNOWN
, DT_DIR
)) {
1091 q
= item_do_children(i
, p
, action
);
1092 if (q
< 0 && r
== 0)
1100 static int glob_item(Item
*i
, action_t action
, bool recursive
) {
1101 _cleanup_globfree_ glob_t g
= {
1102 .gl_closedir
= (void (*)(void *)) closedir
,
1103 .gl_readdir
= (struct dirent
*(*)(void *)) readdir
,
1104 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1112 k
= glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
|GLOB_ALTDIRFUNC
, NULL
, &g
);
1113 if (k
!= 0 && k
!= GLOB_NOMATCH
)
1114 return log_error_errno(errno
?: EIO
, "glob(%s) failed: %m", i
->path
);
1116 STRV_FOREACH(fn
, g
.gl_pathv
) {
1118 if (k
< 0 && r
== 0)
1122 k
= item_do_children(i
, *fn
, action
);
1123 if (k
< 0 && r
== 0)
1136 _CREATION_MODE_INVALID
= -1
1139 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1140 [CREATION_NORMAL
] = "Created",
1141 [CREATION_EXISTING
] = "Found existing",
1142 [CREATION_FORCE
] = "Created replacement",
1145 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1147 static int create_item(Item
*i
) {
1148 _cleanup_free_
char *resolved
= NULL
;
1151 CreationMode creation
;
1155 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1160 case IGNORE_DIRECTORY_PATH
:
1162 case RECURSIVE_REMOVE_PATH
:
1167 r
= write_one_file(i
, i
->path
);
1173 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1175 return log_error_errno(r
, "Failed to substitute specifiers in copy source %s: %m", i
->argument
);
1177 log_debug("Copying tree \"%s\" to \"%s\".", resolved
, i
->path
);
1178 r
= copy_tree(resolved
, i
->path
, false);
1180 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1187 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1189 if (stat(resolved
, &a
) < 0)
1190 return log_error_errno(errno
, "stat(%s) failed: %m", resolved
);
1192 if (stat(i
->path
, &b
) < 0)
1193 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1195 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1196 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1201 r
= path_set_perms(i
, i
->path
);
1208 r
= glob_item(i
, write_one_file
, false);
1214 case CREATE_DIRECTORY
:
1215 case TRUNCATE_DIRECTORY
:
1216 case CREATE_SUBVOLUME
:
1217 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1218 case CREATE_SUBVOLUME_NEW_QUOTA
:
1220 RUN_WITH_UMASK(0000)
1221 mkdir_parents_label(i
->path
, 0755);
1223 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1224 RUN_WITH_UMASK((~i
->mode
) & 0777)
1225 r
= btrfs_subvol_make(i
->path
);
1229 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1230 RUN_WITH_UMASK(0000)
1231 r
= mkdir_label(i
->path
, i
->mode
);
1236 if (r
!= -EEXIST
&& r
!= -EROFS
)
1237 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1239 k
= is_dir(i
->path
, false);
1240 if (k
== -ENOENT
&& r
== -EROFS
)
1241 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1243 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1245 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1249 creation
= CREATION_EXISTING
;
1251 creation
= CREATION_NORMAL
;
1253 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1255 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1256 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1258 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
);
1262 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i
->path
);
1266 return log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1268 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1270 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1273 r
= path_set_perms(i
, i
->path
);
1281 RUN_WITH_UMASK(0000) {
1282 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1283 r
= mkfifo(i
->path
, i
->mode
);
1284 mac_selinux_create_file_clear();
1288 if (errno
!= EEXIST
)
1289 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1291 if (lstat(i
->path
, &st
) < 0)
1292 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1294 if (!S_ISFIFO(st
.st_mode
)) {
1297 RUN_WITH_UMASK(0000) {
1298 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1299 r
= mkfifo_atomic(i
->path
, i
->mode
);
1300 mac_selinux_create_file_clear();
1304 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1305 creation
= CREATION_FORCE
;
1307 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1311 creation
= CREATION_EXISTING
;
1313 creation
= CREATION_NORMAL
;
1314 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1316 r
= path_set_perms(i
, i
->path
);
1323 case CREATE_SYMLINK
: {
1324 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1326 return log_error_errno(r
, "Failed to substitute specifiers in symlink target %s: %m", i
->argument
);
1328 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1329 r
= symlink(resolved
, i
->path
);
1330 mac_selinux_create_file_clear();
1333 _cleanup_free_
char *x
= NULL
;
1335 if (errno
!= EEXIST
)
1336 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1338 r
= readlink_malloc(i
->path
, &x
);
1339 if (r
< 0 || !streq(resolved
, x
)) {
1342 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1343 r
= symlink_atomic(resolved
, i
->path
);
1344 mac_selinux_create_file_clear();
1347 return log_error_errno(r
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1349 creation
= CREATION_FORCE
;
1351 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1355 creation
= CREATION_EXISTING
;
1358 creation
= CREATION_NORMAL
;
1359 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1363 case CREATE_BLOCK_DEVICE
:
1364 case CREATE_CHAR_DEVICE
: {
1367 if (have_effective_cap(CAP_MKNOD
) == 0) {
1368 /* In a container we lack CAP_MKNOD. We
1369 shouldn't attempt to create the device node in
1370 that case to avoid noise, and we don't support
1371 virtualized devices in containers anyway. */
1373 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1377 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1379 RUN_WITH_UMASK(0000) {
1380 mac_selinux_create_file_prepare(i
->path
, file_type
);
1381 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1382 mac_selinux_create_file_clear();
1386 if (errno
== EPERM
) {
1387 log_debug("We lack permissions, possibly because of cgroup configuration; "
1388 "skipping creation of device node %s.", i
->path
);
1392 if (errno
!= EEXIST
)
1393 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1395 if (lstat(i
->path
, &st
) < 0)
1396 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1398 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1402 RUN_WITH_UMASK(0000) {
1403 mac_selinux_create_file_prepare(i
->path
, file_type
);
1404 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1405 mac_selinux_create_file_clear();
1409 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1410 creation
= CREATION_FORCE
;
1412 log_debug("%s is not a device node.", i
->path
);
1416 creation
= CREATION_EXISTING
;
1418 creation
= CREATION_NORMAL
;
1420 log_debug("%s %s device node \"%s\" %u:%u.",
1421 creation_mode_verb_to_string(creation
),
1422 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1423 i
->path
, major(i
->mode
), minor(i
->mode
));
1425 r
= path_set_perms(i
, i
->path
);
1434 r
= glob_item(i
, path_set_perms
, false);
1439 case RECURSIVE_RELABEL_PATH
:
1440 r
= glob_item(i
, path_set_perms
, true);
1446 r
= glob_item(i
, path_set_xattrs
, false);
1451 case RECURSIVE_SET_XATTR
:
1452 r
= glob_item(i
, path_set_xattrs
, true);
1458 r
= glob_item(i
, path_set_acls
, false);
1463 case RECURSIVE_SET_ACL
:
1464 r
= glob_item(i
, path_set_acls
, true);
1470 r
= glob_item(i
, path_set_attribute
, false);
1475 case RECURSIVE_SET_ATTRIBUTE
:
1476 r
= glob_item(i
, path_set_attribute
, true);
1485 static int remove_item_instance(Item
*i
, const char *instance
) {
1493 if (remove(instance
) < 0 && errno
!= ENOENT
)
1494 return log_error_errno(errno
, "rm(%s): %m", instance
);
1498 case TRUNCATE_DIRECTORY
:
1499 case RECURSIVE_REMOVE_PATH
:
1500 /* FIXME: we probably should use dir_cleanup() here
1501 * instead of rm_rf() so that 'x' is honoured. */
1502 log_debug("rm -rf \"%s\"", instance
);
1503 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1504 if (r
< 0 && r
!= -ENOENT
)
1505 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1510 assert_not_reached("wut?");
1516 static int remove_item(Item
*i
) {
1521 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1527 case CREATE_DIRECTORY
:
1528 case CREATE_SUBVOLUME
:
1529 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1530 case CREATE_SUBVOLUME_NEW_QUOTA
:
1532 case CREATE_SYMLINK
:
1533 case CREATE_CHAR_DEVICE
:
1534 case CREATE_BLOCK_DEVICE
:
1536 case IGNORE_DIRECTORY_PATH
:
1539 case RECURSIVE_RELABEL_PATH
:
1543 case RECURSIVE_SET_XATTR
:
1545 case RECURSIVE_SET_ACL
:
1547 case RECURSIVE_SET_ATTRIBUTE
:
1551 case TRUNCATE_DIRECTORY
:
1552 case RECURSIVE_REMOVE_PATH
:
1553 r
= glob_item(i
, remove_item_instance
, false);
1560 static int clean_item_instance(Item
*i
, const char* instance
) {
1561 _cleanup_closedir_
DIR *d
= NULL
;
1565 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1572 n
= now(CLOCK_REALTIME
);
1576 cutoff
= n
- i
->age
;
1578 d
= opendir_nomod(instance
);
1580 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
1581 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1585 log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1589 if (fstat(dirfd(d
), &s
) < 0)
1590 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1592 if (!S_ISDIR(s
.st_mode
)) {
1593 log_error("%s is not a directory.", i
->path
);
1597 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1598 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1600 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1602 log_debug("Cleanup threshold for %s \"%s\" is %s",
1603 mountpoint
? "mount point" : "directory",
1605 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1607 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1608 MAX_DEPTH
, i
->keep_first_level
);
1611 static int clean_item(Item
*i
) {
1616 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1619 case CREATE_DIRECTORY
:
1620 case CREATE_SUBVOLUME
:
1621 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1622 case CREATE_SUBVOLUME_NEW_QUOTA
:
1623 case TRUNCATE_DIRECTORY
:
1626 clean_item_instance(i
, i
->path
);
1628 case IGNORE_DIRECTORY_PATH
:
1629 r
= glob_item(i
, clean_item_instance
, false);
1638 static int process_item_array(ItemArray
*array
);
1640 static int process_item(Item
*i
) {
1642 _cleanup_free_
char *prefix
= NULL
;
1651 prefix
= malloc(strlen(i
->path
) + 1);
1655 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1658 j
= ordered_hashmap_get(items
, prefix
);
1662 s
= process_item_array(j
);
1663 if (s
< 0 && t
== 0)
1668 r
= arg_create
? create_item(i
) : 0;
1669 q
= arg_remove
? remove_item(i
) : 0;
1670 p
= arg_clean
? clean_item(i
) : 0;
1678 static int process_item_array(ItemArray
*array
) {
1684 for (n
= 0; n
< array
->count
; n
++) {
1685 k
= process_item(array
->items
+ n
);
1686 if (k
< 0 && r
== 0)
1693 static void item_free_contents(Item
*i
) {
1697 strv_free(i
->xattrs
);
1700 acl_free(i
->acl_access
);
1701 acl_free(i
->acl_default
);
1705 static void item_array_free(ItemArray
*a
) {
1711 for (n
= 0; n
< a
->count
; n
++)
1712 item_free_contents(a
->items
+ n
);
1717 static int item_compare(const void *a
, const void *b
) {
1718 const Item
*x
= a
, *y
= b
;
1720 /* Make sure that the ownership taking item is put first, so
1721 * that we first create the node, and then can adjust it */
1723 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1725 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1728 return (int) x
->type
- (int) y
->type
;
1731 static bool item_compatible(Item
*a
, Item
*b
) {
1734 assert(streq(a
->path
, b
->path
));
1736 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1737 /* check if the items are the same */
1738 return streq_ptr(a
->argument
, b
->argument
) &&
1740 a
->uid_set
== b
->uid_set
&&
1743 a
->gid_set
== b
->gid_set
&&
1746 a
->mode_set
== b
->mode_set
&&
1747 a
->mode
== b
->mode
&&
1749 a
->age_set
== b
->age_set
&&
1752 a
->mask_perms
== b
->mask_perms
&&
1754 a
->keep_first_level
== b
->keep_first_level
&&
1756 a
->major_minor
== b
->major_minor
;
1761 static bool should_include_path(const char *path
) {
1764 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1765 if (path_startswith(path
, *prefix
)) {
1766 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1771 STRV_FOREACH(prefix
, arg_include_prefixes
)
1772 if (path_startswith(path
, *prefix
)) {
1773 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1777 /* no matches, so we should include this path only if we
1778 * have no whitelist at all */
1779 if (strv_length(arg_include_prefixes
) == 0)
1782 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1786 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1788 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1789 _cleanup_(item_free_contents
) Item i
= {};
1790 ItemArray
*existing
;
1793 bool force
= false, boot
= false;
1799 r
= extract_many_words(
1811 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1813 log_error("[%s:%u] Syntax error.", fname
, line
);
1817 if (!isempty(buffer
) && !streq(buffer
, "-")) {
1818 i
.argument
= strdup(buffer
);
1823 if (isempty(action
)) {
1824 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1828 for (pos
= 1; action
[pos
]; pos
++) {
1829 if (action
[pos
] == '!' && !boot
)
1831 else if (action
[pos
] == '+' && !force
)
1834 log_error("[%s:%u] Unknown modifiers in command '%s'",
1835 fname
, line
, action
);
1840 if (boot
&& !arg_boot
) {
1841 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1849 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1851 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1857 case CREATE_DIRECTORY
:
1858 case CREATE_SUBVOLUME
:
1859 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1860 case CREATE_SUBVOLUME_NEW_QUOTA
:
1861 case TRUNCATE_DIRECTORY
:
1864 case IGNORE_DIRECTORY_PATH
:
1866 case RECURSIVE_REMOVE_PATH
:
1869 case RECURSIVE_RELABEL_PATH
:
1871 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
1879 case CREATE_SYMLINK
:
1881 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1889 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1896 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1899 } else if (!path_is_absolute(i
.argument
)) {
1900 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1904 path_kill_slashes(i
.argument
);
1907 case CREATE_CHAR_DEVICE
:
1908 case CREATE_BLOCK_DEVICE
: {
1909 unsigned major
, minor
;
1912 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1916 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1917 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1921 i
.major_minor
= makedev(major
, minor
);
1926 case RECURSIVE_SET_XATTR
:
1928 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1931 r
= parse_xattrs_from_arg(&i
);
1937 case RECURSIVE_SET_ACL
:
1939 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
1942 r
= parse_acls_from_arg(&i
);
1948 case RECURSIVE_SET_ATTRIBUTE
:
1950 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
1953 r
= parse_attribute_from_arg(&i
);
1959 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
1963 if (!path_is_absolute(i
.path
)) {
1964 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
1968 path_kill_slashes(i
.path
);
1970 if (!should_include_path(i
.path
))
1976 p
= prefix_root(arg_root
, i
.path
);
1984 if (!isempty(user
) && !streq(user
, "-")) {
1985 const char *u
= user
;
1987 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
1989 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
1996 if (!isempty(group
) && !streq(group
, "-")) {
1997 const char *g
= group
;
1999 r
= get_group_creds(&g
, &i
.gid
);
2001 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2008 if (!isempty(mode
) && !streq(mode
, "-")) {
2009 const char *mm
= mode
;
2013 i
.mask_perms
= true;
2017 if (parse_mode(mm
, &m
) < 0) {
2018 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2025 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2027 if (!isempty(age
) && !streq(age
, "-")) {
2028 const char *a
= age
;
2031 i
.keep_first_level
= true;
2035 if (parse_sec(a
, &i
.age
) < 0) {
2036 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2043 h
= needs_glob(i
.type
) ? globs
: items
;
2045 existing
= ordered_hashmap_get(h
, i
.path
);
2049 for (n
= 0; n
< existing
->count
; n
++) {
2050 if (!item_compatible(existing
->items
+ n
, &i
)) {
2051 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2052 fname
, line
, i
.path
);
2057 existing
= new0(ItemArray
, 1);
2058 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2063 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2066 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2068 /* Sort item array, to enforce stable ordering of application */
2069 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2075 static void help(void) {
2076 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2077 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2078 " -h --help Show this help\n"
2079 " --version Show package version\n"
2080 " --create Create marked files/directories\n"
2081 " --clean Clean up marked directories\n"
2082 " --remove Remove marked files/directories\n"
2083 " --boot Execute actions only safe at boot\n"
2084 " --prefix=PATH Only apply rules with the specified prefix\n"
2085 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2086 " --root=PATH Operate on an alternate filesystem root\n",
2087 program_invocation_short_name
);
2090 static int parse_argv(int argc
, char *argv
[]) {
2093 ARG_VERSION
= 0x100,
2103 static const struct option options
[] = {
2104 { "help", no_argument
, NULL
, 'h' },
2105 { "version", no_argument
, NULL
, ARG_VERSION
},
2106 { "create", no_argument
, NULL
, ARG_CREATE
},
2107 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2108 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2109 { "boot", no_argument
, NULL
, ARG_BOOT
},
2110 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2111 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2112 { "root", required_argument
, NULL
, ARG_ROOT
},
2121 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2149 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2153 case ARG_EXCLUDE_PREFIX
:
2154 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2159 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2168 assert_not_reached("Unhandled option");
2171 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2172 log_error("You need to specify at least one of --clean, --create or --remove.");
2179 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2180 _cleanup_fclose_
FILE *f
= NULL
;
2181 char line
[LINE_MAX
];
2189 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &f
);
2191 if (ignore_enoent
&& r
== -ENOENT
) {
2192 log_debug_errno(r
, "Failed to open \"%s\": %m", fn
);
2196 return log_error_errno(r
, "Failed to open '%s', ignoring: %m", fn
);
2198 log_debug("Reading config file \"%s\".", fn
);
2200 FOREACH_LINE(line
, f
, break) {
2207 if (*l
== '#' || *l
== 0)
2210 k
= parse_line(fn
, v
, l
);
2211 if (k
< 0 && r
== 0)
2215 /* we have to determine age parameter for each entry of type X */
2216 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2218 Item
*j
, *candidate_item
= NULL
;
2220 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2223 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2224 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2227 if (path_equal(j
->path
, i
->path
)) {
2232 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2233 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2237 if (candidate_item
&& candidate_item
->age_set
) {
2238 i
->age
= candidate_item
->age
;
2244 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2252 int main(int argc
, char *argv
[]) {
2257 r
= parse_argv(argc
, argv
);
2261 log_set_target(LOG_TARGET_AUTO
);
2262 log_parse_environment();
2267 mac_selinux_init(NULL
);
2269 items
= ordered_hashmap_new(&string_hash_ops
);
2270 globs
= ordered_hashmap_new(&string_hash_ops
);
2272 if (!items
|| !globs
) {
2279 if (optind
< argc
) {
2282 for (j
= optind
; j
< argc
; j
++) {
2283 k
= read_config_file(argv
[j
], false);
2284 if (k
< 0 && r
== 0)
2289 _cleanup_strv_free_
char **files
= NULL
;
2292 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, conf_file_dirs
);
2294 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2298 STRV_FOREACH(f
, files
) {
2299 k
= read_config_file(*f
, true);
2300 if (k
< 0 && r
== 0)
2305 /* The non-globbing ones usually create things, hence we apply
2307 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2308 k
= process_item_array(a
);
2309 if (k
< 0 && r
== 0)
2313 /* The globbing ones usually alter things, hence we apply them
2315 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2316 k
= process_item_array(a
);
2317 if (k
< 0 && r
== 0)
2322 while ((a
= ordered_hashmap_steal_first(items
)))
2325 while ((a
= ordered_hashmap_steal_first(globs
)))
2328 ordered_hashmap_free(items
);
2329 ordered_hashmap_free(globs
);
2331 free(arg_include_prefixes
);
2332 free(arg_exclude_prefixes
);
2335 set_free_free(unix_sockets
);
2337 mac_selinux_finish();
2339 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;