]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/tmpfiles/tmpfiles.c
tmpfiles: fstat() works with fd opened with O_PATH since Linux 3.6
[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 path_set_perms(Item *i, const char *path) {
787 char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
788 _cleanup_close_ int fd = -1;
789 struct stat st;
790
791 assert(i);
792 assert(path);
793
794 if (!i->mode_set && !i->uid_set && !i->gid_set)
795 goto shortcut;
796
797 /* We open the file with O_PATH here, to make the operation
798 * somewhat atomic. Also there's unfortunately no fchmodat()
799 * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
800 * O_PATH. */
801
802 fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
803 if (fd < 0) {
804 int level = LOG_ERR, r = -errno;
805
806 /* Option "e" operates only on existing objects. Do not
807 * print errors about non-existent files or directories */
808 if (i->type == EMPTY_DIRECTORY && errno == ENOENT) {
809 level = LOG_DEBUG;
810 r = 0;
811 }
812
813 log_full_errno(level, errno, "Adjusting owner and mode for %s failed: %m", path);
814 return r;
815 }
816
817 if (fstat(fd, &st) < 0)
818 return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
819
820 if (hardlink_vulnerable(&st)) {
821 log_error("Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
822 return -EPERM;
823 }
824
825 xsprintf(fn, "/proc/self/fd/%i", fd);
826
827 if (i->mode_set) {
828 if (S_ISLNK(st.st_mode))
829 log_debug("Skipping mode fix for symlink %s.", path);
830 else {
831 mode_t m = i->mode;
832
833 if (i->mask_perms) {
834 if (!(st.st_mode & 0111))
835 m &= ~0111;
836 if (!(st.st_mode & 0222))
837 m &= ~0222;
838 if (!(st.st_mode & 0444))
839 m &= ~0444;
840 if (!S_ISDIR(st.st_mode))
841 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
842 }
843
844 if (m == (st.st_mode & 07777))
845 log_debug("\"%s\" has correct mode %o already.", path, st.st_mode);
846 else {
847 log_debug("Changing \"%s\" to mode %o.", path, m);
848
849 if (chmod(fn, m) < 0)
850 return log_error_errno(errno, "chmod() of %s via %s failed: %m", path, fn);
851 }
852 }
853 }
854
855 if ((i->uid_set && i->uid != st.st_uid) ||
856 (i->gid_set && i->gid != st.st_gid)) {
857 log_debug("Changing \"%s\" to owner "UID_FMT":"GID_FMT,
858 path,
859 i->uid_set ? i->uid : UID_INVALID,
860 i->gid_set ? i->gid : GID_INVALID);
861
862 if (chown(fn,
863 i->uid_set ? i->uid : UID_INVALID,
864 i->gid_set ? i->gid : GID_INVALID) < 0)
865 return log_error_errno(errno, "chown() of %s via %s failed: %m", path, fn);
866 }
867
868 fd = safe_close(fd);
869
870 shortcut:
871 return label_fix(path, false, false);
872 }
873
874 static int parse_xattrs_from_arg(Item *i) {
875 const char *p;
876 int r;
877
878 assert(i);
879 assert(i->argument);
880
881 p = i->argument;
882
883 for (;;) {
884 _cleanup_free_ char *name = NULL, *value = NULL, *xattr = NULL;
885
886 r = extract_first_word(&p, &xattr, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
887 if (r < 0)
888 log_warning_errno(r, "Failed to parse extended attribute '%s', ignoring: %m", p);
889 if (r <= 0)
890 break;
891
892 r = split_pair(xattr, "=", &name, &value);
893 if (r < 0) {
894 log_warning_errno(r, "Failed to parse extended attribute, ignoring: %s", xattr);
895 continue;
896 }
897
898 if (isempty(name) || isempty(value)) {
899 log_warning("Malformed extended attribute found, ignoring: %s", xattr);
900 continue;
901 }
902
903 if (strv_push_pair(&i->xattrs, name, value) < 0)
904 return log_oom();
905
906 name = value = NULL;
907 }
908
909 return 0;
910 }
911
912 static int path_set_xattrs(Item *i, const char *path) {
913 char **name, **value;
914
915 assert(i);
916 assert(path);
917
918 STRV_FOREACH_PAIR(name, value, i->xattrs) {
919 log_debug("Setting extended attribute '%s=%s' on %s.", *name, *value, path);
920 if (lsetxattr(path, *name, *value, strlen(*value), 0) < 0)
921 return log_error_errno(errno, "Setting extended attribute %s=%s on %s failed: %m",
922 *name, *value, path);
923 }
924 return 0;
925 }
926
927 static int parse_acls_from_arg(Item *item) {
928 #if HAVE_ACL
929 int r;
930
931 assert(item);
932
933 /* If force (= modify) is set, we will not modify the acl
934 * afterwards, so the mask can be added now if necessary. */
935
936 r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force);
937 if (r < 0)
938 log_warning_errno(r, "Failed to parse ACL \"%s\": %m. Ignoring", item->argument);
939 #else
940 log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring");
941 #endif
942
943 return 0;
944 }
945
946 #if HAVE_ACL
947 static int path_set_acl(const char *path, const char *pretty, acl_type_t type, acl_t acl, bool modify) {
948 _cleanup_(acl_free_charpp) char *t = NULL;
949 _cleanup_(acl_freep) acl_t dup = NULL;
950 int r;
951
952 /* Returns 0 for success, positive error if already warned,
953 * negative error otherwise. */
954
955 if (modify) {
956 r = acls_for_file(path, type, acl, &dup);
957 if (r < 0)
958 return r;
959
960 r = calc_acl_mask_if_needed(&dup);
961 if (r < 0)
962 return r;
963 } else {
964 dup = acl_dup(acl);
965 if (!dup)
966 return -errno;
967
968 /* the mask was already added earlier if needed */
969 }
970
971 r = add_base_acls_if_needed(&dup, path);
972 if (r < 0)
973 return r;
974
975 t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE);
976 log_debug("Setting %s ACL %s on %s.",
977 type == ACL_TYPE_ACCESS ? "access" : "default",
978 strna(t), pretty);
979
980 r = acl_set_file(path, type, dup);
981 if (r < 0)
982 /* Return positive to indicate we already warned */
983 return -log_error_errno(errno,
984 "Setting %s ACL \"%s\" on %s failed: %m",
985 type == ACL_TYPE_ACCESS ? "access" : "default",
986 strna(t), pretty);
987
988 return 0;
989 }
990 #endif
991
992 static int path_set_acls(Item *item, const char *path) {
993 int r = 0;
994 #if HAVE_ACL
995 char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
996 _cleanup_close_ int fd = -1;
997 struct stat st;
998
999 assert(item);
1000 assert(path);
1001
1002 fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
1003 if (fd < 0)
1004 return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path);
1005
1006 if (fstat(fd, &st) < 0)
1007 return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
1008
1009 if (hardlink_vulnerable(&st)) {
1010 log_error("Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
1011 return -EPERM;
1012 }
1013
1014 if (S_ISLNK(st.st_mode)) {
1015 log_debug("Skipping ACL fix for symlink %s.", path);
1016 return 0;
1017 }
1018
1019 xsprintf(fn, "/proc/self/fd/%i", fd);
1020
1021 if (item->acl_access)
1022 r = path_set_acl(fn, path, ACL_TYPE_ACCESS, item->acl_access, item->force);
1023
1024 if (r == 0 && item->acl_default)
1025 r = path_set_acl(fn, path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
1026
1027 if (r > 0)
1028 return -r; /* already warned */
1029 else if (r == -EOPNOTSUPP) {
1030 log_debug_errno(r, "ACLs not supported by file system at %s", path);
1031 return 0;
1032 } else if (r < 0)
1033 log_error_errno(r, "ACL operation on \"%s\" failed: %m", path);
1034 #endif
1035 return r;
1036 }
1037
1038 #define ATTRIBUTES_ALL \
1039 (FS_NOATIME_FL | \
1040 FS_SYNC_FL | \
1041 FS_DIRSYNC_FL | \
1042 FS_APPEND_FL | \
1043 FS_COMPR_FL | \
1044 FS_NODUMP_FL | \
1045 FS_EXTENT_FL | \
1046 FS_IMMUTABLE_FL | \
1047 FS_JOURNAL_DATA_FL | \
1048 FS_SECRM_FL | \
1049 FS_UNRM_FL | \
1050 FS_NOTAIL_FL | \
1051 FS_TOPDIR_FL | \
1052 FS_NOCOW_FL)
1053
1054 static int parse_attribute_from_arg(Item *item) {
1055
1056 static const struct {
1057 char character;
1058 unsigned value;
1059 } attributes[] = {
1060 { 'A', FS_NOATIME_FL }, /* do not update atime */
1061 { 'S', FS_SYNC_FL }, /* Synchronous updates */
1062 { 'D', FS_DIRSYNC_FL }, /* dirsync behaviour (directories only) */
1063 { 'a', FS_APPEND_FL }, /* writes to file may only append */
1064 { 'c', FS_COMPR_FL }, /* Compress file */
1065 { 'd', FS_NODUMP_FL }, /* do not dump file */
1066 { 'e', FS_EXTENT_FL }, /* Extents */
1067 { 'i', FS_IMMUTABLE_FL }, /* Immutable file */
1068 { 'j', FS_JOURNAL_DATA_FL }, /* Reserved for ext3 */
1069 { 's', FS_SECRM_FL }, /* Secure deletion */
1070 { 'u', FS_UNRM_FL }, /* Undelete */
1071 { 't', FS_NOTAIL_FL }, /* file tail should not be merged */
1072 { 'T', FS_TOPDIR_FL }, /* Top of directory hierarchies */
1073 { 'C', FS_NOCOW_FL }, /* Do not cow file */
1074 };
1075
1076 enum {
1077 MODE_ADD,
1078 MODE_DEL,
1079 MODE_SET
1080 } mode = MODE_ADD;
1081
1082 unsigned value = 0, mask = 0;
1083 const char *p;
1084
1085 assert(item);
1086
1087 p = item->argument;
1088 if (p) {
1089 if (*p == '+') {
1090 mode = MODE_ADD;
1091 p++;
1092 } else if (*p == '-') {
1093 mode = MODE_DEL;
1094 p++;
1095 } else if (*p == '=') {
1096 mode = MODE_SET;
1097 p++;
1098 }
1099 }
1100
1101 if (isempty(p) && mode != MODE_SET) {
1102 log_error("Setting file attribute on '%s' needs an attribute specification.", item->path);
1103 return -EINVAL;
1104 }
1105
1106 for (; p && *p ; p++) {
1107 unsigned i, v;
1108
1109 for (i = 0; i < ELEMENTSOF(attributes); i++)
1110 if (*p == attributes[i].character)
1111 break;
1112
1113 if (i >= ELEMENTSOF(attributes)) {
1114 log_error("Unknown file attribute '%c' on '%s'.", *p, item->path);
1115 return -EINVAL;
1116 }
1117
1118 v = attributes[i].value;
1119
1120 SET_FLAG(value, v, IN_SET(mode, MODE_ADD, MODE_SET));
1121
1122 mask |= v;
1123 }
1124
1125 if (mode == MODE_SET)
1126 mask |= ATTRIBUTES_ALL;
1127
1128 assert(mask != 0);
1129
1130 item->attribute_mask = mask;
1131 item->attribute_value = value;
1132 item->attribute_set = true;
1133
1134 return 0;
1135 }
1136
1137 static int path_set_attribute(Item *item, const char *path) {
1138 _cleanup_close_ int fd = -1;
1139 struct stat st;
1140 unsigned f;
1141 int r;
1142
1143 if (!item->attribute_set || item->attribute_mask == 0)
1144 return 0;
1145
1146 fd = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOATIME|O_NOFOLLOW);
1147 if (fd < 0) {
1148 if (errno == ELOOP)
1149 return log_error_errno(errno, "Skipping file attributes adjustment on symlink %s.", path);
1150
1151 return log_error_errno(errno, "Cannot open '%s': %m", path);
1152 }
1153
1154 if (fstat(fd, &st) < 0)
1155 return log_error_errno(errno, "Cannot stat '%s': %m", path);
1156
1157 /* Issuing the file attribute ioctls on device nodes is not
1158 * safe, as that will be delivered to the drivers, not the
1159 * file system containing the device node. */
1160 if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
1161 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path);
1162 return -EINVAL;
1163 }
1164
1165 f = item->attribute_value & item->attribute_mask;
1166
1167 /* Mask away directory-specific flags */
1168 if (!S_ISDIR(st.st_mode))
1169 f &= ~FS_DIRSYNC_FL;
1170
1171 r = chattr_fd(fd, f, item->attribute_mask);
1172 if (r < 0)
1173 log_full_errno(IN_SET(r, -ENOTTY, -EOPNOTSUPP) ? LOG_DEBUG : LOG_WARNING,
1174 r,
1175 "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
1176 path, item->attribute_value, item->attribute_mask);
1177
1178 return 0;
1179 }
1180
1181 static int write_one_file(Item *i, const char *path) {
1182 _cleanup_close_ int fd = -1;
1183 int flags, r = 0;
1184 struct stat st;
1185
1186 assert(i);
1187 assert(path);
1188
1189 flags = i->type == CREATE_FILE ? O_CREAT|O_EXCL|O_NOFOLLOW :
1190 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
1191
1192 RUN_WITH_UMASK(0000) {
1193 mac_selinux_create_file_prepare(path, S_IFREG);
1194 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
1195 mac_selinux_create_file_clear();
1196 }
1197
1198 if (fd < 0) {
1199 if (i->type == WRITE_FILE && errno == ENOENT) {
1200 log_debug_errno(errno, "Not writing missing file \"%s\": %m", path);
1201 return 0;
1202 }
1203 if (i->type == CREATE_FILE && errno == EEXIST) {
1204 log_debug_errno(errno, "Not writing to pre-existing file \"%s\": %m", path);
1205 goto done;
1206 }
1207
1208 r = -errno;
1209 if (!i->argument && errno == EROFS && stat(path, &st) == 0 &&
1210 (i->type == CREATE_FILE || st.st_size == 0))
1211 goto check_mode;
1212
1213 return log_error_errno(r, "Failed to create file %s: %m", path);
1214 }
1215
1216 if (i->argument) {
1217 log_debug("%s to \"%s\".", i->type == CREATE_FILE ? "Appending" : "Writing", path);
1218
1219 r = loop_write(fd, i->argument, strlen(i->argument), false);
1220 if (r < 0)
1221 return log_error_errno(r, "Failed to write file \"%s\": %m", path);
1222 } else
1223 log_debug("\"%s\" has been created.", path);
1224
1225 fd = safe_close(fd);
1226
1227 done:
1228 if (stat(path, &st) < 0)
1229 return log_error_errno(errno, "stat(%s) failed: %m", path);
1230
1231 check_mode:
1232 if (!S_ISREG(st.st_mode)) {
1233 log_error("%s is not a file.", path);
1234 return -EEXIST;
1235 }
1236
1237 r = path_set_perms(i, path);
1238 if (r < 0)
1239 return r;
1240
1241 return 0;
1242 }
1243
1244 typedef int (*action_t)(Item *, const char *);
1245
1246 static int item_do_children(Item *i, const char *path, action_t action) {
1247 _cleanup_closedir_ DIR *d;
1248 struct dirent *de;
1249 int r = 0;
1250
1251 assert(i);
1252 assert(path);
1253
1254 /* This returns the first error we run into, but nevertheless
1255 * tries to go on */
1256
1257 d = opendir_nomod(path);
1258 if (!d)
1259 return IN_SET(errno, ENOENT, ENOTDIR, ELOOP) ? 0 : -errno;
1260
1261 FOREACH_DIRENT_ALL(de, d, r = -errno) {
1262 _cleanup_free_ char *p = NULL;
1263 int q;
1264
1265 if (dot_or_dot_dot(de->d_name))
1266 continue;
1267
1268 p = strjoin(path, "/", de->d_name);
1269 if (!p)
1270 return -ENOMEM;
1271
1272 q = action(i, p);
1273 if (q < 0 && q != -ENOENT && r == 0)
1274 r = q;
1275
1276 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
1277 q = item_do_children(i, p, action);
1278 if (q < 0 && r == 0)
1279 r = q;
1280 }
1281 }
1282
1283 return r;
1284 }
1285
1286 static int glob_item(Item *i, action_t action, bool recursive) {
1287 _cleanup_globfree_ glob_t g = {
1288 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
1289 };
1290 int r = 0, k;
1291 char **fn;
1292
1293 k = safe_glob(i->path, GLOB_NOSORT|GLOB_BRACE, &g);
1294 if (k < 0 && k != -ENOENT)
1295 return log_error_errno(k, "glob(%s) failed: %m", i->path);
1296
1297 STRV_FOREACH(fn, g.gl_pathv) {
1298 k = action(i, *fn);
1299 if (k < 0 && r == 0)
1300 r = k;
1301
1302 if (recursive) {
1303 k = item_do_children(i, *fn, action);
1304 if (k < 0 && r == 0)
1305 r = k;
1306 }
1307 }
1308
1309 return r;
1310 }
1311
1312 typedef enum {
1313 CREATION_NORMAL,
1314 CREATION_EXISTING,
1315 CREATION_FORCE,
1316 _CREATION_MODE_MAX,
1317 _CREATION_MODE_INVALID = -1
1318 } CreationMode;
1319
1320 static const char *creation_mode_verb_table[_CREATION_MODE_MAX] = {
1321 [CREATION_NORMAL] = "Created",
1322 [CREATION_EXISTING] = "Found existing",
1323 [CREATION_FORCE] = "Created replacement",
1324 };
1325
1326 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
1327
1328 static int create_item(Item *i) {
1329 struct stat st;
1330 int r = 0;
1331 int q = 0;
1332 CreationMode creation;
1333
1334 assert(i);
1335
1336 log_debug("Running create action for entry %c %s", (char) i->type, i->path);
1337
1338 switch (i->type) {
1339
1340 case IGNORE_PATH:
1341 case IGNORE_DIRECTORY_PATH:
1342 case REMOVE_PATH:
1343 case RECURSIVE_REMOVE_PATH:
1344 return 0;
1345
1346 case CREATE_FILE:
1347 case TRUNCATE_FILE:
1348 RUN_WITH_UMASK(0000)
1349 (void) mkdir_parents_label(i->path, 0755);
1350
1351 r = write_one_file(i, i->path);
1352 if (r < 0)
1353 return r;
1354 break;
1355
1356 case COPY_FILES: {
1357
1358 RUN_WITH_UMASK(0000)
1359 (void) mkdir_parents_label(i->path, 0755);
1360
1361 log_debug("Copying tree \"%s\" to \"%s\".", i->argument, i->path);
1362 r = copy_tree(i->argument, i->path,
1363 i->uid_set ? i->uid : UID_INVALID,
1364 i->gid_set ? i->gid : GID_INVALID,
1365 COPY_REFLINK);
1366
1367 if (r == -EROFS && stat(i->path, &st) == 0)
1368 r = -EEXIST;
1369
1370 if (r < 0) {
1371 struct stat a, b;
1372
1373 if (r != -EEXIST)
1374 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
1375
1376 if (stat(i->argument, &a) < 0)
1377 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
1378
1379 if (stat(i->path, &b) < 0)
1380 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1381
1382 if ((a.st_mode ^ b.st_mode) & S_IFMT) {
1383 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
1384 return 0;
1385 }
1386 }
1387
1388 r = path_set_perms(i, i->path);
1389 if (r < 0)
1390 return r;
1391
1392 break;
1393
1394 case WRITE_FILE:
1395 r = glob_item(i, write_one_file, false);
1396 if (r < 0)
1397 return r;
1398
1399 break;
1400
1401 case CREATE_DIRECTORY:
1402 case TRUNCATE_DIRECTORY:
1403 case CREATE_SUBVOLUME:
1404 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1405 case CREATE_SUBVOLUME_NEW_QUOTA:
1406 RUN_WITH_UMASK(0000)
1407 (void) mkdir_parents_label(i->path, 0755);
1408
1409 if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) {
1410
1411 if (btrfs_is_subvol(isempty(arg_root) ? "/" : arg_root) <= 0)
1412
1413 /* Don't create a subvolume unless the
1414 * root directory is one, too. We do
1415 * this under the assumption that if
1416 * the root directory is just a plain
1417 * directory (i.e. very light-weight),
1418 * we shouldn't try to split it up
1419 * into subvolumes (i.e. more
1420 * heavy-weight). Thus, chroot()
1421 * environments and suchlike will get
1422 * a full brtfs subvolume set up below
1423 * their tree only if they
1424 * specifically set up a btrfs
1425 * subvolume for the root dir too. */
1426
1427 r = -ENOTTY;
1428 else {
1429 RUN_WITH_UMASK((~i->mode) & 0777)
1430 r = btrfs_subvol_make(i->path);
1431 }
1432 } else
1433 r = 0;
1434
1435 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY)
1436 RUN_WITH_UMASK(0000)
1437 r = mkdir_label(i->path, i->mode);
1438
1439 if (r < 0) {
1440 int k;
1441
1442 if (!IN_SET(r, -EEXIST, -EROFS))
1443 return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path);
1444
1445 k = is_dir(i->path, false);
1446 if (k == -ENOENT && r == -EROFS)
1447 return log_error_errno(r, "%s does not exist and cannot be created as the file system is read-only.", i->path);
1448 if (k < 0)
1449 return log_error_errno(k, "Failed to check if %s exists: %m", i->path);
1450 if (!k) {
1451 log_warning("\"%s\" already exists and is not a directory.", i->path);
1452 return 0;
1453 }
1454
1455 creation = CREATION_EXISTING;
1456 } else
1457 creation = CREATION_NORMAL;
1458
1459 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path);
1460
1461 if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
1462 r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
1463 if (r == -ENOTTY)
1464 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path);
1465 else if (r == -EROFS)
1466 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i->path);
1467 else if (r == -ENOPROTOOPT)
1468 log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i->path);
1469 else if (r < 0)
1470 q = log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
1471 else if (r > 0)
1472 log_debug("Adjusted quota for subvolume \"%s\".", i->path);
1473 else if (r == 0)
1474 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
1475 }
1476
1477 _fallthrough_;
1478 case EMPTY_DIRECTORY:
1479 r = path_set_perms(i, i->path);
1480 if (q < 0)
1481 return q;
1482 if (r < 0)
1483 return r;
1484
1485 break;
1486
1487 case CREATE_FIFO:
1488 RUN_WITH_UMASK(0000) {
1489 (void) mkdir_parents_label(i->path, 0755);
1490
1491 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1492 r = mkfifo(i->path, i->mode);
1493 mac_selinux_create_file_clear();
1494 }
1495
1496 if (r < 0) {
1497 if (errno != EEXIST)
1498 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
1499
1500 if (lstat(i->path, &st) < 0)
1501 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1502
1503 if (!S_ISFIFO(st.st_mode)) {
1504
1505 if (i->force) {
1506 RUN_WITH_UMASK(0000) {
1507 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1508 r = mkfifo_atomic(i->path, i->mode);
1509 mac_selinux_create_file_clear();
1510 }
1511
1512 if (r < 0)
1513 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
1514 creation = CREATION_FORCE;
1515 } else {
1516 log_warning("\"%s\" already exists and is not a fifo.", i->path);
1517 return 0;
1518 }
1519 } else
1520 creation = CREATION_EXISTING;
1521 } else
1522 creation = CREATION_NORMAL;
1523 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation), i->path);
1524
1525 r = path_set_perms(i, i->path);
1526 if (r < 0)
1527 return r;
1528
1529 break;
1530 }
1531
1532 case CREATE_SYMLINK: {
1533 RUN_WITH_UMASK(0000)
1534 (void) mkdir_parents_label(i->path, 0755);
1535
1536 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1537 r = symlink(i->argument, i->path);
1538 mac_selinux_create_file_clear();
1539
1540 if (r < 0) {
1541 _cleanup_free_ char *x = NULL;
1542
1543 if (errno != EEXIST)
1544 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
1545
1546 r = readlink_malloc(i->path, &x);
1547 if (r < 0 || !streq(i->argument, x)) {
1548
1549 if (i->force) {
1550 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1551 r = symlink_atomic(i->argument, i->path);
1552 mac_selinux_create_file_clear();
1553
1554 if (IN_SET(r, -EEXIST, -ENOTEMPTY)) {
1555 r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL);
1556 if (r < 0)
1557 return log_error_errno(r, "rm -fr %s failed: %m", i->path);
1558
1559 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1560 r = symlink(i->argument, i->path) < 0 ? -errno : 0;
1561 mac_selinux_create_file_clear();
1562 }
1563 if (r < 0)
1564 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
1565
1566 creation = CREATION_FORCE;
1567 } else {
1568 log_debug("\"%s\" is not a symlink or does not point to the correct path.", i->path);
1569 return 0;
1570 }
1571 } else
1572 creation = CREATION_EXISTING;
1573 } else
1574
1575 creation = CREATION_NORMAL;
1576 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation), i->path);
1577 break;
1578 }
1579
1580 case CREATE_BLOCK_DEVICE:
1581 case CREATE_CHAR_DEVICE: {
1582 mode_t file_type;
1583
1584 if (have_effective_cap(CAP_MKNOD) == 0) {
1585 /* In a container we lack CAP_MKNOD. We
1586 shouldn't attempt to create the device node in
1587 that case to avoid noise, and we don't support
1588 virtualized devices in containers anyway. */
1589
1590 log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
1591 return 0;
1592 }
1593
1594 RUN_WITH_UMASK(0000)
1595 (void) mkdir_parents_label(i->path, 0755);
1596
1597 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
1598
1599 RUN_WITH_UMASK(0000) {
1600 mac_selinux_create_file_prepare(i->path, file_type);
1601 r = mknod(i->path, i->mode | file_type, i->major_minor);
1602 mac_selinux_create_file_clear();
1603 }
1604
1605 if (r < 0) {
1606 if (errno == EPERM) {
1607 log_debug("We lack permissions, possibly because of cgroup configuration; "
1608 "skipping creation of device node %s.", i->path);
1609 return 0;
1610 }
1611
1612 if (errno != EEXIST)
1613 return log_error_errno(errno, "Failed to create device node %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 ((st.st_mode & S_IFMT) != file_type) {
1619
1620 if (i->force) {
1621
1622 RUN_WITH_UMASK(0000) {
1623 mac_selinux_create_file_prepare(i->path, file_type);
1624 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
1625 mac_selinux_create_file_clear();
1626 }
1627
1628 if (r < 0)
1629 return log_error_errno(r, "Failed to create device node \"%s\": %m", i->path);
1630 creation = CREATION_FORCE;
1631 } else {
1632 log_debug("%s is not a device node.", i->path);
1633 return 0;
1634 }
1635 } else
1636 creation = CREATION_EXISTING;
1637 } else
1638 creation = CREATION_NORMAL;
1639
1640 log_debug("%s %s device node \"%s\" %u:%u.",
1641 creation_mode_verb_to_string(creation),
1642 i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
1643 i->path, major(i->mode), minor(i->mode));
1644
1645 r = path_set_perms(i, i->path);
1646 if (r < 0)
1647 return r;
1648
1649 break;
1650 }
1651
1652 case ADJUST_MODE:
1653 case RELABEL_PATH:
1654 r = glob_item(i, path_set_perms, false);
1655 if (r < 0)
1656 return r;
1657 break;
1658
1659 case RECURSIVE_RELABEL_PATH:
1660 r = glob_item(i, path_set_perms, true);
1661 if (r < 0)
1662 return r;
1663 break;
1664
1665 case SET_XATTR:
1666 r = glob_item(i, path_set_xattrs, false);
1667 if (r < 0)
1668 return r;
1669 break;
1670
1671 case RECURSIVE_SET_XATTR:
1672 r = glob_item(i, path_set_xattrs, true);
1673 if (r < 0)
1674 return r;
1675 break;
1676
1677 case SET_ACL:
1678 r = glob_item(i, path_set_acls, false);
1679 if (r < 0)
1680 return r;
1681 break;
1682
1683 case RECURSIVE_SET_ACL:
1684 r = glob_item(i, path_set_acls, true);
1685 if (r < 0)
1686 return r;
1687 break;
1688
1689 case SET_ATTRIBUTE:
1690 r = glob_item(i, path_set_attribute, false);
1691 if (r < 0)
1692 return r;
1693 break;
1694
1695 case RECURSIVE_SET_ATTRIBUTE:
1696 r = glob_item(i, path_set_attribute, true);
1697 if (r < 0)
1698 return r;
1699 break;
1700 }
1701
1702 return 0;
1703 }
1704
1705 static int remove_item_instance(Item *i, const char *instance) {
1706 int r;
1707
1708 assert(i);
1709
1710 switch (i->type) {
1711
1712 case REMOVE_PATH:
1713 if (remove(instance) < 0 && errno != ENOENT)
1714 return log_error_errno(errno, "rm(%s): %m", instance);
1715
1716 break;
1717
1718 case TRUNCATE_DIRECTORY:
1719 case RECURSIVE_REMOVE_PATH:
1720 /* FIXME: we probably should use dir_cleanup() here
1721 * instead of rm_rf() so that 'x' is honoured. */
1722 log_debug("rm -rf \"%s\"", instance);
1723 r = rm_rf(instance, (i->type == RECURSIVE_REMOVE_PATH ? REMOVE_ROOT|REMOVE_SUBVOLUME : 0) | REMOVE_PHYSICAL);
1724 if (r < 0 && r != -ENOENT)
1725 return log_error_errno(r, "rm_rf(%s): %m", instance);
1726
1727 break;
1728
1729 default:
1730 assert_not_reached("wut?");
1731 }
1732
1733 return 0;
1734 }
1735
1736 static int remove_item(Item *i) {
1737 assert(i);
1738
1739 log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
1740
1741 switch (i->type) {
1742
1743 case REMOVE_PATH:
1744 case TRUNCATE_DIRECTORY:
1745 case RECURSIVE_REMOVE_PATH:
1746 return glob_item(i, remove_item_instance, false);
1747
1748 default:
1749 return 0;
1750 }
1751 }
1752
1753 static int clean_item_instance(Item *i, const char* instance) {
1754 _cleanup_closedir_ DIR *d = NULL;
1755 struct stat s, ps;
1756 bool mountpoint;
1757 usec_t cutoff, n;
1758 char timestamp[FORMAT_TIMESTAMP_MAX];
1759
1760 assert(i);
1761
1762 if (!i->age_set)
1763 return 0;
1764
1765 n = now(CLOCK_REALTIME);
1766 if (n < i->age)
1767 return 0;
1768
1769 cutoff = n - i->age;
1770
1771 d = opendir_nomod(instance);
1772 if (!d) {
1773 if (IN_SET(errno, ENOENT, ENOTDIR)) {
1774 log_debug_errno(errno, "Directory \"%s\": %m", instance);
1775 return 0;
1776 }
1777
1778 return log_error_errno(errno, "Failed to open directory %s: %m", instance);
1779 }
1780
1781 if (fstat(dirfd(d), &s) < 0)
1782 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1783
1784 if (!S_ISDIR(s.st_mode)) {
1785 log_error("%s is not a directory.", i->path);
1786 return -ENOTDIR;
1787 }
1788
1789 if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1790 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1791
1792 mountpoint = s.st_dev != ps.st_dev || s.st_ino == ps.st_ino;
1793
1794 log_debug("Cleanup threshold for %s \"%s\" is %s",
1795 mountpoint ? "mount point" : "directory",
1796 instance,
1797 format_timestamp_us(timestamp, sizeof(timestamp), cutoff));
1798
1799 return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1800 MAX_DEPTH, i->keep_first_level);
1801 }
1802
1803 static int clean_item(Item *i) {
1804 assert(i);
1805
1806 log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
1807
1808 switch (i->type) {
1809 case CREATE_DIRECTORY:
1810 case CREATE_SUBVOLUME:
1811 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1812 case CREATE_SUBVOLUME_NEW_QUOTA:
1813 case TRUNCATE_DIRECTORY:
1814 case IGNORE_PATH:
1815 case COPY_FILES:
1816 clean_item_instance(i, i->path);
1817 return 0;
1818 case EMPTY_DIRECTORY:
1819 case IGNORE_DIRECTORY_PATH:
1820 return glob_item(i, clean_item_instance, false);
1821 default:
1822 return 0;
1823 }
1824 }
1825
1826 static int process_item_array(ItemArray *array);
1827
1828 static int process_item(Item *i) {
1829 int r, q, p, t = 0;
1830 _cleanup_free_ char *prefix = NULL;
1831
1832 assert(i);
1833
1834 if (i->done)
1835 return 0;
1836
1837 i->done = true;
1838
1839 prefix = malloc(strlen(i->path) + 1);
1840 if (!prefix)
1841 return log_oom();
1842
1843 PATH_FOREACH_PREFIX(prefix, i->path) {
1844 ItemArray *j;
1845
1846 j = ordered_hashmap_get(items, prefix);
1847 if (j) {
1848 int s;
1849
1850 s = process_item_array(j);
1851 if (s < 0 && t == 0)
1852 t = s;
1853 }
1854 }
1855
1856 if (chase_symlinks(i->path, NULL, CHASE_NO_AUTOFS, NULL) == -EREMOTE)
1857 return t;
1858
1859 r = arg_create ? create_item(i) : 0;
1860 q = arg_remove ? remove_item(i) : 0;
1861 p = arg_clean ? clean_item(i) : 0;
1862
1863 return t < 0 ? t :
1864 r < 0 ? r :
1865 q < 0 ? q :
1866 p;
1867 }
1868
1869 static int process_item_array(ItemArray *array) {
1870 unsigned n;
1871 int r = 0, k;
1872
1873 assert(array);
1874
1875 for (n = 0; n < array->count; n++) {
1876 k = process_item(array->items + n);
1877 if (k < 0 && r == 0)
1878 r = k;
1879 }
1880
1881 return r;
1882 }
1883
1884 static void item_free_contents(Item *i) {
1885 assert(i);
1886 free(i->path);
1887 free(i->argument);
1888 strv_free(i->xattrs);
1889
1890 #if HAVE_ACL
1891 acl_free(i->acl_access);
1892 acl_free(i->acl_default);
1893 #endif
1894 }
1895
1896 static void item_array_free(ItemArray *a) {
1897 unsigned n;
1898
1899 if (!a)
1900 return;
1901
1902 for (n = 0; n < a->count; n++)
1903 item_free_contents(a->items + n);
1904 free(a->items);
1905 free(a);
1906 }
1907
1908 static int item_compare(const void *a, const void *b) {
1909 const Item *x = a, *y = b;
1910
1911 /* Make sure that the ownership taking item is put first, so
1912 * that we first create the node, and then can adjust it */
1913
1914 if (takes_ownership(x->type) && !takes_ownership(y->type))
1915 return -1;
1916 if (!takes_ownership(x->type) && takes_ownership(y->type))
1917 return 1;
1918
1919 return (int) x->type - (int) y->type;
1920 }
1921
1922 static bool item_compatible(Item *a, Item *b) {
1923 assert(a);
1924 assert(b);
1925 assert(streq(a->path, b->path));
1926
1927 if (takes_ownership(a->type) && takes_ownership(b->type))
1928 /* check if the items are the same */
1929 return streq_ptr(a->argument, b->argument) &&
1930
1931 a->uid_set == b->uid_set &&
1932 a->uid == b->uid &&
1933
1934 a->gid_set == b->gid_set &&
1935 a->gid == b->gid &&
1936
1937 a->mode_set == b->mode_set &&
1938 a->mode == b->mode &&
1939
1940 a->age_set == b->age_set &&
1941 a->age == b->age &&
1942
1943 a->mask_perms == b->mask_perms &&
1944
1945 a->keep_first_level == b->keep_first_level &&
1946
1947 a->major_minor == b->major_minor;
1948
1949 return true;
1950 }
1951
1952 static bool should_include_path(const char *path) {
1953 char **prefix;
1954
1955 STRV_FOREACH(prefix, arg_exclude_prefixes)
1956 if (path_startswith(path, *prefix)) {
1957 log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1958 path, *prefix);
1959 return false;
1960 }
1961
1962 STRV_FOREACH(prefix, arg_include_prefixes)
1963 if (path_startswith(path, *prefix)) {
1964 log_debug("Entry \"%s\" matches include prefix \"%s\".", path, *prefix);
1965 return true;
1966 }
1967
1968 /* no matches, so we should include this path only if we
1969 * have no whitelist at all */
1970 if (strv_isempty(arg_include_prefixes))
1971 return true;
1972
1973 log_debug("Entry \"%s\" does not match any include prefix, skipping.", path);
1974 return false;
1975 }
1976
1977 static int specifier_expansion_from_arg(Item *i) {
1978 _cleanup_free_ char *unescaped = NULL, *resolved = NULL;
1979 char **xattr;
1980 int r;
1981
1982 assert(i);
1983
1984 if (i->argument == NULL)
1985 return 0;
1986
1987 switch (i->type) {
1988 case COPY_FILES:
1989 case CREATE_SYMLINK:
1990 case CREATE_FILE:
1991 case TRUNCATE_FILE:
1992 case WRITE_FILE:
1993 r = cunescape(i->argument, 0, &unescaped);
1994 if (r < 0)
1995 return log_error_errno(r, "Failed to unescape parameter to write: %s", i->argument);
1996
1997 r = specifier_printf(unescaped, specifier_table, NULL, &resolved);
1998 if (r < 0)
1999 return r;
2000
2001 free_and_replace(i->argument, resolved);
2002 break;
2003
2004 case SET_XATTR:
2005 case RECURSIVE_SET_XATTR:
2006 assert(i->xattrs);
2007
2008 STRV_FOREACH (xattr, i->xattrs) {
2009 r = specifier_printf(*xattr, specifier_table, NULL, &resolved);
2010 if (r < 0)
2011 return r;
2012
2013 free_and_replace(*xattr, resolved);
2014 }
2015 break;
2016
2017 default:
2018 break;
2019 }
2020 return 0;
2021 }
2022
2023 static int parse_line(const char *fname, unsigned line, const char *buffer, bool *invalid_config) {
2024
2025 _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
2026 _cleanup_(item_free_contents) Item i = {};
2027 ItemArray *existing;
2028 OrderedHashmap *h;
2029 int r, pos;
2030 bool force = false, boot = false;
2031
2032 assert(fname);
2033 assert(line >= 1);
2034 assert(buffer);
2035
2036 r = extract_many_words(
2037 &buffer,
2038 NULL,
2039 EXTRACT_QUOTES,
2040 &action,
2041 &path,
2042 &mode,
2043 &user,
2044 &group,
2045 &age,
2046 NULL);
2047 if (r < 0) {
2048 if (IN_SET(r, -EINVAL, -EBADSLT))
2049 /* invalid quoting and such or an unknown specifier */
2050 *invalid_config = true;
2051 return log_error_errno(r, "[%s:%u] Failed to parse line: %m", fname, line);
2052 }
2053
2054 else if (r < 2) {
2055 *invalid_config = true;
2056 log_error("[%s:%u] Syntax error.", fname, line);
2057 return -EIO;
2058 }
2059
2060 if (!isempty(buffer) && !streq(buffer, "-")) {
2061 i.argument = strdup(buffer);
2062 if (!i.argument)
2063 return log_oom();
2064 }
2065
2066 if (isempty(action)) {
2067 *invalid_config = true;
2068 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
2069 return -EINVAL;
2070 }
2071
2072 for (pos = 1; action[pos]; pos++) {
2073 if (action[pos] == '!' && !boot)
2074 boot = true;
2075 else if (action[pos] == '+' && !force)
2076 force = true;
2077 else {
2078 *invalid_config = true;
2079 log_error("[%s:%u] Unknown modifiers in command '%s'",
2080 fname, line, action);
2081 return -EINVAL;
2082 }
2083 }
2084
2085 if (boot && !arg_boot) {
2086 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
2087 action, path);
2088 return 0;
2089 }
2090
2091 i.type = action[0];
2092 i.force = force;
2093
2094 r = specifier_printf(path, specifier_table, NULL, &i.path);
2095 if (r == -ENXIO)
2096 return log_unresolvable_specifier(fname, line);
2097 if (r < 0) {
2098 if (IN_SET(r, -EINVAL, -EBADSLT))
2099 *invalid_config = true;
2100 return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s", fname, line, path);
2101 }
2102
2103 switch (i.type) {
2104
2105 case CREATE_DIRECTORY:
2106 case CREATE_SUBVOLUME:
2107 case CREATE_SUBVOLUME_INHERIT_QUOTA:
2108 case CREATE_SUBVOLUME_NEW_QUOTA:
2109 case EMPTY_DIRECTORY:
2110 case TRUNCATE_DIRECTORY:
2111 case CREATE_FIFO:
2112 case IGNORE_PATH:
2113 case IGNORE_DIRECTORY_PATH:
2114 case REMOVE_PATH:
2115 case RECURSIVE_REMOVE_PATH:
2116 case ADJUST_MODE:
2117 case RELABEL_PATH:
2118 case RECURSIVE_RELABEL_PATH:
2119 if (i.argument)
2120 log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname, line, i.type);
2121
2122 break;
2123
2124 case CREATE_FILE:
2125 case TRUNCATE_FILE:
2126 break;
2127
2128 case CREATE_SYMLINK:
2129 if (!i.argument) {
2130 i.argument = strappend("/usr/share/factory/", i.path);
2131 if (!i.argument)
2132 return log_oom();
2133 }
2134 break;
2135
2136 case WRITE_FILE:
2137 if (!i.argument) {
2138 *invalid_config = true;
2139 log_error("[%s:%u] Write file requires argument.", fname, line);
2140 return -EBADMSG;
2141 }
2142 break;
2143
2144 case COPY_FILES:
2145 if (!i.argument) {
2146 i.argument = strappend("/usr/share/factory/", i.path);
2147 if (!i.argument)
2148 return log_oom();
2149 } else if (!path_is_absolute(i.argument)) {
2150 *invalid_config = true;
2151 log_error("[%s:%u] Source path is not absolute.", fname, line);
2152 return -EBADMSG;
2153 }
2154
2155 path_kill_slashes(i.argument);
2156 break;
2157
2158 case CREATE_CHAR_DEVICE:
2159 case CREATE_BLOCK_DEVICE: {
2160 unsigned major, minor;
2161
2162 if (!i.argument) {
2163 *invalid_config = true;
2164 log_error("[%s:%u] Device file requires argument.", fname, line);
2165 return -EBADMSG;
2166 }
2167
2168 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
2169 *invalid_config = true;
2170 log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
2171 return -EBADMSG;
2172 }
2173
2174 i.major_minor = makedev(major, minor);
2175 break;
2176 }
2177
2178 case SET_XATTR:
2179 case RECURSIVE_SET_XATTR:
2180 if (!i.argument) {
2181 *invalid_config = true;
2182 log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
2183 return -EBADMSG;
2184 }
2185 r = parse_xattrs_from_arg(&i);
2186 if (r < 0)
2187 return r;
2188 break;
2189
2190 case SET_ACL:
2191 case RECURSIVE_SET_ACL:
2192 if (!i.argument) {
2193 *invalid_config = true;
2194 log_error("[%s:%u] Set ACLs requires argument.", fname, line);
2195 return -EBADMSG;
2196 }
2197 r = parse_acls_from_arg(&i);
2198 if (r < 0)
2199 return r;
2200 break;
2201
2202 case SET_ATTRIBUTE:
2203 case RECURSIVE_SET_ATTRIBUTE:
2204 if (!i.argument) {
2205 *invalid_config = true;
2206 log_error("[%s:%u] Set file attribute requires argument.", fname, line);
2207 return -EBADMSG;
2208 }
2209 r = parse_attribute_from_arg(&i);
2210 if (IN_SET(r, -EINVAL, -EBADSLT))
2211 *invalid_config = true;
2212 if (r < 0)
2213 return r;
2214 break;
2215
2216 default:
2217 log_error("[%s:%u] Unknown command type '%c'.", fname, line, (char) i.type);
2218 *invalid_config = true;
2219 return -EBADMSG;
2220 }
2221
2222 if (!path_is_absolute(i.path)) {
2223 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
2224 *invalid_config = true;
2225 return -EBADMSG;
2226 }
2227
2228 path_kill_slashes(i.path);
2229
2230 if (!should_include_path(i.path))
2231 return 0;
2232
2233 r = specifier_expansion_from_arg(&i);
2234 if (r == -ENXIO)
2235 return log_unresolvable_specifier(fname, line);
2236 if (r < 0) {
2237 if (IN_SET(r, -EINVAL, -EBADSLT))
2238 *invalid_config = true;
2239 return log_error_errno(r, "[%s:%u] Failed to substitute specifiers in argument: %m",
2240 fname, line);
2241 }
2242
2243 if (arg_root) {
2244 char *p;
2245
2246 p = prefix_root(arg_root, i.path);
2247 if (!p)
2248 return log_oom();
2249
2250 free(i.path);
2251 i.path = p;
2252 }
2253
2254 if (!isempty(user) && !streq(user, "-")) {
2255 const char *u = user;
2256
2257 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
2258 if (r < 0) {
2259 *invalid_config = true;
2260 return log_error_errno(r, "[%s:%u] Unknown user '%s'.", fname, line, user);
2261 }
2262
2263 i.uid_set = true;
2264 }
2265
2266 if (!isempty(group) && !streq(group, "-")) {
2267 const char *g = group;
2268
2269 r = get_group_creds(&g, &i.gid);
2270 if (r < 0) {
2271 *invalid_config = true;
2272 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
2273 return r;
2274 }
2275
2276 i.gid_set = true;
2277 }
2278
2279 if (!isempty(mode) && !streq(mode, "-")) {
2280 const char *mm = mode;
2281 unsigned m;
2282
2283 if (*mm == '~') {
2284 i.mask_perms = true;
2285 mm++;
2286 }
2287
2288 if (parse_mode(mm, &m) < 0) {
2289 *invalid_config = true;
2290 log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
2291 return -EBADMSG;
2292 }
2293
2294 i.mode = m;
2295 i.mode_set = true;
2296 } else
2297 i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
2298
2299 if (!isempty(age) && !streq(age, "-")) {
2300 const char *a = age;
2301
2302 if (*a == '~') {
2303 i.keep_first_level = true;
2304 a++;
2305 }
2306
2307 if (parse_sec(a, &i.age) < 0) {
2308 *invalid_config = true;
2309 log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
2310 return -EBADMSG;
2311 }
2312
2313 i.age_set = true;
2314 }
2315
2316 h = needs_glob(i.type) ? globs : items;
2317
2318 existing = ordered_hashmap_get(h, i.path);
2319 if (existing) {
2320 unsigned n;
2321
2322 for (n = 0; n < existing->count; n++) {
2323 if (!item_compatible(existing->items + n, &i)) {
2324 log_notice("[%s:%u] Duplicate line for path \"%s\", ignoring.",
2325 fname, line, i.path);
2326 return 0;
2327 }
2328 }
2329 } else {
2330 existing = new0(ItemArray, 1);
2331 if (!existing)
2332 return log_oom();
2333
2334 r = ordered_hashmap_put(h, i.path, existing);
2335 if (r < 0)
2336 return log_oom();
2337 }
2338
2339 if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
2340 return log_oom();
2341
2342 memcpy(existing->items + existing->count++, &i, sizeof(i));
2343
2344 /* Sort item array, to enforce stable ordering of application */
2345 qsort_safe(existing->items, existing->count, sizeof(Item), item_compare);
2346
2347 zero(i);
2348 return 0;
2349 }
2350
2351 static void help(void) {
2352 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
2353 "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
2354 " -h --help Show this help\n"
2355 " --user Execute user configuration\n"
2356 " --version Show package version\n"
2357 " --create Create marked files/directories\n"
2358 " --clean Clean up marked directories\n"
2359 " --remove Remove marked files/directories\n"
2360 " --boot Execute actions only safe at boot\n"
2361 " --prefix=PATH Only apply rules with the specified prefix\n"
2362 " --exclude-prefix=PATH Ignore rules with the specified prefix\n"
2363 " --root=PATH Operate on an alternate filesystem root\n"
2364 " --replace=PATH Treat arguments as replacement for PATH\n"
2365 , program_invocation_short_name);
2366 }
2367
2368 static int parse_argv(int argc, char *argv[]) {
2369
2370 enum {
2371 ARG_VERSION = 0x100,
2372 ARG_USER,
2373 ARG_CREATE,
2374 ARG_CLEAN,
2375 ARG_REMOVE,
2376 ARG_BOOT,
2377 ARG_PREFIX,
2378 ARG_EXCLUDE_PREFIX,
2379 ARG_ROOT,
2380 ARG_REPLACE,
2381 };
2382
2383 static const struct option options[] = {
2384 { "help", no_argument, NULL, 'h' },
2385 { "user", no_argument, NULL, ARG_USER },
2386 { "version", no_argument, NULL, ARG_VERSION },
2387 { "create", no_argument, NULL, ARG_CREATE },
2388 { "clean", no_argument, NULL, ARG_CLEAN },
2389 { "remove", no_argument, NULL, ARG_REMOVE },
2390 { "boot", no_argument, NULL, ARG_BOOT },
2391 { "prefix", required_argument, NULL, ARG_PREFIX },
2392 { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
2393 { "root", required_argument, NULL, ARG_ROOT },
2394 { "replace", required_argument, NULL, ARG_REPLACE },
2395 {}
2396 };
2397
2398 int c, r;
2399
2400 assert(argc >= 0);
2401 assert(argv);
2402
2403 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
2404
2405 switch (c) {
2406
2407 case 'h':
2408 help();
2409 return 0;
2410
2411 case ARG_VERSION:
2412 return version();
2413
2414 case ARG_USER:
2415 arg_user = true;
2416 break;
2417
2418 case ARG_CREATE:
2419 arg_create = true;
2420 break;
2421
2422 case ARG_CLEAN:
2423 arg_clean = true;
2424 break;
2425
2426 case ARG_REMOVE:
2427 arg_remove = true;
2428 break;
2429
2430 case ARG_BOOT:
2431 arg_boot = true;
2432 break;
2433
2434 case ARG_PREFIX:
2435 if (strv_push(&arg_include_prefixes, optarg) < 0)
2436 return log_oom();
2437 break;
2438
2439 case ARG_EXCLUDE_PREFIX:
2440 if (strv_push(&arg_exclude_prefixes, optarg) < 0)
2441 return log_oom();
2442 break;
2443
2444 case ARG_ROOT:
2445 r = parse_path_argument_and_warn(optarg, true, &arg_root);
2446 if (r < 0)
2447 return r;
2448 break;
2449
2450 case ARG_REPLACE:
2451 if (!path_is_absolute(optarg) ||
2452 !endswith(optarg, ".conf")) {
2453 log_error("The argument to --replace= must an absolute path to a config file");
2454 return -EINVAL;
2455 }
2456
2457 arg_replace = optarg;
2458 break;
2459
2460 case '?':
2461 return -EINVAL;
2462
2463 default:
2464 assert_not_reached("Unhandled option");
2465 }
2466
2467 if (!arg_clean && !arg_create && !arg_remove) {
2468 log_error("You need to specify at least one of --clean, --create or --remove.");
2469 return -EINVAL;
2470 }
2471
2472 if (arg_replace && optind >= argc) {
2473 log_error("When --replace= is given, some configuration items must be specified");
2474 return -EINVAL;
2475 }
2476
2477 return 1;
2478 }
2479
2480 static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoent, bool *invalid_config) {
2481 _cleanup_fclose_ FILE *_f = NULL;
2482 FILE *f;
2483 char line[LINE_MAX];
2484 Iterator iterator;
2485 unsigned v = 0;
2486 Item *i;
2487 int r = 0;
2488
2489 assert(fn);
2490
2491 if (streq(fn, "-")) {
2492 log_debug("Reading config from stdin…");
2493 fn = "<stdin>";
2494 f = stdin;
2495 } else {
2496 r = search_and_fopen(fn, "re", arg_root, (const char**) config_dirs, &_f);
2497 if (r < 0) {
2498 if (ignore_enoent && r == -ENOENT) {
2499 log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn);
2500 return 0;
2501 }
2502
2503 return log_error_errno(r, "Failed to open '%s': %m", fn);
2504 }
2505 log_debug("Reading config file \"%s\"…", fn);
2506 f = _f;
2507 }
2508
2509 FOREACH_LINE(line, f, break) {
2510 char *l;
2511 int k;
2512 bool invalid_line = false;
2513
2514 v++;
2515
2516 l = strstrip(line);
2517 if (IN_SET(*l, 0, '#'))
2518 continue;
2519
2520 k = parse_line(fn, v, l, &invalid_line);
2521 if (k < 0) {
2522 if (invalid_line)
2523 /* Allow reporting with a special code if the caller requested this */
2524 *invalid_config = true;
2525 else if (r == 0)
2526 /* The first error becomes our return value */
2527 r = k;
2528 }
2529 }
2530
2531 /* we have to determine age parameter for each entry of type X */
2532 ORDERED_HASHMAP_FOREACH(i, globs, iterator) {
2533 Iterator iter;
2534 Item *j, *candidate_item = NULL;
2535
2536 if (i->type != IGNORE_DIRECTORY_PATH)
2537 continue;
2538
2539 ORDERED_HASHMAP_FOREACH(j, items, iter) {
2540 if (!IN_SET(j->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA))
2541 continue;
2542
2543 if (path_equal(j->path, i->path)) {
2544 candidate_item = j;
2545 break;
2546 }
2547
2548 if ((!candidate_item && path_startswith(i->path, j->path)) ||
2549 (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
2550 candidate_item = j;
2551 }
2552
2553 if (candidate_item && candidate_item->age_set) {
2554 i->age = candidate_item->age;
2555 i->age_set = true;
2556 }
2557 }
2558
2559 if (ferror(f)) {
2560 log_error_errno(errno, "Failed to read from file %s: %m", fn);
2561 if (r == 0)
2562 r = -EIO;
2563 }
2564
2565 return r;
2566 }
2567
2568 static int parse_arguments(char **config_dirs, char **args, bool *invalid_config) {
2569 char **arg;
2570 int r;
2571
2572 STRV_FOREACH(arg, args) {
2573 r = read_config_file(config_dirs, *arg, false, invalid_config);
2574 if (r < 0)
2575 return r;
2576 }
2577
2578 return 0;
2579 }
2580
2581 static int read_config_files(char **config_dirs, char **args, bool *invalid_config) {
2582 _cleanup_strv_free_ char **files = NULL;
2583 _cleanup_free_ char *p = NULL;
2584 char **f;
2585 int r;
2586
2587 r = conf_files_list_strv(&files, ".conf", arg_root, 0, (const char* const*) config_dirs);
2588 if (r < 0)
2589 return log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
2590
2591 if (arg_replace) {
2592 r = conf_files_insert(&files, arg_root, config_dirs, arg_replace);
2593 if (r < 0)
2594 return log_error_errno(r, "Failed to extend tmpfiles.d file list: %m");
2595
2596 p = path_join(arg_root, arg_replace, NULL);
2597 if (!p)
2598 return log_oom();
2599 }
2600
2601 STRV_FOREACH(f, files)
2602 if (p && path_equal(*f, p)) {
2603 log_debug("Parsing arguments at position \"%s\"…", *f);
2604
2605 r = parse_arguments(config_dirs, args, invalid_config);
2606 if (r < 0)
2607 return r;
2608 } else
2609 /* Just warn, ignore result otherwise.
2610 * read_config_file() has some debug output, so no need to print anything. */
2611 (void) read_config_file(config_dirs, *f, true, invalid_config);
2612
2613 return 0;
2614 }
2615
2616 int main(int argc, char *argv[]) {
2617 int r, k;
2618 ItemArray *a;
2619 Iterator iterator;
2620 _cleanup_strv_free_ char **config_dirs = NULL;
2621 bool invalid_config = false;
2622
2623 r = parse_argv(argc, argv);
2624 if (r <= 0)
2625 goto finish;
2626
2627 log_set_target(LOG_TARGET_AUTO);
2628 log_parse_environment();
2629 log_open();
2630
2631 umask(0022);
2632
2633 mac_selinux_init();
2634
2635 items = ordered_hashmap_new(&string_hash_ops);
2636 globs = ordered_hashmap_new(&string_hash_ops);
2637
2638 if (!items || !globs) {
2639 r = log_oom();
2640 goto finish;
2641 }
2642
2643 r = 0;
2644
2645 if (arg_user) {
2646 r = user_config_paths(&config_dirs);
2647 if (r < 0) {
2648 log_error_errno(r, "Failed to initialize configuration directory list: %m");
2649 goto finish;
2650 }
2651 } else {
2652 config_dirs = strv_split_nulstr(CONF_PATHS_NULSTR("tmpfiles.d"));
2653 if (!config_dirs) {
2654 r = log_oom();
2655 goto finish;
2656 }
2657 }
2658
2659 if (DEBUG_LOGGING) {
2660 _cleanup_free_ char *t = NULL;
2661
2662 t = strv_join(config_dirs, "\n\t");
2663 if (t)
2664 log_debug("Looking for configuration files in (higher priority first:\n\t%s", t);
2665 }
2666
2667 /* If command line arguments are specified along with --replace, read all
2668 * configuration files and insert the positional arguments at the specified
2669 * place. Otherwise, if command line arguments are specified, execute just
2670 * them, and finally, without --replace= or any positional arguments, just
2671 * read configuration and execute it.
2672 */
2673 if (arg_replace || optind >= argc)
2674 r = read_config_files(config_dirs, argv + optind, &invalid_config);
2675 else
2676 r = parse_arguments(config_dirs, argv + optind, &invalid_config);
2677 if (r < 0)
2678 goto finish;
2679
2680
2681
2682 /* The non-globbing ones usually create things, hence we apply
2683 * them first */
2684 ORDERED_HASHMAP_FOREACH(a, items, iterator) {
2685 k = process_item_array(a);
2686 if (k < 0 && r == 0)
2687 r = k;
2688 }
2689
2690 /* The globbing ones usually alter things, hence we apply them
2691 * second. */
2692 ORDERED_HASHMAP_FOREACH(a, globs, iterator) {
2693 k = process_item_array(a);
2694 if (k < 0 && r == 0)
2695 r = k;
2696 }
2697
2698 finish:
2699 ordered_hashmap_free_with_destructor(items, item_array_free);
2700 ordered_hashmap_free_with_destructor(globs, item_array_free);
2701
2702 free(arg_include_prefixes);
2703 free(arg_exclude_prefixes);
2704 free(arg_root);
2705
2706 set_free_free(unix_sockets);
2707
2708 mac_selinux_finish();
2709
2710 if (r < 0)
2711 return EXIT_FAILURE;
2712 else if (invalid_config)
2713 return EX_DATAERR;
2714 else
2715 return EXIT_SUCCESS;
2716 }