From: Ben Gras Date: Mon, 19 Sep 2005 13:44:31 +0000 (+0000) Subject: 8<->37 X-Git-Tag: v3.1.0~53 X-Git-Url: http://zhaoyanbai.com/repos/icons/apache_pb.png?a=commitdiff_plain;h=d969f7b4bcab5ba455d8c3d6776e778b6608d813;p=minix.git 8<->37 29<->38 20<->39 --- diff --git a/test/run b/test/run index 1f47801f7..9fdb79716 100755 --- a/test/run +++ b/test/run @@ -13,7 +13,8 @@ badones= # list of tests that failed # Print test welcome message clr echo "Running POSIX compliance test suite. There are 42 tests in total." -echo "These tests may take more than 20 minutes, even on fast systems." +echo "The last few tests may take up to 15 minutes each, even on fast" +echo "systems." echo " " # Run all the tests, keeping track of who failed. diff --git a/test/test20.c b/test/test20.c index 9d2f90b6a..3fb628402 100644 --- a/test/test20.c +++ b/test/test20.c @@ -1,702 +1,375 @@ -/* POSIX test program (20). Author: Andy Tanenbaum */ - -/* The following POSIX calls are tested: - * - * opendir() - * readdir() - * rewinddir() - * closedir() - * chdir() - * getcwd() - */ +/* test20: fcntl() Author: Jan-Mark Wams (jms@cs.vu.nl) */ + +/* Some things have to be checked for ``exec()'' call's. Therefor +** there is a check routine called ``do_check()'' that will be +** called if the first argument (``argv[0]'') equals ``DO CHECK.'' +** Note that there is no way the shell (``/bin/sh'') will set +** ``argv[0]'' to this funny value. (Unless we rename ``test20'' +** to ``DO CHECK'' ;-) +*/ #include #include -#include -#include -#include -#include +#include #include +#include #include +#include +#include +#include #include -#include -#include #include -#define DIR_NULL (DIR*) NULL -#define ITERATIONS 3 /* LINK_MAX is high, so time consuming */ -#define MAX_FD 100 /* must be large enough to cause error */ -#define BUF_SIZE PATH_MAX+20 -#define ERR_CODE -1 /* error return */ -#define RD_BUF 200 -#define MAX_ERROR 4 +#define MAX_ERROR 4 +#define ITERATIONS 10 -char str[] = {"The time has come the walrus said to talk of many things.\n"}; -char str2[] = {"Of ships and shoes and sealing wax, of cabbages and kings.\n"}; -char str3[] = {"Of why the sea is boiling hot and whether pigs have wings\n"}; +#define System(cmd) if (system(cmd) != 0) printf("``%s'' failed\n", cmd) +#define Chdir(dir) if (chdir(dir) != 0) printf("Can't goto %s\n", dir) +#define Stat(a,b) if (stat(a,b) != 0) printf("Can't stat %s\n", a) -int subtest, errct; +int errct = 0; +int subtest = 1; +int superuser; +char MaxName[NAME_MAX + 1]; /* Name of maximum length */ +char MaxPath[PATH_MAX]; /* Same for path */ +char ToLongName[NAME_MAX + 2]; /* Name of maximum +1 length */ +char ToLongPath[PATH_MAX + 1]; /* Same for path, both too long */ -_PROTOTYPE(int main, (int argc, char *argv [])); +_PROTOTYPE(void main, (int argc, char *argv[])); _PROTOTYPE(void test20a, (void)); -_PROTOTYPE(void checkdir, (DIR *dirp, int t)); _PROTOTYPE(void test20b, (void)); _PROTOTYPE(void test20c, (void)); _PROTOTYPE(void test20d, (void)); -_PROTOTYPE(void test20e, (void)); -_PROTOTYPE(void test20f, (void)); -_PROTOTYPE(void test20g, (void)); -_PROTOTYPE(void test20h, (void)); -_PROTOTYPE(void test20i, (void)); -_PROTOTYPE(void test20j, (void)); -_PROTOTYPE(void e, (int n)); +_PROTOTYPE(int do_check, (void)); +_PROTOTYPE(void makelongnames, (void)); +_PROTOTYPE(void e, (int number)); _PROTOTYPE(void quit, (void)); -int main(argc, argv) +char executable[1024]; + +void main(argc, argv) int argc; char *argv[]; { - int i, m = 0xFFFF; sync(); - if (geteuid() == 0 || getuid() == 0) { - printf("Test 20 cannot run as root; test aborted\n"); - exit(1); - } - if (argc == 2) m = atoi(argv[1]); + + /* If we have to check things, call do_check(). */ + if (strcmp(argv[0], "DO CHECK") == 0) exit(do_check()); + + /* Get the path of the executable. */ + strcpy(executable, "../"); + strcat(executable, argv[0]); + printf("Test 20 "); fflush(stdout); - - system("rm -rf DIR_20; mkdir DIR_20"); - chdir("DIR_20"); + System("rm -rf DIR_20; mkdir DIR_20"); + Chdir("DIR_20"); + makelongnames(); + superuser = (geteuid() == 0); for (i = 0; i < ITERATIONS; i++) { - if (m & 00001) test20a(); /* test for correct operation */ - if (m & 00002) test20b(); /* test general error handling */ - if (m & 00004) test20c(); /* test for EMFILE error */ - if (m & 00010) test20d(); /* test chdir() and getcwd() */ - if (m & 00020) test20e(); /* test open() */ - if (m & 00040) test20f(); /* test umask(), stat(), fstat() */ - if (m & 00100) test20g(); /* test link() and unlink() */ - if (m & 00200) test20h(); /* test access() */ - if (m & 00400) test20i(); /* test chmod() and chown() */ - if (m & 01000) test20j(); /* test utime() */ + test20a(); + test20b(); + test20c(); + test20d(); } quit(); - return(-1); /* impossible */ } void test20a() -{ -/* Subtest 1. Correct operation */ - - int f1, f2, f3, f4, f5; - DIR *dirp; - - /* Remove any residue of previous tests. */ +{ /* Test normal operation. */ subtest = 1; - - system("rm -rf foo"); - - /* Create a directory foo with 5 files in it. */ - mkdir("foo", 0777); - if ((f1 = creat("foo/f1", 0666)) < 0) e(1); - if ((f2 = creat("foo/f2", 0666)) < 0) e(2); - if ((f3 = creat("foo/f3", 0666)) < 0) e(3); - if ((f4 = creat("foo/f4", 0666)) < 0) e(4); - if ((f5 = creat("foo/f5", 0666)) < 0) e(5); - - /* Now remove 2 files to create holes in the directory. */ - if (unlink("foo/f2") < 0) e(6); - if (unlink("foo/f4") < 0) e(7); - - /* Close the files. */ - close(f1); - close(f2); - close(f3); - close(f4); - close(f5); - - /* Open the directory. */ - dirp = opendir("./foo"); - if (dirp == DIR_NULL) e(6); - - /* Read the 5 files from it. */ - checkdir(dirp, 2); - - /* Rewind dir and test again. */ - rewinddir(dirp); - checkdir(dirp, 3); - - /* We're done. Close the directory stream. */ - if (closedir(dirp) < 0) e(7); - - /* Remove dir for next time. */ - system("rm -rf foo"); -} - -void checkdir(dirp, t) -DIR *dirp; /* poinrter to directory stream */ -int t; /* subtest number to use */ -{ - - int i, f1, f2, f3, f4, f5, dot, dotdot, subt; - struct dirent *d; - char *s; - - /* Save subtest number */ - subt = subtest; - subtest = t; - - /* Clear the counters. */ - f1 = 0; - f2 = 0; - f3 = 0; - f4 = 0; - f5 = 0; - dot = 0; - dotdot = 0; - - /* Read the directory. It should contain 5 entries, ".", ".." and 3 - * files. */ - for (i = 0; i < 5; i++) { - d = readdir(dirp); - if (d == (struct dirent *) NULL) { - e(1); - subtest = subt; /* restore subtest number */ - return; - } - s = d->d_name; - if (strcmp(s, ".") == 0) dot++; - if (strcmp(s, "..") == 0) dotdot++; - if (strcmp(s, "f1") == 0) f1++; - if (strcmp(s, "f2") == 0) f2++; - if (strcmp(s, "f3") == 0) f3++; - if (strcmp(s, "f4") == 0) f4++; - if (strcmp(s, "f5") == 0) f5++; - } - - /* Check results. */ - d = readdir(dirp); - if (d != (struct dirent *) NULL) e(2); - if (f1 != 1 || f3 != 1 || f5 != 1) e(3); - if (f2 != 0 || f4 != 0) e(4); - if (dot != 1 || dotdot != 1) e(5); - subtest = subt; - return; + System("rm -rf ../DIR_20/*"); } void test20b() { -/* Subtest 4. Test error handling. */ - - int fd; - DIR *dirp; - - subtest = 4; - - if (opendir("foo/xyz/---") != DIR_NULL) e(1); - if (errno != ENOENT) e(2); - if (mkdir("foo", 0777) < 0) e(3); - if (chmod("foo", 0) < 0) e(4); - if (opendir("foo/xyz/--") != DIR_NULL) e(5); - if (errno != EACCES) e(6); - if (chmod("foo", 0777) != 0) e(7); - if (rmdir("foo") != 0) e(8); - if ((fd = creat("abc", 0666)) < 0) e(9); - if (close(fd) < 0) e(10); - if (opendir("abc/xyz") != DIR_NULL) e(11); - if (errno != ENOTDIR) e(12); - if ((dirp = opendir(".")) == DIR_NULL) e(13); - if (closedir(dirp) != 0) e(14); - if (unlink("abc") != 0) e(15); - + subtest = 2; + System("rm -rf ../DIR_20/*"); } void test20c() { -/* Subtest 5. See what happens if we open too many directory streams. */ - - int i, j; - DIR *dirp[MAX_FD]; - - subtest = 5; - - for (i = 0; i < MAX_FD; i++) { - dirp[i] = opendir("."); - if (dirp[i] == (DIR *) NULL) { - /* We have hit the limit. */ - if (errno != EMFILE && errno != ENOMEM) e(1); - for (j = 0; j < i; j++) { - if (closedir(dirp[j]) != 0) e(2); /* close */ - } - return; - } - } - - /* Control should never come here. This is an error. */ - e(3); - for (i = 0; i < MAX_FD; i++) closedir(dirp[i]); /* don't check */ + subtest = 3; + System("rm -rf ../DIR_20/*"); } +/* Open fds 3, 4, 5 and 6. Set FD_CLOEXEC on 5 and 6. Exclusively lock the +** first 10 bytes of fd no. 3. Shared lock fd no. 7. Lock fd no. 8 after +** the fork. Do a ``exec()'' call with a funny argv[0] and check the return +** value. +*/ void test20d() -{ -/* Test chdir and getcwd(). */ - - int fd; - char *s; - char base[BUF_SIZE], buf2[BUF_SIZE], tmp[BUF_SIZE]; - - subtest = 6; - - if (getcwd(base, BUF_SIZE) == (char *) NULL) e(1); /* get test dir's path */ - if (system("rm -rf Dir") != 0) e(2); /* remove residue of previous test */ - if (mkdir("Dir", 0777) < 0) e(3); /* create directory called "Dir" */ - - /* Change to Dir and verify that it worked. */ - if (chdir("Dir") < 0) e(4); /* go to Dir */ - s = getcwd(buf2, BUF_SIZE); /* get full path of Dir */ - if (s == (char *) NULL) e(5); /* check for error return */ - if (s != buf2) e(6); /* if successful, first arg is returned */ - strcpy(tmp, base); /* concatenate base name and "/Dir" */ - strcat(tmp, "/"); - strcat(tmp, "Dir"); - if (strcmp(tmp, s) != 0) e(7); - - /* Change to ".." and verify that it worked. */ - if (chdir("..") < 0) e(8); - if (getcwd(buf2, BUF_SIZE) != buf2) e(9); - if (strcmp(buf2, base) != 0) e(10); - - /* Now make calls that do nothing, but do it in a strange way. */ - if (chdir("Dir/..") < 0) e(11); - if (getcwd(buf2, BUF_SIZE) != buf2) e(12); - if (strcmp(buf2, base) != 0) e(13); - - if (chdir("Dir/../Dir/..") < 0) e(14); - if (getcwd(buf2, BUF_SIZE) != buf2) e(15); - if (strcmp(buf2, base) != 0) e(16); - - if (chdir("Dir/../Dir/../Dir/../Dir/../Dir/../Dir/../Dir/..") < 0) e(17); - if (getcwd(buf2, BUF_SIZE) != buf2) e(18); - if (strcmp(buf2, base) != 0) e(19); - - /* Make Dir unreadable and unsearchable. Check error message. */ - if (chmod("Dir", 0) < 0) e(20); - if (chdir("Dir") >= 0) e(21); - if (errno != EACCES) e(22); - - /* Check error message for bad path. */ - if (chmod("Dir", 0777) < 0) e(23); - if (chdir("Dir/x/y") != ERR_CODE) e(24); - if (errno != ENOENT) e(25); - - if ( (fd=creat("Dir/x", 0777)) < 0) e(26); - if (close(fd) != 0) e(27); - if (chdir("Dir/x/y") != ERR_CODE) e(28); - if (errno != ENOTDIR) e(29); - - /* Check empty string. */ - if (chdir("") != ERR_CODE) e(30); - if (errno != ENOENT) e(31); - - /* Remove the directory. */ - if (unlink("Dir/x") != 0) e(32); - if (system("rmdir Dir") != 0) e(33); -} +{ /* Test locks with ``fork()'' and ``exec().'' */ + int fd3, fd4, fd5, fd6, fd7, fd8; + int stat_loc; + int do_check_retval; + char *argv[2]; + struct flock fl; -void test20e() -{ -/* Test open. */ - - int fd, bytes, bytes2; - char buf[RD_BUF]; - - subtest = 7; - - unlink("T20"); /* get rid of it in case it exists */ - - /* Create a test file. */ - bytes = strlen(str); - bytes2 = strlen(str2); - if ((fd = creat("T20", 0777)) < 0) e(1); - if (write(fd, str, bytes) != bytes) e(2); /* T20 now has 'bytes' bytes */ - if (close(fd) != 0) e(3); - - /* Test opening a file with O_RDONLY. */ - if ((fd = open("T20", O_RDONLY)) < 0) e(4); - buf[0] = '\0'; - if (read(fd, buf, RD_BUF) != bytes) e(5); - if (strncmp(buf, str, bytes) != 0) e(6); - if (close(fd) < 0) e(7); - - /* Test the same thing, only with O_RDWR now. */ - if ((fd = open("T20", O_RDWR)) < 0) e(8); - buf[0] = '\0'; - if (read(fd, buf, RD_BUF) != bytes) e(9); - if (strncmp(buf, str, bytes) != 0) e(10); - if (close(fd) < 0) e(11); - - /* Try opening and reading with O_WRONLY. It should fail. */ - if ((fd = open("T20", O_WRONLY)) < 0) e(12); - buf[0] = '\0'; - if (read(fd, buf, RD_BUF) >= 0) e(13); - if (close(fd) != 0) e(14); - - /* Test O_APPEND. */ - if ((fd = open("T20", O_RDWR | O_APPEND)) < 0) e(15); - if (lseek(fd, 0L, SEEK_SET) < 0) e(16); /* go to start of file */ - if ( write(fd, str2, bytes2) != bytes2) e(17); /* write at start of file */ - if (lseek(fd, 0L, SEEK_SET) < 0) e(18); /* go back to start again */ - if (read(fd, buf, RD_BUF) != bytes + bytes2) e(19); /* read whole file */ - if (strncmp(buf, str, bytes) != 0) e(20); - if (close(fd) != 0) e(21); - - /* Get rid of the file. */ - if (unlink("T20") < 0) e(22); -} + subtest = 4; -void test20f() -{ -/* Test stat, fstat, umask. */ - int i, fd; - mode_t m1; - struct stat stbuf1, stbuf2; - time_t t, t1; - - subtest = 8; - - m1 = umask(~0777); - if (system("rm -rf foo xxx") != 0) e(1); - if ((fd = creat("foo", 0777)) < 0) e(2); - if (stat("foo", &stbuf1) < 0) e(3); - if (fstat(fd, &stbuf2) < 0) e(4); - if (stbuf1.st_mode != stbuf2.st_mode) e(5); - if (stbuf1.st_ino != stbuf2.st_ino) e(6); - if (stbuf1.st_dev != stbuf2.st_dev) e(7); - if (stbuf1.st_nlink != stbuf2.st_nlink) e(8); - if (stbuf1.st_uid != stbuf2.st_uid) e(9); - if (stbuf1.st_gid != stbuf2.st_gid) e(10); - if (stbuf1.st_size != stbuf2.st_size) e(11); - if (stbuf1.st_atime != stbuf2.st_atime) e(12); - if (stbuf1.st_mtime != stbuf2.st_mtime) e(13); - if (stbuf1.st_ctime != stbuf2.st_ctime) e(14); - - if (!S_ISREG(stbuf1.st_mode)) e(15); - if (S_ISDIR(stbuf1.st_mode)) e(16); - if (S_ISCHR(stbuf1.st_mode)) e(17); - if (S_ISBLK(stbuf1.st_mode)) e(18); - if (S_ISFIFO(stbuf1.st_mode)) e(19); - - if ((stbuf1.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) != 0777) e(20); - if (stbuf1.st_nlink != 1) e(21); - if (stbuf1.st_uid != getuid()) e(22); - if (stbuf1.st_gid != getgid()) e(23); - if (stbuf1.st_size != 0L) e(24); - - /* First unlink, then close -- harder test */ - if (unlink("foo") < 0) e(25); - if (close(fd) < 0) e(26); - - /* Now try umask a bit more. */ - fd = 0; - if ((i = umask(~0704)) != 0) e(27); - if ((fd = creat("foo", 0777)) < 0) e(28); - if (stat("foo", &stbuf1) < 0) e(29); - if (fstat(fd, &stbuf2) < 0) e(30); - if (stbuf1.st_mode != stbuf2.st_mode) e(31); - if ((stbuf1.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) != 0704) e(32); - - /* First unlink, then close -- harder test */ - if (unlink("foo") < 0) e(33); - if (close(fd) < 0) e(34); - if (umask(m1) != 073) e(35); - - /* Test some errors. */ - if (system("mkdir Dir; date >Dir/x; chmod 666 Dir") != 0) e(36); - if (stat("Dir/x", &stbuf1) >= 0) e(37); - if (errno != EACCES) e(38); - if (stat("......", &stbuf1) >= 0) e(39); - if (errno != ENOENT) e(40); - if (stat("", &stbuf1) >= 0) e(41); - if (errno != ENOENT) e(42); - if (stat("xxx/yyy/zzz", &stbuf1) >= 0) e(43); - if (errno != ENOENT) e(44); - if (fstat(10000, &stbuf1) >= 0) e(45); - if (errno != EBADF) e(46); - if (chmod("Dir", 0777) != 0) e(47); - if (system("rm -rf foo Dir") != 0) e(48); - - /* See if time looks reasonable. */ - errno = 0; - t = time(&t1); /* current time */ - if (t < 650000000L) e(49); /* 650000000 is Sept. 1990 */ - unlink("T20f"); - fd = creat("T20f", 0777); - if (fd < 0) e(50); - if (close(fd) < 0) e(51); - if (stat("T20f", &stbuf1) < 0) e(52); - if (stbuf1.st_mtime < t) e(53); - if (unlink("T20f") < 0) e(54); -} + argv[0] = "DO CHECK"; + argv[1] = (char *) NULL; + + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 10; + + /* Make a dummy files and open them. */ + System("echo 'Great Balls Of Fire!' > file3"); + System("echo 'Great Balls Of Fire!' > file4"); + System("echo 'Great Balls Of Fire!' > file7"); + System("echo 'Great Balls Of Fire!' > file8"); + System("echo 'Great Balls Of Fire!' > file"); + if ((fd3 = open("file3", O_RDWR)) != 3) e(1); + if ((fd4 = open("file4", O_RDWR)) != 4) e(2); + if ((fd5 = open("file", O_RDWR)) != 5) e(3); + if ((fd6 = open("file", O_RDWR)) != 6) e(4); + if ((fd7 = open("file7", O_RDWR)) != 7) e(5); + if ((fd8 = open("file8", O_RDWR)) != 8) e(6); + + /* Set FD_CLOEXEC flags on fd5 and fd6. */ + if (fcntl(fd5, F_SETFD, FD_CLOEXEC) == -1) e(7); + if (fcntl(fd6, F_SETFD, FD_CLOEXEC) == -1) e(8); + + /* Lock the first ten bytes from fd3 (for writing). */ + fl.l_type = F_WRLCK; + if (fcntl(fd3, F_SETLK, &fl) == -1) e(9); + + /* Lock (for reading) fd7. */ + fl.l_type = F_RDLCK; + if (fcntl(fd7, F_SETLK, &fl) == -1) e(10); + + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + + /* Lock fd8. */ + fl.l_type = F_WRLCK; + if (fcntl(fd8, F_SETLK, &fl) == -1) e(11); + + /* Check the lock on fd3 and fd7. */ + fl.l_type = F_WRLCK; + if (fcntl(fd3, F_GETLK, &fl) == -1) e(12); + if (fl.l_type != F_WRLCK) e(13); + if (fl.l_pid != getppid()) e(14); + fl.l_type = F_WRLCK; + if (fcntl(fd7, F_GETLK, &fl) == -1) e(15); + if (fl.l_type != F_RDLCK) e(16); + if (fl.l_pid != getppid()) e(17); + + /* Check FD_CLOEXEC flags. */ + if ((fcntl(fd3, F_GETFD) & FD_CLOEXEC) != 0) e(18); + if ((fcntl(fd4, F_GETFD) & FD_CLOEXEC) != 0) e(19); + if ((fcntl(fd5, F_GETFD) & FD_CLOEXEC) != FD_CLOEXEC) e(20); + if ((fcntl(fd6, F_GETFD) & FD_CLOEXEC) != FD_CLOEXEC) e(21); + if ((fcntl(fd7, F_GETFD) & FD_CLOEXEC) != 0) e(22); + if ((fcntl(fd8, F_GETFD) & FD_CLOEXEC) != 0) e(23); + + execlp(executable + 3, "DO CHECK", (char *) NULL); + execlp(executable, "DO CHECK", (char *) NULL); + printf("Can't exec %s or %s\n", executable + 3, executable); + exit(0); -void test20g() -{ -/* Test link and unlink. */ - int i, fd; - struct stat stbuf; - char name[20]; - - subtest = 9; - - if (system("rm -rf L? L?? Dir; mkdir Dir") != 0) e(1); - if ( (fd = creat("L1", 0666)) < 0) e(2); - if (fstat(fd, &stbuf) != 0) e(3); - if (stbuf.st_nlink != 1) e(4); - if (link("L1", "L2") != 0) e(5); - if (fstat(fd, &stbuf) != 0) e(6); - if (stbuf.st_nlink != 2) e(7); - if (unlink("L2") != 0) e(8); - if (link("L1", "L2") != 0) e(9); - if (unlink("L1") != 0) e(10); - if (close(fd) != 0) e(11); - - /* L2 exists at this point. */ - if ( (fd = creat("L1", 0666)) < 0) e(12); - if (stat("L1", &stbuf) != 0) e(13); - if (stbuf.st_nlink != 1) e(14); - if (link("L1", "Dir/L2") != 0) e(15); - if (stat("L1", &stbuf) != 0) e(16); - if (stbuf.st_nlink != 2) e(17); - if (stat("Dir/L2", &stbuf) != 0) e(18); - if (stbuf.st_nlink != 2) e(19); - - /* L1, L2, and Dir/L2 exist at this point. */ - if (unlink("Dir/L2") != 0) e(20); - if (link("L1", "Dir/L2") != 0) e(21); - if (unlink("L1") != 0) e(22); - if (close(fd) != 0) e(23); - if (chdir("Dir") != 0) e(24); - if (unlink("L2") != 0) e(25); - if (chdir("..") != 0) e(26); - - /* L2 exists at this point. Test linking to unsearchable dir. */ - if (link("L2", "Dir/L2") != 0) e(27); - if (chmod("Dir", 0666) != 0) e(27); - if (link("L2", "Dir/L2") != -1) e(28); - if (errno != EACCES) e(29); - errno = 0; - if (link("Dir/L2", "L3") != -1) e(30); - if (errno != EACCES) e(31); - if (chmod("Dir", 0777) != 0) e(32); - if (unlink("Dir/L2") != 0) e(33); - if (unlink("L3") == 0) e(34); - - /* L2 exists at this point. Test linking to unwriteable dir. */ - if (chmod("Dir", 0555) != 0) e(35); - if (link("L2", "Dir/L2") != -1) e(36); - if (errno != EACCES) e(37); - if (chmod("Dir", 0777) != 0) e(38); - - /* L2 exists at this point. Test linking mode 0 file. */ - if (chmod("L2", 0) != 0) e(39); - if (link("L2", "L3") != 0) e(40); - if (stat("L3", &stbuf) != 0) e(41); - if (stbuf.st_nlink != 2) e(42); - if (unlink("L2") != 0) e(43); - - /* L3 exists at this point. Test linking to an existing file. */ - if ( (fd = creat("L1", 0666)) < 0) e(44); - if (link("L1", "L3") != -1) e(45); - if (errno != EEXIST) e(46); - errno = 0; - if (link("L1", "L1") != -1) e(47); - if (errno != EEXIST) e(48); - if (unlink("L3") != 0) e(49); - - /* L1 exists at this point. Test creating too many links. */ - for (i = 2; i <= LINK_MAX; i++) { - sprintf(name, "Lx%d", i); - if (link("L1", name) != 0) e(50); - } - if (stat("L1", &stbuf) != 0) e(51); - if (stbuf.st_nlink != LINK_MAX) e(52); - if (link("L1", "L2") != -1) e(53); - if (errno != EMLINK) e(54); - for (i = 2; i <= LINK_MAX; i++) { - sprintf(name, "Lx%d", i); - if (unlink(name) != 0) e(55); + default: + wait(&stat_loc); + if (WIFSIGNALED(stat_loc)) e(24); /* Alarm? */ + if (WIFEXITED(stat_loc) == 0) { + errct=10000; + quit(); + } } - if (stat("L1", &stbuf) != 0) e(56); - if (stbuf.st_nlink != 1) e(57); - - /* L1 exists. Test ENOENT. */ - errno = 0; - if (link("xx/L1", "L2") != -1) e(58); - if (errno != ENOENT) e(59); - errno = 0; - if (link("L1", "xx/L2") != -1) e(60); - if (errno != ENOENT) e(61); - errno = 0; - if (link("L4", "L5") != -1) e(62); - if (errno != ENOENT) e(63); - errno = 0; - if (link("", "L5") != -1) e(64); - if (errno != ENOENT) e(65); - errno = 0; - if (link("L1", "") != -1) e(66); - if (errno != ENOENT) e(67); + /* Check the return value of do_check(). */ + do_check_retval = WEXITSTATUS(stat_loc); + if ((do_check_retval & 0x11) == 0x11) e(25); + if ((do_check_retval & 0x12) == 0x12) e(26); + if ((do_check_retval & 0x14) == 0x14) e(27); + if ((do_check_retval & 0x18) == 0x18) e(28); + if ((do_check_retval & 0x21) == 0x21) e(29); + if ((do_check_retval & 0x22) == 0x22) e(30); + if ((do_check_retval & 0x24) == 0x24) e(31); + if ((do_check_retval & 0x28) == 0x28) e(32); + if ((do_check_retval & 0x41) == 0x41) e(33); + if ((do_check_retval & 0x42) == 0x42) e(34); + if ((do_check_retval & 0x44) == 0x44) e(35); + if ((do_check_retval & 0x48) == 0x48) e(36); + if ((do_check_retval & 0x81) == 0x81) e(37); + if ((do_check_retval & 0x82) == 0x82) e(38); + if ((do_check_retval & 0x84) == 0x84) e(39); + if ((do_check_retval & 0x88) == 0x88) e(40); + + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + + /* Lock fd8. */ + fl.l_type = F_WRLCK; + if (fcntl(fd8, F_SETLK, &fl) == -1) e(41); + + execvp(executable + 3, argv); + execvp(executable, argv); + printf("Can't exec %s or %s\n", executable + 3, executable); + exit(0); - /* L1 exists. Test ENOTDIR. */ - errno = 0; - if (link("/dev/tty/x", "L2") != -1) e(68); - if (errno != ENOTDIR) e(69); - - /* L1 exists. Test EPERM. */ - if (link(".", "L2") != -1) e(70); - if (errno != EPERM) e(71); - - /* L1 exists. Test unlink. */ - if (link("L1", "Dir/L1") != 0) e(72); - if (chmod("Dir", 0666) != 0) e(73); - if (unlink("Dir/L1") != -1) e(74); - if (errno != EACCES) e(75); - errno = 0; - if (chmod("Dir", 0555) != 0) e(76); - if (unlink("Dir/L1") != -1) e(77); - if (errno != EACCES) e(78); + default: + wait(&stat_loc); + if (WIFSIGNALED(stat_loc)) e(48); /* Alarm? */ + } - if (unlink("L7") != -1) e(79); - if (errno != ENOENT) e(80); - errno = 0; - if (unlink("") != -1) e(81); - if (errno != ENOENT) e(82); - - if (unlink("Dir/L1/L2") != -1) e(83); - if (errno != ENOTDIR) e(84); - - if (chmod("Dir", 0777) != 0) e(85); - if (unlink("Dir/L1") != 0) e(86); - if (unlink("Dir") != -1) e(87); - if (errno != EPERM) e(88); - if (unlink("L1") != 0) e(89); - if (system("rm -rf Dir") != 0) e(90); - if (close(fd) != 0) e(91); + /* Check the return value of do_check(). */ + do_check_retval = WEXITSTATUS(stat_loc); + if ((do_check_retval & 0x11) == 0x11) e(49); + if ((do_check_retval & 0x12) == 0x12) e(50); + if ((do_check_retval & 0x14) == 0x14) e(51); + if ((do_check_retval & 0x18) == 0x18) e(52); + if ((do_check_retval & 0x21) == 0x21) e(53); + if ((do_check_retval & 0x22) == 0x22) e(54); + if ((do_check_retval & 0x24) == 0x24) e(55); + if ((do_check_retval & 0x28) == 0x28) e(56); + if ((do_check_retval & 0x41) == 0x41) e(57); + if ((do_check_retval & 0x42) == 0x42) e(58); + if ((do_check_retval & 0x44) == 0x44) e(59); + if ((do_check_retval & 0x48) == 0x48) e(60); + if ((do_check_retval & 0x81) == 0x81) e(61); + if ((do_check_retval & 0x82) == 0x82) e(62); + if ((do_check_retval & 0x84) == 0x84) e(63); + if ((do_check_retval & 0x88) == 0x88) e(64); + + fl.l_type = F_UNLCK; + if (fcntl(fd3, F_SETLK, &fl) == -1) e(65); + if (fcntl(fd7, F_SETLK, &fl) == -1) e(66); + + if (close(fd3) != 0) e(67); + if (close(fd4) != 0) e(68); + if (close(fd5) != 0) e(69); + if (close(fd6) != 0) e(70); + if (close(fd7) != 0) e(71); + if (close(fd8) != 0) e(72); + + System("rm -f ../DIR_20/*\n"); } -void test20h() +/* This routine checks that fds 0 through 4, 7 and 8 are open and the rest +** is closed. It also checks if we can lock the first 10 bytes on fd no. 3 +** and 4. It should not be possible to lock fd no. 3, but it should be +** possible to lock fd no. 4. See ``test20d()'' for usage of this routine. +*/ +int do_check() { -/* Test access. */ - - int fd; - - subtest = 10; - system("rm -rf A1"); - if ( (fd = creat("A1", 0777)) < 0) e(1); - if (close(fd) != 0) e(2); - if (access("A1", R_OK) != 0) e(3); - if (access("A1", W_OK) != 0) e(4); - if (access("A1", X_OK) != 0) e(5); - if (access("A1", (R_OK|W_OK|X_OK)) != 0) e(6); - - if (chmod("A1", 0400) != 0) e(7); - if (access("A1", R_OK) != 0) e(8); - if (access("A1", W_OK) != -1) e(9); - if (access("A1", X_OK) != -1) e(10); - if (access("A1", (R_OK|W_OK|X_OK)) != -1) e(11); - - if (chmod("A1", 0077) != 0) e(12); - if (access("A1", R_OK) != -1) e(13); - if (access("A1", W_OK) != -1) e(14); - if (access("A1", X_OK) != -1) e(15); - if (access("A1", (R_OK|W_OK|X_OK)) != -1) e(16); - if (errno != EACCES) e(17); - - if (access("", R_OK) != -1) e(18); - if (errno != ENOENT) e(19); - if (access("./A1/x", R_OK) != -1) e(20); - if (errno != ENOTDIR) e(21); - - if (unlink("A1") != 0) e(22); + int i; + int retval = 0; + struct flock fl; + + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 10; + + /* All std.. are open. */ + if (fcntl(0, F_GETFD) == -1) retval |= 0x11; + if (fcntl(1, F_GETFD) == -1) retval |= 0x11; + if (fcntl(2, F_GETFD) == -1) retval |= 0x11; + + /* Fd no. 3, 4, 7 and 8 are open. */ + if (fcntl(3, F_GETFD) == -1) retval |= 0x12; + if (fcntl(4, F_GETFD) == -1) retval |= 0x12; + if (fcntl(7, F_GETFD) == -1) retval |= 0x12; + + /* Fd no. 5, 6 and 9 trough OPEN_MAX are closed. */ + if (fcntl(5, F_GETFD) != -1) retval |= 0x14; + if (fcntl(6, F_GETFD) != -1) retval |= 0x14; + for (i = 9; i < OPEN_MAX; i++) + if (fcntl(i, F_GETFD) != -1) retval |= 0x18; + +#if 0 + /* Fd no. 3 is WRLCKed. */ + fl.l_type = F_WRLCK; + if (fcntl(3, F_SETLK, &fl) != -1) retval |= 0x21; + if (errno != EACCES && errno != EAGAIN) retval |= 0x22; + fl.l_type = F_RDLCK; + if (fcntl(3, F_SETLK, &fl) != -1) retval |= 0x24; + if (errno != EACCES && errno != EAGAIN) retval |= 0x22; + fl.l_type = F_RDLCK; + if (fcntl(3, F_GETLK, &fl) == -1) retval |= 0x28; + if (fl.l_type != F_WRLCK) retval |= 0x28; + if (fl.l_pid != getpid()) retval |= 0x28; + fl.l_type = F_WRLCK; + if (fcntl(3, F_GETLK, &fl) == -1) retval |= 0x28; + if (fl.l_type != F_WRLCK) retval |= 0x28; + if (fl.l_pid != getpid()) retval |= 0x28; +#endif + + /* Fd no. 4 is not locked. */ + fl.l_type = F_WRLCK; + if (fcntl(4, F_SETLK, &fl) == -1) retval |= 0x41; + if (fcntl(4, F_GETLK, &fl) == -1) retval |= 0x42; +#if 0 /* XXX - see test7.c */ + if (fl.l_type != F_WRLCK) retval |= 0x42; + if (fl.l_pid != getpid()) retval |= 0x42; +#endif /* 0 */ + + /* Fd no. 8 is locked after the fork, it is ours. */ + fl.l_type = F_WRLCK; + if (fcntl(8, F_SETLK, &fl) == -1) retval |= 0x44; + if (fcntl(8, F_GETLK, &fl) == -1) retval |= 0x48; +#if 0 /* XXX - see test7.c */ + if (fl.l_type != F_WRLCK) retval |= 0x48; + if (fl.l_pid != getpid()) retval |= 0x48; +#endif /* 0 */ + +#if 0 + /* Fd no. 7 is RDLCKed. */ + fl.l_type = F_WRLCK; + if (fcntl(7, F_SETLK, &fl) != -1) retval |= 0x81; + if (errno != EACCES && errno != EAGAIN) retval |= 0x82; + fl.l_type = F_RDLCK; + if (fcntl(7, F_SETLK, &fl) == -1) retval |= 0x84; + fl.l_type = F_RDLCK; + if (fcntl(7, F_GETLK, &fl) == -1) retval |= 0x88; + if (fl.l_type != F_UNLCK) retval |= 0x88; + fl.l_type = F_WRLCK; + if (fcntl(7, F_GETLK, &fl) == -1) retval |= 0x88; + if (fl.l_type != F_RDLCK) retval |= 0x88; + if (fl.l_pid != getppid()) retval |= 0x88; +#endif + + return retval; } -void test20i() +void makelongnames() { -/* Test chmod. */ - - int fd, i; - struct stat stbuf; + register int i; - subtest = 11; - system("rm -rf A1"); - if ( (fd = creat("A1", 0777)) < 0) e(1); - - for (i = 0; i < 511; i++) { - if (chmod("A1", i) != 0) e(100+i); - if (fstat(fd, &stbuf) != 0) e(200+i); - if ( (stbuf.st_mode&(S_IRWXU|S_IRWXG|S_IRWXO)) != i) e(300+i); + memset(MaxName, 'a', NAME_MAX); + MaxName[NAME_MAX] = '\0'; + for (i = 0; i < PATH_MAX - 1; i++) { /* idem path */ + MaxPath[i++] = '.'; + MaxPath[i] = '/'; } - if (close(fd) != 0) e(2); + MaxPath[PATH_MAX - 1] = '\0'; - if (chmod("A1/x", 0777) != -1) e(3); - if (errno != ENOTDIR) e(4); - if (chmod("Axxx", 0777) != -1) e(5); - if (errno != ENOENT) e(6); - errno = 0; - if (chmod ("", 0777) != -1) e(7); - if (errno != ENOENT) e(8); - - /* Now perform limited chown tests. These should work even as non su */ - i = getuid(); -/* DEBUG -- Not yet implemented - if (chown("A1", i, 0) != 0) e(9); - if (chown("A1", i, 1) != 0) e(10); - if (chown("A1", i, 2) != 0) e(11); - if (chown("A1", i, 3) != 0) e(12); - if (chown("A1", i, 4) != 0) e(13); - if (chown("A1", i, 0) != 0) e(14); -*/ - - if (unlink("A1") != 0) e(9); -} + strcpy(ToLongName, MaxName); /* copy them Max to ToLong */ + strcpy(ToLongPath, MaxPath); -void test20j() -{ -/* Test utime. */ - - int fd; - time_t tloc; - struct utimbuf times; - struct stat stbuf; - - subtest = 12; - if (system("rm -rf A2") != 0) e(1); - if ( (fd = creat("A2", 0666)) < 0) e(2); - times.modtime = 100; - if (utime("A2", ×) != 0) e(3); - if (stat("A2", &stbuf) != 0) e(4); - if (stbuf.st_mtime != 100) e(5); - - tloc = time((time_t *)NULL); /* get current time */ - times.modtime = tloc; - if (utime("A2", ×) != 0) e(6); - if (stat("A2", &stbuf) != 0) e(7); - if (stbuf.st_mtime != tloc) e(8); - if (close(fd) != 0) e(9); - if (unlink("A2") != 0) e(10); + ToLongName[NAME_MAX] = 'a'; + ToLongName[NAME_MAX + 1] = '\0'; /* extend ToLongName by one too many */ + ToLongPath[PATH_MAX - 1] = '/'; + ToLongPath[PATH_MAX] = '\0'; /* inc ToLongPath by one */ } void e(n) int n; { - int err_num = errno; /* save errno in case printf clobbers it */ + int err_num = errno; /* Save in case printf clobbers it. */ - printf("Subtest %d, error %d errno=%d ", subtest, n, errno); - fflush(stdout); /* stdout and stderr are mixed horribly */ - errno = err_num; /* restore errno, just in case */ + printf("Subtest %d, error %d errno=%d: ", subtest, n, errno); + errno = err_num; perror(""); if (errct++ > MAX_ERROR) { printf("Too many errors; test aborted\n"); @@ -704,19 +377,22 @@ int n; system("rm -rf DIR*"); exit(1); } + errno = 0; } void quit() { - - chdir(".."); - system("rm -rf DIR*"); + Chdir(".."); + System("rm -rf DIR_20"); if (errct == 0) { printf("ok\n"); exit(0); - } else { + } else if (errct < 10000) { printf("%d errors\n", errct); exit(1); + } else { + printf("errors\n"); + exit(2); } } diff --git a/test/test29.c b/test/test29.c index 1ddbcb87c..64da56056 100644 --- a/test/test29.c +++ b/test/test29.c @@ -1,9 +1,16 @@ -/* Many of the tests require 1.6.n, n > 16, so we may as well assume that - * POSIX signals are implemented. - */ -#define SIGACTION - -/* test29: read(), write() Author: Jan-Mark Wams (jms@cs.vu.nl) */ +/* test29: dup() dup2() Author: Jan-Mark Wams (jms@cs.vu.nl) */ + +/* The definition of ``dup2()'' is realy a big mess! For: +** +** (1) if fildes2 is less than zero or greater than {OPEN_MAX} +** errno has to set to [EBADF]. But if fildes2 equals {OPEN_MAX} +** errno has to be set to [EINVAL]. And ``fcntl(F_DUPFD...)'' always +** returns [EINVAL] if fildes2 is out of range! +** +** (2) if the number of file descriptors would exceed {OPEN_MAX}, or no +** file descriptors above fildes2 are available, errno has to be set +** to [EMFILE]. But this can never occur! +*/ #include #include @@ -15,27 +22,30 @@ #include #include #include -#include #include #define MAX_ERROR 4 -#define ITERATIONS 3 -#define BUF_SIZE 1024 +#define ITERATIONS 10 #define System(cmd) if (system(cmd) != 0) printf("``%s'' failed\n", cmd) #define Chdir(dir) if (chdir(dir) != 0) printf("Can't goto %s\n", dir) #define Stat(a,b) if (stat(a,b) != 0) printf("Can't stat %s\n", a) +#define IS_CLOEXEC(fd) ((fcntl(fd, F_GETFD) & FD_CLOEXEC) == FD_CLOEXEC) +#define SET_CLOEXEC(fd) fcntl(fd, F_SETFD, FD_CLOEXEC) + int errct = 0; int subtest = 1; int superuser; -int signumber = 0; +char MaxName[NAME_MAX + 1]; /* Name of maximum length */ +char MaxPath[PATH_MAX]; /* Same for path */ +char ToLongName[NAME_MAX + 2]; /* Name of maximum +1 length */ +char ToLongPath[PATH_MAX + 1]; /* Same for path, both too long */ _PROTOTYPE(void main, (int argc, char *argv[])); _PROTOTYPE(void test29a, (void)); _PROTOTYPE(void test29b, (void)); _PROTOTYPE(void test29c, (void)); -_PROTOTYPE(void setsignumber, (int _signumber)); _PROTOTYPE(void e, (int number)); _PROTOTYPE(void quit, (void)); @@ -52,7 +62,6 @@ char *argv[]; System("rm -rf DIR_29; mkdir DIR_29"); Chdir("DIR_29"); superuser = (geteuid() == 0); - umask(0000); for (i = 0; i < ITERATIONS; i++) { if (m & 0001) test29a(); @@ -63,655 +72,146 @@ char *argv[]; } void test29a() -{ /* Try normal operation. */ - int fd1; - struct stat st1, st2; - time_t time1; - char buf[BUF_SIZE]; - int stat_loc; - int i, j; - int tube[2]; +{ + int fd1, fd2, fd3, fd4, fd5; + struct flock flock; subtest = 1; - System("rm -rf ../DIR_29/*"); - - /* Let's open bar. */ - if ((fd1 = open("bar", O_RDWR | O_CREAT, 0777)) != 3) e(1); - Stat("bar", &st1); - - /* Writing nothing should not affect the file at all. */ - if (write(fd1, "", 0) != 0) e(2); - Stat("bar", &st2); - if (st1.st_uid != st2.st_uid) e(3); - if (st1.st_gid != st2.st_gid) e(4); /* should be same */ - if (st1.st_mode != st2.st_mode) e(5); - if (st1.st_size != st2.st_size) e(6); - if (st1.st_nlink != st2.st_nlink) e(7); - if (st1.st_mtime != st2.st_mtime) e(8); - if (st1.st_ctime != st2.st_ctime) e(9); - if (st1.st_atime != st2.st_atime) e(10); - - /* A write should update some status fields. */ - time(&time1); - while (time1 >= time((time_t *)0)) - ; - if (write(fd1, "foo", 4) != 4) e(11); - Stat("bar", &st2); - if (st1.st_mode != st2.st_mode) e(12); - if (st1.st_size >= st2.st_size) e(13); - if ((off_t) 4 != st2.st_size) e(14); - if (st1.st_nlink != st2.st_nlink) e(15); - if (st1.st_mtime >= st2.st_mtime) e(16); - if (st1.st_ctime >= st2.st_ctime) e(17); - if (st1.st_atime != st2.st_atime) e(18); - - /* Lseeks should not change the file status. */ - if (lseek(fd1, (off_t) - 2, SEEK_END) != 2) e(19); - Stat("bar", &st1); - if (st1.st_mode != st2.st_mode) e(20); - if (st1.st_size != st2.st_size) e(21); - if (st1.st_nlink != st2.st_nlink) e(22); - if (st1.st_mtime != st2.st_mtime) e(23); - if (st1.st_ctime != st2.st_ctime) e(24); - if (st1.st_atime != st2.st_atime) e(25); - - /* Writing should start at the current (2) position. */ - if (write(fd1, "foo", 4) != 4) e(26); - Stat("bar", &st2); - if (st1.st_mode != st2.st_mode) e(27); - if (st1.st_size >= st2.st_size) e(28); - if ((off_t) 6 != st2.st_size) e(29); - if (st1.st_nlink != st2.st_nlink) e(30); - if (st1.st_mtime > st2.st_mtime) e(31); - if (st1.st_ctime > st2.st_ctime) e(32); - if (st1.st_atime != st2.st_atime) e(33); - - /* A read of zero bytes should not affect anything. */ - if (read(fd1, buf, 0) != 0) e(34); - Stat("bar", &st1); - if (st1.st_uid != st2.st_uid) e(35); - if (st1.st_gid != st2.st_gid) e(36); /* should be same */ - if (st1.st_mode != st2.st_mode) e(37); - if (st1.st_size != st2.st_size) e(38); - if (st1.st_nlink != st2.st_nlink) e(39); - if (st1.st_mtime != st2.st_mtime) e(40); - if (st1.st_ctime != st2.st_ctime) e(41); - if (st1.st_atime != st2.st_atime) e(42); - - /* The file now should contain ``fofoo\0'' Let's check that. */ - if (lseek(fd1, (off_t) 0, SEEK_SET) != 0) e(43); - if (read(fd1, buf, BUF_SIZE) != 6) e(44); - if (strcmp(buf, "fofoo") != 0) e(45); - - /* Only the Access Time should be updated. */ - Stat("bar", &st2); - if (st1.st_mtime != st2.st_mtime) e(46); - if (st1.st_ctime != st2.st_ctime) e(47); - if (st1.st_atime >= st2.st_atime) e(48); - - /* A read of zero bytes should do nothing even at the end of the file. */ - time(&time1); - while (time1 >= time((time_t *)0)) - ; - if (read(fd1, buf, 0) != 0) e(49); - Stat("bar", &st1); - if (st1.st_size != st2.st_size) e(50); - if (st1.st_mtime != st2.st_mtime) e(51); - if (st1.st_ctime != st2.st_ctime) e(52); - if (st1.st_atime != st2.st_atime) e(53); - - /* Reading should be done from the current offset. */ - if (read(fd1, buf, BUF_SIZE) != 0) e(54); - if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(55); - if (read(fd1, buf, BUF_SIZE) != 4) e(56); - if (strcmp(buf, "foo") != 0) e(57); - - /* Reading should effect the current file position. */ - if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(58); - if (read(fd1, buf, 1) != 1) e(59); - if (*buf != 'f') e(60); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 3) e(61); - if (read(fd1, buf, 1) != 1) e(62); - if (*buf != 'o') e(63); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 4) e(64); - if (read(fd1, buf, 1) != 1) e(65); - if (*buf != 'o') e(66); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 5) e(67); - if (read(fd1, buf, 1) != 1) e(68); - if (*buf != '\0') e(69); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(70); - - /* Read's at EOF should return 0. */ - if (read(fd1, buf, BUF_SIZE) != 0) e(71); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(72); - if (read(fd1, buf, BUF_SIZE) != 0) e(73); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(74); - if (read(fd1, buf, BUF_SIZE) != 0) e(75); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(76); - if (read(fd1, buf, BUF_SIZE) != 0) e(77); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(78); - if (read(fd1, buf, BUF_SIZE) != 0) e(79); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(80); - - /* Writing should not always change the file size. */ - if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(81); - if (write(fd1, "ba", 2) != 2) e(82); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 4) e(83); - Stat("bar", &st1); - if (st1.st_size != 6) e(84); - - /* Kill the \0 at the end. */ - if (lseek(fd1, (off_t) 5, SEEK_SET) != 5) e(85); - if (write(fd1, "x", 1) != 1) e(86); - - /* And close the bar. */ - if (close(fd1) != 0) e(87); - - /* Try some stuff with O_APPEND. Bar contains ``fobaox'' */ - if ((fd1 = open("bar", O_RDWR | O_APPEND)) != 3) e(88); - - /* No matter what the file position is. Writes should append. */ - if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(89); - if (write(fd1, "y", 1) != 1) e(90); - Stat("bar", &st1); - if (st1.st_size != (off_t) 7) e(91); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 7) e(92); - if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(93); - if (write(fd1, "z", 2) != 2) e(94); - - /* The file should contain ``fobaoxyz\0'' == 9 chars long. */ - Stat("bar", &st1); - if (st1.st_size != (off_t) 9) e(95); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 9) e(96); - - /* Reading on a O_APPEND flag should be from the current offset. */ - if (lseek(fd1, (off_t) 0, SEEK_SET) != 0) e(97); - if (read(fd1, buf, BUF_SIZE) != 9) e(98); - if (strcmp(buf, "fobaoxyz") != 0) e(99); - if (lseek(fd1, (off_t) 0, SEEK_CUR) != 9) e(100); - - if (close(fd1) != 0) e(101); - - /* Let's test fifo writes. First blocking. */ - if (mkfifo("fifo", 0777) != 0) e(102); - - /* Read from fifo but no writer. */ - System("rm -rf /tmp/sema.29a"); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - - case 0: - alarm(20); - if ((fd1 = open("fifo", O_RDONLY)) != 3) e(103); - system("> /tmp/sema.29a"); - system("while test -f /tmp/sema.29a; do sleep 1; done"); -errno =0; - if (read(fd1, buf, BUF_SIZE) != 0) e(104); - if (read(fd1, buf, BUF_SIZE) != 0) e(105); - if (read(fd1, buf, BUF_SIZE) != 0) e(106); - if (close(fd1) != 0) e(107); - exit(0); - - default: - if ((fd1 = open("fifo", O_WRONLY)) != 3) e(108); - while (stat("/tmp/sema.29a", &st1) != 0) sleep(1); - if (close(fd1) != 0) e(109); - unlink("/tmp/sema.29a"); - if (wait(&stat_loc) == -1) e(110); - if (stat_loc != 0) e(111); /* Alarm? */ - } - - /* Read from fifo should wait for writer. */ - switch (fork()) { - case -1: printf("Can't fork\n"); break; - - case 0: - alarm(20); - if ((fd1 = open("fifo", O_RDONLY)) != 3) e(112); - if (read(fd1, buf, BUF_SIZE) != 10) e(113); - if (strcmp(buf, "Hi reader") != 0) e(114); - if (close(fd1) != 0) e(115); - exit(0); - - default: - if ((fd1 = open("fifo", O_WRONLY)) != 3) e(116); - sleep(1); - if (write(fd1, "Hi reader", 10) != 10) e(117); - if (close(fd1) != 0) e(118); - if (wait(&stat_loc) == -1) e(119); - if (stat_loc != 0) e(120); /* Alarm? */ - } - /* Read from fifo should wait for all writers to close. */ - switch (fork()) { - case -1: printf("Can't fork\n"); break; - - case 0: - alarm(20); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - if ((fd1 = open("fifo", O_WRONLY)) != 3) e(121); - if (close(fd1) != 0) e(122); - exit(0); - default: - if ((fd1 = open("fifo", O_WRONLY)) != 3) e(123); - sleep(1); - if (close(fd1) != 0) e(124); - if (wait(&stat_loc) == -1) e(125); - if (stat_loc != 0) e(126); /* Alarm? */ - } - exit(stat_loc); - - default: - if ((fd1 = open("fifo", O_RDONLY)) != 3) e(127); - if (read(fd1, buf, BUF_SIZE) != 0) e(128); - if (close(fd1) != 0) e(129); - if (wait(&stat_loc) == -1) e(130); - if (stat_loc != 0) e(131); /* Alarm? */ - } + /* Basic checking. */ + if ((fd1 = dup(0)) != 3) e(1); + if ((fd2 = dup(0)) != 4) e(2); + if ((fd3 = dup(0)) != 5) e(3); + if ((fd4 = dup(0)) != 6) e(4); + if ((fd5 = dup(0)) != 7) e(5); + if (close(fd2) != 0) e(6); + if (close(fd4) != 0) e(7); + if ((fd2 = dup(0)) != 4) e(8); + if ((fd4 = dup(0)) != 6) e(9); + if (close(fd1) != 0) e(10); + if (close(fd3) != 0) e(11); + if (close(fd5) != 0) e(12); + if ((fd1 = dup(0)) != 3) e(13); + if ((fd3 = dup(0)) != 5) e(14); + if ((fd5 = dup(0)) != 7) e(15); + if (close(fd1) != 0) e(16); + if (close(fd2) != 0) e(17); + if (close(fd3) != 0) e(18); + if (close(fd4) != 0) e(19); + if (close(fd5) != 0) e(20); + + /* FD_CLOEXEC should be cleared. */ + if ((fd1 = dup(0)) != 3) e(21); + if (SET_CLOEXEC(fd1) == -1) e(22); + if (!IS_CLOEXEC(fd1)) e(23); + if ((fd2 = dup(fd1)) != 4) e(24); + if ((fd3 = dup(fd2)) != 5) e(25); + if (IS_CLOEXEC(fd2)) e(26); + if (IS_CLOEXEC(fd3)) e(27); + if (SET_CLOEXEC(fd2) == -1) e(28); + if (!IS_CLOEXEC(fd2)) e(29); + if (IS_CLOEXEC(fd3)) e(30); + if (close(fd1) != 0) e(31); + if (close(fd2) != 0) e(32); + if (close(fd3) != 0) e(33); + + /* Locks should be shared, so we can lock again. */ + System("echo 'Hallo' > file"); + if ((fd1 = open("file", O_RDWR)) != 3) e(34); + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 10; + flock.l_type = F_WRLCK; + if (fcntl(fd1, F_SETLK, &flock) == -1) e(35); + if (fcntl(fd1, F_SETLK, &flock) == -1) e(36); + if ((fd2 = dup(fd1)) != 4) e(37); + if (fcntl(fd1, F_SETLK, &flock) == -1) e(38); + if (fcntl(fd1, F_GETLK, &flock) == -1) e(39); +#if 0 /* XXX - see test7.c */ + if (flock.l_type != F_WRLCK) e(40); + if (flock.l_pid != getpid()) e(41); +#endif /* 0 */ + flock.l_type = F_WRLCK; + if (fcntl(fd2, F_GETLK, &flock) == -1) e(42); +#if 0 /* XXX - see test7.c */ + if (flock.l_type != F_WRLCK) e(43); + if (flock.l_pid != getpid()) e(44); +#endif /* 0 */ + if (close(fd1) != 0) e(45); + if (close(fd2) != 0) e(46); - /* PIPE_BUF has to have a nice value. */ - if (PIPE_BUF < 5) e(132); - if (BUF_SIZE < 1000) e(133); - - /* Writes of blocks smaller than PIPE_BUF should be atomic. */ - System("rm -rf /tmp/sema.29b;> /tmp/sema.29b"); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - - case 0: - alarm(20); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - - case 0: - alarm(20); - if ((fd1 = open("fifo", O_WRONLY)) != 3) e(134); - for (i = 0; i < 100; i++) write(fd1, "1234 ", 5); - system("while test -f /tmp/sema.29b; do sleep 1; done"); - if (close(fd1) != 0) e(135); - exit(0); - - default: - if ((fd1 = open("fifo", O_WRONLY)) != 3) e(136); - for (i = 0; i < 100; i++) write(fd1, "1234 ", 5); - while (stat("/tmp/sema.29b", &st1) == 0) sleep(1); - if (close(fd1) != 0) e(137); - if (wait(&stat_loc) == -1) e(138); - if (stat_loc != 0) e(139); /* Alarm? */ - } - exit(stat_loc); - - default: - if ((fd1 = open("fifo", O_RDONLY)) != 3) e(140); - i = 0; - memset(buf, '\0', BUF_SIZE); - - /* Read buffer full or till EOF. */ - do { - j = read(fd1, buf + i, BUF_SIZE - i); - if (j > 0) { - if (j % 5 != 0) e(141); - i += j; - } - } while (j > 0 && i < 1000); - - /* Signal the children to close write ends. This should not be */ - /* Necessary. But due to a bug in 1.16.6 this is necessary. */ - unlink("/tmp/sema.29b"); - if (j < 0) e(142); - if (i != 1000) e(143); - if (wait(&stat_loc) == -1) e(144); - if (stat_loc != 0) e(145); /* Alarm? */ - - /* Check 200 times 1234. */ - for (i = 0; i < 200; i++) - if (strncmp(buf + (i * 5), "1234 ", 5) != 0) break; - if (i != 200) e(146); - if (buf[1000] != '\0') e(147); - if (buf[1005] != '\0') e(148); - if (buf[1010] != '\0') e(149); - if (read(fd1, buf, BUF_SIZE) != 0) e(150); - if (close(fd1) != 0) e(151); - } - - /* Read from pipe should wait for writer. */ - if (pipe(tube) != 0) e(152); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - if (close(tube[1]) != 0) e(153); - if (read(tube[0], buf, BUF_SIZE) != 10) e(154); - if (strcmp(buf, "Hi reader") != 0) e(155); - if (close(tube[0]) != 0) e(156); - exit(0); - default: - if (close(tube[0]) != 0) e(157); - sleep(1); - if (write(tube[1], "Hi reader", 10) != 10) e(158); - if (close(tube[1]) != 0) e(159); - if (wait(&stat_loc) == -1) e(160); - if (stat_loc != 0) e(161); /* Alarm? */ - } - - /* Read from pipe should wait for all writers to close. */ - if (pipe(tube) != 0) e(162); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - if (close(tube[0]) != 0) e(163); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - if (close(tube[1]) != 0) e(164); - exit(0); - default: - sleep(1); - if (close(tube[1]) != 0) e(165); - if (wait(&stat_loc) == -1) e(166); - if (stat_loc != 0) e(167); /* Alarm? */ - } - exit(stat_loc); - default: - if (close(tube[1]) != 0) e(168); - if (read(tube[0], buf, BUF_SIZE) != 0) e(169); - if (close(tube[0]) != 0) e(170); - if (wait(&stat_loc) == -1) e(171); - if (stat_loc != 0) e(172); /* Alarm? */ - } - - /* Writes of blocks smaller than PIPE_BUF should be atomic. */ - System("rm -rf /tmp/sema.29c;> /tmp/sema.29c"); - if (pipe(tube) != 0) e(173); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - if (close(tube[0]) != 0) e(174); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - for (i = 0; i < 100; i++) write(tube[1], "1234 ", 5); - system("while test -f /tmp/sema.29c; do sleep 1; done"); - if (close(tube[1]) != 0) e(175); - exit(0); - default: - for (i = 0; i < 100; i++) write(tube[1], "1234 ", 5); - while (stat("/tmp/sema.29c", &st1) == 0) sleep(1); - if (close(tube[1]) != 0) e(176); - if (wait(&stat_loc) == -1) e(177); - if (stat_loc != 0) e(178); /* Alarm? */ - } - exit(stat_loc); - default: - i = 0; - if (close(tube[1]) != 0) e(179); - memset(buf, '\0', BUF_SIZE); - do { - j = read(tube[0], buf + i, BUF_SIZE - i); - if (j > 0) { - if (j % 5 != 0) e(180); - i += j; - } else - break; /* EOF seen. */ - } while (i < 1000); - unlink("/tmp/sema.29c"); - if (j < 0) e(181); - if (i != 1000) e(182); - if (close(tube[0]) != 0) e(183); - if (wait(&stat_loc) == -1) e(184); - if (stat_loc != 0) e(185); /* Alarm? */ - - /* Check 200 times 1234. */ - for (i = 0; i < 200; i++) - if (strncmp(buf + (i * 5), "1234 ", 5) != 0) break; - if (i != 200) e(186); - } + System("rm -rf ../DIR_29/*"); } void test29b() { - int i, fd, stat_loc; - char buf[BUF_SIZE]; - char buf2[BUF_SIZE]; - struct stat st; + int fd; + char buf[32]; subtest = 2; - System("rm -rf ../DIR_29/*"); - /* Lets try sequential writes. */ - system("rm -rf /tmp/sema.29d"); - System("> testing"); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(1); - if (write(fd, "one ", 4) != 4) e(2); - if (close(fd) != 0) e(3); - system("> /tmp/sema.29d"); - system("while test -f /tmp/sema.29d; do sleep 1; done"); - if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(4); - if (write(fd, "three ", 6) != 6) e(5); - if (close(fd) != 0) e(6); - system("> /tmp/sema.29d"); - exit(0); - default: - while (stat("/tmp/sema.29d", &st) != 0) sleep(1); - if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(7); - if (write(fd, "two ", 4) != 4) e(8); - if (close(fd) != 0) e(9); - unlink("/tmp/sema.29d"); - while (stat("/tmp/sema.29d", &st) != 0) sleep(1); - if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(10); - if (write(fd, "four", 5) != 5) e(11); - if (close(fd) != 0) e(12); - if (wait(&stat_loc) == -1) e(13); - if (stat_loc != 0) e(14); /* The alarm went off? */ - unlink("/tmp/sema.29d"); - } - if ((fd = open("testing", O_RDONLY)) != 3) e(15); - if (read(fd, buf, BUF_SIZE) != 19) e(16); - if (strcmp(buf, "one two three four") != 0) e(17); - if (close(fd) != 0) e(18); - - /* Non written bytes in regular files should be zero. */ - memset(buf2, '\0', BUF_SIZE); - if ((fd = open("bigfile", O_RDWR | O_CREAT, 0644)) != 3) e(19); - if (lseek(fd, (off_t) 102400, SEEK_SET) != (off_t) 102400L) e(20); - if (read(fd, buf, BUF_SIZE) != 0) e(21); - if (write(fd, ".", 1) != 1) e(22); - Stat("bigfile", &st); - if (st.st_size != (off_t) 102401) e(23); - if (lseek(fd, (off_t) 0, SEEK_SET) != 0) e(24); - for (i = 0; i < 102400 / BUF_SIZE; i++) { - if (read(fd, buf, BUF_SIZE) != BUF_SIZE) e(25); - if (memcmp(buf, buf2, BUF_SIZE) != 0) e(26); - } - if (close(fd) != 0) e(27); + /* Test file called ``file''. */ + System("echo 'Hallo!' > file"); + + /* Check dup2() call with the same fds. Should have no effect. */ + if ((fd = open("file", O_RDONLY)) != 3) e(1); + if (read(fd, buf, 2) != 2) e(2); + if (strncmp(buf, "Ha", 2) != 0) e(3); + if (dup2(fd, fd) != fd) e(4); + if (read(fd, buf, 2) != 2) e(5); + if (strncmp(buf, "ll", 2) != 0) e(6); + if (dup2(fd, fd) != fd) e(7); + if (read(fd, buf, 2) != 2) e(8); + if (strncmp(buf, "o!", 2) != 0) e(9); + if (close(fd) != 0) e(10); + + /* If dup2() call fails, the fildes2 argument has to stay open. */ + if ((fd = open("file", O_RDONLY)) != 3) e(11); + if (read(fd, buf, 2) != 2) e(12); + if (strncmp(buf, "Ha", 2) != 0) e(13); + if (dup2(OPEN_MAX + 3, fd) != -1) e(14); + if (errno != EBADF) e(15); + if (read(fd, buf, 2) != 2) e(16); + if (strncmp(buf, "ll", 2) != 0) e(17); + if (dup2(-4, fd) != -1) e(18); + if (errno != EBADF) e(19); + if (read(fd, buf, 2) != 2) e(20); + if (strncmp(buf, "o!", 2) != 0) e(21); + if (close(fd) != 0) e(22); + + System("rm -rf ../DIR_29/*"); } void test29c() -{ /* Test correct error behavior. */ - char buf[BUF_SIZE]; - int fd, tube[2], stat_loc; - struct stat st; - pid_t pid; -#ifdef SIGACTION - struct sigaction act, oact; -#else -#if _ANSI - void (*oldfunc) (int); -#else - void (*oldfunc) (); -#endif -#endif +{ + int i; subtest = 3; - System("rm -rf ../DIR_29/*"); - /* To test if writing processes on closed pipes are signumbered. */ -#ifdef SIGACTION - act.sa_handler = setsignumber; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - if (sigaction(SIGPIPE, &act, &oact) != 0) e(1); -#else - oldfunc = signal(SIGPIPE, setsignumber); -#endif - - /* Non valid file descriptors should be an error. */ - for (fd = -111; fd < 0; fd++) { - errno = 0; - if (read(fd, buf, BUF_SIZE) != -1) e(2); - if (errno != EBADF) e(3); - } - for (fd = 3; fd < 111; fd++) { - errno = 0; - if (read(fd, buf, BUF_SIZE) != -1) e(4); - if (errno != EBADF) e(5); - } - for (fd = -111; fd < 0; fd++) { - errno = 0; - if (write(fd, buf, BUF_SIZE) != -1) e(6); - if (errno != EBADF) e(7); - } - for (fd = 3; fd < 111; fd++) { - errno = 0; - if (write(fd, buf, BUF_SIZE) != -1) e(8); - if (errno != EBADF) e(9); - } + /* Check bad arguments to dup() and dup2(). */ + for (i = -OPEN_MAX; i < OPEN_MAX * 2; i++) { - /* Writing a pipe with no readers should trigger SIGPIPE. */ - if (pipe(tube) != 0) e(10); - close(tube[0]); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - signumber = 0; - if (write(tube[1], buf, BUF_SIZE) != -1) e(11); - if (errno != EPIPE) e(12); - if (signumber != SIGPIPE) e(13); - if (close(tube[1]) != 0) e(14); - exit(0); - default: - close(tube[1]); - if (wait(&stat_loc) == -1) e(15); - if (stat_loc != 0) e(16); /* Alarm? */ - } + /* ``i'' is a valid and open fd. */ + if (i >= 0 && i < 3) continue; - /* Writing a fifo with no readers should trigger SIGPIPE. */ - System("> /tmp/sema.29e"); - if (mkfifo("fifo", 0666) != 0) e(17); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - if ((fd = open("fifo", O_WRONLY)) != 3) e(18); - system("while test -f /tmp/sema.29e; do sleep 1; done"); - signumber = 0; - if (write(fd, buf, BUF_SIZE) != -1) e(19); - if (errno != EPIPE) e(20); - if (signumber != SIGPIPE) e(21); - if (close(fd) != 0) e(22); - exit(0); - default: - if ((fd = open("fifo", O_RDONLY)) != 3) e(23); - if (close(fd) != 0) e(24); - unlink("/tmp/sema.29e"); - if (wait(&stat_loc) == -1) e(25); - if (stat_loc != 0) e(26); /* Alarm? */ - } + /* If ``i'' is a valid fd it is not open. */ + if (dup(i) != -1) e(1); + if (errno != EBADF) e(2); -#ifdef SIGACTION - /* Restore normal (re)action to SIGPIPE. */ - if (sigaction(SIGPIPE, &oact, NULL) != 0) e(27); -#else - signal(SIGPIPE, oldfunc); -#endif - - /* Read from fifo should return -1 and set errno to EAGAIN. */ - System("rm -rf /tmp/sema.29[fgh]"); - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - system("while test ! -f /tmp/sema.29f; do sleep 1; done"); - System("rm -rf /tmp/sema.29f"); - if ((fd = open("fifo", O_WRONLY | O_NONBLOCK)) != 3) e(28); - close(creat("/tmp/sema.29g", 0666)); - system("while test ! -f /tmp/sema.29h; do sleep 1; done"); - if (close(fd) != 0) e(29); - System("rm -rf /tmp/sema.29h"); - exit(0); - default: - if ((fd = open("fifo", O_RDONLY | O_NONBLOCK)) != 3) e(30); - close(creat("/tmp/sema.29f", 0666)); - system("while test ! -f /tmp/sema.29g; do sleep 1; done"); - System("rm -rf /tmp/sema.29g"); - if (read(fd, buf, BUF_SIZE) != -1) e(31); - if (errno != EAGAIN) e(32); - if (read(fd, buf, BUF_SIZE) != -1) e(33); - if (errno != EAGAIN) e(34); - if (read(fd, buf, BUF_SIZE) != -1) e(35); - if (errno != EAGAIN) e(36); - close(creat("/tmp/sema.29h", 0666)); - while (stat("/tmp/sema.29h", &st) == 0) sleep(1); - if (read(fd, buf, BUF_SIZE) != 0) e(37); - if (close(fd) != 0) e(38); - if (wait(&stat_loc) == -1) e(39); - if (stat_loc != 0) e(40); /* Alarm? */ - } - System("rm -rf fifo"); - - /* If a read is interrupted by a SIGNAL. */ - if (pipe(tube) != 0) e(41); - switch (pid = fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); -#ifdef SIGACTION - act.sa_handler = setsignumber; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - if (sigaction(SIGUSR1, &act, &oact) != 0) e(42); -#else - oldfunc = signal(SIGUSR1, setsignumber); -#endif - if (read(tube[0], buf, BUF_SIZE) != -1) e(43); - if (errno != EINTR) e(44); - if (signumber != SIGUSR1) e(45); -#ifdef SIGACTION - /* Restore normal (re)action to SIGPIPE. */ - if (sigaction(SIGUSR1, &oact, NULL) != 0) e(46); -#else - signal(SIGUSR1, oldfunc); -#endif - close(tube[0]); - close(tube[1]); - exit(0); - default: - /* The sleep 1 should give the child time to start the read. */ - sleep(1); - close(tube[0]); - kill(pid, SIGUSR1); - wait(&stat_loc); - if (stat_loc != 0) e(47); /* Alarm? */ - close(tube[1]); + /* ``i'' Is OPEN_MAX. */ + if (i == OPEN_MAX) { + if (dup2(0, i) != -1) e(3); + if (errno != EINVAL) e(4); + } + + /* ``i'' Is out of range. */ + if (i < 0 || i > OPEN_MAX) { + if (dup2(0, i) != -1) e(5); + if (errno != EBADF) e(6); + } } -} -void setsignumber(signum) -int signum; -{ - signumber = signum; + System("rm -rf ../DIR_29/*"); } void e(n) diff --git a/test/test38.c b/test/test38.c index 4bac6cb61..5340e8355 100644 --- a/test/test38.c +++ b/test/test38.c @@ -1,16 +1,9 @@ -/* test38: dup() dup2() Author: Jan-Mark Wams (jms@cs.vu.nl) */ - -/* The definition of ``dup2()'' is realy a big mess! For: -** -** (1) if fildes2 is less than zero or greater than {OPEN_MAX} -** errno has to set to [EBADF]. But if fildes2 equals {OPEN_MAX} -** errno has to be set to [EINVAL]. And ``fcntl(F_DUPFD...)'' always -** returns [EINVAL] if fildes2 is out of range! -** -** (2) if the number of file descriptors would exceed {OPEN_MAX}, or no -** file descriptors above fildes2 are available, errno has to be set -** to [EMFILE]. But this can never occur! -*/ +/* Many of the tests require 1.6.n, n > 16, so we may as well assume that + * POSIX signals are implemented. + */ +#define SIGACTION + +/* test38: read(), write() Author: Jan-Mark Wams (jms@cs.vu.nl) */ #include #include @@ -22,30 +15,27 @@ #include #include #include +#include #include #define MAX_ERROR 4 -#define ITERATIONS 10 +#define ITERATIONS 3 +#define BUF_SIZE 1024 #define System(cmd) if (system(cmd) != 0) printf("``%s'' failed\n", cmd) #define Chdir(dir) if (chdir(dir) != 0) printf("Can't goto %s\n", dir) #define Stat(a,b) if (stat(a,b) != 0) printf("Can't stat %s\n", a) -#define IS_CLOEXEC(fd) ((fcntl(fd, F_GETFD) & FD_CLOEXEC) == FD_CLOEXEC) -#define SET_CLOEXEC(fd) fcntl(fd, F_SETFD, FD_CLOEXEC) - int errct = 0; int subtest = 1; int superuser; -char MaxName[NAME_MAX + 1]; /* Name of maximum length */ -char MaxPath[PATH_MAX]; /* Same for path */ -char ToLongName[NAME_MAX + 2]; /* Name of maximum +1 length */ -char ToLongPath[PATH_MAX + 1]; /* Same for path, both too long */ +int signumber = 0; _PROTOTYPE(void main, (int argc, char *argv[])); _PROTOTYPE(void test38a, (void)); _PROTOTYPE(void test38b, (void)); _PROTOTYPE(void test38c, (void)); +_PROTOTYPE(void setsignumber, (int _signumber)); _PROTOTYPE(void e, (int number)); _PROTOTYPE(void quit, (void)); @@ -62,6 +52,7 @@ char *argv[]; System("rm -rf DIR_38; mkdir DIR_38"); Chdir("DIR_38"); superuser = (geteuid() == 0); + umask(0000); for (i = 0; i < ITERATIONS; i++) { if (m & 0001) test38a(); @@ -72,146 +63,655 @@ char *argv[]; } void test38a() -{ - int fd1, fd2, fd3, fd4, fd5; - struct flock flock; +{ /* Try normal operation. */ + int fd1; + struct stat st1, st2; + time_t time1; + char buf[BUF_SIZE]; + int stat_loc; + int i, j; + int tube[2]; subtest = 1; + System("rm -rf ../DIR_38/*"); - /* Basic checking. */ - if ((fd1 = dup(0)) != 3) e(1); - if ((fd2 = dup(0)) != 4) e(2); - if ((fd3 = dup(0)) != 5) e(3); - if ((fd4 = dup(0)) != 6) e(4); - if ((fd5 = dup(0)) != 7) e(5); - if (close(fd2) != 0) e(6); - if (close(fd4) != 0) e(7); - if ((fd2 = dup(0)) != 4) e(8); - if ((fd4 = dup(0)) != 6) e(9); - if (close(fd1) != 0) e(10); - if (close(fd3) != 0) e(11); - if (close(fd5) != 0) e(12); - if ((fd1 = dup(0)) != 3) e(13); - if ((fd3 = dup(0)) != 5) e(14); - if ((fd5 = dup(0)) != 7) e(15); - if (close(fd1) != 0) e(16); - if (close(fd2) != 0) e(17); - if (close(fd3) != 0) e(18); - if (close(fd4) != 0) e(19); - if (close(fd5) != 0) e(20); - - /* FD_CLOEXEC should be cleared. */ - if ((fd1 = dup(0)) != 3) e(21); - if (SET_CLOEXEC(fd1) == -1) e(22); - if (!IS_CLOEXEC(fd1)) e(23); - if ((fd2 = dup(fd1)) != 4) e(24); - if ((fd3 = dup(fd2)) != 5) e(25); - if (IS_CLOEXEC(fd2)) e(26); - if (IS_CLOEXEC(fd3)) e(27); - if (SET_CLOEXEC(fd2) == -1) e(28); - if (!IS_CLOEXEC(fd2)) e(29); - if (IS_CLOEXEC(fd3)) e(30); - if (close(fd1) != 0) e(31); - if (close(fd2) != 0) e(32); - if (close(fd3) != 0) e(33); - - /* Locks should be shared, so we can lock again. */ - System("echo 'Hallo' > file"); - if ((fd1 = open("file", O_RDWR)) != 3) e(34); - flock.l_whence = SEEK_SET; - flock.l_start = 0; - flock.l_len = 10; - flock.l_type = F_WRLCK; - if (fcntl(fd1, F_SETLK, &flock) == -1) e(35); - if (fcntl(fd1, F_SETLK, &flock) == -1) e(36); - if ((fd2 = dup(fd1)) != 4) e(37); - if (fcntl(fd1, F_SETLK, &flock) == -1) e(38); - if (fcntl(fd1, F_GETLK, &flock) == -1) e(39); -#if 0 /* XXX - see test7.c */ - if (flock.l_type != F_WRLCK) e(40); - if (flock.l_pid != getpid()) e(41); -#endif /* 0 */ - flock.l_type = F_WRLCK; - if (fcntl(fd2, F_GETLK, &flock) == -1) e(42); -#if 0 /* XXX - see test7.c */ - if (flock.l_type != F_WRLCK) e(43); - if (flock.l_pid != getpid()) e(44); -#endif /* 0 */ - if (close(fd1) != 0) e(45); - if (close(fd2) != 0) e(46); + /* Let's open bar. */ + if ((fd1 = open("bar", O_RDWR | O_CREAT, 0777)) != 3) e(1); + Stat("bar", &st1); + + /* Writing nothing should not affect the file at all. */ + if (write(fd1, "", 0) != 0) e(2); + Stat("bar", &st2); + if (st1.st_uid != st2.st_uid) e(3); + if (st1.st_gid != st2.st_gid) e(4); /* should be same */ + if (st1.st_mode != st2.st_mode) e(5); + if (st1.st_size != st2.st_size) e(6); + if (st1.st_nlink != st2.st_nlink) e(7); + if (st1.st_mtime != st2.st_mtime) e(8); + if (st1.st_ctime != st2.st_ctime) e(9); + if (st1.st_atime != st2.st_atime) e(10); + + /* A write should update some status fields. */ + time(&time1); + while (time1 >= time((time_t *)0)) + ; + if (write(fd1, "foo", 4) != 4) e(11); + Stat("bar", &st2); + if (st1.st_mode != st2.st_mode) e(12); + if (st1.st_size >= st2.st_size) e(13); + if ((off_t) 4 != st2.st_size) e(14); + if (st1.st_nlink != st2.st_nlink) e(15); + if (st1.st_mtime >= st2.st_mtime) e(16); + if (st1.st_ctime >= st2.st_ctime) e(17); + if (st1.st_atime != st2.st_atime) e(18); + + /* Lseeks should not change the file status. */ + if (lseek(fd1, (off_t) - 2, SEEK_END) != 2) e(19); + Stat("bar", &st1); + if (st1.st_mode != st2.st_mode) e(20); + if (st1.st_size != st2.st_size) e(21); + if (st1.st_nlink != st2.st_nlink) e(22); + if (st1.st_mtime != st2.st_mtime) e(23); + if (st1.st_ctime != st2.st_ctime) e(24); + if (st1.st_atime != st2.st_atime) e(25); + + /* Writing should start at the current (2) position. */ + if (write(fd1, "foo", 4) != 4) e(26); + Stat("bar", &st2); + if (st1.st_mode != st2.st_mode) e(27); + if (st1.st_size >= st2.st_size) e(28); + if ((off_t) 6 != st2.st_size) e(29); + if (st1.st_nlink != st2.st_nlink) e(30); + if (st1.st_mtime > st2.st_mtime) e(31); + if (st1.st_ctime > st2.st_ctime) e(32); + if (st1.st_atime != st2.st_atime) e(33); + + /* A read of zero bytes should not affect anything. */ + if (read(fd1, buf, 0) != 0) e(34); + Stat("bar", &st1); + if (st1.st_uid != st2.st_uid) e(35); + if (st1.st_gid != st2.st_gid) e(36); /* should be same */ + if (st1.st_mode != st2.st_mode) e(37); + if (st1.st_size != st2.st_size) e(38); + if (st1.st_nlink != st2.st_nlink) e(39); + if (st1.st_mtime != st2.st_mtime) e(40); + if (st1.st_ctime != st2.st_ctime) e(41); + if (st1.st_atime != st2.st_atime) e(42); + + /* The file now should contain ``fofoo\0'' Let's check that. */ + if (lseek(fd1, (off_t) 0, SEEK_SET) != 0) e(43); + if (read(fd1, buf, BUF_SIZE) != 6) e(44); + if (strcmp(buf, "fofoo") != 0) e(45); + + /* Only the Access Time should be updated. */ + Stat("bar", &st2); + if (st1.st_mtime != st2.st_mtime) e(46); + if (st1.st_ctime != st2.st_ctime) e(47); + if (st1.st_atime >= st2.st_atime) e(48); + + /* A read of zero bytes should do nothing even at the end of the file. */ + time(&time1); + while (time1 >= time((time_t *)0)) + ; + if (read(fd1, buf, 0) != 0) e(49); + Stat("bar", &st1); + if (st1.st_size != st2.st_size) e(50); + if (st1.st_mtime != st2.st_mtime) e(51); + if (st1.st_ctime != st2.st_ctime) e(52); + if (st1.st_atime != st2.st_atime) e(53); + + /* Reading should be done from the current offset. */ + if (read(fd1, buf, BUF_SIZE) != 0) e(54); + if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(55); + if (read(fd1, buf, BUF_SIZE) != 4) e(56); + if (strcmp(buf, "foo") != 0) e(57); + + /* Reading should effect the current file position. */ + if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(58); + if (read(fd1, buf, 1) != 1) e(59); + if (*buf != 'f') e(60); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 3) e(61); + if (read(fd1, buf, 1) != 1) e(62); + if (*buf != 'o') e(63); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 4) e(64); + if (read(fd1, buf, 1) != 1) e(65); + if (*buf != 'o') e(66); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 5) e(67); + if (read(fd1, buf, 1) != 1) e(68); + if (*buf != '\0') e(69); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(70); + + /* Read's at EOF should return 0. */ + if (read(fd1, buf, BUF_SIZE) != 0) e(71); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(72); + if (read(fd1, buf, BUF_SIZE) != 0) e(73); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(74); + if (read(fd1, buf, BUF_SIZE) != 0) e(75); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(76); + if (read(fd1, buf, BUF_SIZE) != 0) e(77); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(78); + if (read(fd1, buf, BUF_SIZE) != 0) e(79); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(80); + + /* Writing should not always change the file size. */ + if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(81); + if (write(fd1, "ba", 2) != 2) e(82); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 4) e(83); + Stat("bar", &st1); + if (st1.st_size != 6) e(84); + + /* Kill the \0 at the end. */ + if (lseek(fd1, (off_t) 5, SEEK_SET) != 5) e(85); + if (write(fd1, "x", 1) != 1) e(86); + + /* And close the bar. */ + if (close(fd1) != 0) e(87); + + /* Try some stuff with O_APPEND. Bar contains ``fobaox'' */ + if ((fd1 = open("bar", O_RDWR | O_APPEND)) != 3) e(88); + + /* No matter what the file position is. Writes should append. */ + if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(89); + if (write(fd1, "y", 1) != 1) e(90); + Stat("bar", &st1); + if (st1.st_size != (off_t) 7) e(91); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 7) e(92); + if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(93); + if (write(fd1, "z", 2) != 2) e(94); + + /* The file should contain ``fobaoxyz\0'' == 9 chars long. */ + Stat("bar", &st1); + if (st1.st_size != (off_t) 9) e(95); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 9) e(96); + + /* Reading on a O_APPEND flag should be from the current offset. */ + if (lseek(fd1, (off_t) 0, SEEK_SET) != 0) e(97); + if (read(fd1, buf, BUF_SIZE) != 9) e(98); + if (strcmp(buf, "fobaoxyz") != 0) e(99); + if (lseek(fd1, (off_t) 0, SEEK_CUR) != 9) e(100); + + if (close(fd1) != 0) e(101); + + /* Let's test fifo writes. First blocking. */ + if (mkfifo("fifo", 0777) != 0) e(102); + + /* Read from fifo but no writer. */ + System("rm -rf /tmp/sema.38a"); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + + case 0: + alarm(20); + if ((fd1 = open("fifo", O_RDONLY)) != 3) e(103); + system("> /tmp/sema.38a"); + system("while test -f /tmp/sema.38a; do sleep 1; done"); +errno =0; + if (read(fd1, buf, BUF_SIZE) != 0) e(104); + if (read(fd1, buf, BUF_SIZE) != 0) e(105); + if (read(fd1, buf, BUF_SIZE) != 0) e(106); + if (close(fd1) != 0) e(107); + exit(0); - System("rm -rf ../DIR_38/*"); + default: + if ((fd1 = open("fifo", O_WRONLY)) != 3) e(108); + while (stat("/tmp/sema.38a", &st1) != 0) sleep(1); + if (close(fd1) != 0) e(109); + unlink("/tmp/sema.38a"); + if (wait(&stat_loc) == -1) e(110); + if (stat_loc != 0) e(111); /* Alarm? */ + } + + /* Read from fifo should wait for writer. */ + switch (fork()) { + case -1: printf("Can't fork\n"); break; + + case 0: + alarm(20); + if ((fd1 = open("fifo", O_RDONLY)) != 3) e(112); + if (read(fd1, buf, BUF_SIZE) != 10) e(113); + if (strcmp(buf, "Hi reader") != 0) e(114); + if (close(fd1) != 0) e(115); + exit(0); + + default: + if ((fd1 = open("fifo", O_WRONLY)) != 3) e(116); + sleep(1); + if (write(fd1, "Hi reader", 10) != 10) e(117); + if (close(fd1) != 0) e(118); + if (wait(&stat_loc) == -1) e(119); + if (stat_loc != 0) e(120); /* Alarm? */ + } + + /* Read from fifo should wait for all writers to close. */ + switch (fork()) { + case -1: printf("Can't fork\n"); break; + + case 0: + alarm(20); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + if ((fd1 = open("fifo", O_WRONLY)) != 3) e(121); + if (close(fd1) != 0) e(122); + exit(0); + default: + if ((fd1 = open("fifo", O_WRONLY)) != 3) e(123); + sleep(1); + if (close(fd1) != 0) e(124); + if (wait(&stat_loc) == -1) e(125); + if (stat_loc != 0) e(126); /* Alarm? */ + } + exit(stat_loc); + + default: + if ((fd1 = open("fifo", O_RDONLY)) != 3) e(127); + if (read(fd1, buf, BUF_SIZE) != 0) e(128); + if (close(fd1) != 0) e(129); + if (wait(&stat_loc) == -1) e(130); + if (stat_loc != 0) e(131); /* Alarm? */ + } + + /* PIPE_BUF has to have a nice value. */ + if (PIPE_BUF < 5) e(132); + if (BUF_SIZE < 1000) e(133); + + /* Writes of blocks smaller than PIPE_BUF should be atomic. */ + System("rm -rf /tmp/sema.38b;> /tmp/sema.38b"); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + + case 0: + alarm(20); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + + case 0: + alarm(20); + if ((fd1 = open("fifo", O_WRONLY)) != 3) e(134); + for (i = 0; i < 100; i++) write(fd1, "1234 ", 5); + system("while test -f /tmp/sema.38b; do sleep 1; done"); + if (close(fd1) != 0) e(135); + exit(0); + + default: + if ((fd1 = open("fifo", O_WRONLY)) != 3) e(136); + for (i = 0; i < 100; i++) write(fd1, "1234 ", 5); + while (stat("/tmp/sema.38b", &st1) == 0) sleep(1); + if (close(fd1) != 0) e(137); + if (wait(&stat_loc) == -1) e(138); + if (stat_loc != 0) e(139); /* Alarm? */ + } + exit(stat_loc); + + default: + if ((fd1 = open("fifo", O_RDONLY)) != 3) e(140); + i = 0; + memset(buf, '\0', BUF_SIZE); + + /* Read buffer full or till EOF. */ + do { + j = read(fd1, buf + i, BUF_SIZE - i); + if (j > 0) { + if (j % 5 != 0) e(141); + i += j; + } + } while (j > 0 && i < 1000); + + /* Signal the children to close write ends. This should not be */ + /* Necessary. But due to a bug in 1.16.6 this is necessary. */ + unlink("/tmp/sema.38b"); + if (j < 0) e(142); + if (i != 1000) e(143); + if (wait(&stat_loc) == -1) e(144); + if (stat_loc != 0) e(145); /* Alarm? */ + + /* Check 200 times 1234. */ + for (i = 0; i < 200; i++) + if (strncmp(buf + (i * 5), "1234 ", 5) != 0) break; + if (i != 200) e(146); + if (buf[1000] != '\0') e(147); + if (buf[1005] != '\0') e(148); + if (buf[1010] != '\0') e(149); + if (read(fd1, buf, BUF_SIZE) != 0) e(150); + if (close(fd1) != 0) e(151); + } + + /* Read from pipe should wait for writer. */ + if (pipe(tube) != 0) e(152); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + if (close(tube[1]) != 0) e(153); + if (read(tube[0], buf, BUF_SIZE) != 10) e(154); + if (strcmp(buf, "Hi reader") != 0) e(155); + if (close(tube[0]) != 0) e(156); + exit(0); + default: + if (close(tube[0]) != 0) e(157); + sleep(1); + if (write(tube[1], "Hi reader", 10) != 10) e(158); + if (close(tube[1]) != 0) e(159); + if (wait(&stat_loc) == -1) e(160); + if (stat_loc != 0) e(161); /* Alarm? */ + } + + /* Read from pipe should wait for all writers to close. */ + if (pipe(tube) != 0) e(162); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + if (close(tube[0]) != 0) e(163); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + if (close(tube[1]) != 0) e(164); + exit(0); + default: + sleep(1); + if (close(tube[1]) != 0) e(165); + if (wait(&stat_loc) == -1) e(166); + if (stat_loc != 0) e(167); /* Alarm? */ + } + exit(stat_loc); + default: + if (close(tube[1]) != 0) e(168); + if (read(tube[0], buf, BUF_SIZE) != 0) e(169); + if (close(tube[0]) != 0) e(170); + if (wait(&stat_loc) == -1) e(171); + if (stat_loc != 0) e(172); /* Alarm? */ + } + + /* Writes of blocks smaller than PIPE_BUF should be atomic. */ + System("rm -rf /tmp/sema.38c;> /tmp/sema.38c"); + if (pipe(tube) != 0) e(173); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + if (close(tube[0]) != 0) e(174); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + for (i = 0; i < 100; i++) write(tube[1], "1234 ", 5); + system("while test -f /tmp/sema.38c; do sleep 1; done"); + if (close(tube[1]) != 0) e(175); + exit(0); + default: + for (i = 0; i < 100; i++) write(tube[1], "1234 ", 5); + while (stat("/tmp/sema.38c", &st1) == 0) sleep(1); + if (close(tube[1]) != 0) e(176); + if (wait(&stat_loc) == -1) e(177); + if (stat_loc != 0) e(178); /* Alarm? */ + } + exit(stat_loc); + default: + i = 0; + if (close(tube[1]) != 0) e(179); + memset(buf, '\0', BUF_SIZE); + do { + j = read(tube[0], buf + i, BUF_SIZE - i); + if (j > 0) { + if (j % 5 != 0) e(180); + i += j; + } else + break; /* EOF seen. */ + } while (i < 1000); + unlink("/tmp/sema.38c"); + if (j < 0) e(181); + if (i != 1000) e(182); + if (close(tube[0]) != 0) e(183); + if (wait(&stat_loc) == -1) e(184); + if (stat_loc != 0) e(185); /* Alarm? */ + + /* Check 200 times 1234. */ + for (i = 0; i < 200; i++) + if (strncmp(buf + (i * 5), "1234 ", 5) != 0) break; + if (i != 200) e(186); + } } void test38b() { - int fd; - char buf[32]; + int i, fd, stat_loc; + char buf[BUF_SIZE]; + char buf2[BUF_SIZE]; + struct stat st; subtest = 2; - - /* Test file called ``file''. */ - System("echo 'Hallo!' > file"); - - /* Check dup2() call with the same fds. Should have no effect. */ - if ((fd = open("file", O_RDONLY)) != 3) e(1); - if (read(fd, buf, 2) != 2) e(2); - if (strncmp(buf, "Ha", 2) != 0) e(3); - if (dup2(fd, fd) != fd) e(4); - if (read(fd, buf, 2) != 2) e(5); - if (strncmp(buf, "ll", 2) != 0) e(6); - if (dup2(fd, fd) != fd) e(7); - if (read(fd, buf, 2) != 2) e(8); - if (strncmp(buf, "o!", 2) != 0) e(9); - if (close(fd) != 0) e(10); - - /* If dup2() call fails, the fildes2 argument has to stay open. */ - if ((fd = open("file", O_RDONLY)) != 3) e(11); - if (read(fd, buf, 2) != 2) e(12); - if (strncmp(buf, "Ha", 2) != 0) e(13); - if (dup2(OPEN_MAX + 3, fd) != -1) e(14); - if (errno != EBADF) e(15); - if (read(fd, buf, 2) != 2) e(16); - if (strncmp(buf, "ll", 2) != 0) e(17); - if (dup2(-4, fd) != -1) e(18); - if (errno != EBADF) e(19); - if (read(fd, buf, 2) != 2) e(20); - if (strncmp(buf, "o!", 2) != 0) e(21); - if (close(fd) != 0) e(22); - System("rm -rf ../DIR_38/*"); + + /* Lets try sequential writes. */ + system("rm -rf /tmp/sema.38d"); + System("> testing"); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(1); + if (write(fd, "one ", 4) != 4) e(2); + if (close(fd) != 0) e(3); + system("> /tmp/sema.38d"); + system("while test -f /tmp/sema.38d; do sleep 1; done"); + if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(4); + if (write(fd, "three ", 6) != 6) e(5); + if (close(fd) != 0) e(6); + system("> /tmp/sema.38d"); + exit(0); + default: + while (stat("/tmp/sema.38d", &st) != 0) sleep(1); + if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(7); + if (write(fd, "two ", 4) != 4) e(8); + if (close(fd) != 0) e(9); + unlink("/tmp/sema.38d"); + while (stat("/tmp/sema.38d", &st) != 0) sleep(1); + if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(10); + if (write(fd, "four", 5) != 5) e(11); + if (close(fd) != 0) e(12); + if (wait(&stat_loc) == -1) e(13); + if (stat_loc != 0) e(14); /* The alarm went off? */ + unlink("/tmp/sema.38d"); + } + if ((fd = open("testing", O_RDONLY)) != 3) e(15); + if (read(fd, buf, BUF_SIZE) != 19) e(16); + if (strcmp(buf, "one two three four") != 0) e(17); + if (close(fd) != 0) e(18); + + /* Non written bytes in regular files should be zero. */ + memset(buf2, '\0', BUF_SIZE); + if ((fd = open("bigfile", O_RDWR | O_CREAT, 0644)) != 3) e(19); + if (lseek(fd, (off_t) 102400, SEEK_SET) != (off_t) 102400L) e(20); + if (read(fd, buf, BUF_SIZE) != 0) e(21); + if (write(fd, ".", 1) != 1) e(22); + Stat("bigfile", &st); + if (st.st_size != (off_t) 102401) e(23); + if (lseek(fd, (off_t) 0, SEEK_SET) != 0) e(24); + for (i = 0; i < 102400 / BUF_SIZE; i++) { + if (read(fd, buf, BUF_SIZE) != BUF_SIZE) e(25); + if (memcmp(buf, buf2, BUF_SIZE) != 0) e(26); + } + if (close(fd) != 0) e(27); } void test38c() -{ - int i; +{ /* Test correct error behavior. */ + char buf[BUF_SIZE]; + int fd, tube[2], stat_loc; + struct stat st; + pid_t pid; +#ifdef SIGACTION + struct sigaction act, oact; +#else +#if _ANSI + void (*oldfunc) (int); +#else + void (*oldfunc) (); +#endif +#endif subtest = 3; + System("rm -rf ../DIR_38/*"); - /* Check bad arguments to dup() and dup2(). */ - for (i = -OPEN_MAX; i < OPEN_MAX * 2; i++) { - - /* ``i'' is a valid and open fd. */ - if (i >= 0 && i < 3) continue; + /* To test if writing processes on closed pipes are signumbered. */ +#ifdef SIGACTION + act.sa_handler = setsignumber; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGPIPE, &act, &oact) != 0) e(1); +#else + oldfunc = signal(SIGPIPE, setsignumber); +#endif + + /* Non valid file descriptors should be an error. */ + for (fd = -111; fd < 0; fd++) { + errno = 0; + if (read(fd, buf, BUF_SIZE) != -1) e(2); + if (errno != EBADF) e(3); + } + for (fd = 3; fd < 111; fd++) { + errno = 0; + if (read(fd, buf, BUF_SIZE) != -1) e(4); + if (errno != EBADF) e(5); + } + for (fd = -111; fd < 0; fd++) { + errno = 0; + if (write(fd, buf, BUF_SIZE) != -1) e(6); + if (errno != EBADF) e(7); + } + for (fd = 3; fd < 111; fd++) { + errno = 0; + if (write(fd, buf, BUF_SIZE) != -1) e(8); + if (errno != EBADF) e(9); + } - /* If ``i'' is a valid fd it is not open. */ - if (dup(i) != -1) e(1); - if (errno != EBADF) e(2); + /* Writing a pipe with no readers should trigger SIGPIPE. */ + if (pipe(tube) != 0) e(10); + close(tube[0]); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + signumber = 0; + if (write(tube[1], buf, BUF_SIZE) != -1) e(11); + if (errno != EPIPE) e(12); + if (signumber != SIGPIPE) e(13); + if (close(tube[1]) != 0) e(14); + exit(0); + default: + close(tube[1]); + if (wait(&stat_loc) == -1) e(15); + if (stat_loc != 0) e(16); /* Alarm? */ + } - /* ``i'' Is OPEN_MAX. */ - if (i == OPEN_MAX) { - if (dup2(0, i) != -1) e(3); - if (errno != EINVAL) e(4); - } + /* Writing a fifo with no readers should trigger SIGPIPE. */ + System("> /tmp/sema.38e"); + if (mkfifo("fifo", 0666) != 0) e(17); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + if ((fd = open("fifo", O_WRONLY)) != 3) e(18); + system("while test -f /tmp/sema.38e; do sleep 1; done"); + signumber = 0; + if (write(fd, buf, BUF_SIZE) != -1) e(19); + if (errno != EPIPE) e(20); + if (signumber != SIGPIPE) e(21); + if (close(fd) != 0) e(22); + exit(0); + default: + if ((fd = open("fifo", O_RDONLY)) != 3) e(23); + if (close(fd) != 0) e(24); + unlink("/tmp/sema.38e"); + if (wait(&stat_loc) == -1) e(25); + if (stat_loc != 0) e(26); /* Alarm? */ + } - /* ``i'' Is out of range. */ - if (i < 0 || i > OPEN_MAX) { - if (dup2(0, i) != -1) e(5); - if (errno != EBADF) e(6); - } +#ifdef SIGACTION + /* Restore normal (re)action to SIGPIPE. */ + if (sigaction(SIGPIPE, &oact, NULL) != 0) e(27); +#else + signal(SIGPIPE, oldfunc); +#endif + + /* Read from fifo should return -1 and set errno to EAGAIN. */ + System("rm -rf /tmp/sema.38[fgh]"); + switch (fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); + system("while test ! -f /tmp/sema.38f; do sleep 1; done"); + System("rm -rf /tmp/sema.38f"); + if ((fd = open("fifo", O_WRONLY | O_NONBLOCK)) != 3) e(28); + close(creat("/tmp/sema.38g", 0666)); + system("while test ! -f /tmp/sema.38h; do sleep 1; done"); + if (close(fd) != 0) e(38); + System("rm -rf /tmp/sema.38h"); + exit(0); + default: + if ((fd = open("fifo", O_RDONLY | O_NONBLOCK)) != 3) e(30); + close(creat("/tmp/sema.38f", 0666)); + system("while test ! -f /tmp/sema.38g; do sleep 1; done"); + System("rm -rf /tmp/sema.38g"); + if (read(fd, buf, BUF_SIZE) != -1) e(31); + if (errno != EAGAIN) e(32); + if (read(fd, buf, BUF_SIZE) != -1) e(33); + if (errno != EAGAIN) e(34); + if (read(fd, buf, BUF_SIZE) != -1) e(35); + if (errno != EAGAIN) e(36); + close(creat("/tmp/sema.38h", 0666)); + while (stat("/tmp/sema.38h", &st) == 0) sleep(1); + if (read(fd, buf, BUF_SIZE) != 0) e(37); + if (close(fd) != 0) e(38); + if (wait(&stat_loc) == -1) e(39); + if (stat_loc != 0) e(40); /* Alarm? */ + } + System("rm -rf fifo"); + + /* If a read is interrupted by a SIGNAL. */ + if (pipe(tube) != 0) e(41); + switch (pid = fork()) { + case -1: printf("Can't fork\n"); break; + case 0: + alarm(20); +#ifdef SIGACTION + act.sa_handler = setsignumber; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGUSR1, &act, &oact) != 0) e(42); +#else + oldfunc = signal(SIGUSR1, setsignumber); +#endif + if (read(tube[0], buf, BUF_SIZE) != -1) e(43); + if (errno != EINTR) e(44); + if (signumber != SIGUSR1) e(45); +#ifdef SIGACTION + /* Restore normal (re)action to SIGPIPE. */ + if (sigaction(SIGUSR1, &oact, NULL) != 0) e(46); +#else + signal(SIGUSR1, oldfunc); +#endif + close(tube[0]); + close(tube[1]); + exit(0); + default: + /* The sleep 1 should give the child time to start the read. */ + sleep(1); + close(tube[0]); + kill(pid, SIGUSR1); + wait(&stat_loc); + if (stat_loc != 0) e(47); /* Alarm? */ + close(tube[1]); } +} - System("rm -rf ../DIR_38/*"); +void setsignumber(signum) +int signum; +{ + signumber = signum; } void e(n) diff --git a/test/test39.c b/test/test39.c index 50cc15ed1..2c2241691 100644 --- a/test/test39.c +++ b/test/test39.c @@ -1,375 +1,702 @@ -/* test39: fcntl() Author: Jan-Mark Wams (jms@cs.vu.nl) */ - -/* Some things have to be checked for ``exec()'' call's. Therefor -** there is a check routine called ``do_check()'' that will be -** called if the first argument (``argv[0]'') equals ``DO CHECK.'' -** Note that there is no way the shell (``/bin/sh'') will set -** ``argv[0]'' to this funny value. (Unless we rename ``test39'' -** to ``DO CHECK'' ;-) -*/ +/* POSIX test program (39). Author: Andy Tanenbaum */ + +/* The following POSIX calls are tested: + * + * opendir() + * readdir() + * rewinddir() + * closedir() + * chdir() + * getcwd() + */ #include #include -#include -#include -#include -#include +#include #include -#include #include +#include +#include +#include #include +#include +#include #include -#define MAX_ERROR 4 -#define ITERATIONS 10 +#define DIR_NULL (DIR*) NULL +#define ITERATIONS 3 /* LINK_MAX is high, so time consuming */ +#define MAX_FD 100 /* must be large enough to cause error */ +#define BUF_SIZE PATH_MAX+20 +#define ERR_CODE -1 /* error return */ +#define RD_BUF 200 +#define MAX_ERROR 4 -#define System(cmd) if (system(cmd) != 0) printf("``%s'' failed\n", cmd) -#define Chdir(dir) if (chdir(dir) != 0) printf("Can't goto %s\n", dir) -#define Stat(a,b) if (stat(a,b) != 0) printf("Can't stat %s\n", a) +char str[] = {"The time has come the walrus said to talk of many things.\n"}; +char str2[] = {"Of ships and shoes and sealing wax, of cabbages and kings.\n"}; +char str3[] = {"Of why the sea is boiling hot and whether pigs have wings\n"}; -int errct = 0; -int subtest = 1; -int superuser; -char MaxName[NAME_MAX + 1]; /* Name of maximum length */ -char MaxPath[PATH_MAX]; /* Same for path */ -char ToLongName[NAME_MAX + 2]; /* Name of maximum +1 length */ -char ToLongPath[PATH_MAX + 1]; /* Same for path, both too long */ +int subtest, errct; -_PROTOTYPE(void main, (int argc, char *argv[])); +_PROTOTYPE(int main, (int argc, char *argv [])); _PROTOTYPE(void test39a, (void)); +_PROTOTYPE(void checkdir, (DIR *dirp, int t)); _PROTOTYPE(void test39b, (void)); _PROTOTYPE(void test39c, (void)); _PROTOTYPE(void test39d, (void)); -_PROTOTYPE(int do_check, (void)); -_PROTOTYPE(void makelongnames, (void)); -_PROTOTYPE(void e, (int number)); +_PROTOTYPE(void test39e, (void)); +_PROTOTYPE(void test39f, (void)); +_PROTOTYPE(void test39g, (void)); +_PROTOTYPE(void test39h, (void)); +_PROTOTYPE(void test39i, (void)); +_PROTOTYPE(void test39j, (void)); +_PROTOTYPE(void e, (int n)); _PROTOTYPE(void quit, (void)); -char executable[1024]; - -void main(argc, argv) +int main(argc, argv) int argc; char *argv[]; { + int i, m = 0xFFFF; sync(); - if (argc == 2) m = atoi(argv[1]); - - /* If we have to check things, call do_check(). */ - if (strcmp(argv[0], "DO CHECK") == 0) exit(do_check()); - - /* Get the path of the executable. */ - strcpy(executable, "../"); - strcat(executable, argv[0]); + if (geteuid() == 0 || getuid() == 0) { + printf("Test 39 cannot run as root; test aborted\n"); + exit(1); + } + if (argc == 2) m = atoi(argv[1]); printf("Test 39 "); fflush(stdout); - System("rm -rf DIR_39; mkdir DIR_39"); - Chdir("DIR_39"); - makelongnames(); - superuser = (geteuid() == 0); + + system("rm -rf DIR_39; mkdir DIR_39"); + chdir("DIR_39"); for (i = 0; i < ITERATIONS; i++) { - test39a(); - test39b(); - test39c(); - test39d(); + if (m & 00001) test39a(); /* test for correct operation */ + if (m & 00002) test39b(); /* test general error handling */ + if (m & 00004) test39c(); /* test for EMFILE error */ + if (m & 00010) test39d(); /* test chdir() and getcwd() */ + if (m & 00020) test39e(); /* test open() */ + if (m & 00040) test39f(); /* test umask(), stat(), fstat() */ + if (m & 00100) test39g(); /* test link() and unlink() */ + if (m & 00200) test39h(); /* test access() */ + if (m & 00400) test39i(); /* test chmod() and chown() */ + if (m & 01000) test39j(); /* test utime() */ } quit(); + return(-1); /* impossible */ } void test39a() -{ /* Test normal operation. */ +{ +/* Subtest 1. Correct operation */ + + int f1, f2, f3, f4, f5; + DIR *dirp; + + /* Remove any residue of previous tests. */ subtest = 1; - System("rm -rf ../DIR_39/*"); + + system("rm -rf foo"); + + /* Create a directory foo with 5 files in it. */ + mkdir("foo", 0777); + if ((f1 = creat("foo/f1", 0666)) < 0) e(1); + if ((f2 = creat("foo/f2", 0666)) < 0) e(2); + if ((f3 = creat("foo/f3", 0666)) < 0) e(3); + if ((f4 = creat("foo/f4", 0666)) < 0) e(4); + if ((f5 = creat("foo/f5", 0666)) < 0) e(5); + + /* Now remove 2 files to create holes in the directory. */ + if (unlink("foo/f2") < 0) e(6); + if (unlink("foo/f4") < 0) e(7); + + /* Close the files. */ + close(f1); + close(f2); + close(f3); + close(f4); + close(f5); + + /* Open the directory. */ + dirp = opendir("./foo"); + if (dirp == DIR_NULL) e(6); + + /* Read the 5 files from it. */ + checkdir(dirp, 2); + + /* Rewind dir and test again. */ + rewinddir(dirp); + checkdir(dirp, 3); + + /* We're done. Close the directory stream. */ + if (closedir(dirp) < 0) e(7); + + /* Remove dir for next time. */ + system("rm -rf foo"); +} + +void checkdir(dirp, t) +DIR *dirp; /* poinrter to directory stream */ +int t; /* subtest number to use */ +{ + + int i, f1, f2, f3, f4, f5, dot, dotdot, subt; + struct dirent *d; + char *s; + + /* Save subtest number */ + subt = subtest; + subtest = t; + + /* Clear the counters. */ + f1 = 0; + f2 = 0; + f3 = 0; + f4 = 0; + f5 = 0; + dot = 0; + dotdot = 0; + + /* Read the directory. It should contain 5 entries, ".", ".." and 3 + * files. */ + for (i = 0; i < 5; i++) { + d = readdir(dirp); + if (d == (struct dirent *) NULL) { + e(1); + subtest = subt; /* restore subtest number */ + return; + } + s = d->d_name; + if (strcmp(s, ".") == 0) dot++; + if (strcmp(s, "..") == 0) dotdot++; + if (strcmp(s, "f1") == 0) f1++; + if (strcmp(s, "f2") == 0) f2++; + if (strcmp(s, "f3") == 0) f3++; + if (strcmp(s, "f4") == 0) f4++; + if (strcmp(s, "f5") == 0) f5++; + } + + /* Check results. */ + d = readdir(dirp); + if (d != (struct dirent *) NULL) e(2); + if (f1 != 1 || f3 != 1 || f5 != 1) e(3); + if (f2 != 0 || f4 != 0) e(4); + if (dot != 1 || dotdot != 1) e(5); + subtest = subt; + return; } void test39b() { - subtest = 2; - System("rm -rf ../DIR_39/*"); +/* Subtest 4. Test error handling. */ + + int fd; + DIR *dirp; + + subtest = 4; + + if (opendir("foo/xyz/---") != DIR_NULL) e(1); + if (errno != ENOENT) e(2); + if (mkdir("foo", 0777) < 0) e(3); + if (chmod("foo", 0) < 0) e(4); + if (opendir("foo/xyz/--") != DIR_NULL) e(5); + if (errno != EACCES) e(6); + if (chmod("foo", 0777) != 0) e(7); + if (rmdir("foo") != 0) e(8); + if ((fd = creat("abc", 0666)) < 0) e(9); + if (close(fd) < 0) e(10); + if (opendir("abc/xyz") != DIR_NULL) e(11); + if (errno != ENOTDIR) e(12); + if ((dirp = opendir(".")) == DIR_NULL) e(13); + if (closedir(dirp) != 0) e(14); + if (unlink("abc") != 0) e(15); + } void test39c() { - subtest = 3; - System("rm -rf ../DIR_39/*"); +/* Subtest 5. See what happens if we open too many directory streams. */ + + int i, j; + DIR *dirp[MAX_FD]; + + subtest = 5; + + for (i = 0; i < MAX_FD; i++) { + dirp[i] = opendir("."); + if (dirp[i] == (DIR *) NULL) { + /* We have hit the limit. */ + if (errno != EMFILE && errno != ENOMEM) e(1); + for (j = 0; j < i; j++) { + if (closedir(dirp[j]) != 0) e(2); /* close */ + } + return; + } + } + + /* Control should never come here. This is an error. */ + e(3); + for (i = 0; i < MAX_FD; i++) closedir(dirp[i]); /* don't check */ } -/* Open fds 3, 4, 5 and 6. Set FD_CLOEXEC on 5 and 6. Exclusively lock the -** first 10 bytes of fd no. 3. Shared lock fd no. 7. Lock fd no. 8 after -** the fork. Do a ``exec()'' call with a funny argv[0] and check the return -** value. -*/ void test39d() -{ /* Test locks with ``fork()'' and ``exec().'' */ - int fd3, fd4, fd5, fd6, fd7, fd8; - int stat_loc; - int do_check_retval; - char *argv[2]; - struct flock fl; +{ +/* Test chdir and getcwd(). */ + + int fd; + char *s; + char base[BUF_SIZE], buf2[BUF_SIZE], tmp[BUF_SIZE]; + + subtest = 6; + + if (getcwd(base, BUF_SIZE) == (char *) NULL) e(1); /* get test dir's path */ + if (system("rm -rf Dir") != 0) e(2); /* remove residue of previous test */ + if (mkdir("Dir", 0777) < 0) e(3); /* create directory called "Dir" */ + + /* Change to Dir and verify that it worked. */ + if (chdir("Dir") < 0) e(4); /* go to Dir */ + s = getcwd(buf2, BUF_SIZE); /* get full path of Dir */ + if (s == (char *) NULL) e(5); /* check for error return */ + if (s != buf2) e(6); /* if successful, first arg is returned */ + strcpy(tmp, base); /* concatenate base name and "/Dir" */ + strcat(tmp, "/"); + strcat(tmp, "Dir"); + if (strcmp(tmp, s) != 0) e(7); + + /* Change to ".." and verify that it worked. */ + if (chdir("..") < 0) e(8); + if (getcwd(buf2, BUF_SIZE) != buf2) e(9); + if (strcmp(buf2, base) != 0) e(10); + + /* Now make calls that do nothing, but do it in a strange way. */ + if (chdir("Dir/..") < 0) e(11); + if (getcwd(buf2, BUF_SIZE) != buf2) e(12); + if (strcmp(buf2, base) != 0) e(13); + + if (chdir("Dir/../Dir/..") < 0) e(14); + if (getcwd(buf2, BUF_SIZE) != buf2) e(15); + if (strcmp(buf2, base) != 0) e(16); + + if (chdir("Dir/../Dir/../Dir/../Dir/../Dir/../Dir/../Dir/..") < 0) e(17); + if (getcwd(buf2, BUF_SIZE) != buf2) e(18); + if (strcmp(buf2, base) != 0) e(19); + + /* Make Dir unreadable and unsearchable. Check error message. */ + if (chmod("Dir", 0) < 0) e(20); + if (chdir("Dir") >= 0) e(21); + if (errno != EACCES) e(22); + + /* Check error message for bad path. */ + if (chmod("Dir", 0777) < 0) e(23); + if (chdir("Dir/x/y") != ERR_CODE) e(24); + if (errno != ENOENT) e(25); + + if ( (fd=creat("Dir/x", 0777)) < 0) e(26); + if (close(fd) != 0) e(27); + if (chdir("Dir/x/y") != ERR_CODE) e(28); + if (errno != ENOTDIR) e(29); + + /* Check empty string. */ + if (chdir("") != ERR_CODE) e(30); + if (errno != ENOENT) e(31); + + /* Remove the directory. */ + if (unlink("Dir/x") != 0) e(32); + if (system("rmdir Dir") != 0) e(33); +} - subtest = 4; +void test39e() +{ +/* Test open. */ + + int fd, bytes, bytes2; + char buf[RD_BUF]; + + subtest = 7; + + unlink("T39"); /* get rid of it in case it exists */ + + /* Create a test file. */ + bytes = strlen(str); + bytes2 = strlen(str2); + if ((fd = creat("T39", 0777)) < 0) e(1); + if (write(fd, str, bytes) != bytes) e(2); /* T39 now has 'bytes' bytes */ + if (close(fd) != 0) e(3); + + /* Test opening a file with O_RDONLY. */ + if ((fd = open("T39", O_RDONLY)) < 0) e(4); + buf[0] = '\0'; + if (read(fd, buf, RD_BUF) != bytes) e(5); + if (strncmp(buf, str, bytes) != 0) e(6); + if (close(fd) < 0) e(7); + + /* Test the same thing, only with O_RDWR now. */ + if ((fd = open("T39", O_RDWR)) < 0) e(8); + buf[0] = '\0'; + if (read(fd, buf, RD_BUF) != bytes) e(9); + if (strncmp(buf, str, bytes) != 0) e(10); + if (close(fd) < 0) e(11); + + /* Try opening and reading with O_WRONLY. It should fail. */ + if ((fd = open("T39", O_WRONLY)) < 0) e(12); + buf[0] = '\0'; + if (read(fd, buf, RD_BUF) >= 0) e(13); + if (close(fd) != 0) e(14); + + /* Test O_APPEND. */ + if ((fd = open("T39", O_RDWR | O_APPEND)) < 0) e(15); + if (lseek(fd, 0L, SEEK_SET) < 0) e(16); /* go to start of file */ + if ( write(fd, str2, bytes2) != bytes2) e(17); /* write at start of file */ + if (lseek(fd, 0L, SEEK_SET) < 0) e(18); /* go back to start again */ + if (read(fd, buf, RD_BUF) != bytes + bytes2) e(19); /* read whole file */ + if (strncmp(buf, str, bytes) != 0) e(20); + if (close(fd) != 0) e(21); + + /* Get rid of the file. */ + if (unlink("T39") < 0) e(22); +} - argv[0] = "DO CHECK"; - argv[1] = (char *) NULL; - - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 10; - - /* Make a dummy files and open them. */ - System("echo 'Great Balls Of Fire!' > file3"); - System("echo 'Great Balls Of Fire!' > file4"); - System("echo 'Great Balls Of Fire!' > file7"); - System("echo 'Great Balls Of Fire!' > file8"); - System("echo 'Great Balls Of Fire!' > file"); - if ((fd3 = open("file3", O_RDWR)) != 3) e(1); - if ((fd4 = open("file4", O_RDWR)) != 4) e(2); - if ((fd5 = open("file", O_RDWR)) != 5) e(3); - if ((fd6 = open("file", O_RDWR)) != 6) e(4); - if ((fd7 = open("file7", O_RDWR)) != 7) e(5); - if ((fd8 = open("file8", O_RDWR)) != 8) e(6); - - /* Set FD_CLOEXEC flags on fd5 and fd6. */ - if (fcntl(fd5, F_SETFD, FD_CLOEXEC) == -1) e(7); - if (fcntl(fd6, F_SETFD, FD_CLOEXEC) == -1) e(8); - - /* Lock the first ten bytes from fd3 (for writing). */ - fl.l_type = F_WRLCK; - if (fcntl(fd3, F_SETLK, &fl) == -1) e(9); - - /* Lock (for reading) fd7. */ - fl.l_type = F_RDLCK; - if (fcntl(fd7, F_SETLK, &fl) == -1) e(10); - - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - - /* Lock fd8. */ - fl.l_type = F_WRLCK; - if (fcntl(fd8, F_SETLK, &fl) == -1) e(11); - - /* Check the lock on fd3 and fd7. */ - fl.l_type = F_WRLCK; - if (fcntl(fd3, F_GETLK, &fl) == -1) e(12); - if (fl.l_type != F_WRLCK) e(13); - if (fl.l_pid != getppid()) e(14); - fl.l_type = F_WRLCK; - if (fcntl(fd7, F_GETLK, &fl) == -1) e(15); - if (fl.l_type != F_RDLCK) e(16); - if (fl.l_pid != getppid()) e(17); - - /* Check FD_CLOEXEC flags. */ - if ((fcntl(fd3, F_GETFD) & FD_CLOEXEC) != 0) e(18); - if ((fcntl(fd4, F_GETFD) & FD_CLOEXEC) != 0) e(19); - if ((fcntl(fd5, F_GETFD) & FD_CLOEXEC) != FD_CLOEXEC) e(20); - if ((fcntl(fd6, F_GETFD) & FD_CLOEXEC) != FD_CLOEXEC) e(21); - if ((fcntl(fd7, F_GETFD) & FD_CLOEXEC) != 0) e(22); - if ((fcntl(fd8, F_GETFD) & FD_CLOEXEC) != 0) e(23); - - execlp(executable + 3, "DO CHECK", (char *) NULL); - execlp(executable, "DO CHECK", (char *) NULL); - printf("Can't exec %s or %s\n", executable + 3, executable); - exit(0); +void test39f() +{ +/* Test stat, fstat, umask. */ + int i, fd; + mode_t m1; + struct stat stbuf1, stbuf2; + time_t t, t1; + + subtest = 8; + + m1 = umask(~0777); + if (system("rm -rf foo xxx") != 0) e(1); + if ((fd = creat("foo", 0777)) < 0) e(2); + if (stat("foo", &stbuf1) < 0) e(3); + if (fstat(fd, &stbuf2) < 0) e(4); + if (stbuf1.st_mode != stbuf2.st_mode) e(5); + if (stbuf1.st_ino != stbuf2.st_ino) e(6); + if (stbuf1.st_dev != stbuf2.st_dev) e(7); + if (stbuf1.st_nlink != stbuf2.st_nlink) e(8); + if (stbuf1.st_uid != stbuf2.st_uid) e(9); + if (stbuf1.st_gid != stbuf2.st_gid) e(10); + if (stbuf1.st_size != stbuf2.st_size) e(11); + if (stbuf1.st_atime != stbuf2.st_atime) e(12); + if (stbuf1.st_mtime != stbuf2.st_mtime) e(13); + if (stbuf1.st_ctime != stbuf2.st_ctime) e(14); + + if (!S_ISREG(stbuf1.st_mode)) e(15); + if (S_ISDIR(stbuf1.st_mode)) e(16); + if (S_ISCHR(stbuf1.st_mode)) e(17); + if (S_ISBLK(stbuf1.st_mode)) e(18); + if (S_ISFIFO(stbuf1.st_mode)) e(19); + + if ((stbuf1.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) != 0777) e(20); + if (stbuf1.st_nlink != 1) e(21); + if (stbuf1.st_uid != getuid()) e(22); + if (stbuf1.st_gid != getgid()) e(23); + if (stbuf1.st_size != 0L) e(24); + + /* First unlink, then close -- harder test */ + if (unlink("foo") < 0) e(25); + if (close(fd) < 0) e(26); + + /* Now try umask a bit more. */ + fd = 0; + if ((i = umask(~0704)) != 0) e(27); + if ((fd = creat("foo", 0777)) < 0) e(28); + if (stat("foo", &stbuf1) < 0) e(29); + if (fstat(fd, &stbuf2) < 0) e(30); + if (stbuf1.st_mode != stbuf2.st_mode) e(31); + if ((stbuf1.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) != 0704) e(32); + + /* First unlink, then close -- harder test */ + if (unlink("foo") < 0) e(33); + if (close(fd) < 0) e(34); + if (umask(m1) != 073) e(35); + + /* Test some errors. */ + if (system("mkdir Dir; date >Dir/x; chmod 666 Dir") != 0) e(36); + if (stat("Dir/x", &stbuf1) >= 0) e(37); + if (errno != EACCES) e(38); + if (stat("......", &stbuf1) >= 0) e(39); + if (errno != ENOENT) e(40); + if (stat("", &stbuf1) >= 0) e(41); + if (errno != ENOENT) e(42); + if (stat("xxx/yyy/zzz", &stbuf1) >= 0) e(43); + if (errno != ENOENT) e(44); + if (fstat(10000, &stbuf1) >= 0) e(45); + if (errno != EBADF) e(46); + if (chmod("Dir", 0777) != 0) e(47); + if (system("rm -rf foo Dir") != 0) e(48); + + /* See if time looks reasonable. */ + errno = 0; + t = time(&t1); /* current time */ + if (t < 650000000L) e(49); /* 650000000 is Sept. 1990 */ + unlink("T39f"); + fd = creat("T39f", 0777); + if (fd < 0) e(50); + if (close(fd) < 0) e(51); + if (stat("T39f", &stbuf1) < 0) e(52); + if (stbuf1.st_mtime < t) e(53); + if (unlink("T39f") < 0) e(54); +} - default: - wait(&stat_loc); - if (WIFSIGNALED(stat_loc)) e(24); /* Alarm? */ - if (WIFEXITED(stat_loc) == 0) { - errct=10000; - quit(); - } +void test39g() +{ +/* Test link and unlink. */ + int i, fd; + struct stat stbuf; + char name[20]; + + subtest = 9; + + if (system("rm -rf L? L?? Dir; mkdir Dir") != 0) e(1); + if ( (fd = creat("L1", 0666)) < 0) e(2); + if (fstat(fd, &stbuf) != 0) e(3); + if (stbuf.st_nlink != 1) e(4); + if (link("L1", "L2") != 0) e(5); + if (fstat(fd, &stbuf) != 0) e(6); + if (stbuf.st_nlink != 2) e(7); + if (unlink("L2") != 0) e(8); + if (link("L1", "L2") != 0) e(9); + if (unlink("L1") != 0) e(10); + if (close(fd) != 0) e(11); + + /* L2 exists at this point. */ + if ( (fd = creat("L1", 0666)) < 0) e(12); + if (stat("L1", &stbuf) != 0) e(13); + if (stbuf.st_nlink != 1) e(14); + if (link("L1", "Dir/L2") != 0) e(15); + if (stat("L1", &stbuf) != 0) e(16); + if (stbuf.st_nlink != 2) e(17); + if (stat("Dir/L2", &stbuf) != 0) e(18); + if (stbuf.st_nlink != 2) e(19); + + /* L1, L2, and Dir/L2 exist at this point. */ + if (unlink("Dir/L2") != 0) e(20); + if (link("L1", "Dir/L2") != 0) e(21); + if (unlink("L1") != 0) e(22); + if (close(fd) != 0) e(23); + if (chdir("Dir") != 0) e(24); + if (unlink("L2") != 0) e(25); + if (chdir("..") != 0) e(26); + + /* L2 exists at this point. Test linking to unsearchable dir. */ + if (link("L2", "Dir/L2") != 0) e(27); + if (chmod("Dir", 0666) != 0) e(27); + if (link("L2", "Dir/L2") != -1) e(28); + if (errno != EACCES) e(29); + errno = 0; + if (link("Dir/L2", "L3") != -1) e(30); + if (errno != EACCES) e(31); + if (chmod("Dir", 0777) != 0) e(32); + if (unlink("Dir/L2") != 0) e(33); + if (unlink("L3") == 0) e(34); + + /* L2 exists at this point. Test linking to unwriteable dir. */ + if (chmod("Dir", 0555) != 0) e(35); + if (link("L2", "Dir/L2") != -1) e(36); + if (errno != EACCES) e(37); + if (chmod("Dir", 0777) != 0) e(38); + + /* L2 exists at this point. Test linking mode 0 file. */ + if (chmod("L2", 0) != 0) e(39); + if (link("L2", "L3") != 0) e(40); + if (stat("L3", &stbuf) != 0) e(41); + if (stbuf.st_nlink != 2) e(42); + if (unlink("L2") != 0) e(43); + + /* L3 exists at this point. Test linking to an existing file. */ + if ( (fd = creat("L1", 0666)) < 0) e(44); + if (link("L1", "L3") != -1) e(45); + if (errno != EEXIST) e(46); + errno = 0; + if (link("L1", "L1") != -1) e(47); + if (errno != EEXIST) e(48); + if (unlink("L3") != 0) e(49); + + /* L1 exists at this point. Test creating too many links. */ + for (i = 2; i <= LINK_MAX; i++) { + sprintf(name, "Lx%d", i); + if (link("L1", name) != 0) e(50); + } + if (stat("L1", &stbuf) != 0) e(51); + if (stbuf.st_nlink != LINK_MAX) e(52); + if (link("L1", "L2") != -1) e(53); + if (errno != EMLINK) e(54); + for (i = 2; i <= LINK_MAX; i++) { + sprintf(name, "Lx%d", i); + if (unlink(name) != 0) e(55); } - /* Check the return value of do_check(). */ - do_check_retval = WEXITSTATUS(stat_loc); - if ((do_check_retval & 0x11) == 0x11) e(25); - if ((do_check_retval & 0x12) == 0x12) e(26); - if ((do_check_retval & 0x14) == 0x14) e(27); - if ((do_check_retval & 0x18) == 0x18) e(28); - if ((do_check_retval & 0x21) == 0x21) e(29); - if ((do_check_retval & 0x22) == 0x22) e(30); - if ((do_check_retval & 0x24) == 0x24) e(31); - if ((do_check_retval & 0x28) == 0x28) e(32); - if ((do_check_retval & 0x41) == 0x41) e(33); - if ((do_check_retval & 0x42) == 0x42) e(34); - if ((do_check_retval & 0x44) == 0x44) e(35); - if ((do_check_retval & 0x48) == 0x48) e(36); - if ((do_check_retval & 0x81) == 0x81) e(37); - if ((do_check_retval & 0x82) == 0x82) e(38); - if ((do_check_retval & 0x84) == 0x84) e(39); - if ((do_check_retval & 0x88) == 0x88) e(40); - - switch (fork()) { - case -1: printf("Can't fork\n"); break; - case 0: - alarm(20); - - /* Lock fd8. */ - fl.l_type = F_WRLCK; - if (fcntl(fd8, F_SETLK, &fl) == -1) e(41); - - execvp(executable + 3, argv); - execvp(executable, argv); - printf("Can't exec %s or %s\n", executable + 3, executable); - exit(0); + if (stat("L1", &stbuf) != 0) e(56); + if (stbuf.st_nlink != 1) e(57); - default: - wait(&stat_loc); - if (WIFSIGNALED(stat_loc)) e(48); /* Alarm? */ - } + /* L1 exists. Test ENOENT. */ + errno = 0; + if (link("xx/L1", "L2") != -1) e(58); + if (errno != ENOENT) e(59); + errno = 0; + if (link("L1", "xx/L2") != -1) e(60); + if (errno != ENOENT) e(61); + errno = 0; + if (link("L4", "L5") != -1) e(62); + if (errno != ENOENT) e(63); + errno = 0; + if (link("", "L5") != -1) e(64); + if (errno != ENOENT) e(65); + errno = 0; + if (link("L1", "") != -1) e(66); + if (errno != ENOENT) e(67); + + /* L1 exists. Test ENOTDIR. */ + errno = 0; + if (link("/dev/tty/x", "L2") != -1) e(68); + if (errno != ENOTDIR) e(69); + + /* L1 exists. Test EPERM. */ + if (link(".", "L2") != -1) e(70); + if (errno != EPERM) e(71); + + /* L1 exists. Test unlink. */ + if (link("L1", "Dir/L1") != 0) e(72); + if (chmod("Dir", 0666) != 0) e(73); + if (unlink("Dir/L1") != -1) e(74); + if (errno != EACCES) e(75); + errno = 0; + if (chmod("Dir", 0555) != 0) e(76); + if (unlink("Dir/L1") != -1) e(77); + if (errno != EACCES) e(78); - /* Check the return value of do_check(). */ - do_check_retval = WEXITSTATUS(stat_loc); - if ((do_check_retval & 0x11) == 0x11) e(49); - if ((do_check_retval & 0x12) == 0x12) e(50); - if ((do_check_retval & 0x14) == 0x14) e(51); - if ((do_check_retval & 0x18) == 0x18) e(52); - if ((do_check_retval & 0x21) == 0x21) e(53); - if ((do_check_retval & 0x22) == 0x22) e(54); - if ((do_check_retval & 0x24) == 0x24) e(55); - if ((do_check_retval & 0x28) == 0x28) e(56); - if ((do_check_retval & 0x41) == 0x41) e(57); - if ((do_check_retval & 0x42) == 0x42) e(58); - if ((do_check_retval & 0x44) == 0x44) e(59); - if ((do_check_retval & 0x48) == 0x48) e(60); - if ((do_check_retval & 0x81) == 0x81) e(61); - if ((do_check_retval & 0x82) == 0x82) e(62); - if ((do_check_retval & 0x84) == 0x84) e(63); - if ((do_check_retval & 0x88) == 0x88) e(64); - - fl.l_type = F_UNLCK; - if (fcntl(fd3, F_SETLK, &fl) == -1) e(65); - if (fcntl(fd7, F_SETLK, &fl) == -1) e(66); - - if (close(fd3) != 0) e(67); - if (close(fd4) != 0) e(68); - if (close(fd5) != 0) e(69); - if (close(fd6) != 0) e(70); - if (close(fd7) != 0) e(71); - if (close(fd8) != 0) e(72); - - System("rm -f ../DIR_39/*\n"); + if (unlink("L7") != -1) e(79); + if (errno != ENOENT) e(80); + errno = 0; + if (unlink("") != -1) e(81); + if (errno != ENOENT) e(82); + + if (unlink("Dir/L1/L2") != -1) e(83); + if (errno != ENOTDIR) e(84); + + if (chmod("Dir", 0777) != 0) e(85); + if (unlink("Dir/L1") != 0) e(86); + if (unlink("Dir") != -1) e(87); + if (errno != EPERM) e(88); + if (unlink("L1") != 0) e(89); + if (system("rm -rf Dir") != 0) e(90); + if (close(fd) != 0) e(91); } -/* This routine checks that fds 0 through 4, 7 and 8 are open and the rest -** is closed. It also checks if we can lock the first 10 bytes on fd no. 3 -** and 4. It should not be possible to lock fd no. 3, but it should be -** possible to lock fd no. 4. See ``test39d()'' for usage of this routine. -*/ -int do_check() +void test39h() { - int i; - int retval = 0; - struct flock fl; - - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 10; - - /* All std.. are open. */ - if (fcntl(0, F_GETFD) == -1) retval |= 0x11; - if (fcntl(1, F_GETFD) == -1) retval |= 0x11; - if (fcntl(2, F_GETFD) == -1) retval |= 0x11; - - /* Fd no. 3, 4, 7 and 8 are open. */ - if (fcntl(3, F_GETFD) == -1) retval |= 0x12; - if (fcntl(4, F_GETFD) == -1) retval |= 0x12; - if (fcntl(7, F_GETFD) == -1) retval |= 0x12; - - /* Fd no. 5, 6 and 9 trough OPEN_MAX are closed. */ - if (fcntl(5, F_GETFD) != -1) retval |= 0x14; - if (fcntl(6, F_GETFD) != -1) retval |= 0x14; - for (i = 9; i < OPEN_MAX; i++) - if (fcntl(i, F_GETFD) != -1) retval |= 0x18; - -#if 0 - /* Fd no. 3 is WRLCKed. */ - fl.l_type = F_WRLCK; - if (fcntl(3, F_SETLK, &fl) != -1) retval |= 0x21; - if (errno != EACCES && errno != EAGAIN) retval |= 0x22; - fl.l_type = F_RDLCK; - if (fcntl(3, F_SETLK, &fl) != -1) retval |= 0x24; - if (errno != EACCES && errno != EAGAIN) retval |= 0x22; - fl.l_type = F_RDLCK; - if (fcntl(3, F_GETLK, &fl) == -1) retval |= 0x28; - if (fl.l_type != F_WRLCK) retval |= 0x28; - if (fl.l_pid != getpid()) retval |= 0x28; - fl.l_type = F_WRLCK; - if (fcntl(3, F_GETLK, &fl) == -1) retval |= 0x28; - if (fl.l_type != F_WRLCK) retval |= 0x28; - if (fl.l_pid != getpid()) retval |= 0x28; -#endif - - /* Fd no. 4 is not locked. */ - fl.l_type = F_WRLCK; - if (fcntl(4, F_SETLK, &fl) == -1) retval |= 0x41; - if (fcntl(4, F_GETLK, &fl) == -1) retval |= 0x42; -#if 0 /* XXX - see test7.c */ - if (fl.l_type != F_WRLCK) retval |= 0x42; - if (fl.l_pid != getpid()) retval |= 0x42; -#endif /* 0 */ - - /* Fd no. 8 is locked after the fork, it is ours. */ - fl.l_type = F_WRLCK; - if (fcntl(8, F_SETLK, &fl) == -1) retval |= 0x44; - if (fcntl(8, F_GETLK, &fl) == -1) retval |= 0x48; -#if 0 /* XXX - see test7.c */ - if (fl.l_type != F_WRLCK) retval |= 0x48; - if (fl.l_pid != getpid()) retval |= 0x48; -#endif /* 0 */ - -#if 0 - /* Fd no. 7 is RDLCKed. */ - fl.l_type = F_WRLCK; - if (fcntl(7, F_SETLK, &fl) != -1) retval |= 0x81; - if (errno != EACCES && errno != EAGAIN) retval |= 0x82; - fl.l_type = F_RDLCK; - if (fcntl(7, F_SETLK, &fl) == -1) retval |= 0x84; - fl.l_type = F_RDLCK; - if (fcntl(7, F_GETLK, &fl) == -1) retval |= 0x88; - if (fl.l_type != F_UNLCK) retval |= 0x88; - fl.l_type = F_WRLCK; - if (fcntl(7, F_GETLK, &fl) == -1) retval |= 0x88; - if (fl.l_type != F_RDLCK) retval |= 0x88; - if (fl.l_pid != getppid()) retval |= 0x88; -#endif - - return retval; +/* Test access. */ + + int fd; + + subtest = 10; + system("rm -rf A1"); + if ( (fd = creat("A1", 0777)) < 0) e(1); + if (close(fd) != 0) e(2); + if (access("A1", R_OK) != 0) e(3); + if (access("A1", W_OK) != 0) e(4); + if (access("A1", X_OK) != 0) e(5); + if (access("A1", (R_OK|W_OK|X_OK)) != 0) e(6); + + if (chmod("A1", 0400) != 0) e(7); + if (access("A1", R_OK) != 0) e(8); + if (access("A1", W_OK) != -1) e(9); + if (access("A1", X_OK) != -1) e(10); + if (access("A1", (R_OK|W_OK|X_OK)) != -1) e(11); + + if (chmod("A1", 0077) != 0) e(12); + if (access("A1", R_OK) != -1) e(13); + if (access("A1", W_OK) != -1) e(14); + if (access("A1", X_OK) != -1) e(15); + if (access("A1", (R_OK|W_OK|X_OK)) != -1) e(16); + if (errno != EACCES) e(17); + + if (access("", R_OK) != -1) e(18); + if (errno != ENOENT) e(19); + if (access("./A1/x", R_OK) != -1) e(20); + if (errno != ENOTDIR) e(21); + + if (unlink("A1") != 0) e(22); } -void makelongnames() +void test39i() { - register int i; +/* Test chmod. */ + + int fd, i; + struct stat stbuf; - memset(MaxName, 'a', NAME_MAX); - MaxName[NAME_MAX] = '\0'; - for (i = 0; i < PATH_MAX - 1; i++) { /* idem path */ - MaxPath[i++] = '.'; - MaxPath[i] = '/'; + subtest = 11; + system("rm -rf A1"); + if ( (fd = creat("A1", 0777)) < 0) e(1); + + for (i = 0; i < 511; i++) { + if (chmod("A1", i) != 0) e(100+i); + if (fstat(fd, &stbuf) != 0) e(200+i); + if ( (stbuf.st_mode&(S_IRWXU|S_IRWXG|S_IRWXO)) != i) e(300+i); } - MaxPath[PATH_MAX - 1] = '\0'; + if (close(fd) != 0) e(2); - strcpy(ToLongName, MaxName); /* copy them Max to ToLong */ - strcpy(ToLongPath, MaxPath); + if (chmod("A1/x", 0777) != -1) e(3); + if (errno != ENOTDIR) e(4); + if (chmod("Axxx", 0777) != -1) e(5); + if (errno != ENOENT) e(6); + errno = 0; + if (chmod ("", 0777) != -1) e(7); + if (errno != ENOENT) e(8); + + /* Now perform limited chown tests. These should work even as non su */ + i = getuid(); +/* DEBUG -- Not yet implemented + if (chown("A1", i, 0) != 0) e(9); + if (chown("A1", i, 1) != 0) e(10); + if (chown("A1", i, 2) != 0) e(11); + if (chown("A1", i, 3) != 0) e(12); + if (chown("A1", i, 4) != 0) e(13); + if (chown("A1", i, 0) != 0) e(14); +*/ + + if (unlink("A1") != 0) e(9); +} - ToLongName[NAME_MAX] = 'a'; - ToLongName[NAME_MAX + 1] = '\0'; /* extend ToLongName by one too many */ - ToLongPath[PATH_MAX - 1] = '/'; - ToLongPath[PATH_MAX] = '\0'; /* inc ToLongPath by one */ +void test39j() +{ +/* Test utime. */ + + int fd; + time_t tloc; + struct utimbuf times; + struct stat stbuf; + + subtest = 12; + if (system("rm -rf A2") != 0) e(1); + if ( (fd = creat("A2", 0666)) < 0) e(2); + times.modtime = 100; + if (utime("A2", ×) != 0) e(3); + if (stat("A2", &stbuf) != 0) e(4); + if (stbuf.st_mtime != 100) e(5); + + tloc = time((time_t *)NULL); /* get current time */ + times.modtime = tloc; + if (utime("A2", ×) != 0) e(6); + if (stat("A2", &stbuf) != 0) e(7); + if (stbuf.st_mtime != tloc) e(8); + if (close(fd) != 0) e(9); + if (unlink("A2") != 0) e(10); } void e(n) int n; { - int err_num = errno; /* Save in case printf clobbers it. */ + int err_num = errno; /* save errno in case printf clobbers it */ - printf("Subtest %d, error %d errno=%d: ", subtest, n, errno); - errno = err_num; + printf("Subtest %d, error %d errno=%d ", subtest, n, errno); + fflush(stdout); /* stdout and stderr are mixed horribly */ + errno = err_num; /* restore errno, just in case */ perror(""); if (errct++ > MAX_ERROR) { printf("Too many errors; test aborted\n"); @@ -377,22 +704,19 @@ int n; system("rm -rf DIR*"); exit(1); } - errno = 0; } void quit() { - Chdir(".."); - System("rm -rf DIR_39"); + + chdir(".."); + system("rm -rf DIR*"); if (errct == 0) { printf("ok\n"); exit(0); - } else if (errct < 10000) { + } else { printf("%d errors\n", errct); exit(1); - } else { - printf("errors\n"); - exit(2); } }