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