9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2013 Gary Mills
24 *
25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 *
28 * Portions Copyright 2009 Chad Mynhier
29 */
30
31 #include <sys/types.h>
32 #include <sys/resource.h>
33 #include <sys/loadavg.h>
34 #include <sys/time.h>
35 #include <sys/pset.h>
36 #include <sys/vm_usage.h>
37 #include <zone.h>
38 #include <libzonecfg.h>
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <dirent.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <poll.h>
47 #include <ctype.h>
48 #include <fcntl.h>
69 #if defined(ERR)
70 #undef ERR
71 #endif
72
73 #ifndef TEXT_DOMAIN /* should be defined by cc -D */
74 #define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */
75 #endif
76
77 #include <curses.h>
78 #include <term.h>
79
80 #define LOGIN_WIDTH 8
81 #define ZONE_WIDTH 28
82 #define PROJECT_WIDTH 28
83
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"
116 #define USAGE_LINE \
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"
119 #define USER_LINE \
120 "%6d %-8s %5.5s %5.5s %3.3s%% %9s %3.3s%%"
121 #define TASK_LINE \
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"
125 #define ZONE_LINE \
126 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
127
128 #define TOTAL_LINE \
129 "Total: %d processes, %d lwps, load averages: %3.2f, %3.2f, %3.2f"
130
131 /* global variables */
132
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 */
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 */
159
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 */
166
167 static volatile uint_t sigwinch = 0;
168 static volatile uint_t sigtstp = 0;
169 static volatile uint_t sigterm = 0;
170
171 static long pagesize;
172
173 /* default settings */
174
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 */
182 };
183
184 /*
185 * Print timestamp as decimal reprentation of time_t value (-d u was specified)
186 * or the standard date format (-d d was specified).
187 */
188 static void
189 print_timestamp(void)
190 {
191 time_t t = time(NULL);
192 static char *fmt = NULL;
193
194 /* We only need to retrieve this once per invocation */
195 if (fmt == NULL)
344 * gathered from psinfo.
345 */
346 }
347 free(results);
348 }
349
350 /*
351 * A routine to display the contents of the list on the screen
352 */
353 static void
354 list_print(list_t *list)
355 {
356 lwp_info_t *lwp;
357 id_info_t *id;
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];
366 float cpu, mem;
367 double loadavg[3] = {0, 0, 0};
368 int i, lwpid;
369
370 if (list->l_size == 0)
371 return;
372
373 if (foreach_element(&set_tbl, &loadavg, psetloadavg) == 0) {
374 /*
375 * If processor sets aren't specified, we display system-wide
376 * load averages.
377 */
378 (void) getloadavg(loadavg, 3);
379 }
380
381 if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)) &&
382 ((list->l_type == LT_LWPS) || !(opts.o_outpmode & OPT_SPLIT)))
383 print_timestamp();
384 if (opts.o_outpmode & OPT_TTY)
385 (void) putchar('\r');
386 (void) putp(t_ulon);
387
388 switch (list->l_type) {
389 case LT_PROJECTS:
390 if (opts.o_outpmode & OPT_LWPS)
391 (void) printf(PROJECT_HEADER_LWP);
392 else
393 (void) printf(PROJECT_HEADER_PROC);
394 break;
395 case LT_TASKS:
396 if (opts.o_outpmode & OPT_LWPS)
397 (void) printf(TASK_HEADER_LWP);
398 else
399 (void) printf(TASK_HEADER_PROC);
400 break;
401 case LT_ZONES:
402 if (opts.o_outpmode & OPT_LWPS)
403 (void) printf(ZONE_HEADER_LWP);
404 else
405 (void) printf(ZONE_HEADER_PROC);
406 break;
407 case LT_USERS:
408 if (opts.o_outpmode & OPT_LWPS)
409 (void) printf(USER_HEADER_LWP);
410 else
411 (void) printf(USER_HEADER_PROC);
412 break;
413 case LT_LWPS:
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);
418 else
419 (void) printf(PSINFO_HEADER_LWP);
420 }
421 if (opts.o_outpmode & OPT_MSACCT)
422 (void) printf(USAGE_HEADER_LWP);
423 } else {
424 if (opts.o_outpmode & OPT_PSINFO) {
425 if (opts.o_outpmode & OPT_LGRP)
426 (void) printf(PSINFO_HEADER_PROC_LGRP);
427 else
428 (void) printf(PSINFO_HEADER_PROC);
429 }
430 if (opts.o_outpmode & OPT_MSACCT)
431 (void) printf(USAGE_HEADER_PROC);
432 }
433 break;
434 }
435
436 (void) putp(t_uloff);
437 (void) putp(t_eol);
438 (void) putchar('\n');
439
440 for (i = 0; i < list->l_used; i++) {
441 switch (list->l_type) {
442 case LT_PROJECTS:
443 case LT_TASKS:
444 case LT_USERS:
445 case LT_ZONES:
446 id = list->l_ptrs[i];
447 /*
448 * CPU usage and memory usage normalization
449 */
450 if (total_cpu >= 100)
451 cpu = (100 * id->id_pctcpu) / total_cpu;
452 else
453 cpu = id->id_pctcpu;
454 if (id->id_sizematch == B_FALSE && total_mem >= 100)
455 mem = (100 * id->id_pctmem) / total_mem;
482 if (list->l_type == LT_PROJECTS)
483 (void) printf(PROJECT_LINE, (int)id->id_projid,
484 id->id_nproc, psize, prssize, pmem, ptime,
485 pcpu, projname);
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,
489 pcpu, projname);
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,
493 pcpu, zonename);
494 else
495 (void) printf(USER_LINE, id->id_nproc, pname,
496 psize, prssize, pmem, ptime, pcpu);
497 (void) putp(t_eol);
498 (void) putchar('\n');
499 break;
500 case LT_LWPS:
501 lwp = list->l_ptrs[i];
502 if (opts.o_outpmode & OPT_LWPS)
503 lwpid = lwp->li_info.pr_lwp.pr_lwpid;
504 else
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),
510 LOGIN_WIDTH);
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);
514 Format_state(pstate,
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,
518 "RT") == 0 ||
519 strcmp(lwp->li_info.pr_lwp.pr_clname,
520 "SYS") == 0 ||
521 lwp->li_info.pr_lwp.pr_sname == 'Z')
522 (void) strcpy(pnice, " -");
523 else
524 Format_num(pnice,
525 lwp->li_info.pr_lwp.pr_nice - NZERO,
526 4);
527 Format_num(ppri, lwp->li_info.pr_lwp.pr_pri, 4);
528 Format_pct(pcpu,
529 FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu), 4);
530 if (opts.o_outpmode & OPT_LWPS)
531 Format_time(ptime,
532 lwp->li_info.pr_lwp.pr_time.tv_sec,
533 10);
534 else
535 Format_time(ptime,
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);
547 } else {
548 (void) printf(PSINFO_LINE,
549 (int)lwp->li_info.pr_pid, pname,
550 psize, prssize,
551 pstate, ppri, pnice,
552 ptime, pcpu,
553 lwp->li_info.pr_fname, lwpid);
554 }
555 (void) putp(t_eol);
556 (void) putchar('\n');
557 }
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);
579 (void) putp(t_eol);
580 (void) putchar('\n');
581 }
582 break;
583 }
584 }
585
586 if (opts.o_outpmode & OPT_TTY)
587 (void) putchar('\r');
588 if (opts.o_outpmode & OPT_TERMCAP) {
589 switch (list->l_type) {
590 case LT_PROJECTS:
591 case LT_USERS:
592 case LT_TASKS:
593 case LT_ZONES:
594 while (i++ < opts.o_nbottom) {
595 (void) putp(t_eol);
596 (void) putchar('\n');
597 }
598 break;
860 }
861 return (0);
862 }
863
864 static void
865 add_proc(psinfo_t *psinfo)
866 {
867 lwp_info_t *lwp;
868 id_t lwpid;
869 pid_t pid = psinfo->pr_pid;
870
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;
877 }
878
879 static void
880 add_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, int flags)
881 {
882 lwp_info_t *lwp;
883 pid_t pid = psinfo->pr_pid;
884 id_t lwpid = lwpsinfo->pr_lwpid;
885
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));
894 }
895
896 static void
897 prstat_scandir(DIR *procdir)
898 {
899 char *pidstr;
900 pid_t pid;
901 id_t lwpid;
902 size_t entsz;
903 long nlwps, nent, i;
904 char *buf, *ptr;
905
906 fds_t *fds;
907 lwp_info_t *lwp;
908 dirent_t *direntp;
909
910 prheader_t header;
911 psinfo_t psinfo;
912 prusage_t usage;
913 lwpsinfo_t *lwpsinfo;
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;
1105 lwp = lwp->li_next;
1106
1107 } else {
1108 lwp_next = lwp->li_next;
1109 list_remove_lwp(&lwps, lwp);
1110 lwp = lwp_next;
1111 }
1112 }
1113 }
1114
1115 static void
1116 curses_on()
1117 {
1118 if ((opts.o_outpmode & OPT_TERMCAP) && (is_curses_on == FALSE)) {
1119 (void) initscr();
1120 (void) nonl();
1121 (void) putp(t_smcup);
1122 is_curses_on = TRUE;
1123 }
1124 }
1125
1126 static void
1127 curses_off()
1128 {
1129 if ((is_curses_on == TRUE) && (opts.o_outpmode & OPT_TERMCAP)) {
1130 (void) putp(t_rmcup);
1131 (void) endwin();
1132 is_curses_on = FALSE;
1133 }
1134 (void) fflush(stdout);
1135 }
1136
1137 static int
1138 nlines()
1139 {
1140 struct winsize ws;
1141 char *envp;
1142 int n;
1143 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
1144 if (ws.ws_row > 0)
1145 return (ws.ws_row);
1146 }
1147 if (envp = getenv("LINES")) {
1148 if ((n = Atoi(envp)) > 0) {
1149 opts.o_outpmode &= ~OPT_USEHOME;
1150 return (n);
1151 }
1152 }
1153 return (-1);
1154 }
1155
1156 static void
1157 setmovecur()
1158 {
1159 int i, n;
1160 if ((opts.o_outpmode & OPT_FULLSCREEN) &&
1161 (opts.o_outpmode & OPT_USEHOME)) {
1162 movecur = t_home;
1163 return;
1164 }
1165 if (opts.o_outpmode & OPT_SPLIT) {
1166 if (opts.o_ntop == 0)
1167 n = opts.o_nbottom + 1;
1168 else
1169 n = opts.o_ntop + opts.o_nbottom + 2;
1170 } else {
1171 if (opts.o_outpmode & OPT_USERS)
1172 n = opts.o_nbottom + 1;
1173 else
1174 n = opts.o_ntop + 1;
1175 }
1176 if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)))
1177 n++;
1178
1179 if (movecur != NULL && movecur != empty_string && movecur != t_home)
1180 free(movecur);
1181 movecur = Zalloc(strlen(t_up) * (n + 5));
1182 for (i = 0; i <= n; i++)
1183 (void) strcat(movecur, t_up);
1184 }
1185
1186 static int
1187 setsize()
1188 {
1189 static int oldn = 0;
1190 int n;
1191
1192 if (opts.o_outpmode & OPT_FULLSCREEN) {
1193 n = nlines();
1194 if (n == oldn)
1195 return (0);
1196 oldn = n;
1197 if (n == -1) {
1198 opts.o_outpmode &= ~OPT_USEHOME;
1199 setmovecur(); /* set default window size */
1200 return (1);
1201 }
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 */
1206 if (n < 1)
1207 Die(gettext("window is too small (try -n)\n"));
1208 if (opts.o_outpmode & OPT_SPLIT) {
1209 if (n < 8) {
1210 Die(gettext("window is too small (try -n)\n"));
1211 } else {
1212 opts.o_ntop = (n / 4) * 3;
1213 opts.o_nbottom = n - 1 - opts.o_ntop;
1214 }
1215 } else {
1216 if (opts.o_outpmode & OPT_USERS)
1217 opts.o_nbottom = n;
|
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2013 Gary Mills
24 *
25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 *
28 * Portions Copyright 2009 Chad Mynhier
29 * Copyright 2018 Joyent, Inc. All rights reserved.
30 */
31
32 #include <sys/types.h>
33 #include <sys/resource.h>
34 #include <sys/loadavg.h>
35 #include <sys/time.h>
36 #include <sys/pset.h>
37 #include <sys/vm_usage.h>
38 #include <zone.h>
39 #include <libzonecfg.h>
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <dirent.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <poll.h>
48 #include <ctype.h>
49 #include <fcntl.h>
70 #if defined(ERR)
71 #undef ERR
72 #endif
73
74 #ifndef TEXT_DOMAIN /* should be defined by cc -D */
75 #define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */
76 #endif
77
78 #include <curses.h>
79 #include <term.h>
80
81 #define LOGIN_WIDTH 8
82 #define ZONE_WIDTH 28
83 #define PROJECT_WIDTH 28
84
85 #define PSINFO_HEADER_PROC \
86 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP "
87 #define PSINFO_HEADER_PROC_LGRP \
88 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU LGRP PROCESS/NLWP "
89 #define PSINFO_HEADER_LWP \
90 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/LWP "
91 #define PSINFO_HEADER_LWP_LGRP \
92 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU LGRP PROCESS/LWP "
93 #define USAGE_HEADER_PROC \
94 " PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP "
95 #define USAGE_HEADER_LWP \
96 " PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/LWP "
97 #define USER_HEADER_PROC \
98 " NPROC USERNAME SWAP RSS MEMORY TIME CPU "
99 #define USER_HEADER_LWP \
100 " NLWP USERNAME SWAP RSS MEMORY TIME CPU "
101 #define TASK_HEADER_PROC \
102 "TASKID NPROC SWAP RSS MEMORY TIME CPU PROJECT "
103 #define TASK_HEADER_LWP \
104 "TASKID NLWP SWAP RSS MEMORY TIME CPU PROJECT "
105 #define PROJECT_HEADER_PROC \
106 "PROJID NPROC SWAP RSS MEMORY TIME CPU PROJECT "
107 #define PROJECT_HEADER_LWP \
108 "PROJID NLWP SWAP RSS MEMORY TIME CPU PROJECT "
109 #define ZONE_HEADER_PROC \
110 "ZONEID NPROC SWAP RSS MEMORY TIME CPU ZONE "
111 #define ZONE_HEADER_LWP \
112 "ZONEID NLWP SWAP RSS MEMORY TIME CPU ZONE "
113 #define PSINFO_LINE \
114 "%6d %-8s %5s %5s %-6s %3s %3s %9s %3.3s%% %s"
115 #define PSINFO_LINE_LGRP \
116 "%6d %-8s %5s %5s %-6s %3s %3s %9s %3.3s%% %4d %s"
117 #define USAGE_LINE \
118 "%6d %-8s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s "\
119 "%3.3s %3.3s %s"
120 #define USER_LINE \
121 "%6d %-8s %5.5s %5.5s %3.3s%% %9s %3.3s%%"
122 #define TASK_LINE \
123 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
124 #define PROJECT_LINE \
125 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
126 #define ZONE_LINE \
127 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
128
129 #define TOTAL_LINE \
130 "Total: %d processes, %d lwps, load averages: %3.2f, %3.2f, %3.2f"
131
132 /* global variables */
133
134 static char *t_ulon; /* termcap: start underline */
135 static char *t_uloff; /* termcap: end underline */
136 static char *t_up; /* termcap: cursor 1 line up */
137 static char *t_eol; /* termcap: clear end of line */
138 static char *t_smcup; /* termcap: cursor mvcap on */
139 static char *t_rmcup; /* termcap: cursor mvcap off */
156 static uint_t total_procs; /* total number of procs */
157 static uint_t total_lwps; /* total number of lwps */
158 static float total_cpu; /* total cpu usage */
159 static float total_mem; /* total memory usage */
160
161 static list_t lwps; /* list of lwps/processes */
162 static list_t users; /* list of users */
163 static list_t tasks; /* list of tasks */
164 static list_t projects; /* list of projects */
165 static list_t zones; /* list of zones */
166 static list_t lgroups; /* list of lgroups */
167
168 static volatile uint_t sigwinch = 0;
169 static volatile uint_t sigtstp = 0;
170 static volatile uint_t sigterm = 0;
171
172 static long pagesize;
173
174 /* default settings */
175
176 optdesc_t opts = {
177 5, /* interval between updates, seconds */
178 15, /* number of lines in top part */
179 5, /* number of lines in bottom part */
180 -1, /* number of iterations; infinitely */
181 OPT_PSINFO | OPT_FULLSCREEN | OPT_USEHOME | OPT_TERMCAP,
182 -1 /* sort in decreasing order */
183 };
184
185 /*
186 * Print timestamp as decimal reprentation of time_t value (-d u was specified)
187 * or the standard date format (-d d was specified).
188 */
189 static void
190 print_timestamp(void)
191 {
192 time_t t = time(NULL);
193 static char *fmt = NULL;
194
195 /* We only need to retrieve this once per invocation */
196 if (fmt == NULL)
345 * gathered from psinfo.
346 */
347 }
348 free(results);
349 }
350
351 /*
352 * A routine to display the contents of the list on the screen
353 */
354 static void
355 list_print(list_t *list)
356 {
357 lwp_info_t *lwp;
358 id_info_t *id;
359 char usr[4], sys[4], trp[4], tfl[4];
360 char dfl[4], lck[4], slp[4], lat[4];
361 char vcx[4], icx[4], scl[4], sig[4];
362 char psize[6], prssize[6], pmem[6], pcpu[6], ptime[12];
363 char pstate[7], pnice[4], ppri[4];
364 char pname[LOGNAME_MAX+1];
365 char name[PRFNSZ + THREAD_NAME_MAX + 2];
366 char projname[PROJNAME_MAX+1];
367 char zonename[ZONENAME_MAX+1];
368 float cpu, mem;
369 double loadavg[3] = {0, 0, 0};
370 int i, n;
371
372 if (list->l_size == 0)
373 return;
374
375 if (foreach_element(&set_tbl, &loadavg, psetloadavg) == 0) {
376 /*
377 * If processor sets aren't specified, we display system-wide
378 * load averages.
379 */
380 (void) getloadavg(loadavg, 3);
381 }
382
383 if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)) &&
384 ((list->l_type == LT_LWPS) || !(opts.o_outpmode & OPT_SPLIT)))
385 print_timestamp();
386 if (opts.o_outpmode & OPT_TTY)
387 (void) putchar('\r');
388 (void) putp(t_ulon);
389
390 n = opts.o_cols;
391 switch (list->l_type) {
392 case LT_PROJECTS:
393 if (opts.o_outpmode & OPT_LWPS)
394 n = printf(PROJECT_HEADER_LWP);
395 else
396 n = printf(PROJECT_HEADER_PROC);
397 break;
398 case LT_TASKS:
399 if (opts.o_outpmode & OPT_LWPS)
400 n = printf(TASK_HEADER_LWP);
401 else
402 n = printf(TASK_HEADER_PROC);
403 break;
404 case LT_ZONES:
405 if (opts.o_outpmode & OPT_LWPS)
406 n = printf(ZONE_HEADER_LWP);
407 else
408 n = printf(ZONE_HEADER_PROC);
409 break;
410 case LT_USERS:
411 if (opts.o_outpmode & OPT_LWPS)
412 n = printf(USER_HEADER_LWP);
413 else
414 n = printf(USER_HEADER_PROC);
415 break;
416 case LT_LWPS:
417 if (opts.o_outpmode & OPT_LWPS) {
418 if (opts.o_outpmode & OPT_PSINFO) {
419 if (opts.o_outpmode & OPT_LGRP)
420 n = printf(PSINFO_HEADER_LWP_LGRP);
421 else
422 n = printf(PSINFO_HEADER_LWP);
423 }
424 if (opts.o_outpmode & OPT_MSACCT)
425 n = printf(USAGE_HEADER_LWP);
426 } else {
427 if (opts.o_outpmode & OPT_PSINFO) {
428 if (opts.o_outpmode & OPT_LGRP)
429 n = printf(PSINFO_HEADER_PROC_LGRP);
430 else
431 n = printf(PSINFO_HEADER_PROC);
432 }
433 if (opts.o_outpmode & OPT_MSACCT)
434 n = printf(USAGE_HEADER_PROC);
435 }
436 break;
437 }
438
439 /* Pad out the header line so the underline spans the whole width */
440 if ((opts.o_outpmode & OPT_TERMCAP) && n < opts.o_cols)
441 (void) printf("%*s", (int)(opts.o_cols - n), "");
442
443 (void) putp(t_uloff);
444 (void) putp(t_eol);
445 (void) putchar('\n');
446
447 for (i = 0; i < list->l_used; i++) {
448 switch (list->l_type) {
449 case LT_PROJECTS:
450 case LT_TASKS:
451 case LT_USERS:
452 case LT_ZONES:
453 id = list->l_ptrs[i];
454 /*
455 * CPU usage and memory usage normalization
456 */
457 if (total_cpu >= 100)
458 cpu = (100 * id->id_pctcpu) / total_cpu;
459 else
460 cpu = id->id_pctcpu;
461 if (id->id_sizematch == B_FALSE && total_mem >= 100)
462 mem = (100 * id->id_pctmem) / total_mem;
489 if (list->l_type == LT_PROJECTS)
490 (void) printf(PROJECT_LINE, (int)id->id_projid,
491 id->id_nproc, psize, prssize, pmem, ptime,
492 pcpu, projname);
493 else if (list->l_type == LT_TASKS)
494 (void) printf(TASK_LINE, (int)id->id_taskid,
495 id->id_nproc, psize, prssize, pmem, ptime,
496 pcpu, projname);
497 else if (list->l_type == LT_ZONES)
498 (void) printf(ZONE_LINE, (int)id->id_zoneid,
499 id->id_nproc, psize, prssize, pmem, ptime,
500 pcpu, zonename);
501 else
502 (void) printf(USER_LINE, id->id_nproc, pname,
503 psize, prssize, pmem, ptime, pcpu);
504 (void) putp(t_eol);
505 (void) putchar('\n');
506 break;
507 case LT_LWPS:
508 lwp = list->l_ptrs[i];
509
510 format_name(lwp, name, sizeof (name));
511
512 pwd_getname(lwp->li_info.pr_uid, pname, sizeof (pname),
513 opts.o_outpmode & OPT_NORESOLVE,
514 opts.o_outpmode & (OPT_TERMCAP|OPT_TRUNC),
515 LOGIN_WIDTH);
516
517 if (opts.o_outpmode & OPT_PSINFO) {
518 Format_size(psize, lwp->li_info.pr_size, 6);
519 Format_size(prssize, lwp->li_info.pr_rssize, 6);
520 Format_state(pstate,
521 lwp->li_info.pr_lwp.pr_sname,
522 lwp->li_info.pr_lwp.pr_onpro, 7);
523 if (strcmp(lwp->li_info.pr_lwp.pr_clname,
524 "RT") == 0 ||
525 strcmp(lwp->li_info.pr_lwp.pr_clname,
526 "SYS") == 0 ||
527 lwp->li_info.pr_lwp.pr_sname == 'Z')
528 (void) strcpy(pnice, " -");
529 else
530 Format_num(pnice,
531 lwp->li_info.pr_lwp.pr_nice - NZERO,
532 4);
533 Format_num(ppri, lwp->li_info.pr_lwp.pr_pri, 4);
534 Format_pct(pcpu,
535 FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu), 4);
536 if (opts.o_outpmode & OPT_LWPS)
537 Format_time(ptime,
538 lwp->li_info.pr_lwp.pr_time.tv_sec,
539 10);
540 else
541 Format_time(ptime,
542 lwp->li_info.pr_time.tv_sec, 10);
543 if (opts.o_outpmode & OPT_TTY)
544 (void) putchar('\r');
545 if (opts.o_outpmode & OPT_LGRP) {
546 (void) printf(PSINFO_LINE_LGRP,
547 (int)lwp->li_info.pr_pid, pname,
548 psize, prssize, pstate,
549 ppri, pnice, ptime, pcpu,
550 lwp->li_info.pr_lwp.pr_lgrp, name);
551 } else {
552 (void) printf(PSINFO_LINE,
553 (int)lwp->li_info.pr_pid, pname,
554 psize, prssize, pstate, ppri, pnice,
555 ptime, pcpu, name);
556 }
557 (void) putp(t_eol);
558 (void) putchar('\n');
559 }
560 if (opts.o_outpmode & OPT_MSACCT) {
561 Format_pct(usr, lwp->li_usr, 4);
562 Format_pct(sys, lwp->li_sys, 4);
563 Format_pct(slp, lwp->li_slp, 4);
564 Format_num(vcx, lwp->li_vcx, 4);
565 Format_num(icx, lwp->li_icx, 4);
566 Format_num(scl, lwp->li_scl, 4);
567 Format_num(sig, lwp->li_sig, 4);
568 Format_pct(trp, lwp->li_trp, 4);
569 Format_pct(tfl, lwp->li_tfl, 4);
570 Format_pct(dfl, lwp->li_dfl, 4);
571 Format_pct(lck, lwp->li_lck, 4);
572 Format_pct(lat, lwp->li_lat, 4);
573 if (opts.o_outpmode & OPT_TTY)
574 (void) putchar('\r');
575 (void) printf(USAGE_LINE,
576 (int)lwp->li_info.pr_pid, pname,
577 usr, sys, trp, tfl, dfl, lck,
578 slp, lat, vcx, icx, scl, sig,
579 name);
580 (void) putp(t_eol);
581 (void) putchar('\n');
582 }
583 break;
584 }
585 }
586
587 if (opts.o_outpmode & OPT_TTY)
588 (void) putchar('\r');
589 if (opts.o_outpmode & OPT_TERMCAP) {
590 switch (list->l_type) {
591 case LT_PROJECTS:
592 case LT_USERS:
593 case LT_TASKS:
594 case LT_ZONES:
595 while (i++ < opts.o_nbottom) {
596 (void) putp(t_eol);
597 (void) putchar('\n');
598 }
599 break;
861 }
862 return (0);
863 }
864
865 static void
866 add_proc(psinfo_t *psinfo)
867 {
868 lwp_info_t *lwp;
869 id_t lwpid;
870 pid_t pid = psinfo->pr_pid;
871
872 lwpid = psinfo->pr_lwp.pr_lwpid;
873 if ((lwp = lwpid_get(pid, lwpid)) == NULL)
874 lwp = list_add_lwp(&lwps, pid, lwpid);
875 lwp->li_flags |= LWP_ALIVE | LWP_REPRESENT;
876 (void) memcpy(&lwp->li_info, psinfo, sizeof (psinfo_t));
877 lwp->li_info.pr_lwp.pr_pctcpu = lwp->li_info.pr_pctcpu;
878 }
879
880 static void
881 get_lwpname(pid_t pid, id_t lwpid, char *buf, size_t bufsize)
882 {
883 char *path = NULL;
884 int fd;
885
886 buf[0] = '\0';
887
888 if (asprintf(&path, "/proc/%d/lwp/%d/lwpname",
889 (int)pid, (int)lwpid) == -1)
890 return;
891
892 if ((fd = open(path, O_RDONLY)) != -1) {
893 (void) read(fd, buf, bufsize);
894 buf[bufsize - 1] = '\0';
895 (void) close(fd);
896 }
897
898 free(path);
899 }
900
901 static void
902 add_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, int flags)
903 {
904 lwp_info_t *lwp;
905 pid_t pid = psinfo->pr_pid;
906 id_t lwpid = lwpsinfo->pr_lwpid;
907
908 if ((lwp = lwpid_get(pid, lwpid)) == NULL)
909 lwp = list_add_lwp(&lwps, pid, lwpid);
910 lwp->li_flags &= ~LWP_REPRESENT;
911 lwp->li_flags |= LWP_ALIVE;
912 lwp->li_flags |= flags;
913 (void) memcpy(&lwp->li_info, psinfo,
914 sizeof (psinfo_t) - sizeof (lwpsinfo_t));
915 (void) memcpy(&lwp->li_info.pr_lwp, lwpsinfo, sizeof (lwpsinfo_t));
916 get_lwpname(pid, lwpid, lwp->li_lwpname, sizeof (lwp->li_lwpname));
917 }
918
919 static void
920 prstat_scandir(DIR *procdir)
921 {
922 char *pidstr;
923 pid_t pid;
924 id_t lwpid;
925 size_t entsz;
926 long nlwps, nent, i;
927 char *buf, *ptr;
928
929 fds_t *fds;
930 lwp_info_t *lwp;
931 dirent_t *direntp;
932
933 prheader_t header;
934 psinfo_t psinfo;
935 prusage_t usage;
936 lwpsinfo_t *lwpsinfo;
1119 if (opts.o_outpmode & OPT_TASKS)
1120 list_update(&tasks, lwp);
1121 if (opts.o_outpmode & OPT_PROJECTS)
1122 list_update(&projects, lwp);
1123 if (opts.o_outpmode & OPT_ZONES)
1124 list_update(&zones, lwp);
1125 if (opts.o_outpmode & OPT_LGRP)
1126 list_update(&lgroups, lwp);
1127 lwp->li_flags &= ~LWP_ALIVE;
1128 lwp = lwp->li_next;
1129
1130 } else {
1131 lwp_next = lwp->li_next;
1132 list_remove_lwp(&lwps, lwp);
1133 lwp = lwp_next;
1134 }
1135 }
1136 }
1137
1138 static void
1139 curses_on(void)
1140 {
1141 if ((opts.o_outpmode & OPT_TERMCAP) && (is_curses_on == FALSE)) {
1142 (void) initscr();
1143 (void) nonl();
1144 (void) putp(t_smcup);
1145 is_curses_on = TRUE;
1146 }
1147 }
1148
1149 static void
1150 curses_off(void)
1151 {
1152 if ((is_curses_on == TRUE) && (opts.o_outpmode & OPT_TERMCAP)) {
1153 (void) putp(t_rmcup);
1154 (void) endwin();
1155 is_curses_on = FALSE;
1156 }
1157 (void) fflush(stdout);
1158 }
1159
1160 static int
1161 nlines(int *linesp, int *colsp)
1162 {
1163 struct winsize ws;
1164 char *envp;
1165 int n;
1166
1167 *linesp = -1;
1168 *colsp = -1;
1169 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
1170 if (ws.ws_row > 0)
1171 *linesp = ws.ws_row;
1172 if (ws.ws_col > 0)
1173 *colsp = ws.ws_col;
1174 if (ws.ws_row > 0 && ws.ws_col > 0)
1175 return (0);
1176 }
1177
1178 if ((envp = getenv("LINES")) != NULL) {
1179 if ((n = Atoi(envp)) > 0) {
1180 opts.o_outpmode &= ~OPT_USEHOME;
1181 *linesp = n;
1182 }
1183 }
1184 if ((envp = getenv("COLUMNS")) != NULL) {
1185 if ((n = Atoi(envp)) > 0) {
1186 *colsp = n;
1187 }
1188 }
1189
1190 return ((*linesp > 0 && *colsp > 0) ? 0 : -1);
1191 }
1192
1193 static void
1194 setmovecur(void)
1195 {
1196 int i, n;
1197 if ((opts.o_outpmode & OPT_FULLSCREEN) &&
1198 (opts.o_outpmode & OPT_USEHOME)) {
1199 movecur = t_home;
1200 return;
1201 }
1202 if (opts.o_outpmode & OPT_SPLIT) {
1203 if (opts.o_ntop == 0)
1204 n = opts.o_nbottom + 1;
1205 else
1206 n = opts.o_ntop + opts.o_nbottom + 2;
1207 } else {
1208 if (opts.o_outpmode & OPT_USERS)
1209 n = opts.o_nbottom + 1;
1210 else
1211 n = opts.o_ntop + 1;
1212 }
1213 if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)))
1214 n++;
1215
1216 if (movecur != NULL && movecur != empty_string && movecur != t_home)
1217 free(movecur);
1218 movecur = Zalloc(strlen(t_up) * (n + 5));
1219 for (i = 0; i <= n; i++)
1220 (void) strcat(movecur, t_up);
1221 }
1222
1223 static int
1224 setsize(void)
1225 {
1226 static int oldn = 0;
1227 int cols, n, ret;
1228
1229 if (opts.o_outpmode & OPT_FULLSCREEN) {
1230 ret = nlines(&n, &cols);
1231 if (ret != -1)
1232 opts.o_cols = cols;
1233 if (n == oldn)
1234 return (0);
1235 oldn = n;
1236 if (ret == -1) {
1237 opts.o_outpmode &= ~OPT_USEHOME;
1238 setmovecur(); /* set default window size */
1239 return (1);
1240 }
1241 n = n - 3; /* minus header, total and cursor lines */
1242 if ((opts.o_outpmode & OPT_UDATE) ||
1243 (opts.o_outpmode & OPT_DDATE))
1244 n--; /* minus timestamp */
1245 if (n < 1)
1246 Die(gettext("window is too small (try -n)\n"));
1247 if (opts.o_outpmode & OPT_SPLIT) {
1248 if (n < 8) {
1249 Die(gettext("window is too small (try -n)\n"));
1250 } else {
1251 opts.o_ntop = (n / 4) * 3;
1252 opts.o_nbottom = n - 1 - opts.o_ntop;
1253 }
1254 } else {
1255 if (opts.o_outpmode & OPT_USERS)
1256 opts.o_nbottom = n;
|