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