]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/tmpfiles/tmpfiles.c
Merge pull request #1837 from poettering/grabbag2
[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_PATHS_NULSTR("tmpfiles.d");
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 == -ENOPROTOOPT) {
1271 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because quota support is disabled: %m", i->path);
1272 return 0;
1273 }
1274 if (r < 0)
1275 return log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
1276 if (r > 0)
1277 log_debug("Adjusted quota for subvolume \"%s\".", i->path);
1278 if (r == 0)
1279 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
1280 }
1281
1282 r = path_set_perms(i, i->path);
1283 if (r < 0)
1284 return r;
1285
1286 break;
1287
1288 case CREATE_FIFO:
1289
1290 RUN_WITH_UMASK(0000) {
1291 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1292 r = mkfifo(i->path, i->mode);
1293 mac_selinux_create_file_clear();
1294 }
1295
1296 if (r < 0) {
1297 if (errno != EEXIST)
1298 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
1299
1300 if (lstat(i->path, &st) < 0)
1301 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1302
1303 if (!S_ISFIFO(st.st_mode)) {
1304
1305 if (i->force) {
1306 RUN_WITH_UMASK(0000) {
1307 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1308 r = mkfifo_atomic(i->path, i->mode);
1309 mac_selinux_create_file_clear();
1310 }
1311
1312 if (r < 0)
1313 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
1314 creation = CREATION_FORCE;
1315 } else {
1316 log_warning("\"%s\" already exists and is not a fifo.", i->path);
1317 return 0;
1318 }
1319 } else
1320 creation = CREATION_EXISTING;
1321 } else
1322 creation = CREATION_NORMAL;
1323 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation), i->path);
1324
1325 r = path_set_perms(i, i->path);
1326 if (r < 0)
1327 return r;
1328
1329 break;
1330 }
1331
1332 case CREATE_SYMLINK: {
1333 r = specifier_printf(i->argument, specifier_table, NULL, &resolved);
1334 if (r < 0)
1335 return log_error_errno(r, "Failed to substitute specifiers in symlink target %s: %m", i->argument);
1336
1337 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1338 r = symlink(resolved, i->path);
1339 mac_selinux_create_file_clear();
1340
1341 if (r < 0) {
1342 _cleanup_free_ char *x = NULL;
1343
1344 if (errno != EEXIST)
1345 return log_error_errno(errno, "symlink(%s, %s) failed: %m", resolved, i->path);
1346
1347 r = readlink_malloc(i->path, &x);
1348 if (r < 0 || !streq(resolved, x)) {
1349
1350 if (i->force) {
1351 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1352 r = symlink_atomic(resolved, i->path);
1353 mac_selinux_create_file_clear();
1354
1355 if (r < 0)
1356 return log_error_errno(r, "symlink(%s, %s) failed: %m", resolved, i->path);
1357
1358 creation = CREATION_FORCE;
1359 } else {
1360 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i->path);
1361 return 0;
1362 }
1363 } else
1364 creation = CREATION_EXISTING;
1365 } else
1366
1367 creation = CREATION_NORMAL;
1368 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation), i->path);
1369 break;
1370 }
1371
1372 case CREATE_BLOCK_DEVICE:
1373 case CREATE_CHAR_DEVICE: {
1374 mode_t file_type;
1375
1376 if (have_effective_cap(CAP_MKNOD) == 0) {
1377 /* In a container we lack CAP_MKNOD. We
1378 shouldn't attempt to create the device node in
1379 that case to avoid noise, and we don't support
1380 virtualized devices in containers anyway. */
1381
1382 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
1383 return 0;
1384 }
1385
1386 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
1387
1388 RUN_WITH_UMASK(0000) {
1389 mac_selinux_create_file_prepare(i->path, file_type);
1390 r = mknod(i->path, i->mode | file_type, i->major_minor);
1391 mac_selinux_create_file_clear();
1392 }
1393
1394 if (r < 0) {
1395 if (errno == EPERM) {
1396 log_debug("We lack permissions, possibly because of cgroup configuration; "
1397 "skipping creation of device node %s.", i->path);
1398 return 0;
1399 }
1400
1401 if (errno != EEXIST)
1402 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
1403
1404 if (lstat(i->path, &st) < 0)
1405 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1406
1407 if ((st.st_mode & S_IFMT) != file_type) {
1408
1409 if (i->force) {
1410
1411 RUN_WITH_UMASK(0000) {
1412 mac_selinux_create_file_prepare(i->path, file_type);
1413 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
1414 mac_selinux_create_file_clear();
1415 }
1416
1417 if (r < 0)
1418 return log_error_errno(r, "Failed to create device node \"%s\": %m", i->path);
1419 creation = CREATION_FORCE;
1420 } else {
1421 log_debug("%s is not a device node.", i->path);
1422 return 0;
1423 }
1424 } else
1425 creation = CREATION_EXISTING;
1426 } else
1427 creation = CREATION_NORMAL;
1428
1429 log_debug("%s %s device node \"%s\" %u:%u.",
1430 creation_mode_verb_to_string(creation),
1431 i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
1432 i->path, major(i->mode), minor(i->mode));
1433
1434 r = path_set_perms(i, i->path);
1435 if (r < 0)
1436 return r;
1437
1438 break;
1439 }
1440
1441 case ADJUST_MODE:
1442 case RELABEL_PATH:
1443 r = glob_item(i, path_set_perms, false);
1444 if (r < 0)
1445 return r;
1446 break;
1447
1448 case RECURSIVE_RELABEL_PATH:
1449 r = glob_item(i, path_set_perms, true);
1450 if (r < 0)
1451 return r;
1452 break;
1453
1454 case SET_XATTR:
1455 r = glob_item(i, path_set_xattrs, false);
1456 if (r < 0)
1457 return r;
1458 break;
1459
1460 case RECURSIVE_SET_XATTR:
1461 r = glob_item(i, path_set_xattrs, true);
1462 if (r < 0)
1463 return r;
1464 break;
1465
1466 case SET_ACL:
1467 r = glob_item(i, path_set_acls, false);
1468 if (r < 0)
1469 return r;
1470 break;
1471
1472 case RECURSIVE_SET_ACL:
1473 r = glob_item(i, path_set_acls, true);
1474 if (r < 0)
1475 return r;
1476 break;
1477
1478 case SET_ATTRIBUTE:
1479 r = glob_item(i, path_set_attribute, false);
1480 if (r < 0)
1481 return r;
1482 break;
1483
1484 case RECURSIVE_SET_ATTRIBUTE:
1485 r = glob_item(i, path_set_attribute, true);
1486 if (r < 0)
1487 return r;
1488 break;
1489 }
1490
1491 return 0;
1492 }
1493
1494 static int remove_item_instance(Item *i, const char *instance) {
1495 int r;
1496
1497 assert(i);
1498
1499 switch (i->type) {
1500
1501 case REMOVE_PATH:
1502 if (remove(instance) < 0 && errno != ENOENT)
1503 return log_error_errno(errno, "rm(%s): %m", instance);
1504
1505 break;
1506
1507 case TRUNCATE_DIRECTORY:
1508 case RECURSIVE_REMOVE_PATH:
1509 /* FIXME: we probably should use dir_cleanup() here
1510 * instead of rm_rf() so that 'x' is honoured. */
1511 log_debug("rm -rf \"%s\"", instance);
1512 r = rm_rf(instance, (i->type == RECURSIVE_REMOVE_PATH ? REMOVE_ROOT|REMOVE_SUBVOLUME : 0) | REMOVE_PHYSICAL);
1513 if (r < 0 && r != -ENOENT)
1514 return log_error_errno(r, "rm_rf(%s): %m", instance);
1515
1516 break;
1517
1518 default:
1519 assert_not_reached("wut?");
1520 }
1521
1522 return 0;
1523 }
1524
1525 static int remove_item(Item *i) {
1526 int r = 0;
1527
1528 assert(i);
1529
1530 log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
1531
1532 switch (i->type) {
1533
1534 case CREATE_FILE:
1535 case TRUNCATE_FILE:
1536 case CREATE_DIRECTORY:
1537 case CREATE_SUBVOLUME:
1538 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1539 case CREATE_SUBVOLUME_NEW_QUOTA:
1540 case CREATE_FIFO:
1541 case CREATE_SYMLINK:
1542 case CREATE_CHAR_DEVICE:
1543 case CREATE_BLOCK_DEVICE:
1544 case IGNORE_PATH:
1545 case IGNORE_DIRECTORY_PATH:
1546 case ADJUST_MODE:
1547 case RELABEL_PATH:
1548 case RECURSIVE_RELABEL_PATH:
1549 case WRITE_FILE:
1550 case COPY_FILES:
1551 case SET_XATTR:
1552 case RECURSIVE_SET_XATTR:
1553 case SET_ACL:
1554 case RECURSIVE_SET_ACL:
1555 case SET_ATTRIBUTE:
1556 case RECURSIVE_SET_ATTRIBUTE:
1557 break;
1558
1559 case REMOVE_PATH:
1560 case TRUNCATE_DIRECTORY:
1561 case RECURSIVE_REMOVE_PATH:
1562 r = glob_item(i, remove_item_instance, false);
1563 break;
1564 }
1565
1566 return r;
1567 }
1568
1569 static int clean_item_instance(Item *i, const char* instance) {
1570 _cleanup_closedir_ DIR *d = NULL;
1571 struct stat s, ps;
1572 bool mountpoint;
1573 usec_t cutoff, n;
1574 char timestamp[FORMAT_TIMESTAMP_MAX];
1575
1576 assert(i);
1577
1578 if (!i->age_set)
1579 return 0;
1580
1581 n = now(CLOCK_REALTIME);
1582 if (n < i->age)
1583 return 0;
1584
1585 cutoff = n - i->age;
1586
1587 d = opendir_nomod(instance);
1588 if (!d) {
1589 if (errno == ENOENT || errno == ENOTDIR) {
1590 log_debug_errno(errno, "Directory \"%s\": %m", instance);
1591 return 0;
1592 }
1593
1594 log_error_errno(errno, "Failed to open directory %s: %m", instance);
1595 return -errno;
1596 }
1597
1598 if (fstat(dirfd(d), &s) < 0)
1599 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1600
1601 if (!S_ISDIR(s.st_mode)) {
1602 log_error("%s is not a directory.", i->path);
1603 return -ENOTDIR;
1604 }
1605
1606 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1607 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1608
1609 mountpoint = s.st_dev != ps.st_dev || s.st_ino == ps.st_ino;
1610
1611 log_debug("Cleanup threshold for %s \"%s\" is %s",
1612 mountpoint ? "mount point" : "directory",
1613 instance,
1614 format_timestamp_us(timestamp, sizeof(timestamp), cutoff));
1615
1616 return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1617 MAX_DEPTH, i->keep_first_level);
1618 }
1619
1620 static int clean_item(Item *i) {
1621 int r = 0;
1622
1623 assert(i);
1624
1625 log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
1626
1627 switch (i->type) {
1628 case CREATE_DIRECTORY:
1629 case CREATE_SUBVOLUME:
1630 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1631 case CREATE_SUBVOLUME_NEW_QUOTA:
1632 case TRUNCATE_DIRECTORY:
1633 case IGNORE_PATH:
1634 case COPY_FILES:
1635 clean_item_instance(i, i->path);
1636 break;
1637 case IGNORE_DIRECTORY_PATH:
1638 r = glob_item(i, clean_item_instance, false);
1639 break;
1640 default:
1641 break;
1642 }
1643
1644 return r;
1645 }
1646
1647 static int process_item_array(ItemArray *array);
1648
1649 static int process_item(Item *i) {
1650 int r, q, p, t = 0;
1651 _cleanup_free_ char *prefix = NULL;
1652
1653 assert(i);
1654
1655 if (i->done)
1656 return 0;
1657
1658 i->done = true;
1659
1660 prefix = malloc(strlen(i->path) + 1);
1661 if (!prefix)
1662 return log_oom();
1663
1664 PATH_FOREACH_PREFIX(prefix, i->path) {
1665 ItemArray *j;
1666
1667 j = ordered_hashmap_get(items, prefix);
1668 if (j) {
1669 int s;
1670
1671 s = process_item_array(j);
1672 if (s < 0 && t == 0)
1673 t = s;
1674 }
1675 }
1676
1677 r = arg_create ? create_item(i) : 0;
1678 q = arg_remove ? remove_item(i) : 0;
1679 p = arg_clean ? clean_item(i) : 0;
1680
1681 return t < 0 ? t :
1682 r < 0 ? r :
1683 q < 0 ? q :
1684 p;
1685 }
1686
1687 static int process_item_array(ItemArray *array) {
1688 unsigned n;
1689 int r = 0, k;
1690
1691 assert(array);
1692
1693 for (n = 0; n < array->count; n++) {
1694 k = process_item(array->items + n);
1695 if (k < 0 && r == 0)
1696 r = k;
1697 }
1698
1699 return r;
1700 }
1701
1702 static void item_free_contents(Item *i) {
1703 assert(i);
1704 free(i->path);
1705 free(i->argument);
1706 strv_free(i->xattrs);
1707
1708 #ifdef HAVE_ACL
1709 acl_free(i->acl_access);
1710 acl_free(i->acl_default);
1711 #endif
1712 }
1713
1714 static void item_array_free(ItemArray *a) {
1715 unsigned n;
1716
1717 if (!a)
1718 return;
1719
1720 for (n = 0; n < a->count; n++)
1721 item_free_contents(a->items + n);
1722 free(a->items);
1723 free(a);
1724 }
1725
1726 static int item_compare(const void *a, const void *b) {
1727 const Item *x = a, *y = b;
1728
1729 /* Make sure that the ownership taking item is put first, so
1730 * that we first create the node, and then can adjust it */
1731
1732 if (takes_ownership(x->type) && !takes_ownership(y->type))
1733 return -1;
1734 if (!takes_ownership(x->type) && takes_ownership(y->type))
1735 return 1;
1736
1737 return (int) x->type - (int) y->type;
1738 }
1739
1740 static bool item_compatible(Item *a, Item *b) {
1741 assert(a);
1742 assert(b);
1743 assert(streq(a->path, b->path));
1744
1745 if (takes_ownership(a->type) && takes_ownership(b->type))
1746 /* check if the items are the same */
1747 return streq_ptr(a->argument, b->argument) &&
1748
1749 a->uid_set == b->uid_set &&
1750 a->uid == b->uid &&
1751
1752 a->gid_set == b->gid_set &&
1753 a->gid == b->gid &&
1754
1755 a->mode_set == b->mode_set &&
1756 a->mode == b->mode &&
1757
1758 a->age_set == b->age_set &&
1759 a->age == b->age &&
1760
1761 a->mask_perms == b->mask_perms &&
1762
1763 a->keep_first_level == b->keep_first_level &&
1764
1765 a->major_minor == b->major_minor;
1766
1767 return true;
1768 }
1769
1770 static bool should_include_path(const char *path) {
1771 char **prefix;
1772
1773 STRV_FOREACH(prefix, arg_exclude_prefixes)
1774 if (path_startswith(path, *prefix)) {
1775 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1776 path, *prefix);
1777 return false;
1778 }
1779
1780 STRV_FOREACH(prefix, arg_include_prefixes)
1781 if (path_startswith(path, *prefix)) {
1782 log_debug("Entry \"%s\" matches include prefix \"%s\".", path, *prefix);
1783 return true;
1784 }
1785
1786 /* no matches, so we should include this path only if we
1787 * have no whitelist at all */
1788 if (strv_length(arg_include_prefixes) == 0)
1789 return true;
1790
1791 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path);
1792 return false;
1793 }
1794
1795 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1796
1797 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1798 _cleanup_(item_free_contents) Item i = {};
1799 ItemArray *existing;
1800 OrderedHashmap *h;
1801 int r, pos;
1802 bool force = false, boot = false;
1803
1804 assert(fname);
1805 assert(line >= 1);
1806 assert(buffer);
1807
1808 r = extract_many_words(
1809 &buffer,
1810 NULL,
1811 EXTRACT_QUOTES,
1812 &action,
1813 &path,
1814 &mode,
1815 &user,
1816 &group,
1817 &age,
1818 NULL);
1819 if (r < 0)
1820 return log_error_errno(r, "[%s:%u] Failed to parse line: %m", fname, line);
1821 else if (r < 2) {
1822 log_error("[%s:%u] Syntax error.", fname, line);
1823 return -EIO;
1824 }
1825
1826 if (!isempty(buffer) && !streq(buffer, "-")) {
1827 i.argument = strdup(buffer);
1828 if (!i.argument)
1829 return log_oom();
1830 }
1831
1832 if (isempty(action)) {
1833 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1834 return -EINVAL;
1835 }
1836
1837 for (pos = 1; action[pos]; pos++) {
1838 if (action[pos] == '!' && !boot)
1839 boot = true;
1840 else if (action[pos] == '+' && !force)
1841 force = true;
1842 else {
1843 log_error("[%s:%u] Unknown modifiers in command '%s'",
1844 fname, line, action);
1845 return -EINVAL;
1846 }
1847 }
1848
1849 if (boot && !arg_boot) {
1850 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1851 action, path);
1852 return 0;
1853 }
1854
1855 i.type = action[0];
1856 i.force = force;
1857
1858 r = specifier_printf(path, specifier_table, NULL, &i.path);
1859 if (r < 0) {
1860 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1861 return r;
1862 }
1863
1864 switch (i.type) {
1865
1866 case CREATE_DIRECTORY:
1867 case CREATE_SUBVOLUME:
1868 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1869 case CREATE_SUBVOLUME_NEW_QUOTA:
1870 case TRUNCATE_DIRECTORY:
1871 case CREATE_FIFO:
1872 case IGNORE_PATH:
1873 case IGNORE_DIRECTORY_PATH:
1874 case REMOVE_PATH:
1875 case RECURSIVE_REMOVE_PATH:
1876 case ADJUST_MODE:
1877 case RELABEL_PATH:
1878 case RECURSIVE_RELABEL_PATH:
1879 if (i.argument)
1880 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname, line, i.type);
1881
1882 break;
1883
1884 case CREATE_FILE:
1885 case TRUNCATE_FILE:
1886 break;
1887
1888 case CREATE_SYMLINK:
1889 if (!i.argument) {
1890 i.argument = strappend("/usr/share/factory/", i.path);
1891 if (!i.argument)
1892 return log_oom();
1893 }
1894 break;
1895
1896 case WRITE_FILE:
1897 if (!i.argument) {
1898 log_error("[%s:%u] Write file requires argument.", fname, line);
1899 return -EBADMSG;
1900 }
1901 break;
1902
1903 case COPY_FILES:
1904 if (!i.argument) {
1905 i.argument = strappend("/usr/share/factory/", i.path);
1906 if (!i.argument)
1907 return log_oom();
1908 } else if (!path_is_absolute(i.argument)) {
1909 log_error("[%s:%u] Source path is not absolute.", fname, line);
1910 return -EBADMSG;
1911 }
1912
1913 path_kill_slashes(i.argument);
1914 break;
1915
1916 case CREATE_CHAR_DEVICE:
1917 case CREATE_BLOCK_DEVICE: {
1918 unsigned major, minor;
1919
1920 if (!i.argument) {
1921 log_error("[%s:%u] Device file requires argument.", fname, line);
1922 return -EBADMSG;
1923 }
1924
1925 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1926 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1927 return -EBADMSG;
1928 }
1929
1930 i.major_minor = makedev(major, minor);
1931 break;
1932 }
1933
1934 case SET_XATTR:
1935 case RECURSIVE_SET_XATTR:
1936 if (!i.argument) {
1937 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1938 return -EBADMSG;
1939 }
1940 r = parse_xattrs_from_arg(&i);
1941 if (r < 0)
1942 return r;
1943 break;
1944
1945 case SET_ACL:
1946 case RECURSIVE_SET_ACL:
1947 if (!i.argument) {
1948 log_error("[%s:%u] Set ACLs requires argument.", fname, line);
1949 return -EBADMSG;
1950 }
1951 r = parse_acls_from_arg(&i);
1952 if (r < 0)
1953 return r;
1954 break;
1955
1956 case SET_ATTRIBUTE:
1957 case RECURSIVE_SET_ATTRIBUTE:
1958 if (!i.argument) {
1959 log_error("[%s:%u] Set file attribute requires argument.", fname, line);
1960 return -EBADMSG;
1961 }
1962 r = parse_attribute_from_arg(&i);
1963 if (r < 0)
1964 return r;
1965 break;
1966
1967 default:
1968 log_error("[%s:%u] Unknown command type '%c'.", fname, line, (char) i.type);
1969 return -EBADMSG;
1970 }
1971
1972 if (!path_is_absolute(i.path)) {
1973 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1974 return -EBADMSG;
1975 }
1976
1977 path_kill_slashes(i.path);
1978
1979 if (!should_include_path(i.path))
1980 return 0;
1981
1982 if (arg_root) {
1983 char *p;
1984
1985 p = prefix_root(arg_root, i.path);
1986 if (!p)
1987 return log_oom();
1988
1989 free(i.path);
1990 i.path = p;
1991 }
1992
1993 if (!isempty(user) && !streq(user, "-")) {
1994 const char *u = user;
1995
1996 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1997 if (r < 0) {
1998 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1999 return r;
2000 }
2001
2002 i.uid_set = true;
2003 }
2004
2005 if (!isempty(group) && !streq(group, "-")) {
2006 const char *g = group;
2007
2008 r = get_group_creds(&g, &i.gid);
2009 if (r < 0) {
2010 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
2011 return r;
2012 }
2013
2014 i.gid_set = true;
2015 }
2016
2017 if (!isempty(mode) && !streq(mode, "-")) {
2018 const char *mm = mode;
2019 unsigned m;
2020
2021 if (*mm == '~') {
2022 i.mask_perms = true;
2023 mm++;
2024 }
2025
2026 if (parse_mode(mm, &m) < 0) {
2027 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
2028 return -EBADMSG;
2029 }
2030
2031 i.mode = m;
2032 i.mode_set = true;
2033 } else
2034 i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
2035
2036 if (!isempty(age) && !streq(age, "-")) {
2037 const char *a = age;
2038
2039 if (*a == '~') {
2040 i.keep_first_level = true;
2041 a++;
2042 }
2043
2044 if (parse_sec(a, &i.age) < 0) {
2045 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
2046 return -EBADMSG;
2047 }
2048
2049 i.age_set = true;
2050 }
2051
2052 h = needs_glob(i.type) ? globs : items;
2053
2054 existing = ordered_hashmap_get(h, i.path);
2055 if (existing) {
2056 unsigned n;
2057
2058 for (n = 0; n < existing->count; n++) {
2059 if (!item_compatible(existing->items + n, &i)) {
2060 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2061 fname, line, i.path);
2062 return 0;
2063 }
2064 }
2065 } else {
2066 existing = new0(ItemArray, 1);
2067 r = ordered_hashmap_put(h, i.path, existing);
2068 if (r < 0)
2069 return log_oom();
2070 }
2071
2072 if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
2073 return log_oom();
2074
2075 memcpy(existing->items + existing->count++, &i, sizeof(i));
2076
2077 /* Sort item array, to enforce stable ordering of application */
2078 qsort_safe(existing->items, existing->count, sizeof(Item), item_compare);
2079
2080 zero(i);
2081 return 0;
2082 }
2083
2084 static void help(void) {
2085 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2086 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2087 " -h --help Show this help\n"
2088 " --version Show package version\n"
2089 " --create Create marked files/directories\n"
2090 " --clean Clean up marked directories\n"
2091 " --remove Remove marked files/directories\n"
2092 " --boot Execute actions only safe at boot\n"
2093 " --prefix=PATH Only apply rules with the specified prefix\n"
2094 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2095 " --root=PATH Operate on an alternate filesystem root\n",
2096 program_invocation_short_name);
2097 }
2098
2099 static int parse_argv(int argc, char *argv[]) {
2100
2101 enum {
2102 ARG_VERSION = 0x100,
2103 ARG_CREATE,
2104 ARG_CLEAN,
2105 ARG_REMOVE,
2106 ARG_BOOT,
2107 ARG_PREFIX,
2108 ARG_EXCLUDE_PREFIX,
2109 ARG_ROOT,
2110 };
2111
2112 static const struct option options[] = {
2113 { "help", no_argument, NULL, 'h' },
2114 { "version", no_argument, NULL, ARG_VERSION },
2115 { "create", no_argument, NULL, ARG_CREATE },
2116 { "clean", no_argument, NULL, ARG_CLEAN },
2117 { "remove", no_argument, NULL, ARG_REMOVE },
2118 { "boot", no_argument, NULL, ARG_BOOT },
2119 { "prefix", required_argument, NULL, ARG_PREFIX },
2120 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
2121 { "root", required_argument, NULL, ARG_ROOT },
2122 {}
2123 };
2124
2125 int c, r;
2126
2127 assert(argc >= 0);
2128 assert(argv);
2129
2130 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
2131
2132 switch (c) {
2133
2134 case 'h':
2135 help();
2136 return 0;
2137
2138 case ARG_VERSION:
2139 return version();
2140
2141 case ARG_CREATE:
2142 arg_create = true;
2143 break;
2144
2145 case ARG_CLEAN:
2146 arg_clean = true;
2147 break;
2148
2149 case ARG_REMOVE:
2150 arg_remove = true;
2151 break;
2152
2153 case ARG_BOOT:
2154 arg_boot = true;
2155 break;
2156
2157 case ARG_PREFIX:
2158 if (strv_push(&arg_include_prefixes, optarg) < 0)
2159 return log_oom();
2160 break;
2161
2162 case ARG_EXCLUDE_PREFIX:
2163 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
2164 return log_oom();
2165 break;
2166
2167 case ARG_ROOT:
2168 r = parse_path_argument_and_warn(optarg, true, &arg_root);
2169 if (r < 0)
2170 return r;
2171 break;
2172
2173 case '?':
2174 return -EINVAL;
2175
2176 default:
2177 assert_not_reached("Unhandled option");
2178 }
2179
2180 if (!arg_clean && !arg_create && !arg_remove) {
2181 log_error("You need to specify at least one of --clean, --create or --remove.");
2182 return -EINVAL;
2183 }
2184
2185 return 1;
2186 }
2187
2188 static int read_config_file(const char *fn, bool ignore_enoent) {
2189 _cleanup_fclose_ FILE *f = NULL;
2190 char line[LINE_MAX];
2191 Iterator iterator;
2192 unsigned v = 0;
2193 Item *i;
2194 int r;
2195
2196 assert(fn);
2197
2198 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
2199 if (r < 0) {
2200 if (ignore_enoent && r == -ENOENT) {
2201 log_debug_errno(r, "Failed to open \"%s\": %m", fn);
2202 return 0;
2203 }
2204
2205 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
2206 }
2207 log_debug("Reading config file \"%s\".", fn);
2208
2209 FOREACH_LINE(line, f, break) {
2210 char *l;
2211 int k;
2212
2213 v++;
2214
2215 l = strstrip(line);
2216 if (*l == '#' || *l == 0)
2217 continue;
2218
2219 k = parse_line(fn, v, l);
2220 if (k < 0 && r == 0)
2221 r = k;
2222 }
2223
2224 /* we have to determine age parameter for each entry of type X */
2225 ORDERED_HASHMAP_FOREACH(i, globs, iterator) {
2226 Iterator iter;
2227 Item *j, *candidate_item = NULL;
2228
2229 if (i->type != IGNORE_DIRECTORY_PATH)
2230 continue;
2231
2232 ORDERED_HASHMAP_FOREACH(j, items, iter) {
2233 if (!IN_SET(j->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA))
2234 continue;
2235
2236 if (path_equal(j->path, i->path)) {
2237 candidate_item = j;
2238 break;
2239 }
2240
2241 if ((!candidate_item && path_startswith(i->path, j->path)) ||
2242 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
2243 candidate_item = j;
2244 }
2245
2246 if (candidate_item && candidate_item->age_set) {
2247 i->age = candidate_item->age;
2248 i->age_set = true;
2249 }
2250 }
2251
2252 if (ferror(f)) {
2253 log_error_errno(errno, "Failed to read from file %s: %m", fn);
2254 if (r == 0)
2255 r = -EIO;
2256 }
2257
2258 return r;
2259 }
2260
2261 int main(int argc, char *argv[]) {
2262 int r, k;
2263 ItemArray *a;
2264 Iterator iterator;
2265
2266 r = parse_argv(argc, argv);
2267 if (r <= 0)
2268 goto finish;
2269
2270 log_set_target(LOG_TARGET_AUTO);
2271 log_parse_environment();
2272 log_open();
2273
2274 umask(0022);
2275
2276 mac_selinux_init(NULL);
2277
2278 items = ordered_hashmap_new(&string_hash_ops);
2279 globs = ordered_hashmap_new(&string_hash_ops);
2280
2281 if (!items || !globs) {
2282 r = log_oom();
2283 goto finish;
2284 }
2285
2286 r = 0;
2287
2288 if (optind < argc) {
2289 int j;
2290
2291 for (j = optind; j < argc; j++) {
2292 k = read_config_file(argv[j], false);
2293 if (k < 0 && r == 0)
2294 r = k;
2295 }
2296
2297 } else {
2298 _cleanup_strv_free_ char **files = NULL;
2299 char **f;
2300
2301 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
2302 if (r < 0) {
2303 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
2304 goto finish;
2305 }
2306
2307 STRV_FOREACH(f, files) {
2308 k = read_config_file(*f, true);
2309 if (k < 0 && r == 0)
2310 r = k;
2311 }
2312 }
2313
2314 /* The non-globbing ones usually create things, hence we apply
2315 * them first */
2316 ORDERED_HASHMAP_FOREACH(a, items, iterator) {
2317 k = process_item_array(a);
2318 if (k < 0 && r == 0)
2319 r = k;
2320 }
2321
2322 /* The globbing ones usually alter things, hence we apply them
2323 * second. */
2324 ORDERED_HASHMAP_FOREACH(a, globs, iterator) {
2325 k = process_item_array(a);
2326 if (k < 0 && r == 0)
2327 r = k;
2328 }
2329
2330 finish:
2331 while ((a = ordered_hashmap_steal_first(items)))
2332 item_array_free(a);
2333
2334 while ((a = ordered_hashmap_steal_first(globs)))
2335 item_array_free(a);
2336
2337 ordered_hashmap_free(items);
2338 ordered_hashmap_free(globs);
2339
2340 free(arg_include_prefixes);
2341 free(arg_exclude_prefixes);
2342 free(arg_root);
2343
2344 set_free_free(unix_sockets);
2345
2346 mac_selinux_finish();
2347
2348 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2349 }