Files
seta75D 2e8a93c394 Init
2021-10-11 18:20:23 -03:00

716 lines
14 KiB
C

#ifndef lint
static char sccsid[] = "@(#)vfs_sys.c 1.1 92/07/30 Copyr 1986 Sun Micro";
#endif
/*
* Copyright (c) 1986 by Sun Microsystems, Inc.
*/
/*
* 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 "boot/param.h"
#include <sys/param.h>
#include <stand/saio.h>
#include "boot/systm.h"
#include <sys/dir.h>
#include <sys/time.h>
#include "boot/vnode.h"
#include <ufs/fs.h>
#include "boot/inode.h"
#include <sys/uio.h>
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/user.h>
#include "boot/iob.h"
#ifdef OPENPROMS
#include "boot/conf.h"
#endif
#undef u
extern struct user u;
/* These are the pools of buffers, iob's, etc. */
char b[NBUFS][MAXBSIZE];
daddr_t blknos[NBUFS];
struct iob iob[NFILES];
static int dump_debug = 20;
extern char *gethex();
char *string();
char *dev_unit_file();
char *pathname();
char *server_path();
/*
*
*/
int
xopen(str, how)
char *str;
int how;
{
register char *p;
char dev[DEV_NAME_LEN+1];
char filename[FILE_NAME_LEN+1];
char server[SERVER_NAME_LEN+1];
char pathname[PATHNAME_LEN+1];
int ctlr, unit, part;
if ((p = dev_unit_file(str, dev, &ctlr, &unit, &part, filename)) !=
(char *)-1) {
if (*p != '\0') {
printf ("garbage after filename '%s'\n",
filename);
return (-1);
}
return (open_dev_file(dev, ctlr, unit, part, filename));
} else if ((p = server_path(str, server, pathname)) !=
(char *)-1) {
if (*p != '\0') {
printf ("garbage after pathname '%s'\n",
pathname);
return (-1);
}
return (open_server_path(server, pathname));
} else {
printf ("syntax error: try again\n");
return (-1);
}
}
/*
* Parse the construct:
*
* <dev_unit_file> -> <dev>(<ctlr>, <unit>, <part>) <filename>
*/
char *
dev_unit_file(str, dev, ctlr, unit, part, filename)
char *str;
char *dev;
int *ctlr;
int *unit;
int *part;
char *filename;
{
char *p;
if ((p = string(str, dev)) == (char *)-1) {
printf ("%s: bad device\n", str);
return ((char *)-1);
}
if (*p++ != '(') {
return ((char *)-1);
}
p = gethex(p, ctlr);
if (*p++ != ',') {
return ((char *)-1);
}
p = gethex(p, unit);
if (*p++ != ',') {
return ((char *)-1);
}
p = gethex(p, part);
if (*p++ != ')') {
return ((char *)-1);
}
if ((p = string(p, filename)) == (char *)-1) {
return ((char *)-1);
}
return (p);
}
/*
* Parses:
*
* <server_path> -> <server> : <pathname>
*/
char *
server_path(str, server, path)
char *str;
char *server;
char *path;
{
char *p;
if ((p = string(str, server)) == (char *)-1) {
printf("%s: bad server name\n", str);
return ((char *)-1);
}
if (*p++ != ':') {
printf("%s: no ':' following server name\n", str);
return ((char *)-1);
}
if ((p = pathname(p, path)) == (char *)-1) {
printf("%s: bad pathname\n", str);
return ((char *)-1);
}
return (0);
}
/*
* Parses:
* <path> = / <string>
*/
char *
pathname(str, path)
char *str;
char *path;
{
char *p, *p1;
for (p = str, p1 = path; *p; p++, p1++)
*p1 = *p;
*p1 = '\0';
return (p);
}
/*
* Parses:
*
* <string> -> {[a-z][A-Z][0-9][._-,:+%]}*
*
* Terminates the output string with a zero byte.
* Returns: pointer to the next character after the end of
* the string, or -1 if there is no valid character in the
* string.
*/
char *
string(str, dest)
char *str;
char *dest;
{
char *p, *p1;
for (p = str; *p == ' '; p++);
for (p1 = dest; *p; p++, p1++) {
if ((*p >= 'a') && (*p <= 'z'))
*p1 = *p;
else if ((*p >= 'A') && (*p <= 'Z'))
*p1 = *p;
else if ((*p >= '0') && (*p <= '9'))
*p1 = *p;
else if ((*p == '.') || (*p == '_') || (*p == '-') ||
(*p == ',') || (*p == ':') || (*p == '+') ||
(*p == '%') || (*p == '*') || (*p == '/'))
*p1 = *p;
else
break;
}
if (p1 == dest) { /* No valid characters. */
dprint(dump_debug, 6,
"string: no valid characters p 0x%x p1 0x%x\n", p, p1);
*p1 = '\0';
return ((char *)-1);
}
*p1 = '\0';
return (p); /* Next character after string */
}
open_server_path(server, path)
char *server;
char *path;
{
return (-1);
}
int
open_dev_file(dev, ctlr, unit, part, file)
char *dev;
int ctlr;
int unit;
int part;
char *file;
{
return (-1);
}
fopen(fnamep, fmode, cmode)
char *fnamep;
int fmode;
int cmode;
{
}
boot_lseek(fd, off, sbase)
int fd;
register off_t off;
int sbase;
{
struct iob *fp;
u.u_error = getvnodefp(fd, &fp);
if (u.u_error) {
#ifdef DUMP_DEBUG
dprint(dump_debug, 6, "lseek: bad fd 0x%x\n", fd);
#endif DUMP_DEBUG
return (-1);
}
if (((struct vnode *)fp->i_ino.i_devvp)->v_type == VFIFO) {
u.u_error = ESPIPE;
return (-1);
}
switch (sbase) {
case L_INCR:
fp->i_offset += off;
break;
case L_XTND: {
struct vattr vattr;
u.u_error = VOP_GETATTR((struct vnode *)fp->i_ino.i_devvp,
&vattr, u.u_cred);
if (u.u_error)
return (-1);
fp->i_offset = off + vattr.va_size;
break;
}
case L_SET:
fp->i_offset = off;
break;
default:
u.u_error = EINVAL;
}
u.u_r.r_off = fp->i_offset;
#ifdef DUMP_DEBUG1
dprint(dump_debug, 6, "lseek: new offset 0x%x\n", fp->i_offset);
#endif DUMP_DEBUG1
return (0);
}
/*ARGSUSED*/
boot_read(fdesc, buf, count)
int fdesc;
register char *buf;
int count;
{
int this_count = 0x2000;
int total_read = 0;
int this_read = 0;
int cc;
#ifdef DUMP_DEBUG1
dprint(dump_debug, 6, "read(fdesc %x, buf %x, count %x)\n",
fdesc, buf, count);
#endif DUMP_DEBUG1
while (count > 0) {
cc = (count > this_count) ? this_count : count;
this_read = xread(fdesc, buf, cc);
if (u.u_error != 0) {
#ifdef DEBUG
printf("boot_read: u.u_error = %d!\n", u.u_error);
#endif DEBUG
return (-1);
}
if (this_read == 0) { /* EOF */
#ifdef DEBUG
printf("boot_read: this_read = 0, total_read = %d\n",
total_read);
#endif DEBUG
break;
}
count -= this_read;
buf += this_read;
total_read += this_read;
feedback(); /* Show activity */
}
#ifdef DEBUG
printf("boot_read: returning total_read = %d\n", total_read);
#endif DEBUG
return (total_read);
}
xread(fdesc, buf, count)
int fdesc;
register char *buf;
int count;
{
struct uio auio;
struct iovec aiov;
#ifdef DUMP_DEBUG1
dprint(dump_debug, 6,
"xread(fdesc %x, buf %x, count %x)\n",
fdesc, buf, count);
#endif DUMP_DEBUG1
aiov.iov_base = buf;
aiov.iov_len = count;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
/*
* It's all dark, really.
*/
auio.uio_seg = UIOSEG_KERNEL;
rwuio(fdesc, &auio, UIO_READ);
return (count-auio.uio_resid);
}
xclose(fdesc)
int fdesc;
{
#ifdef lint
fdesc = fdesc;
#endif lint
}
exit()
{
_stop((char *)0);
}
_stop(s)
char *s;
{
if (s) printf("%s\n", s);
_exit();
}
panic(s)
char *s;
{
_stop(s);
}
/*
* Open a device. No files involved at this point.
*/
opendev(fdesc, file, how)
int fdesc;
struct iob *file;
int how;
{
#ifdef OPENPROMS
if (prom_getversion() > 0)
return (obp_opendev(fdesc, file, how));
#endif
#ifndef sun4m
/*
* Only set ctlr field if device is an IPI ctlr. This allows
* UNIX to be booted from multiple IPI ctlrs. Can't set
* ctlr number in this fashion if sd device (such as CD-ROM)
* since the bits are used for unit info (see below)
*/
if (major(file->i_ino.i_dev) == 1)
file->i_si.si_ctlr = minor(file->i_ino.i_dev) >> 6;
/* XXX
* Purposely don't "AND" unit with 0x7, might break
* other drivers. Driver must get rid of the ctlr
* explicitly.
*/
file->i_si.si_unit = minor(file->i_ino.i_dev) >> 3;
file->i_si.si_boff = minor(file->i_ino.i_dev) & 0x7;
#ifndef OPENPROMS
/*
* XXX HACK HACK HACK - the non-OPENPROM "sd" driver (among others)
* assumes that it will be given "unit" as a PROM style
* (target * 8) + lun number. But getblockdev() needs to give
* a real UNIX minor number (or loose some bits), thus it does
* if ("sd") unit = (((unit & 0xF8) >> 2) | (unit & 0x01));
* Now we convert the si_unit for the "sd" driver back into
* (target * 8) + lun.
* This HACK is here instead of fixing "sd" driver so we
* don't have to fix tpboot and standalone copy (may they die soon!)
* as this work is being done betwee 4.1 preFCS and FCS!!!
*/
/* HARDCODE "sd" major number */
if (major(file->i_ino.i_dev) == 7)
file->i_si.si_unit =
((minor(file->i_ino.i_dev) & 0xF0) >> 1) |
((minor(file->i_ino.i_dev) & 0x08) >> 3);
#endif OPENPROMS
if (devopen(&file->i_si)) {
file->i_flgs = 0;
#ifdef DUMP_DEBUG1
dprint(dump_debug, 6, "opendev: bad open\n");
#endif DUMP_DEBUG1
return (-1); /* if devopen fails, open fails */
}
file->i_flgs |= how+1;
file->i_cc = 0;
file->i_offset = 0;
return (fdesc+3);
#endif !sun4m
}
#ifdef OPENPROMS
/*
* Open a device. No files involved at this point.
*/
obp_opendev(fdesc, file, how)
int fdesc;
struct iob *file;
int how;
{
register struct boottab *dp;
register struct binfo *bd;
register int phandle;
char devtype[32];
dp = file->i_boottab;
bd = (struct binfo *)kmem_alloc(sizeof (struct binfo));
bzero((caddr_t)bd, sizeof (struct binfo));
(struct binfo *)file->i_si.si_devdata = bd;
bd->name = dp->b_desc;
bd->ihandle = 0;
if (devopen(&file->i_si)) {
file->i_flgs = 0;
#ifdef DUMP_DEBUG1
dprint(dump_debug, 6, "opendev: bad open\n");
#endif DUMP_DEBUG1
return (-1); /* if devopen fails, open fails */
}
/*
* find out if the open device is a block device
*/
phandle = prom_getphandle(bd->ihandle);
devtype[0] = '\0';
(void)prom_getprop(phandle, "device_type", devtype);
switch (dp->b_dev[0]) {
case 'b':
if ((strcmp (devtype, "block") != 0) &&
(strcmp (devtype, "byte") != 0)) {
devclose(&file->i_si);
file->i_flgs = 0;
#ifdef DUMP_DEBUG
dprint(dump_debug, 6,
"opendev: open device is not a block or byte device\n");
#endif DUMP_DEBUG
return (-2); /* if devopen fails, open fails */
}
break;
case 'n':
if (strcmp (devtype, "network") != 0) {
devclose(&file->i_si);
file->i_flgs = 0;
#ifdef DUMP_DEBUG
dprint(dump_debug, 6,
"opendev: open device is not a network device\n");
#endif DUMP_DEBUG
return (-2); /* if devopen fails, open fails */
}
break;
default:
devclose(&file->i_si);
file->i_flgs = 0;
#ifdef DUMP_DEBUG
dprint(dump_debug, 6,
"opendev: open device is not a block, byte or net device\n");
#endif DUMP_DEBUG
return (-2); /* if devopen fails, open fails */
}
file->i_flgs |= how+1;
file->i_cc = 0;
file->i_offset = 0;
return (fdesc+3);
}
#endif
rwuio(fdesc, uio, rw)
int fdesc;
register struct uio *uio;
enum uio_rw rw;
{
register struct iob *file;
register struct iovec *iov;
int i;
#ifdef DUMP_DEBUG1
dprint(dump_debug, 6, "rwuio(fdesc 0x%x uio 0x%x rw 0x%x)\n",
fdesc, uio, rw);
#endif DUMP_DEBUG1
file = &iob[fdesc];
uio->uio_resid = 0;
/*
* It's all dark, really.
*/
uio->uio_seg = UIOSEG_KERNEL;
iov = uio->uio_iov;
for (i = 0; i < uio->uio_iovcnt; i++) {
if (iov->iov_len < 0) {
u.u_error = EINVAL;
#ifdef DEBUG
printf("rwuio: EINVAL: iov_len = %d\n", iov->iov_len);
#endif DEBUG
return;
}
uio->uio_resid += iov->iov_len;
if (uio->uio_resid < 0) {
u.u_error = EINVAL;
#ifdef DEBUG
printf("rwuio: EINVAL: iov_len %d, uio_resid %d\n",
iov->iov_len, uio->uio_resid);
#endif DEBUG
return;
}
iov++;
}
/*
* file->i_offset should be set correctly by lseek.
*/
uio->uio_offset = file->i_offset;
uio->uio_fmode = 0 /* fp->f_flag */;
if ((i = vno_rw(file, rw, uio)) != 0) {
#ifdef DEBUG
printf("rwuio: EIO: error %d from vno_rw!\n", i);
#endif DEBUG
u.u_error = EIO;
return;
}
file->i_offset = uio->uio_offset;
#ifdef DUMP_DEBUG1
dprint(dump_debug, 6, "rwuio: new offset 0x%x\n", file->i_offset);
#endif DUMP_DEBUG1
}
vno_rw(fp, rw, uiop)
struct iob *fp;
enum uio_rw rw;
struct uio *uiop;
{
struct vnode *vp;
register int error;
/*
* We store a pointer to the vnode in i_devvp.
*/
vp = fp->i_ino.i_devvp;
#ifdef DUMP_DEBUG1
dprint(dump_debug, 6, "vno_rw: fp 0x%x vp 0x%x\n", fp, vp);
#endif DUMP_DEBUG1
if (vp->v_type == VREG) {
error = VOP_RDWR(vp, uiop, rw, IO_UNIT, u.u_cred);
} else if (vp->v_type == VFIFO) {
/*
* NOTE: Kludge to ensure that FAPPEND stays set.
* This ensures that fp->f_offset is always accurate.
*
* fp->f_flag |= FAPPEND;
*/
/*
* NOTE: Kludge to ensure 'no delay' bit passes thru
*/
error = VOP_RDWR(vp, uiop, rw, IO_APPEND, u.u_cred);
} else {
error = VOP_RDWR(vp, uiop, rw, 0, u.u_cred);
}
if (error) {
#ifdef DEBUG
printf("vno_rw: returning error %d from VOP_RDWR, v_type ",
error);
switch (vp->v_type) {
case VREG: printf("VREG\n"); break;
case VFIFO: printf("VFIFO\n"); break;
default: printf("default (%d)\n", vp->v_type); break;
}
#endif DEBUG
return (error);
}
return (0);
}
/*
* Get the file structure entry for the file descrpitor, but make sure
* its a vnode.
*/
int
getvnodefp(fd, fpp)
int fd;
struct iob **fpp;
{
register struct iob *fp;
#ifdef NEVER
fp = getf(fd);
if (fp == (struct file *)0)
return (EBADF);
if (fp->f_type != DTYPE_VNODE)
return (EINVAL);
#endif NEVER
fp = &iob[fd];
*fpp = fp;
return (0);
}
#define DIR_BUFF_LEN 512
list_directory(dir)
char *dir;
{
char buffer[DIR_BUFF_LEN];
long basep;
int directory;
struct direct *dp;
#ifdef DUMP_DEBUG
dprint(dump_debug, 6, "list_directory('%s')\n", dir);
#endif DUMP_DEBUG
if ((directory = open (dir, O_RDONLY)) == -1) {
dprint(dump_debug, 10,
"list_directory: bad directory %s\n", dir);
return (-1);
}
#ifdef DUMP_DEBUG
dprint(dump_debug, 6,
"list_directory: directory '%s' fd 0x%x\n", dir, directory);
#endif DUMP_DEBUG
while (1) {
if (getdirents(directory, buffer, DIR_BUFF_LEN, &basep) == -1) {
#ifdef DUMP_DEBUG
dprint(dump_debug, 10, "list_directory: bad getdirents\n");
#endif DUMP_DEBUG
return (-1);
}
if (u.u_r.r_val1 == 0) {
#ifdef DUMP_DEBUG
dprint(dump_debug, 6,
"list_directory: end of directory\n");
#endif DUMP_DEBUG
return (0);
}
for (dp = (struct direct *)buffer; dp < (struct direct *)
((char *)buffer + u.u_r.r_val1); /* enpty */) {
printf("ino 0x%x: name '%s'\n",
dp->d_fileno, &(dp->d_name[0]));
dp = (struct direct *)((char *)dp + dp->d_reclen);
}
}
}