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