Home | History | Annotate | Line # | Download | only in ps
ps.c revision 1.27
      1  1.27  bgrayson /*	$NetBSD: ps.c,v 1.27 1999/03/26 22:36:02 bgrayson Exp $	*/
      2  1.13       cgd 
      3   1.1       cgd /*-
      4  1.11       cgd  * Copyright (c) 1990, 1993, 1994
      5  1.11       cgd  *	The Regents of the University of California.  All rights reserved.
      6   1.1       cgd  *
      7   1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8   1.1       cgd  * modification, are permitted provided that the following conditions
      9   1.1       cgd  * are met:
     10   1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11   1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12   1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14   1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15   1.1       cgd  * 3. All advertising materials mentioning features or use of this software
     16   1.1       cgd  *    must display the following acknowledgement:
     17   1.1       cgd  *	This product includes software developed by the University of
     18   1.1       cgd  *	California, Berkeley and its contributors.
     19   1.1       cgd  * 4. Neither the name of the University nor the names of its contributors
     20   1.1       cgd  *    may be used to endorse or promote products derived from this software
     21   1.1       cgd  *    without specific prior written permission.
     22   1.1       cgd  *
     23   1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24   1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25   1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26   1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27   1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28   1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29   1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30   1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31   1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32   1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33   1.1       cgd  * SUCH DAMAGE.
     34   1.1       cgd  */
     35   1.1       cgd 
     36  1.19  christos #include <sys/cdefs.h>
     37   1.1       cgd #ifndef lint
     38  1.19  christos __COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\n\
     39  1.19  christos 	The Regents of the University of California.  All rights reserved.\n");
     40   1.1       cgd #endif /* not lint */
     41   1.1       cgd 
     42   1.1       cgd #ifndef lint
     43  1.13       cgd #if 0
     44  1.11       cgd static char sccsid[] = "@(#)ps.c	8.4 (Berkeley) 4/2/94";
     45  1.13       cgd #else
     46  1.27  bgrayson __RCSID("$NetBSD: ps.c,v 1.27 1999/03/26 22:36:02 bgrayson Exp $");
     47  1.13       cgd #endif
     48   1.1       cgd #endif /* not lint */
     49   1.1       cgd 
     50   1.1       cgd #include <sys/param.h>
     51   1.1       cgd #include <sys/user.h>
     52   1.1       cgd #include <sys/time.h>
     53   1.1       cgd #include <sys/resource.h>
     54   1.1       cgd #include <sys/proc.h>
     55   1.1       cgd #include <sys/stat.h>
     56   1.1       cgd #include <sys/ioctl.h>
     57  1.11       cgd #include <sys/sysctl.h>
     58  1.11       cgd 
     59  1.11       cgd #include <ctype.h>
     60  1.11       cgd #include <err.h>
     61  1.11       cgd #include <errno.h>
     62  1.11       cgd #include <fcntl.h>
     63  1.11       cgd #include <kvm.h>
     64  1.17        pk #include <limits.h>
     65   1.1       cgd #include <nlist.h>
     66  1.11       cgd #include <paths.h>
     67  1.25   mycroft #include <pwd.h>
     68   1.1       cgd #include <stdio.h>
     69   1.1       cgd #include <stdlib.h>
     70   1.1       cgd #include <string.h>
     71  1.11       cgd #include <unistd.h>
     72  1.11       cgd 
     73   1.1       cgd #include "ps.h"
     74   1.1       cgd 
     75  1.10       cgd #ifdef P_PPWAIT
     76   1.1       cgd #define NEWVM
     77   1.1       cgd #endif
     78   1.1       cgd 
     79   1.1       cgd KINFO *kinfo;
     80   1.1       cgd struct varent *vhead, *vtail;
     81   1.1       cgd 
     82   1.1       cgd int	eval;			/* exit value */
     83   1.1       cgd int	rawcpu;			/* -C */
     84   1.1       cgd int	sumrusage;		/* -S */
     85   1.1       cgd int	termwidth;		/* width of screen (0 == infinity) */
     86   1.1       cgd int	totwidth;		/* calculated width of requested variables */
     87   1.1       cgd 
     88  1.15   mycroft int	needuser, needcomm, needenv, commandonly;
     89   1.1       cgd 
     90   1.1       cgd enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT;
     91   1.1       cgd 
     92  1.11       cgd static char	*kludge_oldps_options __P((char *));
     93  1.11       cgd static int	 pscomp __P((const void *, const void *));
     94  1.11       cgd static void	 saveuser __P((KINFO *));
     95  1.11       cgd static void	 scanvars __P((void));
     96  1.11       cgd static void	 usage __P((void));
     97  1.19  christos int		 main __P((int, char *[]));
     98   1.1       cgd 
     99   1.1       cgd char dfmt[] = "pid tt state time command";
    100   1.1       cgd char jfmt[] = "user pid ppid pgid sess jobc state tt time command";
    101   1.1       cgd char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command";
    102   1.1       cgd char   o1[] = "pid";
    103   1.1       cgd char   o2[] = "tt state time command";
    104   1.1       cgd char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command";
    105  1.11       cgd char vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command";
    106  1.11       cgd 
    107  1.11       cgd kvm_t *kd;
    108   1.1       cgd 
    109  1.11       cgd int
    110   1.1       cgd main(argc, argv)
    111   1.1       cgd 	int argc;
    112  1.11       cgd 	char *argv[];
    113   1.1       cgd {
    114  1.11       cgd 	struct kinfo_proc *kp;
    115  1.11       cgd 	struct varent *vent;
    116   1.1       cgd 	struct winsize ws;
    117  1.21       mrg 	gid_t egid = getegid();
    118  1.25   mycroft 	int ch, flag, i, fmt, lineno, nentries;
    119  1.11       cgd 	int prtheader, wflag, what, xflg;
    120  1.17        pk 	char *nlistf, *memf, *swapf, errbuf[_POSIX2_LINE_MAX];
    121  1.26       kim 	char *ttname;
    122   1.1       cgd 
    123  1.21       mrg 	(void)setegid(getgid());
    124   1.1       cgd 	if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
    125   1.1       cgd 	     ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
    126   1.1       cgd 	     ioctl(STDIN_FILENO,  TIOCGWINSZ, (char *)&ws) == -1) ||
    127   1.1       cgd 	     ws.ws_col == 0)
    128   1.1       cgd 		termwidth = 79;
    129   1.1       cgd 	else
    130   1.1       cgd 		termwidth = ws.ws_col - 1;
    131   1.1       cgd 
    132   1.1       cgd 	if (argc > 1)
    133   1.1       cgd 		argv[1] = kludge_oldps_options(argv[1]);
    134   1.1       cgd 
    135  1.25   mycroft 	fmt = prtheader = wflag = xflg = 0;
    136  1.25   mycroft 	what = KERN_PROC_UID;
    137  1.25   mycroft 	flag = getuid();
    138   1.1       cgd 	memf = nlistf = swapf = NULL;
    139   1.1       cgd 	while ((ch = getopt(argc, argv,
    140  1.25   mycroft 	    "acCeghjLlM:mN:O:o:p:rSTt:U:uvW:wx")) != -1)
    141   1.1       cgd 		switch((char)ch) {
    142   1.1       cgd 		case 'a':
    143  1.25   mycroft 			what = KERN_PROC_ALL;
    144  1.25   mycroft 			flag = 0;
    145   1.1       cgd 			break;
    146  1.12   mycroft 		case 'c':
    147  1.12   mycroft 			commandonly = 1;
    148  1.12   mycroft 			break;
    149  1.11       cgd 		case 'e':			/* XXX set ufmt */
    150  1.11       cgd 			needenv = 1;
    151  1.11       cgd 			break;
    152   1.1       cgd 		case 'C':
    153   1.1       cgd 			rawcpu = 1;
    154   1.1       cgd 			break;
    155   1.1       cgd 		case 'g':
    156  1.11       cgd 			break;			/* no-op */
    157   1.1       cgd 		case 'h':
    158   1.1       cgd 			prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
    159   1.1       cgd 			break;
    160   1.1       cgd 		case 'j':
    161   1.1       cgd 			parsefmt(jfmt);
    162  1.15   mycroft 			fmt = 1;
    163   1.1       cgd 			jfmt[0] = '\0';
    164   1.1       cgd 			break;
    165  1.11       cgd 		case 'L':
    166   1.1       cgd 			showkey();
    167   1.1       cgd 			exit(0);
    168  1.23   mycroft 			/* NOTREACHED */
    169   1.1       cgd 		case 'l':
    170   1.1       cgd 			parsefmt(lfmt);
    171  1.15   mycroft 			fmt = 1;
    172   1.1       cgd 			lfmt[0] = '\0';
    173   1.1       cgd 			break;
    174   1.1       cgd 		case 'M':
    175   1.1       cgd 			memf = optarg;
    176   1.1       cgd 			break;
    177   1.1       cgd 		case 'm':
    178   1.1       cgd 			sortby = SORTMEM;
    179   1.1       cgd 			break;
    180   1.1       cgd 		case 'N':
    181   1.1       cgd 			nlistf = optarg;
    182   1.1       cgd 			break;
    183   1.1       cgd 		case 'O':
    184   1.1       cgd 			parsefmt(o1);
    185   1.1       cgd 			parsefmt(optarg);
    186   1.1       cgd 			parsefmt(o2);
    187   1.1       cgd 			o1[0] = o2[0] = '\0';
    188  1.15   mycroft 			fmt = 1;
    189   1.1       cgd 			break;
    190   1.1       cgd 		case 'o':
    191   1.1       cgd 			parsefmt(optarg);
    192  1.15   mycroft 			fmt = 1;
    193   1.1       cgd 			break;
    194   1.1       cgd 		case 'p':
    195  1.25   mycroft 			what = KERN_PROC_PID;
    196  1.25   mycroft 			flag = atol(optarg);
    197   1.1       cgd 			xflg = 1;
    198   1.1       cgd 			break;
    199   1.1       cgd 		case 'r':
    200   1.1       cgd 			sortby = SORTCPU;
    201   1.1       cgd 			break;
    202   1.1       cgd 		case 'S':
    203   1.1       cgd 			sumrusage = 1;
    204   1.1       cgd 			break;
    205   1.1       cgd 		case 'T':
    206  1.22   mycroft 			if ((ttname = ttyname(STDIN_FILENO)) == NULL)
    207  1.11       cgd 				errx(1, "stdin: not a terminal");
    208  1.22   mycroft 			goto tty;
    209  1.22   mycroft 		case 't':
    210  1.22   mycroft 			ttname = optarg;
    211  1.22   mycroft 		tty: {
    212  1.11       cgd 			struct stat sb;
    213  1.11       cgd 			char *ttypath, pathbuf[MAXPATHLEN];
    214   1.1       cgd 
    215  1.26       kim 			if (strcmp(ttname, "co") == 0)
    216   1.1       cgd 				ttypath = _PATH_CONSOLE;
    217  1.26       kim 			else if (*ttname != '/')
    218  1.11       cgd 				(void)snprintf(ttypath = pathbuf,
    219  1.26       kim 				    sizeof(pathbuf), "%s%s", _PATH_TTY, ttname);
    220   1.1       cgd 			else
    221  1.26       kim 				ttypath = ttname;
    222  1.11       cgd 			if (stat(ttypath, &sb) == -1)
    223  1.11       cgd 				err(1, "%s", ttypath);
    224  1.11       cgd 			if (!S_ISCHR(sb.st_mode))
    225  1.11       cgd 				errx(1, "%s: not a terminal", ttypath);
    226  1.25   mycroft 			what = KERN_PROC_TTY;
    227  1.25   mycroft 			flag = sb.st_rdev;
    228   1.1       cgd 			break;
    229   1.1       cgd 		}
    230  1.25   mycroft 		case 'U':
    231  1.25   mycroft 			if (*optarg != '\0') {
    232  1.25   mycroft 				struct passwd *pw;
    233  1.25   mycroft 				char *ep;
    234  1.25   mycroft 
    235  1.25   mycroft 				what = KERN_PROC_UID;
    236  1.25   mycroft 				pw = getpwnam(optarg);
    237  1.25   mycroft 				if (pw == NULL) {
    238  1.25   mycroft 					errno = 0;
    239  1.25   mycroft 					flag = strtoul(optarg, &ep, 10);
    240  1.25   mycroft 					if (errno)
    241  1.25   mycroft 						err(1, "%s", optarg);
    242  1.25   mycroft 					if (*ep != '\0')
    243  1.25   mycroft 						errx(1, "%s: illegal user name",
    244  1.25   mycroft 						    optarg);
    245  1.25   mycroft 				} else
    246  1.25   mycroft 					flag = pw->pw_uid;
    247  1.25   mycroft 			}
    248  1.25   mycroft 			break;
    249   1.1       cgd 		case 'u':
    250   1.1       cgd 			parsefmt(ufmt);
    251   1.1       cgd 			sortby = SORTCPU;
    252  1.15   mycroft 			fmt = 1;
    253   1.1       cgd 			ufmt[0] = '\0';
    254   1.1       cgd 			break;
    255   1.1       cgd 		case 'v':
    256   1.1       cgd 			parsefmt(vfmt);
    257   1.1       cgd 			sortby = SORTMEM;
    258  1.15   mycroft 			fmt = 1;
    259   1.1       cgd 			vfmt[0] = '\0';
    260   1.1       cgd 			break;
    261   1.1       cgd 		case 'W':
    262   1.1       cgd 			swapf = optarg;
    263   1.1       cgd 			break;
    264   1.1       cgd 		case 'w':
    265   1.6       cgd 			if (wflag)
    266   1.6       cgd 				termwidth = UNLIMITED;
    267   1.6       cgd 			else if (termwidth < 131)
    268   1.1       cgd 				termwidth = 131;
    269  1.11       cgd 			wflag++;
    270   1.1       cgd 			break;
    271   1.1       cgd 		case 'x':
    272   1.1       cgd 			xflg = 1;
    273   1.1       cgd 			break;
    274   1.1       cgd 		case '?':
    275   1.1       cgd 		default:
    276   1.1       cgd 			usage();
    277   1.1       cgd 		}
    278   1.1       cgd 	argc -= optind;
    279   1.1       cgd 	argv += optind;
    280   1.1       cgd 
    281   1.1       cgd #define	BACKWARD_COMPATIBILITY
    282   1.1       cgd #ifdef	BACKWARD_COMPATIBILITY
    283   1.1       cgd 	if (*argv) {
    284   1.1       cgd 		nlistf = *argv;
    285   1.1       cgd 		if (*++argv) {
    286   1.1       cgd 			memf = *argv;
    287   1.1       cgd 			if (*++argv)
    288   1.1       cgd 				swapf = *argv;
    289   1.1       cgd 		}
    290   1.1       cgd 	}
    291   1.1       cgd #endif
    292  1.11       cgd 	/*
    293  1.21       mrg 	 * Discard setgid privileges.  If not the running kernel, we toss
    294  1.21       mrg 	 * them away totally so that bad guys can't print interesting stuff
    295  1.21       mrg 	 * from kernel memory, otherwise switch back to kmem for the
    296  1.21       mrg 	 * duration of the kvm_openfiles() call.
    297  1.11       cgd 	 */
    298  1.11       cgd 	if (nlistf != NULL || memf != NULL || swapf != NULL)
    299  1.21       mrg 		(void)setgid(getgid());
    300  1.21       mrg 	else
    301  1.21       mrg 		(void)setegid(egid);
    302  1.11       cgd 
    303  1.11       cgd 	kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf);
    304  1.11       cgd 	if (kd == 0)
    305  1.11       cgd 		errx(1, "%s", errbuf);
    306  1.21       mrg 
    307  1.21       mrg 	if (nlistf == NULL && memf == NULL && swapf == NULL)
    308  1.21       mrg 		(void)setgid(getgid());
    309   1.1       cgd 
    310  1.15   mycroft 	if (!fmt)
    311   1.1       cgd 		parsefmt(dfmt);
    312   1.1       cgd 
    313   1.1       cgd 	/*
    314   1.1       cgd 	 * scan requested variables, noting what structures are needed,
    315   1.1       cgd 	 * and adjusting header widths as appropiate.
    316   1.1       cgd 	 */
    317   1.1       cgd 	scanvars();
    318   1.1       cgd 	/*
    319   1.1       cgd 	 * select procs
    320   1.1       cgd 	 */
    321  1.11       cgd 	if ((kp = kvm_getprocs(kd, what, flag, &nentries)) == 0)
    322  1.27  bgrayson 	{
    323  1.27  bgrayson 	  	/*  sysctl() ought to provide some sort of
    324  1.27  bgrayson 		 *  always-working-but-minimal-functionality
    325  1.27  bgrayson 		 *  method of providing at least some of the
    326  1.27  bgrayson 		 *  process information.  Unfortunately, such a
    327  1.27  bgrayson 		 *  change will require too much work to be put
    328  1.27  bgrayson 		 *  into 1.4.  For now, enable this experimental
    329  1.27  bgrayson 		 *  /proc-based support instead (if /proc is
    330  1.27  bgrayson 		 *  mounted) to grab as much information as we can.
    331  1.27  bgrayson 		 *  The guts of emulating kvm_getprocs() is in
    332  1.27  bgrayson 		 *  the file procfs_ops.c.  */
    333  1.27  bgrayson 		warnx("%s.\n    %s", kvm_geterr(kd),
    334  1.27  bgrayson 		    "Attempting experimental, insecure /proc-based method.");
    335  1.27  bgrayson 		/*  procfs_getprocs supports all but the
    336  1.27  bgrayson 		 *  KERN_PROC_RUID flag.  */
    337  1.27  bgrayson 		kp=procfs_getprocs(what, flag, &nentries);
    338  1.27  bgrayson 		if (kp == 0) {
    339  1.27  bgrayson 		  errx(1, "/proc-based lookup also failed.  Giving up...");
    340  1.27  bgrayson 		}
    341  1.27  bgrayson 		/*  An intruder could have put an ordinary filesystem
    342  1.27  bgrayson 		 *  on /proc, and keep updating it to make
    343  1.27  bgrayson 		 *  it look like it's the real /proc, when in
    344  1.27  bgrayson 		 *  reality they are hiding information about
    345  1.27  bgrayson 		 *  some trojan processes that are running.
    346  1.27  bgrayson 		 *  Should we walk the mounted-filesystems table
    347  1.27  bgrayson 		 *  to figure out whether /proc is mounted with
    348  1.27  bgrayson 		 *  nothing mounted on top of it?  For now, just
    349  1.27  bgrayson 		 *  print a verbose warning.  XXX  bgrayson  */
    350  1.27  bgrayson 		fprintf(stderr, "%s%s%s%s%s%s%s%s%s",
    351  1.27  bgrayson 		    "*****************************************\n",
    352  1.27  bgrayson 		    "Warning:  /proc does not provide sufficient ",
    353  1.27  bgrayson 		    "information to provide\n",
    354  1.27  bgrayson 		    "valid data for all fields.\n",
    355  1.27  bgrayson 		    "1.  Several fields (like ",
    356  1.27  bgrayson 		    "STAT and TIME) will be incorrect.\n",
    357  1.27  bgrayson 		    "2.  If your system may be compromised, ",
    358  1.27  bgrayson 		    "verify that /proc is secure\n",
    359  1.27  bgrayson 		    "    before trusting these results.\n");
    360  1.27  bgrayson 	}
    361  1.11       cgd 	if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL)
    362  1.19  christos 		err(1, "%s", "");
    363  1.11       cgd 	for (i = nentries; --i >= 0; ++kp) {
    364  1.11       cgd 		kinfo[i].ki_p = kp;
    365  1.11       cgd 		if (needuser)
    366  1.11       cgd 			saveuser(&kinfo[i]);
    367   1.1       cgd 	}
    368   1.1       cgd 	/*
    369   1.1       cgd 	 * print header
    370   1.1       cgd 	 */
    371   1.1       cgd 	printheader();
    372  1.24   mycroft 	if (nentries == 0)
    373   1.1       cgd 		exit(0);
    374   1.1       cgd 	/*
    375   1.1       cgd 	 * sort proc list
    376   1.1       cgd 	 */
    377  1.11       cgd 	qsort(kinfo, nentries, sizeof(KINFO), pscomp);
    378   1.1       cgd 	/*
    379   1.1       cgd 	 * for each proc, call each variable output function.
    380   1.1       cgd 	 */
    381   1.1       cgd 	for (i = lineno = 0; i < nentries; i++) {
    382  1.14   mycroft 		KINFO *ki = &kinfo[i];
    383  1.14   mycroft 
    384  1.14   mycroft 		if (xflg == 0 && (KI_EPROC(ki)->e_tdev == NODEV ||
    385  1.14   mycroft 		    (KI_PROC(ki)->p_flag & P_CONTROLT ) == 0))
    386   1.1       cgd 			continue;
    387   1.1       cgd 		for (vent = vhead; vent; vent = vent->next) {
    388  1.14   mycroft 			(vent->var->oproc)(ki, vent);
    389   1.1       cgd 			if (vent->next != NULL)
    390  1.11       cgd 				(void)putchar(' ');
    391   1.1       cgd 		}
    392  1.11       cgd 		(void)putchar('\n');
    393  1.11       cgd 		if (prtheader && lineno++ == prtheader - 4) {
    394  1.11       cgd 			(void)putchar('\n');
    395   1.1       cgd 			printheader();
    396   1.1       cgd 			lineno = 0;
    397   1.1       cgd 		}
    398   1.1       cgd 	}
    399   1.1       cgd 	exit(eval);
    400  1.23   mycroft 	/* NOTREACHED */
    401   1.1       cgd }
    402   1.1       cgd 
    403  1.11       cgd static void
    404   1.1       cgd scanvars()
    405   1.1       cgd {
    406  1.11       cgd 	struct varent *vent;
    407  1.11       cgd 	VAR *v;
    408  1.11       cgd 	int i;
    409   1.1       cgd 
    410   1.1       cgd 	for (vent = vhead; vent; vent = vent->next) {
    411   1.1       cgd 		v = vent->var;
    412   1.1       cgd 		i = strlen(v->header);
    413   1.1       cgd 		if (v->width < i)
    414   1.1       cgd 			v->width = i;
    415   1.1       cgd 		totwidth += v->width + 1;	/* +1 for space */
    416   1.1       cgd 		if (v->flag & USER)
    417   1.1       cgd 			needuser = 1;
    418   1.1       cgd 		if (v->flag & COMM)
    419   1.1       cgd 			needcomm = 1;
    420   1.1       cgd 	}
    421   1.1       cgd 	totwidth--;
    422  1.11       cgd }
    423   1.1       cgd 
    424  1.11       cgd static void
    425   1.1       cgd saveuser(ki)
    426   1.1       cgd 	KINFO *ki;
    427   1.1       cgd {
    428  1.11       cgd 	struct pstats pstats;
    429  1.11       cgd 	struct usave *usp;
    430   1.5       cgd 
    431  1.11       cgd 	usp = &ki->ki_u;
    432  1.11       cgd 	if (kvm_read(kd, (u_long)&KI_PROC(ki)->p_addr->u_stats,
    433  1.11       cgd 	    (char *)&pstats, sizeof(pstats)) == sizeof(pstats)) {
    434   1.1       cgd 		/*
    435  1.11       cgd 		 * The u-area might be swapped out, and we can't get
    436  1.11       cgd 		 * at it because we have a crashdump and no swap.
    437  1.11       cgd 		 * If it's here fill in these fields, otherwise, just
    438  1.11       cgd 		 * leave them 0.
    439   1.1       cgd 		 */
    440  1.11       cgd 		usp->u_start = pstats.p_start;
    441  1.11       cgd 		usp->u_ru = pstats.p_ru;
    442  1.11       cgd 		usp->u_cru = pstats.p_cru;
    443  1.11       cgd 		usp->u_valid = 1;
    444   1.1       cgd 	} else
    445  1.11       cgd 		usp->u_valid = 0;
    446   1.1       cgd }
    447   1.1       cgd 
    448  1.11       cgd static int
    449  1.11       cgd pscomp(a, b)
    450  1.11       cgd 	const void *a, *b;
    451   1.1       cgd {
    452   1.1       cgd 	int i;
    453   1.1       cgd #ifdef NEWVM
    454  1.11       cgd #define VSIZE(k) (KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize + \
    455  1.11       cgd 		  KI_EPROC(k)->e_vm.vm_tsize)
    456   1.1       cgd #else
    457   1.1       cgd #define VSIZE(k) ((k)->ki_p->p_dsize + (k)->ki_p->p_ssize + (k)->ki_e->e_xsize)
    458   1.1       cgd #endif
    459   1.1       cgd 
    460   1.1       cgd 	if (sortby == SORTCPU)
    461  1.11       cgd 		return (getpcpu((KINFO *)b) - getpcpu((KINFO *)a));
    462   1.1       cgd 	if (sortby == SORTMEM)
    463  1.11       cgd 		return (VSIZE((KINFO *)b) - VSIZE((KINFO *)a));
    464  1.11       cgd 	i =  KI_EPROC((KINFO *)a)->e_tdev - KI_EPROC((KINFO *)b)->e_tdev;
    465   1.1       cgd 	if (i == 0)
    466  1.11       cgd 		i = KI_PROC((KINFO *)a)->p_pid - KI_PROC((KINFO *)b)->p_pid;
    467   1.1       cgd 	return (i);
    468   1.1       cgd }
    469   1.1       cgd 
    470   1.1       cgd /*
    471   1.1       cgd  * ICK (all for getopt), would rather hide the ugliness
    472   1.1       cgd  * here than taint the main code.
    473   1.1       cgd  *
    474   1.1       cgd  *  ps foo -> ps -foo
    475   1.1       cgd  *  ps 34 -> ps -p34
    476   1.1       cgd  *
    477  1.25   mycroft  * The old convention that 't' with no trailing tty arg means the user's
    478   1.1       cgd  * tty, is only supported if argv[1] doesn't begin with a '-'.  This same
    479   1.1       cgd  * feature is available with the option 'T', which takes no argument.
    480   1.1       cgd  */
    481  1.11       cgd static char *
    482   1.1       cgd kludge_oldps_options(s)
    483   1.1       cgd 	char *s;
    484   1.1       cgd {
    485   1.1       cgd 	size_t len;
    486   1.1       cgd 	char *newopts, *ns, *cp;
    487   1.1       cgd 
    488   1.1       cgd 	len = strlen(s);
    489  1.16   thorpej 	if ((newopts = ns = malloc(len + 3)) == NULL)
    490  1.19  christos 		err(1, "%s", "");
    491   1.1       cgd 	/*
    492   1.1       cgd 	 * options begin with '-'
    493   1.1       cgd 	 */
    494   1.1       cgd 	if (*s != '-')
    495   1.1       cgd 		*ns++ = '-';	/* add option flag */
    496   1.1       cgd 	/*
    497   1.1       cgd 	 * gaze to end of argv[1]
    498   1.1       cgd 	 */
    499   1.1       cgd 	cp = s + len - 1;
    500   1.1       cgd 	/*
    501   1.1       cgd 	 * if last letter is a 't' flag with no argument (in the context
    502   1.1       cgd 	 * of the oldps options -- option string NOT starting with a '-' --
    503   1.1       cgd 	 * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)).
    504   1.1       cgd 	 */
    505   1.1       cgd 	if (*cp == 't' && *s != '-')
    506   1.1       cgd 		*cp = 'T';
    507   1.1       cgd 	else {
    508   1.1       cgd 		/*
    509   1.1       cgd 		 * otherwise check for trailing number, which *may* be a
    510   1.1       cgd 		 * pid.
    511   1.1       cgd 		 */
    512   1.1       cgd 		while (cp >= s && isdigit(*cp))
    513   1.1       cgd 			--cp;
    514   1.1       cgd 	}
    515   1.1       cgd 	cp++;
    516  1.11       cgd 	memmove(ns, s, (size_t)(cp - s));	/* copy up to trailing number */
    517   1.1       cgd 	ns += cp - s;
    518   1.1       cgd 	/*
    519   1.1       cgd 	 * if there's a trailing number, and not a preceding 'p' (pid) or
    520   1.1       cgd 	 * 't' (tty) flag, then assume it's a pid and insert a 'p' flag.
    521   1.1       cgd 	 */
    522  1.25   mycroft 	if (isdigit(*cp) &&
    523  1.25   mycroft 	    (cp == s || (cp[-1] != 'U' && cp[-1] != 't' && cp[-1] != 'p' &&
    524  1.25   mycroft 	     (cp - 1 == s || cp[-2] != 't'))))
    525   1.1       cgd 		*ns++ = 'p';
    526  1.18       mrg 	/* and append the number */
    527  1.18       mrg 	(void)strcpy(ns, cp);		/* XXX strcpy is safe */
    528   1.1       cgd 
    529   1.1       cgd 	return (newopts);
    530   1.1       cgd }
    531   1.1       cgd 
    532  1.11       cgd static void
    533  1.11       cgd usage()
    534   1.1       cgd {
    535   1.1       cgd 
    536  1.11       cgd 	(void)fprintf(stderr,
    537  1.11       cgd 	    "usage:\t%s\n\t   %s\n\t%s\n",
    538  1.11       cgd 	    "ps [-aChjlmrSTuvwx] [-O|o fmt] [-p pid] [-t tty]",
    539  1.11       cgd 	    "[-M core] [-N system] [-W swap]",
    540  1.11       cgd 	    "ps [-L]");
    541   1.1       cgd 	exit(1);
    542  1.23   mycroft 	/* NOTREACHED */
    543   1.1       cgd }
    544