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