]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/tmpfiles/tmpfiles.c
tmpfiles: age root-owned read-only files, by default (#7917)
[thirdparty/systemd.git] / src / tmpfiles / tmpfiles.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering, Kay Sievers
6 Copyright 2015 Zbigniew Jędrzejewski-Szmek
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <fnmatch.h>
25 #include <getopt.h>
26 #include <glob.h>
27 #include <limits.h>
28 #include <linux/fs.h>
29 #include <stdbool.h>
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/stat.h>
35 #include <sys/xattr.h>
36 #include <sysexits.h>
37 #include <time.h>
38 #include <unistd.h>
39
40 #include "sd-path.h"
41
42 #include "acl-util.h"
43 #include "alloc-util.h"
44 #include "btrfs-util.h"
45 #include "capability-util.h"
46 #include "chattr-util.h"
47 #include "conf-files.h"
48 #include "copy.h"
49 #include "def.h"
50 #include "dirent-util.h"
51 #include "escape.h"
52 #include "fd-util.h"
53 #include "fileio.h"
54 #include "format-util.h"
55 #include "fs-util.h"
56 #include "glob-util.h"
57 #include "io-util.h"
58 #include "label.h"
59 #include "log.h"
60 #include "macro.h"
61 #include "missing.h"
62 #include "mkdir.h"
63 #include "mount-util.h"
64 #include "parse-util.h"
65 #include "path-lookup.h"
66 #include "path-util.h"
67 #include "rm-rf.h"
68 #include "selinux-util.h"
69 #include "set.h"
70 #include "specifier.h"
71 #include "stat-util.h"
72 #include "stdio-util.h"
73 #include "string-table.h"
74 #include "string-util.h"
75 #include "strv.h"
76 #include "umask-util.h"
77 #include "user-util.h"
78 #include "util.h"
79
80 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
81 * them in the file system. This is intended to be used to create
82 * properly owned directories beneath /tmp, /var/tmp, /run, which are
83 * volatile and hence need to be recreated on bootup. */
84
85 typedef enum ItemType {
86 /* These ones take file names */
87 CREATE_FILE = 'f',
88 TRUNCATE_FILE = 'F',
89 CREATE_DIRECTORY = 'd',
90 TRUNCATE_DIRECTORY = 'D',
91 CREATE_SUBVOLUME = 'v',
92 CREATE_SUBVOLUME_INHERIT_QUOTA = 'q',
93 CREATE_SUBVOLUME_NEW_QUOTA = 'Q',
94 CREATE_FIFO = 'p',
95 CREATE_SYMLINK = 'L',
96 CREATE_CHAR_DEVICE = 'c',
97 CREATE_BLOCK_DEVICE = 'b',
98 COPY_FILES = 'C',
99
100 /* These ones take globs */
101 WRITE_FILE = 'w',
102 EMPTY_DIRECTORY = 'e',
103 SET_XATTR = 't',
104 RECURSIVE_SET_XATTR = 'T',
105 SET_ACL = 'a',
106 RECURSIVE_SET_ACL = 'A',
107 SET_ATTRIBUTE = 'h',
108 RECURSIVE_SET_ATTRIBUTE = 'H',
109 IGNORE_PATH = 'x',
110 IGNORE_DIRECTORY_PATH = 'X',
111 REMOVE_PATH = 'r',
112 RECURSIVE_REMOVE_PATH = 'R',
113 RELABEL_PATH = 'z',
114 RECURSIVE_RELABEL_PATH = 'Z',
115 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
116 } ItemType;
117
118 typedef struct Item {
119 ItemType type;
120
121 char *path;
122 char *argument;
123 char **xattrs;
124 #if HAVE_ACL
125 acl_t acl_access;
126 acl_t acl_default;
127 #endif
128 uid_t uid;
129 gid_t gid;
130 mode_t mode;
131 usec_t age;
132
133 dev_t major_minor;
134 unsigned attribute_value;
135 unsigned attribute_mask;
136
137 bool uid_set:1;
138 bool gid_set:1;
139 bool mode_set:1;
140 bool age_set:1;
141 bool mask_perms:1;
142 bool attribute_set:1;
143
144 bool keep_first_level:1;
145
146 bool force:1;
147
148 bool done:1;
149 } Item;
150
151 typedef struct ItemArray {
152 Item *items;
153 size_t count;
154 size_t size;
155 } ItemArray;
156
157 typedef enum DirectoryType {
158 DIRECTORY_RUNTIME = 0,
159 DIRECTORY_STATE,
160 DIRECTORY_CACHE,
161 DIRECTORY_LOGS,
162 _DIRECTORY_TYPE_MAX,
163 } DirectoryType;
164
165 static bool arg_user = false;
166 static bool arg_create = false;
167 static bool arg_clean = false;
168 static bool arg_remove = false;
169 static bool arg_boot = false;
170
171 static char **arg_include_prefixes = NULL;
172 static char **arg_exclude_prefixes = NULL;
173 static char *arg_root = NULL;
174 static char *arg_replace = NULL;
175
176 #define MAX_DEPTH 256
177
178 static OrderedHashmap *items = NULL, *globs = NULL;
179 static Set *unix_sockets = NULL;
180
181 static int specifier_machine_id_safe(char specifier, void *data, void *userdata, char **ret);
182 static int specifier_directory(char specifier, void *data, void *userdata, char **ret);
183
184 static const Specifier specifier_table[] = {
185 { 'm', specifier_machine_id_safe, NULL },
186 { 'b', specifier_boot_id, NULL },
187 { 'H', specifier_host_name, NULL },
188 { 'v', specifier_kernel_release, NULL },
189
190 { 'U', specifier_user_id, NULL },
191 { 'u', specifier_user_name, NULL },
192 { 'h', specifier_user_home, NULL },
193 { 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) },
194 { 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) },
195 { 'C', specifier_directory, UINT_TO_PTR(DIRECTORY_CACHE) },
196 { 'L', specifier_directory, UINT_TO_PTR(DIRECTORY_LOGS) },
197 {}
198 };
199
200 static int specifier_machine_id_safe(char specifier, void *data, void *userdata, char **ret) {
201 int r;
202
203 /* If /etc/machine_id is missing or empty (e.g. in a chroot environment)
204 * return a recognizable error so that the caller can skip the rule
205 * gracefully. */
206
207 r = specifier_machine_id(specifier, data, userdata, ret);
208 if (IN_SET(r, -ENOENT, -ENOMEDIUM))
209 return -ENXIO;
210
211 return r;
212 }
213
214 static int specifier_directory(char specifier, void *data, void *userdata, char **ret) {
215 struct table_entry {
216 uint64_t type;
217 const char *suffix;
218 };
219
220 static const struct table_entry paths_system[] = {
221 [DIRECTORY_RUNTIME] = { SD_PATH_SYSTEM_RUNTIME },
222 [DIRECTORY_STATE] = { SD_PATH_SYSTEM_STATE_PRIVATE },
223 [DIRECTORY_CACHE] = { SD_PATH_SYSTEM_STATE_CACHE },
224 [DIRECTORY_LOGS] = { SD_PATH_SYSTEM_STATE_LOGS },
225 };
226
227 static const struct table_entry paths_user[] = {
228 [DIRECTORY_RUNTIME] = { SD_PATH_USER_RUNTIME },
229 [DIRECTORY_STATE] = { SD_PATH_USER_CONFIGURATION },
230 [DIRECTORY_CACHE] = { SD_PATH_USER_STATE_CACHE },
231 [DIRECTORY_LOGS] = { SD_PATH_USER_CONFIGURATION, "log" },
232 };
233
234 unsigned i;
235 const struct table_entry *paths;
236
237 assert_cc(ELEMENTSOF(paths_system) == ELEMENTSOF(paths_user));
238 paths = arg_user ? paths_user : paths_system;
239
240 i = PTR_TO_UINT(data);
241 assert(i < ELEMENTSOF(paths_system));
242
243 return sd_path_home(paths[i].type, paths[i].suffix, ret);
244 }
245
246 static int log_unresolvable_specifier(const char *filename, unsigned line) {
247 static bool notified = false;
248
249 /* In system mode, this is called when /etc is not fully initialized (e.g.
250 * in a chroot environment) where some specifiers are unresolvable. In user
251 * mode, this is called when some variables are not defined. These cases are
252 * not considered as an error so log at LOG_NOTICE only for the first time
253 * and then downgrade this to LOG_DEBUG for the rest. */
254
255 log_full(notified ? LOG_DEBUG : LOG_NOTICE,
256 "[%s:%u] Failed to resolve specifier: %s, skipping",
257 filename, line,
258 arg_user ? "Required $XDG_... variable not defined" : "uninitialized /etc detected");
259
260 if (!notified)
261 log_notice("All rules containing unresolvable specifiers will be skipped.");
262
263 notified = true;
264 return 0;
265 }
266
267 static int user_config_paths(char*** ret) {
268 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
269 _cleanup_free_ char *persistent_config = NULL, *runtime_config = NULL, *data_home = NULL;
270 _cleanup_strv_free_ char **res = NULL;
271 int r;
272
273 r = xdg_user_dirs(&config_dirs, &data_dirs);
274 if (r < 0)
275 return r;
276
277 r = xdg_user_config_dir(&persistent_config, "/user-tmpfiles.d");
278 if (r < 0 && r != -ENXIO)
279 return r;
280
281 r = xdg_user_runtime_dir(&runtime_config, "/user-tmpfiles.d");
282 if (r < 0 && r != -ENXIO)
283 return r;
284
285 r = xdg_user_data_dir(&data_home, "/user-tmpfiles.d");
286 if (r < 0 && r != -ENXIO)
287 return r;
288
289 r = strv_extend_strv_concat(&res, config_dirs, "/user-tmpfiles.d");
290 if (r < 0)
291 return r;
292
293 r = strv_extend(&res, persistent_config);
294 if (r < 0)
295 return r;
296
297 r = strv_extend(&res, runtime_config);
298 if (r < 0)
299 return r;
300
301 r = strv_extend(&res, data_home);
302 if (r < 0)
303 return r;
304
305 r = strv_extend_strv_concat(&res, data_dirs, "/user-tmpfiles.d");
306 if (r < 0)
307 return r;
308
309 r = path_strv_make_absolute_cwd(res);
310 if (r < 0)
311 return r;
312
313 *ret = res;
314 res = NULL;
315 return 0;
316 }
317
318 static bool needs_glob(ItemType t) {
319 return IN_SET(t,
320 WRITE_FILE,
321 IGNORE_PATH,
322 IGNORE_DIRECTORY_PATH,
323 REMOVE_PATH,
324 RECURSIVE_REMOVE_PATH,
325 EMPTY_DIRECTORY,
326 ADJUST_MODE,
327 RELABEL_PATH,
328 RECURSIVE_RELABEL_PATH,
329 SET_XATTR,
330 RECURSIVE_SET_XATTR,
331 SET_ACL,
332 RECURSIVE_SET_ACL,
333 SET_ATTRIBUTE,
334 RECURSIVE_SET_ATTRIBUTE);
335 }
336
337 static bool takes_ownership(ItemType t) {
338 return IN_SET(t,
339 CREATE_FILE,
340 TRUNCATE_FILE,
341 CREATE_DIRECTORY,
342 EMPTY_DIRECTORY,
343 TRUNCATE_DIRECTORY,
344 CREATE_SUBVOLUME,
345 CREATE_SUBVOLUME_INHERIT_QUOTA,
346 CREATE_SUBVOLUME_NEW_QUOTA,
347 CREATE_FIFO,
348 CREATE_SYMLINK,
349 CREATE_CHAR_DEVICE,
350 CREATE_BLOCK_DEVICE,
351 COPY_FILES,
352 WRITE_FILE,
353 IGNORE_PATH,
354 IGNORE_DIRECTORY_PATH,
355 REMOVE_PATH,
356 RECURSIVE_REMOVE_PATH);
357 }
358
359 static struct Item* find_glob(OrderedHashmap *h, const char *match) {
360 ItemArray *j;
361 Iterator i;
362
363 ORDERED_HASHMAP_FOREACH(j, h, i) {
364 unsigned n;
365
366 for (n = 0; n < j->count; n++) {
367 Item *item = j->items + n;
368
369 if (fnmatch(item->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
370 return item;
371 }
372 }
373
374 return NULL;
375 }
376
377 static void load_unix_sockets(void) {
378 _cleanup_fclose_ FILE *f = NULL;
379 int r;
380
381 if (unix_sockets)
382 return;
383
384 /* We maintain a cache of the sockets we found in /proc/net/unix to speed things up a little. */
385
386 unix_sockets = set_new(&string_hash_ops);
387 if (!unix_sockets)
388 return;
389
390 f = fopen("/proc/net/unix", "re");
391 if (!f) {
392 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
393 "Failed to open /proc/net/unix, ignoring: %m");
394 goto fail;
395 }
396
397 /* Skip header */
398 r = read_line(f, LONG_LINE_MAX, NULL);
399 if (r < 0) {
400 log_warning_errno(r, "Failed to skip /proc/net/unix header line: %m");
401 goto fail;
402 }
403 if (r == 0) {
404 log_warning("Premature end of file reading /proc/net/unix.");
405 goto fail;
406 }
407
408 for (;;) {
409 _cleanup_free_ char *line = NULL;
410 char *p, *s;
411
412 r = read_line(f, LONG_LINE_MAX, &line);
413 if (r < 0) {
414 log_warning_errno(r, "Failed to read /proc/net/unix line, ignoring: %m");
415 goto fail;
416 }
417 if (r == 0) /* EOF */
418 break;
419
420 p = strchr(line, ':');
421 if (!p)
422 continue;
423
424 if (strlen(p) < 37)
425 continue;
426
427 p += 37;
428 p += strspn(p, WHITESPACE);
429 p += strcspn(p, WHITESPACE); /* skip one more word */
430 p += strspn(p, WHITESPACE);
431
432 if (*p != '/')
433 continue;
434
435 s = strdup(p);
436 if (!s) {
437 log_oom();
438 goto fail;
439 }
440
441 path_kill_slashes(s);
442
443 r = set_consume(unix_sockets, s);
444 if (r < 0 && r != -EEXIST) {
445 log_warning_errno(r, "Failed to add AF_UNIX socket to set, ignoring: %m");
446 goto fail;
447 }
448 }
449
450 return;
451
452 fail:
453 unix_sockets = set_free_free(unix_sockets);
454 }
455
456 static bool unix_socket_alive(const char *fn) {
457 assert(fn);
458
459 load_unix_sockets();
460
461 if (unix_sockets)
462 return !!set_get(unix_sockets, (char*) fn);
463
464 /* We don't know, so assume yes */
465 return true;
466 }
467
468 static int dir_is_mount_point(DIR *d, const char *subdir) {
469
470 int mount_id_parent, mount_id;
471 int r_p, r;
472
473 r_p = name_to_handle_at_loop(dirfd(d), ".", NULL, &mount_id_parent, 0);
474 if (r_p < 0)
475 r_p = -errno;
476
477 r = name_to_handle_at_loop(dirfd(d), subdir, NULL, &mount_id, 0);
478 if (r < 0)
479 r = -errno;
480
481 /* got no handle; make no assumptions, return error */
482 if (r_p < 0 && r < 0)
483 return r_p;
484
485 /* got both handles; if they differ, it is a mount point */
486 if (r_p >= 0 && r >= 0)
487 return mount_id_parent != mount_id;
488
489 /* got only one handle; assume different mount points if one
490 * of both queries was not supported by the filesystem */
491 if (IN_SET(r_p, -ENOSYS, -EOPNOTSUPP) || IN_SET(r, -ENOSYS, -EOPNOTSUPP))
492 return true;
493
494 /* return error */
495 if (r_p < 0)
496 return r_p;
497 return r;
498 }
499
500 static DIR* xopendirat_nomod(int dirfd, const char *path) {
501 DIR *dir;
502
503 dir = xopendirat(dirfd, path, O_NOFOLLOW|O_NOATIME);
504 if (dir)
505 return dir;
506
507 log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m", dirfd == AT_FDCWD ? "" : "sub", path);
508 if (errno != EPERM)
509 return NULL;
510
511 dir = xopendirat(dirfd, path, O_NOFOLLOW);
512 if (!dir)
513 log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m", dirfd == AT_FDCWD ? "" : "sub", path);
514
515 return dir;
516 }
517
518 static DIR* opendir_nomod(const char *path) {
519 return xopendirat_nomod(AT_FDCWD, path);
520 }
521
522 static int dir_cleanup(
523 Item *i,
524 const char *p,
525 DIR *d,
526 const struct stat *ds,
527 usec_t cutoff,
528 dev_t rootdev,
529 bool mountpoint,
530 int maxdepth,
531 bool keep_this_level) {
532
533 struct dirent *dent;
534 struct timespec times[2];
535 bool deleted = false;
536 int r = 0;
537
538 FOREACH_DIRENT_ALL(dent, d, break) {
539 struct stat s;
540 usec_t age;
541 _cleanup_free_ char *sub_path = NULL;
542
543 if (dot_or_dot_dot(dent->d_name))
544 continue;
545
546 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
547 if (errno == ENOENT)
548 continue;
549
550 /* FUSE, NFS mounts, SELinux might return EACCES */
551 r = log_full_errno(errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
552 "stat(%s/%s) failed: %m", p, dent->d_name);
553 continue;
554 }
555
556 /* Stay on the same filesystem */
557 if (s.st_dev != rootdev) {
558 log_debug("Ignoring \"%s/%s\": different filesystem.", p, dent->d_name);
559 continue;
560 }
561
562 /* Try to detect bind mounts of the same filesystem instance; they
563 * do not differ in device major/minors. This type of query is not
564 * supported on all kernels or filesystem types though. */
565 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0) {
566 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
567 p, dent->d_name);
568 continue;
569 }
570
571 sub_path = strjoin(p, "/", dent->d_name);
572 if (!sub_path) {
573 r = log_oom();
574 goto finish;
575 }
576
577 /* Is there an item configured for this path? */
578 if (ordered_hashmap_get(items, sub_path)) {
579 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path);
580 continue;
581 }
582
583 if (find_glob(globs, sub_path)) {
584 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path);
585 continue;
586 }
587
588 if (S_ISDIR(s.st_mode)) {
589
590 if (mountpoint &&
591 streq(dent->d_name, "lost+found") &&
592 s.st_uid == 0) {
593 log_debug("Ignoring \"%s\".", sub_path);
594 continue;
595 }
596
597 if (maxdepth <= 0)
598 log_warning("Reached max depth on \"%s\".", sub_path);
599 else {
600 _cleanup_closedir_ DIR *sub_dir;
601 int q;
602
603 sub_dir = xopendirat_nomod(dirfd(d), dent->d_name);
604 if (!sub_dir) {
605 if (errno != ENOENT)
606 r = log_error_errno(errno, "opendir(%s) failed: %m", sub_path);
607
608 continue;
609 }
610
611 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
612 if (q < 0)
613 r = q;
614 }
615
616 /* Note: if you are wondering why we don't
617 * support the sticky bit for excluding
618 * directories from cleaning like we do it for
619 * other file system objects: well, the sticky
620 * bit already has a meaning for directories,
621 * so we don't want to overload that. */
622
623 if (keep_this_level) {
624 log_debug("Keeping \"%s\".", sub_path);
625 continue;
626 }
627
628 /* Ignore ctime, we change it when deleting */
629 age = timespec_load(&s.st_mtim);
630 if (age >= cutoff) {
631 char a[FORMAT_TIMESTAMP_MAX];
632 /* Follows spelling in stat(1). */
633 log_debug("Directory \"%s\": modify time %s is too new.",
634 sub_path,
635 format_timestamp_us(a, sizeof(a), age));
636 continue;
637 }
638
639 age = timespec_load(&s.st_atim);
640 if (age >= cutoff) {
641 char a[FORMAT_TIMESTAMP_MAX];
642 log_debug("Directory \"%s\": access time %s is too new.",
643 sub_path,
644 format_timestamp_us(a, sizeof(a), age));
645 continue;
646 }
647
648 log_debug("Removing directory \"%s\".", sub_path);
649 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0)
650 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
651 r = log_error_errno(errno, "rmdir(%s): %m", sub_path);
652
653 } else {
654 /* Skip files for which the sticky bit is
655 * set. These are semantics we define, and are
656 * unknown elsewhere. See XDG_RUNTIME_DIR
657 * specification for details. */
658 if (s.st_mode & S_ISVTX) {
659 log_debug("Skipping \"%s\": sticky bit set.", sub_path);
660 continue;
661 }
662
663 if (mountpoint && S_ISREG(s.st_mode))
664 if (s.st_uid == 0 && STR_IN_SET(dent->d_name,
665 ".journal",
666 "aquota.user",
667 "aquota.group")) {
668 log_debug("Skipping \"%s\".", sub_path);
669 continue;
670 }
671
672 /* Ignore sockets that are listed in /proc/net/unix */
673 if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path)) {
674 log_debug("Skipping \"%s\": live socket.", sub_path);
675 continue;
676 }
677
678 /* Ignore device nodes */
679 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode)) {
680 log_debug("Skipping \"%s\": a device.", sub_path);
681 continue;
682 }
683
684 /* Keep files on this level around if this is
685 * requested */
686 if (keep_this_level) {
687 log_debug("Keeping \"%s\".", sub_path);
688 continue;
689 }
690
691 age = timespec_load(&s.st_mtim);
692 if (age >= cutoff) {
693 char a[FORMAT_TIMESTAMP_MAX];
694 /* Follows spelling in stat(1). */
695 log_debug("File \"%s\": modify time %s is too new.",
696 sub_path,
697 format_timestamp_us(a, sizeof(a), age));
698 continue;
699 }
700
701 age = timespec_load(&s.st_atim);
702 if (age >= cutoff) {
703 char a[FORMAT_TIMESTAMP_MAX];
704 log_debug("File \"%s\": access time %s is too new.",
705 sub_path,
706 format_timestamp_us(a, sizeof(a), age));
707 continue;
708 }
709
710 age = timespec_load(&s.st_ctim);
711 if (age >= cutoff) {
712 char a[FORMAT_TIMESTAMP_MAX];
713 log_debug("File \"%s\": change time %s is too new.",
714 sub_path,
715 format_timestamp_us(a, sizeof(a), age));
716 continue;
717 }
718
719 log_debug("unlink \"%s\"", sub_path);
720
721 if (unlinkat(dirfd(d), dent->d_name, 0) < 0)
722 if (errno != ENOENT)
723 r = log_error_errno(errno, "unlink(%s): %m", sub_path);
724
725 deleted = true;
726 }
727 }
728
729 finish:
730 if (deleted) {
731 usec_t age1, age2;
732 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
733
734 /* Restore original directory timestamps */
735 times[0] = ds->st_atim;
736 times[1] = ds->st_mtim;
737
738 age1 = timespec_load(&ds->st_atim);
739 age2 = timespec_load(&ds->st_mtim);
740 log_debug("Restoring access and modification time on \"%s\": %s, %s",
741 p,
742 format_timestamp_us(a, sizeof(a), age1),
743 format_timestamp_us(b, sizeof(b), age2));
744 if (futimens(dirfd(d), times) < 0)
745 log_error_errno(errno, "utimensat(%s): %m", p);
746 }
747
748 return r;
749 }
750
751 static bool dangerous_hardlinks(void) {
752 _cleanup_free_ char *value = NULL;
753 static int cached = -1;
754 int r;
755
756 /* Check whether the fs.protected_hardlinks sysctl is on. If we can't determine it we assume its off, as that's
757 * what the upstream default is. */
758
759 if (cached >= 0)
760 return cached;
761
762 r = read_one_line_file("/proc/sys/fs/protected_hardlinks", &value);
763 if (r < 0) {
764 log_debug_errno(r, "Failed to read fs.protected_hardlinks sysctl: %m");
765 return true;
766 }
767
768 r = parse_boolean(value);
769 if (r < 0) {
770 log_debug_errno(r, "Failed to parse fs.protected_hardlinks sysctl: %m");
771 return true;
772 }
773
774 cached = r == 0;
775 return cached;
776 }
777
778 static bool hardlink_vulnerable(struct stat *st) {
779 assert(st);
780
781 return !S_ISDIR(st->st_mode) && st->st_nlink > 1 && dangerous_hardlinks();
782 }
783
784 static int path_set_perms(Item *i, const char *path) {
785 char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
786 _cleanup_close_ int fd = -1;
787 struct stat st;
788
789 assert(i);
790 assert(path);
791
792 if (!i->mode_set && !i->uid_set && !i->gid_set)
793 goto shortcut;
794
795 /* We open the file with O_PATH here, to make the operation
796 * somewhat atomic. Also there's unfortunately no fchmodat()
797 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
798 * O_PATH. */
799
800 fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
801 if (fd < 0) {
802 int level = LOG_ERR, r = -errno;
803
804 /* Option "e" operates only on existing objects. Do not
805 * print errors about non-existent files or directories */
806 if (i->type == EMPTY_DIRECTORY && errno == ENOENT) {
807 level = LOG_DEBUG;
808 r = 0;
809 }
810
811 log_full_errno(level, errno, "Adjusting owner and mode for %s failed: %m", path);
812 return r;
813 }
814
815 if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0)
816 return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
817
818 if (hardlink_vulnerable(&st)) {
819 log_error("Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
820 return -EPERM;
821 }
822
823 xsprintf(fn, "/proc/self/fd/%i", fd);
824
825 if (i->mode_set) {
826 if (S_ISLNK(st.st_mode))
827 log_debug("Skipping mode fix for symlink %s.", path);
828 else {
829 mode_t m = i->mode;
830
831 if (i->mask_perms) {
832 if (!(st.st_mode & 0111))
833 m &= ~0111;
834 if (!(st.st_mode & 0222))
835 m &= ~0222;
836 if (!(st.st_mode & 0444))
837 m &= ~0444;
838 if (!S_ISDIR(st.st_mode))
839 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
840 }
841
842 if (m == (st.st_mode & 07777))
843 log_debug("\"%s\" has correct mode %o already.", path, st.st_mode);
844 else {
845 log_debug("Changing \"%s\" to mode %o.", path, m);
846
847 if (chmod(fn, m) < 0)
848 return log_error_errno(errno, "chmod() of %s via %s failed: %m", path, fn);
849 }
850 }
851 }
852
853 if ((i->uid_set && i->uid != st.st_uid) ||
854 (i->gid_set && i->gid != st.st_gid)) {
855 log_debug("Changing \"%s\" to owner "UID_FMT":"GID_FMT,
856 path,
857 i->uid_set ? i->uid : UID_INVALID,
858 i->gid_set ? i->gid : GID_INVALID);
859
860 if (chown(fn,
861 i->uid_set ? i->uid : UID_INVALID,
862 i->gid_set ? i->gid : GID_INVALID) < 0)
863 return log_error_errno(errno, "chown() of %s via %s failed: %m", path, fn);
864 }
865
866 fd = safe_close(fd);
867
868 shortcut:
869 return label_fix(path, false, false);
870 }
871
872 static int parse_xattrs_from_arg(Item *i) {
873 const char *p;
874 int r;
875
876 assert(i);
877 assert(i->argument);
878
879 p = i->argument;
880
881 for (;;) {
882 _cleanup_free_ char *name = NULL, *value = NULL, *xattr = NULL;
883
884 r = extract_first_word(&p, &xattr, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
885 if (r < 0)
886 log_warning_errno(r, "Failed to parse extended attribute '%s', ignoring: %m", p);
887 if (r <= 0)
888 break;
889
890 r = split_pair(xattr, "=", &name, &value);
891 if (r < 0) {
892 log_warning_errno(r, "Failed to parse extended attribute, ignoring: %s", xattr);
893 continue;
894 }
895
896 if (isempty(name) || isempty(value)) {
897 log_warning("Malformed extended attribute found, ignoring: %s", xattr);
898 continue;
899 }
900
901 if (strv_push_pair(&i->xattrs, name, value) < 0)
902 return log_oom();
903
904 name = value = NULL;
905 }
906
907 return 0;
908 }
909
910 static int path_set_xattrs(Item *i, const char *path) {
911 char **name, **value;
912
913 assert(i);
914 assert(path);
915
916 STRV_FOREACH_PAIR(name, value, i->xattrs) {
917 log_debug("Setting extended attribute '%s=%s' on %s.", *name, *value, path);
918 if (lsetxattr(path, *name, *value, strlen(*value), 0) < 0)
919 return log_error_errno(errno, "Setting extended attribute %s=%s on %s failed: %m",
920 *name, *value, path);
921 }
922 return 0;
923 }
924
925 static int parse_acls_from_arg(Item *item) {
926 #if HAVE_ACL
927 int r;
928
929 assert(item);
930
931 /* If force (= modify) is set, we will not modify the acl
932 * afterwards, so the mask can be added now if necessary. */
933
934 r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force);
935 if (r < 0)
936 log_warning_errno(r, "Failed to parse ACL \"%s\": %m. Ignoring", item->argument);
937 #else
938 log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring");
939 #endif
940
941 return 0;
942 }
943
944 #if HAVE_ACL
945 static int path_set_acl(const char *path, const char *pretty, acl_type_t type, acl_t acl, bool modify) {
946 _cleanup_(acl_free_charpp) char *t = NULL;
947 _cleanup_(acl_freep) acl_t dup = NULL;
948 int r;
949
950 /* Returns 0 for success, positive error if already warned,
951 * negative error otherwise. */
952
953 if (modify) {
954 r = acls_for_file(path, type, acl, &dup);
955 if (r < 0)
956 return r;
957
958 r = calc_acl_mask_if_needed(&dup);
959 if (r < 0)
960 return r;
961 } else {
962 dup = acl_dup(acl);
963 if (!dup)
964 return -errno;
965
966 /* the mask was already added earlier if needed */
967 }
968
969 r = add_base_acls_if_needed(&dup, path);
970 if (r < 0)
971 return r;
972
973 t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE);
974 log_debug("Setting %s ACL %s on %s.",
975 type == ACL_TYPE_ACCESS ? "access" : "default",
976 strna(t), pretty);
977
978 r = acl_set_file(path, type, dup);
979 if (r < 0)
980 /* Return positive to indicate we already warned */
981 return -log_error_errno(errno,
982 "Setting %s ACL \"%s\" on %s failed: %m",
983 type == ACL_TYPE_ACCESS ? "access" : "default",
984 strna(t), pretty);
985
986 return 0;
987 }
988 #endif
989
990 static int path_set_acls(Item *item, const char *path) {
991 int r = 0;
992 #if HAVE_ACL
993 char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
994 _cleanup_close_ int fd = -1;
995 struct stat st;
996
997 assert(item);
998 assert(path);
999
1000 fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
1001 if (fd < 0)
1002 return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path);
1003
1004 if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0)
1005 return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
1006
1007 if (hardlink_vulnerable(&st)) {
1008 log_error("Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
1009 return -EPERM;
1010 }
1011
1012 if (S_ISLNK(st.st_mode)) {
1013 log_debug("Skipping ACL fix for symlink %s.", path);
1014 return 0;
1015 }
1016
1017 xsprintf(fn, "/proc/self/fd/%i", fd);
1018
1019 if (item->acl_access)
1020 r = path_set_acl(fn, path, ACL_TYPE_ACCESS, item->acl_access, item->force);
1021
1022 if (r == 0 && item->acl_default)
1023 r = path_set_acl(fn, path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
1024
1025 if (r > 0)
1026 return -r; /* already warned */
1027 else if (r == -EOPNOTSUPP) {
1028 log_debug_errno(r, "ACLs not supported by file system at %s", path);
1029 return 0;
1030 } else if (r < 0)
1031 log_error_errno(r, "ACL operation on \"%s\" failed: %m", path);
1032 #endif
1033 return r;
1034 }
1035
1036 #define ATTRIBUTES_ALL \
1037 (FS_NOATIME_FL | \
1038 FS_SYNC_FL | \
1039 FS_DIRSYNC_FL | \
1040 FS_APPEND_FL | \
1041 FS_COMPR_FL | \
1042 FS_NODUMP_FL | \
1043 FS_EXTENT_FL | \
1044 FS_IMMUTABLE_FL | \
1045 FS_JOURNAL_DATA_FL | \
1046 FS_SECRM_FL | \
1047 FS_UNRM_FL | \
1048 FS_NOTAIL_FL | \
1049 FS_TOPDIR_FL | \
1050 FS_NOCOW_FL)
1051
1052 static int parse_attribute_from_arg(Item *item) {
1053
1054 static const struct {
1055 char character;
1056 unsigned value;
1057 } attributes[] = {
1058 { 'A', FS_NOATIME_FL }, /* do not update atime */
1059 { 'S', FS_SYNC_FL }, /* Synchronous updates */
1060 { 'D', FS_DIRSYNC_FL }, /* dirsync behaviour (directories only) */
1061 { 'a', FS_APPEND_FL }, /* writes to file may only append */
1062 { 'c', FS_COMPR_FL }, /* Compress file */
1063 { 'd', FS_NODUMP_FL }, /* do not dump file */
1064 { 'e', FS_EXTENT_FL }, /* Extents */
1065 { 'i', FS_IMMUTABLE_FL }, /* Immutable file */
1066 { 'j', FS_JOURNAL_DATA_FL }, /* Reserved for ext3 */
1067 { 's', FS_SECRM_FL }, /* Secure deletion */
1068 { 'u', FS_UNRM_FL }, /* Undelete */
1069 { 't', FS_NOTAIL_FL }, /* file tail should not be merged */
1070 { 'T', FS_TOPDIR_FL }, /* Top of directory hierarchies */
1071 { 'C', FS_NOCOW_FL }, /* Do not cow file */
1072 };
1073
1074 enum {
1075 MODE_ADD,
1076 MODE_DEL,
1077 MODE_SET
1078 } mode = MODE_ADD;
1079
1080 unsigned value = 0, mask = 0;
1081 const char *p;
1082
1083 assert(item);
1084
1085 p = item->argument;
1086 if (p) {
1087 if (*p == '+') {
1088 mode = MODE_ADD;
1089 p++;
1090 } else if (*p == '-') {
1091 mode = MODE_DEL;
1092 p++;
1093 } else if (*p == '=') {
1094 mode = MODE_SET;
1095 p++;
1096 }
1097 }
1098
1099 if (isempty(p) && mode != MODE_SET) {
1100 log_error("Setting file attribute on '%s' needs an attribute specification.", item->path);
1101 return -EINVAL;
1102 }
1103
1104 for (; p && *p ; p++) {
1105 unsigned i, v;
1106
1107 for (i = 0; i < ELEMENTSOF(attributes); i++)
1108 if (*p == attributes[i].character)
1109 break;
1110
1111 if (i >= ELEMENTSOF(attributes)) {
1112 log_error("Unknown file attribute '%c' on '%s'.", *p, item->path);
1113 return -EINVAL;
1114 }
1115
1116 v = attributes[i].value;
1117
1118 SET_FLAG(value, v, IN_SET(mode, MODE_ADD, MODE_SET));
1119
1120 mask |= v;
1121 }
1122
1123 if (mode == MODE_SET)
1124 mask |= ATTRIBUTES_ALL;
1125
1126 assert(mask != 0);
1127
1128 item->attribute_mask = mask;
1129 item->attribute_value = value;
1130 item->attribute_set = true;
1131
1132 return 0;
1133 }
1134
1135 static int path_set_attribute(Item *item, const char *path) {
1136 _cleanup_close_ int fd = -1;
1137 struct stat st;
1138 unsigned f;
1139 int r;
1140
1141 if (!item->attribute_set || item->attribute_mask == 0)
1142 return 0;
1143
1144 fd = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOATIME|O_NOFOLLOW);
1145 if (fd < 0) {
1146 if (errno == ELOOP)
1147 return log_error_errno(errno, "Skipping file attributes adjustment on symlink %s.", path);
1148
1149 return log_error_errno(errno, "Cannot open '%s': %m", path);
1150 }
1151
1152 if (fstat(fd, &st) < 0)
1153 return log_error_errno(errno, "Cannot stat '%s': %m", path);
1154
1155 /* Issuing the file attribute ioctls on device nodes is not
1156 * safe, as that will be delivered to the drivers, not the
1157 * file system containing the device node. */
1158 if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
1159 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path);
1160 return -EINVAL;
1161 }
1162
1163 f = item->attribute_value & item->attribute_mask;
1164
1165 /* Mask away directory-specific flags */
1166 if (!S_ISDIR(st.st_mode))
1167 f &= ~FS_DIRSYNC_FL;
1168
1169 r = chattr_fd(fd, f, item->attribute_mask);
1170 if (r < 0)
1171 log_full_errno(IN_SET(r, -ENOTTY, -EOPNOTSUPP) ? LOG_DEBUG : LOG_WARNING,
1172 r,
1173 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
1174 path, item->attribute_value, item->attribute_mask);
1175
1176 return 0;
1177 }
1178
1179 static int write_one_file(Item *i, const char *path) {
1180 _cleanup_close_ int fd = -1;
1181 int flags, r = 0;
1182 struct stat st;
1183
1184 assert(i);
1185 assert(path);
1186
1187 flags = i->type == CREATE_FILE ? O_CREAT|O_EXCL|O_NOFOLLOW :
1188 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
1189
1190 RUN_WITH_UMASK(0000) {
1191 mac_selinux_create_file_prepare(path, S_IFREG);
1192 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
1193 mac_selinux_create_file_clear();
1194 }
1195
1196 if (fd < 0) {
1197 if (i->type == WRITE_FILE && errno == ENOENT) {
1198 log_debug_errno(errno, "Not writing missing file \"%s\": %m", path);
1199 return 0;
1200 }
1201 if (i->type == CREATE_FILE && errno == EEXIST) {
1202 log_debug_errno(errno, "Not writing to pre-existing file \"%s\": %m", path);
1203 goto done;
1204 }
1205
1206 r = -errno;
1207 if (!i->argument && errno == EROFS && stat(path, &st) == 0 &&
1208 (i->type == CREATE_FILE || st.st_size == 0))
1209 goto check_mode;
1210
1211 return log_error_errno(r, "Failed to create file %s: %m", path);
1212 }
1213
1214 if (i->argument) {
1215 log_debug("%s to \"%s\".", i->type == CREATE_FILE ? "Appending" : "Writing", path);
1216
1217 r = loop_write(fd, i->argument, strlen(i->argument), false);
1218 if (r < 0)
1219 return log_error_errno(r, "Failed to write file \"%s\": %m", path);
1220 } else
1221 log_debug("\"%s\" has been created.", path);
1222
1223 fd = safe_close(fd);
1224
1225 done:
1226 if (stat(path, &st) < 0)
1227 return log_error_errno(errno, "stat(%s) failed: %m", path);
1228
1229 check_mode:
1230 if (!S_ISREG(st.st_mode)) {
1231 log_error("%s is not a file.", path);
1232 return -EEXIST;
1233 }
1234
1235 r = path_set_perms(i, path);
1236 if (r < 0)
1237 return r;
1238
1239 return 0;
1240 }
1241
1242 typedef int (*action_t)(Item *, const char *);
1243
1244 static int item_do_children(Item *i, const char *path, action_t action) {
1245 _cleanup_closedir_ DIR *d;
1246 struct dirent *de;
1247 int r = 0;
1248
1249 assert(i);
1250 assert(path);
1251
1252 /* This returns the first error we run into, but nevertheless
1253 * tries to go on */
1254
1255 d = opendir_nomod(path);
1256 if (!d)
1257 return IN_SET(errno, ENOENT, ENOTDIR, ELOOP) ? 0 : -errno;
1258
1259 FOREACH_DIRENT_ALL(de, d, r = -errno) {
1260 _cleanup_free_ char *p = NULL;
1261 int q;
1262
1263 if (dot_or_dot_dot(de->d_name))
1264 continue;
1265
1266 p = strjoin(path, "/", de->d_name);
1267 if (!p)
1268 return -ENOMEM;
1269
1270 q = action(i, p);
1271 if (q < 0 && q != -ENOENT && r == 0)
1272 r = q;
1273
1274 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
1275 q = item_do_children(i, p, action);
1276 if (q < 0 && r == 0)
1277 r = q;
1278 }
1279 }
1280
1281 return r;
1282 }
1283
1284 static int glob_item(Item *i, action_t action, bool recursive) {
1285 _cleanup_globfree_ glob_t g = {
1286 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
1287 };
1288 int r = 0, k;
1289 char **fn;
1290
1291 k = safe_glob(i->path, GLOB_NOSORT|GLOB_BRACE, &g);
1292 if (k < 0 && k != -ENOENT)
1293 return log_error_errno(k, "glob(%s) failed: %m", i->path);
1294
1295 STRV_FOREACH(fn, g.gl_pathv) {
1296 k = action(i, *fn);
1297 if (k < 0 && r == 0)
1298 r = k;
1299
1300 if (recursive) {
1301 k = item_do_children(i, *fn, action);
1302 if (k < 0 && r == 0)
1303 r = k;
1304 }
1305 }
1306
1307 return r;
1308 }
1309
1310 typedef enum {
1311 CREATION_NORMAL,
1312 CREATION_EXISTING,
1313 CREATION_FORCE,
1314 _CREATION_MODE_MAX,
1315 _CREATION_MODE_INVALID = -1
1316 } CreationMode;
1317
1318 static const char *creation_mode_verb_table[_CREATION_MODE_MAX] = {
1319 [CREATION_NORMAL] = "Created",
1320 [CREATION_EXISTING] = "Found existing",
1321 [CREATION_FORCE] = "Created replacement",
1322 };
1323
1324 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
1325
1326 static int create_item(Item *i) {
1327 struct stat st;
1328 int r = 0;
1329 int q = 0;
1330 CreationMode creation;
1331
1332 assert(i);
1333
1334 log_debug("Running create action for entry %c %s", (char) i->type, i->path);
1335
1336 switch (i->type) {
1337
1338 case IGNORE_PATH:
1339 case IGNORE_DIRECTORY_PATH:
1340 case REMOVE_PATH:
1341 case RECURSIVE_REMOVE_PATH:
1342 return 0;
1343
1344 case CREATE_FILE:
1345 case TRUNCATE_FILE:
1346 RUN_WITH_UMASK(0000)
1347 (void) mkdir_parents_label(i->path, 0755);
1348
1349 r = write_one_file(i, i->path);
1350 if (r < 0)
1351 return r;
1352 break;
1353
1354 case COPY_FILES: {
1355
1356 RUN_WITH_UMASK(0000)
1357 (void) mkdir_parents_label(i->path, 0755);
1358
1359 log_debug("Copying tree \"%s\" to \"%s\".", i->argument, i->path);
1360 r = copy_tree(i->argument, i->path,
1361 i->uid_set ? i->uid : UID_INVALID,
1362 i->gid_set ? i->gid : GID_INVALID,
1363 COPY_REFLINK);
1364
1365 if (r == -EROFS && stat(i->path, &st) == 0)
1366 r = -EEXIST;
1367
1368 if (r < 0) {
1369 struct stat a, b;
1370
1371 if (r != -EEXIST)
1372 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
1373
1374 if (stat(i->argument, &a) < 0)
1375 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
1376
1377 if (stat(i->path, &b) < 0)
1378 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1379
1380 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
1381 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
1382 return 0;
1383 }
1384 }
1385
1386 r = path_set_perms(i, i->path);
1387 if (r < 0)
1388 return r;
1389
1390 break;
1391
1392 case WRITE_FILE:
1393 r = glob_item(i, write_one_file, false);
1394 if (r < 0)
1395 return r;
1396
1397 break;
1398
1399 case CREATE_DIRECTORY:
1400 case TRUNCATE_DIRECTORY:
1401 case CREATE_SUBVOLUME:
1402 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1403 case CREATE_SUBVOLUME_NEW_QUOTA:
1404 RUN_WITH_UMASK(0000)
1405 (void) mkdir_parents_label(i->path, 0755);
1406
1407 if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) {
1408
1409 if (btrfs_is_subvol(isempty(arg_root) ? "/" : arg_root) <= 0)
1410
1411 /* Don't create a subvolume unless the
1412 * root directory is one, too. We do
1413 * this under the assumption that if
1414 * the root directory is just a plain
1415 * directory (i.e. very light-weight),
1416 * we shouldn't try to split it up
1417 * into subvolumes (i.e. more
1418 * heavy-weight). Thus, chroot()
1419 * environments and suchlike will get
1420 * a full brtfs subvolume set up below
1421 * their tree only if they
1422 * specifically set up a btrfs
1423 * subvolume for the root dir too. */
1424
1425 r = -ENOTTY;
1426 else {
1427 RUN_WITH_UMASK((~i->mode) & 0777)
1428 r = btrfs_subvol_make(i->path);
1429 }
1430 } else
1431 r = 0;
1432
1433 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY)
1434 RUN_WITH_UMASK(0000)
1435 r = mkdir_label(i->path, i->mode);
1436
1437 if (r < 0) {
1438 int k;
1439
1440 if (!IN_SET(r, -EEXIST, -EROFS))
1441 return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path);
1442
1443 k = is_dir(i->path, false);
1444 if (k == -ENOENT && r == -EROFS)
1445 return log_error_errno(r, "%s does not exist and cannot be created as the file system is read-only.", i->path);
1446 if (k < 0)
1447 return log_error_errno(k, "Failed to check if %s exists: %m", i->path);
1448 if (!k) {
1449 log_warning("\"%s\" already exists and is not a directory.", i->path);
1450 return 0;
1451 }
1452
1453 creation = CREATION_EXISTING;
1454 } else
1455 creation = CREATION_NORMAL;
1456
1457 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path);
1458
1459 if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
1460 r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
1461 if (r == -ENOTTY)
1462 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path);
1463 else if (r == -EROFS)
1464 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i->path);
1465 else if (r == -ENOPROTOOPT)
1466 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i->path);
1467 else if (r < 0)
1468 q = log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
1469 else if (r > 0)
1470 log_debug("Adjusted quota for subvolume \"%s\".", i->path);
1471 else if (r == 0)
1472 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
1473 }
1474
1475 _fallthrough_;
1476 case EMPTY_DIRECTORY:
1477 r = path_set_perms(i, i->path);
1478 if (q < 0)
1479 return q;
1480 if (r < 0)
1481 return r;
1482
1483 break;
1484
1485 case CREATE_FIFO:
1486 RUN_WITH_UMASK(0000) {
1487 (void) mkdir_parents_label(i->path, 0755);
1488
1489 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1490 r = mkfifo(i->path, i->mode);
1491 mac_selinux_create_file_clear();
1492 }
1493
1494 if (r < 0) {
1495 if (errno != EEXIST)
1496 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
1497
1498 if (lstat(i->path, &st) < 0)
1499 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1500
1501 if (!S_ISFIFO(st.st_mode)) {
1502
1503 if (i->force) {
1504 RUN_WITH_UMASK(0000) {
1505 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1506 r = mkfifo_atomic(i->path, i->mode);
1507 mac_selinux_create_file_clear();
1508 }
1509
1510 if (r < 0)
1511 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
1512 creation = CREATION_FORCE;
1513 } else {
1514 log_warning("\"%s\" already exists and is not a fifo.", i->path);
1515 return 0;
1516 }
1517 } else
1518 creation = CREATION_EXISTING;
1519 } else
1520 creation = CREATION_NORMAL;
1521 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation), i->path);
1522
1523 r = path_set_perms(i, i->path);
1524 if (r < 0)
1525 return r;
1526
1527 break;
1528 }
1529
1530 case CREATE_SYMLINK: {
1531 RUN_WITH_UMASK(0000)
1532 (void) mkdir_parents_label(i->path, 0755);
1533
1534 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1535 r = symlink(i->argument, i->path);
1536 mac_selinux_create_file_clear();
1537
1538 if (r < 0) {
1539 _cleanup_free_ char *x = NULL;
1540
1541 if (errno != EEXIST)
1542 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
1543
1544 r = readlink_malloc(i->path, &x);
1545 if (r < 0 || !streq(i->argument, x)) {
1546
1547 if (i->force) {
1548 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1549 r = symlink_atomic(i->argument, i->path);
1550 mac_selinux_create_file_clear();
1551
1552 if (IN_SET(r, -EEXIST, -ENOTEMPTY)) {
1553 r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL);
1554 if (r < 0)
1555 return log_error_errno(r, "rm -fr %s failed: %m", i->path);
1556
1557 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1558 r = symlink(i->argument, i->path) < 0 ? -errno : 0;
1559 mac_selinux_create_file_clear();
1560 }
1561 if (r < 0)
1562 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
1563
1564 creation = CREATION_FORCE;
1565 } else {
1566 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i->path);
1567 return 0;
1568 }
1569 } else
1570 creation = CREATION_EXISTING;
1571 } else
1572
1573 creation = CREATION_NORMAL;
1574 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation), i->path);
1575 break;
1576 }
1577
1578 case CREATE_BLOCK_DEVICE:
1579 case CREATE_CHAR_DEVICE: {
1580 mode_t file_type;
1581
1582 if (have_effective_cap(CAP_MKNOD) == 0) {
1583 /* In a container we lack CAP_MKNOD. We
1584 shouldn't attempt to create the device node in
1585 that case to avoid noise, and we don't support
1586 virtualized devices in containers anyway. */
1587
1588 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
1589 return 0;
1590 }
1591
1592 RUN_WITH_UMASK(0000)
1593 (void) mkdir_parents_label(i->path, 0755);
1594
1595 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
1596
1597 RUN_WITH_UMASK(0000) {
1598 mac_selinux_create_file_prepare(i->path, file_type);
1599 r = mknod(i->path, i->mode | file_type, i->major_minor);
1600 mac_selinux_create_file_clear();
1601 }
1602
1603 if (r < 0) {
1604 if (errno == EPERM) {
1605 log_debug("We lack permissions, possibly because of cgroup configuration; "
1606 "skipping creation of device node %s.", i->path);
1607 return 0;
1608 }
1609
1610 if (errno != EEXIST)
1611 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
1612
1613 if (lstat(i->path, &st) < 0)
1614 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1615
1616 if ((st.st_mode & S_IFMT) != file_type) {
1617
1618 if (i->force) {
1619
1620 RUN_WITH_UMASK(0000) {
1621 mac_selinux_create_file_prepare(i->path, file_type);
1622 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
1623 mac_selinux_create_file_clear();
1624 }
1625
1626 if (r < 0)
1627 return log_error_errno(r, "Failed to create device node \"%s\": %m", i->path);
1628 creation = CREATION_FORCE;
1629 } else {
1630 log_debug("%s is not a device node.", i->path);
1631 return 0;
1632 }
1633 } else
1634 creation = CREATION_EXISTING;
1635 } else
1636 creation = CREATION_NORMAL;
1637
1638 log_debug("%s %s device node \"%s\" %u:%u.",
1639 creation_mode_verb_to_string(creation),
1640 i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
1641 i->path, major(i->mode), minor(i->mode));
1642
1643 r = path_set_perms(i, i->path);
1644 if (r < 0)
1645 return r;
1646
1647 break;
1648 }
1649
1650 case ADJUST_MODE:
1651 case RELABEL_PATH:
1652 r = glob_item(i, path_set_perms, false);
1653 if (r < 0)
1654 return r;
1655 break;
1656
1657 case RECURSIVE_RELABEL_PATH:
1658 r = glob_item(i, path_set_perms, true);
1659 if (r < 0)
1660 return r;
1661 break;
1662
1663 case SET_XATTR:
1664 r = glob_item(i, path_set_xattrs, false);
1665 if (r < 0)
1666 return r;
1667 break;
1668
1669 case RECURSIVE_SET_XATTR:
1670 r = glob_item(i, path_set_xattrs, true);
1671 if (r < 0)
1672 return r;
1673 break;
1674
1675 case SET_ACL:
1676 r = glob_item(i, path_set_acls, false);
1677 if (r < 0)
1678 return r;
1679 break;
1680
1681 case RECURSIVE_SET_ACL:
1682 r = glob_item(i, path_set_acls, true);
1683 if (r < 0)
1684 return r;
1685 break;
1686
1687 case SET_ATTRIBUTE:
1688 r = glob_item(i, path_set_attribute, false);
1689 if (r < 0)
1690 return r;
1691 break;
1692
1693 case RECURSIVE_SET_ATTRIBUTE:
1694 r = glob_item(i, path_set_attribute, true);
1695 if (r < 0)
1696 return r;
1697 break;
1698 }
1699
1700 return 0;
1701 }
1702
1703 static int remove_item_instance(Item *i, const char *instance) {
1704 int r;
1705
1706 assert(i);
1707
1708 switch (i->type) {
1709
1710 case REMOVE_PATH:
1711 if (remove(instance) < 0 && errno != ENOENT)
1712 return log_error_errno(errno, "rm(%s): %m", instance);
1713
1714 break;
1715
1716 case TRUNCATE_DIRECTORY:
1717 case RECURSIVE_REMOVE_PATH:
1718 /* FIXME: we probably should use dir_cleanup() here
1719 * instead of rm_rf() so that 'x' is honoured. */
1720 log_debug("rm -rf \"%s\"", instance);
1721 r = rm_rf(instance, (i->type == RECURSIVE_REMOVE_PATH ? REMOVE_ROOT|REMOVE_SUBVOLUME : 0) | REMOVE_PHYSICAL);
1722 if (r < 0 && r != -ENOENT)
1723 return log_error_errno(r, "rm_rf(%s): %m", instance);
1724
1725 break;
1726
1727 default:
1728 assert_not_reached("wut?");
1729 }
1730
1731 return 0;
1732 }
1733
1734 static int remove_item(Item *i) {
1735 assert(i);
1736
1737 log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
1738
1739 switch (i->type) {
1740
1741 case REMOVE_PATH:
1742 case TRUNCATE_DIRECTORY:
1743 case RECURSIVE_REMOVE_PATH:
1744 return glob_item(i, remove_item_instance, false);
1745
1746 default:
1747 return 0;
1748 }
1749 }
1750
1751 static int clean_item_instance(Item *i, const char* instance) {
1752 _cleanup_closedir_ DIR *d = NULL;
1753 struct stat s, ps;
1754 bool mountpoint;
1755 usec_t cutoff, n;
1756 char timestamp[FORMAT_TIMESTAMP_MAX];
1757
1758 assert(i);
1759
1760 if (!i->age_set)
1761 return 0;
1762
1763 n = now(CLOCK_REALTIME);
1764 if (n < i->age)
1765 return 0;
1766
1767 cutoff = n - i->age;
1768
1769 d = opendir_nomod(instance);
1770 if (!d) {
1771 if (IN_SET(errno, ENOENT, ENOTDIR)) {
1772 log_debug_errno(errno, "Directory \"%s\": %m", instance);
1773 return 0;
1774 }
1775
1776 return log_error_errno(errno, "Failed to open directory %s: %m", instance);
1777 }
1778
1779 if (fstat(dirfd(d), &s) < 0)
1780 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1781
1782 if (!S_ISDIR(s.st_mode)) {
1783 log_error("%s is not a directory.", i->path);
1784 return -ENOTDIR;
1785 }
1786
1787 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1788 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1789
1790 mountpoint = s.st_dev != ps.st_dev || s.st_ino == ps.st_ino;
1791
1792 log_debug("Cleanup threshold for %s \"%s\" is %s",
1793 mountpoint ? "mount point" : "directory",
1794 instance,
1795 format_timestamp_us(timestamp, sizeof(timestamp), cutoff));
1796
1797 return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1798 MAX_DEPTH, i->keep_first_level);
1799 }
1800
1801 static int clean_item(Item *i) {
1802 assert(i);
1803
1804 log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
1805
1806 switch (i->type) {
1807 case CREATE_DIRECTORY:
1808 case CREATE_SUBVOLUME:
1809 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1810 case CREATE_SUBVOLUME_NEW_QUOTA:
1811 case TRUNCATE_DIRECTORY:
1812 case IGNORE_PATH:
1813 case COPY_FILES:
1814 clean_item_instance(i, i->path);
1815 return 0;
1816 case EMPTY_DIRECTORY:
1817 case IGNORE_DIRECTORY_PATH:
1818 return glob_item(i, clean_item_instance, false);
1819 default:
1820 return 0;
1821 }
1822 }
1823
1824 static int process_item_array(ItemArray *array);
1825
1826 static int process_item(Item *i) {
1827 int r, q, p, t = 0;
1828 _cleanup_free_ char *prefix = NULL;
1829
1830 assert(i);
1831
1832 if (i->done)
1833 return 0;
1834
1835 i->done = true;
1836
1837 prefix = malloc(strlen(i->path) + 1);
1838 if (!prefix)
1839 return log_oom();
1840
1841 PATH_FOREACH_PREFIX(prefix, i->path) {
1842 ItemArray *j;
1843
1844 j = ordered_hashmap_get(items, prefix);
1845 if (j) {
1846 int s;
1847
1848 s = process_item_array(j);
1849 if (s < 0 && t == 0)
1850 t = s;
1851 }
1852 }
1853
1854 if (chase_symlinks(i->path, NULL, CHASE_NO_AUTOFS, NULL) == -EREMOTE)
1855 return t;
1856
1857 r = arg_create ? create_item(i) : 0;
1858 q = arg_remove ? remove_item(i) : 0;
1859 p = arg_clean ? clean_item(i) : 0;
1860
1861 return t < 0 ? t :
1862 r < 0 ? r :
1863 q < 0 ? q :
1864 p;
1865 }
1866
1867 static int process_item_array(ItemArray *array) {
1868 unsigned n;
1869 int r = 0, k;
1870
1871 assert(array);
1872
1873 for (n = 0; n < array->count; n++) {
1874 k = process_item(array->items + n);
1875 if (k < 0 && r == 0)
1876 r = k;
1877 }
1878
1879 return r;
1880 }
1881
1882 static void item_free_contents(Item *i) {
1883 assert(i);
1884 free(i->path);
1885 free(i->argument);
1886 strv_free(i->xattrs);
1887
1888 #if HAVE_ACL
1889 acl_free(i->acl_access);
1890 acl_free(i->acl_default);
1891 #endif
1892 }
1893
1894 static void item_array_free(ItemArray *a) {
1895 unsigned n;
1896
1897 if (!a)
1898 return;
1899
1900 for (n = 0; n < a->count; n++)
1901 item_free_contents(a->items + n);
1902 free(a->items);
1903 free(a);
1904 }
1905
1906 static int item_compare(const void *a, const void *b) {
1907 const Item *x = a, *y = b;
1908
1909 /* Make sure that the ownership taking item is put first, so
1910 * that we first create the node, and then can adjust it */
1911
1912 if (takes_ownership(x->type) && !takes_ownership(y->type))
1913 return -1;
1914 if (!takes_ownership(x->type) && takes_ownership(y->type))
1915 return 1;
1916
1917 return (int) x->type - (int) y->type;
1918 }
1919
1920 static bool item_compatible(Item *a, Item *b) {
1921 assert(a);
1922 assert(b);
1923 assert(streq(a->path, b->path));
1924
1925 if (takes_ownership(a->type) && takes_ownership(b->type))
1926 /* check if the items are the same */
1927 return streq_ptr(a->argument, b->argument) &&
1928
1929 a->uid_set == b->uid_set &&
1930 a->uid == b->uid &&
1931
1932 a->gid_set == b->gid_set &&
1933 a->gid == b->gid &&
1934
1935 a->mode_set == b->mode_set &&
1936 a->mode == b->mode &&
1937
1938 a->age_set == b->age_set &&
1939 a->age == b->age &&
1940
1941 a->mask_perms == b->mask_perms &&
1942
1943 a->keep_first_level == b->keep_first_level &&
1944
1945 a->major_minor == b->major_minor;
1946
1947 return true;
1948 }
1949
1950 static bool should_include_path(const char *path) {
1951 char **prefix;
1952
1953 STRV_FOREACH(prefix, arg_exclude_prefixes)
1954 if (path_startswith(path, *prefix)) {
1955 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1956 path, *prefix);
1957 return false;
1958 }
1959
1960 STRV_FOREACH(prefix, arg_include_prefixes)
1961 if (path_startswith(path, *prefix)) {
1962 log_debug("Entry \"%s\" matches include prefix \"%s\".", path, *prefix);
1963 return true;
1964 }
1965
1966 /* no matches, so we should include this path only if we
1967 * have no whitelist at all */
1968 if (strv_isempty(arg_include_prefixes))
1969 return true;
1970
1971 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path);
1972 return false;
1973 }
1974
1975 static int specifier_expansion_from_arg(Item *i) {
1976 _cleanup_free_ char *unescaped = NULL, *resolved = NULL;
1977 char **xattr;
1978 int r;
1979
1980 assert(i);
1981
1982 if (i->argument == NULL)
1983 return 0;
1984
1985 switch (i->type) {
1986 case COPY_FILES:
1987 case CREATE_SYMLINK:
1988 case CREATE_FILE:
1989 case TRUNCATE_FILE:
1990 case WRITE_FILE:
1991 r = cunescape(i->argument, 0, &unescaped);
1992 if (r < 0)
1993 return log_error_errno(r, "Failed to unescape parameter to write: %s", i->argument);
1994
1995 r = specifier_printf(unescaped, specifier_table, NULL, &resolved);
1996 if (r < 0)
1997 return r;
1998
1999 free_and_replace(i->argument, resolved);
2000 break;
2001
2002 case SET_XATTR:
2003 case RECURSIVE_SET_XATTR:
2004 assert(i->xattrs);
2005
2006 STRV_FOREACH (xattr, i->xattrs) {
2007 r = specifier_printf(*xattr, specifier_table, NULL, &resolved);
2008 if (r < 0)
2009 return r;
2010
2011 free_and_replace(*xattr, resolved);
2012 }
2013 break;
2014
2015 default:
2016 break;
2017 }
2018 return 0;
2019 }
2020
2021 static int parse_line(const char *fname, unsigned line, const char *buffer, bool *invalid_config) {
2022
2023 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
2024 _cleanup_(item_free_contents) Item i = {};
2025 ItemArray *existing;
2026 OrderedHashmap *h;
2027 int r, pos;
2028 bool force = false, boot = false;
2029
2030 assert(fname);
2031 assert(line >= 1);
2032 assert(buffer);
2033
2034 r = extract_many_words(
2035 &buffer,
2036 NULL,
2037 EXTRACT_QUOTES,
2038 &action,
2039 &path,
2040 &mode,
2041 &user,
2042 &group,
2043 &age,
2044 NULL);
2045 if (r < 0) {
2046 if (IN_SET(r, -EINVAL, -EBADSLT))
2047 /* invalid quoting and such or an unknown specifier */
2048 *invalid_config = true;
2049 return log_error_errno(r, "[%s:%u] Failed to parse line: %m", fname, line);
2050 }
2051
2052 else if (r < 2) {
2053 *invalid_config = true;
2054 log_error("[%s:%u] Syntax error.", fname, line);
2055 return -EIO;
2056 }
2057
2058 if (!isempty(buffer) && !streq(buffer, "-")) {
2059 i.argument = strdup(buffer);
2060 if (!i.argument)
2061 return log_oom();
2062 }
2063
2064 if (isempty(action)) {
2065 *invalid_config = true;
2066 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
2067 return -EINVAL;
2068 }
2069
2070 for (pos = 1; action[pos]; pos++) {
2071 if (action[pos] == '!' && !boot)
2072 boot = true;
2073 else if (action[pos] == '+' && !force)
2074 force = true;
2075 else {
2076 *invalid_config = true;
2077 log_error("[%s:%u] Unknown modifiers in command '%s'",
2078 fname, line, action);
2079 return -EINVAL;
2080 }
2081 }
2082
2083 if (boot && !arg_boot) {
2084 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
2085 action, path);
2086 return 0;
2087 }
2088
2089 i.type = action[0];
2090 i.force = force;
2091
2092 r = specifier_printf(path, specifier_table, NULL, &i.path);
2093 if (r == -ENXIO)
2094 return log_unresolvable_specifier(fname, line);
2095 if (r < 0) {
2096 if (IN_SET(r, -EINVAL, -EBADSLT))
2097 *invalid_config = true;
2098 return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s", fname, line, path);
2099 }
2100
2101 switch (i.type) {
2102
2103 case CREATE_DIRECTORY:
2104 case CREATE_SUBVOLUME:
2105 case CREATE_SUBVOLUME_INHERIT_QUOTA:
2106 case CREATE_SUBVOLUME_NEW_QUOTA:
2107 case EMPTY_DIRECTORY:
2108 case TRUNCATE_DIRECTORY:
2109 case CREATE_FIFO:
2110 case IGNORE_PATH:
2111 case IGNORE_DIRECTORY_PATH:
2112 case REMOVE_PATH:
2113 case RECURSIVE_REMOVE_PATH:
2114 case ADJUST_MODE:
2115 case RELABEL_PATH:
2116 case RECURSIVE_RELABEL_PATH:
2117 if (i.argument)
2118 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname, line, i.type);
2119
2120 break;
2121
2122 case CREATE_FILE:
2123 case TRUNCATE_FILE:
2124 break;
2125
2126 case CREATE_SYMLINK:
2127 if (!i.argument) {
2128 i.argument = strappend("/usr/share/factory/", i.path);
2129 if (!i.argument)
2130 return log_oom();
2131 }
2132 break;
2133
2134 case WRITE_FILE:
2135 if (!i.argument) {
2136 *invalid_config = true;
2137 log_error("[%s:%u] Write file requires argument.", fname, line);
2138 return -EBADMSG;
2139 }
2140 break;
2141
2142 case COPY_FILES:
2143 if (!i.argument) {
2144 i.argument = strappend("/usr/share/factory/", i.path);
2145 if (!i.argument)
2146 return log_oom();
2147 } else if (!path_is_absolute(i.argument)) {
2148 *invalid_config = true;
2149 log_error("[%s:%u] Source path is not absolute.", fname, line);
2150 return -EBADMSG;
2151 }
2152
2153 path_kill_slashes(i.argument);
2154 break;
2155
2156 case CREATE_CHAR_DEVICE:
2157 case CREATE_BLOCK_DEVICE: {
2158 unsigned major, minor;
2159
2160 if (!i.argument) {
2161 *invalid_config = true;
2162 log_error("[%s:%u] Device file requires argument.", fname, line);
2163 return -EBADMSG;
2164 }
2165
2166 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
2167 *invalid_config = true;
2168 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
2169 return -EBADMSG;
2170 }
2171
2172 i.major_minor = makedev(major, minor);
2173 break;
2174 }
2175
2176 case SET_XATTR:
2177 case RECURSIVE_SET_XATTR:
2178 if (!i.argument) {
2179 *invalid_config = true;
2180 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
2181 return -EBADMSG;
2182 }
2183 r = parse_xattrs_from_arg(&i);
2184 if (r < 0)
2185 return r;
2186 break;
2187
2188 case SET_ACL:
2189 case RECURSIVE_SET_ACL:
2190 if (!i.argument) {
2191 *invalid_config = true;
2192 log_error("[%s:%u] Set ACLs requires argument.", fname, line);
2193 return -EBADMSG;
2194 }
2195 r = parse_acls_from_arg(&i);
2196 if (r < 0)
2197 return r;
2198 break;
2199
2200 case SET_ATTRIBUTE:
2201 case RECURSIVE_SET_ATTRIBUTE:
2202 if (!i.argument) {
2203 *invalid_config = true;
2204 log_error("[%s:%u] Set file attribute requires argument.", fname, line);
2205 return -EBADMSG;
2206 }
2207 r = parse_attribute_from_arg(&i);
2208 if (IN_SET(r, -EINVAL, -EBADSLT))
2209 *invalid_config = true;
2210 if (r < 0)
2211 return r;
2212 break;
2213
2214 default:
2215 log_error("[%s:%u] Unknown command type '%c'.", fname, line, (char) i.type);
2216 *invalid_config = true;
2217 return -EBADMSG;
2218 }
2219
2220 if (!path_is_absolute(i.path)) {
2221 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
2222 *invalid_config = true;
2223 return -EBADMSG;
2224 }
2225
2226 path_kill_slashes(i.path);
2227
2228 if (!should_include_path(i.path))
2229 return 0;
2230
2231 r = specifier_expansion_from_arg(&i);
2232 if (r == -ENXIO)
2233 return log_unresolvable_specifier(fname, line);
2234 if (r < 0) {
2235 if (IN_SET(r, -EINVAL, -EBADSLT))
2236 *invalid_config = true;
2237 return log_error_errno(r, "[%s:%u] Failed to substitute specifiers in argument: %m",
2238 fname, line);
2239 }
2240
2241 if (arg_root) {
2242 char *p;
2243
2244 p = prefix_root(arg_root, i.path);
2245 if (!p)
2246 return log_oom();
2247
2248 free(i.path);
2249 i.path = p;
2250 }
2251
2252 if (!isempty(user) && !streq(user, "-")) {
2253 const char *u = user;
2254
2255 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
2256 if (r < 0) {
2257 *invalid_config = true;
2258 return log_error_errno(r, "[%s:%u] Unknown user '%s'.", fname, line, user);
2259 }
2260
2261 i.uid_set = true;
2262 }
2263
2264 if (!isempty(group) && !streq(group, "-")) {
2265 const char *g = group;
2266
2267 r = get_group_creds(&g, &i.gid);
2268 if (r < 0) {
2269 *invalid_config = true;
2270 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
2271 return r;
2272 }
2273
2274 i.gid_set = true;
2275 }
2276
2277 if (!isempty(mode) && !streq(mode, "-")) {
2278 const char *mm = mode;
2279 unsigned m;
2280
2281 if (*mm == '~') {
2282 i.mask_perms = true;
2283 mm++;
2284 }
2285
2286 if (parse_mode(mm, &m) < 0) {
2287 *invalid_config = true;
2288 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
2289 return -EBADMSG;
2290 }
2291
2292 i.mode = m;
2293 i.mode_set = true;
2294 } else
2295 i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
2296
2297 if (!isempty(age) && !streq(age, "-")) {
2298 const char *a = age;
2299
2300 if (*a == '~') {
2301 i.keep_first_level = true;
2302 a++;
2303 }
2304
2305 if (parse_sec(a, &i.age) < 0) {
2306 *invalid_config = true;
2307 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
2308 return -EBADMSG;
2309 }
2310
2311 i.age_set = true;
2312 }
2313
2314 h = needs_glob(i.type) ? globs : items;
2315
2316 existing = ordered_hashmap_get(h, i.path);
2317 if (existing) {
2318 unsigned n;
2319
2320 for (n = 0; n < existing->count; n++) {
2321 if (!item_compatible(existing->items + n, &i)) {
2322 log_notice("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2323 fname, line, i.path);
2324 return 0;
2325 }
2326 }
2327 } else {
2328 existing = new0(ItemArray, 1);
2329 if (!existing)
2330 return log_oom();
2331
2332 r = ordered_hashmap_put(h, i.path, existing);
2333 if (r < 0)
2334 return log_oom();
2335 }
2336
2337 if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
2338 return log_oom();
2339
2340 memcpy(existing->items + existing->count++, &i, sizeof(i));
2341
2342 /* Sort item array, to enforce stable ordering of application */
2343 qsort_safe(existing->items, existing->count, sizeof(Item), item_compare);
2344
2345 zero(i);
2346 return 0;
2347 }
2348
2349 static void help(void) {
2350 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2351 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2352 " -h --help Show this help\n"
2353 " --user Execute user configuration\n"
2354 " --version Show package version\n"
2355 " --create Create marked files/directories\n"
2356 " --clean Clean up marked directories\n"
2357 " --remove Remove marked files/directories\n"
2358 " --boot Execute actions only safe at boot\n"
2359 " --prefix=PATH Only apply rules with the specified prefix\n"
2360 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2361 " --root=PATH Operate on an alternate filesystem root\n"
2362 " --replace=PATH Treat arguments as replacement for PATH\n"
2363 , program_invocation_short_name);
2364 }
2365
2366 static int parse_argv(int argc, char *argv[]) {
2367
2368 enum {
2369 ARG_VERSION = 0x100,
2370 ARG_USER,
2371 ARG_CREATE,
2372 ARG_CLEAN,
2373 ARG_REMOVE,
2374 ARG_BOOT,
2375 ARG_PREFIX,
2376 ARG_EXCLUDE_PREFIX,
2377 ARG_ROOT,
2378 ARG_REPLACE,
2379 };
2380
2381 static const struct option options[] = {
2382 { "help", no_argument, NULL, 'h' },
2383 { "user", no_argument, NULL, ARG_USER },
2384 { "version", no_argument, NULL, ARG_VERSION },
2385 { "create", no_argument, NULL, ARG_CREATE },
2386 { "clean", no_argument, NULL, ARG_CLEAN },
2387 { "remove", no_argument, NULL, ARG_REMOVE },
2388 { "boot", no_argument, NULL, ARG_BOOT },
2389 { "prefix", required_argument, NULL, ARG_PREFIX },
2390 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
2391 { "root", required_argument, NULL, ARG_ROOT },
2392 { "replace", required_argument, NULL, ARG_REPLACE },
2393 {}
2394 };
2395
2396 int c, r;
2397
2398 assert(argc >= 0);
2399 assert(argv);
2400
2401 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
2402
2403 switch (c) {
2404
2405 case 'h':
2406 help();
2407 return 0;
2408
2409 case ARG_VERSION:
2410 return version();
2411
2412 case ARG_USER:
2413 arg_user = true;
2414 break;
2415
2416 case ARG_CREATE:
2417 arg_create = true;
2418 break;
2419
2420 case ARG_CLEAN:
2421 arg_clean = true;
2422 break;
2423
2424 case ARG_REMOVE:
2425 arg_remove = true;
2426 break;
2427
2428 case ARG_BOOT:
2429 arg_boot = true;
2430 break;
2431
2432 case ARG_PREFIX:
2433 if (strv_push(&arg_include_prefixes, optarg) < 0)
2434 return log_oom();
2435 break;
2436
2437 case ARG_EXCLUDE_PREFIX:
2438 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
2439 return log_oom();
2440 break;
2441
2442 case ARG_ROOT:
2443 r = parse_path_argument_and_warn(optarg, true, &arg_root);
2444 if (r < 0)
2445 return r;
2446 break;
2447
2448 case ARG_REPLACE:
2449 if (!path_is_absolute(optarg) ||
2450 !endswith(optarg, ".conf")) {
2451 log_error("The argument to --replace= must an absolute path to a config file");
2452 return -EINVAL;
2453 }
2454
2455 arg_replace = optarg;
2456 break;
2457
2458 case '?':
2459 return -EINVAL;
2460
2461 default:
2462 assert_not_reached("Unhandled option");
2463 }
2464
2465 if (!arg_clean && !arg_create && !arg_remove) {
2466 log_error("You need to specify at least one of --clean, --create or --remove.");
2467 return -EINVAL;
2468 }
2469
2470 if (arg_replace && optind >= argc) {
2471 log_error("When --replace= is given, some configuration items must be specified");
2472 return -EINVAL;
2473 }
2474
2475 return 1;
2476 }
2477
2478 static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoent, bool *invalid_config) {
2479 _cleanup_fclose_ FILE *_f = NULL;
2480 FILE *f;
2481 char line[LINE_MAX];
2482 Iterator iterator;
2483 unsigned v = 0;
2484 Item *i;
2485 int r = 0;
2486
2487 assert(fn);
2488
2489 if (streq(fn, "-")) {
2490 log_debug("Reading config from stdin…");
2491 fn = "<stdin>";
2492 f = stdin;
2493 } else {
2494 r = search_and_fopen(fn, "re", arg_root, (const char**) config_dirs, &_f);
2495 if (r < 0) {
2496 if (ignore_enoent && r == -ENOENT) {
2497 log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn);
2498 return 0;
2499 }
2500
2501 return log_error_errno(r, "Failed to open '%s': %m", fn);
2502 }
2503 log_debug("Reading config file \"%s\"…", fn);
2504 f = _f;
2505 }
2506
2507 FOREACH_LINE(line, f, break) {
2508 char *l;
2509 int k;
2510 bool invalid_line = false;
2511
2512 v++;
2513
2514 l = strstrip(line);
2515 if (IN_SET(*l, 0, '#'))
2516 continue;
2517
2518 k = parse_line(fn, v, l, &invalid_line);
2519 if (k < 0) {
2520 if (invalid_line)
2521 /* Allow reporting with a special code if the caller requested this */
2522 *invalid_config = true;
2523 else if (r == 0)
2524 /* The first error becomes our return value */
2525 r = k;
2526 }
2527 }
2528
2529 /* we have to determine age parameter for each entry of type X */
2530 ORDERED_HASHMAP_FOREACH(i, globs, iterator) {
2531 Iterator iter;
2532 Item *j, *candidate_item = NULL;
2533
2534 if (i->type != IGNORE_DIRECTORY_PATH)
2535 continue;
2536
2537 ORDERED_HASHMAP_FOREACH(j, items, iter) {
2538 if (!IN_SET(j->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA))
2539 continue;
2540
2541 if (path_equal(j->path, i->path)) {
2542 candidate_item = j;
2543 break;
2544 }
2545
2546 if ((!candidate_item && path_startswith(i->path, j->path)) ||
2547 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
2548 candidate_item = j;
2549 }
2550
2551 if (candidate_item && candidate_item->age_set) {
2552 i->age = candidate_item->age;
2553 i->age_set = true;
2554 }
2555 }
2556
2557 if (ferror(f)) {
2558 log_error_errno(errno, "Failed to read from file %s: %m", fn);
2559 if (r == 0)
2560 r = -EIO;
2561 }
2562
2563 return r;
2564 }
2565
2566 static int parse_arguments(char **config_dirs, char **args, bool *invalid_config) {
2567 char **arg;
2568 int r;
2569
2570 STRV_FOREACH(arg, args) {
2571 r = read_config_file(config_dirs, *arg, false, invalid_config);
2572 if (r < 0)
2573 return r;
2574 }
2575
2576 return 0;
2577 }
2578
2579 static int read_config_files(char **config_dirs, char **args, bool *invalid_config) {
2580 _cleanup_strv_free_ char **files = NULL;
2581 _cleanup_free_ char *p = NULL;
2582 char **f;
2583 int r;
2584
2585 r = conf_files_list_strv(&files, ".conf", arg_root, 0, (const char* const*) config_dirs);
2586 if (r < 0)
2587 return log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
2588
2589 if (arg_replace) {
2590 r = conf_files_insert(&files, arg_root, config_dirs, arg_replace);
2591 if (r < 0)
2592 return log_error_errno(r, "Failed to extend tmpfiles.d file list: %m");
2593
2594 p = path_join(arg_root, arg_replace, NULL);
2595 if (!p)
2596 return log_oom();
2597 }
2598
2599 STRV_FOREACH(f, files)
2600 if (p && path_equal(*f, p)) {
2601 log_debug("Parsing arguments at position \"%s\"…", *f);
2602
2603 r = parse_arguments(config_dirs, args, invalid_config);
2604 if (r < 0)
2605 return r;
2606 } else
2607 /* Just warn, ignore result otherwise.
2608 * read_config_file() has some debug output, so no need to print anything. */
2609 (void) read_config_file(config_dirs, *f, true, invalid_config);
2610
2611 return 0;
2612 }
2613
2614 int main(int argc, char *argv[]) {
2615 int r, k;
2616 ItemArray *a;
2617 Iterator iterator;
2618 _cleanup_strv_free_ char **config_dirs = NULL;
2619 bool invalid_config = false;
2620
2621 r = parse_argv(argc, argv);
2622 if (r <= 0)
2623 goto finish;
2624
2625 log_set_target(LOG_TARGET_AUTO);
2626 log_parse_environment();
2627 log_open();
2628
2629 umask(0022);
2630
2631 mac_selinux_init();
2632
2633 items = ordered_hashmap_new(&string_hash_ops);
2634 globs = ordered_hashmap_new(&string_hash_ops);
2635
2636 if (!items || !globs) {
2637 r = log_oom();
2638 goto finish;
2639 }
2640
2641 r = 0;
2642
2643 if (arg_user) {
2644 r = user_config_paths(&config_dirs);
2645 if (r < 0) {
2646 log_error_errno(r, "Failed to initialize configuration directory list: %m");
2647 goto finish;
2648 }
2649 } else {
2650 config_dirs = strv_split_nulstr(CONF_PATHS_NULSTR("tmpfiles.d"));
2651 if (!config_dirs) {
2652 r = log_oom();
2653 goto finish;
2654 }
2655 }
2656
2657 if (DEBUG_LOGGING) {
2658 _cleanup_free_ char *t = NULL;
2659
2660 t = strv_join(config_dirs, "\n\t");
2661 if (t)
2662 log_debug("Looking for configuration files in (higher priority first:\n\t%s", t);
2663 }
2664
2665 /* If command line arguments are specified along with --replace, read all
2666 * configuration files and insert the positional arguments at the specified
2667 * place. Otherwise, if command line arguments are specified, execute just
2668 * them, and finally, without --replace= or any positional arguments, just
2669 * read configuration and execute it.
2670 */
2671 if (arg_replace || optind >= argc)
2672 r = read_config_files(config_dirs, argv + optind, &invalid_config);
2673 else
2674 r = parse_arguments(config_dirs, argv + optind, &invalid_config);
2675 if (r < 0)
2676 goto finish;
2677
2678
2679
2680 /* The non-globbing ones usually create things, hence we apply
2681 * them first */
2682 ORDERED_HASHMAP_FOREACH(a, items, iterator) {
2683 k = process_item_array(a);
2684 if (k < 0 && r == 0)
2685 r = k;
2686 }
2687
2688 /* The globbing ones usually alter things, hence we apply them
2689 * second. */
2690 ORDERED_HASHMAP_FOREACH(a, globs, iterator) {
2691 k = process_item_array(a);
2692 if (k < 0 && r == 0)
2693 r = k;
2694 }
2695
2696 finish:
2697 ordered_hashmap_free_with_destructor(items, item_array_free);
2698 ordered_hashmap_free_with_destructor(globs, item_array_free);
2699
2700 free(arg_include_prefixes);
2701 free(arg_exclude_prefixes);
2702 free(arg_root);
2703
2704 set_free_free(unix_sockets);
2705
2706 mac_selinux_finish();
2707
2708 if (r < 0)
2709 return EXIT_FAILURE;
2710 else if (invalid_config)
2711 return EX_DATAERR;
2712 else
2713 return EXIT_SUCCESS;
2714 }