When using the procfs for extracting process information, extract
also process start time, process arguments and session leadership status. The procfs fallback is also used when kvm_openfiles() completely fails (e.g. when /dev/mem is not readable). Solves PR 7772, though the final implementation is different.
This commit is contained in:
parent
9fc25cf0bc
commit
f848d2ec0c
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: extern.h,v 1.13 1999/03/26 22:36:02 bgrayson Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.14 1999/10/15 19:31:24 jdolecek Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993, 1994
|
||||
|
@ -68,7 +68,8 @@ void pmem __P((KINFO *, VARENT *));
|
|||
void pnice __P((KINFO *, VARENT *));
|
||||
void pri __P((KINFO *, VARENT *));
|
||||
void printheader __P((void));
|
||||
struct kinfo_proc * procfs_getprocs __P((int, int, int*));
|
||||
KINFO *getkinfo_procfs __P((int, int, int*));
|
||||
char **procfs_getargv __P((const struct kinfo_proc *, int));
|
||||
void pvar __P((KINFO *, VARENT *));
|
||||
void rssize __P((KINFO *, VARENT *));
|
||||
void runame __P((KINFO *, VARENT *));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: print.c,v 1.44 1999/10/11 09:18:09 mrg Exp $ */
|
||||
/* $NetBSD: print.c,v 1.45 1999/10/15 19:31:24 jdolecek Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993, 1994
|
||||
|
@ -38,7 +38,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: print.c,v 1.44 1999/10/11 09:18:09 mrg Exp $");
|
||||
__RCSID("$NetBSD: print.c,v 1.45 1999/10/15 19:31:24 jdolecek Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -68,7 +68,7 @@ __RCSID("$NetBSD: print.c,v 1.44 1999/10/11 09:18:09 mrg Exp $");
|
|||
#include "ps.h"
|
||||
|
||||
extern kvm_t *kd;
|
||||
extern int needenv, needcomm, commandonly;
|
||||
extern int needenv, needcomm, commandonly, dontuseprocfs;
|
||||
|
||||
static char *cmdpart __P((char *));
|
||||
static void printval __P((char *, VAR *));
|
||||
|
@ -144,6 +144,7 @@ command(ki, ve)
|
|||
{
|
||||
VAR *v;
|
||||
int left;
|
||||
static int use_procfs=0;
|
||||
char **argv, **p, *name;
|
||||
|
||||
v = ve->var;
|
||||
|
@ -156,7 +157,7 @@ command(ki, ve)
|
|||
left = v->width;
|
||||
} else
|
||||
left = -1;
|
||||
if (needenv) {
|
||||
if (needenv && kd) {
|
||||
argv = kvm_getenvv(kd, ki->ki_p, termwidth);
|
||||
if ((p = argv) != NULL) {
|
||||
while (*p) {
|
||||
|
@ -169,7 +170,13 @@ command(ki, ve)
|
|||
if (needcomm) {
|
||||
name = KI_PROC(ki)->p_comm;
|
||||
if (!commandonly) {
|
||||
argv = NULL;
|
||||
if (kd && !use_procfs)
|
||||
argv = kvm_getargv(kd, ki->ki_p, termwidth);
|
||||
if (argv == NULL && !dontuseprocfs) {
|
||||
argv = procfs_getargv(ki->ki_p, termwidth);
|
||||
use_procfs = 1;
|
||||
}
|
||||
if ((p = argv) != NULL) {
|
||||
while (*p) {
|
||||
fmt_puts(*p, &left);
|
||||
|
@ -182,6 +189,10 @@ command(ki, ve)
|
|||
fmt_puts(name, &left);
|
||||
fmt_putc(')', &left);
|
||||
}
|
||||
if (use_procfs) {
|
||||
free(argv[0]);
|
||||
free(argv);
|
||||
}
|
||||
} else {
|
||||
fmt_puts(name, &left);
|
||||
}
|
||||
|
@ -549,7 +560,7 @@ getpcpu(k)
|
|||
static int failure;
|
||||
|
||||
if (!nlistread)
|
||||
failure = donlist();
|
||||
failure = (kd) ? donlist() : 1;
|
||||
if (failure)
|
||||
return (0.0);
|
||||
|
||||
|
@ -588,7 +599,7 @@ getpmem(k)
|
|||
int szptudot;
|
||||
|
||||
if (!nlistread)
|
||||
failure = donlist();
|
||||
failure = (kd) ? donlist() : 1;
|
||||
if (failure)
|
||||
return (0.0);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: procfs_ops.c,v 1.5 1999/05/09 19:23:38 thorpej Exp $ */
|
||||
/* $NetBSD: procfs_ops.c,v 1.6 1999/10/15 19:31:25 jdolecek Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999 The NetBSD Foundation, Inc.
|
||||
|
@ -42,6 +42,7 @@
|
|||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/resource.h> /* for rusage */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
|
@ -52,6 +53,8 @@
|
|||
#include <err.h>
|
||||
#include <kvm.h>
|
||||
|
||||
#include "ps.h"
|
||||
|
||||
/* Assume that no process status file will ever be larger than this. */
|
||||
#define STATUS_SIZE 8192
|
||||
|
||||
|
@ -70,8 +73,7 @@
|
|||
}
|
||||
|
||||
static int verify_procfs_fd __P((int, const char *));
|
||||
static int parsekinfo __P((const char *, struct kinfo_proc *));
|
||||
struct kinfo_proc *procfs_getprocs __P((int, int, int *));
|
||||
static int parsekinfo __P((const char *, KINFO *));
|
||||
|
||||
static int
|
||||
verify_procfs_fd(fd, path)
|
||||
|
@ -97,15 +99,16 @@ verify_procfs_fd(fd, path)
|
|||
}
|
||||
|
||||
static int
|
||||
parsekinfo(path, kp)
|
||||
parsekinfo(path, ki)
|
||||
const char *path;
|
||||
struct kinfo_proc *kp;
|
||||
KINFO *ki;
|
||||
{
|
||||
char fullpath[MAXPATHLEN];
|
||||
int dirfd, fd, nbytes, devmajor, devminor;
|
||||
struct timeval usertime, systime, starttime;
|
||||
char buff[STATUS_SIZE];
|
||||
char flagstr[256];
|
||||
struct kinfo_proc *kp = ki->ki_p;
|
||||
|
||||
/*
|
||||
* Verify that /proc/<pid> is a procfs file (and that no one has
|
||||
|
@ -131,7 +134,6 @@ parsekinfo(path, kp)
|
|||
* Don't print warning, as the process may have died since our
|
||||
* scan of the directory entries.
|
||||
*/
|
||||
close(fd);
|
||||
return -1; /* Process may no longer exist. */
|
||||
}
|
||||
|
||||
|
@ -174,6 +176,14 @@ parsekinfo(path, kp)
|
|||
kp->kp_proc.p_rtime.tv_sec = usertime.tv_sec + systime.tv_sec;
|
||||
kp->kp_proc.p_rtime.tv_usec = usertime.tv_usec + systime.tv_usec;
|
||||
|
||||
/* if starttime.[u]sec is != -1, it's in-memory process */
|
||||
if (starttime.tv_sec != -1 && starttime.tv_usec != -1) {
|
||||
kp->kp_proc.p_flag |= P_INMEM;
|
||||
ki->ki_u.u_valid = 1;
|
||||
ki->ki_u.u_start.tv_sec = starttime.tv_sec;
|
||||
ki->ki_u.u_start.tv_usec = starttime.tv_usec;
|
||||
}
|
||||
|
||||
/*
|
||||
* CPU time isn't shown unless the ki_u.u_valid flag is set.
|
||||
* Unfortunately, we don't have access to that here.
|
||||
|
@ -183,11 +193,15 @@ parsekinfo(path, kp)
|
|||
if (strstr(flagstr, "ctty"))
|
||||
kp->kp_proc.p_flag |= P_CONTROLT;
|
||||
|
||||
/* Set the flag for whether or not this process is session leader */
|
||||
if (strstr(flagstr, "sldr"))
|
||||
kp->kp_eproc.e_flag |= EPROC_SLEADER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct kinfo_proc *
|
||||
procfs_getprocs(op, arg, cnt)
|
||||
KINFO *
|
||||
getkinfo_procfs(op, arg, cnt)
|
||||
int op, arg;
|
||||
int *cnt;
|
||||
{
|
||||
|
@ -195,6 +209,7 @@ procfs_getprocs(op, arg, cnt)
|
|||
int procdirfd, nbytes, knum = 0, maxknum = 0;
|
||||
char *direntbuff;
|
||||
struct kinfo_proc *kp;
|
||||
KINFO *ki;
|
||||
int mib[4];
|
||||
size_t len;
|
||||
struct statfs procfsstat;
|
||||
|
@ -250,8 +265,8 @@ procfs_getprocs(op, arg, cnt)
|
|||
err(1, "sysctl to fetch maxproc");
|
||||
maxknum *= 2; /* Double it, to be really paranoid. */
|
||||
|
||||
kp = (struct kinfo_proc *) malloc(sizeof(struct kinfo_proc) * maxknum);
|
||||
memset(kp, 0, sizeof(struct kinfo_proc) * maxknum);
|
||||
kp = (struct kinfo_proc *) calloc(sizeof(struct kinfo_proc)*maxknum, 1);
|
||||
ki = (KINFO *) calloc(sizeof(KINFO)*maxknum, 1);
|
||||
|
||||
/* Read in a batch of entries at a time. */
|
||||
while ((knum < maxknum) &&
|
||||
|
@ -268,7 +283,8 @@ procfs_getprocs(op, arg, cnt)
|
|||
continue;
|
||||
if (strcmp(dp->d_name, "curproc") == 0)
|
||||
continue;
|
||||
if (parsekinfo(dp->d_name, &kp[knum]) != 0)
|
||||
ki[knum].ki_p = &kp[knum];
|
||||
if (parsekinfo(dp->d_name, &ki[knum]) != 0)
|
||||
continue;
|
||||
/*
|
||||
* Now check some of the flags. If the newest entry
|
||||
|
@ -323,5 +339,80 @@ procfs_getprocs(op, arg, cnt)
|
|||
|
||||
*cnt = knum;
|
||||
close(procdirfd);
|
||||
return kp;
|
||||
/* free unused memory */
|
||||
if (knum < maxknum) {
|
||||
kp = realloc(kp, sizeof(*kp) * knum);
|
||||
ki = realloc(ki, sizeof(*ki) * knum);
|
||||
for(; knum >= 0; knum--)
|
||||
ki[knum].ki_p = &kp[knum];
|
||||
}
|
||||
return ki;
|
||||
}
|
||||
|
||||
/*
|
||||
* return process arguments, possibly ones used when exec()ing
|
||||
* the process; return the array as two element array, first is
|
||||
* argv[0], second element is all the other args separated by spaces
|
||||
*/
|
||||
char **
|
||||
procfs_getargv(kp, nchr)
|
||||
const struct kinfo_proc *kp;
|
||||
int nchr;
|
||||
{
|
||||
char fullpath[MAXPATHLEN], *buf, *name, *args, **argv;
|
||||
int fd, num;
|
||||
ssize_t len;
|
||||
size_t idx;
|
||||
|
||||
/* Open /proc/<pid>/cmdline, and parse it into the argv array */
|
||||
snprintf(fullpath, MAXPATHLEN, "/proc/%d/cmdline", kp->kp_proc.p_pid);
|
||||
fd = open(fullpath, O_RDONLY, 0);
|
||||
if (fd == -1 || verify_procfs_fd(fd, fullpath)) {
|
||||
/*
|
||||
* Don't print warning, as the process may have died since our
|
||||
* scan of the directory entries.
|
||||
*/
|
||||
return NULL; /* Process may no longer exist. */
|
||||
}
|
||||
|
||||
buf = (char *)malloc(nchr+1);
|
||||
len = read(fd, buf, nchr);
|
||||
close(fd);
|
||||
if (len == -1) {
|
||||
warnx("procfs_getargv");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
num = 1;
|
||||
args = NULL;
|
||||
name = buf;
|
||||
/* substitute any \0's with space */
|
||||
for(idx=0; idx < len; idx++) {
|
||||
if (buf[idx] == '\0') {
|
||||
if (!args)
|
||||
args = &buf[idx+1];
|
||||
else
|
||||
buf[idx] = ' ';
|
||||
num++;
|
||||
}
|
||||
}
|
||||
buf[len] = '\0'; /* end the string */
|
||||
|
||||
/* if the name is the same as the p_comm, just enclosed
|
||||
* in parentheses, remove the parentheses */
|
||||
if (num == 1 && name[0] == '(' && name[len-1] == ')'
|
||||
&& strncmp(name+1, kp->kp_proc.p_comm, len-2) == 0)
|
||||
{
|
||||
len -= 2;
|
||||
strncpy(name, name+1, len);
|
||||
name[len] = '\0';
|
||||
}
|
||||
|
||||
argv = (char **) malloc(3*sizeof(char *));
|
||||
argv[0] = name;
|
||||
argv[1] = args;
|
||||
argv[2] = NULL;
|
||||
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
|
55
bin/ps/ps.c
55
bin/ps/ps.c
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ps.c,v 1.28 1999/03/27 21:38:08 bgrayson Exp $ */
|
||||
/* $NetBSD: ps.c,v 1.29 1999/10/15 19:31:25 jdolecek Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993, 1994
|
||||
|
@ -43,7 +43,7 @@ __COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\n\
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: ps.c,v 1.28 1999/03/27 21:38:08 bgrayson Exp $");
|
||||
__RCSID("$NetBSD: ps.c,v 1.29 1999/10/15 19:31:25 jdolecek Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -90,6 +90,7 @@ int needuser, needcomm, needenv, commandonly;
|
|||
|
||||
enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT;
|
||||
|
||||
static KINFO *getkinfo_kvm __P((kvm_t *, int, int, int *, int));
|
||||
static char *kludge_oldps_options __P((char *));
|
||||
static int pscomp __P((const void *, const void *));
|
||||
static void saveuser __P((KINFO *));
|
||||
|
@ -112,7 +113,6 @@ main(argc, argv)
|
|||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
struct kinfo_proc *kp;
|
||||
struct varent *vent;
|
||||
struct winsize ws;
|
||||
gid_t egid = getegid();
|
||||
|
@ -305,8 +305,14 @@ main(argc, argv)
|
|||
(void)setegid(egid);
|
||||
|
||||
kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf);
|
||||
if (kd == 0)
|
||||
if (kd == 0) {
|
||||
if (dontuseprocfs)
|
||||
errx(1, "%s", errbuf);
|
||||
else {
|
||||
warnx("kvm_openfiles: %s", errbuf);
|
||||
fprintf(stderr, "ps: falling back to /proc-based lookup\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (nlistf == NULL && memf == NULL && swapf == NULL)
|
||||
(void)setgid(getgid());
|
||||
|
@ -319,10 +325,11 @@ main(argc, argv)
|
|||
* and adjusting header widths as appropiate.
|
||||
*/
|
||||
scanvars();
|
||||
|
||||
/*
|
||||
* select procs
|
||||
*/
|
||||
if ((kp = kvm_getprocs(kd, what, flag, &nentries)) == 0)
|
||||
if (!kd || !(kinfo = getkinfo_kvm(kd, what, flag, &nentries, needuser)))
|
||||
{
|
||||
/* If/when the /proc-based code is ripped out
|
||||
* again, make sure all references to the -K
|
||||
|
@ -339,14 +346,15 @@ main(argc, argv)
|
|||
* mounted) to grab as much information as we can.
|
||||
* The guts of emulating kvm_getprocs() is in
|
||||
* the file procfs_ops.c. */
|
||||
if (kd)
|
||||
warnx("%s.", kvm_geterr(kd));
|
||||
if (dontuseprocfs) {
|
||||
exit(1);
|
||||
}
|
||||
/* procfs_getprocs supports all but the
|
||||
* KERN_PROC_RUID flag. */
|
||||
kp=procfs_getprocs(what, flag, &nentries);
|
||||
if (kp == 0) {
|
||||
kinfo = getkinfo_procfs(what, flag, &nentries);
|
||||
if (kinfo == 0) {
|
||||
errx(1, "fallback /proc-based lookup also failed. %s",
|
||||
"Giving up...");
|
||||
}
|
||||
|
@ -354,13 +362,7 @@ main(argc, argv)
|
|||
"Warning: /proc does not provide ",
|
||||
"valid data for all fields.\n");
|
||||
}
|
||||
if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL)
|
||||
err(1, "%s", "");
|
||||
for (i = nentries; --i >= 0; ++kp) {
|
||||
kinfo[i].ki_p = kp;
|
||||
if (needuser)
|
||||
saveuser(&kinfo[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* print header
|
||||
*/
|
||||
|
@ -396,6 +398,29 @@ main(argc, argv)
|
|||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static KINFO *
|
||||
getkinfo_kvm(kd, what, flag, nentriesp, needuser)
|
||||
kvm_t *kd;
|
||||
int what, flag, *nentriesp, needuser;
|
||||
{
|
||||
struct kinfo_proc *kp;
|
||||
KINFO *kinfo=NULL;
|
||||
size_t i;
|
||||
|
||||
if ((kp = kvm_getprocs(kd, what, flag, nentriesp)) != 0)
|
||||
{
|
||||
if ((kinfo = malloc((*nentriesp) * sizeof(*kinfo))) == NULL)
|
||||
err(1, "%s", "");
|
||||
for (i = *nentriesp; --i >= 0; ++kp) {
|
||||
kinfo[i].ki_p = kp;
|
||||
if (needuser)
|
||||
saveuser(&kinfo[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return (kinfo);
|
||||
}
|
||||
|
||||
static void
|
||||
scanvars()
|
||||
{
|
||||
|
@ -425,7 +450,7 @@ saveuser(ki)
|
|||
struct usave *usp;
|
||||
|
||||
usp = &ki->ki_u;
|
||||
if (kvm_read(kd, (u_long)&KI_PROC(ki)->p_addr->u_stats,
|
||||
if (kd && 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
|
||||
|
|
Loading…
Reference in New Issue