]> git.proxmox.com Git - systemd.git/blob - src/tmpfiles/tmpfiles.c
Imported Upstream version 218
[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 #include <sys/xattr.h>
43
44 #include "log.h"
45 #include "util.h"
46 #include "macro.h"
47 #include "missing.h"
48 #include "mkdir.h"
49 #include "path-util.h"
50 #include "strv.h"
51 #include "label.h"
52 #include "set.h"
53 #include "conf-files.h"
54 #include "capability.h"
55 #include "specifier.h"
56 #include "build.h"
57 #include "copy.h"
58
59 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
60 * them in the file system. This is intended to be used to create
61 * properly owned directories beneath /tmp, /var/tmp, /run, which are
62 * volatile and hence need to be recreated on bootup. */
63
64 typedef enum ItemType {
65 /* These ones take file names */
66 CREATE_FILE = 'f',
67 TRUNCATE_FILE = 'F',
68 CREATE_DIRECTORY = 'd',
69 TRUNCATE_DIRECTORY = 'D',
70 CREATE_FIFO = 'p',
71 CREATE_SYMLINK = 'L',
72 CREATE_CHAR_DEVICE = 'c',
73 CREATE_BLOCK_DEVICE = 'b',
74 COPY_FILES = 'C',
75 SET_XATTR = 't',
76
77 /* These ones take globs */
78 WRITE_FILE = 'w',
79 IGNORE_PATH = 'x',
80 IGNORE_DIRECTORY_PATH = 'X',
81 REMOVE_PATH = 'r',
82 RECURSIVE_REMOVE_PATH = 'R',
83 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
84 RELABEL_PATH = 'z',
85 RECURSIVE_RELABEL_PATH = 'Z',
86 } ItemType;
87
88 typedef struct Item {
89 ItemType type;
90
91 char *path;
92 char *argument;
93 char **xattrs;
94 uid_t uid;
95 gid_t gid;
96 mode_t mode;
97 usec_t age;
98
99 dev_t major_minor;
100
101 bool uid_set:1;
102 bool gid_set:1;
103 bool mode_set:1;
104 bool age_set:1;
105 bool mask_perms:1;
106
107 bool keep_first_level:1;
108
109 bool force:1;
110
111 bool done:1;
112 } Item;
113
114 static bool arg_create = false;
115 static bool arg_clean = false;
116 static bool arg_remove = false;
117 static bool arg_boot = false;
118
119 static char **arg_include_prefixes = NULL;
120 static char **arg_exclude_prefixes = NULL;
121 static char *arg_root = NULL;
122
123 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
124
125 #define MAX_DEPTH 256
126
127 static Hashmap *items = NULL, *globs = NULL;
128 static Set *unix_sockets = NULL;
129
130 static bool needs_glob(ItemType t) {
131 return IN_SET(t,
132 WRITE_FILE,
133 IGNORE_PATH,
134 IGNORE_DIRECTORY_PATH,
135 REMOVE_PATH,
136 RECURSIVE_REMOVE_PATH,
137 ADJUST_MODE,
138 RELABEL_PATH,
139 RECURSIVE_RELABEL_PATH);
140 }
141
142 static struct Item* find_glob(Hashmap *h, const char *match) {
143 Item *j;
144 Iterator i;
145
146 HASHMAP_FOREACH(j, h, i)
147 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
148 return j;
149
150 return NULL;
151 }
152
153 static void load_unix_sockets(void) {
154 _cleanup_fclose_ FILE *f = NULL;
155 char line[LINE_MAX];
156
157 if (unix_sockets)
158 return;
159
160 /* We maintain a cache of the sockets we found in
161 * /proc/net/unix to speed things up a little. */
162
163 unix_sockets = set_new(&string_hash_ops);
164 if (!unix_sockets)
165 return;
166
167 f = fopen("/proc/net/unix", "re");
168 if (!f)
169 return;
170
171 /* Skip header */
172 if (!fgets(line, sizeof(line), f))
173 goto fail;
174
175 for (;;) {
176 char *p, *s;
177 int k;
178
179 if (!fgets(line, sizeof(line), f))
180 break;
181
182 truncate_nl(line);
183
184 p = strchr(line, ':');
185 if (!p)
186 continue;
187
188 if (strlen(p) < 37)
189 continue;
190
191 p += 37;
192 p += strspn(p, WHITESPACE);
193 p += strcspn(p, WHITESPACE); /* skip one more word */
194 p += strspn(p, WHITESPACE);
195
196 if (*p != '/')
197 continue;
198
199 s = strdup(p);
200 if (!s)
201 goto fail;
202
203 path_kill_slashes(s);
204
205 k = set_consume(unix_sockets, s);
206 if (k < 0 && k != -EEXIST)
207 goto fail;
208 }
209
210 return;
211
212 fail:
213 set_free_free(unix_sockets);
214 unix_sockets = NULL;
215 }
216
217 static bool unix_socket_alive(const char *fn) {
218 assert(fn);
219
220 load_unix_sockets();
221
222 if (unix_sockets)
223 return !!set_get(unix_sockets, (char*) fn);
224
225 /* We don't know, so assume yes */
226 return true;
227 }
228
229 static int dir_is_mount_point(DIR *d, const char *subdir) {
230
231 union file_handle_union h = {
232 .handle.handle_bytes = MAX_HANDLE_SZ
233 };
234
235 int mount_id_parent, mount_id;
236 int r_p, r;
237
238 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
239 if (r_p < 0)
240 r_p = -errno;
241
242 h.handle.handle_bytes = MAX_HANDLE_SZ;
243 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
244 if (r < 0)
245 r = -errno;
246
247 /* got no handle; make no assumptions, return error */
248 if (r_p < 0 && r < 0)
249 return r_p;
250
251 /* got both handles; if they differ, it is a mount point */
252 if (r_p >= 0 && r >= 0)
253 return mount_id_parent != mount_id;
254
255 /* got only one handle; assume different mount points if one
256 * of both queries was not supported by the filesystem */
257 if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
258 return true;
259
260 /* return error */
261 if (r_p < 0)
262 return r_p;
263 return r;
264 }
265
266 static int dir_cleanup(
267 Item *i,
268 const char *p,
269 DIR *d,
270 const struct stat *ds,
271 usec_t cutoff,
272 dev_t rootdev,
273 bool mountpoint,
274 int maxdepth,
275 bool keep_this_level) {
276
277 struct dirent *dent;
278 struct timespec times[2];
279 bool deleted = false;
280 int r = 0;
281
282 while ((dent = readdir(d))) {
283 struct stat s;
284 usec_t age;
285 _cleanup_free_ char *sub_path = NULL;
286
287 if (streq(dent->d_name, ".") ||
288 streq(dent->d_name, ".."))
289 continue;
290
291 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
292 if (errno == ENOENT)
293 continue;
294
295 /* FUSE, NFS mounts, SELinux might return EACCES */
296 if (errno == EACCES)
297 log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
298 else
299 log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
300 r = -errno;
301 continue;
302 }
303
304 /* Stay on the same filesystem */
305 if (s.st_dev != rootdev)
306 continue;
307
308 /* Try to detect bind mounts of the same filesystem instance; they
309 * do not differ in device major/minors. This type of query is not
310 * supported on all kernels or filesystem types though. */
311 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
312 continue;
313
314 /* Do not delete read-only files owned by root */
315 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
316 continue;
317
318 sub_path = strjoin(p, "/", dent->d_name, NULL);
319 if (!sub_path) {
320 r = log_oom();
321 goto finish;
322 }
323
324 /* Is there an item configured for this path? */
325 if (hashmap_get(items, sub_path))
326 continue;
327
328 if (find_glob(globs, sub_path))
329 continue;
330
331 if (S_ISDIR(s.st_mode)) {
332
333 if (mountpoint &&
334 streq(dent->d_name, "lost+found") &&
335 s.st_uid == 0)
336 continue;
337
338 if (maxdepth <= 0)
339 log_warning("Reached max depth on %s.", sub_path);
340 else {
341 _cleanup_closedir_ DIR *sub_dir;
342 int q;
343
344 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
345 if (!sub_dir) {
346 if (errno != ENOENT) {
347 log_error_errno(errno, "opendir(%s/%s) failed: %m", p, dent->d_name);
348 r = -errno;
349 }
350
351 continue;
352 }
353
354 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
355 if (q < 0)
356 r = q;
357 }
358
359 /* Note: if you are wondering why we don't
360 * support the sticky bit for excluding
361 * directories from cleaning like we do it for
362 * other file system objects: well, the sticky
363 * bit already has a meaning for directories,
364 * so we don't want to overload that. */
365
366 if (keep_this_level)
367 continue;
368
369 /* Ignore ctime, we change it when deleting */
370 age = MAX(timespec_load(&s.st_mtim),
371 timespec_load(&s.st_atim));
372 if (age >= cutoff)
373 continue;
374
375 if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
376 log_debug("rmdir '%s'", sub_path);
377
378 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
379 if (errno != ENOENT && errno != ENOTEMPTY) {
380 log_error_errno(errno, "rmdir(%s): %m", sub_path);
381 r = -errno;
382 }
383 }
384 }
385
386 } else {
387 /* Skip files for which the sticky bit is
388 * set. These are semantics we define, and are
389 * unknown elsewhere. See XDG_RUNTIME_DIR
390 * specification for details. */
391 if (s.st_mode & S_ISVTX)
392 continue;
393
394 if (mountpoint && S_ISREG(s.st_mode)) {
395 if (streq(dent->d_name, ".journal") &&
396 s.st_uid == 0)
397 continue;
398
399 if (streq(dent->d_name, "aquota.user") ||
400 streq(dent->d_name, "aquota.group"))
401 continue;
402 }
403
404 /* Ignore sockets that are listed in /proc/net/unix */
405 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
406 continue;
407
408 /* Ignore device nodes */
409 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
410 continue;
411
412 /* Keep files on this level around if this is
413 * requested */
414 if (keep_this_level)
415 continue;
416
417 age = MAX3(timespec_load(&s.st_mtim),
418 timespec_load(&s.st_atim),
419 timespec_load(&s.st_ctim));
420
421 if (age >= cutoff)
422 continue;
423
424 log_debug("unlink '%s'", sub_path);
425
426 if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
427 if (errno != ENOENT) {
428 log_error_errno(errno, "unlink(%s): %m", sub_path);
429 r = -errno;
430 }
431 }
432
433 deleted = true;
434 }
435 }
436
437 finish:
438 if (deleted) {
439 /* Restore original directory timestamps */
440 times[0] = ds->st_atim;
441 times[1] = ds->st_mtim;
442
443 if (futimens(dirfd(d), times) < 0)
444 log_error_errno(errno, "utimensat(%s): %m", p);
445 }
446
447 return r;
448 }
449
450 static int item_set_perms(Item *i, const char *path) {
451 struct stat st;
452 bool st_valid;
453
454 assert(i);
455 assert(path);
456
457 st_valid = stat(path, &st) == 0;
458
459 /* not using i->path directly because it may be a glob */
460 if (i->mode_set) {
461 mode_t m = i->mode;
462
463 if (i->mask_perms && st_valid) {
464 if (!(st.st_mode & 0111))
465 m &= ~0111;
466 if (!(st.st_mode & 0222))
467 m &= ~0222;
468 if (!(st.st_mode & 0444))
469 m &= ~0444;
470 if (!S_ISDIR(st.st_mode))
471 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
472 }
473
474 if (!st_valid || m != (st.st_mode & 07777)) {
475 if (chmod(path, m) < 0)
476 return log_error_errno(errno, "chmod(%s) failed: %m", path);
477 }
478 }
479
480 if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
481 (i->uid_set || i->gid_set))
482 if (chown(path,
483 i->uid_set ? i->uid : UID_INVALID,
484 i->gid_set ? i->gid : GID_INVALID) < 0) {
485
486 log_error_errno(errno, "chown(%s) failed: %m", path);
487 return -errno;
488 }
489
490 return label_fix(path, false, false);
491 }
492
493 static int get_xattrs_from_arg(Item *i) {
494 char *xattr;
495 const char *p;
496 int r;
497
498 assert(i);
499
500 if (!i->argument) {
501 log_error("%s: Argument can't be empty!", i->path);
502 return -EBADMSG;
503 }
504 p = i->argument;
505
506 while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
507 _cleanup_free_ char *tmp = NULL, *name = NULL, *value = NULL;
508 r = split_pair(xattr, "=", &name, &value);
509 if (r < 0) {
510 log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
511 free(xattr);
512 continue;
513 }
514 free(xattr);
515 if (streq(name, "") || streq(value, "")) {
516 log_warning("Malformed xattr found: \"%s=%s\" - ignoring.", name, value);
517 continue;
518 }
519 tmp = unquote(value, "\"");
520 if (!tmp)
521 return log_oom();
522 free(value);
523 value = cunescape(tmp);
524 if (!value)
525 return log_oom();
526 if (strv_consume_pair(&i->xattrs, name, value) < 0)
527 return log_oom();
528 name = value = NULL;
529 }
530
531 return r;
532 }
533
534 static int item_set_xattrs(Item *i, const char *path) {
535 char **name, **value;
536
537 assert(i);
538 assert(path);
539
540 if (strv_isempty(i->xattrs))
541 return 0;
542
543 STRV_FOREACH_PAIR(name, value, i->xattrs) {
544 int n;
545 n = strlen(*value);
546 if (lsetxattr(path, *name, *value, n, 0) < 0) {
547 log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path);
548 return -errno;
549 }
550 }
551 return 0;
552 }
553
554 static int write_one_file(Item *i, const char *path) {
555 _cleanup_close_ int fd = -1;
556 int flags, r = 0;
557 struct stat st;
558
559 assert(i);
560 assert(path);
561
562 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
563 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
564
565 RUN_WITH_UMASK(0000) {
566 mac_selinux_create_file_prepare(path, S_IFREG);
567 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
568 mac_selinux_create_file_clear();
569 }
570
571 if (fd < 0) {
572 if (i->type == WRITE_FILE && errno == ENOENT)
573 return 0;
574
575 log_error_errno(errno, "Failed to create file %s: %m", path);
576 return -errno;
577 }
578
579 if (i->argument) {
580 _cleanup_free_ char *unescaped;
581 ssize_t n;
582 size_t l;
583
584 unescaped = cunescape(i->argument);
585 if (!unescaped)
586 return log_oom();
587
588 l = strlen(unescaped);
589 n = write(fd, unescaped, l);
590
591 if (n < 0 || (size_t) n < l) {
592 log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
593 return n < 0 ? n : -EIO;
594 }
595 }
596
597 fd = safe_close(fd);
598
599 if (stat(path, &st) < 0)
600 return log_error_errno(errno, "stat(%s) failed: %m", path);
601
602 if (!S_ISREG(st.st_mode)) {
603 log_error("%s is not a file.", path);
604 return -EEXIST;
605 }
606
607 r = item_set_perms(i, path);
608 if (r < 0)
609 return r;
610
611 r = item_set_xattrs(i, i->path);
612 if (r < 0)
613 return r;
614
615 return 0;
616 }
617
618 static int item_set_perms_children(Item *i, const char *path) {
619 _cleanup_closedir_ DIR *d;
620 int r = 0;
621
622 assert(i);
623 assert(path);
624
625 /* This returns the first error we run into, but nevertheless
626 * tries to go on */
627
628 d = opendir(path);
629 if (!d)
630 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
631
632 for (;;) {
633 _cleanup_free_ char *p = NULL;
634 struct dirent *de;
635 int q;
636
637 errno = 0;
638 de = readdir(d);
639 if (!de) {
640 if (errno != 0 && r == 0)
641 r = -errno;
642
643 break;
644 }
645
646 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
647 continue;
648
649 p = strjoin(path, "/", de->d_name, NULL);
650 if (!p)
651 return -ENOMEM;
652
653 q = item_set_perms(i, p);
654 if (q < 0 && q != -ENOENT && r == 0)
655 r = q;
656
657 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
658 q = item_set_perms_children(i, p);
659 if (q < 0 && r == 0)
660 r = q;
661 }
662 }
663
664 return r;
665 }
666
667 static int item_set_perms_recursive(Item *i, const char *path) {
668 int r, q;
669
670 assert(i);
671 assert(path);
672
673 r = item_set_perms(i, path);
674 if (r < 0)
675 return r;
676
677 q = item_set_perms_children(i, path);
678 if (q < 0 && r == 0)
679 r = q;
680
681 return r;
682 }
683
684 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
685 _cleanup_globfree_ glob_t g = {};
686 int r = 0, k;
687 char **fn;
688
689 errno = 0;
690 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
691 if (k != 0 && k != GLOB_NOMATCH) {
692 if (errno == 0)
693 errno = EIO;
694
695 log_error_errno(errno, "glob(%s) failed: %m", i->path);
696 return -errno;
697 }
698
699 STRV_FOREACH(fn, g.gl_pathv) {
700 k = action(i, *fn);
701 if (k < 0 && r == 0)
702 r = k;
703 }
704
705 return r;
706 }
707
708 static int create_item(Item *i) {
709 struct stat st;
710 int r = 0;
711
712 assert(i);
713
714 switch (i->type) {
715
716 case IGNORE_PATH:
717 case IGNORE_DIRECTORY_PATH:
718 case REMOVE_PATH:
719 case RECURSIVE_REMOVE_PATH:
720 return 0;
721
722 case CREATE_FILE:
723 case TRUNCATE_FILE:
724 r = write_one_file(i, i->path);
725 if (r < 0)
726 return r;
727 break;
728
729 case COPY_FILES:
730 r = copy_tree(i->argument, i->path, false);
731 if (r < 0) {
732 struct stat a, b;
733
734 if (r != -EEXIST)
735 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
736
737 if (stat(i->argument, &a) < 0)
738 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
739
740 if (stat(i->path, &b) < 0)
741 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
742
743 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
744 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
745 return 0;
746 }
747 }
748
749 r = item_set_perms(i, i->path);
750 if (r < 0)
751 return r;
752
753 break;
754
755 case WRITE_FILE:
756 r = glob_item(i, write_one_file);
757 if (r < 0)
758 return r;
759
760 break;
761
762 case TRUNCATE_DIRECTORY:
763 case CREATE_DIRECTORY:
764
765 RUN_WITH_UMASK(0000) {
766 mkdir_parents_label(i->path, 0755);
767 r = mkdir_label(i->path, i->mode);
768 }
769
770 if (r < 0) {
771 if (r != -EEXIST)
772 return log_error_errno(r, "Failed to create directory %s: %m", i->path);
773
774 if (stat(i->path, &st) < 0)
775 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
776
777 if (!S_ISDIR(st.st_mode)) {
778 log_debug("%s already exists and is not a directory.", i->path);
779 return 0;
780 }
781 }
782
783 r = item_set_perms(i, i->path);
784 if (r < 0)
785 return r;
786
787 r = item_set_xattrs(i, i->path);
788 if (r < 0)
789 return r;
790
791 break;
792
793 case CREATE_FIFO:
794
795 RUN_WITH_UMASK(0000) {
796 mac_selinux_create_file_prepare(i->path, S_IFIFO);
797 r = mkfifo(i->path, i->mode);
798 mac_selinux_create_file_clear();
799 }
800
801 if (r < 0) {
802 if (errno != EEXIST)
803 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
804
805 if (stat(i->path, &st) < 0)
806 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
807
808 if (!S_ISFIFO(st.st_mode)) {
809
810 if (i->force) {
811
812 RUN_WITH_UMASK(0000) {
813 mac_selinux_create_file_prepare(i->path, S_IFIFO);
814 r = mkfifo_atomic(i->path, i->mode);
815 mac_selinux_create_file_clear();
816 }
817
818 if (r < 0)
819 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
820 } else {
821 log_debug("%s is not a fifo.", i->path);
822 return 0;
823 }
824 }
825 }
826
827 r = item_set_perms(i, i->path);
828 if (r < 0)
829 return r;
830
831 r = item_set_xattrs(i, i->path);
832 if (r < 0)
833 return r;
834
835 break;
836
837 case CREATE_SYMLINK:
838
839 mac_selinux_create_file_prepare(i->path, S_IFLNK);
840 r = symlink(i->argument, i->path);
841 mac_selinux_create_file_clear();
842
843 if (r < 0) {
844 _cleanup_free_ char *x = NULL;
845
846 if (errno != EEXIST)
847 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
848
849 r = readlink_malloc(i->path, &x);
850 if (r < 0 || !streq(i->argument, x)) {
851
852 if (i->force) {
853 mac_selinux_create_file_prepare(i->path, S_IFLNK);
854 r = symlink_atomic(i->argument, i->path);
855 mac_selinux_create_file_clear();
856
857 if (r < 0)
858 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
859 } else {
860 log_debug("%s is not a symlink or does not point to the correct path.", i->path);
861 return 0;
862 }
863 }
864 }
865
866 r = item_set_xattrs(i, i->path);
867 if (r < 0)
868 return r;
869
870 break;
871
872 case CREATE_BLOCK_DEVICE:
873 case CREATE_CHAR_DEVICE: {
874 mode_t file_type;
875
876 if (have_effective_cap(CAP_MKNOD) == 0) {
877 /* In a container we lack CAP_MKNOD. We
878 shouldn't attempt to create the device node in
879 that case to avoid noise, and we don't support
880 virtualized devices in containers anyway. */
881
882 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
883 return 0;
884 }
885
886 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
887
888 RUN_WITH_UMASK(0000) {
889 mac_selinux_create_file_prepare(i->path, file_type);
890 r = mknod(i->path, i->mode | file_type, i->major_minor);
891 mac_selinux_create_file_clear();
892 }
893
894 if (r < 0) {
895 if (errno == EPERM) {
896 log_debug("We lack permissions, possibly because of cgroup configuration; "
897 "skipping creation of device node %s.", i->path);
898 return 0;
899 }
900
901 if (errno != EEXIST)
902 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
903
904 if (stat(i->path, &st) < 0)
905 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
906
907 if ((st.st_mode & S_IFMT) != file_type) {
908
909 if (i->force) {
910
911 RUN_WITH_UMASK(0000) {
912 mac_selinux_create_file_prepare(i->path, file_type);
913 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
914 mac_selinux_create_file_clear();
915 }
916
917 if (r < 0)
918 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
919 } else {
920 log_debug("%s is not a device node.", i->path);
921 return 0;
922 }
923 }
924 }
925
926 r = item_set_perms(i, i->path);
927 if (r < 0)
928 return r;
929
930 r = item_set_xattrs(i, i->path);
931 if (r < 0)
932 return r;
933
934 break;
935 }
936
937 case ADJUST_MODE:
938 case RELABEL_PATH:
939
940 r = glob_item(i, item_set_perms);
941 if (r < 0)
942 return r;
943 break;
944
945 case RECURSIVE_RELABEL_PATH:
946
947 r = glob_item(i, item_set_perms_recursive);
948 if (r < 0)
949 return r;
950 break;
951
952 case SET_XATTR:
953 r = item_set_xattrs(i, i->path);
954 if (r < 0)
955 return r;
956 break;
957 }
958
959 log_debug("%s created successfully.", i->path);
960
961 return 0;
962 }
963
964 static int remove_item_instance(Item *i, const char *instance) {
965 int r;
966
967 assert(i);
968
969 switch (i->type) {
970
971 case CREATE_FILE:
972 case TRUNCATE_FILE:
973 case CREATE_DIRECTORY:
974 case CREATE_FIFO:
975 case CREATE_SYMLINK:
976 case CREATE_BLOCK_DEVICE:
977 case CREATE_CHAR_DEVICE:
978 case IGNORE_PATH:
979 case IGNORE_DIRECTORY_PATH:
980 case ADJUST_MODE:
981 case RELABEL_PATH:
982 case RECURSIVE_RELABEL_PATH:
983 case WRITE_FILE:
984 case COPY_FILES:
985 case SET_XATTR:
986 break;
987
988 case REMOVE_PATH:
989 if (remove(instance) < 0 && errno != ENOENT)
990 return log_error_errno(errno, "remove(%s): %m", instance);
991
992 break;
993
994 case TRUNCATE_DIRECTORY:
995 case RECURSIVE_REMOVE_PATH:
996 /* FIXME: we probably should use dir_cleanup() here
997 * instead of rm_rf() so that 'x' is honoured. */
998 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
999 if (r < 0 && r != -ENOENT)
1000 return log_error_errno(r, "rm_rf(%s): %m", instance);
1001
1002 break;
1003 }
1004
1005 return 0;
1006 }
1007
1008 static int remove_item(Item *i) {
1009 int r = 0;
1010
1011 assert(i);
1012
1013 switch (i->type) {
1014
1015 case CREATE_FILE:
1016 case TRUNCATE_FILE:
1017 case CREATE_DIRECTORY:
1018 case CREATE_FIFO:
1019 case CREATE_SYMLINK:
1020 case CREATE_CHAR_DEVICE:
1021 case CREATE_BLOCK_DEVICE:
1022 case IGNORE_PATH:
1023 case IGNORE_DIRECTORY_PATH:
1024 case ADJUST_MODE:
1025 case RELABEL_PATH:
1026 case RECURSIVE_RELABEL_PATH:
1027 case WRITE_FILE:
1028 case COPY_FILES:
1029 case SET_XATTR:
1030 break;
1031
1032 case REMOVE_PATH:
1033 case TRUNCATE_DIRECTORY:
1034 case RECURSIVE_REMOVE_PATH:
1035 r = glob_item(i, remove_item_instance);
1036 break;
1037 }
1038
1039 return r;
1040 }
1041
1042 static int clean_item_instance(Item *i, const char* instance) {
1043 _cleanup_closedir_ DIR *d = NULL;
1044 struct stat s, ps;
1045 bool mountpoint;
1046 int r;
1047 usec_t cutoff, n;
1048
1049 assert(i);
1050
1051 if (!i->age_set)
1052 return 0;
1053
1054 n = now(CLOCK_REALTIME);
1055 if (n < i->age)
1056 return 0;
1057
1058 cutoff = n - i->age;
1059
1060 d = opendir(instance);
1061 if (!d) {
1062 if (errno == ENOENT || errno == ENOTDIR)
1063 return 0;
1064
1065 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1066 return -errno;
1067 }
1068
1069 if (fstat(dirfd(d), &s) < 0)
1070 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1071
1072 if (!S_ISDIR(s.st_mode)) {
1073 log_error("%s is not a directory.", i->path);
1074 return -ENOTDIR;
1075 }
1076
1077 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1078 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1079
1080 mountpoint = s.st_dev != ps.st_dev ||
1081 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1082
1083 r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1084 MAX_DEPTH, i->keep_first_level);
1085 return r;
1086 }
1087
1088 static int clean_item(Item *i) {
1089 int r = 0;
1090
1091 assert(i);
1092
1093 switch (i->type) {
1094 case CREATE_DIRECTORY:
1095 case TRUNCATE_DIRECTORY:
1096 case IGNORE_PATH:
1097 case COPY_FILES:
1098 clean_item_instance(i, i->path);
1099 break;
1100 case IGNORE_DIRECTORY_PATH:
1101 r = glob_item(i, clean_item_instance);
1102 break;
1103 default:
1104 break;
1105 }
1106
1107 return r;
1108 }
1109
1110 static int process_item(Item *i) {
1111 int r, q, p;
1112 _cleanup_free_ char *prefix = NULL;
1113
1114 assert(i);
1115
1116 if (i->done)
1117 return 0;
1118
1119 i->done = true;
1120
1121 prefix = malloc(strlen(i->path) + 1);
1122 if (!prefix)
1123 return log_oom();
1124
1125 PATH_FOREACH_PREFIX(prefix, i->path) {
1126 Item *j;
1127
1128 j = hashmap_get(items, prefix);
1129 if (j)
1130 process_item(j);
1131 }
1132
1133 r = arg_create ? create_item(i) : 0;
1134 q = arg_remove ? remove_item(i) : 0;
1135 p = arg_clean ? clean_item(i) : 0;
1136
1137 if (r < 0)
1138 return r;
1139
1140 if (q < 0)
1141 return q;
1142
1143 return p;
1144 }
1145
1146 static void item_free(Item *i) {
1147
1148 if (!i)
1149 return;
1150
1151 free(i->path);
1152 free(i->argument);
1153 strv_free(i->xattrs);
1154 free(i);
1155 }
1156
1157 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1158
1159 static bool item_equal(Item *a, Item *b) {
1160 assert(a);
1161 assert(b);
1162
1163 if (!streq_ptr(a->path, b->path))
1164 return false;
1165
1166 if (a->type != b->type)
1167 return false;
1168
1169 if (a->uid_set != b->uid_set ||
1170 (a->uid_set && a->uid != b->uid))
1171 return false;
1172
1173 if (a->gid_set != b->gid_set ||
1174 (a->gid_set && a->gid != b->gid))
1175 return false;
1176
1177 if (a->mode_set != b->mode_set ||
1178 (a->mode_set && a->mode != b->mode))
1179 return false;
1180
1181 if (a->age_set != b->age_set ||
1182 (a->age_set && a->age != b->age))
1183 return false;
1184
1185 if ((a->type == CREATE_FILE ||
1186 a->type == TRUNCATE_FILE ||
1187 a->type == WRITE_FILE ||
1188 a->type == CREATE_SYMLINK ||
1189 a->type == COPY_FILES) &&
1190 !streq_ptr(a->argument, b->argument))
1191 return false;
1192
1193 if ((a->type == CREATE_CHAR_DEVICE ||
1194 a->type == CREATE_BLOCK_DEVICE) &&
1195 a->major_minor != b->major_minor)
1196 return false;
1197
1198 return true;
1199 }
1200
1201 static bool should_include_path(const char *path) {
1202 char **prefix;
1203
1204 STRV_FOREACH(prefix, arg_exclude_prefixes)
1205 if (path_startswith(path, *prefix))
1206 return false;
1207
1208 STRV_FOREACH(prefix, arg_include_prefixes)
1209 if (path_startswith(path, *prefix))
1210 return true;
1211
1212 /* no matches, so we should include this path only if we
1213 * have no whitelist at all */
1214 return strv_length(arg_include_prefixes) == 0;
1215 }
1216
1217 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1218
1219 static const Specifier specifier_table[] = {
1220 { 'm', specifier_machine_id, NULL },
1221 { 'b', specifier_boot_id, NULL },
1222 { 'H', specifier_host_name, NULL },
1223 { 'v', specifier_kernel_release, NULL },
1224 {}
1225 };
1226
1227 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1228 _cleanup_(item_freep) Item *i = NULL;
1229 Item *existing;
1230 char type;
1231 Hashmap *h;
1232 int r, n = -1;
1233
1234 assert(fname);
1235 assert(line >= 1);
1236 assert(buffer);
1237
1238 r = sscanf(buffer,
1239 "%ms %ms %ms %ms %ms %ms %n",
1240 &action,
1241 &path,
1242 &mode,
1243 &user,
1244 &group,
1245 &age,
1246 &n);
1247 if (r < 2) {
1248 log_error("[%s:%u] Syntax error.", fname, line);
1249 return -EIO;
1250 }
1251
1252 if (isempty(action)) {
1253 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1254 return -EINVAL;
1255 }
1256
1257 if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1258 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1259 return -EINVAL;
1260 }
1261
1262 if (strchr(action+1, '!') && !arg_boot)
1263 return 0;
1264
1265 type = action[0];
1266
1267 i = new0(Item, 1);
1268 if (!i)
1269 return log_oom();
1270
1271 i->force = !!strchr(action+1, '+');
1272
1273 r = specifier_printf(path, specifier_table, NULL, &i->path);
1274 if (r < 0) {
1275 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1276 return r;
1277 }
1278
1279 if (n >= 0) {
1280 n += strspn(buffer+n, WHITESPACE);
1281 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1282 i->argument = unquote(buffer+n, "\"");
1283 if (!i->argument)
1284 return log_oom();
1285 }
1286 }
1287
1288 switch (type) {
1289
1290 case CREATE_FILE:
1291 case TRUNCATE_FILE:
1292 case CREATE_DIRECTORY:
1293 case TRUNCATE_DIRECTORY:
1294 case CREATE_FIFO:
1295 case IGNORE_PATH:
1296 case IGNORE_DIRECTORY_PATH:
1297 case REMOVE_PATH:
1298 case RECURSIVE_REMOVE_PATH:
1299 case ADJUST_MODE:
1300 case RELABEL_PATH:
1301 case RECURSIVE_RELABEL_PATH:
1302 break;
1303
1304 case CREATE_SYMLINK:
1305 if (!i->argument) {
1306 i->argument = strappend("/usr/share/factory", i->path);
1307 if (!i->argument)
1308 return log_oom();
1309 }
1310 break;
1311
1312 case WRITE_FILE:
1313 if (!i->argument) {
1314 log_error("[%s:%u] Write file requires argument.", fname, line);
1315 return -EBADMSG;
1316 }
1317 break;
1318
1319 case COPY_FILES:
1320 if (!i->argument) {
1321 i->argument = strappend("/usr/share/factory", i->path);
1322 if (!i->argument)
1323 return log_oom();
1324 }
1325
1326 if (!path_is_absolute(i->argument)) {
1327 log_error("[%s:%u] Source path is not absolute.", fname, line);
1328 return -EBADMSG;
1329 }
1330
1331 path_kill_slashes(i->argument);
1332 break;
1333
1334 case CREATE_CHAR_DEVICE:
1335 case CREATE_BLOCK_DEVICE: {
1336 unsigned major, minor;
1337
1338 if (!i->argument) {
1339 log_error("[%s:%u] Device file requires argument.", fname, line);
1340 return -EBADMSG;
1341 }
1342
1343 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1344 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1345 return -EBADMSG;
1346 }
1347
1348 i->major_minor = makedev(major, minor);
1349 break;
1350 }
1351
1352 case SET_XATTR:
1353 if (!i->argument) {
1354 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1355 return -EBADMSG;
1356 }
1357 r = get_xattrs_from_arg(i);
1358 if (r < 0)
1359 return r;
1360 break;
1361
1362 default:
1363 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1364 return -EBADMSG;
1365 }
1366
1367 i->type = type;
1368
1369 if (!path_is_absolute(i->path)) {
1370 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1371 return -EBADMSG;
1372 }
1373
1374 path_kill_slashes(i->path);
1375
1376 if (!should_include_path(i->path))
1377 return 0;
1378
1379 if (arg_root) {
1380 char *p;
1381
1382 p = strappend(arg_root, i->path);
1383 if (!p)
1384 return log_oom();
1385
1386 free(i->path);
1387 i->path = p;
1388 }
1389
1390 if (user && !streq(user, "-")) {
1391 const char *u = user;
1392
1393 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1394 if (r < 0) {
1395 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1396 return r;
1397 }
1398
1399 i->uid_set = true;
1400 }
1401
1402 if (group && !streq(group, "-")) {
1403 const char *g = group;
1404
1405 r = get_group_creds(&g, &i->gid);
1406 if (r < 0) {
1407 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1408 return r;
1409 }
1410
1411 i->gid_set = true;
1412 }
1413
1414 if (mode && !streq(mode, "-")) {
1415 const char *mm = mode;
1416 unsigned m;
1417
1418 if (*mm == '~') {
1419 i->mask_perms = true;
1420 mm++;
1421 }
1422
1423 if (sscanf(mm, "%o", &m) != 1) {
1424 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1425 return -ENOENT;
1426 }
1427
1428 i->mode = m;
1429 i->mode_set = true;
1430 } else
1431 i->mode =
1432 i->type == CREATE_DIRECTORY ||
1433 i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1434
1435 if (age && !streq(age, "-")) {
1436 const char *a = age;
1437
1438 if (*a == '~') {
1439 i->keep_first_level = true;
1440 a++;
1441 }
1442
1443 if (parse_sec(a, &i->age) < 0) {
1444 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1445 return -EBADMSG;
1446 }
1447
1448 i->age_set = true;
1449 }
1450
1451 h = needs_glob(i->type) ? globs : items;
1452
1453 existing = hashmap_get(h, i->path);
1454 if (existing) {
1455 if (i->type == SET_XATTR) {
1456 r = strv_extend_strv(&existing->xattrs, i->xattrs);
1457 if (r < 0)
1458 return log_oom();
1459 return 0;
1460 } else if (existing->type == SET_XATTR) {
1461 r = strv_extend_strv(&i->xattrs, existing->xattrs);
1462 if (r < 0)
1463 return log_oom();
1464 r = hashmap_replace(h, i->path, i);
1465 if (r < 0) {
1466 log_error("Failed to replace item for %s.", i->path);
1467 return r;
1468 }
1469 item_free(existing);
1470 } else {
1471 /* Two identical items are fine */
1472 if (!item_equal(existing, i))
1473 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1474 return 0;
1475 }
1476 } else {
1477 r = hashmap_put(h, i->path, i);
1478 if (r < 0) {
1479 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1480 return r;
1481 }
1482 }
1483
1484 i = NULL; /* avoid cleanup */
1485
1486 return 0;
1487 }
1488
1489 static void help(void) {
1490 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1491 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1492 " -h --help Show this help\n"
1493 " --version Show package version\n"
1494 " --create Create marked files/directories\n"
1495 " --clean Clean up marked directories\n"
1496 " --remove Remove marked files/directories\n"
1497 " --boot Execute actions only safe at boot\n"
1498 " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n"
1499 " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n"
1500 " --root=PATH Operate on an alternate filesystem root\n",
1501 program_invocation_short_name);
1502 }
1503
1504 static int parse_argv(int argc, char *argv[]) {
1505
1506 enum {
1507 ARG_VERSION = 0x100,
1508 ARG_CREATE,
1509 ARG_CLEAN,
1510 ARG_REMOVE,
1511 ARG_BOOT,
1512 ARG_PREFIX,
1513 ARG_EXCLUDE_PREFIX,
1514 ARG_ROOT,
1515 };
1516
1517 static const struct option options[] = {
1518 { "help", no_argument, NULL, 'h' },
1519 { "version", no_argument, NULL, ARG_VERSION },
1520 { "create", no_argument, NULL, ARG_CREATE },
1521 { "clean", no_argument, NULL, ARG_CLEAN },
1522 { "remove", no_argument, NULL, ARG_REMOVE },
1523 { "boot", no_argument, NULL, ARG_BOOT },
1524 { "prefix", required_argument, NULL, ARG_PREFIX },
1525 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1526 { "root", required_argument, NULL, ARG_ROOT },
1527 {}
1528 };
1529
1530 int c;
1531
1532 assert(argc >= 0);
1533 assert(argv);
1534
1535 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1536
1537 switch (c) {
1538
1539 case 'h':
1540 help();
1541 return 0;
1542
1543 case ARG_VERSION:
1544 puts(PACKAGE_STRING);
1545 puts(SYSTEMD_FEATURES);
1546 return 0;
1547
1548 case ARG_CREATE:
1549 arg_create = true;
1550 break;
1551
1552 case ARG_CLEAN:
1553 arg_clean = true;
1554 break;
1555
1556 case ARG_REMOVE:
1557 arg_remove = true;
1558 break;
1559
1560 case ARG_BOOT:
1561 arg_boot = true;
1562 break;
1563
1564 case ARG_PREFIX:
1565 if (strv_push(&arg_include_prefixes, optarg) < 0)
1566 return log_oom();
1567 break;
1568
1569 case ARG_EXCLUDE_PREFIX:
1570 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1571 return log_oom();
1572 break;
1573
1574 case ARG_ROOT:
1575 free(arg_root);
1576 arg_root = path_make_absolute_cwd(optarg);
1577 if (!arg_root)
1578 return log_oom();
1579
1580 path_kill_slashes(arg_root);
1581 break;
1582
1583 case '?':
1584 return -EINVAL;
1585
1586 default:
1587 assert_not_reached("Unhandled option");
1588 }
1589
1590 if (!arg_clean && !arg_create && !arg_remove) {
1591 log_error("You need to specify at least one of --clean, --create or --remove.");
1592 return -EINVAL;
1593 }
1594
1595 return 1;
1596 }
1597
1598 static int read_config_file(const char *fn, bool ignore_enoent) {
1599 _cleanup_fclose_ FILE *f = NULL;
1600 char line[LINE_MAX];
1601 Iterator iterator;
1602 unsigned v = 0;
1603 Item *i;
1604 int r;
1605
1606 assert(fn);
1607
1608 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1609 if (r < 0) {
1610 if (ignore_enoent && r == -ENOENT)
1611 return 0;
1612
1613 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1614 }
1615
1616 FOREACH_LINE(line, f, break) {
1617 char *l;
1618 int k;
1619
1620 v++;
1621
1622 l = strstrip(line);
1623 if (*l == '#' || *l == 0)
1624 continue;
1625
1626 k = parse_line(fn, v, l);
1627 if (k < 0 && r == 0)
1628 r = k;
1629 }
1630
1631 /* we have to determine age parameter for each entry of type X */
1632 HASHMAP_FOREACH(i, globs, iterator) {
1633 Iterator iter;
1634 Item *j, *candidate_item = NULL;
1635
1636 if (i->type != IGNORE_DIRECTORY_PATH)
1637 continue;
1638
1639 HASHMAP_FOREACH(j, items, iter) {
1640 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1641 continue;
1642
1643 if (path_equal(j->path, i->path)) {
1644 candidate_item = j;
1645 break;
1646 }
1647
1648 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1649 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1650 candidate_item = j;
1651 }
1652
1653 if (candidate_item && candidate_item->age_set) {
1654 i->age = candidate_item->age;
1655 i->age_set = true;
1656 }
1657 }
1658
1659 if (ferror(f)) {
1660 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1661 if (r == 0)
1662 r = -EIO;
1663 }
1664
1665 return r;
1666 }
1667
1668 int main(int argc, char *argv[]) {
1669 int r, k;
1670 Item *i;
1671 Iterator iterator;
1672
1673 r = parse_argv(argc, argv);
1674 if (r <= 0)
1675 goto finish;
1676
1677 log_set_target(LOG_TARGET_AUTO);
1678 log_parse_environment();
1679 log_open();
1680
1681 umask(0022);
1682
1683 mac_selinux_init(NULL);
1684
1685 items = hashmap_new(&string_hash_ops);
1686 globs = hashmap_new(&string_hash_ops);
1687
1688 if (!items || !globs) {
1689 r = log_oom();
1690 goto finish;
1691 }
1692
1693 r = 0;
1694
1695 if (optind < argc) {
1696 int j;
1697
1698 for (j = optind; j < argc; j++) {
1699 k = read_config_file(argv[j], false);
1700 if (k < 0 && r == 0)
1701 r = k;
1702 }
1703
1704 } else {
1705 _cleanup_strv_free_ char **files = NULL;
1706 char **f;
1707
1708 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1709 if (r < 0) {
1710 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1711 goto finish;
1712 }
1713
1714 STRV_FOREACH(f, files) {
1715 k = read_config_file(*f, true);
1716 if (k < 0 && r == 0)
1717 r = k;
1718 }
1719 }
1720
1721 HASHMAP_FOREACH(i, globs, iterator)
1722 process_item(i);
1723
1724 HASHMAP_FOREACH(i, items, iterator)
1725 process_item(i);
1726
1727 finish:
1728 while ((i = hashmap_steal_first(items)))
1729 item_free(i);
1730
1731 while ((i = hashmap_steal_first(globs)))
1732 item_free(i);
1733
1734 hashmap_free(items);
1735 hashmap_free(globs);
1736
1737 free(arg_include_prefixes);
1738 free(arg_exclude_prefixes);
1739 free(arg_root);
1740
1741 set_free_free(unix_sockets);
1742
1743 mac_selinux_finish();
1744
1745 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1746 }