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