ps.c revision 127542
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 * Copyright (c) 2004 - Garance Alistair Drosehn <gad@FreeBSD.org>. 341556Srgrimes * All rights reserved. 351556Srgrimes * 361556Srgrimes * Significant modifications made to bring `ps' options somewhat closer 371556Srgrimes * to the standard for `ps' as described in SingleUnixSpec-v3. 3836150Scharnier * ------+---------+---------+-------- + --------+---------+---------+---------* 3936150Scharnier */ 4036150Scharnier 4136150Scharnier#ifndef lint 4250471Speterstatic const char copyright[] = 431556Srgrimes"@(#) Copyright (c) 1990, 1993, 1994\n\ 441556Srgrimes The Regents of the University of California. All rights reserved.\n"; 4517987Speter#endif /* not lint */ 4617987Speter 471556Srgrimes#if 0 481556Srgrimes#ifndef lint 491556Srgrimesstatic char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94"; 501556Srgrimes#endif /* not lint */ 511556Srgrimes#endif 521556Srgrimes 531556Srgrimes#include <sys/cdefs.h> 541556Srgrimes__FBSDID("$FreeBSD: head/bin/ps/ps.c 127542 2004-03-29 01:15:27Z gad $"); 551556Srgrimes 561556Srgrimes#include <sys/param.h> 571556Srgrimes#include <sys/user.h> 581556Srgrimes#include <sys/stat.h> 591556Srgrimes#include <sys/ioctl.h> 601556Srgrimes#include <sys/sysctl.h> 6117987Speter 6259436Scracauer#include <ctype.h> 6317987Speter#include <err.h> 641556Srgrimes#include <errno.h> 6517987Speter#include <fcntl.h> 661556Srgrimes#include <grp.h> 671556Srgrimes#include <kvm.h> 681556Srgrimes#include <limits.h> 691556Srgrimes#include <locale.h> 701556Srgrimes#include <paths.h> 711556Srgrimes#include <pwd.h> 721556Srgrimes#include <stdint.h> 731556Srgrimes#include <stdio.h> 7417987Speter#include <stdlib.h> 751556Srgrimes#include <string.h> 761556Srgrimes#include <unistd.h> 771556Srgrimes 781556Srgrimes#include "ps.h" 791556Srgrimes 801556Srgrimes#define W_SEP " \t" /* "Whitespace" list separators */ 811556Srgrimes#define T_SEP "," /* "Terminate-element" list separators */ 821556Srgrimes 831556Srgrimes#ifdef LAZY_PS 841556Srgrimes#define DEF_UREAD 0; 851556Srgrimes#define OPT_LAZY_f "f" 861556Srgrimes#else 871556Srgrimes#define DEF_UREAD 1; /* Always do the more-expensive read. */ 881556Srgrimes#define OPT_LAZY_f /* I.e., the `-f' option is not added. */ 891556Srgrimes#endif 901556Srgrimes 911556Srgrimesint cflag; /* -c */ 921556Srgrimesint eval; /* Exit value */ 931556Srgrimestime_t now; /* Current time(3) value */ 941556Srgrimesint rawcpu; /* -C */ 951556Srgrimesint sumrusage; /* -S */ 961556Srgrimesint termwidth; /* Width of the screen (0 == infinity). */ 971556Srgrimesint totwidth; /* Calculated-width of requested variables. */ 981556Srgrimes 991556Srgrimesstruct varent *vhead; 1001556Srgrimes 10118018Speterstatic int forceuread = DEF_UREAD; /* Do extra work to get u-area. */ 10218018Speterstatic kvm_t *kd; 1031556Srgrimesstatic KINFO *kinfo; 1041556Srgrimesstatic int needcomm; /* -o "command" */ 1051556Srgrimesstatic int needenv; /* -e */ 1061556Srgrimesstatic int needuser; /* -o "user" */ 1071556Srgrimesstatic int optfatal; /* Fatal error parsing some list-option. */ 1081556Srgrimes 1091556Srgrimesstatic enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; 1101556Srgrimes 11190111Simpstruct listinfo; 11290111Simptypedef int addelem_rtn(struct listinfo *_inf, const char *_elem); 11390111Simp 11490111Simpstruct listinfo { 11590111Simp int count; 11690111Simp int maxcount; 11790111Simp int elemsize; 11890111Simp addelem_rtn *addelem; 11990111Simp const char *lname; 12090111Simp union { 12190111Simp gid_t *gids; 12290111Simp pid_t *pids; 12390111Simp dev_t *ttys; 12490111Simp uid_t *uids; 12590111Simp void *ptr; 12690111Simp }; 1271556Srgrimes}; 12817987Speter 1291556Srgrimesstatic int addelem_gid(struct listinfo *, const char *); 1301556Srgrimesstatic int addelem_pid(struct listinfo *, const char *); 1311556Srgrimesstatic int addelem_tty(struct listinfo *, const char *); 1321556Srgrimesstatic int addelem_uid(struct listinfo *, const char *); 1331556Srgrimesstatic void add_list(struct listinfo *, const char *); 1341556Srgrimesstatic void dynsizevars(KINFO *); 13590111Simpstatic void *expand_list(struct listinfo *); 13617987Speterstatic const char *fmt(char **(*)(kvm_t *, const struct kinfo_proc *, int), 1371556Srgrimes KINFO *, char *, int); 1381556Srgrimesstatic void free_list(struct listinfo *); 13960593Scracauerstatic void init_list(struct listinfo *, addelem_rtn, int, const char *); 1401556Srgrimesstatic char *kludge_oldps_options(char *); 1411556Srgrimesstatic int pscomp(const void *, const void *); 1421556Srgrimesstatic void saveuser(KINFO *); 1431556Srgrimesstatic void scanvars(void); 1441556Srgrimesstatic void sizevars(void); 1451556Srgrimesstatic void usage(void); 1461556Srgrimes 1471556Srgrimesstatic char dfmt[] = "pid,tt,state,time,command"; 1481556Srgrimesstatic char jfmt[] = "user,pid,ppid,pgid,jobc,state,tt,time,command"; 1491556Srgrimesstatic char lfmt[] = "uid,pid,ppid,cpu,pri,nice,vsz,rss,mwchan,state," 1501556Srgrimes "tt,time,command"; 1511556Srgrimesstatic char o1[] = "pid"; 1521556Srgrimesstatic char o2[] = "tt,state,time,command"; 1531556Srgrimesstatic char ufmt[] = "user,pid,%cpu,%mem,vsz,rss,tt,state,start,time,command"; 1541556Srgrimesstatic char vfmt[] = "pid,state,time,sl,re,pagein,vsz,rss,lim,tsiz," 1551556Srgrimes "%cpu,%mem,command"; 1561556Srgrimesstatic char Zfmt[] = "label"; 15790111Simp 15817987Speter#define PS_ARGS "AaCc" OPT_LAZY_f "G:gHhjLlM:mN:O:o:p:rSTt:U:uvwXxZ" 1591556Srgrimes 16017987Speterint 1611556Srgrimesmain(int argc, char *argv[]) 1621556Srgrimes{ 1631556Srgrimes struct listinfo gidlist, pgrplist, pidlist; 1641556Srgrimes struct listinfo ruidlist, sesslist, ttylist, uidlist; 16517987Speter struct kinfo_proc *kp; 1661556Srgrimes struct varent *vent; 16717987Speter struct winsize ws; 16817987Speter const char *cp, *nlistf, *memf; 16917987Speter char *cols; 17017987Speter int all, ch, dropgid, elem, flag, _fmt, i, lineno; 17117987Speter int nentries, nocludge, nkept, nselectors; 17217987Speter int prtheader, showthreads, wflag, what, xkeep, xkeep_implied; 17317987Speter char errbuf[_POSIX2_LINE_MAX]; 17417987Speter 17517987Speter (void) setlocale(LC_ALL, ""); 17617987Speter time(&now); /* Used by routines in print.c. */ 17717987Speter 17817987Speter if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0') 17917987Speter termwidth = atoi(cols); 18017987Speter else if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && 18117987Speter ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && 18217987Speter ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) || 18317987Speter ws.ws_col == 0) 18417987Speter termwidth = 79; 18517987Speter else 18617987Speter termwidth = ws.ws_col - 1; 18717987Speter 18817987Speter /* 18917987Speter * Don't apply a kludge if the first argument is an option taking an 19017987Speter * argument 19117987Speter */ 19217987Speter if (argc > 1) { 19313882Sjoerg nocludge = 0; 19417987Speter if (argv[1][0] == '-') { 19517987Speter for (cp = PS_ARGS; *cp != '\0'; cp++) { 19617987Speter if (*cp != ':') 1971556Srgrimes continue; 19817987Speter if (*(cp - 1) == argv[1][1]) { 19917987Speter nocludge = 1; 20017987Speter break; 20117987Speter } 20217987Speter } 20317987Speter } 20417987Speter if (nocludge == 0) 2051556Srgrimes argv[1] = kludge_oldps_options(argv[1]); 2061556Srgrimes } 2071556Srgrimes 2081556Srgrimes all = dropgid = _fmt = nselectors = optfatal = 0; 2091556Srgrimes prtheader = showthreads = wflag = xkeep_implied = 0; 2101556Srgrimes xkeep = -1; /* Neither -x nor -X. */ 2111556Srgrimes init_list(&gidlist, addelem_gid, sizeof(gid_t), "group"); 2121556Srgrimes init_list(&pgrplist, addelem_pid, sizeof(pid_t), "process group"); 2131556Srgrimes init_list(&pidlist, addelem_pid, sizeof(pid_t), "process id"); 2141556Srgrimes init_list(&ruidlist, addelem_uid, sizeof(uid_t), "ruser"); 2151556Srgrimes init_list(&sesslist, addelem_pid, sizeof(pid_t), "session id"); 2161556Srgrimes init_list(&ttylist, addelem_tty, sizeof(dev_t), "tty"); 2171556Srgrimes init_list(&uidlist, addelem_uid, sizeof(uid_t), "user"); 2181556Srgrimes memf = nlistf = _PATH_DEVNULL; 2191556Srgrimes while ((ch = getopt(argc, argv, PS_ARGS)) != -1) 2201556Srgrimes switch((char)ch) { 2211556Srgrimes case 'A': 2221556Srgrimes /* 2231556Srgrimes * Exactly the same as `-ax'. This has been 2241556Srgrimes * added for compatability with SUSv3, but for 2251556Srgrimes * now it will not be described in the man page. 2261556Srgrimes */ 22790111Simp nselectors++; 22890111Simp all = xkeep = 1; 2291556Srgrimes break; 2301556Srgrimes case 'a': 2311556Srgrimes nselectors++; 2321556Srgrimes all = 1; 2331556Srgrimes break; 2341556Srgrimes case 'C': 2351556Srgrimes rawcpu = 1; 2361556Srgrimes break; 2371556Srgrimes case 'c': 2381556Srgrimes cflag = 1; 2391556Srgrimes break; 2401556Srgrimes case 'e': /* XXX set ufmt */ 2411556Srgrimes needenv = 1; 2421556Srgrimes break; 2431556Srgrimes#ifdef LAZY_PS 2441556Srgrimes case 'f': 2451556Srgrimes if (getuid() == 0 || getgid() == 0) 2461556Srgrimes forceuread = 1; 2471556Srgrimes break; 2481556Srgrimes#endif 2491556Srgrimes case 'G': 2501556Srgrimes add_list(&gidlist, optarg); 2511556Srgrimes xkeep_implied = 1; 2521556Srgrimes nselectors++; 2531556Srgrimes break; 25490111Simp case 'g': 25590111Simp#if 0 25675336Sbrian /* 2571556Srgrimes * XXX - This SUSv3 behavior is still under debate 25875336Sbrian * since it conflicts with the (undocumented) 2591556Srgrimes * `-g' option. So we skip it for now. 26075336Sbrian */ 2611556Srgrimes add_list(&pgrplist, optarg); 26275336Sbrian xkeep_implied = 1; 26375336Sbrian nselectors++; 26475336Sbrian break; 2651556Srgrimes#else 2661556Srgrimes /* The historical BSD-ish (from SunOS) behavior. */ 2671556Srgrimes break; /* no-op */ 2681556Srgrimes#endif 2691556Srgrimes case 'H': 2701556Srgrimes showthreads = KERN_PROC_INC_THREAD; 2711556Srgrimes break; 2721556Srgrimes case 'h': 2731556Srgrimes prtheader = ws.ws_row > 5 ? ws.ws_row : 22; 2741556Srgrimes break; 2751556Srgrimes case 'j': 2761556Srgrimes parsefmt(jfmt, 0); 2771556Srgrimes _fmt = 1; 2781556Srgrimes jfmt[0] = '\0'; 2791556Srgrimes break; 2801556Srgrimes case 'L': 2811556Srgrimes showkey(); 2821556Srgrimes exit(0); 28375336Sbrian case 'l': 28475336Sbrian parsefmt(lfmt, 0); 28575336Sbrian _fmt = 1; 28675336Sbrian lfmt[0] = '\0'; 28775336Sbrian break; 28875336Sbrian case 'M': 28975336Sbrian memf = optarg; 2901556Srgrimes dropgid = 1; 2911556Srgrimes break; 2921556Srgrimes case 'm': 2931556Srgrimes sortby = SORTMEM; 2941556Srgrimes break; 29590111Simp case 'N': 29690111Simp nlistf = optarg; 2971556Srgrimes dropgid = 1; 2981556Srgrimes break; 2991556Srgrimes case 'O': 3001556Srgrimes parsefmt(o1, 1); 30175160Sbrian parsefmt(optarg, 1); 3021556Srgrimes parsefmt(o2, 1); 3031556Srgrimes o1[0] = o2[0] = '\0'; 30417987Speter _fmt = 1; 30517987Speter break; 3061556Srgrimes case 'o': 30720425Ssteve parsefmt(optarg, 1); 3081556Srgrimes _fmt = 1; 3091556Srgrimes break; 3101556Srgrimes case 'p': 3111556Srgrimes add_list(&pidlist, optarg); 3121556Srgrimes /* 3131556Srgrimes * Note: `-p' does not *set* xkeep, but any values 3141556Srgrimes * from pidlist are checked before xkeep is. That 3151556Srgrimes * way they are always matched, even if the user 31675160Sbrian * specifies `-X'. 31775160Sbrian */ 31875160Sbrian nselectors++; 31975160Sbrian break; 32075160Sbrian#if 0 32175160Sbrian case 'R': 3221556Srgrimes /* 3231556Srgrimes * XXX - This un-standard option is still under 3241556Srgrimes * debate. This is what SUSv3 defines as 3251556Srgrimes * the `-U' option, and while it would be 3261556Srgrimes * nice to have, it could cause even more 3271556Srgrimes * confusion to implement it as `-R'. 3281556Srgrimes */ 3291556Srgrimes add_list(&ruidlist, optarg); 3301556Srgrimes xkeep_implied = 1; 3311556Srgrimes nselectors++; 3321556Srgrimes break; 3331556Srgrimes#endif 3341556Srgrimes case 'r': 3351556Srgrimes sortby = SORTCPU; 3361556Srgrimes break; 3371556Srgrimes case 'S': 3381556Srgrimes sumrusage = 1; 3391556Srgrimes break; 3401556Srgrimes#if 0 3411556Srgrimes case 's': 3421556Srgrimes /* 3431556Srgrimes * XXX - This non-standard option is still under 3441556Srgrimes * debate. This *is* supported on Solaris, 3451556Srgrimes * Linux, and IRIX, but conflicts with `-s' 3461556Srgrimes * on NetBSD and maybe some older BSD's. 3471556Srgrimes */ 3481556Srgrimes add_list(&sesslist, optarg); 3491556Srgrimes xkeep_implied = 1; 3501556Srgrimes nselectors++; 3511556Srgrimes break; 3521556Srgrimes#endif 3531556Srgrimes case 'T': 3541556Srgrimes if ((optarg = ttyname(STDIN_FILENO)) == NULL) 3551556Srgrimes errx(1, "stdin: not a terminal"); 3561556Srgrimes /* FALLTHROUGH */ 3571556Srgrimes case 't': 3581556Srgrimes add_list(&ttylist, optarg); 3591556Srgrimes xkeep_implied = 1; 3601556Srgrimes nselectors++; 3611556Srgrimes break; 3621556Srgrimes case 'U': 3631556Srgrimes /* This is what SUSv3 defines as the `-u' option. */ 3641556Srgrimes add_list(&uidlist, optarg); 3651556Srgrimes xkeep_implied = 1; 3661556Srgrimes nselectors++; 3671556Srgrimes break; 3681556Srgrimes case 'u': 3691556Srgrimes parsefmt(ufmt, 0); 3701556Srgrimes sortby = SORTCPU; 3711556Srgrimes _fmt = 1; 3721556Srgrimes ufmt[0] = '\0'; 3731556Srgrimes break; 3741556Srgrimes case 'v': 3751556Srgrimes parsefmt(vfmt, 0); 3761556Srgrimes sortby = SORTMEM; 3771556Srgrimes _fmt = 1; 3781556Srgrimes vfmt[0] = '\0'; 3791556Srgrimes break; 3801556Srgrimes case 'w': 3811556Srgrimes if (wflag) 3821556Srgrimes termwidth = UNLIMITED; 3831556Srgrimes else if (termwidth < 131) 3841556Srgrimes termwidth = 131; 3851556Srgrimes wflag++; 3861556Srgrimes break; 3871556Srgrimes case 'X': 3881556Srgrimes /* 3891556Srgrimes * Note that `-X' and `-x' are not standard "selector" 3901556Srgrimes * options. For most selector-options, we check *all* 3911556Srgrimes * processes to see if any are matched by the given 3921556Srgrimes * value(s). After we have a set of all the matched 3931556Srgrimes * processes, then `-X' and `-x' govern whether we 3941556Srgrimes * modify that *matched* set for processes which do 3951556Srgrimes * not have a controlling terminal. `-X' causes 3961556Srgrimes * those processes to be deleted from the matched 3971556Srgrimes * set, while `-x' causes them to be kept. 3981556Srgrimes */ 3991556Srgrimes xkeep = 0; 4001556Srgrimes break; 4011556Srgrimes case 'x': 4021556Srgrimes xkeep = 1; 4031556Srgrimes break; 4041556Srgrimes case 'Z': 4051556Srgrimes parsefmt(Zfmt, 0); 4061556Srgrimes Zfmt[0] = '\0'; 4071556Srgrimes break; 4081556Srgrimes case '?': 4091556Srgrimes default: 4101556Srgrimes usage(); 4111556Srgrimes } 4121556Srgrimes argc -= optind; 4131556Srgrimes argv += optind; 4141556Srgrimes if (optfatal) 4151556Srgrimes exit(1); /* Error messages already printed. */ 4161556Srgrimes if (xkeep < 0) /* Neither -X nor -x was specified. */ 4171556Srgrimes xkeep = xkeep_implied; 4181556Srgrimes 4191556Srgrimes#define BACKWARD_COMPATIBILITY 4201556Srgrimes#ifdef BACKWARD_COMPATIBILITY 4211556Srgrimes if (*argv) { 4221556Srgrimes nlistf = *argv; 4231556Srgrimes if (*++argv) 4241556Srgrimes memf = *argv; 4251556Srgrimes } 4261556Srgrimes#endif 4271556Srgrimes /* 4281556Srgrimes * Discard setgid privileges if not the running kernel so that bad 4291556Srgrimes * guys can't print interesting stuff from kernel memory. 43018018Speter */ 4312760Ssef if (dropgid) { 4322760Ssef setgid(getgid()); 4331556Srgrimes setuid(getuid()); 4341556Srgrimes } 4351556Srgrimes 4361556Srgrimes kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 4371556Srgrimes if (kd == 0) 4381556Srgrimes errx(1, "%s", errbuf); 4391556Srgrimes 4401556Srgrimes if (!_fmt) 4412760Ssef parsefmt(dfmt, 0); 4421556Srgrimes 4431556Srgrimes if (nselectors == 0) { 4442760Ssef uidlist.ptr = malloc(sizeof(uid_t)); 4451556Srgrimes if (uidlist.ptr == NULL) 4461556Srgrimes errx(1, "malloc failed"); 4471556Srgrimes nselectors = 1; 44818018Speter uidlist.count = uidlist.maxcount = 1; 4491556Srgrimes *uidlist.uids = getuid(); 4502760Ssef } 4512760Ssef 4522760Ssef /* 4532760Ssef * scan requested variables, noting what structures are needed, 45418018Speter * and adjusting header widths as appropriate. 4552760Ssef */ 4562760Ssef scanvars(); 4572760Ssef 4581556Srgrimes /* 4592760Ssef * Get process list. If the user requested just one selector- 46018018Speter * option, then kvm_getprocs can be asked to return just those 4611556Srgrimes * processes. Otherwise, have it return all processes, and 4621556Srgrimes * then this routine will search that full list and select the 4631556Srgrimes * processes which match any of the user's selector-options. 4641556Srgrimes */ 4651556Srgrimes what = showthreads != 0 ? KERN_PROC_ALL : KERN_PROC_PROC; 4661556Srgrimes flag = 0; 4671556Srgrimes if (nselectors == 1) { 4681556Srgrimes /* XXX - Apparently there's no KERN_PROC_GID flag. */ 4691556Srgrimes if (pgrplist.count == 1) { 4701556Srgrimes what = KERN_PROC_PGRP | showthreads; 4711556Srgrimes flag = *pgrplist.pids; 4721556Srgrimes nselectors = 0; 4731556Srgrimes } else if (pidlist.count == 1) { 4741556Srgrimes what = KERN_PROC_PID | showthreads; 4751556Srgrimes flag = *pidlist.pids; 4761556Srgrimes nselectors = 0; 4771556Srgrimes } else if (ruidlist.count == 1) { 4781556Srgrimes what = KERN_PROC_RUID | showthreads; 4791556Srgrimes flag = *ruidlist.uids; 48017987Speter nselectors = 0; 48117987Speter#if 0 48217987Speter /* 48317987Speter * XXX - KERN_PROC_SESSION causes error in kvm_getprocs? 48417987Speter * For now, always do sid-matching in this routine. 48517987Speter */ 48617987Speter } else if (sesslist.count == 1) { 48720425Ssteve what = KERN_PROC_SESSION | showthreads; 48820425Ssteve flag = *sesslist.pids; 4891556Srgrimes nselectors = 0; 49010399Sjoerg#endif 4911556Srgrimes } else if (ttylist.count == 1) { 49217987Speter what = KERN_PROC_TTY | showthreads; 4931556Srgrimes flag = *ttylist.ttys; 49475160Sbrian nselectors = 0; 49575160Sbrian } else if (uidlist.count == 1) { 4961556Srgrimes what = KERN_PROC_UID | showthreads; 4971556Srgrimes flag = *uidlist.uids; 4981556Srgrimes nselectors = 0; 4991556Srgrimes } else if (all) { 5001556Srgrimes /* No need for this routine to select processes. */ 5011556Srgrimes nselectors = 0; 5021556Srgrimes } 5031556Srgrimes } 5041556Srgrimes 5051556Srgrimes /* 5061556Srgrimes * select procs 5071556Srgrimes */ 5081556Srgrimes nentries = -1; 5091556Srgrimes kp = kvm_getprocs(kd, what, flag, &nentries); 5101556Srgrimes if ((kp == 0 && nentries > 0) || (kp != 0 && nentries < 0)) 5111556Srgrimes errx(1, "%s", kvm_geterr(kd)); 5121556Srgrimes nkept = 0; 5131556Srgrimes if (nentries > 0) { 5141556Srgrimes if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL) 5151556Srgrimes errx(1, "malloc failed"); 5161556Srgrimes for (i = nentries; --i >= 0; ++kp) { 51775160Sbrian /* 51875160Sbrian * If the user specified multiple selection-criteria, 51975160Sbrian * then keep any process matched by the inclusive OR 52075160Sbrian * of all the selection-criteria given. 52175160Sbrian */ 52275160Sbrian if (pidlist.count > 0) { 52375160Sbrian for (elem = 0; elem < pidlist.count; elem++) 52475160Sbrian if (kp->ki_pid == pidlist.pids[elem]) 52575160Sbrian goto keepit; 52675160Sbrian } 5271556Srgrimes /* 5281556Srgrimes * Note that we had to process pidlist before 5291556Srgrimes * filtering out processes which do not have 5301556Srgrimes * a controlling terminal. 53190111Simp */ 53290111Simp if (xkeep == 0) { 5331556Srgrimes if ((kp->ki_tdev == NODEV || 5341556Srgrimes (kp->ki_flag & P_CONTROLT) == 0)) 53575160Sbrian continue; 53675160Sbrian } 5371556Srgrimes if (nselectors == 0) 5381556Srgrimes goto keepit; 5391556Srgrimes if (gidlist.count > 0) { 5401556Srgrimes for (elem = 0; elem < gidlist.count; elem++) 5411556Srgrimes if (kp->ki_rgid == gidlist.gids[elem]) 5421556Srgrimes goto keepit; 5431556Srgrimes } 5441556Srgrimes if (pgrplist.count > 0) { 5458855Srgrimes for (elem = 0; elem < pgrplist.count; elem++) 5461556Srgrimes if (kp->ki_pgid == pgrplist.pids[elem]) 5471556Srgrimes goto keepit; 5488855Srgrimes } 5491556Srgrimes if (ruidlist.count > 0) { 5501556Srgrimes for (elem = 0; elem < ruidlist.count; elem++) 5511556Srgrimes if (kp->ki_ruid == ruidlist.uids[elem]) 55275160Sbrian goto keepit; 55375160Sbrian } 55475160Sbrian if (sesslist.count > 0) { 55575160Sbrian for (elem = 0; elem < sesslist.count; elem++) 55675160Sbrian if (kp->ki_sid == sesslist.pids[elem]) 55775160Sbrian goto keepit; 5581556Srgrimes } 5591556Srgrimes if (ttylist.count > 0) { 5601556Srgrimes for (elem = 0; elem < ttylist.count; elem++) 5611556Srgrimes if (kp->ki_tdev == ttylist.ttys[elem]) 5621556Srgrimes goto keepit; 5631556Srgrimes } 5641556Srgrimes if (uidlist.count > 0) { 5651556Srgrimes for (elem = 0; elem < uidlist.count; elem++) 5661556Srgrimes if (kp->ki_uid == uidlist.uids[elem]) 5671556Srgrimes goto keepit; 5681556Srgrimes } 5691556Srgrimes /* 5701556Srgrimes * This process did not match any of the user's 5711556Srgrimes * selector-options, so skip the process. 5721556Srgrimes */ 5731556Srgrimes continue; 5741556Srgrimes 5751556Srgrimes keepit: 5761556Srgrimes kinfo[nkept].ki_p = kp; 5771556Srgrimes if (needuser) 5781556Srgrimes saveuser(&kinfo[nkept]); 5791556Srgrimes dynsizevars(&kinfo[nkept]); 5801556Srgrimes nkept++; 58175160Sbrian } 5821556Srgrimes } 5831556Srgrimes 5841556Srgrimes sizevars(); 5851556Srgrimes 5861556Srgrimes /* 5871556Srgrimes * print header 5881556Srgrimes */ 5891556Srgrimes printheader(); 5901556Srgrimes if (nkept == 0) 5911556Srgrimes exit(1); 5921556Srgrimes 5931556Srgrimes /* 59475160Sbrian * sort proc list 59575160Sbrian */ 59675160Sbrian qsort(kinfo, nkept, sizeof(KINFO), pscomp); 59775160Sbrian /* 59875160Sbrian * For each process, call each variable output function. 59975160Sbrian */ 60075160Sbrian for (i = lineno = 0; i < nkept; i++) { 60175160Sbrian for (vent = vhead; vent; vent = vent->next) { 60275160Sbrian (vent->var->oproc)(&kinfo[i], vent); 60375160Sbrian if (vent->next != NULL) 6041556Srgrimes (void)putchar(' '); 6051556Srgrimes } 60617987Speter (void)putchar('\n'); 60790111Simp if (prtheader && lineno++ == prtheader - 4) { 60890111Simp (void)putchar('\n'); 60917987Speter printheader(); 6101556Srgrimes lineno = 0; 61117987Speter } 61217987Speter } 61317987Speter free_list(&gidlist); 61417987Speter free_list(&pidlist); 61517987Speter free_list(&pgrplist); 61617987Speter free_list(&ruidlist); 61717987Speter free_list(&sesslist); 61817987Speter free_list(&ttylist); 61990111Simp free_list(&uidlist); 62090111Simp 62117987Speter exit(eval); 62217987Speter} 62317987Speter 62417987Speterstatic int 62517987Speteraddelem_gid(struct listinfo *inf, const char *elem) 62617987Speter{ 62717987Speter struct group *grp; 62817987Speter const char *nameorID; 62917987Speter char *endp; 63020425Ssteve intmax_t ltemp; 63117987Speter 63217987Speter if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) { 63317987Speter if (*elem == '\0') 63417987Speter warnx("Invalid (zero-length) %s name", inf->lname); 63517987Speter else 63617987Speter warnx("%s name too long: %s", inf->lname, elem); 63717987Speter optfatal = 1; 63817987Speter return (0); /* Do not add this value. */ 6391556Srgrimes } 64090111Simp 64190111Simp /* 6421556Srgrimes * SUSv3 states that `ps -G grouplist' should match "real-group 6431556Srgrimes * ID numbers", and does not mention group-names. I do want to 6441556Srgrimes * also support group-names, so this tries for a group-id first, 6451556Srgrimes * and only tries for a name if that doesn't work. This is the 6461556Srgrimes * opposite order of what is done in addelem_uid(), but in 6471556Srgrimes * practice the order would only matter for group-names which 6481556Srgrimes * are all-numeric. 6491556Srgrimes */ 6501556Srgrimes grp = NULL; 6511556Srgrimes nameorID = "named"; 6521556Srgrimes errno = 0; 6531556Srgrimes ltemp = strtol(elem, &endp, 10); 6541556Srgrimes if (errno == 0 && *endp == '\0' && ltemp >= 0 && ltemp <= GID_MAX) { 6551556Srgrimes nameorID = "name or ID matches"; 6561556Srgrimes grp = getgrgid((gid_t)ltemp); 6571556Srgrimes } 6581556Srgrimes if (grp == NULL) 6591556Srgrimes grp = getgrnam(elem); 6601556Srgrimes if (grp == NULL) { 6611556Srgrimes warnx("No %s %s '%s'", inf->lname, nameorID, elem); 6621556Srgrimes optfatal = 1; 6631556Srgrimes return (0); /* Do not add this value. */ 6641556Srgrimes } 6651556Srgrimes 6661556Srgrimes if (inf->count >= inf->maxcount) 6671556Srgrimes expand_list(inf); 6681556Srgrimes inf->gids[(inf->count)++] = grp->gr_gid; 6691556Srgrimes return (1); 67017987Speter} 6711556Srgrimes 67217987Speter#define BSD_PID_MAX 99999 /* Copy of PID_MAX from sys/proc.h. */ 6731556Srgrimesstatic int 6741556Srgrimesaddelem_pid(struct listinfo *inf, const char *elem) 6751556Srgrimes{ 6761556Srgrimes char *endp; 6771556Srgrimes long tempid; 6781556Srgrimes 6791556Srgrimes if (*elem == '\0') 6801556Srgrimes tempid = 0L; 6811556Srgrimes else { 68290111Simp errno = 0; 68390111Simp tempid = strtol(elem, &endp, 10); 6841556Srgrimes if (*endp != '\0' || tempid < 0 || elem == endp) { 6851556Srgrimes warnx("Invalid %s: %s", inf->lname, elem); 6861556Srgrimes errno = ERANGE; 6871556Srgrimes } else if (errno != 0 || tempid > BSD_PID_MAX) { 6881556Srgrimes warnx("%s too large: %s", inf->lname, elem); 6891556Srgrimes errno = ERANGE; 6901556Srgrimes } 6911556Srgrimes if (errno == ERANGE) { 6921556Srgrimes optfatal = 1; 6931556Srgrimes return (0); /* Do not add this value. */ 6941556Srgrimes } 6951556Srgrimes } 6961556Srgrimes 6971556Srgrimes if (inf->count >= inf->maxcount) 6981556Srgrimes expand_list(inf); 6991556Srgrimes inf->pids[(inf->count)++] = tempid; 7001556Srgrimes return (1); 7011556Srgrimes} 7021556Srgrimes#undef BSD_PID_MAX 7031556Srgrimes 7041556Srgrimesstatic int 7051556Srgrimesaddelem_tty(struct listinfo *inf, const char *elem) 70690111Simp{ 70790111Simp const char *ttypath; 7081556Srgrimes struct stat sb; 7091556Srgrimes char pathbuf[PATH_MAX]; 7101556Srgrimes 7111556Srgrimes if (strcmp(elem, "co") == 0) 7121556Srgrimes ttypath = strdup(_PATH_CONSOLE); 7131556Srgrimes else if (*elem == '/') 7141556Srgrimes ttypath = elem; 7151556Srgrimes else { 71690111Simp strlcpy(pathbuf, _PATH_TTY, sizeof(pathbuf)); 71790111Simp strlcat(pathbuf, elem, sizeof(pathbuf)); 7181556Srgrimes ttypath = pathbuf; 7191556Srgrimes } 7201556Srgrimes 7211556Srgrimes if (stat(ttypath, &sb) == -1) { 7221556Srgrimes warn("%s", ttypath); 7231556Srgrimes optfatal = 1; 7248855Srgrimes return (0); /* Do not add this value. */ 7251556Srgrimes } 7261556Srgrimes if (!S_ISCHR(sb.st_mode)) { 7271556Srgrimes warn("%s: Not a terminal", ttypath); 7281556Srgrimes optfatal = 1; 7291556Srgrimes return (0); /* Do not add this value. */ 7301556Srgrimes } 7311556Srgrimes 7321556Srgrimes if (inf->count >= inf->maxcount) 7331556Srgrimes expand_list(inf); 7341556Srgrimes inf->ttys[(inf->count)++] = sb.st_rdev; 7351556Srgrimes return (1); 7361556Srgrimes} 7371556Srgrimes 7381556Srgrimesstatic int 7391556Srgrimesaddelem_uid(struct listinfo *inf, const char *elem) 7401556Srgrimes{ 7411556Srgrimes struct passwd *pwd; 7421556Srgrimes char *endp; 74320425Ssteve intmax_t ltemp; 74417987Speter 74525230Ssteve if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) { 7461556Srgrimes if (*elem == '\0') 7471556Srgrimes warnx("Invalid (zero-length) %s name", inf->lname); 74820425Ssteve else 74917987Speter warnx("%s name too long: %s", inf->lname, elem); 7501556Srgrimes optfatal = 1; 7511556Srgrimes return (0); /* Do not add this value. */ 7521556Srgrimes } 7531556Srgrimes 7541556Srgrimes pwd = getpwnam(elem); 75518018Speter if (pwd == NULL) { 75618018Speter errno = 0; 7571556Srgrimes ltemp = strtol(elem, &endp, 10); 7581556Srgrimes if (errno != 0 || *endp != '\0' || ltemp < 0 || 7591556Srgrimes ltemp > UID_MAX) 7601556Srgrimes warnx("No %s named '%s'", inf->lname, elem); 7611556Srgrimes else { 7621556Srgrimes /* The string is all digits, so it might be a userID. */ 76375160Sbrian pwd = getpwuid((uid_t)ltemp); 7641556Srgrimes if (pwd == NULL) 7651556Srgrimes warnx("No %s name or ID matches '%s'", 7661556Srgrimes inf->lname, elem); 7671556Srgrimes } 7681556Srgrimes } 7691556Srgrimes if (pwd == NULL) { 7701556Srgrimes /* 7711556Srgrimes * These used to be treated as minor warnings (and the 7721556Srgrimes * option was simply ignored), but now they are fatal 7731556Srgrimes * errors (and the command will be aborted). 7741556Srgrimes */ 7751556Srgrimes optfatal = 1; 7761556Srgrimes return (0); /* Do not add this value. */ 7771556Srgrimes } 7781556Srgrimes 7791556Srgrimes if (inf->count >= inf->maxcount) 7801556Srgrimes expand_list(inf); 7811556Srgrimes inf->uids[(inf->count)++] = pwd->pw_uid; 7821556Srgrimes return (1); 7831556Srgrimes} 7841556Srgrimes 7851556Srgrimesstatic void 7861556Srgrimesadd_list(struct listinfo *inf, const char *argp) 7871556Srgrimes{ 7881556Srgrimes const char *savep; 7891556Srgrimes char *cp, *endp; 7901556Srgrimes int toolong; 7911556Srgrimes char elemcopy[PATH_MAX]; 7921556Srgrimes 7931556Srgrimes while (*argp != '\0') { 7941556Srgrimes while (*argp != '\0' && strchr(W_SEP, *argp) != NULL) 7951556Srgrimes argp++; 79690111Simp savep = argp; 79790111Simp toolong = 0; 79825230Ssteve cp = elemcopy; 7991556Srgrimes if (strchr(T_SEP, *argp) == NULL) { 8001556Srgrimes endp = elemcopy + sizeof(elemcopy) - 1; 8011556Srgrimes while (*argp != '\0' && cp <= endp && 8021556Srgrimes strchr(W_SEP T_SEP, *argp) == NULL) 8031556Srgrimes *cp++ = *argp++; 8041556Srgrimes if (cp > endp) 8051556Srgrimes toolong = 1; 8061556Srgrimes } 8071556Srgrimes if (!toolong) { 8081556Srgrimes *cp = '\0'; 8091556Srgrimes#ifndef ADD_PS_LISTRESET 8101556Srgrimes /* 8111556Srgrimes * This is how the standard expects lists to 8121556Srgrimes * be handled. 8131556Srgrimes */ 8141556Srgrimes inf->addelem(inf, elemcopy); 8151556Srgrimes#else 8161556Srgrimes /* 8171556Srgrimes * This would add a simple non-standard-but-convienent 8181556Srgrimes * feature. 8191556Srgrimes * 8201556Srgrimes * XXX - The first time I tried to add this check, 8211556Srgrimes * it increased the total size of `ps' by 3940 8221556Srgrimes * bytes on i386! That's 12% of the entire 8231556Srgrimes * program! The `ps.o' file grew by only about 8241556Srgrimes * 40 bytes, but the final (stripped) executable 8251556Srgrimes * in /bin/ps grew by 12%. I have not had time 8261556Srgrimes * to investigate, so skip the feature for now. 8271556Srgrimes */ 8281556Srgrimes /* 8291556Srgrimes * We now have a single element. Add it to the 8301556Srgrimes * list, unless the element is ":". In that case, 8311556Srgrimes * reset the list so previous entries are ignored. 8321556Srgrimes */ 8331556Srgrimes if (strcmp(elemcopy, ":") == 0) 8341556Srgrimes inf->count = 0; 8351556Srgrimes else 8361556Srgrimes inf->addelem(inf, elemcopy); 8371556Srgrimes#endif 8381556Srgrimes } else { 8391556Srgrimes /* 8401556Srgrimes * The string is too long to copy. Find the end 8411556Srgrimes * of the string to print out the warning message. 8421556Srgrimes */ 8431556Srgrimes while (*argp != '\0' && strchr(W_SEP T_SEP, 8441556Srgrimes *argp) == NULL) 8451556Srgrimes argp++; 8461556Srgrimes warnx("Value too long: %.*s", (int)(argp - savep), 8471556Srgrimes savep); 8481556Srgrimes optfatal = 1; 8491556Srgrimes } 8501556Srgrimes /* 8511556Srgrimes * Skip over any number of trailing whitespace characters, 8521556Srgrimes * but only one (at most) trailing element-terminating 8531556Srgrimes * character. 8541556Srgrimes */ 8551556Srgrimes while (*argp != '\0' && strchr(W_SEP, *argp) != NULL) 8561556Srgrimes argp++; 8571556Srgrimes if (*argp != '\0' && strchr(T_SEP, *argp) != NULL) { 8581556Srgrimes argp++; 8591556Srgrimes /* Catch case where string ended with a comma. */ 8601556Srgrimes if (*argp == '\0') 8611556Srgrimes inf->addelem(inf, argp); 8621556Srgrimes } 8631556Srgrimes } 8641556Srgrimes} 8651556Srgrimes 8661556Srgrimesstatic void * 8671556Srgrimesexpand_list(struct listinfo *inf) 8681556Srgrimes{ 8691556Srgrimes void *newlist; 8701556Srgrimes int newmax; 8711556Srgrimes 8721556Srgrimes newmax = (inf->maxcount + 1) << 1; 8731556Srgrimes newlist = realloc(inf->ptr, newmax * inf->elemsize); 8741556Srgrimes if (newlist == NULL) { 8751556Srgrimes free(inf->ptr); 8761556Srgrimes errx(1, "realloc to %d %ss failed", newmax, 8771556Srgrimes inf->lname); 8781556Srgrimes } 8791556Srgrimes inf->maxcount = newmax; 8801556Srgrimes inf->ptr = newlist; 8811556Srgrimes 8821556Srgrimes return (newlist); 8831556Srgrimes} 8841556Srgrimes 8851556Srgrimesstatic void 8861556Srgrimesfree_list(struct listinfo *inf) 88790111Simp{ 88890111Simp 88917987Speter inf->count = inf->elemsize = inf->maxcount = 0; 89017987Speter if (inf->ptr != NULL) 8911556Srgrimes free(inf->ptr); 8921556Srgrimes inf->addelem = NULL; 8931556Srgrimes inf->lname = NULL; 8941556Srgrimes inf->ptr = NULL; 8951556Srgrimes} 8961556Srgrimes 8971556Srgrimesstatic void 8981556Srgrimesinit_list(struct listinfo *inf, addelem_rtn artn, int elemsize, 8991556Srgrimes const char *lname) 9001556Srgrimes{ 90154679Scracauer 90217987Speter inf->count = inf->maxcount = 0; 90317987Speter inf->elemsize = elemsize; 90417987Speter inf->addelem = artn; 90517987Speter inf->lname = lname; 90617987Speter inf->ptr = NULL; 90717987Speter} 90817987Speter 90917987SpeterVARENT * 91017987Speterfind_varentry(VAR *v) 91117987Speter{ 91217987Speter struct varent *vent; 91354679Scracauer 91417987Speter for (vent = vhead; vent; vent = vent->next) { 9151556Srgrimes if (strcmp(vent->var->name, v->name) == 0) 9161556Srgrimes return vent; 9171556Srgrimes } 9181556Srgrimes return NULL; 9191556Srgrimes} 9201556Srgrimes 9211556Srgrimesstatic void 9221556Srgrimesscanvars(void) 9231556Srgrimes{ 9241556Srgrimes struct varent *vent; 9251556Srgrimes VAR *v; 9261556Srgrimes 9271556Srgrimes for (vent = vhead; vent; vent = vent->next) { 9281556Srgrimes v = vent->var; 9291556Srgrimes if (v->flag & DSIZ) { 9301556Srgrimes v->dwidth = v->width; 9311556Srgrimes v->width = 0; 9321556Srgrimes } 9331556Srgrimes if (v->flag & USER) 9341556Srgrimes needuser = 1; 9351556Srgrimes if (v->flag & COMM) 9361556Srgrimes needcomm = 1; 9371556Srgrimes } 9381556Srgrimes} 9391556Srgrimes 9401556Srgrimesstatic void 94154679Scracauerdynsizevars(KINFO *ki) 94264705Scracauer{ 94354679Scracauer struct varent *vent; 94454679Scracauer VAR *v; 9451556Srgrimes int i; 9461556Srgrimes 9471556Srgrimes for (vent = vhead; vent; vent = vent->next) { 9481556Srgrimes v = vent->var; 9491556Srgrimes if (!(v->flag & DSIZ)) 9501556Srgrimes continue; 9511556Srgrimes i = (v->sproc)( ki); 9521556Srgrimes if (v->width < i) 9531556Srgrimes v->width = i; 9541556Srgrimes if (v->width > v->dwidth) 9551556Srgrimes v->width = v->dwidth; 9561556Srgrimes } 9571556Srgrimes} 9581556Srgrimes 9591556Srgrimesstatic void 9601556Srgrimessizevars(void) 9611556Srgrimes{ 9621556Srgrimes struct varent *vent; 9631556Srgrimes VAR *v; 9641556Srgrimes int i; 9651556Srgrimes 9661556Srgrimes for (vent = vhead; vent; vent = vent->next) { 9671556Srgrimes v = vent->var; 9681556Srgrimes i = strlen(vent->header); 9691556Srgrimes if (v->width < i) 9701556Srgrimes v->width = i; 9711556Srgrimes totwidth += v->width + 1; /* +1 for space */ 9721556Srgrimes } 9731556Srgrimes totwidth--; 9741556Srgrimes} 97554631Scracauer 97654631Scracauerstatic const char * 97754631Scracauerfmt(char **(*fn)(kvm_t *, const struct kinfo_proc *, int), KINFO *ki, 9781556Srgrimes char *comm, int maxlen) 97983675Stegge{ 9801556Srgrimes const char *s; 98139137Stegge 98238887Stegge s = fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen); 9831556Srgrimes return (s); 9841556Srgrimes} 9851556Srgrimes 9861556Srgrimes#define UREADOK(ki) (forceuread || (ki->ki_p->ki_sflag & PS_INMEM)) 9871556Srgrimes 98839137Steggestatic void 98939137Steggesaveuser(KINFO *ki) 9901556Srgrimes{ 9911556Srgrimes 9921556Srgrimes if (ki->ki_p->ki_sflag & PS_INMEM) { 99339137Stegge /* 99439137Stegge * The u-area might be swapped out, and we can't get 9951556Srgrimes * at it because we have a crashdump and no swap. 9961556Srgrimes * If it's here fill in these fields, otherwise, just 9971556Srgrimes * leave them 0. 9981556Srgrimes */ 99939137Stegge ki->ki_valid = 1; 100039137Stegge } else 10011556Srgrimes ki->ki_valid = 0; 10021556Srgrimes /* 100339137Stegge * save arguments if needed 10041556Srgrimes */ 100539137Stegge if (needcomm && (UREADOK(ki) || (ki->ki_p->ki_args != NULL))) { 100639137Stegge ki->ki_args = strdup(fmt(kvm_getargv, ki, ki->ki_p->ki_comm, 10071556Srgrimes MAXCOMLEN)); 100839137Stegge } else if (needcomm) { 100939137Stegge asprintf(&ki->ki_args, "(%s)", ki->ki_p->ki_comm); 10101556Srgrimes } else { 10111556Srgrimes ki->ki_args = NULL; 10121556Srgrimes } 10131556Srgrimes if (needenv && UREADOK(ki)) { 10141556Srgrimes ki->ki_env = strdup(fmt(kvm_getenvv, ki, (char *)NULL, 0)); 10151556Srgrimes } else if (needenv) { 10161556Srgrimes ki->ki_env = malloc(3); 10171556Srgrimes strcpy(ki->ki_env, "()"); 10181556Srgrimes } else { 10191556Srgrimes ki->ki_env = NULL; 10201556Srgrimes } 10211556Srgrimes} 10221556Srgrimes 10231556Srgrimesstatic int 10241556Srgrimespscomp(const void *a, const void *b) 10251556Srgrimes{ 10261556Srgrimes int i; 10271556Srgrimes#define VSIZE(k) ((k)->ki_p->ki_dsize + (k)->ki_p->ki_ssize + \ 10281556Srgrimes (k)->ki_p->ki_tsize) 10291556Srgrimes 10301556Srgrimes if (sortby == SORTCPU) 10311556Srgrimes return (getpcpu((const KINFO *)b) - getpcpu((const KINFO *)a)); 10321556Srgrimes if (sortby == SORTMEM) 10331556Srgrimes return (VSIZE((const KINFO *)b) - VSIZE((const KINFO *)a)); 10341556Srgrimes i = (int)((const KINFO *)a)->ki_p->ki_tdev - 10351556Srgrimes (int)((const KINFO *)b)->ki_p->ki_tdev; 10361556Srgrimes if (i == 0) 103739137Stegge i = ((const KINFO *)a)->ki_p->ki_pid - 103839137Stegge ((const KINFO *)b)->ki_p->ki_pid; 103939137Stegge return (i); 104039137Stegge} 10411556Srgrimes 10421556Srgrimes/* 10431556Srgrimes * ICK (all for getopt), would rather hide the ugliness 10448855Srgrimes * here than taint the main code. 10451556Srgrimes * 10461556Srgrimes * ps foo -> ps -foo 10471556Srgrimes * ps 34 -> ps -p34 10481556Srgrimes * 10491556Srgrimes * The old convention that 't' with no trailing tty arg means the users 10501556Srgrimes * tty, is only supported if argv[1] doesn't begin with a '-'. This same 10511556Srgrimes * feature is available with the option 'T', which takes no argument. 10521556Srgrimes */ 10531556Srgrimesstatic char * 10541556Srgrimeskludge_oldps_options(char *s) 10551556Srgrimes{ 10561556Srgrimes int have_fmt; 10571556Srgrimes size_t len; 10581556Srgrimes char *newopts, *ns, *cp; 10591556Srgrimes 10601556Srgrimes /* 10611556Srgrimes * If we have an 'o' option, then note it, since we don't want to do 10621556Srgrimes * some types of munging. 10631556Srgrimes */ 10641556Srgrimes have_fmt = index(s, 'o') != NULL; 10651556Srgrimes 10661556Srgrimes len = strlen(s); 10671556Srgrimes if ((newopts = ns = malloc(len + 2)) == NULL) 10681556Srgrimes errx(1, "malloc failed"); 10691556Srgrimes /* 10701556Srgrimes * options begin with '-' 10711556Srgrimes */ 10721556Srgrimes if (*s != '-') 10731556Srgrimes *ns++ = '-'; /* add option flag */ 10741556Srgrimes /* 10751556Srgrimes * gaze to end of argv[1] 10761556Srgrimes */ 10771556Srgrimes cp = s + len - 1; 10781556Srgrimes /* 10791556Srgrimes * if last letter is a 't' flag with no argument (in the context 10801556Srgrimes * of the oldps options -- option string NOT starting with a '-' -- 10811556Srgrimes * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). 10821556Srgrimes * 10831556Srgrimes * However, if a flag accepting a string argument is found in the 10841556Srgrimes * option string, the remainder of the string is the argument to 10851556Srgrimes * that flag; do not modify that argument. 10861556Srgrimes */ 10871556Srgrimes if (strcspn(s, "MNOoU") == len && *cp == 't' && *s != '-') 10881556Srgrimes *cp = 'T'; 10891556Srgrimes else { 10901556Srgrimes /* 10911556Srgrimes * otherwise check for trailing number, which *may* be a 10921556Srgrimes * pid. 10931556Srgrimes */ 10941556Srgrimes while (cp >= s && isdigit(*cp)) 10951556Srgrimes --cp; 10961556Srgrimes } 10971556Srgrimes cp++; 10981556Srgrimes memmove(ns, s, (size_t)(cp - s)); /* copy up to trailing number */ 10991556Srgrimes ns += cp - s; 11001556Srgrimes /* 11011556Srgrimes * if there's a trailing number, and not a preceding 'p' (pid) or 11021556Srgrimes * 't' (tty) flag, then assume it's a pid and insert a 'p' flag. 11031556Srgrimes */ 11041556Srgrimes if (isdigit(*cp) && 11051556Srgrimes (cp == s || (cp[-1] != 't' && cp[-1] != 'p')) && 11061556Srgrimes (cp - 1 == s || cp[-2] != 't') && !have_fmt) 11071556Srgrimes *ns++ = 'p'; 11081556Srgrimes (void)strcpy(ns, cp); /* and append the number */ 11091556Srgrimes 11101556Srgrimes return (newopts); 11111556Srgrimes} 111225230Ssteve 11131556Srgrimesstatic void 11141556Srgrimesusage(void) 11151556Srgrimes{ 11161556Srgrimes#define SINGLE_OPTS "[-aC" OPT_LAZY_f "HhjlmrSTuvwXxZ]" 11171556Srgrimes 11181556Srgrimes (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", 11191556Srgrimes "usage: ps " SINGLE_OPTS " [-G gid[,gid]] [-O|o fmt]", 11201556Srgrimes " [-p pid[,pid]] [-t tty[,tty]] [-U user[,user]]", 11211556Srgrimes " [-M core] [-N system]", 11221556Srgrimes " ps [-L]"); 11231556Srgrimes exit(1); 11241556Srgrimes} 11251556Srgrimes