minix3/tests/test17.c

867 lines
22 KiB
C

/* 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> /* type defs */
#include <sys/stat.h> /* struct stat */
#include <sys/wait.h>
#include <errno.h> /* the error-numbers */
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <utime.h>
#include <stdio.h>
#include <limits.h>
#include <assert.h>
#define NOCRASH 1 /* test11(), 2nd pipe */
#define PDPNOHANG 1 /* test03(), write_standards() */
int max_error = 2;
#include "common.h"
#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 /* max number 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 LINKCOUNT 5
#define MASK 0777 /* selects lower nine bits */
#define END_FILE 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 READ "read"
#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"
/* "decl.c", created by Rene Montsma and Menno Wilcke */
/* Used in open_alot, close_alot */
char *filenames[MAXOPEN];
#define MODES 8
char *mode_fnames[MODES] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"},
*mode_dir[MODES] = {"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 */
int main(int argc, char *argv []);
void test(int mask);
void test01(void);
void test02(void);
void test08(void);
void test09(void);
void test10(void);
int link_alot(char *bigboss);
int unlink_alot(int number);
void get_new(char name []);
void test11(void);
void nlcr(void);
void str(char *s);
void test03(void);
void put_file_in_dir(char *dirname, int mode);
void init_array(char *a);
void clear_array(char *b);
int comp_array(char *a, char *b, int range);
void try_close(int filedes, char *name);
void try_unlink(char *fname);
void Remove(int fdes, char *fname);
int get_mode(char *name);
void check(char *scall, int number);
void put(int nr);
int open_alot(void);
int close_alot(int number);
void clean_up_the_mess(void);
void chmod_8_dirs(int sw);
void quit(void);
/*****************************************************************************
* TEST *
****************************************************************************/
int main(argc, argv)
int argc;
char *argv[];
{
int n, mask, i;
pid_t child;
start(17);
/* Create filenames for MAXOPEN files, the *filenames[] array. */
for(i = 0; i < MAXOPEN; i++) {
if(asprintf(&filenames[i], "file%d", i) == -1) {
fprintf(stderr, "asprintf failed\n");
quit();
}
}
mask = (argc == 2 ? atoi(argv[1]) : 0xFFFF);
subtest = 0;
child = fork();
if (child == -1) {
e(1);
quit();
} else if (child == 0) {
test(mask);
return(0);
} else {
wait(&n);
clean_up_the_mess();
quit();
}
return(-1); /* impossible */
}
void test(mask)
int mask;
{
umask(0); /* not honest, but i always forget */
if (mask & 00001) test01();
if (mask & 00002) test03();
if (mask & 00004) test02();
if (mask & 00010) test08();
if (mask & 00020) test09();
if (mask & 00040) test10();
if (mask & 00100) test11();
umask(022);
} /* test */
/* "t1.c" created by Rene Montsma and Menno Wilcke */
/*****************************************************************************
* test UMASK *
****************************************************************************/
void test01()
{
int oldvalue, newvalue, tempvalue;
int nr;
subtest = 1;
if ((oldvalue = umask(0777)) != 0) e(1);
/* 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) e(2);
if (oldvalue == newvalue) e(3);
if ((tempvalue = umask(0)) != 0) e(4);
/* Now test all possible modes of umask on a file */
for (newvalue = MASK; newvalue >= 0; newvalue -= 0111) {
tempvalue = umask(newvalue);
if (tempvalue != oldvalue) {
e(5);
break; /* no use trying more */
} else if ((nr = creat("file01", 0777)) < 0)
e(6);
else {
try_close(nr, "'file01'");
if (get_mode("file01") != (MASK & ~newvalue))
e(7);
try_unlink("file01");
}
oldvalue = newvalue;
}
/* The loop has terminated with umask(0) */
if ((tempvalue = umask(0)) != 0)
e(8);
} /* test01 */
/*****************************************************************************
* test CREAT *
****************************************************************************/
void test02()
{
int n, n1, mode;
char a[ARSIZE], b[ARSIZE];
struct stat stbf1;
subtest = 2;
mode = 0;
for (n = 0; n < MAXOPEN; n++) {
if (creat(filenames[n], mode) != FF + n)
e(1);
else {
if (get_mode(filenames[n]) != mode)
e(2);
/* 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(filenames[n], 0700) != OK) e(3);
}
mode = (mode + 0100) % 01000;
}
/* Already twenty files opened; opening another has to fail */
if (creat("file02", 0777) != FAIL)
e(4);
else
if (errno != EMFILE) e(5);
/* Close all files: seems blunt, but it isn't because we've *
* checked all fd's already */
if ((n = close_alot(MAXOPEN)) < MAXOPEN) e(6);
/* Creat 1 file twice; check */
if ((n = creat("file02", 0777)) < 0)
e(7);
else {
init_array(a);
if (write(n, a, ARSIZE) != ARSIZE) e(8);
if ((n1 = creat("file02", 0755)) < 0) /* receate 'file02' */
e(9);
else {
/* Fd should be at the top after recreation */
if (lseek(n1, 0L, SEEK_END) != 0)
e(10);
else {
/* Try to write on recreated file */
clear_array(b);
if (lseek(n1, 0L, SEEK_SET) != 0) e(11);
if (write(n1, a, ARSIZE) != ARSIZE) e(12);
/* In order to read we've to close and open again */
try_close(n1, "'file02' (2nd creation)");
if ((n1 = open("file02", RW)) < 0)
e(13);
/* Continue */
if (lseek(n1, 0L, SEEK_SET) != 0) e(14);
if (read(n1, b, ARSIZE) != ARSIZE) e(15);
if (comp_array(a, b, ARSIZE) != OK) e(16);
}
if (get_mode("file02") != 0777) e(17);
try_close(n1, "recreated 'file02'");
}
Remove(n, "file02");
}
/* Give 'creat' wrong input: dir not searchable */
if (creat("drw-/file02", 0777) != FAIL) e(18);
else
if (errno != EACCES) e(19);
/* Dir not writable */
if (creat("dr-x/file02", 0777) != FAIL) e(20);
else
if (errno != EACCES) e(21);
/* File not writable */
if (creat("drwx/r-x", 0777) != FAIL) e(22);
else
if (errno != EACCES) e(23);
/* Try to creat a dir */
if ((n = creat("dir", 040777)) != FAIL) {
if (fstat(n, &stbf1) != OK) e(24);
else if (stbf1.st_mode != (mode_t) 0100777)
/* cast because mode is negative :-( */
e(25);
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) e(26);
else
if (errno != EISDIR) e(27);
} /* test02 */
void test08()
{
subtest = 8;
/* Test chdir to searchable dir */
if (chdir("drwx") != OK) e(1);
else if (chdir("..") != OK) e(2);
/* Check the chdir(".") and chdir("..") mechanism */
if (chdir("drwx") != OK) e(3);
else {
if (chdir(".") != OK) e(4);
/* If we still are in 'drwx' , we should be able to access *
* file 'rwx'. */
if (access("rwx", 0) != OK) e(5);
/* Try to return to previous dir ('/' !!) */
if (chdir("././../././d--x/../d--x/././..") != OK) e(6);
/* Check whether we are back in '/' */
if (chdir("d--x") != OK) e(7);
} /* Return to '..' */
if (chdir("..") != OK) e(8);
if (chdir("././././drwx") != OK) e(9);
else if (chdir("././././..") != OK) e(10);
/* Try giving chdir wrong parameters */
if (chdir("drwx/rwx") != FAIL) e(11);
else
if (errno != ENOTDIR) e(12);
if (chdir("drw-") != FAIL) e(13);
else
if (errno != EACCES) e(14);
} /* test08 */
/*****************************************************************************
* test CHMOD *
****************************************************************************/
void test09()
{
int n;
subtest = 9;
/* Prepare file09 */
if ((n = creat("drwx/file09", 0644)) != FF) e(1);
try_close(n, "'file09'");
/* Try to chmod a file, check and restore old values, check */
if (chmod("drwx/file09", 0700) != OK) e(2);
else {
/* Check protection */
if (get_mode("drwx/file09") != 0700) e(3);
/* Test if chmod accepts just filenames too */
if (chdir("drwx") != OK) e(4);
else if (chmod("file09", 0177) != OK) e(5);
else
/* Check if value has been restored */
if (get_mode("../drwx/file09") != 0177) e(6);
}
/* Try setuid and setgid */
if ((chmod("file09", 04777) != OK) || (get_mode("file09") != 04777))
e(7);
if ((chmod("file09", 02777) != OK) || (get_mode("file09") != 02777))
e(8);
/* Remove testfile */
try_unlink("file09");
if (chdir("..") != OK) e(9);
/* Try to chmod directory */
if (chmod("d---", 0777) != OK) e(10);
else {
if (get_mode("d---") != 0777) e(11);
if (chmod("d---", 0000) != OK) e(12);
/* Check if old value has been restored */
if (get_mode("d---") != 0000) e(13);
}
/* Try to make chmod failures */
/* We still are in dir root */
/* Wrong filename */
if (chmod("non-file", 0777) != FAIL) e(14);
else
if (errno != ENOENT) e(15);
} /* test 09 */
/* "t4.c", created by Rene Montsma and Menno Wilcke */
/*****************************************************************************
* test LINK/UNLINK *
****************************************************************************/
void test10()
{
int n, n1;
char a[ARSIZE], b[ARSIZE], *f, *lf;
subtest = 10;
f = "anotherfile10";
lf = "linkfile10";
if ((n = creat(f, 0702)) != FF) e(1); /* no other open files */
else {
/* Now link correctly */
if (link(f, lf) != OK) e(2);
else if ((n1 = open(lf, RW)) < 0) e(3);
else {
init_array(a);
clear_array(b);
/* Write on 'file10' means being able to * read
* through linked filedescriptor */
if (write(n, a, ARSIZE) != ARSIZE) e(4);
if (read(n1, b, ARSIZE) != ARSIZE) e(5);
if (comp_array(a, b, ARSIZE) != OK) e(6);
/* Clean up: unlink and close (twice): */
Remove(n, f);
try_close(n1, "'linkfile10'");
/* Check if "linkfile" exists and the info * on it
* is correct ('file' has been deleted) */
if ((n1 = open(lf, R)) < 0) e(7);
else {
/* See if 'linkfile' still contains 0..511 ? */
clear_array(b);
if (read(n1, b, ARSIZE) != ARSIZE) e(8);
if (comp_array(a, b, ARSIZE) != OK) e(9);
try_close(n1, "'linkfile10' 2nd time");
try_unlink(lf);
}
}
}
/* Try if unlink fails with incorrect parameters */
/* File does not exist: */
if (unlink("non-file") != FAIL) e(10);
else
if (errno != ENOENT) e(11);
/* Dir can't be written */
if (unlink("dr-x/rwx") != FAIL) e(12);
else
if (errno != EACCES) e(13);
/* Try to unlink a dir being user */
if (unlink("drwx") != FAIL) e(14);
else
if (errno != EPERM) e(15);
/* Try giving link wrong input */
/* First try if link fails with incorrect parameters * name1 does not
* exist. */
if (link("non-file", "linkfile") != FAIL) e(16);
else
if (errno != ENOENT) e(17);
/* Name2 exists already */
if (link("drwx/rwx", "drwx/rw-") != FAIL) e(18);
else
if (errno != EEXIST) e(19);
/* Directory of name2 not writable: */
if (link("drwx/rwx", "dr-x/linkfile") != FAIL) e(20);
else
if (errno != EACCES) e(21);
/* Try to link a dir, being a user */
if (link("drwx", "linkfile") != FAIL) e(22);
else
if (errno != EPERM) e(23);
/* File has too many links */
if ((n = link_alot("drwx/rwx")) != LINKCOUNT - 1) /* file already has one
* link */
e(24);
if (unlink_alot(n) != n) e(25);
} /* test10 */
int link_alot(bigboss)
char *bigboss;
{
int i;
static char employee[6] = "aaaaa";
/* Every file has already got 1 link, so link 0176 times */
for (i = 1; i < LINKCOUNT; i++) {
if (link(bigboss, employee) != OK)
break;
else
get_new(employee);
}
return(i - 1); /* number of linked files */
} /* link_alot */
int unlink_alot(number)
int number; /* number of files to be unlinked */
{
int j;
static char employee[6] = "aaaaa";
for (j = 0; j < number; j++) {
if (unlink(employee) != OK)
break;
else
get_new(employee);
}
return(j); /* return number of unlinked files */
} /* unlink_alot */
void get_new(name)
char name[];
/* Every call changes string 'name' to a string alphabetically *
* higher. Start with "aaaaa", next value: "aaaab" . *
* N.B. after "aaaaz" comes "aaabz" and not "aaaba" (not needed). *
* The last possibility will be "zzzzz". *
* Total # possibilities: 26+25*4 = 126 = MAXLINK -1 (exactly needed) */
{
int i;
for (i = 4; i >= 0; i--)
if (name[i] != 'z') {
name[i]++;
break;
}
} /* get_new */
/*****************************************************************************
* test PIPE *
****************************************************************************/
void test11()
{
int n, fd[2];
char a[ARSIZE], b[ARSIZE];
subtest = 11;
if (pipe(fd) != OK) e(1);
else {
/* Try reading and writing on a pipe */
init_array(a);
clear_array(b);
if (write(fd[1], a, ARSIZE) != ARSIZE) e(2);
else if (read(fd[0], b, (ARSIZE / 2)) != (ARSIZE / 2)) e(3);
else if (comp_array(a, b, (ARSIZE / 2)) != OK) e(4);
else if (read(fd[0], b, (ARSIZE / 2)) != (ARSIZE / 2)) e(5);
else if (comp_array(&a[ARSIZE / 2], b, (ARSIZE / 2)) != OK) e(6);
/* Try to let the pipe make a mistake */
if (write(fd[0], a, ARSIZE) != FAIL) e(7);
if (read(fd[1], b, ARSIZE) != FAIL) e(8);
try_close(fd[1], "'fd[1]'");
/* Now we shouldn't be able to read, because fd[1] has been closed */
if (read(fd[0], b, ARSIZE) != END_FILE) e(9);
try_close(fd[0], "'fd[0]'");
}
if (pipe(fd) < 0) e(10);
else {
/* Test lseek on a pipe: should fail */
if (write(fd[1], a, ARSIZE) != ARSIZE) e(11);
if (lseek(fd[1], 10L, SEEK_SET) != FAIL) e(12);
else
if (errno != ESPIPE) e(13);
/* Eat half of the pipe: no writing should be possible */
try_close(fd[0], "'fd[0]' (2nd time)");
/* This makes UNIX crash: omit it if pdp or VAX */
#ifndef NOCRASH
if (write(fd[1], a, ARSIZE) != FAIL) e(14);
else
if (errno != EPIPE) e(15);
#endif
try_close(fd[1], "'fd[1]' (2nd time)");
}
/* BUG : *
* Here we planned to test if we could write 4K bytes on a pipe. *
* However, this was not possible to implement, because the whole *
* Monix system crashed when we tried to write more then 3584 bytes *
* (3.5K) on a pipe. That's why we try to write only 3.5K in the *
* folowing test. */
if (pipe(fd) < 0) e(16);
else {
for (n = 0; n < (PIPESIZE / ARSIZE); n++)
if (write(fd[1], a, ARSIZE) != ARSIZE) e(17);
try_close(fd[1], "'fd[1]' (3rd time)");
for (n = 0; n < (PIPESIZE / ARSIZE); n++)
if (read(fd[0], b, ARSIZE) != ARSIZE) e(18);
try_close(fd[0], "'fd[0]' (3rd time)");
}
/* Test opening a lot of files */
if ((n = open_alot()) != MAXOPEN) e(19);
if (pipe(fd) != FAIL) e(20);
else
if (errno != EMFILE) e(21);
if (close_alot(n) != n) e(22);
} /* test11 */
/* Err, test03, init_array, clear_array, comp_array,
try_close, try_unlink, Remove, get_mode, check, open_alot,
close_alot, clean_up_the_mess.
*/
/*****************************************************************************
* *
* MAKE_AND_FILL_DIRS *
* *
*****************************************************************************/
void test03()
/* 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;
subtest = 3;
for (i = 0; i < MODES; i++) {
mkdir(mode_dir[i], 0700);
chown(mode_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 */
} /* test03 */
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) e(1);
else {
/* Creat the file */
assert(mode >= 0 && mode < MODES);
if ((nr = creat(mode_fnames[mode], mode * 0100)) < 0) e(2);
else {
try_close(nr, mode_fnames[mode]);
}
if (chdir("..") != OK) e(3);
}
} /* 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;
{
assert(range >= 0 && range <= ARSIZE);
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) e(90);
} /* try_close */
void try_unlink(fname)
char *fname;
{
if (unlink(fname) != 0) e(91);
} /* 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) {
e(92);
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 */
/*****************************************************************************
* *
* ALOT-functions *
* *
*****************************************************************************/
int open_alot()
{
int i;
for (i = 0; i < MAXOPEN; i++)
if (open(filenames[i], R) == FAIL) break;
if (i == 0) e(93);
return(i);
} /* open_alot */
int close_alot(number)
int number;
{
int i, count = 0;
if (number > MAXOPEN)
e(94);
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 'a lot' files */
for (i = 0; i < MAXOPEN; i++) {
try_unlink(filenames[i]);
}
/* Unlink the files in dir 'drwx' */
if (chdir("drwx") != OK)
e(95);
else {
for (i = 0; i < MODES; i++) {
try_unlink(mode_fnames[i]);
}
if (chdir("..") != OK) e(96);
}
/* 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 < MODES; i++) {
strcpy(dirname, "d");
strcat(dirname, mode_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 < MODES; i++) {
chmod(mode_dir[i], 040000 + mode * 0100);
if (sw == 8) mode++;
}
}