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
;
1156 CreationMode creation
;
1160 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1165 case IGNORE_DIRECTORY_PATH
:
1167 case RECURSIVE_REMOVE_PATH
:
1172 r
= write_one_file(i
, i
->path
);
1178 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1180 return log_error_errno(r
, "Failed to substitute specifiers in copy source %s: %m", i
->argument
);
1182 log_debug("Copying tree \"%s\" to \"%s\".", resolved
, i
->path
);
1183 r
= copy_tree(resolved
, i
->path
, false);
1185 if (r
== -EROFS
&& stat(i
->path
, &st
) == 0)
1192 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1194 if (stat(resolved
, &a
) < 0)
1195 return log_error_errno(errno
, "stat(%s) failed: %m", resolved
);
1197 if (stat(i
->path
, &b
) < 0)
1198 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1200 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1201 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1206 r
= path_set_perms(i
, i
->path
);
1213 r
= glob_item(i
, write_one_file
, false);
1219 case CREATE_DIRECTORY
:
1220 case TRUNCATE_DIRECTORY
:
1221 case CREATE_SUBVOLUME
:
1222 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1223 case CREATE_SUBVOLUME_NEW_QUOTA
:
1225 RUN_WITH_UMASK(0000)
1226 mkdir_parents_label(i
->path
, 0755);
1228 if (IN_SET(i
->type
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
)) {
1230 if (btrfs_is_subvol(isempty(arg_root
) ? "/" : arg_root
) <= 0)
1232 /* Don't create a subvolume unless the
1233 * root directory is one, too. We do
1234 * this under the assumption that if
1235 * the root directory is just a plain
1236 * directory (i.e. very light-weight),
1237 * we shouldn't try to split it up
1238 * into subvolumes (i.e. more
1239 * heavy-weight). Thus, chroot()
1240 * environments and suchlike will get
1241 * a full brtfs subvolume set up below
1242 * their tree only if they
1243 * specifically set up a btrfs
1244 * subvolume for the root dir too. */
1248 RUN_WITH_UMASK((~i
->mode
) & 0777)
1249 r
= btrfs_subvol_make(i
->path
);
1254 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1255 RUN_WITH_UMASK(0000)
1256 r
= mkdir_label(i
->path
, i
->mode
);
1261 if (r
!= -EEXIST
&& r
!= -EROFS
)
1262 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1264 k
= is_dir(i
->path
, false);
1265 if (k
== -ENOENT
&& r
== -EROFS
)
1266 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1268 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1270 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1274 creation
= CREATION_EXISTING
;
1276 creation
= CREATION_NORMAL
;
1278 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1280 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1281 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1283 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
);
1287 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i
->path
);
1290 if (r
== -ENOPROTOOPT
) {
1291 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because quota support is disabled: %m", i
->path
);
1295 return log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1297 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1299 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1302 r
= path_set_perms(i
, i
->path
);
1310 RUN_WITH_UMASK(0000) {
1311 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1312 r
= mkfifo(i
->path
, i
->mode
);
1313 mac_selinux_create_file_clear();
1317 if (errno
!= EEXIST
)
1318 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1320 if (lstat(i
->path
, &st
) < 0)
1321 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1323 if (!S_ISFIFO(st
.st_mode
)) {
1326 RUN_WITH_UMASK(0000) {
1327 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1328 r
= mkfifo_atomic(i
->path
, i
->mode
);
1329 mac_selinux_create_file_clear();
1333 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1334 creation
= CREATION_FORCE
;
1336 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1340 creation
= CREATION_EXISTING
;
1342 creation
= CREATION_NORMAL
;
1343 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1345 r
= path_set_perms(i
, i
->path
);
1352 case CREATE_SYMLINK
: {
1353 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1355 return log_error_errno(r
, "Failed to substitute specifiers in symlink target %s: %m", i
->argument
);
1357 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1358 r
= symlink(resolved
, i
->path
);
1359 mac_selinux_create_file_clear();
1362 _cleanup_free_
char *x
= NULL
;
1364 if (errno
!= EEXIST
)
1365 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1367 r
= readlink_malloc(i
->path
, &x
);
1368 if (r
< 0 || !streq(resolved
, x
)) {
1371 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1372 r
= symlink_atomic(resolved
, i
->path
);
1373 mac_selinux_create_file_clear();
1376 return log_error_errno(r
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1378 creation
= CREATION_FORCE
;
1380 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1384 creation
= CREATION_EXISTING
;
1387 creation
= CREATION_NORMAL
;
1388 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1392 case CREATE_BLOCK_DEVICE
:
1393 case CREATE_CHAR_DEVICE
: {
1396 if (have_effective_cap(CAP_MKNOD
) == 0) {
1397 /* In a container we lack CAP_MKNOD. We
1398 shouldn't attempt to create the device node in
1399 that case to avoid noise, and we don't support
1400 virtualized devices in containers anyway. */
1402 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1406 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1408 RUN_WITH_UMASK(0000) {
1409 mac_selinux_create_file_prepare(i
->path
, file_type
);
1410 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1411 mac_selinux_create_file_clear();
1415 if (errno
== EPERM
) {
1416 log_debug("We lack permissions, possibly because of cgroup configuration; "
1417 "skipping creation of device node %s.", i
->path
);
1421 if (errno
!= EEXIST
)
1422 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1424 if (lstat(i
->path
, &st
) < 0)
1425 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1427 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1431 RUN_WITH_UMASK(0000) {
1432 mac_selinux_create_file_prepare(i
->path
, file_type
);
1433 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1434 mac_selinux_create_file_clear();
1438 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1439 creation
= CREATION_FORCE
;
1441 log_debug("%s is not a device node.", i
->path
);
1445 creation
= CREATION_EXISTING
;
1447 creation
= CREATION_NORMAL
;
1449 log_debug("%s %s device node \"%s\" %u:%u.",
1450 creation_mode_verb_to_string(creation
),
1451 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1452 i
->path
, major(i
->mode
), minor(i
->mode
));
1454 r
= path_set_perms(i
, i
->path
);
1463 r
= glob_item(i
, path_set_perms
, false);
1468 case RECURSIVE_RELABEL_PATH
:
1469 r
= glob_item(i
, path_set_perms
, true);
1475 r
= glob_item(i
, path_set_xattrs
, false);
1480 case RECURSIVE_SET_XATTR
:
1481 r
= glob_item(i
, path_set_xattrs
, true);
1487 r
= glob_item(i
, path_set_acls
, false);
1492 case RECURSIVE_SET_ACL
:
1493 r
= glob_item(i
, path_set_acls
, true);
1499 r
= glob_item(i
, path_set_attribute
, false);
1504 case RECURSIVE_SET_ATTRIBUTE
:
1505 r
= glob_item(i
, path_set_attribute
, true);
1514 static int remove_item_instance(Item
*i
, const char *instance
) {
1522 if (remove(instance
) < 0 && errno
!= ENOENT
)
1523 return log_error_errno(errno
, "rm(%s): %m", instance
);
1527 case TRUNCATE_DIRECTORY
:
1528 case RECURSIVE_REMOVE_PATH
:
1529 /* FIXME: we probably should use dir_cleanup() here
1530 * instead of rm_rf() so that 'x' is honoured. */
1531 log_debug("rm -rf \"%s\"", instance
);
1532 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1533 if (r
< 0 && r
!= -ENOENT
)
1534 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1539 assert_not_reached("wut?");
1545 static int remove_item(Item
*i
) {
1550 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1556 case CREATE_DIRECTORY
:
1557 case CREATE_SUBVOLUME
:
1558 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1559 case CREATE_SUBVOLUME_NEW_QUOTA
:
1561 case CREATE_SYMLINK
:
1562 case CREATE_CHAR_DEVICE
:
1563 case CREATE_BLOCK_DEVICE
:
1565 case IGNORE_DIRECTORY_PATH
:
1568 case RECURSIVE_RELABEL_PATH
:
1572 case RECURSIVE_SET_XATTR
:
1574 case RECURSIVE_SET_ACL
:
1576 case RECURSIVE_SET_ATTRIBUTE
:
1580 case TRUNCATE_DIRECTORY
:
1581 case RECURSIVE_REMOVE_PATH
:
1582 r
= glob_item(i
, remove_item_instance
, false);
1589 static int clean_item_instance(Item
*i
, const char* instance
) {
1590 _cleanup_closedir_
DIR *d
= NULL
;
1594 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1601 n
= now(CLOCK_REALTIME
);
1605 cutoff
= n
- i
->age
;
1607 d
= opendir_nomod(instance
);
1609 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
1610 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1614 log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1618 if (fstat(dirfd(d
), &s
) < 0)
1619 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1621 if (!S_ISDIR(s
.st_mode
)) {
1622 log_error("%s is not a directory.", i
->path
);
1626 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1627 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1629 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1631 log_debug("Cleanup threshold for %s \"%s\" is %s",
1632 mountpoint
? "mount point" : "directory",
1634 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1636 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1637 MAX_DEPTH
, i
->keep_first_level
);
1640 static int clean_item(Item
*i
) {
1645 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1648 case CREATE_DIRECTORY
:
1649 case CREATE_SUBVOLUME
:
1650 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1651 case CREATE_SUBVOLUME_NEW_QUOTA
:
1652 case TRUNCATE_DIRECTORY
:
1655 clean_item_instance(i
, i
->path
);
1657 case IGNORE_DIRECTORY_PATH
:
1658 r
= glob_item(i
, clean_item_instance
, false);
1667 static int process_item_array(ItemArray
*array
);
1669 static int process_item(Item
*i
) {
1671 _cleanup_free_
char *prefix
= NULL
;
1680 prefix
= malloc(strlen(i
->path
) + 1);
1684 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1687 j
= ordered_hashmap_get(items
, prefix
);
1691 s
= process_item_array(j
);
1692 if (s
< 0 && t
== 0)
1697 r
= arg_create
? create_item(i
) : 0;
1698 q
= arg_remove
? remove_item(i
) : 0;
1699 p
= arg_clean
? clean_item(i
) : 0;
1707 static int process_item_array(ItemArray
*array
) {
1713 for (n
= 0; n
< array
->count
; n
++) {
1714 k
= process_item(array
->items
+ n
);
1715 if (k
< 0 && r
== 0)
1722 static void item_free_contents(Item
*i
) {
1726 strv_free(i
->xattrs
);
1729 acl_free(i
->acl_access
);
1730 acl_free(i
->acl_default
);
1734 static void item_array_free(ItemArray
*a
) {
1740 for (n
= 0; n
< a
->count
; n
++)
1741 item_free_contents(a
->items
+ n
);
1746 static int item_compare(const void *a
, const void *b
) {
1747 const Item
*x
= a
, *y
= b
;
1749 /* Make sure that the ownership taking item is put first, so
1750 * that we first create the node, and then can adjust it */
1752 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1754 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1757 return (int) x
->type
- (int) y
->type
;
1760 static bool item_compatible(Item
*a
, Item
*b
) {
1763 assert(streq(a
->path
, b
->path
));
1765 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1766 /* check if the items are the same */
1767 return streq_ptr(a
->argument
, b
->argument
) &&
1769 a
->uid_set
== b
->uid_set
&&
1772 a
->gid_set
== b
->gid_set
&&
1775 a
->mode_set
== b
->mode_set
&&
1776 a
->mode
== b
->mode
&&
1778 a
->age_set
== b
->age_set
&&
1781 a
->mask_perms
== b
->mask_perms
&&
1783 a
->keep_first_level
== b
->keep_first_level
&&
1785 a
->major_minor
== b
->major_minor
;
1790 static bool should_include_path(const char *path
) {
1793 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1794 if (path_startswith(path
, *prefix
)) {
1795 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1800 STRV_FOREACH(prefix
, arg_include_prefixes
)
1801 if (path_startswith(path
, *prefix
)) {
1802 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1806 /* no matches, so we should include this path only if we
1807 * have no whitelist at all */
1808 if (strv_length(arg_include_prefixes
) == 0)
1811 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1815 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1817 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1818 _cleanup_(item_free_contents
) Item i
= {};
1819 ItemArray
*existing
;
1822 bool force
= false, boot
= false;
1828 r
= extract_many_words(
1840 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1842 log_error("[%s:%u] Syntax error.", fname
, line
);
1846 if (!isempty(buffer
) && !streq(buffer
, "-")) {
1847 i
.argument
= strdup(buffer
);
1852 if (isempty(action
)) {
1853 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1857 for (pos
= 1; action
[pos
]; pos
++) {
1858 if (action
[pos
] == '!' && !boot
)
1860 else if (action
[pos
] == '+' && !force
)
1863 log_error("[%s:%u] Unknown modifiers in command '%s'",
1864 fname
, line
, action
);
1869 if (boot
&& !arg_boot
) {
1870 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1878 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1880 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1886 case CREATE_DIRECTORY
:
1887 case CREATE_SUBVOLUME
:
1888 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1889 case CREATE_SUBVOLUME_NEW_QUOTA
:
1890 case TRUNCATE_DIRECTORY
:
1893 case IGNORE_DIRECTORY_PATH
:
1895 case RECURSIVE_REMOVE_PATH
:
1898 case RECURSIVE_RELABEL_PATH
:
1900 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
1908 case CREATE_SYMLINK
:
1910 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1918 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1925 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1928 } else if (!path_is_absolute(i
.argument
)) {
1929 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1933 path_kill_slashes(i
.argument
);
1936 case CREATE_CHAR_DEVICE
:
1937 case CREATE_BLOCK_DEVICE
: {
1938 unsigned major
, minor
;
1941 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1945 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1946 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1950 i
.major_minor
= makedev(major
, minor
);
1955 case RECURSIVE_SET_XATTR
:
1957 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1960 r
= parse_xattrs_from_arg(&i
);
1966 case RECURSIVE_SET_ACL
:
1968 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
1971 r
= parse_acls_from_arg(&i
);
1977 case RECURSIVE_SET_ATTRIBUTE
:
1979 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
1982 r
= parse_attribute_from_arg(&i
);
1988 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
1992 if (!path_is_absolute(i
.path
)) {
1993 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
1997 path_kill_slashes(i
.path
);
1999 if (!should_include_path(i
.path
))
2005 p
= prefix_root(arg_root
, i
.path
);
2013 if (!isempty(user
) && !streq(user
, "-")) {
2014 const char *u
= user
;
2016 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
2018 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
2025 if (!isempty(group
) && !streq(group
, "-")) {
2026 const char *g
= group
;
2028 r
= get_group_creds(&g
, &i
.gid
);
2030 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2037 if (!isempty(mode
) && !streq(mode
, "-")) {
2038 const char *mm
= mode
;
2042 i
.mask_perms
= true;
2046 if (parse_mode(mm
, &m
) < 0) {
2047 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2054 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2056 if (!isempty(age
) && !streq(age
, "-")) {
2057 const char *a
= age
;
2060 i
.keep_first_level
= true;
2064 if (parse_sec(a
, &i
.age
) < 0) {
2065 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2072 h
= needs_glob(i
.type
) ? globs
: items
;
2074 existing
= ordered_hashmap_get(h
, i
.path
);
2078 for (n
= 0; n
< existing
->count
; n
++) {
2079 if (!item_compatible(existing
->items
+ n
, &i
)) {
2080 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2081 fname
, line
, i
.path
);
2086 existing
= new0(ItemArray
, 1);
2087 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2092 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2095 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2097 /* Sort item array, to enforce stable ordering of application */
2098 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2104 static void help(void) {
2105 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2106 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2107 " -h --help Show this help\n"
2108 " --version Show package version\n"
2109 " --create Create marked files/directories\n"
2110 " --clean Clean up marked directories\n"
2111 " --remove Remove marked files/directories\n"
2112 " --boot Execute actions only safe at boot\n"
2113 " --prefix=PATH Only apply rules with the specified prefix\n"
2114 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2115 " --root=PATH Operate on an alternate filesystem root\n",
2116 program_invocation_short_name
);
2119 static int parse_argv(int argc
, char *argv
[]) {
2122 ARG_VERSION
= 0x100,
2132 static const struct option options
[] = {
2133 { "help", no_argument
, NULL
, 'h' },
2134 { "version", no_argument
, NULL
, ARG_VERSION
},
2135 { "create", no_argument
, NULL
, ARG_CREATE
},
2136 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2137 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2138 { "boot", no_argument
, NULL
, ARG_BOOT
},
2139 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2140 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2141 { "root", required_argument
, NULL
, ARG_ROOT
},
2150 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2178 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2182 case ARG_EXCLUDE_PREFIX
:
2183 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2188 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2197 assert_not_reached("Unhandled option");
2200 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2201 log_error("You need to specify at least one of --clean, --create or --remove.");
2208 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2209 _cleanup_fclose_
FILE *f
= NULL
;
2210 char line
[LINE_MAX
];
2218 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &f
);
2220 if (ignore_enoent
&& r
== -ENOENT
) {
2221 log_debug_errno(r
, "Failed to open \"%s\": %m", fn
);
2225 return log_error_errno(r
, "Failed to open '%s', ignoring: %m", fn
);
2227 log_debug("Reading config file \"%s\".", fn
);
2229 FOREACH_LINE(line
, f
, break) {
2236 if (*l
== '#' || *l
== 0)
2239 k
= parse_line(fn
, v
, l
);
2240 if (k
< 0 && r
== 0)
2244 /* we have to determine age parameter for each entry of type X */
2245 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2247 Item
*j
, *candidate_item
= NULL
;
2249 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2252 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2253 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2256 if (path_equal(j
->path
, i
->path
)) {
2261 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2262 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2266 if (candidate_item
&& candidate_item
->age_set
) {
2267 i
->age
= candidate_item
->age
;
2273 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2281 int main(int argc
, char *argv
[]) {
2286 r
= parse_argv(argc
, argv
);
2290 log_set_target(LOG_TARGET_AUTO
);
2291 log_parse_environment();
2296 mac_selinux_init(NULL
);
2298 items
= ordered_hashmap_new(&string_hash_ops
);
2299 globs
= ordered_hashmap_new(&string_hash_ops
);
2301 if (!items
|| !globs
) {
2308 if (optind
< argc
) {
2311 for (j
= optind
; j
< argc
; j
++) {
2312 k
= read_config_file(argv
[j
], false);
2313 if (k
< 0 && r
== 0)
2318 _cleanup_strv_free_
char **files
= NULL
;
2321 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, conf_file_dirs
);
2323 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2327 STRV_FOREACH(f
, files
) {
2328 k
= read_config_file(*f
, true);
2329 if (k
< 0 && r
== 0)
2334 /* The non-globbing ones usually create things, hence we apply
2336 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2337 k
= process_item_array(a
);
2338 if (k
< 0 && r
== 0)
2342 /* The globbing ones usually alter things, hence we apply them
2344 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2345 k
= process_item_array(a
);
2346 if (k
< 0 && r
== 0)
2351 while ((a
= ordered_hashmap_steal_first(items
)))
2354 while ((a
= ordered_hashmap_steal_first(globs
)))
2357 ordered_hashmap_free(items
);
2358 ordered_hashmap_free(globs
);
2360 free(arg_include_prefixes
);
2361 free(arg_exclude_prefixes
);
2364 set_free_free(unix_sockets
);
2366 mac_selinux_finish();
2368 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;