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