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). */ 102de800cd4SGarance A Drosehn int totwidth; /* Calculated-width of requested variables. */ 1037ab24ea3SJulian Elischer int showthreads; /* will threads be shown? */ 1044b88c807SRodney W. Grimes 105bdf8ab46SGarance A Drosehn struct velisthead varlist = STAILQ_HEAD_INITIALIZER(varlist); 106de800cd4SGarance A Drosehn 107de800cd4SGarance A Drosehn static int forceuread = DEF_UREAD; /* Do extra work to get u-area. */ 108de800cd4SGarance A Drosehn static kvm_t *kd; 109de800cd4SGarance A Drosehn static KINFO *kinfo; 110de800cd4SGarance A Drosehn static int needcomm; /* -o "command" */ 111de800cd4SGarance A Drosehn static int needenv; /* -e */ 112de800cd4SGarance A Drosehn static int needuser; /* -o "user" */ 113de800cd4SGarance A Drosehn static int optfatal; /* Fatal error parsing some list-option. */ 114de800cd4SGarance A Drosehn 115de800cd4SGarance A Drosehn static enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; 116ba2cd770SJuli Mallett 117a4c8a745SGarance A Drosehn struct listinfo; 118de800cd4SGarance A Drosehn typedef int addelem_rtn(struct listinfo *_inf, const char *_elem); 119a4c8a745SGarance A Drosehn 120a4c8a745SGarance A Drosehn struct listinfo { 121a4c8a745SGarance A Drosehn int count; 122a4c8a745SGarance A Drosehn int maxcount; 123a4c8a745SGarance A Drosehn int elemsize; 124a4c8a745SGarance A Drosehn addelem_rtn *addelem; 125a4c8a745SGarance A Drosehn const char *lname; 126a4c8a745SGarance A Drosehn union { 127a4c8a745SGarance A Drosehn gid_t *gids; 128a4c8a745SGarance A Drosehn pid_t *pids; 129a4c8a745SGarance A Drosehn dev_t *ttys; 130a4c8a745SGarance A Drosehn uid_t *uids; 131a4c8a745SGarance A Drosehn void *ptr; 132d822163fSGarance A Drosehn } l; 133a4c8a745SGarance A Drosehn }; 134a4c8a745SGarance A Drosehn 135a951d1f8SChristian S.J. Peron static int check_procfs(void); 136a4c8a745SGarance A Drosehn static int addelem_gid(struct listinfo *, const char *); 137a4c8a745SGarance A Drosehn static int addelem_pid(struct listinfo *, const char *); 138a4c8a745SGarance A Drosehn static int addelem_tty(struct listinfo *, const char *); 139a4c8a745SGarance A Drosehn static int addelem_uid(struct listinfo *, const char *); 140a4c8a745SGarance A Drosehn static void add_list(struct listinfo *, const char *); 1414857f240SGarance A Drosehn static void dynsizevars(KINFO *); 142a4c8a745SGarance A Drosehn static void *expand_list(struct listinfo *); 143f35e0715SGarance A Drosehn static const char * 144f35e0715SGarance A Drosehn fmt(char **(*)(kvm_t *, const struct kinfo_proc *, int), 1454857f240SGarance A Drosehn KINFO *, char *, int); 146a4c8a745SGarance A Drosehn static void free_list(struct listinfo *); 147a4c8a745SGarance A Drosehn static void init_list(struct listinfo *, addelem_rtn, int, const char *); 14825113083SGarance A Drosehn static char *kludge_oldps_options(const char *, char *, const char *); 1494857f240SGarance A Drosehn static int pscomp(const void *, const void *); 1504857f240SGarance A Drosehn static void saveuser(KINFO *); 1514857f240SGarance A Drosehn static void scanvars(void); 1524857f240SGarance A Drosehn static void sizevars(void); 1534857f240SGarance A Drosehn static void usage(void); 1544b88c807SRodney W. Grimes 155c0716492SJuli Mallett static char dfmt[] = "pid,tt,state,time,command"; 156259fcfacSGarance A Drosehn static char jfmt[] = "user,pid,ppid,pgid,sid,jobc,state,tt,time,command"; 1571d2324f4SGarance A Drosehn static char lfmt[] = "uid,pid,ppid,cpu,pri,nice,vsz,rss,mwchan,state," 1581d2324f4SGarance A Drosehn "tt,time,command"; 159871e8d8cSMark Murray static char o1[] = "pid"; 160c0716492SJuli Mallett static char o2[] = "tt,state,time,command"; 161c0716492SJuli Mallett static char ufmt[] = "user,pid,%cpu,%mem,vsz,rss,tt,state,start,time,command"; 1621d2324f4SGarance A Drosehn static char vfmt[] = "pid,state,time,sl,re,pagein,vsz,rss,lim,tsiz," 1631d2324f4SGarance A Drosehn "%cpu,%mem,command"; 1642af538ebSRobert Watson static char Zfmt[] = "label"; 1654b88c807SRodney W. Grimes 1669bf69950SGarance A Drosehn #define PS_ARGS "AaCce" OPT_LAZY_f "G:gHhjLlM:mN:O:o:p:rSTt:U:uvwXxZ" 16741623b2dSMaxim Sobolev 1684b88c807SRodney W. Grimes int 16946251ddeSWarner Losh main(int argc, char *argv[]) 1704b88c807SRodney W. Grimes { 171a4c8a745SGarance A Drosehn struct listinfo gidlist, pgrplist, pidlist; 172a4c8a745SGarance A Drosehn struct listinfo ruidlist, sesslist, ttylist, uidlist; 1734b88c807SRodney W. Grimes struct kinfo_proc *kp; 1744bac4483SGarance A Drosehn KINFO *next_KINFO; 1754b88c807SRodney W. Grimes struct varent *vent; 1764b88c807SRodney W. Grimes struct winsize ws; 177c675340aSGarance A Drosehn const char *nlistf, *memf; 178ca62e195SGarance A Drosehn char *cols; 179832b0b55SRuslan Ermilov int all, ch, elem, flag, _fmt, i, lineno; 180c675340aSGarance A Drosehn int nentries, nkept, nselectors; 1817ab24ea3SJulian Elischer int prtheader, wflag, what, xkeep, xkeep_implied; 182871e8d8cSMark Murray char errbuf[_POSIX2_LINE_MAX]; 1834b88c807SRodney W. Grimes 1842bf4b9cfSAndrey A. Chernov (void) setlocale(LC_ALL, ""); 185352b6523SGarance A Drosehn time(&now); /* Used by routines in print.c. */ 1862bf4b9cfSAndrey A. Chernov 1874f18100dSTim J. Robbins if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0') 1884f18100dSTim J. Robbins termwidth = atoi(cols); 1894f18100dSTim J. Robbins else if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && 1904b88c807SRodney W. Grimes ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && 1914b88c807SRodney W. Grimes ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) || 1924b88c807SRodney W. Grimes ws.ws_col == 0) 1934b88c807SRodney W. Grimes termwidth = 79; 1944b88c807SRodney W. Grimes else 1954b88c807SRodney W. Grimes termwidth = ws.ws_col - 1; 1964b88c807SRodney W. Grimes 19741623b2dSMaxim Sobolev /* 198c675340aSGarance A Drosehn * Hide a number of option-processing kludges in a separate routine, 199c675340aSGarance A Drosehn * to support some historical BSD behaviors, such as `ps axu'. 20041623b2dSMaxim Sobolev */ 201c675340aSGarance A Drosehn if (argc > 1) 202bf46a3bfSGarance A Drosehn argv[1] = kludge_oldps_options(PS_ARGS, argv[1], argv[2]); 2034b88c807SRodney W. Grimes 204832b0b55SRuslan Ermilov all = _fmt = nselectors = optfatal = 0; 205352b6523SGarance A Drosehn prtheader = showthreads = wflag = xkeep_implied = 0; 206352b6523SGarance A Drosehn xkeep = -1; /* Neither -x nor -X. */ 207a4c8a745SGarance A Drosehn init_list(&gidlist, addelem_gid, sizeof(gid_t), "group"); 208a4c8a745SGarance A Drosehn init_list(&pgrplist, addelem_pid, sizeof(pid_t), "process group"); 209a4c8a745SGarance A Drosehn init_list(&pidlist, addelem_pid, sizeof(pid_t), "process id"); 210a4c8a745SGarance A Drosehn init_list(&ruidlist, addelem_uid, sizeof(uid_t), "ruser"); 211a4c8a745SGarance A Drosehn init_list(&sesslist, addelem_pid, sizeof(pid_t), "session id"); 212a4c8a745SGarance A Drosehn init_list(&ttylist, addelem_tty, sizeof(dev_t), "tty"); 213a4c8a745SGarance A Drosehn init_list(&uidlist, addelem_uid, sizeof(uid_t), "user"); 214831c910aSRuslan Ermilov memf = nlistf = _PATH_DEVNULL; 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 220a4c8a745SGarance A Drosehn * added for compatability 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; 236db91faacSPeter Wemm case 'e': /* XXX set ufmt */ 237db91faacSPeter Wemm needenv = 1; 238db91faacSPeter Wemm break; 2394a355d17SGarance A Drosehn #ifdef LAZY_PS 2404a355d17SGarance A Drosehn case 'f': 2414a355d17SGarance A Drosehn if (getuid() == 0 || getgid() == 0) 2424a355d17SGarance A Drosehn forceuread = 1; 2434a355d17SGarance A Drosehn break; 2444a355d17SGarance A Drosehn #endif 245a4c8a745SGarance A Drosehn case 'G': 246a4c8a745SGarance A Drosehn add_list(&gidlist, optarg); 247a4c8a745SGarance A Drosehn xkeep_implied = 1; 248a4c8a745SGarance A Drosehn nselectors++; 249a4c8a745SGarance A Drosehn break; 2504b88c807SRodney W. Grimes case 'g': 251352b6523SGarance A Drosehn #if 0 252ba50b0e0SGarance A Drosehn /*- 253352b6523SGarance A Drosehn * XXX - This SUSv3 behavior is still under debate 254352b6523SGarance A Drosehn * since it conflicts with the (undocumented) 255352b6523SGarance A Drosehn * `-g' option. So we skip it for now. 256352b6523SGarance A Drosehn */ 257a4c8a745SGarance A Drosehn add_list(&pgrplist, optarg); 258a4c8a745SGarance A Drosehn xkeep_implied = 1; 259a4c8a745SGarance A Drosehn nselectors++; 260a4c8a745SGarance A Drosehn break; 261a4c8a745SGarance A Drosehn #else 262352b6523SGarance A Drosehn /* The historical BSD-ish (from SunOS) behavior. */ 2634b88c807SRodney W. Grimes break; /* no-op */ 264a4c8a745SGarance A Drosehn #endif 26548b8c0deSScott Long case 'H': 266d75c1d83SDaniel Eischen showthreads = KERN_PROC_INC_THREAD; 26748b8c0deSScott Long break; 2684b88c807SRodney W. Grimes case 'h': 2694b88c807SRodney W. Grimes prtheader = ws.ws_row > 5 ? ws.ws_row : 22; 2704b88c807SRodney W. Grimes break; 2714b88c807SRodney W. Grimes case 'j': 272fde411d5SJuli Mallett parsefmt(jfmt, 0); 273871e8d8cSMark Murray _fmt = 1; 2744b88c807SRodney W. Grimes jfmt[0] = '\0'; 2754b88c807SRodney W. Grimes break; 2764b88c807SRodney W. Grimes case 'L': 2774b88c807SRodney W. Grimes showkey(); 2784b88c807SRodney W. Grimes exit(0); 2794b88c807SRodney W. Grimes case 'l': 280fde411d5SJuli Mallett parsefmt(lfmt, 0); 281871e8d8cSMark Murray _fmt = 1; 2824b88c807SRodney W. Grimes lfmt[0] = '\0'; 2834b88c807SRodney W. Grimes break; 2844b88c807SRodney W. Grimes case 'M': 2854b88c807SRodney W. Grimes memf = optarg; 2864b88c807SRodney W. Grimes break; 2874b88c807SRodney W. Grimes case 'm': 2884b88c807SRodney W. Grimes sortby = SORTMEM; 2894b88c807SRodney W. Grimes break; 2904b88c807SRodney W. Grimes case 'N': 2914b88c807SRodney W. Grimes nlistf = optarg; 2924b88c807SRodney W. Grimes break; 2934b88c807SRodney W. Grimes case 'O': 294fde411d5SJuli Mallett parsefmt(o1, 1); 295fde411d5SJuli Mallett parsefmt(optarg, 1); 296fde411d5SJuli Mallett parsefmt(o2, 1); 2974b88c807SRodney W. Grimes o1[0] = o2[0] = '\0'; 298871e8d8cSMark Murray _fmt = 1; 2994b88c807SRodney W. Grimes break; 3004b88c807SRodney W. Grimes case 'o': 301fde411d5SJuli Mallett parsefmt(optarg, 1); 302871e8d8cSMark Murray _fmt = 1; 3034b88c807SRodney W. Grimes break; 3044b88c807SRodney W. Grimes case 'p': 305a4c8a745SGarance A Drosehn add_list(&pidlist, optarg); 306a4c8a745SGarance A Drosehn /* 307a4c8a745SGarance A Drosehn * Note: `-p' does not *set* xkeep, but any values 308a4c8a745SGarance A Drosehn * from pidlist are checked before xkeep is. That 309a4c8a745SGarance A Drosehn * way they are always matched, even if the user 310a4c8a745SGarance A Drosehn * specifies `-X'. 311a4c8a745SGarance A Drosehn */ 312a4c8a745SGarance A Drosehn nselectors++; 3134b88c807SRodney W. Grimes break; 314a4c8a745SGarance A Drosehn #if 0 315a4c8a745SGarance A Drosehn case 'R': 316ba50b0e0SGarance A Drosehn /*- 317352b6523SGarance A Drosehn * XXX - This un-standard option is still under 318352b6523SGarance A Drosehn * debate. This is what SUSv3 defines as 319352b6523SGarance A Drosehn * the `-U' option, and while it would be 320352b6523SGarance A Drosehn * nice to have, it could cause even more 321352b6523SGarance A Drosehn * confusion to implement it as `-R'. 322352b6523SGarance A Drosehn */ 323a4c8a745SGarance A Drosehn add_list(&ruidlist, optarg); 324a4c8a745SGarance A Drosehn xkeep_implied = 1; 325a4c8a745SGarance A Drosehn nselectors++; 326a4c8a745SGarance A Drosehn break; 327a4c8a745SGarance A Drosehn #endif 3284b88c807SRodney W. Grimes case 'r': 3294b88c807SRodney W. Grimes sortby = SORTCPU; 3304b88c807SRodney W. Grimes break; 3314b88c807SRodney W. Grimes case 'S': 3324b88c807SRodney W. Grimes sumrusage = 1; 3334b88c807SRodney W. Grimes break; 334a4c8a745SGarance A Drosehn #if 0 335a4c8a745SGarance A Drosehn case 's': 336ba50b0e0SGarance A Drosehn /*- 337352b6523SGarance A Drosehn * XXX - This non-standard option is still under 338352b6523SGarance A Drosehn * debate. This *is* supported on Solaris, 339352b6523SGarance A Drosehn * Linux, and IRIX, but conflicts with `-s' 340352b6523SGarance A Drosehn * on NetBSD and maybe some older BSD's. 341352b6523SGarance A Drosehn */ 342a4c8a745SGarance A Drosehn add_list(&sesslist, optarg); 343a4c8a745SGarance A Drosehn xkeep_implied = 1; 344a4c8a745SGarance A Drosehn nselectors++; 345a4c8a745SGarance A Drosehn break; 346a4c8a745SGarance A Drosehn #endif 3474b88c807SRodney W. Grimes case 'T': 3484b88c807SRodney W. Grimes if ((optarg = ttyname(STDIN_FILENO)) == NULL) 3494b88c807SRodney W. Grimes errx(1, "stdin: not a terminal"); 3504b88c807SRodney W. Grimes /* FALLTHROUGH */ 351a4c8a745SGarance A Drosehn case 't': 352a4c8a745SGarance A Drosehn add_list(&ttylist, optarg); 353a4c8a745SGarance A Drosehn xkeep_implied = 1; 354a4c8a745SGarance A Drosehn nselectors++; 3554b88c807SRodney W. Grimes break; 35673eb8310SPeter Wemm case 'U': 357a4c8a745SGarance A Drosehn /* This is what SUSv3 defines as the `-u' option. */ 358a4c8a745SGarance A Drosehn add_list(&uidlist, optarg); 359a4c8a745SGarance A Drosehn xkeep_implied = 1; 360a4c8a745SGarance A Drosehn nselectors++; 36173eb8310SPeter Wemm break; 3624b88c807SRodney W. Grimes case 'u': 363fde411d5SJuli Mallett parsefmt(ufmt, 0); 3644b88c807SRodney W. Grimes sortby = SORTCPU; 365871e8d8cSMark Murray _fmt = 1; 3664b88c807SRodney W. Grimes ufmt[0] = '\0'; 3674b88c807SRodney W. Grimes break; 3684b88c807SRodney W. Grimes case 'v': 369fde411d5SJuli Mallett parsefmt(vfmt, 0); 3704b88c807SRodney W. Grimes sortby = SORTMEM; 371871e8d8cSMark Murray _fmt = 1; 3724b88c807SRodney W. Grimes vfmt[0] = '\0'; 3734b88c807SRodney W. Grimes break; 3744b88c807SRodney W. Grimes case 'w': 3754b88c807SRodney W. Grimes if (wflag) 3764b88c807SRodney W. Grimes termwidth = UNLIMITED; 3774b88c807SRodney W. Grimes else if (termwidth < 131) 3784b88c807SRodney W. Grimes termwidth = 131; 3794b88c807SRodney W. Grimes wflag++; 3804b88c807SRodney W. Grimes break; 381a4c8a745SGarance A Drosehn case 'X': 382a4c8a745SGarance A Drosehn /* 383a4c8a745SGarance A Drosehn * Note that `-X' and `-x' are not standard "selector" 384a4c8a745SGarance A Drosehn * options. For most selector-options, we check *all* 385a4c8a745SGarance A Drosehn * processes to see if any are matched by the given 386a4c8a745SGarance A Drosehn * value(s). After we have a set of all the matched 387a4c8a745SGarance A Drosehn * processes, then `-X' and `-x' govern whether we 388a4c8a745SGarance A Drosehn * modify that *matched* set for processes which do 389a4c8a745SGarance A Drosehn * not have a controlling terminal. `-X' causes 390a4c8a745SGarance A Drosehn * those processes to be deleted from the matched 391a4c8a745SGarance A Drosehn * set, while `-x' causes them to be kept. 392a4c8a745SGarance A Drosehn */ 393a4c8a745SGarance A Drosehn xkeep = 0; 394a4c8a745SGarance A Drosehn break; 3954b88c807SRodney W. Grimes case 'x': 396a4c8a745SGarance A Drosehn xkeep = 1; 3974b88c807SRodney W. Grimes break; 3987304f61fSBrian Feldman case 'Z': 399fde411d5SJuli Mallett parsefmt(Zfmt, 0); 4007304f61fSBrian Feldman Zfmt[0] = '\0'; 4017304f61fSBrian Feldman break; 4024b88c807SRodney W. Grimes case '?': 4034b88c807SRodney W. Grimes default: 4044b88c807SRodney W. Grimes usage(); 4054b88c807SRodney W. Grimes } 4064b88c807SRodney W. Grimes argc -= optind; 4074b88c807SRodney W. Grimes argv += optind; 408c675340aSGarance A Drosehn 409c675340aSGarance A Drosehn /* 410a951d1f8SChristian S.J. Peron * If the user specified ps -e then they want a copy of the process 411a951d1f8SChristian S.J. Peron * environment kvm_getenvv(3) attempts to open /proc/<pid>/mem. 412a951d1f8SChristian S.J. Peron * Check to make sure that procfs is mounted on /proc, otherwise 413a951d1f8SChristian S.J. Peron * print a warning informing the user that output will be incomplete. 414a951d1f8SChristian S.J. Peron */ 415a951d1f8SChristian S.J. Peron if (needenv == 1 && check_procfs() == 0) 416a951d1f8SChristian S.J. Peron warnx("Process environment requires procfs(5)"); 417a951d1f8SChristian S.J. Peron /* 418c675340aSGarance A Drosehn * If there arguments after processing all the options, attempt 419c675340aSGarance A Drosehn * to treat them as a list of process ids. 420c675340aSGarance A Drosehn */ 421c675340aSGarance A Drosehn while (*argv) { 422c675340aSGarance A Drosehn if (!isdigitch(**argv)) 423c675340aSGarance A Drosehn break; 424c675340aSGarance A Drosehn add_list(&pidlist, *argv); 425c675340aSGarance A Drosehn argv++; 426c675340aSGarance A Drosehn } 427c675340aSGarance A Drosehn if (*argv) { 428c675340aSGarance A Drosehn fprintf(stderr, "%s: illegal argument: %s\n", 429c675340aSGarance A Drosehn getprogname(), *argv); 430c675340aSGarance A Drosehn usage(); 431c675340aSGarance A Drosehn } 432a4c8a745SGarance A Drosehn if (optfatal) 433352b6523SGarance A Drosehn exit(1); /* Error messages already printed. */ 434352b6523SGarance A Drosehn if (xkeep < 0) /* Neither -X nor -x was specified. */ 435a4c8a745SGarance A Drosehn xkeep = xkeep_implied; 436a4c8a745SGarance A Drosehn 437831c910aSRuslan Ermilov kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 4384b88c807SRodney W. Grimes if (kd == 0) 4394b88c807SRodney W. Grimes errx(1, "%s", errbuf); 4404b88c807SRodney W. Grimes 441871e8d8cSMark Murray if (!_fmt) 442fde411d5SJuli Mallett parsefmt(dfmt, 0); 4434b88c807SRodney W. Grimes 444a4c8a745SGarance A Drosehn if (nselectors == 0) { 445d822163fSGarance A Drosehn uidlist.l.ptr = malloc(sizeof(uid_t)); 446d822163fSGarance A Drosehn if (uidlist.l.ptr == NULL) 4474fa7d788SJuli Mallett errx(1, "malloc failed"); 448a4c8a745SGarance A Drosehn nselectors = 1; 449a4c8a745SGarance A Drosehn uidlist.count = uidlist.maxcount = 1; 450d822163fSGarance A Drosehn *uidlist.l.uids = getuid(); 451cf22dcfcSBrian Somers } 4524b88c807SRodney W. Grimes 4534b88c807SRodney W. Grimes /* 4544b88c807SRodney W. Grimes * scan requested variables, noting what structures are needed, 455bdfebd84SKris Kennaway * and adjusting header widths as appropriate. 4564b88c807SRodney W. Grimes */ 4574b88c807SRodney W. Grimes scanvars(); 458a4c8a745SGarance A Drosehn 4594b88c807SRodney W. Grimes /* 460a4c8a745SGarance A Drosehn * Get process list. If the user requested just one selector- 461a4c8a745SGarance A Drosehn * option, then kvm_getprocs can be asked to return just those 462a4c8a745SGarance A Drosehn * processes. Otherwise, have it return all processes, and 463a4c8a745SGarance A Drosehn * then this routine will search that full list and select the 464a4c8a745SGarance A Drosehn * processes which match any of the user's selector-options. 4654b88c807SRodney W. Grimes */ 466d75c1d83SDaniel Eischen what = showthreads != 0 ? KERN_PROC_ALL : KERN_PROC_PROC; 46748b8c0deSScott Long flag = 0; 468a4c8a745SGarance A Drosehn if (nselectors == 1) { 4697bd42165SGarance A Drosehn if (gidlist.count == 1) { 4707bd42165SGarance A Drosehn what = KERN_PROC_RGID | showthreads; 4717bd42165SGarance A Drosehn flag = *gidlist.l.gids; 4727bd42165SGarance A Drosehn nselectors = 0; 4737bd42165SGarance A Drosehn } else if (pgrplist.count == 1) { 474a4c8a745SGarance A Drosehn what = KERN_PROC_PGRP | showthreads; 475d822163fSGarance A Drosehn flag = *pgrplist.l.pids; 476a4c8a745SGarance A Drosehn nselectors = 0; 477a4c8a745SGarance A Drosehn } else if (pidlist.count == 1) { 478a4c8a745SGarance A Drosehn what = KERN_PROC_PID | showthreads; 479d822163fSGarance A Drosehn flag = *pidlist.l.pids; 480a4c8a745SGarance A Drosehn nselectors = 0; 481a4c8a745SGarance A Drosehn } else if (ruidlist.count == 1) { 482a4c8a745SGarance A Drosehn what = KERN_PROC_RUID | showthreads; 483d822163fSGarance A Drosehn flag = *ruidlist.l.uids; 484a4c8a745SGarance A Drosehn nselectors = 0; 485a4c8a745SGarance A Drosehn } else if (sesslist.count == 1) { 486a4c8a745SGarance A Drosehn what = KERN_PROC_SESSION | showthreads; 487d822163fSGarance A Drosehn flag = *sesslist.l.pids; 488a4c8a745SGarance A Drosehn nselectors = 0; 489a4c8a745SGarance A Drosehn } else if (ttylist.count == 1) { 490a4c8a745SGarance A Drosehn what = KERN_PROC_TTY | showthreads; 491d822163fSGarance A Drosehn flag = *ttylist.l.ttys; 492a4c8a745SGarance A Drosehn nselectors = 0; 493a4c8a745SGarance A Drosehn } else if (uidlist.count == 1) { 494a4c8a745SGarance A Drosehn what = KERN_PROC_UID | showthreads; 495d822163fSGarance A Drosehn flag = *uidlist.l.uids; 496a4c8a745SGarance A Drosehn nselectors = 0; 497a4c8a745SGarance A Drosehn } else if (all) { 498a4c8a745SGarance A Drosehn /* No need for this routine to select processes. */ 499a4c8a745SGarance A Drosehn nselectors = 0; 500a4c8a745SGarance A Drosehn } 5014b88c807SRodney W. Grimes } 502d75c1d83SDaniel Eischen 5034b88c807SRodney W. Grimes /* 5044b88c807SRodney W. Grimes * select procs 5054b88c807SRodney W. Grimes */ 506a4c8a745SGarance A Drosehn nentries = -1; 5074e8b6a6fSGarance A Drosehn kp = kvm_getprocs(kd, what, flag, &nentries); 50887e47750SGarance A Drosehn if ((kp == NULL && nentries > 0) || (kp != NULL && nentries < 0)) 5094b88c807SRodney W. Grimes errx(1, "%s", kvm_geterr(kd)); 510a4c8a745SGarance A Drosehn nkept = 0; 5114e8b6a6fSGarance A Drosehn if (nentries > 0) { 5124b88c807SRodney W. Grimes if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL) 5134fa7d788SJuli Mallett errx(1, "malloc failed"); 5144b88c807SRodney W. Grimes for (i = nentries; --i >= 0; ++kp) { 515a4c8a745SGarance A Drosehn /* 516a4c8a745SGarance A Drosehn * If the user specified multiple selection-criteria, 517a4c8a745SGarance A Drosehn * then keep any process matched by the inclusive OR 518a4c8a745SGarance A Drosehn * of all the selection-criteria given. 519a4c8a745SGarance A Drosehn */ 520a4c8a745SGarance A Drosehn if (pidlist.count > 0) { 521a4c8a745SGarance A Drosehn for (elem = 0; elem < pidlist.count; elem++) 522d822163fSGarance A Drosehn if (kp->ki_pid == pidlist.l.pids[elem]) 523a4c8a745SGarance A Drosehn goto keepit; 524a4c8a745SGarance A Drosehn } 525a4c8a745SGarance A Drosehn /* 526a4c8a745SGarance A Drosehn * Note that we had to process pidlist before 527a4c8a745SGarance A Drosehn * filtering out processes which do not have 528a4c8a745SGarance A Drosehn * a controlling terminal. 529a4c8a745SGarance A Drosehn */ 530a4c8a745SGarance A Drosehn if (xkeep == 0) { 531a4c8a745SGarance A Drosehn if ((kp->ki_tdev == NODEV || 532a4c8a745SGarance A Drosehn (kp->ki_flag & P_CONTROLT) == 0)) 533a4c8a745SGarance A Drosehn continue; 534a4c8a745SGarance A Drosehn } 535a4c8a745SGarance A Drosehn if (nselectors == 0) 536a4c8a745SGarance A Drosehn goto keepit; 537a4c8a745SGarance A Drosehn if (gidlist.count > 0) { 538a4c8a745SGarance A Drosehn for (elem = 0; elem < gidlist.count; elem++) 539d822163fSGarance A Drosehn if (kp->ki_rgid == gidlist.l.gids[elem]) 540a4c8a745SGarance A Drosehn goto keepit; 541a4c8a745SGarance A Drosehn } 542a4c8a745SGarance A Drosehn if (pgrplist.count > 0) { 543a4c8a745SGarance A Drosehn for (elem = 0; elem < pgrplist.count; elem++) 544d822163fSGarance A Drosehn if (kp->ki_pgid == 545d822163fSGarance A Drosehn pgrplist.l.pids[elem]) 546a4c8a745SGarance A Drosehn goto keepit; 547a4c8a745SGarance A Drosehn } 548a4c8a745SGarance A Drosehn if (ruidlist.count > 0) { 549a4c8a745SGarance A Drosehn for (elem = 0; elem < ruidlist.count; elem++) 550d822163fSGarance A Drosehn if (kp->ki_ruid == 551d822163fSGarance A Drosehn ruidlist.l.uids[elem]) 552a4c8a745SGarance A Drosehn goto keepit; 553a4c8a745SGarance A Drosehn } 554a4c8a745SGarance A Drosehn if (sesslist.count > 0) { 555a4c8a745SGarance A Drosehn for (elem = 0; elem < sesslist.count; elem++) 556d822163fSGarance A Drosehn if (kp->ki_sid == sesslist.l.pids[elem]) 557a4c8a745SGarance A Drosehn goto keepit; 558a4c8a745SGarance A Drosehn } 559a4c8a745SGarance A Drosehn if (ttylist.count > 0) { 560a4c8a745SGarance A Drosehn for (elem = 0; elem < ttylist.count; elem++) 561d822163fSGarance A Drosehn if (kp->ki_tdev == ttylist.l.ttys[elem]) 562a4c8a745SGarance A Drosehn goto keepit; 563a4c8a745SGarance A Drosehn } 564a4c8a745SGarance A Drosehn if (uidlist.count > 0) { 565a4c8a745SGarance A Drosehn for (elem = 0; elem < uidlist.count; elem++) 566d822163fSGarance A Drosehn if (kp->ki_uid == uidlist.l.uids[elem]) 567a4c8a745SGarance A Drosehn goto keepit; 568a4c8a745SGarance A Drosehn } 569a4c8a745SGarance A Drosehn /* 570a4c8a745SGarance A Drosehn * This process did not match any of the user's 571a4c8a745SGarance A Drosehn * selector-options, so skip the process. 572a4c8a745SGarance A Drosehn */ 573a4c8a745SGarance A Drosehn continue; 574a4c8a745SGarance A Drosehn 575a4c8a745SGarance A Drosehn keepit: 5764bac4483SGarance A Drosehn next_KINFO = &kinfo[nkept]; 5774bac4483SGarance A Drosehn next_KINFO->ki_p = kp; 5784bac4483SGarance A Drosehn next_KINFO->ki_pcpu = getpcpu(next_KINFO); 5794bac4483SGarance A Drosehn if (sortby == SORTMEM) 5804bac4483SGarance A Drosehn next_KINFO->ki_memsize = kp->ki_tsize + 5814bac4483SGarance A Drosehn kp->ki_dsize + kp->ki_ssize; 5824b88c807SRodney W. Grimes if (needuser) 5834bac4483SGarance A Drosehn saveuser(next_KINFO); 5844bac4483SGarance A Drosehn dynsizevars(next_KINFO); 585a4c8a745SGarance A Drosehn nkept++; 5864b88c807SRodney W. Grimes } 5874e8b6a6fSGarance A Drosehn } 5886a2d726bSJordan K. Hubbard 5896a2d726bSJordan K. Hubbard sizevars(); 5906a2d726bSJordan K. Hubbard 5914b88c807SRodney W. Grimes /* 5924b88c807SRodney W. Grimes * print header 5934b88c807SRodney W. Grimes */ 5944b88c807SRodney W. Grimes printheader(); 595a4c8a745SGarance A Drosehn if (nkept == 0) 596f8c9c11cSWill Andrews exit(1); 597a4c8a745SGarance A Drosehn 5984b88c807SRodney W. Grimes /* 5994b88c807SRodney W. Grimes * sort proc list 6004b88c807SRodney W. Grimes */ 601a4c8a745SGarance A Drosehn qsort(kinfo, nkept, sizeof(KINFO), pscomp); 6024b88c807SRodney W. Grimes /* 603a4c8a745SGarance A Drosehn * For each process, call each variable output function. 6044b88c807SRodney W. Grimes */ 605a4c8a745SGarance A Drosehn for (i = lineno = 0; i < nkept; i++) { 606bdf8ab46SGarance A Drosehn STAILQ_FOREACH(vent, &varlist, next_ve) { 6074b88c807SRodney W. Grimes (vent->var->oproc)(&kinfo[i], vent); 608bdf8ab46SGarance A Drosehn if (STAILQ_NEXT(vent, next_ve) != NULL) 6094b88c807SRodney W. Grimes (void)putchar(' '); 6104b88c807SRodney W. Grimes } 6114b88c807SRodney W. Grimes (void)putchar('\n'); 6124b88c807SRodney W. Grimes if (prtheader && lineno++ == prtheader - 4) { 6134b88c807SRodney W. Grimes (void)putchar('\n'); 6144b88c807SRodney W. Grimes printheader(); 6154b88c807SRodney W. Grimes lineno = 0; 6164b88c807SRodney W. Grimes } 6174b88c807SRodney W. Grimes } 618a4c8a745SGarance A Drosehn free_list(&gidlist); 619a4c8a745SGarance A Drosehn free_list(&pidlist); 620a4c8a745SGarance A Drosehn free_list(&pgrplist); 621a4c8a745SGarance A Drosehn free_list(&ruidlist); 622a4c8a745SGarance A Drosehn free_list(&sesslist); 623a4c8a745SGarance A Drosehn free_list(&ttylist); 624a4c8a745SGarance A Drosehn free_list(&uidlist); 6252e6c6ac4SGarance A Drosehn 6264b88c807SRodney W. Grimes exit(eval); 6274b88c807SRodney W. Grimes } 6284b88c807SRodney W. Grimes 629a4c8a745SGarance A Drosehn static int 630a4c8a745SGarance A Drosehn addelem_gid(struct listinfo *inf, const char *elem) 6314e8b6a6fSGarance A Drosehn { 632a4c8a745SGarance A Drosehn struct group *grp; 633a4c8a745SGarance A Drosehn const char *nameorID; 634a4c8a745SGarance A Drosehn char *endp; 6350b42be7cSGarance A Drosehn u_long bigtemp; 6364e8b6a6fSGarance A Drosehn 637a4c8a745SGarance A Drosehn if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) { 638a4c8a745SGarance A Drosehn if (*elem == '\0') 639a4c8a745SGarance A Drosehn warnx("Invalid (zero-length) %s name", inf->lname); 640a4c8a745SGarance A Drosehn else 641a4c8a745SGarance A Drosehn warnx("%s name too long: %s", inf->lname, elem); 642a4c8a745SGarance A Drosehn optfatal = 1; 643352b6523SGarance A Drosehn return (0); /* Do not add this value. */ 6444e8b6a6fSGarance A Drosehn } 645a4c8a745SGarance A Drosehn 6464e8b6a6fSGarance A Drosehn /* 647a4c8a745SGarance A Drosehn * SUSv3 states that `ps -G grouplist' should match "real-group 648a4c8a745SGarance A Drosehn * ID numbers", and does not mention group-names. I do want to 649a4c8a745SGarance A Drosehn * also support group-names, so this tries for a group-id first, 650a4c8a745SGarance A Drosehn * and only tries for a name if that doesn't work. This is the 651a4c8a745SGarance A Drosehn * opposite order of what is done in addelem_uid(), but in 652a4c8a745SGarance A Drosehn * practice the order would only matter for group-names which 653a4c8a745SGarance A Drosehn * are all-numeric. 6544e8b6a6fSGarance A Drosehn */ 655a4c8a745SGarance A Drosehn grp = NULL; 656a4c8a745SGarance A Drosehn nameorID = "named"; 657a4c8a745SGarance A Drosehn errno = 0; 6580b42be7cSGarance A Drosehn bigtemp = strtoul(elem, &endp, 10); 6590b42be7cSGarance A Drosehn if (errno == 0 && *endp == '\0' && bigtemp <= GID_MAX) { 660a4c8a745SGarance A Drosehn nameorID = "name or ID matches"; 6610b42be7cSGarance A Drosehn grp = getgrgid((gid_t)bigtemp); 662a4c8a745SGarance A Drosehn } 663a4c8a745SGarance A Drosehn if (grp == NULL) 664a4c8a745SGarance A Drosehn grp = getgrnam(elem); 665a4c8a745SGarance A Drosehn if (grp == NULL) { 666a4c8a745SGarance A Drosehn warnx("No %s %s '%s'", inf->lname, nameorID, elem); 667a4c8a745SGarance A Drosehn optfatal = 1; 668c23b00b7SGarance A Drosehn return (0); 669a4c8a745SGarance A Drosehn } 670a4c8a745SGarance A Drosehn if (inf->count >= inf->maxcount) 671a4c8a745SGarance A Drosehn expand_list(inf); 672d822163fSGarance A Drosehn inf->l.gids[(inf->count)++] = grp->gr_gid; 673a4c8a745SGarance A Drosehn return (1); 674a4c8a745SGarance A Drosehn } 675a4c8a745SGarance A Drosehn 676352b6523SGarance A Drosehn #define BSD_PID_MAX 99999 /* Copy of PID_MAX from sys/proc.h. */ 677a4c8a745SGarance A Drosehn static int 678a4c8a745SGarance A Drosehn addelem_pid(struct listinfo *inf, const char *elem) 679a4c8a745SGarance A Drosehn { 680a4c8a745SGarance A Drosehn char *endp; 681ca62e195SGarance A Drosehn long tempid; 682a4c8a745SGarance A Drosehn 683de1702f4SGarance A Drosehn if (*elem == '\0') { 684de1702f4SGarance A Drosehn warnx("Invalid (zero-length) process id"); 685de1702f4SGarance A Drosehn optfatal = 1; 686de1702f4SGarance A Drosehn return (0); /* Do not add this value. */ 68725113083SGarance A Drosehn } 68825113083SGarance A Drosehn 689a4c8a745SGarance A Drosehn errno = 0; 690a4c8a745SGarance A Drosehn tempid = strtol(elem, &endp, 10); 691a4c8a745SGarance A Drosehn if (*endp != '\0' || tempid < 0 || elem == endp) { 692a4c8a745SGarance A Drosehn warnx("Invalid %s: %s", inf->lname, elem); 6934e8b6a6fSGarance A Drosehn errno = ERANGE; 6944e8b6a6fSGarance A Drosehn } else if (errno != 0 || tempid > BSD_PID_MAX) { 695a4c8a745SGarance A Drosehn warnx("%s too large: %s", inf->lname, elem); 6964e8b6a6fSGarance A Drosehn errno = ERANGE; 6974e8b6a6fSGarance A Drosehn } 6984e8b6a6fSGarance A Drosehn if (errno == ERANGE) { 699a4c8a745SGarance A Drosehn optfatal = 1; 700c23b00b7SGarance A Drosehn return (0); 7014e8b6a6fSGarance A Drosehn } 702a4c8a745SGarance A Drosehn if (inf->count >= inf->maxcount) 703a4c8a745SGarance A Drosehn expand_list(inf); 704d822163fSGarance A Drosehn inf->l.pids[(inf->count)++] = tempid; 705a4c8a745SGarance A Drosehn return (1); 7064e8b6a6fSGarance A Drosehn } 707a4c8a745SGarance A Drosehn #undef BSD_PID_MAX 7084e8b6a6fSGarance A Drosehn 70923b8efadSGarance A Drosehn /*- 71023b8efadSGarance A Drosehn * The user can specify a device via one of three formats: 7118a529f59SJohn Baldwin * 1) fully qualified, e.g.: /dev/ttyp0 /dev/console /dev/pts/0 7128a529f59SJohn Baldwin * 2) missing "/dev", e.g.: ttyp0 console pts/0 7138a529f59SJohn Baldwin * 3) two-letters, e.g.: p0 co 0 71423b8efadSGarance A Drosehn * (matching letters that would be seen in the "TT" column) 71523b8efadSGarance A Drosehn */ 716a4c8a745SGarance A Drosehn static int 717a4c8a745SGarance A Drosehn addelem_tty(struct listinfo *inf, const char *elem) 718cf22dcfcSBrian Somers { 719a4c8a745SGarance A Drosehn const char *ttypath; 720ca62e195SGarance A Drosehn struct stat sb; 7218a529f59SJohn Baldwin char pathbuf[PATH_MAX], pathbuf2[PATH_MAX], pathbuf3[PATH_MAX]; 722a4c8a745SGarance A Drosehn 72323b8efadSGarance A Drosehn ttypath = NULL; 724f2fbfae6SGarance A Drosehn pathbuf2[0] = '\0'; 7258a529f59SJohn Baldwin pathbuf3[0] = '\0'; 72623b8efadSGarance A Drosehn switch (*elem) { 72723b8efadSGarance A Drosehn case '/': 728a4c8a745SGarance A Drosehn ttypath = elem; 72923b8efadSGarance A Drosehn break; 73023b8efadSGarance A Drosehn case 'c': 73123b8efadSGarance A Drosehn if (strcmp(elem, "co") == 0) { 73223b8efadSGarance A Drosehn ttypath = _PATH_CONSOLE; 73323b8efadSGarance A Drosehn break; 73423b8efadSGarance A Drosehn } 73523b8efadSGarance A Drosehn /* FALLTHROUGH */ 73623b8efadSGarance A Drosehn default: 73723b8efadSGarance A Drosehn strlcpy(pathbuf, _PATH_DEV, sizeof(pathbuf)); 738a4c8a745SGarance A Drosehn strlcat(pathbuf, elem, sizeof(pathbuf)); 739a4c8a745SGarance A Drosehn ttypath = pathbuf; 740f2fbfae6SGarance A Drosehn if (strncmp(pathbuf, _PATH_TTY, strlen(_PATH_TTY)) == 0) 74123b8efadSGarance A Drosehn break; 7428a529f59SJohn Baldwin if (strncmp(pathbuf, _PATH_PTS, strlen(_PATH_PTS)) == 0) 7438a529f59SJohn Baldwin break; 74423b8efadSGarance A Drosehn if (strcmp(pathbuf, _PATH_CONSOLE) == 0) 74523b8efadSGarance A Drosehn break; 746f2fbfae6SGarance A Drosehn /* Check to see if /dev/tty${elem} exists */ 747f2fbfae6SGarance A Drosehn strlcpy(pathbuf2, _PATH_TTY, sizeof(pathbuf2)); 748f2fbfae6SGarance A Drosehn strlcat(pathbuf2, elem, sizeof(pathbuf2)); 749f2fbfae6SGarance A Drosehn if (stat(pathbuf2, &sb) == 0 && S_ISCHR(sb.st_mode)) { 75023b8efadSGarance A Drosehn /* No need to repeat stat() && S_ISCHR() checks */ 75123b8efadSGarance A Drosehn ttypath = NULL; 75223b8efadSGarance A Drosehn break; 753a4c8a745SGarance A Drosehn } 7548a529f59SJohn Baldwin /* Check to see if /dev/pts/${elem} exists */ 7558a529f59SJohn Baldwin strlcpy(pathbuf3, _PATH_PTS, sizeof(pathbuf3)); 7568a529f59SJohn Baldwin strlcat(pathbuf3, elem, sizeof(pathbuf3)); 7578a529f59SJohn Baldwin if (stat(pathbuf3, &sb) == 0 && S_ISCHR(sb.st_mode)) { 7588a529f59SJohn Baldwin /* No need to repeat stat() && S_ISCHR() checks */ 7598a529f59SJohn Baldwin ttypath = NULL; 7608a529f59SJohn Baldwin break; 7618a529f59SJohn Baldwin } 76223b8efadSGarance A Drosehn break; 76323b8efadSGarance A Drosehn } 76423b8efadSGarance A Drosehn if (ttypath) { 765a4c8a745SGarance A Drosehn if (stat(ttypath, &sb) == -1) { 7668a529f59SJohn Baldwin if (pathbuf3[0] != '\0') 7678a529f59SJohn Baldwin warn("%s, %s, and %s", pathbuf3, pathbuf2, 7688a529f59SJohn Baldwin ttypath); 769f2fbfae6SGarance A Drosehn else 770a4c8a745SGarance A Drosehn warn("%s", ttypath); 771a4c8a745SGarance A Drosehn optfatal = 1; 772c23b00b7SGarance A Drosehn return (0); 773a4c8a745SGarance A Drosehn } 774a4c8a745SGarance A Drosehn if (!S_ISCHR(sb.st_mode)) { 7758a529f59SJohn Baldwin if (pathbuf3[0] != '\0') 7768a529f59SJohn Baldwin warnx("%s, %s, and %s: Not a terminal", 7778a529f59SJohn Baldwin pathbuf3, pathbuf2, ttypath); 778f2fbfae6SGarance A Drosehn else 779f2fbfae6SGarance A Drosehn warnx("%s: Not a terminal", ttypath); 780a4c8a745SGarance A Drosehn optfatal = 1; 781c23b00b7SGarance A Drosehn return (0); 782a4c8a745SGarance A Drosehn } 78323b8efadSGarance A Drosehn } 784a4c8a745SGarance A Drosehn if (inf->count >= inf->maxcount) 785a4c8a745SGarance A Drosehn expand_list(inf); 786d822163fSGarance A Drosehn inf->l.ttys[(inf->count)++] = sb.st_rdev; 787a4c8a745SGarance A Drosehn return (1); 788a4c8a745SGarance A Drosehn } 789a4c8a745SGarance A Drosehn 790a4c8a745SGarance A Drosehn static int 791a4c8a745SGarance A Drosehn addelem_uid(struct listinfo *inf, const char *elem) 792a4c8a745SGarance A Drosehn { 793cf22dcfcSBrian Somers struct passwd *pwd; 794a4c8a745SGarance A Drosehn char *endp; 7950b42be7cSGarance A Drosehn u_long bigtemp; 796cf22dcfcSBrian Somers 797a4c8a745SGarance A Drosehn if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) { 798a4c8a745SGarance A Drosehn if (*elem == '\0') 799a4c8a745SGarance A Drosehn warnx("Invalid (zero-length) %s name", inf->lname); 800a4c8a745SGarance A Drosehn else 801a4c8a745SGarance A Drosehn warnx("%s name too long: %s", inf->lname, elem); 802a4c8a745SGarance A Drosehn optfatal = 1; 803352b6523SGarance A Drosehn return (0); /* Do not add this value. */ 804a4c8a745SGarance A Drosehn } 805cf22dcfcSBrian Somers 806a4c8a745SGarance A Drosehn pwd = getpwnam(elem); 807a4c8a745SGarance A Drosehn if (pwd == NULL) { 808a4c8a745SGarance A Drosehn errno = 0; 8090b42be7cSGarance A Drosehn bigtemp = strtoul(elem, &endp, 10); 8100b42be7cSGarance A Drosehn if (errno != 0 || *endp != '\0' || bigtemp > UID_MAX) 811a4c8a745SGarance A Drosehn warnx("No %s named '%s'", inf->lname, elem); 812a4c8a745SGarance A Drosehn else { 813a4c8a745SGarance A Drosehn /* The string is all digits, so it might be a userID. */ 8140b42be7cSGarance A Drosehn pwd = getpwuid((uid_t)bigtemp); 815a4c8a745SGarance A Drosehn if (pwd == NULL) 816a4c8a745SGarance A Drosehn warnx("No %s name or ID matches '%s'", 817a4c8a745SGarance A Drosehn inf->lname, elem); 818cf22dcfcSBrian Somers } 819cf22dcfcSBrian Somers } 820a4c8a745SGarance A Drosehn if (pwd == NULL) { 821e3c4e1ddSGarance A Drosehn /* 822e3c4e1ddSGarance A Drosehn * These used to be treated as minor warnings (and the 823e3c4e1ddSGarance A Drosehn * option was simply ignored), but now they are fatal 824e3c4e1ddSGarance A Drosehn * errors (and the command will be aborted). 825e3c4e1ddSGarance A Drosehn */ 826e3c4e1ddSGarance A Drosehn optfatal = 1; 827c23b00b7SGarance A Drosehn return (0); 828cf22dcfcSBrian Somers } 829a4c8a745SGarance A Drosehn if (inf->count >= inf->maxcount) 830a4c8a745SGarance A Drosehn expand_list(inf); 831d822163fSGarance A Drosehn inf->l.uids[(inf->count)++] = pwd->pw_uid; 832a4c8a745SGarance A Drosehn return (1); 833a4c8a745SGarance A Drosehn } 834cf22dcfcSBrian Somers 835a4c8a745SGarance A Drosehn static void 836a4c8a745SGarance A Drosehn add_list(struct listinfo *inf, const char *argp) 837a4c8a745SGarance A Drosehn { 838a4c8a745SGarance A Drosehn const char *savep; 839a4c8a745SGarance A Drosehn char *cp, *endp; 840a4c8a745SGarance A Drosehn int toolong; 841ca62e195SGarance A Drosehn char elemcopy[PATH_MAX]; 842a4c8a745SGarance A Drosehn 843de1702f4SGarance A Drosehn if (*argp == 0) 844de1702f4SGarance A Drosehn inf->addelem(inf, elemcopy); 845a4c8a745SGarance A Drosehn while (*argp != '\0') { 846a4c8a745SGarance A Drosehn while (*argp != '\0' && strchr(W_SEP, *argp) != NULL) 847a4c8a745SGarance A Drosehn argp++; 848a4c8a745SGarance A Drosehn savep = argp; 849a4c8a745SGarance A Drosehn toolong = 0; 850a4c8a745SGarance A Drosehn cp = elemcopy; 851a4c8a745SGarance A Drosehn if (strchr(T_SEP, *argp) == NULL) { 852a4c8a745SGarance A Drosehn endp = elemcopy + sizeof(elemcopy) - 1; 853a4c8a745SGarance A Drosehn while (*argp != '\0' && cp <= endp && 854a4c8a745SGarance A Drosehn strchr(W_SEP T_SEP, *argp) == NULL) 855a4c8a745SGarance A Drosehn *cp++ = *argp++; 856a4c8a745SGarance A Drosehn if (cp > endp) 857a4c8a745SGarance A Drosehn toolong = 1; 858a4c8a745SGarance A Drosehn } 859a4c8a745SGarance A Drosehn if (!toolong) { 860a4c8a745SGarance A Drosehn *cp = '\0'; 861352b6523SGarance A Drosehn /* 862a9626fb3SGarance A Drosehn * Add this single element to the given list. 863352b6523SGarance A Drosehn */ 864a4c8a745SGarance A Drosehn inf->addelem(inf, elemcopy); 865a4c8a745SGarance A Drosehn } else { 866a4c8a745SGarance A Drosehn /* 867a4c8a745SGarance A Drosehn * The string is too long to copy. Find the end 868a4c8a745SGarance A Drosehn * of the string to print out the warning message. 869a4c8a745SGarance A Drosehn */ 870a4c8a745SGarance A Drosehn while (*argp != '\0' && strchr(W_SEP T_SEP, 871a4c8a745SGarance A Drosehn *argp) == NULL) 872a4c8a745SGarance A Drosehn argp++; 873a4c8a745SGarance A Drosehn warnx("Value too long: %.*s", (int)(argp - savep), 874a4c8a745SGarance A Drosehn savep); 875a4c8a745SGarance A Drosehn optfatal = 1; 876a4c8a745SGarance A Drosehn } 877a4c8a745SGarance A Drosehn /* 878a4c8a745SGarance A Drosehn * Skip over any number of trailing whitespace characters, 879a4c8a745SGarance A Drosehn * but only one (at most) trailing element-terminating 880a4c8a745SGarance A Drosehn * character. 881a4c8a745SGarance A Drosehn */ 882a4c8a745SGarance A Drosehn while (*argp != '\0' && strchr(W_SEP, *argp) != NULL) 883a4c8a745SGarance A Drosehn argp++; 884a4c8a745SGarance A Drosehn if (*argp != '\0' && strchr(T_SEP, *argp) != NULL) { 885a4c8a745SGarance A Drosehn argp++; 886a4c8a745SGarance A Drosehn /* Catch case where string ended with a comma. */ 887a4c8a745SGarance A Drosehn if (*argp == '\0') 888a4c8a745SGarance A Drosehn inf->addelem(inf, argp); 889a4c8a745SGarance A Drosehn } 890a4c8a745SGarance A Drosehn } 891a4c8a745SGarance A Drosehn } 892a4c8a745SGarance A Drosehn 893a4c8a745SGarance A Drosehn static void * 894a4c8a745SGarance A Drosehn expand_list(struct listinfo *inf) 895a4c8a745SGarance A Drosehn { 896a4c8a745SGarance A Drosehn void *newlist; 897ca62e195SGarance A Drosehn int newmax; 898a4c8a745SGarance A Drosehn 899a4c8a745SGarance A Drosehn newmax = (inf->maxcount + 1) << 1; 900d822163fSGarance A Drosehn newlist = realloc(inf->l.ptr, newmax * inf->elemsize); 901a4c8a745SGarance A Drosehn if (newlist == NULL) { 902d822163fSGarance A Drosehn free(inf->l.ptr); 903c23b00b7SGarance A Drosehn errx(1, "realloc to %d %ss failed", newmax, inf->lname); 904a4c8a745SGarance A Drosehn } 905a4c8a745SGarance A Drosehn inf->maxcount = newmax; 906d822163fSGarance A Drosehn inf->l.ptr = newlist; 907a4c8a745SGarance A Drosehn 908a4c8a745SGarance A Drosehn return (newlist); 909a4c8a745SGarance A Drosehn } 910a4c8a745SGarance A Drosehn 911a4c8a745SGarance A Drosehn static void 912a4c8a745SGarance A Drosehn free_list(struct listinfo *inf) 913a4c8a745SGarance A Drosehn { 914a4c8a745SGarance A Drosehn 915a4c8a745SGarance A Drosehn inf->count = inf->elemsize = inf->maxcount = 0; 916d822163fSGarance A Drosehn if (inf->l.ptr != NULL) 917d822163fSGarance A Drosehn free(inf->l.ptr); 918a4c8a745SGarance A Drosehn inf->addelem = NULL; 919a4c8a745SGarance A Drosehn inf->lname = NULL; 920d822163fSGarance A Drosehn inf->l.ptr = NULL; 921a4c8a745SGarance A Drosehn } 922a4c8a745SGarance A Drosehn 923a4c8a745SGarance A Drosehn static void 924a4c8a745SGarance A Drosehn init_list(struct listinfo *inf, addelem_rtn artn, int elemsize, 925a4c8a745SGarance A Drosehn const char *lname) 926a4c8a745SGarance A Drosehn { 927a4c8a745SGarance A Drosehn 928a4c8a745SGarance A Drosehn inf->count = inf->maxcount = 0; 929a4c8a745SGarance A Drosehn inf->elemsize = elemsize; 930a4c8a745SGarance A Drosehn inf->addelem = artn; 931a4c8a745SGarance A Drosehn inf->lname = lname; 932d822163fSGarance A Drosehn inf->l.ptr = NULL; 933cf22dcfcSBrian Somers } 934cf22dcfcSBrian Somers 935fde411d5SJuli Mallett VARENT * 936fde411d5SJuli Mallett find_varentry(VAR *v) 937fde411d5SJuli Mallett { 938fde411d5SJuli Mallett struct varent *vent; 939fde411d5SJuli Mallett 940bdf8ab46SGarance A Drosehn STAILQ_FOREACH(vent, &varlist, next_ve) { 941fde411d5SJuli Mallett if (strcmp(vent->var->name, v->name) == 0) 942fde411d5SJuli Mallett return vent; 943fde411d5SJuli Mallett } 944fde411d5SJuli Mallett return NULL; 945fde411d5SJuli Mallett } 946fde411d5SJuli Mallett 9474b88c807SRodney W. Grimes static void 94846251ddeSWarner Losh scanvars(void) 9494b88c807SRodney W. Grimes { 9504b88c807SRodney W. Grimes struct varent *vent; 9514b88c807SRodney W. Grimes VAR *v; 9526a2d726bSJordan K. Hubbard 953bdf8ab46SGarance A Drosehn STAILQ_FOREACH(vent, &varlist, next_ve) { 9546a2d726bSJordan K. Hubbard v = vent->var; 9556a2d726bSJordan K. Hubbard if (v->flag & DSIZ) { 9566a2d726bSJordan K. Hubbard v->dwidth = v->width; 9576a2d726bSJordan K. Hubbard v->width = 0; 9586a2d726bSJordan K. Hubbard } 9596a2d726bSJordan K. Hubbard if (v->flag & USER) 9606a2d726bSJordan K. Hubbard needuser = 1; 9616a2d726bSJordan K. Hubbard if (v->flag & COMM) 9626a2d726bSJordan K. Hubbard needcomm = 1; 9636a2d726bSJordan K. Hubbard } 9646a2d726bSJordan K. Hubbard } 9656a2d726bSJordan K. Hubbard 9666a2d726bSJordan K. Hubbard static void 96746251ddeSWarner Losh dynsizevars(KINFO *ki) 9686a2d726bSJordan K. Hubbard { 9696a2d726bSJordan K. Hubbard struct varent *vent; 9706a2d726bSJordan K. Hubbard VAR *v; 9716a2d726bSJordan K. Hubbard int i; 9726a2d726bSJordan K. Hubbard 973bdf8ab46SGarance A Drosehn STAILQ_FOREACH(vent, &varlist, next_ve) { 9746a2d726bSJordan K. Hubbard v = vent->var; 9756a2d726bSJordan K. Hubbard if (!(v->flag & DSIZ)) 9766a2d726bSJordan K. Hubbard continue; 9776a2d726bSJordan K. Hubbard i = (v->sproc)( ki); 9786a2d726bSJordan K. Hubbard if (v->width < i) 9796a2d726bSJordan K. Hubbard v->width = i; 9806a2d726bSJordan K. Hubbard if (v->width > v->dwidth) 9816a2d726bSJordan K. Hubbard v->width = v->dwidth; 9826a2d726bSJordan K. Hubbard } 9836a2d726bSJordan K. Hubbard } 9846a2d726bSJordan K. Hubbard 9856a2d726bSJordan K. Hubbard static void 98646251ddeSWarner Losh sizevars(void) 9876a2d726bSJordan K. Hubbard { 9886a2d726bSJordan K. Hubbard struct varent *vent; 9896a2d726bSJordan K. Hubbard VAR *v; 9904b88c807SRodney W. Grimes int i; 9914b88c807SRodney W. Grimes 992bdf8ab46SGarance A Drosehn STAILQ_FOREACH(vent, &varlist, next_ve) { 9934b88c807SRodney W. Grimes v = vent->var; 99478b1878aSJuli Mallett i = strlen(vent->header); 9954b88c807SRodney W. Grimes if (v->width < i) 9964b88c807SRodney W. Grimes v->width = i; 9974b88c807SRodney W. Grimes totwidth += v->width + 1; /* +1 for space */ 9984b88c807SRodney W. Grimes } 9994b88c807SRodney W. Grimes totwidth--; 10004b88c807SRodney W. Grimes } 10014b88c807SRodney W. Grimes 1002871e8d8cSMark Murray static const char * 100346251ddeSWarner Losh fmt(char **(*fn)(kvm_t *, const struct kinfo_proc *, int), KINFO *ki, 100446251ddeSWarner Losh char *comm, int maxlen) 10054b88c807SRodney W. Grimes { 1006871e8d8cSMark Murray const char *s; 10074b88c807SRodney W. Grimes 1008871e8d8cSMark Murray s = fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen); 10094b88c807SRodney W. Grimes return (s); 10104b88c807SRodney W. Grimes } 10114b88c807SRodney W. Grimes 1012b61ce5b0SJeff Roberson #define UREADOK(ki) (forceuread || (ki->ki_p->ki_flag & P_INMEM)) 10133ac5e955SJohn Dyson 10144b88c807SRodney W. Grimes static void 101546251ddeSWarner Losh saveuser(KINFO *ki) 10164b88c807SRodney W. Grimes { 10174b88c807SRodney W. Grimes 1018b61ce5b0SJeff Roberson if (ki->ki_p->ki_flag & P_INMEM) { 10194b88c807SRodney W. Grimes /* 10204b88c807SRodney W. Grimes * The u-area might be swapped out, and we can't get 10214b88c807SRodney W. Grimes * at it because we have a crashdump and no swap. 10224b88c807SRodney W. Grimes * If it's here fill in these fields, otherwise, just 10234b88c807SRodney W. Grimes * leave them 0. 10244b88c807SRodney W. Grimes */ 10251f7d2501SKirk McKusick ki->ki_valid = 1; 10264b88c807SRodney W. Grimes } else 10271f7d2501SKirk McKusick ki->ki_valid = 0; 10284b88c807SRodney W. Grimes /* 10294b88c807SRodney W. Grimes * save arguments if needed 10304b88c807SRodney W. Grimes */ 1031dd693acfSGarance A Drosehn if (needcomm) { 1032dd693acfSGarance A Drosehn if (ki->ki_p->ki_stat == SZOMB) 1033dd693acfSGarance A Drosehn ki->ki_args = strdup("<defunct>"); 1034dd693acfSGarance A Drosehn else if (UREADOK(ki) || (ki->ki_p->ki_args != NULL)) 1035dd693acfSGarance A Drosehn ki->ki_args = strdup(fmt(kvm_getargv, ki, 1036dd693acfSGarance A Drosehn ki->ki_p->ki_comm, MAXCOMLEN)); 1037dd693acfSGarance A Drosehn else 1038871e8d8cSMark Murray asprintf(&ki->ki_args, "(%s)", ki->ki_p->ki_comm); 1039bd6233fdSGarance A Drosehn if (ki->ki_args == NULL) 1040dd693acfSGarance A Drosehn errx(1, "malloc failed"); 10413ac5e955SJohn Dyson } else { 10424b88c807SRodney W. Grimes ki->ki_args = NULL; 10433ac5e955SJohn Dyson } 1044dd693acfSGarance A Drosehn if (needenv) { 1045dd693acfSGarance A Drosehn if (UREADOK(ki)) 1046dd693acfSGarance A Drosehn ki->ki_env = strdup(fmt(kvm_getenvv, ki, 1047dd693acfSGarance A Drosehn (char *)NULL, 0)); 1048dd693acfSGarance A Drosehn else 1049dd693acfSGarance A Drosehn ki->ki_env = strdup("()"); 1050dd693acfSGarance A Drosehn if (ki->ki_env == NULL) 1051dd693acfSGarance A Drosehn errx(1, "malloc failed"); 10523ac5e955SJohn Dyson } else { 10534b88c807SRodney W. Grimes ki->ki_env = NULL; 10544b88c807SRodney W. Grimes } 10553ac5e955SJohn Dyson } 10564b88c807SRodney W. Grimes 10574bac4483SGarance A Drosehn /* A macro used to improve the readability of pscomp(). */ 10584bac4483SGarance A Drosehn #define DIFF_RETURN(a, b, field) do { \ 10594bac4483SGarance A Drosehn if ((a)->field != (b)->field) \ 10604bac4483SGarance A Drosehn return (((a)->field < (b)->field) ? -1 : 1); \ 10614bac4483SGarance A Drosehn } while (0) 10624bac4483SGarance A Drosehn 10634b88c807SRodney W. Grimes static int 106446251ddeSWarner Losh pscomp(const void *a, const void *b) 10654b88c807SRodney W. Grimes { 10665bd7b1f3SGarance A Drosehn const KINFO *ka, *kb; 10674b88c807SRodney W. Grimes 10685bd7b1f3SGarance A Drosehn ka = a; 10695bd7b1f3SGarance A Drosehn kb = b; 10705bd7b1f3SGarance A Drosehn /* SORTCPU and SORTMEM are sorted in descending order. */ 10714bac4483SGarance A Drosehn if (sortby == SORTCPU) 10724bac4483SGarance A Drosehn DIFF_RETURN(kb, ka, ki_pcpu); 10734bac4483SGarance A Drosehn if (sortby == SORTMEM) 10744bac4483SGarance A Drosehn DIFF_RETURN(kb, ka, ki_memsize); 10755bd7b1f3SGarance A Drosehn /* 10765bd7b1f3SGarance A Drosehn * TTY's are sorted in ascending order, except that all NODEV 10775bd7b1f3SGarance A Drosehn * processes come before all processes with a device. 10785bd7b1f3SGarance A Drosehn */ 10794bac4483SGarance A Drosehn if (ka->ki_p->ki_tdev != kb->ki_p->ki_tdev) { 10804bac4483SGarance A Drosehn if (ka->ki_p->ki_tdev == NODEV) 10815bd7b1f3SGarance A Drosehn return (-1); 10824bac4483SGarance A Drosehn if (kb->ki_p->ki_tdev == NODEV) 10835bd7b1f3SGarance A Drosehn return (1); 10844bac4483SGarance A Drosehn DIFF_RETURN(ka, kb, ki_p->ki_tdev); 10854bac4483SGarance A Drosehn } 10864bac4483SGarance A Drosehn 1087b4b24324SGarance A Drosehn /* PID's and TID's (threads) are sorted in ascending order. */ 10884bac4483SGarance A Drosehn DIFF_RETURN(ka, kb, ki_p->ki_pid); 1089b4b24324SGarance A Drosehn DIFF_RETURN(ka, kb, ki_p->ki_tid); 10905bd7b1f3SGarance A Drosehn return (0); 10914b88c807SRodney W. Grimes } 10924bac4483SGarance A Drosehn #undef DIFF_RETURN 10934b88c807SRodney W. Grimes 10944b88c807SRodney W. Grimes /* 10954b88c807SRodney W. Grimes * ICK (all for getopt), would rather hide the ugliness 10964b88c807SRodney W. Grimes * here than taint the main code. 10974b88c807SRodney W. Grimes * 10984b88c807SRodney W. Grimes * ps foo -> ps -foo 10994b88c807SRodney W. Grimes * ps 34 -> ps -p34 11004b88c807SRodney W. Grimes * 11014b88c807SRodney W. Grimes * The old convention that 't' with no trailing tty arg means the users 11024b88c807SRodney W. Grimes * tty, is only supported if argv[1] doesn't begin with a '-'. This same 11034b88c807SRodney W. Grimes * feature is available with the option 'T', which takes no argument. 11044b88c807SRodney W. Grimes */ 11054b88c807SRodney W. Grimes static char * 1106bf46a3bfSGarance A Drosehn kludge_oldps_options(const char *optlist, char *origval, const char *nextarg) 11074b88c807SRodney W. Grimes { 11084b88c807SRodney W. Grimes size_t len; 1109c675340aSGarance A Drosehn char *argp, *cp, *newopts, *ns, *optp, *pidp; 11104b88c807SRodney W. Grimes 1111daed3ad6SJuli Mallett /* 1112c675340aSGarance A Drosehn * See if the original value includes any option which takes an 1113c675340aSGarance A Drosehn * argument (and will thus use up the remainder of the string). 1114daed3ad6SJuli Mallett */ 1115c675340aSGarance A Drosehn argp = NULL; 1116c675340aSGarance A Drosehn if (optlist != NULL) { 1117c675340aSGarance A Drosehn for (cp = origval; *cp != '\0'; cp++) { 1118c675340aSGarance A Drosehn optp = strchr(optlist, *cp); 1119c675340aSGarance A Drosehn if ((optp != NULL) && *(optp + 1) == ':') { 1120c675340aSGarance A Drosehn argp = cp; 1121c675340aSGarance A Drosehn break; 1122c675340aSGarance A Drosehn } 1123c675340aSGarance A Drosehn } 1124c675340aSGarance A Drosehn } 1125c675340aSGarance A Drosehn if (argp != NULL && *origval == '-') 1126c675340aSGarance A Drosehn return (origval); 1127daed3ad6SJuli Mallett 11284b88c807SRodney W. Grimes /* 11294b88c807SRodney W. Grimes * if last letter is a 't' flag with no argument (in the context 11304b88c807SRodney W. Grimes * of the oldps options -- option string NOT starting with a '-' -- 11314b88c807SRodney W. Grimes * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). 1132380434d4SBrian Somers * 11332631c777SGarance A Drosehn * However, if a flag accepting a string argument is found earlier 11342631c777SGarance A Drosehn * in the option string (including a possible `t' flag), then the 11352631c777SGarance A Drosehn * remainder of the string must be the argument to that flag; so 1136c675340aSGarance A Drosehn * do not modify that argument. Note that a trailing `t' would 1137c675340aSGarance A Drosehn * cause argp to be set, if argp was not already set by some 1138c675340aSGarance A Drosehn * earlier option. 11394b88c807SRodney W. Grimes */ 1140c675340aSGarance A Drosehn len = strlen(origval); 1141c675340aSGarance A Drosehn cp = origval + len - 1; 1142c675340aSGarance A Drosehn pidp = NULL; 1143bf46a3bfSGarance A Drosehn if (*cp == 't' && *origval != '-' && cp == argp) { 1144bf46a3bfSGarance A Drosehn if (nextarg == NULL || *nextarg == '-' || isdigitch(*nextarg)) 11454b88c807SRodney W. Grimes *cp = 'T'; 1146bf46a3bfSGarance A Drosehn } else if (argp == NULL) { 1147c675340aSGarance A Drosehn /* 1148c675340aSGarance A Drosehn * The original value did not include any option which takes 1149c675340aSGarance A Drosehn * an argument (and that would include `p' and `t'), so check 1150c675340aSGarance A Drosehn * the value for trailing number, or comma-separated list of 1151c675340aSGarance A Drosehn * numbers, which we will treat as a pid request. 1152c675340aSGarance A Drosehn */ 1153c675340aSGarance A Drosehn if (isdigitch(*cp)) { 1154c675340aSGarance A Drosehn while (cp >= origval && (*cp == ',' || isdigitch(*cp))) 1155c675340aSGarance A Drosehn --cp; 1156c675340aSGarance A Drosehn pidp = cp + 1; 1157c675340aSGarance A Drosehn } 1158c675340aSGarance A Drosehn } 1159c675340aSGarance A Drosehn 1160c675340aSGarance A Drosehn /* 1161c675340aSGarance A Drosehn * If nothing needs to be added to the string, then return 1162c675340aSGarance A Drosehn * the "original" (although possibly modified) value. 1163c675340aSGarance A Drosehn */ 1164c675340aSGarance A Drosehn if (*origval == '-' && pidp == NULL) 1165c675340aSGarance A Drosehn return (origval); 1166c675340aSGarance A Drosehn 1167c675340aSGarance A Drosehn /* 1168c675340aSGarance A Drosehn * Create a copy of the string to add '-' and/or 'p' to the 1169c675340aSGarance A Drosehn * original value. 1170c675340aSGarance A Drosehn */ 1171c675340aSGarance A Drosehn if ((newopts = ns = malloc(len + 3)) == NULL) 1172c675340aSGarance A Drosehn errx(1, "malloc failed"); 1173c675340aSGarance A Drosehn 1174c675340aSGarance A Drosehn if (*origval != '-') 1175c675340aSGarance A Drosehn *ns++ = '-'; /* add option flag */ 1176c675340aSGarance A Drosehn 1177c675340aSGarance A Drosehn if (pidp == NULL) 1178c675340aSGarance A Drosehn strcpy(ns, origval); 11794b88c807SRodney W. Grimes else { 11804b88c807SRodney W. Grimes /* 1181c675340aSGarance A Drosehn * Copy everything before the pid string, add the `p', 1182c675340aSGarance A Drosehn * and then copy the pid string. 11834b88c807SRodney W. Grimes */ 1184c675340aSGarance A Drosehn len = pidp - origval; 1185c675340aSGarance A Drosehn memcpy(ns, origval, len); 1186c675340aSGarance A Drosehn ns += len; 11874b88c807SRodney W. Grimes *ns++ = 'p'; 1188c675340aSGarance A Drosehn strcpy(ns, pidp); 1189c675340aSGarance A Drosehn } 11904b88c807SRodney W. Grimes 11914b88c807SRodney W. Grimes return (newopts); 11924b88c807SRodney W. Grimes } 11934b88c807SRodney W. Grimes 1194a951d1f8SChristian S.J. Peron static int 1195a951d1f8SChristian S.J. Peron check_procfs(void) 1196a951d1f8SChristian S.J. Peron { 1197d8654c64SChristian S.J. Peron struct statfs mnt; 1198a951d1f8SChristian S.J. Peron 1199d8654c64SChristian S.J. Peron if (statfs("/proc", &mnt) < 0) 1200a951d1f8SChristian S.J. Peron return (0); 1201d8654c64SChristian S.J. Peron if (strcmp(mnt.f_fstypename, "procfs") != 0) 1202d8654c64SChristian S.J. Peron return (0); 1203d8654c64SChristian S.J. Peron return (1); 1204a951d1f8SChristian S.J. Peron } 1205a951d1f8SChristian S.J. Peron 12064b88c807SRodney W. Grimes static void 120746251ddeSWarner Losh usage(void) 12084b88c807SRodney W. Grimes { 1209a89237aeSRuslan Ermilov #define SINGLE_OPTS "[-aCce" OPT_LAZY_f "HhjlmrSTuvwXxZ]" 12104b88c807SRodney W. Grimes 1211a4c8a745SGarance A Drosehn (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", 1212a89237aeSRuslan Ermilov "usage: ps " SINGLE_OPTS " [-O fmt | -o fmt] [-G gid[,gid...]]", 1213a4c8a745SGarance A Drosehn " [-M core] [-N system]", 1214a89237aeSRuslan Ermilov " [-p pid[,pid...]] [-t tty[,tty...]] [-U user[,user...]]", 12154b88c807SRodney W. Grimes " ps [-L]"); 12164b88c807SRodney W. Grimes exit(1); 12174b88c807SRodney W. Grimes } 1218