1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/resource.h> 31 #include <sys/loadavg.h> 32 #include <sys/time.h> 33 #include <sys/pset.h> 34 #include <zone.h> 35 #include <libzonecfg.h> 36 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <dirent.h> 41 #include <string.h> 42 #include <errno.h> 43 #include <poll.h> 44 #include <ctype.h> 45 #include <fcntl.h> 46 #include <limits.h> 47 #include <signal.h> 48 #include <time.h> 49 #include <project.h> 50 51 #include <libintl.h> 52 #include <locale.h> 53 54 #include "prstat.h" 55 #include "prutil.h" 56 #include "prtable.h" 57 #include "prsort.h" 58 #include "prfile.h" 59 60 /* 61 * x86 <sys/regs.h> ERR conflicts with <curses.h> ERR. For the purposes 62 * of this file, we care about the curses.h ERR so include that last. 63 */ 64 65 #if defined(ERR) 66 #undef ERR 67 #endif 68 69 #ifndef TEXT_DOMAIN /* should be defined by cc -D */ 70 #define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */ 71 #endif 72 73 #include <curses.h> 74 #include <term.h> 75 76 #define PSINFO_HEADER_PROC \ 77 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP " 78 #define PSINFO_HEADER_LWP \ 79 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/LWPID " 80 #define USAGE_HEADER_PROC \ 81 " PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP " 82 #define USAGE_HEADER_LWP \ 83 " PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/LWPID " 84 #define USER_HEADER_PROC \ 85 " NPROC USERNAME SIZE RSS MEMORY TIME CPU " 86 #define USER_HEADER_LWP \ 87 " NLWP USERNAME SIZE RSS MEMORY TIME CPU " 88 #define TASK_HEADER_PROC \ 89 "TASKID NPROC SIZE RSS MEMORY TIME CPU PROJECT " 90 #define TASK_HEADER_LWP \ 91 "TASKID NLWP SIZE RSS MEMORY TIME CPU PROJECT " 92 #define PROJECT_HEADER_PROC \ 93 "PROJID NPROC SIZE RSS MEMORY TIME CPU PROJECT " 94 #define PROJECT_HEADER_LWP \ 95 "PROJID NLWP SIZE RSS MEMORY TIME CPU PROJECT " 96 #define ZONE_HEADER_PROC \ 97 "ZONEID NPROC SIZE RSS MEMORY TIME CPU ZONE " 98 #define ZONE_HEADER_LWP \ 99 "ZONEID NLWP SIZE RSS MEMORY TIME CPU ZONE " 100 #define PSINFO_LINE \ 101 "%6d %-8s %5s %5s %-6s %3s %3s %9s %3.3s%% %-.16s/%d" 102 #define USAGE_LINE \ 103 "%6d %-8s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s "\ 104 "%3.3s %-.12s/%d" 105 #define USER_LINE \ 106 "%6d %-8s %5.5s %5.5s %3.3s%% %9s %3.3s%%" 107 #define TASK_LINE \ 108 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s" 109 #define PROJECT_LINE \ 110 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s" 111 #define ZONE_LINE \ 112 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s" 113 114 #define TOTAL_LINE \ 115 "Total: %d processes, %d lwps, load averages: %3.2f, %3.2f, %3.2f" 116 117 /* global variables */ 118 119 static char *t_ulon; /* termcap: start underline */ 120 static char *t_uloff; /* termcap: end underline */ 121 static char *t_up; /* termcap: cursor 1 line up */ 122 static char *t_eol; /* termcap: clear end of line */ 123 static char *t_smcup; /* termcap: cursor mvcap on */ 124 static char *t_rmcup; /* termcap: cursor mvcap off */ 125 static char *t_home; /* termcap: move cursor home */ 126 static char *movecur = NULL; /* termcap: move up string */ 127 static char *empty_string = "\0"; /* termcap: empty string */ 128 static uint_t print_movecur = FALSE; /* print movecur or not */ 129 static int is_curses_on = FALSE; /* current curses state */ 130 131 static table_t pid_tbl = {0, 0, NULL}; /* selected processes */ 132 static table_t cpu_tbl = {0, 0, NULL}; /* selected processors */ 133 static table_t set_tbl = {0, 0, NULL}; /* selected processor sets */ 134 static table_t prj_tbl = {0, 0, NULL}; /* selected projects */ 135 static table_t tsk_tbl = {0, 0, NULL}; /* selected tasks */ 136 static zonetbl_t zone_tbl = {0, 0, NULL}; /* selected zones */ 137 static nametbl_t euid_tbl = {0, 0, NULL}; /* selected effective users */ 138 static nametbl_t ruid_tbl = {0, 0, NULL}; /* selected real users */ 139 140 static uint_t total_procs; /* total number of procs */ 141 static uint_t total_lwps; /* total number of lwps */ 142 static float total_cpu; /* total cpu usage */ 143 static float total_mem; /* total memory usage */ 144 145 static list_t lwps; /* list of lwps/processes */ 146 static list_t users; /* list of users */ 147 static list_t tasks; /* list of tasks */ 148 static list_t projects; /* list of projects */ 149 static list_t zones; /* list of zones */ 150 151 static volatile uint_t sigwinch = 0; 152 static volatile uint_t sigtstp = 0; 153 static volatile uint_t sigterm = 0; 154 155 /* default settings */ 156 157 static optdesc_t opts = { 158 5, /* interval between updates, seconds */ 159 15, /* number of lines in top part */ 160 5, /* number of lines in bottom part */ 161 -1, /* number of iterations; infinitely */ 162 OPT_PSINFO | OPT_FULLSCREEN | OPT_USEHOME | OPT_TERMCAP, 163 -1 /* sort in decreasing order */ 164 }; 165 166 static void 167 psetloadavg(long psetid, void *ptr) 168 { 169 double psetloadavg[3]; 170 double *loadavg = ptr; 171 172 if (pset_getloadavg((psetid_t)psetid, psetloadavg, 3) != -1) { 173 *loadavg++ += psetloadavg[0]; 174 *loadavg++ += psetloadavg[1]; 175 *loadavg += psetloadavg[2]; 176 } 177 } 178 179 /* 180 * A routine to display the contents of the list on the screen 181 */ 182 static void 183 list_print(list_t *list) 184 { 185 lwp_info_t *lwp; 186 id_info_t *id; 187 char usr[4], sys[4], trp[4], tfl[4]; 188 char dfl[4], lck[4], slp[4], lat[4]; 189 char vcx[4], icx[4], scl[4], sig[4]; 190 char psize[6], prssize[6], pmem[6], pcpu[6], ptime[12]; 191 char pstate[7], pnice[4], ppri[4]; 192 char pname[LOGNAME_MAX+1]; 193 char projname[PROJNAME_MAX+1]; 194 char zonename[ZONENAME_MAX+1]; 195 float cpu, mem; 196 double loadavg[3] = {0, 0, 0}; 197 int i, lwpid; 198 199 if (foreach_element(&set_tbl, &loadavg, psetloadavg) == 0) { 200 /* 201 * If processor sets aren't specified, we display system-wide 202 * load averages. 203 */ 204 (void) getloadavg(loadavg, 3); 205 } 206 207 if (opts.o_outpmode & OPT_TTY) 208 (void) putchar('\r'); 209 (void) putp(t_ulon); 210 211 switch (list->l_type) { 212 case LT_PROJECTS: 213 if (opts.o_outpmode & OPT_LWPS) 214 (void) printf(PROJECT_HEADER_LWP); 215 else 216 (void) printf(PROJECT_HEADER_PROC); 217 break; 218 case LT_TASKS: 219 if (opts.o_outpmode & OPT_LWPS) 220 (void) printf(TASK_HEADER_LWP); 221 else 222 (void) printf(TASK_HEADER_PROC); 223 break; 224 case LT_ZONES: 225 if (opts.o_outpmode & OPT_LWPS) 226 (void) printf(ZONE_HEADER_LWP); 227 else 228 (void) printf(ZONE_HEADER_PROC); 229 break; 230 case LT_USERS: 231 if (opts.o_outpmode & OPT_LWPS) 232 (void) printf(USER_HEADER_LWP); 233 else 234 (void) printf(USER_HEADER_PROC); 235 break; 236 case LT_LWPS: 237 if (opts.o_outpmode & OPT_LWPS) { 238 if (opts.o_outpmode & OPT_PSINFO) 239 (void) printf(PSINFO_HEADER_LWP); 240 if (opts.o_outpmode & OPT_MSACCT) 241 (void) printf(USAGE_HEADER_LWP); 242 } else { 243 if (opts.o_outpmode & OPT_PSINFO) 244 (void) printf(PSINFO_HEADER_PROC); 245 if (opts.o_outpmode & OPT_MSACCT) 246 (void) printf(USAGE_HEADER_PROC); 247 } 248 break; 249 } 250 251 (void) putp(t_uloff); 252 (void) putp(t_eol); 253 (void) putchar('\n'); 254 255 for (i = 0; i < list->l_used; i++) { 256 switch (list->l_type) { 257 case LT_PROJECTS: 258 case LT_TASKS: 259 case LT_USERS: 260 case LT_ZONES: 261 id = list->l_ptrs[i]; 262 /* 263 * CPU usage and memory usage normalization 264 */ 265 if (total_cpu >= 100) 266 cpu = (100 * id->id_pctcpu) / total_cpu; 267 else 268 cpu = id->id_pctcpu; 269 if (total_mem >= 100) 270 mem = (100 * id->id_pctmem) / total_mem; 271 else 272 mem = id->id_pctmem; 273 if (list->l_type == LT_USERS) 274 pwd_getname(id->id_uid, pname, LOGNAME_MAX + 1); 275 else if (list->l_type == LT_ZONES) 276 getzonename(id->id_zoneid, zonename, 277 ZONENAME_MAX); 278 else 279 getprojname(id->id_projid, projname, 280 PROJNAME_MAX); 281 Format_size(psize, id->id_size, 6); 282 Format_size(prssize, id->id_rssize, 6); 283 Format_pct(pmem, mem, 4); 284 Format_pct(pcpu, cpu, 4); 285 Format_time(ptime, id->id_time, 10); 286 if (opts.o_outpmode & OPT_TTY) 287 (void) putchar('\r'); 288 if (list->l_type == LT_PROJECTS) 289 (void) printf(PROJECT_LINE, (int)id->id_projid, 290 id->id_nproc, psize, prssize, pmem, ptime, 291 pcpu, projname); 292 else if (list->l_type == LT_TASKS) 293 (void) printf(TASK_LINE, (int)id->id_taskid, 294 id->id_nproc, psize, prssize, pmem, ptime, 295 pcpu, projname); 296 else if (list->l_type == LT_ZONES) 297 (void) printf(ZONE_LINE, (int)id->id_zoneid, 298 id->id_nproc, psize, prssize, pmem, ptime, 299 pcpu, zonename); 300 else 301 (void) printf(USER_LINE, id->id_nproc, pname, 302 psize, prssize, pmem, ptime, pcpu); 303 (void) putp(t_eol); 304 (void) putchar('\n'); 305 break; 306 case LT_LWPS: 307 lwp = list->l_ptrs[i]; 308 if (opts.o_outpmode & OPT_LWPS) 309 lwpid = lwp->li_info.pr_lwp.pr_lwpid; 310 else 311 lwpid = lwp->li_info.pr_nlwp + 312 lwp->li_info.pr_nzomb; 313 pwd_getname(lwp->li_info.pr_uid, pname, 314 LOGNAME_MAX + 1); 315 if (opts.o_outpmode & OPT_PSINFO) { 316 Format_size(psize, lwp->li_info.pr_size, 6); 317 Format_size(prssize, lwp->li_info.pr_rssize, 6); 318 Format_state(pstate, 319 lwp->li_info.pr_lwp.pr_sname, 320 lwp->li_info.pr_lwp.pr_onpro, 7); 321 if (strcmp(lwp->li_info.pr_lwp.pr_clname, 322 "RT") == 0 || 323 strcmp(lwp->li_info.pr_lwp.pr_clname, 324 "SYS") == 0 || 325 lwp->li_info.pr_lwp.pr_sname == 'Z') 326 (void) strcpy(pnice, " -"); 327 else 328 Format_num(pnice, 329 lwp->li_info.pr_lwp.pr_nice - NZERO, 330 4); 331 Format_num(ppri, lwp->li_info.pr_lwp.pr_pri, 4); 332 Format_pct(pcpu, 333 FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu), 4); 334 if (opts.o_outpmode & OPT_LWPS) 335 Format_time(ptime, 336 lwp->li_info.pr_lwp.pr_time.tv_sec, 337 10); 338 else 339 Format_time(ptime, 340 lwp->li_info.pr_time.tv_sec, 10); 341 if (opts.o_outpmode & OPT_TTY) 342 (void) putchar('\r'); 343 stripfname(lwp->li_info.pr_fname); 344 (void) printf(PSINFO_LINE, 345 (int)lwp->li_info.pr_pid, pname, 346 psize, prssize, pstate, ppri, pnice, 347 ptime, pcpu, lwp->li_info.pr_fname, lwpid); 348 (void) putp(t_eol); 349 (void) putchar('\n'); 350 } 351 if (opts.o_outpmode & OPT_MSACCT) { 352 Format_pct(usr, lwp->li_usr, 4); 353 Format_pct(sys, lwp->li_sys, 4); 354 Format_pct(slp, lwp->li_slp, 4); 355 Format_num(vcx, lwp->li_vcx, 4); 356 Format_num(icx, lwp->li_icx, 4); 357 Format_num(scl, lwp->li_scl, 4); 358 Format_num(sig, lwp->li_sig, 4); 359 Format_pct(trp, lwp->li_trp, 4); 360 Format_pct(tfl, lwp->li_tfl, 4); 361 Format_pct(dfl, lwp->li_dfl, 4); 362 Format_pct(lck, lwp->li_lck, 4); 363 Format_pct(lat, lwp->li_lat, 4); 364 if (opts.o_outpmode & OPT_TTY) 365 (void) putchar('\r'); 366 stripfname(lwp->li_info.pr_fname); 367 (void) printf(USAGE_LINE, 368 (int)lwp->li_info.pr_pid, pname, 369 usr, sys, trp, tfl, dfl, lck, 370 slp, lat, vcx, icx, scl, sig, 371 lwp->li_info.pr_fname, lwpid); 372 (void) putp(t_eol); 373 (void) putchar('\n'); 374 } 375 break; 376 } 377 } 378 379 if (opts.o_outpmode & OPT_TTY) 380 (void) putchar('\r'); 381 if (opts.o_outpmode & OPT_TERMCAP) { 382 switch (list->l_type) { 383 case LT_PROJECTS: 384 case LT_USERS: 385 case LT_TASKS: 386 case LT_ZONES: 387 while (i++ < opts.o_nbottom) { 388 (void) putp(t_eol); 389 (void) putchar('\n'); 390 } 391 break; 392 case LT_LWPS: 393 while (i++ < opts.o_ntop) { 394 (void) putp(t_eol); 395 (void) putchar('\n'); 396 } 397 } 398 } 399 400 if (opts.o_outpmode & OPT_TTY) 401 (void) putchar('\r'); 402 403 if ((opts.o_outpmode & OPT_SPLIT) && list->l_type == LT_LWPS) 404 return; 405 406 (void) printf(TOTAL_LINE, total_procs, total_lwps, 407 loadavg[LOADAVG_1MIN], loadavg[LOADAVG_5MIN], 408 loadavg[LOADAVG_15MIN]); 409 (void) putp(t_eol); 410 (void) putchar('\n'); 411 if (opts.o_outpmode & OPT_TTY) 412 (void) putchar('\r'); 413 (void) putp(t_eol); 414 (void) fflush(stdout); 415 } 416 417 static lwp_info_t * 418 list_add_lwp(list_t *list, pid_t pid, id_t lwpid) 419 { 420 lwp_info_t *lwp; 421 422 if (list->l_head == NULL) { 423 list->l_head = list->l_tail = lwp = Zalloc(sizeof (lwp_info_t)); 424 } else { 425 lwp = Zalloc(sizeof (lwp_info_t)); 426 lwp->li_prev = list->l_tail; 427 ((lwp_info_t *)list->l_tail)->li_next = lwp; 428 list->l_tail = lwp; 429 } 430 lwp->li_info.pr_pid = pid; 431 lwp->li_info.pr_lwp.pr_lwpid = lwpid; 432 lwpid_add(lwp, pid, lwpid); 433 list->l_count++; 434 return (lwp); 435 } 436 437 static void 438 list_remove_lwp(list_t *list, lwp_info_t *lwp) 439 { 440 if (lwp->li_prev) 441 lwp->li_prev->li_next = lwp->li_next; 442 else 443 list->l_head = lwp->li_next; /* removing the head */ 444 if (lwp->li_next) 445 lwp->li_next->li_prev = lwp->li_prev; 446 else 447 list->l_tail = lwp->li_prev; /* removing the tail */ 448 lwpid_del(lwp->li_info.pr_pid, lwp->li_info.pr_lwp.pr_lwpid); 449 if (lwpid_pidcheck(lwp->li_info.pr_pid) == 0) 450 fds_rm(lwp->li_info.pr_pid); 451 list->l_count--; 452 free(lwp); 453 } 454 455 static void 456 list_clear(list_t *list) 457 { 458 if (list->l_type == LT_LWPS) { 459 lwp_info_t *lwp = list->l_tail; 460 lwp_info_t *lwp_tmp; 461 462 fd_closeall(); 463 while (lwp) { 464 lwp_tmp = lwp; 465 lwp = lwp->li_prev; 466 list_remove_lwp(&lwps, lwp_tmp); 467 } 468 } else { 469 id_info_t *id = list->l_head; 470 id_info_t *nextid; 471 472 while (id) { 473 nextid = id->id_next; 474 free(id); 475 id = nextid; 476 } 477 list->l_count = 0; 478 list->l_head = list->l_tail = NULL; 479 } 480 } 481 482 static void 483 list_update(list_t *list, lwp_info_t *lwp) 484 { 485 id_info_t *id; 486 487 if (list->l_head == NULL) { /* first element */ 488 list->l_head = list->l_tail = id = Zalloc(sizeof (id_info_t)); 489 goto update; 490 } 491 492 for (id = list->l_head; id; id = id->id_next) { 493 if ((list->l_type == LT_USERS) && 494 (id->id_uid != lwp->li_info.pr_uid)) 495 continue; 496 if ((list->l_type == LT_TASKS) && 497 (id->id_taskid != lwp->li_info.pr_taskid)) 498 continue; 499 if ((list->l_type == LT_PROJECTS) && 500 (id->id_projid != lwp->li_info.pr_projid)) 501 continue; 502 if ((list->l_type == LT_ZONES) && 503 (id->id_zoneid != lwp->li_info.pr_zoneid)) 504 continue; 505 id->id_nproc++; 506 id->id_taskid = lwp->li_info.pr_taskid; 507 id->id_projid = lwp->li_info.pr_projid; 508 id->id_zoneid = lwp->li_info.pr_zoneid; 509 if (lwp->li_flags & LWP_REPRESENT) { 510 id->id_size += lwp->li_info.pr_size; 511 id->id_rssize += lwp->li_info.pr_rssize; 512 } 513 id->id_pctcpu += FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu); 514 if (opts.o_outpmode & OPT_LWPS) 515 id->id_time += TIME2SEC(lwp->li_info.pr_lwp.pr_time); 516 else 517 id->id_time += TIME2SEC(lwp->li_info.pr_time); 518 id->id_pctmem += FRC2PCT(lwp->li_info.pr_pctmem); 519 id->id_key += lwp->li_key; 520 total_cpu += FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu); 521 total_mem += FRC2PCT(lwp->li_info.pr_pctmem); 522 return; 523 } 524 525 id = list->l_tail; 526 id->id_next = Zalloc(sizeof (id_info_t)); 527 id->id_next->id_prev = list->l_tail; 528 id->id_next->id_next = NULL; 529 list->l_tail = id->id_next; 530 id = list->l_tail; 531 update: 532 id->id_uid = lwp->li_info.pr_uid; 533 id->id_projid = lwp->li_info.pr_projid; 534 id->id_taskid = lwp->li_info.pr_taskid; 535 id->id_zoneid = lwp->li_info.pr_zoneid; 536 id->id_nproc++; 537 if (lwp->li_flags & LWP_REPRESENT) { 538 id->id_size = lwp->li_info.pr_size; 539 id->id_rssize = lwp->li_info.pr_rssize; 540 } 541 id->id_pctcpu = FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu); 542 if (opts.o_outpmode & OPT_LWPS) 543 id->id_time = TIME2SEC(lwp->li_info.pr_lwp.pr_time); 544 else 545 id->id_time = TIME2SEC(lwp->li_info.pr_time); 546 id->id_pctmem = FRC2PCT(lwp->li_info.pr_pctmem); 547 id->id_key = lwp->li_key; 548 total_cpu += id->id_pctcpu; 549 total_mem += id->id_pctmem; 550 list->l_count++; 551 } 552 553 static void 554 lwp_update(lwp_info_t *lwp, pid_t pid, id_t lwpid, struct prusage *usage) 555 { 556 float period; 557 558 if (!lwpid_is_active(pid, lwpid)) { 559 /* 560 * If we are reading cpu times for the first time then 561 * calculate average cpu times based on whole process 562 * execution time. 563 */ 564 (void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t)); 565 period = TIME2NSEC(usage->pr_rtime); 566 period = period/(float)100; 567 568 if (period == 0) { /* zombie */ 569 period = 1; 570 lwp->li_usr = 0; 571 lwp->li_sys = 0; 572 lwp->li_slp = 0; 573 } else { 574 lwp->li_usr = TIME2NSEC(usage->pr_utime)/period; 575 lwp->li_sys = TIME2NSEC(usage->pr_stime)/period; 576 lwp->li_slp = TIME2NSEC(usage->pr_slptime)/period; 577 } 578 lwp->li_trp = TIME2NSEC(usage->pr_ttime)/period; 579 lwp->li_tfl = TIME2NSEC(usage->pr_tftime)/period; 580 lwp->li_dfl = TIME2NSEC(usage->pr_dftime)/period; 581 lwp->li_lck = TIME2NSEC(usage->pr_ltime)/period; 582 lwp->li_lat = TIME2NSEC(usage->pr_wtime)/period; 583 period = (period / NANOSEC)*(float)100; /* now in seconds */ 584 lwp->li_vcx = (ulong_t) 585 (opts.o_interval * (usage->pr_vctx/period)); 586 lwp->li_icx = (ulong_t) 587 (opts.o_interval * (usage->pr_ictx/period)); 588 lwp->li_scl = (ulong_t) 589 (opts.o_interval * (usage->pr_sysc/period)); 590 lwp->li_sig = (ulong_t) 591 (opts.o_interval * (usage->pr_sigs/period)); 592 (void) lwpid_set_active(pid, lwpid); 593 } else { 594 /* 595 * If this is not a first time we are reading a process's 596 * CPU times then recalculate CPU times based on fresh data 597 * obtained from procfs and previous CPU time usage values. 598 */ 599 period = TIME2NSEC(usage->pr_rtime)- 600 TIME2NSEC(lwp->li_usage.pr_rtime); 601 period = period/(float)100; 602 603 if (period == 0) { /* zombie */ 604 period = 1; 605 lwp->li_usr = 0; 606 lwp->li_sys = 0; 607 lwp->li_slp = 0; 608 } else { 609 lwp->li_usr = (TIME2NSEC(usage->pr_utime)- 610 TIME2NSEC(lwp->li_usage.pr_utime))/period; 611 lwp->li_sys = (TIME2NSEC(usage->pr_stime) - 612 TIME2NSEC(lwp->li_usage.pr_stime))/period; 613 lwp->li_slp = (TIME2NSEC(usage->pr_slptime) - 614 TIME2NSEC(lwp->li_usage.pr_slptime))/period; 615 } 616 lwp->li_trp = (TIME2NSEC(usage->pr_ttime) - 617 TIME2NSEC(lwp->li_usage.pr_ttime))/period; 618 lwp->li_tfl = (TIME2NSEC(usage->pr_tftime) - 619 TIME2NSEC(lwp->li_usage.pr_tftime))/period; 620 lwp->li_dfl = (TIME2NSEC(usage->pr_dftime) - 621 TIME2NSEC(lwp->li_usage.pr_dftime))/period; 622 lwp->li_lck = (TIME2NSEC(usage->pr_ltime) - 623 TIME2NSEC(lwp->li_usage.pr_ltime))/period; 624 lwp->li_lat = (TIME2NSEC(usage->pr_wtime) - 625 TIME2NSEC(lwp->li_usage.pr_wtime))/period; 626 lwp->li_vcx = usage->pr_vctx - lwp->li_usage.pr_vctx; 627 lwp->li_icx = usage->pr_ictx - lwp->li_usage.pr_ictx; 628 lwp->li_scl = usage->pr_sysc - lwp->li_usage.pr_sysc; 629 lwp->li_sig = usage->pr_sigs - lwp->li_usage.pr_sigs; 630 (void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t)); 631 } 632 } 633 634 static int 635 read_procfile(fd_t **fd, char *pidstr, char *file, void *buf, size_t bufsize) 636 { 637 char procfile[MAX_PROCFS_PATH]; 638 639 (void) snprintf(procfile, MAX_PROCFS_PATH, 640 "/proc/%s/%s", pidstr, file); 641 if ((*fd = fd_open(procfile, O_RDONLY, *fd)) == NULL) 642 return (1); 643 if (pread(fd_getfd(*fd), buf, bufsize, 0) != bufsize) { 644 fd_close(*fd); 645 return (1); 646 } 647 return (0); 648 } 649 650 static void 651 add_proc(psinfo_t *psinfo) 652 { 653 lwp_info_t *lwp; 654 id_t lwpid; 655 pid_t pid = psinfo->pr_pid; 656 657 lwpid = psinfo->pr_lwp.pr_lwpid; 658 if ((lwp = lwpid_get(pid, lwpid)) == NULL) 659 lwp = list_add_lwp(&lwps, pid, lwpid); 660 lwp->li_flags |= LWP_ALIVE | LWP_REPRESENT; 661 (void) memcpy(&lwp->li_info, psinfo, sizeof (psinfo_t)); 662 lwp->li_info.pr_lwp.pr_pctcpu = lwp->li_info.pr_pctcpu; 663 } 664 665 static void 666 add_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, int flags) 667 { 668 lwp_info_t *lwp; 669 pid_t pid = psinfo->pr_pid; 670 id_t lwpid = lwpsinfo->pr_lwpid; 671 672 if ((lwp = lwpid_get(pid, lwpid)) == NULL) 673 lwp = list_add_lwp(&lwps, pid, lwpid); 674 lwp->li_flags &= ~LWP_REPRESENT; 675 lwp->li_flags |= LWP_ALIVE; 676 lwp->li_flags |= flags; 677 (void) memcpy(&lwp->li_info, psinfo, 678 sizeof (psinfo_t) - sizeof (lwpsinfo_t)); 679 (void) memcpy(&lwp->li_info.pr_lwp, lwpsinfo, sizeof (lwpsinfo_t)); 680 } 681 682 static void 683 prstat_scandir(DIR *procdir) 684 { 685 char *pidstr; 686 pid_t pid; 687 id_t lwpid; 688 size_t entsz; 689 long nlwps, nent, i; 690 char *buf, *ptr; 691 692 fds_t *fds; 693 lwp_info_t *lwp; 694 dirent_t *direntp; 695 696 prheader_t header; 697 psinfo_t psinfo; 698 prusage_t usage; 699 lwpsinfo_t *lwpsinfo; 700 prusage_t *lwpusage; 701 702 total_procs = 0; 703 total_lwps = 0; 704 total_cpu = 0; 705 total_mem = 0; 706 707 convert_zone(&zone_tbl); 708 for (rewinddir(procdir); (direntp = readdir(procdir)); ) { 709 pidstr = direntp->d_name; 710 if (pidstr[0] == '.') /* skip "." and ".." */ 711 continue; 712 pid = atoi(pidstr); 713 if (pid == 0 || pid == 2 || pid == 3) 714 continue; /* skip sched, pageout and fsflush */ 715 if (has_element(&pid_tbl, pid) == 0) 716 continue; /* check if we really want this pid */ 717 fds = fds_get(pid); /* get ptr to file descriptors */ 718 719 if (read_procfile(&fds->fds_psinfo, pidstr, 720 "psinfo", &psinfo, sizeof (psinfo_t)) != 0) 721 continue; 722 if (!has_uid(&ruid_tbl, psinfo.pr_uid) || 723 !has_uid(&euid_tbl, psinfo.pr_euid) || 724 !has_element(&prj_tbl, psinfo.pr_projid) || 725 !has_element(&tsk_tbl, psinfo.pr_taskid) || 726 !has_zone(&zone_tbl, psinfo.pr_zoneid)) { 727 fd_close(fds->fds_psinfo); 728 continue; 729 } 730 nlwps = psinfo.pr_nlwp + psinfo.pr_nzomb; 731 732 if (nlwps > 1 && (opts.o_outpmode & (OPT_LWPS | OPT_PSETS))) { 733 int rep_lwp = 0; 734 735 if (read_procfile(&fds->fds_lpsinfo, pidstr, "lpsinfo", 736 &header, sizeof (prheader_t)) != 0) { 737 fd_close(fds->fds_psinfo); 738 continue; 739 } 740 741 nent = header.pr_nent; 742 entsz = header.pr_entsize * nent; 743 ptr = buf = Malloc(entsz); 744 if (pread(fd_getfd(fds->fds_lpsinfo), buf, 745 entsz, sizeof (struct prheader)) != entsz) { 746 fd_close(fds->fds_lpsinfo); 747 fd_close(fds->fds_psinfo); 748 free(buf); 749 continue; 750 } 751 752 nlwps = 0; 753 for (i = 0; i < nent; i++, ptr += header.pr_entsize) { 754 /*LINTED ALIGNMENT*/ 755 lwpsinfo = (lwpsinfo_t *)ptr; 756 if (!has_element(&cpu_tbl, 757 lwpsinfo->pr_onpro) || 758 !has_element(&set_tbl, 759 lwpsinfo->pr_bindpset)) 760 continue; 761 nlwps++; 762 if ((opts.o_outpmode & (OPT_PSETS | OPT_LWPS)) 763 == OPT_PSETS) { 764 /* 765 * If one of process's LWPs is bound 766 * to a given processor set, report the 767 * whole process. We may be doing this 768 * a few times but we'll get an accurate 769 * lwp count in return. 770 */ 771 add_proc(&psinfo); 772 } else { 773 if (rep_lwp == 0) { 774 rep_lwp = 1; 775 add_lwp(&psinfo, lwpsinfo, 776 LWP_REPRESENT); 777 } else { 778 add_lwp(&psinfo, lwpsinfo, 0); 779 } 780 } 781 } 782 free(buf); 783 if (nlwps == 0) { 784 fd_close(fds->fds_lpsinfo); 785 fd_close(fds->fds_psinfo); 786 continue; 787 } 788 } else { 789 if (!has_element(&cpu_tbl, psinfo.pr_lwp.pr_onpro) || 790 !has_element(&set_tbl, psinfo.pr_lwp.pr_bindpset)) { 791 fd_close(fds->fds_psinfo); 792 continue; 793 } 794 add_proc(&psinfo); 795 } 796 if (!(opts.o_outpmode & OPT_MSACCT)) { 797 total_procs++; 798 total_lwps += nlwps; 799 continue; 800 } 801 /* 802 * Get more information about processes from /proc/pid/usage. 803 * If process has more than one lwp, then we may have to 804 * also look at the /proc/pid/lusage file. 805 */ 806 if ((opts.o_outpmode & OPT_LWPS) && (nlwps > 1)) { 807 if (read_procfile(&fds->fds_lusage, pidstr, "lusage", 808 &header, sizeof (prheader_t)) != 0) { 809 fd_close(fds->fds_lpsinfo); 810 fd_close(fds->fds_psinfo); 811 continue; 812 } 813 nent = header.pr_nent; 814 entsz = header.pr_entsize * nent; 815 buf = Malloc(entsz); 816 if (pread(fd_getfd(fds->fds_lusage), buf, 817 entsz, sizeof (struct prheader)) != entsz) { 818 fd_close(fds->fds_lusage); 819 fd_close(fds->fds_lpsinfo); 820 fd_close(fds->fds_psinfo); 821 free(buf); 822 continue; 823 } 824 for (i = 1, ptr = buf + header.pr_entsize; i < nent; 825 i++, ptr += header.pr_entsize) { 826 /*LINTED ALIGNMENT*/ 827 lwpusage = (prusage_t *)ptr; 828 lwpid = lwpusage->pr_lwpid; 829 /* 830 * New LWPs created after we read lpsinfo 831 * will be ignored. Don't want to do 832 * everything all over again. 833 */ 834 if ((lwp = lwpid_get(pid, lwpid)) == NULL) 835 continue; 836 lwp_update(lwp, pid, lwpid, lwpusage); 837 } 838 free(buf); 839 } else { 840 if (read_procfile(&fds->fds_usage, pidstr, "usage", 841 &usage, sizeof (prusage_t)) != 0) { 842 fd_close(fds->fds_lpsinfo); 843 fd_close(fds->fds_psinfo); 844 continue; 845 } 846 lwpid = psinfo.pr_lwp.pr_lwpid; 847 if ((lwp = lwpid_get(pid, lwpid)) == NULL) 848 continue; 849 lwp_update(lwp, pid, lwpid, &usage); 850 } 851 total_procs++; 852 total_lwps += nlwps; 853 } 854 fd_update(); 855 } 856 857 /* 858 * This procedure removes all dead lwps from the linked list of all lwps. 859 * It also creates linked list of ids if necessary. 860 */ 861 static void 862 list_refresh(list_t *list) 863 { 864 lwp_info_t *lwp, *lwp_next; 865 866 if (!(list->l_type & LT_LWPS)) 867 return; 868 869 for (lwp = list->l_head; lwp != NULL; ) { 870 if (lwp->li_flags & LWP_ALIVE) { 871 /* 872 * Process all live LWPs. 873 * When we're done, mark them as dead. 874 * They will be marked "alive" on the next 875 * /proc scan if they still exist. 876 */ 877 lwp->li_key = list_getkeyval(list, lwp); 878 if (opts.o_outpmode & OPT_USERS) 879 list_update(&users, lwp); 880 if (opts.o_outpmode & OPT_TASKS) 881 list_update(&tasks, lwp); 882 if (opts.o_outpmode & OPT_PROJECTS) 883 list_update(&projects, lwp); 884 if (opts.o_outpmode & OPT_ZONES) 885 list_update(&zones, lwp); 886 lwp->li_flags &= ~LWP_ALIVE; 887 lwp = lwp->li_next; 888 889 } else { 890 lwp_next = lwp->li_next; 891 list_remove_lwp(&lwps, lwp); 892 lwp = lwp_next; 893 } 894 } 895 } 896 897 static void 898 curses_on() 899 { 900 if ((opts.o_outpmode & OPT_TERMCAP) && (is_curses_on == FALSE)) { 901 (void) initscr(); 902 (void) nonl(); 903 (void) putp(t_smcup); 904 is_curses_on = TRUE; 905 } 906 } 907 908 static void 909 curses_off() 910 { 911 if ((is_curses_on == TRUE) && (opts.o_outpmode & OPT_TERMCAP)) { 912 (void) putp(t_rmcup); 913 (void) endwin(); 914 is_curses_on = FALSE; 915 } 916 (void) fflush(stdout); 917 } 918 919 static int 920 nlines() 921 { 922 struct winsize ws; 923 char *envp; 924 int n; 925 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) { 926 if (ws.ws_row > 0) 927 return (ws.ws_row); 928 } 929 if (envp = getenv("LINES")) { 930 if ((n = Atoi(envp)) > 0) { 931 opts.o_outpmode &= ~OPT_USEHOME; 932 return (n); 933 } 934 } 935 return (-1); 936 } 937 938 static void 939 setmovecur() 940 { 941 int i, n; 942 if ((opts.o_outpmode & OPT_FULLSCREEN) && 943 (opts.o_outpmode & OPT_USEHOME)) { 944 movecur = t_home; 945 return; 946 } 947 if (opts.o_outpmode & OPT_SPLIT) { 948 n = opts.o_ntop + opts.o_nbottom + 2; 949 } else { 950 if (opts.o_outpmode & OPT_USERS) 951 n = opts.o_nbottom + 1; 952 else 953 n = opts.o_ntop + 1; 954 } 955 if (movecur != NULL && movecur != empty_string && movecur != t_home) 956 free(movecur); 957 movecur = Zalloc(strlen(t_up) * (n + 5)); 958 for (i = 0; i <= n; i++) 959 (void) strcat(movecur, t_up); 960 } 961 962 static int 963 setsize() 964 { 965 static int oldn = 0; 966 int n; 967 968 if (opts.o_outpmode & OPT_FULLSCREEN) { 969 n = nlines(); 970 if (n == oldn) 971 return (0); 972 oldn = n; 973 if (n == -1) { 974 opts.o_outpmode &= ~OPT_USEHOME; 975 setmovecur(); /* set default window size */ 976 return (1); 977 } 978 n = n - 3; /* minus header, total and cursor lines */ 979 if (n < 1) 980 Die(gettext("window is too small (try -n)\n")); 981 if (opts.o_outpmode & OPT_SPLIT) { 982 if (n < 8) { 983 Die(gettext("window is too small (try -n)\n")); 984 } else { 985 opts.o_ntop = (n / 4) * 3; 986 opts.o_nbottom = n - 1 - opts.o_ntop; 987 } 988 } else { 989 if (opts.o_outpmode & OPT_USERS) 990 opts.o_nbottom = n; 991 else 992 opts.o_ntop = n; 993 } 994 } 995 setmovecur(); 996 return (1); 997 } 998 999 static void 1000 ldtermcap() 1001 { 1002 int err; 1003 if (setupterm(NULL, STDIN_FILENO, &err) == ERR) { 1004 switch (err) { 1005 case 0: 1006 Warn(gettext("failed to load terminal info, " 1007 "defaulting to -c option\n")); 1008 break; 1009 case -1: 1010 Warn(gettext("terminfo database not found, " 1011 "defaulting to -c option\n")); 1012 break; 1013 default: 1014 Warn(gettext("failed to initialize terminal, " 1015 "defaulting to -c option\n")); 1016 } 1017 opts.o_outpmode &= ~OPT_TERMCAP; 1018 t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string; 1019 t_ulon = t_uloff = empty_string; 1020 return; 1021 } 1022 t_ulon = tigetstr("smul"); 1023 t_uloff = tigetstr("rmul"); 1024 t_up = tigetstr("cuu1"); 1025 t_eol = tigetstr("el"); 1026 t_smcup = tigetstr("smcup"); 1027 t_rmcup = tigetstr("rmcup"); 1028 t_home = tigetstr("home"); 1029 if ((t_up == (char *)-1) || (t_eol == (char *)-1) || 1030 (t_smcup == (char *)-1) || (t_rmcup == (char *)-1)) { 1031 opts.o_outpmode &= ~OPT_TERMCAP; 1032 t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string; 1033 return; 1034 } 1035 if (t_up == NULL || t_eol == NULL) { 1036 opts.o_outpmode &= ~OPT_TERMCAP; 1037 t_eol = t_up = movecur = empty_string; 1038 return; 1039 } 1040 if (t_ulon == (char *)-1 || t_uloff == (char *)-1 || 1041 t_ulon == NULL || t_uloff == NULL) { 1042 t_ulon = t_uloff = empty_string; /* can live without it */ 1043 } 1044 if (t_smcup == NULL || t_rmcup == NULL) 1045 t_smcup = t_rmcup = empty_string; 1046 if (t_home == (char *)-1 || t_home == NULL) { 1047 opts.o_outpmode &= ~OPT_USEHOME; 1048 t_home = empty_string; 1049 } 1050 } 1051 1052 static void 1053 sig_handler(int sig) 1054 { 1055 switch (sig) { 1056 case SIGTSTP: sigtstp = 1; 1057 break; 1058 case SIGWINCH: sigwinch = 1; 1059 break; 1060 case SIGINT: 1061 case SIGTERM: sigterm = 1; 1062 break; 1063 } 1064 } 1065 1066 static void 1067 set_signals() 1068 { 1069 (void) signal(SIGTSTP, sig_handler); 1070 (void) signal(SIGINT, sig_handler); 1071 (void) signal(SIGTERM, sig_handler); 1072 if (opts.o_outpmode & OPT_FULLSCREEN) 1073 (void) signal(SIGWINCH, sig_handler); 1074 } 1075 1076 static void 1077 fill_table(table_t *table, char *arg) 1078 { 1079 char *p = strtok(arg, ", "); 1080 long l = Atoi(p); 1081 1082 add_element(table, l); 1083 while (p = strtok(NULL, ", ")) { 1084 l = Atoi(p); 1085 add_element(table, l); 1086 } 1087 } 1088 1089 static void 1090 fill_prj_table(char *arg) 1091 { 1092 projid_t projid; 1093 char *p = strtok(arg, ", "); 1094 1095 if ((projid = getprojidbyname(p)) == -1) 1096 projid = Atoi(p); 1097 add_element(&prj_tbl, (long)projid); 1098 1099 while (p = strtok(NULL, ", ")) { 1100 if ((projid = getprojidbyname(p)) == -1) 1101 projid = Atoi(p); 1102 add_element(&prj_tbl, (long)projid); 1103 } 1104 } 1105 1106 static void 1107 fill_set_table(char *arg) 1108 { 1109 char *p = strtok(arg, ", "); 1110 psetid_t id; 1111 1112 if ((id = Atoi(p)) == 0) 1113 id = PS_NONE; 1114 add_element(&set_tbl, id); 1115 while (p = strtok(NULL, ", ")) { 1116 if ((id = Atoi(p)) == 0) 1117 id = PS_NONE; 1118 if (!has_element(&set_tbl, id)) 1119 add_element(&set_tbl, id); 1120 } 1121 } 1122 1123 static void 1124 Exit() 1125 { 1126 curses_off(); 1127 list_clear(&lwps); 1128 list_clear(&users); 1129 list_clear(&tasks); 1130 list_clear(&projects); 1131 list_clear(&zones); 1132 fd_exit(); 1133 } 1134 1135 int 1136 main(int argc, char **argv) 1137 { 1138 DIR *procdir; 1139 char *p; 1140 char *sortk = "cpu"; /* default sort key */ 1141 int opt; 1142 int timeout; 1143 struct pollfd pollset; 1144 char key; 1145 1146 (void) setlocale(LC_ALL, ""); 1147 (void) textdomain(TEXT_DOMAIN); 1148 Progname(argv[0]); 1149 lwpid_init(); 1150 fd_init(Setrlimit()); 1151 1152 while ((opt = getopt(argc, argv, "vcmaRLtu:U:n:p:C:P:s:S:j:k:TJz:Z")) 1153 != (int)EOF) { 1154 switch (opt) { 1155 case 'R': 1156 opts.o_outpmode |= OPT_REALTIME; 1157 break; 1158 case 'c': 1159 opts.o_outpmode &= ~OPT_TERMCAP; 1160 opts.o_outpmode &= ~OPT_FULLSCREEN; 1161 break; 1162 case 'm': 1163 case 'v': 1164 opts.o_outpmode &= ~OPT_PSINFO; 1165 opts.o_outpmode |= OPT_MSACCT; 1166 break; 1167 case 't': 1168 opts.o_outpmode &= ~OPT_PSINFO; 1169 opts.o_outpmode |= OPT_USERS; 1170 break; 1171 case 'a': 1172 opts.o_outpmode |= OPT_SPLIT | OPT_USERS; 1173 break; 1174 case 'T': 1175 opts.o_outpmode |= OPT_SPLIT | OPT_TASKS; 1176 break; 1177 case 'J': 1178 opts.o_outpmode |= OPT_SPLIT | OPT_PROJECTS; 1179 break; 1180 case 'n': 1181 p = strtok(optarg, ","); 1182 opts.o_ntop = Atoi(p); 1183 if (p = strtok(NULL, ",")) 1184 opts.o_nbottom = Atoi(p); 1185 opts.o_outpmode &= ~OPT_FULLSCREEN; 1186 break; 1187 case 's': 1188 opts.o_sortorder = -1; 1189 sortk = optarg; 1190 break; 1191 case 'S': 1192 opts.o_sortorder = 1; 1193 sortk = optarg; 1194 break; 1195 case 'u': 1196 p = strtok(optarg, ", "); 1197 add_uid(&euid_tbl, p); 1198 while (p = strtok(NULL, ", ")) 1199 add_uid(&euid_tbl, p); 1200 break; 1201 case 'U': 1202 p = strtok(optarg, ", "); 1203 add_uid(&ruid_tbl, p); 1204 while (p = strtok(NULL, ", ")) 1205 add_uid(&ruid_tbl, p); 1206 break; 1207 case 'p': 1208 fill_table(&pid_tbl, optarg); 1209 break; 1210 case 'C': 1211 fill_set_table(optarg); 1212 opts.o_outpmode |= OPT_PSETS; 1213 break; 1214 case 'P': 1215 fill_table(&cpu_tbl, optarg); 1216 break; 1217 case 'k': 1218 fill_table(&tsk_tbl, optarg); 1219 break; 1220 case 'j': 1221 fill_prj_table(optarg); 1222 break; 1223 case 'L': 1224 opts.o_outpmode |= OPT_LWPS; 1225 break; 1226 case 'z': 1227 p = strtok(optarg, ", "); 1228 add_zone(&zone_tbl, p); 1229 while (p = strtok(NULL, ", ")) 1230 add_zone(&zone_tbl, p); 1231 break; 1232 case 'Z': 1233 opts.o_outpmode |= OPT_SPLIT | OPT_ZONES; 1234 break; 1235 default: 1236 Usage(); 1237 } 1238 } 1239 1240 (void) atexit(Exit); 1241 if ((opts.o_outpmode & OPT_USERS) && 1242 !(opts.o_outpmode & OPT_SPLIT)) 1243 opts.o_nbottom = opts.o_ntop; 1244 if (opts.o_ntop == 0 || opts.o_nbottom == 0) 1245 Die(gettext("invalid argument for -n\n")); 1246 if (!(opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode & OPT_USERS) && 1247 ((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT)))) 1248 Die(gettext("-t option cannot be used with -v or -m\n")); 1249 1250 if ((opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode && OPT_USERS) && 1251 !((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT)))) 1252 Die(gettext("-t option cannot be used with " 1253 "-a, -J, -T or -Z\n")); 1254 1255 if ((opts.o_outpmode & OPT_USERS) && 1256 (opts.o_outpmode & (OPT_TASKS | OPT_PROJECTS | OPT_ZONES))) 1257 Die(gettext("-a option cannot be used with " 1258 "-t, -J, -T or -Z\n")); 1259 1260 if (((opts.o_outpmode & OPT_TASKS) && 1261 (opts.o_outpmode & (OPT_PROJECTS|OPT_ZONES))) || 1262 ((opts.o_outpmode & OPT_PROJECTS) && 1263 (opts.o_outpmode & (OPT_TASKS|OPT_ZONES)))) { 1264 Die(gettext("-J, -T and -Z options are mutually exclusive\n")); 1265 } 1266 1267 if (argc > optind) 1268 opts.o_interval = Atoi(argv[optind++]); 1269 if (argc > optind) 1270 opts.o_count = Atoi(argv[optind++]); 1271 if (opts.o_count == 0) 1272 Die(gettext("invalid counter value\n")); 1273 if (argc > optind) 1274 Usage(); 1275 if (opts.o_outpmode & OPT_REALTIME) 1276 Priocntl("RT"); 1277 if (isatty(STDOUT_FILENO) == 1 && isatty(STDIN_FILENO)) 1278 opts.o_outpmode |= OPT_TTY; /* interactive */ 1279 if (!(opts.o_outpmode & OPT_TTY)) { 1280 opts.o_outpmode &= ~OPT_TERMCAP; /* no termcap for pipes */ 1281 opts.o_outpmode &= ~OPT_FULLSCREEN; 1282 } 1283 if (opts.o_outpmode & OPT_TERMCAP) 1284 ldtermcap(); /* can turn OPT_TERMCAP off */ 1285 if (opts.o_outpmode & OPT_TERMCAP) 1286 (void) setsize(); 1287 list_alloc(&lwps, opts.o_ntop); 1288 list_alloc(&users, opts.o_nbottom); 1289 list_alloc(&tasks, opts.o_nbottom); 1290 list_alloc(&projects, opts.o_nbottom); 1291 list_alloc(&zones, opts.o_nbottom); 1292 list_setkeyfunc(sortk, &opts, &lwps, LT_LWPS); 1293 list_setkeyfunc(NULL, &opts, &users, LT_USERS); 1294 list_setkeyfunc(NULL, &opts, &tasks, LT_TASKS); 1295 list_setkeyfunc(NULL, &opts, &projects, LT_PROJECTS); 1296 list_setkeyfunc(NULL, &opts, &zones, LT_ZONES); 1297 if (opts.o_outpmode & OPT_TERMCAP) 1298 curses_on(); 1299 if ((procdir = opendir("/proc")) == NULL) 1300 Die(gettext("cannot open /proc directory\n")); 1301 if (opts.o_outpmode & OPT_TTY) { 1302 (void) printf(gettext("Please wait...\r")); 1303 (void) fflush(stdout); 1304 } 1305 set_signals(); 1306 pollset.fd = STDIN_FILENO; 1307 pollset.events = POLLIN; 1308 timeout = opts.o_interval * MILLISEC; 1309 1310 /* 1311 * main program loop 1312 */ 1313 do { 1314 if (sigterm == 1) 1315 break; 1316 if (sigtstp == 1) { 1317 curses_off(); 1318 (void) signal(SIGTSTP, SIG_DFL); 1319 (void) kill(0, SIGTSTP); 1320 /* 1321 * prstat stops here until it receives SIGCONT signal. 1322 */ 1323 sigtstp = 0; 1324 (void) signal(SIGTSTP, sig_handler); 1325 curses_on(); 1326 print_movecur = FALSE; 1327 if (opts.o_outpmode & OPT_FULLSCREEN) 1328 sigwinch = 1; 1329 } 1330 if (sigwinch == 1) { 1331 if (setsize() == 1) { 1332 list_free(&lwps); 1333 list_free(&users); 1334 list_free(&tasks); 1335 list_free(&projects); 1336 list_free(&zones); 1337 list_alloc(&lwps, opts.o_ntop); 1338 list_alloc(&users, opts.o_nbottom); 1339 list_alloc(&tasks, opts.o_nbottom); 1340 list_alloc(&projects, opts.o_nbottom); 1341 list_alloc(&zones, opts.o_nbottom); 1342 } 1343 sigwinch = 0; 1344 (void) signal(SIGWINCH, sig_handler); 1345 } 1346 prstat_scandir(procdir); 1347 list_refresh(&lwps); 1348 if (print_movecur) 1349 (void) putp(movecur); 1350 print_movecur = TRUE; 1351 if ((opts.o_outpmode & OPT_PSINFO) || 1352 (opts.o_outpmode & OPT_MSACCT)) { 1353 list_sort(&lwps); 1354 list_print(&lwps); 1355 } 1356 if (opts.o_outpmode & OPT_USERS) { 1357 list_sort(&users); 1358 list_print(&users); 1359 list_clear(&users); 1360 } 1361 if (opts.o_outpmode & OPT_TASKS) { 1362 list_sort(&tasks); 1363 list_print(&tasks); 1364 list_clear(&tasks); 1365 } 1366 if (opts.o_outpmode & OPT_PROJECTS) { 1367 list_sort(&projects); 1368 list_print(&projects); 1369 list_clear(&projects); 1370 } 1371 if (opts.o_outpmode & OPT_ZONES) { 1372 list_sort(&zones); 1373 list_print(&zones); 1374 list_clear(&zones); 1375 } 1376 if (opts.o_count == 1) 1377 break; 1378 /* 1379 * If poll() returns -1 and sets errno to EINTR here because 1380 * the process received a signal, it is Ok to abort this 1381 * timeout and loop around because we check the signals at the 1382 * top of the loop. 1383 */ 1384 if (opts.o_outpmode & OPT_TTY) { 1385 if (poll(&pollset, (nfds_t)1, timeout) > 0) { 1386 if (read(STDIN_FILENO, &key, 1) == 1) { 1387 if (tolower(key) == 'q') 1388 break; 1389 } 1390 } 1391 } else { 1392 (void) sleep(opts.o_interval); 1393 } 1394 } while (opts.o_count == (-1) || --opts.o_count); 1395 1396 if (opts.o_outpmode & OPT_TTY) 1397 (void) putchar('\r'); 1398 return (0); 1399 } 1400