GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/fstat/fstat.c Lines: 222 432 51.4 %
Date: 2017-11-07 Branches: 129 355 36.3 %

Line Branch Exec Source
1
/*	$OpenBSD: fstat.c,v 1.90 2017/01/21 12:21:57 deraadt 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
#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.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))
89
90
struct fileargs fileargs = SLIST_HEAD_INITIALIZER(fileargs);
91
92
int	fsflg;	/* show files on same filesystem as file(s) argument */
93
int	pflg;	/* show files open by a particular pid */
94
int	uflg;	/* show files open by a particular (effective) user */
95
int	checkfile; /* true if restricting to particular files or filesystems */
96
int	nflg;	/* (numerical) display f.s. and rdev as dev_t */
97
int	oflg;	/* display file offset */
98
int	sflg;	/* display file xfer/bytes counters */
99
int	vflg;	/* display errors in locating kernel data objects etc... */
100
int	cflg; 	/* fuser only */
101
102
int	fuser;	/* 1 if we are fuser, 0 if we are fstat */
103
int	signo;	/* signal to send (fuser only) */
104
105
kvm_t *kd;
106
uid_t uid;
107
108
void fstat_dofile(struct kinfo_file *);
109
void fstat_header(void);
110
void getinetproto(int);
111
__dead void usage(void);
112
int getfname(char *);
113
void kqueuetrans(struct kinfo_file *);
114
void pipetrans(struct kinfo_file *);
115
struct kinfo_file *splice_find(char, u_int64_t);
116
void splice_insert(char, u_int64_t, struct kinfo_file *);
117
void find_splices(struct kinfo_file *, int);
118
void print_inet_details(struct kinfo_file *);
119
void print_inet6_details(struct kinfo_file *);
120
void print_sock_details(struct kinfo_file *);
121
void socktrans(struct kinfo_file *);
122
void vtrans(struct kinfo_file *);
123
const char *inet6_addrstr(struct in6_addr *);
124
int signame_to_signum(char *);
125
void hide(void *p);
126
127
int hideroot;
128
129
void
130
hide(void *p)
131
{
132
107476
	printf("%p", hideroot ? NULL : p);
133
53738
}
134
135
int
136
main(int argc, char *argv[])
137
{
138
	struct passwd *passwd;
139
	struct kinfo_file *kf, *kflast;
140
	int arg, ch, what;
141
	char *memf, *nlistf, *optstr;
142
642
	char buf[_POSIX2_LINE_MAX];
143
321
	const char *errstr;
144
321
	int cnt, flags;
145
146
321
	hideroot = getuid();
147
148
	arg = -1;
149
	what = KERN_FILE_BYPID;
150
	nlistf = memf = NULL;
151
321
	oflg = 0;
152
153
	/* are we fstat(1) or fuser(1)? */
154
321
	if (strcmp(__progname, "fuser") == 0) {
155
		fuser = 1;
156
		optstr = "cfks:uM:N:";
157
	} else {
158
321
		fuser = 0;
159
		optstr = "fnop:su:vN:M:";
160
	}
161
162
	/*
163
	 * fuser and fstat share three flags: -f, -s and -u.  In both cases
164
	 * -f is a boolean, but for -u fstat wants an argument while fuser
165
	 * does not and for -s fuser wants an argument whereas fstat does not.
166
	 */
167
321
	while ((ch = getopt(argc, argv, optstr)) != -1)
168
		switch ((char)ch) {
169
		case 'c':
170
			if (fsflg)
171
				usage();
172
			cflg = 1;
173
			break;
174
		case 'f':
175
			if (cflg)
176
				usage();
177
			fsflg = 1;
178
			break;
179
		case 'k':
180
			sflg = 1;
181
			signo = SIGKILL;
182
			break;
183
		case 'M':
184
			memf = optarg;
185
			break;
186
		case 'N':
187
			nlistf = optarg;
188
			break;
189
		case 'n':
190
			nflg = 1;
191
			break;
192
		case 'o':
193
			oflg = 1;
194
			break;
195
		case 'p':
196
			if (pflg++)
197
				usage();
198
			arg = strtonum(optarg, 0, INT_MAX, &errstr);
199
			if (errstr != NULL) {
200
				warnx("-p requires a process id, %s: %s",
201
					errstr, optarg);
202
				usage();
203
			}
204
			what = KERN_FILE_BYPID;
205
			break;
206
		case 's':
207
			sflg = 1;
208
			if (fuser) {
209
				signo = signame_to_signum(optarg);
210
				if (signo == -1) {
211
					warnx("invalid signal %s", optarg);
212
					usage();
213
				}
214
			}
215
			break;
216
		case 'u':
217
			if (uflg++)
218
				usage();
219
			if (!fuser) {
220
				if (!(passwd = getpwnam(optarg))) {
221
					arg = strtonum(optarg, 0, UID_MAX,
222
					    &errstr);
223
					if (errstr != NULL) {
224
						errx(1, "%s: unknown uid",
225
						    optarg);
226
					}
227
				} else
228
					arg = passwd->pw_uid;
229
				what = KERN_FILE_BYUID;
230
			}
231
			break;
232
		case 'v':
233
			vflg = 1;
234
			break;
235
		default:
236
			usage();
237
		}
238
239
	/*
240
	 * get the uid, for oflg and sflg
241
	 */
242
321
	uid = getuid();
243
244
	/*
245
	 * Use sysctl unless inspecting an alternate kernel.
246
	 */
247
321
	if (nlistf == NULL || memf == NULL)
248
321
		flags = KVM_NO_FILES;
249
	else
250
		flags = O_RDONLY;
251
252
321
	if ((kd = kvm_openfiles(nlistf, memf, NULL, flags, buf)) == NULL)
253
		errx(1, "%s", buf);
254
255
321
	if (*(argv += optind)) {
256
		for (; *argv; ++argv) {
257
			if (getfname(*argv))
258
				checkfile = 1;
259
		}
260
		/* file(s) specified, but none accessible */
261
		if (!checkfile)
262
			exit(1);
263
321
	} else if (fuser)
264
		usage();
265
266
321
	if (!fuser && fsflg && !checkfile) {
267
		/* fstat -f with no files means use wd */
268
		if (getfname(".") == 0)
269
			exit(1);
270
		checkfile = 1;
271
	}
272
273
321
	if ((kf = kvm_getfiles(kd, what, arg, sizeof(*kf), &cnt)) == NULL)
274
		errx(1, "%s", kvm_geterr(kd));
275
276
321
	if (fuser) {
277
		/*
278
		 * fuser
279
		 *  uflg: need "getpw"
280
		 *  sflg: need "proc" (might call kill(2))
281
		 */
282
		if (uflg && sflg) {
283
			if (pledge("stdio rpath getpw proc flock cpath wpath", NULL) == -1)
284
				err(1, "pledge");
285
		} else if (uflg) {
286
			if (pledge("stdio rpath getpw flock cpath wpath", NULL) == -1)
287
				err(1, "pledge");
288
		} else if (sflg) {
289
			if (pledge("stdio rpath proc flock cpath wpath", NULL) == -1)
290
				err(1, "pledge");
291
		} else {
292
			if (pledge("stdio rpath flock cpath wpath", NULL) == -1)
293
				err(1, "pledge");
294
		}
295
	} else {
296
		/* fstat */
297
321
		if (pledge("stdio rpath getpw flock cpath wpath", NULL) == -1)
298
			err(1, "pledge");
299
	}
300
301
321
	find_splices(kf, cnt);
302
321
	if (!fuser)
303
321
		fstat_header();
304
256582
	for (kflast = &kf[cnt]; kf < kflast; ++kf) {
305
127970
		if (fuser)
306
			fuser_check(kf);
307
		else
308
127970
			fstat_dofile(kf);
309
	}
310
321
	if (fuser)
311
		fuser_run();
312
313
	exit(0);
314
}
315
316
void
317
fstat_header(void)
318
{
319
642
	if (nflg)
320
		printf("%s",
321
"USER     CMD          PID   FD  DEV      INUM       MODE   R/W    SZ|DV");
322
	else
323
321
		printf("%s",
324
"USER     CMD          PID   FD MOUNT        INUM MODE         R/W    SZ|DV");
325
321
	if (oflg)
326
		printf("%s", ":OFFSET  ");
327
321
	if (checkfile && fsflg == 0)
328
		printf(" NAME");
329
321
	if (sflg)
330
		printf("    XFERS   KBYTES");
331
642
	putchar('\n');
332
321
}
333
334
char	*Uname, *Comm;
335
uid_t	*procuid;
336
pid_t	Pid;
337
338
#define PREFIX(i) do { \
339
	printf("%-8.8s %-10s %5ld", Uname, Comm, (long)Pid); \
340
	switch (i) { \
341
	case KERN_FILE_TEXT: \
342
		printf(" text"); \
343
		break; \
344
	case KERN_FILE_CDIR: \
345
		printf("   wd"); \
346
		break; \
347
	case KERN_FILE_RDIR: \
348
		printf(" root"); \
349
		break; \
350
	case KERN_FILE_TRACE: \
351
		printf("   tr"); \
352
		break; \
353
	default: \
354
		printf(" %4d", i); \
355
		break; \
356
	} \
357
} while (0)
358
359
/*
360
 * print open files attributed to this process
361
 */
362
void
363
fstat_dofile(struct kinfo_file *kf)
364
{
365
366
255940
	Uname = user_from_uid(kf->p_uid, 0);
367
127970
	procuid = &kf->p_uid;
368
127970
	Pid = kf->p_pid;
369
127970
	Comm = kf->p_comm;
370
371

127970
	switch (kf->f_type) {
372
	case DTYPE_VNODE:
373
91162
		vtrans(kf);
374
91162
		break;
375
	case DTYPE_SOCKET:
376
27016
		if (checkfile == 0)
377
27016
			socktrans(kf);
378
		break;
379
	case DTYPE_PIPE:
380
5619
		if (checkfile == 0)
381
5619
			pipetrans(kf);
382
		break;
383
	case DTYPE_KQUEUE:
384
4173
		if (checkfile == 0)
385
4173
			kqueuetrans(kf);
386
		break;
387
	default:
388
		if (vflg) {
389
			warnx("unknown file type %d for file %d of pid %ld",
390
			    kf->f_type, kf->fd_fd, (long)Pid);
391
		}
392
		break;
393
	}
394
127970
}
395
396
void
397
vtrans(struct kinfo_file *kf)
398
{
399
	const char *badtype = NULL;
400
182324
	char rwep[5], mode[12];
401
	char *filename = NULL;
402
403
91162
	if (kf->v_type == VNON)
404
		badtype = "none";
405
91162
	else if (kf->v_type == VBAD)
406
		badtype = "bad";
407

92125
	else if (kf->v_tag == VT_NON && !(kf->v_flag & VCLONE))
408
		badtype = "none";	/* not a clone */
409
410
91162
	if (checkfile) {
411
		int fsmatch = 0;
412
		struct filearg *fa;
413
414
		if (badtype)
415
			return;
416
		SLIST_FOREACH(fa, &fileargs, next) {
417
			if (fa->dev == kf->va_fsid) {
418
				fsmatch = 1;
419
				if (fa->ino == kf->va_fileid) {
420
					filename = fa->name;
421
					break;
422
				}
423
			}
424
		}
425
		if (fsmatch == 0 || (filename == NULL && fsflg == 0))
426
			return;
427
	}
428

182324
	PREFIX(kf->fd_fd);
429
91162
	if (badtype) {
430
		(void)printf(" -           -  %10s    -\n", badtype);
431
		return;
432
	}
433
434
91162
	if (nflg)
435
		(void)printf(" %2ld,%-2ld", (long)major(kf->va_fsid),
436
		    (long)minor(kf->va_fsid));
437
91162
	else if (!(kf->v_flag & VCLONE))
438
90199
		(void)printf(" %-8s", kf->f_mntonname);
439
	else
440
963
		(void)printf(" clone   ");
441
91162
	if (nflg)
442
		(void)snprintf(mode, sizeof(mode), "%o", kf->va_mode);
443
	else
444
91162
		strmode(kf->va_mode, mode);
445
182324
	printf(" %8llu%s %11s", kf->va_fileid,
446
91162
	    kf->va_nlink == 0 ? "*" : " ",
447
91162
	    mode);
448
91162
	rwep[0] = '\0';
449
91162
	if (kf->f_flag & FREAD)
450
84052
		strlcat(rwep, "r", sizeof rwep);
451
91162
	if (kf->f_flag & FWRITE)
452
55391
		strlcat(rwep, "w", sizeof rwep);
453
91162
	if (kf->fd_ofileflags & UF_EXCLOSE)
454
4756
		strlcat(rwep, "e", sizeof rwep);
455
91162
	printf(" %4s", rwep);
456
91162
	switch (kf->v_type) {
457
	case VBLK:
458
	case VCHR: {
459
		char *name;
460
461

192220
		if (nflg || ((name = devname(kf->va_rdev,
462
96110
		    kf->v_type == VCHR ?  S_IFCHR : S_IFBLK)) == NULL))
463
			printf("   %2d,%-3d", major(kf->va_rdev), minor(kf->va_rdev));
464
		else
465
48055
			printf("  %7s", name);
466
48055
		if (oflg)
467
			printf("         ");
468
		break;
469
	}
470
	default:
471
43107
		printf(" %8llu", kf->va_size);
472
43107
		if (oflg) {
473
			if (uid == 0 || uid == *procuid)
474
				printf(":%-8llu", kf->f_offset);
475
			else
476
				printf(":%-8s", "*");
477
		}
478
	}
479
91162
	if (sflg) {
480
		if (uid == 0 || uid == *procuid) {
481
			printf(" %8llu %8llu",
482
			    (kf->f_rxfer + kf->f_rwfer),
483
			    (kf->f_rbytes + kf->f_wbytes) / 1024);
484
		} else {
485
			printf(" %8s %8s", "*", "*");
486
		}
487
	}
488
91162
	if (filename && !fsflg)
489
		printf(" %s", filename);
490
182324
	putchar('\n');
491
182324
}
492
493
void
494
pipetrans(struct kinfo_file *kf)
495
{
496
	void *maxaddr;
497
498

16857
	PREFIX(kf->fd_fd);
499
500
5619
	printf(" ");
501
502
	/*
503
	 * We don't have enough space to fit both peer and own address, so
504
	 * we select the higher address so both ends of the pipe have the
505
	 * same visible addr. (it's the higher address because when the other
506
	 * end closes, it becomes 0)
507
	 */
508
5619
	maxaddr = (void *)(uintptr_t)MAXIMUM(kf->f_data, kf->pipe_peer);
509
510
5619
	printf("pipe ");
511
5619
	hide(maxaddr);
512
5619
	printf(" state: %s%s%s",
513
5619
	    (kf->pipe_state & PIPE_WANTR) ? "R" : "",
514
5619
	    (kf->pipe_state & PIPE_WANTW) ? "W" : "",
515
5619
	    (kf->pipe_state & PIPE_EOF) ? "E" : "");
516
5619
	if (sflg)
517
		printf("\t%8llu %8llu",
518
		    (kf->f_rxfer + kf->f_rwfer),
519
		    (kf->f_rbytes + kf->f_wbytes) / 1024);
520
5619
	printf("\n");
521
	return;
522
5619
}
523
524
void
525
kqueuetrans(struct kinfo_file *kf)
526
{
527

12519
	PREFIX(kf->fd_fd);
528
529
4173
	printf(" ");
530
531
4173
	printf("kqueue ");
532
4173
	hide((void *)(uintptr_t)kf->f_data);
533
4173
	printf(" %d state: %s%s\n",
534
4173
	    kf->kq_count,
535
4173
	    (kf->kq_state & KQ_SEL) ? "S" : "",
536
4173
	    (kf->kq_state & KQ_SLEEP) ? "W" : "");
537
4173
	return;
538
}
539
540
const char *
541
inet6_addrstr(struct in6_addr *p)
542
{
543
3662
	struct sockaddr_in6 sin6;
544
	static char hbuf[NI_MAXHOST];
545
	const int niflags = NI_NUMERICHOST;
546
547
1831
	memset(&sin6, 0, sizeof(sin6));
548
1831
	sin6.sin6_family = AF_INET6;
549
1831
	sin6.sin6_len = sizeof(struct sockaddr_in6);
550
1831
	sin6.sin6_addr = *p;
551

2473
	if (IN6_IS_ADDR_LINKLOCAL(p) &&
552
321
	    *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) {
553
321
		sin6.sin6_scope_id =
554
321
		    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
555
321
		sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0;
556
321
	}
557
558
1831
	if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
559
	    hbuf, sizeof(hbuf), NULL, 0, niflags))
560
		return "invalid";
561
562
1831
	return hbuf;
563
1831
}
564
565
void
566
splice_insert(char type, u_int64_t ptr, struct kinfo_file *data)
567
{
568
	ENTRY entry, *found;
569
570
	if (asprintf(&entry.key, "%c%llx", type, hideroot ? 0 : ptr) == -1)
571
		err(1, NULL);
572
	entry.data = data;
573
	if ((found = hsearch(entry, ENTER)) == NULL)
574
		err(1, "hsearch");
575
	/* if it's ambiguous, set the data to NULL */
576
	if (found->data != data)
577
		found->data = NULL;
578
}
579
580
struct kinfo_file *
581
splice_find(char type, u_int64_t ptr)
582
{
583
	ENTRY entry, *found;
584
	char buf[20];
585
586
	snprintf(buf, sizeof(buf), "%c%llx", type, hideroot ? 0 : ptr);
587
	entry.key = buf;
588
	found = hsearch(entry, FIND);
589
	return (found != NULL ? found->data : NULL);
590
}
591
592
void
593
find_splices(struct kinfo_file *kf, int cnt)
594
{
595
	int i, created;
596
597
	created = 0;
598
256903
	for (i = 0; i < cnt; i++) {
599

154986
		if (kf[i].f_type != DTYPE_SOCKET ||
600
54032
		    (kf[i].so_splice == 0 && kf[i].so_splicelen != -1))
601
			continue;
602
		if (created++ == 0) {
603
			if (hcreate(1000) == 0)
604
				err(1, "hcreate");
605
		}
606
		splice_insert('>', kf[i].f_data, &kf[i]);
607
		if (kf[i].so_splice != 0)
608
			splice_insert('<', kf[i].so_splice, &kf[i]);
609
	}
610
321
}
611
612
void
613
print_inet_details(struct kinfo_file *kf)
614
{
615
	struct in_addr laddr, faddr;
616
617
5250
	memcpy(&laddr, kf->inp_laddru, sizeof(laddr));
618
2625
	memcpy(&faddr, kf->inp_faddru, sizeof(faddr));
619
2625
	if (kf->so_protocol == IPPROTO_TCP) {
620
1267
		printf(" ");
621
1267
		hide((void *)(uintptr_t)kf->inp_ppcb);
622
4702
		printf(" %s:%d", laddr.s_addr == INADDR_ANY ? "*" :
623
2168
		    inet_ntoa(laddr), ntohs(kf->inp_lport));
624
1267
		if (kf->inp_fport) {
625
461
			if (kf->so_state & SS_CONNECTOUT)
626
70
				printf(" --> ");
627
			else
628
391
				printf(" <-- ");
629
461
			printf("%s:%d",
630
1383
			    faddr.s_addr == INADDR_ANY ? "*" :
631
922
			    inet_ntoa(faddr), ntohs(kf->inp_fport));
632
461
		}
633
1358
	} else if (kf->so_protocol == IPPROTO_UDP) {
634
3329
		printf(" %s:%d", laddr.s_addr == INADDR_ANY ? "*" :
635
1255
		    inet_ntoa(laddr), ntohs(kf->inp_lport));
636
1037
		if (kf->inp_fport) {
637
			printf(" <-> %s:%d",
638
			    faddr.s_addr == INADDR_ANY ? "*" :
639
			    inet_ntoa(faddr), ntohs(kf->inp_fport));
640
		}
641
321
	} else if (kf->so_pcb) {
642
321
		printf(" ");
643
321
		hide((void *)(uintptr_t)kf->so_pcb);
644
321
	}
645
2625
}
646
647
void
648
print_inet6_details(struct kinfo_file *kf)
649
{
650
4248
	char xaddrbuf[NI_MAXHOST + 2];
651
2124
	struct in6_addr laddr6, faddr6;
652
653
2124
	memcpy(&laddr6, kf->inp_laddru, sizeof(laddr6));
654
2124
	memcpy(&faddr6, kf->inp_faddru, sizeof(faddr6));
655
2124
	if (kf->so_protocol == IPPROTO_TCP) {
656
1040
		printf(" ");
657
1040
		hide((void *)(uintptr_t)kf->inp_ppcb);
658
2080
		snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
659
1040
		    inet6_addrstr(&laddr6));
660
1040
		printf(" %s:%d",
661


4956
		    IN6_IS_ADDR_UNSPECIFIED(&laddr6) ? "*" :
662
1040
		    xaddrbuf, ntohs(kf->inp_lport));
663
1040
		if (kf->inp_fport) {
664
28
			if (kf->so_state & SS_CONNECTOUT)
665
14
				printf(" --> ");
666
			else
667
14
				printf(" <-- ");
668
28
			snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
669
28
			    inet6_addrstr(&faddr6));
670
28
			printf("%s:%d",
671


168
			    IN6_IS_ADDR_UNSPECIFIED(&faddr6) ? "*" :
672
28
			    xaddrbuf, ntohs(kf->inp_fport));
673
28
		}
674
1084
	} else if (kf->so_protocol == IPPROTO_UDP) {
675
1526
		snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
676
763
		    inet6_addrstr(&laddr6));
677
763
		printf(" %s:%d",
678


3857
		    IN6_IS_ADDR_UNSPECIFIED(&laddr6) ? "*" :
679
763
		    xaddrbuf, ntohs(kf->inp_lport));
680
763
		if (kf->inp_fport) {
681
			snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
682
			    inet6_addrstr(&faddr6));
683
			printf(" <-> %s:%d",
684
			    IN6_IS_ADDR_UNSPECIFIED(&faddr6) ? "*" :
685
			    xaddrbuf, ntohs(kf->inp_fport));
686
		}
687
321
	} else if (kf->so_pcb) {
688
321
		printf(" ");
689
321
		hide((void *)(uintptr_t)kf->so_pcb);
690
321
	}
691
2124
}
692
693
void
694
print_sock_details(struct kinfo_file *kf)
695
{
696
	if (kf->so_family == AF_INET)
697
		print_inet_details(kf);
698
	else if (kf->so_family == AF_INET6)
699
		print_inet6_details(kf);
700
}
701
702
void
703
socktrans(struct kinfo_file *kf)
704
{
705
	static char *stypename[] = {
706
		"unused",	/* 0 */
707
		"stream",	/* 1 */
708
		"dgram",	/* 2 */
709
		"raw",		/* 3 */
710
		"rdm",		/* 4 */
711
		"seqpak"	/* 5 */
712
	};
713
#define	STYPEMAX 5
714
54032
	char *stype, stypebuf[24];
715
716

54032
	PREFIX(kf->fd_fd);
717
718
27016
	if (kf->so_type > STYPEMAX) {
719
		snprintf(stypebuf, sizeof(stypebuf), "?%d", kf->so_type);
720
		stype = stypebuf;
721
	} else {
722
27016
		stype = stypename[kf->so_type];
723
	}
724
725
	/*
726
	 * protocol specific formatting
727
	 *
728
	 * Try to find interesting things to print.  For tcp, the interesting
729
	 * thing is the address of the tcpcb, for udp and others, just the
730
	 * inpcb (socket pcb).  For unix domain, its the address of the socket
731
	 * pcb and the address of the connected pcb (if connected).  Otherwise
732
	 * just print the protocol number and address of the socket itself.
733
	 * The idea is not to duplicate netstat, but to make available enough
734
	 * information for further analysis.
735
	 */
736

27016
	switch (kf->so_family) {
737
	case AF_INET:
738
2625
		printf("* internet %s", stype);
739
2625
		getinetproto(kf->so_protocol);
740
2625
		print_inet_details(kf);
741
2625
		break;
742
	case AF_INET6:
743
2124
		printf("* internet6 %s", stype);
744
2124
		getinetproto(kf->so_protocol);
745
2124
		print_inet6_details(kf);
746
2124
		break;
747
	case AF_UNIX:
748
		/* print address of pcb and connected pcb */
749
20983
		printf("* unix %s", stype);
750
20983
		if (kf->so_pcb) {
751
20983
			printf(" ");
752
20983
			hide((void *)(uintptr_t)kf->so_pcb);
753
20983
			if (kf->unp_conn) {
754
18730
				char shoconn[4], *cp;
755
756
18730
				cp = shoconn;
757
18730
				if (!(kf->so_state & SS_CANTRCVMORE))
758
18730
					*cp++ = '<';
759
18730
				*cp++ = '-';
760
18730
				if (!(kf->so_state & SS_CANTSENDMORE))
761
18730
					*cp++ = '>';
762
18730
				*cp = '\0';
763
18730
				printf(" %s ", shoconn);
764
18730
				hide((void *)(uintptr_t)kf->unp_conn);
765
18730
			}
766
		}
767
		break;
768
	case AF_MPLS:
769
		/* print protocol number and socket address */
770
		printf("* mpls %s", stype);
771
		printf(" %d ", kf->so_protocol);
772
		hide((void *)(uintptr_t)kf->f_data);
773
		break;
774
	case AF_ROUTE:
775
		/* print protocol number and socket address */
776
1284
		printf("* route %s", stype);
777
1284
		printf(" %d ", kf->so_protocol);
778
1284
		hide((void *)(uintptr_t)kf->f_data);
779
1284
		break;
780
	default:
781
		/* print protocol number and socket address */
782
		printf("* %d %s", kf->so_family, stype);
783
		printf(" %d ", kf->so_protocol);
784
		hide((void *)(uintptr_t)kf->f_data);
785
	}
786

54032
	if (kf->so_splice != 0 || kf->so_splicelen == -1) {
787
		struct kinfo_file *from, *to;
788
789
		from = splice_find('<', kf->f_data);
790
		to = NULL;
791
		if (kf->so_splice != 0)
792
			to = splice_find('>', kf->so_splice);
793
794
		if (to != NULL && from == to) {
795
			printf(" <==>");
796
			print_sock_details(to);
797
		} else if (kf->so_splice != 0) {
798
			printf(" ==>");
799
			if (to != NULL)
800
				print_sock_details(to);
801
		} else if (kf->so_splicelen == -1) {
802
			printf(" <==");
803
			if (from != NULL)
804
				print_sock_details(from);
805
		}
806
	}
807
27016
	if (sflg)
808
		printf("\t%8llu %8llu",
809
		    (kf->f_rxfer + kf->f_rwfer),
810
		    (kf->f_rbytes + kf->f_wbytes) / 1024);
811
27016
	printf("\n");
812
27016
}
813
814
/*
815
 * getinetproto --
816
 *	print name of protocol number
817
 */
818
void
819
getinetproto(int number)
820
{
821
	static int isopen;
822
	struct protoent *pe;
823
824
9498
	if (!isopen)
825
321
		setprotoent(++isopen);
826
4749
	if ((pe = getprotobynumber(number)) != NULL)
827
4749
		printf(" %s", pe->p_name);
828
	else
829
		printf(" %d", number);
830
4749
}
831
832
int
833
getfname(char *filename)
834
{
835
	static struct statfs *mntbuf;
836
	static int nmounts;
837
	int i;
838
	struct stat sb;
839
	struct filearg *cur;
840
841
	if (stat(filename, &sb)) {
842
		warn("%s", filename);
843
		return (0);
844
	}
845
846
	/*
847
	 * POSIX specifies "For block special devices, all processes using any
848
	 * file on that device are listed".  However the -f flag description
849
	 * states "The report shall be only for the named files", so we only
850
	 * look up a block device if the -f flag has not be specified.
851
	 */
852
	if (fuser && !fsflg && S_ISBLK(sb.st_mode)) {
853
		if (mntbuf == NULL) {
854
			nmounts = getmntinfo(&mntbuf, MNT_NOWAIT);
855
			if (nmounts == -1)
856
				err(1, "getmntinfo");
857
		}
858
		for (i = 0; i < nmounts; i++) {
859
			if (!strcmp(mntbuf[i].f_mntfromname, filename)) {
860
				if (stat(mntbuf[i].f_mntonname, &sb) == -1) {
861
					warn("%s", filename);
862
					return (0);
863
				}
864
				cflg = 1;
865
				break;
866
			}
867
		}
868
	}
869
870
	if ((cur = malloc(sizeof(*cur))) == NULL)
871
		err(1, NULL);
872
873
	cur->ino = sb.st_ino;
874
	cur->dev = sb.st_dev & 0xffff;
875
	cur->name = filename;
876
	TAILQ_INIT(&cur->fusers);
877
	SLIST_INSERT_HEAD(&fileargs, cur, next);
878
	return (1);
879
}
880
881
int
882
signame_to_signum(char *sig)
883
{
884
	int n;
885
	const char *errstr = NULL;
886
887
	if (isdigit((unsigned char)*sig)) {
888
		n = strtonum(sig, 0, NSIG - 1, &errstr);
889
		return (errstr ? -1 : n);
890
	}
891
	if (!strncasecmp(sig, "sig", 3))
892
		sig += 3;
893
	for (n = 1; n < NSIG; n++) {
894
		if (!strcasecmp(sys_signame[n], sig))
895
			return (n);
896
	}
897
	return (-1);
898
}
899
900
void
901
usage(void)
902
{
903
	if (fuser) {
904
		fprintf(stderr, "usage: fuser [-cfku] [-M core] "
905
		    "[-N system] [-s signal] file ...\n");
906
	} else {
907
		fprintf(stderr, "usage: fstat [-fnosv] [-M core] [-N system] "
908
		    "[-p pid] [-u user] [file ...]\n");
909
	}
910
	exit(1);
911
}