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>
48 #include "conf-files.h"
50 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
51 * them in the file system. This is intended to be used to create
52 * properly owned directories beneath /tmp, /var/tmp, /run, which are
53 * volatile and hence need to be recreated on bootup. */
55 typedef enum ItemType {
56 /* These ones take file names */
60 CREATE_DIRECTORY = 'd',
61 TRUNCATE_DIRECTORY = 'D',
64 CREATE_CHAR_DEVICE = 'c',
65 CREATE_BLOCK_DEVICE = 'b',
67 /* These ones take globs */
70 RECURSIVE_REMOVE_PATH = 'R',
72 RECURSIVE_RELABEL_PATH = 'Z'
93 static Hashmap *items = NULL, *globs = NULL;
94 static Set *unix_sockets = NULL;
96 static bool arg_create = false;
97 static bool arg_clean = false;
98 static bool arg_remove = false;
100 static const char *arg_prefix = NULL;
102 #define MAX_DEPTH 256
104 static bool needs_glob(ItemType t) {
105 return t == IGNORE_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
108 static struct Item* find_glob(Hashmap *h, const char *match) {
112 HASHMAP_FOREACH(j, h, i)
113 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
119 static void load_unix_sockets(void) {
126 /* We maintain a cache of the sockets we found in
127 * /proc/net/unix to speed things up a little. */
129 unix_sockets = set_new(string_hash_func, string_compare_func);
133 f = fopen("/proc/net/unix", "re");
138 if (!fgets(line, sizeof(line), f))
145 if (!fgets(line, sizeof(line), f))
150 p = strchr(line, ':');
158 p += strspn(p, WHITESPACE);
159 p += strcspn(p, WHITESPACE); /* skip one more word */
160 p += strspn(p, WHITESPACE);
169 path_kill_slashes(s);
171 k = set_put(unix_sockets, s);
184 set_free_free(unix_sockets);
191 static bool unix_socket_alive(const char *fn) {
197 return !!set_get(unix_sockets, (char*) fn);
199 /* We don't know, so assume yes */
203 static int dir_cleanup(
206 const struct stat *ds,
213 struct timespec times[2];
214 bool deleted = false;
215 char *sub_path = NULL;
218 while ((dent = readdir(d))) {
222 if (streq(dent->d_name, ".") ||
223 streq(dent->d_name, ".."))
226 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
228 if (errno != ENOENT) {
229 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
236 /* Stay on the same filesystem */
237 if (s.st_dev != rootdev)
240 /* Do not delete read-only files owned by root */
241 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
247 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
248 log_error("Out of memory");
253 /* Is there an item configured for this path? */
254 if (hashmap_get(items, sub_path))
257 if (find_glob(globs, sub_path))
260 if (S_ISDIR(s.st_mode)) {
263 streq(dent->d_name, "lost+found") &&
268 log_warning("Reached max depth on %s.", sub_path);
273 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
274 if (sub_dir == NULL) {
275 if (errno != ENOENT) {
276 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
283 q = dir_cleanup(sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1);
290 /* Ignore ctime, we change it when deleting */
291 age = MAX(timespec_load(&s.st_mtim),
292 timespec_load(&s.st_atim));
296 log_debug("rmdir '%s'\n", sub_path);
298 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
299 if (errno != ENOENT && errno != ENOTEMPTY) {
300 log_error("rmdir(%s): %m", sub_path);
306 /* Skip files for which the sticky bit is
307 * set. These are semantics we define, and are
308 * unknown elsewhere. See XDG_RUNTIME_DIR
309 * specification for details. */
310 if (s.st_mode & S_ISVTX)
313 if (mountpoint && S_ISREG(s.st_mode)) {
314 if (streq(dent->d_name, ".journal") &&
318 if (streq(dent->d_name, "aquota.user") ||
319 streq(dent->d_name, "aquota.group"))
323 /* Ignore sockets that are listed in /proc/net/unix */
324 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
327 /* Ignore device nodes */
328 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
331 age = MAX3(timespec_load(&s.st_mtim),
332 timespec_load(&s.st_atim),
333 timespec_load(&s.st_ctim));
338 log_debug("unlink '%s'\n", sub_path);
340 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
341 if (errno != ENOENT) {
342 log_error("unlink(%s): %m", sub_path);
353 /* Restore original directory timestamps */
354 times[0] = ds->st_atim;
355 times[1] = ds->st_mtim;
357 if (futimens(dirfd(d), times) < 0)
358 log_error("utimensat(%s): %m", p);
366 static int clean_item(Item *i) {
375 if (i->type != CREATE_DIRECTORY &&
376 i->type != TRUNCATE_DIRECTORY &&
377 i->type != IGNORE_PATH)
380 if (!i->age_set || i->age <= 0)
383 n = now(CLOCK_REALTIME);
389 d = opendir(i->path);
394 log_error("Failed to open directory %s: %m", i->path);
398 if (fstat(dirfd(d), &s) < 0) {
399 log_error("stat(%s) failed: %m", i->path);
404 if (!S_ISDIR(s.st_mode)) {
405 log_error("%s is not a directory.", i->path);
410 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
411 log_error("stat(%s/..) failed: %m", i->path);
416 mountpoint = s.st_dev != ps.st_dev ||
417 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
419 r = dir_cleanup(i->path, d, &s, cutoff, s.st_dev, mountpoint, MAX_DEPTH);
428 static int item_set_perms(Item *i, const char *path) {
429 /* not using i->path directly because it may be a glob */
431 if (chmod(path, i->mode) < 0) {
432 log_error("chmod(%s) failed: %m", path);
436 if (i->uid_set || i->gid_set)
438 i->uid_set ? i->uid : (uid_t) -1,
439 i->gid_set ? i->gid : (gid_t) -1) < 0) {
441 log_error("chown(%s) failed: %m", path);
445 return label_fix(path, false);
448 static int recursive_relabel_children(Item *i, const char *path) {
452 /* This returns the first error we run into, but nevertheless
457 return errno == ENOENT ? 0 : -errno;
460 struct dirent buf, *de;
465 r = readdir_r(d, &buf, &de);
475 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
478 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
484 if (de->d_type == DT_UNKNOWN) {
487 if (lstat(entry_path, &st) < 0) {
488 if (ret == 0 && errno != ENOENT)
494 is_dir = S_ISDIR(st.st_mode);
497 is_dir = de->d_type == DT_DIR;
499 r = item_set_perms(i, entry_path);
501 if (ret == 0 && r != -ENOENT)
508 r = recursive_relabel_children(i, entry_path);
509 if (r < 0 && ret == 0)
521 static int recursive_relabel(Item *i, const char *path) {
525 r = item_set_perms(i, path);
529 if (lstat(path, &st) < 0)
532 if (S_ISDIR(st.st_mode))
533 r = recursive_relabel_children(i, path);
538 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
546 if ((k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g)) != 0) {
548 if (k != GLOB_NOMATCH) {
552 log_error("glob(%s) failed: %m", i->path);
557 STRV_FOREACH(fn, g.gl_pathv)
558 if ((k = action(i, *fn)) < 0)
565 static int create_item(Item *i) {
576 case RECURSIVE_REMOVE_PATH:
584 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
585 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
588 label_context_set(i->path, S_IFREG);
589 fd = open(i->path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
591 label_context_clear();
596 if (i->type == WRITE_FILE && errno == ENOENT)
599 log_error("Failed to create file %s: %m", i->path);
606 struct iovec iovec[2];
607 static const char new_line = '\n';
609 l = strlen(i->argument);
612 iovec[0].iov_base = i->argument;
613 iovec[0].iov_len = l;
615 iovec[1].iov_base = (void*) &new_line;
616 iovec[1].iov_len = 1;
618 n = writev(fd, iovec, 2);
619 if (n < 0 || (size_t) n != l+1) {
620 log_error("Failed to write file %s: %s", i->path, n < 0 ? strerror(-n) : "Short");
621 close_nointr_nofail(fd);
622 return n < 0 ? n : -EIO;
626 close_nointr_nofail(fd);
628 if (stat(i->path, &st) < 0) {
629 log_error("stat(%s) failed: %m", i->path);
633 if (!S_ISREG(st.st_mode)) {
634 log_error("%s is not a file.", i->path);
638 r = item_set_perms(i, i->path);
645 case TRUNCATE_DIRECTORY:
646 case CREATE_DIRECTORY:
649 mkdir_parents(i->path, 0755);
650 r = mkdir(i->path, i->mode);
653 if (r < 0 && errno != EEXIST) {
654 log_error("Failed to create directory %s: %m", i->path);
658 if (stat(i->path, &st) < 0) {
659 log_error("stat(%s) failed: %m", i->path);
663 if (!S_ISDIR(st.st_mode)) {
664 log_error("%s is not a directory.", i->path);
668 r = item_set_perms(i, i->path);
677 r = mkfifo(i->path, i->mode);
680 if (r < 0 && errno != EEXIST) {
681 log_error("Failed to create fifo %s: %m", i->path);
685 if (stat(i->path, &st) < 0) {
686 log_error("stat(%s) failed: %m", i->path);
690 if (!S_ISFIFO(st.st_mode)) {
691 log_error("%s is not a fifo.", i->path);
695 r = item_set_perms(i, i->path);
701 case CREATE_SYMLINK: {
704 label_context_set(i->path, S_IFLNK);
705 r = symlink(i->argument, i->path);
707 label_context_clear();
710 if (r < 0 && errno != EEXIST) {
711 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
715 r = readlink_malloc(i->path, &x);
717 log_error("readlink(%s) failed: %s", i->path, strerror(-r));
721 if (!streq(i->argument, x)) {
723 log_error("%s is not the right symlinks.", i->path);
731 case CREATE_BLOCK_DEVICE:
732 case CREATE_CHAR_DEVICE: {
735 label_context_set(i->path, CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
736 r = mknod(i->path, i->mode | (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR), i->major_minor);
738 label_context_clear();
742 if (r < 0 && errno != EEXIST) {
743 log_error("Failed to create device node %s: %m", i->path);
747 if (stat(i->path, &st) < 0) {
748 log_error("stat(%s) failed: %m", i->path);
752 if (i->type == CREATE_BLOCK_DEVICE ? !S_ISBLK(st.st_mode) : !S_ISCHR(st.st_mode)) {
753 log_error("%s is not a device node.", i->path);
757 r = item_set_perms(i, i->path);
766 r = glob_item(i, item_set_perms);
771 case RECURSIVE_RELABEL_PATH:
773 r = glob_item(i, recursive_relabel);
778 log_debug("%s created successfully.", i->path);
783 static int remove_item_instance(Item *i, const char *instance) {
792 case CREATE_DIRECTORY:
795 case CREATE_BLOCK_DEVICE:
796 case CREATE_CHAR_DEVICE:
799 case RECURSIVE_RELABEL_PATH:
804 if (remove(instance) < 0 && errno != ENOENT) {
805 log_error("remove(%s): %m", instance);
811 case TRUNCATE_DIRECTORY:
812 case RECURSIVE_REMOVE_PATH:
813 r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
814 if (r < 0 && r != -ENOENT) {
815 log_error("rm_rf(%s): %s", instance, strerror(-r));
825 static int remove_item(Item *i) {
834 case CREATE_DIRECTORY:
837 case CREATE_CHAR_DEVICE:
838 case CREATE_BLOCK_DEVICE:
841 case RECURSIVE_RELABEL_PATH:
846 case TRUNCATE_DIRECTORY:
847 case RECURSIVE_REMOVE_PATH:
848 r = glob_item(i, remove_item_instance);
855 static int process_item(Item *i) {
860 r = arg_create ? create_item(i) : 0;
861 q = arg_remove ? remove_item(i) : 0;
862 p = arg_clean ? clean_item(i) : 0;
873 static void item_free(Item *i) {
881 static bool item_equal(Item *a, Item *b) {
885 if (!streq_ptr(a->path, b->path))
888 if (a->type != b->type)
891 if (a->uid_set != b->uid_set ||
892 (a->uid_set && a->uid != b->uid))
895 if (a->gid_set != b->gid_set ||
896 (a->gid_set && a->gid != b->gid))
899 if (a->mode_set != b->mode_set ||
900 (a->mode_set && a->mode != b->mode))
903 if (a->age_set != b->age_set ||
904 (a->age_set && a->age != b->age))
907 if ((a->type == CREATE_FILE ||
908 a->type == TRUNCATE_FILE ||
909 a->type == WRITE_FILE ||
910 a->type == CREATE_SYMLINK) &&
911 !streq_ptr(a->argument, b->argument))
914 if ((a->type == CREATE_CHAR_DEVICE ||
915 a->type == CREATE_BLOCK_DEVICE) &&
916 a->major_minor != b->major_minor)
922 static int parse_line(const char *fname, unsigned line, const char *buffer) {
924 char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
935 log_error("Out of memory");
954 log_error("[%s:%u] Syntax error.", fname, line);
960 n += strspn(buffer+n, WHITESPACE);
961 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
962 i->argument = unquote(buffer+n, "\"");
964 log_error("Out of memory");
974 case CREATE_DIRECTORY:
975 case TRUNCATE_DIRECTORY:
979 case RECURSIVE_REMOVE_PATH:
981 case RECURSIVE_RELABEL_PATH:
986 log_error("[%s:%u] Symlink file requires argument.", fname, line);
994 log_error("[%s:%u] Write file requires argument.", fname, line);
1000 case CREATE_CHAR_DEVICE:
1001 case CREATE_BLOCK_DEVICE: {
1002 unsigned major, minor;
1005 log_error("[%s:%u] Device file requires argument.", fname, line);
1010 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1011 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1016 i->major_minor = makedev(major, minor);
1021 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1028 if (!path_is_absolute(i->path)) {
1029 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1034 path_kill_slashes(i->path);
1036 if (arg_prefix && !path_startswith(i->path, arg_prefix)) {
1041 if (user && !streq(user, "-")) {
1042 const char *u = user;
1044 r = get_user_creds(&u, &i->uid, NULL, NULL);
1046 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1053 if (group && !streq(group, "-")) {
1054 const char *g = group;
1056 r = get_group_creds(&g, &i->gid);
1058 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1065 if (mode && !streq(mode, "-")) {
1068 if (sscanf(mode, "%o", &m) != 1) {
1069 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1078 i->type == CREATE_DIRECTORY ||
1079 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1081 if (age && !streq(age, "-")) {
1082 if (parse_usec(age, &i->age) < 0) {
1083 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1091 h = needs_glob(i->type) ? globs : items;
1093 existing = hashmap_get(h, i->path);
1096 /* Two identical items are fine */
1097 if (!item_equal(existing, i))
1098 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1104 r = hashmap_put(h, i->path, i);
1106 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1125 static int help(void) {
1127 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1128 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1129 " -h --help Show this help\n"
1130 " --create Create marked files/directories\n"
1131 " --clean Clean up marked directories\n"
1132 " --remove Remove marked files/directories\n"
1133 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n",
1134 program_invocation_short_name);
1139 static int parse_argv(int argc, char *argv[]) {
1148 static const struct option options[] = {
1149 { "help", no_argument, NULL, 'h' },
1150 { "create", no_argument, NULL, ARG_CREATE },
1151 { "clean", no_argument, NULL, ARG_CLEAN },
1152 { "remove", no_argument, NULL, ARG_REMOVE },
1153 { "prefix", required_argument, NULL, ARG_PREFIX },
1154 { NULL, 0, NULL, 0 }
1162 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1183 arg_prefix = optarg;
1190 log_error("Unknown option code %c", c);
1195 if (!arg_clean && !arg_create && !arg_remove) {
1196 log_error("You need to specify at least one of --clean, --create or --remove.");
1203 static int read_config_file(const char *fn, bool ignore_enoent) {
1210 f = fopen(fn, "re");
1213 if (ignore_enoent && errno == ENOENT)
1216 log_error("Failed to open %s: %m", fn);
1220 log_debug("apply: %s\n", fn);
1222 char line[LINE_MAX], *l;
1225 if (!(fgets(line, sizeof(line), f)))
1231 if (*l == '#' || *l == 0)
1234 if ((k = parse_line(fn, v, l)) < 0)
1240 log_error("Failed to read from file %s: %m", fn);
1250 int main(int argc, char *argv[]) {
1255 r = parse_argv(argc, argv);
1257 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1259 log_set_target(LOG_TARGET_AUTO);
1260 log_parse_environment();
1267 items = hashmap_new(string_hash_func, string_compare_func);
1268 globs = hashmap_new(string_hash_func, string_compare_func);
1270 if (!items || !globs) {
1271 log_error("Out of memory");
1278 if (optind < argc) {
1281 for (j = optind; j < argc; j++)
1282 if (read_config_file(argv[j], false) < 0)
1288 r = conf_files_list(&files, ".conf",
1291 "/usr/local/lib/tmpfiles.d",
1292 "/usr/lib/tmpfiles.d",
1295 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1300 STRV_FOREACH(f, files) {
1301 if (read_config_file(*f, true) < 0)
1308 HASHMAP_FOREACH(i, globs, iterator)
1311 HASHMAP_FOREACH(i, items, iterator)
1315 while ((i = hashmap_steal_first(items)))
1318 while ((i = hashmap_steal_first(globs)))
1321 hashmap_free(items);
1322 hashmap_free(globs);
1324 set_free_free(unix_sockets);