]>
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> |
7cff2b79 | 6 | #include <sys/eventfd.h> |
a70581ff | 7 | #include <unistd.h> |
f4c13ad7 RC |
8 | |
9 | #include "alloc-util.h" | |
d8d0da1f | 10 | #include "errno-list.h" |
f4c13ad7 | 11 | #include "fd-util.h" |
bfc569b0 | 12 | #include "fs-util.h" |
f4c13ad7 | 13 | #include "macro.h" |
049af8ad | 14 | #include "mountpoint-util.h" |
0cb8e3d1 | 15 | #include "namespace-util.h" |
846b3bd6 | 16 | #include "path-util.h" |
bfc569b0 | 17 | #include "rm-rf.h" |
e4de7287 | 18 | #include "stat-util.h" |
b845894c | 19 | #include "tests.h" |
e4de7287 | 20 | #include "tmpfile-util.h" |
f4c13ad7 | 21 | |
48542eac ZJS |
22 | TEST(null_or_empty_path) { |
23 | assert_se(null_or_empty_path("/dev/null") == 1); | |
24 | assert_se(null_or_empty_path("/dev/tty") == 1); /* We assume that any character device is "empty", bleh. */ | |
25 | assert_se(null_or_empty_path("../../../../../../../../../../../../../../../../../../../../dev/null") == 1); | |
26 | assert_se(null_or_empty_path("/proc/self/exe") == 0); | |
27 | assert_se(null_or_empty_path("/nosuchfileordir") == -ENOENT); | |
28 | } | |
29 | ||
30 | TEST(null_or_empty_path_with_root) { | |
31 | assert_se(null_or_empty_path_with_root("/dev/null", NULL) == 1); | |
32 | assert_se(null_or_empty_path_with_root("/dev/null", "/") == 1); | |
33 | assert_se(null_or_empty_path_with_root("/dev/null", "/.././../") == 1); | |
34 | assert_se(null_or_empty_path_with_root("/dev/null", "/.././..") == 1); | |
35 | assert_se(null_or_empty_path_with_root("../../../../../../../../../../../../../../../../../../../../dev/null", NULL) == 1); | |
36 | assert_se(null_or_empty_path_with_root("../../../../../../../../../../../../../../../../../../../../dev/null", "/") == 1); | |
37 | assert_se(null_or_empty_path_with_root("/proc/self/exe", NULL) == 0); | |
38 | assert_se(null_or_empty_path_with_root("/proc/self/exe", "/") == 0); | |
39 | assert_se(null_or_empty_path_with_root("/nosuchfileordir", NULL) == -ENOENT); | |
40 | assert_se(null_or_empty_path_with_root("/nosuchfileordir", "/.././../") == -ENOENT); | |
41 | assert_se(null_or_empty_path_with_root("/nosuchfileordir", "/.././..") == -ENOENT); | |
42 | assert_se(null_or_empty_path_with_root("/foobar/barbar/dev/null", "/foobar/barbar") == 1); | |
43 | assert_se(null_or_empty_path_with_root("/foobar/barbar/dev/null", "/foobar/barbar/") == 1); | |
44 | } | |
45 | ||
563e6846 | 46 | TEST(inode_same) { |
254d1313 | 47 | _cleanup_close_ int fd = -EBADF; |
596b44b1 DT |
48 | _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-files_same.XXXXXX"; |
49 | _cleanup_(unlink_tempfilep) char name_alias[] = "/tmp/test-files_same.alias"; | |
f4c13ad7 | 50 | |
646853bd | 51 | fd = mkostemp_safe(name); |
f4c13ad7 RC |
52 | assert_se(fd >= 0); |
53 | assert_se(symlink(name, name_alias) >= 0); | |
54 | ||
563e6846 LP |
55 | assert_se(inode_same(name, name, 0)); |
56 | assert_se(inode_same(name, name, AT_SYMLINK_NOFOLLOW)); | |
57 | assert_se(inode_same(name, name_alias, 0)); | |
58 | assert_se(!inode_same(name, name_alias, AT_SYMLINK_NOFOLLOW)); | |
f4c13ad7 RC |
59 | } |
60 | ||
4f7452a8 | 61 | TEST(is_symlink) { |
596b44b1 DT |
62 | _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-is_symlink.XXXXXX"; |
63 | _cleanup_(unlink_tempfilep) char name_link[] = "/tmp/test-is_symlink.link"; | |
254d1313 | 64 | _cleanup_close_ int fd = -EBADF; |
f4c13ad7 | 65 | |
646853bd | 66 | fd = mkostemp_safe(name); |
f4c13ad7 RC |
67 | assert_se(fd >= 0); |
68 | assert_se(symlink(name, name_link) >= 0); | |
69 | ||
70 | assert_se(is_symlink(name) == 0); | |
71 | assert_se(is_symlink(name_link) == 1); | |
72 | assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0); | |
f4c13ad7 RC |
73 | } |
74 | ||
4f7452a8 | 75 | TEST(path_is_fs_type) { |
cc390161 | 76 | /* run might not be a mount point in build chroots */ |
b409aacb | 77 | if (path_is_mount_point_full("/run", NULL, AT_SYMLINK_FOLLOW) > 0) { |
40fd52f2 ZJS |
78 | assert_se(path_is_fs_type("/run", TMPFS_MAGIC) > 0); |
79 | assert_se(path_is_fs_type("/run", BTRFS_SUPER_MAGIC) == 0); | |
cc390161 | 80 | } |
b409aacb | 81 | if (path_is_mount_point_full("/proc", NULL, AT_SYMLINK_FOLLOW) > 0) { |
51db8fdb ZJS |
82 | assert_se(path_is_fs_type("/proc", PROC_SUPER_MAGIC) > 0); |
83 | assert_se(path_is_fs_type("/proc", BTRFS_SUPER_MAGIC) == 0); | |
84 | } | |
40fd52f2 | 85 | assert_se(path_is_fs_type("/i-dont-exist", BTRFS_SUPER_MAGIC) == -ENOENT); |
436e916e LP |
86 | } |
87 | ||
4f7452a8 | 88 | TEST(path_is_temporary_fs) { |
d8d0da1f ZJS |
89 | int r; |
90 | ||
d8d0da1f ZJS |
91 | FOREACH_STRING(s, "/", "/run", "/sys", "/sys/", "/proc", "/i-dont-exist", "/var", "/var/lib") { |
92 | r = path_is_temporary_fs(s); | |
93 | ||
94 | log_info_errno(r, "path_is_temporary_fs(\"%s\"): %d, %s", | |
95 | s, r, r < 0 ? errno_to_name(r) : yes_no(r)); | |
96 | } | |
97 | ||
8dfc2f40 | 98 | /* run might not be a mount point in build chroots */ |
b409aacb | 99 | if (path_is_mount_point_full("/run", NULL, AT_SYMLINK_FOLLOW) > 0) |
8dfc2f40 | 100 | assert_se(path_is_temporary_fs("/run") > 0); |
436e916e LP |
101 | assert_se(path_is_temporary_fs("/proc") == 0); |
102 | assert_se(path_is_temporary_fs("/i-dont-exist") == -ENOENT); | |
103 | } | |
104 | ||
4f7452a8 | 105 | TEST(path_is_read_only_fs) { |
d8d0da1f ZJS |
106 | int r; |
107 | ||
d8d0da1f ZJS |
108 | FOREACH_STRING(s, "/", "/run", "/sys", "/sys/", "/proc", "/i-dont-exist", "/var", "/var/lib") { |
109 | r = path_is_read_only_fs(s); | |
110 | ||
111 | log_info_errno(r, "path_is_read_only_fs(\"%s\"): %d, %s", | |
112 | s, r, r < 0 ? errno_to_name(r) : yes_no(r)); | |
113 | } | |
114 | ||
b409aacb | 115 | if (path_is_mount_point_full("/sys", NULL, AT_SYMLINK_FOLLOW) > 0) |
d8d0da1f ZJS |
116 | assert_se(IN_SET(path_is_read_only_fs("/sys"), 0, 1)); |
117 | ||
118 | assert_se(path_is_read_only_fs("/proc") == 0); | |
119 | assert_se(path_is_read_only_fs("/i-dont-exist") == -ENOENT); | |
120 | } | |
121 | ||
4f7452a8 | 122 | TEST(fd_is_ns) { |
254d1313 | 123 | _cleanup_close_ int fd = -EBADF; |
b845894c | 124 | |
54c2459d XR |
125 | assert_se(fd_is_ns(STDIN_FILENO, CLONE_NEWNET) == 0); |
126 | assert_se(fd_is_ns(STDERR_FILENO, CLONE_NEWNET) == 0); | |
127 | assert_se(fd_is_ns(STDOUT_FILENO, CLONE_NEWNET) == 0); | |
6619ad88 | 128 | |
51db8fdb ZJS |
129 | fd = open("/proc/self/ns/mnt", O_CLOEXEC|O_RDONLY); |
130 | if (fd < 0) { | |
131 | assert_se(errno == ENOENT); | |
132 | log_notice("Path %s not found, skipping test", "/proc/self/ns/mnt"); | |
133 | return; | |
134 | } | |
135 | assert_se(fd >= 0); | |
54c2459d XR |
136 | assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 0, -EUCLEAN)); |
137 | fd = safe_close(fd); | |
138 | ||
139 | assert_se((fd = open("/proc/self/ns/ipc", O_CLOEXEC|O_RDONLY)) >= 0); | |
140 | assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWIPC), 1, -EUCLEAN)); | |
6619ad88 LP |
141 | fd = safe_close(fd); |
142 | ||
143 | assert_se((fd = open("/proc/self/ns/net", O_CLOEXEC|O_RDONLY)) >= 0); | |
54c2459d | 144 | assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 1, -EUCLEAN)); |
6619ad88 LP |
145 | } |
146 | ||
4f7452a8 | 147 | TEST(dir_is_empty) { |
bfc569b0 | 148 | _cleanup_(rm_rf_physical_and_freep) char *empty_dir = NULL; |
f470cb6d | 149 | _cleanup_free_ char *j = NULL, *jj = NULL, *jjj = NULL; |
bfc569b0 | 150 | |
db55bbf2 LP |
151 | assert_se(dir_is_empty_at(AT_FDCWD, "/proc", /* ignore_hidden_or_backup= */ true) == 0); |
152 | assert_se(dir_is_empty_at(AT_FDCWD, "/icertainlydontexistdoi", /* ignore_hidden_or_backup= */ true) == -ENOENT); | |
bfc569b0 LP |
153 | |
154 | assert_se(mkdtemp_malloc("/tmp/emptyXXXXXX", &empty_dir) >= 0); | |
db55bbf2 | 155 | assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) > 0); |
bfc569b0 LP |
156 | |
157 | j = path_join(empty_dir, "zzz"); | |
158 | assert_se(j); | |
159 | assert_se(touch(j) >= 0); | |
160 | ||
db55bbf2 | 161 | assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) == 0); |
bfc569b0 LP |
162 | |
163 | jj = path_join(empty_dir, "ppp"); | |
164 | assert_se(jj); | |
165 | assert_se(touch(jj) >= 0); | |
166 | ||
f470cb6d LB |
167 | jjj = path_join(empty_dir, ".qqq"); |
168 | assert_se(jjj); | |
169 | assert_se(touch(jjj) >= 0); | |
170 | ||
db55bbf2 LP |
171 | assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) == 0); |
172 | assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ false) == 0); | |
bfc569b0 | 173 | assert_se(unlink(j) >= 0); |
db55bbf2 LP |
174 | assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) == 0); |
175 | assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ false) == 0); | |
bfc569b0 | 176 | assert_se(unlink(jj) >= 0); |
db55bbf2 LP |
177 | assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) > 0); |
178 | assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ false) == 0); | |
f470cb6d | 179 | assert_se(unlink(jjj) >= 0); |
db55bbf2 LP |
180 | assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) > 0); |
181 | assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ false) > 0); | |
bfc569b0 LP |
182 | } |
183 | ||
cc037880 LP |
184 | TEST(inode_type_from_string) { |
185 | static const mode_t types[] = { | |
186 | S_IFREG, | |
187 | S_IFDIR, | |
188 | S_IFLNK, | |
189 | S_IFCHR, | |
190 | S_IFBLK, | |
191 | S_IFIFO, | |
192 | S_IFSOCK, | |
193 | }; | |
194 | ||
85471164 | 195 | FOREACH_ELEMENT(m, types) |
cc037880 LP |
196 | assert_se(inode_type_from_string(inode_type_to_string(*m)) == *m); |
197 | } | |
198 | ||
7cff2b79 LP |
199 | TEST(anonymous_inode) { |
200 | _cleanup_close_ int fd = -EBADF; | |
201 | ||
202 | fd = eventfd(0, EFD_CLOEXEC); | |
203 | assert_se(fd >= 0); | |
204 | ||
205 | /* Verify that we handle anonymous inodes correctly, i.e. those which have no file type */ | |
206 | ||
207 | struct stat st; | |
681e39c1 | 208 | ASSERT_OK_ERRNO(fstat(fd, &st)); |
7cff2b79 LP |
209 | assert_se((st.st_mode & S_IFMT) == 0); |
210 | ||
211 | assert_se(!inode_type_to_string(st.st_mode)); | |
212 | } | |
213 | ||
a6d0cf93 YW |
214 | TEST(fd_verify_linked) { |
215 | _cleanup_(rm_rf_physical_and_freep) char *t = NULL; | |
216 | _cleanup_close_ int tfd = -EBADF, fd = -EBADF; | |
217 | _cleanup_free_ char *p = NULL; | |
218 | ||
219 | tfd = mkdtemp_open(NULL, O_PATH, &t); | |
220 | assert_se(tfd >= 0); | |
221 | ||
222 | assert_se(p = path_join(t, "hoge")); | |
223 | assert_se(touch(p) >= 0); | |
224 | ||
225 | fd = open(p, O_CLOEXEC | O_PATH); | |
226 | assert_se(fd >= 0); | |
227 | ||
228 | assert_se(fd_verify_linked(fd) >= 0); | |
229 | assert_se(unlinkat(tfd, "hoge", 0) >= 0); | |
230 | assert_se(fd_verify_linked(fd) == -EIDRM); | |
231 | } | |
232 | ||
99839c7e LP |
233 | static int intro(void) { |
234 | log_show_color(true); | |
235 | return EXIT_SUCCESS; | |
236 | } | |
237 | ||
e85fdacc | 238 | DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro); |