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