[comp.os.minix] Definitive 1.2 version of some files

ast@cs.vu.nl (Andy Tanenbaum) (08/11/87)

I have been informed that the sizes and checksums of a few files in 1.2 do
not agree with the files posted earlier.  To ensure that everyone has 
exactly the same files, here is a repeat of the files in question.
These files are the definitive 1.2 versions.
Andy Tanenbaum

: 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
echo Extracting \c\p\d\i\r\.\c
sed 's/^X//' > \c\p\d\i\r\.\c << '+ END-OF-FILE '\c\p\d\i\r\.\c
X/* cpdir - copy directory  	 	Author: Erik Baalbergen */
X
X/* Use "cpdir [-v] src dst" to make a copy dst of directory src.
X   Cpdir should behave like the UNIX shell command
X	(cd src; tar cf - .) | (mkdir dst; cd dst; tar xf -)
X   but the linking structure of the tree, and the owner and time
X   information of files are not yet preserved. (See the work-yet-to-be-done list
X   below.)
X   The -v "verbose" flag enables you to see what's going on when running cpdir.
X
X   Work yet to be done:
X  - preserve link structure, times, etc...
X  - 'stat' optimization (stat() is invoked twice for normal files)
X  - link checks, i.e. am I not overwriting a file/directory by itself?
X	* has been solved by letting 'cpdir' create the target directory
X  - handle character and block special files
X	* they're simply not copied
X
X  Please report bugs and suggestions to erikb@cs.vu.nl
X*/
X
X#include "stdio.h"
X
X#define MKDIR1 "/bin/mkdir"
X#define MKDIR2 "/usr/bin/mkdir"
X#ifdef UNIX
X#include <sys/types.h>
X#include <sys/stat.h>
X#else !UNIX
X#include "stat.h"
X#endif
X
X#define BUFSIZE 1024
X#define PLEN	256
X#define DIRSIZ	16
X
Xchar *prog;
Xint vflag = 0;	/* verbose */
Xchar *strcpy();
X
Xmain(argc, argv)
X	char *argv[];
X{
X	int rc = 0;
X	char *p, *s;
X
X	prog = *argv++;
X	if ((p = *argv) && *p == '-') {
X		argv++;
X		argc--;
X		while (*++p) {
X			switch (*p) {
X			case 'v':
X				vflag = 1;
X				break;
X			default:
X				fatal("illegal flag %s", p);
X			}
X		}
X	}
X	if (argc != 3)
X		fatal("Usage: cpdir [-v] source destination");
X	if (ftype(s = *argv++) != S_IFDIR)
X		fatal("%s is not a directory", s);
X	cpdir(s, *argv);
X	exit(0);
X}
X
Xcpdir(s, d)
X	char *s, *d;
X{
X	char spath[PLEN], dpath[PLEN];
X	char ent[DIRSIZ + 1];
X	register char *send = spath, *dend = dpath;
X	int fd, n;
X
X	while (*send++ = *s++) {}
X	send--;
X	while (*dend++ = *d++) {}
X	if ((fd = open(spath, 0)) < 0) {
X		nonfatal("can't read directory %s", spath);
X		return;
X	}
X	*send++ = '/';
X	ent[DIRSIZ] = '\0';
X	mkdir(dpath);
X	dend[-1] = '/';
X	while ((n = read(fd, ent, DIRSIZ)) == DIRSIZ) {
X		if (!((ent[0] == '\0' && ent[1] == '\0')
X		|| (ent[2] == '.') &&
X			(ent[3] == '\0' || (ent[3] == '.' && ent[4] == '\0'))
X		)) {
X			strcpy(send, ent + 2);
X			strcpy(dend, ent + 2);
X			switch (ftype(spath)) {
X			case S_IFDIR:
X				cpdir(spath, dpath);
X				break;
X			case S_IFREG:
X				cp(spath, dpath);
X				break;
X			default:
X				nonfatal("can't copy special file %s", spath);
X			}
X		}
X	}
X	close(fd);
X	if (n)
X		fatal("error in reading directory %s", spath);
X}
X
Xmkdir(s)
X	char *s;
X{
X	int pid, status;
X
X	if (vflag)
X		printf("mkdir %s\n", s);
X	if ((pid = fork()) == 0) {
X		execl(MKDIR1, "mkdir", s, (char *)0);
X		execl(MKDIR2, "mkdir", s, (char *)0);
X		fatal("can't execute %s or %s", MKDIR1, MKDIR2);
X	}
X	if (pid == -1)
X		fatal("can't fork", prog);
X	wait(&status);
X	if (status)
X		fatal("can't create %s", s);
X}
X
Xcp(s, d)
X	char *s, *d;
X{
X	struct stat st;
X	char buf[BUFSIZE];
X	int sfd, dfd, n;
X
X	if (vflag)
X		printf("cp %s %s\n", s, d);
X	if ((sfd = open(s, 0)) < 0)
X		nonfatal("can't read %s", s);
X	else {
X		if (fstat(sfd, &st) < 0)
X			fatal("can't get file status of %s", s);
X		if ((dfd = creat(d, st.st_mode & 0777)) < 0)
X			fatal("can't create %s", d);
X		while ((n = read(sfd, buf, BUFSIZE)) > 0)
X			write(dfd, buf, n);
X		close(sfd);
X		close(dfd);
X		if (n)
X			fatal("error in reading file %s", s);
X	}
X}
X
Xftype(s)
X	char *s;
X{
X	struct stat st;
X
X	if (stat(s, &st) < 0)
X		fatal("can't get file status of %s", s);
X	return st.st_mode & S_IFMT;
X}
X
Xnonfatal(s, a)
X	char *s, *a;
X{
X	fprintf(stderr, "%s: ", prog);
X	fprintf(stderr, s, a);
X	fprintf(stderr, "\n");
X}
X
Xfatal(s, a)
X	char *s, *a;
X{
X	nonfatal(s, a);
X	exit(1);
X}
X
X
+ END-OF-FILE cpdir.c
chmod 'u=rw,g=r,o=r' \c\p\d\i\r\.\c
set `sum \c\p\d\i\r\.\c`
sum=$1
case $sum in
42315)	:;;
*)	echo 'Bad sum in '\c\p\d\i\r\.\c >&2
esac
echo Extracting \c\t\i\m\e\.\c
sed 's/^X//' > \c\t\i\m\e\.\c << '+ END-OF-FILE '\c\t\i\m\e\.\c
Xstruct tm  {
X  int	tm_sec;
X  int	tm_min;
X  int	tm_hour;
X  int	tm_mday;
X  int	tm_mon;
X  int	tm_year;
X  int	tm_wday;
X  int	tm_yday;
X  int	tm_isdst;
X};
X
Xstruct timeb {
X  long	time;
X  unsigned short millitm;
X  short	timezone;
X  short	dstflag;
X};
X
Xextern struct tm *localtime();
Xextern char *asctime();
X
Xchar *ctime(clock)
X	long *clock;
X{
X	return asctime(localtime(clock));
X}
X
Xstatic int monthsize[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
X
X#define SECS_DAY (24*60L*60L)
X#define YEARSIZE(year)	((year) % 4 ? 365 : 366)
X
Xstruct tm *
Xgmtime(clock)
X	long *clock;
X{
X	long cl = *clock;
X	long dayclock, dayno;
X	static struct tm tm_buf;
X	register struct tm *pbuf = &tm_buf;
X	register int *months = monthsize;
X	int year = 1970;
X
X	dayclock = cl % SECS_DAY;
X	dayno = cl / SECS_DAY;
X
X	pbuf->tm_sec = dayclock % 60;
X	pbuf->tm_min = (dayclock % 3600) / 60;
X	pbuf->tm_hour = dayclock / 3600;
X	pbuf->tm_wday = (dayno + 4) % 7; /* day 0 was a thursday */
X	while (dayno >= YEARSIZE(year)) {
X		dayno -= YEARSIZE(year);
X		year++;
X	}
X	pbuf->tm_year = year - 1900;
X	pbuf->tm_yday = dayno;
X	pbuf->tm_isdst = 0;
X	if (YEARSIZE(year) == 366) monthsize[1] = 29;
X	while (dayno - *months >= 0) dayno -= *months++;
X	pbuf->tm_mday = dayno + 1;
X	pbuf->tm_mon = months - monthsize;
X	monthsize[1] = 28;
X	return pbuf;
X}
X
X#define FIRSTSUNDAY(t)	(((t)->tm_yday - (t)->tm_wday + 420) % 7)
X#define SUNDAY(day, t)	((day) < 58 ? \
X			  ((day) < FIRSTSUNDAY(t) ? FIRSTSUNDAY(t) :
Xstatic int
Xlast_sunday(d, t)
X	register int d;
X	register struct tm *t;
X{
X	int first = FIRSTSUNDAY(t);
X
X	if (d >= 58 && YEARSIZE(t->tm_year)) d++;
X	if (d < first) return first;
X	return d - (d - first) % 7;
X}
X
Xextern struct tm *gmtime();
X
Xstruct tm *
Xlocaltime(clock)
X	long *clock;
X{
X	register struct tm *gmt;
X	long cl;
X	int begindst, enddst;
X	extern int __daylight;
X	extern long __timezone;
X
X	tzset();
X	cl = *clock - __timezone;
X	gmt = gmtime(&cl);
X	if (__daylight) {
X		/* daylight saving time.
X		   Unfortunately, rules differ for different countries.
X		   Implemented here are heuristics that got it right
X		   in Holland, over the last couple of years.
X		   Of course, there is no algorithm. It is all
X		   politics ...
X		*/
X		begindst = last_sunday(89, gmt); /* last Sun before Apr */
X		enddst = last_sunday(272, gmt);  /* last Sun in Sep */
X	    	if ((gmt->tm_yday>begindst ||
X		     (gmt->tm_yday==begindst && gmt->tm_hour>=2)) &&
X	    	    (gmt->tm_yday<enddst || 
X		     (gmt->tm_yday==enddst && gmt->tm_hour<3))) {
X			/* it all happens between 2 and 3 */
X			cl += 1*60*60;
X			gmt = gmtime(&cl);
X			gmt->tm_isdst++;
X		}
X	}
X	return gmt;
X}
X#ifdef BSD4_2
X#else
X#ifndef USG
X#endif
X#endif
X
X#ifdef USG
Xlong	timezone = -1 * 60;
Xint	daylight = 1;
Xchar	*tzname[] = {"MET", "MDT",};
X#endif
X
Xlong __timezone = -1 * 60;
Xint __daylight = 1;
Xchar *__tzname[] = {"MET", "MDT", };
X
Xtzset()
X{
X#ifdef BSD4_2
X	struct timeval tval;
X	struct timezone tzon;
X
X	gettimeofday(&tval, &tzon);
X	__timezone = tzon.tz_minuteswest * 60L;
X	__daylight = tzon.tz_dsttime;
X#else
X#ifndef USG
X	struct timeb time;
X
X	ftime(&time);
X	__timezone = time.timezone*60L;
X	__daylight = time.dstflag;
X#endif
X#endif
X
X	{
X	extern char *getenv();
X	register char *p = getenv("TZ");
X
X	if (p && *p) {
X		register int n = 0;
X		int sign = 1;
X
X		strncpy(__tzname[0], p, 3);
X		p += 3;
X		if (*(p += 3) == '-') {
X			sign = -1;
X			p++;
X		}
X
X		while(*p >= '0' && *p <= '9')
X			n = 10 * n + (*p++ - '0');
X		n *= sign;
X		__timezone = ((long)(n * 60)) * 60;
X		__daylight = (*p != '\0');
X		strncpy(__tzname[1], p, 3);
X	}
X	}
X#ifdef USG
X	timezone = __timezone;
X	daylight = __daylight;
X	tzname[0] = __tzname[0];
X	tzname[1] = __tzname[1];
X#endif
X}
+ END-OF-FILE ctime.c
chmod 'u=rw,g=r,o=r' \c\t\i\m\e\.\c
set `sum \c\t\i\m\e\.\c`
sum=$1
case $sum in
38880)	:;;
*)	echo 'Bad sum in '\c\t\i\m\e\.\c >&2
esac
echo Extracting \d\i\f\f\.\c
sed 's/^X//' > \d\i\f\f\.\c << '+ END-OF-FILE '\d\i\f\f\.\c
X/* diff  - print differences between 2 files	  Author: Erik Baalbergen */
X
X/* Poor man's implementation of diff(1)
X - no options available
X - may give more output than other diffs, due to the straight-forward algorithm
X - runs out of memory if the differing chunks become too large
X - input line length should not exceed LINELEN; longer lines are truncated,
X   while only the first LINELEN characters are compared
X 
X Please report bugs and suggestions to erikb@cs.vu.nl
X*/
X#include "stdio.h"
XFILE *fopen();
X
X#define LINELEN 128
X
Xchar *prog;
Xint diffs = 0;
X
Xmain(argc, argv)
X	char **argv;
X{
X	FILE *fp1 = NULL, *fp2 = NULL;
X
X	prog = *argv++;
X	if (argc != 3)
X		fatal("use: %s file1 file2", prog);
X	if (strcmp(argv[0], "-") == 0)
X		fp1 = stdin;
X	else
X	if (strcmp(argv[1], "-") == 0)
X		fp2 = stdin;
X	if (fp1 == NULL && (fp1 = fopen(argv[0], "r")) == NULL)
X		fatal("can't read %s", argv[0]);
X	if (fp2 == NULL && (fp2 = fopen(argv[1], "r")) == NULL)
X		fatal("can't read %s", argv[1]);
X	diff(fp1, fp2);
X	exit(diffs > 0);
X}
X
Xfatal(fmt, s)
X	char *fmt, *s;
X{
X	fprintf(stderr, "%s: ", prog);
X	fprintf(stderr, fmt, s);
X	fprintf(stderr, "\n");
X	exit(2);
X}
X
X/* the line module */
Xchar *malloc();
Xchar *fgets();
X
Xstruct line {
X	struct line *l_next;
X	char l_text[LINELEN + 2];
X};
X
Xstruct line *freelist = 0;
X
Xstruct line *
Xnew_line()
X{
X	register struct line *l;
X
X	if (l = freelist)
X		freelist = freelist->l_next;
X	else
X	if ((l = (struct line *)malloc(sizeof(struct line))) == 0)
X		fatal("out of memory");
X	return l;
X}
X
Xfree_line(l)
X	register struct line *l;
X{
X	l->l_next = freelist;
X	freelist = l;
X}
X
X#define equal_line(l1, l2) (strcmp((l1)->l_text, (l2)->l_text) == 0)
X
Xint equal_3(l1, l2)
X	struct line *l1, *l2;
X{
X	register int i;
X
X	for (i=0; i<3 && l1 && l2; ++i, l1=l1->l_next, l2=l2->l_next) {
X		if (!equal_line(l1, l2))
X			return 0;
X	}
X	return (i==3);
X}
X
Xstruct line *
Xread_line(fp)
X	FILE *fp;
X{
X	register struct line *l = new_line();
X	register char *p;
X	register int c;
X
X	(p = &(l->l_text[LINELEN]))[1] = '\377';
X	if (fgets(l->l_text, LINELEN + 2, fp) == NULL) {
X		free_line(l);
X		return 0;
X	}
X	if ((p[1] & 0377) != '\377' && *p != '\n') {
X		while ((c = fgetc(fp)) != '\n' && c != EOF) {}
X		*p++ = '\n';
X		*p = '\0';
X	}
X	l->l_next = 0;
X	return l;
X}
X
X/* file window handler */
Xstruct f {
X	struct line *f_bwin, *f_ewin;
X	struct line *f_aside;
X	int f_linecnt;	/* line number in file of last advanced line */
X	FILE *f_fp;
X};
X
Xadvance(f)
X	register struct f *f;
X{
X	register struct line *l;
X	
X	if (l = f->f_bwin) {
X		if (f->f_ewin == l)
X			f->f_bwin = f->f_ewin = 0;
X		else
X			f->f_bwin = l->l_next;
X		free_line(l);
X		(f->f_linecnt)++;
X	}
X}
X
Xaside(f, l)
X	struct f *f;
X	struct line *l;
X{
X	register struct line *ll;
X
X	if (ll = l->l_next) {
X		while (ll->l_next)
X			ll = ll->l_next;
X		ll->l_next = f->f_aside;
X		f->f_aside = l->l_next;
X		l->l_next = 0;
X		f->f_ewin = l;
X	}
X}
X
Xstruct line *
Xnext(f)
X	register struct f *f;
X{
X	register struct line *l;
X
X	if (l = f->f_aside) {
X		f->f_aside = l->l_next;
X		l->l_next = 0;
X	}
X	else
X		l = read_line(f->f_fp);
X	if (l) {
X		if (f->f_bwin == 0)
X			f->f_bwin = f->f_ewin = l;
X		else {
X			f->f_ewin->l_next = l;
X			f->f_ewin = l;
X		}
X	}
X	return l;
X}
X
Xinit_f(f, fp)
X	register struct f *f;
X	FILE *fp;
X{
X	f->f_bwin = f->f_ewin =  f->f_aside = 0;
X	f->f_linecnt = 0;
X	f->f_fp = fp;
X}
X
Xupdate(f, s)
X	register struct f *f;
X	char *s;
X{
X	while (f->f_bwin && f->f_bwin != f->f_ewin) {
X		printf("%s%s", s, f->f_bwin->l_text);
X		advance(f);
X	}
X}
X	
X/* diff procedure */
Xdiff(fp1, fp2)
X	FILE *fp1, *fp2;
X{
X	struct f f1, f2;
X	struct line *l1, *s1, *b1, *l2, *s2, *b2;
X	register struct line *ll;
X
X	init_f(&f1, fp1);
X	init_f(&f2, fp2);
X	l1 = next(&f1);
X	l2 = next(&f2);
X	while (l1 && l2) {
X		if (equal_line(l1, l2)) {
Xequal:
X			advance(&f1);
X			advance(&f2);
X			l1 = next(&f1);
X			l2 = next(&f2);
X			continue;
X		}
X		s1 = b1 = l1;
X		s2 = b2 = l2;
X		/* read several more lines */
X		next(&f1); next(&f1);
X		next(&f2); next(&f2);
X		/* start searching */
Xsearch:
X		if ((l2 = next(&f2)) == 0)
X			continue;
X		ll = s1;
X		b2 = b2->l_next;
X		do {
X			if (equal_3(ll, b2)) {
X				aside(&f1, ll);
X				aside(&f2, b2);
X				differ(&f1, &f2);
X				goto equal;
X			}
X		} while (ll = ll->l_next);
X		if ((l1 = next(&f1)) == 0)
X			continue;
X		ll = s2;
X		b1 = b1->l_next;
X		do {
X			if (equal_3(ll, b1)) {
X				aside(&f2, ll);
X				aside(&f1, b1);
X				differ(&f1, &f2);
X				goto equal;
X			}
X		} while (ll = ll->l_next);
X		goto search;
X	}
X	/* one of the files reached EOF */
X	if (l1) /* eof on 2 */
X		while (next(&f1)) {}
X	if (l2)
X		while (next(&f2)) {}
X	f1.f_ewin = 0;
X	f2.f_ewin = 0;
X	differ(&f1, &f2);
X}
X
Xdiffer(f1, f2)
X	register struct f *f1, *f2;
X{
X	int cnt1 = f1->f_linecnt, len1 = wlen(f1), cnt2 = f2->f_linecnt,
X		len2 = wlen(f2);
X
X	if ((len1 = wlen(f1)) || (len2 = wlen(f2))) {
X		if (len1 == 0) {
X			printf("%da", cnt1);
X			range(cnt2 + 1, cnt2 + len2);
X		}
X		else
X		if (len2 == 0) {
X			range(cnt1 + 1, cnt1 + len1);
X			printf("d%d", cnt2);
X		}
X		else {
X			range(cnt1 + 1, cnt1 + len1);
X			putchar('c');
X			range(cnt2 + 1, cnt2 + len2);
X		}
X		putchar('\n');
X		if (len1)
X			update(f1, "< ");
X		if (len1 && len2)
X			printf("---\n");
X		if (len2)
X			update(f2, "> ");
X		diffs++;
X	}
X}
X
Xwlen(f)
X	struct f *f;
X{
X	register cnt = 0;
X	register struct line *l = f->f_bwin, *e = f->f_ewin;
X
X	while (l && l != e) {
X		cnt++;
X		l = l->l_next;
X	}
X	return cnt;
X}
X
Xrange(a, b)
X{
X	printf(((a == b) ? "%d" : "%d,%d"), a, b);
X}
+ END-OF-FILE diff.c
chmod 'u=rw,g=r,o=r' \d\i\f\f\.\c
set `sum \d\i\f\f\.\c`
sum=$1
case $sum in
55356)	:;;
*)	echo 'Bad sum in '\d\i\f\f\.\c >&2
esac
echo Extracting \f\d\i\s\k\.\c
sed 's/^X//' > \f\d\i\s\k\.\c << '+ END-OF-FILE '\f\d\i\s\k\.\c
X/* fdisk - partition a hard disk	Author: Jakob Schripsema */
X
X/*
X * First run the DOS utilities FDISK and FORMAT. FDISK
X * puts the boot code in sector 0.
X * Then run fdisk
X *
X *	fdisk /dev/hdx	(MINIX)
X *	fdisk x:		(DOS)
X *
X * Compiling
X *
X *	cc -o fdisk -DUNIX fdisk.c	(MINIX)
X *	cl -DDOS fdisk.c			(DOS with MS C compiler)
X */
X 
X#include "stdio.h"
X#define UNIX		/* for MINIX */
X
X#ifdef DOS
X#include <dos.h>
X#endif
X
X/*
X * Constants
X */
X
X#define	NHEAD		4		/* # heads		*/
X#define	NSEC		17		/* sectors / track	*/
X#define SECSIZE		512		/* sector size		*/
X#define	OK		0
X#define	ERR		1
X#define	TABLEOFFSET	0x1be		/* offset in boot sector*/
X/*
X * Description of entry in partition table
X */
X
Xstruct part_entry {
X	char	bootind;	/* boot indicator 0/0x80	*/
X	char	start_head;	/* head value for first sector	*/
X	char	start_sec;	/* sector value for first sector*/
X	char	start_cyl;	/* track value for first sector	*/
X	char	sysind;		/* system indicator 00=?? 01=DOS*/
X	char	last_head;	/* head value for last sector	*/
X	char	last_sec;	/* sector value for last sector	*/
X	char	last_cyl;	/* track value for last sector	*/
X	long	lowsec;		/* logical first sector		*/
X	long	size;		/* size of partion in sectors	*/
X};
X	
X/*
X * Globals
X */
X
Xchar	secbuf[SECSIZE];
Xchar	*devname;
Xchar	*dosstr  = "  DOS  ";
Xchar	*ndosstr = "Non-DOS";
X
X#ifdef DOS
Xunion	REGS	regs;
Xstruct	SREGS	sregs;
Xint	drivenum;
X#endif
X
X#ifdef UNIX
Xint	devfd;
X#endif
X
Xmain(argc,argv)
Xint	argc;
Xchar	*argv[];
X{
X	char	ch;
X
X	/* init */
X
X	if (argc != 2) {
X		printf("Usage: fdisk /dev/hdx\n");
X		exit(1);
X	}
X
X	devname = argv[1];
X	getboot(secbuf);	/* get boot sector	*/
X
X	do {
X		dpl_partitions();
X		print_menu();
X		ch = get_a_char();
X		putchar('\n');
X		switch (ch) {
X			case 'c' :
X				change_table();
X				break;
X			case 'w' :
X				if (chk_table() == OK) {
X					putboot(secbuf);
X					exit(0);
X				}
X				break;
X			case 'l' :
X				load_from_file();
X				break;
X			case 's' :
X				save_to_file();
X				break;
X			case 'p' :
X				dump_table();
X				break;
X			case 'q' :
X				exit(0);
X			default :
X				printf(" %c ????\n",ch);
X		}
X	}
X	while (1);
X}
X
X/*
X * Read boot sector
X */
X
X#ifdef DOS
X
Xgetboot(buffer)
Xchar	*buffer;
X{
X	segread(&sregs);	/* get ds */
X
X	if (devname[1] != ':') {
X		printf("Invalid drive %s\n",devname);
X		exit(1);
X	}
X
X	if (*devname >= 'a')
X		*devname += 'A' - 'a';
X	drivenum = (*devname - 'C') & 0xff;
X	if (drivenum < 0 || drivenum > 7) {
X		printf("Funny drive number %d\n",drivenum);
X		exit(1);
X	}
X	regs.x.ax = 0x201;	/* read 1 sectors	*/
X	regs.h.ch = 0;		/* track		*/
X	regs.h.cl = 1;		/* first sector = 1	*/
X	regs.h.dh = 0;		/* head = 0		*/
X	regs.h.dl = 0x80+drivenum;/* drive = 0		*/
X	sregs.es = sregs.ds;	/* buffer address	*/
X	regs.x.bx = (int)secbuf;
X
X	int86x(0x13,&regs,&regs,&sregs);
X	if (regs.x.cflag)
X	{
X		printf("Cannot read boot sector\n");
X		exit(1);
X	}
X}
X#endif
X
X#ifdef UNIX
X
Xgetboot(buffer)
Xchar	*buffer;
X{
X	devfd = open(devname,2);
X	if (devfd < 0) {
X		printf("Cannot open device %s\n",devname);
X		exit(1);
X	}
X	if (read(devfd,buffer,SECSIZE) != SECSIZE) {
X		printf("Cannot read boot sector\n");
X		exit(2);
X	}
X}
X#endif
X
X/*
X * Write boot sector
X */
X
X#ifdef DOS
X
Xputboot(buffer)
Xchar	*buffer;
X{
X	regs.x.ax = 0x301;	/* read 1 sectors	*/
X	regs.h.ch = 0;		/* track		*/
X	regs.h.cl = 1;		/* first sector = 1	*/
X	regs.h.dh = 0;		/* head = 0		*/
X	regs.h.dl = 0x80+drivenum;/* drive = 0		*/
X	sregs.es = sregs.ds;	/* buffer address	*/
X	regs.x.bx = (int)secbuf;
X
X	int86x(0x13,&regs,&regs,&sregs);
X	if (regs.x.cflag)
X	{
X		printf("Cannot write boot sector\n");
X		exit(1);
X	}
X}
X#endif
X
X#ifdef UNIX
X
Xputboot(buffer)
Xchar	*buffer;
X{
X	int r;
X
X	if (lseek(devfd,0L,0) < 0) {
X		printf("Seek error during write\n");
X		exit(1);
X	}
X	if (write(devfd,buffer,SECSIZE) != SECSIZE) {
X		printf("Write error\n");
X		exit(1);
X	}
X	sync();
X}
X#endif
X
X/*
X * Load buffer from file
X */
X
Xload_from_file()
X{
X	char	file[80];
X	int	fd;
X
X	printf("Enter file name: ");
X	gets(file);
X#ifdef UNIX
X	fd = open(file,0);
X#endif
X#ifdef DOS
X	fd = open(file,0x8000);
X#endif
X	if (fd < 0) {
X		fprintf(stderr,"Cannot load from %s\n",file);
X		exit(1);
X	}
X	if (read(fd,secbuf,SECSIZE) != SECSIZE) {
X		fprintf(stderr,"Read error\n");
X		exit(1);
X	}
X	close(fd);
X}
X
X/*
X * Save to file
X */
X
Xsave_to_file()
X{
X	char	file[80];
X	int	fd;
X
X	printf("Enter file name: ");
X	gets(file);
X#ifdef UNIX
X	fd = creat(file,0644);
X#endif
X#ifdef DOS
X	fd = creat(file,0644);
X	if (fd < 0) {
X		fprintf(stderr,"Cannot creat %s\n",file);
X		exit(1);
X	}
X	close(fd);
X	fd = open(file,0x8001);
X#endif
X	if (fd < 0) {
X		fprintf(stderr,"Cannot save to %s\n",file);
X		exit(1);
X	}
X	if (write(fd,secbuf,SECSIZE) != SECSIZE) {
X		fprintf(stderr,"Write error\n");
X		exit(1);
X	}
X	close(fd);
X}
X
X/*
X * Dump partition table
X */
X
Xdump_table()
X{
X	struct	part_entry	*pe;
X	int	i;
X
X	pe = (struct part_entry *)&secbuf[TABLEOFFSET];
X	printf("\n       --first---     ---last---\n");
X	printf("Prt ac hd sec cyl sys hd sec cyl    low      size\n");
X	for (i = 1 ; i < 5 ; i++) {
X		printf(" %x  %2x  %x  %2x  %2x  %2x  %x  %2x  %2x %6D %9D\n",
X			i,
X			pe->bootind & 0xff,
X			pe->start_head & 0xff,
X			pe->start_sec & 0xff,
X			pe->start_cyl & 0xff,
X			pe->sysind & 0xff,
X			pe->last_head & 0xff,
X			pe->last_sec & 0xff,
X			pe->last_cyl & 0xff,
X			pe->lowsec,
X			pe->size);
X		pe++;
X	}
X}
X/*
X * Display partition table
X */
X
Xdpl_partitions()
X{
X	struct	part_entry	*pe;
X	int	i;
X
X	printf("\nPartition      Type     Begin End  Active\n");
X	pe = (struct part_entry *)&secbuf[TABLEOFFSET];
X	for (i = 1 ; i <= 4 ; i++) {
X		dpl_entry(i,pe);
X		pe++;
X	}
X}
X
X/*
X * Display an entry
X */
X
Xdpl_entry(number,entry)
Xint	number;
Xstruct	part_entry	*entry;
X{
X	int	low_cyl,high_cyl,temp;
X	char	*typestring;
X	char	active;
X
X	if (entry->sysind == 0x01)
X		typestring = dosstr;
X	else
X		typestring = ndosstr;
X	printf("%5d         %s  ",number,typestring);
X	temp = entry->start_sec & 0xc0;
X	low_cyl = (entry->start_cyl & 0xff) + (temp << 2);
X	temp = entry->last_sec & 0xc0;
X	high_cyl = (entry->last_cyl & 0xff) + (temp << 2);
X	printf("%4d  %4d",low_cyl,high_cyl);
X	if ((entry->bootind & 0xff) == 0x80)
X		active = 'A';
X	else
X		active = 'N';
X	printf("     %c\n",active);
X}
X
X/*
X * Check partition table
X */
X
Xchk_table()
X{
X	struct part_entry *pe;
X	int i;
X	int active;
X	long limit;
X
X	pe = (struct part_entry *)&secbuf[TABLEOFFSET];
X	limit = 0L;
X	active = 0;
X	for (i = 1 ; i < 5 ; i++) {
X		if (pe->size == 0L)
X			return(OK);
X		if (pe->lowsec <= limit) {
X			printf("Overlap between part. %d and %d\n",i,i-1);
X			return(ERR);
X		}
X		limit = pe->lowsec + pe->size - 1L;
X		if (pe->bootind == 0x80)
X			active++;
X		pe++;
X	}
X	if (active > 1) {
X		printf("%d active partitions\n",active);
X		return(ERR);
X	}
X	return(OK);
X}
X/*
X * Check entry
X * head/sector/track info must match logical sector number
X * Used to check 'foreign' partition table during debugging
X */
X
Xchk_entry(entry)
Xstruct	part_entry	*entry;
X{
X	char	head;
X	char	sector;
X	char	track;
X
X	sec_to_hst(entry->lowsec,&head,&sector,&track);
X	if (	(head != entry->start_head) ||
X		(sector != entry->start_sec) ||
X		(track != entry->start_cyl))
X		return(ERR);
X	sec_to_hst(entry->lowsec + entry->size - 1L,&head,&sector,&track);
X	if (	(head != entry->last_head) ||
X		(sector != entry->last_sec) ||
X		(track != entry->last_cyl))
X		return(ERR);
X	return(OK);
X}
X
X/*
X * Convert a logical sector number to
X * head / sector / track
X */
X
Xsec_to_hst(logsec,hd,sec,cyl)
Xlong	logsec;
Xchar	*hd,*sec,*cyl;
X{
X	int	bigcyl;
X
X	bigcyl = logsec / (NHEAD * NSEC);
X	*sec = (logsec % NSEC) + 1 + ((bigcyl >> 2) & 0xc0);
X	*cyl = bigcyl & 0xff;
X	*hd = (logsec % (NHEAD * NSEC)) / NSEC;
X}
X
X/*
X * change partition table
X */
X
Xchange_table()
X{
X	struct	part_entry	*pe;
X	int	i,temp,low_cyl,high_cyl;
X	char	ch;
X
X	pe = (struct part_entry *)&secbuf[TABLEOFFSET];
X	for (i = 1 ; i <= 4 ; i++) {
X		temp = pe->start_sec & 0xc0;
X		low_cyl = (pe->start_cyl & 0xff) + (temp << 2);
X		temp = pe->last_sec & 0xc0;
X		high_cyl = (pe->last_cyl & 0xff) + (temp << 2);
X		printf("Partition %d from %d to %d. Change? (y/n) ",
X			i,low_cyl,high_cyl);
X		ch = get_a_char();
X		if (ch == 'y' || ch == 'Y')
X			get_partition(pe);
X		pe++;
X	}
X	putchar('\n');
X}
X
X/*
X * Get partition info : first & last cylinder
X */
X
Xget_partition(entry)
Xstruct part_entry *entry;
X{
X	char	buf[80];
X	int	first,last;
X	long	low,high;
X	char	ch;
X
X	printf("	Enter first cylinder: ");
X	gets(buf);
X	sscanf(buf,"%d",&first);
X	printf("	Enter last cylinder: ");
X	gets(buf);
X	sscanf(buf,"%d",&last);;
X	if (first == 0 && last == 0) {
X		entry->bootind = 0;
X		entry->start_head = 0;
X		entry->start_sec = 0;
X		entry->start_cyl = 0;
X		entry->sysind = 0;
X		entry->last_head = 0;
X		entry->last_sec  = 0;
X		entry->last_cyl = 0;
X		entry->lowsec = 0L;
X		entry->size = 0L ;
X		return;
X	}
X	low = first & 0xffff;
X	low = low * NSEC * NHEAD;
X	if (low == 0)
X		low = 1; /* sec0 is master boot record */
X	high = last & 0xffff;
X	high = (high + 1)*NSEC*NHEAD - 1;
X	entry->lowsec = low;
X	entry->size = high - low + 1;
X	sec_to_hst(low,
X		&entry->start_head,
X		&entry->start_sec,
X		&entry->start_cyl);
X	sec_to_hst(high,
X		&entry->last_head,
X		&entry->last_sec,
X		&entry->last_cyl);
X	printf("	DOS partition? (y/n) ");
X	ch = get_a_char();
X	if (ch == 'y' || ch == 'Y')
X		entry->sysind = 1;
X	else
X		entry->sysind = 0;
X	printf("	Active partition? (y/n) ");
X	ch = get_a_char();
X	if (ch == 'y' || ch == 'Y')
X		entry->bootind = 0x80;
X	else
X		entry->bootind = 0;
X}
X
X/*
X * Read 1 character and discard rest of line
X */
X
Xget_a_char()
X{
X	char	ch;
X
X	ch = getchar();
X	if (ch != '\n')
X		while (getchar() != '\n');
X	return(ch);
X}
X
Xprint_menu()
X{
X  printf("\nType a command letter, then a carriage return:\n");
X  printf("   c - change a partition\n");
X  printf("   w - write changed partition table back to disk and exit\n");
X  printf("   q - quit without making any changes\n");
X  printf("   s - save boot block (including partition table) on a file\n");
X  printf("   l - load boot block (including partition table) from a file\n");
X  printf("   p - print partition table\n\n");
X}
+ END-OF-FILE fdisk.c
chmod 'u=rw,g=r,o=r' \f\d\i\s\k\.\c
set `sum \f\d\i\s\k\.\c`
sum=$1
case $sum in
48175)	:;;
*)	echo 'Bad sum in '\f\d\i\s\k\.\c >&2
esac
echo Extracting \f\i\n\d\.\c
sed 's/^X//' > \f\i\n\d\.\c << '+ END-OF-FILE '\f\i\n\d\.\c
X/* find - look for files satisfying a predicat	Author: Erik Baalbergen */
X
X/*
X   *** Check the switches in the SWITCHES section below. ***
X
X   Differences from UNIX version 7 find(1):
X	* -name: no name allowed; only uid
X		e.g. find all core files: "find . -name core -a -print"
X
X   The "-atime" may not work well on Minix.
X   Please report bugs and suggestions to erikb@cs.vu.nl
X*/
X
X#include "stdio.h"
X
X/*######################## SWITCHES ##############################*/
X#include "stat.h"
X#define SHELL "/usr/bin/sh"
X
X#define PLEN	256	/* maximum path length; overflows are not detected */
X#define DIRSIZ	16	/* size of a directory entry */
X#define MAXARG	256	/* maximum length for an argv */
X#define NPATHS	256	/* maximum number of paths in path-list */
X#define BSIZE  1024	/* bytes per block */
X
X/*######################## DEFINITIONS ##############################*/
X#define SECS_PER_DAY	(24L * 60L * 60L)	/* check your planet */
X
Xstruct exec {
X	int e_cnt;
X	char *e_vec[MAXARG];
X};
X
X#define OP_NAME		1
X#define OP_PERM		2
X#define OP_TYPE		3
X#define OP_LINKS	4
X#define OP_USER		5
X#define OP_GROUP	6
X#define OP_SIZE		7
X#define OP_INUM		8
X#define OP_ATIME	9
X#define OP_MTIME	10
X#define OP_EXEC		11
X#define OP_OK		12
X#define OP_PRINT	13
X#define OP_NEWER	14
X#define OP_AND		15
X#define OP_OR		16
X
Xstruct oper {
X	char *op_str;
X	int op_val;
X} ops[] = {
X	{"name",	OP_NAME},
X	{"perm",	OP_PERM},
X	{"type",	OP_TYPE},
X	{"links",	OP_LINKS},
X	{"user",	OP_USER},
X	{"group",	OP_GROUP},
X	{"size",	OP_SIZE},
X	{"inum",	OP_INUM},
X	{"atime",	OP_ATIME},
X	{"mtime",	OP_MTIME},
X	{"exec",	OP_EXEC},
X	{"ok",		OP_OK},
X	{"print",	OP_PRINT},
X	{"newer",	OP_NEWER},
X	{"a",		OP_AND},
X	{"o",		OP_OR},
X	{0,		0}
X};
X
X#define EOI	-1
X#define NONE	0
X#define LPAR	20
X#define RPAR	21
X#define NOT	22
X
Xchar *prog, *strcpy(), *Malloc(), *find_bin();
X
Xstruct node {
X	int n_type;	/* any OP_ or NOT */
X	union {
X		char *n_str;
X		struct {
X			long n_val;
X			int n_sign;
X		} n_int;
X		struct exec *n_exec;
X		struct {
X			struct node *n_left, *n_right;
X		} n_opnd;
X	} n_info;
X};
Xstruct node *expr();
X
Xchar **ipp;
Xint tty;	/* fd for /dev/tty when using -ok */
Xlong current_time;
X
Xchar *
XMalloc(n)
X{
X	char *malloc(), *m;
X
X	if ((m = malloc(n)) == 0)
X		fatal("out of memory", "");
X	return m;
X}
X
Xchar *
XSalloc(s)
X	char *s;
X{
X	return strcpy(Malloc(strlen(s) + 1), s);
X}
X
Xmain(argc, argv)
X	char *argv[];
X{
X	char *pathlist[NPATHS];
X	int pathcnt = 0;
X	register i;
X	struct node *pred;
X
X	prog = *argv++;
X	while (--argc > 0 && lex(*argv) == NONE)
X		pathlist[pathcnt++] = *argv++;
X	if (pathcnt == 0 || argc == 0)
X		fatal("Usage: path-list predicate-list", "");
X	ipp = argv;
X	time(&current_time);
X	pred = expr(lex(*ipp));
X	if (lex(*++ipp) != EOI)
X		fatal("syntax error: garbage at end of predicate", "");
X	for (i = 0; i < pathcnt; i++)
X		find(pathlist[i], pred, "");
X	exit(0);
X}
X
Xfind(path, pred, last)
X	char *path, *last;
X	struct node *pred;
X{
X	char spath[PLEN], ent[DIRSIZ + 1];
X	struct stat st;
X	register char *send = spath;
X	FILE *fp, *fopen();
X
X	if (path[1] == '\0' && *path == '/') {
X		*send++ = '/';
X		*send = '\0';
X	}
X	else
X		while (*send++ = *path++) {}
X	if (stat(spath, &st) == -1)
X		nonfatal("can't get status of ", spath);
X	else {
X		(void) check(spath, &st, pred, last);
X		if ((st.st_mode & S_IFMT) == S_IFDIR) {
X			if ((fp = fopen(spath, "r")) == NULL) {
X				nonfatal("can't read directory ", spath);
X				return;
X			}
X			send[-1] = '/';
X			ent[DIRSIZ] = '\0';
X			while (fread(ent, DIRSIZ, 1, fp) == 1) {
X				if (!((*ent == '\0' && ent[1] == '\0')
X				|| (ent[2] == '.') &&
X					(ent[3] == '\0'
X					|| (ent[3] == '.' && ent[4] == '\0'))
X				)) {
X					strcpy(send, ent + 2);
X					find(spath, pred, ent + 2);
X				}
X			}
X			fclose(fp);
X		}
X	}
X}
X
Xcheck(path, st, n, last)
X	char *path, *last;
X	register struct stat *st;
X	register struct node *n;
X{
X	switch (n->n_type) {
X	case OP_AND:
X		return  check(path, st, n->n_info.n_opnd.n_left, last) &&
X			check(path, st, n->n_info.n_opnd.n_right, last);
X	case OP_OR:
X		return  check(path, st, n->n_info.n_opnd.n_left, last) ||
X			check(path, st, n->n_info.n_opnd.n_right, last);
X	case NOT:
X		return !check(path, st, n->n_info.n_opnd.n_left, last);
X	case OP_NAME:
X		return smatch(last, n->n_info.n_str);
X	case OP_PERM:
X		if (n->n_info.n_int.n_sign < 0)
X			return st->st_mode == (int) n->n_info.n_int.n_val;
X		return (st->st_mode & 0777) == (int) n->n_info.n_int.n_val;
X	case OP_NEWER:
X		return st->st_mtime > n->n_info.n_int.n_val;
X	case OP_TYPE:
X		return (st->st_mode & S_IFMT) == n->n_info.n_int.n_val;
X	case OP_LINKS:
X		return ichk((long)(st->st_nlink), n);
X	case OP_USER:
X		return st->st_uid == n->n_info.n_int.n_val;
X	case OP_GROUP:
X		return st->st_gid == n->n_info.n_int.n_val;
X	case OP_SIZE:
X		return ichk((st->st_size == 0) ? 0L :
X			((st->st_size - 1) / BSIZE + 1), n);
X	case OP_INUM:
X		return ichk((long)(st->st_ino), n);
X	case OP_ATIME:
X		return ichk(st->st_atime, n);
X	case OP_MTIME:
X		return ichk(st->st_mtime, n);
X	case OP_EXEC:
X	case OP_OK:
X		return execute(n->n_type, n->n_info.n_exec, path);
X	case OP_PRINT:
X		prints("%s\n", path);
X		return 1;
X	}
X	fatal("ILLEGAL NODE", "");
X}
X
Xichk(val, n)
X	long val;
X	struct node *n;
X{
X	switch (n->n_info.n_int.n_sign) {
X	case 0:
X		return val == n->n_info.n_int.n_val;
X	case 1:
X		return val > n->n_info.n_int.n_val;
X	case -1:
X		return val < n->n_info.n_int.n_val;
X	}
X	fatal("internal: bad n_sign", "");
X}
X
Xlex(str)
X	char *str;
X{
X	if (str == 0)
X		return EOI;
X	if (*str == '-') {
X		register struct oper *op;
X
X		str++;
X		for (op = ops; op->op_str; op++)
X			if (strcmp(str, op->op_str) == 0)
X				break;
X		return op->op_val;
X	}
X	if (str[1] == 0) {
X		switch(*str) {
X		case '(':
X			return LPAR;
X		case ')':
X			return RPAR;
X		case '!':
X			return NOT;
X		}
X	}
X	return NONE;
X}
X
Xstruct node *
Xnewnode(t)
X{
X	struct node *n = (struct node*) Malloc(sizeof(struct node));
X
X	n->n_type = t;
X	return n;
X}
X
X/*########################### PARSER ###################################*/
X/* grammar:
X	expr : primary | primary OR expr;
X	primary : secondary | secondary AND primary | secondary primary;
X	secondary : NOT secondary | LPAR expr RPAR | simple;
X	simple : -OP args...
X*/
Xstruct node *expr(), *primary(), *secondary(), *simple();
X
Xnumber(str, base, pl, ps)
X	char *str;
X	long *pl;
X	int *ps;
X{
X	int up = '0' + base - 1;
X	long val = 0;
X
X	*ps = ((*str == '-' || *str == '+') ? ((*str++ == '-') ? -1 : 1) : 0);
X	while (*str >= '0' && *str <= up)
X		val = base * val + *str++ - '0';
X	if (*str)
X		fatal("syntax error: illegal numeric value", "");
X	*pl = val;
X}
X
Xstruct node *
Xexpr(t)
X{
X	struct node *nd, *p, *nd2;
X
X	nd = primary(t);
X	if ((t = lex(*++ipp)) == OP_OR) {
X		nd2 = expr(lex(*++ipp));
X		p = newnode(OP_OR);
X		p->n_info.n_opnd.n_left = nd;
X		p->n_info.n_opnd.n_right = nd2;
X		return p;
X	}
X	ipp--;
X	return nd;
X}
X
Xstruct node *
Xprimary(t)
X{
X	struct node *nd, *p, *nd2;
X
X	nd = secondary(t);
X	if ((t = lex(*++ipp)) != OP_AND) {
X		ipp--;
X		if (t == EOI || t == RPAR || t == OP_OR)
X			return nd;
X	}
X	nd2 = primary(lex(*++ipp));
X	p = newnode(OP_AND);
X	p->n_info.n_opnd.n_left = nd;
X	p->n_info.n_opnd.n_right = nd2;
X	return p;
X}
X
Xstruct node *
Xsecondary(t)
X{
X	struct node *n, *p;
X
X	if (t == LPAR) {
X		n = expr(lex(*++ipp));
X		if (lex(*++ipp) != RPAR)
X			fatal("syntax error, ) expected", "");
X		return n;
X	}
X	if (t == NOT) {
X		n = secondary(lex(*++ipp));
X		p = newnode(NOT);
X		p->n_info.n_opnd.n_left = n;
X		return p;
X	}
X	return simple(t);
X}
X
Xcheckarg(arg)
X	char *arg;
X{
X	if (arg == 0)
X		fatal("syntax error, argument expected", "");
X}
X
Xstruct node *
Xsimple(t)
X{
X	struct node *p = newnode(t);
X	struct exec *e;
X	struct stat est;
X	long l;
X
X	switch (t) {
X	case OP_TYPE:
X		checkarg(*++ipp);
X		switch (**ipp) {
X		case 'b':
X			p->n_info.n_int.n_val = S_IFBLK;
X			break;
X		case 'c':
X			p->n_info.n_int.n_val = S_IFCHR;
X			break;
X		case 'd':
X			p->n_info.n_int.n_val = S_IFDIR;
X			break;
X		case 'f':
X			p->n_info.n_int.n_val = S_IFREG;
X			break;
X		default:
X			fatal("-type needs b, c, d or f", "");
X		}
X		break;
X	case OP_LINKS:
X	case OP_USER:
X	case OP_GROUP:
X	case OP_SIZE:
X	case OP_INUM:
X	case OP_PERM:
X		checkarg(*++ipp);
X		number(*ipp, (t == OP_PERM) ? 8 : 10, &(p->n_info.n_int.n_val),
X			&(p->n_info.n_int.n_sign));
X		break;
X	case OP_ATIME:
X	case OP_MTIME:
X		checkarg(*++ipp);
X		number(*ipp, 10, &l, &(p->n_info.n_int.n_sign));
X		p->n_info.n_int.n_val = current_time - l * SECS_PER_DAY;
X		/* more than n days old means less than the absolute time */
X		p->n_info.n_int.n_sign *= -1;
X		break;
X	case OP_EXEC:
X	case OP_OK:
X		checkarg(*++ipp);
X		e = (struct exec *)Malloc(sizeof(struct exec));
X		e->e_cnt = 2;
X		e->e_vec[0] = SHELL;
X		p->n_info.n_exec = e;
X		while (*ipp) {
X			if (**ipp == ';' && (*ipp)[1] == '\0') {
X				e->e_vec[e->e_cnt] = 0;
X				break;
X			}
X			e->e_vec[(e->e_cnt)++] = 
X				(**ipp == '{' && (*ipp)[1] == '}'
X				&& (*ipp)[2] == '\0') ? (char *)(-1) : *ipp;
X			ipp++;
X		}
X		if (*ipp == 0)
X			fatal("-exec/-ok: ; missing", "");
X		if ((e->e_vec[1] = find_bin(e->e_vec[2])) == 0)
X			fatal("can't find program ", e->e_vec[2]);
X		if (t == OP_OK)
X			if ((tty = open("/dev/tty", 2)) < 0)
X				fatal("can't open /dev/tty", "");
X		break;
X	case OP_NEWER:
X		checkarg(*++ipp);
X		if (stat(*ipp, &est) == -1)
X			fatal("-newer: can't get status of ", *ipp);
X		p->n_info.n_int.n_val = est.st_mtime;
X		break;
X	case OP_NAME:
X		checkarg(*++ipp);
X		p->n_info.n_str = *ipp;
X		break;
X	case OP_PRINT:
X		break;
X	default:
X		fatal("syntax error, operator expected", "");
X	}
X	return p;
X}
X
X/*######################## DIAGNOSTICS ##############################*/
X
Xnonfatal(s1, s2)
X	char *s1, *s2;
X{
X	std_err(prog);
X	std_err(": ");
X	std_err(s1);
X	std_err(s2);
X	std_err("\n");
X}
X
Xfatal(s1, s2)
X	char *s1, *s2;
X{
X	nonfatal(s1, s2);
X	exit(1);
X}
X
X/*################### SMATCH #########################*/
X/* Don't try to understand the following one... */
Xsmatch(s, t)	/* shell-like matching */
X	char *s, *t;
X{
X	register n;
X
X	if (*t == '\0')
X		return *s == '\0';
X	if (*t == '*') {
X		++t;
X		do
X			if (smatch(s,t))
X				return 1;
X		while (*s++ != '\0');
X		return 0;
X	}
X	if (*s == '\0') 
X		return 0;
X	if (*t == '\\')
X		return (*s == *++t) ? smatch(++s, ++t) : 0;
X	if (*t == '?')
X		return smatch(++s, ++t);
X	if (*t == '[') {
X		while (*++t != ']') {
X			if (*t == '\\')
X				++t;
X			if (*(t+1) != '-')
X				if (*t == *s) {
X					while (*++t != ']')
X						if (*t == '\\')
X							++t;
X					return smatch(++s, ++t);
X				}
X				else
X					continue;
X			if (*(t+2) == ']')
X				return (*s == *t || *s == '-');
X			n =  (*(t+2) == '\\') ? 3 : 2;
X			if (*s >= *t && *s <= *(t+n)) {
X				while (*++t != ']')
X					if (*t == '\\')
X						++t;
X				return smatch(++s, ++t);
X			}
X			t += n;
X		}
X		return 0;
X	}
X	return  (*s == *t) ? smatch(++s, ++t) : 0;
X}
X
X/*####################### EXECUTE ###########################*/
X/* do -exec or -ok */
X
Xchar *epath = 0;
X
Xchar *
Xgetpath()
X{
X	extern char **environ;
X	register char **e = environ;
X
X	if (epath)	/* retrieve PATH only once */
X		return epath;
X	while (*e) {
X		if (strncmp("PATH=", *e, 5) == 0) {
X			return epath = *e + 5;
X		}
X		e++;
X	}
X	fatal("can't get PATH from environment", "");
X}
X
Xchar *
Xfind_bin(s)
X	char *s;
X{
X	char *f, *l, buf[PLEN];
X	
X	if (*s == '/') /* absolute path name */
X		return (access(s, 1) == 0) ? s : 0;
X	l = f = getpath();
X	for (;;) {
X		if (*l == ':' || *l == 0) {
X			if (l == f) {
X				if (access(s, 1) == 0)
X					return Salloc(s);
X				f++;
X			}
X			else {
X				register char *p = buf, *q = s;
X
X				while (f != l)
X					*p++ = *f++;
X				f++;
X				*p++ = '/';
X				while (*p++ = *q++) {}
X				if (access(buf, 1) == 0)
X					return Salloc(buf);
X			}
X			if (*l == 0)
X				break;
X		}
X		l++;
X	}
X	return 0;
X}
X
Xexecute(op, e, path)
X	struct exec *e;
X	char *path;
X{
X	int s, pid;
X	char *argv[MAXARG];
X	register char **p, **q;
X
X	for (p = e->e_vec, q = argv; *p;) /* replace the {}s */
X		if ((*q++ = *p++) == (char *)-1)
X			q[-1] = path;
X	*q = '\0';
X	if (op == OP_OK) {
X		char answer[10];
X
X		for (p = &argv[2]; *p; p++) {
X			write(tty, *p, strlen(*p));
X			write(tty, " ", 1);
X		}
X		write(tty, "? ", 2);
X		if (read(tty, answer, 10) < 2 || *answer != 'y')
X			return 0;
X	}
X	if ((pid = fork()) == -1)
X		fatal("can't fork", "");
X	if (pid == 0) {
X		register i = 3;
X
X		while (close(i++) == 0) {}		/* wow!!! */
X		execv(argv[1], &argv[2]);	/* binary itself? */
X		execv(argv[0], &argv[1]);	/* shell command? */
X		fatal("exec failure: ", argv[1]);	/* none of them! */
X		exit(127);
X	}
X	return wait(&s) == pid && s == 0;
X}
+ END-OF-FILE find.c
chmod 'u=rw,g=r,o=r' \f\i\n\d\.\c
set `sum \f\i\n\d\.\c`
sum=$1
case $sum in
24425)	:;;
*)	echo 'Bad sum in '\f\i\n\d\.\c >&2
esac
echo Extracting \m\o\r\e\.\c
sed 's/^X//' > \m\o\r\e\.\c << '+ END-OF-FILE '\m\o\r\e\.\c
X/* more - terminal pager		Author: Brandon S. Allbery  */
X
X/* Pager commands:
X *	<space>	 display next page
X *	<return> scroll up 1 line
X *	q	 quit
X*/
X
X#define reverse()	write(1, "\033z\160", 3)	/* reverse video */
X#define normal()	write(1, "\033z\7", 3)		/* undo reverse() */
X#define clearln()	write(1, "\r\033~0", 4)		/* clear line */
X
X#define LINES		23	/* lines/screen (- 1 to retain last line) */
X#define COLS		80	/* columns/line */
X#define TABSTOP		8	/* tabstop expansion */
X
X#include <sgtty.h>
X#include <signal.h>
X
Xextern int byebye();
Xextern char *index();
X
Xint line = 0;			/* current terminal line */
Xint col = 0;			/* current terminal column */
Xint fd = -1;			/* terminal file descriptor (/dev/tty) */
Xstruct sgttyb ttymode;		/* and the terminal modes */
Xchar ibuf[1024];		/* input buffer */
Xchar obuf[1024];		/* output buffer */
Xint ibl = 0;			/* chars in input buffer */
Xint ibc = 0;			/* position in input buffer */
Xint obc = 0;			/* position in output buffer (== chars in) */
Xint isrewind = 0;		/* flag: ' command -- next input() rewind */
Xint isdone = 0;			/* flag: return EOF next read even if not */
X
Xmain(argc, argv)
Xchar **argv; {
X	char ch;
X	int fd, arg;
X
X	signal(SIGINT, byebye);
X	fd = 0;
X	cbreak();
X	if (argc < 2)
X		while ((ch = input(fd)) != 0)
X			output(ch);
X	else
X		for (arg = 1; argv[arg] != (char *) 0; arg++) {
X			if ((fd = open(argv[arg], 0)) == -1) {
X				write(1, "more: cannot open ", 18);
X				write(1, argv[arg], strlen(argv[arg]));
X				write(1, "\n", 1);
X				nocbreak();
X				exit(1);
X			}
X			while ((ch = input(fd)) != 0)
X				output(ch);
X			close(fd);
X			if (argv[arg + 1] != (char *) 0) {
X				oflush();
X				if (isdone) {	/* 'n' command */
X					reverse();
X					write(1, "*** Skipping to next file ***\n", 30);
X					normal();
X					isdone = 0;
X				}
X				reverse();
X				write(1, "--More-- (Next file: ", 21);
X				write(1, argv[arg + 1], strlen(argv[arg + 1]));
X				write(1, ")", 1);
X				normal();
X				switch (wtch()) {
X				case ' ':
X				case '\'':
X				case 'n':
X				case 'N':
X					line = 0;
X					break;
X				case '\r':
X				case '\n':
X					line = LINES - 1;
X					break;
X				case 'q':
X				case 'Q':
X					clearln();
X					byebye();
X				}
X				clearln();
X			}
X		}
X	oflush();
X	byebye();
X}
X
Xinput(fd) {
X	if (isdone) {
X		ibl = 0;
X		ibc = 0;
X		return 0;
X	}
X	if (isrewind) {
X		lseek(fd, 0L, 0);
X		ibl = 0;
X		ibc = 0;
X		isrewind = 0;
X	}
X	if (ibc == ibl) {
X		ibc = 0;
X		if ((ibl = read(fd, ibuf, sizeof ibuf)) <= 0)
X			return 0;
X	}
X	return ibuf[ibc++];
X}
X
Xoutput(c)
Xchar c; {
X	if (obc == sizeof obuf) {
X		lwrite(1, obuf, sizeof obuf);
X		obc = 0;
X	}
X	if (!isrewind)
X		obuf[obc++] = c;
X}
X
Xoflush() {
X	if (!isdone)
X		lwrite(1, obuf, obc);
X	obc = 0;
X}
X
Xlwrite(fd, buf, len)
Xchar *buf;
Xunsigned len; {
X	unsigned here, start;
X	char cmd;
X
X	start = 0;
X	here = 0;
X	while (here != len) {
X		cmd = '\0';
X		switch (buf[here++]) {
X		case '\n':
X			col = 0;
X			if (++line == LINES) {
X				write(fd, buf + start, here - start);
X				reverse();
X				write(1, "--More--", 8);
X				normal();
X				cmd = wtch();
X				clearln();
X				line = 0;
X				start = here;
X			}
X			break;
X		case '\r':
X			col = 0;
X			break;
X		case '\b':
X			if (col != 0)
X				col--;
X			else {
X				line--;
X				col = COLS - 1;
X			}
X			break;
X		case '\t':
X			do {
X				col++;
X			} while (col % TABSTOP != 0);
X			break;
X		default:
X			if (++col == COLS) {
X				col = 0;
X				if (++line == LINES) {
X					write(fd, buf + start, here - start);
X					reverse();
X					write(1, "--More--", 8);
X					normal();
X					cmd = wtch();
X					clearln();
X					line = 0;
X					start = here;
X				}
X			}
X		}
X		switch (cmd) {
X		case '\0':
X			break;
X		case ' ':
X			line = 0;
X			break;
X		case '\r':
X		case '\n':
X			line = LINES - 1;
X			break;
X		case 'q':
X		case 'Q':
X			byebye();
X		case '\'':
X			isrewind = 1;
X			reverse();
X			write(1, "*** Back ***\n", 13);
X			normal();
X			return;
X		case 'n':
X		case 'N':
X			isdone = 1;
X			return;
X		default:
X			break;
X		}
X	}
X	if (here != start)
X		write(fd, buf + start, here - start);
X}
X
Xwtch() {
X	char ch;
X
X	do {
X		read(fd, &ch, 1);
X	} while (index(" \r\nqQ'nN", ch) == (char *) 0);
X	return ch;
X}
X
Xcbreak() {
X	if (fd != -1)
X		return;
X	if ((fd = open("/dev/tty", 0)) == -1) {
X		write(2, "OOPS -- can't open /dev/tty\n", 28);
X		exit(1);
X	}
X	ioctl(fd, TIOCGETP, &ttymode);
X	ttymode.sg_flags |= CBREAK;
X	ttymode.sg_flags &= ~ECHO;
X	ioctl(fd, TIOCSETP, &ttymode);	/* NB: add TIOCSETN! */
X}
X
Xnocbreak() {
X	if (fd == -1)
X		return;
X	ttymode.sg_flags &= ~CBREAK;
X	ttymode.sg_flags |= ECHO;
X	ioctl(fd, TIOCSETP, &ttymode);
X	close(fd);
X	fd = -1;
X}
X
Xbyebye() {
X	nocbreak();
X	exit(0);
X}
+ END-OF-FILE more.c
chmod 'u=rw,g=r,o=r' \m\o\r\e\.\c
set `sum \m\o\r\e\.\c`
sum=$1
case $sum in
58691)	:;;
*)	echo 'Bad sum in '\m\o\r\e\.\c >&2
esac
echo Extracting \p\o\p\e\n\.\c
sed 's/^X//' > \p\o\p\e\n\.\c << '+ END-OF-FILE '\p\o\p\e\n\.\c
X#include <stdio.h>
X#include <signal.h>
X
Xstatic int pids[20];
X
XFILE *
Xpopen(command, type)
X	char *command, *type;
X{
X	int piped[2];
X	int Xtype = *type == 'r' ? 0 : *type == 'w' ? 1 : 2;
X	int pid;
X
X	if (Xtype == 2 ||
X	    pipe(piped) < 0 ||
X	    (pid = fork()) < 0) return 0;
X	
X	if (pid == 0) {
X		/* child */
X		register int *p;
X
X		for (p = pids; p < &pids[20]; p++) {
X			if (*p) close(p - pids);
X		}
X		close(piped[Xtype]);
X		dup2(piped[!Xtype], !Xtype);
X		close(piped[!Xtype]);
X		execl("/bin/sh", "sh", "-c", command, (char *) 0);
X		_exit(127);	/* like system() ??? */
X	}
X
X	pids[piped[Xtype]] = pid;
X	close(piped[!Xtype]);
X	return fdopen(piped[Xtype], type);
X}
X
Xpclose(iop)
X	FILE *iop;
X{
X	int fd = fileno(iop);
X	int status, wret;
X	int (*intsave)() = signal(SIGINT, SIG_IGN);
X	int (*quitsave)() = signal(SIGQUIT, SIG_IGN);
X
X	fclose(iop);
X	while ((wret = wait(&status)) != -1) {
X		if (wret == pids[fd]) break;
X	}
X	if (wret == -1) status = -1;
X	signal(SIGINT, intsave);
X	signal(SIGQUIT, quitsave);
X	pids[fd] = 0;
X	return status;
X}
+ END-OF-FILE popen.c
chmod 'u=rw,g=r,o=r' \p\o\p\e\n\.\c
set `sum \p\o\p\e\n\.\c`
sum=$1
case $sum in
19198)	:;;
*)	echo 'Bad sum in '\p\o\p\e\n\.\c >&2
esac
echo Extracting \p\r\i\n\t\e\n\v\.\c
sed 's/^X//' > \p\r\i\n\t\e\n\v\.\c << '+ END-OF-FILE '\p\r\i\n\t\e\n\v\.\c
X/* printenv - print the current environment	Author: Richard Todd */
X
Xmain ()
X{
X  extern char **environ;
X  char **sptr;
X  for (sptr = environ ; *sptr ; ++sptr) {
X	prints("%s\n",*sptr);
X  }
X}
+ END-OF-FILE printenv.c
chmod 'u=rw,g=r,o=r' \p\r\i\n\t\e\n\v\.\c
set `sum \p\r\i\n\t\e\n\v\.\c`
sum=$1
case $sum in
25077)	:;;
*)	echo 'Bad sum in '\p\r\i\n\t\e\n\v\.\c >&2
esac
echo Extracting \p\u\t\s\.\c
sed 's/^X//' > \p\u\t\s\.\c << '+ END-OF-FILE '\p\u\t\s\.\c
X#include "stdio.h"
X
Xint puts(s)
Xchar *s;
X{
X    char c;
X
X    c = fputs(s,stdout);
X    putchar('\n');
X    return(c);
X}
+ END-OF-FILE puts.c
chmod 'u=rw,g=r,o=r' \p\u\t\s\.\c
set `sum \p\u\t\s\.\c`
sum=$1
case $sum in
09591)	:;;
*)	echo 'Bad sum in '\p\u\t\s\.\c >&2
esac
echo Extracting \q\s\o\r\t\.\c
sed 's/^X//' > \q\s\o\r\t\.\c << '+ END-OF-FILE '\q\s\o\r\t\.\c
Xstatic	qsort1();
Xstatic	int (*qcompar)();
Xstatic	qexchange();
Xstatic	q3exchange();
X
Xqsort(base, nel, width, compar)
X	char *base;
X	int (*compar)();
X{
X	qcompar = compar;
X	qsort1(base, base + (nel - 1) * width, width);
X}
X
Xstatic
Xqsort1(a1, a2, width)
X	char *a1, *a2;
X	register int width;
X{
X	register char *left, *right;
X	register char *lefteq, *righteq;
X	int cmp;
X
X	for (;;) {
X		if (a2 <= a1) return;
X		left = a1;
X		right = a2;
X		lefteq = righteq = a1 + width * (((a2-a1)+width)/(2*width));
X		/*
X		   Pick an element in the middle of the array.
X		   We will collect the equals around it.
X		   "lefteq" and "righteq" indicate the left and right
X		   bounds of the equals respectively.
X		   Smaller elements end up left of it, larger elements end
X		   up right of it.
X		*/
Xagain:
X		while (left < lefteq && (cmp = (*qcompar)(left, lefteq)) <= 0) {
X			if (cmp < 0) {
X				/* leave it where it is */
X				left += width;
X			}
X			else {
X				/* equal, so exchange with the element to
X				   the left of the "equal"-interval.
X				*/
X				lefteq -= width;
X				qexchange(left, lefteq, width);
X			}
X		}
X		while (right > righteq) {
X			if ((cmp = (*qcompar)(right, righteq)) < 0) {
X				/* smaller, should go to left part
X				*/
X				if (left < lefteq) {
X					/* yes, we had a larger one at the
X					   left, so we can just exchange
X					*/
X					qexchange(left, right, width);
X					left += width;
X					right -= width;
X					goto again;
X				}
X				/* no more room at the left part, so we
X				   move the "equal-interval" one place to the
X				   right, and the smaller element to the
X				   left of it.
X				   This is best expressed as a three-way
X				   exchange.
X				*/
X				righteq += width;
X				q3exchange(left, righteq, right, width);
X				lefteq += width;
X				left = lefteq;
X			}
X			else if (cmp == 0) {
X				/* equal, so exchange with the element to
X				   the right of the "equal-interval"
X				*/
X				righteq += width;
X				qexchange(right, righteq, width);
X			}
X			else	/* just leave it */ right -= width;
X		}
X		if (left < lefteq) {
X			/* larger element to the left, but no more room,
X			   so move the "equal-interval" one place to the
X			   left, and the larger element to the right
X			   of it.
X			*/
X			lefteq -= width;
X			q3exchange(right, lefteq, left, width);
X			righteq -= width;
X			right = righteq;
X			goto again;
X		}
X		/* now sort the "smaller" part */
X		qsort1(a1, lefteq - width, width);
X		/* and now the larger, saving a subroutine call
X		   because of the for(;;)
X		*/
X		a1 = righteq + width;
X	}
X	/*NOTREACHED*/
X}
X
Xstatic
Xqexchange(p, q, n)
X	register char *p, *q;
X	register int n;
X{
X	register int c;
X
X	while (n-- > 0) {
X		c = *p;
X		*p++ = *q;
X		*q++ = c;
X	}
X}
X
Xstatic
Xq3exchange(p, q, r, n)
X	register char *p, *q, *r;
X	register int n;
X{
X	register int c;
X
X	while (n-- > 0) {
X		c = *p;
X		*p++ = *r;
X		*r++ = *q;
X		*q++ = c;
X	}
X}
+ END-OF-FILE qsort.c
chmod 'u=rw,g=r,o=r' \q\s\o\r\t\.\c
set `sum \q\s\o\r\t\.\c`
sum=$1
case $sum in
12247)	:;;
*)	echo 'Bad sum in '\q\s\o\r\t\.\c >&2
esac
echo Extracting \s\y\s\t\e\m\.\c
sed 's/^X//' > \s\y\s\t\e\m\.\c << '+ END-OF-FILE '\s\y\s\t\e\m\.\c
X#include	<stdio.h>
X
X#ifndef NIL
X#define NIL 0
X#endif
X
X
Xsystem( cmd )
Xchar *cmd;
X{
X    int retstat, procid, waitstat;
X
X    if( (procid = fork()) == 0 )
X    {
X        execl( "/bin/sh", "sh", "-c", cmd, NIL );
X        exit( 127 );
X    }
X
X    while( (waitstat = wait(&retstat)) != procid && waitstat != -1 )
X        ;
X    if (waitstat == -1)
X        retstat = -1;
X
X    return( retstat );
X}
+ END-OF-FILE system.c
chmod 'u=rw,g=r,o=r' \s\y\s\t\e\m\.\c
set `sum \s\y\s\t\e\m\.\c`
sum=$1
case $sum in
00456)	:;;
*)	echo 'Bad sum in '\s\y\s\t\e\m\.\c >&2
esac
exit 0