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