2021-10-11 18:37:13 -03:00

707 lines
14 KiB
C

#ifndef lint
static char sccsid[] = "@(#)sys.c 1.1 94/10/31 SMI";
#endif
/*
* Copyright (c) 1985-1989 Sun Microsystems, Inc.
*/
#ifndef KADB
/*
* Basic file system reading code for standalone I/O system.
* Simulates a primitive UNIX I/O system (read(), write(), open(), etc).
* Does not attempt writes to file systems, tho writing to whole devices
* is supported, when the driver supports it.
*/
#include <stand/param.h>
#include <stand/saio.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <ufs/fsdir.h>
#include <ufs/fs.h>
#include <ufs/inode.h>
#define NULL 0
#define skipblank(p) { while (*(p) == ' ') (p)++; }
struct direct *readdir();
/*
* This struct keeps track of an open file in the standalone I/O system.
*
* It includes an IOB for device addess, an inode, a buffer for reading
* indirect blocks and inodes, and a buffer for the superblock of the
* file system (if any).
*/
struct iob {
struct saioreq i_si; /* I/O request block for this file */
struct inode i_ino; /* Inode for this file */
char i_buf[MAXBSIZE];/* Buffer for reading inodes & dirs */
union {
struct fs ui_fs; /* Superblock for file system */
char dummy[SBSIZE];
} i_un;
};
#define i_flgs i_si.si_flgs
#define i_boottab i_si.si_boottab
#define i_devdata i_si.si_devdata
#define i_ctlr i_si.si_ctlr
#define i_unit i_si.si_unit
#define i_boff i_si.si_boff
#define i_cyloff i_si.si_cyloff
#define i_offset i_si.si_offset
#define i_bn i_si.si_bn
#define i_ma i_si.si_ma
#define i_cc i_si.si_cc
#define i_fs i_un.ui_fs
/* These are the pools of buffers, iob's, etc. */
#define NBUFS (NIADDR+1) /* NOT! a variable */
char b[NBUFS][MAXBSIZE];
daddr_t blknos[NBUFS];
struct saioreq *open_sip;
struct iob iob[NFILES];
ino_t dlook();
struct dirstuff {
int loc;
struct iob *io;
};
static
openi(n,io)
ino_t n;
register struct iob *io;
{
register struct dinode *dp;
io->i_offset = 0;
io->i_bn = fsbtodb(&io->i_fs, itod(&io->i_fs, n));
io->i_cc = io->i_fs.fs_bsize;
io->i_ma = io->i_buf;
/* FIXME: this call to devread() does not check for errors! */
devread(&io->i_si);
dp = (struct dinode *)io->i_buf;
io->i_ino.i_ic = dp[itoo(&io->i_fs, n)].di_ic;
}
static ino_t
find(path, file)
register char *path;
struct iob *file;
{
register char *q;
char c;
ino_t n;
if (path==NULL || *path=='\0') {
printf("null path\n");
return(0);
}
openi((ino_t) ROOTINO, 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 struct inode *ip;
register int i, j, sh;
register daddr_t nb, *bap;
register daddr_t *db;
ip = &io->i_ino;
db = ip->i_db;
/*
* blocks 0..NDADDR are direct blocks
*/
if(bn < NDADDR) {
nb = db[bn];
return(nb);
}
#ifndef BOOTBLOCK
/*
* addresses NIADDR have single and double indirect blocks.
* the first step is to determine how many levels of indirection.
*/
sh = 1;
bn -= NDADDR;
for (j = NIADDR; j > 0; j--) {
sh *= NINDIR(&io->i_fs);
if (bn < sh)
break;
bn -= sh;
}
if (j == 0) {
printf("bn ovf %D\n", bn);
return ((daddr_t)0);
}
/*
* fetch the first indirect block address from the inode
*/
nb = ip->i_ib[NIADDR - j];
if (nb == 0) {
printf("bn void %D\n",bn);
return((daddr_t)0);
}
/*
* fetch through the indirect blocks
*/
for (; j <= NIADDR; j++) {
if (blknos[j] != nb) {
io->i_bn = fsbtodb(&io->i_fs, nb);
io->i_ma = b[j];
io->i_cc = io->i_fs.fs_bsize;
if (devread(&io->i_si) != io->i_cc)
return((daddr_t)0);
blknos[j] = nb;
}
bap = (daddr_t *)b[j];
sh /= NINDIR(&io->i_fs);
i = (bn / sh) % NINDIR(&io->i_fs);
nb = bap[i];
if(nb == 0) {
printf("bn void %D\n",bn);
return((daddr_t)0);
}
}
return(nb);
#else BOOTBLOCK
return((daddr_t)0);
#endif BOOTBLOCK
}
static ino_t
dlook(s, io)
char *s;
register struct iob *io;
{
register struct direct *dp;
register struct inode *ip;
struct dirstuff dirp;
register int len;
ip = &io->i_ino;
#ifndef BOOTBLOCK
if (s == NULL || *s == '\0')
return(0);
if ((ip->i_mode&IFMT) != IFDIR) {
printf("not a directory\n");
return(0);
}
if (ip->i_size == 0) {
printf("zero length directory\n");
return(0);
}
#endif BOOTBLOCK
len = strlen(s);
dirp.loc = 0;
dirp.io = io;
for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
if(dp->d_ino == 0)
continue;
if (dp->d_namlen == len && !strcmp(s, dp->d_name))
return(dp->d_ino);
#ifndef BOOTBLOCK
/* Allow "*" to print all names at that level, w/out match */
if (!strcmp(s, "*"))
printf("%s\n", dp->d_name);
#endif BOOTBLOCK
}
return(0);
}
/*
* get next entry in a directory.
*/
struct direct *
readdir(dirp)
register struct dirstuff *dirp;
{
register struct direct *dp;
register struct iob *io;
register daddr_t lbn, d;
register int off;
io = dirp->io;
for(;;) {
if (dirp->loc >= io->i_ino.i_size)
return NULL;
off = blkoff(&io->i_fs, dirp->loc);
if (off == 0) {
lbn = lblkno(&io->i_fs, dirp->loc);
d = sbmap(io, lbn);
if(d == 0)
return NULL;
io->i_bn = fsbtodb(&io->i_fs, d);
io->i_ma = io->i_buf;
io->i_cc = blksize(&io->i_fs, &io->i_ino, lbn);
if (devread(&io->i_si) != io->i_cc)
return NULL;
}
dp = (struct direct *)(io->i_buf + off);
dirp->loc += dp->d_reclen;
if (dp->d_ino == 0)
continue;
return (dp);
}
}
/*ARGSUSED*/
lseek(fdesc, addr, ptr)
int fdesc;
register off_t addr;
int ptr;
{
register struct iob *io;
#ifndef BOOTBLOCK
fdesc -= 3;
if (fdesc < 0 || fdesc >= NFILES ||
((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
return(-1);
#else BOOTBLOCK
io = &iob[fdesc - 3];
#endif BOOTBLOCK
io->i_si.si_flgs &= ~F_EOF;
io->i_offset = addr;
io->i_bn = addr / DEV_BSIZE;
io->i_cc = 0;
return(0);
}
/* FIXME: possibly make this static and pass iob, eliminating assorted tests? */
getc(fdesc)
int fdesc;
{
register struct iob *io;
register struct fs *fs;
register char *p;
register int c, off, size, diff;
register daddr_t lbn;
#ifndef BOOTBLOCK
if (fdesc >= 0 && fdesc <= 2)
return(getchar());
fdesc -= 3;
if (fdesc < 0 || fdesc >= NFILES ||
((io = &iob[fdesc])->i_flgs&F_ALLOC) == 0)
return(-1);
#else BOOTBLOCK
io = &iob[fdesc -= 3];
#endif BOOTBLOCK
p = io->i_ma;
if (io->i_cc <= 0) {
if ((io->i_flgs & F_FILE) != 0) {
diff = io->i_ino.i_size - io->i_offset;
if (diff <= 0)
return (-1);
fs = &io->i_fs;
lbn = lblkno(fs, io->i_offset);
io->i_bn = fsbtodb(fs, sbmap(io, lbn));
off = blkoff(fs, io->i_offset);
size = blksize(fs, &io->i_ino, lbn);
} else {
io->i_bn = io->i_offset / DEV_BSIZE;
off = 0;
size = DEV_BSIZE;
}
io->i_ma = io->i_buf;
io->i_cc = size;
if (devread(&io->i_si) != io->i_cc) /* Trap errors */
return(-1);
if ((io->i_flgs & F_FILE) != 0) {
if (io->i_offset - off + size >= io->i_ino.i_size)
io->i_cc = diff + off;
io->i_cc -= off;
}
p = &io->i_buf[off];
}
io->i_cc--;
io->i_offset++;
c = (unsigned)*p++;
io->i_ma = p;
return(c);
}
read(fdesc, buf, count)
int fdesc;
register char *buf;
int count;
{
register i,j;
register struct iob *file;
#ifndef BOOTBLOCK
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);
fdesc += 3;
#else BOOTBLOCK
file = &iob[fdesc - 3];
#endif BOOTBLOCK
if ((file->i_flgs & F_FILE) == 0) {
file->i_cc = count;
file->i_ma = buf;
file->i_bn = (file->i_offset / DEV_BSIZE);
i = devread(&file->i_si);
file->i_offset += count;
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);
#ifdef BOOTBLOCK
do {
*buf++ = getc(fdesc);
} while (--i);
#else BOOTBLOCK
while (i > 0) {
if ((j = file->i_cc) <= 0) {
*buf++ = getc(fdesc);
i--;
} else {
if (i < j)
j = i;
bcopy(file->i_ma, buf, (unsigned)j);
buf += j;
file->i_ma += j;
file->i_offset += j;
file->i_cc -= j;
i -= j;
}
}
#endif BOOTBLOCK
return(count);
}
}
#ifndef BOOTBLOCK
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);
if (count % DEV_BSIZE)
printf("count=%d?\n", count);
file->i_cc = count;
file->i_ma = buf;
file->i_bn = (file->i_offset / DEV_BSIZE);
i = devwrite(&file->i_si);
file->i_offset += count;
return(i);
}
#endif BOOTBLOCK
/*
* Open a file on a physical device, or open the device itself.
*
* The device is identified by a struct bootparam which gives pointers
* to the struct boottab, containing the device open, strategy and close
* routines; and the device parameters such as controller #, unit #, etc.
*
* If *str == 0, the device is opened, else the named file in the file
* system on the device is opened.
*/
int
physopen(bp, str, how)
register struct bootparam *bp;
char *str;
int how;
{
int fdesc;
register struct iob *file;
#ifdef BOOTBLOCK
fdesc = 0;
file = &iob[0];
file->i_flgs |= F_ALLOC;
#else BOOTBLOCK
fdesc = getiob(); /* Allocate an IOB */
file = &iob[fdesc];
#endif BOOTBLOCK
file->i_boottab = bp->bp_boottab; /* Record pointer to boot table */
file->i_ctlr = bp->bp_ctlr;
file->i_unit = bp->bp_unit;
file->i_boff = bp->bp_part;
file->i_ino.i_dev = 0; /* Call it device 0 for chuckles */
return(openfile(fdesc, file, str, how));
}
#ifndef BOOTBLOCK
int openfirst = 1;
/*
* Allocate an IOB for a newly opened file.
*/
int
getiob()
{
register int fdesc;
if (openfirst) {
openfirst = 0;
for (fdesc = 0; fdesc < NFILES; fdesc++)
iob[fdesc].i_flgs = 0;
}
for (fdesc = 0; fdesc < NFILES; fdesc++)
if (iob[fdesc].i_flgs == 0)
goto gotfile;
_stop("No more file slots");
gotfile:
(&iob[fdesc])->i_flgs |= F_ALLOC;
return fdesc;
}
/*
* Description: Reads string for hex variable.
* Also ignores blanks. Returns a pointer pointing at the next
* non-blank character, skipping over one ','.
*
* Synopsis: status = gethex(p, ip)
* status :(char *) pointer to next non-blank character
* p :(char *) pointer to location of start of hex number
* ip :(int) hex variable read
*/
char *
gethex(p, ip)
register char *p;
int *ip;
{
register int ac = 0;
skipblank(p);
while (*p) {
if (*p >= '0' && *p <= '9')
ac = (ac<<4) + (*p - '0');
else if (*p >= 'a' && *p <= 'f')
ac = (ac<<4) + (*p - 'a' + 10);
else if (*p >= 'A' && *p <= 'F')
ac = (ac<<4) + (*p - 'A' + 10);
else
break;
p++;
}
skipblank(p);
if (*p == ',')
p++;
skipblank(p);
*ip = ac;
return (p);
}
/*
* Open a device or file-in-file-system-on-device.
*/
int
open(str, how)
char *str;
int how;
{
register char *cp;
register struct iob *file;
register struct boottab *dp;
register struct boottab **tablep;
int fdesc;
long atol();
extern struct boottab *(devsw[]);
fdesc = getiob(); /* Allocate an IOB */
file = &iob[fdesc];
open_sip = &file->i_si;
for (cp = str; *cp && *cp != '('; cp++)
;
if (*cp++ != '(') {
file->i_flgs = 0;
goto badsyntax;
}
for (tablep = devsw; 0 != (dp = *tablep); tablep++) {
if (str[0] == dp->b_dev[0] && str[1] == dp->b_dev[1])
goto gotdev;
}
printf("Unknown device: %c%c; known devices:\n", str[0], str[1]);
for (tablep = devsw; 0 != (dp = *tablep); tablep++)
printf(" %s\n", dp->b_desc);
file->i_flgs = 0;
return(-1);
gotdev:
file->i_boottab = dp; /* Record pointer to boot table */
file->i_ino.i_dev = tablep-devsw;
cp = gethex(cp, &file->i_ctlr);
cp = gethex(cp, &file->i_unit);
cp = gethex(cp, (int *)&file->i_boff);
if (*cp == '\0') goto doit;
if (*cp++ != ')') {
badsyntax:
printf("%s: bad syntax, try dev(ctlr,unit,part)name\n", str);
return -1;
}
skipblank(cp);
doit:
return(openfile(fdesc, file, cp, how));
}
#endif NOOPEN
/*
* File processing for open call
*/
openfile(fdesc, file, cp, how)
int fdesc;
struct iob *file;
char *cp;
int how;
{
ino_t ino;
if (devopen(&file->i_si)) {
file->i_flgs = 0;
return(-1); /* if devopen fails, open fails */
}
if (*cp == '\0') { /* Opening a device */
file->i_flgs |= how+1;
file->i_cc = 0;
file->i_offset = 0;
return(fdesc+3);
}
/* Opening a file system; read the superblock. */
file->i_ma = (char *)(&file->i_fs);
file->i_cc = SBSIZE;
file->i_bn = SBLOCK;
file->i_offset = 0;
if (devread(&file->i_si) != SBSIZE) {
file->i_flgs = 0;
return(-1);
}
#ifndef BOOTBLOCK
if (file->i_fs.fs_magic != FS_MAGIC) {
printf("Not a file system\n");
return(-1);
}
#endif BOOTBLOCK
if ((ino = find(cp, file)) == 0) {
file->i_flgs = 0;
return(-1);
}
#ifndef BOOTBLOCK
if (how != 0) {
printf("Can't write files yet.. Sorry\n");
file->i_flgs = 0;
return(-1);
}
#endif BOOTBLOCK
openi(ino, file);
file->i_offset = 0;
file->i_cc = 0;
file->i_flgs |= F_FILE | (how+1);
return(fdesc+3);
}
close(fdesc)
int fdesc;
{
register struct iob *file;
fdesc -= 3;
if (fdesc < 0 || fdesc >= NFILES ||
((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0)
return(-1);
devclose(&file->i_si); /* For a file-in-filesys or for raw dev */
file->i_flgs = 0;
return(0);
}
exit()
{
_stop((char *)0);
}
_stop(s)
char *s;
{
register int i;
for (i = 0; i < NFILES; i++)
if (iob[i].i_flgs != 0)
close(i);
if (s) printf("%s\n", s);
_exit();
}
panic(s)
char *s;
{
_stop(s);
}
#endif KADB