Improvements to 'ps -p <x>'. If <x> is a process id that does not exist, then

just print the header (if any) and exit, thus matching the behavior on -stable
and other OS's.

Also adds support for <x> being a comma-separated list of processes, and does
a much better checking for invalid-values of <x>, such as 'ps -p someword'.

Reviewed by:	mentioned on freebsd-current
MFC after:	10 days
This commit is contained in:
Garance A Drosehn 2004-03-17 22:46:58 +00:00
parent 7e7a65a6fa
commit 4e8b6a6fb0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=127149
2 changed files with 104 additions and 21 deletions

View File

@ -45,7 +45,10 @@
.Op Fl N Ar system
.Op Fl O Ar fmt
.Op Fl o Ar fmt
.Op Fl p Ar pid
.Oo Fl p Ar pid Ns Xo
.Op , Ns Ar pid Ns No ...
.Xc
.Oc
.Op Fl t Ar tty
.Oo Fl U Ar username Ns Xo
.Op , Ns Ar username Ns No ...
@ -146,7 +149,7 @@ This causes the printed header to use the specified string instead of
the standard header.
.It Fl p
Display information associated with the specified process
.Tn ID .
.Tn ID(s) .
.It Fl r
Sort by current cpu usage, instead of by process
.Tn ID .

View File

@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
@ -99,6 +100,7 @@ static void scanvars(void);
static void dynsizevars(KINFO *);
static void sizevars(void);
static void usage(void);
static pid_t *getpids(const char *, int *);
static uid_t *getuids(const char *, int *);
static char dfmt[] = "pid,tt,state,time,command";
@ -125,10 +127,10 @@ main(int argc, char *argv[])
struct varent *vent;
struct winsize ws;
dev_t ttydev;
pid_t pid;
pid_t *pids;
uid_t *uids;
int all, ch, flag, i, _fmt, lineno, nentries, nocludge, dropgid;
int prtheader, wflag, what, xflg, uid, nuids, showthreads;
int prtheader, wflag, what, xflg, pid, uid, npids, nuids, showthreads;
char *cols;
char errbuf[_POSIX2_LINE_MAX];
const char *cp, *nlistf, *memf;
@ -168,9 +170,8 @@ main(int argc, char *argv[])
}
all = _fmt = prtheader = wflag = xflg = 0;
pid = -1;
nuids = 0;
uids = NULL;
npids = nuids = 0;
pids = uids = NULL;
ttydev = NODEV;
dropgid = 0;
memf = nlistf = _PATH_DEVNULL;
@ -239,7 +240,7 @@ main(int argc, char *argv[])
break;
#endif
case 'p':
pid = atol(optarg);
pids = getpids(optarg, &npids);
xflg = 1;
break;
case 'r':
@ -333,7 +334,7 @@ main(int argc, char *argv[])
parsefmt(dfmt, 0);
/* XXX - should be cleaner */
if (!all && ttydev == NODEV && pid == -1 && !nuids) {
if (!all && ttydev == NODEV && !npids && !nuids) {
if ((uids = malloc(sizeof (*uids))) == NULL)
errx(1, "malloc failed");
nuids = 1;
@ -354,9 +355,9 @@ main(int argc, char *argv[])
} else if (ttydev != NODEV) {
what = KERN_PROC_TTY | showthreads;
flag = ttydev;
} else if (pid != -1) {
} else if (npids == 1) {
what = KERN_PROC_PID | showthreads;
flag = pid;
flag = *pids;
} else {
what = showthreads != 0 ? KERN_PROC_ALL : KERN_PROC_PROC;
flag = 0;
@ -365,15 +366,18 @@ main(int argc, char *argv[])
/*
* select procs
*/
if ((kp = kvm_getprocs(kd, what, flag, &nentries)) == 0 || nentries < 0)
kp = kvm_getprocs(kd, what, flag, &nentries);
if ((kp == 0 && nentries != 0) || nentries < 0)
errx(1, "%s", kvm_geterr(kd));
if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL)
errx(1, "malloc failed");
for (i = nentries; --i >= 0; ++kp) {
kinfo[i].ki_p = kp;
if (needuser)
saveuser(&kinfo[i]);
dynsizevars(&kinfo[i]);
if (nentries > 0) {
if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL)
errx(1, "malloc failed");
for (i = nentries; --i >= 0; ++kp) {
kinfo[i].ki_p = kp;
if (needuser)
saveuser(&kinfo[i]);
dynsizevars(&kinfo[i]);
}
}
sizevars();
@ -395,6 +399,13 @@ main(int argc, char *argv[])
if (xflg == 0 && ((&kinfo[i])->ki_p->ki_tdev == NODEV ||
((&kinfo[i])->ki_p->ki_flag & P_CONTROLT ) == 0))
continue;
if (npids > 1) {
for (pid = 0; pid < npids; pid++)
if ((&kinfo[i])->ki_p->ki_pid == pids[pid])
break;
if (pid == npids)
continue;
}
if (nuids > 1) {
for (uid = 0; uid < nuids; uid++)
if ((&kinfo[i])->ki_p->ki_uid == uids[uid])
@ -419,6 +430,75 @@ main(int argc, char *argv[])
exit(eval);
}
#define BSD_PID_MAX 99999 /* Copy of PID_MAX from sys/proc.h */
pid_t *
getpids(const char *arg, int *npids)
{
char copyarg[32];
char *copyp, *endp;
pid_t *pids, *morepids;
int alloc;
long tempid;
alloc = 0;
*npids = 0;
pids = NULL;
while (*arg != '\0') {
while (*arg != '\0' && strchr(SEP, *arg) != NULL)
arg++;
if (*arg == '\0' || strchr(SEP, *arg) != NULL)
tempid = 0;
else {
copyp = copyarg;
endp = copyarg + sizeof(copyarg) - 1;
while (*arg != '\0' && strchr(SEP, *arg) == NULL &&
copyp <= endp)
*copyp++ = *arg++;
if (copyp > endp) {
*endp = '\0';
tempid = -1;
while (*arg != '\0' &&
strchr(SEP, *arg) == NULL)
arg++;
} else {
*copyp = '\0';
errno = 0;
tempid = strtol(copyarg, &endp, 10);
}
/*
* Write warning messages for any values which
* would never be a valid process number.
*/
if (*endp != '\0' || tempid < 0 || copyarg == endp) {
warnx("invalid process number: %s", copyarg);
errno = ERANGE;
} else if (errno != 0 || tempid > BSD_PID_MAX) {
warnx("process number too large: %s", copyarg);
errno = ERANGE;
}
if (errno == ERANGE) {
/* Ignore this value from the given list. */
continue;
}
}
if (*npids >= alloc) {
alloc = (alloc + 1) << 1;
morepids = realloc(pids, alloc * sizeof (*pids));
if (morepids == NULL) {
free(pids);
errx(1, "realloc failed");
}
pids = morepids;
}
pids[(*npids)++] = tempid;
}
if (!*npids)
errx(1, "No valid process numbers specified");
return (pids);
}
uid_t *
getuids(const char *arg, int *nuids)
{
@ -669,8 +749,8 @@ usage(void)
{
(void)fprintf(stderr, "%s\n%s\n%s\n",
"usage: ps [-aCHhjlmrSTuvwxZ] [-O|o fmt] [-p pid] [-t tty] [-U user]",
" [-M core] [-N system]",
"usage: ps [-aCHhjlmrSTuvwxZ] [-O|o fmt] [-p pid[,pid]] [-t tty]",
" [-U user[,user]] [-M core] [-N system]",
" ps [-L]");
exit(1);
}