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