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