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