|
|
1.1 ! root 1: /*- ! 2: * Copyright (c) 1990 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: char copyright[] = ! 22: "@(#) Copyright (c) 1990 The Regents of the University of California.\n\ ! 23: All rights reserved.\n"; ! 24: #endif /* not lint */ ! 25: ! 26: #ifndef lint ! 27: static char sccsid[] = "@(#)ps.c 5.28 (Berkeley) 6/26/90"; ! 28: #endif /* not lint */ ! 29: ! 30: #include <machine/pte.h> ! 31: ! 32: #include <sys/param.h> ! 33: #include <sys/ioctl.h> ! 34: #include <sys/tty.h> ! 35: #include <sys/user.h> ! 36: #include <sys/proc.h> ! 37: #include <sys/vm.h> ! 38: #include <sys/text.h> ! 39: #include <sys/stat.h> ! 40: #include <sys/mbuf.h> ! 41: #include <nlist.h> ! 42: #include <pwd.h> ! 43: #include <math.h> ! 44: #include <errno.h> ! 45: #include <stdio.h> ! 46: #include <ctype.h> ! 47: #include <kvm.h> ! 48: ! 49: struct usave { ! 50: struct proc *u_procp; ! 51: struct timeval u_start; ! 52: struct rusage u_ru; ! 53: struct rusage u_cru; ! 54: short u_cmask; ! 55: char u_acflag; ! 56: }; ! 57: ! 58: /* ! 59: * to compute offset in common structures ! 60: */ ! 61: #define POFF(x) ((int)&((struct proc *)0)->x) ! 62: #define EOFF(x) ((int)&((struct eproc *)0)->x) ! 63: #define UOFF(x) ((int)&((struct usave *)0)->x) ! 64: #define ROFF(x) ((int)&((struct rusage *)0)->x) ! 65: ! 66: enum type { CHAR, UCHAR, SHORT, USHORT, LONG, ULONG, KPTR }; ! 67: ! 68: #define UIDFMT "u" ! 69: #define UIDLEN 5 ! 70: #define PIDFMT "d" ! 71: #define PIDLEN 5 ! 72: #define USERLEN 8 ! 73: ! 74: int needuser, needcomm, neednlist; ! 75: ! 76: int command(), ucomm(), logname(), pvar(), evar(), uvar(), rvar(), uname(), ! 77: runame(), state(), pri(), tdev(), tname(), longtname(), started(), ! 78: lstarted(), wchan(), vsize(), rssize(), p_rssize(), cputime(), ! 79: pmem(), pcpu(), pagein(), maxrss(), tsize(), trss(); ! 80: /** ! 81: utime(), stime(), ixrss(), idrss(), isrss(); ! 82: **/ ! 83: ! 84: struct usave *saveuser(); ! 85: char *saveargs(); ! 86: ! 87: struct var { ! 88: char *name[8]; /* name(s) of variable */ ! 89: char *header; /* default header */ ! 90: int flag; ! 91: #define USER 0x01 /* requires user structure */ ! 92: #define LJUST 0x02 /* right adjust on output */ ! 93: #define COMM 0x04 /* requires exec arguments and environment (XXX) */ ! 94: #define NLIST 0x08 /* requires nlist to get extra variables */ ! 95: int (*oproc)(); /* output routine */ ! 96: short width; /* printing width */ ! 97: /* ! 98: * The following (optional) elements are hooks for passing information ! 99: * to the generic output routines: pvar, evar, uvar (those which print ! 100: * simple elements from well known structures: proc, eproc, usave) ! 101: */ ! 102: int off; /* offset in structure */ ! 103: enum type type; /* type of element */ ! 104: char *fmt; /* printf format */ ! 105: /* ! 106: * glue to link selected fields together ! 107: */ ! 108: struct var *next; ! 109: } var[] = { ! 110: {{"command", "comm", "args"}, "COMMAND", USER|LJUST|COMM, ! 111: command, 16}, ! 112: {{"ucomm"}, "COMMAND", LJUST, ucomm, MAXCOMLEN}, ! 113: {{"logname"}, "LOGNAME", LJUST, logname, MAXLOGNAME}, ! 114: {{"flag", "f"}, "F", 0, pvar, 7, POFF(p_flag), LONG, "x"}, ! 115: {{"uid"}, "UID", 0, pvar, UIDLEN, POFF(p_uid),USHORT, UIDFMT}, ! 116: {{"ruid"}, "RUID", 0, pvar, UIDLEN, POFF(p_ruid), USHORT, UIDFMT}, ! 117: {{"svuid"}, "SVUID", 0, pvar, UIDLEN, POFF(p_svuid), USHORT, UIDFMT}, ! 118: {{"rgid"}, "RGID", 0, pvar, UIDLEN, POFF(p_rgid), USHORT, UIDFMT}, ! 119: {{"svgid"}, "SVGID", 0, pvar, UIDLEN, POFF(p_svgid), USHORT, UIDFMT}, ! 120: {{"pid"}, "PID", 0, pvar, PIDLEN, POFF(p_pid),SHORT, PIDFMT}, ! 121: {{"ppid"}, "PPID", 0, pvar, PIDLEN, POFF(p_ppid), SHORT, PIDFMT}, ! 122: {{"cp", "cpu"}, "CP", 0, pvar, 3, POFF(p_cpu), UCHAR, "d"}, ! 123: {{"xstat"}, "XSTAT", 0, pvar, 4, POFF(p_xstat), USHORT, "x"}, ! 124: {{"poip"}, "POIP", 0, pvar, 4, POFF(p_poip), SHORT, "d"}, ! 125: {{"nwchan"}, "WCHAN", 0, pvar, 6, POFF(p_wchan), KPTR, "x"}, ! 126: {{"wchan"}, "WCHAN", LJUST, wchan, 6}, ! 127: {{"rlink"}, "RLINK", 0, pvar, 8, POFF(p_rlink), KPTR, "x"}, ! 128: {{"ktrace", "traceflag"}, "KTRACE", ! 129: 0, pvar, 8, POFF(p_traceflag), LONG, "x"}, ! 130: {{"ktracep", "tracep"}, "KTRACEP", ! 131: 0, pvar, 8, POFF(p_tracep), LONG, "x"}, ! 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 "uid pid sig sigmask sigignore sigcatch stat 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:SCLmrhTg")) != 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: xflg++; ! 375: break; ! 376: case 'S': ! 377: sumrusage++; ! 378: break; ! 379: case 'C': ! 380: rawcpu++; ! 381: break; ! 382: case 'L': { ! 383: int i = 0; ! 384: struct combovar *cb = &combovar[0]; ! 385: char *cp; ! 386: ! 387: v = &var[0]; ! 388: for (;;) { ! 389: if (v->name[0] != NULL) { ! 390: cp = v->name[0]; ! 391: v++; ! 392: } else if (cb->name != NULL) { ! 393: cp = cb->name; ! 394: cb++; ! 395: } else ! 396: break; ! 397: if (termwidth && ! 398: (i += strlen(cp)+1) > termwidth) ! 399: i = strlen(cp), printf("\n"); ! 400: printf("%s ", cp); ! 401: } ! 402: printf("\n"); ! 403: exit(0); ! 404: } ! 405: case 'a': ! 406: all++; ! 407: break; ! 408: case 'x': ! 409: xflg++; ! 410: break; ! 411: case 'm': ! 412: sortby = SORTMEM; ! 413: break; ! 414: case 'r': ! 415: sortby = SORTCPU; ! 416: break; ! 417: case 'h': ! 418: prtheader = ws.ws_row > 5 ? ws.ws_row : 22; ! 419: break; ! 420: case 'g': ! 421: break; /* no-op */ ! 422: case '?': ! 423: default: ! 424: fprintf(stderr, "usage: %s\n", USAGE); ! 425: exit(1); ! 426: } ! 427: argc -= optind; ! 428: argv += optind; ! 429: ! 430: if (*argv) { ! 431: char *nlistf, *memf = NULL, *swapf = NULL; ! 432: ! 433: nlistf = *argv++; ! 434: if (*argv) { ! 435: memf = *argv++; ! 436: if (*argv) ! 437: swapf = *argv++; ! 438: } ! 439: if (kvm_openfiles(nlistf, memf, swapf) == -1) ! 440: error("kvm_openfiles: %s", kvm_geterr()); ! 441: } ! 442: ! 443: if (!fmt) ! 444: parsefmt(DFMT); ! 445: ! 446: if (!all && ttydev == NODEV && pid == -1) /* XXX - should be cleaner */ ! 447: uid = getuid(); ! 448: ! 449: /* ! 450: * scan requested variables, noting what structures are needed, ! 451: * and adjusting header widths as appropiate. ! 452: */ ! 453: scanvars(); ! 454: #ifdef notdef ! 455: if (sortby == SORTCPU) ! 456: neednlist = 1; ! 457: #endif ! 458: if (neednlist) ! 459: donlist(); ! 460: /* ! 461: * get proc list ! 462: */ ! 463: if (uid != -1) { ! 464: what = KINFO_PROC_UID; ! 465: flag = uid; ! 466: } else if (ttydev != NODEV) { ! 467: what = KINFO_PROC_TTY; ! 468: flag = ttydev; ! 469: } else if (pid != -1) { ! 470: what = KINFO_PROC_PID; ! 471: flag = pid; ! 472: } else ! 473: what = KINFO_PROC_ALL; ! 474: /* ! 475: * select procs ! 476: */ ! 477: if ((nentries = kvm_getprocs(what, flag)) == -1) { ! 478: fprintf(stderr, "ps: %s\n", kvm_geterr()); ! 479: exit(1); ! 480: } ! 481: kinfo = (struct kinfo *)malloc(nentries * sizeof (struct kinfo)); ! 482: if (kinfo == NULL) ! 483: error("out of memory"); ! 484: i = 0; ! 485: while ((p = kvm_nextproc()) != NULL) { ! 486: kinfo[i].ki_p = p; ! 487: kinfo[i].ki_e = kvm_geteproc(p); ! 488: if (needuser) ! 489: saveuser(&kinfo[i]); ! 490: i++; ! 491: } ! 492: nentries = i; ! 493: /* ! 494: * print header ! 495: */ ! 496: printheader(); ! 497: if (nentries == 0) ! 498: exit(0); ! 499: /* ! 500: * sort proc list ! 501: */ ! 502: qsort(kinfo, nentries, sizeof (struct kinfo), pscomp); ! 503: /* ! 504: * for each proc, call each variable output function. ! 505: */ ! 506: for (i = 0; i < nentries; i++) { ! 507: if (xflg == 0 && (kinfo[i].ki_e->e_tdev == NODEV || ! 508: (kinfo[i].ki_p->p_flag & SCTTY ) == 0)) ! 509: continue; ! 510: for (v = vhead; v != NULL; v = v->next) { ! 511: (*v->oproc)(&kinfo[i], v); ! 512: if (v->next != NULL) ! 513: putchar(' '); ! 514: } ! 515: putchar('\n'); ! 516: if (prtheader && lineno++ == prtheader-4) { ! 517: putchar('\n'); ! 518: printheader(); ! 519: lineno = 0; ! 520: } ! 521: } ! 522: ! 523: exit(0); ! 524: } ! 525: ! 526: #define FMTSEP " \t,\n" ! 527: ! 528: parsefmt(fmt) ! 529: char *fmt; ! 530: { ! 531: register char *f = fmt, *cp, *hp; ! 532: struct var *v; ! 533: char *strtok(), *index(); ! 534: char newbuf[1024], *nb = newbuf; /* XXX */ ! 535: char *lookupcombo(); ! 536: struct var *lookupvar(); ! 537: ! 538: /* ! 539: * strtok is not &^%^& re-entrant, so we have ! 540: * only one level of expansion, looking for combo ! 541: * variables once here, and expanding the string ! 542: * before really parsing it. With strtok_r, ! 543: * you would move the expansion to before the ! 544: * lookupvar inside the 2nd while loop with a ! 545: * recursive call to parsefmt. ! 546: */ ! 547: while ((cp = strtok(f, FMTSEP)) != NULL) { ! 548: if ((hp = lookupcombo(cp)) == NULL); ! 549: hp = cp; ! 550: if (((nb + strlen(hp)) - newbuf) >= 1024) ! 551: error("format too large"); ! 552: strcpy(nb, hp); ! 553: while (*nb) ! 554: nb++; ! 555: *nb++ = ' '; ! 556: *nb = '\0'; ! 557: f = NULL; ! 558: } ! 559: f = newbuf; ! 560: while ((cp = strtok(f, FMTSEP)) != NULL) { ! 561: if (hp = index(cp, '=')) ! 562: *hp++ = '\0'; ! 563: v = lookupvar(cp); ! 564: if (v == NULL) ! 565: error("unknown variable in format: %s", cp); ! 566: if (v->next != NULL || vtail == v) ! 567: error("can't specify a variable twice: %s", cp); ! 568: if (hp) ! 569: v->header = hp; ! 570: if (vhead == NULL) ! 571: vhead = vtail = v; ! 572: else { ! 573: vtail->next = v; ! 574: vtail = v; ! 575: } ! 576: f = NULL; /* for strtok */ ! 577: } ! 578: ! 579: } ! 580: ! 581: scanvars() ! 582: { ! 583: register i; ! 584: register struct var *v; ! 585: ! 586: for (v = vhead; v != NULL; v = v->next) { ! 587: i = strlen(v->header); ! 588: if (v->width < i) ! 589: v->width = i; ! 590: totwidth += v->width + 1; /* +1 for space */ ! 591: if (v->flag & USER) ! 592: needuser = 1; ! 593: if (v->flag & COMM) ! 594: needcomm = 1; ! 595: if (v->flag & NLIST) ! 596: neednlist = 1; ! 597: } ! 598: totwidth--; ! 599: } ! 600: printheader() ! 601: { ! 602: register struct var *v; ! 603: ! 604: for (v = vhead; v != NULL; v = v->next) { ! 605: if (v->flag & LJUST) { ! 606: if (v->next == NULL) /* last one */ ! 607: printf("%s", v->header); ! 608: else ! 609: printf("%-*s",v->width, v->header); ! 610: } else ! 611: printf("%*s",v->width, v->header); ! 612: if (v->next != NULL) ! 613: putchar(' '); ! 614: } ! 615: putchar('\n'); ! 616: } ! 617: ! 618: command(k, v) ! 619: struct kinfo *k; ! 620: struct var *v; ! 621: { ! 622: ! 623: if (v->next == NULL) { ! 624: /* last field */ ! 625: if (termwidth == UNLIMITED) ! 626: printf("%s", k->ki_args); ! 627: else { ! 628: register left = termwidth - (totwidth - v->width); ! 629: register char *cp = k->ki_args; ! 630: ! 631: if (left < 1) /* already wrapped, just use std width */ ! 632: left = v->width; ! 633: while (left-- && *cp) ! 634: putchar(*cp++); ! 635: } ! 636: } else ! 637: printf("%-*.*s", v->width, v->width, k->ki_args); ! 638: ! 639: } ! 640: ! 641: ucomm(k, v) ! 642: struct kinfo *k; ! 643: struct var *v; ! 644: { ! 645: ! 646: printf("%-*s", v->width, k->ki_p->p_comm); ! 647: } ! 648: ! 649: logname(k, v) ! 650: struct kinfo *k; ! 651: struct var *v; ! 652: { ! 653: ! 654: printf("%-*s", v->width, k->ki_p->p_logname); ! 655: } ! 656: ! 657: state(k, v) ! 658: struct kinfo *k; ! 659: struct var *v; ! 660: { ! 661: char buf[16]; ! 662: register char *cp = buf; ! 663: register struct proc *p = k->ki_p; ! 664: register flag = p->p_flag; ! 665: ! 666: switch (p->p_stat) { ! 667: ! 668: case SSTOP: ! 669: *cp = 'T'; ! 670: break; ! 671: ! 672: case SSLEEP: ! 673: if (flag & SSINTR) /* interuptable (long) */ ! 674: *cp = p->p_slptime >= MAXSLP ? 'I' : 'S'; ! 675: else ! 676: *cp = (flag & SPAGE) ? 'P' : 'D'; ! 677: break; ! 678: ! 679: case SRUN: ! 680: case SIDL: ! 681: *cp = 'R'; ! 682: break; ! 683: ! 684: case SZOMB: ! 685: *cp = 'Z'; ! 686: break; ! 687: ! 688: default: ! 689: *cp = '?'; ! 690: } ! 691: cp++; ! 692: if (flag & SLOAD) { ! 693: if (p->p_rssize > p->p_maxrss) ! 694: *cp++ = '>'; ! 695: } else ! 696: *cp++ = 'W'; ! 697: if (p->p_nice < NZERO) ! 698: *cp++ = '<'; ! 699: else if (p->p_nice > NZERO) ! 700: *cp++ = 'N'; ! 701: if (flag & SUANOM) ! 702: *cp++ = 'A'; ! 703: else if (flag & SSEQL) ! 704: *cp++ = 'S'; ! 705: if (flag & STRC) ! 706: *cp++ = 'X'; ! 707: if (flag & SWEXIT) ! 708: *cp++ = 'E'; ! 709: if (flag & SVFORK) ! 710: *cp++ = 'V'; ! 711: if (flag & (SSYS|SLOCK|SULOCK|SKEEP|SPHYSIO)) ! 712: *cp++ = 'L'; ! 713: if (k->ki_e->e_flag & EPROC_SLEADER) ! 714: *cp++ = 's'; ! 715: if ((flag & SCTTY) && k->ki_e->e_pgid == k->ki_e->e_tpgid) ! 716: *cp++ = '+'; ! 717: *cp = '\0'; ! 718: printf("%-*s", v->width, buf); ! 719: } ! 720: ! 721: pri(k, v) ! 722: struct kinfo *k; ! 723: struct var *v; ! 724: { ! 725: ! 726: printf("%*d", v->width, k->ki_p->p_pri - PZERO); ! 727: } ! 728: ! 729: uname(k, v) ! 730: struct kinfo *k; ! 731: struct var *v; ! 732: { ! 733: ! 734: printf("%-*s", v->width, user_from_uid(k->ki_p->p_uid, 0)); ! 735: } ! 736: ! 737: runame(k, v) ! 738: struct kinfo *k; ! 739: struct var *v; ! 740: { ! 741: ! 742: printf("%-*s", v->width, user_from_uid(k->ki_p->p_ruid, 0)); ! 743: } ! 744: ! 745: tdev(k, v) ! 746: struct kinfo *k; ! 747: struct var *v; ! 748: { ! 749: dev_t dev = k->ki_e->e_tdev; ! 750: ! 751: if (dev == NODEV) ! 752: printf("%*s", v->width, "??"); ! 753: else { ! 754: char buff[16]; ! 755: ! 756: sprintf(buff, "%d/%d", major(dev), minor(dev)); ! 757: printf("%*s", v->width, buff); ! 758: } ! 759: } ! 760: ! 761: extern char *devname(); ! 762: ! 763: tname(k, v) ! 764: struct kinfo *k; ! 765: struct var *v; ! 766: { ! 767: dev_t dev = k->ki_e->e_tdev; ! 768: char *tname; ! 769: ! 770: if (dev == NODEV || (tname = devname(dev, S_IFCHR)) == NULL) ! 771: printf("%-*s", v->width, "??"); ! 772: else { ! 773: if (strncmp(tname, "tty", 3) == 0) ! 774: tname += 3; ! 775: printf("%*.*s%c", v->width-1, v->width-1, tname, ! 776: k->ki_e->e_flag & EPROC_CTTY ? ' ' : '-'); ! 777: } ! 778: } ! 779: ! 780: longtname(k, v) ! 781: struct kinfo *k; ! 782: struct var *v; ! 783: { ! 784: dev_t dev = k->ki_e->e_tdev; ! 785: char *tname; ! 786: ! 787: if (dev == NODEV || (tname = devname(dev, S_IFCHR)) == NULL) ! 788: printf("%-*s", v->width, "??"); ! 789: else ! 790: printf("%-*s", v->width, tname); ! 791: } ! 792: ! 793: #include <sys/time.h> ! 794: ! 795: started(k, v) ! 796: struct kinfo *k; ! 797: struct var *v; ! 798: { ! 799: extern char *attime(); ! 800: ! 801: printf("%-*s", v->width, k->ki_u ? ! 802: attime(&k->ki_u->u_start.tv_sec) : "-"); ! 803: ! 804: } ! 805: ! 806: lstarted(k, v) ! 807: struct kinfo *k; ! 808: struct var *v; ! 809: { ! 810: extern char *ctime(); ! 811: char *tp; ! 812: ! 813: if (k->ki_u) ! 814: (tp = ctime(&k->ki_u->u_start.tv_sec))[24] = '\0'; ! 815: else ! 816: tp = "-"; ! 817: printf("%-*s", v->width, tp); ! 818: } ! 819: ! 820: wchan(k, v) ! 821: struct kinfo *k; ! 822: struct var *v; ! 823: { ! 824: ! 825: if (k->ki_p->p_wchan) { ! 826: if (k->ki_p->p_pri > PZERO) ! 827: printf("%-*.*s", v->width, v->width, k->ki_e->e_wmesg); ! 828: else ! 829: printf("%*x", v->width, ! 830: (int)k->ki_p->p_wchan &~ KERNBASE); ! 831: } else ! 832: printf("%-*s", v->width, "-"); ! 833: } ! 834: ! 835: #define pgtok(a) (((a)*NBPG)/1024) ! 836: #define pgtok(a) (((a)*NBPG)/1024) ! 837: ! 838: vsize(k, v) ! 839: struct kinfo *k; ! 840: struct var *v; ! 841: { ! 842: ! 843: printf("%*d", v->width, ! 844: pgtok(k->ki_p->p_dsize + k->ki_p->p_ssize + k->ki_e->e_xsize)); ! 845: } ! 846: ! 847: rssize(k, v) ! 848: struct kinfo *k; ! 849: struct var *v; ! 850: { ! 851: ! 852: printf("%*d", v->width, ! 853: pgtok(k->ki_p->p_rssize + (k->ki_e->e_xccount ? ! 854: (k->ki_e->e_xrssize / k->ki_e->e_xccount) : 0))); ! 855: } ! 856: ! 857: p_rssize(k, v) /* doesn't account for text */ ! 858: struct kinfo *k; ! 859: struct var *v; ! 860: { ! 861: ! 862: printf("%*d", v->width, pgtok(k->ki_p->p_rssize)); ! 863: } ! 864: ! 865: cputime(k, v) ! 866: struct kinfo *k; ! 867: struct var *v; ! 868: { ! 869: long secs; ! 870: long psecs; /* "parts" of a second. first micro, then centi */ ! 871: char obuff[128]; ! 872: ! 873: if (k->ki_p->p_stat == SZOMB || k->ki_u == NULL) { ! 874: secs = 0; ! 875: psecs = 0; ! 876: } else { ! 877: secs = k->ki_p->p_utime.tv_sec + ! 878: k->ki_p->p_stime.tv_sec; ! 879: psecs = k->ki_p->p_utime.tv_usec + ! 880: k->ki_p->p_stime.tv_usec; ! 881: if (sumrusage) { ! 882: secs += k->ki_u->u_cru.ru_utime.tv_sec + ! 883: k->ki_u->u_cru.ru_stime.tv_sec; ! 884: psecs += k->ki_u->u_cru.ru_utime.tv_usec + ! 885: k->ki_u->u_cru.ru_stime.tv_usec; ! 886: } ! 887: /* ! 888: * round and scale to 100's ! 889: */ ! 890: psecs = (psecs + 5000) / 10000; ! 891: if (psecs >= 100) { ! 892: psecs -= 100; ! 893: secs++; ! 894: } ! 895: } ! 896: sprintf(obuff, "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); ! 897: printf("%*s", v->width, obuff); ! 898: } ! 899: ! 900: double ! 901: getpcpu(k) ! 902: struct kinfo *k; ! 903: { ! 904: /* ! 905: * note: this routine requires ccpu and fscale ! 906: * be initialized. If you call this routine from ! 907: * somewhere new, insure that the "neednlist" flag ! 908: * gets set. ! 909: */ ! 910: struct proc *p = k->ki_p; ! 911: #define fxtofl(fixpt) ((double)(fixpt) / fscale) ! 912: ! 913: if (p->p_time == 0 || (p->p_flag & SLOAD) == 0) /* XXX - I don't like this */ ! 914: return (0.0); ! 915: if (rawcpu) ! 916: return (100.0 * fxtofl(p->p_pctcpu)); ! 917: return (100.0 * fxtofl(p->p_pctcpu) / ! 918: (1.0 - exp(p->p_time * log(fxtofl(ccpu))))); ! 919: } ! 920: ! 921: pcpu(k, v) ! 922: struct kinfo *k; ! 923: struct var *v; ! 924: { ! 925: ! 926: printf("%*.1f", v->width, getpcpu(k)); ! 927: } ! 928: ! 929: double ! 930: getpmem(k, v) ! 931: struct kinfo *k; ! 932: struct var *v; ! 933: { ! 934: struct proc *p = k->ki_p; ! 935: struct eproc *e = k->ki_e; ! 936: double fracmem; ! 937: int szptudot; ! 938: /* ! 939: * note: this routine requires that ecmx ! 940: * be initialized. If you call this routine from ! 941: * somewhere new, insure that the "neednlist" flag ! 942: * gets set. ! 943: */ ! 944: ! 945: if (p->p_flag & SLOAD == 0) ! 946: return (0.0); ! 947: szptudot = UPAGES + clrnd(ctopt(p->p_dsize + p->p_ssize + e->e_xsize)); ! 948: fracmem = ((float)p->p_rssize + szptudot)/CLSIZE/ecmx; ! 949: if (p->p_textp && e->e_xccount) ! 950: fracmem += ((float)e->e_xrssize)/CLSIZE/e->e_xccount/ecmx; ! 951: return (100.0 * fracmem); ! 952: } ! 953: ! 954: pmem(k, v) ! 955: struct kinfo *k; ! 956: struct var *v; ! 957: { ! 958: ! 959: printf("%*.1f", v->width, getpmem(k)); ! 960: } ! 961: ! 962: pagein(k, v) ! 963: struct kinfo *k; ! 964: struct var *v; ! 965: { ! 966: ! 967: printf("%*d", v->width, k->ki_u ? k->ki_u->u_ru.ru_majflt : 0); ! 968: } ! 969: ! 970: maxrss(k, v) ! 971: struct kinfo *k; ! 972: struct var *v; ! 973: { ! 974: ! 975: if (k->ki_p->p_maxrss != (RLIM_INFINITY/NBPG)) ! 976: printf("%*d", v->width, pgtok(k->ki_p->p_maxrss)); ! 977: else ! 978: printf("%*s", v->width, "-"); ! 979: } ! 980: ! 981: tsize(k, v) ! 982: struct kinfo *k; ! 983: struct var *v; ! 984: { ! 985: ! 986: printf("%*d", v->width, pgtok(k->ki_e->e_xsize)); ! 987: } ! 988: ! 989: trss(k, v) ! 990: struct kinfo *k; ! 991: struct var *v; ! 992: { ! 993: ! 994: printf("%*d", v->width, pgtok(k->ki_e->e_xrssize)); ! 995: } ! 996: ! 997: /* ! 998: * Generic output routines. Print fields from various prototype ! 999: * structures. ! 1000: */ ! 1001: pvar(k, v) ! 1002: struct kinfo *k; ! 1003: struct var *v; ! 1004: { ! 1005: ! 1006: printval((char *)((char *)k->ki_p + v->off), v); ! 1007: } ! 1008: ! 1009: evar(k, v) ! 1010: struct kinfo *k; ! 1011: struct var *v; ! 1012: { ! 1013: ! 1014: printval((char *)((char *)k->ki_e + v->off), v); ! 1015: } ! 1016: ! 1017: uvar(k, v) ! 1018: struct kinfo *k; ! 1019: struct var *v; ! 1020: { ! 1021: ! 1022: if (k->ki_u) ! 1023: printval((char *)((char *)k->ki_u + v->off), v); ! 1024: else ! 1025: printf("%*s", v->width, "-"); ! 1026: } ! 1027: ! 1028: rvar(k, v) ! 1029: struct kinfo *k; ! 1030: struct var *v; ! 1031: { ! 1032: ! 1033: if (k->ki_u) ! 1034: printval((char *)((char *)(&k->ki_u->u_ru) + v->off), v); ! 1035: else ! 1036: printf("%*s", v->width, "-"); ! 1037: } ! 1038: ! 1039: char * ! 1040: lookupcombo(cp) ! 1041: char *cp; ! 1042: { ! 1043: register struct combovar *cv = &combovar[0]; ! 1044: ! 1045: for (; cv->name; cv++) ! 1046: if (strcmp(cp, cv->name) == 0) ! 1047: return (cv->replace); ! 1048: return (NULL); ! 1049: } ! 1050: ! 1051: struct var * ! 1052: lookupvar(cp) ! 1053: char *cp; ! 1054: { ! 1055: register int i, j; ! 1056: ! 1057: for (i=0; var[i].name[0] != NULL; i++) ! 1058: for (j=0; var[i].name[j] != NULL; j++) ! 1059: if (strcmp(cp, var[i].name[j]) == 0) ! 1060: return (&var[i]); ! 1061: return (NULL); ! 1062: } ! 1063: ! 1064: printval(bp, v) ! 1065: char *bp; ! 1066: struct var *v; ! 1067: { ! 1068: static char ofmt[32] = "%"; ! 1069: register char *cp = ofmt+1, *fcp = v->fmt; ! 1070: ! 1071: if (v->flag & LJUST) ! 1072: *cp++ = '-'; ! 1073: *cp++ = '*'; ! 1074: while (*cp++ = *fcp++) ! 1075: ; ! 1076: ! 1077: switch (v->type) { ! 1078: case CHAR: ! 1079: printf(ofmt, v->width, *(char *)bp); ! 1080: break; ! 1081: ! 1082: case UCHAR: ! 1083: printf(ofmt, v->width, *(u_char *)bp); ! 1084: break; ! 1085: ! 1086: case SHORT: ! 1087: printf(ofmt, v->width, *(short *)bp); ! 1088: break; ! 1089: ! 1090: case USHORT: ! 1091: printf(ofmt, v->width, *(u_short *)bp); ! 1092: break; ! 1093: ! 1094: case LONG: ! 1095: printf(ofmt, v->width, *(long *)bp); ! 1096: break; ! 1097: ! 1098: case ULONG: ! 1099: printf(ofmt, v->width, *(u_long *)bp); ! 1100: break; ! 1101: ! 1102: case KPTR: ! 1103: printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE); ! 1104: break; ! 1105: ! 1106: default: ! 1107: error("unknown type %d", v->type); ! 1108: } ! 1109: } ! 1110: ! 1111: /* XXX - redo */ ! 1112: struct usave * ! 1113: saveuser(ki) ! 1114: struct kinfo *ki; ! 1115: { ! 1116: register struct usave *usp; ! 1117: register struct user *up; ! 1118: ! 1119: if ((usp = (struct usave *)calloc(1, sizeof (struct usave))) == NULL) { ! 1120: fprintf(stderr, "ps: out of memory\n"); ! 1121: exit(1); ! 1122: } ! 1123: ki->ki_u = usp; ! 1124: up = kvm_getu(ki->ki_p); ! 1125: /* ! 1126: * save arguments if needed ! 1127: */ ! 1128: if (needcomm) ! 1129: ki->ki_args = saveargs(ki->ki_p, up); ! 1130: else ! 1131: ki->ki_args = NULL; ! 1132: if (up != NULL) { ! 1133: /* ! 1134: * save important fields ! 1135: */ ! 1136: usp->u_procp = up->u_procp; ! 1137: usp->u_start = up->u_start; ! 1138: usp->u_ru = up->u_ru; ! 1139: usp->u_cru = up->u_cru; ! 1140: usp->u_cmask = up->u_cmask; ! 1141: usp->u_acflag = up->u_acflag; ! 1142: } ! 1143: return; ! 1144: } ! 1145: ! 1146: char * ! 1147: saveargs(p, up) ! 1148: struct proc *p; ! 1149: struct user *up; ! 1150: { ! 1151: char *savestr(); ! 1152: ! 1153: return(savestr(kvm_getargs(p, up))); ! 1154: } ! 1155: ! 1156: ! 1157: pscomp(k1, k2) ! 1158: struct kinfo *k1, *k2; ! 1159: { ! 1160: int i; ! 1161: #define VSIZE(k) ((k)->ki_p->p_dsize + (k)->ki_p->p_ssize + (k)->ki_e->e_xsize) ! 1162: ! 1163: if (sortby == SORTCPU) ! 1164: return (getpcpu(k2) - getpcpu(k1)); ! 1165: #ifdef notyet ! 1166: if (sortby == SORTRUN) ! 1167: return (proc_compare(k1->ki_p, k2->ki_p)); ! 1168: #endif ! 1169: if (sortby == SORTMEM) ! 1170: return (VSIZE(k2) - VSIZE(k1)); ! 1171: i = k1->ki_e->e_tdev - k2->ki_e->e_tdev; ! 1172: if (i == 0) ! 1173: i = k1->ki_p->p_pid - k2->ki_p->p_pid; ! 1174: return (i); ! 1175: } ! 1176: ! 1177: donlist() ! 1178: { ! 1179: if (kvm_nlist(psnl) != 0) ! 1180: error("can't get namelist"); ! 1181: if (kvm_read(psnl[X_FSCALE].n_value, &fscale, sizeof(int)) != ! 1182: sizeof (int)) ! 1183: error("error reading fscale: %s", kvm_geterr()); ! 1184: if (kvm_read(psnl[X_ECMX].n_value, &ecmx, sizeof(int)) != ! 1185: sizeof (int)) ! 1186: error("error reading ecmx: %s", kvm_geterr()); ! 1187: if (kvm_read(psnl[X_CCPU].n_value, &ccpu, sizeof(fixpt_t)) != ! 1188: sizeof (fixpt_t)) ! 1189: error("error reading ccpu: %s", kvm_geterr()); ! 1190: } ! 1191: ! 1192: char * ! 1193: savestr(cp) ! 1194: char *cp; ! 1195: { ! 1196: register unsigned len; ! 1197: register char *dp; ! 1198: ! 1199: len = strlen(cp); ! 1200: dp = (char *)calloc(len+1, sizeof (char)); ! 1201: (void) strcpy(dp, cp); ! 1202: return (dp); ! 1203: } ! 1204: ! 1205: error(a, b, c, d, e) ! 1206: char *a, *b, *c, *d, *e; ! 1207: { ! 1208: fprintf(stderr, "ps: "); ! 1209: fprintf(stderr, a, b, c, d, e); ! 1210: fprintf(stderr, "\n"); ! 1211: exit(1); ! 1212: } ! 1213: ! 1214: syserror(a) ! 1215: char *a; ! 1216: { ! 1217: extern errno; ! 1218: ! 1219: error("%s: %s", a, strerror(errno)); ! 1220: } ! 1221: ! 1222: /* ! 1223: * ICK (all for getopt), would rather hide the ugliness ! 1224: * here than taint the main code. ! 1225: * ! 1226: * ps foo -> ps -foo ! 1227: * ps 34 -> ps -p34 ! 1228: * ! 1229: * The old convention that 't' with no trailing tty arg means the users ! 1230: * tty, is only supported if argv[1] doesn't begin with a '-'. This same ! 1231: * feature is available with the option 'T', which takes no argument. ! 1232: */ ! 1233: char * ! 1234: kludge_oldps_options(s) ! 1235: char *s; ! 1236: { ! 1237: int len = strlen(s), numlen = 0; ! 1238: char *newopts, *ns, *cp; ! 1239: ! 1240: if ((newopts = ns = (char *)malloc(len+2)) == NULL) ! 1241: error("out of memory"); ! 1242: /* ! 1243: * options begin with '-' ! 1244: */ ! 1245: if (*s != '-') ! 1246: *ns++ = '-'; /* add option flag */ ! 1247: /* ! 1248: * gaze to end of argv[1] ! 1249: */ ! 1250: cp = s + len - 1; ! 1251: /* ! 1252: * if last letter is a 't' flag with no argument (in the context ! 1253: * of the oldps options -- option string NOT starting with a '-' -- ! 1254: * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0). ! 1255: */ ! 1256: if (*cp == 't' && *s != '-') ! 1257: *cp = 'T'; ! 1258: else { ! 1259: /* ! 1260: * otherwise check for trailing number, which *may* be a ! 1261: * pid. ! 1262: */ ! 1263: while (isdigit(*cp)) { ! 1264: --cp; ! 1265: numlen++; ! 1266: } ! 1267: } ! 1268: cp++; ! 1269: bcopy(s, ns, cp - s); /* copy everything up to trailing number */ ! 1270: while (*ns) ! 1271: ns++; ! 1272: /* ! 1273: * if there's a trailing number, and not a preceding 'p' (pid) or ! 1274: * 't' (tty) flag, then assume it's a pid and insert a 'p' flag. ! 1275: */ ! 1276: if (isdigit(*cp) && (cp == s || *(cp-1) != 't' && *(cp-1) != 'p' && ! 1277: ((cp-1) == s || *(cp-2) != 't'))) ! 1278: *ns++ = 'p'; ! 1279: strcat(ns, cp); /* and append the number */ ! 1280: ! 1281: return (newopts); ! 1282: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.