1161 lines
31 KiB
C
1161 lines
31 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>
|
||
|
||
#define NOCRASH 1 /* test11(), 2nd pipe */
|
||
#define PDPNOHANG 1 /* test03(), write_standards() */
|
||
#define MAXERR 2
|
||
|
||
#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"
|
||
|
||
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, (int mask));
|
||
_PROTOTYPE(void test01, (void));
|
||
_PROTOTYPE(void test02, (void));
|
||
_PROTOTYPE(void test08, (void));
|
||
_PROTOTYPE(void test09, (void));
|
||
_PROTOTYPE(void test10, (void));
|
||
_PROTOTYPE(int link_alot, (char *bigboss));
|
||
_PROTOTYPE(int unlink_alot, (int number));
|
||
_PROTOTYPE(void get_new, (char name []));
|
||
_PROTOTYPE(void test11, (void));
|
||
_PROTOTYPE(void comp_stats, (struct stat *stbf1, struct stat *stbf2));
|
||
_PROTOTYPE(void comp_inodes, (int m, int m1));
|
||
_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(argc, argv)
|
||
int argc;
|
||
char *argv[];
|
||
{
|
||
char buffer[PATH_MAX + 1];
|
||
int n, mask;
|
||
|
||
sync();
|
||
if (geteuid() == 0 || getuid() == 0) {
|
||
realpath(argv[0], buffer);
|
||
execl("/usr/bin/su", "/usr/bin/su", "-", "ast", "-c", buffer, NULL);
|
||
printf("Test 17 cannot run as root; test aborted\n");
|
||
exit(1);
|
||
}
|
||
|
||
system("rm -rf DIR_17; mkdir DIR_17");
|
||
chdir("DIR_17");
|
||
|
||
mask = (argc == 2 ? atoi(argv[1]) : 0xFFFF);
|
||
|
||
if (fork()) {
|
||
printf("Test 17 ");
|
||
fflush(stdout);
|
||
|
||
wait(&n);
|
||
clean_up_the_mess();
|
||
quit();
|
||
} else {
|
||
test(mask);
|
||
exit(0);
|
||
}
|
||
return(-1); /* impossible */
|
||
}
|
||
|
||
void test(mask)
|
||
int mask;
|
||
{
|
||
umask(0); /* not honest, but i always forget */
|
||
|
||
if (mask & 00001) test01();
|
||
if (mask & 00002) make_and_fill_dirs();
|
||
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;
|
||
|
||
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 :-( */
|
||
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 */
|
||
|
||
void test08()
|
||
{
|
||
/* Test chdir to searchable dir */
|
||
if (chdir("drwx") != OK)
|
||
err(5, CHDIR, "to accessible dir");
|
||
else if (chdir("..") != OK)
|
||
err(11, CHDIR, "not return to '..'");
|
||
|
||
/* Check the chdir(".") and chdir("..") mechanism */
|
||
if (chdir("drwx") != OK)
|
||
err(5, CHDIR, "to 'drwx'");
|
||
else {
|
||
if (chdir(".") != OK) err(5, CHDIR, "to working dir (.)");
|
||
|
||
/* If we still are in 'drwx' , we should be able to access *
|
||
* file 'rwx'. */
|
||
if (access("rwx", 0) != OK) err(5, CHDIR, "rightly to '.'");
|
||
|
||
/* Try to return to previous dir ('/' !!) */
|
||
if (chdir("././../././d--x/../d--x/././..") != OK)
|
||
err(5, CHDIR, "to motherdir (..)");
|
||
|
||
/* Check whether we are back in '/' */
|
||
if (chdir("d--x") != OK) err(5, CHDIR, "rightly to a '..'");
|
||
}
|
||
|
||
/* Return to '..' */
|
||
if (chdir("..") != OK) err(5, CHDIR, "to '..'");
|
||
|
||
if (chdir("././././drwx") != OK)
|
||
err(11, CHDIR, "not follow a path");
|
||
else if (chdir("././././..") != OK)
|
||
err(11, CHDIR, "not return to path");
|
||
|
||
/* Try giving chdir wrong parameters */
|
||
if (chdir("drwx/rwx") != FAIL)
|
||
err(11, CHDIR, "chdir to a file");
|
||
else
|
||
check(CHDIR, ENOTDIR);
|
||
|
||
if (chdir("drw-") != FAIL)
|
||
err(4, CHDIR, "'/drw-'");
|
||
else
|
||
check(CHDIR, EACCES);
|
||
|
||
/* To be sure: return to root */
|
||
/* If (chdir("/") != OK) err(5, CHDIR, "to '/' (2nd time)"); */
|
||
} /* test08 */
|
||
|
||
/* New page */
|
||
/*****************************************************************************
|
||
* test CHMOD *
|
||
****************************************************************************/
|
||
void test09()
|
||
{
|
||
int n;
|
||
|
||
/* Prepare file09 */
|
||
if ((n = creat("drwx/file09", 0644)) != FF) err(5, CREAT, "'drwx/file09'");
|
||
|
||
try_close(n, "'file09'");
|
||
|
||
/* Try to chmod a file, check and restore old values, check */
|
||
if (chmod("drwx/file09", 0700) != OK)
|
||
err(5, CHMOD, "'drwx/file09'"); /* set rwx */
|
||
else {
|
||
/* Check protection */
|
||
if (get_mode("drwx/file09") != 0700) err(7, CHMOD, "mode");
|
||
|
||
/* Test if chmod accepts just filenames too */
|
||
if (chdir("drwx") != OK)
|
||
err(5, CHDIR, "to '/drwx'");
|
||
else if (chmod("file09", 0177) != OK) /* restore oldies */
|
||
err(5, CHMOD, "'h1'");
|
||
else
|
||
/* Check if value has been restored */
|
||
if (get_mode("../drwx/file09") != 0177)
|
||
err(7, CHMOD, "restored mode");
|
||
}
|
||
|
||
/* Try setuid and setgid */
|
||
if ((chmod("file09", 04777) != OK) || (get_mode("file09") != 04777))
|
||
err(11, CHMOD, "not set uid-bit");
|
||
if ((chmod("file09", 02777) != OK) || (get_mode("file09") != 02777))
|
||
err(11, CHMOD, "not set gid-bit");
|
||
|
||
/* Remove testfile */
|
||
try_unlink("file09");
|
||
|
||
if (chdir("..") != OK) err(5, CHDIR, "to '..'");
|
||
|
||
/* Try to chmod directory */
|
||
if (chmod("d---", 0777) != OK)
|
||
err(5, CHMOD, "dir 'd---'");
|
||
else {
|
||
if (get_mode("d---") != 0777) err(7, CHMOD, "protection value");
|
||
if (chmod("d---", 0000) != OK) err(5, CHMOD, "dir 'a' 2nd time");
|
||
|
||
/* Check if old value has been restored */
|
||
if (get_mode("d---") != 0000)
|
||
err(7, CHMOD, "restored protection value");
|
||
}
|
||
|
||
/* Try to make chmod failures */
|
||
|
||
/* We still are in dir root */
|
||
/* Wrong filename */
|
||
if (chmod("non-file", 0777) != FAIL)
|
||
err(3, CHMOD, NIL);
|
||
else
|
||
check(CHMOD, ENOENT);
|
||
|
||
} /* test 09 */
|
||
|
||
/* New page */
|
||
|
||
/* "t4.c", created by Rene Montsma and Menno Wilcke */
|
||
|
||
/*****************************************************************************
|
||
* test LINK/UNLINK *
|
||
****************************************************************************/
|
||
void test10()
|
||
{
|
||
int n, n1;
|
||
char a[ARSIZE], b[ARSIZE], *f, *lf;
|
||
|
||
f = "file10";
|
||
lf = "linkfile10";
|
||
|
||
if ((n = creat(f, 0702)) != FF) /* no other open files */
|
||
err(13, CREAT, f);
|
||
else {
|
||
/* Now link correctly */
|
||
if (link(f, lf) != OK)
|
||
err(5, LINK, lf);
|
||
else if ((n1 = open(lf, RW)) < 0)
|
||
err(5, OPEN, "'linkfile10'");
|
||
else {
|
||
init_array(a);
|
||
clear_array(b);
|
||
|
||
/* Write on 'file10' means being able to * read
|
||
* through linked filedescriptor */
|
||
if (write(n, a, ARSIZE) != ARSIZE) err(1, WRITE, "bad");
|
||
if (read(n1, b, ARSIZE) != ARSIZE) err(1, READ, "bad");
|
||
if (comp_array(a, b, ARSIZE) != OK) err(8, "r/w", NIL);
|
||
|
||
/* 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)
|
||
err(5, OPEN, "'linkfile10'");
|
||
else {
|
||
/* See if 'linkfile' still contains 0..511 ? */
|
||
|
||
clear_array(b);
|
||
if (read(n1, b, ARSIZE) != ARSIZE)
|
||
err(1, READ, "bad");
|
||
if (comp_array(a, b, ARSIZE) != OK)
|
||
err(8, "r/w", NIL);
|
||
|
||
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)
|
||
err(2, UNLINK, "name");
|
||
else
|
||
check(UNLINK, ENOENT);
|
||
|
||
/* Dir can't be written */
|
||
if (unlink("dr-x/rwx") != FAIL)
|
||
err(11, UNLINK, "could unlink in non-writable dir.");
|
||
else
|
||
check(UNLINK, EACCES);
|
||
|
||
/* Try to unlink a dir being user */
|
||
if (unlink("drwx") != FAIL)
|
||
err(11, UNLINK, "unlink dir's as user");
|
||
else
|
||
check(UNLINK, EPERM);
|
||
|
||
/* Try giving link wrong input */
|
||
|
||
/* First try if link fails with incorrect parameters * name1 does not
|
||
* exist. */
|
||
if (link("non-file", "linkfile") != FAIL)
|
||
err(2, LINK, "1st name");
|
||
else
|
||
check(LINK, ENOENT);
|
||
|
||
/* Name2 exists already */
|
||
if (link("drwx/rwx", "drwx/rw-") != FAIL)
|
||
err(2, LINK, "2nd name");
|
||
else
|
||
check(LINK, EEXIST);
|
||
|
||
/* Directory of name2 not writable: */
|
||
if (link("drwx/rwx", "dr-x/linkfile") != FAIL)
|
||
err(11, LINK, "link non-writable file");
|
||
else
|
||
check(LINK, EACCES);
|
||
|
||
/* Try to link a dir, being a user */
|
||
if (link("drwx", "linkfile") != FAIL)
|
||
err(11, LINK, "link a dir without superuser!");
|
||
else
|
||
check(LINK, EPERM);
|
||
|
||
/* File has too many links */
|
||
if ((n = link_alot("drwx/rwx")) != LINKCOUNT - 1) /* file already has one
|
||
* link */
|
||
err(5, LINK, "many files");
|
||
if (unlink_alot(n) != n) err(5, UNLINK, "all linked files");
|
||
|
||
} /* 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 */
|
||
|
||
/* New page */
|
||
|
||
/*****************************************************************************
|
||
* test PIPE *
|
||
****************************************************************************/
|
||
void test11()
|
||
{
|
||
int n, fd[2];
|
||
char a[ARSIZE], b[ARSIZE];
|
||
|
||
if (pipe(fd) != OK)
|
||
err(13, PIPE, NIL);
|
||
else {
|
||
/* Try reading and writing on a pipe */
|
||
init_array(a);
|
||
clear_array(b);
|
||
|
||
if (write(fd[1], a, ARSIZE) != ARSIZE)
|
||
err(5, WRITE, "on pipe");
|
||
else if (read(fd[0], b, (ARSIZE / 2)) != (ARSIZE / 2))
|
||
err(5, READ, "on pipe (2nd time)");
|
||
else if (comp_array(a, b, (ARSIZE / 2)) != OK)
|
||
err(7, PIPE, "values read/written");
|
||
else if (read(fd[0], b, (ARSIZE / 2)) != (ARSIZE / 2))
|
||
err(5, READ, "on pipe 2");
|
||
else if (comp_array(&a[ARSIZE / 2], b, (ARSIZE / 2)) != OK)
|
||
err(7, PIPE, "pipe created");
|
||
|
||
/* Try to let the pipe make a mistake */
|
||
if (write(fd[0], a, ARSIZE) != FAIL)
|
||
err(11, WRITE, "write on fd[0]");
|
||
if (read(fd[1], b, ARSIZE) != FAIL) err(11, READ, "read on fd[1]");
|
||
|
||
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) err(2, PIPE, "'fd[1]'");
|
||
|
||
try_close(fd[0], "'fd[0]'");
|
||
}
|
||
if (pipe(fd) < 0)
|
||
err(5, PIPE, "2nd time");
|
||
else {
|
||
/* Test lseek on a pipe: should fail */
|
||
if (write(fd[1], a, ARSIZE) != ARSIZE)
|
||
err(5, WRITE, "on pipe (2nd time)");
|
||
if (lseek(fd[1], 10L, SEEK_SET) != FAIL)
|
||
err(11, LSEEK, "lseek on a pipe");
|
||
else
|
||
check(PIPE, ESPIPE);
|
||
|
||
/* 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)
|
||
err(11, WRITE, "write on wrong pipe");
|
||
else
|
||
check(PIPE, EPIPE);
|
||
#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)
|
||
err(5, PIPE, "3rd time");
|
||
else {
|
||
for (n = 0; n < (PIPESIZE / ARSIZE); n++)
|
||
if (write(fd[1], a, ARSIZE) != ARSIZE)
|
||
err(5, WRITE, "on pipe (3rd time) 4K");
|
||
try_close(fd[1], "'fd[1]' (3rd time)");
|
||
|
||
for (n = 0; n < (PIPESIZE / ARSIZE); n++)
|
||
if (read(fd[0], b, ARSIZE) != ARSIZE)
|
||
err(5, READ, "from pipe (3rd time) 4K");
|
||
try_close(fd[0], "'fd[0]' (3rd time)");
|
||
}
|
||
|
||
/* Test opening a lot of files */
|
||
if ((n = open_alot()) != MAXOPEN) err(5, OPEN, "MAXOPEN files");
|
||
if (pipe(fd) != FAIL)
|
||
err(9, PIPE, "open");
|
||
else
|
||
check(PIPE, EMFILE);
|
||
if (close_alot(n) != n) err(5, CLOSE, "all opened files");
|
||
} /* test11 */
|
||
|
||
/* New page */
|
||
|
||
void comp_stats(stbf1, stbf2)
|
||
struct stat *stbf1, *stbf2;
|
||
{
|
||
if (stbf1->st_dev != stbf2->st_dev) err(7, "st/fst", "'dev'");
|
||
if (stbf1->st_ino != stbf2->st_ino) err(7, "st/fst", "'ino'");
|
||
if (stbf1->st_mode != stbf2->st_mode) err(7, "st/fst", "'mode'");
|
||
if (stbf1->st_nlink != stbf2->st_nlink) err(7, "st/fst", "'nlink'");
|
||
if (stbf1->st_uid != stbf2->st_uid) err(7, "st/fst", "'uid'");
|
||
if (stbf1->st_gid != stbf2->st_gid) err(7, "st/fst", "'gid'");
|
||
if (stbf1->st_rdev != stbf2->st_rdev) err(7, "st/fst", "'rdev'");
|
||
if (stbf1->st_size != stbf2->st_size) err(7, "st/fst", "'size'");
|
||
if (stbf1->st_atime != stbf2->st_atime) err(7, "st/fst", "'atime'");
|
||
if (stbf1->st_mtime != stbf2->st_mtime) err(7, "st/fst", "'mtime'");
|
||
} /* comp_stats */
|
||
|
||
/* New page */
|
||
|
||
/* "t5.c", created by Rene Montsma and Menno Wilcke */
|
||
|
||
void comp_inodes(m, m1)
|
||
int m, m1; /* twee filedes's */
|
||
{
|
||
struct stat stbf1, stbf2;
|
||
|
||
if (fstat(m, &stbf1) == OK)
|
||
if (fstat(m1, &stbf2) == OK) {
|
||
if (stbf1.st_ino != stbf2.st_ino)
|
||
err(7, DUP, "inode number");
|
||
} else
|
||
err(100, "comp_inodes", "cannot 'fstat' (m1)");
|
||
else
|
||
err(100, "comp_inodes", "cannot 'fstat' (m)");
|
||
} /* comp_inodes */
|
||
|
||
/* "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.
|
||
*/
|
||
|
||
/***********************************************************************
|
||
* EXTENDED FIONS *
|
||
**********************************************************************/
|
||
/* First extended functions (i.e. not oldfashioned monixcalls.
|
||
e(), nlcr(), octal.*/
|
||
|
||
void e(string)
|
||
char *string;
|
||
{
|
||
printf("Error: %s ", string);
|
||
}
|
||
|
||
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");
|
||
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 'a lot' 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);
|
||
}
|
||
}
|