4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2013 Gary Mills
25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
28 * Portions Copyright 2009 Chad Mynhier
31 #include <sys/types.h>
32 #include <sys/resource.h>
33 #include <sys/loadavg.h>
36 #include <sys/vm_usage.h>
38 #include <libzonecfg.h>
65 * x86 <sys/regs.h> ERR conflicts with <curses.h> ERR. For the purposes
66 * of this file, we care about the curses.h ERR so include that last.
73 #ifndef TEXT_DOMAIN /* should be defined by cc -D */
74 #define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */
82 #define PROJECT_WIDTH 28
84 #define PSINFO_HEADER_PROC \
85 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP "
86 #define PSINFO_HEADER_PROC_LGRP \
87 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU LGRP PROCESS/NLWP "
88 #define PSINFO_HEADER_LWP \
89 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/LWPID "
90 #define PSINFO_HEADER_LWP_LGRP \
91 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU LGRP PROCESS/LWPID "
92 #define USAGE_HEADER_PROC \
93 " PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP "
94 #define USAGE_HEADER_LWP \
95 " PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/LWPID "
96 #define USER_HEADER_PROC \
97 " NPROC USERNAME SWAP RSS MEMORY TIME CPU "
98 #define USER_HEADER_LWP \
99 " NLWP USERNAME SWAP RSS MEMORY TIME CPU "
100 #define TASK_HEADER_PROC \
101 "TASKID NPROC SWAP RSS MEMORY TIME CPU PROJECT "
102 #define TASK_HEADER_LWP \
103 "TASKID NLWP SWAP RSS MEMORY TIME CPU PROJECT "
104 #define PROJECT_HEADER_PROC \
105 "PROJID NPROC SWAP RSS MEMORY TIME CPU PROJECT "
106 #define PROJECT_HEADER_LWP \
107 "PROJID NLWP SWAP RSS MEMORY TIME CPU PROJECT "
108 #define ZONE_HEADER_PROC \
109 "ZONEID NPROC SWAP RSS MEMORY TIME CPU ZONE "
110 #define ZONE_HEADER_LWP \
111 "ZONEID NLWP SWAP RSS MEMORY TIME CPU ZONE "
112 #define PSINFO_LINE \
113 "%6d %-8s %5s %5s %-6s %3s %3s %9s %3.3s%% %-.16s/%d"
114 #define PSINFO_LINE_LGRP \
115 "%6d %-8s %5s %5s %-6s %3s %3s %9s %3.3s%% %4d %-.16s/%d"
117 "%6d %-8s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s "\
118 "%3.3s %3.3s %-.12s/%d"
120 "%6d %-8s %5.5s %5.5s %3.3s%% %9s %3.3s%%"
122 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
123 #define PROJECT_LINE \
124 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
126 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
129 "Total: %d processes, %d lwps, load averages: %3.2f, %3.2f, %3.2f"
131 /* global variables */
133 static char *t_ulon
; /* termcap: start underline */
134 static char *t_uloff
; /* termcap: end underline */
135 static char *t_up
; /* termcap: cursor 1 line up */
136 static char *t_eol
; /* termcap: clear end of line */
137 static char *t_smcup
; /* termcap: cursor mvcap on */
138 static char *t_rmcup
; /* termcap: cursor mvcap off */
139 static char *t_home
; /* termcap: move cursor home */
140 static char *movecur
= NULL
; /* termcap: move up string */
141 static char *empty_string
= "\0"; /* termcap: empty string */
142 static uint_t print_movecur
= FALSE
; /* print movecur or not */
143 static int is_curses_on
= FALSE
; /* current curses state */
145 static table_t pid_tbl
= {0, 0, NULL
}; /* selected processes */
146 static table_t cpu_tbl
= {0, 0, NULL
}; /* selected processors */
147 static table_t set_tbl
= {0, 0, NULL
}; /* selected processor sets */
148 static table_t prj_tbl
= {0, 0, NULL
}; /* selected projects */
149 static table_t tsk_tbl
= {0, 0, NULL
}; /* selected tasks */
150 static table_t lgr_tbl
= {0, 0, NULL
}; /* selected lgroups */
151 static zonetbl_t zone_tbl
= {0, 0, NULL
}; /* selected zones */
152 static uidtbl_t euid_tbl
= {0, 0, NULL
}; /* selected effective users */
153 static uidtbl_t ruid_tbl
= {0, 0, NULL
}; /* selected real users */
155 static uint_t total_procs
; /* total number of procs */
156 static uint_t total_lwps
; /* total number of lwps */
157 static float total_cpu
; /* total cpu usage */
158 static float total_mem
; /* total memory usage */
160 static list_t lwps
; /* list of lwps/processes */
161 static list_t users
; /* list of users */
162 static list_t tasks
; /* list of tasks */
163 static list_t projects
; /* list of projects */
164 static list_t zones
; /* list of zones */
165 static list_t lgroups
; /* list of lgroups */
167 static volatile uint_t sigwinch
= 0;
168 static volatile uint_t sigtstp
= 0;
169 static volatile uint_t sigterm
= 0;
171 static long pagesize
;
173 /* default settings */
175 static optdesc_t opts
= {
176 5, /* interval between updates, seconds */
177 15, /* number of lines in top part */
178 5, /* number of lines in bottom part */
179 -1, /* number of iterations; infinitely */
180 OPT_PSINFO
| OPT_FULLSCREEN
| OPT_USEHOME
| OPT_TERMCAP
,
181 -1 /* sort in decreasing order */
185 * Print timestamp as decimal reprentation of time_t value (-d u was specified)
186 * or the standard date format (-d d was specified).
189 print_timestamp(void)
191 time_t t
= time(NULL
);
192 static char *fmt
= NULL
;
194 /* We only need to retrieve this once per invocation */
196 fmt
= nl_langinfo(_DATE_FMT
);
198 if (opts
.o_outpmode
& OPT_UDATE
) {
199 (void) printf("%ld", t
);
200 } else if (opts
.o_outpmode
& OPT_DDATE
) {
204 len
= strftime(dstr
, sizeof (dstr
), fmt
, localtime(&t
));
206 (void) printf("%s", dstr
);
209 (void) putchar('\n');
213 psetloadavg(long psetid
, void *ptr
)
215 double psetloadavg
[3];
216 double *loadavg
= ptr
;
218 if (pset_getloadavg((psetid_t
)psetid
, psetloadavg
, 3) != -1) {
219 *loadavg
++ += psetloadavg
[0];
220 *loadavg
++ += psetloadavg
[1];
221 *loadavg
+= psetloadavg
[2];
226 * Queries the memory virtual and rss size for each member of a list.
227 * This will override the values computed by /proc aggregation.
230 list_getsize(list_t
*list
)
233 vmusage_t
*results
, *next
;
239 size_t physmem
= sysconf(_SC_PHYS_PAGES
) * pagesize
;
242 * Determine what swap/rss results to calculate. getvmusage() will
243 * prune results returned to non-global zones automatically, so
244 * there is no need to pass different flags when calling from a
247 * Currently list_getsize() is only called with a single flag. This
248 * is because -Z, -J, -T, and -a are mutually exclusive. Regardless
249 * of this, we handle multiple flags.
251 if (opts
.o_outpmode
& OPT_USERS
) {
253 * Gather rss for all users in all zones. Treat the same
254 * uid in different zones as the same user.
256 flags
|= VMUSAGE_COL_RUSERS
;
258 } else if (opts
.o_outpmode
& OPT_TASKS
) {
259 /* Gather rss for all tasks in all zones */
260 flags
|= VMUSAGE_ALL_TASKS
;
262 } else if (opts
.o_outpmode
& OPT_PROJECTS
) {
264 * Gather rss for all projects in all zones. Treat the same
265 * projid in diffrent zones as the same project.
267 flags
|= VMUSAGE_COL_PROJECTS
;
269 } else if (opts
.o_outpmode
& OPT_ZONES
) {
270 /* Gather rss for all zones */
271 flags
|= VMUSAGE_ALL_ZONES
;
275 "Cannot determine rss flags for output options %x\n"),
280 * getvmusage() returns an array of result structures. One for
281 * each zone, project, task, or user on the system, depending on
284 * If getvmusage() fails, prstat will use the size already gathered
287 if (getvmusage(flags
, opts
.o_interval
, NULL
, &nres
) != 0)
290 results
= (vmusage_t
*)Malloc(sizeof (vmusage_t
) * nres
);
292 ret
= getvmusage(flags
, opts
.o_interval
, results
, &nres
);
295 if (errno
== EOVERFLOW
) {
296 results
= (vmusage_t
*)Realloc(results
,
297 sizeof (vmusage_t
) * nres
);
301 * Failure for some other reason. Prstat will use the size
302 * already gathered from psinfo.
307 for (id
= list
->l_head
; id
!= NULL
; id
= id
->id_next
) {
311 for (i
= 0; i
< nres
; i
++, next
++) {
313 case VMUSAGE_COL_RUSERS
:
314 if (next
->vmu_id
== id
->id_uid
)
317 case VMUSAGE_ALL_TASKS
:
318 if (next
->vmu_id
== id
->id_taskid
)
321 case VMUSAGE_COL_PROJECTS
:
322 if (next
->vmu_id
== id
->id_projid
)
325 case VMUSAGE_ALL_ZONES
:
326 if (next
->vmu_id
== id
->id_zoneid
)
331 "Unknown vmusage flags %d\n"), flags
);
335 id
->id_size
= match
->vmu_swap_all
/ 1024;
336 id
->id_rssize
= match
->vmu_rss_all
/ 1024;
337 id
->id_pctmem
= (100.0 * (float)match
->vmu_rss_all
) /
339 /* Output using data from getvmusage() */
340 id
->id_sizematch
= B_TRUE
;
343 * If no match is found, prstat will use the size already
344 * gathered from psinfo.
351 * A routine to display the contents of the list on the screen
354 list_print(list_t
*list
)
358 char usr
[4], sys
[4], trp
[4], tfl
[4];
359 char dfl
[4], lck
[4], slp
[4], lat
[4];
360 char vcx
[4], icx
[4], scl
[4], sig
[4];
361 char psize
[6], prssize
[6], pmem
[6], pcpu
[6], ptime
[12];
362 char pstate
[7], pnice
[4], ppri
[4];
363 char pname
[LOGNAME_MAX
+1];
364 char projname
[PROJNAME_MAX
+1];
365 char zonename
[ZONENAME_MAX
+1];
367 double loadavg
[3] = {0, 0, 0};
370 if (list
->l_size
== 0)
373 if (foreach_element(&set_tbl
, &loadavg
, psetloadavg
) == 0) {
375 * If processor sets aren't specified, we display system-wide
378 (void) getloadavg(loadavg
, 3);
381 if (((opts
.o_outpmode
& OPT_UDATE
) || (opts
.o_outpmode
& OPT_DDATE
)) &&
382 ((list
->l_type
== LT_LWPS
) || !(opts
.o_outpmode
& OPT_SPLIT
)))
384 if (opts
.o_outpmode
& OPT_TTY
)
385 (void) putchar('\r');
388 switch (list
->l_type
) {
390 if (opts
.o_outpmode
& OPT_LWPS
)
391 (void) printf(PROJECT_HEADER_LWP
);
393 (void) printf(PROJECT_HEADER_PROC
);
396 if (opts
.o_outpmode
& OPT_LWPS
)
397 (void) printf(TASK_HEADER_LWP
);
399 (void) printf(TASK_HEADER_PROC
);
402 if (opts
.o_outpmode
& OPT_LWPS
)
403 (void) printf(ZONE_HEADER_LWP
);
405 (void) printf(ZONE_HEADER_PROC
);
408 if (opts
.o_outpmode
& OPT_LWPS
)
409 (void) printf(USER_HEADER_LWP
);
411 (void) printf(USER_HEADER_PROC
);
414 if (opts
.o_outpmode
& OPT_LWPS
) {
415 if (opts
.o_outpmode
& OPT_PSINFO
) {
416 if (opts
.o_outpmode
& OPT_LGRP
)
417 (void) printf(PSINFO_HEADER_LWP_LGRP
);
419 (void) printf(PSINFO_HEADER_LWP
);
421 if (opts
.o_outpmode
& OPT_MSACCT
)
422 (void) printf(USAGE_HEADER_LWP
);
424 if (opts
.o_outpmode
& OPT_PSINFO
) {
425 if (opts
.o_outpmode
& OPT_LGRP
)
426 (void) printf(PSINFO_HEADER_PROC_LGRP
);
428 (void) printf(PSINFO_HEADER_PROC
);
430 if (opts
.o_outpmode
& OPT_MSACCT
)
431 (void) printf(USAGE_HEADER_PROC
);
436 (void) putp(t_uloff
);
438 (void) putchar('\n');
440 for (i
= 0; i
< list
->l_used
; i
++) {
441 switch (list
->l_type
) {
446 id
= list
->l_ptrs
[i
];
448 * CPU usage and memory usage normalization
450 if (total_cpu
>= 100)
451 cpu
= (100 * id
->id_pctcpu
) / total_cpu
;
454 if (id
->id_sizematch
== B_FALSE
&& total_mem
>= 100)
455 mem
= (100 * id
->id_pctmem
) / total_mem
;
458 if (list
->l_type
== LT_USERS
) {
459 pwd_getname(id
->id_uid
, pname
, sizeof (pname
),
460 opts
.o_outpmode
& OPT_NORESOLVE
,
461 opts
.o_outpmode
& (OPT_TERMCAP
|OPT_TRUNC
),
463 } else if (list
->l_type
== LT_ZONES
) {
464 getzonename(id
->id_zoneid
, zonename
,
466 opts
.o_outpmode
& (OPT_TERMCAP
|OPT_TRUNC
),
469 getprojname(id
->id_projid
, projname
,
471 opts
.o_outpmode
& OPT_NORESOLVE
,
472 opts
.o_outpmode
& (OPT_TERMCAP
|OPT_TRUNC
),
475 Format_size(psize
, id
->id_size
, 6);
476 Format_size(prssize
, id
->id_rssize
, 6);
477 Format_pct(pmem
, mem
, 4);
478 Format_pct(pcpu
, cpu
, 4);
479 Format_time(ptime
, id
->id_time
, 10);
480 if (opts
.o_outpmode
& OPT_TTY
)
481 (void) putchar('\r');
482 if (list
->l_type
== LT_PROJECTS
)
483 (void) printf(PROJECT_LINE
, (int)id
->id_projid
,
484 id
->id_nproc
, psize
, prssize
, pmem
, ptime
,
486 else if (list
->l_type
== LT_TASKS
)
487 (void) printf(TASK_LINE
, (int)id
->id_taskid
,
488 id
->id_nproc
, psize
, prssize
, pmem
, ptime
,
490 else if (list
->l_type
== LT_ZONES
)
491 (void) printf(ZONE_LINE
, (int)id
->id_zoneid
,
492 id
->id_nproc
, psize
, prssize
, pmem
, ptime
,
495 (void) printf(USER_LINE
, id
->id_nproc
, pname
,
496 psize
, prssize
, pmem
, ptime
, pcpu
);
498 (void) putchar('\n');
501 lwp
= list
->l_ptrs
[i
];
502 if (opts
.o_outpmode
& OPT_LWPS
)
503 lwpid
= lwp
->li_info
.pr_lwp
.pr_lwpid
;
505 lwpid
= lwp
->li_info
.pr_nlwp
+
506 lwp
->li_info
.pr_nzomb
;
507 pwd_getname(lwp
->li_info
.pr_uid
, pname
, sizeof (pname
),
508 opts
.o_outpmode
& OPT_NORESOLVE
,
509 opts
.o_outpmode
& (OPT_TERMCAP
|OPT_TRUNC
),
511 if (opts
.o_outpmode
& OPT_PSINFO
) {
512 Format_size(psize
, lwp
->li_info
.pr_size
, 6);
513 Format_size(prssize
, lwp
->li_info
.pr_rssize
, 6);
515 lwp
->li_info
.pr_lwp
.pr_sname
,
516 lwp
->li_info
.pr_lwp
.pr_onpro
, 7);
517 if (strcmp(lwp
->li_info
.pr_lwp
.pr_clname
,
519 strcmp(lwp
->li_info
.pr_lwp
.pr_clname
,
521 lwp
->li_info
.pr_lwp
.pr_sname
== 'Z')
522 (void) strcpy(pnice
, " -");
525 lwp
->li_info
.pr_lwp
.pr_nice
- NZERO
,
527 Format_num(ppri
, lwp
->li_info
.pr_lwp
.pr_pri
, 4);
529 FRC2PCT(lwp
->li_info
.pr_lwp
.pr_pctcpu
), 4);
530 if (opts
.o_outpmode
& OPT_LWPS
)
532 lwp
->li_info
.pr_lwp
.pr_time
.tv_sec
,
536 lwp
->li_info
.pr_time
.tv_sec
, 10);
537 if (opts
.o_outpmode
& OPT_TTY
)
538 (void) putchar('\r');
539 stripfname(lwp
->li_info
.pr_fname
);
540 if (opts
.o_outpmode
& OPT_LGRP
) {
541 (void) printf(PSINFO_LINE_LGRP
,
542 (int)lwp
->li_info
.pr_pid
, pname
,
543 psize
, prssize
, pstate
,
544 ppri
, pnice
, ptime
, pcpu
,
545 (int)lwp
->li_info
.pr_lwp
.pr_lgrp
,
546 lwp
->li_info
.pr_fname
, lwpid
);
548 (void) printf(PSINFO_LINE
,
549 (int)lwp
->li_info
.pr_pid
, pname
,
553 lwp
->li_info
.pr_fname
, lwpid
);
556 (void) putchar('\n');
558 if (opts
.o_outpmode
& OPT_MSACCT
) {
559 Format_pct(usr
, lwp
->li_usr
, 4);
560 Format_pct(sys
, lwp
->li_sys
, 4);
561 Format_pct(slp
, lwp
->li_slp
, 4);
562 Format_num(vcx
, lwp
->li_vcx
, 4);
563 Format_num(icx
, lwp
->li_icx
, 4);
564 Format_num(scl
, lwp
->li_scl
, 4);
565 Format_num(sig
, lwp
->li_sig
, 4);
566 Format_pct(trp
, lwp
->li_trp
, 4);
567 Format_pct(tfl
, lwp
->li_tfl
, 4);
568 Format_pct(dfl
, lwp
->li_dfl
, 4);
569 Format_pct(lck
, lwp
->li_lck
, 4);
570 Format_pct(lat
, lwp
->li_lat
, 4);
571 if (opts
.o_outpmode
& OPT_TTY
)
572 (void) putchar('\r');
573 stripfname(lwp
->li_info
.pr_fname
);
574 (void) printf(USAGE_LINE
,
575 (int)lwp
->li_info
.pr_pid
, pname
,
576 usr
, sys
, trp
, tfl
, dfl
, lck
,
577 slp
, lat
, vcx
, icx
, scl
, sig
,
578 lwp
->li_info
.pr_fname
, lwpid
);
580 (void) putchar('\n');
586 if (opts
.o_outpmode
& OPT_TTY
)
587 (void) putchar('\r');
588 if (opts
.o_outpmode
& OPT_TERMCAP
) {
589 switch (list
->l_type
) {
594 while (i
++ < opts
.o_nbottom
) {
596 (void) putchar('\n');
600 while (i
++ < opts
.o_ntop
) {
602 (void) putchar('\n');
607 if (opts
.o_outpmode
& OPT_TTY
)
608 (void) putchar('\r');
610 if ((opts
.o_outpmode
& OPT_SPLIT
) && list
->l_type
== LT_LWPS
)
613 (void) printf(TOTAL_LINE
, total_procs
, total_lwps
,
614 loadavg
[LOADAVG_1MIN
], loadavg
[LOADAVG_5MIN
],
615 loadavg
[LOADAVG_15MIN
]);
617 (void) putchar('\n');
618 if (opts
.o_outpmode
& OPT_TTY
)
619 (void) putchar('\r');
621 (void) fflush(stdout
);
625 list_add_lwp(list_t
*list
, pid_t pid
, id_t lwpid
)
629 if (list
->l_head
== NULL
) {
630 list
->l_head
= list
->l_tail
= lwp
= Zalloc(sizeof (lwp_info_t
));
632 lwp
= Zalloc(sizeof (lwp_info_t
));
633 lwp
->li_prev
= list
->l_tail
;
634 ((lwp_info_t
*)list
->l_tail
)->li_next
= lwp
;
637 lwp
->li_info
.pr_pid
= pid
;
638 lwp
->li_info
.pr_lwp
.pr_lwpid
= lwpid
;
639 lwpid_add(lwp
, pid
, lwpid
);
645 list_remove_lwp(list_t
*list
, lwp_info_t
*lwp
)
648 lwp
->li_prev
->li_next
= lwp
->li_next
;
650 list
->l_head
= lwp
->li_next
; /* removing the head */
652 lwp
->li_next
->li_prev
= lwp
->li_prev
;
654 list
->l_tail
= lwp
->li_prev
; /* removing the tail */
655 lwpid_del(lwp
->li_info
.pr_pid
, lwp
->li_info
.pr_lwp
.pr_lwpid
);
656 if (lwpid_pidcheck(lwp
->li_info
.pr_pid
) == 0)
657 fds_rm(lwp
->li_info
.pr_pid
);
663 list_clear(list_t
*list
)
665 if (list
->l_type
== LT_LWPS
) {
666 lwp_info_t
*lwp
= list
->l_tail
;
673 list_remove_lwp(&lwps
, lwp_tmp
);
676 id_info_t
*id
= list
->l_head
;
680 nextid
= id
->id_next
;
685 list
->l_head
= list
->l_tail
= NULL
;
690 list_update(list_t
*list
, lwp_info_t
*lwp
)
694 if (list
->l_head
== NULL
) { /* first element */
695 list
->l_head
= list
->l_tail
= id
= Zalloc(sizeof (id_info_t
));
699 for (id
= list
->l_head
; id
; id
= id
->id_next
) {
700 if ((list
->l_type
== LT_USERS
) &&
701 (id
->id_uid
!= lwp
->li_info
.pr_uid
))
703 if ((list
->l_type
== LT_TASKS
) &&
704 (id
->id_taskid
!= lwp
->li_info
.pr_taskid
))
706 if ((list
->l_type
== LT_PROJECTS
) &&
707 (id
->id_projid
!= lwp
->li_info
.pr_projid
))
709 if ((list
->l_type
== LT_ZONES
) &&
710 (id
->id_zoneid
!= lwp
->li_info
.pr_zoneid
))
712 if ((list
->l_type
== LT_LGRPS
) &&
713 (id
->id_lgroup
!= lwp
->li_info
.pr_lwp
.pr_lgrp
))
716 id
->id_taskid
= lwp
->li_info
.pr_taskid
;
717 id
->id_projid
= lwp
->li_info
.pr_projid
;
718 id
->id_zoneid
= lwp
->li_info
.pr_zoneid
;
719 id
->id_lgroup
= lwp
->li_info
.pr_lwp
.pr_lgrp
;
721 if (lwp
->li_flags
& LWP_REPRESENT
) {
722 id
->id_size
+= lwp
->li_info
.pr_size
;
723 id
->id_rssize
+= lwp
->li_info
.pr_rssize
;
725 id
->id_pctcpu
+= FRC2PCT(lwp
->li_info
.pr_lwp
.pr_pctcpu
);
726 if (opts
.o_outpmode
& OPT_LWPS
)
727 id
->id_time
+= TIME2SEC(lwp
->li_info
.pr_lwp
.pr_time
);
729 id
->id_time
+= TIME2SEC(lwp
->li_info
.pr_time
);
730 id
->id_pctmem
+= FRC2PCT(lwp
->li_info
.pr_pctmem
);
731 id
->id_key
+= lwp
->li_key
;
732 total_cpu
+= FRC2PCT(lwp
->li_info
.pr_lwp
.pr_pctcpu
);
733 total_mem
+= FRC2PCT(lwp
->li_info
.pr_pctmem
);
738 id
->id_next
= Zalloc(sizeof (id_info_t
));
739 id
->id_next
->id_prev
= list
->l_tail
;
740 id
->id_next
->id_next
= NULL
;
741 list
->l_tail
= id
->id_next
;
744 id
->id_uid
= lwp
->li_info
.pr_uid
;
745 id
->id_projid
= lwp
->li_info
.pr_projid
;
746 id
->id_taskid
= lwp
->li_info
.pr_taskid
;
747 id
->id_zoneid
= lwp
->li_info
.pr_zoneid
;
748 id
->id_lgroup
= lwp
->li_info
.pr_lwp
.pr_lgrp
;
750 id
->id_sizematch
= B_FALSE
;
751 if (lwp
->li_flags
& LWP_REPRESENT
) {
752 id
->id_size
= lwp
->li_info
.pr_size
;
753 id
->id_rssize
= lwp
->li_info
.pr_rssize
;
755 id
->id_pctcpu
= FRC2PCT(lwp
->li_info
.pr_lwp
.pr_pctcpu
);
756 if (opts
.o_outpmode
& OPT_LWPS
)
757 id
->id_time
= TIME2SEC(lwp
->li_info
.pr_lwp
.pr_time
);
759 id
->id_time
= TIME2SEC(lwp
->li_info
.pr_time
);
760 id
->id_pctmem
= FRC2PCT(lwp
->li_info
.pr_pctmem
);
761 id
->id_key
= lwp
->li_key
;
762 total_cpu
+= id
->id_pctcpu
;
763 total_mem
+= id
->id_pctmem
;
768 lwp_update(lwp_info_t
*lwp
, pid_t pid
, id_t lwpid
, struct prusage
*usage
)
772 if (!lwpid_is_active(pid
, lwpid
)) {
774 * If we are reading cpu times for the first time then
775 * calculate average cpu times based on whole process
778 (void) memcpy(&lwp
->li_usage
, usage
, sizeof (prusage_t
));
779 period
= TIME2NSEC(usage
->pr_rtime
);
780 period
= period
/(float)100;
782 if (period
== 0) { /* zombie */
788 lwp
->li_usr
= TIME2NSEC(usage
->pr_utime
)/period
;
789 lwp
->li_sys
= TIME2NSEC(usage
->pr_stime
)/period
;
790 lwp
->li_slp
= TIME2NSEC(usage
->pr_slptime
)/period
;
792 lwp
->li_trp
= TIME2NSEC(usage
->pr_ttime
)/period
;
793 lwp
->li_tfl
= TIME2NSEC(usage
->pr_tftime
)/period
;
794 lwp
->li_dfl
= TIME2NSEC(usage
->pr_dftime
)/period
;
795 lwp
->li_lck
= TIME2NSEC(usage
->pr_ltime
)/period
;
796 lwp
->li_lat
= TIME2NSEC(usage
->pr_wtime
)/period
;
797 period
= (period
/ NANOSEC
)*(float)100; /* now in seconds */
798 lwp
->li_vcx
= (ulong_t
)
799 (opts
.o_interval
* (usage
->pr_vctx
/period
));
800 lwp
->li_icx
= (ulong_t
)
801 (opts
.o_interval
* (usage
->pr_ictx
/period
));
802 lwp
->li_scl
= (ulong_t
)
803 (opts
.o_interval
* (usage
->pr_sysc
/period
));
804 lwp
->li_sig
= (ulong_t
)
805 (opts
.o_interval
* (usage
->pr_sigs
/period
));
806 (void) lwpid_set_active(pid
, lwpid
);
809 * If this is not a first time we are reading a process's
810 * CPU times then recalculate CPU times based on fresh data
811 * obtained from procfs and previous CPU time usage values.
813 period
= TIME2NSEC(usage
->pr_rtime
)-
814 TIME2NSEC(lwp
->li_usage
.pr_rtime
);
815 period
= period
/(float)100;
817 if (period
== 0) { /* zombie */
823 lwp
->li_usr
= (TIME2NSEC(usage
->pr_utime
)-
824 TIME2NSEC(lwp
->li_usage
.pr_utime
))/period
;
825 lwp
->li_sys
= (TIME2NSEC(usage
->pr_stime
) -
826 TIME2NSEC(lwp
->li_usage
.pr_stime
))/period
;
827 lwp
->li_slp
= (TIME2NSEC(usage
->pr_slptime
) -
828 TIME2NSEC(lwp
->li_usage
.pr_slptime
))/period
;
830 lwp
->li_trp
= (TIME2NSEC(usage
->pr_ttime
) -
831 TIME2NSEC(lwp
->li_usage
.pr_ttime
))/period
;
832 lwp
->li_tfl
= (TIME2NSEC(usage
->pr_tftime
) -
833 TIME2NSEC(lwp
->li_usage
.pr_tftime
))/period
;
834 lwp
->li_dfl
= (TIME2NSEC(usage
->pr_dftime
) -
835 TIME2NSEC(lwp
->li_usage
.pr_dftime
))/period
;
836 lwp
->li_lck
= (TIME2NSEC(usage
->pr_ltime
) -
837 TIME2NSEC(lwp
->li_usage
.pr_ltime
))/period
;
838 lwp
->li_lat
= (TIME2NSEC(usage
->pr_wtime
) -
839 TIME2NSEC(lwp
->li_usage
.pr_wtime
))/period
;
840 lwp
->li_vcx
= usage
->pr_vctx
- lwp
->li_usage
.pr_vctx
;
841 lwp
->li_icx
= usage
->pr_ictx
- lwp
->li_usage
.pr_ictx
;
842 lwp
->li_scl
= usage
->pr_sysc
- lwp
->li_usage
.pr_sysc
;
843 lwp
->li_sig
= usage
->pr_sigs
- lwp
->li_usage
.pr_sigs
;
844 (void) memcpy(&lwp
->li_usage
, usage
, sizeof (prusage_t
));
849 read_procfile(fd_t
**fd
, char *pidstr
, char *file
, void *buf
, size_t bufsize
)
851 char procfile
[MAX_PROCFS_PATH
];
853 (void) snprintf(procfile
, MAX_PROCFS_PATH
,
854 "/proc/%s/%s", pidstr
, file
);
855 if ((*fd
= fd_open(procfile
, O_RDONLY
, *fd
)) == NULL
)
857 if (pread(fd_getfd(*fd
), buf
, bufsize
, 0) != bufsize
) {
865 add_proc(psinfo_t
*psinfo
)
869 pid_t pid
= psinfo
->pr_pid
;
871 lwpid
= psinfo
->pr_lwp
.pr_lwpid
;
872 if ((lwp
= lwpid_get(pid
, lwpid
)) == NULL
)
873 lwp
= list_add_lwp(&lwps
, pid
, lwpid
);
874 lwp
->li_flags
|= LWP_ALIVE
| LWP_REPRESENT
;
875 (void) memcpy(&lwp
->li_info
, psinfo
, sizeof (psinfo_t
));
876 lwp
->li_info
.pr_lwp
.pr_pctcpu
= lwp
->li_info
.pr_pctcpu
;
880 add_lwp(psinfo_t
*psinfo
, lwpsinfo_t
*lwpsinfo
, int flags
)
883 pid_t pid
= psinfo
->pr_pid
;
884 id_t lwpid
= lwpsinfo
->pr_lwpid
;
886 if ((lwp
= lwpid_get(pid
, lwpid
)) == NULL
)
887 lwp
= list_add_lwp(&lwps
, pid
, lwpid
);
888 lwp
->li_flags
&= ~LWP_REPRESENT
;
889 lwp
->li_flags
|= LWP_ALIVE
;
890 lwp
->li_flags
|= flags
;
891 (void) memcpy(&lwp
->li_info
, psinfo
,
892 sizeof (psinfo_t
) - sizeof (lwpsinfo_t
));
893 (void) memcpy(&lwp
->li_info
.pr_lwp
, lwpsinfo
, sizeof (lwpsinfo_t
));
897 prstat_scandir(DIR *procdir
)
913 lwpsinfo_t
*lwpsinfo
;
921 convert_zone(&zone_tbl
);
922 for (rewinddir(procdir
); (direntp
= readdir(procdir
)); ) {
923 pidstr
= direntp
->d_name
;
924 if (pidstr
[0] == '.') /* skip "." and ".." */
927 if (pid
== 0 || pid
== 2 || pid
== 3)
928 continue; /* skip sched, pageout and fsflush */
929 if (has_element(&pid_tbl
, pid
) == 0)
930 continue; /* check if we really want this pid */
931 fds
= fds_get(pid
); /* get ptr to file descriptors */
933 if (read_procfile(&fds
->fds_psinfo
, pidstr
,
934 "psinfo", &psinfo
, sizeof (psinfo_t
)) != 0)
936 if (!has_uid(&ruid_tbl
, psinfo
.pr_uid
) ||
937 !has_uid(&euid_tbl
, psinfo
.pr_euid
) ||
938 !has_element(&prj_tbl
, psinfo
.pr_projid
) ||
939 !has_element(&tsk_tbl
, psinfo
.pr_taskid
) ||
940 !has_zone(&zone_tbl
, psinfo
.pr_zoneid
)) {
941 fd_close(fds
->fds_psinfo
);
944 nlwps
= psinfo
.pr_nlwp
+ psinfo
.pr_nzomb
;
946 if (nlwps
> 1 && (opts
.o_outpmode
& (OPT_LWPS
| OPT_PSETS
))) {
949 if (read_procfile(&fds
->fds_lpsinfo
, pidstr
, "lpsinfo",
950 &header
, sizeof (prheader_t
)) != 0) {
951 fd_close(fds
->fds_psinfo
);
955 nent
= header
.pr_nent
;
956 entsz
= header
.pr_entsize
* nent
;
957 ptr
= buf
= Malloc(entsz
);
958 if (pread(fd_getfd(fds
->fds_lpsinfo
), buf
,
959 entsz
, sizeof (struct prheader
)) != entsz
) {
960 fd_close(fds
->fds_lpsinfo
);
961 fd_close(fds
->fds_psinfo
);
967 for (i
= 0; i
< nent
; i
++, ptr
+= header
.pr_entsize
) {
969 lwpsinfo
= (lwpsinfo_t
*)ptr
;
970 if (!has_element(&cpu_tbl
,
971 lwpsinfo
->pr_onpro
) ||
972 !has_element(&set_tbl
,
973 lwpsinfo
->pr_bindpset
) ||
974 !has_element(&lgr_tbl
, lwpsinfo
->pr_lgrp
))
977 if ((opts
.o_outpmode
& (OPT_PSETS
| OPT_LWPS
))
980 * If one of process's LWPs is bound
981 * to a given processor set, report the
982 * whole process. We may be doing this
983 * a few times but we'll get an accurate
984 * lwp count in return.
990 add_lwp(&psinfo
, lwpsinfo
,
993 add_lwp(&psinfo
, lwpsinfo
, 0);
999 fd_close(fds
->fds_lpsinfo
);
1000 fd_close(fds
->fds_psinfo
);
1004 if (!has_element(&cpu_tbl
, psinfo
.pr_lwp
.pr_onpro
) ||
1005 !has_element(&set_tbl
, psinfo
.pr_lwp
.pr_bindpset
) ||
1006 !has_element(&lgr_tbl
, psinfo
.pr_lwp
.pr_lgrp
)) {
1007 fd_close(fds
->fds_psinfo
);
1012 if (!(opts
.o_outpmode
& OPT_MSACCT
)) {
1014 total_lwps
+= nlwps
;
1018 * Get more information about processes from /proc/pid/usage.
1019 * If process has more than one lwp, then we may have to
1020 * also look at the /proc/pid/lusage file.
1022 if ((opts
.o_outpmode
& OPT_LWPS
) && (nlwps
> 1)) {
1023 if (read_procfile(&fds
->fds_lusage
, pidstr
, "lusage",
1024 &header
, sizeof (prheader_t
)) != 0) {
1025 fd_close(fds
->fds_lpsinfo
);
1026 fd_close(fds
->fds_psinfo
);
1029 nent
= header
.pr_nent
;
1030 entsz
= header
.pr_entsize
* nent
;
1031 buf
= Malloc(entsz
);
1032 if (pread(fd_getfd(fds
->fds_lusage
), buf
,
1033 entsz
, sizeof (struct prheader
)) != entsz
) {
1034 fd_close(fds
->fds_lusage
);
1035 fd_close(fds
->fds_lpsinfo
);
1036 fd_close(fds
->fds_psinfo
);
1040 for (i
= 1, ptr
= buf
+ header
.pr_entsize
; i
< nent
;
1041 i
++, ptr
+= header
.pr_entsize
) {
1042 /*LINTED ALIGNMENT*/
1043 lwpusage
= (prusage_t
*)ptr
;
1044 lwpid
= lwpusage
->pr_lwpid
;
1046 * New LWPs created after we read lpsinfo
1047 * will be ignored. Don't want to do
1048 * everything all over again.
1050 if ((lwp
= lwpid_get(pid
, lwpid
)) == NULL
)
1052 lwp_update(lwp
, pid
, lwpid
, lwpusage
);
1056 if (read_procfile(&fds
->fds_usage
, pidstr
, "usage",
1057 &usage
, sizeof (prusage_t
)) != 0) {
1058 fd_close(fds
->fds_lpsinfo
);
1059 fd_close(fds
->fds_psinfo
);
1062 lwpid
= psinfo
.pr_lwp
.pr_lwpid
;
1063 if ((lwp
= lwpid_get(pid
, lwpid
)) == NULL
)
1065 lwp_update(lwp
, pid
, lwpid
, &usage
);
1068 total_lwps
+= nlwps
;
1074 * This procedure removes all dead lwps from the linked list of all lwps.
1075 * It also creates linked list of ids if necessary.
1078 list_refresh(list_t
*list
)
1080 lwp_info_t
*lwp
, *lwp_next
;
1082 if (!(list
->l_type
& LT_LWPS
))
1085 for (lwp
= list
->l_head
; lwp
!= NULL
; ) {
1086 if (lwp
->li_flags
& LWP_ALIVE
) {
1088 * Process all live LWPs.
1089 * When we're done, mark them as dead.
1090 * They will be marked "alive" on the next
1091 * /proc scan if they still exist.
1093 lwp
->li_key
= list_getkeyval(list
, lwp
);
1094 if (opts
.o_outpmode
& OPT_USERS
)
1095 list_update(&users
, lwp
);
1096 if (opts
.o_outpmode
& OPT_TASKS
)
1097 list_update(&tasks
, lwp
);
1098 if (opts
.o_outpmode
& OPT_PROJECTS
)
1099 list_update(&projects
, lwp
);
1100 if (opts
.o_outpmode
& OPT_ZONES
)
1101 list_update(&zones
, lwp
);
1102 if (opts
.o_outpmode
& OPT_LGRP
)
1103 list_update(&lgroups
, lwp
);
1104 lwp
->li_flags
&= ~LWP_ALIVE
;
1108 lwp_next
= lwp
->li_next
;
1109 list_remove_lwp(&lwps
, lwp
);
1118 if ((opts
.o_outpmode
& OPT_TERMCAP
) && (is_curses_on
== FALSE
)) {
1121 (void) putp(t_smcup
);
1122 is_curses_on
= TRUE
;
1129 if ((is_curses_on
== TRUE
) && (opts
.o_outpmode
& OPT_TERMCAP
)) {
1130 (void) putp(t_rmcup
);
1132 is_curses_on
= FALSE
;
1134 (void) fflush(stdout
);
1143 if (ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &ws
) != -1) {
1147 if (envp
= getenv("LINES")) {
1148 if ((n
= Atoi(envp
)) > 0) {
1149 opts
.o_outpmode
&= ~OPT_USEHOME
;
1160 if ((opts
.o_outpmode
& OPT_FULLSCREEN
) &&
1161 (opts
.o_outpmode
& OPT_USEHOME
)) {
1165 if (opts
.o_outpmode
& OPT_SPLIT
) {
1166 if (opts
.o_ntop
== 0)
1167 n
= opts
.o_nbottom
+ 1;
1169 n
= opts
.o_ntop
+ opts
.o_nbottom
+ 2;
1171 if (opts
.o_outpmode
& OPT_USERS
)
1172 n
= opts
.o_nbottom
+ 1;
1174 n
= opts
.o_ntop
+ 1;
1176 if (((opts
.o_outpmode
& OPT_UDATE
) || (opts
.o_outpmode
& OPT_DDATE
)))
1179 if (movecur
!= NULL
&& movecur
!= empty_string
&& movecur
!= t_home
)
1181 movecur
= Zalloc(strlen(t_up
) * (n
+ 5));
1182 for (i
= 0; i
<= n
; i
++)
1183 (void) strcat(movecur
, t_up
);
1189 static int oldn
= 0;
1192 if (opts
.o_outpmode
& OPT_FULLSCREEN
) {
1198 opts
.o_outpmode
&= ~OPT_USEHOME
;
1199 setmovecur(); /* set default window size */
1202 n
= n
- 3; /* minus header, total and cursor lines */
1203 if ((opts
.o_outpmode
& OPT_UDATE
) ||
1204 (opts
.o_outpmode
& OPT_DDATE
))
1205 n
--; /* minus timestamp */
1207 Die(gettext("window is too small (try -n)\n"));
1208 if (opts
.o_outpmode
& OPT_SPLIT
) {
1210 Die(gettext("window is too small (try -n)\n"));
1212 opts
.o_ntop
= (n
/ 4) * 3;
1213 opts
.o_nbottom
= n
- 1 - opts
.o_ntop
;
1216 if (opts
.o_outpmode
& OPT_USERS
)
1230 if (setupterm(NULL
, STDIN_FILENO
, &err
) == ERR
) {
1233 Warn(gettext("failed to load terminal info, "
1234 "defaulting to -c option\n"));
1237 Warn(gettext("terminfo database not found, "
1238 "defaulting to -c option\n"));
1241 Warn(gettext("failed to initialize terminal, "
1242 "defaulting to -c option\n"));
1244 opts
.o_outpmode
&= ~OPT_TERMCAP
;
1245 t_up
= t_eol
= t_smcup
= t_rmcup
= movecur
= empty_string
;
1246 t_ulon
= t_uloff
= empty_string
;
1249 t_ulon
= tigetstr("smul");
1250 t_uloff
= tigetstr("rmul");
1251 t_up
= tigetstr("cuu1");
1252 t_eol
= tigetstr("el");
1253 t_smcup
= tigetstr("smcup");
1254 t_rmcup
= tigetstr("rmcup");
1255 t_home
= tigetstr("home");
1256 if ((t_up
== (char *)-1) || (t_eol
== (char *)-1) ||
1257 (t_smcup
== (char *)-1) || (t_rmcup
== (char *)-1)) {
1258 opts
.o_outpmode
&= ~OPT_TERMCAP
;
1259 t_up
= t_eol
= t_smcup
= t_rmcup
= movecur
= empty_string
;
1262 if (t_up
== NULL
|| t_eol
== NULL
) {
1263 opts
.o_outpmode
&= ~OPT_TERMCAP
;
1264 t_eol
= t_up
= movecur
= empty_string
;
1267 if (t_ulon
== (char *)-1 || t_uloff
== (char *)-1 ||
1268 t_ulon
== NULL
|| t_uloff
== NULL
) {
1269 t_ulon
= t_uloff
= empty_string
; /* can live without it */
1271 if (t_smcup
== NULL
|| t_rmcup
== NULL
)
1272 t_smcup
= t_rmcup
= empty_string
;
1273 if (t_home
== (char *)-1 || t_home
== NULL
) {
1274 opts
.o_outpmode
&= ~OPT_USEHOME
;
1275 t_home
= empty_string
;
1280 sig_handler(int sig
)
1283 case SIGTSTP
: sigtstp
= 1;
1285 case SIGWINCH
: sigwinch
= 1;
1288 case SIGTERM
: sigterm
= 1;
1296 (void) signal(SIGTSTP
, sig_handler
);
1297 (void) signal(SIGINT
, sig_handler
);
1298 (void) signal(SIGTERM
, sig_handler
);
1299 if (opts
.o_outpmode
& OPT_FULLSCREEN
)
1300 (void) signal(SIGWINCH
, sig_handler
);
1304 fill_table(table_t
*table
, char *arg
, char option
)
1306 char *p
= strtok(arg
, ", ");
1309 Die(gettext("invalid argument for -%c\n"), option
);
1311 add_element(table
, (long)Atoi(p
));
1312 while (p
= strtok(NULL
, ", "))
1313 add_element(table
, (long)Atoi(p
));
1317 fill_prj_table(char *arg
)
1320 char *p
= strtok(arg
, ", ");
1323 Die(gettext("invalid argument for -j\n"));
1325 if ((projid
= getprojidbyname(p
)) == -1)
1327 add_element(&prj_tbl
, (long)projid
);
1329 while (p
= strtok(NULL
, ", ")) {
1330 if ((projid
= getprojidbyname(p
)) == -1)
1332 add_element(&prj_tbl
, (long)projid
);
1337 fill_set_table(char *arg
)
1339 char *p
= strtok(arg
, ", ");
1343 Die(gettext("invalid argument for -C\n"));
1345 if ((id
= Atoi(p
)) == 0)
1347 add_element(&set_tbl
, id
);
1348 while (p
= strtok(NULL
, ", ")) {
1349 if ((id
= Atoi(p
)) == 0)
1351 if (!has_element(&set_tbl
, id
))
1352 add_element(&set_tbl
, id
);
1363 list_clear(&projects
);
1370 main(int argc
, char **argv
)
1374 char *sortk
= "cpu"; /* default sort key */
1377 struct pollfd pollset
;
1380 (void) setlocale(LC_ALL
, "");
1381 (void) textdomain(TEXT_DOMAIN
);
1384 fd_init(Setrlimit());
1386 pagesize
= sysconf(_SC_PAGESIZE
);
1388 while ((opt
= getopt(argc
, argv
,
1389 "vcd:HmarRLtu:U:n:p:C:P:h:s:S:j:k:TJWz:Z")) != (int)EOF
) {
1392 opts
.o_outpmode
|= OPT_NORESOLVE
;
1395 opts
.o_outpmode
|= OPT_REALTIME
;
1398 opts
.o_outpmode
&= ~OPT_TERMCAP
;
1399 opts
.o_outpmode
&= ~OPT_FULLSCREEN
;
1404 opts
.o_outpmode
|= OPT_UDATE
;
1405 else if (*optarg
== 'd')
1406 opts
.o_outpmode
|= OPT_DDATE
;
1414 fill_table(&lgr_tbl
, optarg
, 'h');
1417 opts
.o_outpmode
|= OPT_LGRP
;
1421 opts
.o_outpmode
&= ~OPT_PSINFO
;
1422 opts
.o_outpmode
|= OPT_MSACCT
;
1425 opts
.o_outpmode
&= ~OPT_PSINFO
;
1426 opts
.o_outpmode
|= OPT_USERS
;
1429 opts
.o_outpmode
|= OPT_SPLIT
| OPT_USERS
;
1432 opts
.o_outpmode
|= OPT_SPLIT
| OPT_TASKS
;
1435 opts
.o_outpmode
|= OPT_SPLIT
| OPT_PROJECTS
;
1438 if ((p
= strtok(optarg
, ",")) == NULL
)
1439 Die(gettext("invalid argument for -n\n"));
1440 opts
.o_ntop
= Atoi(p
);
1441 if (p
= strtok(NULL
, ","))
1442 opts
.o_nbottom
= Atoi(p
);
1443 else if (opts
.o_ntop
== 0)
1445 opts
.o_outpmode
&= ~OPT_FULLSCREEN
;
1448 opts
.o_sortorder
= -1;
1452 opts
.o_sortorder
= 1;
1456 if ((p
= strtok(optarg
, ", ")) == NULL
)
1457 Die(gettext("invalid argument for -u\n"));
1458 add_uid(&euid_tbl
, p
);
1459 while (p
= strtok(NULL
, ", "))
1460 add_uid(&euid_tbl
, p
);
1463 if ((p
= strtok(optarg
, ", ")) == NULL
)
1464 Die(gettext("invalid argument for -U\n"));
1465 add_uid(&ruid_tbl
, p
);
1466 while (p
= strtok(NULL
, ", "))
1467 add_uid(&ruid_tbl
, p
);
1470 fill_table(&pid_tbl
, optarg
, 'p');
1473 fill_set_table(optarg
);
1474 opts
.o_outpmode
|= OPT_PSETS
;
1477 fill_table(&cpu_tbl
, optarg
, 'P');
1480 fill_table(&tsk_tbl
, optarg
, 'k');
1483 fill_prj_table(optarg
);
1486 opts
.o_outpmode
|= OPT_LWPS
;
1489 opts
.o_outpmode
|= OPT_TRUNC
;
1492 if ((p
= strtok(optarg
, ", ")) == NULL
)
1493 Die(gettext("invalid argument for -z\n"));
1494 add_zone(&zone_tbl
, p
);
1495 while (p
= strtok(NULL
, ", "))
1496 add_zone(&zone_tbl
, p
);
1499 opts
.o_outpmode
|= OPT_SPLIT
| OPT_ZONES
;
1506 (void) atexit(Exit
);
1507 if ((opts
.o_outpmode
& OPT_USERS
) &&
1508 !(opts
.o_outpmode
& OPT_SPLIT
))
1509 opts
.o_nbottom
= opts
.o_ntop
;
1510 if (!(opts
.o_outpmode
& OPT_SPLIT
) && opts
.o_ntop
== 0)
1511 Die(gettext("invalid argument for -n\n"));
1512 if (opts
.o_nbottom
== 0)
1513 Die(gettext("invalid argument for -n\n"));
1514 if (!(opts
.o_outpmode
& OPT_SPLIT
) && (opts
.o_outpmode
& OPT_USERS
) &&
1515 ((opts
.o_outpmode
& (OPT_PSINFO
| OPT_MSACCT
))))
1516 Die(gettext("-t option cannot be used with -v or -m\n"));
1518 if ((opts
.o_outpmode
& OPT_SPLIT
) && (opts
.o_outpmode
& OPT_USERS
) &&
1519 !((opts
.o_outpmode
& (OPT_PSINFO
| OPT_MSACCT
))))
1520 Die(gettext("-t option cannot be used with "
1521 "-a, -J, -T or -Z\n"));
1523 if ((opts
.o_outpmode
& OPT_USERS
) &&
1524 (opts
.o_outpmode
& (OPT_TASKS
| OPT_PROJECTS
| OPT_ZONES
)))
1525 Die(gettext("-a option cannot be used with "
1526 "-t, -J, -T or -Z\n"));
1528 if (((opts
.o_outpmode
& OPT_TASKS
) &&
1529 (opts
.o_outpmode
& (OPT_PROJECTS
|OPT_ZONES
))) ||
1530 ((opts
.o_outpmode
& OPT_PROJECTS
) &&
1531 (opts
.o_outpmode
& (OPT_TASKS
|OPT_ZONES
)))) {
1533 "-J, -T and -Z options are mutually exclusive\n"));
1537 * There is not enough space to combine microstate information and
1538 * lgroup information and still fit in 80-column output.
1540 if ((opts
.o_outpmode
& OPT_LGRP
) && (opts
.o_outpmode
& OPT_MSACCT
)) {
1541 Die(gettext("-H and -m options are mutually exclusive\n"));
1545 opts
.o_interval
= Atoi(argv
[optind
++]);
1547 opts
.o_count
= Atoi(argv
[optind
++]);
1548 if (opts
.o_count
== 0)
1549 Die(gettext("invalid counter value\n"));
1552 if (opts
.o_outpmode
& OPT_REALTIME
)
1554 if (isatty(STDOUT_FILENO
) == 1 && isatty(STDIN_FILENO
))
1555 opts
.o_outpmode
|= OPT_TTY
; /* interactive */
1556 if (!(opts
.o_outpmode
& OPT_TTY
)) {
1557 opts
.o_outpmode
&= ~OPT_TERMCAP
; /* no termcap for pipes */
1558 opts
.o_outpmode
&= ~OPT_FULLSCREEN
;
1560 if (opts
.o_outpmode
& OPT_TERMCAP
)
1561 ldtermcap(); /* can turn OPT_TERMCAP off */
1562 if (opts
.o_outpmode
& OPT_TERMCAP
)
1564 list_alloc(&lwps
, opts
.o_ntop
);
1565 list_alloc(&users
, opts
.o_nbottom
);
1566 list_alloc(&tasks
, opts
.o_nbottom
);
1567 list_alloc(&projects
, opts
.o_nbottom
);
1568 list_alloc(&zones
, opts
.o_nbottom
);
1569 list_alloc(&lgroups
, opts
.o_nbottom
);
1570 list_setkeyfunc(sortk
, &opts
, &lwps
, LT_LWPS
);
1571 list_setkeyfunc(NULL
, &opts
, &users
, LT_USERS
);
1572 list_setkeyfunc(NULL
, &opts
, &tasks
, LT_TASKS
);
1573 list_setkeyfunc(NULL
, &opts
, &projects
, LT_PROJECTS
);
1574 list_setkeyfunc(NULL
, &opts
, &zones
, LT_ZONES
);
1575 list_setkeyfunc(NULL
, &opts
, &lgroups
, LT_LGRPS
);
1576 if (opts
.o_outpmode
& OPT_TERMCAP
)
1578 if ((procdir
= opendir("/proc")) == NULL
)
1579 Die(gettext("cannot open /proc directory\n"));
1580 if (opts
.o_outpmode
& OPT_TTY
) {
1581 (void) printf(gettext("Please wait...\r"));
1582 if (!(opts
.o_outpmode
& OPT_TERMCAP
))
1583 (void) putchar('\n');
1584 (void) fflush(stdout
);
1587 pollset
.fd
= STDIN_FILENO
;
1588 pollset
.events
= POLLIN
;
1589 timeout
= opts
.o_interval
* MILLISEC
;
1599 (void) signal(SIGTSTP
, SIG_DFL
);
1600 (void) kill(0, SIGTSTP
);
1602 * prstat stops here until it receives SIGCONT signal.
1605 (void) signal(SIGTSTP
, sig_handler
);
1607 print_movecur
= FALSE
;
1608 if (opts
.o_outpmode
& OPT_FULLSCREEN
)
1611 if (sigwinch
== 1) {
1612 if (setsize() == 1) {
1616 list_free(&projects
);
1618 list_alloc(&lwps
, opts
.o_ntop
);
1619 list_alloc(&users
, opts
.o_nbottom
);
1620 list_alloc(&tasks
, opts
.o_nbottom
);
1621 list_alloc(&projects
, opts
.o_nbottom
);
1622 list_alloc(&zones
, opts
.o_nbottom
);
1625 (void) signal(SIGWINCH
, sig_handler
);
1627 prstat_scandir(procdir
);
1628 list_refresh(&lwps
);
1630 (void) putp(movecur
);
1631 print_movecur
= TRUE
;
1632 if ((opts
.o_outpmode
& OPT_PSINFO
) ||
1633 (opts
.o_outpmode
& OPT_MSACCT
)) {
1637 if (opts
.o_outpmode
& OPT_USERS
) {
1638 list_getsize(&users
);
1643 if (opts
.o_outpmode
& OPT_TASKS
) {
1644 list_getsize(&tasks
);
1649 if (opts
.o_outpmode
& OPT_PROJECTS
) {
1650 list_getsize(&projects
);
1651 list_sort(&projects
);
1652 list_print(&projects
);
1653 list_clear(&projects
);
1655 if (opts
.o_outpmode
& OPT_ZONES
) {
1656 list_getsize(&zones
);
1661 if (opts
.o_count
== 1)
1664 * If poll() returns -1 and sets errno to EINTR here because
1665 * the process received a signal, it is Ok to abort this
1666 * timeout and loop around because we check the signals at the
1669 if (opts
.o_outpmode
& OPT_TTY
) {
1670 if (poll(&pollset
, (nfds_t
)1, timeout
) > 0) {
1671 if (read(STDIN_FILENO
, &key
, 1) == 1) {
1672 if (tolower(key
) == 'q')
1677 (void) sleep(opts
.o_interval
);
1679 } while (opts
.o_count
== (-1) || --opts
.o_count
);
1681 if (opts
.o_outpmode
& OPT_TTY
)
1682 (void) putchar('\r');