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