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