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