]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/tmpfiles/tmpfiles.c
8cf327a15f5d275d87be3d13c32fffcb4850584d
[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 Copyright 2015 Zbigniew Jędrzejewski-Szmek
8
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <dirent.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <fnmatch.h>
27 #include <getopt.h>
28 #include <glob.h>
29 #include <limits.h>
30 #include <linux/fs.h>
31 #include <stdbool.h>
32 #include <stddef.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/xattr.h>
38 #include <time.h>
39 #include <unistd.h>
40
41 #include "acl-util.h"
42 #include "btrfs-util.h"
43 #include "capability.h"
44 #include "chattr-util.h"
45 #include "conf-files.h"
46 #include "copy.h"
47 #include "escape.h"
48 #include "fd-util.h"
49 #include "fileio.h"
50 #include "formats-util.h"
51 #include "io-util.h"
52 #include "label.h"
53 #include "log.h"
54 #include "macro.h"
55 #include "missing.h"
56 #include "mkdir.h"
57 #include "parse-util.h"
58 #include "path-util.h"
59 #include "rm-rf.h"
60 #include "selinux-util.h"
61 #include "set.h"
62 #include "specifier.h"
63 #include "string-util.h"
64 #include "strv.h"
65 #include "user-util.h"
66 #include "util.h"
67
68 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
69 * them in the file system. This is intended to be used to create
70 * properly owned directories beneath /tmp, /var/tmp, /run, which are
71 * volatile and hence need to be recreated on bootup. */
72
73 typedef enum ItemType {
74 /* These ones take file names */
75 CREATE_FILE = 'f',
76 TRUNCATE_FILE = 'F',
77 CREATE_DIRECTORY = 'd',
78 TRUNCATE_DIRECTORY = 'D',
79 CREATE_SUBVOLUME = 'v',
80 CREATE_SUBVOLUME_INHERIT_QUOTA = 'q',
81 CREATE_SUBVOLUME_NEW_QUOTA = 'Q',
82 CREATE_FIFO = 'p',
83 CREATE_SYMLINK = 'L',
84 CREATE_CHAR_DEVICE = 'c',
85 CREATE_BLOCK_DEVICE = 'b',
86 COPY_FILES = 'C',
87
88 /* These ones take globs */
89 WRITE_FILE = 'w',
90 SET_XATTR = 't',
91 RECURSIVE_SET_XATTR = 'T',
92 SET_ACL = 'a',
93 RECURSIVE_SET_ACL = 'A',
94 SET_ATTRIBUTE = 'h',
95 RECURSIVE_SET_ATTRIBUTE = 'H',
96 IGNORE_PATH = 'x',
97 IGNORE_DIRECTORY_PATH = 'X',
98 REMOVE_PATH = 'r',
99 RECURSIVE_REMOVE_PATH = 'R',
100 RELABEL_PATH = 'z',
101 RECURSIVE_RELABEL_PATH = 'Z',
102 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
103 } ItemType;
104
105 typedef struct Item {
106 ItemType type;
107
108 char *path;
109 char *argument;
110 char **xattrs;
111 #ifdef HAVE_ACL
112 acl_t acl_access;
113 acl_t acl_default;
114 #endif
115 uid_t uid;
116 gid_t gid;
117 mode_t mode;
118 usec_t age;
119
120 dev_t major_minor;
121 unsigned attribute_value;
122 unsigned attribute_mask;
123
124 bool uid_set:1;
125 bool gid_set:1;
126 bool mode_set:1;
127 bool age_set:1;
128 bool mask_perms:1;
129 bool attribute_set:1;
130
131 bool keep_first_level:1;
132
133 bool force:1;
134
135 bool done:1;
136 } Item;
137
138 typedef struct ItemArray {
139 Item *items;
140 size_t count;
141 size_t size;
142 } ItemArray;
143
144 static bool arg_create = false;
145 static bool arg_clean = false;
146 static bool arg_remove = false;
147 static bool arg_boot = false;
148
149 static char **arg_include_prefixes = NULL;
150 static char **arg_exclude_prefixes = NULL;
151 static char *arg_root = NULL;
152
153 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
154
155 #define MAX_DEPTH 256
156
157 static OrderedHashmap *items = NULL, *globs = NULL;
158 static Set *unix_sockets = NULL;
159
160 static const Specifier specifier_table[] = {
161 { 'm', specifier_machine_id, NULL },
162 { 'b', specifier_boot_id, NULL },
163 { 'H', specifier_host_name, NULL },
164 { 'v', specifier_kernel_release, NULL },
165 {}
166 };
167
168 static bool needs_glob(ItemType t) {
169 return IN_SET(t,
170 WRITE_FILE,
171 IGNORE_PATH,
172 IGNORE_DIRECTORY_PATH,
173 REMOVE_PATH,
174 RECURSIVE_REMOVE_PATH,
175 ADJUST_MODE,
176 RELABEL_PATH,
177 RECURSIVE_RELABEL_PATH,
178 SET_XATTR,
179 RECURSIVE_SET_XATTR,
180 SET_ACL,
181 RECURSIVE_SET_ACL,
182 SET_ATTRIBUTE,
183 RECURSIVE_SET_ATTRIBUTE);
184 }
185
186 static bool takes_ownership(ItemType t) {
187 return IN_SET(t,
188 CREATE_FILE,
189 TRUNCATE_FILE,
190 CREATE_DIRECTORY,
191 TRUNCATE_DIRECTORY,
192 CREATE_SUBVOLUME,
193 CREATE_SUBVOLUME_INHERIT_QUOTA,
194 CREATE_SUBVOLUME_NEW_QUOTA,
195 CREATE_FIFO,
196 CREATE_SYMLINK,
197 CREATE_CHAR_DEVICE,
198 CREATE_BLOCK_DEVICE,
199 COPY_FILES,
200 WRITE_FILE,
201 IGNORE_PATH,
202 IGNORE_DIRECTORY_PATH,
203 REMOVE_PATH,
204 RECURSIVE_REMOVE_PATH);
205 }
206
207 static struct Item* find_glob(OrderedHashmap *h, const char *match) {
208 ItemArray *j;
209 Iterator i;
210
211 ORDERED_HASHMAP_FOREACH(j, h, i) {
212 unsigned n;
213
214 for (n = 0; n < j->count; n++) {
215 Item *item = j->items + n;
216
217 if (fnmatch(item->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
218 return item;
219 }
220 }
221
222 return NULL;
223 }
224
225 static void load_unix_sockets(void) {
226 _cleanup_fclose_ FILE *f = NULL;
227 char line[LINE_MAX];
228
229 if (unix_sockets)
230 return;
231
232 /* We maintain a cache of the sockets we found in
233 * /proc/net/unix to speed things up a little. */
234
235 unix_sockets = set_new(&string_hash_ops);
236 if (!unix_sockets)
237 return;
238
239 f = fopen("/proc/net/unix", "re");
240 if (!f)
241 return;
242
243 /* Skip header */
244 if (!fgets(line, sizeof(line), f))
245 goto fail;
246
247 for (;;) {
248 char *p, *s;
249 int k;
250
251 if (!fgets(line, sizeof(line), f))
252 break;
253
254 truncate_nl(line);
255
256 p = strchr(line, ':');
257 if (!p)
258 continue;
259
260 if (strlen(p) < 37)
261 continue;
262
263 p += 37;
264 p += strspn(p, WHITESPACE);
265 p += strcspn(p, WHITESPACE); /* skip one more word */
266 p += strspn(p, WHITESPACE);
267
268 if (*p != '/')
269 continue;
270
271 s = strdup(p);
272 if (!s)
273 goto fail;
274
275 path_kill_slashes(s);
276
277 k = set_consume(unix_sockets, s);
278 if (k < 0 && k != -EEXIST)
279 goto fail;
280 }
281
282 return;
283
284 fail:
285 set_free_free(unix_sockets);
286 unix_sockets = NULL;
287 }
288
289 static bool unix_socket_alive(const char *fn) {
290 assert(fn);
291
292 load_unix_sockets();
293
294 if (unix_sockets)
295 return !!set_get(unix_sockets, (char*) fn);
296
297 /* We don't know, so assume yes */
298 return true;
299 }
300
301 static int dir_is_mount_point(DIR *d, const char *subdir) {
302
303 union file_handle_union h = FILE_HANDLE_INIT;
304 int mount_id_parent, mount_id;
305 int r_p, r;
306
307 r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
308 if (r_p < 0)
309 r_p = -errno;
310
311 h.handle.handle_bytes = MAX_HANDLE_SZ;
312 r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
313 if (r < 0)
314 r = -errno;
315
316 /* got no handle; make no assumptions, return error */
317 if (r_p < 0 && r < 0)
318 return r_p;
319
320 /* got both handles; if they differ, it is a mount point */
321 if (r_p >= 0 && r >= 0)
322 return mount_id_parent != mount_id;
323
324 /* got only one handle; assume different mount points if one
325 * of both queries was not supported by the filesystem */
326 if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
327 return true;
328
329 /* return error */
330 if (r_p < 0)
331 return r_p;
332 return r;
333 }
334
335 static DIR* xopendirat_nomod(int dirfd, const char *path) {
336 DIR *dir;
337
338 dir = xopendirat(dirfd, path, O_NOFOLLOW|O_NOATIME);
339 if (dir)
340 return dir;
341
342 log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m", dirfd == AT_FDCWD ? "" : "sub", path);
343 if (errno != EPERM)
344 return NULL;
345
346 dir = xopendirat(dirfd, path, O_NOFOLLOW);
347 if (!dir)
348 log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m", dirfd == AT_FDCWD ? "" : "sub", path);
349
350 return dir;
351 }
352
353 static DIR* opendir_nomod(const char *path) {
354 return xopendirat_nomod(AT_FDCWD, path);
355 }
356
357 static int dir_cleanup(
358 Item *i,
359 const char *p,
360 DIR *d,
361 const struct stat *ds,
362 usec_t cutoff,
363 dev_t rootdev,
364 bool mountpoint,
365 int maxdepth,
366 bool keep_this_level) {
367
368 struct dirent *dent;
369 struct timespec times[2];
370 bool deleted = false;
371 int r = 0;
372
373 while ((dent = readdir(d))) {
374 struct stat s;
375 usec_t age;
376 _cleanup_free_ char *sub_path = NULL;
377
378 if (STR_IN_SET(dent->d_name, ".", ".."))
379 continue;
380
381 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
382 if (errno == ENOENT)
383 continue;
384
385 /* FUSE, NFS mounts, SELinux might return EACCES */
386 if (errno == EACCES)
387 log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
388 else
389 log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
390 r = -errno;
391 continue;
392 }
393
394 /* Stay on the same filesystem */
395 if (s.st_dev != rootdev) {
396 log_debug("Ignoring \"%s/%s\": different filesystem.", p, dent->d_name);
397 continue;
398 }
399
400 /* Try to detect bind mounts of the same filesystem instance; they
401 * do not differ in device major/minors. This type of query is not
402 * supported on all kernels or filesystem types though. */
403 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0) {
404 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
405 p, dent->d_name);
406 continue;
407 }
408
409 /* Do not delete read-only files owned by root */
410 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR)) {
411 log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p, dent->d_name);
412 continue;
413 }
414
415 sub_path = strjoin(p, "/", dent->d_name, NULL);
416 if (!sub_path) {
417 r = log_oom();
418 goto finish;
419 }
420
421 /* Is there an item configured for this path? */
422 if (ordered_hashmap_get(items, sub_path)) {
423 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path);
424 continue;
425 }
426
427 if (find_glob(globs, sub_path)) {
428 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path);
429 continue;
430 }
431
432 if (S_ISDIR(s.st_mode)) {
433
434 if (mountpoint &&
435 streq(dent->d_name, "lost+found") &&
436 s.st_uid == 0) {
437 log_debug("Ignoring \"%s\".", sub_path);
438 continue;
439 }
440
441 if (maxdepth <= 0)
442 log_warning("Reached max depth on \"%s\".", sub_path);
443 else {
444 _cleanup_closedir_ DIR *sub_dir;
445 int q;
446
447 sub_dir = xopendirat_nomod(dirfd(d), dent->d_name);
448 if (!sub_dir) {
449 if (errno != ENOENT)
450 r = log_error_errno(errno, "opendir(%s) failed: %m", sub_path);
451
452 continue;
453 }
454
455 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
456 if (q < 0)
457 r = q;
458 }
459
460 /* Note: if you are wondering why we don't
461 * support the sticky bit for excluding
462 * directories from cleaning like we do it for
463 * other file system objects: well, the sticky
464 * bit already has a meaning for directories,
465 * so we don't want to overload that. */
466
467 if (keep_this_level) {
468 log_debug("Keeping \"%s\".", sub_path);
469 continue;
470 }
471
472 /* Ignore ctime, we change it when deleting */
473 age = timespec_load(&s.st_mtim);
474 if (age >= cutoff) {
475 char a[FORMAT_TIMESTAMP_MAX];
476 /* Follows spelling in stat(1). */
477 log_debug("Directory \"%s\": modify time %s is too new.",
478 sub_path,
479 format_timestamp_us(a, sizeof(a), age));
480 continue;
481 }
482
483 age = timespec_load(&s.st_atim);
484 if (age >= cutoff) {
485 char a[FORMAT_TIMESTAMP_MAX];
486 log_debug("Directory \"%s\": access time %s is too new.",
487 sub_path,
488 format_timestamp_us(a, sizeof(a), age));
489 continue;
490 }
491
492 log_debug("Removing directory \"%s\".", sub_path);
493 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0)
494 if (errno != ENOENT && errno != ENOTEMPTY) {
495 log_error_errno(errno, "rmdir(%s): %m", sub_path);
496 r = -errno;
497 }
498
499 } else {
500 /* Skip files for which the sticky bit is
501 * set. These are semantics we define, and are
502 * unknown elsewhere. See XDG_RUNTIME_DIR
503 * specification for details. */
504 if (s.st_mode & S_ISVTX) {
505 log_debug("Skipping \"%s\": sticky bit set.", sub_path);
506 continue;
507 }
508
509 if (mountpoint && S_ISREG(s.st_mode))
510 if (s.st_uid == 0 && STR_IN_SET(dent->d_name,
511 ".journal",
512 "aquota.user",
513 "aquota.group")) {
514 log_debug("Skipping \"%s\".", sub_path);
515 continue;
516 }
517
518 /* Ignore sockets that are listed in /proc/net/unix */
519 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path)) {
520 log_debug("Skipping \"%s\": live socket.", sub_path);
521 continue;
522 }
523
524 /* Ignore device nodes */
525 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode)) {
526 log_debug("Skipping \"%s\": a device.", sub_path);
527 continue;
528 }
529
530 /* Keep files on this level around if this is
531 * requested */
532 if (keep_this_level) {
533 log_debug("Keeping \"%s\".", sub_path);
534 continue;
535 }
536
537 age = timespec_load(&s.st_mtim);
538 if (age >= cutoff) {
539 char a[FORMAT_TIMESTAMP_MAX];
540 /* Follows spelling in stat(1). */
541 log_debug("File \"%s\": modify time %s is too new.",
542 sub_path,
543 format_timestamp_us(a, sizeof(a), age));
544 continue;
545 }
546
547 age = timespec_load(&s.st_atim);
548 if (age >= cutoff) {
549 char a[FORMAT_TIMESTAMP_MAX];
550 log_debug("File \"%s\": access time %s is too new.",
551 sub_path,
552 format_timestamp_us(a, sizeof(a), age));
553 continue;
554 }
555
556 age = timespec_load(&s.st_ctim);
557 if (age >= cutoff) {
558 char a[FORMAT_TIMESTAMP_MAX];
559 log_debug("File \"%s\": change time %s is too new.",
560 sub_path,
561 format_timestamp_us(a, sizeof(a), age));
562 continue;
563 }
564
565 log_debug("unlink \"%s\"", sub_path);
566
567 if (unlinkat(dirfd(d), dent->d_name, 0) < 0)
568 if (errno != ENOENT)
569 r = log_error_errno(errno, "unlink(%s): %m", sub_path);
570
571 deleted = true;
572 }
573 }
574
575 finish:
576 if (deleted) {
577 usec_t age1, age2;
578 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
579
580 /* Restore original directory timestamps */
581 times[0] = ds->st_atim;
582 times[1] = ds->st_mtim;
583
584 age1 = timespec_load(&ds->st_atim);
585 age2 = timespec_load(&ds->st_mtim);
586 log_debug("Restoring access and modification time on \"%s\": %s, %s",
587 p,
588 format_timestamp_us(a, sizeof(a), age1),
589 format_timestamp_us(b, sizeof(b), age2));
590 if (futimens(dirfd(d), times) < 0)
591 log_error_errno(errno, "utimensat(%s): %m", p);
592 }
593
594 return r;
595 }
596
597 static int path_set_perms(Item *i, const char *path) {
598 _cleanup_close_ int fd = -1;
599 struct stat st;
600
601 assert(i);
602 assert(path);
603
604 /* We open the file with O_PATH here, to make the operation
605 * somewhat atomic. Also there's unfortunately no fchmodat()
606 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
607 * O_PATH. */
608
609 fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME);
610 if (fd < 0)
611 return log_error_errno(errno, "Adjusting owner and mode for %s failed: %m", path);
612
613 if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0)
614 return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
615
616 if (S_ISLNK(st.st_mode))
617 log_debug("Skipping mode an owner fix for symlink %s.", path);
618 else {
619 char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
620 xsprintf(fn, "/proc/self/fd/%i", fd);
621
622 /* not using i->path directly because it may be a glob */
623 if (i->mode_set) {
624 mode_t m = i->mode;
625
626 if (i->mask_perms) {
627 if (!(st.st_mode & 0111))
628 m &= ~0111;
629 if (!(st.st_mode & 0222))
630 m &= ~0222;
631 if (!(st.st_mode & 0444))
632 m &= ~0444;
633 if (!S_ISDIR(st.st_mode))
634 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
635 }
636
637 if (m == (st.st_mode & 07777))
638 log_debug("\"%s\" has right mode %o", path, st.st_mode);
639 else {
640 log_debug("chmod \"%s\" to mode %o", path, m);
641 if (chmod(fn, m) < 0)
642 return log_error_errno(errno, "chmod(%s) failed: %m", path);
643 }
644 }
645
646 if ((i->uid != st.st_uid || i->gid != st.st_gid) &&
647 (i->uid_set || i->gid_set)) {
648 log_debug("chown \"%s\" to "UID_FMT"."GID_FMT,
649 path,
650 i->uid_set ? i->uid : UID_INVALID,
651 i->gid_set ? i->gid : GID_INVALID);
652 if (chown(fn,
653 i->uid_set ? i->uid : UID_INVALID,
654 i->gid_set ? i->gid : GID_INVALID) < 0)
655 return log_error_errno(errno, "chown(%s) failed: %m", path);
656 }
657 }
658
659 fd = safe_close(fd);
660
661 return label_fix(path, false, false);
662 }
663
664 static int parse_xattrs_from_arg(Item *i) {
665 const char *p;
666 int r;
667
668 assert(i);
669 assert(i->argument);
670
671 p = i->argument;
672
673 for (;;) {
674 _cleanup_free_ char *name = NULL, *value = NULL, *xattr = NULL, *xattr_replaced = NULL;
675
676 r = extract_first_word(&p, &xattr, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
677 if (r < 0)
678 log_warning_errno(r, "Failed to parse extended attribute '%s', ignoring: %m", p);
679 if (r <= 0)
680 break;
681
682 r = specifier_printf(xattr, specifier_table, NULL, &xattr_replaced);
683 if (r < 0)
684 return log_error_errno(r, "Failed to replace specifiers in extended attribute '%s': %m", xattr);
685
686 r = split_pair(xattr_replaced, "=", &name, &value);
687 if (r < 0) {
688 log_warning_errno(r, "Failed to parse extended attribute, ignoring: %s", xattr);
689 continue;
690 }
691
692 if (isempty(name) || isempty(value)) {
693 log_warning("Malformed extended attribute found, ignoring: %s", xattr);
694 continue;
695 }
696
697 if (strv_push_pair(&i->xattrs, name, value) < 0)
698 return log_oom();
699
700 name = value = NULL;
701 }
702
703 return 0;
704 }
705
706 static int path_set_xattrs(Item *i, const char *path) {
707 char **name, **value;
708
709 assert(i);
710 assert(path);
711
712 STRV_FOREACH_PAIR(name, value, i->xattrs) {
713 int n;
714
715 n = strlen(*value);
716 log_debug("Setting extended attribute '%s=%s' on %s.", *name, *value, path);
717 if (lsetxattr(path, *name, *value, n, 0) < 0) {
718 log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path);
719 return -errno;
720 }
721 }
722 return 0;
723 }
724
725 static int parse_acls_from_arg(Item *item) {
726 #ifdef HAVE_ACL
727 int r;
728
729 assert(item);
730
731 /* If force (= modify) is set, we will not modify the acl
732 * afterwards, so the mask can be added now if necessary. */
733
734 r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force);
735 if (r < 0)
736 log_warning_errno(r, "Failed to parse ACL \"%s\": %m. Ignoring", item->argument);
737 #else
738 log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring");
739 #endif
740
741 return 0;
742 }
743
744 #ifdef HAVE_ACL
745 static int path_set_acl(const char *path, const char *pretty, acl_type_t type, acl_t acl, bool modify) {
746 _cleanup_(acl_free_charpp) char *t = NULL;
747 _cleanup_(acl_freep) acl_t dup = NULL;
748 int r;
749
750 /* Returns 0 for success, positive error if already warned,
751 * negative error otherwise. */
752
753 if (modify) {
754 r = acls_for_file(path, type, acl, &dup);
755 if (r < 0)
756 return r;
757
758 r = calc_acl_mask_if_needed(&dup);
759 if (r < 0)
760 return r;
761 } else {
762 dup = acl_dup(acl);
763 if (!dup)
764 return -errno;
765
766 /* the mask was already added earlier if needed */
767 }
768
769 r = add_base_acls_if_needed(&dup, path);
770 if (r < 0)
771 return r;
772
773 t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE);
774 log_debug("Setting %s ACL %s on %s.",
775 type == ACL_TYPE_ACCESS ? "access" : "default",
776 strna(t), pretty);
777
778 r = acl_set_file(path, type, dup);
779 if (r < 0)
780 /* Return positive to indicate we already warned */
781 return -log_error_errno(errno,
782 "Setting %s ACL \"%s\" on %s failed: %m",
783 type == ACL_TYPE_ACCESS ? "access" : "default",
784 strna(t), pretty);
785
786 return 0;
787 }
788 #endif
789
790 static int path_set_acls(Item *item, const char *path) {
791 int r = 0;
792 #ifdef HAVE_ACL
793 char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
794 _cleanup_close_ int fd = -1;
795 struct stat st;
796
797 assert(item);
798 assert(path);
799
800 fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME);
801 if (fd < 0)
802 return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path);
803
804 if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0)
805 return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
806
807 if (S_ISLNK(st.st_mode)) {
808 log_debug("Skipping ACL fix for symlink %s.", path);
809 return 0;
810 }
811
812 xsprintf(fn, "/proc/self/fd/%i", fd);
813
814 if (item->acl_access)
815 r = path_set_acl(fn, path, ACL_TYPE_ACCESS, item->acl_access, item->force);
816
817 if (r == 0 && item->acl_default)
818 r = path_set_acl(fn, path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
819
820 if (r > 0)
821 return -r; /* already warned */
822 else if (r == -EOPNOTSUPP) {
823 log_debug_errno(r, "ACLs not supported by file system at %s", path);
824 return 0;
825 } else if (r < 0)
826 log_error_errno(r, "ACL operation on \"%s\" failed: %m", path);
827 #endif
828 return r;
829 }
830
831 #define ATTRIBUTES_ALL \
832 (FS_NOATIME_FL | \
833 FS_SYNC_FL | \
834 FS_DIRSYNC_FL | \
835 FS_APPEND_FL | \
836 FS_COMPR_FL | \
837 FS_NODUMP_FL | \
838 FS_EXTENT_FL | \
839 FS_IMMUTABLE_FL | \
840 FS_JOURNAL_DATA_FL | \
841 FS_SECRM_FL | \
842 FS_UNRM_FL | \
843 FS_NOTAIL_FL | \
844 FS_TOPDIR_FL | \
845 FS_NOCOW_FL)
846
847 static int parse_attribute_from_arg(Item *item) {
848
849 static const struct {
850 char character;
851 unsigned value;
852 } attributes[] = {
853 { 'A', FS_NOATIME_FL }, /* do not update atime */
854 { 'S', FS_SYNC_FL }, /* Synchronous updates */
855 { 'D', FS_DIRSYNC_FL }, /* dirsync behaviour (directories only) */
856 { 'a', FS_APPEND_FL }, /* writes to file may only append */
857 { 'c', FS_COMPR_FL }, /* Compress file */
858 { 'd', FS_NODUMP_FL }, /* do not dump file */
859 { 'e', FS_EXTENT_FL }, /* Top of directory hierarchies*/
860 { 'i', FS_IMMUTABLE_FL }, /* Immutable file */
861 { 'j', FS_JOURNAL_DATA_FL }, /* Reserved for ext3 */
862 { 's', FS_SECRM_FL }, /* Secure deletion */
863 { 'u', FS_UNRM_FL }, /* Undelete */
864 { 't', FS_NOTAIL_FL }, /* file tail should not be merged */
865 { 'T', FS_TOPDIR_FL }, /* Top of directory hierarchies*/
866 { 'C', FS_NOCOW_FL }, /* Do not cow file */
867 };
868
869 enum {
870 MODE_ADD,
871 MODE_DEL,
872 MODE_SET
873 } mode = MODE_ADD;
874
875 unsigned value = 0, mask = 0;
876 const char *p;
877
878 assert(item);
879
880 p = item->argument;
881 if (p) {
882 if (*p == '+') {
883 mode = MODE_ADD;
884 p++;
885 } else if (*p == '-') {
886 mode = MODE_DEL;
887 p++;
888 } else if (*p == '=') {
889 mode = MODE_SET;
890 p++;
891 }
892 }
893
894 if (isempty(p) && mode != MODE_SET) {
895 log_error("Setting file attribute on '%s' needs an attribute specification.", item->path);
896 return -EINVAL;
897 }
898
899 for (; p && *p ; p++) {
900 unsigned i, v;
901
902 for (i = 0; i < ELEMENTSOF(attributes); i++)
903 if (*p == attributes[i].character)
904 break;
905
906 if (i >= ELEMENTSOF(attributes)) {
907 log_error("Unknown file attribute '%c' on '%s'.", *p, item->path);
908 return -EINVAL;
909 }
910
911 v = attributes[i].value;
912
913 if (mode == MODE_ADD || mode == MODE_SET)
914 value |= v;
915 else
916 value &= ~v;
917
918 mask |= v;
919 }
920
921 if (mode == MODE_SET)
922 mask |= ATTRIBUTES_ALL;
923
924 assert(mask != 0);
925
926 item->attribute_mask = mask;
927 item->attribute_value = value;
928 item->attribute_set = true;
929
930 return 0;
931 }
932
933 static int path_set_attribute(Item *item, const char *path) {
934 _cleanup_close_ int fd = -1;
935 struct stat st;
936 unsigned f;
937 int r;
938
939 if (!item->attribute_set || item->attribute_mask == 0)
940 return 0;
941
942 fd = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOATIME|O_NOFOLLOW);
943 if (fd < 0) {
944 if (errno == ELOOP)
945 return log_error_errno(errno, "Skipping file attributes adjustment on symlink %s.", path);
946
947 return log_error_errno(errno, "Cannot open '%s': %m", path);
948 }
949
950 if (fstat(fd, &st) < 0)
951 return log_error_errno(errno, "Cannot stat '%s': %m", path);
952
953 /* Issuing the file attribute ioctls on device nodes is not
954 * safe, as that will be delivered to the drivers, not the
955 * file system containing the device node. */
956 if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
957 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path);
958 return -EINVAL;
959 }
960
961 f = item->attribute_value & item->attribute_mask;
962
963 /* Mask away directory-specific flags */
964 if (!S_ISDIR(st.st_mode))
965 f &= ~FS_DIRSYNC_FL;
966
967 r = chattr_fd(fd, f, item->attribute_mask);
968 if (r < 0)
969 log_full_errno(r == -ENOTTY ? LOG_DEBUG : LOG_WARNING,
970 r,
971 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
972 path, item->attribute_value, item->attribute_mask);
973
974 return 0;
975 }
976
977 static int write_one_file(Item *i, const char *path) {
978 _cleanup_close_ int fd = -1;
979 int flags, r = 0;
980 struct stat st;
981
982 assert(i);
983 assert(path);
984
985 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
986 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
987
988 RUN_WITH_UMASK(0000) {
989 mac_selinux_create_file_prepare(path, S_IFREG);
990 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
991 mac_selinux_create_file_clear();
992 }
993
994 if (fd < 0) {
995 if (i->type == WRITE_FILE && errno == ENOENT) {
996 log_debug_errno(errno, "Not writing \"%s\": %m", path);
997 return 0;
998 }
999
1000 r = -errno;
1001 if (!i->argument && errno == EROFS && stat(path, &st) == 0 &&
1002 (i->type == CREATE_FILE || st.st_size == 0))
1003 goto check_mode;
1004
1005 return log_error_errno(r, "Failed to create file %s: %m", path);
1006 }
1007
1008 if (i->argument) {
1009 _cleanup_free_ char *unescaped = NULL, *replaced = NULL;
1010
1011 log_debug("%s to \"%s\".", i->type == CREATE_FILE ? "Appending" : "Writing", path);
1012
1013 r = cunescape(i->argument, 0, &unescaped);
1014 if (r < 0)
1015 return log_error_errno(r, "Failed to unescape parameter to write: %s", i->argument);
1016
1017 r = specifier_printf(unescaped, specifier_table, NULL, &replaced);
1018 if (r < 0)
1019 return log_error_errno(r, "Failed to replace specifiers in parameter to write '%s': %m", unescaped);
1020
1021 r = loop_write(fd, replaced, strlen(replaced), false);
1022 if (r < 0)
1023 return log_error_errno(r, "Failed to write file \"%s\": %m", path);
1024 } else
1025 log_debug("\"%s\" has been created.", path);
1026
1027 fd = safe_close(fd);
1028
1029 if (stat(path, &st) < 0)
1030 return log_error_errno(errno, "stat(%s) failed: %m", path);
1031
1032 check_mode:
1033 if (!S_ISREG(st.st_mode)) {
1034 log_error("%s is not a file.", path);
1035 return -EEXIST;
1036 }
1037
1038 r = path_set_perms(i, path);
1039 if (r < 0)
1040 return r;
1041
1042 return 0;
1043 }
1044
1045 typedef int (*action_t)(Item *, const char *);
1046
1047 static int item_do_children(Item *i, const char *path, action_t action) {
1048 _cleanup_closedir_ DIR *d;
1049 int r = 0;
1050
1051 assert(i);
1052 assert(path);
1053
1054 /* This returns the first error we run into, but nevertheless
1055 * tries to go on */
1056
1057 d = opendir_nomod(path);
1058 if (!d)
1059 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
1060
1061 for (;;) {
1062 _cleanup_free_ char *p = NULL;
1063 struct dirent *de;
1064 int q;
1065
1066 errno = 0;
1067 de = readdir(d);
1068 if (!de) {
1069 if (errno != 0 && r == 0)
1070 r = -errno;
1071
1072 break;
1073 }
1074
1075 if (STR_IN_SET(de->d_name, ".", ".."))
1076 continue;
1077
1078 p = strjoin(path, "/", de->d_name, NULL);
1079 if (!p)
1080 return -ENOMEM;
1081
1082 q = action(i, p);
1083 if (q < 0 && q != -ENOENT && r == 0)
1084 r = q;
1085
1086 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
1087 q = item_do_children(i, p, action);
1088 if (q < 0 && r == 0)
1089 r = q;
1090 }
1091 }
1092
1093 return r;
1094 }
1095
1096 static int glob_item(Item *i, action_t action, bool recursive) {
1097 _cleanup_globfree_ glob_t g = {
1098 .gl_closedir = (void (*)(void *)) closedir,
1099 .gl_readdir = (struct dirent *(*)(void *)) readdir,
1100 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
1101 .gl_lstat = lstat,
1102 .gl_stat = stat,
1103 };
1104 int r = 0, k;
1105 char **fn;
1106
1107 errno = 0;
1108 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE|GLOB_ALTDIRFUNC, NULL, &g);
1109 if (k != 0 && k != GLOB_NOMATCH)
1110 return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
1111
1112 STRV_FOREACH(fn, g.gl_pathv) {
1113 k = action(i, *fn);
1114 if (k < 0 && r == 0)
1115 r = k;
1116
1117 if (recursive) {
1118 k = item_do_children(i, *fn, action);
1119 if (k < 0 && r == 0)
1120 r = k;
1121 }
1122 }
1123
1124 return r;
1125 }
1126
1127 typedef enum {
1128 CREATION_NORMAL,
1129 CREATION_EXISTING,
1130 CREATION_FORCE,
1131 _CREATION_MODE_MAX,
1132 _CREATION_MODE_INVALID = -1
1133 } CreationMode;
1134
1135 static const char *creation_mode_verb_table[_CREATION_MODE_MAX] = {
1136 [CREATION_NORMAL] = "Created",
1137 [CREATION_EXISTING] = "Found existing",
1138 [CREATION_FORCE] = "Created replacement",
1139 };
1140
1141 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
1142
1143 static int create_item(Item *i) {
1144 _cleanup_free_ char *resolved = NULL;
1145 struct stat st;
1146 int r = 0;
1147 CreationMode creation;
1148
1149 assert(i);
1150
1151 log_debug("Running create action for entry %c %s", (char) i->type, i->path);
1152
1153 switch (i->type) {
1154
1155 case IGNORE_PATH:
1156 case IGNORE_DIRECTORY_PATH:
1157 case REMOVE_PATH:
1158 case RECURSIVE_REMOVE_PATH:
1159 return 0;
1160
1161 case CREATE_FILE:
1162 case TRUNCATE_FILE:
1163 r = write_one_file(i, i->path);
1164 if (r < 0)
1165 return r;
1166 break;
1167
1168 case COPY_FILES: {
1169 r = specifier_printf(i->argument, specifier_table, NULL, &resolved);
1170 if (r < 0)
1171 return log_error_errno(r, "Failed to substitute specifiers in copy source %s: %m", i->argument);
1172
1173 log_debug("Copying tree \"%s\" to \"%s\".", resolved, i->path);
1174 r = copy_tree(resolved, i->path, false);
1175
1176 if (r == -EROFS && stat(i->path, &st) == 0)
1177 r = -EEXIST;
1178
1179 if (r < 0) {
1180 struct stat a, b;
1181
1182 if (r != -EEXIST)
1183 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
1184
1185 if (stat(resolved, &a) < 0)
1186 return log_error_errno(errno, "stat(%s) failed: %m", resolved);
1187
1188 if (stat(i->path, &b) < 0)
1189 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1190
1191 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
1192 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
1193 return 0;
1194 }
1195 }
1196
1197 r = path_set_perms(i, i->path);
1198 if (r < 0)
1199 return r;
1200
1201 break;
1202
1203 case WRITE_FILE:
1204 r = glob_item(i, write_one_file, false);
1205 if (r < 0)
1206 return r;
1207
1208 break;
1209
1210 case CREATE_DIRECTORY:
1211 case TRUNCATE_DIRECTORY:
1212 case CREATE_SUBVOLUME:
1213 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1214 case CREATE_SUBVOLUME_NEW_QUOTA:
1215
1216 RUN_WITH_UMASK(0000)
1217 mkdir_parents_label(i->path, 0755);
1218
1219 if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) {
1220 RUN_WITH_UMASK((~i->mode) & 0777)
1221 r = btrfs_subvol_make(i->path);
1222 } else
1223 r = 0;
1224
1225 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY)
1226 RUN_WITH_UMASK(0000)
1227 r = mkdir_label(i->path, i->mode);
1228
1229 if (r < 0) {
1230 int k;
1231
1232 if (r != -EEXIST && r != -EROFS)
1233 return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path);
1234
1235 k = is_dir(i->path, false);
1236 if (k == -ENOENT && r == -EROFS)
1237 return log_error_errno(r, "%s does not exist and cannot be created as the file system is read-only.", i->path);
1238 if (k < 0)
1239 return log_error_errno(k, "Failed to check if %s exists: %m", i->path);
1240 if (!k) {
1241 log_warning("\"%s\" already exists and is not a directory.", i->path);
1242 return 0;
1243 }
1244
1245 creation = CREATION_EXISTING;
1246 } else
1247 creation = CREATION_NORMAL;
1248
1249 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path);
1250
1251 if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
1252 r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
1253 if (r == -ENOTTY) {
1254 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i->path);
1255 return 0;
1256 }
1257 if (r == -EROFS) {
1258 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i->path);
1259 return 0;
1260 }
1261 if (r < 0)
1262 return log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
1263 if (r > 0)
1264 log_debug("Adjusted quota for subvolume \"%s\".", i->path);
1265 if (r == 0)
1266 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
1267 }
1268
1269 r = path_set_perms(i, i->path);
1270 if (r < 0)
1271 return r;
1272
1273 break;
1274
1275 case CREATE_FIFO:
1276
1277 RUN_WITH_UMASK(0000) {
1278 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1279 r = mkfifo(i->path, i->mode);
1280 mac_selinux_create_file_clear();
1281 }
1282
1283 if (r < 0) {
1284 if (errno != EEXIST)
1285 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
1286
1287 if (lstat(i->path, &st) < 0)
1288 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1289
1290 if (!S_ISFIFO(st.st_mode)) {
1291
1292 if (i->force) {
1293 RUN_WITH_UMASK(0000) {
1294 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1295 r = mkfifo_atomic(i->path, i->mode);
1296 mac_selinux_create_file_clear();
1297 }
1298
1299 if (r < 0)
1300 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
1301 creation = CREATION_FORCE;
1302 } else {
1303 log_warning("\"%s\" already exists and is not a fifo.", i->path);
1304 return 0;
1305 }
1306 } else
1307 creation = CREATION_EXISTING;
1308 } else
1309 creation = CREATION_NORMAL;
1310 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation), i->path);
1311
1312 r = path_set_perms(i, i->path);
1313 if (r < 0)
1314 return r;
1315
1316 break;
1317 }
1318
1319 case CREATE_SYMLINK: {
1320 r = specifier_printf(i->argument, specifier_table, NULL, &resolved);
1321 if (r < 0)
1322 return log_error_errno(r, "Failed to substitute specifiers in symlink target %s: %m", i->argument);
1323
1324 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1325 r = symlink(resolved, i->path);
1326 mac_selinux_create_file_clear();
1327
1328 if (r < 0) {
1329 _cleanup_free_ char *x = NULL;
1330
1331 if (errno != EEXIST)
1332 return log_error_errno(errno, "symlink(%s, %s) failed: %m", resolved, i->path);
1333
1334 r = readlink_malloc(i->path, &x);
1335 if (r < 0 || !streq(resolved, x)) {
1336
1337 if (i->force) {
1338 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1339 r = symlink_atomic(resolved, i->path);
1340 mac_selinux_create_file_clear();
1341
1342 if (r < 0)
1343 return log_error_errno(r, "symlink(%s, %s) failed: %m", resolved, i->path);
1344
1345 creation = CREATION_FORCE;
1346 } else {
1347 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i->path);
1348 return 0;
1349 }
1350 } else
1351 creation = CREATION_EXISTING;
1352 } else
1353
1354 creation = CREATION_NORMAL;
1355 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation), i->path);
1356 break;
1357 }
1358
1359 case CREATE_BLOCK_DEVICE:
1360 case CREATE_CHAR_DEVICE: {
1361 mode_t file_type;
1362
1363 if (have_effective_cap(CAP_MKNOD) == 0) {
1364 /* In a container we lack CAP_MKNOD. We
1365 shouldn't attempt to create the device node in
1366 that case to avoid noise, and we don't support
1367 virtualized devices in containers anyway. */
1368
1369 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
1370 return 0;
1371 }
1372
1373 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
1374
1375 RUN_WITH_UMASK(0000) {
1376 mac_selinux_create_file_prepare(i->path, file_type);
1377 r = mknod(i->path, i->mode | file_type, i->major_minor);
1378 mac_selinux_create_file_clear();
1379 }
1380
1381 if (r < 0) {
1382 if (errno == EPERM) {
1383 log_debug("We lack permissions, possibly because of cgroup configuration; "
1384 "skipping creation of device node %s.", i->path);
1385 return 0;
1386 }
1387
1388 if (errno != EEXIST)
1389 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
1390
1391 if (lstat(i->path, &st) < 0)
1392 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1393
1394 if ((st.st_mode & S_IFMT) != file_type) {
1395
1396 if (i->force) {
1397
1398 RUN_WITH_UMASK(0000) {
1399 mac_selinux_create_file_prepare(i->path, file_type);
1400 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
1401 mac_selinux_create_file_clear();
1402 }
1403
1404 if (r < 0)
1405 return log_error_errno(r, "Failed to create device node \"%s\": %m", i->path);
1406 creation = CREATION_FORCE;
1407 } else {
1408 log_debug("%s is not a device node.", i->path);
1409 return 0;
1410 }
1411 } else
1412 creation = CREATION_EXISTING;
1413 } else
1414 creation = CREATION_NORMAL;
1415
1416 log_debug("%s %s device node \"%s\" %u:%u.",
1417 creation_mode_verb_to_string(creation),
1418 i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
1419 i->path, major(i->mode), minor(i->mode));
1420
1421 r = path_set_perms(i, i->path);
1422 if (r < 0)
1423 return r;
1424
1425 break;
1426 }
1427
1428 case ADJUST_MODE:
1429 case RELABEL_PATH:
1430 r = glob_item(i, path_set_perms, false);
1431 if (r < 0)
1432 return r;
1433 break;
1434
1435 case RECURSIVE_RELABEL_PATH:
1436 r = glob_item(i, path_set_perms, true);
1437 if (r < 0)
1438 return r;
1439 break;
1440
1441 case SET_XATTR:
1442 r = glob_item(i, path_set_xattrs, false);
1443 if (r < 0)
1444 return r;
1445 break;
1446
1447 case RECURSIVE_SET_XATTR:
1448 r = glob_item(i, path_set_xattrs, true);
1449 if (r < 0)
1450 return r;
1451 break;
1452
1453 case SET_ACL:
1454 r = glob_item(i, path_set_acls, false);
1455 if (r < 0)
1456 return r;
1457 break;
1458
1459 case RECURSIVE_SET_ACL:
1460 r = glob_item(i, path_set_acls, true);
1461 if (r < 0)
1462 return r;
1463 break;
1464
1465 case SET_ATTRIBUTE:
1466 r = glob_item(i, path_set_attribute, false);
1467 if (r < 0)
1468 return r;
1469 break;
1470
1471 case RECURSIVE_SET_ATTRIBUTE:
1472 r = glob_item(i, path_set_attribute, true);
1473 if (r < 0)
1474 return r;
1475 break;
1476 }
1477
1478 return 0;
1479 }
1480
1481 static int remove_item_instance(Item *i, const char *instance) {
1482 int r;
1483
1484 assert(i);
1485
1486 switch (i->type) {
1487
1488 case REMOVE_PATH:
1489 if (remove(instance) < 0 && errno != ENOENT)
1490 return log_error_errno(errno, "rm(%s): %m", instance);
1491
1492 break;
1493
1494 case TRUNCATE_DIRECTORY:
1495 case RECURSIVE_REMOVE_PATH:
1496 /* FIXME: we probably should use dir_cleanup() here
1497 * instead of rm_rf() so that 'x' is honoured. */
1498 log_debug("rm -rf \"%s\"", instance);
1499 r = rm_rf(instance, (i->type == RECURSIVE_REMOVE_PATH ? REMOVE_ROOT|REMOVE_SUBVOLUME : 0) | REMOVE_PHYSICAL);
1500 if (r < 0 && r != -ENOENT)
1501 return log_error_errno(r, "rm_rf(%s): %m", instance);
1502
1503 break;
1504
1505 default:
1506 assert_not_reached("wut?");
1507 }
1508
1509 return 0;
1510 }
1511
1512 static int remove_item(Item *i) {
1513 int r = 0;
1514
1515 assert(i);
1516
1517 log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
1518
1519 switch (i->type) {
1520
1521 case CREATE_FILE:
1522 case TRUNCATE_FILE:
1523 case CREATE_DIRECTORY:
1524 case CREATE_SUBVOLUME:
1525 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1526 case CREATE_SUBVOLUME_NEW_QUOTA:
1527 case CREATE_FIFO:
1528 case CREATE_SYMLINK:
1529 case CREATE_CHAR_DEVICE:
1530 case CREATE_BLOCK_DEVICE:
1531 case IGNORE_PATH:
1532 case IGNORE_DIRECTORY_PATH:
1533 case ADJUST_MODE:
1534 case RELABEL_PATH:
1535 case RECURSIVE_RELABEL_PATH:
1536 case WRITE_FILE:
1537 case COPY_FILES:
1538 case SET_XATTR:
1539 case RECURSIVE_SET_XATTR:
1540 case SET_ACL:
1541 case RECURSIVE_SET_ACL:
1542 case SET_ATTRIBUTE:
1543 case RECURSIVE_SET_ATTRIBUTE:
1544 break;
1545
1546 case REMOVE_PATH:
1547 case TRUNCATE_DIRECTORY:
1548 case RECURSIVE_REMOVE_PATH:
1549 r = glob_item(i, remove_item_instance, false);
1550 break;
1551 }
1552
1553 return r;
1554 }
1555
1556 static int clean_item_instance(Item *i, const char* instance) {
1557 _cleanup_closedir_ DIR *d = NULL;
1558 struct stat s, ps;
1559 bool mountpoint;
1560 usec_t cutoff, n;
1561 char timestamp[FORMAT_TIMESTAMP_MAX];
1562
1563 assert(i);
1564
1565 if (!i->age_set)
1566 return 0;
1567
1568 n = now(CLOCK_REALTIME);
1569 if (n < i->age)
1570 return 0;
1571
1572 cutoff = n - i->age;
1573
1574 d = opendir_nomod(instance);
1575 if (!d) {
1576 if (errno == ENOENT || errno == ENOTDIR) {
1577 log_debug_errno(errno, "Directory \"%s\": %m", instance);
1578 return 0;
1579 }
1580
1581 log_error_errno(errno, "Failed to open directory %s: %m", instance);
1582 return -errno;
1583 }
1584
1585 if (fstat(dirfd(d), &s) < 0)
1586 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1587
1588 if (!S_ISDIR(s.st_mode)) {
1589 log_error("%s is not a directory.", i->path);
1590 return -ENOTDIR;
1591 }
1592
1593 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1594 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1595
1596 mountpoint = s.st_dev != ps.st_dev || s.st_ino == ps.st_ino;
1597
1598 log_debug("Cleanup threshold for %s \"%s\" is %s",
1599 mountpoint ? "mount point" : "directory",
1600 instance,
1601 format_timestamp_us(timestamp, sizeof(timestamp), cutoff));
1602
1603 return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1604 MAX_DEPTH, i->keep_first_level);
1605 }
1606
1607 static int clean_item(Item *i) {
1608 int r = 0;
1609
1610 assert(i);
1611
1612 log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
1613
1614 switch (i->type) {
1615 case CREATE_DIRECTORY:
1616 case CREATE_SUBVOLUME:
1617 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1618 case CREATE_SUBVOLUME_NEW_QUOTA:
1619 case TRUNCATE_DIRECTORY:
1620 case IGNORE_PATH:
1621 case COPY_FILES:
1622 clean_item_instance(i, i->path);
1623 break;
1624 case IGNORE_DIRECTORY_PATH:
1625 r = glob_item(i, clean_item_instance, false);
1626 break;
1627 default:
1628 break;
1629 }
1630
1631 return r;
1632 }
1633
1634 static int process_item_array(ItemArray *array);
1635
1636 static int process_item(Item *i) {
1637 int r, q, p, t = 0;
1638 _cleanup_free_ char *prefix = NULL;
1639
1640 assert(i);
1641
1642 if (i->done)
1643 return 0;
1644
1645 i->done = true;
1646
1647 prefix = malloc(strlen(i->path) + 1);
1648 if (!prefix)
1649 return log_oom();
1650
1651 PATH_FOREACH_PREFIX(prefix, i->path) {
1652 ItemArray *j;
1653
1654 j = ordered_hashmap_get(items, prefix);
1655 if (j) {
1656 int s;
1657
1658 s = process_item_array(j);
1659 if (s < 0 && t == 0)
1660 t = s;
1661 }
1662 }
1663
1664 r = arg_create ? create_item(i) : 0;
1665 q = arg_remove ? remove_item(i) : 0;
1666 p = arg_clean ? clean_item(i) : 0;
1667
1668 return t < 0 ? t :
1669 r < 0 ? r :
1670 q < 0 ? q :
1671 p;
1672 }
1673
1674 static int process_item_array(ItemArray *array) {
1675 unsigned n;
1676 int r = 0, k;
1677
1678 assert(array);
1679
1680 for (n = 0; n < array->count; n++) {
1681 k = process_item(array->items + n);
1682 if (k < 0 && r == 0)
1683 r = k;
1684 }
1685
1686 return r;
1687 }
1688
1689 static void item_free_contents(Item *i) {
1690 assert(i);
1691 free(i->path);
1692 free(i->argument);
1693 strv_free(i->xattrs);
1694
1695 #ifdef HAVE_ACL
1696 acl_free(i->acl_access);
1697 acl_free(i->acl_default);
1698 #endif
1699 }
1700
1701 static void item_array_free(ItemArray *a) {
1702 unsigned n;
1703
1704 if (!a)
1705 return;
1706
1707 for (n = 0; n < a->count; n++)
1708 item_free_contents(a->items + n);
1709 free(a->items);
1710 free(a);
1711 }
1712
1713 static int item_compare(const void *a, const void *b) {
1714 const Item *x = a, *y = b;
1715
1716 /* Make sure that the ownership taking item is put first, so
1717 * that we first create the node, and then can adjust it */
1718
1719 if (takes_ownership(x->type) && !takes_ownership(y->type))
1720 return -1;
1721 if (!takes_ownership(x->type) && takes_ownership(y->type))
1722 return 1;
1723
1724 return (int) x->type - (int) y->type;
1725 }
1726
1727 static bool item_compatible(Item *a, Item *b) {
1728 assert(a);
1729 assert(b);
1730 assert(streq(a->path, b->path));
1731
1732 if (takes_ownership(a->type) && takes_ownership(b->type))
1733 /* check if the items are the same */
1734 return streq_ptr(a->argument, b->argument) &&
1735
1736 a->uid_set == b->uid_set &&
1737 a->uid == b->uid &&
1738
1739 a->gid_set == b->gid_set &&
1740 a->gid == b->gid &&
1741
1742 a->mode_set == b->mode_set &&
1743 a->mode == b->mode &&
1744
1745 a->age_set == b->age_set &&
1746 a->age == b->age &&
1747
1748 a->mask_perms == b->mask_perms &&
1749
1750 a->keep_first_level == b->keep_first_level &&
1751
1752 a->major_minor == b->major_minor;
1753
1754 return true;
1755 }
1756
1757 static bool should_include_path(const char *path) {
1758 char **prefix;
1759
1760 STRV_FOREACH(prefix, arg_exclude_prefixes)
1761 if (path_startswith(path, *prefix)) {
1762 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1763 path, *prefix);
1764 return false;
1765 }
1766
1767 STRV_FOREACH(prefix, arg_include_prefixes)
1768 if (path_startswith(path, *prefix)) {
1769 log_debug("Entry \"%s\" matches include prefix \"%s\".", path, *prefix);
1770 return true;
1771 }
1772
1773 /* no matches, so we should include this path only if we
1774 * have no whitelist at all */
1775 if (strv_length(arg_include_prefixes) == 0)
1776 return true;
1777
1778 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path);
1779 return false;
1780 }
1781
1782 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1783
1784 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1785 _cleanup_(item_free_contents) Item i = {};
1786 ItemArray *existing;
1787 OrderedHashmap *h;
1788 int r, pos;
1789 bool force = false, boot = false;
1790
1791 assert(fname);
1792 assert(line >= 1);
1793 assert(buffer);
1794
1795 r = extract_many_words(
1796 &buffer,
1797 NULL,
1798 EXTRACT_QUOTES,
1799 &action,
1800 &path,
1801 &mode,
1802 &user,
1803 &group,
1804 &age,
1805 NULL);
1806 if (r < 0)
1807 return log_error_errno(r, "[%s:%u] Failed to parse line: %m", fname, line);
1808 else if (r < 2) {
1809 log_error("[%s:%u] Syntax error.", fname, line);
1810 return -EIO;
1811 }
1812
1813 if (!isempty(buffer) && !streq(buffer, "-")) {
1814 i.argument = strdup(buffer);
1815 if (!i.argument)
1816 return log_oom();
1817 }
1818
1819 if (isempty(action)) {
1820 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1821 return -EINVAL;
1822 }
1823
1824 for (pos = 1; action[pos]; pos++) {
1825 if (action[pos] == '!' && !boot)
1826 boot = true;
1827 else if (action[pos] == '+' && !force)
1828 force = true;
1829 else {
1830 log_error("[%s:%u] Unknown modifiers in command '%s'",
1831 fname, line, action);
1832 return -EINVAL;
1833 }
1834 }
1835
1836 if (boot && !arg_boot) {
1837 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1838 action, path);
1839 return 0;
1840 }
1841
1842 i.type = action[0];
1843 i.force = force;
1844
1845 r = specifier_printf(path, specifier_table, NULL, &i.path);
1846 if (r < 0) {
1847 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1848 return r;
1849 }
1850
1851 switch (i.type) {
1852
1853 case CREATE_DIRECTORY:
1854 case CREATE_SUBVOLUME:
1855 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1856 case CREATE_SUBVOLUME_NEW_QUOTA:
1857 case TRUNCATE_DIRECTORY:
1858 case CREATE_FIFO:
1859 case IGNORE_PATH:
1860 case IGNORE_DIRECTORY_PATH:
1861 case REMOVE_PATH:
1862 case RECURSIVE_REMOVE_PATH:
1863 case ADJUST_MODE:
1864 case RELABEL_PATH:
1865 case RECURSIVE_RELABEL_PATH:
1866 if (i.argument)
1867 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname, line, i.type);
1868
1869 break;
1870
1871 case CREATE_FILE:
1872 case TRUNCATE_FILE:
1873 break;
1874
1875 case CREATE_SYMLINK:
1876 if (!i.argument) {
1877 i.argument = strappend("/usr/share/factory/", i.path);
1878 if (!i.argument)
1879 return log_oom();
1880 }
1881 break;
1882
1883 case WRITE_FILE:
1884 if (!i.argument) {
1885 log_error("[%s:%u] Write file requires argument.", fname, line);
1886 return -EBADMSG;
1887 }
1888 break;
1889
1890 case COPY_FILES:
1891 if (!i.argument) {
1892 i.argument = strappend("/usr/share/factory/", i.path);
1893 if (!i.argument)
1894 return log_oom();
1895 } else if (!path_is_absolute(i.argument)) {
1896 log_error("[%s:%u] Source path is not absolute.", fname, line);
1897 return -EBADMSG;
1898 }
1899
1900 path_kill_slashes(i.argument);
1901 break;
1902
1903 case CREATE_CHAR_DEVICE:
1904 case CREATE_BLOCK_DEVICE: {
1905 unsigned major, minor;
1906
1907 if (!i.argument) {
1908 log_error("[%s:%u] Device file requires argument.", fname, line);
1909 return -EBADMSG;
1910 }
1911
1912 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1913 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1914 return -EBADMSG;
1915 }
1916
1917 i.major_minor = makedev(major, minor);
1918 break;
1919 }
1920
1921 case SET_XATTR:
1922 case RECURSIVE_SET_XATTR:
1923 if (!i.argument) {
1924 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1925 return -EBADMSG;
1926 }
1927 r = parse_xattrs_from_arg(&i);
1928 if (r < 0)
1929 return r;
1930 break;
1931
1932 case SET_ACL:
1933 case RECURSIVE_SET_ACL:
1934 if (!i.argument) {
1935 log_error("[%s:%u] Set ACLs requires argument.", fname, line);
1936 return -EBADMSG;
1937 }
1938 r = parse_acls_from_arg(&i);
1939 if (r < 0)
1940 return r;
1941 break;
1942
1943 case SET_ATTRIBUTE:
1944 case RECURSIVE_SET_ATTRIBUTE:
1945 if (!i.argument) {
1946 log_error("[%s:%u] Set file attribute requires argument.", fname, line);
1947 return -EBADMSG;
1948 }
1949 r = parse_attribute_from_arg(&i);
1950 if (r < 0)
1951 return r;
1952 break;
1953
1954 default:
1955 log_error("[%s:%u] Unknown command type '%c'.", fname, line, (char) i.type);
1956 return -EBADMSG;
1957 }
1958
1959 if (!path_is_absolute(i.path)) {
1960 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1961 return -EBADMSG;
1962 }
1963
1964 path_kill_slashes(i.path);
1965
1966 if (!should_include_path(i.path))
1967 return 0;
1968
1969 if (arg_root) {
1970 char *p;
1971
1972 p = prefix_root(arg_root, i.path);
1973 if (!p)
1974 return log_oom();
1975
1976 free(i.path);
1977 i.path = p;
1978 }
1979
1980 if (!isempty(user) && !streq(user, "-")) {
1981 const char *u = user;
1982
1983 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1984 if (r < 0) {
1985 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1986 return r;
1987 }
1988
1989 i.uid_set = true;
1990 }
1991
1992 if (!isempty(group) && !streq(group, "-")) {
1993 const char *g = group;
1994
1995 r = get_group_creds(&g, &i.gid);
1996 if (r < 0) {
1997 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1998 return r;
1999 }
2000
2001 i.gid_set = true;
2002 }
2003
2004 if (!isempty(mode) && !streq(mode, "-")) {
2005 const char *mm = mode;
2006 unsigned m;
2007
2008 if (*mm == '~') {
2009 i.mask_perms = true;
2010 mm++;
2011 }
2012
2013 if (parse_mode(mm, &m) < 0) {
2014 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
2015 return -EBADMSG;
2016 }
2017
2018 i.mode = m;
2019 i.mode_set = true;
2020 } else
2021 i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
2022
2023 if (!isempty(age) && !streq(age, "-")) {
2024 const char *a = age;
2025
2026 if (*a == '~') {
2027 i.keep_first_level = true;
2028 a++;
2029 }
2030
2031 if (parse_sec(a, &i.age) < 0) {
2032 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
2033 return -EBADMSG;
2034 }
2035
2036 i.age_set = true;
2037 }
2038
2039 h = needs_glob(i.type) ? globs : items;
2040
2041 existing = ordered_hashmap_get(h, i.path);
2042 if (existing) {
2043 unsigned n;
2044
2045 for (n = 0; n < existing->count; n++) {
2046 if (!item_compatible(existing->items + n, &i)) {
2047 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2048 fname, line, i.path);
2049 return 0;
2050 }
2051 }
2052 } else {
2053 existing = new0(ItemArray, 1);
2054 r = ordered_hashmap_put(h, i.path, existing);
2055 if (r < 0)
2056 return log_oom();
2057 }
2058
2059 if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
2060 return log_oom();
2061
2062 memcpy(existing->items + existing->count++, &i, sizeof(i));
2063
2064 /* Sort item array, to enforce stable ordering of application */
2065 qsort_safe(existing->items, existing->count, sizeof(Item), item_compare);
2066
2067 zero(i);
2068 return 0;
2069 }
2070
2071 static void help(void) {
2072 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2073 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2074 " -h --help Show this help\n"
2075 " --version Show package version\n"
2076 " --create Create marked files/directories\n"
2077 " --clean Clean up marked directories\n"
2078 " --remove Remove marked files/directories\n"
2079 " --boot Execute actions only safe at boot\n"
2080 " --prefix=PATH Only apply rules with the specified prefix\n"
2081 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2082 " --root=PATH Operate on an alternate filesystem root\n",
2083 program_invocation_short_name);
2084 }
2085
2086 static int parse_argv(int argc, char *argv[]) {
2087
2088 enum {
2089 ARG_VERSION = 0x100,
2090 ARG_CREATE,
2091 ARG_CLEAN,
2092 ARG_REMOVE,
2093 ARG_BOOT,
2094 ARG_PREFIX,
2095 ARG_EXCLUDE_PREFIX,
2096 ARG_ROOT,
2097 };
2098
2099 static const struct option options[] = {
2100 { "help", no_argument, NULL, 'h' },
2101 { "version", no_argument, NULL, ARG_VERSION },
2102 { "create", no_argument, NULL, ARG_CREATE },
2103 { "clean", no_argument, NULL, ARG_CLEAN },
2104 { "remove", no_argument, NULL, ARG_REMOVE },
2105 { "boot", no_argument, NULL, ARG_BOOT },
2106 { "prefix", required_argument, NULL, ARG_PREFIX },
2107 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
2108 { "root", required_argument, NULL, ARG_ROOT },
2109 {}
2110 };
2111
2112 int c, r;
2113
2114 assert(argc >= 0);
2115 assert(argv);
2116
2117 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
2118
2119 switch (c) {
2120
2121 case 'h':
2122 help();
2123 return 0;
2124
2125 case ARG_VERSION:
2126 return version();
2127
2128 case ARG_CREATE:
2129 arg_create = true;
2130 break;
2131
2132 case ARG_CLEAN:
2133 arg_clean = true;
2134 break;
2135
2136 case ARG_REMOVE:
2137 arg_remove = true;
2138 break;
2139
2140 case ARG_BOOT:
2141 arg_boot = true;
2142 break;
2143
2144 case ARG_PREFIX:
2145 if (strv_push(&arg_include_prefixes, optarg) < 0)
2146 return log_oom();
2147 break;
2148
2149 case ARG_EXCLUDE_PREFIX:
2150 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
2151 return log_oom();
2152 break;
2153
2154 case ARG_ROOT:
2155 r = parse_path_argument_and_warn(optarg, true, &arg_root);
2156 if (r < 0)
2157 return r;
2158 break;
2159
2160 case '?':
2161 return -EINVAL;
2162
2163 default:
2164 assert_not_reached("Unhandled option");
2165 }
2166
2167 if (!arg_clean && !arg_create && !arg_remove) {
2168 log_error("You need to specify at least one of --clean, --create or --remove.");
2169 return -EINVAL;
2170 }
2171
2172 return 1;
2173 }
2174
2175 static int read_config_file(const char *fn, bool ignore_enoent) {
2176 _cleanup_fclose_ FILE *f = NULL;
2177 char line[LINE_MAX];
2178 Iterator iterator;
2179 unsigned v = 0;
2180 Item *i;
2181 int r;
2182
2183 assert(fn);
2184
2185 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
2186 if (r < 0) {
2187 if (ignore_enoent && r == -ENOENT) {
2188 log_debug_errno(r, "Failed to open \"%s\": %m", fn);
2189 return 0;
2190 }
2191
2192 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
2193 }
2194 log_debug("Reading config file \"%s\".", fn);
2195
2196 FOREACH_LINE(line, f, break) {
2197 char *l;
2198 int k;
2199
2200 v++;
2201
2202 l = strstrip(line);
2203 if (*l == '#' || *l == 0)
2204 continue;
2205
2206 k = parse_line(fn, v, l);
2207 if (k < 0 && r == 0)
2208 r = k;
2209 }
2210
2211 /* we have to determine age parameter for each entry of type X */
2212 ORDERED_HASHMAP_FOREACH(i, globs, iterator) {
2213 Iterator iter;
2214 Item *j, *candidate_item = NULL;
2215
2216 if (i->type != IGNORE_DIRECTORY_PATH)
2217 continue;
2218
2219 ORDERED_HASHMAP_FOREACH(j, items, iter) {
2220 if (!IN_SET(j->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA))
2221 continue;
2222
2223 if (path_equal(j->path, i->path)) {
2224 candidate_item = j;
2225 break;
2226 }
2227
2228 if ((!candidate_item && path_startswith(i->path, j->path)) ||
2229 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
2230 candidate_item = j;
2231 }
2232
2233 if (candidate_item && candidate_item->age_set) {
2234 i->age = candidate_item->age;
2235 i->age_set = true;
2236 }
2237 }
2238
2239 if (ferror(f)) {
2240 log_error_errno(errno, "Failed to read from file %s: %m", fn);
2241 if (r == 0)
2242 r = -EIO;
2243 }
2244
2245 return r;
2246 }
2247
2248 int main(int argc, char *argv[]) {
2249 int r, k;
2250 ItemArray *a;
2251 Iterator iterator;
2252
2253 r = parse_argv(argc, argv);
2254 if (r <= 0)
2255 goto finish;
2256
2257 log_set_target(LOG_TARGET_AUTO);
2258 log_parse_environment();
2259 log_open();
2260
2261 umask(0022);
2262
2263 mac_selinux_init(NULL);
2264
2265 items = ordered_hashmap_new(&string_hash_ops);
2266 globs = ordered_hashmap_new(&string_hash_ops);
2267
2268 if (!items || !globs) {
2269 r = log_oom();
2270 goto finish;
2271 }
2272
2273 r = 0;
2274
2275 if (optind < argc) {
2276 int j;
2277
2278 for (j = optind; j < argc; j++) {
2279 k = read_config_file(argv[j], false);
2280 if (k < 0 && r == 0)
2281 r = k;
2282 }
2283
2284 } else {
2285 _cleanup_strv_free_ char **files = NULL;
2286 char **f;
2287
2288 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
2289 if (r < 0) {
2290 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
2291 goto finish;
2292 }
2293
2294 STRV_FOREACH(f, files) {
2295 k = read_config_file(*f, true);
2296 if (k < 0 && r == 0)
2297 r = k;
2298 }
2299 }
2300
2301 /* The non-globbing ones usually create things, hence we apply
2302 * them first */
2303 ORDERED_HASHMAP_FOREACH(a, items, iterator) {
2304 k = process_item_array(a);
2305 if (k < 0 && r == 0)
2306 r = k;
2307 }
2308
2309 /* The globbing ones usually alter things, hence we apply them
2310 * second. */
2311 ORDERED_HASHMAP_FOREACH(a, globs, iterator) {
2312 k = process_item_array(a);
2313 if (k < 0 && r == 0)
2314 r = k;
2315 }
2316
2317 finish:
2318 while ((a = ordered_hashmap_steal_first(items)))
2319 item_array_free(a);
2320
2321 while ((a = ordered_hashmap_steal_first(globs)))
2322 item_array_free(a);
2323
2324 ordered_hashmap_free(items);
2325 ordered_hashmap_free(globs);
2326
2327 free(arg_include_prefixes);
2328 free(arg_exclude_prefixes);
2329 free(arg_root);
2330
2331 set_free_free(unix_sockets);
2332
2333 mac_selinux_finish();
2334
2335 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2336 }