xref: /minix/minix/tests/test58.c (revision 7f5f010b)
1 /* This tests the behavior of Minix when the current working dir (cwd) doesn't
2  * actually exist and we either:
3  *   - create a new file
4  *   - make a new directory
5  *   - make a special file (mknod)
6  *   - create a hard link
7  *   - create a symbolic link, or
8  *   - rename a file
9  * In each case, `a component of the path does not name an existing file', and
10  * the operation should fail with ENOENT. These tests should actually be
11  * distributed over the other tests that actually test the specific system
12  * calls.
13  */
14 
15 #include <stdio.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <sys/socket.h>
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 #include <sys/stat.h>
23 #include <sys/syslimits.h>
24 
25 int subtest = -1;
26 int max_error = 999;	/* Effectively no limit. This is necessary as this
27 			 * test tries to undo errors and should therefore not
28 			 * preemptively exit, as that would leave the FS
29 			 * in a corrupted state. */
30 
31 #include "common.h"
32 
33 #define TEST_PATH "a/b/c"
34 #define INTEGR_MSG "You might want to check fs integrity\n"
35 
36 void do_test(void);
37 
38 void do_test(void)
39 {
40   int r, fd;
41   int s[2];
42   char buf[1], testroot[PATH_MAX+1], renamebuf[PATH_MAX+1];
43 
44   subtest = 1;
45   if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) == -1) e(1);
46   if (system("mkdir -p " TEST_PATH) == -1) e(2);
47   if (realpath(".", testroot) == NULL) e(3);
48 
49   r = fork();
50   if (r == -1) e(4);
51   else if (r == 0) { /* Child */
52   	/* Change child's cwd to TEST_PATH */
53   	if (chdir(TEST_PATH) == -1) e(5);
54 
55 	/* Signal parent we're ready for the test */
56 	buf[0] = 'a';
57 	if (write(s[0], buf, sizeof(buf)) != sizeof(buf)) e(6);
58 
59 	/* Wait for parent to remove my cwd */
60 	if (read(s[0], buf, sizeof(buf)) != sizeof(buf)) e(7);
61 
62 	/* Try to create a file */
63 	if ((fd = open("testfile", O_RDWR | O_CREAT)) != -1) {
64 		e(8);
65 		/* Uh oh. We created a file?! Try to remove it. */
66 		(void) close(fd);
67 		if (unlink("testfile") != 0) {
68 			/* This is not good. We created a file, but we can
69 			 * never access it; we have a spurious inode.
70 			 */
71 			e(9);
72 			printf(INTEGR_MSG);
73 			exit(errct);
74 		}
75 	}
76 	if (errno != ENOENT) e(10);
77 
78 	/* Try to create a dir */
79 	errno = 0;
80 	if (mkdir("testdir", 0777) == 0) {
81 		e(11);
82 		/* Uh oh. This shouldn't have been possible. Try to undo. */
83 		if (rmdir("testdir") != 0) {
84 			/* Not good. */
85 			e(12);
86 			printf(INTEGR_MSG);
87 			exit(errct);
88 		}
89 	}
90 	if (errno != ENOENT) e(13);
91 
92 	/* Try to create a special file */
93 	errno = 0;
94 	if (mknod("testnode", 0777 | S_IFIFO, 0) == 0) {
95 		e(14);
96 		/* Impossible. Try to make it unhappen. */
97 		if (unlink("testnode") != 0) {
98 			/* Not good. */
99 			e(15);
100 			printf(INTEGR_MSG);
101 			exit(errct);
102 		}
103 	}
104 	if (errno != ENOENT) e(16);
105 
106 	/* Try to rename a file */
107 	errno = 0;
108 	/* First create a file in the test dir */
109 	snprintf(renamebuf, PATH_MAX, "%s/oldname", testroot);
110 	if ((fd = open(renamebuf, O_RDWR | O_CREAT)) == -1) e(17);
111 	if (close(fd) != 0) e(18);
112 
113 	/* Now try to rename that file to an entry in the current, non-existing
114 	 * working directory.
115 	 */
116 	if (rename(renamebuf, "testrename") == 0) {
117 		e(19);
118 		/* This shouldn't have been possible. Revert the name change.
119 		 */
120 		if (rename("testrename", renamebuf) != 0) {
121 			/* Failed */
122 			e(20);
123 			printf(INTEGR_MSG);
124 			exit(errct);
125 		}
126 	}
127 
128 	/* Try to create a hard link to that file */
129 	errno = 0;
130 	if (link(renamebuf, "testhlink") == 0) {
131 		e(21);
132 		/* Try to undo the hard link to prevent fs corruption. */
133 		if (unlink("testhlink") != 0) {
134 			/* Failed. */
135 			e(22);
136 			printf(INTEGR_MSG);
137 			exit(errct);
138 		}
139 	}
140 	if (errno != ENOENT) e(23);
141 
142 	/* Try to create a symlink */
143 	errno = 0;
144 	if (symlink(testroot, "testslink") == 0) {
145 		e(24);
146 		/* Try to remove the symlink to prevent fs corruption. */
147 		if (unlink("testslink") != 0) {
148 			/* Failed. */
149 			e(25);
150 			printf(INTEGR_MSG);
151 			exit(errct);
152 		}
153 	}
154 	if (errno != ENOENT) e(26);
155 
156 	exit(errct);
157   } else { /* Parent */
158   	int status;
159 
160   	/* Wait for the child to enter the TEST_PATH dir */
161   	if (read(s[1], buf, sizeof(buf)) != sizeof(buf)) e(27);
162 
163   	/* Delete TEST_PATH */
164   	if (rmdir(TEST_PATH) != 0) e(28);
165 
166   	/* Tell child we removed its cwd */
167   	buf[0] = 'b';
168   	if (write(s[1], buf, sizeof(buf)) != sizeof(buf)) e(29);
169 
170   	wait(&status);
171   	errct += WEXITSTATUS(status);	/* Count errors */
172   }
173 }
174 
175 int main(int argc, char* argv[])
176 {
177   start(58);
178   do_test();
179   quit();
180   return(-1);	/* Unreachable */
181 }
182 
183 
184