# /* * si - system internals * examine and print stuff from inside the OS * * To avoid having to basically duplicate the content in ncheck, this * program doesn't bother to include code to convert inode numbers to * file names; instead, it depends on a copy of the output of ncheck * kept in the file "filenms" in the root directory of each disk partition, * in which it grovels to convert inode numbers to file names. * * Further kludgery: in V6, header files don't just define structures, * they also allocate tables, calling in param.h to do do. So at the * moment, although the code is prepared to allocate a new table if * the system is now using a bigger one, it still statically allocates * an initial table. (If things in the system change, and you're really * energetic, you can recompile this and it will stop doing that.) * * * This command is now too large to be compiled with the vanilla V6 C * compiler (symbol table too large), so it is compiled with NCC. * It should still compile with the vanilla V6 C compiler, although * it would have to be split into several modules. * * Note that in the output you will see evidence of si itself running; * it will have opened /dev/mem, the use count of the inode of its * current directory will be incremented, etc. * * JNC Apr/2014 */ #ifdef USR #include "/usr/sys/param.h" #include "/usr/sys/user.h" #include "/usr/sys/text.h" #include "/usr/sys/inode.h" #include "/usr/sys/file.h" #include "/usr/sys/buf.h" #include "/usr/sys/filsys.h" #include "/usr/sys/conf.h" #endif #ifndef USR #include "/sys/param.h" #include "/sys/user.h" #include "/sys/text.h" #include "/sys/inode.h" #include "/sys/file.h" #include "/sys/buf.h" #include "/sys/filsys.h" #include "/sys/conf.h" #endif /* Fundamentals */ #define BLKSIZ 512 /* Fakes - used to fake out V6 header files which include structure * allocation/naming as well as definition. */ struct bdevsw bdevsw[1]; struct cdevsw cdevsw[1]; /* Mount structures. * * m_nread is filename mapping file recompute lock; iff non-zero, * inode mapping file has already been recomputed in this command * run. */ struct mount { int m_dev; /* device mounted */ char *m_bufp; /* pointer to superblock */ char *m_inodp; /* pointer to mounted on inode */ } mount[NMOUNT]; struct mntdata { int m_dev; /* Device */ int m_majdev; /* Used for creation of file names */ int m_mindev; char *m_bloc; /* Location of buffer in kernel */ int m_niblks; /* Copied for use by other routines */ int m_ndblks; char *m_devf; /* Filename for device */ char *m_mpoint; /* Mount point */ char *m_mfile; /* Filename with inode->filename mappings */ int m_mftm[2]; /* Time of last mapping file computation */ int m_nread; /* Recompute lock */ struct filsys *m_filsys; } mdata[NMOUNT]; /* Parameters */ #define DDIRLEN 5 /* strlen(devnm) */ #define DFNMLEN 3 /* strlen("rXN") */ #define FFNMLEN 8 /* strlen(filesf) */ char *devnm "/dev/"; char *filesf "/filenms"; #define MAXDSK 9 /* Convert major device numbers to names */ char *dsknames[MAXDSK] { "RK", "RP", "RF", "TM", "TC", "HS", "HP", "HT", "RL" }; char *dskfnames[MAXDSK] { /* For /dev/ names */ "rrk", "rrp", "rrf", 0, 0, "rhs", "rhp", 0, "rrl" }; /* Unix stuff */ extern char *alloc(); /* Symbol table stuff */ #define ROOTD 0 #define SWAPD 1 #define SWPLO 2 #define NSWAP 3 #define SWAPM 4 #define COREM 5 #define STMEM 6 #define ENDMEM 7 #define UPTIME 8 #define TEXTS 9 #define INODES 10 #define MTAB 11 #define FILES 12 #define BUFS 13 #define END 14 #define ENDSYS 15 #define PNBUF 16 #define PNINODE 17 #define PNFILE 18 #define PNMOUNT 19 #define PNPROC 20 #define PNTEXT 21 #define PCMAPSZ 22 #define PSMAPSZ 23 #define LSTNM 24 #define NMTBLSZ 25 /* + 2 to leave room for null ending entry */ char *names[LSTNM] { "_rootdev", "_swapdev", "_swplo", "_nswap", "_swapmap", "_coremap", "_stmem", "_endmem", "_uptime", "_text", "_inode", "_mount", "_file", "_buf", "_end", "_endsys", "_nbuf", "_ninode", "_nfile", "_nmount", "_nproc", "_ntext", "_cmapsiz", "_smapsiz", }; struct nent { char name[8]; int type; char *value; } nl[NMTBLSZ]; /* Kernel stuff. * * First group is because V6 C seems not to know "sizeof(struct )". * Even though this command now needs NCC to compile (see top header), the * code has been kept V6 C compatible. */ int bufsz; /* sizeof(struct buf) */ int inodesz; /* sizeof(struct inode) */ int filesz; /* sizeof(struct file) */ int mountsz; /* sizeof(struct mount) */ int mdatasz; /* sizeof(struct mntdata) */ int textsz; /* sizeof(struct text) */ int mem; int stmem; int endmem; int tmem; int rootdev; int swapdev; int swaplo; int swapsz; int uptime[2]; int nbuf; /* Don't depend on compiled-in constants */ int ninode; int nfile; int nmount; int ntext; int cmapsiz; int smapsiz; struct buf *bufp; /* If table sizes are wrong */ struct inode *inodep; struct file *filep; struct mount *mountp; struct mntdata *mdatap; struct text *textp; struct map { char *m_size; char *m_addr; }; /* #define CMAPSZ (CMAPSIZ / sizeof(struct map)) #define SMAPSZ (SMAPSIZ / sizeof(struct map)) */ #define CMAPSZ (CMAPSIZ / 4) #define SMAPSZ (CMAPSIZ / 4) struct map coremap[CMAPSZ]; struct map swapmap[SMAPSZ]; /* Command stuff */ int dflg; int kflg; int rflg; int vflg; int nflg; int bflg; int fflg; int iflg; int mflg; int tflg; int sflg; int reptime 10; char *coref; /* Buffered file read/write stuff */ extern char *bfilnm; /* Buffered input file name */ extern int bfile; /* Buffered input file */ extern char lbuf[]; int obuf[259]; main(argc, argv) char **argv; { register char *ap, c; char *symfile; obuf[0] = 1; if (argc > 1) { ap = argv[1]; while (*ap) switch (c = *ap++) { case 'a': mflg++; bflg++; iflg++; fflg++; tflg++; sflg++; break; case 'd': dflg++; break; case 'k': kflg++; break; case 'v': vflg++; case 'r': rflg++; break; case 'V': vflg++; case 'R': rflg++; argv++; argc--; reptime = atoi(argv[1]); break; case 'n': nflg++; break; case 'b': bflg++; break; case 'f': fflg++; break; case 'i': iflg++; break; case 'm': mflg++; break; case 'x': case 't': tflg++; break; case 's': sflg++; break; default: printf("Unknown switch '%c'\n", c); done(1); } } else { iflg++; fflg++; } bufsz = (sizeof(buf) / NBUF); /* See comment on declaration */ inodesz = (sizeof(inode) / NINODE); filesz = (sizeof(file) / NFILE); mountsz = (sizeof(mount) / NMOUNT); mdatasz = (sizeof(mdata) / NMOUNT); textsz = (sizeof(text) / NTEXT); setupnms(); symfile = ((argc > 2) ? argv[2] : "/unix"); nlist(symfile, nl); coref = ((argc > 3) ? argv[3] : "/dev/mem"); if (kflg) coref = "/usr/sys/core"; if ((mem = open(coref, 0)) < 0) serror("No kernel memory\n"); checknms(symfile); /* Needs access to kmem */ rdcdata(); tmem = endmem - stmem; for (;;) { if (vflg) cls(); rddata(); /* Need inode tables for next */ getmount(); if (mflg) prmount(); if (bflg) prbufs(); if (iflg) prinods(); if (fflg) prfiles(); if (tflg) prtexts(); if (sflg) prsysinf(); if (rflg == 0) break; fflush(&obuf[0]); sleep(reptime); } done(0); } setupnms() { register char *s, *p; struct nent *nlp; char **nmp; int i; nlp = &nl[0]; nmp = &names[0]; for (i = 0; (i < LSTNM); i++) { s = *nmp++; p = &(nlp++->name[0]); while (*p++ = *s++); } nlp->name[0] = 0; } /* Check that the namelist applies to the current system. */ checknms(symfile) char *symfile; { char *chkloc, *chkval; if (nl[0].type == 0) cerror("No namelist\n"); chkloc = nl[ENDSYS].value; chkval = rdloc(chkloc); if (dflg) { printf("chkl: %o\n", chkloc); printf("chkv: %o %o\n", nl[END].value, chkval); } if (chkval != nl[END].value) { printf("Symbol table in %s doesn't match running system\n", symfile); cerror("Bad namelist\n"); } } /* Read constant system data; next, check that compiled-in tables * are big enough, and if not, allocate a new one. * Eventually these will all be dynamically allocated from the get-go. * (Pain is that the system's .h files actually allocate tables in V6.) */ rdcdata() { rootdev = rdloc(nl[ROOTD].value); swapdev = rdloc(nl[SWAPD].value); stmem = rdloc(nl[STMEM].value); endmem = rdloc(nl[ENDMEM].value); swaplo = rdloc(nl[SWPLO].value); swapsz = rdloc(nl[NSWAP].value); nbuf = rdloc(nl[PNBUF].value); ninode = rdloc(nl[PNINODE].value); nfile = rdloc(nl[PNFILE].value); nmount = rdloc(nl[PNMOUNT].value); ntext = rdloc(nl[PNTEXT].value); cmapsiz = rdloc(nl[PCMAPSZ].value); smapsiz = rdloc(nl[PSMAPSZ].value); if (dflg) { printf("nbuf: %d %d\n", nbuf, NBUF); printf("ninode: %d %d\n", ninode, NINODE); printf("nfile: %d %d\n", nfile, NFILE); printf("nmount: %d %d\n", nmount, NMOUNT); printf("ntext: %d %d\n", ntext, NTEXT); printf("cmapsiz: %d %d\n", cmapsiz, CMAPSIZ); printf("cmapsiz: %d %d\n", cmapsiz, CMAPSIZ); } dotbl(&bufp, &buf[0], nbuf, NBUF, bufsz, "Buffer header"); dotbl(&inodep, &inode[0], ninode, NINODE, inodesz, "Inodes"); dotbl(&filep, &file[0], nfile, NFILE, filesz, "Files"); dotbl(&mountp, &mount[0], nmount, NMOUNT, mountsz, "Mount"); dotbl(&mdatap, &mdata[0], nmount, NMOUNT, mdatasz, "Mount data"); dotbl(&textp, &text[0], ntext, NTEXT, textsz, "Texts"); if (cmapsiz > CMAPSIZ) cerror("Allocate cmap"); if (smapsiz > SMAPSIZ) cerror("Allocate smap"); } dotbl(atblp, dtbl, ano, cno, siz, typ) char **atblp, *dtbl; char *typ; { register char **tblp; tblp = atblp; if (dflg) printf("dotbl: %s %o %o %d %d %d\n", typ, tblp, dtbl, ano, cno, siz); if (ano <= cno) { *tblp = dtbl; return; } *tblp = alloc(ano * siz); if (*tblp == NULL) { printf("%s\n", typ); serror("Can't allocate table"); } } /* Read all the dynamic databases in one slurp to prevent skew between their * contents as si itself changes things (e.g. reading inode mapping files). */ rddata() { rdtbl(nl[BUFS].value, bufp, (nbuf * bufsz), "Buffer table"); rdtbl(nl[INODES].value, inodep, (ninode * inodesz), "Inode table"); rdtbl(nl[FILES].value, filep, (nfile * filesz), "File table"); rdtbl(nl[TEXTS].value, textp, (ntext * textsz), "Text table"); rdtbl(nl[COREM].value, &coremap, sizeof(coremap), "Core table"); rdtbl(nl[SWAPM].value, &swapmap, sizeof(swapmap), "Swap table"); } /* Set up info about mounted filesystems. * * Algorithm is: scan over newly-read table; for entries which are the same * as before (or are still blank), skip; otherwise, something has changed. * If there was a previous entry, free its data; if there is no entry now, * mark the entry blank, and try the next. At this point, we're dealing with * either i) a previously blank entry which is now in use, or ii) an entry * which has changed; in either case, load its data. * * Minor devmask of 07 is a hack; HS devices for 1MB drives are * numbered 010-017 for devices 0-8. * * NOTE: Assumes all mount points are on the root! Will need some * work to handle non-root-filesystem mount points. */ getmount() { register struct mount *cmp, *smp; register struct mntdata *dp; struct mount *cmountp; int msiz, i; msiz = (nmount * mountsz); cmountp = alloca(msiz); if (cmountp == NULL) serror("Getmount: Can't allocate current mount table"); rdtbl(nl[MTAB].value, cmountp, msiz, "Mount table"); cmp = cmountp; smp = mountp; dp = mdatap; for (i = 0; (i < nmount); i++) { if ((cmp->m_bufp == smp->m_bufp) && (cmp->m_dev == smp->m_dev) && (cmp->m_inodp == smp->m_inodp)) { cmp++; smp++; dp++; continue; } if (dp->m_devf != NULL) freemnt(dp); if (cmp->m_bufp == 0) { smp->m_bufp = NULL; cmp++; smp++; dp++; continue; } if ((cmp->m_dev >> 8) >= MAXDSK) cerror("Unknown block device"); smp->m_bufp = cmp->m_bufp; smp->m_dev = cmp->m_dev; smp->m_inodp = cmp->m_inodp; addmount(smp, dp); gtrtblk(i, dp); cmp++; smp++; dp++; } } addmount(amp, adp) struct mount *amp; struct mntdata *adp; { register struct mount *mp; register struct mntdata *dp; register char *cp; char *bst, *mloc; int len; char *gtinnmp(); mp = amp; dp = adp; bst = nl[BUFS].value; dp->m_dev = mp->m_dev; dp->m_majdev = (mp->m_dev >> 8); dp->m_mindev = (mp->m_dev & 7); dp->m_bloc = bufp[((mp->m_bufp - bst) / bufsz)].b_addr; if (dflg) printf("adding mount %o/%o\n", dp->m_majdev, dp->m_mindev); cp = alloc(DDIRLEN + DFNMLEN + 2); if ((dp->m_devf = cp) == 0) serror("No mem for device file name"); cp = cpystr(&devnm[0], cp); cp = cpystr(dskfnames[dp->m_majdev], cp); *cp++ = ('0' + dp->m_mindev); *cp++ = '\0'; if (mp->m_inodp == 0) mloc = "/"; else mloc = gtinnmp(mp->m_inodp, ""); if ((len = (strlen(mloc) + 1)) <= 0) cerror("Bad mount point string"); cp = alloc(len); if ((dp->m_mpoint = cp) == 0) serror("No mem for device mount point"); cp = cpystr(mloc, cp); cp = alloc(len + FFNMLEN); if ((dp->m_mfile = cp) == 0) serror("No mem for file mapping filename"); if (len > 2) cp = cpystr(mloc, cp); cp = cpystr(&filesf[0], cp); } gtrtblk(i, adp) struct mntdata *adp; { register struct mntdata *dp; register struct filsys *fp; dp = adp; if (dflg) printf("getting root block '%s'\n", dp->m_devf); if ((fp = dp->m_filsys) == NULL) { fp = alloc(BLKSIZ); if ((dp->m_filsys = fp) == 0) serror("No mem for root block copy"); } rdtbl(dp->m_bloc, fp, BLKSIZ, "Root block"); dp->m_niblks = (fp->s_isize + 2); /* Boot and Root */ dp->m_ndblks = fp->s_fsize; if (dflg) printf("%d %o %o %d. %d. '%s' '%s' '%s'\n", i, dp->m_majdev, dp->m_mindev, dp->m_niblks, dp->m_ndblks, dp->m_devf, dp->m_mpoint, dp->m_mfile); } /* Have to free old ones, and re-allocate, because the lengths might * be different. */ freemnt(adp) struct mntdata *adp; { register struct mntdata *dp; dp = adp; if (dflg) printf("freeing mount '%s'\n", dp->m_devf); free(dp->m_devf); dp->m_devf = NULL; free(dp->m_mpoint); dp->m_mpoint = NULL; free(dp->m_mfile); dp->m_mfile = NULL; } struct mntdata *getdev(dev, must) { register struct mntdata *dp; int i; dp = mdatap; for (i = 0; (i < nmount); i++) { if (dp->m_devf == 0) { dp++; continue; } if (dp->m_dev == dev) return(dp); dp++; } if (must) cerror("Can't find dev"); else return(0); } /* Given a pointer to an inode entry in the kernel table, returns a pointer * to a copy of the inode entry in the table here. */ struct inode *gtinode(iaddr) { struct inode *iloc; int offset, tblno; if (iaddr == 0) cerror("Blank inode pointer gtinode"); offset = (iaddr - nl[INODES].value); tblno = (offset / inodesz); iloc = &inodep[tblno]; if (dflg > 1) printf("\niaddr: %o index %d. iloc: %o \n", iaddr, tblno, iloc); return(iloc); } /* Return partition-restricted inode file name, given its inode number and * device. * * If the inode number can't be found, try recomputing the inode number -> * file name mapping table, and try again. */ char *gtinnmn(dev, ino, alt) char *alt; { register struct mntdata *dp; register char *cp; int btmp, linel, inum; if (dflg) printf("gtinnmn: %o %d\n", dev, ino); dp = getdev(dev, 1); if (bfilnm != dp->m_mfile) { if (bfile != 0) bufclose(dflg); btmp = open(dp->m_mfile, 0); if (btmp < 0) newfnms(dp); else close(btmp); bufopen(dp->m_mfile, dflg); } bufstart(dflg); if (ino == 1) return("/"); for (;;) { linel = rdline(); if (linel == 1) break; inum = atoi(&lbuf[0]); if (dflg > 2) printf("chk %d: %s\n", inum, &lbuf[0]); if (inum != ino) continue; cp = &lbuf[0]; while (((*cp >= '0') && (*cp <= '9')) || (*cp == '\t')) cp++; return(cp); } if (dp->m_nread != 0) return(alt); newfnms(dp); return(gtinnmn(dev, ino, alt)); } /* Return partition-restricted inode file name, given a pointer to its inode * table entry in the kernel. */ char *gtinnmp(iaddr, alt) char *alt; { register struct inode *ip; if (dflg) printf("gtinnmp: %o\n", iaddr); if (iaddr == 0) cerror("Blank inode pointer gtinnmp"); ip = gtinode(iaddr); return(gtinnmn(ip->i_dev, ip->i_number, alt)); } /* Print full file name, given its inode number and device. */ char *prfnmn(dev, ino, alt, pdev) char *alt; { register struct mntdata *dp; char *fnm; if (dflg) printf("prfnmn: %o %d\n", dev, ino); if (dev != rootdev) dp = getdev(dev, 1); fnm = gtinnmn(dev, ino, alt); if (nflg) { if (pdev) printf("%o:%o-", (dev >> 8), (dev & 0377)); printf("%d\n", ino); return(0); } if (fnm != alt) { if (dev != rootdev) printf("%s", dp->m_mpoint); printf("%s\n", fnm); return(fnm); } printf("<%s "); if (pdev) printf("%o:%o-", (dev >> 8), (dev & 0377)); printf("%d>\n", ino); return(fnm); } /* Print full file name, given a pointer to its inode table entry in the * kernel. */ char *prfnmp(iaddr, alt, pdev) char *alt; { register struct inode *ip; register struct mntdata *dp; if (dflg) printf("\nprfnmp: %o\n", iaddr); if (iaddr == 0) cerror("Blank inode pointer prfnmp"); ip = gtinode(iaddr); return(prfnmn(ip->i_dev, ip->i_number, alt, pdev)); } /* Extreme hack; if we couldn't find an inode in the inode->filename * mappings file, re-create that by forking and doing an exec of "ncheck" * to produce an up-to-date listing. Only does it once per execution * of this command. * * Mode is 600 because there may be confidential parts of the hierarchy * in that dump. * * Close of stderr is to ditch device name string printed on stdout by * ncheck. Means we can't print an error message if exec fails, but I * guess we can live with that. (Could always reopen /dev/tty, I suppose!) */ newfnms(adp) struct mntdata *adp; { register struct mntdata *dp; int ffile, ofile; int pid, xpid, wret; int exec; dp = adp; if (dflg) printf("newfnms '%s'\n", dp->m_mfile); if (dflg && (dp->m_nread != 0)) { printf("Duplicate call to newfnms()\n"); return; } ffile = creat(dp->m_mfile, 0600); if (ffile < 0) serror("Can't open filename file for rewriting"); if ((pid = fork()) != 0) { if (pid == -1) serror("Fork for re-writing filename file failed"); if (close(ffile) == -1) serror("Close of re-writing filename file failed"); /* Test < 0 fails here, no idea why, err code = 0 */ xpid = wait(&wret); if (xpid == -1) serror("Wait for re-writing filename file failed"); if (xpid != pid) cerror("Unknown child for re-writing filename file"); dp->m_nread++; return; } close(1); ofile = dup(ffile); if (ofile != 1) { write(2, "Bad dup", 7); exit(1); } close(2); ofile = open("/dev/null", 1); exec = execl("/bin/ncheck", "ncheck", dp->m_devf, 0); exit(1); /* Just in case */ } prmount() { register struct mount *mp; register struct mntdata *dp; register struct filsys *fp; char *bst; int *tvec, i; printf("Slot Flags Dev SBlk IBlks DBlks IFree BFree Update Location\n"); bst = nl[BUFS].value; mp = mountp; for (i = 0; (i < nmount); i++) { if (mp->m_bufp == 0) { mp++; continue; } dp = getdev(mp->m_dev, 1); fp = dp->m_filsys; rdtbl(dp->m_bloc, fp, BLKSIZ, "Root block"); printf("%2o: %c", i, ((fp->s_ilock != 0) ? 'I' : ' ')); printf("%c", ((fp->s_flock != 0) ? 'F' : ' ')); printf("%c", ((fp->s_ronly != 0) ? 'R' : ' ')); printf("%c ", ((fp->s_fmod != 0) ? 'M' : ' ')); prdev(mp->m_dev); printf("%2d ", ((mp->m_bufp - bst) / bufsz)); printf("%4d %5l ", fp->s_isize, fp->s_fsize); printf("%3d %3d ", fp->s_ninode, fp->s_nfree); tvec = localtime(&fp->s_time[0]); prtime(tvec[2], ':'); prtime(tvec[1], ':'); prtime(tvec[0], ' '); if (mp->m_inodp == 0) printf("/\n"); else prfnmp(mp->m_inodp, "???", 1); mp++; } printf("\n"); } prbufs() { register struct buf *bp; struct mntdata *dp; int i, boff; printf("Slot Flags Dev Blk Location Err\n"); bp = bufp; for (i = 0; (i < nbuf); i++) { printf("%3d %c", i, (bp->b_flags & B_DELWRI) ? 'L' : ' '); printf("%c", (bp->b_flags & B_ASYNC) ? 'A' : ' '); printf("%c", (bp->b_flags & B_WANTED) ? 'W' : ' '); printf("%c", (bp->b_flags & B_MAP) ? 'M' : ' '); printf("%c", (bp->b_flags & B_PHYS) ? 'P' : ' '); printf("%c", (bp->b_flags & B_BUSY) ? 'B' : ' '); printf("%c", (bp->b_flags & B_ERROR) ? 'E' : ' '); printf("%c", (bp->b_flags & B_DONE) ? 'D' : ' '); printf("%c ", (bp->b_flags & B_READ) ? 'R' : 'W'); if (bp->b_dev == NODEV) printf(" "); else { prdev(bp->b_dev); dp = getdev(bp->b_dev, 0); if (dp != 0) prblk(dp, bp->b_blkno); else if ((bp->b_dev != swapdev) || (bp->b_blkno < swaplo)) printf("%5l ", bp->b_blkno); else { boff = (bp->b_blkno - swaplo); prblkno(bp->b_blkno, boff, 'S'); } } printf("%2o:%6o %2o\n", bp->b_xmem, bp->b_addr, bp->b_error); bp++; } printf("\n"); } prblk(adp, bno) struct mntdata *adp; { register struct mntdata *dp; dp = adp; if (bno < 2) printf("%5l %s ", bno, ((bno == 0) ? "(Boot) " : "(Super)")); else if (bno < dp->m_niblks) prblkno(bno, (bno - 2), 'I'); else if (bno < dp->m_ndblks) prblkno(bno, (bno - dp->m_niblks), 'D'); else printf("%5l ", bno); } prblkno(bno, boff, type) char type; { int nd; printf("%5l (%c%l) ", bno, type, boff); for (nd = ndigits(boff); (nd < 5); nd++) printf("%c", ' '); } prinods() { struct inode *ip; int i; printf("Slot Flags Count Dev Numb Mode File\n"); ip = inodep; for (i = 0; (i < ninode); i++) { if (dflg > 1) printf("index %d. iaddr: %o\n", i, ip); if (ip->i_count == 0) { ip++; continue; } printf("%3d %c", i, (ip->i_flag & ITEXT) ? 'T' : ' '); printf("%c", (ip->i_flag & IWANT) ? 'W' : ' '); printf("%c", (ip->i_flag & IMOUNT) ? 'M' : ' '); printf("%c", (ip->i_flag & IACC) ? 'A' : ' '); printf("%c", (ip->i_flag & IUPD) ? 'U' : ' '); printf("%c", (ip->i_flag & ILOCK) ? 'L' : ' '); printf(" %2d ", ip->i_count); prdev(ip->i_dev); printf("%4d %6o ", ip->i_number, ip->i_mode); /* i_nlink i_uid i_gid i_size0 i_size1 */ prfnmn(ip->i_dev, ip->i_number, "not in filesys", 0); ip++; } printf("\n"); } prfiles() { register struct file *fp, *ip; int i; printf("Slot Flags Count Offset File\n"); fp = filep; for (i = 0; (i < nfile); i++) { if (fp->f_count == 0) { fp++; continue; } printf("%3d %c", i, (fp->f_flag & FPIPE) ? 'P' : ' '); printf("%c", (fp->f_flag & FWRITE) ? 'W' : ' '); printf("%c", (fp->f_flag & FREAD) ? 'R' : ' '); printf(" %2d %4d-%-5l ", fp->f_count, fp->f_offset[0], fp->f_offset[1]); if ((fp->f_flag & FPIPE) != 0) { ip = gtinode(fp->f_inode); printf("pipe %d\n", ip->i_number); } else prfnmp(fp->f_inode, "deleted", 1); fp++; } printf("\n"); } prtexts() { register struct text *tp; int i; printf("Slot Disk Core Siz Usrs Load File\n"); tp = textp; for (i = 0; (i < ntext); i++) { if (tp->x_iptr == 0) { tp++; continue; } if (tp->x_ccount != 0) printf("%2o: %5o %5o %4d %3d %3d ", i, tp->x_daddr, tp->x_caddr, tp->x_size, tp->x_count, tp->x_ccount); else printf("%2o: %5o %4d %3d ", i, tp->x_daddr, tp->x_size, tp->x_count); prfnmp(tp->x_iptr, "deleted", 1); tp++; } printf("\n"); } prdev(dev) { int devmaj, devmin; devmaj = (dev >> 8); devmin = (dev & 0377); if (devmaj >= MAXDSK) cerror("Unknown block device"); printf("%2s/%-2o ", dsknames[devmaj], devmin); } mapfree(*amp) struct map *amp; { register struct map *mp; int space; space = 0; mp = amp; while (mp->m_size != 0) space =+ (mp++)->m_size; return(space); } prsysinf() { int i; pruptime(); i = mapfree(&coremap[0]); printf("Memory: %o start %d end %d total %d used %d free\n", (stmem * 0100), endmem, tmem, (tmem - i), i); i = mapfree(&swapmap[0]); printf("Swap: %d total %d used %d free\n", swapsz, (swapsz - i), i); } /* Bletcherous hack in handling of long division here; an uptime * of 3 weeks would be 1814400 second, which when divided into * minutes would be 30240, which will fit in an int. */ pruptime() { register r; int w, d, h, m, s; extern int ldivr; rdtbl(nl[UPTIME].value, &uptime[0], sizeof(uptime), "Uptime"); r = ldiv(uptime[0], uptime[1], 60); s = ldivr; m = r % 60; r =/ 60; h = r % 24; r =/ 24; d = r % 7; r =/ 7; w = r; printf("Uptime: "); if (w != 0) printf("%d week%c, ", w, ((w == 1) ? '\0' : 's')); if (d != 0) printf("%d day%c, ", d, ((d == 1) ? '\0' : 's')); if (h != 0) printf("%d hour%c, ", h, ((h == 1) ? '\0' : 's')); if (m != 0) printf("%d minute%c, ", m, ((m == 1) ? '\0' : 's')); printf("%d second%c\n", s, ((s == 1) ? '\0' : 's')); } rdloc(loc) { int t; if (seek(mem, loc, 0) < 0) serror("Read location seek failure"); if (read(mem, &t, sizeof(t)) != sizeof(t)) serror("Read location failure"); return(t); } rdtbl(loc, blk, size, nm) char *loc; char *blk; int size; char *nm; { if (dflg) printf("rdtbl: %s %o %o %d\n", nm, loc, blk, size); if (seek(mem, loc, 0) < 0) { printf("%s: ", nm); serror("Read table seek failure"); } if (read(mem, blk, size) != size) { printf("%s: ", nm); serror("Read table failure"); } } prtime(val, pad) char pad; { printf("%c%c%c", ('0' + (val / 10)), ('0' + (val % 10)), pad); } putchar(c) { putc(c, obuf); } done(type) { fflush(obuf); exit(type); }