echo x - test22.c
sed '/^X/s///' > test22.c << '/'
X/* test22: umask()		(p) Jan-Mark Wams. email: jms@cs.vu.nl */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <errno.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <stdlib.h>
X#include <sys/wait.h>
X#include <stdio.h>
X
X#define MAX_ERROR 4		/* Stop after ``MAX_ERROR'' errors. */
X#define ITERATIONS 2
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)	if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X
Xint errct = 0;			/* Total error counter. */
Xint subtest = 1;
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test22a, (void));
X_PROTOTYPE(int mode, (char *filename));
X_PROTOTYPE(int umode, (char *filename));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 22 ");
X  fflush(stdout);
X  system("chmod 777 DIR_22/* DIR_22/*/* > /dev/null 2>&1");
X  System("rm -rf DIR_22; mkdir DIR_22");
X  Chdir("DIR_22");
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test22a();
X  }
X
X  quit();
X}
X
Xvoid test22a()
X{
X  int fd1, fd2;
X  int i, oldmask;
X  int stat_loc;			/* For the wait sys call. */
X
X  subtest = 1;
X
X  system("chmod 777 ../DIR_22/* ../DIR_22/*/* > /dev/null 2>&1");
X  System("rm -rf ../DIR_22/*");
X
X  oldmask = 0123;		/* Set oldmask and umask. */
X  umask(oldmask);		/* Set oldmask and umask. */
X
X  /* Check all the possible values of umask. */
X  for (i = 0000; i <= 0777; i++) {
X	if (oldmask != umask(i)) e(1);	/* set umask() */
X	fd1 = open("open", O_CREAT, 0777);
X	if (fd1 != 3) e(2);	/* test open(), */
X	fd2 = creat("creat", 0777);
X	if (fd2 != 4) e(3);	/* creat(), */
X	if (mkdir("dir", 0777) != 0) e(4);	/* mkdir(), */
X	if (mkfifo("fifo", 0777) != 0) e(5);	/* and mkfifo(). */
X
X	if (umode("open") != i) e(6);	/* see if they have */
X	if (umode("creat") != i) e(7);	/* the proper mode */
X	if (umode("dir") != i) e(8);
X	if (umode("fifo") != i) e(9);
X
X	/* Clean up */
X	if (close(fd1) != 0) e(10);
X	if (close(fd2) != 0) e(11);	/* close fd's and */
X	unlink("open");		/* clean the dir */
X	unlink("creat");
X	rmdir("dir");
X	unlink("fifo");
X	oldmask = i;		/* save current mask */
X  }
X
X  /* Check-reset mask */
X  if (umask(0124) != 0777) e(12);
X
X  /* Check if a umask of 0000 leaves the modes alone. */
X  if (umask(0000) != 0124) e(13);
X  for (i = 0000; i <= 0777; i++) {
X	fd1 = open("open", O_CREAT, i);
X	if (fd1 != 3) e(14);	/* test open(), */
X	fd2 = creat("creat", i);
X	if (fd2 != 4) e(15);	/* creat(), */
X	if (mkdir("dir", i) != 0) e(16);	/* mkdir(), */
X	if (mkfifo("fifo", i) != 0) e(17);	/* and mkfifo(). */
X
X	if (mode("open") != i) e(18);	/* see if they have */
X	if (mode("creat") != i) e(19);	/* the proper mode */
X	if (mode("dir") != i) e(20);
X	if (mode("fifo") != i) e(21);
X
X	/* Clean up */
X	if (close(fd1) != 0) e(22);
X	if (close(fd2) != 0) e(23);
X	if (unlink("open") != 0) e(24);
X	unlink("creat");
X	rmdir("dir");
X	unlink("fifo");
X  }
X
X  /* Check if umask survives a fork() */
X  if (umask(0124) != 0000) e(25);
X  switch (fork()) {
X      case -1:	fprintf(stderr, "Can't fork\n");	break;
X      case 0:
X	mkdir("bar", 0777);	/* child makes a dir */
X	exit(0);
X      default:
X	if (wait(&stat_loc) == -1) e(26);
X  }
X  if (umode("bar") != 0124) e(27);
X  rmdir("bar");
X
X  /* Check if umask in child changes umask in parent. */
X  switch (fork()) {
X      case -1:	fprintf(stderr, "Can't fork\n");	break;
X      case 0:
X	switch (fork()) {
X	    case -1:
X		fprintf(stderr, "Can't fork\n");
X		break;
X	    case 0:
X		if (umask(0432) != 0124) e(28);
X		exit(0);
X	    default:
X		if (wait(&stat_loc) == -1) e(29);
X	}
X	if (umask(0423) != 0124) e(30);
X	exit(0);
X      default:
X	if (wait(&stat_loc) == -1) e(31);
X  }
X  if (umask(0342) != 0124) e(32);
X
X  /* See if extra bits are ignored */
X  if (umask(0xFFFF) != 0342) e(33);
X  if (umask(0xFE00) != 0777) e(34);
X  if (umask(01777) != 0000) e(35);
X  if (umask(0022) != 0777) e(36);
X}
X
Xint mode(arg)
Xchar *arg;
X{				/* return the file mode. */
X  struct stat st;
X  Stat(arg, &st);
X  return st.st_mode & 0777;
X}
X
Xint umode(arg)
Xchar *arg;
X{				/* return the umask used for this file */
X  return 0777 ^ mode(arg);
X}
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  system("chmod 777 ../DIR_22/* ../DIR_22/*/* > /dev/null 2>&1");
X  System("rm -rf DIR_22");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test23.c
sed '/^X/s///' > test23.c << '/'
X/* test23: chdir(), getcwd()	Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X#include <limits.h>
X#include <errno.h>
X#include <unistd.h>
X#include <stdlib.h>
X#include <string.h>
X#include <fcntl.h>
X#include <stdio.h>
X
X#define MAX_ERROR 4
X#define ITERATIONS 3
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X
Xint errct;
Xint subtest;
Xint superuser;			/* True if we are root. */
X
Xchar cwd[PATH_MAX];		/* Space for path names. */
Xchar cwd2[PATH_MAX];
Xchar buf[PATH_MAX];
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test23a, (void));
X_PROTOTYPE(void test23b, (void));
X_PROTOTYPE(void test23c, (void));
X_PROTOTYPE(void makelongnames, (void));	/* Fill MaxName etc. */
X_PROTOTYPE(char *last_index, (char *string, int ch));
X_PROTOTYPE(char *my_getcwd, (char *buf, int size));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 23 ");
X  fflush(stdout);
X  System("rm -rf DIR_23; mkdir DIR_23");
X  Chdir("DIR_23");
X  makelongnames();
X  superuser = (geteuid() == 0);
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test23a();	/* Test normal operation */
X	if (m & 0002) test23b();	/* Test critical operation */
X	if (m & 0004) test23c();	/* Test error operation */
X  }
X
X  quit();
X}
X
Xvoid test23a()
X{				/* Test normal operation. */
X  register int i;
X
X  subtest = 1;
X
X  System("rm -rf ../DIR_23/*");
X
X  /* Let's do some fiddeling with path names. */
X  if (getcwd(cwd, PATH_MAX) != cwd) e(1);
X  if (chdir(cwd) != 0) e(2);
X  if (getcwd(buf, PATH_MAX) != buf) e(3);
X  if (strcmp(buf, cwd) != 0) e(4);
X  if (chdir(".") != 0) e(5);
X  if (getcwd(buf, PATH_MAX) != buf) e(6);
X  if (strcmp(buf, cwd) != 0) e(7);
X  if (chdir("./././.") != 0) e(8);
X  if (getcwd(buf, PATH_MAX) != buf) e(9);
X  if (strcmp(buf, cwd) != 0) e(10);
X
X  /* Creat a working dir named "foo", remove any previous residues. */
X  System("rm -rf foo");
X  if (mkdir("foo", 0777) != 0) e(11);
X
X  /* Do some more fiddeling with path names. */
X  if (chdir("foo/.././foo/..") != 0) e(12);	/* change to cwd */
X  if (getcwd(buf, PATH_MAX) != buf) e(13);
X  if (strcmp(buf, cwd) != 0) e(13);
X  if (chdir("foo") != 0) e(14);	/* change to foo */
X  if (chdir("..") != 0) e(15);	/* and back again */
X  if (getcwd(buf, PATH_MAX) != buf) e(16);
X  if (strcmp(buf, cwd) != 0) e(17);
X
X  /* Make 30 sub dirs, eg. ./bar/bar/bar/bar/bar...... */
X  System("rm -rf bar");		/* get ridd of bar */
X  for (i = 0; i < 30; i++) {
X	if (mkdir("bar", 0777) != 0) e(18);
X	if (chdir("bar") != 0) e(19);	/* change to bar */
X  }
X  for (i = 0; i < 30; i++) {
X	if (chdir("..") != 0) e(20);	/* and back again */
X	if (rmdir("bar") != 0) e(21);
X  }
X
X  /* Make sure we are back where we started. */
X  if (getcwd(buf, PATH_MAX) != buf) e(22);
X  if (strcmp(buf, cwd) != 0) e(23);
X  System("rm -rf bar");		/* just incase */
X
X  /* Do some normal checks on `Chdir()' and `getcwd()' */
X  if (chdir("/") != 0) e(24);
X  if (getcwd(buf, PATH_MAX) != buf) e(25);
X  if (strcmp(buf, "/") != 0) e(26);
X  if (chdir("..") != 0) e(27);	/* go to parent of / */
X  if (getcwd(buf, PATH_MAX) != buf) e(28);
X  if (strcmp(buf, "/") != 0) e(29);
X  if (chdir(cwd) != 0) e(30);
X  if (getcwd(buf, PATH_MAX) != buf) e(31);
X  if (strcmp(buf, cwd) != 0) e(32);
X  if (chdir("/tmp") != 0) e(33);/* /tmp might be on RAM */
X  if (getcwd(buf, PATH_MAX) != buf) e(34);	/* might make a difference */
X  if (strcmp(buf, "/tmp") != 0) e(35);
X  if (chdir(cwd) != 0) e(36);
X  if (getcwd(buf, PATH_MAX) != buf) e(37);
X  if (strcmp(buf, cwd) != 0) e(38);
X  if (chdir(".//.//") != 0) e(39);	/* .//.// == current dir */
X  if (getcwd(buf, PATH_MAX) != buf) e(40);
X  if (strcmp(buf, cwd) != 0) e(41);	/* we might be at '/' */
X  if (my_getcwd(buf, PATH_MAX) != buf) e(42);	/* get cwd my way */
X  if (strcmp(cwd, buf) != 0) e(43);
X  System("rm -rf foo");
X}
X
Xvoid test23b()
X{				/* Test critical values. */
X  subtest = 2;
X
X  System("rm -rf ../DIR_23/*");
X
X  /* Fiddle with the size (2nt) parameter of `getcwd ()'. */
X  if (getcwd(cwd, PATH_MAX) != cwd) e(1);	/* get cwd */
X  if (getcwd(buf, strlen(cwd)) != (char *) 0) e(2);   /* size 1 to small */
X  if (errno != ERANGE) e(3);
X  if (getcwd(buf, PATH_MAX) != buf) e(4);
X  if (strcmp(buf, cwd) != 0) e(5);
X  Chdir(cwd);			/* getcwd might cd / */
X  if (getcwd(buf, strlen(cwd) + 1) != buf) e(6);	/* size just ok */
X  if (getcwd(buf, PATH_MAX) != buf) e(7);
X  if (strcmp(buf, cwd) != 0) e(8);
X
X  /* Let's see how "MaxName" and "ToLongName" are handled. */
X  if (mkdir(MaxName, 0777) != 0) e(9);
X  if (chdir(MaxName) != 0) e(10);
X  if (chdir("..") != 0) e(11);
X  if (rmdir(MaxName) != 0) e(12);
X  if (getcwd(buf, PATH_MAX) != buf) e(13);
X  if (strcmp(buf, cwd) != 0) e(14);
X  if (chdir(MaxPath) != 0) e(15);
X  if (getcwd(buf, PATH_MAX) != buf) e(16);
X  if (strcmp(buf, cwd) != 0) e(17);
X
X  if (chdir(ToLongName) != -1) e(18);
X  if (errno != ENOENT) e(20);
X  if (getcwd(buf, PATH_MAX) != buf) e(21);
X  if (strcmp(buf, cwd) != 0) e(22);
X  if (chdir(ToLongPath) != -1) e(23);
X  if (errno != ENAMETOOLONG) e(24);
X  if (getcwd(buf, PATH_MAX) != buf) e(25);
X  if (strcmp(buf, cwd) != 0) e(26);
X}
X
Xvoid test23c()
X{				/* Check reaction to errors */
X  subtest = 3;
X
X  System("rm -rf ../DIR_23/*");
X
X  if (getcwd(cwd, PATH_MAX) != cwd) e(1);	/* get cwd */
X
X  /* Creat a working dir named "foo", remove any previous residues. */
X  System("rm -rf foo; mkdir foo");
X
X  /* Check some obviouse errors. */
X  if (chdir("") != -1) e(2);
X  if (errno != ENOENT) e(3);
X  if (getcwd(buf, PATH_MAX) != buf) e(4);
X  if (strcmp(buf, cwd) != 0) e(5);
X  if (getcwd(buf, 0) != (char *) 0) e(6);
X  if (errno != EINVAL) e(7);
X  if (getcwd(buf, PATH_MAX) != buf) e(8);
X  if (strcmp(buf, cwd) != 0) e(9);
X  if (getcwd(buf, 0) != (char *) 0) e(10);
X  if (errno != EINVAL) e(11);
X  if (getcwd(buf, PATH_MAX) != buf) e(12);
X  if (strcmp(buf, cwd) != 0) e(13);
X  if (chdir(cwd) != 0) e(14);	/* getcwd might be buggy. */
X
X  /* Change the mode of foo, and check the effect. */
X  if (chdir("foo") != 0) e(15);	/* change to foo */
X  if (mkdir("bar", 0777) != 0) e(16);	/* make a new dir bar */
X  if (getcwd(cwd2, PATH_MAX) != cwd2) e(17);	/* get the new cwd */
X  if (getcwd(buf, 3) != (char *) 0) e(18);	/* size is too small */
X  if (errno != ERANGE) e(19);
X  if (getcwd(buf, PATH_MAX) != buf) e(20);
X  if (strcmp(buf, cwd2) != 0) e(21);
X  Chdir(cwd2);			/* getcwd() might cd / */
X  System("chmod 377 .");	/* make foo unreadable */
X  if (getcwd(buf, PATH_MAX) != buf) e(22);	/* dir not readable */
X  if (getcwd(buf, PATH_MAX) != buf) e(23);
X  if (strcmp(buf, cwd2) != 0) e(24);
X  if (chdir("bar") != 0) e(25);	/* at .../foo/bar */
X  if (!superuser) {
X	if (getcwd(buf, PATH_MAX) != (char *) 0) e(26);
X	if (errno != EACCES) e(27);
X  }
X  if (superuser) {
X	if (getcwd(buf, PATH_MAX) != buf) e(28);
X  }
X  if (chdir(cwd2) != 0) e(29);
X  if (getcwd(buf, PATH_MAX) != buf) e(30);
X  if (strcmp(buf, cwd2) != 0) e(31);
X  System("chmod 677 .");	/* make foo inaccessable */
X  if (!superuser) {
X	if (getcwd(buf, PATH_MAX) != (char *) 0) e(32);	/* try to get cwd */
X	if (errno != EACCES) e(33);	/* but no access */
X	if (chdir("..") != -1) e(34);	/* try to get back */
X	if (errno != EACCES) e(35);	/* again no access */
X	if (chdir(cwd) != 0) e(36);	/* get back to cwd */
X	/* `Chdir()' might do path optimizing, it shouldn't. */
X	if (chdir("foo/..") != -1) e(37);	/* no op */
X	if (chdir("foo") != -1) e(38);	/* try to cd to foo */
X	if (errno != EACCES) e(39);	/* no have access */
X	if (getcwd(buf, PATH_MAX) != buf) e(40);
X	if (strcmp(buf, cwd) != 0) e(41);
X  }
X  if (superuser) {
X	if (getcwd(buf, PATH_MAX) != buf) e(42);
X	if (strcmp(buf, cwd2) != 0) e(43);
X	if (chdir("..") != 0) e(44);	/* get back to cwd */
X	if (chdir("foo") != 0) e(45);	/* get back to foo */
X	if (chdir(cwd) != 0) e(46);	/* get back to cwd */
X  }
X  if (getcwd(buf, PATH_MAX) != buf) e(47);	/* check we are */
X  if (strcmp(buf, cwd) != 0) e(48);	/* back at cwd. */
X  Chdir(cwd);			/* just in case... */
X
X  if (chdir("/etc/passwd") != -1) e(49);	/* try to change to a file */
X  if (errno != ENOTDIR) e(50);
X  if (getcwd(buf, PATH_MAX) != buf) e(51);
X  if (strcmp(buf, cwd) != 0) e(52);
X  if (chdir("/notexist") != -1) e(53);
X  if (errno != ENOENT) e(54);
X  if (getcwd(buf, PATH_MAX) != buf) e(55);
X  if (strcmp(buf, cwd) != 0) e(56);
X  System("chmod 777 foo");
X  if (chdir("foo") != 0) e(57);
X
X  /* * Since `foo' is the cwd, it should not be removeable but * if it
X   * were, this code would be found here; *
X   * 
X   *  System ("cd .. ; rm -rf foo");	remove foo *  if (chdir (".")
X   * != -1) e();		try go to. *  if (errno != ENOENT) e();
X   * hould not be an entry *  if (chdir ("..") != -1) e();	try
X   * to get back *  if (errno != ENOENT) e();		should not be
X   * an entry *  if (getcwd (buf, PATH_MAX) != (char *)0) e(); don't
X   * know where we are *
X   * 
X   * What should errno be now ? The cwd might be gone if te superuser *
X   * removed the cwd. (Might even have linked it first.) But this *
X   * testing should be done by the test program for `rmdir()'. */
X  if (chdir(cwd) != 0) e(58);
X}
X
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
X
X/* The following code, is take from pwd written by Adri Koppes */
X
X/* My_getcwd() helper. */
Xchar *last_index(string, ch)
Xchar *string;
Xchar ch;
X{
X  register char *retval = '\0';
X
X  while (*string != '\0') {
X	if (*string == ch) retval = string;
X	string++;
X  }
X  return(retval);
X}
X
X
Xchar *my_getcwd(buf, size)
Xchar *buf;
Xint size;
X{				/* should be like getcwd() */
X  int sd;
X  register int fd;
X  register char *n;
X  char name[128];
X  struct stat s, st, sk;
X  struct direct d;
X
X  if (size <= 0) return(char *) 0;
X
X  *buf = '\0';
X  *name = '\0';
X  stat(".", &s);
X  do {
X	if ((fd = open("..", O_RDONLY)) < 0) return(char *) 0;
X	st.st_dev = s.st_dev;
X	st.st_ino = s.st_ino;
X	stat("..", &s);
X	Chdir("..");
X	sd = sizeof(struct direct);
X	if (s.st_dev == st.st_dev) {
X		do {
X			if (read(fd, (char *) &d, sd) < sd) return(char *) 0;
X		} while (d.d_ino != st.st_ino);
X	} else {
X		do {
X			if (read(fd, (char *) &d, sd) < sd) return(char *) 0;
X			stat(d.d_name, &sk);
X		} while ((sk.st_dev != st.st_dev) ||
X			 (sk.st_ino != st.st_ino));
X	}
X	close(fd);
X	if (strcmp(".", d.d_name) != 0) {
X		strcat(name, "/");
X		strcat(name, d.d_name);
X	}
X  } while ((s.st_ino != st.st_ino) || (s.st_dev != st.st_dev));
X  if (*name == '\0')
X	strncat(buf, "/", size);
X  else
X	while (n = last_index(name, '/')) {
X		n[NAME_MAX] = '\0';
X		strncat(buf, n, size - strlen(buf));
X		*n = '\0';
X	}
X  strncat(buf, name, size - strlen(buf));
X  buf[size - 1] = '\0';
X  Chdir(buf);			/* get back there */
X  return buf;
X}
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_23");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test24.c
sed '/^X/s///' > test24.c << '/'
X/* Test24: opendir, readdir, rewinddir, closedir       Author: Jan-Mark Wams */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <string.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <limits.h>
X#include <fcntl.h>
X#include <dirent.h>
X#include <errno.h>
X#include <time.h>
X#include <stdio.h>
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void chk_dir, (DIR * dirpntr));
X_PROTOTYPE(void test24a, (void));
X_PROTOTYPE(void test24b, (void));
X_PROTOTYPE(void test24c, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
X#define OVERFLOW_DIR_NR	100
X#define MAX_ERROR	4
X#define ITERATIONS 5
X
X#define DIRENT0	((struct dirent *) NULL)
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
X
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 24 ");
X  fflush(stdout);
X  System("rm -rf DIR_24; mkdir DIR_24");
X  Chdir("DIR_24");
X  makelongnames();
X  superuser = (geteuid() == 0);
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test24a();
X	if (m & 0002) test24b();
X	if (m & 0004) test24c();
X  }
X  quit();
X}
X
Xvoid test24a()
X{				/* Test normal operations. */
X  int fd3, fd4, fd5;
X  DIR *dirp;
X  int j, ret, fd, flags;
X  struct stat st1, st2;
X  int stat_loc;
X  time_t time1;
X
X  subtest = 1;
X
X  System("rm -rf ../DIR_24/*");
X
X  if ((fd = dup(0)) != 3) e(1);	/* dup stdin */
X  close(fd);			/* free the fd again */
X  dirp = opendir("/");		/* open "/" */
X  if (dirp == ((DIR *) NULL)) e(2);	/* has to succseed */
X  if ((fd = dup(0)) <= 2) e(3);	/* dup stdin */
X  if (fd > 3) {			/* if opendir() uses fd 3 */
X	flags = fcntl(3, F_GETFD);	/* get fd fags of 3 */
X	if (flags & FD_CLOEXEC != 0) e(4);	/* it should be closed on */
X  }				/* exec..() calls */
X  close(fd);			/* free the fd again */
X  ret = closedir(dirp);		/* close, we don't need it */
X  if (ret == -1) e(5);		/* closedir () unsucces full */
X  if (ret != 0) e(6);		/* should be 0 or -1 */
X  if ((fd = dup(0)) != 3) e(7);	/* see if next fd is same */
X  close(fd);			/* free the fd again */
X
X  System("rm -rf foo; mkdir foo");
X  Chdir("foo");
X  System("touch f1 f2 f3 f4 f5");	/* make f1 .. f5 */
X  System("rm f[24]");		/* creat `holes' in entrys */
X  Chdir("..");
X
X  if ((dirp = opendir("foo")) == ((DIR *) NULL)) e(8);	/* open foo */
X  chk_dir(dirp);		/* test if foo's ok */
X  for (j = 0; j < 10; j++) {
X	errno = j * 47 % 7;	/* there should */
X	if (readdir(dirp) != DIRENT0) e(9);	/* be nomore dir */
X	if (errno != j * 47 % 7) e(10);	/* entrys */
X  }
X  rewinddir(dirp);		/* rewind foo */
X  chk_dir(dirp);		/* test foosok */
X  for (j = 0; j < 10; j++) {
X	errno = j * 23 % 7;	/* there should */
X	if (readdir(dirp) != DIRENT0) e(11);	/* be nomore dir */
X	if (errno != j * 23 % 7) e(12);	/* entrys */
X  }
X  if ((fd4 = creat("foo/f4", 0666)) <= 2) e(13);	/* Open a file. */
X  System("rm foo/f4");		/* Kill entry. */
X  rewinddir(dirp);		/* Rewind foo. */
X  if ((fd3 = open("foo/f3", O_WRONLY)) <= 2) e(14);	/* Open more files. */
X  if ((fd5 = open("foo/f5", O_WRONLY)) <= 2) e(15);
X  if (write(fd3, "Hello", 6) != 6) e(16);
X  if (write(fd4, "Hello", 6) != 6) e(17);	/* write some data */
X  if (close(fd5) != 0) e(18);
X  chk_dir(dirp);
X  for (j = 0; j < 10; j++) {
X	errno = j * 101 % 7;	/* there should */
X	if (readdir(dirp) != DIRENT0) e(19);	/* be nomore dir */
X	if (errno != j * 101 % 7) e(20);	/* entrys */
X  }
X  if (close(fd4) != 0) e(21);	/* shouldn't matter */
X  if (close(fd3) != 0) e(22);	/* when we do this */
X  if (closedir(dirp) != 0) e(23);	/* close foo again */
X
X  Chdir("foo");
X  if ((dirp = opendir(".//")) == ((DIR *) NULL)) e(24);	/* open foo again */
X  Chdir("..");
X  chk_dir(dirp);		/* foosok? */
X  for (j = 0; j < 10; j++) {
X	errno = (j * 101) % 7;	/* there should */
X	if (readdir(dirp) != DIRENT0) e(25);	/* be nomore dir */
X	if (errno != (j * 101) % 7) e(26);	/* entrys */
X  }
X
X  if (closedir(dirp) != 0) e(27);	/* It should be closable */
X
X  stat("foo", &st1);		/* get stat */
X  time(&time1);
X  while (time1 >= time((time_t *)0))
X	;
X  if ((dirp = opendir("foo")) == ((DIR *) NULL)) e(28);	/* open, */
X  if (readdir(dirp) == DIRENT0) e(29);	/* read and */
X  stat("foo", &st2);		/* get new stat */
X  if (st1.st_atime > st2.st_atime) e(30);	/* st_atime check */
X
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	rewinddir(dirp);	/* rewind childs dirp */
X	if (readdir(dirp) == DIRENT0) e(31);	/* read should be ok */
X	if (closedir(dirp) != 0) e(32);	/* close child'd foo */
X	exit(0);		/* 0 stops here */
X      default:
X	if (wait(&stat_loc) == -1) e(33);	/* PARENT wait()'s */
X	break;
X  }
X  if (closedir(dirp) != 0) e(34);	/* close parent's foo */
X}
X
X
Xvoid test24b()
X/* See what happens with too many dir's open. Check if file size seems ok, 
X * and independency
X */
X{ int i, j;			/* i = highest open dir count */
X  DIR *dirp[OVERFLOW_DIR_NR], *dp;
X  struct dirent *dep, *dep1, *dep2;
X  char name[NAME_MAX + 2];	/* buffer for file name, and count */
X  int dot = 0, dotdot = 0;
X
X  subtest = 2;
X
X  System("rm -rf ../DIR_24/*");
X
X  for (i = 0; i < OVERFLOW_DIR_NR; i++) {
X	dirp[i] = opendir("/");
X	if (dirp[i] == ((DIR *) NULL)) {
X		if (errno != EMFILE) e(1);
X		break;
X	}
X  }
X  if (i <= 4) e(2);		/* sounds resanable */
X  if (i >= OVERFLOW_DIR_NR) e(3);	/* might be to small */
X  for (j = 0; j < i; j++) {
X	if (closedir(dirp[(j + 5) % i]) != 0) e(4);	/* neat! */
X  }
X
X  /* Now check if number of bytes in d_name can go up till NAME_MAX */
X  System("rm -rf foo; mkdir foo");
X  Chdir("foo");
X  name[0] = 0;
X  for (i = 0; i <= NAME_MAX; i++) {
X	if (strcat(name, "X") != name) e(5);
X	close(creat(name, 0666));	/* fails once on */
X  }				/* XX..XX, 1 too long */
X  Chdir("..");
X  /* Now change i-th X to Y in name buffer record file of length i. */
X  if ((dp = opendir("foo")) == ((DIR *) NULL)) e(6);
X  while ((dep = readdir(dp)) != DIRENT0) {
X	if (strcmp("..", dep->d_name) == 0)
X		dotdot++;
X	else if (strcmp(".", dep->d_name) == 0)
X		dot++;
X	else
X		name[strlen(dep->d_name)] += 1;	/* 'X' + 1 == 'Y' */
X  }
X  if (closedir(dp) != 0) e(7);
X  for (i = 1; i <= NAME_MAX; i++) {	/* Check if every length */
X	if (name[i] != 'Y') e(8);	/* has been seen once. */
X  }
X
X  /* Check upper and lower bound. */
X  if (name[0] != 'X') e(9);
X  if (name[NAME_MAX + 1] != '\0') e(10);
X
X  /* Now check if two simultaniouse open dirs do the same */
X  if ((dirp[1] = opendir("foo")) == ((DIR *) NULL)) e(11);
X  if ((dirp[2] = opendir("foo")) == ((DIR *) NULL)) e(12);
X  if ((dep1 = readdir(dirp[1])) == DIRENT0) e(13);
X  if ((dep2 = readdir(dirp[2])) == DIRENT0) e(14);
X  if (dep1->d_name == dep2->d_name) e(15);	/* 1 & 2 Should be */
X  strcpy(name, dep2->d_name);	/* differand buffers */
X  if (strcmp(dep1->d_name, name) != 0) e(16);	/* But hold the same */
X  if ((dep1 = readdir(dirp[1])) == DIRENT0) e(17);
X  if ((dep1 = readdir(dirp[1])) == DIRENT0) e(18);	/* lose some entries */
X  if ((dep1 = readdir(dirp[1])) == DIRENT0) e(19);	/* Using dirp 1 has */
X  if (dep1->d_name == dep2->d_name) e(20);	/* no effect on 2 */
X  if (strcmp(dep2->d_name, name) != 0) e(21);
X  rewinddir(dirp[1]);		/* Rewinding dirp 1 */
X  if ((dep2 = readdir(dirp[2])) == DIRENT0) e(22);	/* can't effect 2 */
X  if (strcmp(dep2->d_name, name) == 0) e(23);	/* Must be next */
X  if (closedir(dirp[1]) != 0) e(24);	/* Closing dirp 1 */
X  if ((dep2 = readdir(dirp[2])) == DIRENT0) e(25);	/* can't effect 2 */
X  if (strcmp(dep2->d_name, name) == 0) e(26);	/* Must be next */
X  if (closedir(dirp[2]) != 0) e(27);
X}
X
X
Xvoid test24c()
X{ /* Test whether wrong things go wrong right. */
X  DIR *dirp;
X
X  subtest = 3;
X
X  System("rm -rf ../DIR_24/*");
X
X  if (opendir("foo/bar/nono") != ((DIR *) NULL)) e(1);	/* nonexistent */
X  if (errno != ENOENT) e(2);
X  System("mkdir foo; chmod 677 foo");	/* foo inaccesable */
X  if (opendir("foo/bar/nono") != ((DIR *) NULL)) e(3);
X  if (superuser) {
X	if (errno != ENOENT) e(4);	/* su has access */
X	System("chmod 377 foo");
X	if ((dirp = opendir("foo")) == ((DIR *) NULL)) e(5);
X	if (closedir(dirp) != 0) e(6);
X  }
X  if (!superuser) {
X	if (errno != EACCES) e(7);	/* we don't ;-) */
X	System("chmod 377 foo");
X	if (opendir("foo") != ((DIR *) NULL)) e(8);
X  }
X  System("chmod 777 foo");
X
X  if (mkdir(MaxName, 0777) != 0) e(9);	/* make longdir */
X  if ((dirp = opendir(MaxName)) == ((DIR *) NULL)) e(10);	/* open it */
X  if (closedir(dirp) != 0) e(11);	/* close it */
X  if (rmdir(MaxName) != 0) e(12);	/* then remove it */
X  if ((dirp = opendir(MaxPath)) == ((DIR *) NULL)) e(13);	/* open '.'  */
X  if (closedir(dirp) != 0) e(14);	/* close it */
X  if (closedir(dirp) != -1) e(15);	/* close it again */
X  if (closedir(dirp) != -1) e(16);	/* and again */
X  if (opendir(ToLongName) != ((DIR *) NULL)) e(17);	/* is too long */
X  if (errno != ENOENT) e(19);
X  if (opendir(ToLongPath) != ((DIR *) NULL)) e(20);	/* path is too long */
X  if (errno != ENAMETOOLONG) e(21);
X  System("touch foo/abc");	/* make a file */
X  if (opendir("foo/abc") != ((DIR *) NULL)) e(22);	/* not a dir */
X  if (errno != ENOTDIR) e(23);
X}
X
Xvoid chk_dir(dirp)		/* dir should contain             */
XDIR *dirp;			/* (`f1', `f3', `f5', `.', `..')  */
X{				/* no more, no less               */
X  int f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0,	/* counters for all */
X   other = 0, dot = 0, dotdot = 0;	/* possible entrys */
X  int i;
X  struct dirent *dep;
X  char *fname;
X  int oldsubtest = subtest;
X
X  subtest = 4;
X
X  for (i = 0; i < 5; i++) {	/* 3 files and `.' and `..' == 5 entrys */
X	dep = readdir(dirp);
X	if (dep == DIRENT0) {	/* not einough */
X		if (dep == DIRENT0) e(1);
X		break;
X	}
X	fname = dep->d_name;
X	if (strcmp(fname, ".") == 0)
X		dot++;
X	else if (strcmp(fname, "..") == 0)
X		dotdot++;
X	else if (strcmp(fname, "f1") == 0)
X		f1++;
X	else if (strcmp(fname, "f2") == 0)
X		f2++;
X	else if (strcmp(fname, "f3") == 0)
X		f3++;
X	else if (strcmp(fname, "f4") == 0)
X		f4++;
X	else if (strcmp(fname, "f5") == 0)
X		f5++;
X	else
X		other++;
X  }				/* do next dir entry */
X
X  if (dot != 1) e(2);		/* Check the entrys */
X  if (dotdot != 1) e(3);
X  if (f1 != 1) e(4);
X  if (f3 != 1) e(5);
X  if (f5 != 1) e(6);
X  if (f2 != 0) e(7);
X  if (f4 != 0) e(8);
X  if (other != 0) e(9);
X
X  subtest = oldsubtest;
X}
X
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_24");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test25.c
sed '/^X/s///' > test25.c << '/'
X/* test4: open (), close ()	(p) Jan-Mark Wams. email: jms@cs.vu.nl */
X
X/* Not tested: O_NONBLOCK on special files, supporting it.
X** On a read-only file system, some error reports are to be expected.
X*/
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS	2
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)	if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X#define Creat(f)	if (close(creat(f,0777))!=0) printf("Can't creat %s\n",f)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test25a, (void));
X_PROTOTYPE(void test25b, (void));
X_PROTOTYPE(void test25c, (void));
X_PROTOTYPE(void test25d, (void));
X_PROTOTYPE(void test25e, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (geteuid() == 0 || getuid() == 0) {
X	printf("Test 25 cannot run as root; test aborted\n");
X	exit(1);
X  }
X
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 25 ");
X  fflush(stdout);
X  System("rm -rf DIR_25; mkdir DIR_25");
X  Chdir("DIR_25");
X  makelongnames();
X  superuser = (geteuid() == 0);
X
X  /* Close all files, the parent might have opened. */
X  for (i = 3; i < 100; i++) close(i);
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 001) test25a();
X	if (m & 002) test25b();
X	if (m & 004) test25c();
X	if (m & 010) test25d();
X	if (m & 020) test25e();
X  }
X  quit();
X}
X
Xvoid test25a()
X{				/* Test fcntl flags. */
X  subtest = 1;
X
X#define EXCLUDE(a,b)	(((a)^(b)) == ((a)|(b)))
X#define ADDIT		(O_APPEND | O_CREAT | O_EXCL | O_NONBLOCK | O_TRUNC)
X
X  /* If this compiles all flags are defined but they have to be or-able. */
X  if (!(EXCLUDE(O_NONBLOCK, O_TRUNC))) e(1);
X  if (!(EXCLUDE(O_EXCL, O_NONBLOCK | O_TRUNC))) e(2);
X  if (!(EXCLUDE(O_CREAT, O_EXCL | O_NONBLOCK | O_TRUNC))) e(3);
X  if (!(EXCLUDE(O_APPEND, O_CREAT | O_EXCL | O_NONBLOCK | O_TRUNC))) e(4);
X  if (!(EXCLUDE(O_RDONLY, ADDIT))) e(5);
X  if (!(EXCLUDE(O_WRONLY, ADDIT))) e(6);
X  if (!(EXCLUDE(O_RDWR, ADDIT))) e(7);
X}
X
X
Xvoid test25b()
X{				/* Test normal operation. */
X
X#define BUF_SIZE 1024
X
X  int fd1, fd2, fd3, fd4, fd5;
X  char buf[BUF_SIZE];
X  struct stat st1, st2, st3;
X  time_t time1, time2;
X  int stat_loc;
X
X  subtest = 2;
X
X  System("/bin/rm -rf ../DIR_25/*");
X
X  System("echo Hello > he");	/* make test files */
X  System("echo Hello > ha");	/* size 6 bytes */
X  System("echo Hello > hi");
X  System("echo Hello > ho");
X
X  /* Check path resolution. Check if lowest fds are returned */
X  if ((fd1 = open("he", O_RDONLY)) != 3) e(1);
X  if (read(fd1, buf, BUF_SIZE) != 6) e(2);
X  if ((fd2 = open("./ha", O_RDONLY)) != 4) e(3);
X  if ((fd3 = open("../DIR_25/he", O_RDWR)) != 5) e(4);
X  if ((fd4 = open("ho", O_WRONLY)) != 6) e(5);
X  if (close(fd4) != 0) e(6);
X  if (close(fd1) != 0) e(7);
X  if ((fd1 = open("./././ho", O_RDWR)) != 3) e(8);
X  if ((fd4 = open("../DIR_25/he", O_RDONLY)) != 6) e(9);
X  if (close(fd2) != 0) e(10);
X  if (close(fd3) != 0) e(11);
X  if ((fd2 = open("ha", O_RDONLY)) != 4) e(12);
X  if ((fd3 = open("/etc/passwd", O_RDONLY)) != 5) e(13);
X  if (close(fd4) != 0) e(14);	/* close all */
X  if (close(fd1) != 0) e(15);
X  if (close(fd3) != 0) e(16);
X
X  /* Check if processes share fd2, and if they have independent new fds */
X  System("rm -rf /tmp/sema.25");
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X
X      case 0:
X	if ((fd1 = open("he", O_WRONLY)) != 3) e(17);
X	if ((fd3 = open("../././DIR_25/ha", O_WRONLY)) != 5) e(18);
X	if ((fd4 = open("../DIR_25/hi", O_WRONLY)) != 6) e(19);
X	if ((fd5 = open("ho", O_WRONLY)) != 7) e(20);
X	system("while test ! -f /tmp/sema.25; do sleep 1; done");  /* parent */
X	if (read(fd2, buf, BUF_SIZE) != 3) e(21);	/* gets Hel */
X	if (strncmp(buf, "lo\n", 3) != 0) e(22);	/* we get lo */
X	if (close(fd1) != 0) e(23);
X	if (close(fd2) != 0) e(24);
X	if (close(fd3) != 0) e(25);
X	if (close(fd4) != 0) e(26);
X	if (close(fd5) != 0) e(27);
X	exit(0);
X
X      default:
X	if ((fd1 = open("ha", O_RDONLY)) != 3) e(28);
X	if ((fd3 = open("./he", O_RDONLY)) != 5) e(29);
X	if ((fd4 = open("../DIR_25/hi", O_RDWR)) != 6) e(30);
X	if ((fd5 = open("ho", O_WRONLY)) != 7) e(31);
X	if (close(fd1) != 0) e(32);
X	if (read(fd2, buf, 3) != 3) e(33);	/* get Hel */
X	Creat("/tmp/sema.25");
X	if (strncmp(buf, "Hel", 3) != 0) e(34);
X	if (close(fd2) != 0) e(35);
X	if (close(fd3) != 0) e(36);
X	if (close(fd4) != 0) e(37);
X	if (close(fd5) != 0) e(38);
X	if (wait(&stat_loc) == -1) e(39);
X	if (stat_loc != 0) e(40);
X  }
X  System("/bin/rm -f /tmp/sema.25");
X
X  /* Check if the file status information is updated correctly */
X  Stat("hi", &st1);		/* get info */
X  Stat("ha", &st2);		/* of files */
X  time(&time1);
X  while (time1 >= time((time_t *)0))
X	;			/* wait a sec */
X  if ((fd1 = open("hi", O_RDONLY)) != 3) e(41);	/* open files */
X  if ((fd2 = open("ha", O_WRONLY)) != 4) e(42);
X  if (read(fd1, buf, 1) != 1) e(43);	/* read one */
X  if (close(fd1) != 0) e(44);	/* close one */
X  Stat("hi", &st3);		/* get info */
X  if (st1.st_uid != st3.st_uid) e(45);
X  if (st1.st_gid != st3.st_gid) e(46);	/* should be same */
X  if (st1.st_mode != st3.st_mode) e(47);
X  if (st1.st_size != st3.st_size) e(48);
X  if (st1.st_nlink != st3.st_nlink) e(49);
X  if (st1.st_mtime != st3.st_mtime) e(50);
X  if (st1.st_ctime != st3.st_ctime) e(51);
X#ifndef V1_FILESYSTEM
X  if (st1.st_atime >= st3.st_atime) e(52);	/* except for atime. */
X#endif
X  if (write(fd2, "Howdy\n", 6) != 6) e(53);	/* Update c & mtime. */
X  if ((fd1 = open("ha", O_RDWR)) != 3) e(54);
X  if (read(fd1, buf, 6) != 6) e(55);	/* Update atime. */
X  if (strncmp(buf, "Howdy\n", 6) != 0) e(56);
X  if (close(fd1) != 0) e(57);
X  Stat("ha", &st3);
X  if (st2.st_uid != st3.st_uid) e(58);
X  if (st2.st_gid != st3.st_gid) e(59);	/* should be same */
X  if (st2.st_mode != st3.st_mode) e(60);
X  if (st2.st_nlink != st3.st_nlink) e(61);
X  if (st2.st_ctime >= st3.st_ctime) e(62);
X#ifndef V1_FILESYSTEM
X  if (st2.st_atime >= st3.st_atime) e(63);
X#endif
X  if (st2.st_mtime >= st3.st_mtime) e(64);
X  if (st2.st_size != st3.st_size) e(65);
X  if (close(fd2) != 0) e(66);
X
X  /* Let's see if RDONLY files are read only. */
X  if ((fd1 = open("hi", O_RDONLY)) != 3) e(67);
X  if (write(fd1, " again", 7) != -1) e(68);	/* we can't write */
X  if (errno != EBADF) e(69);	/* a read only fd */
X  if (read(fd1, buf, 7) != 6) e(70);	/* but we can read */
X  if (close(fd1) != 0) e(71);
X
X  /* Let's see if WRONLY files are write only. */
X  if ((fd1 = open("hi", O_WRONLY)) != 3) e(72);
X  if (read(fd1, buf, 7) != -1) e(73);	/* we can't read */
X  if (errno != EBADF) e(74);	/* a write only fd */
X  if (write(fd1, "hELLO", 6) != 6) e(75);	/* but we can write */
X  if (close(fd1) != 0) e(76);
X
X  /* Let's see if files are closable only once. */
X  if (close(fd1) != -1) e(77);
X  if (errno != EBADF) e(78);
X
X  /* Let's see how calling close() with bad fds is handled. */
X  if (close(10) != -1) e(79);
X  if (errno != EBADF) e(80);
X  if (close(111) != -1) e(81);
X  if (errno != EBADF) e(82);
X  if (close(-432) != -1) e(83);
X  if (errno != EBADF) e(84);
X
X  /* Let's see if RDWR files are read & write able. */
X  if ((fd1 = open("hi", O_RDWR)) != 3) e(85);
X  if (read(fd1, buf, 6) != 6) e(86);	/* we can read */
X  if (strncmp(buf, "hELLO", 6) != 0) e(87);	/* and we can write */
X  if (write(fd1, "Hello", 6) != 6) e(88);	/* a read write fd */
X  if (close(fd1) != 0) e(89);
X
X  /* Check if APPENDed files are realy appended */
X  if ((fd1 = open("hi", O_RDWR | O_APPEND)) != 3) e(90);	/* open hi */
X
X  /* An open should set the file offset to 0. */
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 0) e(91);
X
X  /* Writing 0 bytes should not have an effect. */
X  if (write(fd1, "", 0) != 0) e(92);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 0) e(93);	/* the end? */
X
X  /* A seek befor a wirte should not matter with O_APPEND. */
X  Stat("hi", &st1);
X  if (lseek(fd1, (off_t) - 3, SEEK_END) != st1.st_size - 3) e(94);
X
X  /* By writing 1 byte, we force the offset to the end of the file */
X  if (write(fd1, "1", 1) != 1) e(95);
X  Stat("hi", &st1);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != st1.st_size) e(96);
X  if (write(fd1, "2", 1) != 1) e(97);
X  Stat("hi", &st1);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != st1.st_size) e(98);
X  if (write(fd1, "3", 1) != 1) e(99);
X  Stat("hi", &st1);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != st1.st_size) e(100);
X  if (lseek(fd1, (off_t) - 2, SEEK_CUR) <= 0) e(101);
X  if (write(fd1, "4", 1) != 1) e(102);
X
X  /* Since the mode was O_APPEND, the offset should be reset to EOF */
X  Stat("hi", &st1);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != st1.st_size) e(103);
X  if (lseek(fd1, (off_t) - 4, SEEK_CUR) != st1.st_size - 4) e(104);
X  if (read(fd1, buf, BUF_SIZE) != 4) e(105);
X  if (strncmp(buf, "1234", 4) != 0) e(106);
X  if (close(fd1) != 0) e(107);
X
X  /* Check the effect of O_CREAT */
X  Stat("ho", &st1);
X  fd1 = open("ho", O_RDWR | O_CREAT, 0000);
X  if (fd1 != 3) e(108);
X  Stat("ho", &st2);
X  if (memcmp(&st1, &st2, sizeof(struct stat)) != 0) e(109);
X  if (read(fd1, buf, 6) != 6) e(110);
X  if (strncmp(buf, "Hello\n", 6) != 0) e(111);
X  if (write(fd1, "@", 1) != 1) e(112);
X  if (close(fd1) != 0) e(113);
X  (void) umask(0000);
X  fd1 = open("ho", O_RDWR | O_CREAT | O_EXCL, 0777);
X  if (fd1 != -1) e(114);	/* ho exists */
X  System("/bin/rm -rf new");
X  time(&time1);
X  while (time1 >= time((time_t *)0))	
X	;
X  fd1 = open("new", O_RDWR | O_CREAT, 0716);
X  if (fd1 != 3) e(115);		/* new file */
X  Stat("new", &st1);
X  time(&time2);
X  while (time2 >= time((time_t *)0))
X	;
X  time(&time2);
X  if (st1.st_uid != geteuid()) e(116);	/* try this as superuser. */
X  if (st1.st_gid != getegid()) e(117);
X  if ((st1.st_mode & 0777) != 0716) e(118);
X  if (st1.st_nlink != 1) e(119);
X  if (st1.st_mtime <= time1) e(120);
X  if (st1.st_mtime >= time2) e(121);
X#ifndef V1_FILESYSTEM
X  if (st1.st_atime != st1.st_mtime) e(122);
X#endif
X  if (st1.st_ctime != st1.st_mtime) e(123);
X  if (st1.st_size != 0) e(124);
X  if (write(fd1, "I'm new in town", 16) != 16) e(125);
X  if (lseek(fd1, (off_t) - 5, SEEK_CUR) != 11) e(126);
X  if (read(fd1, buf, 5) != 5) e(127);
X  if (strncmp(buf, "town", 5) != 0) e(128);
X  if (close(fd1) != 0) e(129);
X
X  /* Let's test the O_TRUNC flag on this new file. */
X  time(&time1);
X  while (time1 >= time((time_t *)0));
X  if ((fd1 = open("new", O_RDWR | O_TRUNC)) != 3) e(130);
X  Stat("new", &st1);
X  time(&time2);
X  while (time2 >= time((time_t *)0));
X  time(&time2);
X  if ((st1.st_mode & 0777) != 0716) e(131);
X  if (st1.st_size != (size_t) 0) e(132);	/* TRUNCed ? */
X  if (st1.st_mtime <= time1) e(133);
X  if (st1.st_mtime >= time2) e(134);
X  if (st1.st_ctime != st1.st_mtime) e(135);
X  if (close(fd1) != 0) e(136);
X
X  /* Test if file permission bits and the file ownership are unchanged. */
X  /* So we will see if `O_CREAT' has no effect if the file exists. */
X  if (superuser) {
X	System("echo > bar; chmod 077 bar");	/* Make bar 077 */
X	System("chown daemon bar");
X	System("chgrp daemon bar");	/* Daemon's bar */
X	fd1 = open("bar", O_RDWR | O_CREAT | O_TRUNC, 0777);	/* knock knock */
X	if (fd1 == -1) e(137);
X	if (write(fd1, "foo", 3) != 3) e(138);	/* rewrite bar */
X	if (close(fd1) != 0) e(139);
X	Stat("bar", &st1);
X	if (st1.st_uid != 1) e(140);	/* bar is still */
X	if (st1.st_gid != 1) e(141);	/* owned by daemon */
X	if ((st1.st_mode & 0777) != 077) e(142);	/* mode still is 077 */
X	if (st1.st_size != (size_t) 3) e(143);	/* 3 bytes long */
X
X	/* We do the whole thing again, but with O_WRONLY */
X	fd1 = open("bar", O_WRONLY | O_CREAT | O_TRUNC, 0777);
X	if (fd1 == -1) e(144);
X	if (write(fd1, "foobar", 6) != 6) e(145);	/* rewrite bar */
X	if (close(fd1) != 0) e(146);
X	Stat("bar", &st1);
X	if (st1.st_uid != 1) e(147);	/* bar is still */
X	if (st1.st_gid != 1) e(148);	/* owned by daemon */
X	if ((st1.st_mode & 0777) != 077) e(149);	/* mode still is 077 */
X	if (st1.st_size != (size_t) 6) e(150);	/* 6 bytes long */
X  }
X}
X
X
Xvoid test25c()
X{				/* Test normal operation Part two. */
X  int fd1, fd2;
X  char buf[BUF_SIZE];
X  struct stat st;
X  int stat_loc;
X
X  subtest = 3;
X
X  System("/bin/rm -rf ../DIR_25/*");
X
X
X  /* Fifo file test here. */
X  if (mkfifo("fifo", 0777) != 0) e(1);
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);		/* Give child 20 seconds to live. */
X	if ((fd1 = open("fifo", O_RDONLY)) != 3) e(2);
X	if (read(fd1, buf, BUF_SIZE) != 23) e(3);
X	if (strncmp(buf, "1 2 3 testing testing\n", 23) != 0) e(4);
X	if (close(fd1) != 0) e(5);
X	exit(0);
X      default:
X	if ((fd1 = open("fifo", O_WRONLY)) != 3) e(6);
X	if (write(fd1, "1 2 3 testing testing\n", 23) != 23) e(7);
X	if (close(fd1) != 0) e(8);
X	if (wait(&stat_loc) == -1) e(9);
X	if (stat_loc != 0) e(10);	/* The alarm went off? */
X  }
X
X  /* Try opening for writing with O_NONBLOCK. */
X  fd1 = open("fifo", O_WRONLY | O_NONBLOCK);
X  if (fd1 != -1) e(11);
X  if (errno != ENXIO) e(12);
X  close(fd1);
X
X  /* Try opening for writing with O_NONBLOCK and O_CREAT. */
X  fd1 = open("fifo", O_WRONLY | O_CREAT | O_NONBLOCK, 0777);
X  if (fd1 != -1) e(13);
X  if (errno != ENXIO) e(14);
X  close(fd1);
X
X  /* Both the NONBLOCK and the EXCLusive give raise to error. */
X  fd1 = open("fifo", O_WRONLY | O_CREAT | O_EXCL | O_NONBLOCK, 0777);
X  if (fd1 != -1) e(15);
X  if (errno != EEXIST && errno != ENXIO) e(16);
X  close(fd1);			/* Just in case. */
X
X  /* Try opening for reading with O_NONBLOCK. */
X  fd1 = open("fifo", O_RDONLY | O_NONBLOCK);
X  if (fd1 != 3) e(17);
X  if (close(fd1) != 0) e(18);
X
X/* Nopt runs out of memory. ;-< We just cut out some valid code */
X  /* FIFO's should always append. (They have no file position.) */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);		/* Give child 20 seconds to live. */
X	if ((fd1 = open("fifo", O_WRONLY)) != 3) e(19);
X	if ((fd2 = open("fifo", O_WRONLY)) != 4) e(20);
X	if (write(fd1, "I did see Elvis.\n", 18) != 18) e(21);
X	if (write(fd2, "I DID.\n", 8) != 8) e(22);
X	if (close(fd2) != 0) e(23);
X	if (close(fd1) != 0) e(24);
X	exit(0);
X      default:
X	if ((fd1 = open("fifo", O_RDONLY)) != 3) e(25);
X	if (read(fd1, buf, 18) != 18) e(26);
X	if (strncmp(buf, "I did see Elvis.\n", 18) != 0) e(27);
X	if (read(fd1, buf, BUF_SIZE) != 8) e(28);
X	if (strncmp(buf, "I DID.\n", 8) != 0) e(29);
X	if (close(fd1) != 0) e(30);
X	if (wait(&stat_loc) == -1) e(31);
X	if (stat_loc != 0) e(32);	/* The alarm went off? */
X  }
X
X  /* O_TRUNC should have no effect on FIFO files. */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);		/* Give child 20 seconds to live. */
X	if ((fd1 = open("fifo", O_WRONLY)) != 3) e(33);
X	if (write(fd1, "I did see Elvis.\n", 18) != 18) e(34);
X	if ((fd2 = open("fifo", O_WRONLY | O_TRUNC)) != 4) e(35);
X	if (write(fd2, "I DID.\n", 8) != 8) e(36);
X	if (close(fd2) != 0) e(37);
X	if (close(fd1) != 0) e(38);
X	exit(0);
X      default:
X	if ((fd1 = open("fifo", O_RDONLY)) != 3) e(39);
X	if (read(fd1, buf, 18) != 18) e(40);
X	if (strncmp(buf, "I did see Elvis.\n", 18) != 0) e(41);
X	if (read(fd1, buf, BUF_SIZE) != 8) e(42);
X	if (strncmp(buf, "I DID.\n", 8) != 0) e(43);
X	if (close(fd1) != 0) e(44);
X	if (wait(&stat_loc) == -1) e(45);
X	if (stat_loc != 0) e(46);	/* The alarm went off? */
X  }
X
X  /* Closing the last fd should flush all data to the bitbucket. */
X  System("rm -rf /tmp/sema.25");
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X
X      case 0:
X	alarm(20);		/* Give child 20 seconds to live. */
X	if ((fd1 = open("fifo", O_WRONLY)) != 3) e(47);
X	if (write(fd1, "I did see Elvis.\n", 18) != 18) e(48);
X	Creat("/tmp/sema.25");
X	sleep(1);		/* give parent a chance to open */
X	if (close(fd1) != 0) e(49);
X	exit(0);
X
X      default:
X	if ((fd1 = open("fifo", O_RDONLY)) != 3) e(50);
X	/* Make `sure' write has closed. */
X	while (stat("/tmp/sema.25", &st) != 0) sleep(1);
X	if (close(fd1) != 0) e(51);
X	if ((fd1 = open("fifo", O_RDONLY | O_NONBLOCK)) != 3) e(52);
X	if (read(fd1, buf, BUF_SIZE) != 18) e(53);
X	if (close(fd1) != 0) e(54);
X	if (wait(&stat_loc) == -1) e(55);
X	if (stat_loc != 0) e(56);	/* The alarm went off? */
X  }
X
X  /* Let's try one too many. */
X  System("rm -rf /tmp/sema.25");
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);		/* Give child 20 seconds to live. */
X	if ((fd1 = open("fifo", O_WRONLY)) != 3) e(57);
X	if (write(fd1, "I did see Elvis.\n", 18) != 18) e(58);
X
X	/* Keep open till second reader is opened. */
X	while (stat("/tmp/sema.25", &st) != 0) sleep(1);
X	if (close(fd1) != 0) e(59);
X	exit(0);
X      default:
X	if ((fd1 = open("fifo", O_RDONLY)) != 3) e(60);
X	if (read(fd1, buf, 2) != 2) e(61);
X	if (strncmp(buf, "I ", 2) != 0) e(62);
X	if (close(fd1) != 0) e(63);
X	if ((fd1 = open("fifo", O_RDONLY)) != 3) e(64);
X
X	/* Signal second reader is open. */
X	Creat("/tmp/sema.25");
X	if (read(fd1, buf, 4) != 4) e(65);
X	if (strncmp(buf, "did ", 4) != 0) e(66);
X	if ((fd2 = open("fifo", O_RDONLY)) != 4) e(67);
X	if (read(fd2, buf, BUF_SIZE) != 12) e(68);
X	if (strncmp(buf, "see Elvis.\n", 12) != 0) e(69);
X	if (close(fd2) != 0) e(70);
X	if (close(fd1) != 0) e(71);
X	if (wait(&stat_loc) == -1) e(72);
X	if (stat_loc != 0) e(73);	/* The alarm went off? */
X  }
X  System("rm -rf fifo /tmp/sema.25");
X
X  /* O_TRUNC should have no effect on directroys. */
X  System("mkdir dir; touch dir/f1 dir/f2 dir/f3");
X  if ((fd1 = open("dir", O_WRONLY | O_TRUNC)) != -1) e(74);
X  if (errno != EISDIR) e(75);
X  close(fd1);
X
X  /* Opening a directory for reading should be possible. */
X  if ((fd1 = open("dir", O_RDONLY)) != 3) e(76);
X  if (close(fd1) != 0) e(77);
X  if (unlink("dir/f1") != 0) e(78);	/* Should still be there. */
X  if (unlink("dir/f2") != 0) e(79);
X  if (unlink("dir/f3") != 0) e(80);
X  if (rmdir("dir") != 0) e(81);
X
X  if (!superuser) {
X	/* Test if O_CREAT is not usable to open files with the wrong mode */
X	(void) umask(0200);	/* nono has no */
X	System("touch nono");	/* write bit */
X	(void) umask(0000);
X	fd1 = open("nono", O_RDWR | O_CREAT, 0777);	/* try to open */
X	if (fd1 != -1) e(82);
X	if (errno != EACCES) e(83);	/* but no access */
X  }
X}
X
Xvoid test25d()
X{
X  int fd;
X
X  subtest = 4;
X
X  System("/bin/rm -rf ../DIR_25/*");
X
X  /* Test maximal file name length. */
X  if ((fd = open(MaxName, O_RDWR | O_CREAT, 0777)) != 3) e(1);
X  if (close(fd) != 0) e(2);
X  MaxPath[strlen(MaxPath) - 2] = '/';
X  MaxPath[strlen(MaxPath) - 1] = 'a';	/* make ././.../a */
X  if ((fd = open(MaxPath, O_RDWR | O_CREAT, 0777)) != 3) e(3);
X  if (close(fd) != 0) e(4);
X  MaxPath[strlen(MaxPath) - 1] = '/';	/* make ././.../a */
X}
X
X
Xvoid test25e()
X{
X  int fd;
X  char *noread = "noread";	/* Name for unreadable file. */
X  char *nowrite = "nowrite";	/* Same for unwritable. */
X  int stat_loc;
X
X  subtest = 5;
X
X  System("/bin/rm -rf ../DIR_25/*");
X
X  mkdir("bar", 0777);		/* make bar */
X
X  /* Check if no access on part of path generates the correct error. */
X  System("chmod 677 bar");	/* rw-rwxrwx */
X  if (open("bar/nono", O_RDWR | O_CREAT, 0666) != -1) e(1);
X  if (errno != EACCES) e(2);
X
X  /* Ditto for no write permission. */
X  System("chmod 577 bar");	/* r-xrwxrwx */
X  if (open("bar/nono", O_RDWR | O_CREAT, 0666) != -1) e(3);
X  if (errno != EACCES) e(4);
X
X  /* Clean up bar. */
X  System("/bin/rm -rf bar");
X
X  /* Improper flags set on existing file. */
X  System("touch noread; chmod 377 noread");	/* noread */
X  if (open(noread, O_RDONLY) != -1) e(5);
X  if (open(noread, O_RDWR) != -1) e(6);
X  if (open(noread, O_RDWR | O_CREAT, 0777) != -1) e(7);
X  if (open(noread, O_RDWR | O_CREAT | O_TRUNC, 0777) != -1) e(8);
X  if ((fd = open(noread, O_WRONLY)) != 3) e(9);
X  if (close(fd) != 0) e(10);
X  System("touch nowrite; chmod 577 nowrite");	/* nowrite */
X  if (open(nowrite, O_WRONLY) != -1) e(11);
X  if (open(nowrite, O_RDWR) != -1) e(12);
X  if (open(nowrite, O_RDWR | O_CREAT, 0777) != -1) e(13);
X  if (open(nowrite, O_RDWR | O_CREAT | O_TRUNC, 0777) != -1) e(14);
X  if ((fd = open(nowrite, O_RDONLY)) != 3) e(15);
X  if (close(fd) != 0) e(16);
X  if (superuser) {
X	/* If we can make a file ownd by some one else, test access again. */
X	System("chmod 733 noread");
X	System("chown bin noread");
X	System("chgrp system noread");
X	System("chmod 755 nowrite");
X	System("chown bin nowrite");
X	System("chgrp system nowrite");
X	switch (fork()) {
X	    case -1:	printf("Can't fork\n");	break;
X	    case 0:
X		setuid(1);
X		setgid(1);	/* become daemon */
X		if (open(noread, O_RDONLY) != -1) e(17);
X		if (open(noread, O_RDWR) != -1) e(18);
X		if (open(noread, O_RDWR | O_CREAT, 0777) != -1) e(19);
X		fd = open(noread, O_RDWR | O_CREAT | O_TRUNC, 0777);
X		if (fd != -1) e(20);
X		if ((fd = open(noread, O_WRONLY)) != 3) e(21);
X		if (close(fd) != 0) e(22);
X		if (open(nowrite, O_WRONLY) != -1) e(23);
X		if (open(nowrite, O_RDWR) != -1) e(24);
X		if (open(nowrite, O_RDWR | O_CREAT, 0777) != -1) e(25);
X		fd = open(nowrite, O_RDWR | O_CREAT | O_TRUNC, 0777);
X		if (fd != -1) e(26);
X		if ((fd = open(nowrite, O_RDONLY)) != 3) e(27);
X		if (close(fd) != 0) e(28);
X		exit(0);
X	    default:
X		if (wait(&stat_loc) == -1) e(29);
X	}
X  }
X
X  /* Clean up the noread and nowrite files. */
X  System("/bin/rm -rf noread nowrite");
X
X  /* Test the O_EXCL flag. */
X  System("echo > exists");
X  if (open("exists", O_RDWR | O_CREAT | O_EXCL, 0777) != -1) e(30);
X  if (errno != EEXIST) e(31);
X  if (open("exists", O_RDONLY | O_CREAT | O_EXCL, 0777) != -1) e(32);
X  if (errno != EEXIST) e(33);
X  if (open("exists", O_WRONLY | O_CREAT | O_EXCL, 0777) != -1) e(34);
X  if (errno != EEXIST) e(35);
X  fd = open("exists", O_RDWR | O_CREAT | O_EXCL | O_TRUNC, 0777);
X  if (fd != -1) e(36);
X  if (errno != EEXIST) e(37);
X  fd = open("exists", O_RDONLY | O_CREAT | O_EXCL | O_TRUNC, 0777);
X  if (fd != -1) e(38);
X  if (errno != EEXIST) e(39);
X  fd = open("exists", O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 0777);
X  if (fd != -1) e(40);
X  if (errno != EEXIST) e(41);
X
X  /* Test ToLongName and ToLongPath */
X  if ((fd = open(ToLongName, O_RDWR | O_CREAT, 0777)) != 3) e(45);
X  if (close(fd) != 0) e(46);
X  ToLongPath[PATH_MAX - 2] = '/';
X  ToLongPath[PATH_MAX - 1] = 'a';
X  if ((fd = open(ToLongPath, O_RDWR | O_CREAT, 0777)) != -1) e(47);
X  if (errno != ENAMETOOLONG) e(48);
X  if (close(fd) != -1) e(49);
X  ToLongPath[PATH_MAX - 1] = '/';
X}
X
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_25");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test26.c
sed '/^X/s///' > test26.c << '/'
X/* test26: link() unlink()	Aithor: Jan-Mark Wams (jms@cs.vu.nl) */
X
X/*
X * Not tested readonly file systems
X * Not tested fs full
X * Not tested unlinking bussy files
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <fcntl.h>
X#include <errno.h>
X#include <limits.h>
X#include <string.h>
X#include <time.h>
X#include <stdio.h>
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X#define MAX_ERROR 4
X#define ITERATIONS 4
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)	if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test26a, (void));
X_PROTOTYPE(void test26b, (void));
X_PROTOTYPE(void test26c, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int __n));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 26 ");
X  fflush(stdout);
X  System("rm -rf DIR_26; mkdir DIR_26");
X  Chdir("DIR_26");
X  superuser = (getuid() == 0);
X  makelongnames();
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test26a();
X	if (m & 0002) test26b();
X	if (m & 0004) test26c();
X  }
X  quit();
X}
X
Xvoid test26a()
X{				/* Test normal operation. */
X  struct stat st1, st2, st3;
X  time_t time1;
X
X  subtest = 1;
X
X  /* Clean up any residu. */
X  System("rm -rf ../DIR_26/*");
X
X  System("touch foo");		/* make source file */
X  Stat("foo", &st1);		/* get info of foo */
X  Stat(".", &st2);		/* and the cwd */
X  time(&time1);
X  while (time1 >= time((time_t *)0))
X	;			/* wait a sec */
X  if (link("foo", "bar") != 0) e(1);	/* link foo to bar */
X  Stat("foo", &st3);		/* get new status */
X  if (st1.st_nlink + 1 != st3.st_nlink) e(2);	/* link count foo up 1 */
X#ifndef V1_FILESYSTEM
X  if (st1.st_ctime >= st3.st_ctime) e(3);	/* check stattime changed */
X#endif
X  Stat(".", &st1);		/* get parend dir info */
X  if (st2.st_ctime >= st1.st_ctime) e(4);	/* ctime and mtime */
X  if (st2.st_mtime >= st1.st_mtime) e(5);	/* should be updated */
X  Stat("bar", &st2);		/* get info of bar */
X  if (st2.st_nlink != st3.st_nlink) e(6);	/* link count foo == bar */
X  if (st2.st_ino != st3.st_ino) e(7);	/* ino should be same */
X  if (st2.st_mode != st3.st_mode) e(8);	/* check mode same */
X  if (st2.st_uid != st3.st_uid) e(9);	/* check uid same */
X  if (st2.st_gid != st3.st_gid) e(10);	/* check gid same */
X  if (st2.st_size != st3.st_size) e(11);	/* check size */
X  if (st2.st_ctime != st3.st_ctime) e(12);	/* check ctime */
X  if (st2.st_atime != st3.st_atime) e(13);	/* check atime */
X  if (st2.st_mtime != st3.st_mtime) e(14);	/* check mtime */
X  Stat("foo", &st1);		/* get fooinfo */
X  Stat(".", &st2);		/* get dir info */
X  time(&time1);
X  while (time1 >= time((time_t *)0))
X	;			/* wait a sec */
X  if (unlink("bar") != 0) e(15);/* rm bar */
X  if (stat("bar", &st2) != -1) e(16);	/* it's gone */
X  Stat("foo", &st3);		/* get foo again */
X  if (st1.st_nlink != st3.st_nlink + 1) e(17);	/* link count back to normal */
X#ifndef V1_FILESYSTEM
X  if (st1.st_ctime >= st3.st_ctime) e(18);	/* check ctime */
X#endif
X  Stat(".", &st3);		/* get parend dir info */
X  if (st2.st_ctime >= st3.st_ctime) e(19);	/* ctime and mtime */
X  if (st2.st_mtime >= st3.st_mtime) e(20);	/* should be updated */
X}
X
Xvoid test26b()
X{
X  register int nlink;
X  char *bar = "bar.xxx";	/* the xxx wil hold a number from 000 to 999 */
X  struct stat st, st2;
X
X  subtest = 2;
X
X  /* Clean up any residu. */
X  System("rm -rf ../DIR_26/*");
X
X  /* Test what happens if we make LINK_MAX number of links. */
X  System("touch foo");
X  if (LINK_MAX >= 999) e(1);	/* check 3 xs are enough */
X  for (nlink = 2; nlink <= LINK_MAX; nlink++) {
X	bar[4] = (char) ((nlink / 100) % 10) + '0';
X	bar[5] = (char) ((nlink / 10) % 10) + '0';
X	bar[6] = (char) (nlink % 10) + '0';
X	if (link("foo", bar) != 0) e(2);
X	Stat(bar, &st);
X	if (st.st_nlink != nlink) e(3);
X	Stat("foo", &st);
X	if (st.st_nlink != nlink) e(4);
X  }
X
X  /* Check if we have LINK_MAX links that are all the same. */
X  Stat("foo", &st);
X  if (st.st_nlink != LINK_MAX) e(5);
X  for (nlink = 2; nlink <= LINK_MAX; nlink++) {
X	bar[4] = (char) ((nlink / 100) % 10) + '0';
X	bar[5] = (char) ((nlink / 10) % 10) + '0';
X	bar[6] = (char) (nlink % 10) + '0';
X	Stat(bar, &st2);
X	if (memcmp(&st, &st2, sizeof(struct stat)) != 0) e(6);
X  }
X
X  /* Test no more links are possible. */
X  if (link("foo", "nono") != -1) e(7);
X  if (stat("nono", &st) != -1) e(8);
X  Stat("foo", &st);
X  if (st.st_nlink != LINK_MAX) e(9);	/* recheck the number of links */
X
X  /* Now unlink() the bar.### files */
X  for (nlink = LINK_MAX; nlink >= 2; nlink--) {
X	bar[4] = (char) ((nlink / 100) % 10) + '0';
X	bar[5] = (char) ((nlink / 10) % 10) + '0';
X	bar[6] = (char) (nlink % 10) + '0';
X	Stat(bar, &st);
X	if (st.st_nlink != nlink) e(10);
X	Stat("foo", &st2);
X	if (memcmp(&st, &st2, sizeof(struct stat)) != 0) e(11);
X	if (unlink(bar) != 0) e(12);
X  }
X  Stat("foo", &st);
X  if (st.st_nlink != 1) e(13);	/* number of links back to 1 */
X
X  /* Test max path ed. */
X  if (link("foo", MaxName) != 0) e(14);	/* link to MaxName */
X  if (unlink(MaxName) != 0) e(15);	/* and remove it */
X  MaxPath[strlen(MaxPath) - 2] = '/';
X  MaxPath[strlen(MaxPath) - 1] = 'a';	/* make ././.../a */
X  if (link("foo", MaxPath) != 0) e(16);	/* it should be */
X  if (unlink(MaxPath) != 0) e(17);	/* (un)linkable */
X
X  System("rm -f ../DIR_26/*");	/* clean cwd */
X}
X
Xvoid test26c()
X{
X  subtest = 3;
X
X  /* Clean up any residu. */
X  System("rm -rf ../DIR_26/*");
X
X  /* Check some simple things. */
X  if (link("bar/nono", "nono") != -1) e(1);	/* nonexistent */
X  if (errno != ENOENT) e(2);
X  Chdir("..");
X  System("touch DIR_26/foo");
X  System("chmod 677 DIR_26");	/* make inaccesable */
X  if (!superuser) {
X	if (unlink("DIR_26/foo") != -1) e(3);
X	if (errno != EACCES) e(4);
X  }
X  if (link("DIR_26/bar/nono", "DIR_26/nono") != -1) e(5); /* nono no be */
X  if (superuser) {
X	if (errno != ENOENT) e(6);	/* su has access */
X  }
X  if (!superuser) {
X	if (errno != EACCES) e(7);	/* we don't ;-) */
X  }
X  System("chmod 577 DIR_26");	/* make unwritable */
X  if (superuser) {
X	if (link("DIR_26/foo", "DIR_26/nono") != 0) e(8);
X	if (unlink("DIR_26/nono") != 0) e(9);
X  }
X  if (!superuser) {
X	if (link("DIR_26/foo", "DIR_26/nono") != -1) e(10);
X	if (errno != EACCES) e(11);
X	if (unlink("DIR_26/foo") != -1) e(12);	/* try to rm foo/foo */
X	if (errno != EACCES) e(13);
X  }
X  System("chmod 755 DIR_26");	/* back to normal */
X  Chdir("DIR_26");
X
X  /* Too-long path and name test */
X  ToLongPath[strlen(ToLongPath) - 2] = '/';
X  ToLongPath[strlen(ToLongPath) - 1] = 'a';	/* make ././.../a */
X  if (link("foo", ToLongPath) != -1) e(18);	/* path is too long */
X  if (errno != ENAMETOOLONG) e(19);
X  if (unlink(ToLongPath) != -1) e(20);	/* path is too long */
X  if (errno != ENAMETOOLONG) e(21);
X  if (link("foo", "foo") != -1) e(22);	/* try linking foo to foo */
X  if (errno != EEXIST) e(23);
X  if (link("foo", "bar") != 0) e(24);	/* make a link to bar */
X  if (link("foo", "bar") != -1) e(25);	/* try linking to bar again */
X  if (errno != EEXIST) e(26);
X  if (link("foo", "bar") != -1) e(27);	/* try linking to bar again */
X  if (errno != EEXIST) e(28);
X  if (unlink("nono") != -1) e(29);	/* try rm <not exist> */
X  if (errno != ENOENT) e(30);
X  if (unlink("") != -1) e(31);	/* try unlinking empty */
X  if (errno != ENOENT) e(32);
X  if (link("foo", "") != -1) e(33);	/* try linking to "" */
X  if (errno != ENOENT) e(34);
X  if (link("", "foo") != -1) e(35);	/* try linking "" */
X  if (errno != ENOENT) e(36);
X  if (link("", "") != -1) e(37);/* try linking "" to "" */
X  if (errno != ENOENT) e(38);
X  if (link("/foo/bar/foo", "a") != -1) e(39);	/* try no existing path */
X  if (errno != ENOENT) e(40);
X  if (link("foo", "/foo/bar/foo") != -1) e(41);	/* try no existing path */
X  if (errno != ENOENT) e(42);
X  if (link("/a/b/c", "/d/e/f") != -1) e(43);	/* try no existing path */
X  if (errno != ENOENT) e(44);
X  if (link("abc", "a") != -1) e(45);	/* try no existing file */
X  if (errno != ENOENT) e(46);
X  if (link("foo/bar", "bar") != -1) e(47);	/* foo is a file */
X  if (errno != ENOTDIR) e(48);
X  if (link("foo", "foo/bar") != -1) e(49);	/* foo is not a dir */
X  if (errno != ENOTDIR) e(50);
X  if (unlink("foo/bar") != -1) e(51);	/* foo still no dir */
X  if (errno != ENOTDIR) e(52);
X  if (!superuser) {
X	if (link(".", "root") != -1) e(55);
X	if (errno != EPERM) e(56);	/* noroot can't */
X	if (unlink("root") != -1) e(57);
X	if (errno != ENOENT) e(58);
X  }
X  if (mkdir("dir", 0777) != 0) e(59);
X  if (superuser) {
X	if (rmdir("dir") != 0) e(63);
X  }
X  if (!superuser) {
X	if (unlink("dir") != -1) e(64);
X	if (errno != EPERM) e(65);	/* that ain't w'rkn */
X	if (rmdir("dir") != 0) e(66);	/* that's the way to do it */
X  }
X}
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one
X					 * too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  chdir("..");
X  system("rm -rf DIR_26");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test27.c
sed '/^X/s///' > test27.c << '/'
X/* test27: stat() fstat()	Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <stdlib.h>
X#include <errno.h>
X#include <limits.h>
X#include <string.h>
X#include <limits.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MODE_MASK	(S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID)
X#define MAX_ERROR	4
X#define ITERATIONS      2
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test27a, (void));
X_PROTOTYPE(void test27b, (void));
X_PROTOTYPE(void test27c, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int __n));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 27 ");
X  fflush(stdout);
X  System("rm -rf DIR_27; mkdir DIR_27");
X  Chdir("DIR_27");
X  superuser = (getuid() == 0);
X  makelongnames();
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test27a();
X	if (m & 0002) test27b();
X	if (m & 0004) test27c();
X  }
X  quit();
X}
X
X
Xvoid test27a()
X{				/* Test Normal operation. */
X  struct stat st1, st2;
X  time_t time1, time2;
X  int fd, pfd[2];
X
X  subtest = 1;
X
X  time(&time1);			/* get time before */
X  while (time1 >= time((time_t *)0))
X	;			/* Wait for time to change. */
X  System("echo 7bytes > foo; chmod 4750 foo");
X  if (stat("foo", &st1) != 0) e(1);	/* get foo's info */
X  time(&time2);
X  while (time2 >= time((time_t *)0))
X	;			/* Wait for next second. */
X  time(&time2);			/* get time after */
X  if ((st1.st_mode & MODE_MASK) != 04750) e(2);
X  if (st1.st_nlink != 1) e(3);	/* check stat */
X  if (st1.st_uid != geteuid()) e(4);
X  if (st1.st_gid != getegid()) e(5);
X  if (st1.st_size != (size_t) 7) e(6);
X  if (st1.st_atime <= time1) e(7);
X  if (st1.st_atime >= time2) e(8);
X  if (st1.st_ctime <= time1) e(9);
X  if (st1.st_ctime >= time2) e(10);
X  if (st1.st_mtime <= time1) e(11);
X  if (st1.st_mtime >= time2) e(12);
X
X  /* Compair stat and fstat. */
X  System("echo 7bytes > bar");
X  fd = open("bar", O_RDWR | O_APPEND);	/* the bar is open! */
X  if (fd != 3) e(13);		/* should be stderr + 1 */
X  if (stat("bar", &st1) != 0) e(14);	/* get bar's info */
X  if (fstat(fd, &st2) != 0) e(15);	/* get bar's info */
X
X  /* St1 en st2 should be the same. */
X  if (st1.st_dev != st2.st_dev) e(16);
X  if (st1.st_ino != st2.st_ino) e(17);
X  if (st1.st_mode != st2.st_mode) e(18);
X  if (st1.st_nlink != st2.st_nlink) e(19);
X  if (st1.st_uid != st2.st_uid) e(20);
X  if (st1.st_gid != st2.st_gid) e(21);
X  if (st1.st_size != st2.st_size) e(22);
X  if (st1.st_atime != st2.st_atime) e(23);
X  if (st1.st_ctime != st2.st_ctime) e(24);
X  if (st1.st_mtime != st2.st_mtime) e(25);
X  time(&time1);			/* wait a sec. */
X  while (time1 >= time((time_t *)0))
X	;
X  System("chmod 755 bar");	/* chainge mode */
X  System("rm -f foobar; ln bar foobar");	/* chainge # links */
X  if (write(fd, "foo", 4) != 4) e(26);	/* write a bit (or two) */
X  if (stat("bar", &st2) != 0) e(27);	/* get new info */
X  if (st2.st_dev != st1.st_dev) e(28);
X  if (st2.st_ino != st1.st_ino) e(29);	/* compair the fealds */
X  if ((st2.st_mode & MODE_MASK) != 0755) e(30);
X  if (!S_ISREG(st2.st_mode)) e(31);
X  if (st2.st_nlink != st1.st_nlink + 1) e(32);
X  if (st2.st_uid != st1.st_uid) e(33);
X  if (st2.st_gid != st1.st_gid) e(34);
X  if (st2.st_size != (size_t) 11) e(35);
X  if (st2.st_atime != st1.st_atime) e(36);
X  if (st2.st_ctime <= st1.st_ctime) e(37);
X  if (st2.st_mtime <= st1.st_mtime) e(38);
X  if (close(fd) != 0) e(39);	/* sorry the bar is closed */
X
X  /* Check special file. */
X  if (stat("/dev/tty", &st1) != 0) e(40);
X  if (!S_ISCHR(st1.st_mode)) e(41);
X  if (stat("/dev/ram", &st1) != 0) e(42);
X  if (!S_ISBLK(st1.st_mode)) e(43);
X
X  /* Check fifos. */
X  time(&time1);
X  while (time1 >= time((time_t *)0))
X	;
X  if (mkfifo("fifo", 0640) != 0) e(44);
X  if (stat("fifo", &st1) != 0) e(45);	/* get fifo's info */
X  time(&time2);
X  while (time2 >= time((time_t *)0))
X	;
X  time(&time2);
X  if (!S_ISFIFO(st1.st_mode)) e(46);
X  if (st1.st_nlink != 1) e(47);	/* check the stat info */
X  if (st1.st_uid != geteuid()) e(48);
X  if (st1.st_gid != getegid()) e(49);
X  if (st1.st_size != (size_t) 0) e(50);
X  if (st1.st_atime <= time1) e(51);
X  if (st1.st_atime >= time2) e(52);
X  if (st1.st_ctime <= time1) e(53);
X  if (st1.st_ctime >= time2) e(54);
X  if (st1.st_mtime <= time1) e(55);
X  if (st1.st_mtime >= time2) e(56);
X
X  /* Note: the st_mode of a fstat on a pipe should contain a isfifo bit. */
X  /* Check pipes. */
X  time(&time1);
X  while (time1 >= time((time_t *)0))
X	;
X  if (pipe(pfd) != 0) e(57);
X  if (fstat(pfd[0], &st1) != 0) e(58);	/* get pipe input info */
X  time(&time2);
X  while (time2 >= time((time_t *)0))
X	;
X  time(&time2);
X  if (!(S_ISFIFO(st1.st_mode))) e(59);	/* check stat struct */
X  if (st1.st_uid != geteuid()) e(60);
X  if (st1.st_gid != getegid()) e(61);
X  if (st1.st_size != (size_t) 0) e(62);
X  if (st1.st_atime <= time1) e(63);
X  if (st1.st_atime >= time2) e(64);
X  if (st1.st_ctime <= time1) e(65);
X  if (st1.st_ctime >= time2) e(66);
X  if (st1.st_mtime <= time1) e(67);
X  if (st1.st_mtime >= time2) e(68);
X  if (fstat(pfd[1], &st1) != 0) e(69);	/* get pipe output info */
X  if (!(S_ISFIFO(st1.st_mode))) e(70);
X  if (st1.st_uid != geteuid()) e(71);
X  if (st1.st_gid != getegid()) e(72);
X  if (st1.st_size != (size_t) 0) e(73);
X  if (st1.st_atime < time1) e(74);
X  if (st1.st_atime > time2) e(75);
X  if (st1.st_ctime < time1) e(76);
X  if (st1.st_ctime > time2) e(77);
X  if (st1.st_mtime < time1) e(78);
X  if (st1.st_mtime > time2) e(79);
X  if (close(pfd[0]) != 0) e(80);
X  if (close(pfd[1]) != 0) e(81);/* close pipe */
X
X  /* Check dirs. */
X  time(&time1);
X  while (time1 >= time((time_t *)0))
X	;
X  System("mkdir dir");
X  if (stat("dir", &st1) != 0) e(82);	/* get dir info */
X  time(&time2);
X  while (time2 >= time((time_t *)0))
X	;
X  time(&time2);
X  if (!(S_ISDIR(st1.st_mode))) e(83);	/* check stat struct */
X  if (st1.st_uid != geteuid()) e(84);
X  if (st1.st_gid != getegid()) e(85);
X  if (st1.st_atime < time1) e(86);
X  if (st1.st_atime > time2) e(87);
X  if (st1.st_ctime < time1) e(88);
X  if (st1.st_ctime > time2) e(89);
X  if (st1.st_mtime < time1) e(90);
X  if (st1.st_mtime > time2) e(91);
X  System("rm -rf ../DIR_27/*");
X}
X
Xvoid test27b()
X{				/* Test maxima. */
X  struct stat st;
X  int fd;
X
X  subtest = 2;
X
X  /* Check stats on maximum length files names. */
X  if (mkdir(MaxName, 0777) != 0) e(1);
X  if (stat(MaxName, &st) != 0) e(2);
X  if ((fd = open(MaxName, O_RDONLY)) != 3) e(3);
X  if (fstat(fd, &st) != 0) e(4);
X  if (close(fd) != 0) e(5);
X  if (rmdir(MaxName) != 0) e(6);
X  if (stat(MaxPath, &st) != 0) e(7);
X  if ((fd = open(MaxPath, O_RDONLY)) != 3) e(8);
X  if (fstat(fd, &st) != 0) e(9);
X  if (close(fd) != 0) e(10);
X  System("rm -rf ../DIR_27/*");
X}
X
Xvoid test27c()
X{				/* Test error response. */
X  struct stat st;
X  int fd, i;
X
X  subtest = 3;
X
X  System("echo Hi > foo");	/* Make a file called foo. */
X  /* Check if a un searchable dir is handled ok. */
X  Chdir("..");			/* cd .. */
X  System("chmod 677 DIR_27");	/* no search permission */
X  if (stat("DIR_27/nono", &st) != -1) e(1);
X  if (superuser) {
X	if (errno != ENOENT) e(2);	/* su has access */
X  }
X  if (!superuser) {
X	if (errno != EACCES) e(3);	/* we don't ;-) */
X  }
X  System("chmod 777 DIR_27");
X  Chdir("DIR_27");		/* back to test dir */
X
X  /* Check on ToLongName etc. */
X  if (stat(ToLongPath, &st) != -1) e(6);	/* path is too long */
X  if (errno != ENAMETOOLONG) e(7);
X
X  /* Test some common errors. */
X  if (stat("nono", &st) != -1) e(8);	/* nono nonexistent */
X  if (errno != ENOENT) e(9);
X  if (stat("", &st) != -1) e(10);	/* try empty */
X  if (errno != ENOENT) e(11);
X  if (stat("foo/bar", &st) != -1) e(12);	/* foo is a file */
X  if (errno != ENOTDIR) e(13);
X
X  /* Test fstat on file descriptors that are not open. */
X  for (i = 3; i < 6; i++) {
X	if (fstat(i, &st) != -1) e(14);
X	if (errno != EBADF) e(15);
X  }
X
X  /* Test if a just closed file is `fstat()'-able. */
X  if ((fd = open("foo", O_RDONLY)) != 3) e(16);	/* open foo */
X  if (fstat(fd, &st) != 0) e(17);	/* get stat */
X  if (close(fd) != 0) e(18);	/* close it */
X  if (fstat(fd, &st) != -1) e(19);	/* get stat */
X  if (errno != EBADF) e(20);
X  System("rm -rf ../DIR_27/*");
X}
X
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_27");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test28.c
sed '/^X/s///' > test28.c << '/'
X /* test28: mkdir() rmdir()	Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X/*
X** Not tested readonly file systems (EROFS.)
X** Not tested fs full (ENOSPC.)
X** Not really tested EBUSY.
X** Not tested unlinking busy directories.
X*/
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <string.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <fcntl.h>
X#include <errno.h>
X#include <dirent.h>
X#include <limits.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS      2
X
X#define DIRENT0		((struct dirent *) NULL)
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test28a, (void));
X_PROTOTYPE(void test28c, (void));
X_PROTOTYPE(void test28b, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int n));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 28 ");
X  fflush(stdout);
X  superuser = (getuid() == 0);
X  makelongnames();
X  system("chmod 777 DIR_28/* DIR_28/*/* > /dev/null 2>&1");
X  System("rm -rf DIR_28; mkdir DIR_28");
X  Chdir("DIR_28");
X  umask(0000);			/* no umask */
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test28a();
X	if (m & 0002) test28b();
X	if (m & 0004) test28c();
X  }
X  quit();
X}
X
X
Xvoid test28a()
X{
X  int mode;			/* used in for loop */
X  struct stat st;
X  time_t time1, time2;
X  DIR *dirp;
X  struct dirent *dep;
X  int dot = 0, dotdot = 0;
X
X  subtest = 1;
X
X  System("rm -rf foo /tmp/foo");/* clean up junk */
X
X  /* Check relative path names */
X  if (mkdir("./foo", 0777) != 0) e(1);	/* make a dir foo */
X  if (mkdir("./foo/bar", 0777) != 0) e(2);	/* make foo/bar */
X  if (rmdir("foo/bar") != 0) e(3);	/* delete bar */
X  if (mkdir("foo/../foo/bar", 0777) != 0) e(4);	/* make bar again */
X  if (rmdir("./foo/bar") != 0) e(5);	/* and remove again */
X
X  /* Foo should be empty (ie. contain only "." and ".." */
X  if ((dirp = opendir("foo")) == (DIR *) NULL) e(6);	/* open foo */
X  if ((dep = readdir(dirp)) == DIRENT0) e(7);	/* get first entry */
X  if (strcmp(dep->d_name, ".") == 0) dot += 1;	/* record what it is */
X  if (strcmp(dep->d_name, "..") == 0) dotdot += 1;
X  if ((dep = readdir(dirp)) == DIRENT0) e(8);	/* get second entry */
X  if (strcmp(dep->d_name, ".") == 0) dot += 1;	/* record again */
X  if (strcmp(dep->d_name, "..") == 0) dotdot += 1;
X  if ((dep = readdir(dirp)) != DIRENT0) e(9);	/* no 3d entry */
X  if (dot == 1 && dotdot != 1) e(10);	/* only . and .. */
X  if (closedir(dirp) != 0) e(11);	/* close foo */
X  if (rmdir("./foo") != 0) e(12);	/* remove dir foo */
X
X  /* Check absolute path names */
X  if (mkdir("/tmp/foo", 0777) != 0) e(13);
X  if (mkdir("/tmp/foo/bar", 0777) != 0) e(14);
X  if (rmdir("/tmp/foo/bar") != 0) e(15);	/* make some dirs */
X  if (rmdir("/tmp/foo") != 0) e(16);
X
X  /* Check the mode arument for mkdir() */
X  for (mode = 0; mode <= 0777; mode++) {
X	if (mkdir("foo", mode) != 0) e(17);	/* make foo */
X	if (stat("foo", &st) != 0) e(18);
X	if ((st.st_mode & 0777) != mode) e(19);	/* check it's mode */
X	if (rmdir("foo") != 0) e(20);	/* and remove it */
X  }
X
X  /* Check the stat */
X  time(&time1);
X  while (time1 >= time((time_t *)0))
X	;
X  if (mkdir("foo", 0765) != 0) e(21);	/* make foo */
X  if (stat("foo", &st) != 0) e(22);
X  time(&time2);
X  while (time2 >= time((time_t *)0))
X	;
X  time(&time2);
X  if (st.st_nlink != 2) e(23);
X  if (st.st_uid != geteuid()) e(24);
X  if (st.st_gid != getegid()) e(25);
X  if (st.st_size < 0) e(26);
X  if ((st.st_mode & 0777) != 0765) e(27);
X  if (st.st_atime <= time1) e(28);
X  if (st.st_atime >= time2) e(29);
X  if (st.st_ctime <= time1) e(30);
X  if (st.st_ctime >= time2) e(31);
X  if (st.st_mtime <= time1) e(32);
X  if (st.st_mtime >= time2) e(33);
X
X  /* Check if parent is updated */
X  if (stat(".", &st) != 0) e(34);
X  time(&time2);
X  while (time2 >= time((time_t *)0))
X	;
X  time(&time2);
X  if (st.st_ctime <= time1) e(35);
X  if (st.st_ctime >= time2) e(36);
X  if (st.st_mtime <= time1) e(37);
X  if (st.st_mtime >= time2) e(38);
X  time(&time1);
X  while (time1 >= time((time_t *)0))
X	;
X  if (rmdir("foo") != 0) e(39);
X  if (stat(".", &st) != 0) e(40);
X  time(&time2);
X  while (time2 >= time((time_t *)0))
X	;
X  time(&time2);
X  if (st.st_ctime <= time1) e(41);
X  if (st.st_ctime >= time2) e(42);
X  if (st.st_mtime <= time1) e(43);
X  if (st.st_mtime >= time2) e(44);
X}
X
X
Xvoid test28b()
X{				/* Test critical values. */
X  struct stat st;
X  DIR *dirp;
X  struct dirent *dep;
X  int fd;			/* file descriptor */
X  int other = 0, dot = 0, dotdot = 0;	/* dirent counters */
X  int rmdir_result;		/* tmp var */
X  nlink_t nlink;
X  char *bar = "foo/bar.xxx";
X  int stat_loc;
X
X  subtest = 2;
X
X  System("rm -rf ../DIR_28/*");
X
X  /* Check funny but valid path names */
X  if (mkdir("/../../..////.//../tmp/foo/", 0777) != 0) e(1);
X  if (mkdir("/tmp/foo//////..//foo//../foo/bar/", 0777) != 0) e(2);
X  if (rmdir("///tmp/..//tmp/foo/bar//../..//foo/bar") != 0) e(3);
X  if (mkdir("///tmp/foo/foobar/.", 0777) != 0) e(4);
X  if (rmdir("/tmp/foo/foobar/.") != 0) e(5);
X  if (rmdir("/.././/././/tmp/foo/././././././//") != 0) e(6);
X  if (rmdir("/tmp/foo") != -1) e(7);	/* try again */
X
X  if (LINK_MAX >= 999) e(8);	/* "xxx" long inough */
X
X  /* Test max path ed. */
X  if (mkdir(MaxName, 0777) != 0) e(9);	/* make dir MaxName */
X  if (rmdir(MaxName) != 0) e(10);	/* and remove it */
X  MaxPath[strlen(MaxPath) - 2] = '/';	/* convert MaxPath */
X  MaxPath[strlen(MaxPath) - 1] = 'a';	/* to ././.../a */
X  if (mkdir(MaxPath, 0777) != 0) e(11);	/* it should be */
X  if (rmdir(MaxPath) != 0) e(12);	/* ok */
X
X  /* Test too long path ed. */
X  if (mkdir(ToLongName, 0777) != 0) e(17);	/* Try ToLongName */
X  if (rmdir(ToLongName) != 0) e(18);	/* and remove it */
X  ToLongPath[strlen(ToLongPath) - 2] = '/';	/* make ToLongPath */
X  ToLongPath[strlen(ToLongPath) - 1] = 'a';	/* contain ././.../a */
X  if (mkdir(ToLongPath, 0777) != -1) e(19);	/* it should */
X  if (errno != ENAMETOOLONG) e(20);	/* not be ok */
X  if (rmdir(ToLongPath) != -1) e(21);
X  if (errno != ENAMETOOLONG) e(22);
X
X  /* Test what happens if the parent link count > LINK_MAX. */
X  if (mkdir("foo", 0777) != 0) e(23);	/* make foo */
X  for (nlink = 2; nlink < LINK_MAX; nlink++) {	/* make all */
X	bar[8] = (char) ((nlink / 100) % 10) + '0';
X	bar[9] = (char) ((nlink / 10) % 10) + '0';
X	bar[10] = (char) (nlink % 10) + '0';
X	if (mkdir(bar, 0777) != 0) e(24);
X  }
X  if (stat("foo", &st) != 0) e(25);	/* foo now */
X  if (st.st_nlink != LINK_MAX) e(26);	/* is full */
X  if (mkdir("foo/nono", 0777) != -1) e(27);	/* no more */
X  if (errno != EMLINK) e(28);	/* entrys. */
X  System("rm -rf foo/nono");	/* Just in case. */
X
X  /* Test if rmdir removes only empty dirs */
X  if (rmdir("foo") != -1) e(29);/* not empty */
X  if (errno != EEXIST && errno != ENOTEMPTY) e(30);
X
X  /* Test if rmdir removes a dir with an empty file (it shouldn't.) */
X  System("rm -rf foo");		/* cleanup */
X  if (mkdir("foo", 0777) != 0) e(31);
X  System("> foo/empty");	/* > empty */
X  if (rmdir("foo") != -1) e(32);/* not empty */
X  if (errno != EEXIST && errno != ENOTEMPTY) e(33);
X  if (unlink("foo/empty") != 0) e(34);	/* rm empty */
X
X  /* See what happens if foo is linked. */
X  if (superuser) {
X	if (link("foo", "footoo") != 0) e(35);	/* foo still */
X	if (rmdir("footoo") != 0) e(36);	/* exist */
X	if (chdir("footoo") != -1) e(37);	/* footoo */
X	if (errno != ENOENT) e(38);	/* is gone */
X  }
X#ifdef _MINIX
X  /* Some implementations might allow users to link directories. */
X  if (!superuser) {
X	if (link("foo", "footoo") != -1) e(39);
X	if (errno != EPERM) e(40);
X	if (unlink("foo") != -1) e(41);
X	if (errno != EPERM) e(42);
X  }
X#endif
X
X  /* See if ".." and "." are removed from the dir, and if it is
X   * unwriteable * Note, we can not remove any files in the PARENT
X   * process, because this * will make readdir unpredicatble. (see
X   * 1003.1 page 84 line 30.) However * removal of the directory is
X   * not specified in the standard.
X   */
X  System("rm -rf /tmp/sema[12].07");
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X
X      case 0:
X	alarm(20);
X	if ((fd = open("foo", O_RDONLY)) <= 2) e(43);	/* open */
X	if ((dirp = opendir("foo")) == (DIR *) NULL) e(44);	/* opendir */
X	/* UpA downB */
X	system(">/tmp/sema1.07; while test -f /tmp/sema1.07; do sleep 1;done");
X	while ((dep = readdir(dirp)) != DIRENT0) {
X		if (strcmp(dep->d_name, "..") == 0)
X			dotdot += 1;
X		else if (strcmp(dep->d_name, ".") == 0)
X			dot += 1;
X		else
X			other += 1;
X	}
X	if (dotdot != 0) e(45);	/* no entrys */
X	if (dot != 0) e(46);	/* shoul be */
X	if (other != 0) e(47);	/* left or */
X
X	/* No new files (entrys) are allowed on foo */
X	if (creat("foo/nono", 0777) != -1) e(48);	/* makeable */
X	if (closedir(dirp) != 0) e(49);	/* close foo */
X	system("while test ! -f /tmp/sema2.07; do sleep 1; done");  /* downA */
X	System("rm -f /tmp/sema2.07");	/* clean up */
X
X	/* Foo still exist, so we should be able to get a fstat */
X	if (fstat(fd, &st) != 0) e(50);
X	if (st.st_nlink != (nlink_t) 0) e(51);	/* 0 left */
X	if (close(fd) != 0) e(52);	/* last one */
X	exit(0);
X
X      default:
X	system("while test ! -f /tmp/sema1.07; do sleep 1; done");  /* downA */
X	if (rmdir("foo") != 0) e(53);	/* cleanerup */
X	System("rm -f /tmp/sema1.07");	/* upB */
X	if (chdir("foo") != -1) e(54);	/* it should */
X	if (errno != ENOENT) e(55);	/* be gone */
X	System("> /tmp/sema2.07");	/* upA */
X	if (wait(&stat_loc) == -1) e(56);
X	if (stat_loc != 0) e(57);
X  }
X
X  /* See if foo isn't accessible any more */
X  if (chdir("foo") != -1) e(58);
X  if (errno != ENOENT) e(59);
X
X  /* Let's see if we can get a EBUSSY..... */
X  if (mkdir("foo", 0777) != 0) e(60);	/* mkdir foo */
X  System("rm -f /tmp/sema.07");	/* unness */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	if (chdir("foo") != 0) e(61);	/* child goes */
X	System("> /tmp/sema.07");	/* upA */
X	system("while test -f /tmp/sema.07; do sleep 1; done");	/* downB */
X	sleep(1);
X	exit(0);
X      default:
X	system("while test ! -f /tmp/sema.07; do sleep 1; done");   /* downA */
X	rmdir_result = rmdir("foo");	/* try remove */
X	if (rmdir_result == -1) {	/* if it failed */
X		if (errno != EBUSY) e(62);	/* foo is busy */
X	} else {
X		if (rmdir_result != 0) e(63);
X		if (rmdir("foo") != -1) e(64);	/* not removable */
X		if (errno != ENOENT) e(65);	/* again. */
X		if (chdir("foo") != -1) e(66);	/* we can't go */
X		if (errno != ENOENT) e(67);	/* there any more */
X		if (mkdir("foo", 0777) != 0) e(68);	/* we can remake foo */
X	}
X	System("rm -f /tmp/sema.07");	/* upB */
X	if (wait(&stat_loc) == -1) e(69);
X	if (stat_loc != 0) e(70);
X  }
X  if (rmdir("foo") != 0) e(71);	/* clean up */
X}
X
Xvoid test28c()
X{				/* Test error handeling. */
X  subtest = 3;
X
X  System("rm -rf ../DIR_28/*");
X  System("rm -rf foo /tmp/foo");/* clean up junk */
X
X  /* Test common errors */
X  if (mkdir("foo", 0777) != 0) e(1);	/* mkdir shouldn't fail */
X  if (mkdir("foo", 0777) != -1) e(2);	/* should fail the 2d time */
X  if (errno != EEXIST) e(3);	/* because it exists already */
X  if (rmdir("foo") != 0) e(4);	/* rmdir shouldn't fail */
X  if (rmdir("foo") != -1) e(5);	/* but it should now because */
X  if (errno != ENOENT) e(6);	/* it's gone the 1st time */
X  /* Test on access etc. */
X  if (mkdir("foo", 0777) != 0) e(7);
X  if (mkdir("foo/bar", 0777) != 0) e(8);
X  if (!superuser) {
X	System("chmod 677 foo");/* make foo inaccesable */
X	if (mkdir("foo/foo", 0777) != -1) e(9);
X	if (errno != EACCES) e(10);
X	if (rmdir("foo/bar") != -1) e(11);
X	if (errno != EACCES) e(12);
X	System("chmod 577 foo");/* make foo unwritable */
X	if (mkdir("foo/foo", 0777) != -1) e(13);
X	if (errno != EACCES) e(14);
X	if (rmdir("foo/bar") != -1) e(15);
X	if (errno != EACCES) e(16);
X	System("chmod 777 foo");/* make foo full accessable */
X  }
X  if (rmdir("foo/bar") != 0) e(17);	/* bar should be removable */
X  if (mkdir("foo/no/foo", 0777) != -1) e(18);	/* Note: "no" doesn't exist */
X  if (errno != ENOENT) e(19);
X  if (mkdir("", 0777) != -1) e(20);	/* empty string isn't ok */
X  if (errno != ENOENT) e(21);
X  if (rmdir("") != -1) e(22);	/* empty string isn't ok */
X  if (errno != ENOENT) e(23);
X  System("> foo/no");		/* make a file "no" */
X  if (mkdir("foo/no/foo", 0777) != -1) e(24);
X  if (errno != ENOTDIR) e(25);	/* note: "no" is not a a dir */
X  if (rmdir("foo/no/foo") != -1) e(26);
X  if (errno != ENOTDIR) e(27);
X  System("rm -rf foo");		/* clean up */
X}
X
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_28");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test29.c
sed '/^X/s///' > test29.c << '/'
X/* test29: read(), write()	Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <time.h>
X#include <signal.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS      3
X#define BUF_SIZE 1024
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)	if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xint signumber = 0;
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test29a, (void));
X_PROTOTYPE(void test29b, (void));
X_PROTOTYPE(void test29c, (void));
X_PROTOTYPE(void setsignumber, (int _signumber));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 29 ");
X  fflush(stdout);
X  System("rm -rf DIR_29; mkdir DIR_29");
X  Chdir("DIR_29");
X  superuser = (geteuid() == 0);
X  umask(0000);
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test29a();
X	if (m & 0002) test29b();
X	if (m & 0004) test29c();
X  }
X  quit();
X}
X
Xvoid test29a()
X{				/* Try normal operation. */
X  int fd1;
X  struct stat st1, st2;
X  time_t time1;
X  char buf[BUF_SIZE];
X  int stat_loc;
X  int i, j;
X  int tube[2];
X
X  subtest = 1;
X  System("rm -rf ../DIR_29/*");
X
X  /* Let's open bar. */
X  if ((fd1 = open("bar", O_RDWR | O_CREAT, 0777)) != 3) e(1);
X  Stat("bar", &st1);
X
X  /* Writing nothing should not affect the file at all. */
X  if (write(fd1, "", 0) != 0) e(2);
X  Stat("bar", &st2);
X  if (st1.st_uid != st2.st_uid) e(3);
X  if (st1.st_gid != st2.st_gid) e(4);	/* should be same */
X  if (st1.st_mode != st2.st_mode) e(5);
X  if (st1.st_size != st2.st_size) e(6);
X  if (st1.st_nlink != st2.st_nlink) e(7);
X  if (st1.st_mtime != st2.st_mtime) e(8);
X  if (st1.st_ctime != st2.st_ctime) e(9);
X  if (st1.st_atime != st2.st_atime) e(10);
X
X  /* A write should update some status fields. */
X  time(&time1);
X  while (time1 >= time((time_t *)0))
X	;
X  if (write(fd1, "foo", 4) != 4) e(11);
X  Stat("bar", &st2);
X  if (st1.st_mode != st2.st_mode) e(12);
X  if (st1.st_size >= st2.st_size) e(13);
X  if ((off_t) 4 != st2.st_size) e(14);
X  if (st1.st_nlink != st2.st_nlink) e(15);
X  if (st1.st_mtime >= st2.st_mtime) e(16);
X  if (st1.st_ctime >= st2.st_ctime) e(17);
X  if (st1.st_atime != st2.st_atime) e(18);
X
X  /* Lseeks should not change the file status. */
X  if (lseek(fd1, (off_t) - 2, SEEK_END) != 2) e(19);
X  Stat("bar", &st1);
X  if (st1.st_mode != st2.st_mode) e(20);
X  if (st1.st_size != st2.st_size) e(21);
X  if (st1.st_nlink != st2.st_nlink) e(22);
X  if (st1.st_mtime != st2.st_mtime) e(23);
X  if (st1.st_ctime != st2.st_ctime) e(24);
X  if (st1.st_atime != st2.st_atime) e(25);
X
X  /* Writing should start at the current (2) position. */
X  if (write(fd1, "foo", 4) != 4) e(26);
X  Stat("bar", &st2);
X  if (st1.st_mode != st2.st_mode) e(27);
X  if (st1.st_size >= st2.st_size) e(28);
X  if ((off_t) 6 != st2.st_size) e(29);
X  if (st1.st_nlink != st2.st_nlink) e(30);
X  if (st1.st_mtime > st2.st_mtime) e(31);
X  if (st1.st_ctime > st2.st_ctime) e(32);
X  if (st1.st_atime != st2.st_atime) e(33);
X
X  /* A read of zero bytes should not affect anything. */
X  if (read(fd1, buf, 0) != 0) e(34);
X  Stat("bar", &st1);
X  if (st1.st_uid != st2.st_uid) e(35);
X  if (st1.st_gid != st2.st_gid) e(36);	/* should be same */
X  if (st1.st_mode != st2.st_mode) e(37);
X  if (st1.st_size != st2.st_size) e(38);
X  if (st1.st_nlink != st2.st_nlink) e(39);
X  if (st1.st_mtime != st2.st_mtime) e(40);
X  if (st1.st_ctime != st2.st_ctime) e(41);
X  if (st1.st_atime != st2.st_atime) e(42);
X
X  /* The file now should contain ``fofoo\0'' Let's check that. */
X  if (lseek(fd1, (off_t) 0, SEEK_SET) != 0) e(43);
X  if (read(fd1, buf, BUF_SIZE) != 6) e(44);
X  if (strcmp(buf, "fofoo") != 0) e(45);
X
X  /* Only the Access Time should be updated. */
X  Stat("bar", &st2);
X  if (st1.st_mtime != st2.st_mtime) e(46);
X  if (st1.st_ctime != st2.st_ctime) e(47);
X  if (st1.st_atime >= st2.st_atime) e(48);
X
X  /* A read of zero bytes should do nothing even at the end of the file. */
X  time(&time1);
X  while (time1 >= time((time_t *)0))
X	;
X  if (read(fd1, buf, 0) != 0) e(49);
X  Stat("bar", &st1);
X  if (st1.st_size != st2.st_size) e(50);
X  if (st1.st_mtime != st2.st_mtime) e(51);
X  if (st1.st_ctime != st2.st_ctime) e(52);
X  if (st1.st_atime != st2.st_atime) e(53);
X
X  /* Reading should be done from the current offset. */
X  if (read(fd1, buf, BUF_SIZE) != 0) e(54);
X  if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(55);
X  if (read(fd1, buf, BUF_SIZE) != 4) e(56);
X  if (strcmp(buf, "foo") != 0) e(57);
X
X  /* Reading should effect the current file position. */
X  if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(58);
X  if (read(fd1, buf, 1) != 1) e(59);
X  if (*buf != 'f') e(60);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 3) e(61);
X  if (read(fd1, buf, 1) != 1) e(62);
X  if (*buf != 'o') e(63);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 4) e(64);
X  if (read(fd1, buf, 1) != 1) e(65);
X  if (*buf != 'o') e(66);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 5) e(67);
X  if (read(fd1, buf, 1) != 1) e(68);
X  if (*buf != '\0') e(69);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(70);
X
X  /* Read's at EOF should return 0. */
X  if (read(fd1, buf, BUF_SIZE) != 0) e(71);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(72);
X  if (read(fd1, buf, BUF_SIZE) != 0) e(73);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(74);
X  if (read(fd1, buf, BUF_SIZE) != 0) e(75);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(76);
X  if (read(fd1, buf, BUF_SIZE) != 0) e(77);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(78);
X  if (read(fd1, buf, BUF_SIZE) != 0) e(79);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 6) e(80);
X
X  /* Writing should not always change the file size. */
X  if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(81);
X  if (write(fd1, "ba", 2) != 2) e(82);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 4) e(83);
X  Stat("bar", &st1);
X  if (st1.st_size != 6) e(84);
X
X  /* Kill the \0 at the end. */
X  if (lseek(fd1, (off_t) 5, SEEK_SET) != 5) e(85);
X  if (write(fd1, "x", 1) != 1) e(86);
X
X  /* And close the bar. */
X  if (close(fd1) != 0) e(87);
X
X  /* Try some stuff with O_APPEND. Bar contains ``fobaox'' */
X  if ((fd1 = open("bar", O_RDWR | O_APPEND)) != 3) e(88);
X
X  /* No matter what the file position is. Writes should append. */
X  if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(89);
X  if (write(fd1, "y", 1) != 1) e(90);
X  Stat("bar", &st1);
X  if (st1.st_size != (off_t) 7) e(91);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 7) e(92);
X  if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(93);
X  if (write(fd1, "z", 2) != 2) e(94);
X
X  /* The file should contain ``fobaoxyz\0'' == 9 chars long. */
X  Stat("bar", &st1);
X  if (st1.st_size != (off_t) 9) e(95);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 9) e(96);
X
X  /* Reading on a O_APPEND flag should be from the current offset. */
X  if (lseek(fd1, (off_t) 0, SEEK_SET) != 0) e(97);
X  if (read(fd1, buf, BUF_SIZE) != 9) e(98);
X  if (strcmp(buf, "fobaoxyz") != 0) e(99);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 9) e(100);
X
X  if (close(fd1) != 0) e(101);
X
X  /* Let's test fifo writes. First blocking. */
X  if (mkfifo("fifo", 0777) != 0) e(102);
X
X  /* Read from fifo but no writer. */
X  System("rm -rf /tmp/sema.29a");
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X
X      case 0:
X	alarm(20);
X	if ((fd1 = open("fifo", O_RDONLY)) != 3) e(103);
X	system("> /tmp/sema.29a");
X	system("while test -f /tmp/sema.29a; do sleep 1; done");
Xerrno =0;
X	if (read(fd1, buf, BUF_SIZE) != 0) e(104);
X	if (read(fd1, buf, BUF_SIZE) != 0) e(105);
X	if (read(fd1, buf, BUF_SIZE) != 0) e(106);
X	if (close(fd1) != 0) e(107);
X	exit(0);
X
X      default:
X	if ((fd1 = open("fifo", O_WRONLY)) != 3) e(108);
X	while (stat("/tmp/sema.29a", &st1) != 0) sleep(1);
X	if (close(fd1) != 0) e(109);
X	unlink("/tmp/sema.29a");
X	if (wait(&stat_loc) == -1) e(110);
X	if (stat_loc != 0) e(111);	/* Alarm? */
X  }
X
X  /* Read from fifo should wait for writer. */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X
X      case 0:
X	alarm(20);
X	if ((fd1 = open("fifo", O_RDONLY)) != 3) e(112);
X	if (read(fd1, buf, BUF_SIZE) != 10) e(113);
X	if (strcmp(buf, "Hi reader") != 0) e(114);
X	if (close(fd1) != 0) e(115);
X	exit(0);
X
X      default:
X	if ((fd1 = open("fifo", O_WRONLY)) != 3) e(116);
X	sleep(1);
X	if (write(fd1, "Hi reader", 10) != 10) e(117);
X	if (close(fd1) != 0) e(118);
X	if (wait(&stat_loc) == -1) e(119);
X	if (stat_loc != 0) e(120);	/* Alarm? */
X  }
X
X  /* Read from fifo should wait for all writers to close. */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X
X      case 0:
X	alarm(20);
X	switch (fork()) {
X	    case -1:	printf("Can't fork\n");	break;
X	    case 0:
X		alarm(20);
X		if ((fd1 = open("fifo", O_WRONLY)) != 3) e(121);
X		if (close(fd1) != 0) e(122);
X		exit(0);
X	    default:
X		if ((fd1 = open("fifo", O_WRONLY)) != 3) e(123);
X		sleep(1);
X		if (close(fd1) != 0) e(124);
X		if (wait(&stat_loc) == -1) e(125);
X		if (stat_loc != 0) e(126);	/* Alarm? */
X	}
X	exit(stat_loc);
X
X      default:
X	if ((fd1 = open("fifo", O_RDONLY)) != 3) e(127);
X	if (read(fd1, buf, BUF_SIZE) != 0) e(128);
X	if (close(fd1) != 0) e(129);
X	if (wait(&stat_loc) == -1) e(130);
X	if (stat_loc != 0) e(131);	/* Alarm? */
X  }
X
X  /* PIPE_BUF has to have a nice value. */
X  if (PIPE_BUF < 5) e(132);
X  if (BUF_SIZE < 1000) e(133);
X
X  /* Writes of blocks smaller than PIPE_BUF should be atomic. */
X  System("rm -rf /tmp/sema.29b;> /tmp/sema.29b");
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X
X      case 0:
X	alarm(20);
X	switch (fork()) {
X	    case -1:	printf("Can't fork\n");	break;
X
X	    case 0:
X		alarm(20);
X		if ((fd1 = open("fifo", O_WRONLY)) != 3) e(134);
X		for (i = 0; i < 100; i++) write(fd1, "1234 ", 5);
X		system("while test -f /tmp/sema.29b; do sleep 1; done");
X		if (close(fd1) != 0) e(135);
X		exit(0);
X
X	    default:
X		if ((fd1 = open("fifo", O_WRONLY)) != 3) e(136);
X		for (i = 0; i < 100; i++) write(fd1, "1234 ", 5);
X		while (stat("/tmp/sema.29b", &st1) == 0) sleep(1);
X		if (close(fd1) != 0) e(137);
X		if (wait(&stat_loc) == -1) e(138);
X		if (stat_loc != 0) e(139);	/* Alarm? */
X	}
X	exit(stat_loc);
X
X      default:
X	if ((fd1 = open("fifo", O_RDONLY)) != 3) e(140);
X	i = 0;
X	memset(buf, '\0', BUF_SIZE);
X
X	/* Read buffer full or till EOF. */
X	do {
X		j = read(fd1, buf + i, BUF_SIZE - i);
X		if (j > 0) {
X			if (j % 5 != 0) e(141);
X			i += j;
X		}
X	} while (j > 0 && i < 1000);
X
X	/* Signal the children to close write ends. This should not be */
X	/* Necessary. But due to a bug in 1.16.6 this is necessary. */
X	unlink("/tmp/sema.29b");
X	if (j < 0) e(142);
X	if (i != 1000) e(143);
X	if (wait(&stat_loc) == -1) e(144);
X	if (stat_loc != 0) e(145);	/* Alarm? */
X
X	/* Check 200 times 1234. */
X	for (i = 0; i < 200; i++)
X		if (strncmp(buf + (i * 5), "1234 ", 5) != 0) break;
X	if (i != 200) e(146);
X	if (buf[1000] != '\0') e(147);
X	if (buf[1005] != '\0') e(148);
X	if (buf[1010] != '\0') e(149);
X	if (read(fd1, buf, BUF_SIZE) != 0) e(150);
X	if (close(fd1) != 0) e(151);
X  }
X
X  /* Read from pipe should wait for writer. */
X  if (pipe(tube) != 0) e(152);
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	if (close(tube[1]) != 0) e(153);
X	if (read(tube[0], buf, BUF_SIZE) != 10) e(154);
X	if (strcmp(buf, "Hi reader") != 0) e(155);
X	if (close(tube[0]) != 0) e(156);
X	exit(0);
X      default:
X	if (close(tube[0]) != 0) e(157);
X	sleep(1);
X	if (write(tube[1], "Hi reader", 10) != 10) e(158);
X	if (close(tube[1]) != 0) e(159);
X	if (wait(&stat_loc) == -1) e(160);
X	if (stat_loc != 0) e(161);	/* Alarm? */
X  }
X
X  /* Read from pipe should wait for all writers to close. */
X  if (pipe(tube) != 0) e(162);
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	if (close(tube[0]) != 0) e(163);
X	switch (fork()) {
X	    case -1:	printf("Can't fork\n");	break;
X	    case 0:
X		alarm(20);
X		if (close(tube[1]) != 0) e(164);
X		exit(0);
X	    default:
X		sleep(1);
X		if (close(tube[1]) != 0) e(165);
X		if (wait(&stat_loc) == -1) e(166);
X		if (stat_loc != 0) e(167);	/* Alarm? */
X	}
X	exit(stat_loc);
X      default:
X	if (close(tube[1]) != 0) e(168);
X	if (read(tube[0], buf, BUF_SIZE) != 0) e(169);
X	if (close(tube[0]) != 0) e(170);
X	if (wait(&stat_loc) == -1) e(171);
X	if (stat_loc != 0) e(172);	/* Alarm? */
X  }
X
X  /* Writes of blocks smaller than PIPE_BUF should be atomic. */
X  System("rm -rf /tmp/sema.29c;> /tmp/sema.29c");
X  if (pipe(tube) != 0) e(173);
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	if (close(tube[0]) != 0) e(174);
X	switch (fork()) {
X	    case -1:	printf("Can't fork\n");	break;
X	    case 0:
X		alarm(20);
X		for (i = 0; i < 100; i++) write(tube[1], "1234 ", 5);
X		system("while test -f /tmp/sema.29c; do sleep 1; done");
X		if (close(tube[1]) != 0) e(175);
X		exit(0);
X	    default:
X		for (i = 0; i < 100; i++) write(tube[1], "1234 ", 5);
X		while (stat("/tmp/sema.29c", &st1) == 0) sleep(1);
X		if (close(tube[1]) != 0) e(176);
X		if (wait(&stat_loc) == -1) e(177);
X		if (stat_loc != 0) e(178);	/* Alarm? */
X	}
X	exit(stat_loc);
X      default:
X	i = 0;
X	if (close(tube[1]) != 0) e(179);
X	memset(buf, '\0', BUF_SIZE);
X	do {
X		j = read(tube[0], buf + i, BUF_SIZE - i);
X		if (j > 0) {
X			if (j % 5 != 0) e(180);
X			i += j;
X		} else
X			break;	/* EOF seen. */
X	} while (i < 1000);
X	unlink("/tmp/sema.29c");
X	if (j < 0) e(181);
X	if (i != 1000) e(182);
X	if (close(tube[0]) != 0) e(183);
X	if (wait(&stat_loc) == -1) e(184);
X	if (stat_loc != 0) e(185);	/* Alarm? */
X
X	/* Check 200 times 1234. */
X	for (i = 0; i < 200; i++)
X		if (strncmp(buf + (i * 5), "1234 ", 5) != 0) break;
X	if (i != 200) e(186);
X  }
X}
X
X
Xvoid test29b()
X{
X  int i, fd, stat_loc;
X  char buf[BUF_SIZE];
X  char buf2[BUF_SIZE];
X  struct stat st;
X
X  subtest = 2;
X  System("rm -rf ../DIR_29/*");
X
X  /* Lets try sequential writes. */
X  system("rm -rf /tmp/sema.29d");
X  System("> testing");
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(1);
X	if (write(fd, "one ", 4) != 4) e(2);
X	if (close(fd) != 0) e(3);
X	system("> /tmp/sema.29d");
X	system("while test -f /tmp/sema.29d; do sleep 1; done");
X	if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(4);
X	if (write(fd, "three ", 6) != 6) e(5);
X	if (close(fd) != 0) e(6);
X	system("> /tmp/sema.29d");
X	exit(0);
X      default:
X	while (stat("/tmp/sema.29d", &st) != 0) sleep(1);
X	if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(7);
X	if (write(fd, "two ", 4) != 4) e(8);
X	if (close(fd) != 0) e(9);
X	unlink("/tmp/sema.29d");
X	while (stat("/tmp/sema.29d", &st) != 0) sleep(1);
X	if ((fd = open("testing", O_WRONLY | O_APPEND)) != 3) e(10);
X	if (write(fd, "four", 5) != 5) e(11);
X	if (close(fd) != 0) e(12);
X	if (wait(&stat_loc) == -1) e(13);
X	if (stat_loc != 0) e(14);	/* The alarm went off? */
X	unlink("/tmp/sema.29d");
X  }
X  if ((fd = open("testing", O_RDONLY)) != 3) e(15);
X  if (read(fd, buf, BUF_SIZE) != 19) e(16);
X  if (strcmp(buf, "one two three four") != 0) e(17);
X  if (close(fd) != 0) e(18);
X
X
X  /* Non written bytes in regular files should be zero. */
X  memset(buf2, '\0', BUF_SIZE);
X  if ((fd = open("bigfile", O_RDWR | O_CREAT, 0644)) != 3) e(19);
X  if (lseek(fd, (off_t) 102400, SEEK_SET) != (off_t) 102400L) e(20);
X  if (read(fd, buf, BUF_SIZE) != 0) e(21);
X  if (write(fd, ".", 1) != 1) e(22);
X  Stat("bigfile", &st);
X  if (st.st_size != (off_t) 102401) e(23);
X  if (lseek(fd, (off_t) 0, SEEK_SET) != 0) e(24);
X  for (i = 0; i < 102400 / BUF_SIZE; i++) {
X	if (read(fd, buf, BUF_SIZE) != BUF_SIZE) e(25);
X	if (memcmp(buf, buf2, BUF_SIZE) != 0) e(26);
X  }
X  if (close(fd) != 0) e(27);
X}
X
Xvoid test29c()
X{				/* Test correct error behavior. */
X  char buf[BUF_SIZE];
X  int fd, tube[2], stat_loc;
X  struct stat st;
X  pid_t pid;
X#ifdef SIGACTION
X  struct sigaction act, oact;
X#else
X#if _ANSI
X  void (*oldfunc) (int);
X#else
X  void (*oldfunc) ();
X#endif
X#endif
X
X  subtest = 3;
X  System("rm -rf ../DIR_29/*");
X
X  /* To test if writing processes on closed pipes are signumbered. */
X#ifdef SIGACTION
X  act.sa_handler = setsignumber;
X  sigemptyset(&act.sa_mask);
X  act.sa_flags = 0;
X  if (sigaction(SIGPIPE, &act, &oact) != 0) e(1);
X#else
X  oldfunc = signal(SIGPIPE, setsignumber);
X#endif
X
X  /* Non valid file descriptors should be an error. */
X  for (fd = -111; fd < 0; fd++) {
X	errno = 0;
X	if (read(fd, buf, BUF_SIZE) != -1) e(2);
X	if (errno != EBADF) e(3);
X  }
X  for (fd = 3; fd < 111; fd++) {
X	errno = 0;
X	if (read(fd, buf, BUF_SIZE) != -1) e(4);
X	if (errno != EBADF) e(5);
X  }
X  for (fd = -111; fd < 0; fd++) {
X	errno = 0;
X	if (write(fd, buf, BUF_SIZE) != -1) e(6);
X	if (errno != EBADF) e(7);
X  }
X  for (fd = 3; fd < 111; fd++) {
X	errno = 0;
X	if (write(fd, buf, BUF_SIZE) != -1) e(8);
X	if (errno != EBADF) e(9);
X  }
X
X  /* Writing a pipe with no readers should trigger SIGPIPE. */
X  if (pipe(tube) != 0) e(10);
X  close(tube[0]);
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	signumber = 0;
X	if (write(tube[1], buf, BUF_SIZE) != -1) e(11);
X	if (errno != EPIPE) e(12);
X	if (signumber != SIGPIPE) e(13);
X	if (close(tube[1]) != 0) e(14);
X	exit(0);
X      default:
X	close(tube[1]);
X	if (wait(&stat_loc) == -1) e(15);
X	if (stat_loc != 0) e(16);	/* Alarm? */
X  }
X
X  /* Writing a fifo with no readers should trigger SIGPIPE. */
X  System("> /tmp/sema.29e");
X  if (mkfifo("fifo", 0666) != 0) e(17);
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	if ((fd = open("fifo", O_WRONLY)) != 3) e(18);
X	system("while test -f /tmp/sema.29e; do sleep 1; done");
X	signumber = 0;
X	if (write(fd, buf, BUF_SIZE) != -1) e(19);
X	if (errno != EPIPE) e(20);
X	if (signumber != SIGPIPE) e(21);
X	if (close(fd) != 0) e(22);
X	exit(0);
X      default:
X	if ((fd = open("fifo", O_RDONLY)) != 3) e(23);
X	if (close(fd) != 0) e(24);
X	unlink("/tmp/sema.29e");
X	if (wait(&stat_loc) == -1) e(25);
X	if (stat_loc != 0) e(26);	/* Alarm? */
X  }
X
X#ifdef SIGACTION
X  /* Restore normal (re)action to SIGPIPE. */
X  if (sigaction(SIGPIPE, &oact, NULL) != 0) e(27);
X#else
X  signal(SIGPIPE, oldfunc);
X#endif
X
X  /* Read from fifo should return -1 and set errno to EAGAIN. */
X  System("rm -rf /tmp/sema.29[fgh]");
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	system("while test ! -f /tmp/sema.29f; do sleep 1; done");
X	System("rm -rf /tmp/sema.29f");
X	if ((fd = open("fifo", O_WRONLY | O_NONBLOCK)) != 3) e(28);
X	close(creat("/tmp/sema.29g", 0666));
X	system("while test ! -f /tmp/sema.29h; do sleep 1; done");
X	if (close(fd) != 0) e(29);
X	System("rm -rf /tmp/sema.29h");
X	exit(0);
X      default:
X	if ((fd = open("fifo", O_RDONLY | O_NONBLOCK)) != 3) e(30);
X	close(creat("/tmp/sema.29f", 0666));
X	system("while test ! -f /tmp/sema.29g; do sleep 1; done");
X	System("rm -rf /tmp/sema.29g");
X	if (read(fd, buf, BUF_SIZE) != -1) e(31);
X	if (errno != EAGAIN) e(32);
X	if (read(fd, buf, BUF_SIZE) != -1) e(33);
X	if (errno != EAGAIN) e(34);
X	if (read(fd, buf, BUF_SIZE) != -1) e(35);
X	if (errno != EAGAIN) e(36);
X	close(creat("/tmp/sema.29h", 0666));
X	while (stat("/tmp/sema.29h", &st) == 0) sleep(1);
X	if (read(fd, buf, BUF_SIZE) != 0) e(37);
X	if (close(fd) != 0) e(38);
X	if (wait(&stat_loc) == -1) e(39);
X	if (stat_loc != 0) e(40);	/* Alarm? */
X  }
X  System("rm -rf fifo");
X
X  /* If a read is interrupted by a SIGNAL. */
X  if (pipe(tube) != 0) e(41);
X  switch (pid = fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X#ifdef SIGACTION
X	act.sa_handler = setsignumber;
X	sigemptyset(&act.sa_mask);
X	act.sa_flags = 0;
X	if (sigaction(SIGUSR1, &act, &oact) != 0) e(42);
X#else
X	oldfunc = signal(SIGUSR1, setsignumber);
X#endif
X	if (read(tube[0], buf, BUF_SIZE) != -1) e(43);
X	if (errno != EINTR) e(44);
X	if (signumber != SIGUSR1) e(45);
X#ifdef SIGACTION
X	/* Restore normal (re)action to SIGPIPE. */
X	if (sigaction(SIGUSR1, &oact, NULL) != 0) e(46);
X#else
X	signal(SIGUSR1, oldfunc);
X#endif
X	close(tube[0]);
X	close(tube[1]);
X	exit(0);
X      default:
X	/* The sleep 1 should give the child time to start the read. */
X	sleep(1);
X	close(tube[0]);
X	kill(pid, SIGUSR1);
X	wait(&stat_loc);
X	if (stat_loc != 0) e(47);	/* Alarm? */
X	close(tube[1]);
X  }
X}
X
X
Xvoid setsignumber(signum)
Xint signum;
X{
X  signumber = signum;
X}
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_29");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test30.c
sed '/^X/s///' > test30.c << '/'
X/* test30: creat() 		(p) Jan-Mark Wams. email: jms@cs.vu.nl */
X
X/*
X** Creat() should be equivalent to:
X**	open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
X** Since we can not look in the source, we can not assume creat() is
X** a mere sysnonym (= a systemcall synonym).
X*/
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS     10
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)	if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test30a, (void));
X_PROTOTYPE(void test30b, (void));
X_PROTOTYPE(void test30c, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (geteuid() == 0 || getuid() == 0) {
X	printf("Test 30 cannot run as root; test aborted\n");
X	exit(1);
X  }
X
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 30 ");
X  fflush(stdout);
X  System("rm -rf DIR_30; mkdir DIR_30");
X  Chdir("DIR_30");
X  makelongnames();
X  superuser = (geteuid() == 0);
X
X  umask(0000);
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test30a();
X	if (m & 0002) test30b();
X	if (m & 0004) test30c();
X  }
X  quit();
X}
X
X
Xvoid test30a()
X{				/* Test normal operation. */
X
X#define BUF_SIZE 1024
X
X  int fd1, fd2;
X  char buf[BUF_SIZE];
X  struct stat st, dirst;
X  time_t time1, time2;
X  int stat_loc, cnt;
X
X  subtest = 1;
X
X  System("/bin/rm -rf ../DIR_30/*");
X
X  /* Check if processes have independent new fds */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	if ((fd1 = creat("myfile", 0644)) != 3) e(1);
X	if (close(fd1) != 0) e(2);
X	exit(0);
X      default:
X	if ((fd1 = creat("myfile", 0644)) != 3) e(3);
X	if (close(fd1) != 0) e(4);
X	if (wait(&stat_loc) == -1) e(5);
X	if (stat_loc != 0) e(6);
X  }
X
X  /* Save the dir status. */
X  Stat(".", &dirst);
X  time(&time1);
X  while (time1 == time((time_t *)0))
X	;
X
X  /* Check if the file status information is updated correctly */
X  cnt = 0;
X  System("rm -rf myfile");
X  do {
X	time(&time1);
X	if ((fd1 = creat("myfile", 0644)) != 3) e(7);
X	Stat("myfile", &st);
X	time(&time2);
X  } while (time1 != time2 && cnt++ < 100);
X  if (cnt >= 100) e(8);
X  if (st.st_uid != geteuid()) e(9);	/* Uid should be set. */
X  if (st.st_gid != getegid()) e(10);
X  if (!S_ISREG(st.st_mode)) e(11);
X  if (st.st_mode & 0777 != 0644) e(12);
X  if (st.st_nlink != 1) e(13);
X  if (st.st_ctime != time1) e(14);	/* All time fields should be updated */
X  if (st.st_atime != time1) e(15);
X  if (st.st_mtime != time1) e(16);
X  if (st.st_size != 0) e(17);	/* File should be trunked. */
X
X  /* Check if c and mtime for "." is updated. */
X  Stat(".", &st);
X  if (st.st_ctime <= dirst.st_ctime) e(18);
X  if (st.st_mtime <= dirst.st_mtime) e(19);
X
X  /* Let's see if cread fds are write only. */
X  if (read(fd1, buf, 7) != -1) e(20);	/* we can't read */
X  if (errno != EBADF) e(21);	/* a write only fd */
X  if (write(fd1, "HELLO", 6) != 6) e(22);	/* but we can write */
X
X  /* No O_APPEND flag should have been used. */
X  if (lseek(fd1, (off_t) 1, SEEK_SET) != 1) e(23);
X  if (write(fd1, "ello", 5) != 5) e(24);
X  Stat("myfile", &st);
X  if (st.st_size != 6) e(25);
X  if (st.st_size == 11) e(26);	/* O_APPEND should make it 11. */
X  if (close(fd1) != 0) e(27);
X
X  /* A creat should set the file offset to 0. */
X  if ((fd1 = creat("myfile", 0644)) != 3) e(28);
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 0) e(29);
X  if (close(fd1) != 0) e(30);
X
X  /* Test if file permission bits and the file ownership are unchanged. */
X  /* So we will see if creat() is just an open() if the file exists. */
X  if (superuser) {
X	System("echo > bar; chmod 073 bar");	/* Make bar 073 */
X	System("chown daemon bar");
X	System("chgrp daemon bar");	/* Daemon's bar */
X	fd1 = creat("bar", 0777);	/* knock knock */
X	if (fd1 == -1) e(31);
X	Stat("bar", &st);
X	if (st.st_size != (size_t) 0) e(32);	/* empty file. */
X	if (write(fd1, "foo", 3) != 3) e(33);	/* rewrite bar */
X	if (close(fd1) != 0) e(34);
X	Stat("bar", &st);
X	if (st.st_uid != 1) e(35);	/* bar is still */
X	if (st.st_gid != 1) e(36);	/* owned by daemon */
X	if ((st.st_mode & 0777) != 073) e(37);	/* mode still is 077 */
X	if (st.st_size != (size_t) 3) e(38);
X  }
X
X  /* Fifo's should be openable with creat(). */
X  if (mkfifo("fifo", 0644) != 0) e(39);
X
X  /* Creat() should have no effect on FIFO files. */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);		/* Give child 20 seconds to live. */
X	if ((fd1 = open("fifo", O_WRONLY)) != 3) e(40);
X	if (write(fd1, "I did see Elvis.\n", 18) != 18) e(41);
X	if ((fd2 = creat("fifo", 0644)) != 4) e(42);
X	if (write(fd2, "I DID.\n", 8) != 8) e(43);
X	if (close(fd2) != 0) e(44);
X	if (close(fd1) != 0) e(45);
X	exit(0);
X      default:
X	if ((fd1 = open("fifo", O_RDONLY)) != 3) e(46);
X	if (read(fd1, buf, 18) != 18) e(47);
X	if (strcmp(buf, "I did see Elvis.\n") != 0) e(48);
X	if (strcmp(buf, "I DID.\n") == 0) e(49);
X	if (read(fd1, buf, BUF_SIZE) != 8) e(50);
X	if (strcmp(buf, "I DID.\n") != 0) e(51);
X	if (close(fd1) != 0) e(52);
X	if (wait(&stat_loc) == -1) e(53);
X	if (stat_loc != 0) e(54);	/* The alarm went off? */
X  }
X
X  /* Creat() should have no effect on directroys. */
X  System("mkdir dir; touch dir/f1 dir/f2 dir/f3");
X  if ((fd1 = creat("dir", 0644)) != -1) e(55);
X  if (errno != EISDIR) e(56);
X  close(fd1);
X
X  /* The path should contain only dirs in the prefix. */
X  if ((fd1 = creat("dir/f1/nono", 0644)) != -1) e(57);
X  if (errno != ENOTDIR) e(58);
X  close(fd1);
X
X  /* The path should contain only dirs in the prefix. */
X  if ((fd1 = creat("", 0644)) != -1) e(59);
X  if (errno != ENOENT) e(60);
X  close(fd1);
X  if ((fd1 = creat("dir/noso/nono", 0644)) != -1) e(61);
X  if (errno != ENOENT) e(62);
X  close(fd1);
X
X}
X
Xvoid test30b()
X{
X  int fd;
X
X  subtest = 2;
X
X  System("/bin/rm -rf ../DIR_30/*");
X
X  /* Test maximal file name length. */
X  if ((fd = creat(MaxName, 0777)) != 3) e(1);
X  if (close(fd) != 0) e(2);
X  MaxPath[strlen(MaxPath) - 2] = '/';
X  MaxPath[strlen(MaxPath) - 1] = 'a';	/* make ././.../a */
X  if ((fd = creat(MaxPath, 0777)) != 3) e(3);
X  if (close(fd) != 0) e(4);
X  MaxPath[strlen(MaxPath) - 1] = '/';	/* make ././.../a */
X}
X
X
Xvoid test30c()
X{
X  int fd;
X
X  subtest = 3;
X
X  System("/bin/rm -rf ../DIR_30/*");
X
X  if (!superuser) {
X	/* Test if creat is not usable to open files with the wrong mode */
X	System("> nono; chmod 177 nono");
X	fd = creat("nono", 0777);
X	if (fd != -1) e(1);
X	if (errno != EACCES) e(2);
X  }
X  if (mkdir("bar", 0777) != 0) e(3);	/* make bar */
X
X  /* Check if no access on part of path generates the correct error. */
X  System("chmod 577 bar");	/* r-xrwxrwx */
X  if (!superuser) {
X	/* Normal users can't creat without write permision. */
X	if (creat("bar/nono", 0666) != -1) e(4);
X	if (errno != EACCES) e(5);
X	if (creat("bar/../nono", 0666) != -1) e(6);
X	if (errno != EACCES) e(7);
X  }
X  if (superuser) {
X	/* Super user can still creat stuff. */
X	if ((fd = creat("bar/nono", 0666)) != 3) e(8);
X	if (close(fd) != 0) e(9);
X	if (unlink("bar/nono") != 0) e(10);
X  }
X
X  /* Clean up bar. */
X  System("/bin/rm -rf bar");
X
X  /* Test ToLongName and ToLongPath */
X  if ((fd = creat(ToLongName, 0777)) != 3) e(13);
X  if (close(fd) != 0) e(14);
X  ToLongPath[PATH_MAX - 2] = '/';
X  ToLongPath[PATH_MAX - 1] = 'a';
X  if ((fd = creat(ToLongPath, 0777)) != -1) e(15);
X  if (errno != ENAMETOOLONG) e(16);
X  if (close(fd) != -1) e(17);
X  ToLongPath[PATH_MAX - 1] = '/';
X}
X
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_30");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test31.c
sed '/^X/s///' > test31.c << '/'
X/* test31: mkfifo()		Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS     10
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)	if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test31a, (void));
X_PROTOTYPE(void test31b, (void));
X_PROTOTYPE(void test31c, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 31 ");
X  fflush(stdout);
X  System("rm -rf DIR_31; mkdir DIR_31");
X  Chdir("DIR_31");
X  makelongnames();
X  superuser = (geteuid() == 0);
X
X  umask(0000);
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test31a();
X	if (m & 0002) test31b();
X	if (m & 0004) test31c();
X  }
X  quit();
X}
X
X
Xvoid test31a()
X{				/* Test normal operation. */
X
X#define BUF_SIZE 1024
X
X  int fd;
X  char buf[BUF_SIZE];
X  struct stat st, dirst;
X  time_t time1, time2;
X  int stat_loc, cnt;
X
X  subtest = 1;
X
X  System("/bin/rm -rf ../DIR_31/*");
X
X  /* Check if the file status information is updated correctly */
X  System("rm -rf fifo");
X  cnt = 0;
X  Stat(".", &dirst);
X  time(&time1);
X  while (time1 == time((time_t *)0))
X	;
X
X  do {
X	time(&time1);
X	if (mkfifo("fifo", 0644) != 0) e(1);
X	Stat("fifo", &st);
X	time(&time2);
X  } while (time1 != time2 && cnt++ < 100);
X
X  if (cnt >= 100) e(2);
X  if (st.st_uid != geteuid()) e(3);	/* Uid should be set. */
X  if (st.st_gid != getegid()) e(4);
X  if (!S_ISFIFO(st.st_mode)) e(5);
X  if (st.st_mode & 0777 != 0644) e(6);
X  if (st.st_nlink != 1) e(7);
X  if (st.st_ctime != time1) e(8);
X  if (st.st_atime != time1) e(9);
X  if (st.st_mtime != time1) e(10);
X  if (st.st_size != 0) e(11);	/* File should be empty. */
X
X  /* Check if status for "." is updated. */
X  Stat(".", &st);
X  if (st.st_ctime <= dirst.st_ctime) e(12);
X  if (st.st_mtime <= dirst.st_mtime) e(13);
X
X  /* Basic checking if a fifo file created with mkfifo() is a pipe. */
X  alarm(10);		/* in case fifo hangs */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	if ((fd = open("fifo", O_RDONLY)) != 3) e(14);
X	if (read(fd, buf, BUF_SIZE) != 7) e(15);
X	if (strcmp(buf, "banana") != 0) e(16);
X	if (close(fd) != 0) e(17);
X	if ((fd = open("fifo", O_WRONLY)) != 3) e(18);
X	if (write(fd, "thanks", 7) != 7) e(19);
X	if (close(fd) != 0) e(20);
X	exit(0);
X
X      default:
X	if ((fd = open("fifo", O_WRONLY)) != 3) e(21);
X	if (write(fd, "banana", 7) != 7) e(22);
X	if (close(fd) != 0) e(23);
X	if ((fd = open("fifo", O_RDONLY)) != 3) e(24);
X	if (read(fd, buf, BUF_SIZE) != 7) e(25);
X	if (strcmp(buf, "thanks") != 0) e(26);
X	if (close(fd) != 0) e(27);
X	wait(&stat_loc);
X	if (stat_loc != 0) e(28);	/* Alarm? */
X  }
X  alarm(0);
X}
X
Xvoid test31b()
X{
X  subtest = 2;
X
X  System("/bin/rm -rf ../DIR_31/*");
X
X  /* Test maximal file name length. */
X  if (mkfifo(MaxName, 0777) != 0) e(1);
X  if (unlink(MaxName) != 0) e(2);
X  MaxPath[strlen(MaxPath) - 2] = '/';
X  MaxPath[strlen(MaxPath) - 1] = 'a';	/* make ././.../a */
X  if (mkfifo(MaxPath, 0777) != 0) e(3);
X  if (unlink(MaxPath) != 0) e(4);
X  MaxPath[strlen(MaxPath) - 1] = '/';	/* make ././.../a */
X}
X
X
Xvoid test31c()
X{
X  subtest = 3;
X
X  System("/bin/rm -rf ../DIR_31/*");
X
X  /* Check if mkfifo() removes, files, fifos, dirs. */
X  if (mkfifo("fifo", 0777) != 0) e(1);
X  System("mkdir dir; > file");
X  if (mkfifo("fifo", 0777) != -1) e(2);
X  if (errno != EEXIST) e(3);
X  if (mkfifo("dir", 0777) != -1) e(4);
X  if (errno != EEXIST) e(5);
X  if (mkfifo("file", 0777) != -1) e(6);
X  if (errno != EEXIST) e(7);
X
X  /* Test empty path. */
X  if (mkfifo("", 0777) != -1) e(8);
X  if (errno != ENOENT) e(9);
X  if (mkfifo("/tmp/noway/out", 0777) != -1) e(10);
X  if (errno != ENOENT) e(11);
X
X  /* Test if path prefix is a directory. */
X  if (mkfifo("/etc/passwd/nono", 0777) != -1) e(12);
X  if (errno != ENOTDIR) e(13);
X
X  mkdir("bar", 0777);		/* make bar */
X
X  /* Check if no access on part of path generates the correct error. */
X  System("chmod 577 bar");	/* r-xrwxrwx */
X  if (!superuser) {
X	if (mkfifo("bar/nono", 0666) != -1) e(14);
X	if (errno != EACCES) e(15);
X  }
X  if (superuser) {
X	if (mkfifo("bar/nono", 0666) != 0) e(14);
X	if (unlink("bar/nono") != 0) e(666);
X  }
X  System("chmod 677 bar");	/* rw-rwxrwx */
X  if (!superuser) {
X	if (mkfifo("bar/../nono", 0666) != -1) e(16);
X	if (errno != EACCES) e(17);
X  }
X  if (unlink("nono") != -1) e(18);
X
X  /* Clean up bar. */
X  System("/bin/rm -rf bar");
X
X  /* Test ToLongName and ToLongPath */
X  if (mkfifo(ToLongName, 0777) != 0) e(21);
X  ToLongPath[PATH_MAX - 2] = '/';
X  ToLongPath[PATH_MAX - 1] = 'a';
X  if (mkfifo(ToLongPath, 0777) != -1) e(22);
X  if (errno != ENAMETOOLONG) e(23);
X  ToLongPath[PATH_MAX - 1] = '/';
X}
X
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_31");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test32.c
sed '/^X/s///' > test32.c << '/'
X/* test32: rename()		Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS      2
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)	if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X#define Creat(f)	if (close(creat(f,0777))!=0) printf("Can't creat %s\n",f)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test32a, (void));
X_PROTOTYPE(void test32b, (void));
X_PROTOTYPE(void test32c, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 32 ");
X  fflush(stdout);
X  System("rm -rf DIR_32; mkdir DIR_32");
X  Chdir("DIR_32");
X  makelongnames();
X  superuser = (geteuid() == 0);
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test32a();
X	if (m & 0002) test32b();
X	if (m & 0004) test32c();
X  }
X  quit();
X}
X
X#define BUF_SIZE 1024
X
Xvoid test32a()
X{				/* Test normal operation. */
X  struct stat st1, st2;
X  int fd1, fd2;
X  time_t time1, time2, time3;
X  char buf[BUF_SIZE];
X
X  subtest = 1;
X  System("/bin/rm -rf ../DIR_32/*");
X
X  /* Test normal file renamal. */
X  System("echo haha > old");
X  Stat("old", &st1);
X  if (rename("old", "new") != 0) e(1);
X  Stat("new", &st2);
X
X  /* The status of new should be the same as old. */
X  if (st1.st_dev != st2.st_dev) e(2);
X  if (st1.st_ino != st2.st_ino) e(3);
X  if (st1.st_mode != st2.st_mode) e(4);
X  if (st1.st_nlink != st2.st_nlink) e(5);
X  if (st1.st_uid != st2.st_uid) e(6);
X  if (st1.st_gid != st2.st_gid) e(7);
X  if (st1.st_rdev != st2.st_rdev) e(8);
X  if (st1.st_size != st2.st_size) e(9);
X  if (st1.st_atime != st2.st_atime) e(10);
X  if (st1.st_mtime != st2.st_mtime) e(11);
X  if (st1.st_ctime != st2.st_ctime) e(12);
X
X  /* If new exists, it should be removed. */
X  System("ln new new2");
X  System("echo foobar > old");
X  Stat("old", &st1);
X  if (rename("old", "new") != 0) e(13);
X  Stat("new", &st2);
X
X  /* The status of new should be the same as old. */
X  if (st1.st_dev != st2.st_dev) e(14);
X  if (st1.st_ino != st2.st_ino) e(15);
X  if (st1.st_mode != st2.st_mode) e(16);
X  if (st1.st_nlink != st2.st_nlink) e(17);
X  if (st1.st_uid != st2.st_uid) e(18);
X  if (st1.st_gid != st2.st_gid) e(19);
X  if (st1.st_rdev != st2.st_rdev) e(20);
X  if (st1.st_size != st2.st_size) e(21);
X  if (st1.st_atime != st2.st_atime) e(22);
X  if (st1.st_mtime != st2.st_mtime) e(23);
X  if (st1.st_ctime != st2.st_ctime) e(24);
X
X  /* The link count on new2 should be one since the old new is removed. */
X  Stat("new2", &st1);
X  if (st1.st_nlink != 1) e(25);
X
X  /* Check if status for "." is updated. */
X  System("> OLD");
X  Stat(".", &st1);
X  time(&time1);
X  while (time1 == time((time_t *)0))
X	;
X  time(&time2);
X  rename("OLD", "NEW");
X  Stat(".", &st2);
X  time(&time3);
X  while (time3 == time((time_t *)0))
X	;
X  time(&time3);
X  if (st1.st_ctime >= st2.st_ctime) e(26);
X  if (st1.st_mtime >= st2.st_mtime) e(27);
X  if (st1.st_ctime > time1) e(28);
X  if (st1.st_mtime > time1) e(29);
X  if (st1.st_ctime >= time2) e(30);
X  if (st1.st_mtime >= time2) e(31);
X  if (st2.st_ctime < time2) e(32);
X  if (st2.st_mtime < time2) e(33);
X  if (st2.st_ctime >= time3) e(34);
X  if (st2.st_mtime >= time3) e(35);
X
X  /* If the new file is removed while it's open it should still be
X   * readable. */
X  System("rm -rf new NEW old OLD");
X  if ((fd1 = creat("new", 0644)) != 3) e(36);
X  if (write(fd1, "Hi there! I am Sammy the string", 33) != 33) e(37);
X  if (close(fd1) != 0) e(38);
X  if ((fd1 = creat("old", 0644)) != 3) e(39);
X  if (write(fd1, "I need a new name", 18) != 18) e(40);
X  if (close(fd1) != 0) e(41);
X  if ((fd1 = open("new", O_RDONLY)) != 3) e(42);
X  if ((fd2 = open("new", O_RDONLY)) != 4) e(43);
X  if (rename("old", "new") != 0) e(44);
X  if (stat("old", &st1) == 0) e(45);
X  if (close(fd1) != 0) e(46);
X  if ((fd1 = open("new", O_RDONLY)) != 3) e(47);
X  if (read(fd2, buf, BUF_SIZE) != 33) e(48);
X  if (strcmp(buf, "Hi there! I am Sammy the string") != 0) e(49);
X  if (read(fd1, buf, BUF_SIZE) != 18) e(50);
X  if (strcmp(buf, "I need a new name") != 0) e(51);
X  if (close(fd1) != 0) e(52);
X  if (close(fd2) != 0) e(53);
X}
X
Xvoid test32b()
X{
X  char MaxPath2[PATH_MAX];	/* Same for path */
X  char MaxName2[NAME_MAX + 1];	/* Name of maximum length */
X  int fd, i;
X  int stat_loc;
X  struct stat st;
X
X  subtest = 2;
X  System("/bin/rm -rf ../DIR_32/*");
X
X  /* Test maximal file name length. */
X  if ((fd = creat(MaxName, 0777)) != 3) e(1);
X  if (close(fd) != 0) e(2);
X  strcpy(MaxName2, MaxName);
X  MaxName2[strlen(MaxName2) - 1] ^= 1;
X  if (rename(MaxName, MaxName2) != 0) e(3);
X  if (rename(MaxName2, MaxName) != 0) e(4);
X  MaxName2[strlen(MaxName2) - 1] ^= 2;
X  if (rename(MaxName, MaxName2) != 0) e(5);
X  MaxPath[strlen(MaxPath) - 2] = '/';
X  MaxPath[strlen(MaxPath) - 1] = 'a';	/* make ././.../a */
X  if ((fd = creat(MaxPath, 0777)) != 3) e(6);
X  if (close(fd) != 0) e(7);
X  strcpy(MaxPath2, MaxPath);
X  MaxPath2[strlen(MaxPath2) - 1] ^= 1;
X  if (rename(MaxPath, MaxPath2) != 0) e(8);
X  if (rename(MaxPath2, MaxPath) != 0) e(9);
X  MaxPath2[strlen(MaxPath2) - 1] ^= 2;
X  if (rename(MaxPath, MaxPath2) != 0) e(10);
X  MaxPath[strlen(MaxPath) - 1] = '/';	/* make ././.../a */
X
X  /* Test if linked files are renamable. */
X  System("> foo; ln foo bar");
X  if (rename("foo", "bar") != 0) e(11);
X  if (rename("bar", "foo") != 0) e(12);
X  System("ln foo foobar");
X  if (rename("foo", "foobar") != 0) e(13);
X  if (rename("bar", "foobar") != 0) e(14);
X
X  /* Since the same files have the same links.... */
X  if (rename("bar", "bar") != 0) e(15);
X  if (rename("foo", "foo") != 0) e(16);
X  if (rename("foobar", "foobar") != 0) e(17);
X
X  /* In ``rename(old, new)'' with new existing, there is always an new
X   * entry. */
X  for (i = 0; i < 5; i++) {
X	System("echo old > old");
X	System("echo news > new");
X	switch (fork()) {
X	    case -1:	printf("Can't fork\n");	break;
X	    case 0:
X		alarm(20);
X		sleep(1);
X		rename("old", "new");
X		exit(0);
X	    default:
X		while (stat("old", &st) != 0)
X			if (stat("new", &st) != 0) e(18);
X		wait(&stat_loc);
X		if (stat_loc != 0) e(19);	/* Alarm? */
X	}
X  }
X
X}
X
Xvoid test32c()
X{				/* Test behavior under error contitions. */
X  struct stat st1;
X  int stat_loc;
X
X  subtest = 3;
X  System("/bin/rm -rf ../DIR_32/*");
X
X  /* Test if we have access. */
X  system("chmod 777 noacc nowrite > /dev/null 2>/dev/null");
X  system("rm -rf noacc nowrite");
X
X  System("mkdir noacc nowrite");
X  System("> noacc/file");
X  System("> nowrite/file");
X  System("> file");
X  System("chmod 677 noacc");
X  System("chmod 577 nowrite");
X  if (!superuser) {
X	if (rename("noacc/file", "nono") != -1) e(1);
X	if (errno != EACCES) e(2);
X	if (rename("nowrite/file", "nono") != -1) e(3);
X	if (errno != EACCES) e(4);
X	if (rename("file", "noacc/file") != -1) e(5);
X	if (errno != EACCES) e(6);
X	if (rename("file", "nowrite/file") != -1) e(7);
X	if (errno != EACCES) e(8);
X  }
X  if (superuser) {
X	/* Super user heeft access. */
X	if (rename("noacc/file", "noacc/yes") != 0) e(9);
X	if (rename("nowrite/file", "nowrite/yes") != 0) e(10);
X	if (rename("file", "yes") != 0) e(11);
X	if (rename("noacc/yes", "noacc/file") != 0) e(12);
X	if (rename("nowrite/yes", "nowrite/file") != 0) e(13);
X	if (rename("yes", "file") != 0) e(14);
X  }
X  System("chmod 777 noacc nowrite");
X
X  /* If rmdir() doesn't remove a directory, rename() shouldn't eighter. */
X  System("mkdir newdir olddir");
X  System("rm -rf /tmp/sema.11[ab]");
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	switch (fork()) {
X	    case -1:	printf("Can't fork\n");	break;
X	    case 0:
X		/* Child A. */
X		alarm(20);
X		if (chdir("newdir") != 0) e(15);
X		Creat("/tmp/sema.11a");
X		while (stat("/tmp/sema.11a", &st1) == -1) sleep(1);
X		exit(0);
X	    default:
X		wait(&stat_loc);
X		if (stat_loc != 0) e(16);	/* Alarm? */
X	}
X
X	/* Child B. */
X	if (chdir("olddir") != 0) e(17);
X	Creat("/tmp/sema.11b");
X	while (stat("/tmp/sema.11b", &st1) == -1) sleep(1);
X	exit(0);
X      default:
X	/* Wait for child A. It will keep ``newdir'' bussy. */
X	while (stat("/tmp/sema.11a", &st1) == -1) sleep(1);
X	if (rmdir("newdir") == -1) {
X		if (rename("olddir", "newdir") != -1) e(18);
X		if (errno != EBUSY) e(19);
X	}
X	(void) unlink("/tmp/sema.11a");
X
X	/* Wait for child B. It will keep ``olddir'' bussy. */
X	while (stat("/tmp/sema.11b", &st1) == -1) sleep(1);
X	if (rmdir("olddir") == -1) {
X		if (rename("olddir", "newdir") != -1) e(20);
X		if (errno != EBUSY) e(21);
X	}
X	(void) unlink("/tmp/sema.11b");
X	wait(&stat_loc);
X	if (stat_loc != 0) e(22);	/* Alarm? */
X  }
X}
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_32");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test33.c
sed '/^X/s///' > test33.c << '/'
X/* test33: access()		Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR      1
X#define ITERATIONS     2
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)	if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X#define Chmod(a,b)	if (chmod(a,b) != 0) printf("Can't chmod %s\n", a)
X#define Mkfifo(f)	if (mkfifo(f,0777)!=0) printf("Can't make fifo %s\n", f)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test33a, (void));
X_PROTOTYPE(void test33b, (void));
X_PROTOTYPE(void test33c, (void));
X_PROTOTYPE(void test33d, (void));
X_PROTOTYPE(void test_access, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 33 ");
X  fflush(stdout);
X  umask(0000);
X  System("rm -rf DIR_33; mkdir DIR_33");
X
X  if (geteuid() != 0) {
X	printf("must be setuid root; test aborted\n");
X	exit(1);
X  }
X
X  Chdir("DIR_33");
X  makelongnames();
X  superuser = (geteuid() == 0);
X
X  for (i = 0; i < ITERATIONS; i++) {
X/* Something wrong here.
X	if (m & 0001) test33a();
X	if (m & 0002) test33b();
X */
X	if (m & 0004) test33c();
X	if (m & 0010) test33d();
X  }
X  quit();
X}
X
Xvoid test33a()
X{				/* Test normal operation. */
X  int stat_loc;			/* For the wait(&stat_loc) call. */
X
X  subtest = 1;
X  System("/bin/rm -rf ../DIR_33/*");
X
X  /* To test normal access first make some files for real uid. */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	setuid(getuid());	/* (Re)set the effective ids to the
X				 * real ids. */
X	setgid(getgid());
X	System("> rwx; chmod 700 rwx");
X	System("> rw_; chmod 600 rw_");
X	System("> r_x; chmod 500 r_x");
X	System("> r__; chmod 400 r__");
X	System("> _wx; chmod 300 _wx");
X	System("> _w_; chmod 200 _w_");
X	System("> __x; chmod 100 __x");
X	System("> ___; chmod 000 ___");
X	exit(0);
X
X      default:
X	wait(&stat_loc);
X	if (stat_loc != 0) e(1);/* Alarm? */
X  }
X  test_access();
X
X  /* Let's test access() on directorys. */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	setuid(getuid());	/* (Re)set the effective ids to the
X				 * real ids. */
X	setgid(getgid());
X	System("rm -rf [_r][_w][_x]");
X	System("mkdir rwx; chmod 700 rwx");
X	System("mkdir rw_; chmod 600 rw_");
X	System("mkdir r_x; chmod 500 r_x");
X	System("mkdir r__; chmod 400 r__");
X	System("mkdir _wx; chmod 300 _wx");
X	System("mkdir _w_; chmod 200 _w_");
X	System("mkdir __x; chmod 100 __x");
X	System("mkdir ___; chmod 000 ___");
X	exit(0);
X
X      default:
X	wait(&stat_loc);
X	if (stat_loc != 0) e(2);/* Alarm? */
X  }
X  test_access();
X
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	setuid(getuid());	/* (Re)set the effective ids to the
X				 * real ids. */
X	setgid(getgid());
X	System("rmdir [_r][_w][_x]");
X	Mkfifo("rwx");
X	System("chmod 700 rwx");
X	Mkfifo("rw_");
X	System("chmod 600 rw_");
X	Mkfifo("r_x");
X	System("chmod 500 r_x");
X	Mkfifo("r__");
X	System("chmod 400 r__");
X	Mkfifo("_wx");
X	System("chmod 300 _wx");
X	Mkfifo("_w_");
X	System("chmod 200 _w_");
X	Mkfifo("__x");
X	System("chmod 100 __x");
X	Mkfifo("___");
X	System("chmod 000 ___");
X	exit(0);
X
X      default:
X	wait(&stat_loc);
X	if (stat_loc != 0) e(3);/* Alarm? */
X  }
X  test_access();
X
X  /* Remove all the fifos. */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	setuid(getuid());
X	setgid(getgid());
X	System("rm -rf [_r][_w][_x]");
X	exit(0);
X
X      default:
X	wait(&stat_loc);
X	if (stat_loc != 0) e(4);/* Alarm? */
X  }
X}
X
X
X
Xvoid test33b()
X{
X  int stat_loc;			/* For the wait(&stat_loc) call. */
X
X  subtest = 2;
X  System("/bin/rm -rf ../DIR_33/*");
X
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X
X	/* (Re)set the effective ids to the real ids. */
X	setuid(getuid());
X	setgid(getgid());
X	System("> ______rwx; chmod 007 ______rwx");
X	System("> ________x; chmod 001 ________x");
X	System("> _________; chmod 000 _________");
X	exit(0);
X
X      default:
X	wait(&stat_loc);
X	if (stat_loc != 0) e(1);/* Alarm? */
X  }
X
X  /* If we are superuser, we have access to all. */
X  /* Well, almost, execution access might need at least one X bit. */
X  if (superuser) {
X	if (access("_________", R_OK) != 0) e(2);
X	if (access("_________", W_OK) != 0) e(3);
X	if (access("________x", R_OK) != 0) e(4);
X	if (access("________x", W_OK) != 0) e(5);
X	if (access("________x", X_OK) != 0) e(6);
X	if (access("______rwx", R_OK) != 0) e(7);
X	if (access("______rwx", W_OK) != 0) e(8);
X	if (access("______rwx", X_OK) != 0) e(9);
X  }
X  if (!superuser) {
X	if (access("_________", R_OK) != -1) e(10);
X	if (errno != EACCES) e(11);
X	if (access("_________", W_OK) != -1) e(12);
X	if (errno != EACCES) e(13);
X	if (access("_________", X_OK) != -1) e(14);
X	if (errno != EACCES) e(15);
X	if (access("________x", R_OK) != -1) e(16);
X	if (errno != EACCES) e(17);
X	if (access("________x", W_OK) != -1) e(18);
X	if (errno != EACCES) e(19);
X	if (access("________x", X_OK) != -1) e(20);
X	if (errno != EACCES) e(21);
X	if (access("______rwx", R_OK) != -1) e(22);
X	if (errno != EACCES) e(23);
X	if (access("______rwx", W_OK) != -1) e(24);
X	if (errno != EACCES) e(25);
X	if (access("______rwx", X_OK) != -1) e(26);
X	if (errno != EACCES) e(27);
X  }
X
X  /* If the real uid != effective uid. */
X  if (getuid() != geteuid() && !superuser) {
X	System("rm -rf [_r][_w][_x]");
X	System("> rwx");
X	Chmod("rwx", 0700);
X	System("> rw_");
X	Chmod("rw_", 0600);
X	System("> r_x");
X	Chmod("r_x", 0500);
X	System("> r__");
X	Chmod("r__", 0400);
X	System("> _wx");
X	Chmod("_wx", 0300);
X	System("> _w_");
X	Chmod("_w_", 0200);
X	System("> __x");
X	Chmod("__x", 0100);
X	System("> ___");
X	Chmod("___", 0000);
X
X	if (access("rwx", F_OK) != 0) e(28);
X	if (access("rwx", R_OK) != -1) e(29);
X	if (errno != EACCES) e(30);
X	if (access("rwx", W_OK) != -1) e(31);
X	if (errno != EACCES) e(32);
X	if (access("rwx", X_OK) != -1) e(33);
X	if (errno != EACCES) e(34);
X
X	if (access("rw_", F_OK) != 0) e(35);
X	if (access("rw_", R_OK) != -1) e(36);
X	if (errno != EACCES) e(37);
X	if (access("rw_", W_OK) != -1) e(38);
X	if (errno != EACCES) e(39);
X	if (access("rw_", X_OK) != -1) e(40);
X	if (errno != EACCES) e(41);
X
X	if (access("r_x", F_OK) != 0) e(42);
X	if (access("r_x", R_OK) != -1) e(43);
X	if (errno != EACCES) e(44);
X	if (access("r_x", W_OK) != -1) e(45);
X	if (errno != EACCES) e(46);
X	if (access("r_x", X_OK) != -1) e(47);
X	if (errno != EACCES) e(48);
X
X	if (access("r__", F_OK) != 0) e(49);
X	if (access("r__", R_OK) != -1) e(50);
X	if (errno != EACCES) e(51);
X	if (access("r__", W_OK) != -1) e(52);
X	if (errno != EACCES) e(53);
X	if (access("r__", X_OK) != -1) e(54);
X	if (errno != EACCES) e(55);
X
X	if (access("_wx", F_OK) != 0) e(56);
X	if (access("_wx", R_OK) != -1) e(57);
X	if (errno != EACCES) e(58);
X	if (access("_wx", W_OK) != -1) e(59);
X	if (errno != EACCES) e(60);
X	if (access("_wx", X_OK) != -1) e(61);
X	if (errno != EACCES) e(62);
X
X	if (access("_w_", F_OK) != 0) e(63);
X	if (access("_w_", R_OK) != -1) e(64);
X	if (errno != EACCES) e(65);
X	if (access("_w_", W_OK) != -1) e(66);
X	if (errno != EACCES) e(67);
X	if (access("_w_", X_OK) != -1) e(68);
X	if (errno != EACCES) e(69);
X
X	if (access("__x", F_OK) != 0) e(70);
X	if (access("__x", R_OK) != -1) e(71);
X	if (errno != EACCES) e(72);
X	if (access("__x", W_OK) != -1) e(73);
X	if (errno != EACCES) e(74);
X	if (access("__x", X_OK) != -1) e(75);
X	if (errno != EACCES) e(76);
X
X	if (access("___", F_OK) != 0) e(77);
X	if (access("___", R_OK) != -1) e(78);
X	if (errno != EACCES) e(79);
X	if (access("___", W_OK) != -1) e(80);
X	if (errno != EACCES) e(81);
X	if (access("___", X_OK) != -1) e(82);
X	if (errno != EACCES) e(83);
X
X	System("rm -rf [_r][_w][_x]");
X  }
X}
X
Xvoid test33c()
X{				/* Test errors returned. */
X  int i;
X
X  subtest = 3;
X  System("/bin/rm -rf ../DIR_33/*");
X
X  /* Test what access() does with non existing files. */
X  System("rm -rf nonexist");
X  if (access("noexist", F_OK) != -1) e(1);
X  if (errno != ENOENT) e(2);
X  if (access("noexist", R_OK) != -1) e(3);
X  if (errno != ENOENT) e(4);
X  if (access("noexist", W_OK) != -1) e(5);
X  if (errno != ENOENT) e(6);
X  if (access("noexist", X_OK) != -1) e(7);
X  if (errno != ENOENT) e(8);
X  if (access("noexist", R_OK | W_OK) != -1) e(9);
X  if (errno != ENOENT) e(10);
X  if (access("noexist", R_OK | X_OK) != -1) e(11);
X  if (errno != ENOENT) e(12);
X  if (access("noexist", W_OK | X_OK) != -1) e(13);
X  if (errno != ENOENT) e(14);
X  if (access("noexist", R_OK | W_OK | X_OK) != -1) e(15);
X  if (errno != ENOENT) e(16);
X
X  /* Test access on a nonsearchable path. */
X  System("mkdir nosearch");
X  System("> nosearch/file");
X  System("> file");
X  Chmod("nosearch/file", 05777);
X  Chmod("file", 05777);
X  Chmod("nosearch", 0677);
X  if (!superuser) {
X	if (access("nosearch/file", F_OK) != -1) e(17);
X	if (errno != EACCES) e(18);
X	if (access("nosearch/../file", F_OK) != -1) e(19);
X	if (errno != EACCES) e(20);
X  }
X  if (superuser) {
X	if (access("nosearch/file", F_OK) != 0) e(21);
X  }
X
X  /* Double check the file is accessable. */
X  Chmod("nosearch", 0700);
X  if (access("nosearch/file", F_OK) != 0) e(22);
X
X  /* Test ToLongName and ToLongPath */
X  if (close(creat(ToLongName, 0777)) != 0) e(25);
X  if (access(ToLongName, F_OK) != 0) e(26);
X  ToLongPath[PATH_MAX - 2] = '/';
X  ToLongPath[PATH_MAX - 1] = 'a';
X  if (access(ToLongPath, F_OK) != -1) e(27);
X  if (errno != ENAMETOOLONG) e(28);
X  ToLongPath[PATH_MAX - 1] = '/';
X
X  /* Test empty strings. */
X  if (access("", F_OK) != -1) e(29);
X  if (errno != ENOENT) e(30);
X  System("rm -rf idonotexist");
X  if (access("idonotexist", F_OK) != -1) e(31);
X  if (errno != ENOENT) e(32);
X
X  /* Test non directorys in prefix of path. */
X  if (access("/etc/passwd/dir/foo", F_OK) != -1) e(33);
X  if (errno != ENOTDIR) e(34);
X  System("rm -rf nodir; > nodir");
X  if (access("nodir/foo", F_OK) != -1) e(35);
X  if (errno != ENOTDIR) e(36);
X
X  /* Test if invalid amode arguments are signaled. */
X  System("> allmod");
X  Chmod("allmod", 05777);
X  for (i = -1025; i < 1025; i++) {
X	if ((mode_t) i != F_OK && ((mode_t) i & ~(R_OK | W_OK | X_OK)) != 0) {
X		if (access("allmod", (mode_t) i) != -1) e(37);
X		if (errno != EINVAL) e(38);
X	} else 
X		if (access("allmod", (mode_t) i) != 0) e(39);
X  }
X}
X
Xvoid test33d()
X{				/* Test access() flags. */
X#define EXCLUDE(a,b)	(((a)^(b)) == ((a)|(b)))
X  subtest = 4;
X  System("/bin/rm -rf ../DIR_33/*");
X
X  /* The test are rather strong, stronger that POSIX specifies. */
X  /* The should be OR able, this test tests if all the 1 bits */
X  /* Are in diferent places. This should be what one wants. */
X  if (!EXCLUDE(R_OK, W_OK | X_OK)) e(1);
X  if (!EXCLUDE(W_OK, R_OK | X_OK)) e(2);
X  if (!EXCLUDE(X_OK, R_OK | W_OK)) e(3);
X  if (F_OK == R_OK) e(4);
X  if (F_OK == W_OK) e(5);
X  if (F_OK == X_OK) e(6);
X  if (F_OK == (R_OK | W_OK)) e(7);
X  if (F_OK == (W_OK | X_OK)) e(8);
X  if (F_OK == (R_OK | X_OK)) e(9);
X  if (F_OK == (R_OK | W_OK | X_OK)) e(10);
X}
X
Xvoid test_access()
X{				/* Test all [_r][_w][_x] files. */
X  if (!superuser) {
X	/* Test normal access. */
X	if (access("rwx", F_OK) != 0) e(11);
X	if (access("rwx", R_OK) != 0) e(12);
X	if (access("rwx", W_OK) != 0) e(13);
X	if (access("rwx", X_OK) != 0) e(14);
X	if (access("rwx", R_OK | W_OK) != 0) e(15);
X	if (access("rwx", R_OK | X_OK) != 0) e(16);
X	if (access("rwx", W_OK | X_OK) != 0) e(17);
X	if (access("rwx", R_OK | W_OK | X_OK) != 0) e(18);
X
X	if (access("rw_", F_OK) != 0) e(19);
X	if (access("rw_", R_OK) != 0) e(20);
X	if (access("rw_", W_OK) != 0) e(21);
X	if (access("rw_", X_OK) != -1) e(22);
X	if (errno != EACCES) e(23);
X	if (access("rw_", R_OK | W_OK) != 0) e(24);
X	if (access("rw_", R_OK | X_OK) != -1) e(25);
X	if (errno != EACCES) e(26);
X	if (access("rw_", W_OK | X_OK) != -1) e(27);
X	if (errno != EACCES) e(28);
X	if (access("rw_", R_OK | W_OK | X_OK) != -1) e(29);
X	if (errno != EACCES) e(30);
X
X	if (access("r_x", F_OK) != 0) e(31);
X	if (access("r_x", R_OK) != 0) e(32);
X	if (access("r_x", W_OK) != -1) e(33);
X	if (errno != EACCES) e(34);
X	if (access("r_x", X_OK) != 0) e(35);
X	if (access("r_x", R_OK | W_OK) != -1) e(36);
X	if (errno != EACCES) e(37);
X	if (access("r_x", R_OK | X_OK) != 0) e(38);
X	if (access("r_x", W_OK | X_OK) != -1) e(39);
X	if (errno != EACCES) e(40);
X	if (access("r_x", R_OK | W_OK | X_OK) != -1) e(41);
X	if (errno != EACCES) e(42);
X
X	if (access("r__", F_OK) != 0) e(43);
X	if (access("r__", R_OK) != 0) e(44);
X	if (access("r__", W_OK) != -1) e(45);
X	if (errno != EACCES) e(46);
X	if (access("r__", X_OK) != -1) e(47);
X	if (errno != EACCES) e(48);
X	if (access("r__", R_OK | W_OK) != -1) e(49);
X	if (errno != EACCES) e(50);
X	if (access("r__", R_OK | X_OK) != -1) e(51);
X	if (errno != EACCES) e(52);
X	if (access("r__", W_OK | X_OK) != -1) e(53);
X	if (errno != EACCES) e(54);
X	if (access("r__", R_OK | W_OK | X_OK) != -1) e(55);
X	if (errno != EACCES) e(56);
X
X	if (access("_wx", F_OK) != 0) e(57);
X	if (access("_wx", R_OK) != -1) e(58);
X	if (errno != EACCES) e(59);
X	if (access("_wx", W_OK) != 0) e(60);
X	if (access("_wx", X_OK) != 0) e(61);
X	if (access("_wx", R_OK | W_OK) != -1) e(62);
X	if (errno != EACCES) e(63);
X	if (access("_wx", R_OK | X_OK) != -1) e(64);
X	if (errno != EACCES) e(65);
X	if (access("_wx", W_OK | X_OK) != 0) e(66);
X	if (access("_wx", R_OK | W_OK | X_OK) != -1) e(67);
X	if (errno != EACCES) e(68);
X
X	if (access("_w_", F_OK) != 0) e(69);
X	if (access("_w_", R_OK) != -1) e(70);
X	if (errno != EACCES) e(71);
X	if (access("_w_", W_OK) != 0) e(72);
X	if (access("_w_", X_OK) != -1) e(73);
X	if (errno != EACCES) e(74);
X	if (access("_w_", R_OK | W_OK) != -1) e(75);
X	if (errno != EACCES) e(76);
X	if (access("_w_", R_OK | X_OK) != -1) e(77);
X	if (errno != EACCES) e(78);
X	if (access("_w_", W_OK | X_OK) != -1) e(79);
X	if (errno != EACCES) e(80);
X	if (access("_w_", R_OK | W_OK | X_OK) != -1) e(81);
X	if (errno != EACCES) e(82);
X
X	if (access("__x", F_OK) != 0) e(83);
X	if (access("__x", R_OK) != -1) e(84);
X	if (errno != EACCES) e(85);
X	if (access("__x", W_OK) != -1) e(86);
X	if (errno != EACCES) e(87);
X	if (access("__x", X_OK) != 0) e(88);
X	if (access("__x", R_OK | W_OK) != -1) e(89);
X	if (errno != EACCES) e(90);
X	if (access("__x", R_OK | X_OK) != -1) e(91);
X	if (errno != EACCES) e(92);
X	if (access("__x", W_OK | X_OK) != -1) e(93);
X	if (errno != EACCES) e(94);
X	if (access("__x", R_OK | W_OK | X_OK) != -1) e(95);
X	if (errno != EACCES) e(96);
X
X	if (access("___", F_OK) != 0) e(97);
X	if (access("___", R_OK) != -1) e(98);
X	if (errno != EACCES) e(99);
X	if (access("___", W_OK) != -1) e(100);
X	if (errno != EACCES) e(101);
X	if (access("___", X_OK) != -1) e(102);
X	if (errno != EACCES) e(103);
X	if (access("___", R_OK | W_OK) != -1) e(104);
X	if (errno != EACCES) e(105);
X	if (access("___", R_OK | X_OK) != -1) e(106);
X	if (errno != EACCES) e(107);
X	if (access("___", W_OK | X_OK) != -1) e(108);
X	if (errno != EACCES) e(109);
X	if (access("___", R_OK | W_OK | X_OK) != -1) e(110);
X	if (errno != EACCES) e(111);
X  }
X  if (superuser) {
X	/* Test root access don't test X_OK on [_r][_w]_ files. */
X	if (access("rwx", F_OK) != 0) e(112);
X	if (access("rwx", R_OK) != 0) e(113);
X	if (access("rwx", W_OK) != 0) e(114);
X	if (access("rwx", X_OK) != 0) e(115);
X	if (access("rwx", R_OK | W_OK) != 0) e(116);
X	if (access("rwx", R_OK | X_OK) != 0) e(117);
X	if (access("rwx", W_OK | X_OK) != 0) e(118);
X	if (access("rwx", R_OK | W_OK | X_OK) != 0) e(119);
X
X	if (access("rw_", F_OK) != 0) e(120);
X	if (access("rw_", R_OK) != 0) e(121);
X	if (access("rw_", W_OK) != 0) e(122);
X	if (access("rw_", R_OK | W_OK) != 0) e(123);
X
X	if (access("r_x", F_OK) != 0) e(124);
X	if (access("r_x", R_OK) != 0) e(125);
X	if (access("r_x", W_OK) != 0) e(126);
X	if (access("r_x", X_OK) != 0) e(127);
X	if (access("r_x", R_OK | W_OK) != 0) e(128);
X	if (access("r_x", R_OK | X_OK) != 0) e(129);
X	if (access("r_x", W_OK | X_OK) != 0) e(130);
X	if (access("r_x", R_OK | W_OK | X_OK) != 0) e(131);
X
X	if (access("r__", F_OK) != 0) e(132);
X	if (access("r__", R_OK) != 0) e(133);
X	if (access("r__", W_OK) != 0) e(134);
X	if (access("r__", R_OK | W_OK) != 0) e(135);
X
X	if (access("_wx", F_OK) != 0) e(136);
X	if (access("_wx", R_OK) != 0) e(137);
X	if (access("_wx", W_OK) != 0) e(138);
X	if (access("_wx", X_OK) != 0) e(139);
X	if (access("_wx", R_OK | W_OK) != 0) e(140);
X	if (access("_wx", R_OK | X_OK) != 0) e(141);
X	if (access("_wx", W_OK | X_OK) != 0) e(142);
X	if (access("_wx", R_OK | W_OK | X_OK) != 0) e(143);
X
X	if (access("_w_", F_OK) != 0) e(144);
X	if (access("_w_", R_OK) != 0) e(145);
X	if (access("_w_", W_OK) != 0) e(146);
X	if (access("_w_", R_OK | W_OK) != 0) e(147);
X
X	if (access("__x", F_OK) != 0) e(148);
X	if (access("__x", R_OK) != 0) e(149);
X	if (access("__x", W_OK) != 0) e(150);
X	if (access("__x", X_OK) != 0) e(151);
X	if (access("__x", R_OK | W_OK) != 0) e(152);
X	if (access("__x", R_OK | X_OK) != 0) e(153);
X	if (access("__x", W_OK | X_OK) != 0) e(154);
X	if (access("__x", R_OK | W_OK | X_OK) != 0) e(155);
X
X	if (access("___", F_OK) != 0) e(156);
X	if (access("___", R_OK) != 0) e(157);
X	if (access("___", W_OK) != 0) e(158);
X	if (access("___", R_OK | W_OK) != 0) e(159);
X  }
X}
X
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_33");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test34.c
sed '/^X/s///' > test34.c << '/'
X/* test34: chmod() chown() 	Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X/* There is a problem getting valid uids and gids, so we use the passwd
X** file (ie. /etc/passwd). I don't like this, but I see no other way.
X** The read-only-device-error (EROFS) is not checked!
X** Supplementary group IDs are ignored.
X*/
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <ctype.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS      4
X#define N 100
X
X#define ALL_RWXB	(S_IRWXU | S_IRWXG | S_IRWXO)
X#define ALL_SETB	(S_ISUID | S_ISGID)
X#define ALL_BITS	(ALL_RWXB | ALL_SETB)
X
X#define System(cmd)   if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)    if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)     if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X#define Mkfifo(f)     if (mkfifo(f,0777)!=0) printf("Can't make fifo %s\n", f)
X#define Mkdir(f)      if (mkdir(f,0777)!=0) printf("Can't make dir %s\n", f)
X#define Creat(f)      if (close(creat(f,0777))!=0) printf("Can't creat %s\n",f)
X
X/* This program uses /etc/passwd and assumes things about it's contents. */
X#define PASSWD_FILE	"/etc/passwd"
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xint I_can_chown;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar NameTooLong[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar PathTooLong[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test34a, (void));
X_PROTOTYPE(void test34b, (void));
X_PROTOTYPE(void test34c, (void));
X_PROTOTYPE(mode_t mode, (char *file_name));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X_PROTOTYPE(void getids, (uid_t * uid, gid_t * gid));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 34 ");
X  fflush(stdout);
X  (void) system("chmod 777 DIR_34/* > /dev/null 2> /dev/null");
X  System("rm -rf DIR_34; mkdir DIR_34");
X  if (chdir("DIR_34") != 0) {
X	fprintf(stderr, "Can't go to DIR_34\n");
X	system("rm -rf DIR_34");
X	exit(1);
X  }
X  makelongnames();
X  superuser = (geteuid() == (uid_t) 0);
X
X#ifdef _POSIX_CHOWN_RESTRICTED
X  I_can_chown = superuser;
X#else
X  I_can_chown = 1;
X#endif
X
X  umask(0000);
X
X  for (i = 1; i < ITERATIONS; i++) {
X	if (m & 0001) test34a();
X	if (m & 0002) test34b();
X	if (m & 0004) test34c();
X  }
X  quit();
X}
X
Xvoid test34a()
X{				/* Test normal operation. */
X  time_t time1, time2;
X  mode_t mod;
X  struct stat st1, st2;
X  int cnt;
X  uid_t uid, uid2;
X  gid_t gid, gid2;
X  int stat_loc;
X
X  subtest = 1;
X
X  /* Make scratch file. */
X  Creat("foo");
X
X  for (mod = 0; mod <= ALL_BITS; mod++) {
X	if ((mod & ALL_BITS) != mod)	/* If not a valid mod next. */
X		continue;
X	Stat("foo", &st1);
X	if (time(&time1) == (time_t) - 1) e(1);
X	if (chmod("foo", mod) != 0) e(2);
X	Stat("foo", &st2);
X	if (time(&time2) == (time_t) - 1) e(3);
X	if (superuser)
X		if ((st2.st_mode & ALL_BITS) != mod) e(4);
X	if (!superuser)
X		if ((st2.st_mode & ALL_RWXB) != (mod & ALL_RWXB)) e(5);
X
X	/* Test the C time feald. */
X	if (st1.st_ctime > st2.st_ctime) e(6);
X	if (st1.st_ctime > time1) e(7);
X	if (st1.st_ctime > time2) e(8);
X#ifndef V1_FILESYSTEM
X	if (st2.st_ctime < time1) e(9);
X#endif
X	if (st2.st_ctime > time2) e(10);
X	if (st1.st_atime != st2.st_atime) e(11);
X	if (st1.st_mtime != st2.st_mtime) e(12);
X  }				/* End for loop. */
X
X  /* Check if chown(file, geteuid(), getegid()) works. */
X  for (cnt = 0; cnt < 20; cnt++) {
X	/* Set all rights on foo, including the set .id bits. */
X	if (chmod("foo", ALL_BITS) != 0) e(13);
X	Stat("foo", &st1);
X	if (time(&time1) == (time_t) -1) e(14);
X
X	if (chown("foo", geteuid(), getegid()) != 0) e(15);
X	Stat("foo", &st2);
X	if (time(&time2) == (time_t) -1) e(16);
X
X	/* Check ``chown()'' killed the set .id bits. */
X	if (!superuser) {
X		if ((st1.st_mode & ALL_RWXB) != ALL_RWXB) e(17);
X		if ((st2.st_mode & ALL_BITS) != ALL_RWXB) e(18);
X	}
X	if (superuser) {
X		if ((st1.st_mode & ALL_BITS) != ALL_BITS) e(19);
X		if ((st1.st_mode & ALL_RWXB) != ALL_RWXB) e(20);
X	}
X
X	/* Check the timing. */
X	if (st1.st_ctime > st2.st_ctime) e(21);
X	if (st1.st_ctime > time1) e(22);
X	if (st1.st_ctime > time2) e(23);
X#ifndef V1_FILESYSTEM
X	if (st2.st_ctime < time1) e(24);
X#endif
X	if (st2.st_ctime > time2) e(25);
X	if (st1.st_atime != st2.st_atime) e(26);
X	if (st1.st_mtime != st2.st_mtime) e(27);
X  }				/* End for loop. */
X
X  /* Make scratch file. */
X  if (chmod("foo", ALL_RWXB) != 0) e(28);
X
X  if (I_can_chown) {
X	/* Do a 20 tests on a gid and uid. */
X	for (cnt = 0; cnt < 20; cnt++) {
X		/* Get a uid and a gid, test chown. */
X		getids(&uid, &gid);
X		Stat("foo", &st1);
X		if (time(&time1) == (time_t) -1) e(29);
X		if (chown("foo", (uid_t) 0, (gid_t) 0) != 0) e(30);
X		Stat("foo", &st2);
X		if (time(&time2) == (time_t) -1) e(31);
X
X		/* Test the C time field. */
X		if (st1.st_ctime > st2.st_ctime) e(32);
X		if (st1.st_ctime > time1) e(33);
X		if (st1.st_ctime > time2) e(34);
X		if (st2.st_ctime < time1) e(35);
X		if (st2.st_ctime > time2) e(36);
X		if (st1.st_atime != st2.st_atime) e(37);
X		if (st1.st_mtime != st2.st_mtime) e(38);
X
X		/* Do aditional tests. */
X		if (chown("foo", (uid_t) 0, gid) != 0) e(39);
X		if (chown("foo", uid, (gid_t) 0) != 0) e(40);
X		if (chown("foo", uid, gid) != 0) e(41);
X	}
X  }
X  if (superuser) {
X	/* Check if a non-superuser can change a files gid to gid2 *
X	 * if gid2 is the current process gid. */
X	for (cnt = 0; cnt < 5; cnt++) {
X		switch (fork()) {
X		    case -1:
X			printf("Can't fork\n");
X			break;
X		    case 0:
X			alarm(20);
X
X			getids(&uid, &gid);
X			if (uid == 0) {
X				getids(&uid, &gid);
X				if (uid == 0) e(42);
X			}
X			getids(&uid2, &gid2);
X			if (gid == gid2) e(43);
X
X			/* Creat boo and bar for user uid of group gid. */
X			Creat("boo");
X			if (chown("boo", uid, gid) != 0) e(44);
X			if (chmod("boo", ALL_BITS) != 0) e(45);
X			Creat("bar");
X			if (chown("bar", uid, gid) != 0) e(46);
X			if (chmod("bar", ALL_BITS) != 0) e(47);
X
X			/* We now become user uid of group gid2. */
X			setgid(gid2);
X			setuid(uid);
X
X			Stat("bar", &st1);
X			if (time(&time1) == (time_t) -1) e(48);
X			if (chown("bar", uid, gid2) != 0) e(49);
X			Stat("bar", &st2);
X			if (time(&time2) == (time_t) -1) e(50);
X
X			/* Check if the SET_BITS are cleared. */
X			if ((st1.st_mode & ALL_BITS) != ALL_BITS) e(51);
X			if ((st2.st_mode & ALL_BITS) != ALL_RWXB) e(52);
X
X			/* Check the st_times. */
X			if (st1.st_ctime > st2.st_ctime) e(53);
X			if (st1.st_ctime > time1) e(54);
X			if (st1.st_ctime > time2) e(55);
X			if (st2.st_ctime < time1) e(56);
X			if (st2.st_ctime > time2) e(57);
X			if (st1.st_atime != st2.st_atime) e(58);
X			if (st1.st_mtime != st2.st_mtime) e(59);
X
X			Stat("boo", &st1);
X			if (chmod("boo", ALL_BITS) != 0) e(60);
X			Stat("boo", &st2);
X
X			/* Check if the set gid bit is cleared. */
X			if ((st1.st_mode & ALL_RWXB) != ALL_RWXB) e(61);
X			if ((st2.st_mode & S_ISGID) != 0) e(62);
X
X			if (chown("boo", uid, gid2) != 0) e(63);
X			Stat("boo", &st1);
X
X			/* Check if the set uid bit is cleared. */
X			if ((st1.st_mode & S_ISUID) != 0) e(64);
X
X			exit(0);
X		    default:
X			wait(&stat_loc);
X			if (stat_loc != 0) e(65);	/* Alarm? */
X		}
X	}			/* end for loop. */
X  }				/* end if (superuser). */
X  if (chmod("foo", ALL_BITS) != 0) e(66);
X  Stat("foo", &st1);
X  if (chown("foo", geteuid(), getegid()) != 0) e(67);
X  Stat("foo", &st2);
X  if ((st1.st_mode & ALL_BITS) != ALL_BITS) e(68);	/* See intro! */
X  if (superuser)
X	if ((st2.st_mode & ALL_RWXB) != ALL_RWXB) e(69);
X  if (!superuser)
X	if ((st2.st_mode & ALL_BITS) != ALL_RWXB) e(70);
X
X  (void) system("chmod 777 ../DIR_34/* > /dev/null 2> /dev/null");
X  System("/bin/rm -rf ../DIR_34/*");
X}
X
Xvoid test34b()
X{
X  time_t time1, time2;
X  mode_t mod;
X  struct stat st1, st2;
X
X  subtest = 2;
X
X  /* Test chmod() and chown() on non regular files and on MaxName and
X   * MaxPath. * Funny, but dirs should also have S_IS.ID bits.
X   */
X  Mkfifo("fifo");
X  Mkdir("dir");
X  Creat(MaxName);
X  MaxPath[strlen(MaxPath) - 2] = '/';
X  MaxPath[strlen(MaxPath) - 1] = 'a';	/* make ././.../a */
X  Creat(MaxPath);
X
X  for (mod = 1; mod <= ALL_BITS; mod <<= 1) {
X	if ((mod & ALL_BITS) != mod) continue;	/* bad mod */
X	Stat("dir", &st1);
X	if (time(&time1) == (time_t) -1) e(1);
X	if (chmod("dir", mod) != 0) e(2);
X	Stat("dir", &st2);
X	if (time(&time2) == (time_t) -1) e(3);
X	if (superuser)
X		if ((st2.st_mode & ALL_BITS) != mod) e(4);
X	if (!superuser)
X		if ((st2.st_mode & ALL_RWXB) != (mod & ALL_RWXB)) e(5);
X
X	/* Test the C time field. */
X	if (st1.st_ctime > st2.st_ctime) e(6);
X	if (st1.st_ctime > time1) e(7);
X	if (st1.st_ctime > time2) e(8);
X#ifndef V1_FILESYSTEM
X	if (st2.st_ctime < time1) e(9);
X#endif
X	if (st2.st_ctime > time2) e(10);
X	if (st1.st_atime != st2.st_atime) e(11);
X	if (st1.st_mtime != st2.st_mtime) e(12);
X
X	Stat("fifo", &st1);
X	if (time(&time1) == (time_t) -1) e(13);
X	if (chmod("fifo", mod) != 0) e(14);
X	Stat("fifo", &st2);
X	if (time(&time2) == (time_t) -1) e(15);
X	if (superuser)
X		if ((st2.st_mode & ALL_BITS) != mod) e(16);
X	if (!superuser)
X		if ((st2.st_mode & ALL_RWXB) != (mod & ALL_RWXB)) e(17);
X
X	/* Test the C time field. */
X	if (st1.st_ctime > st2.st_ctime) e(18);
X	if (st1.st_ctime > time1) e(19);
X	if (st1.st_ctime > time2) e(20);
X#ifndef V1_FILESYSTEM
X	if (st2.st_ctime < time1) e(21);
X#endif
X	if (st2.st_ctime > time2) e(22);
X	if (st1.st_atime != st2.st_atime) e(23);
X	if (st1.st_mtime != st2.st_mtime) e(24);
X
X	Stat(MaxName, &st1);
X	if (time(&time1) == (time_t) -1) e(25);
X	if (chmod(MaxName, mod) != 0) e(26);
X	Stat(MaxName, &st2);
X	if (time(&time2) == (time_t) -1) e(27);
X	if (superuser)
X		if ((st2.st_mode & ALL_BITS) != mod) e(28);
X	if (!superuser)
X		if ((st2.st_mode & ALL_RWXB) != (mod & ALL_RWXB)) e(29);
X
X	/* Test the C time field. */
X	if (st1.st_ctime > st2.st_ctime) e(30);
X	if (st1.st_ctime > time1) e(31);
X	if (st1.st_ctime > time2) e(32);
X#ifndef V1_FILESYSTEM
X	if (st2.st_ctime < time1) e(33);
X#endif
X	if (st2.st_ctime > time2) e(34);
X	if (st1.st_atime != st2.st_atime) e(35);
X	if (st1.st_mtime != st2.st_mtime) e(36);
X
X	Stat(MaxPath, &st1);
X	if (time(&time1) == (time_t) -1) e(37);
X	if (chmod(MaxPath, mod) != 0) e(38);
X	Stat(MaxPath, &st2);
X	if (time(&time2) == (time_t) -1) e(39);
X	if (superuser)
X		if ((st2.st_mode & ALL_BITS) != mod) e(40);
X	if (!superuser)
X		if ((st2.st_mode & ALL_RWXB) != (mod & ALL_RWXB)) e(41);
X
X	/* Test the C time field. */
X	if (st1.st_ctime > st2.st_ctime) e(42);
X	if (st1.st_ctime > time1) e(43);
X	if (st1.st_ctime > time2) e(44);
X#ifndef V1_FILESYSTEM
X	if (st2.st_ctime < time1) e(45);
X#endif
X	if (st2.st_ctime > time2) e(46);
X	if (st1.st_atime != st2.st_atime) e(47);
X	if (st1.st_mtime != st2.st_mtime) e(48);
X  }
X
X  if (chmod("dir", 0777) != 0) e(49);
X  if (chmod("fifo", 0777) != 0) e(50);
X  if (chmod(MaxName, 0777) != 0) e(51);
X  if (chmod(MaxPath, 0777) != 0) e(52);
X
X  (void) system("chmod 777 ../DIR_34/* > /dev/null 2> /dev/null");
X  System("/bin/rm -rf ../DIR_34/*");
X}
X
Xvoid test34c()
X{
X  struct stat st;
X  uid_t uid, uid2;
X  gid_t gid, gid2;
X  int stat_loc;
X
X  subtest = 3;
X
X  Mkdir("dir");
X  Creat("dir/try_me");
X
X  /* Disalow search permission and see if chmod() and chown() return
X   * EACCES. 
X   */
X  if (chmod("dir", ALL_BITS & ~S_IXUSR) != 0) e(1);
X  if (!superuser) {
X	if (chmod("dir/try_me", 0) != -1) e(2);
X	if (errno != EACCES) e(3);
X	if (I_can_chown) {
X		if (chown("dir/try_me", geteuid(), getegid()) != -1) e(4);
X		if (errno != EACCES) e(5);
X	}
X  }
X
X  /* Check ENOTDIR. */
X  Mkfifo("fifo");
X  if (chmod("fifo/try_me", 0) != -1) e(6);
X  if (errno != ENOTDIR) e(7);
X  if (chown("fifo/try_me", geteuid(), getegid()) != -1) e(8);
X  if (errno != ENOTDIR) e(9);
X
X  Creat("file");
X  if (chmod("file/try_me", 0) != -1) e(10);
X  if (errno != ENOTDIR) e(11);
X  if (chown("file/try_me", geteuid(), getegid()) != -1) e(12);
X  if (errno != ENOTDIR) e(13);
X
X  /* Check empty path. */
X  if (chmod("", 0) != -1) e(14);
X  if (errno != ENOENT) e(15);
X  if (chown("", geteuid(), getegid()) != -1) e(16);
X  if (errno != ENOENT) e(17);
X
X  /* Check non existing file name. */
X  if (chmod("non_exist", 0) != -1) e(18);
X  if (errno != ENOENT) e(19);
X  if (chown("non_exist", geteuid(), getegid()) != -1) e(20);
X  if (errno != ENOENT) e(21);
X
X  /* Check what we get if we do not have permisson. */
X  if (!superuser) {
X	Stat("/", &st);
X	if (st.st_uid == geteuid()) e(22);
X
X	/* First I had 0, I changed it to st.st_mode 8-). */
X	if (chmod("/", st.st_mode) != -1) e(23);
X	if (errno != EPERM) e(24);
X  }
X  if (!I_can_chown) {
X	Stat("/", &st);
X	if (st.st_uid == geteuid()) e(25);
X	if (chown("/", geteuid(), getegid()) != -1) e(26);
X	if (errno != EPERM) e(27);
X  }
X
X  /* If we are superuser, we can test all id combinations. */
X  if (superuser) {
X	switch (fork()) {
X	    case -1:	printf("Can't fork\n");	break;
X	    case 0:
X		alarm(20);
X
X		getids(&uid, &gid);
X		if (uid == 0) {
X			getids(&uid, &gid);
X			if (uid == 0) e(28);
X		}
X		getids(&uid2, &gid2);
X		if (gid == gid2) e(29);
X		if (uid == uid2) e(30);
X
X		/* Creat boo, owned by root. */
X		Creat("boo");
X		if (chmod("boo", ALL_BITS) != 0) e(31);
X
X		/* Creat boo for user uid2 of group gid2. */
X		Creat("bar");
X		if (chown("bar", uid2, gid2) != 0) e(32);
X		if (chmod("bar", ALL_BITS) != 0) e(33);
X
X		/* Creat my_gid for user uid2 of group gid. */
X		Creat("my_gid");
X		if (chown("my_gid", uid2, gid) != 0) e(34);
X		if (chmod("my_gid", ALL_BITS) != 0) e(35);
X
X		/* Creat my_uid for user uid of uid gid. */
X		Creat("my_uid");
X		if (chown("my_uid", uid, gid) != 0) e(36);
X		if (chmod("my_uid", ALL_BITS) != 0) e(37);
X
X		/* We now become user uid of uid gid. */
X		setgid(gid);
X		setuid(uid);
X
X		if (chown("boo", uid, gid) != -1) e(38);
X		if (errno != EPERM) e(39);
X		if (chown("bar", uid, gid) != -1) e(40);
X		if (errno != EPERM) e(41);
X		if (chown("my_gid", uid, gid) != -1) e(42);
X		if (errno != EPERM) e(43);
X		if (chown("my_uid", uid, gid2) != -1) e(44);
X
X		/* The EPERM is not strict POSIX. */
X		if (errno != EPERM) e(45);
X
X		if (chmod("boo", 0) != -1) e(46);
X		if (errno != EPERM) e(47);
X		if (chmod("bar", 0) != -1) e(48);
X		if (errno != EPERM) e(49);
X		if (chmod("my_gid", 0) != -1) e(50);
X		if (errno != EPERM) e(51);
X
X		exit(0);
X	    default:
X		wait(&stat_loc);
X		if (stat_loc != 0) e(52);	/* Alarm? */
X	}
X  }
X
X  /* Check too long path ed. */
X  Creat(NameTooLong);
X  if (chmod(NameTooLong, 0777) != 0) e(57);
X  if (chown(NameTooLong, geteuid(), getegid()) != 0) e(58);
X
X  /* Make PathTooLong contain ././.../a */
X  PathTooLong[strlen(PathTooLong) - 2] = '/';
X  PathTooLong[strlen(PathTooLong) - 1] = 'a';
X  Creat("a");
X  if (chmod(PathTooLong, 0777) != -1) e(59);
X  if (errno != ENAMETOOLONG) e(60);
X  if (chown(PathTooLong, geteuid(), getegid()) != -1) e(61);
X  if (errno != ENAMETOOLONG) e(62);
X
X  (void) system("chmod 777 ../DIR_34/* > /dev/null 2> /dev/null");
X  System("/bin/rm -rf ../DIR_34/*");
X}
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(NameTooLong, MaxName);	/* copy them Max to TooLong */
X  strcpy(PathTooLong, MaxPath);
X
X  NameTooLong[NAME_MAX] = 'a';
X  NameTooLong[NAME_MAX + 1] = '\0';	/* extend NameTooLong by one too many*/
X  PathTooLong[PATH_MAX - 1] = '/';
X  PathTooLong[PATH_MAX] = '\0';	/* inc PathTooLong by one */
X}
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	system("rm -rf DIR_34");
X	exit(1);
X  }
X  errno = 0;
X}
X
Xvoid quit()
X{
X  Chdir("..");
X  (void) system("chmod 777 DIR_34/* > /dev/null 2> /dev/null");
X  System("rm -rf DIR_34");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
X
X/* Getids returns a valid uid and gid. Is used PASSWD FILE.
X * It assumes the following format for a passwd file line:
X * <user_name>:<passwd>:<uid>:<gid>:<other_stuff>
X * If no uids and gids can be found, it will only return 0 ids.
X */
Xvoid getids(r_uid, r_gid)
Xuid_t * r_uid;
Xgid_t * r_gid;
X{
X  char line[N];
X  char *p;
X  uid_t uid;
X  gid_t gid;
X  FILE *fp;
X  int i;
X
X  static uid_t a_uid[N];	/* Array for uids. */
X  static gid_t a_gid[N];	/* Array for gids. */
X  static int nuid = 0, ngid = 0;/* The number of user & group ids. */
X  static int cuid = 0, cgid = 0;/* The current id index. */
X
X  /* If we don't have any uids go read some from the passwd file. */
X  if (nuid == 0) {
X	a_uid[nuid++] = 0;	/* Root uid and gid. */
X	a_gid[ngid++] = 0;
X	if ((fp = fopen(PASSWD_FILE, "r")) == NULL) {
X		printf("Can't open ");
X		perror(PASSWD_FILE);
X	}
X	while (fp != NULL && fgets(line, sizeof(line), fp) != NULL) {
X		p = strchr(line, ':');
X		if (p != NULL) p = strchr(p + 1, ':');
X		if (p != NULL) {
X			p++;
X			uid = 0;
X			while (isdigit(*p)) {
X				uid *= 10;
X				uid += (uid_t) (*p - '0');
X				p++;
X			}
X			if (*p != ':') continue;
X			p++;
X			gid = 0;
X			while (isdigit(*p)) {
X				gid *= 10;
X				gid += (gid_t) (*p - '0');
X				p++;
X			}
X			if (*p != ':') continue;
X			if (nuid < N) {
X				for (i = 0; i < nuid; i++)
X					if (a_uid[i] == uid) break;
X				if (i == nuid) a_uid[nuid++] = uid;
X			}
X			if (ngid < N) {
X				for (i = 0; i < ngid; i++)
X					if (a_gid[i] == gid) break;
X				if (i == ngid) a_gid[ngid++] = gid;
X			}
X			if (nuid >= N && ngid >= N) break;
X		}
X	}
X	if (fp != NULL) fclose(fp);
X  }
X
X  /* We now have uids and gids in a_uid and a_gid. */
X  if (cuid >= nuid) cuid = 0;
X  if (cgid >= ngid) cgid = 0;
X  *r_uid = a_uid[cuid++];
X  *r_gid = a_gid[cgid++];
X}
/
echo x - test35.c
sed '/^X/s///' > test35.c << '/'
X/* test35: utime()		Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <utime.h>
X#include <errno.h>
X#include <time.h>
X#include <ctype.h>
X#include <stdio.h>
X
X#define MAX_ERROR	1
X#define ITERATIONS     10
X#define N 100
X
X#define System(cmd)   if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)    if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)     if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X#define Mkfifo(f)     if (mkfifo(f,0777)!=0) printf("Can't make fifo %s\n", f)
X#define Mkdir(f)      if (mkdir(f,0777)!=0) printf("Can't make dir %s\n", f)
X#define Creat(f)      if (close(creat(f,0777))!=0) printf("Can't creat %s\n",f)
X#define Time(t)	      if (time(t) == (time_t)-1) printf("Time error\n")
X#define Chown(f,u,g)  if (chown(f,u,g) != 0) printf("Can't chown %s\n", f)
X#define Chmod(f,m)    if (chmod(f,m) != 0) printf("Can't chmod %s\n", f)
X
X#define PASSWD_FILE 	"/etc/passwd"
X
Xint errct = 0;
Xint subtest = 1;
Xint I_can_chown;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar NameTooLong[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar PathTooLong[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test35a, (void));
X_PROTOTYPE(void test35b, (void));
X_PROTOTYPE(void test35c, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X_PROTOTYPE(void getids, (uid_t * uid, gid_t * gid));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (geteuid() == 0 || getuid() == 0) {
X	printf("Test 35 cannot run as root; test aborted\n");
X	exit(1);
X  }
X
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 35 ");
X  fflush(stdout);
X  System("rm -rf DIR_35; mkdir DIR_35");
X  Chdir("DIR_35");
X  makelongnames();
X  superuser = (geteuid() == 0);
X#ifdef _POSIX_CHOWN_RESTRICTED
X  I_can_chown = superuser;
X#else
X  I_can_chown = 1;
X#endif
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test35a();
X	if (m & 0002) test35b();
X	if (m & 0004) test35c();
X  }
X  quit();
X}
X
Xvoid test35a()
X{				/* Test normal operation. */
X  struct stat st;
X  struct utimbuf ub;
X  time_t time1, time2;
X  int cnt;
X
X  subtest = 1;
X
X  /* Creat scratch file. */
X  Creat("foo");
X
X  /* Set file times back two seconds. */
X  Stat("foo", &st);
X  ub.actime = st.st_atime - 2;
X  ub.modtime = st.st_mtime - 2;
X  Time(&time1);
X  utime("foo", &ub);
X  Time(&time2);
X  Stat("foo", &st);
X  if (ub.actime != st.st_atime) e(1);
X  if (ub.modtime != st.st_mtime) e(2);
X
X  /* The status changed time sould be changed. */
X#ifndef V1_FILESYSTEM
X  if (st.st_ctime < time1) e(3);
X#endif
X  if (st.st_ctime > time2) e(4);
X
X  /* Add twenty seconds. */
X  Stat("foo", &st);
X  ub.actime = st.st_atime + 20;
X  ub.modtime = st.st_mtime + 20;
X  Time(&time1);
X  utime("foo", &ub);
X  Time(&time2);
X  Stat("foo", &st);
X  if (ub.actime != st.st_atime) e(5);
X  if (ub.modtime != st.st_mtime) e(6);
X  if (st.st_ctime < time1) e(7);
X#ifndef V1_FILESYSTEM
X  if (st.st_ctime > time2) e(8);
X#endif
X
X  /* Try 100 times to do utime in less than one second. */
X  cnt = 0;
X  do {
X	Time(&time1);
X	utime("foo", (struct utimbuf *) NULL);
X	Time(&time2);
X  } while (time1 != time2 && cnt++ < 100);
X  if (time1 == time2) {
X	Stat("foo", &st);
X	Time(&time2);
X	if (st.st_atime != time1) e(9);
X	if (st.st_mtime != time1) e(10);
X  } else {
X	Stat("foo", &st);
X	if (st.st_atime > time2) e(11);
X	if (st.st_mtime > time2) e(12);
X	Time(&time2);
X	if (st.st_atime < time1) e(13);
X	if (st.st_mtime < time1) e(14);
X  }
X  if (st.st_ctime < time1) e(15);
X  if (st.st_ctime > time2) e(16);
X
X  System("/bin/rm -rf ../DIR_35/*");
X}
X
Xvoid test35b()
X{
X  subtest = 2;
X
X  /* MaxPath and MaxName checkup. */
X  Creat(MaxName);
X  MaxPath[strlen(MaxPath) - 2] = '/';
X  MaxPath[strlen(MaxPath) - 1] = 'a';	/* make ././.../a */
X  Creat(MaxPath);
X  if (utime(MaxName, NULL) != 0) e(1);
X  if (utime(MaxPath, NULL) != 0) e(2);
X
X  /* The owner doesn't need write permisson to set  times. */
X  Creat("foo");
X  if (chmod("foo", 0) != 0) e(3);
X  if (utime("foo", NULL) != 0) e(4);
X  if (chmod("foo", 0777) != 0) e(5);
X  if (utime("foo", NULL) != 0) e(6);
X
X
X
X  System("/bin/rm -rf ../DIR_35/*");
X}
X
Xvoid test35c()
X{
X  gid_t gid, gid2;
X  uid_t uid, uid2;
X  struct utimbuf ub;
X  int stat_loc;
X
X  subtest = 3;
X
X  /* Access problems. */
X  Mkdir("bar");
X  Creat("bar/tryme");
X  if (superuser) {
X	Chmod("bar", 0000);	/* No search permisson at all. */
X	if (utime("bar/tryme", NULL) != 0) e(1);
X  }
X  if (!superuser) {
X	Chmod("bar", 0677);	/* No search permisson. */
X	if (utime("bar/tryme", NULL) != -1) e(2);
X	if (errno != EACCES) e(3);
X  }
X  Chmod("bar", 0777);
X
X  if (I_can_chown) {
X	switch (fork()) {
X	    case -1:	printf("Can't fork\n");	break;
X	    case 0:
X		alarm(20);
X
X		/* Get two differend non root uids. */
X		if (superuser) {
X			getids(&uid, &gid);
X			if (uid == 0) getids(&uid, &gid);
X			if (uid == 0) e(4);
X		}
X		if (!superuser) {
X			uid = geteuid();
X			gid = getegid();
X		}
X		getids(&uid2, &gid);
X		if (uid == uid2) getids(&uid2, &gid2);
X		if (uid == uid2) e(5);
X
X		/* Creat a number of files for root, user and user2. */
X		Creat("rootfile");	/* Owned by root. */
X		Chmod("rootfile", 0600);
X		Chown("rootfile", 0, 0);
X		Creat("user2file");	/* Owned by user 2, writeable. */
X		Chmod("user2file", 0020);
X		Chown("user2file", uid2, gid);
X		Creat("user2private");	/* Owned by user 2, privately. */
X		Chmod("user2private", 0600);
X		Chown("user2private", uid2, gid);
X
X		if (superuser) {
X			setgid(gid);
X			setuid(uid);
X		}
X
X		/* We now are user ``uid'' from group ``gid''. */
X		ub.actime = (time_t) 12345L;
X		ub.modtime = (time_t) 12345L;
X
X		if (utime("rootfile", NULL) != -1) e(6);
X		if (errno != EACCES) e(7);
X		if (utime("rootfile", &ub) != -1) e(8);
X		/* If (errno != EACCES) e(9); Posix doesn't realy say. */
X
X		if (utime("user2file", NULL) != 0) e(10);
X		if (utime("user2file", &ub) != -1) e(11);
X		if (errno != EPERM) e(12);
X
X		if (utime("user2private", NULL) != -1) e(13);
X		if (errno != EACCES) e(14);
X		if (utime("user2private", &ub) != -1) e(15);
X		/* If (errno != EACCES) e(16); Posix doesn't realy say. */
X
X		exit(0);
X	    default:
X		wait(&stat_loc);
X		if (stat_loc != 0) e(17);	/* Alarm? */
X	}
X  }
X
X  /* Test names that are too long. */
X  Creat(NameTooLong);
X  if (utime(NameTooLong, NULL) != 0) e(20);
X
X  /* Make PathTooLong contain ././.../a */
X  PathTooLong[strlen(PathTooLong) - 2] = '/';
X  PathTooLong[strlen(PathTooLong) - 1] = 'a';
X  Creat("a");
X  if (utime(PathTooLong, NULL) != -1) e(21);
X  if (errno != ENAMETOOLONG) e(22);
X
X  /* Non existing file name. */
X  if (utime("nonexist", NULL) != -1) e(23);
X  if (errno != ENOENT) e(24);
X
X  /* Empty file name. */
X  if (utime("", NULL) != -1) e(25);
X  if (errno != ENOENT) e(26);
X
X  System("/bin/rm -rf ../DIR_35/*");
X}
X
X
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(NameTooLong, MaxName);	/* copy them Max to TooLong */
X  strcpy(PathTooLong, MaxPath);
X
X  NameTooLong[NAME_MAX] = 'a';
X  NameTooLong[NAME_MAX + 1] = '\0';	/* extend NameTooLong by one too many*/
X  PathTooLong[PATH_MAX - 1] = '/';
X  PathTooLong[PATH_MAX] = '\0';	/* inc PathTooLong by one */
X}
X
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_35");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
X
X
X/* Getids returns a valid uid and gid. Is used PASSWD FILE.
X** It assumes the following format for a passwd file line:
X** <user_name>:<passwd>:<uid>:<gid>:<other_stuff>
X** If no uids and gids can be found, it will only return 0 ids.
X*/
Xvoid getids(r_uid, r_gid)
Xuid_t *r_uid;
Xgid_t *r_gid;
X{
X  char line[N];
X  char *p;
X  uid_t uid;
X  gid_t gid;
X  FILE *fp;
X  int i;
X
X  static uid_t a_uid[N];	/* Array for uids. */
X  static gid_t a_gid[N];	/* Array for gids. */
X  static int nuid = 0, ngid = 0;/* The number of user & group ids. */
X  static int cuid = 0, cgid = 0;/* The current id index. */
X
X  /* If we don't have any uids go read some from the passwd file. */
X  if (nuid == 0) {
X	a_uid[nuid++] = 0;	/* Root uid and gid. */
X	a_gid[ngid++] = 0;
X	if ((fp = fopen(PASSWD_FILE, "r")) == NULL) {
X		printf("Can't open ");
X		perror(PASSWD_FILE);
X	}
X	while (fp != NULL && fgets(line, sizeof(line), fp) != NULL) {
X		p = strchr(line, ':');
X		if (p != NULL) p = strchr(p + 1, ':');
X		if (p != NULL) {
X			p++;
X			uid = 0;
X			while (isdigit(*p)) {
X				uid *= 10;
X				uid += (uid_t) (*p - '0');
X				p++;
X			}
X			if (*p != ':') continue;
X			p++;
X			gid = 0;
X			while (isdigit(*p)) {
X				gid *= 10;
X				gid += (gid_t) (*p - '0');
X				p++;
X			}
X			if (*p != ':') continue;
X			if (nuid < N) {
X				for (i = 0; i < nuid; i++)
X					if (a_uid[i] == uid) break;
X				if (i == nuid) a_uid[nuid++] = uid;
X			}
X			if (ngid < N) {
X				for (i = 0; i < ngid; i++)
X					if (a_gid[i] == gid) break;
X				if (i == ngid) a_gid[ngid++] = gid;
X			}
X			if (nuid >= N && ngid >= N) break;
X		}
X	}
X	if (fp != NULL) fclose(fp);
X  }
X
X  /* We now have uids and gids in a_uid and a_gid. */
X  if (cuid >= nuid) cuid = 0;
X  if (cgid >= ngid) cgid = 0;
X  *r_uid = a_uid[cuid++];
X  *r_gid = a_gid[cgid++];
X}
/
echo x - test36.c
sed '/^X/s///' > test36.c << '/'
X/* test36: pathconf() fpathconf()	Author: Jan-mark Wams */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS     10
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)	if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test36a, (void));
X_PROTOTYPE(void test36b, (void));
X_PROTOTYPE(void test36c, (void));
X_PROTOTYPE(void test36d, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X_PROTOTYPE(int not_provided_option, (int _option));
X_PROTOTYPE(int provided_option, (int _option, int _minimum_value));
X_PROTOTYPE(int variating_option, (int _option, int _minimum_value));
X
X
Xchar *testdirs[] = {
X	    "/",
X	    "/etc",
X	    "/tmp",
X	    "/usr",
X	    "/usr/bin",
X	    ".",
X	    NULL
X};
X
Xchar *testfiles[] = {
X	     "/",
X	     "/etc",
X	     "/etc/passwd",
X	     "/tmp",
X	     "/dev/tty",
X	     "/usr",
X	     "/usr/bin",
X	     ".",
X	     NULL
X};
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 36 ");
X  fflush(stdout);
X  System("rm -rf DIR_36; mkdir DIR_36");
X  Chdir("DIR_36");
X  makelongnames();
X  superuser = (geteuid() == 0);
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test36a();
X	if (m & 0002) test36b();
X	if (m & 0004) test36c();
X	if (m & 0010) test36d();
X  }
X  quit();
X}
X
Xvoid test36a()
X{				/* Test normal operation. */
X  subtest = 1;
X  System("/bin/rm -rf ../DIR_36/*");
X
X#ifdef _POSIX_CHOWN_RESTRICTED
X# if _POSIX_CHOWN_RESTRICTED - 0 == -1
X  if (not_provided_option(_PC_CHOWN_RESTRICTED) != 0) e(1);
X# else
X  if (provided_option(_PC_CHOWN_RESTRICTED, 0) != 0) e(2);
X# endif
X#else
X  if (variating_option(_PC_CHOWN_RESTRICTED, 0) != 0) e(3);
X#endif
X
X#ifdef _POSIX_NO_TRUNC
X# if _POSIX_NO_TRUNC - 0 == -1
X  if (not_provided_option(_PC_NO_TRUNC) != 0) e(4);
X# else
X  if (provided_option(_PC_NO_TRUNC, 0) != 0) e(5);
X# endif
X#else
X  if (variating_option(_PC_NO_TRUNC, 0) != 0) e(6);
X#endif
X
X#ifdef _POSIX_VDISABLE
X# if _POSIX_VDISABLE - 0 == -1
X  if (not_provided_option(_PC_VDISABLE) != 0) e(7);
X# else
X  if (provided_option(_PC_VDISABLE, 0) != 0) e(8);
X# endif
X#else
X  if (variating_option(_PC_VDISABLE, 0) != 0) e(9);
X#endif
X
X}
X
Xvoid test36b()
X{
X  subtest = 2;
X  System("/bin/rm -rf ../DIR_36/*");
X}
X
Xvoid test36c()
X{
X  subtest = 3;
X  System("/bin/rm -rf ../DIR_36/*");
X}
X
Xvoid test36d()
X{
X  subtest = 4;
X  System("/bin/rm -rf ../DIR_36/*");
X}
X
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_36");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
X
Xint not_provided_option(option)
Xint option;
X{
X  char **p;
X
X  for (p = testfiles; *p != (char *) NULL; p++) {
X	if (pathconf(*p, option) != -1) return printf("*p == %s\n", *p), 1;
X  }
X  return 0;
X}
X
X
Xint provided_option(option, minimum)
Xint option, minimum;
X{
X  char **p;
X
X  /* These three options are only defined on directorys. */
X  if (option == _PC_NO_TRUNC
X      || option == _PC_NAME_MAX
X      || option == _PC_PATH_MAX)
X	p = testdirs;
X  else
X	p = testfiles;
X
X  for (; *p != NULL; p++) {
X	if (pathconf(*p, option) < minimum)
X		return printf("*p == %s\n", *p), 1;
X  }
X  return 0;
X}
X
X
Xint variating_option(option, minimum)
Xint option, minimum;
X{
X  char **p;
X
X  /* These three options are only defined on directorys. */
X  if (option == _PC_NO_TRUNC
X      || option == _PC_NAME_MAX
X      || option == _PC_PATH_MAX)
X	p = testdirs;
X  else
X	p = testfiles;
X
X  for (; *p != NULL; p++) {
X	if (pathconf(*p, option) < minimum)
X		return printf("*p == %s\n", *p), 1;
X  }
X  return 0;
X}
/
echo x - test37.c
sed '/^X/s///' > test37.c << '/'
X/* test37: pipe()		Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS     60
X
X#define Fstat(a,b)	if (fstat(a,b) != 0) printf("Can't fstat %d\n", a)
X#define Time(t)		if (time(t) == (time_t)-1) printf("Time error\n")
X
Xint errct = 0;
Xint subtest = 1;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test37a, (void));
X_PROTOTYPE(void test37b, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 37 ");
X  fflush(stdout);
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test37a();
X	if (m & 0002) test37b();
X  }
X  quit();
X}
X
Xvoid test37a()
X{				/* Test fcntl flags. */
X  int tube[2], t1[2], t2[2], t3[2];
X  time_t time1, time2;
X  char buf[128];
X  struct stat st1, st2;
X  int stat_loc, flags;
X
X  subtest = 1;
X
X  /* Check if lowest fds are returned. */
X  if (pipe(tube) != 0) e(1);
X  if (tube[0] != 3 && tube[1] != 3) e(2);
X  if (tube[1] != 4 && tube[0] != 4) e(3);
X  if (tube[1] == tube[0]) e(4);
X  if (pipe(t1) != 0) e(5);
X  if (t1[0] != 5 && t1[1] != 5) e(6);
X  if (t1[1] != 6 && t1[0] != 6) e(7);
X  if (t1[1] == t1[0]) e(8);
X  if (close(t1[0]) != 0) e(9);
X  if (close(tube[0]) != 0) e(10);
X  if (pipe(t2) != 0) e(11);
X  if (t2[0] != tube[0] && t2[1] != tube[0]) e(12);
X  if (t2[1] != t1[0] && t2[0] != t1[0]) e(13);
X  if (t2[1] == t2[0]) e(14);
X  if (pipe(t3) != 0) e(15);
X  if (t3[0] != 7 && t3[1] != 7) e(16);
X  if (t3[1] != 8 && t3[0] != 8) e(17);
X  if (t3[1] == t3[0]) e(18);
X  if (close(tube[1]) != 0) e(19);
X  if (close(t1[1]) != 0) e(20);
X  if (close(t2[0]) != 0) e(21);
X  if (close(t2[1]) != 0) e(22);
X  if (close(t3[0]) != 0) e(23);
X  if (close(t3[1]) != 0) e(24);
X
X  /* All time fields should be marked for update. */
X  Time(&time1);
X  if (pipe(tube) != 0) e(25);
X  Fstat(tube[0], &st1);
X  Fstat(tube[1], &st2);
X  Time(&time2);
X  if (st1.st_atime < time1) e(26);
X  if (st1.st_ctime < time1) e(27);
X  if (st1.st_mtime < time1) e(28);
X  if (st1.st_atime > time2) e(29);
X  if (st1.st_ctime > time2) e(30);
X  if (st1.st_mtime > time2) e(31);
X  if (st2.st_atime < time1) e(32);
X  if (st2.st_ctime < time1) e(33);
X  if (st2.st_mtime < time1) e(34);
X  if (st2.st_atime > time2) e(35);
X  if (st2.st_ctime > time2) e(36);
X  if (st2.st_mtime > time2) e(37);
X
X  /* Check the file characteristics. */
X  if ((flags = fcntl(tube[0], F_GETFD)) != 0) e(38);
X  if ((flags & FD_CLOEXEC) != 0) e(39);
X  if ((flags = fcntl(tube[0], F_GETFL)) != 0) e(40);
X  if ((flags & O_RDONLY) != O_RDONLY) e(41);
X  if ((flags & O_NONBLOCK) != 0) e(42);
X  if ((flags & O_RDWR) != 0) e(43);
X  if ((flags & O_WRONLY) != 0) e(44);
X
X  if ((flags = fcntl(tube[1], F_GETFD)) != 0) e(45);
X  if ((flags & FD_CLOEXEC) != 0) e(46);
X  if ((flags = fcntl(tube[1], F_GETFL)) == -1) e(47);
X  if ((flags & O_WRONLY) != O_WRONLY) e(48);
X  if ((flags & O_NONBLOCK) != 0) e(49);
X  if ((flags & O_RDWR) != 0) e(50);
X  if ((flags & O_RDONLY) != 0) e(51);
X
X  /* Check if we can read and write. */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	if (close(tube[0]) != 0) e(52);
X	if (write(tube[1], "Hello", 6) != 6) e(53);
X	if (close(tube[1]) != 0) e(54);
X	exit(0);
X      default:
X	if (read(tube[0], buf, sizeof(buf)) != 6) e(55);
X	if (strncmp(buf, "Hello", 6) != 0) e(56);
X	wait(&stat_loc);
X	if (stat_loc != 0) e(57);	/* Alarm? */
X  }
X  if (close(tube[0]) != 0) e(58);
X  if (close(tube[1]) != 0) e(59);
X}
X
X
Xvoid test37b()
X{
X  int tube[2], child2parent[2], parent2child[2];
X  int i, nchild = 0, nopen = 3, stat_loc;
X  int fd;
X  int forkretry = 30;		/* Number of times we retray to fork. */
X  char c;
X
X  subtest = 2;
X
X  /* Take all the pipes we can get. */
X  while (nopen < OPEN_MAX - 2) {
X	if (pipe(tube) != 0) {
X		/* We have not reached OPEN_MAX yet, so we have ENFILE. */
X		if (errno != ENFILE) e(1);
X		sleep(2);	/* Wait for others to (maybe) closefiles. */
X		break;
X	}
X	nopen += 2;
X  }
X
X  if (nopen < OPEN_MAX - 2) {
X	if (pipe(tube) != -1) e(2);
X	switch (errno) {
X	    case EMFILE:	/* Errno value is ok. */
X		break;
X	    case ENFILE:	/* No process can open files any more. */
X		switch (fork()) {
X		    case -1:
X			printf("Can't fork\n");
X			break;
X		    case 0:
X			alarm(20);
X			if (open("/", O_RDONLY) != -1) e(3);
X			if (errno != ENFILE) e(4);
X			exit(0);
X		    default:
X			wait(&stat_loc);
X			if (stat_loc != 0) e(5);	/* Alarm? */
X		}
X		break;
X	    default:		/* Wrong value for errno. */
X		e(6);
X	}
X  }
X
X  /* Close all but stdin,out,err. */
X  for (i = 3; i < OPEN_MAX; i++) (void) close(i);
X
X  /* ENFILE test. Have children each grab OPEN_MAX fds. */
X  if (pipe(child2parent) != 0) e(7);
X  if (pipe(parent2child) != 0) e(8);
X  while (forkretry > 0 && (fd = open("/", O_RDONLY)) != -1) {
X	close(fd);
X	switch (fork()) {
X	    case -1:
X		sleep(1);
X		forkretry--;
X		break;
X	    case 0:
X		alarm(60);
X
X		/* Grab all the fds. */
X		while (pipe(tube) != -1);
X		while (open("/", O_RDONLY) != -1);
X
X		/* Signal parent OPEN_MAX fds gone. */
X		if (write(child2parent[1], "*", 1) != 1) e(9);
X
X		/* Wait for parent befor freeing all the fds. */
X		if (read(parent2child[0], &c, 1) != 1) e(10);
X		exit(0);
X	    default:
X
X		/* Wait for child to grab OPEN_MAX fds. */
X		if (read(child2parent[0], &c, 1) != 1) e(11);
X		nchild++;
X		break;
X	}
X  }
X
X  if (forkretry > 0) {
X	if (pipe(tube) != -1) e(12);
X	if (errno != ENFILE) e(13);
X  }
X
X  /* Signal children to die and wait for it. */
X  while (nchild-- > 0) {
X	if (write(parent2child[1], "*", 1) != 1) e(14);
X	wait(&stat_loc);
X	if (stat_loc != 0) e(15);	/* Alarm? */
X  }
X
X  /* Close all but stdin,out,err. */
X  for (i = 3; i < OPEN_MAX; i++) (void) close(i);
X}
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test38.c
sed '/^X/s///' > test38.c << '/'
X/* test38: dup() dup2()		Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X/* The definition of ``dup2()'' is realy a big mess! For:
X**
X** (1) if fildes2 is less than zero or greater than {OPEN_MAX}
X**     errno has to set to [EBADF]. But if fildes2 equals {OPEN_MAX}
X**     errno has to be set to [EINVAL]. And ``fcntl(F_DUPFD...)'' always
X**     returns [EINVAL] if fildes2 is out of range!
X**
X** (2) if the number of file descriptors would exceed {OPEN_MAX}, or no
X**     file descriptors above fildes2 are available, errno has to be set
X**     to [EMFILE]. But this can never occur!
X*/
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS     10
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)	if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X
X#define IS_CLOEXEC(fd)	((fcntl(fd, F_GETFD) & FD_CLOEXEC) == FD_CLOEXEC)
X#define SET_CLOEXEC(fd)	fcntl(fd, F_SETFD, FD_CLOEXEC)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test38a, (void));
X_PROTOTYPE(void test38b, (void));
X_PROTOTYPE(void test38c, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 38 ");
X  fflush(stdout);
X  System("rm -rf DIR_38; mkdir DIR_38");
X  Chdir("DIR_38");
X  superuser = (geteuid() == 0);
X
X  for (i = 0; i < ITERATIONS; i++) {
X	if (m & 0001) test38a();
X	if (m & 0002) test38b();
X	if (m & 0004) test38c();
X  }
X  quit();
X}
X
Xvoid test38a()
X{
X  int fd1, fd2, fd3, fd4, fd5;
X  struct flock flock;
X
X  subtest = 1;
X
X  /* Basic checking. */
X  if ((fd1 = dup(0)) != 3) e(1);
X  if ((fd2 = dup(0)) != 4) e(2);
X  if ((fd3 = dup(0)) != 5) e(3);
X  if ((fd4 = dup(0)) != 6) e(4);
X  if ((fd5 = dup(0)) != 7) e(5);
X  if (close(fd2) != 0) e(6);
X  if (close(fd4) != 0) e(7);
X  if ((fd2 = dup(0)) != 4) e(8);
X  if ((fd4 = dup(0)) != 6) e(9);
X  if (close(fd1) != 0) e(10);
X  if (close(fd3) != 0) e(11);
X  if (close(fd5) != 0) e(12);
X  if ((fd1 = dup(0)) != 3) e(13);
X  if ((fd3 = dup(0)) != 5) e(14);
X  if ((fd5 = dup(0)) != 7) e(15);
X  if (close(fd1) != 0) e(16);
X  if (close(fd2) != 0) e(17);
X  if (close(fd3) != 0) e(18);
X  if (close(fd4) != 0) e(19);
X  if (close(fd5) != 0) e(20);
X
X  /* FD_CLOEXEC should be cleared. */
X  if ((fd1 = dup(0)) != 3) e(21);
X  if (SET_CLOEXEC(fd1) == -1) e(22);
X  if (!IS_CLOEXEC(fd1)) e(23);
X  if ((fd2 = dup(fd1)) != 4) e(24);
X  if ((fd3 = dup(fd2)) != 5) e(25);
X  if (IS_CLOEXEC(fd2)) e(26);
X  if (IS_CLOEXEC(fd3)) e(27);
X  if (SET_CLOEXEC(fd2) == -1) e(28);
X  if (!IS_CLOEXEC(fd2)) e(29);
X  if (IS_CLOEXEC(fd3)) e(30);
X  if (close(fd1) != 0) e(31);
X  if (close(fd2) != 0) e(32);
X  if (close(fd3) != 0) e(33);
X
X  /* Locks should be shared, so we can lock again. */
X  System("echo 'Hallo' > file");
X  if ((fd1 = open("file", O_RDWR)) != 3) e(34);
X  flock.l_whence = SEEK_SET;
X  flock.l_start = 0;
X  flock.l_len = 10;
X  flock.l_type = F_WRLCK;
X  if (fcntl(fd1, F_SETLK, &flock) == -1) e(35);
X  if (fcntl(fd1, F_SETLK, &flock) == -1) e(36);
X  if ((fd2 = dup(fd1)) != 4) e(37);
X  if (fcntl(fd1, F_SETLK, &flock) == -1) e(38);
X  if (fcntl(fd1, F_GETLK, &flock) == -1) e(39);
X  if (flock.l_type != F_WRLCK) e(40);
X  if (flock.l_pid != getpid()) e(41);
X  if (fcntl(fd2, F_GETLK, &flock) == -1) e(42);
X  if (flock.l_type != F_WRLCK) e(43);
X  if (flock.l_pid != getpid()) e(44);
X  if (close(fd1) != 0) e(45);
X  if (close(fd2) != 0) e(46);
X
X  System("/bin/rm -rf ../DIR_38/*");
X}
X
Xvoid test38b()
X{
X  int fd;
X  char buf[32];
X
X  subtest = 2;
X
X  /* Test file called ``file''. */
X  System("echo 'Hallo!' > file");
X
X  /* Check dup2() call with the same fds. Should have no effect. */
X  if ((fd = open("file", O_RDONLY)) != 3) e(1);
X  if (read(fd, buf, 2) != 2) e(2);
X  if (strncmp(buf, "Ha", 2) != 0) e(3);
X  if (dup2(fd, fd) != fd) e(4);
X  if (read(fd, buf, 2) != 2) e(5);
X  if (strncmp(buf, "ll", 2) != 0) e(6);
X  if (dup2(fd, fd) != fd) e(7);
X  if (read(fd, buf, 2) != 2) e(8);
X  if (strncmp(buf, "o!", 2) != 0) e(9);
X  if (close(fd) != 0) e(10);
X
X  /* If dup2() call fails, the fildes2 argument has to stay open. */
X  if ((fd = open("file", O_RDONLY)) != 3) e(11);
X  if (read(fd, buf, 2) != 2) e(12);
X  if (strncmp(buf, "Ha", 2) != 0) e(13);
X  if (dup2(OPEN_MAX + 3, fd) != -1) e(14);
X  if (errno != EBADF) e(15);
X  if (read(fd, buf, 2) != 2) e(16);
X  if (strncmp(buf, "ll", 2) != 0) e(17);
X  if (dup2(-4, fd) != -1) e(18);
X  if (errno != EBADF) e(19);
X  if (read(fd, buf, 2) != 2) e(20);
X  if (strncmp(buf, "o!", 2) != 0) e(21);
X  if (close(fd) != 0) e(22);
X
X
X  System("/bin/rm -rf ../DIR_38/*");
X}
X
Xvoid test38c()
X{
X  int i;
X
X  subtest = 3;
X
X  /* Check bad arguments to dup() and dup2(). */
X  for (i = -OPEN_MAX; i < OPEN_MAX * 2; i++) {
X
X	/* ``i'' is a valid and open fd. */
X	if (i >= 0 && i < 3) continue;
X
X	/* If ``i'' is a valid fd it is not open. */
X	if (dup(i) != -1) e(1);
X	if (errno != EBADF) e(2);
X
X	/* ``i'' Is OPEN_MAX. */
X	if (i == OPEN_MAX) {
X		if (dup2(0, i) != -1) e(3);
X		if (errno != EINVAL) e(4);
X	}
X
X	/* ``i'' Is out of range. */
X	if (i < 0 || i > OPEN_MAX) {
X		if (dup2(0, i) != -1) e(5);
X		if (errno != EBADF) e(6);
X	}
X  }
X
X  System("/bin/rm -rf ../DIR_38/*");
X}
X
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_38");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test39.c
sed '/^X/s///' > test39.c << '/'
X/* test39: fcntl()		Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X/* Some things have to be checked for ``exec()'' call's. Therefor
X** there is a check routine called ``do_check()'' that will be
X** called if the first argument (``argv[0]'') equals ``DO CHECK.''
X** Note that there is no way the shell (``/bin/sh'') will set
X** ``argv[0]'' to this funny value. (Unless we rename ``test39''
X** to ``DO CHECK'' ;-)
X*/
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS     10
X
X#define System(cmd)	if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)	if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)	if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X
Xint errct = 0;
Xint subtest = 1;
Xint superuser;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test39a, (void));
X_PROTOTYPE(void test39b, (void));
X_PROTOTYPE(void test39c, (void));
X_PROTOTYPE(void test39d, (void));
X_PROTOTYPE(int do_check, (void));
X_PROTOTYPE(void makelongnames, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xchar executable[1024];
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X
X  /* If we have to check things, call do_check(). */
X  if (strcmp(argv[0], "DO CHECK") == 0) exit(do_check());
X
X  /* Get the path of the executable. */
X  strcpy(executable, "../");
X  strcat(executable, argv[0]);
X
X  printf("Test 39 ");
X  fflush(stdout);
X  System("rm -rf DIR_39; mkdir DIR_39");
X  Chdir("DIR_39");
X  makelongnames();
X  superuser = (geteuid() == 0);
X
X  for (i = 0; i < ITERATIONS; i++) {
X	test39a();
X	test39b();
X	test39c();
X	test39d();
X  }
X  quit();
X}
X
Xvoid test39a()
X{				/* Test normal operation. */
X  subtest = 1;
X  System("/bin/rm -rf ../DIR_39/*");
X}
X
Xvoid test39b()
X{
X  subtest = 2;
X  System("/bin/rm -rf ../DIR_39/*");
X}
X
Xvoid test39c()
X{
X  subtest = 3;
X  System("/bin/rm -rf ../DIR_39/*");
X}
X
X/* Open fds 3, 4, 5 and 6. Set FD_CLOEXEC on 5 and 6. Exclusively lock the
X** first 10 bytes of fd no. 3. Shared lock fd no. 7. Lock fd no. 8 after
X** the fork. Do a ``exec()'' call with a funny argv[0] and check the return
X** value.
X*/
Xvoid test39d()
X{				/* Test locks with ``fork()'' and ``exec().'' */
X  int fd3, fd4, fd5, fd6, fd7, fd8;
X  int stat_loc;
X  int do_check_retval;
X  char *argv[2];
X  struct flock fl;
X
X  subtest = 4;
X
X  argv[0] = "DO CHECK";
X  argv[1] = (char *) NULL;
X
X  fl.l_whence = SEEK_SET;
X  fl.l_start = 0;
X  fl.l_len = 10;
X
X  /* Make a dummy files and open them. */
X  System("echo 'Great Balls Of Fire!' > file3");
X  System("echo 'Great Balls Of Fire!' > file4");
X  System("echo 'Great Balls Of Fire!' > file7");
X  System("echo 'Great Balls Of Fire!' > file8");
X  System("echo 'Great Balls Of Fire!' > file");
X  if ((fd3 = open("file3", O_RDWR)) != 3) e(1);
X  if ((fd4 = open("file4", O_RDWR)) != 4) e(2);
X  if ((fd5 = open("file", O_RDWR)) != 5) e(3);
X  if ((fd6 = open("file", O_RDWR)) != 6) e(4);
X  if ((fd7 = open("file7", O_RDWR)) != 7) e(5);
X  if ((fd8 = open("file8", O_RDWR)) != 8) e(6);
X
X  /* Set FD_CLOEXEC flags on fd5 and fd6. */
X  if (fcntl(fd5, F_SETFD, FD_CLOEXEC) == -1) e(7);
X  if (fcntl(fd6, F_SETFD, FD_CLOEXEC) == -1) e(8);
X
X  /* Lock the first ten bytes from fd3 (for writing). */
X  fl.l_type = F_WRLCK;
X  if (fcntl(fd3, F_SETLK, &fl) == -1) e(9);
X
X  /* Lock (for reading) fd7. */
X  fl.l_type = F_RDLCK;
X  if (fcntl(fd7, F_SETLK, &fl) == -1) e(10);
X
X
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X
X	/* Lock fd8. */
X	fl.l_type = F_WRLCK;
X	if (fcntl(fd8, F_SETLK, &fl) == -1) e(11);
X
X	/* Check the lock on fd3 and fd7. */
X	fl.l_type = F_WRLCK;
X	if (fcntl(fd3, F_GETLK, &fl) == -1) e(12);
X	if (fl.l_type != F_WRLCK) e(13);
X	if (fl.l_pid != getppid()) e(14);
X	fl.l_type = F_WRLCK;
X	if (fcntl(fd7, F_GETLK, &fl) == -1) e(15);
X	if (fl.l_type != F_RDLCK) e(16);
X	if (fl.l_pid != getppid()) e(17);
X
X	/* Check FD_CLOEXEC flags. */
X	if ((fcntl(fd3, F_GETFD) & FD_CLOEXEC) != 0) e(18);
X	if ((fcntl(fd4, F_GETFD) & FD_CLOEXEC) != 0) e(19);
X	if ((fcntl(fd5, F_GETFD) & FD_CLOEXEC) != FD_CLOEXEC) e(20);
X	if ((fcntl(fd6, F_GETFD) & FD_CLOEXEC) != FD_CLOEXEC) e(21);
X	if ((fcntl(fd7, F_GETFD) & FD_CLOEXEC) != 0) e(22);
X	if ((fcntl(fd8, F_GETFD) & FD_CLOEXEC) != 0) e(23);
X
X	execlp(executable + 3, "DO CHECK", (char *) NULL);
X	execlp(executable, "DO CHECK", (char *) NULL);
X	printf("Can't exec %s or %s\n", executable + 3, executable);
X	exit(0);
X
X      default:
X	wait(&stat_loc);
X	if (WIFSIGNALED(stat_loc)) e(24);	/* Alarm? */
X	if (WIFEXITED(stat_loc) == 0) {
X		errct=10000;
X		quit();
X	}
X  }
X
X  /* Check the return value of do_check(). */
X  do_check_retval = WEXITSTATUS(stat_loc);
X  if ((do_check_retval & 0x11) == 0x11) e(25);
X  if ((do_check_retval & 0x12) == 0x12) e(26);
X  if ((do_check_retval & 0x14) == 0x14) e(27);
X  if ((do_check_retval & 0x18) == 0x18) e(28);
X  if ((do_check_retval & 0x21) == 0x21) e(29);
X  if ((do_check_retval & 0x22) == 0x22) e(30);
X  if ((do_check_retval & 0x24) == 0x24) e(31);
X  if ((do_check_retval & 0x28) == 0x28) e(32);
X  if ((do_check_retval & 0x41) == 0x41) e(33);
X  if ((do_check_retval & 0x42) == 0x42) e(34);
X  if ((do_check_retval & 0x44) == 0x44) e(35);
X  if ((do_check_retval & 0x48) == 0x48) e(36);
X  if ((do_check_retval & 0x81) == 0x81) e(37);
X  if ((do_check_retval & 0x82) == 0x82) e(38);
X  if ((do_check_retval & 0x84) == 0x84) e(39);
X  if ((do_check_retval & 0x88) == 0x88) e(40);
X
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X
X	/* Lock fd8. */
X	fl.l_type = F_WRLCK;
X	if (fcntl(fd8, F_SETLK, &fl) == -1) e(41);
X
X	execvp(executable + 3, argv);
X	execvp(executable, argv);
X	printf("Can't exec %s or %s\n", executable + 3, executable);
X	exit(0);
X
X      default:
X	wait(&stat_loc);
X	if (WIFSIGNALED(stat_loc)) e(48);	/* Alarm? */
X  }
X
X  /* Check the return value of do_check(). */
X  do_check_retval = WEXITSTATUS(stat_loc);
X  if ((do_check_retval & 0x11) == 0x11) e(49);
X  if ((do_check_retval & 0x12) == 0x12) e(50);
X  if ((do_check_retval & 0x14) == 0x14) e(51);
X  if ((do_check_retval & 0x18) == 0x18) e(52);
X  if ((do_check_retval & 0x21) == 0x21) e(53);
X  if ((do_check_retval & 0x22) == 0x22) e(54);
X  if ((do_check_retval & 0x24) == 0x24) e(55);
X  if ((do_check_retval & 0x28) == 0x28) e(56);
X  if ((do_check_retval & 0x41) == 0x41) e(57);
X  if ((do_check_retval & 0x42) == 0x42) e(58);
X  if ((do_check_retval & 0x44) == 0x44) e(59);
X  if ((do_check_retval & 0x48) == 0x48) e(60);
X  if ((do_check_retval & 0x81) == 0x81) e(61);
X  if ((do_check_retval & 0x82) == 0x82) e(62);
X  if ((do_check_retval & 0x84) == 0x84) e(63);
X  if ((do_check_retval & 0x88) == 0x88) e(64);
X
X  fl.l_type = F_UNLCK;
X  if (fcntl(fd3, F_SETLK, &fl) == -1) e(65);
X  if (fcntl(fd7, F_SETLK, &fl) == -1) e(66);
X
X  if (close(fd3) != 0) e(67);
X  if (close(fd4) != 0) e(68);
X  if (close(fd5) != 0) e(69);
X  if (close(fd6) != 0) e(70);
X  if (close(fd7) != 0) e(71);
X  if (close(fd8) != 0) e(72);
X
X  System("rm -f ../DIR_39/*\n");
X}
X
X
X/* This routine checks that fds 0 through 4, 7 and 8 are open and the rest
X** is closed. It also checks if we can lock the first 10 bytes on fd no. 3
X** and 4. It should not be possible to lock fd no. 3, but it should be
X** possible to lock fd no. 4. See ``test39d()'' for usage of this routine.
X*/
Xint do_check()
X{
X  int i;
X  int retval = 0;
X  struct flock fl;
X
X  fl.l_whence = SEEK_SET;
X  fl.l_start = 0;
X  fl.l_len = 10;
X
X  /* All std.. are open. */
X  if (fcntl(0, F_GETFD) == -1) retval |= 0x11;
X  if (fcntl(1, F_GETFD) == -1) retval |= 0x11;
X  if (fcntl(2, F_GETFD) == -1) retval |= 0x11;
X
X  /* Fd no. 3, 4, 7 and 8 are open. */
X  if (fcntl(3, F_GETFD) == -1) retval |= 0x12;
X  if (fcntl(4, F_GETFD) == -1) retval |= 0x12;
X  if (fcntl(7, F_GETFD) == -1) retval |= 0x12;
X
X  /* Fd no. 5, 6 and 9 trough OPEN_MAX are closed. */
X  if (fcntl(5, F_GETFD) != -1) retval |= 0x14;
X  if (fcntl(6, F_GETFD) != -1) retval |= 0x14;
X  for (i = 9; i < OPEN_MAX; i++)
X	if (fcntl(i, F_GETFD) != -1) retval |= 0x18;
X
X#if 0
X  /* Fd no. 3 is WRLCKed. */
X  fl.l_type = F_WRLCK;
X  if (fcntl(3, F_SETLK, &fl) != -1) retval |= 0x21;
X  if (errno != EACCES && errno != EAGAIN) retval |= 0x22;
X  fl.l_type = F_RDLCK;
X  if (fcntl(3, F_SETLK, &fl) != -1) retval |= 0x24;
X  if (errno != EACCES && errno != EAGAIN) retval |= 0x22;
X  fl.l_type = F_RDLCK;
X  if (fcntl(3, F_GETLK, &fl) == -1) retval |= 0x28;
X  if (fl.l_type != F_WRLCK) retval |= 0x28;
X  if (fl.l_pid != getpid()) retval |= 0x28;
X  fl.l_type = F_WRLCK;
X  if (fcntl(3, F_GETLK, &fl) == -1) retval |= 0x28;
X  if (fl.l_type != F_WRLCK) retval |= 0x28;
X  if (fl.l_pid != getpid()) retval |= 0x28;
X#endif
X
X  /* Fd no. 4 is not locked. */
X  fl.l_type = F_WRLCK;
X  if (fcntl(4, F_SETLK, &fl) == -1) retval |= 0x41;
X  if (fcntl(4, F_GETLK, &fl) == -1) retval |= 0x42;
X  if (fl.l_type != F_WRLCK) retval |= 0x42;
X  if (fl.l_pid != getpid()) retval |= 0x42;
X
X  /* Fd no. 8 is locked after the fork, it is ours. */
X  fl.l_type = F_WRLCK;
X  if (fcntl(8, F_SETLK, &fl) == -1) retval |= 0x44;
X  if (fcntl(8, F_GETLK, &fl) == -1) retval |= 0x48;
X  if (fl.l_type != F_WRLCK) retval |= 0x48;
X  if (fl.l_pid != getpid()) retval |= 0x48;
X
X#if 0
X  /* Fd no. 7 is RDLCKed. */
X  fl.l_type = F_WRLCK;
X  if (fcntl(7, F_SETLK, &fl) != -1) retval |= 0x81;
X  if (errno != EACCES && errno != EAGAIN) retval |= 0x82;
X  fl.l_type = F_RDLCK;
X  if (fcntl(7, F_SETLK, &fl) == -1) retval |= 0x84;
X  fl.l_type = F_RDLCK;
X  if (fcntl(7, F_GETLK, &fl) == -1) retval |= 0x88;
X  if (fl.l_type != F_UNLCK) retval |= 0x88;
X  fl.l_type = F_WRLCK;
X  if (fcntl(7, F_GETLK, &fl) == -1) retval |= 0x88;
X  if (fl.l_type != F_RDLCK) retval |= 0x88;
X  if (fl.l_pid != getppid()) retval |= 0x88;
X#endif
X
X  return retval;
X}
X
Xvoid makelongnames()
X{
X  register int i;
X
X  memset(MaxName, 'a', NAME_MAX);
X  MaxName[NAME_MAX] = '\0';
X  for (i = 0; i < PATH_MAX - 1; i++) {	/* idem path */
X	MaxPath[i++] = '.';
X	MaxPath[i] = '/';
X  }
X  MaxPath[PATH_MAX - 1] = '\0';
X
X  strcpy(ToLongName, MaxName);	/* copy them Max to ToLong */
X  strcpy(ToLongPath, MaxPath);
X
X  ToLongName[NAME_MAX] = 'a';
X  ToLongName[NAME_MAX + 1] = '\0';	/* extend ToLongName by one too many */
X  ToLongPath[PATH_MAX - 1] = '/';
X  ToLongPath[PATH_MAX] = '\0';	/* inc ToLongPath by one */
X}
X
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_39");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else if (errct < 10000) {
X	printf("%d errors\n", errct);
X	exit(1);
X  } else {
X	printf("errors\n");
X	exit(2);
X  }
X}
/
echo x - test40.c
sed '/^X/s///' > test40.c << '/'
X/* test40: lseek()		Author: Jan-Mark Wams (jms@cs.vu.nl) */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <string.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <errno.h>
X#include <time.h>
X#include <stdio.h>
X
X#define MAX_ERROR	4
X#define ITERATIONS     10
X
X#define System(cmd)   if (system(cmd) != 0) printf("``%s'' failed\n", cmd)
X#define Chdir(dir)    if (chdir(dir) != 0) printf("Can't goto %s\n", dir)
X#define Stat(a,b)     if (stat(a,b) != 0) printf("Can't stat %s\n", a)
X#define Mkfifo(f)     if (mkfifo(f,0777)!=0) printf("Can't make fifo %s\n", f)
X
Xint errct = 0;
Xint subtest = 1;
Xchar MaxName[NAME_MAX + 1];	/* Name of maximum length */
Xchar MaxPath[PATH_MAX];		/* Same for path */
Xchar ToLongName[NAME_MAX + 2];	/* Name of maximum +1 length */
Xchar ToLongPath[PATH_MAX + 1];	/* Same for path, both too long */
X
X_PROTOTYPE(void main, (int argc, char *argv[]));
X_PROTOTYPE(void test40a, (void));
X_PROTOTYPE(void test40b, (void));
X_PROTOTYPE(void test40c, (void));
X_PROTOTYPE(void e, (int number));
X_PROTOTYPE(void quit, (void));
X
Xvoid main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int i, m = 0xFFFF;
X
X  sync();
X  if (argc == 2) m = atoi(argv[1]);
X  printf("Test 40 ");
X  fflush(stdout);
X  System("rm -rf DIR_40; mkdir DIR_40");
X  Chdir("DIR_40");
X
X  for (i = 0; i < 10; i++) {
X	if (m & 0001) test40a();
X	if (m & 0002) test40b();
X	if (m & 0004) test40c();
X  }
X  quit();
X}
X
Xvoid test40a()
X{				/* Test normal operation. */
X  int fd;
X  char buf[20];
X  int i, j;
X  struct stat st;
X
X  subtest = 1;
X  System("/bin/rm -rf ../DIR_40/*");
X
X
X  System("echo -n hihaho > hihaho");
X  if ((fd = open("hihaho", O_RDONLY)) != 3) e(1);
X  if (lseek(fd, (off_t) 3, SEEK_SET) != (off_t) 3) e(2);
X  if (read(fd, buf, 1) != 1) e(3);
X  if (buf[0] != 'a') e(4);
X  if (lseek(fd, (off_t) - 1, SEEK_END) != 5) e(5);
X  if (read(fd, buf, 1) != 1) e(6);
X  if (buf[0] != 'o') e(7);
X
X  /* Seek past end of file. */
X  if (lseek(fd, (off_t) 1000, SEEK_END) != 1006) e(8);
X  if (read(fd, buf, 1) != 0) e(9);
X
X  /* Lseek() should not extend the file. */
X  if (fstat(fd, &st) != 0) e(10);
X  if (st.st_size != (off_t) 6) e(11);
X  if (close(fd) != 0) e(12);
X
X  /* Probeer lseek met write. */
X  if ((fd = open("hihaho", O_WRONLY)) != 3) e(13);
X  if (lseek(fd, (off_t) 3, SEEK_SET) != (off_t) 3) e(14);
X  if (write(fd, "e", 1) != 1) e(15);
X  if (lseek(fd, (off_t) 1000, SEEK_END) != 1006) e(16);
X
X  /* Lseek() should not extend the file. */
X  if (fstat(fd, &st) != 0) e(17);
X  if (st.st_size != (off_t) 6) e(18);
X  if (write(fd, "e", 1) != 1) e(19);
X
X  /* Lseek() and a subsequent write should! */
X  if (fstat(fd, &st) != 0) e(20);
X  if (st.st_size != (off_t) 1007) e(21);
X
X  if (close(fd) != 0) e(22);
X
X  /* Check the file, it should start with hiheho. */
X  if ((fd = open("hihaho", O_RDONLY)) != 3) e(23);
X  if (read(fd, buf, 6) != 6) e(24);
X  if (strncmp(buf, "hiheho", 6) != 0) e(25);
X
X  /* The should be zero bytes and a trailing ``e''. */
X  if (sizeof(buf) < 10) e(26);
X  for (i = 1; i <= 20; i++) {
X	if (read(fd, buf, 10) != 10) e(27);
X	for (j = 0; j < 10; j++)
X		if (buf[j] != '\0') break;
X	if (j != 10) e(28);
X	if (lseek(fd, (off_t) 15, SEEK_CUR) != (off_t) i * 25 + 6) e(29);
X  }
X
X  if (lseek(fd, (off_t) 1006, SEEK_SET) != (off_t) 1006) e(30);
X  if (read(fd, buf, sizeof(buf)) != 1) e(31);
X  if (buf[0] != 'e') e(32);
X
X  if (lseek(fd, (off_t) - 1, SEEK_END) != (off_t) 1006) e(33);
X  if (read(fd, buf, sizeof(buf)) != 1) e(34);
X  if (buf[0] != 'e') e(35);
X
X  /* Closing time. */
X  if (close(fd) != 0) e(36);
X}
X
Xvoid test40b()
X{
X  int fd1, fd2, fd3;
X  int stat_loc;
X
X  subtest = 2;
X  System("/bin/rm -rf ../DIR_40/*");
X
X  /* See if childs lseek() is effecting the parent. * See also if
X   * lseeking() on same file messes things up. */
X
X  /* Creat a file of 11 bytes. */
X  if ((fd1 = open("santa", O_WRONLY | O_CREAT, 0777)) != 3) e(1);
X  if (write(fd1, "ho ho ho ho", 11) != 11) e(2);
X  if (close(fd1) != 0) e(3);
X
X  /* Open it multiple times. */
X  if ((fd1 = open("santa", O_RDONLY)) != 3) e(4);
X  if ((fd2 = open("santa", O_WRONLY)) != 4) e(5);
X  if ((fd3 = open("santa", O_RDWR)) != 5) e(6);
X
X  /* Set all offsets different. */
X  if (lseek(fd1, (off_t) 2, SEEK_SET) != 2) e(7);
X  if (lseek(fd2, (off_t) 4, SEEK_SET) != 4) e(8);
X  if (lseek(fd3, (off_t) 7, SEEK_SET) != 7) e(9);
X
X  /* Have a child process do additional offset changes. */
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(20);
X	if (lseek(fd1, (off_t) 1, SEEK_CUR) != 3) e(10);
X	if (lseek(fd2, (off_t) 5, SEEK_SET) != 5) e(11);
X	if (lseek(fd3, (off_t) - 4, SEEK_END) != 7) e(12);
X	exit(0);
X      default:
X	wait(&stat_loc);
X	if (stat_loc != 0) e(13);	/* Alarm? */
X  }
X
X  /* Check if the new offsets are correct. */
X  if (lseek(fd1, (off_t) 0, SEEK_CUR) != 3) e(14);
X  if (lseek(fd2, (off_t) 0, SEEK_CUR) != 5) e(15);
X  if (lseek(fd3, (off_t) 0, SEEK_CUR) != 7) e(16);
X
X  /* Close the file. */
X  if (close(fd1) != 0) e(17);
X  if (close(fd2) != 0) e(18);
X  if (close(fd3) != 0) e(19);
X}
X
Xvoid test40c()
X{				/* Test error returns. */
X  int fd;
X  int tube[2];
X  int i, stat_loc;
X
X  subtest = 3;
X  System("/bin/rm -rf ../DIR_40/*");
X
X  /* Fifo's can't be lseeked(). */
X  Mkfifo("fifo");
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(3);		/* Try for max 3 secs. */
X	if ((fd = open("fifo", O_RDONLY)) != 3) e(1);
X	if (lseek(fd, (off_t) 0, SEEK_SET) != (off_t) - 1) e(2);
X	if (errno != ESPIPE) e(3);
X	if (close(fd) != 0) e(4);
X	exit(0);
X      default:
X	if ((fd = open("fifo", O_WRONLY)) != 3) e(5);
X	wait(&stat_loc);
X	if (stat_loc != 0) e(6);/* Alarm? */
X	if (close(fd) != 0) e(7);
X  }
X
X  /* Pipes can't be lseeked() eigther. */
X  if (pipe(tube) != 0) e(8);
X  switch (fork()) {
X      case -1:	printf("Can't fork\n");	break;
X      case 0:
X	alarm(3);		/* Max 3 sconds wait. */
X	if (lseek(tube[0], (off_t) 0, SEEK_SET) != (off_t) - 1) e(9);
X	if (errno != ESPIPE) e(10);
X	if (lseek(tube[1], (off_t) 0, SEEK_SET) != (off_t) - 1) e(11);
X	if (errno != ESPIPE) e(12);
X	if (close(fd) != 0) e(13);
X	exit(0);
X      default:
X	wait(&stat_loc);
X	if (stat_loc != 0) e(14);	/* Alarm? */
X  }
X
X  /* Close the pipe. */
X  if (close(tube[0]) != 0) e(15);
X  if (close(tube[1]) != 0) e(16);
X
X  /* Whence arument invalid. */
X  System("echo -n contact > file");
X  if ((fd = open("file", O_RDWR)) != 3) e(17);
X  for (i = -1000; i < 1000; i++) {
X	if (i == SEEK_SET || i == SEEK_END || i == SEEK_CUR) continue;
X	if (lseek(fd, (off_t) 0, i) != (off_t) -1) e(18);
X	if (errno != EINVAL) e(19);
X  }
X  if (close(fd) != 0) e(20);
X
X  /* EBADF for bad fides. */
X  for (i = -1000; i < 1000; i++) {
X	if (i >= 0 && i < OPEN_MAX) continue;
X	if (lseek(i, (off_t) 0, SEEK_SET) != (off_t) - 1) e(21);
X	if (lseek(i, (off_t) 0, SEEK_END) != (off_t) - 1) e(22);
X	if (lseek(i, (off_t) 0, SEEK_CUR) != (off_t) - 1) e(23);
X  }
X}
X
X
Xvoid e(n)
Xint n;
X{
X  int err_num = errno;		/* Save in case printf clobbers it. */
X
X  printf("Subtest %d,  error %d  errno=%d: ", subtest, n, errno);
X  errno = err_num;
X  perror("");
X  if (errct++ > MAX_ERROR) {
X	printf("Too many errors; test aborted\n");
X	chdir("..");
X	system("rm -rf DIR*");
X	exit(1);
X  }
X  errno = 0;
X}
X
X
Xvoid quit()
X{
X  Chdir("..");
X  System("rm -rf DIR_40");
X
X  if (errct == 0) {
X	printf("ok\n");
X	exit(0);
X  } else {
X	printf("%d errors\n", errct);
X	exit(1);
X  }
X}
/
echo x - test.cd
sed '/^X/s///' > test.cd << '/'
Xecho x - Makefile.d
Xsed '/^X/s///' > Makefile.d << '/'
XX*** /home/top/ast/minix/1.5/test/Makefile  crc=47940   1703	Sat May  5 13:16:07 1990
XX--- /home/top/ast/minix/1.6.25/test/Makefile  crc=21803   1841	Wed Nov  4 07:59:09 1992
XX***************
XX*** 1,45 ****
XX! CFLAGS= -F -D_MINIX -D_POSIX_SOURCE
XX  
XX! $f:	$f.s
XX! 	@cc -o $f $f.s
XX! 	@chmem =8192 $f >/dev/null
XX  
XX! clean:	
XX! 	@rm -f *.s *.bak
XX  
XX! # The test11 file must be setuid root, which means
XX! # that you should be root when typing 'make all'.  Furthermore, cem needs
XX! # extra memory when compiling test17.c and test18.c.
XX! all:
XX! 	cc $(CFLAGS) -o test0 test0.c;		chmem =8192  test0
XX! 	cc $(CFLAGS) -o test1 test1.c;		chmem =8192  test1
XX! 	cc $(CFLAGS) -o test2 test2.c;		chmem =8192  test2
XX! 	cc $(CFLAGS) -o test3 test3.c;		chmem =8192  test3
XX! 	cc $(CFLAGS) -o test4 test4.c;		chmem =8192  test4
XX! 	cc $(CFLAGS) -o test5 test5.c;		chmem =8192  test5
XX! 	cc $(CFLAGS) -o test6 test6.c;		chmem =8192  test6
XX! 	cc $(CFLAGS) -o test7 test7.c;		chmem =8192  test7
XX! 	cc $(CFLAGS) -o test8 test8.c;		chmem =8192  test8
XX! 	cc $(CFLAGS) -o test9 test9.c;		chmem =8192  test9
XX! 	cc $(CFLAGS) -o test10 test10.c;	chmem =8192  test10
XX! 	cc $(CFLAGS) -o test11 test11.c;	chmem =8192  test11
XX! 	cc $(CFLAGS) -o test12 test12.c;	chmem =8192  test12
XX! 	cc $(CFLAGS) -o test13 test13.c;	chmem =8192  test13
XX! 	cc $(CFLAGS) -o test14 test14.c;	chmem =20000 test14
XX! 	cc $(CFLAGS) -o test15 test15.c;	chmem =8192  test15
XX! 	cc $(CFLAGS) -o test16 test16.c;	chmem =8192  test16
XX! 	cc $(CFLAGS) -o test17 test17.c;	chmem =8192  test17
XX! 	cc $(CFLAGS) -o test18 test18.c;	chmem =8192  test18
XX! 	cc $(CFLAGS) -o test19 test19.c;	chmem =8192  test19
XX! 	cc $(CFLAGS) -o test20 test20.c;	chmem =65000 test20
XX! 	cc $(CFLAGS) -o test21 test21.c;	chmem =8192  test21
XX! 	cc $(CFLAGS) -o t10a t10a.c;		chmem =8192  t10a
XX! 	cc $(CFLAGS) -o t11a t11a.c;		chmem =8192  t11a
XX! 	cc $(CFLAGS) -o t11b t11b.c;		chmem =8192  t11b
XX! 	rm -f *.bak *.s
XX  
XX! 	chown bin test*
XX! 	chown root test11
XX! 	chmod 4755 test11
XX! 	chmod 777 .
XX  
XX--- 1,85 ----
XX! CC = exec cc
XX! CFLAGS= -O -D_MINIX -D_POSIX_SOURCE -I/include
XX  
XX! OBJ=       test1  test2  test3  test4  test5  test6  test7  test8  test9  \
XX!     test10 test11 test12 test13 test14 test15 test16 test17 test18 test19 \
XX!     test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \
XX!     test30 test31 test32 test33 test34 test35 test36 test37 test38 test39 \
XX!     test40 t10a t11a t11b
XX  
XX! all: $(OBJ)
XX  
XX! $(OBJ):
XX! 	$(CC) $(CFLAGS) -o $@ $@.c
XX! 	@chmem =20000 $@ >/dev/null 2>&1
XX! 	@chown bin $@ >/dev/null 2>&1 || true
XX! 	@if test $@ = test11 || test $@ = test33;	\
XX! 	    then					\
XX! 		if test `whoami` = root;		\
XX! 		    then				\
XX! 		        chown root $@ >/dev/null 2>&1;	\
XX! 		        chmod 4755 $@;			\
XX! 	            else				\
XX! 		        echo Do not forget to give the following 2 commands as root; \
XX! 		        echo "	chown root $@";		\
XX! 		        echo "	chmod 4755 $@";		\
XX! 	        fi					\
XX! 	    else					\
XX! 		exit 0;					\
XX! 	fi
XX! 	@if test $@ = test20 || test $@ = test24;	\
XX! 	    then					\
XX! 		chmem =65000 $@ >/dev/null;		\
XX! 	    else					\
XX! 		exit 0;					\
XX! 	fi
XX  
XX! clean:	
XX! 	@rm -f *.o *.s *.bak 
XX  
XX+ veryclean:
XX+ 	@rm -f *.o *.s *.bak test? test?? t10a t11a t11b
XX+ 
XX+ test1:	test1.c
XX+ test2:	test2.c
XX+ test3:	test3.c
XX+ test4:	test4.c
XX+ test5:	test5.c
XX+ test6:	test6.c
XX+ test7:	test7.c
XX+ test8:	test8.c
XX+ test9:	test9.c
XX+ test10:	test10.c
XX+ t10a:	t10a.c
XX+ test11:	test11.c
XX+ t11a:	t11a.c
XX+ t11b:	t11b.c
XX+ test12:	test12.c
XX+ test13:	test13.c
XX+ test14:	test14.c
XX+ test15:	test15.c
XX+ test16:	test16.c
XX+ test17:	test17.c
XX+ test18:	test18.c
XX+ test19:	test19.c
XX+ test20:	test20.c
XX+ test21:	test21.c
XX+ test22:	test22.c
XX+ test23:	test23.c
XX+ test24:	test24.c
XX+ test25:	test25.c
XX+ test26:	test26.c
XX+ test27:	test27.c
XX+ test28:	test28.c
XX+ test29:	test29.c
XX+ test30:	test30.c
XX+ test31:	test31.c
XX+ test32:	test32.c
XX+ test33:	test33.c
XX+ test34:	test34.c
XX+ test35:	test35.c
XX+ test36:	test36.c
XX+ test37:	test37.c
XX+ test38:	test38.c
XX+ test39:	test39.c
XX+ test40:	test40.c
X/
Xecho x - run.d
Xsed '/^X/s///' > run.d << '/'
XX*** /home/top/ast/minix/1.5/test/run  crc=35365    225	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/run  crc=20245    902	Wed Nov  4 07:59:09 1992
XX***************
XX*** 1,26 ****
XX  PATH=:$PATH
XX! test0
XX! test1
XX! test2
XX! test3
XX! test4
XX! test5
XX! test6
XX! test7
XX! test8
XX! test9
XX! test10
XX! test11
XX! test12
XX! test13
XX! test14
XX! test15
XX! test16
XX! test17
XX! test18
XX! test19
XX! test20
XX! test21
XX! echo All system call tests completed.
XX! echo Try running sh1 and sh2.
XX  
XX--- 1,31 ----
XX+ # Initialization
XX  PATH=:$PATH
XX! rm -rf DIR*			# remove any old junk lying around
XX! passed=`expr 0`			# count number of tests run correctly
XX! failed=`expr 0`			# count number of tests that failed
XX! total=`expr 0`			# total number of tests tried
XX! badones=			# list of tests that failed
XX  
XX+ # Run all the tests, keeping track of who failed.
XX+ clr
XX+ for i in  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 \
XX+          21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
XX+ do total=`expr $total + 1`
XX+    if test$i
XX+       then passed=`expr $passed + 1`
XX+       else failed=`expr $failed + 1`
XX+            badones=`echo $badones " " $i`
XX+    fi
XX+ done
XX+ 
XX+ # Print results of the tests.
XX+ echo " "
XX+ if test $total = $passed
XX+    then echo All $passed tests completed without error.
XX+    else echo Testing completed.  Score:   $passed passed,  $failed failed
XX+         echo The following tests failed: $badones
XX+ fi
XX+ 
XX+ echo " "
XX+ sh1
XX+ sh2
X/
Xecho x - sh1.d
Xsed '/^X/s///' > sh1.d << '/'
XX*** /home/top/ast/minix/1.5/test/sh1  crc=21403   6782	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/sh1  crc=26217   6756	Wed Nov  4 07:59:09 1992
XX***************
XX*** 5,11 ****
XX  mkdir testdir
XX  cd testdir
XX  
XX! f=../test0.c
XX  if test -r $f; then : ; else echo sh1 cannot read $f; exit 1; fi
XX  
XX  #Initial setup
XX--- 5,11 ----
XX  mkdir testdir
XX  cd testdir
XX  
XX! f=../test1.c
XX  if test -r $f; then : ; else echo sh1 cannot read $f; exit 1; fi
XX  
XX  #Initial setup
XX***************
XX*** 41,49 ****
XX  date >r
XX  ar r x.a p q r 2>/dev/null
XX  ar r x.a /bin/cp
XX! # ar syntax is different for IBM and 68000
XX! if chip INTEL;  then ar rb p x.a /bin/cat; fi
XX! if chip M68000; then ar r x.a /bin/cat; fi
XX  rm p q
XX  mv r R
XX  ar x x.a
XX--- 41,48 ----
XX  date >r
XX  ar r x.a p q r 2>/dev/null
XX  ar r x.a /bin/cp
XX! # ar syntax is different for M68000
XX! if chip M68000; then ar r x.a /bin/cat; else ar rb p x.a /bin/cat; fi
XX  rm p q
XX  mv r R
XX  ar x x.a
X/
Xecho x - sh2.d
Xsed '/^X/s///' > sh2.d << '/'
XX*** /home/top/ast/minix/1.5/test/sh2  crc=24875   5198	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/sh2  crc=26909   5335	Wed Nov  4 07:59:09 1992
XX***************
XX*** 1,5 ****
XX--- 1,8 ----
XX  # Shell script #2 used to test MINIX.
XX  
XX+ # CC="exec cc -wo -F"		# nonstandard flags for ACK :-(
XX+ CC=cc
XX+ 
XX  echo -n "Shell test  2 "
XX  rm -rf testdir
XX  mkdir testdir			# all files are created here
XX***************
XX*** 14,22 ****
XX  
XX  cat >makefile <<END		# create a makefile
XX  all:	x.c
XX! 	@cc -F x.c
XX  END
XX  cat >x.c <<END			# create a C program
XX  char s[] = {"MS-DOS: Just say no"};	/* used by strings later */
XX  main() 
XX  {
XX--- 17,26 ----
XX  
XX  cat >makefile <<END		# create a makefile
XX  all:	x.c
XX! 	@$CC x.c >/dev/null 2>&1
XX  END
XX  cat >x.c <<END			# create a C program
XX+ #include <stdio.h>
XX  char s[] = {"MS-DOS: Just say no"};	/* used by strings later */
XX  main() 
XX  {
XX***************
XX*** 41,47 ****
XX  echo Hi there folks >x
XX  if test -r x; then : ; else echo Error on chmod test 1; fi
XX  chmod 377 x
XX! if test -r x; then echo Error on chmod test 2; fi
XX  chmod 700 x
XX  if test -r x; then : ; else echo Error on chmod test 3; fi
XX  
XX--- 45,51 ----
XX  echo Hi there folks >x
XX  if test -r x; then : ; else echo Error on chmod test 1; fi
XX  chmod 377 x
XX! if test -r x; then test -w / || echo Error on chmod test 2; fi
XX  chmod 700 x
XX  if test -r x; then : ; else echo Error on chmod test 3; fi
XX  
XX***************
XX*** 60,66 ****
XX  black
XX  END
XX  
XX! cut -c3-7 x >y			# extract columns 3-7
XX  if cmp -s y answer; then : ; else echo Error in cut test 1; fi
XX  
XX  #Test dd
XX--- 64,70 ----
XX  black
XX  END
XX  
XX! cut -c 3-7 x >y			# extract columns 3-7
XX  if cmp -s y answer; then : ; else echo Error in cut test 1; fi
XX  
XX  #Test dd
XX***************
XX*** 82,88 ****
XX  
XX  #Test od			
XX  head -1 $f |od >x		# see if od converts ascii to octal ok
XX! if chip M68000
XX  then
XX  cat >answer <<END
XX  0000000 052150 062440 072151 066545 020150 060563 020143 067555
XX--- 86,92 ----
XX  
XX  #Test od			
XX  head -1 $f |od >x		# see if od converts ascii to octal ok
XX! if chip M68000 || chip SPARC
XX  then
XX  cat >answer <<END
XX  0000000 052150 062440 072151 066545 020150 060563 020143 067555
XX***************
XX*** 104,110 ****
XX  if cmp -s x answer; then : ; else echo Error in od test 1; fi
XX  
XX  head -1 $f |od -d >x		# see if od converts ascii to decimal ok
XX! if chip M68000
XX  then
XX  cat >answer <<END
XX  0000000 21608 25888 29801 28005 08296 24947 08291 28525
XX--- 108,114 ----
XX  if cmp -s x answer; then : ; else echo Error in od test 1; fi
XX  
XX  head -1 $f |od -d >x		# see if od converts ascii to decimal ok
XX! if chip M68000 || chip SPARC
XX  then
XX  cat >answer <<END
XX  0000000 21608 25888 29801 28005 08296 24947 08291 28525
X/
Xecho x - t10a.c.d
Xsed '/^X/s///' > t10a.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/t10a.c  crc=20503     22	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/t10a.c  crc=50844     78	Fri Mar 19 21:24:59 1993
XX***************
XX*** 1,4 ****
XX! main()
XX  {
XX    exit(0);
XX  }
XX--- 1,8 ----
XX! #include <stdlib.h>
XX! 
XX! _PROTOTYPE(int main, (void));
XX! 
XX! int main()
XX  {
XX    exit(0);
XX  }
X/
Xecho x - t11a.c.d
Xsed '/^X/s///' > t11a.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/t11a.c  crc=17790   1040	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/t11a.c  crc=56559   1348	Fri Mar 19 21:25:00 1993
XX***************
XX*** 1,9 ****
XX  #define MAX_ERROR 4
XX  
XX  int errct, subtest=1;
XX- extern errno;
XX  
XX! main(argc, argv, envp)
XX  int argc;
XX  char *argv[], *envp[];
XX  {
XX--- 1,21 ----
XX+ /* t11a */
XX+ 
XX+ #include <sys/types.h>
XX+ #include <errno.h>
XX+ #include <fcntl.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX+ #include <stdio.h>
XX+ 
XX  #define MAX_ERROR 4
XX  
XX  int errct, subtest=1;
XX  
XX! _PROTOTYPE(int main, (int argc, char *argv [], char *envp []));
XX! _PROTOTYPE(int diff, (char *s1, char *s2));
XX! _PROTOTYPE(void e, (int n));
XX! 
XX! int main(argc, argv, envp)
XX  int argc;
XX  char *argv[], *envp[];
XX  {
XX***************
XX*** 33,39 ****
XX    exit(100);
XX  }
XX  
XX! diff(s1, s2)
XX  char *s1, *s2;
XX  {
XX    while (1) {
XX--- 45,51 ----
XX    exit(100);
XX  }
XX  
XX! int diff(s1, s2)
XX  char *s1, *s2;
XX  {
XX    while (1) {
XX***************
XX*** 45,57 ****
XX  }
XX  
XX  
XX! e(n)
XX  int n;
XX  {
XX    printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX  	exit(1);
XX    }
XX  }
XX--- 57,71 ----
XX  }
XX  
XX  
XX! void e(n)
XX  int n;
XX  {
XX    printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX  	exit(1);
XX    }
XX  }
X/
Xecho x - t11b.c.d
Xsed '/^X/s///' > t11b.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/t11b.c  crc=16068    662	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/t11b.c  crc=23473    934	Fri Mar 19 21:25:00 1993
XX***************
XX*** 1,16 ****
XX  #define MAX_ERROR 4
XX  
XX  int errct, subtest=1;
XX- extern errno;
XX  
XX  
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX  /* See if arguments passed ok. */
XX  
XX- 
XX    if (diff(argv[0], "t11b")) e(31);
XX    if (diff(argv[1], "abc")) e(32);
XX    if (diff(argv[2], "defghi")) e(33);
XX--- 1,25 ----
XX+ /* t11b */
XX+ 
XX+ #include <sys/types.h>
XX+ #include <errno.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX+ #include <stdio.h>
XX+ 
XX  #define MAX_ERROR 4
XX  
XX  int errct, subtest=1;
XX  
XX+ _PROTOTYPE(int main, (int argc, char *argv []));
XX+ _PROTOTYPE(int diff, (char *s1, char *s2));
XX+ _PROTOTYPE(void e, (int n));
XX  
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX  /* See if arguments passed ok. */
XX  
XX    if (diff(argv[0], "t11b")) e(31);
XX    if (diff(argv[1], "abc")) e(32);
XX    if (diff(argv[2], "defghi")) e(33);
XX***************
XX*** 21,27 ****
XX    exit(75);
XX  }
XX  
XX! diff(s1, s2)
XX  char *s1, *s2;
XX  {
XX    while (1) {
XX--- 30,36 ----
XX    exit(75);
XX  }
XX  
XX! int diff(s1, s2)
XX  char *s1, *s2;
XX  {
XX    while (1) {
XX***************
XX*** 32,44 ****
XX    }
XX  }
XX  
XX! e(n)
XX  int n;
XX  {
XX    printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX  	exit(1);
XX    }
XX  }
XX--- 41,55 ----
XX    }
XX  }
XX  
XX! void e(n)
XX  int n;
XX  {
XX    printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX  	exit(1);
XX    }
XX  }
X/
Xecho x - test1.c.d
Xsed '/^X/s///' > test1.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test1.c  crc=25204   1478	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test1.c  crc=04313   2029	Sat Dec 19 19:50:01 1992
XX***************
XX*** 1,38 ****
XX  /* test 1 */
XX  
XX  #include <signal.h>
XX  #include <stdio.h>
XX  
XX  #define SIGNUM 10
XX  #define MAX_ERROR 4
XX  
XX! int glov, gct;
XX! extern int errno;
XX  int errct;
XX! int subtest = 1;
XX  
XX! main()
XX  {
XX!   int i;
XX  
XX    printf("Test  1 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX!   for (i = 0; i < 15; i++) {
XX! 	test10();
XX! 	test11();
XX    }
XX!   if (errct == 0)
XX! 	printf("ok\n");
XX!   else
XX! 	printf(" %d errors\n", errct);
XX!   exit(0);
XX  }
XX  
XX! test10()
XX  {
XX    int i, n, pid;
XX  
XX    n = 4;
XX    for (i = 0; i < n; i++) {
XX  	if ((pid = fork())) {
XX--- 1,62 ----
XX  /* test 1 */
XX  
XX+ #include <sys/types.h>
XX+ #include <sys/wait.h>
XX+ #include <errno.h>
XX  #include <signal.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX  #include <stdio.h>
XX  
XX  #define SIGNUM 10
XX  #define MAX_ERROR 4
XX+ #define ITERATIONS 10
XX  
XX! _VOLATILE int glov, gct;
XX  int errct;
XX! int subtest;
XX  
XX! _PROTOTYPE(int main, (int argc, char *argv []));
XX! _PROTOTYPE(void test1a, (void));
XX! _PROTOTYPE(void parent, (void));
XX! _PROTOTYPE(void child, (int i));
XX! _PROTOTYPE(void test1b, (void));
XX! _PROTOTYPE(void parent1, (int childpid));
XX! _PROTOTYPE(void func, (int s));
XX! _PROTOTYPE(void child1, (void));
XX! _PROTOTYPE(void e, (int n));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   int i, m = 0xFFFF;
XX  
XX+   sync();
XX+ 
XX+   if (argc == 2) m = atoi(argv[1]);
XX+ 
XX    printf("Test  1 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX!   system("rm -rf DIR_01; mkdir DIR_01");
XX!   chdir("DIR_01");
XX! 
XX!   for (i = 0; i < ITERATIONS; i++) {
XX! 	if (m & 00001) test1a();
XX! 	if (m & 00002) test1b();
XX    }
XX! 
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX! void test1a()
XX  {
XX    int i, n, pid;
XX  
XX+   subtest = 1;
XX    n = 4;
XX    for (i = 0; i < n; i++) {
XX  	if ((pid = fork())) {
XX***************
XX*** 46,52 ****
XX    }
XX  }
XX  
XX! parent()
XX  {
XX  
XX    int n;
XX--- 70,76 ----
XX    }
XX  }
XX  
XX! void parent()
XX  {
XX  
XX    int n;
XX***************
XX*** 55,73 ****
XX    wait(&n);
XX  }
XX  
XX! child(i)
XX  int i;
XX  {
XX    int n;
XX  
XX    n = getpid();
XX!   exit(i);
XX  }
XX  
XX! test11()
XX  {
XX!   int i, k, func();
XX  
XX    for (i = 0; i < 4; i++) {
XX  	glov = 0;
XX  	signal(SIGNUM, func);
XX--- 79,98 ----
XX    wait(&n);
XX  }
XX  
XX! void child(i)
XX  int i;
XX  {
XX    int n;
XX  
XX    n = getpid();
XX!   exit(100+i);
XX  }
XX  
XX! void test1b()
XX  {
XX!   int i, k;
XX  
XX+   subtest = 2;
XX    for (i = 0; i < 4; i++) {
XX  	glov = 0;
XX  	signal(SIGNUM, func);
XX***************
XX*** 78,89 ****
XX  		}
XX  		parent1(k);
XX  	} else
XX! 		child1(k);
XX    }
XX  }
XX  
XX  
XX! parent1(childpid)
XX  int childpid;
XX  {
XX  
XX--- 103,114 ----
XX  		}
XX  		parent1(k);
XX  	} else
XX! 		child1();
XX    }
XX  }
XX  
XX  
XX! void parent1(childpid)
XX  int childpid;
XX  {
XX  
XX***************
XX*** 95,125 ****
XX    wait(&n);
XX  }
XX  
XX! func()
XX  {
XX    glov++;
XX    gct++;
XX  }
XX  
XX! child1(k)
XX! int k;
XX  {
XX    while (glov == 0);
XX    exit(gct);
XX  }
XX  
XX  
XX! 
XX! e(n)
XX! int n;
XX  {
XX-   int err_num = errno;		/* save errno in case printf clobbers it */
XX  
XX!   printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX!   errno = err_num;		/* restore errno, just in case */
XX!   perror("");
XX!   if (errct++ > MAX_ERROR) {
XX! 	printf("Too many errors; test aborted\n");
XX  	exit(1);
XX    }
XX  }
XX--- 120,150 ----
XX    wait(&n);
XX  }
XX  
XX! void func(s)
XX! int s;				/* for ANSI */
XX  {
XX    glov++;
XX    gct++;
XX  }
XX  
XX! void child1()
XX  {
XX    while (glov == 0);
XX    exit(gct);
XX  }
XX  
XX  
XX! void quit()
XX  {
XX  
XX!   chdir("..");
XX!   system("rm -rf DIR*");
XX! 
XX!   if (errct == 0) {
XX! 	printf("ok\n");
XX! 	exit(0);
XX!   } else {
XX! 	printf("%d errors\n", errct);
XX  	exit(1);
XX    }
XX  }
X/
Xecho x - test10.c.d
Xsed '/^X/s///' > test10.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test10.c  crc=49421   1951	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test10.c  crc=56980   2549	Sat Dec 19 19:50:01 1992
XX***************
XX*** 1,22 ****
XX  /* test 10 */
XX  
XX  #include <sys/types.h>
XX  #include <fcntl.h>
XX  #include <stdio.h>
XX  
XX! char *name[] = {"t10a", "t10b", "t10c", "t10d", "t10e", "t10f", "t10g", "t10h", "t10i", "t10j"};
XX! 
XX! extern int errno;
XX  int errct;
XX  long prog[300];
XX  int psize;
XX  
XX! main()
XX  {
XX!   int i, n, pid;
XX  
XX    printf("Test 10 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX    pid = getpid();
XX  
XX    /* Create files t10b ... t10h */
XX--- 1,36 ----
XX  /* test 10 */
XX  
XX  #include <sys/types.h>
XX+ #include <sys/wait.h>
XX+ #include <errno.h>
XX  #include <fcntl.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX  #include <stdio.h>
XX  
XX! char *name[] = {"t10a", "t10b", "t10c", "t10d", "t10e", "t10f", "t10g", 
XX! 						      "t10h", "t10i", "t10j"};
XX  int errct;
XX  long prog[300];
XX  int psize;
XX  
XX! _PROTOTYPE(int main, (void));
XX! _PROTOTYPE(void spawn, (int n));
XX! _PROTOTYPE(void mkfiles, (void));
XX! _PROTOTYPE(void cr_file, (char *name, int size));
XX! _PROTOTYPE(void rmfiles, (void));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! int main()
XX  {
XX!   int i, n, pid, r;
XX  
XX    printf("Test 10 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX+ 
XX+   system("rm -rf DIR_10; mkdir DIR_10; cp t10a DIR_10");
XX+   chdir("DIR_10");
XX+ 
XX    pid = getpid();
XX  
XX    /* Create files t10b ... t10h */
XX***************
XX*** 42,60 ****
XX  		execl("t10d", (char *) 0);
XX  		exit(0);
XX  	}
XX    for (i = 0; i < 60; i++) {
XX! 	spawn(rand() & 07);
XX    }
XX    for (i = 0; i < 4; i++) wait(&n);
XX-   if (errct == 0)
XX- 	printf("ok\n");
XX-   else
XX- 	printf(" %d errors\n", errct);
XX    rmfiles();
XX!   exit(0);
XX  }
XX  
XX! spawn(n)
XX  int n;
XX  {
XX    int pid, k;
XX--- 56,75 ----
XX  		execl("t10d", (char *) 0);
XX  		exit(0);
XX  	}
XX+ 
XX+   srand(100);
XX    for (i = 0; i < 60; i++) {
XX! 	r = rand() & 07;
XX! 	spawn(r);
XX    }
XX+ 
XX    for (i = 0; i < 4; i++) wait(&n);
XX    rmfiles();
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX! void spawn(n)
XX  int n;
XX  {
XX    int pid, k;
XX***************
XX*** 66,77 ****
XX  	errct++;
XX  	printf("Child execl didn't take. file=%s errno=%d\n", name[n], errno);
XX  	rmfiles();
XX! 	exit(0);
XX  	printf("Worse yet, EXIT didn't exit\n");
XX    }
XX  }
XX  
XX! mkfiles()
XX  {
XX    int fd;
XX    fd = open("t10a", 0);
XX--- 81,92 ----
XX  	errct++;
XX  	printf("Child execl didn't take. file=%s errno=%d\n", name[n], errno);
XX  	rmfiles();
XX! 	exit(1);
XX  	printf("Worse yet, EXIT didn't exit\n");
XX    }
XX  }
XX  
XX! void mkfiles()
XX  {
XX    int fd;
XX    fd = open("t10a", 0);
XX***************
XX*** 79,85 ****
XX  	printf("Can't open t10a\n");
XX  	exit(1);
XX    }
XX!   psize = read(fd, prog, 300 * 4);
XX    cr_file("t10b", 1600);
XX    cr_file("t10c", 1400);
XX    cr_file("t10d", 2300);
XX--- 94,100 ----
XX  	printf("Can't open t10a\n");
XX  	exit(1);
XX    }
XX!   psize = read(fd, (char *) prog, 300 * 4);
XX    cr_file("t10b", 1600);
XX    cr_file("t10c", 1400);
XX    cr_file("t10d", 2300);
XX***************
XX*** 93,112 ****
XX  }
XX  
XX  
XX! cr_file(name, size)
XX  char *name;
XX  int size;
XX  
XX  {
XX    int fd;
XX  
XX    prog[6] = (long) size;
XX    fd = creat(name, 0755);
XX!   write(fd, prog, psize);
XX    close(fd);
XX  }
XX  
XX! rmfiles()
XX  {
XX    unlink("t10b");
XX    unlink("t10c");
XX--- 108,130 ----
XX  }
XX  
XX  
XX! void cr_file(name, size)
XX  char *name;
XX  int size;
XX  
XX  {
XX    int fd;
XX  
XX+ #if (CHIP == SPARC)
XX+   size += 4000;
XX+ #endif
XX    prog[6] = (long) size;
XX    fd = creat(name, 0755);
XX!   write(fd, (char *) prog, psize);
XX    close(fd);
XX  }
XX  
XX! void rmfiles()
XX  {
XX    unlink("t10b");
XX    unlink("t10c");
XX***************
XX*** 117,120 ****
XX--- 135,153 ----
XX    unlink("t10h");
XX    unlink("t10i");
XX    unlink("t10j");
XX+ }
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX+ 	exit(1);
XX+   }
XX  }
X/
Xecho x - test11.c.d
Xsed '/^X/s///' > test11.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test11.c  crc=45825   2355	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test11.c  crc=14097   4967	Fri Mar 19 21:25:01 1993
XX***************
XX*** 1,21 ****
XX  /* test 11 */
XX  
XX  #include <sys/types.h>
XX  #include <fcntl.h>
XX  #include <unistd.h>
XX  #include <stdio.h>
XX  
XX  #define MAX_ERROR 1
XX  
XX  char *envp[3] = {"spring", "summer", 0};
XX  
XX! extern errno;
XX! int errct, subtest;
XX  
XX! main()
XX  {
XX!   int i;
XX  
XX    printf("Test 11 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX--- 1,37 ----
XX  /* test 11 */
XX  
XX  #include <sys/types.h>
XX+ #include <sys/stat.h>
XX+ #include <sys/wait.h>
XX+ #include <errno.h>
XX  #include <fcntl.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX  #include <unistd.h>
XX  #include <stdio.h>
XX  
XX+ #define ITERATIONS 10
XX  #define MAX_ERROR 1
XX  
XX+ int errct, subtest;
XX  char *envp[3] = {"spring", "summer", 0};
XX+ char *passwd_file = "/etc/passwd";
XX  
XX! _PROTOTYPE(int main, (int argc, char *argv[]));
XX! _PROTOTYPE(void test11a, (void));
XX! _PROTOTYPE(void test11b, (void));
XX! _PROTOTYPE(void test11c, (void));
XX! _PROTOTYPE(void test11d, (void));
XX! _PROTOTYPE(void e, (int n));
XX  
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   int i, m = 0xFFFF;
XX  
XX+   if (argc == 2) m = atoi(argv[1]);
XX+ 
XX    printf("Test 11 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX***************
XX*** 23,45 ****
XX  	printf("must be setuid root; test aborted\n");
XX  	exit(1);
XX    }
XX  
XX!   for (i = 0; i < 9; i++) {
XX! 	test11a();
XX! 	test11b();
XX    }
XX    if (errct == 0)
XX  	printf("ok\n");
XX    else
XX  	printf(" %d errors\n", errct);
XX!   exit(0);
XX  }
XX  
XX  
XX! test11a()
XX  {
XX  /* Test exec */
XX!   int n, fd, fd1, i;
XX    char aa[4];
XX  
XX  
XX--- 39,77 ----
XX  	printf("must be setuid root; test aborted\n");
XX  	exit(1);
XX    }
XX+   if (getuid() == 0) {
XX+        printf("must be setuid root logged in as someone else; test aborted\n");
XX+        exit(1);
XX+   }
XX  
XX! /*
XX!   system("rm -rf DIR_11; mkdir DIR_11");
XX!   chdir("DIR_11");
XX! */
XX! 
XX!   for (i = 0; i < ITERATIONS; i++) {
XX! 	if (m & 0001) test11a();
XX! 	if (m & 0002) test11b();
XX! 	if (m & 0004) test11c();
XX! 	if (m & 0010) test11d();
XX    }
XX    if (errct == 0)
XX  	printf("ok\n");
XX    else
XX  	printf(" %d errors\n", errct);
XX! 
XX! /*
XX!   chdir("..");
XX!   system("rm -rf DIR_11");
XX! */
XX!   return(0);
XX  }
XX  
XX  
XX! void test11a()
XX  {
XX  /* Test exec */
XX!   int n, fd;
XX    char aa[4];
XX  
XX  
XX***************
XX*** 56,64 ****
XX  
XX  	/* The following call should fail because the mode has no X
XX  	 * bits on. If a bug lets it unexpectedly succeed, the child
XX! 	 * will print an error message since the arguments are wrong. */
XX! 	execl("t11a", (char *) 0, envp);	/* should fail -- no X
XX! 						 * bits on */
XX  
XX  	/* Control should come here after the failed execl(). */
XX  	chmod("t11a", 06555);
XX--- 88,96 ----
XX  
XX  	/* The following call should fail because the mode has no X
XX  	 * bits on. If a bug lets it unexpectedly succeed, the child
XX! 	 * will print an error message since the arguments are wrong.
XX!  	 */
XX! 	execl("t11a", (char *) 0, envp);	/* should fail -- no X bits */
XX  
XX  	/* Control should come here after the failed execl(). */
XX  	chmod("t11a", 06555);
XX***************
XX*** 91,97 ****
XX  
XX  
XX  
XX! test11b()
XX  {
XX    int n;
XX    char *argv[5];
XX--- 123,129 ----
XX  
XX  
XX  
XX! void test11b()
XX  {
XX    int n;
XX    char *argv[5];
XX***************
XX*** 112,118 ****
XX    }
XX  }
XX  
XX! e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX--- 144,217 ----
XX    }
XX  }
XX  
XX! void test11c()
XX! {
XX! /* Test getlogin() and cuserid().  This test  MUST run setuid root. */
XX! 
XX!   int n, etc_uid;
XX!   uid_t ruid, euid;
XX!   char *lnamep, *cnamep, *p;
XX!   char array[L_cuserid], save[L_cuserid], save2[L_cuserid];
XX!   FILE *stream;
XX! 
XX!   subtest = 3;
XX!   errno = -2000;		/* None of these calls set errno. */
XX!   array[0] = '@';
XX!   array[1] = '0';
XX!   save[0] = '#';
XX!   save[1] = '0';
XX!   ruid = getuid();
XX!   euid = geteuid();
XX!   lnamep = getlogin();
XX!   strcpy(save, lnamep);
XX!   cnamep = cuserid(array);
XX!   strcpy(save2, cnamep);
XX! 
XX!   /* Because we are setuid root, cuser == array == 'root';  login != 'root' */
XX!   if (euid != 0) e(1);
XX!   if (ruid == 0) e(2);
XX!   if (strcmp(cnamep, "root") != 0) e(3);
XX!   if (strcmp(array, "root") != 0) e(4);
XX!   if ( (n = strlen(save)) == 0) e(5);
XX!   if (strcmp(save, cnamep) == 0) e(6);		/* they must be different */
XX!   cnamep = cuserid(NULL);
XX!   if (strcmp(cnamep, save2) != 0) e(7);
XX! 
XX!   /* Check login against passwd file. First lookup login in /etc/passwd. */
XX!   if (n == 0) return;		/* if login not found, don't look it up */
XX!   if ( (stream = fopen(passwd_file, "r")) == NULL) e(8);
XX!   while (fgets(array, L_cuserid, stream) != NULL) {
XX! 	if (strncmp(array, save, n) == 0) {
XX! 		p = &array[0];		/* hunt for uid */
XX! 		while (*p != ':') p++;
XX! 		p++;
XX! 		while (*p != ':') p++;
XX! 		p++;			/* p now points to uid */
XX! 		etc_uid = atoi(p);
XX! 		if (etc_uid != ruid) e(9);
XX! 		break;			/* 1 entry per login please */
XX! 	}
XX!   }
XX!   fclose(stream);
XX! }
XX! 
XX! void test11d()
XX! {
XX!   int fd;
XX!   struct stat statbuf;
XX! 
XX!   subtest = 4;
XX!   fd = creat("T11.1", 0750);
XX!   if (fd < 0) e(1);
XX!   if (chown("T11.1", 8, 1) != 0) e(2);
XX!   if (chmod("T11.1", 0666) != 0) e(3);
XX!   if (stat("T11.1", &statbuf) != 0) e(4);
XX!   if ((statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) != 0666) e(5);
XX!   if (close(fd) != 0) e(6);
XX!   if (unlink("T11.1") != 0) e(7);
XX! }
XX! 
XX! void e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX***************
XX*** 122,127 ****
XX--- 221,228 ----
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX  	exit(1);
XX    }
XX  }
X/
Xecho x - test12.c.d
Xsed '/^X/s///' > test12.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test12.c  crc=04396    462	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test12.c  crc=40133    880	Sat Dec 19 19:50:01 1992
XX***************
XX*** 3,12 ****
XX  /* Copyright (C) 1987 by Martin Leisner. All rights reserved. */
XX  /* Used by permission. */
XX  
XX  #include <stdio.h>
XX  
XX  #define NUM_TIMES	1000
XX! main()
XX  {
XX    register int i;
XX    int k;
XX--- 3,22 ----
XX  /* Copyright (C) 1987 by Martin Leisner. All rights reserved. */
XX  /* Used by permission. */
XX  
XX+ #include <sys/types.h>
XX+ #include <sys/wait.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX  #include <stdio.h>
XX  
XX  #define NUM_TIMES	1000
XX! 
XX! int errct = 0;
XX! 
XX! _PROTOTYPE(int main, (void));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! int main()
XX  {
XX    register int i;
XX    int k;
XX***************
XX*** 14,26 ****
XX    printf("Test 12 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX    for (i = 0; i < NUM_TIMES; i++) switch (fork()) {
XX! 	    case 0:	exit();	  		break;
XX  	    case -1:
XX  		printf("fork broke\n");
XX! 		exit();
XX  	    default:	wait(&k);	  		break;
XX  	}
XX  
XX!   printf("ok\n");
XX  }
XX--- 24,55 ----
XX    printf("Test 12 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX+   system("rm -rf DIR_12; mkdir DIR_12");
XX+   chdir("DIR_12");
XX+ 
XX    for (i = 0; i < NUM_TIMES; i++) switch (fork()) {
XX! 	    case 0:	exit(1);	  		break;
XX  	    case -1:
XX  		printf("fork broke\n");
XX! 		exit(1);
XX  	    default:	wait(&k);	  		break;
XX  	}
XX  
XX!   quit();
XX!   return(-1);			/* impossible */
XX! }
XX! 
XX! void quit()
XX! {
XX! 
XX!   chdir("..");
XX!   system("rm -rf DIR*");
XX! 
XX!   if (errct == 0) {
XX! 	printf("ok\n");
XX! 	exit(0);
XX!   } else {
XX! 	printf("%d errors\n", errct);
XX! 	exit(1);
XX!   }
XX  }
X/
Xecho x - test13.c.d
Xsed '/^X/s///' > test13.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test13.c  crc=41529    832	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test13.c  crc=36652   1254	Sat Dec 19 19:50:01 1992
XX***************
XX*** 6,46 ****
XX  /* Copyright (C) 1987 by Martin Leisner. All rights reserved. */
XX  /* Used by permission. */
XX  
XX  #include <stdio.h>
XX  
XX  #define BLOCK_SIZE 	1000
XX  #define NUM_BLOCKS	1000
XX  char buffer[BLOCK_SIZE];
XX  
XX! main()
XX  {
XX!   int pipefd[2];
XX    register int i;
XX    pipe(pipefd);
XX  
XX    printf("Test 13 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX    pipe(pipefd);
XX  
XX    switch (fork()) {
XX        case 0:
XX  	/* Child code */
XX  	for (i = 0; i < NUM_BLOCKS; i++)
XX! 		if (read(pipefd[0], buffer, BLOCK_SIZE) != BLOCK_SIZE) break;
XX! 	;
XX! 	exit();
XX! 	break;
XX        case -1:
XX  	perror("fork broke");
XX! 	exit();
XX        default:
XX  	/* Parent code */
XX! 	for (i = 0; i < NUM_BLOCKS; i++)
XX! 		write(pipefd[1], buffer, BLOCK_SIZE);
XX! 
XX! 	wait((char *) 0);
XX  	break;
XX    }
XX!   printf("ok\n");
XX  }
XX--- 6,72 ----
XX  /* Copyright (C) 1987 by Martin Leisner. All rights reserved. */
XX  /* Used by permission. */
XX  
XX+ #include <sys/types.h>
XX+ #include <sys/wait.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX  #include <stdio.h>
XX  
XX  #define BLOCK_SIZE 	1000
XX  #define NUM_BLOCKS	1000
XX+ 
XX+ int errct = 0;
XX  char buffer[BLOCK_SIZE];
XX  
XX! _PROTOTYPE(int main, (void));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! int main()
XX  {
XX!   int stat_loc, pipefd[2];
XX    register int i;
XX    pipe(pipefd);
XX  
XX    printf("Test 13 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX+   system("rm -rf DIR_13; mkdir DIR_13");
XX+   chdir("DIR_13");
XX+ 
XX    pipe(pipefd);
XX  
XX    switch (fork()) {
XX        case 0:
XX  	/* Child code */
XX  	for (i = 0; i < NUM_BLOCKS; i++)
XX! 	         if (read(pipefd[0], buffer, BLOCK_SIZE) != BLOCK_SIZE) break;
XX! 	exit(0);
XX! 
XX        case -1:
XX  	perror("fork broke");
XX! 	exit(1);
XX! 
XX        default:
XX  	/* Parent code */
XX! 	for (i = 0; i < NUM_BLOCKS; i++) write(pipefd[1], buffer, BLOCK_SIZE);
XX! 	wait(&stat_loc);
XX  	break;
XX    }
XX!   quit();
XX!   return(-1);			/* impossible */
XX! }
XX! 
XX! void quit()
XX! {
XX! 
XX!   chdir("..");
XX!   system("rm -rf DIR*");
XX! 
XX!   if (errct == 0) {
XX! 	printf("ok\n");
XX! 	exit(0);
XX!   } else {
XX! 	printf("%d errors\n", errct);
XX! 	exit(1);
XX!   }
XX  }
X/
Xecho x - test14.c.d
Xsed '/^X/s///' > test14.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test14.c  crc=19231    885	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test14.c  crc=34909   1391	Sat Dec 19 19:50:01 1992
XX***************
XX*** 1,6 ****
XX--- 1,11 ----
XX  /* Test 14. unlinking an open file. */
XX  
XX+ #include <sys/types.h>
XX  #include <errno.h>
XX+ #include <fcntl.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX+ #include <stdio.h>
XX  
XX  #define TRIALS 100
XX  #define MAX_ERROR 4
XX***************
XX*** 9,19 ****
XX  int errct;
XX  int subtest = 1;
XX  
XX! main()
XX  {
XX    int fd0, i, pid;
XX  
XX    printf("Test 14 ");
XX    pid = getpid();
XX    name[6] = (pid & 037) + 33;
XX    name[7] = ((pid * pid) & 037) + 33;
XX--- 14,33 ----
XX  int errct;
XX  int subtest = 1;
XX  
XX! _PROTOTYPE(int main, (void));
XX! _PROTOTYPE(void e, (int n));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! int main()
XX  {
XX    int fd0, i, pid;
XX  
XX    printf("Test 14 ");
XX+   fflush(stdout);
XX+ 
XX+   system("rm -rf DIR_14; mkdir DIR_14");
XX+   chdir("DIR_14");
XX+ 
XX    pid = getpid();
XX    name[6] = (pid & 037) + 33;
XX    name[7] = ((pid * pid) & 037) + 33;
XX***************
XX*** 31,41 ****
XX    fd0 = creat(name, 0777);
XX    write(fd0, name, 20);
XX    unlink(name);
XX!   printf("ok\n");
XX  }
XX  
XX  
XX! e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX--- 45,56 ----
XX    fd0 = creat(name, 0777);
XX    write(fd0, name, 20);
XX    unlink(name);
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX  
XX! void e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX***************
XX*** 45,50 ****
XX--- 60,82 ----
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX+ 	exit(1);
XX+   }
XX+ }
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX  	exit(1);
XX    }
XX  }
X/
Xecho x - test15.c.d
Xsed '/^X/s///' > test15.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test15.c  crc=32792  20339	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test15.c  crc=00725  23944	Sat Dec 19 19:50:01 1992
XX***************
XX*** 1,23 ****
XX  /* Test program for string(3) routines.
XX   *
XX!  * Note that at least one Bell Labs implementation of the string
XX!  * routines flunks a couple of these tests -- the ones which test
XX!  * behavior on "negative" characters.
XX   */
XX  
XX  #include <sys/types.h>
XX- #include <string.h>
XX  #include <fcntl.h>
XX  #include <stdio.h>
XX  
XX  #define	STREQ(a, b)	(strcmp((a), (b)) == 0)
XX  
XX  char *it = "<UNSET>";		/* Routine name for message routines. */
XX  int waserror = 0;		/* For exit status. */
XX  
XX  char uctest[] = "\004\203";	/* For testing signedness of chars. */
XX  int charsigned;			/* Result. */
XX  
XX  /*
XX   - check - complain if condition is not true
XX   */
XX--- 1,36 ----
XX  /* Test program for string(3) routines.
XX   *
XX!  * Slightly modified from Henry Spencer's original routine.
XX!  *   - incorporates semantic changes per the ANSI standard (original tests
XX!  *     can be recovered by defining the symbol NOT_ANSI while compiling,
XX!  *     except for the change of memcpy() to memmove()).
XX!  *   - makes additional tests of functions on unaligned buffers and strings.
XX   */
XX  
XX  #include <sys/types.h>
XX  #include <fcntl.h>
XX+ #include <string.h>
XX+ #include <stdlib.h>
XX  #include <stdio.h>
XX  
XX+ _PROTOTYPE( int chdir, (char *_path));		/* from <unistd.h> */
XX+ 
XX  #define	STREQ(a, b)	(strcmp((a), (b)) == 0)
XX  
XX  char *it = "<UNSET>";		/* Routine name for message routines. */
XX+ int errct;			/* count errors */
XX  int waserror = 0;		/* For exit status. */
XX  
XX  char uctest[] = "\004\203";	/* For testing signedness of chars. */
XX  int charsigned;			/* Result. */
XX  
XX+ _PROTOTYPE(void check, (int thing, int number));
XX+ _PROTOTYPE(void equal, (char *a, char *b, int number));
XX+ _PROTOTYPE(int main, (int argc, char *argv []));
XX+ _PROTOTYPE(void first, (void));
XX+ _PROTOTYPE(void second, (void));
XX+ _PROTOTYPE(void quit, (void));
XX+ 
XX  /*
XX   - check - complain if condition is not true
XX   */
XX***************
XX*** 26,33 ****
XX  int number;			/* Test number for error message. */
XX  {
XX    if (!thing) {
XX! 	printf("\t%s flunked test %d\n", it, number);
XX  	waserror = 1;
XX    }
XX  }
XX  
XX--- 39,47 ----
XX  int number;			/* Test number for error message. */
XX  {
XX    if (!thing) {
XX! 	printf("%s flunked test %d\n", it, number);
XX  	waserror = 1;
XX+ 	errct++;
XX    }
XX  }
XX  
XX***************
XX*** 55,71 ****
XX  int f;
XX  extern char *sys_errlist[];
XX  extern int sys_nerr;
XX- extern int errno;
XX  #endif
XX  
XX  /* ARGSUSED */
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX- 
XX    printf("Test 15 ");
XX  
XX    /* First, establish whether chars are signed. */
XX    if (uctest[0] < uctest[1])
XX  	charsigned = 0;
XX--- 69,86 ----
XX  int f;
XX  extern char *sys_errlist[];
XX  extern int sys_nerr;
XX  #endif
XX  
XX  /* ARGSUSED */
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX    printf("Test 15 ");
XX+   fflush(stdout);
XX  
XX+   system("rm -rf DIR_15; mkdir DIR_15");
XX+   chdir("DIR_15");
XX    /* First, establish whether chars are signed. */
XX    if (uctest[0] < uctest[1])
XX  	charsigned = 0;
XX***************
XX*** 77,87 ****
XX    first();
XX    second();
XX  
XX!   printf("ok\n");
XX!   exit((waserror) ? 1 : 0);
XX  }
XX  
XX! first()
XX  {
XX    /* Test strcmp first because we use it to test other things. */
XX    it = "strcmp";
XX--- 92,103 ----
XX    first();
XX    second();
XX  
XX!   errct = waserror;
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX! void first()
XX  {
XX    /* Test strcmp first because we use it to test other things. */
XX    it = "strcmp";
XX***************
XX*** 94,106 ****
XX    check(strcmp("abce", "abcd") > 0, 7);
XX    check(strcmp("a\203", "a") > 0, 8);	/* Tricky if char signed. */
XX  
XX! /* This gives problems DEBUG
XX!   if (charsigned)	
XX  	check(strcmp("a\203", "a\003") < 0, 9);
XX    else
XX  	check(strcmp("a\203", "a\003") > 0, 9);
XX  */
XX  
XX    /* Test strcpy next because we need it to set up other tests. */
XX    it = "strcpy";
XX    check(strcpy(one, "abcd") == one, 1);	/* Returned value. */
XX--- 110,133 ----
XX    check(strcmp("abce", "abcd") > 0, 7);
XX    check(strcmp("a\203", "a") > 0, 8);	/* Tricky if char signed. */
XX  
XX! /*
XX! #ifdef NOT_ANSI
XX!   if (charsigned)
XX  	check(strcmp("a\203", "a\003") < 0, 9);
XX    else
XX  	check(strcmp("a\203", "a\003") > 0, 9);
XX+ #else
XX+   check(strcmp("a\203", "a\003") > 0, 9);
XX+ #endif
XX  */
XX  
XX+   check(strcmp("abcd" + 1, "abcd" + 1) == 0, 10);	/* Unaligned tests. */
XX+   check(strcmp("abcd" + 1, "abce" + 1) < 0, 11);
XX+   check(strcmp("abcd" + 1, "bcd") == 0, 12);
XX+   check(strcmp("abce" + 1, "bcd") > 0, 13);
XX+   check(strcmp("abcd" + 2, "bcd" + 1) == 0, 14);
XX+   check(strcmp("abcd" + 2, "bce" + 1) < 0, 15);
XX+ 
XX    /* Test strcpy next because we need it to set up other tests. */
XX    it = "strcpy";
XX    check(strcpy(one, "abcd") == one, 1);	/* Returned value. */
XX***************
XX*** 118,123 ****
XX--- 145,156 ----
XX    (void) strcpy(one, "");
XX    equal(one, "", 7);		/* Boundary condition. */
XX  
XX+   (void) strcpy(one, "abcdef" + 1);	/* Unaligned tests. */
XX+   equal(one, "bcdef", 8);
XX+   (void) strcpy(one + 1, "*xy" + 1);
XX+   equal(one, "bxy", 9);
XX+   equal(one + 4, "f", 10);
XX+ 
XX    /* Strcat */
XX    it = "strcat";
XX    (void) strcpy(one, "ijk");
XX***************
XX*** 183,188 ****
XX--- 216,229 ----
XX    (void) strncat(one, "gh", 2);
XX    equal(one, "abcdgh", 12);	/* Count and length equal. */
XX  
XX+   (void) strcpy(one, "abcdefghij");	/* Unaligned tests. */
XX+   (void) strcpy(one, "abcd");
XX+   (void) strcpy(one, "abc");
XX+   (void) strncat(one, "de" + 1, 1);
XX+   equal(one, "abce", 13);
XX+   equal(one + 4, "", 14);
XX+   equal(one + 5, "fghij", 15);
XX+ 
XX    /* Strncmp - first test as strcmp with big counts, then test count code. */
XX    it = "strncmp";
XX    check(strncmp("", "", 99) == 0, 1);	/* Trivial case. */
XX***************
XX*** 194,204 ****
XX    check(strncmp("abce", "abcd", 99) > 0, 7);
XX    check(strncmp("a\203", "a", 2) > 0, 8);	/* Tricky if '\203' < 0 */
XX  
XX! /*  This gives problems -- DEBUG
XX    if (charsigned)
XX  	check(strncmp("a\203", "a\003", 2) < 0, 9);
XX    else
XX  	check(strncmp("a\203", "a\003", 2) > 0, 9);
XX  */
XX  
XX    check(strncmp("abce", "abcd", 3) == 0, 10);	/* Count limited. */
XX--- 235,249 ----
XX    check(strncmp("abce", "abcd", 99) > 0, 7);
XX    check(strncmp("a\203", "a", 2) > 0, 8);	/* Tricky if '\203' < 0 */
XX  
XX! /*
XX! #ifdef NOT_ANSI
XX    if (charsigned)
XX  	check(strncmp("a\203", "a\003", 2) < 0, 9);
XX    else
XX  	check(strncmp("a\203", "a\003", 2) > 0, 9);
XX+ #else
XX+   check(strncmp("a\203", "a\003", 2) > 0, 9);
XX+ #endif
XX  */
XX  
XX    check(strncmp("abce", "abcd", 3) == 0, 10);	/* Count limited. */
XX***************
XX*** 249,254 ****
XX--- 294,300 ----
XX    check(strlen("") == 0, 1);	/* Empty. */
XX    check(strlen("a") == 1, 2);	/* Single char. */
XX    check(strlen("abcd") == 4, 3);/* Multiple chars. */
XX+   check(strlen("abcd" + 1) == 3, 4);	/* Unaligned test. */
XX  
XX    /* Strchr */
XX    it = "strchr";
XX***************
XX*** 307,313 ****
XX    check(rindex(one, '\0') == one, 8);	/* NUL in empty string. */
XX  }
XX  
XX! second()
XX  {
XX    /* Strpbrk - somewhat like strchr */
XX    it = "strpbrk";
XX--- 353,359 ----
XX    check(rindex(one, '\0') == one, 8);	/* NUL in empty string. */
XX  }
XX  
XX! void second()
XX  {
XX    /* Strpbrk - somewhat like strchr */
XX    it = "strpbrk";
XX***************
XX*** 339,345 ****
XX--- 385,395 ----
XX    check(strstr(one, "abcd") == one, 8);	/* Exact match. */
XX    check(strstr(one, "abcde") == NULL, 9);	/* Too long. */
XX    check(strstr(one, "de") == NULL, 10);	/* Past end. */
XX+ #ifdef NOT_ANSI
XX+   check(strstr(one, "") == one + 4, 11);	/* Finding empty. */
XX+ #else
XX    check(strstr(one, "") == one, 11);	/* Finding empty. */
XX+ #endif
XX    (void) strcpy(one, "ababa");
XX    check(strstr(one, "ba") == one + 1, 12);	/* Finding first. */
XX    (void) strcpy(one, "");
XX***************
XX*** 421,456 ****
XX    check(memcmp("abce", "abcd", 4) > 0, 4);
XX    check(memcmp("alph", "beta", 4) < 0, 5);
XX  
XX! /* This gives problems -- DEBUG
XX!   if (charsigned)	
XX  	check(memcmp("a\203", "a\003", 2) < 0, 6);
XX    else
XX  	check(memcmp("a\203", "a\003", 2) > 0, 6);
XX  */
XX  
XX    check(memcmp("abce", "abcd", 3) == 0, 7);	/* Count limited. */
XX    check(memcmp("abc", "def", 0) == 0, 8);	/* Zero count. */
XX  
XX    /* Memchr */
XX    it = "memchr";
XX    check(memchr("abcd", 'z', 4) == NULL, 1);	/* Not found. */
XX    (void) strcpy(one, "abcd");
XX!   check(memchr(one, 'c', 4) == one + 2, 2);	/* Basic test. */
XX!   check(memchr(one, 'd', 4) == one + 3, 3);	/* End of string. */
XX!   check(memchr(one, 'a', 4) == one, 4);	/* Beginning. */
XX!   check(memchr(one, '\0', 5) == one + 4, 5);	/* Finding NUL. */
XX    (void) strcpy(one, "ababa");
XX!   check(memchr(one, 'b', 5) == one + 1, 6);	/* Finding first. */
XX!   check(memchr(one, 'b', 0) == NULL, 7);	/* Zero count. */
XX!   check(memchr(one, 'a', 1) == one, 8);	/* Singleton case. */
XX    (void) strcpy(one, "a\203b");
XX!   check(memchr(one, 0203, 3) == one + 1, 9);	/* Unsignedness. */
XX  
XX    /* Memcpy 
XX!    * Note that X3J11 says memcpy must work regardless of overlap. The SVID
XX!    * says it might fail. */
XX    it = "memcpy";
XX!   check(memcpy(one, "abc", 4) == one, 1);	/* Returned value. */
XX    equal(one, "abc", 2);		/* Did the copy go right? */
XX  
XX    (void) strcpy(one, "abcdefgh");
XX--- 471,519 ----
XX    check(memcmp("abce", "abcd", 4) > 0, 4);
XX    check(memcmp("alph", "beta", 4) < 0, 5);
XX  
XX! /*
XX! #ifdef NOT_ANSI
XX!   if (charsigned)
XX  	check(memcmp("a\203", "a\003", 2) < 0, 6);
XX    else
XX  	check(memcmp("a\203", "a\003", 2) > 0, 6);
XX+ #else
XX+   check(memcmp("a\203", "a\003", 2) > 0, 6);
XX+ #endif
XX  */
XX  
XX    check(memcmp("abce", "abcd", 3) == 0, 7);	/* Count limited. */
XX    check(memcmp("abc", "def", 0) == 0, 8);	/* Zero count. */
XX  
XX+   check(memcmp("a" + 1, "a" + 1, 1) == 0, 9);	/* Unaligned tests. */
XX+   check(memcmp("abc" + 1, "bc", 2) == 0, 10);
XX+   check(memcmp("bc", "abc" + 1, 2) == 0, 11);
XX+   check(memcmp("abcd" + 1, "abce" + 1, 3) < 0, 12);
XX+   check(memcmp("abce" + 1, "abcd" + 1, 3) > 0, 13);
XX+ /*
XX+   check(memcmp("a\203" + 1, "a\003" + 1, 1) > 0, 14);
XX+ */
XX+   check(memcmp("abcde" + 1, "abcdf" + 1, 3) == 0, 15);
XX+ 
XX    /* Memchr */
XX    it = "memchr";
XX    check(memchr("abcd", 'z', 4) == NULL, 1);	/* Not found. */
XX    (void) strcpy(one, "abcd");
XX!   check( (char *)memchr(one, 'c', 4) == one + 2, 2);	/* Basic test. */
XX!   check( (char *)memchr(one, 'd', 4) == one + 3, 3);	/* End of string. */
XX!   check( (char *)memchr(one, 'a', 4) == one, 4);	/* Beginning. */
XX!   check( (char *)memchr(one, '\0', 5) == one + 4, 5);	/* Finding NUL. */
XX    (void) strcpy(one, "ababa");
XX!   check( (char *)memchr(one, 'b', 5) == one + 1, 6);	/* Finding first. */
XX!   check( (char *)memchr(one, 'b', 0) == NULL, 7);	/* Zero count. */
XX!   check( (char *)memchr(one, 'a', 1) == one, 8);	/* Singleton case. */
XX    (void) strcpy(one, "a\203b");
XX!   check( (char *)memchr(one, 0203, 3) == one + 1, 9);	/* Unsignedness. */
XX  
XX    /* Memcpy 
XX!    * Note that X3J11 says memcpy may fail on overlap. */
XX    it = "memcpy";
XX!   check( (char *)memcpy(one, "abc", 4) == one, 1);	/* Returned value. */
XX    equal(one, "abc", 2);		/* Did the copy go right? */
XX  
XX    (void) strcpy(one, "abcdefgh");
XX***************
XX*** 467,484 ****
XX    equal(two, "hi there", 5);	/* Just paranoia. */
XX    equal(one, "hi there", 6);	/* Stomped on source? */
XX  
XX    (void) strcpy(one, "abcdefgh");
XX!   (void) memcpy(one + 1, one, 9);
XX    equal(one, "aabcdefgh", 7);	/* Overlap, right-to-left. */
XX  
XX    (void) strcpy(one, "abcdefgh");
XX!   (void) memcpy(one + 1, one + 2, 7);
XX    equal(one, "acdefgh", 8);	/* Overlap, left-to-right. */
XX  
XX    (void) strcpy(one, "abcdefgh");
XX!   (void) memcpy(one, one, 9);
XX    equal(one, "abcdefgh", 9);	/* 100% overlap. */
XX  
XX    /* Memccpy - first test like memcpy, then the search part 
XX     * The SVID, the only place where memccpy is mentioned, says overlap
XX     * might fail, so we don't try it.  Besides, it's hard to see the
XX--- 530,589 ----
XX    equal(two, "hi there", 5);	/* Just paranoia. */
XX    equal(one, "hi there", 6);	/* Stomped on source? */
XX  
XX+   (void) strcpy(one, "abcde");	/* Unaligned tests. */
XX+   (void) memcpy(one + 1, "\0\0\0\0\0", 1);
XX+   equal(one, "a", 7);
XX+   equal(one + 2, "cde", 8);
XX+   (void) memcpy(one + 1, "xyz" + 1, 2);
XX+   equal(one, "ayzde", 9);
XX+   (void) memcpy(one + 1, "xyz" + 1, 3);
XX+   equal(one, "ayz", 10);
XX+ 
XX+   /* Memmove 
XX+    * Note that X3J11 says memmove must work regardless of overlap. */
XX+   it = "memmove";
XX+   check( (char *)memmove(one, "abc", 4) == one, 1);	/* Returned value. */
XX+   equal(one, "abc", 2);		/* Did the copy go right? */
XX+ 
XX    (void) strcpy(one, "abcdefgh");
XX!   (void) memmove(one + 1, "xyz", 2);
XX!   equal(one, "axydefgh", 3);	/* Basic test. */
XX! 
XX!   (void) strcpy(one, "abc");
XX!   (void) memmove(one, "xyz", 0);
XX!   equal(one, "abc", 4);		/* Zero-length copy. */
XX! 
XX!   (void) strcpy(one, "hi there");
XX!   (void) strcpy(two, "foo");
XX!   (void) memmove(two, one, 9);
XX!   equal(two, "hi there", 5);	/* Just paranoia. */
XX!   equal(one, "hi there", 6);	/* Stomped on source? */
XX! 
XX!   (void) strcpy(one, "abcdefgh");
XX!   (void) memmove(one + 1, one, 9);
XX    equal(one, "aabcdefgh", 7);	/* Overlap, right-to-left. */
XX  
XX    (void) strcpy(one, "abcdefgh");
XX!   (void) memmove(one + 1, one + 2, 7);
XX    equal(one, "acdefgh", 8);	/* Overlap, left-to-right. */
XX  
XX    (void) strcpy(one, "abcdefgh");
XX!   (void) memmove(one, one, 9);
XX    equal(one, "abcdefgh", 9);	/* 100% overlap. */
XX  
XX+   (void) strcpy(one, "abcde");	/* Unaligned tests. */
XX+   (void) memmove(one + 1, "\0\0\0\0\0", 1);
XX+   equal(one, "a", 10);
XX+   equal(one + 2, "cde", 11);
XX+   (void) memmove(one + 1, "xyz" + 1, 2);
XX+   equal(one, "ayzde", 12);
XX+   (void) memmove(one + 1, "xyz" + 1, 3);
XX+   equal(one, "ayz", 13);
XX+   (void) strcpy(one, "abcdefgh");
XX+   (void) memmove(one + 2, one + 1, 8);
XX+   equal(one, "abbcdefgh", 14);
XX+ 
XX+ 
XX    /* Memccpy - first test like memcpy, then the search part 
XX     * The SVID, the only place where memccpy is mentioned, says overlap
XX     * might fail, so we don't try it.  Besides, it's hard to see the
XX***************
XX*** 503,526 ****
XX  
XX    (void) strcpy(one, "abcdefgh");
XX    (void) strcpy(two, "horsefeathers");
XX!   check(memccpy(two, one, 'f', 9) == two + 6, 7);	/* Returned value. */
XX    equal(one, "abcdefgh", 8);	/* Source intact? */
XX    equal(two, "abcdefeathers", 9);	/* Copy correct? */
XX  
XX    (void) strcpy(one, "abcd");
XX    (void) strcpy(two, "bumblebee");
XX!   check(memccpy(two, one, 'a', 4) == two + 1, 10);	/* First char. */
XX    equal(two, "aumblebee", 11);
XX!   check(memccpy(two, one, 'd', 4) == two + 4, 12);	/* Last char. */
XX    equal(two, "abcdlebee", 13);
XX    (void) strcpy(one, "xyz");
XX!   check(memccpy(two, one, 'x', 1) == two + 1, 14);	/* Singleton. */
XX    equal(two, "xbcdlebee", 15);
XX  
XX    /* Memset */
XX    it = "memset";
XX    (void) strcpy(one, "abcdefgh");
XX!   check(memset(one + 1, 'x', 3) == one + 1, 1);	/* Return value. */
XX    equal(one, "axxxefgh", 2);	/* Basic test. */
XX  
XX    (void) memset(one + 2, 'y', 0);
XX--- 608,631 ----
XX  
XX    (void) strcpy(one, "abcdefgh");
XX    (void) strcpy(two, "horsefeathers");
XX!   check( (char *)memccpy(two, one, 'f', 9) == two + 6, 7);/* Returned value. */
XX    equal(one, "abcdefgh", 8);	/* Source intact? */
XX    equal(two, "abcdefeathers", 9);	/* Copy correct? */
XX  
XX    (void) strcpy(one, "abcd");
XX    (void) strcpy(two, "bumblebee");
XX!   check((char *)memccpy(two, one, 'a', 4) == two + 1, 10);    /* First char. */
XX    equal(two, "aumblebee", 11);
XX!   check((char *)memccpy(two, one, 'd', 4) == two + 4, 12);     /* Last char. */
XX    equal(two, "abcdlebee", 13);
XX    (void) strcpy(one, "xyz");
XX!   check((char *)memccpy(two, one, 'x', 1) == two + 1, 14);     /* Singleton. */
XX    equal(two, "xbcdlebee", 15);
XX  
XX    /* Memset */
XX    it = "memset";
XX    (void) strcpy(one, "abcdefgh");
XX!   check( (char *) memset(one + 1, 'x', 3) == one + 1, 1);   /* Return value. */
XX    equal(one, "axxxefgh", 2);	/* Basic test. */
XX  
XX    (void) memset(one + 2, 'y', 0);
XX***************
XX*** 578,584 ****
XX  #ifdef ERR
XX    /* Strerror - VERY system-dependent */
XX    it = "strerror";
XX!   f = open("/", O_WRONLY);		/* Should always fail. */
XX    check(f < 0 && errno > 0 && errno < sys_nerr, 1);
XX    equal(strerror(errno), sys_errlist[errno], 2);
XX  #ifdef UNIXERR
XX--- 683,689 ----
XX  #ifdef ERR
XX    /* Strerror - VERY system-dependent */
XX    it = "strerror";
XX!   f = open("/", O_WRONLY);	/* Should always fail. */
XX    check(f < 0 && errno > 0 && errno < sys_nerr, 1);
XX    equal(strerror(errno), sys_errlist[errno], 2);
XX  #ifdef UNIXERR
XX***************
XX*** 588,591 ****
XX--- 693,711 ----
XX    equal(strerror(errno), "Permission denied", 3);
XX  #endif
XX  #endif
XX+ }
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX+ 	exit(1);
XX+   }
XX  }
X/
Xecho x - test16.c.d
Xsed '/^X/s///' > test16.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test16.c  crc=09236   4935	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test16.c  crc=39237   6607	Fri Mar 19 21:25:02 1993
XX***************
XX*** 1,305 ****
XX  /* test 16 */
XX  
XX! #include <signal.h>
XX  #include <errno.h>
XX  #include <stdio.h>
XX  
XX  #define MAX_ERROR 4
XX  
XX! extern int errno;
XX! int errct, subtest;
XX  
XX  
XX! int func1(), func10(), func8(), funcalrm(), func11();
XX! int childsigs, parsigs, alarms;
XX! int zero[1024];
XX! 
XX! main()
XX  {
XX!   int i;
XX  
XX!   printf("Test 16 ");
XX!   fflush(stdout);		/* have to flush for child's benefit */
XX  
XX!   for (i = 0; i < 1; i++) {
XX! 	test50();
XX! 	test51();
XX! 	test53();
XX! 	test54();
XX! 	test55();
XX! /*	test56(); */
XX! 	test57();
XX!   }
XX!   if (errct == 0)
XX! 	printf("ok\n");
XX!   else
XX! 	printf("%d errors\n", errct);
XX!   exit(0);
XX! }
XX  
XX! 
XX! test50()
XX! {
XX!   int parpid, childpid, flag, *zp;
XX! 
XX!   flag = 0;
XX!   for (zp = &zero[0]; zp < &zero[1024]; zp++)
XX! 	if (*zp != 0) flag = 1;
XX!   if (flag) e(0);		/* check if bss is cleared to 0 */
XX!   if (signal(1, func1) < 0) e(1);
XX!   if (signal(10, func10) < 0) e(2);
XX!   parpid = getpid();
XX!   if (childpid = fork()) {
XX! 	if (childpid < 0) ex();
XX! 	parent(childpid);
XX!   } else {
XX! 	child(parpid);
XX    }
XX!   if (signal(1, SIG_DFL) < 0) e(4);
XX!   if (signal(10, SIG_DFL) < 0) e(5);
XX  }
XX  
XX- parent(childpid)
XX- int childpid;
XX- {
XX-   int i;
XX  
XX!   for (i = 0; i < 3; i++) {
XX! 	if (kill(childpid, 1) < 0) e(6);
XX! 	while (parsigs == 0);
XX! 	parsigs--;
XX!   }
XX!   if (wait(&i) < 0) e(7);
XX!   if (i != 256 * 6) e(8);
XX! }
XX! 
XX! child(parpid)
XX! int parpid;
XX  {
XX  
XX!   int i;
XX  
XX!   for (i = 0; i < 3; i++) {
XX! 	while (childsigs == 0);
XX! 	childsigs--;
XX! 	if (kill(parpid, 10) < 0) e(9);
XX!   }
XX!   exit(6);
XX! }
XX  
XX! func1()
XX! {
XX!   if (signal(1, func1) < 0) e(10);
XX!   childsigs++;
XX! }
XX! 
XX! func10()
XX! {
XX!   if (signal(10, func10) < 0) e(11);
XX!   parsigs++;
XX! }
XX! 
XX! 
XX! test51()
XX! {
XX!   int cpid, n, pid;
XX! 
XX!   if ((pid = fork())) {
XX! 	if (pid < 0) ex();
XX! 	if ((pid = fork())) {
XX! 		if (pid < 0) ex();
XX! 		if (cpid = fork()) {
XX! 			if (cpid < 0) ex();
XX! 			if (kill(cpid, 9) < 0) e(12);
XX! 			if (wait(&n) < 0) e(13);
XX! 			if (wait(&n) < 0) e(14);
XX! 			if (wait(&n) < 0) e(15);
XX! 		} else {
XX! 			pause();
XX! 			while (1);
XX! 		}
XX! 	} else {
XX! 		exit(0);
XX! 	}
XX!   } else {
XX! 	exit(0);
XX    }
XX- }
XX  
XX! test52()
XX! {
XX!   int pid, n, k;
XX  
XX!   pid = getpid();
XX!   if (getpid() == pid) k = fork();	/* only parent forks */
XX!   if (k < 0) ex();
XX!   if (getpid() == pid) k = fork();	/* only parent forks */
XX!   if (k < 0) ex();
XX!   if (getpid() == pid) k = fork();	/* only parent forks */
XX!   if (k < 0) ex();
XX  
XX!   if (getpid() == pid) {
XX! 	if (kill(0, 9) < 0) e(16);
XX! 	if (wait(&n) < 0) e(17);
XX! 	if (wait(&n) < 0) e(18);
XX! 	if (wait(&n) < 0) e(19);
XX!   } else
XX! 	pause();
XX! }
XX  
XX! int sigmap[5] = {9, 10, 11};
XX! test53()
XX! {
XX!   int n, i, pid, wpid;
XX  
XX!   /* Test exit status codes for processes killed by signals. */
XX!   for (i = 0; i < 3; i++) {
XX! 	if (pid = fork()) {
XX! 		if (pid < 0) ex();
XX! 		sleep(3);	/* wait for child to pause */
XX! 		if (kill(pid, sigmap[i]) < 0) {
XX! 			e(20);
XX! 			exit(1);
XX! 		}
XX! 		if ((wpid = wait(&n)) < 0) e(21);
XX! 		if ((n & 077) != sigmap[i]) e(22);
XX! 		if (pid != wpid) e(23);
XX! 	} else {
XX! 		pause();
XX! 		exit(0);
XX! 	}
XX!   }
XX! }
XX  
XX! test54()
XX! {
XX! /* Test alarm */
XX! 
XX!   int i;
XX! 
XX!   alarms = 0;
XX!   for (i = 0; i < 8; i++) {
XX! 	signal(SIGALRM, funcalrm);
XX! 	alarm(1);
XX! 	pause();
XX! 	if (alarms != i + 1) e(24);
XX!   }
XX  }
XX  
XX  
XX! 
XX! test55()
XX  {
XX! /* When a signal knocks a processes out of WAIT or PAUSE, it is supposed to
XX!  * get EINTR as error status.  Check that.
XX!  */
XX!   int n, j, i;
XX  
XX!   if (signal(8, func8) < 0) e(25);
XX!   if (n = fork()) {
XX! 	/* Parent must delay to give child a chance to pause. */
XX! 	if (n < 0) ex();
XX! 	sleep(1);
XX! 	if (kill(n, 8) < 0) e(26);
XX! 	if (wait(&n) < 0) e(27);
XX! 	if (signal(8, SIG_DFL) < 0) e(28);
XX!   } else {
XX! 	j = pause();
XX! 	if (errno != EINTR && -errno != EINTR) e(29);
XX! 	exit(0);
XX!   }
XX  }
XX  
XX- func8()
XX- {
XX- }
XX  
XX- test56()
XX- {
XX-   int i, j, k, n;
XX  
XX!   n = fork();
XX!   if (n < 0) ex();
XX!   if (n) {
XX! 	wait(&i);
XX! 	i = (i >> 8) & 0377;
XX! 	if (i != (n & 0377)) e(30);
XX!   } else {
XX! 	i = getgid();
XX! 	j = getegid();
XX! 	k = (i + j + 7) & 0377;
XX! 	if (setgid(k) < 0) e(31);
XX! 	if (getgid() != k) e(32);
XX! 	if (getegid() != k) e(33);
XX! 	i = getuid();
XX! 	j = geteuid();
XX! 	k = (i + j + 1) & 0377;
XX! 	if (setuid(k) < 0) e(34);
XX! 	if (getuid() != k) e(35);
XX! 	if (geteuid() != k) e(36);
XX! 	i = getpid() & 0377;
XX! 	if (wait(&j) != -1) e(37);
XX! 	exit(i);
XX!   }
XX! }
XX! 
XX! func11()
XX! {
XX!   e(38);
XX! }
XX! 
XX! 
XX! test57()
XX! {
XX!   int n;
XX! 
XX!   signal(11, func11);
XX!   signal(11, SIG_IGN);
XX!   n = getpid();
XX!   kill(n, 11);
XX!   signal(11, SIG_DFL);
XX! }
XX! 
XX! funcalrm()
XX! {
XX!   alarms++;
XX! }
XX! 
XX! 
XX! test58()
XX! {
XX! /* When a signal knocks a processes out of PIPE, it is supposed to
XX!  * get EINTR as error status.  Check that.
XX!  */
XX!   int n, j, i, fd[2];
XX! 
XX!   if (signal(8, func8) < 0) e(38);
XX!   pipe(fd);
XX!   if (n = fork()) {
XX! 	/* Parent must delay to give child a chance to pause. */
XX! 	if (n < 0) ex();
XX! 	sleep(3);
XX! 	if (kill(n, 8) < 0) e(39);
XX! 	if (wait(&n) < 0) e(40);
XX! 	if (signal(8, SIG_DFL) < 0) e(41);
XX! 	close(fd[0]);
XX! 	close(fd[1]);
XX!   } else {
XX! 	j = read(fd[0], &n, 1);
XX! 	if (errno != EINTR) e(42);
XX! 	exit(0);
XX!   }
XX! }
XX! 
XX! ex()
XX! {
XX!   printf("Test 16.  fork failed.  Errno=%d\n", errno);
XX!   exit(1);
XX! }
XX! 
XX! 
XX! 
XX! e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX--- 1,228 ----
XX  /* test 16 */
XX  
XX! #include <sys/types.h>
XX! #include <sys/stat.h>
XX  #include <errno.h>
XX+ #include <fcntl.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX+ #include <utime.h>
XX  #include <stdio.h>
XX  
XX  #define MAX_ERROR 4
XX  
XX! int errct, subtest, passes;
XX  
XX+ _PROTOTYPE(int main, (int argc, char *argv []));
XX+ _PROTOTYPE(void test16a, (void));
XX+ _PROTOTYPE(void get_times, (char *name, time_t *a, time_t *c, time_t *m));
XX+ _PROTOTYPE(void e, (int n));
XX+ _PROTOTYPE(void quit, (void));
XX  
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   int i, m;
XX  
XX!   m = (argc == 2 ? atoi(argv[1]) : 0xFFFF);
XX  
XX!   system("rm -rf DIR_16; mkdir DIR_16");
XX!   chdir("DIR_16");
XX  
XX!   printf("Test 16 ");
XX!   fflush(stdout);
XX!   for (i = 0; i < 4; i++) {
XX! 	if (m & 0001) test16a();
XX! 	passes++;
XX    }
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX  
XX! void test16a()
XX  {
XX+ /* Test atime, ctime, and mtime. */
XX  
XX!   int fd, fd1, fd2, fd3, fd4;
XX!   time_t a, c, m, pa, pc, pm, xa, xc, xm, ya, yc, ym, za, zc, zm, ta, tc, tm;
XX!   time_t wa, wc, wm;
XX!   char buf[1024];
XX!   struct stat s;
XX  
XX!   subtest = 1;
XX!   if (passes > 0) return;	/* takes too long to repeat this test */
XX  
XX!   if ( (fd = creat("T16.a", 0666)) < 0) e(1);
XX!   if (write(fd, buf, 1024) != 1024) e(2);
XX!   if (close(fd) < 0) e(3);
XX!   sleep(1);			/* wait 1 sec before continuing */
XX!   if ( (fd = open("T16.a", O_RDONLY)) < 0) e(4);
XX!   if (read(fd, buf, 3) != 3) e(5);
XX!   if (close(fd) != 0) e(6);
XX!   if (stat("T16.a", &s) != 0) e(7);
XX!   a = s.st_atime;
XX!   c = s.st_ctime;
XX!   m = s.st_mtime;
XX!   if (a == 0) {
XX! 	/* Almost certainly means we are running a V1 file system. */
XX! 	printf(" (atime = 0. Probably V1 file system.  V2 tests skipped.) ");
XX! 	return;
XX    }
XX  
XX!   /* Many system calls affect atime, ctime, and mtime.  Test them.  They
XX!    * fall into several groups.  The members of each group can be tested
XX!    * together.  Start with creat(), mkdir(), and mkfifo, all of which
XX!    * set all 3 times on the created object, and ctime and mtime of the dir.
XX!    */
XX!   if ( (fd = creat("T16.b", 0666)) < 0) e(8);
XX!   if (close(fd) != 0) e(9);
XX!   get_times("T16.b", &a, &c, &m);
XX!   get_times(".", &pa, &pc, &pm);
XX!   if (a != c) e(10);
XX!   if (a != m) e(11);
XX!   if (a != pc) e(12);
XX!   if (a != pm) e(13);
XX!   if (unlink("T16.b") < 0) e(14);
XX  
XX!   /* Test the times for mkfifo. */
XX!   if  ( (fd = mkfifo("T16.c", 0666)) != 0) e(15);
XX!   if (access("T16.c", R_OK | W_OK) != 0) e(16);
XX!   get_times("T16.c", &a, &c, &m);
XX!   get_times(".", &pa, &pc, &pm);
XX!   if (a != c) e(17);
XX!   if (a != m) e(18);
XX!   if (a != pc) e(19);
XX!   if (a != pm) e(20);
XX!   if (unlink("T16.c") < 0) e(21);
XX  
XX!   /* Test the times for mkdir. */
XX!   if (mkdir("T16.d", 0666) < 0) e(22);
XX!   get_times("T16.d", &a, &c, &m);
XX!   get_times(".", &pa, &pc, &pm);
XX!   if (a != c) e(23);
XX!   if (a != m) e(24);
XX!   if (a != pc) e(25);
XX!   if (a != pm) e(26);
XX!   sleep(1);
XX!   if (rmdir("T16.d") < 0) e(27);
XX!   get_times(".", &xa, &xc, &xm);
XX!   if (c == xc) e(28);
XX!   if (m == xm) e(29);
XX!   if (xc != xm) e(30);
XX  
XX!   /* Test open(file, O_TRUNC). */
XX!   if ( (fd = open("T16.e", O_WRONLY|O_CREAT, 0666)) < 0) e(31);
XX!   if (write(fd, buf, 1024) != 1024) e(32);
XX!   if (close(fd) != 0) e(33);
XX!   get_times("T16.e", &a, &c, &m);
XX!   get_times(".", &pa, &pc, &pm);
XX!   sleep(1);
XX!   if ( (fd = open("T16.e", O_WRONLY|O_TRUNC)) < 0) e(34);
XX!   get_times("T16.e", &xa, &xc, &xm);
XX!   get_times(".", &ya, &yc, &ym);
XX!   if (c != m) e(35);
XX!   if (pc != pm) e(36);
XX!   if (c == xc) e(37);
XX!   if (m == xm) e(38);
XX!   if (yc != pc) e(39);
XX!   if (ym != pm) e(40);
XX!   if (close(fd) != 0) e(41);
XX  
XX!   /* Test the times for link/unlink. */
XX!   get_times("T16.e", &a, &c, &m);
XX!   get_times(".", &ya, &yc, &ym);
XX!   sleep(1);
XX!   if (link("T16.e", "T16.f") != 0) e(42);	/* second link */
XX!   get_times("T16.e", &xa, &xc, &xm);
XX!   get_times(".", &pa, &pc, &pm);
XX!   if (a != xa) e(43);
XX!   if (m != xm) e(44);
XX! #ifndef V1_FILESYSTEM
XX!   if (c == xc) e(45);
XX! #endif
XX!   if (ya != pa) e(46);
XX!   if (yc == pc) e(47);
XX!   if (ym == pm) e(48);
XX!   if (yc != ym) e(49);
XX!   if (pc != pm) e(50);
XX!   sleep(1);
XX!   if (unlink("T16.f") != 0) e(46);
XX!   get_times("T16.e", &a, &c, &m);
XX!   get_times(".", &ya, &yc, &ym);
XX!   if (a != xa) e(51);
XX!   if (m != xm) e(52);
XX! #ifndef V1_FILESYSTEM
XX!   if (c == xc) e(53);
XX! #endif
XX!   if (pa != ya) e(54);
XX!   if (pc == yc) e(55);
XX!   if (pm == ym) e(56);
XX!   if (yc != ym) e(57);
XX!   if (unlink("T16.e") != 0) e(58);
XX  
XX!   /* Test rename, read, write, chmod, utime. */
XX!   get_times(".", &pa, &pc, &pm);
XX!   if ( (fd  = open("T16.g", O_RDWR|O_CREAT)) < 0) e(59);
XX!   if ( (fd1 = open("T16.h", O_WRONLY|O_CREAT, 0666)) < 0) e(60);
XX!   if ( (fd2 = open("T16.i", O_WRONLY|O_CREAT, 0666)) < 0) e(61);
XX!   if ( (fd3 = open("T16.j", O_WRONLY|O_CREAT, 0666)) < 0) e(62);
XX!   if ( (fd4 = open("T16.k", O_RDWR|O_CREAT, 0666)) < 0) e(63);
XX!   if (write(fd, buf, 1024) != 1024) e(64);
XX!   get_times("T16.g", &a, &c, &m);
XX!   get_times("T16.h", &pa, &pc, &pm);
XX!   get_times("T16.i", &xa, &xc, &xm);
XX!   get_times("T16.j", &ya, &yc, &ym);
XX!   get_times("T16.k", &za, &zc, &zm);
XX!   get_times(".", &wa, &wc, &wm);
XX!   sleep(1);
XX!   lseek(fd, 0L, SEEK_SET);
XX!   if (read(fd, buf, 35) != 35) e(65);
XX!   get_times("T16.g", &ta, &tc, &tm);
XX!   if (a == ta || c != tc || m != tm) e(66);
XX!   if (write(fd1, buf, 35) != 35) e(67);
XX!   get_times("T16.h", &ta, &tc, &tm);
XX!   if (pa != ta || pc == tc || pm == tm) e(69);
XX!   if (rename("T16.i", "T16.i1") != 0) e(70);
XX!   get_times("T16.i1", &ta, &tc, &tm);
XX!   if (xa != ta || xc != tc || xm != tm) e(71);
XX!   get_times(".", &a, &c, &m);
XX!   if (a != wa || c == wc || m == wm || wc != wm) e(72);
XX!   if (chmod("T16.j", 0777) != 0) e(73);
XX!   get_times("T16.j", &ta, &tc, &tm);
XX!   if (ya != ta || yc == tc || ym != tm) e(74);
XX!   if (utime("T16.k", (void *) 0) != 0) e(75);
XX!   get_times("T16.k", &ta, &tc, &tm);
XX!   if (za == ta || zc == tc) e(76);
XX!   if (close(fd) != 0) e(77);
XX!   if (close(fd1) != 0) e(78);
XX!   if (close(fd2) != 0) e(79);
XX!   if (close(fd3) != 0) e(80);
XX!   if (close(fd4) != 0) e(81);
XX!   if (unlink("T16.g") != 0) e(82); 
XX!   if (unlink("T16.h") != 0) e(83); 
XX!   if (unlink("T16.i1") != 0) e(84); 
XX!   if (unlink("T16.j") != 0) e(85); 
XX!   if (unlink("T16.k") != 0) e(86); 
XX  }
XX  
XX  
XX! void get_times(name, a, c, m)
XX! char *name;
XX! time_t *a, *c, *m;
XX  {
XX!   struct stat s;
XX  
XX!   if (stat(name, &s) != 0) e(500);
XX!   *a = s.st_atime;
XX!   *c = s.st_ctime;
XX!   *m = s.st_mtime;
XX  }
XX  
XX  
XX  
XX! void e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX***************
XX*** 309,314 ****
XX--- 232,255 ----
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX  	exit(1);
XX    }
XX  }
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX+ 	exit(1);
XX+   }
XX+ }
XX+ 
X/
Xecho x - test17.c.d
Xsed '/^X/s///' > test17.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test17.c  crc=41596  38494	Sat May  5 13:16:07 1990
XX--- /home/top/ast/minix/1.6.25/test/test17.c  crc=27502  31446	Fri Mar 19 21:25:03 1993
XX***************
XX*** 2,16 ****
XX  
XX  /* "const.h", created by Rene Montsma and Menno Wilcke */
XX  
XX- 
XX  #include <sys/types.h>		/* type defs */
XX  #include <sys/stat.h>		/* struct stat */
XX  #include <errno.h>		/* the error-numbers */
XX  #include <fcntl.h>
XX  #include <unistd.h>
XX  
XX  #define NOCRASH 1		/* test11(), 2nd pipe */
XX  #define PDPNOHANG  1		/* test03(), write_standards() */
XX  
XX  #define USER_ID   12
XX  #define GROUP_ID   1
XX--- 2,21 ----
XX  
XX  /* "const.h", created by Rene Montsma and Menno Wilcke */
XX  
XX  #include <sys/types.h>		/* type defs */
XX  #include <sys/stat.h>		/* struct stat */
XX+ #include <sys/wait.h>
XX  #include <errno.h>		/* the error-numbers */
XX  #include <fcntl.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX  #include <unistd.h>
XX+ #include <utime.h>
XX+ #include <stdio.h>
XX  
XX  #define NOCRASH 1		/* test11(), 2nd pipe */
XX  #define PDPNOHANG  1		/* test03(), write_standards() */
XX+ #define MAXERR 2
XX  
XX  #define USER_ID   12
XX  #define GROUP_ID   1
XX***************
XX*** 19,34 ****
XX  #define GROUP     0		/* gid */
XX  
XX  #define ARSIZE   256		/* array size */
XX! #define PIPESIZE 3584		/* maximum number of bytes to be * written on
XX! 			 * pipe               */
XX! 
XX  #define MAXOPEN  17		/* maximum number of extra open files */
XX- 
XX  #define MAXLINK 0177		/* maximum number of links per file */
XX  #define LINKCOUNT 5
XX- 
XX  #define MASK    0777		/* selects lower nine bits */
XX- 
XX  #define END_FILE     0		/* returned by read-call at eof */
XX  
XX  #define OK      0
XX--- 24,34 ----
XX  #define GROUP     0		/* gid */
XX  
XX  #define ARSIZE   256		/* array size */
XX! #define PIPESIZE 3584		/* max number of bytes to be written on pipe */
XX  #define MAXOPEN  17		/* maximum number of extra open files */
XX  #define MAXLINK 0177		/* maximum number of links per file */
XX  #define LINKCOUNT 5
XX  #define MASK    0777		/* selects lower nine bits */
XX  #define END_FILE     0		/* returned by read-call at eof */
XX  
XX  #define OK      0
XX***************
XX*** 59,71 ****
XX  #define DUP     "dup"
XX  #define UTIME   "utime"
XX  
XX- extern int errno;		/* the error-number */
XX  int errct;
XX  
XX- long lseek();
XX- 
XX  char *file[];
XX- extern char *strcpy(), *strcat();
XX  char *fnames[];
XX  char *dir[];
XX  
XX--- 59,67 ----
XX***************
XX*** 81,120 ****
XX  
XX  /* "test.c", created by Rene Montsma and Menno Wilcke */
XX  
XX  
XX  /*****************************************************************************
XX   *                              TEST                                         *
XX   ****************************************************************************/
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX    int n, mask;
XX  
XX    mask = (argc == 2 ? atoi(argv[1]) : 0xFFFF);
XX  
XX    if (fork()) {
XX  	printf("Test 17 ");
XX  
XX  	wait(&n);
XX  	clean_up_the_mess();
XX! 	if (errct == 0)
XX! 		printf("ok\n");
XX! 	else
XX! 		printf("%d errors\n", errct);
XX! 	exit(0);
XX    } else {
XX  	test(mask);
XX  	exit(0);
XX    }
XX  }
XX  
XX! 
XX! 
XX! test(mask)
XX  int mask;
XX  {
XX-   int n;
XX    umask(0);			/* not honest, but i always forget */
XX  
XX    if (mask & 00001) test01();
XX--- 77,153 ----
XX  
XX  /* "test.c", created by Rene Montsma and Menno Wilcke */
XX  
XX+ _PROTOTYPE(int main, (int argc, char *argv []));
XX+ _PROTOTYPE(void test, (int mask));
XX+ _PROTOTYPE(void test01, (void));
XX+ _PROTOTYPE(void test02, (void));
XX+ _PROTOTYPE(void test08, (void));
XX+ _PROTOTYPE(void test09, (void));
XX+ _PROTOTYPE(void test10, (void));
XX+ _PROTOTYPE(int link_alot, (char *bigboss));
XX+ _PROTOTYPE(int unlink_alot, (int number));
XX+ _PROTOTYPE(void get_new, (char name []));
XX+ _PROTOTYPE(void test11, (void));
XX+ _PROTOTYPE(void comp_stats, (struct stat *stbf1, struct stat *stbf2));
XX+ _PROTOTYPE(void comp_inodes, (int m, int m1));
XX+ _PROTOTYPE(void e, (char *string));
XX+ _PROTOTYPE(void nlcr, (void));
XX+ _PROTOTYPE(void str, (char *s));
XX+ _PROTOTYPE(void err, (int number, char *scall, char *name));
XX+ _PROTOTYPE(void make_and_fill_dirs, (void));
XX+ _PROTOTYPE(void put_file_in_dir, (char *dirname, int mode));
XX+ _PROTOTYPE(void init_array, (char *a));
XX+ _PROTOTYPE(void clear_array, (char *b));
XX+ _PROTOTYPE(int comp_array, (char *a, char *b, int range));
XX+ _PROTOTYPE(void try_close, (int filedes, char *name));
XX+ _PROTOTYPE(void try_unlink, (char *fname));
XX+ _PROTOTYPE(void Remove, (int fdes, char *fname));
XX+ _PROTOTYPE(int get_mode, (char *name));
XX+ _PROTOTYPE(void check, (char *scall, int number));
XX+ _PROTOTYPE(void put, (int nr));
XX+ _PROTOTYPE(int open_alot, (void));
XX+ _PROTOTYPE(int close_alot, (int number));
XX+ _PROTOTYPE(void clean_up_the_mess, (void));
XX+ _PROTOTYPE(void chmod_8_dirs, (int sw));
XX+ _PROTOTYPE(void quit, (void));
XX  
XX  /*****************************************************************************
XX   *                              TEST                                         *
XX   ****************************************************************************/
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX    int n, mask;
XX  
XX+   sync();
XX+   if (geteuid() == 0 || getuid() == 0) {
XX+ 	printf("Test 17 cannot run as root; test aborted\n");
XX+ 	exit(1);
XX+   }
XX+ 
XX+   system("rm -rf DIR_18; mkdir DIR_18");
XX+   chdir("DIR_18");
XX+ 
XX    mask = (argc == 2 ? atoi(argv[1]) : 0xFFFF);
XX  
XX    if (fork()) {
XX  	printf("Test 17 ");
XX+ 	fflush(stdout);
XX  
XX  	wait(&n);
XX  	clean_up_the_mess();
XX! 	quit();
XX    } else {
XX  	test(mask);
XX  	exit(0);
XX    }
XX+   return(-1);			/* impossible */
XX  }
XX  
XX! void test(mask)
XX  int mask;
XX  {
XX    umask(0);			/* not honest, but i always forget */
XX  
XX    if (mask & 00001) test01();
XX***************
XX*** 124,146 ****
XX    if (mask & 00020) test09();
XX    if (mask & 00040) test10();
XX    if (mask & 00100) test11();
XX-   if (mask & 00200) test12();
XX-   if (mask & 00400) test13();
XX-   if (mask & 01000) test14();
XX    umask(022);
XX  }				/* test */
XX  
XX  
XX  
XX- 
XX- 
XX- 
XX  /* "t1.c" created by Rene Montsma and Menno Wilcke */
XX  
XX  /*****************************************************************************
XX   *                              test UMASK                                   *
XX   ****************************************************************************/
XX! test01()
XX  {
XX    int oldvalue, newvalue, tempvalue;
XX    int nr;
XX--- 157,173 ----
XX    if (mask & 00020) test09();
XX    if (mask & 00040) test10();
XX    if (mask & 00100) test11();
XX    umask(022);
XX  }				/* test */
XX  
XX  
XX  
XX  /* "t1.c" created by Rene Montsma and Menno Wilcke */
XX  
XX  /*****************************************************************************
XX   *                              test UMASK                                   *
XX   ****************************************************************************/
XX! void test01()
XX  {
XX    int oldvalue, newvalue, tempvalue;
XX    int nr;
XX***************
XX*** 156,162 ****
XX  
XX    if ((tempvalue = umask(0)) != 0) err(2, UMASK, "values");
XX  
XX- 
XX    /* Now test all possible modes of umask on a file */
XX    for (newvalue = MASK; newvalue >= 0; newvalue -= 0111) {
XX  	tempvalue = umask(newvalue);
XX--- 183,188 ----
XX***************
XX*** 179,190 ****
XX  	err(7, UMASK, "umask may influence rest of tests!");
XX  }				/* test01 */
XX  
XX- 
XX- 
XX  /*****************************************************************************
XX   *                              test CREAT                                   *
XX   ****************************************************************************/
XX! test02()
XX  {
XX    int n, n1, mode;
XX    char a[ARSIZE], b[ARSIZE];
XX--- 205,214 ----
XX  	err(7, UMASK, "umask may influence rest of tests!");
XX  }				/* test01 */
XX  
XX  /*****************************************************************************
XX   *                              test CREAT                                   *
XX   ****************************************************************************/
XX! void test02()
XX  {
XX    int n, n1, mode;
XX    char a[ARSIZE], b[ARSIZE];
XX***************
XX*** 259,265 ****
XX  		try_close(n1, "recreated 'file02'");
XX  
XX  	}
XX! 	remove(n, "file02");
XX    }
XX  
XX    /* Give 'creat' wrong input: dir not searchable */
XX--- 283,289 ----
XX  		try_close(n1, "recreated 'file02'");
XX  
XX  	}
XX! 	Remove(n, "file02");
XX    }
XX  
XX    /* Give 'creat' wrong input: dir not searchable */
XX***************
XX*** 284,292 ****
XX    if ((n = creat("dir", 040777)) != FAIL) {
XX  	if (fstat(n, &stbf1) != OK)
XX  		err(5, FSTAT, "'dir'");
XX! 	else if (stbf1.st_mode != 0100777)
XX  		err(11, CREAT, "'creat' a new directory");
XX! 	remove(n, "dir");
XX    }
XX  
XX    /* We don't consider it to be a bug when creat * does not accept
XX--- 308,317 ----
XX    if ((n = creat("dir", 040777)) != FAIL) {
XX  	if (fstat(n, &stbf1) != OK)
XX  		err(5, FSTAT, "'dir'");
XX! 	else if (stbf1.st_mode != (mode_t) 0100777)
XX! 				/* cast because mode is negative :-( */
XX  		err(11, CREAT, "'creat' a new directory");
XX! 	Remove(n, "dir");
XX    }
XX  
XX    /* We don't consider it to be a bug when creat * does not accept
XX***************
XX*** 301,320 ****
XX  
XX  
XX  
XX! 
XX! 
XX! 
XX! test08()
XX  {
XX- 
XX- 
XX    /* Test chdir to searchable dir */
XX    if (chdir("drwx") != OK)
XX  	err(5, CHDIR, "to accessible dir");
XX    else if (chdir("..") != OK)
XX  	err(11, CHDIR, "not return to '..'");
XX  
XX- 
XX    /* Check the chdir(".") and chdir("..") mechanism */
XX    if (chdir("drwx") != OK)
XX  	err(5, CHDIR, "to 'drwx'");
XX--- 326,339 ----
XX  
XX  
XX  
XX! void test08()
XX  {
XX    /* Test chdir to searchable dir */
XX    if (chdir("drwx") != OK)
XX  	err(5, CHDIR, "to accessible dir");
XX    else if (chdir("..") != OK)
XX  	err(11, CHDIR, "not return to '..'");
XX  
XX    /* Check the chdir(".") and chdir("..") mechanism */
XX    if (chdir("drwx") != OK)
XX  	err(5, CHDIR, "to 'drwx'");
XX***************
XX*** 352,372 ****
XX    else
XX  	check(CHDIR, EACCES);
XX  
XX- 
XX- 
XX    /* To be sure: return to root */
XX    /* If (chdir("/") != OK) err(5, CHDIR, "to '/' (2nd time)"); */
XX  }				/* test08 */
XX  
XX- 
XX- 
XX  /* New page */
XX  /*****************************************************************************
XX   *                              test CHMOD                                   *
XX   ****************************************************************************/
XX! test09()
XX  {
XX- 
XX    int n;
XX  
XX    /* Prepare file09 */
XX--- 371,386 ----
XX    else
XX  	check(CHDIR, EACCES);
XX  
XX    /* To be sure: return to root */
XX    /* If (chdir("/") != OK) err(5, CHDIR, "to '/' (2nd time)"); */
XX  }				/* test08 */
XX  
XX  /* New page */
XX  /*****************************************************************************
XX   *                              test CHMOD                                   *
XX   ****************************************************************************/
XX! void test09()
XX  {
XX    int n;
XX  
XX    /* Prepare file09 */
XX***************
XX*** 392,398 ****
XX  		err(7, CHMOD, "restored mode");
XX    }
XX  
XX!   /* Try setid and setgid */
XX    if ((chmod("file09", 04777) != OK) || (get_mode("file09") != 04777))
XX  	err(11, CHMOD, "not set uid-bit");
XX    if ((chmod("file09", 02777) != OK) || (get_mode("file09") != 02777))
XX--- 406,412 ----
XX  		err(7, CHMOD, "restored mode");
XX    }
XX  
XX!   /* Try setuid and setgid */
XX    if ((chmod("file09", 04777) != OK) || (get_mode("file09") != 04777))
XX  	err(11, CHMOD, "not set uid-bit");
XX    if ((chmod("file09", 02777) != OK) || (get_mode("file09") != 02777))
XX***************
XX*** 403,409 ****
XX  
XX    if (chdir("..") != OK) err(5, CHDIR, "to '..'");
XX  
XX- 
XX    /* Try to chmod directory */
XX    if (chmod("d---", 0777) != OK)
XX  	err(5, CHMOD, "dir 'd---'");
XX--- 417,422 ----
XX***************
XX*** 427,445 ****
XX  
XX  }				/* test 09 */
XX  
XX- 
XX  /* New page */
XX  
XX  
XX- 
XX- 
XX  /* "t4.c", created by Rene Montsma and Menno Wilcke */
XX  
XX- 
XX  /*****************************************************************************
XX   *                              test LINK/UNLINK                             *
XX   ****************************************************************************/
XX! test10()
XX  {
XX    int n, n1;
XX    char a[ARSIZE], b[ARSIZE], *f, *lf;
XX--- 440,454 ----
XX  
XX  }				/* test 09 */
XX  
XX  /* New page */
XX  
XX  
XX  /* "t4.c", created by Rene Montsma and Menno Wilcke */
XX  
XX  /*****************************************************************************
XX   *                              test LINK/UNLINK                             *
XX   ****************************************************************************/
XX! void test10()
XX  {
XX    int n, n1;
XX    char a[ARSIZE], b[ARSIZE], *f, *lf;
XX***************
XX*** 450,456 ****
XX    if ((n = creat(f, 0702)) != FF)	/* no other open files */
XX  	err(13, CREAT, f);
XX    else {
XX- 
XX  	/* Now link correctly */
XX  	if (link(f, lf) != OK)
XX  		err(5, LINK, lf);
XX--- 459,464 ----
XX***************
XX*** 467,473 ****
XX  		if (comp_array(a, b, ARSIZE) != OK) err(8, "r/w", NIL);
XX  
XX  		/* Clean up: unlink and close (twice): */
XX! 		remove(n, f);
XX  		try_close(n1, "'linkfile10'");
XX  
XX  		/* Check if "linkfile" exists and the info    * on it
XX--- 475,481 ----
XX  		if (comp_array(a, b, ARSIZE) != OK) err(8, "r/w", NIL);
XX  
XX  		/* Clean up: unlink and close (twice): */
XX! 		Remove(n, f);
XX  		try_close(n1, "'linkfile10'");
XX  
XX  		/* Check if "linkfile" exists and the info    * on it
XX***************
XX*** 508,514 ****
XX    else
XX  	check(UNLINK, EPERM);
XX  
XX- 
XX    /* Try giving link wrong input */
XX  
XX    /* First try if link fails with incorrect parameters * name1 does not
XX--- 516,521 ----
XX***************
XX*** 536,542 ****
XX    else
XX  	check(LINK, EPERM);
XX  
XX- 
XX    /* File has too many links */
XX    if ((n = link_alot("drwx/rwx")) != LINKCOUNT - 1)	/* file already has one
XX  							 * link */
XX--- 543,548 ----
XX***************
XX*** 546,559 ****
XX  }				/* test10 */
XX  
XX  
XX! 
XX! 
XX! 
XX! link_alot(bigboss)
XX  char *bigboss;
XX  {
XX    int i;
XX!   char *employee = {"aaaaa"};
XX  
XX    /* Every file has already got 1 link, so link 0176 times */
XX    for (i = 1; i < LINKCOUNT; i++) {
XX--- 552,562 ----
XX  }				/* test10 */
XX  
XX  
XX! int link_alot(bigboss)
XX  char *bigboss;
XX  {
XX    int i;
XX!   static char employee[6] = "aaaaa";
XX  
XX    /* Every file has already got 1 link, so link 0176 times */
XX    for (i = 1; i < LINKCOUNT; i++) {
XX***************
XX*** 566,577 ****
XX    return(i - 1);		/* number of linked files */
XX  }				/* link_alot */
XX  
XX! 
XX! unlink_alot(number)
XX  int number;			/* number of files to be unlinked */
XX  {
XX    int j;
XX!   char *employee = {"aaaaa"};
XX  
XX    for (j = 0; j < number; j++) {
XX  	if (unlink(employee) != OK)
XX--- 569,579 ----
XX    return(i - 1);		/* number of linked files */
XX  }				/* link_alot */
XX  
XX! int unlink_alot(number)
XX  int number;			/* number of files to be unlinked */
XX  {
XX    int j;
XX!   static char employee[6] = "aaaaa";
XX  
XX    for (j = 0; j < number; j++) {
XX  	if (unlink(employee) != OK)
XX***************
XX*** 583,590 ****
XX    return(j);			/* return number of unlinked files */
XX  }				/* unlink_alot */
XX  
XX! 
XX! get_new(name)
XX  char name[];
XX   /* Every call changes string 'name' to a string alphabetically          *
XX    * higher. Start with "aaaaa", next value: "aaaab" .                    *
XX--- 585,591 ----
XX    return(j);			/* return number of unlinked files */
XX  }				/* unlink_alot */
XX  
XX! void get_new(name)
XX  char name[];
XX   /* Every call changes string 'name' to a string alphabetically          *
XX    * higher. Start with "aaaaa", next value: "aaaab" .                    *
XX***************
XX*** 592,598 ****
XX    * The last possibility will be "zzzzz".                                *
XX    * Total # possibilities: 26+25*4 = 126 = MAXLINK -1 (exactly needed)   */
XX  {
XX- 
XX    int i;
XX  
XX    for (i = 4; i >= 0; i--)
XX--- 593,598 ----
XX***************
XX*** 607,613 ****
XX  /*****************************************************************************
XX   *                              test PIPE                                    *
XX   ****************************************************************************/
XX! test11()
XX  {
XX    int n, fd[2];
XX    char a[ARSIZE], b[ARSIZE];
XX--- 607,613 ----
XX  /*****************************************************************************
XX   *                              test PIPE                                    *
XX   ****************************************************************************/
XX! void test11()
XX  {
XX    int n, fd[2];
XX    char a[ARSIZE], b[ARSIZE];
XX***************
XX*** 695,807 ****
XX    if (close_alot(n) != n) err(5, CLOSE, "all opened files");
XX  }				/* test11 */
XX  
XX- 
XX  /* New page */
XX  
XX- /*****************************************************************************
XX-  *                              test STAT/FSTAT                              *
XX-  ****************************************************************************/
XX- test12()
XX- {
XX  
XX!   struct stat stbf1, stbf2;
XX!   int n, n1;
XX!   char a[ARSIZE];
XX! 
XX! 
XX!   /* We now consecutively test after OPEN, CREAT, DUP, PIPE */
XX! 
XX!   /* Test after a CREAT */
XX!   if ((n = creat("file12", 0702)) != FF)	/* no other open files left */
XX! 	err(5, CREAT, "'file12'");
XX!   if (fstat(n, &stbf1) < 0)
XX! 	err(5, FSTAT, "'file12'");
XX!   else {
XX! 	if (stbf1.st_mode != 0100702) err(7, FSTAT, "mode");
XX! 	if (stbf1.st_nlink != 1) err(7, FSTAT, "nlink");
XX! 	if (stbf1.st_size != 0L) err(7, FSTAT, "size");
XX! 
XX! 	if (stat("file12", &stbf2) < 0)
XX! 		err(5, STAT, "'file12'");
XX! 	else
XX! 		comp_stats(&stbf1, &stbf2);	/* 'stat' & 'fstat'
XX! 						 * should deliver * the
XX! 						 * same information            */
XX!   }
XX!   try_close(n, "'file12'");
XX! 
XX!   /* Test after OPEN */
XX!   /* Prepare */
XX!   if (link("file12", "linkfile12") < 0) err(5, LINK, "'linkfile12'");
XX!   if ((n1 = open("linkfile12", RW)) < 0)
XX! 	err(5, OPEN, "'linkfile12'");
XX!   else {
XX! 	/* Give linkfile information */
XX! 	init_array(a);
XX! 	if (write(n1, a, ARSIZE) != ARSIZE) err(5, WRITE, "'linkfile12'");
XX! 
XX! 	try_close(n1, "'linkfile12'");
XX!   }
XX! 
XX! 
XX!   if (stat("file12", &stbf1) < 0)
XX! 	err(5, STAT, "'file12'");
XX!   else {
XX! 	if (stbf1.st_mode != 0100702) err(7, STAT, "mode");
XX! 	if (stbf1.st_nlink != 2) err(7, STAT, "nlink");
XX! 	if (stbf1.st_size != ((long) (ARSIZE))) err(7, STAT, "size");
XX! 
XX! 	if ((n1 = open("linkfile12", RW)) < 0)
XX! 		err(5, OPEN, "'linkfile12' (2nd time)");
XX! 
XX! 	if (fstat(n1, &stbf2) < 0)
XX! 		err(5, FSTAT, "'linkfile12'");
XX! 	else
XX! 		comp_stats(&stbf1, &stbf2);	/* should be equal */
XX! 
XX! 	try_close(n1, "'linkfile12'");
XX!   }
XX! 
XX!   /* Test after a DUP */
XX!   if ((n = open("file12", RW)) < 0) err(5, OPEN, "'file12'");
XX!   if ((n1 = dup(n)) < 0)
XX! 	err(5, DUP, "'file12'");
XX!   else {
XX! 	if (fstat(n1, &stbf2) < 0)
XX! 		err(5, FSTAT, "duplicated fd 'file12'");
XX! 	else
XX! 		comp_stats(&stbf1, &stbf2);
XX! 	/* Stbf1 remained from OPEN test */
XX! 
XX! 	try_close(n1, "duplicated fd 'file12'");
XX!   }
XX! 
XX! 
XX!   /* Remove testfile */
XX!   remove(n, "file12");
XX! 
XX!   /* Remove linkfile */
XX!   try_unlink("linkfile12");
XX! 
XX!   /* Try giving stat wrong input */
XX!   /* First see if stat fails with incorrect input: non-existing file */
XX!   if (stat("non-file", &stbf1) != FAIL)
XX! 	err(3, STAT, NIL);
XX!   else
XX! 	check(STAT, ENOENT);
XX! 
XX!   /* Non-accessible file: dir's not searchable */
XX!   if (stat("drw-/rwx", &stbf1) != FAIL)
XX! 	err(4, STAT, "'a'");
XX!   else
XX! 	check(STAT, EACCES);
XX! }				/* test12 */
XX! 
XX! 
XX! comp_stats(stbf1, stbf2)
XX  struct stat *stbf1, *stbf2;
XX  {
XX- 
XX    if (stbf1->st_dev != stbf2->st_dev) err(7, "st/fst", "'dev'");
XX    if (stbf1->st_ino != stbf2->st_ino) err(7, "st/fst", "'ino'");
XX    if (stbf1->st_mode != stbf2->st_mode) err(7, "st/fst", "'mode'");
XX--- 695,706 ----
XX    if (close_alot(n) != n) err(5, CLOSE, "all opened files");
XX  }				/* test11 */
XX  
XX  /* New page */
XX  
XX  
XX! void comp_stats(stbf1, stbf2)
XX  struct stat *stbf1, *stbf2;
XX  {
XX    if (stbf1->st_dev != stbf2->st_dev) err(7, "st/fst", "'dev'");
XX    if (stbf1->st_ino != stbf2->st_ino) err(7, "st/fst", "'ino'");
XX    if (stbf1->st_mode != stbf2->st_mode) err(7, "st/fst", "'mode'");
XX***************
XX*** 814,937 ****
XX    if (stbf1->st_mtime != stbf2->st_mtime) err(7, "st/fst", "'mtime'");
XX  }				/* comp_stats */
XX  
XX- 
XX  /* New page */
XX  
XX  
XX- 
XX- 
XX  /* "t5.c", created by Rene Montsma and Menno Wilcke */
XX  
XX  
XX- /*****************************************************************************
XX-  *                              test DUP                                     *
XX-  ****************************************************************************/
XX- test13()
XX- {
XX-   int n, n1, i, fd[4];
XX-   char a[ARSIZE], b[ARSIZE];
XX  
XX! 
XX!   /* We consecutively test 'dup' after CREAT, OPEN, PIPE */
XX! 
XX!   /* Test dup after a CREAT */
XX!   if ((n = creat("file13", 0777)) != FF)	/* no other open files left */
XX! 	err(13, CREAT, "'file13'");
XX!   else {
XX! 	if ((n1 = dup(n)) != n + 1) err(13, DUP, "dupped 'file13'");
XX! 	comp_inodes(n, n1);	/* should point to the same inode */
XX! 	try_close(n, "'file13'");
XX! 	try_close(n1, "duplicated fd 'file13'");
XX!   }
XX! 
XX!   /* Now test with correct values with filedes returned from an * OPEN
XX!    * call                                                  */
XX!   if ((n = open("file13", RW)) < 0)
XX! 	err(5, OPEN, "'file13'");
XX!   else {
XX! 	if ((n1 = dup(n)) != n + 1)
XX! 		err(13, DUP, "dupped fd 'file13'");
XX! 	else {
XX! 		comp_inodes(n, n1);
XX! 		try_close(n1, "duplicated 'file13'");
XX! 	}
XX! 	try_close(n, "'file13'");
XX!   }
XX! 
XX!   /* Test with correct values after a  PIPE */
XX!   if (pipe(fd) < 0)
XX! 	err(5, DUP, NIL);
XX!   else if ((fd[2] = dup(fd[0])) < 0)
XX! 	err(5, DUP, "pipe 'fd[0]'");
XX!   else {
XX! 	comp_inodes(fd[0], fd[2]);
XX! 
XX! 	if ((fd[3] = dup(fd[1])) < 0)
XX! 		err(5, DUP, "pipe 'fd[1]'");
XX! 	else
XX! 		comp_inodes(fd[1], fd[3]);
XX! 
XX! 	for (i = 0; i < 4; i++) try_close(fd[i], "a filedes");
XX!   }
XX! 
XX!   /* Try writing and reading */
XX!   if ((n = open("file13", RW)) < 0) err(5, OPEN, "'file13' 3rd time");
XX!   if ((n1 = dup(n)) != n + 1)
XX! 	err(13, DUP, "dupped 'file13' 2nd time");
XX!   else {
XX! 	init_array(a);
XX! 	clear_array(b);
XX! 
XX! 	if (write(n, a, ARSIZE) != ARSIZE) err(1, WRITE, "bad");
XX! 
XX! 	/* Set filedes back to be ready for a read */
XX! 	if (lseek(n1, 0L, SEEK_SET) != 0)
XX! 		err(5, LSEEK, "to beginning of 'file13'");
XX! 
XX! 	if (read(n1, b, ARSIZE / 2) != ARSIZE / 2) err(1, READ, "bad");
XX! 	if (comp_array(a, b, ARSIZE / 2) != OK)
XX! 		err(7, DUP, "values read/written");
XX! 
XX! 	clear_array(b);
XX! 	if (lseek(n1, 0L, SEEK_SET) != 0L)
XX! 		err(5, LSEEK, "to beginning of 'file13 (2nd time)'");
XX! 	if (read(n, b, ARSIZE) != ARSIZE) err(1, READ, "bad");
XX! 	if (comp_array(a, b, ARSIZE) != OK)
XX! 		err(7, DUP, "values read/written (2nd time)");
XX! 
XX! 	try_close(n1, "duplicated fd 'file13'");
XX!   }
XX! 
XX!   /* Remove testfile */
XX!   remove(n, "file13");
XX! 
XX!   /* Try giving dup wrong input */
XX! 
XX!   /* Does dup take care of many open files ? */
XX!   if ((n = open_alot()) != MAXOPEN)
XX! 	err(5, OPEN, "MAXOPEN files");
XX!   else if (dup(n) != FAIL)
XX! 	err(9, DUP, "open");
XX!   else
XX! 	check(DUP, EMFILE);
XX!   if (close_alot(n) != n) err(5, CLOSE, "all opened files");
XX! 
XX!   /* Try to make dup accept illegal values */
XX!   if ((n1 = dup(-1)) != FAIL)
XX! 	err(2, DUP, "filedes");
XX!   else
XX! 	check(DUP, EBADF);
XX!   if ((n1 = dup(MAXOPEN)) != FAIL)
XX! 	err(7, DUP, "filedes");
XX!   else
XX! 	check(DUP, EBADF);
XX! }				/* test13 */
XX! 
XX! 
XX! 
XX! 
XX! 
XX! comp_inodes(m, m1)
XX  int m, m1;			/* twee filedes's */
XX  {
XX    struct stat stbf1, stbf2;
XX--- 713,726 ----
XX    if (stbf1->st_mtime != stbf2->st_mtime) err(7, "st/fst", "'mtime'");
XX  }				/* comp_stats */
XX  
XX  /* New page */
XX  
XX  
XX  /* "t5.c", created by Rene Montsma and Menno Wilcke */
XX  
XX  
XX  
XX! void comp_inodes(m, m1)
XX  int m, m1;			/* twee filedes's */
XX  {
XX    struct stat stbf1, stbf2;
XX***************
XX*** 946,1111 ****
XX  	err(100, "comp_inodes", "cannot 'fstat' (m)");
XX  }				/* comp_inodes */
XX  
XX- /* New page */
XX- /*****************************************************************************
XX-  *                              test UTIME                                   *
XX-  ****************************************************************************/
XX- test14()
XX- {
XX-   int n;
XX-   long oldmtime;
XX-   time_t timep[2];
XX-   struct stat stbf1;
XX- 
XX-   if ((n = creat("file14", 0777)) != FF)	/* no other open files left */
XX- 	err(5, CREAT, "'file14'");
XX-   else {
XX- 	if (fstat(n, &stbf1) != OK)
XX- 		err(5, FSTAT, "'file14'");
XX- 	else
XX- 		oldmtime = stbf1.st_mtime;
XX- 
XX- 	/* N.B. We have noticed that the field 'atime' does not
XX- 	 * exist,  * but we decided not to mention it as a bug.                   */
XX- 
XX- 	timep[0] = oldmtime - 1;
XX- 	timep[1] = oldmtime - 2;
XX- 	/* Change inode-info of 'file04' */
XX- 	if (utime("file14", timep) != OK)
XX- 		err(5, UTIME, "'file14'");
XX- 	else
XX- 	 /* Check if values in inode have been altered */ if (fstat(n, &stbf1) != OK)
XX- 		err(5, FSTAT, "'file14' (2nd time)");
XX- 	else if (stbf1.st_mtime != oldmtime - 2)
XX- 		err(7, UTIME, "st_mtime");
XX- 	remove(n, "file14");
XX-   }
XX- 
XX- 
XX-   /* Try giving utime wrong input */
XX-   if (utime("non-file", timep) != FAIL)
XX- 	err(3, UTIME, NIL);
XX-   else
XX- 	check(UTIME, ENOENT);
XX- }				/* test14 */
XX- 
XX- access_standards()
XX- {
XX-   int i, mode = 0;
XX- 
XX-   for (i = 0; i < 8; i++)
XX- 	if (i == 0)
XX- 		try_access(fnames[mode], i, OK);
XX- 	else
XX- 		try_access(fnames[mode], i, FAIL);
XX-   mode++;
XX- 
XX-   for (i = 0; i < 8; i++)
XX- 	if (i < 2)
XX- 		try_access(fnames[mode], i, OK);
XX- 	else
XX- 		try_access(fnames[mode], i, FAIL);
XX-   mode++;
XX- 
XX-   for (i = 0; i < 8; i++)
XX- 	if (i == 0 || i == 2)
XX- 		try_access(fnames[mode], i, OK);
XX- 	else
XX- 		try_access(fnames[mode], i, FAIL);
XX-   mode++;
XX- 
XX-   for (i = 0; i < 8; i++)
XX- 	if (i < 4)
XX- 		try_access(fnames[mode], i, OK);
XX- 	else
XX- 		try_access(fnames[mode], i, FAIL);
XX-   mode++;
XX- 
XX-   for (i = 0; i < 8; i++)
XX- 	if (i == 0 || i == 4)
XX- 		try_access(fnames[mode], i, OK);
XX- 	else
XX- 		try_access(fnames[mode], i, FAIL);
XX-   mode++;
XX- 
XX-   for (i = 0; i < 8; i++)
XX- 	if (i == 0 || i == 1 || i == 4 || i == 5)
XX- 		try_access(fnames[mode], i, OK);
XX- 	else
XX- 		try_access(fnames[mode], i, FAIL);
XX-   mode++;
XX- 
XX-   for (i = 0; i < 8; i++)
XX- 	if (i % 2 == 0)
XX- 		try_access(fnames[mode], i, OK);
XX- 	else
XX- 		try_access(fnames[mode], i, FAIL);
XX-   mode++;
XX- 
XX-   for (i = 0; i < 8; i++) try_access(fnames[mode], i, OK);
XX- }				/* access_standards */
XX- 
XX- 
XX- 
XX- try_access(fname, mode, test)
XX- int mode, test;
XX- char *fname;
XX- {
XX-   if (access(fname, mode) != test)
XX- 	err(100, ACCESS, "incorrect access on a file (try_access)");
XX- }				/* try_access */
XX- 
XX- 
XX- 
XX- 
XX- 
XX- 
XX- 
XX  /* "support.c", created by Rene Montsma and Menno Wilcke */
XX  
XX- 
XX  /* Err, make_and_fill_dirs, init_array, clear_array, comp_array,
XX!    try_close, try_unlink, remove, get_mode, setid, check, open_alot,
XX     close_alot, clean_up_the_mess.
XX  */
XX  
XX- 
XX  /***********************************************************************
XX   *				EXTENDED FIONS			       *
XX   **********************************************************************/
XX  /* First extended functions (i.e. not oldfashioned monixcalls.
XX     e(), nlcr(), octal.*/
XX  
XX! e(string)
XX  char *string;
XX  {
XX!   printf("Test program error: %s\n", string);
XX  }
XX  
XX! nlcr()
XX  {
XX    printf("\n");
XX  }
XX  
XX! str(s)
XX  char *s;
XX  {
XX    printf(s);
XX  }
XX  
XX- 
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                               ERR(or) messages                             *
XX  *                                                                            *
XX  *****************************************************************************/
XX! err(number, scall, name)
XX   /* Give nice error messages */
XX  
XX  char *scall, *name;
XX  int number;
XX  
XX  {
XX    e("");
XX    str("\t");
XX    switch (number) {
XX--- 735,787 ----
XX  	err(100, "comp_inodes", "cannot 'fstat' (m)");
XX  }				/* comp_inodes */
XX  
XX  /* "support.c", created by Rene Montsma and Menno Wilcke */
XX  
XX  /* Err, make_and_fill_dirs, init_array, clear_array, comp_array,
XX!    try_close, try_unlink, Remove, get_mode, check, open_alot,
XX     close_alot, clean_up_the_mess.
XX  */
XX  
XX  /***********************************************************************
XX   *				EXTENDED FIONS			       *
XX   **********************************************************************/
XX  /* First extended functions (i.e. not oldfashioned monixcalls.
XX     e(), nlcr(), octal.*/
XX  
XX! void e(string)
XX  char *string;
XX  {
XX!   printf("Error: %s ", string);
XX  }
XX  
XX! void nlcr()
XX  {
XX    printf("\n");
XX  }
XX  
XX! void str(s)
XX  char *s;
XX  {
XX    printf(s);
XX  }
XX  
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                               ERR(or) messages                             *
XX  *                                                                            *
XX  *****************************************************************************/
XX! void err(number, scall, name)
XX   /* Give nice error messages */
XX  
XX  char *scall, *name;
XX  int number;
XX  
XX  {
XX+   errct++;
XX+   if (errct > MAXERR) {
XX+ 	printf("Too many errors;  test aborted\n");
XX+ 	quit();
XX+   }
XX    e("");
XX    str("\t");
XX    switch (number) {
XX***************
XX*** 1192,1205 ****
XX    nlcr();
XX  }				/* err */
XX  
XX- 
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                          MAKE_AND_FILL_DIRS                                *
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX! make_and_fill_dirs()
XX   /* Create 8 dir.'s: "d---", "d--x", "d-w-", "d-wx", "dr--", "dr-x",     *
XX    * "drw-", "drwx".                                     * Then create 8 files
XX    * in "drwx", and some needed files in other dirs.  */
XX--- 868,880 ----
XX    nlcr();
XX  }				/* err */
XX  
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                          MAKE_AND_FILL_DIRS                                *
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX! void make_and_fill_dirs()
XX   /* Create 8 dir.'s: "d---", "d--x", "d-w-", "d-wx", "dr--", "dr-x",     *
XX    * "drw-", "drwx".                                     * Then create 8 files
XX    * in "drwx", and some needed files in other dirs.  */
XX***************
XX*** 1223,1261 ****
XX  
XX  }				/* make_and_fill_dirs */
XX  
XX! /* This function is not used */
XX! create_8_dirs()
XX! {
XX!   switch (fork()) {
XX!       case -1:
XX! 	printf("create_8_dirs: failed fork .\n");
XX! 	break;
XX!       case 0:
XX! 	execl("/bin/mkdir", "mkdir", "d---", "d--x",
XX! 	      "d-w-", "d-wx", "dr--", "dr-x", "drw-", "drwx", 0);
XX! 	printf("mkdir: something went wrong.\n");
XX! 	exit(1);
XX!       default:
XX! 	printf("waiting\n");
XX! 	wait(0);
XX!   }
XX! }
XX! 
XX! 
XX! 
XX! put_file_in_dir(dirname, mode)
XX  char *dirname;
XX  int mode;
XX   /* Fill directory 'dirname' with file with mode 'mode'.   */
XX  {
XX    int nr;
XX  
XX- 
XX    if (chdir(dirname) != OK)
XX  	err(5, CHDIR, "to dirname (put_f_in_dir)");
XX    else {
XX  	/* Creat the file */
XX! 	if ((nr = creat(fnames[mode], mode * 0100, 0)) < 0)
XX  		err(13, CREAT, fnames[mode]);
XX  	else
XX  		try_close(nr, fnames[mode]);
XX--- 898,915 ----
XX  
XX  }				/* make_and_fill_dirs */
XX  
XX! void put_file_in_dir(dirname, mode)
XX  char *dirname;
XX  int mode;
XX   /* Fill directory 'dirname' with file with mode 'mode'.   */
XX  {
XX    int nr;
XX  
XX    if (chdir(dirname) != OK)
XX  	err(5, CHDIR, "to dirname (put_f_in_dir)");
XX    else {
XX  	/* Creat the file */
XX! 	if ((nr = creat(fnames[mode], mode * 0100)) < 0)
XX  		err(13, CREAT, fnames[mode]);
XX  	else
XX  		try_close(nr, fnames[mode]);
XX***************
XX*** 1265,1281 ****
XX    }
XX  }				/* put_file_in_dir */
XX  
XX- 
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                               MISCELLANEOUS                                *
XX  *                                                                            *
XX! *(all about arrays, 'try_close', 'try_unlink', 'remove', 'get_mode', 'setid')*
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX! 
XX! init_array(a)
XX  char *a;
XX  {
XX    int i;
XX--- 919,933 ----
XX    }
XX  }				/* put_file_in_dir */
XX  
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                               MISCELLANEOUS                                *
XX  *                                                                            *
XX! *(all about arrays, 'try_close', 'try_unlink', 'Remove', 'get_mode')*
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX! void init_array(a)
XX  char *a;
XX  {
XX    int i;
XX***************
XX*** 1284,1290 ****
XX    while (i++ < ARSIZE) *a++ = 'a' + (i % 26);
XX  }				/* init_array */
XX  
XX! clear_array(b)
XX  char *b;
XX  {
XX    int i;
XX--- 936,942 ----
XX    while (i++ < ARSIZE) *a++ = 'a' + (i % 26);
XX  }				/* init_array */
XX  
XX! void clear_array(b)
XX  char *b;
XX  {
XX    int i;
XX***************
XX*** 1294,1300 ****
XX  
XX  }				/* clear_array */
XX  
XX- 
XX  int comp_array(a, b, range)
XX  char *a, *b;
XX  int range;
XX--- 946,951 ----
XX***************
XX*** 1311,1341 ****
XX    }
XX  }				/* comp_array */
XX  
XX! 
XX! try_close(filedes, name)
XX  int filedes;
XX  char *name;
XX  {
XX    if (close(filedes) != OK) err(5, CLOSE, name);
XX  }				/* try_close */
XX  
XX! 
XX! try_unlink(fname)
XX  char *fname;
XX  {
XX    if (unlink(fname) != 0) err(5, UNLINK, fname);
XX  }				/* try_unlink */
XX  
XX! 
XX! remove(fdes, fname)
XX  int fdes;
XX  char *fname;
XX  {
XX    try_close(fdes, fname);
XX    try_unlink(fname);
XX! }				/* remove */
XX  
XX- 
XX  int get_mode(name)
XX  char *name;
XX  {
XX--- 962,988 ----
XX    }
XX  }				/* comp_array */
XX  
XX! void try_close(filedes, name)
XX  int filedes;
XX  char *name;
XX  {
XX    if (close(filedes) != OK) err(5, CLOSE, name);
XX  }				/* try_close */
XX  
XX! void try_unlink(fname)
XX  char *fname;
XX  {
XX    if (unlink(fname) != 0) err(5, UNLINK, fname);
XX  }				/* try_unlink */
XX  
XX! void Remove(fdes, fname)
XX  int fdes;
XX  char *fname;
XX  {
XX    try_close(fdes, fname);
XX    try_unlink(fname);
XX! }				/* Remove */
XX  
XX  int get_mode(name)
XX  char *name;
XX  {
XX***************
XX*** 1350,1372 ****
XX  	return(stbf1.st_mode & 07777);	/* take last 4 bits */
XX  }				/* get_mode */
XX  
XX- setid(newid)
XX- int newid;
XX- {
XX-   if (setuid(newid) != OK) printf("setid: setuid called.\n");
XX-   /* Err(100, "setid", "cannot change 'uid'"); */
XX- }
XX- 
XX- 
XX- 
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                                  CHECK                                     *
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX! 
XX! check(scall, number)
XX  int number;
XX  char *scall;
XX  {
XX--- 997,1009 ----
XX  	return(stbf1.st_mode & 07777);	/* take last 4 bits */
XX  }				/* get_mode */
XX  
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                                  CHECK                                     *
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX! void check(scall, number)
XX  int number;
XX  char *scall;
XX  {
XX***************
XX*** 1382,1388 ****
XX    }
XX  }				/* check */
XX  
XX! put(nr)
XX  int nr;
XX  {
XX    switch (nr) {
XX--- 1019,1025 ----
XX    }
XX  }				/* check */
XX  
XX! void put(nr)
XX  int nr;
XX  {
XX    switch (nr) {
XX***************
XX*** 1424,1430 ****
XX    }
XX  }
XX  
XX- 
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                                ALOT-functions                              *
XX--- 1061,1066 ----
XX***************
XX*** 1432,1439 ****
XX  *****************************************************************************/
XX  
XX  
XX- 
XX- 
XX  int open_alot()
XX  {
XX    int i;
XX--- 1068,1073 ----
XX***************
XX*** 1444,1450 ****
XX    return(i);
XX  }				/* open_alot */
XX  
XX- 
XX  int close_alot(number)
XX  int number;
XX  {
XX--- 1078,1083 ----
XX***************
XX*** 1459,1480 ****
XX    return(number - count);	/* return number of closed files */
XX  }				/* close_alot */
XX  
XX- 
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                         CLEAN UP THE MESS                                  *
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX! 
XX! clean_up_the_mess()
XX  {
XX    int i;
XX!   char dirname[6], filename[9], dotdot[60];
XX!   static char comm[60];
XX  
XX! 
XX!   /* First remove 'alot' files */
XX    for (i = 0; i < MAXOPEN; i++) try_unlink(file[i]);
XX  
XX    /* Unlink the files in dir 'drwx' */
XX--- 1092,1109 ----
XX    return(number - count);	/* return number of closed files */
XX  }				/* close_alot */
XX  
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                         CLEAN UP THE MESS                                  *
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX! void clean_up_the_mess()
XX  {
XX    int i;
XX!   char dirname[6];
XX  
XX!   /* First remove 'a lot' files */
XX    for (i = 0; i < MAXOPEN; i++) try_unlink(file[i]);
XX  
XX    /* Unlink the files in dir 'drwx' */
XX***************
XX*** 1485,1491 ****
XX  	if (chdir("..") != OK) err(5, CHDIR, "to '..'");
XX    }
XX  
XX- 
XX    /* Before unlinking files in some dirs, make them writable */
XX    chmod_8_dirs(RWX);
XX  
XX--- 1114,1119 ----
XX***************
XX*** 1506,1518 ****
XX    /* FINISH */
XX  }				/* clean_up_the_mess */
XX  
XX! chmod_8_dirs(sw)
XX  int sw;				/* if switch == 8, give all different
XX  			 * mode,else the same mode */
XX  {
XX    int mode;
XX    int i;
XX-   static char comm[60], dirname[6], filename[9];
XX  
XX    if (sw == 8)
XX  	mode = 0;
XX--- 1134,1145 ----
XX    /* FINISH */
XX  }				/* clean_up_the_mess */
XX  
XX! void chmod_8_dirs(sw)
XX  int sw;				/* if switch == 8, give all different
XX  			 * mode,else the same mode */
XX  {
XX    int mode;
XX    int i;
XX  
XX    if (sw == 8)
XX  	mode = 0;
XX***************
XX*** 1525,1559 ****
XX    }
XX  }
XX  
XX! 
XX! strappend(d, s1, s2)
XX! char *d, *s1, *s2;
XX  {
XX-   while (*s1 != 0) *d++ = *s1++;
XX-   while (*s2 != 0) *d++ = *s2++;
XX-   *d = 0;
XX- }
XX  
XX  
XX! char *strcpy(s1, s2)
XX! register char *s1, *s2;
XX! 
XX! {
XX!   register char *rp;
XX! 
XX!   rp = s1;
XX!   while (*s1++ = *s2++);
XX!   return(rp);
XX! }
XX! char *strcat(s1, s2)
XX! register char *s1, *s2;
XX! {
XX!   register char *rp;
XX! 
XX!   rp = s1;
XX!   while (*s1++);
XX!   --s1;
XX!   while (*s1++ = *s2++);
XX!   return(rp);
XX! 
XX  }
XX--- 1152,1168 ----
XX    }
XX  }
XX  
XX! void quit()
XX  {
XX  
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX  
XX!   if (errct == 0) {
XX! 	printf("ok\n");
XX! 	exit(0);
XX!   } else {
XX! 	printf("%d errors\n", errct);
XX! 	exit(1);
XX!   }
XX  }
X/
Xecho x - test18.c.d
Xsed '/^X/s///' > test18.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test18.c  crc=13138  32112	Sat May  5 13:16:08 1990
XX--- /home/top/ast/minix/1.6.25/test/test18.c  crc=19069  33253	Fri Mar 19 21:25:04 1993
XX***************
XX*** 4,21 ****
XX  
XX  /* "const.h", created by Rene Montsma and Menno Wilcke */
XX  
XX- 
XX  #include <sys/types.h>		/* needed in struct stat */
XX  #include <sys/stat.h>		/* struct stat */
XX  #include <errno.h>		/* the error-numbers */
XX  #include <fcntl.h>
XX  #include <unistd.h>
XX  #include <stdio.h>
XX  
XX  #define NOCRASH 1		/* test11(), 2nd pipe */
XX  #define PDPNOHANG  1		/* test03(), write_standards() */
XX  
XX- 
XX  #define USER_ID   12
XX  #define GROUP_ID   1
XX  #define FF        3		/* first free filedes. */
XX--- 4,23 ----
XX  
XX  /* "const.h", created by Rene Montsma and Menno Wilcke */
XX  
XX  #include <sys/types.h>		/* needed in struct stat */
XX  #include <sys/stat.h>		/* struct stat */
XX+ #include <sys/wait.h>
XX  #include <errno.h>		/* the error-numbers */
XX  #include <fcntl.h>
XX+ #include <stdlib.h>
XX  #include <unistd.h>
XX+ #include <string.h>
XX  #include <stdio.h>
XX  
XX  #define NOCRASH 1		/* test11(), 2nd pipe */
XX  #define PDPNOHANG  1		/* test03(), write_standards() */
XX+ #define MAXERR 5
XX  
XX  #define USER_ID   12
XX  #define GROUP_ID   1
XX  #define FF        3		/* first free filedes. */
XX***************
XX*** 23,37 ****
XX  #define GROUP     0		/* gid */
XX  
XX  #define ARSIZE   256		/* array size */
XX! #define PIPESIZE 3584		/* maximum number of bytes to be * written on
XX! 			 * pipe               */
XX! 
XX  #define MAXOPEN  17		/* maximum number of extra open files */
XX- 
XX  #define MAXLINK 0177		/* maximum number of links per file */
XX- 
XX  #define MASK    0777		/* selects lower nine bits */
XX- 
XX  #define READ_EOF 0		/* returned by read-call at eof */
XX  
XX  #define OK      0
XX--- 25,34 ----
XX  #define GROUP     0		/* gid */
XX  
XX  #define ARSIZE   256		/* array size */
XX! #define PIPESIZE 3584		/* maxnumber of bytes to be written on pipe */
XX  #define MAXOPEN  17		/* maximum number of extra open files */
XX  #define MAXLINK 0177		/* maximum number of links per file */
XX  #define MASK    0777		/* selects lower nine bits */
XX  #define READ_EOF 0		/* returned by read-call at eof */
XX  
XX  #define OK      0
XX***************
XX*** 62,72 ****
XX  #define DUP     "dup"
XX  #define UTIME   "utime"
XX  
XX- extern int errno;		/* the error-number */
XX  int errct;
XX  
XX- long lseek();
XX- 
XX  char *file[];
XX  char *fnames[];
XX  char *dir[];
XX--- 59,66 ----
XX***************
XX*** 83,118 ****
XX  
XX  /* "test.c", created by Rene Montsma and Menno Wilcke */
XX  
XX  
XX  /*****************************************************************************
XX   *                              TEST                                         *
XX   ****************************************************************************/
XX! main()
XX  {
XX    int n;
XX  
XX    if (fork()) {
XX  	printf("Test 18 ");
XX  	fflush(stdout);		/* have to flush for child's benefit */
XX  
XX  	wait(&n);
XX  	clean_up_the_mess();
XX! 	if (errct == 0)
XX! 		printf("ok\n");
XX! 	else
XX! 		printf(" %d errors\n", errct);
XX! 	exit(0);
XX    } else {
XX  	test();
XX  	exit(0);
XX    }
XX  }
XX  
XX  
XX  
XX! test()
XX  {
XX-   int n;
XX    umask(0);			/* not honest, but i always forget */
XX  
XX    test01();
XX--- 77,153 ----
XX  
XX  /* "test.c", created by Rene Montsma and Menno Wilcke */
XX  
XX+ _PROTOTYPE(int main, (void));
XX+ _PROTOTYPE(void test, (void));
XX+ _PROTOTYPE(void test01, (void));
XX+ _PROTOTYPE(void test02, (void));
XX+ _PROTOTYPE(void test03, (void));
XX+ _PROTOTYPE(void write_standards, (int filedes, char a []));
XX+ _PROTOTYPE(void test04, (void));
XX+ _PROTOTYPE(void read_standards, (int filedes, char a []));
XX+ _PROTOTYPE(void read_more, (int filedes, char a []));
XX+ _PROTOTYPE(void test05, (void));
XX+ _PROTOTYPE(void try_open, (char *fname, int mode, int test));
XX+ _PROTOTYPE(void test06, (void));
XX+ _PROTOTYPE(void test07, (void));
XX+ _PROTOTYPE(void access_standards, (void));
XX+ _PROTOTYPE(void try_access, (char *fname, int mode, int test));
XX+ _PROTOTYPE(void e, (char *string));
XX+ _PROTOTYPE(void nlcr, (void));
XX+ _PROTOTYPE(void str, (char *s));
XX+ _PROTOTYPE(void err, (int number, char *scall, char *name));
XX+ _PROTOTYPE(void make_and_fill_dirs, (void));
XX+ _PROTOTYPE(void put_file_in_dir, (char *dirname, int mode));
XX+ _PROTOTYPE(void init_array, (char *a));
XX+ _PROTOTYPE(void clear_array, (char *b));
XX+ _PROTOTYPE(int comp_array, (char *a, char *b, int range));
XX+ _PROTOTYPE(void try_close, (int filedes, char *name));
XX+ _PROTOTYPE(void try_unlink, (char *fname));
XX+ _PROTOTYPE(void Remove, (int fdes, char *fname));
XX+ _PROTOTYPE(int get_mode, (char *name));
XX+ _PROTOTYPE(void check, (char *scall, int number));
XX+ _PROTOTYPE(void put, (int nr));
XX+ _PROTOTYPE(int open_alot, (void));
XX+ _PROTOTYPE(int close_alot, (int number));
XX+ _PROTOTYPE(void clean_up_the_mess, (void));
XX+ _PROTOTYPE(void chmod_8_dirs, (int sw));
XX+ _PROTOTYPE(void quit, (void));
XX  
XX+ 
XX  /*****************************************************************************
XX   *                              TEST                                         *
XX   ****************************************************************************/
XX! int main()
XX  {
XX    int n;
XX  
XX+   if (geteuid() == 0 || getuid() == 0) {
XX+ 	printf("Test 18 cannot run as root; test aborted\n");
XX+ 	exit(1);
XX+   }
XX+ 
XX+   system("rm -rf DIR_18; mkdir DIR_18");
XX+   chdir("DIR_18");
XX+ 
XX    if (fork()) {
XX  	printf("Test 18 ");
XX  	fflush(stdout);		/* have to flush for child's benefit */
XX  
XX  	wait(&n);
XX  	clean_up_the_mess();
XX! 	quit();
XX    } else {
XX  	test();
XX  	exit(0);
XX    }
XX+ 
XX+   return(0);
XX  }
XX  
XX  
XX  
XX! void test()
XX  {
XX    umask(0);			/* not honest, but i always forget */
XX  
XX    test01();
XX***************
XX*** 136,142 ****
XX  /*****************************************************************************
XX   *                              test UMASK                                   *
XX   ****************************************************************************/
XX! test01()
XX  {
XX    int oldvalue, newvalue, tempvalue;
XX    int nr;
XX--- 171,177 ----
XX  /*****************************************************************************
XX   *                              test UMASK                                   *
XX   ****************************************************************************/
XX! void test01()
XX  {
XX    int oldvalue, newvalue, tempvalue;
XX    int nr;
XX***************
XX*** 180,186 ****
XX  /*****************************************************************************
XX   *                              test CREAT                                   *
XX   ****************************************************************************/
XX! test02()
XX  {
XX    int n, n1, mode;
XX    char a[ARSIZE], b[ARSIZE];
XX--- 215,221 ----
XX  /*****************************************************************************
XX   *                              test CREAT                                   *
XX   ****************************************************************************/
XX! void test02()
XX  {
XX    int n, n1, mode;
XX    char a[ARSIZE], b[ARSIZE];
XX***************
XX*** 280,286 ****
XX    if ((n = creat("dir", 040777)) != FAIL) {
XX  	if (fstat(n, &stbf1) != OK)
XX  		err(5, FSTAT, "'dir'");
XX! 	else if (stbf1.st_mode != 0100777)
XX  		err(11, CREAT, "'creat' a new directory");
XX  	Remove(n, "dir");
XX    }
XX--- 315,325 ----
XX    if ((n = creat("dir", 040777)) != FAIL) {
XX  	if (fstat(n, &stbf1) != OK)
XX  		err(5, FSTAT, "'dir'");
XX! 	else if (stbf1.st_mode != (mode_t) 0100777)
XX! 				/* Cast because mode is negative :-(.
XX! 				 * HACK DEBUG FIXME: this appears to duplicate
XX! 				 * code in test17.c.
XX! 				 */
XX  		err(11, CREAT, "'creat' a new directory");
XX  	Remove(n, "dir");
XX    }
XX***************
XX*** 302,308 ****
XX  /*****************************************************************************
XX   *                              test WRITE                                   *
XX   ****************************************************************************/
XX! test03()
XX  {
XX    int n, n1;
XX    int fd[2];
XX--- 341,347 ----
XX  /*****************************************************************************
XX   *                              test WRITE                                   *
XX   ****************************************************************************/
XX! void test03()
XX  {
XX    int n, n1;
XX    int fd[2];
XX***************
XX*** 357,363 ****
XX  }				/* test03 */
XX  
XX  
XX! write_standards(filedes, a)
XX  int filedes;
XX  char a[];
XX  {
XX--- 396,402 ----
XX  }				/* test03 */
XX  
XX  
XX! void write_standards(filedes, a)
XX  int filedes;
XX  char a[];
XX  {
XX***************
XX*** 392,398 ****
XX  /*****************************************************************************
XX   *                              test READ                                    *
XX   ****************************************************************************/
XX! test04()
XX  {
XX    int n, n1, fd[2];
XX    char a[ARSIZE];
XX--- 431,437 ----
XX  /*****************************************************************************
XX   *                              test READ                                    *
XX   ****************************************************************************/
XX! void test04()
XX  {
XX    int n, n1, fd[2];
XX    char a[ARSIZE];
XX***************
XX*** 467,473 ****
XX  }				/* test04 */
XX  
XX  
XX! read_standards(filedes, a)
XX  int filedes;
XX  char a[];
XX  {
XX--- 506,512 ----
XX  }				/* test04 */
XX  
XX  
XX! void read_standards(filedes, a)
XX  int filedes;
XX  char a[];
XX  {
XX***************
XX*** 498,504 ****
XX  
XX  
XX  
XX! read_more(filedes, a)
XX  int filedes;
XX  char a[];
XX   /* Separated from read_standards() because the PIPE test * would fail.                                           */
XX--- 537,543 ----
XX  
XX  
XX  
XX! void read_more(filedes, a)
XX  int filedes;
XX  char a[];
XX   /* Separated from read_standards() because the PIPE test * would fail.                                           */
XX***************
XX*** 520,526 ****
XX  /*****************************************************************************
XX   *                              test OPEN/CLOSE                              *
XX   ****************************************************************************/
XX! test05()
XX  {
XX    int n, n1, mode, fd[2];
XX    char b[ARSIZE];
XX--- 559,565 ----
XX  /*****************************************************************************
XX   *                              test OPEN/CLOSE                              *
XX   ****************************************************************************/
XX! void test05()
XX  {
XX    int n, n1, mode, fd[2];
XX    char b[ARSIZE];
XX***************
XX*** 660,666 ****
XX  }				/* test05 */
XX  
XX  
XX! try_open(fname, mode, test)
XX  int mode, test;
XX  char *fname;
XX  {
XX--- 699,705 ----
XX  }				/* test05 */
XX  
XX  
XX! void try_open(fname, mode, test)
XX  int mode, test;
XX  char *fname;
XX  {
XX***************
XX*** 676,682 ****
XX  /*****************************************************************************
XX   *                              test LSEEK                                   *
XX   ****************************************************************************/
XX! test06()
XX  {
XX    char a[ARSIZE], b[ARSIZE];
XX    int fd;
XX--- 715,721 ----
XX  /*****************************************************************************
XX   *                              test LSEEK                                   *
XX   ****************************************************************************/
XX! void test06()
XX  {
XX    char a[ARSIZE], b[ARSIZE];
XX    int fd;
XX***************
XX*** 741,747 ****
XX  /*****************************************************************************
XX   *                              test ACCESS                                  *
XX   ****************************************************************************/
XX! test07()
XX  {
XX    /* Check with proper parameters */
XX    if (access("drwx/rwx", RWX) != OK) err(5, ACCESS, "accessible file");
XX--- 780,786 ----
XX  /*****************************************************************************
XX   *                              test ACCESS                                  *
XX   ****************************************************************************/
XX! void test07()
XX  {
XX    /* Check with proper parameters */
XX    if (access("drwx/rwx", RWX) != OK) err(5, ACCESS, "accessible file");
XX***************
XX*** 779,785 ****
XX  }				/* test07 */
XX  
XX  
XX! access_standards()
XX  {
XX    int i, mode = 0;
XX  
XX--- 818,824 ----
XX  }				/* test07 */
XX  
XX  
XX! void access_standards()
XX  {
XX    int i, mode = 0;
XX  
XX***************
XX*** 837,843 ****
XX  
XX  
XX  
XX! try_access(fname, mode, test)
XX  int mode, test;
XX  char *fname;
XX  {
XX--- 876,882 ----
XX  
XX  
XX  
XX! void try_access(fname, mode, test)
XX  int mode, test;
XX  char *fname;
XX  {
XX***************
XX*** 855,861 ****
XX  
XX  
XX  /* Err, make_and_fill_dirs, init_array, clear_array, comp_array,
XX!    try_close, try_unlink, Remove, get_mode, setid, check, open_alot,
XX     close_alot, clean_up_the_mess.
XX  */
XX  
XX--- 894,900 ----
XX  
XX  
XX  /* Err, make_and_fill_dirs, init_array, clear_array, comp_array,
XX!    try_close, try_unlink, Remove, get_mode, check, open_alot,
XX     close_alot, clean_up_the_mess.
XX  */
XX  
XX***************
XX*** 866,884 ****
XX  /* First extended functions (i.e. not oldfashioned monixcalls.
XX     e(), nlcr(), octal.*/
XX  
XX! e(string)
XX  char *string;
XX  {
XX    printf("Test program error: %s\n", string);
XX    errct++;
XX  }
XX  
XX! nlcr()
XX  {
XX    printf("\n");
XX  }
XX  
XX! str(s)
XX  char *s;
XX  {
XX    printf(s);
XX--- 905,923 ----
XX  /* First extended functions (i.e. not oldfashioned monixcalls.
XX     e(), nlcr(), octal.*/
XX  
XX! void e(string)
XX  char *string;
XX  {
XX    printf("Test program error: %s\n", string);
XX    errct++;
XX  }
XX  
XX! void nlcr()
XX  {
XX    printf("\n");
XX  }
XX  
XX! void str(s)
XX  char *s;
XX  {
XX    printf(s);
XX***************
XX*** 890,902 ****
XX  *                               ERR(or) messages                             *
XX  *                                                                            *
XX  *****************************************************************************/
XX! err(number, scall, name)
XX   /* Give nice error messages */
XX  
XX  char *scall, *name;
XX  int number;
XX  
XX  {
XX    e("");
XX    str("\t");
XX    switch (number) {
XX--- 929,948 ----
XX  *                               ERR(or) messages                             *
XX  *                                                                            *
XX  *****************************************************************************/
XX! void err(number, scall, name)
XX   /* Give nice error messages */
XX  
XX  char *scall, *name;
XX  int number;
XX  
XX  {
XX+   errct++;
XX+   if (errct > MAXERR) {
XX+ 	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX+ 	quit();
XX+   }
XX    e("");
XX    str("\t");
XX    switch (number) {
XX***************
XX*** 990,996 ****
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX! make_and_fill_dirs()
XX   /* Create 8 dir.'s: "d---", "d--x", "d-w-", "d-wx", "dr--", "dr-x",     *
XX    * "drw-", "drwx".                                     * Then create 8 files
XX    * in "drwx", and some needed files in other dirs.  */
XX--- 1036,1042 ----
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX! void make_and_fill_dirs()
XX   /* Create 8 dir.'s: "d---", "d--x", "d-w-", "d-wx", "dr--", "dr-x",     *
XX    * "drw-", "drwx".                                     * Then create 8 files
XX    * in "drwx", and some needed files in other dirs.  */
XX***************
XX*** 1014,1040 ****
XX  
XX  }				/* make_and_fill_dirs */
XX  
XX- /* This function is not used */
XX- create_8_dirs()
XX- {
XX-   switch (fork()) {
XX-       case -1:
XX- 	printf("create_8_dirs: failed fork .\n");
XX- 	break;
XX-       case 0:
XX- 	execl("/bin/mkdir", "mkdir", "d---", "d--x",
XX- 	      "d-w-", "d-wx", "dr--", "dr-x", "drw-", "drwx", 0);
XX- 	printf("mkdir: something went wrong.\n");
XX- 	exit(1);
XX-       default:
XX- 	printf("waiting\n");
XX- 	wait(0);
XX-   }
XX- }
XX  
XX  
XX! 
XX! put_file_in_dir(dirname, mode)
XX  char *dirname;
XX  int mode;
XX   /* Fill directory 'dirname' with file with mode 'mode'.   */
XX--- 1060,1068 ----
XX  
XX  }				/* make_and_fill_dirs */
XX  
XX  
XX  
XX! void put_file_in_dir(dirname, mode)
XX  char *dirname;
XX  int mode;
XX   /* Fill directory 'dirname' with file with mode 'mode'.   */
XX***************
XX*** 1046,1052 ****
XX  	err(5, CHDIR, "to dirname (put_f_in_dir)");
XX    else {
XX  	/* Creat the file */
XX! 	if ((nr = creat(fnames[mode], mode * 0100, 0)) < 0)
XX  		err(13, CREAT, fnames[mode]);
XX  	else
XX  		try_close(nr, fnames[mode]);
XX--- 1074,1080 ----
XX  	err(5, CHDIR, "to dirname (put_f_in_dir)");
XX    else {
XX  	/* Creat the file */
XX! 	if ((nr = creat(fnames[mode], mode * 0100)) < 0)
XX  		err(13, CREAT, fnames[mode]);
XX  	else
XX  		try_close(nr, fnames[mode]);
XX***************
XX*** 1061,1072 ****
XX  *                                                                            *
XX  *                               MISCELLANEOUS                                *
XX  *                                                                            *
XX! *(all about arrays, 'try_close', 'try_unlink', 'Remove', 'get_mode', 'setid')*
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX  
XX! init_array(a)
XX  char *a;
XX  {
XX    int i;
XX--- 1089,1100 ----
XX  *                                                                            *
XX  *                               MISCELLANEOUS                                *
XX  *                                                                            *
XX! *(all about arrays, 'try_close', 'try_unlink', 'Remove', 'get_mode')         *
XX  *                                                                            *
XX  *****************************************************************************/
XX  
XX  
XX! void init_array(a)
XX  char *a;
XX  {
XX    int i;
XX***************
XX*** 1075,1081 ****
XX    while (i++ < ARSIZE) *a++ = 'a' + (i % 26);
XX  }				/* init_array */
XX  
XX! clear_array(b)
XX  char *b;
XX  {
XX    int i;
XX--- 1103,1109 ----
XX    while (i++ < ARSIZE) *a++ = 'a' + (i % 26);
XX  }				/* init_array */
XX  
XX! void clear_array(b)
XX  char *b;
XX  {
XX    int i;
XX***************
XX*** 1103,1109 ****
XX  }				/* comp_array */
XX  
XX  
XX! try_close(filedes, name)
XX  int filedes;
XX  char *name;
XX  {
XX--- 1131,1137 ----
XX  }				/* comp_array */
XX  
XX  
XX! void try_close(filedes, name)
XX  int filedes;
XX  char *name;
XX  {
XX***************
XX*** 1111,1124 ****
XX  }				/* try_close */
XX  
XX  
XX! try_unlink(fname)
XX  char *fname;
XX  {
XX    if (unlink(fname) != 0) err(5, UNLINK, fname);
XX  }				/* try_unlink */
XX  
XX  
XX! Remove(fdes, fname)
XX  int fdes;
XX  char *fname;
XX  {
XX--- 1139,1152 ----
XX  }				/* try_close */
XX  
XX  
XX! void try_unlink(fname)
XX  char *fname;
XX  {
XX    if (unlink(fname) != 0) err(5, UNLINK, fname);
XX  }				/* try_unlink */
XX  
XX  
XX! void Remove(fdes, fname)
XX  int fdes;
XX  char *fname;
XX  {
XX***************
XX*** 1141,1155 ****
XX  	return(stbf1.st_mode & 07777);	/* take last 4 bits */
XX  }				/* get_mode */
XX  
XX- setid(newid)
XX- int newid;
XX- {
XX-   if (setuid(newid) != OK) printf("setid: setuid called.\n");
XX-   /* Err(100, "setid", "cannot change 'uid'"); */
XX- }
XX  
XX- 
XX- 
XX  /*****************************************************************************
XX  *                                                                            *
XX  *                                  CHECK                                     *
XX--- 1169,1175 ----
XX***************
XX*** 1157,1163 ****
XX  *****************************************************************************/
XX  
XX  
XX! check(scall, number)
XX  int number;
XX  char *scall;
XX  {
XX--- 1177,1183 ----
XX  *****************************************************************************/
XX  
XX  
XX! void check(scall, number)
XX  int number;
XX  char *scall;
XX  {
XX***************
XX*** 1173,1179 ****
XX    }
XX  }				/* check */
XX  
XX! put(nr)
XX  int nr;
XX  {
XX    switch (nr) {
XX--- 1193,1199 ----
XX    }
XX  }				/* check */
XX  
XX! void put(nr)
XX  int nr;
XX  {
XX    switch (nr) {
XX***************
XX*** 1258,1271 ****
XX  *****************************************************************************/
XX  
XX  
XX! clean_up_the_mess()
XX  {
XX    int i;
XX!   char dirname[6], filename[9], dotdot[60];
XX!   static char comm[60];
XX!   char *strcpy(), *strcat();
XX  
XX- 
XX    /* First remove 'alot' files */
XX    for (i = 0; i < MAXOPEN; i++) try_unlink(file[i]);
XX  
XX--- 1278,1288 ----
XX  *****************************************************************************/
XX  
XX  
XX! void clean_up_the_mess()
XX  {
XX    int i;
XX!   char dirname[6];
XX  
XX    /* First remove 'alot' files */
XX    for (i = 0; i < MAXOPEN; i++) try_unlink(file[i]);
XX  
XX***************
XX*** 1297,1309 ****
XX    /* FINISH */
XX  }				/* clean_up_the_mess */
XX  
XX! chmod_8_dirs(sw)
XX  int sw;				/* if switch == 8, give all different
XX  			 * mode,else the same mode */
XX  {
XX    int mode;
XX    int i;
XX-   static char comm[60], dirname[6], filename[9];
XX  
XX    if (sw == 8)
XX  	mode = 0;
XX--- 1314,1325 ----
XX    /* FINISH */
XX  }				/* clean_up_the_mess */
XX  
XX! void chmod_8_dirs(sw)
XX  int sw;				/* if switch == 8, give all different
XX  			 * mode,else the same mode */
XX  {
XX    int mode;
XX    int i;
XX  
XX    if (sw == 8)
XX  	mode = 0;
XX***************
XX*** 1317,1350 ****
XX  }
XX  
XX  
XX- strappend(d, s1, s2)
XX- char *d, *s1, *s2;
XX- {
XX-   while (*s1 != 0) *d++ = *s1++;
XX-   while (*s2 != 0) *d++ = *s2++;
XX-   *d = 0;
XX- }
XX  
XX! 
XX! char *strcpy(s1, s2)
XX! register char *s1, *s2;
XX! 
XX  {
XX-   register char *rp;
XX  
XX!   rp = s1;
XX!   while (*s1++ = *s2++);
XX!   return(rp);
XX! }
XX! char *strcat(s1, s2)
XX! register char *s1, *s2;
XX! {
XX!   register char *rp;
XX  
XX!   rp = s1;
XX!   while (*s1++);
XX!   --s1;
XX!   while (*s1++ = *s2++);
XX!   return(rp);
XX! 
XX  }
XX--- 1333,1350 ----
XX  }
XX  
XX  
XX  
XX! void quit()
XX  {
XX  
XX!   chdir("..");
XX!   system("rm -rf DIR*");
XX  
XX!   if (errct == 0) {
XX! 	printf("ok\n");
XX! 	exit(0);
XX!   } else {
XX! 	printf("%d errors\n", errct);
XX! 	exit(1);
XX!   }
XX  }
X/
Xecho x - test19.c.d
Xsed '/^X/s///' > test19.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test19.c  crc=48341   4941	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test19.c  crc=17076  14694	Sat Dec 19 19:50:02 1992
XX***************
XX*** 1,314 ****
XX! /* test 19 */
XX! 
XX! #include <signal.h>
XX  #include <errno.h>
XX  #include <stdio.h>
XX  
XX  #define MAX_ERROR 4
XX  
XX! extern int errno;
XX! int errct;
XX! int subtest = 1;
XX  
XX! int func1(), func10(), func8(), funcalrm(), func11();
XX! int childsigs, parsigs, alarms;
XX! int zero[1024];
XX  
XX! main()
XX  {
XX!   int i;
XX  
XX!   printf("Test 19 ");
XX!   fflush(stdout);		/* have to flush for child's benefit */
XX  
XX!   for (i = 0; i < 1; i++) {
XX! 	test50();
XX! 	test51();
XX! 	test53();
XX! 	test54();
XX! 	test55();
XX! /*	test56(); */
XX! 	test57();
XX    }
XX-   if (errct == 0)
XX- 	printf("ok\n");
XX-   else
XX- 	printf("%d errors\n", errct);
XX-   exit(0);
XX- }
XX  
XX  
XX! 
XX! test50()
XX! {
XX!   int parpid, childpid, flag, *zp;
XX! 
XX!   flag = 0;
XX!   for (zp = &zero[0]; zp < &zero[1024]; zp++)
XX! 	if (*zp != 0) flag = 1;
XX!   if (flag) e(0);		/* check if bss is cleared to 0 */
XX!   if (signal(1, func1) < 0) e(1);
XX!   if (signal(10, func10) < 0) e(2);
XX!   parpid = getpid();
XX!   if (childpid = fork()) {
XX! 	if (childpid < 0) ex();
XX! 	parent(childpid);
XX!   } else {
XX! 	child(parpid);
XX    }
XX!   if (signal(1, SIG_DFL) < 0) e(4);
XX!   if (signal(10, SIG_DFL) < 0) e(5);
XX  }
XX  
XX! parent(childpid)
XX! int childpid;
XX  {
XX!   int i;
XX  
XX!   for (i = 0; i < 3; i++) {
XX! 	if (kill(childpid, 1) < 0) e(6);
XX! 	while (parsigs == 0);
XX! 	parsigs--;
XX!   }
XX!   if (wait(&i) < 0) e(7);
XX!   if (i != 256 * 6) e(8);
XX! }
XX  
XX! child(parpid)
XX! int parpid;
XX! {
XX  
XX!   int i;
XX  
XX!   for (i = 0; i < 3; i++) {
XX! 	while (childsigs == 0);
XX! 	childsigs--;
XX! 	if (kill(parpid, 10) < 0) e(9);
XX!   }
XX!   exit(6);
XX! }
XX  
XX! func1()
XX! {
XX!   if (signal(1, func1) < 0) e(10);
XX!   childsigs++;
XX  }
XX  
XX! func10()
XX  {
XX!   if (signal(10, func10) < 0) e(11);
XX!   parsigs++;
XX  }
XX  
XX  
XX! test51()
XX  {
XX!   int cpid, n, pid;
XX  
XX!   if ((pid = fork())) {
XX! 	if (pid < 0) ex();
XX! 	if ((pid = fork())) {
XX! 		if (pid < 0) ex();
XX! 		if (cpid = fork()) {
XX! 			if (cpid < 0) ex();
XX! 			if (kill(cpid, 9) < 0) e(12);
XX! 			if (wait(&n) < 0) e(13);
XX! 			if (wait(&n) < 0) e(14);
XX! 			if (wait(&n) < 0) e(15);
XX! 		} else {
XX! 			pause();
XX! 			while (1);
XX! 		}
XX! 	} else {
XX! 		exit(0);
XX  	}
XX!   } else {
XX! 	exit(0);
XX    }
XX! }
XX  
XX! test52()
XX! {
XX!   int pid, n, k;
XX  
XX!   pid = getpid();
XX!   if (getpid() == pid) k = fork();	/* only parent forks */
XX!   if (k < 0) ex();
XX!   if (getpid() == pid) k = fork();	/* only parent forks */
XX!   if (k < 0) ex();
XX!   if (getpid() == pid) k = fork();	/* only parent forks */
XX!   if (k < 0) ex();
XX  
XX!   if (getpid() == pid) {
XX! 	if (kill(0, 9) < 0) e(16);
XX! 	if (wait(&n) < 0) e(17);
XX! 	if (wait(&n) < 0) e(18);
XX! 	if (wait(&n) < 0) e(19);
XX!   } else
XX! 	pause();
XX  }
XX  
XX! int sigmap[5] = {9, 10, 11};
XX! test53()
XX  {
XX!   int n, i, pid, wpid;
XX  
XX!   /* Test exit status codes for processes killed by signals. */
XX!   for (i = 0; i < 3; i++) {
XX! 	if (pid = fork()) {
XX! 		if (pid < 0) ex();
XX! 		sleep(3);	/* wait for child to pause */
XX! 		if (kill(pid, sigmap[i]) < 0) {
XX! 			e(20);
XX! 			exit(1);
XX! 		}
XX! 		if ((wpid = wait(&n)) < 0) e(21);
XX! 		if ((n & 077) != sigmap[i]) e(22);
XX! 		if (pid != wpid) e(23);
XX! 	} else {
XX! 		pause();
XX! 		exit(0);
XX! 	}
XX!   }
XX! }
XX  
XX! test54()
XX! {
XX! /* Test alarm */
XX  
XX!   int i;
XX  
XX!   alarms = 0;
XX!   for (i = 0; i < 8; i++) {
XX! 	signal(SIGALRM, funcalrm);
XX! 	alarm(1);
XX! 	pause();
XX! 	if (alarms != i + 1) e(24);
XX!   }
XX  }
XX  
XX  
XX  
XX! test55()
XX  {
XX! /* When a signal knocks a processes out of WAIT or PAUSE, it is supposed to
XX!  * get EINTR as error status.  Check that.
XX!  */
XX!   int n, j, i;
XX  
XX!   if (signal(8, func8) < 0) e(25);
XX!   if (n = fork()) {
XX! 	/* Parent must delay to give child a chance to pause. */
XX! 	if (n < 0) ex();
XX! 	sleep(1);
XX! 	if (kill(n, 8) < 0) e(26);
XX! 	if (wait(&n) < 0) e(27);
XX! 	if (signal(8, SIG_DFL) < 0) e(28);
XX!   } else {
XX! 	j = pause();
XX! 	if (errno != EINTR && -errno != EINTR) e(29);
XX! 	exit(0);
XX    }
XX  }
XX  
XX! func8()
XX  {
XX! }
XX  
XX! test56()
XX! {
XX!   int i, j, k, n;
XX  
XX!   n = fork();
XX!   if (n < 0) ex();
XX!   if (n) {
XX! 	wait(&i);
XX! 	i = (i >> 8) & 0377;
XX! 	if (i != (n & 0377)) e(30);
XX!   } else {
XX! 	i = getgid();
XX! 	j = getegid();
XX! 	k = (i + j + 7) & 0377;
XX! 	if (setgid(k) < 0) e(31);
XX! 	if (getgid() != k) e(32);
XX! 	if (getegid() != k) e(33);
XX! 	i = getuid();
XX! 	j = geteuid();
XX! 	k = (i + j + 1) & 0377;
XX! 	if (setuid(k) < 0) e(34);
XX! 	if (getuid() != k) e(35);
XX! 	if (geteuid() != k) e(36);
XX! 	i = getpid() & 0377;
XX! 	if (wait(&j) != -1) e(37);
XX! 	exit(i);
XX    }
XX  }
XX  
XX! func11()
XX  {
XX!   e(38);
XX! }
XX  
XX  
XX! test57()
XX! {
XX!   int n;
XX  
XX!   signal(11, func11);
XX!   signal(11, SIG_IGN);
XX!   n = getpid();
XX!   kill(n, 11);
XX!   signal(11, SIG_DFL);
XX! }
XX  
XX! funcalrm()
XX! {
XX!   alarms++;
XX! }
XX  
XX  
XX! test58()
XX! {
XX! /* When a signal knocks a processes out of PIPE, it is supposed to
XX!  * get EINTR as error status.  Check that.
XX!  */
XX!   int n, j, i, fd[2];
XX  
XX!   if (signal(8, func8) < 0) e(38);
XX!   pipe(fd);
XX!   if (n = fork()) {
XX! 	/* Parent must delay to give child a chance to pause. */
XX! 	if (n < 0) ex();
XX! 	sleep(3);
XX! 	if (kill(n, 8) < 0) e(39);
XX! 	if (wait(&n) < 0) e(40);
XX! 	if (signal(8, SIG_DFL) < 0) e(41);
XX! 	close(fd[0]);
XX! 	close(fd[1]);
XX!   } else {
XX! 	j = read(fd[0], &n, 1);
XX! 	if (errno != EINTR) e(42);
XX! 	exit(0);
XX    }
XX  }
XX  
XX! ex()
XX  {
XX!   printf("Test 5.  fork failed.  Errno=%d\n", errno);
XX!   exit(1);
XX  }
XX  
XX  
XX! e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX  
XX    printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX    errno = err_num;		/* restore errno, just in case */
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX  	exit(1);
XX    }
XX  }
XX--- 1,531 ----
XX! #include <sys/types.h>
XX! #include <sys/stat.h>
XX  #include <errno.h>
XX+ #include <fcntl.h>
XX+ #include <signal.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX  #include <stdio.h>
XX  
XX  #define MAX_ERROR 4
XX+ #define NB 30L
XX+ #define NBOUNDS 6
XX  
XX! int errct, subtest, passes, pipesigs;
XX! long t1;
XX  
XX! char aa[100];
XX! char b[4] = {0, 1, 2, 3}, c[4] = {10, 20, 30, 40}, d[4] = {6, 7, 8, 9};
XX! long bounds[NBOUNDS] = {7, 9, 50, 519, 520, 40000L};
XX! char buff[30000];
XX  
XX! _PROTOTYPE(int main, (int argc, char *argv[]));
XX! _PROTOTYPE(void test19a, (void));
XX! _PROTOTYPE(void test19b, (void));
XX! _PROTOTYPE(void test19c, (void));
XX! _PROTOTYPE(void test19d, (void));
XX! _PROTOTYPE(void test19e, (void));
XX! _PROTOTYPE(void test19f, (void));
XX! _PROTOTYPE(void test19g, (void));
XX! _PROTOTYPE(void clraa, (void));
XX! _PROTOTYPE(void pipecatcher, (int s));
XX! _PROTOTYPE(void e, (int n));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! 
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   int i, m;
XX  
XX!   m = (argc == 2 ? atoi(argv[1]) : 0xFFFF);
XX  
XX!   if (geteuid() == 0 || getuid() == 0) {
XX! 	printf("Test 19 cannot run as root; test aborted\n");
XX! 	exit(1);
XX    }
XX  
XX+   system("rm -rf DIR_19; mkdir DIR_19");
XX+   chdir("DIR_19");
XX  
XX!   printf("Test 19 ");
XX!   fflush(stdout);
XX!   for (i = 0; i < 4; i++) {
XX! 	if (m & 0001) test19a();
XX! 	if (m & 0002) test19b();
XX! 	if (m & 0004) test19c();
XX! 	if (m & 0010) test19d();
XX! 	if (m & 0020) test19e();
XX! 	if (m & 0040) test19f();
XX! 	if (m & 0100) test19g();
XX! 	passes++;
XX    }
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX! void test19a()
XX  {
XX! /* Test open with O_CREAT and O_EXCL. */
XX  
XX!   int fd;
XX  
XX!   subtest = 1;
XX!   
XX!   if ( (fd = creat("T19.a1", 0777)) != 3) e(1);	/* create test file */
XX!   if (close(fd) != 0) e(2);
XX!   if ( (fd = open("T19.a1", O_RDONLY)) != 3) e(3);
XX!   if (close(fd) != 0) e(4);
XX!   if ( (fd = open("T19.a1", O_WRONLY)) != 3) e(5);
XX!   if (close(fd) != 0) e(6);
XX!   if ( (fd = open("T19.a1", O_RDWR)) != 3) e(7);
XX!   if (close(fd) != 0) e(8);
XX  
XX!   /* See if O_CREAT actually creates a file. */
XX!   if ( (fd = open("T19.a2", O_RDONLY)) != -1) e(9);	/* must fail */
XX!   if ( (fd = open("T19.a2", O_RDONLY | O_CREAT, 0444)) != 3) e(10);
XX!   if (close(fd) != 0) e(11);
XX!   if ( (fd = open("T19.a2", O_RDONLY)) != 3) e(12);
XX!   if (close(fd) != 0) e(13);
XX!   if ( (fd = open("T19.a2", O_WRONLY)) != -1) e(14);
XX!   if ( (fd = open("T19.a2", O_RDWR)) != -1) e(15);
XX  
XX!   /* See what O_CREAT does on an existing file. */
XX!   if ( (fd = open("T19.a2", O_RDONLY | O_CREAT, 0777)) != 3) e(16);
XX!   if (close(fd) != 0) e(17);
XX!   if ( (fd = open("T19.a2", O_RDONLY)) != 3) e(18);
XX!   if (close(fd) != 0) e(19);
XX!   if ( (fd = open("T19.a2", O_WRONLY)) != -1) e(20);
XX!   if ( (fd = open("T19.a2", O_RDWR)) != -1) e(21);
XX  
XX!   /* See if O_EXCL works. */
XX!   if ( (fd = open("T19.a2", O_RDONLY | O_EXCL)) != 3) e(22);
XX!   if (close(fd) != 0) e(23);
XX!   if ( (fd = open("T19.a2", O_WRONLY | O_EXCL)) != -1) e(24);
XX!   if ( (fd = open("T19.a3", O_RDONLY | O_EXCL)) != -1) e(25);
XX!   if ( (fd = open("T19.a3", O_RDONLY | O_CREAT | O_EXCL, 0444)) != 3) e(26);
XX!   if (close(fd) != 0) e(27);
XX!   errno = 0;
XX!   if ( (fd = open("T19.a3", O_RDONLY | O_CREAT | O_EXCL, 0444)) != -1) e(28);
XX!   if (errno != EEXIST) e(29);
XX!  
XX!   if (unlink("T19.a1") != 0) e(30);
XX!   if (unlink("T19.a2") != 0) e(31);
XX!   if (unlink("T19.a3") != 0) e(32);
XX  }
XX  
XX! 
XX! void test19b()
XX  {
XX! /* Test open with O_APPEND and O_TRUNC. */
XX! 
XX!   int fd;
XX! 
XX!   subtest = 2;
XX!   
XX!   if ( (fd = creat("T19.b1", 0777)) != 3) e(1);	/* create test file */
XX!   if (write(fd, b, 4) != 4) e(2);
XX!   if (close(fd) != 0) e(3);
XX!   clraa();
XX!   if ( (fd = open("T19.b1", O_RDWR | O_APPEND)) != 3) e(4);
XX!   if (read(fd, aa, 100) != 4) e(5);
XX!   if (aa[0] != 0 || aa[1] != 1 || aa[2] != 2 || aa[3] != 3) e(6);
XX!   if (close(fd) != 0) e(7);
XX!   if ( (fd = open("T19.b1", O_RDWR | O_APPEND)) != 3) e(8);
XX!   if (write(fd, b, 4) != 4) e(9);
XX!   if (lseek(fd, 0L, SEEK_SET) != 0L) e(10);
XX!   clraa();
XX!   if (read(fd, aa, 100) != 8) e(11);
XX!   if (aa[4] != 0 || aa[5] != 1 || aa[6] != 2 || aa[7] != 3) e(12);
XX!   if (close(fd) != 0) e(13);
XX! 
XX!   if ( (fd = open("T19.b1", O_RDWR | O_TRUNC)) != 3) e(14);
XX!   if (read(fd, aa, 100) != 0) e(15);
XX!   if (close(fd) != 0) e(16);
XX! 
XX!   unlink("T19.b1");
XX  }
XX  
XX  
XX! void test19c()
XX  {
XX! /* Test program for open(), close(), creat(), read(), write(), lseek(). */
XX  
XX!   int i, n, n1, n2;
XX! 
XX!   subtest = 3;
XX!   if ((n = creat("foop", 0777)) != 3) e(1);
XX!   if ((n1 = creat("foop", 0777)) != 4) e(2);
XX!   if ((n2 = creat("/", 0777)) != -1) e(3);
XX!   if (close(n) != 0) e(4);
XX!   if ((n = open("foop", O_RDONLY)) != 3) e(5);
XX!   if ((n2 = open("nofile", O_RDONLY)) != -1) e(6);
XX!   if (close(n1) != 0) e(7);
XX! 
XX!   /* N is the only one open now. */
XX!   for (i = 0; i < 2; i++) {
XX! 	n1 = creat("File2", 0777);
XX! 	if (n1 != 4) {
XX! 		printf("creat yielded fd=%d, expected 4\n", n1);
XX! 		e(8);
XX  	}
XX! 	if ((n2 = open("File2", O_RDONLY)) != 5) e(9);
XX! 	if (close(n1) != 0) e(10);
XX! 	if (close(n2) != 0) e(11);
XX    }
XX!   unlink("File2");
XX!   if (close(n) != 0) e(12);
XX  
XX!   /* All files closed now. */
XX!   for (i = 0; i < 2; i++) {
XX! 	if ((n = creat("foop", 0777)) != 3) e(13);
XX! 	if (close(n) != 0) e(14);
XX! 	if ((n = open("foop", O_RDWR)) != 3) e(15);
XX  
XX! 	/* Read/write tests */
XX! 	if (write(n, b, 4) != 4) e(16);
XX! 	if (read(n, aa, 4) != 0) e(17);
XX! 	if (lseek(n, 0L, SEEK_SET) != 0L) e(18);
XX! 	if (read(n, aa, 4) != 4) e(19);
XX! 	if (aa[0] != 0 || aa[1] != 1 || aa[2] != 2 || aa[3] != 3) e(20);
XX! 	if (lseek(n, 0L, SEEK_SET) != 0L) e(21);
XX! 	if (lseek(n, 2L, SEEK_CUR) != 2L) e(22);
XX! 	if (read(n, aa, 4) != 2) e(23);
XX! 	if (aa[0] != 2 || aa[1] != 3 || aa[2] != 2 || aa[3] != 3) e(24);
XX! 	if (lseek(n, 2L, SEEK_SET) != 2L) e(25);
XX! 	clraa();
XX! 	if (write(n, c, 4) != 4) e(26);
XX! 	if (lseek(n, 0L, SEEK_SET) != 0L) e(27);
XX! 	if (read(n, aa, 10) != 6) e(28);
XX! 	if (aa[0] != 0 || aa[1] != 1 || aa[2] != 10 || aa[3] != 20) e(29);
XX! 	if (lseek(n, 16L, SEEK_SET) != 16L) e(30);
XX! 	if (lseek(n, 2040L, SEEK_END) != 2046L) e(31);
XX! 	if (read(n, aa, 10) != 0) e(32);
XX! 	if (lseek(n, 0L, SEEK_CUR) != 2046L) e(33);
XX! 	clraa();
XX! 	if (write(n, c, 4) != 4) e(34);
XX! 	if (lseek(n, 0L, SEEK_CUR) != 2050L) e(35);
XX! 	if (lseek(n, 2040L, SEEK_SET) != 2040L) e(36);
XX! 	clraa();
XX! 	if (read(n, aa, 20) != 10) e(37);
XX! 	if (aa[0] != 0 || aa[5] != 0 || aa[6] != 10 || aa[9] != 40) e(38);
XX! 	if (lseek(n, 10239L, SEEK_SET) != 10239L) e(39);
XX! 	if (write(n, d, 2) != 2) e(40);
XX! 	if (lseek(n, -2L, SEEK_END) != 10239L) e(41);
XX! 	if (read(n, aa, 2) != 2) e(42);
XX! 	if (aa[0] != 6 || aa[1] != 7) e(43);
XX! 	if (lseek(n, NB * 1024L - 2L, SEEK_SET) != NB * 1024L - 2L) e(44);
XX! 	if (write(n, b, 4) != 4) e(45);
XX! 	if (lseek(n, 0L, SEEK_SET) != 0L) e(46);
XX! 	if (lseek(n, -6L, SEEK_END) != 1024L * NB - 4) e(47);
XX! 	clraa();
XX! 	if (read(n, aa, 100) != 6) e(48);
XX! 	if (aa[0] != 0 || aa[1] != 0 || aa[3] != 1 || aa[4] != 2|| aa[5] != 3)
XX! 		e(49);
XX! 	if (lseek(n, 20000L, SEEK_SET) != 20000L) e(50);
XX! 	if (write(n, c, 4) != 4) e(51);
XX! 	if (lseek(n, -4L, SEEK_CUR) != 20000L) e(52);
XX! 	if (read(n, aa, 4) != 4) e(53);
XX! 	if (aa[0] != 10 || aa[1] != 20 || aa[2] != 30 || aa[3] != 40) e(54);
XX! 	if (close(n) != 0) e(55);
XX! 	if ((n1 = creat("foop", 0777)) != 3) e(56);
XX! 	if (close(n1) != 0) e(57);
XX! 	unlink("foop");
XX  
XX!   }
XX  }
XX  
XX! void test19d()
XX  {
XX! /* Test read. */
XX  
XX!   int i, fd, pd[2];
XX!   char bb[100];
XX  
XX!   subtest = 4;
XX!   
XX!   for (i = 0; i < 100; i++) bb[i] = i;
XX!   if ( (fd = creat("T19.d1", 0777)) != 3) e(1);	/* create test file */
XX!   if (write(fd, bb, 100) != 100) e(2);
XX!   if (close(fd) != 0) e(3);
XX!   clraa();
XX!   if ( (fd = open("T19.d1", O_RDONLY)) != 3) e(4);
XX!   errno = 1000;
XX!   if (read(fd, aa, 0) != 0) e(5);
XX!   if (errno != 1000) e(6);
XX!   if (read(fd, aa, 100) != 100) e(7);
XX!   if (lseek(fd, 37L, SEEK_SET) != 37L) e(8);
XX!   if (read(fd, aa, 10) != 10) e(9);
XX!   if (lseek(fd, 0L, SEEK_CUR) != 47L) e(10);
XX!   if (read(fd, aa, 100) != 53) e(11);
XX!   if (aa[0] != 47) e(12);
XX!   if (read(fd, aa, 1) != 0) e(13);
XX!   if (close(fd) != 0) e(14);
XX  
XX!   /* Read from pipe with no writer open. */
XX!   if (pipe(pd) != 0) e(15);
XX!   if (close(pd[1]) != 0) e(16);
XX!   errno = 2000;
XX!   if (read(pd[0], aa, 1) != 0) e(17);	/* must return EOF */
XX!   if (errno != 2000) e(18);
XX  
XX!   /* Read from a pipe with O_NONBLOCK set. */
XX!   if (fcntl(pd[0], F_SETFL, O_NONBLOCK) != 0) e(19);      /* set O_NONBLOCK */
XX! /*
XX!   if (read(pd[0], aa, 1) != -1) e(20);
XX!   if (errno != EAGAIN) e(21);
XX! */
XX!   if (close(pd[0]) != 0) e(19);
XX!   if (unlink("T19.d1") != 0) e(20);
XX  }
XX  
XX  
XX  
XX! void test19e()
XX  {
XX! /* Test link, unlink, stat, fstat, dup, umask.  */
XX  
XX!   int i, j, n, n1, flag;
XX!   char a[255], b[255];
XX!   struct stat s, s1;
XX! 
XX!   subtest = 5;
XX!   for (i = 0; i < 2; i++) {
XX! 	umask(0);
XX! 
XX! 	if ((n = creat("T3", 0702)) < 0) e(1);
XX! 	if (link("T3", "newT3") < 0) e(2);
XX! 	if ((n1 = open("newT3", O_RDWR)) < 0) e(3);
XX! 	for (j = 0; j < 255; j++) a[j] = j;
XX! 	if (write(n, a, 255) != 255) e(4);
XX! 	if (read(n1, b, 255) != 255) e(5);
XX! 	flag = 0;
XX! 	for (j = 0; j < 255; j++)
XX! 		if (a[j] != b[j]) flag++;
XX! 	if (flag) e(6);
XX! 	if (unlink("T3") < 0) e(7);
XX! 	if (close(n) < 0) e(8);
XX! 	if (close(n1) < 0) e(9);
XX! 	if ((n1 = open("newT3", O_RDONLY)) < 0) e(10);
XX! 	if (read(n1, b, 255) != 255) e(11);
XX! 	flag = 0;
XX! 	for (j = 0; j < 255; j++)
XX! 		if (a[j] != b[j]) flag++;
XX! 	if (flag) e(12);
XX! 
XX! 	/* Now check out stat, fstat. */
XX! 	if (stat("newT3", &s) < 0) e(13);
XX! 	if (s.st_mode != (mode_t) 0100702) e(14);
XX! 				/* The cast was because regular modes are
XX! 				 * negative :-(.  Anyway, the magic number
XX! 				 * should be (S_IFREG | S_IRWXU | S_IWOTH)
XX! 				 * for POSIX.
XX! 				 */
XX! 	if (s.st_nlink != 1) e(15);
XX! 	if (s.st_size != 255L) e(16);
XX! 	if (fstat(n1, &s1) < 0) e(17);
XX! 	if (s.st_dev != s1.st_dev) e(18);
XX! 	if (s.st_ino != s1.st_ino) e(19);
XX! 	if (s.st_mode != s1.st_mode) e(20);
XX! 	if (s.st_nlink != s1.st_nlink) e(21);
XX! 	if (s.st_uid != s1.st_uid) e(22);
XX! 	if (s.st_gid != s1.st_gid) e(23);
XX! 	if (s.st_rdev != s1.st_rdev) e(24);
XX! 	if (s.st_size != s1.st_size) e(25);
XX! 	if (s.st_atime != s1.st_atime) e(26);
XX! 	if (close(n1) < 0) e(27);
XX! 	if (unlink("newT3") < 0) e(28);
XX! 
XX! 	umask(040);
XX! 	if ((n = creat("T3a", 0777)) < 0) e(29);
XX! 	if (stat("T3a", &s) < 0) e(30);
XX! 	if (s.st_mode != (mode_t) 0100737) e(31);	/* negative :-( */
XX! 	if (unlink("T3a") < 0) e(32);
XX! 	if (close(n1) < 0) e(33);
XX! 
XX! 	/* Dup */
XX! 	if ((n = creat("T3b", 0777)) < 0) e(34);
XX! 	if (close(n) < 0) e(35);
XX! 	if ((n = open("T3b", O_RDWR)) < 0) e(36);
XX! 	if ((n1 = dup(n)) != n + 1) e(37);
XX! 	if (write(n, a, 255) != 255) e(38);
XX! 	read(n1, b, 20);
XX! 	if (lseek(n, 0L, SEEK_SET) != 0L) e(39);
XX! 	if ((j = read(n1, b, 1024)) != 255) e(40);
XX! 	if (unlink("T3b") < 0) e(41);
XX! 	if (close(n) < 0) e(42);
XX! 	if (close(n1) < 0) e(43);
XX! 
XX    }
XX  }
XX  
XX! void test19f()
XX  {
XX! /* Test large files to see if indirect block stuff works. */
XX  
XX!   int fd, i;
XX!   long pos;
XX  
XX!   subtest = 6;
XX! 
XX!   if (passes > 0) return;	/* takes too long to repeat this test */
XX!   for (i = 0; i < NBOUNDS; i ++) {
XX! 	pos = 1024L * bounds[i];
XX! 	fd = creat("T19f", 0777);
XX! 	if (fd < 0) e(10*i+1);
XX! 	if (lseek(fd, pos, 0) < 0) e(10*i+2);
XX! 	if (write(fd, buff, 30720) != 30720) e(10*i+3);
XX! 	if (close(fd) < 0) e(10*i+3);
XX! 	if (unlink("T19f") < 0) e(10*i+4);
XX    }
XX  }
XX  
XX! 
XX! void test19g()
XX  {
XX! /* Test POSIX calls for pipe, read, write, lseek and close. */
XX  
XX+   int pipefd[2], n, i, fd;
XX+   char buf[512], buf2[512];
XX  
XX!   subtest = 7;
XX  
XX!   for (i = 0; i < 512; i++) buf[i] = i % 128;
XX  
XX!   if (pipe(pipefd) < 0) e(1);
XX!   if (write(pipefd[1], buf, 512) != 512) e(2);
XX!   if (read(pipefd[0], buf2, 512) != 512) e(3);
XX!   if (close(pipefd[1]) != 0) e(4);
XX!   if (close(pipefd[1]) >= 0) e(5);
XX!   if (read(pipefd[0], buf2, 1) != 0) e(6);
XX!   if (close(pipefd[0]) != 0) e(7);
XX  
XX+   /* Test O_NONBLOCK on pipes. */
XX+   if (pipe(pipefd) < 0) e(8);
XX+   if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) != 0) e(9);
XX+   if (read(pipefd[0], buf2, 1) != -1) e(10);
XX+   if (errno != EAGAIN) e(11);
XX+   if (close(pipefd[0]) != 0) e(12);
XX+   if (close(pipefd[1]) != 0) e(13);
XX  
XX!   /* Test read and lseek. */
XX!   if ( (fd = creat("T19.g1", 0777)) != 3) e(14);	/* create test file */
XX!   if (write(fd, buf, 512) != 512) e(15);
XX!   errno = 3000;
XX!   if (read(fd, buf2, 512) != -1) e(16);
XX!   if (errno != EBADF) e(17);
XX!   if (close(fd) != 0) e(18);
XX!   if ( (fd = open("T19.g1", O_RDWR)) != 3) e(19);
XX!   if (read(fd, buf2, 512) != 512) e(20);
XX!   if (read(fd, buf2, 512) != 0) e(21);
XX!   if (lseek(fd, 100L, SEEK_SET) != 100L) e(22);
XX!   if (read(fd, buf2, 512) != 412) e(23);
XX!   if (lseek(fd, 1000L, SEEK_SET) != 1000L) e(24);
XX  
XX!   /* Test write. */
XX!   if (lseek(fd, -1000L, SEEK_CUR) != 0) e(25);
XX!   if (write(fd, buf, 512) != 512) e(26);
XX!   if (lseek(fd, 2L, SEEK_SET) != 2) e(27);
XX!   if (write(fd, buf, 3) != 3) e(28);
XX!   if (lseek(fd, -2L, SEEK_CUR) != 3) e(29);
XX!   if (write(fd, &buf[30], 1) != 1) e(30);
XX!   if (lseek(fd, 2L, SEEK_CUR) != 6) e(31);
XX!   if (write(fd, &buf[60], 1) != 1) e(32);
XX!   if (lseek(fd, -512L, SEEK_END) != 0) e(33);
XX!   if (read(fd, buf2, 8) != 8) e(34);
XX!   errno = 4000;
XX!   if (buf2[0] != 0 || buf2[1] != 1 || buf2[2] != 0 || buf2[3] != 30) e(35);
XX!   if (buf2[4] != 2 || buf2[5] != 5 || buf2[6] != 60 || buf2[7] != 7) e(36);
XX! 
XX!   /* Turn the O_APPEND flag on. */
XX!   if (fcntl(fd, F_SETFL, O_APPEND) != 0) e(37);
XX!   if (lseek(fd, 0L, SEEK_SET) != 0) e(38);
XX!   if (write(fd, &buf[100], 1) != 1) e(39);
XX!   if (lseek(fd, 0L, SEEK_SET) != 0) e(40);
XX!   if (read(fd, buf2, 10) != 10) e(41);
XX!   if (buf2[0] != 0) e(42);
XX!   if (lseek(fd, -1L, SEEK_END) != 512) e(43);
XX!   if (read(fd, buf2, 10) != 1) e(44);
XX!   if (buf2[0] != 100) e(45);
XX!   if (close(fd) != 0) e(46);
XX! 
XX!   /* Now try write with O_NONBLOCK. */
XX!   if (pipe(pipefd) != 0) e(47);
XX!   if (fcntl(pipefd[1], F_SETFL, O_NONBLOCK) != 0) e(48);
XX!   if (write(pipefd[1], buf, 512) != 512) e(49);
XX!   if (write(pipefd[1], buf, 512) != 512) e(50);
XX!   errno = 0;
XX!   for (i = 1; i < 20; i++) {
XX! 	n = write(pipefd[1], buf, 512);
XX! 	if (n == 512) continue;
XX! 	if (n != -1 || errno != EAGAIN) {e(51); break;}
XX    }
XX+   if (read(pipefd[0], buf, 512) != 512) e(52);
XX+   if (close(pipefd[0]) != 0) e(53);
XX+ 
XX+   /* Write to a pipe with no reader.  This should generate a signal. */
XX+   signal(SIGPIPE, pipecatcher);
XX+   errno = 0;
XX+   if (write(pipefd[1], buf, 1) != -1) e(54);
XX+   if (errno != EPIPE) e(55);
XX+   if (pipesigs != passes + 1) e(56);	/* we should have had the sig now */
XX+   if (close(pipefd[1]) != 0) e(57);
XX+   errno = 0;
XX+   if (write(100, buf, 512) != -1) e(58);
XX+   if (errno != EBADF) e(59);
XX+   if (unlink("T19.g1") != 0) e(60);
XX  }
XX  
XX! 
XX! void clraa()
XX  {
XX!   int i;
XX!   for (i = 0; i < 100; i++) aa[i] = 0;
XX  }
XX  
XX  
XX! void pipecatcher(s)
XX! int s;				/* it is supposed to have an arg */
XX! {
XX!   pipesigs++;
XX! }
XX! 
XX! 
XX! void e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX  
XX    printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX+   fflush(stdout);		/* aargh!  Most results go to stdout and are
XX+ 				 * messed up by perror going to stderr.
XX+ 				 * Should replace perror by printf and strerror
XX+ 				 * in all the tests.
XX+ 				 */
XX    errno = err_num;		/* restore errno, just in case */
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX  	exit(1);
XX    }
XX  }
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX+ 	exit(1);
XX+   }
XX+ }
XX+ 
XX+ 
X/
Xecho x - test2.c.d
Xsed '/^X/s///' > test2.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test2.c  crc=49794   1183	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test2.c  crc=31464   7686	Fri Mar 19 21:25:04 1993
XX***************
XX*** 1,41 ****
XX  /* test 2 */
XX  
XX  #include <stdio.h>
XX  
XX! extern errno;
XX! int kk = 0;
XX  
XX  char buf[2048];
XX! main()
XX  {
XX!   int i;
XX  
XX    printf("Test  2 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX!   for (i = 0; i < 19; i++) {
XX! 	test20();
XX    }
XX!   printf("ok\n");
XX!   exit(0);
XX  }
XX  
XX  
XX! test20()
XX  {
XX  /* Test pipes */
XX  
XX    int fd[2];
XX!   int n, i, j, ij, q = 0, nn, m = 0, k;
XX  
XX    if (pipe(fd) < 0) {
XX  	printf("pipe error.  errno= %d\n", errno);
XX! 	exit(0);
XX    }
XX    i = fork();
XX    if (i < 0) {
XX  	printf("fork failed\n");
XX! 	exit(0);
XX    }
XX    if (i != 0) {
XX  	/* Parent code */
XX--- 1,87 ----
XX  /* test 2 */
XX  
XX+ #include <sys/types.h>
XX+ #include <sys/times.h>
XX+ #include <sys/wait.h>
XX+ #include <errno.h>
XX+ #include <signal.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX+ #include <time.h>
XX  #include <stdio.h>
XX  
XX! #define ITERATIONS 10
XX! #define MAX_ERROR 4
XX  
XX+ int is, array[4], parsigs, parcum, sigct, cumsig, errct, subtest;
XX+ int iteration, kk = 0, errct = 0;
XX  char buf[2048];
XX! 
XX! _PROTOTYPE(int main, (int argc, char *argv []));
XX! _PROTOTYPE(void test2a, (void));
XX! _PROTOTYPE(void test2b, (void));
XX! _PROTOTYPE(void test2c, (void));
XX! _PROTOTYPE(void test2d, (void));
XX! _PROTOTYPE(void test2e, (void));
XX! _PROTOTYPE(void test2f, (void));
XX! _PROTOTYPE(void test2g, (void));
XX! _PROTOTYPE(void test2h, (void));
XX! _PROTOTYPE(void sigpip, (int s));
XX! _PROTOTYPE(void quit, (void));
XX! _PROTOTYPE(void e, (int n));
XX! 
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   int i, m = 0xFFFF;
XX  
XX+   sync();
XX+ 
XX+   if (argc == 2) m = atoi(argv[1]);
XX+ 
XX    printf("Test  2 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX!   system("rm -rf DIR_02; mkdir DIR_02");
XX!   chdir("DIR_02");
XX! 
XX!   for (i = 0; i < ITERATIONS; i++) {
XX! 	iteration = i;
XX! 	if (m & 0001) test2a();
XX! 	if (m & 0002) test2b();
XX! 	if (m & 0004) test2c();
XX! 	if (m & 0010) test2d();
XX! 	if (m & 0020) test2e();
XX! 	if (m & 0040) test2f();
XX! 	if (m & 0100) test2g();
XX! 	if (m & 0200) test2h();
XX    }
XX!   subtest = 100;
XX!   if (cumsig != ITERATIONS) e(101);
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX  
XX! void test2a()
XX  {
XX  /* Test pipes */
XX  
XX    int fd[2];
XX!   int n, i, j, q = 0;
XX  
XX+   subtest = 1;
XX    if (pipe(fd) < 0) {
XX  	printf("pipe error.  errno= %d\n", errno);
XX! 	errct++;
XX! 	quit();
XX    }
XX    i = fork();
XX    if (i < 0) {
XX  	printf("fork failed\n");
XX! 	errct++;
XX! 	quit();
XX    }
XX    if (i != 0) {
XX  	/* Parent code */
XX***************
XX*** 44,57 ****
XX  	for (q = 0; q < 8; q++) {
XX  		if (write(fd[1], buf, 2048) < 0) {
XX  			printf("write pipe err.  errno=%d\n", errno);
XX! 			exit(0);
XX  		}
XX  	}
XX  	close(fd[1]);
XX  	wait(&q);
XX  	if (q != 256 * 58) {
XX  		printf("wrong exit code %d\n", q);
XX! 		exit(0);
XX  	}
XX    } else {
XX  	/* Child code */
XX--- 90,105 ----
XX  	for (q = 0; q < 8; q++) {
XX  		if (write(fd[1], buf, 2048) < 0) {
XX  			printf("write pipe err.  errno=%d\n", errno);
XX! 			errct++;
XX! 			quit();
XX  		}
XX  	}
XX  	close(fd[1]);
XX  	wait(&q);
XX  	if (q != 256 * 58) {
XX  		printf("wrong exit code %d\n", q);
XX! 		errct++;
XX! 		quit();
XX  	}
XX    } else {
XX  	/* Child code */
XX***************
XX*** 60,74 ****
XX  		n = read(fd[0], buf, 512);
XX  		if (n != 512) {
XX  			printf("read yielded %d bytes, not 512\n", n);
XX! 			exit(0);
XX  		}
XX  		for (j = 0; j < n; j++)
XX  			if ((buf[j] & 0377) != (kk & 0377)) {
XX! 				printf("wrong data: %d %d %d \n ", j, buf[j] & 0377, kk & 0377);
XX  			} else {
XX  				kk++;
XX  			}
XX  	}
XX  	exit(58);
XX    }
XX  }
XX--- 108,416 ----
XX  		n = read(fd[0], buf, 512);
XX  		if (n != 512) {
XX  			printf("read yielded %d bytes, not 512\n", n);
XX! 			errct++;
XX! 			quit();
XX  		}
XX  		for (j = 0; j < n; j++)
XX  			if ((buf[j] & 0377) != (kk & 0377)) {
XX! 				printf("wrong data: %d %d %d \n ", 
XX! 						j, buf[j] & 0377, kk & 0377);
XX  			} else {
XX  				kk++;
XX  			}
XX  	}
XX  	exit(58);
XX+   }
XX+ }
XX+ 
XX+ 
XX+ void test2b()
XX+ {
XX+   int fd[2], n;
XX+   char buf[4];
XX+ 
XX+   subtest = 2;
XX+   sigct = 0;
XX+   signal(SIGPIPE, sigpip);
XX+   pipe(fd);
XX+   if (fork()) {
XX+ 	/* Parent */
XX+ 	close(fd[0]);
XX+ 	while (sigct == 0) {
XX+ 		write(fd[1], buf, 1);
XX+ 	}
XX+ 	wait(&n);
XX+   } else {
XX+ 	/* Child */
XX+ 	close(fd[0]);
XX+ 	close(fd[1]);
XX+ 	exit(0);
XX+   }
XX+ }
XX+ 
XX+ 
XX+ 
XX+ void test2c()
XX+ {
XX+   int n;
XX+ 
XX+   subtest = 3;
XX+   signal(SIGINT, SIG_DFL);
XX+   is = 0;
XX+   if ((array[is++] = fork()) > 0) {
XX+ 	if ((array[is++] = fork()) > 0) {
XX+ 		if ((array[is++] = fork()) > 0) {
XX+ 			if ((array[is++] = fork()) > 0) {
XX+ 				signal(SIGINT, SIG_IGN);
XX+ 				kill(array[0], SIGINT);
XX+ 				kill(array[1], SIGINT);
XX+ 				kill(array[2], SIGINT);
XX+ 				kill(array[3], SIGINT);
XX+ 				wait(&n);
XX+ 				wait(&n);
XX+ 				wait(&n);
XX+ 				wait(&n);
XX+ 			} else {
XX+ 				pause();
XX+ 			}
XX+ 		} else {
XX+ 			pause();
XX+ 		}
XX+ 	} else {
XX+ 		pause();
XX+ 	}
XX+   } else {
XX+ 	pause();
XX+   }
XX+ }
XX+ 
XX+ void test2d()
XX+ {
XX+ 
XX+   int pid, stat_loc, s;
XX+ 
XX+   /* Test waitpid. */
XX+   subtest = 4;
XX+ 
XX+   /* Test waitpid(pid, arg2, 0) */
XX+   pid = fork();
XX+   if (pid < 0) e(1);
XX+   if (pid > 0) {
XX+ 	/* Parent. */
XX+ 	s = waitpid(pid, &stat_loc, 0);
XX+ 	if (s != pid) e(2);
XX+ 	if (WIFEXITED(stat_loc) == 0) e(3);
XX+ 	if (WIFSIGNALED(stat_loc) != 0) e(4);
XX+ 	if (WEXITSTATUS(stat_loc) != 22) e(5);
XX+   } else {
XX+ 	/* Child */
XX+ 	exit(22);
XX+   }
XX+ 
XX+   /* Test waitpid(-1, arg2, 0) */
XX+   pid = fork();
XX+   if (pid < 0) e(6);
XX+   if (pid > 0) {
XX+ 	/* Parent. */
XX+ 	s = waitpid(-1, &stat_loc, 0);
XX+ 	if (s != pid) e(7);
XX+ 	if (WIFEXITED(stat_loc) == 0) e(8);
XX+ 	if (WIFSIGNALED(stat_loc) != 0) e(9);
XX+ 	if (WEXITSTATUS(stat_loc) != 33) e(10);
XX+   } else {
XX+ 	/* Child */
XX+ 	exit(33);
XX+   }
XX+ 
XX+   /* Test waitpid(0, arg2, 0) */
XX+   pid = fork();
XX+   if (pid < 0) e(11);
XX+   if (pid > 0) {
XX+ 	/* Parent. */
XX+ 	s = waitpid(0, &stat_loc, 0);
XX+ 	if (s != pid) e(12);
XX+ 	if (WIFEXITED(stat_loc) == 0) e(13);
XX+ 	if (WIFSIGNALED(stat_loc) != 0) e(14);
XX+ 	if (WEXITSTATUS(stat_loc) != 44) e(15);
XX+   } else {
XX+ 	/* Child */
XX+ 	exit(44);
XX+   }
XX+ 
XX+   /* Test waitpid(0, arg2, WNOHANG) */
XX+   signal(SIGTERM, SIG_DFL);
XX+   pid = fork();
XX+   if (pid < 0) e(16);
XX+   if (pid > 0) {
XX+ 	/* Parent. */
XX+ 	s = waitpid(0, &stat_loc, WNOHANG);
XX+ 	if (s != 0) e(17);
XX+ 	if (kill(pid, SIGTERM) != 0) e(18);
XX+ 	if (waitpid(pid, &stat_loc, 0) != pid) e(19);
XX+ 	if (WIFEXITED(stat_loc) != 0) e(20);
XX+ 	if (WIFSIGNALED(stat_loc) == 0) e(21);
XX+ 	if (WTERMSIG(stat_loc) != SIGTERM) e(22);
XX+   } else {
XX+ 	/* Child */
XX+ 	pause();
XX+   }
XX+ 
XX+   /* Test some error conditions. */
XX+   errno = 9999;
XX+   if (waitpid(0, &stat_loc, 0) != -1) e(23);
XX+   if (errno != ECHILD) e(24);
XX+   errno = 9999;
XX+   if (waitpid(0, &stat_loc, WNOHANG) != -1) e(25);
XX+   if (errno != ECHILD) e(26);
XX+ }
XX+ 
XX+ 
XX+ void test2e()
XX+ {
XX+ 
XX+   int pid1, pid2, stat_loc, s;
XX+ 
XX+   /* Test waitpid with two children. */
XX+   subtest = 5;
XX+   if (iteration > 1) return;		/* slow test, don't do it too much */
XX+   if ( (pid1 = fork())) {
XX+ 	/* Parent. */
XX+ 	if ( (pid2 = fork()) ) {
XX+ 		/* Parent. Collect second child first. */
XX+ 		s = waitpid(pid2, &stat_loc, 0);
XX+ 		if (s != pid2) e(1);
XX+ 		if (WIFEXITED(stat_loc) == 0) e(2);
XX+ 		if (WIFSIGNALED(stat_loc) != 0) e(3);
XX+ 		if (WEXITSTATUS(stat_loc) != 222) e(4);
XX+ 
XX+ 		/* Now collect first child. */
XX+ 		s = waitpid(pid1, &stat_loc, 0);
XX+ 		if (s != pid1) e(5);
XX+ 		if (WIFEXITED(stat_loc) == 0) e(6);
XX+ 		if (WIFSIGNALED(stat_loc) != 0) e(7);
XX+ 		if (WEXITSTATUS(stat_loc) != 111) e(8);
XX+ 	} else {
XX+ 		/* Child 2. */
XX+ 		sleep(2);		/* child 2 delays before exiting. */
XX+ 		exit(222);
XX+ 	}
XX+   } else {
XX+ 	/* Child 1. */
XX+ 	exit(111);			/* child 1 exits immediately */
XX+   }
XX+ 
XX+ }
XX+ 
XX+ 
XX+ void test2f()
XX+ {
XX+ /* test getpid, getppid, getuid, etc. */
XX+ 
XX+   pid_t pid, pid1, ppid, cpid, stat_loc, err;
XX+ 
XX+   subtest = 6;
XX+   errno = -2000;
XX+   err = 0;
XX+   pid = getpid();
XX+   if ( (pid1 = fork())) {
XX+ 	/* Parent.  Do nothing. */
XX+ 	if (wait(&stat_loc) != pid1) e(1);
XX+ 	if (WEXITSTATUS(stat_loc) != (pid1 & 0377)) e(2);
XX+   } else {
XX+ 	/* Child.  Get ppid. */
XX+ 	cpid = getpid();
XX+ 	ppid = getppid();
XX+ 	if (ppid != pid) err = 3;
XX+ 	if (cpid == ppid) err = 4;
XX+ 	exit(cpid & 0377);
XX+   }
XX+   if (err != 0) e(err);
XX+ }
XX+ 
XX+ void test2g()
XX+ {
XX+ /* test time(), times() */
XX+ 
XX+   time_t t1, t2;
XX+   clock_t t3, t4;
XX+   struct tms tmsbuf;
XX+ 
XX+   subtest = 7;
XX+   errno = -7000;
XX+ 
XX+   /* First time(). */
XX+   t1 = -1;
XX+   t2 = -2;
XX+   t1 = time(&t2);
XX+   if (t1 < 650000000L) e(1);	/* 650000000 is Sept. 1990 */
XX+   if (t1 != t2) e(2);
XX+   t1 = -1;
XX+   t1 = time( (time_t *) NULL);
XX+   if (t1 < 650000000L) e(3);
XX+   t3 = times(&tmsbuf);
XX+   sleep(1);
XX+   t2 = time( (time_t *) NULL);
XX+   if (t2 < 0L) e(4);
XX+   if (t2 - t1 < 1) e(5);
XX+ 
XX+   /* Now times(). */
XX+   t4 = times(&tmsbuf);
XX+   if (t4 < 0) e(6);
XX+   if (t4 - t3 < 60) e(7);
XX+   if (tmsbuf.tms_utime < 0) e(8);
XX+   if (tmsbuf.tms_stime < 0) e(9);
XX+   if (tmsbuf.tms_cutime < 0) e(10);
XX+   if (tmsbuf.tms_cstime < 0) e(11);
XX+ }
XX+ 
XX+ void test2h()
XX+ {
XX+ /* Test getgroups(). */
XX+ 
XX+   gid_t g[10];
XX+ 
XX+   subtest = 8;
XX+   errno = -8000;
XX+   if (getgroups(10, g) != 0) e(1);
XX+   if (getgroups(1, g) != 0) e(2);
XX+   if (getgroups(0, g) != 0) e(3);
XX+ }
XX+ 
XX+ 
XX+ void sigpip(s)
XX+ int s;				/* for ANSI */
XX+ {
XX+   sigct++;
XX+   cumsig++;
XX+ }
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX+ 	exit(4);
XX+   }
XX+ }
XX+ 
XX+ void e(n)
XX+ int n;
XX+ {
XX+   int err_num = errno;		/* save errno in case printf clobbers it */
XX+ 
XX+   printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX+   errno = err_num;		/* restore errno, just in case */
XX+   perror("");
XX+   if (errct++ > MAX_ERROR) {
XX+ 	printf("Too many errors;  test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX+ 	exit(1);
XX    }
XX  }
X/
Xecho x - test20.c.d
Xsed '/^X/s///' > test20.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test20.c  crc=14756  18363	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test20.c  crc=33739  19535	Fri Mar 19 21:25:05 1993
XX***************
XX*** 13,22 ****
XX  
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX- #include <limits.h>
XX  #include <dirent.h>
XX  #include <fcntl.h>
XX  #include <errno.h>
XX  #include <time.h>
XX  #include <unistd.h>
XX  #include <utime.h>
XX--- 13,24 ----
XX  
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX  #include <dirent.h>
XX  #include <fcntl.h>
XX  #include <errno.h>
XX+ #include <limits.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX  #include <time.h>
XX  #include <unistd.h>
XX  #include <utime.h>
XX***************
XX*** 35,60 ****
XX  char str3[] = {"Of why the sea is boiling hot and whether pigs have wings\n"};
XX  
XX  int subtest, errct;
XX- extern errno;
XX  
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX  
XX!   int i, m=0xFFFF;
XX  
XX    sync();
XX!   if (geteuid() == 0) {
XX! 	/* Must not run as root. */
XX! 	setgid(2);
XX! 	setuid(2);
XX    }
XX  
XX    if (argc == 2) m = atoi(argv[1]);
XX    printf("Test 20 ");
XX    fflush(stdout);
XX  
XX    for (i = 0; i < ITERATIONS; i++) {
XX  	if (m & 00001) test20a();	/* test for correct operation */
XX  	if (m & 00002) test20b();	/* test general error handling */
XX--- 37,78 ----
XX  char str3[] = {"Of why the sea is boiling hot and whether pigs have wings\n"};
XX  
XX  int subtest, errct;
XX  
XX! _PROTOTYPE(int main, (int argc, char *argv []));
XX! _PROTOTYPE(void test20a, (void));
XX! _PROTOTYPE(void checkdir, (DIR *dirp, int t));
XX! _PROTOTYPE(void test20b, (void));
XX! _PROTOTYPE(void test20c, (void));
XX! _PROTOTYPE(void test20d, (void));
XX! _PROTOTYPE(void test20e, (void));
XX! _PROTOTYPE(void test20f, (void));
XX! _PROTOTYPE(void test20g, (void));
XX! _PROTOTYPE(void test20h, (void));
XX! _PROTOTYPE(void test20i, (void));
XX! _PROTOTYPE(void test20j, (void));
XX! _PROTOTYPE(void e, (int n));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX  
XX!   int i, m = 0xFFFF;
XX  
XX    sync();
XX!   if (geteuid() == 0 || getuid() == 0) {
XX! 	printf("Test 20 cannot run as root; test aborted\n");
XX! 	exit(1);
XX    }
XX  
XX    if (argc == 2) m = atoi(argv[1]);
XX    printf("Test 20 ");
XX    fflush(stdout);
XX  
XX+   system("rm -rf DIR_20; mkdir DIR_20");
XX+   chdir("DIR_20");
XX+ 
XX    for (i = 0; i < ITERATIONS; i++) {
XX  	if (m & 00001) test20a();	/* test for correct operation */
XX  	if (m & 00002) test20b();	/* test general error handling */
XX***************
XX*** 67,80 ****
XX  	if (m & 00400) test20i();	/* test chmod() and chown() */
XX  	if (m & 01000) test20j();	/* test utime() */
XX    }
XX!   if (errct == 0)
XX! 	printf("ok\n");
XX!   else
XX! 	printf(" %d errors\n", errct);
XX!   exit(0);
XX  }
XX  
XX! test20a()
XX  {
XX  /* Subtest 1. Correct operation */
XX  
XX--- 85,95 ----
XX  	if (m & 00400) test20i();	/* test chmod() and chown() */
XX  	if (m & 01000) test20j();	/* test utime() */
XX    }
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX! void test20a()
XX  {
XX  /* Subtest 1. Correct operation */
XX  
XX***************
XX*** 123,129 ****
XX    system("rm -rf foo");
XX  }
XX  
XX! checkdir(dirp, t)
XX  DIR *dirp;			/* poinrter to directory stream */
XX  int t;				/* subtest number to use */
XX  {
XX--- 138,144 ----
XX    system("rm -rf foo");
XX  }
XX  
XX! void checkdir(dirp, t)
XX  DIR *dirp;			/* poinrter to directory stream */
XX  int t;				/* subtest number to use */
XX  {
XX***************
XX*** 175,185 ****
XX  }
XX  
XX  
XX! test20b()
XX  {
XX  /* Subtest 4.  Test error handling. */
XX  
XX!   int fd, fd2;
XX    DIR *dirp;
XX  
XX    subtest = 4;
XX--- 190,200 ----
XX  }
XX  
XX  
XX! void test20b()
XX  {
XX  /* Subtest 4.  Test error handling. */
XX  
XX!   int fd;
XX    DIR *dirp;
XX  
XX    subtest = 4;
XX***************
XX*** 208,214 ****
XX  }
XX  
XX  
XX! test20c()
XX  {
XX  /* Subtest 5.  See what happens if we open too many directory streams. */
XX  
XX--- 223,229 ----
XX  }
XX  
XX  
XX! void test20c()
XX  {
XX  /* Subtest 5.  See what happens if we open too many directory streams. */
XX  
XX***************
XX*** 234,250 ****
XX    for (i = 0; i < MAX_FD; i++) closedir(dirp[i]);	/* don't check */
XX  }
XX  
XX! test20d()
XX  {
XX  /* Test chdir and getcwd(). */
XX  
XX!   int i, fd;
XX    char *s;
XX    char base[BUF_SIZE], buf2[BUF_SIZE], tmp[BUF_SIZE];
XX  
XX    subtest = 6;
XX  
XX!   if (getcwd(base, BUF_SIZE) == (char *) NULL) 	e(1); /* get test dir's path */
XX    if (system("rm -rf Dir") != 0) e(2);	/* remove residue of previous test */
XX    if (mkdir("Dir", 0777) < 0) e(3); 	/* create directory called "Dir" */
XX  
XX--- 249,265 ----
XX    for (i = 0; i < MAX_FD; i++) closedir(dirp[i]);	/* don't check */
XX  }
XX  
XX! void test20d()
XX  {
XX  /* Test chdir and getcwd(). */
XX  
XX!   int fd;
XX    char *s;
XX    char base[BUF_SIZE], buf2[BUF_SIZE], tmp[BUF_SIZE];
XX  
XX    subtest = 6;
XX  
XX!   if (getcwd(base, BUF_SIZE) == (char *) NULL) e(1); /* get test dir's path */
XX    if (system("rm -rf Dir") != 0) e(2);	/* remove residue of previous test */
XX    if (mkdir("Dir", 0777) < 0) e(3); 	/* create directory called "Dir" */
XX  
XX***************
XX*** 301,311 ****
XX  }
XX  
XX  
XX! test20e()
XX  {
XX  /* Test open. */
XX  
XX!   int fd, bytes, bytes2, n;
XX    char buf[RD_BUF];
XX  
XX    subtest = 7;
XX--- 316,326 ----
XX  }
XX  
XX  
XX! void test20e()
XX  {
XX  /* Test open. */
XX  
XX!   int fd, bytes, bytes2;
XX    char buf[RD_BUF];
XX  
XX    subtest = 7;
XX***************
XX*** 352,363 ****
XX    if (unlink("T20") < 0) e(22);
XX  }
XX  
XX! test20f()
XX  {
XX  /* Test stat, fstat, umask. */
XX    int i, fd;
XX    mode_t m1;
XX    struct stat stbuf1, stbuf2;
XX  
XX    subtest = 8;
XX  
XX--- 367,379 ----
XX    if (unlink("T20") < 0) e(22);
XX  }
XX  
XX! void test20f()
XX  {
XX  /* Test stat, fstat, umask. */
XX    int i, fd;
XX    mode_t m1;
XX    struct stat stbuf1, stbuf2;
XX+   time_t t, t1;
XX  
XX    subtest = 8;
XX  
XX***************
XX*** 421,430 ****
XX    if (errno != EBADF) e(46);
XX    if (chmod("Dir", 0777) != 0) e(47);
XX    if (system("rm -rf foo Dir") != 0) e(48);
XX  }
XX  
XX  
XX! test20g()
XX  {
XX  /* Test link and unlink. */
XX    int i, fd;
XX--- 437,458 ----
XX    if (errno != EBADF) e(46);
XX    if (chmod("Dir", 0777) != 0) e(47);
XX    if (system("rm -rf foo Dir") != 0) e(48);
XX+ 
XX+   /* See if time looks reasonable. */
XX+   errno = 0;
XX+   t = time(&t1);		/* current time */
XX+   if (t < 650000000L) e(49);	/* 650000000 is Sept. 1990 */
XX+   unlink("T20f");
XX+   fd = creat("T20f", 0777);
XX+   if (fd < 0) e(50);
XX+   if (close(fd) < 0) e(51);
XX+   if (stat("T20f", &stbuf1) < 0) e(52);
XX+   if (stbuf1.st_mtime < t) e(53);
XX+   if (unlink("T20f") < 0) e(54);
XX  }
XX  
XX  
XX! void test20g()
XX  {
XX  /* Test link and unlink. */
XX    int i, fd;
XX***************
XX*** 573,579 ****
XX    if (close(fd) != 0) e(91);  
XX  }
XX  
XX! test20h()
XX  {
XX  /* Test access. */
XX  
XX--- 601,607 ----
XX    if (close(fd) != 0) e(91);  
XX  }
XX  
XX! void test20h()
XX  {
XX  /* Test access. */
XX  
XX***************
XX*** 609,615 ****
XX    if (unlink("A1") != 0) e(22);
XX  }
XX  
XX! test20i()
XX  {
XX  /* Test chmod. */
XX  
XX--- 637,643 ----
XX    if (unlink("A1") != 0) e(22);
XX  }
XX  
XX! void test20i()
XX  {
XX  /* Test chmod. */
XX  
XX***************
XX*** 649,660 ****
XX    if (unlink("A1") != 0) e(9);
XX  }
XX  
XX! test20j()
XX  {
XX  /* Test utime. */
XX  
XX!   int i, fd;
XX!   time_t tloc, t;
XX    struct utimbuf times;
XX    struct stat stbuf;
XX  
XX--- 677,688 ----
XX    if (unlink("A1") != 0) e(9);
XX  }
XX  
XX! void test20j()
XX  {
XX  /* Test utime. */
XX  
XX!   int fd;
XX!   time_t tloc;
XX    struct utimbuf times;
XX    struct stat stbuf;
XX  
XX***************
XX*** 665,680 ****
XX    if (utime("A2", &times) != 0) e(3);
XX    if (stat("A2", &stbuf) != 0) e(4);
XX    if (stbuf.st_mtime != 100) e(5);
XX    tloc = time((time_t *)NULL);		/* get current time */
XX!   if (utime("A2", (struct utimbuf *)NULL) != 0) e(6);
XX    if (stat("A2", &stbuf) != 0) e(7);
XX!   t = stbuf.st_mtime - tloc;
XX!   if (t < -1 || t > 1) e(8);
XX    if (close(fd) != 0) e(9);
XX    if (unlink("A2") != 0) e(10);
XX  }
XX  
XX! e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX--- 693,709 ----
XX    if (utime("A2", &times) != 0) e(3);
XX    if (stat("A2", &stbuf) != 0) e(4);
XX    if (stbuf.st_mtime != 100) e(5);
XX+ 
XX    tloc = time((time_t *)NULL);		/* get current time */
XX!   times.modtime = tloc;
XX!   if (utime("A2", &times) != 0) e(6);
XX    if (stat("A2", &stbuf) != 0) e(7);
XX!   if (stbuf.st_mtime != tloc) e(8);
XX    if (close(fd) != 0) e(9);
XX    if (unlink("A2") != 0) e(10);
XX  }
XX  
XX! void e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX***************
XX*** 685,690 ****
XX--- 714,736 ----
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX+ 	exit(1);
XX+   }
XX+ }
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX  	exit(1);
XX    }
XX  }
X/
Xecho x - test21.c.d
Xsed '/^X/s///' > test21.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test21.c  crc=17070  18558	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test21.c  crc=29484  19981	Fri Mar 19 21:25:06 1993
XX***************
XX*** 5,25 ****
XX   *	rename(),  mkdir(),  rmdir()
XX   */
XX  
XX- 
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX  #include <limits.h>
XX  #include <unistd.h>
XX! #include <fcntl.h>
XX! #include <errno.h>
XX  
XX! #define ITERATIONS        10
XX  #define MAX_ERROR 4
XX  
XX  int subtest, errct;
XX- extern errno;
XX  
XX! main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX--- 5,45 ----
XX   *	rename(),  mkdir(),  rmdir()
XX   */
XX  
XX  #include <sys/types.h>
XX  #include <sys/stat.h>
XX+ #include <errno.h>
XX+ #include <fcntl.h>
XX  #include <limits.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX  #include <unistd.h>
XX! #include <stdio.h>
XX  
XX! #define ITERATIONS        1
XX  #define MAX_ERROR 4
XX  
XX  int subtest, errct;
XX  
XX! _PROTOTYPE(int main, (int argc, char *argv []));
XX! _PROTOTYPE(void test21a, (void));
XX! _PROTOTYPE(void test21b, (void));
XX! _PROTOTYPE(void test21c, (void));
XX! _PROTOTYPE(void test21d, (void));
XX! _PROTOTYPE(void test21e, (void));
XX! _PROTOTYPE(void test21f, (void));
XX! _PROTOTYPE(void test21g, (void));
XX! _PROTOTYPE(void test21h, (void));
XX! _PROTOTYPE(void test21i, (void));
XX! _PROTOTYPE(void test21k, (void));
XX! _PROTOTYPE(void test21l, (void));
XX! _PROTOTYPE(void test21m, (void));
XX! _PROTOTYPE(void test21n, (void));
XX! _PROTOTYPE(void test21o, (void));
XX! _PROTOTYPE(int get_link, (char *name));
XX! _PROTOTYPE(void e, (int n));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! int main(argc, argv)
XX  int argc;
XX  char *argv[];
XX  {
XX***************
XX*** 27,41 ****
XX    int i, m = 0xFFFF;
XX  
XX    sync();
XX!   if (geteuid() == 0) {
XX! 	/* Must not run as root. */
XX! 	setgid(2);
XX! 	setuid(2);
XX    }
XX  
XX    if (argc == 2) m = atoi(argv[1]);
XX    printf("Test 21 ");
XX  
XX    for (i = 0; i < ITERATIONS; i++) {
XX  	if (m & 00001) test21a();
XX  	if (m & 00002) test21b();
XX--- 47,64 ----
XX    int i, m = 0xFFFF;
XX  
XX    sync();
XX!   if (geteuid() == 0 || getuid() == 0) {
XX! 	printf("Test 21 cannot run as root; test aborted\n");
XX! 	exit(1);
XX    }
XX  
XX    if (argc == 2) m = atoi(argv[1]);
XX    printf("Test 21 ");
XX+   fflush(stdout);
XX  
XX+   system("rm -rf DIR_21; mkdir DIR_21");
XX+   chdir("DIR_21");
XX+ 
XX    for (i = 0; i < ITERATIONS; i++) {
XX  	if (m & 00001) test21a();
XX  	if (m & 00002) test21b();
XX***************
XX*** 50,71 ****
XX  	if (m & 02000) test21l();
XX  	if (m & 04000) test21m();
XX  	if (m & 010000) test21n();
XX    }
XX!   if (errct == 0)
XX! 	printf("ok\n");
XX!   else
XX! 	printf(" %d errors\n", errct);
XX!   exit(0);
XX  }
XX  
XX! test21a()
XX  {
XX  /* Test rename(). */
XX  
XX!   int fd, fd2, fd3;
XX    char buf[PATH_MAX+1], buf1[PATH_MAX+1], buf2[PATH_MAX+1];
XX    struct stat stat1, stat2;
XX-   extern char *getcwd();
XX  
XX    subtest = 1;
XX  
XX--- 73,91 ----
XX  	if (m & 02000) test21l();
XX  	if (m & 04000) test21m();
XX  	if (m & 010000) test21n();
XX+ 	if (m & 020000) test21o();
XX    }
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX! void test21a()
XX  {
XX  /* Test rename(). */
XX  
XX!   int fd, fd2;
XX    char buf[PATH_MAX+1], buf1[PATH_MAX+1], buf2[PATH_MAX+1];
XX    struct stat stat1, stat2;
XX  
XX    subtest = 1;
XX  
XX***************
XX*** 220,226 ****
XX  
XX    
XX  
XX! test21b()
XX  {
XX  /* Test mkdir() and rmdir(). */
XX  
XX--- 240,246 ----
XX  
XX    
XX  
XX! void test21b()
XX  {
XX  /* Test mkdir() and rmdir(). */
XX  
XX***************
XX*** 252,265 ****
XX    }
XX  }
XX  
XX! test21c()
XX  {
XX  /* Test mkdir() and rmdir(). */
XX  
XX-   int i;
XX-   char name[3];
XX-   struct stat statbuf;
XX- 
XX    subtest = 3;
XX  
XX    if (mkdir("D1", 0777) != 0) e(1);
XX--- 272,281 ----
XX    }
XX  }
XX  
XX! void test21c()
XX  {
XX  /* Test mkdir() and rmdir(). */
XX  
XX    subtest = 3;
XX  
XX    if (mkdir("D1", 0777) != 0) e(1);
XX***************
XX*** 283,295 ****
XX    if (rmdir("D1") != 0) e(17);
XX  }
XX    
XX! test21d()
XX  {
XX  /* Test making directories with files and directories in them. */
XX  
XX!   int i, fd1, fd2, fd3, fd4, fd5, fd6, fd7, fd8, fd9;
XX!   char name[3];
XX!   struct stat statbuf;
XX  
XX    subtest = 4;
XX    
XX--- 299,309 ----
XX    if (rmdir("D1") != 0) e(17);
XX  }
XX    
XX! void test21d()
XX  {
XX  /* Test making directories with files and directories in them. */
XX  
XX!   int fd1, fd2, fd3, fd4, fd5, fd6, fd7, fd8, fd9;
XX  
XX    subtest = 4;
XX    
XX***************
XX*** 297,311 ****
XX    if (mkdir("D1/D2", 0777) != 0) e(2);
XX    if (mkdir("./D1/D3", 0777) != 0) e(3);
XX    if (mkdir("././D1/D4", 0777) != 0) e(4);
XX!   if ( (fd1 = creat("D1/D2/x")) < 0) e(5);
XX!   if ( (fd2 = creat("D1/D2/y")) < 0) e(6);
XX!   if ( (fd3 = creat("D1/D2/z")) < 0) e(7);
XX!   if ( (fd4 = creat("D1/D3/x")) < 0) e(8);
XX!   if ( (fd5 = creat("D1/D3/y")) < 0) e(9);
XX!   if ( (fd6 = creat("D1/D3/z")) < 0) e(10);
XX!   if ( (fd7 = creat("D1/D4/x")) < 0) e(11);
XX!   if ( (fd8 = creat("D1/D4/y")) < 0) e(12);
XX!   if ( (fd9 = creat("D1/D4/z")) < 0) e(13);
XX    if (unlink("D1/D2/z") != 0) e(14);
XX    if (unlink("D1/D2/y") != 0) e(15);
XX    if (unlink("D1/D2/x") != 0) e(16);
XX--- 311,325 ----
XX    if (mkdir("D1/D2", 0777) != 0) e(2);
XX    if (mkdir("./D1/D3", 0777) != 0) e(3);
XX    if (mkdir("././D1/D4", 0777) != 0) e(4);
XX!   if ( (fd1 = creat("D1/D2/x", 0700)) < 0) e(5);
XX!   if ( (fd2 = creat("D1/D2/y", 0700)) < 0) e(6);
XX!   if ( (fd3 = creat("D1/D2/z", 0700)) < 0) e(7);
XX!   if ( (fd4 = creat("D1/D3/x", 0700)) < 0) e(8);
XX!   if ( (fd5 = creat("D1/D3/y", 0700)) < 0) e(9);
XX!   if ( (fd6 = creat("D1/D3/z", 0700)) < 0) e(10);
XX!   if ( (fd7 = creat("D1/D4/x", 0700)) < 0) e(11);
XX!   if ( (fd8 = creat("D1/D4/y", 0700)) < 0) e(12);
XX!   if ( (fd9 = creat("D1/D4/z", 0700)) < 0) e(13);
XX    if (unlink("D1/D2/z") != 0) e(14);
XX    if (unlink("D1/D2/y") != 0) e(15);
XX    if (unlink("D1/D2/x") != 0) e(16);
XX***************
XX*** 332,343 ****
XX  }
XX  
XX  
XX! test21e()
XX  {
XX  /* Test error conditions. */
XX    
XX-   int fd;
XX- 
XX    subtest = 5;
XX  
XX    if (mkdir("D1", 0677) != 0) e(1);
XX--- 346,355 ----
XX  }
XX  
XX  
XX! void test21e()
XX  {
XX  /* Test error conditions. */
XX    
XX    subtest = 5;
XX  
XX    if (mkdir("D1", 0677) != 0) e(1);
XX***************
XX*** 357,363 ****
XX    if (rmdir("D1/ABCDEFGHIJKLMNOPQ") != 0) e(12);
XX    if (access("D1/ABCDEFGHIJKLMN", 7 ) != -1) e(13);
XX    errno = 0;
XX!   if (mkdir("D1/D2/x") != -1) e(14);
XX    if (errno != ENOENT) e(15);
XX  
XX    /* A particularly nasty test is when the parent has mode 0.  Although
XX--- 369,375 ----
XX    if (rmdir("D1/ABCDEFGHIJKLMNOPQ") != 0) e(12);
XX    if (access("D1/ABCDEFGHIJKLMN", 7 ) != -1) e(13);
XX    errno = 0;
XX!   if (mkdir("D1/D2/x", 0777) != -1) e(14);
XX    if (errno != ENOENT) e(15);
XX  
XX    /* A particularly nasty test is when the parent has mode 0.  Although
XX***************
XX*** 373,379 ****
XX    if (rmdir("D1") != 0) e(22);
XX  }
XX  
XX! test21f()
XX  {
XX  /* The rename() function affects the link count of all the files and
XX   * directories it goes near.  Test to make sure it gets everything ok.
XX--- 385,391 ----
XX    if (rmdir("D1") != 0) e(22);
XX  }
XX  
XX! void test21f()
XX  {
XX  /* The rename() function affects the link count of all the files and
XX   * directories it goes near.  Test to make sure it gets everything ok.
XX***************
XX*** 388,397 ****
XX   * and when it does not exist, giving 8 cases in all.
XX   */
XX  
XX!   int fd, D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX!   struct stat statbuf;
XX  
XX- 
XX    /* Test case 1: renaming a file within the same directory. */
XX    subtest = 6;
XX    if (mkdir("D1", 0777) != 0) e(1);
XX--- 400,407 ----
XX   * and when it does not exist, giving 8 cases in all.
XX   */
XX  
XX!   int fd, D1_before, D1_after, x_link, y_link;
XX  
XX    /* Test case 1: renaming a file within the same directory. */
XX    subtest = 6;
XX    if (mkdir("D1", 0777) != 0) e(1);
XX***************
XX*** 412,421 ****
XX  }
XX  
XX  
XX! test21g()
XX  {
XX    int fd, D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX-   struct stat statbuf;
XX  
XX    /* Test case 2: move a file to a new directory. */
XX    subtest = 7;
XX--- 422,430 ----
XX  }
XX  
XX  
XX! void test21g()
XX  {
XX    int fd, D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX  
XX    /* Test case 2: move a file to a new directory. */
XX    subtest = 7;
XX***************
XX*** 442,451 ****
XX    if (rmdir("D2") != 0) e(15);
XX  }
XX  
XX! test21h()
XX  {
XX!   int fd, D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX!   struct stat statbuf;
XX  
XX    /* Test case 3: renaming a directory within the same directory. */
XX    subtest = 8;
XX--- 451,459 ----
XX    if (rmdir("D2") != 0) e(15);
XX  }
XX  
XX! void test21h()
XX  {
XX!   int D1_before, D1_after, x_link, y_link;
XX  
XX    /* Test case 3: renaming a directory within the same directory. */
XX    subtest = 8;
XX***************
XX*** 466,475 ****
XX    if (rmdir("D1") != 0) e(11);
XX  }
XX  
XX! test21i()
XX  {
XX!   int fd, D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX!   struct stat statbuf;
XX  
XX    /* Test case 4: move a directory to a new directory. */
XX    subtest = 9;
XX--- 474,482 ----
XX    if (rmdir("D1") != 0) e(11);
XX  }
XX  
XX! void test21i()
XX  {
XX!   int D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX  
XX    /* Test case 4: move a directory to a new directory. */
XX    subtest = 9;
XX***************
XX*** 499,512 ****
XX    if (rmdir("D2") != 0) e(18);
XX  }
XX  
XX! test21k()
XX  {
XX  /* Now test the same 4 cases, except when the target exists. */
XX  
XX!   int fd, D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX!   struct stat statbuf;
XX  
XX- 
XX    /* Test case 5: renaming a file within the same directory. */
XX    subtest = 10;
XX    if (mkdir("D1", 0777) != 0) e(1);
XX--- 506,517 ----
XX    if (rmdir("D2") != 0) e(18);
XX  }
XX  
XX! void test21k()
XX  {
XX  /* Now test the same 4 cases, except when the target exists. */
XX  
XX!   int fd, D1_before, D1_after, x_link, y_link;
XX  
XX    /* Test case 5: renaming a file within the same directory. */
XX    subtest = 10;
XX    if (mkdir("D1", 0777) != 0) e(1);
XX***************
XX*** 528,537 ****
XX    if (rmdir("D1") != 0) e(12);
XX  }
XX  
XX! test21l()
XX  {
XX    int fd, D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX-   struct stat statbuf;
XX  
XX    /* Test case 6: move a file to a new directory. */
XX    subtest = 11;
XX--- 533,541 ----
XX    if (rmdir("D1") != 0) e(12);
XX  }
XX  
XX! void test21l()
XX  {
XX    int fd, D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX  
XX    /* Test case 6: move a file to a new directory. */
XX    subtest = 11;
XX***************
XX*** 560,569 ****
XX    if (rmdir("D2") != 0) e(17);
XX  }
XX  
XX! test21m()
XX  {
XX!   int fd, D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX!   struct stat statbuf;
XX  
XX    /* Test case 7: renaming a directory within the same directory. */
XX    subtest = 12;
XX--- 564,572 ----
XX    if (rmdir("D2") != 0) e(17);
XX  }
XX  
XX! void test21m()
XX  {
XX!   int D1_before, D1_after, x_link, y_link;
XX  
XX    /* Test case 7: renaming a directory within the same directory. */
XX    subtest = 12;
XX***************
XX*** 586,595 ****
XX  }
XX  
XX  
XX! test21n()
XX  {
XX!   int fd, D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX!   struct stat statbuf;
XX  
XX    /* Test case 8: move a directory to a new directory. */
XX    subtest = 13;
XX--- 589,597 ----
XX  }
XX  
XX  
XX! void test21n()
XX  {
XX!   int D1_before, D1_after, D2_before, D2_after, x_link, y_link;
XX  
XX    /* Test case 8: move a directory to a new directory. */
XX    subtest = 13;
XX***************
XX*** 621,627 ****
XX  }
XX  
XX  
XX! get_link(name)
XX  char *name;
XX  {
XX    struct stat statbuf;
XX--- 623,651 ----
XX  }
XX  
XX  
XX! void test21o()
XX! {
XX! 
XX!   /* Test trying to remove . and .. */
XX!   subtest = 14;
XX!   if (mkdir("D1", 0777) != 0) e(1);
XX!   if (chdir("D1") != 0) e(2);
XX!   if (rmdir(".") == 0) e(3);
XX!   if (rmdir("..") == 0) e(4);
XX!   if (mkdir("D2", 0777) != 0) e(5);
XX!   if (mkdir("D3", 0777) != 0) e(6);
XX!   if (mkdir("D4", 0777) != 0) e(7);
XX!   if (rmdir("D2/../D3/../D4") != 0) e(8);	/* legal way to remove D4 */
XX!   if (rmdir("D2/../D3/../D2/..") == 0) e(9);	/* removing self is illegal */
XX!   if (rmdir("D2/../D3/../D2/../..") == 0) e(10);/* removing parent is illegal*/
XX!   if (rmdir("../D1/../D1/D3") != 0) e(11);	/* legal way to remove D3 */
XX!   if (rmdir("./D2/../D2") != 0) e(12);		/* legal way to remove D2 */
XX!   if (chdir("..") != 0) e(13);
XX!   if (rmdir("D1") != 0) e(14);
XX! }
XX! 
XX! 
XX! int get_link(name)
XX  char *name;
XX  {
XX    struct stat statbuf;
XX***************
XX*** 635,641 ****
XX  }
XX  
XX  
XX! e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX--- 659,665 ----
XX  }
XX  
XX  
XX! void e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX***************
XX*** 645,650 ****
XX--- 669,691 ----
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX+ 	exit(1);
XX+   }
XX+ }
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX  	exit(1);
XX    }
XX  }
X/
Xecho x - test3.c.d
Xsed '/^X/s///' > test3.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test3.c  crc=16624   1564	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test3.c  crc=23444   6888	Fri Mar 19 21:25:14 1993
XX***************
XX*** 1,126 ****
XX! /* test 3 */
XX  
XX  #include <signal.h>
XX  #include <stdio.h>
XX  
XX! int is, array[4];
XX! int parsigs, parpid, parcum;
XX! int sigct, cumsig, errct;
XX  
XX! main()
XX  {
XX!   int i;
XX  
XX    printf("Test  3 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX!   for (i = 0; i < 9; i++) {
XX! 	test91();
XX! 	test92();
XX    }
XX!   if (cumsig != 9) e(3);
XX!   if (errct == 0)
XX! 	printf("ok\n");
XX!   else
XX! 	printf("%d errors\n", errct);
XX  }
XX  
XX! 
XX! test90()
XX  {
XX!   extern catch();
XX  
XX!   int n, pid;
XX  
XX!   parpid = getpid();
XX!   signal(10, catch);
XX  
XX!   if (pid = fork()) {
XX! 	while (parsigs == 0);
XX! 	if (kill(pid, 9) < 0) e(1);
XX! 	wait(&n);
XX! 	if (n != 9) e(2);
XX!   } else {
XX! 	kill(parpid, 10);
XX! 	pause();
XX!   }
XX  }
XX  
XX  
XX! catch()
XX  {
XX!   parsigs++;
XX!   parcum++;
XX  }
XX  
XX! e(n)
XX! int n;
XX  {
XX!   printf("Error %d  ", n);
XX!   errct++;
XX!   perror("");
XX  }
XX  
XX  
XX! test91()
XX  {
XX!   int fd[2], n, sigpip();
XX!   char buf[4];
XX  
XX!   sigct = 0;
XX!   signal(SIGPIPE, sigpip);
XX!   pipe(fd);
XX!   if (fork()) {
XX! 	/* Parent */
XX! 	close(fd[0]);
XX! 	while (sigct == 0) {
XX! 		write(fd[1], buf, 1);
XX! 	}
XX! 	wait(&n);
XX!   } else {
XX! 	/* Child */
XX! 	close(fd[0]);
XX! 	close(fd[1]);
XX  	exit(0);
XX    }
XX  }
XX  
XX- sigpip()
XX- {
XX-   sigct++;
XX-   cumsig++;
XX- }
XX  
XX  
XX! test92()
XX  {
XX!   int pid, n;
XX  
XX!   signal(SIGINT, SIG_DFL);
XX!   is = 0;
XX!   if ((array[is++] = fork()) > 0) {
XX! 	if ((array[is++] = fork()) > 0) {
XX! 		if ((array[is++] = fork()) > 0) {
XX! 			if ((array[is++] = fork()) > 0) {
XX! 				signal(SIGINT, SIG_IGN);
XX! 				kill(array[0], SIGINT);
XX! 				kill(array[1], SIGINT);
XX! 				kill(array[2], SIGINT);
XX! 				kill(array[3], SIGINT);
XX! 				wait(&n);
XX! 				wait(&n);
XX! 				wait(&n);
XX! 				wait(&n);
XX! 			} else {
XX! 				pause();
XX! 			}
XX! 		} else {
XX! 			pause();
XX! 		}
XX! 	} else {
XX! 		pause();
XX! 	}
XX!   } else {
XX! 	pause();
XX    }
XX  }
XX--- 1,259 ----
XX! /* test 3 - library routines rather than system calls */
XX  
XX+ #include <sys/types.h>
XX+ #include <sys/utsname.h>
XX+ #include <errno.h>
XX+ #include <fcntl.h>
XX+ #include <limits.h>
XX  #include <signal.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX+ #include <unistd.h>
XX  #include <stdio.h>
XX  
XX! #define ITERATIONS 10
XX! #define MAX_ERROR 4
XX! #define SIZE 64
XX  
XX! int errct, subtest;
XX! char el_weirdo[] = "\n\t\\\e@@!!##\e\e\n\n";
XX! 
XX! _PROTOTYPE(int main, (int argc, char *argv []));
XX! _PROTOTYPE(void test3a, (void));
XX! _PROTOTYPE(void test3b, (void));
XX! _PROTOTYPE(void test3c, (void));
XX! _PROTOTYPE(void test3d, (void));
XX! _PROTOTYPE(void test3e, (void));
XX! _PROTOTYPE(void quit, (void));
XX! _PROTOTYPE(void e, (int n));
XX! 
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   int i, m = 0xFFFF;
XX  
XX+   sync();
XX+   if (geteuid() == 0 || getuid() == 0) {
XX+ 	printf("Test  3 cannot run as root; test aborted\n");
XX+ 	exit(1);
XX+   }
XX+ 
XX+   if (argc == 2) m = atoi(argv[1]);
XX+ 
XX    printf("Test  3 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX!   system("rm -rf DIR_03; mkdir DIR_03");
XX!   chdir("DIR_03");
XX! 
XX!   for (i = 0; i < ITERATIONS; i++) {
XX! 	if (m & 0001) test3a();
XX! 	if (m & 0002) test3b();
XX! 	if (m & 0004) test3c();
XX! 	if (m & 0010) test3d();
XX! 	if (m & 0020) test3e();
XX    }
XX!   quit();
XX!   return(-1);			/* impossible */
XX! 
XX  }
XX  
XX! void test3a()
XX  {
XX! /* Signal set manipulation. */
XX  
XX!   sigset_t s, s1;
XX  
XX!   subtest = 1;
XX!   errno = -1000;		/* None of these calls set errno. */
XX!   if (sigemptyset(&s) != 0) e(1);
XX!   if (sigemptyset(&s1) != 0) e(2);
XX!   if (sigaddset(&s, SIGABRT) != 0) e(3);
XX!   if (sigaddset(&s, SIGALRM) != 0) e(4);
XX!   if (sigaddset(&s, SIGFPE ) != 0) e(5);
XX!   if (sigaddset(&s, SIGHUP ) != 0) e(6);
XX!   if (sigaddset(&s, SIGILL ) != 0) e(7);
XX!   if (sigaddset(&s, SIGINT ) != 0) e(8);
XX!   if (sigaddset(&s, SIGKILL) != 0) e(9);
XX!   if (sigaddset(&s, SIGPIPE) != 0) e(10);
XX!   if (sigaddset(&s, SIGQUIT) != 0) e(11);
XX!   if (sigaddset(&s, SIGSEGV) != 0) e(12);
XX!   if (sigaddset(&s, SIGTERM) != 0) e(13);
XX!   if (sigaddset(&s, SIGUSR1) != 0) e(14);
XX!   if (sigaddset(&s, SIGUSR2) != 0) e(15);
XX!   
XX!   if (sigismember(&s, SIGABRT) != 1) e(16);
XX!   if (sigismember(&s, SIGALRM) != 1) e(17);
XX!   if (sigismember(&s, SIGFPE ) != 1) e(18);
XX!   if (sigismember(&s, SIGHUP ) != 1) e(19);
XX!   if (sigismember(&s, SIGILL ) != 1) e(20);
XX!   if (sigismember(&s, SIGINT ) != 1) e(21);
XX!   if (sigismember(&s, SIGKILL) != 1) e(22);
XX!   if (sigismember(&s, SIGPIPE) != 1) e(23);
XX!   if (sigismember(&s, SIGQUIT) != 1) e(24);
XX!   if (sigismember(&s, SIGSEGV) != 1) e(25);
XX!   if (sigismember(&s, SIGTERM) != 1) e(26);
XX!   if (sigismember(&s, SIGUSR1) != 1) e(27);
XX!   if (sigismember(&s, SIGUSR2) != 1) e(28);
XX!   
XX!   if (sigdelset(&s, SIGABRT) != 0) e(29);
XX!   if (sigdelset(&s, SIGALRM) != 0) e(30);
XX!   if (sigdelset(&s, SIGFPE ) != 0) e(31);
XX!   if (sigdelset(&s, SIGHUP ) != 0) e(32);
XX!   if (sigdelset(&s, SIGILL ) != 0) e(33);
XX!   if (sigdelset(&s, SIGINT ) != 0) e(34);
XX!   if (sigdelset(&s, SIGKILL) != 0) e(35);
XX!   if (sigdelset(&s, SIGPIPE) != 0) e(36);
XX!   if (sigdelset(&s, SIGQUIT) != 0) e(37);
XX!   if (sigdelset(&s, SIGSEGV) != 0) e(38);
XX!   if (sigdelset(&s, SIGTERM) != 0) e(39);
XX!   if (sigdelset(&s, SIGUSR1) != 0) e(40);
XX!   if (sigdelset(&s, SIGUSR2) != 0) e(41);
XX!   
XX!   if (s != s1) e(42);
XX  
XX!   if (sigaddset(&s, SIGILL) != 0) e(43);
XX!   if (s == s1) e(44);  
XX! 
XX!   if (sigfillset(&s) != 0) e(45);
XX!   if (sigismember(&s, SIGABRT) != 1) e(46);
XX!   if (sigismember(&s, SIGALRM) != 1) e(47);
XX!   if (sigismember(&s, SIGFPE ) != 1) e(48);
XX!   if (sigismember(&s, SIGHUP ) != 1) e(49);
XX!   if (sigismember(&s, SIGILL ) != 1) e(50);
XX!   if (sigismember(&s, SIGINT ) != 1) e(51);
XX!   if (sigismember(&s, SIGKILL) != 1) e(52);
XX!   if (sigismember(&s, SIGPIPE) != 1) e(53);
XX!   if (sigismember(&s, SIGQUIT) != 1) e(54);
XX!   if (sigismember(&s, SIGSEGV) != 1) e(55);
XX!   if (sigismember(&s, SIGTERM) != 1) e(56);
XX!   if (sigismember(&s, SIGUSR1) != 1) e(57);
XX!   if (sigismember(&s, SIGUSR2) != 1) e(58);
XX! 
XX!   /* Test error returns. */
XX!   if (sigaddset(&s, -1) != -1) e(59);
XX!   if (sigaddset(&s, -1) != -1) e(60);
XX!   if (sigismember(&s, -1) != -1) e(61);
XX!   if (sigaddset(&s, 10000) != -1) e(62);
XX!   if (sigaddset(&s, 10000) != -1) e(63);
XX!   if (sigismember(&s, 10000) != -1) e(64);
XX! 
XX  }
XX  
XX+ void test3b()
XX+ {
XX+ /* Test uname. */
XX  
XX!   struct utsname u;		/* contains all kinds of system ids */
XX! 
XX!   subtest = 2;
XX!   errno = -2000;		/* None of these calls set errno. */
XX!   if (access("/etc/uname", R_OK) != 0) {
XX! 	printf("/etc/uname is not present.  Cannot test uname()\n");
XX! 	errct++;
XX! 	return;
XX!   }
XX!   if (uname(&u) != 0) e(1);
XX!   if (strncmp(u.sysname, "MINIX", 5) != 0) e(2);    /* only one defined */
XX! }
XX! 
XX! void test3c()
XX  {
XX! /* Test getenv.  Asume HOME, PATH, and LOGNAME exist (not strictly required).*/
XX! 
XX!   char *p, name[SIZE];
XX! 
XX!   subtest = 3;
XX!   errno = -3000;		/* None of these calls set errno. */
XX!   if ( (p = getenv("HOME")) == NULL) e(1);
XX!   if (*p != '/') e(2);		/* path must be absolute */
XX!   if ( (p = getenv("PATH")) == NULL) e(3);
XX!   if (*p != ':') e(4);		/* this is a MINIX convention, not POSIX */
XX!   if ( (p = getenv("LOGNAME")) == NULL) e(5);
XX!   strcpy(name, p);		/* save it, since getlogin might wipe it out */
XX!   p = getlogin();
XX!   if (strcmp(p, name) != 0) e(6);
XX! 
XX!   /* The following test could fail in a legal POSIX system.  However, if it
XX!    * does, you deserve it to fail.
XX!    */
XX!   if (getenv(el_weirdo) != NULL) e(7);
XX  }
XX  
XX! void test3d()
XX  {
XX! /* Test ctermid, ttyname, and isatty. */
XX! 
XX!   int fd;
XX!   char *p, name[L_ctermid];
XX! 
XX!   subtest = 4;
XX!   errno = -4000;		/* None of these calls set errno. */
XX! 
XX!   /* Test ctermid first. */
XX!   if ( (p = ctermid(name)) == NULL) e(1);
XX!   if (strcmp(p, name) != 0) e(2);
XX!   if (strncmp(p, "/dev/tty", 8) != 0) e(3);	/* MINIX convention */
XX!   
XX!   if ( (p = ttyname(0)) == NULL) e(4);
XX!   if (strncmp(p, "/dev/tty", 8) != 0) e(5);
XX!   if ( (p = ttyname(3)) != NULL) e(6);
XX!   if (ttyname(5000) != NULL) e(7);
XX!   if ( (fd = creat("T3a", 0777)) < 0) e(8);
XX!   if (ttyname(fd) != NULL) e(9);
XX! 
XX!   if (isatty(0) != 1) e(10);
XX!   if (isatty(3) != 0) e(11);
XX!   if (isatty(fd) != 0) e(12);
XX!   if (close(fd) != 0) e(13);
XX!   if (ttyname(fd) != NULL) e(14);
XX  }
XX  
XX+ void test3e()
XX+ {
XX+ /* Test ctermid, ttyname, and isatty. */
XX  
XX!   subtest = 5;
XX!   errno = -5000;		/* None of these calls set errno. */
XX! 
XX!   if (sysconf(_SC_ARG_MAX) < _POSIX_ARG_MAX) e(1);
XX!   if (sysconf(_SC_CHILD_MAX) < _POSIX_CHILD_MAX) e(2);
XX!   if (sysconf(_SC_NGROUPS_MAX) < 0) e(3);
XX!   if (sysconf(_SC_OPEN_MAX) < _POSIX_OPEN_MAX) e(4);
XX! 
XX!   /* The rest are MINIX specific */
XX!   if (sysconf(_SC_JOB_CONTROL) >= 0) e(5);	/* no job control! */
XX! }
XX! 
XX! void quit()
XX  {
XX!   chdir("..");
XX!   system("rm -rf DIR*");
XX  
XX!   if (errct == 0) {
XX! 	printf("ok\n");
XX  	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX+ 	exit(4);
XX    }
XX  }
XX  
XX  
XX  
XX! void e(n)
XX! int n;
XX  {
XX!   int err_num = errno;		/* save errno in case printf clobbers it */
XX  
XX!   printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX!   errno = err_num;		/* restore errno, just in case */
XX!   perror("");
XX!   if (errct++ > MAX_ERROR) {
XX! 	printf("Test aborted.  Too many errors: ");
XX! 	chdir("..");
XX! 	system("rm -rf DIR*");
XX! 	exit(1);
XX    }
XX  }
X/
Xecho x - test4.c.d
Xsed '/^X/s///' > test4.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test4.c  crc=28861   1191	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test4.c  crc=52464   1648	Sat Dec 19 19:50:07 1992
XX***************
XX*** 1,33 ****
XX  /* test 4 */
XX  
XX  #include <sys/types.h>
XX  #include <fcntl.h>
XX  #include <unistd.h>
XX  #include <stdio.h>
XX  
XX  int pid0, pid1, pid2, pid3, s;
XX! int i, fd;
XX! int nextb;
XX  char *tempfile = "test4.temp";
XX  char buf[1024];
XX  
XX! main()
XX  {
XX    int k;
XX  
XX-   creat(tempfile, 0777);
XX    printf("Test  4 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX    for (k = 0; k < 20; k++) {
XX  	subr();
XX    }
XX-   printf("ok\n");
XX    unlink(tempfile);
XX  }
XX  
XX  
XX! subr()
XX  {
XX    if (pid0 = fork()) {
XX  	/* Parent 0 */
XX--- 1,44 ----
XX  /* test 4 */
XX  
XX  #include <sys/types.h>
XX+ #include <sys/wait.h>
XX  #include <fcntl.h>
XX+ #include <signal.h>
XX+ #include <stdlib.h>
XX  #include <unistd.h>
XX  #include <stdio.h>
XX  
XX  int pid0, pid1, pid2, pid3, s;
XX! int i, fd, nextb, errct = 0;
XX  char *tempfile = "test4.temp";
XX  char buf[1024];
XX  
XX! _PROTOTYPE(int main, (void));
XX! _PROTOTYPE(void subr, (void));
XX! _PROTOTYPE(void nofork, (void));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! int main()
XX  {
XX    int k;
XX  
XX    printf("Test  4 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX+   system("rm -rf DIR_04; mkdir DIR_04");
XX+   chdir("DIR_04");
XX+ 
XX+   creat(tempfile, 0777);
XX    for (k = 0; k < 20; k++) {
XX  	subr();
XX    }
XX    unlink(tempfile);
XX+   quit();
XX+   return(-1);			/* impossible */
XX  }
XX  
XX  
XX! void subr()
XX  {
XX    if (pid0 = fork()) {
XX  	/* Parent 0 */
XX***************
XX*** 68,75 ****
XX    }
XX  }
XX  
XX! nofork()
XX  {
XX    printf("Fork failed.  Not enough memory.\n");
XX    exit(1);
XX  }
XX--- 79,101 ----
XX    }
XX  }
XX  
XX! void nofork()
XX  {
XX    printf("Fork failed.  Not enough memory.\n");
XX    exit(1);
XX+ }
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX+ 	exit(1);
XX+   }
XX  }
X/
Xecho x - test5.c.d
Xsed '/^X/s///' > test5.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test5.c  crc=44672   4953	Sat Apr 21 22:26:25 1990
XX--- /home/top/ast/minix/1.6.25/test/test5.c  crc=28922   7330	Sat Dec 19 19:50:07 1992
XX***************
XX*** 1,53 ****
XX  /* test 5 */
XX  
XX! #include <signal.h>
XX  #include <errno.h>
XX  #include <stdio.h>
XX  
XX  #define MAX_ERROR 4
XX  
XX- extern int errno;
XX  int errct;
XX! int subtest = 1;
XX! 
XX! int func1(), func10(), func8(), funcalrm(), func11();
XX! int childsigs, parsigs, alarms;
XX  int zero[1024];
XX  
XX! main()
XX  {
XX!   int i;
XX  
XX    printf("Test  5 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX!   for (i = 0; i < 1; i++) {
XX! 	test50();
XX! 	test51();
XX! 	test53();
XX! 	test54();
XX! 	test55();
XX! 	test56();
XX    }
XX!   if (errct == 0)
XX! 	printf("ok\n");
XX!   else
XX! 	printf("%d errors\n", errct);
XX!   exit(0);
XX  }
XX  
XX  
XX  
XX! test50()
XX  {
XX    int parpid, childpid, flag, *zp;
XX  
XX    flag = 0;
XX    for (zp = &zero[0]; zp < &zero[1024]; zp++)
XX  	if (*zp != 0) flag = 1;
XX    if (flag) e(0);		/* check if bss is cleared to 0 */
XX!   if (signal(1, func1) < 0) e(1);
XX!   if (signal(10, func10) < 0) e(2);
XX    parpid = getpid();
XX    if (childpid = fork()) {
XX  	if (childpid < 0) ex();
XX--- 1,96 ----
XX  /* test 5 */
XX  
XX! #include <sys/types.h>
XX! #include <sys/wait.h>
XX  #include <errno.h>
XX+ #include <fcntl.h>
XX+ #include <signal.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX  #include <stdio.h>
XX  
XX+ #define ITERATIONS 2
XX  #define MAX_ERROR 4
XX  
XX  int errct;
XX! int subtest;
XX  int zero[1024];
XX  
XX! int sigmap[5] = {9, 10, 11};
XX! 
XX! _PROTOTYPE(int main, (int argc, char *argv[]));
XX! _PROTOTYPE(void test5a, (void));
XX! _PROTOTYPE(void parent, (int childpid));
XX! _PROTOTYPE(void child, (int parpid));
XX! _PROTOTYPE(void func1, (int s));
XX! _PROTOTYPE(void func8, (int s));
XX! _PROTOTYPE(void func10, (int s));
XX! _PROTOTYPE(void func11, (int s));
XX! _PROTOTYPE(void test5b, (void));
XX! _PROTOTYPE(void test5c, (void));
XX! _PROTOTYPE(void test5d, (void));
XX! _PROTOTYPE(void test5e, (void));
XX! _PROTOTYPE(void test5f, (void));
XX! _PROTOTYPE(void test5g, (void));
XX! _PROTOTYPE(void funcalrm, (int s));
XX! _PROTOTYPE(void test5h, (void));
XX! _PROTOTYPE(void test5i, (void));
XX! _PROTOTYPE(void ex, (void));
XX! _PROTOTYPE(void e, (int n));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! 
XX! #ifdef _ANSI
XX! void (*Signal(int _sig, void (*_func)(int)))(int);
XX! #define SIG_ZERO	((void (*)(int))0)	/* default signal handling */
XX! #else
XX! sighandler_t Signal();
XX! /* void (*Signal()) (); */
XX! #define SIG_ZERO	((void (*)())0)		/* default signal handling */
XX! #endif
XX! 
XX! _VOLATILE int childsigs, parsigs, alarms;
XX! 
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   int i, m = 0x7777;
XX  
XX    printf("Test  5 ");
XX    fflush(stdout);		/* have to flush for child's benefit */
XX  
XX!   system("rm -rf DIR_05; mkdir DIR_05");
XX!   chdir("DIR_05");
XX! 
XX!   for (i = 0; i < ITERATIONS; i++) {
XX! 	if (m & 0001) test5a();
XX! 	if (m & 0002) test5b();
XX! 	if (m & 0004) test5c();
XX! 	if (m & 0010) test5d();
XX! 	if (m & 0020) test5e();
XX! 	if (m & 0040) test5f();
XX! 	if (m & 0100) test5g();
XX! 	if (m & 0200) test5h();
XX! 	if (m & 0400) test5i();
XX    }
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX  
XX  
XX! void test5a()
XX  {
XX    int parpid, childpid, flag, *zp;
XX  
XX+   subtest = 0;
XX    flag = 0;
XX    for (zp = &zero[0]; zp < &zero[1024]; zp++)
XX  	if (*zp != 0) flag = 1;
XX    if (flag) e(0);		/* check if bss is cleared to 0 */
XX!   if (Signal(1, func1) ==  SIG_ERR) e(1);
XX!   if (Signal(10, func10) < SIG_ZERO) e(2);
XX    parpid = getpid();
XX    if (childpid = fork()) {
XX  	if (childpid < 0) ex();
XX***************
XX*** 55,79 ****
XX    } else {
XX  	child(parpid);
XX    }
XX!   if (signal(1, SIG_DFL) < 0) e(4);
XX!   if (signal(10, SIG_DFL) < 0) e(5);
XX  }
XX  
XX! parent(childpid)
XX  int childpid;
XX  {
XX!   int i;
XX  
XX    for (i = 0; i < 3; i++) {
XX  	if (kill(childpid, 1) < 0) e(6);
XX  	while (parsigs == 0);
XX  	parsigs--;
XX    }
XX!   if (wait(&i) < 0) e(7);
XX    if (i != 256 * 6) e(8);
XX  }
XX  
XX! child(parpid)
XX  int parpid;
XX  {
XX  
XX--- 98,122 ----
XX    } else {
XX  	child(parpid);
XX    }
XX!   if (Signal(1, SIG_DFL) <  SIG_ZERO) e(4);
XX!   if (Signal(10, SIG_DFL) < SIG_ZERO) e(5);
XX  }
XX  
XX! void parent(childpid)
XX  int childpid;
XX  {
XX!   int i, pid;
XX  
XX    for (i = 0; i < 3; i++) {
XX  	if (kill(childpid, 1) < 0) e(6);
XX  	while (parsigs == 0);
XX  	parsigs--;
XX    }
XX!   if ( (pid = wait(&i)) < 0) e(7);
XX    if (i != 256 * 6) e(8);
XX  }
XX  
XX! void child(parpid)
XX  int parpid;
XX  {
XX  
XX***************
XX*** 87,109 ****
XX    exit(6);
XX  }
XX  
XX! func1()
XX  {
XX!   if (signal(1, func1) < 0) e(10);
XX    childsigs++;
XX  }
XX  
XX! func10()
XX  {
XX!   if (signal(10, func10) < 0) e(11);
XX    parsigs++;
XX  }
XX  
XX  
XX! test51()
XX  {
XX    int cpid, n, pid;
XX  
XX    if ((pid = fork())) {
XX  	if (pid < 0) ex();
XX  	if ((pid = fork())) {
XX--- 130,166 ----
XX    exit(6);
XX  }
XX  
XX! void func1(s)
XX! int s;				/* for ANSI */
XX  {
XX!   if (Signal(1, func1) < SIG_ZERO) e(10);
XX    childsigs++;
XX  }
XX  
XX! void func8(s)
XX! int s;
XX  {
XX! }
XX! 
XX! void func10(s)
XX! int s;				/* for ANSI */
XX! {
XX!   if (Signal(10, func10) < SIG_ZERO) e(11);
XX    parsigs++;
XX  }
XX  
XX+ void func11(s)
XX+ int s;				/* for ANSI */
XX+ {
XX+   e(38);
XX+ }
XX  
XX! 
XX! void test5b()
XX  {
XX    int cpid, n, pid;
XX  
XX+   subtest = 1;
XX    if ((pid = fork())) {
XX  	if (pid < 0) ex();
XX  	if ((pid = fork())) {
XX***************
XX*** 126,162 ****
XX    }
XX  }
XX  
XX- test52()
XX- {
XX-   int pid, n, k;
XX  
XX!   pid = getpid();
XX!   if (getpid() == pid) k = fork();	/* only parent forks */
XX!   if (k < 0) ex();
XX!   if (getpid() == pid) k = fork();	/* only parent forks */
XX!   if (k < 0) ex();
XX!   if (getpid() == pid) k = fork();	/* only parent forks */
XX!   if (k < 0) ex();
XX! 
XX!   if (getpid() == pid) {
XX! 	if (kill(0, 9) < 0) e(16);
XX! 	if (wait(&n) < 0) e(17);
XX! 	if (wait(&n) < 0) e(18);
XX! 	if (wait(&n) < 0) e(19);
XX!   } else
XX! 	pause();
XX! }
XX! 
XX! int sigmap[5] = {9, 10, 11};
XX! test53()
XX  {
XX    int n, i, pid, wpid;
XX  
XX    /* Test exit status codes for processes killed by signals. */
XX    for (i = 0; i < 2; i++) {
XX  	if (pid = fork()) {
XX  		if (pid < 0) ex();
XX! 		sleep(5);	/* wait for child to pause */
XX  		if (kill(pid, sigmap[i]) < 0) {
XX  			e(20);
XX  			exit(1);
XX--- 183,199 ----
XX    }
XX  }
XX  
XX  
XX! void test5c()
XX  {
XX    int n, i, pid, wpid;
XX  
XX    /* Test exit status codes for processes killed by signals. */
XX+   subtest = 3;
XX    for (i = 0; i < 2; i++) {
XX  	if (pid = fork()) {
XX  		if (pid < 0) ex();
XX! 		sleep(2);	/* wait for child to pause */
XX  		if (kill(pid, sigmap[i]) < 0) {
XX  			e(20);
XX  			exit(1);
XX***************
XX*** 171,185 ****
XX    }
XX  }
XX  
XX! test54()
XX  {
XX  /* Test alarm */
XX  
XX    int i;
XX  
XX    alarms = 0;
XX    for (i = 0; i < 8; i++) {
XX! 	signal(SIGALRM, funcalrm);
XX  	alarm(1);
XX  	pause();
XX  	if (alarms != i + 1) e(24);
XX--- 208,223 ----
XX    }
XX  }
XX  
XX! void test5d()
XX  {
XX  /* Test alarm */
XX  
XX    int i;
XX  
XX+   subtest = 4;
XX    alarms = 0;
XX    for (i = 0; i < 8; i++) {
XX! 	Signal(SIGALRM, funcalrm);
XX  	alarm(1);
XX  	pause();
XX  	if (alarms != i + 1) e(24);
XX***************
XX*** 188,208 ****
XX  
XX  
XX  
XX! test55()
XX  {
XX  /* When a signal knocks a processes out of WAIT or PAUSE, it is supposed to
XX   * get EINTR as error status.  Check that.
XX   */
XX!   int n, j, i;
XX  
XX!   if (signal(8, func8) < 0) e(25);
XX    if (n = fork()) {
XX  	/* Parent must delay to give child a chance to pause. */
XX  	if (n < 0) ex();
XX  	sleep(1);
XX  	if (kill(n, 8) < 0) e(26);
XX  	if (wait(&n) < 0) e(27);
XX! 	if (signal(8, SIG_DFL) < 0) e(28);
XX    } else {
XX  	j = pause();
XX  	if (errno != EINTR && -errno != EINTR) e(29);
XX--- 226,247 ----
XX  
XX  
XX  
XX! void test5e()
XX  {
XX  /* When a signal knocks a processes out of WAIT or PAUSE, it is supposed to
XX   * get EINTR as error status.  Check that.
XX   */
XX!   int n, j;
XX  
XX!   subtest = 5;
XX!   if (Signal(8, func8) < SIG_ZERO) e(25);
XX    if (n = fork()) {
XX  	/* Parent must delay to give child a chance to pause. */
XX  	if (n < 0) ex();
XX  	sleep(1);
XX  	if (kill(n, 8) < 0) e(26);
XX  	if (wait(&n) < 0) e(27);
XX! 	if (Signal(8, SIG_DFL) < SIG_ZERO) e(28);
XX    } else {
XX  	j = pause();
XX  	if (errno != EINTR && -errno != EINTR) e(29);
XX***************
XX*** 210,223 ****
XX    }
XX  }
XX  
XX- func8()
XX- {
XX- }
XX  
XX! test56()
XX  {
XX    int i, j, k, n;
XX  
XX    if (getuid() != 0) return;
XX    n = fork();
XX    if (n < 0) ex();
XX--- 249,260 ----
XX    }
XX  }
XX  
XX  
XX! void test5f()
XX  {
XX    int i, j, k, n;
XX  
XX+   subtest = 6;
XX    if (getuid() != 0) return;
XX    n = fork();
XX    if (n < 0) ex();
XX***************
XX*** 244,305 ****
XX    }
XX  }
XX  
XX- func11()
XX- {
XX-   e(38);
XX- }
XX  
XX! 
XX! test57()
XX  {
XX    int n;
XX  
XX!   signal(11, func11);
XX!   signal(11, SIG_IGN);
XX    n = getpid();
XX!   kill(n, 11);
XX!   signal(11, SIG_DFL);
XX  }
XX  
XX! funcalrm()
XX  {
XX    alarms++;
XX  }
XX  
XX  
XX! test58()
XX  {
XX  /* When a signal knocks a processes out of PIPE, it is supposed to
XX   * get EINTR as error status.  Check that.
XX   */
XX!   int n, j, i, fd[2];
XX  
XX!   if (signal(8, func8) < 0) e(38);
XX    pipe(fd);
XX    if (n = fork()) {
XX  	/* Parent must delay to give child a chance to pause. */
XX  	if (n < 0) ex();
XX! 	sleep(3);
XX! 	if (kill(n, 8) < 0) e(39);
XX! 	if (wait(&n) < 0) e(40);
XX! 	if (signal(8, SIG_DFL) < 0) e(41);
XX! 	close(fd[0]);
XX! 	close(fd[1]);
XX    } else {
XX! 	j = read(fd[0], &n, 1);
XX! 	if (errno != EINTR) e(42);
XX  	exit(0);
XX    }
XX  }
XX  
XX! ex()
XX  {
XX    printf("Test 5.  fork failed.  Errno=%d\n", errno);
XX    exit(1);
XX  }
XX  
XX  
XX! e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX--- 281,370 ----
XX    }
XX  }
XX  
XX  
XX! void test5g()
XX  {
XX    int n;
XX  
XX!   subtest = 7;
XX!   Signal(11, func11);
XX!   Signal(11, SIG_IGN);
XX    n = getpid();
XX!   if (kill(n, 11) != 0) e(1);
XX!   Signal(11, SIG_DFL);
XX  }
XX  
XX! void funcalrm(s)
XX! int s;				/* for ANSI */
XX  {
XX    alarms++;
XX  }
XX  
XX  
XX! void test5h()
XX  {
XX  /* When a signal knocks a processes out of PIPE, it is supposed to
XX   * get EINTR as error status.  Check that.
XX   */
XX!   int n, j, fd[2];
XX  
XX!   subtest = 8;
XX!   unlink("XXX.test5");
XX!   if (Signal(8, func8) < SIG_ZERO) e(1);
XX    pipe(fd);
XX    if (n = fork()) {
XX  	/* Parent must delay to give child a chance to pause. */
XX  	if (n < 0) ex();
XX! 	while (access("XXX.test5", 0) != 0) /* just wait */ ;
XX! 	sleep(1);
XX!  	unlink("XXX.test5");
XX! 	if (kill(n, 8) < 0) e(2);
XX! 	if (wait(&n) < 0) e(3);
XX! 	if (Signal(8, SIG_DFL) < SIG_ZERO) e(4);
XX! 	if (close(fd[0]) != 0) e(5);
XX! 	if (close(fd[1]) != 0) e(6);
XX    } else {
XX! 	if (creat("XXX.test5", 0777) < 0) e(7);
XX! 	j = read(fd[0], (char *) &n, 1);
XX! 	if (errno != EINTR) e(8);
XX  	exit(0);
XX    }
XX  }
XX  
XX! void test5i()
XX  {
XX+   int fd[2], pid, buf[10], n;
XX+ 
XX+   subtest = 9;
XX+   pipe(fd);
XX+   unlink("XXXxxxXXX");
XX+ 
XX+   if ( (pid = fork())) {
XX+ 	/* Parent */
XX+ 	/* Wait until child has started and has created the XXXxxxXXX file. */
XX+ 	while (access("XXXxxxXXX", 0) != 0) /* loop */ ;
XX+ 	sleep(1);
XX+ 	if (kill(pid, SIGKILL) != 0) e(1);
XX+ 	if (wait(&n) < 0) e(2);
XX+ 	if (close(fd[0]) != 0) e(3);
XX+ 	if (close(fd[1]) != 0) e(4);
XX+   } else {
XX+ 	if (creat("XXXxxxXXX", 0777) < 0) e(5);
XX+ 	read(fd[0], (char *) buf, 1);
XX+ 	e(5);		/* should be killed by signal and not get here */
XX+   }
XX+   unlink("XXXxxxXXX");
XX+ }
XX+ 
XX+ 
XX+ void ex()
XX+ {
XX    printf("Test 5.  fork failed.  Errno=%d\n", errno);
XX    exit(1);
XX  }
XX  
XX  
XX! void e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX***************
XX*** 309,314 ****
XX--- 374,411 ----
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX+ 	exit(1);
XX+   }
XX+ }
XX+ 
XX+ #ifdef _ANSI
XX+ void (*Signal(int a, void (*b)(int)))(int)
XX+ #else
XX+ sighandler_t Signal(a, b)
XX+ int a;
XX+ void (*b)();
XX+ #endif
XX+ {
XX+   if (signal(a, (void (*) ()) b) == (void (*)()) -1)
XX+ 	return(SIG_ERR);
XX+   else
XX+ 	return(SIG_ZERO);
XX+ }
XX+ 
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX  	exit(1);
XX    }
XX  }
X/
Xecho x - test6.c.d
Xsed '/^X/s///' > test6.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test6.c  crc=23504   1554	Sat Apr 21 22:26:26 1990
XX--- /home/top/ast/minix/1.6.25/test/test6.c  crc=55588   4437	Fri Mar 19 21:25:20 1993
XX***************
XX*** 1,37 ****
XX  /* test 6 */
XX  
XX  #define MAX_ERROR 4
XX  
XX- extern char *brk(), *sbrk();
XX- extern int errno;
XX- 
XX  int errct;
XX  int subtest = 1;
XX  
XX! main()
XX  {
XX!   int i;
XX  
XX    printf("Test  6 ");
XX    for (i = 0; i < 70; i++) {
XX! 	test60();
XX    }
XX!   if (errct == 0)
XX! 	printf("ok\n");
XX!   else
XX! 	printf(" %d errors\n", errct);
XX!   exit(0);
XX  }
XX  
XX  
XX  
XX! test60()
XX  {
XX  /* Test sbrk() and brk(). */
XX  
XX    char *addr, *addr2, *addr3;
XX    int i, del, click, click2;
XX  
XX    addr = sbrk(0);
XX    addr = sbrk(0);		/* force break to a click boundary */
XX    for (i = 0; i < 10; i++) sbrk(7 * i);
XX--- 1,70 ----
XX  /* test 6 */
XX  
XX+ #include <sys/types.h>
XX+ #include <sys/stat.h>
XX+ #include <errno.h>
XX+ #include <fcntl.h>
XX+ #include <limits.h>
XX+ #include <signal.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX+ #include <stdio.h>
XX+ 
XX  #define MAX_ERROR 4
XX  
XX  int errct;
XX  int subtest = 1;
XX+ int zilch[5000];
XX+ char curdir[PATH_MAX];
XX  
XX! _PROTOTYPE(int main, (int argc, char *argv []));
XX! _PROTOTYPE(void test6a, (void));
XX! _PROTOTYPE(void test6b, (void));
XX! _PROTOTYPE(void test6c, (void));
XX! _PROTOTYPE(void e, (int n));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   int i, m = 0xFFFF;
XX  
XX+   sync();
XX+   if (geteuid() == 0 || getuid() == 0) {
XX+ 	printf("Test  6 cannot run as root; test aborted\n");
XX+ 	exit(1);
XX+   }
XX+ 
XX+   if (argc == 2) m = atoi(argv[1]);
XX+ 
XX    printf("Test  6 ");
XX+   fflush(stdout);
XX+ 
XX+   getcwd(curdir, PATH_MAX);
XX+   system("rm -rf DIR_06; mkdir DIR_06");
XX+   chdir("DIR_06");
XX+ 
XX    for (i = 0; i < 70; i++) {
XX! 	if (m & 00001) test6a();
XX! 	if (m & 00002) test6b();
XX! 	if (m & 00004) test6c();
XX    }
XX! 
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX  
XX  
XX! void test6a()
XX  {
XX  /* Test sbrk() and brk(). */
XX  
XX    char *addr, *addr2, *addr3;
XX    int i, del, click, click2;
XX  
XX+   subtest = 1;
XX    addr = sbrk(0);
XX    addr = sbrk(0);		/* force break to a click boundary */
XX    for (i = 0; i < 10; i++) sbrk(7 * i);
XX***************
XX*** 75,83 ****
XX  }
XX  
XX  
XX! e(n)
XX  int n;
XX  {
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX  
XX    printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX--- 108,192 ----
XX  }
XX  
XX  
XX! void test6b()
XX! {
XX!   int i, err;
XX! 
XX!   subtest = 2;
XX!   signal(SIGQUIT, SIG_IGN);
XX!   err = 0;
XX!   for (i = 0; i < 5000; i++)
XX! 	if (zilch[i] != 0) err++;
XX!   if (err > 0) e(1);
XX!   kill(getpid(), SIGQUIT);
XX! }
XX! 
XX! 
XX! 
XX! void test6c()
XX! {
XX! /* Test mknod, chdir, chmod, chown, access.  */
XX! 
XX!   int i, j;
XX!   struct stat s;
XX! 
XX!   subtest = 3;
XX!   if (getuid() != 0) return;
XX!   for (j = 0; j < 2; j++) {
XX! 	umask(0);
XX! 
XX! 	if (chdir("/") < 0) e(1);
XX! 	if (mknod("dir", 040700, 0) < 0) e(2);
XX! 	if (link("/", "/dir/..") < 0) e(3);
XX! 	if (mknod("T3a", 0777, 0) < 0) e(4);
XX! 	if (mknod("/dir/T3b", 0777, 0) < 0) e(5);
XX! 	if (mknod("dir/T3c", 0777, 0) < 0) e(6);
XX! 	if ((i = open("/dir/T3b", 0)) < 0) e(7);
XX! 	if (close(i) < 0) e(8);
XX! 	if ((i = open("dir/T3c", O_RDONLY)) < 0) e(9);
XX! 	if (close(i) < 0) e(10);
XX! 	if (chdir("dir") < 0) e(11);
XX! 	if ((i = open("T3b", 0)) < 0) e(12);
XX! 	if (close(i) < 0) e(13);
XX! 	if ((i = open("../T3a", O_RDONLY)) < 0) e(14);
XX! 	if (close(i) < 0) e(15);
XX! 	if ((i = open("../dir/../dir/../dir/../dir/../dir/T3c", O_RDONLY)) < 0)
XX! 		e(16);
XX! 	if (close(i) < 0) e(17);
XX! 
XX! 	if (chmod("../dir/../dir/../dir/../dir/../T3a", 0123) < 0) e(18);
XX! 	if (stat("../dir/../dir/../dir/../T3a", &s) < 0) e(19);
XX! 	if ((s.st_mode & 077777) != 0123) e(20);
XX! 	if (chmod("../dir/../dir/../T3a", 0456) < 0) e(21);
XX! 	if (stat("../T3a", &s) < 0) e(22);
XX! 	if ((s.st_mode & 077777) != 0456) e(23);
XX! 	if (chown("../dir/../dir/../T3a", 20, 30) < 0) e(24);
XX! 	if (stat("../T3a", &s) < 0) e(25);
XX! 	if (s.st_uid != 20) e(26);
XX! 	if (s.st_gid != 30) e(27);
XX! 
XX! 	if ((i = open("/T3c", O_RDONLY)) >= 0) e(28);
XX! 	if ((i = open("/T3a", O_RDONLY)) < 0) e(29);
XX! 	if (close(i) < 0) e(30);
XX! 
XX! 	if (access("/T3a", 4) < 0) e(31);
XX! 	if (access("/dir/T3b", 4) < 0) e(32);
XX! 	if (access("/dir/T3d", 4) >= 0) e(33);
XX! 
XX! 	if (unlink("T3b") < 0) e(34);
XX! 	if (unlink("T3c") < 0) e(35);
XX! 	if (unlink("..") < 0) e(36);
XX! 	if (chdir("/") < 0) e(37);
XX! 	if (unlink("dir") < 0) e(38);
XX! 	if (unlink("/T3a") < 0) e(39);
XX!   }
XX! 
XX! }
XX! 
XX! void e(n)
XX  int n;
XX  {
XX+ 
XX    int err_num = errno;		/* save errno in case printf clobbers it */
XX  
XX    printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX***************
XX*** 85,90 ****
XX--- 194,218 ----
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX+ 	exit(1);
XX+   }
XX+ }
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   chdir(curdir);
XX+   system("rm -rf DIR*");
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX  	exit(1);
XX    }
XX  }
X/
Xecho x - test7.c.d
Xsed '/^X/s///' > test7.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test7.c  crc=40777    642	Sat Apr 21 22:26:26 1990
XX--- /home/top/ast/minix/1.6.25/test/test7.c  crc=23453  18427	Sat Dec 19 19:50:07 1992
XX***************
XX*** 1,51 ****
XX! /* test 7 */
XX  
XX  #include <signal.h>
XX  #define MAX_ERROR 4
XX  
XX! extern int errno;
XX! int subtest;
XX! int errct;
XX  
XX! int zilch[5000];
XX  
XX! main()
XX  {
XX-   int i;
XX  
XX    printf("Test  7 ");
XX!   for (i = 0; i < 150; i++) {
XX! 	test70();
XX    }
XX!   if (errct == 0)
XX! 	printf("ok\n");
XX!   else
XX! 	printf("%d errors\n", errct);
XX  }
XX  
XX  
XX  
XX! test70()
XX  {
XX!   int i, err, pid;
XX  
XX!   signal(SIGQUIT, SIG_IGN);
XX!   err = 0;
XX!   for (i = 0; i < 5000; i++)
XX! 	if (zilch[i] != 0) err++;
XX!   if (err > 0) e(1);
XX!   kill(getpid(), SIGQUIT);
XX  }
XX  
XX  
XX  
XX! e(n)
XX  int n;
XX  {
XX    printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX  	exit(1);
XX    }
XX  }
XX--- 1,679 ----
XX! /* POSIX test program (7).			Author: Andy Tanenbaum */
XX  
XX+ /* The following POSIX calls are tested:
XX+  *
XX+  *	pipe(), mkfifo(), fcntl()
XX+  */
XX+ 
XX+ 
XX+ #include <sys/types.h>
XX+ #include <sys/stat.h>
XX+ #include <sys/wait.h>
XX+ #include <errno.h>
XX+ #include <fcntl.h>
XX+ #include <limits.h>
XX  #include <signal.h>
XX+ #include <stdlib.h>
XX+ #include <string.h>
XX+ #include <unistd.h>
XX+ #include <stdio.h>
XX+ 
XX+ #define ITERATIONS        4
XX  #define MAX_ERROR 4
XX+ #define ITEMS  32
XX+ #define READ   10
XX+ #define WRITE  20
XX+ #define UNLOCK 30
XX+ #define U      70
XX+ #define L      80
XX  
XX! char buf[ITEMS] = {0,1,2,3,4,5,6,7,8,9,8,7,6,5,4,3,2,1,0,1,2,3,4,5,6,7,8,9};
XX  
XX! int subtest, errct, xfd;
XX! int whence = SEEK_SET, func_code = F_SETLK;
XX! extern char *environ;
XX  
XX! _PROTOTYPE(int main, (int argc, char *argv []));
XX! _PROTOTYPE(void test7a, (void));
XX! _PROTOTYPE(void test7b, (void));
XX! _PROTOTYPE(void test7c, (void));
XX! _PROTOTYPE(void test7d, (void));
XX! _PROTOTYPE(void test7e, (void));
XX! _PROTOTYPE(void test7f, (void));
XX! _PROTOTYPE(void test7g, (void));
XX! _PROTOTYPE(void test7h, (void));
XX! _PROTOTYPE(void test7i, (void));
XX! _PROTOTYPE(void test7j, (void));
XX! _PROTOTYPE(void cloexec_test, (void));
XX! _PROTOTYPE(int set, (int how, int first, int last));
XX! _PROTOTYPE(int locked, (int b));
XX! _PROTOTYPE(void e, (int n));
XX! _PROTOTYPE(void sigfunc, (int s));
XX! _PROTOTYPE(void quit, (void));
XX! 
XX! 
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX  
XX+   int i, m = 0xFFFF;
XX+ 
XX+   sync();
XX+ 
XX+   if (argc == 2) m = atoi(argv[1]);
XX+   if (m == 0) cloexec_test();	/* important; do not remove this! */
XX    printf("Test  7 ");
XX!   fflush(stdout);
XX! 
XX!   system("rm -rf DIR_07; mkdir DIR_07");
XX!   chdir("DIR_07");
XX! 
XX!   for (i = 0; i < ITERATIONS; i++) {
XX! 	if (m & 00001) test7a();
XX! 	if (m & 00002) test7b();
XX! 	if (m & 00004) test7c();
XX! 	if (m & 00010) test7d();
XX! 	if (m & 00020) test7e();
XX! 	if (m & 00040) test7f();
XX! 	if (m & 00100) test7g();
XX! 	if (m & 00200) test7h();
XX! 	if (m & 00400) test7i();
XX! 	if (m & 01000) test7j();
XX    }
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX+ void test7a()
XX+ {
XX+ /* Test pipe(). */
XX  
XX+   int i, fd[2], ect;
XX+   char buf2[ITEMS+1];
XX  
XX!   /* Create a pipe, write on it, and read it back. */
XX!   subtest = 1;
XX!   if (pipe(fd) != 0) e(1);
XX!   if (write(fd[1], buf, ITEMS) != ITEMS) e(2);
XX!   buf2[0] = 0;
XX!   if (read(fd[0], buf2, ITEMS+1) != ITEMS) e(3);
XX!   ect = 0;
XX!   for (i = 0; i < ITEMS; i++) if (buf[i] != buf2[i]) ect++;
XX!   if (ect != 0) e(4);
XX!   if (close(fd[0]) != 0) e(5);
XX!   if (close(fd[1]) != 0) e(6);
XX! 
XX!   /* Error test.  Keep opening pipes until it fails.  Check error code. */
XX!   errno = 0;
XX!   while (1) {
XX! 	if (pipe(fd) < 0) break;
XX!   }
XX!   if (errno != EMFILE) e(7);
XX! 
XX!   /* Close all the pipes. */
XX!   for (i = 3; i < OPEN_MAX; i++) close(i);
XX! }
XX! 
XX! 
XX! void test7b()
XX  {
XX! /* Test mkfifo(). */
XX  
XX!   int fdr, fdw, status;
XX!   char buf2[ITEMS+1];
XX! 
XX!   /* Create a fifo, write on it, and read it back. */
XX!   subtest = 2;
XX!   if (mkfifo("T7.b", 0777) != 0) e(1);
XX!   if (fork()) {
XX! 	/* Parent writes on the fifo. */
XX! 	if ( (fdw = open("T7.b", O_WRONLY)) < 0) e(2);
XX! 	if (write(fdw, buf, ITEMS) != ITEMS) e(3);
XX! 	wait(&status);
XX! 	if (close(fdw) != 0) e(4);
XX!   } else {
XX! 	/* Child reads from the fifo. */
XX! 	if ( (fdr = open("T7.b", O_RDONLY)) < 0) e(5);
XX! 	if (read(fdr, buf2, ITEMS+1) != ITEMS) e(6);
XX! 	if (strcmp(buf, buf2) != 0) e(7);
XX! 	if (close(fdr) != 0) e(8);
XX! 	exit(0);
XX!   }
XX! 
XX!   /* Check some error conditions. */
XX!   if (mkfifo("T7.b", 0777) != -1) e(9);
XX!   errno = 0;
XX!   if (mkfifo("a/b/c", 0777) != -1) e(10);
XX!   if (errno != ENOENT) e(11);
XX!   errno = 0;
XX!   if (mkfifo("", 0777) != -1) e(12);
XX!   if (errno != ENOENT) e(13);
XX!   errno = 0;
XX!   if (mkfifo("T7.b/x", 0777) != -1) e(14);
XX!   if (errno != ENOTDIR) e(15);
XX!   if (unlink("T7.b") != 0) e(16);
XX! 
XX!   /* Now check fifos and the O_NONBLOCK flag. */
XX!   if (mkfifo("T7.b", 0600) != 0) e(17);
XX!   errno = 0;
XX!   if (open("T7.b", O_WRONLY | O_NONBLOCK) != -1) e(18);
XX!   if (errno != ENXIO) e(19);
XX!   if ( (fdr = open("T7.b", O_RDONLY | O_NONBLOCK)) < 0) e(20);
XX!   if (fork()) {
XX! 	/* Parent reads from fdr. */
XX! 	wait(&status);		/* but first make sure writer has already run*/
XX! 	if ( ( (status>>8) & 0377) != 77) e(21);
XX! 	if (read(fdr, buf2, ITEMS+1) != ITEMS) e(22);
XX! 	if (strcmp(buf, buf2) != 0) e(23);
XX! 	if (close(fdr) != 0) e(24);
XX!   } else {
XX! 	/* Child opens the fifo for writing and writes to it. */
XX! 	if ( (fdw = open("T7.b", O_WRONLY | O_NONBLOCK)) < 0) e(25);
XX! 	if (write(fdw, buf, ITEMS) != ITEMS) e(26);
XX! 	if (close(fdw) != 0) e(27);
XX! 	exit(77);
XX!   }
XX!   
XX!   if (unlink("T7.b") != 0) e(28);
XX  }
XX  
XX  
XX+ void test7c()
XX+ {
XX+ /* Test fcntl(). */
XX  
XX!   int fd, m, s, newfd, newfd2;
XX!   struct stat stat1, stat2, stat3;
XX! 
XX!   subtest = 3;
XX!   errno = -100;
XX!   if ( (fd = creat("T7.c", 0777)) < 0) e(1);
XX! 
XX!   /* Turn the per-file-descriptor flags on and off. */
XX!   if (fcntl(fd, F_GETFD) != 0) e(2);	/* FD_CLOEXEC is initially off */
XX!   if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) e(3);/* turn it on */
XX!   if (fcntl(fd, F_GETFD) != FD_CLOEXEC) e(4);	/* should be on now */
XX!   if (fcntl(fd, F_SETFD, 0) != 0) e(5);		/* turn it off */
XX!   if (fcntl(fd, F_GETFD) != 0) e(6);		/* should be off now */
XX! 
XX!   /* Turn the open-file-description flags on and off. Start with O_APPEND. */
XX!   m = O_WRONLY;
XX!   if (fcntl(fd, F_GETFL) != m) e(7);	/* O_APPEND, O_NONBLOCK are off */
XX!   if (fcntl(fd, F_SETFL, O_APPEND) != 0) e(8);	 /* turn on O_APPEND */
XX!   if (fcntl(fd, F_GETFL) != (O_APPEND | m)) e(9);/* should be on now */
XX!   if (fcntl(fd, F_SETFL, 0) != 0) e(10);	 /* turn it off */
XX!   if (fcntl(fd, F_GETFL) != m) e(11);		 /* should be off now */
XX!   
XX!   /* Turn the open-file-description flags on and off. Now try O_NONBLOCK.  */
XX!   if (fcntl(fd, F_SETFL, O_NONBLOCK) != 0) e(12);      /* turn on O_NONBLOCK */
XX!   if (fcntl(fd, F_GETFL) != (O_NONBLOCK | m)) e(13);   /* should be on now */
XX!   if (fcntl(fd, F_SETFL, 0) != 0) e(14);	       /* turn it off */
XX!   if (fcntl(fd, F_GETFL) != m) e(15);		       /* should be off now */
XX!   
XX!   /* Now both at once. */
XX!   if (fcntl(fd, F_SETFL, O_APPEND|O_NONBLOCK) != 0) e(16);
XX!   if (fcntl(fd, F_GETFL) != (O_NONBLOCK | O_APPEND | m)) e(17);
XX!   if (fcntl(fd, F_SETFL, 0) != 0) e(18);
XX!   if (fcntl(fd, F_GETFL) != m) e(19);
XX! 
XX!   /* Now test F_DUPFD. */
XX!   if ( (newfd = fcntl(fd, F_DUPFD, 0)) != 4) e(20);	/* 0-4 open */
XX!   if ( (newfd2 = fcntl(fd, F_DUPFD, 0)) != 5) e(21);	/* 0-5 open */
XX!   if (close(newfd) != 0) e(22);				/* 0-3, 5 open */
XX!   if ( (newfd = fcntl(fd, F_DUPFD, 0)) != 4) e(23);	/* 0-5 open */
XX!   if (close(newfd) != 0) e(24);				/* 0-3, 5 open */
XX!   if ( (newfd = fcntl(fd, F_DUPFD, 5)) != 6) e(25);	/* 0-3, 5, 6 open */
XX!   if (close(newfd2) != 0) e(26);			/* 0-3, 6 open */
XX!   
XX!   /* O_APPEND should be inherited, but FD_CLOEXEC should be cleared.  Check. */
XX!   if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) e(26);/* turn FD_CLOEXEC on */
XX!   if (fcntl(fd, F_SETFL, O_APPEND) != 0) e(27);	 /* turn O_APPEND on */
XX!   if ( (newfd2 = fcntl(fd, F_DUPFD, 10)) != 10) e(28);	/* 0-3, 6, 10 open */
XX!   if (fcntl(newfd2, F_GETFD) != 0) e(29);	/* FD_CLOEXEC must be 0 */
XX!   if (fcntl(newfd2, F_GETFL) != (O_APPEND | m)) e(30);	/* O_APPEND set */
XX!   if (fcntl(fd, F_SETFD, 0) != 0) e(31);/* turn FD_CLOEXEC off */
XX! 
XX!   /* Check if newfd and newfd2 are the same inode. */
XX!   if (fstat(fd, &stat1) != 0) e(32);
XX!   if (fstat(fd, &stat2) != 0) e(33);
XX!   if (fstat(fd, &stat3) != 0) e(34);
XX!   if (stat1.st_dev != stat2.st_dev) e(35);
XX!   if (stat1.st_dev != stat3.st_dev) e(36);
XX!   if (stat1.st_ino != stat2.st_ino) e(37);
XX!   if (stat1.st_ino != stat3.st_ino) e(38);
XX! 
XX!   /* Now check on the FD_CLOEXEC flag.  Set it for fd (3) and newfd2 (10) */
XX!   if (fd != 3 || newfd2 != 10 || newfd != 6) e(39);
XX!   if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) e(40);	/* close 3 on exec */
XX!   if (fcntl(newfd2, F_SETFD, FD_CLOEXEC) != 0) e(41);	/* close 10 on exec */
XX!   if (fcntl(newfd, F_SETFD, 0) != 0) e(42);		/* don't close 6 */
XX!   if (fork()) {
XX! 	wait(&s);		/* parent just waits */
XX! 	if (WEXITSTATUS(s) != 0) e(43);
XX!   } else {
XX! 	execle("../test7", "test7", "0", (char *) 0, environ);
XX! 	exit(1);		/* the impossible never happens, right? */
XX!   }
XX!   
XX!   /* Finally, close all the files. */
XX!   if (fcntl(fd, F_SETFD, 0) != 0) e(44);	/* FD_CLOEXEC off */
XX!   if (fcntl(newfd2, F_SETFD, 0) != 0) e(45);	/* FD_CLOEXEC off */
XX!   if (close(fd) != 0) e(46);
XX!   if (close(newfd) != 0) e(47);
XX!   if (close(newfd2) != 0) e(48);
XX! }
XX! 
XX! 
XX! void test7d()
XX! {
XX! /* Test file locking. */
XX! 
XX!   subtest = 4;
XX!  
XX!   if ( (xfd = creat("T7.d", 0777)) != 3) e(1);
XX!   close(xfd);
XX!   if ( (xfd = open("T7.d", O_RDWR)) < 0) e(2);
XX!   if (write(xfd, buf, ITEMS) != ITEMS) e(3);
XX!   if (set(WRITE, 0, 3) != 0) e(4);
XX!   if (set(WRITE, 5, 9) != 0) e(5);
XX!   if (set(UNLOCK, 0, 3) != 0) e(6);
XX!   if (set(UNLOCK, 4, 9) != 0) e(7);
XX! 
XX!   if (set(READ, 1, 4) != 0) e(8);
XX!   if (set(READ, 4, 7) != 0) e(9);
XX!   if (set(UNLOCK, 4, 7) != 0) e(10);
XX!   if (set(UNLOCK, 1, 4) != 0) e(11);
XX! 
XX!   if (set(WRITE, 0, 3) != 0) e(12);
XX!   if (set(WRITE, 5, 7) != 0) e(13);
XX!   if (set(WRITE, 9 ,10) != 0) e(14);
XX!   if (set(UNLOCK, 0, 4) != 0) e(15);
XX!   if (set(UNLOCK, 0, 7) != 0) e(16);
XX!   if (set(UNLOCK, 0, 2000) != 0) e(17);
XX! 
XX!   if (set(WRITE, 0, 3) != 0) e(18);
XX!   if (set(WRITE, 5, 7) != 0) e(19);
XX!   if (set(WRITE, 9 ,10) != 0) e(20);
XX!   if (set(UNLOCK, 0, 100) != 0) e(21);
XX! 
XX!   if (set(WRITE, 0, 9) != 0) e(22);
XX!   if (set(UNLOCK, 8, 9) != 0) e(23);
XX!   if (set(UNLOCK, 0, 2) != 0) e(24);
XX!   if (set(UNLOCK, 5, 5) != 0) e(25);
XX!   if (set(UNLOCK, 4, 6) != 0) e(26);
XX!   if (set(UNLOCK, 3, 3) != 0) e(27);
XX!   if (set(UNLOCK, 7, 7) != 0) e(28);
XX! 
XX!   if (set(WRITE, 0, 10) != 0) e(29);
XX!   if (set(UNLOCK, 0, 1000) != 0) e(30);
XX! 
XX!   /* Up until now, all locks have been disjoint.  Now try conflicts. */
XX!   if (set(WRITE, 0, 4) != 0) e(31);
XX!   if (set(WRITE, 4, 7) != 0) e(32);	/* owner may lock same byte twice */
XX!   if (set(WRITE, 5, 10) != 0) e(33);
XX!   if (set(UNLOCK, 0, 11) != 0) e(34);
XX! 
XX!   /* File is now unlocked. Length 0 means whole file. */
XX!   if (set(WRITE, 2, 1) != 0) e(35);	/* this locks whole file */
XX!   if (set(WRITE, 9,10) != 0) e(36);	/* a process can relock its file */
XX!   if (set(WRITE, 3, 3) != 0) e(37);
XX!   if (set(UNLOCK, 0, -1) != 0) e(38);	/* file is now unlocked. */
XX! 
XX!   /* Test F_GETLK. */
XX!   if (set(WRITE, 2, 3) != 0) e(39);
XX!   if (locked(1) != U) e(40);
XX!   if (locked(2) != L) e(41);
XX!   if (locked(3) != L) e(42);
XX!   if (locked(4) != U) e(43);
XX!   if (set(UNLOCK, 2, 3) != 0) e(44);
XX!   if (locked(2) != U) e(45);
XX!   if (locked(3) != U) e(46);
XX! 
XX!   close(xfd);
XX! }
XX! 
XX! void test7e()
XX! {
XX! /* Test to see if SETLKW blocks as it should. */
XX! 
XX!   int pid, s;
XX! 
XX!   subtest = 5;
XX!  
XX!   if ( (xfd = creat("T7.e", 0777)) != 3) e(1);
XX!   if (close(xfd) != 0) e(2);
XX!   if ( (xfd = open("T7.e", O_RDWR)) < 0) e(3);
XX!   if (write(xfd, buf, ITEMS) != ITEMS) e(4);
XX!   if (set(WRITE, 0, 3) != 0) e(5);
XX! 
XX!   if ( (pid = fork()) ) {
XX! 	/* Parent waits until child has started before signaling it. */
XX! 	while (access("T7.e1", 0) != 0) ;
XX! 	unlink("T7.e1");
XX! 	sleep(1);
XX! 	if (kill(pid, SIGKILL) < 0) e(6);
XX! 	if (wait(&s) != pid) e(7);
XX!   } else {
XX! 	/* Child tries to lock and should block. */
XX! 	if (creat("T7.e1", 0777) < 0) e(8);
XX! 	func_code = F_SETLKW;
XX! 	if (set(WRITE, 0, 3) != 0) e(9);	/* should block */
XX! 	errno = -1000;
XX! 	e(10);			/* process should be killed by signal */
XX! 	exit(0);		/* should never happen */
XX!   }
XX!   close(xfd);
XX! }
XX! 
XX! void test7f()
XX! {
XX! /* Test to see if SETLKW gives EINTR when interrupted. */
XX! 
XX!   int pid, s;
XX! 
XX!   subtest = 6;
XX!  
XX!   if ( (xfd = creat("T7.f", 0777)) != 3) e(1);
XX!   if (close(xfd) != 0) e(2);
XX!   if ( (xfd = open("T7.f", O_RDWR)) < 0) e(3);
XX!   if (write(xfd, buf, ITEMS) != ITEMS) e(4);
XX!   if (set(WRITE, 0, 3) != 0) e(5);
XX! 
XX!   if ( (pid = fork()) ) {
XX! 	/* Parent waits until child has started before signaling it. */
XX! 	while (access("T7.f1", 0) != 0) ;
XX! 	unlink("T7.f1");
XX! 	sleep(1);
XX! 	if (kill(pid, SIGTERM) < 0) e(6);
XX! 	if (wait(&s) != pid) e(7);
XX! 	if ( (s>>8) != 19) e(8);
XX!   } else {
XX! 	/* Child tries to lock and should block. */
XX! 	signal(SIGTERM, sigfunc);
XX! 	if (creat("T7.f1", 0777) < 0) e(9);
XX! 	func_code = F_SETLKW;
XX! 	if (set(WRITE, 0, 3) != -1) e(10);	/* should block */
XX! 	if (errno != EINTR) e(11);	/* signal should release it */
XX! 	exit(19);
XX!   }
XX!   close(xfd);
XX! }
XX! 
XX! 
XX! void test7g()
XX! {
XX! /* Test to see if SETLKW unlocks when the needed lock becomes available. */
XX! 
XX!   int pid, s;
XX! 
XX!   subtest = 7;
XX!  
XX!   if ( (xfd = creat("T7.g", 0777)) != 3) e(1);
XX!   if (close(xfd) != 0) e(2);
XX!   if ( (xfd = open("T7.g", O_RDWR)) < 0) e(3);
XX!   if (write(xfd, buf, ITEMS) != ITEMS) e(4);
XX!   if (set(WRITE, 0, 3) != 0) e(5);	/* bytes 0 to 3 are now locked */
XX! 
XX!   if ( (pid = fork()) ) {
XX! 	/* Parent waits for child to start. */
XX! 	while (access("T7.g1", 0) != 0) ;
XX! 	unlink("T7.g1");
XX! 	sleep(1);
XX! 	if (set(UNLOCK, 0, 3) != 0) e(5);
XX! 	if (wait(&s) != pid) e(6);
XX! 	if ( (s >> 8) != 29) e(7);
XX!   } else {
XX! 	/* Child tells parent it is alive, then tries to lock and is blocked.*/
XX! 	func_code = F_SETLKW;	
XX! 	if (creat("T7.g1", 0777) < 0) e(8);
XX! 	if (set(WRITE, 3, 3) != 0) e(9);	/* process must block now */
XX! 	if (set(UNLOCK, 3, 3) != 0) e(10);
XX! 	exit(29);
XX!   }
XX!   close(xfd);
XX! }
XX! 
XX! 
XX! void test7h()
XX! {
XX! /* Test to see what happens if two processed block on the same lock. */
XX! 
XX!   int pid, pid2, s, w;
XX! 
XX!   subtest = 8;
XX!  
XX!   if ( (xfd = creat("T7.h", 0777)) != 3) e(1);
XX!   if (close(xfd) != 0) e(2);
XX!   if ( (xfd = open("T7.h", O_RDWR)) < 0) e(3);
XX!   if (write(xfd, buf, ITEMS) != ITEMS) e(4);
XX!   if (set(WRITE, 0, 3) != 0) e(5);	/* bytes 0 to 3 are now locked */
XX! 
XX!   if ( (pid = fork()) ) {
XX! 	if ( (pid2 = fork()) ) {
XX! 		/* Parent waits for child to start. */
XX! 		while (access("T7.h1", 0) != 0) ;
XX! 		while (access("T7.h2", 0) != 0) ;
XX! 		unlink("T7.h1");
XX! 		unlink("T7.h2");
XX! 		sleep(1);
XX! 		if (set(UNLOCK, 0, 3) != 0) e(6);
XX! 		w = wait(&s);
XX! 		if (w != pid && w != pid2) e(7);
XX! 		s = s >> 8;
XX! 		if (s != 39 && s != 49) e(8);
XX! 		w = wait(&s);
XX! 		if (w != pid && w != pid2) e(9);
XX! 		s = s >> 8;
XX! 		if (s != 39 && s != 49) e(10);
XX! 	} else {
XX! 		func_code = F_SETLKW;	
XX! 		if (creat("T7.h1", 0777) < 0) e(11);
XX! 		if (set(WRITE, 0, 0) != 0) e(12);	/* block now */
XX! 		if (set(UNLOCK, 0, 0) != 0) e(13);
XX! 		exit(39);
XX! 	}
XX!   } else {
XX! 	/* Child tells parent it is alive, then tries to lock and is blocked.*/
XX! 	func_code = F_SETLKW;	
XX! 	if (creat("T7.h2", 0777) < 0) e(14);
XX! 	if (set(WRITE, 0, 1) != 0) e(15);	/* process must block now */
XX! 	if (set(UNLOCK, 0, 1) != 0) e(16);
XX! 	exit(49);
XX!   }
XX!   close(xfd);
XX! }
XX! 
XX! void test7i()
XX! {
XX! /* Check error conditions for fcntl(). */
XX! 
XX!   int tfd, i;
XX! 
XX!   subtest = 9;
XX!  
XX!   errno = 0;
XX!   if ( (xfd = creat("T7.i", 0777)) != 3) e(1);
XX!   if (close(xfd) != 0) e(2);
XX!   if ( (xfd = open("T7.i", O_RDWR)) < 0) e(3);
XX!   if (write(xfd, buf, ITEMS) != ITEMS) e(4);
XX!   if (set(WRITE, 0, 3) != 0) e(5);	/* bytes 0 to 3 are now locked */
XX!   if (set(WRITE, 0, 0) != 0) e(6);
XX!   if (errno != 0) e(7);
XX!   errno = 0;
XX!   if (set(WRITE, 3, 3) != 0) e(8);
XX!   if (errno != 0) e(9);
XX!   tfd = xfd;			/* hold good value */
XX!   xfd = -99;
XX!   errno = 0;
XX!   if (set(WRITE, 0, 0) != -1) e(10);
XX!   if (errno != EBADF) e(11);
XX! 
XX!   errno = 0;  
XX!   if ( (xfd = open("T7.i", O_WRONLY)) < 0) e(12);
XX!   if (set(READ, 0, 0) != -1) e(13);
XX!   if (errno != EBADF) e(14);
XX!   if (close(xfd) != 0) e(15);
XX! 
XX!   errno = 0;  
XX!   if ( (xfd = open("T7.i", O_RDONLY)) < 0) e(16);
XX!   if (set(WRITE, 0, 0) != -1) e(17);
XX!   if (errno != EBADF) e(18);
XX!   if (close(xfd) != 0) e(19);
XX!   xfd = tfd;			/* restore legal xfd value */
XX! 
XX!   /* Check for EINVAL. */
XX!   errno = 0;
XX!   if (fcntl(xfd, F_DUPFD, OPEN_MAX) != -1) e(20);
XX!   if (errno != EINVAL) e(21);
XX!   errno = 0;
XX!   if (fcntl(xfd, F_DUPFD, -1) != -1) e(22);
XX!   if (errno != EINVAL) e(23);
XX! 
XX!   xfd = 0;			/* stdin does not support locking */
XX!   errno = 0;
XX!   if (set(READ, 0, 0) != -1) e(24);
XX!   if (errno != EINVAL) e(25);
XX!   xfd = tfd;
XX! 
XX!   /* Check ENOLCK. */
XX!   for (i = 0; i < ITEMS; i++) {
XX! 	if (set(WRITE, i, i) == 0) continue;
XX! 	if (errno != ENOLCK) {
XX! 		e(26);
XX! 		break;
XX! 	}
XX!   }
XX! 
XX! 
XX!   /* Check EMFILE. */
XX!   for (i = xfd + 1; i < OPEN_MAX; i++) open("T7.i", 0);	/* use up all fds */
XX!   errno = 0;
XX!   if (fcntl(xfd, F_DUPFD, 0) != -1) e(27);	/* No fds left */
XX!   if (errno != EMFILE) e(28);
XX! 
XX!   for (i = xfd; i < OPEN_MAX; i++) if (close(i) != 0) e(29);
XX! }
XX! 
XX! 
XX! void test7j()
XX! {
XX! /* Test file locking with two processes. */
XX! 
XX!   int s;
XX! 
XX!   subtest = 10;
XX!  
XX!   if ( (xfd = creat("T7.j", 0777)) != 3) e(1);
XX!   close(xfd);
XX!   if ( (xfd = open("T7.j", O_RDWR)) < 0) e(2);
XX!   if (write(xfd, buf, ITEMS) != ITEMS) e(3);
XX!   if (set(WRITE, 0, 4) != 0) e(4);	/* lock belongs to parent */
XX!   if (set(READ, 10, 16) != 0) e(5);	/* lock belongs to parent */
XX! 
XX!   /* Up until now, all locks have been disjoint.  Now try conflicts. */
XX!   if (fork()) {
XX! 	/* Parent just waits for child to finish. */
XX! 	wait(&s);
XX!   } else {
XX! 	/* Child does the testing. */
XX! 	errno = -100;
XX! 	if (set(WRITE, 5, 7) < 0) e(6);	/* should work */
XX! 	if (set(WRITE, 4, 7) >= 0) e(7);	/* child may not lock byte 4 */
XX! 	if (errno != EACCES && errno != EAGAIN) e(8);
XX! 	if (set(WRITE, 5, 9) != 0) e(9);
XX! 	if (set(UNLOCK, 5, 9) != 0) e(10);
XX! 	if (set(READ, 9, 17) < 0) e(11);	/* shared READ lock is ok */
XX! 	exit(0);
XX!   }
XX!   close(xfd);
XX! }
XX! 
XX! void cloexec_test()
XX! {
XX! /* To text whether the FD_CLOEXEC flag actually causes files to be
XX!  * closed upon exec, we have to exec something.  The test is carried
XX!  * out by forking, and then having the child exec test7 itself, but
XX!  * with argument 0.  This is detected, and control comes here.
XX!  * File descriptors 3 and 10 should be closed here, and 10 open.
XX!  */
XX! 
XX!   if (close(3) == 0) e(1001);	/* close should fail; it was closed on exec */
XX!   if (close(6) != 0) e(1002);	/* close should succeed */
XX!   if (close(10) == 0) e(1003);	/* close should fail */
XX!   fflush(stdout);
XX!   exit(0);
XX! }
XX! 
XX! 
XX! int set(how, first, last)
XX! int how, first, last;
XX! {
XX!   int r;
XX!   struct flock flock;
XX! 
XX!   if (how == READ) flock.l_type = F_RDLCK;
XX!   if (how == WRITE) flock.l_type = F_WRLCK;
XX!   if (how == UNLOCK) flock.l_type = F_UNLCK;
XX!   flock.l_whence = whence;
XX!   flock.l_start = (long) first;
XX!   flock.l_len = (long) last - (long) first + 1;
XX!   r = fcntl(xfd, func_code, &flock);
XX!   if (r != -1) 
XX! 	return(0);
XX!   else
XX! 	return(-1);
XX! }
XX! 
XX! int locked(b)
XX! int b;
XX! /* Test to see if byte b is locked.  Return L or U */
XX! {
XX!   struct flock flock;
XX!   int r;
XX! 
XX!   flock.l_type = F_WRLCK;
XX!   flock.l_whence = whence;
XX!   flock.l_start = (long) b;
XX!   flock.l_len = 1;
XX!   r = fcntl(xfd, F_GETLK, &flock);
XX!   if (r != 0) e(1000);
XX!   return(flock.l_type == F_UNLCK ? U : L);  
XX! }
XX! 
XX! void e(n)
XX  int n;
XX  {
XX+   int err_num = errno;		/* save errno in case printf clobbers it */
XX+ 
XX    printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX+   fflush(stdout);
XX+   errno = err_num;		/* restore errno, just in case */
XX    perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	chdir("..");
XX+ 	system("rm -rf DIR*");
XX+ 	exit(1);
XX+   }
XX+ }
XX+ 
XX+ void sigfunc(s)
XX+ int s;				/* for ANSI */
XX+ {
XX+ }
XX+ 
XX+ void quit()
XX+ {
XX+ 
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ 
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX  	exit(1);
XX    }
XX  }
X/
Xecho x - test8.c.d
Xsed '/^X/s///' > test8.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test8.c  crc=05202   2286	Sat Apr 21 22:26:26 1990
XX--- /home/top/ast/minix/1.6.25/test/test8.c  crc=07088  26401	Sun Dec 20 15:36:57 1992
XX***************
XX*** 1,101 ****
XX! /* test 8 */
XX  
XX  #include <sys/types.h>
XX! #include <fcntl.h>
XX  #include <unistd.h>
XX! #include <sys/stat.h>
XX  
XX  #define MAX_ERROR 4
XX  
XX! extern int errno;
XX! int subtest, errct;
XX! extern off_t lseek();
XX  
XX  
XX! main()
XX  {
XX!   int i;
XX  
XX    printf("Test  8 ");
XX!   for (i = 0; i < 4; i++) {
XX! 	test80();
XX    }
XX!   printf("ok\n");
XX  }
XX  
XX  
XX  
XX! test80()
XX  {
XX! /* Test mknod, chdir, chmod, chown, access.  */
XX  
XX!   int i, j;
XX!   struct stat s;
XX  
XX!   subtest = 0;
XX!   if (getuid() != 0) return;
XX!   for (j = 0; j < 2; j++) {
XX! 	umask(0);
XX  
XX! 	if (chdir("/") < 0) e(1);
XX! 	if (mknod("dir", 040700, 0) < 0) e(2);
XX! 	if (link("/", "/dir/..") < 0) e(3);
XX! 	if (mknod("T3a", 0777, 0) < 0) e(4);
XX! 	if (mknod("/dir/T3b", 0777, 0) < 0) e(5);
XX! 	if (mknod("dir/T3c", 0777, 0) < 0) e(6);
XX! 	if ((i = open("/dir/T3b", 0)) < 0) e(7);
XX! 	if (close(i) < 0) e(8);
XX! 	if ((i = open("dir/T3c", O_RDONLY)) < 0) e(9);
XX! 	if (close(i) < 0) e(10);
XX! 	if (chdir("dir") < 0) e(11);
XX! 	if ((i = open("T3b", 0)) < 0) e(12);
XX! 	if (close(i) < 0) e(13);
XX! 	if ((i = open("../T3a", O_RDONLY)) < 0) e(14);
XX! 	if (close(i) < 0) e(15);
XX! 	if ((i = open("../dir/../dir/../dir/../dir/../dir/T3c", O_RDONLY)) < 0)
XX! 		e(16);
XX! 	if (close(i) < 0) e(17);
XX  
XX! 	if (chmod("../dir/../dir/../dir/../dir/../T3a", 0123) < 0) e(18);
XX! 	if (stat("../dir/../dir/../dir/../T3a", &s) < 0) e(19);
XX! 	if ((s.st_mode & 077777) != 0123) e(20);
XX! 	if (chmod("../dir/../dir/../T3a", 0456) < 0) e(21);
XX! 	if (stat("../T3a", &s) < 0) e(22);
XX! 	if ((s.st_mode & 077777) != 0456) e(23);
XX! 	if (chown("../dir/../dir/../T3a", 20, 30) < 0) e(24);
XX! 	if (stat("../T3a", &s) < 0) e(25);
XX! 	if (s.st_uid != 20) e(26);
XX! 	if (s.st_gid != 30) e(27);
XX  
XX! 	if ((i = open("/T3c", O_RDONLY)) >= 0) e(28);
XX! 	if ((i = open("/T3a", O_RDONLY)) < 0) e(29);
XX! 	if (close(i) < 0) e(30);
XX  
XX! 	if (access("/T3a", 4) < 0) e(31);
XX! 	if (access("/dir/T3b", 4) < 0) e(32);
XX! 	if (access("/dir/T3d", 4) >= 0) e(33);
XX  
XX! 	if (unlink("T3b") < 0) e(34);
XX! 	if (unlink("T3c") < 0) e(35);
XX! 	if (unlink("..") < 0) e(36);
XX! 	if (chdir("/") < 0) e(37);
XX! 	if (unlink("dir") < 0) e(38);
XX! 	if (unlink("/T3a") < 0) e(39);
XX    }
XX  
XX  }
XX  
XX  
XX! e(n)
XX  int n;
XX  {
XX!   int err_num = errno;		/* save errno in case printf clobbers it */
XX  
XX!   printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX!   errno = err_num;		/* restore errno, just in case */
XX!   perror("");
XX    if (errct++ > MAX_ERROR) {
XX! 	printf("Too many errors; test aborted\n");
XX  	exit(1);
XX    }
XX  }
XX--- 1,1077 ----
XX! /* test 8 - signals */
XX  
XX  #include <sys/types.h>
XX! #include <sys/times.h>
XX! #include <sys/sigcontext.h>
XX! #include <sys/wait.h>
XX! #include <errno.h>
XX! #include <signal.h>
XX! #include <setjmp.h>
XX! #include <stdlib.h>
XX  #include <unistd.h>
XX! #include <stdio.h>
XX  
XX+ #define ITERATIONS 2
XX+ #define SIGS 14
XX  #define MAX_ERROR 4
XX  
XX! int iteration, cumsig, subtest, errct = 0, sig1, sig2;
XX  
XX+ int sigarray[SIGS] = {SIGHUP, SIGILL, SIGTRAP, SIGABRT, SIGIOT, SIGUNUSED,
XX+ 	      SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM,
XX+ 	      SIGTERM, SIGSTKFLT};
XX  
XX! /* Prototypes produced automatically by mkptypes. */
XX! _PROTOTYPE(int main, (int argc, char *argv []));
XX! _PROTOTYPE(void test8a, (void));
XX! _PROTOTYPE(void func1, (int sig));
XX! _PROTOTYPE(void func2, (int sig));
XX! _PROTOTYPE(void test8b, (void));
XX! _PROTOTYPE(void catch1, (int signo));
XX! _PROTOTYPE(void catch2, (int signo));
XX! _PROTOTYPE(void test8c, (void));
XX! _PROTOTYPE(void catch3, (int signo));
XX! _PROTOTYPE(void test8d, (void));
XX! _PROTOTYPE(void catch4, (int signo));
XX! _PROTOTYPE(void test8e, (void));
XX! _PROTOTYPE(void catch5, (int signo));
XX! _PROTOTYPE(void test8f, (void));
XX! _PROTOTYPE(void sigint_handler, (int signo));
XX! _PROTOTYPE(void sigpipe_handler, (int signo));
XX! _PROTOTYPE(void test8g, (void));
XX! _PROTOTYPE(void sighup8, (int signo));
XX! _PROTOTYPE(void sigpip8, (int signo));
XX! _PROTOTYPE(void sigter8, (int signo));
XX! _PROTOTYPE(void test8h, (void));
XX! _PROTOTYPE(void sighup9, (int signo));
XX! _PROTOTYPE(void sigter9, (int signo));
XX! _PROTOTYPE(void test8i, (void));
XX! _PROTOTYPE(void sighup10, (int signo));
XX! _PROTOTYPE(void sigalrm_handler10, (int signo));
XX! _PROTOTYPE(void test8j, (void));
XX! _PROTOTYPE(void test8k, (void));
XX! _PROTOTYPE(void test8l, (void));
XX! _PROTOTYPE(void func_m1, (void));
XX! _PROTOTYPE(void func_m2, (void));
XX! _PROTOTYPE(void test8m, (void));
XX! _PROTOTYPE(void test8n, (void));
XX! _PROTOTYPE(void longjerr, (void));
XX! _PROTOTYPE(void catch14, (int signo, int code, struct sigcontext * scp));
XX! _PROTOTYPE(void test8o, (void));
XX! _PROTOTYPE(void catch15, (int signo));
XX! _PROTOTYPE(void test8p, (void));
XX! _PROTOTYPE(void test8q, (void));
XX! _PROTOTYPE(void clearsigstate, (void));
XX! _PROTOTYPE(void quit, (void));
XX! _PROTOTYPE(void wait_for, (pid_t pid));
XX! _PROTOTYPE(void e, (int n));
XX! 
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX!   int i, m = 0xFFFF;
XX  
XX+   sync();
XX+ 
XX+   if (argc == 2) m = atoi(argv[1]);
XX+ 
XX    printf("Test  8 ");
XX!   fflush(stdout);		/* have to flush for child's benefit */
XX! 
XX!   system("rm -rf DIR_08; mkdir DIR_08");
XX!   chdir("DIR_08");
XX! 
XX! 
XX!   for (i = 0; i < ITERATIONS; i++) {
XX! 	iteration = i;
XX! 	if (m & 0000001) test8a();
XX! 	if (m & 0000002) test8b();
XX! 	if (m & 0000004) test8c();
XX! 	if (m & 0000010) test8d();
XX! 	if (m & 0000020) test8e();
XX! 	if (m & 0000040) test8f();
XX! 	if (m & 0000100) test8g();
XX! 	if (m & 0000200) test8h();
XX! 	if (m & 0000400) test8i();
XX! 	if (m & 0001000) test8j();
XX! 	if (m & 0002000) test8k();
XX! 	if (m & 0004000) test8l();
XX! 	if (m & 0010000) test8m();
XX! 	if (m & 0020000) test8n();
XX! 	if (m & 0040000) test8o();
XX! 	if (m & 0100000) test8p();
XX    }
XX! 
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX  
XX+ void test8a()
XX+ {
XX+ /* Test signal set management. */
XX  
XX!   sigset_t s;
XX! 
XX!   subtest = 1;
XX! 
XX!   /* Create an empty set and see if any bits are on. */
XX!   if (sigemptyset(&s) != 0) e(1);
XX!   if (sigismember(&s, SIGHUP) != 0) e(2);
XX!   if (sigismember(&s, SIGINT) != 0) e(3);
XX!   if (sigismember(&s, SIGQUIT) != 0) e(4);
XX!   if (sigismember(&s, SIGILL) != 0) e(5);
XX!   if (sigismember(&s, SIGTRAP) != 0) e(6);
XX!   if (sigismember(&s, SIGABRT) != 0) e(7);
XX!   if (sigismember(&s, SIGIOT) != 0) e(8);
XX!   if (sigismember(&s, SIGUNUSED) != 0) e(9);
XX!   if (sigismember(&s, SIGFPE) != 0) e(10);
XX!   if (sigismember(&s, SIGKILL) != 0) e(11);
XX!   if (sigismember(&s, SIGUSR1) != 0) e(12);
XX!   if (sigismember(&s, SIGSEGV) != 0) e(13);
XX!   if (sigismember(&s, SIGUSR2) != 0) e(14);
XX!   if (sigismember(&s, SIGPIPE) != 0) e(15);
XX!   if (sigismember(&s, SIGALRM) != 0) e(16);
XX!   if (sigismember(&s, SIGTERM) != 0) e(17);
XX!   if (sigismember(&s, SIGSTKFLT) != 0) e(18);
XX! 
XX!   /* Create a full set and see if any bits are off. */
XX!   if (sigfillset(&s) != 0) e(19);
XX!   if (sigemptyset(&s) != 0) e(20);
XX!   if (sigfillset(&s) != 0) e(21);
XX!   if (sigismember(&s, SIGHUP) != 1) e(22);
XX!   if (sigismember(&s, SIGINT) != 1) e(23);
XX!   if (sigismember(&s, SIGQUIT) != 1) e(24);
XX!   if (sigismember(&s, SIGILL) != 1) e(25);
XX!   if (sigismember(&s, SIGTRAP) != 1) e(26);
XX!   if (sigismember(&s, SIGABRT) != 1) e(27);
XX!   if (sigismember(&s, SIGIOT) != 1) e(28);
XX!   if (sigismember(&s, SIGUNUSED) != 1) e(29);
XX!   if (sigismember(&s, SIGFPE) != 1) e(30);
XX!   if (sigismember(&s, SIGKILL) != 1) e(31);
XX!   if (sigismember(&s, SIGUSR1) != 1) e(32);
XX!   if (sigismember(&s, SIGSEGV) != 1) e(33);
XX!   if (sigismember(&s, SIGUSR2) != 1) e(34);
XX!   if (sigismember(&s, SIGPIPE) != 1) e(35);
XX!   if (sigismember(&s, SIGALRM) != 1) e(36);
XX!   if (sigismember(&s, SIGTERM) != 1) e(37);
XX!   if (sigismember(&s, SIGSTKFLT) != 1) e(38);
XX! 
XX!   /* Create an empty set, then turn on bits individually. */
XX!   if (sigemptyset(&s) != 0) e(39);
XX!   if (sigaddset(&s, SIGHUP) != 0) e(40);
XX!   if (sigaddset(&s, SIGINT) != 0) e(41);
XX!   if (sigaddset(&s, SIGQUIT) != 0) e(42);
XX!   if (sigaddset(&s, SIGILL) != 0) e(43);
XX!   if (sigaddset(&s, SIGTRAP) != 0) e(44);
XX! 
XX!   /* See if the bits just turned on are indeed on. */
XX!   if (sigismember(&s, SIGHUP) != 1) e(45);
XX!   if (sigismember(&s, SIGINT) != 1) e(46);
XX!   if (sigismember(&s, SIGQUIT) != 1) e(47);
XX!   if (sigismember(&s, SIGILL) != 1) e(48);
XX!   if (sigismember(&s, SIGTRAP) != 1) e(49);
XX! 
XX!   /* The others should be turned off. */
XX!   if (sigismember(&s, SIGABRT) != 0) e(50);
XX!   if (sigismember(&s, SIGIOT) != 0) e(51);
XX!   if (sigismember(&s, SIGUNUSED) != 0) e(52);
XX!   if (sigismember(&s, SIGFPE) != 0) e(53);
XX!   if (sigismember(&s, SIGKILL) != 0) e(54);
XX!   if (sigismember(&s, SIGUSR1) != 0) e(55);
XX!   if (sigismember(&s, SIGSEGV) != 0) e(56);
XX!   if (sigismember(&s, SIGUSR2) != 0) e(57);
XX!   if (sigismember(&s, SIGPIPE) != 0) e(58);
XX!   if (sigismember(&s, SIGALRM) != 0) e(59);
XX!   if (sigismember(&s, SIGTERM) != 0) e(60);
XX!   if (sigismember(&s, SIGSTKFLT) != 0) e(61);
XX! 
XX!   /* Now turn them off and see if all are off. */
XX!   if (sigdelset(&s, SIGHUP) != 0) e(62);
XX!   if (sigdelset(&s, SIGINT) != 0) e(63);
XX!   if (sigdelset(&s, SIGQUIT) != 0) e(64);
XX!   if (sigdelset(&s, SIGILL) != 0) e(65);
XX!   if (sigdelset(&s, SIGTRAP) != 0) e(66);
XX! 
XX!   if (sigismember(&s, SIGHUP) != 0) e(67);
XX!   if (sigismember(&s, SIGINT) != 0) e(68);
XX!   if (sigismember(&s, SIGQUIT) != 0) e(69);
XX!   if (sigismember(&s, SIGILL) != 0) e(70);
XX!   if (sigismember(&s, SIGTRAP) != 0) e(71);
XX!   if (sigismember(&s, SIGABRT) != 0) e(72);
XX!   if (sigismember(&s, SIGIOT) != 0) e(73);
XX!   if (sigismember(&s, SIGUNUSED) != 0) e(74);
XX!   if (sigismember(&s, SIGFPE) != 0) e(75);
XX!   if (sigismember(&s, SIGKILL) != 0) e(76);
XX!   if (sigismember(&s, SIGUSR1) != 0) e(77);
XX!   if (sigismember(&s, SIGSEGV) != 0) e(78);
XX!   if (sigismember(&s, SIGUSR2) != 0) e(79);
XX!   if (sigismember(&s, SIGPIPE) != 0) e(80);
XX!   if (sigismember(&s, SIGALRM) != 0) e(81);
XX!   if (sigismember(&s, SIGTERM) != 0) e(82);
XX!   if (sigismember(&s, SIGSTKFLT) != 0) e(83);
XX! }
XX! 
XX! void func1(sig)
XX! int sig;
XX  {
XX!   sig1++;
XX! }
XX  
XX! void func2(sig)
XX! int sig;
XX! {
XX!   sig2++;
XX! }
XX  
XX! void test8b()
XX! {
XX! /* Test sigprocmask and sigpending. */
XX!   int i;
XX!   pid_t p;
XX!   sigset_t s, s1, s_empty, s_full, s_ill, s_ill_pip, s_nokill;
XX!   struct sigaction sa, osa;
XX  
XX!   subtest = 2;
XX! 
XX!   /* Construct s_ill = {SIGILL} and s_ill_pip {SIGILL | SIGPIP}, etc. */
XX!   if (sigemptyset(&s_empty) != 0) e(1);
XX!   if (sigemptyset(&s_ill) != 0) e(2);
XX!   if (sigemptyset(&s_ill_pip) != 0) e(3);
XX!   if (sigaddset(&s_ill, SIGILL) != 0) e(4);
XX!   if (sigaddset(&s_ill_pip, SIGILL) != 0) e(5);
XX!   if (sigaddset(&s_ill_pip, SIGPIPE) != 0) e(6);
XX!   if (sigfillset(&s_full) != 0) e(7);
XX!   s_nokill = s_full;
XX!   if (sigdelset(&s_nokill, SIGKILL) != 0) e(8);
XX! 
XX!   /* Now get most of the signals into default state.  Don't change SIGINT
XX!   * or SIGQUIT, so this program can be killed.  SIGKILL is also special.
XX!   */
XX!   sa.sa_handler = SIG_DFL;
XX!   sa.sa_mask = s_empty;
XX!   sa.sa_flags = 0;
XX!   for (i = 0; i < SIGS; i++) sigaction(i, &sa, &osa);
XX! 
XX!   /* The second argument may be zero.  See if it wipes out the system. */
XX!   for (i = 0; i < SIGS; i++) sigaction(i, (struct sigaction *) 0, &osa);
XX! 
XX!   /* Install a signal handler. */
XX!   sa.sa_handler = func1;
XX!   sa.sa_mask = s_ill;
XX!   sa.sa_flags = SA_NODEFER | SA_NOCLDSTOP;
XX!   osa.sa_handler = SIG_IGN;
XX!   osa.sa_mask = s_empty;
XX!   osa.sa_flags = 0;
XX!   if (sigaction(SIGHUP, &sa, &osa) != 0) e(9);
XX!   if (osa.sa_handler != SIG_DFL) e(10);
XX!   if (osa.sa_mask != 0) e(11);
XX!   if (osa.sa_flags != s_empty) e(12);
XX! 
XX!   /* Replace action and see if old value is read back correctly. */
XX!   sa.sa_handler = func2;
XX!   sa.sa_mask = s_ill_pip;
XX!   sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_COMPAT;
XX!   osa.sa_handler = SIG_IGN;
XX!   osa.sa_mask = s_empty;
XX!   osa.sa_flags = 0;
XX!   if (sigaction(SIGHUP, &sa, &osa) != 0) e(13);
XX!   if (osa.sa_handler != func1) e(14);
XX!   if (osa.sa_mask != s_ill) e(15);
XX!   if (osa.sa_flags != (SA_NODEFER | SA_NOCLDSTOP)) e(16);
XX! 
XX!   /* Replace action once more and check what is read back. */
XX!   sa.sa_handler = SIG_DFL;
XX!   sa.sa_mask = s_empty;
XX!   osa.sa_handler = SIG_IGN;
XX!   osa.sa_mask = s_empty;
XX!   osa.sa_flags = 0;
XX!   if (sigaction(SIGHUP, &sa, &osa) != 0) e(17);
XX!   if (osa.sa_handler != func2) e(18);
XX!   if (osa.sa_mask != s_ill_pip) e(19);
XX!   if (osa.sa_flags != (SA_RESETHAND | SA_NODEFER)) e(20);
XX! 
XX!   /* Test sigprocmask(SIG_SETMASK, ...). */
XX!   if (sigprocmask(SIG_SETMASK, &s_full, &s1) != 0) e(18);    /* block all */
XX!   if (sigemptyset(&s1) != 0) e(19);
XX!   if (sigprocmask(SIG_SETMASK, &s_empty, &s1) != 0) e(20);   /* block none */
XX!   if (s1 != s_nokill) e(21);
XX!   if (sigprocmask(SIG_SETMASK, &s_ill, &s1) != 0) e(22);     /* block SIGILL */
XX!   if (s1 != s_empty) e(23);
XX!   if (sigprocmask(SIG_SETMASK, &s_ill_pip, &s1) != 0) e(24); /* SIGILL+PIP */
XX!   if (s1 != s_ill) e(25);
XX!   if (sigprocmask(SIG_SETMASK, &s_full, &s1) != 0) e(26);    /* block all */
XX!   if (s1 != s_ill_pip) e(27);
XX! 
XX!   /* Test sigprocmask(SIG_UNBLOCK, ...) */
XX!   if (sigprocmask(SIG_UNBLOCK, &s_ill, &s1) != 0) e(28);
XX!   if (s1 != s_nokill) e(29);
XX!   if (sigprocmask(SIG_UNBLOCK, &s_ill_pip, &s1) != 0) e(30);
XX!   s = s_nokill;
XX!   if (sigdelset(&s, SIGILL) != 0) e(31);
XX!   if (s != s1) e(32);
XX!   if (sigprocmask(SIG_UNBLOCK, &s_empty, &s1) != 0) e(33);
XX!   s = s_nokill;
XX!   if (sigdelset(&s, SIGILL) != 0) e(34);
XX!   if (sigdelset(&s, SIGPIPE) != 0) e(35);
XX!   if (s != s1) e(36);
XX!   s1 = s_nokill;
XX!   if (sigprocmask(SIG_SETMASK, &s_empty, &s1) != 0) e(37);
XX!   if (s != s1) e(38);
XX! 
XX!   /* Test sigprocmask(SIG_BLOCK, ...) */
XX!   if (sigprocmask(SIG_BLOCK, &s_ill, &s1) != 0) e(39);
XX!   if (s1 != s_empty) e(40);
XX!   if (sigprocmask(SIG_BLOCK, &s_ill_pip, &s1) != 0) e(41);
XX!   if (s1 != s_ill) e(42);
XX!   if (sigprocmask(SIG_SETMASK, &s_full, &s1) != 0) e(43);
XX!   if (s1 != s_ill_pip) e(44);
XX! 
XX!   /* Check error condition. */
XX!   errno = 0;
XX!   if (sigprocmask(20000, &s_full, &s1) != -1) e(45);
XX!   if (errno != EINVAL) e(46);
XX!   if (sigprocmask(SIG_SETMASK, &s_full, &s1) != 0) e(47);
XX!   if (s1 != s_nokill) e(48);
XX! 
XX!   /* If second arg is 0, nothing is set. */
XX!   if (sigprocmask(SIG_SETMASK, (sigset_t *) 0, &s1) != 0) e(49);
XX!   if (s1 != s_nokill) e(50);
XX!   if (sigprocmask(SIG_SETMASK, &s_ill_pip, &s1) != 0) e(51);
XX!   if (s1 != s_nokill) e(52);
XX!   if (sigprocmask(SIG_SETMASK, (sigset_t *) 0, &s1) != 0) e(53);
XX!   if (s1 != s_ill_pip) e(54);
XX!   if (sigprocmask(SIG_BLOCK, (sigset_t *) 0, &s1) != 0) e(55);
XX!   if (s1 != s_ill_pip) e(56);
XX!   if (sigprocmask(SIG_UNBLOCK, (sigset_t *) 0, &s1) != 0) e(57);
XX!   if (s1 != s_ill_pip) e(58);
XX! 
XX!   /* Trying to block SIGKILL is not allowed, but is not an error, either. */
XX!   s = s_empty;
XX!   if (sigaddset(&s, SIGKILL) != 0) e(59);
XX!   if (sigprocmask(SIG_BLOCK, &s, &s1) != 0) e(60);
XX!   if (s1 != s_ill_pip) e(61);
XX!   if (sigprocmask(SIG_SETMASK, &s_full, &s1) != 0) e(62);
XX!   if (s1 != s_ill_pip) e(63);
XX! 
XX!   /* Test sigpending. At this moment, all signals are blocked. */
XX!   sa.sa_handler = func2;
XX!   sa.sa_mask = s_empty;
XX!   if (sigaction(SIGHUP, &sa, &osa) != 0) e(64);
XX!   p = getpid();
XX!   kill(p, SIGHUP);		/* send SIGHUP to self */
XX!   if (sigpending(&s) != 0) e(65);
XX!   if (sigemptyset(&s1) != 0) e(66);
XX!   if (sigaddset(&s1, SIGHUP) != 0) e(67);
XX!   if (s != s1) e(68);
XX!   sa.sa_handler = SIG_IGN;
XX!   if (sigaction(SIGHUP, &sa, &osa) != 0) e(69);
XX!   if (sigpending(&s) != 0) e(70);
XX!   if (s != s_empty) e(71);
XX! }
XX! 
XX! /*---------------------------------------------------------------------------*/
XX! int x;
XX! sigset_t glo_vol_set;
XX! 
XX! void catch1(signo)
XX! int signo;
XX! {
XX!   x = 42;
XX! }
XX! 
XX! void catch2(signo)
XX! int signo;
XX! {
XX!   if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, (sigset_t *) & glo_vol_set) != 0) e(1);
XX! }
XX! 
XX! /* Verify that signal(2), which is now built on top of sigaction(2), still
XX! * works.
XX! */
XX! void test8c()
XX! {
XX!   pid_t pid;
XX!   sigset_t sigset_var;
XX! 
XX!   subtest = 3;
XX! 
XX!   clearsigstate();
XX!   x = 0;
XX! 
XX!   /* Verify an installed signal handler persists across a fork(2). */
XX!   if (signal(SIGTERM, catch1) == SIG_ERR) e(1);
XX!   switch (pid = fork()) {
XX!       case 0:			/* child */
XX! 	errct = 0;
XX! 	while (x == 0);
XX! 	if (x != 42) e(2);
XX! 	exit(errct == 0 ? 0 : 1);
XX!       case -1:	e(3);	break;
XX!       default:			/* parent */
XX! 	sleep(1);
XX! 	if (kill(pid, SIGTERM) != 0) e(4);
XX! 	wait_for(pid);
XX! 	break;
XX!   }
XX! 
XX!   /* Verify that the return value is the previous handler. */
XX!   signal(SIGINT, SIG_IGN);
XX!   if (signal(SIGINT, catch2) != SIG_IGN) e(5);
XX!   if (signal(SIGINT, catch1) != catch2) e(6);
XX!   if (signal(SIGINT, SIG_DFL) != catch1) e(7);
XX!   if (signal(SIGINT, catch1) != SIG_DFL) e(8);
XX!   if (signal(SIGINT, SIG_DFL) != catch1) e(9);
XX!   if (signal(SIGINT, SIG_DFL) != SIG_DFL) e(10);
XX!   if (signal(SIGINT, catch1) != SIG_DFL) e(11);
XX! 
XX!   /* Verify that SIG_ERR is correctly generated. */
XX!   if (signal(_NSIG + 1, catch1) != SIG_ERR) e(12);
XX!   if (signal(0, catch1) != SIG_ERR) e(13);
XX!   if (signal(-1, SIG_DFL) != SIG_ERR) e(14);
XX! 
XX!   /* Verify that caught signals are automatically reset to the default,
XX!    * and that further instances of the same signal are not blocked here
XX!    * or in the signal handler.
XX!    */
XX!   if (signal(SIGTERM, catch1) == SIG_ERR) e(15);
XX!   switch ((pid = fork())) {
XX!       case 0:			/* child */
XX! 	errct = 0;
XX! 	while (x == 0);
XX! 	if (x != 42) e(16);
XX! 	if (sigismember((sigset_t *) & glo_vol_set, SIGTERM)) e(17);
XX! 	if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &sigset_var) != 0) e(18);
XX! 	if (sigismember(&sigset_var, SIGTERM)) e(19);
XX! 
XX!   /* If you have compiled signal() with the BSD behaviour, then
XX!    * the next line will incorrectly detect an error.
XX!    */
XX! 	if (signal(SIGTERM, catch1) != SIG_DFL) e(20);
XX! 	exit(errct == 0 ? 0 : 1);
XX!       default:			/* parent */
XX! 	sleep(1);
XX! 	if (kill(pid, SIGTERM) != 0) e(21);
XX! 	wait_for(pid);
XX! 	break;
XX!       case -1:	e(22);	break;
XX!   }
XX! }
XX! 
XX! /*---------------------------------------------------------------------------*/
XX! /* Test that the signal handler can be invoked recursively with the
XX! * state being properly saved and restored.
XX! */
XX! 
XX! static int y;
XX! static int z;
XX! 
XX! void catch3(signo)
XX! int signo;
XX! {
XX!   if (z == 1) {			/* catching a nested signal */
XX! 	y = 2;
XX! 	return;
XX!   }
XX!   z = 1;
XX!   if (kill(getpid(), SIGHUP) != 0) e(1);
XX!   while (y != 2);
XX!   y = 1;
XX! }
XX! 
XX! void test8d()
XX! {
XX!   struct sigaction act;
XX! 
XX!   subtest = 4;
XX! 
XX!   clearsigstate();
XX!   y = 0;
XX!   z = 0;
XX!   act.sa_handler = catch3;
XX!   act.sa_mask = 0;
XX!   act.sa_flags = SA_NODEFER;	/* Otherwise, nested occurence of
XX! 				 * SIGINT is blocked. */
XX!   if (sigaction(SIGHUP, &act, (struct sigaction *) NULL) != 0) e(2);
XX!   if (kill(getpid(), SIGHUP) != 0) e(3);
XX!   if (y != 1) e(4);
XX! }
XX! 
XX! /*---------------------------------------------------------------------------*/
XX! 
XX! /* Test that the signal mask in effect for the duration of a signal handler
XX! * is as specified in POSIX Section 3, lines 718 -724.  Test that the
XX! * previous signal mask is restored when the signal handler returns.
XX! */
XX! 
XX! void catch4(signo)
XX! int signo;
XX! {
XX!   sigset_t oset;
XX!   sigset_t set;
XX! 
XX!   if (sigemptyset(&set) == -1) e(1);
XX!   if (sigaddset(&set, SIGTERM) == -1) e(2);
XX!   if (sigaddset(&set, SIGHUP) == -1) e(3);
XX!   if (sigaddset(&set, SIGINT) == -1) e(4);
XX!   if (sigaddset(&set, SIGPIPE) == -10) e(5);
XX!   if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &oset) != 0) e(6);
XX!   if (oset != set) e(7);
XX! }
XX! 
XX! void test8e()
XX! {
XX!   struct sigaction act, oact;
XX!   sigset_t set, oset;
XX! 
XX!   subtest = 5;
XX!   clearsigstate();
XX! 
XX!   act.sa_handler = catch4;
XX!   sigemptyset(&act.sa_mask);
XX!   sigaddset(&act.sa_mask, SIGTERM);
XX!   sigaddset(&act.sa_mask, SIGHUP);
XX!   act.sa_flags = 0;
XX!   if (sigaction(SIGINT, &act, &oact) == -1) e(2);
XX! 
XX!   if (sigemptyset(&set) == -1) e(3);
XX!   if (sigaddset(&set, SIGPIPE) == -1) e(4);
XX!   if (sigprocmask(SIG_SETMASK, &set, &oset) == -1) e(5);
XX!   if (kill(getpid(), SIGINT) == -1) e(6);
XX!   if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &oset) == -1) e(7);
XX!   if (sigemptyset(&set) == -1) e(8);
XX!   if (sigaddset(&set, SIGPIPE) == -1) e(9);
XX!   if (set != oset) e(10);
XX! }
XX! 
XX! /*---------------------------------------------------------------------------*/
XX! 
XX! /* Test the basic functionality of sigsuspend(2). */
XX! 
XX! void catch5(signo)
XX! int signo;
XX! {
XX!   x = 1;
XX! }
XX! 
XX! void test8f()
XX! {
XX!   sigset_t set;
XX!   int r;
XX!   struct sigaction act;
XX!   pid_t pid;
XX! 
XX!   subtest = 6;
XX! 
XX!   switch (pid = fork()) {
XX!       case 0:			/* child */
XX! 	errct = 0;
XX! 	sleep(1);
XX! 	if (kill(getppid(), SIGINT) == -1) e(1);
XX! 	exit(errct == 0 ? 0 : 1);
XX!       case -1:	e(2);	break;
XX!       default:			/* parent */
XX! 	if (sigemptyset(&act.sa_mask) == -1) e(3);
XX! 	act.sa_flags = 0;
XX! 	act.sa_handler = catch5;
XX! 	if (sigaction(SIGINT, &act, 0) == -1) e(4);
XX! 
XX! 	if (sigemptyset(&set) == -1) e(5);
XX! 	r = sigsuspend(&set);
XX! 
XX! 	if (r != -1 || errno != EINTR || x != 1) e(6);
XX! 	wait_for(pid);
XX! 	break;
XX!   }
XX! }
XX! 
XX! /*----------------------------------------------------------------------*/
XX! 
XX! /* Test that sigsuspend() does block the signals specified in its
XX! * argument, and after sigsuspend returns, the previous signal
XX! * mask is restored.
XX! *
XX! * The child sends two signals to the parent SIGINT and then SIGPIPE,
XX! * separated by a long delay.  The parent executes sigsuspend() with
XX! * SIGINT blocked.  It is expected that the parent's SIGPIPE handler
XX! * will be invoked, then sigsuspend will return restoring the
XX! * original signal mask, and then the SIGPIPE handler will be
XX! * invoked.
XX! */
XX! 
XX! void sigint_handler(signo)
XX! int signo;
XX! {
XX!   x = 1;
XX!   z++;
XX! }
XX! 
XX! void sigpipe_handler(signo)
XX! int signo;
XX! {
XX!   x = 2;
XX!   z++;
XX! }
XX! 
XX! void test8g()
XX! {
XX!   sigset_t set;
XX!   int r;
XX!   struct sigaction act;
XX!   pid_t pid;
XX! 
XX!   subtest = 7;
XX!   clearsigstate();
XX!   x = 0;
XX!   z = 0;
XX  
XX!   switch (pid = fork()) {
XX!       case 0:			/* child */
XX! 	errct = 0;
XX! 	sleep(1);
XX! 	if (kill(getppid(), SIGINT) == -1) e(1);
XX! 	sleep(1);
XX! 	if (kill(getppid(), SIGPIPE) == -1) e(2);
XX! 	exit(errct == 0 ? 0 : 1);
XX!       case -1:	e(3);	break;
XX!       default:			/* parent */
XX! 	if (sigemptyset(&act.sa_mask) == -1) e(3);
XX! 	act.sa_flags = 0;
XX! 	act.sa_handler = sigint_handler;
XX! 	if (sigaction(SIGINT, &act, 0) == -1) e(4);
XX  
XX! 	act.sa_handler = sigpipe_handler;
XX! 	if (sigaction(SIGPIPE, &act, 0) == -1) e(5);
XX  
XX! 	if (sigemptyset(&set) == -1) e(6);
XX! 	if (sigaddset(&set, SIGINT) == -1) e(7);
XX! 	r = sigsuspend(&set);
XX! 	if (r != -1) e(8);
XX! 	if (errno != EINTR) e(9);
XX! 	if (z != 2) e(10);
XX! 	if (x != 1) e(11);
XX! 	wait_for(pid);
XX! 	break;
XX!   }
XX! }
XX  
XX! /*--------------------------------------------------------------------------*/
XX! 
XX! /* Test that sigsuspend() does block the signals specified in its
XX! * argument, and after sigsuspend returns, the previous signal
XX! * mask is restored.
XX! *
XX! * The child sends three signals to the parent: SIGHUP, then SIGPIPE,
XX! * and then SIGTERM, separated by a long delay.  The parent executes
XX! * sigsuspend() with SIGHUP and SIGPIPE blocked.  It is expected that
XX! * the parent's SIGTERM handler will be invoked first, then sigsuspend()
XX! * will return restoring the original signal mask, and then the other
XX! * two handlers will be invoked.
XX! */
XX! 
XX! void sighup8(signo)
XX! int signo;
XX! {
XX!   x = 1;
XX!   z++;
XX! }
XX! 
XX! void sigpip8(signo)
XX! int signo;
XX! {
XX!   x = 1;
XX!   z++;
XX! }
XX! 
XX! void sigter8(signo)
XX! int signo;
XX! {
XX!   x = 2;
XX!   z++;
XX! }
XX! 
XX! void test8h()
XX! {
XX!   sigset_t set;
XX!   int r;
XX!   struct sigaction act;
XX!   pid_t pid;
XX! 
XX!   subtest = 8;
XX!   clearsigstate();
XX!   x = 0;
XX!   z = 0;
XX! 
XX!   switch (pid = fork()) {
XX!       case 0:			/* child */
XX! 	errct = 0;
XX! 	sleep(1);
XX! 	if (kill(getppid(), SIGHUP) == -1) e(1);
XX! 	sleep(1);
XX! 	if (kill(getppid(), SIGPIPE) == -1) e(2);
XX! 	sleep(1);
XX! 	if (kill(getppid(), SIGTERM) == -1) e(3);
XX! 	exit(errct == 0 ? 0 : 1);
XX!       case -1:	e(5);	break;
XX!       default:			/* parent */
XX! 	if (sigemptyset(&act.sa_mask) == -1) e(6);
XX! 	act.sa_flags = 0;
XX! 	act.sa_handler = sighup8;
XX! 	if (sigaction(SIGHUP, &act, 0) == -1) e(7);
XX! 
XX! 	act.sa_handler = sigpip8;
XX! 	if (sigaction(SIGPIPE, &act, 0) == -1) e(8);
XX! 
XX! 	act.sa_handler = sigter8;
XX! 	if (sigaction(SIGTERM, &act, 0) == -1) e(9);
XX! 
XX! 	if (sigemptyset(&set) == -1) e(10);
XX! 	if (sigaddset(&set, SIGHUP) == -1) e(11);
XX! 	if (sigaddset(&set, SIGPIPE) == -1) e(12);
XX! 	r = sigsuspend(&set);
XX! 	if (r != -1) e(13);
XX! 	if (errno != EINTR) e(14);
XX! 	if (z != 3) e(15);
XX! 	if (x != 1) e(16);
XX! 	wait_for(pid);
XX! 	break;
XX    }
XX+ }
XX  
XX+ /*--------------------------------------------------------------------------*/
XX+ 
XX+ /* Block SIGHUP and SIGTERM with sigprocmask(), send ourself SIGHUP
XX+ * and SIGTERM, unblock these signals with sigprocmask, and verify
XX+ * that these signals are delivered.
XX+ */
XX+ 
XX+ void sighup9(signo)
XX+ int signo;
XX+ {
XX+   y++;
XX  }
XX  
XX+ void sigter9(signo)
XX+ int signo;
XX+ {
XX+   z++;
XX+ }
XX  
XX! void test8i()
XX! {
XX!   sigset_t set;
XX!   struct sigaction act;
XX! 
XX!   clearsigstate();
XX!   subtest = 9;
XX!   y = 0;
XX!   z = 0;
XX! 
XX!   if (sigemptyset(&act.sa_mask) == -1) e(1);
XX!   act.sa_flags = 0;
XX! 
XX!   act.sa_handler = sighup9;
XX!   if (sigaction(SIGHUP, &act, 0) == -1) e(2);
XX! 
XX!   act.sa_handler = sigter9;
XX!   if (sigaction(SIGTERM, &act, 0) == -1) e(3);
XX! 
XX!   if (sigemptyset(&set) == -1) e(4);
XX!   if (sigaddset(&set, SIGTERM) == -1) e(5);
XX!   if (sigaddset(&set, SIGHUP) == -1) e(6);
XX!   if (sigprocmask(SIG_SETMASK, &set, (sigset_t *)NULL) == -1) e(7);
XX! 
XX!   if (kill(getpid(), SIGHUP) == -1) e(8);
XX!   if (kill(getpid(), SIGTERM) == -1) e(9);
XX!   if (y != 0) e(10);
XX!   if (z != 0) e(11);
XX! 
XX!   if (sigemptyset(&set) == -1) e(12);
XX!   if (sigprocmask(SIG_SETMASK, &set, (sigset_t *)NULL) == -1) e(12);
XX!   if (y != 1) e(13);
XX!   if (z != 1) e(14);
XX! }
XX! 
XX! /*---------------------------------------------------------------------------*/
XX! 
XX! /* Block SIGINT and then send this signal to ourself.
XX! *
XX! * Install signal handlers for SIGALRM and SIGINT.
XX! *
XX! * Set an alarm for 6 second, then sleep for 7.
XX! *
XX! * The SIGALRM should interrupt the sleep, but the SIGINT
XX! * should remain pending.
XX! */
XX! 
XX! void sighup10(signo)
XX! int signo;
XX! {
XX!   y++;
XX! }
XX! 
XX! void sigalrm_handler10(signo)
XX! int signo;
XX! {
XX!   z++;
XX! }
XX! 
XX! void test8j()
XX! {
XX!   sigset_t set, set2;
XX!   struct sigaction act;
XX! 
XX!   clearsigstate();
XX! 
XX!   subtest = 10;
XX!   y = 0;
XX!   z = 0;
XX! 
XX!   if (sigemptyset(&act.sa_mask) == -1) e(1);
XX!   act.sa_flags = 0;
XX! 
XX!   act.sa_handler = sighup10;
XX!   if (sigaction(SIGHUP, &act, 0) == -1) e(2);
XX! 
XX!   act.sa_handler = sigalrm_handler10;
XX!   if (sigaction(SIGALRM, &act, 0) == -1) e(3);
XX! 
XX!   if (sigemptyset(&set) == -1) e(4);
XX!   if (sigaddset(&set, SIGHUP) == -1) e(5);
XX!   if (sigprocmask(SIG_SETMASK, &set, (sigset_t *)NULL) == -1) e(6);
XX! 
XX!   if (kill(getpid(), SIGHUP) == -1) e(7);
XX!   if (sigpending(&set) == -1) e(8);
XX!   if (sigemptyset(&set2) == -1) e(9);
XX!   if (sigaddset(&set2, SIGHUP) == -1) e(10);
XX!   if (set2 != set) e(11);
XX!   alarm(6);
XX!   sleep(7);
XX!   if (sigpending(&set) == -1) e(12);
XX!   if (set != set2) e(13);
XX!   if (y != 0) e(14);
XX!   if (z != 1) e(15);
XX! }
XX! 
XX! /*--------------------------------------------------------------------------*/
XX! 
XX! void test8k()
XX! {
XX! }
XX! void test8l()
XX! {
XX! }
XX! 
XX! /*--------------------------------------------------------------------------*/
XX! 
XX! /* Basic test for _setjmp/_longjmp. */
XX! 
XX! jmp_buf glo_jb;
XX! 
XX! void func_m1()
XX! {
XX!   func_m2();
XX! }
XX! 
XX! void func_m2()
XX! {
XX!   z++;
XX!   _longjmp(glo_jb, 1);
XX! }
XX! 
XX! void test8m()
XX! {
XX!   subtest = 13;
XX!   z = 0;
XX! 
XX!   if (_setjmp(glo_jb)) {
XX! 	if (z != 1) e(1);
XX! 	return;
XX!   }
XX!   func_m1();
XX! }
XX! 
XX! /*---------------------------------------------------------------------------*/
XX! 
XX! /* Basic test for setjmp/longjmp.  This includes testing that the
XX! * signal mask is properly restored.
XX! */
XX! 
XX! void test8n()
XX! {
XX!   jmp_buf jb;
XX!   sigset_t ss;
XX! 
XX!   subtest = 13;
XX!   clearsigstate();
XX!   ss = 0x32;
XX!   if (sigprocmask(SIG_SETMASK, &ss, (sigset_t *)NULL) == -1) e(1);
XX!   if (setjmp(jb)) {
XX! 	if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &ss) == -1) e(2);
XX! 	if (ss != 0x32) e(388);
XX! 	return;
XX!   }
XX!   ss = 0x3abc;
XX!   if (sigprocmask(SIG_SETMASK, &ss, (sigset_t *)NULL) == -1) e(4);
XX!   longjmp(jb, 1);
XX! }
XX! 
XX! void longjerr()
XX! {
XX!   e(5);
XX! }
XX! 
XX! /*--------------------------------------------------------------------------*/
XX! 
XX! /* Test for setjmp/longjmp.
XX! *
XX! * Catch a signal.  While in signal handler do setjmp/longjmp.
XX! */
XX! 
XX! void catch14(signo, code, scp)
XX! int signo;
XX! int code;
XX! struct sigcontext *scp;
XX! {
XX!   jmp_buf jb;
XX! 
XX!   if (setjmp(jb)) {
XX! 	x++;
XX! 	sigreturn(scp);
XX! 	e(1);
XX!   }
XX!   y++;
XX!   longjmp(jb, 1);
XX!   e(2);
XX! }
XX! 
XX! void test8o()
XX! {
XX!   struct sigaction act;
XX! 
XX!   subtest = 14;
XX!   clearsigstate();
XX!   x = 0;
XX!   y = 0;
XX! 
XX!   act.sa_flags = 0;
XX!   act.sa_mask = 0;
XX!   act.sa_handler = (sighandler_t) catch14;
XX!   if (sigaction(SIGSEGV, &act, (struct sigaction *) NULL) == -1) e(3);
XX!   if (kill(getpid(), SIGSEGV) == -1) e(4);
XX! 
XX!   if (x != 1) e(5);
XX!   if (y != 1) e(6);
XX! }
XX! 
XX! /*---------------------------------------------------------------------------*/
XX! 
XX! /* Test for setjmp/longjmp.
XX!  *
XX!  * Catch a signal.  Longjmp out of signal handler.
XX!  */
XX! 
XX! void catch15(signo)
XX! int signo;
XX! {
XX!   z++;
XX!   longjmp(glo_jb, 7);
XX!   e(1);
XX! 
XX! }
XX! 
XX! void test8p()
XX! {
XX!   struct sigaction act;
XX!   int k;
XX! 
XX!   subtest = 15;
XX!   clearsigstate();
XX!   z = 0;
XX! 
XX!   act.sa_flags = 0;
XX!   act.sa_mask = 0;
XX!   act.sa_handler = catch15;
XX!   if (sigaction(SIGALRM, &act, (struct sigaction *) NULL) == -1) e(2);
XX! 
XX!   if ((k = setjmp(glo_jb))) {
XX! 	if (z != 1) e(399);
XX! 	if (k != 7) e(4);
XX! 	return;
XX!   }
XX!   if (kill(getpid(), SIGALRM) == -1) e(5);
XX! }
XX! 
XX! void test8q()
XX! {
XX! }
XX! 
XX! 
XX! 
XX! void clearsigstate()
XX! {
XX!   int i;
XX!   sigset_t sigset_var;
XX! 
XX!   /* Clear the signal state. */
XX!   for (i = 1; i < _NSIG; i++) signal(i, SIG_IGN);
XX!   for (i = 1; i < _NSIG; i++) signal(i, SIG_DFL);
XX!   sigfillset(&sigset_var);
XX!   sigprocmask(SIG_UNBLOCK, &sigset_var, (sigset_t *)NULL);
XX! }
XX! 
XX! void quit()
XX! {
XX! 
XX!   chdir("..");
XX!   system("rm -rf DIR*");
XX! 
XX!   if (errct == 0) {
XX! 	printf("ok\n");
XX! 	exit(0);
XX!   } else {
XX! 	printf("%d errors\n", errct);
XX! 	exit(4);
XX!   }
XX! }
XX! 
XX! void wait_for(pid)
XX! pid_t pid;
XX! {
XX! /* Expect exactly one child, and that it exits with 0. */
XX! 
XX!   int r;
XX!   int status;
XX! 
XX!   errno = 0;
XX!   while (1) {
XX! 	errno = 0;
XX! 	r = wait(&status);
XX! 	if (r == pid) {
XX! 		errno = 0;
XX! 		if (status != 0) e(90);
XX! 		return;
XX! 	}
XX! 	if (r < 0) {
XX! 		e(91);
XX! 		return;
XX! 	}
XX! 	e(92);
XX!   }
XX! }
XX! 
XX! void e(n)
XX  int n;
XX  {
XX!   char msgbuf[80];
XX  
XX!   sprintf(msgbuf, "Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX!   perror(msgbuf);
XX    if (errct++ > MAX_ERROR) {
XX! 	fprintf(stderr, "Too many errors;  test aborted\n");
XX! 	chdir("..");
XX! 	system("rm -rf DIR*");
XX  	exit(1);
XX    }
XX  }
X/
Xecho x - test9.c.d
Xsed '/^X/s///' > test9.c.d << '/'
XX*** /home/top/ast/minix/1.5/test/test9.c  crc=22610   3815	Sat Apr 21 22:26:26 1990
XX--- /home/top/ast/minix/1.6.25/test/test9.c  crc=52072   5183	Sat Feb 20 20:47:30 1993
XX***************
XX*** 1,37 ****
XX! /* Test 9 setjmp with register variables.		Author: Ceriel Jacobs */
XX  
XX  #include <setjmp.h>
XX  #include <signal.h>
XX  #include <stdio.h>
XX  
XX  #define MAX_ERROR 4
XX  
XX- int whichtest;
XX  int nerrors;
XX  int errct;
XX  int subtest = 1;
XX  char *tmpa;
XX  
XX  
XX- extern int errno;
XX  
XX! main()
XX  {
XX    jmp_buf envm;
XX-   register int i;
XX    int j;
XX  
XX    printf("Test  9 ");
XX    for (j = 0; j < 100; j++) {
XX! 	test1();
XX! 	test2();
XX! 	test3();
XX! 	test4();
XX! 	test5();
XX! 	test6();
XX    }
XX    if (nerrors) {
XX  	printf("%d errors detected\n", nerrors);
XX  	exit(nerrors);
XX    }
XX    i = 1;
XX--- 1,70 ----
XX! /* Test 9 setjmp with register variables.	Author: Ceriel Jacobs */
XX  
XX+ #include <sys/types.h>
XX+ #include <errno.h>
XX  #include <setjmp.h>
XX  #include <signal.h>
XX+ #include <string.h>
XX+ #include <stdlib.h>
XX+ #include <unistd.h>
XX  #include <stdio.h>
XX  
XX  #define MAX_ERROR 4
XX  
XX  int nerrors;
XX  int errct;
XX  int subtest = 1;
XX  char *tmpa;
XX  
XX+ _PROTOTYPE(int main, (int argc, char *argv []));
XX+ _PROTOTYPE(void test9a, (void));
XX+ _PROTOTYPE(void test9b, (void));
XX+ _PROTOTYPE(void test9c, (void));
XX+ _PROTOTYPE(void test9d, (void));
XX+ _PROTOTYPE(void test9e, (void));
XX+ _PROTOTYPE(void test9f, (void));
XX+ _PROTOTYPE(char *addr, (void));
XX+ _PROTOTYPE(void garbage, (void));
XX+ _PROTOTYPE(void  level1, (void));
XX+ _PROTOTYPE(void level2, (void));
XX+ _PROTOTYPE(void dolev, (void));
XX+ _PROTOTYPE(void catch, (int s));
XX+ _PROTOTYPE(void hard, (void));
XX+ _PROTOTYPE(void e, (int n));
XX+ _PROTOTYPE(void cleanup, (void));
XX+ _PROTOTYPE(void quit, (void));
XX  
XX  
XX! int main(argc, argv)
XX! int argc;
XX! char *argv[];
XX  {
XX    jmp_buf envm;
XX    int j;
XX  
XX+   int i, m = 0xFFFF;
XX+ 
XX+   sync();
XX+ 
XX+   if (argc == 2) m = atoi(argv[1]);
XX+ 
XX    printf("Test  9 ");
XX+   fflush(stdout);
XX+ 
XX+   system("rm -rf DIR_09; mkdir DIR_09");
XX+   chdir("DIR_09");
XX+ 
XX    for (j = 0; j < 100; j++) {
XX! 	if (m & 00001) test9a();
XX! 	if (m & 00002) test9b();
XX! 	if (m & 00004) test9c();
XX! 	if (m & 00010) test9d();
XX! 	if (m & 00020) test9e();
XX! 	if (m & 00040) test9f();
XX    }
XX    if (nerrors) {
XX  	printf("%d errors detected\n", nerrors);
XX+ 	cleanup();
XX  	exit(nerrors);
XX    }
XX    i = 1;
XX***************
XX*** 43,73 ****
XX  		/* Correct */
XX  	} else if (i == 1) {
XX  		printf("WARNING: The setjmp/longjmp of this machine restore register variables\n\
XX! to the value they had at the time of the \"setjmp\"\n");
XX  	} else {
XX  		printf("Aha, I just found one last error\n");
XX  		return 1;
XX  	}
XX    }
XX!   printf("ok\n");
XX  }
XX  
XX  
XX! test1()
XX  {
XX    register p;
XX  
XX!   whichtest = 1;
XX    p = 200;
XX    garbage();
XX    if (p != 200) e(1);
XX  }
XX  
XX! test2()
XX  {
XX    register p, q;
XX  
XX!   whichtest = 2;
XX    p = 200;
XX    q = 300;
XX    garbage();
XX--- 76,107 ----
XX  		/* Correct */
XX  	} else if (i == 1) {
XX  		printf("WARNING: The setjmp/longjmp of this machine restore register variables\n\
XX! to the value they had at the time of the Setjmp\n");
XX  	} else {
XX  		printf("Aha, I just found one last error\n");
XX  		return 1;
XX  	}
XX    }
XX!   quit();
XX!   return(-1);			/* impossible */
XX  }
XX  
XX  
XX! void test9a()
XX  {
XX    register p;
XX  
XX!   subtest = 1;
XX    p = 200;
XX    garbage();
XX    if (p != 200) e(1);
XX  }
XX  
XX! void test9b()
XX  {
XX    register p, q;
XX  
XX!   subtest = 2;
XX    p = 200;
XX    q = 300;
XX    garbage();
XX***************
XX*** 75,85 ****
XX    if (q != 300) e(2);
XX  }
XX  
XX! test3()
XX  {
XX    register p, q, r;
XX  
XX!   whichtest = 3;
XX    p = 200;
XX    q = 300;
XX    r = 400;
XX--- 109,119 ----
XX    if (q != 300) e(2);
XX  }
XX  
XX! void test9c()
XX  {
XX    register p, q, r;
XX  
XX!   subtest = 3;
XX    p = 200;
XX    q = 300;
XX    r = 400;
XX***************
XX*** 91,111 ****
XX  
XX  char buf[512];
XX  
XX! test4()
XX  {
XX    register char *p;
XX  
XX!   whichtest = 4;
XX    p = &buf[100];
XX    garbage();
XX    if (p != &buf[100]) e(1);
XX  }
XX  
XX! test5()
XX  {
XX    register char *p, *q;
XX  
XX!   whichtest = 5;
XX    p = &buf[100];
XX    q = &buf[200];
XX    garbage();
XX--- 125,145 ----
XX  
XX  char buf[512];
XX  
XX! void test9d()
XX  {
XX    register char *p;
XX  
XX!   subtest = 4;
XX    p = &buf[100];
XX    garbage();
XX    if (p != &buf[100]) e(1);
XX  }
XX  
XX! void test9e()
XX  {
XX    register char *p, *q;
XX  
XX!   subtest = 5;
XX    p = &buf[100];
XX    q = &buf[200];
XX    garbage();
XX***************
XX*** 113,123 ****
XX    if (q != &buf[200]) e(2);
XX  }
XX  
XX! test6()
XX  {
XX    register char *p, *q, *r;
XX  
XX!   whichtest = 6;
XX    p = &buf[100];
XX    q = &buf[200];
XX    r = &buf[300];
XX--- 147,157 ----
XX    if (q != &buf[200]) e(2);
XX  }
XX  
XX! void test9f()
XX  {
XX    register char *p, *q, *r;
XX  
XX!   subtest = 6;
XX    p = &buf[100];
XX    q = &buf[200];
XX    r = &buf[300];
XX***************
XX*** 140,151 ****
XX    return &a;
XX  }
XX  
XX! garbage()
XX  {
XX    register i, j, k;
XX    register char *p, *q, *r;
XX    char *a;
XX-   int t;
XX  
XX    p = &buf[300];
XX    q = &buf[400];
XX--- 174,184 ----
XX    return &a;
XX  }
XX  
XX! void garbage()
XX  {
XX    register i, j, k;
XX    register char *p, *q, *r;
XX    char *a;
XX  
XX    p = &buf[300];
XX    q = &buf[400];
XX***************
XX*** 156,161 ****
XX--- 189,203 ----
XX    switch (setjmp(env)) {
XX        case 0:
XX  	a = addr();
XX+ #ifdef __GNUC__
XX+ 	/*
XX+ 	 * to defeat the smartness of the GNU C optimizer we pretend we
XX+ 	 * use 'a'. Otherwise the optimizer will not detect the looping
XX+ 	 * effectuated by setjmp/longjmp, so that it thinks it can get
XX+ 	 * rid of the assignment to 'a'.
XX+ 	 */
XX+ 	srand((unsigned)a);
XX+ #endif
XX  	longjmp(env, 1);
XX  	break;
XX        case 1:
XX***************
XX*** 206,212 ****
XX    e(200);
XX  }
XX  
XX! level1()
XX  {
XX    register char *p;
XX    register i;
XX--- 248,254 ----
XX    e(200);
XX  }
XX  
XX! void level1()
XX  {
XX    register char *p;
XX    register i;
XX***************
XX*** 218,224 ****
XX    longjmp(env, 2);
XX  }
XX  
XX! level2()
XX  {
XX    register char *p;
XX    register i;
XX--- 260,266 ----
XX    longjmp(env, 2);
XX  }
XX  
XX! void level2()
XX  {
XX    register char *p;
XX    register i;
XX***************
XX*** 229,235 ****
XX    dolev();
XX  }
XX  
XX! dolev()
XX  {
XX    register char *p;
XX    register i;
XX--- 271,277 ----
XX    dolev();
XX  }
XX  
XX! void dolev()
XX  {
XX    register char *p;
XX    register i;
XX***************
XX*** 240,251 ****
XX    longjmp(env, 3);
XX  }
XX  
XX! catch()
XX  {
XX    longjmp(env, 4);
XX  }
XX  
XX! hard()
XX  {
XX    register char *p;
XX  
XX--- 282,294 ----
XX    longjmp(env, 3);
XX  }
XX  
XX! void catch(s)
XX! int s;
XX  {
XX    longjmp(env, 4);
XX  }
XX  
XX! void hard()
XX  {
XX    register char *p;
XX  
XX***************
XX*** 254,269 ****
XX    kill(getpid(), SIGHUP);
XX  }
XX  
XX! e(n)
XX  int n;
XX  {
XX!   int err_num = errno;		/* save errno in case printf clobbers it */
XX! 
XX!   printf("Subtest %d,  error %d  errno=%d  ", subtest, n, errno);
XX!   errno = err_num;		/* restore errno, just in case */
XX!   perror("");
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX  	exit(1);
XX    }
XX  }
XX--- 297,328 ----
XX    kill(getpid(), SIGHUP);
XX  }
XX  
XX! void e(n)
XX  int n;
XX  {
XX!   printf("Subtest %d,  error %d  errno %d (%s)\n",
XX! 	 subtest, n, errno, strerror(errno));
XX    if (errct++ > MAX_ERROR) {
XX  	printf("Too many errors; test aborted\n");
XX+ 	cleanup();
XX+ 	exit(1);
XX+   }
XX+ }
XX+ 
XX+ void cleanup()
XX+ {
XX+   chdir("..");
XX+   system("rm -rf DIR*");
XX+ }
XX+ 
XX+ void quit()
XX+ {
XX+   cleanup();
XX+   if (errct == 0) {
XX+ 	printf("ok\n");
XX+ 	exit(0);
XX+   } else {
XX+ 	printf("%d errors\n", errct);
XX  	exit(1);
XX    }
XX  }
X/
/
