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