root/lib/libutil/kinfo_getfile.c
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <stdlib.h>
#include <string.h>

#include "libutil.h"

struct kinfo_file *
kinfo_getfile(pid_t pid, int *cntp)
{
        int mib[4];
        int error;
        int cnt;
        size_t len;
        char *buf, *bp, *eb;
        struct kinfo_file *kif, *kp, *kf;

        *cntp = 0;
        len = 0;
        mib[0] = CTL_KERN;
        mib[1] = KERN_PROC;
        mib[2] = KERN_PROC_FILEDESC;
        mib[3] = pid;

        error = sysctl(mib, nitems(mib), NULL, &len, NULL, 0);
        if (error)
                return (NULL);
        /*
         * Add extra space as the table may grow between requesting the size
         * and fetching the data.
         */
        len = len * 4 / 3;
        buf = malloc(len);
        if (buf == NULL)
                return (NULL);
        error = sysctl(mib, nitems(mib), buf, &len, NULL, 0);
        if (error) {
                free(buf);
                return (NULL);
        }
        /* Pass 1: count items */
        cnt = 0;
        bp = buf;
        eb = buf + len;
        while (bp < eb) {
                kf = (struct kinfo_file *)(uintptr_t)bp;
                if (kf->kf_structsize == 0)
                        break;
                bp += kf->kf_structsize;
                cnt++;
        }

        kif = calloc(cnt, sizeof(*kif));
        if (kif == NULL) {
                free(buf);
                return (NULL);
        }
        bp = buf;
        eb = buf + len;
        kp = kif;
        /* Pass 2: unpack */
        while (bp < eb) {
                kf = (struct kinfo_file *)(uintptr_t)bp;
                if (kf->kf_structsize == 0)
                        break;
                /* Copy/expand into pre-zeroed buffer */
                memcpy(kp, kf, kf->kf_structsize);
                /* Advance to next packed record */
                bp += kf->kf_structsize;
                /* Set field size to fixed length, advance */
                kp->kf_structsize = sizeof(*kp);
                kp++;
        }
        free(buf);
        *cntp = cnt;
        return (kif);   /* Caller must free() return value */
}