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