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