GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/fstat/fstat.c Lines: 0 381 0.0 %
Date: 2016-12-06 Branches: 0 401 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: fstat.c,v 1.88 2016/05/04 19:48:08 jca Exp $	*/
2
3
/*
4
 * Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
/*-
20
 * Copyright (c) 1988, 1993
21
 *	The Regents of the University of California.  All rights reserved.
22
 *
23
 * Redistribution and use in source and binary forms, with or without
24
 * modification, are permitted provided that the following conditions
25
 * are met:
26
 * 1. Redistributions of source code must retain the above copyright
27
 *    notice, this list of conditions and the following disclaimer.
28
 * 2. Redistributions in binary form must reproduce the above copyright
29
 *    notice, this list of conditions and the following disclaimer in the
30
 *    documentation and/or other materials provided with the distribution.
31
 * 3. Neither the name of the University nor the names of its contributors
32
 *    may be used to endorse or promote products derived from this software
33
 *    without specific prior written permission.
34
 *
35
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45
 * SUCH DAMAGE.
46
 */
47
48
#include <sys/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
#define _KERNEL /* for DTYPE_* */
58
#include <sys/file.h>
59
#undef _KERNEL
60
61
#include <net/route.h>
62
#include <netinet/in.h>
63
64
#include <netdb.h>
65
#include <arpa/inet.h>
66
67
#include <sys/pipe.h>
68
69
#include <ctype.h>
70
#include <errno.h>
71
#include <fcntl.h>
72
#include <kvm.h>
73
#include <limits.h>
74
#include <nlist.h>
75
#include <pwd.h>
76
#include <search.h>
77
#include <signal.h>
78
#include <stdio.h>
79
#include <stdint.h>
80
#include <stdlib.h>
81
#include <string.h>
82
#include <unistd.h>
83
#include <err.h>
84
85
#include "fstat.h"
86
87
#define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
88
89
struct fileargs fileargs = SLIST_HEAD_INITIALIZER(fileargs);
90
91
int	fsflg;	/* show files on same filesystem as file(s) argument */
92
int	pflg;	/* show files open by a particular pid */
93
int	uflg;	/* show files open by a particular (effective) user */
94
int	checkfile; /* true if restricting to particular files or filesystems */
95
int	nflg;	/* (numerical) display f.s. and rdev as dev_t */
96
int	oflg;	/* display file offset */
97
int	sflg;	/* display file xfer/bytes counters */
98
int	vflg;	/* display errors in locating kernel data objects etc... */
99
int	cflg; 	/* fuser only */
100
101
int	fuser;	/* 1 if we are fuser, 0 if we are fstat */
102
int	signo;	/* signal to send (fuser only) */
103
104
kvm_t *kd;
105
uid_t uid;
106
107
void fstat_dofile(struct kinfo_file *);
108
void fstat_header(void);
109
void getinetproto(int);
110
__dead void usage(void);
111
int getfname(char *);
112
void kqueuetrans(struct kinfo_file *);
113
void pipetrans(struct kinfo_file *);
114
struct kinfo_file *splice_find(char, u_int64_t);
115
void splice_insert(char, u_int64_t, struct kinfo_file *);
116
void find_splices(struct kinfo_file *, int);
117
void print_inet_details(struct kinfo_file *);
118
void print_inet6_details(struct kinfo_file *);
119
void print_sock_details(struct kinfo_file *);
120
void socktrans(struct kinfo_file *);
121
void vtrans(struct kinfo_file *);
122
const char *inet6_addrstr(struct in6_addr *);
123
int signame_to_signum(char *);
124
void hide(void *p);
125
126
int hideroot;
127
128
void
129
hide(void *p)
130
{
131
	printf("%p", hideroot ? NULL : p);
132
}
133
134
int
135
main(int argc, char *argv[])
136
{
137
	struct passwd *passwd;
138
	struct kinfo_file *kf, *kflast;
139
	int arg, ch, what;
140
	char *memf, *nlistf, *optstr;
141
	char buf[_POSIX2_LINE_MAX];
142
	const char *errstr;
143
	int cnt, flags;
144
145
	hideroot = getuid();
146
147
	arg = -1;
148
	what = KERN_FILE_BYPID;
149
	nlistf = memf = NULL;
150
	oflg = 0;
151
152
	/* are we fstat(1) or fuser(1)? */
153
	if (strcmp(__progname, "fuser") == 0) {
154
		fuser = 1;
155
		optstr = "cfks:uM:N:";
156
	} else {
157
		fuser = 0;
158
		optstr = "fnop:su:vN:M:";
159
	}
160
161
	/*
162
	 * fuser and fstat share three flags: -f, -s and -u.  In both cases
163
	 * -f is a boolean, but for -u fstat wants an argument while fuser
164
	 * does not and for -s fuser wants an argument whereas fstat does not.
165
	 */
166
	while ((ch = getopt(argc, argv, optstr)) != -1)
167
		switch ((char)ch) {
168
		case 'c':
169
			if (fsflg)
170
				usage();
171
			cflg = 1;
172
			break;
173
		case 'f':
174
			if (cflg)
175
				usage();
176
			fsflg = 1;
177
			break;
178
		case 'k':
179
			sflg = 1;
180
			signo = SIGKILL;
181
			break;
182
		case 'M':
183
			memf = optarg;
184
			break;
185
		case 'N':
186
			nlistf = optarg;
187
			break;
188
		case 'n':
189
			nflg = 1;
190
			break;
191
		case 'o':
192
			oflg = 1;
193
			break;
194
		case 'p':
195
			if (pflg++)
196
				usage();
197
			arg = strtonum(optarg, 0, INT_MAX, &errstr);
198
			if (errstr != NULL) {
199
				warnx("-p requires a process id, %s: %s",
200
					errstr, optarg);
201
				usage();
202
			}
203
			what = KERN_FILE_BYPID;
204
			break;
205
		case 's':
206
			sflg = 1;
207
			if (fuser) {
208
				signo = signame_to_signum(optarg);
209
				if (signo == -1) {
210
					warnx("invalid signal %s", optarg);
211
					usage();
212
				}
213
			}
214
			break;
215
		case 'u':
216
			if (uflg++)
217
				usage();
218
			if (!fuser) {
219
				if (!(passwd = getpwnam(optarg))) {
220
					arg = strtonum(optarg, 0, UID_MAX,
221
					    &errstr);
222
					if (errstr != NULL) {
223
						errx(1, "%s: unknown uid",
224
						    optarg);
225
					}
226
				} else
227
					arg = passwd->pw_uid;
228
				what = KERN_FILE_BYUID;
229
			}
230
			break;
231
		case 'v':
232
			vflg = 1;
233
			break;
234
		default:
235
			usage();
236
		}
237
238
	/*
239
	 * get the uid, for oflg and sflg
240
	 */
241
	uid = getuid();
242
243
	/*
244
	 * Use sysctl unless inspecting an alternate kernel.
245
	 */
246
	if (nlistf == NULL || memf == NULL)
247
		flags = KVM_NO_FILES;
248
	else
249
		flags = O_RDONLY;
250
251
	if ((kd = kvm_openfiles(nlistf, memf, NULL, flags, buf)) == NULL)
252
		errx(1, "%s", buf);
253
254
	if (*(argv += optind)) {
255
		for (; *argv; ++argv) {
256
			if (getfname(*argv))
257
				checkfile = 1;
258
		}
259
		/* file(s) specified, but none accessible */
260
		if (!checkfile)
261
			exit(1);
262
	} else if (fuser)
263
		usage();
264
265
	if (!fuser && fsflg && !checkfile) {
266
		/* fstat -f with no files means use wd */
267
		if (getfname(".") == 0)
268
			exit(1);
269
		checkfile = 1;
270
	}
271
272
	if ((kf = kvm_getfiles(kd, what, arg, sizeof(*kf), &cnt)) == NULL)
273
		errx(1, "%s", kvm_geterr(kd));
274
275
	if (fuser) {
276
		/*
277
		 * fuser
278
		 *  uflg: need "getpw"
279
		 *  sflg: need "proc" (might call kill(2))
280
		 */
281
		if (uflg && sflg) {
282
			if (pledge("stdio rpath getpw proc wpath cpath", NULL) == -1)
283
				err(1, "pledge");
284
		} else if (uflg) {
285
			if (pledge("stdio rpath getpw wpath cpath", NULL) == -1)
286
				err(1, "pledge");
287
		} else if (sflg) {
288
			if (pledge("stdio rpath proc wpath cpath", NULL) == -1)
289
				err(1, "pledge");
290
		} else {
291
			if (pledge("stdio rpath wpath cpath", NULL) == -1)
292
				err(1, "pledge");
293
		}
294
	} else {
295
		/* fstat */
296
		if (pledge("stdio rpath getpw wpath cpath", NULL) == -1)
297
			err(1, "pledge");
298
	}
299
300
	find_splices(kf, cnt);
301
	if (!fuser)
302
		fstat_header();
303
	for (kflast = &kf[cnt]; kf < kflast; ++kf) {
304
		if (fuser)
305
			fuser_check(kf);
306
		else
307
			fstat_dofile(kf);
308
	}
309
	if (fuser)
310
		fuser_run();
311
312
	exit(0);
313
}
314
315
void
316
fstat_header(void)
317
{
318
	if (nflg)
319
		printf("%s",
320
"USER     CMD          PID   FD  DEV      INUM       MODE R/W    SZ|DV");
321
	else
322
		printf("%s",
323
"USER     CMD          PID   FD MOUNT        INUM MODE       R/W    SZ|DV");
324
	if (oflg)
325
		printf("%s", ":OFFSET  ");
326
	if (checkfile && fsflg == 0)
327
		printf(" NAME");
328
	if (sflg)
329
		printf("    XFERS   KBYTES");
330
	putchar('\n');
331
}
332
333
char	*Uname, *Comm;
334
uid_t	*procuid;
335
pid_t	Pid;
336
337
#define PREFIX(i) do { \
338
	printf("%-8.8s %-10s %5ld", Uname, Comm, (long)Pid); \
339
	switch (i) { \
340
	case KERN_FILE_TEXT: \
341
		printf(" text"); \
342
		break; \
343
	case KERN_FILE_CDIR: \
344
		printf("   wd"); \
345
		break; \
346
	case KERN_FILE_RDIR: \
347
		printf(" root"); \
348
		break; \
349
	case KERN_FILE_TRACE: \
350
		printf("   tr"); \
351
		break; \
352
	default: \
353
		printf(" %4d", i); \
354
		break; \
355
	} \
356
} while (0)
357
358
/*
359
 * print open files attributed to this process
360
 */
361
void
362
fstat_dofile(struct kinfo_file *kf)
363
{
364
365
	Uname = user_from_uid(kf->p_uid, 0);
366
	procuid = &kf->p_uid;
367
	Pid = kf->p_pid;
368
	Comm = kf->p_comm;
369
370
	switch (kf->f_type) {
371
	case DTYPE_VNODE:
372
		vtrans(kf);
373
		break;
374
	case DTYPE_SOCKET:
375
		if (checkfile == 0)
376
			socktrans(kf);
377
		break;
378
	case DTYPE_PIPE:
379
		if (checkfile == 0)
380
			pipetrans(kf);
381
		break;
382
	case DTYPE_KQUEUE:
383
		if (checkfile == 0)
384
			kqueuetrans(kf);
385
		break;
386
	default:
387
		if (vflg) {
388
			warnx("unknown file type %d for file %d of pid %ld",
389
			    kf->f_type, kf->fd_fd, (long)Pid);
390
		}
391
		break;
392
	}
393
}
394
395
void
396
vtrans(struct kinfo_file *kf)
397
{
398
	const char *badtype = NULL;
399
	char rw[3], mode[12];
400
	char *filename = NULL;
401
402
	if (kf->v_type == VNON)
403
		badtype = "none";
404
	else if (kf->v_type == VBAD)
405
		badtype = "bad";
406
	else if (kf->v_tag == VT_NON && !(kf->v_flag & VCLONE))
407
		badtype = "none";	/* not a clone */
408
409
	if (checkfile) {
410
		int fsmatch = 0;
411
		struct filearg *fa;
412
413
		if (badtype)
414
			return;
415
		SLIST_FOREACH(fa, &fileargs, next) {
416
			if (fa->dev == kf->va_fsid) {
417
				fsmatch = 1;
418
				if (fa->ino == kf->va_fileid) {
419
					filename = fa->name;
420
					break;
421
				}
422
			}
423
		}
424
		if (fsmatch == 0 || (filename == NULL && fsflg == 0))
425
			return;
426
	}
427
	PREFIX(kf->fd_fd);
428
	if (badtype) {
429
		(void)printf(" -           -  %10s    -\n", badtype);
430
		return;
431
	}
432
433
	if (nflg)
434
		(void)printf(" %2ld,%-2ld", (long)major(kf->va_fsid),
435
		    (long)minor(kf->va_fsid));
436
	else if (!(kf->v_flag & VCLONE))
437
		(void)printf(" %-8s", kf->f_mntonname);
438
	else
439
		(void)printf(" clone   ");
440
	if (nflg)
441
		(void)snprintf(mode, sizeof(mode), "%o", kf->va_mode);
442
	else
443
		strmode(kf->va_mode, mode);
444
	printf(" %8llu %11s", kf->va_fileid, mode);
445
	rw[0] = '\0';
446
	if (kf->f_flag & FREAD)
447
		strlcat(rw, "r", sizeof rw);
448
	if (kf->f_flag & FWRITE)
449
		strlcat(rw, "w", sizeof rw);
450
	printf(" %2s", rw);
451
	switch (kf->v_type) {
452
	case VBLK:
453
	case VCHR: {
454
		char *name;
455
456
		if (nflg || ((name = devname(kf->va_rdev,
457
		    kf->v_type == VCHR ?  S_IFCHR : S_IFBLK)) == NULL))
458
			printf("   %2d,%-3d", major(kf->va_rdev), minor(kf->va_rdev));
459
		else
460
			printf("  %7s", name);
461
		if (oflg)
462
			printf("         ");
463
		break;
464
	}
465
	default:
466
		printf(" %8llu", kf->va_size);
467
		if (oflg) {
468
			if (uid == 0 || uid == *procuid)
469
				printf(":%-8llu", kf->f_offset);
470
			else
471
				printf(":%-8s", "*");
472
		}
473
	}
474
	if (sflg) {
475
		if (uid == 0 || uid == *procuid) {
476
			printf(" %8llu %8llu",
477
			    (kf->f_rxfer + kf->f_rwfer),
478
			    (kf->f_rbytes + kf->f_wbytes) / 1024);
479
		} else {
480
			printf(" %8s %8s", "*", "*");
481
		}
482
	}
483
	if (filename && !fsflg)
484
		printf(" %s", filename);
485
	putchar('\n');
486
}
487
488
void
489
pipetrans(struct kinfo_file *kf)
490
{
491
	void *maxaddr;
492
493
	PREFIX(kf->fd_fd);
494
495
	printf(" ");
496
497
	/*
498
	 * We don't have enough space to fit both peer and own address, so
499
	 * we select the higher address so both ends of the pipe have the
500
	 * same visible addr. (it's the higher address because when the other
501
	 * end closes, it becomes 0)
502
	 */
503
	maxaddr = (void *)(uintptr_t)MAXIMUM(kf->f_data, kf->pipe_peer);
504
505
	printf("pipe ");
506
	hide(maxaddr);
507
	printf(" state: %s%s%s",
508
	    (kf->pipe_state & PIPE_WANTR) ? "R" : "",
509
	    (kf->pipe_state & PIPE_WANTW) ? "W" : "",
510
	    (kf->pipe_state & PIPE_EOF) ? "E" : "");
511
	if (sflg)
512
		printf("\t%8llu %8llu",
513
		    (kf->f_rxfer + kf->f_rwfer),
514
		    (kf->f_rbytes + kf->f_wbytes) / 1024);
515
	printf("\n");
516
	return;
517
}
518
519
void
520
kqueuetrans(struct kinfo_file *kf)
521
{
522
	PREFIX(kf->fd_fd);
523
524
	printf(" ");
525
526
	printf("kqueue ");
527
	hide((void *)(uintptr_t)kf->f_data);
528
	printf(" %d state: %s%s\n",
529
	    kf->kq_count,
530
	    (kf->kq_state & KQ_SEL) ? "S" : "",
531
	    (kf->kq_state & KQ_SLEEP) ? "W" : "");
532
	return;
533
}
534
535
const char *
536
inet6_addrstr(struct in6_addr *p)
537
{
538
	struct sockaddr_in6 sin6;
539
	static char hbuf[NI_MAXHOST];
540
	const int niflags = NI_NUMERICHOST;
541
542
	memset(&sin6, 0, sizeof(sin6));
543
	sin6.sin6_family = AF_INET6;
544
	sin6.sin6_len = sizeof(struct sockaddr_in6);
545
	sin6.sin6_addr = *p;
546
	if (IN6_IS_ADDR_LINKLOCAL(p) &&
547
	    *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) {
548
		sin6.sin6_scope_id =
549
		    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
550
		sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0;
551
	}
552
553
	if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
554
	    hbuf, sizeof(hbuf), NULL, 0, niflags))
555
		return "invalid";
556
557
	return hbuf;
558
}
559
560
void
561
splice_insert(char type, u_int64_t ptr, struct kinfo_file *data)
562
{
563
	ENTRY entry, *found;
564
565
	if (asprintf(&entry.key, "%c%llx", type, hideroot ? 0 : ptr) == -1)
566
		err(1, NULL);
567
	entry.data = data;
568
	if ((found = hsearch(entry, ENTER)) == NULL)
569
		err(1, "hsearch");
570
	/* if it's ambiguous, set the data to NULL */
571
	if (found->data != data)
572
		found->data = NULL;
573
}
574
575
struct kinfo_file *
576
splice_find(char type, u_int64_t ptr)
577
{
578
	ENTRY entry, *found;
579
	char buf[20];
580
581
	snprintf(buf, sizeof(buf), "%c%llx", type, hideroot ? 0 : ptr);
582
	entry.key = buf;
583
	found = hsearch(entry, FIND);
584
	return (found != NULL ? found->data : NULL);
585
}
586
587
void
588
find_splices(struct kinfo_file *kf, int cnt)
589
{
590
	int i, created;
591
592
	created = 0;
593
	for (i = 0; i < cnt; i++) {
594
		if (kf[i].f_type != DTYPE_SOCKET ||
595
		    (kf[i].so_splice == 0 && kf[i].so_splicelen != -1))
596
			continue;
597
		if (created++ == 0) {
598
			if (hcreate(1000) == 0)
599
				err(1, "hcreate");
600
		}
601
		splice_insert('>', kf[i].f_data, &kf[i]);
602
		if (kf[i].so_splice != 0)
603
			splice_insert('<', kf[i].so_splice, &kf[i]);
604
	}
605
}
606
607
void
608
print_inet_details(struct kinfo_file *kf)
609
{
610
	struct in_addr laddr, faddr;
611
612
	memcpy(&laddr, kf->inp_laddru, sizeof(laddr));
613
	memcpy(&faddr, kf->inp_faddru, sizeof(faddr));
614
	if (kf->so_protocol == IPPROTO_TCP) {
615
		printf(" ");
616
		hide((void *)(uintptr_t)kf->inp_ppcb);
617
		printf(" %s:%d", laddr.s_addr == INADDR_ANY ? "*" :
618
		    inet_ntoa(laddr), ntohs(kf->inp_lport));
619
		if (kf->inp_fport) {
620
			if (kf->so_state & SS_CONNECTOUT)
621
				printf(" --> ");
622
			else
623
				printf(" <-- ");
624
			printf("%s:%d",
625
			    faddr.s_addr == INADDR_ANY ? "*" :
626
			    inet_ntoa(faddr), ntohs(kf->inp_fport));
627
		}
628
	} else if (kf->so_protocol == IPPROTO_UDP) {
629
		printf(" %s:%d", laddr.s_addr == INADDR_ANY ? "*" :
630
		    inet_ntoa(laddr), ntohs(kf->inp_lport));
631
		if (kf->inp_fport) {
632
			printf(" <-> %s:%d",
633
			    faddr.s_addr == INADDR_ANY ? "*" :
634
			    inet_ntoa(faddr), ntohs(kf->inp_fport));
635
		}
636
	} else if (kf->so_pcb) {
637
		printf(" ");
638
		hide((void *)(uintptr_t)kf->so_pcb);
639
	}
640
}
641
642
void
643
print_inet6_details(struct kinfo_file *kf)
644
{
645
	char xaddrbuf[NI_MAXHOST + 2];
646
	struct in6_addr laddr6, faddr6;
647
648
	memcpy(&laddr6, kf->inp_laddru, sizeof(laddr6));
649
	memcpy(&faddr6, kf->inp_faddru, sizeof(faddr6));
650
	if (kf->so_protocol == IPPROTO_TCP) {
651
		printf(" ");
652
		hide((void *)(uintptr_t)kf->inp_ppcb);
653
		snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
654
		    inet6_addrstr(&laddr6));
655
		printf(" %s:%d",
656
		    IN6_IS_ADDR_UNSPECIFIED(&laddr6) ? "*" :
657
		    xaddrbuf, ntohs(kf->inp_lport));
658
		if (kf->inp_fport) {
659
			if (kf->so_state & SS_CONNECTOUT)
660
				printf(" --> ");
661
			else
662
				printf(" <-- ");
663
			snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
664
			    inet6_addrstr(&faddr6));
665
			printf("%s:%d",
666
			    IN6_IS_ADDR_UNSPECIFIED(&faddr6) ? "*" :
667
			    xaddrbuf, ntohs(kf->inp_fport));
668
		}
669
	} else if (kf->so_protocol == IPPROTO_UDP) {
670
		snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
671
		    inet6_addrstr(&laddr6));
672
		printf(" %s:%d",
673
		    IN6_IS_ADDR_UNSPECIFIED(&laddr6) ? "*" :
674
		    xaddrbuf, ntohs(kf->inp_lport));
675
		if (kf->inp_fport) {
676
			snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
677
			    inet6_addrstr(&faddr6));
678
			printf(" <-> %s:%d",
679
			    IN6_IS_ADDR_UNSPECIFIED(&faddr6) ? "*" :
680
			    xaddrbuf, ntohs(kf->inp_fport));
681
		}
682
	} else if (kf->so_pcb) {
683
		printf(" ");
684
		hide((void *)(uintptr_t)kf->so_pcb);
685
	}
686
}
687
688
void
689
print_sock_details(struct kinfo_file *kf)
690
{
691
	if (kf->so_family == AF_INET)
692
		print_inet_details(kf);
693
	else if (kf->so_family == AF_INET6)
694
		print_inet6_details(kf);
695
}
696
697
void
698
socktrans(struct kinfo_file *kf)
699
{
700
	static char *stypename[] = {
701
		"unused",	/* 0 */
702
		"stream",	/* 1 */
703
		"dgram",	/* 2 */
704
		"raw",		/* 3 */
705
		"rdm",		/* 4 */
706
		"seqpak"	/* 5 */
707
	};
708
#define	STYPEMAX 5
709
	char *stype, stypebuf[24];
710
711
	PREFIX(kf->fd_fd);
712
713
	if (kf->so_type > STYPEMAX) {
714
		snprintf(stypebuf, sizeof(stypebuf), "?%d", kf->so_type);
715
		stype = stypebuf;
716
	} else {
717
		stype = stypename[kf->so_type];
718
	}
719
720
	/*
721
	 * protocol specific formatting
722
	 *
723
	 * Try to find interesting things to print.  For tcp, the interesting
724
	 * thing is the address of the tcpcb, for udp and others, just the
725
	 * inpcb (socket pcb).  For unix domain, its the address of the socket
726
	 * pcb and the address of the connected pcb (if connected).  Otherwise
727
	 * just print the protocol number and address of the socket itself.
728
	 * The idea is not to duplicate netstat, but to make available enough
729
	 * information for further analysis.
730
	 */
731
	switch (kf->so_family) {
732
	case AF_INET:
733
		printf("* internet %s", stype);
734
		getinetproto(kf->so_protocol);
735
		print_inet_details(kf);
736
		break;
737
	case AF_INET6:
738
		printf("* internet6 %s", stype);
739
		getinetproto(kf->so_protocol);
740
		print_inet6_details(kf);
741
		break;
742
	case AF_UNIX:
743
		/* print address of pcb and connected pcb */
744
		printf("* unix %s", stype);
745
		if (kf->so_pcb) {
746
			printf(" ");
747
			hide((void *)(uintptr_t)kf->so_pcb);
748
			if (kf->unp_conn) {
749
				char shoconn[4], *cp;
750
751
				cp = shoconn;
752
				if (!(kf->so_state & SS_CANTRCVMORE))
753
					*cp++ = '<';
754
				*cp++ = '-';
755
				if (!(kf->so_state & SS_CANTSENDMORE))
756
					*cp++ = '>';
757
				*cp = '\0';
758
				printf(" %s ", shoconn);
759
				hide((void *)(uintptr_t)kf->unp_conn);
760
			}
761
		}
762
		break;
763
	case AF_MPLS:
764
		/* print protocol number and socket address */
765
		printf("* mpls %s", stype);
766
		printf(" %d ", kf->so_protocol);
767
		hide((void *)(uintptr_t)kf->f_data);
768
		break;
769
	case AF_ROUTE:
770
		/* print protocol number and socket address */
771
		printf("* route %s", stype);
772
		printf(" %d ", kf->so_protocol);
773
		hide((void *)(uintptr_t)kf->f_data);
774
		break;
775
	default:
776
		/* print protocol number and socket address */
777
		printf("* %d %s", kf->so_family, stype);
778
		printf(" %d ", kf->so_protocol);
779
		hide((void *)(uintptr_t)kf->f_data);
780
	}
781
	if (kf->so_splice != 0 || kf->so_splicelen == -1) {
782
		struct kinfo_file *from, *to;
783
784
		from = splice_find('<', kf->f_data);
785
		to = NULL;
786
		if (kf->so_splice != 0)
787
			to = splice_find('>', kf->so_splice);
788
789
		if (to != NULL && from == to) {
790
			printf(" <==>");
791
			print_sock_details(to);
792
		} else if (kf->so_splice != 0) {
793
			printf(" ==>");
794
			if (to != NULL)
795
				print_sock_details(to);
796
		} else if (kf->so_splicelen == -1) {
797
			printf(" <==");
798
			if (from != NULL)
799
				print_sock_details(from);
800
		}
801
	}
802
	if (sflg)
803
		printf("\t%8llu %8llu",
804
		    (kf->f_rxfer + kf->f_rwfer),
805
		    (kf->f_rbytes + kf->f_wbytes) / 1024);
806
	printf("\n");
807
}
808
809
/*
810
 * getinetproto --
811
 *	print name of protocol number
812
 */
813
void
814
getinetproto(int number)
815
{
816
	static int isopen;
817
	struct protoent *pe;
818
819
	if (!isopen)
820
		setprotoent(++isopen);
821
	if ((pe = getprotobynumber(number)) != NULL)
822
		printf(" %s", pe->p_name);
823
	else
824
		printf(" %d", number);
825
}
826
827
int
828
getfname(char *filename)
829
{
830
	static struct statfs *mntbuf;
831
	static int nmounts;
832
	int i;
833
	struct stat sb;
834
	struct filearg *cur;
835
836
	if (stat(filename, &sb)) {
837
		warn("%s", filename);
838
		return (0);
839
	}
840
841
	/*
842
	 * POSIX specifies "For block special devices, all processes using any
843
	 * file on that device are listed".  However the -f flag description
844
	 * states "The report shall be only for the named files", so we only
845
	 * look up a block device if the -f flag has not be specified.
846
	 */
847
	if (fuser && !fsflg && S_ISBLK(sb.st_mode)) {
848
		if (mntbuf == NULL) {
849
			nmounts = getmntinfo(&mntbuf, MNT_NOWAIT);
850
			if (nmounts == -1)
851
				err(1, "getmntinfo");
852
		}
853
		for (i = 0; i < nmounts; i++) {
854
			if (!strcmp(mntbuf[i].f_mntfromname, filename)) {
855
				if (stat(mntbuf[i].f_mntonname, &sb) == -1) {
856
					warn("%s", filename);
857
					return (0);
858
				}
859
				cflg = 1;
860
				break;
861
			}
862
		}
863
	}
864
865
	if ((cur = malloc(sizeof(*cur))) == NULL)
866
		err(1, NULL);
867
868
	cur->ino = sb.st_ino;
869
	cur->dev = sb.st_dev & 0xffff;
870
	cur->name = filename;
871
	TAILQ_INIT(&cur->fusers);
872
	SLIST_INSERT_HEAD(&fileargs, cur, next);
873
	return (1);
874
}
875
876
int
877
signame_to_signum(char *sig)
878
{
879
	int n;
880
	const char *errstr = NULL;
881
882
	if (isdigit((unsigned char)*sig)) {
883
		n = strtonum(sig, 0, NSIG - 1, &errstr);
884
		return (errstr ? -1 : n);
885
	}
886
	if (!strncasecmp(sig, "sig", 3))
887
		sig += 3;
888
	for (n = 1; n < NSIG; n++) {
889
		if (!strcasecmp(sys_signame[n], sig))
890
			return (n);
891
	}
892
	return (-1);
893
}
894
895
void
896
usage(void)
897
{
898
	if (fuser) {
899
		fprintf(stderr, "usage: fuser [-cfku] [-M core] "
900
		    "[-N system] [-s signal] file ...\n");
901
	} else {
902
		fprintf(stderr, "usage: fstat [-fnosv] [-M core] [-N system] "
903
		    "[-p pid] [-u user] [file ...]\n");
904
	}
905
	exit(1);
906
}