]> git.proxmox.com Git - systemd.git/blob - src/tmpfiles/tmpfiles.c
Imported Upstream version 217
[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_ops);
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 == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
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 struct stat st;
457 bool st_valid;
458
459 assert(i);
460 assert(path);
461
462 st_valid = stat(path, &st) == 0;
463
464 /* not using i->path directly because it may be a glob */
465 if (i->mode_set) {
466 mode_t m = i->mode;
467
468 if (i->mask_perms && st_valid) {
469 if (!(st.st_mode & 0111))
470 m &= ~0111;
471 if (!(st.st_mode & 0222))
472 m &= ~0222;
473 if (!(st.st_mode & 0444))
474 m &= ~0444;
475 if (!S_ISDIR(st.st_mode))
476 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
477 }
478
479 if (!st_valid || m != (st.st_mode & 07777)) {
480 if (chmod(path, m) < 0) {
481 log_error("chmod(%s) failed: %m", path);
482 return -errno;
483 }
484 }
485 }
486
487 if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
488 (i->uid_set || i->gid_set))
489 if (chown(path,
490 i->uid_set ? i->uid : (uid_t) -1,
491 i->gid_set ? i->gid : (gid_t) -1) < 0) {
492
493 log_error("chown(%s) failed: %m", path);
494 return -errno;
495 }
496
497 return label_fix(path, false, false);
498 }
499
500 static int write_one_file(Item *i, const char *path) {
501 _cleanup_close_ int fd = -1;
502 int flags, r = 0;
503 struct stat st;
504
505 assert(i);
506 assert(path);
507
508 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
509 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
510
511 RUN_WITH_UMASK(0000) {
512 mac_selinux_create_file_prepare(path, S_IFREG);
513 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
514 mac_selinux_create_file_clear();
515 }
516
517 if (fd < 0) {
518 if (i->type == WRITE_FILE && errno == ENOENT)
519 return 0;
520
521 log_error("Failed to create file %s: %m", path);
522 return -errno;
523 }
524
525 if (i->argument) {
526 _cleanup_free_ char *unescaped;
527 ssize_t n;
528 size_t l;
529
530 unescaped = cunescape(i->argument);
531 if (!unescaped)
532 return log_oom();
533
534 l = strlen(unescaped);
535 n = write(fd, unescaped, l);
536
537 if (n < 0 || (size_t) n < l) {
538 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
539 return n < 0 ? n : -EIO;
540 }
541 }
542
543 fd = 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, false);
675 if (r < 0) {
676 struct stat a, b;
677
678 if (r != -EEXIST) {
679 log_error("Failed to copy files to %s: %s", i->path, strerror(-r));
680 return -r;
681 }
682
683 if (stat(i->argument, &a) < 0) {
684 log_error("stat(%s) failed: %m", i->argument);
685 return -errno;
686 }
687
688 if (stat(i->path, &b) < 0) {
689 log_error("stat(%s) failed: %m", i->path);
690 return -errno;
691 }
692
693 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
694 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
695 return 0;
696 }
697 }
698
699 r = item_set_perms(i, i->path);
700 if (r < 0)
701 return r;
702
703 break;
704
705 case WRITE_FILE:
706 r = glob_item(i, write_one_file);
707 if (r < 0)
708 return r;
709
710 break;
711
712 case TRUNCATE_DIRECTORY:
713 case CREATE_DIRECTORY:
714
715 RUN_WITH_UMASK(0000) {
716 mkdir_parents_label(i->path, 0755);
717 r = mkdir_label(i->path, i->mode);
718 }
719
720 if (r < 0) {
721 if (r != -EEXIST) {
722 log_error("Failed to create directory %s: %s", i->path, strerror(-r));
723 return r;
724 }
725
726 if (stat(i->path, &st) < 0) {
727 log_error("stat(%s) failed: %m", i->path);
728 return -errno;
729 }
730
731 if (!S_ISDIR(st.st_mode)) {
732 log_debug("%s already exists and is not a directory.", i->path);
733 return 0;
734 }
735 }
736
737 r = item_set_perms(i, i->path);
738 if (r < 0)
739 return r;
740
741 break;
742
743 case CREATE_FIFO:
744
745 RUN_WITH_UMASK(0000) {
746 mac_selinux_create_file_prepare(i->path, S_IFIFO);
747 r = mkfifo(i->path, i->mode);
748 mac_selinux_create_file_clear();
749 }
750
751 if (r < 0) {
752 if (errno != EEXIST) {
753 log_error("Failed to create fifo %s: %m", i->path);
754 return -errno;
755 }
756
757 if (stat(i->path, &st) < 0) {
758 log_error("stat(%s) failed: %m", i->path);
759 return -errno;
760 }
761
762 if (!S_ISFIFO(st.st_mode)) {
763
764 if (i->force) {
765
766 RUN_WITH_UMASK(0000) {
767 mac_selinux_create_file_prepare(i->path, S_IFIFO);
768 r = mkfifo_atomic(i->path, i->mode);
769 mac_selinux_create_file_clear();
770 }
771
772 if (r < 0) {
773 log_error("Failed to create fifo %s: %s", i->path, strerror(-r));
774 return r;
775 }
776 } else {
777 log_debug("%s is not a fifo.", i->path);
778 return 0;
779 }
780 }
781 }
782
783 r = item_set_perms(i, i->path);
784 if (r < 0)
785 return r;
786
787 break;
788
789 case CREATE_SYMLINK:
790
791 mac_selinux_create_file_prepare(i->path, S_IFLNK);
792 r = symlink(i->argument, i->path);
793 mac_selinux_create_file_clear();
794
795 if (r < 0) {
796 _cleanup_free_ char *x = NULL;
797
798 if (errno != EEXIST) {
799 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
800 return -errno;
801 }
802
803 r = readlink_malloc(i->path, &x);
804 if (r < 0 || !streq(i->argument, x)) {
805
806 if (i->force) {
807 mac_selinux_create_file_prepare(i->path, S_IFLNK);
808 r = symlink_atomic(i->argument, i->path);
809 mac_selinux_create_file_clear();
810
811 if (r < 0) {
812 log_error("symlink(%s, %s) failed: %s", i->argument, i->path, strerror(-r));
813 return r;
814 }
815 } else {
816 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
817 return 0;
818 }
819 }
820 }
821
822 break;
823
824 case CREATE_BLOCK_DEVICE:
825 case CREATE_CHAR_DEVICE: {
826 mode_t file_type;
827
828 if (have_effective_cap(CAP_MKNOD) == 0) {
829 /* In a container we lack CAP_MKNOD. We
830 shouldn't attempt to create the device node in
831 that case to avoid noise, and we don't support
832 virtualized devices in containers anyway. */
833
834 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
835 return 0;
836 }
837
838 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
839
840 RUN_WITH_UMASK(0000) {
841 mac_selinux_create_file_prepare(i->path, file_type);
842 r = mknod(i->path, i->mode | file_type, i->major_minor);
843 mac_selinux_create_file_clear();
844 }
845
846 if (r < 0) {
847 if (errno == EPERM) {
848 log_debug("We lack permissions, possibly because of cgroup configuration; "
849 "skipping creation of device node %s.", i->path);
850 return 0;
851 }
852
853 if (errno != EEXIST) {
854 log_error("Failed to create device node %s: %m", i->path);
855 return -errno;
856 }
857
858 if (stat(i->path, &st) < 0) {
859 log_error("stat(%s) failed: %m", i->path);
860 return -errno;
861 }
862
863 if ((st.st_mode & S_IFMT) != file_type) {
864
865 if (i->force) {
866
867 RUN_WITH_UMASK(0000) {
868 mac_selinux_create_file_prepare(i->path, file_type);
869 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
870 mac_selinux_create_file_clear();
871 }
872
873 if (r < 0) {
874 log_error("Failed to create device node %s: %s", i->path, strerror(-r));
875 return r;
876 }
877 } else {
878 log_debug("%s is not a device node.", i->path);
879 return 0;
880 }
881 }
882 }
883
884 r = item_set_perms(i, i->path);
885 if (r < 0)
886 return r;
887
888 break;
889 }
890
891 case ADJUST_MODE:
892 case RELABEL_PATH:
893
894 r = glob_item(i, item_set_perms);
895 if (r < 0)
896 return r;
897 break;
898
899 case RECURSIVE_RELABEL_PATH:
900
901 r = glob_item(i, item_set_perms_recursive);
902 if (r < 0)
903 return r;
904
905 break;
906 }
907
908 log_debug("%s created successfully.", i->path);
909
910 return 0;
911 }
912
913 static int remove_item_instance(Item *i, const char *instance) {
914 int r;
915
916 assert(i);
917
918 switch (i->type) {
919
920 case CREATE_FILE:
921 case TRUNCATE_FILE:
922 case CREATE_DIRECTORY:
923 case CREATE_FIFO:
924 case CREATE_SYMLINK:
925 case CREATE_BLOCK_DEVICE:
926 case CREATE_CHAR_DEVICE:
927 case IGNORE_PATH:
928 case IGNORE_DIRECTORY_PATH:
929 case ADJUST_MODE:
930 case RELABEL_PATH:
931 case RECURSIVE_RELABEL_PATH:
932 case WRITE_FILE:
933 case COPY_FILES:
934 break;
935
936 case REMOVE_PATH:
937 if (remove(instance) < 0 && errno != ENOENT) {
938 log_error("remove(%s): %m", instance);
939 return -errno;
940 }
941
942 break;
943
944 case TRUNCATE_DIRECTORY:
945 case RECURSIVE_REMOVE_PATH:
946 /* FIXME: we probably should use dir_cleanup() here
947 * instead of rm_rf() so that 'x' is honoured. */
948 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
949 if (r < 0 && r != -ENOENT) {
950 log_error("rm_rf(%s): %s", instance, strerror(-r));
951 return r;
952 }
953
954 break;
955 }
956
957 return 0;
958 }
959
960 static int remove_item(Item *i) {
961 int r = 0;
962
963 assert(i);
964
965 switch (i->type) {
966
967 case CREATE_FILE:
968 case TRUNCATE_FILE:
969 case CREATE_DIRECTORY:
970 case CREATE_FIFO:
971 case CREATE_SYMLINK:
972 case CREATE_CHAR_DEVICE:
973 case CREATE_BLOCK_DEVICE:
974 case IGNORE_PATH:
975 case IGNORE_DIRECTORY_PATH:
976 case ADJUST_MODE:
977 case RELABEL_PATH:
978 case RECURSIVE_RELABEL_PATH:
979 case WRITE_FILE:
980 case COPY_FILES:
981 break;
982
983 case REMOVE_PATH:
984 case TRUNCATE_DIRECTORY:
985 case RECURSIVE_REMOVE_PATH:
986 r = glob_item(i, remove_item_instance);
987 break;
988 }
989
990 return r;
991 }
992
993 static int clean_item_instance(Item *i, const char* instance) {
994 _cleanup_closedir_ DIR *d = NULL;
995 struct stat s, ps;
996 bool mountpoint;
997 int r;
998 usec_t cutoff, n;
999
1000 assert(i);
1001
1002 if (!i->age_set)
1003 return 0;
1004
1005 n = now(CLOCK_REALTIME);
1006 if (n < i->age)
1007 return 0;
1008
1009 cutoff = n - i->age;
1010
1011 d = opendir(instance);
1012 if (!d) {
1013 if (errno == ENOENT || errno == ENOTDIR)
1014 return 0;
1015
1016 log_error("Failed to open directory %s: %m", i->path);
1017 return -errno;
1018 }
1019
1020 if (fstat(dirfd(d), &s) < 0) {
1021 log_error("stat(%s) failed: %m", i->path);
1022 return -errno;
1023 }
1024
1025 if (!S_ISDIR(s.st_mode)) {
1026 log_error("%s is not a directory.", i->path);
1027 return -ENOTDIR;
1028 }
1029
1030 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
1031 log_error("stat(%s/..) failed: %m", i->path);
1032 return -errno;
1033 }
1034
1035 mountpoint = s.st_dev != ps.st_dev ||
1036 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1037
1038 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1039 MAX_DEPTH, i->keep_first_level);
1040 return r;
1041 }
1042
1043 static int clean_item(Item *i) {
1044 int r = 0;
1045
1046 assert(i);
1047
1048 switch (i->type) {
1049 case CREATE_DIRECTORY:
1050 case TRUNCATE_DIRECTORY:
1051 case IGNORE_PATH:
1052 case COPY_FILES:
1053 clean_item_instance(i, i->path);
1054 break;
1055 case IGNORE_DIRECTORY_PATH:
1056 r = glob_item(i, clean_item_instance);
1057 break;
1058 default:
1059 break;
1060 }
1061
1062 return r;
1063 }
1064
1065 static int process_item(Item *i) {
1066 int r, q, p;
1067 _cleanup_free_ char *prefix = NULL;
1068
1069 assert(i);
1070
1071 if (i->done)
1072 return 0;
1073
1074 i->done = true;
1075
1076 prefix = malloc(strlen(i->path) + 1);
1077 if (!prefix)
1078 return log_oom();
1079
1080 PATH_FOREACH_PREFIX(prefix, i->path) {
1081 Item *j;
1082
1083 j = hashmap_get(items, prefix);
1084 if (j)
1085 process_item(j);
1086 }
1087
1088 r = arg_create ? create_item(i) : 0;
1089 q = arg_remove ? remove_item(i) : 0;
1090 p = arg_clean ? clean_item(i) : 0;
1091
1092 if (r < 0)
1093 return r;
1094
1095 if (q < 0)
1096 return q;
1097
1098 return p;
1099 }
1100
1101 static void item_free(Item *i) {
1102
1103 if (!i)
1104 return;
1105
1106 free(i->path);
1107 free(i->argument);
1108 free(i);
1109 }
1110
1111 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1112
1113 static bool item_equal(Item *a, Item *b) {
1114 assert(a);
1115 assert(b);
1116
1117 if (!streq_ptr(a->path, b->path))
1118 return false;
1119
1120 if (a->type != b->type)
1121 return false;
1122
1123 if (a->uid_set != b->uid_set ||
1124 (a->uid_set && a->uid != b->uid))
1125 return false;
1126
1127 if (a->gid_set != b->gid_set ||
1128 (a->gid_set && a->gid != b->gid))
1129 return false;
1130
1131 if (a->mode_set != b->mode_set ||
1132 (a->mode_set && a->mode != b->mode))
1133 return false;
1134
1135 if (a->age_set != b->age_set ||
1136 (a->age_set && a->age != b->age))
1137 return false;
1138
1139 if ((a->type == CREATE_FILE ||
1140 a->type == TRUNCATE_FILE ||
1141 a->type == WRITE_FILE ||
1142 a->type == CREATE_SYMLINK ||
1143 a->type == COPY_FILES) &&
1144 !streq_ptr(a->argument, b->argument))
1145 return false;
1146
1147 if ((a->type == CREATE_CHAR_DEVICE ||
1148 a->type == CREATE_BLOCK_DEVICE) &&
1149 a->major_minor != b->major_minor)
1150 return false;
1151
1152 return true;
1153 }
1154
1155 static bool should_include_path(const char *path) {
1156 char **prefix;
1157
1158 STRV_FOREACH(prefix, arg_exclude_prefixes)
1159 if (path_startswith(path, *prefix))
1160 return false;
1161
1162 STRV_FOREACH(prefix, arg_include_prefixes)
1163 if (path_startswith(path, *prefix))
1164 return true;
1165
1166 /* no matches, so we should include this path only if we
1167 * have no whitelist at all */
1168 return strv_length(arg_include_prefixes) == 0;
1169 }
1170
1171 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1172
1173 static const Specifier specifier_table[] = {
1174 { 'm', specifier_machine_id, NULL },
1175 { 'b', specifier_boot_id, NULL },
1176 { 'H', specifier_host_name, NULL },
1177 { 'v', specifier_kernel_release, NULL },
1178 {}
1179 };
1180
1181 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1182 _cleanup_(item_freep) Item *i = NULL;
1183 Item *existing;
1184 char type;
1185 Hashmap *h;
1186 int r, n = -1;
1187
1188 assert(fname);
1189 assert(line >= 1);
1190 assert(buffer);
1191
1192 r = sscanf(buffer,
1193 "%ms %ms %ms %ms %ms %ms %n",
1194 &action,
1195 &path,
1196 &mode,
1197 &user,
1198 &group,
1199 &age,
1200 &n);
1201 if (r < 2) {
1202 log_error("[%s:%u] Syntax error.", fname, line);
1203 return -EIO;
1204 }
1205
1206 if (isempty(action)) {
1207 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1208 return -EINVAL;
1209 }
1210
1211 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1212 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1213 return -EINVAL;
1214 }
1215
1216 if (strchr(action+1, '!') && !arg_boot)
1217 return 0;
1218
1219 type = action[0];
1220
1221 i = new0(Item, 1);
1222 if (!i)
1223 return log_oom();
1224
1225 i->force = !!strchr(action+1, '+');
1226
1227 r = specifier_printf(path, specifier_table, NULL, &i->path);
1228 if (r < 0) {
1229 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1230 return r;
1231 }
1232
1233 if (n >= 0) {
1234 n += strspn(buffer+n, WHITESPACE);
1235 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1236 i->argument = unquote(buffer+n, "\"");
1237 if (!i->argument)
1238 return log_oom();
1239 }
1240 }
1241
1242 switch (type) {
1243
1244 case CREATE_FILE:
1245 case TRUNCATE_FILE:
1246 case CREATE_DIRECTORY:
1247 case TRUNCATE_DIRECTORY:
1248 case CREATE_FIFO:
1249 case IGNORE_PATH:
1250 case IGNORE_DIRECTORY_PATH:
1251 case REMOVE_PATH:
1252 case RECURSIVE_REMOVE_PATH:
1253 case ADJUST_MODE:
1254 case RELABEL_PATH:
1255 case RECURSIVE_RELABEL_PATH:
1256 break;
1257
1258 case CREATE_SYMLINK:
1259 if (!i->argument) {
1260 i->argument = strappend("/usr/share/factory", i->path);
1261 if (!i->argument)
1262 return log_oom();
1263 }
1264 break;
1265
1266 case WRITE_FILE:
1267 if (!i->argument) {
1268 log_error("[%s:%u] Write file requires argument.", fname, line);
1269 return -EBADMSG;
1270 }
1271 break;
1272
1273 case COPY_FILES:
1274 if (!i->argument) {
1275 i->argument = strappend("/usr/share/factory", i->path);
1276 if (!i->argument)
1277 return log_oom();
1278 }
1279
1280 if (!path_is_absolute(i->argument)) {
1281 log_error("[%s:%u] Source path is not absolute.", fname, line);
1282 return -EBADMSG;
1283 }
1284
1285 path_kill_slashes(i->argument);
1286 break;
1287
1288 case CREATE_CHAR_DEVICE:
1289 case CREATE_BLOCK_DEVICE: {
1290 unsigned major, minor;
1291
1292 if (!i->argument) {
1293 log_error("[%s:%u] Device file requires argument.", fname, line);
1294 return -EBADMSG;
1295 }
1296
1297 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1298 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1299 return -EBADMSG;
1300 }
1301
1302 i->major_minor = makedev(major, minor);
1303 break;
1304 }
1305
1306 default:
1307 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1308 return -EBADMSG;
1309 }
1310
1311 i->type = type;
1312
1313 if (!path_is_absolute(i->path)) {
1314 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1315 return -EBADMSG;
1316 }
1317
1318 path_kill_slashes(i->path);
1319
1320 if (!should_include_path(i->path))
1321 return 0;
1322
1323 if (arg_root) {
1324 char *p;
1325
1326 p = strappend(arg_root, i->path);
1327 if (!p)
1328 return log_oom();
1329
1330 free(i->path);
1331 i->path = p;
1332 }
1333
1334 if (user && !streq(user, "-")) {
1335 const char *u = user;
1336
1337 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1338 if (r < 0) {
1339 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1340 return r;
1341 }
1342
1343 i->uid_set = true;
1344 }
1345
1346 if (group && !streq(group, "-")) {
1347 const char *g = group;
1348
1349 r = get_group_creds(&g, &i->gid);
1350 if (r < 0) {
1351 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1352 return r;
1353 }
1354
1355 i->gid_set = true;
1356 }
1357
1358 if (mode && !streq(mode, "-")) {
1359 const char *mm = mode;
1360 unsigned m;
1361
1362 if (*mm == '~') {
1363 i->mask_perms = true;
1364 mm++;
1365 }
1366
1367 if (sscanf(mm, "%o", &m) != 1) {
1368 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1369 return -ENOENT;
1370 }
1371
1372 i->mode = m;
1373 i->mode_set = true;
1374 } else
1375 i->mode =
1376 i->type == CREATE_DIRECTORY ||
1377 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1378
1379 if (age && !streq(age, "-")) {
1380 const char *a = age;
1381
1382 if (*a == '~') {
1383 i->keep_first_level = true;
1384 a++;
1385 }
1386
1387 if (parse_sec(a, &i->age) < 0) {
1388 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1389 return -EBADMSG;
1390 }
1391
1392 i->age_set = true;
1393 }
1394
1395 h = needs_glob(i->type) ? globs : items;
1396
1397 existing = hashmap_get(h, i->path);
1398 if (existing) {
1399
1400 /* Two identical items are fine */
1401 if (!item_equal(existing, i))
1402 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1403
1404 return 0;
1405 }
1406
1407 r = hashmap_put(h, i->path, i);
1408 if (r < 0) {
1409 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1410 return r;
1411 }
1412
1413 i = NULL; /* avoid cleanup */
1414
1415 return 0;
1416 }
1417
1418 static void help(void) {
1419 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1420 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1421 " -h --help Show this help\n"
1422 " --version Show package version\n"
1423 " --create Create marked files/directories\n"
1424 " --clean Clean up marked directories\n"
1425 " --remove Remove marked files/directories\n"
1426 " --boot Execute actions only safe at boot\n"
1427 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1428 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1429 " --root=PATH Operate on an alternate filesystem root\n",
1430 program_invocation_short_name);
1431 }
1432
1433 static int parse_argv(int argc, char *argv[]) {
1434
1435 enum {
1436 ARG_VERSION = 0x100,
1437 ARG_CREATE,
1438 ARG_CLEAN,
1439 ARG_REMOVE,
1440 ARG_BOOT,
1441 ARG_PREFIX,
1442 ARG_EXCLUDE_PREFIX,
1443 ARG_ROOT,
1444 };
1445
1446 static const struct option options[] = {
1447 { "help", no_argument, NULL, 'h' },
1448 { "version", no_argument, NULL, ARG_VERSION },
1449 { "create", no_argument, NULL, ARG_CREATE },
1450 { "clean", no_argument, NULL, ARG_CLEAN },
1451 { "remove", no_argument, NULL, ARG_REMOVE },
1452 { "boot", no_argument, NULL, ARG_BOOT },
1453 { "prefix", required_argument, NULL, ARG_PREFIX },
1454 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1455 { "root", required_argument, NULL, ARG_ROOT },
1456 {}
1457 };
1458
1459 int c;
1460
1461 assert(argc >= 0);
1462 assert(argv);
1463
1464 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1465
1466 switch (c) {
1467
1468 case 'h':
1469 help();
1470 return 0;
1471
1472 case ARG_VERSION:
1473 puts(PACKAGE_STRING);
1474 puts(SYSTEMD_FEATURES);
1475 return 0;
1476
1477 case ARG_CREATE:
1478 arg_create = true;
1479 break;
1480
1481 case ARG_CLEAN:
1482 arg_clean = true;
1483 break;
1484
1485 case ARG_REMOVE:
1486 arg_remove = true;
1487 break;
1488
1489 case ARG_BOOT:
1490 arg_boot = true;
1491 break;
1492
1493 case ARG_PREFIX:
1494 if (strv_push(&arg_include_prefixes, optarg) < 0)
1495 return log_oom();
1496 break;
1497
1498 case ARG_EXCLUDE_PREFIX:
1499 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1500 return log_oom();
1501 break;
1502
1503 case ARG_ROOT:
1504 free(arg_root);
1505 arg_root = path_make_absolute_cwd(optarg);
1506 if (!arg_root)
1507 return log_oom();
1508
1509 path_kill_slashes(arg_root);
1510 break;
1511
1512 case '?':
1513 return -EINVAL;
1514
1515 default:
1516 assert_not_reached("Unhandled option");
1517 }
1518
1519 if (!arg_clean && !arg_create && !arg_remove) {
1520 log_error("You need to specify at least one of --clean, --create or --remove.");
1521 return -EINVAL;
1522 }
1523
1524 return 1;
1525 }
1526
1527 static int read_config_file(const char *fn, bool ignore_enoent) {
1528 _cleanup_fclose_ FILE *f = NULL;
1529 char line[LINE_MAX];
1530 Iterator iterator;
1531 unsigned v = 0;
1532 Item *i;
1533 int r;
1534
1535 assert(fn);
1536
1537 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1538 if (r < 0) {
1539 if (ignore_enoent && r == -ENOENT)
1540 return 0;
1541
1542 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1543 return r;
1544 }
1545
1546 FOREACH_LINE(line, f, break) {
1547 char *l;
1548 int k;
1549
1550 v++;
1551
1552 l = strstrip(line);
1553 if (*l == '#' || *l == 0)
1554 continue;
1555
1556 k = parse_line(fn, v, l);
1557 if (k < 0 && r == 0)
1558 r = k;
1559 }
1560
1561 /* we have to determine age parameter for each entry of type X */
1562 HASHMAP_FOREACH(i, globs, iterator) {
1563 Iterator iter;
1564 Item *j, *candidate_item = NULL;
1565
1566 if (i->type != IGNORE_DIRECTORY_PATH)
1567 continue;
1568
1569 HASHMAP_FOREACH(j, items, iter) {
1570 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1571 continue;
1572
1573 if (path_equal(j->path, i->path)) {
1574 candidate_item = j;
1575 break;
1576 }
1577
1578 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1579 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1580 candidate_item = j;
1581 }
1582
1583 if (candidate_item && candidate_item->age_set) {
1584 i->age = candidate_item->age;
1585 i->age_set = true;
1586 }
1587 }
1588
1589 if (ferror(f)) {
1590 log_error("Failed to read from file %s: %m", fn);
1591 if (r == 0)
1592 r = -EIO;
1593 }
1594
1595 return r;
1596 }
1597
1598 int main(int argc, char *argv[]) {
1599 int r, k;
1600 Item *i;
1601 Iterator iterator;
1602
1603 r = parse_argv(argc, argv);
1604 if (r <= 0)
1605 goto finish;
1606
1607 log_set_target(LOG_TARGET_AUTO);
1608 log_parse_environment();
1609 log_open();
1610
1611 umask(0022);
1612
1613 mac_selinux_init(NULL);
1614
1615 items = hashmap_new(&string_hash_ops);
1616 globs = hashmap_new(&string_hash_ops);
1617
1618 if (!items || !globs) {
1619 r = log_oom();
1620 goto finish;
1621 }
1622
1623 r = 0;
1624
1625 if (optind < argc) {
1626 int j;
1627
1628 for (j = optind; j < argc; j++) {
1629 k = read_config_file(argv[j], false);
1630 if (k < 0 && r == 0)
1631 r = k;
1632 }
1633
1634 } else {
1635 _cleanup_strv_free_ char **files = NULL;
1636 char **f;
1637
1638 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1639 if (r < 0) {
1640 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1641 goto finish;
1642 }
1643
1644 STRV_FOREACH(f, files) {
1645 k = read_config_file(*f, true);
1646 if (k < 0 && r == 0)
1647 r = k;
1648 }
1649 }
1650
1651 HASHMAP_FOREACH(i, globs, iterator)
1652 process_item(i);
1653
1654 HASHMAP_FOREACH(i, items, iterator)
1655 process_item(i);
1656
1657 finish:
1658 while ((i = hashmap_steal_first(items)))
1659 item_free(i);
1660
1661 while ((i = hashmap_steal_first(globs)))
1662 item_free(i);
1663
1664 hashmap_free(items);
1665 hashmap_free(globs);
1666
1667 free(arg_include_prefixes);
1668 free(arg_exclude_prefixes);
1669 free(arg_root);
1670
1671 set_free_free(unix_sockets);
1672
1673 mac_selinux_finish();
1674
1675 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1676 }