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