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