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