14b88c807SRodney W. Grimes /*- 24b88c807SRodney W. Grimes * Copyright (c) 1990, 1993, 1994 34b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 44b88c807SRodney W. Grimes * 54b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 64b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 74b88c807SRodney W. Grimes * are met: 84b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 94b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 104b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 114b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 124b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 134b88c807SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 144b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 154b88c807SRodney W. Grimes * without specific prior written permission. 164b88c807SRodney W. Grimes * 174b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 184b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 194b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 204b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 214b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 224b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 234b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 244b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 254b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 264b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 274b88c807SRodney W. Grimes * SUCH DAMAGE. 28a4c8a745SGarance A Drosehn * ------+---------+---------+-------- + --------+---------+---------+---------* 29a4c8a745SGarance A Drosehn * Copyright (c) 2004 - Garance Alistair Drosehn <gad@FreeBSD.org>. 30a4c8a745SGarance A Drosehn * All rights reserved. 31a4c8a745SGarance A Drosehn * 32a4c8a745SGarance A Drosehn * Significant modifications made to bring `ps' options somewhat closer 33a4c8a745SGarance A Drosehn * to the standard for `ps' as described in SingleUnixSpec-v3. 34a4c8a745SGarance A Drosehn * ------+---------+---------+-------- + --------+---------+---------+---------* 354b88c807SRodney W. Grimes */ 364b88c807SRodney W. Grimes 374b88c807SRodney W. Grimes #ifndef lint 38871e8d8cSMark Murray static const char copyright[] = 394b88c807SRodney W. Grimes "@(#) Copyright (c) 1990, 1993, 1994\n\ 404b88c807SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 414b88c807SRodney W. Grimes #endif /* not lint */ 424b88c807SRodney W. Grimes 43c9a8d1f4SPhilippe Charnier #if 0 44871e8d8cSMark Murray #ifndef lint 45c9a8d1f4SPhilippe Charnier static char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94"; 464b88c807SRodney W. Grimes #endif /* not lint */ 47871e8d8cSMark Murray #endif 48eaed5652SPhilippe Charnier 492749b141SDavid E. O'Brien #include <sys/cdefs.h> 502749b141SDavid E. O'Brien __FBSDID("$FreeBSD$"); 514b88c807SRodney W. Grimes 524b88c807SRodney W. Grimes #include <sys/param.h> 53c7910c3aSGarance A Drosehn #include <sys/proc.h> 548b6f5f5fSDavid Greenman #include <sys/user.h> 554b88c807SRodney W. Grimes #include <sys/stat.h> 564b88c807SRodney W. Grimes #include <sys/ioctl.h> 574b88c807SRodney W. Grimes #include <sys/sysctl.h> 58a951d1f8SChristian S.J. Peron #include <sys/mount.h> 594b88c807SRodney W. Grimes 604b88c807SRodney W. Grimes #include <ctype.h> 614b88c807SRodney W. Grimes #include <err.h> 624e8b6a6fSGarance A Drosehn #include <errno.h> 634b88c807SRodney W. Grimes #include <fcntl.h> 64a4c8a745SGarance A Drosehn #include <grp.h> 654b88c807SRodney W. Grimes #include <kvm.h> 66b2496d93SMike Pritchard #include <limits.h> 6708017519SAndrey A. Chernov #include <locale.h> 684b88c807SRodney W. Grimes #include <paths.h> 69871e8d8cSMark Murray #include <pwd.h> 704b88c807SRodney W. Grimes #include <stdio.h> 714b88c807SRodney W. Grimes #include <stdlib.h> 724b88c807SRodney W. Grimes #include <string.h> 734b88c807SRodney W. Grimes #include <unistd.h> 744b88c807SRodney W. Grimes 754b88c807SRodney W. Grimes #include "ps.h" 764b88c807SRodney W. Grimes 778a529f59SJohn Baldwin #define _PATH_PTS "/dev/pts/" 788a529f59SJohn Baldwin 79a4c8a745SGarance A Drosehn #define W_SEP " \t" /* "Whitespace" list separators */ 80a4c8a745SGarance A Drosehn #define T_SEP "," /* "Terminate-element" list separators */ 81cf22dcfcSBrian Somers 82de800cd4SGarance A Drosehn #ifdef LAZY_PS 83c46bb4b3SGarance A Drosehn #define DEF_UREAD 0 84de800cd4SGarance A Drosehn #define OPT_LAZY_f "f" 85de800cd4SGarance A Drosehn #else 86c46bb4b3SGarance A Drosehn #define DEF_UREAD 1 /* Always do the more-expensive read. */ 87de800cd4SGarance A Drosehn #define OPT_LAZY_f /* I.e., the `-f' option is not added. */ 88de800cd4SGarance A Drosehn #endif 894b88c807SRodney W. Grimes 90c675340aSGarance A Drosehn /* 91ecbb06f8SGarance A Drosehn * isdigit takes an `int', but expects values in the range of unsigned char. 92ecbb06f8SGarance A Drosehn * This wrapper ensures that values from a 'char' end up in the correct range. 93c675340aSGarance A Drosehn */ 94ecbb06f8SGarance A Drosehn #define isdigitch(Anychar) isdigit((u_char)(Anychar)) 95c675340aSGarance A Drosehn 96db91faacSPeter Wemm int cflag; /* -c */ 97de800cd4SGarance A Drosehn int eval; /* Exit value */ 98de800cd4SGarance A Drosehn time_t now; /* Current time(3) value */ 994b88c807SRodney W. Grimes int rawcpu; /* -C */ 1004b88c807SRodney W. Grimes int sumrusage; /* -S */ 101de800cd4SGarance A Drosehn int termwidth; /* Width of the screen (0 == infinity). */ 1027ab24ea3SJulian Elischer int showthreads; /* will threads be shown? */ 1034b88c807SRodney W. Grimes 104bdf8ab46SGarance A Drosehn struct velisthead varlist = STAILQ_HEAD_INITIALIZER(varlist); 105de800cd4SGarance A Drosehn 106de800cd4SGarance A Drosehn static int forceuread = DEF_UREAD; /* Do extra work to get u-area. */ 107de800cd4SGarance A Drosehn static kvm_t *kd; 108de800cd4SGarance A Drosehn static int needcomm; /* -o "command" */ 109de800cd4SGarance A Drosehn static int needenv; /* -e */ 110de800cd4SGarance A Drosehn static int needuser; /* -o "user" */ 111de800cd4SGarance A Drosehn static int optfatal; /* Fatal error parsing some list-option. */ 112de800cd4SGarance A Drosehn 113de800cd4SGarance A Drosehn static enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; 114ba2cd770SJuli Mallett 115a4c8a745SGarance A Drosehn struct listinfo; 116de800cd4SGarance A Drosehn typedef int addelem_rtn(struct listinfo *_inf, const char *_elem); 117a4c8a745SGarance A Drosehn 118a4c8a745SGarance A Drosehn struct listinfo { 119a4c8a745SGarance A Drosehn int count; 120a4c8a745SGarance A Drosehn int maxcount; 121a4c8a745SGarance A Drosehn int elemsize; 122a4c8a745SGarance A Drosehn addelem_rtn *addelem; 123a4c8a745SGarance A Drosehn const char *lname; 124a4c8a745SGarance A Drosehn union { 125a4c8a745SGarance A Drosehn gid_t *gids; 126a4c8a745SGarance A Drosehn pid_t *pids; 127a4c8a745SGarance A Drosehn dev_t *ttys; 128a4c8a745SGarance A Drosehn uid_t *uids; 129a4c8a745SGarance A Drosehn void *ptr; 130d822163fSGarance A Drosehn } l; 131a4c8a745SGarance A Drosehn }; 132a4c8a745SGarance A Drosehn 133a4c8a745SGarance A Drosehn static int addelem_gid(struct listinfo *, const char *); 134a4c8a745SGarance A Drosehn static int addelem_pid(struct listinfo *, const char *); 135a4c8a745SGarance A Drosehn static int addelem_tty(struct listinfo *, const char *); 136a4c8a745SGarance A Drosehn static int addelem_uid(struct listinfo *, const char *); 137a4c8a745SGarance A Drosehn static void add_list(struct listinfo *, const char *); 138044fce53SBrian Somers static void descendant_sort(KINFO *, int); 1391d1143ecSEdward Tomasz Napierala static void format_output(KINFO *); 140a4c8a745SGarance A Drosehn static void *expand_list(struct listinfo *); 141f35e0715SGarance A Drosehn static const char * 142f35e0715SGarance A Drosehn fmt(char **(*)(kvm_t *, const struct kinfo_proc *, int), 1434857f240SGarance A Drosehn KINFO *, char *, int); 144a4c8a745SGarance A Drosehn static void free_list(struct listinfo *); 145a4c8a745SGarance A Drosehn static void init_list(struct listinfo *, addelem_rtn, int, const char *); 14625113083SGarance A Drosehn static char *kludge_oldps_options(const char *, char *, const char *); 1474857f240SGarance A Drosehn static int pscomp(const void *, const void *); 1484857f240SGarance A Drosehn static void saveuser(KINFO *); 1494857f240SGarance A Drosehn static void scanvars(void); 1504857f240SGarance A Drosehn static void sizevars(void); 1514857f240SGarance A Drosehn static void usage(void); 1524b88c807SRodney W. Grimes 153c0716492SJuli Mallett static char dfmt[] = "pid,tt,state,time,command"; 154259fcfacSGarance A Drosehn static char jfmt[] = "user,pid,ppid,pgid,sid,jobc,state,tt,time,command"; 1551d2324f4SGarance A Drosehn static char lfmt[] = "uid,pid,ppid,cpu,pri,nice,vsz,rss,mwchan,state," 1561d2324f4SGarance A Drosehn "tt,time,command"; 157871e8d8cSMark Murray static char o1[] = "pid"; 158c0716492SJuli Mallett static char o2[] = "tt,state,time,command"; 159c0716492SJuli Mallett static char ufmt[] = "user,pid,%cpu,%mem,vsz,rss,tt,state,start,time,command"; 1601d2324f4SGarance A Drosehn static char vfmt[] = "pid,state,time,sl,re,pagein,vsz,rss,lim,tsiz," 1611d2324f4SGarance A Drosehn "%cpu,%mem,command"; 1622af538ebSRobert Watson static char Zfmt[] = "label"; 1634b88c807SRodney W. Grimes 164044fce53SBrian Somers #define PS_ARGS "AaCcde" OPT_LAZY_f "G:gHhjLlM:mN:O:o:p:rSTt:U:uvwXxZ" 16541623b2dSMaxim Sobolev 1664b88c807SRodney W. Grimes int 16746251ddeSWarner Losh main(int argc, char *argv[]) 1684b88c807SRodney W. Grimes { 169a4c8a745SGarance A Drosehn struct listinfo gidlist, pgrplist, pidlist; 170a4c8a745SGarance A Drosehn struct listinfo ruidlist, sesslist, ttylist, uidlist; 1714b88c807SRodney W. Grimes struct kinfo_proc *kp; 1721d1143ecSEdward Tomasz Napierala KINFO *kinfo = NULL, *next_KINFO; 1731d1143ecSEdward Tomasz Napierala KINFO_STR *ks; 1744b88c807SRodney W. Grimes struct varent *vent; 1754b88c807SRodney W. Grimes struct winsize ws; 1761d1143ecSEdward Tomasz Napierala const char *nlistf, *memf, *fmtstr, *str; 177ca62e195SGarance A Drosehn char *cols; 1781d1143ecSEdward Tomasz Napierala int all, ch, elem, flag, _fmt, i, lineno, linelen, left; 179044fce53SBrian Somers int descendancy, nentries, nkept, nselectors; 1807ab24ea3SJulian Elischer int prtheader, wflag, what, xkeep, xkeep_implied; 181871e8d8cSMark Murray char errbuf[_POSIX2_LINE_MAX]; 1824b88c807SRodney W. Grimes 1832bf4b9cfSAndrey A. Chernov (void) setlocale(LC_ALL, ""); 184352b6523SGarance A Drosehn time(&now); /* Used by routines in print.c. */ 1852bf4b9cfSAndrey A. Chernov 1864f18100dSTim J. Robbins if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0') 1874f18100dSTim J. Robbins termwidth = atoi(cols); 1884f18100dSTim J. Robbins else if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && 1894b88c807SRodney W. Grimes ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && 1904b88c807SRodney W. Grimes ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) || 1914b88c807SRodney W. Grimes ws.ws_col == 0) 1924b88c807SRodney W. Grimes termwidth = 79; 1934b88c807SRodney W. Grimes else 1944b88c807SRodney W. Grimes termwidth = ws.ws_col - 1; 1954b88c807SRodney W. Grimes 19641623b2dSMaxim Sobolev /* 197c675340aSGarance A Drosehn * Hide a number of option-processing kludges in a separate routine, 198c675340aSGarance A Drosehn * to support some historical BSD behaviors, such as `ps axu'. 19941623b2dSMaxim Sobolev */ 200c675340aSGarance A Drosehn if (argc > 1) 201bf46a3bfSGarance A Drosehn argv[1] = kludge_oldps_options(PS_ARGS, argv[1], argv[2]); 2024b88c807SRodney W. Grimes 203044fce53SBrian Somers all = descendancy = _fmt = nselectors = optfatal = 0; 204352b6523SGarance A Drosehn prtheader = showthreads = wflag = xkeep_implied = 0; 205352b6523SGarance A Drosehn xkeep = -1; /* Neither -x nor -X. */ 206a4c8a745SGarance A Drosehn init_list(&gidlist, addelem_gid, sizeof(gid_t), "group"); 207a4c8a745SGarance A Drosehn init_list(&pgrplist, addelem_pid, sizeof(pid_t), "process group"); 208a4c8a745SGarance A Drosehn init_list(&pidlist, addelem_pid, sizeof(pid_t), "process id"); 209a4c8a745SGarance A Drosehn init_list(&ruidlist, addelem_uid, sizeof(uid_t), "ruser"); 210a4c8a745SGarance A Drosehn init_list(&sesslist, addelem_pid, sizeof(pid_t), "session id"); 211a4c8a745SGarance A Drosehn init_list(&ttylist, addelem_tty, sizeof(dev_t), "tty"); 212a4c8a745SGarance A Drosehn init_list(&uidlist, addelem_uid, sizeof(uid_t), "user"); 213c08dcaf1SRebecca Cran memf = _PATH_DEVNULL; 214c08dcaf1SRebecca Cran nlistf = NULL; 21541623b2dSMaxim Sobolev while ((ch = getopt(argc, argv, PS_ARGS)) != -1) 2160c025af9SKevin Lo switch (ch) { 217a4c8a745SGarance A Drosehn case 'A': 218a4c8a745SGarance A Drosehn /* 219a4c8a745SGarance A Drosehn * Exactly the same as `-ax'. This has been 220bf2fe08eSUlrich Spörlein * added for compatibility with SUSv3, but for 221a4c8a745SGarance A Drosehn * now it will not be described in the man page. 222a4c8a745SGarance A Drosehn */ 223a4c8a745SGarance A Drosehn nselectors++; 224a4c8a745SGarance A Drosehn all = xkeep = 1; 225a4c8a745SGarance A Drosehn break; 2264b88c807SRodney W. Grimes case 'a': 227a4c8a745SGarance A Drosehn nselectors++; 2284b88c807SRodney W. Grimes all = 1; 2294b88c807SRodney W. Grimes break; 2304b88c807SRodney W. Grimes case 'C': 2314b88c807SRodney W. Grimes rawcpu = 1; 2324b88c807SRodney W. Grimes break; 233db91faacSPeter Wemm case 'c': 234db91faacSPeter Wemm cflag = 1; 235db91faacSPeter Wemm break; 236044fce53SBrian Somers case 'd': 237044fce53SBrian Somers descendancy = 1; 238044fce53SBrian Somers break; 239db91faacSPeter Wemm case 'e': /* XXX set ufmt */ 240db91faacSPeter Wemm needenv = 1; 241db91faacSPeter Wemm break; 2424a355d17SGarance A Drosehn #ifdef LAZY_PS 2434a355d17SGarance A Drosehn case 'f': 2444a355d17SGarance A Drosehn if (getuid() == 0 || getgid() == 0) 2454a355d17SGarance A Drosehn forceuread = 1; 2464a355d17SGarance A Drosehn break; 2474a355d17SGarance A Drosehn #endif 248a4c8a745SGarance A Drosehn case 'G': 249a4c8a745SGarance A Drosehn add_list(&gidlist, optarg); 250a4c8a745SGarance A Drosehn xkeep_implied = 1; 251a4c8a745SGarance A Drosehn nselectors++; 252a4c8a745SGarance A Drosehn break; 2534b88c807SRodney W. Grimes case 'g': 254352b6523SGarance A Drosehn #if 0 255ba50b0e0SGarance A Drosehn /*- 256352b6523SGarance A Drosehn * XXX - This SUSv3 behavior is still under debate 257352b6523SGarance A Drosehn * since it conflicts with the (undocumented) 258352b6523SGarance A Drosehn * `-g' option. So we skip it for now. 259352b6523SGarance A Drosehn */ 260a4c8a745SGarance A Drosehn add_list(&pgrplist, optarg); 261a4c8a745SGarance A Drosehn xkeep_implied = 1; 262a4c8a745SGarance A Drosehn nselectors++; 263a4c8a745SGarance A Drosehn break; 264a4c8a745SGarance A Drosehn #else 265352b6523SGarance A Drosehn /* The historical BSD-ish (from SunOS) behavior. */ 2664b88c807SRodney W. Grimes break; /* no-op */ 267a4c8a745SGarance A Drosehn #endif 26848b8c0deSScott Long case 'H': 269d75c1d83SDaniel Eischen showthreads = KERN_PROC_INC_THREAD; 27048b8c0deSScott Long break; 2714b88c807SRodney W. Grimes case 'h': 2724b88c807SRodney W. Grimes prtheader = ws.ws_row > 5 ? ws.ws_row : 22; 2734b88c807SRodney W. Grimes break; 2744b88c807SRodney W. Grimes case 'j': 275fde411d5SJuli Mallett parsefmt(jfmt, 0); 276871e8d8cSMark Murray _fmt = 1; 2774b88c807SRodney W. Grimes jfmt[0] = '\0'; 2784b88c807SRodney W. Grimes break; 2794b88c807SRodney W. Grimes case 'L': 2804b88c807SRodney W. Grimes showkey(); 2814b88c807SRodney W. Grimes exit(0); 2824b88c807SRodney W. Grimes case 'l': 283fde411d5SJuli Mallett parsefmt(lfmt, 0); 284871e8d8cSMark Murray _fmt = 1; 2854b88c807SRodney W. Grimes lfmt[0] = '\0'; 2864b88c807SRodney W. Grimes break; 2874b88c807SRodney W. Grimes case 'M': 2884b88c807SRodney W. Grimes memf = optarg; 2894b88c807SRodney W. Grimes break; 2904b88c807SRodney W. Grimes case 'm': 2914b88c807SRodney W. Grimes sortby = SORTMEM; 2924b88c807SRodney W. Grimes break; 2934b88c807SRodney W. Grimes case 'N': 2944b88c807SRodney W. Grimes nlistf = optarg; 2954b88c807SRodney W. Grimes break; 2964b88c807SRodney W. Grimes case 'O': 297fde411d5SJuli Mallett parsefmt(o1, 1); 298fde411d5SJuli Mallett parsefmt(optarg, 1); 299fde411d5SJuli Mallett parsefmt(o2, 1); 3004b88c807SRodney W. Grimes o1[0] = o2[0] = '\0'; 301871e8d8cSMark Murray _fmt = 1; 3024b88c807SRodney W. Grimes break; 3034b88c807SRodney W. Grimes case 'o': 304fde411d5SJuli Mallett parsefmt(optarg, 1); 305871e8d8cSMark Murray _fmt = 1; 3064b88c807SRodney W. Grimes break; 3074b88c807SRodney W. Grimes case 'p': 308a4c8a745SGarance A Drosehn add_list(&pidlist, optarg); 309a4c8a745SGarance A Drosehn /* 310a4c8a745SGarance A Drosehn * Note: `-p' does not *set* xkeep, but any values 311a4c8a745SGarance A Drosehn * from pidlist are checked before xkeep is. That 312a4c8a745SGarance A Drosehn * way they are always matched, even if the user 313a4c8a745SGarance A Drosehn * specifies `-X'. 314a4c8a745SGarance A Drosehn */ 315a4c8a745SGarance A Drosehn nselectors++; 3164b88c807SRodney W. Grimes break; 317a4c8a745SGarance A Drosehn #if 0 318a4c8a745SGarance A Drosehn case 'R': 319ba50b0e0SGarance A Drosehn /*- 320352b6523SGarance A Drosehn * XXX - This un-standard option is still under 321352b6523SGarance A Drosehn * debate. This is what SUSv3 defines as 322352b6523SGarance A Drosehn * the `-U' option, and while it would be 323352b6523SGarance A Drosehn * nice to have, it could cause even more 324352b6523SGarance A Drosehn * confusion to implement it as `-R'. 325352b6523SGarance A Drosehn */ 326a4c8a745SGarance A Drosehn add_list(&ruidlist, optarg); 327a4c8a745SGarance A Drosehn xkeep_implied = 1; 328a4c8a745SGarance A Drosehn nselectors++; 329a4c8a745SGarance A Drosehn break; 330a4c8a745SGarance A Drosehn #endif 3314b88c807SRodney W. Grimes case 'r': 3324b88c807SRodney W. Grimes sortby = SORTCPU; 3334b88c807SRodney W. Grimes break; 3344b88c807SRodney W. Grimes case 'S': 3354b88c807SRodney W. Grimes sumrusage = 1; 3364b88c807SRodney W. Grimes break; 337a4c8a745SGarance A Drosehn #if 0 338a4c8a745SGarance A Drosehn case 's': 339ba50b0e0SGarance A Drosehn /*- 340352b6523SGarance A Drosehn * XXX - This non-standard option is still under 341352b6523SGarance A Drosehn * debate. This *is* supported on Solaris, 342352b6523SGarance A Drosehn * Linux, and IRIX, but conflicts with `-s' 343352b6523SGarance A Drosehn * on NetBSD and maybe some older BSD's. 344352b6523SGarance A Drosehn */ 345a4c8a745SGarance A Drosehn add_list(&sesslist, optarg); 346a4c8a745SGarance A Drosehn xkeep_implied = 1; 347a4c8a745SGarance A Drosehn nselectors++; 348a4c8a745SGarance A Drosehn break; 349a4c8a745SGarance A Drosehn #endif 3504b88c807SRodney W. Grimes case 'T': 3514b88c807SRodney W. Grimes if ((optarg = ttyname(STDIN_FILENO)) == NULL) 3524b88c807SRodney W. Grimes errx(1, "stdin: not a terminal"); 3534b88c807SRodney W. Grimes /* FALLTHROUGH */ 354a4c8a745SGarance A Drosehn case 't': 355a4c8a745SGarance A Drosehn add_list(&ttylist, optarg); 356a4c8a745SGarance A Drosehn xkeep_implied = 1; 357a4c8a745SGarance A Drosehn nselectors++; 3584b88c807SRodney W. Grimes break; 35973eb8310SPeter Wemm case 'U': 360a4c8a745SGarance A Drosehn /* This is what SUSv3 defines as the `-u' option. */ 361a4c8a745SGarance A Drosehn add_list(&uidlist, optarg); 362a4c8a745SGarance A Drosehn xkeep_implied = 1; 363a4c8a745SGarance A Drosehn nselectors++; 36473eb8310SPeter Wemm break; 3654b88c807SRodney W. Grimes case 'u': 366fde411d5SJuli Mallett parsefmt(ufmt, 0); 3674b88c807SRodney W. Grimes sortby = SORTCPU; 368871e8d8cSMark Murray _fmt = 1; 3694b88c807SRodney W. Grimes ufmt[0] = '\0'; 3704b88c807SRodney W. Grimes break; 3714b88c807SRodney W. Grimes case 'v': 372fde411d5SJuli Mallett parsefmt(vfmt, 0); 3734b88c807SRodney W. Grimes sortby = SORTMEM; 374871e8d8cSMark Murray _fmt = 1; 3754b88c807SRodney W. Grimes vfmt[0] = '\0'; 3764b88c807SRodney W. Grimes break; 3774b88c807SRodney W. Grimes case 'w': 3784b88c807SRodney W. Grimes if (wflag) 3794b88c807SRodney W. Grimes termwidth = UNLIMITED; 3804b88c807SRodney W. Grimes else if (termwidth < 131) 3814b88c807SRodney W. Grimes termwidth = 131; 3824b88c807SRodney W. Grimes wflag++; 3834b88c807SRodney W. Grimes break; 384a4c8a745SGarance A Drosehn case 'X': 385a4c8a745SGarance A Drosehn /* 386a4c8a745SGarance A Drosehn * Note that `-X' and `-x' are not standard "selector" 387a4c8a745SGarance A Drosehn * options. For most selector-options, we check *all* 388a4c8a745SGarance A Drosehn * processes to see if any are matched by the given 389a4c8a745SGarance A Drosehn * value(s). After we have a set of all the matched 390a4c8a745SGarance A Drosehn * processes, then `-X' and `-x' govern whether we 391a4c8a745SGarance A Drosehn * modify that *matched* set for processes which do 392a4c8a745SGarance A Drosehn * not have a controlling terminal. `-X' causes 393a4c8a745SGarance A Drosehn * those processes to be deleted from the matched 394a4c8a745SGarance A Drosehn * set, while `-x' causes them to be kept. 395a4c8a745SGarance A Drosehn */ 396a4c8a745SGarance A Drosehn xkeep = 0; 397a4c8a745SGarance A Drosehn break; 3984b88c807SRodney W. Grimes case 'x': 399a4c8a745SGarance A Drosehn xkeep = 1; 4004b88c807SRodney W. Grimes break; 4017304f61fSBrian Feldman case 'Z': 402fde411d5SJuli Mallett parsefmt(Zfmt, 0); 4037304f61fSBrian Feldman Zfmt[0] = '\0'; 4047304f61fSBrian Feldman break; 4054b88c807SRodney W. Grimes case '?': 4064b88c807SRodney W. Grimes default: 4074b88c807SRodney W. Grimes usage(); 4084b88c807SRodney W. Grimes } 4094b88c807SRodney W. Grimes argc -= optind; 4104b88c807SRodney W. Grimes argv += optind; 411c675340aSGarance A Drosehn 412c675340aSGarance A Drosehn /* 413c675340aSGarance A Drosehn * If there arguments after processing all the options, attempt 414c675340aSGarance A Drosehn * to treat them as a list of process ids. 415c675340aSGarance A Drosehn */ 416c675340aSGarance A Drosehn while (*argv) { 417c675340aSGarance A Drosehn if (!isdigitch(**argv)) 418c675340aSGarance A Drosehn break; 419c675340aSGarance A Drosehn add_list(&pidlist, *argv); 420c675340aSGarance A Drosehn argv++; 421c675340aSGarance A Drosehn } 422c675340aSGarance A Drosehn if (*argv) { 423c675340aSGarance A Drosehn fprintf(stderr, "%s: illegal argument: %s\n", 424c675340aSGarance A Drosehn getprogname(), *argv); 425c675340aSGarance A Drosehn usage(); 426c675340aSGarance A Drosehn } 427a4c8a745SGarance A Drosehn if (optfatal) 428352b6523SGarance A Drosehn exit(1); /* Error messages already printed. */ 429352b6523SGarance A Drosehn if (xkeep < 0) /* Neither -X nor -x was specified. */ 430a4c8a745SGarance A Drosehn xkeep = xkeep_implied; 431a4c8a745SGarance A Drosehn 432831c910aSRuslan Ermilov kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 4334b88c807SRodney W. Grimes if (kd == 0) 4344b88c807SRodney W. Grimes errx(1, "%s", errbuf); 4354b88c807SRodney W. Grimes 436871e8d8cSMark Murray if (!_fmt) 437fde411d5SJuli Mallett parsefmt(dfmt, 0); 4384b88c807SRodney W. Grimes 439a4c8a745SGarance A Drosehn if (nselectors == 0) { 440d822163fSGarance A Drosehn uidlist.l.ptr = malloc(sizeof(uid_t)); 441d822163fSGarance A Drosehn if (uidlist.l.ptr == NULL) 4424fa7d788SJuli Mallett errx(1, "malloc failed"); 443a4c8a745SGarance A Drosehn nselectors = 1; 444a4c8a745SGarance A Drosehn uidlist.count = uidlist.maxcount = 1; 445d822163fSGarance A Drosehn *uidlist.l.uids = getuid(); 446cf22dcfcSBrian Somers } 4474b88c807SRodney W. Grimes 4484b88c807SRodney W. Grimes /* 4494b88c807SRodney W. Grimes * scan requested variables, noting what structures are needed, 450bdfebd84SKris Kennaway * and adjusting header widths as appropriate. 4514b88c807SRodney W. Grimes */ 4524b88c807SRodney W. Grimes scanvars(); 453a4c8a745SGarance A Drosehn 4544b88c807SRodney W. Grimes /* 455a4c8a745SGarance A Drosehn * Get process list. If the user requested just one selector- 456a4c8a745SGarance A Drosehn * option, then kvm_getprocs can be asked to return just those 457a4c8a745SGarance A Drosehn * processes. Otherwise, have it return all processes, and 458a4c8a745SGarance A Drosehn * then this routine will search that full list and select the 459a4c8a745SGarance A Drosehn * processes which match any of the user's selector-options. 4604b88c807SRodney W. Grimes */ 461d75c1d83SDaniel Eischen what = showthreads != 0 ? KERN_PROC_ALL : KERN_PROC_PROC; 46248b8c0deSScott Long flag = 0; 463a4c8a745SGarance A Drosehn if (nselectors == 1) { 4647bd42165SGarance A Drosehn if (gidlist.count == 1) { 4657bd42165SGarance A Drosehn what = KERN_PROC_RGID | showthreads; 4667bd42165SGarance A Drosehn flag = *gidlist.l.gids; 4677bd42165SGarance A Drosehn nselectors = 0; 4687bd42165SGarance A Drosehn } else if (pgrplist.count == 1) { 469a4c8a745SGarance A Drosehn what = KERN_PROC_PGRP | showthreads; 470d822163fSGarance A Drosehn flag = *pgrplist.l.pids; 471a4c8a745SGarance A Drosehn nselectors = 0; 472a4c8a745SGarance A Drosehn } else if (pidlist.count == 1) { 473a4c8a745SGarance A Drosehn what = KERN_PROC_PID | showthreads; 474d822163fSGarance A Drosehn flag = *pidlist.l.pids; 475a4c8a745SGarance A Drosehn nselectors = 0; 476a4c8a745SGarance A Drosehn } else if (ruidlist.count == 1) { 477a4c8a745SGarance A Drosehn what = KERN_PROC_RUID | showthreads; 478d822163fSGarance A Drosehn flag = *ruidlist.l.uids; 479a4c8a745SGarance A Drosehn nselectors = 0; 480a4c8a745SGarance A Drosehn } else if (sesslist.count == 1) { 481a4c8a745SGarance A Drosehn what = KERN_PROC_SESSION | showthreads; 482d822163fSGarance A Drosehn flag = *sesslist.l.pids; 483a4c8a745SGarance A Drosehn nselectors = 0; 484a4c8a745SGarance A Drosehn } else if (ttylist.count == 1) { 485a4c8a745SGarance A Drosehn what = KERN_PROC_TTY | showthreads; 486d822163fSGarance A Drosehn flag = *ttylist.l.ttys; 487a4c8a745SGarance A Drosehn nselectors = 0; 488a4c8a745SGarance A Drosehn } else if (uidlist.count == 1) { 489a4c8a745SGarance A Drosehn what = KERN_PROC_UID | showthreads; 490d822163fSGarance A Drosehn flag = *uidlist.l.uids; 491a4c8a745SGarance A Drosehn nselectors = 0; 492a4c8a745SGarance A Drosehn } else if (all) { 493a4c8a745SGarance A Drosehn /* No need for this routine to select processes. */ 494a4c8a745SGarance A Drosehn nselectors = 0; 495a4c8a745SGarance A Drosehn } 4964b88c807SRodney W. Grimes } 497d75c1d83SDaniel Eischen 4984b88c807SRodney W. Grimes /* 4994b88c807SRodney W. Grimes * select procs 5004b88c807SRodney W. Grimes */ 501a4c8a745SGarance A Drosehn nentries = -1; 5024e8b6a6fSGarance A Drosehn kp = kvm_getprocs(kd, what, flag, &nentries); 50387e47750SGarance A Drosehn if ((kp == NULL && nentries > 0) || (kp != NULL && nentries < 0)) 5044b88c807SRodney W. Grimes errx(1, "%s", kvm_geterr(kd)); 505a4c8a745SGarance A Drosehn nkept = 0; 5064e8b6a6fSGarance A Drosehn if (nentries > 0) { 5074b88c807SRodney W. Grimes if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL) 5084fa7d788SJuli Mallett errx(1, "malloc failed"); 5094b88c807SRodney W. Grimes for (i = nentries; --i >= 0; ++kp) { 510a4c8a745SGarance A Drosehn /* 511a4c8a745SGarance A Drosehn * If the user specified multiple selection-criteria, 512a4c8a745SGarance A Drosehn * then keep any process matched by the inclusive OR 513a4c8a745SGarance A Drosehn * of all the selection-criteria given. 514a4c8a745SGarance A Drosehn */ 515a4c8a745SGarance A Drosehn if (pidlist.count > 0) { 516a4c8a745SGarance A Drosehn for (elem = 0; elem < pidlist.count; elem++) 517d822163fSGarance A Drosehn if (kp->ki_pid == pidlist.l.pids[elem]) 518a4c8a745SGarance A Drosehn goto keepit; 519a4c8a745SGarance A Drosehn } 520a4c8a745SGarance A Drosehn /* 521a4c8a745SGarance A Drosehn * Note that we had to process pidlist before 522a4c8a745SGarance A Drosehn * filtering out processes which do not have 523a4c8a745SGarance A Drosehn * a controlling terminal. 524a4c8a745SGarance A Drosehn */ 525a4c8a745SGarance A Drosehn if (xkeep == 0) { 526a4c8a745SGarance A Drosehn if ((kp->ki_tdev == NODEV || 527a4c8a745SGarance A Drosehn (kp->ki_flag & P_CONTROLT) == 0)) 528a4c8a745SGarance A Drosehn continue; 529a4c8a745SGarance A Drosehn } 530a4c8a745SGarance A Drosehn if (nselectors == 0) 531a4c8a745SGarance A Drosehn goto keepit; 532a4c8a745SGarance A Drosehn if (gidlist.count > 0) { 533a4c8a745SGarance A Drosehn for (elem = 0; elem < gidlist.count; elem++) 534d822163fSGarance A Drosehn if (kp->ki_rgid == gidlist.l.gids[elem]) 535a4c8a745SGarance A Drosehn goto keepit; 536a4c8a745SGarance A Drosehn } 537a4c8a745SGarance A Drosehn if (pgrplist.count > 0) { 538a4c8a745SGarance A Drosehn for (elem = 0; elem < pgrplist.count; elem++) 539d822163fSGarance A Drosehn if (kp->ki_pgid == 540d822163fSGarance A Drosehn pgrplist.l.pids[elem]) 541a4c8a745SGarance A Drosehn goto keepit; 542a4c8a745SGarance A Drosehn } 543a4c8a745SGarance A Drosehn if (ruidlist.count > 0) { 544a4c8a745SGarance A Drosehn for (elem = 0; elem < ruidlist.count; elem++) 545d822163fSGarance A Drosehn if (kp->ki_ruid == 546d822163fSGarance A Drosehn ruidlist.l.uids[elem]) 547a4c8a745SGarance A Drosehn goto keepit; 548a4c8a745SGarance A Drosehn } 549a4c8a745SGarance A Drosehn if (sesslist.count > 0) { 550a4c8a745SGarance A Drosehn for (elem = 0; elem < sesslist.count; elem++) 551d822163fSGarance A Drosehn if (kp->ki_sid == sesslist.l.pids[elem]) 552a4c8a745SGarance A Drosehn goto keepit; 553a4c8a745SGarance A Drosehn } 554a4c8a745SGarance A Drosehn if (ttylist.count > 0) { 555a4c8a745SGarance A Drosehn for (elem = 0; elem < ttylist.count; elem++) 556d822163fSGarance A Drosehn if (kp->ki_tdev == ttylist.l.ttys[elem]) 557a4c8a745SGarance A Drosehn goto keepit; 558a4c8a745SGarance A Drosehn } 559a4c8a745SGarance A Drosehn if (uidlist.count > 0) { 560a4c8a745SGarance A Drosehn for (elem = 0; elem < uidlist.count; elem++) 561d822163fSGarance A Drosehn if (kp->ki_uid == uidlist.l.uids[elem]) 562a4c8a745SGarance A Drosehn goto keepit; 563a4c8a745SGarance A Drosehn } 564a4c8a745SGarance A Drosehn /* 565a4c8a745SGarance A Drosehn * This process did not match any of the user's 566a4c8a745SGarance A Drosehn * selector-options, so skip the process. 567a4c8a745SGarance A Drosehn */ 568a4c8a745SGarance A Drosehn continue; 569a4c8a745SGarance A Drosehn 570a4c8a745SGarance A Drosehn keepit: 5714bac4483SGarance A Drosehn next_KINFO = &kinfo[nkept]; 5724bac4483SGarance A Drosehn next_KINFO->ki_p = kp; 573044fce53SBrian Somers next_KINFO->ki_d.level = 0; 574044fce53SBrian Somers next_KINFO->ki_d.prefix = NULL; 5754bac4483SGarance A Drosehn next_KINFO->ki_pcpu = getpcpu(next_KINFO); 5764bac4483SGarance A Drosehn if (sortby == SORTMEM) 5774bac4483SGarance A Drosehn next_KINFO->ki_memsize = kp->ki_tsize + 5784bac4483SGarance A Drosehn kp->ki_dsize + kp->ki_ssize; 5794b88c807SRodney W. Grimes if (needuser) 5804bac4483SGarance A Drosehn saveuser(next_KINFO); 581a4c8a745SGarance A Drosehn nkept++; 5824b88c807SRodney W. Grimes } 5834e8b6a6fSGarance A Drosehn } 5846a2d726bSJordan K. Hubbard 5856a2d726bSJordan K. Hubbard sizevars(); 5866a2d726bSJordan K. Hubbard 5871d1143ecSEdward Tomasz Napierala if (nkept == 0) { 5884b88c807SRodney W. Grimes printheader(); 589f8c9c11cSWill Andrews exit(1); 5901d1143ecSEdward Tomasz Napierala } 591a4c8a745SGarance A Drosehn 5924b88c807SRodney W. Grimes /* 5934b88c807SRodney W. Grimes * sort proc list 5944b88c807SRodney W. Grimes */ 595a4c8a745SGarance A Drosehn qsort(kinfo, nkept, sizeof(KINFO), pscomp); 596044fce53SBrian Somers 597044fce53SBrian Somers /* 598044fce53SBrian Somers * We want things in descendant order 599044fce53SBrian Somers */ 600044fce53SBrian Somers if (descendancy) 601044fce53SBrian Somers descendant_sort(kinfo, nkept); 602044fce53SBrian Somers 6031d1143ecSEdward Tomasz Napierala 6044b88c807SRodney W. Grimes /* 6051d1143ecSEdward Tomasz Napierala * Prepare formatted output. 6061d1143ecSEdward Tomasz Napierala */ 6071d1143ecSEdward Tomasz Napierala for (i = 0; i < nkept; i++) 6081d1143ecSEdward Tomasz Napierala format_output(&kinfo[i]); 6091d1143ecSEdward Tomasz Napierala 6101d1143ecSEdward Tomasz Napierala /* 6111d1143ecSEdward Tomasz Napierala * Print header. 6121d1143ecSEdward Tomasz Napierala */ 6131d1143ecSEdward Tomasz Napierala printheader(); 6141d1143ecSEdward Tomasz Napierala 6151d1143ecSEdward Tomasz Napierala /* 6161d1143ecSEdward Tomasz Napierala * Output formatted lines. 6174b88c807SRodney W. Grimes */ 618a4c8a745SGarance A Drosehn for (i = lineno = 0; i < nkept; i++) { 6191d1143ecSEdward Tomasz Napierala linelen = 0; 620bdf8ab46SGarance A Drosehn STAILQ_FOREACH(vent, &varlist, next_ve) { 6211d1143ecSEdward Tomasz Napierala if (vent->var->flag & LJUST) 6221d1143ecSEdward Tomasz Napierala fmtstr = "%-*s"; 6231d1143ecSEdward Tomasz Napierala else 6241d1143ecSEdward Tomasz Napierala fmtstr = "%*s"; 6251d1143ecSEdward Tomasz Napierala 6261d1143ecSEdward Tomasz Napierala ks = STAILQ_FIRST(&kinfo[i].ki_ks); 6271d1143ecSEdward Tomasz Napierala STAILQ_REMOVE_HEAD(&kinfo[i].ki_ks, ks_next); 628*38494effSUlrich Spörlein /* Truncate rightmost column if necessary. */ 6291d1143ecSEdward Tomasz Napierala if (STAILQ_NEXT(vent, next_ve) == NULL && 6301d1143ecSEdward Tomasz Napierala termwidth != UNLIMITED && ks->ks_str != NULL) { 6311d1143ecSEdward Tomasz Napierala left = termwidth - linelen; 6321d1143ecSEdward Tomasz Napierala if (left > 0 && left < (int)strlen(ks->ks_str)) 6331d1143ecSEdward Tomasz Napierala ks->ks_str[left] = '\0'; 6341d1143ecSEdward Tomasz Napierala } 6351d1143ecSEdward Tomasz Napierala str = ks->ks_str; 6361d1143ecSEdward Tomasz Napierala if (str == NULL) 6371d1143ecSEdward Tomasz Napierala str = "-"; 6381d1143ecSEdward Tomasz Napierala /* No padding for the last column, if it's LJUST. */ 6391d1143ecSEdward Tomasz Napierala if (STAILQ_NEXT(vent, next_ve) == NULL && 6401d1143ecSEdward Tomasz Napierala vent->var->flag & LJUST) 6411d1143ecSEdward Tomasz Napierala linelen += printf(fmtstr, 0, str); 6421d1143ecSEdward Tomasz Napierala else 6431d1143ecSEdward Tomasz Napierala linelen += printf(fmtstr, vent->var->width, str); 6441d1143ecSEdward Tomasz Napierala 6451d1143ecSEdward Tomasz Napierala if (ks->ks_str != NULL) { 6461d1143ecSEdward Tomasz Napierala free(ks->ks_str); 6471d1143ecSEdward Tomasz Napierala ks->ks_str = NULL; 6481d1143ecSEdward Tomasz Napierala } 6491d1143ecSEdward Tomasz Napierala free(ks); 6501d1143ecSEdward Tomasz Napierala ks = NULL; 6511d1143ecSEdward Tomasz Napierala 6521d1143ecSEdward Tomasz Napierala if (STAILQ_NEXT(vent, next_ve) != NULL) { 6534b88c807SRodney W. Grimes (void)putchar(' '); 6541d1143ecSEdward Tomasz Napierala linelen++; 6551d1143ecSEdward Tomasz Napierala } 6564b88c807SRodney W. Grimes } 6574b88c807SRodney W. Grimes (void)putchar('\n'); 6584b88c807SRodney W. Grimes if (prtheader && lineno++ == prtheader - 4) { 6594b88c807SRodney W. Grimes (void)putchar('\n'); 6604b88c807SRodney W. Grimes printheader(); 6614b88c807SRodney W. Grimes lineno = 0; 6624b88c807SRodney W. Grimes } 6634b88c807SRodney W. Grimes } 664a4c8a745SGarance A Drosehn free_list(&gidlist); 665a4c8a745SGarance A Drosehn free_list(&pidlist); 666a4c8a745SGarance A Drosehn free_list(&pgrplist); 667a4c8a745SGarance A Drosehn free_list(&ruidlist); 668a4c8a745SGarance A Drosehn free_list(&sesslist); 669a4c8a745SGarance A Drosehn free_list(&ttylist); 670a4c8a745SGarance A Drosehn free_list(&uidlist); 671044fce53SBrian Somers for (i = 0; i < nkept; i++) 672044fce53SBrian Somers free(kinfo[i].ki_d.prefix); 673044fce53SBrian Somers free(kinfo); 6742e6c6ac4SGarance A Drosehn 6754b88c807SRodney W. Grimes exit(eval); 6764b88c807SRodney W. Grimes } 6774b88c807SRodney W. Grimes 678a4c8a745SGarance A Drosehn static int 679a4c8a745SGarance A Drosehn addelem_gid(struct listinfo *inf, const char *elem) 6804e8b6a6fSGarance A Drosehn { 681a4c8a745SGarance A Drosehn struct group *grp; 682a4c8a745SGarance A Drosehn const char *nameorID; 683a4c8a745SGarance A Drosehn char *endp; 6840b42be7cSGarance A Drosehn u_long bigtemp; 6854e8b6a6fSGarance A Drosehn 686a4c8a745SGarance A Drosehn if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) { 687a4c8a745SGarance A Drosehn if (*elem == '\0') 688a4c8a745SGarance A Drosehn warnx("Invalid (zero-length) %s name", inf->lname); 689a4c8a745SGarance A Drosehn else 690a4c8a745SGarance A Drosehn warnx("%s name too long: %s", inf->lname, elem); 691a4c8a745SGarance A Drosehn optfatal = 1; 692352b6523SGarance A Drosehn return (0); /* Do not add this value. */ 6934e8b6a6fSGarance A Drosehn } 694a4c8a745SGarance A Drosehn 6954e8b6a6fSGarance A Drosehn /* 696a4c8a745SGarance A Drosehn * SUSv3 states that `ps -G grouplist' should match "real-group 697a4c8a745SGarance A Drosehn * ID numbers", and does not mention group-names. I do want to 698a4c8a745SGarance A Drosehn * also support group-names, so this tries for a group-id first, 699a4c8a745SGarance A Drosehn * and only tries for a name if that doesn't work. This is the 700a4c8a745SGarance A Drosehn * opposite order of what is done in addelem_uid(), but in 701a4c8a745SGarance A Drosehn * practice the order would only matter for group-names which 702a4c8a745SGarance A Drosehn * are all-numeric. 7034e8b6a6fSGarance A Drosehn */ 704a4c8a745SGarance A Drosehn grp = NULL; 705a4c8a745SGarance A Drosehn nameorID = "named"; 706a4c8a745SGarance A Drosehn errno = 0; 7070b42be7cSGarance A Drosehn bigtemp = strtoul(elem, &endp, 10); 7080b42be7cSGarance A Drosehn if (errno == 0 && *endp == '\0' && bigtemp <= GID_MAX) { 709a4c8a745SGarance A Drosehn nameorID = "name or ID matches"; 7100b42be7cSGarance A Drosehn grp = getgrgid((gid_t)bigtemp); 711a4c8a745SGarance A Drosehn } 712a4c8a745SGarance A Drosehn if (grp == NULL) 713a4c8a745SGarance A Drosehn grp = getgrnam(elem); 714a4c8a745SGarance A Drosehn if (grp == NULL) { 715a4c8a745SGarance A Drosehn warnx("No %s %s '%s'", inf->lname, nameorID, elem); 716a4c8a745SGarance A Drosehn optfatal = 1; 717c23b00b7SGarance A Drosehn return (0); 718a4c8a745SGarance A Drosehn } 719a4c8a745SGarance A Drosehn if (inf->count >= inf->maxcount) 720a4c8a745SGarance A Drosehn expand_list(inf); 721d822163fSGarance A Drosehn inf->l.gids[(inf->count)++] = grp->gr_gid; 722a4c8a745SGarance A Drosehn return (1); 723a4c8a745SGarance A Drosehn } 724a4c8a745SGarance A Drosehn 725352b6523SGarance A Drosehn #define BSD_PID_MAX 99999 /* Copy of PID_MAX from sys/proc.h. */ 726a4c8a745SGarance A Drosehn static int 727a4c8a745SGarance A Drosehn addelem_pid(struct listinfo *inf, const char *elem) 728a4c8a745SGarance A Drosehn { 729a4c8a745SGarance A Drosehn char *endp; 730ca62e195SGarance A Drosehn long tempid; 731a4c8a745SGarance A Drosehn 732de1702f4SGarance A Drosehn if (*elem == '\0') { 733de1702f4SGarance A Drosehn warnx("Invalid (zero-length) process id"); 734de1702f4SGarance A Drosehn optfatal = 1; 735de1702f4SGarance A Drosehn return (0); /* Do not add this value. */ 73625113083SGarance A Drosehn } 73725113083SGarance A Drosehn 738a4c8a745SGarance A Drosehn errno = 0; 739a4c8a745SGarance A Drosehn tempid = strtol(elem, &endp, 10); 740a4c8a745SGarance A Drosehn if (*endp != '\0' || tempid < 0 || elem == endp) { 741a4c8a745SGarance A Drosehn warnx("Invalid %s: %s", inf->lname, elem); 7424e8b6a6fSGarance A Drosehn errno = ERANGE; 7434e8b6a6fSGarance A Drosehn } else if (errno != 0 || tempid > BSD_PID_MAX) { 744a4c8a745SGarance A Drosehn warnx("%s too large: %s", inf->lname, elem); 7454e8b6a6fSGarance A Drosehn errno = ERANGE; 7464e8b6a6fSGarance A Drosehn } 7474e8b6a6fSGarance A Drosehn if (errno == ERANGE) { 748a4c8a745SGarance A Drosehn optfatal = 1; 749c23b00b7SGarance A Drosehn return (0); 7504e8b6a6fSGarance A Drosehn } 751a4c8a745SGarance A Drosehn if (inf->count >= inf->maxcount) 752a4c8a745SGarance A Drosehn expand_list(inf); 753d822163fSGarance A Drosehn inf->l.pids[(inf->count)++] = tempid; 754a4c8a745SGarance A Drosehn return (1); 7554e8b6a6fSGarance A Drosehn } 756a4c8a745SGarance A Drosehn #undef BSD_PID_MAX 7574e8b6a6fSGarance A Drosehn 75823b8efadSGarance A Drosehn /*- 75923b8efadSGarance A Drosehn * The user can specify a device via one of three formats: 7608a529f59SJohn Baldwin * 1) fully qualified, e.g.: /dev/ttyp0 /dev/console /dev/pts/0 7618a529f59SJohn Baldwin * 2) missing "/dev", e.g.: ttyp0 console pts/0 7628a529f59SJohn Baldwin * 3) two-letters, e.g.: p0 co 0 76323b8efadSGarance A Drosehn * (matching letters that would be seen in the "TT" column) 76423b8efadSGarance A Drosehn */ 765a4c8a745SGarance A Drosehn static int 766a4c8a745SGarance A Drosehn addelem_tty(struct listinfo *inf, const char *elem) 767cf22dcfcSBrian Somers { 768a4c8a745SGarance A Drosehn const char *ttypath; 769ca62e195SGarance A Drosehn struct stat sb; 7708a529f59SJohn Baldwin char pathbuf[PATH_MAX], pathbuf2[PATH_MAX], pathbuf3[PATH_MAX]; 771a4c8a745SGarance A Drosehn 77223b8efadSGarance A Drosehn ttypath = NULL; 773f2fbfae6SGarance A Drosehn pathbuf2[0] = '\0'; 7748a529f59SJohn Baldwin pathbuf3[0] = '\0'; 77523b8efadSGarance A Drosehn switch (*elem) { 77623b8efadSGarance A Drosehn case '/': 777a4c8a745SGarance A Drosehn ttypath = elem; 77823b8efadSGarance A Drosehn break; 77923b8efadSGarance A Drosehn case 'c': 78023b8efadSGarance A Drosehn if (strcmp(elem, "co") == 0) { 78123b8efadSGarance A Drosehn ttypath = _PATH_CONSOLE; 78223b8efadSGarance A Drosehn break; 78323b8efadSGarance A Drosehn } 78423b8efadSGarance A Drosehn /* FALLTHROUGH */ 78523b8efadSGarance A Drosehn default: 78623b8efadSGarance A Drosehn strlcpy(pathbuf, _PATH_DEV, sizeof(pathbuf)); 787a4c8a745SGarance A Drosehn strlcat(pathbuf, elem, sizeof(pathbuf)); 788a4c8a745SGarance A Drosehn ttypath = pathbuf; 789f2fbfae6SGarance A Drosehn if (strncmp(pathbuf, _PATH_TTY, strlen(_PATH_TTY)) == 0) 79023b8efadSGarance A Drosehn break; 7918a529f59SJohn Baldwin if (strncmp(pathbuf, _PATH_PTS, strlen(_PATH_PTS)) == 0) 7928a529f59SJohn Baldwin break; 79323b8efadSGarance A Drosehn if (strcmp(pathbuf, _PATH_CONSOLE) == 0) 79423b8efadSGarance A Drosehn break; 795f2fbfae6SGarance A Drosehn /* Check to see if /dev/tty${elem} exists */ 796f2fbfae6SGarance A Drosehn strlcpy(pathbuf2, _PATH_TTY, sizeof(pathbuf2)); 797f2fbfae6SGarance A Drosehn strlcat(pathbuf2, elem, sizeof(pathbuf2)); 798f2fbfae6SGarance A Drosehn if (stat(pathbuf2, &sb) == 0 && S_ISCHR(sb.st_mode)) { 79923b8efadSGarance A Drosehn /* No need to repeat stat() && S_ISCHR() checks */ 80023b8efadSGarance A Drosehn ttypath = NULL; 80123b8efadSGarance A Drosehn break; 802a4c8a745SGarance A Drosehn } 8038a529f59SJohn Baldwin /* Check to see if /dev/pts/${elem} exists */ 8048a529f59SJohn Baldwin strlcpy(pathbuf3, _PATH_PTS, sizeof(pathbuf3)); 8058a529f59SJohn Baldwin strlcat(pathbuf3, elem, sizeof(pathbuf3)); 8068a529f59SJohn Baldwin if (stat(pathbuf3, &sb) == 0 && S_ISCHR(sb.st_mode)) { 8078a529f59SJohn Baldwin /* No need to repeat stat() && S_ISCHR() checks */ 8088a529f59SJohn Baldwin ttypath = NULL; 8098a529f59SJohn Baldwin break; 8108a529f59SJohn Baldwin } 81123b8efadSGarance A Drosehn break; 81223b8efadSGarance A Drosehn } 81323b8efadSGarance A Drosehn if (ttypath) { 814a4c8a745SGarance A Drosehn if (stat(ttypath, &sb) == -1) { 8158a529f59SJohn Baldwin if (pathbuf3[0] != '\0') 8168a529f59SJohn Baldwin warn("%s, %s, and %s", pathbuf3, pathbuf2, 8178a529f59SJohn Baldwin ttypath); 818f2fbfae6SGarance A Drosehn else 819a4c8a745SGarance A Drosehn warn("%s", ttypath); 820a4c8a745SGarance A Drosehn optfatal = 1; 821c23b00b7SGarance A Drosehn return (0); 822a4c8a745SGarance A Drosehn } 823a4c8a745SGarance A Drosehn if (!S_ISCHR(sb.st_mode)) { 8248a529f59SJohn Baldwin if (pathbuf3[0] != '\0') 8258a529f59SJohn Baldwin warnx("%s, %s, and %s: Not a terminal", 8268a529f59SJohn Baldwin pathbuf3, pathbuf2, ttypath); 827f2fbfae6SGarance A Drosehn else 828f2fbfae6SGarance A Drosehn warnx("%s: Not a terminal", ttypath); 829a4c8a745SGarance A Drosehn optfatal = 1; 830c23b00b7SGarance A Drosehn return (0); 831a4c8a745SGarance A Drosehn } 83223b8efadSGarance A Drosehn } 833a4c8a745SGarance A Drosehn if (inf->count >= inf->maxcount) 834a4c8a745SGarance A Drosehn expand_list(inf); 835d822163fSGarance A Drosehn inf->l.ttys[(inf->count)++] = sb.st_rdev; 836a4c8a745SGarance A Drosehn return (1); 837a4c8a745SGarance A Drosehn } 838a4c8a745SGarance A Drosehn 839a4c8a745SGarance A Drosehn static int 840a4c8a745SGarance A Drosehn addelem_uid(struct listinfo *inf, const char *elem) 841a4c8a745SGarance A Drosehn { 842cf22dcfcSBrian Somers struct passwd *pwd; 843a4c8a745SGarance A Drosehn char *endp; 8440b42be7cSGarance A Drosehn u_long bigtemp; 845cf22dcfcSBrian Somers 846a4c8a745SGarance A Drosehn if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) { 847a4c8a745SGarance A Drosehn if (*elem == '\0') 848a4c8a745SGarance A Drosehn warnx("Invalid (zero-length) %s name", inf->lname); 849a4c8a745SGarance A Drosehn else 850a4c8a745SGarance A Drosehn warnx("%s name too long: %s", inf->lname, elem); 851a4c8a745SGarance A Drosehn optfatal = 1; 852352b6523SGarance A Drosehn return (0); /* Do not add this value. */ 853a4c8a745SGarance A Drosehn } 854cf22dcfcSBrian Somers 855a4c8a745SGarance A Drosehn pwd = getpwnam(elem); 856a4c8a745SGarance A Drosehn if (pwd == NULL) { 857a4c8a745SGarance A Drosehn errno = 0; 8580b42be7cSGarance A Drosehn bigtemp = strtoul(elem, &endp, 10); 8590b42be7cSGarance A Drosehn if (errno != 0 || *endp != '\0' || bigtemp > UID_MAX) 860a4c8a745SGarance A Drosehn warnx("No %s named '%s'", inf->lname, elem); 861a4c8a745SGarance A Drosehn else { 862a4c8a745SGarance A Drosehn /* The string is all digits, so it might be a userID. */ 8630b42be7cSGarance A Drosehn pwd = getpwuid((uid_t)bigtemp); 864a4c8a745SGarance A Drosehn if (pwd == NULL) 865a4c8a745SGarance A Drosehn warnx("No %s name or ID matches '%s'", 866a4c8a745SGarance A Drosehn inf->lname, elem); 867cf22dcfcSBrian Somers } 868cf22dcfcSBrian Somers } 869a4c8a745SGarance A Drosehn if (pwd == NULL) { 870e3c4e1ddSGarance A Drosehn /* 871e3c4e1ddSGarance A Drosehn * These used to be treated as minor warnings (and the 872e3c4e1ddSGarance A Drosehn * option was simply ignored), but now they are fatal 873e3c4e1ddSGarance A Drosehn * errors (and the command will be aborted). 874e3c4e1ddSGarance A Drosehn */ 875e3c4e1ddSGarance A Drosehn optfatal = 1; 876c23b00b7SGarance A Drosehn return (0); 877cf22dcfcSBrian Somers } 878a4c8a745SGarance A Drosehn if (inf->count >= inf->maxcount) 879a4c8a745SGarance A Drosehn expand_list(inf); 880d822163fSGarance A Drosehn inf->l.uids[(inf->count)++] = pwd->pw_uid; 881a4c8a745SGarance A Drosehn return (1); 882a4c8a745SGarance A Drosehn } 883cf22dcfcSBrian Somers 884a4c8a745SGarance A Drosehn static void 885a4c8a745SGarance A Drosehn add_list(struct listinfo *inf, const char *argp) 886a4c8a745SGarance A Drosehn { 887a4c8a745SGarance A Drosehn const char *savep; 888a4c8a745SGarance A Drosehn char *cp, *endp; 889a4c8a745SGarance A Drosehn int toolong; 890ca62e195SGarance A Drosehn char elemcopy[PATH_MAX]; 891a4c8a745SGarance A Drosehn 892de1702f4SGarance A Drosehn if (*argp == 0) 893de1702f4SGarance A Drosehn inf->addelem(inf, elemcopy); 894a4c8a745SGarance A Drosehn while (*argp != '\0') { 895a4c8a745SGarance A Drosehn while (*argp != '\0' && strchr(W_SEP, *argp) != NULL) 896a4c8a745SGarance A Drosehn argp++; 897a4c8a745SGarance A Drosehn savep = argp; 898a4c8a745SGarance A Drosehn toolong = 0; 899a4c8a745SGarance A Drosehn cp = elemcopy; 900a4c8a745SGarance A Drosehn if (strchr(T_SEP, *argp) == NULL) { 901a4c8a745SGarance A Drosehn endp = elemcopy + sizeof(elemcopy) - 1; 902a4c8a745SGarance A Drosehn while (*argp != '\0' && cp <= endp && 903a4c8a745SGarance A Drosehn strchr(W_SEP T_SEP, *argp) == NULL) 904a4c8a745SGarance A Drosehn *cp++ = *argp++; 905a4c8a745SGarance A Drosehn if (cp > endp) 906a4c8a745SGarance A Drosehn toolong = 1; 907a4c8a745SGarance A Drosehn } 908a4c8a745SGarance A Drosehn if (!toolong) { 909a4c8a745SGarance A Drosehn *cp = '\0'; 910352b6523SGarance A Drosehn /* 911a9626fb3SGarance A Drosehn * Add this single element to the given list. 912352b6523SGarance A Drosehn */ 913a4c8a745SGarance A Drosehn inf->addelem(inf, elemcopy); 914a4c8a745SGarance A Drosehn } else { 915a4c8a745SGarance A Drosehn /* 916a4c8a745SGarance A Drosehn * The string is too long to copy. Find the end 917a4c8a745SGarance A Drosehn * of the string to print out the warning message. 918a4c8a745SGarance A Drosehn */ 919a4c8a745SGarance A Drosehn while (*argp != '\0' && strchr(W_SEP T_SEP, 920a4c8a745SGarance A Drosehn *argp) == NULL) 921a4c8a745SGarance A Drosehn argp++; 922a4c8a745SGarance A Drosehn warnx("Value too long: %.*s", (int)(argp - savep), 923a4c8a745SGarance A Drosehn savep); 924a4c8a745SGarance A Drosehn optfatal = 1; 925a4c8a745SGarance A Drosehn } 926a4c8a745SGarance A Drosehn /* 927a4c8a745SGarance A Drosehn * Skip over any number of trailing whitespace characters, 928a4c8a745SGarance A Drosehn * but only one (at most) trailing element-terminating 929a4c8a745SGarance A Drosehn * character. 930a4c8a745SGarance A Drosehn */ 931a4c8a745SGarance A Drosehn while (*argp != '\0' && strchr(W_SEP, *argp) != NULL) 932a4c8a745SGarance A Drosehn argp++; 933a4c8a745SGarance A Drosehn if (*argp != '\0' && strchr(T_SEP, *argp) != NULL) { 934a4c8a745SGarance A Drosehn argp++; 935a4c8a745SGarance A Drosehn /* Catch case where string ended with a comma. */ 936a4c8a745SGarance A Drosehn if (*argp == '\0') 937a4c8a745SGarance A Drosehn inf->addelem(inf, argp); 938a4c8a745SGarance A Drosehn } 939a4c8a745SGarance A Drosehn } 940a4c8a745SGarance A Drosehn } 941a4c8a745SGarance A Drosehn 942044fce53SBrian Somers static void 943044fce53SBrian Somers descendant_sort(KINFO *ki, int items) 944044fce53SBrian Somers { 945044fce53SBrian Somers int dst, lvl, maxlvl, n, ndst, nsrc, siblings, src; 946044fce53SBrian Somers unsigned char *path; 947044fce53SBrian Somers KINFO kn; 948044fce53SBrian Somers 949044fce53SBrian Somers /* 950044fce53SBrian Somers * First, sort the entries by descendancy, tracking the descendancy 951044fce53SBrian Somers * depth in the ki_d.level field. 952044fce53SBrian Somers */ 953044fce53SBrian Somers src = 0; 954044fce53SBrian Somers maxlvl = 0; 955044fce53SBrian Somers while (src < items) { 956044fce53SBrian Somers if (ki[src].ki_d.level) { 957044fce53SBrian Somers src++; 958044fce53SBrian Somers continue; 959044fce53SBrian Somers } 960044fce53SBrian Somers for (nsrc = 1; src + nsrc < items; nsrc++) 961044fce53SBrian Somers if (!ki[src + nsrc].ki_d.level) 962044fce53SBrian Somers break; 963044fce53SBrian Somers 964044fce53SBrian Somers for (dst = 0; dst < items; dst++) { 965044fce53SBrian Somers if (ki[dst].ki_p->ki_pid == ki[src].ki_p->ki_pid) 966044fce53SBrian Somers continue; 967044fce53SBrian Somers if (ki[dst].ki_p->ki_pid == ki[src].ki_p->ki_ppid) 968044fce53SBrian Somers break; 969044fce53SBrian Somers } 970044fce53SBrian Somers 971044fce53SBrian Somers if (dst == items) { 972044fce53SBrian Somers src += nsrc; 973044fce53SBrian Somers continue; 974044fce53SBrian Somers } 975044fce53SBrian Somers 976044fce53SBrian Somers for (ndst = 1; dst + ndst < items; ndst++) 977044fce53SBrian Somers if (ki[dst + ndst].ki_d.level <= ki[dst].ki_d.level) 978044fce53SBrian Somers break; 979044fce53SBrian Somers 980044fce53SBrian Somers for (n = src; n < src + nsrc; n++) { 981044fce53SBrian Somers ki[n].ki_d.level += ki[dst].ki_d.level + 1; 982044fce53SBrian Somers if (maxlvl < ki[n].ki_d.level) 983044fce53SBrian Somers maxlvl = ki[n].ki_d.level; 984044fce53SBrian Somers } 985044fce53SBrian Somers 986044fce53SBrian Somers while (nsrc) { 987044fce53SBrian Somers if (src < dst) { 988044fce53SBrian Somers kn = ki[src]; 989044fce53SBrian Somers memmove(ki + src, ki + src + 1, 990044fce53SBrian Somers (dst - src + ndst - 1) * sizeof *ki); 991044fce53SBrian Somers ki[dst + ndst - 1] = kn; 992044fce53SBrian Somers nsrc--; 993044fce53SBrian Somers dst--; 994044fce53SBrian Somers ndst++; 995044fce53SBrian Somers } else if (src != dst + ndst) { 996044fce53SBrian Somers kn = ki[src]; 997044fce53SBrian Somers memmove(ki + dst + ndst + 1, ki + dst + ndst, 998044fce53SBrian Somers (src - dst - ndst) * sizeof *ki); 999044fce53SBrian Somers ki[dst + ndst] = kn; 1000044fce53SBrian Somers ndst++; 1001044fce53SBrian Somers nsrc--; 1002044fce53SBrian Somers src++; 1003044fce53SBrian Somers } else { 1004044fce53SBrian Somers ndst += nsrc; 1005044fce53SBrian Somers src += nsrc; 1006044fce53SBrian Somers nsrc = 0; 1007044fce53SBrian Somers } 1008044fce53SBrian Somers } 1009044fce53SBrian Somers } 1010044fce53SBrian Somers 1011044fce53SBrian Somers /* 1012044fce53SBrian Somers * Now populate ki_d.prefix (instead of ki_d.level) with the command 1013044fce53SBrian Somers * prefix used to show descendancies. 1014044fce53SBrian Somers */ 1015044fce53SBrian Somers path = malloc((maxlvl + 7) / 8); 1016044fce53SBrian Somers memset(path, '\0', (maxlvl + 7) / 8); 1017044fce53SBrian Somers for (src = 0; src < items; src++) { 1018044fce53SBrian Somers if ((lvl = ki[src].ki_d.level) == 0) { 1019044fce53SBrian Somers ki[src].ki_d.prefix = NULL; 1020044fce53SBrian Somers continue; 1021044fce53SBrian Somers } 1022044fce53SBrian Somers if ((ki[src].ki_d.prefix = malloc(lvl * 2 + 1)) == NULL) 1023044fce53SBrian Somers errx(1, "malloc failed"); 1024044fce53SBrian Somers for (n = 0; n < lvl - 2; n++) { 1025044fce53SBrian Somers ki[src].ki_d.prefix[n * 2] = 1026044fce53SBrian Somers path[n / 8] & 1 << (n % 8) ? '|' : ' '; 1027044fce53SBrian Somers ki[src].ki_d.prefix[n * 2 + 1] = ' '; 1028044fce53SBrian Somers } 1029044fce53SBrian Somers if (n == lvl - 2) { 1030044fce53SBrian Somers /* Have I any more siblings? */ 1031044fce53SBrian Somers for (siblings = 0, dst = src + 1; dst < items; dst++) { 1032044fce53SBrian Somers if (ki[dst].ki_d.level > lvl) 1033044fce53SBrian Somers continue; 1034044fce53SBrian Somers if (ki[dst].ki_d.level == lvl) 1035044fce53SBrian Somers siblings = 1; 1036044fce53SBrian Somers break; 1037044fce53SBrian Somers } 1038044fce53SBrian Somers if (siblings) 1039044fce53SBrian Somers path[n / 8] |= 1 << (n % 8); 1040044fce53SBrian Somers else 1041044fce53SBrian Somers path[n / 8] &= ~(1 << (n % 8)); 1042044fce53SBrian Somers ki[src].ki_d.prefix[n * 2] = siblings ? '|' : '`'; 1043044fce53SBrian Somers ki[src].ki_d.prefix[n * 2 + 1] = '-'; 1044044fce53SBrian Somers n++; 1045044fce53SBrian Somers } 1046044fce53SBrian Somers strcpy(ki[src].ki_d.prefix + n * 2, "- "); 1047044fce53SBrian Somers } 1048044fce53SBrian Somers free(path); 1049044fce53SBrian Somers } 1050044fce53SBrian Somers 1051a4c8a745SGarance A Drosehn static void * 1052a4c8a745SGarance A Drosehn expand_list(struct listinfo *inf) 1053a4c8a745SGarance A Drosehn { 1054a4c8a745SGarance A Drosehn void *newlist; 1055ca62e195SGarance A Drosehn int newmax; 1056a4c8a745SGarance A Drosehn 1057a4c8a745SGarance A Drosehn newmax = (inf->maxcount + 1) << 1; 1058d822163fSGarance A Drosehn newlist = realloc(inf->l.ptr, newmax * inf->elemsize); 1059a4c8a745SGarance A Drosehn if (newlist == NULL) { 1060d822163fSGarance A Drosehn free(inf->l.ptr); 1061c23b00b7SGarance A Drosehn errx(1, "realloc to %d %ss failed", newmax, inf->lname); 1062a4c8a745SGarance A Drosehn } 1063a4c8a745SGarance A Drosehn inf->maxcount = newmax; 1064d822163fSGarance A Drosehn inf->l.ptr = newlist; 1065a4c8a745SGarance A Drosehn 1066a4c8a745SGarance A Drosehn return (newlist); 1067a4c8a745SGarance A Drosehn } 1068a4c8a745SGarance A Drosehn 1069a4c8a745SGarance A Drosehn static void 1070a4c8a745SGarance A Drosehn free_list(struct listinfo *inf) 1071a4c8a745SGarance A Drosehn { 1072a4c8a745SGarance A Drosehn 1073a4c8a745SGarance A Drosehn inf->count = inf->elemsize = inf->maxcount = 0; 1074d822163fSGarance A Drosehn if (inf->l.ptr != NULL) 1075d822163fSGarance A Drosehn free(inf->l.ptr); 1076a4c8a745SGarance A Drosehn inf->addelem = NULL; 1077a4c8a745SGarance A Drosehn inf->lname = NULL; 1078d822163fSGarance A Drosehn inf->l.ptr = NULL; 1079a4c8a745SGarance A Drosehn } 1080a4c8a745SGarance A Drosehn 1081a4c8a745SGarance A Drosehn static void 1082a4c8a745SGarance A Drosehn init_list(struct listinfo *inf, addelem_rtn artn, int elemsize, 1083a4c8a745SGarance A Drosehn const char *lname) 1084a4c8a745SGarance A Drosehn { 1085a4c8a745SGarance A Drosehn 1086a4c8a745SGarance A Drosehn inf->count = inf->maxcount = 0; 1087a4c8a745SGarance A Drosehn inf->elemsize = elemsize; 1088a4c8a745SGarance A Drosehn inf->addelem = artn; 1089a4c8a745SGarance A Drosehn inf->lname = lname; 1090d822163fSGarance A Drosehn inf->l.ptr = NULL; 1091cf22dcfcSBrian Somers } 1092cf22dcfcSBrian Somers 1093fde411d5SJuli Mallett VARENT * 1094fde411d5SJuli Mallett find_varentry(VAR *v) 1095fde411d5SJuli Mallett { 1096fde411d5SJuli Mallett struct varent *vent; 1097fde411d5SJuli Mallett 1098bdf8ab46SGarance A Drosehn STAILQ_FOREACH(vent, &varlist, next_ve) { 1099fde411d5SJuli Mallett if (strcmp(vent->var->name, v->name) == 0) 1100fde411d5SJuli Mallett return vent; 1101fde411d5SJuli Mallett } 1102fde411d5SJuli Mallett return NULL; 1103fde411d5SJuli Mallett } 1104fde411d5SJuli Mallett 11054b88c807SRodney W. Grimes static void 110646251ddeSWarner Losh scanvars(void) 11074b88c807SRodney W. Grimes { 11084b88c807SRodney W. Grimes struct varent *vent; 11094b88c807SRodney W. Grimes VAR *v; 11106a2d726bSJordan K. Hubbard 1111bdf8ab46SGarance A Drosehn STAILQ_FOREACH(vent, &varlist, next_ve) { 11126a2d726bSJordan K. Hubbard v = vent->var; 11136a2d726bSJordan K. Hubbard if (v->flag & USER) 11146a2d726bSJordan K. Hubbard needuser = 1; 11156a2d726bSJordan K. Hubbard if (v->flag & COMM) 11166a2d726bSJordan K. Hubbard needcomm = 1; 11176a2d726bSJordan K. Hubbard } 11186a2d726bSJordan K. Hubbard } 11196a2d726bSJordan K. Hubbard 11206a2d726bSJordan K. Hubbard static void 11211d1143ecSEdward Tomasz Napierala format_output(KINFO *ki) 11226a2d726bSJordan K. Hubbard { 11236a2d726bSJordan K. Hubbard struct varent *vent; 11246a2d726bSJordan K. Hubbard VAR *v; 11251d1143ecSEdward Tomasz Napierala KINFO_STR *ks; 11261d1143ecSEdward Tomasz Napierala char *str; 11271d1143ecSEdward Tomasz Napierala int len; 11286a2d726bSJordan K. Hubbard 11291d1143ecSEdward Tomasz Napierala STAILQ_INIT(&ki->ki_ks); 1130bdf8ab46SGarance A Drosehn STAILQ_FOREACH(vent, &varlist, next_ve) { 11316a2d726bSJordan K. Hubbard v = vent->var; 11321d1143ecSEdward Tomasz Napierala str = (v->oproc)(ki, vent); 11331d1143ecSEdward Tomasz Napierala ks = malloc(sizeof(*ks)); 11341d1143ecSEdward Tomasz Napierala if (ks == NULL) 11351d1143ecSEdward Tomasz Napierala errx(1, "malloc failed"); 11361d1143ecSEdward Tomasz Napierala ks->ks_str = str; 11371d1143ecSEdward Tomasz Napierala STAILQ_INSERT_TAIL(&ki->ki_ks, ks, ks_next); 11381d1143ecSEdward Tomasz Napierala if (str != NULL) { 11391d1143ecSEdward Tomasz Napierala len = strlen(str); 11401d1143ecSEdward Tomasz Napierala } else 11411d1143ecSEdward Tomasz Napierala len = 1; /* "-" */ 11421d1143ecSEdward Tomasz Napierala if (v->width < len) 11431d1143ecSEdward Tomasz Napierala v->width = len; 11446a2d726bSJordan K. Hubbard } 11456a2d726bSJordan K. Hubbard } 11466a2d726bSJordan K. Hubbard 11476a2d726bSJordan K. Hubbard static void 114846251ddeSWarner Losh sizevars(void) 11496a2d726bSJordan K. Hubbard { 11506a2d726bSJordan K. Hubbard struct varent *vent; 11516a2d726bSJordan K. Hubbard VAR *v; 11524b88c807SRodney W. Grimes int i; 11534b88c807SRodney W. Grimes 1154bdf8ab46SGarance A Drosehn STAILQ_FOREACH(vent, &varlist, next_ve) { 11554b88c807SRodney W. Grimes v = vent->var; 115678b1878aSJuli Mallett i = strlen(vent->header); 11574b88c807SRodney W. Grimes if (v->width < i) 11584b88c807SRodney W. Grimes v->width = i; 11594b88c807SRodney W. Grimes } 11604b88c807SRodney W. Grimes } 11614b88c807SRodney W. Grimes 1162871e8d8cSMark Murray static const char * 116346251ddeSWarner Losh fmt(char **(*fn)(kvm_t *, const struct kinfo_proc *, int), KINFO *ki, 116446251ddeSWarner Losh char *comm, int maxlen) 11654b88c807SRodney W. Grimes { 1166871e8d8cSMark Murray const char *s; 11674b88c807SRodney W. Grimes 1168871e8d8cSMark Murray s = fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen); 11694b88c807SRodney W. Grimes return (s); 11704b88c807SRodney W. Grimes } 11714b88c807SRodney W. Grimes 1172b61ce5b0SJeff Roberson #define UREADOK(ki) (forceuread || (ki->ki_p->ki_flag & P_INMEM)) 11733ac5e955SJohn Dyson 11744b88c807SRodney W. Grimes static void 117546251ddeSWarner Losh saveuser(KINFO *ki) 11764b88c807SRodney W. Grimes { 11774b88c807SRodney W. Grimes 1178b61ce5b0SJeff Roberson if (ki->ki_p->ki_flag & P_INMEM) { 11794b88c807SRodney W. Grimes /* 11804b88c807SRodney W. Grimes * The u-area might be swapped out, and we can't get 11814b88c807SRodney W. Grimes * at it because we have a crashdump and no swap. 11824b88c807SRodney W. Grimes * If it's here fill in these fields, otherwise, just 11834b88c807SRodney W. Grimes * leave them 0. 11844b88c807SRodney W. Grimes */ 11851f7d2501SKirk McKusick ki->ki_valid = 1; 11864b88c807SRodney W. Grimes } else 11871f7d2501SKirk McKusick ki->ki_valid = 0; 11884b88c807SRodney W. Grimes /* 11894b88c807SRodney W. Grimes * save arguments if needed 11904b88c807SRodney W. Grimes */ 1191dd693acfSGarance A Drosehn if (needcomm) { 1192dd693acfSGarance A Drosehn if (ki->ki_p->ki_stat == SZOMB) 1193dd693acfSGarance A Drosehn ki->ki_args = strdup("<defunct>"); 1194dd693acfSGarance A Drosehn else if (UREADOK(ki) || (ki->ki_p->ki_args != NULL)) 1195dd693acfSGarance A Drosehn ki->ki_args = strdup(fmt(kvm_getargv, ki, 1196dd693acfSGarance A Drosehn ki->ki_p->ki_comm, MAXCOMLEN)); 1197dd693acfSGarance A Drosehn else 1198871e8d8cSMark Murray asprintf(&ki->ki_args, "(%s)", ki->ki_p->ki_comm); 1199bd6233fdSGarance A Drosehn if (ki->ki_args == NULL) 1200dd693acfSGarance A Drosehn errx(1, "malloc failed"); 12013ac5e955SJohn Dyson } else { 12024b88c807SRodney W. Grimes ki->ki_args = NULL; 12033ac5e955SJohn Dyson } 1204dd693acfSGarance A Drosehn if (needenv) { 1205dd693acfSGarance A Drosehn if (UREADOK(ki)) 1206dd693acfSGarance A Drosehn ki->ki_env = strdup(fmt(kvm_getenvv, ki, 1207dd693acfSGarance A Drosehn (char *)NULL, 0)); 1208dd693acfSGarance A Drosehn else 1209dd693acfSGarance A Drosehn ki->ki_env = strdup("()"); 1210dd693acfSGarance A Drosehn if (ki->ki_env == NULL) 1211dd693acfSGarance A Drosehn errx(1, "malloc failed"); 12123ac5e955SJohn Dyson } else { 12134b88c807SRodney W. Grimes ki->ki_env = NULL; 12144b88c807SRodney W. Grimes } 12153ac5e955SJohn Dyson } 12164b88c807SRodney W. Grimes 12174bac4483SGarance A Drosehn /* A macro used to improve the readability of pscomp(). */ 12184bac4483SGarance A Drosehn #define DIFF_RETURN(a, b, field) do { \ 12194bac4483SGarance A Drosehn if ((a)->field != (b)->field) \ 12204bac4483SGarance A Drosehn return (((a)->field < (b)->field) ? -1 : 1); \ 12214bac4483SGarance A Drosehn } while (0) 12224bac4483SGarance A Drosehn 12234b88c807SRodney W. Grimes static int 122446251ddeSWarner Losh pscomp(const void *a, const void *b) 12254b88c807SRodney W. Grimes { 12265bd7b1f3SGarance A Drosehn const KINFO *ka, *kb; 12274b88c807SRodney W. Grimes 12285bd7b1f3SGarance A Drosehn ka = a; 12295bd7b1f3SGarance A Drosehn kb = b; 12305bd7b1f3SGarance A Drosehn /* SORTCPU and SORTMEM are sorted in descending order. */ 12314bac4483SGarance A Drosehn if (sortby == SORTCPU) 12324bac4483SGarance A Drosehn DIFF_RETURN(kb, ka, ki_pcpu); 12334bac4483SGarance A Drosehn if (sortby == SORTMEM) 12344bac4483SGarance A Drosehn DIFF_RETURN(kb, ka, ki_memsize); 12355bd7b1f3SGarance A Drosehn /* 12365bd7b1f3SGarance A Drosehn * TTY's are sorted in ascending order, except that all NODEV 12375bd7b1f3SGarance A Drosehn * processes come before all processes with a device. 12385bd7b1f3SGarance A Drosehn */ 12394bac4483SGarance A Drosehn if (ka->ki_p->ki_tdev != kb->ki_p->ki_tdev) { 12404bac4483SGarance A Drosehn if (ka->ki_p->ki_tdev == NODEV) 12415bd7b1f3SGarance A Drosehn return (-1); 12424bac4483SGarance A Drosehn if (kb->ki_p->ki_tdev == NODEV) 12435bd7b1f3SGarance A Drosehn return (1); 12444bac4483SGarance A Drosehn DIFF_RETURN(ka, kb, ki_p->ki_tdev); 12454bac4483SGarance A Drosehn } 12464bac4483SGarance A Drosehn 1247b4b24324SGarance A Drosehn /* PID's and TID's (threads) are sorted in ascending order. */ 12484bac4483SGarance A Drosehn DIFF_RETURN(ka, kb, ki_p->ki_pid); 1249b4b24324SGarance A Drosehn DIFF_RETURN(ka, kb, ki_p->ki_tid); 12505bd7b1f3SGarance A Drosehn return (0); 12514b88c807SRodney W. Grimes } 12524bac4483SGarance A Drosehn #undef DIFF_RETURN 12534b88c807SRodney W. Grimes 12544b88c807SRodney W. Grimes /* 12554b88c807SRodney W. Grimes * ICK (all for getopt), would rather hide the ugliness 12564b88c807SRodney W. Grimes * here than taint the main code. 12574b88c807SRodney W. Grimes * 12584b88c807SRodney W. Grimes * ps foo -> ps -foo 12594b88c807SRodney W. Grimes * ps 34 -> ps -p34 12604b88c807SRodney W. Grimes * 12614b88c807SRodney W. Grimes * The old convention that 't' with no trailing tty arg means the users 12624b88c807SRodney W. Grimes * tty, is only supported if argv[1] doesn't begin with a '-'. This same 12634b88c807SRodney W. Grimes * feature is available with the option 'T', which takes no argument. 12644b88c807SRodney W. Grimes */ 12654b88c807SRodney W. Grimes static char * 1266bf46a3bfSGarance A Drosehn kludge_oldps_options(const char *optlist, char *origval, const char *nextarg) 12674b88c807SRodney W. Grimes { 12684b88c807SRodney W. Grimes size_t len; 1269c675340aSGarance A Drosehn char *argp, *cp, *newopts, *ns, *optp, *pidp; 12704b88c807SRodney W. Grimes 1271daed3ad6SJuli Mallett /* 1272c675340aSGarance A Drosehn * See if the original value includes any option which takes an 1273c675340aSGarance A Drosehn * argument (and will thus use up the remainder of the string). 1274daed3ad6SJuli Mallett */ 1275c675340aSGarance A Drosehn argp = NULL; 1276c675340aSGarance A Drosehn if (optlist != NULL) { 1277c675340aSGarance A Drosehn for (cp = origval; *cp != '\0'; cp++) { 1278c675340aSGarance A Drosehn optp = strchr(optlist, *cp); 1279c675340aSGarance A Drosehn if ((optp != NULL) && *(optp + 1) == ':') { 1280c675340aSGarance A Drosehn argp = cp; 1281c675340aSGarance A Drosehn break; 1282c675340aSGarance A Drosehn } 1283c675340aSGarance A Drosehn } 1284c675340aSGarance A Drosehn } 1285c675340aSGarance A Drosehn if (argp != NULL && *origval == '-') 1286c675340aSGarance A Drosehn return (origval); 1287daed3ad6SJuli Mallett 12884b88c807SRodney W. Grimes /* 12894b88c807SRodney W. Grimes * if last letter is a 't' flag with no argument (in the context 12904b88c807SRodney W. Grimes * of the oldps options -- option string NOT starting with a '-' -- 12914b88c807SRodney W. Grimes * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). 1292380434d4SBrian Somers * 12932631c777SGarance A Drosehn * However, if a flag accepting a string argument is found earlier 12942631c777SGarance A Drosehn * in the option string (including a possible `t' flag), then the 12952631c777SGarance A Drosehn * remainder of the string must be the argument to that flag; so 1296c675340aSGarance A Drosehn * do not modify that argument. Note that a trailing `t' would 1297c675340aSGarance A Drosehn * cause argp to be set, if argp was not already set by some 1298c675340aSGarance A Drosehn * earlier option. 12994b88c807SRodney W. Grimes */ 1300c675340aSGarance A Drosehn len = strlen(origval); 1301c675340aSGarance A Drosehn cp = origval + len - 1; 1302c675340aSGarance A Drosehn pidp = NULL; 1303bf46a3bfSGarance A Drosehn if (*cp == 't' && *origval != '-' && cp == argp) { 1304bf46a3bfSGarance A Drosehn if (nextarg == NULL || *nextarg == '-' || isdigitch(*nextarg)) 13054b88c807SRodney W. Grimes *cp = 'T'; 1306bf46a3bfSGarance A Drosehn } else if (argp == NULL) { 1307c675340aSGarance A Drosehn /* 1308c675340aSGarance A Drosehn * The original value did not include any option which takes 1309c675340aSGarance A Drosehn * an argument (and that would include `p' and `t'), so check 1310c675340aSGarance A Drosehn * the value for trailing number, or comma-separated list of 1311c675340aSGarance A Drosehn * numbers, which we will treat as a pid request. 1312c675340aSGarance A Drosehn */ 1313c675340aSGarance A Drosehn if (isdigitch(*cp)) { 1314c675340aSGarance A Drosehn while (cp >= origval && (*cp == ',' || isdigitch(*cp))) 1315c675340aSGarance A Drosehn --cp; 1316c675340aSGarance A Drosehn pidp = cp + 1; 1317c675340aSGarance A Drosehn } 1318c675340aSGarance A Drosehn } 1319c675340aSGarance A Drosehn 1320c675340aSGarance A Drosehn /* 1321c675340aSGarance A Drosehn * If nothing needs to be added to the string, then return 1322c675340aSGarance A Drosehn * the "original" (although possibly modified) value. 1323c675340aSGarance A Drosehn */ 1324c675340aSGarance A Drosehn if (*origval == '-' && pidp == NULL) 1325c675340aSGarance A Drosehn return (origval); 1326c675340aSGarance A Drosehn 1327c675340aSGarance A Drosehn /* 1328c675340aSGarance A Drosehn * Create a copy of the string to add '-' and/or 'p' to the 1329c675340aSGarance A Drosehn * original value. 1330c675340aSGarance A Drosehn */ 1331c675340aSGarance A Drosehn if ((newopts = ns = malloc(len + 3)) == NULL) 1332c675340aSGarance A Drosehn errx(1, "malloc failed"); 1333c675340aSGarance A Drosehn 1334c675340aSGarance A Drosehn if (*origval != '-') 1335c675340aSGarance A Drosehn *ns++ = '-'; /* add option flag */ 1336c675340aSGarance A Drosehn 1337c675340aSGarance A Drosehn if (pidp == NULL) 1338c675340aSGarance A Drosehn strcpy(ns, origval); 13394b88c807SRodney W. Grimes else { 13404b88c807SRodney W. Grimes /* 1341c675340aSGarance A Drosehn * Copy everything before the pid string, add the `p', 1342c675340aSGarance A Drosehn * and then copy the pid string. 13434b88c807SRodney W. Grimes */ 1344c675340aSGarance A Drosehn len = pidp - origval; 1345c675340aSGarance A Drosehn memcpy(ns, origval, len); 1346c675340aSGarance A Drosehn ns += len; 13474b88c807SRodney W. Grimes *ns++ = 'p'; 1348c675340aSGarance A Drosehn strcpy(ns, pidp); 1349c675340aSGarance A Drosehn } 13504b88c807SRodney W. Grimes 13514b88c807SRodney W. Grimes return (newopts); 13524b88c807SRodney W. Grimes } 13534b88c807SRodney W. Grimes 13544b88c807SRodney W. Grimes static void 135546251ddeSWarner Losh usage(void) 13564b88c807SRodney W. Grimes { 1357aa14b5abSBrian Somers #define SINGLE_OPTS "[-aCcde" OPT_LAZY_f "HhjlmrSTuvwXxZ]" 13584b88c807SRodney W. Grimes 1359a4c8a745SGarance A Drosehn (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", 1360a89237aeSRuslan Ermilov "usage: ps " SINGLE_OPTS " [-O fmt | -o fmt] [-G gid[,gid...]]", 1361a4c8a745SGarance A Drosehn " [-M core] [-N system]", 1362a89237aeSRuslan Ermilov " [-p pid[,pid...]] [-t tty[,tty...]] [-U user[,user...]]", 13634b88c807SRodney W. Grimes " ps [-L]"); 13644b88c807SRodney W. Grimes exit(1); 13654b88c807SRodney W. Grimes } 1366