#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1990, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif
#if 0
#ifndef lint
static char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94";
#endif
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/ps/ps.c,v 1.110 2005/02/09 17:37:38 ru Exp $");
#include <sys/param.h>
#ifdef __APPLE__
#include <sys/time.h>
#endif
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <sys/mount.h>
#include <sys/resourcevar.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#ifndef __APPLE__
#include <kvm.h>
#endif
#include <limits.h>
#include <locale.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ps.h"
#ifdef __APPLE__
#include <get_compat.h>
#else
#define COMPAT_MODE(func, mode) (1)
#endif
#define W_SEP " \t"
#define T_SEP ","
#ifdef LAZY_PS
#define DEF_UREAD 0
#define OPT_LAZY_f "f"
#else
#define DEF_UREAD 1
#define OPT_LAZY_f
#endif
#define isdigitch(Anychar) isdigit((u_char)(Anychar))
int cflag;
int eval;
time_t now;
int rawcpu;
int sumrusage;
int termwidth;
int totwidth;
struct velisthead varlist = STAILQ_HEAD_INITIALIZER(varlist);
#ifndef __APPLE__
static int forceuread = DEF_UREAD;
static kvm_t *kd;
#endif
static KINFO *kinfo;
static int needcomm;
static int needenv;
static int needuser;
static int optfatal;
static enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT;
struct listinfo;
typedef int addelem_rtn(struct listinfo *_inf, const char *_elem);
struct listinfo {
int count;
int maxcount;
int elemsize;
addelem_rtn *addelem;
const char *lname;
union {
gid_t *gids;
pid_t *pids;
dev_t *ttys;
uid_t *uids;
void *ptr;
} l;
};
#ifndef __APPLE__
static int check_procfs(void);
#endif
static int addelem_gid(struct listinfo *, const char *);
static int addelem_pid(struct listinfo *, const char *);
static int addelem_tty(struct listinfo *, const char *);
static int addelem_uid(struct listinfo *, const char *);
static void add_list(struct listinfo *, const char *);
static void dynsizevars(KINFO *);
static void *expand_list(struct listinfo *);
#ifndef __APPLE__
static const char *
fmt(char **(*)(kvm_t *, const struct kinfo_proc *, int),
KINFO *, char *, int);
#endif
static void free_list(struct listinfo *);
static void init_list(struct listinfo *, addelem_rtn, int, const char *);
static char *kludge_oldps_options(const char *, char *, const char *, int *);
static int pscomp(const void *, const void *);
static void saveuser(KINFO *);
static void scanvars(void);
static void sizevars(void);
static void usage(int);
VAR *findvar(char *, int, char **);
static char dfmt[] = "pid,tt,state,time,command";
static char jfmt[] = "user,pid,ppid,pgid,sess,jobc,state,tt,time,command";
static char lfmt[] = "uid,pid,ppid,cpu,pri,nice,vsz,rss,wchan,state,"
"tt,time,command";
static char o1[] = "pid";
static char o2[] = "tt,state,time,command";
static char ufmt[] = "user,pid,%cpu,%mem,vsz,rss,tt,state,start,time,command";
static char vfmt[] = "pid,state,time,sl,re,pagein,vsz,rss,lim,tsiz,"
"%cpu,%mem,command";
#ifndef __APPLE__
static char Zfmt[] = "label";
#endif
char p_dfmt[] = "pid tty time command=CMD";
char p_ffmt[] = "uid pid ppid cpu=C start=STIME tty time command=CMD";
char p_uffmt[] = "user pid ppid cpu=C start=STIME tty time command=CMD";
char p_lfmt[] = "uid pid ppid flags cpu pri nice vsz=SZ rss wchan state=S paddr=ADDR tty time command=CMD";
char mfmt[] = "user pid tt %cpu state pri stime utime command";
int eflg = 0;
int mflg = 0;
int print_thread_num = 0;
int print_all_thread = 0;
#define PS_ARGS (u03 ? "aACcdeEfg:G:hjLlMmO:o:p:rSTt:U:u:vwx" : \
"aACcdeEgG:hjLlMmO:o:p:rSTt:U:uvwx")
int
main(int argc, char *argv[])
{
struct listinfo gidlist, pgrplist, pidlist;
struct listinfo ruidlist, sesslist, ttylist, uidlist;
struct kinfo_proc *kp;
KINFO *next_KINFO;
struct varent *vent;
struct winsize ws;
#ifndef __APPLE__
const char *nlistf, *memf;
#endif
char *cols;
int all, ch, elem, flag, _fmt, i, lineno;
int nentries, nkept, nselectors;
int prtheader, showthreads, wflag, what, xkeep, xkeep_implied;
#ifndef __APPLE__
char errbuf[_POSIX2_LINE_MAX];
#endif
struct kinfo_proc *kprocbuf;
int j;
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
size_t bufSize = 0;
size_t orig_bufSize = 0;
int local_error=0;
int retry_count = 0;
int u03 = COMPAT_MODE("bin/ps", "unix2003");
#ifdef __APPLE__
int dflag = 0;
#endif
(void) setlocale(LC_ALL, "");
time(&now);
if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0')
termwidth = atoi(cols);
else 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(PS_ARGS, argv[1], argv[2], &u03);
all = _fmt = nselectors = optfatal = 0;
prtheader = showthreads = wflag = xkeep_implied = 0;
xkeep = -1;
init_list(&gidlist, addelem_gid, sizeof(gid_t), "group");
init_list(&pgrplist, addelem_pid, sizeof(pid_t), "process group");
init_list(&pidlist, addelem_pid, sizeof(pid_t), "process id");
init_list(&ruidlist, addelem_uid, sizeof(uid_t), "ruser");
init_list(&sesslist, addelem_pid, sizeof(pid_t), "session id");
init_list(&ttylist, addelem_tty, sizeof(dev_t), "tty");
init_list(&uidlist, addelem_uid, sizeof(uid_t), "user");
#ifndef __APPLE__
memf = nlistf = _PATH_DEVNULL;
#endif
while ((ch = getopt(argc, argv, PS_ARGS)) != -1)
switch ((char)ch) {
#ifdef __APPLE__
case 'd':
dflag = 1;
#endif
case 'A':
nselectors++;
all = xkeep = 1;
break;
case 'a':
nselectors++;
all = 1;
break;
case 'C':
rawcpu = 1;
break;
case 'c':
cflag = 1;
break;
case 'e':
if (u03) {
nselectors++;
all = xkeep = 1;
break;
}
case 'E':
needenv = 1;
eflg = 1;
break;
#ifdef LAZY_PS
case 'f':
if (getuid() == 0 || getgid() == 0)
forceuread = 1;
break;
#endif
case 'f':
termwidth = UNLIMITED;
if (u03 && uidlist.count == 0) {
parsefmt(p_ffmt, 0);
VAR *v = findvar("command", 0, NULL);
if (v) {
v->width = 64;
}
} else {
parsefmt(p_uffmt, 0);
}
_fmt = 1;
break;
case 'G':
add_list(&gidlist, optarg);
xkeep_implied = 1;
nselectors++;
break;
case 'g':
if (!u03) break;
add_list(&pgrplist, optarg);
xkeep_implied = 1;
nselectors++;
break;
#ifndef __APPLE__
case 'H':
showthreads = KERN_PROC_INC_THREAD;
break;
#endif
case 'h':
prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
break;
case 'j':
parsefmt(jfmt, 0);
_fmt = 1;
jfmt[0] = '\0';
break;
case 'L':
showkey();
exit(0);
case 'l':
parsefmt(u03 ? p_lfmt : lfmt, 0);
_fmt = 1;
lfmt[0] = '\0';
break;
case 'M':
#ifndef __APPLE__
memf = optarg;
#else
parsefmt(mfmt, 0);
_fmt = 1;
mfmt[0] = '\0';
mflg = 1;
#endif
break;
case 'm':
sortby = SORTMEM;
break;
#ifndef __APPLE__
case 'N':
nlistf = optarg;
break;
#endif
case 'O':
parsefmt(o1, 1);
parsefmt(optarg, 1);
parsefmt(o2, 1);
o1[0] = o2[0] = '\0';
_fmt = 1;
break;
case 'o':
parsefmt(optarg, 1);
_fmt = 1;
break;
case 'p':
add_list(&pidlist, optarg);
nselectors++;
break;
case 'r':
sortby = SORTCPU;
break;
case 'S':
sumrusage = 1;
break;
case 'T':
if ((optarg = ttyname(STDIN_FILENO)) == NULL)
errx(1, "stdin: not a terminal");
case 't':
add_list(&ttylist, optarg);
xkeep_implied = 1;
nselectors++;
break;
case 'U':
add_list(&ruidlist, optarg);
xkeep_implied = 1;
nselectors++;
break;
case 'u':
if (u03) {
add_list(&uidlist, optarg);
xkeep_implied = 1;
nselectors++;
break;
}
parsefmt(ufmt, 0);
sortby = SORTCPU;
_fmt = 1;
ufmt[0] = '\0';
break;
case 'v':
parsefmt(vfmt, 0);
sortby = SORTMEM;
_fmt = 1;
vfmt[0] = '\0';
break;
case 'w':
if (wflag)
termwidth = UNLIMITED;
else if (termwidth < 131)
termwidth = 131;
wflag++;
break;
case 'X':
xkeep = 0;
break;
case 'x':
xkeep = 1;
break;
case '?':
default:
usage(u03);
}
argc -= optind;
argv += optind;
#ifdef __APPLE__
if (!isatty(STDOUT_FILENO))
termwidth = UNLIMITED;
#endif
#ifndef __APPLE__
if (needenv == 1 && check_procfs() == 0)
warnx("Process environment requires procfs(5)");
#endif
while (*argv) {
if (!isdigitch(**argv))
break;
add_list(&pidlist, *argv);
argv++;
}
if (*argv) {
fprintf(stderr, "%s: illegal argument: %s\n",
getprogname(), *argv);
usage(u03);
}
if (optfatal)
exit(1);
if (xkeep < 0)
xkeep = xkeep_implied;
#if FIXME
kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
if (kd == 0)
errx(1, "%s", errbuf);
#endif
if (!_fmt) {
if (u03 && uidlist.count != 0) {
parsefmt("uid", 0);
}
parsefmt(u03 ? p_dfmt : dfmt, 0);
}
if (nselectors == 0) {
uidlist.l.ptr = malloc(sizeof(uid_t));
if (uidlist.l.ptr == NULL)
errx(1, "malloc failed");
nselectors = 1;
uidlist.count = uidlist.maxcount = 1;
*uidlist.l.uids = getuid();
}
scanvars();
what = KERN_PROC_ALL;
flag = 0;
if (nselectors == 1) {
if (gidlist.count == 1) {
#if 0
what = KERN_PROC_RGID | showthreads;
flag = *gidlist.l.gids;
nselectors = 0;
#endif
} else if (pgrplist.count == 1) {
what = KERN_PROC_PGRP | showthreads;
flag = *pgrplist.l.pids;
nselectors = 0;
} else if (pidlist.count == 1) {
what = KERN_PROC_PID | showthreads;
flag = *pidlist.l.pids;
nselectors = 0;
} else if (ruidlist.count == 1) {
what = KERN_PROC_RUID | showthreads;
flag = *ruidlist.l.uids;
nselectors = 0;
} else if (sesslist.count == 1) {
what = KERN_PROC_SESSION | showthreads;
flag = *sesslist.l.pids;
nselectors = 0;
} else if (ttylist.count == 1) {
what = KERN_PROC_TTY | showthreads;
flag = *ttylist.l.ttys;
nselectors = 0;
} else if (uidlist.count == 1) {
what = (xkeep ? KERN_PROC_RUID : KERN_PROC_UID) | showthreads;
flag = *uidlist.l.uids;
nselectors = 0;
}
}
nentries = -1;
#if FIXME
kp = kvm_getprocs(kd, what, flag, &nentries);
if ((kp == NULL && nentries > 0) || (kp != NULL && nentries < 0))
errx(1, "%s", kvm_geterr(kd));
#else
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = what;
mib[3] = flag;
if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
perror("Failure calling sysctl");
return 0;
}
kprocbuf= kp = (struct kinfo_proc *)malloc(bufSize);
retry_count = 0;
orig_bufSize = bufSize;
for(retry_count=0; ; retry_count++) {
local_error = 0;
bufSize = orig_bufSize;
if ((local_error = sysctl(mib, 4, kp, &bufSize, NULL, 0)) < 0) {
if (retry_count < 1000) {
sleep(1);
continue;
}
perror("Failure calling sysctl");
return 0;
} else if (local_error == 0) {
break;
}
sleep(1);
}
nentries = bufSize / sizeof(struct kinfo_proc);
#endif
nkept = 0;
if (nentries > 0) {
if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL)
errx(1, "malloc failed");
for (i = nentries; --i >= 0; ++kp) {
#ifdef __APPLE__
if (kp->kp_proc.p_pid == 0) {
continue;
}
#endif
#ifdef __APPLE__
if (dflag && (kp->kp_proc.p_pid == kp->kp_eproc.e_pgid))
continue;
#endif
if (pidlist.count > 0) {
for (elem = 0; elem < pidlist.count; elem++)
if (kp->kp_proc.p_pid == pidlist.l.pids[elem])
goto keepit;
}
if (xkeep == 0) {
if ((kp->kp_eproc.e_tdev == NODEV ||
(kp->kp_proc.p_flag & P_CONTROLT) == 0))
continue;
}
if (all || nselectors == 0)
goto keepit;
if (gidlist.count > 0) {
for (elem = 0; elem < gidlist.count; elem++)
if (kp->kp_eproc.e_pcred.p_rgid == gidlist.l.gids[elem])
goto keepit;
}
if (pgrplist.count > 0) {
for (elem = 0; elem < pgrplist.count; elem++)
if (kp->kp_eproc.e_pgid ==
pgrplist.l.pids[elem])
goto keepit;
}
if (ruidlist.count > 0) {
for (elem = 0; elem < ruidlist.count; elem++)
if (kp->kp_eproc.e_pcred.p_ruid ==
ruidlist.l.uids[elem])
goto keepit;
}
#if 0
if (sesslist.count > 0) {
for (elem = 0; elem < sesslist.count; elem++)
if (kp->ki_sid == sesslist.l.pids[elem])
goto keepit;
}
#endif
if (ttylist.count > 0) {
for (elem = 0; elem < ttylist.count; elem++)
if (kp->kp_eproc.e_tdev == ttylist.l.ttys[elem])
goto keepit;
}
if (uidlist.count > 0) {
for (elem = 0; elem < uidlist.count; elem++)
if (kp->kp_eproc.e_ucred.cr_uid == uidlist.l.uids[elem])
goto keepit;
}
continue;
keepit:
next_KINFO = &kinfo[nkept];
next_KINFO->ki_p = kp;
get_task_info(next_KINFO);
#ifndef __APPLE__
next_KINFO->ki_pcpu = getpcpu(next_KINFO);
if (sortby == SORTMEM)
next_KINFO->ki_memsize = kp->ki_tsize +
kp->ki_dsize + kp->ki_ssize;
#endif
if (needuser)
saveuser(next_KINFO);
dynsizevars(next_KINFO);
nkept++;
}
}
sizevars();
printheader();
if (nkept == 0)
exit(1);
qsort(kinfo, nkept, sizeof(KINFO), pscomp);
for (i = lineno = 0; i < nkept; i++) {
if(mflg) {
print_all_thread = 1;
for(j=0; j < kinfo[i].thread_count; j++) {
print_thread_num = j;
STAILQ_FOREACH(vent, &varlist, next_ve) {
(vent->var->oproc)(&kinfo[i], vent);
if (STAILQ_NEXT(vent, next_ve) != NULL)
(void)putchar(' ');
}
(void)putchar('\n');
if (prtheader && lineno++ == prtheader - 4) {
(void)putchar('\n');
printheader();
lineno = 0;
}
}
print_all_thread = 0;
} else {
STAILQ_FOREACH(vent, &varlist, next_ve) {
(vent->var->oproc)(&kinfo[i], vent);
if (STAILQ_NEXT(vent, next_ve) != NULL)
(void)putchar(' ');
}
(void)putchar('\n');
if (prtheader && lineno++ == prtheader - 4) {
(void)putchar('\n');
printheader();
lineno = 0;
}
}
}
for (i = 0; i < nkept; i++) {
if (kinfo[i].invalid_tinfo == 0 && kinfo[i].thread_count)
free(kinfo[i].thval);
}
free(kprocbuf);
free(kinfo);
free_list(&gidlist);
free_list(&pidlist);
free_list(&pgrplist);
free_list(&ruidlist);
free_list(&sesslist);
free_list(&ttylist);
free_list(&uidlist);
exit(eval);
}
static int
addelem_gid(struct listinfo *inf, const char *elem)
{
struct group *grp;
const char *nameorID;
char *endp;
u_long bigtemp;
if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) {
if (*elem == '\0')
warnx("Invalid (zero-length) %s name", inf->lname);
else
warnx("%s name too long: %s", inf->lname, elem);
optfatal = 1;
return (0);
}
grp = NULL;
nameorID = "named";
errno = 0;
bigtemp = strtoul(elem, &endp, 10);
if (errno == 0 && *endp == '\0' && bigtemp <= GID_MAX) {
nameorID = "name or ID matches";
grp = getgrgid((gid_t)bigtemp);
}
if (grp == NULL)
grp = getgrnam(elem);
if (grp == NULL) {
warnx("No %s %s '%s'", inf->lname, nameorID, elem);
optfatal = 1;
return (0);
}
if (inf->count >= inf->maxcount)
expand_list(inf);
inf->l.gids[(inf->count)++] = grp->gr_gid;
return (1);
}
#define BSD_PID_MAX 99999
static int
addelem_pid(struct listinfo *inf, const char *elem)
{
char *endp;
long tempid;
if (*elem == '\0') {
warnx("Invalid (zero-length) process id");
optfatal = 1;
return (0);
}
errno = 0;
tempid = strtol(elem, &endp, 10);
if (*endp != '\0' || tempid < 0 || elem == endp) {
warnx("Invalid %s: %s", inf->lname, elem);
errno = ERANGE;
} else if (errno != 0 || tempid > BSD_PID_MAX) {
warnx("%s too large: %s", inf->lname, elem);
errno = ERANGE;
}
if (errno == ERANGE) {
optfatal = 1;
return (0);
}
if (inf->count >= inf->maxcount)
expand_list(inf);
inf->l.pids[(inf->count)++] = tempid;
return (1);
}
#undef BSD_PID_MAX
static int
addelem_tty(struct listinfo *inf, const char *elem)
{
const char *ttypath;
struct stat sb;
char pathbuf[PATH_MAX], pathbuf2[PATH_MAX];
ttypath = NULL;
pathbuf2[0] = '\0';
switch (*elem) {
case '/':
ttypath = elem;
break;
case 'c':
if (strcmp(elem, "co") == 0) {
ttypath = _PATH_CONSOLE;
break;
}
default:
strlcpy(pathbuf, _PATH_DEV, sizeof(pathbuf));
strlcat(pathbuf, elem, sizeof(pathbuf));
ttypath = pathbuf;
if (strncmp(pathbuf, _PATH_TTY, strlen(_PATH_TTY)) == 0)
break;
if (strcmp(pathbuf, _PATH_CONSOLE) == 0)
break;
strlcpy(pathbuf2, _PATH_TTY, sizeof(pathbuf2));
strlcat(pathbuf2, elem, sizeof(pathbuf2));
if (stat(pathbuf2, &sb) == 0 && S_ISCHR(sb.st_mode)) {
ttypath = NULL;
break;
}
break;
}
if (ttypath) {
#ifdef __APPLE__
if (access(ttypath, F_OK) == -1 || stat(ttypath, &sb) == -1) {
#else
if (stat(ttypath, &sb) == -1) {
#endif
if (pathbuf2[0] != '\0')
warn("%s and %s", pathbuf2, ttypath);
else
warn("%s", ttypath);
optfatal = 1;
return (0);
}
if (!S_ISCHR(sb.st_mode)) {
if (pathbuf2[0] != '\0')
warnx("%s and %s: Not a terminal", pathbuf2,
ttypath);
else
warnx("%s: Not a terminal", ttypath);
optfatal = 1;
return (0);
}
}
if (inf->count >= inf->maxcount)
expand_list(inf);
inf->l.ttys[(inf->count)++] = sb.st_rdev;
return (1);
}
static int
addelem_uid(struct listinfo *inf, const char *elem)
{
struct passwd *pwd;
char *endp;
u_long bigtemp;
if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) {
if (*elem == '\0')
warnx("Invalid (zero-length) %s name", inf->lname);
else
warnx("%s name too long: %s", inf->lname, elem);
optfatal = 1;
return (0);
}
pwd = getpwnam(elem);
if (pwd == NULL) {
errno = 0;
bigtemp = strtoul(elem, &endp, 10);
if (errno != 0 || *endp != '\0' || bigtemp > UID_MAX)
warnx("No %s named '%s'", inf->lname, elem);
else {
pwd = getpwuid((uid_t)bigtemp);
if (pwd == NULL)
warnx("No %s name or ID matches '%s'",
inf->lname, elem);
}
}
if (pwd == NULL) {
optfatal = 1;
return (0);
}
if (inf->count >= inf->maxcount)
expand_list(inf);
inf->l.uids[(inf->count)++] = pwd->pw_uid;
return (1);
}
static void
add_list(struct listinfo *inf, const char *argp)
{
const char *savep;
char *cp, *endp;
int toolong;
char elemcopy[PATH_MAX];
if (*argp == 0)
inf->addelem(inf, elemcopy);
while (*argp != '\0') {
while (*argp != '\0' && strchr(W_SEP, *argp) != NULL)
argp++;
savep = argp;
toolong = 0;
cp = elemcopy;
if (strchr(T_SEP, *argp) == NULL) {
endp = elemcopy + sizeof(elemcopy) - 1;
while (*argp != '\0' && cp <= endp &&
strchr(W_SEP T_SEP, *argp) == NULL)
*cp++ = *argp++;
if (cp > endp)
toolong = 1;
}
if (!toolong) {
*cp = '\0';
inf->addelem(inf, elemcopy);
} else {
while (*argp != '\0' && strchr(W_SEP T_SEP,
*argp) == NULL)
argp++;
warnx("Value too long: %.*s", (int)(argp - savep),
savep);
optfatal = 1;
}
while (*argp != '\0' && strchr(W_SEP, *argp) != NULL)
argp++;
if (*argp != '\0' && strchr(T_SEP, *argp) != NULL) {
argp++;
#if 0
if (*argp == '\0')
inf->addelem(inf, argp);
#endif
}
}
}
static void *
expand_list(struct listinfo *inf)
{
void *newlist;
int newmax;
newmax = (inf->maxcount + 1) << 1;
newlist = realloc(inf->l.ptr, newmax * inf->elemsize);
if (newlist == NULL) {
free(inf->l.ptr);
errx(1, "realloc to %d %ss failed", newmax, inf->lname);
}
inf->maxcount = newmax;
inf->l.ptr = newlist;
return (newlist);
}
static void
free_list(struct listinfo *inf)
{
inf->count = inf->elemsize = inf->maxcount = 0;
if (inf->l.ptr != NULL)
free(inf->l.ptr);
inf->addelem = NULL;
inf->lname = NULL;
inf->l.ptr = NULL;
}
static void
init_list(struct listinfo *inf, addelem_rtn artn, int elemsize,
const char *lname)
{
inf->count = inf->maxcount = 0;
inf->elemsize = elemsize;
inf->addelem = artn;
inf->lname = lname;
inf->l.ptr = NULL;
}
VARENT *
find_varentry(VAR *v)
{
struct varent *vent;
STAILQ_FOREACH(vent, &varlist, next_ve) {
if (strcmp(vent->var->name, v->name) == 0)
return vent;
}
return NULL;
}
static void
scanvars(void)
{
struct varent *vent;
VAR *v;
STAILQ_FOREACH(vent, &varlist, next_ve) {
v = vent->var;
if (v->flag & DSIZ) {
v->dwidth = v->width;
v->width = 0;
}
if (v->flag & USER)
needuser = 1;
if (v->flag & COMM)
needcomm = 1;
}
}
static void
dynsizevars(KINFO *ki)
{
struct varent *vent;
VAR *v;
int i;
STAILQ_FOREACH(vent, &varlist, next_ve) {
v = vent->var;
if (!(v->flag & DSIZ))
continue;
i = (v->sproc)( ki);
if (v->width < i)
v->width = i;
if (v->width > v->dwidth)
v->width = v->dwidth;
}
}
static void
sizevars(void)
{
struct varent *vent;
VAR *v;
int i;
STAILQ_FOREACH(vent, &varlist, next_ve) {
v = vent->var;
i = strlen(vent->header);
if (v->width < i)
v->width = i;
totwidth += v->width + 1;
}
totwidth--;
}
#ifndef __APPLE__
static const char *
fmt(char **(*fn)(kvm_t *, const struct kinfo_proc *, int), KINFO *ki,
char *comm, int maxlen)
{
const char *s;
s = fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen);
return (s);
}
#endif
#define UREADOK(ki) (forceuread || (KI_PROC(ki)->p_flag & P_INMEM))
static void
saveuser(KINFO *ki)
{
struct usave *usp;
#if FIXME
struct user *u_addr = (struct user *)USRSTACK;
#endif
usp = &ki->ki_u;
#if FIXME
if (UREADOK(ki) && kvm_uread(kd, KI_PROC(ki), (unsigned long)&u_addr->u_stats,
(char *)&pstats, sizeof(pstats)) == sizeof(pstats))
{
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;
#else
usp->u_valid = 0;
#endif
#if FIXME
if (needcomm && UREADOK(ki)) {
ki->ki_args = fmt(kvm_getargv, ki, KI_PROC(ki)->p_comm,
MAXCOMLEN);
} else if (needcomm) {
ki->ki_args = malloc(strlen(KI_PROC(ki)->p_comm) + 3);
sprintf(ki->ki_args, "(%s)", KI_PROC(ki)->p_comm);
} else {
ki->ki_args = NULL;
}
#else
ki->ki_args = malloc(strlen(KI_PROC(ki)->p_comm) + 3);
sprintf(ki->ki_args, "%s", KI_PROC(ki)->p_comm);
#endif
#if FIXME
if (needenv && UREADOK(ki)) {
ki->ki_env = fmt(kvm_getenvv, ki, (char *)NULL, 0);
} else if (needenv) {
ki->ki_env = malloc(3);
strcpy(ki->ki_env, "()");
} else {
ki->ki_env = NULL;
}
#else
ki->ki_env = malloc(10);
strcpy(ki->ki_env, "");
#endif
}
static int
pscomp(const void *a, const void *b)
{
int i;
#if FIXME
#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)->tasks_info.resident_size)
#endif
if (sortby == SORTCPU)
return (getpcpu((KINFO *)b) - getpcpu((KINFO *)a));
if (sortby == SORTMEM)
return (VSIZE((KINFO *)b) - VSIZE((KINFO *)a));
i = KI_EPROC((KINFO *)a)->e_tdev - KI_EPROC((KINFO *)b)->e_tdev;
if (i == 0)
i = KI_PROC((KINFO *)a)->p_pid - KI_PROC((KINFO *)b)->p_pid;
return (i);
}
static char *
kludge_oldps_options(const char *optlist, char *origval, const char *nextarg, int *u03)
{
size_t len;
char *argp, *cp, *newopts, *ns, *optp, *pidp;
argp = NULL;
if (optlist != NULL) {
for (cp = origval; *cp != '\0'; cp++) {
optp = strchr(optlist, *cp);
if ((optp != NULL) && *(optp + 1) == ':') {
argp = cp;
break;
}
}
}
if (argp != NULL && *origval == '-')
return (origval);
len = strlen(origval);
cp = origval + len - 1;
pidp = NULL;
if (*cp == 't' && *origval != '-' && cp == argp) {
if (nextarg == NULL || *nextarg == '-' || isdigitch(*nextarg))
*cp = 'T';
} else if (argp == NULL) {
if (isdigitch(*cp)) {
while (cp >= origval && (*cp == ',' || isdigitch(*cp)))
--cp;
pidp = cp + 1;
}
}
if (*origval == '-' && pidp == NULL)
return (origval);
if ((newopts = ns = malloc(len + 3)) == NULL)
errx(1, "malloc failed");
if (*origval != '-') {
*ns++ = '-';
*u03 = 0;
}
if (pidp == NULL)
strcpy(ns, origval);
else {
len = pidp - origval;
memcpy(ns, origval, len);
ns += len;
*ns++ = 'p';
strcpy(ns, pidp);
}
return (newopts);
}
#ifndef __APPLE__
static int
check_procfs(void)
{
struct statfs mnt;
if (statfs("/proc", &mnt) < 0)
return (0);
if (strcmp(mnt.f_fstypename, "procfs") != 0)
return (0);
return (1);
}
#endif
static void
usage(int u03)
{
#define SINGLE_OPTS "[-AaCcEefhjlMmrSTvwXx]"
(void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
"usage: ps " SINGLE_OPTS " [-O fmt | -o fmt] [-G gid[,gid...]]",
(u03 ? " [-g grp[,grp...]] [-u [uid,uid...]]" : " [-u]"),
" [-p pid[,pid...]] [-t tty[,tty...]] [-U user[,user...]]",
" ps [-L]");
exit(1);
}