]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/tmpfiles/tmpfiles.c
Introduce CONF_DIRS_NULSTR helper to define standard conf dirs
[thirdparty/systemd.git] / src / tmpfiles / tmpfiles.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering, Kay Sievers
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <limits.h>
28 #include <dirent.h>
29 #include <grp.h>
30 #include <pwd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <getopt.h>
35 #include <stdbool.h>
36 #include <time.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <glob.h>
40 #include <fnmatch.h>
41 #include <sys/capability.h>
42
43 #include "log.h"
44 #include "util.h"
45 #include "macro.h"
46 #include "missing.h"
47 #include "mkdir.h"
48 #include "path-util.h"
49 #include "strv.h"
50 #include "label.h"
51 #include "set.h"
52 #include "conf-files.h"
53 #include "capability.h"
54 #include "specifier.h"
55 #include "build.h"
56 #include "copy.h"
57
58 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
59 * them in the file system. This is intended to be used to create
60 * properly owned directories beneath /tmp, /var/tmp, /run, which are
61 * volatile and hence need to be recreated on bootup. */
62
63 typedef enum ItemType {
64 /* These ones take file names */
65 CREATE_FILE = 'f',
66 TRUNCATE_FILE = 'F',
67 CREATE_DIRECTORY = 'd',
68 TRUNCATE_DIRECTORY = 'D',
69 CREATE_FIFO = 'p',
70 CREATE_SYMLINK = 'L',
71 CREATE_CHAR_DEVICE = 'c',
72 CREATE_BLOCK_DEVICE = 'b',
73 COPY_FILES = 'C',
74
75 /* These ones take globs */
76 WRITE_FILE = 'w',
77 IGNORE_PATH = 'x',
78 IGNORE_DIRECTORY_PATH = 'X',
79 REMOVE_PATH = 'r',
80 RECURSIVE_REMOVE_PATH = 'R',
81 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
82 RELABEL_PATH = 'z',
83 RECURSIVE_RELABEL_PATH = 'Z',
84 } ItemType;
85
86 typedef struct Item {
87 ItemType type;
88
89 char *path;
90 char *argument;
91 uid_t uid;
92 gid_t gid;
93 mode_t mode;
94 usec_t age;
95
96 dev_t major_minor;
97
98 bool uid_set:1;
99 bool gid_set:1;
100 bool mode_set:1;
101 bool age_set:1;
102 bool mask_perms:1;
103
104 bool keep_first_level:1;
105
106 bool force:1;
107
108 bool done:1;
109 } Item;
110
111 static bool arg_create = false;
112 static bool arg_clean = false;
113 static bool arg_remove = false;
114 static bool arg_boot = false;
115
116 static char **arg_include_prefixes = NULL;
117 static char **arg_exclude_prefixes = NULL;
118 static char *arg_root = NULL;
119
120 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
121
122 #define MAX_DEPTH 256
123
124 static Hashmap *items = NULL, *globs = NULL;
125 static Set *unix_sockets = NULL;
126
127 static bool needs_glob(ItemType t) {
128 return IN_SET(t,
129 WRITE_FILE,
130 IGNORE_PATH,
131 IGNORE_DIRECTORY_PATH,
132 REMOVE_PATH,
133 RECURSIVE_REMOVE_PATH,
134 ADJUST_MODE,
135 RELABEL_PATH,
136 RECURSIVE_RELABEL_PATH);
137 }
138
139 static struct Item* find_glob(Hashmap *h, const char *match) {
140 Item *j;
141 Iterator i;
142
143 HASHMAP_FOREACH(j, h, i)
144 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
145 return j;
146
147 return NULL;
148 }
149
150 static void load_unix_sockets(void) {
151 _cleanup_fclose_ FILE *f = NULL;
152 char line[LINE_MAX];
153
154 if (unix_sockets)
155 return;
156
157 /* We maintain a cache of the sockets we found in
158 * /proc/net/unix to speed things up a little. */
159
160 unix_sockets = set_new(&string_hash_ops);
161 if (!unix_sockets)
162 return;
163
164 f = fopen("/proc/net/unix", "re");
165 if (!f)
166 return;
167
168 /* Skip header */
169 if (!fgets(line, sizeof(line), f))
170 goto fail;
171
172 for (;;) {
173 char *p, *s;
174 int k;
175
176 if (!fgets(line, sizeof(line), f))
177 break;
178
179 truncate_nl(line);
180
181 p = strchr(line, ':');
182 if (!p)
183 continue;
184
185 if (strlen(p) < 37)
186 continue;
187
188 p += 37;
189 p += strspn(p, WHITESPACE);
190 p += strcspn(p, WHITESPACE); /* skip one more word */
191 p += strspn(p, WHITESPACE);
192
193 if (*p != '/')
194 continue;
195
196 s = strdup(p);
197 if (!s)
198 goto fail;
199
200 path_kill_slashes(s);
201
202 k = set_consume(unix_sockets, s);
203 if (k < 0 && k != -EEXIST)
204 goto fail;
205 }
206
207 return;
208
209 fail:
210 set_free_free(unix_sockets);
211 unix_sockets = NULL;
212 }
213
214 static bool unix_socket_alive(const char *fn) {
215 assert(fn);
216
217 load_unix_sockets();
218
219 if (unix_sockets)
220 return !!set_get(unix_sockets, (char*) fn);
221
222 /* We don't know, so assume yes */
223 return true;
224 }
225
226 static int dir_is_mount_point(DIR *d, const char *subdir) {
227
228 union file_handle_union h = {
229 .handle.handle_bytes = MAX_HANDLE_SZ
230 };
231
232 int mount_id_parent, mount_id;
233 int r_p, r;
234
235 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
236 if (r_p < 0)
237 r_p = -errno;
238
239 h.handle.handle_bytes = MAX_HANDLE_SZ;
240 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
241 if (r < 0)
242 r = -errno;
243
244 /* got no handle; make no assumptions, return error */
245 if (r_p < 0 && r < 0)
246 return r_p;
247
248 /* got both handles; if they differ, it is a mount point */
249 if (r_p >= 0 && r >= 0)
250 return mount_id_parent != mount_id;
251
252 /* got only one handle; assume different mount points if one
253 * of both queries was not supported by the filesystem */
254 if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
255 return true;
256
257 /* return error */
258 if (r_p < 0)
259 return r_p;
260 return r;
261 }
262
263 static int dir_cleanup(
264 Item *i,
265 const char *p,
266 DIR *d,
267 const struct stat *ds,
268 usec_t cutoff,
269 dev_t rootdev,
270 bool mountpoint,
271 int maxdepth,
272 bool keep_this_level) {
273
274 struct dirent *dent;
275 struct timespec times[2];
276 bool deleted = false;
277 int r = 0;
278
279 while ((dent = readdir(d))) {
280 struct stat s;
281 usec_t age;
282 _cleanup_free_ char *sub_path = NULL;
283
284 if (streq(dent->d_name, ".") ||
285 streq(dent->d_name, ".."))
286 continue;
287
288 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
289 if (errno == ENOENT)
290 continue;
291
292 /* FUSE, NFS mounts, SELinux might return EACCES */
293 if (errno == EACCES)
294 log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
295 else
296 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
297 r = -errno;
298 continue;
299 }
300
301 /* Stay on the same filesystem */
302 if (s.st_dev != rootdev)
303 continue;
304
305 /* Try to detect bind mounts of the same filesystem instance; they
306 * do not differ in device major/minors. This type of query is not
307 * supported on all kernels or filesystem types though. */
308 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
309 continue;
310
311 /* Do not delete read-only files owned by root */
312 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
313 continue;
314
315 sub_path = strjoin(p, "/", dent->d_name, NULL);
316 if (!sub_path) {
317 r = log_oom();
318 goto finish;
319 }
320
321 /* Is there an item configured for this path? */
322 if (hashmap_get(items, sub_path))
323 continue;
324
325 if (find_glob(globs, sub_path))
326 continue;
327
328 if (S_ISDIR(s.st_mode)) {
329
330 if (mountpoint &&
331 streq(dent->d_name, "lost+found") &&
332 s.st_uid == 0)
333 continue;
334
335 if (maxdepth <= 0)
336 log_warning("Reached max depth on %s.", sub_path);
337 else {
338 _cleanup_closedir_ DIR *sub_dir;
339 int q;
340
341 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
342 if (!sub_dir) {
343 if (errno != ENOENT) {
344 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
345 r = -errno;
346 }
347
348 continue;
349 }
350
351 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
352 if (q < 0)
353 r = q;
354 }
355
356 /* Note: if you are wondering why we don't
357 * support the sticky bit for excluding
358 * directories from cleaning like we do it for
359 * other file system objects: well, the sticky
360 * bit already has a meaning for directories,
361 * so we don't want to overload that. */
362
363 if (keep_this_level)
364 continue;
365
366 /* Ignore ctime, we change it when deleting */
367 age = MAX(timespec_load(&s.st_mtim),
368 timespec_load(&s.st_atim));
369 if (age >= cutoff)
370 continue;
371
372 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
373 log_debug("rmdir '%s'", sub_path);
374
375 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
376 if (errno != ENOENT && errno != ENOTEMPTY) {
377 log_error("rmdir(%s): %m", sub_path);
378 r = -errno;
379 }
380 }
381 }
382
383 } else {
384 /* Skip files for which the sticky bit is
385 * set. These are semantics we define, and are
386 * unknown elsewhere. See XDG_RUNTIME_DIR
387 * specification for details. */
388 if (s.st_mode & S_ISVTX)
389 continue;
390
391 if (mountpoint && S_ISREG(s.st_mode)) {
392 if (streq(dent->d_name, ".journal") &&
393 s.st_uid == 0)
394 continue;
395
396 if (streq(dent->d_name, "aquota.user") ||
397 streq(dent->d_name, "aquota.group"))
398 continue;
399 }
400
401 /* Ignore sockets that are listed in /proc/net/unix */
402 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
403 continue;
404
405 /* Ignore device nodes */
406 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
407 continue;
408
409 /* Keep files on this level around if this is
410 * requested */
411 if (keep_this_level)
412 continue;
413
414 age = MAX3(timespec_load(&s.st_mtim),
415 timespec_load(&s.st_atim),
416 timespec_load(&s.st_ctim));
417
418 if (age >= cutoff)
419 continue;
420
421 log_debug("unlink '%s'", sub_path);
422
423 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
424 if (errno != ENOENT) {
425 log_error("unlink(%s): %m", sub_path);
426 r = -errno;
427 }
428 }
429
430 deleted = true;
431 }
432 }
433
434 finish:
435 if (deleted) {
436 /* Restore original directory timestamps */
437 times[0] = ds->st_atim;
438 times[1] = ds->st_mtim;
439
440 if (futimens(dirfd(d), times) < 0)
441 log_error("utimensat(%s): %m", p);
442 }
443
444 return r;
445 }
446
447 static int item_set_perms(Item *i, const char *path) {
448 struct stat st;
449 bool st_valid;
450
451 assert(i);
452 assert(path);
453
454 st_valid = stat(path, &st) == 0;
455
456 /* not using i->path directly because it may be a glob */
457 if (i->mode_set) {
458 mode_t m = i->mode;
459
460 if (i->mask_perms && st_valid) {
461 if (!(st.st_mode & 0111))
462 m &= ~0111;
463 if (!(st.st_mode & 0222))
464 m &= ~0222;
465 if (!(st.st_mode & 0444))
466 m &= ~0444;
467 if (!S_ISDIR(st.st_mode))
468 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
469 }
470
471 if (!st_valid || m != (st.st_mode & 07777)) {
472 if (chmod(path, m) < 0) {
473 log_error("chmod(%s) failed: %m", path);
474 return -errno;
475 }
476 }
477 }
478
479 if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
480 (i->uid_set || i->gid_set))
481 if (chown(path,
482 i->uid_set ? i->uid : (uid_t) -1,
483 i->gid_set ? i->gid : (gid_t) -1) < 0) {
484
485 log_error("chown(%s) failed: %m", path);
486 return -errno;
487 }
488
489 return label_fix(path, false, false);
490 }
491
492 static int write_one_file(Item *i, const char *path) {
493 _cleanup_close_ int fd = -1;
494 int flags, r = 0;
495 struct stat st;
496
497 assert(i);
498 assert(path);
499
500 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
501 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
502
503 RUN_WITH_UMASK(0000) {
504 mac_selinux_create_file_prepare(path, S_IFREG);
505 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
506 mac_selinux_create_file_clear();
507 }
508
509 if (fd < 0) {
510 if (i->type == WRITE_FILE && errno == ENOENT)
511 return 0;
512
513 log_error("Failed to create file %s: %m", path);
514 return -errno;
515 }
516
517 if (i->argument) {
518 _cleanup_free_ char *unescaped;
519 ssize_t n;
520 size_t l;
521
522 unescaped = cunescape(i->argument);
523 if (!unescaped)
524 return log_oom();
525
526 l = strlen(unescaped);
527 n = write(fd, unescaped, l);
528
529 if (n < 0 || (size_t) n < l) {
530 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
531 return n < 0 ? n : -EIO;
532 }
533 }
534
535 fd = safe_close(fd);
536
537 if (stat(path, &st) < 0) {
538 log_error("stat(%s) failed: %m", path);
539 return -errno;
540 }
541
542 if (!S_ISREG(st.st_mode)) {
543 log_error("%s is not a file.", path);
544 return -EEXIST;
545 }
546
547 r = item_set_perms(i, path);
548 if (r < 0)
549 return r;
550
551 return 0;
552 }
553
554 static int item_set_perms_children(Item *i, const char *path) {
555 _cleanup_closedir_ DIR *d;
556 int r = 0;
557
558 assert(i);
559 assert(path);
560
561 /* This returns the first error we run into, but nevertheless
562 * tries to go on */
563
564 d = opendir(path);
565 if (!d)
566 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
567
568 for (;;) {
569 _cleanup_free_ char *p = NULL;
570 struct dirent *de;
571 int q;
572
573 errno = 0;
574 de = readdir(d);
575 if (!de) {
576 if (errno != 0 && r == 0)
577 r = -errno;
578
579 break;
580 }
581
582 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
583 continue;
584
585 p = strjoin(path, "/", de->d_name, NULL);
586 if (!p)
587 return -ENOMEM;
588
589 q = item_set_perms(i, p);
590 if (q < 0 && q != -ENOENT && r == 0)
591 r = q;
592
593 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
594 q = item_set_perms_children(i, p);
595 if (q < 0 && r == 0)
596 r = q;
597 }
598 }
599
600 return r;
601 }
602
603 static int item_set_perms_recursive(Item *i, const char *path) {
604 int r, q;
605
606 assert(i);
607 assert(path);
608
609 r = item_set_perms(i, path);
610 if (r < 0)
611 return r;
612
613 q = item_set_perms_children(i, path);
614 if (q < 0 && r == 0)
615 r = q;
616
617 return r;
618 }
619
620 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
621 _cleanup_globfree_ glob_t g = {};
622 int r = 0, k;
623 char **fn;
624
625 errno = 0;
626 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
627 if (k != 0 && k != GLOB_NOMATCH) {
628 if (errno == 0)
629 errno = EIO;
630
631 log_error("glob(%s) failed: %m", i->path);
632 return -errno;
633 }
634
635 STRV_FOREACH(fn, g.gl_pathv) {
636 k = action(i, *fn);
637 if (k < 0 && r == 0)
638 r = k;
639 }
640
641 return r;
642 }
643
644 static int create_item(Item *i) {
645 struct stat st;
646 int r = 0;
647
648 assert(i);
649
650 switch (i->type) {
651
652 case IGNORE_PATH:
653 case IGNORE_DIRECTORY_PATH:
654 case REMOVE_PATH:
655 case RECURSIVE_REMOVE_PATH:
656 return 0;
657
658 case CREATE_FILE:
659 case TRUNCATE_FILE:
660 r = write_one_file(i, i->path);
661 if (r < 0)
662 return r;
663 break;
664
665 case COPY_FILES:
666 r = copy_tree(i->argument, i->path, false);
667 if (r < 0) {
668 struct stat a, b;
669
670 if (r != -EEXIST) {
671 log_error("Failed to copy files to %s: %s", i->path, strerror(-r));
672 return -r;
673 }
674
675 if (stat(i->argument, &a) < 0) {
676 log_error("stat(%s) failed: %m", i->argument);
677 return -errno;
678 }
679
680 if (stat(i->path, &b) < 0) {
681 log_error("stat(%s) failed: %m", i->path);
682 return -errno;
683 }
684
685 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
686 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
687 return 0;
688 }
689 }
690
691 r = item_set_perms(i, i->path);
692 if (r < 0)
693 return r;
694
695 break;
696
697 case WRITE_FILE:
698 r = glob_item(i, write_one_file);
699 if (r < 0)
700 return r;
701
702 break;
703
704 case TRUNCATE_DIRECTORY:
705 case CREATE_DIRECTORY:
706
707 RUN_WITH_UMASK(0000) {
708 mkdir_parents_label(i->path, 0755);
709 r = mkdir_label(i->path, i->mode);
710 }
711
712 if (r < 0) {
713 if (r != -EEXIST) {
714 log_error("Failed to create directory %s: %s", i->path, strerror(-r));
715 return r;
716 }
717
718 if (stat(i->path, &st) < 0) {
719 log_error("stat(%s) failed: %m", i->path);
720 return -errno;
721 }
722
723 if (!S_ISDIR(st.st_mode)) {
724 log_debug("%s already exists and is not a directory.", i->path);
725 return 0;
726 }
727 }
728
729 r = item_set_perms(i, i->path);
730 if (r < 0)
731 return r;
732
733 break;
734
735 case CREATE_FIFO:
736
737 RUN_WITH_UMASK(0000) {
738 mac_selinux_create_file_prepare(i->path, S_IFIFO);
739 r = mkfifo(i->path, i->mode);
740 mac_selinux_create_file_clear();
741 }
742
743 if (r < 0) {
744 if (errno != EEXIST) {
745 log_error("Failed to create fifo %s: %m", i->path);
746 return -errno;
747 }
748
749 if (stat(i->path, &st) < 0) {
750 log_error("stat(%s) failed: %m", i->path);
751 return -errno;
752 }
753
754 if (!S_ISFIFO(st.st_mode)) {
755
756 if (i->force) {
757
758 RUN_WITH_UMASK(0000) {
759 mac_selinux_create_file_prepare(i->path, S_IFIFO);
760 r = mkfifo_atomic(i->path, i->mode);
761 mac_selinux_create_file_clear();
762 }
763
764 if (r < 0) {
765 log_error("Failed to create fifo %s: %s", i->path, strerror(-r));
766 return r;
767 }
768 } else {
769 log_debug("%s is not a fifo.", i->path);
770 return 0;
771 }
772 }
773 }
774
775 r = item_set_perms(i, i->path);
776 if (r < 0)
777 return r;
778
779 break;
780
781 case CREATE_SYMLINK:
782
783 mac_selinux_create_file_prepare(i->path, S_IFLNK);
784 r = symlink(i->argument, i->path);
785 mac_selinux_create_file_clear();
786
787 if (r < 0) {
788 _cleanup_free_ char *x = NULL;
789
790 if (errno != EEXIST) {
791 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
792 return -errno;
793 }
794
795 r = readlink_malloc(i->path, &x);
796 if (r < 0 || !streq(i->argument, x)) {
797
798 if (i->force) {
799 mac_selinux_create_file_prepare(i->path, S_IFLNK);
800 r = symlink_atomic(i->argument, i->path);
801 mac_selinux_create_file_clear();
802
803 if (r < 0) {
804 log_error("symlink(%s, %s) failed: %s", i->argument, i->path, strerror(-r));
805 return r;
806 }
807 } else {
808 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
809 return 0;
810 }
811 }
812 }
813
814 break;
815
816 case CREATE_BLOCK_DEVICE:
817 case CREATE_CHAR_DEVICE: {
818 mode_t file_type;
819
820 if (have_effective_cap(CAP_MKNOD) == 0) {
821 /* In a container we lack CAP_MKNOD. We
822 shouldn't attempt to create the device node in
823 that case to avoid noise, and we don't support
824 virtualized devices in containers anyway. */
825
826 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
827 return 0;
828 }
829
830 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
831
832 RUN_WITH_UMASK(0000) {
833 mac_selinux_create_file_prepare(i->path, file_type);
834 r = mknod(i->path, i->mode | file_type, i->major_minor);
835 mac_selinux_create_file_clear();
836 }
837
838 if (r < 0) {
839 if (errno == EPERM) {
840 log_debug("We lack permissions, possibly because of cgroup configuration; "
841 "skipping creation of device node %s.", i->path);
842 return 0;
843 }
844
845 if (errno != EEXIST) {
846 log_error("Failed to create device node %s: %m", i->path);
847 return -errno;
848 }
849
850 if (stat(i->path, &st) < 0) {
851 log_error("stat(%s) failed: %m", i->path);
852 return -errno;
853 }
854
855 if ((st.st_mode & S_IFMT) != file_type) {
856
857 if (i->force) {
858
859 RUN_WITH_UMASK(0000) {
860 mac_selinux_create_file_prepare(i->path, file_type);
861 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
862 mac_selinux_create_file_clear();
863 }
864
865 if (r < 0) {
866 log_error("Failed to create device node %s: %s", i->path, strerror(-r));
867 return r;
868 }
869 } else {
870 log_debug("%s is not a device node.", i->path);
871 return 0;
872 }
873 }
874 }
875
876 r = item_set_perms(i, i->path);
877 if (r < 0)
878 return r;
879
880 break;
881 }
882
883 case ADJUST_MODE:
884 case RELABEL_PATH:
885
886 r = glob_item(i, item_set_perms);
887 if (r < 0)
888 return r;
889 break;
890
891 case RECURSIVE_RELABEL_PATH:
892
893 r = glob_item(i, item_set_perms_recursive);
894 if (r < 0)
895 return r;
896
897 break;
898 }
899
900 log_debug("%s created successfully.", i->path);
901
902 return 0;
903 }
904
905 static int remove_item_instance(Item *i, const char *instance) {
906 int r;
907
908 assert(i);
909
910 switch (i->type) {
911
912 case CREATE_FILE:
913 case TRUNCATE_FILE:
914 case CREATE_DIRECTORY:
915 case CREATE_FIFO:
916 case CREATE_SYMLINK:
917 case CREATE_BLOCK_DEVICE:
918 case CREATE_CHAR_DEVICE:
919 case IGNORE_PATH:
920 case IGNORE_DIRECTORY_PATH:
921 case ADJUST_MODE:
922 case RELABEL_PATH:
923 case RECURSIVE_RELABEL_PATH:
924 case WRITE_FILE:
925 case COPY_FILES:
926 break;
927
928 case REMOVE_PATH:
929 if (remove(instance) < 0 && errno != ENOENT) {
930 log_error("remove(%s): %m", instance);
931 return -errno;
932 }
933
934 break;
935
936 case TRUNCATE_DIRECTORY:
937 case RECURSIVE_REMOVE_PATH:
938 /* FIXME: we probably should use dir_cleanup() here
939 * instead of rm_rf() so that 'x' is honoured. */
940 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
941 if (r < 0 && r != -ENOENT) {
942 log_error("rm_rf(%s): %s", instance, strerror(-r));
943 return r;
944 }
945
946 break;
947 }
948
949 return 0;
950 }
951
952 static int remove_item(Item *i) {
953 int r = 0;
954
955 assert(i);
956
957 switch (i->type) {
958
959 case CREATE_FILE:
960 case TRUNCATE_FILE:
961 case CREATE_DIRECTORY:
962 case CREATE_FIFO:
963 case CREATE_SYMLINK:
964 case CREATE_CHAR_DEVICE:
965 case CREATE_BLOCK_DEVICE:
966 case IGNORE_PATH:
967 case IGNORE_DIRECTORY_PATH:
968 case ADJUST_MODE:
969 case RELABEL_PATH:
970 case RECURSIVE_RELABEL_PATH:
971 case WRITE_FILE:
972 case COPY_FILES:
973 break;
974
975 case REMOVE_PATH:
976 case TRUNCATE_DIRECTORY:
977 case RECURSIVE_REMOVE_PATH:
978 r = glob_item(i, remove_item_instance);
979 break;
980 }
981
982 return r;
983 }
984
985 static int clean_item_instance(Item *i, const char* instance) {
986 _cleanup_closedir_ DIR *d = NULL;
987 struct stat s, ps;
988 bool mountpoint;
989 int r;
990 usec_t cutoff, n;
991
992 assert(i);
993
994 if (!i->age_set)
995 return 0;
996
997 n = now(CLOCK_REALTIME);
998 if (n < i->age)
999 return 0;
1000
1001 cutoff = n - i->age;
1002
1003 d = opendir(instance);
1004 if (!d) {
1005 if (errno == ENOENT || errno == ENOTDIR)
1006 return 0;
1007
1008 log_error("Failed to open directory %s: %m", i->path);
1009 return -errno;
1010 }
1011
1012 if (fstat(dirfd(d), &s) < 0) {
1013 log_error("stat(%s) failed: %m", i->path);
1014 return -errno;
1015 }
1016
1017 if (!S_ISDIR(s.st_mode)) {
1018 log_error("%s is not a directory.", i->path);
1019 return -ENOTDIR;
1020 }
1021
1022 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
1023 log_error("stat(%s/..) failed: %m", i->path);
1024 return -errno;
1025 }
1026
1027 mountpoint = s.st_dev != ps.st_dev ||
1028 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1029
1030 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1031 MAX_DEPTH, i->keep_first_level);
1032 return r;
1033 }
1034
1035 static int clean_item(Item *i) {
1036 int r = 0;
1037
1038 assert(i);
1039
1040 switch (i->type) {
1041 case CREATE_DIRECTORY:
1042 case TRUNCATE_DIRECTORY:
1043 case IGNORE_PATH:
1044 case COPY_FILES:
1045 clean_item_instance(i, i->path);
1046 break;
1047 case IGNORE_DIRECTORY_PATH:
1048 r = glob_item(i, clean_item_instance);
1049 break;
1050 default:
1051 break;
1052 }
1053
1054 return r;
1055 }
1056
1057 static int process_item(Item *i) {
1058 int r, q, p;
1059 _cleanup_free_ char *prefix = NULL;
1060
1061 assert(i);
1062
1063 if (i->done)
1064 return 0;
1065
1066 i->done = true;
1067
1068 prefix = malloc(strlen(i->path) + 1);
1069 if (!prefix)
1070 return log_oom();
1071
1072 PATH_FOREACH_PREFIX(prefix, i->path) {
1073 Item *j;
1074
1075 j = hashmap_get(items, prefix);
1076 if (j)
1077 process_item(j);
1078 }
1079
1080 r = arg_create ? create_item(i) : 0;
1081 q = arg_remove ? remove_item(i) : 0;
1082 p = arg_clean ? clean_item(i) : 0;
1083
1084 if (r < 0)
1085 return r;
1086
1087 if (q < 0)
1088 return q;
1089
1090 return p;
1091 }
1092
1093 static void item_free(Item *i) {
1094
1095 if (!i)
1096 return;
1097
1098 free(i->path);
1099 free(i->argument);
1100 free(i);
1101 }
1102
1103 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1104
1105 static bool item_equal(Item *a, Item *b) {
1106 assert(a);
1107 assert(b);
1108
1109 if (!streq_ptr(a->path, b->path))
1110 return false;
1111
1112 if (a->type != b->type)
1113 return false;
1114
1115 if (a->uid_set != b->uid_set ||
1116 (a->uid_set && a->uid != b->uid))
1117 return false;
1118
1119 if (a->gid_set != b->gid_set ||
1120 (a->gid_set && a->gid != b->gid))
1121 return false;
1122
1123 if (a->mode_set != b->mode_set ||
1124 (a->mode_set && a->mode != b->mode))
1125 return false;
1126
1127 if (a->age_set != b->age_set ||
1128 (a->age_set && a->age != b->age))
1129 return false;
1130
1131 if ((a->type == CREATE_FILE ||
1132 a->type == TRUNCATE_FILE ||
1133 a->type == WRITE_FILE ||
1134 a->type == CREATE_SYMLINK ||
1135 a->type == COPY_FILES) &&
1136 !streq_ptr(a->argument, b->argument))
1137 return false;
1138
1139 if ((a->type == CREATE_CHAR_DEVICE ||
1140 a->type == CREATE_BLOCK_DEVICE) &&
1141 a->major_minor != b->major_minor)
1142 return false;
1143
1144 return true;
1145 }
1146
1147 static bool should_include_path(const char *path) {
1148 char **prefix;
1149
1150 STRV_FOREACH(prefix, arg_exclude_prefixes)
1151 if (path_startswith(path, *prefix))
1152 return false;
1153
1154 STRV_FOREACH(prefix, arg_include_prefixes)
1155 if (path_startswith(path, *prefix))
1156 return true;
1157
1158 /* no matches, so we should include this path only if we
1159 * have no whitelist at all */
1160 return strv_length(arg_include_prefixes) == 0;
1161 }
1162
1163 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1164
1165 static const Specifier specifier_table[] = {
1166 { 'm', specifier_machine_id, NULL },
1167 { 'b', specifier_boot_id, NULL },
1168 { 'H', specifier_host_name, NULL },
1169 { 'v', specifier_kernel_release, NULL },
1170 {}
1171 };
1172
1173 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1174 _cleanup_(item_freep) Item *i = NULL;
1175 Item *existing;
1176 char type;
1177 Hashmap *h;
1178 int r, n = -1;
1179
1180 assert(fname);
1181 assert(line >= 1);
1182 assert(buffer);
1183
1184 r = sscanf(buffer,
1185 "%ms %ms %ms %ms %ms %ms %n",
1186 &action,
1187 &path,
1188 &mode,
1189 &user,
1190 &group,
1191 &age,
1192 &n);
1193 if (r < 2) {
1194 log_error("[%s:%u] Syntax error.", fname, line);
1195 return -EIO;
1196 }
1197
1198 if (isempty(action)) {
1199 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1200 return -EINVAL;
1201 }
1202
1203 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1204 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1205 return -EINVAL;
1206 }
1207
1208 if (strchr(action+1, '!') && !arg_boot)
1209 return 0;
1210
1211 type = action[0];
1212
1213 i = new0(Item, 1);
1214 if (!i)
1215 return log_oom();
1216
1217 i->force = !!strchr(action+1, '+');
1218
1219 r = specifier_printf(path, specifier_table, NULL, &i->path);
1220 if (r < 0) {
1221 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1222 return r;
1223 }
1224
1225 if (n >= 0) {
1226 n += strspn(buffer+n, WHITESPACE);
1227 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1228 i->argument = unquote(buffer+n, "\"");
1229 if (!i->argument)
1230 return log_oom();
1231 }
1232 }
1233
1234 switch (type) {
1235
1236 case CREATE_FILE:
1237 case TRUNCATE_FILE:
1238 case CREATE_DIRECTORY:
1239 case TRUNCATE_DIRECTORY:
1240 case CREATE_FIFO:
1241 case IGNORE_PATH:
1242 case IGNORE_DIRECTORY_PATH:
1243 case REMOVE_PATH:
1244 case RECURSIVE_REMOVE_PATH:
1245 case ADJUST_MODE:
1246 case RELABEL_PATH:
1247 case RECURSIVE_RELABEL_PATH:
1248 break;
1249
1250 case CREATE_SYMLINK:
1251 if (!i->argument) {
1252 i->argument = strappend("/usr/share/factory", i->path);
1253 if (!i->argument)
1254 return log_oom();
1255 }
1256 break;
1257
1258 case WRITE_FILE:
1259 if (!i->argument) {
1260 log_error("[%s:%u] Write file requires argument.", fname, line);
1261 return -EBADMSG;
1262 }
1263 break;
1264
1265 case COPY_FILES:
1266 if (!i->argument) {
1267 i->argument = strappend("/usr/share/factory", i->path);
1268 if (!i->argument)
1269 return log_oom();
1270 }
1271
1272 if (!path_is_absolute(i->argument)) {
1273 log_error("[%s:%u] Source path is not absolute.", fname, line);
1274 return -EBADMSG;
1275 }
1276
1277 path_kill_slashes(i->argument);
1278 break;
1279
1280 case CREATE_CHAR_DEVICE:
1281 case CREATE_BLOCK_DEVICE: {
1282 unsigned major, minor;
1283
1284 if (!i->argument) {
1285 log_error("[%s:%u] Device file requires argument.", fname, line);
1286 return -EBADMSG;
1287 }
1288
1289 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1290 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1291 return -EBADMSG;
1292 }
1293
1294 i->major_minor = makedev(major, minor);
1295 break;
1296 }
1297
1298 default:
1299 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1300 return -EBADMSG;
1301 }
1302
1303 i->type = type;
1304
1305 if (!path_is_absolute(i->path)) {
1306 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1307 return -EBADMSG;
1308 }
1309
1310 path_kill_slashes(i->path);
1311
1312 if (!should_include_path(i->path))
1313 return 0;
1314
1315 if (arg_root) {
1316 char *p;
1317
1318 p = strappend(arg_root, i->path);
1319 if (!p)
1320 return log_oom();
1321
1322 free(i->path);
1323 i->path = p;
1324 }
1325
1326 if (user && !streq(user, "-")) {
1327 const char *u = user;
1328
1329 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1330 if (r < 0) {
1331 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1332 return r;
1333 }
1334
1335 i->uid_set = true;
1336 }
1337
1338 if (group && !streq(group, "-")) {
1339 const char *g = group;
1340
1341 r = get_group_creds(&g, &i->gid);
1342 if (r < 0) {
1343 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1344 return r;
1345 }
1346
1347 i->gid_set = true;
1348 }
1349
1350 if (mode && !streq(mode, "-")) {
1351 const char *mm = mode;
1352 unsigned m;
1353
1354 if (*mm == '~') {
1355 i->mask_perms = true;
1356 mm++;
1357 }
1358
1359 if (sscanf(mm, "%o", &m) != 1) {
1360 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1361 return -ENOENT;
1362 }
1363
1364 i->mode = m;
1365 i->mode_set = true;
1366 } else
1367 i->mode =
1368 i->type == CREATE_DIRECTORY ||
1369 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1370
1371 if (age && !streq(age, "-")) {
1372 const char *a = age;
1373
1374 if (*a == '~') {
1375 i->keep_first_level = true;
1376 a++;
1377 }
1378
1379 if (parse_sec(a, &i->age) < 0) {
1380 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1381 return -EBADMSG;
1382 }
1383
1384 i->age_set = true;
1385 }
1386
1387 h = needs_glob(i->type) ? globs : items;
1388
1389 existing = hashmap_get(h, i->path);
1390 if (existing) {
1391
1392 /* Two identical items are fine */
1393 if (!item_equal(existing, i))
1394 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1395
1396 return 0;
1397 }
1398
1399 r = hashmap_put(h, i->path, i);
1400 if (r < 0) {
1401 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1402 return r;
1403 }
1404
1405 i = NULL; /* avoid cleanup */
1406
1407 return 0;
1408 }
1409
1410 static void help(void) {
1411 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1412 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1413 " -h --help Show this help\n"
1414 " --version Show package version\n"
1415 " --create Create marked files/directories\n"
1416 " --clean Clean up marked directories\n"
1417 " --remove Remove marked files/directories\n"
1418 " --boot Execute actions only safe at boot\n"
1419 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1420 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1421 " --root=PATH Operate on an alternate filesystem root\n",
1422 program_invocation_short_name);
1423 }
1424
1425 static int parse_argv(int argc, char *argv[]) {
1426
1427 enum {
1428 ARG_VERSION = 0x100,
1429 ARG_CREATE,
1430 ARG_CLEAN,
1431 ARG_REMOVE,
1432 ARG_BOOT,
1433 ARG_PREFIX,
1434 ARG_EXCLUDE_PREFIX,
1435 ARG_ROOT,
1436 };
1437
1438 static const struct option options[] = {
1439 { "help", no_argument, NULL, 'h' },
1440 { "version", no_argument, NULL, ARG_VERSION },
1441 { "create", no_argument, NULL, ARG_CREATE },
1442 { "clean", no_argument, NULL, ARG_CLEAN },
1443 { "remove", no_argument, NULL, ARG_REMOVE },
1444 { "boot", no_argument, NULL, ARG_BOOT },
1445 { "prefix", required_argument, NULL, ARG_PREFIX },
1446 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1447 { "root", required_argument, NULL, ARG_ROOT },
1448 {}
1449 };
1450
1451 int c;
1452
1453 assert(argc >= 0);
1454 assert(argv);
1455
1456 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1457
1458 switch (c) {
1459
1460 case 'h':
1461 help();
1462 return 0;
1463
1464 case ARG_VERSION:
1465 puts(PACKAGE_STRING);
1466 puts(SYSTEMD_FEATURES);
1467 return 0;
1468
1469 case ARG_CREATE:
1470 arg_create = true;
1471 break;
1472
1473 case ARG_CLEAN:
1474 arg_clean = true;
1475 break;
1476
1477 case ARG_REMOVE:
1478 arg_remove = true;
1479 break;
1480
1481 case ARG_BOOT:
1482 arg_boot = true;
1483 break;
1484
1485 case ARG_PREFIX:
1486 if (strv_push(&arg_include_prefixes, optarg) < 0)
1487 return log_oom();
1488 break;
1489
1490 case ARG_EXCLUDE_PREFIX:
1491 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1492 return log_oom();
1493 break;
1494
1495 case ARG_ROOT:
1496 free(arg_root);
1497 arg_root = path_make_absolute_cwd(optarg);
1498 if (!arg_root)
1499 return log_oom();
1500
1501 path_kill_slashes(arg_root);
1502 break;
1503
1504 case '?':
1505 return -EINVAL;
1506
1507 default:
1508 assert_not_reached("Unhandled option");
1509 }
1510
1511 if (!arg_clean && !arg_create && !arg_remove) {
1512 log_error("You need to specify at least one of --clean, --create or --remove.");
1513 return -EINVAL;
1514 }
1515
1516 return 1;
1517 }
1518
1519 static int read_config_file(const char *fn, bool ignore_enoent) {
1520 _cleanup_fclose_ FILE *f = NULL;
1521 char line[LINE_MAX];
1522 Iterator iterator;
1523 unsigned v = 0;
1524 Item *i;
1525 int r;
1526
1527 assert(fn);
1528
1529 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1530 if (r < 0) {
1531 if (ignore_enoent && r == -ENOENT)
1532 return 0;
1533
1534 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1535 return r;
1536 }
1537
1538 FOREACH_LINE(line, f, break) {
1539 char *l;
1540 int k;
1541
1542 v++;
1543
1544 l = strstrip(line);
1545 if (*l == '#' || *l == 0)
1546 continue;
1547
1548 k = parse_line(fn, v, l);
1549 if (k < 0 && r == 0)
1550 r = k;
1551 }
1552
1553 /* we have to determine age parameter for each entry of type X */
1554 HASHMAP_FOREACH(i, globs, iterator) {
1555 Iterator iter;
1556 Item *j, *candidate_item = NULL;
1557
1558 if (i->type != IGNORE_DIRECTORY_PATH)
1559 continue;
1560
1561 HASHMAP_FOREACH(j, items, iter) {
1562 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1563 continue;
1564
1565 if (path_equal(j->path, i->path)) {
1566 candidate_item = j;
1567 break;
1568 }
1569
1570 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1571 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1572 candidate_item = j;
1573 }
1574
1575 if (candidate_item && candidate_item->age_set) {
1576 i->age = candidate_item->age;
1577 i->age_set = true;
1578 }
1579 }
1580
1581 if (ferror(f)) {
1582 log_error("Failed to read from file %s: %m", fn);
1583 if (r == 0)
1584 r = -EIO;
1585 }
1586
1587 return r;
1588 }
1589
1590 int main(int argc, char *argv[]) {
1591 int r, k;
1592 Item *i;
1593 Iterator iterator;
1594
1595 r = parse_argv(argc, argv);
1596 if (r <= 0)
1597 goto finish;
1598
1599 log_set_target(LOG_TARGET_AUTO);
1600 log_parse_environment();
1601 log_open();
1602
1603 umask(0022);
1604
1605 mac_selinux_init(NULL);
1606
1607 items = hashmap_new(&string_hash_ops);
1608 globs = hashmap_new(&string_hash_ops);
1609
1610 if (!items || !globs) {
1611 r = log_oom();
1612 goto finish;
1613 }
1614
1615 r = 0;
1616
1617 if (optind < argc) {
1618 int j;
1619
1620 for (j = optind; j < argc; j++) {
1621 k = read_config_file(argv[j], false);
1622 if (k < 0 && r == 0)
1623 r = k;
1624 }
1625
1626 } else {
1627 _cleanup_strv_free_ char **files = NULL;
1628 char **f;
1629
1630 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1631 if (r < 0) {
1632 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1633 goto finish;
1634 }
1635
1636 STRV_FOREACH(f, files) {
1637 k = read_config_file(*f, true);
1638 if (k < 0 && r == 0)
1639 r = k;
1640 }
1641 }
1642
1643 HASHMAP_FOREACH(i, globs, iterator)
1644 process_item(i);
1645
1646 HASHMAP_FOREACH(i, items, iterator)
1647 process_item(i);
1648
1649 finish:
1650 while ((i = hashmap_steal_first(items)))
1651 item_free(i);
1652
1653 while ((i = hashmap_steal_first(globs)))
1654 item_free(i);
1655
1656 hashmap_free(items);
1657 hashmap_free(globs);
1658
1659 free(arg_include_prefixes);
1660 free(arg_exclude_prefixes);
1661 free(arg_root);
1662
1663 set_free_free(unix_sockets);
1664
1665 mac_selinux_finish();
1666
1667 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1668 }