]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/tmpfiles/tmpfiles.c
systemctl: fix log message when glob patterns passed to disable command and friends
[thirdparty/systemd.git] / src / tmpfiles / tmpfiles.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <fnmatch.h>
6 #include <getopt.h>
7 #include <limits.h>
8 #include <linux/fs.h>
9 #include <stdbool.h>
10 #include <stddef.h>
11 #include <stdlib.h>
12 #include <sys/file.h>
13 #include <sys/xattr.h>
14 #include <sysexits.h>
15 #include <time.h>
16 #include <unistd.h>
17
18 #include "sd-path.h"
19
20 #include "acl-util.h"
21 #include "alloc-util.h"
22 #include "btrfs-util.h"
23 #include "build.h"
24 #include "capability-util.h"
25 #include "chase.h"
26 #include "chattr-util.h"
27 #include "conf-files.h"
28 #include "constants.h"
29 #include "copy.h"
30 #include "creds-util.h"
31 #include "devnum-util.h"
32 #include "dirent-util.h"
33 #include "dissect-image.h"
34 #include "env-util.h"
35 #include "errno-util.h"
36 #include "escape.h"
37 #include "fd-util.h"
38 #include "fileio.h"
39 #include "format-util.h"
40 #include "fs-util.h"
41 #include "glob-util.h"
42 #include "hexdecoct.h"
43 #include "io-util.h"
44 #include "label-util.h"
45 #include "log.h"
46 #include "macro.h"
47 #include "main-func.h"
48 #include "missing_syscall.h"
49 #include "mkdir-label.h"
50 #include "mount-util.h"
51 #include "mountpoint-util.h"
52 #include "offline-passwd.h"
53 #include "pager.h"
54 #include "parse-argument.h"
55 #include "parse-util.h"
56 #include "path-lookup.h"
57 #include "path-util.h"
58 #include "pretty-print.h"
59 #include "rlimit-util.h"
60 #include "rm-rf.h"
61 #include "selinux-util.h"
62 #include "set.h"
63 #include "sort-util.h"
64 #include "specifier.h"
65 #include "stat-util.h"
66 #include "stdio-util.h"
67 #include "string-table.h"
68 #include "string-util.h"
69 #include "strv.h"
70 #include "terminal-util.h"
71 #include "umask-util.h"
72 #include "user-util.h"
73 #include "virt.h"
74
75 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
76 * them in the file system. This is intended to be used to create
77 * properly owned directories beneath /tmp, /var/tmp, /run, which are
78 * volatile and hence need to be recreated on bootup. */
79
80 typedef enum OperationMask {
81 OPERATION_CREATE = 1 << 0,
82 OPERATION_REMOVE = 1 << 1,
83 OPERATION_CLEAN = 1 << 2,
84 OPERATION_PURGE = 1 << 3,
85 } OperationMask;
86
87 typedef enum ItemType {
88 /* These ones take file names */
89 CREATE_FILE = 'f',
90 TRUNCATE_FILE = 'F', /* deprecated: use f+ */
91 CREATE_DIRECTORY = 'd',
92 TRUNCATE_DIRECTORY = 'D',
93 CREATE_SUBVOLUME = 'v',
94 CREATE_SUBVOLUME_INHERIT_QUOTA = 'q',
95 CREATE_SUBVOLUME_NEW_QUOTA = 'Q',
96 CREATE_FIFO = 'p',
97 CREATE_SYMLINK = 'L',
98 CREATE_CHAR_DEVICE = 'c',
99 CREATE_BLOCK_DEVICE = 'b',
100 COPY_FILES = 'C',
101
102 /* These ones take globs */
103 WRITE_FILE = 'w',
104 EMPTY_DIRECTORY = 'e',
105 SET_XATTR = 't',
106 RECURSIVE_SET_XATTR = 'T',
107 SET_ACL = 'a',
108 RECURSIVE_SET_ACL = 'A',
109 SET_ATTRIBUTE = 'h',
110 RECURSIVE_SET_ATTRIBUTE = 'H',
111 IGNORE_PATH = 'x',
112 IGNORE_DIRECTORY_PATH = 'X',
113 REMOVE_PATH = 'r',
114 RECURSIVE_REMOVE_PATH = 'R',
115 RELABEL_PATH = 'z',
116 RECURSIVE_RELABEL_PATH = 'Z',
117 ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
118 } ItemType;
119
120 typedef enum AgeBy {
121 AGE_BY_ATIME = 1 << 0,
122 AGE_BY_BTIME = 1 << 1,
123 AGE_BY_CTIME = 1 << 2,
124 AGE_BY_MTIME = 1 << 3,
125
126 /* All file timestamp types are checked by default. */
127 AGE_BY_DEFAULT_FILE = AGE_BY_ATIME | AGE_BY_BTIME | AGE_BY_CTIME | AGE_BY_MTIME,
128 AGE_BY_DEFAULT_DIR = AGE_BY_ATIME | AGE_BY_BTIME | AGE_BY_MTIME,
129 } AgeBy;
130
131 typedef struct Item {
132 ItemType type;
133
134 char *path;
135 char *argument;
136 void *binary_argument; /* set if binary data, in which case it takes precedence over 'argument' */
137 size_t binary_argument_size;
138 char **xattrs;
139 #if HAVE_ACL
140 acl_t acl_access;
141 acl_t acl_access_exec;
142 acl_t acl_default;
143 #endif
144 uid_t uid;
145 gid_t gid;
146 mode_t mode;
147 usec_t age;
148 AgeBy age_by_file, age_by_dir;
149
150 dev_t major_minor;
151 unsigned attribute_value;
152 unsigned attribute_mask;
153
154 bool uid_set:1;
155 bool gid_set:1;
156 bool mode_set:1;
157 bool uid_only_create:1;
158 bool gid_only_create:1;
159 bool mode_only_create:1;
160 bool age_set:1;
161 bool mask_perms:1;
162 bool attribute_set:1;
163
164 bool keep_first_level:1;
165
166 bool append_or_force:1;
167
168 bool allow_failure:1;
169
170 bool try_replace:1;
171
172 OperationMask done;
173 } Item;
174
175 typedef struct ItemArray {
176 Item *items;
177 size_t n_items;
178
179 struct ItemArray *parent;
180 Set *children;
181 } ItemArray;
182
183 typedef enum DirectoryType {
184 DIRECTORY_RUNTIME,
185 DIRECTORY_STATE,
186 DIRECTORY_CACHE,
187 DIRECTORY_LOGS,
188 _DIRECTORY_TYPE_MAX,
189 } DirectoryType;
190
191 typedef enum {
192 CREATION_NORMAL,
193 CREATION_EXISTING,
194 CREATION_FORCE,
195 _CREATION_MODE_MAX,
196 _CREATION_MODE_INVALID = -EINVAL,
197 } CreationMode;
198
199 static CatFlags arg_cat_flags = CAT_CONFIG_OFF;
200 static bool arg_dry_run = false;
201 static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
202 static OperationMask arg_operation = 0;
203 static bool arg_boot = false;
204 static bool arg_graceful = false;
205 static PagerFlags arg_pager_flags = 0;
206
207 static char **arg_include_prefixes = NULL;
208 static char **arg_exclude_prefixes = NULL;
209 static char *arg_root = NULL;
210 static char *arg_image = NULL;
211 static char *arg_replace = NULL;
212 static ImagePolicy *arg_image_policy = NULL;
213
214 #define MAX_DEPTH 256
215
216 typedef struct Context {
217 OrderedHashmap *items;
218 OrderedHashmap *globs;
219 Set *unix_sockets;
220 Hashmap *uid_cache;
221 Hashmap *gid_cache;
222 } Context;
223
224 STATIC_DESTRUCTOR_REGISTER(arg_include_prefixes, strv_freep);
225 STATIC_DESTRUCTOR_REGISTER(arg_exclude_prefixes, strv_freep);
226 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
227 STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
228 STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
229
230 static const char *const creation_mode_verb_table[_CREATION_MODE_MAX] = {
231 [CREATION_NORMAL] = "Created",
232 [CREATION_EXISTING] = "Found existing",
233 [CREATION_FORCE] = "Created replacement",
234 };
235
236 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
237
238 static void context_done(Context *c) {
239 assert(c);
240
241 ordered_hashmap_free(c->items);
242 ordered_hashmap_free(c->globs);
243
244 set_free(c->unix_sockets);
245
246 hashmap_free(c->uid_cache);
247 hashmap_free(c->gid_cache);
248 }
249
250 /* Different kinds of errors that mean that information is not available in the environment. */
251 static bool ERRNO_IS_NOINFO(int r) {
252 return IN_SET(abs(r),
253 EUNATCH, /* os-release or machine-id missing */
254 ENOMEDIUM, /* machine-id or another file empty */
255 ENOPKG, /* machine-id is uninitialized */
256 ENXIO); /* env var is unset */
257 }
258
259 static int specifier_directory(
260 char specifier,
261 const void *data,
262 const char *root,
263 const void *userdata,
264 char **ret) {
265
266 struct table_entry {
267 uint64_t type;
268 const char *suffix;
269 };
270
271 static const struct table_entry paths_system[] = {
272 [DIRECTORY_RUNTIME] = { SD_PATH_SYSTEM_RUNTIME },
273 [DIRECTORY_STATE] = { SD_PATH_SYSTEM_STATE_PRIVATE },
274 [DIRECTORY_CACHE] = { SD_PATH_SYSTEM_STATE_CACHE },
275 [DIRECTORY_LOGS] = { SD_PATH_SYSTEM_STATE_LOGS },
276 };
277
278 static const struct table_entry paths_user[] = {
279 [DIRECTORY_RUNTIME] = { SD_PATH_USER_RUNTIME },
280 [DIRECTORY_STATE] = { SD_PATH_USER_STATE_PRIVATE },
281 [DIRECTORY_CACHE] = { SD_PATH_USER_STATE_CACHE },
282 [DIRECTORY_LOGS] = { SD_PATH_USER_STATE_PRIVATE, "log" },
283 };
284
285 const struct table_entry *paths;
286 _cleanup_free_ char *p = NULL;
287 unsigned i;
288 int r;
289
290 assert_cc(ELEMENTSOF(paths_system) == ELEMENTSOF(paths_user));
291 paths = arg_runtime_scope == RUNTIME_SCOPE_USER ? paths_user : paths_system;
292
293 i = PTR_TO_UINT(data);
294 assert(i < ELEMENTSOF(paths_system));
295
296 r = sd_path_lookup(paths[i].type, paths[i].suffix, &p);
297 if (r < 0)
298 return r;
299
300 if (arg_root) {
301 _cleanup_free_ char *j = NULL;
302
303 j = path_join(arg_root, p);
304 if (!j)
305 return -ENOMEM;
306
307 *ret = TAKE_PTR(j);
308 } else
309 *ret = TAKE_PTR(p);
310
311 return 0;
312 }
313
314 static int log_unresolvable_specifier(const char *filename, unsigned line) {
315 static bool notified = false;
316
317 /* In system mode, this is called when /etc is not fully initialized and some specifiers are
318 * unresolvable. In user mode, this is called when some variables are not defined. These cases are
319 * not considered a fatal error, so log at LOG_NOTICE only for the first time and then downgrade this
320 * to LOG_DEBUG for the rest.
321 *
322 * If we're running in a chroot (--root was used or sd_booted() reports that systemd is not running),
323 * always use LOG_DEBUG. We may be called to initialize a chroot before booting and there is no
324 * expectation that machine-id and other files will be populated.
325 */
326
327 int log_level = notified || arg_root || running_in_chroot() > 0 ?
328 LOG_DEBUG : LOG_NOTICE;
329
330 log_syntax(NULL,
331 log_level,
332 filename, line, 0,
333 "Failed to resolve specifier: %s, skipping.",
334 arg_runtime_scope == RUNTIME_SCOPE_USER ? "Required $XDG_... variable not defined" : "uninitialized /etc/ detected");
335
336 if (!notified)
337 log_full(log_level,
338 "All rules containing unresolvable specifiers will be skipped.");
339
340 notified = true;
341 return 0;
342 }
343
344 #define log_action(would, doing, fmt, ...) \
345 log_full(arg_dry_run ? LOG_INFO : LOG_DEBUG, \
346 fmt, \
347 arg_dry_run ? (would) : (doing), \
348 __VA_ARGS__)
349
350 static int user_config_paths(char*** ret) {
351 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
352 _cleanup_free_ char *persistent_config = NULL, *runtime_config = NULL, *data_home = NULL;
353 _cleanup_strv_free_ char **res = NULL;
354 int r;
355
356 r = xdg_user_dirs(&config_dirs, &data_dirs);
357 if (r < 0)
358 return r;
359
360 r = xdg_user_config_dir(&persistent_config, "/user-tmpfiles.d");
361 if (r < 0 && !ERRNO_IS_NOINFO(r))
362 return r;
363
364 r = xdg_user_runtime_dir(&runtime_config, "/user-tmpfiles.d");
365 if (r < 0 && !ERRNO_IS_NOINFO(r))
366 return r;
367
368 r = xdg_user_data_dir(&data_home, "/user-tmpfiles.d");
369 if (r < 0 && !ERRNO_IS_NOINFO(r))
370 return r;
371
372 r = strv_extend_strv_concat(&res, (const char* const*) config_dirs, "/user-tmpfiles.d");
373 if (r < 0)
374 return r;
375
376 r = strv_extend_many(
377 &res,
378 persistent_config,
379 runtime_config,
380 data_home);
381 if (r < 0)
382 return r;
383
384 r = strv_extend_strv_concat(&res, (const char* const*) data_dirs, "/user-tmpfiles.d");
385 if (r < 0)
386 return r;
387
388 r = path_strv_make_absolute_cwd(res);
389 if (r < 0)
390 return r;
391
392 *ret = TAKE_PTR(res);
393 return 0;
394 }
395
396 static bool needs_purge(ItemType t) {
397 return IN_SET(t,
398 COPY_FILES,
399 TRUNCATE_FILE,
400 CREATE_FILE,
401 WRITE_FILE,
402 EMPTY_DIRECTORY,
403 CREATE_SUBVOLUME,
404 CREATE_SUBVOLUME_INHERIT_QUOTA,
405 CREATE_SUBVOLUME_NEW_QUOTA,
406 CREATE_CHAR_DEVICE,
407 CREATE_BLOCK_DEVICE,
408 CREATE_SYMLINK,
409 CREATE_FIFO,
410 CREATE_DIRECTORY,
411 TRUNCATE_DIRECTORY);
412 }
413
414 static bool needs_glob(ItemType t) {
415 return IN_SET(t,
416 WRITE_FILE,
417 EMPTY_DIRECTORY,
418 SET_XATTR,
419 RECURSIVE_SET_XATTR,
420 SET_ACL,
421 RECURSIVE_SET_ACL,
422 SET_ATTRIBUTE,
423 RECURSIVE_SET_ATTRIBUTE,
424 IGNORE_PATH,
425 IGNORE_DIRECTORY_PATH,
426 REMOVE_PATH,
427 RECURSIVE_REMOVE_PATH,
428 RELABEL_PATH,
429 RECURSIVE_RELABEL_PATH,
430 ADJUST_MODE);
431 }
432
433 static bool takes_ownership(ItemType t) {
434 return IN_SET(t,
435 CREATE_FILE,
436 TRUNCATE_FILE,
437 CREATE_DIRECTORY,
438 TRUNCATE_DIRECTORY,
439 CREATE_SUBVOLUME,
440 CREATE_SUBVOLUME_INHERIT_QUOTA,
441 CREATE_SUBVOLUME_NEW_QUOTA,
442 CREATE_FIFO,
443 CREATE_SYMLINK,
444 CREATE_CHAR_DEVICE,
445 CREATE_BLOCK_DEVICE,
446 COPY_FILES,
447 WRITE_FILE,
448 EMPTY_DIRECTORY,
449 IGNORE_PATH,
450 IGNORE_DIRECTORY_PATH,
451 REMOVE_PATH,
452 RECURSIVE_REMOVE_PATH);
453 }
454
455 static struct Item* find_glob(OrderedHashmap *h, const char *match) {
456 ItemArray *j;
457
458 ORDERED_HASHMAP_FOREACH(j, h)
459 FOREACH_ARRAY(item, j->items, j->n_items)
460 if (fnmatch(item->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
461 return item;
462 return NULL;
463 }
464
465 static int load_unix_sockets(Context *c) {
466 _cleanup_set_free_ Set *sockets = NULL;
467 _cleanup_fclose_ FILE *f = NULL;
468 int r;
469
470 if (c->unix_sockets)
471 return 0;
472
473 /* We maintain a cache of the sockets we found in /proc/net/unix to speed things up a little. */
474
475 f = fopen("/proc/net/unix", "re");
476 if (!f)
477 return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
478 "Failed to open /proc/net/unix, ignoring: %m");
479
480 /* Skip header */
481 r = read_line(f, LONG_LINE_MAX, NULL);
482 if (r < 0)
483 return log_warning_errno(r, "Failed to skip /proc/net/unix header line: %m");
484 if (r == 0)
485 return log_warning_errno(SYNTHETIC_ERRNO(EIO), "Premature end of file reading /proc/net/unix.");
486
487 for (;;) {
488 _cleanup_free_ char *line = NULL;
489 char *p;
490
491 r = read_line(f, LONG_LINE_MAX, &line);
492 if (r < 0)
493 return log_warning_errno(r, "Failed to read /proc/net/unix line, ignoring: %m");
494 if (r == 0) /* EOF */
495 break;
496
497 p = strchr(line, ':');
498 if (!p)
499 continue;
500
501 if (strlen(p) < 37)
502 continue;
503
504 p += 37;
505 p += strspn(p, WHITESPACE);
506 p += strcspn(p, WHITESPACE); /* skip one more word */
507 p += strspn(p, WHITESPACE);
508
509 if (!path_is_absolute(p))
510 continue;
511
512 r = set_put_strdup_full(&sockets, &path_hash_ops_free, p);
513 if (r < 0)
514 return log_warning_errno(r, "Failed to add AF_UNIX socket to set, ignoring: %m");
515 }
516
517 c->unix_sockets = TAKE_PTR(sockets);
518 return 1;
519 }
520
521 static bool unix_socket_alive(Context *c, const char *fn) {
522 assert(c);
523 assert(fn);
524
525 if (load_unix_sockets(c) < 0)
526 return true; /* We don't know, so assume yes */
527
528 return set_contains(c->unix_sockets, fn);
529 }
530
531 /* Accessors for the argument in binary format */
532 static const void* item_binary_argument(const Item *i) {
533 assert(i);
534 return i->binary_argument ?: i->argument;
535 }
536
537 static size_t item_binary_argument_size(const Item *i) {
538 assert(i);
539 return i->binary_argument ? i->binary_argument_size : strlen_ptr(i->argument);
540 }
541
542 static DIR* xopendirat_nomod(int dirfd, const char *path) {
543 DIR *dir;
544
545 dir = xopendirat(dirfd, path, O_NOFOLLOW|O_NOATIME);
546 if (dir)
547 return dir;
548
549 if (!IN_SET(errno, ENOENT, ELOOP))
550 log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m", dirfd == AT_FDCWD ? "" : "sub", path);
551
552 if (errno != EPERM)
553 return NULL;
554
555 dir = xopendirat(dirfd, path, O_NOFOLLOW);
556 if (!dir)
557 log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m", dirfd == AT_FDCWD ? "" : "sub", path);
558
559 return dir;
560 }
561
562 static DIR* opendir_nomod(const char *path) {
563 return xopendirat_nomod(AT_FDCWD, path);
564 }
565
566 static int opendir_and_stat(
567 const char *path,
568 DIR **ret,
569 struct statx *ret_sx,
570 bool *ret_mountpoint) {
571
572 _cleanup_closedir_ DIR *d = NULL;
573 STRUCT_NEW_STATX_DEFINE(st1);
574 int r;
575
576 assert(path);
577 assert(ret);
578 assert(ret_sx);
579 assert(ret_mountpoint);
580
581 /* Do opendir() and statx() on the directory.
582 * Return 1 if successful, 0 if file doesn't exist or is not a directory,
583 * negative errno otherwise.
584 */
585
586 d = opendir_nomod(path);
587 if (!d) {
588 bool ignore = IN_SET(errno, ENOENT, ENOTDIR);
589 r = log_full_errno(ignore ? LOG_DEBUG : LOG_ERR,
590 errno, "Failed to open directory %s: %m", path);
591 if (!ignore)
592 return r;
593
594 *ret = NULL;
595 *ret_sx = (struct statx) {};
596 *ret_mountpoint = NULL;
597 return 0;
598 }
599
600 r = statx_fallback(dirfd(d), "", AT_EMPTY_PATH, STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME, &st1.sx);
601 if (r < 0)
602 return log_error_errno(r, "statx(%s) failed: %m", path);
603
604 if (FLAGS_SET(st1.sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT))
605 *ret_mountpoint = FLAGS_SET(st1.sx.stx_attributes, STATX_ATTR_MOUNT_ROOT);
606 else {
607 STRUCT_NEW_STATX_DEFINE(st2);
608
609 r = statx_fallback(dirfd(d), "..", 0, STATX_INO, &st2.sx);
610 if (r < 0)
611 return log_error_errno(r, "statx(%s/..) failed: %m", path);
612
613 *ret_mountpoint = !statx_mount_same(&st1.nsx, &st2.nsx);
614 }
615
616 *ret = TAKE_PTR(d);
617 *ret_sx = st1.sx;
618 return 1;
619 }
620
621 static bool needs_cleanup(
622 nsec_t atime,
623 nsec_t btime,
624 nsec_t ctime,
625 nsec_t mtime,
626 nsec_t cutoff,
627 const char *sub_path,
628 AgeBy age_by,
629 bool is_dir) {
630
631 if (FLAGS_SET(age_by, AGE_BY_MTIME) && mtime != NSEC_INFINITY && mtime >= cutoff) {
632 /* Follows spelling in stat(1). */
633 log_debug("%s \"%s\": modify time %s is too new.",
634 is_dir ? "Directory" : "File",
635 sub_path,
636 FORMAT_TIMESTAMP_STYLE(mtime / NSEC_PER_USEC, TIMESTAMP_US));
637
638 return false;
639 }
640
641 if (FLAGS_SET(age_by, AGE_BY_ATIME) && atime != NSEC_INFINITY && atime >= cutoff) {
642 log_debug("%s \"%s\": access time %s is too new.",
643 is_dir ? "Directory" : "File",
644 sub_path,
645 FORMAT_TIMESTAMP_STYLE(atime / NSEC_PER_USEC, TIMESTAMP_US));
646
647 return false;
648 }
649
650 /*
651 * Note: Unless explicitly specified by the user, "ctime" is ignored
652 * by default for directories, because we change it when deleting.
653 */
654 if (FLAGS_SET(age_by, AGE_BY_CTIME) && ctime != NSEC_INFINITY && ctime >= cutoff) {
655 log_debug("%s \"%s\": change time %s is too new.",
656 is_dir ? "Directory" : "File",
657 sub_path,
658 FORMAT_TIMESTAMP_STYLE(ctime / NSEC_PER_USEC, TIMESTAMP_US));
659
660 return false;
661 }
662
663 if (FLAGS_SET(age_by, AGE_BY_BTIME) && btime != NSEC_INFINITY && btime >= cutoff) {
664 log_debug("%s \"%s\": birth time %s is too new.",
665 is_dir ? "Directory" : "File",
666 sub_path,
667 FORMAT_TIMESTAMP_STYLE(btime / NSEC_PER_USEC, TIMESTAMP_US));
668
669 return false;
670 }
671
672 return true;
673 }
674
675 static int dir_cleanup(
676 Context *c,
677 Item *i,
678 const char *p,
679 DIR *d,
680 nsec_t self_atime_nsec,
681 nsec_t self_mtime_nsec,
682 nsec_t cutoff_nsec,
683 dev_t rootdev_major,
684 dev_t rootdev_minor,
685 bool mountpoint,
686 int maxdepth,
687 bool keep_this_level,
688 AgeBy age_by_file,
689 AgeBy age_by_dir) {
690
691 bool deleted = false;
692 int r = 0;
693
694 assert(c);
695 assert(i);
696 assert(d);
697
698 FOREACH_DIRENT_ALL(de, d, break) {
699 _cleanup_free_ char *sub_path = NULL;
700 nsec_t atime_nsec, mtime_nsec, ctime_nsec, btime_nsec;
701
702 if (dot_or_dot_dot(de->d_name))
703 continue;
704
705 /* If statx() is supported, use it. It's preferable over fstatat() since it tells us
706 * explicitly where we are looking at a mount point, for free as side information. Determining
707 * the same information without statx() is hard, see the complexity of path_is_mount_point(),
708 * and also much slower as it requires a number of syscalls instead of just one. Hence, when
709 * we have modern statx() we use it instead of fstat() and do proper mount point checks,
710 * while on older kernels's well do traditional st_dev based detection of mount points.
711 *
712 * Using statx() for detecting mount points also has the benefit that we handle weird file
713 * systems such as overlayfs better where each file is originating from a different
714 * st_dev. */
715
716 STRUCT_STATX_DEFINE(sx);
717
718 r = statx_fallback(
719 dirfd(d), de->d_name,
720 AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT,
721 STATX_TYPE|STATX_MODE|STATX_UID|STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_BTIME,
722 &sx);
723 if (r == -ENOENT)
724 continue;
725 if (r < 0) {
726 /* FUSE, NFS mounts, SELinux might return EACCES */
727 log_full_errno(r == -EACCES ? LOG_DEBUG : LOG_ERR, r,
728 "statx(%s/%s) failed: %m", p, de->d_name);
729 continue;
730 }
731
732 if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) {
733 /* Yay, we have the mount point API, use it */
734 if (FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT)) {
735 log_debug("Ignoring \"%s/%s\": different mount points.", p, de->d_name);
736 continue;
737 }
738 } else {
739 /* So we might have statx() but the STATX_ATTR_MOUNT_ROOT flag is not supported, fall
740 * back to traditional stx_dev checking. */
741 if (sx.stx_dev_major != rootdev_major ||
742 sx.stx_dev_minor != rootdev_minor) {
743 log_debug("Ignoring \"%s/%s\": different filesystem.", p, de->d_name);
744 continue;
745 }
746
747 /* Try to detect bind mounts of the same filesystem instance; they do not differ in
748 * device major/minors. This type of query is not supported on all kernels or
749 * filesystem types though. */
750 if (S_ISDIR(sx.stx_mode)) {
751 int q;
752
753 q = fd_is_mount_point(dirfd(d), de->d_name, 0);
754 if (q < 0)
755 log_debug_errno(q, "Failed to determine whether \"%s/%s\" is a mount point, ignoring: %m", p, de->d_name);
756 else if (q > 0) {
757 log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.", p, de->d_name);
758 continue;
759 }
760 }
761 }
762
763 atime_nsec = FLAGS_SET(sx.stx_mask, STATX_ATIME) ? statx_timestamp_load_nsec(&sx.stx_atime) : 0;
764 mtime_nsec = FLAGS_SET(sx.stx_mask, STATX_MTIME) ? statx_timestamp_load_nsec(&sx.stx_mtime) : 0;
765 ctime_nsec = FLAGS_SET(sx.stx_mask, STATX_CTIME) ? statx_timestamp_load_nsec(&sx.stx_ctime) : 0;
766 btime_nsec = FLAGS_SET(sx.stx_mask, STATX_BTIME) ? statx_timestamp_load_nsec(&sx.stx_btime) : 0;
767
768 sub_path = path_join(p, de->d_name);
769 if (!sub_path) {
770 r = log_oom();
771 goto finish;
772 }
773
774 /* Is there an item configured for this path? */
775 if (ordered_hashmap_get(c->items, sub_path)) {
776 log_debug("Ignoring \"%s\": a separate entry exists.", sub_path);
777 continue;
778 }
779
780 if (find_glob(c->globs, sub_path)) {
781 log_debug("Ignoring \"%s\": a separate glob exists.", sub_path);
782 continue;
783 }
784
785 if (S_ISDIR(sx.stx_mode)) {
786 _cleanup_closedir_ DIR *sub_dir = NULL;
787
788 if (mountpoint &&
789 streq(de->d_name, "lost+found") &&
790 sx.stx_uid == 0) {
791 log_debug("Ignoring directory \"%s\".", sub_path);
792 continue;
793 }
794
795 if (maxdepth <= 0)
796 log_warning("Reached max depth on \"%s\".", sub_path);
797 else {
798 int q;
799
800 sub_dir = xopendirat_nomod(dirfd(d), de->d_name);
801 if (!sub_dir) {
802 if (errno != ENOENT)
803 r = log_warning_errno(errno, "Opening directory \"%s\" failed, ignoring: %m", sub_path);
804
805 continue;
806 }
807
808 if (!arg_dry_run &&
809 flock(dirfd(sub_dir), LOCK_EX|LOCK_NB) < 0) {
810 log_debug_errno(errno, "Couldn't acquire shared BSD lock on directory \"%s\", skipping: %m", sub_path);
811 continue;
812 }
813
814 q = dir_cleanup(c, i,
815 sub_path, sub_dir,
816 atime_nsec, mtime_nsec, cutoff_nsec,
817 rootdev_major, rootdev_minor,
818 false, maxdepth-1, false,
819 age_by_file, age_by_dir);
820 if (q < 0)
821 r = q;
822 }
823
824 /* Note: if you are wondering why we don't support the sticky bit for excluding
825 * directories from cleaning like we do it for other file system objects: well, the
826 * sticky bit already has a meaning for directories, so we don't want to overload
827 * that. */
828
829 if (keep_this_level) {
830 log_debug("Keeping directory \"%s\".", sub_path);
831 continue;
832 }
833
834 /*
835 * Check the file timestamps of an entry against the
836 * given cutoff time; delete if it is older.
837 */
838 if (!needs_cleanup(atime_nsec, btime_nsec, ctime_nsec, mtime_nsec,
839 cutoff_nsec, sub_path, age_by_dir, true))
840 continue;
841
842 log_action("Would remove", "Removing", "%s directory \"%s\"", sub_path);
843 if (!arg_dry_run &&
844 unlinkat(dirfd(d), de->d_name, AT_REMOVEDIR) < 0 &&
845 !IN_SET(errno, ENOENT, ENOTEMPTY))
846 r = log_warning_errno(errno, "Failed to remove directory \"%s\", ignoring: %m", sub_path);
847
848 } else {
849 _cleanup_close_ int fd = -EBADF; /* This file descriptor is defined here so that the
850 * lock that is taken below is only dropped _after_
851 * the unlink operation has finished. */
852
853 /* Skip files for which the sticky bit is set. These are semantics we define, and are
854 * unknown elsewhere. See XDG_RUNTIME_DIR specification for details. */
855 if (sx.stx_mode & S_ISVTX) {
856 log_debug("Skipping \"%s\": sticky bit set.", sub_path);
857 continue;
858 }
859
860 if (mountpoint &&
861 S_ISREG(sx.stx_mode) &&
862 sx.stx_uid == 0 &&
863 STR_IN_SET(de->d_name,
864 ".journal",
865 "aquota.user",
866 "aquota.group")) {
867 log_debug("Skipping \"%s\".", sub_path);
868 continue;
869 }
870
871 /* Ignore sockets that are listed in /proc/net/unix */
872 if (S_ISSOCK(sx.stx_mode) && unix_socket_alive(c, sub_path)) {
873 log_debug("Skipping \"%s\": live socket.", sub_path);
874 continue;
875 }
876
877 /* Ignore device nodes */
878 if (S_ISCHR(sx.stx_mode) || S_ISBLK(sx.stx_mode)) {
879 log_debug("Skipping \"%s\": a device.", sub_path);
880 continue;
881 }
882
883 /* Keep files on this level if this was requested */
884 if (keep_this_level) {
885 log_debug("Keeping \"%s\".", sub_path);
886 continue;
887 }
888
889 if (!needs_cleanup(atime_nsec, btime_nsec, ctime_nsec, mtime_nsec,
890 cutoff_nsec, sub_path, age_by_file, false))
891 continue;
892
893 if (!arg_dry_run) {
894 fd = xopenat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME|O_NONBLOCK);
895 if (fd < 0 && !IN_SET(fd, -ENOENT, -ELOOP))
896 log_warning_errno(fd, "Opening file \"%s\" failed, ignoring: %m", sub_path);
897 if (fd >= 0 && flock(fd, LOCK_EX|LOCK_NB) < 0 && errno == EAGAIN) {
898 log_debug_errno(errno, "Couldn't acquire shared BSD lock on file \"%s\", skipping: %m", sub_path);
899 continue;
900 }
901 }
902
903 log_action("Would remove", "Removing", "%s \"%s\"", sub_path);
904 if (!arg_dry_run &&
905 unlinkat(dirfd(d), de->d_name, 0) < 0 &&
906 errno != ENOENT)
907 r = log_warning_errno(errno, "Failed to remove \"%s\", ignoring: %m", sub_path);
908
909 deleted = true;
910 }
911 }
912
913 finish:
914 if (deleted && (self_atime_nsec < NSEC_INFINITY || self_mtime_nsec < NSEC_INFINITY)) {
915 struct timespec ts[2];
916
917 log_action("Would restore", "Restoring",
918 "%s access and modification time on \"%s\": %s, %s",
919 p,
920 FORMAT_TIMESTAMP_STYLE(self_atime_nsec / NSEC_PER_USEC, TIMESTAMP_US),
921 FORMAT_TIMESTAMP_STYLE(self_mtime_nsec / NSEC_PER_USEC, TIMESTAMP_US));
922
923 timespec_store_nsec(ts + 0, self_atime_nsec);
924 timespec_store_nsec(ts + 1, self_mtime_nsec);
925
926 /* Restore original directory timestamps */
927 if (!arg_dry_run &&
928 futimens(dirfd(d), ts) < 0)
929 log_warning_errno(errno, "Failed to revert timestamps of '%s', ignoring: %m", p);
930 }
931
932 return r;
933 }
934
935 static bool dangerous_hardlinks(void) {
936 _cleanup_free_ char *value = NULL;
937 static int cached = -1;
938 int r;
939
940 /* Check whether the fs.protected_hardlinks sysctl is on. If we can't determine it we assume its off,
941 * as that's what the upstream default is. */
942
943 if (cached >= 0)
944 return cached;
945
946 r = read_one_line_file("/proc/sys/fs/protected_hardlinks", &value);
947 if (r < 0) {
948 log_debug_errno(r, "Failed to read fs.protected_hardlinks sysctl: %m");
949 return true;
950 }
951
952 r = parse_boolean(value);
953 if (r < 0) {
954 log_debug_errno(r, "Failed to parse fs.protected_hardlinks sysctl: %m");
955 return true;
956 }
957
958 cached = r == 0;
959 return cached;
960 }
961
962 static bool hardlink_vulnerable(const struct stat *st) {
963 assert(st);
964
965 return !S_ISDIR(st->st_mode) && st->st_nlink > 1 && dangerous_hardlinks();
966 }
967
968 static mode_t process_mask_perms(mode_t mode, mode_t current) {
969
970 if ((current & 0111) == 0)
971 mode &= ~0111;
972 if ((current & 0222) == 0)
973 mode &= ~0222;
974 if ((current & 0444) == 0)
975 mode &= ~0444;
976 if (!S_ISDIR(current))
977 mode &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
978
979 return mode;
980 }
981
982 static int fd_set_perms(
983 Context *c,
984 Item *i,
985 int fd,
986 const char *path,
987 const struct stat *st,
988 CreationMode creation) {
989
990 bool do_chown, do_chmod;
991 struct stat stbuf;
992 mode_t new_mode;
993 uid_t new_uid;
994 gid_t new_gid;
995 int r;
996
997 assert(c);
998 assert(i);
999 assert(fd >= 0);
1000 assert(path);
1001
1002 if (!i->mode_set && !i->uid_set && !i->gid_set)
1003 goto shortcut;
1004
1005 if (!st) {
1006 if (fstat(fd, &stbuf) < 0)
1007 return log_error_errno(errno, "fstat(%s) failed: %m", path);
1008 st = &stbuf;
1009 }
1010
1011 if (hardlink_vulnerable(st))
1012 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
1013 "Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.",
1014 path);
1015 new_uid = i->uid_set && (creation != CREATION_EXISTING || !i->uid_only_create) ? i->uid : st->st_uid;
1016 new_gid = i->gid_set && (creation != CREATION_EXISTING || !i->gid_only_create) ? i->gid : st->st_gid;
1017
1018 /* Do we need a chown()? */
1019 do_chown = (new_uid != st->st_uid) || (new_gid != st->st_gid);
1020
1021 /* Calculate the mode to apply */
1022 new_mode = i->mode_set && (creation != CREATION_EXISTING || !i->mode_only_create) ?
1023 (i->mask_perms ? process_mask_perms(i->mode, st->st_mode) : i->mode) :
1024 (st->st_mode & 07777);
1025
1026 do_chmod = ((new_mode ^ st->st_mode) & 07777) != 0;
1027
1028 if (do_chmod && do_chown) {
1029 /* Before we issue the chmod() let's reduce the access mode to the common bits of the old and
1030 * the new mode. That way there's no time window where the file exists under the old owner
1031 * with more than the old access modes — and not under the new owner with more than the new
1032 * access modes either. */
1033
1034 if (S_ISLNK(st->st_mode))
1035 log_debug("Skipping temporary mode fix for symlink %s.", path);
1036 else {
1037 mode_t m = new_mode & st->st_mode; /* Mask new mode by old mode */
1038
1039 if (((m ^ st->st_mode) & 07777) == 0)
1040 log_debug("\"%s\" matches temporary mode %o already.", path, m);
1041 else {
1042 log_action("Would temporarily change", "Temporarily changing",
1043 "%s \"%s\" to mode %o", path, m);
1044 if (!arg_dry_run) {
1045 r = fchmod_opath(fd, m);
1046 if (r < 0)
1047 return log_error_errno(r, "fchmod() of %s failed: %m", path);
1048 }
1049 }
1050 }
1051 }
1052
1053 if (do_chown) {
1054 log_action("Would change", "Changing",
1055 "%s \"%s\" to owner "UID_FMT":"GID_FMT, path, new_uid, new_gid);
1056
1057 if (!arg_dry_run &&
1058 fchownat(fd, "",
1059 new_uid != st->st_uid ? new_uid : UID_INVALID,
1060 new_gid != st->st_gid ? new_gid : GID_INVALID,
1061 AT_EMPTY_PATH) < 0)
1062 return log_error_errno(errno, "fchownat() of %s failed: %m", path);
1063 }
1064
1065 /* Now, apply the final mode. We do this in two cases: when the user set a mode explicitly, or after a
1066 * chown(), since chown()'s mangle the access mode in regards to sgid/suid in some conditions. */
1067 if (do_chmod || do_chown) {
1068 if (S_ISLNK(st->st_mode))
1069 log_debug("Skipping mode fix for symlink %s.", path);
1070 else {
1071 log_action("Would change", "Changing", "%s \"%s\" to mode %o", path, new_mode);
1072 if (!arg_dry_run) {
1073 r = fchmod_opath(fd, new_mode);
1074 if (r < 0)
1075 return log_error_errno(r, "fchmod() of %s failed: %m", path);
1076 }
1077 }
1078 }
1079
1080 shortcut:
1081 return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, 0);
1082 }
1083
1084 static int path_open_parent_safe(const char *path, bool allow_failure) {
1085 _cleanup_free_ char *dn = NULL;
1086 int r, fd;
1087
1088 if (!path_is_normalized(path))
1089 return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
1090 SYNTHETIC_ERRNO(EINVAL),
1091 "Failed to open parent of '%s': path not normalized%s.",
1092 path,
1093 allow_failure ? ", ignoring" : "");
1094
1095 r = path_extract_directory(path, &dn);
1096 if (r < 0)
1097 return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
1098 r,
1099 "Unable to determine parent directory of '%s'%s: %m",
1100 path,
1101 allow_failure ? ", ignoring" : "");
1102
1103 r = chase(dn, arg_root, allow_failure ? CHASE_SAFE : CHASE_SAFE|CHASE_WARN, NULL, &fd);
1104 if (r == -ENOLINK) /* Unsafe symlink: already covered by CHASE_WARN */
1105 return r;
1106 if (r < 0)
1107 return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
1108 r,
1109 "Failed to open path '%s'%s: %m",
1110 dn,
1111 allow_failure ? ", ignoring" : "");
1112
1113 return fd;
1114 }
1115
1116 static int path_open_safe(const char *path) {
1117 int r, fd;
1118
1119 /* path_open_safe() returns a file descriptor opened with O_PATH after
1120 * verifying that the path doesn't contain unsafe transitions, except
1121 * for its final component as the function does not follow symlink. */
1122
1123 assert(path);
1124
1125 if (!path_is_normalized(path))
1126 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to open invalid path '%s'.", path);
1127
1128 r = chase(path, arg_root, CHASE_SAFE|CHASE_WARN|CHASE_NOFOLLOW, NULL, &fd);
1129 if (r == -ENOLINK)
1130 return r; /* Unsafe symlink: already covered by CHASE_WARN */
1131 if (r < 0)
1132 return log_error_errno(r, "Failed to open path %s: %m", path);
1133
1134 return fd;
1135 }
1136
1137 static int path_set_perms(
1138 Context *c,
1139 Item *i,
1140 const char *path,
1141 CreationMode creation) {
1142
1143 _cleanup_close_ int fd = -EBADF;
1144
1145 assert(c);
1146 assert(i);
1147 assert(path);
1148
1149 fd = path_open_safe(path);
1150 if (fd < 0)
1151 return fd;
1152
1153 return fd_set_perms(c, i, fd, path, /* st= */ NULL, creation);
1154 }
1155
1156 static int parse_xattrs_from_arg(Item *i) {
1157 const char *p;
1158 int r;
1159
1160 assert(i);
1161
1162 assert_se(p = i->argument);
1163 for (;;) {
1164 _cleanup_free_ char *name = NULL, *value = NULL, *xattr = NULL;
1165
1166 r = extract_first_word(&p, &xattr, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
1167 if (r < 0)
1168 log_warning_errno(r, "Failed to parse extended attribute '%s', ignoring: %m", p);
1169 if (r <= 0)
1170 break;
1171
1172 r = split_pair(xattr, "=", &name, &value);
1173 if (r < 0) {
1174 log_warning_errno(r, "Failed to parse extended attribute, ignoring: %s", xattr);
1175 continue;
1176 }
1177
1178 if (isempty(name) || isempty(value)) {
1179 log_warning("Malformed extended attribute found, ignoring: %s", xattr);
1180 continue;
1181 }
1182
1183 if (strv_push_pair(&i->xattrs, name, value) < 0)
1184 return log_oom();
1185
1186 name = value = NULL;
1187 }
1188
1189 return 0;
1190 }
1191
1192 static int fd_set_xattrs(
1193 Context *c,
1194 Item *i,
1195 int fd,
1196 const char *path,
1197 const struct stat *st,
1198 CreationMode creation) {
1199
1200 assert(c);
1201 assert(i);
1202 assert(fd >= 0);
1203 assert(path);
1204
1205 STRV_FOREACH_PAIR(name, value, i->xattrs) {
1206 log_action("Would set", "Setting",
1207 "%s extended attribute '%s=%s' on %s", *name, *value, path);
1208
1209 if (!arg_dry_run &&
1210 setxattr(FORMAT_PROC_FD_PATH(fd), *name, *value, strlen(*value), 0) < 0)
1211 return log_error_errno(errno, "Setting extended attribute %s=%s on %s failed: %m",
1212 *name, *value, path);
1213 }
1214 return 0;
1215 }
1216
1217 static int path_set_xattrs(
1218 Context *c,
1219 Item *i,
1220 const char *path,
1221 CreationMode creation) {
1222
1223 _cleanup_close_ int fd = -EBADF;
1224
1225 assert(c);
1226 assert(i);
1227 assert(path);
1228
1229 fd = path_open_safe(path);
1230 if (fd < 0)
1231 return fd;
1232
1233 return fd_set_xattrs(c, i, fd, path, /* st = */ NULL, creation);
1234 }
1235
1236 static int parse_acls_from_arg(Item *item) {
1237 #if HAVE_ACL
1238 int r;
1239
1240 assert(item);
1241
1242 /* If append_or_force (= modify) is set, we will not modify the acl
1243 * afterwards, so the mask can be added now if necessary. */
1244
1245 r = parse_acl(item->argument, &item->acl_access, &item->acl_access_exec,
1246 &item->acl_default, !item->append_or_force);
1247 if (r < 0)
1248 log_full_errno(arg_graceful && IN_SET(r, -EINVAL, -ENOENT, -ESRCH) ? LOG_DEBUG : LOG_WARNING,
1249 r, "Failed to parse ACL \"%s\", ignoring: %m", item->argument);
1250 #else
1251 log_warning("ACLs are not supported, ignoring.");
1252 #endif
1253
1254 return 0;
1255 }
1256
1257 #if HAVE_ACL
1258 static int parse_acl_cond_exec(
1259 const char *path,
1260 const struct stat *st,
1261 acl_t cond_exec,
1262 acl_t access, /* could be empty (NULL) */
1263 bool append,
1264 acl_t *ret) {
1265
1266 acl_entry_t entry;
1267 acl_permset_t permset;
1268 bool has_exec;
1269 int r;
1270
1271 assert(path);
1272 assert(st);
1273 assert(cond_exec);
1274 assert(ret);
1275
1276 if (!S_ISDIR(st->st_mode)) {
1277 _cleanup_(acl_freep) acl_t old = NULL;
1278
1279 old = acl_get_file(path, ACL_TYPE_ACCESS);
1280 if (!old)
1281 return -errno;
1282
1283 has_exec = false;
1284
1285 for (r = acl_get_entry(old, ACL_FIRST_ENTRY, &entry);
1286 r > 0;
1287 r = acl_get_entry(old, ACL_NEXT_ENTRY, &entry)) {
1288
1289 acl_tag_t tag;
1290
1291 if (acl_get_tag_type(entry, &tag) < 0)
1292 return -errno;
1293
1294 if (tag == ACL_MASK)
1295 continue;
1296
1297 /* If not appending, skip ACL definitions */
1298 if (!append && IN_SET(tag, ACL_USER, ACL_GROUP))
1299 continue;
1300
1301 if (acl_get_permset(entry, &permset) < 0)
1302 return -errno;
1303
1304 r = acl_get_perm(permset, ACL_EXECUTE);
1305 if (r < 0)
1306 return -errno;
1307 if (r > 0) {
1308 has_exec = true;
1309 break;
1310 }
1311 }
1312 if (r < 0)
1313 return -errno;
1314
1315 /* Check if we're about to set the execute bit in acl_access */
1316 if (!has_exec && access) {
1317 for (r = acl_get_entry(access, ACL_FIRST_ENTRY, &entry);
1318 r > 0;
1319 r = acl_get_entry(access, ACL_NEXT_ENTRY, &entry)) {
1320
1321 if (acl_get_permset(entry, &permset) < 0)
1322 return -errno;
1323
1324 r = acl_get_perm(permset, ACL_EXECUTE);
1325 if (r < 0)
1326 return -errno;
1327 if (r > 0) {
1328 has_exec = true;
1329 break;
1330 }
1331 }
1332 if (r < 0)
1333 return -errno;
1334 }
1335 } else
1336 has_exec = true;
1337
1338 _cleanup_(acl_freep) acl_t parsed = access ? acl_dup(access) : acl_init(0);
1339 if (!parsed)
1340 return -errno;
1341
1342 for (r = acl_get_entry(cond_exec, ACL_FIRST_ENTRY, &entry);
1343 r > 0;
1344 r = acl_get_entry(cond_exec, ACL_NEXT_ENTRY, &entry)) {
1345
1346 acl_entry_t parsed_entry;
1347
1348 if (acl_create_entry(&parsed, &parsed_entry) < 0)
1349 return -errno;
1350
1351 if (acl_copy_entry(parsed_entry, entry) < 0)
1352 return -errno;
1353
1354 /* We substituted 'X' with 'x' in parse_acl(), so drop execute bit here if not applicable. */
1355 if (!has_exec) {
1356 if (acl_get_permset(parsed_entry, &permset) < 0)
1357 return -errno;
1358
1359 if (acl_delete_perm(permset, ACL_EXECUTE) < 0)
1360 return -errno;
1361 }
1362 }
1363 if (r < 0)
1364 return -errno;
1365
1366 if (!append) { /* want_mask = true */
1367 r = calc_acl_mask_if_needed(&parsed);
1368 if (r < 0)
1369 return r;
1370 }
1371
1372 *ret = TAKE_PTR(parsed);
1373
1374 return 0;
1375 }
1376
1377 static int path_set_acl(
1378 Context *c,
1379 const char *path,
1380 const char *pretty,
1381 acl_type_t type,
1382 acl_t acl,
1383 bool modify) {
1384
1385 _cleanup_(acl_free_charpp) char *t = NULL;
1386 _cleanup_(acl_freep) acl_t dup = NULL;
1387 int r;
1388
1389 assert(c);
1390
1391 /* Returns 0 for success, positive error if already warned, negative error otherwise. */
1392
1393 if (modify) {
1394 r = acls_for_file(path, type, acl, &dup);
1395 if (r < 0)
1396 return r;
1397
1398 r = calc_acl_mask_if_needed(&dup);
1399 if (r < 0)
1400 return r;
1401 } else {
1402 dup = acl_dup(acl);
1403 if (!dup)
1404 return -errno;
1405
1406 /* the mask was already added earlier if needed */
1407 }
1408
1409 r = add_base_acls_if_needed(&dup, path);
1410 if (r < 0)
1411 return r;
1412
1413 t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE);
1414 log_action("Would set", "Setting",
1415 "%s %s ACL %s on %s",
1416 type == ACL_TYPE_ACCESS ? "access" : "default",
1417 strna(t), pretty);
1418
1419 if (!arg_dry_run &&
1420 acl_set_file(path, type, dup) < 0) {
1421 if (ERRNO_IS_NOT_SUPPORTED(errno))
1422 /* No error if filesystem doesn't support ACLs. Return negative. */
1423 return -errno;
1424 else
1425 /* Return positive to indicate we already warned */
1426 return -log_error_errno(errno,
1427 "Setting %s ACL \"%s\" on %s failed: %m",
1428 type == ACL_TYPE_ACCESS ? "access" : "default",
1429 strna(t), pretty);
1430 }
1431 return 0;
1432 }
1433 #endif
1434
1435 static int fd_set_acls(
1436 Context *c,
1437 Item *item,
1438 int fd,
1439 const char *path,
1440 const struct stat *st,
1441 CreationMode creation) {
1442
1443 int r = 0;
1444 #if HAVE_ACL
1445 _cleanup_(acl_freep) acl_t access_with_exec_parsed = NULL;
1446 struct stat stbuf;
1447
1448 assert(c);
1449 assert(item);
1450 assert(fd >= 0);
1451 assert(path);
1452
1453 if (!st) {
1454 if (fstat(fd, &stbuf) < 0)
1455 return log_error_errno(errno, "fstat(%s) failed: %m", path);
1456 st = &stbuf;
1457 }
1458
1459 if (hardlink_vulnerable(st))
1460 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
1461 "Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.",
1462 path);
1463
1464 if (S_ISLNK(st->st_mode)) {
1465 log_debug("Skipping ACL fix for symlink %s.", path);
1466 return 0;
1467 }
1468
1469 if (item->acl_access_exec) {
1470 r = parse_acl_cond_exec(FORMAT_PROC_FD_PATH(fd), st,
1471 item->acl_access_exec,
1472 item->acl_access,
1473 item->append_or_force,
1474 &access_with_exec_parsed);
1475 if (r < 0)
1476 return log_error_errno(r, "Failed to parse conditionalized execute bit for \"%s\": %m", path);
1477
1478 r = path_set_acl(c, FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_ACCESS, access_with_exec_parsed, item->append_or_force);
1479 } else if (item->acl_access)
1480 r = path_set_acl(c, FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_ACCESS, item->acl_access, item->append_or_force);
1481
1482 /* set only default acls to folders */
1483 if (r == 0 && item->acl_default && S_ISDIR(st->st_mode))
1484 r = path_set_acl(c, FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_DEFAULT, item->acl_default, item->append_or_force);
1485
1486 if (ERRNO_IS_NOT_SUPPORTED(r)) {
1487 log_debug_errno(r, "ACLs not supported by file system at %s", path);
1488 return 0;
1489 }
1490
1491 if (r > 0)
1492 return -r; /* already warned in path_set_acl */
1493
1494 /* The above procfs paths don't work if /proc is not mounted. */
1495 if (r == -ENOENT && proc_mounted() == 0)
1496 r = -ENOSYS;
1497
1498 if (r < 0)
1499 return log_error_errno(r, "ACL operation on \"%s\" failed: %m", path);
1500 #endif
1501 return r;
1502 }
1503
1504 static int path_set_acls(
1505 Context *c,
1506 Item *item,
1507 const char *path,
1508 CreationMode creation) {
1509
1510 int r = 0;
1511 #if HAVE_ACL
1512 _cleanup_close_ int fd = -EBADF;
1513
1514 assert(c);
1515 assert(item);
1516 assert(path);
1517
1518 fd = path_open_safe(path);
1519 if (fd < 0)
1520 return fd;
1521
1522 r = fd_set_acls(c, item, fd, path, /* st= */ NULL, creation);
1523 #endif
1524 return r;
1525 }
1526
1527 static int parse_attribute_from_arg(Item *item) {
1528 static const struct {
1529 char character;
1530 unsigned value;
1531 } attributes[] = {
1532 { 'A', FS_NOATIME_FL }, /* do not update atime */
1533 { 'S', FS_SYNC_FL }, /* Synchronous updates */
1534 { 'D', FS_DIRSYNC_FL }, /* dirsync behaviour (directories only) */
1535 { 'a', FS_APPEND_FL }, /* writes to file may only append */
1536 { 'c', FS_COMPR_FL }, /* Compress file */
1537 { 'd', FS_NODUMP_FL }, /* do not dump file */
1538 { 'e', FS_EXTENT_FL }, /* Extents */
1539 { 'i', FS_IMMUTABLE_FL }, /* Immutable file */
1540 { 'j', FS_JOURNAL_DATA_FL }, /* Reserved for ext3 */
1541 { 's', FS_SECRM_FL }, /* Secure deletion */
1542 { 'u', FS_UNRM_FL }, /* Undelete */
1543 { 't', FS_NOTAIL_FL }, /* file tail should not be merged */
1544 { 'T', FS_TOPDIR_FL }, /* Top of directory hierarchies */
1545 { 'C', FS_NOCOW_FL }, /* Do not cow file */
1546 { 'P', FS_PROJINHERIT_FL }, /* Inherit the quota project ID */
1547 };
1548
1549 enum {
1550 MODE_ADD,
1551 MODE_DEL,
1552 MODE_SET
1553 } mode = MODE_ADD;
1554
1555 unsigned value = 0, mask = 0;
1556 const char *p;
1557
1558 assert(item);
1559
1560 p = item->argument;
1561 if (p) {
1562 if (*p == '+') {
1563 mode = MODE_ADD;
1564 p++;
1565 } else if (*p == '-') {
1566 mode = MODE_DEL;
1567 p++;
1568 } else if (*p == '=') {
1569 mode = MODE_SET;
1570 p++;
1571 }
1572 }
1573
1574 if (isempty(p) && mode != MODE_SET)
1575 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1576 "Setting file attribute on '%s' needs an attribute specification.",
1577 item->path);
1578
1579 for (; p && *p ; p++) {
1580 unsigned i, v;
1581
1582 for (i = 0; i < ELEMENTSOF(attributes); i++)
1583 if (*p == attributes[i].character)
1584 break;
1585
1586 if (i >= ELEMENTSOF(attributes))
1587 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1588 "Unknown file attribute '%c' on '%s'.", *p, item->path);
1589
1590 v = attributes[i].value;
1591
1592 SET_FLAG(value, v, IN_SET(mode, MODE_ADD, MODE_SET));
1593
1594 mask |= v;
1595 }
1596
1597 if (mode == MODE_SET)
1598 mask |= CHATTR_ALL_FL;
1599
1600 assert(mask != 0);
1601
1602 item->attribute_mask = mask;
1603 item->attribute_value = value;
1604 item->attribute_set = true;
1605
1606 return 0;
1607 }
1608
1609 static int fd_set_attribute(
1610 Context *c,
1611 Item *item,
1612 int fd,
1613 const char *path,
1614 const struct stat *st,
1615 CreationMode creation) {
1616
1617 struct stat stbuf;
1618 unsigned f;
1619 int r;
1620
1621 assert(c);
1622 assert(item);
1623 assert(fd >= 0);
1624 assert(path);
1625
1626 if (!item->attribute_set || item->attribute_mask == 0)
1627 return 0;
1628
1629 if (!st) {
1630 if (fstat(fd, &stbuf) < 0)
1631 return log_error_errno(errno, "fstat(%s) failed: %m", path);
1632 st = &stbuf;
1633 }
1634
1635 /* Issuing the file attribute ioctls on device nodes is not safe, as that will be delivered to the
1636 * drivers, not the file system containing the device node. */
1637 if (!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode))
1638 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1639 "Setting file flags is only supported on regular files and directories, cannot set on '%s'.",
1640 path);
1641
1642 f = item->attribute_value & item->attribute_mask;
1643
1644 /* Mask away directory-specific flags */
1645 if (!S_ISDIR(st->st_mode))
1646 f &= ~FS_DIRSYNC_FL;
1647
1648 log_action("Would try to set", "Trying to set",
1649 "%s file attributes 0x%08x on %s",
1650 f & item->attribute_mask,
1651 path);
1652
1653 if (!arg_dry_run) {
1654 _cleanup_close_ int procfs_fd = -EBADF;
1655
1656 procfs_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NOATIME);
1657 if (procfs_fd < 0)
1658 return log_error_errno(procfs_fd, "Failed to reopen '%s': %m", path);
1659
1660 unsigned previous, current;
1661 r = chattr_full(procfs_fd, NULL, f, item->attribute_mask, &previous, &current, CHATTR_FALLBACK_BITWISE);
1662 if (r == -ENOANO)
1663 log_warning("Cannot set file attributes for '%s', maybe due to incompatibility in specified attributes, "
1664 "previous=0x%08x, current=0x%08x, expected=0x%08x, ignoring.",
1665 path, previous, current, (previous & ~item->attribute_mask) | (f & item->attribute_mask));
1666 else if (r < 0)
1667 log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r,
1668 "Cannot set file attributes for '%s', value=0x%08x, mask=0x%08x, ignoring: %m",
1669 path, item->attribute_value, item->attribute_mask);
1670 }
1671
1672 return 0;
1673 }
1674
1675 static int path_set_attribute(
1676 Context *c,
1677 Item *item,
1678 const char *path,
1679 CreationMode creation) {
1680
1681 _cleanup_close_ int fd = -EBADF;
1682
1683 assert(c);
1684 assert(item);
1685
1686 if (!item->attribute_set || item->attribute_mask == 0)
1687 return 0;
1688
1689 fd = path_open_safe(path);
1690 if (fd < 0)
1691 return fd;
1692
1693 return fd_set_attribute(c, item, fd, path, /* st= */ NULL, creation);
1694 }
1695
1696 static int write_argument_data(Item *i, int fd, const char *path) {
1697 int r;
1698
1699 assert(i);
1700 assert(fd >= 0);
1701 assert(path);
1702
1703 if (item_binary_argument_size(i) == 0)
1704 return 0;
1705
1706 assert(item_binary_argument(i));
1707
1708 log_action("Would write", "Writing", "%s to \"%s\"", path);
1709
1710 if (!arg_dry_run) {
1711 r = loop_write(fd, item_binary_argument(i), item_binary_argument_size(i));
1712 if (r < 0)
1713 return log_error_errno(r, "Failed to write file \"%s\": %m", path);
1714 }
1715
1716 return 0;
1717 }
1718
1719 static int write_one_file(Context *c, Item *i, const char *path, CreationMode creation) {
1720 _cleanup_close_ int fd = -EBADF, dir_fd = -EBADF;
1721 _cleanup_free_ char *bn = NULL;
1722 int r;
1723
1724 assert(c);
1725 assert(i);
1726 assert(path);
1727 assert(i->type == WRITE_FILE);
1728
1729 r = path_extract_filename(path, &bn);
1730 if (r < 0)
1731 return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
1732 if (r == O_DIRECTORY)
1733 return log_error_errno(SYNTHETIC_ERRNO(EISDIR), "Cannot open path '%s' for writing, is a directory.", path);
1734
1735 /* Validate the path and keep the fd on the directory for opening the file so we're sure that it
1736 * can't be changed behind our back. */
1737 dir_fd = path_open_parent_safe(path, i->allow_failure);
1738 if (dir_fd < 0)
1739 return dir_fd;
1740
1741 /* Follow symlinks. Open with O_PATH in dry-run mode to make sure we don't use the path inadvertently. */
1742 int flags = O_NONBLOCK | O_CLOEXEC | O_WRONLY | O_NOCTTY | i->append_or_force * O_APPEND | arg_dry_run * O_PATH;
1743 fd = openat(dir_fd, bn, flags, i->mode);
1744 if (fd < 0) {
1745 if (errno == ENOENT) {
1746 log_debug_errno(errno, "Not writing missing file \"%s\": %m", path);
1747 return 0;
1748 }
1749
1750 if (i->allow_failure)
1751 return log_debug_errno(errno, "Failed to open file \"%s\", ignoring: %m", path);
1752
1753 return log_error_errno(errno, "Failed to open file \"%s\": %m", path);
1754 }
1755
1756 /* 'w' is allowed to write into any kind of files. */
1757
1758 r = write_argument_data(i, fd, path);
1759 if (r < 0)
1760 return r;
1761
1762 return fd_set_perms(c, i, fd, path, NULL, creation);
1763 }
1764
1765 static int create_file(
1766 Context *c,
1767 Item *i,
1768 const char *path) {
1769
1770 _cleanup_close_ int fd = -EBADF, dir_fd = -EBADF;
1771 _cleanup_free_ char *bn = NULL;
1772 struct stat stbuf, *st = NULL;
1773 CreationMode creation;
1774 int r = 0;
1775
1776 assert(c);
1777 assert(i);
1778 assert(path);
1779 assert(i->type == CREATE_FILE);
1780
1781 /* 'f' operates on regular files exclusively. */
1782
1783 r = path_extract_filename(path, &bn);
1784 if (r < 0)
1785 return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
1786 if (r == O_DIRECTORY)
1787 return log_error_errno(SYNTHETIC_ERRNO(EISDIR), "Cannot open path '%s' for writing, is a directory.", path);
1788
1789 if (arg_dry_run) {
1790 log_info("Would create file %s", path);
1791 return 0;
1792
1793 /* The opening of the directory below would fail if it doesn't exist,
1794 * so log and exit before even trying to do that. */
1795 }
1796
1797 /* Validate the path and keep the fd on the directory for opening the file so we're sure that it
1798 * can't be changed behind our back. */
1799 dir_fd = path_open_parent_safe(path, i->allow_failure);
1800 if (dir_fd < 0)
1801 return dir_fd;
1802
1803 WITH_UMASK(0000) {
1804 mac_selinux_create_file_prepare(path, S_IFREG);
1805 fd = RET_NERRNO(openat(dir_fd, bn, O_CREAT|O_EXCL|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode));
1806 mac_selinux_create_file_clear();
1807 }
1808
1809 if (fd < 0) {
1810 /* Even on a read-only filesystem, open(2) returns EEXIST if the file already exists. It
1811 * returns EROFS only if it needs to create the file. */
1812 if (fd != -EEXIST)
1813 return log_error_errno(fd, "Failed to create file %s: %m", path);
1814
1815 /* Re-open the file. At that point it must exist since open(2) failed with EEXIST. We still
1816 * need to check if the perms/mode need to be changed. For read-only filesystems, we let
1817 * fd_set_perms() report the error if the perms need to be modified. */
1818 fd = openat(dir_fd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH, i->mode);
1819 if (fd < 0)
1820 return log_error_errno(errno, "Failed to reopen file %s: %m", path);
1821
1822 if (fstat(fd, &stbuf) < 0)
1823 return log_error_errno(errno, "stat(%s) failed: %m", path);
1824
1825 if (!S_ISREG(stbuf.st_mode))
1826 return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
1827 "%s exists and is not a regular file.",
1828 path);
1829
1830 st = &stbuf;
1831 creation = CREATION_EXISTING;
1832 } else {
1833 r = write_argument_data(i, fd, path);
1834 if (r < 0)
1835 return r;
1836
1837 creation = CREATION_NORMAL;
1838 }
1839
1840 return fd_set_perms(c, i, fd, path, st, creation);
1841 }
1842
1843 static int truncate_file(
1844 Context *c,
1845 Item *i,
1846 const char *path) {
1847
1848 _cleanup_close_ int fd = -EBADF, dir_fd = -EBADF;
1849 _cleanup_free_ char *bn = NULL;
1850 struct stat stbuf, *st = NULL;
1851 CreationMode creation;
1852 bool erofs = false;
1853 int r = 0;
1854
1855 assert(c);
1856 assert(i);
1857 assert(path);
1858 assert(i->type == TRUNCATE_FILE || (i->type == CREATE_FILE && i->append_or_force));
1859
1860 /* We want to operate on regular file exclusively especially since O_TRUNC is unspecified if the file
1861 * is neither a regular file nor a fifo nor a terminal device. Therefore we first open the file and
1862 * make sure it's a regular one before truncating it. */
1863
1864 r = path_extract_filename(path, &bn);
1865 if (r < 0)
1866 return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
1867 if (r == O_DIRECTORY)
1868 return log_error_errno(SYNTHETIC_ERRNO(EISDIR), "Cannot open path '%s' for truncation, is a directory.", path);
1869
1870 /* Validate the path and keep the fd on the directory for opening the file so we're sure that it
1871 * can't be changed behind our back. */
1872 dir_fd = path_open_parent_safe(path, i->allow_failure);
1873 if (dir_fd < 0)
1874 return dir_fd;
1875
1876 if (arg_dry_run) {
1877 log_info("Would truncate %s", path);
1878 return 0;
1879 }
1880
1881 creation = CREATION_EXISTING;
1882 fd = RET_NERRNO(openat(dir_fd, bn, O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode));
1883 if (fd == -ENOENT) {
1884 creation = CREATION_NORMAL; /* Didn't work without O_CREATE, try again with */
1885
1886 WITH_UMASK(0000) {
1887 mac_selinux_create_file_prepare(path, S_IFREG);
1888 fd = RET_NERRNO(openat(dir_fd, bn, O_CREAT|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode));
1889 mac_selinux_create_file_clear();
1890 }
1891 }
1892
1893 if (fd < 0) {
1894 if (fd != -EROFS)
1895 return log_error_errno(fd, "Failed to open/create file %s: %m", path);
1896
1897 /* On a read-only filesystem, we don't want to fail if the target is already empty and the
1898 * perms are set. So we still proceed with the sanity checks and let the remaining operations
1899 * fail with EROFS if they try to modify the target file. */
1900
1901 fd = openat(dir_fd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH, i->mode);
1902 if (fd < 0) {
1903 if (errno == ENOENT)
1904 return log_error_errno(SYNTHETIC_ERRNO(EROFS),
1905 "Cannot create file %s on a read-only file system.",
1906 path);
1907
1908 return log_error_errno(errno, "Failed to reopen file %s: %m", path);
1909 }
1910
1911 erofs = true;
1912 creation = CREATION_EXISTING;
1913 }
1914
1915 if (fstat(fd, &stbuf) < 0)
1916 return log_error_errno(errno, "stat(%s) failed: %m", path);
1917
1918 if (!S_ISREG(stbuf.st_mode))
1919 return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
1920 "%s exists and is not a regular file.",
1921 path);
1922
1923 if (stbuf.st_size > 0) {
1924 if (ftruncate(fd, 0) < 0) {
1925 r = erofs ? -EROFS : -errno;
1926 return log_error_errno(r, "Failed to truncate file %s: %m", path);
1927 }
1928 } else
1929 st = &stbuf;
1930
1931 log_debug("\"%s\" has been created.", path);
1932
1933 if (item_binary_argument(i)) {
1934 r = write_argument_data(i, fd, path);
1935 if (r < 0)
1936 return r;
1937 }
1938
1939 return fd_set_perms(c, i, fd, path, st, creation);
1940 }
1941
1942 static int copy_files(Context *c, Item *i) {
1943 _cleanup_close_ int dfd = -EBADF, fd = -EBADF;
1944 _cleanup_free_ char *bn = NULL;
1945 struct stat st, a;
1946 int r;
1947
1948 log_action("Would copy", "Copying", "%s tree \"%s\" to \"%s\"", i->argument, i->path);
1949 if (arg_dry_run)
1950 return 0;
1951
1952 r = path_extract_filename(i->path, &bn);
1953 if (r < 0)
1954 return log_error_errno(r, "Failed to extract filename from path '%s': %m", i->path);
1955
1956 /* Validate the path and use the returned directory fd for copying the target so we're sure that the
1957 * path can't be changed behind our back. */
1958 dfd = path_open_parent_safe(i->path, i->allow_failure);
1959 if (dfd < 0)
1960 return dfd;
1961
1962 r = copy_tree_at(AT_FDCWD, i->argument,
1963 dfd, bn,
1964 i->uid_set ? i->uid : UID_INVALID,
1965 i->gid_set ? i->gid : GID_INVALID,
1966 COPY_REFLINK | ((i->append_or_force) ? COPY_MERGE : COPY_MERGE_EMPTY) | COPY_MAC_CREATE | COPY_HARDLINKS,
1967 NULL, NULL);
1968
1969 fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
1970 if (fd < 0) {
1971 if (r < 0) /* Look at original error first */
1972 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
1973
1974 return log_error_errno(errno, "Failed to openat(%s): %m", i->path);
1975 }
1976
1977 if (fstat(fd, &st) < 0)
1978 return log_error_errno(errno, "Failed to fstat(%s): %m", i->path);
1979
1980 if (stat(i->argument, &a) < 0)
1981 return log_error_errno(errno, "Failed to stat(%s): %m", i->argument);
1982
1983 if (((st.st_mode ^ a.st_mode) & S_IFMT) != 0) {
1984 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
1985 return 0;
1986 }
1987
1988 return fd_set_perms(c, i, fd, i->path, &st, _CREATION_MODE_INVALID);
1989 }
1990
1991 static int create_directory_or_subvolume(
1992 const char *path,
1993 mode_t mode,
1994 bool subvol,
1995 bool allow_failure,
1996 struct stat *ret_st,
1997 CreationMode *ret_creation) {
1998
1999 _cleanup_free_ char *bn = NULL;
2000 _cleanup_close_ int pfd = -EBADF;
2001 CreationMode creation;
2002 struct stat st;
2003 int r, fd;
2004
2005 assert(path);
2006
2007 r = path_extract_filename(path, &bn);
2008 if (r < 0)
2009 return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
2010
2011 pfd = path_open_parent_safe(path, allow_failure);
2012 if (pfd < 0)
2013 return pfd;
2014
2015 if (subvol) {
2016 r = getenv_bool("SYSTEMD_TMPFILES_FORCE_SUBVOL");
2017 if (r < 0) {
2018 if (r != -ENXIO) /* env var is unset */
2019 log_warning_errno(r, "Cannot parse value of $SYSTEMD_TMPFILES_FORCE_SUBVOL, ignoring.");
2020 r = btrfs_is_subvol(empty_to_root(arg_root)) > 0;
2021 }
2022 if (r == 0)
2023 /* Don't create a subvolume unless the root directory is one, too. We do this under
2024 * the assumption that if the root directory is just a plain directory (i.e. very
2025 * light-weight), we shouldn't try to split it up into subvolumes (i.e. more
2026 * heavy-weight). Thus, chroot() environments and suchlike will get a full brtfs
2027 * subvolume set up below their tree only if they specifically set up a btrfs
2028 * subvolume for the root dir too. */
2029 subvol = false;
2030 else {
2031 log_action("Would create", "Creating", "%s btrfs subvolume %s", path);
2032 if (!arg_dry_run)
2033 WITH_UMASK((~mode) & 0777)
2034 r = btrfs_subvol_make(pfd, bn);
2035 else
2036 r = 0;
2037 }
2038 } else
2039 r = 0;
2040
2041 if (!subvol || ERRNO_IS_NEG_NOT_SUPPORTED(r)) {
2042 log_action("Would create", "Creating", "%s directory \"%s\"", path);
2043 if (!arg_dry_run)
2044 WITH_UMASK(0000)
2045 r = mkdirat_label(pfd, bn, mode);
2046 }
2047
2048 if (arg_dry_run)
2049 return 0;
2050
2051 creation = r >= 0 ? CREATION_NORMAL : CREATION_EXISTING;
2052
2053 fd = openat(pfd, bn, O_NOFOLLOW|O_CLOEXEC|O_DIRECTORY|O_PATH);
2054 if (fd < 0) {
2055 /* We couldn't open it because it is not actually a directory? */
2056 if (errno == ENOTDIR)
2057 return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "\"%s\" already exists and is not a directory.", path);
2058
2059 /* Then look at the original error */
2060 if (r < 0)
2061 return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
2062 r,
2063 "Failed to create directory or subvolume \"%s\"%s: %m",
2064 path,
2065 allow_failure ? ", ignoring" : "");
2066
2067 return log_error_errno(errno, "Failed to open directory/subvolume we just created '%s': %m", path);
2068 }
2069
2070 if (fstat(fd, &st) < 0)
2071 return log_error_errno(errno, "Failed to fstat(%s): %m", path);
2072
2073 assert(S_ISDIR(st.st_mode)); /* we used O_DIRECTORY above */
2074
2075 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), path);
2076
2077 if (ret_st)
2078 *ret_st = st;
2079 if (ret_creation)
2080 *ret_creation = creation;
2081
2082 return fd;
2083 }
2084
2085 static int create_directory(
2086 Context *c,
2087 Item *i,
2088 const char *path) {
2089
2090 _cleanup_close_ int fd = -EBADF;
2091 CreationMode creation;
2092 struct stat st;
2093
2094 assert(c);
2095 assert(i);
2096 assert(IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY));
2097
2098 if (arg_dry_run) {
2099 log_info("Would create directory %s", path);
2100 return 0;
2101 }
2102
2103 fd = create_directory_or_subvolume(path, i->mode, /* subvol= */ false, i->allow_failure, &st, &creation);
2104 if (fd == -EEXIST)
2105 return 0;
2106 if (fd < 0)
2107 return fd;
2108
2109 return fd_set_perms(c, i, fd, path, &st, creation);
2110 }
2111
2112 static int create_subvolume(
2113 Context *c,
2114 Item *i,
2115 const char *path) {
2116
2117 _cleanup_close_ int fd = -EBADF;
2118 CreationMode creation;
2119 struct stat st;
2120 int r, q = 0;
2121
2122 assert(c);
2123 assert(i);
2124 assert(IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA));
2125
2126 if (arg_dry_run) {
2127 log_info("Would create subvolume %s", path);
2128 return 0;
2129 }
2130
2131 fd = create_directory_or_subvolume(path, i->mode, /* subvol = */ true, i->allow_failure, &st, &creation);
2132 if (fd == -EEXIST)
2133 return 0;
2134 if (fd < 0)
2135 return fd;
2136
2137 if (creation == CREATION_NORMAL &&
2138 IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
2139 r = btrfs_subvol_auto_qgroup_fd(fd, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
2140 if (r == -ENOTTY)
2141 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path);
2142 else if (r == -EROFS)
2143 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i->path);
2144 else if (r == -ENOTCONN)
2145 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i->path);
2146 else if (r < 0)
2147 q = log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
2148 else if (r > 0)
2149 log_debug("Adjusted quota for subvolume \"%s\".", i->path);
2150 else if (r == 0)
2151 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
2152 }
2153
2154 r = fd_set_perms(c, i, fd, path, &st, creation);
2155 if (q < 0) /* prefer the quota change error from above */
2156 return q;
2157
2158 return r;
2159 }
2160
2161 static int empty_directory(
2162 Context *c,
2163 Item *i,
2164 const char *path,
2165 CreationMode creation) {
2166
2167 _cleanup_close_ int fd = -EBADF;
2168 struct stat st;
2169 int r;
2170
2171 assert(c);
2172 assert(i);
2173 assert(i->type == EMPTY_DIRECTORY);
2174
2175 r = chase(path, arg_root, CHASE_SAFE|CHASE_WARN, NULL, &fd);
2176 if (r == -ENOLINK) /* Unsafe symlink: already covered by CHASE_WARN */
2177 return r;
2178 if (r == -ENOENT) {
2179 /* Option "e" operates only on existing objects. Do not print errors about non-existent files
2180 * or directories */
2181 log_debug_errno(r, "Skipping missing directory: %s", path);
2182 return 0;
2183 }
2184 if (r < 0)
2185 return log_error_errno(r, "Failed to open directory '%s': %m", path);
2186
2187 if (fstat(fd, &st) < 0)
2188 return log_error_errno(errno, "Failed to fstat(%s): %m", path);
2189 if (!S_ISDIR(st.st_mode)) {
2190 log_warning("'%s' already exists and is not a directory.", path);
2191 return 0;
2192 }
2193
2194 return fd_set_perms(c, i, fd, path, &st, creation);
2195 }
2196
2197 static int create_device(
2198 Context *c,
2199 Item *i,
2200 mode_t file_type) {
2201
2202 _cleanup_close_ int dfd = -EBADF, fd = -EBADF;
2203 _cleanup_free_ char *bn = NULL;
2204 CreationMode creation;
2205 struct stat st;
2206 int r;
2207
2208 assert(c);
2209 assert(i);
2210 assert(IN_SET(i->type, CREATE_BLOCK_DEVICE, CREATE_CHAR_DEVICE));
2211 assert(IN_SET(file_type, S_IFBLK, S_IFCHR));
2212
2213 r = path_extract_filename(i->path, &bn);
2214 if (r < 0)
2215 return log_error_errno(r, "Failed to extract filename from path '%s': %m", i->path);
2216 if (r == O_DIRECTORY)
2217 return log_error_errno(SYNTHETIC_ERRNO(EISDIR),
2218 "Cannot open path '%s' for creating device node, is a directory.", i->path);
2219
2220 if (arg_dry_run) {
2221 log_info("Would create device node %s", i->path);
2222 return 0;
2223 }
2224
2225 /* Validate the path and use the returned directory fd for copying the target so we're sure that the
2226 * path can't be changed behind our back. */
2227 dfd = path_open_parent_safe(i->path, i->allow_failure);
2228 if (dfd < 0)
2229 return dfd;
2230
2231 WITH_UMASK(0000) {
2232 mac_selinux_create_file_prepare(i->path, file_type);
2233 r = RET_NERRNO(mknodat(dfd, bn, i->mode | file_type, i->major_minor));
2234 mac_selinux_create_file_clear();
2235 }
2236 creation = r >= 0 ? CREATION_NORMAL : CREATION_EXISTING;
2237
2238 /* Try to open the inode via O_PATH, regardless if we could create it or not. Maybe everything is in
2239 * order anyway and we hence can ignore the error to create the device node */
2240 fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
2241 if (fd < 0) {
2242 /* OK, so opening the inode failed, let's look at the original error then. */
2243
2244 if (r < 0) {
2245 if (ERRNO_IS_PRIVILEGE(r))
2246 goto handle_privilege;
2247
2248 return log_error_errno(r, "Failed to create device node '%s': %m", i->path);
2249 }
2250
2251 return log_error_errno(errno, "Failed to open device node '%s' we just created: %m", i->path);
2252 }
2253
2254 if (fstat(fd, &st) < 0)
2255 return log_error_errno(errno, "Failed to fstat(%s): %m", i->path);
2256
2257 if (((st.st_mode ^ file_type) & S_IFMT) != 0) {
2258
2259 if (i->append_or_force) {
2260 fd = safe_close(fd);
2261
2262 WITH_UMASK(0000) {
2263 mac_selinux_create_file_prepare(i->path, file_type);
2264 r = mknodat_atomic(dfd, bn, i->mode | file_type, i->major_minor);
2265 mac_selinux_create_file_clear();
2266 }
2267 if (ERRNO_IS_PRIVILEGE(r))
2268 goto handle_privilege;
2269 if (IN_SET(r, -EISDIR, -EEXIST, -ENOTEMPTY)) {
2270 r = rm_rf_child(dfd, bn, REMOVE_PHYSICAL);
2271 if (r < 0)
2272 return log_error_errno(r, "rm -rf %s failed: %m", i->path);
2273
2274 mac_selinux_create_file_prepare(i->path, file_type);
2275 r = RET_NERRNO(mknodat(dfd, bn, i->mode | file_type, i->major_minor));
2276 mac_selinux_create_file_clear();
2277 }
2278 if (r < 0)
2279 return log_error_errno(r, "Failed to create device node '%s': %m", i->path);
2280
2281 fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
2282 if (fd < 0)
2283 return log_error_errno(errno, "Failed to open device node we just created '%s': %m", i->path);
2284
2285 /* Validate type before change ownership below */
2286 if (fstat(fd, &st) < 0)
2287 return log_error_errno(errno, "Failed to fstat(%s): %m", i->path);
2288
2289 if (((st.st_mode ^ file_type) & S_IFMT) != 0)
2290 return log_error_errno(SYNTHETIC_ERRNO(EBADF),
2291 "Device node we just created is not a device node, refusing.");
2292
2293 creation = CREATION_FORCE;
2294 } else {
2295 log_warning("\"%s\" already exists and is not a device node.", i->path);
2296 return 0;
2297 }
2298 }
2299
2300 log_debug("%s %s device node \"%s\" %u:%u.",
2301 creation_mode_verb_to_string(creation),
2302 i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
2303 i->path, major(i->mode), minor(i->mode));
2304
2305 return fd_set_perms(c, i, fd, i->path, &st, creation);
2306
2307 handle_privilege:
2308 log_debug_errno(r,
2309 "We lack permissions, possibly because of cgroup configuration; "
2310 "skipping creation of device node '%s'.", i->path);
2311 return 0;
2312 }
2313
2314 static int create_fifo(Context *c, Item *i) {
2315 _cleanup_close_ int pfd = -EBADF, fd = -EBADF;
2316 _cleanup_free_ char *bn = NULL;
2317 CreationMode creation;
2318 struct stat st;
2319 int r;
2320
2321 assert(c);
2322 assert(i);
2323 assert(i->type == CREATE_FIFO);
2324
2325 r = path_extract_filename(i->path, &bn);
2326 if (r < 0)
2327 return log_error_errno(r, "Failed to extract filename from path '%s': %m", i->path);
2328 if (r == O_DIRECTORY)
2329 return log_error_errno(SYNTHETIC_ERRNO(EISDIR),
2330 "Cannot open path '%s' for creating FIFO, is a directory.", i->path);
2331
2332 if (arg_dry_run) {
2333 log_info("Would create fifo %s", i->path);
2334 return 0;
2335 }
2336
2337 pfd = path_open_parent_safe(i->path, i->allow_failure);
2338 if (pfd < 0)
2339 return pfd;
2340
2341 WITH_UMASK(0000) {
2342 mac_selinux_create_file_prepare(i->path, S_IFIFO);
2343 r = RET_NERRNO(mkfifoat(pfd, bn, i->mode));
2344 mac_selinux_create_file_clear();
2345 }
2346
2347 creation = r >= 0 ? CREATION_NORMAL : CREATION_EXISTING;
2348
2349 /* Open the inode via O_PATH, regardless if we managed to create it or not. Maybe it is already the FIFO we want */
2350 fd = openat(pfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
2351 if (fd < 0) {
2352 if (r < 0)
2353 return log_error_errno(r, "Failed to create FIFO %s: %m", i->path); /* original error! */
2354
2355 return log_error_errno(errno, "Failed to open FIFO we just created %s: %m", i->path);
2356 }
2357
2358 if (fstat(fd, &st) < 0)
2359 return log_error_errno(errno, "Failed to fstat(%s): %m", i->path);
2360
2361 if (!S_ISFIFO(st.st_mode)) {
2362
2363 if (i->append_or_force) {
2364 fd = safe_close(fd);
2365
2366 WITH_UMASK(0000) {
2367 mac_selinux_create_file_prepare(i->path, S_IFIFO);
2368 r = mkfifoat_atomic(pfd, bn, i->mode);
2369 mac_selinux_create_file_clear();
2370 }
2371 if (IN_SET(r, -EISDIR, -EEXIST, -ENOTEMPTY)) {
2372 r = rm_rf_child(pfd, bn, REMOVE_PHYSICAL);
2373 if (r < 0)
2374 return log_error_errno(r, "rm -rf %s failed: %m", i->path);
2375
2376 mac_selinux_create_file_prepare(i->path, S_IFIFO);
2377 r = RET_NERRNO(mkfifoat(pfd, bn, i->mode));
2378 mac_selinux_create_file_clear();
2379 }
2380 if (r < 0)
2381 return log_error_errno(r, "Failed to create FIFO %s: %m", i->path);
2382
2383 fd = openat(pfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
2384 if (fd < 0)
2385 return log_error_errno(errno, "Failed to open FIFO we just created '%s': %m", i->path);
2386
2387 /* Validate type before change ownership below */
2388 if (fstat(fd, &st) < 0)
2389 return log_error_errno(errno, "Failed to fstat(%s): %m", i->path);
2390
2391 if (!S_ISFIFO(st.st_mode))
2392 return log_error_errno(SYNTHETIC_ERRNO(EBADF),
2393 "FIFO inode we just created is not a FIFO, refusing.");
2394
2395 creation = CREATION_FORCE;
2396 } else {
2397 log_warning("\"%s\" already exists and is not a FIFO.", i->path);
2398 return 0;
2399 }
2400 }
2401
2402 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation), i->path);
2403
2404 return fd_set_perms(c, i, fd, i->path, &st, creation);
2405 }
2406
2407 static int create_symlink(Context *c, Item *i) {
2408 _cleanup_close_ int pfd = -EBADF, fd = -EBADF;
2409 _cleanup_free_ char *bn = NULL;
2410 CreationMode creation;
2411 struct stat st;
2412 bool good = false;
2413 int r;
2414
2415 assert(c);
2416 assert(i);
2417
2418 r = path_extract_filename(i->path, &bn);
2419 if (r < 0)
2420 return log_error_errno(r, "Failed to extract filename from path '%s': %m", i->path);
2421 if (r == O_DIRECTORY)
2422 return log_error_errno(SYNTHETIC_ERRNO(EISDIR),
2423 "Cannot open path '%s' for creating FIFO, is a directory.", i->path);
2424
2425 if (arg_dry_run) {
2426 log_info("Would create symlink %s -> %s", i->path, i->argument);
2427 return 0;
2428 }
2429
2430 pfd = path_open_parent_safe(i->path, i->allow_failure);
2431 if (pfd < 0)
2432 return pfd;
2433
2434 mac_selinux_create_file_prepare(i->path, S_IFLNK);
2435 r = RET_NERRNO(symlinkat(i->argument, pfd, bn));
2436 mac_selinux_create_file_clear();
2437
2438 creation = r >= 0 ? CREATION_NORMAL : CREATION_EXISTING;
2439
2440 fd = openat(pfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
2441 if (fd < 0) {
2442 if (r < 0)
2443 return log_error_errno(r, "Failed to create symlink '%s': %m", i->path); /* original error! */
2444
2445 return log_error_errno(errno, "Failed to open symlink we just created '%s': %m", i->path);
2446 }
2447
2448 if (fstat(fd, &st) < 0)
2449 return log_error_errno(errno, "Failed to fstat(%s): %m", i->path);
2450
2451 if (S_ISLNK(st.st_mode)) {
2452 _cleanup_free_ char *x = NULL;
2453
2454 r = readlinkat_malloc(fd, "", &x);
2455 if (r < 0)
2456 return log_error_errno(r, "readlinkat(%s) failed: %m", i->path);
2457
2458 good = streq(x, i->argument);
2459 } else
2460 good = false;
2461
2462 if (!good) {
2463 if (!i->append_or_force) {
2464 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i->path);
2465 return 0;
2466 }
2467
2468 fd = safe_close(fd);
2469
2470 mac_selinux_create_file_prepare(i->path, S_IFLNK);
2471 r = symlinkat_atomic_full(i->argument, pfd, bn, /* make_relative= */ false);
2472 mac_selinux_create_file_clear();
2473 if (IN_SET(r, -EISDIR, -EEXIST, -ENOTEMPTY)) {
2474 r = rm_rf_child(pfd, bn, REMOVE_PHYSICAL);
2475 if (r < 0)
2476 return log_error_errno(r, "rm -rf %s failed: %m", i->path);
2477
2478 mac_selinux_create_file_prepare(i->path, S_IFLNK);
2479 r = RET_NERRNO(symlinkat(i->argument, pfd, i->path));
2480 mac_selinux_create_file_clear();
2481 }
2482 if (r < 0)
2483 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
2484
2485 fd = openat(pfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
2486 if (fd < 0)
2487 return log_error_errno(errno, "Failed to open symlink we just created '%s': %m", i->path);
2488
2489 /* Validate type before change ownership below */
2490 if (fstat(fd, &st) < 0)
2491 return log_error_errno(errno, "Failed to fstat(%s): %m", i->path);
2492
2493 if (!S_ISLNK(st.st_mode))
2494 return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Symlink we just created is not a symlink, refusing.");
2495
2496 creation = CREATION_FORCE;
2497 }
2498
2499 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation), i->path);
2500 return fd_set_perms(c, i, fd, i->path, &st, creation);
2501 }
2502
2503 typedef int (*action_t)(Context *c, Item *i, const char *path, CreationMode creation);
2504 typedef int (*fdaction_t)(Context *c, Item *i, int fd, const char *path, const struct stat *st, CreationMode creation);
2505
2506 static int item_do(
2507 Context *c,
2508 Item *i,
2509 int fd,
2510 const char *path,
2511 CreationMode creation,
2512 fdaction_t action) {
2513
2514 struct stat st;
2515 int r = 0, q;
2516
2517 assert(c);
2518 assert(i);
2519 assert(path);
2520 assert(fd >= 0);
2521
2522 if (fstat(fd, &st) < 0) {
2523 r = log_error_errno(errno, "fstat() on file failed: %m");
2524 goto finish;
2525 }
2526
2527 /* This returns the first error we run into, but nevertheless tries to go on */
2528 r = action(c, i, fd, path, &st, creation);
2529
2530 if (S_ISDIR(st.st_mode)) {
2531 _cleanup_closedir_ DIR *d = NULL;
2532
2533 /* The passed 'fd' was opened with O_PATH. We need to convert it into a 'regular' fd before
2534 * reading the directory content. */
2535 d = opendir(FORMAT_PROC_FD_PATH(fd));
2536 if (!d) {
2537 log_error_errno(errno, "Failed to opendir() '%s': %m", FORMAT_PROC_FD_PATH(fd));
2538 if (r == 0)
2539 r = -errno;
2540 goto finish;
2541 }
2542
2543 FOREACH_DIRENT_ALL(de, d, q = -errno; goto finish) {
2544 int de_fd;
2545
2546 if (dot_or_dot_dot(de->d_name))
2547 continue;
2548
2549 de_fd = openat(fd, de->d_name, O_NOFOLLOW|O_CLOEXEC|O_PATH);
2550 if (de_fd < 0)
2551 q = log_error_errno(errno, "Failed to open() file '%s': %m", de->d_name);
2552 else {
2553 _cleanup_free_ char *de_path = NULL;
2554
2555 de_path = path_join(path, de->d_name);
2556 if (!de_path)
2557 q = log_oom();
2558 else
2559 /* Pass ownership of dirent fd over */
2560 q = item_do(c, i, de_fd, de_path, CREATION_EXISTING, action);
2561 }
2562
2563 if (q < 0 && r == 0)
2564 r = q;
2565 }
2566 }
2567 finish:
2568 safe_close(fd);
2569 return r;
2570 }
2571
2572 static int glob_item(Context *c, Item *i, action_t action) {
2573 _cleanup_globfree_ glob_t g = {
2574 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
2575 };
2576 int r = 0, k;
2577
2578 assert(c);
2579 assert(i);
2580
2581 k = safe_glob(i->path, GLOB_NOSORT|GLOB_BRACE, &g);
2582 if (k < 0 && k != -ENOENT)
2583 return log_error_errno(k, "glob(%s) failed: %m", i->path);
2584
2585 STRV_FOREACH(fn, g.gl_pathv) {
2586 /* We pass CREATION_EXISTING here, since if we are globbing for it, it always has to exist */
2587 k = action(c, i, *fn, CREATION_EXISTING);
2588 if (k < 0 && r == 0)
2589 r = k;
2590 }
2591
2592 return r;
2593 }
2594
2595 static int glob_item_recursively(
2596 Context *c,
2597 Item *i,
2598 fdaction_t action) {
2599
2600 _cleanup_globfree_ glob_t g = {
2601 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
2602 };
2603 int r = 0, k;
2604
2605 k = safe_glob(i->path, GLOB_NOSORT|GLOB_BRACE, &g);
2606 if (k < 0 && k != -ENOENT)
2607 return log_error_errno(k, "glob(%s) failed: %m", i->path);
2608
2609 STRV_FOREACH(fn, g.gl_pathv) {
2610 _cleanup_close_ int fd = -EBADF;
2611
2612 /* Make sure we won't trigger/follow file object (such as
2613 * device nodes, automounts, ...) pointed out by 'fn' with
2614 * O_PATH. Note, when O_PATH is used, flags other than
2615 * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored. */
2616
2617 fd = open(*fn, O_CLOEXEC|O_NOFOLLOW|O_PATH);
2618 if (fd < 0) {
2619 log_error_errno(errno, "Opening '%s' failed: %m", *fn);
2620 if (r == 0)
2621 r = -errno;
2622 continue;
2623 }
2624
2625 k = item_do(c, i, fd, *fn, CREATION_EXISTING, action);
2626 if (k < 0 && r == 0)
2627 r = k;
2628
2629 /* we passed fd ownership to the previous call */
2630 fd = -EBADF;
2631 }
2632
2633 return r;
2634 }
2635
2636 static int rm_if_wrong_type_safe(
2637 mode_t mode,
2638 int parent_fd,
2639 const struct stat *parent_st, /* Only used if follow_links below is true. */
2640 const char *name,
2641 int flags) {
2642 _cleanup_free_ char *parent_name = NULL;
2643 bool follow_links = !FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW);
2644 struct stat st;
2645 int r;
2646
2647 assert(name);
2648 assert((mode & ~S_IFMT) == 0);
2649 assert(!follow_links || parent_st);
2650 assert((flags & ~AT_SYMLINK_NOFOLLOW) == 0);
2651
2652 if (mode == 0)
2653 return 0;
2654
2655 if (!filename_is_valid(name))
2656 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "\"%s\" is not a valid filename.", name);
2657
2658 r = fstatat_harder(parent_fd, name, &st, flags, REMOVE_CHMOD | REMOVE_CHMOD_RESTORE);
2659 if (r < 0) {
2660 (void) fd_get_path(parent_fd, &parent_name);
2661 return log_full_errno(r == -ENOENT? LOG_DEBUG : LOG_ERR, r,
2662 "Failed to stat \"%s/%s\": %m", parent_name ?: "...", name);
2663 }
2664
2665 /* Fail before removing anything if this is an unsafe transition. */
2666 if (follow_links && unsafe_transition(parent_st, &st)) {
2667 (void) fd_get_path(parent_fd, &parent_name);
2668 return log_error_errno(SYNTHETIC_ERRNO(ENOLINK),
2669 "Unsafe transition from \"%s\" to \"%s\".", parent_name ?: "...", name);
2670 }
2671
2672 if ((st.st_mode & S_IFMT) == mode)
2673 return 0;
2674
2675 (void) fd_get_path(parent_fd, &parent_name);
2676 log_notice("Wrong file type 0o%o; rm -rf \"%s/%s\"", st.st_mode & S_IFMT, parent_name ?: "...", name);
2677
2678 /* If the target of the symlink was the wrong type, the link needs to be removed instead of the
2679 * target, so make sure it is identified as a link and not a directory. */
2680 if (follow_links) {
2681 r = fstatat_harder(parent_fd, name, &st, AT_SYMLINK_NOFOLLOW, REMOVE_CHMOD | REMOVE_CHMOD_RESTORE);
2682 if (r < 0)
2683 return log_error_errno(r, "Failed to stat \"%s/%s\": %m", parent_name ?: "...", name);
2684 }
2685
2686 /* Do not remove mount points. */
2687 r = fd_is_mount_point(parent_fd, name, follow_links ? AT_SYMLINK_FOLLOW : 0);
2688 if (r < 0)
2689 (void) log_warning_errno(r, "Failed to check if \"%s/%s\" is a mount point: %m; continuing.",
2690 parent_name ?: "...", name);
2691 else if (r > 0)
2692 return log_error_errno(SYNTHETIC_ERRNO(EBUSY),
2693 "Not removing \"%s/%s\" because it is a mount point.", parent_name ?: "...", name);
2694
2695 log_action("Would remove", "Removing", "%s %s/%s", parent_name ?: "...", name);
2696 if (!arg_dry_run) {
2697 if ((st.st_mode & S_IFMT) == S_IFDIR) {
2698 _cleanup_close_ int child_fd = -EBADF;
2699
2700 child_fd = openat(parent_fd, name, O_NOCTTY | O_CLOEXEC | O_DIRECTORY);
2701 if (child_fd < 0)
2702 return log_error_errno(errno, "Failed to open \"%s/%s\": %m", parent_name ?: "...", name);
2703
2704 r = rm_rf_children(TAKE_FD(child_fd), REMOVE_ROOT|REMOVE_SUBVOLUME|REMOVE_PHYSICAL, &st);
2705 if (r < 0)
2706 return log_error_errno(r, "Failed to remove contents of \"%s/%s\": %m", parent_name ?: "...", name);
2707
2708 r = unlinkat_harder(parent_fd, name, AT_REMOVEDIR, REMOVE_CHMOD | REMOVE_CHMOD_RESTORE);
2709 } else
2710 r = unlinkat_harder(parent_fd, name, 0, REMOVE_CHMOD | REMOVE_CHMOD_RESTORE);
2711 if (r < 0)
2712 return log_error_errno(r, "Failed to remove \"%s/%s\": %m", parent_name ?: "...", name);
2713 }
2714
2715 /* This is covered by the log_notice "Wrong file type...".
2716 * It is logged earlier because it gives context to other error messages that might follow. */
2717 return -ENOENT;
2718 }
2719
2720 /* If child_mode is non-zero, rm_if_wrong_type_safe will be executed for the last path component. */
2721 static int mkdir_parents_rm_if_wrong_type(mode_t child_mode, const char *path) {
2722 _cleanup_close_ int parent_fd = -EBADF;
2723 struct stat parent_st;
2724 size_t path_len;
2725 int r;
2726
2727 assert(path);
2728 assert((child_mode & ~S_IFMT) == 0);
2729
2730 path_len = strlen(path);
2731
2732 if (!is_path(path))
2733 /* rm_if_wrong_type_safe already logs errors. */
2734 return rm_if_wrong_type_safe(child_mode, AT_FDCWD, NULL, path, AT_SYMLINK_NOFOLLOW);
2735
2736 if (child_mode != 0 && endswith(path, "/"))
2737 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2738 "Trailing path separators are only allowed if child_mode is not set; got \"%s\"", path);
2739
2740 /* Get the parent_fd and stat. */
2741 parent_fd = openat(AT_FDCWD, path_is_absolute(path) ? "/" : ".", O_NOCTTY | O_CLOEXEC | O_DIRECTORY);
2742 if (parent_fd < 0)
2743 return log_error_errno(errno, "Failed to open root: %m");
2744
2745 if (fstat(parent_fd, &parent_st) < 0)
2746 return log_error_errno(errno, "Failed to stat root: %m");
2747
2748 /* Check every parent directory in the path, except the last component */
2749 for (const char *e = path;;) {
2750 _cleanup_close_ int next_fd = -EBADF;
2751 char t[path_len + 1];
2752 const char *s;
2753
2754 /* Find the start of the next path component. */
2755 s = e + strspn(e, "/");
2756 /* Find the end of the next path component. */
2757 e = s + strcspn(s, "/");
2758
2759 /* Copy the path component to t so it can be a null terminated string. */
2760 *((char*) mempcpy(t, s, e - s)) = 0;
2761
2762 /* Is this the last component? If so, then check the type */
2763 if (*e == 0)
2764 return rm_if_wrong_type_safe(child_mode, parent_fd, &parent_st, t, AT_SYMLINK_NOFOLLOW);
2765
2766 r = rm_if_wrong_type_safe(S_IFDIR, parent_fd, &parent_st, t, 0);
2767 /* Remove dangling symlinks. */
2768 if (r == -ENOENT)
2769 r = rm_if_wrong_type_safe(S_IFDIR, parent_fd, &parent_st, t, AT_SYMLINK_NOFOLLOW);
2770 if (r == -ENOENT) {
2771 if (!arg_dry_run) {
2772 WITH_UMASK(0000)
2773 r = mkdirat_label(parent_fd, t, 0755);
2774 if (r < 0) {
2775 _cleanup_free_ char *parent_name = NULL;
2776
2777 (void) fd_get_path(parent_fd, &parent_name);
2778 return log_error_errno(r, "Failed to mkdir \"%s\" at \"%s\": %m", t, strnull(parent_name));
2779 }
2780 }
2781 } else if (r < 0)
2782 /* rm_if_wrong_type_safe already logs errors. */
2783 return r;
2784
2785 next_fd = RET_NERRNO(openat(parent_fd, t, O_NOCTTY | O_CLOEXEC | O_DIRECTORY));
2786 if (next_fd < 0) {
2787 _cleanup_free_ char *parent_name = NULL;
2788
2789 (void) fd_get_path(parent_fd, &parent_name);
2790 return log_error_errno(next_fd, "Failed to open \"%s\" at \"%s\": %m", t, strnull(parent_name));
2791 }
2792 r = RET_NERRNO(fstat(next_fd, &parent_st));
2793 if (r < 0) {
2794 _cleanup_free_ char *parent_name = NULL;
2795
2796 (void) fd_get_path(parent_fd, &parent_name);
2797 return log_error_errno(r, "Failed to stat \"%s\" at \"%s\": %m", t, strnull(parent_name));
2798 }
2799
2800 close_and_replace(parent_fd, next_fd);
2801 }
2802 }
2803
2804 static int mkdir_parents_item(Item *i, mode_t child_mode) {
2805 int r;
2806
2807 if (i->try_replace) {
2808 r = mkdir_parents_rm_if_wrong_type(child_mode, i->path);
2809 if (r < 0 && r != -ENOENT)
2810 return r;
2811 } else
2812 WITH_UMASK(0000)
2813 if (!arg_dry_run)
2814 (void) mkdir_parents_label(i->path, 0755);
2815
2816 return 0;
2817 }
2818
2819 static int create_item(Context *c, Item *i) {
2820 int r;
2821
2822 assert(c);
2823 assert(i);
2824
2825 log_debug("Running create action for entry %c %s", (char) i->type, i->path);
2826
2827 switch (i->type) {
2828
2829 case IGNORE_PATH:
2830 case IGNORE_DIRECTORY_PATH:
2831 case REMOVE_PATH:
2832 case RECURSIVE_REMOVE_PATH:
2833 return 0;
2834
2835 case TRUNCATE_FILE:
2836 case CREATE_FILE:
2837 r = mkdir_parents_item(i, S_IFREG);
2838 if (r < 0)
2839 return r;
2840
2841 if ((i->type == CREATE_FILE && i->append_or_force) || i->type == TRUNCATE_FILE)
2842 r = truncate_file(c, i, i->path);
2843 else
2844 r = create_file(c, i, i->path);
2845 if (r < 0)
2846 return r;
2847 break;
2848
2849 case COPY_FILES:
2850 r = mkdir_parents_item(i, 0);
2851 if (r < 0)
2852 return r;
2853
2854 r = copy_files(c, i);
2855 if (r < 0)
2856 return r;
2857 break;
2858
2859 case WRITE_FILE:
2860 r = glob_item(c, i, write_one_file);
2861 if (r < 0)
2862 return r;
2863
2864 break;
2865
2866 case CREATE_DIRECTORY:
2867 case TRUNCATE_DIRECTORY:
2868 r = mkdir_parents_item(i, S_IFDIR);
2869 if (r < 0)
2870 return r;
2871
2872 r = create_directory(c, i, i->path);
2873 if (r < 0)
2874 return r;
2875 break;
2876
2877 case CREATE_SUBVOLUME:
2878 case CREATE_SUBVOLUME_INHERIT_QUOTA:
2879 case CREATE_SUBVOLUME_NEW_QUOTA:
2880 r = mkdir_parents_item(i, S_IFDIR);
2881 if (r < 0)
2882 return r;
2883
2884 r = create_subvolume(c, i, i->path);
2885 if (r < 0)
2886 return r;
2887 break;
2888
2889 case EMPTY_DIRECTORY:
2890 r = glob_item(c, i, empty_directory);
2891 if (r < 0)
2892 return r;
2893 break;
2894
2895 case CREATE_FIFO:
2896 r = mkdir_parents_item(i, S_IFIFO);
2897 if (r < 0)
2898 return r;
2899
2900 r = create_fifo(c, i);
2901 if (r < 0)
2902 return r;
2903 break;
2904
2905 case CREATE_SYMLINK:
2906 r = mkdir_parents_item(i, S_IFLNK);
2907 if (r < 0)
2908 return r;
2909
2910 r = create_symlink(c, i);
2911 if (r < 0)
2912 return r;
2913
2914 break;
2915
2916 case CREATE_BLOCK_DEVICE:
2917 case CREATE_CHAR_DEVICE:
2918 if (have_effective_cap(CAP_MKNOD) <= 0) {
2919 /* In a container we lack CAP_MKNOD. We shouldn't attempt to create the device node in that
2920 * case to avoid noise, and we don't support virtualized devices in containers anyway. */
2921
2922 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
2923 return 0;
2924 }
2925
2926 r = mkdir_parents_item(i, i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
2927 if (r < 0)
2928 return r;
2929
2930 r = create_device(c, i, i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
2931 if (r < 0)
2932 return r;
2933
2934 break;
2935
2936 case ADJUST_MODE:
2937 case RELABEL_PATH:
2938 r = glob_item(c, i, path_set_perms);
2939 if (r < 0)
2940 return r;
2941 break;
2942
2943 case RECURSIVE_RELABEL_PATH:
2944 r = glob_item_recursively(c, i, fd_set_perms);
2945 if (r < 0)
2946 return r;
2947 break;
2948
2949 case SET_XATTR:
2950 r = glob_item(c, i, path_set_xattrs);
2951 if (r < 0)
2952 return r;
2953 break;
2954
2955 case RECURSIVE_SET_XATTR:
2956 r = glob_item_recursively(c, i, fd_set_xattrs);
2957 if (r < 0)
2958 return r;
2959 break;
2960
2961 case SET_ACL:
2962 r = glob_item(c, i, path_set_acls);
2963 if (r < 0)
2964 return r;
2965 break;
2966
2967 case RECURSIVE_SET_ACL:
2968 r = glob_item_recursively(c, i, fd_set_acls);
2969 if (r < 0)
2970 return r;
2971 break;
2972
2973 case SET_ATTRIBUTE:
2974 r = glob_item(c, i, path_set_attribute);
2975 if (r < 0)
2976 return r;
2977 break;
2978
2979 case RECURSIVE_SET_ATTRIBUTE:
2980 r = glob_item_recursively(c, i, fd_set_attribute);
2981 if (r < 0)
2982 return r;
2983 break;
2984 }
2985
2986 return 0;
2987 }
2988
2989 static int remove_recursive(
2990 Context *c,
2991 Item *i,
2992 const char *instance,
2993 bool remove_instance) {
2994
2995 _cleanup_closedir_ DIR *d = NULL;
2996 STRUCT_STATX_DEFINE(sx);
2997 bool mountpoint;
2998 int r;
2999
3000 r = opendir_and_stat(instance, &d, &sx, &mountpoint);
3001 if (r < 0)
3002 return r;
3003 if (r == 0) {
3004 if (remove_instance) {
3005 log_action("Would remove", "Removing", "%s file \"%s\".", instance);
3006 if (!arg_dry_run &&
3007 remove(instance) < 0 &&
3008 errno != ENOENT)
3009 return log_error_errno(errno, "rm %s: %m", instance);
3010 }
3011 return 0;
3012 }
3013
3014 r = dir_cleanup(c, i, instance, d,
3015 /* self_atime_nsec= */ NSEC_INFINITY,
3016 /* self_mtime_nsec= */ NSEC_INFINITY,
3017 /* cutoff_nsec= */ NSEC_INFINITY,
3018 sx.stx_dev_major, sx.stx_dev_minor,
3019 mountpoint,
3020 MAX_DEPTH,
3021 /* keep_this_level= */ false,
3022 /* age_by_file= */ 0,
3023 /* age_by_dir= */ 0);
3024 if (r < 0)
3025 return r;
3026
3027 if (remove_instance) {
3028 log_debug("Removing directory \"%s\".", instance);
3029 r = RET_NERRNO(rmdir(instance));
3030 if (r < 0 && !IN_SET(r, -ENOENT, -ENOTEMPTY))
3031 return log_error_errno(r, "Failed to remove %s: %m", instance);
3032 }
3033 return 0;
3034 }
3035
3036 static int purge_item_instance(Context *c, Item *i, const char *instance, CreationMode creation) {
3037 return remove_recursive(c, i, instance, /* remove_instance= */ true);
3038 }
3039
3040 static int purge_item(Context *c, Item *i) {
3041 assert(i);
3042
3043 if (!needs_purge(i->type))
3044 return 0;
3045
3046 log_debug("Running purge action for entry %c %s", (char) i->type, i->path);
3047
3048 if (needs_glob(i->type))
3049 return glob_item(c, i, purge_item_instance);
3050
3051 return purge_item_instance(c, i, i->path, CREATION_EXISTING);
3052 }
3053
3054 static int remove_item_instance(
3055 Context *c,
3056 Item *i,
3057 const char *instance,
3058 CreationMode creation) {
3059
3060 assert(c);
3061 assert(i);
3062
3063 switch (i->type) {
3064
3065 case REMOVE_PATH:
3066 log_action("Would remove", "Removing", "%s \"%s\".", instance);
3067 if (!arg_dry_run &&
3068 remove(instance) < 0 &&
3069 errno != ENOENT)
3070 return log_error_errno(errno, "rm %s: %m", instance);
3071
3072 return 0;
3073
3074 case RECURSIVE_REMOVE_PATH:
3075 return remove_recursive(c, i, instance, /* remove_instance= */ true);
3076
3077 default:
3078 assert_not_reached();
3079 }
3080 }
3081
3082 static int remove_item(Context *c, Item *i) {
3083 assert(c);
3084 assert(i);
3085
3086 log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
3087
3088 switch (i->type) {
3089
3090 case TRUNCATE_DIRECTORY:
3091 return remove_recursive(c, i, i->path, /* remove_instance= */ false);
3092
3093 case REMOVE_PATH:
3094 case RECURSIVE_REMOVE_PATH:
3095 return glob_item(c, i, remove_item_instance);
3096
3097 default:
3098 return 0;
3099 }
3100 }
3101
3102 static char *age_by_to_string(AgeBy ab, bool is_dir) {
3103 static const char ab_map[] = { 'a', 'b', 'c', 'm' };
3104 size_t j = 0;
3105 char *ret;
3106
3107 ret = new(char, ELEMENTSOF(ab_map) + 1);
3108 if (!ret)
3109 return NULL;
3110
3111 for (size_t i = 0; i < ELEMENTSOF(ab_map); i++)
3112 if (FLAGS_SET(ab, 1U << i))
3113 ret[j++] = is_dir ? ascii_toupper(ab_map[i]) : ab_map[i];
3114
3115 ret[j] = 0;
3116 return ret;
3117 }
3118
3119 static int clean_item_instance(
3120 Context *c,
3121 Item *i,
3122 const char* instance,
3123 CreationMode creation) {
3124
3125 assert(i);
3126
3127 if (!i->age_set)
3128 return 0;
3129
3130 usec_t n = now(CLOCK_REALTIME);
3131 if (n < i->age)
3132 return 0;
3133
3134 usec_t cutoff = n - i->age;
3135
3136 _cleanup_closedir_ DIR *d = NULL;
3137 STRUCT_STATX_DEFINE(sx);
3138 bool mountpoint;
3139 int r;
3140
3141 r = opendir_and_stat(instance, &d, &sx, &mountpoint);
3142 if (r <= 0)
3143 return r;
3144
3145 if (DEBUG_LOGGING) {
3146 _cleanup_free_ char *ab_f = NULL, *ab_d = NULL;
3147
3148 ab_f = age_by_to_string(i->age_by_file, false);
3149 if (!ab_f)
3150 return log_oom();
3151
3152 ab_d = age_by_to_string(i->age_by_dir, true);
3153 if (!ab_d)
3154 return log_oom();
3155
3156 log_debug("Cleanup threshold for %s \"%s\" is %s; age-by: %s%s",
3157 mountpoint ? "mount point" : "directory",
3158 instance,
3159 FORMAT_TIMESTAMP_STYLE(cutoff, TIMESTAMP_US),
3160 ab_f, ab_d);
3161 }
3162
3163 return dir_cleanup(c, i, instance, d,
3164 statx_timestamp_load_nsec(&sx.stx_atime),
3165 statx_timestamp_load_nsec(&sx.stx_mtime),
3166 cutoff * NSEC_PER_USEC,
3167 sx.stx_dev_major, sx.stx_dev_minor,
3168 mountpoint,
3169 MAX_DEPTH, i->keep_first_level,
3170 i->age_by_file, i->age_by_dir);
3171 }
3172
3173 static int clean_item(Context *c, Item *i) {
3174 assert(c);
3175 assert(i);
3176
3177 log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
3178
3179 switch (i->type) {
3180
3181 case CREATE_DIRECTORY:
3182 case TRUNCATE_DIRECTORY:
3183 case CREATE_SUBVOLUME:
3184 case CREATE_SUBVOLUME_INHERIT_QUOTA:
3185 case CREATE_SUBVOLUME_NEW_QUOTA:
3186 case COPY_FILES:
3187 clean_item_instance(c, i, i->path, CREATION_EXISTING);
3188 return 0;
3189
3190 case EMPTY_DIRECTORY:
3191 case IGNORE_PATH:
3192 case IGNORE_DIRECTORY_PATH:
3193 return glob_item(c, i, clean_item_instance);
3194
3195 default:
3196 return 0;
3197 }
3198 }
3199
3200 static int process_item(
3201 Context *c,
3202 Item *i,
3203 OperationMask operation) {
3204
3205 OperationMask todo;
3206 _cleanup_free_ char *_path = NULL;
3207 const char *path;
3208 int r;
3209
3210 assert(c);
3211 assert(i);
3212
3213 todo = operation & ~i->done;
3214 if (todo == 0) /* Everything already done? */
3215 return 0;
3216
3217 i->done |= operation;
3218
3219 path = i->path;
3220 if (string_is_glob(path)) {
3221 /* We can't easily check whether a glob matches any autofs path, so let's do the check only
3222 * for the non-glob part. */
3223
3224 r = glob_non_glob_prefix(path, &_path);
3225 if (r < 0 && r != -ENOENT)
3226 return log_debug_errno(r, "Failed to deglob path: %m");
3227 if (r >= 0)
3228 path = _path;
3229 }
3230
3231 r = chase(path, arg_root, CHASE_NO_AUTOFS|CHASE_NONEXISTENT|CHASE_WARN, NULL, NULL);
3232 if (r == -EREMOTE) {
3233 log_notice_errno(r, "Skipping %s", i->path); /* We log the configured path, to not confuse the user. */
3234 return 0;
3235 }
3236 if (r < 0)
3237 log_debug_errno(r, "Failed to determine whether '%s' is below autofs, ignoring: %m", i->path);
3238
3239 r = FLAGS_SET(operation, OPERATION_CREATE) ? create_item(c, i) : 0;
3240 /* Failure can only be tolerated for create */
3241 if (i->allow_failure)
3242 r = 0;
3243
3244 RET_GATHER(r, FLAGS_SET(operation, OPERATION_REMOVE) ? remove_item(c, i) : 0);
3245 RET_GATHER(r, FLAGS_SET(operation, OPERATION_CLEAN) ? clean_item(c, i) : 0);
3246 RET_GATHER(r, FLAGS_SET(operation, OPERATION_PURGE) ? purge_item(c, i) : 0);
3247
3248 return r;
3249 }
3250
3251 static int process_item_array(
3252 Context *c,
3253 ItemArray *array,
3254 OperationMask operation) {
3255
3256 int r = 0;
3257
3258 assert(c);
3259 assert(array);
3260
3261 /* Create any parent first. */
3262 if (FLAGS_SET(operation, OPERATION_CREATE) && array->parent)
3263 r = process_item_array(c, array->parent, operation & OPERATION_CREATE);
3264
3265 /* Clean up all children first */
3266 if ((operation & (OPERATION_REMOVE|OPERATION_CLEAN|OPERATION_PURGE)) && !set_isempty(array->children)) {
3267 ItemArray *cc;
3268
3269 SET_FOREACH(cc, array->children)
3270 RET_GATHER(r, process_item_array(c, cc, operation & (OPERATION_REMOVE|OPERATION_CLEAN|OPERATION_PURGE)));
3271 }
3272
3273 FOREACH_ARRAY(item, array->items, array->n_items)
3274 RET_GATHER(r, process_item(c, item, operation));
3275
3276 return r;
3277 }
3278
3279 static void item_free_contents(Item *i) {
3280 assert(i);
3281 free(i->path);
3282 free(i->argument);
3283 free(i->binary_argument);
3284 strv_free(i->xattrs);
3285
3286 #if HAVE_ACL
3287 if (i->acl_access)
3288 acl_free(i->acl_access);
3289
3290 if (i->acl_access_exec)
3291 acl_free(i->acl_access_exec);
3292
3293 if (i->acl_default)
3294 acl_free(i->acl_default);
3295 #endif
3296 }
3297
3298 static ItemArray* item_array_free(ItemArray *a) {
3299 if (!a)
3300 return NULL;
3301
3302 FOREACH_ARRAY(item, a->items, a->n_items)
3303 item_free_contents(item);
3304
3305 set_free(a->children);
3306 free(a->items);
3307 return mfree(a);
3308 }
3309
3310 static int item_compare(const Item *a, const Item *b) {
3311 /* Make sure that the ownership taking item is put first, so
3312 * that we first create the node, and then can adjust it */
3313
3314 if (takes_ownership(a->type) && !takes_ownership(b->type))
3315 return -1;
3316 if (!takes_ownership(a->type) && takes_ownership(b->type))
3317 return 1;
3318
3319 return CMP(a->type, b->type);
3320 }
3321
3322 static bool item_compatible(const Item *a, const Item *b) {
3323 assert(a);
3324 assert(b);
3325 assert(streq(a->path, b->path));
3326
3327 if (takes_ownership(a->type) && takes_ownership(b->type))
3328 /* check if the items are the same */
3329 return memcmp_nn(item_binary_argument(a), item_binary_argument_size(a),
3330 item_binary_argument(b), item_binary_argument_size(b)) == 0 &&
3331
3332 a->uid_set == b->uid_set &&
3333 a->uid == b->uid &&
3334 a->uid_only_create == b->uid_only_create &&
3335
3336 a->gid_set == b->gid_set &&
3337 a->gid == b->gid &&
3338 a->gid_only_create == b->gid_only_create &&
3339
3340 a->mode_set == b->mode_set &&
3341 a->mode == b->mode &&
3342 a->mode_only_create == b->mode_only_create &&
3343
3344 a->age_set == b->age_set &&
3345 a->age == b->age &&
3346
3347 a->age_by_file == b->age_by_file &&
3348 a->age_by_dir == b->age_by_dir &&
3349
3350 a->mask_perms == b->mask_perms &&
3351
3352 a->keep_first_level == b->keep_first_level &&
3353
3354 a->major_minor == b->major_minor;
3355
3356 return true;
3357 }
3358
3359 static bool should_include_path(const char *path) {
3360 STRV_FOREACH(prefix, arg_exclude_prefixes)
3361 if (path_startswith(path, *prefix)) {
3362 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
3363 path, *prefix);
3364 return false;
3365 }
3366
3367 STRV_FOREACH(prefix, arg_include_prefixes)
3368 if (path_startswith(path, *prefix)) {
3369 log_debug("Entry \"%s\" matches include prefix \"%s\".", path, *prefix);
3370 return true;
3371 }
3372
3373 /* no matches, so we should include this path only if we have no allow list at all */
3374 if (strv_isempty(arg_include_prefixes))
3375 return true;
3376
3377 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path);
3378 return false;
3379 }
3380
3381 static int specifier_expansion_from_arg(const Specifier *specifier_table, Item *i) {
3382 int r;
3383
3384 assert(i);
3385
3386 if (!i->argument)
3387 return 0;
3388
3389 switch (i->type) {
3390 case COPY_FILES:
3391 case CREATE_SYMLINK:
3392 case CREATE_FILE:
3393 case TRUNCATE_FILE:
3394 case WRITE_FILE: {
3395 _cleanup_free_ char *unescaped = NULL, *resolved = NULL;
3396 ssize_t l;
3397
3398 l = cunescape(i->argument, 0, &unescaped);
3399 if (l < 0)
3400 return log_error_errno(l, "Failed to unescape parameter to write: %s", i->argument);
3401
3402 r = specifier_printf(unescaped, PATH_MAX-1, specifier_table, arg_root, NULL, &resolved);
3403 if (r < 0)
3404 return r;
3405
3406 return free_and_replace(i->argument, resolved);
3407 }
3408 case SET_XATTR:
3409 case RECURSIVE_SET_XATTR:
3410 STRV_FOREACH(xattr, i->xattrs) {
3411 _cleanup_free_ char *resolved = NULL;
3412
3413 r = specifier_printf(*xattr, SIZE_MAX, specifier_table, arg_root, NULL, &resolved);
3414 if (r < 0)
3415 return r;
3416
3417 free_and_replace(*xattr, resolved);
3418 }
3419 return 0;
3420
3421 default:
3422 return 0;
3423 }
3424 }
3425
3426 static int patch_var_run(const char *fname, unsigned line, char **path) {
3427 const char *k;
3428 char *n;
3429
3430 assert(path);
3431 assert(*path);
3432
3433 /* Optionally rewrites lines referencing /var/run/, to use /run/ instead. Why bother? tmpfiles merges
3434 * lines in some cases and detects conflicts in others. If files/directories are specified through
3435 * two equivalent lines this is problematic as neither case will be detected. Ideally we'd detect
3436 * these cases by resolving symlinks early, but that's precisely not what we can do here as this code
3437 * very likely is running very early on, at a time where the paths in question are not available yet,
3438 * or even more importantly, our own tmpfiles rules might create the paths that are intermediary to
3439 * the listed paths. We can't really cover the generic case, but the least we can do is cover the
3440 * specific case of /var/run vs. /run, as /var/run is a legacy name for /run only, and we explicitly
3441 * document that and require that on systemd systems the former is a symlink to the latter. Moreover
3442 * files below this path are by far the primary use case for tmpfiles.d/. */
3443
3444 k = path_startswith(*path, "/var/run/");
3445 if (isempty(k)) /* Don't complain about paths other than under /var/run,
3446 * and not about /var/run itself either. */
3447 return 0;
3448
3449 n = path_join("/run", k);
3450 if (!n)
3451 return log_oom();
3452
3453 /* Also log about this briefly. We do so at LOG_NOTICE level, as we fixed up the situation
3454 * automatically, hence there's no immediate need for action by the user. However, in the interest of
3455 * making things less confusing to the user, let's still inform the user that these snippets should
3456 * really be updated. */
3457 log_syntax(NULL, LOG_NOTICE, fname, line, 0,
3458 "Line references path below legacy directory /var/run/, updating %s → %s; please update the tmpfiles.d/ drop-in file accordingly.",
3459 *path, n);
3460
3461 free_and_replace(*path, n);
3462
3463 return 0;
3464 }
3465
3466 static int find_uid(const char *user, uid_t *ret_uid, Hashmap **cache) {
3467 int r;
3468
3469 assert(user);
3470 assert(ret_uid);
3471
3472 /* First: parse as numeric UID string */
3473 r = parse_uid(user, ret_uid);
3474 if (r >= 0)
3475 return r;
3476
3477 /* Second: pass to NSS if we are running "online" */
3478 if (!arg_root)
3479 return get_user_creds(&user, ret_uid, NULL, NULL, NULL, 0);
3480
3481 /* Third, synthesize "root" unconditionally */
3482 if (streq(user, "root")) {
3483 *ret_uid = 0;
3484 return 0;
3485 }
3486
3487 /* Fourth: use fgetpwent() to read /etc/passwd directly, if we are "offline" */
3488 return name_to_uid_offline(arg_root, user, ret_uid, cache);
3489 }
3490
3491 static int find_gid(const char *group, gid_t *ret_gid, Hashmap **cache) {
3492 int r;
3493
3494 assert(group);
3495 assert(ret_gid);
3496
3497 /* First: parse as numeric GID string */
3498 r = parse_gid(group, ret_gid);
3499 if (r >= 0)
3500 return r;
3501
3502 /* Second: pass to NSS if we are running "online" */
3503 if (!arg_root)
3504 return get_group_creds(&group, ret_gid, 0);
3505
3506 /* Third, synthesize "root" unconditionally */
3507 if (streq(group, "root")) {
3508 *ret_gid = 0;
3509 return 0;
3510 }
3511
3512 /* Fourth: use fgetgrent() to read /etc/group directly, if we are "offline" */
3513 return name_to_gid_offline(arg_root, group, ret_gid, cache);
3514 }
3515
3516 static int parse_age_by_from_arg(const char *age_by_str, Item *item) {
3517 AgeBy ab_f = 0, ab_d = 0;
3518
3519 static const struct {
3520 char age_by_chr;
3521 AgeBy age_by_flag;
3522 } age_by_types[] = {
3523 { 'a', AGE_BY_ATIME },
3524 { 'b', AGE_BY_BTIME },
3525 { 'c', AGE_BY_CTIME },
3526 { 'm', AGE_BY_MTIME },
3527 };
3528
3529 assert(age_by_str);
3530 assert(item);
3531
3532 if (isempty(age_by_str))
3533 return -EINVAL;
3534
3535 for (const char *s = age_by_str; *s != 0; s++) {
3536 size_t i;
3537
3538 /* Ignore whitespace. */
3539 if (strchr(WHITESPACE, *s))
3540 continue;
3541
3542 for (i = 0; i < ELEMENTSOF(age_by_types); i++) {
3543 /* Check lower-case for files, upper-case for directories. */
3544 if (*s == age_by_types[i].age_by_chr) {
3545 ab_f |= age_by_types[i].age_by_flag;
3546 break;
3547 } else if (*s == ascii_toupper(age_by_types[i].age_by_chr)) {
3548 ab_d |= age_by_types[i].age_by_flag;
3549 break;
3550 }
3551 }
3552
3553 /* Invalid character. */
3554 if (i >= ELEMENTSOF(age_by_types))
3555 return -EINVAL;
3556 }
3557
3558 /* No match. */
3559 if (ab_f == 0 && ab_d == 0)
3560 return -EINVAL;
3561
3562 item->age_by_file = ab_f > 0 ? ab_f : AGE_BY_DEFAULT_FILE;
3563 item->age_by_dir = ab_d > 0 ? ab_d : AGE_BY_DEFAULT_DIR;
3564
3565 return 0;
3566 }
3567
3568 static bool is_duplicated_item(ItemArray *existing, const Item *i) {
3569 assert(existing);
3570 assert(i);
3571
3572 FOREACH_ARRAY(e, existing->items, existing->n_items) {
3573 if (item_compatible(e, i))
3574 continue;
3575
3576 /* Only multiple 'w+' lines for the same path are allowed. */
3577 if (e->type != WRITE_FILE || !e->append_or_force ||
3578 i->type != WRITE_FILE || !i->append_or_force)
3579 return true;
3580 }
3581
3582 return false;
3583 }
3584
3585 static int parse_line(
3586 const char *fname,
3587 unsigned line,
3588 const char *buffer,
3589 bool *invalid_config,
3590 void *context) {
3591
3592 Context *c = ASSERT_PTR(context);
3593 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
3594 _cleanup_(item_free_contents) Item i = {
3595 /* The "age-by" argument considers all file timestamp types by default. */
3596 .age_by_file = AGE_BY_DEFAULT_FILE,
3597 .age_by_dir = AGE_BY_DEFAULT_DIR,
3598 };
3599 ItemArray *existing;
3600 OrderedHashmap *h;
3601 bool append_or_force = false, boot = false, allow_failure = false, try_replace = false,
3602 unbase64 = false, from_cred = false, missing_user_or_group = false;
3603 int r;
3604
3605 assert(fname);
3606 assert(line >= 1);
3607 assert(buffer);
3608
3609 const Specifier specifier_table[] = {
3610 { 'a', specifier_architecture, NULL },
3611 { 'b', specifier_boot_id, NULL },
3612 { 'B', specifier_os_build_id, NULL },
3613 { 'H', specifier_hostname, NULL },
3614 { 'l', specifier_short_hostname, NULL },
3615 { 'm', specifier_machine_id, NULL },
3616 { 'o', specifier_os_id, NULL },
3617 { 'v', specifier_kernel_release, NULL },
3618 { 'w', specifier_os_version_id, NULL },
3619 { 'W', specifier_os_variant_id, NULL },
3620
3621 { 'h', specifier_user_home, NULL },
3622
3623 { 'C', specifier_directory, UINT_TO_PTR(DIRECTORY_CACHE) },
3624 { 'L', specifier_directory, UINT_TO_PTR(DIRECTORY_LOGS) },
3625 { 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) },
3626 { 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) },
3627
3628 COMMON_CREDS_SPECIFIERS(arg_runtime_scope),
3629 COMMON_TMP_SPECIFIERS,
3630 {}
3631 };
3632
3633 r = extract_many_words(
3634 &buffer,
3635 NULL,
3636 EXTRACT_UNQUOTE | EXTRACT_CUNESCAPE,
3637 &action,
3638 &path,
3639 &mode,
3640 &user,
3641 &group,
3642 &age);
3643 if (r < 0) {
3644 if (IN_SET(r, -EINVAL, -EBADSLT))
3645 /* invalid quoting and such or an unknown specifier */
3646 *invalid_config = true;
3647 return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to parse line: %m");
3648 } else if (r < 2) {
3649 *invalid_config = true;
3650 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Syntax error.");
3651 }
3652
3653 if (!empty_or_dash(buffer)) {
3654 i.argument = strdup(buffer);
3655 if (!i.argument)
3656 return log_oom();
3657 }
3658
3659 if (isempty(action)) {
3660 *invalid_config = true;
3661 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3662 "Command too short '%s'.", action);
3663 }
3664
3665 for (int pos = 1; action[pos]; pos++)
3666 if (action[pos] == '!' && !boot)
3667 boot = true;
3668 else if (action[pos] == '+' && !append_or_force)
3669 append_or_force = true;
3670 else if (action[pos] == '-' && !allow_failure)
3671 allow_failure = true;
3672 else if (action[pos] == '=' && !try_replace)
3673 try_replace = true;
3674 else if (action[pos] == '~' && !unbase64)
3675 unbase64 = true;
3676 else if (action[pos] == '^' && !from_cred)
3677 from_cred = true;
3678 else {
3679 *invalid_config = true;
3680 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3681 "Unknown modifiers in command '%s'.", action);
3682 }
3683
3684 if (boot && !arg_boot) {
3685 log_syntax(NULL, LOG_DEBUG, fname, line, 0,
3686 "Ignoring entry %s \"%s\" because --boot is not specified.", action, path);
3687 return 0;
3688 }
3689
3690 i.type = action[0];
3691 i.append_or_force = append_or_force;
3692 i.allow_failure = allow_failure;
3693 i.try_replace = try_replace;
3694
3695 r = specifier_printf(path, PATH_MAX-1, specifier_table, arg_root, NULL, &i.path);
3696 if (ERRNO_IS_NOINFO(r))
3697 return log_unresolvable_specifier(fname, line);
3698 if (r < 0) {
3699 if (IN_SET(r, -EINVAL, -EBADSLT))
3700 *invalid_config = true;
3701 return log_syntax(NULL, LOG_ERR, fname, line, r,
3702 "Failed to replace specifiers in '%s': %m", path);
3703 }
3704
3705 r = patch_var_run(fname, line, &i.path);
3706 if (r < 0)
3707 return r;
3708
3709 if (!path_is_absolute(i.path)) {
3710 *invalid_config = true;
3711 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3712 "Path '%s' not absolute.", i.path);
3713 }
3714
3715 path_simplify(i.path);
3716
3717 switch (i.type) {
3718
3719 case CREATE_DIRECTORY:
3720 case CREATE_SUBVOLUME:
3721 case CREATE_SUBVOLUME_INHERIT_QUOTA:
3722 case CREATE_SUBVOLUME_NEW_QUOTA:
3723 case EMPTY_DIRECTORY:
3724 case TRUNCATE_DIRECTORY:
3725 case CREATE_FIFO:
3726 case IGNORE_PATH:
3727 case IGNORE_DIRECTORY_PATH:
3728 case REMOVE_PATH:
3729 case RECURSIVE_REMOVE_PATH:
3730 case ADJUST_MODE:
3731 case RELABEL_PATH:
3732 case RECURSIVE_RELABEL_PATH:
3733 if (i.argument)
3734 log_syntax(NULL, LOG_WARNING, fname, line, 0,
3735 "%c lines don't take argument fields, ignoring.", (char) i.type);
3736 break;
3737
3738 case CREATE_FILE:
3739 case TRUNCATE_FILE:
3740 break;
3741
3742 case CREATE_SYMLINK:
3743 if (unbase64) {
3744 *invalid_config = true;
3745 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3746 "base64 decoding not supported for symlink targets.");
3747 }
3748 break;
3749
3750 case WRITE_FILE:
3751 if (!i.argument) {
3752 *invalid_config = true;
3753 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3754 "Write file requires argument.");
3755 }
3756 break;
3757
3758 case COPY_FILES:
3759 if (unbase64) {
3760 *invalid_config = true;
3761 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3762 "base64 decoding not supported for copy sources.");
3763 }
3764 break;
3765
3766 case CREATE_CHAR_DEVICE:
3767 case CREATE_BLOCK_DEVICE:
3768 if (unbase64) {
3769 *invalid_config = true;
3770 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3771 "base64 decoding not supported for device node creation.");
3772 }
3773
3774 if (!i.argument) {
3775 *invalid_config = true;
3776 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3777 "Device file requires argument.");
3778 }
3779
3780 r = parse_devnum(i.argument, &i.major_minor);
3781 if (r < 0) {
3782 *invalid_config = true;
3783 return log_syntax(NULL, LOG_ERR, fname, line, r,
3784 "Can't parse device file major/minor '%s'.", i.argument);
3785 }
3786
3787 break;
3788
3789 case SET_XATTR:
3790 case RECURSIVE_SET_XATTR:
3791 if (unbase64) {
3792 *invalid_config = true;
3793 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3794 "base64 decoding not supported for extended attributes.");
3795 }
3796 if (!i.argument) {
3797 *invalid_config = true;
3798 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3799 "Set extended attribute requires argument.");
3800 }
3801 r = parse_xattrs_from_arg(&i);
3802 if (r < 0)
3803 return r;
3804 break;
3805
3806 case SET_ACL:
3807 case RECURSIVE_SET_ACL:
3808 if (unbase64) {
3809 *invalid_config = true;
3810 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3811 "base64 decoding not supported for ACLs.");
3812 }
3813 if (!i.argument) {
3814 *invalid_config = true;
3815 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3816 "Set ACLs requires argument.");
3817 }
3818 r = parse_acls_from_arg(&i);
3819 if (r < 0)
3820 return r;
3821 break;
3822
3823 case SET_ATTRIBUTE:
3824 case RECURSIVE_SET_ATTRIBUTE:
3825 if (unbase64) {
3826 *invalid_config = true;
3827 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3828 "base64 decoding not supported for file attributes.");
3829 }
3830 if (!i.argument) {
3831 *invalid_config = true;
3832 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3833 "Set file attribute requires argument.");
3834 }
3835 r = parse_attribute_from_arg(&i);
3836 if (IN_SET(r, -EINVAL, -EBADSLT))
3837 *invalid_config = true;
3838 if (r < 0)
3839 return r;
3840 break;
3841
3842 default:
3843 *invalid_config = true;
3844 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3845 "Unknown command type '%c'.", (char) i.type);
3846 }
3847
3848 if (!should_include_path(i.path))
3849 return 0;
3850
3851 if (!unbase64) {
3852 /* Do specifier expansion except if base64 mode is enabled */
3853 r = specifier_expansion_from_arg(specifier_table, &i);
3854 if (ERRNO_IS_NOINFO(r))
3855 return log_unresolvable_specifier(fname, line);
3856 if (r < 0) {
3857 if (IN_SET(r, -EINVAL, -EBADSLT))
3858 *invalid_config = true;
3859 return log_syntax(NULL, LOG_ERR, fname, line, r,
3860 "Failed to substitute specifiers in argument: %m");
3861 }
3862 }
3863
3864 switch (i.type) {
3865 case CREATE_SYMLINK:
3866 if (!i.argument) {
3867 i.argument = path_join("/usr/share/factory", i.path);
3868 if (!i.argument)
3869 return log_oom();
3870 }
3871 break;
3872
3873 case COPY_FILES:
3874 if (!i.argument) {
3875 i.argument = path_join("/usr/share/factory", i.path);
3876 if (!i.argument)
3877 return log_oom();
3878 } else if (!path_is_absolute(i.argument)) {
3879 *invalid_config = true;
3880 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
3881 "Source path '%s' is not absolute.", i.argument);
3882
3883 }
3884
3885 if (!empty_or_root(arg_root)) {
3886 char *p;
3887
3888 p = path_join(arg_root, i.argument);
3889 if (!p)
3890 return log_oom();
3891 free_and_replace(i.argument, p);
3892 }
3893
3894 path_simplify(i.argument);
3895
3896 if (laccess(i.argument, F_OK) == -ENOENT) {
3897 /* Silently skip over lines where the source file is missing. */
3898 log_syntax(NULL, LOG_DEBUG, fname, line, 0,
3899 "Copy source path '%s' does not exist, skipping line.", i.argument);
3900 return 0;
3901 }
3902
3903 break;
3904
3905 default:
3906 break;
3907 }
3908
3909 if (from_cred) {
3910 if (!i.argument)
3911 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
3912 "Reading from credential requested, but no credential name specified.");
3913 if (!credential_name_valid(i.argument))
3914 return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
3915 "Credential name not valid: %s", i.argument);
3916
3917 r = read_credential(i.argument, &i.binary_argument, &i.binary_argument_size);
3918 if (IN_SET(r, -ENXIO, -ENOENT)) {
3919 /* Silently skip over lines that have no credentials passed */
3920 log_syntax(NULL, LOG_DEBUG, fname, line, 0,
3921 "Credential '%s' not specified, skipping line.", i.argument);
3922 return 0;
3923 }
3924 if (r < 0)
3925 return log_error_errno(r, "Failed to read credential '%s': %m", i.argument);
3926 }
3927
3928 /* If base64 decoding is requested, do so now */
3929 if (unbase64 && item_binary_argument(&i)) {
3930 _cleanup_free_ void *data = NULL;
3931 size_t data_size = 0;
3932
3933 r = unbase64mem_full(item_binary_argument(&i), item_binary_argument_size(&i), /* secure = */ false,
3934 &data, &data_size);
3935 if (r < 0)
3936 return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to base64 decode specified argument '%s': %m", i.argument);
3937
3938 free_and_replace(i.binary_argument, data);
3939 i.binary_argument_size = data_size;
3940 }
3941
3942 if (!empty_or_root(arg_root)) {
3943 char *p;
3944
3945 p = path_join(arg_root, i.path);
3946 if (!p)
3947 return log_oom();
3948 free_and_replace(i.path, p);
3949 }
3950
3951 if (!empty_or_dash(user)) {
3952 const char *u;
3953
3954 u = startswith(user, ":");
3955 if (u)
3956 i.uid_only_create = true;
3957 else
3958 u = user;
3959
3960 r = find_uid(u, &i.uid, &c->uid_cache);
3961 if (r == -ESRCH && arg_graceful) {
3962 log_syntax(NULL, LOG_DEBUG, fname, line, r,
3963 "%s: user '%s' not found, not adjusting ownership.", i.path, u);
3964 missing_user_or_group = true;
3965 } else if (r < 0) {
3966 *invalid_config = true;
3967 return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve user '%s': %m", u);
3968 } else
3969 i.uid_set = true;
3970 }
3971
3972 if (!empty_or_dash(group)) {
3973 const char *g;
3974
3975 g = startswith(group, ":");
3976 if (g)
3977 i.gid_only_create = true;
3978 else
3979 g = group;
3980
3981 r = find_gid(g, &i.gid, &c->gid_cache);
3982 if (r == -ESRCH && arg_graceful) {
3983 log_syntax(NULL, LOG_DEBUG, fname, line, r,
3984 "%s: group '%s' not found, not adjusting ownership.", i.path, g);
3985 missing_user_or_group = true;
3986 } else if (r < 0) {
3987 *invalid_config = true;
3988 return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve group '%s': %m", g);
3989 } else
3990 i.gid_set = true;
3991 }
3992
3993 if (!empty_or_dash(mode)) {
3994 const char *mm;
3995 unsigned m;
3996
3997 for (mm = mode;; mm++)
3998 if (*mm == '~')
3999 i.mask_perms = true;
4000 else if (*mm == ':')
4001 i.mode_only_create = true;
4002 else
4003 break;
4004
4005 r = parse_mode(mm, &m);
4006 if (r < 0) {
4007 *invalid_config = true;
4008 return log_syntax(NULL, LOG_ERR, fname, line, r, "Invalid mode '%s'.", mode);
4009 }
4010
4011 i.mode = m;
4012 i.mode_set = true;
4013 } else
4014 i.mode = IN_SET(i.type,
4015 CREATE_DIRECTORY,
4016 TRUNCATE_DIRECTORY,
4017 CREATE_SUBVOLUME,
4018 CREATE_SUBVOLUME_INHERIT_QUOTA,
4019 CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
4020
4021 if (missing_user_or_group && (i.mode & ~0777) != 0) {
4022 /* Refuse any special bits for nodes where we couldn't resolve the ownership properly. */
4023 mode_t adjusted = i.mode & 0777;
4024 log_syntax(NULL, LOG_INFO, fname, line, 0,
4025 "Changing mode 0%o to 0%o because of changed ownership.", i.mode, adjusted);
4026 i.mode = adjusted;
4027 }
4028
4029 if (!empty_or_dash(age)) {
4030 const char *a = age;
4031 _cleanup_free_ char *seconds = NULL, *age_by = NULL;
4032
4033 if (*a == '~') {
4034 i.keep_first_level = true;
4035 a++;
4036 }
4037
4038 /* Format: "age-by:age"; where age-by is "[abcmABCM]+". */
4039 r = split_pair(a, ":", &age_by, &seconds);
4040 if (r == -ENOMEM)
4041 return log_oom();
4042 if (r < 0 && r != -EINVAL)
4043 return log_error_errno(r, "Failed to parse age-by for '%s': %m", age);
4044 if (r >= 0) {
4045 /* We found a ":", parse the "age-by" part. */
4046 r = parse_age_by_from_arg(age_by, &i);
4047 if (r == -ENOMEM)
4048 return log_oom();
4049 if (r < 0) {
4050 *invalid_config = true;
4051 return log_syntax(NULL, LOG_ERR, fname, line, r, "Invalid age-by '%s'.", age_by);
4052 }
4053
4054 /* For parsing the "age" part, after the ":". */
4055 a = seconds;
4056 }
4057
4058 r = parse_sec(a, &i.age);
4059 if (r < 0) {
4060 *invalid_config = true;
4061 return log_syntax(NULL, LOG_ERR, fname, line, r, "Invalid age '%s'.", a);
4062 }
4063
4064 i.age_set = true;
4065 }
4066
4067 h = needs_glob(i.type) ? c->globs : c->items;
4068
4069 existing = ordered_hashmap_get(h, i.path);
4070 if (existing) {
4071 if (is_duplicated_item(existing, &i)) {
4072 log_syntax(NULL, LOG_NOTICE, fname, line, 0,
4073 "Duplicate line for path \"%s\", ignoring.", i.path);
4074 return 0;
4075 }
4076 } else {
4077 existing = new0(ItemArray, 1);
4078 if (!existing)
4079 return log_oom();
4080
4081 r = ordered_hashmap_put(h, i.path, existing);
4082 if (r < 0) {
4083 free(existing);
4084 return log_oom();
4085 }
4086 }
4087
4088 if (!GREEDY_REALLOC(existing->items, existing->n_items + 1))
4089 return log_oom();
4090
4091 existing->items[existing->n_items++] = TAKE_STRUCT(i);
4092
4093 /* Sort item array, to enforce stable ordering of application */
4094 typesafe_qsort(existing->items, existing->n_items, item_compare);
4095
4096 return 0;
4097 }
4098
4099 static int cat_config(char **config_dirs, char **args) {
4100 _cleanup_strv_free_ char **files = NULL;
4101 int r;
4102
4103 r = conf_files_list_with_replacement(arg_root, config_dirs, arg_replace, &files, NULL);
4104 if (r < 0)
4105 return r;
4106
4107 pager_open(arg_pager_flags);
4108
4109 return cat_files(NULL, files, arg_cat_flags);
4110 }
4111
4112 static int exclude_default_prefixes(void) {
4113 int r;
4114
4115 /* Provide an easy way to exclude virtual/memory file systems from what we do here. Useful in
4116 * combination with --root= where we probably don't want to apply stuff to these dirs as they are
4117 * likely over-mounted if the root directory is actually used, and it wouldbe less than ideal to have
4118 * all kinds of files created/adjusted underneath these mount points. */
4119
4120 r = strv_extend_many(
4121 &arg_exclude_prefixes,
4122 "/dev",
4123 "/proc",
4124 "/run",
4125 "/sys");
4126 if (r < 0)
4127 return log_oom();
4128
4129 strv_uniq(arg_exclude_prefixes);
4130 return 0;
4131 }
4132
4133 static int help(void) {
4134 _cleanup_free_ char *link = NULL;
4135 int r;
4136
4137 r = terminal_urlify_man("systemd-tmpfiles", "8", &link);
4138 if (r < 0)
4139 return log_oom();
4140
4141 printf("%1$s COMMAND [OPTIONS...] [CONFIGURATION FILE...]\n"
4142 "\n%2$sCreate, delete, and clean up files and directories.%4$s\n"
4143 "\n%3$sCommands:%4$s\n"
4144 " --create Create files and directories\n"
4145 " --clean Clean up files and directories\n"
4146 " --remove Remove files and directories\n"
4147 " -h --help Show this help\n"
4148 " --version Show package version\n"
4149 "\n%3$sOptions:%4$s\n"
4150 " --user Execute user configuration\n"
4151 " --cat-config Show configuration files\n"
4152 " --tldr Show non-comment parts of configuration\n"
4153 " --boot Execute actions only safe at boot\n"
4154 " --graceful Quietly ignore unknown users or groups\n"
4155 " --purge Delete all files owned by the configuration files\n"
4156 " --prefix=PATH Only apply rules with the specified prefix\n"
4157 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
4158 " -E Ignore rules prefixed with /dev, /proc, /run, /sys\n"
4159 " --root=PATH Operate on an alternate filesystem root\n"
4160 " --image=PATH Operate on disk image as filesystem root\n"
4161 " --image-policy=POLICY Specify disk image dissection policy\n"
4162 " --replace=PATH Treat arguments as replacement for PATH\n"
4163 " --dry-run Just print what would be done\n"
4164 " --no-pager Do not pipe output into a pager\n"
4165 "\nSee the %5$s for details.\n",
4166 program_invocation_short_name,
4167 ansi_highlight(),
4168 ansi_underline(),
4169 ansi_normal(),
4170 link);
4171
4172 return 0;
4173 }
4174
4175 static int parse_argv(int argc, char *argv[]) {
4176 enum {
4177 ARG_VERSION = 0x100,
4178 ARG_CAT_CONFIG,
4179 ARG_TLDR,
4180 ARG_USER,
4181 ARG_CREATE,
4182 ARG_CLEAN,
4183 ARG_REMOVE,
4184 ARG_PURGE,
4185 ARG_BOOT,
4186 ARG_GRACEFUL,
4187 ARG_PREFIX,
4188 ARG_EXCLUDE_PREFIX,
4189 ARG_ROOT,
4190 ARG_IMAGE,
4191 ARG_IMAGE_POLICY,
4192 ARG_REPLACE,
4193 ARG_DRY_RUN,
4194 ARG_NO_PAGER,
4195 };
4196
4197 static const struct option options[] = {
4198 { "help", no_argument, NULL, 'h' },
4199 { "user", no_argument, NULL, ARG_USER },
4200 { "version", no_argument, NULL, ARG_VERSION },
4201 { "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
4202 { "tldr", no_argument, NULL, ARG_TLDR },
4203 { "create", no_argument, NULL, ARG_CREATE },
4204 { "clean", no_argument, NULL, ARG_CLEAN },
4205 { "remove", no_argument, NULL, ARG_REMOVE },
4206 { "purge", no_argument, NULL, ARG_PURGE },
4207 { "boot", no_argument, NULL, ARG_BOOT },
4208 { "graceful", no_argument, NULL, ARG_GRACEFUL },
4209 { "prefix", required_argument, NULL, ARG_PREFIX },
4210 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
4211 { "root", required_argument, NULL, ARG_ROOT },
4212 { "image", required_argument, NULL, ARG_IMAGE },
4213 { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
4214 { "replace", required_argument, NULL, ARG_REPLACE },
4215 { "dry-run", no_argument, NULL, ARG_DRY_RUN },
4216 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
4217 {}
4218 };
4219
4220 int c, r;
4221
4222 assert(argc >= 0);
4223 assert(argv);
4224
4225 while ((c = getopt_long(argc, argv, "hE", options, NULL)) >= 0)
4226
4227 switch (c) {
4228
4229 case 'h':
4230 return help();
4231
4232 case ARG_VERSION:
4233 return version();
4234
4235 case ARG_CAT_CONFIG:
4236 arg_cat_flags = CAT_CONFIG_ON;
4237 break;
4238
4239 case ARG_TLDR:
4240 arg_cat_flags = CAT_TLDR;
4241 break;
4242
4243 case ARG_USER:
4244 arg_runtime_scope = RUNTIME_SCOPE_USER;
4245 break;
4246
4247 case ARG_CREATE:
4248 arg_operation |= OPERATION_CREATE;
4249 break;
4250
4251 case ARG_CLEAN:
4252 arg_operation |= OPERATION_CLEAN;
4253 break;
4254
4255 case ARG_REMOVE:
4256 arg_operation |= OPERATION_REMOVE;
4257 break;
4258
4259 case ARG_BOOT:
4260 arg_boot = true;
4261 break;
4262
4263 case ARG_PURGE:
4264 arg_operation |= OPERATION_PURGE;
4265 break;
4266
4267 case ARG_GRACEFUL:
4268 arg_graceful = true;
4269 break;
4270
4271 case ARG_PREFIX:
4272 if (strv_extend(&arg_include_prefixes, optarg) < 0)
4273 return log_oom();
4274 break;
4275
4276 case ARG_EXCLUDE_PREFIX:
4277 if (strv_extend(&arg_exclude_prefixes, optarg) < 0)
4278 return log_oom();
4279 break;
4280
4281 case ARG_ROOT:
4282 r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_root);
4283 if (r < 0)
4284 return r;
4285 break;
4286
4287 case ARG_IMAGE:
4288 #ifdef STANDALONE
4289 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
4290 "This systemd-tmpfiles version is compiled without support for --image=.");
4291 #else
4292 r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image);
4293 if (r < 0)
4294 return r;
4295 #endif
4296 /* Imply -E here since it makes little sense to create files persistently in the /run mountpoint of a disk image */
4297 _fallthrough_;
4298
4299 case 'E':
4300 r = exclude_default_prefixes();
4301 if (r < 0)
4302 return r;
4303
4304 break;
4305
4306 case ARG_IMAGE_POLICY:
4307 r = parse_image_policy_argument(optarg, &arg_image_policy);
4308 if (r < 0)
4309 return r;
4310 break;
4311
4312 case ARG_REPLACE:
4313 if (!path_is_absolute(optarg))
4314 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
4315 "The argument to --replace= must be an absolute path.");
4316 if (!endswith(optarg, ".conf"))
4317 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
4318 "The argument to --replace= must have the extension '.conf'.");
4319
4320 arg_replace = optarg;
4321 break;
4322
4323 case ARG_DRY_RUN:
4324 arg_dry_run = true;
4325 break;
4326
4327 case ARG_NO_PAGER:
4328 arg_pager_flags |= PAGER_DISABLE;
4329 break;
4330
4331 case '?':
4332 return -EINVAL;
4333
4334 default:
4335 assert_not_reached();
4336 }
4337
4338 if (arg_operation == 0 && arg_cat_flags == CAT_CONFIG_OFF)
4339 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
4340 "You need to specify at least one of --clean, --create, --remove, or --purge.");
4341
4342 if (arg_replace && arg_cat_flags != CAT_CONFIG_OFF)
4343 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
4344 "Option --replace= is not supported with --cat-config/--tldr.");
4345
4346 if (arg_replace && optind >= argc)
4347 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
4348 "When --replace= is given, some configuration items must be specified.");
4349
4350 if (arg_root && arg_runtime_scope == RUNTIME_SCOPE_USER)
4351 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
4352 "Combination of --user and --root= is not supported.");
4353
4354 if (arg_image && arg_root)
4355 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
4356 "Please specify either --root= or --image=, the combination of both is not supported.");
4357
4358 return 1;
4359 }
4360
4361 static int read_config_file(
4362 Context *c,
4363 char **config_dirs,
4364 const char *fn,
4365 bool ignore_enoent,
4366 bool *invalid_config) {
4367
4368 ItemArray *ia;
4369 int r = 0;
4370
4371 assert(c);
4372 assert(fn);
4373
4374 r = conf_file_read(arg_root, (const char**) config_dirs, fn,
4375 parse_line, c, ignore_enoent, invalid_config);
4376 if (r <= 0)
4377 return r;
4378
4379 /* we have to determine age parameter for each entry of type X */
4380 ORDERED_HASHMAP_FOREACH(ia, c->globs)
4381 FOREACH_ARRAY(i, ia->items, ia->n_items) {
4382 ItemArray *ja;
4383 Item *candidate_item = NULL;
4384
4385 if (i->type != IGNORE_DIRECTORY_PATH)
4386 continue;
4387
4388 ORDERED_HASHMAP_FOREACH(ja, c->items)
4389 FOREACH_ARRAY(j, ja->items, ja->n_items) {
4390 if (!IN_SET(j->type, CREATE_DIRECTORY,
4391 TRUNCATE_DIRECTORY,
4392 CREATE_SUBVOLUME,
4393 CREATE_SUBVOLUME_INHERIT_QUOTA,
4394 CREATE_SUBVOLUME_NEW_QUOTA))
4395 continue;
4396
4397 if (path_equal(j->path, i->path)) {
4398 candidate_item = j;
4399 break;
4400 }
4401
4402 if (candidate_item
4403 ? (path_startswith(j->path, candidate_item->path) && fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)
4404 : path_startswith(i->path, j->path) != NULL)
4405 candidate_item = j;
4406 }
4407
4408 if (candidate_item && candidate_item->age_set) {
4409 i->age = candidate_item->age;
4410 i->age_set = true;
4411 }
4412 }
4413
4414 return r;
4415 }
4416
4417 static int parse_arguments(
4418 Context *c,
4419 char **config_dirs,
4420 char **args,
4421 bool *invalid_config) {
4422 int r;
4423
4424 assert(c);
4425
4426 STRV_FOREACH(arg, args) {
4427 r = read_config_file(c, config_dirs, *arg, false, invalid_config);
4428 if (r < 0)
4429 return r;
4430 }
4431
4432 return 0;
4433 }
4434
4435 static int read_config_files(
4436 Context *c,
4437 char **config_dirs,
4438 char **args,
4439 bool *invalid_config) {
4440
4441 _cleanup_strv_free_ char **files = NULL;
4442 _cleanup_free_ char *p = NULL;
4443 int r;
4444
4445 assert(c);
4446
4447 r = conf_files_list_with_replacement(arg_root, config_dirs, arg_replace, &files, &p);
4448 if (r < 0)
4449 return r;
4450
4451 STRV_FOREACH(f, files)
4452 if (p && path_equal(*f, p)) {
4453 log_debug("Parsing arguments at position \"%s\"%s", *f, special_glyph(SPECIAL_GLYPH_ELLIPSIS));
4454
4455 r = parse_arguments(c, config_dirs, args, invalid_config);
4456 if (r < 0)
4457 return r;
4458 } else
4459 /* Just warn, ignore result otherwise.
4460 * read_config_file() has some debug output, so no need to print anything. */
4461 (void) read_config_file(c, config_dirs, *f, true, invalid_config);
4462
4463 return 0;
4464 }
4465
4466 static int read_credential_lines(Context *c, bool *invalid_config) {
4467 _cleanup_free_ char *j = NULL;
4468 const char *d;
4469 int r;
4470
4471 assert(c);
4472
4473 r = get_credentials_dir(&d);
4474 if (r == -ENXIO)
4475 return 0;
4476 if (r < 0)
4477 return log_error_errno(r, "Failed to get credentials directory: %m");
4478
4479 j = path_join(d, "tmpfiles.extra");
4480 if (!j)
4481 return log_oom();
4482
4483 (void) read_config_file(c, /* config_dirs= */ NULL, j, /* ignore_enoent= */ true, invalid_config);
4484 return 0;
4485 }
4486
4487 static int link_parent(Context *c, ItemArray *a) {
4488 const char *path;
4489 char *prefix;
4490 int r;
4491
4492 assert(c);
4493 assert(a);
4494
4495 /* Finds the closest "parent" item array for the specified item array. Then registers the specified
4496 * item array as child of it, and fills the parent in, linking them both ways. This allows us to
4497 * later create parents before their children, and clean up/remove children before their parents.
4498 */
4499
4500 if (a->n_items <= 0)
4501 return 0;
4502
4503 path = a->items[0].path;
4504 prefix = newa(char, strlen(path) + 1);
4505 PATH_FOREACH_PREFIX(prefix, path) {
4506 ItemArray *j;
4507
4508 j = ordered_hashmap_get(c->items, prefix);
4509 if (!j)
4510 j = ordered_hashmap_get(c->globs, prefix);
4511 if (j) {
4512 r = set_ensure_put(&j->children, NULL, a);
4513 if (r < 0)
4514 return log_oom();
4515
4516 a->parent = j;
4517 return 1;
4518 }
4519 }
4520
4521 return 0;
4522 }
4523
4524 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(item_array_hash_ops, char, string_hash_func, string_compare_func,
4525 ItemArray, item_array_free);
4526
4527 static int run(int argc, char *argv[]) {
4528 #ifndef STANDALONE
4529 _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
4530 _cleanup_(umount_and_freep) char *mounted_dir = NULL;
4531 #endif
4532 _cleanup_strv_free_ char **config_dirs = NULL;
4533 _cleanup_(context_done) Context c = {};
4534 bool invalid_config = false;
4535 ItemArray *a;
4536 enum {
4537 PHASE_PURGE,
4538 PHASE_REMOVE_AND_CLEAN,
4539 PHASE_CREATE,
4540 _PHASE_MAX
4541 } phase;
4542 int r, k;
4543
4544 r = parse_argv(argc, argv);
4545 if (r <= 0)
4546 return r;
4547
4548 log_setup();
4549
4550 /* We require /proc/ for a lot of our operations, i.e. for adjusting access modes, for anything
4551 * SELinux related, for recursive operation, for xattr, acl and chattr handling, for btrfs stuff and
4552 * a lot more. It's probably the majority of invocations where /proc/ is required. Since people
4553 * apparently invoke it without anyway and are surprised about the failures, let's catch this early
4554 * and output a nice and friendly warning. */
4555 if (proc_mounted() == 0)
4556 return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
4557 "/proc/ is not mounted, but required for successful operation of systemd-tmpfiles. "
4558 "Please mount /proc/. Alternatively, consider using the --root= or --image= switches.");
4559
4560 /* Descending down file system trees might take a lot of fds */
4561 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
4562
4563 switch (arg_runtime_scope) {
4564
4565 case RUNTIME_SCOPE_USER:
4566 r = user_config_paths(&config_dirs);
4567 if (r < 0)
4568 return log_error_errno(r, "Failed to initialize configuration directory list: %m");
4569 break;
4570
4571 case RUNTIME_SCOPE_SYSTEM:
4572 config_dirs = strv_new(CONF_PATHS("tmpfiles.d"));
4573 if (!config_dirs)
4574 return log_oom();
4575 break;
4576
4577 default:
4578 assert_not_reached();
4579 }
4580
4581 if (DEBUG_LOGGING) {
4582 _cleanup_free_ char *t = NULL;
4583
4584 STRV_FOREACH(i, config_dirs) {
4585 _cleanup_free_ char *j = NULL;
4586
4587 j = path_join(arg_root, *i);
4588 if (!j)
4589 return log_oom();
4590
4591 if (!strextend(&t, "\n\t", j))
4592 return log_oom();
4593 }
4594
4595 log_debug("Looking for configuration files in (higher priority first):%s", t);
4596 }
4597
4598 if (arg_cat_flags != CAT_CONFIG_OFF)
4599 return cat_config(config_dirs, argv + optind);
4600
4601 umask(0022);
4602
4603 r = mac_init();
4604 if (r < 0)
4605 return r;
4606
4607 #ifndef STANDALONE
4608 if (arg_image) {
4609 assert(!arg_root);
4610
4611 r = mount_image_privately_interactively(
4612 arg_image,
4613 arg_image_policy,
4614 DISSECT_IMAGE_GENERIC_ROOT |
4615 DISSECT_IMAGE_REQUIRE_ROOT |
4616 DISSECT_IMAGE_VALIDATE_OS |
4617 DISSECT_IMAGE_RELAX_VAR_CHECK |
4618 DISSECT_IMAGE_FSCK |
4619 DISSECT_IMAGE_GROWFS |
4620 DISSECT_IMAGE_ALLOW_USERSPACE_VERITY,
4621 &mounted_dir,
4622 /* ret_dir_fd= */ NULL,
4623 &loop_device);
4624 if (r < 0)
4625 return r;
4626
4627 arg_root = strdup(mounted_dir);
4628 if (!arg_root)
4629 return log_oom();
4630 }
4631 #else
4632 assert(!arg_image);
4633 #endif
4634
4635 c.items = ordered_hashmap_new(&item_array_hash_ops);
4636 c.globs = ordered_hashmap_new(&item_array_hash_ops);
4637 if (!c.items || !c.globs)
4638 return log_oom();
4639
4640 /* If command line arguments are specified along with --replace, read all
4641 * configuration files and insert the positional arguments at the specified
4642 * place. Otherwise, if command line arguments are specified, execute just
4643 * them, and finally, without --replace= or any positional arguments, just
4644 * read configuration and execute it.
4645 */
4646 if (arg_replace || optind >= argc)
4647 r = read_config_files(&c, config_dirs, argv + optind, &invalid_config);
4648 else
4649 r = parse_arguments(&c, config_dirs, argv + optind, &invalid_config);
4650 if (r < 0)
4651 return r;
4652
4653 r = read_credential_lines(&c, &invalid_config);
4654 if (r < 0)
4655 return r;
4656
4657 /* Let's now link up all child/parent relationships */
4658 ORDERED_HASHMAP_FOREACH(a, c.items) {
4659 r = link_parent(&c, a);
4660 if (r < 0)
4661 return r;
4662 }
4663 ORDERED_HASHMAP_FOREACH(a, c.globs) {
4664 r = link_parent(&c, a);
4665 if (r < 0)
4666 return r;
4667 }
4668
4669 /* If multiple operations are requested, let's first run the remove/clean operations, and only then
4670 * the create operations. i.e. that we first clean out the platform we then build on. */
4671 for (phase = 0; phase < _PHASE_MAX; phase++) {
4672 OperationMask op;
4673
4674 if (phase == PHASE_PURGE)
4675 op = arg_operation & OPERATION_PURGE;
4676 else if (phase == PHASE_REMOVE_AND_CLEAN)
4677 op = arg_operation & (OPERATION_REMOVE|OPERATION_CLEAN);
4678 else if (phase == PHASE_CREATE)
4679 op = arg_operation & OPERATION_CREATE;
4680 else
4681 assert_not_reached();
4682
4683 if (op == 0) /* Nothing requested in this phase */
4684 continue;
4685
4686 /* The non-globbing ones usually create things, hence we apply them first */
4687 ORDERED_HASHMAP_FOREACH(a, c.items) {
4688 k = process_item_array(&c, a, op);
4689 if (k < 0 && r >= 0)
4690 r = k;
4691 }
4692
4693 /* The globbing ones usually alter things, hence we apply them second. */
4694 ORDERED_HASHMAP_FOREACH(a, c.globs) {
4695 k = process_item_array(&c, a, op);
4696 if (k < 0 && r >= 0)
4697 r = k;
4698 }
4699 }
4700
4701 if (ERRNO_IS_RESOURCE(r))
4702 return r;
4703 if (invalid_config)
4704 return EX_DATAERR;
4705 if (r < 0)
4706 return EX_CANTCREAT;
4707 return 0;
4708 }
4709
4710 DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);