home *** CD-ROM | disk | FTP | other *** search
- /*
-
- ps.c: a program to print MiNT process statuses
-
-
- Coded: 3/24/1991 by Tony Reynolds, cctony@sgisci1.ocis.olemiss.edu
- For use with: MiNT release 0.7
- Updated: 3/29/1991 by Eric Smith for MiNT version 0.8
-
- Updated and completely revised from 'ps' into 'top' by AKP 8/91.
- Link with -lcurses and -ltermcap. Beware! Bammi's GNU curses
- makefile actually links the termcap object files into curses.olb,
- so changing them and recompiling only termcap.olb will have no effect!
-
- Updated some more 11/91 by Allan Pratt for MiNT version 0.9
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <osbind.h>
- #include <errno.h>
- #include <basepage.h>
- #include <ioctl.h>
- #include <time.h>
- #include <curses.h>
- #include <signal.h>
- #include <mintbind.h>
- #include <ctype.h>
- #include <string.h>
- #include <unistd.h>
-
- #ifndef PCTXTSIZE
- #define PCTXTSIZE (('P'<<8)|3)
- #endif
-
- #define MINWIDTH 36 /* this is the width of everything before the command */
- #define DEF_PTABSIZ 99 /* this is how many process' worth of table to have */
-
- struct status { /* defines values for internal->external process states */
- int mint; /* what MiNT knows */
- char desc[6]; /* a textual description for above */
- } proc_stat[] = {
- 0, "Run ", /* really "run" but "top" is always running! */
- 0x01, "Run ",
- 0x20, "Wait ",
- 0x21, "Sleep",
- 0x22, "Exit ",
- 0x02, "TSR ",
- 0x24, "Stop ",
- -1, "?????"
- };
-
- typedef struct _context {
- long regs[15]; /* registers d0-d7, a0-a6 */
- long usp; /* user stack pointer (a7) */
- short sr; /* status register */
- long pc; /* program counter */
- long ssp; /* supervisor stack pointer */
- long term_vec; /* GEMDOS terminate vector (0x102) */
-
- /* these fields were added in MiNT 0.9 -- ERS */
- char fstate[216]; /* FPU internal state */
- char fregs[12*8]; /* registers fp0-fp7 */
- long fctrl[3]; /* FPCR/FPSR/FPIAR */
- short sfmt; /* stack frame format identifier */
- long iar; /* instruction address */
- short internal[4]; /* four words of internal info */
- } CONTEXT;
-
- struct pinfo {
- long magic;
- char *base;
- short pid, ppid, pgrp;
- short ruid, rgid;
- short euid, egid;
- short flags;
- short pri;
- short wait_q;
- long wait_cond;
- unsigned long systime, usrtime, chldstime, chldutime;
- unsigned long maxmem, maxdata, maxcore, maxcpu;
- short domain;
- short curpri;
- };
-
- /* open the process named "name" */
- int
- open_proc(name)
- char *name;
- {
- static char pname[32] = "u:\\proc\\";
-
- strcpy(pname+8, name);
- return open(pname, 0);
- }
-
- struct ptab {
- short pid;
- short used;
- long lasttime;
- char line[2]; /* make sure sizeof(struct ptab) is even */
- } *ptab; /* an array of these gets malloc'ed */
-
- #define INCPTAB(p) ((struct ptab *)(((char *)p) + sizeof(struct ptab) + width))
-
- int garbage = 0; /* when set, screen needs total update */
-
- void
- quit(sig)
- long sig;
- {
- /* move to bottom of screen */
- mvcur(0, COLS - 1, LINES - 1, 0);
- endwin();
- exit(0);
- }
-
- void
- usage()
- {
- puts("Usage: top [-s sleeptime] [-w width] [-n nlines] [-r]");
- puts("-r sorts procs in decreasing PID order; usually increasing PID.");
- puts("TOP ONLY RUNS UNDER MiNT. Use '?' to get help.");
- exit(1);
- }
-
- void
- dokill(s)
- char *s;
- {
- int signum = SIGTERM;
- int pid;
- char *p;
- char hold;
-
- while (isspace(*s)) s++;
- if (*s == '-') {
- p = ++s;
- while (*p && !isspace(*p)) p++;
- hold = *p;
- *p = '\0';
- if (p != s) signum = atoi(s);
- *p = hold;
- if (!signum) signum = SIGTERM;
- s = p;
- }
- while (isspace(*s)) s++;
-
- while (*s) {
- p = s;
- while (*p && !isspace(*p)) p++;
- hold = *p;
- *p = '\0';
- pid = atoi(s);
- *p = hold;
- s = p;
- if (pid) (void)Pkill(pid,signum);
- while (isspace(*s)) s++;
- }
- }
-
- void
- dorenice(s)
- char *s;
- {
- int niceval;
- int pid;
- char *p;
- char hold;
-
- while (isspace(*s)) s++;
- p = s;
- while (*p && !isspace(*p)) p++;
- hold = *p;
- *p = '\0';
- niceval = atoi(s);
- *p = hold;
- s = p;
-
- while (isspace(*s)) s++;
-
- while (*s) {
- p = s;
- while (*p && !isspace(*p)) p++;
- hold = *p;
- *p = '\0';
- pid = atoi(s);
- *p = hold;
- s = p;
- if (pid) (void)Prenice(pid,niceval);
- while (isspace(*s)) s++;
- }
- }
-
- int
- cmp_incr_pid(void *p1, void *p2)
- {
- struct ptab *pt1 = p1, *pt2 = p2;
- int pid1 = pt1->pid, pid2 = pt2->pid;
- if (pid1 == -1 && pid2 == -1) return 0;
- if (pid1 == -1) return 1; /* send invalid procs to bottom */
- if (pid2 == -1) return -1;
- return pid1 - pid2;
- }
-
- int
- cmp_decr_pid(void *p1, void *p2)
- {
- struct ptab *pt1 = p1, *pt2 = p2;
- int pid1 = pt1->pid, pid2 = pt2->pid;
- if (pid1 == -1 && pid2 == -1) return 0;
- if (pid1 == -1) return 1; /* send invalid procs to bottom */
- if (pid2 == -1) return -1;
- return pid2 - pid1;
- }
-
- char helpstr[] =
- " s[leeptime] w[idth] n[lines] k[ill] r[enice] h[elp] p[riority] q[uit]\r";
-
- void
- main(argc, argv)
- int argc;
- char **argv;
- {
- int repeat_time = 0;
- _DTA mydta;
- int fd;
- int fserror=0;
- long place, procaddr;
- int pid, ppid;
- char *cmdline;
- struct status *statp;
- char bpage[sizeof(BASEPAGE)];
- struct pinfo proc;
- int thispid;
- struct ptab *pt;
- char *c;
- unsigned long ptime, hour, min, sec, frac;
- long realtime;
- long lastclock = clock();
- long thisclock;
- int i;
- long deltime;
- long ctxtsize;
- int nprocs, nrunning;
- long cummemory, idletime;
- int width = 0;
- long readfds;
- char ibuf[80];
- int ichar;
- int taillen, cmdlen;
- int tailstart;
- int nlines = 0;
- int helpline = 0;
- int ptabsiz = DEF_PTABSIZ;
- int len;
- int (*cmpfunc)();
- extern int __mint;
- int ppid_mode = 1;
-
- cmpfunc = cmp_incr_pid;
-
- if (!__mint) usage();
- --argc, ++argv;
- while (argc) {
- if (**argv != '-') usage();
- switch(argv[0][1]) {
- case 'r': cmpfunc = cmp_decr_pid;
- break;
- case 's': if (argc == 0) usage();
- if ((repeat_time = atoi(argv[1])) == 0) usage();
- ++argv, --argc;
- break;
- case 'w': if (argc == 0) usage();
- if ((width = atoi(argv[1])) <= 0) usage();
- if (width < MINWIDTH) width = MINWIDTH;
- ++argv, --argc;
- break;
- case 'n': if (argc == 0) usage();
- if ((nlines = atoi(argv[1])) <= 0) usage();
- ++argv, --argc;
- break;
-
- default: usage();
- }
- --argc, ++argv;
- }
-
- Fsetdta(&mydta); /* give the OS my new DTA */
-
- initscr();
-
- if (!width) width = COLS-1; /* default if it's unset */
- width &= ~1; /* make sure width is even, too */
-
- if (!repeat_time) repeat_time = 5;
- if (LINES < 4) {
- puts("top: can't run on a screen with < 4 lines");
- exit(1);
- }
- if (nlines == 0 || nlines > (LINES-3)) nlines = LINES-3;
-
- /* struct ptab ends with char line[2] so there's already padding for '\0' */
- if ((ptab = malloc((sizeof(struct ptab) + width) * ptabsiz)) == NULL) {
- puts("top: can't get memory for process structures");
- exit(1);
- }
-
- cbreak();
- noecho();
-
- signal(SIGINT,quit);
- signal(SIGQUIT,quit);
- signal(SIGHUP,quit);
- signal(SIGTERM,quit);
-
- for (i = ptabsiz, pt = ptab; i; i--, pt = INCPTAB(pt)) {
- pt->pid = -1;
- pt->used = 0;
- }
-
- while (1) {
- fserror=Fsfirst("u:\\proc\\*.*", -1);
- if (fserror < 0) {
- fprintf(stderr, "top: cannot list processes ?!");
- exit(1);
- }
-
- erase();
-
- /* top line is printed later */
-
- if (ppid_mode) {
- printw("\n\nPID PPID STATUS SIZE TIME %% COMMAND\n");
- }
- else {
- printw("\n\nPID PRI CUR STATUS SIZE TIME %% COMMAND\n");
- }
-
- nprocs = 0;
- nrunning = 0;
- idletime = 0;
- cummemory = 0;
-
- thisclock = clock();
- realtime = (thisclock - lastclock) * (1000/CLOCKS_PER_SEC);
- lastclock = thisclock;
-
- /* okay, now run the Fsnext bit through the wringer */
-
- fserror = E_OK; /* set up for the loop */
-
- while (fserror == E_OK ) {
- fd = open_proc(mydta.dta_name);
- if (fd < 0) goto getnext;
-
- /* cut name off at '.' */
- for (cmdline = mydta.dta_name;
- *cmdline && *cmdline != '.';
- cmdline++)
- /* do nothing */ ;
- *cmdline = 0;
-
- ioctl(fd, PPROCADDR, &procaddr);
- if (ioctl(fd, PCTXTSIZE, &ctxtsize) < 0)
- lseek(fd, procaddr+4+2*sizeof(CONTEXT), 0);
- else
- lseek(fd, procaddr, 0);
- read(fd, &proc, sizeof(proc));
- pid = proc.pid;
- ppid = proc.ppid;
- ioctl(fd, PBASEADDR, &place);
- lseek(fd, place, 0);
- read(fd, bpage, sizeof(bpage));
- close(fd);
- cmdline = bpage+128;
- if (*cmdline) *cmdline = ' ';
-
- /* span cmdline turning control chars into question marks */
- for (c = cmdline; *c; c++) if (*c < ' ') *c = '?';
-
- taillen = c - cmdline;
-
- thispid = proc.pid;
- if (ppid < 0) ppid = 0;
-
- statp = proc_stat; /* hunt down string referring to
- process status */
- while (statp->mint != mydta.dta_attribute &&
- statp->mint >= 0) statp++;
-
- ptime = proc.systime + proc.usrtime;
-
- /* set deltime to the time used since last time we checked */
- for (i = ptabsiz, pt = ptab; i; i--, pt = INCPTAB(pt)) {
- if (pt->pid == thispid) {
- pt->used = 1;
- deltime = ptime - pt->lasttime;
- pt->lasttime = ptime;
- goto found;
- }
- }
-
- /* fell out: didn't find the process */
- for (i = ptabsiz, pt = ptab; i; i--, pt = INCPTAB(pt)) {
- if (pt->pid == -1) {
- /* use this slot */
- pt->used = 1;
- pt->pid = thispid;
- pt->lasttime = ptime;
- deltime = (ptime > realtime ? realtime : ptime);
- goto found;
- }
- }
- /* fell out again - can't keep track of this process (sorry!) */
- deltime = 0;
- pt = NULL;
-
- found:
-
- if (thispid == 0) {
- /* idle time is charged to process zero */
- idletime = deltime;
- strcpy(mydta.dta_name,"(idle)");
- }
-
- hour = (ptime/1000/60/60);
- min = (ptime/1000/60)%60;
- sec = (ptime/1000)%60;
- frac = (ptime%1000) / 10; /* (never anything in .001 digit) */
-
- if (ppid_mode) {
- len = sprintf(pt->line,"%03d %03d %-5s %8ld ",
- pid, ppid, statp->desc, mydta.dta_size);
- }
- else {
- len = sprintf(pt->line,"%03d %3d %3d %-5s %8ld ",
- pid, proc.pri, proc.curpri, statp->desc, mydta.dta_size);
- }
-
- if (hour)
- len += sprintf(pt->line + len,"%2ld:%02ld:%02ld",hour,min,sec);
- else
- len += sprintf(pt->line + len,"%2ld:%02ld.%02ld",min,sec,frac);
-
- len += sprintf(pt->line + len," %3ld ",(deltime * 100) / realtime);
-
- /* if the line's too long, cut off the tail so the total is width */
- cmdlen = strlen(mydta.dta_name);
- tailstart = len+cmdlen;
- if (width < tailstart) cmdline[0] = 0;
- else if (tailstart+taillen > width) {
- cmdline[width-tailstart] = '\0';
- }
- sprintf(pt->line + len,"%s%s",mydta.dta_name,cmdline);
-
- nprocs++;
-
- cummemory += mydta.dta_size;
- if (deltime) nrunning++;
-
- getnext:
- fserror = Fsnext();
- }
-
- /*
- * Now zero out those slots which weren't used in the last pass, and zero
- * all "used" fields
- */
- for (i = nlines, pt = ptab; i; i--, pt = INCPTAB(pt)) {
- if (!pt->used) pt->pid = -1;
- else pt->used = 0;
- }
-
- /*
- * Now all processes are in the ptab array, their lines stored. Sort them
- * into printing order and print nlines of them.
- */
-
- qsort(ptab,nlines,sizeof(struct ptab) + width,cmpfunc);
- if (nprocs < nlines) i = nprocs;
- else i = nlines;
- for (pt = ptab; i; i--, pt = INCPTAB(pt)) {
- printw("%s\n",pt->line);
- }
-
- /* compute idle percentage into idletime */
- idletime = (idletime * 100) / realtime;
-
- move(0,0);
- printw("Sample time: %5ld; %3ld%% idle; %3d processes, %3d running"
- "; %ld bytes used\n",
- realtime,idletime,nprocs,nrunning,cummemory);
-
- if (helpline) printw(helpstr);
-
- if (garbage) wrefresh(curscr);
- else refresh();
- garbage = 0;
-
- /* Fall asleep for repeat_time seconds or until a key comes in. */
- /* We want zero to mean "no time" not "forever" so add one. */
- readfds = 1;
- if (Fselect(repeat_time * 1000 + 1,&readfds,0L,0L)) {
- /* input waiting */
- if (helpline) {
- clrtoeol();
- refresh();
- helpline = 0;
- }
- ichar = getch();
- switch(ichar) {
- case 'L'-'@':
- garbage = 1;
- break;
- case 's':
- printw("sleep time: ");
- refresh();
- echo();
- getstr(ibuf);
- noecho();
- if (*ibuf) repeat_time = atoi(ibuf);
- if (repeat_time < 0) repeat_time = 0;
- break;
- case 'w':
- printw("width: ");
- refresh();
- echo();
- getstr(ibuf);
- noecho();
- if (*ibuf) width = atoi(ibuf);
- if (width < MINWIDTH) width = MINWIDTH;
- width &= ~1; /* make sure width is even */
- break;
- case 'n':
- printw("nlines: ");
- refresh();
- echo();
- getstr(ibuf);
- noecho();
- if (*ibuf) nlines = atoi(ibuf);
- if (nlines == 0 || nlines > (LINES-3)) nlines = (LINES-3);
- break;
- case 'k':
- printw("kill ");
- refresh();
- echo();
- getstr(ibuf);
- noecho();
- if (*ibuf) dokill(ibuf);
- break;
- case 'r':
- printw("renice ");
- refresh();
- echo();
- getstr(ibuf);
- noecho();
- if (*ibuf) dorenice(ibuf);
- break;
- case 'p':
- /* toggle ppid_mode */
- ppid_mode ^= 1;
- break;
- case 'h':
- case '?':
- helpline = 1;
- break;
- case 'q': quit();
- default: ;
- }
- }
- }
- }
-
-
-