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:
jdolecek 1999-10-15 19:31:24 +00:00
parent 9fc25cf0bc
commit f848d2ec0c
4 changed files with 166 additions and 38 deletions

View File

@ -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 *));

View File

@ -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);

View File

@ -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;
}

View File

@ -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