diff options
Diffstat (limited to 'usr/src/cmd/ps/ucbps.c')
| -rw-r--r-- | usr/src/cmd/ps/ucbps.c | 1186 |
1 files changed, 1186 insertions, 0 deletions
diff --git a/usr/src/cmd/ps/ucbps.c b/usr/src/cmd/ps/ucbps.c new file mode 100644 index 0000000000..4731f260e9 --- /dev/null +++ b/usr/src/cmd/ps/ucbps.c @@ -0,0 +1,1186 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +/* + * ps -- print things about processes. + */ + +#define _SYSCALL32 + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <pwd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mkdev.h> +#include <unistd.h> +#include <stdlib.h> +#include <limits.h> +#include <dirent.h> +#include <procfs.h> +#include <sys/param.h> +#include <sys/ttold.h> +#include <libelf.h> +#include <gelf.h> +#include <locale.h> +#include <wctype.h> +#include <stdarg.h> +#include <sys/proc.h> +#include <priv_utils.h> + +#define NTTYS 2 /* max ttys that can be specified with the -t option */ + /* only one tty can be specified with SunOS ps */ +#define SIZ 30 /* max processes that can be specified with -p and -g */ +#define ARGSIZ 30 /* size of buffer holding args for -t, -p, -u options */ + +#define FSTYPE_MAX 8 + +struct psent { + psinfo_t *psinfo; + char *psargs; + int found; +}; + +static int tplen, maxlen, twidth; +static char hdr[81]; +static struct winsize win; + +static int retcode = 1; +static int lflg; /* long format */ +static int uflg; /* user-oriented output */ +static int aflg; /* Display all processes */ +static int eflg; /* Display environment as well as arguments */ +static int gflg; /* Display process group leaders */ +static int tflg; /* Processes running on specific terminals */ +static int rflg; /* Running processes only flag */ +static int Sflg; /* Accumulated time plus all reaped children */ +static int xflg; /* Include processes with no controlling tty */ +static int cflg; /* Display command name */ +static int vflg; /* Virtual memory-oriented output */ +static int nflg; /* Numerical output */ +static int pflg; /* Specific process id passed as argument */ +static int Uflg; /* Update private database, ups_data */ +static int errflg; + +static char *gettty(); +static char argbuf[ARGSIZ]; +static char *parg; +static char *p1; /* points to successive option arguments */ +static uid_t my_uid; +static char stdbuf[BUFSIZ]; + +static int ndev; /* number of devices */ +static int maxdev; /* number of devl structures allocated */ + +#define DNINCR 100 +#define DNSIZE 14 +static struct devl { /* device list */ + char dname[DNSIZE]; /* device name */ + dev_t ddev; /* device number */ +} *devl; + +static struct tty { + char *tname; + dev_t tdev; +} tty[NTTYS]; /* for t option */ +static int ntty = 0; +static pid_t pidsave; +static int pidwidth; + +static char *procdir = "/proc"; /* standard /proc directory */ +static void usage(); /* print usage message and quit */ +static void getarg(void); +static void prtime(timestruc_t st); +static void przom(psinfo_t *psinfo); +static int num(char *); +static int preadargs(int, psinfo_t *, char *); +static int preadenvs(int, psinfo_t *, char *); +static int prcom(int, psinfo_t *, char *); +static int namencnt(char *, int, int); +static int pscompare(const void *, const void *); +static char *err_string(int); + +extern int scrwidth(wchar_t); /* header file? */ + +int +ucbmain(int argc, char **argv) +{ + psinfo_t info; /* process information structure from /proc */ + char *psargs = NULL; /* pointer to buffer for -w and -ww options */ + char *svpsargs = NULL; + struct psent *psent; + int entsize; + int nent; + pid_t maxpid; + + struct tty *ttyp = tty; + char *tmp; + char *p; + int c; + pid_t pid; /* pid: process id */ + pid_t ppid; /* ppid: parent process id */ + int i, found; + + size_t size; + + DIR *dirp; + struct dirent *dentp; + char psname[100]; + char asname[100]; + int pdlen; + size_t len; + + (void) setlocale(LC_ALL, ""); + + my_uid = getuid(); + + /* + * This program needs the proc_owner privilege + */ + (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_PROC_OWNER, + (char *)NULL); + + /* + * calculate width of pid fields based on configured MAXPID + * (must be at least 5 to retain output format compatibility) + */ + maxpid = (pid_t)sysconf(_SC_MAXPID); + pidwidth = 1; + while ((maxpid /= 10) > 0) + ++pidwidth; + pidwidth = pidwidth < 5 ? 5 : pidwidth; + + if (ioctl(1, TIOCGWINSZ, &win) == -1) + twidth = 80; + else + twidth = (win.ws_col == 0 ? 80 : win.ws_col); + + /* add the '-' for BSD compatibility */ + if (argc > 1) { + if (argv[1][0] != '-' && !isdigit(argv[1][0])) { + len = strlen(argv[1]) + 2; + tmp = malloc(len); + if (tmp != NULL) { + (void) snprintf(tmp, len, "%s%s", "-", argv[1]); + argv[1] = tmp; + } + } + } + + setbuf(stdout, stdbuf); + while ((c = getopt(argc, argv, "lcaengrSt:xuvwU")) != EOF) + switch (c) { + case 'g': + gflg++; /* include process group leaders */ + break; + case 'c': /* display internal command name */ + cflg++; + break; + case 'r': /* restrict output to running processes */ + rflg++; + break; + case 'S': /* display time by process and all reaped children */ + Sflg++; + break; + case 'x': /* process w/o controlling tty */ + xflg++; + break; + case 'l': /* long listing */ + lflg++; + uflg = vflg = 0; + break; + case 'u': /* user-oriented output */ + uflg++; + lflg = vflg = 0; + break; + case 'U': /* update private database ups_data */ + Uflg++; + break; + case 'w': /* increase display width */ + if (twidth < 132) + twidth = 132; + else /* second w option */ + twidth = NCARGS; + break; + case 'v': /* display virtual memory format */ + vflg++; + lflg = uflg = 0; + break; + case 'a': + /* + * display all processes except process group + * leaders and processes w/o controlling tty + */ + aflg++; + gflg++; + break; + case 'e': + /* Display environment along with aguments. */ + eflg++; + break; + case 'n': /* Display numerical output */ + nflg++; + break; + case 't': /* restrict output to named terminal */ +#define TSZ 30 + tflg++; + gflg++; + xflg = 0; + + p1 = optarg; + do { /* only loop through once (NTTYS = 2) */ + parg = argbuf; + if (ntty >= NTTYS-1) + break; + getarg(); + if ((p = malloc(TSZ+1)) == NULL) { + (void) fprintf(stderr, + "ps: no memory\n"); + exit(1); + } + p[0] = '\0'; + size = TSZ; + if (isdigit(*parg)) { + (void) strcpy(p, "tty"); + size -= 3; + } + + (void) strncat(p, parg, size); + ttyp->tdev = PRNODEV; + if (parg && *parg == '?') + xflg++; + else { + char nambuf[TSZ+6]; /* for /dev/+\0 */ + struct stat64 s; + (void) strcpy(nambuf, "/dev/"); + (void) strcat(nambuf, p); + if (stat64(nambuf, &s) == 0) + ttyp->tdev = s.st_rdev; + } + ttyp++->tname = p; + ntty++; + } while (*p1); + break; + default: /* error on ? */ + errflg++; + break; + } + + if (errflg) + usage(); + + if (optind + 1 < argc) { /* more than one additional argument */ + (void) fprintf(stderr, "ps: too many arguments\n"); + usage(); + } + + /* + * The -U option is obsolete. Attempts to use it cause ps to exit + * without printing anything. + */ + if (Uflg) + exit(0); + + if (optind < argc) { /* user specified a specific proc id */ + pflg++; + p1 = argv[optind]; + parg = argbuf; + getarg(); + if (!num(parg)) { + (void) fprintf(stderr, + "ps: %s is an invalid non-numeric argument for a process id\n", parg); + usage(); + } + pidsave = (pid_t)atol(parg); + aflg = rflg = xflg = 0; + gflg++; + } + + if (tflg) + ttyp->tname = NULL; + + /* allocate an initial guess for the number of processes */ + entsize = 1024; + psent = malloc(entsize * sizeof (struct psent)); + if (psent == NULL) { + (void) fprintf(stderr, "ps: no memory\n"); + exit(1); + } + nent = 0; /* no active entries yet */ + + if (lflg) { + (void) sprintf(hdr, + " F UID%*s%*s %%C PRI NI SZ RSS " + "WCHAN S TT TIME COMMAND", pidwidth + 1, "PID", + pidwidth + 1, "PPID"); + } else if (uflg) { + if (nflg) + (void) sprintf(hdr, + " UID%*s %%CPU %%MEM SZ RSS " + "TT S START TIME COMMAND", + pidwidth + 1, "PID"); + else + (void) sprintf(hdr, + "USER %*s %%CPU %%MEM SZ RSS " + "TT S START TIME COMMAND", + pidwidth + 1, "PID"); + } else if (vflg) { + (void) sprintf(hdr, + "%*s TT S TIME SIZE RSS %%CPU %%MEM " + "COMMAND", pidwidth + 1, "PID"); + } else + (void) sprintf(hdr, "%*s TT S TIME COMMAND", + pidwidth + 1, "PID"); + + twidth = twidth - strlen(hdr) + 6; + (void) printf("%s\n", hdr); + + if (twidth > PRARGSZ && (psargs = malloc(twidth)) == NULL) { + (void) fprintf(stderr, "ps: no memory\n"); + exit(1); + } + svpsargs = psargs; + + /* + * Determine which processes to print info about by searching + * the /proc directory and looking at each process. + */ + if ((dirp = opendir(procdir)) == NULL) { + (void) fprintf(stderr, "ps: cannot open PROC directory %s\n", + procdir); + exit(1); + } + + (void) strcpy(psname, procdir); + pdlen = strlen(psname); + psname[pdlen++] = '/'; + + /* for each active process --- */ + while (dentp = readdir(dirp)) { + int psfd; /* file descriptor for /proc/nnnnn/psinfo */ + int asfd; /* file descriptor for /proc/nnnnn/as */ + + if (dentp->d_name[0] == '.') /* skip . and .. */ + continue; + (void) strcpy(psname + pdlen, dentp->d_name); + (void) strcpy(asname, psname); + (void) strcat(psname, "/psinfo"); + (void) strcat(asname, "/as"); +retry: + if ((psfd = open(psname, O_RDONLY)) == -1) + continue; + asfd = -1; + if (psargs != NULL || eflg) { + + /* now we need the proc_owner privilege */ + (void) __priv_bracket(PRIV_ON); + + asfd = open(asname, O_RDONLY); + + /* drop proc_owner privilege after open */ + (void) __priv_bracket(PRIV_OFF); + } + + /* + * Get the info structure for the process + */ + if (read(psfd, &info, sizeof (info)) != sizeof (info)) { + int saverr = errno; + + (void) close(psfd); + if (asfd > 0) + (void) close(asfd); + if (saverr == EAGAIN) + goto retry; + if (saverr != ENOENT) + (void) fprintf(stderr, "ps: read() on %s: %s\n", + psname, err_string(saverr)); + continue; + } + (void) close(psfd); + + found = 0; + if (info.pr_lwp.pr_state == 0) /* can't happen? */ + goto closeit; + pid = info.pr_pid; + ppid = info.pr_ppid; + + /* Display only process from command line */ + if (pflg) { /* pid in arg list */ + if (pidsave == pid) + found++; + else + goto closeit; + } + + /* + * Omit "uninteresting" processes unless 'g' option. + */ + if ((ppid == 1) && !(gflg)) + goto closeit; + + /* + * Omit non-running processes for 'r' option + */ + if (rflg && + !(info.pr_lwp.pr_sname == 'O' || + info.pr_lwp.pr_sname == 'R')) + goto closeit; + + if (!found && !tflg && !aflg && info.pr_euid != my_uid) + goto closeit; + + /* + * Read the args for the -w and -ww cases + */ + if (asfd > 0) { + if ((psargs != NULL && + preadargs(asfd, &info, psargs) == -1) || + (eflg && preadenvs(asfd, &info, psargs) == -1)) { + int saverr = errno; + + (void) close(asfd); + if (saverr == EAGAIN) + goto retry; + if (saverr != ENOENT) + (void) fprintf(stderr, + "ps: read() on %s: %s\n", + asname, err_string(saverr)); + continue; + } + } else { + psargs = info.pr_psargs; + } + + if (nent >= entsize) { + entsize *= 2; + psent = (struct psent *)realloc((char *)psent, + entsize * sizeof (struct psent)); + if (psent == NULL) { + (void) fprintf(stderr, "ps: no memory\n"); + exit(1); + } + } + if ((psent[nent].psinfo = malloc(sizeof (psinfo_t))) + == NULL) { + (void) fprintf(stderr, "ps: no memory\n"); + exit(1); + } + *psent[nent].psinfo = info; + if (psargs == NULL) + psent[nent].psargs = NULL; + else { + if ((psent[nent].psargs = malloc(strlen(psargs)+1)) + == NULL) { + (void) fprintf(stderr, "ps: no memory\n"); + exit(1); + } + (void) strcpy(psent[nent].psargs, psargs); + } + psent[nent].found = found; + nent++; +closeit: + if (asfd > 0) + (void) close(asfd); + psargs = svpsargs; + } + + /* revert to non-privileged user */ + (void) __priv_relinquish(); + + (void) closedir(dirp); + + qsort((char *)psent, nent, sizeof (psent[0]), pscompare); + + for (i = 0; i < nent; i++) { + struct psent *pp = &psent[i]; + if (prcom(pp->found, pp->psinfo, pp->psargs)) { + (void) printf("\n"); + retcode = 0; + } + } + + return (retcode); +} + +static void +usage() /* print usage message and quit */ +{ + static char usage1[] = "ps [ -aceglnrSuUvwx ] [ -t term ] [ num ]"; + + (void) fprintf(stderr, "usage: %s\n", usage1); + exit(1); +} + +/* + * Read the process arguments from the process. + * This allows >PRARGSZ characters of arguments to be displayed but, + * unlike pr_psargs[], the process may have changed them. + */ +#define NARG 100 +static int +preadargs(int pfd, psinfo_t *psinfo, char *psargs) +{ + off_t argvoff = (off_t)psinfo->pr_argv; + size_t len; + char *psa = psargs; + int bsize = twidth; + int narg = NARG; + off_t argv[NARG]; + off_t argoff; + off_t nextargoff; + int i; +#ifdef _LP64 + caddr32_t argv32[NARG]; + int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64); +#endif + + if (psinfo->pr_nlwp == 0 || + strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0) + goto out; + + (void) memset(psa, 0, bsize--); + nextargoff = 0; + errno = EIO; + while (bsize > 0) { + if (narg == NARG) { + (void) memset(argv, 0, sizeof (argv)); +#ifdef _LP64 + if (is32) { + if ((i = pread(pfd, argv32, sizeof (argv32), + argvoff)) <= 0) { + if (i == 0 || errno == EIO) + break; + return (-1); + } + for (i = 0; i < NARG; i++) + argv[i] = argv32[i]; + } else +#endif + if ((i = pread(pfd, argv, sizeof (argv), + argvoff)) <= 0) { + if (i == 0 || errno == EIO) + break; + return (-1); + } + narg = 0; + } + if ((argoff = argv[narg++]) == 0) + break; + if (argoff != nextargoff && + (i = pread(pfd, psa, bsize, argoff)) <= 0) { + if (i == 0 || errno == EIO) + break; + return (-1); + } + len = strlen(psa); + psa += len; + *psa++ = ' '; + bsize -= len + 1; + nextargoff = argoff + len + 1; +#ifdef _LP64 + argvoff += is32? sizeof (caddr32_t) : sizeof (caddr_t); +#else + argvoff += sizeof (caddr_t); +#endif + } + while (psa > psargs && isspace(*(psa-1))) + psa--; + +out: + *psa = '\0'; + if (strlen(psinfo->pr_psargs) > strlen(psargs)) + (void) strcpy(psargs, psinfo->pr_psargs); + + return (0); +} + +/* + * Read environment variables from the process. + * Append them to psargs if there is room. + */ +static int +preadenvs(int pfd, psinfo_t *psinfo, char *psargs) +{ + off_t envpoff = (off_t)psinfo->pr_envp; + int len; + char *psa; + char *psainit; + int bsize; + int nenv = NARG; + off_t envp[NARG]; + off_t envoff; + off_t nextenvoff; + int i; +#ifdef _LP64 + caddr32_t envp32[NARG]; + int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64); +#endif + + psainit = psa = (psargs != NULL)? psargs : psinfo->pr_psargs; + len = strlen(psa); + psa += len; + bsize = twidth - len - 1; + + if (bsize <= 0 || psinfo->pr_nlwp == 0 || + strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0) + return (0); + + nextenvoff = 0; + errno = EIO; + while (bsize > 0) { + if (nenv == NARG) { + (void) memset(envp, 0, sizeof (envp)); +#ifdef _LP64 + if (is32) { + if ((i = pread(pfd, envp32, sizeof (envp32), + envpoff)) <= 0) { + if (i == 0 || errno == EIO) + break; + return (-1); + } + for (i = 0; i < NARG; i++) + envp[i] = envp32[i]; + } else +#endif + if ((i = pread(pfd, envp, sizeof (envp), + envpoff)) <= 0) { + if (i == 0 || errno == EIO) + break; + return (-1); + } + nenv = 0; + } + if ((envoff = envp[nenv++]) == 0) + break; + if (envoff != nextenvoff && + (i = pread(pfd, psa+1, bsize, envoff)) <= 0) { + if (i == 0 || errno == EIO) + break; + return (-1); + } + *psa++ = ' '; + len = strlen(psa); + psa += len; + bsize -= len + 1; + nextenvoff = envoff + len + 1; +#ifdef _LP64 + envpoff += is32? sizeof (caddr32_t) : sizeof (caddr_t); +#else + envpoff += sizeof (caddr_t); +#endif + } + while (psa > psainit && isspace(*(psa-1))) + psa--; + *psa = '\0'; + + return (0); +} + +/* + * getarg() finds the next argument in list and copies arg into argbuf. + * p1 first pts to arg passed back from getopt routine. p1 is then + * bumped to next character that is not a comma or blank -- p1 NULL + * indicates end of list. + */ + +static void +getarg() +{ + char *parga; + int c; + + while ((c = *p1) != '\0' && (c == ',' || isspace(c))) + p1++; + + parga = argbuf; + while ((c = *p1) != '\0' && c != ',' && !isspace(c)) { + if (parga < argbuf + ARGSIZ - 1) + *parga++ = c; + p1++; + } + *parga = '\0'; + + while ((c = *p1) != '\0' && (c == ',' || isspace(c))) + p1++; +} + +static char * +devlookup(dev_t ddev) +{ + struct devl *dp; + int i; + + for (dp = devl, i = 0; i < ndev; dp++, i++) { + if (dp->ddev == ddev) + return (dp->dname); + } + return (NULL); +} + +static char * +devadd(char *name, dev_t ddev) +{ + struct devl *dp; + int leng, start, i; + + if (ndev == maxdev) { + maxdev += DNINCR; + devl = realloc(devl, maxdev * sizeof (struct devl)); + if (devl == NULL) { + (void) fprintf(stderr, + "ps: not enough memory for %d devices\n", maxdev); + exit(1); + } + } + dp = &devl[ndev++]; + + dp->ddev = ddev; + if (name == NULL) { + (void) strcpy(dp->dname, "??"); + return (dp->dname); + } + + leng = strlen(name); + /* Strip off /dev/ */ + if (leng < DNSIZE + 4) + (void) strcpy(dp->dname, &name[5]); + else { + start = leng - (DNSIZE - 1); + + for (i = start; i < leng && name[i] != '/'; i++) + ; + if (i == leng) + (void) strlcpy(dp->dname, &name[start], DNSIZE); + else + (void) strlcpy(dp->dname, &name[i+1], DNSIZE); + } + return (dp->dname); +} + +/* + * gettty returns the user's tty number or ? if none. + */ +static char * +gettty(psinfo_t *psinfo) +{ + extern char *_ttyname_dev(dev_t, char *, size_t); + char devname[TTYNAME_MAX]; + char *retval; + + if (psinfo->pr_ttydev == PRNODEV) + return ("?"); + + if ((retval = devlookup(psinfo->pr_ttydev)) != NULL) + return (retval); + + retval = _ttyname_dev(psinfo->pr_ttydev, devname, sizeof (devname)); + + return (devadd(retval, psinfo->pr_ttydev)); +} + +/* + * Print percent from 16-bit binary fraction [0 .. 1] + * Round up .01 to .1 to indicate some small percentage (the 0x7000 below). + */ +static void +prtpct(ushort_t pct) +{ + uint_t value = pct; /* need 32 bits to compute with */ + + value = ((value * 1000) + 0x7000) >> 15; /* [0 .. 1000] */ + (void) printf("%3u.%u", value / 10, value % 10); +} + +/* + * Print info about the process. + */ +static int +prcom(int found, psinfo_t *psinfo, char *psargs) +{ + char *cp; + char *tp; + char *psa; + long tm; + int i, wcnt, length; + wchar_t wchar; + struct tty *ttyp; + + /* + * If process is zombie, call print routine and return. + */ + if (psinfo->pr_nlwp == 0) { + if (tflg && !found) + return (0); + else { + przom(psinfo); + return (1); + } + } + + /* + * Get current terminal. If none ("?") and 'a' is set, don't print + * info. If 't' is set, check if term is in list of desired terminals + * and print it if it is. + */ + i = 0; + tp = gettty(psinfo); + + if (*tp == '?' && !found && !xflg) + return (0); + + if (!(*tp == '?' && aflg) && tflg && !found) { + int match = 0; + char *other = NULL; + for (ttyp = tty; ttyp->tname != NULL; ttyp++) { + /* + * Look for a name match + */ + if (strcmp(tp, ttyp->tname) == 0) { + match = 1; + break; + } + /* + * Look for same device under different names. + */ + if ((other == NULL) && + (psinfo->pr_ttydev == ttyp->tdev)) + other = ttyp->tname; + } + if (!match) { + if (other == NULL) + return (0); + tp = other; + } + } + + if (lflg) + (void) printf("%2x", psinfo->pr_flag & 0377); + if (uflg) { + if (!nflg) { + struct passwd *pwd; + + if ((pwd = getpwuid(psinfo->pr_euid)) != NULL) + /* USER */ + (void) printf("%-8.8s", pwd->pw_name); + else + /* UID */ + (void) printf(" %7.7d", (int)psinfo->pr_euid); + } else { + (void) printf(" %5d", (int)psinfo->pr_euid); /* UID */ + } + } else if (lflg) + (void) printf(" %5d", (int)psinfo->pr_euid); /* UID */ + + (void) printf("%*d", pidwidth + 1, (int)psinfo->pr_pid); /* PID */ + if (lflg) + (void) printf("%*d", pidwidth + 1, + (int)psinfo->pr_ppid); /* PPID */ + if (lflg) + (void) printf("%3d", psinfo->pr_lwp.pr_cpu & 0377); /* CP */ + if (uflg) { + prtpct(psinfo->pr_pctcpu); /* %CPU */ + prtpct(psinfo->pr_pctmem); /* %MEM */ + } + if (lflg) { + (void) printf("%4d", psinfo->pr_lwp.pr_pri); /* PRI */ + (void) printf("%3d", psinfo->pr_lwp.pr_nice); /* NICE */ + } + if (lflg || uflg) { + if (psinfo->pr_flag & SSYS) /* SZ */ + (void) printf(" 0"); + else if (psinfo->pr_size) + (void) printf("%5lu", (ulong_t)psinfo->pr_size); + else + (void) printf(" ?"); + if (psinfo->pr_flag & SSYS) /* RSS */ + (void) printf(" 0"); + else if (psinfo->pr_rssize) + (void) printf("%5lu", (ulong_t)psinfo->pr_rssize); + else + (void) printf(" ?"); + } + if (lflg) { /* WCHAN */ + if (psinfo->pr_lwp.pr_sname != 'S') { + (void) printf(" "); + } else if (psinfo->pr_lwp.pr_wchan) { + (void) printf(" %+8.8lx", + (ulong_t)psinfo->pr_lwp.pr_wchan); + } else { + (void) printf(" ?"); + } + } + if ((tplen = strlen(tp)) > 9) + maxlen = twidth - tplen + 9; + else + maxlen = twidth; + + if (!lflg) + (void) printf(" %-8.14s", tp); /* TTY */ + (void) printf(" %c", psinfo->pr_lwp.pr_sname); /* STATE */ + if (lflg) + (void) printf(" %-8.14s", tp); /* TTY */ + if (uflg) + prtime(psinfo->pr_start); /* START */ + + /* time just for process */ + tm = psinfo->pr_time.tv_sec; + if (Sflg) { /* calculate time for process and all reaped children */ + tm += psinfo->pr_ctime.tv_sec; + if (psinfo->pr_time.tv_nsec + psinfo->pr_ctime.tv_nsec + >= 1000000000) + tm += 1; + } + + (void) printf(" %2ld:%.2ld", tm / 60, tm % 60); /* TIME */ + + if (vflg) { + if (psinfo->pr_flag & SSYS) /* SZ */ + (void) printf(" 0"); + else if (psinfo->pr_size) + (void) printf("%5lu", (ulong_t)psinfo->pr_size); + else + (void) printf(" ?"); + if (psinfo->pr_flag & SSYS) /* SZ */ + (void) printf(" 0"); + else if (psinfo->pr_rssize) + (void) printf("%5lu", (ulong_t)psinfo->pr_rssize); + else + (void) printf(" ?"); + prtpct(psinfo->pr_pctcpu); /* %CPU */ + prtpct(psinfo->pr_pctmem); /* %MEM */ + } + if (cflg) { /* CMD */ + wcnt = namencnt(psinfo->pr_fname, 16, maxlen); + (void) printf(" %.*s", wcnt, psinfo->pr_fname); + return (1); + } + /* + * PRARGSZ == length of cmd arg string. + */ + if (psargs == NULL) { + psa = &psinfo->pr_psargs[0]; + i = PRARGSZ; + tp = &psinfo->pr_psargs[PRARGSZ]; + } else { + psa = psargs; + i = strlen(psargs); + tp = psa + i; + } + + for (cp = psa; cp < tp; /* empty */) { + if (*cp == 0) + break; + length = mbtowc(&wchar, cp, MB_LEN_MAX); + if (length < 0 || !iswprint(wchar)) { + (void) printf(" [ %.16s ]", psinfo->pr_fname); + return (1); + } + cp += length; + } + wcnt = namencnt(psa, i, maxlen); +#if 0 + /* dumps core on really long strings */ + (void) printf(" %.*s", wcnt, psa); +#else + (void) putchar(' '); + (void) fwrite(psa, 1, wcnt, stdout); +#endif + return (1); +} + +/* + * Print starting time of process unless process started more than 24 hours + * ago, in which case the date is printed. + */ +static void +prtime(timestruc_t st) +{ + char sttim[26]; + static time_t tim = 0L; + time_t starttime; + + if (tim == 0L) + tim = time((time_t *)0); + starttime = st.tv_sec; + if (tim - starttime > 24*60*60) { + (void) strftime(sttim, sizeof (sttim), "%b %d", + localtime(&starttime)); + } else { + (void) strftime(sttim, sizeof (sttim), "%H:%M:%S", + localtime(&starttime)); + } + (void) printf("%9.9s", sttim); +} + +static void +przom(psinfo_t *psinfo) +{ + long tm; + + if (lflg) + (void) printf("%2x", psinfo->pr_flag & 0377); + if (uflg) { + struct passwd *pwd; + + if ((pwd = getpwuid(psinfo->pr_euid)) != NULL) + (void) printf("%-8.8s", pwd->pw_name); /* USER */ + else + (void) printf(" %7.7d", (int)psinfo->pr_euid); /* UID */ + } else if (lflg) + (void) printf(" %5d", (int)psinfo->pr_euid); /* UID */ + + (void) printf("%*d", pidwidth + 1, (int)psinfo->pr_pid); /* PID */ + if (lflg) + (void) printf("%*d", pidwidth + 1, + (int)psinfo->pr_ppid); /* PPID */ + if (lflg) + (void) printf(" 0"); /* CP */ + if (uflg) { + prtpct(0); /* %CPU */ + prtpct(0); /* %MEM */ + } + if (lflg) { + (void) printf("%4d", psinfo->pr_lwp.pr_pri); /* PRI */ + (void) printf(" "); /* NICE */ + } + if (lflg || uflg) { + (void) printf(" 0"); /* SZ */ + (void) printf(" 0"); /* RSS */ + } + if (lflg) + (void) printf(" "); /* WCHAN */ + (void) printf(" "); /* TTY */ + (void) printf("%c", psinfo->pr_lwp.pr_sname); /* STATE */ + if (uflg) + (void) printf(" "); /* START */ + + /* time just for process */ + tm = psinfo->pr_time.tv_sec; + if (Sflg) { /* calculate time for process and all reaped children */ + tm += psinfo->pr_ctime.tv_sec; + if (psinfo->pr_time.tv_nsec + psinfo->pr_ctime.tv_nsec + >= 1000000000) + tm += 1; + } + (void) printf(" %2ld:%.2ld", tm / 60, tm % 60); /* TIME */ + + if (vflg) { + (void) printf(" 0"); /* SZ */ + (void) printf(" 0"); /* RSS */ + prtpct(0); /* %CPU */ + prtpct(0); /* %MEM */ + } + (void) printf(" %.*s", maxlen, " <defunct>"); +} + +/* + * Returns true iff string is all numeric. + */ +static int +num(char *s) +{ + int c; + + if (s == NULL) + return (0); + c = *s; + do { + if (!isdigit(c)) + return (0); + } while ((c = *++s) != '\0'); + return (1); +} + +/* + * Function to compute the number of printable bytes in a multibyte + * command string ("internationalization"). + */ +static int +namencnt(char *cmd, int eucsize, int scrsize) +{ + int eucwcnt = 0, scrwcnt = 0; + int neucsz, nscrsz; + wchar_t wchar; + + while (*cmd != '\0') { + if ((neucsz = mbtowc(&wchar, cmd, MB_LEN_MAX)) < 0) + return (8); /* default to use for illegal chars */ + if ((nscrsz = scrwidth(wchar)) == 0) + return (8); + if (eucwcnt + neucsz > eucsize || scrwcnt + nscrsz > scrsize) + break; + eucwcnt += neucsz; + scrwcnt += nscrsz; + cmd += neucsz; + } + return (eucwcnt); +} + +static int +pscompare(const void *v1, const void *v2) +{ + const struct psent *p1 = v1; + const struct psent *p2 = v2; + int i; + + if (uflg) + i = p2->psinfo->pr_pctcpu - p1->psinfo->pr_pctcpu; + else if (vflg) + i = p2->psinfo->pr_rssize - p1->psinfo->pr_rssize; + else + i = p1->psinfo->pr_ttydev - p2->psinfo->pr_ttydev; + if (i == 0) + i = p1->psinfo->pr_pid - p2->psinfo->pr_pid; + return (i); +} + +static char * +err_string(int err) +{ + static char buf[32]; + char *str = strerror(err); + + if (str == NULL) + (void) sprintf(str = buf, "Errno #%d", err); + + return (str); +} |
