1 |
|
|
/* $OpenBSD: kvm_file2.c,v 1.52 2017/01/21 05:42:04 guenther Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com> |
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/param.h> |
58 |
|
|
#include <sys/uio.h> |
59 |
|
|
#include <sys/ucred.h> |
60 |
|
|
#include <sys/proc.h> |
61 |
|
|
#define _KERNEL |
62 |
|
|
#include <sys/file.h> |
63 |
|
|
#include <sys/mount.h> |
64 |
|
|
#undef _KERNEL |
65 |
|
|
#include <sys/vnode.h> |
66 |
|
|
#include <sys/socket.h> |
67 |
|
|
#include <sys/socketvar.h> |
68 |
|
|
#include <sys/domain.h> |
69 |
|
|
#include <sys/protosw.h> |
70 |
|
|
#include <sys/event.h> |
71 |
|
|
#include <sys/eventvar.h> |
72 |
|
|
#include <sys/un.h> |
73 |
|
|
#include <sys/unpcb.h> |
74 |
|
|
#include <sys/filedesc.h> |
75 |
|
|
#include <sys/mbuf.h> |
76 |
|
|
#include <sys/pipe.h> |
77 |
|
|
#include <sys/stat.h> |
78 |
|
|
#include <sys/sysctl.h> |
79 |
|
|
#include <sys/specdev.h> |
80 |
|
|
|
81 |
|
|
#define _KERNEL |
82 |
|
|
#include <ufs/ufs/quota.h> |
83 |
|
|
#include <ufs/ufs/inode.h> |
84 |
|
|
#undef _KERNEL |
85 |
|
|
|
86 |
|
|
#include <nfs/nfsproto.h> |
87 |
|
|
#include <nfs/rpcv2.h> |
88 |
|
|
#include <nfs/nfs.h> |
89 |
|
|
#include <nfs/nfsnode.h> |
90 |
|
|
|
91 |
|
|
#include <msdosfs/bpb.h> |
92 |
|
|
#include <msdosfs/denode.h> |
93 |
|
|
#include <msdosfs/msdosfsmount.h> |
94 |
|
|
|
95 |
|
|
#include <net/route.h> |
96 |
|
|
#include <netinet/in.h> |
97 |
|
|
#include <netinet/ip.h> |
98 |
|
|
#include <netinet/in_pcb.h> |
99 |
|
|
#include <netinet/tcp.h> |
100 |
|
|
#include <netinet/tcp_timer.h> |
101 |
|
|
#include <netinet/tcp_var.h> |
102 |
|
|
|
103 |
|
|
#ifdef INET6 |
104 |
|
|
#include <netinet/ip6.h> |
105 |
|
|
#include <netinet6/ip6_var.h> |
106 |
|
|
#endif |
107 |
|
|
|
108 |
|
|
#include <nlist.h> |
109 |
|
|
#include <kvm.h> |
110 |
|
|
#include <db.h> |
111 |
|
|
#include <stddef.h> |
112 |
|
|
#include <stdlib.h> |
113 |
|
|
#include <string.h> |
114 |
|
|
#include <unistd.h> |
115 |
|
|
#include <limits.h> |
116 |
|
|
#include <errno.h> |
117 |
|
|
|
118 |
|
|
#include "kvm_private.h" |
119 |
|
|
#include "kvm_file.h" |
120 |
|
|
|
121 |
|
|
static struct kinfo_file *kvm_deadfile_byfile(kvm_t *, int, int, |
122 |
|
|
size_t, int *); |
123 |
|
|
static struct kinfo_file *kvm_deadfile_byid(kvm_t *, int, int, |
124 |
|
|
size_t, int *); |
125 |
|
|
static int fill_file(kvm_t *, struct kinfo_file *, struct file *, u_long, |
126 |
|
|
struct vnode *, struct process *, int, pid_t); |
127 |
|
|
static int filestat(kvm_t *, struct kinfo_file *, struct vnode *); |
128 |
|
|
|
129 |
|
|
LIST_HEAD(processlist, process); |
130 |
|
|
|
131 |
|
|
struct kinfo_file * |
132 |
|
|
kvm_getfiles(kvm_t *kd, int op, int arg, size_t esize, int *cnt) |
133 |
|
|
{ |
134 |
|
|
int mib[6], rv; |
135 |
|
|
void *filebase; |
136 |
|
|
size_t size; |
137 |
|
|
|
138 |
|
|
if (ISALIVE(kd)) { |
139 |
|
|
mib[0] = CTL_KERN; |
140 |
|
|
mib[1] = KERN_FILE; |
141 |
|
|
mib[2] = op; |
142 |
|
|
mib[3] = arg; |
143 |
|
|
mib[4] = esize; |
144 |
|
|
|
145 |
|
|
do { |
146 |
|
|
mib[5] = 0; |
147 |
|
|
|
148 |
|
|
/* find size and alloc buffer */ |
149 |
|
|
rv = sysctl(mib, 6, NULL, &size, NULL, 0); |
150 |
|
|
if (rv == -1) { |
151 |
|
|
if (errno != ESRCH && kd->vmfd != -1) |
152 |
|
|
goto deadway; |
153 |
|
|
_kvm_syserr(kd, kd->program, "kvm_getfiles"); |
154 |
|
|
return (NULL); |
155 |
|
|
} |
156 |
|
|
|
157 |
|
|
size += size / 8; /* add ~10% */ |
158 |
|
|
|
159 |
|
|
filebase = _kvm_realloc(kd, kd->filebase, size); |
160 |
|
|
if (filebase == NULL) |
161 |
|
|
return (NULL); |
162 |
|
|
|
163 |
|
|
kd->filebase = filebase; |
164 |
|
|
|
165 |
|
|
/* get actual data */ |
166 |
|
|
mib[5] = size / esize; |
167 |
|
|
rv = sysctl(mib, 6, kd->filebase, &size, NULL, 0); |
168 |
|
|
if (rv == -1 && errno != ENOMEM) { |
169 |
|
|
_kvm_syserr(kd, kd->program, |
170 |
|
|
"kvm_getfiles"); |
171 |
|
|
return (NULL); |
172 |
|
|
} |
173 |
|
|
} while (rv == -1); |
174 |
|
|
|
175 |
|
|
*cnt = size / esize; |
176 |
|
|
return (kd->filebase); |
177 |
|
|
} else { |
178 |
|
|
if (esize > sizeof(struct kinfo_file)) { |
179 |
|
|
_kvm_syserr(kd, kd->program, |
180 |
|
|
"kvm_getfiles: unknown fields requested: libkvm out of date?"); |
181 |
|
|
return (NULL); |
182 |
|
|
} |
183 |
|
|
deadway: |
184 |
|
|
switch (op) { |
185 |
|
|
case KERN_FILE_BYFILE: |
186 |
|
|
return (kvm_deadfile_byfile(kd, op, arg, esize, cnt)); |
187 |
|
|
break; |
188 |
|
|
case KERN_FILE_BYPID: |
189 |
|
|
case KERN_FILE_BYUID: |
190 |
|
|
return (kvm_deadfile_byid(kd, op, arg, esize, cnt)); |
191 |
|
|
break; |
192 |
|
|
default: |
193 |
|
|
return (NULL); |
194 |
|
|
} |
195 |
|
|
} |
196 |
|
|
} |
197 |
|
|
|
198 |
|
|
static struct kinfo_file * |
199 |
|
|
kvm_deadfile_byfile(kvm_t *kd, int op, int arg, size_t esize, int *cnt) |
200 |
|
|
{ |
201 |
|
|
struct nlist nl[3], *p; |
202 |
|
|
size_t buflen; |
203 |
|
|
int n = 0; |
204 |
|
|
char *where; |
205 |
|
|
struct kinfo_file kf; |
206 |
|
|
struct file *fp, file; |
207 |
|
|
struct filelist filehead; |
208 |
|
|
int nfiles; |
209 |
|
|
|
210 |
|
|
nl[0].n_name = "_filehead"; |
211 |
|
|
nl[1].n_name = "_nfiles"; |
212 |
|
|
nl[2].n_name = 0; |
213 |
|
|
|
214 |
|
|
if (kvm_nlist(kd, nl) != 0) { |
215 |
|
|
for (p = nl; p->n_type != 0; ++p) |
216 |
|
|
; |
217 |
|
|
_kvm_err(kd, kd->program, |
218 |
|
|
"%s: no such symbol", p->n_name); |
219 |
|
|
return (NULL); |
220 |
|
|
} |
221 |
|
|
if (KREAD(kd, nl[0].n_value, &filehead)) { |
222 |
|
|
_kvm_err(kd, kd->program, "can't read filehead"); |
223 |
|
|
return (NULL); |
224 |
|
|
} |
225 |
|
|
if (KREAD(kd, nl[1].n_value, &nfiles)) { |
226 |
|
|
_kvm_err(kd, kd->program, "can't read nfiles"); |
227 |
|
|
return (NULL); |
228 |
|
|
} |
229 |
|
|
where = _kvm_reallocarray(kd, kd->filebase, nfiles, esize); |
230 |
|
|
if (where == NULL) |
231 |
|
|
return (NULL); |
232 |
|
|
|
233 |
|
|
kd->filebase = (void *)where; |
234 |
|
|
buflen = nfiles * esize; |
235 |
|
|
|
236 |
|
|
for (fp = LIST_FIRST(&filehead); |
237 |
|
|
fp != NULL && esize <= buflen; |
238 |
|
|
fp = LIST_NEXT(&file, f_list)) { |
239 |
|
|
if (KREAD(kd, (u_long)fp, &file)) { |
240 |
|
|
_kvm_err(kd, kd->program, "can't read kfp"); |
241 |
|
|
return (NULL); |
242 |
|
|
} |
243 |
|
|
if (file.f_count == 0) |
244 |
|
|
continue; |
245 |
|
|
if (arg != 0 && file.f_type != arg) |
246 |
|
|
continue; |
247 |
|
|
if (fill_file(kd, &kf, &file, (u_long)fp, NULL, NULL, 0, 0) |
248 |
|
|
== -1) |
249 |
|
|
return (NULL); |
250 |
|
|
memcpy(where, &kf, esize); |
251 |
|
|
where += esize; |
252 |
|
|
buflen -= esize; |
253 |
|
|
n++; |
254 |
|
|
} |
255 |
|
|
if (n != nfiles) { |
256 |
|
|
_kvm_err(kd, kd->program, "inconsistent nfiles"); |
257 |
|
|
return (NULL); |
258 |
|
|
} |
259 |
|
|
*cnt = n; |
260 |
|
|
return (kd->filebase); |
261 |
|
|
} |
262 |
|
|
|
263 |
|
|
static struct kinfo_file * |
264 |
|
|
kvm_deadfile_byid(kvm_t *kd, int op, int arg, size_t esize, int *cnt) |
265 |
|
|
{ |
266 |
|
|
size_t buflen; |
267 |
|
|
struct nlist nl[4], *np; |
268 |
|
|
int n = 0, matched = 0; |
269 |
|
|
char *where; |
270 |
|
|
struct kinfo_file kf; |
271 |
|
|
struct file *fp, file; |
272 |
|
|
struct filelist filehead; |
273 |
|
|
struct filedesc0 filed0; |
274 |
|
|
#define filed filed0.fd_fd |
275 |
|
|
struct processlist allprocess; |
276 |
|
|
struct process *pr, process; |
277 |
|
|
struct ucred ucred; |
278 |
|
|
char *filebuf = NULL; |
279 |
|
|
int i, nfiles; |
280 |
|
|
|
281 |
|
|
nl[0].n_name = "_filehead"; |
282 |
|
|
nl[1].n_name = "_nfiles"; |
283 |
|
|
nl[2].n_name = "_allprocess"; |
284 |
|
|
nl[3].n_name = 0; |
285 |
|
|
|
286 |
|
|
if (kvm_nlist(kd, nl) != 0) { |
287 |
|
|
for (np = nl; np->n_type != 0; ++np) |
288 |
|
|
; |
289 |
|
|
_kvm_err(kd, kd->program, |
290 |
|
|
"%s: no such symbol", np->n_name); |
291 |
|
|
return (NULL); |
292 |
|
|
} |
293 |
|
|
if (KREAD(kd, nl[0].n_value, &filehead)) { |
294 |
|
|
_kvm_err(kd, kd->program, "can't read filehead"); |
295 |
|
|
return (NULL); |
296 |
|
|
} |
297 |
|
|
if (KREAD(kd, nl[1].n_value, &nfiles)) { |
298 |
|
|
_kvm_err(kd, kd->program, "can't read nfiles"); |
299 |
|
|
return (NULL); |
300 |
|
|
} |
301 |
|
|
if (KREAD(kd, nl[2].n_value, &allprocess)) { |
302 |
|
|
_kvm_err(kd, kd->program, "can't read allprocess"); |
303 |
|
|
return (NULL); |
304 |
|
|
} |
305 |
|
|
/* this may be more room than we need but counting is expensive */ |
306 |
|
|
where = _kvm_reallocarray(kd, kd->filebase, nfiles + 10, esize); |
307 |
|
|
if (where == NULL) |
308 |
|
|
return (NULL); |
309 |
|
|
|
310 |
|
|
kd->filebase = (void *)where; |
311 |
|
|
buflen = (nfiles + 10) * esize; |
312 |
|
|
|
313 |
|
|
if (op != KERN_FILE_BYPID || arg <= 0) |
314 |
|
|
matched = 1; |
315 |
|
|
|
316 |
|
|
for (pr = LIST_FIRST(&allprocess); |
317 |
|
|
pr != NULL; |
318 |
|
|
pr = LIST_NEXT(&process, ps_list)) { |
319 |
|
|
if (KREAD(kd, (u_long)pr, &process)) { |
320 |
|
|
_kvm_err(kd, kd->program, "can't read process at %lx", |
321 |
|
|
(u_long)pr); |
322 |
|
|
goto cleanup; |
323 |
|
|
} |
324 |
|
|
|
325 |
|
|
/* skip system, exiting, embryonic and undead processes */ |
326 |
|
|
if (process.ps_flags & (PS_SYSTEM | PS_EMBRYO | PS_EXITING)) |
327 |
|
|
continue; |
328 |
|
|
|
329 |
|
|
if (op == KERN_FILE_BYPID) { |
330 |
|
|
/* check if this is the pid we are looking for */ |
331 |
|
|
if (arg > 0 && process.ps_pid != (pid_t)arg) |
332 |
|
|
continue; |
333 |
|
|
matched = 1; |
334 |
|
|
} |
335 |
|
|
|
336 |
|
|
if (KREAD(kd, (u_long)process.ps_ucred, &ucred)) { |
337 |
|
|
_kvm_err(kd, kd->program, "can't read ucred at %lx", |
338 |
|
|
(u_long)process.ps_ucred); |
339 |
|
|
goto cleanup; |
340 |
|
|
} |
341 |
|
|
process.ps_ucred = &ucred; |
342 |
|
|
|
343 |
|
|
if (op == KERN_FILE_BYUID && arg >= 0 && |
344 |
|
|
process.ps_ucred->cr_uid != (uid_t)arg) { |
345 |
|
|
/* not the uid we are looking for */ |
346 |
|
|
continue; |
347 |
|
|
} |
348 |
|
|
|
349 |
|
|
if (KREAD(kd, (u_long)process.ps_fd, &filed0)) { |
350 |
|
|
_kvm_err(kd, kd->program, "can't read filedesc at %lx", |
351 |
|
|
(u_long)process.ps_fd); |
352 |
|
|
goto cleanup; |
353 |
|
|
} |
354 |
|
|
if ((char *)process.ps_fd + offsetof(struct filedesc0,fd_dfiles) |
355 |
|
|
== (char *)filed.fd_ofiles) { |
356 |
|
|
filed.fd_ofiles = filed0.fd_dfiles; |
357 |
|
|
filed.fd_ofileflags = filed0.fd_dfileflags; |
358 |
|
|
} else { |
359 |
|
|
size_t fsize; |
360 |
|
|
char *tmp = reallocarray(filebuf, |
361 |
|
|
filed.fd_nfiles, OFILESIZE); |
362 |
|
|
|
363 |
|
|
fsize = filed.fd_nfiles * OFILESIZE; |
364 |
|
|
if (tmp == NULL) { |
365 |
|
|
_kvm_syserr(kd, kd->program, "realloc ofiles"); |
366 |
|
|
goto cleanup; |
367 |
|
|
} |
368 |
|
|
filebuf = tmp; |
369 |
|
|
if (kvm_read(kd, (u_long)filed.fd_ofiles, filebuf, |
370 |
|
|
fsize) != fsize) { |
371 |
|
|
_kvm_err(kd, kd->program, |
372 |
|
|
"can't read fd_ofiles"); |
373 |
|
|
goto cleanup; |
374 |
|
|
} |
375 |
|
|
filed.fd_ofiles = (void *)filebuf; |
376 |
|
|
filed.fd_ofileflags = filebuf + |
377 |
|
|
(filed.fd_nfiles * sizeof(struct file *)); |
378 |
|
|
} |
379 |
|
|
process.ps_fd = &filed; |
380 |
|
|
|
381 |
|
|
if (process.ps_textvp) { |
382 |
|
|
if (buflen < esize) |
383 |
|
|
goto done; |
384 |
|
|
if (fill_file(kd, &kf, NULL, 0, process.ps_textvp, |
385 |
|
|
&process, KERN_FILE_TEXT, process.ps_pid) == -1) |
386 |
|
|
goto cleanup; |
387 |
|
|
memcpy(where, &kf, esize); |
388 |
|
|
where += esize; |
389 |
|
|
buflen -= esize; |
390 |
|
|
n++; |
391 |
|
|
} |
392 |
|
|
if (filed.fd_cdir) { |
393 |
|
|
if (buflen < esize) |
394 |
|
|
goto done; |
395 |
|
|
if (fill_file(kd, &kf, NULL, 0, filed.fd_cdir, |
396 |
|
|
&process, KERN_FILE_CDIR, process.ps_pid) == -1) |
397 |
|
|
goto cleanup; |
398 |
|
|
memcpy(where, &kf, esize); |
399 |
|
|
where += esize; |
400 |
|
|
buflen -= esize; |
401 |
|
|
n++; |
402 |
|
|
} |
403 |
|
|
if (filed.fd_rdir) { |
404 |
|
|
if (buflen < esize) |
405 |
|
|
goto done; |
406 |
|
|
if (fill_file(kd, &kf, NULL, 0, filed.fd_rdir, |
407 |
|
|
&process, KERN_FILE_RDIR, process.ps_pid) == -1) |
408 |
|
|
goto cleanup; |
409 |
|
|
memcpy(where, &kf, esize); |
410 |
|
|
where += esize; |
411 |
|
|
buflen -= esize; |
412 |
|
|
n++; |
413 |
|
|
} |
414 |
|
|
if (process.ps_tracevp) { |
415 |
|
|
if (buflen < esize) |
416 |
|
|
goto done; |
417 |
|
|
if (fill_file(kd, &kf, NULL, 0, process.ps_tracevp, |
418 |
|
|
&process, KERN_FILE_TRACE, process.ps_pid) == -1) |
419 |
|
|
goto cleanup; |
420 |
|
|
memcpy(where, &kf, esize); |
421 |
|
|
where += esize; |
422 |
|
|
buflen -= esize; |
423 |
|
|
n++; |
424 |
|
|
} |
425 |
|
|
|
426 |
|
|
if (filed.fd_nfiles < 0 || |
427 |
|
|
filed.fd_lastfile >= filed.fd_nfiles || |
428 |
|
|
filed.fd_freefile > filed.fd_lastfile + 1) { |
429 |
|
|
_kvm_err(kd, kd->program, |
430 |
|
|
"filedesc corrupted at %lx for pid %d", |
431 |
|
|
(u_long)process.ps_fd, process.ps_pid); |
432 |
|
|
goto cleanup; |
433 |
|
|
} |
434 |
|
|
|
435 |
|
|
for (i = 0; i < filed.fd_nfiles; i++) { |
436 |
|
|
if (buflen < esize) |
437 |
|
|
goto done; |
438 |
|
|
if ((fp = filed.fd_ofiles[i]) == NULL) |
439 |
|
|
continue; |
440 |
|
|
if (KREAD(kd, (u_long)fp, &file)) { |
441 |
|
|
_kvm_err(kd, kd->program, "can't read file"); |
442 |
|
|
goto cleanup; |
443 |
|
|
} |
444 |
|
|
if (fill_file(kd, &kf, &file, (u_long)fp, NULL, |
445 |
|
|
&process, i, process.ps_pid) == -1) |
446 |
|
|
goto cleanup; |
447 |
|
|
memcpy(where, &kf, esize); |
448 |
|
|
where += esize; |
449 |
|
|
buflen -= esize; |
450 |
|
|
n++; |
451 |
|
|
} |
452 |
|
|
} |
453 |
|
|
if (!matched) { |
454 |
|
|
errno = ESRCH; |
455 |
|
|
goto cleanup; |
456 |
|
|
} |
457 |
|
|
done: |
458 |
|
|
*cnt = n; |
459 |
|
|
free(filebuf); |
460 |
|
|
return (kd->filebase); |
461 |
|
|
cleanup: |
462 |
|
|
free(filebuf); |
463 |
|
|
return (NULL); |
464 |
|
|
} |
465 |
|
|
|
466 |
|
|
static int |
467 |
|
|
fill_file(kvm_t *kd, struct kinfo_file *kf, struct file *fp, u_long fpaddr, |
468 |
|
|
struct vnode *vp, struct process *pr, int fd, pid_t pid) |
469 |
|
|
{ |
470 |
|
|
struct ucred f_cred; |
471 |
|
|
|
472 |
|
|
memset(kf, 0, sizeof(*kf)); |
473 |
|
|
|
474 |
|
|
kf->fd_fd = fd; /* might not really be an fd */ |
475 |
|
|
|
476 |
|
|
if (fp != NULL) { |
477 |
|
|
/* Fill in f_cred */ |
478 |
|
|
if (KREAD(kd, (u_long)fp->f_cred, &f_cred)) { |
479 |
|
|
_kvm_err(kd, kd->program, "can't read f_cred"); |
480 |
|
|
return (-1); |
481 |
|
|
} |
482 |
|
|
|
483 |
|
|
kf->f_fileaddr = PTRTOINT64(fpaddr); |
484 |
|
|
kf->f_flag = fp->f_flag; |
485 |
|
|
kf->f_iflags = fp->f_iflags; |
486 |
|
|
kf->f_type = fp->f_type; |
487 |
|
|
kf->f_count = fp->f_count; |
488 |
|
|
kf->f_ucred = PTRTOINT64(fp->f_cred); |
489 |
|
|
kf->f_uid = f_cred.cr_uid; |
490 |
|
|
kf->f_gid = f_cred.cr_gid; |
491 |
|
|
kf->f_ops = PTRTOINT64(fp->f_ops); |
492 |
|
|
kf->f_offset = fp->f_offset; |
493 |
|
|
kf->f_data = PTRTOINT64(fp->f_data); |
494 |
|
|
kf->f_usecount = 0; |
495 |
|
|
|
496 |
|
|
kf->f_rxfer = fp->f_rxfer; |
497 |
|
|
kf->f_rwfer = fp->f_wxfer; |
498 |
|
|
kf->f_seek = fp->f_seek; |
499 |
|
|
kf->f_rbytes = fp->f_rbytes; |
500 |
|
|
kf->f_wbytes = fp->f_wbytes; |
501 |
|
|
} else if (vp != NULL) { |
502 |
|
|
/* fake it */ |
503 |
|
|
kf->f_type = DTYPE_VNODE; |
504 |
|
|
kf->f_flag = FREAD; |
505 |
|
|
if (fd == KERN_FILE_TRACE) |
506 |
|
|
kf->f_flag |= FWRITE; |
507 |
|
|
kf->f_data = PTRTOINT64(vp); |
508 |
|
|
} |
509 |
|
|
|
510 |
|
|
/* information about the object associated with this file */ |
511 |
|
|
switch (kf->f_type) { |
512 |
|
|
case DTYPE_VNODE: { |
513 |
|
|
struct vnode vbuf; |
514 |
|
|
|
515 |
|
|
if (KREAD(kd, (u_long)(fp ? fp->f_data : vp), &vbuf)) { |
516 |
|
|
_kvm_err(kd, kd->program, "can't read vnode"); |
517 |
|
|
return (-1); |
518 |
|
|
} |
519 |
|
|
vp = &vbuf; |
520 |
|
|
|
521 |
|
|
kf->v_un = PTRTOINT64(vp->v_un.vu_socket); |
522 |
|
|
kf->v_type = vp->v_type; |
523 |
|
|
kf->v_tag = vp->v_tag; |
524 |
|
|
kf->v_flag = vp->v_flag; |
525 |
|
|
kf->v_data = PTRTOINT64(vp->v_data); |
526 |
|
|
kf->v_mount = PTRTOINT64(vp->v_mount); |
527 |
|
|
|
528 |
|
|
if (vp->v_mount != NULL) { |
529 |
|
|
struct mount mount; |
530 |
|
|
|
531 |
|
|
if (KREAD(kd, (u_long)vp->v_mount, &mount)) { |
532 |
|
|
_kvm_err(kd, kd->program, "can't read v_mount"); |
533 |
|
|
return (-1); |
534 |
|
|
} |
535 |
|
|
|
536 |
|
|
strlcpy(kf->f_mntonname, mount.mnt_stat.f_mntonname, |
537 |
|
|
sizeof(kf->f_mntonname)); |
538 |
|
|
} |
539 |
|
|
|
540 |
|
|
/* Fill in va_fsid, va_fileid, va_mode, va_size, va_rdev */ |
541 |
|
|
filestat(kd, kf, vp); |
542 |
|
|
break; |
543 |
|
|
} |
544 |
|
|
|
545 |
|
|
case DTYPE_SOCKET: { |
546 |
|
|
struct socket sock; |
547 |
|
|
struct sosplice ssp; |
548 |
|
|
struct protosw protosw; |
549 |
|
|
struct domain domain; |
550 |
|
|
|
551 |
|
|
if (KREAD(kd, (u_long)fp->f_data, &sock)) { |
552 |
|
|
_kvm_err(kd, kd->program, "can't read socket"); |
553 |
|
|
return (-1); |
554 |
|
|
} |
555 |
|
|
|
556 |
|
|
kf->so_type = sock.so_type; |
557 |
|
|
kf->so_state = sock.so_state; |
558 |
|
|
kf->so_pcb = PTRTOINT64(sock.so_pcb); |
559 |
|
|
if (KREAD(kd, (u_long)sock.so_proto, &protosw)) { |
560 |
|
|
_kvm_err(kd, kd->program, "can't read protosw"); |
561 |
|
|
return (-1); |
562 |
|
|
} |
563 |
|
|
kf->so_protocol = protosw.pr_protocol; |
564 |
|
|
if (KREAD(kd, (u_long)protosw.pr_domain, &domain)) { |
565 |
|
|
_kvm_err(kd, kd->program, "can't read domain"); |
566 |
|
|
return (-1); |
567 |
|
|
} |
568 |
|
|
kf->so_family = domain.dom_family; |
569 |
|
|
kf->so_rcv_cc = sock.so_rcv.sb_cc; |
570 |
|
|
kf->so_snd_cc = sock.so_snd.sb_cc; |
571 |
|
|
if (sock.so_sp) { |
572 |
|
|
if (KREAD(kd, (u_long)sock.so_sp, &ssp)) { |
573 |
|
|
_kvm_err(kd, kd->program, "can't read splice"); |
574 |
|
|
return (-1); |
575 |
|
|
} |
576 |
|
|
if (ssp.ssp_socket) { |
577 |
|
|
kf->so_splice = PTRTOINT64(ssp.ssp_socket); |
578 |
|
|
kf->so_splicelen = ssp.ssp_len; |
579 |
|
|
} else if (ssp.ssp_soback) { |
580 |
|
|
kf->so_splicelen = -1; |
581 |
|
|
} |
582 |
|
|
} |
583 |
|
|
if (!sock.so_pcb) |
584 |
|
|
break; |
585 |
|
|
switch (kf->so_family) { |
586 |
|
|
case AF_INET: { |
587 |
|
|
struct inpcb inpcb; |
588 |
|
|
|
589 |
|
|
if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) { |
590 |
|
|
_kvm_err(kd, kd->program, "can't read inpcb"); |
591 |
|
|
return (-1); |
592 |
|
|
} |
593 |
|
|
kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb); |
594 |
|
|
kf->inp_lport = inpcb.inp_lport; |
595 |
|
|
kf->inp_laddru[0] = inpcb.inp_laddr.s_addr; |
596 |
|
|
kf->inp_fport = inpcb.inp_fport; |
597 |
|
|
kf->inp_faddru[0] = inpcb.inp_faddr.s_addr; |
598 |
|
|
kf->inp_rtableid = inpcb.inp_rtableid; |
599 |
|
|
if (sock.so_type == SOCK_RAW) |
600 |
|
|
kf->inp_proto = inpcb.inp_ip.ip_p; |
601 |
|
|
if (protosw.pr_protocol == IPPROTO_TCP) { |
602 |
|
|
struct tcpcb tcpcb; |
603 |
|
|
if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) { |
604 |
|
|
_kvm_err(kd, kd->program, |
605 |
|
|
"can't read tcpcb"); |
606 |
|
|
return (-1); |
607 |
|
|
} |
608 |
|
|
kf->t_rcv_wnd = tcpcb.rcv_wnd; |
609 |
|
|
kf->t_snd_wnd = tcpcb.snd_wnd; |
610 |
|
|
kf->t_snd_cwnd = tcpcb.snd_cwnd; |
611 |
|
|
kf->t_state = tcpcb.t_state; |
612 |
|
|
} |
613 |
|
|
break; |
614 |
|
|
} |
615 |
|
|
case AF_INET6: { |
616 |
|
|
struct inpcb inpcb; |
617 |
|
|
#define s6_addr32 __u6_addr.__u6_addr32 |
618 |
|
|
|
619 |
|
|
if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) { |
620 |
|
|
_kvm_err(kd, kd->program, "can't read inpcb"); |
621 |
|
|
return (-1); |
622 |
|
|
} |
623 |
|
|
kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb); |
624 |
|
|
kf->inp_lport = inpcb.inp_lport; |
625 |
|
|
kf->inp_laddru[0] = inpcb.inp_laddr6.s6_addr32[0]; |
626 |
|
|
kf->inp_laddru[1] = inpcb.inp_laddr6.s6_addr32[1]; |
627 |
|
|
kf->inp_laddru[2] = inpcb.inp_laddr6.s6_addr32[2]; |
628 |
|
|
kf->inp_laddru[3] = inpcb.inp_laddr6.s6_addr32[3]; |
629 |
|
|
kf->inp_fport = inpcb.inp_fport; |
630 |
|
|
kf->inp_faddru[0] = inpcb.inp_laddr6.s6_addr32[0]; |
631 |
|
|
kf->inp_faddru[1] = inpcb.inp_faddr6.s6_addr32[1]; |
632 |
|
|
kf->inp_faddru[2] = inpcb.inp_faddr6.s6_addr32[2]; |
633 |
|
|
kf->inp_faddru[3] = inpcb.inp_faddr6.s6_addr32[3]; |
634 |
|
|
kf->inp_rtableid = inpcb.inp_rtableid; |
635 |
|
|
if (sock.so_type == SOCK_RAW) |
636 |
|
|
kf->inp_proto = inpcb.inp_ipv6.ip6_nxt; |
637 |
|
|
if (protosw.pr_protocol == IPPROTO_TCP) { |
638 |
|
|
struct tcpcb tcpcb; |
639 |
|
|
if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) { |
640 |
|
|
_kvm_err(kd, kd->program, |
641 |
|
|
"can't read tcpcb"); |
642 |
|
|
return (-1); |
643 |
|
|
} |
644 |
|
|
kf->t_rcv_wnd = tcpcb.rcv_wnd; |
645 |
|
|
kf->t_snd_wnd = tcpcb.snd_wnd; |
646 |
|
|
kf->t_snd_cwnd = tcpcb.snd_cwnd; |
647 |
|
|
kf->t_state = tcpcb.t_state; |
648 |
|
|
} |
649 |
|
|
break; |
650 |
|
|
} |
651 |
|
|
case AF_UNIX: { |
652 |
|
|
struct unpcb unpcb; |
653 |
|
|
|
654 |
|
|
if (KREAD(kd, (u_long)sock.so_pcb, &unpcb)) { |
655 |
|
|
_kvm_err(kd, kd->program, "can't read unpcb"); |
656 |
|
|
return (-1); |
657 |
|
|
} |
658 |
|
|
kf->f_msgcount = unpcb.unp_msgcount; |
659 |
|
|
kf->unp_conn = PTRTOINT64(unpcb.unp_conn); |
660 |
|
|
kf->unp_refs = PTRTOINT64( |
661 |
|
|
SLIST_FIRST(&unpcb.unp_refs)); |
662 |
|
|
kf->unp_nextref = PTRTOINT64( |
663 |
|
|
SLIST_NEXT(&unpcb, unp_nextref)); |
664 |
|
|
kf->v_un = PTRTOINT64(unpcb.unp_vnode); |
665 |
|
|
if (unpcb.unp_addr != NULL) { |
666 |
|
|
struct mbuf mb; |
667 |
|
|
struct sockaddr_un un; |
668 |
|
|
|
669 |
|
|
if (KREAD(kd, (u_long)unpcb.unp_addr, &mb)) { |
670 |
|
|
_kvm_err(kd, kd->program, |
671 |
|
|
"can't read sockaddr_un mbuf"); |
672 |
|
|
return (-1); |
673 |
|
|
} |
674 |
|
|
if (KREAD(kd, (u_long)mb.m_data, &un)) { |
675 |
|
|
_kvm_err(kd, kd->program, |
676 |
|
|
"can't read sockaddr_un"); |
677 |
|
|
return (-1); |
678 |
|
|
} |
679 |
|
|
|
680 |
|
|
kf->unp_addr = PTRTOINT64(unpcb.unp_addr); |
681 |
|
|
memcpy(kf->unp_path, un.sun_path, un.sun_len |
682 |
|
|
- offsetof(struct sockaddr_un,sun_path)); |
683 |
|
|
} |
684 |
|
|
|
685 |
|
|
break; |
686 |
|
|
} |
687 |
|
|
} |
688 |
|
|
break; |
689 |
|
|
} |
690 |
|
|
|
691 |
|
|
case DTYPE_PIPE: { |
692 |
|
|
struct pipe pipe; |
693 |
|
|
|
694 |
|
|
if (KREAD(kd, (u_long)fp->f_data, &pipe)) { |
695 |
|
|
_kvm_err(kd, kd->program, "can't read pipe"); |
696 |
|
|
return (-1); |
697 |
|
|
} |
698 |
|
|
kf->pipe_peer = PTRTOINT64(pipe.pipe_peer); |
699 |
|
|
kf->pipe_state = pipe.pipe_state; |
700 |
|
|
break; |
701 |
|
|
} |
702 |
|
|
|
703 |
|
|
case DTYPE_KQUEUE: { |
704 |
|
|
struct kqueue kqi; |
705 |
|
|
|
706 |
|
|
if (KREAD(kd, (u_long)fp->f_data, &kqi)) { |
707 |
|
|
_kvm_err(kd, kd->program, "can't read kqi"); |
708 |
|
|
return (-1); |
709 |
|
|
} |
710 |
|
|
kf->kq_count = kqi.kq_count; |
711 |
|
|
kf->kq_state = kqi.kq_state; |
712 |
|
|
break; |
713 |
|
|
} |
714 |
|
|
} |
715 |
|
|
|
716 |
|
|
/* per-process information for KERN_FILE_BY[PU]ID */ |
717 |
|
|
if (pr != NULL) { |
718 |
|
|
kf->p_pid = pid; |
719 |
|
|
kf->p_uid = pr->ps_ucred->cr_uid; |
720 |
|
|
kf->p_gid = pr->ps_ucred->cr_gid; |
721 |
|
|
kf->p_tid = -1; |
722 |
|
|
strlcpy(kf->p_comm, pr->ps_comm, sizeof(kf->p_comm)); |
723 |
|
|
if (pr->ps_fd != NULL) |
724 |
|
|
kf->fd_ofileflags = pr->ps_fd->fd_ofileflags[fd]; |
725 |
|
|
} |
726 |
|
|
|
727 |
|
|
return (0); |
728 |
|
|
} |
729 |
|
|
|
730 |
|
|
mode_t |
731 |
|
|
_kvm_getftype(enum vtype v_type) |
732 |
|
|
{ |
733 |
|
|
mode_t ftype = 0; |
734 |
|
|
|
735 |
|
|
switch (v_type) { |
736 |
|
|
case VREG: |
737 |
|
|
ftype = S_IFREG; |
738 |
|
|
break; |
739 |
|
|
case VDIR: |
740 |
|
|
ftype = S_IFDIR; |
741 |
|
|
break; |
742 |
|
|
case VBLK: |
743 |
|
|
ftype = S_IFBLK; |
744 |
|
|
break; |
745 |
|
|
case VCHR: |
746 |
|
|
ftype = S_IFCHR; |
747 |
|
|
break; |
748 |
|
|
case VLNK: |
749 |
|
|
ftype = S_IFLNK; |
750 |
|
|
break; |
751 |
|
|
case VSOCK: |
752 |
|
|
ftype = S_IFSOCK; |
753 |
|
|
break; |
754 |
|
|
case VFIFO: |
755 |
|
|
ftype = S_IFIFO; |
756 |
|
|
break; |
757 |
|
|
case VNON: |
758 |
|
|
case VBAD: |
759 |
|
|
break; |
760 |
|
|
} |
761 |
|
|
|
762 |
|
|
return (ftype); |
763 |
|
|
} |
764 |
|
|
|
765 |
|
|
static int |
766 |
|
|
ufs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) |
767 |
|
|
{ |
768 |
|
|
struct inode inode; |
769 |
|
|
struct ufs1_dinode di1; |
770 |
|
|
|
771 |
|
|
if (KREAD(kd, (u_long)VTOI(vp), &inode)) { |
772 |
|
|
_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp)); |
773 |
|
|
return (-1); |
774 |
|
|
} |
775 |
|
|
|
776 |
|
|
if (KREAD(kd, (u_long)inode.i_din1, &di1)) { |
777 |
|
|
_kvm_err(kd, kd->program, "can't read dinode at %p", |
778 |
|
|
inode.i_din1); |
779 |
|
|
return (-1); |
780 |
|
|
} |
781 |
|
|
|
782 |
|
|
inode.i_din1 = &di1; |
783 |
|
|
|
784 |
|
|
kf->va_fsid = inode.i_dev & 0xffff; |
785 |
|
|
kf->va_fileid = (long)inode.i_number; |
786 |
|
|
kf->va_mode = inode.i_ffs1_mode; |
787 |
|
|
kf->va_size = inode.i_ffs1_size; |
788 |
|
|
kf->va_rdev = inode.i_ffs1_rdev; |
789 |
|
|
kf->va_nlink = inode.i_ffs1_nlink; |
790 |
|
|
|
791 |
|
|
return (0); |
792 |
|
|
} |
793 |
|
|
|
794 |
|
|
static int |
795 |
|
|
ext2fs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) |
796 |
|
|
{ |
797 |
|
|
struct inode inode; |
798 |
|
|
struct ext2fs_dinode e2di; |
799 |
|
|
|
800 |
|
|
if (KREAD(kd, (u_long)VTOI(vp), &inode)) { |
801 |
|
|
_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp)); |
802 |
|
|
return (-1); |
803 |
|
|
} |
804 |
|
|
|
805 |
|
|
if (KREAD(kd, (u_long)inode.i_e2din, &e2di)) { |
806 |
|
|
_kvm_err(kd, kd->program, "can't read dinode at %p", |
807 |
|
|
inode.i_e2din); |
808 |
|
|
return (-1); |
809 |
|
|
} |
810 |
|
|
|
811 |
|
|
inode.i_e2din = &e2di; |
812 |
|
|
|
813 |
|
|
kf->va_fsid = inode.i_dev & 0xffff; |
814 |
|
|
kf->va_fileid = (long)inode.i_number; |
815 |
|
|
kf->va_mode = inode.i_e2fs_mode; |
816 |
|
|
kf->va_size = inode.i_e2fs_size; |
817 |
|
|
kf->va_rdev = 0; /* XXX */ |
818 |
|
|
kf->va_nlink = inode.i_e2fs_nlink; |
819 |
|
|
|
820 |
|
|
return (0); |
821 |
|
|
} |
822 |
|
|
|
823 |
|
|
static int |
824 |
|
|
msdos_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) |
825 |
|
|
{ |
826 |
|
|
struct denode de; |
827 |
|
|
struct msdosfsmount mp; |
828 |
|
|
|
829 |
|
|
if (KREAD(kd, (u_long)VTODE(vp), &de)) { |
830 |
|
|
_kvm_err(kd, kd->program, "can't read denode at %p", VTODE(vp)); |
831 |
|
|
return (-1); |
832 |
|
|
} |
833 |
|
|
if (KREAD(kd, (u_long)de.de_pmp, &mp)) { |
834 |
|
|
_kvm_err(kd, kd->program, "can't read mount struct at %p", |
835 |
|
|
de.de_pmp); |
836 |
|
|
return (-1); |
837 |
|
|
} |
838 |
|
|
|
839 |
|
|
kf->va_fsid = de.de_dev & 0xffff; |
840 |
|
|
kf->va_fileid = 0; /* XXX see msdosfs_vptofh() for more info */ |
841 |
|
|
kf->va_mode = (mp.pm_mask & 0777) | _kvm_getftype(vp->v_type); |
842 |
|
|
kf->va_size = de.de_FileSize; |
843 |
|
|
kf->va_rdev = 0; /* msdosfs doesn't support device files */ |
844 |
|
|
kf->va_nlink = 1; |
845 |
|
|
|
846 |
|
|
return (0); |
847 |
|
|
} |
848 |
|
|
|
849 |
|
|
static int |
850 |
|
|
nfs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) |
851 |
|
|
{ |
852 |
|
|
struct nfsnode nfsnode; |
853 |
|
|
|
854 |
|
|
if (KREAD(kd, (u_long)VTONFS(vp), &nfsnode)) { |
855 |
|
|
_kvm_err(kd, kd->program, "can't read nfsnode at %p", |
856 |
|
|
VTONFS(vp)); |
857 |
|
|
return (-1); |
858 |
|
|
} |
859 |
|
|
kf->va_fsid = nfsnode.n_vattr.va_fsid; |
860 |
|
|
kf->va_fileid = nfsnode.n_vattr.va_fileid; |
861 |
|
|
kf->va_size = nfsnode.n_size; |
862 |
|
|
kf->va_rdev = nfsnode.n_vattr.va_rdev; |
863 |
|
|
kf->va_mode = (mode_t)nfsnode.n_vattr.va_mode | _kvm_getftype(vp->v_type); |
864 |
|
|
kf->va_nlink = nfsnode.n_vattr.va_nlink; |
865 |
|
|
|
866 |
|
|
return (0); |
867 |
|
|
} |
868 |
|
|
|
869 |
|
|
static int |
870 |
|
|
spec_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) |
871 |
|
|
{ |
872 |
|
|
struct specinfo specinfo; |
873 |
|
|
struct vnode parent; |
874 |
|
|
|
875 |
|
|
if (KREAD(kd, (u_long)vp->v_specinfo, &specinfo)) { |
876 |
|
|
_kvm_err(kd, kd->program, "can't read specinfo at %p", |
877 |
|
|
vp->v_specinfo); |
878 |
|
|
return (-1); |
879 |
|
|
} |
880 |
|
|
|
881 |
|
|
vp->v_specinfo = &specinfo; |
882 |
|
|
|
883 |
|
|
if (KREAD(kd, (u_long)vp->v_specparent, &parent)) { |
884 |
|
|
_kvm_err(kd, kd->program, "can't read parent vnode at %p", |
885 |
|
|
vp->v_specparent); |
886 |
|
|
return (-1); |
887 |
|
|
} |
888 |
|
|
|
889 |
|
|
if (ufs_filestat(kd, kf, vp)) |
890 |
|
|
return (-1); |
891 |
|
|
|
892 |
|
|
return (0); |
893 |
|
|
} |
894 |
|
|
|
895 |
|
|
static int |
896 |
|
|
filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) |
897 |
|
|
{ |
898 |
|
|
int ret = 0; |
899 |
|
|
|
900 |
|
|
if (vp->v_type != VNON && vp->v_type != VBAD) { |
901 |
|
|
switch (vp->v_tag) { |
902 |
|
|
case VT_UFS: |
903 |
|
|
case VT_MFS: |
904 |
|
|
ret = ufs_filestat(kd, kf, vp); |
905 |
|
|
break; |
906 |
|
|
case VT_NFS: |
907 |
|
|
ret = nfs_filestat(kd, kf, vp); |
908 |
|
|
break; |
909 |
|
|
case VT_EXT2FS: |
910 |
|
|
ret = ext2fs_filestat(kd, kf, vp); |
911 |
|
|
break; |
912 |
|
|
case VT_ISOFS: |
913 |
|
|
ret = _kvm_stat_cd9660(kd, kf, vp); |
914 |
|
|
break; |
915 |
|
|
case VT_MSDOSFS: |
916 |
|
|
ret = msdos_filestat(kd, kf, vp); |
917 |
|
|
break; |
918 |
|
|
case VT_UDF: |
919 |
|
|
ret = _kvm_stat_udf(kd, kf, vp); |
920 |
|
|
break; |
921 |
|
|
case VT_NTFS: |
922 |
|
|
ret = _kvm_stat_ntfs(kd, kf, vp); |
923 |
|
|
break; |
924 |
|
|
case VT_NON: |
925 |
|
|
if (vp->v_flag & VCLONE) |
926 |
|
|
ret = spec_filestat(kd, kf, vp); |
927 |
|
|
break; |
928 |
|
|
default: |
929 |
|
|
ret = -1; |
930 |
|
|
break; |
931 |
|
|
} |
932 |
|
|
} |
933 |
|
|
return (ret); |
934 |
|
|
} |