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