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