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