home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga GigaPD 3
/
Amiga_GigaPD_v3_3of3.iso
/
netbsd
/
incoming
/
near-ps.c.z
/
near-ps.c
Wrap
C/C++ Source or Header
|
1994-01-23
|
9KB
|
362 lines
/*
It's:
A ps for NetBSD with /proc. It's a quick nasty job, and probably
doesn't do what you want, but it does list processes. Not to be
confused in any way with the traditional BSD ps. Just compile
with cc, no flags particularly required.
Without args, lists all processes.
ps -p pid ... lists only specified processes.
ps -u user ... lists only processes belonging to user
(name or uid).
ps -t tty ... lists only processes on tty, as shown (e.g. "p4").
There's only one format. "FILE" is the size of the /proc "file"
file, which I guess is "the binary". "MEM" is the size of the
/proc "mem" file - total process memory? Both in 512-blocks.
"COMM" is just the file name, not the command w/ args.
Defects:
times: disregard microseconds.
start: ctime[1..2] if > 12 hrs old, ctime[3] otherwise,
which probably isn't the way it's done (displaytime).
tty: surely bogus assumptions about major/minor (parsestatus).
Desireable format options might include a roll-your-own feature
as in AIX ps, where you specify the items and the format of the
output. Or BSD-style flags, wretched as they may be, this is after
all BSD! Sorting.
Some clever person may be able to figure out how to obtain the
command argument list.
enjoy,
Donn Cave, donn@cac.washington.edu
*/
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <dirent.h>
#include <sys/stat.h>
/*
Attributes per process. Started out mostly integer, but it
turned out they're mostly just converted back to text. Several
have been commented out, because the sole format doesn't need
them.
*/
struct Process {
/* From "status" file. */
/*uid_t uid;*/ char uid[8];
/*pid_t pid;*/ char pid[8];
/*pid_t ppid;*/ char ppid[8];
/*
gid_t gid;
pid_t pgid;
pid_t sid;
*/
unsigned short major, minor;
char tty[4];
time_t start;
time_t utime;
time_t stime;
char wmesg[16];
char comm[16];
/* From "file" file. */
int filesize;
/* From "mem" file. */
int memsize;
};
/* Pick out a word. Copy to ``buf'', return chars advanced. */
static int parseword (const char *w, char *buf, int size) {
register int i;
register const char *start, *cp;
cp = w;
for (; *cp == ' ' || *cp == ','; ++cp);
for (start = cp; *cp != ' ' && *cp != ',' && *cp != '\n'; ++cp);
i = cp - start;
if (i >= size) i = size - 1;
bcopy (start, buf, i);
buf[i] = 0;
return cp - w;
}
/* Pick out an int. Copy to ``i'', return chars advanced. */
static int parseint (const char *cp, int *i) {
char buf[32];
int cs;
register int val = 0;
cs = parseword (cp, buf, sizeof (buf));
if (cs > 0) {
val = atoi (buf);
}
*i = val;
return cs;
}
/* Pick out the useful fields in the ``status'' file. */
static void parsestatus (const char *status, struct Process *p) {
const char *cp = status;
for (; *cp == ' '; ++cp);
{ /* comm */
cp += parseword (cp, p->comm, sizeof (p->comm));
}
{ /* pid */
cp += parseword (cp, p->pid, sizeof (p->pid));
}
{ /* ppid */
cp += parseword (cp, p->ppid, sizeof (p->ppid));
}
{ /* pgid (skip [useful field, actually DC]) */
for (; *cp == ' '; ++cp);
for (; *cp != ' ' && *cp != '\n'; ++cp);
}
{ /* sid (skip) */
for (; *cp == ' '; ++cp);
for (; *cp != ' ' && *cp != '\n'; ++cp);
}
{ /* major,minor */
int a, i;
cp += parseint (cp, &a);
if (*cp != ',' || a < 0) p->major = 0;
else p->major = a;
cp += parseint (cp, &i);
if (i < 0) p->minor = 0;
else p->minor = i;
p->tty[0] = 0;
if (a >= 0 && i >= 0) {
/* This loses for sure. DC */
switch (a) {
case 12: sprintf (p->tty, "%02d", i); break;
case 13: sprintf (p->tty, "e%d", i); break;
case 4: sprintf (p->tty, "p%x", i); break;
}
}
}
{ /* flags (skip) */
for (; *cp == ' '; ++cp);
for (; *cp != ' ' && *cp != '\n'; ++cp);
}
{ /* start */
int i;
cp += parseint (cp, &i);
p->start = i;
for (; *cp == ' '; ++cp);
for (; *cp != ' ' && *cp != '\n'; ++cp);
}
{ /* utime */
int i;
cp += parseint (cp, &i);
p->utime = i;
for (; *cp == ' '; ++cp);
for (; *cp != ' ' && *cp != '\n'; ++cp);
}
{ /* stime */
int i;
cp += parseint (cp, &i);
p->stime = i;
for (; *cp == ' '; ++cp);
for (; *cp != ' ' && *cp != '\n'; ++cp);
}
{ /* wmesg */
cp += parseword (cp, p->wmesg, sizeof (p->wmesg));
}
{ /* uid */
cp += parseword (cp, p->uid, sizeof (p->uid));
}
/* gid (skip) */
/* groups (skip) */
}
/* Shorten ctime() string. Copy to buf, no size check. */
static void displaytime (char *buf, time_t now, time_t then) {
int diff = now - then;
char *cp = ctime (&then);
int wc, w0;
if (diff > 60*60*12) { /* Old process */
wc = 2; /* get two words */
w0 = 1; /* starting at 1 - Jan 1 */
}
else {
wc = 1; /* get one word */
w0 = 3; /* starting at 3 - 00:00:00 */
}
for (; *cp == ' '; ++cp);
for (; w0 > 0; --w0) {
for (; *cp != ' ' && *cp != '\n'; ++cp);
for (; *cp == ' '; ++cp);
}
for (;;) {
for (; *cp != ' ' && *cp != '\n';) *buf++ = *cp++;
if (--wc > 0) {
*buf++ = ' ';
for (; *cp == ' '; ++cp);
}
else {
*buf = 0;
break;
}
}
}
/*
Selection list ... for users or pids from the command line.
*/
struct selent {
char *val;
struct selent *next;
};
static struct selent *list = 0;
static void addsel (const char *v, int vlen) {
struct selent *ent;
/* Fastidious programmers: please don't look. */
ent = (struct selent *) malloc (sizeof (struct selent) + vlen + 1);
ent->val = (char *) ent + sizeof (struct selent);
bcopy (v, ent->val, vlen);
ent->val[vlen] = 0;
ent->next = list;
list = ent;
}
/* Pick out and add words from a selection list. I gather POSIX ps may
take a string of space or comma delimited values, at least that's how
some latter-day SysV ps implementations look. */
static void addsels (const char *arg) {
register int i;
register const char *cp = arg;
for (;;) {
const char *start;
for (; *cp == ' '; ++cp);
if (!*cp) break;
for (i = 0, start = cp; *cp != ' ' && *cp; ++cp, ++i);
addsel (start, i);
}
}
static int checksel (const char *val) {
struct selent *ent;
for (ent = list; ent; ent = ent->next) {
if (strcmp (val, ent->val) == 0) return 1;
}
return 0;
}
main (int argc, char **argv) {
time_t now;
DIR *procfs;
struct dirent *d;
int doproc, douser, dotty, uidok;
char *arg;
/* The chdir() may save strain on the / inode ... a problem
with user loads ca. 1000, ask me. */
if (chdir ("/proc") < 0 || (procfs = opendir (".")) == 0) {
perror ("/proc");
exit (1);
}
dotty = doproc = douser = 0;
/* Someone may want to convert this to "getopt". */
for (++argv; arg = *argv; ++argv) {
if (*arg == '-') {
for (++arg; *arg; ++arg) {
switch (*arg) {
case 'u' : douser = 1; doproc = 0; dotty = 0; break;
case 'p' : doproc = 1; douser = 0; dotty = 0; break;
case 't' : dotty = 1; douser = 0; doproc = 0; break;
}
}
}
else {
if (doproc || douser || dotty) {
addsels (arg);
}
else {
fprintf (stderr, "%s: invalid argument\n", arg);
}
}
}
now = time (0);
setpwent ();
/* 123456781234512345 12345 12345 1234567890 12345678 12312312 */
puts ("USER PID PPID FILE MEM WMESG START TT CPU COMM");
while (d = readdir (procfs)) {
char line[256];
struct Process p;
FILE *pstatus;
struct passwd *pw;
char pfile[64];
char *name;
char start[12];
int seconds, minutes;
struct stat st;
/* Skip ".", "..", and "curproc". */
if (d->d_name[0] < '0' || d->d_name[0] > '9') continue;
if (doproc) {
if (!checksel (d->d_name)) continue;
}
sprintf (pfile, "%s/status", d->d_name);
if (!(pstatus = fopen (pfile, "r")) ||
!fgets (line, sizeof (line), pstatus))
{
perror (pfile);
continue;
}
fclose (pstatus);
parsestatus (line, &p);
if (dotty && !checksel (p.tty)) continue;
/* Check now to see if UID matches user arg. */
uidok = douser && checksel (p.uid);
pw = getpwuid (atoi (p.uid));
if (pw) name = pw->pw_name;
else name = p.uid;
if (douser) {
if (!uidok && !checksel (name)) continue;
}
sprintf (pfile, "%s/file", d->d_name);
if (stat (pfile, &st) < 0) {
/*perror (pfile);*/
/* pagedaemon/swapper "device not configured" */
p.filesize = 0;
}
else {
p.filesize = st.st_size;
}
sprintf (pfile, "%s/mem", d->d_name);
if (stat (pfile, &st) < 0) {
perror (pfile);
p.memsize = 0;
}
else {
p.memsize = st.st_size;
}
seconds = p.utime + p.stime;
minutes = seconds / 60;
seconds -= minutes * 60;
displaytime (start, now, p.start);
printf ("%-8.8s%5s%5s %5d %5d %-10.10s %-8s %-3.3s%3d:%02d %s\n",
name, p.pid, p.ppid,
(p.filesize + 511)/512,
(p.memsize + 511)/512,
p.wmesg, start, p.tty,
minutes, seconds, p.comm);
}
endpwent ();
exit (0);
}