Subject: pstat -f broken on sparc
To: NetBSD tech-userlevel mailing list <tech-userlevel@netbsd.org>
From: Julian Coleman <jdc@coris.org.uk>
List: tech-userlevel
Date: 02/18/2004 15:01:09
If you run `pstat -f` on sparc, you will get a bus error because it tries
to access an 8 byte variable on a 4 byte address. It looks like it has
been broken for quite a while (I checked back 15 months).
The problem is in getfiles() in pstat.c where it calls sysctl() with the
KERN_FILE mib. This fills in a buffer with a single (struct filelist)
followed by a number of (struct file)'s. The size of (struct filelist) is
4 bytes, so the following (struct file)'s are aligned on a 4 byte boundary.
However, because they contain an 8 byte variable (f_offset - an off_t),
they need to be aligned on an 8 byte boundary.
It seems to me that the real fix is don't return a buffer containing
different kind of structs like this. Alternatively, a workround is
appended. Comments?
J
- - 8< - - - - - - - - - - - - - Cut here - - - - - - - - - - - - - >8 - -
--- /usr/src/usr.sbin/pstat/pstat.c 2003-12-21 03:12:59.000000000 +0000
+++ pstat.c 2004-02-18 09:40:49.000000000 +0000
@@ -154,7 +154,7 @@
#endif
void filemode __P((void));
-int getfiles __P((char **, int *));
+int getfiles __P((char **, int *, int *));
int getflags __P((const struct flagbit_desc *, char *, u_int));
struct mount *
getmnt __P((struct mount *));
@@ -879,7 +879,7 @@
struct file *addr;
char flags[sizeof(filemode_flags) / sizeof(filemode_flags[0])];
char *buf;
- int len, maxfile, nfile, ovflw;
+ int len, offset, maxfile, nfile, ovflw;
static const char * const dtypes[] =
{ "???", "inode", "socket", "pipe" };
@@ -889,22 +889,22 @@
(void)printf("%3d/%3d files\n", nfile, maxfile);
return;
}
- if (getfiles(&buf, &len) == -1)
+ if (getfiles(&buf, &len, &offset) == -1)
return;
/*
* Getfiles returns in malloc'd memory a pointer to the first file
* structure, and then an array of file structs (whose addresses are
* derivable from the previous entry).
*/
- addr = ((struct filelist *)buf)->lh_first;
- fp = (struct file *)(buf + sizeof(struct filelist));
+ addr = ((struct filelist *)buf + offset)->lh_first;
+ fp = (struct file *)(buf + offset + sizeof(struct filelist));
nfile = (len - sizeof(struct filelist)) / sizeof(struct file);
(void)printf("%d/%d open files\n", nfile, maxfile);
(void)printf("%*s%s%*s TYPE FLG CNT MSG %*s%s%*s OFFSET\n",
(PTRSTRWIDTH - 4) / 2, "", " LOC", (PTRSTRWIDTH - 4) / 2, "",
(PTRSTRWIDTH - 4) / 2, "", "DATA", (PTRSTRWIDTH - 4) / 2, "");
- for (; (char *)fp < buf + len; addr = fp->f_list.le_next, fp++) {
+ for (; (char *)fp < buf + offset + len; addr = fp->f_list.le_next, fp++) {
if ((unsigned)fp->f_type > DTYPE_PIPE)
continue;
ovflw = 0;
@@ -916,7 +916,7 @@
PRWORD(ovflw, " %*d", 5, 1, fp->f_msgcount);
PRWORD(ovflw, " %*lx", PTRSTRWIDTH + 1, 2, (long)fp->f_data);
if (fp->f_offset < 0)
- PRWORD(ovflw, " %-*llx\n", PTRSTRWIDTH + 1, 2,
+ PRWORD(ovflw, " %-*lld\n", PTRSTRWIDTH + 1, 2,
(long long)fp->f_offset);
else
PRWORD(ovflw, " %-*lld\n", PTRSTRWIDTH + 1, 2,
@@ -926,11 +926,13 @@
}
int
-getfiles(abuf, alen)
+getfiles(abuf, alen, aoffset)
char **abuf;
int *alen;
+ int *aoffset;
{
size_t len;
+ int offset;
int mib[2];
char *buf;
@@ -947,14 +949,16 @@
warn("sysctl: KERN_FILE");
return (-1);
}
- if ((buf = malloc(len)) == NULL)
+ offset = len % sizeof(off_t); /* Need to align (struct file *). */
+ if ((buf = malloc(len + offset)) == NULL)
err(1, "malloc");
- if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
+ if (sysctl(mib, 2, buf + offset, &len, NULL, 0) == -1) {
warn("sysctl: KERN_FILE");
return (-1);
}
*abuf = buf;
*alen = len;
+ *aoffset = offset;
return (0);
}
- - 8< - - - - - - - - - - - - - Cut here - - - - - - - - - - - - - >8 - -
--
My other computer also runs NetBSD / Sailing at Newbiggin
http://www.netbsd.org/ / http://www.newbigginsailingclub.org/