File: | src/lib/libkvm/kvm_file2.c |
Warning: | line 888, column 3 Address of stack memory associated with local variable 'specinfo' is still referred to by the stack variable 'vbuf' upon returning to the caller. This will be a dangling reference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: kvm_file2.c,v 1.57 2022/02/22 17:35:01 deraadt Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2009 Todd C. Miller <millert@openbsd.org> | |||
5 | * | |||
6 | * Permission to use, copy, modify, and distribute this software for any | |||
7 | * purpose with or without fee is hereby granted, provided that the above | |||
8 | * copyright notice and this permission notice appear in all copies. | |||
9 | * | |||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
17 | */ | |||
18 | ||||
19 | /*- | |||
20 | * Copyright (c) 1989, 1992, 1993 | |||
21 | * The Regents of the University of California. All rights reserved. | |||
22 | * | |||
23 | * Redistribution and use in source and binary forms, with or without | |||
24 | * modification, are permitted provided that the following conditions | |||
25 | * are met: | |||
26 | * 1. Redistributions of source code must retain the above copyright | |||
27 | * notice, this list of conditions and the following disclaimer. | |||
28 | * 2. Redistributions in binary form must reproduce the above copyright | |||
29 | * notice, this list of conditions and the following disclaimer in the | |||
30 | * documentation and/or other materials provided with the distribution. | |||
31 | * 3. Neither the name of the University nor the names of its contributors | |||
32 | * may be used to endorse or promote products derived from this software | |||
33 | * without specific prior written permission. | |||
34 | * | |||
35 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
36 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
37 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
38 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
39 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
40 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
41 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
42 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
43 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
44 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
45 | * SUCH DAMAGE. | |||
46 | */ | |||
47 | ||||
48 | /* | |||
49 | * Extended file list interface for kvm. pstat, fstat and netstat are | |||
50 | * users of this code, so we've factored it out into a separate module. | |||
51 | * Thus, we keep this grunge out of the other kvm applications (i.e., | |||
52 | * most other applications are interested only in open/close/read/nlist). | |||
53 | */ | |||
54 | ||||
55 | #define __need_process | |||
56 | ||||
57 | #include <sys/types.h> | |||
58 | #include <sys/signal.h> | |||
59 | #include <sys/uio.h> | |||
60 | #include <sys/ucred.h> | |||
61 | #include <sys/proc.h> | |||
62 | #define _KERNEL | |||
63 | #include <sys/file.h> | |||
64 | #include <sys/mount.h> | |||
65 | #undef _KERNEL | |||
66 | #include <sys/vnode.h> | |||
67 | #include <sys/socket.h> | |||
68 | #include <sys/socketvar.h> | |||
69 | #include <sys/domain.h> | |||
70 | #include <sys/protosw.h> | |||
71 | #include <sys/event.h> | |||
72 | #include <sys/eventvar.h> | |||
73 | #include <sys/un.h> | |||
74 | #include <sys/unpcb.h> | |||
75 | #include <sys/filedesc.h> | |||
76 | #include <sys/mbuf.h> | |||
77 | #include <sys/pipe.h> | |||
78 | #include <sys/stat.h> | |||
79 | #include <sys/sysctl.h> | |||
80 | #include <sys/specdev.h> | |||
81 | ||||
82 | #define _KERNEL | |||
83 | #include <ufs/ufs/quota.h> | |||
84 | #include <ufs/ufs/inode.h> | |||
85 | #undef _KERNEL | |||
86 | ||||
87 | #include <nfs/nfsproto.h> | |||
88 | #include <nfs/rpcv2.h> | |||
89 | #include <nfs/nfs.h> | |||
90 | #include <nfs/nfsnode.h> | |||
91 | ||||
92 | #include <msdosfs/bpb.h> | |||
93 | #include <msdosfs/denode.h> | |||
94 | #include <msdosfs/msdosfsmount.h> | |||
95 | ||||
96 | #include <net/route.h> | |||
97 | #include <netinet/in.h> | |||
98 | #include <netinet/ip.h> | |||
99 | #include <netinet/in_pcb.h> | |||
100 | #include <netinet/tcp.h> | |||
101 | #include <netinet/tcp_timer.h> | |||
102 | #include <netinet/tcp_var.h> | |||
103 | ||||
104 | #ifdef INET6 | |||
105 | #include <netinet/ip6.h> | |||
106 | #include <netinet6/ip6_var.h> | |||
107 | #endif | |||
108 | ||||
109 | #include <fcntl.h> | |||
110 | #include <nlist.h> | |||
111 | #include <kvm.h> | |||
112 | #include <db.h> | |||
113 | #include <stddef.h> | |||
114 | #include <stdlib.h> | |||
115 | #include <string.h> | |||
116 | #include <unistd.h> | |||
117 | #include <limits.h> | |||
118 | #include <errno(*__errno()).h> | |||
119 | ||||
120 | #include "kvm_private.h" | |||
121 | #include "kvm_file.h" | |||
122 | ||||
123 | static struct kinfo_file *kvm_deadfile_byfile(kvm_t *, int, int, | |||
124 | size_t, int *); | |||
125 | static struct kinfo_file *kvm_deadfile_byid(kvm_t *, int, int, | |||
126 | size_t, int *); | |||
127 | static int fill_file(kvm_t *, struct kinfo_file *, struct file *, u_long, | |||
128 | struct vnode *, struct process *, int, pid_t); | |||
129 | static int filestat(kvm_t *, struct kinfo_file *, struct vnode *); | |||
130 | ||||
131 | LIST_HEAD(processlist, process)struct processlist { struct process *lh_first; }; | |||
132 | ||||
133 | struct kinfo_file * | |||
134 | kvm_getfiles(kvm_t *kd, int op, int arg, size_t esize, int *cnt) | |||
135 | { | |||
136 | int mib[6], rv; | |||
137 | void *filebase; | |||
138 | size_t size; | |||
139 | ||||
140 | if (ISALIVE(kd)((kd)->alive)) { | |||
| ||||
141 | mib[0] = CTL_KERN1; | |||
142 | mib[1] = KERN_FILE73; | |||
143 | mib[2] = op; | |||
144 | mib[3] = arg; | |||
145 | mib[4] = esize; | |||
146 | ||||
147 | do { | |||
148 | mib[5] = 0; | |||
149 | ||||
150 | /* find size and alloc buffer */ | |||
151 | rv = sysctl(mib, 6, NULL((void *)0), &size, NULL((void *)0), 0); | |||
152 | if (rv == -1) { | |||
153 | if (errno(*__errno()) != ESRCH3 && kd->vmfd != -1) | |||
154 | goto deadway; | |||
155 | _kvm_syserr(kd, kd->program, "kvm_getfiles"); | |||
156 | return (NULL((void *)0)); | |||
157 | } | |||
158 | ||||
159 | size += size / 8; /* add ~10% */ | |||
160 | ||||
161 | filebase = _kvm_realloc(kd, kd->filebase, size); | |||
162 | if (filebase == NULL((void *)0)) | |||
163 | return (NULL((void *)0)); | |||
164 | ||||
165 | kd->filebase = filebase; | |||
166 | ||||
167 | /* get actual data */ | |||
168 | mib[5] = size / esize; | |||
169 | rv = sysctl(mib, 6, kd->filebase, &size, NULL((void *)0), 0); | |||
170 | if (rv == -1 && errno(*__errno()) != ENOMEM12) { | |||
171 | _kvm_syserr(kd, kd->program, | |||
172 | "kvm_getfiles"); | |||
173 | return (NULL((void *)0)); | |||
174 | } | |||
175 | } while (rv == -1); | |||
176 | ||||
177 | *cnt = size / esize; | |||
178 | return (kd->filebase); | |||
179 | } else { | |||
180 | if (esize > sizeof(struct kinfo_file)) { | |||
181 | _kvm_syserr(kd, kd->program, | |||
182 | "kvm_getfiles: unknown fields requested: libkvm out of date?"); | |||
183 | return (NULL((void *)0)); | |||
184 | } | |||
185 | deadway: | |||
186 | switch (op) { | |||
187 | case KERN_FILE_BYFILE1: | |||
188 | return (kvm_deadfile_byfile(kd, op, arg, esize, cnt)); | |||
189 | break; | |||
190 | case KERN_FILE_BYPID2: | |||
191 | case KERN_FILE_BYUID3: | |||
192 | return (kvm_deadfile_byid(kd, op, arg, esize, cnt)); | |||
193 | break; | |||
194 | default: | |||
195 | return (NULL((void *)0)); | |||
196 | } | |||
197 | } | |||
198 | } | |||
199 | ||||
200 | static struct kinfo_file * | |||
201 | kvm_deadfile_byfile(kvm_t *kd, int op, int arg, size_t esize, int *cnt) | |||
202 | { | |||
203 | struct nlist nl[3], *p; | |||
204 | size_t buflen; | |||
205 | int n = 0; | |||
206 | char *where; | |||
207 | struct kinfo_file kf; | |||
208 | struct file *fp, file; | |||
209 | struct filelist filehead; | |||
210 | int nfiles; | |||
211 | ||||
212 | nl[0].n_name = "_filehead"; | |||
213 | nl[1].n_name = "_numfiles"; | |||
214 | nl[2].n_name = 0; | |||
215 | ||||
216 | if (kvm_nlist(kd, nl) != 0) { | |||
217 | for (p = nl; p->n_type != 0; ++p) | |||
218 | ; | |||
219 | _kvm_err(kd, kd->program, | |||
220 | "%s: no such symbol", p->n_name); | |||
221 | return (NULL((void *)0)); | |||
222 | } | |||
223 | if (KREAD(kd, nl[0].n_value, &filehead)(kvm_read(kd, nl[0].n_value, (void *)(&filehead), sizeof( *&filehead)) != sizeof(*&filehead))) { | |||
224 | _kvm_err(kd, kd->program, "can't read filehead"); | |||
225 | return (NULL((void *)0)); | |||
226 | } | |||
227 | if (KREAD(kd, nl[1].n_value, &nfiles)(kvm_read(kd, nl[1].n_value, (void *)(&nfiles), sizeof(*& nfiles)) != sizeof(*&nfiles))) { | |||
228 | _kvm_err(kd, kd->program, "can't read nfiles"); | |||
229 | return (NULL((void *)0)); | |||
230 | } | |||
231 | where = _kvm_reallocarray(kd, kd->filebase, nfiles, esize); | |||
232 | if (where == NULL((void *)0)) | |||
233 | return (NULL((void *)0)); | |||
234 | ||||
235 | kd->filebase = (void *)where; | |||
236 | buflen = nfiles * esize; | |||
237 | ||||
238 | for (fp = LIST_FIRST(&filehead)((&filehead)->lh_first); | |||
239 | fp != NULL((void *)0) && esize <= buflen; | |||
240 | fp = LIST_NEXT(&file, f_list)((&file)->f_list.le_next)) { | |||
241 | if (KREAD(kd, (u_long)fp, &file)(kvm_read(kd, (u_long)fp, (void *)(&file), sizeof(*&file )) != sizeof(*&file))) { | |||
242 | _kvm_err(kd, kd->program, "can't read kfp"); | |||
243 | return (NULL((void *)0)); | |||
244 | } | |||
245 | if (file.f_count == 0) | |||
246 | continue; | |||
247 | if (arg != 0 && file.f_type != arg) | |||
248 | continue; | |||
249 | if (fill_file(kd, &kf, &file, (u_long)fp, NULL((void *)0), NULL((void *)0), 0, 0) | |||
250 | == -1) | |||
251 | return (NULL((void *)0)); | |||
252 | memcpy(where, &kf, esize); | |||
253 | where += esize; | |||
254 | buflen -= esize; | |||
255 | n++; | |||
256 | } | |||
257 | if (n != nfiles) { | |||
258 | _kvm_err(kd, kd->program, "inconsistent nfiles"); | |||
259 | return (NULL((void *)0)); | |||
260 | } | |||
261 | *cnt = n; | |||
262 | return (kd->filebase); | |||
263 | } | |||
264 | ||||
265 | static struct kinfo_file * | |||
266 | kvm_deadfile_byid(kvm_t *kd, int op, int arg, size_t esize, int *cnt) | |||
267 | { | |||
268 | size_t buflen; | |||
269 | struct nlist nl[4], *np; | |||
270 | int n = 0, matched = 0; | |||
271 | char *where; | |||
272 | struct kinfo_file kf; | |||
273 | struct file *fp, file; | |||
274 | struct filelist filehead; | |||
275 | struct filedesc0 filed0; | |||
276 | #define filedfiled0.fd_fd filed0.fd_fd | |||
277 | struct processlist allprocess; | |||
278 | struct process *pr, process; | |||
279 | struct ucred ucred; | |||
280 | char *filebuf = NULL((void *)0); | |||
281 | int i, nfiles; | |||
282 | ||||
283 | nl[0].n_name = "_filehead"; | |||
284 | nl[1].n_name = "_numfiles"; | |||
285 | nl[2].n_name = "_allprocess"; | |||
286 | nl[3].n_name = 0; | |||
287 | ||||
288 | if (kvm_nlist(kd, nl) != 0) { | |||
289 | for (np = nl; np->n_type != 0; ++np) | |||
290 | ; | |||
291 | _kvm_err(kd, kd->program, | |||
292 | "%s: no such symbol", np->n_name); | |||
293 | return (NULL((void *)0)); | |||
294 | } | |||
295 | if (KREAD(kd, nl[0].n_value, &filehead)(kvm_read(kd, nl[0].n_value, (void *)(&filehead), sizeof( *&filehead)) != sizeof(*&filehead))) { | |||
296 | _kvm_err(kd, kd->program, "can't read filehead"); | |||
297 | return (NULL((void *)0)); | |||
298 | } | |||
299 | if (KREAD(kd, nl[1].n_value, &nfiles)(kvm_read(kd, nl[1].n_value, (void *)(&nfiles), sizeof(*& nfiles)) != sizeof(*&nfiles))) { | |||
300 | _kvm_err(kd, kd->program, "can't read nfiles"); | |||
301 | return (NULL((void *)0)); | |||
302 | } | |||
303 | if (KREAD(kd, nl[2].n_value, &allprocess)(kvm_read(kd, nl[2].n_value, (void *)(&allprocess), sizeof (*&allprocess)) != sizeof(*&allprocess))) { | |||
304 | _kvm_err(kd, kd->program, "can't read allprocess"); | |||
305 | return (NULL((void *)0)); | |||
306 | } | |||
307 | /* this may be more room than we need but counting is expensive */ | |||
308 | where = _kvm_reallocarray(kd, kd->filebase, nfiles + 10, esize); | |||
309 | if (where == NULL((void *)0)) | |||
310 | return (NULL((void *)0)); | |||
311 | ||||
312 | kd->filebase = (void *)where; | |||
313 | buflen = (nfiles + 10) * esize; | |||
314 | ||||
315 | if (op != KERN_FILE_BYPID2 || arg <= 0) | |||
316 | matched = 1; | |||
317 | ||||
318 | for (pr = LIST_FIRST(&allprocess)((&allprocess)->lh_first); | |||
319 | pr != NULL((void *)0); | |||
320 | pr = LIST_NEXT(&process, ps_list)((&process)->ps_list.le_next)) { | |||
321 | if (KREAD(kd, (u_long)pr, &process)(kvm_read(kd, (u_long)pr, (void *)(&process), sizeof(*& process)) != sizeof(*&process))) { | |||
322 | _kvm_err(kd, kd->program, "can't read process at %lx", | |||
323 | (u_long)pr); | |||
324 | goto cleanup; | |||
325 | } | |||
326 | ||||
327 | /* skip system, exiting, embryonic and undead processes */ | |||
328 | if (process.ps_flags & (PS_SYSTEM0x00010000 | PS_EMBRYO0x00020000 | PS_EXITING0x00000008)) | |||
329 | continue; | |||
330 | ||||
331 | if (op == KERN_FILE_BYPID2) { | |||
332 | /* check if this is the pid we are looking for */ | |||
333 | if (arg > 0 && process.ps_pid != (pid_t)arg) | |||
334 | continue; | |||
335 | matched = 1; | |||
336 | } | |||
337 | ||||
338 | if (KREAD(kd, (u_long)process.ps_ucred, &ucred)(kvm_read(kd, (u_long)process.ps_ucred, (void *)(&ucred), sizeof(*&ucred)) != sizeof(*&ucred))) { | |||
339 | _kvm_err(kd, kd->program, "can't read ucred at %lx", | |||
340 | (u_long)process.ps_ucred); | |||
341 | goto cleanup; | |||
342 | } | |||
343 | process.ps_ucred = &ucred; | |||
344 | ||||
345 | if (op == KERN_FILE_BYUID3 && arg >= 0 && | |||
346 | process.ps_ucred->cr_uid != (uid_t)arg) { | |||
347 | /* not the uid we are looking for */ | |||
348 | continue; | |||
349 | } | |||
350 | ||||
351 | if (KREAD(kd, (u_long)process.ps_fd, &filed0)(kvm_read(kd, (u_long)process.ps_fd, (void *)(&filed0), sizeof (*&filed0)) != sizeof(*&filed0))) { | |||
352 | _kvm_err(kd, kd->program, "can't read filedesc at %lx", | |||
353 | (u_long)process.ps_fd); | |||
354 | goto cleanup; | |||
355 | } | |||
356 | if ((char *)process.ps_fd + offsetof(struct filedesc0,fd_dfiles)__builtin_offsetof(struct filedesc0, fd_dfiles) | |||
357 | == (char *)filedfiled0.fd_fd.fd_ofiles) { | |||
358 | filedfiled0.fd_fd.fd_ofiles = filed0.fd_dfiles; | |||
359 | filedfiled0.fd_fd.fd_ofileflags = filed0.fd_dfileflags; | |||
360 | } else { | |||
361 | size_t fsize; | |||
362 | char *tmp = reallocarray(filebuf, | |||
363 | filedfiled0.fd_fd.fd_nfiles, OFILESIZE(sizeof(struct file *) + sizeof(char))); | |||
364 | ||||
365 | fsize = filedfiled0.fd_fd.fd_nfiles * OFILESIZE(sizeof(struct file *) + sizeof(char)); | |||
366 | if (tmp == NULL((void *)0)) { | |||
367 | _kvm_syserr(kd, kd->program, "realloc ofiles"); | |||
368 | goto cleanup; | |||
369 | } | |||
370 | filebuf = tmp; | |||
371 | if (kvm_read(kd, (u_long)filedfiled0.fd_fd.fd_ofiles, filebuf, | |||
372 | fsize) != fsize) { | |||
373 | _kvm_err(kd, kd->program, | |||
374 | "can't read fd_ofiles"); | |||
375 | goto cleanup; | |||
376 | } | |||
377 | filedfiled0.fd_fd.fd_ofiles = (void *)filebuf; | |||
378 | filedfiled0.fd_fd.fd_ofileflags = filebuf + | |||
379 | (filedfiled0.fd_fd.fd_nfiles * sizeof(struct file *)); | |||
380 | } | |||
381 | process.ps_fd = &filedfiled0.fd_fd; | |||
382 | ||||
383 | if (process.ps_textvp) { | |||
384 | if (buflen < esize) | |||
385 | goto done; | |||
386 | if (fill_file(kd, &kf, NULL((void *)0), 0, process.ps_textvp, | |||
387 | &process, KERN_FILE_TEXT-1, process.ps_pid) == -1) | |||
388 | goto cleanup; | |||
389 | memcpy(where, &kf, esize); | |||
390 | where += esize; | |||
391 | buflen -= esize; | |||
392 | n++; | |||
393 | } | |||
394 | if (filedfiled0.fd_fd.fd_cdir) { | |||
395 | if (buflen < esize) | |||
396 | goto done; | |||
397 | if (fill_file(kd, &kf, NULL((void *)0), 0, filedfiled0.fd_fd.fd_cdir, | |||
398 | &process, KERN_FILE_CDIR-2, process.ps_pid) == -1) | |||
399 | goto cleanup; | |||
400 | memcpy(where, &kf, esize); | |||
401 | where += esize; | |||
402 | buflen -= esize; | |||
403 | n++; | |||
404 | } | |||
405 | if (filedfiled0.fd_fd.fd_rdir) { | |||
406 | if (buflen < esize) | |||
407 | goto done; | |||
408 | if (fill_file(kd, &kf, NULL((void *)0), 0, filedfiled0.fd_fd.fd_rdir, | |||
409 | &process, KERN_FILE_RDIR-3, process.ps_pid) == -1) | |||
410 | goto cleanup; | |||
411 | memcpy(where, &kf, esize); | |||
412 | where += esize; | |||
413 | buflen -= esize; | |||
414 | n++; | |||
415 | } | |||
416 | if (process.ps_tracevp) { | |||
417 | if (buflen < esize) | |||
418 | goto done; | |||
419 | if (fill_file(kd, &kf, NULL((void *)0), 0, process.ps_tracevp, | |||
420 | &process, KERN_FILE_TRACE-4, process.ps_pid) == -1) | |||
421 | goto cleanup; | |||
422 | memcpy(where, &kf, esize); | |||
423 | where += esize; | |||
424 | buflen -= esize; | |||
425 | n++; | |||
426 | } | |||
427 | ||||
428 | if (filedfiled0.fd_fd.fd_nfiles < 0 || | |||
429 | filedfiled0.fd_fd.fd_lastfile >= filedfiled0.fd_fd.fd_nfiles || | |||
430 | filedfiled0.fd_fd.fd_freefile > filedfiled0.fd_fd.fd_lastfile + 1) { | |||
431 | _kvm_err(kd, kd->program, | |||
432 | "filedesc corrupted at %lx for pid %d", | |||
433 | (u_long)process.ps_fd, process.ps_pid); | |||
434 | goto cleanup; | |||
435 | } | |||
436 | ||||
437 | for (i = 0; i < filedfiled0.fd_fd.fd_nfiles; i++) { | |||
438 | if (buflen < esize) | |||
439 | goto done; | |||
440 | if ((fp = filedfiled0.fd_fd.fd_ofiles[i]) == NULL((void *)0)) | |||
441 | continue; | |||
442 | if (KREAD(kd, (u_long)fp, &file)(kvm_read(kd, (u_long)fp, (void *)(&file), sizeof(*&file )) != sizeof(*&file))) { | |||
443 | _kvm_err(kd, kd->program, "can't read file"); | |||
444 | goto cleanup; | |||
445 | } | |||
446 | if (fill_file(kd, &kf, &file, (u_long)fp, NULL((void *)0), | |||
447 | &process, i, process.ps_pid) == -1) | |||
448 | goto cleanup; | |||
449 | memcpy(where, &kf, esize); | |||
450 | where += esize; | |||
451 | buflen -= esize; | |||
452 | n++; | |||
453 | } | |||
454 | } | |||
455 | if (!matched) { | |||
456 | errno(*__errno()) = ESRCH3; | |||
457 | goto cleanup; | |||
458 | } | |||
459 | done: | |||
460 | *cnt = n; | |||
461 | free(filebuf); | |||
462 | return (kd->filebase); | |||
463 | cleanup: | |||
464 | free(filebuf); | |||
465 | return (NULL((void *)0)); | |||
466 | } | |||
467 | ||||
468 | static int | |||
469 | fill_file(kvm_t *kd, struct kinfo_file *kf, struct file *fp, u_long fpaddr, | |||
470 | struct vnode *vp, struct process *pr, int fd, pid_t pid) | |||
471 | { | |||
472 | struct ucred f_cred; | |||
473 | ||||
474 | memset(kf, 0, sizeof(*kf)); | |||
475 | ||||
476 | kf->fd_fd = fd; /* might not really be an fd */ | |||
477 | ||||
478 | if (fp
| |||
479 | /* Fill in f_cred */ | |||
480 | if (KREAD(kd, (u_long)fp->f_cred, &f_cred)(kvm_read(kd, (u_long)fp->f_cred, (void *)(&f_cred), sizeof (*&f_cred)) != sizeof(*&f_cred))) { | |||
481 | _kvm_err(kd, kd->program, "can't read f_cred"); | |||
482 | return (-1); | |||
483 | } | |||
484 | ||||
485 | kf->f_fileaddr = PTRTOINT64(fpaddr)((u_int64_t)(u_long)(fpaddr)); | |||
486 | kf->f_flag = fp->f_flag; | |||
487 | kf->f_iflags = fp->f_iflags; | |||
488 | kf->f_type = fp->f_type; | |||
489 | kf->f_count = fp->f_count; | |||
490 | kf->f_ucred = PTRTOINT64(fp->f_cred)((u_int64_t)(u_long)(fp->f_cred)); | |||
491 | kf->f_uid = f_cred.cr_uid; | |||
492 | kf->f_gid = f_cred.cr_gid; | |||
493 | kf->f_ops = PTRTOINT64(fp->f_ops)((u_int64_t)(u_long)(fp->f_ops)); | |||
494 | kf->f_offset = fp->f_offset; | |||
495 | kf->f_data = PTRTOINT64(fp->f_data)((u_int64_t)(u_long)(fp->f_data)); | |||
496 | kf->f_usecount = 0; | |||
497 | ||||
498 | kf->f_rxfer = fp->f_rxfer; | |||
499 | kf->f_rwfer = fp->f_wxfer; | |||
500 | kf->f_seek = fp->f_seek; | |||
501 | kf->f_rbytes = fp->f_rbytes; | |||
502 | kf->f_wbytes = fp->f_wbytes; | |||
503 | } else if (vp != NULL((void *)0)) { | |||
504 | /* fake it */ | |||
505 | kf->f_type = DTYPE_VNODE1; | |||
506 | kf->f_flag = FREAD0x0001; | |||
507 | if (fd == KERN_FILE_TRACE-4) | |||
508 | kf->f_flag |= FWRITE0x0002; | |||
509 | kf->f_data = PTRTOINT64(vp)((u_int64_t)(u_long)(vp)); | |||
510 | } | |||
511 | ||||
512 | /* information about the object associated with this file */ | |||
513 | switch (kf->f_type) { | |||
514 | case DTYPE_VNODE1: { | |||
515 | struct vnode vbuf; | |||
516 | ||||
517 | if (KREAD(kd, (u_long)(fp ? fp->f_data : vp), &vbuf)(kvm_read(kd, (u_long)(fp ? fp->f_data : vp), (void *)(& vbuf), sizeof(*&vbuf)) != sizeof(*&vbuf))) { | |||
518 | _kvm_err(kd, kd->program, "can't read vnode"); | |||
519 | return (-1); | |||
520 | } | |||
521 | vp = &vbuf; | |||
522 | ||||
523 | kf->v_un = PTRTOINT64(vp->v_un.vu_socket)((u_int64_t)(u_long)(vp->v_un.vu_socket)); | |||
524 | kf->v_type = vp->v_type; | |||
525 | kf->v_tag = vp->v_tag; | |||
526 | kf->v_flag = vp->v_flag; | |||
527 | kf->v_data = PTRTOINT64(vp->v_data)((u_int64_t)(u_long)(vp->v_data)); | |||
528 | kf->v_mount = PTRTOINT64(vp->v_mount)((u_int64_t)(u_long)(vp->v_mount)); | |||
529 | ||||
530 | if (vp->v_mount != NULL((void *)0)) { | |||
531 | struct mount mount; | |||
532 | ||||
533 | if (KREAD(kd, (u_long)vp->v_mount, &mount)(kvm_read(kd, (u_long)vp->v_mount, (void *)(&mount), sizeof (*&mount)) != sizeof(*&mount))) { | |||
534 | _kvm_err(kd, kd->program, "can't read v_mount"); | |||
535 | return (-1); | |||
536 | } | |||
537 | ||||
538 | strlcpy(kf->f_mntonname, mount.mnt_stat.f_mntonname, | |||
539 | sizeof(kf->f_mntonname)); | |||
540 | } | |||
541 | ||||
542 | /* Fill in va_fsid, va_fileid, va_mode, va_size, va_rdev */ | |||
543 | filestat(kd, kf, vp); | |||
544 | break; | |||
545 | } | |||
546 | ||||
547 | case DTYPE_SOCKET2: { | |||
548 | struct socket sock; | |||
549 | struct sosplice ssp; | |||
550 | struct protosw protosw; | |||
551 | struct domain domain; | |||
552 | ||||
553 | if (KREAD(kd, (u_long)fp->f_data, &sock)(kvm_read(kd, (u_long)fp->f_data, (void *)(&sock), sizeof (*&sock)) != sizeof(*&sock))) { | |||
554 | _kvm_err(kd, kd->program, "can't read socket"); | |||
555 | return (-1); | |||
556 | } | |||
557 | ||||
558 | kf->so_type = sock.so_type; | |||
559 | kf->so_state = sock.so_state; | |||
560 | kf->so_pcb = PTRTOINT64(sock.so_pcb)((u_int64_t)(u_long)(sock.so_pcb)); | |||
561 | if (KREAD(kd, (u_long)sock.so_proto, &protosw)(kvm_read(kd, (u_long)sock.so_proto, (void *)(&protosw), sizeof (*&protosw)) != sizeof(*&protosw))) { | |||
562 | _kvm_err(kd, kd->program, "can't read protosw"); | |||
563 | return (-1); | |||
564 | } | |||
565 | kf->so_protocol = protosw.pr_protocol; | |||
566 | if (KREAD(kd, (u_long)protosw.pr_domain, &domain)(kvm_read(kd, (u_long)protosw.pr_domain, (void *)(&domain ), sizeof(*&domain)) != sizeof(*&domain))) { | |||
567 | _kvm_err(kd, kd->program, "can't read domain"); | |||
568 | return (-1); | |||
569 | } | |||
570 | kf->so_family = domain.dom_family; | |||
571 | kf->so_rcv_cc = sock.so_rcv.sb_cc; | |||
572 | kf->so_snd_cc = sock.so_snd.sb_cc; | |||
573 | if (sock.so_sp) { | |||
574 | if (KREAD(kd, (u_long)sock.so_sp, &ssp)(kvm_read(kd, (u_long)sock.so_sp, (void *)(&ssp), sizeof( *&ssp)) != sizeof(*&ssp))) { | |||
575 | _kvm_err(kd, kd->program, "can't read splice"); | |||
576 | return (-1); | |||
577 | } | |||
578 | if (ssp.ssp_socket) { | |||
579 | kf->so_splice = PTRTOINT64(ssp.ssp_socket)((u_int64_t)(u_long)(ssp.ssp_socket)); | |||
580 | kf->so_splicelen = ssp.ssp_len; | |||
581 | } else if (ssp.ssp_soback) { | |||
582 | kf->so_splicelen = -1; | |||
583 | } | |||
584 | } | |||
585 | if (!sock.so_pcb) | |||
586 | break; | |||
587 | switch (kf->so_family) { | |||
588 | case AF_INET2: { | |||
589 | struct inpcb inpcb; | |||
590 | ||||
591 | if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)(kvm_read(kd, (u_long)sock.so_pcb, (void *)(&inpcb), sizeof (*&inpcb)) != sizeof(*&inpcb))) { | |||
592 | _kvm_err(kd, kd->program, "can't read inpcb"); | |||
593 | return (-1); | |||
594 | } | |||
595 | kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb)((u_int64_t)(u_long)(inpcb.inp_ppcb)); | |||
596 | kf->inp_lport = inpcb.inp_lport; | |||
597 | kf->inp_laddru[0] = inpcb.inp_laddrinp_laddru.iau_a4u.inaddr.s_addr; | |||
598 | kf->inp_fport = inpcb.inp_fport; | |||
599 | kf->inp_faddru[0] = inpcb.inp_faddrinp_faddru.iau_a4u.inaddr.s_addr; | |||
600 | kf->inp_rtableid = inpcb.inp_rtableid; | |||
601 | if (sock.so_type == SOCK_RAW3) | |||
602 | kf->inp_proto = inpcb.inp_ipinp_hu.hu_ip.ip_p; | |||
603 | if (protosw.pr_protocol == IPPROTO_TCP6) { | |||
604 | struct tcpcb tcpcb; | |||
605 | if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)(kvm_read(kd, (u_long)inpcb.inp_ppcb, (void *)(&tcpcb), sizeof (*&tcpcb)) != sizeof(*&tcpcb))) { | |||
606 | _kvm_err(kd, kd->program, | |||
607 | "can't read tcpcb"); | |||
608 | return (-1); | |||
609 | } | |||
610 | kf->t_rcv_wnd = tcpcb.rcv_wnd; | |||
611 | kf->t_snd_wnd = tcpcb.snd_wnd; | |||
612 | kf->t_snd_cwnd = tcpcb.snd_cwnd; | |||
613 | kf->t_state = tcpcb.t_state; | |||
614 | } | |||
615 | break; | |||
616 | } | |||
617 | case AF_INET624: { | |||
618 | struct inpcb inpcb; | |||
619 | #define s6_addr32__u6_addr.__u6_addr32 __u6_addr.__u6_addr32 | |||
620 | ||||
621 | if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)(kvm_read(kd, (u_long)sock.so_pcb, (void *)(&inpcb), sizeof (*&inpcb)) != sizeof(*&inpcb))) { | |||
622 | _kvm_err(kd, kd->program, "can't read inpcb"); | |||
623 | return (-1); | |||
624 | } | |||
625 | kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb)((u_int64_t)(u_long)(inpcb.inp_ppcb)); | |||
626 | kf->inp_lport = inpcb.inp_lport; | |||
627 | kf->inp_laddru[0] = inpcb.inp_laddr6inp_laddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[0]; | |||
628 | kf->inp_laddru[1] = inpcb.inp_laddr6inp_laddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[1]; | |||
629 | kf->inp_laddru[2] = inpcb.inp_laddr6inp_laddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[2]; | |||
630 | kf->inp_laddru[3] = inpcb.inp_laddr6inp_laddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[3]; | |||
631 | kf->inp_fport = inpcb.inp_fport; | |||
632 | kf->inp_faddru[0] = inpcb.inp_laddr6inp_laddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[0]; | |||
633 | kf->inp_faddru[1] = inpcb.inp_faddr6inp_faddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[1]; | |||
634 | kf->inp_faddru[2] = inpcb.inp_faddr6inp_faddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[2]; | |||
635 | kf->inp_faddru[3] = inpcb.inp_faddr6inp_faddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[3]; | |||
636 | kf->inp_rtableid = inpcb.inp_rtableid; | |||
637 | if (sock.so_type == SOCK_RAW3) | |||
638 | kf->inp_proto = inpcb.inp_ipv6inp_hu.hu_ipv6.ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt; | |||
639 | if (protosw.pr_protocol == IPPROTO_TCP6) { | |||
640 | struct tcpcb tcpcb; | |||
641 | if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)(kvm_read(kd, (u_long)inpcb.inp_ppcb, (void *)(&tcpcb), sizeof (*&tcpcb)) != sizeof(*&tcpcb))) { | |||
642 | _kvm_err(kd, kd->program, | |||
643 | "can't read tcpcb"); | |||
644 | return (-1); | |||
645 | } | |||
646 | kf->t_rcv_wnd = tcpcb.rcv_wnd; | |||
647 | kf->t_snd_wnd = tcpcb.snd_wnd; | |||
648 | kf->t_snd_cwnd = tcpcb.snd_cwnd; | |||
649 | kf->t_state = tcpcb.t_state; | |||
650 | } | |||
651 | break; | |||
652 | } | |||
653 | case AF_UNIX1: { | |||
654 | struct unpcb unpcb; | |||
655 | ||||
656 | if (KREAD(kd, (u_long)sock.so_pcb, &unpcb)(kvm_read(kd, (u_long)sock.so_pcb, (void *)(&unpcb), sizeof (*&unpcb)) != sizeof(*&unpcb))) { | |||
657 | _kvm_err(kd, kd->program, "can't read unpcb"); | |||
658 | return (-1); | |||
659 | } | |||
660 | kf->f_msgcount = unpcb.unp_msgcount; | |||
661 | kf->unp_conn = PTRTOINT64(unpcb.unp_conn)((u_int64_t)(u_long)(unpcb.unp_conn)); | |||
662 | kf->unp_refs = PTRTOINT64(((u_int64_t)(u_long)(((&unpcb.unp_refs)->slh_first))) | |||
663 | SLIST_FIRST(&unpcb.unp_refs))((u_int64_t)(u_long)(((&unpcb.unp_refs)->slh_first))); | |||
664 | kf->unp_nextref = PTRTOINT64(((u_int64_t)(u_long)(((&unpcb)->unp_nextref.sle_next)) ) | |||
665 | SLIST_NEXT(&unpcb, unp_nextref))((u_int64_t)(u_long)(((&unpcb)->unp_nextref.sle_next)) ); | |||
666 | kf->v_un = PTRTOINT64(unpcb.unp_vnode)((u_int64_t)(u_long)(unpcb.unp_vnode)); | |||
667 | if (unpcb.unp_addr != NULL((void *)0)) { | |||
668 | struct mbuf mb; | |||
669 | struct sockaddr_un un; | |||
670 | ||||
671 | if (KREAD(kd, (u_long)unpcb.unp_addr, &mb)(kvm_read(kd, (u_long)unpcb.unp_addr, (void *)(&mb), sizeof (*&mb)) != sizeof(*&mb))) { | |||
672 | _kvm_err(kd, kd->program, | |||
673 | "can't read sockaddr_un mbuf"); | |||
674 | return (-1); | |||
675 | } | |||
676 | if (KREAD(kd, (u_long)mb.m_data, &un)(kvm_read(kd, (u_long)mb.m_hdr.mh_data, (void *)(&un), sizeof (*&un)) != sizeof(*&un))) { | |||
677 | _kvm_err(kd, kd->program, | |||
678 | "can't read sockaddr_un"); | |||
679 | return (-1); | |||
680 | } | |||
681 | ||||
682 | kf->unp_addr = PTRTOINT64(unpcb.unp_addr)((u_int64_t)(u_long)(unpcb.unp_addr)); | |||
683 | memcpy(kf->unp_path, un.sun_path, un.sun_len | |||
684 | - offsetof(struct sockaddr_un,sun_path)__builtin_offsetof(struct sockaddr_un, sun_path)); | |||
685 | } | |||
686 | ||||
687 | break; | |||
688 | } | |||
689 | } | |||
690 | break; | |||
691 | } | |||
692 | ||||
693 | case DTYPE_PIPE3: { | |||
694 | struct pipe pipe; | |||
695 | ||||
696 | if (KREAD(kd, (u_long)fp->f_data, &pipe)(kvm_read(kd, (u_long)fp->f_data, (void *)(&pipe), sizeof (*&pipe)) != sizeof(*&pipe))) { | |||
697 | _kvm_err(kd, kd->program, "can't read pipe"); | |||
698 | return (-1); | |||
699 | } | |||
700 | kf->pipe_peer = PTRTOINT64(pipe.pipe_peer)((u_int64_t)(u_long)(pipe.pipe_peer)); | |||
701 | kf->pipe_state = pipe.pipe_state; | |||
702 | break; | |||
703 | } | |||
704 | ||||
705 | case DTYPE_KQUEUE4: { | |||
706 | struct kqueue kqi; | |||
707 | ||||
708 | if (KREAD(kd, (u_long)fp->f_data, &kqi)(kvm_read(kd, (u_long)fp->f_data, (void *)(&kqi), sizeof (*&kqi)) != sizeof(*&kqi))) { | |||
709 | _kvm_err(kd, kd->program, "can't read kqi"); | |||
710 | return (-1); | |||
711 | } | |||
712 | kf->kq_count = kqi.kq_count; | |||
713 | kf->kq_state = kqi.kq_state; | |||
714 | break; | |||
715 | } | |||
716 | } | |||
717 | ||||
718 | /* per-process information for KERN_FILE_BY[PU]ID */ | |||
719 | if (pr != NULL((void *)0)) { | |||
720 | kf->p_pid = pid; | |||
721 | kf->p_uid = pr->ps_ucred->cr_uid; | |||
722 | kf->p_gid = pr->ps_ucred->cr_gid; | |||
723 | kf->p_tid = -1; | |||
724 | strlcpy(kf->p_comm, pr->ps_comm, sizeof(kf->p_comm)); | |||
725 | if (pr->ps_fd != NULL((void *)0)) | |||
726 | kf->fd_ofileflags = pr->ps_fd->fd_ofileflags[fd]; | |||
727 | } | |||
728 | ||||
729 | return (0); | |||
730 | } | |||
731 | ||||
732 | mode_t | |||
733 | _kvm_getftype(enum vtype v_type) | |||
734 | { | |||
735 | mode_t ftype = 0; | |||
736 | ||||
737 | switch (v_type) { | |||
738 | case VREG: | |||
739 | ftype = S_IFREG0100000; | |||
740 | break; | |||
741 | case VDIR: | |||
742 | ftype = S_IFDIR0040000; | |||
743 | break; | |||
744 | case VBLK: | |||
745 | ftype = S_IFBLK0060000; | |||
746 | break; | |||
747 | case VCHR: | |||
748 | ftype = S_IFCHR0020000; | |||
749 | break; | |||
750 | case VLNK: | |||
751 | ftype = S_IFLNK0120000; | |||
752 | break; | |||
753 | case VSOCK: | |||
754 | ftype = S_IFSOCK0140000; | |||
755 | break; | |||
756 | case VFIFO: | |||
757 | ftype = S_IFIFO0010000; | |||
758 | break; | |||
759 | case VNON: | |||
760 | case VBAD: | |||
761 | break; | |||
762 | } | |||
763 | ||||
764 | return (ftype); | |||
765 | } | |||
766 | ||||
767 | static int | |||
768 | ufs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
769 | { | |||
770 | struct inode inode; | |||
771 | struct ufs1_dinode di1; | |||
772 | ||||
773 | if (KREAD(kd, (u_long)VTOI(vp), &inode)(kvm_read(kd, (u_long)((struct inode *)(vp)->v_data), (void *)(&inode), sizeof(*&inode)) != sizeof(*&inode))) { | |||
774 | _kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp)((struct inode *)(vp)->v_data)); | |||
775 | return (-1); | |||
776 | } | |||
777 | ||||
778 | if (KREAD(kd, (u_long)inode.i_din1, &di1)(kvm_read(kd, (u_long)inode.dinode_u.ffs1_din, (void *)(& di1), sizeof(*&di1)) != sizeof(*&di1))) { | |||
779 | _kvm_err(kd, kd->program, "can't read dinode at %p", | |||
780 | inode.i_din1dinode_u.ffs1_din); | |||
781 | return (-1); | |||
782 | } | |||
783 | ||||
784 | inode.i_din1dinode_u.ffs1_din = &di1; | |||
785 | ||||
786 | kf->va_fsid = inode.i_dev & 0xffff; | |||
787 | kf->va_fileid = (long)inode.i_number; | |||
788 | kf->va_mode = inode.i_ffs1_modedinode_u.ffs1_din->di_mode; | |||
789 | kf->va_size = inode.i_ffs1_sizedinode_u.ffs1_din->di_size; | |||
790 | kf->va_rdev = inode.i_ffs1_rdevdinode_u.ffs1_din->di_db[0]; | |||
791 | kf->va_nlink = inode.i_ffs1_nlinkdinode_u.ffs1_din->di_nlink; | |||
792 | ||||
793 | return (0); | |||
794 | } | |||
795 | ||||
796 | static int | |||
797 | ext2fs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
798 | { | |||
799 | struct inode inode; | |||
800 | struct ext2fs_dinode e2di; | |||
801 | ||||
802 | if (KREAD(kd, (u_long)VTOI(vp), &inode)(kvm_read(kd, (u_long)((struct inode *)(vp)->v_data), (void *)(&inode), sizeof(*&inode)) != sizeof(*&inode))) { | |||
803 | _kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp)((struct inode *)(vp)->v_data)); | |||
804 | return (-1); | |||
805 | } | |||
806 | ||||
807 | if (KREAD(kd, (u_long)inode.i_e2din, &e2di)(kvm_read(kd, (u_long)inode.dinode_u.e2fs_din, (void *)(& e2di), sizeof(*&e2di)) != sizeof(*&e2di))) { | |||
808 | _kvm_err(kd, kd->program, "can't read dinode at %p", | |||
809 | inode.i_e2dindinode_u.e2fs_din); | |||
810 | return (-1); | |||
811 | } | |||
812 | ||||
813 | inode.i_e2dindinode_u.e2fs_din = &e2di; | |||
814 | ||||
815 | kf->va_fsid = inode.i_dev & 0xffff; | |||
816 | kf->va_fileid = (long)inode.i_number; | |||
817 | kf->va_mode = inode.i_e2fs_modedinode_u.e2fs_din->e2di_mode; | |||
818 | kf->va_size = inode.i_e2fs_sizedinode_u.e2fs_din->e2di_size; | |||
819 | kf->va_rdev = 0; /* XXX */ | |||
820 | kf->va_nlink = inode.i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink; | |||
821 | ||||
822 | return (0); | |||
823 | } | |||
824 | ||||
825 | static int | |||
826 | msdos_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
827 | { | |||
828 | struct denode de; | |||
829 | struct msdosfsmount mp; | |||
830 | ||||
831 | if (KREAD(kd, (u_long)VTODE(vp), &de)(kvm_read(kd, (u_long)((struct denode *)(vp)->v_data), (void *)(&de), sizeof(*&de)) != sizeof(*&de))) { | |||
832 | _kvm_err(kd, kd->program, "can't read denode at %p", VTODE(vp)((struct denode *)(vp)->v_data)); | |||
833 | return (-1); | |||
834 | } | |||
835 | if (KREAD(kd, (u_long)de.de_pmp, &mp)(kvm_read(kd, (u_long)de.de_pmp, (void *)(&mp), sizeof(*& mp)) != sizeof(*&mp))) { | |||
836 | _kvm_err(kd, kd->program, "can't read mount struct at %p", | |||
837 | de.de_pmp); | |||
838 | return (-1); | |||
839 | } | |||
840 | ||||
841 | kf->va_fsid = de.de_dev & 0xffff; | |||
842 | kf->va_fileid = 0; /* XXX see msdosfs_vptofh() for more info */ | |||
843 | kf->va_mode = (mp.pm_mask & 0777) | _kvm_getftype(vp->v_type); | |||
844 | kf->va_size = de.de_FileSize; | |||
845 | kf->va_rdev = 0; /* msdosfs doesn't support device files */ | |||
846 | kf->va_nlink = 1; | |||
847 | ||||
848 | return (0); | |||
849 | } | |||
850 | ||||
851 | static int | |||
852 | nfs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
853 | { | |||
854 | struct nfsnode nfsnode; | |||
855 | ||||
856 | if (KREAD(kd, (u_long)VTONFS(vp), &nfsnode)(kvm_read(kd, (u_long)((struct nfsnode *)(vp)->v_data), (void *)(&nfsnode), sizeof(*&nfsnode)) != sizeof(*&nfsnode ))) { | |||
857 | _kvm_err(kd, kd->program, "can't read nfsnode at %p", | |||
858 | VTONFS(vp)((struct nfsnode *)(vp)->v_data)); | |||
859 | return (-1); | |||
860 | } | |||
861 | kf->va_fsid = nfsnode.n_vattr.va_fsid; | |||
862 | kf->va_fileid = nfsnode.n_vattr.va_fileid; | |||
863 | kf->va_size = nfsnode.n_size; | |||
864 | kf->va_rdev = nfsnode.n_vattr.va_rdev; | |||
865 | kf->va_mode = (mode_t)nfsnode.n_vattr.va_mode | _kvm_getftype(vp->v_type); | |||
866 | kf->va_nlink = nfsnode.n_vattr.va_nlink; | |||
867 | ||||
868 | return (0); | |||
869 | } | |||
870 | ||||
871 | static int | |||
872 | spec_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
873 | { | |||
874 | struct specinfo specinfo; | |||
875 | struct vnode parent; | |||
876 | ||||
877 | if (KREAD(kd, (u_long)vp->v_specinfo, &specinfo)(kvm_read(kd, (u_long)vp->v_un.vu_specinfo, (void *)(& specinfo), sizeof(*&specinfo)) != sizeof(*&specinfo))) { | |||
878 | _kvm_err(kd, kd->program, "can't read specinfo at %p", | |||
879 | vp->v_specinfov_un.vu_specinfo); | |||
880 | return (-1); | |||
881 | } | |||
882 | ||||
883 | vp->v_specinfov_un.vu_specinfo = &specinfo; | |||
884 | ||||
885 | if (KREAD(kd, (u_long)vp->v_specparent, &parent)(kvm_read(kd, (u_long)vp->v_un.vu_specinfo->si_ci.ci_parent , (void *)(&parent), sizeof(*&parent)) != sizeof(*& parent))) { | |||
886 | _kvm_err(kd, kd->program, "can't read parent vnode at %p", | |||
887 | vp->v_specparentv_un.vu_specinfo->si_ci.ci_parent); | |||
888 | return (-1); | |||
| ||||
889 | } | |||
890 | ||||
891 | if (ufs_filestat(kd, kf, vp)) | |||
892 | return (-1); | |||
893 | ||||
894 | return (0); | |||
895 | } | |||
896 | ||||
897 | static int | |||
898 | filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
899 | { | |||
900 | int ret = 0; | |||
901 | ||||
902 | if (vp->v_type != VNON && vp->v_type != VBAD) { | |||
903 | switch (vp->v_tag) { | |||
904 | case VT_UFS: | |||
905 | case VT_MFS: | |||
906 | ret = ufs_filestat(kd, kf, vp); | |||
907 | break; | |||
908 | case VT_NFS: | |||
909 | ret = nfs_filestat(kd, kf, vp); | |||
910 | break; | |||
911 | case VT_EXT2FS: | |||
912 | ret = ext2fs_filestat(kd, kf, vp); | |||
913 | break; | |||
914 | case VT_ISOFS: | |||
915 | ret = _kvm_stat_cd9660(kd, kf, vp); | |||
916 | break; | |||
917 | case VT_MSDOSFS: | |||
918 | ret = msdos_filestat(kd, kf, vp); | |||
919 | break; | |||
920 | case VT_UDF: | |||
921 | ret = _kvm_stat_udf(kd, kf, vp); | |||
922 | break; | |||
923 | case VT_NTFS: | |||
924 | ret = _kvm_stat_ntfs(kd, kf, vp); | |||
925 | break; | |||
926 | case VT_NON: | |||
927 | if (vp->v_flag & VCLONE0x8000) | |||
928 | ret = spec_filestat(kd, kf, vp); | |||
929 | break; | |||
930 | default: | |||
931 | ret = -1; | |||
932 | break; | |||
933 | } | |||
934 | } | |||
935 | return (ret); | |||
936 | } |