1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1990 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)ps.c 5.29 (Berkeley) 08/30/90"; 16 #endif /* not lint */ 17 18 #include <machine/pte.h> 19 20 #include <sys/param.h> 21 #include <sys/ioctl.h> 22 #include <sys/tty.h> 23 #include <sys/user.h> 24 #include <sys/proc.h> 25 #include <sys/vm.h> 26 #include <sys/text.h> 27 #include <sys/stat.h> 28 #include <sys/mbuf.h> 29 #include <nlist.h> 30 #include <pwd.h> 31 #include <math.h> 32 #include <errno.h> 33 #include <stddef.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <ctype.h> 38 #include <varargs.h> 39 #include <kvm.h> 40 #include "pathnames.h" 41 42 struct usave { 43 struct proc *u_procp; 44 struct timeval u_start; 45 struct rusage u_ru; 46 struct rusage u_cru; 47 short u_cmask; 48 char u_acflag; 49 }; 50 51 /* 52 * to compute offset in common structures 53 */ 54 #define POFF(x) offsetof(struct proc, x) 55 #define EOFF(x) offsetof(struct eproc, x) 56 #define UOFF(x) offsetof(struct usave, x) 57 #define ROFF(x) offsetof(struct rusage, x) 58 59 enum type { CHAR, UCHAR, SHORT, USHORT, LONG, ULONG, KPTR }; 60 61 #define UIDFMT "u" 62 #define UIDLEN 5 63 #define PIDFMT "d" 64 #define PIDLEN 5 65 #define USERLEN 8 66 67 int needuser, needcomm, neednlist; 68 69 int command(), ucomm(), logname(), pvar(), evar(), uvar(), rvar(), uname(), 70 runame(), state(), pri(), tdev(), tname(), longtname(), started(), 71 lstarted(), wchan(), vsize(), rssize(), p_rssize(), cputime(), 72 pmem(), pcpu(), pagein(), maxrss(), tsize(), trss(); 73 /** 74 utime(), stime(), ixrss(), idrss(), isrss(); 75 **/ 76 77 uid_t getuid(); 78 char *ttyname(); 79 80 struct var { 81 char *name[4]; /* name(s) of variable */ 82 char *header; /* default header */ 83 int flag; 84 #define USER 0x01 /* requires user structure */ 85 #define LJUST 0x02 /* left adjust on output (trailing blanks) */ 86 #define COMM 0x04 /* requires exec arguments and environment (XXX) */ 87 #define NLIST 0x08 /* requires nlist to get extra variables */ 88 int (*oproc)(); /* output routine */ 89 short width; /* printing width */ 90 /* 91 * The following (optional) elements are hooks for passing information 92 * to the generic output routines: pvar, evar, uvar (those which print 93 * simple elements from well known structures: proc, eproc, usave) 94 */ 95 int off; /* offset in structure */ 96 enum type type; /* type of element */ 97 char *fmt; /* printf format */ 98 /* 99 * glue to link selected fields together 100 */ 101 struct var *next; 102 } var[] = { 103 {{"command", "comm", "args"}, "COMMAND", USER|LJUST|COMM, 104 command, 16}, 105 {{"ucomm"}, "COMMAND", LJUST, ucomm, MAXCOMLEN}, 106 {{"logname"}, "LOGNAME", LJUST, logname, MAXLOGNAME}, 107 {{"flag", "f"}, "F", 0, pvar, 7, POFF(p_flag), LONG, "x"}, 108 {{"uid"}, "UID", 0, pvar, UIDLEN, POFF(p_uid),USHORT, UIDFMT}, 109 {{"ruid"}, "RUID", 0, pvar, UIDLEN, POFF(p_ruid), USHORT, UIDFMT}, 110 {{"svuid"}, "SVUID", 0, pvar, UIDLEN, POFF(p_svuid), USHORT, UIDFMT}, 111 {{"rgid"}, "RGID", 0, pvar, UIDLEN, POFF(p_rgid), USHORT, UIDFMT}, 112 {{"svgid"}, "SVGID", 0, pvar, UIDLEN, POFF(p_svgid), USHORT, UIDFMT}, 113 {{"pid"}, "PID", 0, pvar, PIDLEN, POFF(p_pid),SHORT, PIDFMT}, 114 {{"ppid"}, "PPID", 0, pvar, PIDLEN, POFF(p_ppid), SHORT, PIDFMT}, 115 {{"cp", "cpu"}, "CP", 0, pvar, 3, POFF(p_cpu), UCHAR, "d"}, 116 {{"xstat"}, "XSTAT", 0, pvar, 4, POFF(p_xstat), USHORT, "x"}, 117 {{"poip"}, "POIP", 0, pvar, 4, POFF(p_poip), SHORT, "d"}, 118 {{"nwchan"}, "WCHAN", 0, pvar, 6, POFF(p_wchan), KPTR, "x"}, 119 {{"wchan"}, "WCHAN", LJUST, wchan, 6}, 120 {{"rlink"}, "RLINK", 0, pvar, 8, POFF(p_rlink), KPTR, "x"}, 121 {{"ktrace", "traceflag"}, "KTRACE", 122 0, pvar, 8, POFF(p_traceflag), LONG, "x"}, 123 {{"ktracep", "tracep"}, "KTRACEP", 124 0, pvar, 8, POFF(p_tracep), LONG, "x"}, 125 {{"sig", "pending"}, "PENDING", 126 0, pvar, 8, POFF(p_sig), LONG, "x"}, 127 {{"sigmask", "blocked"}, "BLOCKED", 128 0, pvar, 8, POFF(p_sigmask), LONG, "x"}, 129 {{"sigignore", "ignored"}, "IGNORED", 130 0, pvar, 8, POFF(p_sigignore), LONG, "x"}, 131 {{"sigcatch", "caught"}, "CAUGHT", 132 0, pvar, 8, POFF(p_sigcatch), LONG, "x"}, 133 {{"user", "uname"}, "USER", LJUST, uname, USERLEN}, 134 {{"ruser", "runame"}, "RUSER", LJUST, runame, USERLEN}, 135 {{"pgid"}, "PGID", 0, evar, PIDLEN, EOFF(e_pgid), USHORT, PIDFMT}, 136 {{"jobc"}, "JOBC", 0, evar, 4, EOFF(e_jobc), SHORT, "d"}, 137 {{"sess", "session"}, "SESS", 0, evar, 6, EOFF(e_sess), KPTR, "x"}, 138 {{"tdev", "dev"}, "TDEV", 0, tdev, 4}, 139 {{"tname", "tty", "tt"}, "TT", LJUST, tname, 3}, 140 {{"longtname", "longtty"}, "TT", LJUST, longtname, 8}, 141 {{"tpgid"}, "TPGID", 0, evar, 4, EOFF(e_tpgid), USHORT, PIDFMT}, 142 {{"tsession", "tsess"}, "TSESS", 143 0, evar, 6, EOFF(e_tsess), KPTR, "x"}, 144 {{"paddr", "procaddr"}, "PADDR", 145 0, evar, 6, EOFF(e_paddr), KPTR, "x"}, 146 {{"state", "stat"}, "STAT", 0, state, 4}, 147 {{"pri"}, "PRI", 0, pri, 3}, 148 {{"usrpri"}, "UPR", 0, pvar, 3, POFF(p_usrpri), CHAR, "d"}, 149 {{"nice", "ni"}, "NI", 0, pvar, 2, POFF(p_nice), CHAR, "d"}, 150 {{"vsize", "vsz"}, "VSZ", 0, vsize, 5}, 151 {{"rssize", "rsz"}, "RSZ", 0, rssize, 4}, 152 {{"rss", "p_rss"}, "RSS", 0, p_rssize, 4}, 153 {{"u_procp", "uprocp"}, "UPROCP", 154 USER, uvar, 6, UOFF(u_procp), KPTR, "x"}, 155 {{"umask", "u_cmask"}, "UMASK", 156 USER, uvar, 3, UOFF(u_cmask), CHAR, "#o"}, 157 {{"acflag", "acflg"}, "ACFLG", 158 USER, uvar, 3, UOFF(u_acflag), SHORT, "x"}, 159 {{"start"}, "STARTED", USER|LJUST, started, 8}, 160 {{"lstart"}, "STARTED", USER|LJUST, lstarted, 28}, 161 {{"cputime", "time"}, "TIME", USER, cputime, 9}, 162 {{"p_ru"}, "P_RU", 0, pvar, 6, POFF(p_ru), KPTR, "x"}, 163 {{"pcpu", "%cpu"}, "%CPU", NLIST, pcpu, 4}, 164 {{"pmem", "%mem"}, "%MEM", NLIST, pmem, 4}, 165 {{"sl", "slp", "slptime"}, "SL", 166 0, pvar, 3, POFF(p_slptime), CHAR, "d"}, 167 {{"re", "resident"}, "RE", 168 0, pvar, 3, POFF(p_time), CHAR, "d"}, 169 {{"pagein", "majflt"}, "PAGEIN", USER, pagein, 6}, 170 {{"lim", "maxrss"}, "LIM", 0, maxrss, 5}, 171 {{"tsiz"}, "TSIZ", 0, tsize, 4}, 172 {{"trs"}, "TRS", 0, trss, 3}, 173 /*** 174 {{"utime"}, "UTIME", USER, utime, 4}, 175 {{"stime"}, "STIME", USER, stime, 4}, 176 {{"ixrss"}, "IXRSS", USER, ixrss, 4}, 177 {{"idrss"}, "IDRSS", USER, idrss, 4}, 178 {{"isrss"}, "ISRSS", USER, isrss, 4}, 179 ***/ 180 {{"minflt"}, "MINFLT", 181 USER, rvar, 4, ROFF(ru_minflt), LONG, "d"}, 182 {{"majflt"}, "MAJFLT", 183 USER, rvar, 4, ROFF(ru_majflt), LONG, "d"}, 184 {{"nswap"}, "NSWAP", 185 USER, rvar, 4, ROFF(ru_nswap), LONG, "d"}, 186 {{"inblock", "inblk"}, "INBLK", 187 USER, rvar, 4, ROFF(ru_inblock), LONG, "d"}, 188 {{"oublock", "oublk"}, "OUBLK", 189 USER, rvar, 4, ROFF(ru_oublock), LONG, "d"}, 190 {{"msgsnd"}, "MSGSND", 191 USER, rvar, 4, ROFF(ru_msgsnd), LONG, "d"}, 192 {{"msgrcv"}, "MSGRCV", 193 USER, rvar, 4, ROFF(ru_msgrcv), LONG, "d"}, 194 {{"nsignals", "nsigs"}, "NSIGS", 195 USER, rvar, 4, ROFF(ru_nsignals), LONG, "d"}, 196 {{"nvcsw", "vcsw"}, "VCSW", 197 USER, rvar, 5, ROFF(ru_nvcsw), LONG, "d"}, 198 {{"nivcsw", "ivcsw"}, "IVCSW", 199 USER, rvar, 5, ROFF(ru_nivcsw), LONG, "d"}, 200 NULL 201 }; 202 203 /* 204 * combination variables 205 */ 206 struct combovar { 207 char *name; 208 char *replace; 209 } combovar[] = { 210 "RUSAGE", "minflt majflt nswap inblock oublock \ 211 msgsnd msgrcv nsigs nvcsw nivcsw", 212 0, 0 213 }; 214 #define DFMT "pid tname state cputime comm" 215 #define LFMT \ 216 "uid pid ppid cp pri nice vsz rss wchan state tname cputime comm" 217 #define JFMT "user pid ppid pgid sess jobc state tname cputime comm" 218 #define SFMT "uid pid sig sigmask sigignore sigcatch stat tname comm" 219 #define VFMT \ 220 "pid tt state time sl re pagein vsz rss lim tsiz trs %cpu %mem comm" 221 #define UFMT \ 222 "uname pid %cpu %mem vsz rss tt state start time comm" 223 224 struct kinfo { 225 struct proc *ki_p; /* proc structure */ 226 struct eproc *ki_e; /* extra stuff */ 227 struct usave *ki_u; /* interesting parts of user */ 228 char *ki_args; /* exec args (should be char **) */ 229 char *ki_env; /* environment (should be char **) */ 230 } *kinfo; 231 232 struct var *vhead, *vtail; 233 int termwidth; /* width of screen (0 == infinity) */ 234 #define UNLIMITED 0 235 int totwidth; /* calculated width of requested variables */ 236 int sumrusage; 237 int rawcpu; 238 int sortby; 239 #define SORTMEM 1 240 #define SORTCPU 2 241 242 int uid = -1; 243 dev_t ttydev = NODEV; 244 int pid = -1; 245 int all; 246 int xflg; 247 int prtheader; 248 int lineno; 249 250 /* 251 * variables retrieved via nlist 252 */ 253 struct nlist psnl[] = { 254 {"_ecmx"}, 255 #define X_ECMX 0 256 {"_fscale"}, 257 #define X_FSCALE 1 258 {"_ccpu"}, 259 #define X_CCPU 2 260 {NULL} 261 }; 262 int fscale; 263 int ecmx; 264 fixpt_t ccpu; 265 266 #define USAGE "ps [ -(o|O) fmt ] [ -wlvujnsaxSCLmcr ] [ -p pid ] [ -t tty ]" 267 268 main (argc, argv) 269 char *argv[]; 270 { 271 extern char *optarg; 272 extern int optind; 273 int ch; 274 register int i; 275 register struct var *v; 276 register struct proc *p; 277 struct winsize ws; 278 size_t nentries; 279 int fmt = 0; 280 int pscomp(); 281 int what, flag; 282 char *kludge_oldps_options(); 283 284 if ((ioctl(1, TIOCGWINSZ, (char *)&ws) == -1 && 285 ioctl(2, TIOCGWINSZ, (char *)&ws) == -1 && 286 ioctl(0, TIOCGWINSZ, (char *)&ws) == -1) || 287 ws.ws_col == 0) 288 termwidth = 79; 289 else 290 termwidth = ws.ws_col - 1; 291 if (argc > 1) 292 argv[1] = kludge_oldps_options(argv[1]); 293 294 while ((ch = getopt(argc, argv, "o:O:wlvujnsaxt:p:SCLmrhTg")) != EOF) 295 switch((char)ch) { 296 case 'o': 297 parsefmt(optarg); 298 fmt++; 299 break; 300 case 'O': 301 parsefmt("pid"); 302 parsefmt(optarg); 303 parsefmt("state tt time command"); 304 fmt++; 305 break; 306 case 'w': 307 if (termwidth < 131) 308 termwidth = 131; 309 else 310 termwidth = UNLIMITED; 311 break; 312 case 'l': 313 parsefmt(LFMT); 314 fmt++; 315 break; 316 case 'v': 317 parsefmt(VFMT); 318 sortby = SORTMEM; 319 fmt++; 320 break; 321 case 'u': 322 parsefmt(UFMT); 323 sortby = SORTCPU; 324 fmt++; 325 break; 326 case 'j': 327 parsefmt(JFMT); 328 fmt++; 329 break; 330 case 's': 331 parsefmt(SFMT); 332 fmt++; 333 break; 334 case 'T': 335 if ((optarg = ttyname(0)) == NULL) 336 error("<stdin>: not a terminal"); 337 /* FALLTHROUGH */ 338 case 't': { 339 char *ttypath; 340 struct stat stbuf; 341 char pathbuf[MAXPATHLEN]; 342 343 if (strcmp(optarg, "co") == 0) 344 ttypath = _PATH_CONSOLE; 345 else if (*optarg != '/') 346 (void) sprintf(ttypath = pathbuf, "%s%s", 347 _PATH_TTY, optarg); 348 else 349 ttypath = optarg; 350 if (stat(ttypath, &stbuf) == -1) 351 syserror(ttypath); 352 if ((stbuf.st_mode & S_IFMT) != S_IFCHR) 353 error("%s: not a terminal", ttypath); 354 ttydev = stbuf.st_rdev; 355 break; 356 } 357 case 'p': 358 pid = atoi(optarg); 359 xflg++; 360 break; 361 case 'S': 362 sumrusage++; 363 break; 364 case 'C': 365 rawcpu++; 366 break; 367 case 'L': { 368 struct combovar *cb = &combovar[0]; 369 char *cp, *sep = ""; 370 371 for (i = 0, v = &var[0];;) { 372 if (v->name[0] != NULL) 373 cp = v++->name[0]; 374 else if (cb->name != NULL) 375 cp = cb++->name; 376 else 377 break; 378 if (termwidth && 379 (i += strlen(cp) + 1) > termwidth) 380 i = strlen(cp), sep = "\n"; 381 (void) printf("%s%s", sep, cp); 382 sep = " "; 383 } 384 (void) printf("\n"); 385 exit(0); 386 } 387 case 'a': 388 all++; 389 break; 390 case 'x': 391 xflg++; 392 break; 393 case 'm': 394 sortby = SORTMEM; 395 break; 396 case 'r': 397 sortby = SORTCPU; 398 break; 399 case 'h': 400 prtheader = ws.ws_row > 5 ? ws.ws_row : 22; 401 break; 402 case 'g': 403 break; /* no-op */ 404 case '?': 405 default: 406 (void) fprintf(stderr, "usage: %s\n", USAGE); 407 exit(1); 408 } 409 argc -= optind; 410 argv += optind; 411 412 if (*argv) { 413 char *nlistf, *memf = NULL, *swapf = NULL; 414 415 nlistf = *argv++; 416 if (*argv) { 417 memf = *argv++; 418 if (*argv) 419 swapf = *argv++; 420 } 421 if (kvm_openfiles(nlistf, memf, swapf) == -1) 422 error("kvm_openfiles: %s", kvm_geterr()); 423 } 424 425 if (!fmt) 426 parsefmt(DFMT); 427 428 if (!all && ttydev == NODEV && pid == -1) /* XXX - should be cleaner */ 429 uid = getuid(); 430 431 /* 432 * scan requested variables, noting what structures are needed, 433 * and adjusting header widths as appropiate. 434 */ 435 scanvars(); 436 #ifdef notdef 437 if (sortby == SORTCPU) 438 neednlist = 1; 439 #endif 440 if (neednlist) 441 donlist(); 442 /* 443 * get proc list 444 */ 445 if (uid != -1) { 446 what = KINFO_PROC_UID; 447 flag = uid; 448 } else if (ttydev != NODEV) { 449 what = KINFO_PROC_TTY; 450 flag = ttydev; 451 } else if (pid != -1) { 452 what = KINFO_PROC_PID; 453 flag = pid; 454 } else 455 what = KINFO_PROC_ALL; 456 /* 457 * select procs 458 */ 459 if ((nentries = kvm_getprocs(what, flag)) == -1) { 460 (void) fprintf(stderr, "ps: %s\n", kvm_geterr()); 461 exit(1); 462 } 463 kinfo = (struct kinfo *)malloc(nentries * sizeof (struct kinfo)); 464 if (kinfo == NULL) 465 error("out of memory"); 466 i = 0; 467 while ((p = kvm_nextproc()) != NULL) { 468 kinfo[i].ki_p = p; 469 kinfo[i].ki_e = kvm_geteproc(p); 470 if (needuser) 471 saveuser(&kinfo[i]); 472 i++; 473 } 474 nentries = i; 475 /* 476 * print header 477 */ 478 printheader(); 479 if (nentries == 0) 480 exit(0); 481 /* 482 * sort proc list 483 */ 484 qsort((void *)kinfo, nentries, sizeof (struct kinfo), pscomp); 485 /* 486 * for each proc, call each variable output function. 487 */ 488 for (i = 0; i < nentries; i++) { 489 if (xflg == 0 && (kinfo[i].ki_e->e_tdev == NODEV || 490 (kinfo[i].ki_p->p_flag & SCTTY ) == 0)) 491 continue; 492 for (v = vhead; v != NULL; v = v->next) { 493 (*v->oproc)(&kinfo[i], v); 494 if (v->next != NULL) 495 (void) putchar(' '); 496 } 497 (void) putchar('\n'); 498 if (prtheader && lineno++ == prtheader-4) { 499 (void) putchar('\n'); 500 printheader(); 501 lineno = 0; 502 } 503 } 504 505 exit(0); 506 } 507 508 #define FMTSEP " \t,\n" 509 510 parsefmt(fmt) 511 char *fmt; 512 { 513 register char *cp, *hp; 514 struct var *v; 515 char *lookupcombo(); 516 struct var *lookupvar(); 517 518 while (fmt) { 519 while ((cp = strsep(&fmt, FMTSEP)) != NULL && *cp == '\0') 520 /* void */; 521 if ((hp = lookupcombo(cp)) != NULL) { 522 parsefmt(hp); 523 continue; 524 } 525 if ((hp = index(cp, '=')) != NULL) 526 *hp++ = '\0'; 527 v = lookupvar(cp); 528 if (v == NULL) 529 error("unknown variable in format: %s", cp); 530 if (v->next != NULL || vtail == v) { 531 (void) fprintf(stderr, 532 "ps: can't specify a variable twice: %s\n", cp); 533 continue; 534 } 535 if (hp) 536 v->header = hp; 537 if (vhead == NULL) 538 vhead = vtail = v; 539 else { 540 vtail->next = v; 541 vtail = v; 542 } 543 } 544 } 545 546 scanvars() 547 { 548 register i; 549 register struct var *v; 550 551 for (v = vhead; v != NULL; v = v->next) { 552 i = strlen(v->header); 553 if (v->width < i) 554 v->width = i; 555 totwidth += v->width + 1; /* +1 for space */ 556 if (v->flag & USER) 557 needuser = 1; 558 if (v->flag & COMM) 559 needcomm = 1; 560 if (v->flag & NLIST) 561 neednlist = 1; 562 } 563 totwidth--; 564 } 565 566 printheader() 567 { 568 register struct var *v; 569 570 for (v = vhead; v != NULL; v = v->next) { 571 if (v->flag & LJUST) { 572 if (v->next == NULL) /* last one */ 573 (void) printf("%s", v->header); 574 else 575 (void) printf("%-*s", v->width, v->header); 576 } else 577 (void) printf("%*s", v->width, v->header); 578 if (v->next != NULL) 579 (void) putchar(' '); 580 } 581 (void) putchar('\n'); 582 } 583 584 command(k, v) 585 struct kinfo *k; 586 struct var *v; 587 { 588 589 if (v->next == NULL) { 590 /* last field */ 591 if (termwidth == UNLIMITED) 592 (void) printf("%s", k->ki_args); 593 else { 594 register int left = termwidth - (totwidth - v->width); 595 register char *cp = k->ki_args; 596 597 if (left < 1) /* already wrapped, just use std width */ 598 left = v->width; 599 while (--left >= 0 && *cp) 600 (void) putchar(*cp++); 601 } 602 } else 603 (void) printf("%-*.*s", v->width, v->width, k->ki_args); 604 605 } 606 607 ucomm(k, v) 608 struct kinfo *k; 609 struct var *v; 610 { 611 612 (void) printf("%-*s", v->width, k->ki_p->p_comm); 613 } 614 615 logname(k, v) 616 struct kinfo *k; 617 struct var *v; 618 { 619 620 (void) printf("%-*s", v->width, k->ki_p->p_logname); 621 } 622 623 state(k, v) 624 struct kinfo *k; 625 struct var *v; 626 { 627 char buf[16]; 628 register char *cp = buf; 629 register struct proc *p = k->ki_p; 630 register flag = p->p_flag; 631 632 switch (p->p_stat) { 633 634 case SSTOP: 635 *cp = 'T'; 636 break; 637 638 case SSLEEP: 639 if (flag & SSINTR) /* interuptable (long) */ 640 *cp = p->p_slptime >= MAXSLP ? 'I' : 'S'; 641 else 642 *cp = (flag & SPAGE) ? 'P' : 'D'; 643 break; 644 645 case SRUN: 646 case SIDL: 647 *cp = 'R'; 648 break; 649 650 case SZOMB: 651 *cp = 'Z'; 652 break; 653 654 default: 655 *cp = '?'; 656 } 657 cp++; 658 if (flag & SLOAD) { 659 if (p->p_rssize > p->p_maxrss) 660 *cp++ = '>'; 661 } else 662 *cp++ = 'W'; 663 if (p->p_nice < NZERO) 664 *cp++ = '<'; 665 else if (p->p_nice > NZERO) 666 *cp++ = 'N'; 667 if (flag & SUANOM) 668 *cp++ = 'A'; 669 else if (flag & SSEQL) 670 *cp++ = 'S'; 671 if (flag & STRC) 672 *cp++ = 'X'; 673 if (flag & SWEXIT) 674 *cp++ = 'E'; 675 if (flag & SVFORK) 676 *cp++ = 'V'; 677 if (flag & (SSYS|SLOCK|SULOCK|SKEEP|SPHYSIO)) 678 *cp++ = 'L'; 679 if (k->ki_e->e_flag & EPROC_SLEADER) 680 *cp++ = 's'; 681 if ((flag & SCTTY) && k->ki_e->e_pgid == k->ki_e->e_tpgid) 682 *cp++ = '+'; 683 *cp = '\0'; 684 (void) printf("%-*s", v->width, buf); 685 } 686 687 pri(k, v) 688 struct kinfo *k; 689 struct var *v; 690 { 691 692 (void) printf("%*d", v->width, k->ki_p->p_pri - PZERO); 693 } 694 695 uname(k, v) 696 struct kinfo *k; 697 struct var *v; 698 { 699 700 (void) printf("%-*s", v->width, user_from_uid(k->ki_p->p_uid, 0)); 701 } 702 703 runame(k, v) 704 struct kinfo *k; 705 struct var *v; 706 { 707 708 (void) printf("%-*s", v->width, user_from_uid(k->ki_p->p_ruid, 0)); 709 } 710 711 tdev(k, v) 712 struct kinfo *k; 713 struct var *v; 714 { 715 dev_t dev = k->ki_e->e_tdev; 716 717 if (dev == NODEV) 718 (void) printf("%*s", v->width, "??"); 719 else { 720 char buff[16]; 721 722 (void) sprintf(buff, "%d/%d", major(dev), minor(dev)); 723 (void) printf("%*s", v->width, buff); 724 } 725 } 726 727 extern char *devname(); 728 729 tname(k, v) 730 struct kinfo *k; 731 struct var *v; 732 { 733 dev_t dev = k->ki_e->e_tdev; 734 char *ttname; 735 736 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) 737 (void) printf("%-*s", v->width, "??"); 738 else { 739 if (strncmp(ttname, "tty", 3) == 0) 740 ttname += 3; 741 (void) printf("%*.*s%c", v->width-1, v->width-1, ttname, 742 k->ki_e->e_flag & EPROC_CTTY ? ' ' : '-'); 743 } 744 } 745 746 longtname(k, v) 747 struct kinfo *k; 748 struct var *v; 749 { 750 dev_t dev = k->ki_e->e_tdev; 751 char *ttname; 752 753 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) 754 (void) printf("%-*s", v->width, "??"); 755 else 756 (void) printf("%-*s", v->width, ttname); 757 } 758 759 #include <sys/time.h> 760 761 started(k, v) 762 struct kinfo *k; 763 struct var *v; 764 { 765 extern char *attime(); 766 767 (void) printf("%-*s", v->width, k->ki_u ? 768 attime(&k->ki_u->u_start.tv_sec) : "-"); 769 770 } 771 772 lstarted(k, v) 773 struct kinfo *k; 774 struct var *v; 775 { 776 extern char *ctime(); 777 char *tp; 778 779 if (k->ki_u) 780 (tp = ctime(&k->ki_u->u_start.tv_sec))[24] = '\0'; 781 else 782 tp = "-"; 783 (void) printf("%-*s", v->width, tp); 784 } 785 786 wchan(k, v) 787 struct kinfo *k; 788 struct var *v; 789 { 790 791 if (k->ki_p->p_wchan) { 792 if (k->ki_p->p_pri > PZERO) 793 (void) printf("%-*.*s", v->width, v->width, k->ki_e->e_wmesg); 794 else 795 (void) printf("%*x", v->width, 796 (int)k->ki_p->p_wchan &~ KERNBASE); 797 } else 798 (void) printf("%-*s", v->width, "-"); 799 } 800 801 #define pgtok(a) (((a)*NBPG)/1024) 802 #define pgtok(a) (((a)*NBPG)/1024) 803 804 vsize(k, v) 805 struct kinfo *k; 806 struct var *v; 807 { 808 809 (void) printf("%*d", v->width, 810 pgtok(k->ki_p->p_dsize + k->ki_p->p_ssize + k->ki_e->e_xsize)); 811 } 812 813 rssize(k, v) 814 struct kinfo *k; 815 struct var *v; 816 { 817 818 (void) printf("%*d", v->width, 819 pgtok(k->ki_p->p_rssize + (k->ki_e->e_xccount ? 820 (k->ki_e->e_xrssize / k->ki_e->e_xccount) : 0))); 821 } 822 823 p_rssize(k, v) /* doesn't account for text */ 824 struct kinfo *k; 825 struct var *v; 826 { 827 828 (void) printf("%*d", v->width, pgtok(k->ki_p->p_rssize)); 829 } 830 831 cputime(k, v) 832 struct kinfo *k; 833 struct var *v; 834 { 835 long secs; 836 long psecs; /* "parts" of a second. first micro, then centi */ 837 char obuff[128]; 838 839 if (k->ki_p->p_stat == SZOMB || k->ki_u == NULL) { 840 secs = 0; 841 psecs = 0; 842 } else { 843 secs = k->ki_p->p_utime.tv_sec + 844 k->ki_p->p_stime.tv_sec; 845 psecs = k->ki_p->p_utime.tv_usec + 846 k->ki_p->p_stime.tv_usec; 847 if (sumrusage) { 848 secs += k->ki_u->u_cru.ru_utime.tv_sec + 849 k->ki_u->u_cru.ru_stime.tv_sec; 850 psecs += k->ki_u->u_cru.ru_utime.tv_usec + 851 k->ki_u->u_cru.ru_stime.tv_usec; 852 } 853 /* 854 * round and scale to 100's 855 */ 856 psecs = (psecs + 5000) / 10000; 857 if (psecs >= 100) { 858 psecs -= 100; 859 secs++; 860 } 861 } 862 (void) sprintf(obuff, "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); 863 (void) printf("%*s", v->width, obuff); 864 } 865 866 double 867 getpcpu(k) 868 struct kinfo *k; 869 { 870 /* 871 * note: this routine requires ccpu and fscale 872 * be initialized. If you call this routine from 873 * somewhere new, insure that the "neednlist" flag 874 * gets set. 875 */ 876 struct proc *p = k->ki_p; 877 #define fxtofl(fixpt) ((double)(fixpt) / fscale) 878 879 if (p->p_time == 0 || (p->p_flag & SLOAD) == 0) /* XXX - I don't like this */ 880 return (0.0); 881 if (rawcpu) 882 return (100.0 * fxtofl(p->p_pctcpu)); 883 return (100.0 * fxtofl(p->p_pctcpu) / 884 (1.0 - exp(p->p_time * log(fxtofl(ccpu))))); 885 } 886 887 pcpu(k, v) 888 struct kinfo *k; 889 struct var *v; 890 { 891 892 (void) printf("%*.1f", v->width, getpcpu(k)); 893 } 894 895 double 896 getpmem(k) 897 struct kinfo *k; 898 { 899 struct proc *p = k->ki_p; 900 struct eproc *e = k->ki_e; 901 double fracmem; 902 int szptudot; 903 /* 904 * note: this routine requires that ecmx 905 * be initialized. If you call this routine from 906 * somewhere new, insure that the "neednlist" flag 907 * gets set. 908 */ 909 910 if ((p->p_flag & SLOAD) == 0) 911 return (0.0); 912 szptudot = UPAGES + clrnd(ctopt(p->p_dsize + p->p_ssize + e->e_xsize)); 913 fracmem = ((float)p->p_rssize + szptudot)/CLSIZE/ecmx; 914 if (p->p_textp && e->e_xccount) 915 fracmem += ((float)e->e_xrssize)/CLSIZE/e->e_xccount/ecmx; 916 return (100.0 * fracmem); 917 } 918 919 pmem(k, v) 920 struct kinfo *k; 921 struct var *v; 922 { 923 924 (void) printf("%*.1f", v->width, getpmem(k)); 925 } 926 927 pagein(k, v) 928 struct kinfo *k; 929 struct var *v; 930 { 931 932 (void) printf("%*d", v->width, k->ki_u ? k->ki_u->u_ru.ru_majflt : 0); 933 } 934 935 maxrss(k, v) 936 struct kinfo *k; 937 struct var *v; 938 { 939 940 if (k->ki_p->p_maxrss != (RLIM_INFINITY/NBPG)) 941 (void) printf("%*d", v->width, pgtok(k->ki_p->p_maxrss)); 942 else 943 (void) printf("%*s", v->width, "-"); 944 } 945 946 tsize(k, v) 947 struct kinfo *k; 948 struct var *v; 949 { 950 951 (void) printf("%*d", v->width, pgtok(k->ki_e->e_xsize)); 952 } 953 954 trss(k, v) 955 struct kinfo *k; 956 struct var *v; 957 { 958 959 (void) printf("%*d", v->width, pgtok(k->ki_e->e_xrssize)); 960 } 961 962 /* 963 * Generic output routines. Print fields from various prototype 964 * structures. 965 */ 966 pvar(k, v) 967 struct kinfo *k; 968 struct var *v; 969 { 970 971 printval((char *)((char *)k->ki_p + v->off), v); 972 } 973 974 evar(k, v) 975 struct kinfo *k; 976 struct var *v; 977 { 978 979 printval((char *)((char *)k->ki_e + v->off), v); 980 } 981 982 uvar(k, v) 983 struct kinfo *k; 984 struct var *v; 985 { 986 987 if (k->ki_u) 988 printval((char *)((char *)k->ki_u + v->off), v); 989 else 990 (void) printf("%*s", v->width, "-"); 991 } 992 993 rvar(k, v) 994 struct kinfo *k; 995 struct var *v; 996 { 997 998 if (k->ki_u) 999 printval((char *)((char *)(&k->ki_u->u_ru) + v->off), v); 1000 else 1001 (void) printf("%*s", v->width, "-"); 1002 } 1003 1004 char * 1005 lookupcombo(cp) 1006 char *cp; 1007 { 1008 register struct combovar *cv = &combovar[0]; 1009 1010 for (; cv->name; cv++) 1011 if (strcmp(cp, cv->name) == 0) 1012 return (cv->replace); 1013 return (NULL); 1014 } 1015 1016 struct var * 1017 lookupvar(cp) 1018 char *cp; 1019 { 1020 register int i, j; 1021 1022 for (i=0; var[i].name[0] != NULL; i++) 1023 for (j=0; var[i].name[j] != NULL; j++) 1024 if (strcmp(cp, var[i].name[j]) == 0) 1025 return (&var[i]); 1026 return (NULL); 1027 } 1028 1029 printval(bp, v) 1030 char *bp; 1031 struct var *v; 1032 { 1033 static char ofmt[32] = "%"; 1034 register char *cp = ofmt+1, *fcp = v->fmt; 1035 1036 if (v->flag & LJUST) 1037 *cp++ = '-'; 1038 *cp++ = '*'; 1039 while (*cp++ = *fcp++) 1040 ; 1041 1042 switch (v->type) { 1043 case CHAR: 1044 (void) printf(ofmt, v->width, *(char *)bp); 1045 break; 1046 1047 case UCHAR: 1048 (void) printf(ofmt, v->width, *(u_char *)bp); 1049 break; 1050 1051 case SHORT: 1052 (void) printf(ofmt, v->width, *(short *)bp); 1053 break; 1054 1055 case USHORT: 1056 (void) printf(ofmt, v->width, *(u_short *)bp); 1057 break; 1058 1059 case LONG: 1060 (void) printf(ofmt, v->width, *(long *)bp); 1061 break; 1062 1063 case ULONG: 1064 (void) printf(ofmt, v->width, *(u_long *)bp); 1065 break; 1066 1067 case KPTR: 1068 (void) printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE); 1069 break; 1070 1071 default: 1072 error("unknown type %d", v->type); 1073 } 1074 } 1075 1076 /* XXX - redo */ 1077 saveuser(ki) 1078 struct kinfo *ki; 1079 { 1080 register struct usave *usp; 1081 register struct user *up; 1082 1083 if ((usp = (struct usave *)calloc(1, sizeof (struct usave))) == NULL) { 1084 (void) fprintf(stderr, "ps: out of memory\n"); 1085 exit(1); 1086 } 1087 ki->ki_u = usp; 1088 up = kvm_getu(ki->ki_p); 1089 /* 1090 * save arguments if needed 1091 */ 1092 if (needcomm) 1093 ki->ki_args = strdup(kvm_getargs(ki->ki_p, up)); 1094 else 1095 ki->ki_args = NULL; 1096 if (up != NULL) { 1097 /* 1098 * save important fields 1099 */ 1100 usp->u_procp = up->u_procp; 1101 usp->u_start = up->u_start; 1102 usp->u_ru = up->u_ru; 1103 usp->u_cru = up->u_cru; 1104 usp->u_cmask = up->u_cmask; 1105 usp->u_acflag = up->u_acflag; 1106 } 1107 } 1108 1109 1110 pscomp(k1, k2) 1111 struct kinfo *k1, *k2; 1112 { 1113 int i; 1114 #define VSIZE(k) ((k)->ki_p->p_dsize + (k)->ki_p->p_ssize + (k)->ki_e->e_xsize) 1115 1116 if (sortby == SORTCPU) 1117 return (getpcpu(k2) - getpcpu(k1)); 1118 #ifdef notyet 1119 if (sortby == SORTRUN) 1120 return (proc_compare(k1->ki_p, k2->ki_p)); 1121 #endif 1122 if (sortby == SORTMEM) 1123 return (VSIZE(k2) - VSIZE(k1)); 1124 i = k1->ki_e->e_tdev - k2->ki_e->e_tdev; 1125 if (i == 0) 1126 i = k1->ki_p->p_pid - k2->ki_p->p_pid; 1127 return (i); 1128 } 1129 1130 donlist() 1131 { 1132 #define kread(x, v) \ 1133 kvm_read(psnl[x].n_value, (char *)&v, sizeof v) != sizeof(v) 1134 1135 if (kvm_nlist(psnl) != 0) 1136 error("can't get namelist"); 1137 if (kread(X_FSCALE, fscale)) 1138 error("error reading fscale: %s", kvm_geterr()); 1139 if (kread(X_ECMX, ecmx)) 1140 error("error reading ecmx: %s", kvm_geterr()); 1141 if (kread(X_CCPU, ccpu)) 1142 error("error reading ccpu: %s", kvm_geterr()); 1143 #undef kread 1144 } 1145 1146 #ifdef lint 1147 /* VARARGS1 */ 1148 error(fmt) char *fmt; { (void) fputs(fmt, stderr); exit(1); /* NOTREACHED */ } 1149 #else 1150 error(va_alist) 1151 va_dcl 1152 { 1153 char *fmt; 1154 va_list ap; 1155 1156 va_start(ap); 1157 fmt = va_arg(ap, char *); 1158 (void) fprintf(stderr, "ps: "); 1159 (void) vfprintf(stderr, fmt, ap); 1160 (void) fprintf(stderr, "\n"); 1161 exit(1); 1162 } 1163 #endif 1164 1165 syserror(a) 1166 char *a; 1167 { 1168 extern errno; 1169 1170 error("%s: %s", a, strerror(errno)); 1171 } 1172 1173 /* 1174 * ICK (all for getopt), would rather hide the ugliness 1175 * here than taint the main code. 1176 * 1177 * ps foo -> ps -foo 1178 * ps 34 -> ps -p34 1179 * 1180 * The old convention that 't' with no trailing tty arg means the users 1181 * tty, is only supported if argv[1] doesn't begin with a '-'. This same 1182 * feature is available with the option 'T', which takes no argument. 1183 */ 1184 char * 1185 kludge_oldps_options(s) 1186 char *s; 1187 { 1188 size_t len = strlen(s); 1189 char *newopts, *ns, *cp; 1190 1191 if ((newopts = ns = malloc(len + 2)) == NULL) 1192 error("out of memory"); 1193 /* 1194 * options begin with '-' 1195 */ 1196 if (*s != '-') 1197 *ns++ = '-'; /* add option flag */ 1198 /* 1199 * gaze to end of argv[1] 1200 */ 1201 cp = s + len - 1; 1202 /* 1203 * if last letter is a 't' flag with no argument (in the context 1204 * of the oldps options -- option string NOT starting with a '-' -- 1205 * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). 1206 */ 1207 if (*cp == 't' && *s != '-') 1208 *cp = 'T'; 1209 else { 1210 /* 1211 * otherwise check for trailing number, which *may* be a 1212 * pid. 1213 */ 1214 while (cp >= s && isdigit(*cp)) 1215 --cp; 1216 } 1217 cp++; 1218 bcopy(s, ns, (size_t)(cp - s)); /* copy up to trailing number */ 1219 ns += cp - s; 1220 /* 1221 * if there's a trailing number, and not a preceding 'p' (pid) or 1222 * 't' (tty) flag, then assume it's a pid and insert a 'p' flag. 1223 */ 1224 if (isdigit(*cp) && (cp == s || cp[-1] != 't' && cp[-1] != 'p' && 1225 (cp - 1 == s || cp[-2] != 't'))) 1226 *ns++ = 'p'; 1227 (void) strcpy(ns, cp); /* and append the number */ 1228 1229 return (newopts); 1230 } 1231