Ultrix-3.1/sys/sas/SYS.c

Compare this file to the similar file:
Show the results in this format:

/*
 * SCCSID: @(#)SYS.c	3.0	4/21/86
 */
/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/
/*
 * ULTRIX-11 standalone bootstrap I/O routines
 *
 * IMPORTANT CHANGE -- Fred Canter 6/20/85
 *
 * The stand-alone programs now can only access files with
 * up to one indirect block, i.e., 260K bytes. This change was
 * necessary to shrink the stand-alone programs back to the
 * size they were before the 1K file system was implemented.
 * See code changes in sbmap() and saio.h.
 * These routines are not used in two different ways:
 *
 * 1.	Boot: uses them in /lib/libsa.a as before.
 *
 * 2.	All other standalone programs have the system calls
 *	and device drivers removed from /lib/libsa.a, only
 *	the prf.o, exit, and trap routines are used from /lib/libsa.a.
 *
 * The syscalls and drivers are now in the file syscall.
 * When creating /lib/libsa.a and the syscall file, the parameter
 * NOSYSCALL is not defined and all code is compiled.
 * When creating a standalone program, NOSYSCALL is defined and
 * the code for the system calls is not compiled.
 * See /usr/sys/sas/README for more information.
 *
 * #ifdef NO_FIO
 *
 *	NO_FIO is defined when building programs like rabads
 *	that only access physical devices and don't need all the
 *	code and buffers used to deal with the file system.
 */
#include <sys/param.h>
#include <sys/ino.h>
#include <sys/inode.h>
#include <sys/filsys.h>
#include <sys/dir.h>
#ifndef	NOSYSCALL
#include "saio.h"

/* int	segflag = 0; */


static
openi(n,io)
register struct iob *io;
{
	register struct dinode *dp;
#ifdef	UCB_NKB
	daddr_t	tdp;
#endif	UCB_NKB

	io->i_offset = 0;
#ifdef	UCB_NKB
	tdp = itod(n);
	io->i_bn = fsbtodb(tdp) + io->i_boff;
	io->i_cc = BSIZE;
#else
	io->i_bn = (daddr_t)((n+15)/INOPB) + io->i_boff;
	io->i_cc = 512;
#endif	UCB_NKB
	io->i_ma = io->i_buf;
	devread(io);

	dp = io->i_buf;
#ifdef	UCB_NKB
	dp = &dp[itoo(n)];
#else
	dp = &dp[(n-1)%INOPB];
#endif	UCB_NKB
	io->i_ino.i_number = n;
	io->i_ino.i_mode = dp->di_mode;
	io->i_ino.i_size = dp->di_size;
	l3tol((char *)io->i_ino.i_addr,(char *)dp->di_addr,NADDR);
}


#ifndef	NO_FIO
static
find(path, file)
register char *path;
struct iob *file;
{
	register char *q;
	char c;
	int n;

	if (path==NULL || *path=='\0') {
		printf("null path\n");
		return(0);
	}

	openi((ino_t) 2, file);
	while (*path) {
		while (*path == '/')
			path++;
		q = path;
		while(*q != '/' && *q != '\0')
			q++;
		c = *q;
		*q = '\0';

		if ((n=dlook(path, file))!=0) {
			if (c=='\0')
				break;
			openi(n, file);
			*q = c;
			path = q;
			continue;
		} else {
			printf("%s not found\n",path);
			return(0);
		}
	}
	return(n);
}


static daddr_t
sbmap(io, bn)
register struct iob *io;
daddr_t bn;
{
	register i;
	register struct inode *ip;
	int j, sh;
	daddr_t nb, *bap;

/*
 * Clear blknos[], in case it should ever get reused.
 */
	for(j=0; j<NBUFS; j++)
		blknos[j] = 0L;
	ip = &io->i_ino;;
	if(bn < 0) {
		printf("bn negative\n");
		return((daddr_t)0);
	}

	/*
	 * blocks 0..NADDR-4 are direct blocks
	 */
	if(bn < NADDR-3) {
		i = bn;
		nb = ip->i_addr[i];
		return(nb);
	}

	/*
	 * addresses NADDR-3, NADDR-2, and NADDR-1
	 * have single, double, triple indirect blocks.
	 * the first step is to determine
	 * how many levels of indirection.
	 * CAN ONLY HANDLE FILES WITH SINGLE INDIRECT BLOCK
	 */
	sh = 0;
	nb = 1;
	bn -= NADDR-3;
	for(j=3; j>0; j--) {
		sh += NSHIFT;
		nb <<= NSHIFT;
		if(bn < nb)
			break;
		bn -= nb;
	}
#ifdef	UCB_NKB
	if(j != 3) {	/* must be single indirect block (j == 3) */
#else
	if(j == 0) {
#endif	UCB_NKB
		printf("bn ovf %D\n",bn);
		return((daddr_t)0);
	}

	/*
	 * fetch the address from the inode
	 */
	nb = ip->i_addr[NADDR-j];
	if(nb == 0) {
		printf("bn void %D\n",bn);
		return((daddr_t)0);
	}

	/*
	 * fetch through the indirect blocks
	 */
	for(; j<=3; j++) {
#ifdef	UCB_NKB
		if (blknos[0] != nb) {
			io->i_bn = fsbtodb(nb) + io->i_boff;
			io->i_ma = &sbmapb;
			io->i_cc = BSIZE;
#else
		if (blknos[j] != nb) {
			io->i_bn = nb + io->i_boff;
			io->i_ma = sbmapb[j];
			io->i_cc = 512;
#endif	UCB_NKB
			devread(io);
#ifdef	UCB_NKB
			blknos[0] = nb;
#else
			blknos[j] = nb;
#endif	UCB_NKB
		}
#ifdef	UCB_NKB
		bap = &sbmapb;
#else
		bap = sbmapb[j];
#endif	UCB_NKB
		sh -= NSHIFT;
		i = (bn>>sh) & NMASK;
		nb = bap[i];
		if(nb == 0) {
			printf("bn void %D\n",bn);
			return((daddr_t)0);
		}
	}

	return(nb);
}

static ino_t
dlook(s, io)
char *s;
register struct iob *io;
{
	register struct direct *dp;
	register struct inode *ip;
	daddr_t bn;
	int n,dc;
#ifdef	UCB_NKB
	daddr_t	tbn;
#endif	UCB_NKB

	if (s==NULL || *s=='\0')
		return(0);
	ip = &io->i_ino;
	if ((ip->i_mode&IFMT)!=IFDIR) {
		printf("not a directory\n");
		return(0);
	}

	n = ip->i_size/sizeof(struct direct);

	if (n==0) {
		printf("zero length directory\n");
		return(0);
	}

#ifdef	UCB_NKB
	dc = BSIZE;
	bn = (daddr_t)0;
	while(n--) {
		if (++dc >= BSIZE/sizeof(struct direct)) {
			tbn = sbmap(io,bn++);
			io->i_bn = fsbtodb(tbn) + io->i_boff;
			io->i_ma = io->i_buf;
			io->i_cc = BSIZE;
#else
	dc = 512;
	bn = (daddr_t)0;
	while(n--) {
		if (++dc >= 512/sizeof(struct direct)) {
			io->i_bn = sbmap(io, bn++) + io->i_boff;
			io->i_ma = io->i_buf;
			io->i_cc = 512;
#endif	UCB_NKB
			devread(io);
			dp = io->i_buf;
			dc = 0;
		}

		if (match(s, dp->d_name))
			return(dp->d_ino);
		dp++;
	}
	return(0);
}
#endif	NO_FIO

static
match(s1,s2)
register char *s1,*s2;
{
	register cc;

	cc = DIRSIZ;
	while (cc--) {
		if (*s1 != *s2)
			return(0);
		if (*s1++ && *s2++)
			continue; else
			return(1);
	}
	return(1);
}

lseek(fdesc, addr, ptr)
int	fdesc;
off_t	addr;
int	ptr;
{
	register struct iob *io;

	if (ptr != 0) {
		printf("Seek not from beginning of file\n");
		return(-1);
	}
	fdesc -= 3;
	if (fdesc < 0 || fdesc >= NFILES || ((io = &iob[fdesc])->i_flgs&F_ALLOC) == 0)
		return(-1);
	io->i_offset = addr;
#ifdef	UCB_NKB
	if((io->i_flgs&F_FILE) == 0)
		io->i_bn = addr/512 + io->i_boff;
	else
		io->i_bn = fsbtodb(addr/BSIZE) + io->i_boff;
#else
	io->i_bn = addr/512 + io->i_boff;
#endif	UCB_NKB
	io->i_cc = 0;
	return(0);
}

getc(fdesc)
int	fdesc;
{
	register struct iob *io;
	register unsigned char *p;
	register  c;
	int off;
#ifdef	UCB_NKB
	daddr_t	tbn;
	int	mtfile;	/* file being read from a magtape */
#endif	UCB_NKB


	if (fdesc >= 0 && fdesc <= 2)
		return(getchar());
#ifdef	NO_FIO
	return(-1);
#else
	fdesc -= 3;
	if (fdesc < 0 || fdesc >= NFILES || ((io = &iob[fdesc])->i_flgs&F_ALLOC) == 0)
		return(-1);
#ifdef	UCB_NKB
	mtfile = devsw[io->i_ino.i_dev].dv_flags&DV_TAPE;
#endif	UCB_NKB
	p = io->i_ma;
	if (io->i_cc <= 0) {
#ifdef	UCB_NKB
		/*
		 * The block number is not used by tape drivers,
		 * but it might be used someday, so we deal with it.
		 */
		if(mtfile)
			io->i_bn = io->i_offset/(off_t)512;
		else
			io->i_bn = fsbtodb(io->i_offset/(off_t)BSIZE);
		if (io->i_flgs&F_FILE) {
			tbn = sbmap(io, dbtofsb(io->i_bn));
			io->i_bn = fsbtodb(tbn) + io->i_boff;
		}
		io->i_ma = io->i_buf;
		if(mtfile)
			io->i_cc = 512;
		else
			io->i_cc = BSIZE;
		devread(io);
		if (io->i_flgs&F_FILE) {
			off = io->i_offset % (off_t)BSIZE;
			if (io->i_offset+(BSIZE-off) >= io->i_ino.i_size)
#else
		io->i_bn = io->i_offset/(off_t)512;
		if (io->i_flgs&F_FILE)
			io->i_bn = sbmap(io, io->i_bn) + io->i_boff;
		io->i_ma = io->i_buf;
		io->i_cc = 512;
		devread(io);
		if (io->i_flgs&F_FILE) {
			off = io->i_offset % (off_t)512;
			if (io->i_offset+(512-off) >= io->i_ino.i_size)
#endif	UCB_NKB
				io->i_cc = io->i_ino.i_size - io->i_offset + off;
			io->i_cc -= off;
			if (io->i_cc <= 0)
				return(-1);
		} else
			off = 0;
		p = &io->i_buf[off];
	}
	io->i_cc--;
	io->i_offset++;
	c = *p++;
	io->i_ma = p;
	return(c);
#endif	NO_FIO
}
getw(fdesc)
int	fdesc;
{
	register w,i;
	register char *cp;
	int val;

	for (i = 0, val = 0, cp = &val; i < sizeof(val); i++) {
		w = getc(fdesc);
		if (w == -1) {
			if (i == 0)
				return(-1);
			else
				return(val);
		}
		*cp++ = w;
	}
	return(val);
}

read(fdesc, buf, count)
int	fdesc;
char	*buf;
int	count;
{
	register i;
	register struct iob *file;

	if (fdesc >= 0 && fdesc <= 2) {
		i = count;
		do {
			*buf = getchar();
		} while (--i && *buf++ != '\n');
		return(count - i);
	}
	fdesc -= 3;
	if (fdesc < 0 || fdesc >= NFILES || ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0)
		return(-1);
	if ((file->i_flgs&F_READ) == 0)
		return(-1);
	if ((file->i_flgs&F_FILE) == 0) {
		file->i_cc = count;
		file->i_ma = buf;
		i = devread(file);
/*
 * Following code was in error and caused continuous
 * read/write of a device to fail, i.e., a lseek needed
 * prior to each read/write. We always deal with physical
 * device in 512 byte chuncks, so CLSIZE not used.
 * All program have the lseeks, no reason to remove them.
 *
#ifdef	UCB_NKB
		file->i_bn += CLSIZE;
#else
		file->i_bn++;
#endif	UCB_NKB
 *
 * END OF OLD CODE
 */
		file->i_bn += (i/512);
		return(i);
	}
	else {
		if (file->i_offset+count > file->i_ino.i_size)
			count = file->i_ino.i_size - file->i_offset;
		if ((i = count) <= 0)
			return(0);
		do {
			*buf++ = getc(fdesc+3);
		} while (--i);
		return(count);
	}
}

write(fdesc, buf, count)
int	fdesc;
char	*buf;
int	count;
{
	register i;
	register struct iob *file;

	if (fdesc >= 0 && fdesc <= 2) {
		i = count;
		while (i--)
			putchar(*buf++);
		return(count);
	}
	fdesc -= 3;
	if (fdesc < 0 || fdesc >= NFILES || ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0)
		return(-1);
	if ((file->i_flgs&F_WRITE) == 0)
		return(-1);
	file->i_cc = count;
	file->i_ma = buf;
	i = devwrite(file);
/*
 * See comment above same statement in read().
#ifdef	UCB_NKB
	file->i_bn += CLSIZE;
#else
	file->i_bn++;
#endif	UCB_NKB
*/
	file->i_bn += (i/512);
	return(i);
}

/*
 * Names of files that can be loaded from magtape,
 * position in the list must be that same as their
 * position on the tape.
 *
 * !!!!!! ORDER MUST MATCH TADE DIRECTORY FILES IN /SAS !!!!!!
 */

static	char	*mtfiles[] =
{
	"boot",
	"syscall",
	"sdload",
	"scat",
	"contents",
	"mkfs",
	"restor",
	"dskinit",
	"bads",
	"rabads",
	"copy",
	"icheck",
	"saprog",
	"rcmds",
	"f77",
	"pascal",
	"plot",
	"sccs",
	"usat",
	"usep",
	"tcpip",
	"uucp",
	"spell",
	"userdev",
	"docprep",
	"learn",
	"libsa",
	"dict",
	"orphans",
	"games",
	"manuals",
	"sysgen",
	"root",
	"usr",
	0
};

open(str, how)
char *str;
int	how;
{
	register char *cp;
	int i;
	register struct iob *file;
	register struct devsw *dp;
	int	fdesc;
	static first = 1;
	int	c;
	long	atol();

	if (first) {
		for (i = 0; i < NFILES; i++)
			iob[i].i_flgs = 0;
		first = 0;
	}

	for (fdesc = 0; fdesc < NFILES; fdesc++)
		if (iob[fdesc].i_flgs == 0)
			goto gotfile;
	_stop("No more file slots");
gotfile:
	(file = &iob[fdesc])->i_flgs |= F_ALLOC;
	for (cp = str; *cp && *cp != '('; cp++)
			;
	if (*cp != '(') {
		printf("Bad device\n");
		file->i_flgs = 0;
		return(-1);
	}
	*cp++ = '\0';
	for (dp = devsw; dp->dv_name; dp++) {
		if (match(str, dp->dv_name))
			goto gotdev;
	}
	printf("Unknown device\n");
	file->i_flgs = 0;
	return(-1);
gotdev:
	*(cp-1) = '(';
	file->i_ino.i_dev = dp-devsw;
	file->i_unit = *cp++ - '0';
	if (file->i_unit < 0 || file->i_unit > 7) {
		printf("Bad unit specifier\n");
		file->i_flgs = 0;
		return(-1);
	}
	if (*cp++ != ',') {
badoff:
		printf("Missing offset specification\n");
		file->i_flgs = 0;
		return(-1);
	}
	file->i_boff = atol(cp);
	for (;;) {
		if (*cp == ')')
			break;
		if (*cp++)
			continue;
		goto badoff;
	}
/*
 * Files may be loaded from magtape either by offset
 * or by name. If the offset is zero the "mtfiles" table
 * is serarched to find the offset. If the offset is not
 * zero, it is used and the name is ignored. If the offset
 * is zero and the name is zero, the offset is used, i.e., ht(0,0).
 */
	if(dp->dv_flags&DV_TAPE) {
		c = *(cp+1);	/* save first char of file name */
		if(file->i_boff != 0)
			*(cp+1) = '\0';
		else if((file->i_boff == 0) && *(cp+1)) {
			for(i=0; mtfiles[i]; i++)
				if(match((cp+1), mtfiles[i])) {
					file->i_boff = i;
					*(cp+1) = '\0';
					break;
				}
			if(mtfiles[i] == 0) {
				printf("Bad magtape file name\n");
				*(cp+1) = c;
				file->i_flgs = 0;
				return(-1);
			}
		}
	}
	if(devopen(file) < 0)
		return(-1);
	if (*++cp == '\0') {
		*cp = c;
		file->i_flgs |= how+1;
		file->i_cc = 0;
		file->i_offset = 0;
		return(fdesc+3);
	}
#ifdef	NO_FIO
	printf("\nDEBUG: Sorry - no file I/O code!\n");
	return(-1);
#else
	if ((i = find(cp, file)) == 0) {
		file->i_flgs = 0;
		return(-1);
	}
	if (how != 0) {
		printf("Can't write files yet.. Sorry\n");
		file->i_flgs = 0;
		return(-1);
	}
	openi(i, file);
	file->i_offset = 0;
	file->i_cc = 0;
	file->i_flgs |= F_FILE | (how+1);
	return(fdesc+3);
#endif	NO_FIO
}

close(fdesc)
int	fdesc;
{
	struct iob *file;

	fdesc -= 3;
	if (fdesc < 0 || fdesc >= NFILES || ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0)
		return(-1);
	if ((file->i_flgs&F_FILE) == 0)
		devclose(file);
	file->i_flgs = 0;
	return(0);
}
#endif	NOSYSCALL

/*
 * Returned status is saved in location rtnstat.
 * For boot and sdload, rtnstat is a local variable and is not used.
 * For all standalone programs, rtnstat is physically in srt0.s @ 1010.
 * The sdload program gets the returned status from the rtnstat
 * location via mfpi().
 */
int	rtnstat;
exit(status)
int	status;
{
	rtnstat = status;
	_stop("Exit called");
}

_stop(s)
char	*s;
{
	printf("%s\n", s);
	_rtt();
}

char	*ttm[] =
{
	"bus error",
	"illegal instruction",
	"break point trace",
	"IOT instruction",
	"power fail",
	"EMT instruction",
	"TRAP instruction",
	"Programmed interrupt request",
	"floating point exception",
	"memory management segmentation",
	"memory parity",
	"",
	"",
	"",
	"",
	"stray vector",
	0
};

trap(tt,sp,r5,r4,r3,r2,r1,r0,pc,ps)
{
	printf("\n\nTrap - %s\n", ttm[tt&017]);
	printf("\nps = %o\npc = %o", ps, pc);
	printf("\nr0 = %o\nr1 = %o\nr2 = %o", r0, r1, r2);
	printf("\nr3 = %o\nr4 = %o\nr5 = %o", r3, r4, r5);
	printf("\nsp = %o\n", sp);
	for (;;)
		;
}