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/>.
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/xattr.h>
49 #include "path-util.h"
53 #include "conf-files.h"
54 #include "capability.h"
55 #include "specifier.h"
58 #include "selinux-util.h"
59 #include "btrfs-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',
80 /* These ones take globs */
83 IGNORE_DIRECTORY_PATH = 'X',
85 RECURSIVE_REMOVE_PATH = 'R',
86 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
88 RECURSIVE_RELABEL_PATH = 'Z',
110 bool keep_first_level:1;
117 typedef struct ItemArray {
123 static bool arg_create = false;
124 static bool arg_clean = false;
125 static bool arg_remove = false;
126 static bool arg_boot = false;
128 static char **arg_include_prefixes = NULL;
129 static char **arg_exclude_prefixes = NULL;
130 static char *arg_root = NULL;
132 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
134 #define MAX_DEPTH 256
136 static Hashmap *items = NULL, *globs = NULL;
137 static Set *unix_sockets = NULL;
139 static bool needs_glob(ItemType t) {
143 IGNORE_DIRECTORY_PATH,
145 RECURSIVE_REMOVE_PATH,
148 RECURSIVE_RELABEL_PATH);
151 static bool takes_ownership(ItemType t) {
166 IGNORE_DIRECTORY_PATH,
168 RECURSIVE_REMOVE_PATH);
171 static struct Item* find_glob(Hashmap *h, const char *match) {
175 HASHMAP_FOREACH(j, h, i) {
178 for (n = 0; n < j->count; n++) {
179 Item *item = j->items + n;
181 if (fnmatch(item->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
189 static void load_unix_sockets(void) {
190 _cleanup_fclose_ FILE *f = NULL;
196 /* We maintain a cache of the sockets we found in
197 * /proc/net/unix to speed things up a little. */
199 unix_sockets = set_new(&string_hash_ops);
203 f = fopen("/proc/net/unix", "re");
208 if (!fgets(line, sizeof(line), f))
215 if (!fgets(line, sizeof(line), f))
220 p = strchr(line, ':');
228 p += strspn(p, WHITESPACE);
229 p += strcspn(p, WHITESPACE); /* skip one more word */
230 p += strspn(p, WHITESPACE);
239 path_kill_slashes(s);
241 k = set_consume(unix_sockets, s);
242 if (k < 0 && k != -EEXIST)
249 set_free_free(unix_sockets);
253 static bool unix_socket_alive(const char *fn) {
259 return !!set_get(unix_sockets, (char*) fn);
261 /* We don't know, so assume yes */
265 static int dir_is_mount_point(DIR *d, const char *subdir) {
267 union file_handle_union h = FILE_HANDLE_INIT;
268 int mount_id_parent, mount_id;
271 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
275 h.handle.handle_bytes = MAX_HANDLE_SZ;
276 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
280 /* got no handle; make no assumptions, return error */
281 if (r_p < 0 && r < 0)
284 /* got both handles; if they differ, it is a mount point */
285 if (r_p >= 0 && r >= 0)
286 return mount_id_parent != mount_id;
288 /* got only one handle; assume different mount points if one
289 * of both queries was not supported by the filesystem */
290 if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
299 static int dir_cleanup(
303 const struct stat *ds,
308 bool keep_this_level) {
311 struct timespec times[2];
312 bool deleted = false;
315 while ((dent = readdir(d))) {
318 _cleanup_free_ char *sub_path = NULL;
320 if (streq(dent->d_name, ".") ||
321 streq(dent->d_name, ".."))
324 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
328 /* FUSE, NFS mounts, SELinux might return EACCES */
330 log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
332 log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
337 /* Stay on the same filesystem */
338 if (s.st_dev != rootdev)
341 /* Try to detect bind mounts of the same filesystem instance; they
342 * do not differ in device major/minors. This type of query is not
343 * supported on all kernels or filesystem types though. */
344 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
347 /* Do not delete read-only files owned by root */
348 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
351 sub_path = strjoin(p, "/", dent->d_name, NULL);
357 /* Is there an item configured for this path? */
358 if (hashmap_get(items, sub_path))
361 if (find_glob(globs, sub_path))
364 if (S_ISDIR(s.st_mode)) {
367 streq(dent->d_name, "lost+found") &&
372 log_warning("Reached max depth on %s.", sub_path);
374 _cleanup_closedir_ DIR *sub_dir;
377 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
379 if (errno != ENOENT) {
380 log_error_errno(errno, "opendir(%s/%s) failed: %m", p, dent->d_name);
387 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
392 /* Note: if you are wondering why we don't
393 * support the sticky bit for excluding
394 * directories from cleaning like we do it for
395 * other file system objects: well, the sticky
396 * bit already has a meaning for directories,
397 * so we don't want to overload that. */
402 /* Ignore ctime, we change it when deleting */
403 age = MAX(timespec_load(&s.st_mtim),
404 timespec_load(&s.st_atim));
408 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
409 log_debug("rmdir '%s'", sub_path);
411 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
412 if (errno != ENOENT && errno != ENOTEMPTY) {
413 log_error_errno(errno, "rmdir(%s): %m", sub_path);
420 /* Skip files for which the sticky bit is
421 * set. These are semantics we define, and are
422 * unknown elsewhere. See XDG_RUNTIME_DIR
423 * specification for details. */
424 if (s.st_mode & S_ISVTX)
427 if (mountpoint && S_ISREG(s.st_mode)) {
428 if (streq(dent->d_name, ".journal") &&
432 if (streq(dent->d_name, "aquota.user") ||
433 streq(dent->d_name, "aquota.group"))
437 /* Ignore sockets that are listed in /proc/net/unix */
438 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
441 /* Ignore device nodes */
442 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
445 /* Keep files on this level around if this is
450 age = MAX3(timespec_load(&s.st_mtim),
451 timespec_load(&s.st_atim),
452 timespec_load(&s.st_ctim));
457 log_debug("unlink '%s'", sub_path);
459 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
460 if (errno != ENOENT) {
461 log_error_errno(errno, "unlink(%s): %m", sub_path);
472 /* Restore original directory timestamps */
473 times[0] = ds->st_atim;
474 times[1] = ds->st_mtim;
476 if (futimens(dirfd(d), times) < 0)
477 log_error_errno(errno, "utimensat(%s): %m", p);
483 static int item_set_perms(Item *i, const char *path) {
490 st_valid = stat(path, &st) == 0;
492 /* not using i->path directly because it may be a glob */
496 if (i->mask_perms && st_valid) {
497 if (!(st.st_mode & 0111))
499 if (!(st.st_mode & 0222))
501 if (!(st.st_mode & 0444))
503 if (!S_ISDIR(st.st_mode))
504 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
507 if (!st_valid || m != (st.st_mode & 07777)) {
508 if (chmod(path, m) < 0)
509 return log_error_errno(errno, "chmod(%s) failed: %m", path);
513 if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
514 (i->uid_set || i->gid_set))
516 i->uid_set ? i->uid : UID_INVALID,
517 i->gid_set ? i->gid : GID_INVALID) < 0)
519 return log_error_errno(errno, "chown(%s) failed: %m", path);
521 return label_fix(path, false, false);
524 static int get_xattrs_from_arg(Item *i) {
534 while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
535 _cleanup_free_ char *tmp = NULL, *name = NULL,
536 *value = NULL, *value2 = NULL, *_xattr = xattr;
538 r = split_pair(xattr, "=", &name, &value);
540 log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
544 if (strempty(name) || strempty(value)) {
545 log_warning("Malformed xattr found: \"%s\" - ignoring.", xattr);
549 tmp = unquote(value, "\"");
553 value2 = cunescape(tmp);
557 if (strv_push_pair(&i->xattrs, name, value2) < 0)
559 name = value2 = NULL;
565 static int item_set_xattrs(Item *i, const char *path) {
566 char **name, **value;
571 STRV_FOREACH_PAIR(name, value, i->xattrs) {
575 if (lsetxattr(path, *name, *value, n, 0) < 0) {
576 log_error("Setting extended attribute %s=%s on %s failed: %m",
577 *name, *value, path);
584 static int write_one_file(Item *i, const char *path) {
585 _cleanup_close_ int fd = -1;
592 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
593 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
595 RUN_WITH_UMASK(0000) {
596 mac_selinux_create_file_prepare(path, S_IFREG);
597 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
598 mac_selinux_create_file_clear();
602 if (i->type == WRITE_FILE && errno == ENOENT)
605 log_error_errno(errno, "Failed to create file %s: %m", path);
610 _cleanup_free_ char *unescaped;
614 unescaped = cunescape(i->argument);
618 l = strlen(unescaped);
619 n = write(fd, unescaped, l);
621 if (n < 0 || (size_t) n < l) {
622 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
623 return n < 0 ? n : -EIO;
629 if (stat(path, &st) < 0)
630 return log_error_errno(errno, "stat(%s) failed: %m", path);
632 if (!S_ISREG(st.st_mode)) {
633 log_error("%s is not a file.", path);
637 r = item_set_perms(i, path);
644 static int item_set_perms_children(Item *i, const char *path) {
645 _cleanup_closedir_ DIR *d;
651 /* This returns the first error we run into, but nevertheless
656 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
659 _cleanup_free_ char *p = NULL;
666 if (errno != 0 && r == 0)
672 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
675 p = strjoin(path, "/", de->d_name, NULL);
679 q = item_set_perms(i, p);
680 if (q < 0 && q != -ENOENT && r == 0)
683 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
684 q = item_set_perms_children(i, p);
693 static int item_set_perms_recursive(Item *i, const char *path) {
699 r = item_set_perms(i, path);
703 q = item_set_perms_children(i, path);
710 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
711 _cleanup_globfree_ glob_t g = {};
716 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
717 if (k != 0 && k != GLOB_NOMATCH) {
721 log_error_errno(errno, "glob(%s) failed: %m", i->path);
725 STRV_FOREACH(fn, g.gl_pathv) {
734 static int create_item(Item *i) {
743 case IGNORE_DIRECTORY_PATH:
745 case RECURSIVE_REMOVE_PATH:
750 r = write_one_file(i, i->path);
756 r = copy_tree(i->argument, i->path, false);
761 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
763 if (stat(i->argument, &a) < 0)
764 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
766 if (stat(i->path, &b) < 0)
767 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
769 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
770 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
775 r = item_set_perms(i, i->path);
782 r = glob_item(i, write_one_file);
788 case CREATE_DIRECTORY:
789 case TRUNCATE_DIRECTORY:
790 case CREATE_SUBVOLUME:
793 mkdir_parents_label(i->path, 0755);
795 if (i->type == CREATE_SUBVOLUME) {
796 RUN_WITH_UMASK((~i->mode) & 0777)
797 r = btrfs_subvol_make(i->path);
801 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY) {
803 r = mkdir_label(i->path, i->mode);
808 return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
810 if (stat(i->path, &st) < 0)
811 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
813 if (!S_ISDIR(st.st_mode)) {
814 log_debug("%s already exists and is not a directory.", i->path);
819 r = item_set_perms(i, i->path);
827 RUN_WITH_UMASK(0000) {
828 mac_selinux_create_file_prepare(i->path, S_IFIFO);
829 r = mkfifo(i->path, i->mode);
830 mac_selinux_create_file_clear();
835 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
837 if (stat(i->path, &st) < 0)
838 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
840 if (!S_ISFIFO(st.st_mode)) {
844 RUN_WITH_UMASK(0000) {
845 mac_selinux_create_file_prepare(i->path, S_IFIFO);
846 r = mkfifo_atomic(i->path, i->mode);
847 mac_selinux_create_file_clear();
851 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
853 log_debug("%s is not a fifo.", i->path);
859 r = item_set_perms(i, i->path);
867 mac_selinux_create_file_prepare(i->path, S_IFLNK);
868 r = symlink(i->argument, i->path);
869 mac_selinux_create_file_clear();
872 _cleanup_free_ char *x = NULL;
875 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
877 r = readlink_malloc(i->path, &x);
878 if (r < 0 || !streq(i->argument, x)) {
881 mac_selinux_create_file_prepare(i->path, S_IFLNK);
882 r = symlink_atomic(i->argument, i->path);
883 mac_selinux_create_file_clear();
886 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
888 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
896 case CREATE_BLOCK_DEVICE:
897 case CREATE_CHAR_DEVICE: {
900 if (have_effective_cap(CAP_MKNOD) == 0) {
901 /* In a container we lack CAP_MKNOD. We
902 shouldn't attempt to create the device node in
903 that case to avoid noise, and we don't support
904 virtualized devices in containers anyway. */
906 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
910 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
912 RUN_WITH_UMASK(0000) {
913 mac_selinux_create_file_prepare(i->path, file_type);
914 r = mknod(i->path, i->mode | file_type, i->major_minor);
915 mac_selinux_create_file_clear();
919 if (errno == EPERM) {
920 log_debug("We lack permissions, possibly because of cgroup configuration; "
921 "skipping creation of device node %s.", i->path);
926 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
928 if (stat(i->path, &st) < 0)
929 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
931 if ((st.st_mode & S_IFMT) != file_type) {
935 RUN_WITH_UMASK(0000) {
936 mac_selinux_create_file_prepare(i->path, file_type);
937 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
938 mac_selinux_create_file_clear();
942 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
944 log_debug("%s is not a device node.", i->path);
950 r = item_set_perms(i, i->path);
960 r = glob_item(i, item_set_perms);
965 case RECURSIVE_RELABEL_PATH:
967 r = glob_item(i, item_set_perms_recursive);
973 r = item_set_xattrs(i, i->path);
979 log_debug("%s created successfully.", i->path);
984 static int remove_item_instance(Item *i, const char *instance) {
993 case CREATE_DIRECTORY:
994 case CREATE_SUBVOLUME:
997 case CREATE_BLOCK_DEVICE:
998 case CREATE_CHAR_DEVICE:
1000 case IGNORE_DIRECTORY_PATH:
1003 case RECURSIVE_RELABEL_PATH:
1010 if (remove(instance) < 0 && errno != ENOENT)
1011 return log_error_errno(errno, "rm(%s): %m", instance);
1015 case TRUNCATE_DIRECTORY:
1016 case RECURSIVE_REMOVE_PATH:
1017 /* FIXME: we probably should use dir_cleanup() here
1018 * instead of rm_rf() so that 'x' is honoured. */
1019 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1020 if (r < 0 && r != -ENOENT)
1021 return log_error_errno(r, "rm_rf(%s): %m", instance);
1029 static int remove_item(Item *i) {
1038 case CREATE_DIRECTORY:
1039 case CREATE_SUBVOLUME:
1041 case CREATE_SYMLINK:
1042 case CREATE_CHAR_DEVICE:
1043 case CREATE_BLOCK_DEVICE:
1045 case IGNORE_DIRECTORY_PATH:
1048 case RECURSIVE_RELABEL_PATH:
1055 case TRUNCATE_DIRECTORY:
1056 case RECURSIVE_REMOVE_PATH:
1057 r = glob_item(i, remove_item_instance);
1064 static int clean_item_instance(Item *i, const char* instance) {
1065 _cleanup_closedir_ DIR *d = NULL;
1076 n = now(CLOCK_REALTIME);
1080 cutoff = n - i->age;
1082 d = opendir(instance);
1084 if (errno == ENOENT || errno == ENOTDIR)
1087 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1091 if (fstat(dirfd(d), &s) < 0)
1092 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1094 if (!S_ISDIR(s.st_mode)) {
1095 log_error("%s is not a directory.", i->path);
1099 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1100 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1102 mountpoint = s.st_dev != ps.st_dev ||
1103 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1105 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1106 MAX_DEPTH, i->keep_first_level);
1110 static int clean_item(Item *i) {
1116 case CREATE_DIRECTORY:
1117 case CREATE_SUBVOLUME:
1118 case TRUNCATE_DIRECTORY:
1121 clean_item_instance(i, i->path);
1123 case IGNORE_DIRECTORY_PATH:
1124 r = glob_item(i, clean_item_instance);
1133 static int process_item_array(ItemArray *array);
1135 static int process_item(Item *i) {
1137 _cleanup_free_ char *prefix = NULL;
1146 prefix = malloc(strlen(i->path) + 1);
1150 PATH_FOREACH_PREFIX(prefix, i->path) {
1153 j = hashmap_get(items, prefix);
1157 s = process_item_array(j);
1158 if (s < 0 && t == 0)
1163 r = arg_create ? create_item(i) : 0;
1164 q = arg_remove ? remove_item(i) : 0;
1165 p = arg_clean ? clean_item(i) : 0;
1173 static int process_item_array(ItemArray *array) {
1179 for (n = 0; n < array->count; n++) {
1180 k = process_item(array->items + n);
1181 if (k < 0 && r == 0)
1188 static void item_free_contents(Item *i) {
1192 strv_free(i->xattrs);
1195 static void item_array_free(ItemArray *a) {
1201 for (n = 0; n < a->count; n++)
1202 item_free_contents(a->items + n);
1207 static bool item_compatible(Item *a, Item *b) {
1210 assert(streq(a->path, b->path));
1212 if (takes_ownership(a->type) && takes_ownership(b->type))
1213 /* check if the items are the same */
1214 return streq_ptr(a->argument, b->argument) &&
1216 a->uid_set == b->uid_set &&
1219 a->gid_set == b->gid_set &&
1222 a->mode_set == b->mode_set &&
1223 a->mode == b->mode &&
1225 a->age_set == b->age_set &&
1228 a->mask_perms == b->mask_perms &&
1230 a->keep_first_level == b->keep_first_level &&
1232 a->major_minor == b->major_minor;
1237 static bool should_include_path(const char *path) {
1240 STRV_FOREACH(prefix, arg_exclude_prefixes)
1241 if (path_startswith(path, *prefix))
1244 STRV_FOREACH(prefix, arg_include_prefixes)
1245 if (path_startswith(path, *prefix))
1248 /* no matches, so we should include this path only if we
1249 * have no whitelist at all */
1250 return strv_length(arg_include_prefixes) == 0;
1253 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1255 static const Specifier specifier_table[] = {
1256 { 'm', specifier_machine_id, NULL },
1257 { 'b', specifier_boot_id, NULL },
1258 { 'H', specifier_host_name, NULL },
1259 { 'v', specifier_kernel_release, NULL },
1263 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1264 _cleanup_(item_free_contents) Item i = {};
1265 ItemArray *existing;
1268 bool force = false, boot = false;
1275 "%ms %ms %ms %ms %ms %ms %n",
1284 log_error("[%s:%u] Syntax error.", fname, line);
1288 if (isempty(action)) {
1289 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1293 for (pos = 1; action[pos]; pos++) {
1294 if (action[pos] == '!' && !boot)
1296 else if (action[pos] == '+' && !force)
1299 log_error("[%s:%u] Unknown modifiers in command '%s'",
1300 fname, line, action);
1305 if (boot && !arg_boot)
1311 r = specifier_printf(path, specifier_table, NULL, &i.path);
1313 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1318 c += strspn(buffer+c, WHITESPACE);
1319 if (buffer[c] != 0 && (buffer[c] != '-' || buffer[c+1] != 0)) {
1320 i.argument = unquote(buffer+c, "\"");
1330 case CREATE_DIRECTORY:
1331 case CREATE_SUBVOLUME:
1332 case TRUNCATE_DIRECTORY:
1335 case IGNORE_DIRECTORY_PATH:
1337 case RECURSIVE_REMOVE_PATH:
1340 case RECURSIVE_RELABEL_PATH:
1343 case CREATE_SYMLINK:
1345 i.argument = strappend("/usr/share/factory/", i.path);
1353 log_error("[%s:%u] Write file requires argument.", fname, line);
1360 i.argument = strappend("/usr/share/factory/", i.path);
1363 } else if (!path_is_absolute(i.argument)) {
1364 log_error("[%s:%u] Source path is not absolute.", fname, line);
1368 path_kill_slashes(i.argument);
1371 case CREATE_CHAR_DEVICE:
1372 case CREATE_BLOCK_DEVICE: {
1373 unsigned major, minor;
1376 log_error("[%s:%u] Device file requires argument.", fname, line);
1380 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1381 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1385 i.major_minor = makedev(major, minor);
1391 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1394 r = get_xattrs_from_arg(&i);
1400 log_error("[%s:%u] Unknown command type '%c'.", fname, line, i.type);
1404 if (!path_is_absolute(i.path)) {
1405 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1409 path_kill_slashes(i.path);
1411 if (!should_include_path(i.path))
1417 p = strappend(arg_root, i.path);
1425 if (user && !streq(user, "-")) {
1426 const char *u = user;
1428 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1430 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1437 if (group && !streq(group, "-")) {
1438 const char *g = group;
1440 r = get_group_creds(&g, &i.gid);
1442 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1449 if (mode && !streq(mode, "-")) {
1450 const char *mm = mode;
1454 i.mask_perms = true;
1458 if (sscanf(mm, "%o", &m) != 1) {
1459 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1466 i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
1469 if (age && !streq(age, "-")) {
1470 const char *a = age;
1473 i.keep_first_level = true;
1477 if (parse_sec(a, &i.age) < 0) {
1478 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1485 h = needs_glob(i.type) ? globs : items;
1487 existing = hashmap_get(h, i.path);
1491 for (n = 0; n < existing->count; n++) {
1492 if (!item_compatible(existing->items + n, &i))
1493 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1494 fname, line, i.path);
1497 existing = new0(ItemArray, 1);
1498 r = hashmap_put(h, i.path, existing);
1503 if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
1506 memcpy(existing->items + existing->count++, &i, sizeof(i));
1511 static void help(void) {
1512 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1513 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1514 " -h --help Show this help\n"
1515 " --version Show package version\n"
1516 " --create Create marked files/directories\n"
1517 " --clean Clean up marked directories\n"
1518 " --remove Remove marked files/directories\n"
1519 " --boot Execute actions only safe at boot\n"
1520 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1521 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1522 " --root=PATH Operate on an alternate filesystem root\n",
1523 program_invocation_short_name);
1526 static int parse_argv(int argc, char *argv[]) {
1529 ARG_VERSION = 0x100,
1539 static const struct option options[] = {
1540 { "help", no_argument, NULL, 'h' },
1541 { "version", no_argument, NULL, ARG_VERSION },
1542 { "create", no_argument, NULL, ARG_CREATE },
1543 { "clean", no_argument, NULL, ARG_CLEAN },
1544 { "remove", no_argument, NULL, ARG_REMOVE },
1545 { "boot", no_argument, NULL, ARG_BOOT },
1546 { "prefix", required_argument, NULL, ARG_PREFIX },
1547 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1548 { "root", required_argument, NULL, ARG_ROOT },
1557 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1566 puts(PACKAGE_STRING);
1567 puts(SYSTEMD_FEATURES);
1587 if (strv_push(&arg_include_prefixes, optarg) < 0)
1591 case ARG_EXCLUDE_PREFIX:
1592 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1598 arg_root = path_make_absolute_cwd(optarg);
1602 path_kill_slashes(arg_root);
1609 assert_not_reached("Unhandled option");
1612 if (!arg_clean && !arg_create && !arg_remove) {
1613 log_error("You need to specify at least one of --clean, --create or --remove.");
1620 static int read_config_file(const char *fn, bool ignore_enoent) {
1621 _cleanup_fclose_ FILE *f = NULL;
1622 char line[LINE_MAX];
1630 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1632 if (ignore_enoent && r == -ENOENT)
1635 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1638 FOREACH_LINE(line, f, break) {
1645 if (*l == '#' || *l == 0)
1648 k = parse_line(fn, v, l);
1649 if (k < 0 && r == 0)
1653 /* we have to determine age parameter for each entry of type X */
1654 HASHMAP_FOREACH(i, globs, iterator) {
1656 Item *j, *candidate_item = NULL;
1658 if (i->type != IGNORE_DIRECTORY_PATH)
1661 HASHMAP_FOREACH(j, items, iter) {
1662 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1665 if (path_equal(j->path, i->path)) {
1670 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1671 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1675 if (candidate_item && candidate_item->age_set) {
1676 i->age = candidate_item->age;
1682 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1690 int main(int argc, char *argv[]) {
1695 r = parse_argv(argc, argv);
1699 log_set_target(LOG_TARGET_AUTO);
1700 log_parse_environment();
1705 mac_selinux_init(NULL);
1707 items = hashmap_new(&string_hash_ops);
1708 globs = hashmap_new(&string_hash_ops);
1710 if (!items || !globs) {
1717 if (optind < argc) {
1720 for (j = optind; j < argc; j++) {
1721 k = read_config_file(argv[j], false);
1722 if (k < 0 && r == 0)
1727 _cleanup_strv_free_ char **files = NULL;
1730 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1732 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1736 STRV_FOREACH(f, files) {
1737 k = read_config_file(*f, true);
1738 if (k < 0 && r == 0)
1743 HASHMAP_FOREACH(a, globs, iterator) {
1744 k = process_item_array(a);
1745 if (k < 0 && r == 0)
1749 HASHMAP_FOREACH(a, items, iterator) {
1750 k = process_item_array(a);
1751 if (k < 0 && r == 0)
1756 while ((a = hashmap_steal_first(items)))
1759 while ((a = hashmap_steal_first(globs)))
1762 hashmap_free(items);
1763 hashmap_free(globs);
1765 free(arg_include_prefixes);
1766 free(arg_exclude_prefixes);
1769 set_free_free(unix_sockets);
1771 mac_selinux_finish();
1773 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;