/*- * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * %sccs.include.noredist.c% * * @(#)sys.c 7.1 (Berkeley) 04/24/90 */ #include "../h/param.h" #include "../h/inode.h" #include "../h/fs.h" #undef KERNEL #include "../h/dir.h" #include "saio.h" #define DEV_IOSIZE 1024 #define DB printf("%s:%d\n",__FILE__,__LINE__) ino_t dlook(); struct dirstuff { int loc; struct iob *io; }; #undef register static openi(n, io) register struct iob *io; { register struct dinode *dp; int cc; io->i_offset = 0; io->i_bn = fsbtodb(&io->i_fs, itod(&io->i_fs, n)) + io->i_boff; io->i_cc = io->i_fs.fs_bsize; io->i_ma = io->i_buf; cc = devread(io); dp = (struct dinode *)io->i_buf; io->i_ino.i_ic = dp[itoo(&io->i_fs, n)].di_ic; return (cc); } 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); } if (openi((ino_t) ROOTINO, file) < 0) { printf("can't read root inode\n"); return (0); } while (*path) { while (*path == '/') path++; q = path; while(*q != '/' && *q != '\0') q++; c = *q; *q = '\0'; if (path == q) path = "." ; /* / means /. */ if ((n = dlook(path, file)) != 0) { if (c == '\0') break; if (openi(n, file) < 0) return (0); *q = c; path = q; continue; } else { printf("%s: not found\n", path); return (0); } } return (n); } char b[MAXBSIZE]; daddr_t blkno; static daddr_t sbmap(io, bn) register struct iob *io; daddr_t bn; { register struct inode *ip; int i, j, sh; daddr_t nb, *bap; ip = &io->i_ino; if (bn < 0) { printf("bn negative\n"); return ((daddr_t)0); } /* * blocks 0..NDADDR are direct blocks */ if(bn < NDADDR) { nb = ip->i_db[bn]; return (nb); } /* * 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 (blkno != nb) { io->i_bn = fsbtodb(&io->i_fs, nb) + io->i_boff; io->i_ma = b; io->i_cc = io->i_fs.fs_bsize; if (devread(io) != io->i_fs.fs_bsize) { if (io->i_error) errno = io->i_error; printf("bn %D: read error\n", io->i_bn); return ((daddr_t)0); } blkno = nb; } bap = (daddr_t *)b; 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); } static ino_t dlook(s, io) char *s; register struct iob *io; { register struct direct *dp; register struct inode *ip; struct dirstuff dirp; int len; if (s == NULL || *s == '\0') return (0); ip = &io->i_ino; if ((ip->i_mode&IFMT) != IFDIR) { printf("%s: not a directory\n", s); return (0); } if (ip->i_size == 0) { printf("%s: zero length directory\n", s); return (0); } 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); } return (0); } /* * get next entry in a directory. */ struct direct * readdir(dirp) register struct dirstuff *dirp; { register struct direct *dp; register struct iob *io; daddr_t lbn, d; 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_boff; io->i_ma = io->i_buf; io->i_cc = blksize(&io->i_fs, &io->i_ino, lbn); if (devread(io) < 0) { errno = io->i_error; printf("bn %D: directory read error\n", io->i_bn); return (NULL); } } dp = (struct direct *)(io->i_buf + off); dirp->loc += dp->d_reclen; if (dp->d_ino == 0) continue; return (dp); } } lseek(fdesc, addr, ptr) int fdesc, ptr; off_t addr; { register struct iob *io; if (ptr != 0) { printf("seek not from beginning of file\n"); errno = EOFFSET; return (-1); } fdesc -= 3; if (fdesc < 0 || fdesc >= NFILES || ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0) { errno = EBADF; return (-1); } io->i_offset = addr; io->i_cc = 0; return (0); } getc(fdesc) int fdesc; { register struct iob *io; register struct fs *fs; register char *p; int c, lbn, off, size, diff; errno = 0 ; if (fdesc >= 0 && fdesc <= 2) return (getchar()); fdesc -= 3; if (fdesc < 0 || fdesc >= NFILES || ((io = &iob[fdesc])->i_flgs&F_ALLOC) == 0) { errno = EBADF; return (-1); } 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)) + io->i_boff; off = blkoff(fs, io->i_offset); size = blksize(fs, &io->i_ino, lbn); } else { io->i_bn = io->i_offset / DEV_IOSIZE * (DEV_IOSIZE/DEV_BSIZE); off = io->i_offset % DEV_IOSIZE; size = DEV_IOSIZE; } io->i_ma = io->i_buf; io->i_cc = size; if (devread(io) <= 0) { errno = io->i_error; 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); } /* does this port? 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 < 0) { if (i == 0) return (-1); else return (val); } *cp++ = w; } return (val); } */ int errno; read(fdesc, buf, count) int fdesc, count; char *buf; { register int i, size; register struct iob *io; register struct fs *fs; int lbn, off; errno = 0; if (fdesc >= 0 & fdesc <= 2) { i = count; do { *buf = getchar(); } while (--i && *buf++ != '\n'); return (count - i); } fdesc -= 3; if (fdesc < 0 || fdesc >= NFILES || ((io = &iob[fdesc])->i_flgs&F_ALLOC) == 0) { errno = EBADF; return (-1); } if ((io->i_flgs&F_READ) == 0) { errno = EBADF; return (-1); } /*#ifndef SMALL*/ if ((io->i_flgs & F_FILE) == 0) { #ifndef SMALL if (io->i_offset % 512 || count % 512) { #endif i = count; do { *buf++ = getc(fdesc+3); } while (--i); return (count - i); #ifndef SMALL } else { io->i_cc = count; io->i_ma = buf; io->i_bn = io->i_boff + (io->i_offset / DEV_BSIZE); i = devread(io); io->i_offset += count; if (i < 0) errno = io->i_error; return (i); } #endif } if (io->i_offset+count > io->i_ino.i_size) count = io->i_ino.i_size - io->i_offset; if ((i = count) <= 0) return (0); /* * While reading full blocks, do I/O into user buffer. * Anything else uses getc(). */ fs = &io->i_fs; while (i) { off = blkoff(fs, io->i_offset); lbn = lblkno(fs, io->i_offset); size = blksize(fs, &io->i_ino, lbn); if (off == 0 && size <= i) { io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff; io->i_cc = size; io->i_ma = buf; if (devread(io) < 0) { errno = io->i_error; return (-1); } io->i_offset += size; io->i_cc = 0; buf += size; i -= size; } else { size -= off; if (size > i) size = i; i -= size; do { *buf++ = getc(fdesc+3); } while (--size); } } return (count); } #ifndef SMALL write(fdesc, buf, count) int fdesc, count; char *buf; { register int i; register struct iob *file; errno = 0; 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) { errno = EBADF; return (-1); } if ((file->i_flgs&F_WRITE) == 0) { errno = EBADF; return (-1); } file->i_cc = count; file->i_ma = buf; file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE); i = devwrite(file); file->i_offset += count; if (i < 0) errno = file->i_error; return (i); } #endif int openfirst = 1; int opendev; /* last device opened; for boot to set bootdev */ open(str, how) char *str; int how; { register char *cp; int i; register struct iob *file; register struct devsw *dp; int fdesc; long atol(); extern int bootdev; if (openfirst) { for (i = 0; i < NFILES; i++) iob[i].i_flgs = 0; openfirst = 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 != ':'; cp++) ; if (*cp != ':') { /* default bootstrap unit and device */ file->i_ino.i_dev = bootdev; cp = str; } else { # define isdigit(n) ((n>='0') && (n<='9')) /* * syntax for possible device name: * : */ for (cp = str; *cp != ':' && !isdigit(*cp); cp++) ; for (dp = devsw; dp->dv_name; dp++) { if (!strncmp(str, dp->dv_name,cp-str)) goto gotdev; } printf("unknown device\n"); file->i_flgs = 0; errno = ENXIO; return (-1); gotdev: i = 0; while (*cp >= '0' && *cp <= '9') i = i * 10 + *cp++ - '0'; if (i < 0 || i > 255) { printf("minor device number out of range (0-255)\n"); file->i_flgs = 0; errno = EUNIT; return (-1); } if (*cp >= 'a' && *cp <= 'h') { if (i > 31) { printf("unit number out of range (0-31)\n"); file->i_flgs = 0; errno = EUNIT; return (-1); } i = make_minor(i, *cp++ - 'a'); } if (*cp++ != ':') { printf("incorrect device specification\n"); file->i_flgs = 0; errno = EOFFSET; return (-1); } file->i_ino.i_dev = makedev(dp-devsw, i); } file->i_boff = 0; devopen(file); opendev = file->i_ino.i_dev; if (cp != str && *cp == '\0') { file->i_flgs |= how+1; file->i_cc = 0; file->i_offset = 0; return (fdesc+3); } file->i_ma = file->i_buf; file->i_cc = SBSIZE; file->i_bn = SBLOCK + file->i_boff; file->i_offset = 0; if (devread(file) < 0) { errno = file->i_error; printf("super block read error\n"); return (-1); } file->i_fs = *(struct fs *)(file->i_buf); if ((i = find(cp, file)) == 0) { file->i_flgs = 0; errno = ESRCH; return (-1); } if (how != 0) { printf("can't write files yet.. sorry\n"); file->i_flgs = 0; errno = EIO; return (-1); } if (openi(i, file) < 0) { errno = file->i_error; return (-1); } file->i_offset = 0; file->i_cc = 0; file->i_flgs |= F_FILE | (how+1); return (fdesc+3); } close(fdesc) int fdesc; { struct iob *file; fdesc -= 3; if (fdesc < 0 || fdesc >= NFILES || ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) { errno = EBADF; return (-1); } if ((file->i_flgs&F_FILE) == 0) devclose(file); file->i_flgs = 0; return (0); } #ifndef SMALL ioctl(fdesc, cmd, arg) int fdesc, cmd; char *arg; { register struct iob *file; int error = 0; fdesc -= 3; if (fdesc < 0 || fdesc >= NFILES || ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) { errno = EBADF; return (-1); } switch (cmd) { case SAIOHDR: file->i_flgs |= F_HDR; break; case SAIOCHECK: file->i_flgs |= F_CHECK; break; case SAIOHCHECK: file->i_flgs |= F_HCHECK; break; case SAIONOBAD: file->i_flgs |= F_NBSF; break; case SAIODOBAD: file->i_flgs &= ~F_NBSF; break; case SAIOECCLIM: file->i_flgs |= F_ECCLM; break; case SAIOECCUNL: file->i_flgs &= ~F_ECCLM; break; case SAIOSEVRE: file->i_flgs |= F_SEVRE; break; case SAIONSEVRE: file->i_flgs &= ~F_SEVRE; break; default: error = devioctl(file, cmd, arg); break; } if (error < 0) errno = file->i_error; return (error); } #endif _stop(s) char *s; { int i; for (i = 0; i < NFILES; i++) if (iob[i].i_flgs != 0) close(i); printf("%s\n", s); _rtt(); } trap(ps) int ps; { printf("trap %o\n", ps); for (;;) ; }