1 /* test20: fcntl() Author: Jan-Mark Wams (jms@cs.vu.nl) */ 2 3 /* Some things have to be checked for ``exec()'' call's. Therefor 4 ** there is a check routine called ``do_check()'' that will be 5 ** called if the first argument (``argv[0]'') equals ``DO CHECK.'' 6 ** Note that there is no way the shell (``/bin/sh'') will set 7 ** ``argv[0]'' to this funny value. (Unless we rename ``test20'' 8 ** to ``DO CHECK'' ;-) 9 */ 10 11 #include <sys/types.h> 12 #include <sys/stat.h> 13 #include <sys/wait.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 #include <string.h> 17 #include <fcntl.h> 18 #include <limits.h> 19 #include <errno.h> 20 #include <time.h> 21 #include <stdio.h> 22 23 int max_error = 4; 24 #include "common.h" 25 26 #define ITERATIONS 10 27 28 #define System(cmd) if (system(cmd) != 0) printf("``%s'' failed\n", cmd) 29 #define Chdir(dir) if (chdir(dir) != 0) printf("Can't goto %s\n", dir) 30 #define Stat(a,b) if (stat(a,b) != 0) printf("Can't stat %s\n", a) 31 32 33 int superuser; 34 35 void test20a(void); 36 void test20b(void); 37 void test20c(void); 38 void test20d(void); 39 int do_check(void); 40 41 char executable[1024]; 42 43 int main(int argc, char *argv[]) 44 { 45 int i; 46 47 sync(); 48 /* If we have to check things, call do_check(). */ 49 if (strcmp(argv[0], "DO CHECK") == 0) exit(do_check()); 50 51 /* Get the path of the executable. */ 52 strcpy(executable, "../"); 53 strcat(executable, argv[0]); 54 55 start(20); 56 superuser = (geteuid() == 0); 57 58 for (i = 0; i < ITERATIONS; i++) { 59 test20a(); 60 test20b(); 61 test20c(); 62 test20d(); 63 } 64 quit(); 65 66 return(-1); /* Unreachable */ 67 } 68 69 void test20a() 70 { /* Test normal operation. */ 71 subtest = 1; 72 System("rm -rf ../DIR_20/*"); 73 } 74 75 void test20b() 76 { 77 subtest = 2; 78 System("rm -rf ../DIR_20/*"); 79 } 80 81 void test20c() 82 { 83 subtest = 3; 84 System("rm -rf ../DIR_20/*"); 85 } 86 87 /* Open fds 3, 4, 5 and 6. Set FD_CLOEXEC on 5 and 6. Exclusively lock the 88 ** first 10 bytes of fd no. 3. Shared lock fd no. 7. Lock fd no. 8 after 89 ** the fork. Do a ``exec()'' call with a funny argv[0] and check the return 90 ** value. 91 */ 92 void test20d() 93 { /* Test locks with ``fork()'' and ``exec().'' */ 94 int fd3, fd4, fd5, fd6, fd7, fd8; 95 int stat_loc; 96 int do_check_retval; 97 char *argv[2]; 98 struct flock fl; 99 100 subtest = 4; 101 102 argv[0] = "DO CHECK"; 103 argv[1] = (char *) NULL; 104 105 fl.l_whence = SEEK_SET; 106 fl.l_start = 0; 107 fl.l_len = 10; 108 109 /* Make a dummy files and open them. */ 110 System("echo 'Great Balls Of Fire!' > file3"); 111 System("echo 'Great Balls Of Fire!' > file4"); 112 System("echo 'Great Balls Of Fire!' > file7"); 113 System("echo 'Great Balls Of Fire!' > file8"); 114 System("echo 'Great Balls Of Fire!' > file"); 115 if ((fd3 = open("file3", O_RDWR)) != 3) e(1); 116 if ((fd4 = open("file4", O_RDWR)) != 4) e(2); 117 if ((fd5 = open("file", O_RDWR)) != 5) e(3); 118 if ((fd6 = open("file", O_RDWR)) != 6) e(4); 119 if ((fd7 = open("file7", O_RDWR)) != 7) e(5); 120 if ((fd8 = open("file8", O_RDWR)) != 8) e(6); 121 122 /* Set FD_CLOEXEC flags on fd5 and fd6. */ 123 if (fcntl(fd5, F_SETFD, FD_CLOEXEC) == -1) e(7); 124 if (fcntl(fd6, F_SETFD, FD_CLOEXEC) == -1) e(8); 125 126 /* Lock the first ten bytes from fd3 (for writing). */ 127 fl.l_type = F_WRLCK; 128 if (fcntl(fd3, F_SETLK, &fl) == -1) e(9); 129 130 /* Lock (for reading) fd7. */ 131 fl.l_type = F_RDLCK; 132 if (fcntl(fd7, F_SETLK, &fl) == -1) e(10); 133 134 switch (fork()) { 135 case -1: printf("Can't fork\n"); break; 136 case 0: 137 alarm(20); 138 139 /* Lock fd8. */ 140 fl.l_type = F_WRLCK; 141 if (fcntl(fd8, F_SETLK, &fl) == -1) e(11); 142 143 /* Check the lock on fd3 and fd7. */ 144 fl.l_type = F_WRLCK; 145 if (fcntl(fd3, F_GETLK, &fl) == -1) e(12); 146 if (fl.l_type != F_WRLCK) e(13); 147 if (fl.l_pid != getppid()) e(14); 148 fl.l_type = F_WRLCK; 149 if (fcntl(fd7, F_GETLK, &fl) == -1) e(15); 150 if (fl.l_type != F_RDLCK) e(16); 151 if (fl.l_pid != getppid()) e(17); 152 153 /* Check FD_CLOEXEC flags. */ 154 if ((fcntl(fd3, F_GETFD) & FD_CLOEXEC) != 0) e(18); 155 if ((fcntl(fd4, F_GETFD) & FD_CLOEXEC) != 0) e(19); 156 if ((fcntl(fd5, F_GETFD) & FD_CLOEXEC) != FD_CLOEXEC) e(20); 157 if ((fcntl(fd6, F_GETFD) & FD_CLOEXEC) != FD_CLOEXEC) e(21); 158 if ((fcntl(fd7, F_GETFD) & FD_CLOEXEC) != 0) e(22); 159 if ((fcntl(fd8, F_GETFD) & FD_CLOEXEC) != 0) e(23); 160 161 execlp(executable + 3, "DO CHECK", (char *) NULL); 162 execlp(executable, "DO CHECK", (char *) NULL); 163 printf("Can't exec %s or %s\n", executable + 3, executable); 164 exit(0); 165 166 default: 167 wait(&stat_loc); 168 if (WIFSIGNALED(stat_loc)) e(24); /* Alarm? */ 169 if (WIFEXITED(stat_loc) == 0) { 170 errct=10000; 171 quit(); 172 } 173 } 174 175 /* Check the return value of do_check(). */ 176 do_check_retval = WEXITSTATUS(stat_loc); 177 if ((do_check_retval & 0x11) == 0x11) e(25); 178 if ((do_check_retval & 0x12) == 0x12) e(26); 179 if ((do_check_retval & 0x14) == 0x14) e(27); 180 if ((do_check_retval & 0x18) == 0x18) e(28); 181 if ((do_check_retval & 0x21) == 0x21) e(29); 182 if ((do_check_retval & 0x22) == 0x22) e(30); 183 if ((do_check_retval & 0x24) == 0x24) e(31); 184 if ((do_check_retval & 0x28) == 0x28) e(32); 185 if ((do_check_retval & 0x41) == 0x41) e(33); 186 if ((do_check_retval & 0x42) == 0x42) e(34); 187 if ((do_check_retval & 0x44) == 0x44) e(35); 188 if ((do_check_retval & 0x48) == 0x48) e(36); 189 if ((do_check_retval & 0x81) == 0x81) e(37); 190 if ((do_check_retval & 0x82) == 0x82) e(38); 191 if ((do_check_retval & 0x84) == 0x84) e(39); 192 if ((do_check_retval & 0x88) == 0x88) e(40); 193 194 switch (fork()) { 195 case -1: printf("Can't fork\n"); break; 196 case 0: 197 alarm(20); 198 199 /* Lock fd8. */ 200 fl.l_type = F_WRLCK; 201 if (fcntl(fd8, F_SETLK, &fl) == -1) e(41); 202 203 execvp(executable + 3, argv); 204 execvp(executable, argv); 205 printf("Can't exec %s or %s\n", executable + 3, executable); 206 exit(0); 207 208 default: 209 wait(&stat_loc); 210 if (WIFSIGNALED(stat_loc)) e(48); /* Alarm? */ 211 } 212 213 /* Check the return value of do_check(). */ 214 do_check_retval = WEXITSTATUS(stat_loc); 215 if ((do_check_retval & 0x11) == 0x11) e(49); 216 if ((do_check_retval & 0x12) == 0x12) e(50); 217 if ((do_check_retval & 0x14) == 0x14) e(51); 218 if ((do_check_retval & 0x18) == 0x18) e(52); 219 if ((do_check_retval & 0x21) == 0x21) e(53); 220 if ((do_check_retval & 0x22) == 0x22) e(54); 221 if ((do_check_retval & 0x24) == 0x24) e(55); 222 if ((do_check_retval & 0x28) == 0x28) e(56); 223 if ((do_check_retval & 0x41) == 0x41) e(57); 224 if ((do_check_retval & 0x42) == 0x42) e(58); 225 if ((do_check_retval & 0x44) == 0x44) e(59); 226 if ((do_check_retval & 0x48) == 0x48) e(60); 227 if ((do_check_retval & 0x81) == 0x81) e(61); 228 if ((do_check_retval & 0x82) == 0x82) e(62); 229 if ((do_check_retval & 0x84) == 0x84) e(63); 230 if ((do_check_retval & 0x88) == 0x88) e(64); 231 232 fl.l_type = F_UNLCK; 233 if (fcntl(fd3, F_SETLK, &fl) == -1) e(65); 234 if (fcntl(fd7, F_SETLK, &fl) == -1) e(66); 235 236 if (close(fd3) != 0) e(67); 237 if (close(fd4) != 0) e(68); 238 if (close(fd5) != 0) e(69); 239 if (close(fd6) != 0) e(70); 240 if (close(fd7) != 0) e(71); 241 if (close(fd8) != 0) e(72); 242 243 System("rm -f ../DIR_20/*\n"); 244 } 245 246 /* This routine checks that fds 0 through 4, 7 and 8 are open and the rest 247 ** is closed. It also checks if we can lock the first 10 bytes on fd no. 3 248 ** and 4. It should not be possible to lock fd no. 3, but it should be 249 ** possible to lock fd no. 4. See ``test20d()'' for usage of this routine. 250 */ 251 int do_check() 252 { 253 int i; 254 int retval = 0; 255 struct flock fl; 256 257 fl.l_whence = SEEK_SET; 258 fl.l_start = 0; 259 fl.l_len = 10; 260 261 /* All std.. are open. */ 262 if (fcntl(0, F_GETFD) == -1) retval |= 0x11; 263 if (fcntl(1, F_GETFD) == -1) retval |= 0x11; 264 if (fcntl(2, F_GETFD) == -1) retval |= 0x11; 265 266 /* Fd no. 3, 4, 7 and 8 are open. */ 267 if (fcntl(3, F_GETFD) == -1) retval |= 0x12; 268 if (fcntl(4, F_GETFD) == -1) retval |= 0x12; 269 if (fcntl(7, F_GETFD) == -1) retval |= 0x12; 270 271 /* Fd no. 5, 6 and 9 trough OPEN_MAX are closed. */ 272 if (fcntl(5, F_GETFD) != -1) retval |= 0x14; 273 if (fcntl(6, F_GETFD) != -1) retval |= 0x14; 274 for (i = 9; i < OPEN_MAX; i++) 275 if (fcntl(i, F_GETFD) != -1) retval |= 0x18; 276 277 #if 0 278 /* Fd no. 3 is WRLCKed. */ 279 fl.l_type = F_WRLCK; 280 if (fcntl(3, F_SETLK, &fl) != -1) retval |= 0x21; 281 if (errno != EACCES && errno != EAGAIN) retval |= 0x22; 282 fl.l_type = F_RDLCK; 283 if (fcntl(3, F_SETLK, &fl) != -1) retval |= 0x24; 284 if (errno != EACCES && errno != EAGAIN) retval |= 0x22; 285 fl.l_type = F_RDLCK; 286 if (fcntl(3, F_GETLK, &fl) == -1) retval |= 0x28; 287 if (fl.l_type != F_WRLCK) retval |= 0x28; 288 if (fl.l_pid != getpid()) retval |= 0x28; 289 fl.l_type = F_WRLCK; 290 if (fcntl(3, F_GETLK, &fl) == -1) retval |= 0x28; 291 if (fl.l_type != F_WRLCK) retval |= 0x28; 292 if (fl.l_pid != getpid()) retval |= 0x28; 293 #endif 294 295 /* Fd no. 4 is not locked. */ 296 fl.l_type = F_WRLCK; 297 if (fcntl(4, F_SETLK, &fl) == -1) retval |= 0x41; 298 if (fcntl(4, F_GETLK, &fl) == -1) retval |= 0x42; 299 #if 0 /* XXX - see test7.c */ 300 if (fl.l_type != F_WRLCK) retval |= 0x42; 301 if (fl.l_pid != getpid()) retval |= 0x42; 302 #endif /* 0 */ 303 304 /* Fd no. 8 is locked after the fork, it is ours. */ 305 fl.l_type = F_WRLCK; 306 if (fcntl(8, F_SETLK, &fl) == -1) retval |= 0x44; 307 if (fcntl(8, F_GETLK, &fl) == -1) retval |= 0x48; 308 #if 0 /* XXX - see test7.c */ 309 if (fl.l_type != F_WRLCK) retval |= 0x48; 310 if (fl.l_pid != getpid()) retval |= 0x48; 311 #endif /* 0 */ 312 313 #if 0 314 /* Fd no. 7 is RDLCKed. */ 315 fl.l_type = F_WRLCK; 316 if (fcntl(7, F_SETLK, &fl) != -1) retval |= 0x81; 317 if (errno != EACCES && errno != EAGAIN) retval |= 0x82; 318 fl.l_type = F_RDLCK; 319 if (fcntl(7, F_SETLK, &fl) == -1) retval |= 0x84; 320 fl.l_type = F_RDLCK; 321 if (fcntl(7, F_GETLK, &fl) == -1) retval |= 0x88; 322 if (fl.l_type != F_UNLCK) retval |= 0x88; 323 fl.l_type = F_WRLCK; 324 if (fcntl(7, F_GETLK, &fl) == -1) retval |= 0x88; 325 if (fl.l_type != F_RDLCK) retval |= 0x88; 326 if (fl.l_pid != getppid()) retval |= 0x88; 327 #endif 328 329 return retval; 330 } 331 332