use oxpcie only if enabled to avoid baud bottleneck of uart.
[minix.git] / test / test43.c
blob0e4d509ab5dadc0744f2c5428dcb28b6f847fe9c
1 /* Tests for MINIX3 realpath(3) - by Erik van der Kouwe */
2 #define _POSIX_SOURCE 1
3 #include <assert.h>
4 #include <dirent.h>
5 #include <errno.h>
6 #include <libgen.h>
7 #include <limits.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
14 #define MAX_ERROR 4
16 static int errct = 0;
17 static const char *executable, *subtest;
19 #define ERR (e(__LINE__))
21 static void e(int n)
23 printf("File %s, error line %d, errno %d: %s\n",
24 subtest, n, errno, strerror(errno));
26 if (errct++ > MAX_ERROR)
28 printf("Too many errors; test aborted\n");
29 exit(1);
33 static void quit(void)
35 if (errct == 0)
37 printf("ok\n");
38 exit(0);
40 else
42 printf("%d errors\n", errct);
43 exit(1);
47 static char *remove_last_path_component(char *path)
49 char *current, *last;
51 assert(path);
53 /* find last slash */
54 last = NULL;
55 for (current = path; *current; current++)
56 if (*current == '/')
57 last = current;
59 /* check path component */
60 if (last)
62 if (strcmp(last + 1, ".") == 0) ERR;
63 if (strcmp(last + 1, "..") == 0) ERR;
66 /* if only root path slash, we are done */
67 if (last <= path)
68 return NULL;
70 /* chop off last path component */
71 *last = 0;
72 return path;
75 static int check_path_components(const char *path)
77 char buffer[PATH_MAX + 1], *bufferpos;
78 struct stat statbuf;
80 assert(strlen(path) < sizeof(buffer));
82 bufferpos = buffer;
83 while (*path)
85 /* copy next path segment */
86 do
88 *(bufferpos++) = *(path++);
89 } while (*path && *path != '/');
90 *bufferpos = 0;
92 /*
93 * is this a valid path segment? if not, return errno.
94 * one exception: the last path component need not exist
96 if (stat(buffer, &statbuf) < 0 &&
97 (*path || errno != ENOENT))
98 return errno;
101 return 0;
104 static void check_realpath(const char *path, int expected_errno)
106 char buffer[PATH_MAX + 1], *resolved_path;
107 int expected_errno2;
108 struct stat statbuf[2];
110 assert(path);
112 /* any errors in the path that realpath should report? */
113 expected_errno2 = check_path_components(path);
115 /* run realpath */
116 subtest = path;
117 errno = 0;
118 resolved_path = realpath(path, buffer);
120 /* do we get errors when expected? */
121 if (expected_errno || expected_errno2)
123 if (resolved_path) ERR;
124 if (errno != expected_errno && errno != expected_errno2) ERR;
125 subtest = NULL;
126 return;
129 /* do we get success when expected? */
130 if (!resolved_path)
132 ERR;
133 subtest = NULL;
134 return;
136 errno = 0;
138 /* do the paths point to the same file? (only check if exists) */
139 if (stat(path, &statbuf[0]) < 0)
141 if (errno != ENOENT) { ERR; return; }
143 else
145 if (stat(resolved_path, &statbuf[1]) < 0) { ERR; return; }
146 if (statbuf[0].st_dev != statbuf[1].st_dev) ERR;
147 if (statbuf[0].st_ino != statbuf[1].st_ino) ERR;
150 /* is the path absolute? */
151 if (resolved_path[0] != '/') ERR;
153 /* is each path element allowable? */
154 while (remove_last_path_component(resolved_path))
156 /* not a symlink? */
157 if (lstat(resolved_path, &statbuf[1]) < 0) { ERR; return; }
158 if ((statbuf[1].st_mode & S_IFMT) != S_IFDIR) ERR;
160 subtest = NULL;
163 static void check_realpath_step_by_step(const char *path, int expected_errno)
165 char buffer[PATH_MAX + 1];
166 const char *path_current;
168 assert(path);
169 assert(strlen(path) < sizeof(buffer));
171 /* check the absolute path */
172 check_realpath(path, expected_errno);
174 /* try with different CWDs */
175 for (path_current = path; *path_current; path_current++)
176 if (path_current[0] == '/' && path_current[1])
178 /* set CWD */
179 memcpy(buffer, path, path_current - path + 1);
180 buffer[path_current - path + 1] = 0;
181 if (chdir(buffer) < 0) { ERR; continue; }
183 /* perform test */
184 check_realpath(path_current + 1, expected_errno);
188 static char *pathncat(char *buffer, size_t size, const char *path1, const char *path2)
190 size_t len1, len2, lenslash;
192 assert(buffer);
193 assert(path1);
194 assert(path2);
196 /* check whether it fits */
197 len1 = strlen(path1);
198 len2 = strlen(path2);
199 lenslash = (len1 > 0 && path1[len1 - 1] == '/') ? 0 : 1;
200 if (len1 >= size || /* check individual components to avoid overflow */
201 len2 >= size ||
202 len1 + len2 + lenslash >= size)
203 return NULL;
205 /* perform the copy */
206 memcpy(buffer, path1, len1);
207 if (lenslash)
208 buffer[len1] = '/';
210 memcpy(buffer + len1 + lenslash, path2, len2 + 1);
211 return buffer;
214 static void check_realpath_recurse(const char *path, int depth)
216 DIR *dir;
217 struct dirent *dirent;
218 char pathsub[PATH_MAX + 1];
220 /* check with the path itself */
221 check_realpath_step_by_step(path, 0);
223 /* don't go too deep */
224 if (depth < 1)
225 return;
227 /* loop through subdirectories (including . and ..) */
228 if (!(dir = opendir(path)))
230 if (errno != ENOENT && errno != ENOTDIR)
231 ERR;
232 return;
234 while (dirent = readdir(dir))
236 /* build path */
237 if (!pathncat(pathsub, sizeof(pathsub), path, dirent->d_name))
239 ERR;
240 continue;
243 /* check path */
244 check_realpath_recurse(pathsub, depth - 1);
246 if (closedir(dir) < 0) ERR;
249 #define PATH_DEPTH 4
250 #define PATH_BASE "/t43"
251 #define L(x) PATH_BASE "/link_" #x ".tmp"
253 static char basepath[PATH_MAX + 1];
255 static char *addbasepath(char *buffer, const char *path)
257 size_t basepathlen, pathlen;
258 int slashlen;
260 /* assumption: both start with slash and neither end with it */
261 assert(basepath[0] == '/');
262 assert(basepath[strlen(basepath) - 1] != '/');
263 assert(buffer);
264 assert(path);
265 assert(path[0] == '/');
267 /* check result length */
268 basepathlen = strlen(basepath);
269 pathlen = strlen(path);
270 if (basepathlen + pathlen > PATH_MAX)
272 printf("path too long\n");
273 exit(-1);
276 /* concatenate base path and path */
277 memcpy(buffer, basepath, basepathlen);
278 memcpy(buffer + basepathlen, path, pathlen + 1);
279 return buffer;
282 static void cleanup(const char *path)
284 DIR *dir;
285 struct dirent *dirent;
286 char pathsub[PATH_MAX + 1];
287 struct stat statbuf;
289 /* determine file type, avoid following links */
290 if (lstat(path, &statbuf) < 0)
292 if (errno != ENOENT) ERR;
293 return;
296 /* only recursively process directories (NOT symlinks!) */
297 if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
299 if (unlink(path) < 0) ERR;
300 return;
303 /* loop through subdirectories (excluding . and ..) */
304 if (!(dir = opendir(path)))
306 ERR;
307 return;
309 while (dirent = readdir(dir))
311 /* ignore current and parent directories */
312 if (strcmp(dirent->d_name, ".") == 0 ||
313 strcmp(dirent->d_name, "..") == 0)
314 continue;
316 /* build path */
317 if (!pathncat(pathsub, sizeof(pathsub), path, dirent->d_name))
319 ERR;
320 continue;
323 /* delete path */
324 cleanup(pathsub);
326 if (closedir(dir) < 0) ERR;
328 /* remove the (now empty) directory itself */
329 if (rmdir(path) < 0) ERR;
332 static void test_dirname(const char *path, const char *exp)
334 char buffer[PATH_MAX];
335 int i, j;
336 size_t pathlen = strlen(path);
337 char *pathout;
339 assert(pathlen + 3 < PATH_MAX);
341 /* try with no, one or two trailing slashes */
342 for (i = 0; i < 3; i++)
344 /* no trailing slashes for empty string */
345 if (pathlen < 1 && i > 0)
346 continue;
348 /* prepare buffer */
349 strcpy(buffer, path);
350 for (j = 0; j < i; j++)
351 buffer[pathlen + j] = '/';
353 buffer[pathlen + i] = 0;
355 /* perform test */
356 pathout = dirname(buffer);
357 if (strcmp(pathout, exp) != 0)
358 ERR;
362 int main(int argc, char **argv)
364 char buffer1[PATH_MAX + 1], buffer2[PATH_MAX + 1];
366 /* initialize */
367 printf("Test 43 ");
368 fflush(stdout);
369 executable = argv[0];
370 getcwd(basepath, sizeof(basepath));
371 cleanup(addbasepath(buffer1, PATH_BASE));
373 /* prepare some symlinks to make it more difficult */
374 if (mkdir(addbasepath(buffer1, PATH_BASE), S_IRWXU) < 0) ERR;
375 if (symlink("/", addbasepath(buffer1, L(1))) < 0) ERR;
376 if (symlink(basepath, addbasepath(buffer1, L(2))) < 0) ERR;
378 /* perform some tests */
379 check_realpath_recurse(basepath, PATH_DEPTH);
381 /* now try with recursive symlinks */
382 if (symlink(addbasepath(buffer1, L(3)), addbasepath(buffer2, L(3))) < 0) ERR;
383 if (symlink(addbasepath(buffer1, L(5)), addbasepath(buffer2, L(4))) < 0) ERR;
384 if (symlink(addbasepath(buffer1, L(4)), addbasepath(buffer2, L(5))) < 0) ERR;
385 check_realpath_step_by_step(addbasepath(buffer1, L(3)), ELOOP);
386 check_realpath_step_by_step(addbasepath(buffer1, L(4)), ELOOP);
387 check_realpath_step_by_step(addbasepath(buffer1, L(5)), ELOOP);
389 /* delete the symlinks */
390 cleanup(addbasepath(buffer1, PATH_BASE));
392 /* also test dirname */
393 test_dirname("", ".");
394 test_dirname(".", ".");
395 test_dirname("..", ".");
396 test_dirname("x", ".");
397 test_dirname("xy", ".");
398 test_dirname("x/y", "x");
399 test_dirname("xy/z", "xy");
400 test_dirname("x/yz", "x");
401 test_dirname("ab/cd", "ab");
402 test_dirname("x//y", "x");
403 test_dirname("xy//z", "xy");
404 test_dirname("x//yz", "x");
405 test_dirname("ab//cd", "ab");
406 test_dirname("/", "/");
407 test_dirname("/x", "/");
408 test_dirname("/xy", "/");
409 test_dirname("/x/y", "/x");
410 test_dirname("/xy/z", "/xy");
411 test_dirname("/x/yz", "/x");
412 test_dirname("/ab/cd", "/ab");
413 test_dirname("/x//y", "/x");
414 test_dirname("/xy//z", "/xy");
415 test_dirname("/x//yz", "/x");
416 test_dirname("/ab//cd", "/ab");
417 test_dirname("/usr/src", "/usr");
418 test_dirname("/usr/src/test", "/usr/src");
419 test_dirname("usr/src", "usr");
420 test_dirname("usr/src/test", "usr/src");
422 /* done */
423 quit();
424 return(-1); /* impossible */