1 /* $OpenBSD: fstat.c,v 1.74 2013/03/24 15:09:13 deraadt 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) 1988, 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 #include <sys/param.h> 49 #include <sys/queue.h> 50 #include <sys/mount.h> 51 #include <sys/stat.h> 52 #include <sys/vnode.h> 53 #include <sys/socket.h> 54 #include <sys/socketvar.h> 55 #include <sys/eventvar.h> 56 #include <sys/sysctl.h> 57 #define _KERNEL /* for DTYPE_* */ 58 #include <sys/file.h> 59 #undef _KERNEL 60 61 #include <net/route.h> 62 #include <netinet/in.h> 63 64 #include <netdb.h> 65 #include <arpa/inet.h> 66 67 #include <sys/pipe.h> 68 69 #include <ctype.h> 70 #include <errno.h> 71 #include <fcntl.h> 72 #include <kvm.h> 73 #include <limits.h> 74 #include <nlist.h> 75 #include <pwd.h> 76 #include <search.h> 77 #include <signal.h> 78 #include <stdio.h> 79 #include <stdint.h> 80 #include <stdlib.h> 81 #include <string.h> 82 #include <unistd.h> 83 #include <err.h> 84 85 #include "fstat.h" 86 87 struct fileargs fileargs = SLIST_HEAD_INITIALIZER(fileargs); 88 89 int fsflg; /* show files on same filesystem as file(s) argument */ 90 int pflg; /* show files open by a particular pid */ 91 int uflg; /* show files open by a particular (effective) user */ 92 int checkfile; /* true if restricting to particular files or filesystems */ 93 int nflg; /* (numerical) display f.s. and rdev as dev_t */ 94 int oflg; /* display file offset */ 95 int sflg; /* display file xfer/bytes counters */ 96 int vflg; /* display errors in locating kernel data objects etc... */ 97 int cflg; /* fuser only */ 98 99 int fuser; /* 1 if we are fuser, 0 if we are fstat */ 100 int signo; /* signal to send (fuser only) */ 101 102 kvm_t *kd; 103 uid_t uid; 104 105 void fstat_dofile(struct kinfo_file2 *); 106 void fstat_header(void); 107 void getinetproto(int); 108 void usage(void); 109 int getfname(char *); 110 void cryptotrans(struct kinfo_file2 *); 111 void kqueuetrans(struct kinfo_file2 *); 112 void pipetrans(struct kinfo_file2 *); 113 struct kinfo_file2 *splice_find(char, u_int64_t); 114 void splice_insert(char, u_int64_t, struct kinfo_file2 *); 115 void find_splices(struct kinfo_file2 *, int); 116 void print_inet_details(struct kinfo_file2 *); 117 #ifdef INET6 118 void print_inet6_details(struct kinfo_file2 *); 119 #endif 120 void print_sock_details(struct kinfo_file2 *); 121 void socktrans(struct kinfo_file2 *); 122 void systracetrans(struct kinfo_file2 *); 123 void vtrans(struct kinfo_file2 *); 124 const char *inet6_addrstr(struct in6_addr *); 125 int signame_to_signum(char *); 126 void hide(void *p); 127 128 int hideroot; 129 130 void 131 hide(void *p) 132 { 133 printf("%p", hideroot ? NULL : p); 134 } 135 136 int 137 main(int argc, char *argv[]) 138 { 139 struct passwd *passwd; 140 struct kinfo_file2 *kf, *kflast; 141 int arg, ch, what; 142 char *memf, *nlistf, *optstr; 143 char buf[_POSIX2_LINE_MAX]; 144 const char *errstr; 145 int cnt, flags; 146 147 hideroot = getuid(); 148 149 arg = -1; 150 what = KERN_FILE_BYPID; 151 nlistf = memf = NULL; 152 oflg = 0; 153 154 /* are we fstat(1) or fuser(1)? */ 155 if (strcmp(__progname, "fuser") == 0) { 156 fuser = 1; 157 optstr = "cfks:uM:N:"; 158 } else { 159 fuser = 0; 160 optstr = "fnop:su:vN:M:"; 161 } 162 163 /* 164 * fuser and fstat share three flags: -f, -s and -u. In both cases 165 * -f is a boolean, but for -u fstat wants an argument while fuser 166 * does not and for -s fuser wants an argument whereas fstat does not. 167 */ 168 while ((ch = getopt(argc, argv, optstr)) != -1) 169 switch ((char)ch) { 170 case 'c': 171 if (fsflg) 172 usage(); 173 cflg = 1; 174 break; 175 case 'f': 176 if (cflg) 177 usage(); 178 fsflg = 1; 179 break; 180 case 'k': 181 sflg = 1; 182 signo = SIGKILL; 183 break; 184 case 'M': 185 memf = optarg; 186 break; 187 case 'N': 188 nlistf = optarg; 189 break; 190 case 'n': 191 nflg = 1; 192 break; 193 case 'o': 194 oflg = 1; 195 break; 196 case 'p': 197 if (pflg++) 198 usage(); 199 arg = strtonum(optarg, 0, INT_MAX, &errstr); 200 if (errstr != NULL) { 201 warnx("-p requires a process id, %s: %s", 202 errstr, optarg); 203 usage(); 204 } 205 what = KERN_FILE_BYPID; 206 break; 207 case 's': 208 sflg = 1; 209 if (fuser) { 210 signo = signame_to_signum(optarg); 211 if (signo == -1) { 212 warnx("invalid signal %s", optarg); 213 usage(); 214 } 215 } 216 break; 217 case 'u': 218 if (uflg++) 219 usage(); 220 if (!fuser) { 221 if (!(passwd = getpwnam(optarg))) { 222 arg = strtonum(optarg, 0, UID_MAX, 223 &errstr); 224 if (errstr != NULL) { 225 errx(1, "%s: unknown uid", 226 optarg); 227 } 228 } else 229 arg = passwd->pw_uid; 230 what = KERN_FILE_BYUID; 231 } 232 break; 233 case 'v': 234 vflg = 1; 235 break; 236 default: 237 usage(); 238 } 239 240 /* 241 * get the uid, for oflg and sflg 242 */ 243 uid = getuid(); 244 245 /* 246 * Use sysctl unless inspecting an alternate kernel. 247 */ 248 if (nlistf == NULL || memf == NULL) 249 flags = KVM_NO_FILES; 250 else 251 flags = O_RDONLY; 252 253 if ((kd = kvm_openfiles(nlistf, memf, NULL, flags, buf)) == NULL) 254 errx(1, "%s", buf); 255 256 if (*(argv += optind)) { 257 for (; *argv; ++argv) { 258 if (getfname(*argv)) 259 checkfile = 1; 260 } 261 /* file(s) specified, but none accessible */ 262 if (!checkfile) 263 exit(1); 264 } else if (fuser) 265 usage(); 266 267 if (!fuser && fsflg && !checkfile) { 268 /* fstat -f with no files means use wd */ 269 if (getfname(".") == 0) 270 exit(1); 271 checkfile = 1; 272 } 273 274 if ((kf = kvm_getfile2(kd, what, arg, sizeof(*kf), &cnt)) == NULL) 275 errx(1, "%s", kvm_geterr(kd)); 276 277 find_splices(kf, cnt); 278 if (!fuser) 279 fstat_header(); 280 for (kflast = &kf[cnt]; kf < kflast; ++kf) { 281 if (fuser) 282 fuser_check(kf); 283 else 284 fstat_dofile(kf); 285 } 286 if (fuser) 287 fuser_run(); 288 289 exit(0); 290 } 291 292 void 293 fstat_header(void) 294 { 295 if (nflg) 296 printf("%s", 297 "USER CMD PID FD DEV INUM MODE R/W SZ|DV"); 298 else 299 printf("%s", 300 "USER CMD PID FD MOUNT INUM MODE R/W SZ|DV"); 301 if (oflg) 302 printf("%s", ":OFFSET "); 303 if (checkfile && fsflg == 0) 304 printf(" NAME"); 305 if (sflg) 306 printf(" XFERS KBYTES"); 307 putchar('\n'); 308 } 309 310 char *Uname, *Comm; 311 uid_t *procuid; 312 pid_t Pid; 313 314 #define PREFIX(i) do { \ 315 printf("%-8.8s %-10s %5ld", Uname, Comm, (long)Pid); \ 316 switch (i) { \ 317 case KERN_FILE_TEXT: \ 318 printf(" text"); \ 319 break; \ 320 case KERN_FILE_CDIR: \ 321 printf(" wd"); \ 322 break; \ 323 case KERN_FILE_RDIR: \ 324 printf(" root"); \ 325 break; \ 326 case KERN_FILE_TRACE: \ 327 printf(" tr"); \ 328 break; \ 329 default: \ 330 printf(" %4d", i); \ 331 break; \ 332 } \ 333 } while (0) 334 335 /* 336 * print open files attributed to this process 337 */ 338 void 339 fstat_dofile(struct kinfo_file2 *kf) 340 { 341 342 Uname = user_from_uid(kf->p_uid, 0); 343 procuid = &kf->p_uid; 344 Pid = kf->p_pid; 345 Comm = kf->p_comm; 346 347 switch (kf->f_type) { 348 case DTYPE_VNODE: 349 vtrans(kf); 350 break; 351 case DTYPE_SOCKET: 352 if (checkfile == 0) 353 socktrans(kf); 354 break; 355 case DTYPE_PIPE: 356 if (checkfile == 0) 357 pipetrans(kf); 358 break; 359 case DTYPE_KQUEUE: 360 if (checkfile == 0) 361 kqueuetrans(kf); 362 break; 363 case DTYPE_CRYPTO: 364 if (checkfile == 0) 365 cryptotrans(kf); 366 break; 367 case DTYPE_SYSTRACE: 368 if (checkfile == 0) 369 systracetrans(kf); 370 break; 371 default: 372 if (vflg) { 373 warnx("unknown file type %d for file %d of pid %ld", 374 kf->f_type, kf->fd_fd, (long)Pid); 375 } 376 break; 377 } 378 } 379 380 void 381 vtrans(struct kinfo_file2 *kf) 382 { 383 const char *badtype = NULL; 384 char rw[3], mode[12]; 385 char *filename = NULL; 386 387 if (kf->v_type == VNON) 388 badtype = "none"; 389 else if (kf->v_type == VBAD) 390 badtype = "bad"; 391 else if (kf->v_tag == VT_NON && !(kf->v_flag & VCLONE)) 392 badtype = "none"; /* not a clone */ 393 394 if (checkfile) { 395 int fsmatch = 0; 396 struct filearg *fa; 397 398 if (badtype) 399 return; 400 SLIST_FOREACH(fa, &fileargs, next) { 401 if (fa->dev == kf->va_fsid) { 402 fsmatch = 1; 403 if (fa->ino == kf->va_fileid) { 404 filename = fa->name; 405 break; 406 } 407 } 408 } 409 if (fsmatch == 0 || (filename == NULL && fsflg == 0)) 410 return; 411 } 412 PREFIX(kf->fd_fd); 413 if (badtype) { 414 (void)printf(" - - %10s -\n", badtype); 415 return; 416 } 417 418 if (nflg) 419 (void)printf(" %2ld,%-2ld", (long)major(kf->va_fsid), 420 (long)minor(kf->va_fsid)); 421 else if (!(kf->v_flag & VCLONE)) 422 (void)printf(" %-8s", kf->f_mntonname); 423 else 424 (void)printf(" clone "); 425 if (nflg) 426 (void)snprintf(mode, sizeof(mode), "%o", kf->va_mode); 427 else 428 strmode(kf->va_mode, mode); 429 printf(" %8llu %11s", kf->va_fileid, mode); 430 rw[0] = '\0'; 431 if (kf->f_flag & FREAD) 432 strlcat(rw, "r", sizeof rw); 433 if (kf->f_flag & FWRITE) 434 strlcat(rw, "w", sizeof rw); 435 printf(" %2s", rw); 436 switch (kf->v_type) { 437 case VBLK: 438 case VCHR: { 439 char *name; 440 441 if (nflg || ((name = devname(kf->va_rdev, 442 kf->v_type == VCHR ? S_IFCHR : S_IFBLK)) == NULL)) 443 printf(" %2d,%-3d", major(kf->va_rdev), minor(kf->va_rdev)); 444 else 445 printf(" %7s", name); 446 if (oflg) 447 printf(" "); 448 break; 449 } 450 default: 451 printf(" %8llu", kf->va_size); 452 if (oflg) { 453 if (uid == 0 || uid == *procuid) 454 printf(":%-8llu", kf->f_offset); 455 else 456 printf(":%-8s", "*"); 457 } 458 } 459 if (sflg) { 460 if (uid == 0 || uid == *procuid) { 461 printf(" %8llu %8llu", 462 (kf->f_rxfer + kf->f_rwfer), 463 (kf->f_rbytes + kf->f_wbytes) / 1024); 464 } else { 465 printf(" %8s %8s", "*", "*"); 466 } 467 } 468 if (filename && !fsflg) 469 printf(" %s", filename); 470 putchar('\n'); 471 } 472 473 void 474 pipetrans(struct kinfo_file2 *kf) 475 { 476 void *maxaddr; 477 478 PREFIX(kf->fd_fd); 479 480 printf(" "); 481 482 /* 483 * We don't have enough space to fit both peer and own address, so 484 * we select the higher address so both ends of the pipe have the 485 * same visible addr. (it's the higher address because when the other 486 * end closes, it becomes 0) 487 */ 488 maxaddr = (void *)(uintptr_t)MAX(kf->f_data, kf->pipe_peer); 489 490 printf("pipe "); 491 hide(maxaddr); 492 printf("state: %s%s%s", 493 (kf->pipe_state & PIPE_WANTR) ? "R" : "", 494 (kf->pipe_state & PIPE_WANTW) ? "W" : "", 495 (kf->pipe_state & PIPE_EOF) ? "E" : ""); 496 if (sflg) 497 printf("\t%8llu %8llu", 498 (kf->f_rxfer + kf->f_rwfer), 499 (kf->f_rbytes + kf->f_wbytes) / 1024); 500 printf("\n"); 501 return; 502 } 503 504 void 505 kqueuetrans(struct kinfo_file2 *kf) 506 { 507 PREFIX(kf->fd_fd); 508 509 printf(" "); 510 511 printf("kqueue "); 512 hide((void *)(uintptr_t)kf->f_data); 513 printf(" %d state: %s%s\n", 514 kf->kq_count, 515 (kf->kq_state & KQ_SEL) ? "S" : "", 516 (kf->kq_state & KQ_SLEEP) ? "W" : ""); 517 return; 518 } 519 520 void 521 cryptotrans(struct kinfo_file2 *kf) 522 { 523 PREFIX(kf->fd_fd); 524 525 printf(" "); 526 527 printf("crypto "); 528 hide((void *)(uintptr_t)kf->f_data); 529 printf("\n"); 530 } 531 532 void 533 systracetrans(struct kinfo_file2 *kf) 534 { 535 PREFIX(kf->fd_fd); 536 537 printf(" "); 538 539 printf("systrace "); 540 hide((void *)(uintptr_t)kf->f_data); 541 printf(" npol %d\n", kf->str_npolicies); 542 return; 543 } 544 545 #ifdef INET6 546 const char * 547 inet6_addrstr(struct in6_addr *p) 548 { 549 struct sockaddr_in6 sin6; 550 static char hbuf[NI_MAXHOST]; 551 const int niflags = NI_NUMERICHOST; 552 553 memset(&sin6, 0, sizeof(sin6)); 554 sin6.sin6_family = AF_INET6; 555 sin6.sin6_len = sizeof(struct sockaddr_in6); 556 sin6.sin6_addr = *p; 557 if (IN6_IS_ADDR_LINKLOCAL(p) && 558 *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) { 559 sin6.sin6_scope_id = 560 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); 561 sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0; 562 } 563 564 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 565 hbuf, sizeof(hbuf), NULL, 0, niflags)) 566 return "invalid"; 567 568 return hbuf; 569 } 570 #endif 571 572 void 573 splice_insert(char type, u_int64_t ptr, struct kinfo_file2 *data) 574 { 575 ENTRY entry, *found; 576 577 if (asprintf(&entry.key, "%c%llx", type, hideroot ? 0 : ptr) == -1) 578 err(1, NULL); 579 entry.data = data; 580 if ((found = hsearch(entry, ENTER)) == NULL) 581 err(1, "hsearch"); 582 /* if it's ambiguous, set the data to NULL */ 583 if (found->data != data) 584 found->data = NULL; 585 } 586 587 struct kinfo_file2 * 588 splice_find(char type, u_int64_t ptr) 589 { 590 ENTRY entry, *found; 591 char buf[20]; 592 593 snprintf(buf, sizeof(buf), "%c%llx", type, hideroot ? 0 : ptr); 594 entry.key = buf; 595 found = hsearch(entry, FIND); 596 return (found != NULL ? found->data : NULL); 597 } 598 599 void 600 find_splices(struct kinfo_file2 *kf, int cnt) 601 { 602 int i, created; 603 604 created = 0; 605 for (i = 0; i < cnt; i++) { 606 if (kf[i].f_type != DTYPE_SOCKET || 607 (kf[i].so_splice == 0 && kf[i].so_splicelen != -1)) 608 continue; 609 if (created++ == 0) { 610 if (hcreate(1000) == 0) 611 err(1, "hcreate"); 612 } 613 splice_insert('>', kf[i].f_data, &kf[i]); 614 if (kf[i].so_splice != 0) 615 splice_insert('<', kf[i].so_splice, &kf[i]); 616 } 617 } 618 619 void 620 print_inet_details(struct kinfo_file2 *kf) 621 { 622 struct in_addr laddr, faddr; 623 624 memcpy(&laddr, kf->inp_laddru, sizeof(laddr)); 625 memcpy(&faddr, kf->inp_faddru, sizeof(faddr)); 626 if (kf->so_protocol == IPPROTO_TCP) { 627 printf(" "); 628 hide((void *)(uintptr_t)kf->inp_ppcb); 629 printf(" %s:%d", laddr.s_addr == INADDR_ANY ? "*" : 630 inet_ntoa(laddr), ntohs(kf->inp_lport)); 631 if (kf->inp_fport) { 632 if (kf->so_state & SS_CONNECTOUT) 633 printf(" --> "); 634 else 635 printf(" <-- "); 636 printf("%s:%d", 637 faddr.s_addr == INADDR_ANY ? "*" : 638 inet_ntoa(faddr), ntohs(kf->inp_fport)); 639 } 640 } else if (kf->so_protocol == IPPROTO_UDP) { 641 printf(" %s:%d", laddr.s_addr == INADDR_ANY ? "*" : 642 inet_ntoa(laddr), ntohs(kf->inp_lport)); 643 if (kf->inp_fport) { 644 printf(" <-> %s:%d", 645 faddr.s_addr == INADDR_ANY ? "*" : 646 inet_ntoa(faddr), ntohs(kf->inp_fport)); 647 } 648 } else if (kf->so_pcb) { 649 printf(" "); 650 hide((void *)(uintptr_t)kf->so_pcb); 651 } 652 } 653 654 #ifdef INET6 655 void 656 print_inet6_details(struct kinfo_file2 *kf) 657 { 658 char xaddrbuf[NI_MAXHOST + 2]; 659 struct in6_addr laddr6, faddr6; 660 661 memcpy(&laddr6, kf->inp_laddru, sizeof(laddr6)); 662 memcpy(&faddr6, kf->inp_faddru, sizeof(faddr6)); 663 if (kf->so_protocol == IPPROTO_TCP) { 664 printf(" "); 665 hide((void *)(uintptr_t)kf->inp_ppcb); 666 snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]", 667 inet6_addrstr(&laddr6)); 668 printf(" %s:%d", 669 IN6_IS_ADDR_UNSPECIFIED(&laddr6) ? "*" : 670 xaddrbuf, ntohs(kf->inp_lport)); 671 if (kf->inp_fport) { 672 if (kf->so_state & SS_CONNECTOUT) 673 printf(" --> "); 674 else 675 printf(" <-- "); 676 snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]", 677 inet6_addrstr(&faddr6)); 678 printf("%s:%d", 679 IN6_IS_ADDR_UNSPECIFIED(&faddr6) ? "*" : 680 xaddrbuf, ntohs(kf->inp_fport)); 681 } 682 } else if (kf->so_protocol == IPPROTO_UDP) { 683 snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]", 684 inet6_addrstr(&laddr6)); 685 printf(" %s:%d", 686 IN6_IS_ADDR_UNSPECIFIED(&laddr6) ? "*" : 687 xaddrbuf, ntohs(kf->inp_lport)); 688 if (kf->inp_fport) { 689 snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]", 690 inet6_addrstr(&faddr6)); 691 printf(" <-> %s:%d", 692 IN6_IS_ADDR_UNSPECIFIED(&faddr6) ? "*" : 693 xaddrbuf, ntohs(kf->inp_fport)); 694 } 695 } else if (kf->so_pcb) { 696 printf(" "); 697 hide((void *)(uintptr_t)kf->so_pcb); 698 } 699 } 700 #endif 701 702 void 703 print_sock_details(struct kinfo_file2 *kf) 704 { 705 if (kf->so_family == AF_INET) 706 print_inet_details(kf); 707 #ifdef INET6 708 else if (kf->so_family == AF_INET6) 709 print_inet6_details(kf); 710 #endif 711 } 712 713 void 714 socktrans(struct kinfo_file2 *kf) 715 { 716 static char *stypename[] = { 717 "unused", /* 0 */ 718 "stream", /* 1 */ 719 "dgram", /* 2 */ 720 "raw", /* 3 */ 721 "rdm", /* 4 */ 722 "seqpak" /* 5 */ 723 }; 724 #define STYPEMAX 5 725 char *stype, stypebuf[24]; 726 727 PREFIX(kf->fd_fd); 728 729 if (kf->so_type > STYPEMAX) { 730 snprintf(stypebuf, sizeof(stypebuf), "?%d", kf->so_type); 731 stype = stypebuf; 732 } else { 733 stype = stypename[kf->so_type]; 734 } 735 736 /* 737 * protocol specific formatting 738 * 739 * Try to find interesting things to print. For tcp, the interesting 740 * thing is the address of the tcpcb, for udp and others, just the 741 * inpcb (socket pcb). For unix domain, its the address of the socket 742 * pcb and the address of the connected pcb (if connected). Otherwise 743 * just print the protocol number and address of the socket itself. 744 * The idea is not to duplicate netstat, but to make available enough 745 * information for further analysis. 746 */ 747 switch (kf->so_family) { 748 case AF_INET: 749 printf("* internet %s", stype); 750 getinetproto(kf->so_protocol); 751 print_inet_details(kf); 752 break; 753 #ifdef INET6 754 case AF_INET6: 755 printf("* internet6 %s", stype); 756 getinetproto(kf->so_protocol); 757 print_inet6_details(kf); 758 break; 759 #endif 760 case AF_UNIX: 761 /* print address of pcb and connected pcb */ 762 printf("* unix %s", stype); 763 if (kf->so_pcb) { 764 printf(" "); 765 hide((void *)(uintptr_t)kf->so_pcb); 766 if (kf->unp_conn) { 767 char shoconn[4], *cp; 768 769 cp = shoconn; 770 if (!(kf->so_state & SS_CANTRCVMORE)) 771 *cp++ = '<'; 772 *cp++ = '-'; 773 if (!(kf->so_state & SS_CANTSENDMORE)) 774 *cp++ = '>'; 775 *cp = '\0'; 776 printf(" %s ", shoconn); 777 hide((void *)(uintptr_t)kf->unp_conn); 778 } 779 } 780 break; 781 case AF_MPLS: 782 /* print protocol number and socket address */ 783 printf("* mpls %s", stype); 784 printf(" %d ", kf->so_protocol); 785 hide((void *)(uintptr_t)kf->f_data); 786 break; 787 case AF_ROUTE: 788 /* print protocol number and socket address */ 789 printf("* route %s", stype); 790 printf(" %d ", kf->so_protocol); 791 hide((void *)(uintptr_t)kf->f_data); 792 break; 793 case AF_BLUETOOTH: 794 /* print protocol number and socket address */ 795 printf("* bluetooth %s", stype); 796 printf(" %d ", kf->so_protocol); 797 hide((void *)(uintptr_t)kf->f_data); 798 break; 799 case AF_NATM: 800 /* print protocol number and socket address */ 801 printf("* natm %s", stype); 802 printf(" %d ", kf->so_protocol); 803 hide((void *)(uintptr_t)kf->f_data); 804 break; 805 default: 806 /* print protocol number and socket address */ 807 printf("* %d %s", kf->so_family, stype); 808 printf(" %d ", kf->so_protocol); 809 hide((void *)(uintptr_t)kf->f_data); 810 } 811 if (kf->so_splice != 0 || kf->so_splicelen == -1) { 812 struct kinfo_file2 *from, *to; 813 814 from = splice_find('<', kf->f_data); 815 to = NULL; 816 if (kf->so_splice != 0) 817 to = splice_find('>', kf->so_splice); 818 819 if (to != NULL && from == to) { 820 printf(" <==>"); 821 print_sock_details(to); 822 } else if (kf->so_splice != 0) { 823 printf(" ==>"); 824 if (to != NULL) 825 print_sock_details(to); 826 } else if (kf->so_splicelen == -1) { 827 printf(" <=="); 828 if (from != NULL) 829 print_sock_details(from); 830 } 831 } 832 if (sflg) 833 printf("\t%8llu %8llu", 834 (kf->f_rxfer + kf->f_rwfer), 835 (kf->f_rbytes + kf->f_wbytes) / 1024); 836 printf("\n"); 837 } 838 839 /* 840 * getinetproto -- 841 * print name of protocol number 842 */ 843 void 844 getinetproto(number) 845 int number; 846 { 847 static int isopen; 848 struct protoent *pe; 849 850 if (!isopen) 851 setprotoent(++isopen); 852 if ((pe = getprotobynumber(number)) != NULL) 853 printf(" %s", pe->p_name); 854 else 855 printf(" %d", number); 856 } 857 858 int 859 getfname(char *filename) 860 { 861 static struct statfs *mntbuf; 862 static int nmounts; 863 int i; 864 struct stat sb; 865 struct filearg *cur; 866 867 if (stat(filename, &sb)) { 868 warn("%s", filename); 869 return (0); 870 } 871 872 /* 873 * POSIX specifies "For block special devices, all processes using any 874 * file on that device are listed". However the -f flag description 875 * states "The report shall be only for the named files", so we only 876 * look up a block device if the -f flag has not be specified. 877 */ 878 if (fuser && !fsflg && S_ISBLK(sb.st_mode)) { 879 if (mntbuf == NULL) { 880 nmounts = getmntinfo(&mntbuf, MNT_NOWAIT); 881 if (nmounts == -1) 882 err(1, "getmntinfo"); 883 } 884 for (i = 0; i < nmounts; i++) { 885 if (!strcmp(mntbuf[i].f_mntfromname, filename)) { 886 if (stat(mntbuf[i].f_mntonname, &sb) == -1) { 887 warn("%s", filename); 888 return (0); 889 } 890 cflg = 1; 891 break; 892 } 893 } 894 } 895 896 if ((cur = malloc(sizeof(*cur))) == NULL) 897 err(1, NULL); 898 899 cur->ino = sb.st_ino; 900 cur->dev = sb.st_dev & 0xffff; 901 cur->name = filename; 902 TAILQ_INIT(&cur->fusers); 903 SLIST_INSERT_HEAD(&fileargs, cur, next); 904 return (1); 905 } 906 907 int 908 signame_to_signum(char *sig) 909 { 910 int n; 911 const char *errstr = NULL; 912 913 if (isdigit((unsigned char)*sig)) { 914 n = strtonum(sig, 0, NSIG - 1, &errstr); 915 return (errstr ? -1 : n); 916 } 917 if (!strncasecmp(sig, "sig", 3)) 918 sig += 3; 919 for (n = 1; n < NSIG; n++) { 920 if (!strcasecmp(sys_signame[n], sig)) 921 return (n); 922 } 923 return (-1); 924 } 925 926 void 927 usage(void) 928 { 929 if (fuser) { 930 fprintf(stderr, "usage: fuser [-cfku] [-M core] " 931 "[-N system] [-s signal] file ...\n"); 932 } else { 933 fprintf(stderr, "usage: fstat [-fnosv] [-M core] [-N system] " 934 "[-p pid] [-u user] [file ...]\n"); 935 } 936 exit(1); 937 } 938