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