xref: /freebsd/usr.bin/fstat/fstat.c (revision 91ad311be0def02ebf6e1afdb36533718777fa4c)
19b50d902SRodney W. Grimes /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
40daf62d9SStanislav Sedov  * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
59b50d902SRodney W. Grimes  * Copyright (c) 1988, 1993
69b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
79b50d902SRodney W. Grimes  *
89b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
99b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
109b50d902SRodney W. Grimes  * are met:
119b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
129b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
139b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
149b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
159b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
16fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
179b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
189b50d902SRodney W. Grimes  *    without specific prior written permission.
199b50d902SRodney W. Grimes  *
209b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
219b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
249b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
259b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
269b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
279b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
289b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
299b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
309b50d902SRodney W. Grimes  * SUCH DAMAGE.
319b50d902SRodney W. Grimes  */
329b50d902SRodney W. Grimes 
33e026a48cSDavid E. O'Brien #include <sys/cdefs.h>
34e026a48cSDavid E. O'Brien __FBSDID("$FreeBSD$");
359b50d902SRodney W. Grimes 
369b50d902SRodney W. Grimes #include <sys/param.h>
379b50d902SRodney W. Grimes #include <sys/user.h>
389b50d902SRodney W. Grimes #include <sys/stat.h>
399b50d902SRodney W. Grimes #include <sys/socket.h>
409b50d902SRodney W. Grimes #include <sys/socketvar.h>
419b50d902SRodney W. Grimes #include <sys/sysctl.h>
42d2bccb9fSDavid Greenman #include <sys/queue.h>
43*91ad311bSJeremie Le Hen #include <sys/un.h>
449b50d902SRodney W. Grimes 
459b50d902SRodney W. Grimes #include <netinet/in.h>
469b50d902SRodney W. Grimes 
47*91ad311bSJeremie Le Hen #include <arpa/inet.h>
48*91ad311bSJeremie Le Hen 
490daf62d9SStanislav Sedov #include <assert.h>
509b50d902SRodney W. Grimes #include <ctype.h>
51c1e65942SPhilippe Charnier #include <err.h>
520daf62d9SStanislav Sedov #include <libprocstat.h>
53df3f5d9dSPeter Wemm #include <limits.h>
549b50d902SRodney W. Grimes #include <pwd.h>
5576db9ccfSWarner Losh #include <stdint.h>
569b50d902SRodney W. Grimes #include <stdio.h>
579b50d902SRodney W. Grimes #include <stdlib.h>
5805427aafSKonstantin Belousov #include <stddef.h>
599b50d902SRodney W. Grimes #include <string.h>
60df3f5d9dSPeter Wemm #include <unistd.h>
610b7a57ddSRuslan Ermilov #include <netdb.h>
629b50d902SRodney W. Grimes 
630daf62d9SStanislav Sedov #include "functions.h"
649b50d902SRodney W. Grimes 
65357050fcSEd Schouten static int 	fsflg,	/* show files on same filesystem as file(s) argument */
669b50d902SRodney W. Grimes 		pflg,	/* show files open by a particular pid */
67*91ad311bSJeremie Le Hen 		sflg,	/* show socket details */
689b50d902SRodney W. Grimes 		uflg;	/* show files open by a particular (effective) user */
69357050fcSEd Schouten static int 	checkfile; /* restrict to particular files or filesystems */
70357050fcSEd Schouten static int	nflg;	/* (numerical) display f.s. and rdev as dev_t */
71357050fcSEd Schouten static int	mflg;	/* include memory-mapped files */
72357050fcSEd Schouten static int	vflg;	/* be verbose */
739b50d902SRodney W. Grimes 
740daf62d9SStanislav Sedov typedef struct devs {
750daf62d9SStanislav Sedov 	struct devs	*next;
7640ea8d27SAndriy Gapon 	uint64_t	fsid;
770daf62d9SStanislav Sedov 	uint64_t	ino;
780daf62d9SStanislav Sedov 	const char	*name;
790daf62d9SStanislav Sedov } DEVS;
809b50d902SRodney W. Grimes 
81357050fcSEd Schouten static DEVS *devs;
82357050fcSEd Schouten static char *memf, *nlistf;
839b50d902SRodney W. Grimes 
840daf62d9SStanislav Sedov static int	getfname(const char *filename);
850daf62d9SStanislav Sedov static void	dofiles(struct procstat *procstat, struct kinfo_proc *p);
860daf62d9SStanislav Sedov static void	print_access_flags(int flags);
870daf62d9SStanislav Sedov static void	print_file_info(struct procstat *procstat,
880daf62d9SStanislav Sedov     struct filestat *fst, const char *uname, const char *cmd, int pid);
890daf62d9SStanislav Sedov static void	print_pipe_info(struct procstat *procstat,
900daf62d9SStanislav Sedov     struct filestat *fst);
910daf62d9SStanislav Sedov static void	print_pts_info(struct procstat *procstat,
920daf62d9SStanislav Sedov     struct filestat *fst);
93958aa575SJohn Baldwin static void	print_sem_info(struct procstat *procstat,
94958aa575SJohn Baldwin     struct filestat *fst);
95e506e182SJohn Baldwin static void	print_shm_info(struct procstat *procstat,
96e506e182SJohn Baldwin     struct filestat *fst);
970daf62d9SStanislav Sedov static void	print_socket_info(struct procstat *procstat,
980daf62d9SStanislav Sedov     struct filestat *fst);
990daf62d9SStanislav Sedov static void	print_vnode_info(struct procstat *procstat,
1000daf62d9SStanislav Sedov     struct filestat *fst);
1010daf62d9SStanislav Sedov static void	usage(void) __dead2;
1021c17fc99SPeter Wemm 
1031c17fc99SPeter Wemm int
1040daf62d9SStanislav Sedov do_fstat(int argc, char **argv)
1059b50d902SRodney W. Grimes {
1060daf62d9SStanislav Sedov 	struct kinfo_proc *p;
10727d57ea9SDavid Malone 	struct passwd *passwd;
1080daf62d9SStanislav Sedov 	struct procstat *procstat;
1099b50d902SRodney W. Grimes 	int arg, ch, what;
1100daf62d9SStanislav Sedov 	int cnt, i;
1119b50d902SRodney W. Grimes 
1129b50d902SRodney W. Grimes 	arg = 0;
113f9feee17SEd Maste 	what = KERN_PROC_PROC;
1149b50d902SRodney W. Grimes 	nlistf = memf = NULL;
115*91ad311bSJeremie Le Hen 	while ((ch = getopt(argc, argv, "fmnp:su:vN:M:")) != -1)
1169b50d902SRodney W. Grimes 		switch((char)ch) {
1179b50d902SRodney W. Grimes 		case 'f':
1189b50d902SRodney W. Grimes 			fsflg = 1;
1199b50d902SRodney W. Grimes 			break;
1209b50d902SRodney W. Grimes 		case 'M':
1219b50d902SRodney W. Grimes 			memf = optarg;
1229b50d902SRodney W. Grimes 			break;
1239b50d902SRodney W. Grimes 		case 'N':
1249b50d902SRodney W. Grimes 			nlistf = optarg;
1259b50d902SRodney W. Grimes 			break;
126d0482be8SBrian Feldman 		case 'm':
127d0482be8SBrian Feldman 			mflg = 1;
128d0482be8SBrian Feldman 			break;
1299b50d902SRodney W. Grimes 		case 'n':
1309b50d902SRodney W. Grimes 			nflg = 1;
1319b50d902SRodney W. Grimes 			break;
1329b50d902SRodney W. Grimes 		case 'p':
1339b50d902SRodney W. Grimes 			if (pflg++)
1349b50d902SRodney W. Grimes 				usage();
1359b50d902SRodney W. Grimes 			if (!isdigit(*optarg)) {
136c1e65942SPhilippe Charnier 				warnx("-p requires a process id");
1379b50d902SRodney W. Grimes 				usage();
1389b50d902SRodney W. Grimes 			}
1399b50d902SRodney W. Grimes 			what = KERN_PROC_PID;
1409b50d902SRodney W. Grimes 			arg = atoi(optarg);
1419b50d902SRodney W. Grimes 			break;
142*91ad311bSJeremie Le Hen 		case 's':
143*91ad311bSJeremie Le Hen 			sflg = 1;
144*91ad311bSJeremie Le Hen 			break;
1459b50d902SRodney W. Grimes 		case 'u':
1469b50d902SRodney W. Grimes 			if (uflg++)
1479b50d902SRodney W. Grimes 				usage();
148c1e65942SPhilippe Charnier 			if (!(passwd = getpwnam(optarg)))
149c1e65942SPhilippe Charnier 				errx(1, "%s: unknown uid", optarg);
1509b50d902SRodney W. Grimes 			what = KERN_PROC_UID;
1519b50d902SRodney W. Grimes 			arg = passwd->pw_uid;
1529b50d902SRodney W. Grimes 			break;
1539b50d902SRodney W. Grimes 		case 'v':
1549b50d902SRodney W. Grimes 			vflg = 1;
1559b50d902SRodney W. Grimes 			break;
1569b50d902SRodney W. Grimes 		case '?':
1579b50d902SRodney W. Grimes 		default:
1589b50d902SRodney W. Grimes 			usage();
1599b50d902SRodney W. Grimes 		}
1609b50d902SRodney W. Grimes 
1619b50d902SRodney W. Grimes 	if (*(argv += optind)) {
1629b50d902SRodney W. Grimes 		for (; *argv; ++argv) {
1639b50d902SRodney W. Grimes 			if (getfname(*argv))
1649b50d902SRodney W. Grimes 				checkfile = 1;
1659b50d902SRodney W. Grimes 		}
166487ac9acSUlrich Spörlein 		if (!checkfile)	/* file(s) specified, but none accessible */
1679b50d902SRodney W. Grimes 			exit(1);
1689b50d902SRodney W. Grimes 	}
1699b50d902SRodney W. Grimes 
1709b50d902SRodney W. Grimes 	if (fsflg && !checkfile) {
1719b50d902SRodney W. Grimes 		/* -f with no files means use wd */
1729b50d902SRodney W. Grimes 		if (getfname(".") == 0)
1739b50d902SRodney W. Grimes 			exit(1);
1749b50d902SRodney W. Grimes 		checkfile = 1;
1759b50d902SRodney W. Grimes 	}
1769b50d902SRodney W. Grimes 
1771f910d6cSDag-Erling Smørgrav 	if (memf != NULL)
1780daf62d9SStanislav Sedov 		procstat = procstat_open_kvm(nlistf, memf);
1791f910d6cSDag-Erling Smørgrav 	else
1800daf62d9SStanislav Sedov 		procstat = procstat_open_sysctl();
1810daf62d9SStanislav Sedov 	if (procstat == NULL)
1820daf62d9SStanislav Sedov 		errx(1, "procstat_open()");
1830daf62d9SStanislav Sedov 	p = procstat_getprocs(procstat, what, arg, &cnt);
1840daf62d9SStanislav Sedov 	if (p == NULL)
1850daf62d9SStanislav Sedov 		errx(1, "procstat_getprocs()");
1861f910d6cSDag-Erling Smørgrav 
1870daf62d9SStanislav Sedov 	/*
1880daf62d9SStanislav Sedov 	 * Print header.
1890daf62d9SStanislav Sedov 	 */
1901f910d6cSDag-Erling Smørgrav 	if (nflg)
1911f910d6cSDag-Erling Smørgrav 		printf("%s",
1921f910d6cSDag-Erling Smørgrav "USER     CMD          PID   FD  DEV    INUM       MODE SZ|DV R/W");
1931f910d6cSDag-Erling Smørgrav 	else
1941f910d6cSDag-Erling Smørgrav 		printf("%s",
1951f910d6cSDag-Erling Smørgrav "USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W");
1961f910d6cSDag-Erling Smørgrav 	if (checkfile && fsflg == 0)
1971f910d6cSDag-Erling Smørgrav 		printf(" NAME\n");
1981f910d6cSDag-Erling Smørgrav 	else
1991f910d6cSDag-Erling Smørgrav 		putchar('\n');
2000daf62d9SStanislav Sedov 
2010daf62d9SStanislav Sedov 	/*
2020daf62d9SStanislav Sedov 	 * Go through the process list.
2030daf62d9SStanislav Sedov 	 */
2040daf62d9SStanislav Sedov 	for (i = 0; i < cnt; i++) {
2050daf62d9SStanislav Sedov 		if (p[i].ki_stat == SZOMB)
2060daf62d9SStanislav Sedov 			continue;
2070daf62d9SStanislav Sedov 		dofiles(procstat, &p[i]);
2080daf62d9SStanislav Sedov 	}
2090daf62d9SStanislav Sedov 	procstat_freeprocs(procstat, p);
2100daf62d9SStanislav Sedov 	procstat_close(procstat);
2110daf62d9SStanislav Sedov 	return (0);
2121f910d6cSDag-Erling Smørgrav }
2131f910d6cSDag-Erling Smørgrav 
2141f910d6cSDag-Erling Smørgrav static void
2150daf62d9SStanislav Sedov dofiles(struct procstat *procstat, struct kinfo_proc *kp)
2161f910d6cSDag-Erling Smørgrav {
2170daf62d9SStanislav Sedov 	const char *cmd;
2180daf62d9SStanislav Sedov 	const char *uname;
2190daf62d9SStanislav Sedov 	struct filestat *fst;
2200daf62d9SStanislav Sedov 	struct filestat_list *head;
2210daf62d9SStanislav Sedov 	int pid;
2221f910d6cSDag-Erling Smørgrav 
2230daf62d9SStanislav Sedov 	uname = user_from_uid(kp->ki_uid, 0);
2240daf62d9SStanislav Sedov 	pid = kp->ki_pid;
2250daf62d9SStanislav Sedov 	cmd = kp->ki_comm;
2261f910d6cSDag-Erling Smørgrav 
2270daf62d9SStanislav Sedov 	head = procstat_getfiles(procstat, kp, mflg);
2280daf62d9SStanislav Sedov 	if (head == NULL)
2290daf62d9SStanislav Sedov 		return;
2300daf62d9SStanislav Sedov 	STAILQ_FOREACH(fst, head, next)
2310daf62d9SStanislav Sedov 		print_file_info(procstat, fst, uname, cmd, pid);
2320daf62d9SStanislav Sedov 	procstat_freefiles(procstat, head);
2339b50d902SRodney W. Grimes }
2340daf62d9SStanislav Sedov 
2351f910d6cSDag-Erling Smørgrav 
2361f910d6cSDag-Erling Smørgrav static void
2370daf62d9SStanislav Sedov print_file_info(struct procstat *procstat, struct filestat *fst,
2380daf62d9SStanislav Sedov     const char *uname, const char *cmd, int pid)
2391f910d6cSDag-Erling Smørgrav {
2400daf62d9SStanislav Sedov 	struct vnstat vn;
24127d57ea9SDavid Malone 	DEVS *d;
2420daf62d9SStanislav Sedov 	const char *filename;
2430daf62d9SStanislav Sedov 	int error, fsmatch = 0;
2440daf62d9SStanislav Sedov 	char errbuf[_POSIX2_LINE_MAX];
2459b50d902SRodney W. Grimes 
2460daf62d9SStanislav Sedov 	filename = NULL;
2470daf62d9SStanislav Sedov 	if (checkfile != 0) {
248b4fe201cSSergey Kandaurov 		if (fst->fs_type != PS_FST_TYPE_VNODE &&
249b4fe201cSSergey Kandaurov 		    fst->fs_type != PS_FST_TYPE_FIFO)
250e22c40faSSergey Kandaurov 			return;
251b4fe201cSSergey Kandaurov 		error = procstat_get_vnode_info(procstat, fst, &vn, errbuf);
2520daf62d9SStanislav Sedov 		if (error != 0)
2530daf62d9SStanislav Sedov 			return;
2540daf62d9SStanislav Sedov 
2559b50d902SRodney W. Grimes 		for (d = devs; d != NULL; d = d->next)
2560daf62d9SStanislav Sedov 			if (d->fsid == vn.vn_fsid) {
2579b50d902SRodney W. Grimes 				fsmatch = 1;
258e458cb77SGleb Kurtsou 				if (d->ino == vn.vn_fileid) {
2599b50d902SRodney W. Grimes 					filename = d->name;
2609b50d902SRodney W. Grimes 					break;
2619b50d902SRodney W. Grimes 				}
2629b50d902SRodney W. Grimes 			}
2639b50d902SRodney W. Grimes 		if (fsmatch == 0 || (filename == NULL && fsflg == 0))
2649b50d902SRodney W. Grimes 			return;
2659b50d902SRodney W. Grimes 	}
2669b50d902SRodney W. Grimes 
2670daf62d9SStanislav Sedov 	/*
2680daf62d9SStanislav Sedov 	 * Print entry prefix.
2690daf62d9SStanislav Sedov 	 */
2700daf62d9SStanislav Sedov 	printf("%-8.8s %-10s %5d", uname, cmd, pid);
2710daf62d9SStanislav Sedov 	if (fst->fs_uflags & PS_FST_UFLAG_TEXT)
2720daf62d9SStanislav Sedov 		printf(" text");
2730daf62d9SStanislav Sedov 	else if (fst->fs_uflags & PS_FST_UFLAG_CDIR)
2740daf62d9SStanislav Sedov 		printf("   wd");
2750daf62d9SStanislav Sedov 	else if (fst->fs_uflags & PS_FST_UFLAG_RDIR)
2760daf62d9SStanislav Sedov 		printf(" root");
2770daf62d9SStanislav Sedov 	else if (fst->fs_uflags & PS_FST_UFLAG_TRACE)
2780daf62d9SStanislav Sedov 		printf("   tr");
2790daf62d9SStanislav Sedov 	else if (fst->fs_uflags & PS_FST_UFLAG_MMAP)
2800daf62d9SStanislav Sedov 		printf(" mmap");
2810daf62d9SStanislav Sedov 	else if (fst->fs_uflags & PS_FST_UFLAG_JAIL)
2820daf62d9SStanislav Sedov 		printf(" jail");
2830daf62d9SStanislav Sedov 	else if (fst->fs_uflags & PS_FST_UFLAG_CTTY)
2840daf62d9SStanislav Sedov 		printf(" ctty");
2850daf62d9SStanislav Sedov 	else
2860daf62d9SStanislav Sedov 		printf(" %4d", fst->fs_fd);
2870daf62d9SStanislav Sedov 
2880daf62d9SStanislav Sedov 	/*
2890daf62d9SStanislav Sedov 	 * Print type-specific data.
2900daf62d9SStanislav Sedov 	 */
2910daf62d9SStanislav Sedov 	switch (fst->fs_type) {
2920daf62d9SStanislav Sedov 	case PS_FST_TYPE_FIFO:
2930daf62d9SStanislav Sedov 	case PS_FST_TYPE_VNODE:
2940daf62d9SStanislav Sedov 		print_vnode_info(procstat, fst);
2959b50d902SRodney W. Grimes 		break;
2960daf62d9SStanislav Sedov 	case PS_FST_TYPE_SOCKET:
2970daf62d9SStanislav Sedov 		print_socket_info(procstat, fst);
2980daf62d9SStanislav Sedov 		break;
2990daf62d9SStanislav Sedov 	case PS_FST_TYPE_PIPE:
3000daf62d9SStanislav Sedov 		print_pipe_info(procstat, fst);
3010daf62d9SStanislav Sedov 		break;
3020daf62d9SStanislav Sedov 	case PS_FST_TYPE_PTS:
3030daf62d9SStanislav Sedov 		print_pts_info(procstat, fst);
3040daf62d9SStanislav Sedov 		break;
305e506e182SJohn Baldwin 	case PS_FST_TYPE_SHM:
306e506e182SJohn Baldwin 		print_shm_info(procstat, fst);
307e506e182SJohn Baldwin 		break;
308958aa575SJohn Baldwin 	case PS_FST_TYPE_SEM:
309958aa575SJohn Baldwin 		print_sem_info(procstat, fst);
310958aa575SJohn Baldwin 		break;
311a66732deSKonstantin Belousov 	case PS_FST_TYPE_DEV:
312a66732deSKonstantin Belousov 		break;
3139b50d902SRodney W. Grimes 	default:
3140daf62d9SStanislav Sedov 		if (vflg)
3150daf62d9SStanislav Sedov 			fprintf(stderr,
3160daf62d9SStanislav Sedov 			    "unknown file type %d for file %d of pid %d\n",
3170daf62d9SStanislav Sedov 			    fst->fs_type, fst->fs_fd, pid);
3189b50d902SRodney W. Grimes 	}
3199b50d902SRodney W. Grimes 	if (filename && !fsflg)
3209b50d902SRodney W. Grimes 		printf("  %s", filename);
3219b50d902SRodney W. Grimes 	putchar('\n');
3229b50d902SRodney W. Grimes }
3239b50d902SRodney W. Grimes 
324*91ad311bSJeremie Le Hen static char *
325*91ad311bSJeremie Le Hen addr_to_string(struct sockaddr_storage *ss, char *buffer, int buflen)
326*91ad311bSJeremie Le Hen {
327*91ad311bSJeremie Le Hen 	char buffer2[INET6_ADDRSTRLEN];
328*91ad311bSJeremie Le Hen 	struct sockaddr_in6 *sin6;
329*91ad311bSJeremie Le Hen 	struct sockaddr_in *sin;
330*91ad311bSJeremie Le Hen 	struct sockaddr_un *sun;
331*91ad311bSJeremie Le Hen 
332*91ad311bSJeremie Le Hen 	switch (ss->ss_family) {
333*91ad311bSJeremie Le Hen 	case AF_LOCAL:
334*91ad311bSJeremie Le Hen 		sun = (struct sockaddr_un *)ss;
335*91ad311bSJeremie Le Hen 		if (strlen(sun->sun_path) == 0)
336*91ad311bSJeremie Le Hen 			strlcpy(buffer, "-", buflen);
337*91ad311bSJeremie Le Hen 		else
338*91ad311bSJeremie Le Hen 			strlcpy(buffer, sun->sun_path, buflen);
339*91ad311bSJeremie Le Hen 		break;
340*91ad311bSJeremie Le Hen 
341*91ad311bSJeremie Le Hen 	case AF_INET:
342*91ad311bSJeremie Le Hen 		sin = (struct sockaddr_in *)ss;
343*91ad311bSJeremie Le Hen 		if (sin->sin_addr.s_addr == INADDR_ANY)
344*91ad311bSJeremie Le Hen 			snprintf(buffer, buflen, "%s:%d", "*",
345*91ad311bSJeremie Le Hen 			    ntohs(sin->sin_port));
346*91ad311bSJeremie Le Hen 		else if (inet_ntop(AF_INET, &sin->sin_addr, buffer2,
347*91ad311bSJeremie Le Hen 		    sizeof(buffer2)) != NULL)
348*91ad311bSJeremie Le Hen 			snprintf(buffer, buflen, "%s:%d", buffer2,
349*91ad311bSJeremie Le Hen 		            ntohs(sin->sin_port));
350*91ad311bSJeremie Le Hen 		break;
351*91ad311bSJeremie Le Hen 
352*91ad311bSJeremie Le Hen 	case AF_INET6:
353*91ad311bSJeremie Le Hen 		sin6 = (struct sockaddr_in6 *)ss;
354*91ad311bSJeremie Le Hen 		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
355*91ad311bSJeremie Le Hen 			snprintf(buffer, buflen, "%s.%d", "*",
356*91ad311bSJeremie Le Hen 			    ntohs(sin6->sin6_port));
357*91ad311bSJeremie Le Hen 		else if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer2,
358*91ad311bSJeremie Le Hen 		    sizeof(buffer2)) != NULL)
359*91ad311bSJeremie Le Hen 			snprintf(buffer, buflen, "%s.%d", buffer2,
360*91ad311bSJeremie Le Hen 			    ntohs(sin6->sin6_port));
361*91ad311bSJeremie Le Hen 		else
362*91ad311bSJeremie Le Hen 			strlcpy(buffer, "-", buflen);
363*91ad311bSJeremie Le Hen 		break;
364*91ad311bSJeremie Le Hen 
365*91ad311bSJeremie Le Hen 	default:
366*91ad311bSJeremie Le Hen 		strlcpy(buffer, "", buflen);
367*91ad311bSJeremie Le Hen 		break;
368*91ad311bSJeremie Le Hen 	}
369*91ad311bSJeremie Le Hen 	return buffer;
370*91ad311bSJeremie Le Hen }
371*91ad311bSJeremie Le Hen 
372*91ad311bSJeremie Le Hen 
3730daf62d9SStanislav Sedov static void
3740daf62d9SStanislav Sedov print_socket_info(struct procstat *procstat, struct filestat *fst)
3759b50d902SRodney W. Grimes {
37627d57ea9SDavid Malone 	static const char *stypename[] = {
3779b50d902SRodney W. Grimes 		"unused",	/* 0 */
3789b50d902SRodney W. Grimes 		"stream",	/* 1 */
3799b50d902SRodney W. Grimes 		"dgram",	/* 2 */
3809b50d902SRodney W. Grimes 		"raw",		/* 3 */
3819b50d902SRodney W. Grimes 		"rdm",		/* 4 */
3829b50d902SRodney W. Grimes 		"seqpak"	/* 5 */
3839b50d902SRodney W. Grimes 	};
3849b50d902SRodney W. Grimes #define STYPEMAX 5
3850daf62d9SStanislav Sedov 	struct sockstat sock;
3860daf62d9SStanislav Sedov 	struct protoent *pe;
3870daf62d9SStanislav Sedov 	char errbuf[_POSIX2_LINE_MAX];
388*91ad311bSJeremie Le Hen 	char src_addr[PATH_MAX], dst_addr[PATH_MAX];
389*91ad311bSJeremie Le Hen 	struct sockaddr_un *sun;
3900daf62d9SStanislav Sedov 	int error;
3910daf62d9SStanislav Sedov 	static int isopen;
3929b50d902SRodney W. Grimes 
3930daf62d9SStanislav Sedov 	error = procstat_get_socket_info(procstat, fst, &sock, errbuf);
3940daf62d9SStanislav Sedov 	if (error != 0) {
3950daf62d9SStanislav Sedov 		printf("* error");
3960daf62d9SStanislav Sedov 		return;
3979b50d902SRodney W. Grimes 	}
3980daf62d9SStanislav Sedov 	if (sock.type > STYPEMAX)
3990daf62d9SStanislav Sedov 		printf("* %s ?%d", sock.dname, sock.type);
4009b50d902SRodney W. Grimes 	else
4010daf62d9SStanislav Sedov 		printf("* %s %s", sock.dname, stypename[sock.type]);
4029b50d902SRodney W. Grimes 
4039b50d902SRodney W. Grimes 	/*
4049b50d902SRodney W. Grimes 	 * protocol specific formatting
4059b50d902SRodney W. Grimes 	 *
4069b50d902SRodney W. Grimes 	 * Try to find interesting things to print.  For tcp, the interesting
4079b50d902SRodney W. Grimes 	 * thing is the address of the tcpcb, for udp and others, just the
4089b50d902SRodney W. Grimes 	 * inpcb (socket pcb).  For unix domain, its the address of the socket
4099b50d902SRodney W. Grimes 	 * pcb and the address of the connected pcb (if connected).  Otherwise
4109b50d902SRodney W. Grimes 	 * just print the protocol number and address of the socket itself.
4119b50d902SRodney W. Grimes 	 * The idea is not to duplicate netstat, but to make available enough
4129b50d902SRodney W. Grimes 	 * information for further analysis.
4139b50d902SRodney W. Grimes 	 */
4140daf62d9SStanislav Sedov 	switch (sock.dom_family) {
4159b50d902SRodney W. Grimes 	case AF_INET:
416677e00c0SYoshinobu Inoue 	case AF_INET6:
4170daf62d9SStanislav Sedov 		if (!isopen)
4180daf62d9SStanislav Sedov 			setprotoent(++isopen);
4190daf62d9SStanislav Sedov 		if ((pe = getprotobynumber(sock.proto)) != NULL)
4200daf62d9SStanislav Sedov 			printf(" %s", pe->p_name);
4210daf62d9SStanislav Sedov 		else
4220daf62d9SStanislav Sedov 			printf(" %d", sock.proto);
4230daf62d9SStanislav Sedov 		if (sock.proto == IPPROTO_TCP ) {
4240daf62d9SStanislav Sedov 			if (sock.inp_ppcb != 0)
4250daf62d9SStanislav Sedov 				printf(" %lx", (u_long)sock.inp_ppcb);
4269b50d902SRodney W. Grimes 		}
4270daf62d9SStanislav Sedov 		else if (sock.so_pcb != 0)
4280daf62d9SStanislav Sedov 			printf(" %lx", (u_long)sock.so_pcb);
429*91ad311bSJeremie Le Hen 		if (!sflg)
430*91ad311bSJeremie Le Hen 			break;
431*91ad311bSJeremie Le Hen 		printf(" %s <-> %s",
432*91ad311bSJeremie Le Hen 		    addr_to_string(&sock.sa_local, src_addr, sizeof(src_addr)),
433*91ad311bSJeremie Le Hen 		    addr_to_string(&sock.sa_peer, dst_addr, sizeof(dst_addr)));
4349b50d902SRodney W. Grimes 		break;
4359b50d902SRodney W. Grimes 	case AF_UNIX:
4369b50d902SRodney W. Grimes 		/* print address of pcb and connected pcb */
4370daf62d9SStanislav Sedov 		if (sock.so_pcb != 0) {
4380daf62d9SStanislav Sedov 			printf(" %lx", (u_long)sock.so_pcb);
4390daf62d9SStanislav Sedov 			if (sock.unp_conn) {
4409b50d902SRodney W. Grimes 				char shoconn[4], *cp;
4419b50d902SRodney W. Grimes 
4429b50d902SRodney W. Grimes 				cp = shoconn;
4430daf62d9SStanislav Sedov 				if (!(sock.so_rcv_sb_state & SBS_CANTRCVMORE))
4449b50d902SRodney W. Grimes 					*cp++ = '<';
4459b50d902SRodney W. Grimes 				*cp++ = '-';
4460daf62d9SStanislav Sedov 				if (!(sock.so_snd_sb_state & SBS_CANTSENDMORE))
4479b50d902SRodney W. Grimes 					*cp++ = '>';
4489b50d902SRodney W. Grimes 				*cp = '\0';
449df94d4d2SMatt Jacob 				printf(" %s %lx", shoconn,
4500daf62d9SStanislav Sedov 				    (u_long)sock.unp_conn);
4519b50d902SRodney W. Grimes 			}
4529b50d902SRodney W. Grimes 		}
453*91ad311bSJeremie Le Hen 		if (!sflg)
454*91ad311bSJeremie Le Hen 			break;
455*91ad311bSJeremie Le Hen 		sun = (struct sockaddr_un *)&sock.sa_local;
456*91ad311bSJeremie Le Hen 		/*
457*91ad311bSJeremie Le Hen 		 * While generally we like to print two addresses,
458*91ad311bSJeremie Le Hen 		 * local and peer, for sockets, it turns out to be
459*91ad311bSJeremie Le Hen 		 * more useful to print the first non-null address for
460*91ad311bSJeremie Le Hen 		 * local sockets, as typically they aren't bound and
461*91ad311bSJeremie Le Hen 		 *  connected, and the path strings can get long.
462*91ad311bSJeremie Le Hen 		 */
463*91ad311bSJeremie Le Hen 		if (sun->sun_path[0] != 0)
464*91ad311bSJeremie Le Hen 			addr_to_string(&sock.sa_local,
465*91ad311bSJeremie Le Hen 			    src_addr, sizeof(src_addr));
466*91ad311bSJeremie Le Hen 		else
467*91ad311bSJeremie Le Hen 			addr_to_string(&sock.sa_peer,
468*91ad311bSJeremie Le Hen 			    src_addr, sizeof(src_addr));
469*91ad311bSJeremie Le Hen 		printf(" %s", src_addr);
4709b50d902SRodney W. Grimes 		break;
4719b50d902SRodney W. Grimes 	default:
4729b50d902SRodney W. Grimes 		/* print protocol number and socket address */
4730daf62d9SStanislav Sedov 		printf(" %d %lx", sock.proto, (u_long)sock.so_addr);
4749b50d902SRodney W. Grimes 	}
4759b50d902SRodney W. Grimes }
4769b50d902SRodney W. Grimes 
4770daf62d9SStanislav Sedov static void
4780daf62d9SStanislav Sedov print_pipe_info(struct procstat *procstat, struct filestat *fst)
479bc093719SEd Schouten {
4800daf62d9SStanislav Sedov 	struct pipestat ps;
4810daf62d9SStanislav Sedov 	char errbuf[_POSIX2_LINE_MAX];
4820daf62d9SStanislav Sedov 	int error;
4830daf62d9SStanislav Sedov 
4840daf62d9SStanislav Sedov 	error = procstat_get_pipe_info(procstat, fst, &ps, errbuf);
4850daf62d9SStanislav Sedov 	if (error != 0) {
4860daf62d9SStanislav Sedov 		printf("* error");
4870daf62d9SStanislav Sedov 		return;
4880daf62d9SStanislav Sedov 	}
4890daf62d9SStanislav Sedov 	printf("* pipe %8lx <-> %8lx", (u_long)ps.addr, (u_long)ps.peer);
4900daf62d9SStanislav Sedov 	printf(" %6zd", ps.buffer_cnt);
4910daf62d9SStanislav Sedov 	print_access_flags(fst->fs_fflags);
4920daf62d9SStanislav Sedov }
4930daf62d9SStanislav Sedov 
4940daf62d9SStanislav Sedov static void
4950daf62d9SStanislav Sedov print_pts_info(struct procstat *procstat, struct filestat *fst)
4960daf62d9SStanislav Sedov {
4970daf62d9SStanislav Sedov 	struct ptsstat pts;
4980daf62d9SStanislav Sedov 	char errbuf[_POSIX2_LINE_MAX];
4990daf62d9SStanislav Sedov 	int error;
5000daf62d9SStanislav Sedov 
5010daf62d9SStanislav Sedov 	error = procstat_get_pts_info(procstat, fst, &pts, errbuf);
5020daf62d9SStanislav Sedov 	if (error != 0) {
5030daf62d9SStanislav Sedov 		printf("* error");
5040daf62d9SStanislav Sedov 		return;
5050daf62d9SStanislav Sedov 	}
5060daf62d9SStanislav Sedov 	printf("* pseudo-terminal master ");
5070daf62d9SStanislav Sedov 	if (nflg || !*pts.devname) {
5089f365aa1SEd Schouten 		printf("%#10jx", (uintmax_t)pts.dev);
5090daf62d9SStanislav Sedov 	} else {
5100daf62d9SStanislav Sedov 		printf("%10s", pts.devname);
5110daf62d9SStanislav Sedov 	}
5120daf62d9SStanislav Sedov 	print_access_flags(fst->fs_fflags);
5130daf62d9SStanislav Sedov }
5140daf62d9SStanislav Sedov 
5150daf62d9SStanislav Sedov static void
516958aa575SJohn Baldwin print_sem_info(struct procstat *procstat, struct filestat *fst)
517958aa575SJohn Baldwin {
518958aa575SJohn Baldwin 	struct semstat sem;
519958aa575SJohn Baldwin 	char errbuf[_POSIX2_LINE_MAX];
520958aa575SJohn Baldwin 	char mode[15];
521958aa575SJohn Baldwin 	int error;
522958aa575SJohn Baldwin 
523958aa575SJohn Baldwin 	error = procstat_get_sem_info(procstat, fst, &sem, errbuf);
524958aa575SJohn Baldwin 	if (error != 0) {
525958aa575SJohn Baldwin 		printf("* error");
526958aa575SJohn Baldwin 		return;
527958aa575SJohn Baldwin 	}
528958aa575SJohn Baldwin 	if (nflg) {
529958aa575SJohn Baldwin 		printf("             ");
530958aa575SJohn Baldwin 		(void)snprintf(mode, sizeof(mode), "%o", sem.mode);
531958aa575SJohn Baldwin 	} else {
532958aa575SJohn Baldwin 		printf(" %-15s", fst->fs_path != NULL ? fst->fs_path : "-");
533958aa575SJohn Baldwin 		strmode(sem.mode, mode);
534958aa575SJohn Baldwin 	}
535958aa575SJohn Baldwin 	printf(" %10s %6u", mode, sem.value);
536958aa575SJohn Baldwin 	print_access_flags(fst->fs_fflags);
537958aa575SJohn Baldwin }
538958aa575SJohn Baldwin 
539958aa575SJohn Baldwin static void
540e506e182SJohn Baldwin print_shm_info(struct procstat *procstat, struct filestat *fst)
541e506e182SJohn Baldwin {
542e506e182SJohn Baldwin 	struct shmstat shm;
543e506e182SJohn Baldwin 	char errbuf[_POSIX2_LINE_MAX];
544e506e182SJohn Baldwin 	char mode[15];
545e506e182SJohn Baldwin 	int error;
546e506e182SJohn Baldwin 
547e506e182SJohn Baldwin 	error = procstat_get_shm_info(procstat, fst, &shm, errbuf);
548e506e182SJohn Baldwin 	if (error != 0) {
549e506e182SJohn Baldwin 		printf("* error");
550e506e182SJohn Baldwin 		return;
551e506e182SJohn Baldwin 	}
552e506e182SJohn Baldwin 	if (nflg) {
553e506e182SJohn Baldwin 		printf("             ");
554e506e182SJohn Baldwin 		(void)snprintf(mode, sizeof(mode), "%o", shm.mode);
555e506e182SJohn Baldwin 	} else {
556e506e182SJohn Baldwin 		printf(" %-15s", fst->fs_path != NULL ? fst->fs_path : "-");
557e506e182SJohn Baldwin 		strmode(shm.mode, mode);
558e506e182SJohn Baldwin 	}
559e506e182SJohn Baldwin 	printf(" %10s %6ju", mode, shm.size);
560e506e182SJohn Baldwin 	print_access_flags(fst->fs_fflags);
561e506e182SJohn Baldwin }
562e506e182SJohn Baldwin 
563e506e182SJohn Baldwin static void
5640daf62d9SStanislav Sedov print_vnode_info(struct procstat *procstat, struct filestat *fst)
5650daf62d9SStanislav Sedov {
5660daf62d9SStanislav Sedov 	struct vnstat vn;
5670daf62d9SStanislav Sedov 	char errbuf[_POSIX2_LINE_MAX];
5680daf62d9SStanislav Sedov 	char mode[15];
5690daf62d9SStanislav Sedov 	const char *badtype;
5700daf62d9SStanislav Sedov 	int error;
5710daf62d9SStanislav Sedov 
5720daf62d9SStanislav Sedov 	badtype = NULL;
5730daf62d9SStanislav Sedov 	error = procstat_get_vnode_info(procstat, fst, &vn, errbuf);
5740daf62d9SStanislav Sedov 	if (error != 0)
5750daf62d9SStanislav Sedov 		badtype = errbuf;
5760daf62d9SStanislav Sedov 	else if (vn.vn_type == PS_FST_VTYPE_VBAD)
5770daf62d9SStanislav Sedov 		badtype = "bad";
5780daf62d9SStanislav Sedov 	else if (vn.vn_type == PS_FST_VTYPE_VNON)
5790daf62d9SStanislav Sedov 		badtype = "none";
5800daf62d9SStanislav Sedov 	if (badtype != NULL) {
5810daf62d9SStanislav Sedov 		printf(" -         -  %10s    -", badtype);
5820daf62d9SStanislav Sedov 		return;
5830daf62d9SStanislav Sedov 	}
5840daf62d9SStanislav Sedov 
5850daf62d9SStanislav Sedov 	if (nflg)
58605806a06SEd Schouten 		printf(" %#5jx", (uintmax_t)vn.vn_fsid);
5870daf62d9SStanislav Sedov 	else if (vn.vn_mntdir != NULL)
5880daf62d9SStanislav Sedov 		(void)printf(" %-8s", vn.vn_mntdir);
5890daf62d9SStanislav Sedov 
5900daf62d9SStanislav Sedov 	/*
5910daf62d9SStanislav Sedov 	 * Print access mode.
5920daf62d9SStanislav Sedov 	 */
5930daf62d9SStanislav Sedov 	if (nflg)
5940daf62d9SStanislav Sedov 		(void)snprintf(mode, sizeof(mode), "%o", vn.vn_mode);
5950daf62d9SStanislav Sedov 	else {
5960daf62d9SStanislav Sedov 		strmode(vn.vn_mode, mode);
5970daf62d9SStanislav Sedov 	}
59876db9ccfSWarner Losh 	(void)printf(" %6jd %10s", (intmax_t)vn.vn_fileid, mode);
5990daf62d9SStanislav Sedov 
6000daf62d9SStanislav Sedov 	if (vn.vn_type == PS_FST_VTYPE_VBLK || vn.vn_type == PS_FST_VTYPE_VCHR) {
6010daf62d9SStanislav Sedov 		if (nflg || !*vn.vn_devname)
6029f365aa1SEd Schouten 			printf(" %#6jx", (uintmax_t)vn.vn_dev);
6030daf62d9SStanislav Sedov 		else {
6040daf62d9SStanislav Sedov 			printf(" %6s", vn.vn_devname);
6050daf62d9SStanislav Sedov 		}
6060daf62d9SStanislav Sedov 	} else
6078d917b4bSWarner Losh 		printf(" %6ju", (uintmax_t)vn.vn_size);
6080daf62d9SStanislav Sedov 	print_access_flags(fst->fs_fflags);
6090daf62d9SStanislav Sedov }
6100daf62d9SStanislav Sedov 
6110daf62d9SStanislav Sedov static void
6120daf62d9SStanislav Sedov print_access_flags(int flags)
6130daf62d9SStanislav Sedov {
614bc093719SEd Schouten 	char rw[3];
615bc093719SEd Schouten 
616bc093719SEd Schouten 	rw[0] = '\0';
6170daf62d9SStanislav Sedov 	if (flags & PS_FST_FFLAG_READ)
618bc093719SEd Schouten 		strcat(rw, "r");
6190daf62d9SStanislav Sedov 	if (flags & PS_FST_FFLAG_WRITE)
620bc093719SEd Schouten 		strcat(rw, "w");
6210daf62d9SStanislav Sedov 	printf(" %2s", rw);
6229b50d902SRodney W. Grimes }
6239b50d902SRodney W. Grimes 
6241c17fc99SPeter Wemm int
6251e925017SDavid Malone getfname(const char *filename)
6269b50d902SRodney W. Grimes {
6279b50d902SRodney W. Grimes 	struct stat statbuf;
6289b50d902SRodney W. Grimes 	DEVS *cur;
6299b50d902SRodney W. Grimes 
6309b50d902SRodney W. Grimes 	if (stat(filename, &statbuf)) {
631c1e65942SPhilippe Charnier 		warn("%s", filename);
6329b50d902SRodney W. Grimes 		return (0);
6339b50d902SRodney W. Grimes 	}
634c1e65942SPhilippe Charnier 	if ((cur = malloc(sizeof(DEVS))) == NULL)
635c1e65942SPhilippe Charnier 		err(1, NULL);
6369b50d902SRodney W. Grimes 	cur->next = devs;
6379b50d902SRodney W. Grimes 	devs = cur;
6389b50d902SRodney W. Grimes 
6399b50d902SRodney W. Grimes 	cur->ino = statbuf.st_ino;
640b628b0dcSDavid Malone 	cur->fsid = statbuf.st_dev;
6419b50d902SRodney W. Grimes 	cur->name = filename;
6429b50d902SRodney W. Grimes 	return (1);
6439b50d902SRodney W. Grimes }
6449b50d902SRodney W. Grimes 
6450daf62d9SStanislav Sedov static void
6461e925017SDavid Malone usage(void)
6479b50d902SRodney W. Grimes {
6489b50d902SRodney W. Grimes 	(void)fprintf(stderr,
649f682f10cSRuslan Ermilov  "usage: fstat [-fmnv] [-M core] [-N system] [-p pid] [-u user] [file ...]\n");
6509b50d902SRodney W. Grimes 	exit(1);
6519b50d902SRodney W. Grimes }
652