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