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
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
37 #include <sys/types.h>
38 #include <sys/param.h>
41 #include <sys/capability.h>
48 #include "path-util.h"
52 #include "conf-files.h"
53 #include "capability.h"
54 #include "specifier.h"
57 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
58 * them in the file system. This is intended to be used to create
59 * properly owned directories beneath /tmp, /var/tmp, /run, which are
60 * volatile and hence need to be recreated on bootup. */
62 typedef enum ItemType
{
63 /* These ones take file names */
67 CREATE_DIRECTORY
= 'd',
68 TRUNCATE_DIRECTORY
= 'D',
71 CREATE_CHAR_DEVICE
= 'c',
72 CREATE_BLOCK_DEVICE
= 'b',
75 /* These ones take globs */
77 IGNORE_DIRECTORY_PATH
= 'X',
79 RECURSIVE_REMOVE_PATH
= 'R',
81 RECURSIVE_RELABEL_PATH
= 'Z'
101 bool keep_first_level
:1;
104 static Hashmap
*items
= NULL
, *globs
= NULL
;
105 static Set
*unix_sockets
= NULL
;
107 static bool arg_create
= false;
108 static bool arg_clean
= false;
109 static bool arg_remove
= false;
110 static bool arg_boot
= false;
112 static char **include_prefixes
= NULL
;
113 static char **exclude_prefixes
= NULL
;
115 static const char conf_file_dirs
[] =
118 "/usr/local/lib/tmpfiles.d\0"
119 "/usr/lib/tmpfiles.d\0"
120 #ifdef HAVE_SPLIT_USR
125 #define MAX_DEPTH 256
127 static bool needs_glob(ItemType t
) {
128 return t
== IGNORE_PATH
|| t
== IGNORE_DIRECTORY_PATH
|| t
== REMOVE_PATH
|| t
== RECURSIVE_REMOVE_PATH
|| t
== RELABEL_PATH
|| t
== RECURSIVE_RELABEL_PATH
;
131 static struct Item
* find_glob(Hashmap
*h
, const char *match
) {
135 HASHMAP_FOREACH(j
, h
, i
)
136 if (fnmatch(j
->path
, match
, FNM_PATHNAME
|FNM_PERIOD
) == 0)
142 static void load_unix_sockets(void) {
143 _cleanup_fclose_
FILE *f
= NULL
;
149 /* We maintain a cache of the sockets we found in
150 * /proc/net/unix to speed things up a little. */
152 unix_sockets
= set_new(string_hash_func
, string_compare_func
);
156 f
= fopen("/proc/net/unix", "re");
161 if (!fgets(line
, sizeof(line
), f
))
168 if (!fgets(line
, sizeof(line
), f
))
173 p
= strchr(line
, ':');
181 p
+= strspn(p
, WHITESPACE
);
182 p
+= strcspn(p
, WHITESPACE
); /* skip one more word */
183 p
+= strspn(p
, WHITESPACE
);
192 path_kill_slashes(s
);
194 k
= set_consume(unix_sockets
, s
);
195 if (k
< 0 && k
!= -EEXIST
)
202 set_free_free(unix_sockets
);
206 static bool unix_socket_alive(const char *fn
) {
212 return !!set_get(unix_sockets
, (char*) fn
);
214 /* We don't know, so assume yes */
218 static int dir_is_mount_point(DIR *d
, const char *subdir
) {
219 struct file_handle
*h
;
220 int mount_id_parent
, mount_id
;
223 h
= alloca(MAX_HANDLE_SZ
);
225 h
->handle_bytes
= MAX_HANDLE_SZ
;
226 r_p
= name_to_handle_at(dirfd(d
), ".", h
, &mount_id_parent
, 0);
230 h
->handle_bytes
= MAX_HANDLE_SZ
;
231 r
= name_to_handle_at(dirfd(d
), subdir
, h
, &mount_id
, 0);
235 /* got no handle; make no assumptions, return error */
236 if (r_p
< 0 && r
< 0)
239 /* got both handles; if they differ, it is a mount point */
240 if (r_p
>= 0 && r
>= 0)
241 return mount_id_parent
!= mount_id
;
243 /* got only one handle; assume different mount points if one
244 * of both queries was not supported by the filesystem */
245 if (r_p
== -ENOSYS
|| r_p
== -ENOTSUP
|| r
== -ENOSYS
|| r
== -ENOTSUP
)
254 static int dir_cleanup(
258 const struct stat
*ds
,
263 bool keep_this_level
) {
266 struct timespec times
[2];
267 bool deleted
= false;
270 while ((dent
= readdir(d
))) {
273 _cleanup_free_
char *sub_path
= NULL
;
275 if (streq(dent
->d_name
, ".") ||
276 streq(dent
->d_name
, ".."))
279 if (fstatat(dirfd(d
), dent
->d_name
, &s
, AT_SYMLINK_NOFOLLOW
) < 0) {
283 /* FUSE, NFS mounts, SELinux might return EACCES */
285 log_debug("stat(%s/%s) failed: %m", p
, dent
->d_name
);
287 log_error("stat(%s/%s) failed: %m", p
, dent
->d_name
);
292 /* Stay on the same filesystem */
293 if (s
.st_dev
!= rootdev
)
296 /* Try to detect bind mounts of the same filesystem instance; they
297 * do not differ in device major/minors. This type of query is not
298 * supported on all kernels or filesystem types though. */
299 if (S_ISDIR(s
.st_mode
) && dir_is_mount_point(d
, dent
->d_name
) > 0)
302 /* Do not delete read-only files owned by root */
303 if (s
.st_uid
== 0 && !(s
.st_mode
& S_IWUSR
))
306 if (asprintf(&sub_path
, "%s/%s", p
, dent
->d_name
) < 0) {
311 /* Is there an item configured for this path? */
312 if (hashmap_get(items
, sub_path
))
315 if (find_glob(globs
, sub_path
))
318 if (S_ISDIR(s
.st_mode
)) {
321 streq(dent
->d_name
, "lost+found") &&
326 log_warning("Reached max depth on %s.", sub_path
);
328 _cleanup_closedir_
DIR *sub_dir
;
331 sub_dir
= xopendirat(dirfd(d
), dent
->d_name
, O_NOFOLLOW
|O_NOATIME
);
332 if (sub_dir
== NULL
) {
333 if (errno
!= ENOENT
) {
334 log_error("opendir(%s/%s) failed: %m", p
, dent
->d_name
);
341 q
= dir_cleanup(i
, sub_path
, sub_dir
, &s
, cutoff
, rootdev
, false, maxdepth
-1, false);
347 /* Note: if you are wondering why we don't
348 * support the sticky bit for excluding
349 * directories from cleaning like we do it for
350 * other file system objects: well, the sticky
351 * bit already has a meaning for directories,
352 * so we don't want to overload that. */
357 /* Ignore ctime, we change it when deleting */
358 age
= MAX(timespec_load(&s
.st_mtim
),
359 timespec_load(&s
.st_atim
));
363 if (i
->type
!= IGNORE_DIRECTORY_PATH
|| !streq(dent
->d_name
, p
)) {
364 log_debug("rmdir '%s'", sub_path
);
366 if (unlinkat(dirfd(d
), dent
->d_name
, AT_REMOVEDIR
) < 0) {
367 if (errno
!= ENOENT
&& errno
!= ENOTEMPTY
) {
368 log_error("rmdir(%s): %m", sub_path
);
375 /* Skip files for which the sticky bit is
376 * set. These are semantics we define, and are
377 * unknown elsewhere. See XDG_RUNTIME_DIR
378 * specification for details. */
379 if (s
.st_mode
& S_ISVTX
)
382 if (mountpoint
&& S_ISREG(s
.st_mode
)) {
383 if (streq(dent
->d_name
, ".journal") &&
387 if (streq(dent
->d_name
, "aquota.user") ||
388 streq(dent
->d_name
, "aquota.group"))
392 /* Ignore sockets that are listed in /proc/net/unix */
393 if (S_ISSOCK(s
.st_mode
) && unix_socket_alive(sub_path
))
396 /* Ignore device nodes */
397 if (S_ISCHR(s
.st_mode
) || S_ISBLK(s
.st_mode
))
400 /* Keep files on this level around if this is
405 age
= MAX3(timespec_load(&s
.st_mtim
),
406 timespec_load(&s
.st_atim
),
407 timespec_load(&s
.st_ctim
));
412 log_debug("unlink '%s'", sub_path
);
414 if (unlinkat(dirfd(d
), dent
->d_name
, 0) < 0) {
415 if (errno
!= ENOENT
) {
416 log_error("unlink(%s): %m", sub_path
);
427 /* Restore original directory timestamps */
428 times
[0] = ds
->st_atim
;
429 times
[1] = ds
->st_mtim
;
431 if (futimens(dirfd(d
), times
) < 0)
432 log_error("utimensat(%s): %m", p
);
438 static int item_set_perms_full(Item
*i
, const char *path
, bool ignore_enoent
) {
439 /* not using i->path directly because it may be a glob */
441 if (chmod(path
, i
->mode
) < 0) {
442 if (errno
!= ENOENT
|| !ignore_enoent
) {
443 log_error("chmod(%s) failed: %m", path
);
448 if (i
->uid_set
|| i
->gid_set
)
450 i
->uid_set
? i
->uid
: (uid_t
) -1,
451 i
->gid_set
? i
->gid
: (gid_t
) -1) < 0) {
453 if (errno
!= ENOENT
|| !ignore_enoent
) {
454 log_error("chown(%s) failed: %m", path
);
459 return label_fix(path
, ignore_enoent
, false);
462 static int item_set_perms(Item
*i
, const char *path
) {
463 return item_set_perms_full(i
, path
, false);
466 static int write_one_file(Item
*i
, const char *path
) {
472 flags
= i
->type
== CREATE_FILE
? O_CREAT
|O_APPEND
:
473 i
->type
== TRUNCATE_FILE
? O_CREAT
|O_TRUNC
: 0;
476 label_context_set(path
, S_IFREG
);
477 fd
= open(path
, flags
|O_NDELAY
|O_CLOEXEC
|O_WRONLY
|O_NOCTTY
|O_NOFOLLOW
, i
->mode
);
479 label_context_clear();
484 if (i
->type
== WRITE_FILE
&& errno
== ENOENT
)
487 log_error("Failed to create file %s: %m", path
);
494 _cleanup_free_
char *unescaped
;
496 unescaped
= cunescape(i
->argument
);
497 if (unescaped
== NULL
) {
498 close_nointr_nofail(fd
);
502 l
= strlen(unescaped
);
503 n
= write(fd
, unescaped
, l
);
505 if (n
< 0 || (size_t) n
< l
) {
506 log_error("Failed to write file %s: %s", path
, n
< 0 ? strerror(-n
) : "Short write");
507 close_nointr_nofail(fd
);
508 return n
< 0 ? n
: -EIO
;
512 close_nointr_nofail(fd
);
514 if (stat(path
, &st
) < 0) {
515 log_error("stat(%s) failed: %m", path
);
519 if (!S_ISREG(st
.st_mode
)) {
520 log_error("%s is not a file.", path
);
524 r
= item_set_perms(i
, path
);
531 static int recursive_relabel_children(Item
*i
, const char *path
) {
532 _cleanup_closedir_
DIR *d
;
535 /* This returns the first error we run into, but nevertheless
540 return errno
== ENOENT
? 0 : -errno
;
546 _cleanup_free_
char *entry_path
= NULL
;
550 if (!de
&& errno
!= 0) {
559 if (streq(de
->d_name
, ".") || streq(de
->d_name
, ".."))
562 if (asprintf(&entry_path
, "%s/%s", path
, de
->d_name
) < 0) {
568 if (de
->d_type
== DT_UNKNOWN
) {
571 if (lstat(entry_path
, &st
) < 0) {
572 if (ret
== 0 && errno
!= ENOENT
)
577 is_dir
= S_ISDIR(st
.st_mode
);
580 is_dir
= de
->d_type
== DT_DIR
;
582 r
= item_set_perms(i
, entry_path
);
584 if (ret
== 0 && r
!= -ENOENT
)
590 r
= recursive_relabel_children(i
, entry_path
);
591 if (r
< 0 && ret
== 0)
599 static int recursive_relabel(Item
*i
, const char *path
) {
603 r
= item_set_perms(i
, path
);
607 if (lstat(path
, &st
) < 0)
610 if (S_ISDIR(st
.st_mode
))
611 r
= recursive_relabel_children(i
, path
);
616 static int glob_item(Item
*i
, int (*action
)(Item
*, const char *)) {
618 _cleanup_globfree_ glob_t g
= {};
622 k
= glob(i
->path
, GLOB_NOSORT
|GLOB_BRACE
, NULL
, &g
);
624 if (k
!= GLOB_NOMATCH
) {
628 log_error("glob(%s) failed: %m", i
->path
);
632 STRV_FOREACH(fn
, g
.gl_pathv
) {
641 static int create_item(Item
*i
) {
651 case IGNORE_DIRECTORY_PATH
:
653 case RECURSIVE_REMOVE_PATH
:
658 r
= write_one_file(i
, i
->path
);
664 r
= glob_item(i
, write_one_file
);
671 r
= item_set_perms_full(i
, i
->path
, true);
677 case TRUNCATE_DIRECTORY
:
678 case CREATE_DIRECTORY
:
680 RUN_WITH_UMASK(0000) {
681 mkdir_parents_label(i
->path
, 0755);
682 r
= mkdir(i
->path
, i
->mode
);
685 if (r
< 0 && errno
!= EEXIST
) {
686 log_error("Failed to create directory %s: %m", i
->path
);
690 if (stat(i
->path
, &st
) < 0) {
691 log_error("stat(%s) failed: %m", i
->path
);
695 if (!S_ISDIR(st
.st_mode
)) {
696 log_error("%s is not a directory.", i
->path
);
700 r
= item_set_perms(i
, i
->path
);
708 RUN_WITH_UMASK(0000) {
709 r
= mkfifo(i
->path
, i
->mode
);
712 if (r
< 0 && errno
!= EEXIST
) {
713 log_error("Failed to create fifo %s: %m", i
->path
);
717 if (stat(i
->path
, &st
) < 0) {
718 log_error("stat(%s) failed: %m", i
->path
);
722 if (!S_ISFIFO(st
.st_mode
)) {
723 log_error("%s is not a fifo.", i
->path
);
727 r
= item_set_perms(i
, i
->path
);
733 case CREATE_SYMLINK
: {
734 _cleanup_free_
char *x
= NULL
;
736 label_context_set(i
->path
, S_IFLNK
);
737 r
= symlink(i
->argument
, i
->path
);
739 label_context_clear();
742 if (r
< 0 && errno
!= EEXIST
) {
743 log_error("symlink(%s, %s) failed: %m", i
->argument
, i
->path
);
747 r
= readlink_malloc(i
->path
, &x
);
749 log_error("readlink(%s) failed: %s", i
->path
, strerror(-r
));
753 if (!streq(i
->argument
, x
)) {
754 log_error("%s is not the right symlinks.", i
->path
);
761 case CREATE_BLOCK_DEVICE
:
762 case CREATE_CHAR_DEVICE
: {
765 if (have_effective_cap(CAP_MKNOD
) == 0) {
766 /* In a container we lack CAP_MKNOD. We
767 shouldn't attempt to create the device node in
768 that case to avoid noise, and we don't support
769 virtualized devices in containers anyway. */
771 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i
->path
);
775 file_type
= (i
->type
== CREATE_BLOCK_DEVICE
? S_IFBLK
: S_IFCHR
);
777 RUN_WITH_UMASK(0000) {
778 label_context_set(i
->path
, file_type
);
779 r
= mknod(i
->path
, i
->mode
| file_type
, i
->major_minor
);
781 label_context_clear();
785 if (r
< 0 && errno
!= EEXIST
) {
786 log_error("Failed to create device node %s: %m", i
->path
);
790 if (stat(i
->path
, &st
) < 0) {
791 log_error("stat(%s) failed: %m", i
->path
);
795 if ((st
.st_mode
& S_IFMT
) != file_type
) {
796 log_error("%s is not a device node.", i
->path
);
800 r
= item_set_perms(i
, i
->path
);
809 r
= glob_item(i
, item_set_perms
);
814 case RECURSIVE_RELABEL_PATH
:
816 r
= glob_item(i
, recursive_relabel
);
821 log_debug("%s created successfully.", i
->path
);
826 static int remove_item_instance(Item
*i
, const char *instance
) {
835 case CREATE_DIRECTORY
:
838 case CREATE_BLOCK_DEVICE
:
839 case CREATE_CHAR_DEVICE
:
841 case IGNORE_DIRECTORY_PATH
:
843 case RECURSIVE_RELABEL_PATH
:
849 if (remove(instance
) < 0 && errno
!= ENOENT
) {
850 log_error("remove(%s): %m", instance
);
856 case TRUNCATE_DIRECTORY
:
857 case RECURSIVE_REMOVE_PATH
:
858 /* FIXME: we probably should use dir_cleanup() here
859 * instead of rm_rf() so that 'x' is honoured. */
860 r
= rm_rf_dangerous(instance
, false, i
->type
== RECURSIVE_REMOVE_PATH
, false);
861 if (r
< 0 && r
!= -ENOENT
) {
862 log_error("rm_rf(%s): %s", instance
, strerror(-r
));
872 static int remove_item(Item
*i
) {
881 case CREATE_DIRECTORY
:
884 case CREATE_CHAR_DEVICE
:
885 case CREATE_BLOCK_DEVICE
:
887 case IGNORE_DIRECTORY_PATH
:
889 case RECURSIVE_RELABEL_PATH
:
895 case TRUNCATE_DIRECTORY
:
896 case RECURSIVE_REMOVE_PATH
:
897 r
= glob_item(i
, remove_item_instance
);
904 static int clean_item_instance(Item
*i
, const char* instance
) {
905 _cleanup_closedir_
DIR *d
= NULL
;
916 n
= now(CLOCK_REALTIME
);
922 d
= opendir(instance
);
924 if (errno
== ENOENT
|| errno
== ENOTDIR
)
927 log_error("Failed to open directory %s: %m", i
->path
);
931 if (fstat(dirfd(d
), &s
) < 0) {
932 log_error("stat(%s) failed: %m", i
->path
);
936 if (!S_ISDIR(s
.st_mode
)) {
937 log_error("%s is not a directory.", i
->path
);
941 if (fstatat(dirfd(d
), "..", &ps
, AT_SYMLINK_NOFOLLOW
) != 0) {
942 log_error("stat(%s/..) failed: %m", i
->path
);
946 mountpoint
= s
.st_dev
!= ps
.st_dev
||
947 (s
.st_dev
== ps
.st_dev
&& s
.st_ino
== ps
.st_ino
);
949 r
= dir_cleanup(i
, instance
, d
, &s
, cutoff
, s
.st_dev
, mountpoint
,
950 MAX_DEPTH
, i
->keep_first_level
);
954 static int clean_item(Item
*i
) {
960 case CREATE_DIRECTORY
:
961 case TRUNCATE_DIRECTORY
:
963 clean_item_instance(i
, i
->path
);
965 case IGNORE_DIRECTORY_PATH
:
966 r
= glob_item(i
, clean_item_instance
);
975 static int process_item(Item
*i
) {
980 r
= arg_create
? create_item(i
) : 0;
981 q
= arg_remove
? remove_item(i
) : 0;
982 p
= arg_clean
? clean_item(i
) : 0;
993 static void item_free(Item
*i
) {
1001 DEFINE_TRIVIAL_CLEANUP_FUNC(Item
*, item_free
);
1002 #define _cleanup_item_free_ _cleanup_(item_freep)
1004 static bool item_equal(Item
*a
, Item
*b
) {
1008 if (!streq_ptr(a
->path
, b
->path
))
1011 if (a
->type
!= b
->type
)
1014 if (a
->uid_set
!= b
->uid_set
||
1015 (a
->uid_set
&& a
->uid
!= b
->uid
))
1018 if (a
->gid_set
!= b
->gid_set
||
1019 (a
->gid_set
&& a
->gid
!= b
->gid
))
1022 if (a
->mode_set
!= b
->mode_set
||
1023 (a
->mode_set
&& a
->mode
!= b
->mode
))
1026 if (a
->age_set
!= b
->age_set
||
1027 (a
->age_set
&& a
->age
!= b
->age
))
1030 if ((a
->type
== CREATE_FILE
||
1031 a
->type
== TRUNCATE_FILE
||
1032 a
->type
== WRITE_FILE
||
1033 a
->type
== CREATE_SYMLINK
) &&
1034 !streq_ptr(a
->argument
, b
->argument
))
1037 if ((a
->type
== CREATE_CHAR_DEVICE
||
1038 a
->type
== CREATE_BLOCK_DEVICE
) &&
1039 a
->major_minor
!= b
->major_minor
)
1045 static bool should_include_path(const char *path
) {
1048 STRV_FOREACH(prefix
, exclude_prefixes
) {
1049 if (path_startswith(path
, *prefix
))
1053 STRV_FOREACH(prefix
, include_prefixes
) {
1054 if (path_startswith(path
, *prefix
))
1058 /* no matches, so we should include this path only if we
1059 * have no whitelist at all */
1060 return strv_length(include_prefixes
) == 0;
1063 static int parse_line(const char *fname
, unsigned line
, const char *buffer
) {
1065 static const Specifier specifier_table
[] = {
1066 { 'm', specifier_machine_id
, NULL
},
1067 { 'b', specifier_boot_id
, NULL
},
1068 { 'H', specifier_host_name
, NULL
},
1069 { 'v', specifier_kernel_release
, NULL
},
1073 _cleanup_item_free_ Item
*i
= NULL
;
1076 *action
= NULL
, *mode
= NULL
, *user
= NULL
, *group
= NULL
, *age
= NULL
, *path
= NULL
;
1086 "%ms %ms %ms %ms %ms %ms %n",
1095 log_error("[%s:%u] Syntax error.", fname
, line
);
1099 if (strlen(action
) > 2 || (strlen(action
) > 1 && action
[1] != '!')) {
1100 log_error("[%s:%u] Unknown modifier '%s'", fname
, line
, action
);
1102 } else if (strlen(action
) > 1 && !arg_boot
)
1111 r
= specifier_printf(path
, specifier_table
, NULL
, &i
->path
);
1113 log_error("[%s:%u] Failed to replace specifiers: %s", fname
, line
, path
);
1118 n
+= strspn(buffer
+n
, WHITESPACE
);
1119 if (buffer
[n
] != 0 && (buffer
[n
] != '-' || buffer
[n
+1] != 0)) {
1120 i
->argument
= unquote(buffer
+n
, "\"");
1130 case CREATE_DIRECTORY
:
1131 case TRUNCATE_DIRECTORY
:
1134 case IGNORE_DIRECTORY_PATH
:
1136 case RECURSIVE_REMOVE_PATH
:
1138 case RECURSIVE_RELABEL_PATH
:
1142 case CREATE_SYMLINK
:
1144 log_error("[%s:%u] Symlink file requires argument.", fname
, line
);
1151 log_error("[%s:%u] Write file requires argument.", fname
, line
);
1156 case CREATE_CHAR_DEVICE
:
1157 case CREATE_BLOCK_DEVICE
: {
1158 unsigned major
, minor
;
1161 log_error("[%s:%u] Device file requires argument.", fname
, line
);
1165 if (sscanf(i
->argument
, "%u:%u", &major
, &minor
) != 2) {
1166 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname
, line
, i
->argument
);
1170 i
->major_minor
= makedev(major
, minor
);
1175 log_error("[%s:%u] Unknown file type '%c'.", fname
, line
, type
);
1181 if (!path_is_absolute(i
->path
)) {
1182 log_error("[%s:%u] Path '%s' not absolute.", fname
, line
, i
->path
);
1186 path_kill_slashes(i
->path
);
1188 if (!should_include_path(i
->path
))
1191 if (user
&& !streq(user
, "-")) {
1192 const char *u
= user
;
1194 r
= get_user_creds(&u
, &i
->uid
, NULL
, NULL
, NULL
);
1196 log_error("[%s:%u] Unknown user '%s'.", fname
, line
, user
);
1203 if (group
&& !streq(group
, "-")) {
1204 const char *g
= group
;
1206 r
= get_group_creds(&g
, &i
->gid
);
1208 log_error("[%s:%u] Unknown group '%s'.", fname
, line
, group
);
1215 if (mode
&& !streq(mode
, "-")) {
1218 if (sscanf(mode
, "%o", &m
) != 1) {
1219 log_error("[%s:%u] Invalid mode '%s'.", fname
, line
, mode
);
1227 i
->type
== CREATE_DIRECTORY
||
1228 i
->type
== TRUNCATE_DIRECTORY
? 0755 : 0644;
1230 if (age
&& !streq(age
, "-")) {
1231 const char *a
= age
;
1234 i
->keep_first_level
= true;
1238 if (parse_sec(a
, &i
->age
) < 0) {
1239 log_error("[%s:%u] Invalid age '%s'.", fname
, line
, age
);
1246 h
= needs_glob(i
->type
) ? globs
: items
;
1248 existing
= hashmap_get(h
, i
->path
);
1251 /* Two identical items are fine */
1252 if (!item_equal(existing
, i
))
1253 log_warning("Two or more conflicting lines for %s configured, ignoring.", i
->path
);
1258 r
= hashmap_put(h
, i
->path
, i
);
1260 log_error("Failed to insert item %s: %s", i
->path
, strerror(-r
));
1264 i
= NULL
; /* avoid cleanup */
1269 static int help(void) {
1271 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1272 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1273 " -h --help Show this help\n"
1274 " --version Show package version\n"
1275 " --create Create marked files/directories\n"
1276 " --clean Clean up marked directories\n"
1277 " --remove Remove marked files/directories\n"
1278 " --boot Execute actions only safe at boot\n"
1279 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1280 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n",
1281 program_invocation_short_name
);
1286 static int parse_argv(int argc
, char *argv
[]) {
1289 ARG_VERSION
= 0x100,
1298 static const struct option options
[] = {
1299 { "help", no_argument
, NULL
, 'h' },
1300 { "version", no_argument
, NULL
, ARG_VERSION
},
1301 { "create", no_argument
, NULL
, ARG_CREATE
},
1302 { "clean", no_argument
, NULL
, ARG_CLEAN
},
1303 { "remove", no_argument
, NULL
, ARG_REMOVE
},
1304 { "boot", no_argument
, NULL
, ARG_BOOT
},
1305 { "prefix", required_argument
, NULL
, ARG_PREFIX
},
1306 { "exclude-prefix", required_argument
, NULL
, ARG_EXCLUDE_PREFIX
},
1315 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0) {
1323 puts(PACKAGE_STRING
);
1324 puts(SYSTEMD_FEATURES
);
1344 if (strv_push(&include_prefixes
, optarg
) < 0)
1348 case ARG_EXCLUDE_PREFIX
:
1349 if (strv_push(&exclude_prefixes
, optarg
) < 0)
1357 assert_not_reached("Unhandled option");
1361 if (!arg_clean
&& !arg_create
&& !arg_remove
) {
1362 log_error("You need to specify at least one of --clean, --create or --remove.");
1369 static int read_config_file(const char *fn
, bool ignore_enoent
) {
1370 _cleanup_fclose_
FILE *f
= NULL
;
1371 char line
[LINE_MAX
];
1379 r
= search_and_fopen_nulstr(fn
, "re", conf_file_dirs
, &f
);
1381 if (ignore_enoent
&& r
== -ENOENT
)
1384 log_error("Failed to open '%s', ignoring: %s", fn
, strerror(-r
));
1388 FOREACH_LINE(line
, f
, break) {
1395 if (*l
== '#' || *l
== 0)
1398 k
= parse_line(fn
, v
, l
);
1399 if (k
< 0 && r
== 0)
1403 /* we have to determine age parameter for each entry of type X */
1404 HASHMAP_FOREACH(i
, globs
, iterator
) {
1406 Item
*j
, *candidate_item
= NULL
;
1408 if (i
->type
!= IGNORE_DIRECTORY_PATH
)
1411 HASHMAP_FOREACH(j
, items
, iter
) {
1412 if (j
->type
!= CREATE_DIRECTORY
&& j
->type
!= TRUNCATE_DIRECTORY
)
1415 if (path_equal(j
->path
, i
->path
)) {
1420 if ((!candidate_item
&& path_startswith(i
->path
, j
->path
)) ||
1421 (candidate_item
&& path_startswith(j
->path
, candidate_item
->path
) && (fnmatch(i
->path
, j
->path
, FNM_PATHNAME
| FNM_PERIOD
) == 0)))
1425 if (candidate_item
) {
1426 i
->age
= candidate_item
->age
;
1432 log_error("Failed to read from file %s: %m", fn
);
1440 int main(int argc
, char *argv
[]) {
1445 r
= parse_argv(argc
, argv
);
1447 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;
1449 log_set_target(LOG_TARGET_AUTO
);
1450 log_parse_environment();
1457 items
= hashmap_new(string_hash_func
, string_compare_func
);
1458 globs
= hashmap_new(string_hash_func
, string_compare_func
);
1460 if (!items
|| !globs
) {
1467 if (optind
< argc
) {
1470 for (j
= optind
; j
< argc
; j
++) {
1471 k
= read_config_file(argv
[j
], false);
1472 if (k
< 0 && r
== 0)
1477 _cleanup_strv_free_
char **files
= NULL
;
1480 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, conf_file_dirs
);
1482 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r
));
1486 STRV_FOREACH(f
, files
) {
1487 k
= read_config_file(*f
, true);
1488 if (k
< 0 && r
== 0)
1493 HASHMAP_FOREACH(i
, globs
, iterator
)
1496 HASHMAP_FOREACH(i
, items
, iterator
)
1500 while ((i
= hashmap_steal_first(items
)))
1503 while ((i
= hashmap_steal_first(globs
)))
1506 hashmap_free(items
);
1507 hashmap_free(globs
);
1509 free(include_prefixes
);
1510 free(exclude_prefixes
);
1512 set_free_free(unix_sockets
);
1516 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;