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