1#include <sys/cdefs.h>
2__FBSDID("$FreeBSD$");
3
4#include <sys/param.h>
5#include <sys/user.h>
6#include <sys/sysctl.h>
7#include <stdlib.h>
8#include <string.h>
9
10#include "libutil.h"
11
12struct kinfo_file *
13kinfo_getfile(pid_t pid, int *cntp)
14{
15	int mib[4];
16	int error;
17	int cnt;
18	size_t len;
19	char *buf, *bp, *eb;
20	struct kinfo_file *kif, *kp, *kf;
21
22	*cntp = 0;
23	len = 0;
24	mib[0] = CTL_KERN;
25	mib[1] = KERN_PROC;
26	mib[2] = KERN_PROC_FILEDESC;
27	mib[3] = pid;
28
29	error = sysctl(mib, 4, NULL, &len, NULL, 0);
30	if (error)
31		return (NULL);
32	len = len * 4 / 3;
33	buf = malloc(len);
34	if (buf == NULL)
35		return (NULL);
36	error = sysctl(mib, 4, buf, &len, NULL, 0);
37	if (error) {
38		free(buf);
39		return (NULL);
40	}
41	/* Pass 1: count items */
42	cnt = 0;
43	bp = buf;
44	eb = buf + len;
45	while (bp < eb) {
46		kf = (struct kinfo_file *)(uintptr_t)bp;
47		bp += kf->kf_structsize;
48		cnt++;
49	}
50
51	kif = calloc(cnt, sizeof(*kif));
52	if (kif == NULL) {
53		free(buf);
54		return (NULL);
55	}
56	bp = buf;
57	eb = buf + len;
58	kp = kif;
59	/* Pass 2: unpack */
60	while (bp < eb) {
61		kf = (struct kinfo_file *)(uintptr_t)bp;
62		/* Copy/expand into pre-zeroed buffer */
63		memcpy(kp, kf, kf->kf_structsize);
64		/* Advance to next packed record */
65		bp += kf->kf_structsize;
66		/* Set field size to fixed length, advance */
67		kp->kf_structsize = sizeof(*kp);
68		kp++;
69	}
70	free(buf);
71	*cntp = cnt;
72	return (kif);	/* Caller must free() return value */
73}
74