]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
f4c13ad7 RC |
2 | |
3 | #include <fcntl.h> | |
436e916e | 4 | #include <linux/magic.h> |
54c2459d | 5 | #include <sched.h> |
a70581ff | 6 | #include <unistd.h> |
f4c13ad7 RC |
7 | |
8 | #include "alloc-util.h" | |
d8d0da1f | 9 | #include "errno-list.h" |
f4c13ad7 | 10 | #include "fd-util.h" |
f4c13ad7 | 11 | #include "macro.h" |
049af8ad | 12 | #include "mountpoint-util.h" |
0cb8e3d1 | 13 | #include "namespace-util.h" |
846b3bd6 | 14 | #include "path-util.h" |
e4de7287 | 15 | #include "stat-util.h" |
b845894c | 16 | #include "tests.h" |
e4de7287 | 17 | #include "tmpfile-util.h" |
f4c13ad7 RC |
18 | |
19 | static void test_files_same(void) { | |
20 | _cleanup_close_ int fd = -1; | |
21 | char name[] = "/tmp/test-files_same.XXXXXX"; | |
22 | char name_alias[] = "/tmp/test-files_same.alias"; | |
23 | ||
b845894c ZJS |
24 | log_info("/* %s */", __func__); |
25 | ||
646853bd | 26 | fd = mkostemp_safe(name); |
f4c13ad7 RC |
27 | assert_se(fd >= 0); |
28 | assert_se(symlink(name, name_alias) >= 0); | |
29 | ||
e3f791a2 ZJS |
30 | assert_se(files_same(name, name, 0)); |
31 | assert_se(files_same(name, name, AT_SYMLINK_NOFOLLOW)); | |
32 | assert_se(files_same(name, name_alias, 0)); | |
33 | assert_se(!files_same(name, name_alias, AT_SYMLINK_NOFOLLOW)); | |
f4c13ad7 RC |
34 | |
35 | unlink(name); | |
36 | unlink(name_alias); | |
37 | } | |
38 | ||
39 | static void test_is_symlink(void) { | |
40 | char name[] = "/tmp/test-is_symlink.XXXXXX"; | |
41 | char name_link[] = "/tmp/test-is_symlink.link"; | |
42 | _cleanup_close_ int fd = -1; | |
43 | ||
b845894c ZJS |
44 | log_info("/* %s */", __func__); |
45 | ||
646853bd | 46 | fd = mkostemp_safe(name); |
f4c13ad7 RC |
47 | assert_se(fd >= 0); |
48 | assert_se(symlink(name, name_link) >= 0); | |
49 | ||
50 | assert_se(is_symlink(name) == 0); | |
51 | assert_se(is_symlink(name_link) == 1); | |
52 | assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0); | |
53 | ||
f4c13ad7 RC |
54 | unlink(name); |
55 | unlink(name_link); | |
56 | } | |
57 | ||
40fd52f2 | 58 | static void test_path_is_fs_type(void) { |
b845894c ZJS |
59 | log_info("/* %s */", __func__); |
60 | ||
cc390161 MP |
61 | /* run might not be a mount point in build chroots */ |
62 | if (path_is_mount_point("/run", NULL, AT_SYMLINK_FOLLOW) > 0) { | |
40fd52f2 ZJS |
63 | assert_se(path_is_fs_type("/run", TMPFS_MAGIC) > 0); |
64 | assert_se(path_is_fs_type("/run", BTRFS_SUPER_MAGIC) == 0); | |
cc390161 | 65 | } |
51db8fdb ZJS |
66 | if (path_is_mount_point("/proc", NULL, AT_SYMLINK_FOLLOW) > 0) { |
67 | assert_se(path_is_fs_type("/proc", PROC_SUPER_MAGIC) > 0); | |
68 | assert_se(path_is_fs_type("/proc", BTRFS_SUPER_MAGIC) == 0); | |
69 | } | |
40fd52f2 | 70 | assert_se(path_is_fs_type("/i-dont-exist", BTRFS_SUPER_MAGIC) == -ENOENT); |
436e916e LP |
71 | } |
72 | ||
73 | static void test_path_is_temporary_fs(void) { | |
d8d0da1f ZJS |
74 | const char *s; |
75 | int r; | |
76 | ||
b845894c ZJS |
77 | log_info("/* %s */", __func__); |
78 | ||
d8d0da1f ZJS |
79 | FOREACH_STRING(s, "/", "/run", "/sys", "/sys/", "/proc", "/i-dont-exist", "/var", "/var/lib") { |
80 | r = path_is_temporary_fs(s); | |
81 | ||
82 | log_info_errno(r, "path_is_temporary_fs(\"%s\"): %d, %s", | |
83 | s, r, r < 0 ? errno_to_name(r) : yes_no(r)); | |
84 | } | |
85 | ||
8dfc2f40 MP |
86 | /* run might not be a mount point in build chroots */ |
87 | if (path_is_mount_point("/run", NULL, AT_SYMLINK_FOLLOW) > 0) | |
88 | assert_se(path_is_temporary_fs("/run") > 0); | |
436e916e LP |
89 | assert_se(path_is_temporary_fs("/proc") == 0); |
90 | assert_se(path_is_temporary_fs("/i-dont-exist") == -ENOENT); | |
91 | } | |
92 | ||
d8d0da1f ZJS |
93 | static void test_path_is_read_only_fs(void) { |
94 | const char *s; | |
95 | int r; | |
96 | ||
97 | log_info("/* %s */", __func__); | |
98 | ||
99 | FOREACH_STRING(s, "/", "/run", "/sys", "/sys/", "/proc", "/i-dont-exist", "/var", "/var/lib") { | |
100 | r = path_is_read_only_fs(s); | |
101 | ||
102 | log_info_errno(r, "path_is_read_only_fs(\"%s\"): %d, %s", | |
103 | s, r, r < 0 ? errno_to_name(r) : yes_no(r)); | |
104 | } | |
105 | ||
106 | if (path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0) | |
107 | assert_se(IN_SET(path_is_read_only_fs("/sys"), 0, 1)); | |
108 | ||
109 | assert_se(path_is_read_only_fs("/proc") == 0); | |
110 | assert_se(path_is_read_only_fs("/i-dont-exist") == -ENOENT); | |
111 | } | |
112 | ||
54c2459d | 113 | static void test_fd_is_ns(void) { |
6619ad88 | 114 | _cleanup_close_ int fd = -1; |
b845894c ZJS |
115 | |
116 | log_info("/* %s */", __func__); | |
117 | ||
54c2459d XR |
118 | assert_se(fd_is_ns(STDIN_FILENO, CLONE_NEWNET) == 0); |
119 | assert_se(fd_is_ns(STDERR_FILENO, CLONE_NEWNET) == 0); | |
120 | assert_se(fd_is_ns(STDOUT_FILENO, CLONE_NEWNET) == 0); | |
6619ad88 | 121 | |
51db8fdb ZJS |
122 | fd = open("/proc/self/ns/mnt", O_CLOEXEC|O_RDONLY); |
123 | if (fd < 0) { | |
124 | assert_se(errno == ENOENT); | |
125 | log_notice("Path %s not found, skipping test", "/proc/self/ns/mnt"); | |
126 | return; | |
127 | } | |
128 | assert_se(fd >= 0); | |
54c2459d XR |
129 | assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 0, -EUCLEAN)); |
130 | fd = safe_close(fd); | |
131 | ||
132 | assert_se((fd = open("/proc/self/ns/ipc", O_CLOEXEC|O_RDONLY)) >= 0); | |
133 | assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWIPC), 1, -EUCLEAN)); | |
6619ad88 LP |
134 | fd = safe_close(fd); |
135 | ||
136 | assert_se((fd = open("/proc/self/ns/net", O_CLOEXEC|O_RDONLY)) >= 0); | |
54c2459d | 137 | assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 1, -EUCLEAN)); |
6619ad88 LP |
138 | } |
139 | ||
fb2430c6 | 140 | static void test_device_major_minor_valid(void) { |
b845894c ZJS |
141 | log_info("/* %s */", __func__); |
142 | ||
fb2430c6 LP |
143 | /* on glibc dev_t is 64bit, even though in the kernel it is only 32bit */ |
144 | assert_cc(sizeof(dev_t) == sizeof(uint64_t)); | |
145 | ||
146 | assert_se(DEVICE_MAJOR_VALID(0U)); | |
147 | assert_se(DEVICE_MINOR_VALID(0U)); | |
148 | ||
149 | assert_se(DEVICE_MAJOR_VALID(1U)); | |
150 | assert_se(DEVICE_MINOR_VALID(1U)); | |
151 | ||
152 | assert_se(!DEVICE_MAJOR_VALID(-1U)); | |
153 | assert_se(!DEVICE_MINOR_VALID(-1U)); | |
154 | ||
155 | assert_se(DEVICE_MAJOR_VALID(1U << 10)); | |
156 | assert_se(DEVICE_MINOR_VALID(1U << 10)); | |
157 | ||
158 | assert_se(DEVICE_MAJOR_VALID((1U << 12) - 1)); | |
159 | assert_se(DEVICE_MINOR_VALID((1U << 20) - 1)); | |
160 | ||
161 | assert_se(!DEVICE_MAJOR_VALID((1U << 12))); | |
162 | assert_se(!DEVICE_MINOR_VALID((1U << 20))); | |
163 | ||
164 | assert_se(!DEVICE_MAJOR_VALID(1U << 25)); | |
165 | assert_se(!DEVICE_MINOR_VALID(1U << 25)); | |
166 | ||
167 | assert_se(!DEVICE_MAJOR_VALID(UINT32_MAX)); | |
168 | assert_se(!DEVICE_MINOR_VALID(UINT32_MAX)); | |
169 | ||
170 | assert_se(!DEVICE_MAJOR_VALID(UINT64_MAX)); | |
171 | assert_se(!DEVICE_MINOR_VALID(UINT64_MAX)); | |
172 | ||
173 | assert_se(DEVICE_MAJOR_VALID(major(0))); | |
174 | assert_se(DEVICE_MINOR_VALID(minor(0))); | |
175 | } | |
176 | ||
846b3bd6 LP |
177 | static void test_device_path_make_canonical_one(const char *path) { |
178 | _cleanup_free_ char *resolved = NULL, *raw = NULL; | |
179 | struct stat st; | |
180 | dev_t devno; | |
181 | mode_t mode; | |
182 | int r; | |
183 | ||
b845894c ZJS |
184 | log_debug("> %s", path); |
185 | ||
51db8fdb | 186 | if (stat(path, &st) < 0) { |
f21b863e | 187 | assert_se(errno == ENOENT); |
51db8fdb ZJS |
188 | log_notice("Path %s not found, skipping test", path); |
189 | return; | |
190 | } | |
191 | ||
846b3bd6 | 192 | r = device_path_make_canonical(st.st_mode, st.st_rdev, &resolved); |
51db8fdb ZJS |
193 | if (r == -ENOENT) { |
194 | /* maybe /dev/char/x:y and /dev/block/x:y are missing in this test environment, because we | |
195 | * run in a container or so? */ | |
196 | log_notice("Device %s cannot be resolved, skipping test", path); | |
846b3bd6 | 197 | return; |
51db8fdb | 198 | } |
846b3bd6 LP |
199 | |
200 | assert_se(r >= 0); | |
201 | assert_se(path_equal(path, resolved)); | |
202 | ||
203 | assert_se(device_path_make_major_minor(st.st_mode, st.st_rdev, &raw) >= 0); | |
204 | assert_se(device_path_parse_major_minor(raw, &mode, &devno) >= 0); | |
205 | ||
206 | assert_se(st.st_rdev == devno); | |
207 | assert_se((st.st_mode & S_IFMT) == (mode & S_IFMT)); | |
208 | } | |
209 | ||
210 | static void test_device_path_make_canonical(void) { | |
b845894c | 211 | log_info("/* %s */", __func__); |
846b3bd6 LP |
212 | |
213 | test_device_path_make_canonical_one("/dev/null"); | |
214 | test_device_path_make_canonical_one("/dev/zero"); | |
215 | test_device_path_make_canonical_one("/dev/full"); | |
216 | test_device_path_make_canonical_one("/dev/random"); | |
217 | test_device_path_make_canonical_one("/dev/urandom"); | |
218 | test_device_path_make_canonical_one("/dev/tty"); | |
219 | ||
5b5ce629 | 220 | if (is_device_node("/run/systemd/inaccessible/blk") > 0) { |
846b3bd6 LP |
221 | test_device_path_make_canonical_one("/run/systemd/inaccessible/chr"); |
222 | test_device_path_make_canonical_one("/run/systemd/inaccessible/blk"); | |
223 | } | |
224 | } | |
225 | ||
f4c13ad7 | 226 | int main(int argc, char *argv[]) { |
b845894c ZJS |
227 | log_show_color(true); |
228 | test_setup_logging(LOG_INFO); | |
229 | ||
f4c13ad7 RC |
230 | test_files_same(); |
231 | test_is_symlink(); | |
40fd52f2 | 232 | test_path_is_fs_type(); |
436e916e | 233 | test_path_is_temporary_fs(); |
d8d0da1f | 234 | test_path_is_read_only_fs(); |
54c2459d | 235 | test_fd_is_ns(); |
fb2430c6 | 236 | test_device_major_minor_valid(); |
846b3bd6 | 237 | test_device_path_make_canonical(); |
f4c13ad7 RC |
238 | |
239 | return 0; | |
240 | } |