1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering, Kay Sievers
7 Copyright 2015 Zbigniew Jędrzejewski-Szmek
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
37 #include <sys/xattr.h>
42 #include "btrfs-util.h"
43 #include "capability.h"
44 #include "chattr-util.h"
45 #include "conf-files.h"
50 #include "formats-util.h"
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 "user-util.h"
71 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
72 * them in the file system. This is intended to be used to create
73 * properly owned directories beneath /tmp, /var/tmp, /run, which are
74 * volatile and hence need to be recreated on bootup. */
76 typedef enum ItemType
{
77 /* These ones take file names */
80 CREATE_DIRECTORY
= 'd',
81 TRUNCATE_DIRECTORY
= 'D',
82 CREATE_SUBVOLUME
= 'v',
83 CREATE_SUBVOLUME_INHERIT_QUOTA
= 'q',
84 CREATE_SUBVOLUME_NEW_QUOTA
= 'Q',
87 CREATE_CHAR_DEVICE
= 'c',
88 CREATE_BLOCK_DEVICE
= 'b',
91 /* These ones take globs */
94 RECURSIVE_SET_XATTR
= 'T',
96 RECURSIVE_SET_ACL
= 'A',
98 RECURSIVE_SET_ATTRIBUTE
= 'H',
100 IGNORE_DIRECTORY_PATH
= 'X',
102 RECURSIVE_REMOVE_PATH
= 'R',
104 RECURSIVE_RELABEL_PATH
= 'Z',
105 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
108 typedef struct Item
{
124 unsigned attribute_value
;
125 unsigned attribute_mask
;
132 bool attribute_set
:1;
134 bool keep_first_level
:1;
141 typedef struct ItemArray
{
147 static bool arg_create
= false;
148 static bool arg_clean
= false;
149 static bool arg_remove
= false;
150 static bool arg_boot
= false;
152 static char **arg_include_prefixes
= NULL
;
153 static char **arg_exclude_prefixes
= NULL
;
154 static char *arg_root
= NULL
;
156 static const char conf_file_dirs
[] = CONF_DIRS_NULSTR("tmpfiles");
158 #define MAX_DEPTH 256
160 static OrderedHashmap
*items
= NULL
, *globs
= NULL
;
161 static Set
*unix_sockets
= NULL
;
163 static const Specifier specifier_table
[] = {
164 { 'm', specifier_machine_id
, NULL
},
165 { 'b', specifier_boot_id
, NULL
},
166 { 'H', specifier_host_name
, NULL
},
167 { 'v', specifier_kernel_release
, NULL
},
171 static bool needs_glob(ItemType t
) {
175 IGNORE_DIRECTORY_PATH
,
177 RECURSIVE_REMOVE_PATH
,
180 RECURSIVE_RELABEL_PATH
,
186 RECURSIVE_SET_ATTRIBUTE
);
189 static bool takes_ownership(ItemType t
) {
196 CREATE_SUBVOLUME_INHERIT_QUOTA
,
197 CREATE_SUBVOLUME_NEW_QUOTA
,
205 IGNORE_DIRECTORY_PATH
,
207 RECURSIVE_REMOVE_PATH
);
210 static struct Item
* find_glob(OrderedHashmap
*h
, const char *match
) {
214 ORDERED_HASHMAP_FOREACH(j
, h
, i
) {
217 for (n
= 0; n
< j
->count
; n
++) {
218 Item
*item
= j
->items
+ n
;
220 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
228 static void load_unix_sockets(void) {
229 _cleanup_fclose_
FILE *f
= NULL
;
235 /* We maintain a cache of the sockets we found in
236 * /proc/net/unix to speed things up a little. */
238 unix_sockets
= set_new(&string_hash_ops
);
242 f
= fopen("/proc/net/unix", "re");
247 if (!fgets(line
, sizeof(line
), f
))
254 if (!fgets(line
, sizeof(line
), f
))
259 p
= strchr(line
, ':');
267 p
+= strspn(p
, WHITESPACE
);
268 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
269 p
+= strspn(p
, WHITESPACE
);
278 path_kill_slashes(s
);
280 k
= set_consume(unix_sockets
, s
);
281 if (k
< 0 && k
!= -EEXIST
)
288 set_free_free(unix_sockets
);
292 static bool unix_socket_alive(const char *fn
) {
298 return !!set_get(unix_sockets
, (char*) fn
);
300 /* We don't know, so assume yes */
304 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
306 union file_handle_union h
= FILE_HANDLE_INIT
;
307 int mount_id_parent
, mount_id
;
310 r_p
= name_to_handle_at(dirfd(d
), ".", &h
.handle
, &mount_id_parent
, 0);
314 h
.handle
.handle_bytes
= MAX_HANDLE_SZ
;
315 r
= name_to_handle_at(dirfd(d
), subdir
, &h
.handle
, &mount_id
, 0);
319 /* got no handle; make no assumptions, return error */
320 if (r_p
< 0 && r
< 0)
323 /* got both handles; if they differ, it is a mount point */
324 if (r_p
>= 0 && r
>= 0)
325 return mount_id_parent
!= mount_id
;
327 /* got only one handle; assume different mount points if one
328 * of both queries was not supported by the filesystem */
329 if (r_p
== -ENOSYS
|| r_p
== -EOPNOTSUPP
|| r
== -ENOSYS
|| r
== -EOPNOTSUPP
)
338 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
341 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
345 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
349 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
351 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
356 static DIR* opendir_nomod(const char *path
) {
357 return xopendirat_nomod(AT_FDCWD
, path
);
360 static int dir_cleanup(
364 const struct stat
*ds
,
369 bool keep_this_level
) {
372 struct timespec times
[2];
373 bool deleted
= false;
376 while ((dent
= readdir(d
))) {
379 _cleanup_free_
char *sub_path
= NULL
;
381 if (STR_IN_SET(dent
->d_name
, ".", ".."))
384 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
388 /* FUSE, NFS mounts, SELinux might return EACCES */
390 log_debug_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
392 log_error_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
397 /* Stay on the same filesystem */
398 if (s
.st_dev
!= rootdev
) {
399 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
403 /* Try to detect bind mounts of the same filesystem instance; they
404 * do not differ in device major/minors. This type of query is not
405 * supported on all kernels or filesystem types though. */
406 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
407 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
412 /* Do not delete read-only files owned by root */
413 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
)) {
414 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p
, dent
->d_name
);
418 sub_path
= strjoin(p
, "/", dent
->d_name
, NULL
);
424 /* Is there an item configured for this path? */
425 if (ordered_hashmap_get(items
, sub_path
)) {
426 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
430 if (find_glob(globs
, sub_path
)) {
431 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
435 if (S_ISDIR(s
.st_mode
)) {
438 streq(dent
->d_name
, "lost+found") &&
440 log_debug("Ignoring \"%s\".", sub_path
);
445 log_warning("Reached max depth on \"%s\".", sub_path
);
447 _cleanup_closedir_
DIR *sub_dir
;
450 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
453 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
458 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
463 /* Note: if you are wondering why we don't
464 * support the sticky bit for excluding
465 * directories from cleaning like we do it for
466 * other file system objects: well, the sticky
467 * bit already has a meaning for directories,
468 * so we don't want to overload that. */
470 if (keep_this_level
) {
471 log_debug("Keeping \"%s\".", sub_path
);
475 /* Ignore ctime, we change it when deleting */
476 age
= timespec_load(&s
.st_mtim
);
478 char a
[FORMAT_TIMESTAMP_MAX
];
479 /* Follows spelling in stat(1). */
480 log_debug("Directory \"%s\": modify time %s is too new.",
482 format_timestamp_us(a
, sizeof(a
), age
));
486 age
= timespec_load(&s
.st_atim
);
488 char a
[FORMAT_TIMESTAMP_MAX
];
489 log_debug("Directory \"%s\": access time %s is too new.",
491 format_timestamp_us(a
, sizeof(a
), age
));
495 log_debug("Removing directory \"%s\".", sub_path
);
496 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
497 if (errno
!= ENOENT
&& errno
!= ENOTEMPTY
) {
498 log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
503 /* Skip files for which the sticky bit is
504 * set. These are semantics we define, and are
505 * unknown elsewhere. See XDG_RUNTIME_DIR
506 * specification for details. */
507 if (s
.st_mode
& S_ISVTX
) {
508 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
512 if (mountpoint
&& S_ISREG(s
.st_mode
))
513 if (s
.st_uid
== 0 && STR_IN_SET(dent
->d_name
,
517 log_debug("Skipping \"%s\".", sub_path
);
521 /* Ignore sockets that are listed in /proc/net/unix */
522 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
523 log_debug("Skipping \"%s\": live socket.", sub_path
);
527 /* Ignore device nodes */
528 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
529 log_debug("Skipping \"%s\": a device.", sub_path
);
533 /* Keep files on this level around if this is
535 if (keep_this_level
) {
536 log_debug("Keeping \"%s\".", sub_path
);
540 age
= timespec_load(&s
.st_mtim
);
542 char a
[FORMAT_TIMESTAMP_MAX
];
543 /* Follows spelling in stat(1). */
544 log_debug("File \"%s\": modify time %s is too new.",
546 format_timestamp_us(a
, sizeof(a
), age
));
550 age
= timespec_load(&s
.st_atim
);
552 char a
[FORMAT_TIMESTAMP_MAX
];
553 log_debug("File \"%s\": access time %s is too new.",
555 format_timestamp_us(a
, sizeof(a
), age
));
559 age
= timespec_load(&s
.st_ctim
);
561 char a
[FORMAT_TIMESTAMP_MAX
];
562 log_debug("File \"%s\": change time %s is too new.",
564 format_timestamp_us(a
, sizeof(a
), age
));
568 log_debug("unlink \"%s\"", sub_path
);
570 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
572 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
581 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
583 /* Restore original directory timestamps */
584 times
[0] = ds
->st_atim
;
585 times
[1] = ds
->st_mtim
;
587 age1
= timespec_load(&ds
->st_atim
);
588 age2
= timespec_load(&ds
->st_mtim
);
589 log_debug("Restoring access and modification time on \"%s\": %s, %s",
591 format_timestamp_us(a
, sizeof(a
), age1
),
592 format_timestamp_us(b
, sizeof(b
), age2
));
593 if (futimens(dirfd(d
), times
) < 0)
594 log_error_errno(errno
, "utimensat(%s): %m", p
);
600 static int path_set_perms(Item
*i
, const char *path
) {
601 _cleanup_close_
int fd
= -1;
607 /* We open the file with O_PATH here, to make the operation
608 * somewhat atomic. Also there's unfortunately no fchmodat()
609 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
612 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
614 return log_error_errno(errno
, "Adjusting owner and mode for %s failed: %m", path
);
616 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
617 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
619 if (S_ISLNK(st
.st_mode
))
620 log_debug("Skipping mode an owner fix for symlink %s.", path
);
622 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
623 xsprintf(fn
, "/proc/self/fd/%i", fd
);
625 /* not using i->path directly because it may be a glob */
630 if (!(st
.st_mode
& 0111))
632 if (!(st
.st_mode
& 0222))
634 if (!(st
.st_mode
& 0444))
636 if (!S_ISDIR(st
.st_mode
))
637 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
640 if (m
== (st
.st_mode
& 07777))
641 log_debug("\"%s\" has right mode %o", path
, st
.st_mode
);
643 log_debug("chmod \"%s\" to mode %o", path
, m
);
644 if (chmod(fn
, m
) < 0)
645 return log_error_errno(errno
, "chmod(%s) failed: %m", path
);
649 if ((i
->uid
!= st
.st_uid
|| i
->gid
!= st
.st_gid
) &&
650 (i
->uid_set
|| i
->gid_set
)) {
651 log_debug("chown \"%s\" to "UID_FMT
"."GID_FMT
,
653 i
->uid_set
? i
->uid
: UID_INVALID
,
654 i
->gid_set
? i
->gid
: GID_INVALID
);
656 i
->uid_set
? i
->uid
: UID_INVALID
,
657 i
->gid_set
? i
->gid
: GID_INVALID
) < 0)
658 return log_error_errno(errno
, "chown(%s) failed: %m", path
);
664 return label_fix(path
, false, false);
667 static int parse_xattrs_from_arg(Item
*i
) {
677 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
, *xattr_replaced
= NULL
;
679 r
= extract_first_word(&p
, &xattr
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
681 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
685 r
= specifier_printf(xattr
, specifier_table
, NULL
, &xattr_replaced
);
687 return log_error_errno(r
, "Failed to replace specifiers in extended attribute '%s': %m", xattr
);
689 r
= split_pair(xattr_replaced
, "=", &name
, &value
);
691 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
695 if (isempty(name
) || isempty(value
)) {
696 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
700 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
709 static int path_set_xattrs(Item
*i
, const char *path
) {
710 char **name
, **value
;
715 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
719 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
720 if (lsetxattr(path
, *name
, *value
, n
, 0) < 0) {
721 log_error("Setting extended attribute %s=%s on %s failed: %m", *name
, *value
, path
);
728 static int parse_acls_from_arg(Item
*item
) {
734 /* If force (= modify) is set, we will not modify the acl
735 * afterwards, so the mask can be added now if necessary. */
737 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
739 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
741 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
748 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
749 _cleanup_(acl_free_charpp
) char *t
= NULL
;
750 _cleanup_(acl_freep
) acl_t dup
= NULL
;
753 /* Returns 0 for success, positive error if already warned,
754 * negative error otherwise. */
757 r
= acls_for_file(path
, type
, acl
, &dup
);
761 r
= calc_acl_mask_if_needed(&dup
);
769 /* the mask was already added earlier if needed */
772 r
= add_base_acls_if_needed(&dup
, path
);
776 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
777 log_debug("Setting %s ACL %s on %s.",
778 type
== ACL_TYPE_ACCESS
? "access" : "default",
781 r
= acl_set_file(path
, type
, dup
);
783 /* Return positive to indicate we already warned */
784 return -log_error_errno(errno
,
785 "Setting %s ACL \"%s\" on %s failed: %m",
786 type
== ACL_TYPE_ACCESS
? "access" : "default",
793 static int path_set_acls(Item
*item
, const char *path
) {
796 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
797 _cleanup_close_
int fd
= -1;
803 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
805 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
807 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
808 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
810 if (S_ISLNK(st
.st_mode
)) {
811 log_debug("Skipping ACL fix for symlink %s.", path
);
815 xsprintf(fn
, "/proc/self/fd/%i", fd
);
817 if (item
->acl_access
)
818 r
= path_set_acl(fn
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
820 if (r
== 0 && item
->acl_default
)
821 r
= path_set_acl(fn
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
824 return -r
; /* already warned */
825 else if (r
== -EOPNOTSUPP
) {
826 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
829 log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
834 #define ATTRIBUTES_ALL \
843 FS_JOURNAL_DATA_FL | \
850 static int parse_attribute_from_arg(Item
*item
) {
852 static const struct {
856 { 'A', FS_NOATIME_FL
}, /* do not update atime */
857 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
858 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
859 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
860 { 'c', FS_COMPR_FL
}, /* Compress file */
861 { 'd', FS_NODUMP_FL
}, /* do not dump file */
862 { 'e', FS_EXTENT_FL
}, /* Top of directory hierarchies*/
863 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
864 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
865 { 's', FS_SECRM_FL
}, /* Secure deletion */
866 { 'u', FS_UNRM_FL
}, /* Undelete */
867 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
868 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies*/
869 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
878 unsigned value
= 0, mask
= 0;
888 } else if (*p
== '-') {
891 } else if (*p
== '=') {
897 if (isempty(p
) && mode
!= MODE_SET
) {
898 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
902 for (; p
&& *p
; p
++) {
905 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
906 if (*p
== attributes
[i
].character
)
909 if (i
>= ELEMENTSOF(attributes
)) {
910 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
914 v
= attributes
[i
].value
;
916 if (mode
== MODE_ADD
|| mode
== MODE_SET
)
924 if (mode
== MODE_SET
)
925 mask
|= ATTRIBUTES_ALL
;
929 item
->attribute_mask
= mask
;
930 item
->attribute_value
= value
;
931 item
->attribute_set
= true;
936 static int path_set_attribute(Item
*item
, const char *path
) {
937 _cleanup_close_
int fd
= -1;
942 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
945 fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
|O_NOATIME
|O_NOFOLLOW
);
948 return log_error_errno(errno
, "Skipping file attributes adjustment on symlink %s.", path
);
950 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
953 if (fstat(fd
, &st
) < 0)
954 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
956 /* Issuing the file attribute ioctls on device nodes is not
957 * safe, as that will be delivered to the drivers, not the
958 * file system containing the device node. */
959 if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
)) {
960 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
964 f
= item
->attribute_value
& item
->attribute_mask
;
966 /* Mask away directory-specific flags */
967 if (!S_ISDIR(st
.st_mode
))
970 r
= chattr_fd(fd
, f
, item
->attribute_mask
);
972 log_full_errno(r
== -ENOTTY
? LOG_DEBUG
: LOG_WARNING
,
974 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
975 path
, item
->attribute_value
, item
->attribute_mask
);
980 static int write_one_file(Item
*i
, const char *path
) {
981 _cleanup_close_
int fd
= -1;
988 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
|O_NOFOLLOW
:
989 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
991 RUN_WITH_UMASK(0000) {
992 mac_selinux_create_file_prepare(path
, S_IFREG
);
993 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
994 mac_selinux_create_file_clear();
998 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
999 log_debug_errno(errno
, "Not writing \"%s\": %m", path
);
1004 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
1005 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
1008 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1012 _cleanup_free_
char *unescaped
= NULL
, *replaced
= NULL
;
1014 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1016 r
= cunescape(i
->argument
, 0, &unescaped
);
1018 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
1020 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &replaced
);
1022 return log_error_errno(r
, "Failed to replace specifiers in parameter to write '%s': %m", unescaped
);
1024 r
= loop_write(fd
, replaced
, strlen(replaced
), false);
1026 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1028 log_debug("\"%s\" has been created.", path
);
1030 fd
= safe_close(fd
);
1032 if (stat(path
, &st
) < 0)
1033 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1036 if (!S_ISREG(st
.st_mode
)) {
1037 log_error("%s is not a file.", path
);
1041 r
= path_set_perms(i
, path
);
1048 typedef int (*action_t
)(Item
*, const char *);
1050 static int item_do_children(Item
*i
, const char *path
, action_t action
) {
1051 _cleanup_closedir_
DIR *d
;
1057 /* This returns the first error we run into, but nevertheless
1060 d
= opendir_nomod(path
);
1062 return errno
== ENOENT
|| errno
== ENOTDIR
? 0 : -errno
;
1065 _cleanup_free_
char *p
= NULL
;
1072 if (errno
!= 0 && r
== 0)
1078 if (STR_IN_SET(de
->d_name
, ".", ".."))
1081 p
= strjoin(path
, "/", de
->d_name
, NULL
);
1086 if (q
< 0 && q
!= -ENOENT
&& r
== 0)
1089 if (IN_SET(de
->d_type
, DT_UNKNOWN
, DT_DIR
)) {
1090 q
= item_do_children(i
, p
, action
);
1091 if (q
< 0 && r
== 0)
1099 static int glob_item(Item
*i
, action_t action
, bool recursive
) {
1100 _cleanup_globfree_ glob_t g
= {
1101 .gl_closedir
= (void (*)(void *)) closedir
,
1102 .gl_readdir
= (struct dirent
*(*)(void *)) readdir
,
1103 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1111 k
= glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
|GLOB_ALTDIRFUNC
, NULL
, &g
);
1112 if (k
!= 0 && k
!= GLOB_NOMATCH
)
1113 return log_error_errno(errno
?: EIO
, "glob(%s) failed: %m", i
->path
);
1115 STRV_FOREACH(fn
, g
.gl_pathv
) {
1117 if (k
< 0 && r
== 0)
1121 k
= item_do_children(i
, *fn
, action
);
1122 if (k
< 0 && r
== 0)
1135 _CREATION_MODE_INVALID
= -1
1138 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1139 [CREATION_NORMAL
] = "Created",
1140 [CREATION_EXISTING
] = "Found existing",
1141 [CREATION_FORCE
] = "Created replacement",
1144 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1146 static int create_item(Item
*i
) {
1147 _cleanup_free_
char *resolved
= NULL
;
1150 CreationMode creation
;
1154 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1159 case IGNORE_DIRECTORY_PATH
:
1161 case RECURSIVE_REMOVE_PATH
:
1166 r
= write_one_file(i
, i
->path
);
1172 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1174 return log_error_errno(r
, "Failed to substitute specifiers in copy source %s: %m", i
->argument
);
1176 log_debug("Copying tree \"%s\" to \"%s\".", resolved
, i
->path
);
1177 r
= copy_tree(resolved
, i
->path
, false);
1179 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1186 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1188 if (stat(resolved
, &a
) < 0)
1189 return log_error_errno(errno
, "stat(%s) failed: %m", resolved
);
1191 if (stat(i
->path
, &b
) < 0)
1192 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1194 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1195 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1200 r
= path_set_perms(i
, i
->path
);
1207 r
= glob_item(i
, write_one_file
, false);
1213 case CREATE_DIRECTORY
:
1214 case TRUNCATE_DIRECTORY
:
1215 case CREATE_SUBVOLUME
:
1216 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1217 case CREATE_SUBVOLUME_NEW_QUOTA
:
1219 RUN_WITH_UMASK(0000)
1220 mkdir_parents_label(i
->path
, 0755);
1222 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1223 RUN_WITH_UMASK((~i
->mode
) & 0777)
1224 r
= btrfs_subvol_make(i
->path
);
1228 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1229 RUN_WITH_UMASK(0000)
1230 r
= mkdir_label(i
->path
, i
->mode
);
1235 if (r
!= -EEXIST
&& r
!= -EROFS
)
1236 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1238 k
= is_dir(i
->path
, false);
1239 if (k
== -ENOENT
&& r
== -EROFS
)
1240 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1242 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1244 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1248 creation
= CREATION_EXISTING
;
1250 creation
= CREATION_NORMAL
;
1252 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1254 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1255 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1257 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
);
1261 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i
->path
);
1265 return log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1267 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1269 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1272 r
= path_set_perms(i
, i
->path
);
1280 RUN_WITH_UMASK(0000) {
1281 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1282 r
= mkfifo(i
->path
, i
->mode
);
1283 mac_selinux_create_file_clear();
1287 if (errno
!= EEXIST
)
1288 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1290 if (lstat(i
->path
, &st
) < 0)
1291 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1293 if (!S_ISFIFO(st
.st_mode
)) {
1296 RUN_WITH_UMASK(0000) {
1297 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1298 r
= mkfifo_atomic(i
->path
, i
->mode
);
1299 mac_selinux_create_file_clear();
1303 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1304 creation
= CREATION_FORCE
;
1306 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1310 creation
= CREATION_EXISTING
;
1312 creation
= CREATION_NORMAL
;
1313 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1315 r
= path_set_perms(i
, i
->path
);
1322 case CREATE_SYMLINK
: {
1323 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1325 return log_error_errno(r
, "Failed to substitute specifiers in symlink target %s: %m", i
->argument
);
1327 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1328 r
= symlink(resolved
, i
->path
);
1329 mac_selinux_create_file_clear();
1332 _cleanup_free_
char *x
= NULL
;
1334 if (errno
!= EEXIST
)
1335 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1337 r
= readlink_malloc(i
->path
, &x
);
1338 if (r
< 0 || !streq(resolved
, x
)) {
1341 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1342 r
= symlink_atomic(resolved
, i
->path
);
1343 mac_selinux_create_file_clear();
1346 return log_error_errno(r
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1348 creation
= CREATION_FORCE
;
1350 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1354 creation
= CREATION_EXISTING
;
1357 creation
= CREATION_NORMAL
;
1358 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1362 case CREATE_BLOCK_DEVICE
:
1363 case CREATE_CHAR_DEVICE
: {
1366 if (have_effective_cap(CAP_MKNOD
) == 0) {
1367 /* In a container we lack CAP_MKNOD. We
1368 shouldn't attempt to create the device node in
1369 that case to avoid noise, and we don't support
1370 virtualized devices in containers anyway. */
1372 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1376 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1378 RUN_WITH_UMASK(0000) {
1379 mac_selinux_create_file_prepare(i
->path
, file_type
);
1380 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1381 mac_selinux_create_file_clear();
1385 if (errno
== EPERM
) {
1386 log_debug("We lack permissions, possibly because of cgroup configuration; "
1387 "skipping creation of device node %s.", i
->path
);
1391 if (errno
!= EEXIST
)
1392 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1394 if (lstat(i
->path
, &st
) < 0)
1395 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1397 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1401 RUN_WITH_UMASK(0000) {
1402 mac_selinux_create_file_prepare(i
->path
, file_type
);
1403 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1404 mac_selinux_create_file_clear();
1408 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1409 creation
= CREATION_FORCE
;
1411 log_debug("%s is not a device node.", i
->path
);
1415 creation
= CREATION_EXISTING
;
1417 creation
= CREATION_NORMAL
;
1419 log_debug("%s %s device node \"%s\" %u:%u.",
1420 creation_mode_verb_to_string(creation
),
1421 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1422 i
->path
, major(i
->mode
), minor(i
->mode
));
1424 r
= path_set_perms(i
, i
->path
);
1433 r
= glob_item(i
, path_set_perms
, false);
1438 case RECURSIVE_RELABEL_PATH
:
1439 r
= glob_item(i
, path_set_perms
, true);
1445 r
= glob_item(i
, path_set_xattrs
, false);
1450 case RECURSIVE_SET_XATTR
:
1451 r
= glob_item(i
, path_set_xattrs
, true);
1457 r
= glob_item(i
, path_set_acls
, false);
1462 case RECURSIVE_SET_ACL
:
1463 r
= glob_item(i
, path_set_acls
, true);
1469 r
= glob_item(i
, path_set_attribute
, false);
1474 case RECURSIVE_SET_ATTRIBUTE
:
1475 r
= glob_item(i
, path_set_attribute
, true);
1484 static int remove_item_instance(Item
*i
, const char *instance
) {
1492 if (remove(instance
) < 0 && errno
!= ENOENT
)
1493 return log_error_errno(errno
, "rm(%s): %m", instance
);
1497 case TRUNCATE_DIRECTORY
:
1498 case RECURSIVE_REMOVE_PATH
:
1499 /* FIXME: we probably should use dir_cleanup() here
1500 * instead of rm_rf() so that 'x' is honoured. */
1501 log_debug("rm -rf \"%s\"", instance
);
1502 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1503 if (r
< 0 && r
!= -ENOENT
)
1504 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1509 assert_not_reached("wut?");
1515 static int remove_item(Item
*i
) {
1520 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1526 case CREATE_DIRECTORY
:
1527 case CREATE_SUBVOLUME
:
1528 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1529 case CREATE_SUBVOLUME_NEW_QUOTA
:
1531 case CREATE_SYMLINK
:
1532 case CREATE_CHAR_DEVICE
:
1533 case CREATE_BLOCK_DEVICE
:
1535 case IGNORE_DIRECTORY_PATH
:
1538 case RECURSIVE_RELABEL_PATH
:
1542 case RECURSIVE_SET_XATTR
:
1544 case RECURSIVE_SET_ACL
:
1546 case RECURSIVE_SET_ATTRIBUTE
:
1550 case TRUNCATE_DIRECTORY
:
1551 case RECURSIVE_REMOVE_PATH
:
1552 r
= glob_item(i
, remove_item_instance
, false);
1559 static int clean_item_instance(Item
*i
, const char* instance
) {
1560 _cleanup_closedir_
DIR *d
= NULL
;
1564 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1571 n
= now(CLOCK_REALTIME
);
1575 cutoff
= n
- i
->age
;
1577 d
= opendir_nomod(instance
);
1579 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
1580 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1584 log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1588 if (fstat(dirfd(d
), &s
) < 0)
1589 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1591 if (!S_ISDIR(s
.st_mode
)) {
1592 log_error("%s is not a directory.", i
->path
);
1596 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1597 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1599 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1601 log_debug("Cleanup threshold for %s \"%s\" is %s",
1602 mountpoint
? "mount point" : "directory",
1604 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1606 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1607 MAX_DEPTH
, i
->keep_first_level
);
1610 static int clean_item(Item
*i
) {
1615 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1618 case CREATE_DIRECTORY
:
1619 case CREATE_SUBVOLUME
:
1620 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1621 case CREATE_SUBVOLUME_NEW_QUOTA
:
1622 case TRUNCATE_DIRECTORY
:
1625 clean_item_instance(i
, i
->path
);
1627 case IGNORE_DIRECTORY_PATH
:
1628 r
= glob_item(i
, clean_item_instance
, false);
1637 static int process_item_array(ItemArray
*array
);
1639 static int process_item(Item
*i
) {
1641 _cleanup_free_
char *prefix
= NULL
;
1650 prefix
= malloc(strlen(i
->path
) + 1);
1654 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1657 j
= ordered_hashmap_get(items
, prefix
);
1661 s
= process_item_array(j
);
1662 if (s
< 0 && t
== 0)
1667 r
= arg_create
? create_item(i
) : 0;
1668 q
= arg_remove
? remove_item(i
) : 0;
1669 p
= arg_clean
? clean_item(i
) : 0;
1677 static int process_item_array(ItemArray
*array
) {
1683 for (n
= 0; n
< array
->count
; n
++) {
1684 k
= process_item(array
->items
+ n
);
1685 if (k
< 0 && r
== 0)
1692 static void item_free_contents(Item
*i
) {
1696 strv_free(i
->xattrs
);
1699 acl_free(i
->acl_access
);
1700 acl_free(i
->acl_default
);
1704 static void item_array_free(ItemArray
*a
) {
1710 for (n
= 0; n
< a
->count
; n
++)
1711 item_free_contents(a
->items
+ n
);
1716 static int item_compare(const void *a
, const void *b
) {
1717 const Item
*x
= a
, *y
= b
;
1719 /* Make sure that the ownership taking item is put first, so
1720 * that we first create the node, and then can adjust it */
1722 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1724 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1727 return (int) x
->type
- (int) y
->type
;
1730 static bool item_compatible(Item
*a
, Item
*b
) {
1733 assert(streq(a
->path
, b
->path
));
1735 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1736 /* check if the items are the same */
1737 return streq_ptr(a
->argument
, b
->argument
) &&
1739 a
->uid_set
== b
->uid_set
&&
1742 a
->gid_set
== b
->gid_set
&&
1745 a
->mode_set
== b
->mode_set
&&
1746 a
->mode
== b
->mode
&&
1748 a
->age_set
== b
->age_set
&&
1751 a
->mask_perms
== b
->mask_perms
&&
1753 a
->keep_first_level
== b
->keep_first_level
&&
1755 a
->major_minor
== b
->major_minor
;
1760 static bool should_include_path(const char *path
) {
1763 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1764 if (path_startswith(path
, *prefix
)) {
1765 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1770 STRV_FOREACH(prefix
, arg_include_prefixes
)
1771 if (path_startswith(path
, *prefix
)) {
1772 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1776 /* no matches, so we should include this path only if we
1777 * have no whitelist at all */
1778 if (strv_length(arg_include_prefixes
) == 0)
1781 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1785 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1787 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1788 _cleanup_(item_free_contents
) Item i
= {};
1789 ItemArray
*existing
;
1792 bool force
= false, boot
= false;
1798 r
= extract_many_words(
1810 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1812 log_error("[%s:%u] Syntax error.", fname
, line
);
1816 if (!isempty(buffer
) && !streq(buffer
, "-")) {
1817 i
.argument
= strdup(buffer
);
1822 if (isempty(action
)) {
1823 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1827 for (pos
= 1; action
[pos
]; pos
++) {
1828 if (action
[pos
] == '!' && !boot
)
1830 else if (action
[pos
] == '+' && !force
)
1833 log_error("[%s:%u] Unknown modifiers in command '%s'",
1834 fname
, line
, action
);
1839 if (boot
&& !arg_boot
) {
1840 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1848 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1850 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1856 case CREATE_DIRECTORY
:
1857 case CREATE_SUBVOLUME
:
1858 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1859 case CREATE_SUBVOLUME_NEW_QUOTA
:
1860 case TRUNCATE_DIRECTORY
:
1863 case IGNORE_DIRECTORY_PATH
:
1865 case RECURSIVE_REMOVE_PATH
:
1868 case RECURSIVE_RELABEL_PATH
:
1870 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
1878 case CREATE_SYMLINK
:
1880 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1888 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1895 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1898 } else if (!path_is_absolute(i
.argument
)) {
1899 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1903 path_kill_slashes(i
.argument
);
1906 case CREATE_CHAR_DEVICE
:
1907 case CREATE_BLOCK_DEVICE
: {
1908 unsigned major
, minor
;
1911 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1915 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1916 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1920 i
.major_minor
= makedev(major
, minor
);
1925 case RECURSIVE_SET_XATTR
:
1927 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1930 r
= parse_xattrs_from_arg(&i
);
1936 case RECURSIVE_SET_ACL
:
1938 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
1941 r
= parse_acls_from_arg(&i
);
1947 case RECURSIVE_SET_ATTRIBUTE
:
1949 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
1952 r
= parse_attribute_from_arg(&i
);
1958 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
1962 if (!path_is_absolute(i
.path
)) {
1963 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
1967 path_kill_slashes(i
.path
);
1969 if (!should_include_path(i
.path
))
1975 p
= prefix_root(arg_root
, i
.path
);
1983 if (!isempty(user
) && !streq(user
, "-")) {
1984 const char *u
= user
;
1986 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
1988 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
1995 if (!isempty(group
) && !streq(group
, "-")) {
1996 const char *g
= group
;
1998 r
= get_group_creds(&g
, &i
.gid
);
2000 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2007 if (!isempty(mode
) && !streq(mode
, "-")) {
2008 const char *mm
= mode
;
2012 i
.mask_perms
= true;
2016 if (parse_mode(mm
, &m
) < 0) {
2017 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2024 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2026 if (!isempty(age
) && !streq(age
, "-")) {
2027 const char *a
= age
;
2030 i
.keep_first_level
= true;
2034 if (parse_sec(a
, &i
.age
) < 0) {
2035 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2042 h
= needs_glob(i
.type
) ? globs
: items
;
2044 existing
= ordered_hashmap_get(h
, i
.path
);
2048 for (n
= 0; n
< existing
->count
; n
++) {
2049 if (!item_compatible(existing
->items
+ n
, &i
)) {
2050 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2051 fname
, line
, i
.path
);
2056 existing
= new0(ItemArray
, 1);
2057 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2062 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2065 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2067 /* Sort item array, to enforce stable ordering of application */
2068 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2074 static void help(void) {
2075 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2076 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2077 " -h --help Show this help\n"
2078 " --version Show package version\n"
2079 " --create Create marked files/directories\n"
2080 " --clean Clean up marked directories\n"
2081 " --remove Remove marked files/directories\n"
2082 " --boot Execute actions only safe at boot\n"
2083 " --prefix=PATH Only apply rules with the specified prefix\n"
2084 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2085 " --root=PATH Operate on an alternate filesystem root\n",
2086 program_invocation_short_name
);
2089 static int parse_argv(int argc
, char *argv
[]) {
2092 ARG_VERSION
= 0x100,
2102 static const struct option options
[] = {
2103 { "help", no_argument
, NULL
, 'h' },
2104 { "version", no_argument
, NULL
, ARG_VERSION
},
2105 { "create", no_argument
, NULL
, ARG_CREATE
},
2106 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2107 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2108 { "boot", no_argument
, NULL
, ARG_BOOT
},
2109 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2110 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2111 { "root", required_argument
, NULL
, ARG_ROOT
},
2120 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2148 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2152 case ARG_EXCLUDE_PREFIX
:
2153 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2158 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2167 assert_not_reached("Unhandled option");
2170 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2171 log_error("You need to specify at least one of --clean, --create or --remove.");
2178 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2179 _cleanup_fclose_
FILE *f
= NULL
;
2180 char line
[LINE_MAX
];
2188 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &f
);
2190 if (ignore_enoent
&& r
== -ENOENT
) {
2191 log_debug_errno(r
, "Failed to open \"%s\": %m", fn
);
2195 return log_error_errno(r
, "Failed to open '%s', ignoring: %m", fn
);
2197 log_debug("Reading config file \"%s\".", fn
);
2199 FOREACH_LINE(line
, f
, break) {
2206 if (*l
== '#' || *l
== 0)
2209 k
= parse_line(fn
, v
, l
);
2210 if (k
< 0 && r
== 0)
2214 /* we have to determine age parameter for each entry of type X */
2215 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2217 Item
*j
, *candidate_item
= NULL
;
2219 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2222 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2223 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2226 if (path_equal(j
->path
, i
->path
)) {
2231 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2232 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2236 if (candidate_item
&& candidate_item
->age_set
) {
2237 i
->age
= candidate_item
->age
;
2243 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2251 int main(int argc
, char *argv
[]) {
2256 r
= parse_argv(argc
, argv
);
2260 log_set_target(LOG_TARGET_AUTO
);
2261 log_parse_environment();
2266 mac_selinux_init(NULL
);
2268 items
= ordered_hashmap_new(&string_hash_ops
);
2269 globs
= ordered_hashmap_new(&string_hash_ops
);
2271 if (!items
|| !globs
) {
2278 if (optind
< argc
) {
2281 for (j
= optind
; j
< argc
; j
++) {
2282 k
= read_config_file(argv
[j
], false);
2283 if (k
< 0 && r
== 0)
2288 _cleanup_strv_free_
char **files
= NULL
;
2291 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, conf_file_dirs
);
2293 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2297 STRV_FOREACH(f
, files
) {
2298 k
= read_config_file(*f
, true);
2299 if (k
< 0 && r
== 0)
2304 /* The non-globbing ones usually create things, hence we apply
2306 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2307 k
= process_item_array(a
);
2308 if (k
< 0 && r
== 0)
2312 /* The globbing ones usually alter things, hence we apply them
2314 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2315 k
= process_item_array(a
);
2316 if (k
< 0 && r
== 0)
2321 while ((a
= ordered_hashmap_steal_first(items
)))
2324 while ((a
= ordered_hashmap_steal_first(globs
)))
2327 ordered_hashmap_free(items
);
2328 ordered_hashmap_free(globs
);
2330 free(arg_include_prefixes
);
2331 free(arg_exclude_prefixes
);
2334 set_free_free(unix_sockets
);
2336 mac_selinux_finish();
2338 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;