diff options
Diffstat (limited to 'lib/libutil/kinfo_getfile.c')
-rw-r--r-- | lib/libutil/kinfo_getfile.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/lib/libutil/kinfo_getfile.c b/lib/libutil/kinfo_getfile.c new file mode 100644 index 0000000..84b64db --- /dev/null +++ b/lib/libutil/kinfo_getfile.c @@ -0,0 +1,73 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/user.h> +#include <sys/sysctl.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, 4, NULL, &len, NULL, 0); + if (error) + return (NULL); + len = len * 4 / 3; + buf = malloc(len); + if (buf == NULL) + return (NULL); + error = sysctl(mib, 4, 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; + 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; + /* 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 */ +} |