ps.c revision 127149
1270096Strasz/*- 2332596Strasz * Copyright (c) 1990, 1993, 1994 3332596Strasz * The Regents of the University of California. All rights reserved. 4270096Strasz * 5270096Strasz * Redistribution and use in source and binary forms, with or without 6270096Strasz * modification, are permitted provided that the following conditions 7270096Strasz * are met: 8270096Strasz * 1. Redistributions of source code must retain the above copyright 9270096Strasz * notice, this list of conditions and the following disclaimer. 10270096Strasz * 2. Redistributions in binary form must reproduce the above copyright 11270096Strasz * notice, this list of conditions and the following disclaimer in the 12270096Strasz * documentation and/or other materials provided with the distribution. 13270096Strasz * 3. All advertising materials mentioning features or use of this software 14270096Strasz * must display the following acknowledgement: 15270096Strasz * This product includes software developed by the University of 16270096Strasz * California, Berkeley and its contributors. 17270096Strasz * 4. Neither the name of the University nor the names of its contributors 18270096Strasz * may be used to endorse or promote products derived from this software 19270096Strasz * without specific prior written permission. 20270096Strasz * 21270096Strasz * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22270096Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23270096Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24270096Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25270096Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26270096Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27270096Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28270096Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29270096Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30270096Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31270096Strasz * SUCH DAMAGE. 32270096Strasz */ 33270096Strasz 34270096Strasz#ifndef lint 35270096Straszstatic const char copyright[] = 36270096Strasz"@(#) Copyright (c) 1990, 1993, 1994\n\ 37341074Smarkj The Regents of the University of California. All rights reserved.\n"; 38270096Strasz#endif /* not lint */ 39270096Strasz 40270096Strasz#if 0 41270096Strasz#ifndef lint 42270096Straszstatic char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94"; 43270096Strasz#endif /* not lint */ 44270096Strasz#endif 45270096Strasz 46270096Strasz#include <sys/cdefs.h> 47296718Strasz__FBSDID("$FreeBSD: head/bin/ps/ps.c 127149 2004-03-17 22:46:58Z gad $"); 48272403Strasz 49297236Strasz#include <sys/param.h> 50270096Strasz#include <sys/user.h> 51270096Strasz#include <sys/stat.h> 52270096Strasz#include <sys/ioctl.h> 53270096Strasz#include <sys/sysctl.h> 54270281Strasz 55270096Strasz#include <ctype.h> 56270096Strasz#include <err.h> 57270096Strasz#include <errno.h> 58270096Strasz#include <fcntl.h> 59270402Strasz#include <kvm.h> 60270402Strasz#include <limits.h> 61270096Strasz#include <locale.h> 62270096Strasz#include <paths.h> 63270096Strasz#include <pwd.h> 64270096Strasz#include <stdio.h> 65270096Strasz#include <stdlib.h> 66270096Strasz#include <string.h> 67270096Strasz#include <unistd.h> 68270096Strasz 69270096Strasz#include "ps.h" 70270096Strasz 71270096Strasz#define SEP ", \t" /* username separators */ 72270096Strasz 73270096Straszstatic KINFO *kinfo; 74270096Straszstruct varent *vhead; 75270096Strasz 76270096Straszint eval; /* exit value */ 77270096Straszint cflag; /* -c */ 78270096Straszint rawcpu; /* -C */ 79270096Straszint sumrusage; /* -S */ 80270096Straszint termwidth; /* width of screen (0 == infinity) */ 81270096Straszint totwidth; /* calculated width of requested variables */ 82270096Strasz 83270096Strasztime_t now; /* current time(3) value */ 84270096Strasz 85270096Straszstatic int needuser, needcomm, needenv; 86270096Strasz#if defined(LAZY_PS) 87270096Straszstatic int forceuread=0; 88270096Strasz#else 89270096Straszstatic int forceuread=1; 90270096Strasz#endif 91270096Strasz 92270096Straszstatic enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; 93270096Strasz 94270096Straszstatic const char *fmt(char **(*)(kvm_t *, const struct kinfo_proc *, int), 95270096Strasz KINFO *, char *, int); 96270096Straszstatic char *kludge_oldps_options(char *); 97270096Straszstatic int pscomp(const void *, const void *); 98270096Straszstatic void saveuser(KINFO *); 99270096Straszstatic void scanvars(void); 100270096Straszstatic void dynsizevars(KINFO *); 101270096Straszstatic void sizevars(void); 102270096Straszstatic void usage(void); 103270096Straszstatic pid_t *getpids(const char *, int *); 104270096Straszstatic uid_t *getuids(const char *, int *); 105270096Strasz 106270096Straszstatic char dfmt[] = "pid,tt,state,time,command"; 107270096Straszstatic char jfmt[] = "user,pid,ppid,pgid,jobc,state,tt,time,command"; 108270096Straszstatic char lfmt[] = "uid,pid,ppid,cpu,pri,nice,vsz,rss,mwchan,state,tt,time,command"; 109270096Straszstatic char o1[] = "pid"; 110270096Straszstatic char o2[] = "tt,state,time,command"; 111270096Straszstatic char ufmt[] = "user,pid,%cpu,%mem,vsz,rss,tt,state,start,time,command"; 112270096Straszstatic char vfmt[] = "pid,state,time,sl,re,pagein,vsz,rss,lim,tsiz,%cpu,%mem,command"; 113270096Straszstatic char Zfmt[] = "label"; 114270096Strasz 115270096Straszstatic kvm_t *kd; 116270096Strasz 117296718Strasz#if defined(LAZY_PS) 118296718Strasz#define PS_ARGS "aCcefgHhjLlM:mN:O:o:p:rSTt:U:uvwxZ" 119270096Strasz#else 120270096Strasz#define PS_ARGS "aCcegHhjLlM:mN:O:o:p:rSTt:U:uvwxZ" 121270096Strasz#endif 122270096Strasz 123270096Straszint 124270096Straszmain(int argc, char *argv[]) 125270096Strasz{ 126296718Strasz struct kinfo_proc *kp; 127270096Strasz struct varent *vent; 128270096Strasz struct winsize ws; 129270096Strasz dev_t ttydev; 130270096Strasz pid_t *pids; 131270096Strasz uid_t *uids; 132270096Strasz int all, ch, flag, i, _fmt, lineno, nentries, nocludge, dropgid; 133270096Strasz int prtheader, wflag, what, xflg, pid, uid, npids, nuids, showthreads; 134270096Strasz char *cols; 135270096Strasz char errbuf[_POSIX2_LINE_MAX]; 136270096Strasz const char *cp, *nlistf, *memf; 137270096Strasz 138270096Strasz (void) setlocale(LC_ALL, ""); 139270096Strasz /* Set the time to what it is right now. */ 140270096Strasz time(&now); 141270096Strasz 142270096Strasz if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0') 143270096Strasz termwidth = atoi(cols); 144270096Strasz else if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && 145270096Strasz ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && 146270096Strasz ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) || 147270096Strasz ws.ws_col == 0) 148270096Strasz termwidth = 79; 149270096Strasz else 150270096Strasz termwidth = ws.ws_col - 1; 151270096Strasz 152270096Strasz /* 153270096Strasz * Don't apply a kludge if the first argument is an option taking an 154270096Strasz * argument 155270096Strasz */ 156270096Strasz if (argc > 1) { 157270402Strasz nocludge = 0; 158270096Strasz if (argv[1][0] == '-') { 159270096Strasz for (cp = PS_ARGS; *cp != '\0'; cp++) { 160270096Strasz if (*cp != ':') 161270096Strasz continue; 162270096Strasz if (*(cp - 1) == argv[1][1]) { 163270096Strasz nocludge = 1; 164270096Strasz break; 165270096Strasz } 166270096Strasz } 167270096Strasz } 168270096Strasz if (nocludge == 0) 169270402Strasz argv[1] = kludge_oldps_options(argv[1]); 170270096Strasz } 171270096Strasz 172270096Strasz all = _fmt = prtheader = wflag = xflg = 0; 173270096Strasz npids = nuids = 0; 174270096Strasz pids = uids = NULL; 175270096Strasz ttydev = NODEV; 176270096Strasz dropgid = 0; 177270096Strasz memf = nlistf = _PATH_DEVNULL; 178270096Strasz showthreads = 0; 179270096Strasz while ((ch = getopt(argc, argv, PS_ARGS)) != -1) 180270096Strasz switch((char)ch) { 181270096Strasz case 'a': 182270096Strasz all = 1; 183270096Strasz break; 184270096Strasz case 'C': 185270096Strasz rawcpu = 1; 186270096Strasz break; 187270096Strasz case 'c': 188270096Strasz cflag = 1; 189270096Strasz break; 190270096Strasz case 'e': /* XXX set ufmt */ 191270096Strasz needenv = 1; 192270096Strasz break; 193270096Strasz case 'g': 194270096Strasz break; /* no-op */ 195270096Strasz case 'H': 196270096Strasz showthreads = KERN_PROC_INC_THREAD; 197270096Strasz break; 198270096Strasz case 'h': 199270096Strasz prtheader = ws.ws_row > 5 ? ws.ws_row : 22; 200270096Strasz break; 201270096Strasz case 'j': 202270096Strasz parsefmt(jfmt, 0); 203272512Strasz _fmt = 1; 204270207Strasz jfmt[0] = '\0'; 205270207Strasz break; 206270207Strasz case 'L': 207270207Strasz showkey(); 208272512Strasz exit(0); 209270207Strasz case 'l': 210270207Strasz parsefmt(lfmt, 0); 211270207Strasz _fmt = 1; 212270096Strasz lfmt[0] = '\0'; 213270096Strasz break; 214270096Strasz case 'M': 215270096Strasz memf = optarg; 216270096Strasz dropgid = 1; 217270096Strasz break; 218270096Strasz case 'm': 219296715Strasz sortby = SORTMEM; 220270096Strasz break; 221270096Strasz case 'N': 222270096Strasz nlistf = optarg; 223270096Strasz dropgid = 1; 224270096Strasz break; 225270096Strasz case 'O': 226270096Strasz parsefmt(o1, 1); 227270096Strasz parsefmt(optarg, 1); 228270096Strasz parsefmt(o2, 1); 229270096Strasz o1[0] = o2[0] = '\0'; 230270096Strasz _fmt = 1; 231270207Strasz break; 232270207Strasz case 'o': 233270207Strasz parsefmt(optarg, 1); 234270207Strasz _fmt = 1; 235270207Strasz break; 236270096Strasz#if defined(LAZY_PS) 237270207Strasz case 'f': 238272512Strasz if (getuid() == 0 || getgid() == 0) 239270096Strasz forceuread = 1; 240270207Strasz break; 241270096Strasz#endif 242270207Strasz case 'p': 243270096Strasz pids = getpids(optarg, &npids); 244270096Strasz xflg = 1; 245270096Strasz break; 246270096Strasz case 'r': 247270096Strasz sortby = SORTCPU; 248270096Strasz break; 249270096Strasz case 'S': 250270096Strasz sumrusage = 1; 251270096Strasz break; 252270096Strasz case 'T': 253270096Strasz if ((optarg = ttyname(STDIN_FILENO)) == NULL) 254270096Strasz errx(1, "stdin: not a terminal"); 255270096Strasz /* FALLTHROUGH */ 256270096Strasz case 't': { 257270096Strasz struct stat sb; 258270096Strasz char *ttypath, pathbuf[PATH_MAX]; 259270096Strasz 260270096Strasz if (strcmp(optarg, "co") == 0) 261270096Strasz ttypath = strdup(_PATH_CONSOLE); 262270096Strasz else if (*optarg != '/') 263296715Strasz (void)snprintf(ttypath = pathbuf, 264296715Strasz sizeof(pathbuf), "%s%s", _PATH_TTY, optarg); 265296715Strasz else 266270096Strasz ttypath = optarg; 267296715Strasz if (stat(ttypath, &sb) == -1) 268296715Strasz err(1, "%s", ttypath); 269270096Strasz if (!S_ISCHR(sb.st_mode)) 270270096Strasz errx(1, "%s: not a terminal", ttypath); 271270096Strasz ttydev = sb.st_rdev; 272272470Strasz break; 273270096Strasz } 274270096Strasz case 'U': 275270096Strasz uids = getuids(optarg, &nuids); 276272470Strasz xflg++; /* XXX: intuitive? */ 277270096Strasz break; 278270096Strasz case 'u': 279270096Strasz parsefmt(ufmt, 0); 280272470Strasz sortby = SORTCPU; 281270096Strasz _fmt = 1; 282270096Strasz ufmt[0] = '\0'; 283270096Strasz break; 284270096Strasz case 'v': 285270096Strasz parsefmt(vfmt, 0); 286270096Strasz sortby = SORTMEM; 287272470Strasz _fmt = 1; 288270096Strasz vfmt[0] = '\0'; 289272512Strasz break; 290270096Strasz case 'w': 291270096Strasz if (wflag) 292270096Strasz termwidth = UNLIMITED; 293270096Strasz else if (termwidth < 131) 294270096Strasz termwidth = 131; 295270096Strasz wflag++; 296270096Strasz break; 297270096Strasz case 'x': 298270096Strasz xflg = 1; 299270096Strasz break; 300270096Strasz case 'Z': 301270096Strasz parsefmt(Zfmt, 0); 302270096Strasz Zfmt[0] = '\0'; 303270096Strasz break; 304270096Strasz case '?': 305270096Strasz default: 306270096Strasz usage(); 307270096Strasz } 308270096Strasz argc -= optind; 309270096Strasz argv += optind; 310270096Strasz 311270096Strasz#define BACKWARD_COMPATIBILITY 312270096Strasz#ifdef BACKWARD_COMPATIBILITY 313270096Strasz if (*argv) { 314270096Strasz nlistf = *argv; 315270096Strasz if (*++argv) { 316270096Strasz memf = *argv; 317270096Strasz } 318270096Strasz } 319270096Strasz#endif 320272470Strasz /* 321270096Strasz * Discard setgid privileges if not the running kernel so that bad 322270096Strasz * guys can't print interesting stuff from kernel memory. 323270096Strasz */ 324272470Strasz if (dropgid) { 325270096Strasz setgid(getgid()); 326270096Strasz setuid(getuid()); 327272470Strasz } 328270096Strasz 329272512Strasz kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 330270096Strasz if (kd == 0) 331270096Strasz errx(1, "%s", errbuf); 332270096Strasz 333270096Strasz if (!_fmt) 334308253Strasz parsefmt(dfmt, 0); 335308253Strasz 336308253Strasz /* XXX - should be cleaner */ 337308253Strasz if (!all && ttydev == NODEV && !npids && !nuids) { 338308253Strasz if ((uids = malloc(sizeof (*uids))) == NULL) 339308253Strasz errx(1, "malloc failed"); 340308253Strasz nuids = 1; 341308253Strasz *uids = getuid(); 342308253Strasz } 343308253Strasz 344308253Strasz /* 345308253Strasz * scan requested variables, noting what structures are needed, 346308253Strasz * and adjusting header widths as appropriate. 347308253Strasz */ 348308253Strasz scanvars(); 349296798Strasz /* 350296798Strasz * get proc list 351296798Strasz */ 352270096Strasz if (nuids == 1) { 353296798Strasz what = KERN_PROC_UID | showthreads; 354296798Strasz flag = *uids; 355270096Strasz } else if (ttydev != NODEV) { 356270096Strasz what = KERN_PROC_TTY | showthreads; 357296798Strasz flag = ttydev; 358296798Strasz } else if (npids == 1) { 359270096Strasz what = KERN_PROC_PID | showthreads; 360296798Strasz flag = *pids; 361296798Strasz } else { 362296798Strasz what = showthreads != 0 ? KERN_PROC_ALL : KERN_PROC_PROC; 363296798Strasz flag = 0; 364296798Strasz } 365296798Strasz 366296798Strasz /* 367296798Strasz * select procs 368296798Strasz */ 369296798Strasz kp = kvm_getprocs(kd, what, flag, &nentries); 370296798Strasz if ((kp == 0 && nentries != 0) || nentries < 0) 371296798Strasz errx(1, "%s", kvm_geterr(kd)); 372296798Strasz if (nentries > 0) { 373296798Strasz if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL) 374296798Strasz errx(1, "malloc failed"); 375270096Strasz for (i = nentries; --i >= 0; ++kp) { 376296798Strasz kinfo[i].ki_p = kp; 377296798Strasz if (needuser) 378341074Smarkj saveuser(&kinfo[i]); 379296798Strasz dynsizevars(&kinfo[i]); 380270096Strasz } 381270096Strasz } 382270096Strasz 383270096Strasz sizevars(); 384296798Strasz 385296798Strasz /* 386296798Strasz * print header 387296798Strasz */ 388296798Strasz printheader(); 389296937Strasz if (nentries == 0) 390296798Strasz exit(1); 391296798Strasz /* 392296798Strasz * sort proc list 393296798Strasz */ 394270096Strasz qsort(kinfo, nentries, sizeof(KINFO), pscomp); 395270096Strasz /* 396270096Strasz * for each proc, call each variable output function. 397270096Strasz */ 398270096Strasz for (i = lineno = 0; i < nentries; i++) { 399270096Strasz if (xflg == 0 && ((&kinfo[i])->ki_p->ki_tdev == NODEV || 400270096Strasz ((&kinfo[i])->ki_p->ki_flag & P_CONTROLT ) == 0)) 401296798Strasz continue; 402296798Strasz if (npids > 1) { 403296798Strasz for (pid = 0; pid < npids; pid++) 404270096Strasz if ((&kinfo[i])->ki_p->ki_pid == pids[pid]) 405270096Strasz break; 406270096Strasz if (pid == npids) 407270096Strasz continue; 408270096Strasz } 409296798Strasz if (nuids > 1) { 410270096Strasz for (uid = 0; uid < nuids; uid++) 411270096Strasz if ((&kinfo[i])->ki_p->ki_uid == uids[uid]) 412270096Strasz break; 413270096Strasz if (uid == nuids) 414270096Strasz continue; 415270096Strasz } 416270096Strasz for (vent = vhead; vent; vent = vent->next) { 417270096Strasz (vent->var->oproc)(&kinfo[i], vent); 418270096Strasz if (vent->next != NULL) 419270096Strasz (void)putchar(' '); 420270096Strasz } 421270096Strasz (void)putchar('\n'); 422270096Strasz if (prtheader && lineno++ == prtheader - 4) { 423270096Strasz (void)putchar('\n'); 424270096Strasz printheader(); 425270096Strasz lineno = 0; 426270096Strasz } 427296798Strasz } 428270096Strasz free(uids); 429270096Strasz 430270096Strasz exit(eval); 431296798Strasz} 432270096Strasz 433296798Strasz#define BSD_PID_MAX 99999 /* Copy of PID_MAX from sys/proc.h */ 434296798Straszpid_t * 435296798Straszgetpids(const char *arg, int *npids) 436296798Strasz{ 437296798Strasz char copyarg[32]; 438296798Strasz char *copyp, *endp; 439296798Strasz pid_t *pids, *morepids; 440270096Strasz int alloc; 441296798Strasz long tempid; 442270096Strasz 443296798Strasz alloc = 0; 444270096Strasz *npids = 0; 445296798Strasz pids = NULL; 446296798Strasz while (*arg != '\0') { 447296798Strasz while (*arg != '\0' && strchr(SEP, *arg) != NULL) 448296798Strasz arg++; 449296798Strasz if (*arg == '\0' || strchr(SEP, *arg) != NULL) 450296798Strasz tempid = 0; 451270096Strasz else { 452296798Strasz copyp = copyarg; 453296798Strasz endp = copyarg + sizeof(copyarg) - 1; 454270096Strasz while (*arg != '\0' && strchr(SEP, *arg) == NULL && 455270096Strasz copyp <= endp) 456296798Strasz *copyp++ = *arg++; 457270096Strasz if (copyp > endp) { 458270096Strasz *endp = '\0'; 459296798Strasz tempid = -1; 460270096Strasz while (*arg != '\0' && 461270096Strasz strchr(SEP, *arg) == NULL) 462296798Strasz arg++; 463296798Strasz } else { 464296798Strasz *copyp = '\0'; 465296798Strasz errno = 0; 466296798Strasz tempid = strtol(copyarg, &endp, 10); 467272470Strasz } 468297236Strasz /* 469296798Strasz * Write warning messages for any values which 470296798Strasz * would never be a valid process number. 471296798Strasz */ 472296798Strasz if (*endp != '\0' || tempid < 0 || copyarg == endp) { 473296798Strasz warnx("invalid process number: %s", copyarg); 474296798Strasz errno = ERANGE; 475296798Strasz } else if (errno != 0 || tempid > BSD_PID_MAX) { 476270096Strasz warnx("process number too large: %s", copyarg); 477270096Strasz errno = ERANGE; 478270096Strasz } 479296798Strasz if (errno == ERANGE) { 480270096Strasz /* Ignore this value from the given list. */ 481296798Strasz continue; 482296798Strasz } 483296798Strasz } 484296798Strasz if (*npids >= alloc) { 485270096Strasz alloc = (alloc + 1) << 1; 486270096Strasz morepids = realloc(pids, alloc * sizeof (*pids)); 487296798Strasz if (morepids == NULL) { 488296798Strasz free(pids); 489270096Strasz errx(1, "realloc failed"); 490272470Strasz } 491296798Strasz pids = morepids; 492270096Strasz } 493270096Strasz pids[(*npids)++] = tempid; 494296798Strasz } 495270096Strasz 496296798Strasz if (!*npids) 497296798Strasz errx(1, "No valid process numbers specified"); 498296798Strasz 499270096Strasz return (pids); 500296798Strasz} 501296798Strasz 502296798Straszuid_t * 503296798Straszgetuids(const char *arg, int *nuids) 504296798Strasz{ 505296798Strasz char name[MAXLOGNAME]; 506296798Strasz struct passwd *pwd; 507296798Strasz uid_t *uids, *moreuids; 508296798Strasz int alloc; 509296798Strasz size_t l; 510296798Strasz 511296798Strasz 512296798Strasz alloc = 0; 513296798Strasz *nuids = 0; 514296798Strasz uids = NULL; 515270096Strasz for (; (l = strcspn(arg, SEP)) > 0; arg += l + strspn(arg + l, SEP)) { 516270096Strasz if (l >= sizeof name) { 517270096Strasz warnx("%.*s: name too long", (int)l, arg); 518270096Strasz continue; 519270096Strasz } 520272836Strasz strncpy(name, arg, l); 521272836Strasz name[l] = '\0'; 522270096Strasz if ((pwd = getpwnam(name)) == NULL) { 523270096Strasz warnx("%s: no such user", name); 524270096Strasz continue; 525270096Strasz } 526270096Strasz if (*nuids >= alloc) { 527270096Strasz alloc = (alloc + 1) << 1; 528270096Strasz moreuids = realloc(uids, alloc * sizeof (*uids)); 529270096Strasz if (moreuids == NULL) { 530270096Strasz free(uids); 531270096Strasz errx(1, "realloc failed"); 532270096Strasz } 533270096Strasz uids = moreuids; 534270096Strasz } 535270096Strasz uids[(*nuids)++] = pwd->pw_uid; 536270096Strasz } 537270096Strasz endpwent(); 538270096Strasz 539270096Strasz if (!*nuids) 540270096Strasz errx(1, "No users specified"); 541270096Strasz 542270096Strasz return uids; 543270096Strasz} 544270096Strasz 545270096StraszVARENT * 546270096Straszfind_varentry(VAR *v) 547270096Strasz{ 548308253Strasz struct varent *vent; 549270096Strasz 550270096Strasz for (vent = vhead; vent; vent = vent->next) { 551270096Strasz if (strcmp(vent->var->name, v->name) == 0) 552270096Strasz return vent; 553270096Strasz } 554270096Strasz return NULL; 555270096Strasz} 556270096Strasz 557270096Straszstatic void 558270096Straszscanvars(void) 559270096Strasz{ 560270096Strasz struct varent *vent; 561270096Strasz VAR *v; 562270096Strasz 563270096Strasz for (vent = vhead; vent; vent = vent->next) { 564270096Strasz v = vent->var; 565270096Strasz if (v->flag & DSIZ) { 566272931Strasz v->dwidth = v->width; 567272470Strasz v->width = 0; 568270096Strasz } 569272931Strasz if (v->flag & USER) 570272931Strasz needuser = 1; 571272931Strasz if (v->flag & COMM) 572272931Strasz needcomm = 1; 573270096Strasz } 574270096Strasz} 575270096Strasz 576270096Straszstatic void 577270096Straszdynsizevars(KINFO *ki) 578270096Strasz{ 579270096Strasz struct varent *vent; 580270096Strasz VAR *v; 581270096Strasz int i; 582270096Strasz 583270096Strasz for (vent = vhead; vent; vent = vent->next) { 584270096Strasz v = vent->var; 585270096Strasz if (!(v->flag & DSIZ)) 586270096Strasz continue; 587270096Strasz i = (v->sproc)( ki); 588270096Strasz if (v->width < i) 589270096Strasz v->width = i; 590270096Strasz if (v->width > v->dwidth) 591270096Strasz v->width = v->dwidth; 592270096Strasz } 593270096Strasz} 594297236Strasz 595297236Straszstatic void 596270096Straszsizevars(void) 597270096Strasz{ 598270096Strasz struct varent *vent; 599270096Strasz VAR *v; 600270096Strasz int i; 601270096Strasz 602270096Strasz for (vent = vhead; vent; vent = vent->next) { 603270096Strasz v = vent->var; 604270096Strasz i = strlen(vent->header); 605297236Strasz if (v->width < i) 606297236Strasz v->width = i; 607270096Strasz totwidth += v->width + 1; /* +1 for space */ 608270096Strasz } 609270096Strasz totwidth--; 610297236Strasz} 611297236Strasz 612297236Straszstatic const char * 613297236Straszfmt(char **(*fn)(kvm_t *, const struct kinfo_proc *, int), KINFO *ki, 614270096Strasz char *comm, int maxlen) 615297236Strasz{ 616297236Strasz const char *s; 617297236Strasz 618270096Strasz s = fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen); 619270096Strasz return (s); 620297236Strasz} 621297236Strasz 622270096Strasz#define UREADOK(ki) (forceuread || (ki->ki_p->ki_sflag & PS_INMEM)) 623270096Strasz 624297236Straszstatic void 625297236Straszsaveuser(KINFO *ki) 626297236Strasz{ 627270096Strasz 628270096Strasz if (ki->ki_p->ki_sflag & PS_INMEM) { 629270096Strasz /* 630270096Strasz * The u-area might be swapped out, and we can't get 631270096Strasz * at it because we have a crashdump and no swap. 632270096Strasz * If it's here fill in these fields, otherwise, just 633270096Strasz * leave them 0. 634272470Strasz */ 635297236Strasz ki->ki_valid = 1; 636270096Strasz } else 637270096Strasz ki->ki_valid = 0; 638270096Strasz /* 639270096Strasz * save arguments if needed 640270096Strasz */ 641297236Strasz if (needcomm && (UREADOK(ki) || (ki->ki_p->ki_args != NULL))) { 642270096Strasz ki->ki_args = strdup(fmt(kvm_getargv, ki, ki->ki_p->ki_comm, 643270096Strasz MAXCOMLEN)); 644270096Strasz } else if (needcomm) { 645270096Strasz asprintf(&ki->ki_args, "(%s)", ki->ki_p->ki_comm); 646270096Strasz } else { 647270096Strasz ki->ki_args = NULL; 648272512Strasz } 649272512Strasz if (needenv && UREADOK(ki)) { 650270096Strasz ki->ki_env = strdup(fmt(kvm_getenvv, ki, (char *)NULL, 0)); 651270096Strasz } else if (needenv) { 652270096Strasz ki->ki_env = malloc(3); 653270096Strasz strcpy(ki->ki_env, "()"); 654270096Strasz } else { 655270096Strasz ki->ki_env = NULL; 656270096Strasz } 657270096Strasz} 658270096Strasz 659270096Straszstatic int 660272512Straszpscomp(const void *a, const void *b) 661270096Strasz{ 662270096Strasz int i; 663270096Strasz#define VSIZE(k) ((k)->ki_p->ki_dsize + (k)->ki_p->ki_ssize + \ 664270096Strasz (k)->ki_p->ki_tsize) 665270096Strasz 666270096Strasz if (sortby == SORTCPU) 667270096Strasz return (getpcpu((const KINFO *)b) - getpcpu((const KINFO *)a)); 668270096Strasz if (sortby == SORTMEM) 669270096Strasz return (VSIZE((const KINFO *)b) - VSIZE((const KINFO *)a)); 670270096Strasz i = (int)((const KINFO *)a)->ki_p->ki_tdev - (int)((const KINFO *)b)->ki_p->ki_tdev; 671270096Strasz if (i == 0) 672270096Strasz i = ((const KINFO *)a)->ki_p->ki_pid - ((const KINFO *)b)->ki_p->ki_pid; 673270096Strasz return (i); 674270096Strasz} 675270096Strasz 676270096Strasz/* 677270096Strasz * ICK (all for getopt), would rather hide the ugliness 678270096Strasz * here than taint the main code. 679270096Strasz * 680270096Strasz * ps foo -> ps -foo 681270096Strasz * ps 34 -> ps -p34 682270096Strasz * 683270096Strasz * The old convention that 't' with no trailing tty arg means the users 684270096Strasz * tty, is only supported if argv[1] doesn't begin with a '-'. This same 685270096Strasz * feature is available with the option 'T', which takes no argument. 686270096Strasz */ 687270096Straszstatic char * 688270096Straszkludge_oldps_options(char *s) 689270096Strasz{ 690270096Strasz int have_fmt; 691270096Strasz size_t len; 692270096Strasz char *newopts, *ns, *cp; 693270096Strasz 694270096Strasz /* 695270096Strasz * If we have an 'o' option, then note it, since we don't want to do 696270096Strasz * some types of munging. 697270096Strasz */ 698270096Strasz have_fmt = index(s, 'o') != NULL; 699270096Strasz 700272512Strasz len = strlen(s); 701272512Strasz if ((newopts = ns = malloc(len + 2)) == NULL) 702270096Strasz errx(1, "malloc failed"); 703270096Strasz /* 704300047Strasz * options begin with '-' 705270096Strasz */ 706270096Strasz if (*s != '-') 707270096Strasz *ns++ = '-'; /* add option flag */ 708270096Strasz /* 709270096Strasz * gaze to end of argv[1] 710270096Strasz */ 711270096Strasz cp = s + len - 1; 712270096Strasz /* 713270096Strasz * if last letter is a 't' flag with no argument (in the context 714270096Strasz * of the oldps options -- option string NOT starting with a '-' -- 715270096Strasz * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). 716270096Strasz * 717 * However, if a flag accepting a string argument is found in the 718 * option string, the remainder of the string is the argument to 719 * that flag; do not modify that argument. 720 */ 721 if (strcspn(s, "MNOoU") == len && *cp == 't' && *s != '-') 722 *cp = 'T'; 723 else { 724 /* 725 * otherwise check for trailing number, which *may* be a 726 * pid. 727 */ 728 while (cp >= s && isdigit(*cp)) 729 --cp; 730 } 731 cp++; 732 memmove(ns, s, (size_t)(cp - s)); /* copy up to trailing number */ 733 ns += cp - s; 734 /* 735 * if there's a trailing number, and not a preceding 'p' (pid) or 736 * 't' (tty) flag, then assume it's a pid and insert a 'p' flag. 737 */ 738 if (isdigit(*cp) && 739 (cp == s || (cp[-1] != 't' && cp[-1] != 'p')) && 740 (cp - 1 == s || cp[-2] != 't') && !have_fmt) 741 *ns++ = 'p'; 742 (void)strcpy(ns, cp); /* and append the number */ 743 744 return (newopts); 745} 746 747static void 748usage(void) 749{ 750 751 (void)fprintf(stderr, "%s\n%s\n%s\n", 752 "usage: ps [-aCHhjlmrSTuvwxZ] [-O|o fmt] [-p pid[,pid]] [-t tty]", 753 " [-U user[,user]] [-M core] [-N system]", 754 " ps [-L]"); 755 exit(1); 756} 757