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