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