Subject: C compiler prototype redefines static variable, new top(1) program Index: src/lib/ccom/c03.c,ansi.c src/ucb/top Description: ANSI C prototype declaraction overwrites static data item declaration. top(1) program not present in 2.11BSD Repeat-By: 1) Examine the generated code (cc -S foo.c) from this test case: ------- static char *screen; static void clr_scr(char *screen) { memset(screen, ' ', 100); } main() { char *s; screen = s; } ------- Note that the use of screen in main() does not refer to the static data item (_screen) but to the local function argument 4(r5) in clr_scr() -----bad----- _main: jsr r5,csv jbr L4 L5:~s=177766 mov -12(r5),4(r5) L6:jmp cret L4:tst -(sp) jbr L5 ------fixed----- _main: jsr r5,csv jbr L4 L5:~s=177766 mov -12(r5),_screen L6:jmp cret L4:tst -(sp) jbr L5 2) Inspection shows there is no top(1) program present in the system. Fix: Thanks to digbyt42@gmail.com for contributing top(1) to the system. The program will be enhanced in the future - email Digby with feedback and feature requests. Thanks for ragge@tethuvudet.se's very fast response to the report of an error in the ANSI prototype handling. In addition to fixing the reported bugt the ability to parse statement "const int *const *volatile *c;" was added. (Something we didn't know we needed ;-)) This update is somewhat more complicated because not only are files patched but new program sources are being added to the system. There is an extra step involved in unpacking the files. Cut where indicated and save to a file (/tmp/465). Then cd /tmp sh 465 sh top.shar cd / patch -p0 < /tmp/465.patch cd /usr/src/lib/ccom make make install make clean cd /usr/src/ucb/top make make install make clean This and previous updates to 2.11BSD are available at the following locations: ftp://ftp.update.uu.se/pub/pdp11/2.11BSD https://www.tuhs.org/Archive/Distributions/UCB/2.11BSD/Patches/ ftp://ftp.2bsd.com/2.11BSD ---------------------------cut here-------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # 465.patch # top.shar # This archive created: Tue Mar 10 07:58:00 2020 export PATH; PATH=/bin:/usr/bin:$PATH if test -f '465.patch' then echo shar: "will not over-write existing file '465.patch'" else sed 's/^X//' << \SHAR_EOF > '465.patch' X*** ./usr/src/lib/ccom/c03.c.old Tue Jan 7 13:22:29 2020 X--- ./usr/src/lib/ccom/c03.c Mon Mar 9 19:05:10 2020 X*************** X*** 582,588 **** X X defsym = 0; X type = 0; X! switch(o=symbol()) { X X case TIMES: X type = getype(dimp, absname); X--- 582,592 ---- X X defsym = 0; X type = 0; X! more: switch(o=symbol()) { X! case KEYW: X! if (cval == CONST || cval == VOLATIL) X! goto more; X! break; X X case TIMES: X type = getype(dimp, absname); X*** ./usr/src/lib/ccom/ansi.c.old Tue Jan 7 13:19:58 2020 X--- ./usr/src/lib/ccom/ansi.c Mon Mar 9 19:05:10 2020 X*************** X*** 81,86 **** X--- 81,88 ---- X * For other declarations, fake an auto variable. X */ X if (blklev == 1 && defsym) { X+ if (defsym->hblklev < blklev) X+ defsym = pushdecl(defsym); X if (paraml==NULL) X paraml = defsym; X else X*** ./usr/src/ucb/Makefile.old Fri Oct 13 23:54:55 2000 X--- ./usr/src/ucb/Makefile Wed Mar 4 20:18:10 2020 X*************** X*** 3,9 **** X # All rights reserved. The Berkeley software License Agreement X # specifies the terms and conditions for redistribution. X # X! # @(#)Makefile 5.17.5 (2.11BSD) 2000/5/17 X # X DESTDIR= X CFLAGS= -O X--- 3,9 ---- X # All rights reserved. The Berkeley software License Agreement X # specifies the terms and conditions for redistribution. X # X! # @(#)Makefile 5.18 (2.11BSD) 2020/3/4 X # X DESTDIR= X CFLAGS= -O X*************** X*** 13,19 **** X # X SUBDIR= Mail compress dbx error ex finger fp ftp indent lock man \ X more msgs netstat pascal rdist rlogin sendbug talk tftp \ X! tn3270 tset vgrind vlp window X X # Shell scripts that need only be installed and are never removed. X # X--- 13,19 ---- X # X SUBDIR= Mail compress dbx error ex finger fp ftp indent lock man \ X more msgs netstat pascal rdist rlogin sendbug talk tftp \ X! tn3270 top tset vgrind vlp window X X # Shell scripts that need only be installed and are never removed. X # X*** ./VERSION.old Thu Mar 5 20:57:06 2020 X--- ./VERSION Tue Mar 10 07:29:50 2020 X*************** X*** 1,5 **** X! Current Patch Level: 464 X! Date: March 5, 2020 X X 2.11 BSD X ============ X--- 1,5 ---- X! Current Patch Level: 465 X! Date: March 10, 2020 X X 2.11 BSD X ============ SHAR_EOF fi if test -f 'top.shar' then echo shar: "will not over-write existing file 'top.shar'" else sed 's/^X//' << \SHAR_EOF > 'top.shar' X#! /bin/sh X# This is a shell archive, meaning: X# 1. Remove everything above the #! /bin/sh line. X# 2. Save the resulting text in a file. X# 3. Execute the file with /bin/sh (not csh) to create: X# /usr/src/ucb/top X# This archive created: Tue Mar 10 07:49:33 2020 Xexport PATH; PATH=/bin:/usr/bin:$PATH Xif test ! -d '/usr/src/ucb/top' Xthen X mkdir '/usr/src/ucb/top' Xfi Xcd '/usr/src/ucb/top' Xif test -f 'top.c' Xthen X echo shar: "will not over-write existing file 'top.c'" Xelse Xsed 's/^Z//' << \SHAR_EOF > 'top.c' XZ/* XZ * Display processes in order of CPU utilization XZ * XZ * Implemented for 2.11 BSD to evaluate mechanisems for accessing XZ * system system state from user mode. XZ * Process information access is modeled on mechanism used by ps(1) XZ * in particular, makes use of the cached static information in XZ * /var/run/psdatabase XZ * which is generated for the ps program at system boot XZ * XZ * Digby Tarvin XZ * December 2019. XZ * XZ * History XZ * ======= XZ * Ed Date What Who XZ * -- ---------- ----------------------------------------------- ---- XZ * 01 05/12/2019 Written DRST XZ * 02 07/03/2020 Removed kmem based nswap access (sysctl updated) DRST XZ * 03 09/03/2020 added BADKEY_IGNORE, delay spec now in seconds DRST XZ * XZ */ XZ/* XZ * Using RAW removes the need for signal processing, but adds a requirement XZ * to process NL -> CRNL mapping etc. Choose your preference... XZ */ XZ#define TTY_RAW 0 /* use RAW/!CBRK for terminal */ XZ#define BADKEY_IGNORE 1 /* no abort on invalid commands */ XZ XZ#include XZ#include /* usleep */ XZ#include /* getopt */ XZ#include /* NGROUPS */ XZ#include /* boottime,.. */ XZ#include /* isdigit */ XZ#include /* lseek */ XZ#include /* struct stat */ XZ#include /* MAXCOMLEN */ XZ#include /* struct proc */ XZ#include XZ#include /* select() */ XZ#include /* select() */ XZ#include /* select() */ XZ#include /* winsize, TIOCGETP */ XZ#include /* isdigit() */ XZ#include XZ#include /* PS_NAMESIZE, _PATH_UTMP */ XZ#include XZ#include "psdb.h" XZ XZ#define LOCAL static XZ#define EXPORT /**/ XZ XZ#define DIV60(t) ((t+30)/60) /* x/60 rounded */ XZtypedef struct udata_s XZ{ XZ dev_t o_ttyd; /* u_ttyd */ XZ char o_tty[3]; /* 1st 2 chars of tty after 'tty' */ XZ char *o_uname; /* login name of process owner */ XZ time_t o_utime; /* u_utime */ XZ time_t o_stime; /* u_stime */ XZ time_t o_cutime; /* u_cutime */ XZ time_t o_cstime; /* u_cstime */ XZ time_t o_ttime; /* u_utime + u_stime */ XZ time_t o_dtime; /* o_ttime - o_LastTime */ XZ int o_sigs; /* sum of SIGINT & SIGQUIT (2 => ignore both) */ XZ size_t o_tsize; /* text size */ XZ int o_increment; /* current - last */ XZ char o_comm[MAXCOMLEN+1]; /* u_comm */ XZ char *o_args; /* best guess at args to process */ XZ long o_nswap; /* swaps */ XZ long o_nvcsw; /* voluntary context switches */ XZ long o_nicsw; /* involuntary " */ XZ /* XZ * details from last update XZ */ XZ short o_LastPid; /* last pid in this slot */ XZ short o_LastStat; /* is previous process data valid? */ XZ time_t o_LastTime; /* time at last update */ XZ} udata_t; XZ XZ#define DRATE (1000000) /* default delay between updates (us) */ XZ#define MAXUSER 10 /* user names to cache */ XZ XZLOCAL struct userdb_s XZ{ XZ char uname[UT_NAMESIZE]; XZ short uid; XZ} untab[MAXUSER]; XZ XZ XZLOCAL long upd_us = DRATE; /* delay between updates */ XZLOCAL struct proc *proctab; /* buffer to contain proc array */ XZLOCAL int ptsz = 0; /* size of proc array */ XZLOCAL int *procidx; /* indirect array for proc access */ XZLOCAL struct udata_s *userdata; /* process information from u */ XZ XZLOCAL char xflg; XZLOCAL char gflg; XZLOCAL char *tptr; XZLOCAL char *memf = "/dev/mem"; XZLOCAL char *kmemf = "/dev/kmem"; XZLOCAL char *swapf = "/dev/swap"; XZ XZLOCAL int kmem; XZLOCAL int mem; XZLOCAL int swap; XZLOCAL u_int nproc; XZLOCAL int hz; XZLOCAL float fhz; XZLOCAL int done = 0; XZLOCAL struct tchars tc; /* determine t_intrc and t_quitc */ XZ XZ/* system stats */ XZLOCAL time_t now; XZLOCAL struct tm *ltp; XZLOCAL struct timeval boottime; XZLOCAL time_t uptime; XZLOCAL FILE *ut; XZLOCAL struct utmp utmp; XZLOCAL int nusers; XZLOCAL double avenrun[3]; XZ XZLOCAL struct map_s XZ{ XZ off_t b1, e1; XZ off_t f1; XZ off_t b2, e2; XZ off_t f2; XZ} datmap; XZ/* XZ * Screen Management XZ */ XZLOCAL struct winsize win; XZLOCAL int lines, columns; XZLOCAL char *CMOV; /* Cursor Movement */ XZLOCAL char *CLEARSCR; /* Clear Screen */ XZLOCAL char *US; /* Start underscore mode */ XZLOCAL char *UE; /* End underscore mode */ XZ XZLOCAL char *UP; /* Upline (cursor up) */ XZLOCAL char *BC; /* Backspace if not ^H */ XZLOCAL char *VE; /* cursor normal */ XZLOCAL char *VI; /* cursor invisible */ XZ XZLOCAL short ospeed; /* output speed */ XZLOCAL char PC_; /* Pad Character */ XZ XZ#if TTY_RAW XZLOCAL char NewLine[] = "\r\n"; XZ#else XZLOCAL char NewLine[] = "\n"; XZ#endif XZchar *tgetstr(); XZchar *tgoto(); XZ/* XZ * write character routine for tputs XZ */ XZstatic void ttout(c) XZchar c; XZ{ XZ putchar(c); XZ} XZ XZLOCAL int error(s) XZchar *s; XZ{ XZ fprintf(stderr, "error - %s%s", s, NewLine); XZ return(-1); XZ} XZ XZ XZstatic int ttcom(c) XZchar c; XZ{ XZ ttout(c); XZ} XZ XZ#if 1 XZstatic void dial(dline,dcol) XZint dline, dcol; XZ{ XZ static int odline, odcol; XZ char *sptr; XZ XZ if(odline == dline && odcol == (dcol-1)) XZ { XZ odcol++; XZ return; XZ } XZ if((odline == (dline-1)) && dcol == 0) XZ ttout('\n'); XZ else XZ { XZ sptr = tgoto(CMOV, dcol % columns, dline % lines); XZ tputs(sptr, 1, ttcom); XZ } XZ odline = dline; XZ odcol = dcol; XZ} XZ#endif XZstatic int tcinit() XZ{ XZ char bp[1024]; XZ static char capbuff[100]; XZ char *buffp = capbuff; XZ XZ if(tgetent(bp, (char *)getenv("TERM")) != 1) XZ return(error("no termcap entry")); XZ#if 0 /* dont seem to have this?? */ XZ VE = buffp; XZ if(tgetstr("ve", &buffp) == NULL) XZ return(error("no cursor normal entry")); XZ VI = buffp; XZ if(tgetstr("vi", &buffp) == NULL) XZ return(error("no cursor invisible entry")); XZ#endif XZ CLEARSCR = buffp; XZ if(tgetstr("cl", &buffp) == NULL) XZ return(error("no \"cl\" capability")); XZ CMOV = buffp; XZ if(tgetstr("cm", &buffp) == NULL) XZ return(error("no \"cl\" capability")); XZ XZ US = buffp; XZ if((tgetstr("so",&buffp)==NULL)&&(tgetstr("us",&buffp)==NULL)) XZ return(error("no hi-light (\"so\" or \"us\") capabilty")); XZ UE = buffp; XZ if((tgetstr("se",&buffp)==NULL)&&(tgetstr("ue",&buffp)==NULL)) XZ return(error("No end highlight\n")); XZ UP = tgetstr("up", &buffp); XZ BC = tgetstr("bc", &buffp); XZ#ifdef PAD XZ/* set up padding characters */ XZ if( tgetflag("pc") == 1) XZ { XZ tgetstr("pc", &buffp); XZ PC = *--buffp; XZ } XZ gtty(1, &ttybuff); XZ ospeed = ttybuff.sg_ospeed; XZ#endif /* PAD */ XZ#if 0 /* now using ioctl */ XZ if(lines == 0) XZ lines = tgetnum("li"); XZ if(columns == 0) XZ columns = tgetnum("co"); XZ#endif XZ} XZ XZ/* XZ * Configure/restore output terminal XZ */ XZLOCAL int config_tty(onoff, lp, cp) XZint onoff; XZint *lp; XZint *cp; XZ{ XZ static struct sgttyb smode; /* saved/original mode */ XZ struct sgttyb nmode; /* new mode */ XZ struct winsize win; XZ XZ if(onoff == 0) XZ { XZ dial(lines-1, 0); XZ printf("\n"); XZ ioctl(0, TIOCSETP, &smode); XZ return(0); XZ } XZ XZ if(ioctl(1, TIOCGWINSZ, &win) < 0) XZ { XZ perror("ioctl"); XZ return(-1); XZ } XZ *lp = win.ws_row; XZ *cp = win.ws_col; XZ XZ if(ioctl(0, TIOCGETC, &tc) < 0) XZ { XZ perror("TIOGETC"); XZ return(-1); XZ } XZ if(ioctl(0, TIOCGETP, &smode) < 0) XZ return(-1); XZ nmode = smode; XZ#if TTY_RAW XZ /* using raw mode eliminates the need for signal handling */ XZ nmode.sg_flags |= RAW; XZ#else XZ nmode.sg_flags |= CBREAK; XZ#endif XZ nmode.sg_flags &= ~ECHO; XZ if(ioctl(0, TIOCSETP, &nmode) < 0) XZ return(-1); XZ return(0); XZ} XZ XZ/* XZ * Read from specified location in file XZ * returns 1 on success XZ * -1 on failure XZ */ XZLOCAL int readat(fd, pos, buff, count) XZint fd; XZoff_t pos; XZchar *buff; XZunsigned short count; XZ{ XZ if(lseek(fd, pos, L_SET) == (off_t) -1) XZ return(-1); XZ return((read(fd, buff, count) == count)? 1 : -1); XZ} XZ XZ/* XZ ******* Get Information for a process given a proc array entry ******** XZ */ XZ#define within(x,y,z) (((unsigned)(x) >= (y)) && ((unsigned)(x) < (z))) XZ XZLOCAL getbyte(adr, file) XZregister char *adr; XZint file; XZ{ XZ register struct map_s *amap = &datmap; XZ char b; XZ off_t saddr; XZ XZ if(!within(adr, amap->b1, amap->e1)) XZ { XZ if(within(adr, amap->b2, amap->e2)) XZ saddr = (unsigned) adr + amap->f2 - amap->b2; XZ else XZ return(0); XZ } XZ else XZ { XZ saddr = (unsigned) adr + amap->f1 - amap->b1; XZ } XZ if(lseek(file, saddr, L_SET) == (off_t) -1 || read (file, &b, 1) < 1) XZ return(0); XZ return((unsigned) b); XZ} XZ XZLOCAL char * XZgetptr(adr, file) XZchar **adr; XZint file; XZ{ XZ char *ptr = 0; XZ register char *p, *pa; XZ register int i; XZ XZ pa = (char *)adr; XZ p = (char *)&ptr; XZ for (i = 0; i < sizeof (ptr); i++) XZ *p++ = getbyte(pa++, file); XZ return(ptr); XZ} XZ/* XZ * Get process command line XZ * Passed: XZ * fd - descriptor for process image (mem or swap as appropriate) XZ * stk - offset to process stack area (mem or swap in file) XZ * pp - proc structure for process XZ * a - pointer to process summary structure to update XZ * XZ * Returns: XZ * 1 - success XZ * 0 - failed XZ */ XZ/* amount of top of stack to examine for args */ XZ#define ARGLIST (1024/sizeof(int)) XZ XZLOCAL getargs(fd, stk, pp, a, u) XZint fd; XZoff_t stk; XZstruct proc *pp; XZregister struct udata_s *a; XZstruct user *u; XZ{ XZ register int *ip; XZ register char *cp, *cp1; XZ char c, **ap; XZ int cc, nbad, abuf[ARGLIST]; XZ off_t pos; XZ XZ if(a->o_args == NULL) XZ { XZ if((a->o_args = (char *) malloc(64)) == NULL) XZ return(1); XZ } XZ a->o_args[0] = 0; XZ stk += ctob((off_t) pp->p_ssize) - ARGLIST*sizeof(int); XZ XZ /* look for sh special */ XZ pos = stk + ARGLIST*sizeof(int) - sizeof (char **); XZ if(readat(fd, pos, (char *)&ap, sizeof(char *)) < 0) XZ return(1); XZ XZ if(ap) XZ { XZ char b[82]; XZ char *bp = b; XZ while((cp = getptr(ap++, fd)) && cp && (bp < b+sizeof (a->o_args)) ) XZ { XZ nbad = 0; XZ while( (c = getbyte(cp++, fd))&&(bp < b+sizeof (a->o_args))) XZ { XZ if(c<' ' || c > '~') XZ { XZ if(nbad++ > 3) XZ break; XZ continue; XZ } XZ *bp++ = c; XZ } XZ *bp++ = ' '; XZ } XZ *bp++ = 0; XZ (void)strcpy(a->o_args, b); XZ return(1); XZ } XZ XZ if(readat(fd, stk, (char *) abuf, sizeof (abuf)) < 0) XZ return(1); XZ XZ abuf[ARGLIST-1] = 0; XZ for(ip = &abuf[ARGLIST-2]; ip > abuf;) XZ { XZ if(*--ip == -1 || *ip == 0) XZ { XZ cp = (char *) (ip + 1); XZ if(*cp == '\0') XZ cp++; XZ nbad = 0; XZ for (cp1 = cp; cp1 < (char *) &abuf[ARGLIST]; cp1++) XZ { XZ cc = *cp1 & 0177; XZ if(cc == 0) XZ *cp1 = ' '; XZ else if(cc < ' ' || cc > 0176) XZ { XZ if(++nbad >= 5) XZ { XZ *cp1++ = ' '; XZ break; XZ } XZ *cp1 = '?'; XZ } XZ else if(cc == '=') XZ { XZ *cp1 = '\0'; XZ while(cp1 > cp && *--cp1 != ' ') XZ *cp1 = '\0'; XZ break; XZ } XZ } XZ while(*--cp1 == ' ') XZ *cp1 = 0; XZ XZ (void)strcpy(a->o_args, cp); XZgarbage: XZ cp = a->o_args; XZ if(cp[0] == '-'&&cp[1]<=' '||cp[0]=='?'||cp[0]<=' ') XZ { XZ strcat(cp, " ("); XZ strcat(cp, u->u_comm); XZ strcat(cp, ")"); XZ } XZ cp[63] = 0; /* max room in udata_s is 64 chars */ XZ if(xflg || gflg || tptr || cp[0] != '-') XZ return(1); XZ return(0); XZ } XZ } XZ goto garbage; XZ} XZ XZLOCAL char * XZgettty(ttyp, ttyd) XZstruct tty *ttyp; XZdev_t ttyd; XZ{ XZ register int tty_step; XZ register char *p = "?"; XZ XZ if(ttyp == NULL) XZ return(p); XZ XZ for(tty_step = 0;tty_step < nttys; ++tty_step) XZ if(ttlist[tty_step].ttyd == ttyd) XZ { XZ p = ttlist[tty_step].name; XZ if(!strncmp(p,"tty",3)) XZ p += 3; XZ } XZ XZ return(p); XZ} XZ/* XZ * Save process information to udata_s structure XZ */ XZ XZLOCAL int fuser(idx, uid) XZint idx; XZshort uid; XZ{ XZ register struct passwd *pw; XZ XZ if((pw = getpwuid(uid)) == NULL) XZ return(-1); XZ untab[idx].uid = uid; XZ strcpy(untab[idx].uname, pw->pw_name); XZ return(1); XZ} XZ XZ#define round(x,y) ((long) ((((long) (x) + (long) (y) - 1L) / (long) (y)) * (long) (y))) XZ XZLOCAL getu(pp, a, noargs) XZstruct proc *pp; XZstruct udata_s *a; XZchar noargs; XZ{ XZ char *tp; XZ off_t addr; XZ off_t daddr; XZ off_t saddr; XZ struct user user; /* for reading user structs */ XZ register struct user *up = &user; XZ register struct proc *procp = pp; XZ long txtsiz, datsiz, stksiz; XZ int septxt; XZ int pifile; XZ int i; XZ XZ if(procp->p_flag & SLOAD) /* in memory */ XZ { XZ addr = ctob((off_t) procp->p_addr); XZ daddr = ctob((off_t) procp->p_daddr); XZ saddr = ctob((off_t) procp->p_saddr); XZ pifile = mem; XZ } XZ else /* swapped */ XZ { XZ addr = (off_t)procp->p_addr << 9; XZ daddr = (off_t)procp->p_daddr << 9; XZ saddr = (off_t)procp->p_saddr << 9; XZ pifile = swap; XZ } XZ XZ if(readat(pifile, addr, (char *) up, sizeof(user)) < 0) XZ { XZ perror("read"); XZ return(0); XZ } XZ XZ txtsiz = ctob(up->u_tsize); /* address maps for usr pcs */ XZ datsiz = ctob(up->u_dsize); XZ stksiz = ctob(up->u_ssize); XZ septxt = up->u_sep; XZ datmap.b1 = (septxt ? 0 : round(txtsiz, TXTRNDSIZ)); XZ datmap.e1 = datmap.b1 + datsiz; XZ datmap.f1 = daddr; XZ datmap.f2 = saddr; XZ datmap.b2 = stackbas(stksiz); XZ datmap.e2 = stacktop(stksiz); XZ tp = gettty(up->u_ttyp, up->u_ttyd); XZ strncpy(a->o_tty, tp, sizeof (a->o_tty)); XZ a->o_ttyd = tp[0] == '?' ? -1 : up->u_ttyd; XZ if(procp->p_stat == SZOMB) XZ return(1); XZ XZ a->o_tsize = up->u_tsize; XZ a->o_utime = up->u_ru.ru_utime; XZ a->o_stime = up->u_ru.ru_stime; XZ a->o_nswap = up->u_ru.ru_nswap; XZ a->o_nvcsw = up->u_ru.ru_nvcsw; XZ a->o_nicsw = up->u_ru.ru_nivcsw; XZ a->o_cutime = up->u_cru.ru_utime; XZ a->o_cstime = up->u_cru.ru_stime; XZ a->o_ttime = a->o_utime + a->o_stime + a->o_cutime + a->o_cstime; XZ a->o_sigs = (int)up->u_signal[SIGINT]+(int)up->u_signal[SIGQUIT]; XZ if(a->o_LastStat && (pp->p_pid == a->o_LastPid)) XZ a->o_dtime = a->o_ttime - a->o_LastTime; XZ else XZ a->o_dtime = a->o_ttime; XZ XZ a->o_uname = NULL; XZ for(i = 0; i < MAXUSER; i++) XZ { XZ if(untab[i].uname[0] == 0) XZ break; XZ if(untab[i].uid == procp->p_uid) XZ { XZ a->o_uname = untab[i].uname; XZ break; XZ } XZ } XZ if((a->o_uname == NULL) && (i< MAXUSER)) XZ { XZ /* name not found and space in table */ XZ if(fuser(i, procp->p_uid) >= 0) XZ a->o_uname = untab[i].uname; XZ } XZ XZ strncpy(a->o_comm, up->u_comm, MAXCOMLEN); XZ XZ if(noargs) XZ return(1); XZ return(getargs(pifile, saddr, pp, a, up)); XZ} XZ/* XZ * Compare function for process sorting XZ */ XZLOCAL int sortcmp(i1, i2) XZregister int *i1, *i2; XZ{ XZ time_t usage1, usage2; XZ XZ usage1 = userdata[*i1].o_dtime; XZ usage2 = userdata[*i2].o_dtime; XZ if(usage1 != usage2) XZ return((usage2>usage1)? 1:-1); XZ usage1 = userdata[*i1].o_ttime; XZ usage2 = userdata[*i2].o_ttime; XZ if(usage1 != usage2) XZ return((usage2>usage1)? 1:-1); XZ return(0); XZ} XZ/* XZ * Update the process list XZ */ XZLOCAL int update() XZ{ XZ int np; XZ int i; XZ XZ /* XZ * before over-writing old proc structure, XZ * record old stat and if applicable, pid and ttime XZ */ XZ for(i = 0; i < nproc; i++) XZ { XZ struct proc *procp = &proctab[i]; XZ register struct udata_s *up = &userdata[i]; XZ XZ if((up->o_LastStat = procp->p_stat) != 0) XZ { XZ up->o_LastTime = up->o_ttime; XZ up->o_LastPid = procp->p_pid; XZ } XZ } XZ XZ /* read the current proc table into buffer */ XZ if(readat(kmem, (off_t) proc_sym, proctab, ptsz) < 0) XZ { XZ fprintf(stderr, "Error reading process table\n"); XZ return(1); XZ } XZ XZ for(np = i = 0; i < nproc; i++) XZ { XZ struct proc *procp = &proctab[i]; XZ XZ if(procp->p_stat == 0) XZ continue; XZ XZ if(getu(procp, &userdata[i], 1) == 0) XZ { XZ fprintf(stderr, "Error getting process %d uinf\n", XZ procp->p_pid); XZ continue; XZ } XZ procidx[np] = i; XZ np++; XZ } XZ return(np); XZ} XZ XZLOCAL char states[] = { '?', 'S', 'W', 'R', 'I', 'Z', 'T' }; XZ XZLOCAL void printw(w, s) XZint w; XZchar *s; XZ{ XZ while(w-- > 0) XZ { XZ char c = ' '; XZ if(*s) XZ c = *s++; XZ putchar(c); XZ } XZ} XZ/* XZ * Get Memory Statistics for summary lines XZ * Returns: XZ * totmem - total physical memory in bytes XZ * freemem - available memory in bytes XZ */ XZLOCAL int GetMemStats(totmem, freemem) XZlong *totmem; XZlong *freemem; XZ{ XZ int mib[2]; XZ size_t size; XZ static size_t cmsz = 0; XZ static long physmem = 0; XZ static char *coremap = NULL; XZ struct mapent *map; XZ int i; XZ long tfree; XZ XZ if(physmem == 0) XZ { XZ /* first call - get static values */ XZ mib[0] = CTL_HW; XZ mib[1] = HW_PHYSMEM; XZ size = sizeof(physmem); XZ if(sysctl(mib, 2, &physmem, &size, NULL, 0) == -1) XZ { XZ perror("PHYSMEM"); XZ printf("\n"); XZ return(-1); XZ } XZ mib[0] = CTL_VM; XZ mib[1] = VM_COREMAP; XZ if(sysctl(mib, 2, NULL, &cmsz, NULL, 0) == -1) XZ { XZ perror("COREMAP"); XZ printf("\n"); XZ return(-1); XZ } XZ if((coremap = (char *)malloc((unsigned)cmsz)) == NULL) XZ { XZ perror("COREMAP"); XZ printf("\n"); XZ exit(1); XZ } XZ memset(coremap, 0, cmsz); XZ } XZ mib[0] = CTL_VM; XZ mib[1] = VM_COREMAP; XZ size = cmsz; XZ if(sysctl(mib, 2, coremap, &size, NULL, 0) == -1) XZ { XZ perror("COREMAP2"); XZ printf("\n"); XZ return(-1); XZ } XZ XZ map = (struct mapent *)coremap; XZ for(tfree = i = 0; i < cmsz / sizeof(struct mapent); i++) XZ tfree += map[i].m_size; XZ *totmem = physmem; XZ *freemem = (long) tfree*64; XZ return(0); XZ} XZ XZ/* XZ * Get Swap Statistics for summary lines XZ * Returns: XZ * totmem - total physical memory in bytes XZ * freemem - available memory in bytes XZ */ XZ XZLOCAL int GetSwapStats(totswap, freeswap) XZlong *totswap; XZlong *freeswap; XZ{ XZ int mib[2]; XZ size_t size; XZ static size_t smsz = 0; XZ static long nswap = 0; XZ static char *swapmap = NULL; XZ struct mapent *map; XZ int i; XZ long tfree; XZ XZ if(nswap == 0) XZ { XZ /* first call - get static values */ XZ mib[0] = CTL_VM; XZ mib[1] = VM_NSWAP; XZ size = sizeof(i); XZ if(sysctl(mib, 2, &i, &size, NULL, 0) == -1) XZ { XZ perror("NSWAP"); XZ printf("\n"); XZ return(-1); XZ } XZ nswap = i; XZ mib[0] = CTL_VM; XZ mib[1] = VM_SWAPMAP; XZ if(sysctl(mib, 2, NULL, &smsz, NULL, 0) == -1) XZ { XZ perror("SWAPMAP"); XZ printf("\n"); XZ return(-1); XZ } XZ if((swapmap = (char *)malloc((unsigned)smsz)) == NULL) XZ { XZ perror("SWAPMAP"); XZ printf("\n"); XZ exit(1); XZ } XZ memset(swapmap, 0, smsz); XZ } XZ mib[0] = CTL_VM; XZ mib[1] = VM_SWAPMAP; XZ size = smsz; XZ if(sysctl(mib, 2, swapmap, &size, NULL, 0) == -1) XZ { XZ perror("SWAPMAP2"); XZ printf("\n"); XZ return(-1); XZ } XZ XZ map = (struct mapent *)swapmap; XZ for(tfree = i = 0; i < smsz / sizeof(struct mapent); i++) XZ tfree += map[i].m_size; XZ *totswap = nswap*512; XZ *freeswap = (long) tfree*512; XZ return(0); XZ} XZ XZ/* XZ * Show summary stats XZ */ XZLOCAL void XZshow_stats(npr) XZint npr; XZ{ XZ int i, run, sleep, stop, zombie; XZ static int calls = 0; XZ int mib[2]; XZ size_t size; XZ long memsize, memfree; XZ long swapsize, swapfree; XZ XZ /* get time */ XZ time(&now); XZ ltp = localtime(&now); XZ printf("top - %02d:%02d:%02d", ltp->tm_hour, ltp->tm_min, ltp->tm_sec); XZ XZ /* get uptime */ XZ XZ mib[0] = CTL_KERN; XZ mib[1] = KERN_BOOTTIME; XZ size = sizeof(boottime); XZ if(sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && XZ boottime.tv_sec != 0) XZ { XZ int days, hrs, mins; XZ XZ uptime = now - boottime.tv_sec; XZ days = uptime / (60L*60L*24L); XZ uptime %= (60L*60L*24L); XZ hrs = uptime / (60L*60L); XZ uptime %= (60L*60L); XZ mins = DIV60(uptime); XZ XZ printf(" up %2d day%s", days, days != 1?"s":""); XZ printf(", %2d:%02d", hrs, mins); XZ } XZ XZ /* get user count */ XZ XZ nusers = 0; XZ while(fread(&utmp, sizeof(utmp), 1, ut)) XZ if(utmp.ut_name[0] != '\0') XZ nusers++; XZ rewind(ut); XZ printf(", %3d user%c", nusers, nusers > 1? 's': '\0'); XZ XZ /* load average */ XZ if(getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])) == -1) XZ printf(", no load average information available"); XZ else XZ { XZ int i; XZ printf(", load average:"); XZ for(i = 0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) XZ { XZ if(i > 0) XZ printf(","); XZ printf(" %.2f", avenrun[i]); XZ } XZ } XZ printf(NewLine); XZ /* process status summary */ XZ run = sleep = stop = zombie = 0; XZ for(i = 0; i < npr; i++) XZ { XZ register struct proc *p = &proctab[procidx[i]]; XZ switch(p->p_stat) XZ { XZ case SSLEEP: sleep++; break; XZ case SWAIT: sleep++; break; XZ case SRUN: run++; break; XZ case SIDL: run++; break; XZ case SZOMB: zombie++; break; XZ case SSTOP: stop++; break; XZ/* case 0: run++; break; /* ?? */ XZ default: XZ zombie++; /* shouldn't happen */ XZ } XZ } XZ printf("Tasks:%4d total, %3d running,", npr, run); XZ printf(" %4d sleeping, %3d stopped, %3d zombie", XZ sleep, stop, zombie); XZ printf(NewLine); XZ XZ /* Memory and Swap status */ XZ XZ if(GetMemStats(&memsize, &memfree) < 0) XZ return; XZ if(GetSwapStats(&swapsize, &swapfree) < 0) XZ return; XZ /* 2.11 BSD has static buffer cache so no need to display this */ XZ printf(" Mem : %8ld total, %8ld free, %8ld used (%2ld%%)%s", XZ memsize, memfree, memsize-memfree, XZ (memsize-memfree)*100L/memsize, NewLine); XZ printf(" Swap: %8ld total, %8ld free, %8ld used (%2ld%%)%s", XZ swapsize, swapfree, swapsize-swapfree, XZ (swapsize-swapfree)*100L/swapsize, NewLine); XZ} XZ/* XZ * show heading information XZ */ XZLOCAL void XZshow_titles() XZ{ XZ tputs(US, 1, ttcom); XZ printw(columns, " PID USER PR NI TEXT DATA STACK S TIME DTIME COMMAND"); XZ tputs(UE, 1, ttcom); XZ} XZ XZLOCAL void XZshow_procs(np, max) XZint np; XZint max; XZ{ XZ int i; XZ XZ#if 0 XZ printf(" nproc=%d witharg=%d hz = %d\n", nproc, np, hz); XZ#endif XZ qsort((char *)procidx, np, sizeof(int), sortcmp); XZ for(i = 0; i < np; i++) XZ { XZ register struct proc *p = &proctab[procidx[i]]; XZ register struct udata_s *a = &userdata[procidx[i]]; XZ XZ printf("%5d ", p->p_pid); XZ if(a->o_uname != NULL) XZ printf("%-7s", a->o_uname); XZ else XZ printf("%7d", p->p_uid); XZ printf("%5d", p->p_pri); XZ printf("%4d", p->p_nice); XZ printf("%6d", a->o_tsize); XZ printf("%6d", p->p_dsize); XZ printf("%6d", p->p_ssize); XZ printf(" %c", (p->p_stat>6)? '?' : states[p->p_stat]); XZ printf("%c", (p->p_flag & SLOAD)? ' ':'s'); XZ XZ#if 1 XZ printf("%8.2f ", a->o_ttime/fhz); XZ printf("%7.2f ", a->o_dtime/fhz); XZ#else XZ printf("%8ld ", a->o_ttime); XZ printf("%7ld ", a->o_dtime); XZ#endif XZ#if 0 XZ printf(" %2d %2d %2d ", a->o_nswap, a->o_nvcsw, a->o_nicsw); XZ printf(" %4d %1d ", a->o_LastPid, a->o_LastStat); XZ#endif XZ if((a->o_comm[0] == 0)&&(p->p_pid == 0)) XZ printf("%-19s", "swapper"); XZ else XZ printf("%-19s", a->o_comm); XZ#if 1 XZ if(i >= (max-1)) XZ break; XZ#endif XZ printf("%s", NewLine); XZ } XZ} XZ/* XZ * Wait for a key press on stdin, signal or until tout microseconds XZ * have elapsed XZ * returns the key value, -1 on error, or zero if timeout occured XZ */ XZLOCAL int keypress(usec) XZlong usec; XZ{ XZ struct timeval tv; XZ fd_set rfds; XZ XZ if(done) XZ return('q'); /* signal */ XZ XZ tv.tv_sec = usec / 1000000; XZ tv.tv_usec = usec % 1000000; XZ FD_ZERO(&rfds); XZ FD_SET(0, &rfds); XZ XZ if(select(1, &rfds, NULL, NULL, &tv) > 0) XZ { XZ char c; XZ if(read(0, &c, 1) != 1) XZ return(-1); XZ if((c == tc.t_intrc)||(c == tc.t_quitc)) XZ c = 'q'; XZ return(c); XZ } XZ return(0); XZ} XZ/* XZ * Convert and return a ms value formatted s[.d[d[d]]] XZ * returns delay on success XZ * -1 on invalid delay spec XZ */ XZLOCAL long GetDelay(ds) XZchar *ds; XZ{ XZ char *p; XZ char *dp = NULL; XZ long delay = 0; XZ XZ /*check valid syntax delay spec */ XZ for(p = ds; *p; p++) XZ { XZ if(*p == '.') XZ { XZ if(dp != NULL) XZ return(-1); XZ dp = p; XZ continue; XZ } XZ if(!isdigit(*p)) XZ return(-1); XZ } XZ /* do conversion */ XZ if(dp != NULL) /* subseconds specified */ XZ { XZ int dd; /* decimal digits */ XZ XZ *dp++ = 0; XZ dd = p - dp; XZ XZ if((dd > 3)||(dd < 1)) XZ return(-1); XZ delay = atoi(dp); XZ if(dd == 1) XZ delay *= 100; XZ else if(dd == 2) XZ delay *= 10; XZ delay *= 1000; XZ } XZ delay += atol(ds)*1000000; XZ return(delay); XZ} XZ XZLOCAL char *ReadLine() XZ{ XZ char c; XZ static char lbuff[50]; XZ char *lp = lbuff; XZ XZ while(read(0, &c, 1) == 1) XZ { XZ if(c == '\n') XZ { XZ *lp = 0; XZ return(lbuff); XZ } XZ if(c == 0x7f) XZ { XZ if(lp == &lbuff[0]) XZ continue; XZ --lp; XZ write(1, "\b \b", 3); XZ continue; XZ } XZ#if 1 XZ write(1, &c, 1); XZ#else XZ printf("%02x", c); XZ fflush(stdout); XZ#endif XZ *lp++ = c; XZ if(lp == &lbuff[sizeof(lbuff)-2]) XZ return(NULL); XZ } XZ return(NULL); XZ} XZ XZ/* XZ ********************* Main Program ******************* XZ */ XZ XZ#define STATLINES (5) XZ XZLOCAL int XZdo_top() XZ{ XZ int nread; XZ int npr; XZ XZ /* XZ * Open files required for obtaining system information: XZ * /dev/kmem - kernel symbols and proc array XZ * /dev/mem - incore process user struct and stack XZ * /dev/swap - swapped process user struct and stack XZ */ XZ if((kmem = open(kmemf, 0)) < 0) XZ { XZ perror(kmemf); XZ return(1); XZ } XZ if((mem = open(memf, 0)) < 0) XZ { XZ perror(memf); XZ return(1); XZ } XZ if((swap = open(swapf, 0)) < 0) XZ { XZ perror(swapf); XZ return(1); XZ } XZ XZ if(getksyms("/unix") < 0) XZ { XZ fprintf(stderr, "Can't read kernel symbols - aborting\n"); XZ return(1); XZ } XZ XZ /* find number of procs */ XZ XZ if(nproc_sym == 0) XZ { XZ fputs("nproc not in namelist\n",stderr); XZ return(-1); XZ } XZ XZ if(readat(kmem, (off_t) nproc_sym, (char *)&nproc,sizeof(nproc)) <0) XZ { XZ perror(kmemf); XZ return(-1); XZ } XZ /* find value of hz */ XZ if(readat(kmem, (off_t) hz_sym, (char *)&hz,sizeof(hz)) < 0) XZ { XZ perror(kmemf); XZ return(-1); XZ } XZ fhz = hz * 1.0; XZ memset(untab, 0, sizeof(untab)); XZ /* XZ * allocate an array to hold processess information XZ */ XZ ptsz = nproc * sizeof(struct proc); XZ XZ if((proctab = (struct proc *)malloc(ptsz))==NULL) XZ { XZ fputs("top: not enough memory for proc table\n",stderr); XZ exit(1); XZ } XZ /* XZ * allocate an array to user struct information XZ */ XZ if((userdata=(struct udata_s *)calloc(nproc, sizeof(struct udata_s)))==NULL) XZ { XZ fprintf(stdout, "top: can't allocate %d bytes for saving info\n", nproc*sizeof(struct udata_s)); XZ exit(1); XZ } XZ /* XZ * allocate an indirection table for efficient sorting XZ */ XZ if( (procidx = (int *) malloc(nproc*sizeof(short))) == NULL) XZ { XZ fputs("top: cant allocate index table\n", stderr); XZ return(1); XZ } XZ if((npr = update()) < 0) XZ return(1); XZ tputs(CLEARSCR, 1, ttcom); XZ dial(STATLINES, 0); XZ show_titles(); XZ if((ut = fopen(_PATH_UTMP, "r")) == NULL) XZ { XZ perror(_PATH_UTMP); XZ return(1); XZ } XZ XZ while(1) XZ { XZ char c = keypress(upd_us); XZ XZ if(c != 0) XZ { XZ if(c == 'q') XZ return(0); XZ if(c == 's') XZ { XZ char *s; XZ XZ dial(STATLINES-1,0); XZ fprintf(stdout, "Change delay from %4.3f to ", XZ (upd_us *1.0)/1000000); XZ fflush(stdout); XZ s = ReadLine(); XZ dial(STATLINES-1,0); XZ fprintf(stdout, "%40s", ""); XZ fflush(stdout); XZ if(s != NULL) XZ { XZ long newdelay; XZ XZ if((newdelay = GetDelay(s)) > 0) XZ { XZ upd_us = newdelay; XZ dial(lines-1, 0); XZ fflush(stdout); XZ continue; XZ } XZ if(*s == 0) XZ continue; XZ } XZ dial(STATLINES-1,0); XZ fprintf(stdout, "Unacceptable delay: %s", s); XZ fflush(stdout); XZ sleep(1); XZ dial(STATLINES-1,0); XZ fprintf(stdout, "%40s", ""); XZ dial(lines-1, 0); XZ fflush(stdout); XZ continue; XZ } XZ#if !BADKEY_IGNORE XZ XZ dial(lines-1,0); XZ fprintf(stdout, "\nUnexpected command: '%c'", c); XZ return(0); XZ/* otherwise invalid key commands just force an update */ XZ#endif XZ } XZ if((npr = update()) < 0) XZ return(1); XZ dial(0,0); XZ show_stats(npr); XZ dial(STATLINES+1,0); XZ show_procs(npr, lines-(STATLINES+1)); XZ fflush(stdout); XZ } XZ} XZ XZ#if !TTY_RAW XZLOCAL int sighand(sig, code, scp) XZint sig, code; XZstruct sigcontext *scp; XZ{ XZ done = 1; XZ} XZ#endif /* TTY_RAW */ XZ XZLOCAL void usage(p) XZchar *p; XZ{ XZ fprintf(stderr, "Usage: %s [opts]\n", p); XZ fprintf(stderr, "Where options are\n"); XZ fprintf(stderr, "\t-h show this summary\n"); XZ fprintf(stderr, "\t-s delay in seconds between updates\n"); XZ} XZ XZEXPORT int main(int argc, char *argv[]) XZ{ XZ int status = 0; XZ char ch; XZ XZ while((ch = getopt(argc, argv, "hs:")) != EOF) XZ { XZ switch(ch) XZ { XZ case 's': XZ if((upd_us = GetDelay(optarg)) <= 0) XZ { XZ fprintf(stderr, "Invalid delay\n"); XZ exit(1); XZ } XZ break; XZ default: XZ case 'h': XZ usage(argv[0]); XZ exit(1); XZ } XZ argc -= optind; XZ argv += optind; XZ } XZ XZ if(tcinit() < 0) XZ return(1); XZ#if !TTY_RAW XZ if( XZ (signal(SIGHUP, sighand) == -1) XZ || XZ (signal(SIGINT, sighand) == -1) XZ ) XZ { XZ perror("signal"); XZ exit(1); XZ } XZ#endif /* TTY_RAW */ XZ if(config_tty(1, &lines, &columns) < 0) XZ return(1); XZ XZ if(do_top() != 0) XZ status = 1; XZ XZ config_tty(0, NULL, NULL); XZ if(done) XZ fprintf(stdout, "*interrupt*\n"); XZ return(status); XZ} XSHAR_EOF Xfi Xif test -f 'Makefile' Xthen X echo shar: "will not over-write existing file 'Makefile'" Xelse Xsed 's/^Z//' << \SHAR_EOF > 'Makefile' XZ# XZ# @(#)Makefile 1.0 (2.11BSD) 2020/3/4 XZ# XZ XZCFLAGS= -O XZSEPFLAG= -i XZMAN= top.0 XZMANSRC= top.1 XZ XZall: top ${MAN} XZ XZtop: top.o psdb.o XZ cc -i -o top top.o psdb.o -ltermcap XZ XZtop.o: top.c psdb.h XZ cc ${CFLAGS} -c top.c XZ XZpsdb.o: psdb.c psdb.h XZ cc ${CFLAGS} -c psdb.c XZ XZtop.0: top.1 XZ /usr/man/manroff ${MANSRC} > ${MAN} XZ XZinstall: XZ install -s -o root -g kmem -m 2755 top ${DESTDIR}/usr/ucb XZ install -c -o bin -g bin -m 444 ${MAN} ${DESTDIR}/usr/man/cat1 XZ XZclean: XZ rm -f top.o psdb.o top ${MAN} XSHAR_EOF Xfi Xif test -f 'psdb.h' Xthen X echo shar: "will not over-write existing file 'psdb.h'" Xelse Xsed 's/^Z//' << \SHAR_EOF > 'psdb.h' XZ/* XZ * Structure for the wchan table XZ */ XZtypedef struct wc_s XZ{ XZ char cname[8]; XZ unsigned caddr; XZ} wc_t; XZ/* XZ * structure for the terminal table XZ * store 14 chars of name as MAXNAMLEN uses too much memory XZ * and device names tend to be short XZ */ XZtypedef struct ttab_s XZ{ XZ char name[14]; XZ dev_t ttyd; XZ} ttab_t; XZ XZextern u_int proc_sym; XZextern u_int nproc_sym; XZextern u_int hz_sym; XZ XZextern int hz; XZextern u_int nproc; XZ XZextern int nttys; XZextern int nchans; XZextern wc_t *wclist; XZextern ttab_t *ttlist; XZ XZint getksyms(); XSHAR_EOF Xfi Xif test -f 'top.1' Xthen X echo shar: "will not over-write existing file 'top.1'" Xelse Xsed 's/^Z//' << \SHAR_EOF > 'top.1' XZ.\" Copyright (c) 1980 Regents of the University of California. XZ.\" All rights reserved. The Berkeley software License Agreement XZ.\" specifies the terms and conditions for redistribution. XZ.\" XZ.\" @(#)top.1 6.2 (Berkeley) 6/8/85 XZ.\" XZ.TH TOP 1 "March 4, 2020" XZ.UC 4 XZ.SH NAME XZtop \- display system activity XZ.SH SYNOPSIS XZ.B top XZ[ XZ.B \-h XZ] [ XZ.B \-s delay XZ] XZ.SH DESCRIPTION XZThe XZ.B top XZprogram provides a dynamic real-time view of a running system. XZIt displays system summary information as well as a list of the XZmost active processes currently being managed by the system. XZIt is a trimmed down and less flexible version of the the program of XZthe same name commonly found on more recent Unix and Unix like XZoperating systems. The information provided closely resembles the XZdefault display of the program on larger, more recent systems. XZ.PP XZIf the XZ.B \-s XZcommand line option is specified, its argument is the update delay XZin seconds followed by an optional decimal point and up to 3 digits, allowing XZmillisecond accurate delay specifications. XZThe default delay is one second. The XZ.B \-h XZcommand line option produces a usage summary. XZ.PP XZ.I Summary Display XZ.PP XZThe first line of the summary includes the name of the program, the XZtime of day, the system up time, the number of currently logged in XZusers, and the system load average as returned by the getloadavg(3), XZwhich is the average number of processes in the system run queue XZcalculated over the last 1, 5 and 15 minutes. The system up time is XZobtained by subtracting the boot time returned by sysctl(3) from XZthe current time. XZ.PP XZThe second summary line displays the current total number of processes, XZplus the breakdown of this number into running, sleeping, stopped and XZzombie processes. The classification is based on p_stat value in each XZprocesses proctab entry as follows: XZ.TP XZ.B running XZSRUN, SIDL or 0 XZ.TP XZ.B sleeping XZSSLEEP or SWAIT XZ.TP XZ.B stop XZSSTOP XZ.TP XZ.B zombie XZSZOMB or any undefined state XZ.PP XZThe third line provides a memory usage summary. This displays the total XZphysical memory, the amount of free memory, and the amount of memory used XZin bytes. It also shows the amount of memory used as a percentage of total XZmemory. Memory is allocated in 64 byte units, so displaying memory amounts XZin KiB as in other versions of top would involve fractions and is XZunnecessary in a small system. There is also no need to distinguish free XZmemory from available memory, as there is no dynamic sizing of the buffer XZcache. XZ.PP XZThe last status line provides information about swap usage. It displays XZtotal, free and available space in bytes, as well as percentage used. XZ.PP XZ.I Process Summary XZ.PP XZThe process summary includes a title line followed by information about XZthe most recently active processes, one per line, for as many lines that XZare left on the display (as reported by the TIOCSETP ioctl). XZ.PP XZThe processes are displayed most active first, where activity is determined XZby the change in the sum u_utime+u_stime for a process between the most recent XZread of the process table and the previous read. Within groups of processes XZhavng the same value for this metric, the ordering is determined by the XZprocesses total u_utime+u_stime. The default delay between updates is XZone second. Two process table reads occur before the first display update XZto allow the above calculation to be performed. XZ.PP XZThe details displayed for each process include XZ.TP XZ.B PID XZThe process ID XZ.TP XZ.B USER XZName of the process owner XZ.TP XZ.B PR XZProcess priority XZ.TP XZ.B NI XZnice value. XZ.TP XZ.B TEXT XZsize of process text area XZ.TP XZ.B DATA XZsizeof process initialized data XZ.TP XZ.B STACK XZprocess stack space size XZ.TP XZ.B S XZProcess state (S=sleep, W=wait, R=run, I=idle, Z=zombie, T=stop) XZ.TP XZ.B TIME XZTotal user plus system time used by the process (u_utime+u_stime) XZ.TP XZ.B DTIME XZChange in TIME value since last update XZ.TP XZ.B COMMAND XZThe process name XZ.PP XZ.I User Commands XZ.PP XZThe display updates indefinately until a command in the form of a XZkey press is received, or a signal is received. XZKeys are not echoed and are acted on immediately without the XZneed for a carriage return. The only command currently implemented is XZthe XZ.B q XZcommand, which terminates the program. Any unrecognized command will XZresult in termination with a warning message. XZ.P XZ.SH EXAMPLE XZAnd example of typical output is XZ.nf XZtop - 17:33:34 up 1 day, 1:17, 3 users, load average: 0.37, 0.23, 0.01 XZTasks: 27 total, 1 running, 26 sleeping, 0 stopped, 0 zombie XZ Mem : 3932160 total, 1939200 free, 1992960 used (50%) XZ Swap: 16719 total, 14706 free, 2013 used (12%) XZ XZ PID USER PR NI TEXT DATA STACK S TIME DTIME COMMAND XZ 644 root 50 0 411 608 90 R 4.52 0.02 top XZ 1 root 30 0 250 160 72 S 85.63 0.00 init XZ 483 digbyt 40 0 760 640 102 S 72.77 0.00 tcsh XZ 470 digbyt 28 0 760 624 102 S 59.77 0.00 tcsh XZ 59 root 26 0 576 272 72 S 23.20 0.00 cron XZ 482 root 26 0 372 192 76 S 20.70 0.00 telnetd XZ 568 digbyt 28 0 760 560 102 S 15.83 0.00 tcsh XZ 469 root 26 0 372 192 76 S 2.95 0.00 telnetd XZ 0 root 0 0 0 0 0 S 1.95 0.00 swapper XZ 71 root 26 0 408 224 22 S 0.50 0.00 inetd XZ 46 root 26 0 347 240 155 S 0.47 0.00 syslogd XZ 567 root 26 0 372 192 76 S 0.32 0.00 telnetd XZ 79 root 26 0 770 272 42 S 0.22 0.00 lpd XZ 95 root 26 0 879 432 71 S 0.22 0.00 sendmail XZ 56 root 40 0 24 3 22 S 0.15 0.00 update XZ 63 root 26 -1 243 128 43 S 0.12 0.00 acctd XZ 75 root 26 0 238 112 42 S 0.03 0.00 rwhod XZ 109 root 28 0 247 127 21 S 0.03 0.00 getty XZ.fi XZ.SH AUTHOR XZDigby Tarvin XZ.SH FILES XZ.nf XZ/var/run/psdatabase kernel symbols cache built and used by ps(1) XZ.fi XZ.SH "SEE ALSO" XZps(1) XSHAR_EOF Xfi Xif test -f 'psdb.c' Xthen X echo shar: "will not over-write existing file 'psdb.c'" Xelse Xsed 's/^Z//' << \SHAR_EOF > 'psdb.c' XZ/* XZ * Load the process status cache saved for the 'ps' program at boot XZ * XZ * The ps data cache contains: XZ * XZ * KernelName MAXPATHLEN+1 Name of cached Kernel XZ * nllen int namelist structure count XZ * nttys int ttys structure count XZ * nchans int wchan structure count XZ * nl nllen*struct proc,npoc and hz namelist entries XZ * ttlist nttys*struct terminal information XZ * wclist nchans*struct wait channel information XZ * XZ */ XZ#include /* fopen/fread.. */ XZ#include /* struct nlist */ XZ#include /* lseek */ XZ#include /* MAXPATHLEN */ XZ#include "psdb.h" XZ XZ#define LOCAL static XZ#define EXPORT /**/ XZ XZ#define MAXTTYS 160 /* 128 plus a few extra */ XZ XZ#define X_PROC 0 XZ#define X_NPROC 1 XZ#define X_HZ 2 XZ XZLOCAL char *psdbf = "/var/run/psdatabase"; XZLOCAL struct nlist nl[4]; XZ/* XZ * Returned information XZ */ XZEXPORT u_int proc_sym = 0; XZEXPORT u_int hz_sym = 0; XZEXPORT u_int nproc_sym = 0; XZ XZEXPORT int nttys = 0; XZEXPORT ttab_t *ttlist = NULL; XZ XZEXPORT int nchans = 0; XZEXPORT wc_t *wclist = NULL; XZ XZvoid *calloc(); XZ XZLOCAL char *readpsdb() XZ{ XZ static char unamebuf[MAXPATHLEN+1]; XZ char *p = unamebuf; XZ register FILE *fp; XZ int nllen; XZ XZ if((fp = fopen(psdbf, "r")) == NULL) XZ { XZ perror(psdbf); XZ return(NULL); XZ } XZ XZ while ((*p= getc(fp)) != '\0') XZ p++; XZ XZ if( XZ (fread((char *)&nllen, sizeof nllen, 1, fp) != 1) XZ || XZ (fread((char *)&nttys, sizeof nttys, 1, fp) != 1) XZ || XZ (fread((char *)&nchans, sizeof nchans, 1, fp) != 1) XZ || XZ (fread((char *)nl, sizeof(struct nlist), nllen, fp) != nllen) XZ ) XZ { XZ perror(psdbf); XZ return(NULL); XZ } XZ XZ if((ttlist = (ttab_t *) calloc((unsigned)nttys, sizeof(ttab_t))) == NULL) XZ { XZ fputs("Too many tty names\n",stderr); XZ return(NULL); XZ } XZ if(fread((char *)ttlist, sizeof(ttab_t), nttys, fp) != nttys) XZ { XZ perror(psdbf); XZ return(NULL); XZ } XZ XZ if((wclist = (wc_t *)calloc((unsigned)nchans, sizeof(wc_t))) == NULL) XZ { XZ fputs("Too many wchan symbols\n",stderr); XZ return(NULL); XZ } XZ XZ if(fread((char *) wclist, sizeof(wc_t), nchans, fp) != nchans) XZ { XZ perror(psdbf); XZ return(NULL); XZ } XZ (void) fclose(fp); XZ return(unamebuf); XZ} XZ XZEXPORT int getksyms(kname) XZchar *kname; XZ{ XZ char *uname; XZ XZ if((uname = readpsdb()) == NULL) XZ return(-1); XZ XZ if(strcmp(uname,kname) != 0) XZ { XZ free((char *)wclist); XZ nchans = 0; XZ return(-1); XZ } XZ XZ proc_sym = nl[X_PROC].n_value; XZ nproc_sym = nl[X_NPROC].n_value; XZ hz_sym = nl[X_HZ].n_value; XZ return(0); XZ} XSHAR_EOF Xfi Xcd .. Xexit 0 X# End of shell archive SHAR_EOF fi exit 0 # End of shell archive