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