ps.c revision 81743
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1990, 1993, 1994 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * Redistribution and use in source and binary forms, with or without 61556Srgrimes * modification, are permitted provided that the following conditions 71556Srgrimes * are met: 81556Srgrimes * 1. Redistributions of source code must retain the above copyright 91556Srgrimes * notice, this list of conditions and the following disclaimer. 101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer in the 121556Srgrimes * documentation and/or other materials provided with the distribution. 131556Srgrimes * 3. All advertising materials mentioning features or use of this software 141556Srgrimes * must display the following acknowledgement: 151556Srgrimes * This product includes software developed by the University of 161556Srgrimes * California, Berkeley and its contributors. 171556Srgrimes * 4. Neither the name of the University nor the names of its contributors 181556Srgrimes * may be used to endorse or promote products derived from this software 191556Srgrimes * without specific prior written permission. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311556Srgrimes * SUCH DAMAGE. 321556Srgrimes */ 331556Srgrimes 341556Srgrimes#ifndef lint 353044Sdgstatic char const copyright[] = 3617987Speter"@(#) Copyright (c) 1990, 1993, 1994\n\ 371556Srgrimes The Regents of the University of California. All rights reserved.\n"; 381556Srgrimes#endif /* not lint */ 391556Srgrimes 4017987Speter#ifndef lint 411556Srgrimes#if 0 421556Srgrimesstatic char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94"; 4317987Speter#endif 4417987Speterstatic const char rcsid[] = 4517987Speter "$FreeBSD: head/bin/ps/ps.c 81743 2001-08-16 02:41:42Z brian $"; 4617987Speter#endif /* not lint */ 4717987Speter 4817987Speter#include <sys/param.h> 4917987Speter#include <sys/user.h> 5017987Speter#include <sys/time.h> 511556Srgrimes#include <sys/resource.h> 521556Srgrimes#include <sys/stat.h> 531556Srgrimes#include <sys/ioctl.h> 541556Srgrimes#include <sys/sysctl.h> 551556Srgrimes 561556Srgrimes#include <ctype.h> 571556Srgrimes#include <err.h> 581556Srgrimes#include <errno.h> 591556Srgrimes#include <fcntl.h> 601556Srgrimes#include <kvm.h> 611556Srgrimes#include <limits.h> 621556Srgrimes#include <locale.h> 631556Srgrimes#include <nlist.h> 641556Srgrimes#include <paths.h> 651556Srgrimes#include <stdio.h> 661556Srgrimes#include <stdlib.h> 671556Srgrimes#include <string.h> 681556Srgrimes#include <unistd.h> 691556Srgrimes#include <pwd.h> 701556Srgrimes#include <utmp.h> 711556Srgrimes 721556Srgrimes#include "ps.h" 731556Srgrimes 741556Srgrimes#define SEP ", \t" /* username separators */ 751556Srgrimes 761556SrgrimesKINFO *kinfo; 771556Srgrimesstruct varent *vhead, *vtail; 788855Srgrimes 791556Srgrimesint eval; /* exit value */ 801556Srgrimesint cflag; /* -c */ 818855Srgrimesint rawcpu; /* -C */ 821556Srgrimesint sumrusage; /* -S */ 831556Srgrimesint termwidth; /* width of screen (0 == infinity) */ 841556Srgrimesint totwidth; /* calculated width of requested variables */ 8517987Speter 8617987Speterstatic int needuser, needcomm, needenv; 871556Srgrimes#if defined(LAZY_PS) 881556Srgrimesstatic int forceuread=0; 891556Srgrimes#else 901556Srgrimesstatic int forceuread=1; 911556Srgrimes#endif 921556Srgrimes 931556Srgrimesenum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; 941556Srgrimes 951556Srgrimesstatic char *fmt __P((char **(*)(kvm_t *, const struct kinfo_proc *, int), 961556Srgrimes KINFO *, char *, int)); 971556Srgrimesstatic char *kludge_oldps_options __P((char *)); 981556Srgrimesstatic int pscomp __P((const void *, const void *)); 991556Srgrimesstatic void saveuser __P((KINFO *)); 1001556Srgrimesstatic void scanvars __P((void)); 1011556Srgrimesstatic void dynsizevars __P((KINFO *)); 1021556Srgrimesstatic void sizevars __P((void)); 10317987Speterstatic void usage __P((void)); 1041556Srgrimesstatic uid_t *getuids(const char *, int *); 1051556Srgrimes 1061556Srgrimeschar dfmt[] = "pid tt state time command"; 1071556Srgrimeschar jfmt[] = "user pid ppid pgid jobc state tt time command"; 1081556Srgrimeschar lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command"; 1091556Srgrimeschar o1[] = "pid"; 1101556Srgrimeschar o2[] = "tt state time command"; 1111556Srgrimeschar ufmt[] = "user pid %cpu %mem vsz rss tt state start time command"; 1121556Srgrimeschar vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command"; 1131556Srgrimes 1141556Srgrimeskvm_t *kd; 1151556Srgrimes 1161556Srgrimesint 1171556Srgrimesmain(argc, argv) 1181556Srgrimes int argc; 1191556Srgrimes char *argv[]; 12011601Sjoerg{ 12111601Sjoerg struct kinfo_proc *kp; 12211601Sjoerg struct varent *vent; 1231556Srgrimes struct winsize ws; 1241556Srgrimes dev_t ttydev; 1251556Srgrimes pid_t pid; 1261556Srgrimes uid_t *uids; 1271556Srgrimes int all, ch, flag, i, fmt, lineno, nentries, dropgid; 1281556Srgrimes int prtheader, wflag, what, xflg, uid, nuids; 1291556Srgrimes char *nlistf, *memf, *swapf, errbuf[_POSIX2_LINE_MAX]; 1301556Srgrimes 1311556Srgrimes (void) setlocale(LC_ALL, ""); 1321556Srgrimes 1331556Srgrimes if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && 1341556Srgrimes ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && 1351556Srgrimes ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) || 1361556Srgrimes ws.ws_col == 0) 1371556Srgrimes termwidth = 79; 1381556Srgrimes else 1391556Srgrimes termwidth = ws.ws_col - 1; 1401556Srgrimes 1411556Srgrimes if (argc > 1) 1421556Srgrimes argv[1] = kludge_oldps_options(argv[1]); 1431556Srgrimes 1441556Srgrimes all = fmt = prtheader = wflag = xflg = 0; 1451556Srgrimes pid = -1; 1461556Srgrimes nuids = 0; 1471556Srgrimes uids = NULL; 1481556Srgrimes ttydev = NODEV; 1491556Srgrimes dropgid = 0; 1501556Srgrimes memf = nlistf = swapf = _PATH_DEVNULL; 1511556Srgrimes while ((ch = getopt(argc, argv, 1521556Srgrimes#if defined(LAZY_PS) 1531556Srgrimes "aCcefghjLlM:mN:O:o:p:rSTt:U:uvW:wx")) != -1) 1541556Srgrimes#else 1551556Srgrimes "aCceghjLlM:mN:O:o:p:rSTt:U:uvW:wx")) != -1) 1561556Srgrimes#endif 1571556Srgrimes switch((char)ch) { 1581556Srgrimes case 'a': 1591556Srgrimes all = 1; 1601556Srgrimes break; 1611556Srgrimes case 'C': 1621556Srgrimes rawcpu = 1; 1631556Srgrimes break; 1641556Srgrimes case 'c': 1651556Srgrimes cflag = 1; 1661556Srgrimes break; 1671556Srgrimes case 'e': /* XXX set ufmt */ 1681556Srgrimes needenv = 1; 1691556Srgrimes break; 1701556Srgrimes case 'g': 1711556Srgrimes break; /* no-op */ 1721556Srgrimes case 'h': 1731556Srgrimes prtheader = ws.ws_row > 5 ? ws.ws_row : 22; 1741556Srgrimes break; 1751556Srgrimes case 'j': 1761556Srgrimes parsefmt(jfmt); 1771556Srgrimes fmt = 1; 1781556Srgrimes jfmt[0] = '\0'; 1791556Srgrimes break; 1801556Srgrimes case 'L': 1811556Srgrimes showkey(); 1821556Srgrimes exit(0); 1831556Srgrimes case 'l': 1841556Srgrimes parsefmt(lfmt); 1851556Srgrimes fmt = 1; 1861556Srgrimes lfmt[0] = '\0'; 1871556Srgrimes break; 1881556Srgrimes case 'M': 1891556Srgrimes memf = optarg; 1901556Srgrimes dropgid = 1; 1911556Srgrimes break; 1921556Srgrimes case 'm': 1931556Srgrimes sortby = SORTMEM; 1941556Srgrimes break; 1951556Srgrimes case 'N': 1961556Srgrimes nlistf = optarg; 1971556Srgrimes dropgid = 1; 1981556Srgrimes break; 1991556Srgrimes case 'O': 2001556Srgrimes parsefmt(o1); 2011556Srgrimes parsefmt(optarg); 2021556Srgrimes parsefmt(o2); 2031556Srgrimes o1[0] = o2[0] = '\0'; 2041556Srgrimes fmt = 1; 2051556Srgrimes break; 2061556Srgrimes case 'o': 2071556Srgrimes parsefmt(optarg); 2081556Srgrimes fmt = 1; 2091556Srgrimes break; 2101556Srgrimes#if defined(LAZY_PS) 2111556Srgrimes case 'f': 2121556Srgrimes if (getuid() == 0 || getgid() == 0) 2131556Srgrimes forceuread = 1; 2141556Srgrimes break; 2151556Srgrimes#endif 2161556Srgrimes case 'p': 2171556Srgrimes pid = atol(optarg); 2181556Srgrimes xflg = 1; 2191556Srgrimes break; 2201556Srgrimes case 'r': 2211556Srgrimes sortby = SORTCPU; 2221556Srgrimes break; 2231556Srgrimes case 'S': 2241556Srgrimes sumrusage = 1; 2251556Srgrimes break; 22617987Speter case 'T': 2271556Srgrimes if ((optarg = ttyname(STDIN_FILENO)) == NULL) 2281556Srgrimes errx(1, "stdin: not a terminal"); 2291556Srgrimes /* FALLTHROUGH */ 2301556Srgrimes case 't': { 2311556Srgrimes struct stat sb; 2321556Srgrimes char *ttypath, pathbuf[PATH_MAX]; 2331556Srgrimes 2341556Srgrimes if (strcmp(optarg, "co") == 0) 2351556Srgrimes ttypath = _PATH_CONSOLE; 2361556Srgrimes else if (*optarg != '/') 2371556Srgrimes (void)snprintf(ttypath = pathbuf, 2381556Srgrimes sizeof(pathbuf), "%s%s", _PATH_TTY, optarg); 2391556Srgrimes else 2401556Srgrimes ttypath = optarg; 2411556Srgrimes if (stat(ttypath, &sb) == -1) 2421556Srgrimes err(1, "%s", ttypath); 2431556Srgrimes if (!S_ISCHR(sb.st_mode)) 2441556Srgrimes errx(1, "%s: not a terminal", ttypath); 2451556Srgrimes ttydev = sb.st_rdev; 2461556Srgrimes break; 2471556Srgrimes } 2481556Srgrimes case 'U': 2491556Srgrimes uids = getuids(optarg, &nuids); 2501556Srgrimes xflg++; /* XXX: intuitive? */ 2511556Srgrimes break; 2521556Srgrimes case 'u': 2531556Srgrimes parsefmt(ufmt); 2541556Srgrimes sortby = SORTCPU; 2551556Srgrimes fmt = 1; 2561556Srgrimes ufmt[0] = '\0'; 2571556Srgrimes break; 2581556Srgrimes case 'v': 2591556Srgrimes parsefmt(vfmt); 2601556Srgrimes sortby = SORTMEM; 2611556Srgrimes fmt = 1; 2621556Srgrimes vfmt[0] = '\0'; 2631556Srgrimes break; 2641556Srgrimes case 'W': 2651556Srgrimes swapf = optarg; 2661556Srgrimes dropgid = 1; 2671556Srgrimes break; 2681556Srgrimes case 'w': 2691556Srgrimes if (wflag) 2701556Srgrimes termwidth = UNLIMITED; 2711556Srgrimes else if (termwidth < 131) 2721556Srgrimes termwidth = 131; 2731556Srgrimes wflag++; 2741556Srgrimes break; 2751556Srgrimes case 'x': 2761556Srgrimes xflg = 1; 2771556Srgrimes break; 2781556Srgrimes case '?': 2791556Srgrimes default: 2801556Srgrimes usage(); 2811556Srgrimes } 2821556Srgrimes argc -= optind; 2831556Srgrimes argv += optind; 2841556Srgrimes 2851556Srgrimes#define BACKWARD_COMPATIBILITY 2861556Srgrimes#ifdef BACKWARD_COMPATIBILITY 2871556Srgrimes if (*argv) { 2881556Srgrimes nlistf = *argv; 2891556Srgrimes if (*++argv) { 2901556Srgrimes memf = *argv; 2911556Srgrimes if (*++argv) 2921556Srgrimes swapf = *argv; 2931556Srgrimes } 2941556Srgrimes } 2951556Srgrimes#endif 2961556Srgrimes /* 2971556Srgrimes * Discard setgid privileges if not the running kernel so that bad 2981556Srgrimes * guys can't print interesting stuff from kernel memory. 2991556Srgrimes */ 3001556Srgrimes if (dropgid) { 3011556Srgrimes setgid(getgid()); 3021556Srgrimes setuid(getuid()); 3031556Srgrimes } 3041556Srgrimes 3051556Srgrimes kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf); 3061556Srgrimes if (kd == 0) 3071556Srgrimes errx(1, "%s", errbuf); 3081556Srgrimes 3091556Srgrimes if (!fmt) 3101556Srgrimes parsefmt(dfmt); 3111556Srgrimes 3121556Srgrimes /* XXX - should be cleaner */ 3131556Srgrimes if (!all && ttydev == NODEV && pid == -1 && !nuids) { 3141556Srgrimes if ((uids = malloc(sizeof (*uids))) == NULL) 3151556Srgrimes errx(1, "malloc: %s", strerror(errno)); 3161556Srgrimes nuids = 1; 3171556Srgrimes *uids = getuid(); 3181556Srgrimes } 3191556Srgrimes 3201556Srgrimes /* 3211556Srgrimes * scan requested variables, noting what structures are needed, 3221556Srgrimes * and adjusting header widths as appropriate. 3231556Srgrimes */ 3241556Srgrimes scanvars(); 3251556Srgrimes /* 3261556Srgrimes * get proc list 3271556Srgrimes */ 3281556Srgrimes if (nuids == 1) { 3291556Srgrimes what = KERN_PROC_UID; 3301556Srgrimes flag = *uids; 3311556Srgrimes } else if (ttydev != NODEV) { 3321556Srgrimes what = KERN_PROC_TTY; 3331556Srgrimes flag = ttydev; 3341556Srgrimes } else if (pid != -1) { 3351556Srgrimes what = KERN_PROC_PID; 3361556Srgrimes flag = pid; 3371556Srgrimes } else { 33817987Speter what = KERN_PROC_ALL; 33917987Speter flag = 0; 34017987Speter } 34117987Speter /* 3421556Srgrimes * select procs 3431556Srgrimes */ 3441556Srgrimes if ((kp = kvm_getprocs(kd, what, flag, &nentries)) == 0) 3451556Srgrimes errx(1, "%s", kvm_geterr(kd)); 3461556Srgrimes if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL) 34711601Sjoerg err(1, NULL); 34811601Sjoerg for (i = nentries; --i >= 0; ++kp) { 3491556Srgrimes kinfo[i].ki_p = kp; 3501556Srgrimes if (needuser) 351 saveuser(&kinfo[i]); 352 dynsizevars(&kinfo[i]); 353 } 354 355 sizevars(); 356 357 /* 358 * print header 359 */ 360 printheader(); 361 if (nentries == 0) 362 exit(1); 363 /* 364 * sort proc list 365 */ 366 qsort(kinfo, nentries, sizeof(KINFO), pscomp); 367 /* 368 * for each proc, call each variable output function. 369 */ 370 for (i = lineno = 0; i < nentries; i++) { 371 if (xflg == 0 && ((&kinfo[i])->ki_p->ki_tdev == NODEV || 372 ((&kinfo[i])->ki_p->ki_flag & P_CONTROLT ) == 0)) 373 continue; 374 if (nuids > 1) { 375 for (uid = 0; uid < nuids; uid++) 376 if ((&kinfo[i])->ki_p->ki_uid == uids[uid]) 377 break; 378 if (uid == nuids) 379 continue; 380 } 381 for (vent = vhead; vent; vent = vent->next) { 382 (vent->var->oproc)(&kinfo[i], vent); 383 if (vent->next != NULL) 384 (void)putchar(' '); 385 } 386 (void)putchar('\n'); 387 if (prtheader && lineno++ == prtheader - 4) { 388 (void)putchar('\n'); 389 printheader(); 390 lineno = 0; 391 } 392 } 393 free(uids); 394 395 exit(eval); 396} 397 398uid_t * 399getuids(const char *arg, int *nuids) 400{ 401 char name[UT_NAMESIZE + 1]; 402 struct passwd *pwd; 403 uid_t *uids, *moreuids; 404 int l, alloc; 405 406 407 alloc = 0; 408 *nuids = 0; 409 uids = NULL; 410 for (; (l = strcspn(arg, SEP)) > 0; arg += l + strspn(arg + l, SEP)) { 411 if (l >= sizeof name) { 412 warnx("%.*s: name too long", l, arg); 413 continue; 414 } 415 strncpy(name, arg, l); 416 name[l] = '\0'; 417 if ((pwd = getpwnam(name)) == NULL) { 418 warnx("%s: no such user", name); 419 continue; 420 } 421 if (*nuids >= alloc) { 422 alloc = (alloc + 1) << 1; 423 moreuids = realloc(uids, alloc * sizeof (*uids)); 424 if (moreuids == NULL) { 425 free(uids); 426 errx(1, "realloc: %s", strerror(errno)); 427 } 428 uids = moreuids; 429 } 430 uids[(*nuids)++] = pwd->pw_uid; 431 } 432 endpwent(); 433 434 if (!*nuids) 435 errx(1, "No users specified"); 436 437 return uids; 438} 439 440static void 441scanvars() 442{ 443 struct varent *vent; 444 VAR *v; 445 446 for (vent = vhead; vent; vent = vent->next) { 447 v = vent->var; 448 if (v->flag & DSIZ) { 449 v->dwidth = v->width; 450 v->width = 0; 451 } 452 if (v->flag & USER) 453 needuser = 1; 454 if (v->flag & COMM) 455 needcomm = 1; 456 } 457} 458 459static void 460dynsizevars(ki) 461 KINFO *ki; 462{ 463 struct varent *vent; 464 VAR *v; 465 int i; 466 467 for (vent = vhead; vent; vent = vent->next) { 468 v = vent->var; 469 if (!(v->flag & DSIZ)) 470 continue; 471 i = (v->sproc)( ki); 472 if (v->width < i) 473 v->width = i; 474 if (v->width > v->dwidth) 475 v->width = v->dwidth; 476 } 477} 478 479static void 480sizevars() 481{ 482 struct varent *vent; 483 VAR *v; 484 int i; 485 486 for (vent = vhead; vent; vent = vent->next) { 487 v = vent->var; 488 i = strlen(v->header); 489 if (v->width < i) 490 v->width = i; 491 totwidth += v->width + 1; /* +1 for space */ 492 } 493 totwidth--; 494} 495 496static char * 497fmt(fn, ki, comm, maxlen) 498 char **(*fn) __P((kvm_t *, const struct kinfo_proc *, int)); 499 KINFO *ki; 500 char *comm; 501 int maxlen; 502{ 503 char *s; 504 505 if ((s = 506 fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen)) == NULL) 507 err(1, NULL); 508 return (s); 509} 510 511#define UREADOK(ki) (forceuread || (ki->ki_p->ki_sflag & PS_INMEM)) 512 513static void 514saveuser(ki) 515 KINFO *ki; 516{ 517 518 if (ki->ki_p->ki_sflag & PS_INMEM) { 519 /* 520 * The u-area might be swapped out, and we can't get 521 * at it because we have a crashdump and no swap. 522 * If it's here fill in these fields, otherwise, just 523 * leave them 0. 524 */ 525 ki->ki_valid = 1; 526 } else 527 ki->ki_valid = 0; 528 /* 529 * save arguments if needed 530 */ 531 if (needcomm && (UREADOK(ki) || (ki->ki_p->ki_args != NULL))) { 532 ki->ki_args = fmt(kvm_getargv, ki, ki->ki_p->ki_comm, 533 MAXCOMLEN); 534 } else if (needcomm) { 535 ki->ki_args = malloc(strlen(ki->ki_p->ki_comm) + 3); 536 sprintf(ki->ki_args, "(%s)", ki->ki_p->ki_comm); 537 } else { 538 ki->ki_args = NULL; 539 } 540 if (needenv && UREADOK(ki)) { 541 ki->ki_env = fmt(kvm_getenvv, ki, (char *)NULL, 0); 542 } else if (needenv) { 543 ki->ki_env = malloc(3); 544 strcpy(ki->ki_env, "()"); 545 } else { 546 ki->ki_env = NULL; 547 } 548} 549 550static int 551pscomp(a, b) 552 const void *a, *b; 553{ 554 int i; 555#define VSIZE(k) ((k)->ki_p->ki_dsize + (k)->ki_p->ki_ssize + \ 556 (k)->ki_p->ki_tsize) 557 558 if (sortby == SORTCPU) 559 return (getpcpu((KINFO *)b) - getpcpu((KINFO *)a)); 560 if (sortby == SORTMEM) 561 return (VSIZE((KINFO *)b) - VSIZE((KINFO *)a)); 562 i = ((KINFO *)a)->ki_p->ki_tdev - ((KINFO *)b)->ki_p->ki_tdev; 563 if (i == 0) 564 i = ((KINFO *)a)->ki_p->ki_pid - ((KINFO *)b)->ki_p->ki_pid; 565 return (i); 566} 567 568/* 569 * ICK (all for getopt), would rather hide the ugliness 570 * here than taint the main code. 571 * 572 * ps foo -> ps -foo 573 * ps 34 -> ps -p34 574 * 575 * The old convention that 't' with no trailing tty arg means the users 576 * tty, is only supported if argv[1] doesn't begin with a '-'. This same 577 * feature is available with the option 'T', which takes no argument. 578 */ 579static char * 580kludge_oldps_options(s) 581 char *s; 582{ 583 size_t len; 584 char *newopts, *ns, *cp; 585 586 len = strlen(s); 587 if ((newopts = ns = malloc(len + 2)) == NULL) 588 err(1, NULL); 589 /* 590 * options begin with '-' 591 */ 592 if (*s != '-') 593 *ns++ = '-'; /* add option flag */ 594 /* 595 * gaze to end of argv[1] 596 */ 597 cp = s + len - 1; 598 /* 599 * if last letter is a 't' flag with no argument (in the context 600 * of the oldps options -- option string NOT starting with a '-' -- 601 * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). 602 * 603 * However, if a flag accepting a string argument is found in the 604 * option string, the remainder of the string is the argument to 605 * that flag; do not modify that argument. 606 */ 607 if (strcspn(s, "MNOoUW") == len && *cp == 't' && *s != '-') 608 *cp = 'T'; 609 else { 610 /* 611 * otherwise check for trailing number, which *may* be a 612 * pid. 613 */ 614 while (cp >= s && isdigit(*cp)) 615 --cp; 616 } 617 cp++; 618 memmove(ns, s, (size_t)(cp - s)); /* copy up to trailing number */ 619 ns += cp - s; 620 /* 621 * if there's a trailing number, and not a preceding 'p' (pid) or 622 * 't' (tty) flag, then assume it's a pid and insert a 'p' flag. 623 */ 624 if (isdigit(*cp) && 625 (cp == s || (cp[-1] != 't' && cp[-1] != 'p')) && 626 (cp - 1 == s || cp[-2] != 't')) 627 *ns++ = 'p'; 628 (void)strcpy(ns, cp); /* and append the number */ 629 630 return (newopts); 631} 632 633static void 634usage() 635{ 636 637 (void)fprintf(stderr, "%s\n%s\n%s\n", 638 "usage: ps [-aChjlmrSTuvwx] [-O|o fmt] [-p pid] [-t tty] [-U user]", 639 " [-M core] [-N system] [-W swap]", 640 " ps [-L]"); 641 exit(1); 642} 643