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 "alloc-util.h"
43 #include "btrfs-util.h"
44 #include "capability-util.h"
45 #include "chattr-util.h"
46 #include "conf-files.h"
52 #include "formats-util.h"
54 #include "glob-util.h"
61 #include "mount-util.h"
62 #include "parse-util.h"
63 #include "path-util.h"
65 #include "selinux-util.h"
67 #include "specifier.h"
68 #include "stat-util.h"
69 #include "stdio-util.h"
70 #include "string-table.h"
71 #include "string-util.h"
73 #include "umask-util.h"
74 #include "user-util.h"
77 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
78 * them in the file system. This is intended to be used to create
79 * properly owned directories beneath /tmp, /var/tmp, /run, which are
80 * volatile and hence need to be recreated on bootup. */
82 typedef enum ItemType
{
83 /* These ones take file names */
86 CREATE_DIRECTORY
= 'd',
87 TRUNCATE_DIRECTORY
= 'D',
88 CREATE_SUBVOLUME
= 'v',
89 CREATE_SUBVOLUME_INHERIT_QUOTA
= 'q',
90 CREATE_SUBVOLUME_NEW_QUOTA
= 'Q',
93 CREATE_CHAR_DEVICE
= 'c',
94 CREATE_BLOCK_DEVICE
= 'b',
97 /* These ones take globs */
100 RECURSIVE_SET_XATTR
= 'T',
102 RECURSIVE_SET_ACL
= 'A',
104 RECURSIVE_SET_ATTRIBUTE
= 'H',
106 IGNORE_DIRECTORY_PATH
= 'X',
108 RECURSIVE_REMOVE_PATH
= 'R',
110 RECURSIVE_RELABEL_PATH
= 'Z',
111 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
114 typedef struct Item
{
130 unsigned attribute_value
;
131 unsigned attribute_mask
;
138 bool attribute_set
:1;
140 bool keep_first_level
:1;
147 typedef struct ItemArray
{
153 static bool arg_create
= false;
154 static bool arg_clean
= false;
155 static bool arg_remove
= false;
156 static bool arg_boot
= false;
158 static char **arg_include_prefixes
= NULL
;
159 static char **arg_exclude_prefixes
= NULL
;
160 static char *arg_root
= NULL
;
162 static const char conf_file_dirs
[] = CONF_PATHS_NULSTR("tmpfiles.d");
164 #define MAX_DEPTH 256
166 static OrderedHashmap
*items
= NULL
, *globs
= NULL
;
167 static Set
*unix_sockets
= NULL
;
169 static const Specifier specifier_table
[] = {
170 { 'm', specifier_machine_id
, NULL
},
171 { 'b', specifier_boot_id
, NULL
},
172 { 'H', specifier_host_name
, NULL
},
173 { 'v', specifier_kernel_release
, NULL
},
177 static bool needs_glob(ItemType t
) {
181 IGNORE_DIRECTORY_PATH
,
183 RECURSIVE_REMOVE_PATH
,
186 RECURSIVE_RELABEL_PATH
,
192 RECURSIVE_SET_ATTRIBUTE
);
195 static bool takes_ownership(ItemType t
) {
202 CREATE_SUBVOLUME_INHERIT_QUOTA
,
203 CREATE_SUBVOLUME_NEW_QUOTA
,
211 IGNORE_DIRECTORY_PATH
,
213 RECURSIVE_REMOVE_PATH
);
216 static struct Item
* find_glob(OrderedHashmap
*h
, const char *match
) {
220 ORDERED_HASHMAP_FOREACH(j
, h
, i
) {
223 for (n
= 0; n
< j
->count
; n
++) {
224 Item
*item
= j
->items
+ n
;
226 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
234 static void load_unix_sockets(void) {
235 _cleanup_fclose_
FILE *f
= NULL
;
241 /* We maintain a cache of the sockets we found in
242 * /proc/net/unix to speed things up a little. */
244 unix_sockets
= set_new(&string_hash_ops
);
248 f
= fopen("/proc/net/unix", "re");
253 if (!fgets(line
, sizeof(line
), f
))
260 if (!fgets(line
, sizeof(line
), f
))
265 p
= strchr(line
, ':');
273 p
+= strspn(p
, WHITESPACE
);
274 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
275 p
+= strspn(p
, WHITESPACE
);
284 path_kill_slashes(s
);
286 k
= set_consume(unix_sockets
, s
);
287 if (k
< 0 && k
!= -EEXIST
)
294 set_free_free(unix_sockets
);
298 static bool unix_socket_alive(const char *fn
) {
304 return !!set_get(unix_sockets
, (char*) fn
);
306 /* We don't know, so assume yes */
310 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
312 union file_handle_union h
= FILE_HANDLE_INIT
;
313 int mount_id_parent
, mount_id
;
316 r_p
= name_to_handle_at(dirfd(d
), ".", &h
.handle
, &mount_id_parent
, 0);
320 h
.handle
.handle_bytes
= MAX_HANDLE_SZ
;
321 r
= name_to_handle_at(dirfd(d
), subdir
, &h
.handle
, &mount_id
, 0);
325 /* got no handle; make no assumptions, return error */
326 if (r_p
< 0 && r
< 0)
329 /* got both handles; if they differ, it is a mount point */
330 if (r_p
>= 0 && r
>= 0)
331 return mount_id_parent
!= mount_id
;
333 /* got only one handle; assume different mount points if one
334 * of both queries was not supported by the filesystem */
335 if (r_p
== -ENOSYS
|| r_p
== -EOPNOTSUPP
|| r
== -ENOSYS
|| r
== -EOPNOTSUPP
)
344 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
347 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
351 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
355 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
357 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
362 static DIR* opendir_nomod(const char *path
) {
363 return xopendirat_nomod(AT_FDCWD
, path
);
366 static int dir_cleanup(
370 const struct stat
*ds
,
375 bool keep_this_level
) {
378 struct timespec times
[2];
379 bool deleted
= false;
382 while ((dent
= readdir(d
))) {
385 _cleanup_free_
char *sub_path
= NULL
;
387 if (STR_IN_SET(dent
->d_name
, ".", ".."))
390 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
394 /* FUSE, NFS mounts, SELinux might return EACCES */
396 log_debug_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
398 log_error_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
403 /* Stay on the same filesystem */
404 if (s
.st_dev
!= rootdev
) {
405 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
409 /* Try to detect bind mounts of the same filesystem instance; they
410 * do not differ in device major/minors. This type of query is not
411 * supported on all kernels or filesystem types though. */
412 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
413 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
418 /* Do not delete read-only files owned by root */
419 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
)) {
420 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p
, dent
->d_name
);
424 sub_path
= strjoin(p
, "/", dent
->d_name
, NULL
);
430 /* Is there an item configured for this path? */
431 if (ordered_hashmap_get(items
, sub_path
)) {
432 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
436 if (find_glob(globs
, sub_path
)) {
437 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
441 if (S_ISDIR(s
.st_mode
)) {
444 streq(dent
->d_name
, "lost+found") &&
446 log_debug("Ignoring \"%s\".", sub_path
);
451 log_warning("Reached max depth on \"%s\".", sub_path
);
453 _cleanup_closedir_
DIR *sub_dir
;
456 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
459 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
464 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
469 /* Note: if you are wondering why we don't
470 * support the sticky bit for excluding
471 * directories from cleaning like we do it for
472 * other file system objects: well, the sticky
473 * bit already has a meaning for directories,
474 * so we don't want to overload that. */
476 if (keep_this_level
) {
477 log_debug("Keeping \"%s\".", sub_path
);
481 /* Ignore ctime, we change it when deleting */
482 age
= timespec_load(&s
.st_mtim
);
484 char a
[FORMAT_TIMESTAMP_MAX
];
485 /* Follows spelling in stat(1). */
486 log_debug("Directory \"%s\": modify time %s is too new.",
488 format_timestamp_us(a
, sizeof(a
), age
));
492 age
= timespec_load(&s
.st_atim
);
494 char a
[FORMAT_TIMESTAMP_MAX
];
495 log_debug("Directory \"%s\": access time %s is too new.",
497 format_timestamp_us(a
, sizeof(a
), age
));
501 log_debug("Removing directory \"%s\".", sub_path
);
502 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
503 if (errno
!= ENOENT
&& errno
!= ENOTEMPTY
) {
504 log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
509 /* Skip files for which the sticky bit is
510 * set. These are semantics we define, and are
511 * unknown elsewhere. See XDG_RUNTIME_DIR
512 * specification for details. */
513 if (s
.st_mode
& S_ISVTX
) {
514 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
518 if (mountpoint
&& S_ISREG(s
.st_mode
))
519 if (s
.st_uid
== 0 && STR_IN_SET(dent
->d_name
,
523 log_debug("Skipping \"%s\".", sub_path
);
527 /* Ignore sockets that are listed in /proc/net/unix */
528 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
529 log_debug("Skipping \"%s\": live socket.", sub_path
);
533 /* Ignore device nodes */
534 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
535 log_debug("Skipping \"%s\": a device.", sub_path
);
539 /* Keep files on this level around if this is
541 if (keep_this_level
) {
542 log_debug("Keeping \"%s\".", sub_path
);
546 age
= timespec_load(&s
.st_mtim
);
548 char a
[FORMAT_TIMESTAMP_MAX
];
549 /* Follows spelling in stat(1). */
550 log_debug("File \"%s\": modify time %s is too new.",
552 format_timestamp_us(a
, sizeof(a
), age
));
556 age
= timespec_load(&s
.st_atim
);
558 char a
[FORMAT_TIMESTAMP_MAX
];
559 log_debug("File \"%s\": access time %s is too new.",
561 format_timestamp_us(a
, sizeof(a
), age
));
565 age
= timespec_load(&s
.st_ctim
);
567 char a
[FORMAT_TIMESTAMP_MAX
];
568 log_debug("File \"%s\": change time %s is too new.",
570 format_timestamp_us(a
, sizeof(a
), age
));
574 log_debug("unlink \"%s\"", sub_path
);
576 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
578 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
587 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
589 /* Restore original directory timestamps */
590 times
[0] = ds
->st_atim
;
591 times
[1] = ds
->st_mtim
;
593 age1
= timespec_load(&ds
->st_atim
);
594 age2
= timespec_load(&ds
->st_mtim
);
595 log_debug("Restoring access and modification time on \"%s\": %s, %s",
597 format_timestamp_us(a
, sizeof(a
), age1
),
598 format_timestamp_us(b
, sizeof(b
), age2
));
599 if (futimens(dirfd(d
), times
) < 0)
600 log_error_errno(errno
, "utimensat(%s): %m", p
);
606 static int path_set_perms(Item
*i
, const char *path
) {
607 _cleanup_close_
int fd
= -1;
613 /* We open the file with O_PATH here, to make the operation
614 * somewhat atomic. Also there's unfortunately no fchmodat()
615 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
618 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
620 return log_error_errno(errno
, "Adjusting owner and mode for %s failed: %m", path
);
622 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
623 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
625 if (S_ISLNK(st
.st_mode
))
626 log_debug("Skipping mode an owner fix for symlink %s.", path
);
628 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
629 xsprintf(fn
, "/proc/self/fd/%i", fd
);
631 /* not using i->path directly because it may be a glob */
636 if (!(st
.st_mode
& 0111))
638 if (!(st
.st_mode
& 0222))
640 if (!(st
.st_mode
& 0444))
642 if (!S_ISDIR(st
.st_mode
))
643 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
646 if (m
== (st
.st_mode
& 07777))
647 log_debug("\"%s\" has right mode %o", path
, st
.st_mode
);
649 log_debug("chmod \"%s\" to mode %o", path
, m
);
650 if (chmod(fn
, m
) < 0)
651 return log_error_errno(errno
, "chmod(%s) failed: %m", path
);
655 if ((i
->uid
!= st
.st_uid
|| i
->gid
!= st
.st_gid
) &&
656 (i
->uid_set
|| i
->gid_set
)) {
657 log_debug("chown \"%s\" to "UID_FMT
"."GID_FMT
,
659 i
->uid_set
? i
->uid
: UID_INVALID
,
660 i
->gid_set
? i
->gid
: GID_INVALID
);
662 i
->uid_set
? i
->uid
: UID_INVALID
,
663 i
->gid_set
? i
->gid
: GID_INVALID
) < 0)
664 return log_error_errno(errno
, "chown(%s) failed: %m", path
);
670 return label_fix(path
, false, false);
673 static int parse_xattrs_from_arg(Item
*i
) {
683 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
, *xattr_replaced
= NULL
;
685 r
= extract_first_word(&p
, &xattr
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
);
687 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
691 r
= specifier_printf(xattr
, specifier_table
, NULL
, &xattr_replaced
);
693 return log_error_errno(r
, "Failed to replace specifiers in extended attribute '%s': %m", xattr
);
695 r
= split_pair(xattr_replaced
, "=", &name
, &value
);
697 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
701 if (isempty(name
) || isempty(value
)) {
702 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
706 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
715 static int path_set_xattrs(Item
*i
, const char *path
) {
716 char **name
, **value
;
721 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
725 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
726 if (lsetxattr(path
, *name
, *value
, n
, 0) < 0) {
727 log_error("Setting extended attribute %s=%s on %s failed: %m", *name
, *value
, path
);
734 static int parse_acls_from_arg(Item
*item
) {
740 /* If force (= modify) is set, we will not modify the acl
741 * afterwards, so the mask can be added now if necessary. */
743 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
745 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
747 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
754 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
755 _cleanup_(acl_free_charpp
) char *t
= NULL
;
756 _cleanup_(acl_freep
) acl_t dup
= NULL
;
759 /* Returns 0 for success, positive error if already warned,
760 * negative error otherwise. */
763 r
= acls_for_file(path
, type
, acl
, &dup
);
767 r
= calc_acl_mask_if_needed(&dup
);
775 /* the mask was already added earlier if needed */
778 r
= add_base_acls_if_needed(&dup
, path
);
782 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
783 log_debug("Setting %s ACL %s on %s.",
784 type
== ACL_TYPE_ACCESS
? "access" : "default",
787 r
= acl_set_file(path
, type
, dup
);
789 /* Return positive to indicate we already warned */
790 return -log_error_errno(errno
,
791 "Setting %s ACL \"%s\" on %s failed: %m",
792 type
== ACL_TYPE_ACCESS
? "access" : "default",
799 static int path_set_acls(Item
*item
, const char *path
) {
802 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
803 _cleanup_close_
int fd
= -1;
809 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
811 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
813 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
814 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
816 if (S_ISLNK(st
.st_mode
)) {
817 log_debug("Skipping ACL fix for symlink %s.", path
);
821 xsprintf(fn
, "/proc/self/fd/%i", fd
);
823 if (item
->acl_access
)
824 r
= path_set_acl(fn
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
826 if (r
== 0 && item
->acl_default
)
827 r
= path_set_acl(fn
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
830 return -r
; /* already warned */
831 else if (r
== -EOPNOTSUPP
) {
832 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
835 log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
840 #define ATTRIBUTES_ALL \
849 FS_JOURNAL_DATA_FL | \
856 static int parse_attribute_from_arg(Item
*item
) {
858 static const struct {
862 { 'A', FS_NOATIME_FL
}, /* do not update atime */
863 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
864 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
865 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
866 { 'c', FS_COMPR_FL
}, /* Compress file */
867 { 'd', FS_NODUMP_FL
}, /* do not dump file */
868 { 'e', FS_EXTENT_FL
}, /* Top of directory hierarchies*/
869 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
870 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
871 { 's', FS_SECRM_FL
}, /* Secure deletion */
872 { 'u', FS_UNRM_FL
}, /* Undelete */
873 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
874 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies*/
875 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
884 unsigned value
= 0, mask
= 0;
894 } else if (*p
== '-') {
897 } else if (*p
== '=') {
903 if (isempty(p
) && mode
!= MODE_SET
) {
904 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
908 for (; p
&& *p
; p
++) {
911 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
912 if (*p
== attributes
[i
].character
)
915 if (i
>= ELEMENTSOF(attributes
)) {
916 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
920 v
= attributes
[i
].value
;
922 if (mode
== MODE_ADD
|| mode
== MODE_SET
)
930 if (mode
== MODE_SET
)
931 mask
|= ATTRIBUTES_ALL
;
935 item
->attribute_mask
= mask
;
936 item
->attribute_value
= value
;
937 item
->attribute_set
= true;
942 static int path_set_attribute(Item
*item
, const char *path
) {
943 _cleanup_close_
int fd
= -1;
948 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
951 fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
|O_NOATIME
|O_NOFOLLOW
);
954 return log_error_errno(errno
, "Skipping file attributes adjustment on symlink %s.", path
);
956 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
959 if (fstat(fd
, &st
) < 0)
960 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
962 /* Issuing the file attribute ioctls on device nodes is not
963 * safe, as that will be delivered to the drivers, not the
964 * file system containing the device node. */
965 if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
)) {
966 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
970 f
= item
->attribute_value
& item
->attribute_mask
;
972 /* Mask away directory-specific flags */
973 if (!S_ISDIR(st
.st_mode
))
976 r
= chattr_fd(fd
, f
, item
->attribute_mask
);
978 log_full_errno(r
== -ENOTTY
? LOG_DEBUG
: LOG_WARNING
,
980 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
981 path
, item
->attribute_value
, item
->attribute_mask
);
986 static int write_one_file(Item
*i
, const char *path
) {
987 _cleanup_close_
int fd
= -1;
994 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
|O_NOFOLLOW
:
995 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
997 RUN_WITH_UMASK(0000) {
998 mac_selinux_create_file_prepare(path
, S_IFREG
);
999 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
1000 mac_selinux_create_file_clear();
1004 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
1005 log_debug_errno(errno
, "Not writing \"%s\": %m", path
);
1010 if (!i
->argument
&& errno
== EROFS
&& stat(path
, &st
) == 0 &&
1011 (i
->type
== CREATE_FILE
|| st
.st_size
== 0))
1014 return log_error_errno(r
, "Failed to create file %s: %m", path
);
1018 _cleanup_free_
char *unescaped
= NULL
, *replaced
= NULL
;
1020 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
1022 r
= cunescape(i
->argument
, 0, &unescaped
);
1024 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
1026 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &replaced
);
1028 return log_error_errno(r
, "Failed to replace specifiers in parameter to write '%s': %m", unescaped
);
1030 r
= loop_write(fd
, replaced
, strlen(replaced
), false);
1032 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1034 log_debug("\"%s\" has been created.", path
);
1036 fd
= safe_close(fd
);
1038 if (stat(path
, &st
) < 0)
1039 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1042 if (!S_ISREG(st
.st_mode
)) {
1043 log_error("%s is not a file.", path
);
1047 r
= path_set_perms(i
, path
);
1054 typedef int (*action_t
)(Item
*, const char *);
1056 static int item_do_children(Item
*i
, const char *path
, action_t action
) {
1057 _cleanup_closedir_
DIR *d
;
1063 /* This returns the first error we run into, but nevertheless
1066 d
= opendir_nomod(path
);
1068 return errno
== ENOENT
|| errno
== ENOTDIR
? 0 : -errno
;
1071 _cleanup_free_
char *p
= NULL
;
1078 if (errno
> 0 && r
== 0)
1084 if (STR_IN_SET(de
->d_name
, ".", ".."))
1087 p
= strjoin(path
, "/", de
->d_name
, NULL
);
1092 if (q
< 0 && q
!= -ENOENT
&& r
== 0)
1095 if (IN_SET(de
->d_type
, DT_UNKNOWN
, DT_DIR
)) {
1096 q
= item_do_children(i
, p
, action
);
1097 if (q
< 0 && r
== 0)
1105 static int glob_item(Item
*i
, action_t action
, bool recursive
) {
1106 _cleanup_globfree_ glob_t g
= {
1107 .gl_closedir
= (void (*)(void *)) closedir
,
1108 .gl_readdir
= (struct dirent
*(*)(void *)) readdir
,
1109 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1117 k
= glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
|GLOB_ALTDIRFUNC
, NULL
, &g
);
1118 if (k
!= 0 && k
!= GLOB_NOMATCH
)
1119 return log_error_errno(errno
?: EIO
, "glob(%s) failed: %m", i
->path
);
1121 STRV_FOREACH(fn
, g
.gl_pathv
) {
1123 if (k
< 0 && r
== 0)
1127 k
= item_do_children(i
, *fn
, action
);
1128 if (k
< 0 && r
== 0)
1141 _CREATION_MODE_INVALID
= -1
1144 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1145 [CREATION_NORMAL
] = "Created",
1146 [CREATION_EXISTING
] = "Found existing",
1147 [CREATION_FORCE
] = "Created replacement",
1150 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1152 static int create_item(Item
*i
) {
1153 _cleanup_free_
char *resolved
= NULL
;
1157 CreationMode creation
;
1161 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1166 case IGNORE_DIRECTORY_PATH
:
1168 case RECURSIVE_REMOVE_PATH
:
1173 r
= write_one_file(i
, i
->path
);
1179 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1181 return log_error_errno(r
, "Failed to substitute specifiers in copy source %s: %m", i
->argument
);
1183 log_debug("Copying tree \"%s\" to \"%s\".", resolved
, i
->path
);
1184 r
= copy_tree(resolved
, i
->path
, false);
1186 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1193 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1195 if (stat(resolved
, &a
) < 0)
1196 return log_error_errno(errno
, "stat(%s) failed: %m", resolved
);
1198 if (stat(i
->path
, &b
) < 0)
1199 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1201 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1202 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1207 r
= path_set_perms(i
, i
->path
);
1214 r
= glob_item(i
, write_one_file
, false);
1220 case CREATE_DIRECTORY
:
1221 case TRUNCATE_DIRECTORY
:
1222 case CREATE_SUBVOLUME
:
1223 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1224 case CREATE_SUBVOLUME_NEW_QUOTA
:
1226 RUN_WITH_UMASK(0000)
1227 mkdir_parents_label(i
->path
, 0755);
1229 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1231 if (btrfs_is_subvol(isempty(arg_root
) ? "/" : arg_root
) <= 0)
1233 /* Don't create a subvolume unless the
1234 * root directory is one, too. We do
1235 * this under the assumption that if
1236 * the root directory is just a plain
1237 * directory (i.e. very light-weight),
1238 * we shouldn't try to split it up
1239 * into subvolumes (i.e. more
1240 * heavy-weight). Thus, chroot()
1241 * environments and suchlike will get
1242 * a full brtfs subvolume set up below
1243 * their tree only if they
1244 * specifically set up a btrfs
1245 * subvolume for the root dir too. */
1249 RUN_WITH_UMASK((~i
->mode
) & 0777)
1250 r
= btrfs_subvol_make(i
->path
);
1255 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1256 RUN_WITH_UMASK(0000)
1257 r
= mkdir_label(i
->path
, i
->mode
);
1262 if (r
!= -EEXIST
&& r
!= -EROFS
)
1263 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1265 k
= is_dir(i
->path
, false);
1266 if (k
== -ENOENT
&& r
== -EROFS
)
1267 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1269 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1271 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1275 creation
= CREATION_EXISTING
;
1277 creation
= CREATION_NORMAL
;
1279 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1281 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1282 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1284 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
);
1285 else if (r
== -EROFS
)
1286 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i
->path
);
1287 else if (r
== -ENOPROTOOPT
)
1288 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because quota support is disabled: %m", i
->path
);
1290 q
= log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1292 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1294 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1297 r
= path_set_perms(i
, i
->path
);
1307 RUN_WITH_UMASK(0000) {
1308 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1309 r
= mkfifo(i
->path
, i
->mode
);
1310 mac_selinux_create_file_clear();
1314 if (errno
!= EEXIST
)
1315 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1317 if (lstat(i
->path
, &st
) < 0)
1318 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1320 if (!S_ISFIFO(st
.st_mode
)) {
1323 RUN_WITH_UMASK(0000) {
1324 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1325 r
= mkfifo_atomic(i
->path
, i
->mode
);
1326 mac_selinux_create_file_clear();
1330 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1331 creation
= CREATION_FORCE
;
1333 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1337 creation
= CREATION_EXISTING
;
1339 creation
= CREATION_NORMAL
;
1340 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1342 r
= path_set_perms(i
, i
->path
);
1349 case CREATE_SYMLINK
: {
1350 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1352 return log_error_errno(r
, "Failed to substitute specifiers in symlink target %s: %m", i
->argument
);
1354 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1355 r
= symlink(resolved
, i
->path
);
1356 mac_selinux_create_file_clear();
1359 _cleanup_free_
char *x
= NULL
;
1361 if (errno
!= EEXIST
)
1362 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1364 r
= readlink_malloc(i
->path
, &x
);
1365 if (r
< 0 || !streq(resolved
, x
)) {
1368 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1369 r
= symlink_atomic(resolved
, i
->path
);
1370 mac_selinux_create_file_clear();
1373 return log_error_errno(r
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1375 creation
= CREATION_FORCE
;
1377 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1381 creation
= CREATION_EXISTING
;
1384 creation
= CREATION_NORMAL
;
1385 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1389 case CREATE_BLOCK_DEVICE
:
1390 case CREATE_CHAR_DEVICE
: {
1393 if (have_effective_cap(CAP_MKNOD
) == 0) {
1394 /* In a container we lack CAP_MKNOD. We
1395 shouldn't attempt to create the device node in
1396 that case to avoid noise, and we don't support
1397 virtualized devices in containers anyway. */
1399 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1403 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1405 RUN_WITH_UMASK(0000) {
1406 mac_selinux_create_file_prepare(i
->path
, file_type
);
1407 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1408 mac_selinux_create_file_clear();
1412 if (errno
== EPERM
) {
1413 log_debug("We lack permissions, possibly because of cgroup configuration; "
1414 "skipping creation of device node %s.", i
->path
);
1418 if (errno
!= EEXIST
)
1419 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1421 if (lstat(i
->path
, &st
) < 0)
1422 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1424 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1428 RUN_WITH_UMASK(0000) {
1429 mac_selinux_create_file_prepare(i
->path
, file_type
);
1430 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1431 mac_selinux_create_file_clear();
1435 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1436 creation
= CREATION_FORCE
;
1438 log_debug("%s is not a device node.", i
->path
);
1442 creation
= CREATION_EXISTING
;
1444 creation
= CREATION_NORMAL
;
1446 log_debug("%s %s device node \"%s\" %u:%u.",
1447 creation_mode_verb_to_string(creation
),
1448 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1449 i
->path
, major(i
->mode
), minor(i
->mode
));
1451 r
= path_set_perms(i
, i
->path
);
1460 r
= glob_item(i
, path_set_perms
, false);
1465 case RECURSIVE_RELABEL_PATH
:
1466 r
= glob_item(i
, path_set_perms
, true);
1472 r
= glob_item(i
, path_set_xattrs
, false);
1477 case RECURSIVE_SET_XATTR
:
1478 r
= glob_item(i
, path_set_xattrs
, true);
1484 r
= glob_item(i
, path_set_acls
, false);
1489 case RECURSIVE_SET_ACL
:
1490 r
= glob_item(i
, path_set_acls
, true);
1496 r
= glob_item(i
, path_set_attribute
, false);
1501 case RECURSIVE_SET_ATTRIBUTE
:
1502 r
= glob_item(i
, path_set_attribute
, true);
1511 static int remove_item_instance(Item
*i
, const char *instance
) {
1519 if (remove(instance
) < 0 && errno
!= ENOENT
)
1520 return log_error_errno(errno
, "rm(%s): %m", instance
);
1524 case TRUNCATE_DIRECTORY
:
1525 case RECURSIVE_REMOVE_PATH
:
1526 /* FIXME: we probably should use dir_cleanup() here
1527 * instead of rm_rf() so that 'x' is honoured. */
1528 log_debug("rm -rf \"%s\"", instance
);
1529 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1530 if (r
< 0 && r
!= -ENOENT
)
1531 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1536 assert_not_reached("wut?");
1542 static int remove_item(Item
*i
) {
1547 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1553 case CREATE_DIRECTORY
:
1554 case CREATE_SUBVOLUME
:
1555 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1556 case CREATE_SUBVOLUME_NEW_QUOTA
:
1558 case CREATE_SYMLINK
:
1559 case CREATE_CHAR_DEVICE
:
1560 case CREATE_BLOCK_DEVICE
:
1562 case IGNORE_DIRECTORY_PATH
:
1565 case RECURSIVE_RELABEL_PATH
:
1569 case RECURSIVE_SET_XATTR
:
1571 case RECURSIVE_SET_ACL
:
1573 case RECURSIVE_SET_ATTRIBUTE
:
1577 case TRUNCATE_DIRECTORY
:
1578 case RECURSIVE_REMOVE_PATH
:
1579 r
= glob_item(i
, remove_item_instance
, false);
1586 static int clean_item_instance(Item
*i
, const char* instance
) {
1587 _cleanup_closedir_
DIR *d
= NULL
;
1591 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1598 n
= now(CLOCK_REALTIME
);
1602 cutoff
= n
- i
->age
;
1604 d
= opendir_nomod(instance
);
1606 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
1607 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1611 log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1615 if (fstat(dirfd(d
), &s
) < 0)
1616 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1618 if (!S_ISDIR(s
.st_mode
)) {
1619 log_error("%s is not a directory.", i
->path
);
1623 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1624 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1626 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1628 log_debug("Cleanup threshold for %s \"%s\" is %s",
1629 mountpoint
? "mount point" : "directory",
1631 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1633 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1634 MAX_DEPTH
, i
->keep_first_level
);
1637 static int clean_item(Item
*i
) {
1642 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1645 case CREATE_DIRECTORY
:
1646 case CREATE_SUBVOLUME
:
1647 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1648 case CREATE_SUBVOLUME_NEW_QUOTA
:
1649 case TRUNCATE_DIRECTORY
:
1652 clean_item_instance(i
, i
->path
);
1654 case IGNORE_DIRECTORY_PATH
:
1655 r
= glob_item(i
, clean_item_instance
, false);
1664 static int process_item_array(ItemArray
*array
);
1666 static int process_item(Item
*i
) {
1668 _cleanup_free_
char *prefix
= NULL
;
1677 prefix
= malloc(strlen(i
->path
) + 1);
1681 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1684 j
= ordered_hashmap_get(items
, prefix
);
1688 s
= process_item_array(j
);
1689 if (s
< 0 && t
== 0)
1694 r
= arg_create
? create_item(i
) : 0;
1695 q
= arg_remove
? remove_item(i
) : 0;
1696 p
= arg_clean
? clean_item(i
) : 0;
1704 static int process_item_array(ItemArray
*array
) {
1710 for (n
= 0; n
< array
->count
; n
++) {
1711 k
= process_item(array
->items
+ n
);
1712 if (k
< 0 && r
== 0)
1719 static void item_free_contents(Item
*i
) {
1723 strv_free(i
->xattrs
);
1726 acl_free(i
->acl_access
);
1727 acl_free(i
->acl_default
);
1731 static void item_array_free(ItemArray
*a
) {
1737 for (n
= 0; n
< a
->count
; n
++)
1738 item_free_contents(a
->items
+ n
);
1743 static int item_compare(const void *a
, const void *b
) {
1744 const Item
*x
= a
, *y
= b
;
1746 /* Make sure that the ownership taking item is put first, so
1747 * that we first create the node, and then can adjust it */
1749 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1751 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1754 return (int) x
->type
- (int) y
->type
;
1757 static bool item_compatible(Item
*a
, Item
*b
) {
1760 assert(streq(a
->path
, b
->path
));
1762 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1763 /* check if the items are the same */
1764 return streq_ptr(a
->argument
, b
->argument
) &&
1766 a
->uid_set
== b
->uid_set
&&
1769 a
->gid_set
== b
->gid_set
&&
1772 a
->mode_set
== b
->mode_set
&&
1773 a
->mode
== b
->mode
&&
1775 a
->age_set
== b
->age_set
&&
1778 a
->mask_perms
== b
->mask_perms
&&
1780 a
->keep_first_level
== b
->keep_first_level
&&
1782 a
->major_minor
== b
->major_minor
;
1787 static bool should_include_path(const char *path
) {
1790 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1791 if (path_startswith(path
, *prefix
)) {
1792 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1797 STRV_FOREACH(prefix
, arg_include_prefixes
)
1798 if (path_startswith(path
, *prefix
)) {
1799 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1803 /* no matches, so we should include this path only if we
1804 * have no whitelist at all */
1805 if (strv_length(arg_include_prefixes
) == 0)
1808 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1812 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1814 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1815 _cleanup_(item_free_contents
) Item i
= {};
1816 ItemArray
*existing
;
1819 bool force
= false, boot
= false;
1825 r
= extract_many_words(
1837 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1839 log_error("[%s:%u] Syntax error.", fname
, line
);
1843 if (!isempty(buffer
) && !streq(buffer
, "-")) {
1844 i
.argument
= strdup(buffer
);
1849 if (isempty(action
)) {
1850 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1854 for (pos
= 1; action
[pos
]; pos
++) {
1855 if (action
[pos
] == '!' && !boot
)
1857 else if (action
[pos
] == '+' && !force
)
1860 log_error("[%s:%u] Unknown modifiers in command '%s'",
1861 fname
, line
, action
);
1866 if (boot
&& !arg_boot
) {
1867 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1875 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1877 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1883 case CREATE_DIRECTORY
:
1884 case CREATE_SUBVOLUME
:
1885 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1886 case CREATE_SUBVOLUME_NEW_QUOTA
:
1887 case TRUNCATE_DIRECTORY
:
1890 case IGNORE_DIRECTORY_PATH
:
1892 case RECURSIVE_REMOVE_PATH
:
1895 case RECURSIVE_RELABEL_PATH
:
1897 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
1905 case CREATE_SYMLINK
:
1907 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1915 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1922 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1925 } else if (!path_is_absolute(i
.argument
)) {
1926 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1930 path_kill_slashes(i
.argument
);
1933 case CREATE_CHAR_DEVICE
:
1934 case CREATE_BLOCK_DEVICE
: {
1935 unsigned major
, minor
;
1938 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1942 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1943 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1947 i
.major_minor
= makedev(major
, minor
);
1952 case RECURSIVE_SET_XATTR
:
1954 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1957 r
= parse_xattrs_from_arg(&i
);
1963 case RECURSIVE_SET_ACL
:
1965 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
1968 r
= parse_acls_from_arg(&i
);
1974 case RECURSIVE_SET_ATTRIBUTE
:
1976 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
1979 r
= parse_attribute_from_arg(&i
);
1985 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
1989 if (!path_is_absolute(i
.path
)) {
1990 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
1994 path_kill_slashes(i
.path
);
1996 if (!should_include_path(i
.path
))
2002 p
= prefix_root(arg_root
, i
.path
);
2010 if (!isempty(user
) && !streq(user
, "-")) {
2011 const char *u
= user
;
2013 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
2015 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
2022 if (!isempty(group
) && !streq(group
, "-")) {
2023 const char *g
= group
;
2025 r
= get_group_creds(&g
, &i
.gid
);
2027 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2034 if (!isempty(mode
) && !streq(mode
, "-")) {
2035 const char *mm
= mode
;
2039 i
.mask_perms
= true;
2043 if (parse_mode(mm
, &m
) < 0) {
2044 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2051 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2053 if (!isempty(age
) && !streq(age
, "-")) {
2054 const char *a
= age
;
2057 i
.keep_first_level
= true;
2061 if (parse_sec(a
, &i
.age
) < 0) {
2062 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2069 h
= needs_glob(i
.type
) ? globs
: items
;
2071 existing
= ordered_hashmap_get(h
, i
.path
);
2075 for (n
= 0; n
< existing
->count
; n
++) {
2076 if (!item_compatible(existing
->items
+ n
, &i
)) {
2077 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2078 fname
, line
, i
.path
);
2083 existing
= new0(ItemArray
, 1);
2084 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2089 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2092 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2094 /* Sort item array, to enforce stable ordering of application */
2095 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2101 static void help(void) {
2102 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2103 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2104 " -h --help Show this help\n"
2105 " --version Show package version\n"
2106 " --create Create marked files/directories\n"
2107 " --clean Clean up marked directories\n"
2108 " --remove Remove marked files/directories\n"
2109 " --boot Execute actions only safe at boot\n"
2110 " --prefix=PATH Only apply rules with the specified prefix\n"
2111 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2112 " --root=PATH Operate on an alternate filesystem root\n",
2113 program_invocation_short_name
);
2116 static int parse_argv(int argc
, char *argv
[]) {
2119 ARG_VERSION
= 0x100,
2129 static const struct option options
[] = {
2130 { "help", no_argument
, NULL
, 'h' },
2131 { "version", no_argument
, NULL
, ARG_VERSION
},
2132 { "create", no_argument
, NULL
, ARG_CREATE
},
2133 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2134 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2135 { "boot", no_argument
, NULL
, ARG_BOOT
},
2136 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2137 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2138 { "root", required_argument
, NULL
, ARG_ROOT
},
2147 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2175 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2179 case ARG_EXCLUDE_PREFIX
:
2180 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2185 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2194 assert_not_reached("Unhandled option");
2197 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2198 log_error("You need to specify at least one of --clean, --create or --remove.");
2205 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2206 _cleanup_fclose_
FILE *f
= NULL
;
2207 char line
[LINE_MAX
];
2215 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &f
);
2217 if (ignore_enoent
&& r
== -ENOENT
) {
2218 log_debug_errno(r
, "Failed to open \"%s\": %m", fn
);
2222 return log_error_errno(r
, "Failed to open '%s', ignoring: %m", fn
);
2224 log_debug("Reading config file \"%s\".", fn
);
2226 FOREACH_LINE(line
, f
, break) {
2233 if (*l
== '#' || *l
== 0)
2236 k
= parse_line(fn
, v
, l
);
2237 if (k
< 0 && r
== 0)
2241 /* we have to determine age parameter for each entry of type X */
2242 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2244 Item
*j
, *candidate_item
= NULL
;
2246 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2249 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2250 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2253 if (path_equal(j
->path
, i
->path
)) {
2258 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2259 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2263 if (candidate_item
&& candidate_item
->age_set
) {
2264 i
->age
= candidate_item
->age
;
2270 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2278 int main(int argc
, char *argv
[]) {
2283 r
= parse_argv(argc
, argv
);
2287 log_set_target(LOG_TARGET_AUTO
);
2288 log_parse_environment();
2293 mac_selinux_init(NULL
);
2295 items
= ordered_hashmap_new(&string_hash_ops
);
2296 globs
= ordered_hashmap_new(&string_hash_ops
);
2298 if (!items
|| !globs
) {
2305 if (optind
< argc
) {
2308 for (j
= optind
; j
< argc
; j
++) {
2309 k
= read_config_file(argv
[j
], false);
2310 if (k
< 0 && r
== 0)
2315 _cleanup_strv_free_
char **files
= NULL
;
2318 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, conf_file_dirs
);
2320 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2324 STRV_FOREACH(f
, files
) {
2325 k
= read_config_file(*f
, true);
2326 if (k
< 0 && r
== 0)
2331 /* The non-globbing ones usually create things, hence we apply
2333 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2334 k
= process_item_array(a
);
2335 if (k
< 0 && r
== 0)
2339 /* The globbing ones usually alter things, hence we apply them
2341 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2342 k
= process_item_array(a
);
2343 if (k
< 0 && r
== 0)
2348 while ((a
= ordered_hashmap_steal_first(items
)))
2351 while ((a
= ordered_hashmap_steal_first(globs
)))
2354 ordered_hashmap_free(items
);
2355 ordered_hashmap_free(globs
);
2357 free(arg_include_prefixes
);
2358 free(arg_exclude_prefixes
);
2361 set_free_free(unix_sockets
);
2363 mac_selinux_finish();
2365 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;