xref: /freebsd/lib/libutil/kinfo_getfile.c (revision cc426dd31990b8b50b210efc450e404596548ca1)
1 #include <sys/cdefs.h>
2 __FBSDID("$FreeBSD$");
3 
4 #include <sys/param.h>
5 #include <sys/sysctl.h>
6 #include <sys/user.h>
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #include "libutil.h"
11 
12 struct kinfo_file *
13 kinfo_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, nitems(mib), 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, nitems(mib), 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 		if (kf->kf_structsize == 0)
48 			break;
49 		bp += kf->kf_structsize;
50 		cnt++;
51 	}
52 
53 	kif = calloc(cnt, sizeof(*kif));
54 	if (kif == NULL) {
55 		free(buf);
56 		return (NULL);
57 	}
58 	bp = buf;
59 	eb = buf + len;
60 	kp = kif;
61 	/* Pass 2: unpack */
62 	while (bp < eb) {
63 		kf = (struct kinfo_file *)(uintptr_t)bp;
64 		if (kf->kf_structsize == 0)
65 			break;
66 		/* Copy/expand into pre-zeroed buffer */
67 		memcpy(kp, kf, kf->kf_structsize);
68 		/* Advance to next packed record */
69 		bp += kf->kf_structsize;
70 		/* Set field size to fixed length, advance */
71 		kp->kf_structsize = sizeof(*kp);
72 		kp++;
73 	}
74 	free(buf);
75 	*cntp = cnt;
76 	return (kif);	/* Caller must free() return value */
77 }
78