1 /* $NetBSD: ps.c,v 1.33 2009/04/13 23:20:27 lukem Exp $ */
5 * The NetBSD Foundation, Inc. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the NetBSD Foundation.
18 * 4. Neither the name of the Foundation nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * showps -- print data needed at each refresh
38 * fetchps -- get data used by mode (done at each refresh)
39 * labelps -- print labels (ie info not needing refreshing)
40 * initps -- prepare once-only data structures for mode
41 * openps -- prepare per-run information for mode, return window
42 * closeps -- close mode to prepare to switch modes
43 * cmdps -- optional, handle commands
46 #include <sys/cdefs.h>
48 __RCSID("$NetBSD: ps.c,v 1.33 2009/04/13 23:20:27 lukem Exp $");
51 #include <sys/param.h>
52 #include <sys/sched.h>
53 #include <sys/sysctl.h>
68 int compare_pctcpu_noidle(const void *, const void *);
69 char *state2str(struct kinfo_proc2
*);
70 char *tty2str(struct kinfo_proc2
*);
71 int rss2int(struct kinfo_proc2
*);
72 int vsz2int(struct kinfo_proc2
*);
73 char *comm2str(struct kinfo_proc2
*);
74 double pmem2float(struct kinfo_proc2
*);
75 char *start2str(struct kinfo_proc2
*);
76 char *time2str(struct kinfo_proc2
*);
80 #define SHOWUSER_ANY (uid_t)-1
81 static uid_t showuser
= SHOWUSER_ANY
;
84 #define P_ZOMBIE(p) ((p)->p_stat == SZOMB)
90 mvwaddstr(wnd
, 0, 0, "USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND");
96 int i
, k
, y
, vsz
, rss
;
97 const char *user
, *comm
, *state
, *tty
, *start
, *time_str
;
99 double pctcpu
, pctmem
;
100 struct kinfo_proc2
*kp
;
102 now
= 0; /* force start2str to reget current time */
104 qsort(pt
, nproc
+ 1, sizeof (struct p_times
), compare_pctcpu_noidle
);
108 if (i
> getmaxy(wnd
)-2)
110 for (k
= 0; i
> 0 ; k
++) {
111 if (pt
[k
].pt_kp
== NULL
) /* We're all the way down to the imaginary idle proc */
115 if (showuser
!= SHOWUSER_ANY
&& kp
->p_uid
!= showuser
)
117 user
= user_from_uid(kp
->p_uid
, 0);
119 pctcpu
= 100.0 * pt
[k
].pt_pctcpu
;
120 pctmem
= pmem2float(pt
[k
].pt_kp
);
121 vsz
= vsz2int(pt
[k
].pt_kp
);
122 rss
= rss2int(pt
[k
].pt_kp
);
123 tty
= tty2str(pt
[k
].pt_kp
);
124 state
= state2str(pt
[k
].pt_kp
);
125 start
= start2str(pt
[k
].pt_kp
);
126 time_str
= time2str(pt
[k
].pt_kp
);
127 comm
= comm2str(pt
[k
].pt_kp
);
128 /*comm = pt[k].pt_kp->kp_proc.p_comm; */
132 mvwprintw(wnd
, y
++, 0,
133 "%-8.8s%5d %4.1f %4.1f %6d %5d %-3s %-4s %7s %10.10s %s",
134 user
, pid
, pctcpu
, pctmem
, vsz
, rss
, tty
, state
, start
,
143 compare_pctcpu_noidle(const void *a
, const void *b
)
145 if (((const struct p_times
*) a
)->pt_kp
== NULL
)
148 if (((const struct p_times
*) b
)->pt_kp
== NULL
)
151 return (((const struct p_times
*) a
)->pt_pctcpu
>
152 ((const struct p_times
*) b
)->pt_pctcpu
)? -1: 1;
155 /* from here down adapted from .../src/usr.bin/ps/print.c . Any mistakes are my own, however. */
157 state2str(struct kinfo_proc2
*kp
)
162 static char statestr
[4];
167 switch (kp
->p_stat
) {
173 if (flag
& L_SINTR
) /* interruptable (long) */
174 *cp
= kp
->p_slptime
>= (uint32_t)maxslp
? 'I' : 'S';
196 if (kp
->p_nice
< NZERO
)
198 else if (kp
->p_nice
> NZERO
)
202 if (flag
& P_WEXIT
&&
203 /* XXX - I don't like this */
204 (kp
->p_stat
!= LSZOMB
))
208 if (kp
->p_eflag
& EPROC_SLEADER
)
210 if ((flag
& P_CONTROLT
) && kp
->p__pgid
== kp
->p_tpgid
)
213 snprintf(statestr
, sizeof(statestr
), "%-s", buf
);
219 tty2str(struct kinfo_proc2
*kp
)
221 static char ttystr
[4];
224 if (kp
->p_tdev
== (uint32_t)NODEV
||
225 (tty_name
= devname(kp
->p_tdev
, S_IFCHR
)) == NULL
)
226 strlcpy(ttystr
, "??", sizeof(ttystr
));
228 if (strncmp(tty_name
, "tty", 3) == 0 ||
229 strncmp(tty_name
, "dty", 3) == 0)
231 snprintf(ttystr
, sizeof(ttystr
), "%s%c", tty_name
,
232 kp
->p_eflag
& EPROC_CTTY
? ' ' : '-');
238 #define pgtok(a) (((a)*getpagesize())/1024)
241 vsz2int(struct kinfo_proc2
*kp
)
245 i
= pgtok(kp
->p_vm_msize
);
247 return ((i
< 0) ? 0 : i
);
251 rss2int(struct kinfo_proc2
*kp
)
255 i
= pgtok(kp
->p_vm_rssize
);
257 /* XXX don't have info about shared */
258 return ((i
< 0) ? 0 : i
);
262 comm2str(struct kinfo_proc2
*kp
)
265 static char commstr
[41];
269 argv
= kvm_getargv2(kd
, kp
, 40);
272 strlcat(commstr
, *argv
, sizeof(commstr
));
274 strlcat(commstr
, " ", sizeof(commstr
));
280 * Commands that don't set an argv vector are printed with
281 * square brackets if they are system commands. Otherwise
282 * they are printed within parentheses.
284 if (kp
->p_flag
& P_SYSTEM
)
289 snprintf(commstr
, sizeof(commstr
), fmt
, kp
->p_comm
);
296 pmem2float(struct kinfo_proc2
*kp
)
302 /* XXX want pmap ptpages, segtab, etc. (per architecture) */
303 szptudot
= USPACE
/getpagesize();
305 /* XXX don't have info about shared */
306 fracmem
= ((double)kp
->p_vm_rssize
+ szptudot
)/mempages
;
307 return (fracmem
>= 0) ? 100.0 * fracmem
: 0;
311 start2str(struct kinfo_proc2
*kp
)
313 struct timeval u_start
;
316 static char startstr
[10];
318 u_start
.tv_sec
= kp
->p_ustart_sec
;
319 u_start
.tv_usec
= kp
->p_ustart_usec
;
321 startt
= u_start
.tv_sec
;
322 tp
= localtime(&startt
);
325 if (now
- u_start
.tv_sec
< 24 * SECSPERHOUR
) {
326 /* I *hate* SCCS... */
327 static char fmt
[] = "%l:%" "M%p";
328 strftime(startstr
, sizeof(startstr
) - 1, fmt
, tp
);
329 } else if (now
- u_start
.tv_sec
< 7 * SECSPERDAY
) {
330 /* I *hate* SCCS... */
331 static char fmt
[] = "%a%" "I%p";
332 strftime(startstr
, sizeof(startstr
) - 1, fmt
, tp
);
334 strftime(startstr
, sizeof(startstr
) - 1, "%e%b%y", tp
);
340 time2str(struct kinfo_proc2
*kp
)
343 long psecs
; /* "parts" of a second. first micro, then centi */
344 static char timestr
[10];
346 /* XXX - I don't like this. */
347 if (kp
->p_stat
== SZOMB
) {
352 * This counts time spent handling interrupts. We could
353 * fix this, but it is not 100% trivial (and interrupt
354 * time fractions only work on the sparc anyway). XXX
356 secs
= kp
->p_rtime_sec
;
357 psecs
= kp
->p_rtime_usec
;
360 secs
+= k
->ki_u
.u_cru
.ru_utime
.tv_sec
+
361 k
->ki_u
.u_cru
.ru_stime
.tv_sec
;
362 psecs
+= k
->ki_u
.u_cru
.ru_utime
.tv_usec
+
363 k
->ki_u
.u_cru
.ru_stime
.tv_usec
;
367 * round and scale to 100's
369 psecs
= (psecs
+ 5000) / 10000;
373 snprintf(timestr
, sizeof(timestr
), "%3ld:%02ld.%02ld", secs
/60,
384 if (args
== NULL
|| *args
== 0 || strcmp(args
, "+") == 0) {
386 } else if (uid_from_user(args
, &uid
) != 0) {
387 error("%s: unknown user", args
);