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