1 /* $NetBSD: fstat.c,v 1.120 2023/11/02 10:31:55 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993\ 35 The Regents of the University of California. All rights reserved."); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)fstat.c 8.3 (Berkeley) 5/2/95"; 41 #else 42 __RCSID("$NetBSD: fstat.c,v 1.120 2023/11/02 10:31:55 martin Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 #include <sys/types.h> 47 #include <sys/param.h> 48 #include <sys/time.h> 49 #include <sys/proc.h> 50 #include <sys/stat.h> 51 #include <sys/vnode.h> 52 #include <sys/socket.h> 53 #include <sys/socketvar.h> 54 #include <sys/domain.h> 55 #include <sys/protosw.h> 56 #include <sys/unpcb.h> 57 #include <sys/sysctl.h> 58 #include <sys/filedesc.h> 59 #include <sys/pipe.h> 60 #define _KERNEL 61 #include <sys/mount.h> 62 #undef _KERNEL 63 #define _KERNEL 64 #include <sys/file.h> 65 #include <ufs/ufs/inode.h> 66 #include <ufs/ufs/ufsmount.h> 67 #undef _KERNEL 68 #define NFS 69 #include <nfs/nfsproto.h> 70 #include <nfs/rpcv2.h> 71 #include <nfs/nfs.h> 72 #include <nfs/nfsnode.h> 73 #undef NFS 74 #include <msdosfs/denode.h> 75 #include <msdosfs/bpb.h> 76 #define _KERNEL 77 #include <msdosfs/msdosfsmount.h> 78 #undef _KERNEL 79 #define _KERNEL 80 #include <miscfs/genfs/layer.h> 81 #undef _KERNEL 82 83 #include <net/route.h> 84 #include <netinet/in.h> 85 #include <netinet/in_systm.h> 86 #include <netinet/ip.h> 87 #include <netinet/in_pcb.h> 88 89 #ifdef INET6 90 #include <netinet/ip6.h> 91 #include <netinet6/in6.h> 92 #include <netinet6/ip6_var.h> 93 #include <netinet6/in6_pcb.h> 94 #endif 95 96 #include <netatalk/at.h> 97 #include <netatalk/ddp_var.h> 98 99 #include <netdb.h> 100 #include <arpa/inet.h> 101 102 #include <ctype.h> 103 #include <errno.h> 104 #include <kvm.h> 105 #include <limits.h> 106 #include <nlist.h> 107 #include <paths.h> 108 #include <pwd.h> 109 #include <stdio.h> 110 #include <stdlib.h> 111 #include <string.h> 112 #include <unistd.h> 113 #include <err.h> 114 #include <util.h> 115 116 #include "fstat.h" 117 118 #define TEXT -1 119 #define CDIR -2 120 #define RDIR -3 121 #define TRACE -4 122 123 typedef struct devs { 124 struct devs *next; 125 long fsid; 126 ino_t ino; 127 const char *name; 128 } DEVS; 129 static DEVS *devs; 130 131 static int fsflg, /* show files on same filesystem as file(s) argument */ 132 pflg, /* show files open by a particular pid */ 133 uflg; /* show files open by a particular (effective) user */ 134 static int checkfile; /* true if restricting to particular files or filesystems */ 135 static int nflg; /* (numerical) display f.s. and rdev as dev_t */ 136 static int Aflg; /* prefix with address of file structure */ 137 static int Oflg; /* print offset instead of size */ 138 int vflg; /* display errors in locating kernel data objects etc... */ 139 140 static fdfile_t **ofiles; /* buffer of pointers to file structures */ 141 static int fstat_maxfiles; 142 #define ALLOC_OFILES(d) \ 143 if ((d) > fstat_maxfiles) { \ 144 size_t len = (d) * sizeof(fdfile_t *); \ 145 free(ofiles); \ 146 ofiles = malloc(len); \ 147 if (ofiles == NULL) { \ 148 err(1, "malloc(%zu)", len); \ 149 } \ 150 fstat_maxfiles = (d); \ 151 } 152 153 kvm_t *kd; 154 155 static const char *const dtypes[] = { 156 DTYPE_NAMES 157 }; 158 159 static void dofiles(struct kinfo_proc2 *); 160 static int ext2fs_filestat(struct vnode *, struct filestat *); 161 static int getfname(const char *); 162 static void getinetproto(char *, size_t, int); 163 static void getatproto(char *, size_t, int); 164 static char *getmnton(struct mount *); 165 static const char *layer_filestat(struct vnode *, struct filestat *); 166 static int msdosfs_filestat(struct vnode *, struct filestat *); 167 static int nfs_filestat(struct vnode *, struct filestat *); 168 static const char *inet_addrstr(char *, size_t, const struct in_addr *, 169 uint16_t, bool); 170 #ifdef INET6 171 static const char *inet6_addrstr(char *, size_t, const struct in6_addr *, 172 uint16_t, bool); 173 #endif 174 static const char *at_addrstr(char *, size_t, const struct sockaddr_at *); 175 static void socktrans(struct file *, struct socket *, int); 176 static void misctrans(struct file *, int); 177 static int ufs_filestat(struct vnode *, struct filestat *); 178 static void usage(void) __dead; 179 static const char *vfilestat(struct vnode *, struct filestat *); 180 static void vtrans(struct file *, struct vnode *, int, int, long); 181 static void ftrans(fdfile_t *, int); 182 static void ptrans(struct file *, struct pipe *, int); 183 static void kdriver_init(void); 184 static void check_privs(void); 185 186 int 187 main(int argc, char **argv) 188 { 189 struct passwd *passwd; 190 struct kinfo_proc2 *p, *plast; 191 int arg, ch, what; 192 char *memf, *nlistf; 193 char buf[_POSIX2_LINE_MAX]; 194 int cnt; 195 gid_t egid = getegid(); 196 197 (void)setegid(getgid()); 198 arg = 0; 199 what = KERN_PROC_ALL; 200 nlistf = memf = NULL; 201 while ((ch = getopt(argc, argv, "fnAOp:u:vN:M:")) != -1) 202 switch((char)ch) { 203 case 'f': 204 fsflg = 1; 205 break; 206 case 'M': 207 memf = optarg; 208 break; 209 case 'N': 210 nlistf = optarg; 211 break; 212 case 'n': 213 nflg = 1; 214 break; 215 case 'A': 216 Aflg = 1; 217 break; 218 case 'O': 219 Oflg = 1; 220 break; 221 case 'p': 222 if (pflg++) 223 usage(); 224 if (!isdigit((unsigned char)*optarg)) { 225 warnx("-p requires a process id"); 226 usage(); 227 } 228 what = KERN_PROC_PID; 229 arg = atoi(optarg); 230 break; 231 case 'u': 232 if (uflg++) 233 usage(); 234 if (!(passwd = getpwnam(optarg))) { 235 errx(1, "%s: unknown uid", optarg); 236 } 237 what = KERN_PROC_UID; 238 arg = passwd->pw_uid; 239 break; 240 case 'v': 241 vflg = 1; 242 break; 243 case '?': 244 default: 245 usage(); 246 } 247 248 check_privs(); 249 250 kdriver_init(); 251 252 if (*(argv += optind)) { 253 for (; *argv; ++argv) { 254 if (getfname(*argv)) 255 checkfile = 1; 256 } 257 if (!checkfile) /* file(s) specified, but none accessible */ 258 exit(1); 259 } 260 261 ALLOC_OFILES(256); /* reserve space for file pointers */ 262 263 if (fsflg && !checkfile) { 264 /* -f with no files means use wd */ 265 if (getfname(".") == 0) 266 exit(1); 267 checkfile = 1; 268 } 269 270 /* 271 * Discard setgid privileges. If not the running kernel, we toss 272 * them away totally so that bad guys can't print interesting stuff 273 * from kernel memory, otherwise switch back to kmem for the 274 * duration of the kvm_openfiles() call. 275 */ 276 if (nlistf != NULL || memf != NULL) 277 (void)setgid(getgid()); 278 else 279 (void)setegid(egid); 280 281 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL) 282 errx(1, "%s", buf); 283 284 /* get rid of it now anyway */ 285 if (nlistf == NULL && memf == NULL) 286 (void)setgid(getgid()); 287 288 if ((p = kvm_getproc2(kd, what, arg, sizeof *p, &cnt)) == NULL) { 289 errx(1, "%s", kvm_geterr(kd)); 290 } 291 if (Aflg) 292 (void)printf("%-*s ", 2*(int)(sizeof(void*)), "ADDR"); 293 if (nflg) 294 (void)printf( 295 "USER CMD PID FD DEV INUM MODE %s R/W", 296 Oflg ? " OFFS" : "SZ|DV" ); 297 else 298 (void)printf( 299 "USER CMD PID FD MOUNT INUM MODE %s R/W", 300 Oflg ? " OFFS" : "SZ|DV" ); 301 302 if (checkfile && fsflg == 0) 303 (void)printf(" NAME\n"); 304 else 305 (void)putchar('\n'); 306 307 for (plast = &p[cnt]; p < plast; ++p) { 308 if (p->p_stat == SZOMB) 309 continue; 310 dofiles(p); 311 } 312 return 0; 313 } 314 315 static void 316 check_privs(void) 317 { 318 int expaddr; 319 size_t expsize = sizeof(expaddr); 320 const char *expname = "kern.expose_address"; 321 322 if (geteuid() == 0) 323 return; 324 325 if (sysctlbyname(expname, &expaddr, &expsize, NULL, 0) == -1) 326 err(EXIT_FAILURE, "Can't get sysctl `%s'", expname); 327 if (expaddr == 0) 328 errx(EXIT_FAILURE, "This program does not work without " 329 "sysctl `%s' being set", expname); 330 } 331 332 static const char *Uname, *Comm; 333 pid_t Pid; 334 335 #define PREFIX(i) (void)printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \ 336 switch(i) { \ 337 case TEXT: \ 338 (void)printf(" text"); \ 339 break; \ 340 case CDIR: \ 341 (void)printf(" wd"); \ 342 break; \ 343 case RDIR: \ 344 (void)printf(" root"); \ 345 break; \ 346 case TRACE: \ 347 (void)printf(" tr"); \ 348 break; \ 349 default: \ 350 (void)printf(" %4d", i); \ 351 break; \ 352 } 353 354 static struct kinfo_drivers *kdriver; 355 static size_t kdriverlen; 356 357 static int 358 kdriver_comp(const void *a, const void *b) 359 { 360 const struct kinfo_drivers *ka = a; 361 const struct kinfo_drivers *kb = b; 362 int kac = ka->d_cmajor == -1 ? 0 : ka->d_cmajor; 363 int kbc = kb->d_cmajor == -1 ? 0 : kb->d_cmajor; 364 int kab = ka->d_bmajor == -1 ? 0 : ka->d_bmajor; 365 int kbb = kb->d_bmajor == -1 ? 0 : kb->d_bmajor; 366 int c = kac - kbc; 367 if (c == 0) 368 return kab - kbb; 369 else 370 return c; 371 } 372 373 static const char * 374 kdriver_search(int type, dev_t num) 375 { 376 struct kinfo_drivers k, *kp; 377 static char buf[64]; 378 379 if (nflg) 380 goto out; 381 382 if (type == VBLK) { 383 k.d_bmajor = num; 384 k.d_cmajor = -1; 385 } else { 386 k.d_bmajor = -1; 387 k.d_cmajor = num; 388 } 389 kp = bsearch(&k, kdriver, kdriverlen, sizeof(*kdriver), kdriver_comp); 390 if (kp) 391 return kp->d_name; 392 out: 393 snprintf(buf, sizeof(buf), "%llu", (unsigned long long)num); 394 return buf; 395 } 396 397 398 static void 399 kdriver_init(void) 400 { 401 size_t sz; 402 int error; 403 static const int name[2] = { CTL_KERN, KERN_DRIVERS }; 404 405 error = sysctl(name, __arraycount(name), NULL, &sz, NULL, 0); 406 if (error == -1) { 407 warn("sysctl kern.drivers"); 408 return; 409 } 410 411 if (sz % sizeof(*kdriver)) { 412 warnx("bad size %zu for kern.drivers", sz); 413 return; 414 } 415 416 kdriver = malloc(sz); 417 if (kdriver == NULL) { 418 warn("malloc"); 419 return; 420 } 421 422 error = sysctl(name, __arraycount(name), kdriver, &sz, NULL, 0); 423 if (error == -1) { 424 warn("sysctl kern.drivers"); 425 return; 426 } 427 428 kdriverlen = sz / sizeof(*kdriver); 429 qsort(kdriver, kdriverlen, sizeof(*kdriver), kdriver_comp); 430 #ifdef DEBUG 431 for (size_t i = 0; i < kdriverlen; i++) 432 printf("%d %d %s\n", kdriver[i].d_cmajor, kdriver[i].d_bmajor, 433 kdriver[i].d_name); 434 #endif 435 } 436 437 /* 438 * print open files attributed to this process 439 */ 440 static void 441 dofiles(struct kinfo_proc2 *p) 442 { 443 int i; 444 struct filedesc filed; 445 struct cwdinfo cwdi; 446 struct fdtab dt; 447 448 Uname = user_from_uid(p->p_uid, 0); 449 Pid = p->p_pid; 450 Comm = p->p_comm; 451 452 if (p->p_fd == 0 || p->p_cwdi == 0) 453 return; 454 if (!KVM_READ(p->p_fd, &filed, sizeof (filed))) { 455 warnx("can't read filedesc at %p for pid %d", 456 (void *)(uintptr_t)p->p_fd, Pid); 457 return; 458 } 459 if (filed.fd_lastfile == -1) 460 return; 461 if (!KVM_READ(p->p_cwdi, &cwdi, sizeof(cwdi))) { 462 warnx("can't read cwdinfo at %p for pid %d", 463 (void *)(uintptr_t)p->p_cwdi, Pid); 464 return; 465 } 466 if (!KVM_READ(filed.fd_dt, &dt, sizeof(dt))) { 467 warnx("can't read dtab at %p for pid %d", filed.fd_dt, Pid); 468 return; 469 } 470 if ((unsigned)filed.fd_lastfile >= dt.dt_nfiles || 471 filed.fd_freefile > filed.fd_lastfile + 1) { 472 dprintf("filedesc corrupted at %p for pid %d", 473 (void *)(uintptr_t)p->p_fd, Pid); 474 return; 475 } 476 /* 477 * root directory vnode, if one 478 */ 479 if (cwdi.cwdi_rdir) 480 vtrans(NULL, cwdi.cwdi_rdir, RDIR, FREAD, (long)cwdi.cwdi_rdir); 481 /* 482 * current working directory vnode 483 */ 484 vtrans(NULL, cwdi.cwdi_cdir, CDIR, FREAD, (long)cwdi.cwdi_cdir); 485 #if 0 486 /* 487 * Disable for now, since p->p_tracep appears to point to a ktr_desc * 488 * ktrace vnode, if one 489 */ 490 if (p->p_tracep) 491 ftrans(p->p_tracep, TRACE); 492 #endif 493 /* 494 * open files 495 */ 496 #define FPSIZE (sizeof (fdfile_t *)) 497 ALLOC_OFILES(filed.fd_lastfile+1); 498 if (!KVM_READ(&filed.fd_dt->dt_ff, ofiles, 499 (filed.fd_lastfile+1) * FPSIZE)) { 500 dprintf("can't read file structures at %p for pid %d", 501 &filed.fd_dt->dt_ff, Pid); 502 return; 503 } 504 for (i = 0; i <= filed.fd_lastfile; i++) { 505 if (ofiles[i] == NULL) 506 continue; 507 ftrans(ofiles[i], i); 508 } 509 } 510 511 static void 512 ftrans(fdfile_t *fp, int i) 513 { 514 struct file file; 515 fdfile_t fdfile; 516 517 if (!KVM_READ(fp, &fdfile, sizeof(fdfile))) { 518 dprintf("can't read file %d at %p for pid %d", 519 i, fp, Pid); 520 return; 521 } 522 if (fdfile.ff_file == NULL) { 523 dprintf("null ff_file for %d at %p for pid %d", 524 i, fp, Pid); 525 return; 526 } 527 if (!KVM_READ(fdfile.ff_file, &file, sizeof(file))) { 528 dprintf("can't read file %d at %p for pid %d", 529 i, fdfile.ff_file, Pid); 530 return; 531 } 532 if (Aflg && file.f_type != DTYPE_VNODE && checkfile == 0) 533 (void)printf("%*lx ", 534 2*(int)(sizeof(void*)), (long)fdfile.ff_file); 535 switch (file.f_type) { 536 case DTYPE_VNODE: 537 vtrans(&file, file.f_data, i, file.f_flag, (long)fdfile.ff_file); 538 break; 539 case DTYPE_SOCKET: 540 socktrans(&file, file.f_data, i); 541 break; 542 case DTYPE_PIPE: 543 if (checkfile == 0) 544 ptrans(&file, file.f_data, i); 545 break; 546 case DTYPE_MISC: 547 case DTYPE_KQUEUE: 548 case DTYPE_CRYPTO: 549 case DTYPE_MQUEUE: 550 case DTYPE_SEM: 551 case DTYPE_MEMFD: 552 if (checkfile == 0) 553 misctrans(&file, i); 554 break; 555 default: 556 dprintf("unknown file type %d for file %d of pid %d", 557 file.f_type, i, Pid); 558 break; 559 } 560 } 561 562 static const char dead[] = "dead"; 563 static const char *vnode_tag[] = { 564 VNODE_TAGS 565 }; 566 567 static const char * 568 vfilestat(struct vnode *vp, struct filestat *fsp) 569 { 570 const char *badtype = NULL; 571 572 if (vp->v_type == VNON) 573 badtype = "none"; 574 else if (vp->v_type == VBAD) 575 badtype = "bad"; 576 else 577 switch (vp->v_tag) { 578 case VT_NON: 579 badtype = dead; 580 break; 581 case VT_UFS: 582 case VT_LFS: 583 case VT_MFS: 584 if (!ufs_filestat(vp, fsp)) 585 badtype = "error"; 586 break; 587 case VT_MSDOSFS: 588 if (!msdosfs_filestat(vp, fsp)) 589 badtype = "error"; 590 break; 591 case VT_NFS: 592 if (!nfs_filestat(vp, fsp)) 593 badtype = "error"; 594 break; 595 case VT_EXT2FS: 596 if (!ext2fs_filestat(vp, fsp)) 597 badtype = "error"; 598 break; 599 case VT_ISOFS: 600 if (!isofs_filestat(vp, fsp)) 601 badtype = "error"; 602 break; 603 case VT_NTFS: 604 if (!ntfs_filestat(vp, fsp)) 605 badtype = "error"; 606 break; 607 case VT_PTYFS: 608 if (!ptyfs_filestat(vp, fsp)) 609 badtype = "error"; 610 break; 611 case VT_TMPFS: 612 if (!tmpfs_filestat(vp, fsp)) 613 badtype = "error"; 614 break; 615 #ifdef HAVE_ZFS 616 case VT_ZFS: 617 if (!zfs_filestat(vp, fsp)) 618 badtype = "error"; 619 break; 620 #endif 621 case VT_NULL: 622 case VT_OVERLAY: 623 case VT_UMAP: 624 badtype = layer_filestat(vp, fsp); 625 break; 626 default: { 627 static char unknown[10]; 628 (void)snprintf(unknown, sizeof unknown, "%s(%#x)", 629 (size_t)vp->v_tag < __arraycount(vnode_tag) ? 630 vnode_tag[vp->v_tag] : "?", vp->v_tag); 631 badtype = unknown; 632 break; 633 } 634 } 635 return badtype; 636 } 637 638 static int 639 checkfs(struct vnode *vp, struct vnode *vn, struct filestat *fst, 640 const char **type, const char **fname) 641 { 642 *fname = NULL; 643 if (!KVM_READ(vp, vn, sizeof(*vn))) { 644 dprintf("can't read vnode at %p for pid %d", vp, Pid); 645 return 0; 646 } 647 *type = vfilestat(vn, fst); 648 if (checkfile) { 649 int fsmatch = 0; 650 DEVS *d; 651 #if 0 652 if (*type && *type != dead) 653 return 0; 654 #endif 655 for (d = devs; d != NULL; d = d->next) { 656 if (d->fsid == fst->fsid) { 657 fsmatch = 1; 658 if (d->ino == fst->fileid) { 659 *fname = d->name; 660 break; 661 } 662 } 663 } 664 if (fsmatch == 0 || (*fname == NULL && fsflg == 0)) 665 return 0; 666 } 667 return 1; 668 } 669 670 static void 671 vprint(struct vnode *vn, struct filestat *fst) 672 { 673 switch (vn->v_type) { 674 case VBLK: 675 case VCHR: { 676 const char *name; 677 678 if (nflg || ((name = devname(fst->rdev, vn->v_type == VCHR ? 679 S_IFCHR : S_IFBLK)) == NULL)) 680 (void)printf(" %s,%-2llu", 681 kdriver_search(vn->v_type, major(fst->rdev)), 682 (unsigned long long)minor(fst->rdev)); 683 else 684 (void)printf(" %6s", name); 685 break; 686 } 687 default: 688 (void)printf(" %6lld", (long long)fst->size); 689 } 690 } 691 692 void 693 oprint(struct file *fp, const char *str) 694 { 695 if (Oflg) 696 (void)printf(" %6lld", (long long)(fp ? fp->f_offset : 0)); 697 fputs(str, stdout); 698 } 699 700 static void 701 vtrans(struct file *fp, struct vnode *vp, int i, int flag, long addr) 702 { 703 struct vnode vn; 704 char mode[15], rw[3]; 705 const char *badtype, *filename; 706 struct filestat fst; 707 708 if (!checkfs(vp, &vn, &fst, &badtype, &filename)) 709 return; 710 711 if (Aflg) 712 (void)printf("%*lx ", 2*(int)(sizeof(void*)), addr); 713 PREFIX(i); 714 if (badtype == dead) { 715 char buf[1024]; 716 (void)snprintb(buf, sizeof(buf), VNODE_FLAGBITS, 717 vn.v_iflag | vn.v_vflag | vn.v_uflag); 718 (void)printf(" flags %s\n", buf); 719 return; 720 } else if (badtype) { 721 (void)printf(" - - %10s -\n", badtype); 722 return; 723 } 724 if (nflg) 725 (void)printf(" %3llu,%-2llu", 726 (unsigned long long)major(fst.fsid), 727 (unsigned long long)minor(fst.fsid)); 728 else 729 (void)printf(" %-8s", getmnton(vn.v_mount)); 730 if (nflg) 731 (void)snprintf(mode, sizeof mode, "%6o", fst.mode); 732 else 733 strmode(fst.mode, mode); 734 (void)printf(" %8"PRIu64" %*s", fst.fileid, nflg ? 5 : 10, mode); 735 if (Oflg) { 736 oprint(fp, ""); 737 } else { 738 vprint(&vn, &fst); 739 } 740 rw[0] = '\0'; 741 if (flag & FREAD) 742 (void)strlcat(rw, "r", sizeof(rw)); 743 if (flag & FWRITE) 744 (void)strlcat(rw, "w", sizeof(rw)); 745 (void)printf(" %-2s", rw); 746 if (filename && !fsflg) 747 (void)printf(" %s", filename); 748 (void)putchar('\n'); 749 } 750 751 static int 752 ufs_filestat(struct vnode *vp, struct filestat *fsp) 753 { 754 struct inode inode; 755 struct ufsmount ufsmount; 756 union dinode { 757 struct ufs1_dinode dp1; 758 struct ufs2_dinode dp2; 759 } dip; 760 761 if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) { 762 dprintf("can't read inode at %p for pid %d", VTOI(vp), Pid); 763 return 0; 764 } 765 766 if (!KVM_READ(inode.i_ump, &ufsmount, sizeof (struct ufsmount))) { 767 dprintf("can't read ufsmount at %p for pid %d", inode.i_ump, Pid); 768 return 0; 769 } 770 771 switch (ufsmount.um_fstype) { 772 case UFS1: 773 if (!KVM_READ(inode.i_din.ffs1_din, &dip, 774 sizeof(struct ufs1_dinode))) { 775 dprintf("can't read dinode at %p for pid %d", 776 inode.i_din.ffs1_din, Pid); 777 return 0; 778 } 779 fsp->rdev = dip.dp1.di_rdev; 780 break; 781 case UFS2: 782 if (!KVM_READ(inode.i_din.ffs2_din, &dip, 783 sizeof(struct ufs2_dinode))) { 784 dprintf("can't read dinode at %p for pid %d", 785 inode.i_din.ffs2_din, Pid); 786 return 0; 787 } 788 fsp->rdev = dip.dp2.di_rdev; 789 break; 790 default: 791 dprintf("unknown ufs type %ld for pid %d", 792 ufsmount.um_fstype, Pid); 793 break; 794 } 795 fsp->fsid = inode.i_dev & 0xffff; 796 fsp->fileid = inode.i_number; 797 fsp->mode = (mode_t)inode.i_mode; 798 fsp->size = inode.i_size; 799 800 return 1; 801 } 802 803 static int 804 ext2fs_filestat(struct vnode *vp, struct filestat *fsp) 805 { 806 struct inode inode; 807 struct ext2fs_dinode dinode; 808 809 if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) { 810 dprintf("can't read inode at %p for pid %d", VTOI(vp), Pid); 811 return 0; 812 } 813 fsp->fsid = inode.i_dev & 0xffff; 814 fsp->fileid = inode.i_number; 815 816 if (!KVM_READ(inode.i_din.e2fs_din, &dinode, sizeof dinode)) { 817 dprintf("can't read ext2fs_dinode at %p for pid %d", 818 inode.i_din.e2fs_din, Pid); 819 return 0; 820 } 821 fsp->mode = dinode.e2di_mode; 822 fsp->size = dinode.e2di_size; 823 fsp->rdev = dinode.e2di_rdev; 824 825 return 1; 826 } 827 828 static int 829 nfs_filestat(struct vnode *vp, struct filestat *fsp) 830 { 831 struct nfsnode nfsnode; 832 struct vattr va; 833 834 if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) { 835 dprintf("can't read nfsnode at %p for pid %d", VTONFS(vp), 836 Pid); 837 return 0; 838 } 839 if (!KVM_READ(nfsnode.n_vattr, &va, sizeof(va))) { 840 dprintf("can't read vnode attributes at %p for pid %d", 841 nfsnode.n_vattr, Pid); 842 return 0; 843 } 844 fsp->fsid = va.va_fsid; 845 fsp->fileid = va.va_fileid; 846 fsp->size = nfsnode.n_size; 847 fsp->rdev = va.va_rdev; 848 fsp->mode = (mode_t)va.va_mode | getftype(vp->v_type); 849 850 return 1; 851 } 852 853 static int 854 msdosfs_filestat(struct vnode *vp, struct filestat *fsp) 855 { 856 struct denode de; 857 struct msdosfsmount mp; 858 859 if (!KVM_READ(VTONFS(vp), &de, sizeof(de))) { 860 dprintf("can't read denode at %p for pid %d", VTONFS(vp), 861 Pid); 862 return 0; 863 } 864 if (!KVM_READ(de.de_pmp, &mp, sizeof(mp))) { 865 dprintf("can't read mount struct at %p for pid %d", de.de_pmp, 866 Pid); 867 return 0; 868 } 869 870 fsp->fsid = de.de_dev & 0xffff; 871 fsp->fileid = 0; /* XXX see msdosfs_vptofh() for more info */ 872 fsp->size = de.de_FileSize; 873 fsp->rdev = 0; /* msdosfs doesn't support device files */ 874 fsp->mode = (0777 & mp.pm_mask) | getftype(vp->v_type); 875 return 1; 876 } 877 878 static const char * 879 layer_filestat(struct vnode *vp, struct filestat *fsp) 880 { 881 struct layer_node layer_node; 882 struct mount mount; 883 struct vnode vn; 884 const char *badtype; 885 886 if (!KVM_READ(VTOLAYER(vp), &layer_node, sizeof(layer_node))) { 887 dprintf("can't read layer_node at %p for pid %d", 888 VTOLAYER(vp), Pid); 889 return "error"; 890 } 891 if (!KVM_READ(vp->v_mount, &mount, sizeof(struct mount))) { 892 dprintf("can't read mount struct at %p for pid %d", 893 vp->v_mount, Pid); 894 return "error"; 895 } 896 vp = layer_node.layer_lowervp; 897 if (!KVM_READ(vp, &vn, sizeof(struct vnode))) { 898 dprintf("can't read vnode at %p for pid %d", vp, Pid); 899 return "error"; 900 } 901 if ((badtype = vfilestat(&vn, fsp)) == NULL) 902 fsp->fsid = mount.mnt_stat.f_fsidx.__fsid_val[0]; 903 return badtype; 904 } 905 906 static char * 907 getmnton(struct mount *m) 908 { 909 static struct mount mount; 910 static struct mtab { 911 struct mtab *next; 912 struct mount *m; 913 char mntonname[MNAMELEN]; 914 } *mhead = NULL; 915 struct mtab *mt; 916 917 for (mt = mhead; mt != NULL; mt = mt->next) 918 if (m == mt->m) 919 return mt->mntonname; 920 if (!KVM_READ(m, &mount, sizeof(struct mount))) { 921 warnx("can't read mount table at %p", m); 922 return NULL; 923 } 924 if ((mt = malloc(sizeof (struct mtab))) == NULL) { 925 err(1, "malloc(%u)", (unsigned int)sizeof(struct mtab)); 926 } 927 mt->m = m; 928 (void)memmove(&mt->mntonname[0], &mount.mnt_stat.f_mntonname[0], 929 MNAMELEN); 930 mt->next = mhead; 931 mhead = mt; 932 return mt->mntonname; 933 } 934 935 static const char * 936 inet_addrstr(char *buf, size_t len, const struct in_addr *a, uint16_t p, bool isdg) 937 { 938 char addr[256], serv[256]; 939 struct sockaddr_in sin; 940 const int niflags = 941 (nflg ? (NI_NUMERICHOST|NI_NUMERICSERV) : 0) | 942 (isdg ? NI_DGRAM : 0); 943 944 945 (void)memset(&sin, 0, sizeof(sin)); 946 sin.sin_family = AF_INET; 947 sin.sin_len = sizeof(sin); 948 sin.sin_addr = *a; 949 sin.sin_port = htons(p); 950 951 serv[0] = '\0'; 952 953 if (getnameinfo((struct sockaddr *)&sin, sin.sin_len, 954 addr, sizeof(addr), serv, sizeof(serv), niflags)) { 955 if (inet_ntop(AF_INET, a, addr, sizeof(addr)) == NULL) 956 strlcpy(addr, "invalid", sizeof(addr)); 957 } 958 959 if (serv[0] == '\0') 960 snprintf(serv, sizeof(serv), "%u", p); 961 962 if (a->s_addr == INADDR_ANY) { 963 if (p == 0) 964 buf[0] = '\0'; 965 else 966 snprintf(buf, len, "*:%s", serv); 967 return buf; 968 } 969 970 snprintf(buf, len, "%s:%s", addr, serv); 971 return buf; 972 } 973 974 #ifdef INET6 975 static const char * 976 inet6_addrstr(char *buf, size_t len, const struct in6_addr *a, uint16_t p, bool isdg) 977 { 978 char addr[256], serv[256]; 979 struct sockaddr_in6 sin6; 980 const int niflags = 981 (nflg ? (NI_NUMERICHOST|NI_NUMERICSERV) : 0) | 982 (isdg ? NI_DGRAM : 0); 983 984 (void)memset(&sin6, 0, sizeof(sin6)); 985 sin6.sin6_family = AF_INET6; 986 sin6.sin6_len = sizeof(sin6); 987 sin6.sin6_addr = *a; 988 sin6.sin6_port = htons(p); 989 990 inet6_getscopeid(&sin6, INET6_IS_ADDR_LINKLOCAL); 991 serv[0] = '\0'; 992 993 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 994 addr, sizeof(addr), serv, sizeof(serv), niflags)) { 995 if (inet_ntop(AF_INET6, a, addr, sizeof(addr)) == NULL) 996 strlcpy(addr, "invalid", sizeof(addr)); 997 } 998 999 if (serv[0] == '\0') 1000 snprintf(serv, sizeof(serv), "%u", p); 1001 1002 if (IN6_IS_ADDR_UNSPECIFIED(a)) { 1003 if (p == 0) 1004 buf[0] = '\0'; 1005 else 1006 snprintf(buf, len, "*:%s", serv); 1007 return buf; 1008 } 1009 1010 if (strchr(addr, ':') == NULL) 1011 snprintf(buf, len, "%s:%s", addr, serv); 1012 else 1013 snprintf(buf, len, "[%s]:%s", addr, serv); 1014 1015 return buf; 1016 } 1017 #endif 1018 1019 static const char * 1020 at_addrstr(char *buf, size_t len, const struct sockaddr_at *sat) 1021 { 1022 const struct netrange *nr = &sat->sat_range.r_netrange; 1023 const struct at_addr *at = &sat->sat_addr; 1024 char addr[64], phase[64], range[64]; 1025 1026 if (sat->sat_port || at->s_net || at->s_node) { 1027 if (at->s_net || at->s_node) 1028 snprintf(addr, sizeof(addr), "%u.%u:%u", 1029 ntohs(at->s_net), at->s_node, sat->sat_port); 1030 else 1031 snprintf(addr, sizeof(addr), "*:%u", sat->sat_port); 1032 } else 1033 addr[0] = '\0'; 1034 1035 if (nr->nr_phase) 1036 snprintf(phase, sizeof(phase), " phase %u", nr->nr_phase); 1037 else 1038 phase[0] = '\0'; 1039 1040 if (nr->nr_firstnet || nr->nr_lastnet) 1041 snprintf(range, sizeof(range), " range [%u-%u]", 1042 ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet)); 1043 else 1044 range[0] = '\0'; 1045 1046 snprintf(buf, len, "%s%s%s", addr, phase, range); 1047 return buf; 1048 } 1049 1050 static void 1051 socktrans(struct file *f, struct socket *sock, int i) 1052 { 1053 static const char *stypename[] = { 1054 "unused", /* 0 */ 1055 "stream", /* 1 */ 1056 "dgram", /* 2 */ 1057 "raw", /* 3 */ 1058 "rdm", /* 4 */ 1059 "seqpak" /* 5 */ 1060 }; 1061 #define STYPEMAX 5 1062 struct socket so; 1063 struct protosw proto; 1064 struct domain dom; 1065 struct in4pcb in4pcb; 1066 struct in6pcb in6pcb; 1067 struct unpcb unpcb; 1068 struct ddpcb ddpcb; 1069 int len; 1070 char dname[32]; 1071 char lbuf[512], fbuf[512], pbuf[24]; 1072 bool isdgram; 1073 1074 pbuf[0] = '\0'; 1075 /* fill in socket */ 1076 if (!KVM_READ(sock, &so, sizeof(struct socket))) { 1077 dprintf("can't read sock at %p", sock); 1078 goto bad; 1079 } 1080 1081 /* fill in protosw entry */ 1082 if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) { 1083 dprintf("can't read protosw at %p", so.so_proto); 1084 goto bad; 1085 } 1086 1087 /* fill in domain */ 1088 if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) { 1089 dprintf("can't read domain at %p", proto.pr_domain); 1090 goto bad; 1091 } 1092 1093 if (checkfile && dom.dom_family != AF_LOCAL) 1094 return; 1095 1096 if ((len = kvm_read(kd, (u_long)dom.dom_name, dname, 1097 sizeof(dname) - 1)) != sizeof(dname) -1) { 1098 dprintf("can't read domain name at %p", dom.dom_name); 1099 dname[0] = '\0'; 1100 } 1101 else 1102 dname[len] = '\0'; 1103 1104 /* 1105 * protocol specific formatting 1106 * 1107 * Try to find interesting things to print. For TCP, the interesting 1108 * thing is the address of the tcpcb, for UDP and others, just the 1109 * inpcb (socket pcb). For UNIX domain, its the address of the socket 1110 * pcb and the address of the connected pcb (if connected). Otherwise 1111 * just print the protocol number and address of the socket itself. 1112 * The idea is not to duplicate netstat, but to make available enough 1113 * information for further analysis. 1114 */ 1115 fbuf[0] = '\0'; 1116 lbuf[0] = '\0'; 1117 isdgram = false; 1118 switch(dom.dom_family) { 1119 case AF_INET: 1120 getinetproto(pbuf, sizeof(pbuf), proto.pr_protocol); 1121 switch (proto.pr_protocol) { 1122 case IPPROTO_UDP: 1123 isdgram = true; 1124 /* FALLTHROUGH */ 1125 case IPPROTO_TCP: 1126 if (so.so_pcb == NULL) 1127 break; 1128 if (kvm_read(kd, (u_long)so.so_pcb, (char *)&in4pcb, 1129 sizeof(in4pcb)) != sizeof(in4pcb)) { 1130 dprintf("can't read in4pcb at %p", so.so_pcb); 1131 goto bad; 1132 } 1133 struct inpcb *inp = (struct inpcb *)&in4pcb; 1134 inet_addrstr(lbuf, sizeof(lbuf), &in4p_laddr(inp), 1135 ntohs(inp->inp_lport), isdgram); 1136 inet_addrstr(fbuf, sizeof(fbuf), &in4p_faddr(inp), 1137 ntohs(inp->inp_fport), isdgram); 1138 break; 1139 default: 1140 break; 1141 } 1142 break; 1143 #ifdef INET6 1144 case AF_INET6: 1145 getinetproto(pbuf, sizeof(pbuf), proto.pr_protocol); 1146 switch (proto.pr_protocol) { 1147 case IPPROTO_UDP: 1148 isdgram = true; 1149 /* FALLTHROUGH */ 1150 case IPPROTO_TCP: 1151 if (so.so_pcb == NULL) 1152 break; 1153 if (kvm_read(kd, (u_long)so.so_pcb, (char *)&in6pcb, 1154 sizeof(in6pcb)) != sizeof(in6pcb)) { 1155 dprintf("can't read in6pcb at %p", so.so_pcb); 1156 goto bad; 1157 } 1158 struct inpcb *inp = (struct inpcb *)&in6pcb; 1159 inet6_addrstr(lbuf, sizeof(lbuf), &in6p_laddr(inp), 1160 ntohs(inp->inp_lport), isdgram); 1161 inet6_addrstr(fbuf, sizeof(fbuf), &in6p_faddr(inp), 1162 ntohs(inp->inp_fport), isdgram); 1163 break; 1164 default: 1165 break; 1166 } 1167 break; 1168 #endif 1169 case AF_LOCAL: 1170 /* print address of pcb and connected pcb */ 1171 if (so.so_pcb) { 1172 char shoconn[4], *cp; 1173 void *pcb[2]; 1174 size_t p = 0; 1175 1176 pcb[0] = so.so_pcb; 1177 1178 cp = shoconn; 1179 if (!(so.so_state & SS_CANTRCVMORE)) 1180 *cp++ = '<'; 1181 *cp++ = '-'; 1182 if (!(so.so_state & SS_CANTSENDMORE)) 1183 *cp++ = '>'; 1184 *cp = '\0'; 1185 again: 1186 if (kvm_read(kd, (u_long)pcb[p], (char *)&unpcb, 1187 sizeof(struct unpcb)) != sizeof(struct unpcb)){ 1188 dprintf("can't read unpcb at %p", so.so_pcb); 1189 goto bad; 1190 } 1191 if (checkfile) { 1192 struct vnode vn; 1193 struct filestat fst; 1194 const char *badtype, *filename; 1195 if (unpcb.unp_vnode == NULL) 1196 return; 1197 if (!checkfs(unpcb.unp_vnode, &vn, &fst, 1198 &badtype, &filename)) 1199 return; 1200 } 1201 1202 if (unpcb.unp_addr) { 1203 struct sockaddr_un *sun = 1204 malloc(unpcb.unp_addrlen); 1205 if (sun == NULL) 1206 err(1, "malloc(%zu)", 1207 unpcb.unp_addrlen); 1208 if (kvm_read(kd, (u_long)unpcb.unp_addr, 1209 sun, unpcb.unp_addrlen) != 1210 (ssize_t)unpcb.unp_addrlen) { 1211 dprintf("can't read sun at %p", 1212 unpcb.unp_addr); 1213 free(sun); 1214 } else { 1215 snprintf(fbuf, sizeof(fbuf), " %s %s %s", 1216 shoconn, sun->sun_path, 1217 p == 0 ? "[creat]" : "[using]"); 1218 free(sun); 1219 break; 1220 } 1221 } 1222 if (unpcb.unp_conn) { 1223 if (p == 0) { 1224 pcb[++p] = unpcb.unp_conn; 1225 goto again; 1226 } else 1227 snprintf(fbuf, sizeof(fbuf), 1228 " %p %s %p", pcb[0], shoconn, 1229 pcb[1]); 1230 } 1231 } 1232 break; 1233 case AF_APPLETALK: 1234 getatproto(pbuf, sizeof(pbuf), proto.pr_protocol); 1235 if (so.so_pcb) { 1236 if (kvm_read(kd, (u_long)so.so_pcb, (char *)&ddpcb, 1237 sizeof(ddpcb)) != sizeof(ddpcb)){ 1238 dprintf("can't read ddpcb at %p", so.so_pcb); 1239 goto bad; 1240 } 1241 at_addrstr(fbuf, sizeof(fbuf), &ddpcb.ddp_fsat); 1242 at_addrstr(lbuf, sizeof(lbuf), &ddpcb.ddp_lsat); 1243 } 1244 break; 1245 default: 1246 /* print protocol number and socket address */ 1247 snprintf(fbuf, sizeof(fbuf), " %d %jx", proto.pr_protocol, 1248 (uintmax_t)(uintptr_t)sock); 1249 break; 1250 } 1251 PREFIX(i); 1252 if ((u_short)so.so_type > STYPEMAX) 1253 (void)printf("* %s ?%d", dname, so.so_type); 1254 else 1255 (void)printf("* %s %s", dname, stypename[so.so_type]); 1256 1257 if (pbuf[0]) 1258 printf("%s", pbuf); 1259 if (fbuf[0] || lbuf[0]) 1260 printf(" %s%s%s", fbuf, (fbuf[0] && lbuf[0]) ? " <-> " : "", 1261 lbuf); 1262 else if (so.so_pcb) 1263 printf(" %jx", (uintmax_t)(uintptr_t)so.so_pcb); 1264 oprint(f, "\n"); 1265 return; 1266 bad: 1267 (void)printf("* error\n"); 1268 } 1269 1270 static void 1271 ptrans(struct file *fp, struct pipe *cpipe, int i) 1272 { 1273 struct pipe cp; 1274 1275 PREFIX(i); 1276 1277 /* fill in pipe */ 1278 if (!KVM_READ(cpipe, &cp, sizeof(struct pipe))) { 1279 dprintf("can't read pipe at %p", cpipe); 1280 goto bad; 1281 } 1282 1283 /* pipe descriptor is either read or write, never both */ 1284 (void)printf("* pipe %p %s %p %s%s%s", cpipe, 1285 (fp->f_flag & FWRITE) ? "->" : "<-", 1286 cp.pipe_peer, 1287 (fp->f_flag & FWRITE) ? "w" : "r", 1288 (fp->f_flag & FNONBLOCK) ? "n" : "", 1289 (cp.pipe_state & PIPE_ASYNC) ? "a" : ""); 1290 oprint(fp, "\n"); 1291 return; 1292 bad: 1293 (void)printf("* error\n"); 1294 } 1295 1296 static void 1297 misctrans(struct file *file, int i) 1298 { 1299 1300 PREFIX(i); 1301 pmisc(file, dtypes[file->f_type]); 1302 } 1303 1304 /* 1305 * getinetproto -- 1306 * print name of protocol number 1307 */ 1308 static void 1309 getinetproto(char *buf, size_t len, int number) 1310 { 1311 const char *cp; 1312 1313 switch (number) { 1314 case IPPROTO_IP: 1315 cp = "ip"; break; 1316 case IPPROTO_ICMP: 1317 cp ="icmp"; break; 1318 case IPPROTO_GGP: 1319 cp ="ggp"; break; 1320 case IPPROTO_TCP: 1321 cp ="tcp"; break; 1322 case IPPROTO_EGP: 1323 cp ="egp"; break; 1324 case IPPROTO_PUP: 1325 cp ="pup"; break; 1326 case IPPROTO_UDP: 1327 cp ="udp"; break; 1328 case IPPROTO_IDP: 1329 cp ="idp"; break; 1330 case IPPROTO_RAW: 1331 cp ="raw"; break; 1332 case IPPROTO_ICMPV6: 1333 cp ="icmp6"; break; 1334 default: 1335 (void)snprintf(buf, len, " %d", number); 1336 return; 1337 } 1338 (void)snprintf(buf, len, " %s", cp); 1339 } 1340 1341 /* 1342 * getatproto -- 1343 * print name of protocol number 1344 */ 1345 static void 1346 getatproto(char *buf, size_t len, int number) 1347 { 1348 const char *cp; 1349 1350 switch (number) { 1351 case ATPROTO_DDP: 1352 cp = "ddp"; break; 1353 case ATPROTO_AARP: 1354 cp ="aarp"; break; 1355 default: 1356 (void)snprintf(buf, len, " %d", number); 1357 return; 1358 } 1359 (void)snprintf(buf, len, " %s", cp); 1360 } 1361 1362 static int 1363 getfname(const char *filename) 1364 { 1365 struct stat statbuf; 1366 DEVS *cur; 1367 1368 if (stat(filename, &statbuf)) { 1369 warn("stat(%s)", filename); 1370 return 0; 1371 } 1372 if ((cur = malloc(sizeof(*cur))) == NULL) { 1373 err(1, "malloc(%zu)", sizeof(*cur)); 1374 } 1375 cur->next = devs; 1376 devs = cur; 1377 1378 cur->ino = statbuf.st_ino; 1379 cur->fsid = statbuf.st_dev & 0xffff; 1380 cur->name = filename; 1381 return 1; 1382 } 1383 1384 mode_t 1385 getftype(enum vtype v_type) 1386 { 1387 mode_t ftype; 1388 1389 switch (v_type) { 1390 case VREG: 1391 ftype = S_IFREG; 1392 break; 1393 case VDIR: 1394 ftype = S_IFDIR; 1395 break; 1396 case VBLK: 1397 ftype = S_IFBLK; 1398 break; 1399 case VCHR: 1400 ftype = S_IFCHR; 1401 break; 1402 case VLNK: 1403 ftype = S_IFLNK; 1404 break; 1405 case VSOCK: 1406 ftype = S_IFSOCK; 1407 break; 1408 case VFIFO: 1409 ftype = S_IFIFO; 1410 break; 1411 default: 1412 ftype = 0; 1413 break; 1414 }; 1415 1416 return ftype; 1417 } 1418 1419 static void 1420 usage(void) 1421 { 1422 (void)fprintf(stderr, "Usage: %s [-Afnv] [-M core] [-N system] " 1423 "[-p pid] [-u user] [file ...]\n", getprogname()); 1424 exit(1); 1425 } 1426