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 | } |