]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
3577de7a | 2 | /*** |
96b2fb93 | 3 | Copyright © 2014 Kay Sievers |
3577de7a KS |
4 | ***/ |
5 | ||
6 | #include <errno.h> | |
a8fbdf54 TA |
7 | #include <fcntl.h> |
8 | #include <stdbool.h> | |
3577de7a | 9 | #include <stdlib.h> |
07630cea | 10 | #include <sys/stat.h> |
a8fbdf54 | 11 | #include <syslog.h> |
3577de7a KS |
12 | #include <unistd.h> |
13 | ||
b5efdb8a | 14 | #include "alloc-util.h" |
affb60b1 LP |
15 | #include "base-filesystem.h" |
16 | #include "fd-util.h" | |
3577de7a KS |
17 | #include "log.h" |
18 | #include "macro.h" | |
07630cea | 19 | #include "string-util.h" |
affb60b1 | 20 | #include "umask-util.h" |
ee104e11 | 21 | #include "user-util.h" |
3577de7a | 22 | #include "util.h" |
3577de7a KS |
23 | |
24 | typedef struct BaseFilesystem { | |
25 | const char *dir; | |
26 | mode_t mode; | |
27 | const char *target; | |
3fd165e5 | 28 | const char *exists; |
6404ecc8 | 29 | bool ignore_failure; |
3577de7a KS |
30 | } BaseFilesystem; |
31 | ||
32 | static const BaseFilesystem table[] = { | |
30d7c9c4 HH |
33 | { "bin", 0, "usr/bin\0", NULL }, |
34 | { "lib", 0, "usr/lib\0", NULL }, | |
6404ecc8 | 35 | { "root", 0755, NULL, NULL, true }, |
30d7c9c4 | 36 | { "sbin", 0, "usr/sbin\0", NULL }, |
03cfe0d5 LP |
37 | { "usr", 0755, NULL, NULL }, |
38 | { "var", 0755, NULL, NULL }, | |
39 | { "etc", 0755, NULL, NULL }, | |
10404d52 DH |
40 | { "proc", 0755, NULL, NULL, true }, |
41 | { "sys", 0755, NULL, NULL, true }, | |
42 | { "dev", 0755, NULL, NULL, true }, | |
e1ae9755 | 43 | #if defined(__i386__) || defined(__x86_64__) |
30d7c9c4 HH |
44 | { "lib64", 0, "usr/lib/x86_64-linux-gnu\0" |
45 | "usr/lib64\0", "ld-linux-x86-64.so.2" }, | |
e1ae9755 | 46 | #endif |
3577de7a KS |
47 | }; |
48 | ||
03cfe0d5 | 49 | int base_filesystem_create(const char *root, uid_t uid, gid_t gid) { |
3577de7a | 50 | _cleanup_close_ int fd = -1; |
a7f7d1bd | 51 | int r = 0; |
da6053d0 | 52 | size_t i; |
3577de7a KS |
53 | |
54 | fd = open(root, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); | |
4a62c710 MS |
55 | if (fd < 0) |
56 | return log_error_errno(errno, "Failed to open root file system: %m"); | |
3577de7a KS |
57 | |
58 | for (i = 0; i < ELEMENTSOF(table); i ++) { | |
6f4f8056 HH |
59 | if (faccessat(fd, table[i].dir, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) |
60 | continue; | |
61 | ||
3577de7a | 62 | if (table[i].target) { |
6dc2852c | 63 | const char *target = NULL, *s; |
e1ae9755 KS |
64 | |
65 | /* check if one of the targets exists */ | |
66 | NULSTR_FOREACH(s, table[i].target) { | |
67 | if (faccessat(fd, s, F_OK, AT_SYMLINK_NOFOLLOW) < 0) | |
68 | continue; | |
69 | ||
3fd165e5 KS |
70 | /* check if a specific file exists at the target path */ |
71 | if (table[i].exists) { | |
72 | _cleanup_free_ char *p = NULL; | |
73 | ||
605405c6 | 74 | p = strjoin(s, "/", table[i].exists); |
3fd165e5 KS |
75 | if (!p) |
76 | return log_oom(); | |
77 | ||
78 | if (faccessat(fd, p, F_OK, AT_SYMLINK_NOFOLLOW) < 0) | |
79 | continue; | |
80 | } | |
81 | ||
e1ae9755 KS |
82 | target = s; |
83 | break; | |
84 | } | |
85 | ||
86 | if (!target) | |
3577de7a KS |
87 | continue; |
88 | ||
e1ae9755 | 89 | r = symlinkat(target, fd, table[i].dir); |
4a62c710 MS |
90 | if (r < 0 && errno != EEXIST) |
91 | return log_error_errno(errno, "Failed to create symlink at %s/%s: %m", root, table[i].dir); | |
03cfe0d5 | 92 | |
289cb4d5 | 93 | if (uid_is_valid(uid) || gid_is_valid(gid)) { |
03cfe0d5 LP |
94 | if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0) |
95 | return log_error_errno(errno, "Failed to chown symlink at %s/%s: %m", root, table[i].dir); | |
96 | } | |
97 | ||
3577de7a KS |
98 | continue; |
99 | } | |
100 | ||
101 | RUN_WITH_UMASK(0000) | |
102 | r = mkdirat(fd, table[i].dir, table[i].mode); | |
6404ecc8 LP |
103 | if (r < 0 && errno != EEXIST) { |
104 | log_full_errno(table[i].ignore_failure ? LOG_DEBUG : LOG_ERR, errno, | |
105 | "Failed to create directory at %s/%s: %m", root, table[i].dir); | |
106 | ||
107 | if (!table[i].ignore_failure) | |
108 | return -errno; | |
d1d59eeb DH |
109 | |
110 | continue; | |
6404ecc8 | 111 | } |
03cfe0d5 LP |
112 | |
113 | if (uid != UID_INVALID || gid != UID_INVALID) { | |
114 | if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0) | |
115 | return log_error_errno(errno, "Failed to chown directory at %s/%s: %m", root, table[i].dir); | |
116 | } | |
3577de7a KS |
117 | } |
118 | ||
119 | return 0; | |
120 | } |