kern.file weirdness
YONETANI Tomokazu
qhwt at myrealbox.com
Sat Nov 22 16:01:51 PST 2003
On Sat, Nov 22, 2003 at 02:22:57PM +0100, Eirik Nygaard wrote:
> On Sat, Nov 22, 2003 at 10:08:57PM +0900, YONETANI Tomokazu wrote:
> > Hello.
> >
> > On Sat, Nov 22, 2003 at 11:53:30AM +0100, Eirik Nygaard wrote:
> > > I am working on removing perlism in userland and have come over a little
> > > problem when I am rewriting sockstat. I try to get all the open fd's from
> > > the kern.file sysctl with this code:
> > > void
> > > get_files(void)
> > > {
> > > size_t size;
> > >
> > > if (sysctlbyname("kern.file", NULL, &size, NULL, 0) < 0)
> > > err(1, "sysctlbyname()");
> > > if ((files = malloc(size)) == NULL)
> > > err(1, "malloc()");
> > > if (sysctlbyname("kern.file", files, &size, NULL, 0) < 0)
> > > err(1, "sysctlbyname()");
> > >
> > > nfiles = size / sizeof(struct file);
> > > {
> > > int i;
> > > for(i = 0; i < nfiles; i++)
> > > printf("Type: %d\n", files[i].f_type);
> > > }
> > >
> > > }
> > >
> > > but it only gives me bogus results for some reason.
> > >
> > > Output:
> > > Type: -16333
> > > Type: -14424
> > > [...]
> > > Type: -14424
> > >
> > > Would be grateful if someone knows what I am doing wrong here.
> >
> > FreeBSD-current's version of sockstat has a block of code
> > which looks like this:
> >
> > static void
> > getfiles(void)
> > {
> > size_t len;
> >
> > if ((xfiles = malloc(len = sizeof *xfiles)) == NULL)
> > err(1, "malloc()");
> > while (sysctlbyname("kern.file", xfiles, &len, 0, 0) == -1) {
> > if (errno != ENOMEM)
> > err(1, "sysctlbyname()");
> > len *= 2;
> > if ((xfiles = realloc(xfiles, len)) == NULL)
> > err(1, "realloc()");
> > }
> > if (len > 0 && xfiles->xf_size != sizeof *xfiles)
> > errx(1, "struct xfile size mismatch");
> > nxfiles = len / sizeof *xfiles;
> > }
> >
> > i.e., you must resize the buffer until sysctlbyname() fails with
> > ENOMEM.
>
> If you check out the manpage for sysctlbyname it states:
> The size of the available data can be determined by calling sysctl() with
> the NULL argument for oldp. The size of the available data will be
> returned in the location pointed to by oldlenp. For some operations, the
> amount of space may change often. For these operations, the system
> attempts to round up so that the returned size is large enough for a call
> to return the data shortly thereafter.
>
> so I think it is something else, but thanks for the tip.
Ah, I didn't even understand your question, sorry. Please do
less +/^sysctl_kern_file /sys/kern/kern_descrip.c
And you'll notice why the returned array has an extra garbage(filehead)
in front of it.
| error = SYSCTL_OUT(req, (caddr_t)&filehead, sizeof(filehead));
| if (error)
| return (error);
|
| /*
| * followed by an array of file structures
| */
| LIST_FOREACH(fp, &filehead, f_list) {
| error = SYSCTL_OUT(req, (caddr_t)fp, sizeof (struct file));
| if (error)
| return (error);
| }
| return (0);
|}
So you can rewrite your example code to something like this:
void
get_files(void)
{
struct {
struct filelist head;
struct file array[1];
} *files;
struct file *f;
size_t size;
int i;
if (sysctlbyname("kern.file", NULL, &size, NULL, 0) < 0)
err(1, "sysctlbyname()");
if ((files = malloc(size)) == NULL)
err(1, "malloc()");
if (sysctlbyname("kern.file", files, &size, NULL, 0) < 0)
err(1, "sysctlbyname()");
nfiles = (size - sizeof(files->head)) / (sizeof files->array[0]);
for(f = files->array; f < files->array + nfiles; ++f)
printf("Type: %d\n", f->f_type);
}
FreeBSD-CURRENT's version of `sysctl -b kern.file' returns just an
array of struct xfile, so your code could be simpler(but making
sysctl_kern_file messy).
More information about the Submit
mailing list