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/>.
38 #include <sys/xattr.h>
46 #include "path-util.h"
50 #include "conf-files.h"
51 #include "capability.h"
52 #include "specifier.h"
56 #include "selinux-util.h"
57 #include "btrfs-util.h"
59 #include "formats-util.h"
61 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
62 * them in the file system. This is intended to be used to create
63 * properly owned directories beneath /tmp, /var/tmp, /run, which are
64 * volatile and hence need to be recreated on bootup. */
66 typedef enum ItemType
{
67 /* These ones take file names */
70 CREATE_DIRECTORY
= 'd',
71 TRUNCATE_DIRECTORY
= 'D',
72 CREATE_SUBVOLUME
= 'v',
75 CREATE_CHAR_DEVICE
= 'c',
76 CREATE_BLOCK_DEVICE
= 'b',
79 /* These ones take globs */
82 RECURSIVE_SET_XATTR
= 'T',
84 RECURSIVE_SET_ACL
= 'A',
86 RECURSIVE_SET_ATTRIBUTE
= 'H',
88 IGNORE_DIRECTORY_PATH
= 'X',
90 RECURSIVE_REMOVE_PATH
= 'R',
92 RECURSIVE_RELABEL_PATH
= 'Z',
93 ADJUST_MODE
= 'm', /* legacy, 'z' is identical to this */
112 unsigned attribute_value
;
113 unsigned attribute_mask
;
120 bool attribute_set
:1;
122 bool keep_first_level
:1;
129 typedef struct ItemArray
{
135 static bool arg_create
= false;
136 static bool arg_clean
= false;
137 static bool arg_remove
= false;
138 static bool arg_boot
= false;
140 static char **arg_include_prefixes
= NULL
;
141 static char **arg_exclude_prefixes
= NULL
;
142 static char *arg_root
= NULL
;
144 static const char conf_file_dirs
[] = CONF_DIRS_NULSTR("tmpfiles");
146 #define MAX_DEPTH 256
148 static Hashmap
*items
= NULL
, *globs
= NULL
;
149 static Set
*unix_sockets
= NULL
;
151 static const Specifier specifier_table
[] = {
152 { 'm', specifier_machine_id
, NULL
},
153 { 'b', specifier_boot_id
, NULL
},
154 { 'H', specifier_host_name
, NULL
},
155 { 'v', specifier_kernel_release
, NULL
},
159 static bool needs_glob(ItemType t
) {
163 IGNORE_DIRECTORY_PATH
,
165 RECURSIVE_REMOVE_PATH
,
168 RECURSIVE_RELABEL_PATH
,
174 RECURSIVE_SET_ATTRIBUTE
);
177 static bool takes_ownership(ItemType t
) {
191 IGNORE_DIRECTORY_PATH
,
193 RECURSIVE_REMOVE_PATH
);
196 static struct Item
* find_glob(Hashmap
*h
, const char *match
) {
200 HASHMAP_FOREACH(j
, h
, i
) {
203 for (n
= 0; n
< j
->count
; n
++) {
204 Item
*item
= j
->items
+ n
;
206 if (fnmatch(item
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
214 static void load_unix_sockets(void) {
215 _cleanup_fclose_
FILE *f
= NULL
;
221 /* We maintain a cache of the sockets we found in
222 * /proc/net/unix to speed things up a little. */
224 unix_sockets
= set_new(&string_hash_ops
);
228 f
= fopen("/proc/net/unix", "re");
233 if (!fgets(line
, sizeof(line
), f
))
240 if (!fgets(line
, sizeof(line
), f
))
245 p
= strchr(line
, ':');
253 p
+= strspn(p
, WHITESPACE
);
254 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
255 p
+= strspn(p
, WHITESPACE
);
264 path_kill_slashes(s
);
266 k
= set_consume(unix_sockets
, s
);
267 if (k
< 0 && k
!= -EEXIST
)
274 set_free_free(unix_sockets
);
278 static bool unix_socket_alive(const char *fn
) {
284 return !!set_get(unix_sockets
, (char*) fn
);
286 /* We don't know, so assume yes */
290 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
292 union file_handle_union h
= FILE_HANDLE_INIT
;
293 int mount_id_parent
, mount_id
;
296 r_p
= name_to_handle_at(dirfd(d
), ".", &h
.handle
, &mount_id_parent
, 0);
300 h
.handle
.handle_bytes
= MAX_HANDLE_SZ
;
301 r
= name_to_handle_at(dirfd(d
), subdir
, &h
.handle
, &mount_id
, 0);
305 /* got no handle; make no assumptions, return error */
306 if (r_p
< 0 && r
< 0)
309 /* got both handles; if they differ, it is a mount point */
310 if (r_p
>= 0 && r
>= 0)
311 return mount_id_parent
!= mount_id
;
313 /* got only one handle; assume different mount points if one
314 * of both queries was not supported by the filesystem */
315 if (r_p
== -ENOSYS
|| r_p
== -EOPNOTSUPP
|| r
== -ENOSYS
|| r
== -EOPNOTSUPP
)
324 static DIR* xopendirat_nomod(int dirfd
, const char *path
) {
327 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
|O_NOATIME
);
331 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
335 dir
= xopendirat(dirfd
, path
, O_NOFOLLOW
);
337 log_debug_errno(errno
, "Cannot open %sdirectory \"%s\": %m", dirfd
== AT_FDCWD
? "" : "sub", path
);
342 static DIR* opendir_nomod(const char *path
) {
343 return xopendirat_nomod(AT_FDCWD
, path
);
346 static int dir_cleanup(
350 const struct stat
*ds
,
355 bool keep_this_level
) {
358 struct timespec times
[2];
359 bool deleted
= false;
362 while ((dent
= readdir(d
))) {
365 _cleanup_free_
char *sub_path
= NULL
;
367 if (STR_IN_SET(dent
->d_name
, ".", ".."))
370 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
374 /* FUSE, NFS mounts, SELinux might return EACCES */
376 log_debug_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
378 log_error_errno(errno
, "stat(%s/%s) failed: %m", p
, dent
->d_name
);
383 /* Stay on the same filesystem */
384 if (s
.st_dev
!= rootdev
) {
385 log_debug("Ignoring \"%s/%s\": different filesystem.", p
, dent
->d_name
);
389 /* Try to detect bind mounts of the same filesystem instance; they
390 * do not differ in device major/minors. This type of query is not
391 * supported on all kernels or filesystem types though. */
392 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0) {
393 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
398 /* Do not delete read-only files owned by root */
399 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
)) {
400 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p
, dent
->d_name
);
404 sub_path
= strjoin(p
, "/", dent
->d_name
, NULL
);
410 /* Is there an item configured for this path? */
411 if (hashmap_get(items
, sub_path
)) {
412 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path
);
416 if (find_glob(globs
, sub_path
)) {
417 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path
);
421 if (S_ISDIR(s
.st_mode
)) {
424 streq(dent
->d_name
, "lost+found") &&
426 log_debug("Ignoring \"%s\".", sub_path
);
431 log_warning("Reached max depth on \"%s\".", sub_path
);
433 _cleanup_closedir_
DIR *sub_dir
;
436 sub_dir
= xopendirat_nomod(dirfd(d
), dent
->d_name
);
439 r
= log_error_errno(errno
, "opendir(%s) failed: %m", sub_path
);
444 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
449 /* Note: if you are wondering why we don't
450 * support the sticky bit for excluding
451 * directories from cleaning like we do it for
452 * other file system objects: well, the sticky
453 * bit already has a meaning for directories,
454 * so we don't want to overload that. */
456 if (keep_this_level
) {
457 log_debug("Keeping \"%s\".", sub_path
);
461 /* Ignore ctime, we change it when deleting */
462 age
= timespec_load(&s
.st_mtim
);
464 char a
[FORMAT_TIMESTAMP_MAX
];
465 /* Follows spelling in stat(1). */
466 log_debug("Directory \"%s\": modify time %s is too new.",
468 format_timestamp_us(a
, sizeof(a
), age
));
472 age
= timespec_load(&s
.st_atim
);
474 char a
[FORMAT_TIMESTAMP_MAX
];
475 log_debug("Directory \"%s\": access time %s is too new.",
477 format_timestamp_us(a
, sizeof(a
), age
));
481 log_debug("Removing directory \"%s\".", sub_path
);
482 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0)
483 if (errno
!= ENOENT
&& errno
!= ENOTEMPTY
) {
484 log_error_errno(errno
, "rmdir(%s): %m", sub_path
);
489 /* Skip files for which the sticky bit is
490 * set. These are semantics we define, and are
491 * unknown elsewhere. See XDG_RUNTIME_DIR
492 * specification for details. */
493 if (s
.st_mode
& S_ISVTX
) {
494 log_debug("Skipping \"%s\": sticky bit set.", sub_path
);
498 if (mountpoint
&& S_ISREG(s
.st_mode
))
499 if ((streq(dent
->d_name
, ".journal") && s
.st_uid
== 0) ||
500 streq(dent
->d_name
, "aquota.user") ||
501 streq(dent
->d_name
, "aquota.group")) {
502 log_debug("Skipping \"%s\".", sub_path
);
506 /* Ignore sockets that are listed in /proc/net/unix */
507 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
)) {
508 log_debug("Skipping \"%s\": live socket.", sub_path
);
512 /* Ignore device nodes */
513 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
)) {
514 log_debug("Skipping \"%s\": a device.", sub_path
);
518 /* Keep files on this level around if this is
520 if (keep_this_level
) {
521 log_debug("Keeping \"%s\".", sub_path
);
525 age
= timespec_load(&s
.st_mtim
);
527 char a
[FORMAT_TIMESTAMP_MAX
];
528 /* Follows spelling in stat(1). */
529 log_debug("File \"%s\": modify time %s is too new.",
531 format_timestamp_us(a
, sizeof(a
), age
));
535 age
= timespec_load(&s
.st_atim
);
537 char a
[FORMAT_TIMESTAMP_MAX
];
538 log_debug("File \"%s\": access time %s is too new.",
540 format_timestamp_us(a
, sizeof(a
), age
));
544 age
= timespec_load(&s
.st_ctim
);
546 char a
[FORMAT_TIMESTAMP_MAX
];
547 log_debug("File \"%s\": change time %s is too new.",
549 format_timestamp_us(a
, sizeof(a
), age
));
553 log_debug("unlink \"%s\"", sub_path
);
555 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0)
557 r
= log_error_errno(errno
, "unlink(%s): %m", sub_path
);
566 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
568 /* Restore original directory timestamps */
569 times
[0] = ds
->st_atim
;
570 times
[1] = ds
->st_mtim
;
572 age1
= timespec_load(&ds
->st_atim
);
573 age2
= timespec_load(&ds
->st_mtim
);
574 log_debug("Restoring access and modification time on \"%s\": %s, %s",
576 format_timestamp_us(a
, sizeof(a
), age1
),
577 format_timestamp_us(b
, sizeof(b
), age2
));
578 if (futimens(dirfd(d
), times
) < 0)
579 log_error_errno(errno
, "utimensat(%s): %m", p
);
585 static int path_set_perms(Item
*i
, const char *path
) {
586 _cleanup_close_
int fd
= -1;
592 /* We open the file with O_PATH here, to make the operation
593 * somewhat atomic. Also there's unfortunately no fchmodat()
594 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
597 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
599 return log_error_errno(errno
, "Adjusting owner and mode for %s failed: %m", path
);
601 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
602 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
604 if (S_ISLNK(st
.st_mode
))
605 log_debug("Skipping mode an owner fix for symlink %s.", path
);
607 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
608 xsprintf(fn
, "/proc/self/fd/%i", fd
);
610 /* not using i->path directly because it may be a glob */
615 if (!(st
.st_mode
& 0111))
617 if (!(st
.st_mode
& 0222))
619 if (!(st
.st_mode
& 0444))
621 if (!S_ISDIR(st
.st_mode
))
622 m
&= ~07000; /* remove sticky/sgid/suid bit, unless directory */
625 if (m
== (st
.st_mode
& 07777))
626 log_debug("\"%s\" has right mode %o", path
, st
.st_mode
);
628 log_debug("chmod \"%s\" to mode %o", path
, m
);
629 if (chmod(fn
, m
) < 0)
630 return log_error_errno(errno
, "chmod(%s) failed: %m", path
);
634 if ((i
->uid
!= st
.st_uid
|| i
->gid
!= st
.st_gid
) &&
635 (i
->uid_set
|| i
->gid_set
)) {
636 log_debug("chown \"%s\" to "UID_FMT
"."GID_FMT
,
638 i
->uid_set
? i
->uid
: UID_INVALID
,
639 i
->gid_set
? i
->gid
: GID_INVALID
);
641 i
->uid_set
? i
->uid
: UID_INVALID
,
642 i
->gid_set
? i
->gid
: GID_INVALID
) < 0)
643 return log_error_errno(errno
, "chown(%s) failed: %m", path
);
649 return label_fix(path
, false, false);
652 static int parse_xattrs_from_arg(Item
*i
) {
662 _cleanup_free_
char *name
= NULL
, *value
= NULL
, *xattr
= NULL
, *xattr_replaced
= NULL
;
664 r
= unquote_first_word(&p
, &xattr
, UNQUOTE_CUNESCAPE
);
666 log_warning_errno(r
, "Failed to parse extended attribute '%s', ignoring: %m", p
);
670 r
= specifier_printf(xattr
, specifier_table
, NULL
, &xattr_replaced
);
672 return log_error_errno(r
, "Failed to replace specifiers in extended attribute '%s': %m", xattr
);
674 r
= split_pair(xattr_replaced
, "=", &name
, &value
);
676 log_warning_errno(r
, "Failed to parse extended attribute, ignoring: %s", xattr
);
680 if (isempty(name
) || isempty(value
)) {
681 log_warning("Malformed extended attribute found, ignoring: %s", xattr
);
685 if (strv_push_pair(&i
->xattrs
, name
, value
) < 0)
694 static int path_set_xattrs(Item
*i
, const char *path
) {
695 char **name
, **value
;
700 STRV_FOREACH_PAIR(name
, value
, i
->xattrs
) {
704 log_debug("Setting extended attribute '%s=%s' on %s.", *name
, *value
, path
);
705 if (lsetxattr(path
, *name
, *value
, n
, 0) < 0) {
706 log_error("Setting extended attribute %s=%s on %s failed: %m", *name
, *value
, path
);
713 static int parse_acls_from_arg(Item
*item
) {
719 /* If force (= modify) is set, we will not modify the acl
720 * afterwards, so the mask can be added now if necessary. */
722 r
= parse_acl(item
->argument
, &item
->acl_access
, &item
->acl_default
, !item
->force
);
724 log_warning_errno(r
, "Failed to parse ACL \"%s\": %m. Ignoring", item
->argument
);
726 log_warning_errno(ENOSYS
, "ACLs are not supported. Ignoring");
733 static int path_set_acl(const char *path
, const char *pretty
, acl_type_t type
, acl_t acl
, bool modify
) {
734 _cleanup_(acl_free_charpp
) char *t
= NULL
;
735 _cleanup_(acl_freep
) acl_t dup
= NULL
;
738 /* Returns 0 for success, positive error if already warned,
739 * negative error otherwise. */
742 r
= acls_for_file(path
, type
, acl
, &dup
);
746 r
= calc_acl_mask_if_needed(&dup
);
754 /* the mask was already added earlier if needed */
757 r
= add_base_acls_if_needed(&dup
, path
);
761 t
= acl_to_any_text(dup
, NULL
, ',', TEXT_ABBREVIATE
);
762 log_debug("Setting %s ACL %s on %s.",
763 type
== ACL_TYPE_ACCESS
? "access" : "default",
766 r
= acl_set_file(path
, type
, dup
);
768 /* Return positive to indicate we already warned */
769 return -log_error_errno(errno
,
770 "Setting %s ACL \"%s\" on %s failed: %m",
771 type
== ACL_TYPE_ACCESS
? "access" : "default",
778 static int path_set_acls(Item
*item
, const char *path
) {
781 char fn
[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
782 _cleanup_close_
int fd
= -1;
788 fd
= open(path
, O_RDONLY
|O_NOFOLLOW
|O_CLOEXEC
|O_PATH
|O_NOATIME
);
790 return log_error_errno(errno
, "Adjusting ACL of %s failed: %m", path
);
792 if (fstatat(fd
, "", &st
, AT_EMPTY_PATH
) < 0)
793 return log_error_errno(errno
, "Failed to fstat() file %s: %m", path
);
795 if (S_ISLNK(st
.st_mode
)) {
796 log_debug("Skipping ACL fix for symlink %s.", path
);
800 xsprintf(fn
, "/proc/self/fd/%i", fd
);
802 if (item
->acl_access
)
803 r
= path_set_acl(fn
, path
, ACL_TYPE_ACCESS
, item
->acl_access
, item
->force
);
805 if (r
== 0 && item
->acl_default
)
806 r
= path_set_acl(fn
, path
, ACL_TYPE_DEFAULT
, item
->acl_default
, item
->force
);
809 return -r
; /* already warned */
810 else if (r
== -EOPNOTSUPP
) {
811 log_debug_errno(r
, "ACLs not supported by file system at %s", path
);
814 log_error_errno(r
, "ACL operation on \"%s\" failed: %m", path
);
819 #define ATTRIBUTES_ALL \
828 FS_JOURNAL_DATA_FL | \
835 static int parse_attribute_from_arg(Item
*item
) {
837 static const struct {
841 { 'A', FS_NOATIME_FL
}, /* do not update atime */
842 { 'S', FS_SYNC_FL
}, /* Synchronous updates */
843 { 'D', FS_DIRSYNC_FL
}, /* dirsync behaviour (directories only) */
844 { 'a', FS_APPEND_FL
}, /* writes to file may only append */
845 { 'c', FS_COMPR_FL
}, /* Compress file */
846 { 'd', FS_NODUMP_FL
}, /* do not dump file */
847 { 'e', FS_EXTENT_FL
}, /* Top of directory hierarchies*/
848 { 'i', FS_IMMUTABLE_FL
}, /* Immutable file */
849 { 'j', FS_JOURNAL_DATA_FL
}, /* Reserved for ext3 */
850 { 's', FS_SECRM_FL
}, /* Secure deletion */
851 { 'u', FS_UNRM_FL
}, /* Undelete */
852 { 't', FS_NOTAIL_FL
}, /* file tail should not be merged */
853 { 'T', FS_TOPDIR_FL
}, /* Top of directory hierarchies*/
854 { 'C', FS_NOCOW_FL
}, /* Do not cow file */
863 unsigned value
= 0, mask
= 0;
873 } else if (*p
== '-') {
876 } else if (*p
== '=') {
882 if (isempty(p
) && mode
!= MODE_SET
) {
883 log_error("Setting file attribute on '%s' needs an attribute specification.", item
->path
);
887 for (; p
&& *p
; p
++) {
890 for (i
= 0; i
< ELEMENTSOF(attributes
); i
++)
891 if (*p
== attributes
[i
].character
)
894 if (i
>= ELEMENTSOF(attributes
)) {
895 log_error("Unknown file attribute '%c' on '%s'.", *p
, item
->path
);
899 v
= attributes
[i
].value
;
901 if (mode
== MODE_ADD
|| mode
== MODE_SET
)
909 if (mode
== MODE_SET
)
910 mask
|= ATTRIBUTES_ALL
;
914 item
->attribute_mask
= mask
;
915 item
->attribute_value
= value
;
916 item
->attribute_set
= true;
921 static int path_set_attribute(Item
*item
, const char *path
) {
922 _cleanup_close_
int fd
= -1;
927 if (!item
->attribute_set
|| item
->attribute_mask
== 0)
930 fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
|O_NOATIME
|O_NOFOLLOW
);
933 return log_error_errno(errno
, "Skipping file attributes adjustment on symlink %s.", path
);
935 return log_error_errno(errno
, "Cannot open '%s': %m", path
);
938 if (fstat(fd
, &st
) < 0)
939 return log_error_errno(errno
, "Cannot stat '%s': %m", path
);
941 /* Issuing the file attribute ioctls on device nodes is not
942 * safe, as that will be delivered to the drivers, not the
943 * file system containing the device node. */
944 if (!S_ISREG(st
.st_mode
) && !S_ISDIR(st
.st_mode
)) {
945 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path
);
949 f
= item
->attribute_value
& item
->attribute_mask
;
951 /* Mask away directory-specific flags */
952 if (!S_ISDIR(st
.st_mode
))
955 r
= chattr_fd(fd
, f
, item
->attribute_mask
);
957 return log_error_errno(r
,
958 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
959 path
, item
->attribute_value
, item
->attribute_mask
);
964 static int write_one_file(Item
*i
, const char *path
) {
965 _cleanup_close_
int fd
= -1;
972 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
|O_NOFOLLOW
:
973 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
|O_NOFOLLOW
: 0;
975 RUN_WITH_UMASK(0000) {
976 mac_selinux_create_file_prepare(path
, S_IFREG
);
977 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
, i
->mode
);
978 mac_selinux_create_file_clear();
982 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
) {
983 log_debug_errno(errno
, "Not writing \"%s\": %m", path
);
987 log_error_errno(errno
, "Failed to create file %s: %m", path
);
992 _cleanup_free_
char *unescaped
= NULL
, *replaced
= NULL
;
994 log_debug("%s to \"%s\".", i
->type
== CREATE_FILE
? "Appending" : "Writing", path
);
996 r
= cunescape(i
->argument
, 0, &unescaped
);
998 return log_error_errno(r
, "Failed to unescape parameter to write: %s", i
->argument
);
1000 r
= specifier_printf(unescaped
, specifier_table
, NULL
, &replaced
);
1002 return log_error_errno(r
, "Failed to replace specifiers in parameter to write '%s': %m", unescaped
);
1004 r
= loop_write(fd
, replaced
, strlen(replaced
), false);
1006 return log_error_errno(r
, "Failed to write file \"%s\": %m", path
);
1008 log_debug("\"%s\" has been created.", path
);
1010 fd
= safe_close(fd
);
1012 if (stat(path
, &st
) < 0)
1013 return log_error_errno(errno
, "stat(%s) failed: %m", path
);
1015 if (!S_ISREG(st
.st_mode
)) {
1016 log_error("%s is not a file.", path
);
1020 r
= path_set_perms(i
, path
);
1027 typedef int (*action_t
)(Item
*, const char *);
1029 static int item_do_children(Item
*i
, const char *path
, action_t action
) {
1030 _cleanup_closedir_
DIR *d
;
1036 /* This returns the first error we run into, but nevertheless
1039 d
= opendir_nomod(path
);
1041 return errno
== ENOENT
|| errno
== ENOTDIR
? 0 : -errno
;
1044 _cleanup_free_
char *p
= NULL
;
1051 if (errno
!= 0 && r
== 0)
1057 if (STR_IN_SET(de
->d_name
, ".", ".."))
1060 p
= strjoin(path
, "/", de
->d_name
, NULL
);
1065 if (q
< 0 && q
!= -ENOENT
&& r
== 0)
1068 if (IN_SET(de
->d_type
, DT_UNKNOWN
, DT_DIR
)) {
1069 q
= item_do_children(i
, p
, action
);
1070 if (q
< 0 && r
== 0)
1078 static int glob_item(Item
*i
, action_t action
, bool recursive
) {
1079 _cleanup_globfree_ glob_t g
= {
1080 .gl_closedir
= (void (*)(void *)) closedir
,
1081 .gl_readdir
= (struct dirent
*(*)(void *)) readdir
,
1082 .gl_opendir
= (void *(*)(const char *)) opendir_nomod
,
1090 k
= glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
|GLOB_ALTDIRFUNC
, NULL
, &g
);
1091 if (k
!= 0 && k
!= GLOB_NOMATCH
)
1092 return log_error_errno(errno
?: EIO
, "glob(%s) failed: %m", i
->path
);
1094 STRV_FOREACH(fn
, g
.gl_pathv
) {
1096 if (k
< 0 && r
== 0)
1100 k
= item_do_children(i
, *fn
, action
);
1101 if (k
< 0 && r
== 0)
1114 _CREATION_MODE_INVALID
= -1
1117 static const char *creation_mode_verb_table
[_CREATION_MODE_MAX
] = {
1118 [CREATION_NORMAL
] = "Created",
1119 [CREATION_EXISTING
] = "Found existing",
1120 [CREATION_FORCE
] = "Created replacement",
1123 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb
, CreationMode
);
1125 static int create_item(Item
*i
) {
1126 _cleanup_free_
char *resolved
= NULL
;
1129 CreationMode creation
;
1133 log_debug("Running create action for entry %c %s", (char) i
->type
, i
->path
);
1138 case IGNORE_DIRECTORY_PATH
:
1140 case RECURSIVE_REMOVE_PATH
:
1145 r
= write_one_file(i
, i
->path
);
1151 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1153 return log_error_errno(r
, "Failed to substitute specifiers in copy source %s: %m", i
->argument
);
1155 log_debug("Copying tree \"%s\" to \"%s\".", resolved
, i
->path
);
1156 r
= copy_tree(resolved
, i
->path
, false);
1161 return log_error_errno(r
, "Failed to copy files to %s: %m", i
->path
);
1163 if (stat(resolved
, &a
) < 0)
1164 return log_error_errno(errno
, "stat(%s) failed: %m", resolved
);
1166 if (stat(i
->path
, &b
) < 0)
1167 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1169 if ((a
.st_mode
^ b
.st_mode
) & S_IFMT
) {
1170 log_debug("Can't copy to %s, file exists already and is of different type", i
->path
);
1175 r
= path_set_perms(i
, i
->path
);
1182 r
= glob_item(i
, write_one_file
, false);
1188 case CREATE_DIRECTORY
:
1189 case TRUNCATE_DIRECTORY
:
1190 case CREATE_SUBVOLUME
:
1192 RUN_WITH_UMASK(0000)
1193 mkdir_parents_label(i
->path
, 0755);
1195 if (i
->type
== CREATE_SUBVOLUME
)
1196 RUN_WITH_UMASK((~i
->mode
) & 0777) {
1197 r
= btrfs_subvol_make(i
->path
);
1198 log_debug_errno(r
, "Creating subvolume \"%s\": %m", i
->path
);
1203 if (IN_SET(i
->type
, CREATE_DIRECTORY
, TRUNCATE_DIRECTORY
) || r
== -ENOTTY
)
1204 RUN_WITH_UMASK(0000)
1205 r
= mkdir_label(i
->path
, i
->mode
);
1209 return log_error_errno(r
, "Failed to create directory or subvolume \"%s\": %m", i
->path
);
1211 if (stat(i
->path
, &st
) < 0)
1212 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1214 if (!S_ISDIR(st
.st_mode
)) {
1215 log_debug("\"%s\" already exists and is not a directory.", i
->path
);
1219 creation
= CREATION_EXISTING
;
1221 creation
= CREATION_NORMAL
;
1222 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1224 r
= path_set_perms(i
, i
->path
);
1232 RUN_WITH_UMASK(0000) {
1233 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1234 r
= mkfifo(i
->path
, i
->mode
);
1235 mac_selinux_create_file_clear();
1239 if (errno
!= EEXIST
)
1240 return log_error_errno(errno
, "Failed to create fifo %s: %m", i
->path
);
1242 if (stat(i
->path
, &st
) < 0)
1243 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1245 if (!S_ISFIFO(st
.st_mode
)) {
1249 RUN_WITH_UMASK(0000) {
1250 mac_selinux_create_file_prepare(i
->path
, S_IFIFO
);
1251 r
= mkfifo_atomic(i
->path
, i
->mode
);
1252 mac_selinux_create_file_clear();
1256 return log_error_errno(r
, "Failed to create fifo %s: %m", i
->path
);
1257 creation
= CREATION_FORCE
;
1259 log_debug("%s is not a fifo.", i
->path
);
1263 creation
= CREATION_EXISTING
;
1265 creation
= CREATION_NORMAL
;
1266 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1268 r
= path_set_perms(i
, i
->path
);
1275 case CREATE_SYMLINK
: {
1276 r
= specifier_printf(i
->argument
, specifier_table
, NULL
, &resolved
);
1278 return log_error_errno(r
, "Failed to substitute specifiers in symlink target %s: %m", i
->argument
);
1280 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1281 r
= symlink(resolved
, i
->path
);
1282 mac_selinux_create_file_clear();
1285 _cleanup_free_
char *x
= NULL
;
1287 if (errno
!= EEXIST
)
1288 return log_error_errno(errno
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1290 r
= readlink_malloc(i
->path
, &x
);
1291 if (r
< 0 || !streq(resolved
, x
)) {
1294 mac_selinux_create_file_prepare(i
->path
, S_IFLNK
);
1295 r
= symlink_atomic(resolved
, i
->path
);
1296 mac_selinux_create_file_clear();
1299 return log_error_errno(r
, "symlink(%s, %s) failed: %m", resolved
, i
->path
);
1300 creation
= CREATION_FORCE
;
1302 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i
->path
);
1306 creation
= CREATION_EXISTING
;
1308 creation
= CREATION_NORMAL
;
1309 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation
), i
->path
);
1314 case CREATE_BLOCK_DEVICE
:
1315 case CREATE_CHAR_DEVICE
: {
1318 if (have_effective_cap(CAP_MKNOD
) == 0) {
1319 /* In a container we lack CAP_MKNOD. We
1320 shouldn't attempt to create the device node in
1321 that case to avoid noise, and we don't support
1322 virtualized devices in containers anyway. */
1324 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
1328 file_type
= i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
;
1330 RUN_WITH_UMASK(0000) {
1331 mac_selinux_create_file_prepare(i
->path
, file_type
);
1332 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1333 mac_selinux_create_file_clear();
1337 if (errno
== EPERM
) {
1338 log_debug("We lack permissions, possibly because of cgroup configuration; "
1339 "skipping creation of device node %s.", i
->path
);
1343 if (errno
!= EEXIST
)
1344 return log_error_errno(errno
, "Failed to create device node %s: %m", i
->path
);
1346 if (stat(i
->path
, &st
) < 0)
1347 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1349 if ((st
.st_mode
& S_IFMT
) != file_type
) {
1353 RUN_WITH_UMASK(0000) {
1354 mac_selinux_create_file_prepare(i
->path
, file_type
);
1355 r
= mknod_atomic(i
->path
, i
->mode
| file_type
, i
->major_minor
);
1356 mac_selinux_create_file_clear();
1360 return log_error_errno(r
, "Failed to create device node \"%s\": %m", i
->path
);
1361 creation
= CREATION_FORCE
;
1363 log_debug("%s is not a device node.", i
->path
);
1367 creation
= CREATION_EXISTING
;
1369 creation
= CREATION_NORMAL
;
1370 log_debug("%s %s device node \"%s\" %u:%u.",
1371 creation_mode_verb_to_string(creation
),
1372 i
->type
== CREATE_BLOCK_DEVICE
? "block" : "char",
1373 i
->path
, major(i
->mode
), minor(i
->mode
));
1375 r
= path_set_perms(i
, i
->path
);
1384 r
= glob_item(i
, path_set_perms
, false);
1389 case RECURSIVE_RELABEL_PATH
:
1390 r
= glob_item(i
, path_set_perms
, true);
1396 r
= glob_item(i
, path_set_xattrs
, false);
1401 case RECURSIVE_SET_XATTR
:
1402 r
= glob_item(i
, path_set_xattrs
, true);
1408 r
= glob_item(i
, path_set_acls
, false);
1413 case RECURSIVE_SET_ACL
:
1414 r
= glob_item(i
, path_set_acls
, true);
1420 r
= glob_item(i
, path_set_attribute
, false);
1425 case RECURSIVE_SET_ATTRIBUTE
:
1426 r
= glob_item(i
, path_set_attribute
, true);
1435 static int remove_item_instance(Item
*i
, const char *instance
) {
1443 if (remove(instance
) < 0 && errno
!= ENOENT
)
1444 return log_error_errno(errno
, "rm(%s): %m", instance
);
1448 case TRUNCATE_DIRECTORY
:
1449 case RECURSIVE_REMOVE_PATH
:
1450 /* FIXME: we probably should use dir_cleanup() here
1451 * instead of rm_rf() so that 'x' is honoured. */
1452 log_debug("rm -rf \"%s\"", instance
);
1453 r
= rm_rf(instance
, (i
->type
== RECURSIVE_REMOVE_PATH
? REMOVE_ROOT
: 0) | REMOVE_PHYSICAL
);
1454 if (r
< 0 && r
!= -ENOENT
)
1455 return log_error_errno(r
, "rm_rf(%s): %m", instance
);
1460 assert_not_reached("wut?");
1466 static int remove_item(Item
*i
) {
1471 log_debug("Running remove action for entry %c %s", (char) i
->type
, i
->path
);
1477 case CREATE_DIRECTORY
:
1478 case CREATE_SUBVOLUME
:
1480 case CREATE_SYMLINK
:
1481 case CREATE_CHAR_DEVICE
:
1482 case CREATE_BLOCK_DEVICE
:
1484 case IGNORE_DIRECTORY_PATH
:
1487 case RECURSIVE_RELABEL_PATH
:
1491 case RECURSIVE_SET_XATTR
:
1493 case RECURSIVE_SET_ACL
:
1495 case RECURSIVE_SET_ATTRIBUTE
:
1499 case TRUNCATE_DIRECTORY
:
1500 case RECURSIVE_REMOVE_PATH
:
1501 r
= glob_item(i
, remove_item_instance
, false);
1508 static int clean_item_instance(Item
*i
, const char* instance
) {
1509 _cleanup_closedir_
DIR *d
= NULL
;
1513 char timestamp
[FORMAT_TIMESTAMP_MAX
];
1520 n
= now(CLOCK_REALTIME
);
1524 cutoff
= n
- i
->age
;
1526 d
= opendir_nomod(instance
);
1528 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
1529 log_debug_errno(errno
, "Directory \"%s\": %m", instance
);
1533 log_error_errno(errno
, "Failed to open directory %s: %m", instance
);
1537 if (fstat(dirfd(d
), &s
) < 0)
1538 return log_error_errno(errno
, "stat(%s) failed: %m", i
->path
);
1540 if (!S_ISDIR(s
.st_mode
)) {
1541 log_error("%s is not a directory.", i
->path
);
1545 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0)
1546 return log_error_errno(errno
, "stat(%s/..) failed: %m", i
->path
);
1548 mountpoint
= s
.st_dev
!= ps
.st_dev
||
1549 (s
.st_dev
== ps
.st_dev
&& s
.st_ino
== ps
.st_ino
);
1551 log_debug("Cleanup threshold for %s \"%s\" is %s",
1552 mountpoint
? "mount point" : "directory",
1554 format_timestamp_us(timestamp
, sizeof(timestamp
), cutoff
));
1556 return dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
1557 MAX_DEPTH
, i
->keep_first_level
);
1560 static int clean_item(Item
*i
) {
1565 log_debug("Running clean action for entry %c %s", (char) i
->type
, i
->path
);
1568 case CREATE_DIRECTORY
:
1569 case CREATE_SUBVOLUME
:
1570 case TRUNCATE_DIRECTORY
:
1573 clean_item_instance(i
, i
->path
);
1575 case IGNORE_DIRECTORY_PATH
:
1576 r
= glob_item(i
, clean_item_instance
, false);
1585 static int process_item_array(ItemArray
*array
);
1587 static int process_item(Item
*i
) {
1589 _cleanup_free_
char *prefix
= NULL
;
1598 prefix
= malloc(strlen(i
->path
) + 1);
1602 PATH_FOREACH_PREFIX(prefix
, i
->path
) {
1605 j
= hashmap_get(items
, prefix
);
1609 s
= process_item_array(j
);
1610 if (s
< 0 && t
== 0)
1615 r
= arg_create
? create_item(i
) : 0;
1616 q
= arg_remove
? remove_item(i
) : 0;
1617 p
= arg_clean
? clean_item(i
) : 0;
1625 static int process_item_array(ItemArray
*array
) {
1631 for (n
= 0; n
< array
->count
; n
++) {
1632 k
= process_item(array
->items
+ n
);
1633 if (k
< 0 && r
== 0)
1640 static void item_free_contents(Item
*i
) {
1644 strv_free(i
->xattrs
);
1647 acl_free(i
->acl_access
);
1648 acl_free(i
->acl_default
);
1652 static void item_array_free(ItemArray
*a
) {
1658 for (n
= 0; n
< a
->count
; n
++)
1659 item_free_contents(a
->items
+ n
);
1664 static int item_compare(const void *a
, const void *b
) {
1665 const Item
*x
= a
, *y
= b
;
1667 /* Make sure that the ownership taking item is put first, so
1668 * that we first create the node, and then can adjust it */
1670 if (takes_ownership(x
->type
) && !takes_ownership(y
->type
))
1672 if (!takes_ownership(x
->type
) && takes_ownership(y
->type
))
1675 return (int) x
->type
- (int) y
->type
;
1678 static bool item_compatible(Item
*a
, Item
*b
) {
1681 assert(streq(a
->path
, b
->path
));
1683 if (takes_ownership(a
->type
) && takes_ownership(b
->type
))
1684 /* check if the items are the same */
1685 return streq_ptr(a
->argument
, b
->argument
) &&
1687 a
->uid_set
== b
->uid_set
&&
1690 a
->gid_set
== b
->gid_set
&&
1693 a
->mode_set
== b
->mode_set
&&
1694 a
->mode
== b
->mode
&&
1696 a
->age_set
== b
->age_set
&&
1699 a
->mask_perms
== b
->mask_perms
&&
1701 a
->keep_first_level
== b
->keep_first_level
&&
1703 a
->major_minor
== b
->major_minor
;
1708 static bool should_include_path(const char *path
) {
1711 STRV_FOREACH(prefix
, arg_exclude_prefixes
)
1712 if (path_startswith(path
, *prefix
)) {
1713 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1718 STRV_FOREACH(prefix
, arg_include_prefixes
)
1719 if (path_startswith(path
, *prefix
)) {
1720 log_debug("Entry \"%s\" matches include prefix \"%s\".", path
, *prefix
);
1724 /* no matches, so we should include this path only if we
1725 * have no whitelist at all */
1726 if (strv_length(arg_include_prefixes
) == 0)
1729 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path
);
1733 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1735 _cleanup_free_
char *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1736 _cleanup_(item_free_contents
) Item i
= {};
1737 ItemArray
*existing
;
1740 bool force
= false, boot
= false;
1746 r
= unquote_many_words(
1757 return log_error_errno(r
, "[%s:%u] Failed to parse line: %m", fname
, line
);
1759 log_error("[%s:%u] Syntax error.", fname
, line
);
1763 if (!isempty(buffer
) && !streq(buffer
, "-")) {
1764 i
.argument
= strdup(buffer
);
1769 if (isempty(action
)) {
1770 log_error("[%s:%u] Command too short '%s'.", fname
, line
, action
);
1774 for (pos
= 1; action
[pos
]; pos
++) {
1775 if (action
[pos
] == '!' && !boot
)
1777 else if (action
[pos
] == '+' && !force
)
1780 log_error("[%s:%u] Unknown modifiers in command '%s'",
1781 fname
, line
, action
);
1786 if (boot
&& !arg_boot
) {
1787 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1795 r
= specifier_printf(path
, specifier_table
, NULL
, &i
.path
);
1797 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1803 case CREATE_DIRECTORY
:
1804 case CREATE_SUBVOLUME
:
1805 case TRUNCATE_DIRECTORY
:
1808 case IGNORE_DIRECTORY_PATH
:
1810 case RECURSIVE_REMOVE_PATH
:
1813 case RECURSIVE_RELABEL_PATH
:
1815 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname
, line
, i
.type
);
1823 case CREATE_SYMLINK
:
1825 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1833 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1840 i
.argument
= strappend("/usr/share/factory/", i
.path
);
1843 } else if (!path_is_absolute(i
.argument
)) {
1844 log_error("[%s:%u] Source path is not absolute.", fname
, line
);
1848 path_kill_slashes(i
.argument
);
1851 case CREATE_CHAR_DEVICE
:
1852 case CREATE_BLOCK_DEVICE
: {
1853 unsigned major
, minor
;
1856 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1860 if (sscanf(i
.argument
, "%u:%u", &major
, &minor
) != 2) {
1861 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
.argument
);
1865 i
.major_minor
= makedev(major
, minor
);
1870 case RECURSIVE_SET_XATTR
:
1872 log_error("[%s:%u] Set extended attribute requires argument.", fname
, line
);
1875 r
= parse_xattrs_from_arg(&i
);
1881 case RECURSIVE_SET_ACL
:
1883 log_error("[%s:%u] Set ACLs requires argument.", fname
, line
);
1886 r
= parse_acls_from_arg(&i
);
1892 case RECURSIVE_SET_ATTRIBUTE
:
1894 log_error("[%s:%u] Set file attribute requires argument.", fname
, line
);
1897 r
= parse_attribute_from_arg(&i
);
1903 log_error("[%s:%u] Unknown command type '%c'.", fname
, line
, (char) i
.type
);
1907 if (!path_is_absolute(i
.path
)) {
1908 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
.path
);
1912 path_kill_slashes(i
.path
);
1914 if (!should_include_path(i
.path
))
1920 p
= strappend(arg_root
, i
.path
);
1928 if (!isempty(user
) && !streq(user
, "-")) {
1929 const char *u
= user
;
1931 r
= get_user_creds(&u
, &i
.uid
, NULL
, NULL
, NULL
);
1933 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
1940 if (!isempty(group
) && !streq(group
, "-")) {
1941 const char *g
= group
;
1943 r
= get_group_creds(&g
, &i
.gid
);
1945 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
1952 if (!isempty(mode
) && !streq(mode
, "-")) {
1953 const char *mm
= mode
;
1957 i
.mask_perms
= true;
1961 if (parse_mode(mm
, &m
) < 0) {
1962 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
1969 i
.mode
= IN_SET(i
.type
, CREATE_DIRECTORY
, CREATE_SUBVOLUME
, TRUNCATE_DIRECTORY
)
1972 if (!isempty(age
) && !streq(age
, "-")) {
1973 const char *a
= age
;
1976 i
.keep_first_level
= true;
1980 if (parse_sec(a
, &i
.age
) < 0) {
1981 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
1988 h
= needs_glob(i
.type
) ? globs
: items
;
1990 existing
= hashmap_get(h
, i
.path
);
1994 for (n
= 0; n
< existing
->count
; n
++) {
1995 if (!item_compatible(existing
->items
+ n
, &i
)) {
1996 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1997 fname
, line
, i
.path
);
2002 existing
= new0(ItemArray
, 1);
2003 r
= hashmap_put(h
, i
.path
, existing
);
2008 if (!GREEDY_REALLOC(existing
->items
, existing
->size
, existing
->count
+ 1))
2011 memcpy(existing
->items
+ existing
->count
++, &i
, sizeof(i
));
2013 /* Sort item array, to enforce stable ordering of application */
2014 qsort_safe(existing
->items
, existing
->count
, sizeof(Item
), item_compare
);
2020 static void help(void) {
2021 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2022 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2023 " -h --help Show this help\n"
2024 " --version Show package version\n"
2025 " --create Create marked files/directories\n"
2026 " --clean Clean up marked directories\n"
2027 " --remove Remove marked files/directories\n"
2028 " --boot Execute actions only safe at boot\n"
2029 " --prefix=PATH Only apply rules with the specified prefix\n"
2030 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2031 " --root=PATH Operate on an alternate filesystem root\n",
2032 program_invocation_short_name
);
2035 static int parse_argv(int argc
, char *argv
[]) {
2038 ARG_VERSION
= 0x100,
2048 static const struct option options
[] = {
2049 { "help", no_argument
, NULL
, 'h' },
2050 { "version", no_argument
, NULL
, ARG_VERSION
},
2051 { "create", no_argument
, NULL
, ARG_CREATE
},
2052 { "clean", no_argument
, NULL
, ARG_CLEAN
},
2053 { "remove", no_argument
, NULL
, ARG_REMOVE
},
2054 { "boot", no_argument
, NULL
, ARG_BOOT
},
2055 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
2056 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
2057 { "root", required_argument
, NULL
, ARG_ROOT
},
2066 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
2075 puts(PACKAGE_STRING
);
2076 puts(SYSTEMD_FEATURES
);
2096 if (strv_push(&arg_include_prefixes
, optarg
) < 0)
2100 case ARG_EXCLUDE_PREFIX
:
2101 if (strv_push(&arg_exclude_prefixes
, optarg
) < 0)
2107 arg_root
= path_make_absolute_cwd(optarg
);
2111 path_kill_slashes(arg_root
);
2118 assert_not_reached("Unhandled option");
2121 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
2122 log_error("You need to specify at least one of --clean, --create or --remove.");
2129 static int read_config_file(const char *fn
, bool ignore_enoent
) {
2130 _cleanup_fclose_
FILE *f
= NULL
;
2131 char line
[LINE_MAX
];
2139 r
= search_and_fopen_nulstr(fn
, "re", arg_root
, conf_file_dirs
, &f
);
2141 if (ignore_enoent
&& r
== -ENOENT
) {
2142 log_debug_errno(r
, "Failed to open \"%s\": %m", fn
);
2146 return log_error_errno(r
, "Failed to open '%s', ignoring: %m", fn
);
2148 log_debug("Reading config file \"%s\".", fn
);
2150 FOREACH_LINE(line
, f
, break) {
2157 if (*l
== '#' || *l
== 0)
2160 k
= parse_line(fn
, v
, l
);
2161 if (k
< 0 && r
== 0)
2165 /* we have to determine age parameter for each entry of type X */
2166 HASHMAP_FOREACH(i
, globs
, iterator
) {
2168 Item
*j
, *candidate_item
= NULL
;
2170 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
2173 HASHMAP_FOREACH(j
, items
, iter
) {
2174 if (j
->type
!= CREATE_DIRECTORY
&& j
->type
!= TRUNCATE_DIRECTORY
&& j
->type
!= CREATE_SUBVOLUME
)
2177 if (path_equal(j
->path
, i
->path
)) {
2182 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
2183 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
2187 if (candidate_item
&& candidate_item
->age_set
) {
2188 i
->age
= candidate_item
->age
;
2194 log_error_errno(errno
, "Failed to read from file %s: %m", fn
);
2202 int main(int argc
, char *argv
[]) {
2207 r
= parse_argv(argc
, argv
);
2211 log_set_target(LOG_TARGET_AUTO
);
2212 log_parse_environment();
2217 mac_selinux_init(NULL
);
2219 items
= hashmap_new(&string_hash_ops
);
2220 globs
= hashmap_new(&string_hash_ops
);
2222 if (!items
|| !globs
) {
2229 if (optind
< argc
) {
2232 for (j
= optind
; j
< argc
; j
++) {
2233 k
= read_config_file(argv
[j
], false);
2234 if (k
< 0 && r
== 0)
2239 _cleanup_strv_free_
char **files
= NULL
;
2242 r
= conf_files_list_nulstr(&files
, ".conf", arg_root
, conf_file_dirs
);
2244 log_error_errno(r
, "Failed to enumerate tmpfiles.d files: %m");
2248 STRV_FOREACH(f
, files
) {
2249 k
= read_config_file(*f
, true);
2250 if (k
< 0 && r
== 0)
2255 /* The non-globbing ones usually create things, hence we apply
2257 HASHMAP_FOREACH(a
, items
, iterator
) {
2258 k
= process_item_array(a
);
2259 if (k
< 0 && r
== 0)
2263 /* The globbing ones usually alter things, hence we apply them
2265 HASHMAP_FOREACH(a
, globs
, iterator
) {
2266 k
= process_item_array(a
);
2267 if (k
< 0 && r
== 0)
2272 while ((a
= hashmap_steal_first(items
)))
2275 while ((a
= hashmap_steal_first(globs
)))
2278 hashmap_free(items
);
2279 hashmap_free(globs
);
2281 free(arg_include_prefixes
);
2282 free(arg_exclude_prefixes
);
2285 set_free_free(unix_sockets
);
2287 mac_selinux_finish();
2289 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;