File: | src/usr.bin/fstat/fstat.c |
Warning: | line 619, 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.103 2022/06/20 01:39:44 visa 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_MAX0x7fffffff, | ||||
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_MAX0xffffffffU, | ||||
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\n", | ||||
566 | kf->kq_count, | ||||
567 | (kf->kq_state & KQ_SLEEP0x02) ? "W" : ""); | ||||
568 | return; | ||||
569 | } | ||||
570 | |||||
571 | const char * | ||||
572 | inet6_addrstr(struct in6_addr *p) | ||||
573 | { | ||||
574 | struct sockaddr_in6 sin6; | ||||
575 | static char hbuf[NI_MAXHOST256]; | ||||
576 | const int niflags = NI_NUMERICHOST1; | ||||
577 | |||||
578 | memset(&sin6, 0, sizeof(sin6)); | ||||
579 | sin6.sin6_family = AF_INET624; | ||||
580 | sin6.sin6_len = sizeof(struct sockaddr_in6); | ||||
581 | sin6.sin6_addr = *p; | ||||
582 | if (IN6_IS_ADDR_LINKLOCAL(p)(((p)->__u6_addr.__u6_addr8[0] == 0xfe) && (((p)-> __u6_addr.__u6_addr8[1] & 0xc0) == 0x80)) && | ||||
583 | *(u_int16_t *)&sin6.sin6_addr.s6_addr__u6_addr.__u6_addr8[2] != 0) { | ||||
584 | sin6.sin6_scope_id = | ||||
585 | 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])); | ||||
586 | sin6.sin6_addr.s6_addr__u6_addr.__u6_addr8[2] = sin6.sin6_addr.s6_addr__u6_addr.__u6_addr8[3] = 0; | ||||
587 | } | ||||
588 | |||||
589 | if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, | ||||
590 | hbuf, sizeof(hbuf), NULL((void *)0), 0, niflags)) | ||||
591 | return "invalid"; | ||||
592 | |||||
593 | return hbuf; | ||||
594 | } | ||||
595 | |||||
596 | void | ||||
597 | splice_insert(char type, u_int64_t ptr, struct kinfo_file *data) | ||||
598 | { | ||||
599 | ENTRY entry, *found; | ||||
600 | |||||
601 | if (asprintf(&entry.key, "%c%llx", type, hideroot ? 0 : ptr) == -1) | ||||
602 | err(1, NULL((void *)0)); | ||||
603 | entry.data = data; | ||||
604 | if ((found = hsearch(entry, ENTER)) == NULL((void *)0)) | ||||
605 | err(1, "hsearch"); | ||||
606 | /* if it's ambiguous, set the data to NULL */ | ||||
607 | if (found->data != data) | ||||
608 | found->data = NULL((void *)0); | ||||
609 | } | ||||
610 | |||||
611 | struct kinfo_file * | ||||
612 | splice_find(char type, u_int64_t ptr) | ||||
613 | { | ||||
614 | ENTRY entry, *found; | ||||
615 | char buf[20]; | ||||
616 | |||||
617 | snprintf(buf, sizeof(buf), "%c%llx", type, hideroot ? 0 : ptr); | ||||
618 | entry.key = buf; | ||||
619 | found = hsearch(entry, FIND); | ||||
| |||||
620 | return (found != NULL((void *)0) ? found->data : NULL((void *)0)); | ||||
621 | } | ||||
622 | |||||
623 | void | ||||
624 | find_splices(struct kinfo_file *kf, int cnt) | ||||
625 | { | ||||
626 | int i, created; | ||||
627 | |||||
628 | created = 0; | ||||
629 | for (i = 0; i < cnt; i++) { | ||||
630 | if (kf[i].f_type != DTYPE_SOCKET2 || | ||||
631 | (kf[i].so_splice == 0 && kf[i].so_splicelen != -1)) | ||||
632 | continue; | ||||
633 | if (created++ == 0) { | ||||
634 | if (hcreate(1000) == 0) | ||||
635 | err(1, "hcreate"); | ||||
636 | } | ||||
637 | splice_insert('>', kf[i].f_data, &kf[i]); | ||||
638 | if (kf[i].so_splice != 0) | ||||
639 | splice_insert('<', kf[i].so_splice, &kf[i]); | ||||
640 | } | ||||
641 | } | ||||
642 | |||||
643 | void | ||||
644 | print_inet_details(struct kinfo_file *kf) | ||||
645 | { | ||||
646 | struct in_addr laddr, faddr; | ||||
647 | |||||
648 | memcpy(&laddr, kf->inp_laddru, sizeof(laddr)); | ||||
649 | memcpy(&faddr, kf->inp_faddru, sizeof(faddr)); | ||||
650 | if (kf->so_protocol == IPPROTO_TCP6) { | ||||
651 | printf(" "); | ||||
652 | hide((void *)(uintptr_t)kf->inp_ppcb); | ||||
653 | printf(" %s:%d", laddr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)) ? "*" : | ||||
654 | 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))); | ||||
655 | if (kf->inp_fport) { | ||||
656 | if (kf->so_state & SS_CONNECTOUT0x1000) | ||||
657 | printf(" --> "); | ||||
658 | else | ||||
659 | printf(" <-- "); | ||||
660 | printf("%s:%d", | ||||
661 | faddr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)) ? "*" : | ||||
662 | 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))); | ||||
663 | } | ||||
664 | } else if (kf->so_protocol == IPPROTO_UDP17) { | ||||
665 | printf(" %s:%d", laddr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)) ? "*" : | ||||
666 | 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))); | ||||
667 | if (kf->inp_fport) { | ||||
668 | printf(" <-> %s:%d", | ||||
669 | faddr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)) ? "*" : | ||||
670 | 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))); | ||||
671 | } | ||||
672 | } else if (kf->so_pcb) { | ||||
673 | printf(" "); | ||||
674 | hide((void *)(uintptr_t)kf->so_pcb); | ||||
675 | } | ||||
676 | } | ||||
677 | |||||
678 | void | ||||
679 | print_inet6_details(struct kinfo_file *kf) | ||||
680 | { | ||||
681 | char xaddrbuf[NI_MAXHOST256 + 2]; | ||||
682 | struct in6_addr laddr6, faddr6; | ||||
683 | |||||
684 | memcpy(&laddr6, kf->inp_laddru, sizeof(laddr6)); | ||||
685 | memcpy(&faddr6, kf->inp_faddru, sizeof(faddr6)); | ||||
686 | if (kf->so_protocol == IPPROTO_TCP6) { | ||||
687 | printf(" "); | ||||
688 | hide((void *)(uintptr_t)kf->inp_ppcb); | ||||
689 | snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]", | ||||
690 | inet6_addrstr(&laddr6)); | ||||
691 | printf(" %s:%d", | ||||
692 | 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)) ? "*" : | ||||
693 | 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))); | ||||
694 | if (kf->inp_fport) { | ||||
695 | if (kf->so_state & SS_CONNECTOUT0x1000) | ||||
696 | printf(" --> "); | ||||
697 | else | ||||
698 | printf(" <-- "); | ||||
699 | snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]", | ||||
700 | inet6_addrstr(&faddr6)); | ||||
701 | printf("%s:%d", | ||||
702 | 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)) ? "*" : | ||||
703 | 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))); | ||||
704 | } | ||||
705 | } else if (kf->so_protocol == IPPROTO_UDP17) { | ||||
706 | snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]", | ||||
707 | inet6_addrstr(&laddr6)); | ||||
708 | printf(" %s:%d", | ||||
709 | 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)) ? "*" : | ||||
710 | 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))); | ||||
711 | if (kf->inp_fport) { | ||||
712 | snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]", | ||||
713 | inet6_addrstr(&faddr6)); | ||||
714 | printf(" <-> %s:%d", | ||||
715 | 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)) ? "*" : | ||||
716 | 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))); | ||||
717 | } | ||||
718 | } else if (kf->so_pcb) { | ||||
719 | printf(" "); | ||||
720 | hide((void *)(uintptr_t)kf->so_pcb); | ||||
721 | } | ||||
722 | } | ||||
723 | |||||
724 | void | ||||
725 | print_sock_details(struct kinfo_file *kf) | ||||
726 | { | ||||
727 | if (kf->so_family == AF_INET2) | ||||
728 | print_inet_details(kf); | ||||
729 | else if (kf->so_family == AF_INET624) | ||||
730 | print_inet6_details(kf); | ||||
731 | } | ||||
732 | |||||
733 | void | ||||
734 | socktrans(struct kinfo_file *kf) | ||||
735 | { | ||||
736 | static char *stypename[] = { | ||||
737 | "unused", /* 0 */ | ||||
738 | "stream", /* 1 */ | ||||
739 | "dgram", /* 2 */ | ||||
740 | "raw", /* 3 */ | ||||
741 | "rdm", /* 4 */ | ||||
742 | "seqpak" /* 5 */ | ||||
743 | }; | ||||
744 | #define STYPEMAX5 5 | ||||
745 | char *stype, stypebuf[24]; | ||||
746 | |||||
747 | if (checkfile
| ||||
748 | struct filearg *fa; | ||||
749 | |||||
750 | if (kf->so_type != AF_UNIX1) | ||||
751 | return; | ||||
752 | SLIST_FOREACH(fa, &fileargs, next)for((fa) = ((&fileargs)->slh_first); (fa) != ((void *) 0); (fa) = ((fa)->next.sle_next)) { | ||||
753 | if (fa->dev != 0) | ||||
754 | continue; | ||||
755 | if (strcmp(kf->unp_path, fa->name) == 0) | ||||
756 | break; | ||||
757 | } | ||||
758 | if (fa == NULL((void *)0)) | ||||
759 | return; | ||||
760 | } | ||||
761 | |||||
762 | 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); | ||||
763 | |||||
764 | if (kf->so_type > STYPEMAX5) { | ||||
765 | snprintf(stypebuf, sizeof(stypebuf), "?%d", kf->so_type); | ||||
766 | stype = stypebuf; | ||||
767 | } else { | ||||
768 | stype = stypename[kf->so_type]; | ||||
769 | } | ||||
770 | |||||
771 | /* | ||||
772 | * protocol specific formatting | ||||
773 | * | ||||
774 | * Try to find interesting things to print. For tcp, the interesting | ||||
775 | * thing is the address of the tcpcb, for udp and others, just the | ||||
776 | * inpcb (socket pcb). For unix domain, its the address of the socket | ||||
777 | * pcb and the address of the connected pcb (if connected). Otherwise | ||||
778 | * just print the protocol number and address of the socket itself. | ||||
779 | * The idea is not to duplicate netstat, but to make available enough | ||||
780 | * information for further analysis. | ||||
781 | */ | ||||
782 | switch (kf->so_family) { | ||||
783 | case AF_INET2: | ||||
784 | printf("* internet %s", stype); | ||||
785 | getinetproto(kf->so_protocol); | ||||
786 | print_inet_details(kf); | ||||
787 | if (kf->inp_rtableid) | ||||
788 | printf(" rtable %u", kf->inp_rtableid); | ||||
789 | break; | ||||
790 | case AF_INET624: | ||||
791 | printf("* internet6 %s", stype); | ||||
792 | getinetproto(kf->so_protocol); | ||||
793 | print_inet6_details(kf); | ||||
794 | if (kf->inp_rtableid) | ||||
795 | printf(" rtable %u", kf->inp_rtableid); | ||||
796 | break; | ||||
797 | case AF_UNIX1: | ||||
798 | /* print address of pcb and connected pcb */ | ||||
799 | printf("* unix %s", stype); | ||||
800 | if (kf->so_pcb) { | ||||
801 | printf(" "); | ||||
802 | hide((void *)(uintptr_t)kf->so_pcb); | ||||
803 | if (kf->unp_conn) { | ||||
804 | char shoconn[4], *cp; | ||||
805 | |||||
806 | cp = shoconn; | ||||
807 | if (!(kf->so_state & SS_CANTRCVMORE0x020)) | ||||
808 | *cp++ = '<'; | ||||
809 | *cp++ = '-'; | ||||
810 | if (!(kf->so_state & SS_CANTSENDMORE0x010)) | ||||
811 | *cp++ = '>'; | ||||
812 | *cp = '\0'; | ||||
813 | printf(" %s ", shoconn); | ||||
814 | hide((void *)(uintptr_t)kf->unp_conn); | ||||
815 | } | ||||
816 | } | ||||
817 | if (kf->unp_path[0] != '\0') | ||||
818 | printf(" %s", kf->unp_path); | ||||
819 | break; | ||||
820 | case AF_MPLS33: | ||||
821 | /* print protocol number and socket address */ | ||||
822 | printf("* mpls %s", stype); | ||||
823 | printf(" %d ", kf->so_protocol); | ||||
824 | hide((void *)(uintptr_t)kf->f_data); | ||||
825 | break; | ||||
826 | case AF_ROUTE17: | ||||
827 | /* print protocol number and socket address */ | ||||
828 | printf("* route %s", stype); | ||||
829 | printf(" %d ", kf->so_protocol); | ||||
830 | hide((void *)(uintptr_t)kf->f_data); | ||||
831 | break; | ||||
832 | case AF_KEY30: | ||||
833 | printf("* pfkey %s", stype); | ||||
834 | printf(" %d ", kf->so_protocol); | ||||
835 | hide((void *)(uintptr_t)kf->f_data); | ||||
836 | break; | ||||
837 | default: | ||||
838 | /* print protocol number and socket address */ | ||||
839 | printf("* %d %s", kf->so_family, stype); | ||||
840 | printf(" %d ", kf->so_protocol); | ||||
841 | hide((void *)(uintptr_t)kf->f_data); | ||||
842 | } | ||||
843 | if (kf->so_splice != 0 || kf->so_splicelen == -1) { | ||||
844 | struct kinfo_file *from, *to; | ||||
845 | |||||
846 | from = splice_find('<', kf->f_data); | ||||
847 | to = NULL((void *)0); | ||||
848 | if (kf->so_splice != 0) | ||||
849 | to = splice_find('>', kf->so_splice); | ||||
850 | |||||
851 | if (to != NULL((void *)0) && from == to) { | ||||
852 | printf(" <==>"); | ||||
853 | print_sock_details(to); | ||||
854 | } else if (kf->so_splice != 0) { | ||||
855 | printf(" ==>"); | ||||
856 | if (to != NULL((void *)0)) | ||||
857 | print_sock_details(to); | ||||
858 | } else if (kf->so_splicelen == -1) { | ||||
859 | printf(" <=="); | ||||
860 | if (from != NULL((void *)0)) | ||||
861 | print_sock_details(from); | ||||
862 | } | ||||
863 | } | ||||
864 | if (sflg) | ||||
865 | printf("\t%8llu %8llu", | ||||
866 | (kf->f_rxfer + kf->f_rwfer), | ||||
867 | (kf->f_rbytes + kf->f_wbytes) / 1024); | ||||
868 | printf("\n"); | ||||
869 | } | ||||
870 | |||||
871 | /* | ||||
872 | * getinetproto -- | ||||
873 | * print name of protocol number | ||||
874 | */ | ||||
875 | void | ||||
876 | getinetproto(int number) | ||||
877 | { | ||||
878 | static int isopen; | ||||
879 | struct protoent *pe; | ||||
880 | |||||
881 | if (!isopen) | ||||
882 | setprotoent(++isopen); | ||||
883 | if ((pe = getprotobynumber(number)) != NULL((void *)0)) | ||||
884 | printf(" %s", pe->p_name); | ||||
885 | else | ||||
886 | printf(" %d", number); | ||||
887 | } | ||||
888 | |||||
889 | int | ||||
890 | getfname(char *filename) | ||||
891 | { | ||||
892 | static struct statfs *mntbuf; | ||||
893 | static int nmounts; | ||||
894 | int i; | ||||
895 | struct stat sb; | ||||
896 | struct filearg *cur; | ||||
897 | |||||
898 | if (stat(filename, &sb)) { | ||||
899 | warn("%s", filename); | ||||
900 | return (0); | ||||
901 | } | ||||
902 | |||||
903 | /* | ||||
904 | * POSIX specifies "For block special devices, all processes using any | ||||
905 | * file on that device are listed". However the -f flag description | ||||
906 | * states "The report shall be only for the named files", so we only | ||||
907 | * look up a block device if the -f flag has not be specified. | ||||
908 | */ | ||||
909 | if (fuser && !fsflg && S_ISBLK(sb.st_mode)((sb.st_mode & 0170000) == 0060000)) { | ||||
910 | if (mntbuf == NULL((void *)0)) { | ||||
911 | nmounts = getmntinfo(&mntbuf, MNT_NOWAIT2); | ||||
912 | if (nmounts == -1) | ||||
913 | err(1, "getmntinfo"); | ||||
914 | } | ||||
915 | for (i = 0; i < nmounts; i++) { | ||||
916 | if (!strcmp(mntbuf[i].f_mntfromname, filename)) { | ||||
917 | if (stat(mntbuf[i].f_mntonname, &sb) == -1) { | ||||
918 | warn("%s", filename); | ||||
919 | return (0); | ||||
920 | } | ||||
921 | cflg = 1; | ||||
922 | break; | ||||
923 | } | ||||
924 | } | ||||
925 | } | ||||
926 | if (!fuser && S_ISSOCK(sb.st_mode)((sb.st_mode & 0170000) == 0140000)) { | ||||
927 | char *newname = realpath(filename, NULL((void *)0)); | ||||
928 | if (newname != NULL((void *)0)) | ||||
929 | filename = newname; | ||||
930 | } | ||||
931 | |||||
932 | if ((cur = calloc(1, sizeof(*cur))) == NULL((void *)0)) | ||||
933 | err(1, NULL((void *)0)); | ||||
934 | |||||
935 | if (!S_ISSOCK(sb.st_mode)((sb.st_mode & 0170000) == 0140000)) { | ||||
936 | cur->ino = sb.st_ino; | ||||
937 | cur->dev = sb.st_dev & 0xffff; | ||||
938 | } | ||||
939 | cur->name = filename; | ||||
940 | TAILQ_INIT(&cur->fusers)do { (&cur->fusers)->tqh_first = ((void *)0); (& cur->fusers)->tqh_last = &(&cur->fusers)-> tqh_first; } while (0); | ||||
941 | SLIST_INSERT_HEAD(&fileargs, cur, next)do { (cur)->next.sle_next = (&fileargs)->slh_first; (&fileargs)->slh_first = (cur); } while (0); | ||||
942 | return (1); | ||||
943 | } | ||||
944 | |||||
945 | int | ||||
946 | signame_to_signum(char *sig) | ||||
947 | { | ||||
948 | int n; | ||||
949 | const char *errstr = NULL((void *)0); | ||||
950 | |||||
951 | if (isdigit((unsigned char)*sig)) { | ||||
952 | n = strtonum(sig, 0, NSIG33 - 1, &errstr); | ||||
953 | return (errstr ? -1 : n); | ||||
954 | } | ||||
955 | if (!strncasecmp(sig, "sig", 3)) | ||||
956 | sig += 3; | ||||
957 | for (n = 1; n < NSIG33; n++) { | ||||
958 | if (!strcasecmp(sys_signame[n], sig)) | ||||
959 | return (n); | ||||
960 | } | ||||
961 | return (-1); | ||||
962 | } | ||||
963 | |||||
964 | void | ||||
965 | usage(void) | ||||
966 | { | ||||
967 | if (fuser) { | ||||
968 | fprintf(stderr(&__sF[2]), "usage: fuser [-cfku] [-M core] " | ||||
969 | "[-N system] [-s signal] file ...\n"); | ||||
970 | } else { | ||||
971 | fprintf(stderr(&__sF[2]), "usage: fstat [-fnosv] [-M core] [-N system] " | ||||
972 | "[-p pid] [-u user] [file ...]\n"); | ||||
973 | } | ||||
974 | exit(1); | ||||
975 | } |