jfh@rpp386.UUCP (The Beach Bum) (11/27/88)
Posting-number: Volume 5, Issue 61 Submitted-by: "The Beach Bum" <jfh@rpp386.UUCP> Archive-name: xenix.w [This has been waiting for me to fold it into the main "w" code; I've finally admitted that it isn't going to happen anytime soon, so here it is. Sigh. ++bsa] i have hacked the hell out of your "w" command to produce one which works on sco xenix for a '386. i don't know what order you will receive the submissions in, but this is one of two. the other is a fuser command. oh yes, both of them need to be re-wrapped because my shar doesn't know about the perils of being mailed about. - john. (jfh@rpp386) --- beginning for w.shar --- #! /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: # README # w.1l # w.c # This archive created: Fri Jul 8 09:15:25 1988 # By: The Beach Bum (Big "D" Home for Wayward Hackers) export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'README' then echo shar: "will not over-write existing file 'README'" else cat << \SHAR_EOF > 'README' [ This is the original README which was included with this package. Note that only "w" works. "avenrun" depends on system statistics which are not present in Xenix, and "csl" depends, in part, on "avenrun". -jfh ] The following are some programs which give you some familiar BSD utilities in a System V environment. The programs are: w - Yes, "w", as big as life! Requires... avenrun - A program to be invoked in /etc/rc which computes a "load average" from information in the "sysinfo" structure of the kernel. Based on a program by Phil Budne which forges "rwhod" packets for mixed networks; #define RWHOD for the original program. csl - I have no idea what the BSD "sysline" does, but this is my idea of a status line. The name stands for "cyclic status line"; it doesn't even attempt to fit everything into one line, instead it cycles through a set of "panels". See the man page. This also wants "avenrun" to be running. Note that "w" (and ONLY "w") can be compiled for System III or Xenix 3.0; this is in fact the default, use -DSYS5 to get the full version. No Makefile; the compile commands are trivial: cc -O -o w w.c -DSYS5 # omit the -DSYS5 for System III cc -O -o avenrun avenrun.c # add -DRWHOD for rwhod forgery cc -O -o csl csl.c "w" requires read permission on /dev/kmem, /dev/mem, and /dev/swap. "avenrun" requires read permission on /dev/kmem (to read the sysinfo structure). "csl" can run as a normal user program. On tdi2 we keep /dev/*mem and /dev/swap -r--r----- root/sys and have "avenrun" and "w" setgid sys. If someone wants to tell me what "sysline" under BSD does, I'd be interested in writing a real one. But "csl" is everything in one small package, so I will probably continue to use it. Enjoy! ++Brando SHAR_EOF fi if test -f 'w.1l' then echo shar: "will not over-write existing file 'w.1l'" else cat << \SHAR_EOF > 'w.1l' .TH W 1 local .SH NAME w \- display users and processes .SH SYNOPSIS .B w .SH DESCRIPTION .B W is a program which displays an "intelligent" listing of the current users, what they're doing, and how active they are. There are two basic kinds of information displayed: system information and per-user information. An example is shown below. .nf 10:55pm up 2 wks 2 days, 4 users User tty login@ idle JCPU PCPU what rhg tty6 10:36pm 12:20 12:20 csh robertd tty7 10:21pm 9:21 9:21 csh bobw tty13 10:26pm 160:35 149:43 rn allbery tty15 9:47pm 50:22 0:18 sh .fi The first line displays the current time, how long the system has been up, and the number of users. The other lines display for each user, the user's login name, the terminal the user is on, the time the user logged in, how long the user has been idle, the CPU time used by the current program and total CPU for the login session, and the current program. .SH FILES .ta \w'/dev/kmem 'u /dev/kmem System memory (the process table) .br /dev/mem In-core program images .br /dev/swap Swapped program images .br /dev Searches for terminals .br /etc/utmp Current system users and boot time .br /xenix System namelist .DT .SH NOTES .B W displays the process name as shown by .B ps(1) without the -f argument. .SH SEE ALSO ps(1), who(1). .SH BUGS JCPU and current process are both kludges. The former is really only the CPU of running programs in the terminal session, as Xenix does not retain user and system times for all programs in a session; the latter attempts to disregard background processes, but it is nearly impossible to successfully determine if a program is in the background or not. This is exacerbated by the fact that VAR csh(1)'s, when available, look suspiciously like background processes because they close their standard input. .PP If the user block is demand paged, .B w won't find it; I don't have access to a demand-paged system. .PP .B who -u and .B w have different ideas on what constitutes idle time; one uses time of last input, the other the time of last output. .PP It is possible that reading the summarized child's system and user times would produce a better approximation of JCPU. This is only likely, however, if the times are updated recursively. .PP Things can change while .B w is running; this occasionally causes the current program to be printed as "[can't stat]" or as "[interstice]". .PP If you want "w" to work correctly, get 4.2BSD. .PP It should really take options for the system namelist, memory, and swap files. .PP Because Xenix lacks the appropriate kernel variables, load averages are not available. .SH CREDIT Based on a utility written at the University of California at Berkeley. Original written by Brandon S. Allbery. Modified for SCO Xenix 386 by John F. Haugh II (jfh@rpp386). SHAR_EOF fi if test -f 'w.c' then echo shar: "will not over-write existing file 'w.c'" else cat << \SHAR_EOF > 'w.c' /* * %W% %E% %U% ncoast!bsa %Z% * %Z% Copyright (C) 1985 by Brandon S. Allbery, All Rights Reserved %Z% * * 8-Jul-88 John F. Haugh II (jfh@rpp386) * Major hacks to force to work on SCO Xenix 386 */ #ifndef lint static char _SccsId[] = "%W% %E% %U% ncoast!bsa %Z%"; static char _CopyRt[] = "%Z% Copyright (C) 1985 by Brandon S. Allbery %Z%"; #endif lint #include <stdio.h> #include <time.h> #include <signal.h> #include <a.out.h> #include <sys/types.h> #include <sys/page.h> #include <sys/seg.h> #include <sys/param.h> #include <sys/var.h> #include <sys/proc.h> #include <sys/dir.h> #include <sys/user.h> #include <sys/stat.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sysmacros.h> #include <utmp.h> #define UTMP "/etc/utmp" #ifndef KERNEL #define KERNEL "/xenix" #endif #define KMEM "/dev/kmem" #define PMEM "/dev/mem" #define SMEM "/dev/swap" #define MIN (60) #define HOUR (MIN * 60) #define DAY (HOUR * 24) #define WEEK (DAY * 7) #define MONTH (DAY * 30) FILE *kfd; FILE *mfd; FILE *sfd; FILE *utmp; long nproc; char _SObuf[BUFSIZ]; daddr_t swplo; short mypid; struct xlist kernel[] = { {0, 0, 0, "_v"}, {0, 0, 0, "_proc"}, {0, 0, 0, "_swplo"}, {0, 0, 0, "_lbolt"}, {0, 0, 0, (char *) 0}, }; char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; struct tm *localtime(); char *vtime(); char *uptime(); char *itoa(); main() { struct utmp user; short ucnt; long now; struct var vars; setbuf(stdout, _SObuf); mypid = getpid(); time(&now); if (xlist(KERNEL, kernel) == -1) { perror(KERNEL); exit(2); } if ((utmp = fopen(UTMP, "r")) == NULL) { perror(UTMP); exit(1); } ucnt = 0; while (fread(&user, sizeof user, 1, utmp) > 0) { if (user.ut_type != USER_PROCESS) continue; ucnt++; } if (kfd == NULL) { if ((kfd = fopen(KMEM, "r")) == NULL) { perror(KMEM); exit(3); } } fseek(kfd, kernel[0].xl_value, 0); fread(&vars, sizeof vars, 1, kfd); nproc = vars.v_proc; fseek(kfd, kernel[2].xl_value, 0); fread(&swplo, sizeof swplo, 1, kfd); if (mfd == NULL) { if ((mfd = fopen(PMEM, "r")) == NULL) { perror(PMEM); exit(4); } } if (sfd == NULL) { if ((sfd = fopen(SMEM, "r")) == NULL) { perror(SMEM); exit(5); } } printf(" %s up%s, %d users\nUser tty login@ idle JCPU PCPU what\n", vtime(&now), uptime(), ucnt); rewind(utmp); while (fread(&user, sizeof user, 1, utmp) > 0) { if (user.ut_type != USER_PROCESS) continue; show(&user); } fclose(utmp); exit(0); } char *uptime() { static char timebuf[128]; struct proc swapper; struct user bootproc; long oldpos, now; short cnt, ocnt; long boottime = 0L; oldpos = fseek(kfd, 0L, 1); fseek(kfd, kernel[3].xl_value, 0); fread(&boottime, sizeof boottime, 1, kfd); now = boottime / HZ; if (now < 0L) return " with strange clock time"; timebuf[0] = '\0'; ocnt = 0; cnt = 0; while (now >= MONTH) { cnt++; now -= MONTH; } if (cnt > 0) { strcat(timebuf, itoa(cnt)); strcat(timebuf, " mon"); if (cnt > 1) strcat(timebuf, "s"); if (++ocnt == 2) return timebuf; } cnt = 0; while (now >= WEEK) { cnt++; now -= WEEK; } if (cnt > 0) { strcat(timebuf, itoa(cnt)); strcat(timebuf, " wk"); if (cnt > 1) strcat(timebuf, "s"); if (++ocnt == 2) return timebuf; } cnt = 0; while (now >= DAY) { cnt++; now -= DAY; } if (cnt > 0) { strcat(timebuf, itoa(cnt)); strcat(timebuf, " day"); if (cnt > 1) strcat(timebuf, "s"); if (++ocnt == 2) return timebuf; } cnt = 0; while (now >= HOUR) { cnt++; now -= HOUR; } if (cnt > 0) { strcat(timebuf, itoa(cnt)); strcat(timebuf, " hr"); if (cnt > 1) strcat(timebuf, "s"); } return timebuf; } char *itoa(n) int n; { static char buf[20]; sprintf(buf, " %d", n); return buf; } findu (proc, slot, user) struct proc *proc; int slot; struct user *user; { struct proc *procs = (struct proc *) kernel[1].xl_value; long swapaddr; int i; if ((proc->p_flag & (SSWAP|SSPART)) || ! (proc->p_flag & SLOAD)) { swapaddr = proc->p_addr[0].te_frameno * NBPC; if (fseek (sfd, swapaddr, 0) == -1L) fprintf (stderr, "error in lseek\n"); fread (user, sizeof *user, 1, sfd); } else { if (fseek (mfd, proc->p_addr[0].te_frameno * NBPC, 0) == -1L) fprintf (stderr, "error in lseek\n"); fread (user, sizeof *user, 1, mfd); } if (user->u_procp - procs == slot) return (1); else return (0); } show(uinfo) struct utmp *uinfo; { struct stat sbuf; struct proc proc; struct user prog; char ttydev[16]; long now, cnt, offset, jcpu; short mpid, isswap; FILE *ufd; strcpy(ttydev, "/dev/"); strncpy(&ttydev[5], uinfo->ut_line, 8); ttydev[13] = '\0'; if (stat(ttydev, &sbuf) != 0) { perror(ttydev); return; } time(&now); now -= sbuf.st_atime; printf("%-8.8s %-8.8s %7s ", uinfo->ut_name, uinfo->ut_line, vtime(&uinfo->ut_time)); if (now > DAY) printf("%4dd", now / DAY); else if (now > HOUR) printf("%2d:%02d", now / HOUR, (now % HOUR) / 60); else if (now > MIN) printf("%5d", now / MIN); else printf(" "); putchar(' '); mpid = -1; jcpu = 0; for (cnt = 0; cnt < nproc; cnt++) { fseek (kfd, kernel[1].xl_value + (cnt * sizeof proc), 0); fread(&proc, sizeof proc, 1, kfd); if (proc.p_stat == 0 || proc.p_stat == SZOMB || proc.p_stat == SWAIT) continue; if (findu (&proc, cnt, &prog) == 0) continue; if (prog.u_ttyp == NULL) continue; if (sbuf.st_rdev != prog.u_ttyd) continue; jcpu += prog.u_utime + prog.u_stime + prog.u_cutime + prog.u_cstime; if (proc.p_pid == mypid) continue; if (proc.p_pid > mpid) mpid = proc.p_pid; } if (mpid == -1) printf("[can't stat]"); else { fseek(kfd, kernel[1].xl_value, 0); for (cnt = 0; cnt < nproc; cnt++) { fread(&proc, sizeof proc, 1, kfd); if (proc.p_pid == mpid) break; } if (proc.p_pid != mpid) printf("[interstice]"); else { if (findu (&proc, cnt, &prog) == 0) fprintf (stderr, "can't find parent\n"); printf("%3d:%02d %3d:%02d ", (jcpu / HZ) / MIN, (jcpu / HZ) % MIN, ((prog.u_utime + prog.u_stime) / HZ) / MIN, ((prog.u_utime + prog.u_stime) / HZ) % MIN); prog.u_procp = &proc; pcmd(&prog); } } putchar('\n'); } char *vtime(when) long *when; { struct tm then, now; static char buf[20]; short hour, min, ampm; long clock; time(&clock); now = *localtime(&clock); then = *localtime(when); if (then.tm_mon != now.tm_mon || then.tm_mday != now.tm_mday) { sprintf(buf, "%s %2d", months[then.tm_mon], then.tm_mday); return buf; } min = then.tm_min; if (then.tm_hour == 0) { ampm = 'a'; hour = 12; } else if (then.tm_hour > 0 && then.tm_hour < 12) { ampm = 'a'; hour = then.tm_hour; } else if (then.tm_hour == 12) { ampm = 'p'; hour = 12; } else { ampm = 'p'; hour = then.tm_hour - 12; } sprintf(buf, "%d:%02d%cm", hour, min, ampm); return buf; } pcmd(uinfo) struct user *uinfo; { /* someday look up the user's command line */ printf("%-.14s", uinfo->u_comm); } SHAR_EOF fi exit 0 # End of shell archive