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