Home | History | Annotate | Line # | Download | only in systat
ps.c revision 1.14
      1  1.14  thorpej /*      $NetBSD: ps.c,v 1.14 2000/06/02 04:32:07 thorpej Exp $  */
      2   1.1    jwise 
      3   1.1    jwise /*-
      4   1.1    jwise  * Copyright (c) 1999
      5   1.1    jwise  *      The NetBSD Foundation, Inc.  All rights reserved.
      6   1.1    jwise  *
      7   1.1    jwise  * Redistribution and use in source and binary forms, with or without
      8   1.1    jwise  * modification, are permitted provided that the following conditions
      9   1.1    jwise  * are met:
     10   1.1    jwise  * 1. Redistributions of source code must retain the above copyright
     11   1.1    jwise  *    notice, this list of conditions and the following disclaimer.
     12   1.1    jwise  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1    jwise  *    notice, this list of conditions and the following disclaimer in the
     14   1.1    jwise  *    documentation and/or other materials provided with the distribution.
     15   1.9    jwise  * 3. All advertising materials mentioning features or use of this software
     16   1.9    jwise  *    must display the following acknowledgement:
     17  1.11    jwise  *      This product includes software developed by the NetBSD Foundation.
     18  1.11    jwise  * 4. Neither the name of the Foundation nor the names of its contributors
     19   1.1    jwise  *    may be used to endorse or promote products derived from this software
     20   1.1    jwise  *    without specific prior written permission.
     21   1.1    jwise  *
     22   1.1    jwise  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23   1.1    jwise  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24   1.1    jwise  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25   1.1    jwise  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26   1.1    jwise  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27   1.1    jwise  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28   1.1    jwise  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29   1.1    jwise  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30   1.1    jwise  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31   1.1    jwise  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32   1.1    jwise  * SUCH DAMAGE.
     33   1.1    jwise  */
     34   1.1    jwise 
     35   1.1    jwise /*
     36   1.1    jwise  * XXX Notes XXX
     37   1.1    jwise  * showps -- print data needed at each refresh
     38   1.1    jwise  * fetchps -- get data used by mode (done at each refresh)
     39   1.1    jwise  * labelps -- print labels (ie info not needing refreshing)
     40   1.1    jwise  * initps -- prepare once-only data structures for mode
     41   1.1    jwise  * openps -- prepare per-run information for mode, return window
     42   1.1    jwise  * closeps -- close mode to prepare to switch modes
     43   1.1    jwise  * cmdps -- optional, handle commands
     44   1.1    jwise  */
     45   1.2   simonb 
     46   1.2   simonb #include <sys/cdefs.h>
     47   1.2   simonb #ifndef lint
     48  1.14  thorpej __RCSID("$NetBSD: ps.c,v 1.14 2000/06/02 04:32:07 thorpej Exp $");
     49   1.2   simonb #endif /* not lint */
     50   1.1    jwise 
     51   1.1    jwise #include <sys/param.h>
     52   1.1    jwise #include <sys/dkstat.h>
     53   1.1    jwise #include <sys/dir.h>
     54   1.1    jwise #include <sys/time.h>
     55   1.1    jwise #include <sys/proc.h>
     56   1.1    jwise #include <sys/sysctl.h>
     57   1.1    jwise #include <sys/user.h>
     58   1.1    jwise #include <curses.h>
     59   1.1    jwise #include <math.h>
     60   1.1    jwise #include <nlist.h>
     61   1.1    jwise #include <pwd.h>
     62   1.1    jwise #include <stdlib.h>
     63   1.1    jwise #include <string.h>
     64   1.1    jwise #include <tzfile.h>
     65   1.1    jwise #include <unistd.h>
     66   1.1    jwise 
     67   1.1    jwise #include "extern.h"
     68   1.1    jwise #include "systat.h"
     69   1.1    jwise #include "ps.h"
     70   1.1    jwise 
     71   1.1    jwise int compare_pctcpu_noidle __P((const void *, const void *));
     72   1.1    jwise char *state2str __P((struct kinfo_proc *));
     73   1.1    jwise char *tty2str __P((struct kinfo_proc *));
     74   1.1    jwise int rss2int __P((struct kinfo_proc *));
     75   1.1    jwise int vsz2int __P((struct kinfo_proc *));
     76   1.1    jwise char *comm2str __P((struct kinfo_proc *));
     77   1.3    itohy double pmem2float __P((struct kinfo_proc *));
     78   1.1    jwise char *start2str __P((struct kinfo_proc *));
     79   1.1    jwise char *time2str __P((struct kinfo_proc *));
     80   1.1    jwise 
     81   1.1    jwise static time_t now;
     82   1.1    jwise 
     83  1.12   kleink #define SHOWUSER_ANY	(uid_t)-1
     84  1.12   kleink static uid_t showuser = SHOWUSER_ANY;
     85  1.12   kleink 
     86  1.13   itojun #ifndef P_ZOMBIE
     87  1.13   itojun #define P_ZOMBIE(p)	((p)->p_stat == SZOMB)
     88  1.13   itojun #endif
     89  1.13   itojun 
     90   1.1    jwise void
     91   1.1    jwise labelps ()
     92   1.1    jwise {
     93   1.1    jwise 	mvwaddstr(wnd, 0, 0, "USER      PID %CPU %MEM    VSZ   RSS TT  STAT STARTED       TIME COMMAND");
     94   1.1    jwise }
     95   1.1    jwise 
     96   1.1    jwise void
     97   1.1    jwise showps ()
     98   1.1    jwise {
     99   1.1    jwise 	int i, k, y, vsz, rss;
    100   1.1    jwise 	const char *user, *comm, *state, *tty, *start, *time;
    101   1.1    jwise 	pid_t pid;
    102   1.3    itohy 	double pctcpu, pctmem;
    103   1.1    jwise 	struct  eproc *ep;
    104   1.1    jwise 
    105   1.1    jwise 	now = 0;	/* force start2str to reget current time */
    106   1.1    jwise 
    107   1.1    jwise 	qsort(pt, nproc + 1, sizeof (struct p_times), compare_pctcpu_noidle);
    108   1.1    jwise 
    109   1.1    jwise 	y = 1;
    110   1.1    jwise 	i = nproc + 1;
    111   1.1    jwise 	if (i > getmaxy(wnd)-2)
    112   1.1    jwise 		i = getmaxy(wnd)-1;
    113  1.12   kleink 	for (k = 0; i > 0 ; k++) {
    114   1.1    jwise 		if (pt[k].pt_kp == NULL) /* We're all the way down to the imaginary idle proc */
    115  1.12   kleink 			break;
    116   1.1    jwise 
    117   1.1    jwise 		ep = &pt[k].pt_kp->kp_eproc;
    118  1.12   kleink 		if (showuser != SHOWUSER_ANY && ep->e_ucred.cr_uid != showuser)
    119  1.12   kleink 			continue;
    120   1.1    jwise 		user = user_from_uid(ep->e_ucred.cr_uid, 0);
    121   1.1    jwise 		pid = pt[k].pt_kp->kp_proc.p_pid;
    122   1.3    itohy 		pctcpu = 100.0 * pt[k].pt_pctcpu;
    123   1.1    jwise 		pctmem = pmem2float(pt[k].pt_kp);
    124   1.1    jwise 		vsz = vsz2int(pt[k].pt_kp);
    125   1.1    jwise 		rss = rss2int(pt[k].pt_kp);
    126   1.1    jwise 		tty = tty2str(pt[k].pt_kp);
    127   1.1    jwise 		state = state2str(pt[k].pt_kp);
    128   1.1    jwise 		start = start2str(pt[k].pt_kp);
    129   1.1    jwise 		time = time2str(pt[k].pt_kp);
    130   1.1    jwise 		comm = comm2str(pt[k].pt_kp);
    131   1.1    jwise 		/*comm = pt[k].pt_kp->kp_proc.p_comm; */
    132   1.1    jwise 
    133   1.1    jwise 		wmove(wnd, y, 0);
    134   1.1    jwise 		wclrtoeol(wnd);
    135  1.12   kleink 		mvwprintw(wnd, y++, 0,
    136  1.12   kleink 		    "%-8.8s%5d %4.1f %4.1f %6d %5d %-3s %-4s %7s %10.10s %s",
    137  1.12   kleink 		    user, pid, pctcpu, pctmem, vsz, rss, tty, state, start, time, comm);
    138  1.12   kleink 		i--;
    139   1.1    jwise 	}
    140  1.12   kleink 	wmove(wnd, y, 0);
    141  1.12   kleink 	wclrtobot(wnd);
    142   1.1    jwise }
    143   1.1    jwise 
    144   1.1    jwise int
    145   1.1    jwise compare_pctcpu_noidle (a, b)
    146   1.1    jwise 	const void *a, *b;
    147   1.1    jwise {
    148   1.1    jwise 	if (((struct p_times *) a)->pt_kp == NULL)
    149   1.1    jwise 		return 1;
    150   1.1    jwise 
    151   1.1    jwise 	if (((struct p_times *) b)->pt_kp == NULL)
    152   1.1    jwise 	 	return -1;
    153   1.1    jwise 
    154   1.1    jwise 	return (((struct p_times *) a)->pt_pctcpu >
    155   1.1    jwise 		((struct p_times *) b)->pt_pctcpu)? -1: 1;
    156   1.1    jwise }
    157   1.1    jwise 
    158   1.1    jwise /* from here down adapted from .../src/usr.bin/ps/print.c .  Any mistakes are my own, however. */
    159   1.1    jwise char *
    160   1.1    jwise state2str(kp)
    161   1.1    jwise 	struct kinfo_proc *kp;
    162   1.1    jwise {
    163   1.1    jwise 	struct proc *p;
    164   1.1    jwise 	struct eproc *e;
    165   1.1    jwise 	int flag;
    166   1.1    jwise 	char *cp;
    167   1.1    jwise 	char buf[5];
    168   1.1    jwise 	static char statestr[4];
    169   1.1    jwise 
    170   1.1    jwise 	p = &(kp->kp_proc);
    171   1.1    jwise 	e = &(kp->kp_eproc);
    172   1.1    jwise 
    173   1.1    jwise 	flag = p->p_flag;
    174   1.1    jwise 	cp = buf;
    175   1.1    jwise 
    176   1.1    jwise 	switch (p->p_stat) {
    177   1.1    jwise 	case SSTOP:
    178   1.1    jwise 		*cp = 'T';
    179   1.1    jwise 		break;
    180   1.1    jwise 
    181   1.1    jwise 	case SSLEEP:
    182   1.1    jwise 		if (flag & P_SINTR)     /* interuptable (long) */
    183   1.1    jwise 			*cp = p->p_slptime >= MAXSLP ? 'I' : 'S';
    184   1.1    jwise 		else
    185   1.1    jwise 			*cp = 'D';
    186   1.1    jwise 		break;
    187   1.1    jwise 
    188   1.1    jwise 	case SRUN:
    189   1.1    jwise 	case SIDL:
    190  1.14  thorpej 	case SONPROC:
    191   1.1    jwise 		*cp = 'R';
    192   1.1    jwise 		break;
    193   1.1    jwise 
    194   1.1    jwise 	case SZOMB:
    195  1.13   itojun #ifdef SDEAD
    196   1.5    veego 	case SDEAD:
    197  1.13   itojun #endif
    198   1.1    jwise 		*cp = 'Z';
    199   1.1    jwise 		break;
    200   1.1    jwise 
    201   1.1    jwise 	default:
    202   1.1    jwise 		*cp = '?';
    203   1.1    jwise 	}
    204   1.1    jwise 	cp++;
    205   1.1    jwise 	if (flag & P_INMEM) {
    206   1.1    jwise 	} else
    207   1.1    jwise 		*cp++ = 'W';
    208   1.1    jwise 	if (p->p_nice < NZERO)
    209   1.1    jwise 		*cp++ = '<';
    210   1.1    jwise 	else if (p->p_nice > NZERO)
    211   1.1    jwise 		*cp++ = 'N';
    212   1.1    jwise 	if (flag & P_TRACED)
    213   1.1    jwise 		*cp++ = 'X';
    214   1.4  thorpej 	if (flag & P_WEXIT && P_ZOMBIE(p) == 0)
    215   1.1    jwise 		*cp++ = 'E';
    216   1.1    jwise 	if (flag & P_PPWAIT)
    217   1.1    jwise 		*cp++ = 'V';
    218   1.1    jwise 	if ((flag & P_SYSTEM) || p->p_holdcnt)
    219   1.1    jwise 		*cp++ = 'L';
    220   1.1    jwise 	if (e->e_flag & EPROC_SLEADER)
    221   1.1    jwise 		*cp++ = 's';
    222   1.1    jwise 	if ((flag & P_CONTROLT) && e->e_pgid == e->e_tpgid)
    223   1.1    jwise 		*cp++ = '+';
    224   1.1    jwise 	*cp = '\0';
    225  1.10    jwise 	snprintf(statestr, sizeof(statestr), "%-s",  buf);
    226   1.1    jwise 
    227   1.1    jwise 	return statestr;
    228   1.1    jwise }
    229   1.1    jwise 
    230   1.1    jwise char *
    231   1.1    jwise tty2str(kp)
    232   1.1    jwise 	struct kinfo_proc *kp;
    233   1.1    jwise {
    234   1.1    jwise 	static char ttystr[4];
    235   1.1    jwise 	char *ttyname;
    236   1.1    jwise 	struct eproc *e;
    237   1.1    jwise 
    238   1.1    jwise 	e = &(kp->kp_eproc);
    239   1.1    jwise 
    240   1.1    jwise 	if (e->e_tdev == NODEV || (ttyname = devname(e->e_tdev, S_IFCHR)) == NULL)
    241   1.1    jwise 		strcpy(ttystr, "??");
    242   1.1    jwise 	else {
    243   1.6      mrg 		if (strncmp(ttyname, "tty", 3) == 0 ||
    244   1.6      mrg 		    strncmp(ttyname, "dty", 3) == 0)
    245   1.1    jwise 			ttyname += 3;
    246  1.10    jwise 		snprintf(ttystr, sizeof(ttystr), "%s%c", ttyname, e->e_flag & EPROC_CTTY ? ' ' : '-');
    247   1.1    jwise 	}
    248   1.1    jwise 
    249   1.1    jwise 	return ttystr;
    250   1.1    jwise }
    251   1.1    jwise 
    252   1.1    jwise #define pgtok(a)	(((a)*getpagesize())/1024)
    253   1.1    jwise 
    254   1.1    jwise int
    255   1.1    jwise vsz2int(kp)
    256   1.1    jwise 	struct kinfo_proc *kp;
    257   1.1    jwise {
    258   1.1    jwise 	struct eproc *e;
    259   1.1    jwise 	int     i;
    260   1.1    jwise 
    261   1.1    jwise 	e = &(kp->kp_eproc);
    262   1.1    jwise 	i = pgtok(e->e_vm.vm_dsize + e->e_vm.vm_ssize + e->e_vm.vm_tsize);
    263   1.1    jwise 
    264   1.1    jwise 	return ((i < 0) ? 0 : i);
    265   1.1    jwise }
    266   1.1    jwise 
    267   1.1    jwise int
    268   1.1    jwise rss2int(kp)
    269   1.1    jwise 	struct kinfo_proc *kp;
    270   1.1    jwise {
    271   1.1    jwise 	struct eproc *e;
    272   1.1    jwise 	int	i;
    273   1.1    jwise 
    274   1.1    jwise 	e = &(kp->kp_eproc);
    275   1.1    jwise 	i = pgtok(e->e_vm.vm_rssize);
    276   1.1    jwise 
    277   1.1    jwise 	/* XXX don't have info about shared */
    278   1.1    jwise 	return ((i < 0) ? 0 : i);
    279   1.1    jwise }
    280   1.1    jwise 
    281   1.1    jwise char *
    282   1.1    jwise comm2str(kp)
    283   1.1    jwise 	struct kinfo_proc *kp;
    284   1.1    jwise {
    285   1.1    jwise 	char **argv, **pt;
    286   1.1    jwise 	static char commstr[41];
    287   1.1    jwise 	struct proc *p;
    288   1.1    jwise 
    289   1.1    jwise 	p = &(kp->kp_proc);
    290   1.1    jwise 	commstr[0]='\0';
    291   1.1    jwise 
    292   1.1    jwise 	argv = kvm_getargv(kd, kp, 40);
    293   1.1    jwise 	if ((pt = argv) != NULL) {
    294   1.1    jwise 		while (*pt) {
    295   1.1    jwise 			strcat(commstr, *pt);
    296   1.1    jwise 			pt++;
    297   1.1    jwise 			strcat(commstr, " ");
    298   1.1    jwise 		}
    299   1.1    jwise 	} else {
    300   1.1    jwise 		commstr[0] = '(';
    301   1.1    jwise 		commstr[1] = '\0';
    302   1.1    jwise 		strncat(commstr, p->p_comm, sizeof(commstr) - 1);
    303   1.1    jwise 		strcat(commstr, ")");
    304   1.1    jwise 	}
    305   1.1    jwise 
    306   1.1    jwise 	return commstr;
    307   1.1    jwise }
    308   1.1    jwise 
    309   1.3    itohy double
    310   1.1    jwise pmem2float(kp)
    311   1.1    jwise 	struct kinfo_proc *kp;
    312   1.1    jwise {
    313   1.1    jwise 	struct proc *p;
    314   1.1    jwise 	struct eproc *e;
    315   1.1    jwise 	double fracmem;
    316   1.1    jwise 	int szptudot;
    317   1.1    jwise 
    318   1.1    jwise 	p = &(kp->kp_proc);
    319   1.1    jwise 	e = &(kp->kp_eproc);
    320   1.1    jwise 
    321   1.1    jwise 	if ((p->p_flag & P_INMEM) == 0)
    322   1.1    jwise 	        return (0.0);
    323   1.1    jwise 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
    324   1.1    jwise 	szptudot = USPACE/getpagesize();
    325   1.1    jwise 	/* XXX don't have info about shared */
    326   1.7    fredb 	fracmem = ((double)e->e_vm.vm_rssize + szptudot)/mempages;
    327   1.1    jwise 	return (fracmem >= 0) ? 100.0 * fracmem : 0;
    328   1.1    jwise }
    329   1.1    jwise 
    330   1.1    jwise char *
    331   1.1    jwise start2str(kp)
    332   1.1    jwise 	struct kinfo_proc *kp;
    333   1.1    jwise {
    334   1.1    jwise 	struct proc *p;
    335   1.1    jwise 	struct pstats pstats;
    336   1.1    jwise 	struct timeval u_start;
    337   1.1    jwise 	struct tm *tp;
    338   1.1    jwise 	time_t startt;
    339   1.1    jwise 	static char startstr[10];
    340   1.1    jwise 
    341   1.1    jwise 	p = &(kp->kp_proc);
    342   1.1    jwise 
    343   1.1    jwise 	kvm_read(kd, (u_long)&(p->p_addr->u_stats), (char *)&pstats, sizeof(pstats));
    344   1.1    jwise 	u_start = pstats.p_start;
    345   1.1    jwise 
    346   1.1    jwise 	startt = u_start.tv_sec;
    347   1.1    jwise 	tp = localtime(&startt);
    348   1.1    jwise 	if (now == 0)
    349   1.1    jwise 	        time(&now);
    350   1.1    jwise 	if (now - u_start.tv_sec < 24 * SECSPERHOUR) {
    351   1.1    jwise 		/* I *hate* SCCS... */
    352   1.1    jwise 	        static char fmt[] = __CONCAT("%l:%", "M%p");
    353   1.1    jwise 	        strftime(startstr, sizeof(startstr) - 1, fmt, tp);
    354   1.1    jwise 	} else if (now - u_start.tv_sec < 7 * SECSPERDAY) {
    355   1.1    jwise 	        /* I *hate* SCCS... */
    356   1.1    jwise 	        static char fmt[] = __CONCAT("%a%", "I%p");
    357   1.1    jwise 	        strftime(startstr, sizeof(startstr) - 1, fmt, tp);
    358   1.1    jwise 	} else
    359   1.1    jwise 	        strftime(startstr, sizeof(startstr) - 1, "%e%b%y", tp);
    360   1.1    jwise 
    361   1.1    jwise 	return startstr;
    362   1.1    jwise }
    363   1.1    jwise 
    364   1.1    jwise char *
    365   1.1    jwise time2str(kp)
    366   1.1    jwise 	struct kinfo_proc *kp;
    367   1.1    jwise {
    368   1.1    jwise 	long secs;
    369   1.1    jwise 	long psecs;     /* "parts" of a second. first micro, then centi */
    370   1.1    jwise 	static char timestr[10];
    371   1.1    jwise 	struct proc *p;
    372   1.1    jwise 
    373   1.1    jwise 	p = &(kp->kp_proc);
    374   1.1    jwise 
    375   1.4  thorpej 	if (P_ZOMBIE(p)) {
    376   1.1    jwise 	        secs = 0;
    377   1.1    jwise 	        psecs = 0;
    378   1.1    jwise 	} else {
    379   1.1    jwise 	        /*
    380   1.1    jwise 	         * This counts time spent handling interrupts.  We could
    381   1.1    jwise 	         * fix this, but it is not 100% trivial (and interrupt
    382   1.1    jwise 	         * time fractions only work on the sparc anyway).       XXX
    383   1.1    jwise 	         */
    384   1.1    jwise 	        secs = p->p_rtime.tv_sec;
    385   1.1    jwise 	        psecs = p->p_rtime.tv_usec;
    386   1.1    jwise 	        /* if (sumrusage) {
    387   1.1    jwise 	                secs += k->ki_u.u_cru.ru_utime.tv_sec +
    388   1.1    jwise 	                        k->ki_u.u_cru.ru_stime.tv_sec;
    389   1.1    jwise 	                psecs += k->ki_u.u_cru.ru_utime.tv_usec +
    390   1.1    jwise 	                        k->ki_u.u_cru.ru_stime.tv_usec;
    391   1.1    jwise 	        } */
    392   1.1    jwise 	        /*
    393   1.1    jwise 	         * round and scale to 100's
    394   1.1    jwise 	         */
    395   1.1    jwise 	        psecs = (psecs + 5000) / 10000;
    396   1.1    jwise 	        secs += psecs / 100;
    397   1.1    jwise 	        psecs = psecs % 100;
    398   1.1    jwise 	}
    399   1.1    jwise 	snprintf(timestr, sizeof(timestr), "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
    400   1.1    jwise 
    401   1.1    jwise 	return timestr;
    402  1.12   kleink }
    403  1.12   kleink 
    404  1.12   kleink void
    405  1.12   kleink ps_user(args)
    406  1.12   kleink 	char *args;
    407  1.12   kleink {
    408  1.12   kleink 	uid_t uid;
    409  1.12   kleink 
    410  1.12   kleink 	if (args == NULL)
    411  1.12   kleink 		args = "";
    412  1.12   kleink 	if (strcmp(args, "+") == 0) {
    413  1.12   kleink 		uid = SHOWUSER_ANY;
    414  1.12   kleink 	} else if (uid_from_user(args, &uid) != 0) {
    415  1.12   kleink 		error("%s: unknown user", args);
    416  1.12   kleink 		return;
    417  1.12   kleink 	}
    418  1.12   kleink 
    419  1.12   kleink 	showuser = uid;
    420  1.12   kleink 	display(0);
    421   1.1    jwise }
    422