v05i061: "w" for Xenix/386
The Beach Bum
jfh at rpp386.UUCP
Sun Nov 27 09:17:38 AEST 1988
Posting-number: Volume 5, Issue 61
Submitted-by: "The Beach Bum" <jfh at 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 at 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 at 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 at 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
More information about the Comp.sources.misc
mailing list