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