X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/1c15e88899094343f75aeba04122cd96a96b428e..ad7871609881e73855d0b04da49b486cd93efca7:/usr/src/bin/ps/ps.c diff --git a/usr/src/bin/ps/ps.c b/usr/src/bin/ps/ps.c index d529999889..0fb2ae3ff6 100644 --- a/usr/src/bin/ps/ps.c +++ b/usr/src/bin/ps/ps.c @@ -1,447 +1,271 @@ /*- - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. * - * Redistribution and use in source and binary forms are permitted provided - * that: (1) source distributions retain this entire copyright notice and - * comment, and (2) distributions including binaries display the following - * acknowledgement: ``This product includes software developed by the - * University of California, Berkeley and its contributors'' in the - * documentation or other materials provided with the distribution and in - * all advertising materials mentioning features or use of this software. - * Neither the name of the University nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #ifndef lint -char copyright[] = -"@(#) Copyright (c) 1990 The Regents of the University of California.\n\ - All rights reserved.\n"; +static char copyright[] = +"@(#) Copyright (c) 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)ps.c 5.28 (Berkeley) 6/26/90"; +static char sccsid[] = "@(#)ps.c 8.1 (Berkeley) 5/31/93"; #endif /* not lint */ -#include - #include -#include -#include #include +#include +#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include +#include +#include + #include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include -struct usave { - struct proc *u_procp; - struct timeval u_start; - struct rusage u_ru; - struct rusage u_cru; - short u_cmask; - char u_acflag; -}; +#include "ps.h" -/* - * to compute offset in common structures - */ -#define POFF(x) ((int)&((struct proc *)0)->x) -#define EOFF(x) ((int)&((struct eproc *)0)->x) -#define UOFF(x) ((int)&((struct usave *)0)->x) -#define ROFF(x) ((int)&((struct rusage *)0)->x) +#ifdef SPPWAIT +#define NEWVM +#endif -enum type { CHAR, UCHAR, SHORT, USHORT, LONG, ULONG, KPTR }; +KINFO *kinfo; +struct varent *vhead, *vtail; -#define UIDFMT "u" -#define UIDLEN 5 -#define PIDFMT "d" -#define PIDLEN 5 -#define USERLEN 8 +int eval; /* exit value */ +int rawcpu; /* -C */ +int sumrusage; /* -S */ +int termwidth; /* width of screen (0 == infinity) */ +int totwidth; /* calculated width of requested variables */ -int needuser, needcomm, neednlist; +static int needuser, needcomm, needenv; -int command(), ucomm(), logname(), pvar(), evar(), uvar(), rvar(), uname(), - runame(), state(), pri(), tdev(), tname(), longtname(), started(), - lstarted(), wchan(), vsize(), rssize(), p_rssize(), cputime(), - pmem(), pcpu(), pagein(), maxrss(), tsize(), trss(); - /** - utime(), stime(), ixrss(), idrss(), isrss(); - **/ +enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; -struct usave *saveuser(); -char *saveargs(); +static char *fmt __P((char **(*)(kvm_t *, const struct kinfo_proc *, int), + KINFO *, char *, int)); +static char *kludge_oldps_options __P((char *)); +static int pscomp __P((const void *, const void *)); +static void saveuser __P((KINFO *)); +static void scanvars __P((void)); +static void usage __P((void)); -struct var { - char *name[8]; /* name(s) of variable */ - char *header; /* default header */ - int flag; -#define USER 0x01 /* requires user structure */ -#define LJUST 0x02 /* right adjust on output */ -#define COMM 0x04 /* requires exec arguments and environment (XXX) */ -#define NLIST 0x08 /* requires nlist to get extra variables */ - int (*oproc)(); /* output routine */ - short width; /* printing width */ - /* - * The following (optional) elements are hooks for passing information - * to the generic output routines: pvar, evar, uvar (those which print - * simple elements from well known structures: proc, eproc, usave) - */ - int off; /* offset in structure */ - enum type type; /* type of element */ - char *fmt; /* printf format */ - /* - * glue to link selected fields together - */ - struct var *next; -} var[] = { - {{"command", "comm", "args"}, "COMMAND", USER|LJUST|COMM, - command, 16}, - {{"ucomm"}, "COMMAND", LJUST, ucomm, MAXCOMLEN}, - {{"logname"}, "LOGNAME", LJUST, logname, MAXLOGNAME}, - {{"flag", "f"}, "F", 0, pvar, 7, POFF(p_flag), LONG, "x"}, - {{"uid"}, "UID", 0, pvar, UIDLEN, POFF(p_uid),USHORT, UIDFMT}, - {{"ruid"}, "RUID", 0, pvar, UIDLEN, POFF(p_ruid), USHORT, UIDFMT}, - {{"svuid"}, "SVUID", 0, pvar, UIDLEN, POFF(p_svuid), USHORT, UIDFMT}, - {{"rgid"}, "RGID", 0, pvar, UIDLEN, POFF(p_rgid), USHORT, UIDFMT}, - {{"svgid"}, "SVGID", 0, pvar, UIDLEN, POFF(p_svgid), USHORT, UIDFMT}, - {{"pid"}, "PID", 0, pvar, PIDLEN, POFF(p_pid),SHORT, PIDFMT}, - {{"ppid"}, "PPID", 0, pvar, PIDLEN, POFF(p_ppid), SHORT, PIDFMT}, - {{"cp", "cpu"}, "CP", 0, pvar, 3, POFF(p_cpu), UCHAR, "d"}, - {{"xstat"}, "XSTAT", 0, pvar, 4, POFF(p_xstat), USHORT, "x"}, - {{"poip"}, "POIP", 0, pvar, 4, POFF(p_poip), SHORT, "d"}, - {{"nwchan"}, "WCHAN", 0, pvar, 6, POFF(p_wchan), KPTR, "x"}, - {{"wchan"}, "WCHAN", LJUST, wchan, 6}, - {{"rlink"}, "RLINK", 0, pvar, 8, POFF(p_rlink), KPTR, "x"}, - {{"ktrace", "traceflag"}, "KTRACE", - 0, pvar, 8, POFF(p_traceflag), LONG, "x"}, - {{"ktracep", "tracep"}, "KTRACEP", - 0, pvar, 8, POFF(p_tracep), LONG, "x"}, - {{"sig", "pending"}, "PENDING", - 0, pvar, 8, POFF(p_sig), LONG, "x"}, - {{"sigmask", "blocked"}, "BLOCKED", - 0, pvar, 8, POFF(p_sigmask), LONG, "x"}, - {{"sigignore", "ignored"}, "IGNORED", - 0, pvar, 8, POFF(p_sigignore), LONG, "x"}, - {{"sigcatch", "caught"}, "CAUGHT", - 0, pvar, 8, POFF(p_sigcatch), LONG, "x"}, - {{"user", "uname"}, "USER", LJUST, uname, USERLEN}, - {{"ruser", "runame"}, "RUSER", LJUST, runame, USERLEN}, - {{"pgid"}, "PGID", 0, evar, PIDLEN, EOFF(e_pgid), USHORT, PIDFMT}, - {{"jobc"}, "JOBC", 0, evar, 4, EOFF(e_jobc), SHORT, "d"}, - {{"sess", "session"}, "SESS", 0, evar, 6, EOFF(e_sess), KPTR, "x"}, - {{"tdev", "dev"}, "TDEV", 0, tdev, 4}, - {{"tname", "tty", "tt"}, "TT", LJUST, tname, 3}, - {{"longtname", "longtty"}, "TT", LJUST, longtname, 8}, - {{"tpgid"}, "TPGID", 0, evar, 4, EOFF(e_tpgid), USHORT, PIDFMT}, - {{"tsession", "tsess"}, "TSESS", - 0, evar, 6, EOFF(e_tsess), KPTR, "x"}, - {{"paddr", "procaddr"}, "PADDR", - 0, evar, 6, EOFF(e_paddr), KPTR, "x"}, - {{"state", "stat"}, "STAT", 0, state, 4}, - {{"pri"}, "PRI", 0, pri, 3}, - {{"usrpri"}, "UPR", 0, pvar, 3, POFF(p_usrpri), CHAR, "d"}, - {{"nice", "ni"}, "NI", 0, pvar, 2, POFF(p_nice), CHAR, "d"}, - {{"vsize", "vsz"}, "VSZ", 0, vsize, 5}, - {{"rssize", "rsz"}, "RSZ", 0, rssize, 4}, - {{"rss", "p_rss"}, "RSS", 0, p_rssize, 4}, - {{"u_procp", "uprocp"}, "UPROCP", - USER, uvar, 6, UOFF(u_procp), KPTR, "x"}, - {{"umask", "u_cmask"}, "UMASK", - USER, uvar, 3, UOFF(u_cmask), CHAR, "#o"}, - {{"acflag", "acflg"}, "ACFLG", - USER, uvar, 3, UOFF(u_acflag), SHORT, "x"}, - {{"start"}, "STARTED", USER|LJUST, started, 8}, - {{"lstart"}, "STARTED", USER|LJUST, lstarted, 28}, - {{"cputime", "time"}, "TIME", USER, cputime, 9}, - {{"p_ru"}, "P_RU", 0, pvar, 6, POFF(p_ru), KPTR, "x"}, - {{"pcpu", "%cpu"}, "%CPU", NLIST, pcpu, 4}, - {{"pmem", "%mem"}, "%MEM", NLIST, pmem, 4}, - {{"sl", "slp", "slptime"}, "SL", - 0, pvar, 3, POFF(p_slptime), CHAR, "d"}, - {{"re", "resident"}, "RE", - 0, pvar, 3, POFF(p_time), CHAR, "d"}, - {{"pagein", "majflt"}, "PAGEIN", USER, pagein, 6}, - {{"lim", "maxrss"}, "LIM", 0, maxrss, 5}, - {{"tsiz"}, "TSIZ", 0, tsize, 4}, - {{"trs"}, "TRS", 0, trss, 3}, - /*** - {{"utime"}, "UTIME", USER, utime, 4}, - {{"stime"}, "STIME", USER, stime, 4}, - {{"ixrss"}, "IXRSS", USER, ixrss, 4}, - {{"idrss"}, "IDRSS", USER, idrss, 4}, - {{"isrss"}, "ISRSS", USER, isrss, 4}, - ***/ - {{"minflt"}, "MINFLT", - USER, rvar, 4, ROFF(ru_minflt), LONG, "d"}, - {{"majflt"}, "MAJFLT", - USER, rvar, 4, ROFF(ru_majflt), LONG, "d"}, - {{"nswap"}, "NSWAP", - USER, rvar, 4, ROFF(ru_nswap), LONG, "d"}, - {{"inblock", "inblk"}, "INBLK", - USER, rvar, 4, ROFF(ru_inblock), LONG, "d"}, - {{"oublock", "oublk"}, "OUBLK", - USER, rvar, 4, ROFF(ru_oublock), LONG, "d"}, - {{"msgsnd"}, "MSGSND", - USER, rvar, 4, ROFF(ru_msgsnd), LONG, "d"}, - {{"msgrcv"}, "MSGRCV", - USER, rvar, 4, ROFF(ru_msgrcv), LONG, "d"}, - {{"nsignals", "nsigs"}, "NSIGS", - USER, rvar, 4, ROFF(ru_nsignals), LONG, "d"}, - {{"nvcsw", "vcsw"}, "VCSW", - USER, rvar, 5, ROFF(ru_nvcsw), LONG, "d"}, - {{"nivcsw", "ivcsw"}, "IVCSW", - USER, rvar, 5, ROFF(ru_nivcsw), LONG, "d"}, - NULL -}; +char dfmt[] = "pid tt state time command"; +char jfmt[] = "user pid ppid pgid sess jobc state tt time command"; +char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command"; +char o1[] = "pid"; +char o2[] = "tt state time command"; +char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command"; +char vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command"; -/* - * combination variables - */ -struct combovar { - char *name; - char *replace; -} combovar[] = { - "RUSAGE", "minflt majflt nswap inblock oublock \ - msgsnd msgrcv nsigs nvcsw nivcsw", - 0, 0 -}; -#define DFMT "pid tname state cputime comm" -#define LFMT \ - "uid pid ppid cp pri nice vsz rss wchan state tname cputime comm" -#define JFMT "user pid ppid pgid sess jobc state tname cputime comm" -#define SFMT "uid pid sig sigmask sigignore sigcatch stat tname comm" -#define VFMT \ - "pid tt state time sl re pagein vsz rss lim tsiz trs %cpu %mem comm" -#define UFMT \ - "uname pid %cpu %mem vsz rss tt state start time comm" +kvm_t *kd; -struct kinfo { - struct proc *ki_p; /* proc structure */ - struct eproc *ki_e; /* extra stuff */ - struct usave *ki_u; /* interesting parts of user */ - char *ki_args; /* exec args (should be char **) */ - char *ki_env; /* environment (should be char **) */ -} *kinfo; - -struct var *vhead, *vtail; -int termwidth; /* width of screen (0 == infinity) */ -#define UNLIMITED 0 -int totwidth; /* calculated width of requested variables */ -int sumrusage; -int rawcpu; -int sortby; -#define SORTMEM 1 -#define SORTCPU 2 - -int uid = -1; -dev_t ttydev = NODEV; -int pid = -1; -int all; -int xflg; -int prtheader; -int lineno; - -/* - * variables retrieved via nlist - */ -struct nlist psnl[] = { - {"_ecmx"}, -#define X_ECMX 0 - {"_fscale"}, -#define X_FSCALE 1 - {"_ccpu"}, -#define X_CCPU 2 - {NULL} -}; -int fscale; -int ecmx; -fixpt_t ccpu; - -#define USAGE "ps [ -(o|O) fmt ] [ -wlvujnsaxSCLmcr ] [ -p pid ] [ -t tty ]" - -main (argc, argv) +int +main(argc, argv) + int argc; char *argv[]; { - extern char *optarg; - extern int optind; - int ch; - register i; - register struct var *v; - register struct proc *p; - struct winsize ws; - struct kinfo_proc *kprocs; + register struct kinfo_proc *kp; + register struct varent *vent; int nentries; - int fmt = 0; - int pscomp(); - int what, flag; - char *kludge_oldps_options(); + register int i; + struct winsize ws; + dev_t ttydev; + int all, ch, flag, fmt, lineno, pid, prtheader, uid, wflag, what, xflg; + char *nlistf, *memf, *swapf, errbuf[256]; - if ((ioctl(1, TIOCGWINSZ, &ws) == -1 && - ioctl(2, TIOCGWINSZ, &ws) == -1 && - ioctl(0, TIOCGWINSZ, &ws) == -1) || + if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && + ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && + ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) || ws.ws_col == 0) termwidth = 79; else termwidth = ws.ws_col - 1; + if (argc > 1) argv[1] = kludge_oldps_options(argv[1]); - while ((ch = getopt(argc, argv, "o:O:wlvujnsaxt:p:SCLmrhTg")) != EOF) + all = fmt = prtheader = wflag = xflg = 0; + pid = uid = -1; + ttydev = NODEV; + memf = nlistf = swapf = NULL; + while ((ch = getopt(argc, argv, + "aCeghjLlM:mN:O:o:p:rSTt:uvW:wx")) != EOF) switch((char)ch) { - case 'o': - parsefmt(optarg); - fmt++; + case 'a': + all = 1; break; - case 'O': - parsefmt("pid"); - parsefmt(optarg); - parsefmt("state tt time command"); - fmt++; + case 'e': /* XXX set ufmt */ + needenv = 1; break; - case 'w': - if (termwidth < 131) - termwidth = 131; - else - termwidth = UNLIMITED; + case 'C': + rawcpu = 1; + break; + case 'g': + break; /* no-op */ + case 'h': + prtheader = ws.ws_row > 5 ? ws.ws_row : 22; break; + case 'j': + parsefmt(jfmt); + fmt = 1; + jfmt[0] = '\0'; + break; + case 'L': + showkey(); + exit(0); case 'l': - parsefmt(LFMT); - fmt++; + parsefmt(lfmt); + fmt = 1; + lfmt[0] = '\0'; break; - case 'v': - parsefmt(VFMT); - sortby = SORTMEM; - fmt++; + case 'M': + memf = optarg; break; - case 'u': - parsefmt(UFMT); - sortby = SORTCPU; - fmt++; + case 'm': + sortby = SORTMEM; break; - case 'j': - parsefmt(JFMT); - fmt++; + case 'N': + nlistf = optarg; break; - case 's': - parsefmt(SFMT); - fmt++; + case 'O': + parsefmt(o1); + parsefmt(optarg); + parsefmt(o2); + o1[0] = o2[0] = '\0'; + fmt = 1; break; - case 'T': - case 't': { - struct stat stbuf; - char *tname, *ttyname(); - char termname[MAXPATHLEN+1]; - - if (ch == 'T') { - if ((tname = ttyname(0)) == NULL) - error(": not a terminal"); - } else - tname = optarg; - if (strlen(tname) == 2) { - if (strcmp(tname, "co") == 0) - strcpy(termname, "/dev/console"); - else { - strcpy(termname, "/dev/tty"); - strcat(termname, tname); - } - } else if (*tname != '/') { - strcpy(termname, "/dev/"); - strcat(termname, tname); - } else - strcpy(termname, tname); - if (stat(termname, &stbuf) == -1) - syserror(termname); - if ((stbuf.st_mode & S_IFMT) != S_IFCHR) - error("%s: not a terminal", termname); - ttydev = stbuf.st_rdev; + case 'o': + parsefmt(optarg); + fmt = 1; break; - } case 'p': pid = atoi(optarg); - xflg++; + xflg = 1; + break; + case 'r': + sortby = SORTCPU; break; case 'S': - sumrusage++; + sumrusage = 1; break; - case 'C': - rawcpu++; + case 'T': + if ((optarg = ttyname(STDIN_FILENO)) == NULL) + errx(1, "stdin: not a terminal"); + /* FALLTHROUGH */ + case 't': { + struct stat sb; + char *ttypath, pathbuf[MAXPATHLEN]; + + if (strcmp(optarg, "co") == 0) + ttypath = _PATH_CONSOLE; + else if (*optarg != '/') + (void)snprintf(ttypath = pathbuf, + sizeof(pathbuf), "%s%s", _PATH_TTY, optarg); + else + ttypath = optarg; + if (stat(ttypath, &sb) == -1) + err(1, "%s", ttypath); + if (!S_ISCHR(sb.st_mode)) + errx(1, "%s: not a terminal", ttypath); + ttydev = sb.st_rdev; break; - case 'L': { - int i = 0; - struct combovar *cb = &combovar[0]; - char *cp; - - v = &var[0]; - for (;;) { - if (v->name[0] != NULL) { - cp = v->name[0]; - v++; - } else if (cb->name != NULL) { - cp = cb->name; - cb++; - } else - break; - if (termwidth && - (i += strlen(cp)+1) > termwidth) - i = strlen(cp), printf("\n"); - printf("%s ", cp); - } - printf("\n"); - exit(0); } - case 'a': - all++; - break; - case 'x': - xflg++; + case 'u': + parsefmt(ufmt); + sortby = SORTCPU; + fmt = 1; + ufmt[0] = '\0'; break; - case 'm': + case 'v': + parsefmt(vfmt); sortby = SORTMEM; + fmt = 1; + vfmt[0] = '\0'; break; - case 'r': - sortby = SORTCPU; + case 'W': + swapf = optarg; break; - case 'h': - prtheader = ws.ws_row > 5 ? ws.ws_row : 22; + case 'w': + if (wflag) + termwidth = UNLIMITED; + else if (termwidth < 131) + termwidth = 131; + wflag++; + break; + case 'x': + xflg = 1; break; - case 'g': - break; /* no-op */ case '?': default: - fprintf(stderr, "usage: %s\n", USAGE); - exit(1); + usage(); } argc -= optind; argv += optind; - - if (*argv) { - char *nlistf, *memf = NULL, *swapf = NULL; - nlistf = *argv++; - if (*argv) { - memf = *argv++; - if (*argv) - swapf = *argv++; +#define BACKWARD_COMPATIBILITY +#ifdef BACKWARD_COMPATIBILITY + if (*argv) { + nlistf = *argv; + if (*++argv) { + memf = *argv; + if (*++argv) + swapf = *argv; } - if (kvm_openfiles(nlistf, memf, swapf) == -1) - error("kvm_openfiles: %s", kvm_geterr()); } +#endif + /* + * Discard setgid privileges if not the running kernel so that bad + * guys can't print interesting stuff from kernel memory. + */ + if (nlistf != NULL || memf != NULL || swapf != NULL) + setgid(getgid()); + + kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf); + if (kd == 0) + errx(1, "%s", errbuf); if (!fmt) - parsefmt(DFMT); + parsefmt(dfmt); if (!all && ttydev == NODEV && pid == -1) /* XXX - should be cleaner */ uid = getuid(); @@ -451,45 +275,34 @@ main (argc, argv) * and adjusting header widths as appropiate. */ scanvars(); -#ifdef notdef - if (sortby == SORTCPU) - neednlist = 1; -#endif - if (neednlist) - donlist(); /* * get proc list */ if (uid != -1) { - what = KINFO_PROC_UID; + what = KERN_PROC_UID; flag = uid; } else if (ttydev != NODEV) { - what = KINFO_PROC_TTY; + what = KERN_PROC_TTY; flag = ttydev; } else if (pid != -1) { - what = KINFO_PROC_PID; + what = KERN_PROC_PID; flag = pid; - } else - what = KINFO_PROC_ALL; + } else { + what = KERN_PROC_ALL; + flag = 0; + } /* * select procs */ - if ((nentries = kvm_getprocs(what, flag)) == -1) { - fprintf(stderr, "ps: %s\n", kvm_geterr()); - exit(1); - } - kinfo = (struct kinfo *)malloc(nentries * sizeof (struct kinfo)); - if (kinfo == NULL) - error("out of memory"); - i = 0; - while ((p = kvm_nextproc()) != NULL) { - kinfo[i].ki_p = p; - kinfo[i].ki_e = kvm_geteproc(p); + if ((kp = kvm_getprocs(kd, what, flag, &nentries)) == 0) + errx(1, "%s", kvm_geterr(kd)); + if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL) + err(1, NULL); + for (i = nentries; --i >= 0; ++kp) { + kinfo[i].ki_p = kp; if (needuser) saveuser(&kinfo[i]); - i++; } - nentries = i; /* * print header */ @@ -499,91 +312,38 @@ main (argc, argv) /* * sort proc list */ - qsort(kinfo, nentries, sizeof (struct kinfo), pscomp); + qsort(kinfo, nentries, sizeof(KINFO), pscomp); /* * for each proc, call each variable output function. */ - for (i = 0; i < nentries; i++) { - if (xflg == 0 && (kinfo[i].ki_e->e_tdev == NODEV || - (kinfo[i].ki_p->p_flag & SCTTY ) == 0)) + for (i = lineno = 0; i < nentries; i++) { + if (xflg == 0 && (KI_EPROC(&kinfo[i])->e_tdev == NODEV || + (KI_PROC(&kinfo[i])->p_flag & SCTTY ) == 0)) continue; - for (v = vhead; v != NULL; v = v->next) { - (*v->oproc)(&kinfo[i], v); - if (v->next != NULL) - putchar(' '); + for (vent = vhead; vent; vent = vent->next) { + (vent->var->oproc)(&kinfo[i], vent); + if (vent->next != NULL) + (void)putchar(' '); } - putchar('\n'); - if (prtheader && lineno++ == prtheader-4) { - putchar('\n'); + (void)putchar('\n'); + if (prtheader && lineno++ == prtheader - 4) { + (void)putchar('\n'); printheader(); lineno = 0; } } - - exit(0); -} - -#define FMTSEP " \t,\n" - -parsefmt(fmt) - char *fmt; -{ - register char *f = fmt, *cp, *hp; - struct var *v; - char *strtok(), *index(); - char newbuf[1024], *nb = newbuf; /* XXX */ - char *lookupcombo(); - struct var *lookupvar(); - - /* - * strtok is not &^%^& re-entrant, so we have - * only one level of expansion, looking for combo - * variables once here, and expanding the string - * before really parsing it. With strtok_r, - * you would move the expansion to before the - * lookupvar inside the 2nd while loop with a - * recursive call to parsefmt. - */ - while ((cp = strtok(f, FMTSEP)) != NULL) { - if ((hp = lookupcombo(cp)) == NULL); - hp = cp; - if (((nb + strlen(hp)) - newbuf) >= 1024) - error("format too large"); - strcpy(nb, hp); - while (*nb) - nb++; - *nb++ = ' '; - *nb = '\0'; - f = NULL; - } - f = newbuf; - while ((cp = strtok(f, FMTSEP)) != NULL) { - if (hp = index(cp, '=')) - *hp++ = '\0'; - v = lookupvar(cp); - if (v == NULL) - error("unknown variable in format: %s", cp); - if (v->next != NULL || vtail == v) - error("can't specify a variable twice: %s", cp); - if (hp) - v->header = hp; - if (vhead == NULL) - vhead = vtail = v; - else { - vtail->next = v; - vtail = v; - } - f = NULL; /* for strtok */ - } - + exit(eval); } +static void scanvars() { - register i; - register struct var *v; + register struct varent *vent; + register VAR *v; + register int i; - for (v = vhead; v != NULL; v = v->next) { + for (vent = vhead; vent; vent = vent->next) { + v = vent->var; i = strlen(v->header); if (v->width < i) v->width = i; @@ -592,633 +352,83 @@ scanvars() needuser = 1; if (v->flag & COMM) needcomm = 1; - if (v->flag & NLIST) - neednlist = 1; } totwidth--; } -printheader() -{ - register struct var *v; - - for (v = vhead; v != NULL; v = v->next) { - if (v->flag & LJUST) { - if (v->next == NULL) /* last one */ - printf("%s", v->header); - else - printf("%-*s",v->width, v->header); - } else - printf("%*s",v->width, v->header); - if (v->next != NULL) - putchar(' '); - } - putchar('\n'); -} - -command(k, v) - struct kinfo *k; - struct var *v; -{ - - if (v->next == NULL) { - /* last field */ - if (termwidth == UNLIMITED) - printf("%s", k->ki_args); - else { - register left = termwidth - (totwidth - v->width); - register char *cp = k->ki_args; - - if (left < 1) /* already wrapped, just use std width */ - left = v->width; - while (left-- && *cp) - putchar(*cp++); - } - } else - printf("%-*.*s", v->width, v->width, k->ki_args); - -} - -ucomm(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%-*s", v->width, k->ki_p->p_comm); -} - -logname(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%-*s", v->width, k->ki_p->p_logname); -} - -state(k, v) - struct kinfo *k; - struct var *v; -{ - char buf[16]; - register char *cp = buf; - register struct proc *p = k->ki_p; - register flag = p->p_flag; - - switch (p->p_stat) { - - case SSTOP: - *cp = 'T'; - break; - - case SSLEEP: - if (flag & SSINTR) /* interuptable (long) */ - *cp = p->p_slptime >= MAXSLP ? 'I' : 'S'; - else - *cp = (flag & SPAGE) ? 'P' : 'D'; - break; - - case SRUN: - case SIDL: - *cp = 'R'; - break; - - case SZOMB: - *cp = 'Z'; - break; - - default: - *cp = '?'; - } - cp++; - if (flag & SLOAD) { - if (p->p_rssize > p->p_maxrss) - *cp++ = '>'; - } else - *cp++ = 'W'; - if (p->p_nice < NZERO) - *cp++ = '<'; - else if (p->p_nice > NZERO) - *cp++ = 'N'; - if (flag & SUANOM) - *cp++ = 'A'; - else if (flag & SSEQL) - *cp++ = 'S'; - if (flag & STRC) - *cp++ = 'X'; - if (flag & SWEXIT) - *cp++ = 'E'; - if (flag & SVFORK) - *cp++ = 'V'; - if (flag & (SSYS|SLOCK|SULOCK|SKEEP|SPHYSIO)) - *cp++ = 'L'; - if (k->ki_e->e_flag & EPROC_SLEADER) - *cp++ = 's'; - if ((flag & SCTTY) && k->ki_e->e_pgid == k->ki_e->e_tpgid) - *cp++ = '+'; - *cp = '\0'; - printf("%-*s", v->width, buf); -} - -pri(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%*d", v->width, k->ki_p->p_pri - PZERO); -} - -uname(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%-*s", v->width, user_from_uid(k->ki_p->p_uid, 0)); -} - -runame(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%-*s", v->width, user_from_uid(k->ki_p->p_ruid, 0)); -} -tdev(k, v) - struct kinfo *k; - struct var *v; +static char * +fmt(fn, ki, comm, maxlen) + char **(*fn) __P((kvm_t *, const struct kinfo_proc *, int)); + KINFO *ki; + char *comm; + int maxlen; { - dev_t dev = k->ki_e->e_tdev; + register char *s; - if (dev == NODEV) - printf("%*s", v->width, "??"); - else { - char buff[16]; - - sprintf(buff, "%d/%d", major(dev), minor(dev)); - printf("%*s", v->width, buff); - } -} - -extern char *devname(); - -tname(k, v) - struct kinfo *k; - struct var *v; -{ - dev_t dev = k->ki_e->e_tdev; - char *tname; - - if (dev == NODEV || (tname = devname(dev, S_IFCHR)) == NULL) - printf("%-*s", v->width, "??"); - else { - if (strncmp(tname, "tty", 3) == 0) - tname += 3; - printf("%*.*s%c", v->width-1, v->width-1, tname, - k->ki_e->e_flag & EPROC_CTTY ? ' ' : '-'); - } -} - -longtname(k, v) - struct kinfo *k; - struct var *v; -{ - dev_t dev = k->ki_e->e_tdev; - char *tname; - - if (dev == NODEV || (tname = devname(dev, S_IFCHR)) == NULL) - printf("%-*s", v->width, "??"); - else - printf("%-*s", v->width, tname); -} - -#include - -started(k, v) - struct kinfo *k; - struct var *v; -{ - extern char *attime(); - - printf("%-*s", v->width, k->ki_u ? - attime(&k->ki_u->u_start.tv_sec) : "-"); - -} - -lstarted(k, v) - struct kinfo *k; - struct var *v; -{ - extern char *ctime(); - char *tp; - - if (k->ki_u) - (tp = ctime(&k->ki_u->u_start.tv_sec))[24] = '\0'; - else - tp = "-"; - printf("%-*s", v->width, tp); -} - -wchan(k, v) - struct kinfo *k; - struct var *v; -{ - - if (k->ki_p->p_wchan) { - if (k->ki_p->p_pri > PZERO) - printf("%-*.*s", v->width, v->width, k->ki_e->e_wmesg); - else - printf("%*x", v->width, - (int)k->ki_p->p_wchan &~ KERNBASE); - } else - printf("%-*s", v->width, "-"); -} - -#define pgtok(a) (((a)*NBPG)/1024) -#define pgtok(a) (((a)*NBPG)/1024) - -vsize(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%*d", v->width, - pgtok(k->ki_p->p_dsize + k->ki_p->p_ssize + k->ki_e->e_xsize)); -} - -rssize(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%*d", v->width, - pgtok(k->ki_p->p_rssize + (k->ki_e->e_xccount ? - (k->ki_e->e_xrssize / k->ki_e->e_xccount) : 0))); -} - -p_rssize(k, v) /* doesn't account for text */ - struct kinfo *k; - struct var *v; -{ - - printf("%*d", v->width, pgtok(k->ki_p->p_rssize)); + if ((s = + fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen)) == NULL) + err(1, NULL); + return (s); } -cputime(k, v) - struct kinfo *k; - struct var *v; +static void +saveuser(ki) + KINFO *ki; { - long secs; - long psecs; /* "parts" of a second. first micro, then centi */ - char obuff[128]; + register struct usave *usp = &ki->ki_u; + struct pstats pstats; + extern char *fmt_argv(); - if (k->ki_p->p_stat == SZOMB || k->ki_u == NULL) { - secs = 0; - psecs = 0; - } else { - secs = k->ki_p->p_utime.tv_sec + - k->ki_p->p_stime.tv_sec; - psecs = k->ki_p->p_utime.tv_usec + - k->ki_p->p_stime.tv_usec; - if (sumrusage) { - secs += k->ki_u->u_cru.ru_utime.tv_sec + - k->ki_u->u_cru.ru_stime.tv_sec; - psecs += k->ki_u->u_cru.ru_utime.tv_usec + - k->ki_u->u_cru.ru_stime.tv_usec; - } + if (kvm_read(kd, (u_long)&KI_PROC(ki)->p_addr->u_stats, + (char *)&pstats, sizeof(pstats)) == sizeof(pstats)) { /* - * round and scale to 100's + * The u-area might be swapped out, and we can't get + * at it because we have a crashdump and no swap. + * If it's here fill in these fields, otherwise, just + * leave them 0. */ - psecs = (psecs + 5000) / 10000; - if (psecs >= 100) { - psecs -= 100; - secs++; - } - } - sprintf(obuff, "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); - printf("%*s", v->width, obuff); -} - -double -getpcpu(k) - struct kinfo *k; -{ - /* - * note: this routine requires ccpu and fscale - * be initialized. If you call this routine from - * somewhere new, insure that the "neednlist" flag - * gets set. - */ - struct proc *p = k->ki_p; -#define fxtofl(fixpt) ((double)(fixpt) / fscale) - - if (p->p_time == 0 || (p->p_flag & SLOAD) == 0) /* XXX - I don't like this */ - return (0.0); - if (rawcpu) - return (100.0 * fxtofl(p->p_pctcpu)); - return (100.0 * fxtofl(p->p_pctcpu) / - (1.0 - exp(p->p_time * log(fxtofl(ccpu))))); -} - -pcpu(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%*.1f", v->width, getpcpu(k)); -} - -double -getpmem(k, v) - struct kinfo *k; - struct var *v; -{ - struct proc *p = k->ki_p; - struct eproc *e = k->ki_e; - double fracmem; - int szptudot; - /* - * note: this routine requires that ecmx - * be initialized. If you call this routine from - * somewhere new, insure that the "neednlist" flag - * gets set. - */ - - if (p->p_flag & SLOAD == 0) - return (0.0); - szptudot = UPAGES + clrnd(ctopt(p->p_dsize + p->p_ssize + e->e_xsize)); - fracmem = ((float)p->p_rssize + szptudot)/CLSIZE/ecmx; - if (p->p_textp && e->e_xccount) - fracmem += ((float)e->e_xrssize)/CLSIZE/e->e_xccount/ecmx; - return (100.0 * fracmem); -} - -pmem(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%*.1f", v->width, getpmem(k)); -} - -pagein(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%*d", v->width, k->ki_u ? k->ki_u->u_ru.ru_majflt : 0); -} - -maxrss(k, v) - struct kinfo *k; - struct var *v; -{ - - if (k->ki_p->p_maxrss != (RLIM_INFINITY/NBPG)) - printf("%*d", v->width, pgtok(k->ki_p->p_maxrss)); - else - printf("%*s", v->width, "-"); -} - -tsize(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%*d", v->width, pgtok(k->ki_e->e_xsize)); -} - -trss(k, v) - struct kinfo *k; - struct var *v; -{ - - printf("%*d", v->width, pgtok(k->ki_e->e_xrssize)); -} - -/* - * Generic output routines. Print fields from various prototype - * structures. - */ -pvar(k, v) - struct kinfo *k; - struct var *v; -{ - - printval((char *)((char *)k->ki_p + v->off), v); -} - -evar(k, v) - struct kinfo *k; - struct var *v; -{ - - printval((char *)((char *)k->ki_e + v->off), v); -} - -uvar(k, v) - struct kinfo *k; - struct var *v; -{ - - if (k->ki_u) - printval((char *)((char *)k->ki_u + v->off), v); - else - printf("%*s", v->width, "-"); -} - -rvar(k, v) - struct kinfo *k; - struct var *v; -{ - - if (k->ki_u) - printval((char *)((char *)(&k->ki_u->u_ru) + v->off), v); - else - printf("%*s", v->width, "-"); -} - -char * -lookupcombo(cp) - char *cp; -{ - register struct combovar *cv = &combovar[0]; - - for (; cv->name; cv++) - if (strcmp(cp, cv->name) == 0) - return (cv->replace); - return (NULL); -} - -struct var * -lookupvar(cp) - char *cp; -{ - register int i, j; - - for (i=0; var[i].name[0] != NULL; i++) - for (j=0; var[i].name[j] != NULL; j++) - if (strcmp(cp, var[i].name[j]) == 0) - return (&var[i]); - return (NULL); -} - -printval(bp, v) - char *bp; - struct var *v; -{ - static char ofmt[32] = "%"; - register char *cp = ofmt+1, *fcp = v->fmt; - - if (v->flag & LJUST) - *cp++ = '-'; - *cp++ = '*'; - while (*cp++ = *fcp++) - ; - - switch (v->type) { - case CHAR: - printf(ofmt, v->width, *(char *)bp); - break; - - case UCHAR: - printf(ofmt, v->width, *(u_char *)bp); - break; - - case SHORT: - printf(ofmt, v->width, *(short *)bp); - break; - - case USHORT: - printf(ofmt, v->width, *(u_short *)bp); - break; - - case LONG: - printf(ofmt, v->width, *(long *)bp); - break; - - case ULONG: - printf(ofmt, v->width, *(u_long *)bp); - break; - - case KPTR: - printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE); - break; - - default: - error("unknown type %d", v->type); - } -} - -/* XXX - redo */ -struct usave * -saveuser(ki) - struct kinfo *ki; -{ - register struct usave *usp; - register struct user *up; - - if ((usp = (struct usave *)calloc(1, sizeof (struct usave))) == NULL) { - fprintf(stderr, "ps: out of memory\n"); - exit(1); - } - ki->ki_u = usp; - up = kvm_getu(ki->ki_p); + usp->u_start = pstats.p_start; + usp->u_ru = pstats.p_ru; + usp->u_cru = pstats.p_cru; + usp->u_valid = 1; + } else + usp->u_valid = 0; /* * save arguments if needed */ if (needcomm) - ki->ki_args = saveargs(ki->ki_p, up); + ki->ki_args = fmt(kvm_getargv, ki, KI_PROC(ki)->p_comm, + MAXCOMLEN); else ki->ki_args = NULL; - if (up != NULL) { - /* - * save important fields - */ - usp->u_procp = up->u_procp; - usp->u_start = up->u_start; - usp->u_ru = up->u_ru; - usp->u_cru = up->u_cru; - usp->u_cmask = up->u_cmask; - usp->u_acflag = up->u_acflag; - } - return; -} - -char * -saveargs(p, up) - struct proc *p; - struct user *up; -{ - char *savestr(); - - return(savestr(kvm_getargs(p, up))); + if (needenv) + ki->ki_env = fmt(kvm_getenvv, ki, (char *)NULL, 0); + else + ki->ki_env = NULL; } - -pscomp(k1, k2) - struct kinfo *k1, *k2; +static int +pscomp(a, b) + const void *a, *b; { int i; +#ifdef NEWVM +#define VSIZE(k) (KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize + \ + KI_EPROC(k)->e_vm.vm_tsize) +#else #define VSIZE(k) ((k)->ki_p->p_dsize + (k)->ki_p->p_ssize + (k)->ki_e->e_xsize) +#endif if (sortby == SORTCPU) - return (getpcpu(k2) - getpcpu(k1)); -#ifdef notyet - if (sortby == SORTRUN) - return (proc_compare(k1->ki_p, k2->ki_p)); -#endif + return (getpcpu((KINFO *)b) - getpcpu((KINFO *)a)); if (sortby == SORTMEM) - return (VSIZE(k2) - VSIZE(k1)); - i = k1->ki_e->e_tdev - k2->ki_e->e_tdev; + return (VSIZE((KINFO *)b) - VSIZE((KINFO *)a)); + i = KI_EPROC((KINFO *)a)->e_tdev - KI_EPROC((KINFO *)b)->e_tdev; if (i == 0) - i = k1->ki_p->p_pid - k2->ki_p->p_pid; + i = KI_PROC((KINFO *)a)->p_pid - KI_PROC((KINFO *)b)->p_pid; return (i); } -donlist() -{ - if (kvm_nlist(psnl) != 0) - error("can't get namelist"); - if (kvm_read(psnl[X_FSCALE].n_value, &fscale, sizeof(int)) != - sizeof (int)) - error("error reading fscale: %s", kvm_geterr()); - if (kvm_read(psnl[X_ECMX].n_value, &ecmx, sizeof(int)) != - sizeof (int)) - error("error reading ecmx: %s", kvm_geterr()); - if (kvm_read(psnl[X_CCPU].n_value, &ccpu, sizeof(fixpt_t)) != - sizeof (fixpt_t)) - error("error reading ccpu: %s", kvm_geterr()); -} - -char * -savestr(cp) - char *cp; -{ - register unsigned len; - register char *dp; - - len = strlen(cp); - dp = (char *)calloc(len+1, sizeof (char)); - (void) strcpy(dp, cp); - return (dp); -} - -error(a, b, c, d, e) - char *a, *b, *c, *d, *e; -{ - fprintf(stderr, "ps: "); - fprintf(stderr, a, b, c, d, e); - fprintf(stderr, "\n"); - exit(1); -} - -syserror(a) - char *a; -{ - extern errno; - - error("%s: %s", a, strerror(errno)); -} - /* * ICK (all for getopt), would rather hide the ugliness * here than taint the main code. @@ -1230,15 +440,16 @@ syserror(a) * tty, is only supported if argv[1] doesn't begin with a '-'. This same * feature is available with the option 'T', which takes no argument. */ -char * +static char * kludge_oldps_options(s) char *s; { - int len = strlen(s), numlen = 0; + size_t len; char *newopts, *ns, *cp; - if ((newopts = ns = (char *)malloc(len+2)) == NULL) - error("out of memory"); + len = strlen(s); + if ((newopts = ns = malloc(len + 2)) == NULL) + err(1, NULL); /* * options begin with '-' */ @@ -1251,7 +462,7 @@ kludge_oldps_options(s) /* * if last letter is a 't' flag with no argument (in the context * of the oldps options -- option string NOT starting with a '-' -- - * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0). + * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). */ if (*cp == 't' && *s != '-') *cp = 'T'; @@ -1260,23 +471,28 @@ kludge_oldps_options(s) * otherwise check for trailing number, which *may* be a * pid. */ - while (isdigit(*cp)) { + while (cp >= s && isdigit(*cp)) --cp; - numlen++; - } } cp++; - bcopy(s, ns, cp - s); /* copy everything up to trailing number */ - while (*ns) - ns++; + memmove(ns, s, (size_t)(cp - s)); /* copy up to trailing number */ + ns += cp - s; /* * if there's a trailing number, and not a preceding 'p' (pid) or * 't' (tty) flag, then assume it's a pid and insert a 'p' flag. */ - if (isdigit(*cp) && (cp == s || *(cp-1) != 't' && *(cp-1) != 'p' && - ((cp-1) == s || *(cp-2) != 't'))) + if (isdigit(*cp) && (cp == s || cp[-1] != 't' && cp[-1] != 'p' && + (cp - 1 == s || cp[-2] != 't'))) *ns++ = 'p'; - strcat(ns, cp); /* and append the number */ + (void)strcpy(ns, cp); /* and append the number */ return (newopts); } + +static void +usage() +{ + (void)fprintf(stderr, +"usage: ps [-aChjlmrSTuvwx] [-O|o fmt] [-p pid] [-t tty]\n\t [-M core] [-N system] [-W swap]\n ps [-L]\n"); + exit(1); +}