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 "conf-files.h"
48 #include "formats-util.h"
54 #include "path-util.h"
56 #include "selinux-util.h"
58 #include "specifier.h"
59 #include "string-util.h"
63 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
64 * them in the file system. This is intended to be used to create
65 * properly owned directories beneath /tmp, /var/tmp, /run, which are
66 * volatile and hence need to be recreated on bootup. */
68 typedef enum ItemType
{
69 /* These ones take file names */
72 CREATE_DIRECTORY
= 'd',
73 TRUNCATE_DIRECTORY
= 'D',
74 CREATE_SUBVOLUME
= 'v',
75 CREATE_SUBVOLUME_INHERIT_QUOTA
= 'q',
76 CREATE_SUBVOLUME_NEW_QUOTA
= 'Q',
79 CREATE_CHAR_DEVICE
= 'c',
80 CREATE_BLOCK_DEVICE
= 'b',
83 /* These ones take globs */
86 RECURSIVE_SET_XATTR
= 'T',
88 RECURSIVE_SET_ACL
= 'A',
90 RECURSIVE_SET_ATTRIBUTE
= 'H',
92 IGNORE_DIRECTORY_PATH
= 'X',
94 RECURSIVE_REMOVE_PATH
= 'R',
96 RECURSIVE_RELABEL_PATH
= 'Z',
97 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
100 typedef struct Item
{
116 unsigned attribute_value
;
117 unsigned attribute_mask
;
124 bool attribute_set
:1;
126 bool keep_first_level
:1;
133 typedef struct ItemArray
{
139 static bool arg_create
= false;
140 static bool arg_clean
= false;
141 static bool arg_remove
= false;
142 static bool arg_boot
= false;
144 static char **arg_include_prefixes
= NULL
;
145 static char **arg_exclude_prefixes
= NULL
;
146 static char *arg_root
= NULL
;
148 static const char conf_file_dirs
[] = CONF_DIRS_NULSTR("tmpfiles");
150 #define MAX_DEPTH 256
152 static OrderedHashmap
*items
= NULL
, *globs
= NULL
;
153 static Set
*unix_sockets
= NULL
;
155 static const Specifier specifier_table
[] = {
156 { 'm', specifier_machine_id
, NULL
},
157 { 'b', specifier_boot_id
, NULL
},
158 { 'H', specifier_host_name
, NULL
},
159 { 'v', specifier_kernel_release
, NULL
},
163 static bool needs_glob(ItemType t
) {
167 IGNORE_DIRECTORY_PATH
,
169 RECURSIVE_REMOVE_PATH
,
172 RECURSIVE_RELABEL_PATH
,
178 RECURSIVE_SET_ATTRIBUTE
);
181 static bool takes_ownership(ItemType t
) {
188 CREATE_SUBVOLUME_INHERIT_QUOTA
,
189 CREATE_SUBVOLUME_NEW_QUOTA
,
197 IGNORE_DIRECTORY_PATH
,
199 RECURSIVE_REMOVE_PATH
);
202 static struct Item
* find_glob(OrderedHashmap
*h
, const char *match
) {
206 ORDERED_HASHMAP_FOREACH(j
, h
, i
) {
209 for (n
= 0; n
< j
->count
; n
++) {
210 Item
*item
= j
->items
+ n
;
212 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
220 static void load_unix_sockets(void) {
221 _cleanup_fclose_
FILE *f
= NULL
;
227 /* We maintain a cache of the sockets we found in
228 * /proc/net/unix to speed things up a little. */
230 unix_sockets
= set_new(&string_hash_ops
);
234 f
= fopen("/proc/net/unix", "re");
239 if (!fgets(line
, sizeof(line
), f
))
246 if (!fgets(line
, sizeof(line
), f
))
251 p
= strchr(line
, ':');
259 p
+= strspn(p
, WHITESPACE
);
260 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
261 p
+= strspn(p
, WHITESPACE
);
270 path_kill_slashes(s
);
272 k
= set_consume(unix_sockets
, s
);
273 if (k
< 0 && k
!= -EEXIST
)
280 set_free_free(unix_sockets
);
284 static bool unix_socket_alive(const char *fn
) {
290 return !!set_get(unix_sockets
, (char*) fn
);
292 /* We don't know, so assume yes */
296 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
298 union file_handle_union h
= FILE_HANDLE_INIT
;
299 int mount_id_parent
, mount_id
;
302 r_p
= name_to_handle_at(dirfd(d
), ".", &h
.handle
, &mount_id_parent
, 0);
306 h
.handle
.handle_bytes
= MAX_HANDLE_SZ
;
307 r
= name_to_handle_at(dirfd(d
), subdir
, &h
.handle
, &mount_id
, 0);
311 /* got no handle; make no assumptions, return error */
312 if (r_p
< 0 && r
< 0)
315 /* got both handles; if they differ, it is a mount point */
316 if (r_p
>= 0 && r
>= 0)
317 return mount_id_parent
!= mount_id
;
319 /* got only one handle; assume different mount points if one
320 * of both queries was not supported by the filesystem */
321 if (r_p
== -ENOSYS
|| r_p
== -EOPNOTSUPP
|| r
== -ENOSYS
|| r
== -EOPNOTSUPP
)
330 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
333 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
337 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
341 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
343 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
348 static DIR* opendir_nomod(const char *path
) {
349 return xopendirat_nomod(AT_FDCWD
, path
);
352 static int dir_cleanup(
356 const struct stat
*ds
,
361 bool keep_this_level
) {
364 struct timespec times
[2];
365 bool deleted
= false;
368 while ((dent
= readdir(d
))) {
371 _cleanup_free_
char *sub_path
= NULL
;
373 if (STR_IN_SET(dent
->d_name
, ".", ".."))
376 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
380 /* FUSE, NFS mounts, SELinux might return EACCES */
382 log_debug_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
384 log_error_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
389 /* Stay on the same filesystem */
390 if (s
.st_dev
!= rootdev
) {
391 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
395 /* Try to detect bind mounts of the same filesystem instance; they
396 * do not differ in device major/minors. This type of query is not
397 * supported on all kernels or filesystem types though. */
398 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
399 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
404 /* Do not delete read-only files owned by root */
405 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
)) {
406 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p
, dent
->d_name
);
410 sub_path
= strjoin(p
, "/", dent
->d_name
, NULL
);
416 /* Is there an item configured for this path? */
417 if (ordered_hashmap_get(items
, sub_path
)) {
418 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
422 if (find_glob(globs
, sub_path
)) {
423 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
427 if (S_ISDIR(s
.st_mode
)) {
430 streq(dent
->d_name
, "lost+found") &&
432 log_debug("Ignoring \"%s\".", sub_path
);
437 log_warning("Reached max depth on \"%s\".", sub_path
);
439 _cleanup_closedir_
DIR *sub_dir
;
442 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
445 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
450 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
455 /* Note: if you are wondering why we don't
456 * support the sticky bit for excluding
457 * directories from cleaning like we do it for
458 * other file system objects: well, the sticky
459 * bit already has a meaning for directories,
460 * so we don't want to overload that. */
462 if (keep_this_level
) {
463 log_debug("Keeping \"%s\".", sub_path
);
467 /* Ignore ctime, we change it when deleting */
468 age
= timespec_load(&s
.st_mtim
);
470 char a
[FORMAT_TIMESTAMP_MAX
];
471 /* Follows spelling in stat(1). */
472 log_debug("Directory \"%s\": modify time %s is too new.",
474 format_timestamp_us(a
, sizeof(a
), age
));
478 age
= timespec_load(&s
.st_atim
);
480 char a
[FORMAT_TIMESTAMP_MAX
];
481 log_debug("Directory \"%s\": access time %s is too new.",
483 format_timestamp_us(a
, sizeof(a
), age
));
487 log_debug("Removing directory \"%s\".", sub_path
);
488 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
489 if (errno
!= ENOENT
&& errno
!= ENOTEMPTY
) {
490 log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
495 /* Skip files for which the sticky bit is
496 * set. These are semantics we define, and are
497 * unknown elsewhere. See XDG_RUNTIME_DIR
498 * specification for details. */
499 if (s
.st_mode
& S_ISVTX
) {
500 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
504 if (mountpoint
&& S_ISREG(s
.st_mode
))
505 if (s
.st_uid
== 0 && STR_IN_SET(dent
->d_name
,
509 log_debug("Skipping \"%s\".", sub_path
);
513 /* Ignore sockets that are listed in /proc/net/unix */
514 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
515 log_debug("Skipping \"%s\": live socket.", sub_path
);
519 /* Ignore device nodes */
520 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
521 log_debug("Skipping \"%s\": a device.", sub_path
);
525 /* Keep files on this level around if this is
527 if (keep_this_level
) {
528 log_debug("Keeping \"%s\".", sub_path
);
532 age
= timespec_load(&s
.st_mtim
);
534 char a
[FORMAT_TIMESTAMP_MAX
];
535 /* Follows spelling in stat(1). */
536 log_debug("File \"%s\": modify time %s is too new.",
538 format_timestamp_us(a
, sizeof(a
), age
));
542 age
= timespec_load(&s
.st_atim
);
544 char a
[FORMAT_TIMESTAMP_MAX
];
545 log_debug("File \"%s\": access time %s is too new.",
547 format_timestamp_us(a
, sizeof(a
), age
));
551 age
= timespec_load(&s
.st_ctim
);
553 char a
[FORMAT_TIMESTAMP_MAX
];
554 log_debug("File \"%s\": change time %s is too new.",
556 format_timestamp_us(a
, sizeof(a
), age
));
560 log_debug("unlink \"%s\"", sub_path
);
562 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
564 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
573 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
575 /* Restore original directory timestamps */
576 times
[0] = ds
->st_atim
;
577 times
[1] = ds
->st_mtim
;
579 age1
= timespec_load(&ds
->st_atim
);
580 age2
= timespec_load(&ds
->st_mtim
);
581 log_debug("Restoring access and modification time on \"%s\": %s, %s",
583 format_timestamp_us(a
, sizeof(a
), age1
),
584 format_timestamp_us(b
, sizeof(b
), age2
));
585 if (futimens(dirfd(d
), times
) < 0)
586 log_error_errno(errno
, "utimensat(%s): %m", p
);
592 static int path_set_perms(Item
*i
, const char *path
) {
593 _cleanup_close_
int fd
= -1;
599 /* We open the file with O_PATH here, to make the operation
600 * somewhat atomic. Also there's unfortunately no fchmodat()
601 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
604 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
606 return log_error_errno(errno
, "Adjusting owner and mode for %s failed: %m", path
);
608 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
609 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
611 if (S_ISLNK(st
.st_mode
))
612 log_debug("Skipping mode an owner fix for symlink %s.", path
);
614 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
615 xsprintf(fn
, "/proc/self/fd/%i", fd
);
617 /* not using i->path directly because it may be a glob */
622 if (!(st
.st_mode
& 0111))
624 if (!(st
.st_mode
& 0222))
626 if (!(st
.st_mode
& 0444))
628 if (!S_ISDIR(st
.st_mode
))
629 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
632 if (m
== (st
.st_mode
& 07777))
633 log_debug("\"%s\" has right mode %o", path
, st
.st_mode
);
635 log_debug("chmod \"%s\" to mode %o", path
, m
);
636 if (chmod(fn
, m
) < 0)
637 return log_error_errno(errno
, "chmod(%s) failed: %m", path
);
641 if ((i
->uid
!= st
.st_uid
|| i
->gid
!= st
.st_gid
) &&
642 (i
->uid_set
|| i
->gid_set
)) {
643 log_debug("chown \"%s\" to "UID_FMT
"."GID_FMT
,
645 i
->uid_set
? i
->uid
: UID_INVALID
,
646 i
->gid_set
? i
->gid
: GID_INVALID
);
648 i
->uid_set
? i
->uid
: UID_INVALID
,
649 i
->gid_set
? i
->gid
: GID_INVALID
) < 0)
650 return log_error_errno(errno
, "chown(%s) failed: %m", path
);
656 return label_fix(path
, false, false);
659 static int parse_xattrs_from_arg(Item
*i
) {
669 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
, *xattr_replaced
= NULL
;
671 r
= extract_first_word(&p
, &xattr
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
673 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
677 r
= specifier_printf(xattr
, specifier_table
, NULL
, &xattr_replaced
);
679 return log_error_errno(r
, "Failed to replace specifiers in extended attribute '%s': %m", xattr
);
681 r
= split_pair(xattr_replaced
, "=", &name
, &value
);
683 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
687 if (isempty(name
) || isempty(value
)) {
688 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
692 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
701 static int path_set_xattrs(Item
*i
, const char *path
) {
702 char **name
, **value
;
707 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
711 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
712 if (lsetxattr(path
, *name
, *value
, n
, 0) < 0) {
713 log_error("Setting extended attribute %s=%s on %s failed: %m", *name
, *value
, path
);
720 static int parse_acls_from_arg(Item
*item
) {
726 /* If force (= modify) is set, we will not modify the acl
727 * afterwards, so the mask can be added now if necessary. */
729 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
731 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
733 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
740 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
741 _cleanup_(acl_free_charpp
) char *t
= NULL
;
742 _cleanup_(acl_freep
) acl_t dup
= NULL
;
745 /* Returns 0 for success, positive error if already warned,
746 * negative error otherwise. */
749 r
= acls_for_file(path
, type
, acl
, &dup
);
753 r
= calc_acl_mask_if_needed(&dup
);
761 /* the mask was already added earlier if needed */
764 r
= add_base_acls_if_needed(&dup
, path
);
768 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
769 log_debug("Setting %s ACL %s on %s.",
770 type
== ACL_TYPE_ACCESS
? "access" : "default",
773 r
= acl_set_file(path
, type
, dup
);
775 /* Return positive to indicate we already warned */
776 return -log_error_errno(errno
,
777 "Setting %s ACL \"%s\" on %s failed: %m",
778 type
== ACL_TYPE_ACCESS
? "access" : "default",
785 static int path_set_acls(Item
*item
, const char *path
) {
788 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
789 _cleanup_close_
int fd
= -1;
795 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
797 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
799 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
800 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
802 if (S_ISLNK(st
.st_mode
)) {
803 log_debug("Skipping ACL fix for symlink %s.", path
);
807 xsprintf(fn
, "/proc/self/fd/%i", fd
);
809 if (item
->acl_access
)
810 r
= path_set_acl(fn
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
812 if (r
== 0 && item
->acl_default
)
813 r
= path_set_acl(fn
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
816 return -r
; /* already warned */
817 else if (r
== -EOPNOTSUPP
) {
818 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
821 log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
826 #define ATTRIBUTES_ALL \
835 FS_JOURNAL_DATA_FL | \
842 static int parse_attribute_from_arg(Item
*item
) {
844 static const struct {
848 { 'A', FS_NOATIME_FL
}, /* do not update atime */
849 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
850 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
851 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
852 { 'c', FS_COMPR_FL
}, /* Compress file */
853 { 'd', FS_NODUMP_FL
}, /* do not dump file */
854 { 'e', FS_EXTENT_FL
}, /* Top of directory hierarchies*/
855 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
856 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
857 { 's', FS_SECRM_FL
}, /* Secure deletion */
858 { 'u', FS_UNRM_FL
}, /* Undelete */
859 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
860 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies*/
861 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
870 unsigned value
= 0, mask
= 0;
880 } else if (*p
== '-') {
883 } else if (*p
== '=') {
889 if (isempty(p
) && mode
!= MODE_SET
) {
890 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
894 for (; p
&& *p
; p
++) {
897 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
898 if (*p
== attributes
[i
].character
)
901 if (i
>= ELEMENTSOF(attributes
)) {
902 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
906 v
= attributes
[i
].value
;
908 if (mode
== MODE_ADD
|| mode
== MODE_SET
)
916 if (mode
== MODE_SET
)
917 mask
|= ATTRIBUTES_ALL
;
921 item
->attribute_mask
= mask
;
922 item
->attribute_value
= value
;
923 item
->attribute_set
= true;
928 static int path_set_attribute(Item
*item
, const char *path
) {
929 _cleanup_close_
int fd
= -1;
934 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
937 fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
|O_NOATIME
|O_NOFOLLOW
);
940 return log_error_errno(errno
, "Skipping file attributes adjustment on symlink %s.", path
);
942 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
945 if (fstat(fd
, &st
) < 0)
946 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
948 /* Issuing the file attribute ioctls on device nodes is not
949 * safe, as that will be delivered to the drivers, not the
950 * file system containing the device node. */
951 if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
)) {
952 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
956 f
= item
->attribute_value
& item
->attribute_mask
;
958 /* Mask away directory-specific flags */
959 if (!S_ISDIR(st
.st_mode
))
962 r
= chattr_fd(fd
, f
, item
->attribute_mask
);
964 log_full_errno(r
== -ENOTTY
? LOG_DEBUG
: LOG_WARNING
,
966 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
967 path
, item
->attribute_value
, item
->attribute_mask
);
972 static int write_one_file(Item
*i
, const char *path
) {
973 _cleanup_close_
int fd
= -1;
980 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
|O_NOFOLLOW
:
981 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
983 RUN_WITH_UMASK(0000) {
984 mac_selinux_create_file_prepare(path
, S_IFREG
);
985 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
986 mac_selinux_create_file_clear();
990 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
991 log_debug_errno(errno
, "Not writing \"%s\": %m", path
);
996 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
997 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
1000 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1004 _cleanup_free_
char *unescaped
= NULL
, *replaced
= NULL
;
1006 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1008 r
= cunescape(i
->argument
, 0, &unescaped
);
1010 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
1012 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &replaced
);
1014 return log_error_errno(r
, "Failed to replace specifiers in parameter to write '%s': %m", unescaped
);
1016 r
= loop_write(fd
, replaced
, strlen(replaced
), false);
1018 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1020 log_debug("\"%s\" has been created.", path
);
1022 fd
= safe_close(fd
);
1024 if (stat(path
, &st
) < 0)
1025 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1028 if (!S_ISREG(st
.st_mode
)) {
1029 log_error("%s is not a file.", path
);
1033 r
= path_set_perms(i
, path
);
1040 typedef int (*action_t
)(Item
*, const char *);
1042 static int item_do_children(Item
*i
, const char *path
, action_t action
) {
1043 _cleanup_closedir_
DIR *d
;
1049 /* This returns the first error we run into, but nevertheless
1052 d
= opendir_nomod(path
);
1054 return errno
== ENOENT
|| errno
== ENOTDIR
? 0 : -errno
;
1057 _cleanup_free_
char *p
= NULL
;
1064 if (errno
!= 0 && r
== 0)
1070 if (STR_IN_SET(de
->d_name
, ".", ".."))
1073 p
= strjoin(path
, "/", de
->d_name
, NULL
);
1078 if (q
< 0 && q
!= -ENOENT
&& r
== 0)
1081 if (IN_SET(de
->d_type
, DT_UNKNOWN
, DT_DIR
)) {
1082 q
= item_do_children(i
, p
, action
);
1083 if (q
< 0 && r
== 0)
1091 static int glob_item(Item
*i
, action_t action
, bool recursive
) {
1092 _cleanup_globfree_ glob_t g
= {
1093 .gl_closedir
= (void (*)(void *)) closedir
,
1094 .gl_readdir
= (struct dirent
*(*)(void *)) readdir
,
1095 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1103 k
= glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
|GLOB_ALTDIRFUNC
, NULL
, &g
);
1104 if (k
!= 0 && k
!= GLOB_NOMATCH
)
1105 return log_error_errno(errno
?: EIO
, "glob(%s) failed: %m", i
->path
);
1107 STRV_FOREACH(fn
, g
.gl_pathv
) {
1109 if (k
< 0 && r
== 0)
1113 k
= item_do_children(i
, *fn
, action
);
1114 if (k
< 0 && r
== 0)
1127 _CREATION_MODE_INVALID
= -1
1130 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1131 [CREATION_NORMAL
] = "Created",
1132 [CREATION_EXISTING
] = "Found existing",
1133 [CREATION_FORCE
] = "Created replacement",
1136 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1138 static int create_item(Item
*i
) {
1139 _cleanup_free_
char *resolved
= NULL
;
1142 CreationMode creation
;
1146 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1151 case IGNORE_DIRECTORY_PATH
:
1153 case RECURSIVE_REMOVE_PATH
:
1158 r
= write_one_file(i
, i
->path
);
1164 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1166 return log_error_errno(r
, "Failed to substitute specifiers in copy source %s: %m", i
->argument
);
1168 log_debug("Copying tree \"%s\" to \"%s\".", resolved
, i
->path
);
1169 r
= copy_tree(resolved
, i
->path
, false);
1171 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1178 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1180 if (stat(resolved
, &a
) < 0)
1181 return log_error_errno(errno
, "stat(%s) failed: %m", resolved
);
1183 if (stat(i
->path
, &b
) < 0)
1184 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1186 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1187 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1192 r
= path_set_perms(i
, i
->path
);
1199 r
= glob_item(i
, write_one_file
, false);
1205 case CREATE_DIRECTORY
:
1206 case TRUNCATE_DIRECTORY
:
1207 case CREATE_SUBVOLUME
:
1208 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1209 case CREATE_SUBVOLUME_NEW_QUOTA
:
1211 RUN_WITH_UMASK(0000)
1212 mkdir_parents_label(i
->path
, 0755);
1214 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1215 RUN_WITH_UMASK((~i
->mode
) & 0777)
1216 r
= btrfs_subvol_make(i
->path
);
1220 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1221 RUN_WITH_UMASK(0000)
1222 r
= mkdir_label(i
->path
, i
->mode
);
1227 if (r
!= -EEXIST
&& r
!= -EROFS
)
1228 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1230 k
= is_dir(i
->path
, false);
1231 if (k
== -ENOENT
&& r
== -EROFS
)
1232 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1234 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1236 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1240 creation
= CREATION_EXISTING
;
1242 creation
= CREATION_NORMAL
;
1244 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1246 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1247 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1249 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
);
1253 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i
->path
);
1257 return log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1259 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1261 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1264 r
= path_set_perms(i
, i
->path
);
1272 RUN_WITH_UMASK(0000) {
1273 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1274 r
= mkfifo(i
->path
, i
->mode
);
1275 mac_selinux_create_file_clear();
1279 if (errno
!= EEXIST
)
1280 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1282 if (lstat(i
->path
, &st
) < 0)
1283 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1285 if (!S_ISFIFO(st
.st_mode
)) {
1288 RUN_WITH_UMASK(0000) {
1289 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1290 r
= mkfifo_atomic(i
->path
, i
->mode
);
1291 mac_selinux_create_file_clear();
1295 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1296 creation
= CREATION_FORCE
;
1298 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1302 creation
= CREATION_EXISTING
;
1304 creation
= CREATION_NORMAL
;
1305 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1307 r
= path_set_perms(i
, i
->path
);
1314 case CREATE_SYMLINK
: {
1315 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1317 return log_error_errno(r
, "Failed to substitute specifiers in symlink target %s: %m", i
->argument
);
1319 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1320 r
= symlink(resolved
, i
->path
);
1321 mac_selinux_create_file_clear();
1324 _cleanup_free_
char *x
= NULL
;
1326 if (errno
!= EEXIST
)
1327 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1329 r
= readlink_malloc(i
->path
, &x
);
1330 if (r
< 0 || !streq(resolved
, x
)) {
1333 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1334 r
= symlink_atomic(resolved
, i
->path
);
1335 mac_selinux_create_file_clear();
1338 return log_error_errno(r
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1340 creation
= CREATION_FORCE
;
1342 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1346 creation
= CREATION_EXISTING
;
1349 creation
= CREATION_NORMAL
;
1350 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1354 case CREATE_BLOCK_DEVICE
:
1355 case CREATE_CHAR_DEVICE
: {
1358 if (have_effective_cap(CAP_MKNOD
) == 0) {
1359 /* In a container we lack CAP_MKNOD. We
1360 shouldn't attempt to create the device node in
1361 that case to avoid noise, and we don't support
1362 virtualized devices in containers anyway. */
1364 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1368 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1370 RUN_WITH_UMASK(0000) {
1371 mac_selinux_create_file_prepare(i
->path
, file_type
);
1372 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1373 mac_selinux_create_file_clear();
1377 if (errno
== EPERM
) {
1378 log_debug("We lack permissions, possibly because of cgroup configuration; "
1379 "skipping creation of device node %s.", i
->path
);
1383 if (errno
!= EEXIST
)
1384 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1386 if (lstat(i
->path
, &st
) < 0)
1387 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1389 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1393 RUN_WITH_UMASK(0000) {
1394 mac_selinux_create_file_prepare(i
->path
, file_type
);
1395 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1396 mac_selinux_create_file_clear();
1400 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1401 creation
= CREATION_FORCE
;
1403 log_debug("%s is not a device node.", i
->path
);
1407 creation
= CREATION_EXISTING
;
1409 creation
= CREATION_NORMAL
;
1411 log_debug("%s %s device node \"%s\" %u:%u.",
1412 creation_mode_verb_to_string(creation
),
1413 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1414 i
->path
, major(i
->mode
), minor(i
->mode
));
1416 r
= path_set_perms(i
, i
->path
);
1425 r
= glob_item(i
, path_set_perms
, false);
1430 case RECURSIVE_RELABEL_PATH
:
1431 r
= glob_item(i
, path_set_perms
, true);
1437 r
= glob_item(i
, path_set_xattrs
, false);
1442 case RECURSIVE_SET_XATTR
:
1443 r
= glob_item(i
, path_set_xattrs
, true);
1449 r
= glob_item(i
, path_set_acls
, false);
1454 case RECURSIVE_SET_ACL
:
1455 r
= glob_item(i
, path_set_acls
, true);
1461 r
= glob_item(i
, path_set_attribute
, false);
1466 case RECURSIVE_SET_ATTRIBUTE
:
1467 r
= glob_item(i
, path_set_attribute
, true);
1476 static int remove_item_instance(Item
*i
, const char *instance
) {
1484 if (remove(instance
) < 0 && errno
!= ENOENT
)
1485 return log_error_errno(errno
, "rm(%s): %m", instance
);
1489 case TRUNCATE_DIRECTORY
:
1490 case RECURSIVE_REMOVE_PATH
:
1491 /* FIXME: we probably should use dir_cleanup() here
1492 * instead of rm_rf() so that 'x' is honoured. */
1493 log_debug("rm -rf \"%s\"", instance
);
1494 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1495 if (r
< 0 && r
!= -ENOENT
)
1496 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1501 assert_not_reached("wut?");
1507 static int remove_item(Item
*i
) {
1512 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1518 case CREATE_DIRECTORY
:
1519 case CREATE_SUBVOLUME
:
1520 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1521 case CREATE_SUBVOLUME_NEW_QUOTA
:
1523 case CREATE_SYMLINK
:
1524 case CREATE_CHAR_DEVICE
:
1525 case CREATE_BLOCK_DEVICE
:
1527 case IGNORE_DIRECTORY_PATH
:
1530 case RECURSIVE_RELABEL_PATH
:
1534 case RECURSIVE_SET_XATTR
:
1536 case RECURSIVE_SET_ACL
:
1538 case RECURSIVE_SET_ATTRIBUTE
:
1542 case TRUNCATE_DIRECTORY
:
1543 case RECURSIVE_REMOVE_PATH
:
1544 r
= glob_item(i
, remove_item_instance
, false);
1551 static int clean_item_instance(Item
*i
, const char* instance
) {
1552 _cleanup_closedir_
DIR *d
= NULL
;
1556 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1563 n
= now(CLOCK_REALTIME
);
1567 cutoff
= n
- i
->age
;
1569 d
= opendir_nomod(instance
);
1571 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
1572 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1576 log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1580 if (fstat(dirfd(d
), &s
) < 0)
1581 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1583 if (!S_ISDIR(s
.st_mode
)) {
1584 log_error("%s is not a directory.", i
->path
);
1588 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1589 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1591 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1593 log_debug("Cleanup threshold for %s \"%s\" is %s",
1594 mountpoint
? "mount point" : "directory",
1596 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1598 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1599 MAX_DEPTH
, i
->keep_first_level
);
1602 static int clean_item(Item
*i
) {
1607 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1610 case CREATE_DIRECTORY
:
1611 case CREATE_SUBVOLUME
:
1612 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1613 case CREATE_SUBVOLUME_NEW_QUOTA
:
1614 case TRUNCATE_DIRECTORY
:
1617 clean_item_instance(i
, i
->path
);
1619 case IGNORE_DIRECTORY_PATH
:
1620 r
= glob_item(i
, clean_item_instance
, false);
1629 static int process_item_array(ItemArray
*array
);
1631 static int process_item(Item
*i
) {
1633 _cleanup_free_
char *prefix
= NULL
;
1642 prefix
= malloc(strlen(i
->path
) + 1);
1646 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1649 j
= ordered_hashmap_get(items
, prefix
);
1653 s
= process_item_array(j
);
1654 if (s
< 0 && t
== 0)
1659 r
= arg_create
? create_item(i
) : 0;
1660 q
= arg_remove
? remove_item(i
) : 0;
1661 p
= arg_clean
? clean_item(i
) : 0;
1669 static int process_item_array(ItemArray
*array
) {
1675 for (n
= 0; n
< array
->count
; n
++) {
1676 k
= process_item(array
->items
+ n
);
1677 if (k
< 0 && r
== 0)
1684 static void item_free_contents(Item
*i
) {
1688 strv_free(i
->xattrs
);
1691 acl_free(i
->acl_access
);
1692 acl_free(i
->acl_default
);
1696 static void item_array_free(ItemArray
*a
) {
1702 for (n
= 0; n
< a
->count
; n
++)
1703 item_free_contents(a
->items
+ n
);
1708 static int item_compare(const void *a
, const void *b
) {
1709 const Item
*x
= a
, *y
= b
;
1711 /* Make sure that the ownership taking item is put first, so
1712 * that we first create the node, and then can adjust it */
1714 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1716 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1719 return (int) x
->type
- (int) y
->type
;
1722 static bool item_compatible(Item
*a
, Item
*b
) {
1725 assert(streq(a
->path
, b
->path
));
1727 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1728 /* check if the items are the same */
1729 return streq_ptr(a
->argument
, b
->argument
) &&
1731 a
->uid_set
== b
->uid_set
&&
1734 a
->gid_set
== b
->gid_set
&&
1737 a
->mode_set
== b
->mode_set
&&
1738 a
->mode
== b
->mode
&&
1740 a
->age_set
== b
->age_set
&&
1743 a
->mask_perms
== b
->mask_perms
&&
1745 a
->keep_first_level
== b
->keep_first_level
&&
1747 a
->major_minor
== b
->major_minor
;
1752 static bool should_include_path(const char *path
) {
1755 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1756 if (path_startswith(path
, *prefix
)) {
1757 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1762 STRV_FOREACH(prefix
, arg_include_prefixes
)
1763 if (path_startswith(path
, *prefix
)) {
1764 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1768 /* no matches, so we should include this path only if we
1769 * have no whitelist at all */
1770 if (strv_length(arg_include_prefixes
) == 0)
1773 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1777 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1779 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1780 _cleanup_(item_free_contents
) Item i
= {};
1781 ItemArray
*existing
;
1784 bool force
= false, boot
= false;
1790 r
= extract_many_words(
1802 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1804 log_error("[%s:%u] Syntax error.", fname
, line
);
1808 if (!isempty(buffer
) && !streq(buffer
, "-")) {
1809 i
.argument
= strdup(buffer
);
1814 if (isempty(action
)) {
1815 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1819 for (pos
= 1; action
[pos
]; pos
++) {
1820 if (action
[pos
] == '!' && !boot
)
1822 else if (action
[pos
] == '+' && !force
)
1825 log_error("[%s:%u] Unknown modifiers in command '%s'",
1826 fname
, line
, action
);
1831 if (boot
&& !arg_boot
) {
1832 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1840 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1842 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1848 case CREATE_DIRECTORY
:
1849 case CREATE_SUBVOLUME
:
1850 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1851 case CREATE_SUBVOLUME_NEW_QUOTA
:
1852 case TRUNCATE_DIRECTORY
:
1855 case IGNORE_DIRECTORY_PATH
:
1857 case RECURSIVE_REMOVE_PATH
:
1860 case RECURSIVE_RELABEL_PATH
:
1862 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
1870 case CREATE_SYMLINK
:
1872 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1880 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1887 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1890 } else if (!path_is_absolute(i
.argument
)) {
1891 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1895 path_kill_slashes(i
.argument
);
1898 case CREATE_CHAR_DEVICE
:
1899 case CREATE_BLOCK_DEVICE
: {
1900 unsigned major
, minor
;
1903 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1907 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1908 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1912 i
.major_minor
= makedev(major
, minor
);
1917 case RECURSIVE_SET_XATTR
:
1919 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1922 r
= parse_xattrs_from_arg(&i
);
1928 case RECURSIVE_SET_ACL
:
1930 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
1933 r
= parse_acls_from_arg(&i
);
1939 case RECURSIVE_SET_ATTRIBUTE
:
1941 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
1944 r
= parse_attribute_from_arg(&i
);
1950 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
1954 if (!path_is_absolute(i
.path
)) {
1955 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
1959 path_kill_slashes(i
.path
);
1961 if (!should_include_path(i
.path
))
1967 p
= prefix_root(arg_root
, i
.path
);
1975 if (!isempty(user
) && !streq(user
, "-")) {
1976 const char *u
= user
;
1978 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
1980 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
1987 if (!isempty(group
) && !streq(group
, "-")) {
1988 const char *g
= group
;
1990 r
= get_group_creds(&g
, &i
.gid
);
1992 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
1999 if (!isempty(mode
) && !streq(mode
, "-")) {
2000 const char *mm
= mode
;
2004 i
.mask_perms
= true;
2008 if (parse_mode(mm
, &m
) < 0) {
2009 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2016 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2018 if (!isempty(age
) && !streq(age
, "-")) {
2019 const char *a
= age
;
2022 i
.keep_first_level
= true;
2026 if (parse_sec(a
, &i
.age
) < 0) {
2027 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2034 h
= needs_glob(i
.type
) ? globs
: items
;
2036 existing
= ordered_hashmap_get(h
, i
.path
);
2040 for (n
= 0; n
< existing
->count
; n
++) {
2041 if (!item_compatible(existing
->items
+ n
, &i
)) {
2042 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2043 fname
, line
, i
.path
);
2048 existing
= new0(ItemArray
, 1);
2049 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2054 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2057 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2059 /* Sort item array, to enforce stable ordering of application */
2060 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2066 static void help(void) {
2067 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2068 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2069 " -h --help Show this help\n"
2070 " --version Show package version\n"
2071 " --create Create marked files/directories\n"
2072 " --clean Clean up marked directories\n"
2073 " --remove Remove marked files/directories\n"
2074 " --boot Execute actions only safe at boot\n"
2075 " --prefix=PATH Only apply rules with the specified prefix\n"
2076 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2077 " --root=PATH Operate on an alternate filesystem root\n",
2078 program_invocation_short_name
);
2081 static int parse_argv(int argc
, char *argv
[]) {
2084 ARG_VERSION
= 0x100,
2094 static const struct option options
[] = {
2095 { "help", no_argument
, NULL
, 'h' },
2096 { "version", no_argument
, NULL
, ARG_VERSION
},
2097 { "create", no_argument
, NULL
, ARG_CREATE
},
2098 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2099 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2100 { "boot", no_argument
, NULL
, ARG_BOOT
},
2101 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2102 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2103 { "root", required_argument
, NULL
, ARG_ROOT
},
2112 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2140 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2144 case ARG_EXCLUDE_PREFIX
:
2145 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2150 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2159 assert_not_reached("Unhandled option");
2162 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2163 log_error("You need to specify at least one of --clean, --create or --remove.");
2170 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2171 _cleanup_fclose_
FILE *f
= NULL
;
2172 char line
[LINE_MAX
];
2180 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &f
);
2182 if (ignore_enoent
&& r
== -ENOENT
) {
2183 log_debug_errno(r
, "Failed to open \"%s\": %m", fn
);
2187 return log_error_errno(r
, "Failed to open '%s', ignoring: %m", fn
);
2189 log_debug("Reading config file \"%s\".", fn
);
2191 FOREACH_LINE(line
, f
, break) {
2198 if (*l
== '#' || *l
== 0)
2201 k
= parse_line(fn
, v
, l
);
2202 if (k
< 0 && r
== 0)
2206 /* we have to determine age parameter for each entry of type X */
2207 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2209 Item
*j
, *candidate_item
= NULL
;
2211 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2214 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2215 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2218 if (path_equal(j
->path
, i
->path
)) {
2223 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2224 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2228 if (candidate_item
&& candidate_item
->age_set
) {
2229 i
->age
= candidate_item
->age
;
2235 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2243 int main(int argc
, char *argv
[]) {
2248 r
= parse_argv(argc
, argv
);
2252 log_set_target(LOG_TARGET_AUTO
);
2253 log_parse_environment();
2258 mac_selinux_init(NULL
);
2260 items
= ordered_hashmap_new(&string_hash_ops
);
2261 globs
= ordered_hashmap_new(&string_hash_ops
);
2263 if (!items
|| !globs
) {
2270 if (optind
< argc
) {
2273 for (j
= optind
; j
< argc
; j
++) {
2274 k
= read_config_file(argv
[j
], false);
2275 if (k
< 0 && r
== 0)
2280 _cleanup_strv_free_
char **files
= NULL
;
2283 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, conf_file_dirs
);
2285 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2289 STRV_FOREACH(f
, files
) {
2290 k
= read_config_file(*f
, true);
2291 if (k
< 0 && r
== 0)
2296 /* The non-globbing ones usually create things, hence we apply
2298 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2299 k
= process_item_array(a
);
2300 if (k
< 0 && r
== 0)
2304 /* The globbing ones usually alter things, hence we apply them
2306 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2307 k
= process_item_array(a
);
2308 if (k
< 0 && r
== 0)
2313 while ((a
= ordered_hashmap_steal_first(items
)))
2316 while ((a
= ordered_hashmap_steal_first(globs
)))
2319 ordered_hashmap_free(items
);
2320 ordered_hashmap_free(globs
);
2322 free(arg_include_prefixes
);
2323 free(arg_exclude_prefixes
);
2326 set_free_free(unix_sockets
);
2328 mac_selinux_finish();
2330 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;