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
)) {
1229 RUN_WITH_UMASK((~i
->mode
) & 0777)
1230 r
= btrfs_subvol_make(i
->path
);
1234 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1235 RUN_WITH_UMASK(0000)
1236 r
= mkdir_label(i
->path
, i
->mode
);
1241 if (r
!= -EEXIST
&& r
!= -EROFS
)
1242 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1244 k
= is_dir(i
->path
, false);
1245 if (k
== -ENOENT
&& r
== -EROFS
)
1246 return log_error_errno(r
, "%s does not exist and cannot be created as the file system is read-only.", i
->path
);
1248 return log_error_errno(k
, "Failed to check if %s exists: %m", i
->path
);
1250 log_warning("\"%s\" already exists and is not a directory.", i
->path
);
1254 creation
= CREATION_EXISTING
;
1256 creation
= CREATION_NORMAL
;
1258 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1260 if (IN_SET(i
->type
, CREATE_SUBVOLUME_NEW_QUOTA
, CREATE_SUBVOLUME_INHERIT_QUOTA
)) {
1261 r
= btrfs_subvol_auto_qgroup(i
->path
, 0, i
->type
== CREATE_SUBVOLUME_NEW_QUOTA
);
1263 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
);
1267 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i
->path
);
1270 if (r
== -ENOPROTOOPT
) {
1271 log_debug_errno(r
, "Couldn't adjust quota for subvolume \"%s\" because quota support is disabled: %m", i
->path
);
1275 return log_error_errno(r
, "Failed to adjust quota for subvolume \"%s\": %m", i
->path
);
1277 log_debug("Adjusted quota for subvolume \"%s\".", i
->path
);
1279 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i
->path
);
1282 r
= path_set_perms(i
, i
->path
);
1290 RUN_WITH_UMASK(0000) {
1291 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1292 r
= mkfifo(i
->path
, i
->mode
);
1293 mac_selinux_create_file_clear();
1297 if (errno
!= EEXIST
)
1298 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1300 if (lstat(i
->path
, &st
) < 0)
1301 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1303 if (!S_ISFIFO(st
.st_mode
)) {
1306 RUN_WITH_UMASK(0000) {
1307 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1308 r
= mkfifo_atomic(i
->path
, i
->mode
);
1309 mac_selinux_create_file_clear();
1313 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1314 creation
= CREATION_FORCE
;
1316 log_warning("\"%s\" already exists and is not a fifo.", i
->path
);
1320 creation
= CREATION_EXISTING
;
1322 creation
= CREATION_NORMAL
;
1323 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1325 r
= path_set_perms(i
, i
->path
);
1332 case CREATE_SYMLINK
: {
1333 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1335 return log_error_errno(r
, "Failed to substitute specifiers in symlink target %s: %m", i
->argument
);
1337 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1338 r
= symlink(resolved
, i
->path
);
1339 mac_selinux_create_file_clear();
1342 _cleanup_free_
char *x
= NULL
;
1344 if (errno
!= EEXIST
)
1345 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1347 r
= readlink_malloc(i
->path
, &x
);
1348 if (r
< 0 || !streq(resolved
, x
)) {
1351 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1352 r
= symlink_atomic(resolved
, i
->path
);
1353 mac_selinux_create_file_clear();
1356 return log_error_errno(r
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1358 creation
= CREATION_FORCE
;
1360 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1364 creation
= CREATION_EXISTING
;
1367 creation
= CREATION_NORMAL
;
1368 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1372 case CREATE_BLOCK_DEVICE
:
1373 case CREATE_CHAR_DEVICE
: {
1376 if (have_effective_cap(CAP_MKNOD
) == 0) {
1377 /* In a container we lack CAP_MKNOD. We
1378 shouldn't attempt to create the device node in
1379 that case to avoid noise, and we don't support
1380 virtualized devices in containers anyway. */
1382 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1386 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1388 RUN_WITH_UMASK(0000) {
1389 mac_selinux_create_file_prepare(i
->path
, file_type
);
1390 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1391 mac_selinux_create_file_clear();
1395 if (errno
== EPERM
) {
1396 log_debug("We lack permissions, possibly because of cgroup configuration; "
1397 "skipping creation of device node %s.", i
->path
);
1401 if (errno
!= EEXIST
)
1402 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1404 if (lstat(i
->path
, &st
) < 0)
1405 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1407 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1411 RUN_WITH_UMASK(0000) {
1412 mac_selinux_create_file_prepare(i
->path
, file_type
);
1413 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1414 mac_selinux_create_file_clear();
1418 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1419 creation
= CREATION_FORCE
;
1421 log_debug("%s is not a device node.", i
->path
);
1425 creation
= CREATION_EXISTING
;
1427 creation
= CREATION_NORMAL
;
1429 log_debug("%s %s device node \"%s\" %u:%u.",
1430 creation_mode_verb_to_string(creation
),
1431 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1432 i
->path
, major(i
->mode
), minor(i
->mode
));
1434 r
= path_set_perms(i
, i
->path
);
1443 r
= glob_item(i
, path_set_perms
, false);
1448 case RECURSIVE_RELABEL_PATH
:
1449 r
= glob_item(i
, path_set_perms
, true);
1455 r
= glob_item(i
, path_set_xattrs
, false);
1460 case RECURSIVE_SET_XATTR
:
1461 r
= glob_item(i
, path_set_xattrs
, true);
1467 r
= glob_item(i
, path_set_acls
, false);
1472 case RECURSIVE_SET_ACL
:
1473 r
= glob_item(i
, path_set_acls
, true);
1479 r
= glob_item(i
, path_set_attribute
, false);
1484 case RECURSIVE_SET_ATTRIBUTE
:
1485 r
= glob_item(i
, path_set_attribute
, true);
1494 static int remove_item_instance(Item
*i
, const char *instance
) {
1502 if (remove(instance
) < 0 && errno
!= ENOENT
)
1503 return log_error_errno(errno
, "rm(%s): %m", instance
);
1507 case TRUNCATE_DIRECTORY
:
1508 case RECURSIVE_REMOVE_PATH
:
1509 /* FIXME: we probably should use dir_cleanup() here
1510 * instead of rm_rf() so that 'x' is honoured. */
1511 log_debug("rm -rf \"%s\"", instance
);
1512 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
|REMOVE_SUBVOLUME
: 0) | REMOVE_PHYSICAL
);
1513 if (r
< 0 && r
!= -ENOENT
)
1514 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1519 assert_not_reached("wut?");
1525 static int remove_item(Item
*i
) {
1530 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1536 case CREATE_DIRECTORY
:
1537 case CREATE_SUBVOLUME
:
1538 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1539 case CREATE_SUBVOLUME_NEW_QUOTA
:
1541 case CREATE_SYMLINK
:
1542 case CREATE_CHAR_DEVICE
:
1543 case CREATE_BLOCK_DEVICE
:
1545 case IGNORE_DIRECTORY_PATH
:
1548 case RECURSIVE_RELABEL_PATH
:
1552 case RECURSIVE_SET_XATTR
:
1554 case RECURSIVE_SET_ACL
:
1556 case RECURSIVE_SET_ATTRIBUTE
:
1560 case TRUNCATE_DIRECTORY
:
1561 case RECURSIVE_REMOVE_PATH
:
1562 r
= glob_item(i
, remove_item_instance
, false);
1569 static int clean_item_instance(Item
*i
, const char* instance
) {
1570 _cleanup_closedir_
DIR *d
= NULL
;
1574 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1581 n
= now(CLOCK_REALTIME
);
1585 cutoff
= n
- i
->age
;
1587 d
= opendir_nomod(instance
);
1589 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
1590 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1594 log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1598 if (fstat(dirfd(d
), &s
) < 0)
1599 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1601 if (!S_ISDIR(s
.st_mode
)) {
1602 log_error("%s is not a directory.", i
->path
);
1606 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1607 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1609 mountpoint
= s
.st_dev
!= ps
.st_dev
|| s
.st_ino
== ps
.st_ino
;
1611 log_debug("Cleanup threshold for %s \"%s\" is %s",
1612 mountpoint
? "mount point" : "directory",
1614 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1616 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1617 MAX_DEPTH
, i
->keep_first_level
);
1620 static int clean_item(Item
*i
) {
1625 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1628 case CREATE_DIRECTORY
:
1629 case CREATE_SUBVOLUME
:
1630 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1631 case CREATE_SUBVOLUME_NEW_QUOTA
:
1632 case TRUNCATE_DIRECTORY
:
1635 clean_item_instance(i
, i
->path
);
1637 case IGNORE_DIRECTORY_PATH
:
1638 r
= glob_item(i
, clean_item_instance
, false);
1647 static int process_item_array(ItemArray
*array
);
1649 static int process_item(Item
*i
) {
1651 _cleanup_free_
char *prefix
= NULL
;
1660 prefix
= malloc(strlen(i
->path
) + 1);
1664 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1667 j
= ordered_hashmap_get(items
, prefix
);
1671 s
= process_item_array(j
);
1672 if (s
< 0 && t
== 0)
1677 r
= arg_create
? create_item(i
) : 0;
1678 q
= arg_remove
? remove_item(i
) : 0;
1679 p
= arg_clean
? clean_item(i
) : 0;
1687 static int process_item_array(ItemArray
*array
) {
1693 for (n
= 0; n
< array
->count
; n
++) {
1694 k
= process_item(array
->items
+ n
);
1695 if (k
< 0 && r
== 0)
1702 static void item_free_contents(Item
*i
) {
1706 strv_free(i
->xattrs
);
1709 acl_free(i
->acl_access
);
1710 acl_free(i
->acl_default
);
1714 static void item_array_free(ItemArray
*a
) {
1720 for (n
= 0; n
< a
->count
; n
++)
1721 item_free_contents(a
->items
+ n
);
1726 static int item_compare(const void *a
, const void *b
) {
1727 const Item
*x
= a
, *y
= b
;
1729 /* Make sure that the ownership taking item is put first, so
1730 * that we first create the node, and then can adjust it */
1732 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1734 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1737 return (int) x
->type
- (int) y
->type
;
1740 static bool item_compatible(Item
*a
, Item
*b
) {
1743 assert(streq(a
->path
, b
->path
));
1745 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1746 /* check if the items are the same */
1747 return streq_ptr(a
->argument
, b
->argument
) &&
1749 a
->uid_set
== b
->uid_set
&&
1752 a
->gid_set
== b
->gid_set
&&
1755 a
->mode_set
== b
->mode_set
&&
1756 a
->mode
== b
->mode
&&
1758 a
->age_set
== b
->age_set
&&
1761 a
->mask_perms
== b
->mask_perms
&&
1763 a
->keep_first_level
== b
->keep_first_level
&&
1765 a
->major_minor
== b
->major_minor
;
1770 static bool should_include_path(const char *path
) {
1773 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1774 if (path_startswith(path
, *prefix
)) {
1775 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1780 STRV_FOREACH(prefix
, arg_include_prefixes
)
1781 if (path_startswith(path
, *prefix
)) {
1782 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1786 /* no matches, so we should include this path only if we
1787 * have no whitelist at all */
1788 if (strv_length(arg_include_prefixes
) == 0)
1791 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1795 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1797 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1798 _cleanup_(item_free_contents
) Item i
= {};
1799 ItemArray
*existing
;
1802 bool force
= false, boot
= false;
1808 r
= extract_many_words(
1820 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1822 log_error("[%s:%u] Syntax error.", fname
, line
);
1826 if (!isempty(buffer
) && !streq(buffer
, "-")) {
1827 i
.argument
= strdup(buffer
);
1832 if (isempty(action
)) {
1833 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1837 for (pos
= 1; action
[pos
]; pos
++) {
1838 if (action
[pos
] == '!' && !boot
)
1840 else if (action
[pos
] == '+' && !force
)
1843 log_error("[%s:%u] Unknown modifiers in command '%s'",
1844 fname
, line
, action
);
1849 if (boot
&& !arg_boot
) {
1850 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1858 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1860 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1866 case CREATE_DIRECTORY
:
1867 case CREATE_SUBVOLUME
:
1868 case CREATE_SUBVOLUME_INHERIT_QUOTA
:
1869 case CREATE_SUBVOLUME_NEW_QUOTA
:
1870 case TRUNCATE_DIRECTORY
:
1873 case IGNORE_DIRECTORY_PATH
:
1875 case RECURSIVE_REMOVE_PATH
:
1878 case RECURSIVE_RELABEL_PATH
:
1880 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
1888 case CREATE_SYMLINK
:
1890 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1898 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1905 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1908 } else if (!path_is_absolute(i
.argument
)) {
1909 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1913 path_kill_slashes(i
.argument
);
1916 case CREATE_CHAR_DEVICE
:
1917 case CREATE_BLOCK_DEVICE
: {
1918 unsigned major
, minor
;
1921 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1925 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1926 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1930 i
.major_minor
= makedev(major
, minor
);
1935 case RECURSIVE_SET_XATTR
:
1937 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1940 r
= parse_xattrs_from_arg(&i
);
1946 case RECURSIVE_SET_ACL
:
1948 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
1951 r
= parse_acls_from_arg(&i
);
1957 case RECURSIVE_SET_ATTRIBUTE
:
1959 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
1962 r
= parse_attribute_from_arg(&i
);
1968 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
1972 if (!path_is_absolute(i
.path
)) {
1973 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
1977 path_kill_slashes(i
.path
);
1979 if (!should_include_path(i
.path
))
1985 p
= prefix_root(arg_root
, i
.path
);
1993 if (!isempty(user
) && !streq(user
, "-")) {
1994 const char *u
= user
;
1996 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
1998 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
2005 if (!isempty(group
) && !streq(group
, "-")) {
2006 const char *g
= group
;
2008 r
= get_group_creds(&g
, &i
.gid
);
2010 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
2017 if (!isempty(mode
) && !streq(mode
, "-")) {
2018 const char *mm
= mode
;
2022 i
.mask_perms
= true;
2026 if (parse_mode(mm
, &m
) < 0) {
2027 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
2034 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
) ? 0755 : 0644;
2036 if (!isempty(age
) && !streq(age
, "-")) {
2037 const char *a
= age
;
2040 i
.keep_first_level
= true;
2044 if (parse_sec(a
, &i
.age
) < 0) {
2045 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
2052 h
= needs_glob(i
.type
) ? globs
: items
;
2054 existing
= ordered_hashmap_get(h
, i
.path
);
2058 for (n
= 0; n
< existing
->count
; n
++) {
2059 if (!item_compatible(existing
->items
+ n
, &i
)) {
2060 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2061 fname
, line
, i
.path
);
2066 existing
= new0(ItemArray
, 1);
2067 r
= ordered_hashmap_put(h
, i
.path
, existing
);
2072 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2075 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2077 /* Sort item array, to enforce stable ordering of application */
2078 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2084 static void help(void) {
2085 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2086 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2087 " -h --help Show this help\n"
2088 " --version Show package version\n"
2089 " --create Create marked files/directories\n"
2090 " --clean Clean up marked directories\n"
2091 " --remove Remove marked files/directories\n"
2092 " --boot Execute actions only safe at boot\n"
2093 " --prefix=PATH Only apply rules with the specified prefix\n"
2094 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2095 " --root=PATH Operate on an alternate filesystem root\n",
2096 program_invocation_short_name
);
2099 static int parse_argv(int argc
, char *argv
[]) {
2102 ARG_VERSION
= 0x100,
2112 static const struct option options
[] = {
2113 { "help", no_argument
, NULL
, 'h' },
2114 { "version", no_argument
, NULL
, ARG_VERSION
},
2115 { "create", no_argument
, NULL
, ARG_CREATE
},
2116 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2117 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2118 { "boot", no_argument
, NULL
, ARG_BOOT
},
2119 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2120 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2121 { "root", required_argument
, NULL
, ARG_ROOT
},
2130 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2158 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2162 case ARG_EXCLUDE_PREFIX
:
2163 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2168 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
2177 assert_not_reached("Unhandled option");
2180 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2181 log_error("You need to specify at least one of --clean, --create or --remove.");
2188 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2189 _cleanup_fclose_
FILE *f
= NULL
;
2190 char line
[LINE_MAX
];
2198 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &f
);
2200 if (ignore_enoent
&& r
== -ENOENT
) {
2201 log_debug_errno(r
, "Failed to open \"%s\": %m", fn
);
2205 return log_error_errno(r
, "Failed to open '%s', ignoring: %m", fn
);
2207 log_debug("Reading config file \"%s\".", fn
);
2209 FOREACH_LINE(line
, f
, break) {
2216 if (*l
== '#' || *l
== 0)
2219 k
= parse_line(fn
, v
, l
);
2220 if (k
< 0 && r
== 0)
2224 /* we have to determine age parameter for each entry of type X */
2225 ORDERED_HASHMAP_FOREACH(i
, globs
, iterator
) {
2227 Item
*j
, *candidate_item
= NULL
;
2229 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2232 ORDERED_HASHMAP_FOREACH(j
, items
, iter
) {
2233 if (!IN_SET(j
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
, CREATE_SUBVOLUME
, CREATE_SUBVOLUME_INHERIT_QUOTA
, CREATE_SUBVOLUME_NEW_QUOTA
))
2236 if (path_equal(j
->path
, i
->path
)) {
2241 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2242 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2246 if (candidate_item
&& candidate_item
->age_set
) {
2247 i
->age
= candidate_item
->age
;
2253 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2261 int main(int argc
, char *argv
[]) {
2266 r
= parse_argv(argc
, argv
);
2270 log_set_target(LOG_TARGET_AUTO
);
2271 log_parse_environment();
2276 mac_selinux_init(NULL
);
2278 items
= ordered_hashmap_new(&string_hash_ops
);
2279 globs
= ordered_hashmap_new(&string_hash_ops
);
2281 if (!items
|| !globs
) {
2288 if (optind
< argc
) {
2291 for (j
= optind
; j
< argc
; j
++) {
2292 k
= read_config_file(argv
[j
], false);
2293 if (k
< 0 && r
== 0)
2298 _cleanup_strv_free_
char **files
= NULL
;
2301 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, conf_file_dirs
);
2303 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2307 STRV_FOREACH(f
, files
) {
2308 k
= read_config_file(*f
, true);
2309 if (k
< 0 && r
== 0)
2314 /* The non-globbing ones usually create things, hence we apply
2316 ORDERED_HASHMAP_FOREACH(a
, items
, iterator
) {
2317 k
= process_item_array(a
);
2318 if (k
< 0 && r
== 0)
2322 /* The globbing ones usually alter things, hence we apply them
2324 ORDERED_HASHMAP_FOREACH(a
, globs
, iterator
) {
2325 k
= process_item_array(a
);
2326 if (k
< 0 && r
== 0)
2331 while ((a
= ordered_hashmap_steal_first(items
)))
2334 while ((a
= ordered_hashmap_steal_first(globs
)))
2337 ordered_hashmap_free(items
);
2338 ordered_hashmap_free(globs
);
2340 free(arg_include_prefixes
);
2341 free(arg_exclude_prefixes
);
2344 set_free_free(unix_sockets
);
2346 mac_selinux_finish();
2348 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;