/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint char copyright[] = "@(#) Copyright (c) 1980 Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)pstat.c 5.26 (Berkeley) 6/29/90"; #endif /* not lint */ /* * Print system stuff */ #include <sys/param.h> #include <sys/user.h> #include <sys/proc.h> #include <sys/text.h> #include <sys/time.h> #include <sys/vnode.h> #include <sys/map.h> #define KERNEL #define NFS #include <sys/file.h> #include <sys/mount.h> #include <ufs/quota.h> #include <ufs/inode.h> #include <sys/stat.h> #include <nfs/nfsv2.h> #include <nfs/nfs.h> #include <nfs/nfsnode.h> #include <sys/ioctl.h> #include <sys/tty.h> #undef KERNEL #include <sys/conf.h> #include <sys/vm.h> #include <machine/pte.h> #include <kvm.h> #include <nlist.h> #include <stdio.h> #include "pathnames.h" #define mask(x) (x&0377) #define clear(x) ((int)x &~ KERNBASE) char *fnlist = NULL; char *fcore = NULL; struct nlist nl[] = { #define STEXT 0 { "_text" }, #define SCONS 1 { "_cons" }, #define SPROC 2 { "_proc" }, #define SFIL 3 { "_file" }, #define SWAPMAP 4 { "_swapmap" }, #define SNPROC 5 { "_nproc" }, #define SNTEXT 6 { "_ntext" }, #define SNFILE 7 { "_nfile" }, #define SNSWAPMAP 8 { "_nswapmap" }, #define SPTY 9 { "_pt_tty" }, #define SDMMIN 10 { "_dmmin" }, #define SDMMAX 11 { "_dmmax" }, #define SNSWDEV 12 { "_nswdev" }, #define SSWDEVT 13 { "_swdevt" }, #define SNPTY 14 { "_npty" }, #ifdef vax #define SDZ (SNPTY+1) { "_dz_tty" }, #define SNDZ (SNPTY+2) { "_dz_cnt" }, #define SDMF (SNPTY+3) { "_dmf_tty" }, #define SNDMF (SNPTY+4) { "_ndmf" }, #define SDH (SNPTY+5) { "_dh11" }, #define SNDH (SNPTY+6) { "_ndh11" }, #define SDHU (SNPTY+7) { "_dhu_tty" }, #define SNDHU (SNPTY+8) { "_ndhu" }, #define SDMZ (SNPTY+9) { "_dmz_tty" }, #define SNDMZ (SNPTY+10) { "_ndmz" }, #define SQD (SNPTY+11) { "_qd_tty" }, #define SNQD (SNPTY+12) { "_nNQD" }, #endif #ifdef tahoe #define SVX (SNPTY+1) { "_vx_tty" }, #define SNVX (SNPTY+2) { "_nvx" }, #define SMP (SNPTY+3) { "_mp_tty" }, #define SNMP (SNPTY+4) { "_nmp" }, #endif { "" } }; int vnof; int txtf; int prcf; int ttyf; int usrf; int upid; int filf; int swpf; int totflg; char partab[1]; struct cdevsw cdevsw[1]; struct bdevsw bdevsw[1]; int allflg; int nflg; u_long getword(); off_t mkphys(); char *Program; main(argc, argv) int argc; char **argv; { extern char *optarg; extern int optind; int ch; Program = argv[0]; while ((ch = getopt(argc, argv, "Tafvikptu:sxn")) != EOF) switch((char)ch) { case 'T': totflg++; break; case 'a': allflg++; /*FALLTHROUGH*/ case 'p': prcf++; break; case 'f': filf++; break; case 'v': case 'i': vnof++; break; case 't': ttyf++; break; case 'u': usrf++; sscanf(optarg, "%d", &upid); break; case 's': swpf++; break; case 'x': txtf++; break; case 'n': nflg++; break; case '?': default: printf("usage: pstat -[Tafiptsx] [-u [pid]] [system] [core]\n"); exit(1); } argc -= optind; argv += optind; if (argc > 1) fcore = argv[1]; if (argc > 0) fnlist = argv[0]; if (kvm_openfiles(fnlist, fcore, NULL) == -1) { syserror("kvm_openfiles: %s", kvm_geterr()); exit(1); } if (kvm_nlist(nl) != 0) { syserror("kvm_nlist: %s", kvm_geterr()); exit(1); } if (!(filf | totflg | vnof | prcf | txtf | ttyf | usrf | swpf)) { printf("pstat: one or more of -[aivxptfsu] is required\n"); exit(1); } if (filf||totflg) dofile(); if (vnof||totflg) dovnode(); if (prcf||totflg) doproc(); if (txtf||totflg) dotext(); if (ttyf) dotty(); if (usrf) dousr(); if (swpf||totflg) doswap(); } struct e_vnode { struct vnode *avnode; struct vnode vnode; }; dovnode() { register struct e_vnode *e_vnodebase, *endvnode, *evp; register struct vnode *vp; register struct mount *maddr = NULL, *mp; register struct inode *ip; int numvnodes; struct e_vnode *loadvnodes(); struct mount *getmnt(); e_vnodebase = loadvnodes(&numvnodes); if (totflg) { printf("%7d vnodes\n", numvnodes); return; } endvnode = e_vnodebase + numvnodes; printf("%d active vnodes\n", numvnodes); #define ST mp->mnt_stat for (evp = e_vnodebase; evp < endvnode; evp++) { vp = &evp->vnode; if (vp->v_mount != maddr) { /* * New filesystem */ if ((mp = getmnt(vp->v_mount)) == NULL) continue; maddr = vp->v_mount; mount_print(mp); vnode_header(); switch(ST.f_type) { case MOUNT_UFS: case MOUNT_MFS: ufs_header(); break; case MOUNT_NFS: nfs_header(); break; case MOUNT_NONE: case MOUNT_PC: default: break; } printf("\n"); } vnode_print(evp->avnode, vp); switch(ST.f_type) { case MOUNT_UFS: case MOUNT_MFS: ufs_print(vp); break; case MOUNT_NFS: nfs_print(vp); break; case MOUNT_NONE: case MOUNT_PC: default: break; } printf("\n"); } free(e_vnodebase); } vnode_header() { printf("ADDR TYP VFLAG USE REF"); } vnode_print(avnode, vp) struct vnode *avnode; struct vnode *vp; { char *type, flags[16]; char *fp = flags; register flag; /* * set type */ switch(vp->v_type) { case VNON: type = "non"; break; case VREG: type = "reg"; break; case VDIR: type = "dir"; break; case VBLK: type = "blk"; break; case VCHR: type = "chr"; break; case VLNK: type = "lnk"; break; case VSOCK: type = "soc"; break; case VFIFO: type = "fif"; break; case VBAD: type = "bad"; break; default: type = "unk"; break; } /* * gather flags */ flag = vp->v_flag; if (flag & VROOT) *fp++ = 'R'; if (flag & VTEXT) *fp++ = 'T'; if (flag & VXLOCK) *fp++ = 'L'; if (flag & VXWANT) *fp++ = 'W'; if (flag & VEXLOCK) *fp++ = 'E'; if (flag & VSHLOCK) *fp++ = 'S'; if (flag & VLWAIT) *fp++ = 'T'; if (flag & VALIASED) *fp++ = 'A'; if (flag & VBWAIT) *fp++ = 'B'; if (flag == 0) *fp++ = '-'; *fp = '\0'; /* * print it */ printf("%8x %s %5s %4d %4d", avnode, type, flags, vp->v_usecount, vp->v_holdcnt); } ufs_header() { printf(" FILEID IFLAG RDEV|SZ"); } ufs_print(vp) struct vnode *vp; { struct inode *ip = VTOI(vp); char flagbuf[16], *flags = flagbuf; register flag; char *name; mode_t type; extern char *devname(); flag = ip->i_flag; if (flag & ILOCKED) *flags++ = 'L'; if (flag & IWANT) *flags++ = 'W'; if (flag & IRENAME) *flags++ = 'R'; if (flag & IUPD) *flags++ = 'U'; if (flag & IACC) *flags++ = 'A'; if (flag & ICHG) *flags++ = 'C'; if (flag & IMOD) *flags++ = 'M'; if (flag & ISHLOCK) *flags++ = 'S'; if (flag & IEXLOCK) *flags++ = 'E'; if (flag & ILWAIT) *flags++ = 'Z'; if (flag == 0) *flags++ = '-'; *flags = '\0'; printf(" %6d %5s", ip->i_number, flagbuf); type = ip->i_mode & S_IFMT; if (type == S_IFCHR || type == S_IFBLK) if (nflg || ((name = devname(ip->i_rdev, type)) == NULL)) printf(" %2d,%-2d", major(ip->i_rdev), minor(ip->i_rdev)); else printf(" %7s", name); else printf(" %7d", ip->i_size); } nfs_header() { printf(" FILEID NFLAG RDEV|SZ"); } nfs_print(vp) struct vnode *vp; { struct nfsnode *np = VTONFS(vp); char flagbuf[16], *flags = flagbuf; register flag; char *name; mode_t type; extern char *devname(); flag = np->n_flag; if (flag & NLOCKED) *flags++ = 'L'; if (flag & NWANT) *flags++ = 'W'; if (flag & NMODIFIED) *flags++ = 'M'; if (flag & NWRITEERR) *flags++ = 'E'; if (flag == 0) *flags++ = '-'; *flags = '\0'; #define VT np->n_vattr printf(" %6d %5s", VT.va_fileid, flagbuf); type = VT.va_mode & S_IFMT; if (type == S_IFCHR || type == S_IFBLK) if (nflg || ((name = devname(VT.va_rdev, type)) == NULL)) printf(" %2d,%-2d", major(VT.va_rdev), minor(VT.va_rdev)); else printf(" %7s", name); else printf(" %7d", np->n_size); } /* * Given a pointer to a mount structure in kernel space, * read it in and return a usable pointer to it. */ struct mount * getmnt(maddr) struct mount *maddr; { static struct mtab { struct mtab *next; struct mount *maddr; struct mount mount; } *mhead = NULL; register struct mtab *mt; for (mt = mhead; mt != NULL; mt = mt->next) if (maddr == mt->maddr) return (&mt->mount); if ((mt = (struct mtab *)malloc(sizeof (struct mtab))) == NULL) { error("out of memory"); exit(1); } if (kvm_read((off_t)maddr, &mt->mount, sizeof(struct mount)) != sizeof(struct mount)) { error("can't read mount table at %x", maddr); return (NULL); } mt->maddr = maddr; mt->next = mhead; mhead = mt; return (&mt->mount); } mount_print(mp) struct mount *mp; { char *type = "unknown"; register flags; #define ST mp->mnt_stat printf("*** MOUNT "); switch (ST.f_type) { case MOUNT_NONE: type = "none"; break; case MOUNT_UFS: type = "ufs"; break; case MOUNT_NFS: type = "nfs"; break; case MOUNT_MFS: type = "mfs"; break; case MOUNT_PC: type = "pc"; break; } printf("%s %s on %s", type, ST.f_mntfromname, ST.f_mntonname); if (flags = mp->mnt_flag) { char *comma = "("; putchar(' '); /* user visable flags */ if (flags & MNT_RDONLY) { printf("%srdonly", comma); flags &= ~MNT_RDONLY; comma = ","; } if (flags & MNT_SYNCHRONOUS) { printf("%ssynchronous", comma); flags &= ~MNT_SYNCHRONOUS; comma = ","; } if (flags & MNT_NOEXEC) { printf("%snoexec", comma); flags &= ~MNT_NOEXEC; comma = ","; } if (flags & MNT_NOSUID) { printf("%snosuid", comma); flags &= ~MNT_NOSUID; comma = ","; } if (flags & MNT_NODEV) { printf("%snodev", comma); flags &= ~MNT_NODEV; comma = ","; } if (flags & MNT_EXPORTED) { printf("%sexport", comma); flags &= ~MNT_EXPORTED; comma = ","; } if (flags & MNT_EXRDONLY) { printf("%sexrdonly", comma); flags &= ~MNT_EXRDONLY; comma = ","; } if (flags & MNT_LOCAL) { printf("%slocal", comma); flags &= ~MNT_LOCAL; comma = ","; } if (flags & MNT_QUOTA) { printf("%squota", comma); flags &= ~MNT_QUOTA; comma = ","; } /* filesystem control flags */ if (flags & MNT_UPDATE) { printf("%supdate", comma); flags &= ~MNT_UPDATE; comma = ","; } if (flags & MNT_MLOCK) { printf("%slock", comma); flags &= ~MNT_MLOCK; comma = ","; } if (flags & MNT_MWAIT) { printf("%swait", comma); flags &= ~MNT_MWAIT; comma = ","; } if (flags & MNT_MPBUSY) { printf("%sbusy", comma); flags &= ~MNT_MPBUSY; comma = ","; } if (flags & MNT_MPWANT) { printf("%swant", comma); flags &= ~MNT_MPWANT; comma = ","; } if (flags & MNT_UNMOUNT) { printf("%sunmount", comma); flags &= ~MNT_UNMOUNT; comma = ","; } if (flags) printf("%sunknown_flags:%x", flags); printf(")"); } printf("\n"); #undef ST } struct e_vnode * loadvnodes(avnodes) int *avnodes; { int ret, copysize, i; struct e_vnode *vnodebase; if (fcore != NULL) { error("vnodes on dead kernel, not impl yet\n"); exit(1); } if ((ret = getkerninfo(KINFO_VNODE, NULL, NULL, 0)) == -1) { syserror("can't get estimate for kerninfo"); exit(1); } copysize = ret; if ((vnodebase = (struct e_vnode *)malloc(copysize)) == NULL) { error("out of memory"); exit(1); } if ((ret = getkerninfo(KINFO_VNODE, vnodebase, ©size, 0)) == -1) { syserror("can't get vnode list"); exit(1); } if (copysize % sizeof (struct e_vnode)) { error("vnode size mismatch"); error(1); } *avnodes = copysize / sizeof (struct e_vnode); return (vnodebase); } u_long getword(loc) off_t loc; { u_long word; kvm_read(loc, &word, sizeof (word)); return (word); } putf(v, n) { if (v) printf("%c", n); else printf(" "); } dotext() { register struct text *xp; int ntext; struct text *xtext, *atext; int ntx, ntxca; ntx = ntxca = 0; ntext = getword(nl[SNTEXT].n_value); xtext = (struct text *)calloc(ntext, sizeof (struct text)); atext = (struct text *)getword(nl[STEXT].n_value); if (ntext < 0 || ntext > 10000) { fprintf(stderr, "number of texts is preposterous (%d)\n", ntext); return; } if (xtext == NULL) { fprintf(stderr, "can't allocate memory for text table\n"); return; } kvm_read(atext, xtext, ntext * sizeof (struct text)); for (xp = xtext; xp < &xtext[ntext]; xp++) { if (xp->x_vptr != NULL) ntxca++; if (xp->x_count != 0) ntx++; } if (totflg) { printf("%3d/%3d texts active, %3d used\n", ntx, ntext, ntxca); return; } printf("%d/%d active texts, %d used\n", ntx, ntext, ntxca); printf("\ LOC FLAGS DADDR CADDR RSS SIZE VPTR CNT CCNT FORW BACK\n"); for (xp = xtext; xp < &xtext[ntext]; xp++) { if (xp->x_vptr == NULL) continue; printf("%8.1x", atext + (xp - xtext)); printf(" "); putf(xp->x_flag&XPAGV, 'P'); putf(xp->x_flag&XTRC, 'T'); putf(xp->x_flag&XWRIT, 'W'); putf(xp->x_flag&XLOAD, 'L'); putf(xp->x_flag&XLOCK, 'K'); putf(xp->x_flag&XWANT, 'w'); printf("%5x", xp->x_daddr[0]); printf("%10x", xp->x_caddr); printf("%5d", xp->x_rssize); printf("%5d", xp->x_size); printf("%10.1x", xp->x_vptr); printf("%5d", xp->x_count&0377); printf("%5d", xp->x_ccount); printf("%10x", xp->x_forw); printf("%9x", xp->x_back); printf("\n"); } free(xtext); } doproc() { struct proc *xproc, *aproc; int nproc; register struct proc *pp; register loc, np; struct pte apte; nproc = getword(nl[SNPROC].n_value); xproc = (struct proc *)calloc(nproc, sizeof (struct proc)); aproc = (struct proc *)getword(nl[SPROC].n_value); if (nproc < 0 || nproc > 10000) { fprintf(stderr, "number of procs is preposterous (%d)\n", nproc); return; } if (xproc == NULL) { fprintf(stderr, "can't allocate memory for proc table\n"); return; } kvm_read(aproc, xproc, nproc * sizeof (struct proc)); np = 0; for (pp=xproc; pp < &xproc[nproc]; pp++) if (pp->p_stat) np++; if (totflg) { printf("%3d/%3d processes\n", np, nproc); return; } printf("%d/%d processes\n", np, nproc); printf(" LOC S F POIP PRI SIG UID SLP TIM CPU NI PID PPID ADDR RSS SRSS SIZE WCHAN LINK TEXTP\n"); for (pp=xproc; pp<&xproc[nproc]; pp++) { if (pp->p_stat==0 && allflg==0) continue; printf("%8x", aproc + (pp - xproc)); printf(" %2d", pp->p_stat); printf(" %8x", pp->p_flag); printf(" %4d", pp->p_poip); printf(" %3d", pp->p_pri); printf(" %8x", pp->p_sig); printf(" %4d", pp->p_uid); printf(" %3d", pp->p_slptime); printf(" %3d", pp->p_time); printf(" %4d", pp->p_cpu&0377); printf(" %3d", pp->p_nice); printf(" %6d", pp->p_pid); printf(" %6d", pp->p_ppid); /* if (pp->p_flag & SLOAD) { kvm_read(pp->p_addr, &apte, sizeof(apte)); printf(" %8x", apte.pg_pfnum); } else printf(" %8x", pp->p_swaddr); */ printf(" %4x", pp->p_rssize); printf(" %4x", pp->p_swrss); printf(" %5x", pp->p_dsize+pp->p_ssize); printf(" %7x", clear(pp->p_wchan)); printf(" %7x", clear(pp->p_link)); printf(" %7x", clear(pp->p_textp)); printf("\n"); } free(xproc); } char mesg[] = "LINE RAW CAN OUT RCC CCC OCC HWT LWT ADDR COL STATE PGID DISC\n"; int ttyspace = 128; struct tty *tty; dotty() { if ((tty = (struct tty *)malloc(ttyspace * sizeof(*tty))) == 0) { printf("pstat: out of memory\n"); return; } printf("1 cons\n"); kvm_read((long)nl[SCONS].n_value, tty, sizeof(*tty)); printf(mesg); ttyprt(&tty[0], 0); #ifdef vax if (nl[SNQD].n_type != 0) doqdss(); if (nl[SNDZ].n_type != 0) dottytype("dz", SDZ, SNDZ); if (nl[SNDH].n_type != 0) dottytype("dh", SDH, SNDH); if (nl[SNDMF].n_type != 0) dottytype("dmf", SDMF, SNDMF); if (nl[SNDHU].n_type != 0) dottytype("dhu", SDHU, SNDHU); if (nl[SNDMZ].n_type != 0) dottytype("dmz", SDMZ, SNDMZ); #endif #ifdef tahoe if (nl[SNVX].n_type != 0) dottytype("vx", SVX, SNVX); if (nl[SNMP].n_type != 0) dottytype("mp", SMP, SNMP); #endif if (nl[SNPTY].n_type != 0) dottytype("pty", SPTY, SNPTY); } /* * Special case the qdss: there are 4 ttys per qdss, * but only the first of each is used as a tty. */ #ifdef vax doqdss() { int nqd; register struct tty *tp; kvm_read((long)nl[SNQD].n_value, &nqd, sizeof(nqd)); printf("%d qd\n", nqd); kvm_read((long)nl[SQD].n_value, tty, nqd * sizeof(struct tty) * 4); printf(mesg); for (tp = tty; tp < &tty[nqd * 4]; tp += 4) ttyprt(tp, tp - tty); } #endif dottytype(name, type, number) char *name; { int ntty; register struct tty *tp; extern char *realloc(); if (tty == (struct tty *)0) return; kvm_read((long)nl[number].n_value, &ntty, sizeof(ntty)); printf("%d %s lines\n", ntty, name); if (ntty > ttyspace) { ttyspace = ntty; if ((tty = (struct tty *)realloc(tty, ttyspace * sizeof(*tty))) == 0) { printf("pstat: out of memory\n"); return; } } kvm_read((long)nl[type].n_value, tty, ntty * sizeof(struct tty)); printf(mesg); for (tp = tty; tp < &tty[ntty]; tp++) ttyprt(tp, tp - tty); } struct { int flag; char val; } ttystates[] = { TS_WOPEN, 'W', TS_ISOPEN, 'O', TS_CARR_ON, 'C', TS_TIMEOUT, 'T', TS_FLUSH, 'F', TS_BUSY, 'B', TS_ASLEEP, 'A', TS_XCLUDE, 'X', TS_TTSTOP, 'S', TS_HUPCLS, 'H', TS_TBLOCK, 'K', TS_RCOLL, 'R', TS_WCOLL, 'I', /* running short on letters ! */ TS_ASYNC, 'Y', TS_BKSL, 'D', TS_ERASE, 'E', TS_LNCH, 'L', TS_TYPEN, 'P', TS_CNTTB, 'N', 0, 0 }; ttyprt(atp, line) struct tty *atp; { register struct tty *tp; char state[20]; register i, j; char *name; extern char *devname(); pid_t pgid; tp = atp; if (nflg || tp->t_dev == 0 || /* XXX */ (name = devname(tp->t_dev, S_IFCHR)) == NULL) printf("%7d ", line); else printf("%7s ", name); printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc); printf("%3d %6d %6d %6d %4d %3d %8x %3d ", tp->t_outq.c_cc, tp->t_rawcc, tp->t_cancc, tp->t_outcc, tp->t_hiwat, tp->t_lowat, tp->t_addr, tp->t_col); for (i = j = 0; ttystates[i].flag; i++) if (tp->t_state&ttystates[i].flag) state[j++] = ttystates[i].val; state[j] = '\0'; printf("%-4s ", state); if (tp->t_pgrp == NULL || kvm_read(&tp->t_pgrp->pg_id, &pgid, sizeof (pid_t)) != sizeof (pid_t)) pgid = 0; printf("%6d ", pgid); switch (tp->t_line) { case 0: printf("term\n"); break; case TABLDISC: printf("tab\n"); break; case SLIPDISC: printf("slip\n"); break; default: printf("%d\n", tp->t_line); } } dousr() { #ifdef notyet register struct user *up; register i, j, *ip; register struct nameidata *nd = &U.u_nd; struct proc *p; /* This wins only if CLBYTES >= sizeof (struct user) */ /* (WHICH IT ISN'T, but u. is going away - so who cares */ if (kvm_getprocs(KINFO_PROC_PID, upid) != 0) { error("kvm_getproc: %s", kvm_geterr()); return (1); } if ((p = kvm_nextproc()); == NULL) { error("kvm_nextproc: %s", kvm_geterr()); return (1); } if (up = kvm_getu(p)) == NULL) { error("kvm_getu: %s", kvm_geterr()); return (1); } printf("pcb"); ip = (int *)&up->u_pcb; while (ip < &up->u_arg[0]) { if ((ip - (int *)&up->u_pcb) % 4 == 0) printf("\t"); printf("%x ", *ip++); if ((ip - (int *)&up->u_pcb) % 4 == 0) printf("\n"); } if ((ip - (int *)&up->u_pcb) % 4 != 0) printf("\n"); printf("arg"); for (i=0; i<sizeof(up->u_arg)/sizeof(up->u_arg[0]); i++) { if (i%5==0) printf("\t"); printf(" %.1x", up->u_arg[i]); if (i%5==4) printf("\n"); } if (i%5) printf("\n"); printf("segflg\t%d\nerror %d\n", nd->ni_segflg, up->u_error); printf("uids\t%d,%d,%d,%d\n", up->u_uid,up->u_gid,up->u_ruid,up->u_rgid); printf("procp\t%.1x\n", up->u_procp); printf("ap\t%.1x\n", up->u_ap); printf("r_val?\t%.1x %.1x\n", up->u_r.r_val1, up->u_r.r_val2); printf("base, count, offset %.1x %.1x %ld\n", nd->ni_base, nd->ni_count, nd->ni_offset); printf("cdir rdir %.1x %.1x\n", up->u_cdir, up->u_rdir); printf("dirp %.1x\n", nd->ni_dirp); printf("dent %d %.14s\n", nd->ni_dent.d_ino, nd->ni_dent.d_name); printf("dvp vp %.1x %.1x\n", nd->ni_dvp, nd->ni_vp); printf("file"); for (i=0; i<NOFILE; i++) { if (i % 8 == 0) printf("\t"); printf("%9.1x", up->u_ofile[i]); if (i % 8 == 7) printf("\n"); } if (i % 8) printf("\n"); printf("pofile"); for (i=0; i<NOFILE; i++) { if (i % 8 == 0) printf("\t"); printf("%9.1x", up->u_pofile[i]); if (i % 8 == 7) printf("\n"); } if (i % 8) printf("\n"); printf("ssave"); for (i=0; i<sizeof(label_t)/sizeof(int); i++) { if (i%5==0) printf("\t"); printf("%9.1x", up->u_ssave.val[i]); if (i%5==4) printf("\n"); } if (i%5) printf("\n"); printf("sigs"); for (i=0; i<NSIG; i++) { if (i % 8 == 0) printf("\t"); printf("%.1x ", up->u_signal[i]); if (i % 8 == 7) printf("\n"); } if (i % 8) printf("\n"); printf("code\t%.1x\n", up->u_code); printf("ar0\t%.1x\n", up->u_ar0); printf("prof\t%x %x %x %x\n", up->u_prof.pr_base, up->u_prof.pr_size, up->u_prof.pr_off, up->u_prof.pr_scale); printf("start\t%ld\n", up->u_start.tv_sec); printf("acflag\t%ld\n", up->u_acflag); printf("cmask\t%ld\n", up->u_cmask); printf("sizes\t%.1x %.1x %.1x\n", up->u_tsize, up->u_dsize, up->u_ssize); printf("ru\t"); ip = (int *)&up->u_ru; for (i = 0; i < sizeof(up->u_ru)/sizeof(int); i++) printf("%ld ", ip[i]); printf("\n"); ip = (int *)&up->u_cru; printf("cru\t"); for (i = 0; i < sizeof(up->u_cru)/sizeof(int); i++) printf("%ld ", ip[i]); printf("\n"); #ifdef notdef i = up->u_stack - &U; while (U[++i] == 0); i &= ~07; while (i < 512) { printf("%x ", 0140000+2*i); for (j=0; j<8; j++) printf("%9x", U[i++]); printf("\n"); } #endif #endif } oatoi(s) char *s; { register v; v = 0; while (*s) v = (v<<3) + *s++ - '0'; return(v); } dofile() { int nfile; struct file *xfile, *afile; register struct file *fp; register nf; int loc; static char *dtypes[] = { "???", "inode", "socket" }; nf = 0; nfile = getword(nl[SNFILE].n_value); xfile = (struct file *)calloc(nfile, sizeof (struct file)); afile = (struct file *)getword(nl[SFIL].n_value); if (nfile < 0 || nfile > 10000) { fprintf(stderr, "number of files is preposterous (%d)\n", nfile); return; } if (xfile == NULL) { fprintf(stderr, "can't allocate memory for file table\n"); return; } kvm_read(afile, xfile, nfile * sizeof (struct file)); for (fp=xfile; fp < &xfile[nfile]; fp++) if (fp->f_count) nf++; if (totflg) { printf("%3d/%3d files\n", nf, nfile); return; } printf("%d/%d open files\n", nf, nfile); printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n"); for (fp=xfile,loc=(int)afile; fp < &xfile[nfile]; fp++,loc+=sizeof(xfile[0])) { if (fp->f_count==0) continue; printf("%8x ", loc); if (fp->f_type <= DTYPE_SOCKET) printf("%-8.8s", dtypes[fp->f_type]); else printf("%8d", fp->f_type); putf(fp->f_flag&FREAD, 'R'); putf(fp->f_flag&FWRITE, 'W'); putf(fp->f_flag&FAPPEND, 'A'); putf(fp->f_flag&FSHLOCK, 'S'); putf(fp->f_flag&FEXLOCK, 'X'); putf(fp->f_flag&FASYNC, 'I'); printf(" %3d", mask(fp->f_count)); printf(" %3d", mask(fp->f_msgcount)); printf(" %8.1x", fp->f_data); if (fp->f_offset < 0) printf(" %x\n", fp->f_offset); else printf(" %ld\n", fp->f_offset); } free(xfile); } int dmmin, dmmax, nswdev; doswap() { struct proc *proc; int nproc; struct text *xtext; int ntext; struct map *swapmap; int nswapmap; struct swdevt *swdevt, *sw; register struct proc *pp; int nswap, used, tused, free, waste; int db, sb; register struct mapent *me; register struct text *xp; int i, j; long rmalloc(); nproc = getword(nl[SNPROC].n_value); ntext = getword(nl[SNTEXT].n_value); if (nproc < 0 || nproc > 10000 || ntext < 0 || ntext > 10000) { fprintf(stderr, "number of procs/texts is preposterous (%d, %d)\n", nproc, ntext); return; } proc = (struct proc *)calloc(nproc, sizeof (struct proc)); if (proc == NULL) { fprintf(stderr, "can't allocate memory for proc table\n"); exit(1); } xtext = (struct text *)calloc(ntext, sizeof (struct text)); if (xtext == NULL) { fprintf(stderr, "can't allocate memory for text table\n"); exit(1); } nswapmap = getword(nl[SNSWAPMAP].n_value); swapmap = (struct map *)calloc(nswapmap, sizeof (struct map)); if (swapmap == NULL) { fprintf(stderr, "can't allocate memory for swapmap\n"); exit(1); } nswdev = getword(nl[SNSWDEV].n_value); swdevt = (struct swdevt *)calloc(nswdev, sizeof (struct swdevt)); if (swdevt == NULL) { fprintf(stderr, "can't allocate memory for swdevt table\n"); exit(1); } kvm_read(nl[SSWDEVT].n_value, swdevt, nswdev * sizeof (struct swdevt)); kvm_read(nl[SPROC].n_value, proc, nproc * sizeof (struct proc)); kvm_read(nl[STEXT].n_value, xtext, ntext * sizeof (struct text)); kvm_read(nl[SWAPMAP].n_value, swapmap, nswapmap * sizeof (struct map)); swapmap->m_name = "swap"; swapmap->m_limit = (struct mapent *)&swapmap[nswapmap]; dmmin = getword(nl[SDMMIN].n_value); dmmax = getword(nl[SDMMAX].n_value); nswap = 0; for (sw = swdevt; sw < &swdevt[nswdev]; sw++) if (sw->sw_freed) nswap += sw->sw_nblks; free = 0; for (me = (struct mapent *)(swapmap+1); me < (struct mapent *)&swapmap[nswapmap]; me++) free += me->m_size; tused = 0; for (xp = xtext; xp < &xtext[ntext]; xp++) if (xp->x_vptr!=NULL) { tused += ctod(clrnd(xp->x_size)); if (xp->x_flag & XPAGV) tused += ctod(clrnd(ctopt(xp->x_size))); } used = tused; waste = 0; for (pp = proc; pp < &proc[nproc]; pp++) { if (pp->p_stat == 0 || pp->p_stat == SZOMB) continue; if (pp->p_flag & SSYS) continue; db = ctod(pp->p_dsize), sb = up(db); used += sb; waste += sb - db; db = ctod(pp->p_ssize), sb = up(db); used += sb; waste += sb - db; if ((pp->p_flag&SLOAD) == 0) used += ctod(vusize(pp)); } if (totflg) { #define btok(x) ((x) / (1024 / DEV_BSIZE)) printf("%3d/%3d 00k swap\n", btok(used/100), btok((used+free)/100)); return; } printf("%dk used (%dk text), %dk free, %dk wasted, %dk missing\n", btok(used), btok(tused), btok(free), btok(waste), /* a dmmax/2 block goes to argmap */ btok(nswap - dmmax/2 - (used + free))); printf("avail: "); for (i = dmmax; i >= dmmin; i /= 2) { j = 0; while (rmalloc(swapmap, i) != 0) j++; if (j) printf("%d*%dk ", j, btok(i)); } free = 0; for (me = (struct mapent *)(swapmap+1); me < (struct mapent *)&swapmap[nswapmap]; me++) free += me->m_size; printf("%d*1k\n", btok(free)); } up(size) register int size; { register int i, block; i = 0; block = dmmin; while (i < size) { i += block; if (block < dmmax) block *= 2; } return (i); } /* * Compute number of pages to be allocated to the u. area * and data and stack area page tables, which are stored on the * disk immediately after the u. area. */ vusize(p) register struct proc *p; { register int tsz = p->p_tsize / NPTEPG; /* * We do not need page table space on the disk for page * table pages wholly containing text. */ return (clrnd(UPAGES + clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES)) - tsz)); } /* * Allocate 'size' units from the given * map. Return the base of the allocated space. * In a map, the addresses are increasing and the * list is terminated by a 0 size. * * Algorithm is first-fit. * * This routine knows about the interleaving of the swapmap * and handles that. */ long rmalloc(mp, size) register struct map *mp; long size; { register struct mapent *ep = (struct mapent *)(mp+1); register int addr; register struct mapent *bp; swblk_t first, rest; if (size <= 0 || size > dmmax) return (0); /* * Search for a piece of the resource map which has enough * free space to accomodate the request. */ for (bp = ep; bp->m_size; bp++) { if (bp->m_size >= size) { /* * If allocating from swapmap, * then have to respect interleaving * boundaries. */ if (nswdev > 1 && (first = dmmax - bp->m_addr%dmmax) < bp->m_size) { if (bp->m_size - first < size) continue; addr = bp->m_addr + first; rest = bp->m_size - first - size; bp->m_size = first; if (rest) rmfree(mp, rest, addr+size); return (addr); } /* * Allocate from the map. * If there is no space left of the piece * we allocated from, move the rest of * the pieces to the left. */ addr = bp->m_addr; bp->m_addr += size; if ((bp->m_size -= size) == 0) { do { bp++; (bp-1)->m_addr = bp->m_addr; } while ((bp-1)->m_size = bp->m_size); } if (addr % CLSIZE) return (0); return (addr); } } return (0); } /* * Free the previously allocated space at addr * of size units into the specified map. * Sort addr into map and combine on * one or both ends if possible. */ rmfree(mp, size, addr) struct map *mp; long size, addr; { struct mapent *firstbp; register struct mapent *bp; register int t; /* * Both address and size must be * positive, or the protocol has broken down. */ if (addr <= 0 || size <= 0) goto badrmfree; /* * Locate the piece of the map which starts after the * returned space (or the end of the map). */ firstbp = bp = (struct mapent *)(mp + 1); for (; bp->m_addr <= addr && bp->m_size != 0; bp++) continue; /* * If the piece on the left abuts us, * then we should combine with it. */ if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) { /* * Check no overlap (internal error). */ if ((bp-1)->m_addr+(bp-1)->m_size > addr) goto badrmfree; /* * Add into piece on the left by increasing its size. */ (bp-1)->m_size += size; /* * If the combined piece abuts the piece on * the right now, compress it in also, * by shifting the remaining pieces of the map over. */ if (bp->m_addr && addr+size >= bp->m_addr) { if (addr+size > bp->m_addr) goto badrmfree; (bp-1)->m_size += bp->m_size; while (bp->m_size) { bp++; (bp-1)->m_addr = bp->m_addr; (bp-1)->m_size = bp->m_size; } } goto done; } /* * Don't abut on the left, check for abutting on * the right. */ if (addr+size >= bp->m_addr && bp->m_size) { if (addr+size > bp->m_addr) goto badrmfree; bp->m_addr -= size; bp->m_size += size; goto done; } /* * Don't abut at all. Make a new entry * and check for map overflow. */ do { t = bp->m_addr; bp->m_addr = addr; addr = t; t = bp->m_size; bp->m_size = size; bp++; } while (size = t); /* * Segment at bp is to be the delimiter; * If there is not room for it * then the table is too full * and we must discard something. */ if (bp+1 > mp->m_limit) { /* * Back bp up to last available segment. * which contains a segment already and must * be made into the delimiter. * Discard second to last entry, * since it is presumably smaller than the last * and move the last entry back one. */ bp--; printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name, (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size); bp[-1] = bp[0]; bp[0].m_size = bp[0].m_addr = 0; } done: return; badrmfree: printf("bad rmfree\n"); } #include <varargs.h> error(va_alist) va_dcl { char *fmt; va_list ap; extern errno; fprintf(stderr, "%s: ", Program); va_start(ap); fmt = va_arg(ap, char *); (void) vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } syserror(va_alist) va_dcl { char *fmt; va_list ap; extern errno; fprintf(stderr, "%s: ", Program); va_start(ap); fmt = va_arg(ap, char *); (void) vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, ": %s\n", strerror(errno)); }