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>
49 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
50 * them in the file system. This is intended to be used to create
51 * properly owned directories beneath /tmp, /var/tmp, /run, which are
52 * volatile and hence need to be recreated on bootup. */
54 typedef enum ItemType {
55 /* These ones take file names */
59 CREATE_DIRECTORY = 'd',
60 TRUNCATE_DIRECTORY = 'D',
63 CREATE_CHAR_DEVICE = 'c',
64 CREATE_BLOCK_DEVICE = 'b',
66 /* These ones take globs */
69 RECURSIVE_REMOVE_PATH = 'R',
71 RECURSIVE_RELABEL_PATH = 'Z'
92 static Hashmap *items = NULL, *globs = NULL;
93 static Set *unix_sockets = NULL;
95 static bool arg_create = false;
96 static bool arg_clean = false;
97 static bool arg_remove = false;
99 static const char *arg_prefix = NULL;
101 #define MAX_DEPTH 256
103 static bool needs_glob(ItemType t) {
104 return t == IGNORE_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
107 static struct Item* find_glob(Hashmap *h, const char *match) {
111 HASHMAP_FOREACH(j, h, i)
112 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
118 static void load_unix_sockets(void) {
125 /* We maintain a cache of the sockets we found in
126 * /proc/net/unix to speed things up a little. */
128 unix_sockets = set_new(string_hash_func, string_compare_func);
132 f = fopen("/proc/net/unix", "re");
137 if (!fgets(line, sizeof(line), f))
144 if (!fgets(line, sizeof(line), f))
149 p = strchr(line, ':');
157 p += strspn(p, WHITESPACE);
158 p += strcspn(p, WHITESPACE); /* skip one more word */
159 p += strspn(p, WHITESPACE);
168 path_kill_slashes(s);
170 k = set_put(unix_sockets, s);
183 set_free_free(unix_sockets);
190 static bool unix_socket_alive(const char *fn) {
196 return !!set_get(unix_sockets, (char*) fn);
198 /* We don't know, so assume yes */
202 static int dir_cleanup(
205 const struct stat *ds,
212 struct timespec times[2];
213 bool deleted = false;
214 char *sub_path = NULL;
217 while ((dent = readdir(d))) {
221 if (streq(dent->d_name, ".") ||
222 streq(dent->d_name, ".."))
225 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
227 if (errno != ENOENT) {
228 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
235 /* Stay on the same filesystem */
236 if (s.st_dev != rootdev)
239 /* Do not delete read-only files owned by root */
240 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
246 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
247 log_error("Out of memory");
252 /* Is there an item configured for this path? */
253 if (hashmap_get(items, sub_path))
256 if (find_glob(globs, sub_path))
259 if (S_ISDIR(s.st_mode)) {
262 streq(dent->d_name, "lost+found") &&
267 log_warning("Reached max depth on %s.", sub_path);
272 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
273 if (sub_dir == NULL) {
274 if (errno != ENOENT) {
275 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
282 q = dir_cleanup(sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1);
289 /* Ignore ctime, we change it when deleting */
290 age = MAX(timespec_load(&s.st_mtim),
291 timespec_load(&s.st_atim));
295 log_debug("rmdir '%s'\n", sub_path);
297 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
298 if (errno != ENOENT && errno != ENOTEMPTY) {
299 log_error("rmdir(%s): %m", sub_path);
305 /* Skip files for which the sticky bit is
306 * set. These are semantics we define, and are
307 * unknown elsewhere. See XDG_RUNTIME_DIR
308 * specification for details. */
309 if (s.st_mode & S_ISVTX)
312 if (mountpoint && S_ISREG(s.st_mode)) {
313 if (streq(dent->d_name, ".journal") &&
317 if (streq(dent->d_name, "aquota.user") ||
318 streq(dent->d_name, "aquota.group"))
322 /* Ignore sockets that are listed in /proc/net/unix */
323 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
326 /* Ignore device nodes */
327 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
330 age = MAX3(timespec_load(&s.st_mtim),
331 timespec_load(&s.st_atim),
332 timespec_load(&s.st_ctim));
337 log_debug("unlink '%s'\n", sub_path);
339 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
340 if (errno != ENOENT) {
341 log_error("unlink(%s): %m", sub_path);
352 /* Restore original directory timestamps */
353 times[0] = ds->st_atim;
354 times[1] = ds->st_mtim;
356 if (futimens(dirfd(d), times) < 0)
357 log_error("utimensat(%s): %m", p);
365 static int clean_item(Item *i) {
374 if (i->type != CREATE_DIRECTORY &&
375 i->type != TRUNCATE_DIRECTORY &&
376 i->type != IGNORE_PATH)
379 if (!i->age_set || i->age <= 0)
382 n = now(CLOCK_REALTIME);
388 d = opendir(i->path);
393 log_error("Failed to open directory %s: %m", i->path);
397 if (fstat(dirfd(d), &s) < 0) {
398 log_error("stat(%s) failed: %m", i->path);
403 if (!S_ISDIR(s.st_mode)) {
404 log_error("%s is not a directory.", i->path);
409 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
410 log_error("stat(%s/..) failed: %m", i->path);
415 mountpoint = s.st_dev != ps.st_dev ||
416 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
418 r = dir_cleanup(i->path, d, &s, cutoff, s.st_dev, mountpoint, MAX_DEPTH);
427 static int item_set_perms(Item *i, const char *path) {
428 /* not using i->path directly because it may be a glob */
430 if (chmod(path, i->mode) < 0) {
431 log_error("chmod(%s) failed: %m", path);
435 if (i->uid_set || i->gid_set)
437 i->uid_set ? i->uid : (uid_t) -1,
438 i->gid_set ? i->gid : (gid_t) -1) < 0) {
440 log_error("chown(%s) failed: %m", path);
444 return label_fix(path, false);
447 static int recursive_relabel_children(Item *i, const char *path) {
451 /* This returns the first error we run into, but nevertheless
456 return errno == ENOENT ? 0 : -errno;
459 struct dirent buf, *de;
464 r = readdir_r(d, &buf, &de);
474 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
477 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
483 if (de->d_type == DT_UNKNOWN) {
486 if (lstat(entry_path, &st) < 0) {
487 if (ret == 0 && errno != ENOENT)
493 is_dir = S_ISDIR(st.st_mode);
496 is_dir = de->d_type == DT_DIR;
498 r = item_set_perms(i, entry_path);
500 if (ret == 0 && r != -ENOENT)
507 r = recursive_relabel_children(i, entry_path);
508 if (r < 0 && ret == 0)
520 static int recursive_relabel(Item *i, const char *path) {
524 r = item_set_perms(i, path);
528 if (lstat(path, &st) < 0)
531 if (S_ISDIR(st.st_mode))
532 r = recursive_relabel_children(i, path);
537 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
545 if ((k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g)) != 0) {
547 if (k != GLOB_NOMATCH) {
551 log_error("glob(%s) failed: %m", i->path);
556 STRV_FOREACH(fn, g.gl_pathv)
557 if ((k = action(i, *fn)) < 0)
564 static int create_item(Item *i) {
575 case RECURSIVE_REMOVE_PATH:
583 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
584 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
587 fd = open(i->path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
591 if (i->type == WRITE_FILE && errno == ENOENT)
594 log_error("Failed to create file %s: %m", i->path);
601 struct iovec iovec[2];
602 static const char new_line = '\n';
604 l = strlen(i->argument);
607 iovec[0].iov_base = i->argument;
608 iovec[0].iov_len = l;
610 iovec[1].iov_base = (void*) &new_line;
611 iovec[1].iov_len = 1;
613 n = writev(fd, iovec, 2);
614 if (n < 0 || (size_t) n != l+1) {
615 log_error("Failed to write file %s: %s", i->path, n < 0 ? strerror(-n) : "Short");
616 close_nointr_nofail(fd);
617 return n < 0 ? n : -EIO;
621 close_nointr_nofail(fd);
623 if (stat(i->path, &st) < 0) {
624 log_error("stat(%s) failed: %m", i->path);
628 if (!S_ISREG(st.st_mode)) {
629 log_error("%s is not a file.", i->path);
633 r = item_set_perms(i, i->path);
640 case TRUNCATE_DIRECTORY:
641 case CREATE_DIRECTORY:
644 mkdir_parents(i->path, 0755);
645 r = mkdir(i->path, i->mode);
648 if (r < 0 && errno != EEXIST) {
649 log_error("Failed to create directory %s: %m", i->path);
653 if (stat(i->path, &st) < 0) {
654 log_error("stat(%s) failed: %m", i->path);
658 if (!S_ISDIR(st.st_mode)) {
659 log_error("%s is not a directory.", i->path);
663 r = item_set_perms(i, i->path);
672 r = mkfifo(i->path, i->mode);
675 if (r < 0 && errno != EEXIST) {
676 log_error("Failed to create fifo %s: %m", i->path);
680 if (stat(i->path, &st) < 0) {
681 log_error("stat(%s) failed: %m", i->path);
685 if (!S_ISFIFO(st.st_mode)) {
686 log_error("%s is not a fifo.", i->path);
690 r = item_set_perms(i, i->path);
696 case CREATE_SYMLINK: {
699 r = symlink(i->argument, i->path);
700 if (r < 0 && errno != EEXIST) {
701 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
705 r = readlink_malloc(i->path, &x);
707 log_error("readlink(%s) failed: %s", i->path, strerror(-r));
711 if (!streq(i->argument, x)) {
713 log_error("%s is not the right symlinks.", i->path);
721 case CREATE_BLOCK_DEVICE:
722 case CREATE_CHAR_DEVICE: {
725 r = mknod(i->path, i->mode | (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR), i->major_minor);
728 if (r < 0 && errno != EEXIST) {
729 log_error("Failed to create device node %s: %m", i->path);
733 if (stat(i->path, &st) < 0) {
734 log_error("stat(%s) failed: %m", i->path);
738 if (i->type == CREATE_BLOCK_DEVICE ? !S_ISBLK(st.st_mode) : !S_ISCHR(st.st_mode)) {
739 log_error("%s is not a device node.", i->path);
743 r = item_set_perms(i, i->path);
752 r = glob_item(i, item_set_perms);
757 case RECURSIVE_RELABEL_PATH:
759 r = glob_item(i, recursive_relabel);
764 log_debug("%s created successfully.", i->path);
769 static int remove_item_instance(Item *i, const char *instance) {
778 case CREATE_DIRECTORY:
781 case CREATE_BLOCK_DEVICE:
782 case CREATE_CHAR_DEVICE:
785 case RECURSIVE_RELABEL_PATH:
790 if (remove(instance) < 0 && errno != ENOENT) {
791 log_error("remove(%s): %m", instance);
797 case TRUNCATE_DIRECTORY:
798 case RECURSIVE_REMOVE_PATH:
799 r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
800 if (r < 0 && r != -ENOENT) {
801 log_error("rm_rf(%s): %s", instance, strerror(-r));
811 static int remove_item(Item *i) {
820 case CREATE_DIRECTORY:
823 case CREATE_CHAR_DEVICE:
824 case CREATE_BLOCK_DEVICE:
827 case RECURSIVE_RELABEL_PATH:
832 case TRUNCATE_DIRECTORY:
833 case RECURSIVE_REMOVE_PATH:
834 r = glob_item(i, remove_item_instance);
841 static int process_item(Item *i) {
846 r = arg_create ? create_item(i) : 0;
847 q = arg_remove ? remove_item(i) : 0;
848 p = arg_clean ? clean_item(i) : 0;
859 static void item_free(Item *i) {
867 static bool item_equal(Item *a, Item *b) {
871 if (!streq_ptr(a->path, b->path))
874 if (a->type != b->type)
877 if (a->uid_set != b->uid_set ||
878 (a->uid_set && a->uid != b->uid))
881 if (a->gid_set != b->gid_set ||
882 (a->gid_set && a->gid != b->gid))
885 if (a->mode_set != b->mode_set ||
886 (a->mode_set && a->mode != b->mode))
889 if (a->age_set != b->age_set ||
890 (a->age_set && a->age != b->age))
893 if ((a->type == CREATE_FILE ||
894 a->type == TRUNCATE_FILE ||
895 a->type == WRITE_FILE ||
896 a->type == CREATE_SYMLINK) &&
897 !streq_ptr(a->argument, b->argument))
900 if ((a->type == CREATE_CHAR_DEVICE ||
901 a->type == CREATE_BLOCK_DEVICE) &&
902 a->major_minor != b->major_minor)
908 static int parse_line(const char *fname, unsigned line, const char *buffer) {
910 char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
921 log_error("Out of memory");
940 log_error("[%s:%u] Syntax error.", fname, line);
946 n += strspn(buffer+n, WHITESPACE);
947 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
948 i->argument = unquote(buffer+n, "\"");
950 log_error("Out of memory");
960 case CREATE_DIRECTORY:
961 case TRUNCATE_DIRECTORY:
965 case RECURSIVE_REMOVE_PATH:
967 case RECURSIVE_RELABEL_PATH:
972 log_error("[%s:%u] Symlink file requires argument.", fname, line);
980 log_error("[%s:%u] Write file requires argument.", fname, line);
986 case CREATE_CHAR_DEVICE:
987 case CREATE_BLOCK_DEVICE: {
988 unsigned major, minor;
991 log_error("[%s:%u] Device file requires argument.", fname, line);
996 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
997 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1002 i->major_minor = makedev(major, minor);
1007 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1014 if (!path_is_absolute(i->path)) {
1015 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1020 path_kill_slashes(i->path);
1022 if (arg_prefix && !path_startswith(i->path, arg_prefix)) {
1027 if (user && !streq(user, "-")) {
1028 const char *u = user;
1030 r = get_user_creds(&u, &i->uid, NULL, NULL);
1032 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1039 if (group && !streq(group, "-")) {
1040 const char *g = group;
1042 r = get_group_creds(&g, &i->gid);
1044 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1051 if (mode && !streq(mode, "-")) {
1054 if (sscanf(mode, "%o", &m) != 1) {
1055 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1064 i->type == CREATE_DIRECTORY ||
1065 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1067 if (age && !streq(age, "-")) {
1068 if (parse_usec(age, &i->age) < 0) {
1069 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1077 h = needs_glob(i->type) ? globs : items;
1079 existing = hashmap_get(h, i->path);
1082 /* Two identical items are fine */
1083 if (!item_equal(existing, i))
1084 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1090 r = hashmap_put(h, i->path, i);
1092 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1111 static int help(void) {
1113 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1114 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1115 " -h --help Show this help\n"
1116 " --create Create marked files/directories\n"
1117 " --clean Clean up marked directories\n"
1118 " --remove Remove marked files/directories\n"
1119 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n",
1120 program_invocation_short_name);
1125 static int parse_argv(int argc, char *argv[]) {
1134 static const struct option options[] = {
1135 { "help", no_argument, NULL, 'h' },
1136 { "create", no_argument, NULL, ARG_CREATE },
1137 { "clean", no_argument, NULL, ARG_CLEAN },
1138 { "remove", no_argument, NULL, ARG_REMOVE },
1139 { "prefix", required_argument, NULL, ARG_PREFIX },
1140 { NULL, 0, NULL, 0 }
1148 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1169 arg_prefix = optarg;
1176 log_error("Unknown option code %c", c);
1181 if (!arg_clean && !arg_create && !arg_remove) {
1182 log_error("You need to specify at least one of --clean, --create or --remove.");
1189 static int read_config_file(const char *fn, bool ignore_enoent) {
1196 f = fopen(fn, "re");
1199 if (ignore_enoent && errno == ENOENT)
1202 log_error("Failed to open %s: %m", fn);
1206 log_debug("apply: %s\n", fn);
1208 char line[LINE_MAX], *l;
1211 if (!(fgets(line, sizeof(line), f)))
1217 if (*l == '#' || *l == 0)
1220 if ((k = parse_line(fn, v, l)) < 0)
1226 log_error("Failed to read from file %s: %m", fn);
1236 int main(int argc, char *argv[]) {
1241 r = parse_argv(argc, argv);
1243 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1245 log_set_target(LOG_TARGET_AUTO);
1246 log_parse_environment();
1253 items = hashmap_new(string_hash_func, string_compare_func);
1254 globs = hashmap_new(string_hash_func, string_compare_func);
1256 if (!items || !globs) {
1257 log_error("Out of memory");
1264 if (optind < argc) {
1267 for (j = optind; j < argc; j++)
1268 if (read_config_file(argv[j], false) < 0)
1274 r = conf_files_list(&files, ".conf",
1277 "/usr/local/lib/tmpfiles.d",
1278 "/usr/lib/tmpfiles.d",
1282 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1286 STRV_FOREACH(f, files) {
1287 if (read_config_file(*f, true) < 0)
1294 HASHMAP_FOREACH(i, globs, iterator)
1297 HASHMAP_FOREACH(i, items, iterator)
1301 while ((i = hashmap_steal_first(items)))
1304 while ((i = hashmap_steal_first(globs)))
1307 hashmap_free(items);
1308 hashmap_free(globs);
1310 set_free_free(unix_sockets);