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