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