[comp.os.minix] Smaller files in Johan's list

ast@cs.vu.nl (Andy Tanenbaum) (10/06/88)

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'chgrp.c'
sed 's/^X//' > 'chgrp.c' << '+ END-OF-FILE ''chgrp.c'
X/* chgrp - change group		Authors: P. van Kleef and D. Spinellis */
X
X#include <grp.h>
X#include <minix/type.h>
X#include <sys/stat.h>
X#include <stdio.h>
X
Xmain (argc, argv)
Xint   argc;
Xchar *argv[];
X{
X	int     i,
X	status = 0;
X	struct group  *grp, *getgrnam ();
X	struct stat stbuf;
X
X	if (argc < 3) {
X		fprintf (stderr,"Usage: chgrp gid file ...\n");
X		exit (1);
X	}
X
X	if ((grp = getgrnam (argv[1])) == 0) {
X		fprintf (stderr,"Unknown group id: %s\n", argv[1]);
X		exit (4);
X	}
X
X	for (i = 2; i < argc; i++) {
X		if (stat (argv[i], &stbuf) < 0) {
X			perror (argv[i]);
X			status++;
X		}
X		else
X			if (chown (argv[i], stbuf.st_uid, grp -> gr_gid) < 0) {
X				fprintf (stderr,"%s: not changed\n", argv[i]);
X				status++;
X			}
X	}
X	exit (status);
X}
+ END-OF-FILE chgrp.c
chmod 'u=rw,g=r,o=r' 'chgrp.c'
set `wc -c 'chgrp.c'`
count=$1
case $count in
732)	:;;
*)	echo 'Bad character count in ''chgrp.c' >&2
		echo 'Count should be 732' >&2
esac
echo Extracting 'diskcheck.c'
sed 's/^X//' > 'diskcheck.c' << '+ END-OF-FILE ''diskcheck.c'
X/* diskcheck - test a disk for bad blocks	Author: Andy Tanenbaum */
X
X#include <signal.h>
X#include <fs/const.h>
X#include <minix/const.h>
X#include <errno.h>
X#undef printf
X#define PRINTFREQ  100
X#define N 30
X
Xchar purgebuf[BLOCK_SIZE * N];
Xchar buf[BLOCK_SIZE], zero[BLOCK_SIZE];
Xint pat1[BLOCK_SIZE/2], pat2[BLOCK_SIZE/2];
Xint blk = -1;			/* number of the block in buf, or -1 */
Xint pfd;			/* file descriptor for purging */
Xint fd;				/* file descriptor for data I/O */
Xunsigned initblock;		/* first block to test */
Xunsigned curblock;		/* current block */
Xunsigned limit;			/* first block beyond test zone */
Xunsigned errors;		/* # errors so far */
Xunsigned ct;			/* # blocks read so far */
Xint intflag;			/* set when signal seen */
Xextern errno;
Xlong lseek(), pos;
Xchar *purgefile = "/dev/ram";
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  unsigned b;
X  int i;
X  int catch();
X
X  signal(SIGINT, catch);
X  signal(SIGQUIT, catch);
X  if (argc != 4) usage();
X  if ( (fd = open(argv[1], 2)) < 0) {
X	printf("Cannot open %s\n",argv[1]);
X	exit(1);
X  }
X  if ( (pfd = open(purgefile, 2)) < 0) {
X	printf("Cannot open %s\n",purgefile);
X	exit(1);
X  }
X
X  initblock = atoi(argv[2]);
X  limit = initblock + atoi(argv[3]);
X  if (limit <= initblock) usage();
X
X  for (i = 0; i < BLOCK_SIZE/2; i++) {
X	pat1[i] = i;
X	pat2[i] = 1000 - i;
X  }
X
X    for (b = initblock; b < limit; b++) {
X	if (intflag) break;
X	if (testblock(b) == ERROR) {
X		errors++;
X		if (blk == b) {
X			/* Read ok, write failed; try to restore block. */
X			lseek(fd, pos, 0);
X			write(fd, buf, BLOCK_SIZE);
X		}
X	}
X	curblock = b;
X	ct++;
X	if (ct % PRINTFREQ == 0) status();
X  }
X		
X  status();
X  exit(0);
X}
X
X
Xint testblock(b)
Xunsigned b;
X{
X/* Read block b in, save it in buf.  Then overwrite that block with a
X * known test pattern and read it back.  Finally, replace the block.
X * Return OK or ERROR.
X */
X
X  int s;
X
X  blk = -1;
X  pos = (long) BLOCK_SIZE * (long) b;
X  purge_cache();
X  if (lseek(fd, pos, 0) != pos) fatal("Cannot seek to block ",b);
X
X  /* Read block b into 'buf'. */
X  s = read(fd, buf, BLOCK_SIZE);
X
X  /* Test for various outcomes of the read. */
X  if (s == BLOCK_SIZE) {
X	blk = b;
X	if (wtest(pos, pat1) == ERROR) return(ERROR);
X	if (wtest(pos, pat2) == ERROR) return(ERROR);
X	lseek(fd, pos, 0);
X	if (write(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) {
X		nonfatal("Cannot rewrite block ", b);
X		return(ERROR);
X	} else {
X		return(OK);
X	}
X  }
X  if (s < 0) {
X	if (errno == EIO) 
X		nonfatal("Read error on block ", b);
X	else {
X		printf("Error.  Read returned %d.  errno=%d.   ", s,errno);
X		fatal("Block ", b);
X	}
X	return(ERROR);
X  } 
X
X  if (s == 0) fatal("End of file reached trying to read block ", b);
X
X
X  nonfatal("Read size error on block ", b);
X}
X
Xstatus()
X{
X  printf("%5u blocks tested, %u errors detected (last block tested = %5u)\n",
X						ct,errors,curblock);
X}
X
Xnonfatal(s, b)
Xchar *s;
Xunsigned b;
X{
X  printf("%s%u\n",s,b);
X}
X
Xfatal(s, b)
Xchar *s;
Xunsigned b;
X{
X  printf("%s%u\n",s,b);
X  status();
X  exit(1);
X}
X
X
Xcatch()
X{
X  signal(SIGINT, catch);
X  signal(SIGQUIT, catch);
X  intflag = 1;
X}
X
X
Xusage()
X{
X  printf("Usage: diskcheck device start-block block-count\n");
X  exit(1);
X}
X
Xwtest(pos, pat)
Xlong pos;
Xint pat[];
X{
X  int testb[BLOCK_SIZE/2];
X  int i;
X
X  lseek(fd, pos, 0);
X  if (write(fd, pat, BLOCK_SIZE) != BLOCK_SIZE) return(ERROR);
X  sync();			/* force the write to the disk */
X  purge_cache();
X  lseek(fd, pos, 0);
X  if (read(fd, testb, BLOCK_SIZE) != BLOCK_SIZE) return(ERROR);
X  for (i = 0; i < BLOCK_SIZE/2; i++)
X	if (testb[i] != pat[i]) {printf("%d %d\n",testb[i],pat[i]);return(ERROR);}
X  return(OK);
X}
X
Xpurge_cache()
X{
X/* Do enough reads that the cache is purged. */
X
X  int left, count,r;
X
X  pfd = open(purgefile, 0);
X  left = NR_BUFS;
X  while (left > 0) {
X	count = (left < N ? left : N);
X	if ((r=read(pfd, purgebuf, count* BLOCK_SIZE)) != count * BLOCK_SIZE) {
X		printf("ERROR: count=%d  left=%d r=%d.  ",count, left,r);
X		fatal("Cannot purge cache.  errno= ", errno);
X	}
X	left -= count;
X  }
X  close(pfd);
X}
X
+ END-OF-FILE diskcheck.c
chmod 'u=rw,g=r,o=r' 'diskcheck.c'
set `wc -c 'diskcheck.c'`
count=$1
case $count in
3982)	:;;
*)	echo 'Bad character count in ''diskcheck.c' >&2
		echo 'Count should be 3982' >&2
esac
echo Extracting 'dp8390stat.h'
sed 's/^X//' > 'dp8390stat.h' << '+ END-OF-FILE ''dp8390stat.h'
X#ifdef DPSTAT
X/* statistics from dp8390 */
Xstruct dpstat {
X	long	ds_read;	/* packets read */
X	long	ds_written;	/* packets written */
X        long    ds_fram;	/* Input framing errors */
X        long    ds_crc;		/* Input CRC errors */
X	long	ds_lost;	/* Packets lost */
X	long	ds_btint;	/* Bogus transmit interrupts */
X	long	ds_deferred;	/* Deferred packets */
X	long	ds_collisions;	/* Packets collided at least once */
X	long	ds_xcollisions;	/* Aborts due to excessive collisions */
X	long	ds_carlost;	/* Carrier sense lost */
X	long	ds_fifo;	/* Fifo underrun */
X	long	ds_heartbeat;	/* Heart beat failure */
X	long	ds_lcol;	/* Late collisions */
X};
X#define STINC(x) dpstat.x++
X#define STADD(x,y) dpstat.x += y
X#else
X#define STINC(x)        /* nothing */
X#define STADD(x,y)      /* nothing */
X#endif DPSTAT
+ END-OF-FILE dp8390stat.h
chmod 'u=rw,g=r,o=r' 'dp8390stat.h'
set `wc -c 'dp8390stat.h'`
count=$1
case $count in
821)	:;;
*)	echo 'Bad character count in ''dp8390stat.h' >&2
		echo 'Count should be 821' >&2
esac
echo Extracting 'master.c'
sed 's/^X//' > 'master.c' << '+ END-OF-FILE ''master.c'
X#include <signal.h>
X
Xchar console[] = "/dev/console";
X
Xrun(uid, gid, argv)
Xchar **argv;
X{
X
X	for (;;)
X		switch (fork()) {
X		default:
X			return;
X		case 0:
X			if (setgid(gid) < 0) perror("can't set gid");
X			if (setuid(uid) < 0) perror("can't set uid");
X/*
X			execvp(*argv, argv);
X*/
X			execv(*argv, argv);
X			perror("master: exec'ing");
X			prints("can't execute %s\n", *argv);
X/*
X			kill(getppid(), SIGTERM);
X*/
X			/* If the exec failed, don't try it again immediately.
X			 * Give the kernel a chance to do something else.
X			 */
X			sleep (5);
X			_exit(1);
X		case -1:
X			sleep(10);
X		}
X}
X
Xmain(argc, argv)
Xchar **argv;
X{
X  register n, uid, gid;
X
X  /* Minix can't do this
X	setpgrp(getpid(), getpid());
X  */
X	if (argc < 4) {
X		prints("Usage: master # uid gid command args ...\n");
X		return(1);
X	}
X	n = atoi(argv[1]);
X	if (n < 1 || n > 20) {
X		prints("Bad count.\n");
X		return(1);
X	}
X	signal(SIGHUP, SIG_IGN);
X	signal(SIGINT, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X
X/* Put the program into the background. */
X	switch (fork()) {
X	case 0:
X		break;
X	case -1:
X		perror(argv[0]);
X		return 1;
X	default:
X		return 0;
X	}
X	uid = atoi(argv[2]);
X	gid = atoi(argv[3]);
X
X/* Start n copies of the program. */
X	do
X		run(uid, gid, &argv[4]);
X	while (--n);
X
X/* Replace each one that dies. */
X	while (wait((int *) 0) > 0)
X		run(uid, gid, &argv[4]);
X	return(0);
X}
+ END-OF-FILE master.c
chmod 'u=rw,g=r,o=r' 'master.c'
set `wc -c 'master.c'`
count=$1
case $count in
1337)	:;;
*)	echo 'Bad character count in ''master.c' >&2
		echo 'Count should be 1337' >&2
esac
echo Extracting 'paste.c'
sed 's/^X//' > 'paste.c' << '+ END-OF-FILE ''paste.c'
X/* paste - laminate files		Author: David Ihnat */
X
X/*
X * paste - a recreation of the Unix(Tm) paste(1) command.
X *
X * syntax:	paste file1 file2 ...
X *		paste -dLIST file1 file2 ...
X *		paste -s [-dLIST] file1 file2 ...
X *
X *	Copyright (C) 1984 by David M. Ihnat
X *
X * This program is a total rewrite of the Bell Laboratories Unix(Tm)
X * command of the same name, as of System V.  It contains no proprietary
X * code, and therefore may be used without violation of any proprietary
X * agreements whatsoever.  However, you will notice that the program is
X * copyrighted by me.  This is to assure the program does *not* fall
X * into the public domain.  Thus, I may specify just what I am now:
X * This program may be freely copied and distributed, provided this notice
X * remains; it may not be sold for profit without express written consent of
X * the author.
X * Please note that I recreated the behavior of the Unix(Tm) 'paste' command
X * as faithfully as possible, with minor exceptions (noted below); however,
X * I haven't run a full set of regression * tests.  Thus, the user of
X * this program accepts full responsibility for any effects or loss;
X * in particular, the author is not responsible for any losses,
X * explicit or incidental, that may be incurred through use of this program.
X *
X * The changes to the program, with one exception, are transparent to
X * a user familiar with the Unix command of the same name.  These changes
X * are:
X *
X * 1) The '-s' option had a bug in the Unix version when used with multiple
X *    files.  (It would repeat each file in a list, i.e., for
X *    'paste -s file1 file2 file3', it would list
X *    <file1\n><file1\n><file2\n><file1\n><file2\n><file3\n>
X *    I fixed this, and reported the bug to the providers of the command in
X *    Unix.
X *
X * 2) The list of valid escape sequences has been expanded to include
X *    \b,\f, and \r.  (Just because *I* can't imagine why you'd want
X *    to use them doesn't mean I should keep them from you.)
X *
X * 3) There is no longer any restriction on line length.
X *
X * I ask that any bugs (and, if possible, fixes) be reported to me when
X * possible.  -David Ihnat (312) 784-4544 ihuxx!ignatz
X */
X
X/* Modified to run under MINIX 1.1
X * by David O. Tinker  (416) 978-3636 (utgpu!dtinker)
X * Sept. 19, 1987
X */
X
X#include <stdio.h>
X#include <errno.h>  /* make sure errno.h is available */
X#include <ctype.h>  /* make sure ctype.h is available */
X
Xextern int errno;
X
X#define MINIX   /* as opposed to C86, or AZTEC in my case */
X		/* just in case I want to compile under DOS sometime */
X
X#undef toupper
X
X/* I'd love to use enums, but not everyone has them.  Portability, y'know. */
X#define NODELIM		1
X#define USAGE		2
X#define BADFILE		3
X#define TOOMANY		4
X
X#define	TAB		'\t'
X#define	NL		'\n'
X#define	BS		'\b'
X#define	FF		'\f'
X#define	CR		'\r'
X#define DEL             '\177'
X
X#define	_MAXSZ		512
X#define _MAXFILES	12
X#define	CLOSED		((FILE *)-1)
X#define ENDLIST		((FILE *)-2)
X
Xchar *cmdnam, toupper();
X
X
Xshort int dflag,sflag;
Xchar delims[] = { TAB };
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X	char *strcpy();
X
X	dflag = sflag = 0;
X
X	cmdnam = *argv;
X
X  if(argc >= 2) {
X
X	/* Skip invocation name */
X	argv++;
X	argc--;
X
X	/* First, parse input options */
X
X	while(argv[0][0] == '-' && argv[0][1] != '\0')
X	{
X		switch(toupper(argv[0][1]))
X		{
X			case 'D':
X				/* Delimiter character(s) */
X				strcpy(delims,&argv[0][2]);
X				if(*delims == '\0')
X					prerr(NODELIM,"");
X				else
X					delimbuild(delims);
X
X				break;
X
X			case 'S':
X				sflag++;
X				break;
X
X			default:
X				prerr(USAGE,"");
X		}
X		argv++;
X		argc--;
X	}
X  }
X
X  else
X        prerr(USAGE,"");
X
X	/*
X	 * If no files specified, simply exit.  Otherwise,
X	 * if not the old '-s' option, process all files.
X	 * If '-s', then process files one-at-a-time.
X	 */
X	if(!sflag)
X		docol(argc,argv); /* Column paste */
X	else
X		doserial(argc,argv);	/* Serial paste */
X
X        _cleanup();
X        exit(0);
X} 
X
Xdocol(nfiles,fnamptr)
Xint nfiles;
Xchar **fnamptr;
X{
X	char iobuff[_MAXSZ];	/* i/o buffer for the fgets */
X	short int somedone;	/* flag for blank field handling */
X
X	/*
X	 * There is a strange case where all files are just ready to
X	 * be closed, or will on this round.  In that case, the string
X	 * of delimiters must be preserved.  delbuf[1] ->delbuf[MAXFILES+1]
X	 * provides intermediate storage for closed files, if needed;
X	 * delbuf[0] is the current index.
X	 */
X	char delbuf[_MAXFILES+2];
X
X	FILE *fileptr[_MAXFILES+1];
X	FILE *fopen();
X
X	char *fgets();
X
X	int filecnt;			/* Set to number of files to process */
X	register char *delimptr;	/* Cycling delimiter pointer */
X	int index;			/* Working variable */
X	int strend;			/* End of string in buffer */
X
X	/*
X	 * Perform column paste.  First, attempt to open all
X	 * files. (This could be expanded to an infinite number of files,
X	 * but at the (considerable) expense of remembering the file and
X	 * its current offset, then opening/reading/closing.  The
X	 * commands' utility doesn't warrant the effort; at least, to me...)
X	 */
X
X	for(filecnt=0;(nfiles>0) && (filecnt<_MAXFILES);filecnt++,nfiles--,fnamptr++)
X	{
X		if(fnamptr[0][0] == '-')
X			fileptr[filecnt] = stdin;
X		else
X		{
X			fileptr[filecnt] = fopen(*fnamptr,"r");
X			if(fileptr[filecnt] == NULL)
X				prerr(BADFILE,*fnamptr);
X		}
X	}
X
X	fileptr[filecnt] = ENDLIST;	/* End of list. */
X
X	if(nfiles)
X		prerr(TOOMANY,"");
X
X	/*
X	 * Have all files.  Now, read a line from each file, and output
X	 * to stdout.  Notice that the old 511 character limitation on
X	 * the line length no longer applies, since this program doesn't
X	 * do the buffering.  Do this until you go through the loop and
X	 * don't successfully read from any of the files.
X	 */
X	for(;filecnt;)
X	{
X		somedone = 0;		/* Blank field handling flag */
X		delimptr = delims;	/* Start at beginning of delim list */
X		delbuf[0] = 0;		/* No squirreled delims */
X
X		for(index = 0;(fileptr[index] != ENDLIST) && filecnt; index++)
X		{
X			/* Read a line and immediately output.
X			 * If it's too big for the buffer, then dump what was
X			 * read and go back for more.
X			 *
X			 * Otherwise, if it is from the last file, then leave
X			 * the carriage return in place; if not, replace with
X			 * a delimiter (if any)
X			 */
X
X			strend = 0;	/* Set so can easily detect EOF */
X
X			if(fileptr[index] != CLOSED)
X
X				while(fgets(iobuff,(_MAXSZ-1),fileptr[index]) != (char *)NULL)
X				{
X					strend = strlen(iobuff);	/* Did the buffer fill? */
X
X					if(strend == (_MAXSZ-1))
X					{
X						/* Gosh, what a long line. */
X						fputs(iobuff,stdout);
X						strend = 0;
X						continue;
X					}
X
X					/* Ok got whole line in buffer. */
X					break;	/* Out of loop for this file */
X				}
X
X			/* Ended either on an EOF (well, actually NULL return--
X			 * it *could* be some sort of file error, but
X			 * but if the file was opened successfully, this is
X			 * unlikely. Besides, error checking on streams
X			 * doesn't allow us to decide exactly what went
X			 * wrong, so I'm going to be very Unix-like and ignore
X			 * it!), or a closed file, or a received line.
X			 * If an EOF, close the file and mark it in the
X			 * list.  In any case, output the delimiter of choice.
X			 */
X
X			if(!strend)
X			{
X				if(fileptr[index] != CLOSED)
X				{
X					fclose(fileptr[index]);
X					fileptr[index] = CLOSED;
X					filecnt--;
X				}
X
X				/* Is this the end of the whole thing? */
X				if((fileptr[index+1] == ENDLIST) && !somedone)
X					continue; /* EXITS */
X
X				/* Ok, some files not closed this line. Last file? */
X				if(fileptr[index+1] == ENDLIST)
X				{
X					if(delbuf[0])
X					{
X						fputs(&delbuf[1],stdout);
X						delbuf[0] = 0;
X					}
X					putc((int)NL,stdout);
X					continue;	/* Next read of files */
X				}else
X				{
X					/* Closed file; setup delim */
X					if(*delimptr != DEL)
X					{
X						delbuf[0]++;
X						delbuf[delbuf[0]] = *delimptr++;
X						delbuf[delbuf[0]+1] = '\0';
X					}else
X						delimptr++;
X				}
X
X				/* Reset end of delimiter string if necessary */
X				if(*delimptr == '\0')
X					delimptr = delims;
X			}else
X			{
X				/* Some data read. */
X				somedone++;
X
X				/* Any saved delims? */
X				if(delbuf[0])
X				{
X					fputs(&delbuf[1],stdout);
X					delbuf[0] = 0;
X				}
X
X				/* If last file, last char will be NL. */
X				if(fileptr[index+1] != ENDLIST)
X				{
X					if(*delimptr == DEL)
X					{
X						delimptr++;
X						iobuff[strend-1] = '\0'; /* No delim */
X					}else
X						iobuff[strend-1] = *delimptr++;
X				}
X
X				if(*delimptr == '\0')
X					delimptr = delims;
X
X				/* Now dump the buffer */
X				fputs(iobuff,stdout);
X				_cleanup();
X			}
X		}
X	}
X}
X
Xdoserial(nfiles,fnamptr)
Xint nfiles;
Xchar **fnamptr;
X{
X	/*
X	 * Do serial paste.  Simply scarf characters, performing
X	 * one-character buffering to facilitate delim processing.
X	 */
X	
X	register int charnew,charold;
X	register char *delimptr;
X
X	register FILE *fileptr;
X	FILE *fopen();
X
X	for(;nfiles;nfiles--,fnamptr++)
X	{
X		if(fnamptr[0][0] == '-')
X			fileptr = stdin;
X		else
X		{
X			fileptr = fopen(*fnamptr,"r");
X
X			if(fileptr == NULL)
X				prerr(BADFILE,*fnamptr);
X		}
X
X		/*
X		 * The file is open; just keep taking characters,
X		 * stashing them in charnew; output charold, converting to
X		 * the appropriate delimiter character if needful.  After the
X		 * EOF, simply output 'charold' if it's a newline; otherwise,
X		 * output it and then a newline.
X		 */
X
X		delimptr = delims;	/* Set up for delimiter string */
X
X		if((charold = getc(fileptr)) == EOF)
X		{
X			/* Empty file! */
X			putc(NL,stdout);
X			_cleanup();
X			continue;	/* Go on to the next file */
X		}
X
X		/* Ok, 'charold' is set up.  Hit it! */
X
X		while((charnew = getc(fileptr)) != EOF)
X		{
X			/* Ok, process the old character */
X			if(charold == NL)
X			{
X				if(*delimptr != DEL)
X					putc(*delimptr++,stdout);
X
X				/* Reset pointer at end of delimiter string */
X				if(*delimptr == '\0')
X					delimptr = delims;
X			} else
X				putc((char)charold,stdout);
X			
X			charold = charnew;
X		}
X
X		/* Ok, hit EOF.  Process that last character */
X
X		putc((char)charold,stdout);
X		_cleanup();
X
X		if((char)charold != NL)
X			putc(NL,stdout);
X	}
X}
X
Xdelimbuild(strptr)
Xchar *strptr;
X{
X	/*
X	 * Process the delimiter string into something that can be
X	 * used by the routines.  This involves, primarily, collapsing
X	 * the backslash representations of special characters into
X	 * their actual values, and terminating the string in a manner
X	 * that the routines can recognize.  The set of possible backslash
X	 * characters has been expanded beyond that recognized by the
X	 * vanilla Unix(Tm) version.
X	 */
X
X	register char *strout;
X
X	strout = strptr;	/* Start at the same place, anyway */
X
X	while(*strptr)
X	{
X		if(*strptr != '\\')	/* Is it an escape character? */
X			*strout++ = *strptr++;	/* No, just transfer it */
X		else
X		{
X			strptr++;	/* Get past escape character */
X
X			switch(toupper(*strptr))
X			{
X				case '0':
X					*strout++ = DEL;
X					break;
X
X				case 'T':
X					*strout++ = TAB;
X					break;
X
X				case 'N':
X					*strout++ = NL;
X					break;
X
X				case 'B':
X					*strout++ = BS;
X					break;
X
X				case 'F':
X					*strout++ = FF;
X					break;
X
X				case 'R':
X					*strout++ = CR;
X					break;
X
X				default:
X					*strout++ = *strptr;
X			}
X			
X			strptr++;
X		}
X
X	}
X	*strout = '\0';	/* Heaven forfend that we forget this! */
X}
X
Xprerr(etype, estring)
Xint etype;
Xchar *estring;
X{
X	switch(etype)
X	{
X		case USAGE:
X			fprintf(stderr,"%s : Usage: %s [-s] [-d<delimiter>] file1 file2 ...\n",cmdnam,cmdnam);
X			break;
X
X		case NODELIM:
X			fprintf(stderr,"%s : no delimiters\n",cmdnam);
X			break;
X
X		case BADFILE:
X			fprintf(stderr,"%s : %s : cannot open\n",cmdnam,estring);
X			break;
X		
X		case TOOMANY:
X			fprintf(stderr,"%s : too many files\n",cmdnam);
X			break;
X	}
X	_cleanup();
X	exit(1);
X}
X
Xchar toupper(c)			/* This is non-standard, but it works */
Xchar c;
X{
X   char x;
X
X   if (isalpha(c)) {
X      if (c > 'Z') x = (c - ' ');
X      else x = c;
X   }
X   else {
X      if (isdigit(c))
X      	x = c;
X      else x = '\0';		/* this will terminate a string
X				 * at any character other than a
X				 * letter or numeral.            */ 
X   }
X   return (x);
X}
+ END-OF-FILE paste.c
chmod 'u=rw,g=r,o=r' 'paste.c'
set `wc -c 'paste.c'`
count=$1
case $count in
12000)	:;;
*)	echo 'Bad character count in ''paste.c' >&2
		echo 'Count should be 12000' >&2
esac
echo Extracting 'pwd.c'
sed 's/^X//' > 'pwd.c' << '+ END-OF-FILE ''pwd.c'
X/* pwd - print working directory		Author: Adri Koppes */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X
Xmain()
X{
X	register int fd;
X	register char *n;
X	char name[128];
X	char *last_index();
X	struct stat s, st, sk;
X	struct direct d;
X
X	*name = 0;
X	stat(".", &s);
X	do {
X		if ((fd = open("..",0)) < 0) {
X			prints("Can't open ..\n");
X			exit(1);
X		}
X		st.st_dev = s.st_dev;
X		st.st_ino = s.st_ino;
X		st.st_mode = s.st_mode;
X		st.st_nlink = s.st_nlink;
X		st.st_uid = s.st_uid;
X		st.st_gid = s.st_gid;
X		st.st_rdev = s.st_rdev;
X		st.st_size = s.st_size;
X		st.st_atime = s.st_atime;
X		st.st_mtime = s.st_mtime;
X		st.st_ctime = s.st_ctime;
X		stat("..", &s);
X		chdir("..");
X		if (s.st_dev == st.st_dev)
X			do
X				if (read(fd, (char *)&d, sizeof(struct direct)) < sizeof(struct direct)) {
X					prints("Can't read ..\n");
X					exit(1);
X				}
X			while(d.d_ino != st.st_ino);
X		else
X			do {
X				if (read(fd, (char *)&d, sizeof(struct direct)) < sizeof(struct direct)) {
X					prints("Can't read ..\n");
X					exit(1);
X				}
X				stat(d.d_name, &sk);
X			} while ((sk.st_dev != st.st_dev) || (sk.st_ino != st.st_ino));
X		close(fd);
X		if (strcmp(".",d.d_name)) {
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)
X		prints("/");
X	else
X		while (n = last_index(name, '/')) {
X			*(n+14) = 0;
X			prints(n);
X			*n = 0;
X		}
X	prints(name);
X	prints("\n");
X	exit(0);
X}
X
X
Xchar   *
Xlast_index (string, ch)
Xregister char  *string;
Xregister char   ch;
X{
X    register char  *retval = 0;
X
X    for (; *string; *string++)
X	if (*string == ch)
X	    retval = string;
X    return (retval);
X}
+ END-OF-FILE pwd.c
chmod 'u=rw,g=r,o=r' 'pwd.c'
set `wc -c 'pwd.c'`
count=$1
case $count in
1646)	:;;
*)	echo 'Bad character count in ''pwd.c' >&2
		echo 'Count should be 1646' >&2
esac
echo Extracting 'sgtty.h'
sed 's/^X//' > 'sgtty.h' << '+ END-OF-FILE ''sgtty.h'
X/* Data structures for IOCTL. */
X
Xstruct sgttyb {
X  char sg_ispeed;		/* input speed */
X  char sg_ospeed;		/* output speed */
X  char sg_erase;		/* erase character */
X  char sg_kill;			/* kill character */
X  int  sg_flags;		/* mode flags */
X};
X
Xstruct tchars {
X  char t_intrc;			/* SIGINT char */
X  char t_quitc;			/* SIGQUIT char */
X  char t_startc;		/* start output (initially CTRL-Q) */
X  char t_stopc;			/* stop output	(initially CTRL-S) */
X  char t_eofc;			/* EOF (initially CTRL-D) */
X  char t_brkc;			/* input delimiter (like nl) */
X};
X
X/* Field names */
X#define XTABS	     0006000	/* do tab expansion */
X#define BITS8        0001400	/* 8 bits/char */
X#define BITS7        0001000	/* 7 bits/char */
X#define BITS6        0000400	/* 6 bits/char */
X#define BITS5        0000000	/* 5 bits/char */
X#define EVENP        0000200	/* even parity */
X#define ODDP         0000100	/* odd parity */
X#define RAW	     0000040	/* enable raw mode */
X#define CRMOD	     0000020	/* map lf to cr + lf */
X#define ECHO	     0000010	/* echo input */
X#define CBREAK	     0000002	/* enable cbreak mode */
X#define COOKED       0000000	/* neither CBREAK nor RAW */
X
X/* Line speeds */
X#define B110		   1
X#define B300		   3
X#define B1200		  12
X#define B2400		  24
X#define B4800		  48
X#define B9600 		  96
X
X#define TIOCGETP (('t'<<8) | 8)
X#define TIOCSETP (('t'<<8) | 9)
X#define TIOCGETC (('t'<<8) | 18)
X#define TIOCSETC (('t'<<8) | 17)
+ END-OF-FILE sgtty.h
chmod 'u=rw,g=r,o=r' 'sgtty.h'
set `wc -c 'sgtty.h'`
count=$1
case $count in
1412)	:;;
*)	echo 'Bad character count in ''sgtty.h' >&2
		echo 'Count should be 1412' >&2
esac
echo Extracting 'signal.c'
sed 's/^X//' > 'signal.c' << '+ END-OF-FILE ''signal.c'
X#include "lib.h"
X#include <signal.h>
X
Xint (*vectab[NSIG])();	/* array of functions to catch signals */
X
X/* The definition of signal really should be 
X *  PUBLIC int (*signal(signr, func))()
X * but some compilers refuse to accept this, even though it is correct.
X * The only thing to do if you are stuck with such a defective compiler is
X * change it to
X *  PUBLIC int *signal(signr, func)
X * and change ../h/signal.h accordingly.
X */
X
XPUBLIC int (*signal(signr, func))()
Xint signr;			/* which signal is being set */
Xint (*func)();			/* pointer to function that catches signal */
X{
X  int r,(*old)();
X
X  old = vectab[signr - 1];
X  vectab[signr - 1] = func;
X  M.m6_i1 = signr;
X  M.m6_f1 = ( (func == SIG_IGN || func == SIG_DFL) ? func : begsig);
X  r = callx(MM, SIGNAL);
X  if (r == 1) old = SIG_IGN;
X  return( (r < 0 ? (int (*)()) r : old) );
X}
+ END-OF-FILE signal.c
chmod 'u=rw,g=r,o=r' 'signal.c'
set `wc -c 'signal.c'`
count=$1
case $count in
842)	:;;
*)	echo 'Bad character count in ''signal.c' >&2
		echo 'Count should be 842' >&2
esac
echo Extracting 'strings.c'
sed 's/^X//' > 'strings.c' << '+ END-OF-FILE ''strings.c'
X/* strings - print ASCII strings in a file	Author: Peter S. Housel */
X
X/*
X	This is a version of the BSD "strings" program for Minix. It is used
Xto search a file for printable strings. To install,
X
X	cc -o strings strings.c
X	chmem =8000 strings
X
XCommand:  strings - search file for printable strings
XSyntax:	  strings [-] [-o] [-len] file ...
XFlags:	  -	Search the entire file. If this option is not given, only
X		the initialized data segment of files that appear to be
X		"a.out" format is searched.
X	  -o	Print the offset (in octal) with each string.
X	  -len	Use "len" as the minimum string length. The default is 4.
XExamples: strings core
X	  strings -o a.out > str
X
XStrings searches the specified file(s) for printable ASCII strings (four
Xor more printable characters followed by a newline or a null) and writes
Xthem to the standard output. This can be used to find out, for example, to
Xfind out what program a "core" file came from, what kinds of error messages
Xare in an executable, or to see ASCII data hidden in a "binary" data file.
X
XP.S. The program doesn't use the "a.out.h" file posted last week by
XDick van Veen, both because it was written before then, and because
Xnot everybody has a.out.h yet. Future revisions probably ought to, though.
X
X*/
X
X
X
X#include <stdio.h>
X#include <ctype.h>
X
X/* Minix (8086 version) dependant definitions */
X#define SMALLMAGIC	0x04100301L	/* small model a.out magic number */
X#define SEPARATEMAGIC	0x04200301L	/* separate instruction/data a.out */
X
X#define HDR_MAGIC	0		/* 0'th long  magic number */
X#define HDR_HSIZE	1		/* 1'st long  size of header */
X#define HDR_TSIZE	2		/* 2'nd long  size of text */
X#define HDR_DSIZE	3		/* 3'rd long  size of init'ed data */
X#define HDR_BSIZE	4		/* 4'th long  size of bss */
X#define HDR_TOTMEM	6		/* 6'th long  total memory */
X
X#define HDR_LEN		8		/* total length of header */
X
X/* miscellaneous definitions */
X#define	STRLEN		4		/* default minimum string length */
X#define STRBUF		512		/* buffer length for strings */
X
Xvoid strings(), usage();
X
Xint strmin = STRLEN;			/* minimum string length */
Xint printoff = 0;			/* print octal offset of each str */
Xint objall = 0;				/* search entire a.out file, not */
X					/* just initialized data segment */
X
Xmain(argc, argv)
Xint argc; char *argv[];
X{
X while((++argv, --argc) && '-' == (*argv)[0])
X      {
X       if(!strcmp(*argv, "-"))
X	  ++objall;
X       else if(!strcmp(*argv, "-o"))
X	  ++printoff;
X       else if(isdigit((*argv)[1]))
X	  strmin = atoi(&(*argv)[1]);
X       else
X	  usage();
X      } 
X
X if(0 == argc)
X    usage();
X
X while(argc--)
X       strings(*argv++);
X
X exit(0);
X}
X
Xvoid strings(filename)
Xchar *filename;
X{
X char buf[STRBUF];	/* the strings buffer */
X char *bufptr;		/* pointer into the strings buffer */ 
X FILE *input;		/* input file */
X long header[HDR_LEN];	/* buffer for reading the header */
X long offset;		/* file offset */
X long limit;		/* limit, if doing data segment only */
X int c;			/* input character */
X
X
X extern FILE *fopen();
X extern int fread();
X
X if(NULL == (input = fopen(filename, "r")))
X   {
X    fprintf(stderr, "strings: ");
X    perror(filename);
X    exit(1);
X   }
X
X if(HDR_LEN == fread(header, sizeof(long), HDR_LEN, input)
X    && (SMALLMAGIC == header[HDR_MAGIC]
X	|| SEPARATEMAGIC == header[HDR_MAGIC]) && !objall)
X   {
X    offset = header[HDR_HSIZE] + header[HDR_TSIZE]; /* object file */
X    limit = offset + header[HDR_DSIZE];
X   }
X else
X   {
X    offset = 0L;
X    limit = 0L;
X   }
X
X fseek(input, offset, 0);
X bufptr = buf;
X
X while(!limit || offset < limit)
X      {
X       if(EOF == (c = getc(input)))
X          break;
X       if((('\0' == c || '\n' == c) && bufptr - buf >= strmin)
X	  || (bufptr - buf == STRBUF - 1))
X         {
X	  *bufptr = '\0';
X	  if(printoff)
X             printf("%O:", offset - (bufptr - buf));
X	  puts(buf);
X	  bufptr = buf;
X	 }
X       else if((' ' <= c && c < 0177) || '\t' == c)
X	  *bufptr++ = c;
X       else
X	  bufptr = buf;
X
X       ++offset;
X      }
X
X fclose(input);  
X}
X
Xvoid usage()
X{
X fprintf(stderr, "usage: strings [-] [-o] [-num] file ...\n");
X exit(1);
X}
X
X
+ END-OF-FILE strings.c
chmod 'u=rw,g=r,o=r' 'strings.c'
set `wc -c 'strings.c'`
count=$1
case $count in
4052)	:;;
*)	echo 'Bad character count in ''strings.c' >&2
		echo 'Count should be 4052' >&2
esac
echo Extracting 'test0.c'
sed 's/^X//' > 'test0.c' << '+ END-OF-FILE ''test0.c'
X#include <sys/stat.h>
X
Xextern int errno;
Xint errct;
Xint testnr;
Xextern long lseek();
X
X
X#define NB          30L
Xmain()
X{
X  int i;
X  char let;
X
X  printf("Test  0 ");
X  for (i = 0; i < 4; i++) {
X	test00();
X	test01();
X  }
X  if (errct == 0)
X	printf("ok\n");
X  else
X	printf(" %d errors\n", errct);
X}
X
X
X
X
X
X
Xchar aa[100];
Xchar b[4] = {0,1,2,3}, c[4] = {10,20,30,40}, d[4] = {6,7,8,9};
Xlong t1;
X
Xtest00()
X{
X /* Test program for open(), close(), creat(), read(), write(), lseek(). */
X  int i, n, n1, n2;
X  long t, time(), abuf[4];
X  struct stat s;
X
X
X  testnr = 1;
X  if ((n = creat("foop", 0777)) != 3) {
X	printf("Creating a file returned file descriptor %d instead of 3\n",n);
X	e(1);
X  }
X  if ((n1 = creat("foop", 0777)) != 4) e(2);
X  if ((n2 = creat("/", 0777)) != -1) e(3);
X  if (close(n) != 0) e(4);
X  if ((n = open("foop", 0)) != 3) e(5);
X  if ((n2 = open("nofile", 0)) != -1) e(6);
X  if (close(n1) != 0) e(7);
X
X  /* n is the only one open now. */
X  for (i = 0; i < 2; i++) {
X	n1 = creat("File2", 0777);
X	if (n1 != 4) {printf("creat yielded fd=%d, expected 4\n",n1); e(8);}
X	if ((n2 = open("File2", 0)) != 5) e(9);
X	if (close(n1) != 0) e(10);
X	if (close(n2) != 0) e(11);
X  }
X  unlink("File2");
X  if (close(n) != 0) e(12);
X
X  /* All files closed now.*/
X  for (i = 0; i < 2; i++) {
X	t = 105L;
X	if ((n = creat("foop", 0777)) != 3) e(13);
X	if (close(n) != 0) e(14);
X	if ((n = open("foop", 2)) != 3) e(15);
X
X	/* read/write tests */
X	if (write(n, b, 4) != 4) e(16);
X	if (read(n, aa, 4) != 0) e(17);
X	if (lseek(n, 0L, 0) != 0L) e(18);
X	if (read(n, aa, 4) != 4) e(19);
X	if (aa[0] != 0 || aa[1] != 1 || aa[2] != 2 || aa[3] != 3) e(20);
X	if (lseek(n, 0L, 0) != 0L) e(21);
X	if (lseek(n, 2L, 1) != 2L) e(22);
X	if (read(n, aa, 4) != 2) e(23);
X	if (aa[0] != 2 || aa[1] != 3 || aa[2] != 2 || aa[3] != 3) e(24);
X	if (lseek(n, 2L, 0) != 2L) e(25);
X	clraa();
X	if (write(n, c, 4) != 4) e(26);
X	if (lseek(n, 0L, 0) != 0L) e(27);
X	if (read(n, aa, 10) != 6) e(28);
X	if (aa[0] != 0 || aa[1] != 1 || aa[2] != 10 || aa[3] != 20) e(29);
X	if (lseek(n, 16L, 0) != 16L) e(30);
X	if (lseek(n, 2040L, 2) != 2046L) e(31);
X	if (read(n, aa, 10) != 0) e(32);
X	if (lseek(n, 0L, 1) != 2046L) e(33);
X	clraa();
X	if (write(n, c, 4) != 4) e(34);
X	if (lseek(n, 0L, 1) != 2050L) e(35);
X	if (lseek(n, 2040L, 0) != 2040L) e(36);
X	clraa();
X	if (read(n, aa, 20) != 10) e(37);
X	if (aa[0] != 0 || aa[5] != 0 || aa[6] != 10 || aa[9] != 40) e(38);
X	if (lseek(n, 10239L, 0) != 10239L) e(39);
X	if (write(n, d, 2) != 2) e(40);
X	if (lseek(n, -2L, 2) != 10239L) e(41);
X	if (read(n, aa, 2) != 2) e(42);
X	if (aa[0] != 6 || aa[1] != 7) e(43);
X	if (lseek(n, NB*1024L-2L, 0) != NB*1024L-2L) e(44);
X	if (write(n, b, 4) != 4) e(45);
X	if (lseek(n, 0L, 0) != 0L) e(46);
X	if (lseek(n, -6L, 2) != 1024L*NB-4) e(47);
X	clraa();
X	if (read(n, aa, 100) != 6) e(48);
X	if (aa[0] != 0 || aa[1] != 0 || aa[3] != 1 || aa[4] != 2 
X					|| aa[5] != 3) e(49);
X	if (lseek(n, 20000L, 0) != 20000L) e(50);
X	if (write(n, c, 4) != 4) e(51);
X	if (lseek(n, -4L, 1) != 20000L ) e(52);
X	if (read(n, aa, 4) != 4) e(53);
X	if (aa[0] != 10 || aa[1] != 20 || aa[2] != 30 || aa[3] != 40) e(54);
X	if (close(n) != 0) e(55);
X	if ((n1 = creat("foop", 0777)) != 3) e(56);
X	if (close(n1) != 0) e(57);
X	unlink("foop");
X
X	/* Test clock. */
X/*  This test messes up the clock value
X	t = 20L;
X	stime(&t);
X	t = 0L;
X	t = time(&t);
X	if (t < 20L || t > 70L) e(59);
X	t = 200L;
X	if (stime(&t) < 0) e(60);
X	t = 0L;
X	if (time(&t) < 200L || time(&t) > 205L) e(61);
X	n1 = creat("timefile", 0777);
X	abuf[0] = 03003L;
X	abuf[1] = 03003L;
X	if (utime("timefile", abuf) < 0) e(62);
X	if (stat("timefile", &s) < 0) e(63);
X	if (s.st_atime != 03003) e(64);
X	abuf[0] = 06226;
X	abuf[1] = 06226;
X	if (utime("timefile", abuf) < 0) e(65);
X	if (stat("timefile", &s) < 0) e(66);
X	if (s.st_ctime != 06226) e(67);
X	if (unlink("timefile") < 0) e(68);
X	if (close(n1) < 0) e(69);
X	if (times(abuf) < 0) e(70);
X*/
X  }
X}
X
X
Xstatic clraa()
X{
X  int i;
X  for (i = 0; i < 100; i++) aa[i] = 0;
X}
X
X
Xtest01()
X{
X/* Test link, unlink, stat, fstat, dup, umask,
X * mknod.
X */
X
X  int i, j, n, n1, flag;
X  char a[255], b[255];
X  struct stat s, s1;
X
X  testnr = 2;
X  for (i=0; i < 2; i++) {
X	umask(0);
X
X	if ((n = creat("T3", 0702)) < 0) e(1);
X	if (link("T3", "newT3") < 0) e(2);
X	if ((n1 = open("newT3", 2)) < 0) e(3);
X	for (j = 0; j < 255; j++) a[j] = j;
X	if (write(n, a, 255) != 255) e(4);
X	if (read(n1, b, 255) != 255) e(5);
X	flag = 0;
X	for (j = 0; j < 255; j++) if (a[j] != b[j]) flag++;
X	if (flag) e(6);
X	if (unlink("T3") < 0) e(7);
X	if (close(n) <0) e(8);
X	if (close(n1) < 0) e(9);
X	if ((n1 = open("newT3", 0))  < 0) e(10);
X	if (read(n1, b, 255) != 255) e(11);
X	flag = 0;
X	for (j = 0; j < 255; j++) if (a[j] != b[j]) flag++;
X	if (flag) e(12);
X
X	/* Now check out stat, fstat. */
X	if (stat("newT3", &s) < 0) e(13);
X	if (s.st_mode != 0100702) e(14);
X	if (s.st_nlink != 1) e(15);
X	if (s.st_size != 255L) e(16);
X	if (fstat(n1, &s1) < 0) e(17);
X	if (s.st_dev != s1.st_dev) e(18);
X	if (s.st_ino != s1.st_ino) e(19);
X	if (s.st_mode != s1.st_mode) e(20);
X	if (s.st_nlink != s1.st_nlink) e(21);
X	if (s.st_uid != s1.st_uid) e(22);
X	if (s.st_gid != s1.st_gid) e(23);
X	if (s.st_rdev != s1.st_rdev) e(24);
X	if (s.st_size != s1.st_size) e(25);
X	if (s.st_atime != s1.st_atime) e(26);
X	if (close(n1) < 0) e(27);
X	if (unlink("newT3") < 0)e (28);
X
X	umask(040);
X	if ((n=creat("T3a", 0777)) < 0) e(29);
X	if (stat("T3a", &s) < 0) e(30);
X	if (s.st_mode != 0100737) e(31);
X	if (unlink("T3a") < 0) e(32);
X	if (close(n1) < 0) e(33);
X
X	/* dup */
X	if ((n=creat("T3b", 0777)) < 0) e(34);
X	if (close(n) < 0) e(35);
X	if ((n=open("T3b", 2)) < 0) e(36);
X	if ( (n1=dup(n)) != n+1) e(37);
X	if (write(n, a, 255) != 255) e(38);
X	read(n1, b, 20);
X	if (lseek(n, 0L, 0) != 0L) e(39);
X	if ((j=read(n1, b, 1024)) != 255) e(40);
X	if (unlink("T3b") < 0) e(41);
X	if (close(n) < 0) e(42);
X	if (close(n1) < 0) e(43);
X
X  }
X}
X
X
Xe(n)
Xint n;
X{
X  printf("Subtest %d,  error %d  errno=%d  ", testnr, n, errno);
X  perror("");
X  errct++;
X}
+ END-OF-FILE test0.c
chmod 'u=rw,g=r,o=r' 'test0.c'
set `wc -c 'test0.c'`
count=$1
case $count in
5927)	:;;
*)	echo 'Bad character count in ''test0.c' >&2
		echo 'Count should be 5927' >&2
esac
echo Extracting 'test10.c'
sed 's/^X//' > 'test10.c' << '+ END-OF-FILE ''test10.c'
Xchar *name[] = {"t10a","t10b","t10c","t10d","t10e","t10f","t10g","t10h","t10i","t10j"};
X
Xextern int errno;
Xint errct;
Xlong prog[300];
Xint psize;
X
Xmain()
X{
X  int i, n, pid;
X
X  printf("Test 10 ");
X  pid = getpid();
X
X  /* Create files t10b ... t10h */
X  mkfiles();
X
X  if (getpid() == pid) if (fork() == 0) {execl("t10a", (char *) 0); exit(0);}
X  if (getpid() == pid) if (fork() == 0) {execl("t10b", (char *) 0); exit(0);}
X  if (getpid() == pid) if (fork() == 0) {execl("t10c", (char *) 0); exit(0);}
X  if (getpid() == pid) if (fork() == 0) {execl("t10d", (char *) 0); exit(0);}
X
X  for (i = 0; i < 60; i++) {
X	spawn( rand()&07);
X  }
X  for (i = 0; i < 4; i++) wait(&n);
X  if (errct == 0)
X	printf("ok\n");
X  else
X	printf(" %d errors\n", errct);
X  rmfiles();
X  exit(0);
X}
X
Xspawn(n)
Xint n;
X{
X  int pid, k;
X
X  if (pid =fork()) {
X	wait(&n);		/* wait for some child (any one) */
X  } else {
X	k = execl(name[n], (char *) 0);
X	errct++;
X	printf("Child execl didn't take. file=%s errno=%d\n", name[n], errno);
X	rmfiles();
X	exit(0);
X	printf("Worse yet, EXIT didn't exit\n"); 
X  }
X}
X
Xmkfiles()
X{
X  int fd;
X  fd = open("t10a",0);
X  if (fd < 0) {printf("Can't open t10a\n"); exit(1);}
X  psize = read(fd, prog, 300*4);
X  cr_file("t10b", 1600);
X  cr_file("t10c", 1400);
X  cr_file("t10d", 2300);
X  cr_file("t10e", 3100);
X  cr_file("t10f", 2400);
X  cr_file("t10g", 1700);
X  cr_file("t10h", 1500);
X  cr_file("t10i", 4000);
X  cr_file("t10j", 2250);
X  close(fd);
X}
X
X
Xcr_file(name, size)
Xchar *name;
Xint size;
X
X{
X  int fd;
X
X  prog[6] = (long) size;
X  fd = creat(name, 0755);
X  write(fd, prog, psize);
X  close(fd);
X}
X
Xrmfiles()
X{
X  unlink("t10b");
X  unlink("t10c");
X  unlink("t10d");
X  unlink("t10e");
X  unlink("t10f");
X  unlink("t10g");
X  unlink("t10h");
X  unlink("t10i");
X  unlink("t10j");
X}
+ END-OF-FILE test10.c
chmod 'u=rw,g=r,o=r' 'test10.c'
set `wc -c 'test10.c'`
count=$1
case $count in
1765)	:;;
*)	echo 'Bad character count in ''test10.c' >&2
		echo 'Count should be 1765' >&2
esac
echo Extracting 'test11.c'
sed 's/^X//' > 'test11.c' << '+ END-OF-FILE ''test11.c'
Xchar *envp[3] = {"spring", "summer", 0};
X
Xextern errno;
Xint errct;
X
Xmain()
X{
X  int i;
X
X  printf("Test 11 ");
X  for (i = 0; i<9; i++) {
X	test110();
X	test111();
X  }
X  if (errct == 0)
X	printf("ok\n");
X  else
X	printf(" %d errors\n", errct);
X  exit(0);
X}
X
X
Xe(n)
Xint n;
X{
X  printf("\nError %d.  errno = %d  ",n, errno);
X  perror("");
X  errct++;
X}
X
X
X
Xtest110()
X{
X/* Test exec */
X  int n, fd, fd1, i;
X  char aa[4];
X
X
X  if (fork()) {
X	wait(&n);
X	if (n != 25600) e(1);
X	unlink("t1");
X	unlink("t2");
X  } else {
X	if (chown("t11a", 10, 20) < 0) e(2);
X	chmod("t11a", 0666);
X
X	/* The following call should fail because the mode has no X bits on.
X	 * If a bug lets it unexpectedly succeed, the child will print an
X	 * error message since the arguments are wrong.
X	 */
X	execl("t11a", (char *) 0, envp);  /* should fail -- no X bits on */
X
X	/* Control should come here after the failed execl(). */
X	chmod("t11a", 06555);
X	if ( (fd = creat("t1", 0600)) != 3) e(3);
X	if (close(fd) < 0) e(4);
X	if (open("t1", 2) != 3) e(5);
X	if (chown("t1", 10, 99) < 0) e(6);
X	if ( (fd = creat("t2", 0060)) != 4) e(7);
X	if (close(fd) < 0) e(8);
X	if (open("t2", 2)  != 4) e(9);
X	if (chown("t2", 99, 20) < 0) e(10);
X	if (setgid(6) < 0) e(11);
X	if (setuid(5) < 0) e(12);
X	if (getuid() != 5) e(13);
X	if (geteuid() != 5) e(14);
X	if (getgid() != 6) e(15);
X	if (getegid() != 6) e(16);
X	aa[0] = 3;  aa[1] = 5;  aa[2] = 7;  aa[3] = 9;
X	if (write(3, aa, 4) != 4) e(17);
X	lseek(3, 2L, 0);
X	execle("t11a", "t11a",  "arg0", "arg1", "arg2", (char *) 0, envp);
X	e(18);
X	printf("Can't exec t11a\n");
X	exit(3);
X  }
X}
X
X
X
Xtest111()
X{
X  int n;
X  char *argv[5];
X
X  if (fork()) {
X	wait(&n);
X	if (n != (75<<8)) e(20);
X  } else {
X	/* Child tests execv. */
X	argv[0] = "t11b";
X	argv[1] = "abc";
X	argv[2] = "defghi";
X	argv[3] = "j";
X	argv[4] = 0;
X	execv("t11b", argv);
X  	e(19);
X  }
X}
+ END-OF-FILE test11.c
chmod 'u=rw,g=r,o=r' 'test11.c'
set `wc -c 'test11.c'`
count=$1
case $count in
1821)	:;;
*)	echo 'Bad character count in ''test11.c' >&2
		echo 'Count should be 1821' >&2
esac
echo Extracting 'test4.c'
sed 's/^X//' > 'test4.c' << '+ END-OF-FILE ''test4.c'
Xint pid0, pid1, pid2, pid3, s;
Xint i, fd;
Xint nextb;
Xchar *tmpfile = "test4.temp";
Xchar buf[1024];
X
Xmain() {
X  int k;
X
X  creat(tmpfile, 0777);
X  printf("Test  4 ");
X  for (k = 0; k < 20; k++) {
X  	subr();
X  }
X  printf("ok\n");
X  unlink(tmpfile);
X}
X
X
Xsubr()
X{
X  if ( pid0 = fork()){
X	/* Parent 0 */
X	if (pid0 < 0) nofork();
X	if ( pid1 = fork()) {
X		/* Parent 1 */
X		if (pid1 < 0) nofork();
X		if (pid2 = fork()) {
X			/* Parent 2 */
X			if (pid2 < 0) nofork();
X			if ( pid3 = fork()) {
X				/* Parent 3 */
X				if (pid3 < 0) nofork();
X				for (i= 0; i<10000; i++) ;
X				kill(pid2, 9);
X				kill(pid1, 9);
X				kill(pid0, 9);
X				wait(&s);
X				wait(&s);
X				wait(&s);
X				wait(&s);
X			} else {
X				fd = open(tmpfile, 0);
X				lseek(fd, 20480L*nextb, 0);
X				for (i= 0; i<10; i++) read(fd,buf,1024);
X				nextb++;
X				close(fd);
X				exit(0);
X			}
X		} else {
X			while (1) getpid();
X		}
X	} else {
X		while (1) getpid();
X	}
X  } else {
X	while (1) getpid();
X  }
X}
X
Xnofork()
X{
X  printf("Fork failed.  Not enough memory.\n");
X  exit(1);
X}
+ END-OF-FILE test4.c
chmod 'u=rw,g=r,o=r' 'test4.c'
set `wc -c 'test4.c'`
count=$1
case $count in
1019)	:;;
*)	echo 'Bad character count in ''test4.c' >&2
		echo 'Count should be 1019' >&2
esac
echo Extracting 'test5.c'
sed 's/^X//' > 'test5.c' << '+ END-OF-FILE ''test5.c'
X#include "signal.h"
X#include "errno.h"
Xextern int errno;
Xint errct;
X
X
Xint func1(), func10(), func8(), funcalrm(), func11();
Xint childsigs, parsigs, alarms;
X  int zero[1024];
X
Xmain()
X{
X  int i;
X
X  printf("Test  5 ");
X  for (i = 0; i<1; i++) {
X	test50();
X	test51();
X	test53();
X	test54();
X	test55();
X	test56();
X  }
X  if (errct == 0)
X	printf("ok\n");
X  else
X	printf("%d errors\n",errct);
X  exit(0);
X}
X
Xe(n)
Xint n;
X{
X  printf("\nError %d.  errno=%d\n", n, errno);
X  errct++;
X}
X
X
X
Xtest50()
X{
X  int parpid, childpid, flag, *zp;
X
X  flag = 0;
X  for (zp = &zero[0]; zp < &zero[1024]; zp++) if (*zp != 0) flag = 1;
X  if (flag) e(0);		/* check if bss is cleared to 0 */
X  if (signal(1, func1) < 0) e(1);
X  if (signal(10, func10) < 0) e(2);
X  parpid = getpid();
X  if (childpid=fork())  {
X	if (childpid < 0) ex();
X	parent(childpid);
X  } else {
X	child(parpid);
X  }
X  if (signal(1, SIG_DFL) < 0) e(4);
X  if (signal(10, SIG_DFL) < 0) e(5);
X}
X
Xparent(childpid)
Xint childpid;
X{
X  int i;
X
X  for (i = 0; i < 3; i++) {
X	if (kill(childpid, 1) < 0) e(6);
X	while(parsigs == 0) ;
X	parsigs--;
X  }
X  if (wait(&i) < 0) e(7);
X  if (i != 256*6) e(8);
X}
X
Xchild(parpid)
Xint parpid;
X{
X
X  int i;
X
X  for (i = 0; i < 3; i++) {
X	while(childsigs == 0) ;
X	childsigs--;
X	if (kill(parpid, 10) < 0) e(9);
X  }
X  exit(6);
X}
X
Xfunc1()
X{
X  if (signal(1, func1) < 0) e(10);
X  childsigs++;
X}
X
Xfunc10()
X{
X  if (signal(10, func10) < 0) e(11);
X  parsigs++;
X}
X
X
Xtest51()
X{
X  int cpid, n, pid;
X
X  if ( (pid=fork()) ) {
X	if (pid < 0) ex();
X	if ( (pid = fork() )) {
X		if (pid < 0) ex();
X		if (cpid=fork()) {
X			if (cpid < 0) ex();
X			if (kill(cpid, 9) < 0) e(12);
X			if (wait(&n) < 0) e(13);
X			if (wait(&n) < 0) e(14);
X			if (wait(&n) < 0) e(15);
X		} else {
X			pause();
X			while(1);
X		}
X	} else {
X		exit(0);
X	}
X  } else {
X	exit(0);
X  }
X}
X
Xtest52()
X{
X  int pid, n, k;
X
X  pid = getpid();
X  if (getpid() == pid) k = fork();	/* only parent forks */
X  if (k < 0) ex();
X  if (getpid() == pid) k = fork();	/* only parent forks */
X  if (k < 0) ex();
X  if (getpid() == pid) k = fork();	/* only parent forks */
X  if (k < 0) ex();
X
X  if (getpid() == pid) {
X	if (kill(0, 9) < 0) e(16);
X	if (wait(&n) < 0) e(17);
X	if (wait(&n) < 0) e(18);
X	if (wait(&n) < 0) e(19);
X  } else
X	pause();
X}
X
Xint sigmap[5]= {9, 10, 11};
Xtest53()
X{
X  int n, i, pid, wpid;
X
X  /* Test exit status codes for processes killed by signals. */
X  for (i = 0; i < 2; i++) {
X	if (pid=fork()) {
X		if (pid < 0) ex();
X		sleep(5);	/* wait for child to pause */
X		if (kill(pid, sigmap[i]) < 0) {e(20); exit(1);}
X		if ((wpid=wait(&n)) < 0) e(21);
X		if ((n&077) != sigmap[i]) e(22);
X		if (pid != wpid) e(23);
X	} else {
X		pause();
X		exit(0);
X	}
X  }
X}
X
Xtest54()
X{
X/* Test alarm */
X
X  int i;
X
X  alarms = 0;
X  for (i = 0; i < 8; i++) {
X	signal(SIGALRM, funcalrm);
X	alarm(1);
X	pause();
X	if (alarms != i+1) e(24);
X  }
X}
X
X
X
Xtest55()
X{
X/* When a signal knocks a processes out of WAIT or PAUSE, it is supposed to
X * get EINTR as error status.  Check that.
X */
X  int n, j, i;
X
X  if (signal(8, func8) < 0) e(25);
X  if (n=fork()) {
X	/* Parent must delay to give child a chance to pause. */
X	if (n < 0) ex();
X	sleep(1);
X	if (kill(n, 8) < 0) e(26);
X	if (wait(&n) < 0) e(27);
X	if (signal(8, SIG_DFL) < 0) e(28);
X  } else {
X	j = pause();
X	if (errno != EINTR && -errno != EINTR) e(29);
X	exit(0);
X  }
X}
Xfunc8()
X{
X}
Xtest56()
X{
X  int i, j, k, n;
X
X  n = fork();
X  if (n < 0) ex();
X  if (n) {
X	wait(&i);
X	i = (i >> 8) & 0377;
X	if ( i != (n&0377)) e(30);
X  } else {
X	i = getgid();
X	j = getegid();
X	k = (i + j + 7) & 0377;
X	if (setgid(k) < 0) e(31);
X	if (getgid() != k) e(32);
X	if (getegid() != k) e(33);
X	i = getuid();
X	j = geteuid();
X	k = (i + j + 1) & 0377;
X	if (setuid(k) < 0) e(34);
X	if (getuid() != k) e(35);
X	if (geteuid() != k) e(36);
X	i = getpid() & 0377 ;
X	if (wait(&j) != -1) e(37);
X	exit(i);
X  }
X}
X
Xfunc11()
X{
X  e(38);
X}
X
X
Xtest57()
X{
X  int n;
X
X  signal(11, func11);
X  signal(11, SIG_IGN);
X  n = getpid();
X  kill (n, 11);
X  signal(11, SIG_DFL);
X}
X
Xfuncalrm() 
X{
X  alarms++;
X}
X
X
Xtest58()
X{
X/* When a signal knocks a processes out of PIPE, it is supposed to
X * get EINTR as error status.  Check that.
X */
X  int n, j, i, fd[2];
X
X  if (signal(8, func8) < 0) e(38);
X  pipe(fd);
X  if (n=fork()) {
X	/* Parent must delay to give child a chance to pause. */
X	if (n < 0) ex();
X	sleep(3);
X	if (kill(n, 8) < 0) e(39);
X	if (wait(&n) < 0) e(40);
X	if (signal(8, SIG_DFL) < 0) e(41);
X	close(fd[0]);
X	close(fd[1]);
X  } else {
X	j = read(fd[0], &n, 1);
X	if (errno != EINTR) e(42);
X	exit(0);
X  }
X}
X
Xex()
X{
X  printf("Test 5.  fork failed.  Errno=%d\n", errno);
X  exit(1);
X}
X
+ END-OF-FILE test5.c
chmod 'u=rw,g=r,o=r' 'test5.c'
set `wc -c 'test5.c'`
count=$1
case $count in
4532)	:;;
*)	echo 'Bad character count in ''test5.c' >&2
		echo 'Count should be 4532' >&2
esac
echo Extracting 'test8.c'
sed 's/^X//' > 'test8.c' << '+ END-OF-FILE ''test8.c'
X#include <sys/stat.h>
X
Xextern int errno;
Xint testnr;
Xextern long lseek();
X
X
Xmain()
X{
X  int i;
X
X  printf("Test  8 ");
X  for (i = 0; i < 4; i++) {
X	test80();
X  }
X  printf("ok\n");
X}
X
X
X
Xtest80()
X{
X/* Test mknod, chdir, chmod, chown, access.  */
X
X  int i, j;
X  struct stat s;
X
X  testnr = 0;
X  for (j=0; j < 2; j++) {
X	umask(0);
X
X	if (chdir("/") < 0) e(1);
X	if (mknod("dir", 040700, 0) < 0) e(2);
X	if (link("/", "/dir/..") < 0) e(3);
X	if ( mknod("T3a", 0777, 0) < 0) e(4);
X	if (mknod("/dir/T3b", 0777, 0) < 0) e(5);
X	if (mknod("dir/T3c", 0777, 0) < 0) e(6);
X	if ((i=open("/dir/T3b",0)) < 0) e(7);
X	if (close(i) < 0) e(8);
X	if ((i=open("dir/T3c", 0)) < 0) e(9);
X	if (close(i) < 0) e(10);
X	if (chdir("dir") < 0) e(11);
X	if ((i=open("T3b",0)) < 0) e(12);
X	if (close(i) < 0) e(13);
X	if ((i=open("../T3a", 0)) < 0) e(14);
X	if (close(i) < 0 ) e(15);
X	if ((i=open("../dir/../dir/../dir/../dir/../dir/T3c", 0)) < 0) e(16);
X	if (close(i) < 0) e(17);
X
X	if (chmod("../dir/../dir/../dir/../dir/../T3a", 0123) < 0) e(18);
X	if (stat("../dir/../dir/../dir/../T3a", &s) < 0) e(19);
X	if((s.st_mode & 077777) != 0123) e(20);
X	if (chmod("../dir/../dir/../T3a", 0456) < 0) e(21);
X	if (stat("../T3a", &s) < 0) e(22);
X	if((s.st_mode & 077777) != 0456) e(23);
X	if (chown("../dir/../dir/../T3a", 20,30) < 0) e(24);
X	if (stat("../T3a", &s) < 0) e(25);
X	if(s.st_uid != 20) e(26);
X	if(s.st_gid != 30) e(27);
X
X	if ((i=open("/T3c", 0)) >= 0) e(28);
X	if ((i=open("/T3a", 0)) < 0) e(29);
X	if (close(i) < 0) e(30);
X
X	if (access("/T3a", 4) < 0) e(31);
X	if (access("/dir/T3b", 4) < 0) e(32);
X	if (access("/dir/T3d", 4) >= 0) e(33);
X
X	if (unlink("T3b") < 0) e(34);
X	if (unlink("T3c") < 0) e(35);
X	if (unlink("..") < 0) e(36);
X	if (chdir("/") < 0) e(37);
X	if (unlink("dir") < 0) e(38);
X	if (unlink("/T3a") < 0) e(39);
X  }
X
X}
X
X
X
Xe(n)
Xint n;
X{
X  printf("Subtest %d,  error %d  errno=%d  ", testnr, n, errno);
X  perror("");
X}
+ END-OF-FILE test8.c
chmod 'u=rw,g=r,o=r' 'test8.c'
set `wc -c 'test8.c'`
count=$1
case $count in
1882)	:;;
*)	echo 'Bad character count in ''test8.c' >&2
		echo 'Count should be 1882' >&2
esac
echo Extracting 'tty.c'
sed 's/^X//' > 'tty.c' << '+ END-OF-FILE ''tty.c'
X/* tty.c - Return tty name		Author: Freeman P. Pascal IV */
X
X#include <stdio.h>
X
Xchar	*ttyname();
X
Xmain(argc, argv)
Xint  argc;
Xchar *argv[];
X{
X  char *tty_name;
X
X  tty_name = ttyname( 0 );
X  if(( argc == 2 ) && ( !strcmp(argv[1], "-s") ))
X	/* do nothing - shhh! we're in silent mode */;
X  else
X	printf("%s\n", ((tty_name) ? tty_name : "not a tty"));
X  exit((tty_name) ? 0 : 1 );
X}
X
+ END-OF-FILE tty.c
chmod 'u=rw,g=r,o=r' 'tty.c'
set `wc -c 'tty.c'`
count=$1
case $count in
382)	:;;
*)	echo 'Bad character count in ''tty.c' >&2
		echo 'Count should be 382' >&2
esac
echo Extracting 'vol.c'
sed 's/^X//' > 'vol.c' << '+ END-OF-FILE ''vol.c'
X/* vol - break stdin into volumes	Author: Andy Tanenbaum */
X
X/* This program reads standard input and writes it onto diskettes, pausing
X * at the start of each one.  It's main use is for saving files that are
X * larger than a single diskette.  Vol just writes its standard input onto
X * a diskette, and prompts for a new one when it is full.  This mechanism
X * is transparent to the process producing vol's standard input. For example,
X *	tar c - . | vol 360 /dev/fd0
X * puts the tar output as as many diskettes as needed.  To read them back in,
X * use
X *	vol -u 360 /dev/fd0 | tar x -
X *
X */
X
X#include <sys/stat.h>
X#include <minix/blocksize.h>
X#include <signal.h>
X
Xextern int errno;
Xextern char *itoa();
X
Xchar buffer[BLOCK_SIZE];
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  int volume = 1, size, reading, fd, tty;
X  char *p, *name;
X  struct stat stb;
X
X  signal(SIGPIPE, SIG_IGN);
X
X  /* Fetch and verify the arguments. */
X  if (argc != 3 && argc != 4) 
X	message("Usage: vol [-u] size block-special\n", "");
X  p = argv[1];
X  reading = (*p == '-' && *(p+1) == 'u' ? 1 : 0);
X  size = atoi(argv[reading + 1]);
X  name = argv[reading + 2];
X  tty = open("/dev/tty", 0);
X
X  if (size <= 0) 
X	message("vol: bad volume size\n", argv[reading+1]);
X  if (stat(name, &stb) < 0) 
X	message("vol: cannot stat %s\n", name);
X  if ( (stb.st_mode & S_IFMT)  != S_IFBLK) 
X	message("vol: %s is not a block special file\n", name);
X  if (tty < 0)
X	message("vol: cannot open /dev/tty\n", "");
X
X  while (1) {
X	/* Open the special file. */
X	fd = open(name, 1 - reading);
X	if (fd < 0)
X		message("vol: cannot open %s\n", name);
X
X	std_err("Please insert volume ");
X	num(volume);
X	std_err(" and hit return\n");
X	read(tty, buffer, BLOCK_SIZE);
X	volume++;
X
X	/* Read or write the requisite number of blocks. */
X	if (reading)
X		diskio(size, fd, 1, name, "stdout");	/* vol -u | tar xf -*/
X	else
X		diskio(size, 0, fd, "stdin", name);	/* tar cf - | vol */
X
X	close(fd);
X  }
X}
X
Xdiskio(size, fd1, fd2, errstr1, errstr2)
Xint size, fd1, fd2;
Xchar *errstr1, *errstr2;
X{
X/* Read 'size' blocks from 'fd1' and write them on 'fd2'.  Watch out for
X * the fact that reads on pipes can return less than the desired data.
X */
X
X  int n, m, count;
X  long needed;
X
X  needed = (long) BLOCK_SIZE * (long) size;	/* # bytes to read */
X  while (needed > 0L) {
X	count = (needed > (long) BLOCK_SIZE ? BLOCK_SIZE : (int) needed);
X	n = read(fd1, buffer, count);
X	if (n == 0) exit(0);
X	if (n < 0) message("Error encountered while reading %s\n", errstr1);
X	m = write(fd2, buffer, n);
X	if (m < 0 && errno == SIGPIPE) exit(0);
X	if (m > 0 && m != n) message("Output error on %s\n", errstr2);
X	if (m < 0) message("Error encountered while writing %s\n", errstr2);
X	needed -= n;
X  }
X}
X
X
X
Xmessage(s1, s2)
Xchar *s1, *s2;
X{
X  printf(s1, s2);
X  exit(1);
X}
X
Xnum(n)
Xint n;
X{
X  char out[3];
X
X  out[0] = ' ';
X  out[1] = '0';
X  out[2] = 0;
X  if (n < 10) {
X	out[1] += n;
X  } else {
X	out[1] += (n%10);
X	out[0] = '0' + (n/10);
X  }
X  std_err(out);
X}
+ END-OF-FILE vol.c
chmod 'u=rw,g=r,o=r' 'vol.c'
set `wc -c 'vol.c'`
count=$1
case $count in
2966)	:;;
*)	echo 'Bad character count in ''vol.c' >&2
		echo 'Count should be 2966' >&2
esac
exit 0