1/* 2 * dfile.c -- Darwin file processing functions for libproc-based lsof 3 */ 4 5 6/* 7 * Portions Copyright 2005-2007 Apple Inc. All rights reserved. 8 * 9 * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana 10 * 47907. All rights reserved. 11 * 12 * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue 13 * University. 14 * 15 * This software is not subject to any license of the American Telephone 16 * and Telegraph Company or the Regents of the University of California. 17 * 18 * Permission is granted to anyone to use this software for any purpose on 19 * any computer system, and to alter it and redistribute it freely, subject 20 * to the following restrictions: 21 * 22 * 1. Neither the authors, nor Apple Inc. nor Purdue University are 23 * responsible for any consequences of the use of this software. 24 * 25 * 2. The origin of this software must not be misrepresented, either 26 * by explicit claim or by omission. Credit to the authors, Apple 27 * Inc. and Purdue University must appear in documentation and sources. 28 * 29 * 3. Altered versions must be plainly marked as such, and must not be 30 * misrepresented as being the original software. 31 * 32 * 4. This notice may not be removed or altered. 33 */ 34 35 36#ifndef lint 37static char copyright[] = 38"@(#) Copyright 2005-2007 Apple Inc. and Purdue Research Foundation.\nAll rights reserved.\n"; 39static char *rcsid = "$Id: dfile.c,v 1.8 2012/04/10 16:41:04 abe Exp $"; 40#endif 41 42 43#include "lsof.h" 44 45 46/* 47 * enter_file_info() -- enter file information 48 */ 49 50void 51enter_file_info(pfi) 52 struct proc_fileinfo *pfi; /* pointer to process file info */ 53{ 54 int f; 55/* 56 * Construct access code 57 */ 58 f = pfi->fi_openflags & (FREAD | FWRITE); 59 if (f == FREAD) 60 Lf->access = 'r'; 61 else if (f == FWRITE) 62 Lf->access = 'w'; 63 else if (f == (FREAD | FWRITE)) 64 Lf->access = 'u'; 65/* 66 * Save the offset / size 67 */ 68 Lf->off = (SZOFFTYPE)pfi->fi_offset; 69 if (Foffset) 70 Lf->off_def = 1; 71/* 72 * Save file structure information as requested. 73 */ 74 if (Fsv & FSV_FG) { 75 Lf->ffg = (long)pfi->fi_openflags; 76 Lf->fsv |= FSV_FG; 77 78#ifdef PROC_FP_GUARDED 79 if (pfi->fi_status & PROC_FP_GUARDED) { 80 Lf->guardflags = pfi->fi_guardflags; 81 } 82#endif /* PROC_FP_GUARDED */ 83 } 84 Lf->pof = (long)pfi->fi_status; 85} 86 87 88/* 89 * enter_vnode_info() -- enter vnode information 90 */ 91 92void 93enter_vnode_info(vip) 94 struct vnode_info_path *vip; /* pointer to vnode info with path */ 95{ 96 char buf[32], *cp; 97 dev_t dev = 0; 98 int devs = 0; 99 struct mounts *mp; 100/* 101 * Derive file type. 102 */ 103 switch ((int)(vip->vip_vi.vi_stat.vst_mode & S_IFMT)) { 104 case S_IFIFO: 105 cp = "FIFO"; 106 Ntype = N_FIFO; 107 break; 108 case S_IFCHR: 109 cp = "CHR"; 110 Ntype = N_CHR; 111 break; 112 case S_IFDIR: 113 cp = "DIR"; 114 Ntype = N_REGLR; 115 break; 116 case S_IFBLK: 117 cp = "BLK"; 118 Ntype = N_BLK; 119 break; 120 case S_IFREG: 121 cp = "REG"; 122 Ntype = N_REGLR; 123 break; 124 case S_IFLNK: 125 cp = "LINK"; 126 Ntype = N_REGLR; 127 break; 128 default: 129 (void) snpf(buf, sizeof(buf), "%04o", 130 (((vip->vip_vi.vi_stat.vst_mode & S_IFMT) >> 12) & 0xfff)); 131 cp = buf; 132 Ntype = N_REGLR; 133 } 134 if (!Lf->type[0]) 135 (void) snpf(Lf->type, sizeof(Lf->type), "%s", cp); 136 Lf->ntype = Ntype; 137/* 138 * Save device number and path 139 */ 140 switch (Ntype) { 141 case N_FIFO: 142 break; 143 case N_CHR: 144 case N_BLK: 145 Lf->rdev = vip->vip_vi.vi_stat.vst_rdev; 146 Lf->rdev_def = 1; 147 /* fall through */ 148 default: 149 Lf->dev = dev = vip->vip_vi.vi_stat.vst_dev; 150 Lf->dev_def = devs = 1; 151 } 152/* 153 * Save path name. 154 */ 155 vip->vip_path[sizeof(vip->vip_path) - 1] = '\0'; 156 if (vip->vip_path[0] != '\0') { 157 Lf->V_path = mkstrcpy(vip->vip_path, (MALLOC_S *)NULL); 158 } 159/* 160 * Save node number. 161 */ 162 Lf->inode = (INODETYPE)vip->vip_vi.vi_stat.vst_ino; 163 Lf->inp_ty = 1; 164/* 165 * Save link count, as requested. 166 */ 167 if (Fnlink) { 168 Lf->nlink = vip->vip_vi.vi_stat.vst_nlink; 169 Lf->nlink_def = 1; 170 if (Nlink && (Lf->nlink < Nlink)) 171 Lf->sf |= SELNLINK; 172 } 173/* 174 * If a device number is defined, locate file system and save its identity. 175 */ 176 if (devs) { 177 for (mp = readmnt(); mp; mp = mp->next) { 178 if (dev == mp->dev) { 179 Lf->fsdir = mp->dir; 180 Lf->fsdev = mp->fsname; 181 if (mp->is_nfs && Fnfs) 182 Lf->sf |= SELNFS; 183 break; 184 } 185 } 186 } 187/* 188 * Save the file size. 189 */ 190 switch (Ntype) { 191 case N_CHR: 192 case N_FIFO: 193 Lf->off_def = 1; 194 break; 195 default: 196 Lf->sz = (SZOFFTYPE)vip->vip_vi.vi_stat.vst_size; 197 Lf->sz_def = 1; 198 } 199/* 200 * Test for specified file. 201 */ 202 if (Sfile && is_file_named(NULL, 203 ((Ntype == N_CHR) || (Ntype == N_BLK) ? 1 204 : 0))) 205 { 206 Lf->sf |= SELNM; 207 } 208/* 209 * Enter name characters. 210 */ 211 if (!Lf->nm && Namech[0]) 212 enter_nm(Namech); 213} 214 215 216/* 217 * err2nm() -- convert errno to a message in Namech 218 */ 219 220void 221err2nm(pfx) 222 char *pfx; /* Namech message prefix */ 223{ 224 char *sfx; 225 226 switch (errno) { 227 case EBADF: 228 229 /* 230 * The file descriptor is no longer available. 231 */ 232 sfx = "FD unavailable"; 233 break; 234 case ESRCH: 235 236 /* 237 * The process is no longer available. 238 */ 239 sfx = "process unavailable"; 240 break; 241 default: 242 243 /* 244 * All other errors are reported with strerror() information. 245 */ 246 sfx = strerror(errno); 247 } 248 (void) snpf(Namech, Namechl, "%s: %s", pfx, sfx); 249 enter_nm(Namech); 250} 251 252 253/* 254 * print_nm() -- print Name column 255 */ 256void 257print_nm(lf) 258 struct lfile *lf; 259{ 260 unsigned char extra = 0; 261 262 printname(0); 263 264#ifdef PROC_PIDLISTFILEPORTS 265 if (lf->fileport) extra++; 266#endif /* PROC_PIDLISTFILEPORTS */ 267#ifdef PROC_FP_GUARDED 268 if (lf->guardflags) extra++; 269#endif /* PROC_FP_GUARDED */ 270 271 if (extra) 272 (void) printf(" ("); 273 274#ifdef PROC_PIDLISTFILEPORTS 275 if (lf->fileport) 276 (void) printf("fileport=0x%04x", lf->fileport); 277#endif /* PROC_PIDLISTFILEPORTS */ 278 279 if (extra > 1) 280 (void) printf(","); 281 282#ifdef PROC_FP_GUARDED 283 if (lf->guardflags) { 284 struct pff_tab *tp; 285 long gf; 286 287 (void) printf("guard="); 288 tp = Pgf_tab; 289 gf = lf->guardflags; 290 while (gf && !FsvFlagX) { 291 while (tp->nm) { 292 if (gf & tp->val) 293 break; 294 tp++; 295 } 296 if (!tp->nm) 297 break; 298 gf &= ~(tp->val); 299 (void) printf("%s%s", tp->nm, gf ? "," : ""); 300 } 301 /* 302 * If flag bits remain, print them in hex. If hex output was 303 * specified with +fG, print all flag values, including zero, 304 * in hex. 305 */ 306 if (gf || FsvFlagX) 307 (void) printf("0x%lx", gf); 308 } 309#endif /* PROC_FP_GUARDED */ 310 311 if (extra) 312 (void) printf(")"); 313 314 putchar('\n'); 315} 316 317 318/* 319 * print_v_path() -- print vnode's path 320 */ 321 322int 323print_v_path(lf) 324 struct lfile *lf; 325{ 326 if (lf->V_path) { 327 safestrprt(lf->V_path, stdout, 0); 328 return(1); 329 } 330 return(0); 331} 332 333 334/* 335 * process_atalk() -- process an Apple Talk file 336 */ 337 338void 339process_atalk(pid, fd) 340 int pid; /* PID */ 341 int32_t fd; /* FD */ 342{ 343 (void) snpf(Lf->type, sizeof(Lf->type), "ATALK"); 344 return; 345} 346 347 348/* 349 * process_fsevents() -- process a file system events file 350 */ 351 352void 353process_fsevents(pid, fd) 354 int pid; /* PID */ 355 int32_t fd; /* FD */ 356{ 357 (void) snpf(Lf->type, sizeof(Lf->type), "FSEVENTS"); 358} 359 360 361/* 362 * process_kqueue() -- process a kernel queue file 363 */ 364 365void 366process_kqueue(pid, fd) 367 int pid; /* PID */ 368 int32_t fd; /* FD */ 369{ 370 struct kqueue_fdinfo kq; 371 int nb; 372/* 373 * Get the kernel queue file information. 374 */ 375 (void) snpf(Lf->type, sizeof(Lf->type), "KQUEUE"); 376 nb = proc_pidfdinfo(pid, fd, PROC_PIDFDKQUEUEINFO, &kq, sizeof(kq)); 377 if (nb <= 0) { 378 (void) err2nm("kqueue"); 379 return; 380 } else if (nb < sizeof(kq)) { 381 (void) fprintf(stderr, 382 "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDKQUEUEINFO);\n", 383 Pn, pid, fd); 384 (void) fprintf(stderr, 385 " too few bytes; expected %ld, got %d\n", 386 sizeof(kq), nb); 387 Exit(1); 388 } 389/* 390 * Enter the kernel queue file information. 391 */ 392 enter_file_info(&kq.pfi); 393/* 394 * Enter queue counts as NAME column information. 395 */ 396 (void) snpf(Namech, Namechl, 397 "count=%" SZOFFPSPEC "u, state=%#x", 398 (SZOFFTYPE)kq.kqueueinfo.kq_stat.vst_size, 399 kq.kqueueinfo.kq_state); 400 enter_nm(Namech); 401} 402 403 404/* 405 * process_pipe() -- process pipe file 406 */ 407 408static void 409process_pipe_common(pi) 410 struct pipe_fdinfo *pi; 411{ 412 char dev_ch[32], *ep; 413 size_t sz; 414 415 (void) snpf(Lf->type, sizeof(Lf->type), "PIPE"); 416/* 417 * Enter the pipe handle as the device. 418 */ 419 (void) snpf(dev_ch, sizeof(dev_ch), "%s", 420 print_kptr((KA_T)pi->pipeinfo.pipe_handle, (char *)NULL, 0)); 421 enter_dev_ch(dev_ch); 422/* 423 * Enable offset or size reporting. 424 */ 425 if (Foffset) 426 Lf->off_def = 1; 427 else { 428 Lf->sz = (SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_blksize; 429 Lf->sz_def = 1; 430 } 431/* 432 * If there is a peer handle, enter it in as NAME column information. 433 */ 434 if (pi->pipeinfo.pipe_peerhandle) { 435 (void) snpf(Namech, Namechl, "->%s", 436 print_kptr((KA_T)pi->pipeinfo.pipe_peerhandle, (char *)NULL, 0)); 437 enter_nm(Namech); 438 } else 439 Namech[0] = '\0'; 440/* 441 * If the pipe has a count, add it to the NAME column. 442 */ 443 if (pi->pipeinfo.pipe_stat.vst_size) { 444 ep = endnm(&sz); 445 (void) snpf(ep, sz, ", cnt=%" SZOFFPSPEC "u", 446 (SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_size); 447 } 448} 449 450 451void 452process_pipe(pid, fd) 453 int pid; /* PID */ 454 int32_t fd; /* FD */ 455{ 456 int nb; 457 struct pipe_fdinfo pi; 458/* 459 * Get pipe file information. 460 */ 461 nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPIPEINFO, &pi, sizeof(pi)); 462 if (nb <= 0) { 463 (void) err2nm("pipe"); 464 return; 465 } else if (nb < sizeof(pi)) { 466 (void) fprintf(stderr, 467 "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPIPEINFO);\n", 468 Pn, pid, fd); 469 (void) fprintf(stderr, 470 " too few bytes; expected %ld, got %d\n", 471 sizeof(pi), nb); 472 Exit(1); 473 } 474 475 process_pipe_common(&pi); 476} 477 478 479#ifdef PROC_PIDLISTFILEPORTS 480void 481process_fileport_pipe(pid, fp) 482 int pid; /* PID */ 483 uint32_t fp; /* FILEPORT */ 484{ 485 int nb; 486 struct pipe_fdinfo pi; 487/* 488 * Get pipe file information. 489 */ 490 nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPIPEINFO, &pi, sizeof(pi)); 491 if (nb <= 0) { 492 (void) err2nm("pipe"); 493 return; 494 } else if (nb < sizeof(pi)) { 495 (void) fprintf(stderr, 496 "%s: PID %d, FILEPORT %u; proc_pidfileportinfo(PROC_PIDFILEPORTPIPEINFO);\n", 497 Pn, pid, fp); 498 (void) fprintf(stderr, 499 " too few bytes; expected %ld, got %d\n", 500 sizeof(pi), nb); 501 Exit(1); 502 } 503 504 process_pipe_common(&pi); 505} 506#endif /* PROC_PIDLISTFILEPORTS */ 507 508 509/* 510 * process_psem() -- process a POSIX semaphore file 511 */ 512 513void 514process_psem(pid, fd) 515 int pid; /* PID */ 516 int32_t fd; /* FD */ 517{ 518 int nb; 519 struct psem_fdinfo ps; 520/* 521 * Get the sempaphore file information. 522 */ 523 (void) snpf(Lf->type, sizeof(Lf->type), "PSXSEM"); 524 nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSEMINFO, &ps, sizeof(ps)); 525 if (nb <= 0) { 526 (void) err2nm("semaphore"); 527 return; 528 } else if (nb < sizeof(ps)) { 529 (void) fprintf(stderr, 530 "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSEMINFO);\n", 531 Pn, pid, fd); 532 (void) fprintf(stderr, 533 " too few bytes; expected %ld, got %d\n", 534 sizeof(ps), nb); 535 Exit(1); 536 } 537/* 538 * Enter the semaphore file information. 539 */ 540 enter_file_info(&ps.pfi); 541/* 542 * If there is a semaphore file name, enter it. 543 */ 544 if (ps.pseminfo.psem_name[0]) { 545 ps.pseminfo.psem_name[sizeof(ps.pseminfo.psem_name) - 1] = '\0'; 546 (void) snpf(Namech, Namechl, "%s", ps.pseminfo.psem_name); 547 enter_nm(Namech); 548 } 549/* 550 * Unless file size has been specifically requested, enable the printing of 551 * file offset. 552 */ 553 if (!Fsize) 554 Lf->off_def = 1; 555} 556 557 558/* 559 * process_pshm() -- process POSIX shared memory file 560 */ 561 562static void 563process_pshm_common(ps) 564 struct pshm_fdinfo *ps; 565{ 566 (void) snpf(Lf->type, sizeof(Lf->type), "PSXSHM"); 567/* 568 * Enter the POSIX shared memory file information. 569 */ 570 enter_file_info(&ps->pfi); 571/* 572 * If the POSIX shared memory file has a path name, enter it; otherwise, if it 573 * has a mapping address, enter that. 574 */ 575 if (ps->pshminfo.pshm_name[0]) { 576 ps->pshminfo.pshm_name[sizeof(ps->pshminfo.pshm_name) - 1] = '\0'; 577 (void) snpf(Namech, Namechl, "%s", ps->pshminfo.pshm_name); 578 enter_nm(Namech); 579 } else if (ps->pshminfo.pshm_mappaddr) { 580 (void) snpf(Namech, Namechl, "obj=%s", 581 print_kptr((KA_T)ps->pshminfo.pshm_mappaddr, (char *)NULL, 0)); 582 enter_nm(Namech); 583 } 584/* 585 * Enable offset or size reporting. 586 */ 587 if (Foffset) 588 Lf->off_def = 1; 589 else { 590 Lf->sz = (SZOFFTYPE)ps->pshminfo.pshm_stat.vst_size; 591 Lf->sz_def = 1; 592 } 593} 594 595 596void 597process_pshm(pid, fd) 598 int pid; /* PID */ 599 int32_t fd; /* FD */ 600{ 601 int nb; 602 struct pshm_fdinfo ps; 603/* 604 * Get the POSIX shared memory file information. 605 */ 606 nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSHMINFO, &ps, sizeof(ps)); 607 if (nb <= 0) { 608 (void) err2nm("POSIX shared memory"); 609 return; 610 } else if (nb < sizeof(ps)) { 611 (void) fprintf(stderr, 612 "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSHMINFO);\n", 613 Pn, pid, fd); 614 (void) fprintf(stderr, 615 " too few bytes; expected %ld, got %d\n", 616 sizeof(ps), nb); 617 Exit(1); 618 } 619 620 process_pshm_common(&ps); 621} 622 623 624#ifdef PROC_PIDLISTFILEPORTS 625void 626process_fileport_pshm(pid, fp) 627 int pid; /* PID */ 628 uint32_t fp; /* FILEPORT */ 629{ 630 int nb; 631 struct pshm_fdinfo ps; 632/* 633 * Get the POSIX shared memory file information. 634 */ 635 nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPSHMINFO, &ps, sizeof(ps)); 636 if (nb <= 0) { 637 (void) err2nm("POSIX shared memory"); 638 return; 639 } else if (nb < sizeof(ps)) { 640 (void) fprintf(stderr, 641 "%s: PID %d, FILEPORT %u; proc_pidfileportinfo(PROC_PIDFILEPORTPSHMINFO);\n", 642 Pn, pid, fp); 643 (void) fprintf(stderr, 644 " too few bytes; expected %ld, got %d\n", 645 sizeof(ps), nb); 646 Exit(1); 647 } 648 649 process_pshm_common(&ps); 650} 651#endif /* PROC_PIDLISTFILEPORTS */ 652 653 654/* 655 * process_vnode() -- process a vnode file 656 */ 657 658static void 659process_vnode_common(vi) 660 struct vnode_fdinfowithpath *vi; 661{ 662/* 663 * Enter the file and vnode information. 664 */ 665 enter_file_info(&vi->pfi); 666 enter_vnode_info(&vi->pvip); 667} 668 669 670void 671process_vnode(pid, fd) 672 int pid; /* PID */ 673 int32_t fd; /* FD */ 674{ 675 int nb; 676 struct vnode_fdinfowithpath vi; 677 678 nb = proc_pidfdinfo(pid, fd, PROC_PIDFDVNODEPATHINFO, &vi, sizeof(vi)); 679 if (nb <= 0) { 680 if (errno == ENOENT) { 681 682 /* 683 * The file descriptor's vnode may have been revoked. This is a 684 * bit of a hack, since an ENOENT error might not always mean the 685 * descriptor's vnode has been revoked. As the libproc API 686 * matures, this code may need to be revisited. 687 */ 688 enter_nm("(revoked)"); 689 } else 690 (void) err2nm("vnode"); 691 return; 692 } else if (nb < sizeof(vi)) { 693 (void) fprintf(stderr, 694 "%s: PID %d, FD %d: proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n", 695 Pn, pid, fd); 696 (void) fprintf(stderr, 697 " too few bytes; expected %ld, got %d\n", 698 sizeof(vi), nb); 699 Exit(1); 700 } 701 702 process_vnode_common(&vi); 703} 704 705 706#ifdef PROC_PIDLISTFILEPORTS 707void 708process_fileport_vnode(pid, fp) 709 int pid; /* PID */ 710 uint32_t fp; /* FILEPORT */ 711{ 712 int nb; 713 struct vnode_fdinfowithpath vi; 714 715 nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTVNODEPATHINFO, &vi, sizeof(vi)); 716 if (nb <= 0) { 717 if (errno == ENOENT) { 718 719 /* 720 * The file descriptor's vnode may have been revoked. This is a 721 * bit of a hack, since an ENOENT error might not always mean the 722 * descriptor's vnode has been revoked. As the libproc API 723 * matures, this code may need to be revisited. 724 */ 725 enter_nm("(revoked)"); 726 } else 727 (void) err2nm("vnode"); 728 return; 729 } else if (nb < sizeof(vi)) { 730 (void) fprintf(stderr, 731 "%s: PID %d, FILEPORT %u: proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n", 732 Pn, pid, fp); 733 (void) fprintf(stderr, 734 " too few bytes; expected %ld, got %d\n", 735 sizeof(vi), nb); 736 Exit(1); 737 } 738 739 process_vnode_common(&vi); 740} 741#endif /* PROC_PIDLISTFILEPORTS */ 742