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