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