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>
42 #include <sys/xattr.h>
49 #include "path-util.h"
53 #include "conf-files.h"
54 #include "capability.h"
55 #include "specifier.h"
59 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
60 * them in the file system. This is intended to be used to create
61 * properly owned directories beneath /tmp, /var/tmp, /run, which are
62 * volatile and hence need to be recreated on bootup. */
64 typedef enum ItemType {
65 /* These ones take file names */
68 CREATE_DIRECTORY = 'd',
69 TRUNCATE_DIRECTORY = 'D',
72 CREATE_CHAR_DEVICE = 'c',
73 CREATE_BLOCK_DEVICE = 'b',
77 /* These ones take globs */
80 IGNORE_DIRECTORY_PATH = 'X',
82 RECURSIVE_REMOVE_PATH = 'R',
83 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
85 RECURSIVE_RELABEL_PATH = 'Z',
107 bool keep_first_level:1;
114 static bool arg_create = false;
115 static bool arg_clean = false;
116 static bool arg_remove = false;
117 static bool arg_boot = false;
119 static char **arg_include_prefixes = NULL;
120 static char **arg_exclude_prefixes = NULL;
121 static char *arg_root = NULL;
123 static const char conf_file_dirs[] =
126 "/usr/local/lib/tmpfiles.d\0"
127 "/usr/lib/tmpfiles.d\0"
128 #ifdef HAVE_SPLIT_USR
133 #define MAX_DEPTH 256
135 static Hashmap *items = NULL, *globs = NULL;
136 static Set *unix_sockets = NULL;
138 static bool needs_glob(ItemType t) {
142 IGNORE_DIRECTORY_PATH,
144 RECURSIVE_REMOVE_PATH,
147 RECURSIVE_RELABEL_PATH);
150 static struct Item* find_glob(Hashmap *h, const char *match) {
154 HASHMAP_FOREACH(j, h, i)
155 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
161 static void load_unix_sockets(void) {
162 _cleanup_fclose_ FILE *f = NULL;
168 /* We maintain a cache of the sockets we found in
169 * /proc/net/unix to speed things up a little. */
171 unix_sockets = set_new(string_hash_func, string_compare_func);
175 f = fopen("/proc/net/unix", "re");
180 if (!fgets(line, sizeof(line), f))
187 if (!fgets(line, sizeof(line), f))
192 p = strchr(line, ':');
200 p += strspn(p, WHITESPACE);
201 p += strcspn(p, WHITESPACE); /* skip one more word */
202 p += strspn(p, WHITESPACE);
211 path_kill_slashes(s);
213 k = set_consume(unix_sockets, s);
214 if (k < 0 && k != -EEXIST)
221 set_free_free(unix_sockets);
225 static bool unix_socket_alive(const char *fn) {
231 return !!set_get(unix_sockets, (char*) fn);
233 /* We don't know, so assume yes */
237 static int dir_is_mount_point(DIR *d, const char *subdir) {
239 union file_handle_union h = {
240 .handle.handle_bytes = MAX_HANDLE_SZ
243 int mount_id_parent, mount_id;
246 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
250 h.handle.handle_bytes = MAX_HANDLE_SZ;
251 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
255 /* got no handle; make no assumptions, return error */
256 if (r_p < 0 && r < 0)
259 /* got both handles; if they differ, it is a mount point */
260 if (r_p >= 0 && r >= 0)
261 return mount_id_parent != mount_id;
263 /* got only one handle; assume different mount points if one
264 * of both queries was not supported by the filesystem */
265 if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
274 static int dir_cleanup(
278 const struct stat *ds,
283 bool keep_this_level) {
286 struct timespec times[2];
287 bool deleted = false;
290 while ((dent = readdir(d))) {
293 _cleanup_free_ char *sub_path = NULL;
295 if (streq(dent->d_name, ".") ||
296 streq(dent->d_name, ".."))
299 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
303 /* FUSE, NFS mounts, SELinux might return EACCES */
305 log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
307 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
312 /* Stay on the same filesystem */
313 if (s.st_dev != rootdev)
316 /* Try to detect bind mounts of the same filesystem instance; they
317 * do not differ in device major/minors. This type of query is not
318 * supported on all kernels or filesystem types though. */
319 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
322 /* Do not delete read-only files owned by root */
323 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
326 sub_path = strjoin(p, "/", dent->d_name, NULL);
332 /* Is there an item configured for this path? */
333 if (hashmap_get(items, sub_path))
336 if (find_glob(globs, sub_path))
339 if (S_ISDIR(s.st_mode)) {
342 streq(dent->d_name, "lost+found") &&
347 log_warning("Reached max depth on %s.", sub_path);
349 _cleanup_closedir_ DIR *sub_dir;
352 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
354 if (errno != ENOENT) {
355 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
362 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
367 /* Note: if you are wondering why we don't
368 * support the sticky bit for excluding
369 * directories from cleaning like we do it for
370 * other file system objects: well, the sticky
371 * bit already has a meaning for directories,
372 * so we don't want to overload that. */
377 /* Ignore ctime, we change it when deleting */
378 age = MAX(timespec_load(&s.st_mtim),
379 timespec_load(&s.st_atim));
383 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
384 log_debug("rmdir '%s'", sub_path);
386 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
387 if (errno != ENOENT && errno != ENOTEMPTY) {
388 log_error("rmdir(%s): %m", sub_path);
395 /* Skip files for which the sticky bit is
396 * set. These are semantics we define, and are
397 * unknown elsewhere. See XDG_RUNTIME_DIR
398 * specification for details. */
399 if (s.st_mode & S_ISVTX)
402 if (mountpoint && S_ISREG(s.st_mode)) {
403 if (streq(dent->d_name, ".journal") &&
407 if (streq(dent->d_name, "aquota.user") ||
408 streq(dent->d_name, "aquota.group"))
412 /* Ignore sockets that are listed in /proc/net/unix */
413 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
416 /* Ignore device nodes */
417 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
420 /* Keep files on this level around if this is
425 age = MAX3(timespec_load(&s.st_mtim),
426 timespec_load(&s.st_atim),
427 timespec_load(&s.st_ctim));
432 log_debug("unlink '%s'", sub_path);
434 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
435 if (errno != ENOENT) {
436 log_error("unlink(%s): %m", sub_path);
447 /* Restore original directory timestamps */
448 times[0] = ds->st_atim;
449 times[1] = ds->st_mtim;
451 if (futimens(dirfd(d), times) < 0)
452 log_error("utimensat(%s): %m", p);
458 static int item_set_perms(Item *i, const char *path) {
465 st_valid = stat(path, &st) == 0;
467 /* not using i->path directly because it may be a glob */
471 if (i->mask_perms && st_valid) {
472 if (!(st.st_mode & 0111))
474 if (!(st.st_mode & 0222))
476 if (!(st.st_mode & 0444))
478 if (!S_ISDIR(st.st_mode))
479 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
482 if (!st_valid || m != (st.st_mode & 07777)) {
483 if (chmod(path, m) < 0) {
484 log_error("chmod(%s) failed: %m", path);
490 if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
491 (i->uid_set || i->gid_set))
493 i->uid_set ? i->uid : (uid_t) -1,
494 i->gid_set ? i->gid : (gid_t) -1) < 0) {
496 log_error("chown(%s) failed: %m", path);
500 return label_fix(path, false, false);
503 static int get_xattrs_from_arg(Item *i) {
511 log_error("%s: Argument can't be empty!", i->path);
516 while ((r = unquote_first_word(&p, &xattr)) > 0) {
517 _cleanup_free_ char *tmp = NULL, *name = NULL, *value = NULL;
518 r = split_pair(xattr, "=", &name, &value);
520 log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
525 if (streq(name, "") || streq(value, "")) {
526 log_warning("Malformed xattr found: \"%s=%s\" - ignoring.", name, value);
529 tmp = unquote(value, "\"");
533 value = cunescape(tmp);
536 if (strv_consume_pair(&i->xattrs, name, value) < 0)
544 static int item_set_xattrs(Item *i, const char *path) {
545 char **name, **value;
550 if (strv_isempty(i->xattrs))
553 STRV_FOREACH_PAIR(name, value, i->xattrs) {
556 if (lsetxattr(path, *name, *value, n, 0) < 0) {
557 log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path);
564 static int write_one_file(Item *i, const char *path) {
565 _cleanup_close_ int fd = -1;
572 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
573 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
575 RUN_WITH_UMASK(0000) {
576 label_context_set(path, S_IFREG);
577 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
578 label_context_clear();
582 if (i->type == WRITE_FILE && errno == ENOENT)
585 log_error("Failed to create file %s: %m", path);
590 _cleanup_free_ char *unescaped;
594 unescaped = cunescape(i->argument);
598 l = strlen(unescaped);
599 n = write(fd, unescaped, l);
601 if (n < 0 || (size_t) n < l) {
602 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
603 return n < 0 ? n : -EIO;
609 if (stat(path, &st) < 0) {
610 log_error("stat(%s) failed: %m", path);
614 if (!S_ISREG(st.st_mode)) {
615 log_error("%s is not a file.", path);
619 r = item_set_perms(i, path);
623 r = item_set_xattrs(i, i->path);
630 static int item_set_perms_children(Item *i, const char *path) {
631 _cleanup_closedir_ DIR *d;
637 /* This returns the first error we run into, but nevertheless
642 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
645 _cleanup_free_ char *p = NULL;
652 if (errno != 0 && r == 0)
658 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
661 p = strjoin(path, "/", de->d_name, NULL);
665 q = item_set_perms(i, p);
666 if (q < 0 && q != -ENOENT && r == 0)
669 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
670 q = item_set_perms_children(i, p);
679 static int item_set_perms_recursive(Item *i, const char *path) {
685 r = item_set_perms(i, path);
689 q = item_set_perms_children(i, path);
696 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
697 _cleanup_globfree_ glob_t g = {};
702 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
703 if (k != 0 && k != GLOB_NOMATCH) {
707 log_error("glob(%s) failed: %m", i->path);
711 STRV_FOREACH(fn, g.gl_pathv) {
720 static int create_item(Item *i) {
729 case IGNORE_DIRECTORY_PATH:
731 case RECURSIVE_REMOVE_PATH:
736 r = write_one_file(i, i->path);
742 r = copy_tree(i->argument, i->path, false);
747 log_error("Failed to copy files to %s: %s", i->path, strerror(-r));
751 if (stat(i->argument, &a) < 0) {
752 log_error("stat(%s) failed: %m", i->argument);
756 if (stat(i->path, &b) < 0) {
757 log_error("stat(%s) failed: %m", i->path);
761 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
762 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
767 r = item_set_perms(i, i->path);
774 r = glob_item(i, write_one_file);
780 case TRUNCATE_DIRECTORY:
781 case CREATE_DIRECTORY:
783 RUN_WITH_UMASK(0000) {
784 mkdir_parents_label(i->path, 0755);
785 r = mkdir_label(i->path, i->mode);
790 log_error("Failed to create directory %s: %s", i->path, strerror(-r));
794 if (stat(i->path, &st) < 0) {
795 log_error("stat(%s) failed: %m", i->path);
799 if (!S_ISDIR(st.st_mode)) {
800 log_debug("%s already exists and is not a directory.", i->path);
805 r = item_set_perms(i, i->path);
809 r = item_set_xattrs(i, i->path);
817 RUN_WITH_UMASK(0000) {
818 label_context_set(i->path, S_IFIFO);
819 r = mkfifo(i->path, i->mode);
820 label_context_clear();
824 if (errno != EEXIST) {
825 log_error("Failed to create fifo %s: %m", i->path);
829 if (stat(i->path, &st) < 0) {
830 log_error("stat(%s) failed: %m", i->path);
834 if (!S_ISFIFO(st.st_mode)) {
838 RUN_WITH_UMASK(0000) {
839 label_context_set(i->path, S_IFIFO);
840 r = mkfifo_atomic(i->path, i->mode);
841 label_context_clear();
845 log_error("Failed to create fifo %s: %s", i->path, strerror(-r));
849 log_debug("%s is not a fifo.", i->path);
855 r = item_set_perms(i, i->path);
859 r = item_set_xattrs(i, i->path);
867 label_context_set(i->path, S_IFLNK);
868 r = symlink(i->argument, i->path);
869 label_context_clear();
872 _cleanup_free_ char *x = NULL;
874 if (errno != EEXIST) {
875 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
879 r = readlink_malloc(i->path, &x);
880 if (r < 0 || !streq(i->argument, x)) {
883 label_context_set(i->path, S_IFLNK);
884 r = symlink_atomic(i->argument, i->path);
885 label_context_clear();
888 log_error("symlink(%s, %s) failed: %s", i->argument, i->path, strerror(-r));
892 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
898 r = item_set_xattrs(i, i->path);
904 case CREATE_BLOCK_DEVICE:
905 case CREATE_CHAR_DEVICE: {
908 if (have_effective_cap(CAP_MKNOD) == 0) {
909 /* In a container we lack CAP_MKNOD. We
910 shouldn't attempt to create the device node in
911 that case to avoid noise, and we don't support
912 virtualized devices in containers anyway. */
914 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
918 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
920 RUN_WITH_UMASK(0000) {
921 label_context_set(i->path, file_type);
922 r = mknod(i->path, i->mode | file_type, i->major_minor);
923 label_context_clear();
927 if (errno == EPERM) {
928 log_debug("We lack permissions, possibly because of cgroup configuration; "
929 "skipping creation of device node %s.", i->path);
933 if (errno != EEXIST) {
934 log_error("Failed to create device node %s: %m", i->path);
938 if (stat(i->path, &st) < 0) {
939 log_error("stat(%s) failed: %m", i->path);
943 if ((st.st_mode & S_IFMT) != file_type) {
947 RUN_WITH_UMASK(0000) {
948 label_context_set(i->path, file_type);
949 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
950 label_context_clear();
954 log_error("Failed to create device node %s: %s", i->path, strerror(-r));
958 log_debug("%s is not a device node.", i->path);
964 r = item_set_perms(i, i->path);
968 r = item_set_xattrs(i, i->path);
978 r = glob_item(i, item_set_perms);
983 case RECURSIVE_RELABEL_PATH:
985 r = glob_item(i, item_set_perms_recursive);
991 r = item_set_xattrs(i, i->path);
997 log_debug("%s created successfully.", i->path);
1002 static int remove_item_instance(Item *i, const char *instance) {
1011 case CREATE_DIRECTORY:
1013 case CREATE_SYMLINK:
1014 case CREATE_BLOCK_DEVICE:
1015 case CREATE_CHAR_DEVICE:
1017 case IGNORE_DIRECTORY_PATH:
1020 case RECURSIVE_RELABEL_PATH:
1027 if (remove(instance) < 0 && errno != ENOENT) {
1028 log_error("remove(%s): %m", instance);
1034 case TRUNCATE_DIRECTORY:
1035 case RECURSIVE_REMOVE_PATH:
1036 /* FIXME: we probably should use dir_cleanup() here
1037 * instead of rm_rf() so that 'x' is honoured. */
1038 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1039 if (r < 0 && r != -ENOENT) {
1040 log_error("rm_rf(%s): %s", instance, strerror(-r));
1050 static int remove_item(Item *i) {
1059 case CREATE_DIRECTORY:
1061 case CREATE_SYMLINK:
1062 case CREATE_CHAR_DEVICE:
1063 case CREATE_BLOCK_DEVICE:
1065 case IGNORE_DIRECTORY_PATH:
1068 case RECURSIVE_RELABEL_PATH:
1075 case TRUNCATE_DIRECTORY:
1076 case RECURSIVE_REMOVE_PATH:
1077 r = glob_item(i, remove_item_instance);
1084 static int clean_item_instance(Item *i, const char* instance) {
1085 _cleanup_closedir_ DIR *d = NULL;
1096 n = now(CLOCK_REALTIME);
1100 cutoff = n - i->age;
1102 d = opendir(instance);
1104 if (errno == ENOENT || errno == ENOTDIR)
1107 log_error("Failed to open directory %s: %m", i->path);
1111 if (fstat(dirfd(d), &s) < 0) {
1112 log_error("stat(%s) failed: %m", i->path);
1116 if (!S_ISDIR(s.st_mode)) {
1117 log_error("%s is not a directory.", i->path);
1121 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
1122 log_error("stat(%s/..) failed: %m", i->path);
1126 mountpoint = s.st_dev != ps.st_dev ||
1127 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1129 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1130 MAX_DEPTH, i->keep_first_level);
1134 static int clean_item(Item *i) {
1140 case CREATE_DIRECTORY:
1141 case TRUNCATE_DIRECTORY:
1144 clean_item_instance(i, i->path);
1146 case IGNORE_DIRECTORY_PATH:
1147 r = glob_item(i, clean_item_instance);
1156 static int process_item(Item *i) {
1158 char prefix[PATH_MAX];
1167 PATH_FOREACH_PREFIX(prefix, i->path) {
1170 j = hashmap_get(items, prefix);
1175 r = arg_create ? create_item(i) : 0;
1176 q = arg_remove ? remove_item(i) : 0;
1177 p = arg_clean ? clean_item(i) : 0;
1188 static void item_free(Item *i) {
1195 strv_free(i->xattrs);
1199 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1201 static bool item_equal(Item *a, Item *b) {
1205 if (!streq_ptr(a->path, b->path))
1208 if (a->type != b->type)
1211 if (a->uid_set != b->uid_set ||
1212 (a->uid_set && a->uid != b->uid))
1215 if (a->gid_set != b->gid_set ||
1216 (a->gid_set && a->gid != b->gid))
1219 if (a->mode_set != b->mode_set ||
1220 (a->mode_set && a->mode != b->mode))
1223 if (a->age_set != b->age_set ||
1224 (a->age_set && a->age != b->age))
1227 if ((a->type == CREATE_FILE ||
1228 a->type == TRUNCATE_FILE ||
1229 a->type == WRITE_FILE ||
1230 a->type == CREATE_SYMLINK ||
1231 a->type == COPY_FILES) &&
1232 !streq_ptr(a->argument, b->argument))
1235 if ((a->type == CREATE_CHAR_DEVICE ||
1236 a->type == CREATE_BLOCK_DEVICE) &&
1237 a->major_minor != b->major_minor)
1243 static bool should_include_path(const char *path) {
1246 STRV_FOREACH(prefix, arg_exclude_prefixes)
1247 if (path_startswith(path, *prefix))
1250 STRV_FOREACH(prefix, arg_include_prefixes)
1251 if (path_startswith(path, *prefix))
1254 /* no matches, so we should include this path only if we
1255 * have no whitelist at all */
1256 return strv_length(arg_include_prefixes) == 0;
1259 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1261 static const Specifier specifier_table[] = {
1262 { 'm', specifier_machine_id, NULL },
1263 { 'b', specifier_boot_id, NULL },
1264 { 'H', specifier_host_name, NULL },
1265 { 'v', specifier_kernel_release, NULL },
1269 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1270 _cleanup_(item_freep) Item *i = NULL;
1281 "%ms %ms %ms %ms %ms %ms %n",
1290 log_error("[%s:%u] Syntax error.", fname, line);
1294 if (isempty(action)) {
1295 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1299 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1300 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1304 if (strchr(action+1, '!') && !arg_boot)
1313 i->force = !!strchr(action+1, '+');
1315 r = specifier_printf(path, specifier_table, NULL, &i->path);
1317 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1322 n += strspn(buffer+n, WHITESPACE);
1323 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1324 i->argument = unquote(buffer+n, "\"");
1334 case CREATE_DIRECTORY:
1335 case TRUNCATE_DIRECTORY:
1338 case IGNORE_DIRECTORY_PATH:
1340 case RECURSIVE_REMOVE_PATH:
1343 case RECURSIVE_RELABEL_PATH:
1346 case CREATE_SYMLINK:
1348 i->argument = strappend("/usr/share/factory", i->path);
1356 log_error("[%s:%u] Write file requires argument.", fname, line);
1363 i->argument = strappend("/usr/share/factory", i->path);
1368 if (!path_is_absolute(i->argument)) {
1369 log_error("[%s:%u] Source path is not absolute.", fname, line);
1373 path_kill_slashes(i->argument);
1376 case CREATE_CHAR_DEVICE:
1377 case CREATE_BLOCK_DEVICE: {
1378 unsigned major, minor;
1381 log_error("[%s:%u] Device file requires argument.", fname, line);
1385 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1386 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1390 i->major_minor = makedev(major, minor);
1396 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1399 r = get_xattrs_from_arg(i);
1405 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1411 if (!path_is_absolute(i->path)) {
1412 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1416 path_kill_slashes(i->path);
1418 if (!should_include_path(i->path))
1424 p = strappend(arg_root, i->path);
1432 if (user && !streq(user, "-")) {
1433 const char *u = user;
1435 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1437 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1444 if (group && !streq(group, "-")) {
1445 const char *g = group;
1447 r = get_group_creds(&g, &i->gid);
1449 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1456 if (mode && !streq(mode, "-")) {
1457 const char *mm = mode;
1461 i->mask_perms = true;
1465 if (sscanf(mm, "%o", &m) != 1) {
1466 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1474 i->type == CREATE_DIRECTORY ||
1475 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1477 if (age && !streq(age, "-")) {
1478 const char *a = age;
1481 i->keep_first_level = true;
1485 if (parse_sec(a, &i->age) < 0) {
1486 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1493 h = needs_glob(i->type) ? globs : items;
1495 existing = hashmap_get(h, i->path);
1497 if (i->type == SET_XATTR) {
1498 r = strv_extend_strv(&existing->xattrs, i->xattrs);
1502 } else if (existing->type == SET_XATTR) {
1503 r = strv_extend_strv(&i->xattrs, existing->xattrs);
1506 r = hashmap_replace(h, i->path, i);
1508 log_error("Failed to replace item for %s.", i->path);
1511 item_free(existing);
1513 /* Two identical items are fine */
1514 if (!item_equal(existing, i))
1515 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1519 r = hashmap_put(h, i->path, i);
1521 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1526 i = NULL; /* avoid cleanup */
1531 static void help(void) {
1532 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1533 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1534 " -h --help Show this help\n"
1535 " --version Show package version\n"
1536 " --create Create marked files/directories\n"
1537 " --clean Clean up marked directories\n"
1538 " --remove Remove marked files/directories\n"
1539 " --boot Execute actions only safe at boot\n"
1540 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1541 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1542 " --root=PATH Operate on an alternate filesystem root\n",
1543 program_invocation_short_name);
1546 static int parse_argv(int argc, char *argv[]) {
1549 ARG_VERSION = 0x100,
1559 static const struct option options[] = {
1560 { "help", no_argument, NULL, 'h' },
1561 { "version", no_argument, NULL, ARG_VERSION },
1562 { "create", no_argument, NULL, ARG_CREATE },
1563 { "clean", no_argument, NULL, ARG_CLEAN },
1564 { "remove", no_argument, NULL, ARG_REMOVE },
1565 { "boot", no_argument, NULL, ARG_BOOT },
1566 { "prefix", required_argument, NULL, ARG_PREFIX },
1567 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1568 { "root", required_argument, NULL, ARG_ROOT },
1577 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1586 puts(PACKAGE_STRING);
1587 puts(SYSTEMD_FEATURES);
1607 if (strv_push(&arg_include_prefixes, optarg) < 0)
1611 case ARG_EXCLUDE_PREFIX:
1612 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1618 arg_root = path_make_absolute_cwd(optarg);
1622 path_kill_slashes(arg_root);
1629 assert_not_reached("Unhandled option");
1632 if (!arg_clean && !arg_create && !arg_remove) {
1633 log_error("You need to specify at least one of --clean, --create or --remove.");
1640 static int read_config_file(const char *fn, bool ignore_enoent) {
1641 _cleanup_fclose_ FILE *f = NULL;
1642 char line[LINE_MAX];
1650 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1652 if (ignore_enoent && r == -ENOENT)
1655 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1659 FOREACH_LINE(line, f, break) {
1666 if (*l == '#' || *l == 0)
1669 k = parse_line(fn, v, l);
1670 if (k < 0 && r == 0)
1674 /* we have to determine age parameter for each entry of type X */
1675 HASHMAP_FOREACH(i, globs, iterator) {
1677 Item *j, *candidate_item = NULL;
1679 if (i->type != IGNORE_DIRECTORY_PATH)
1682 HASHMAP_FOREACH(j, items, iter) {
1683 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1686 if (path_equal(j->path, i->path)) {
1691 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1692 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1696 if (candidate_item) {
1697 i->age = candidate_item->age;
1703 log_error("Failed to read from file %s: %m", fn);
1711 int main(int argc, char *argv[]) {
1716 r = parse_argv(argc, argv);
1720 log_set_target(LOG_TARGET_AUTO);
1721 log_parse_environment();
1728 items = hashmap_new(string_hash_func, string_compare_func);
1729 globs = hashmap_new(string_hash_func, string_compare_func);
1731 if (!items || !globs) {
1738 if (optind < argc) {
1741 for (j = optind; j < argc; j++) {
1742 k = read_config_file(argv[j], false);
1743 if (k < 0 && r == 0)
1748 _cleanup_strv_free_ char **files = NULL;
1751 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1753 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1757 STRV_FOREACH(f, files) {
1758 k = read_config_file(*f, true);
1759 if (k < 0 && r == 0)
1764 HASHMAP_FOREACH(i, globs, iterator)
1767 HASHMAP_FOREACH(i, items, iterator)
1771 while ((i = hashmap_steal_first(items)))
1774 while ((i = hashmap_steal_first(globs)))
1777 hashmap_free(items);
1778 hashmap_free(globs);
1780 free(arg_include_prefixes);
1781 free(arg_exclude_prefixes);
1784 set_free_free(unix_sockets);
1788 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;