Home | History | Annotate | Line # | Download | only in systat
ps.c revision 1.24
      1  1.24   itojun /*      $NetBSD: ps.c,v 1.24 2003/05/17 21:03:21 itojun 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.24   itojun __RCSID("$NetBSD: ps.c,v 1.24 2003/05/17 21:03:21 itojun Exp $");
     49   1.2   simonb #endif /* not lint */
     50   1.1    jwise 
     51   1.1    jwise #include <sys/param.h>
     52  1.15    perry #include <sys/sched.h>
     53   1.1    jwise #include <sys/sysctl.h>
     54   1.1    jwise #include <sys/user.h>
     55  1.17   simonb 
     56   1.1    jwise #include <curses.h>
     57   1.1    jwise #include <math.h>
     58   1.1    jwise #include <pwd.h>
     59   1.1    jwise #include <stdlib.h>
     60   1.1    jwise #include <string.h>
     61   1.1    jwise #include <tzfile.h>
     62   1.1    jwise #include <unistd.h>
     63   1.1    jwise 
     64   1.1    jwise #include "extern.h"
     65   1.1    jwise #include "systat.h"
     66   1.1    jwise #include "ps.h"
     67   1.1    jwise 
     68  1.16       ad int compare_pctcpu_noidle(const void *, const void *);
     69  1.20  thorpej char *state2str(struct kinfo_proc2 *);
     70  1.20  thorpej char *tty2str(struct kinfo_proc2 *);
     71  1.20  thorpej int rss2int(struct kinfo_proc2 *);
     72  1.20  thorpej int vsz2int(struct kinfo_proc2 *);
     73  1.20  thorpej char *comm2str(struct kinfo_proc2 *);
     74  1.20  thorpej double pmem2float(struct kinfo_proc2 *);
     75  1.20  thorpej char *start2str(struct kinfo_proc2 *);
     76  1.20  thorpej char *time2str(struct kinfo_proc2 *);
     77   1.1    jwise 
     78   1.1    jwise static time_t now;
     79   1.1    jwise 
     80  1.12   kleink #define SHOWUSER_ANY	(uid_t)-1
     81  1.12   kleink static uid_t showuser = SHOWUSER_ANY;
     82  1.12   kleink 
     83  1.13   itojun #ifndef P_ZOMBIE
     84  1.13   itojun #define P_ZOMBIE(p)	((p)->p_stat == SZOMB)
     85  1.13   itojun #endif
     86  1.13   itojun 
     87   1.1    jwise void
     88  1.16       ad labelps(void)
     89   1.1    jwise {
     90   1.1    jwise 	mvwaddstr(wnd, 0, 0, "USER      PID %CPU %MEM    VSZ   RSS TT  STAT STARTED       TIME COMMAND");
     91   1.1    jwise }
     92   1.1    jwise 
     93   1.1    jwise void
     94  1.16       ad showps(void)
     95   1.1    jwise {
     96   1.1    jwise 	int i, k, y, vsz, rss;
     97   1.1    jwise 	const char *user, *comm, *state, *tty, *start, *time;
     98   1.1    jwise 	pid_t pid;
     99   1.3    itohy 	double pctcpu, pctmem;
    100  1.20  thorpej 	struct kinfo_proc2 *kp;
    101   1.1    jwise 
    102   1.1    jwise 	now = 0;	/* force start2str to reget current time */
    103   1.1    jwise 
    104   1.1    jwise 	qsort(pt, nproc + 1, sizeof (struct p_times), compare_pctcpu_noidle);
    105   1.1    jwise 
    106   1.1    jwise 	y = 1;
    107   1.1    jwise 	i = nproc + 1;
    108   1.1    jwise 	if (i > getmaxy(wnd)-2)
    109   1.1    jwise 		i = getmaxy(wnd)-1;
    110  1.12   kleink 	for (k = 0; i > 0 ; k++) {
    111   1.1    jwise 		if (pt[k].pt_kp == NULL) /* We're all the way down to the imaginary idle proc */
    112  1.12   kleink 			break;
    113   1.1    jwise 
    114  1.20  thorpej 		kp = pt[k].pt_kp;
    115  1.20  thorpej 		if (showuser != SHOWUSER_ANY && kp->p_uid != showuser)
    116  1.12   kleink 			continue;
    117  1.20  thorpej 		user = user_from_uid(kp->p_uid, 0);
    118  1.20  thorpej 		pid = kp->p_pid;
    119   1.3    itohy 		pctcpu = 100.0 * pt[k].pt_pctcpu;
    120   1.1    jwise 		pctmem = pmem2float(pt[k].pt_kp);
    121   1.1    jwise 		vsz = vsz2int(pt[k].pt_kp);
    122   1.1    jwise 		rss = rss2int(pt[k].pt_kp);
    123   1.1    jwise 		tty = tty2str(pt[k].pt_kp);
    124   1.1    jwise 		state = state2str(pt[k].pt_kp);
    125   1.1    jwise 		start = start2str(pt[k].pt_kp);
    126   1.1    jwise 		time = time2str(pt[k].pt_kp);
    127   1.1    jwise 		comm = comm2str(pt[k].pt_kp);
    128   1.1    jwise 		/*comm = pt[k].pt_kp->kp_proc.p_comm; */
    129   1.1    jwise 
    130   1.1    jwise 		wmove(wnd, y, 0);
    131   1.1    jwise 		wclrtoeol(wnd);
    132  1.12   kleink 		mvwprintw(wnd, y++, 0,
    133  1.12   kleink 		    "%-8.8s%5d %4.1f %4.1f %6d %5d %-3s %-4s %7s %10.10s %s",
    134  1.12   kleink 		    user, pid, pctcpu, pctmem, vsz, rss, tty, state, start, time, comm);
    135  1.12   kleink 		i--;
    136   1.1    jwise 	}
    137  1.12   kleink 	wmove(wnd, y, 0);
    138  1.12   kleink 	wclrtobot(wnd);
    139   1.1    jwise }
    140   1.1    jwise 
    141   1.1    jwise int
    142  1.16       ad compare_pctcpu_noidle(const void *a, const void *b)
    143   1.1    jwise {
    144   1.1    jwise 	if (((struct p_times *) a)->pt_kp == NULL)
    145   1.1    jwise 		return 1;
    146   1.1    jwise 
    147   1.1    jwise 	if (((struct p_times *) b)->pt_kp == NULL)
    148   1.1    jwise 	 	return -1;
    149   1.1    jwise 
    150   1.1    jwise 	return (((struct p_times *) a)->pt_pctcpu >
    151   1.1    jwise 		((struct p_times *) b)->pt_pctcpu)? -1: 1;
    152   1.1    jwise }
    153   1.1    jwise 
    154   1.1    jwise /* from here down adapted from .../src/usr.bin/ps/print.c .  Any mistakes are my own, however. */
    155   1.1    jwise char *
    156  1.20  thorpej state2str(struct kinfo_proc2 *kp)
    157   1.1    jwise {
    158   1.1    jwise 	int flag;
    159   1.1    jwise 	char *cp;
    160   1.1    jwise 	char buf[5];
    161   1.1    jwise 	static char statestr[4];
    162   1.1    jwise 
    163  1.20  thorpej 	flag = kp->p_flag;
    164   1.1    jwise 	cp = buf;
    165   1.1    jwise 
    166  1.20  thorpej 	switch (kp->p_stat) {
    167  1.22  thorpej 	case LSSTOP:
    168   1.1    jwise 		*cp = 'T';
    169   1.1    jwise 		break;
    170   1.1    jwise 
    171  1.22  thorpej 	case LSSLEEP:
    172  1.22  thorpej 		if (flag & L_SINTR)     /* interruptable (long) */
    173  1.20  thorpej 			*cp = kp->p_slptime >= maxslp ? 'I' : 'S';
    174   1.1    jwise 		else
    175   1.1    jwise 			*cp = 'D';
    176   1.1    jwise 		break;
    177   1.1    jwise 
    178  1.22  thorpej 	case LSRUN:
    179  1.22  thorpej 	case LSIDL:
    180  1.22  thorpej 	case LSONPROC:
    181   1.1    jwise 		*cp = 'R';
    182   1.1    jwise 		break;
    183   1.1    jwise 
    184  1.22  thorpej 	case LSZOMB:
    185  1.22  thorpej #ifdef LSDEAD
    186  1.22  thorpej 	case LSDEAD:
    187  1.13   itojun #endif
    188   1.1    jwise 		*cp = 'Z';
    189   1.1    jwise 		break;
    190   1.1    jwise 
    191   1.1    jwise 	default:
    192   1.1    jwise 		*cp = '?';
    193   1.1    jwise 	}
    194   1.1    jwise 	cp++;
    195  1.22  thorpej 	if (flag & L_INMEM) {
    196   1.1    jwise 	} else
    197   1.1    jwise 		*cp++ = 'W';
    198  1.20  thorpej 	if (kp->p_nice < NZERO)
    199   1.1    jwise 		*cp++ = '<';
    200  1.20  thorpej 	else if (kp->p_nice > NZERO)
    201   1.1    jwise 		*cp++ = 'N';
    202   1.1    jwise 	if (flag & P_TRACED)
    203   1.1    jwise 		*cp++ = 'X';
    204  1.20  thorpej 	if (flag & P_WEXIT &&
    205  1.20  thorpej 	    /* XXX - I don't like this */
    206  1.22  thorpej 	    (kp->p_stat == LSZOMB || kp->p_stat == LSDEAD) == 0)
    207   1.1    jwise 		*cp++ = 'E';
    208   1.1    jwise 	if (flag & P_PPWAIT)
    209   1.1    jwise 		*cp++ = 'V';
    210  1.20  thorpej 	if ((flag & P_SYSTEM) || kp->p_holdcnt)
    211   1.1    jwise 		*cp++ = 'L';
    212  1.20  thorpej 	if (kp->p_eflag & EPROC_SLEADER)
    213   1.1    jwise 		*cp++ = 's';
    214  1.20  thorpej 	if ((flag & P_CONTROLT) && kp->p__pgid == kp->p_tpgid)
    215   1.1    jwise 		*cp++ = '+';
    216   1.1    jwise 	*cp = '\0';
    217  1.10    jwise 	snprintf(statestr, sizeof(statestr), "%-s",  buf);
    218   1.1    jwise 
    219   1.1    jwise 	return statestr;
    220   1.1    jwise }
    221   1.1    jwise 
    222   1.1    jwise char *
    223  1.20  thorpej tty2str(struct kinfo_proc2 *kp)
    224   1.1    jwise {
    225   1.1    jwise 	static char ttystr[4];
    226   1.1    jwise 	char *ttyname;
    227   1.1    jwise 
    228  1.20  thorpej 	if (kp->p_tdev == NODEV ||
    229  1.20  thorpej 	    (ttyname = devname(kp->p_tdev, S_IFCHR)) == NULL)
    230  1.23   itojun 		strlcpy(ttystr, "??", sizeof(ttystr));
    231   1.1    jwise 	else {
    232   1.6      mrg 		if (strncmp(ttyname, "tty", 3) == 0 ||
    233   1.6      mrg 		    strncmp(ttyname, "dty", 3) == 0)
    234   1.1    jwise 			ttyname += 3;
    235  1.20  thorpej 		snprintf(ttystr, sizeof(ttystr), "%s%c", ttyname,
    236  1.20  thorpej 		    kp->p_eflag & EPROC_CTTY ? ' ' : '-');
    237   1.1    jwise 	}
    238   1.1    jwise 
    239   1.1    jwise 	return ttystr;
    240   1.1    jwise }
    241   1.1    jwise 
    242   1.1    jwise #define pgtok(a)	(((a)*getpagesize())/1024)
    243   1.1    jwise 
    244   1.1    jwise int
    245  1.20  thorpej vsz2int(struct kinfo_proc2 *kp)
    246   1.1    jwise {
    247   1.1    jwise 	int     i;
    248   1.1    jwise 
    249  1.20  thorpej 	i = pgtok(kp->p_vm_dsize + kp->p_vm_ssize + kp->p_vm_tsize);
    250   1.1    jwise 
    251   1.1    jwise 	return ((i < 0) ? 0 : i);
    252  1.20  thorpej }
    253   1.1    jwise 
    254   1.1    jwise int
    255  1.20  thorpej rss2int(struct kinfo_proc2 *kp)
    256   1.1    jwise {
    257   1.1    jwise 	int	i;
    258   1.1    jwise 
    259  1.20  thorpej 	i = pgtok(kp->p_vm_rssize);
    260   1.1    jwise 
    261   1.1    jwise 	/* XXX don't have info about shared */
    262   1.1    jwise 	return ((i < 0) ? 0 : i);
    263   1.1    jwise }
    264   1.1    jwise 
    265   1.1    jwise char *
    266  1.20  thorpej comm2str(struct kinfo_proc2 *kp)
    267   1.1    jwise {
    268   1.1    jwise 	char **argv, **pt;
    269   1.1    jwise 	static char commstr[41];
    270   1.1    jwise 
    271   1.1    jwise 	commstr[0]='\0';
    272   1.1    jwise 
    273  1.20  thorpej 	argv = kvm_getargv2(kd, kp, 40);
    274   1.1    jwise 	if ((pt = argv) != NULL) {
    275   1.1    jwise 		while (*pt) {
    276  1.24   itojun 			strlcat(commstr, *pt, sizeof(commstr));
    277   1.1    jwise 			pt++;
    278  1.24   itojun 			strlcat(commstr, " ", sizeof(commstr));
    279   1.1    jwise 		}
    280  1.24   itojun 	} else
    281  1.24   itojun 		snprintf(commstr, sizeof(commstr), "(%s)", kp->p_comm);
    282   1.1    jwise 
    283   1.1    jwise 	return commstr;
    284   1.1    jwise }
    285   1.1    jwise 
    286   1.3    itohy double
    287  1.20  thorpej pmem2float(struct kinfo_proc2 *kp)
    288   1.1    jwise {
    289   1.1    jwise 	double fracmem;
    290  1.19     matt 	int szptudot = 0;
    291   1.1    jwise 
    292  1.20  thorpej 	/* XXX - I don't like this. */
    293  1.22  thorpej 	if ((kp->p_flag & L_INMEM) == 0)
    294   1.1    jwise 	        return (0.0);
    295  1.19     matt #ifdef USPACE
    296   1.1    jwise 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
    297   1.1    jwise 	szptudot = USPACE/getpagesize();
    298  1.19     matt #endif
    299   1.1    jwise 	/* XXX don't have info about shared */
    300  1.20  thorpej 	fracmem = ((double)kp->p_vm_rssize + szptudot)/mempages;
    301   1.1    jwise 	return (fracmem >= 0) ? 100.0 * fracmem : 0;
    302   1.1    jwise }
    303   1.1    jwise 
    304   1.1    jwise char *
    305  1.20  thorpej start2str(struct kinfo_proc2 *kp)
    306   1.1    jwise {
    307   1.1    jwise 	struct timeval u_start;
    308   1.1    jwise 	struct tm *tp;
    309   1.1    jwise 	time_t startt;
    310   1.1    jwise 	static char startstr[10];
    311   1.1    jwise 
    312  1.20  thorpej 	u_start.tv_sec = kp->p_ustart_sec;
    313  1.20  thorpej 	u_start.tv_usec = kp->p_ustart_usec;
    314   1.1    jwise 
    315   1.1    jwise 	startt = u_start.tv_sec;
    316   1.1    jwise 	tp = localtime(&startt);
    317   1.1    jwise 	if (now == 0)
    318   1.1    jwise 	        time(&now);
    319   1.1    jwise 	if (now - u_start.tv_sec < 24 * SECSPERHOUR) {
    320   1.1    jwise 		/* I *hate* SCCS... */
    321  1.18      cgd 	        static char fmt[] = "%l:%" "M%p";
    322   1.1    jwise 	        strftime(startstr, sizeof(startstr) - 1, fmt, tp);
    323   1.1    jwise 	} else if (now - u_start.tv_sec < 7 * SECSPERDAY) {
    324   1.1    jwise 	        /* I *hate* SCCS... */
    325  1.18      cgd 	        static char fmt[] = "%a%" "I%p";
    326   1.1    jwise 	        strftime(startstr, sizeof(startstr) - 1, fmt, tp);
    327   1.1    jwise 	} else
    328   1.1    jwise 	        strftime(startstr, sizeof(startstr) - 1, "%e%b%y", tp);
    329   1.1    jwise 
    330   1.1    jwise 	return startstr;
    331   1.1    jwise }
    332   1.1    jwise 
    333   1.1    jwise char *
    334  1.20  thorpej time2str(struct kinfo_proc2 *kp)
    335   1.1    jwise {
    336   1.1    jwise 	long secs;
    337   1.1    jwise 	long psecs;     /* "parts" of a second. first micro, then centi */
    338   1.1    jwise 	static char timestr[10];
    339   1.1    jwise 
    340  1.20  thorpej 	/* XXX - I don't like this. */
    341  1.20  thorpej 	if (kp->p_stat == SZOMB || kp->p_stat == SDEAD) {
    342   1.1    jwise 	        secs = 0;
    343   1.1    jwise 	        psecs = 0;
    344   1.1    jwise 	} else {
    345   1.1    jwise 	        /*
    346   1.1    jwise 	         * This counts time spent handling interrupts.  We could
    347   1.1    jwise 	         * fix this, but it is not 100% trivial (and interrupt
    348   1.1    jwise 	         * time fractions only work on the sparc anyway).       XXX
    349   1.1    jwise 	         */
    350  1.20  thorpej 	        secs = kp->p_rtime_sec;
    351  1.20  thorpej 	        psecs = kp->p_rtime_usec;
    352  1.20  thorpej #if 0
    353  1.20  thorpej 	        if (sumrusage) {
    354   1.1    jwise 	                secs += k->ki_u.u_cru.ru_utime.tv_sec +
    355   1.1    jwise 	                        k->ki_u.u_cru.ru_stime.tv_sec;
    356   1.1    jwise 	                psecs += k->ki_u.u_cru.ru_utime.tv_usec +
    357   1.1    jwise 	                        k->ki_u.u_cru.ru_stime.tv_usec;
    358  1.20  thorpej 	        }
    359  1.20  thorpej #endif
    360   1.1    jwise 	        /*
    361   1.1    jwise 	         * round and scale to 100's
    362   1.1    jwise 	         */
    363   1.1    jwise 	        psecs = (psecs + 5000) / 10000;
    364   1.1    jwise 	        secs += psecs / 100;
    365   1.1    jwise 	        psecs = psecs % 100;
    366   1.1    jwise 	}
    367  1.20  thorpej 	snprintf(timestr, sizeof(timestr), "%3ld:%02ld.%02ld", secs/60,
    368  1.20  thorpej 	    secs%60, psecs);
    369   1.1    jwise 
    370   1.1    jwise 	return timestr;
    371  1.12   kleink }
    372  1.12   kleink 
    373  1.12   kleink void
    374  1.16       ad ps_user(char *args)
    375  1.12   kleink {
    376  1.12   kleink 	uid_t uid;
    377  1.12   kleink 
    378  1.12   kleink 	if (args == NULL)
    379  1.12   kleink 		args = "";
    380  1.12   kleink 	if (strcmp(args, "+") == 0) {
    381  1.12   kleink 		uid = SHOWUSER_ANY;
    382  1.12   kleink 	} else if (uid_from_user(args, &uid) != 0) {
    383  1.12   kleink 		error("%s: unknown user", args);
    384  1.12   kleink 		return;
    385  1.12   kleink 	}
    386  1.12   kleink 
    387  1.12   kleink 	showuser = uid;
    388  1.12   kleink 	display(0);
    389   1.1    jwise }
    390