]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/tmpfiles/tmpfiles.c
d8fcb4015544a691198f4dac5727ad815f73d7ac
[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
42 #include "log.h"
43 #include "util.h"
44 #include "mkdir.h"
45 #include "strv.h"
46 #include "label.h"
47 #include "set.h"
48
49 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
50 * them in the file system. This is intended to be used to create
51 * properly owned directories beneath /tmp, /var/tmp, /run, which are
52 * volatile and hence need to be recreated on bootup. */
53
54 typedef enum ItemType {
55 /* These ones take file names */
56 CREATE_FILE = 'f',
57 TRUNCATE_FILE = 'F',
58 WRITE_FILE = 'w',
59 CREATE_DIRECTORY = 'd',
60 TRUNCATE_DIRECTORY = 'D',
61 CREATE_FIFO = 'p',
62 CREATE_SYMLINK = 'L',
63 CREATE_CHAR_DEVICE = 'c',
64 CREATE_BLOCK_DEVICE = 'b',
65
66 /* These ones take globs */
67 IGNORE_PATH = 'x',
68 REMOVE_PATH = 'r',
69 RECURSIVE_REMOVE_PATH = 'R',
70 RELABEL_PATH = 'z',
71 RECURSIVE_RELABEL_PATH = 'Z'
72 } ItemType;
73
74 typedef struct Item {
75 ItemType type;
76
77 char *path;
78 char *argument;
79 uid_t uid;
80 gid_t gid;
81 mode_t mode;
82 usec_t age;
83
84 dev_t major_minor;
85
86 bool uid_set:1;
87 bool gid_set:1;
88 bool mode_set:1;
89 bool age_set:1;
90 } Item;
91
92 static Hashmap *items = NULL, *globs = NULL;
93 static Set *unix_sockets = NULL;
94
95 static bool arg_create = false;
96 static bool arg_clean = false;
97 static bool arg_remove = false;
98
99 static const char *arg_prefix = NULL;
100
101 #define MAX_DEPTH 256
102
103 static bool needs_glob(ItemType t) {
104 return t == IGNORE_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
105 }
106
107 static struct Item* find_glob(Hashmap *h, const char *match) {
108 Item *j;
109 Iterator i;
110
111 HASHMAP_FOREACH(j, h, i)
112 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
113 return j;
114
115 return NULL;
116 }
117
118 static void load_unix_sockets(void) {
119 FILE *f = NULL;
120 char line[LINE_MAX];
121
122 if (unix_sockets)
123 return;
124
125 /* We maintain a cache of the sockets we found in
126 * /proc/net/unix to speed things up a little. */
127
128 unix_sockets = set_new(string_hash_func, string_compare_func);
129 if (!unix_sockets)
130 return;
131
132 f = fopen("/proc/net/unix", "re");
133 if (!f)
134 return;
135
136 /* Skip header */
137 if (!fgets(line, sizeof(line), f))
138 goto fail;
139
140 for (;;) {
141 char *p, *s;
142 int k;
143
144 if (!fgets(line, sizeof(line), f))
145 break;
146
147 truncate_nl(line);
148
149 p = strchr(line, ':');
150 if (!p)
151 continue;
152
153 if (strlen(p) < 37)
154 continue;
155
156 p += 37;
157 p += strspn(p, WHITESPACE);
158 p += strcspn(p, WHITESPACE); /* skip one more word */
159 p += strspn(p, WHITESPACE);
160
161 if (*p != '/')
162 continue;
163
164 s = strdup(p);
165 if (!s)
166 goto fail;
167
168 path_kill_slashes(s);
169
170 k = set_put(unix_sockets, s);
171 if (k < 0) {
172 free(s);
173
174 if (k != -EEXIST)
175 goto fail;
176 }
177 }
178
179 fclose(f);
180 return;
181
182 fail:
183 set_free_free(unix_sockets);
184 unix_sockets = NULL;
185
186 if (f)
187 fclose(f);
188 }
189
190 static bool unix_socket_alive(const char *fn) {
191 assert(fn);
192
193 load_unix_sockets();
194
195 if (unix_sockets)
196 return !!set_get(unix_sockets, (char*) fn);
197
198 /* We don't know, so assume yes */
199 return true;
200 }
201
202 static int dir_cleanup(
203 const char *p,
204 DIR *d,
205 const struct stat *ds,
206 usec_t cutoff,
207 dev_t rootdev,
208 bool mountpoint,
209 int maxdepth)
210 {
211 struct dirent *dent;
212 struct timespec times[2];
213 bool deleted = false;
214 char *sub_path = NULL;
215 int r = 0;
216
217 while ((dent = readdir(d))) {
218 struct stat s;
219 usec_t age;
220
221 if (streq(dent->d_name, ".") ||
222 streq(dent->d_name, ".."))
223 continue;
224
225 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
226
227 if (errno != ENOENT) {
228 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
229 r = -errno;
230 }
231
232 continue;
233 }
234
235 /* Stay on the same filesystem */
236 if (s.st_dev != rootdev)
237 continue;
238
239 /* Do not delete read-only files owned by root */
240 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
241 continue;
242
243 free(sub_path);
244 sub_path = NULL;
245
246 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
247 log_error("Out of memory");
248 r = -ENOMEM;
249 goto finish;
250 }
251
252 /* Is there an item configured for this path? */
253 if (hashmap_get(items, sub_path))
254 continue;
255
256 if (find_glob(globs, sub_path))
257 continue;
258
259 if (S_ISDIR(s.st_mode)) {
260
261 if (mountpoint &&
262 streq(dent->d_name, "lost+found") &&
263 s.st_uid == 0)
264 continue;
265
266 if (maxdepth <= 0)
267 log_warning("Reached max depth on %s.", sub_path);
268 else {
269 DIR *sub_dir;
270 int q;
271
272 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
273 if (sub_dir == NULL) {
274 if (errno != ENOENT) {
275 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
276 r = -errno;
277 }
278
279 continue;
280 }
281
282 q = dir_cleanup(sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1);
283 closedir(sub_dir);
284
285 if (q < 0)
286 r = q;
287 }
288
289 /* Ignore ctime, we change it when deleting */
290 age = MAX(timespec_load(&s.st_mtim),
291 timespec_load(&s.st_atim));
292 if (age >= cutoff)
293 continue;
294
295 log_debug("rmdir '%s'\n", sub_path);
296
297 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
298 if (errno != ENOENT && errno != ENOTEMPTY) {
299 log_error("rmdir(%s): %m", sub_path);
300 r = -errno;
301 }
302 }
303
304 } else {
305 /* Skip files for which the sticky bit is
306 * set. These are semantics we define, and are
307 * unknown elsewhere. See XDG_RUNTIME_DIR
308 * specification for details. */
309 if (s.st_mode & S_ISVTX)
310 continue;
311
312 if (mountpoint && S_ISREG(s.st_mode)) {
313 if (streq(dent->d_name, ".journal") &&
314 s.st_uid == 0)
315 continue;
316
317 if (streq(dent->d_name, "aquota.user") ||
318 streq(dent->d_name, "aquota.group"))
319 continue;
320 }
321
322 /* Ignore sockets that are listed in /proc/net/unix */
323 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
324 continue;
325
326 /* Ignore device nodes */
327 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
328 continue;
329
330 age = MAX3(timespec_load(&s.st_mtim),
331 timespec_load(&s.st_atim),
332 timespec_load(&s.st_ctim));
333
334 if (age >= cutoff)
335 continue;
336
337 log_debug("unlink '%s'\n", sub_path);
338
339 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
340 if (errno != ENOENT) {
341 log_error("unlink(%s): %m", sub_path);
342 r = -errno;
343 }
344 }
345
346 deleted = true;
347 }
348 }
349
350 finish:
351 if (deleted) {
352 /* Restore original directory timestamps */
353 times[0] = ds->st_atim;
354 times[1] = ds->st_mtim;
355
356 if (futimens(dirfd(d), times) < 0)
357 log_error("utimensat(%s): %m", p);
358 }
359
360 free(sub_path);
361
362 return r;
363 }
364
365 static int clean_item(Item *i) {
366 DIR *d;
367 struct stat s, ps;
368 bool mountpoint;
369 int r;
370 usec_t cutoff, n;
371
372 assert(i);
373
374 if (i->type != CREATE_DIRECTORY &&
375 i->type != TRUNCATE_DIRECTORY &&
376 i->type != IGNORE_PATH)
377 return 0;
378
379 if (!i->age_set || i->age <= 0)
380 return 0;
381
382 n = now(CLOCK_REALTIME);
383 if (n < i->age)
384 return 0;
385
386 cutoff = n - i->age;
387
388 d = opendir(i->path);
389 if (!d) {
390 if (errno == ENOENT)
391 return 0;
392
393 log_error("Failed to open directory %s: %m", i->path);
394 return -errno;
395 }
396
397 if (fstat(dirfd(d), &s) < 0) {
398 log_error("stat(%s) failed: %m", i->path);
399 r = -errno;
400 goto finish;
401 }
402
403 if (!S_ISDIR(s.st_mode)) {
404 log_error("%s is not a directory.", i->path);
405 r = -ENOTDIR;
406 goto finish;
407 }
408
409 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
410 log_error("stat(%s/..) failed: %m", i->path);
411 r = -errno;
412 goto finish;
413 }
414
415 mountpoint = s.st_dev != ps.st_dev ||
416 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
417
418 r = dir_cleanup(i->path, d, &s, cutoff, s.st_dev, mountpoint, MAX_DEPTH);
419
420 finish:
421 if (d)
422 closedir(d);
423
424 return r;
425 }
426
427 static int item_set_perms(Item *i, const char *path) {
428 /* not using i->path directly because it may be a glob */
429 if (i->mode_set)
430 if (chmod(path, i->mode) < 0) {
431 log_error("chmod(%s) failed: %m", path);
432 return -errno;
433 }
434
435 if (i->uid_set || i->gid_set)
436 if (chown(path,
437 i->uid_set ? i->uid : (uid_t) -1,
438 i->gid_set ? i->gid : (gid_t) -1) < 0) {
439
440 log_error("chown(%s) failed: %m", path);
441 return -errno;
442 }
443
444 return label_fix(path, false);
445 }
446
447 static int recursive_relabel_children(Item *i, const char *path) {
448 DIR *d;
449 int ret = 0;
450
451 /* This returns the first error we run into, but nevertheless
452 * tries to go on */
453
454 d = opendir(path);
455 if (!d)
456 return errno == ENOENT ? 0 : -errno;
457
458 for (;;) {
459 struct dirent buf, *de;
460 bool is_dir;
461 int r;
462 char *entry_path;
463
464 r = readdir_r(d, &buf, &de);
465 if (r != 0) {
466 if (ret == 0)
467 ret = -r;
468 break;
469 }
470
471 if (!de)
472 break;
473
474 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
475 continue;
476
477 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
478 if (ret == 0)
479 ret = -ENOMEM;
480 continue;
481 }
482
483 if (de->d_type == DT_UNKNOWN) {
484 struct stat st;
485
486 if (lstat(entry_path, &st) < 0) {
487 if (ret == 0 && errno != ENOENT)
488 ret = -errno;
489 free(entry_path);
490 continue;
491 }
492
493 is_dir = S_ISDIR(st.st_mode);
494
495 } else
496 is_dir = de->d_type == DT_DIR;
497
498 r = item_set_perms(i, entry_path);
499 if (r < 0) {
500 if (ret == 0 && r != -ENOENT)
501 ret = r;
502 free(entry_path);
503 continue;
504 }
505
506 if (is_dir) {
507 r = recursive_relabel_children(i, entry_path);
508 if (r < 0 && ret == 0)
509 ret = r;
510 }
511
512 free(entry_path);
513 }
514
515 closedir(d);
516
517 return ret;
518 }
519
520 static int recursive_relabel(Item *i, const char *path) {
521 int r;
522 struct stat st;
523
524 r = item_set_perms(i, path);
525 if (r < 0)
526 return r;
527
528 if (lstat(path, &st) < 0)
529 return -errno;
530
531 if (S_ISDIR(st.st_mode))
532 r = recursive_relabel_children(i, path);
533
534 return r;
535 }
536
537 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
538 int r = 0, k;
539 glob_t g;
540 char **fn;
541
542 zero(g);
543
544 errno = 0;
545 if ((k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g)) != 0) {
546
547 if (k != GLOB_NOMATCH) {
548 if (errno != 0)
549 errno = EIO;
550
551 log_error("glob(%s) failed: %m", i->path);
552 return -errno;
553 }
554 }
555
556 STRV_FOREACH(fn, g.gl_pathv)
557 if ((k = action(i, *fn)) < 0)
558 r = k;
559
560 globfree(&g);
561 return r;
562 }
563
564 static int create_item(Item *i) {
565 int r, e;
566 mode_t u;
567 struct stat st;
568
569 assert(i);
570
571 switch (i->type) {
572
573 case IGNORE_PATH:
574 case REMOVE_PATH:
575 case RECURSIVE_REMOVE_PATH:
576 return 0;
577
578 case CREATE_FILE:
579 case TRUNCATE_FILE:
580 case WRITE_FILE: {
581 int fd, flags;
582
583 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
584 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
585
586 u = umask(0);
587 label_context_set(i->path, S_IFREG);
588 fd = open(i->path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
589 e = errno;
590 label_context_clear();
591 umask(u);
592 errno = e;
593
594 if (fd < 0) {
595 if (i->type == WRITE_FILE && errno == ENOENT)
596 break;
597
598 log_error("Failed to create file %s: %m", i->path);
599 return -errno;
600 }
601
602 if (i->argument) {
603 ssize_t n;
604 size_t l;
605 struct iovec iovec[2];
606 static const char new_line = '\n';
607
608 l = strlen(i->argument);
609
610 zero(iovec);
611 iovec[0].iov_base = i->argument;
612 iovec[0].iov_len = l;
613
614 iovec[1].iov_base = (void*) &new_line;
615 iovec[1].iov_len = 1;
616
617 n = writev(fd, iovec, 2);
618 if (n < 0 || (size_t) n != l+1) {
619 log_error("Failed to write file %s: %s", i->path, n < 0 ? strerror(-n) : "Short");
620 close_nointr_nofail(fd);
621 return n < 0 ? n : -EIO;
622 }
623 }
624
625 close_nointr_nofail(fd);
626
627 if (stat(i->path, &st) < 0) {
628 log_error("stat(%s) failed: %m", i->path);
629 return -errno;
630 }
631
632 if (!S_ISREG(st.st_mode)) {
633 log_error("%s is not a file.", i->path);
634 return -EEXIST;
635 }
636
637 r = item_set_perms(i, i->path);
638 if (r < 0)
639 return r;
640
641 break;
642 }
643
644 case TRUNCATE_DIRECTORY:
645 case CREATE_DIRECTORY:
646
647 u = umask(0);
648 mkdir_parents(i->path, 0755);
649 r = mkdir(i->path, i->mode);
650 umask(u);
651
652 if (r < 0 && errno != EEXIST) {
653 log_error("Failed to create directory %s: %m", i->path);
654 return -errno;
655 }
656
657 if (stat(i->path, &st) < 0) {
658 log_error("stat(%s) failed: %m", i->path);
659 return -errno;
660 }
661
662 if (!S_ISDIR(st.st_mode)) {
663 log_error("%s is not a directory.", i->path);
664 return -EEXIST;
665 }
666
667 r = item_set_perms(i, i->path);
668 if (r < 0)
669 return r;
670
671 break;
672
673 case CREATE_FIFO:
674
675 u = umask(0);
676 r = mkfifo(i->path, i->mode);
677 umask(u);
678
679 if (r < 0 && errno != EEXIST) {
680 log_error("Failed to create fifo %s: %m", i->path);
681 return -errno;
682 }
683
684 if (stat(i->path, &st) < 0) {
685 log_error("stat(%s) failed: %m", i->path);
686 return -errno;
687 }
688
689 if (!S_ISFIFO(st.st_mode)) {
690 log_error("%s is not a fifo.", i->path);
691 return -EEXIST;
692 }
693
694 r = item_set_perms(i, i->path);
695 if (r < 0)
696 return r;
697
698 break;
699
700 case CREATE_SYMLINK: {
701 char *x;
702
703 label_context_set(i->path, S_IFLNK);
704 r = symlink(i->argument, i->path);
705 e = errno;
706 label_context_clear();
707 errno = e;
708
709 if (r < 0 && errno != EEXIST) {
710 log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
711 return -errno;
712 }
713
714 r = readlink_malloc(i->path, &x);
715 if (r < 0) {
716 log_error("readlink(%s) failed: %s", i->path, strerror(-r));
717 return -errno;
718 }
719
720 if (!streq(i->argument, x)) {
721 free(x);
722 log_error("%s is not the right symlinks.", i->path);
723 return -EEXIST;
724 }
725
726 free(x);
727 break;
728 }
729
730 case CREATE_BLOCK_DEVICE:
731 case CREATE_CHAR_DEVICE: {
732
733 u = umask(0);
734 label_context_set(i->path, CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
735 r = mknod(i->path, i->mode | (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR), i->major_minor);
736 e = errno;
737 label_context_clear();
738 umask(u);
739 errno = e;
740
741 if (r < 0 && errno != EEXIST) {
742 log_error("Failed to create device node %s: %m", i->path);
743 return -errno;
744 }
745
746 if (stat(i->path, &st) < 0) {
747 log_error("stat(%s) failed: %m", i->path);
748 return -errno;
749 }
750
751 if (i->type == CREATE_BLOCK_DEVICE ? !S_ISBLK(st.st_mode) : !S_ISCHR(st.st_mode)) {
752 log_error("%s is not a device node.", i->path);
753 return -EEXIST;
754 }
755
756 r = item_set_perms(i, i->path);
757 if (r < 0)
758 return r;
759
760 break;
761 }
762
763 case RELABEL_PATH:
764
765 r = glob_item(i, item_set_perms);
766 if (r < 0)
767 return 0;
768 break;
769
770 case RECURSIVE_RELABEL_PATH:
771
772 r = glob_item(i, recursive_relabel);
773 if (r < 0)
774 return r;
775 }
776
777 log_debug("%s created successfully.", i->path);
778
779 return 0;
780 }
781
782 static int remove_item_instance(Item *i, const char *instance) {
783 int r;
784
785 assert(i);
786
787 switch (i->type) {
788
789 case CREATE_FILE:
790 case TRUNCATE_FILE:
791 case CREATE_DIRECTORY:
792 case CREATE_FIFO:
793 case CREATE_SYMLINK:
794 case CREATE_BLOCK_DEVICE:
795 case CREATE_CHAR_DEVICE:
796 case IGNORE_PATH:
797 case RELABEL_PATH:
798 case RECURSIVE_RELABEL_PATH:
799 case WRITE_FILE:
800 break;
801
802 case REMOVE_PATH:
803 if (remove(instance) < 0 && errno != ENOENT) {
804 log_error("remove(%s): %m", instance);
805 return -errno;
806 }
807
808 break;
809
810 case TRUNCATE_DIRECTORY:
811 case RECURSIVE_REMOVE_PATH:
812 r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
813 if (r < 0 && r != -ENOENT) {
814 log_error("rm_rf(%s): %s", instance, strerror(-r));
815 return r;
816 }
817
818 break;
819 }
820
821 return 0;
822 }
823
824 static int remove_item(Item *i) {
825 int r = 0;
826
827 assert(i);
828
829 switch (i->type) {
830
831 case CREATE_FILE:
832 case TRUNCATE_FILE:
833 case CREATE_DIRECTORY:
834 case CREATE_FIFO:
835 case CREATE_SYMLINK:
836 case CREATE_CHAR_DEVICE:
837 case CREATE_BLOCK_DEVICE:
838 case IGNORE_PATH:
839 case RELABEL_PATH:
840 case RECURSIVE_RELABEL_PATH:
841 case WRITE_FILE:
842 break;
843
844 case REMOVE_PATH:
845 case TRUNCATE_DIRECTORY:
846 case RECURSIVE_REMOVE_PATH:
847 r = glob_item(i, remove_item_instance);
848 break;
849 }
850
851 return r;
852 }
853
854 static int process_item(Item *i) {
855 int r, q, p;
856
857 assert(i);
858
859 r = arg_create ? create_item(i) : 0;
860 q = arg_remove ? remove_item(i) : 0;
861 p = arg_clean ? clean_item(i) : 0;
862
863 if (r < 0)
864 return r;
865
866 if (q < 0)
867 return q;
868
869 return p;
870 }
871
872 static void item_free(Item *i) {
873 assert(i);
874
875 free(i->path);
876 free(i->argument);
877 free(i);
878 }
879
880 static bool item_equal(Item *a, Item *b) {
881 assert(a);
882 assert(b);
883
884 if (!streq_ptr(a->path, b->path))
885 return false;
886
887 if (a->type != b->type)
888 return false;
889
890 if (a->uid_set != b->uid_set ||
891 (a->uid_set && a->uid != b->uid))
892 return false;
893
894 if (a->gid_set != b->gid_set ||
895 (a->gid_set && a->gid != b->gid))
896 return false;
897
898 if (a->mode_set != b->mode_set ||
899 (a->mode_set && a->mode != b->mode))
900 return false;
901
902 if (a->age_set != b->age_set ||
903 (a->age_set && a->age != b->age))
904 return false;
905
906 if ((a->type == CREATE_FILE ||
907 a->type == TRUNCATE_FILE ||
908 a->type == WRITE_FILE ||
909 a->type == CREATE_SYMLINK) &&
910 !streq_ptr(a->argument, b->argument))
911 return false;
912
913 if ((a->type == CREATE_CHAR_DEVICE ||
914 a->type == CREATE_BLOCK_DEVICE) &&
915 a->major_minor != b->major_minor)
916 return false;
917
918 return true;
919 }
920
921 static int parse_line(const char *fname, unsigned line, const char *buffer) {
922 Item *i, *existing;
923 char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
924 char type;
925 Hashmap *h;
926 int r, n = -1;
927
928 assert(fname);
929 assert(line >= 1);
930 assert(buffer);
931
932 i = new0(Item, 1);
933 if (!i) {
934 log_error("Out of memory");
935 return -ENOMEM;
936 }
937
938 if (sscanf(buffer,
939 "%c "
940 "%ms "
941 "%ms "
942 "%ms "
943 "%ms "
944 "%ms "
945 "%n",
946 &type,
947 &i->path,
948 &mode,
949 &user,
950 &group,
951 &age,
952 &n) < 2) {
953 log_error("[%s:%u] Syntax error.", fname, line);
954 r = -EIO;
955 goto finish;
956 }
957
958 if (n >= 0) {
959 n += strspn(buffer+n, WHITESPACE);
960 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
961 i->argument = unquote(buffer+n, "\"");
962 if (!i->argument) {
963 log_error("Out of memory");
964 return -ENOMEM;
965 }
966 }
967 }
968
969 switch(type) {
970
971 case CREATE_FILE:
972 case TRUNCATE_FILE:
973 case CREATE_DIRECTORY:
974 case TRUNCATE_DIRECTORY:
975 case CREATE_FIFO:
976 case IGNORE_PATH:
977 case REMOVE_PATH:
978 case RECURSIVE_REMOVE_PATH:
979 case RELABEL_PATH:
980 case RECURSIVE_RELABEL_PATH:
981 break;
982
983 case CREATE_SYMLINK:
984 if (!i->argument) {
985 log_error("[%s:%u] Symlink file requires argument.", fname, line);
986 r = -EBADMSG;
987 goto finish;
988 }
989 break;
990
991 case WRITE_FILE:
992 if (!i->argument) {
993 log_error("[%s:%u] Write file requires argument.", fname, line);
994 r = -EBADMSG;
995 goto finish;
996 }
997 break;
998
999 case CREATE_CHAR_DEVICE:
1000 case CREATE_BLOCK_DEVICE: {
1001 unsigned major, minor;
1002
1003 if (!i->argument) {
1004 log_error("[%s:%u] Device file requires argument.", fname, line);
1005 r = -EBADMSG;
1006 goto finish;
1007 }
1008
1009 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1010 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1011 r = -EBADMSG;
1012 goto finish;
1013 }
1014
1015 i->major_minor = makedev(major, minor);
1016 break;
1017 }
1018
1019 default:
1020 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1021 r = -EBADMSG;
1022 goto finish;
1023 }
1024
1025 i->type = type;
1026
1027 if (!path_is_absolute(i->path)) {
1028 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1029 r = -EBADMSG;
1030 goto finish;
1031 }
1032
1033 path_kill_slashes(i->path);
1034
1035 if (arg_prefix && !path_startswith(i->path, arg_prefix)) {
1036 r = 0;
1037 goto finish;
1038 }
1039
1040 if (user && !streq(user, "-")) {
1041 const char *u = user;
1042
1043 r = get_user_creds(&u, &i->uid, NULL, NULL);
1044 if (r < 0) {
1045 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1046 goto finish;
1047 }
1048
1049 i->uid_set = true;
1050 }
1051
1052 if (group && !streq(group, "-")) {
1053 const char *g = group;
1054
1055 r = get_group_creds(&g, &i->gid);
1056 if (r < 0) {
1057 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1058 goto finish;
1059 }
1060
1061 i->gid_set = true;
1062 }
1063
1064 if (mode && !streq(mode, "-")) {
1065 unsigned m;
1066
1067 if (sscanf(mode, "%o", &m) != 1) {
1068 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1069 r = -ENOENT;
1070 goto finish;
1071 }
1072
1073 i->mode = m;
1074 i->mode_set = true;
1075 } else
1076 i->mode =
1077 i->type == CREATE_DIRECTORY ||
1078 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1079
1080 if (age && !streq(age, "-")) {
1081 if (parse_usec(age, &i->age) < 0) {
1082 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1083 r = -EBADMSG;
1084 goto finish;
1085 }
1086
1087 i->age_set = true;
1088 }
1089
1090 h = needs_glob(i->type) ? globs : items;
1091
1092 existing = hashmap_get(h, i->path);
1093 if (existing) {
1094
1095 /* Two identical items are fine */
1096 if (!item_equal(existing, i))
1097 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1098
1099 r = 0;
1100 goto finish;
1101 }
1102
1103 r = hashmap_put(h, i->path, i);
1104 if (r < 0) {
1105 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1106 goto finish;
1107 }
1108
1109 i = NULL;
1110 r = 0;
1111
1112 finish:
1113 free(user);
1114 free(group);
1115 free(mode);
1116 free(age);
1117
1118 if (i)
1119 item_free(i);
1120
1121 return r;
1122 }
1123
1124 static int help(void) {
1125
1126 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1127 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1128 " -h --help Show this help\n"
1129 " --create Create marked files/directories\n"
1130 " --clean Clean up marked directories\n"
1131 " --remove Remove marked files/directories\n"
1132 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n",
1133 program_invocation_short_name);
1134
1135 return 0;
1136 }
1137
1138 static int parse_argv(int argc, char *argv[]) {
1139
1140 enum {
1141 ARG_CREATE,
1142 ARG_CLEAN,
1143 ARG_REMOVE,
1144 ARG_PREFIX
1145 };
1146
1147 static const struct option options[] = {
1148 { "help", no_argument, NULL, 'h' },
1149 { "create", no_argument, NULL, ARG_CREATE },
1150 { "clean", no_argument, NULL, ARG_CLEAN },
1151 { "remove", no_argument, NULL, ARG_REMOVE },
1152 { "prefix", required_argument, NULL, ARG_PREFIX },
1153 { NULL, 0, NULL, 0 }
1154 };
1155
1156 int c;
1157
1158 assert(argc >= 0);
1159 assert(argv);
1160
1161 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1162
1163 switch (c) {
1164
1165 case 'h':
1166 help();
1167 return 0;
1168
1169 case ARG_CREATE:
1170 arg_create = true;
1171 break;
1172
1173 case ARG_CLEAN:
1174 arg_clean = true;
1175 break;
1176
1177 case ARG_REMOVE:
1178 arg_remove = true;
1179 break;
1180
1181 case ARG_PREFIX:
1182 arg_prefix = optarg;
1183 break;
1184
1185 case '?':
1186 return -EINVAL;
1187
1188 default:
1189 log_error("Unknown option code %c", c);
1190 return -EINVAL;
1191 }
1192 }
1193
1194 if (!arg_clean && !arg_create && !arg_remove) {
1195 log_error("You need to specify at least one of --clean, --create or --remove.");
1196 return -EINVAL;
1197 }
1198
1199 return 1;
1200 }
1201
1202 static int read_config_file(const char *fn, bool ignore_enoent) {
1203 FILE *f;
1204 unsigned v = 0;
1205 int r = 0;
1206
1207 assert(fn);
1208
1209 f = fopen(fn, "re");
1210 if (!f) {
1211
1212 if (ignore_enoent && errno == ENOENT)
1213 return 0;
1214
1215 log_error("Failed to open %s: %m", fn);
1216 return -errno;
1217 }
1218
1219 log_debug("apply: %s\n", fn);
1220 for (;;) {
1221 char line[LINE_MAX], *l;
1222 int k;
1223
1224 if (!(fgets(line, sizeof(line), f)))
1225 break;
1226
1227 v++;
1228
1229 l = strstrip(line);
1230 if (*l == '#' || *l == 0)
1231 continue;
1232
1233 if ((k = parse_line(fn, v, l)) < 0)
1234 if (r == 0)
1235 r = k;
1236 }
1237
1238 if (ferror(f)) {
1239 log_error("Failed to read from file %s: %m", fn);
1240 if (r == 0)
1241 r = -EIO;
1242 }
1243
1244 fclose(f);
1245
1246 return r;
1247 }
1248
1249 int main(int argc, char *argv[]) {
1250 int r;
1251 Item *i;
1252 Iterator iterator;
1253
1254 r = parse_argv(argc, argv);
1255 if (r <= 0)
1256 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1257
1258 log_set_target(LOG_TARGET_AUTO);
1259 log_parse_environment();
1260 log_open();
1261
1262 umask(0022);
1263
1264 label_init(NULL);
1265
1266 items = hashmap_new(string_hash_func, string_compare_func);
1267 globs = hashmap_new(string_hash_func, string_compare_func);
1268
1269 if (!items || !globs) {
1270 log_error("Out of memory");
1271 r = EXIT_FAILURE;
1272 goto finish;
1273 }
1274
1275 r = EXIT_SUCCESS;
1276
1277 if (optind < argc) {
1278 int j;
1279
1280 for (j = optind; j < argc; j++)
1281 if (read_config_file(argv[j], false) < 0)
1282 r = EXIT_FAILURE;
1283
1284 } else {
1285 char **files, **f;
1286
1287 r = conf_files_list(&files, ".conf",
1288 "/etc/tmpfiles.d",
1289 "/run/tmpfiles.d",
1290 "/usr/local/lib/tmpfiles.d",
1291 "/usr/lib/tmpfiles.d",
1292 NULL);
1293 if (r < 0) {
1294 log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1295 r = EXIT_FAILURE;
1296 goto finish;
1297 }
1298
1299 STRV_FOREACH(f, files) {
1300 if (read_config_file(*f, true) < 0)
1301 r = EXIT_FAILURE;
1302 }
1303
1304 strv_free(files);
1305 }
1306
1307 HASHMAP_FOREACH(i, globs, iterator)
1308 process_item(i);
1309
1310 HASHMAP_FOREACH(i, items, iterator)
1311 process_item(i);
1312
1313 finish:
1314 while ((i = hashmap_steal_first(items)))
1315 item_free(i);
1316
1317 while ((i = hashmap_steal_first(globs)))
1318 item_free(i);
1319
1320 hashmap_free(items);
1321 hashmap_free(globs);
1322
1323 set_free_free(unix_sockets);
1324
1325 label_finish();
1326
1327 return r;
1328 }