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"
47 #include "formats-util.h"
53 #include "path-util.h"
55 #include "selinux-util.h"
57 #include "specifier.h"
58 #include "string-util.h"
62 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
63 * them in the file system. This is intended to be used to create
64 * properly owned directories beneath /tmp, /var/tmp, /run, which are
65 * volatile and hence need to be recreated on bootup. */
67 typedef enum ItemType
{
68 /* These ones take file names */
71 CREATE_DIRECTORY
= 'd',
72 TRUNCATE_DIRECTORY
= 'D',
73 CREATE_SUBVOLUME
= 'v',
74 CREATE_SUBVOLUME_INHERIT_QUOTA
= 'q',
75 CREATE_SUBVOLUME_NEW_QUOTA
= 'Q',
78 CREATE_CHAR_DEVICE
= 'c',
79 CREATE_BLOCK_DEVICE
= 'b',
82 /* These ones take globs */
85 RECURSIVE_SET_XATTR
= 'T',
87 RECURSIVE_SET_ACL
= 'A',
89 RECURSIVE_SET_ATTRIBUTE
= 'H',
91 IGNORE_DIRECTORY_PATH
= 'X',
93 RECURSIVE_REMOVE_PATH
= 'R',
95 RECURSIVE_RELABEL_PATH
= 'Z',
96 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
115 unsigned attribute_value
;
116 unsigned attribute_mask
;
123 bool attribute_set
:1;
125 bool keep_first_level
:1;
132 typedef struct ItemArray
{
138 static bool arg_create
= false;
139 static bool arg_clean
= false;
140 static bool arg_remove
= false;
141 static bool arg_boot
= false;
143 static char **arg_include_prefixes
= NULL
;
144 static char **arg_exclude_prefixes
= NULL
;
145 static char *arg_root
= NULL
;
147 static const char conf_file_dirs
[] = CONF_DIRS_NULSTR("tmpfiles");
149 #define MAX_DEPTH 256
151 static OrderedHashmap
*items
= NULL
, *globs
= NULL
;
152 static Set
*unix_sockets
= NULL
;
154 static const Specifier specifier_table
[] = {
155 { 'm', specifier_machine_id
, NULL
},
156 { 'b', specifier_boot_id
, NULL
},
157 { 'H', specifier_host_name
, NULL
},
158 { 'v', specifier_kernel_release
, NULL
},
162 static bool needs_glob(ItemType t
) {
166 IGNORE_DIRECTORY_PATH
,
168 RECURSIVE_REMOVE_PATH
,
171 RECURSIVE_RELABEL_PATH
,
177 RECURSIVE_SET_ATTRIBUTE
);
180 static bool takes_ownership(ItemType t
) {
187 CREATE_SUBVOLUME_INHERIT_QUOTA
,
188 CREATE_SUBVOLUME_NEW_QUOTA
,
196 IGNORE_DIRECTORY_PATH
,
198 RECURSIVE_REMOVE_PATH
);
201 static struct Item
* find_glob(OrderedHashmap
*h
, const char *match
) {
205 ORDERED_HASHMAP_FOREACH(j
, h
, i
) {
208 for (n
= 0; n
< j
->count
; n
++) {
209 Item
*item
= j
->items
+ n
;
211 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
219 static void load_unix_sockets(void) {
220 _cleanup_fclose_
FILE *f
= NULL
;
226 /* We maintain a cache of the sockets we found in
227 * /proc/net/unix to speed things up a little. */
229 unix_sockets
= set_new(&string_hash_ops
);
233 f
= fopen("/proc/net/unix", "re");
238 if (!fgets(line
, sizeof(line
), f
))
245 if (!fgets(line
, sizeof(line
), f
))
250 p
= strchr(line
, ':');
258 p
+= strspn(p
, WHITESPACE
);
259 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
260 p
+= strspn(p
, WHITESPACE
);
269 path_kill_slashes(s
);
271 k
= set_consume(unix_sockets
, s
);
272 if (k
< 0 && k
!= -EEXIST
)
279 set_free_free(unix_sockets
);
283 static bool unix_socket_alive(const char *fn
) {
289 return !!set_get(unix_sockets
, (char*) fn
);
291 /* We don't know, so assume yes */
295 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
297 union file_handle_union h
= FILE_HANDLE_INIT
;
298 int mount_id_parent
, mount_id
;
301 r_p
= name_to_handle_at(dirfd(d
), ".", &h
.handle
, &mount_id_parent
, 0);
305 h
.handle
.handle_bytes
= MAX_HANDLE_SZ
;
306 r
= name_to_handle_at(dirfd(d
), subdir
, &h
.handle
, &mount_id
, 0);
310 /* got no handle; make no assumptions, return error */
311 if (r_p
< 0 && r
< 0)
314 /* got both handles; if they differ, it is a mount point */
315 if (r_p
>= 0 && r
>= 0)
316 return mount_id_parent
!= mount_id
;
318 /* got only one handle; assume different mount points if one
319 * of both queries was not supported by the filesystem */
320 if (r_p
== -ENOSYS
|| r_p
== -EOPNOTSUPP
|| r
== -ENOSYS
|| r
== -EOPNOTSUPP
)
329 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
332 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
336 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
340 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
342 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
347 static DIR* opendir_nomod(const char *path
) {
348 return xopendirat_nomod(AT_FDCWD
, path
);
351 static int dir_cleanup(
355 const struct stat
*ds
,
360 bool keep_this_level
) {
363 struct timespec times
[2];
364 bool deleted
= false;
367 while ((dent
= readdir(d
))) {
370 _cleanup_free_
char *sub_path
= NULL
;
372 if (STR_IN_SET(dent
->d_name
, ".", ".."))
375 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
379 /* FUSE, NFS mounts, SELinux might return EACCES */
381 log_debug_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
383 log_error_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
388 /* Stay on the same filesystem */
389 if (s
.st_dev
!= rootdev
) {
390 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
394 /* Try to detect bind mounts of the same filesystem instance; they
395 * do not differ in device major/minors. This type of query is not
396 * supported on all kernels or filesystem types though. */
397 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
398 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
403 /* Do not delete read-only files owned by root */
404 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
)) {
405 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p
, dent
->d_name
);
409 sub_path
= strjoin(p
, "/", dent
->d_name
, NULL
);
415 /* Is there an item configured for this path? */
416 if (ordered_hashmap_get(items
, sub_path
)) {
417 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
421 if (find_glob(globs
, sub_path
)) {
422 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
426 if (S_ISDIR(s
.st_mode
)) {
429 streq(dent
->d_name
, "lost+found") &&
431 log_debug("Ignoring \"%s\".", sub_path
);
436 log_warning("Reached max depth on \"%s\".", sub_path
);
438 _cleanup_closedir_
DIR *sub_dir
;
441 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
444 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
449 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
454 /* Note: if you are wondering why we don't
455 * support the sticky bit for excluding
456 * directories from cleaning like we do it for
457 * other file system objects: well, the sticky
458 * bit already has a meaning for directories,
459 * so we don't want to overload that. */
461 if (keep_this_level
) {
462 log_debug("Keeping \"%s\".", sub_path
);
466 /* Ignore ctime, we change it when deleting */
467 age
= timespec_load(&s
.st_mtim
);
469 char a
[FORMAT_TIMESTAMP_MAX
];
470 /* Follows spelling in stat(1). */
471 log_debug("Directory \"%s\": modify time %s is too new.",
473 format_timestamp_us(a
, sizeof(a
), age
));
477 age
= timespec_load(&s
.st_atim
);
479 char a
[FORMAT_TIMESTAMP_MAX
];
480 log_debug("Directory \"%s\": access time %s is too new.",
482 format_timestamp_us(a
, sizeof(a
), age
));
486 log_debug("Removing directory \"%s\".", sub_path
);
487 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
488 if (errno
!= ENOENT
&& errno
!= ENOTEMPTY
) {
489 log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
494 /* Skip files for which the sticky bit is
495 * set. These are semantics we define, and are
496 * unknown elsewhere. See XDG_RUNTIME_DIR
497 * specification for details. */
498 if (s
.st_mode
& S_ISVTX
) {
499 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
503 if (mountpoint
&& S_ISREG(s
.st_mode
))
504 if (s
.st_uid
== 0 && STR_IN_SET(dent
->d_name
,
508 log_debug("Skipping \"%s\".", sub_path
);
512 /* Ignore sockets that are listed in /proc/net/unix */
513 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
514 log_debug("Skipping \"%s\": live socket.", sub_path
);
518 /* Ignore device nodes */
519 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
520 log_debug("Skipping \"%s\": a device.", sub_path
);
524 /* Keep files on this level around if this is
526 if (keep_this_level
) {
527 log_debug("Keeping \"%s\".", sub_path
);
531 age
= timespec_load(&s
.st_mtim
);
533 char a
[FORMAT_TIMESTAMP_MAX
];
534 /* Follows spelling in stat(1). */
535 log_debug("File \"%s\": modify time %s is too new.",
537 format_timestamp_us(a
, sizeof(a
), age
));
541 age
= timespec_load(&s
.st_atim
);
543 char a
[FORMAT_TIMESTAMP_MAX
];
544 log_debug("File \"%s\": access time %s is too new.",
546 format_timestamp_us(a
, sizeof(a
), age
));
550 age
= timespec_load(&s
.st_ctim
);
552 char a
[FORMAT_TIMESTAMP_MAX
];
553 log_debug("File \"%s\": change time %s is too new.",
555 format_timestamp_us(a
, sizeof(a
), age
));
559 log_debug("unlink \"%s\"", sub_path
);
561 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
563 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
572 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
574 /* Restore original directory timestamps */
575 times
[0] = ds
->st_atim
;
576 times
[1] = ds
->st_mtim
;
578 age1
= timespec_load(&ds
->st_atim
);
579 age2
= timespec_load(&ds
->st_mtim
);
580 log_debug("Restoring access and modification time on \"%s\": %s, %s",
582 format_timestamp_us(a
, sizeof(a
), age1
),
583 format_timestamp_us(b
, sizeof(b
), age2
));
584 if (futimens(dirfd(d
), times
) < 0)
585 log_error_errno(errno
, "utimensat(%s): %m", p
);
591 static int path_set_perms(Item
*i
, const char *path
) {
592 _cleanup_close_
int fd
= -1;
598 /* We open the file with O_PATH here, to make the operation
599 * somewhat atomic. Also there's unfortunately no fchmodat()
600 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
603 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
605 return log_error_errno(errno
, "Adjusting owner and mode for %s failed: %m", path
);
607 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
608 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
610 if (S_ISLNK(st
.st_mode
))
611 log_debug("Skipping mode an owner fix for symlink %s.", path
);
613 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
614 xsprintf(fn
, "/proc/self/fd/%i", fd
);
616 /* not using i->path directly because it may be a glob */
621 if (!(st
.st_mode
& 0111))
623 if (!(st
.st_mode
& 0222))
625 if (!(st
.st_mode
& 0444))
627 if (!S_ISDIR(st
.st_mode
))
628 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
631 if (m
== (st
.st_mode
& 07777))
632 log_debug("\"%s\" has right mode %o", path
, st
.st_mode
);
634 log_debug("chmod \"%s\" to mode %o", path
, m
);
635 if (chmod(fn
, m
) < 0)
636 return log_error_errno(errno
, "chmod(%s) failed: %m", path
);
640 if ((i
->uid
!= st
.st_uid
|| i
->gid
!= st
.st_gid
) &&
641 (i
->uid_set
|| i
->gid_set
)) {
642 log_debug("chown \"%s\" to "UID_FMT
"."GID_FMT
,
644 i
->uid_set
? i
->uid
: UID_INVALID
,
645 i
->gid_set
? i
->gid
: GID_INVALID
);
647 i
->uid_set
? i
->uid
: UID_INVALID
,
648 i
->gid_set
? i
->gid
: GID_INVALID
) < 0)
649 return log_error_errno(errno
, "chown(%s) failed: %m", path
);
655 return label_fix(path
, false, false);
658 static int parse_xattrs_from_arg(Item
*i
) {
668 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
, *xattr_replaced
= NULL
;
670 r
= extract_first_word(&p
, &xattr
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
672 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
676 r
= specifier_printf(xattr
, specifier_table
, NULL
, &xattr_replaced
);
678 return log_error_errno(r
, "Failed to replace specifiers in extended attribute '%s': %m", xattr
);
680 r
= split_pair(xattr_replaced
, "=", &name
, &value
);
682 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
686 if (isempty(name
) || isempty(value
)) {
687 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
691 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
700 static int path_set_xattrs(Item
*i
, const char *path
) {
701 char **name
, **value
;
706 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
710 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
711 if (lsetxattr(path
, *name
, *value
, n
, 0) < 0) {
712 log_error("Setting extended attribute %s=%s on %s failed: %m", *name
, *value
, path
);
719 static int parse_acls_from_arg(Item
*item
) {
725 /* If force (= modify) is set, we will not modify the acl
726 * afterwards, so the mask can be added now if necessary. */
728 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
730 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
732 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
739 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
740 _cleanup_(acl_free_charpp
) char *t
= NULL
;
741 _cleanup_(acl_freep
) acl_t dup
= NULL
;
744 /* Returns 0 for success, positive error if already warned,
745 * negative error otherwise. */
748 r
= acls_for_file(path
, type
, acl
, &dup
);
752 r
= calc_acl_mask_if_needed(&dup
);
760 /* the mask was already added earlier if needed */
763 r
= add_base_acls_if_needed(&dup
, path
);
767 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
768 log_debug("Setting %s ACL %s on %s.",
769 type
== ACL_TYPE_ACCESS
? "access" : "default",
772 r
= acl_set_file(path
, type
, dup
);
774 /* Return positive to indicate we already warned */
775 return -log_error_errno(errno
,
776 "Setting %s ACL \"%s\" on %s failed: %m",
777 type
== ACL_TYPE_ACCESS
? "access" : "default",
784 static int path_set_acls(Item
*item
, const char *path
) {
787 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
788 _cleanup_close_
int fd
= -1;
794 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
796 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
798 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
799 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
801 if (S_ISLNK(st
.st_mode
)) {
802 log_debug("Skipping ACL fix for symlink %s.", path
);
806 xsprintf(fn
, "/proc/self/fd/%i", fd
);
808 if (item
->acl_access
)
809 r
= path_set_acl(fn
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
811 if (r
== 0 && item
->acl_default
)
812 r
= path_set_acl(fn
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
815 return -r
; /* already warned */
816 else if (r
== -EOPNOTSUPP
) {
817 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
820 log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
825 #define ATTRIBUTES_ALL \
834 FS_JOURNAL_DATA_FL | \
841 static int parse_attribute_from_arg(Item
*item
) {
843 static const struct {
847 { 'A', FS_NOATIME_FL
}, /* do not update atime */
848 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
849 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
850 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
851 { 'c', FS_COMPR_FL
}, /* Compress file */
852 { 'd', FS_NODUMP_FL
}, /* do not dump file */
853 { 'e', FS_EXTENT_FL
}, /* Top of directory hierarchies*/
854 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
855 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
856 { 's', FS_SECRM_FL
}, /* Secure deletion */
857 { 'u', FS_UNRM_FL
}, /* Undelete */
858 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
859 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies*/
860 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
869 unsigned value
= 0, mask
= 0;
879 } else if (*p
== '-') {
882 } else if (*p
== '=') {
888 if (isempty(p
) && mode
!= MODE_SET
) {
889 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
893 for (; p
&& *p
; p
++) {
896 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
897 if (*p
== attributes
[i
].character
)
900 if (i
>= ELEMENTSOF(attributes
)) {
901 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
905 v
= attributes
[i
].value
;
907 if (mode
== MODE_ADD
|| mode
== MODE_SET
)
915 if (mode
== MODE_SET
)
916 mask
|= ATTRIBUTES_ALL
;
920 item
->attribute_mask
= mask
;
921 item
->attribute_value
= value
;
922 item
->attribute_set
= true;
927 static int path_set_attribute(Item
*item
, const char *path
) {
928 _cleanup_close_
int fd
= -1;
933 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
936 fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
|O_NOATIME
|O_NOFOLLOW
);
939 return log_error_errno(errno
, "Skipping file attributes adjustment on symlink %s.", path
);
941 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
944 if (fstat(fd
, &st
) < 0)
945 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
947 /* Issuing the file attribute ioctls on device nodes is not
948 * safe, as that will be delivered to the drivers, not the
949 * file system containing the device node. */
950 if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
)) {
951 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
955 f
= item
->attribute_value
& item
->attribute_mask
;
957 /* Mask away directory-specific flags */
958 if (!S_ISDIR(st
.st_mode
))
961 r
= chattr_fd(fd
, f
, item
->attribute_mask
);
963 log_full_errno(r
== -ENOTTY
? LOG_DEBUG
: LOG_WARNING
,
965 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
966 path
, item
->attribute_value
, item
->attribute_mask
);
971 static int write_one_file(Item
*i
, const char *path
) {
972 _cleanup_close_
int fd
= -1;
979 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
|O_NOFOLLOW
:
980 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
982 RUN_WITH_UMASK(0000) {
983 mac_selinux_create_file_prepare(path
, S_IFREG
);
984 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
985 mac_selinux_create_file_clear();
989 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
990 log_debug_errno(errno
, "Not writing \"%s\": %m", path
);
995 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
996 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
999 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1003 _cleanup_free_
char *unescaped
= NULL
, *replaced
= NULL
;
1005 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1007 r
= cunescape(i
->argument
, 0, &unescaped
);
1009 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
1011 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &replaced
);
1013 return log_error_errno(r
, "Failed to replace specifiers in parameter to write '%s': %m", unescaped
);
1015 r
= loop_write(fd
, replaced
, strlen(replaced
), false);
1017 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1019 log_debug("\"%s\" has been created.", path
);
1021 fd
= safe_close(fd
);
1023 if (stat(path
, &st
) < 0)
1024 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1027 if (!S_ISREG(st
.st_mode
)) {
1028 log_error("%s is not a file.", path
);
1032 r
= path_set_perms(i
, path
);
1039 typedef int (*action_t
)(Item
*, const char *);
1041 static int item_do_children(Item
*i
, const char *path
, action_t action
) {
1042 _cleanup_closedir_
DIR *d
;
1048 /* This returns the first error we run into, but nevertheless
1051 d
= opendir_nomod(path
);
1053 return errno
== ENOENT
|| errno
== ENOTDIR
? 0 : -errno
;
1056 _cleanup_free_
char *p
= NULL
;
1063 if (errno
!= 0 && r
== 0)
1069 if (STR_IN_SET(de
->d_name
, ".", ".."))
1072 p
= strjoin(path
, "/", de
->d_name
, NULL
);
1077 if (q
< 0 && q
!= -ENOENT
&& r
== 0)
1080 if (IN_SET(de
->d_type
, DT_UNKNOWN
, DT_DIR
)) {
1081 q
= item_do_children(i
, p
, action
);
1082 if (q
< 0 && r
== 0)
1090 static int glob_item(Item
*i
, action_t action
, bool recursive
) {
1091 _cleanup_globfree_ glob_t g
= {
1092 .gl_closedir
= (void (*)(void *)) closedir
,
1093 .gl_readdir
= (struct dirent
*(*)(void *)) readdir
,
1094 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1102 k
= glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
|GLOB_ALTDIRFUNC
, NULL
, &g
);
1103 if (k
!= 0 && k
!= GLOB_NOMATCH
)
1104 return log_error_errno(errno
?: EIO
, "glob(%s) failed: %m", i
->path
);
1106 STRV_FOREACH(fn
, g
.gl_pathv
) {
1108 if (k
< 0 && r
== 0)
1112 k
= item_do_children(i
, *fn
, action
);
1113 if (k
< 0 && r
== 0)
1126 _CREATION_MODE_INVALID
= -1
1129 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1130 [CREATION_NORMAL
] = "Created",
1131 [CREATION_EXISTING
] = "Found existing",
1132 [CREATION_FORCE
] = "Created replacement",
1135 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1137 static int create_item(Item
*i
) {
1138 _cleanup_free_
char *resolved
= NULL
;
1141 CreationMode creation
;
1145 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1150 case IGNORE_DIRECTORY_PATH
:
1152 case RECURSIVE_REMOVE_PATH
:
1157 r
= write_one_file(i
, i
->path
);
1163 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1165 return log_error_errno(r
, "Failed to substitute specifiers in copy source %s: %m", i
->argument
);
1167 log_debug("Copying tree \"%s\" to \"%s\".", resolved
, i
->path
);
1168 r
= copy_tree(resolved
, i
->path
, false);
1170 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1177 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1179 if (stat(resolved
, &a
) < 0)
1180 return log_error_errno(errno
, "stat(%s) failed: %m", resolved
);
1182 if (stat(i
->path
, &b
) < 0)
1183 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1185 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1186 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1191 r
= path_set_perms(i
, i
->path
);
1198 r
= glob_item(i
, write_one_file
, false);
1204 case CREATE_DIRECTORY
:
1205 case TRUNCATE_DIRECTORY
:
1206 case CREATE_SUBVOLUME
:
1207 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1208 case CREATE_SUBVOLUME_NEW_QUOTA
:
1210 RUN_WITH_UMASK(0000)
1211 mkdir_parents_label(i
->path
, 0755);
1213 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1214 RUN_WITH_UMASK((~i
->mode
) & 0777)
1215 r
= btrfs_subvol_make(i
->path
);
1219 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1220 RUN_WITH_UMASK(0000)
1221 r
= mkdir_label(i
->path
, i
->mode
);
1226 if (r
!= -EEXIST
&& r
!= -EROFS
)
1227 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1229 k
= is_dir(i
->path
, false);
1230 if (k
== -ENOENT
&& r
== -EROFS
)
1231 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1233 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1235 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1239 creation
= CREATION_EXISTING
;
1241 creation
= CREATION_NORMAL
;
1243 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1245 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1246 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1248 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
);
1252 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i
->path
);
1256 return log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1258 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1260 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1263 r
= path_set_perms(i
, i
->path
);
1271 RUN_WITH_UMASK(0000) {
1272 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1273 r
= mkfifo(i
->path
, i
->mode
);
1274 mac_selinux_create_file_clear();
1278 if (errno
!= EEXIST
)
1279 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1281 if (lstat(i
->path
, &st
) < 0)
1282 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1284 if (!S_ISFIFO(st
.st_mode
)) {
1287 RUN_WITH_UMASK(0000) {
1288 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1289 r
= mkfifo_atomic(i
->path
, i
->mode
);
1290 mac_selinux_create_file_clear();
1294 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1295 creation
= CREATION_FORCE
;
1297 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1301 creation
= CREATION_EXISTING
;
1303 creation
= CREATION_NORMAL
;
1304 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1306 r
= path_set_perms(i
, i
->path
);
1313 case CREATE_SYMLINK
: {
1314 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1316 return log_error_errno(r
, "Failed to substitute specifiers in symlink target %s: %m", i
->argument
);
1318 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1319 r
= symlink(resolved
, i
->path
);
1320 mac_selinux_create_file_clear();
1323 _cleanup_free_
char *x
= NULL
;
1325 if (errno
!= EEXIST
)
1326 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1328 r
= readlink_malloc(i
->path
, &x
);
1329 if (r
< 0 || !streq(resolved
, x
)) {
1332 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1333 r
= symlink_atomic(resolved
, i
->path
);
1334 mac_selinux_create_file_clear();
1337 return log_error_errno(r
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1339 creation
= CREATION_FORCE
;
1341 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1345 creation
= CREATION_EXISTING
;
1348 creation
= CREATION_NORMAL
;
1349 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1353 case CREATE_BLOCK_DEVICE
:
1354 case CREATE_CHAR_DEVICE
: {
1357 if (have_effective_cap(CAP_MKNOD
) == 0) {
1358 /* In a container we lack CAP_MKNOD. We
1359 shouldn't attempt to create the device node in
1360 that case to avoid noise, and we don't support
1361 virtualized devices in containers anyway. */
1363 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1367 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1369 RUN_WITH_UMASK(0000) {
1370 mac_selinux_create_file_prepare(i
->path
, file_type
);
1371 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1372 mac_selinux_create_file_clear();
1376 if (errno
== EPERM
) {
1377 log_debug("We lack permissions, possibly because of cgroup configuration; "
1378 "skipping creation of device node %s.", i
->path
);
1382 if (errno
!= EEXIST
)
1383 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1385 if (lstat(i
->path
, &st
) < 0)
1386 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1388 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1392 RUN_WITH_UMASK(0000) {
1393 mac_selinux_create_file_prepare(i
->path
, file_type
);
1394 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1395 mac_selinux_create_file_clear();
1399 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1400 creation
= CREATION_FORCE
;
1402 log_debug("%s is not a device node.", i
->path
);
1406 creation
= CREATION_EXISTING
;
1408 creation
= CREATION_NORMAL
;
1410 log_debug("%s %s device node \"%s\" %u:%u.",
1411 creation_mode_verb_to_string(creation
),
1412 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1413 i
->path
, major(i
->mode
), minor(i
->mode
));
1415 r
= path_set_perms(i
, i
->path
);
1424 r
= glob_item(i
, path_set_perms
, false);
1429 case RECURSIVE_RELABEL_PATH
:
1430 r
= glob_item(i
, path_set_perms
, true);
1436 r
= glob_item(i
, path_set_xattrs
, false);
1441 case RECURSIVE_SET_XATTR
:
1442 r
= glob_item(i
, path_set_xattrs
, true);
1448 r
= glob_item(i
, path_set_acls
, false);
1453 case RECURSIVE_SET_ACL
:
1454 r
= glob_item(i
, path_set_acls
, true);
1460 r
= glob_item(i
, path_set_attribute
, false);
1465 case RECURSIVE_SET_ATTRIBUTE
:
1466 r
= glob_item(i
, path_set_attribute
, true);
1475 static int remove_item_instance(Item
*i
, const char *instance
) {
1483 if (remove(instance
) < 0 && errno
!= ENOENT
)
1484 return log_error_errno(errno
, "rm(%s): %m", instance
);
1488 case TRUNCATE_DIRECTORY
:
1489 case RECURSIVE_REMOVE_PATH
:
1490 /* FIXME: we probably should use dir_cleanup() here
1491 * instead of rm_rf() so that 'x' is honoured. */
1492 log_debug("rm -rf \"%s\"", instance
);
1493 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1494 if (r
< 0 && r
!= -ENOENT
)
1495 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1500 assert_not_reached("wut?");
1506 static int remove_item(Item
*i
) {
1511 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1517 case CREATE_DIRECTORY
:
1518 case CREATE_SUBVOLUME
:
1519 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1520 case CREATE_SUBVOLUME_NEW_QUOTA
:
1522 case CREATE_SYMLINK
:
1523 case CREATE_CHAR_DEVICE
:
1524 case CREATE_BLOCK_DEVICE
:
1526 case IGNORE_DIRECTORY_PATH
:
1529 case RECURSIVE_RELABEL_PATH
:
1533 case RECURSIVE_SET_XATTR
:
1535 case RECURSIVE_SET_ACL
:
1537 case RECURSIVE_SET_ATTRIBUTE
:
1541 case TRUNCATE_DIRECTORY
:
1542 case RECURSIVE_REMOVE_PATH
:
1543 r
= glob_item(i
, remove_item_instance
, false);
1550 static int clean_item_instance(Item
*i
, const char* instance
) {
1551 _cleanup_closedir_
DIR *d
= NULL
;
1555 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1562 n
= now(CLOCK_REALTIME
);
1566 cutoff
= n
- i
->age
;
1568 d
= opendir_nomod(instance
);
1570 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
1571 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1575 log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1579 if (fstat(dirfd(d
), &s
) < 0)
1580 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1582 if (!S_ISDIR(s
.st_mode
)) {
1583 log_error("%s is not a directory.", i
->path
);
1587 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1588 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1590 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1592 log_debug("Cleanup threshold for %s \"%s\" is %s",
1593 mountpoint
? "mount point" : "directory",
1595 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1597 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1598 MAX_DEPTH
, i
->keep_first_level
);
1601 static int clean_item(Item
*i
) {
1606 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1609 case CREATE_DIRECTORY
:
1610 case CREATE_SUBVOLUME
:
1611 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1612 case CREATE_SUBVOLUME_NEW_QUOTA
:
1613 case TRUNCATE_DIRECTORY
:
1616 clean_item_instance(i
, i
->path
);
1618 case IGNORE_DIRECTORY_PATH
:
1619 r
= glob_item(i
, clean_item_instance
, false);
1628 static int process_item_array(ItemArray
*array
);
1630 static int process_item(Item
*i
) {
1632 _cleanup_free_
char *prefix
= NULL
;
1641 prefix
= malloc(strlen(i
->path
) + 1);
1645 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1648 j
= ordered_hashmap_get(items
, prefix
);
1652 s
= process_item_array(j
);
1653 if (s
< 0 && t
== 0)
1658 r
= arg_create
? create_item(i
) : 0;
1659 q
= arg_remove
? remove_item(i
) : 0;
1660 p
= arg_clean
? clean_item(i
) : 0;
1668 static int process_item_array(ItemArray
*array
) {
1674 for (n
= 0; n
< array
->count
; n
++) {
1675 k
= process_item(array
->items
+ n
);
1676 if (k
< 0 && r
== 0)
1683 static void item_free_contents(Item
*i
) {
1687 strv_free(i
->xattrs
);
1690 acl_free(i
->acl_access
);
1691 acl_free(i
->acl_default
);
1695 static void item_array_free(ItemArray
*a
) {
1701 for (n
= 0; n
< a
->count
; n
++)
1702 item_free_contents(a
->items
+ n
);
1707 static int item_compare(const void *a
, const void *b
) {
1708 const Item
*x
= a
, *y
= b
;
1710 /* Make sure that the ownership taking item is put first, so
1711 * that we first create the node, and then can adjust it */
1713 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1715 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1718 return (int) x
->type
- (int) y
->type
;
1721 static bool item_compatible(Item
*a
, Item
*b
) {
1724 assert(streq(a
->path
, b
->path
));
1726 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1727 /* check if the items are the same */
1728 return streq_ptr(a
->argument
, b
->argument
) &&
1730 a
->uid_set
== b
->uid_set
&&
1733 a
->gid_set
== b
->gid_set
&&
1736 a
->mode_set
== b
->mode_set
&&
1737 a
->mode
== b
->mode
&&
1739 a
->age_set
== b
->age_set
&&
1742 a
->mask_perms
== b
->mask_perms
&&
1744 a
->keep_first_level
== b
->keep_first_level
&&
1746 a
->major_minor
== b
->major_minor
;
1751 static bool should_include_path(const char *path
) {
1754 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1755 if (path_startswith(path
, *prefix
)) {
1756 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1761 STRV_FOREACH(prefix
, arg_include_prefixes
)
1762 if (path_startswith(path
, *prefix
)) {
1763 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1767 /* no matches, so we should include this path only if we
1768 * have no whitelist at all */
1769 if (strv_length(arg_include_prefixes
) == 0)
1772 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1776 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1778 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1779 _cleanup_(item_free_contents
) Item i
= {};
1780 ItemArray
*existing
;
1783 bool force
= false, boot
= false;
1789 r
= extract_many_words(
1801 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1803 log_error("[%s:%u] Syntax error.", fname
, line
);
1807 if (!isempty(buffer
) && !streq(buffer
, "-")) {
1808 i
.argument
= strdup(buffer
);
1813 if (isempty(action
)) {
1814 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1818 for (pos
= 1; action
[pos
]; pos
++) {
1819 if (action
[pos
] == '!' && !boot
)
1821 else if (action
[pos
] == '+' && !force
)
1824 log_error("[%s:%u] Unknown modifiers in command '%s'",
1825 fname
, line
, action
);
1830 if (boot
&& !arg_boot
) {
1831 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1839 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1841 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1847 case CREATE_DIRECTORY
:
1848 case CREATE_SUBVOLUME
:
1849 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1850 case CREATE_SUBVOLUME_NEW_QUOTA
:
1851 case TRUNCATE_DIRECTORY
:
1854 case IGNORE_DIRECTORY_PATH
:
1856 case RECURSIVE_REMOVE_PATH
:
1859 case RECURSIVE_RELABEL_PATH
:
1861 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
1869 case CREATE_SYMLINK
:
1871 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1879 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1886 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1889 } else if (!path_is_absolute(i
.argument
)) {
1890 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1894 path_kill_slashes(i
.argument
);
1897 case CREATE_CHAR_DEVICE
:
1898 case CREATE_BLOCK_DEVICE
: {
1899 unsigned major
, minor
;
1902 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1906 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1907 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1911 i
.major_minor
= makedev(major
, minor
);
1916 case RECURSIVE_SET_XATTR
:
1918 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1921 r
= parse_xattrs_from_arg(&i
);
1927 case RECURSIVE_SET_ACL
:
1929 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
1932 r
= parse_acls_from_arg(&i
);
1938 case RECURSIVE_SET_ATTRIBUTE
:
1940 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
1943 r
= parse_attribute_from_arg(&i
);
1949 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
1953 if (!path_is_absolute(i
.path
)) {
1954 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
1958 path_kill_slashes(i
.path
);
1960 if (!should_include_path(i
.path
))
1966 p
= prefix_root(arg_root
, i
.path
);
1974 if (!isempty(user
) && !streq(user
, "-")) {
1975 const char *u
= user
;
1977 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
1979 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
1986 if (!isempty(group
) && !streq(group
, "-")) {
1987 const char *g
= group
;
1989 r
= get_group_creds(&g
, &i
.gid
);
1991 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
1998 if (!isempty(mode
) && !streq(mode
, "-")) {
1999 const char *mm
= mode
;
2003 i
.mask_perms
= true;
2007 if (parse_mode(mm
, &m
) < 0) {
2008 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2015 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2017 if (!isempty(age
) && !streq(age
, "-")) {
2018 const char *a
= age
;
2021 i
.keep_first_level
= true;
2025 if (parse_sec(a
, &i
.age
) < 0) {
2026 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2033 h
= needs_glob(i
.type
) ? globs
: items
;
2035 existing
= ordered_hashmap_get(h
, i
.path
);
2039 for (n
= 0; n
< existing
->count
; n
++) {
2040 if (!item_compatible(existing
->items
+ n
, &i
)) {
2041 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2042 fname
, line
, i
.path
);
2047 existing
= new0(ItemArray
, 1);
2048 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2053 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2056 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2058 /* Sort item array, to enforce stable ordering of application */
2059 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2065 static void help(void) {
2066 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2067 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2068 " -h --help Show this help\n"
2069 " --version Show package version\n"
2070 " --create Create marked files/directories\n"
2071 " --clean Clean up marked directories\n"
2072 " --remove Remove marked files/directories\n"
2073 " --boot Execute actions only safe at boot\n"
2074 " --prefix=PATH Only apply rules with the specified prefix\n"
2075 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2076 " --root=PATH Operate on an alternate filesystem root\n",
2077 program_invocation_short_name
);
2080 static int parse_argv(int argc
, char *argv
[]) {
2083 ARG_VERSION
= 0x100,
2093 static const struct option options
[] = {
2094 { "help", no_argument
, NULL
, 'h' },
2095 { "version", no_argument
, NULL
, ARG_VERSION
},
2096 { "create", no_argument
, NULL
, ARG_CREATE
},
2097 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2098 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2099 { "boot", no_argument
, NULL
, ARG_BOOT
},
2100 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2101 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2102 { "root", required_argument
, NULL
, ARG_ROOT
},
2111 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2139 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2143 case ARG_EXCLUDE_PREFIX
:
2144 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2149 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2158 assert_not_reached("Unhandled option");
2161 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2162 log_error("You need to specify at least one of --clean, --create or --remove.");
2169 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2170 _cleanup_fclose_
FILE *f
= NULL
;
2171 char line
[LINE_MAX
];
2179 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &f
);
2181 if (ignore_enoent
&& r
== -ENOENT
) {
2182 log_debug_errno(r
, "Failed to open \"%s\": %m", fn
);
2186 return log_error_errno(r
, "Failed to open '%s', ignoring: %m", fn
);
2188 log_debug("Reading config file \"%s\".", fn
);
2190 FOREACH_LINE(line
, f
, break) {
2197 if (*l
== '#' || *l
== 0)
2200 k
= parse_line(fn
, v
, l
);
2201 if (k
< 0 && r
== 0)
2205 /* we have to determine age parameter for each entry of type X */
2206 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2208 Item
*j
, *candidate_item
= NULL
;
2210 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2213 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2214 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2217 if (path_equal(j
->path
, i
->path
)) {
2222 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2223 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2227 if (candidate_item
&& candidate_item
->age_set
) {
2228 i
->age
= candidate_item
->age
;
2234 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2242 int main(int argc
, char *argv
[]) {
2247 r
= parse_argv(argc
, argv
);
2251 log_set_target(LOG_TARGET_AUTO
);
2252 log_parse_environment();
2257 mac_selinux_init(NULL
);
2259 items
= ordered_hashmap_new(&string_hash_ops
);
2260 globs
= ordered_hashmap_new(&string_hash_ops
);
2262 if (!items
|| !globs
) {
2269 if (optind
< argc
) {
2272 for (j
= optind
; j
< argc
; j
++) {
2273 k
= read_config_file(argv
[j
], false);
2274 if (k
< 0 && r
== 0)
2279 _cleanup_strv_free_
char **files
= NULL
;
2282 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, conf_file_dirs
);
2284 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2288 STRV_FOREACH(f
, files
) {
2289 k
= read_config_file(*f
, true);
2290 if (k
< 0 && r
== 0)
2295 /* The non-globbing ones usually create things, hence we apply
2297 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2298 k
= process_item_array(a
);
2299 if (k
< 0 && r
== 0)
2303 /* The globbing ones usually alter things, hence we apply them
2305 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2306 k
= process_item_array(a
);
2307 if (k
< 0 && r
== 0)
2312 while ((a
= ordered_hashmap_steal_first(items
)))
2315 while ((a
= ordered_hashmap_steal_first(globs
)))
2318 ordered_hashmap_free(items
);
2319 ordered_hashmap_free(globs
);
2321 free(arg_include_prefixes
);
2322 free(arg_exclude_prefixes
);
2325 set_free_free(unix_sockets
);
2327 mac_selinux_finish();
2329 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;