]> git.proxmox.com Git - systemd.git/blob - src/tmpfiles/tmpfiles.c
Imported Upstream version 219
[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
686 assert(item);
687
688 /* If force (= modify) is set, we will not modify the acl
689 * afterwards, so the mask can be added now if necessary. */
690 r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force);
691 if (r < 0)
692 log_warning_errno(errno, "Failed to parse ACL \"%s\": %m. Ignoring",
693 item->argument);
694 #else
695 log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring");
696 #endif
697
698 return 0;
699 }
700
701 #ifdef HAVE_ACL
702 static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) {
703 _cleanup_(acl_freep) acl_t dup = NULL;
704 int r;
705 _cleanup_(acl_free_charpp) char *t = NULL;
706
707 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 #endif
741
742 static int path_set_acls(Item *item, const char *path) {
743 #ifdef HAVE_ACL
744 int r;
745
746 assert(item);
747 assert(path);
748
749 if (item->acl_access) {
750 r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force);
751 if (r < 0)
752 return r;
753 }
754
755 if (item->acl_default) {
756 r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
757 if (r < 0)
758 return r;
759 }
760 #endif
761
762 return 0;
763 }
764
765 static int write_one_file(Item *i, const char *path) {
766 _cleanup_close_ int fd = -1;
767 int flags, r = 0;
768 struct stat st;
769
770 assert(i);
771 assert(path);
772
773 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
774 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
775
776 RUN_WITH_UMASK(0000) {
777 mac_selinux_create_file_prepare(path, S_IFREG);
778 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
779 mac_selinux_create_file_clear();
780 }
781
782 if (fd < 0) {
783 if (i->type == WRITE_FILE && errno == ENOENT) {
784 log_debug_errno(errno, "Not writing \"%s\": %m", path);
785 return 0;
786 }
787
788 log_error_errno(errno, "Failed to create file %s: %m", path);
789 return -errno;
790 }
791
792 if (i->argument) {
793 _cleanup_free_ char *unescaped;
794
795 log_debug("%s to \"%s\".",
796 i->type == CREATE_FILE ? "Appending" : "Writing", path);
797
798 unescaped = cunescape(i->argument);
799 if (!unescaped)
800 return log_oom();
801
802 r = loop_write(fd, unescaped, strlen(unescaped), false);
803 if (r < 0)
804 return log_error_errno(r, "Failed to write file \"%s\": %m", path);
805 } else
806 log_debug("\"%s\" has been created.", path);
807
808 fd = safe_close(fd);
809
810 if (stat(path, &st) < 0)
811 return log_error_errno(errno, "stat(%s) failed: %m", path);
812
813 if (!S_ISREG(st.st_mode)) {
814 log_error("%s is not a file.", path);
815 return -EEXIST;
816 }
817
818 r = path_set_perms(i, path);
819 if (r < 0)
820 return r;
821
822 return 0;
823 }
824
825 typedef int (*action_t)(Item *, const char *);
826
827 static int item_do_children(Item *i, const char *path, action_t action) {
828 _cleanup_closedir_ DIR *d;
829 int r = 0;
830
831 assert(i);
832 assert(path);
833
834 /* This returns the first error we run into, but nevertheless
835 * tries to go on */
836
837 d = opendir_nomod(path);
838 if (!d)
839 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
840
841 for (;;) {
842 _cleanup_free_ char *p = NULL;
843 struct dirent *de;
844 int q;
845
846 errno = 0;
847 de = readdir(d);
848 if (!de) {
849 if (errno != 0 && r == 0)
850 r = -errno;
851
852 break;
853 }
854
855 if (STR_IN_SET(de->d_name, ".", ".."))
856 continue;
857
858 p = strjoin(path, "/", de->d_name, NULL);
859 if (!p)
860 return -ENOMEM;
861
862 q = action(i, p);
863 if (q < 0 && q != -ENOENT && r == 0)
864 r = q;
865
866 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
867 q = item_do_children(i, p, action);
868 if (q < 0 && r == 0)
869 r = q;
870 }
871 }
872
873 return r;
874 }
875
876 static int glob_item(Item *i, action_t action, bool recursive) {
877 _cleanup_globfree_ glob_t g = {
878 .gl_closedir = (void (*)(void *)) closedir,
879 .gl_readdir = (struct dirent *(*)(void *)) readdir,
880 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
881 .gl_lstat = lstat,
882 .gl_stat = stat,
883 };
884 int r = 0, k;
885 char **fn;
886
887 errno = 0;
888 k = glob(i->path, GLOB_NOSORT|GLOB_BRACE|GLOB_ALTDIRFUNC, NULL, &g);
889 if (k != 0 && k != GLOB_NOMATCH)
890 return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
891
892 STRV_FOREACH(fn, g.gl_pathv) {
893 k = action(i, *fn);
894 if (k < 0 && r == 0)
895 r = k;
896
897 if (recursive) {
898 k = item_do_children(i, *fn, action);
899 if (k < 0 && r == 0)
900 r = k;
901 }
902 }
903
904 return r;
905 }
906
907 typedef enum {
908 CREATION_NORMAL,
909 CREATION_EXISTING,
910 CREATION_FORCE,
911 _CREATION_MODE_MAX,
912 _CREATION_MODE_INVALID = -1
913 } CreationMode;
914
915 static const char *creation_mode_verb_table[_CREATION_MODE_MAX] = {
916 [CREATION_NORMAL] = "Created",
917 [CREATION_EXISTING] = "Found existing",
918 [CREATION_FORCE] = "Created replacement",
919 };
920
921 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
922
923 static int create_item(Item *i) {
924 struct stat st;
925 int r = 0;
926 CreationMode creation;
927
928 assert(i);
929
930 log_debug("Running create action for entry %c %s", (char) i->type, i->path);
931
932 switch (i->type) {
933
934 case IGNORE_PATH:
935 case IGNORE_DIRECTORY_PATH:
936 case REMOVE_PATH:
937 case RECURSIVE_REMOVE_PATH:
938 return 0;
939
940 case CREATE_FILE:
941 case TRUNCATE_FILE:
942 r = write_one_file(i, i->path);
943 if (r < 0)
944 return r;
945 break;
946
947 case COPY_FILES:
948 log_debug("Copying tree \"%s\" to \"%s\".", i->argument, i->path);
949 r = copy_tree(i->argument, i->path, false);
950 if (r < 0) {
951 struct stat a, b;
952
953 if (r != -EEXIST)
954 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
955
956 if (stat(i->argument, &a) < 0)
957 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
958
959 if (stat(i->path, &b) < 0)
960 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
961
962 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
963 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
964 return 0;
965 }
966 }
967
968 r = path_set_perms(i, i->path);
969 if (r < 0)
970 return r;
971
972 break;
973
974 case WRITE_FILE:
975 r = glob_item(i, write_one_file, false);
976 if (r < 0)
977 return r;
978
979 break;
980
981 case CREATE_DIRECTORY:
982 case TRUNCATE_DIRECTORY:
983 case CREATE_SUBVOLUME:
984
985 RUN_WITH_UMASK(0000)
986 mkdir_parents_label(i->path, 0755);
987
988 if (i->type == CREATE_SUBVOLUME)
989 RUN_WITH_UMASK((~i->mode) & 0777) {
990 r = btrfs_subvol_make(i->path);
991 log_debug_errno(r, "Creating subvolume \"%s\": %m", i->path);
992 }
993 else
994 r = 0;
995
996 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY)
997 RUN_WITH_UMASK(0000)
998 r = mkdir_label(i->path, i->mode);
999
1000 if (r < 0) {
1001 if (r != -EEXIST)
1002 return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path);
1003
1004 if (stat(i->path, &st) < 0)
1005 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1006
1007 if (!S_ISDIR(st.st_mode)) {
1008 log_debug("\"%s\" already exists and is not a directory.", i->path);
1009 return 0;
1010 }
1011
1012 creation = CREATION_EXISTING;
1013 } else
1014 creation = CREATION_NORMAL;
1015 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path);
1016
1017 r = path_set_perms(i, i->path);
1018 if (r < 0)
1019 return r;
1020
1021 break;
1022
1023 case CREATE_FIFO:
1024
1025 RUN_WITH_UMASK(0000) {
1026 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1027 r = mkfifo(i->path, i->mode);
1028 mac_selinux_create_file_clear();
1029 }
1030
1031 if (r < 0) {
1032 if (errno != EEXIST)
1033 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
1034
1035 if (stat(i->path, &st) < 0)
1036 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1037
1038 if (!S_ISFIFO(st.st_mode)) {
1039
1040 if (i->force) {
1041
1042 RUN_WITH_UMASK(0000) {
1043 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1044 r = mkfifo_atomic(i->path, i->mode);
1045 mac_selinux_create_file_clear();
1046 }
1047
1048 if (r < 0)
1049 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
1050 creation = CREATION_FORCE;
1051 } else {
1052 log_debug("%s is not a fifo.", i->path);
1053 return 0;
1054 }
1055 } else
1056 creation = CREATION_EXISTING;
1057 } else
1058 creation = CREATION_NORMAL;
1059 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation), i->path);
1060
1061 r = path_set_perms(i, i->path);
1062 if (r < 0)
1063 return r;
1064
1065 break;
1066
1067 case CREATE_SYMLINK:
1068
1069 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1070 r = symlink(i->argument, i->path);
1071 mac_selinux_create_file_clear();
1072
1073 if (r < 0) {
1074 _cleanup_free_ char *x = NULL;
1075
1076 if (errno != EEXIST)
1077 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
1078
1079 r = readlink_malloc(i->path, &x);
1080 if (r < 0 || !streq(i->argument, x)) {
1081
1082 if (i->force) {
1083 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1084 r = symlink_atomic(i->argument, i->path);
1085 mac_selinux_create_file_clear();
1086
1087 if (r < 0)
1088 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
1089 creation = CREATION_FORCE;
1090 } else {
1091 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i->path);
1092 return 0;
1093 }
1094 } else
1095 creation = CREATION_EXISTING;
1096 } else
1097 creation = CREATION_NORMAL;
1098 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation), i->path);
1099
1100 break;
1101
1102 case CREATE_BLOCK_DEVICE:
1103 case CREATE_CHAR_DEVICE: {
1104 mode_t file_type;
1105
1106 if (have_effective_cap(CAP_MKNOD) == 0) {
1107 /* In a container we lack CAP_MKNOD. We
1108 shouldn't attempt to create the device node in
1109 that case to avoid noise, and we don't support
1110 virtualized devices in containers anyway. */
1111
1112 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
1113 return 0;
1114 }
1115
1116 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
1117
1118 RUN_WITH_UMASK(0000) {
1119 mac_selinux_create_file_prepare(i->path, file_type);
1120 r = mknod(i->path, i->mode | file_type, i->major_minor);
1121 mac_selinux_create_file_clear();
1122 }
1123
1124 if (r < 0) {
1125 if (errno == EPERM) {
1126 log_debug("We lack permissions, possibly because of cgroup configuration; "
1127 "skipping creation of device node %s.", i->path);
1128 return 0;
1129 }
1130
1131 if (errno != EEXIST)
1132 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
1133
1134 if (stat(i->path, &st) < 0)
1135 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1136
1137 if ((st.st_mode & S_IFMT) != file_type) {
1138
1139 if (i->force) {
1140
1141 RUN_WITH_UMASK(0000) {
1142 mac_selinux_create_file_prepare(i->path, file_type);
1143 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
1144 mac_selinux_create_file_clear();
1145 }
1146
1147 if (r < 0)
1148 return log_error_errno(r, "Failed to create device node \"%s\": %m", i->path);
1149 creation = CREATION_FORCE;
1150 } else {
1151 log_debug("%s is not a device node.", i->path);
1152 return 0;
1153 }
1154 } else
1155 creation = CREATION_EXISTING;
1156 } else
1157 creation = CREATION_NORMAL;
1158 log_debug("%s %s device node \"%s\" %u:%u.",
1159 creation_mode_verb_to_string(creation),
1160 i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
1161 i->path, major(i->mode), minor(i->mode));
1162
1163 r = path_set_perms(i, i->path);
1164 if (r < 0)
1165 return r;
1166
1167 break;
1168 }
1169
1170 case ADJUST_MODE:
1171 case RELABEL_PATH:
1172 r = glob_item(i, path_set_perms, false);
1173 if (r < 0)
1174 return r;
1175 break;
1176
1177 case RECURSIVE_RELABEL_PATH:
1178 r = glob_item(i, path_set_perms, true);
1179 if (r < 0)
1180 return r;
1181 break;
1182
1183 case SET_XATTR:
1184 r = glob_item(i, path_set_xattrs, false);
1185 if (r < 0)
1186 return r;
1187 break;
1188
1189 case RECURSIVE_SET_XATTR:
1190 r = glob_item(i, path_set_xattrs, true);
1191 if (r < 0)
1192 return r;
1193 break;
1194
1195 case SET_ACL:
1196 r = glob_item(i, path_set_acls, false);
1197 if (r < 0)
1198 return r;
1199 break;
1200
1201 case RECURSIVE_SET_ACL:
1202 r = glob_item(i, path_set_acls, true);
1203 if (r < 0)
1204 return r;
1205 break;
1206 }
1207
1208 log_debug("%s created successfully.", i->path);
1209
1210 return 0;
1211 }
1212
1213 static int remove_item_instance(Item *i, const char *instance) {
1214 int r;
1215
1216 assert(i);
1217
1218 switch (i->type) {
1219
1220 case REMOVE_PATH:
1221 if (remove(instance) < 0 && errno != ENOENT)
1222 return log_error_errno(errno, "rm(%s): %m", instance);
1223
1224 break;
1225
1226 case TRUNCATE_DIRECTORY:
1227 case RECURSIVE_REMOVE_PATH:
1228 /* FIXME: we probably should use dir_cleanup() here
1229 * instead of rm_rf() so that 'x' is honoured. */
1230 log_debug("rm -rf \"%s\"", instance);
1231 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1232 if (r < 0 && r != -ENOENT)
1233 return log_error_errno(r, "rm_rf(%s): %m", instance);
1234
1235 break;
1236
1237 default:
1238 assert_not_reached("wut?");
1239 }
1240
1241 return 0;
1242 }
1243
1244 static int remove_item(Item *i) {
1245 int r = 0;
1246
1247 assert(i);
1248
1249 log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
1250
1251 switch (i->type) {
1252
1253 case CREATE_FILE:
1254 case TRUNCATE_FILE:
1255 case CREATE_DIRECTORY:
1256 case CREATE_SUBVOLUME:
1257 case CREATE_FIFO:
1258 case CREATE_SYMLINK:
1259 case CREATE_CHAR_DEVICE:
1260 case CREATE_BLOCK_DEVICE:
1261 case IGNORE_PATH:
1262 case IGNORE_DIRECTORY_PATH:
1263 case ADJUST_MODE:
1264 case RELABEL_PATH:
1265 case RECURSIVE_RELABEL_PATH:
1266 case WRITE_FILE:
1267 case COPY_FILES:
1268 case SET_XATTR:
1269 case RECURSIVE_SET_XATTR:
1270 case SET_ACL:
1271 case RECURSIVE_SET_ACL:
1272 break;
1273
1274 case REMOVE_PATH:
1275 case TRUNCATE_DIRECTORY:
1276 case RECURSIVE_REMOVE_PATH:
1277 r = glob_item(i, remove_item_instance, false);
1278 break;
1279 }
1280
1281 return r;
1282 }
1283
1284 static int clean_item_instance(Item *i, const char* instance) {
1285 _cleanup_closedir_ DIR *d = NULL;
1286 struct stat s, ps;
1287 bool mountpoint;
1288 usec_t cutoff, n;
1289 char timestamp[FORMAT_TIMESTAMP_MAX];
1290
1291 assert(i);
1292
1293 if (!i->age_set)
1294 return 0;
1295
1296 n = now(CLOCK_REALTIME);
1297 if (n < i->age)
1298 return 0;
1299
1300 cutoff = n - i->age;
1301
1302 d = opendir_nomod(instance);
1303 if (!d) {
1304 if (errno == ENOENT || errno == ENOTDIR) {
1305 log_debug_errno(errno, "Directory \"%s\": %m", instance);
1306 return 0;
1307 }
1308
1309 log_error_errno(errno, "Failed to open directory %s: %m", instance);
1310 return -errno;
1311 }
1312
1313 if (fstat(dirfd(d), &s) < 0)
1314 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1315
1316 if (!S_ISDIR(s.st_mode)) {
1317 log_error("%s is not a directory.", i->path);
1318 return -ENOTDIR;
1319 }
1320
1321 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1322 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1323
1324 mountpoint = s.st_dev != ps.st_dev ||
1325 (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1326
1327 log_debug("Cleanup threshold for %s \"%s\" is %s",
1328 mountpoint ? "mount point" : "directory",
1329 instance,
1330 format_timestamp_us(timestamp, sizeof(timestamp), cutoff));
1331
1332 return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1333 MAX_DEPTH, i->keep_first_level);
1334 }
1335
1336 static int clean_item(Item *i) {
1337 int r = 0;
1338
1339 assert(i);
1340
1341 log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
1342
1343 switch (i->type) {
1344 case CREATE_DIRECTORY:
1345 case CREATE_SUBVOLUME:
1346 case TRUNCATE_DIRECTORY:
1347 case IGNORE_PATH:
1348 case COPY_FILES:
1349 clean_item_instance(i, i->path);
1350 break;
1351 case IGNORE_DIRECTORY_PATH:
1352 r = glob_item(i, clean_item_instance, false);
1353 break;
1354 default:
1355 break;
1356 }
1357
1358 return r;
1359 }
1360
1361 static int process_item_array(ItemArray *array);
1362
1363 static int process_item(Item *i) {
1364 int r, q, p, t = 0;
1365 _cleanup_free_ char *prefix = NULL;
1366
1367 assert(i);
1368
1369 if (i->done)
1370 return 0;
1371
1372 i->done = true;
1373
1374 prefix = malloc(strlen(i->path) + 1);
1375 if (!prefix)
1376 return log_oom();
1377
1378 PATH_FOREACH_PREFIX(prefix, i->path) {
1379 ItemArray *j;
1380
1381 j = hashmap_get(items, prefix);
1382 if (j) {
1383 int s;
1384
1385 s = process_item_array(j);
1386 if (s < 0 && t == 0)
1387 t = s;
1388 }
1389 }
1390
1391 r = arg_create ? create_item(i) : 0;
1392 q = arg_remove ? remove_item(i) : 0;
1393 p = arg_clean ? clean_item(i) : 0;
1394
1395 return t < 0 ? t :
1396 r < 0 ? r :
1397 q < 0 ? q :
1398 p;
1399 }
1400
1401 static int process_item_array(ItemArray *array) {
1402 unsigned n;
1403 int r = 0, k;
1404
1405 assert(array);
1406
1407 for (n = 0; n < array->count; n++) {
1408 k = process_item(array->items + n);
1409 if (k < 0 && r == 0)
1410 r = k;
1411 }
1412
1413 return r;
1414 }
1415
1416 static void item_free_contents(Item *i) {
1417 assert(i);
1418 free(i->path);
1419 free(i->argument);
1420 strv_free(i->xattrs);
1421
1422 #ifdef HAVE_ACL
1423 acl_free(i->acl_access);
1424 acl_free(i->acl_default);
1425 #endif
1426 }
1427
1428 static void item_array_free(ItemArray *a) {
1429 unsigned n;
1430
1431 if (!a)
1432 return;
1433
1434 for (n = 0; n < a->count; n++)
1435 item_free_contents(a->items + n);
1436 free(a->items);
1437 free(a);
1438 }
1439
1440 static bool item_compatible(Item *a, Item *b) {
1441 assert(a);
1442 assert(b);
1443 assert(streq(a->path, b->path));
1444
1445 if (takes_ownership(a->type) && takes_ownership(b->type))
1446 /* check if the items are the same */
1447 return streq_ptr(a->argument, b->argument) &&
1448
1449 a->uid_set == b->uid_set &&
1450 a->uid == b->uid &&
1451
1452 a->gid_set == b->gid_set &&
1453 a->gid == b->gid &&
1454
1455 a->mode_set == b->mode_set &&
1456 a->mode == b->mode &&
1457
1458 a->age_set == b->age_set &&
1459 a->age == b->age &&
1460
1461 a->mask_perms == b->mask_perms &&
1462
1463 a->keep_first_level == b->keep_first_level &&
1464
1465 a->major_minor == b->major_minor;
1466
1467 return true;
1468 }
1469
1470 static bool should_include_path(const char *path) {
1471 char **prefix;
1472
1473 STRV_FOREACH(prefix, arg_exclude_prefixes)
1474 if (path_startswith(path, *prefix)) {
1475 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1476 path, *prefix);
1477 return false;
1478 }
1479
1480 STRV_FOREACH(prefix, arg_include_prefixes)
1481 if (path_startswith(path, *prefix)) {
1482 log_debug("Entry \"%s\" matches include prefix \"%s\".", path, *prefix);
1483 return true;
1484 }
1485
1486 /* no matches, so we should include this path only if we
1487 * have no whitelist at all */
1488 if (strv_length(arg_include_prefixes) == 0)
1489 return true;
1490
1491 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path);
1492 return false;
1493 }
1494
1495 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1496
1497 static const Specifier specifier_table[] = {
1498 { 'm', specifier_machine_id, NULL },
1499 { 'b', specifier_boot_id, NULL },
1500 { 'H', specifier_host_name, NULL },
1501 { 'v', specifier_kernel_release, NULL },
1502 {}
1503 };
1504
1505 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1506 _cleanup_(item_free_contents) Item i = {};
1507 ItemArray *existing;
1508 Hashmap *h;
1509 int r, c = -1, pos;
1510 bool force = false, boot = false;
1511
1512 assert(fname);
1513 assert(line >= 1);
1514 assert(buffer);
1515
1516 r = sscanf(buffer,
1517 "%ms %ms %ms %ms %ms %ms %n",
1518 &action,
1519 &path,
1520 &mode,
1521 &user,
1522 &group,
1523 &age,
1524 &c);
1525 if (r < 2) {
1526 log_error("[%s:%u] Syntax error.", fname, line);
1527 return -EIO;
1528 }
1529
1530 if (isempty(action)) {
1531 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1532 return -EINVAL;
1533 }
1534
1535 for (pos = 1; action[pos]; pos++) {
1536 if (action[pos] == '!' && !boot)
1537 boot = true;
1538 else if (action[pos] == '+' && !force)
1539 force = true;
1540 else {
1541 log_error("[%s:%u] Unknown modifiers in command '%s'",
1542 fname, line, action);
1543 return -EINVAL;
1544 }
1545 }
1546
1547 if (boot && !arg_boot) {
1548 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1549 action, path);
1550 return 0;
1551 }
1552
1553 i.type = action[0];
1554 i.force = force;
1555
1556 r = specifier_printf(path, specifier_table, NULL, &i.path);
1557 if (r < 0) {
1558 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1559 return r;
1560 }
1561
1562 if (c >= 0) {
1563 c += strspn(buffer+c, WHITESPACE);
1564 if (buffer[c] != 0 && (buffer[c] != '-' || buffer[c+1] != 0)) {
1565 i.argument = unquote(buffer+c, "\"");
1566 if (!i.argument)
1567 return log_oom();
1568 }
1569 }
1570
1571 switch (i.type) {
1572
1573 case CREATE_FILE:
1574 case TRUNCATE_FILE:
1575 case CREATE_DIRECTORY:
1576 case CREATE_SUBVOLUME:
1577 case TRUNCATE_DIRECTORY:
1578 case CREATE_FIFO:
1579 case IGNORE_PATH:
1580 case IGNORE_DIRECTORY_PATH:
1581 case REMOVE_PATH:
1582 case RECURSIVE_REMOVE_PATH:
1583 case ADJUST_MODE:
1584 case RELABEL_PATH:
1585 case RECURSIVE_RELABEL_PATH:
1586 break;
1587
1588 case CREATE_SYMLINK:
1589 if (!i.argument) {
1590 i.argument = strappend("/usr/share/factory/", i.path);
1591 if (!i.argument)
1592 return log_oom();
1593 }
1594 break;
1595
1596 case WRITE_FILE:
1597 if (!i.argument) {
1598 log_error("[%s:%u] Write file requires argument.", fname, line);
1599 return -EBADMSG;
1600 }
1601 break;
1602
1603 case COPY_FILES:
1604 if (!i.argument) {
1605 i.argument = strappend("/usr/share/factory/", i.path);
1606 if (!i.argument)
1607 return log_oom();
1608 } else if (!path_is_absolute(i.argument)) {
1609 log_error("[%s:%u] Source path is not absolute.", fname, line);
1610 return -EBADMSG;
1611 }
1612
1613 path_kill_slashes(i.argument);
1614 break;
1615
1616 case CREATE_CHAR_DEVICE:
1617 case CREATE_BLOCK_DEVICE: {
1618 unsigned major, minor;
1619
1620 if (!i.argument) {
1621 log_error("[%s:%u] Device file requires argument.", fname, line);
1622 return -EBADMSG;
1623 }
1624
1625 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1626 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1627 return -EBADMSG;
1628 }
1629
1630 i.major_minor = makedev(major, minor);
1631 break;
1632 }
1633
1634 case SET_XATTR:
1635 case RECURSIVE_SET_XATTR:
1636 if (!i.argument) {
1637 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1638 return -EBADMSG;
1639 }
1640 r = get_xattrs_from_arg(&i);
1641 if (r < 0)
1642 return r;
1643 break;
1644
1645 case SET_ACL:
1646 case RECURSIVE_SET_ACL:
1647 if (!i.argument) {
1648 log_error("[%s:%u] Set ACLs requires argument.", fname, line);
1649 return -EBADMSG;
1650 }
1651 r = get_acls_from_arg(&i);
1652 if (r < 0)
1653 return r;
1654 break;
1655
1656 default:
1657 log_error("[%s:%u] Unknown command type '%c'.", fname, line, (char) i.type);
1658 return -EBADMSG;
1659 }
1660
1661 if (!path_is_absolute(i.path)) {
1662 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1663 return -EBADMSG;
1664 }
1665
1666 path_kill_slashes(i.path);
1667
1668 if (!should_include_path(i.path))
1669 return 0;
1670
1671 if (arg_root) {
1672 char *p;
1673
1674 p = strappend(arg_root, i.path);
1675 if (!p)
1676 return log_oom();
1677
1678 free(i.path);
1679 i.path = p;
1680 }
1681
1682 if (user && !streq(user, "-")) {
1683 const char *u = user;
1684
1685 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1686 if (r < 0) {
1687 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1688 return r;
1689 }
1690
1691 i.uid_set = true;
1692 }
1693
1694 if (group && !streq(group, "-")) {
1695 const char *g = group;
1696
1697 r = get_group_creds(&g, &i.gid);
1698 if (r < 0) {
1699 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1700 return r;
1701 }
1702
1703 i.gid_set = true;
1704 }
1705
1706 if (mode && !streq(mode, "-")) {
1707 const char *mm = mode;
1708 unsigned m;
1709
1710 if (*mm == '~') {
1711 i.mask_perms = true;
1712 mm++;
1713 }
1714
1715 if (sscanf(mm, "%o", &m) != 1) {
1716 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1717 return -ENOENT;
1718 }
1719
1720 i.mode = m;
1721 i.mode_set = true;
1722 } else
1723 i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
1724 ? 0755 : 0644;
1725
1726 if (age && !streq(age, "-")) {
1727 const char *a = age;
1728
1729 if (*a == '~') {
1730 i.keep_first_level = true;
1731 a++;
1732 }
1733
1734 if (parse_sec(a, &i.age) < 0) {
1735 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1736 return -EBADMSG;
1737 }
1738
1739 i.age_set = true;
1740 }
1741
1742 h = needs_glob(i.type) ? globs : items;
1743
1744 existing = hashmap_get(h, i.path);
1745 if (existing) {
1746 unsigned n;
1747
1748 for (n = 0; n < existing->count; n++) {
1749 if (!item_compatible(existing->items + n, &i))
1750 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1751 fname, line, i.path);
1752 }
1753 } else {
1754 existing = new0(ItemArray, 1);
1755 r = hashmap_put(h, i.path, existing);
1756 if (r < 0)
1757 return log_oom();
1758 }
1759
1760 if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
1761 return log_oom();
1762
1763 memcpy(existing->items + existing->count++, &i, sizeof(i));
1764 zero(i);
1765 return 0;
1766 }
1767
1768 static void help(void) {
1769 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1770 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1771 " -h --help Show this help\n"
1772 " --version Show package version\n"
1773 " --create Create marked files/directories\n"
1774 " --clean Clean up marked directories\n"
1775 " --remove Remove marked files/directories\n"
1776 " --boot Execute actions only safe at boot\n"
1777 " --prefix=PATH Only apply rules with the specified prefix\n"
1778 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
1779 " --root=PATH Operate on an alternate filesystem root\n",
1780 program_invocation_short_name);
1781 }
1782
1783 static int parse_argv(int argc, char *argv[]) {
1784
1785 enum {
1786 ARG_VERSION = 0x100,
1787 ARG_CREATE,
1788 ARG_CLEAN,
1789 ARG_REMOVE,
1790 ARG_BOOT,
1791 ARG_PREFIX,
1792 ARG_EXCLUDE_PREFIX,
1793 ARG_ROOT,
1794 };
1795
1796 static const struct option options[] = {
1797 { "help", no_argument, NULL, 'h' },
1798 { "version", no_argument, NULL, ARG_VERSION },
1799 { "create", no_argument, NULL, ARG_CREATE },
1800 { "clean", no_argument, NULL, ARG_CLEAN },
1801 { "remove", no_argument, NULL, ARG_REMOVE },
1802 { "boot", no_argument, NULL, ARG_BOOT },
1803 { "prefix", required_argument, NULL, ARG_PREFIX },
1804 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
1805 { "root", required_argument, NULL, ARG_ROOT },
1806 {}
1807 };
1808
1809 int c;
1810
1811 assert(argc >= 0);
1812 assert(argv);
1813
1814 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1815
1816 switch (c) {
1817
1818 case 'h':
1819 help();
1820 return 0;
1821
1822 case ARG_VERSION:
1823 puts(PACKAGE_STRING);
1824 puts(SYSTEMD_FEATURES);
1825 return 0;
1826
1827 case ARG_CREATE:
1828 arg_create = true;
1829 break;
1830
1831 case ARG_CLEAN:
1832 arg_clean = true;
1833 break;
1834
1835 case ARG_REMOVE:
1836 arg_remove = true;
1837 break;
1838
1839 case ARG_BOOT:
1840 arg_boot = true;
1841 break;
1842
1843 case ARG_PREFIX:
1844 if (strv_push(&arg_include_prefixes, optarg) < 0)
1845 return log_oom();
1846 break;
1847
1848 case ARG_EXCLUDE_PREFIX:
1849 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1850 return log_oom();
1851 break;
1852
1853 case ARG_ROOT:
1854 free(arg_root);
1855 arg_root = path_make_absolute_cwd(optarg);
1856 if (!arg_root)
1857 return log_oom();
1858
1859 path_kill_slashes(arg_root);
1860 break;
1861
1862 case '?':
1863 return -EINVAL;
1864
1865 default:
1866 assert_not_reached("Unhandled option");
1867 }
1868
1869 if (!arg_clean && !arg_create && !arg_remove) {
1870 log_error("You need to specify at least one of --clean, --create or --remove.");
1871 return -EINVAL;
1872 }
1873
1874 return 1;
1875 }
1876
1877 static int read_config_file(const char *fn, bool ignore_enoent) {
1878 _cleanup_fclose_ FILE *f = NULL;
1879 char line[LINE_MAX];
1880 Iterator iterator;
1881 unsigned v = 0;
1882 Item *i;
1883 int r;
1884
1885 assert(fn);
1886
1887 r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1888 if (r < 0) {
1889 if (ignore_enoent && r == -ENOENT) {
1890 log_debug_errno(r, "Failed to open \"%s\": %m", fn);
1891 return 0;
1892 }
1893
1894 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1895 }
1896 log_debug("Reading config file \"%s\".", fn);
1897
1898 FOREACH_LINE(line, f, break) {
1899 char *l;
1900 int k;
1901
1902 v++;
1903
1904 l = strstrip(line);
1905 if (*l == '#' || *l == 0)
1906 continue;
1907
1908 k = parse_line(fn, v, l);
1909 if (k < 0 && r == 0)
1910 r = k;
1911 }
1912
1913 /* we have to determine age parameter for each entry of type X */
1914 HASHMAP_FOREACH(i, globs, iterator) {
1915 Iterator iter;
1916 Item *j, *candidate_item = NULL;
1917
1918 if (i->type != IGNORE_DIRECTORY_PATH)
1919 continue;
1920
1921 HASHMAP_FOREACH(j, items, iter) {
1922 if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1923 continue;
1924
1925 if (path_equal(j->path, i->path)) {
1926 candidate_item = j;
1927 break;
1928 }
1929
1930 if ((!candidate_item && path_startswith(i->path, j->path)) ||
1931 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1932 candidate_item = j;
1933 }
1934
1935 if (candidate_item && candidate_item->age_set) {
1936 i->age = candidate_item->age;
1937 i->age_set = true;
1938 }
1939 }
1940
1941 if (ferror(f)) {
1942 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1943 if (r == 0)
1944 r = -EIO;
1945 }
1946
1947 return r;
1948 }
1949
1950 int main(int argc, char *argv[]) {
1951 int r, k;
1952 ItemArray *a;
1953 Iterator iterator;
1954
1955 r = parse_argv(argc, argv);
1956 if (r <= 0)
1957 goto finish;
1958
1959 log_set_target(LOG_TARGET_AUTO);
1960 log_parse_environment();
1961 log_open();
1962
1963 umask(0022);
1964
1965 mac_selinux_init(NULL);
1966
1967 items = hashmap_new(&string_hash_ops);
1968 globs = hashmap_new(&string_hash_ops);
1969
1970 if (!items || !globs) {
1971 r = log_oom();
1972 goto finish;
1973 }
1974
1975 r = 0;
1976
1977 if (optind < argc) {
1978 int j;
1979
1980 for (j = optind; j < argc; j++) {
1981 k = read_config_file(argv[j], false);
1982 if (k < 0 && r == 0)
1983 r = k;
1984 }
1985
1986 } else {
1987 _cleanup_strv_free_ char **files = NULL;
1988 char **f;
1989
1990 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1991 if (r < 0) {
1992 log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1993 goto finish;
1994 }
1995
1996 STRV_FOREACH(f, files) {
1997 k = read_config_file(*f, true);
1998 if (k < 0 && r == 0)
1999 r = k;
2000 }
2001 }
2002
2003 HASHMAP_FOREACH(a, globs, iterator) {
2004 k = process_item_array(a);
2005 if (k < 0 && r == 0)
2006 r = k;
2007 }
2008
2009 HASHMAP_FOREACH(a, items, iterator) {
2010 k = process_item_array(a);
2011 if (k < 0 && r == 0)
2012 r = k;
2013 }
2014
2015 finish:
2016 while ((a = hashmap_steal_first(items)))
2017 item_array_free(a);
2018
2019 while ((a = hashmap_steal_first(globs)))
2020 item_array_free(a);
2021
2022 hashmap_free(items);
2023 hashmap_free(globs);
2024
2025 free(arg_include_prefixes);
2026 free(arg_exclude_prefixes);
2027 free(arg_root);
2028
2029 set_free_free(unix_sockets);
2030
2031 mac_selinux_finish();
2032
2033 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2034 }