minix/test/test18.c
2010-01-08 13:40:34 +00:00

1411 lines
36 KiB
C

/* test 18 */
/* Comment on usage and program: ark!/mnt/rene/prac/os/unix/comment.changes */
/* "const.h", created by Rene Montsma and Menno Wilcke */
#include <sys/types.h> /* needed in struct stat */
#include <sys/stat.h> /* struct stat */
#include <sys/wait.h>
#include <errno.h> /* the error-numbers */
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <limits.h>
#include <assert.h>
#include <sys/uio.h>
#define NOCRASH 1 /* test11(), 2nd pipe */
#define PDPNOHANG 1 /* test03(), write_standards() */
#define MAXERR 5
#define USER_ID 12
#define GROUP_ID 1
#define FF 3 /* first free filedes. */
#define USER 1 /* uid */
#define GROUP 0 /* gid */
#define ARSIZE 256 /* array size */
#define PIPESIZE 3584 /* maxnumber of bytes to be written on pipe */
#define MAXOPEN (OPEN_MAX-3) /* maximum number of extra open files */
#define MAXLINK 0177 /* maximum number of links per file */
#define MASK 0777 /* selects lower nine bits */
#define READ_EOF 0 /* returned by read-call at eof */
#define OK 0
#define FAIL -1
#define R 0 /* read (open-call) */
#define W 1 /* write (open-call) */
#define RW 2 /* read & write (open-call) */
#define RWX 7 /* read & write & execute (mode) */
#define NIL ""
#define UMASK "umask"
#define CREAT "creat"
#define WRITE "write"
#define WRITEV "writev"
#define READ "read"
#define READV "readv"
#define OPEN "open"
#define CLOSE "close"
#define LSEEK "lseek"
#define ACCESS "access"
#define CHDIR "chdir"
#define CHMOD "chmod"
#define LINK "link"
#define UNLINK "unlink"
#define PIPE "pipe"
#define STAT "stat"
#define FSTAT "fstat"
#define DUP "dup"
#define UTIME "utime"
int errct;
char *file[];
char *fnames[];
char *dir[];
/* "decl.c", created by Rene Montsma and Menno Wilcke */
/* Used in open_alot, close_alot */
char *file[20] = {"f0", "f1", "f2", "f3", "f4", "f5", "f6",
"f7", "f8", "f9", "f10", "f11", "f12", "f13",
"f14", "f15", "f16", "f17", "f18", "f19"}, *fnames[8] = {"---", "--x", "-w-", "-wx", "r--",
"r-x", "rw-", "rwx"}, *dir[8] = {"d---", "d--x", "d-w-", "d-wx", "dr--", "dr-x",
"drw-", "drwx"};
/* Needed for easy creating and deleting of directories */
/* "test.c", created by Rene Montsma and Menno Wilcke */
_PROTOTYPE(int main, (int argc, char **argv));
_PROTOTYPE(void test, (void));
_PROTOTYPE(void test01, (void));
_PROTOTYPE(void test02, (void));
_PROTOTYPE(void test03, (void));
_PROTOTYPE(void write_standards, (int filedes, char a []));
_PROTOTYPE(void test04, (void));
_PROTOTYPE(void read_standards, (int filedes, char a []));
_PROTOTYPE(void read_more, (int filedes, char a []));
_PROTOTYPE(void test05, (void));
_PROTOTYPE(void try_open, (char *fname, int mode, int test));
_PROTOTYPE(void test06, (void));
_PROTOTYPE(void test07, (void));
_PROTOTYPE(void access_standards, (void));
_PROTOTYPE(void test08, (void));
_PROTOTYPE(static int iovec_is_equal,
(struct iovec *x, struct iovec *y, size_t size));
_PROTOTYPE(static size_t iovec_setup,
(int pattern, struct iovec *iovec, char *buffer, int count));
_PROTOTYPE(static int power, (int base, int exponent));
_PROTOTYPE(void try_access, (char *fname, int mode, int test));
_PROTOTYPE(void e, (char *string));
_PROTOTYPE(void nlcr, (void));
_PROTOTYPE(void str, (char *s));
_PROTOTYPE(void err, (int number, char *scall, char *name));
_PROTOTYPE(void make_and_fill_dirs, (void));
_PROTOTYPE(void put_file_in_dir, (char *dirname, int mode));
_PROTOTYPE(void init_array, (char *a));
_PROTOTYPE(void clear_array, (char *b));
_PROTOTYPE(int comp_array, (char *a, char *b, int range));
_PROTOTYPE(void try_close, (int filedes, char *name));
_PROTOTYPE(void try_unlink, (char *fname));
_PROTOTYPE(void Remove, (int fdes, char *fname));
_PROTOTYPE(int get_mode, (char *name));
_PROTOTYPE(void check, (char *scall, int number));
_PROTOTYPE(void put, (int nr));
_PROTOTYPE(int open_alot, (void));
_PROTOTYPE(int close_alot, (int number));
_PROTOTYPE(void clean_up_the_mess, (void));
_PROTOTYPE(void chmod_8_dirs, (int sw));
_PROTOTYPE(void quit, (void));
/*****************************************************************************
* TEST *
****************************************************************************/
int main(int argc, char **argv)
{
char buffer[PATH_MAX + 1];
int n;
if (geteuid() == 0 || getuid() == 0) {
realpath(argv[0], buffer);
execl("/usr/bin/su", "/usr/bin/su", "-", "ast", "-c", buffer, NULL);
printf("Test 18 cannot run as root; test aborted\n");
exit(1);
}
system("rm -rf DIR_18; mkdir DIR_18");
chdir("DIR_18");
if (fork()) {
printf("Test 18 ");
fflush(stdout); /* have to flush for child's benefit */
wait(&n);
clean_up_the_mess();
quit();
} else {
test();
exit(0);
}
return(0);
}
void test()
{
umask(0); /* not honest, but i always forget */
test01();
make_and_fill_dirs();
test02();
test03();
test04();
test05();
test06();
test07();
test08();
umask(022);
} /* test */
/* "t1.c" created by Rene Montsma and Menno Wilcke */
/*****************************************************************************
* test UMASK *
****************************************************************************/
void test01()
{
int oldvalue, newvalue, tempvalue;
int nr;
if ((oldvalue = umask(0777)) != 0) err(0, UMASK, NIL);
/* Special test: only the lower 9 bits (protection bits) may part- *
* icipate. ~0777 means: 111 000 000 000. Giving this to umask must*
* not change any value. */
if ((newvalue = umask(~0777)) != 0777) err(1, UMASK, "illegal");
if (oldvalue == newvalue) err(11, UMASK, "not change mask");
if ((tempvalue = umask(0)) != 0) err(2, UMASK, "values");
/* Now test all possible modes of umask on a file */
for (newvalue = MASK; newvalue >= 0; newvalue -= 0111) {
tempvalue = umask(newvalue);
if (tempvalue != oldvalue) {
err(1, UMASK, "illegal");
break; /* no use trying more */
} else if ((nr = creat("file01", 0777)) < 0)
err(5, CREAT, "'file01'");
else {
try_close(nr, "'file01'");
if (get_mode("file01") != (MASK & ~newvalue))
err(7, UMASK, "mode computed");
try_unlink("file01");
}
oldvalue = newvalue;
}
/* The loop has terminated with umask(0) */
if ((tempvalue = umask(0)) != 0)
err(7, UMASK, "umask may influence rest of tests!");
} /* test01 */
/*****************************************************************************
* test CREAT *
****************************************************************************/
void test02()
{
int n, n1, mode;
char a[ARSIZE], b[ARSIZE];
struct stat stbf1;
mode = 0;
/* Create twenty files, check filedes */
for (n = 0; n < MAXOPEN; n++) {
if (creat(file[n], mode) != FF + n)
err(13, CREAT, file[n]);
else {
if (get_mode(file[n]) != mode)
err(7, CREAT, "mode set while creating many files");
/* Change mode of file to standard mode, we want to *
* use a lot (20) of files to be opened later, see *
* open_alot(), close_alot(). */
if (chmod(file[n], 0700) != OK) err(5, CHMOD, file[n]);
}
mode = (mode + 0100) % 01000;
}
/* Already twenty files opened; opening another has to fail */
if (creat("file02", 0777) != FAIL)
err(9, CREAT, "created");
else
check(CREAT, EMFILE);
/* Close all files: seems blunt, but it isn't because we've *
* checked all fd's already */
if ((n = close_alot(MAXOPEN)) < MAXOPEN) err(5, CLOSE, "MAXOPEN files");
/* Creat 1 file twice; check */
if ((n = creat("file02", 0777)) < 0)
err(5, CREAT, "'file02'");
else {
init_array(a);
if (write(n, a, ARSIZE) != ARSIZE) err(1, WRITE, "bad");
if ((n1 = creat("file02", 0755)) < 0) /* receate 'file02' */
err(5, CREAT, "'file02' (2nd time)");
else {
/* Fd should be at the top after recreation */
if (lseek(n1, 0L, SEEK_END) != 0)
err(11, CREAT, "not truncate file by recreation");
else {
/* Try to write on recreated file */
clear_array(b);
if (lseek(n1, 0L, SEEK_SET) != 0)
err(5, LSEEK, "to top of 2nd fd 'file02'");
if (write(n1, a, ARSIZE) != ARSIZE)
err(1, WRITE, "(2) bad");
/* In order to read we've to close and open again */
try_close(n1, "'file02' (2nd creation)");
if ((n1 = open("file02", RW)) < 0)
err(5, OPEN, "'file02' (2nd recreation)");
/* Continue */
if (lseek(n1, 0L, SEEK_SET) != 0)
err(5, LSEEK, "to top 'file02'(2nd fd) (2)");
if (read(n1, b, ARSIZE) != ARSIZE)
err(1, READ, "wrong");
if (comp_array(a, b, ARSIZE) != OK) err(11, CREAT,
"not really truncate file by recreation");
}
if (get_mode("file02") != 0777)
err(11, CREAT, "not maintain mode by recreation");
try_close(n1, "recreated 'file02'");
}
Remove(n, "file02");
}
/* Give 'creat' wrong input: dir not searchable */
if (creat("drw-/file02", 0777) != FAIL)
err(4, CREAT, "'drw-'");
else
check(CREAT, EACCES);
/* Dir not writable */
if (creat("dr-x/file02", 0777) != FAIL)
err(12, CREAT, "'dr-x/file02'");
else
check(CREAT, EACCES);
/* File not writable */
if (creat("drwx/r-x", 0777) != FAIL)
err(11, CREAT, "recreate non-writable file");
else
check(CREAT, EACCES);
/* Try to creat a dir */
if ((n = creat("dir", 040777)) != FAIL) {
if (fstat(n, &stbf1) != OK)
err(5, FSTAT, "'dir'");
else if (stbf1.st_mode != (mode_t) 0100777)
/* Cast because mode is negative :-(.
* HACK DEBUG FIXME: this appears to duplicate
* code in test17.c.
*/
err(11, CREAT, "'creat' a new directory");
Remove(n, "dir");
}
/* We don't consider it to be a bug when creat * does not accept
* tricky modes */
/* File is an existing dir */
if (creat("drwx", 0777) != FAIL)
err(11, CREAT, "create an existing dir!");
else
check(CREAT, EISDIR);
} /* test02 */
/*****************************************************************************
* test WRITE *
****************************************************************************/
void test03()
{
int n, n1;
int fd[2];
char a[ARSIZE];
init_array(a);
/* Test write after a CREAT */
if ((n = creat("file03", 0700)) != FF) /* 'file03' only open file */
err(13, CREAT, "'file03'");
else {
write_standards(n, a); /* test simple writes, wrong input too */
try_close(n, "'file03'");
}
/* Test write after an OPEN */
if ((n = open("file03", W)) < 0)
err(5, OPEN, "'file03'");
else
write_standards(n, a); /* test simple writes, wrong input too */
/* Test write after a DUP */
if ((n1 = dup(n)) < 0)
err(5, DUP, "'file03'");
else {
write_standards(n1, a);
try_close(n1, "duplicated fd 'file03'");
}
/* Remove testfile */
Remove(n, "file03");
/* Test write after a PIPE */
if (pipe(fd) < 0)
err(5, PIPE, NIL);
else {
write_standards(fd[1], a);
try_close(fd[0], "'fd[0]'");
try_close(fd[1], "'fd[1]'");
}
/* Last test: does write check protections ? */
if ((n = open("drwx/r--", R)) < 0)
err(5, OPEN, "'drwx/r--'");
else {
if (write(n, a, ARSIZE) != FAIL)
err(11, WRITE, "write on non-writ. file");
else
check(WRITE, EBADF);
try_close(n, "'drwx/r--'");
}
} /* test03 */
void write_standards(filedes, a)
int filedes;
char a[];
{
/* Write must return written account of numbers */
if (write(filedes, a, ARSIZE) != ARSIZE) err(1, WRITE, "bad");
/* Try giving 'write' wrong input */
/* Wrong filedes */
if (write(-1, a, ARSIZE) != FAIL)
err(2, WRITE, "filedes");
else
check(WRITE, EBADF);
/* Wrong length (illegal) */
#ifndef PDPNOHANG
if (write(filedes, a, -ARSIZE) != FAIL)
err(2, WRITE, "length");
else
check(WRITE, EINVAL); /* EFAULT on vu45 */
#endif
} /* write_standards */
/* "t2.c", created by Rene Montsma and Menno Wilcke */
/*****************************************************************************
* test READ *
****************************************************************************/
void test04()
{
int n, n1, fd[2];
char a[ARSIZE];
/* Test read after creat */
if ((n = creat("file04", 0700)) != FF) /* no other open files may be
* left */
err(13, CREAT, "'file04'");
else {
/* Closing and opening needed before writing */
try_close(n, "'file04'");
if ((n = open("file04", RW)) < 0) err(5, OPEN, "'file04'");
init_array(a);
if (write(n, a, ARSIZE) != ARSIZE)
err(1, WRITE, "bad");
else {
if (lseek(n, 0L, SEEK_SET) != 0) err(5, LSEEK, "'file04'");
read_standards(n, a);
read_more(n, a);
}
try_close(n, "'file04'");
}
/* Test read after OPEN */
if ((n = open("file04", R)) < 0)
err(5, OPEN, "'file04'");
else {
read_standards(n, a);
read_more(n, a);
try_close(n, "'file04'");
}
/* Test read after DUP */
if ((n = open("file04", R)) < 0) err(5, OPEN, "'file04'");
if ((n1 = dup(n)) < 0)
err(5, DUP, "'file04'");
else {
read_standards(n1, a);
read_more(n1, a);
try_close(n1, "duplicated fd 'file04'");
}
/* Remove testfile */
Remove(n, "file04");
/* Test read after pipe */
if (pipe(fd) < 0)
err(5, PIPE, NIL);
else {
if (write(fd[1], a, ARSIZE) != ARSIZE) {
err(5, WRITE, "'fd[1]'");
try_close(fd[1], "'fd[1]'");
} else {
try_close(fd[1], "'fd[1]'");
read_standards(fd[0], a);
}
try_close(fd[0], "'fd[0]'");
}
/* Last test: try to read a read-protected file */
if ((n = open("drwx/-wx", W)) < 0)
err(5, OPEN, "'drwx/-wx'");
else {
if (read(n, a, ARSIZE) != FAIL)
err(11, READ, "read a non-read. file");
else
check(READ, EBADF);
try_close(n, "'/drwx/-wx'");
}
} /* test04 */
void read_standards(filedes, a)
int filedes;
char a[];
{
char b[ARSIZE];
clear_array(b);
if (read(filedes, b, ARSIZE) != ARSIZE)
err(1, READ, "bad");
else if (comp_array(a, b, ARSIZE) != OK)
err(7, "read/write", "values");
else if (read(filedes, b, ARSIZE) != READ_EOF)
err(11, READ, "read beyond endoffile");
/* Try giving read wrong input: wrong filedes */
if (read(FAIL, b, ARSIZE) != FAIL)
err(2, READ, "filedes");
else
check(READ, EBADF);
/* Wrong length */
if (read(filedes, b, -ARSIZE) != FAIL)
err(2, READ, "length");
else
check(READ, EINVAL);
} /* read_standards */
void read_more(filedes, a)
int filedes;
char a[];
/* Separated from read_standards() because the PIPE test * would fail. */
{
int i;
char b[ARSIZE];
if (lseek(filedes, (long) (ARSIZE / 2), SEEK_SET) != ARSIZE / 2)
err(5, LSEEK, "to location ARSIZE/2");
clear_array(b);
if (read(filedes, b, ARSIZE) != ARSIZE / 2) err(1, READ, "bad");
for (i = 0; i < ARSIZE / 2; i++)
if (b[i] != a[(ARSIZE / 2) + i])
err(7, READ, "from location ARSIZE/2");
}
/*****************************************************************************
* test OPEN/CLOSE *
****************************************************************************/
void test05()
{
int n, n1, mode, fd[2];
char b[ARSIZE];
/* Test open after CREAT */
if ((n = creat("file05", 0700)) != FF) /* no other open files left */
err(13, CREAT, "'file05'");
else {
if ((n1 = open("file05", RW)) != FF + 1)
err(13, OPEN, "'file05' after creation");
try_close(n1, "'file05' (open after creation)");
try_close(n, "'file05'");
if ((n = open("file05", R)) != FF)
err(13, OPEN, "after closing");
else
try_close(n, "'file05' (open after closing)");
/* Remove testfile */
try_unlink("file05");
}
/* Test all possible modes, try_open not only opens file (sometimes) *
* but closes files too (when opened) */
if ((n = creat("file05", 0700)) < 0) /* no other files left */
err(5, CREAT, "'file05' (2nd time)");
else {
try_close(n, "file05");
for (mode = 0; mode <= 0700; mode += 0100) {
if (chmod("file05", mode) != OK) err(5, CHMOD, "'file05'");
if (mode <= 0100) {
try_open("file05", R, FAIL);
try_open("file05", W, FAIL);
try_open("file05", RW, FAIL);
} else if (mode >= 0200 && mode <= 0300) {
try_open("file05", R, FAIL);
try_open("file05", W, FF);
try_open("file05", RW, FAIL);
} else if (mode >= 0400 && mode <= 0500) {
try_open("file05", R, FF);
try_open("file05", W, FAIL);
try_open("file05", RW, FAIL);
} else {
try_open("file05", R, FF);
try_open("file05", W, FF);
try_open("file05", RW, FF);
}
}
}
/* Test opening existing file */
if ((n = open("drwx/rwx", R)) < 0)
err(13, OPEN, "existing file");
else { /* test close after DUP */
if ((n1 = dup(n)) < 0)
err(13, DUP, "'drwx/rwx'");
else {
try_close(n1, "duplicated fd 'drwx/rwx'");
if (read(n1, b, ARSIZE) != FAIL)
err(11, READ, "on closed dupped fd 'drwx/rwx'");
else
check(READ, EBADF);
if (read(n, b, ARSIZE) == FAIL) /* should read an eof */
err(13, READ, "on fd '/drwx/rwx'");
}
try_close(n, "'drwx/rwx'");
}
/* Test close after PIPE */
if (pipe(fd) < 0)
err(13, PIPE, NIL);
else {
try_close(fd[1], "duplicated fd 'fd[1]'");
/* Fd[1] really should be closed now; check */
clear_array(b);
if (read(fd[0], b, ARSIZE) != READ_EOF)
err(11, READ, "read on empty pipe (and fd[1] was closed)");
try_close(fd[0], "duplicated fd 'fd[0]'");
}
/* Try to open a non-existing file */
if (open("non-file", R) != FAIL)
err(11, OPEN, "open non-executable file");
else
check(OPEN, ENOENT);
/* Dir does not exist */
if (open("dzzz/file05", R) != FAIL)
err(11, OPEN, "open in an non-searchable dir");
else
check(OPEN, ENOENT);
/* Dir is not searchable */
if (n = open("drw-/rwx", R) != FAIL)
err(11, OPEN, "open in an non-searchabledir");
else
check(OPEN, EACCES);
/* Unlink testfile */
try_unlink("file05");
/* File is not readable */
if (open("drwx/-wx", R) != FAIL)
err(11, OPEN, "open unreadable file for reading");
else
check(OPEN, EACCES);
/* File is not writable */
if (open("drwx/r-x", W) != FAIL)
err(11, OPEN, "open unwritable file for writing");
else
check(OPEN, EACCES);
/* Try opening more than MAXOPEN ('extra' (19-8-85)) files */
if ((n = open_alot()) != MAXOPEN)
err(13, OPEN, "MAXOPEN files");
else
/* Maximum # of files opened now, another open should fail
* because * all filedescriptors have already been used. */
if (open("drwx/rwx", RW) != FAIL)
err(9, OPEN, "open");
else
check(OPEN, EMFILE);
if (close_alot(n) != n) err(5, CLOSE, "all opened files");
/* Can close make mistakes ? */
if (close(-1) != FAIL)
err(2, CLOSE, "filedes");
else
check(CLOSE, EBADF);
} /* test05 */
void try_open(fname, mode, test)
int mode, test;
char *fname;
{
int n;
if ((n = open(fname, mode)) != test)
err(11, OPEN, "break through filepermission with an incorrect mode");
if (n != FAIL) try_close(n, fname); /* cleanup */
} /* try_open */
/*****************************************************************************
* test LSEEK *
****************************************************************************/
void test06()
{
char a[ARSIZE], b[ARSIZE];
int fd;
if ((fd = open("drwx/rwx", RW)) != FF) /* there should be no */
err(13, OPEN, "'drwx/rwx'"); /* other open files */
else {
init_array(a);
if (write(fd, a, 10) != 10)
err(1, WRITE, "bad");
else {
/* Lseek back to begin file */
if (lseek(fd, 0L, SEEK_SET) != 0)
err(5, LSEEK, "to begin file");
else if (read(fd, b, 10) != 10)
err(1, READ, "bad");
else if (comp_array(a, b, 10) != OK)
err(7, LSEEK, "values r/w after lseek to begin");
/* Lseek to endoffile */
if (lseek(fd, 0L, SEEK_END) != 10)
err(5, LSEEK, "to end of file");
else if (read(fd, b, 1) != READ_EOF)
err(7, LSEEK, "read at end of file");
/* Lseek beyond file */
if (lseek(fd, 10L, SEEK_CUR) != 20)
err(5, LSEEK, "beyond end of file");
else if (write(fd, a, 10) != 10)
err(1, WRITE, "bad");
else {
/* Lseek to begin second write */
if (lseek(fd, 20L, SEEK_SET) != 20)
err(5, LSEEK, "'/drwx/rwx'");
if (read(fd, b, 10) != 10)
err(1, READ, "bad");
else if (comp_array(a, b, 10) != OK)
err(7, LSEEK,
"values read after lseek MAXOPEN");
}
}
/* Lseek to position before begin of file */
if (lseek(fd, -1L, 0) != FAIL)
err(11, LSEEK, "lseek before beginning of file");
try_close(fd, "'drwx/rwx'");
}
/* Lseek on invalid filediscriptor */
if (lseek(-1, 0L, SEEK_SET) != FAIL)
err(2, LSEEK, "filedes");
else
check(LSEEK, EBADF);
}
/* "t3.c", created by Rene Montsma and Menno Wilcke */
/*****************************************************************************
* test ACCESS *
****************************************************************************/
void test07()
{
/* Check with proper parameters */
if (access("drwx/rwx", RWX) != OK) err(5, ACCESS, "accessible file");
if (access("./././drwx/././rwx", 0) != OK)
err(5, ACCESS, "'/./.(etc)/drwx///rwx'");
/* Check 8 files with 8 different modes on 8 accesses */
if (chdir("drwx") != OK) err(5, CHDIR, "'drwx'");
access_standards();
if (chdir("..") != OK) err(5, CHDIR, "'..'");
/* Check several wrong combinations */
/* File does not exist */
if (access("non-file", 0) != FAIL)
err(11, ACCESS, "access non-existing file");
else
check(ACCESS, ENOENT);
/* Non-searchable dir */
if (access("drw-/rwx", 0) != FAIL)
err(4, ACCESS, "'drw-'");
else
check(ACCESS, EACCES);
/* Searchable dir, but wrong file-mode */
if (access("drwx/--x", RWX) != FAIL)
err(11, ACCESS, "a non accessible file");
else
check(ACCESS, EACCES);
} /* test07 */
void access_standards()
{
int i, mode = 0;
for (i = 0; i < 8; i++)
if (i == 0)
try_access(fnames[mode], i, OK);
else
try_access(fnames[mode], i, FAIL);
mode++;
for (i = 0; i < 8; i++)
if (i < 2)
try_access(fnames[mode], i, OK);
else
try_access(fnames[mode], i, FAIL);
mode++;
for (i = 0; i < 8; i++)
if (i == 0 || i == 2)
try_access(fnames[mode], i, OK);
else
try_access(fnames[mode], i, FAIL);
mode++;
for (i = 0; i < 8; i++)
if (i < 4)
try_access(fnames[mode], i, OK);
else
try_access(fnames[mode], i, FAIL);
mode++;
for (i = 0; i < 8; i++)
if (i == 0 || i == 4)
try_access(fnames[mode], i, OK);
else
try_access(fnames[mode], i, FAIL);
mode++;
for (i = 0; i < 8; i++)
if (i == 0 || i == 1 || i == 4 || i == 5)
try_access(fnames[mode], i, OK);
else
try_access(fnames[mode], i, FAIL);
mode++;
for (i = 0; i < 8; i++)
if (i % 2 == 0)
try_access(fnames[mode], i, OK);
else
try_access(fnames[mode], i, FAIL);
mode++;
for (i = 0; i < 8; i++) try_access(fnames[mode], i, OK);
} /* access_standards */
void try_access(fname, mode, test)
int mode, test;
char *fname;
{
if (access(fname, mode) != test)
err(100, ACCESS, "incorrect access on a file (try_access)");
} /* try_access */
/* "support.c", created by Rene Montsma and Menno Wilcke */
/* Err, make_and_fill_dirs, init_array, clear_array, comp_array,
try_close, try_unlink, Remove, get_mode, check, open_alot,
close_alot, clean_up_the_mess.
*/
/*****************************************************************************
* test READV/WRITEV *
****************************************************************************/
#define TEST8_BUFSZCOUNT 3
#define TEST8_BUFSZMAX 65536
#define TEST8_IOVCOUNT 4
void test08()
{
char buffer_read[TEST8_IOVCOUNT * TEST8_BUFSZMAX];
char buffer_write[TEST8_IOVCOUNT * TEST8_BUFSZMAX];
struct iovec iovec_read[TEST8_IOVCOUNT];
struct iovec iovec_write[TEST8_IOVCOUNT];
int fd, i, j, k, l, m;
ssize_t sz_read, sz_write;
size_t sz_read_exp, sz_read_sum, sz_write_sum;
/* try various combinations of buffer sizes */
for (i = 0; i <= TEST8_IOVCOUNT; i++)
for (j = 0; j < power(TEST8_BUFSZCOUNT, i); j++)
for (k = 0; k <= TEST8_IOVCOUNT; k++)
for (l = 0; l < power(TEST8_BUFSZCOUNT, k); l++)
{
/* put data in the buffers */
for (m = 0; m < sizeof(buffer_write); m++)
{
buffer_write[m] = m ^ (m >> 8);
buffer_read[m] = ~buffer_write[m];
}
/* set up the vectors to point to the buffers */
sz_read_sum = iovec_setup(j, iovec_read, buffer_read, i);
sz_write_sum = iovec_setup(l, iovec_write, buffer_write, k);
sz_read_exp = (sz_read_sum < sz_write_sum) ?
sz_read_sum : sz_write_sum;
/* test reading and writing */
if ((fd = open("file08", O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0)
err(13, OPEN, "'file08'");
else {
sz_write = writev(fd, iovec_write, k);
if (sz_write != sz_write_sum) err(5, WRITEV, "'file08'");
if (lseek(fd, 0, SEEK_SET) != 0) err(5, LSEEK, "'file08'");
sz_read = readv(fd, iovec_read, i);
if (sz_read != sz_read_exp)
err(5, READV, "'file08'");
else
{
if (!iovec_is_equal(iovec_read, iovec_write, sz_read))
err(8, READV, "'file08'");
}
/* Remove testfile */
Remove(fd, "file08");
}
}
} /* test08 */
static int iovec_is_equal(struct iovec *x, struct iovec *y, size_t size)
{
int xpos = 0, xvec = 0, ypos = 0, yvec = 0;
/* compare byte by byte */
while (size-- > 0)
{
/* skip over zero-byte buffers and those that have been completed */
while (xpos >= x[xvec].iov_len)
{
xpos -= x[xvec++].iov_len;
assert(xvec < TEST8_IOVCOUNT);
}
while (ypos >= y[yvec].iov_len)
{
ypos -= y[yvec++].iov_len;
assert(yvec < TEST8_IOVCOUNT);
}
/* compare */
if (((char *) x[xvec].iov_base)[xpos++] !=
((char *) y[yvec].iov_base)[ypos++])
return 0;
}
/* no difference found */
return 1;
}
static size_t iovec_setup(int pattern, struct iovec *iovec, char *buffer, int count)
{
static const size_t bufsizes[TEST8_BUFSZCOUNT] = { 0, 1, TEST8_BUFSZMAX };
int i;
size_t sum = 0;
/* the pattern specifies each buffer */
for (i = 0; i < TEST8_IOVCOUNT; i++)
{
iovec->iov_base = buffer;
sum += iovec->iov_len = bufsizes[pattern % TEST8_BUFSZCOUNT];
iovec++;
buffer += TEST8_BUFSZMAX;
pattern /= TEST8_BUFSZCOUNT;
}
return sum;
}
static int power(int base, int exponent)
{
int result = 1;
/* compute base^exponent */
while (exponent-- > 0)
result *= base;
return result;
}
/***********************************************************************
* EXTENDED FIONS *
**********************************************************************/
/* First extended functions (i.e. not oldfashioned monixcalls.
e(), nlcr(), octal.*/
void e(string)
char *string;
{
printf("Test program error: %s\n", string);
errct++;
}
void nlcr()
{
printf("\n");
}
void str(s)
char *s;
{
printf(s);
}
/*****************************************************************************
* *
* ERR(or) messages *
* *
*****************************************************************************/
void err(number, scall, name)
/* Give nice error messages */
char *scall, *name;
int number;
{
errct++;
if (errct > MAXERR) {
printf("Too many errors; test aborted\n");
chdir("..");
system("rm -rf DIR*");
quit();
}
e("");
str("\t");
switch (number) {
case 0:
str(scall);
str(": illegal initial value.");
break;
case 1:
str(scall);
str(": ");
str(name);
str(" value returned.");
break;
case 2:
str(scall);
str(": accepting illegal ");
str(name);
str(".");
break;
case 3:
str(scall);
str(": accepting non-existing file.");
break;
case 4:
str(scall);
str(": could search non-searchable dir (");
str(name);
str(").");
break;
case 5:
str(scall);
str(": cannot ");
str(scall);
str(" ");
str(name);
str(".");
break;
case 7:
str(scall);
str(": incorrect ");
str(name);
str(".");
break;
case 8:
str(scall);
str(": wrong values.");
break;
case 9:
str(scall);
str(": accepting too many ");
str(name);
str(" files.");
break;
case 10:
str(scall);
str(": even a superuser can't do anything!");
break;
case 11:
str(scall);
str(": could ");
str(name);
str(".");
break;
case 12:
str(scall);
str(": could write in non-writable dir (");
str(name);
str(").");
break;
case 13:
str(scall);
str(": wrong filedes returned (");
str(name);
str(").");
break;
case 100:
str(scall); /* very common */
str(": ");
str(name);
str(".");
break;
default: str("errornumber does not exist!\n");
}
nlcr();
} /* err */
/*****************************************************************************
* *
* MAKE_AND_FILL_DIRS *
* *
*****************************************************************************/
void make_and_fill_dirs()
/* Create 8 dir.'s: "d---", "d--x", "d-w-", "d-wx", "dr--", "dr-x", *
* "drw-", "drwx". * Then create 8 files
* in "drwx", and some needed files in other dirs. */
{
int mode, i;
for (i = 0; i < 8; i++) {
mkdir(dir[i], 0700);
chown(dir[i], USER_ID, GROUP_ID);
}
setuid(USER_ID);
setgid(GROUP_ID);
for (mode = 0; mode < 8; mode++) put_file_in_dir("drwx", mode);
put_file_in_dir("d-wx", RWX);
put_file_in_dir("dr-x", RWX);
put_file_in_dir("drw-", RWX);
chmod_8_dirs(8); /* 8 means; 8 different modes */
} /* make_and_fill_dirs */
void put_file_in_dir(dirname, mode)
char *dirname;
int mode;
/* Fill directory 'dirname' with file with mode 'mode'. */
{
int nr;
if (chdir(dirname) != OK)
err(5, CHDIR, "to dirname (put_f_in_dir)");
else {
/* Creat the file */
if ((nr = creat(fnames[mode], mode * 0100)) < 0)
err(13, CREAT, fnames[mode]);
else
try_close(nr, fnames[mode]);
if (chdir("..") != OK)
err(5, CHDIR, "to previous dir (put_f_in_dir)");
}
} /* put_file_in_dir */
/*****************************************************************************
* *
* MISCELLANEOUS *
* *
*(all about arrays, 'try_close', 'try_unlink', 'Remove', 'get_mode') *
* *
*****************************************************************************/
void init_array(a)
char *a;
{
int i;
i = 0;
while (i++ < ARSIZE) *a++ = 'a' + (i % 26);
} /* init_array */
void clear_array(b)
char *b;
{
int i;
i = 0;
while (i++ < ARSIZE) *b++ = '0';
} /* clear_array */
int comp_array(a, b, range)
char *a, *b;
int range;
{
if ((range < 0) || (range > ARSIZE)) {
err(100, "comp_array", "illegal range");
return(FAIL);
} else {
while (range-- && (*a++ == *b++));
if (*--a == *--b)
return(OK);
else
return(FAIL);
}
} /* comp_array */
void try_close(filedes, name)
int filedes;
char *name;
{
if (close(filedes) != OK) err(5, CLOSE, name);
} /* try_close */
void try_unlink(fname)
char *fname;
{
if (unlink(fname) != 0) err(5, UNLINK, fname);
} /* try_unlink */
void Remove(fdes, fname)
int fdes;
char *fname;
{
try_close(fdes, fname);
try_unlink(fname);
} /* Remove */
int get_mode(name)
char *name;
{
struct stat stbf1;
if (stat(name, &stbf1) != OK) {
err(5, STAT, name);
return(stbf1.st_mode); /* return a mode which will cause *
* error in the calling function *
* (file/dir bit) */
} else
return(stbf1.st_mode & 07777); /* take last 4 bits */
} /* get_mode */
/*****************************************************************************
* *
* CHECK *
* *
*****************************************************************************/
void check(scall, number)
int number;
char *scall;
{
if (errno != number) {
e(NIL);
str("\t");
str(scall);
str(": bad errno-value: ");
put(errno);
str(" should have been: ");
put(number);
nlcr();
}
} /* check */
void put(nr)
int nr;
{
switch (nr) {
case 0: str("unused"); break;
case 1: str("EPERM"); break;
case 2: str("ENOENT"); break;
case 3: str("ESRCH"); break;
case 4: str("EINTR"); break;
case 5: str("EIO"); break;
case 6: str("ENXIO"); break;
case 7: str("E2BIG"); break;
case 8: str("ENOEXEC"); break;
case 9: str("EBADF"); break;
case 10: str("ECHILD"); break;
case 11: str("EAGAIN"); break;
case 12: str("ENOMEM"); break;
case 13: str("EACCES"); break;
case 14: str("EFAULT"); break;
case 15: str("ENOTBLK"); break;
case 16: str("EBUSY"); break;
case 17: str("EEXIST"); break;
case 18: str("EXDEV"); break;
case 19: str("ENODEV"); break;
case 20: str("ENOTDIR"); break;
case 21: str("EISDIR"); break;
case 22: str("EINVAL"); break;
case 23: str("ENFILE"); break;
case 24: str("EMFILE"); break;
case 25: str("ENOTTY"); break;
case 26: str("ETXTBSY"); break;
case 27: str("EFBIG"); break;
case 28: str("ENOSPC"); break;
case 29: str("ESPIPE"); break;
case 30: str("EROFS"); break;
case 31: str("EMLINK"); break;
case 32: str("EPIPE"); break;
case 33: str("EDOM"); break;
case 34: str("ERANGE"); break;
}
}
/*****************************************************************************
* *
* ALOT-functions *
* *
*****************************************************************************/
int open_alot()
{
int i;
for (i = 0; i < MAXOPEN; i++)
if (open(file[i], R) == FAIL) break;
if (i == 0) err(5, "open_alot", "at all");
return(i);
} /* open_alot */
int close_alot(number)
int number;
{
int i, count = 0;
if (number > MAXOPEN)
err(5, "close_alot", "accept this argument");
else
for (i = FF; i < number + FF; i++)
if (close(i) != OK) count++;
return(number - count); /* return number of closed files */
} /* close_alot */
/*****************************************************************************
* *
* CLEAN UP THE MESS *
* *
*****************************************************************************/
void clean_up_the_mess()
{
int i;
char dirname[6];
/* First remove 'alot' files */
for (i = 0; i < MAXOPEN; i++) try_unlink(file[i]);
/* Unlink the files in dir 'drwx' */
if (chdir("drwx") != OK)
err(5, CHDIR, "to 'drwx'");
else {
for (i = 0; i < 8; i++) try_unlink(fnames[i]);
if (chdir("..") != OK) err(5, CHDIR, "to '..'");
}
/* Before unlinking files in some dirs, make them writable */
chmod_8_dirs(RWX);
/* Unlink files in other dirs */
try_unlink("d-wx/rwx");
try_unlink("dr-x/rwx");
try_unlink("drw-/rwx");
/* Unlink dirs */
for (i = 0; i < 8; i++) {
strcpy(dirname, "d");
strcat(dirname, fnames[i]);
/* 'dirname' contains the directoryname */
rmdir(dirname);
}
/* FINISH */
} /* clean_up_the_mess */
void chmod_8_dirs(sw)
int sw; /* if switch == 8, give all different
* mode,else the same mode */
{
int mode;
int i;
if (sw == 8)
mode = 0;
else
mode = sw;
for (i = 0; i < 8; i++) {
chmod(dir[i], 040000 + mode * 0100);
if (sw == 8) mode++;
}
}
void quit()
{
chdir("..");
system("rm -rf DIR*");
if (errct == 0) {
printf("ok\n");
exit(0);
} else {
printf("%d errors\n", errct);
exit(1);
}
}