use err/warn from C library; lots of minor cleanup, lint
[unix-history] / usr / src / bin / ps / ps.c
index e335981..d1b2521 100644 (file)
@@ -12,7 +12,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)ps.c       5.33 (Berkeley) %G%";
+static char sccsid[] = "@(#)ps.c       5.51 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -22,19 +22,28 @@ static char sccsid[] = "@(#)ps.c    5.33 (Berkeley) %G%";
 #include <sys/proc.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/proc.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
-#include <sys/kinfo.h>
-#include <kvm.h>
+#include <sys/sysctl.h>
+
+#include <ctype.h>
+#include <err.h>
 #include <errno.h>
 #include <errno.h>
-#include <unistd.h>
-#include <stdarg.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <nlist.h>
+#include <paths.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <paths.h>
+#include <unistd.h>
+
 #include "ps.h"
 
 #include "ps.h"
 
+#ifdef SPPWAIT
+#define NEWVM
+#endif
+
 KINFO *kinfo;
 KINFO *kinfo;
-VAR *vhead, *vtail;
+struct varent *vhead, *vtail;
 
 int    eval;                   /* exit value */
 int    rawcpu;                 /* -C */
 
 int    eval;                   /* exit value */
 int    rawcpu;                 /* -C */
@@ -42,38 +51,41 @@ int sumrusage;              /* -S */
 int    termwidth;              /* width of screen (0 == infinity) */
 int    totwidth;               /* calculated width of requested variables */
 
 int    termwidth;              /* width of screen (0 == infinity) */
 int    totwidth;               /* calculated width of requested variables */
 
-static int needuser, needcomm;
+static int needuser, needcomm, needenv;
 
 
-enum sort { SORTMEM, SORTCPU } sortby;
+enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT;
 
 
-uid_t  getuid();
-char   *ttyname();
+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));
 
 
-#define DFMT   "pid tt state time command"
-#define        JFMT    "user pid ppid pgid sess jobc state tt time command"
-#define LFMT \
-       "uid pid ppid cpu pri nice vsz rss wchan state tt time command"
-#define        SFMT    "uid pid sig sigmask sigignore sigcatch state tt command"
-#define UFMT \
-       "user pid %cpu %mem vsz rss tt state start time command"
-#define        VFMT \
-       "pid state time sl re pagein vsz rss lim tsiz trs %cpu %mem command"
+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";
 
 
+kvm_t *kd;
+
+int
 main(argc, argv)
        int argc;
 main(argc, argv)
        int argc;
-       char **argv;
+       char *argv[];
 {
 {
-       extern char *optarg;
-       extern int optind;
-       register struct proc *p;
-       register size_t nentries;
-       register VAR *v;
+       register struct kinfo_proc *kp;
+       register struct varent *vent;
+       int nentries;
        register int i;
        struct winsize ws;
        dev_t ttydev;
        register int i;
        struct winsize ws;
        dev_t ttydev;
-       int all, ch, flag, fmt, lineno, pid, prtheader, uid, what, xflg;
-       int pscomp();
-       char *kludge_oldps_options();
+       int all, ch, flag, fmt, lineno, pid, prtheader, uid, wflag, what, xflg;
+       char *nlistf, *memf, *swapf, errbuf[256];
 
        if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
             ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
 
        if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
             ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
@@ -86,41 +98,54 @@ main(argc, argv)
        if (argc > 1)
                argv[1] = kludge_oldps_options(argv[1]);
 
        if (argc > 1)
                argv[1] = kludge_oldps_options(argv[1]);
 
-       fmt = 0;
-       all = xflg = 0;
+       all = fmt = prtheader = wflag = xflg = 0;
        pid = uid = -1;
        ttydev = NODEV;
        pid = uid = -1;
        ttydev = NODEV;
-       while ((ch = getopt(argc, argv, "aCghjLlmO:o:p:rSsTt:uvwx")) != EOF)
+       memf = nlistf = swapf = NULL;
+       while ((ch = getopt(argc, argv,
+           "aCeghjLlM:mN:O:o:p:rSTt:uvW:wx")) != EOF)
                switch((char)ch) {
                case 'a':
                        all = 1;
                        break;
                switch((char)ch) {
                case 'a':
                        all = 1;
                        break;
+               case 'e':                       /* XXX set ufmt */
+                       needenv = 1;
+                       break;
                case 'C':
                        rawcpu = 1;
                        break;
                case 'g':
                case 'C':
                        rawcpu = 1;
                        break;
                case 'g':
-                       break;  /* no-op */
+                       break;                  /* no-op */
                case 'h':
                        prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
                        break;
                case 'j':
                case 'h':
                        prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
                        break;
                case 'j':
-                       parsefmt(JFMT);
+                       parsefmt(jfmt);
                        fmt = 1;
                        fmt = 1;
+                       jfmt[0] = '\0';
                        break;
                        break;
-               case 'L': 
+               case 'L':
                        showkey();
                        exit(0);
                case 'l':
                        showkey();
                        exit(0);
                case 'l':
-                       parsefmt(LFMT);
+                       parsefmt(lfmt);
                        fmt = 1;
                        fmt = 1;
+                       lfmt[0] = '\0';
+                       break;
+               case 'M':
+                       memf = optarg;
                        break;
                case 'm':
                        sortby = SORTMEM;
                        break;
                        break;
                case 'm':
                        sortby = SORTMEM;
                        break;
+               case 'N':
+                       nlistf = optarg;
+                       break;
                case 'O':
                case 'O':
-                       parsefmt("pid");
+                       parsefmt(o1);
                        parsefmt(optarg);
                        parsefmt(optarg);
-                       parsefmt("tt state time command");
+                       parsefmt(o2);
+                       o1[0] = o2[0] = '\0';
                        fmt = 1;
                        break;
                case 'o':
                        fmt = 1;
                        break;
                case 'o':
@@ -137,51 +162,49 @@ main(argc, argv)
                case 'S':
                        sumrusage = 1;
                        break;
                case 'S':
                        sumrusage = 1;
                        break;
-               case 's':
-                       parsefmt(SFMT);
-                       fmt = 1;
-                       break;
                case 'T':
                        if ((optarg = ttyname(STDIN_FILENO)) == NULL)
                case 'T':
                        if ((optarg = ttyname(STDIN_FILENO)) == NULL)
-                               error("stdin: not a terminal");
+                               errx(1, "stdin: not a terminal");
                        /* FALLTHROUGH */
                case 't': {
                        /* FALLTHROUGH */
                case 't': {
-                       char *ttypath;
-                       struct stat stbuf;
-                       char pathbuf[MAXPATHLEN];
+                       struct stat sb;
+                       char *ttypath, pathbuf[MAXPATHLEN];
 
                        if (strcmp(optarg, "co") == 0)
                                ttypath = _PATH_CONSOLE;
                        else if (*optarg != '/')
 
                        if (strcmp(optarg, "co") == 0)
                                ttypath = _PATH_CONSOLE;
                        else if (*optarg != '/')
-                               (void) sprintf(ttypath = pathbuf, "%s%s",
-                                   _PATH_TTY, optarg);
+                               (void)snprintf(ttypath = pathbuf,
+                                   sizeof(pathbuf), "%s%s", _PATH_TTY, optarg);
                        else
                                ttypath = optarg;
                        else
                                ttypath = optarg;
-                       if (stat(ttypath, &stbuf) == -1) {
-                               (void)fprintf(stderr,
-                                   "ps: %s: %s\n", strerror(ttypath));
-                               exit(1);
-                       }
-                       if (!S_ISCHR(stbuf.st_mode))
-                               error("%s: not a terminal", ttypath);
-                       ttydev = stbuf.st_rdev;
+                       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 'u':
                        break;
                }
                case 'u':
-                       parsefmt(UFMT);
+                       parsefmt(ufmt);
                        sortby = SORTCPU;
                        fmt = 1;
                        sortby = SORTCPU;
                        fmt = 1;
+                       ufmt[0] = '\0';
                        break;
                case 'v':
                        break;
                case 'v':
-                       parsefmt(VFMT);
+                       parsefmt(vfmt);
                        sortby = SORTMEM;
                        fmt = 1;
                        sortby = SORTMEM;
                        fmt = 1;
+                       vfmt[0] = '\0';
+                       break;
+               case 'W':
+                       swapf = optarg;
                        break;
                case 'w':
                        break;
                case 'w':
-                       if (termwidth < 131)
-                               termwidth = 131;
-                       else
+                       if (wflag)
                                termwidth = UNLIMITED;
                                termwidth = UNLIMITED;
+                       else if (termwidth < 131)
+                               termwidth = 131;
+                       wflag++;
                        break;
                case 'x':
                        xflg = 1;
                        break;
                case 'x':
                        xflg = 1;
@@ -193,21 +216,30 @@ main(argc, argv)
        argc -= optind;
        argv += optind;
 
        argc -= optind;
        argv += optind;
 
+#define        BACKWARD_COMPATIBILITY
+#ifdef BACKWARD_COMPATIBILITY
        if (*argv) {
        if (*argv) {
-               char *nlistf, *memf = NULL, *swapf = NULL;
-
-               nlistf = *argv++;
-               if (*argv) {
-                       memf = *argv++;
-                       if (*argv)
-                               swapf = *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)
 
        if (!fmt)
-               parsefmt(DFMT);
+               parsefmt(dfmt);
 
        if (!all && ttydev == NODEV && pid == -1)  /* XXX - should be cleaner */
                uid = getuid();
 
        if (!all && ttydev == NODEV && pid == -1)  /* XXX - should be cleaner */
                uid = getuid();
@@ -221,31 +253,25 @@ main(argc, argv)
         * get proc list
         */
        if (uid != -1) {
         * get proc list
         */
        if (uid != -1) {
-               what = KINFO_PROC_UID;
+               what = KERN_PROC_UID;
                flag = uid;
        } else if (ttydev != NODEV) {
                flag = uid;
        } else if (ttydev != NODEV) {
-               what = KINFO_PROC_TTY;
+               what = KERN_PROC_TTY;
                flag = ttydev;
        } else if (pid != -1) {
                flag = ttydev;
        } else if (pid != -1) {
-               what = KINFO_PROC_PID;
+               what = KERN_PROC_PID;
                flag = pid;
        /*
         * select procs
         */
                flag = pid;
        /*
         * select procs
         */
-       if ((nentries = kvm_getprocs(what, flag)) == -1) {
-               (void) fprintf(stderr, "ps: %s\n", kvm_geterr());
-               exit(1);
-       }
-       kinfo = (KINFO *)malloc(nentries * sizeof(KINFO));
-       if (kinfo == NULL) {
-               (void)fprintf(stderr, "ps: %s\n", strerror(ENOMEM));
-               exit(1);
-       }
-       for (nentries = 0; p = kvm_nextproc(); ++nentries) {
-               kinfo[nentries].ki_p = p;
-               kinfo[nentries].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)
                if (needuser)
-                       saveuser(&kinfo[nentries]);
+                       saveuser(&kinfo[i]);
        }
        /*
         * print header
        }
        /*
         * print header
@@ -256,22 +282,22 @@ main(argc, argv)
        /*
         * sort proc list
         */
        /*
         * sort proc list
         */
-       qsort((void *)kinfo, nentries, sizeof(KINFO), pscomp);
+       qsort(kinfo, nentries, sizeof(KINFO), pscomp);
        /*
         * for each proc, call each variable output function.
         */
        for (i = lineno = 0; i < nentries; i++) {
        /*
         * for each proc, call each variable output function.
         */
        for (i = lineno = 0; i < nentries; i++) {
-               if (xflg == 0 && (kinfo[i].ki_e->e_tdev == NODEV ||
-                   (kinfo[i].ki_p->p_flag & SCTTY ) == 0))
+               if (xflg == 0 && (KI_EPROC(&kinfo[i])->e_tdev == NODEV ||
+                   (KI_PROC(&kinfo[i])->p_flag & SCTTY ) == 0))
                        continue;
                        continue;
-               for (v = vhead; v; v = v->next) {
-                       (*v->oproc)(&kinfo[i], v);
-                       if (v->next != NULL)
-                               (void) putchar(' ');
+               for (vent = vhead; vent; vent = vent->next) {
+                       (vent->var->oproc)(&kinfo[i], vent);
+                       if (vent->next != NULL)
+                               (void)putchar(' ');
                }
                }
-               (void) putchar('\n');
-               if (prtheader && lineno++ == prtheader-4) {
-                       (void) putchar('\n');
+               (void)putchar('\n');
+               if (prtheader && lineno++ == prtheader - 4) {
+                       (void)putchar('\n');
                        printheader();
                        lineno = 0;
                }
                        printheader();
                        lineno = 0;
                }
@@ -279,12 +305,15 @@ main(argc, argv)
        exit(eval);
 }
 
        exit(eval);
 }
 
+static void
 scanvars()
 {
 scanvars()
 {
+       register struct varent *vent;
        register VAR *v;
        register int i;
 
        register VAR *v;
        register int i;
 
-       for (v = vhead; v; v = v->next) {
+       for (vent = vhead; vent; vent = vent->next) {
+               v = vent->var;
                i = strlen(v->header);
                if (v->width < i)
                        v->width = i;
                i = strlen(v->header);
                if (v->width < i)
                        v->width = i;
@@ -297,49 +326,76 @@ scanvars()
        totwidth--;
 }
 
        totwidth--;
 }
 
+static char *
+fmt(fn, ki, comm, maxlen)
+       char **(*fn) __P((kvm_t *, const struct kinfo_proc *, int));
+       KINFO *ki;
+       char *comm;
+       int maxlen;
+{
+       register char *s;
+
+       if ((s =
+           fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen)) == NULL)
+               err(1, NULL);
+       return (s);
+}
 
 
-/* XXX - redo */
+static void
 saveuser(ki)
        KINFO *ki;
 {
 saveuser(ki)
        KINFO *ki;
 {
-       register struct usave *usp;
-       register struct user *up;
+       register struct usave *usp = &ki->ki_u;
+       struct pstats pstats;
+       extern char *fmt_argv();
 
 
-       if ((usp = (struct usave *)calloc(1, sizeof(struct usave))) == NULL) {
-               (void)fprintf(stderr, "ps: %s\n", strerror(errno));
-               exit(1);
-       }
-       ki->ki_u = usp;
-       up = kvm_getu(ki->ki_p);
+       if (kvm_read(kd, (u_long)&KI_PROC(ki)->p_addr->u_stats,
+                    (char *)&pstats, sizeof(pstats)) == sizeof(pstats)) {
+               /*
+                * 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.
+                */
+               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
         */
        /*
         * save arguments if needed
         */
-       ki->ki_args = needcomm ? strdup(kvm_getargs(ki->ki_p, up)) : 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_acflag = up->u_acflag;
-       }
+       if (needcomm)
+               ki->ki_args = fmt(kvm_getargv, ki, KI_PROC(ki)->p_comm,
+                   MAXCOMLEN);
+       else
+               ki->ki_args = NULL;
+       if (needenv)
+               ki->ki_env = fmt(kvm_getenvv, ki, (char *)NULL, 0);
+       else
+               ki->ki_env = NULL;
 }
 
 }
 
-pscomp(k1, k2)
-       KINFO *k1, *k2;
+static int
+pscomp(a, b)
+       const void *a, *b;
 {
        int i;
 {
        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)
 #define VSIZE(k) ((k)->ki_p->p_dsize + (k)->ki_p->p_ssize + (k)->ki_e->e_xsize)
+#endif
 
        if (sortby == SORTCPU)
 
        if (sortby == SORTCPU)
-               return (getpcpu(k2) - getpcpu(k1));
+               return (getpcpu((KINFO *)b) - getpcpu((KINFO *)a));
        if (sortby == SORTMEM)
        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)
        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);
 }
 
        return (i);
 }
 
@@ -354,7 +410,7 @@ pscomp(k1, k2)
  * 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.
  */
  * 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;
 {
 kludge_oldps_options(s)
        char *s;
 {
@@ -362,10 +418,8 @@ kludge_oldps_options(s)
        char *newopts, *ns, *cp;
 
        len = strlen(s);
        char *newopts, *ns, *cp;
 
        len = strlen(s);
-       if ((newopts = ns = malloc(len + 2)) == NULL) {
-               (void)fprintf(stderr, "ps: %s\n", strerror(errno));
-               exit(1);
-       }
+       if ((newopts = ns = malloc(len + 2)) == NULL)
+               err(1, NULL);
        /*
         * options begin with '-'
         */
        /*
         * options begin with '-'
         */
@@ -391,7 +445,7 @@ kludge_oldps_options(s)
                        --cp;
        }
        cp++;
                        --cp;
        }
        cp++;
-       bcopy(s, ns, (size_t)(cp - s)); /* copy up to trailing number */
+       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
        ns += cp - s;
        /*
         * if there's a trailing number, and not a preceding 'p' (pid) or
@@ -400,32 +454,15 @@ kludge_oldps_options(s)
        if (isdigit(*cp) && (cp == s || cp[-1] != 't' && cp[-1] != 'p' &&
            (cp - 1 == s || cp[-2] != 't')))
                *ns++ = 'p';
        if (isdigit(*cp) && (cp == s || cp[-1] != 't' && cp[-1] != 'p' &&
            (cp - 1 == s || cp[-2] != 't')))
                *ns++ = 'p';
-       (void) strcpy(ns, cp);          /* and append the number */
+       (void)strcpy(ns, cp);           /* and append the number */
 
        return (newopts);
 }
 
 
        return (newopts);
 }
 
-#ifdef lint
-/* VARARGS1 */
-error(fmt) char *fmt; { (void) fputs(fmt, stderr); exit(1); /* NOTREACHED */ }
-#else
-error(fmt)
-       char *fmt;
-{
-       va_list ap;
-
-       va_start(ap, fmt);
-       (void) fprintf(stderr, "ps: ");
-       (void) vfprintf(stderr, fmt, ap);
-       (void) fprintf(stderr, "\n");
-       va_end(ap);
-       exit(1);
-}
-#endif
-
+static void
 usage()
 {
 usage()
 {
-       (void) fprintf(stderr,
-           "usage:\tps [ -aChjlmrSsTuvwx ] [ -O|o fmt ] [ -p pid ] [ -t tty ] [ system ] [ core ] [ swap ]\n\t ps [ -L ]\n");
+       (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);
 }
        exit(1);
 }