xref: /freebsd/usr.bin/procstat/procstat_files.c (revision 39f6ca65531fe4ebaecdda2780151c38837e91d5)
13d91be41SRobert Watson /*-
2d57486e2SRobert Watson  * Copyright (c) 2007-2011 Robert N. M. Watson
33d91be41SRobert Watson  * All rights reserved.
43d91be41SRobert Watson  *
53d91be41SRobert Watson  * Redistribution and use in source and binary forms, with or without
63d91be41SRobert Watson  * modification, are permitted provided that the following conditions
73d91be41SRobert Watson  * are met:
83d91be41SRobert Watson  * 1. Redistributions of source code must retain the above copyright
93d91be41SRobert Watson  *    notice, this list of conditions and the following disclaimer.
103d91be41SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
113d91be41SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
123d91be41SRobert Watson  *    documentation and/or other materials provided with the distribution.
133d91be41SRobert Watson  *
143d91be41SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153d91be41SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163d91be41SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173d91be41SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183d91be41SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193d91be41SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203d91be41SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213d91be41SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223d91be41SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233d91be41SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243d91be41SRobert Watson  * SUCH DAMAGE.
253d91be41SRobert Watson  *
263d91be41SRobert Watson  * $FreeBSD$
273d91be41SRobert Watson  */
283d91be41SRobert Watson 
29e1f323f3SRobert Watson #include <sys/param.h>
30d57486e2SRobert Watson #include <sys/capability.h>
313d91be41SRobert Watson #include <sys/socket.h>
323d91be41SRobert Watson #include <sys/sysctl.h>
333d91be41SRobert Watson #include <sys/un.h>
343d91be41SRobert Watson #include <sys/user.h>
353d91be41SRobert Watson 
363d91be41SRobert Watson #include <netinet/in.h>
373d91be41SRobert Watson 
383d91be41SRobert Watson #include <arpa/inet.h>
393d91be41SRobert Watson 
40821df508SXin LI #include <err.h>
410daf62d9SStanislav Sedov #include <libprocstat.h>
423d91be41SRobert Watson #include <inttypes.h>
433d91be41SRobert Watson #include <stdio.h>
443d91be41SRobert Watson #include <stdlib.h>
453d91be41SRobert Watson #include <string.h>
463d91be41SRobert Watson 
473d91be41SRobert Watson #include "procstat.h"
483d91be41SRobert Watson 
493d91be41SRobert Watson static const char *
503d91be41SRobert Watson protocol_to_string(int domain, int type, int protocol)
513d91be41SRobert Watson {
523d91be41SRobert Watson 
533d91be41SRobert Watson 	switch (domain) {
543d91be41SRobert Watson 	case AF_INET:
553d91be41SRobert Watson 	case AF_INET6:
563d91be41SRobert Watson 		switch (protocol) {
573d91be41SRobert Watson 		case IPPROTO_TCP:
583d91be41SRobert Watson 			return ("TCP");
593d91be41SRobert Watson 		case IPPROTO_UDP:
603d91be41SRobert Watson 			return ("UDP");
613d91be41SRobert Watson 		case IPPROTO_ICMP:
625a246d29SRobert Watson 			return ("ICM");
633d91be41SRobert Watson 		case IPPROTO_RAW:
643d91be41SRobert Watson 			return ("RAW");
653d91be41SRobert Watson 		case IPPROTO_SCTP:
665a246d29SRobert Watson 			return ("SCT");
675a246d29SRobert Watson 		case IPPROTO_DIVERT:
685a246d29SRobert Watson 			return ("IPD");
693d91be41SRobert Watson 		default:
705a246d29SRobert Watson 			return ("IP?");
713d91be41SRobert Watson 		}
723d91be41SRobert Watson 
733d91be41SRobert Watson 	case AF_LOCAL:
743d91be41SRobert Watson 		switch (type) {
753d91be41SRobert Watson 		case SOCK_STREAM:
765a246d29SRobert Watson 			return ("UDS");
773d91be41SRobert Watson 		case SOCK_DGRAM:
785a246d29SRobert Watson 			return ("UDD");
793d91be41SRobert Watson 		default:
805a246d29SRobert Watson 			return ("UD?");
813d91be41SRobert Watson 		}
823d91be41SRobert Watson 	default:
835a246d29SRobert Watson 		return ("?");
843d91be41SRobert Watson 	}
853d91be41SRobert Watson }
863d91be41SRobert Watson 
873d91be41SRobert Watson static void
883d91be41SRobert Watson addr_to_string(struct sockaddr_storage *ss, char *buffer, int buflen)
893d91be41SRobert Watson {
903d91be41SRobert Watson 	char buffer2[INET6_ADDRSTRLEN];
913d91be41SRobert Watson 	struct sockaddr_in6 *sin6;
923d91be41SRobert Watson 	struct sockaddr_in *sin;
933d91be41SRobert Watson 	struct sockaddr_un *sun;
943d91be41SRobert Watson 
953d91be41SRobert Watson 	switch (ss->ss_family) {
963d91be41SRobert Watson 	case AF_LOCAL:
973d91be41SRobert Watson 		sun = (struct sockaddr_un *)ss;
983d91be41SRobert Watson 		if (strlen(sun->sun_path) == 0)
993d91be41SRobert Watson 			strlcpy(buffer, "-", buflen);
1003d91be41SRobert Watson 		else
1013d91be41SRobert Watson 			strlcpy(buffer, sun->sun_path, buflen);
1023d91be41SRobert Watson 		break;
1033d91be41SRobert Watson 
1043d91be41SRobert Watson 	case AF_INET:
1053d91be41SRobert Watson 		sin = (struct sockaddr_in *)ss;
1063d91be41SRobert Watson 		snprintf(buffer, buflen, "%s:%d", inet_ntoa(sin->sin_addr),
1073d91be41SRobert Watson 		    ntohs(sin->sin_port));
1083d91be41SRobert Watson 		break;
1093d91be41SRobert Watson 
1103d91be41SRobert Watson 	case AF_INET6:
1113d91be41SRobert Watson 		sin6 = (struct sockaddr_in6 *)ss;
1123d91be41SRobert Watson 		if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer2,
1133d91be41SRobert Watson 		    sizeof(buffer2)) != NULL)
1143d91be41SRobert Watson 			snprintf(buffer, buflen, "%s.%d", buffer2,
1153d91be41SRobert Watson 			    ntohs(sin6->sin6_port));
1163d91be41SRobert Watson 		else
1173d91be41SRobert Watson 			strlcpy(buffer, "-", sizeof(buffer));
1183d91be41SRobert Watson 		break;
1193d91be41SRobert Watson 
1203d91be41SRobert Watson 	default:
1213d91be41SRobert Watson 		strlcpy(buffer, "", buflen);
1223d91be41SRobert Watson 		break;
1233d91be41SRobert Watson 	}
1243d91be41SRobert Watson }
1253d91be41SRobert Watson 
1263d91be41SRobert Watson static void
1273d91be41SRobert Watson print_address(struct sockaddr_storage *ss)
1283d91be41SRobert Watson {
1293d91be41SRobert Watson 	char addr[PATH_MAX];
1303d91be41SRobert Watson 
1313d91be41SRobert Watson 	addr_to_string(ss, addr, sizeof(addr));
1325a246d29SRobert Watson 	printf("%s", addr);
1333d91be41SRobert Watson }
1343d91be41SRobert Watson 
135d57486e2SRobert Watson static struct cap_desc {
136d57486e2SRobert Watson 	cap_rights_t	 cd_right;
137d57486e2SRobert Watson 	const char	*cd_desc;
138d57486e2SRobert Watson } cap_desc[] = {
139d57486e2SRobert Watson 	/* General file I/O. */
140d57486e2SRobert Watson 	{ CAP_READ,		"rd" },
141d57486e2SRobert Watson 	{ CAP_WRITE,		"wr" },
142d57486e2SRobert Watson 	{ CAP_MMAP,		"mm" },
143d57486e2SRobert Watson 	{ CAP_MAPEXEC,		"me" },
144d57486e2SRobert Watson 	{ CAP_FEXECVE,		"fe" },
145d57486e2SRobert Watson 	{ CAP_FSYNC,		"fy" },
146d57486e2SRobert Watson 	{ CAP_FTRUNCATE,	"ft" },
147d57486e2SRobert Watson 	{ CAP_SEEK,		"se" },
148d57486e2SRobert Watson 
149d57486e2SRobert Watson 	/* VFS methods. */
150d57486e2SRobert Watson 	{ CAP_FCHFLAGS,		"cf" },
151d57486e2SRobert Watson 	{ CAP_FCHDIR,		"cd" },
152d57486e2SRobert Watson 	{ CAP_FCHMOD,		"cm" },
153d57486e2SRobert Watson 	{ CAP_FCHOWN,		"cn" },
154d57486e2SRobert Watson 	{ CAP_FCNTL,		"fc" },
155d57486e2SRobert Watson 	{ CAP_FPATHCONF,	"fp" },
156d57486e2SRobert Watson 	{ CAP_FLOCK,		"fl" },
157d57486e2SRobert Watson 	{ CAP_FSCK,		"fk" },
158d57486e2SRobert Watson 	{ CAP_FSTAT,		"fs" },
159d57486e2SRobert Watson 	{ CAP_FSTATFS,		"sf" },
160d57486e2SRobert Watson 	{ CAP_FUTIMES,		"fu" },
161d57486e2SRobert Watson 	{ CAP_CREATE,		"cr" },
162d57486e2SRobert Watson 	{ CAP_DELETE,		"de" },
163d57486e2SRobert Watson 	{ CAP_MKDIR,		"md" },
164d57486e2SRobert Watson 	{ CAP_RMDIR,		"rm" },
165d57486e2SRobert Watson 	{ CAP_MKFIFO,		"mf" },
166d57486e2SRobert Watson 
167d57486e2SRobert Watson 	/* Lookups - used to constraint *at() calls. */
168d57486e2SRobert Watson 	{ CAP_LOOKUP,		"lo" },
169d57486e2SRobert Watson 
170d57486e2SRobert Watson 	/* Extended attributes. */
171d57486e2SRobert Watson 	{ CAP_EXTATTR_GET,	"eg" },
172d57486e2SRobert Watson 	{ CAP_EXTATTR_SET,	"es" },
173d57486e2SRobert Watson 	{ CAP_EXTATTR_DELETE,	"ed" },
174d57486e2SRobert Watson 	{ CAP_EXTATTR_LIST,	"el" },
175d57486e2SRobert Watson 
176d57486e2SRobert Watson 	/* Access Control Lists. */
177d57486e2SRobert Watson 	{ CAP_ACL_GET,		"ag" },
178d57486e2SRobert Watson 	{ CAP_ACL_SET,		"as" },
179d57486e2SRobert Watson 	{ CAP_ACL_DELETE,	"ad" },
180d57486e2SRobert Watson 	{ CAP_ACL_CHECK,	"ac" },
181d57486e2SRobert Watson 
182d57486e2SRobert Watson 	/* Socket operations. */
183d57486e2SRobert Watson 	{ CAP_ACCEPT,		"at" },
184d57486e2SRobert Watson 	{ CAP_BIND,		"bd" },
185d57486e2SRobert Watson 	{ CAP_CONNECT,		"co" },
186d57486e2SRobert Watson 	{ CAP_GETPEERNAME,	"pn" },
187d57486e2SRobert Watson 	{ CAP_GETSOCKNAME,	"sn" },
188d57486e2SRobert Watson 	{ CAP_GETSOCKOPT,	"gs" },
189d57486e2SRobert Watson 	{ CAP_LISTEN,		"ln" },
190d57486e2SRobert Watson 	{ CAP_PEELOFF,		"pf" },
191d57486e2SRobert Watson 	{ CAP_SETSOCKOPT,	"ss" },
192d57486e2SRobert Watson 	{ CAP_SHUTDOWN,		"sh" },
193d57486e2SRobert Watson 
194d57486e2SRobert Watson 	/* Mandatory Access Control. */
195d57486e2SRobert Watson 	{ CAP_MAC_GET,		"mg" },
196d57486e2SRobert Watson 	{ CAP_MAC_SET,		"ms" },
197d57486e2SRobert Watson 
198d57486e2SRobert Watson 	/* Methods on semaphores. */
199d57486e2SRobert Watson 	{ CAP_SEM_GETVALUE,	"sg" },
200d57486e2SRobert Watson 	{ CAP_SEM_POST,		"sp" },
201d57486e2SRobert Watson 	{ CAP_SEM_WAIT,		"sw" },
202d57486e2SRobert Watson 
203d57486e2SRobert Watson 	/* Event monitoring and posting. */
204d57486e2SRobert Watson 	{ CAP_POLL_EVENT,	"po" },
205d57486e2SRobert Watson 	{ CAP_POST_EVENT,	"ev" },
206d57486e2SRobert Watson 
207d57486e2SRobert Watson 	/* Strange and powerful rights that should not be given lightly. */
208d57486e2SRobert Watson 	{ CAP_IOCTL,		"io" },
209d57486e2SRobert Watson 	{ CAP_TTYHOOK,		"ty" },
210d57486e2SRobert Watson 
211d57486e2SRobert Watson #ifdef NOTYET
212d57486e2SRobert Watson 	{ CAP_PDGETPID,		"pg" },
213d57486e2SRobert Watson 	{ CAP_PDWAIT4,		"pw" },
214d57486e2SRobert Watson 	{ CAP_PDKILL,		"pk" },
215d57486e2SRobert Watson #endif
216d57486e2SRobert Watson };
217d57486e2SRobert Watson static const u_int	cap_desc_count = sizeof(cap_desc) /
218d57486e2SRobert Watson 			    sizeof(cap_desc[0]);
219d57486e2SRobert Watson 
220d57486e2SRobert Watson static u_int
221d57486e2SRobert Watson width_capability(cap_rights_t rights)
222d57486e2SRobert Watson {
223d57486e2SRobert Watson 	u_int count, i, width;
224d57486e2SRobert Watson 
225d57486e2SRobert Watson 	count = 0;
226d57486e2SRobert Watson 	width = 0;
227d57486e2SRobert Watson 	for (i = 0; i < cap_desc_count; i++) {
228d57486e2SRobert Watson 		if (rights & cap_desc[i].cd_right) {
229d57486e2SRobert Watson 			width += strlen(cap_desc[i].cd_desc);
230d57486e2SRobert Watson 			if (count)
231d57486e2SRobert Watson 				width++;
232d57486e2SRobert Watson 			count++;
233d57486e2SRobert Watson 		}
234d57486e2SRobert Watson 	}
235d57486e2SRobert Watson 	return (width);
236d57486e2SRobert Watson }
237d57486e2SRobert Watson 
238d57486e2SRobert Watson static void
239d57486e2SRobert Watson print_capability(cap_rights_t rights, u_int capwidth)
240d57486e2SRobert Watson {
241d57486e2SRobert Watson 	u_int count, i, width;
242d57486e2SRobert Watson 
243d57486e2SRobert Watson 	count = 0;
244d57486e2SRobert Watson 	width = 0;
245d57486e2SRobert Watson 	for (i = width_capability(rights); i < capwidth; i++) {
246d57486e2SRobert Watson 		if (rights || i != 0)
247d57486e2SRobert Watson 			printf(" ");
248d57486e2SRobert Watson 		else
249d57486e2SRobert Watson 			printf("-");
250d57486e2SRobert Watson 	}
251d57486e2SRobert Watson 	for (i = 0; i < cap_desc_count; i++) {
252d57486e2SRobert Watson 		if (rights & cap_desc[i].cd_right) {
253d57486e2SRobert Watson 			printf("%s%s", count ? "," : "", cap_desc[i].cd_desc);
254d57486e2SRobert Watson 			width += strlen(cap_desc[i].cd_desc);
255d57486e2SRobert Watson 			if (count)
256d57486e2SRobert Watson 				width++;
257d57486e2SRobert Watson 			count++;
258d57486e2SRobert Watson 		}
259d57486e2SRobert Watson 	}
260d57486e2SRobert Watson }
261d57486e2SRobert Watson 
2623d91be41SRobert Watson void
2630daf62d9SStanislav Sedov procstat_files(struct procstat *procstat, struct kinfo_proc *kipp)
2643d91be41SRobert Watson {
2650daf62d9SStanislav Sedov 	struct sockstat sock;
2660daf62d9SStanislav Sedov 	struct filestat_list *head;
2670daf62d9SStanislav Sedov 	struct filestat *fst;
2683d91be41SRobert Watson 	const char *str;
2690daf62d9SStanislav Sedov 	struct vnstat vn;
270d57486e2SRobert Watson 	u_int capwidth, width;
2710daf62d9SStanislav Sedov 	int error;
2723d91be41SRobert Watson 
273d57486e2SRobert Watson 	/*
274d57486e2SRobert Watson 	 * To print the header in capability mode, we need to know the width
275d57486e2SRobert Watson 	 * of the widest capability string.  Even if we get no processes
276d57486e2SRobert Watson 	 * back, we will print the header, so we defer aborting due to a lack
277d57486e2SRobert Watson 	 * of processes until after the header logic.
278d57486e2SRobert Watson 	 */
279d57486e2SRobert Watson 	capwidth = 0;
2800daf62d9SStanislav Sedov 	head = procstat_getfiles(procstat, kipp, 0);
281d57486e2SRobert Watson 	if (head != NULL && Cflag) {
282d57486e2SRobert Watson 		STAILQ_FOREACH(fst, head, next) {
283d57486e2SRobert Watson 			width = width_capability(fst->fs_cap_rights);
284d57486e2SRobert Watson 			if (width > capwidth)
285d57486e2SRobert Watson 				capwidth = width;
286d57486e2SRobert Watson 		}
287d57486e2SRobert Watson 		if (capwidth < strlen("CAPABILITIES"))
288d57486e2SRobert Watson 			capwidth = strlen("CAPABILITIES");
289d57486e2SRobert Watson 	}
290d57486e2SRobert Watson 
291d57486e2SRobert Watson 	if (!hflag) {
292d57486e2SRobert Watson 		if (Cflag)
293d57486e2SRobert Watson 			printf("%5s %-16s %4s %1s %-9s %-*s "
294d57486e2SRobert Watson 			    "%-3s %-12s\n", "PID", "COMM", "FD", "T",
295d57486e2SRobert Watson 			    "FLAGS", capwidth, "CAPABILITIES", "PRO",
296d57486e2SRobert Watson 			    "NAME");
297d57486e2SRobert Watson 		else
298d57486e2SRobert Watson 			printf("%5s %-16s %4s %1s %1s %-9s "
299d57486e2SRobert Watson 			    "%3s %7s %-3s %-12s\n", "PID", "COMM", "FD", "T",
300d57486e2SRobert Watson 			    "V", "FLAGS", "REF", "OFFSET", "PRO", "NAME");
301d57486e2SRobert Watson 	}
302d57486e2SRobert Watson 
3030daf62d9SStanislav Sedov 	if (head == NULL)
30408afefa8SJoe Marcus Clarke 		return;
3050daf62d9SStanislav Sedov 	STAILQ_FOREACH(fst, head, next) {
3060daf62d9SStanislav Sedov 		printf("%5d ", kipp->ki_pid);
3075a246d29SRobert Watson 		printf("%-16s ", kipp->ki_comm);
3080daf62d9SStanislav Sedov 		if (fst->fs_uflags & PS_FST_UFLAG_CTTY)
3090daf62d9SStanislav Sedov 			printf("ctty ");
3100daf62d9SStanislav Sedov 		else if (fst->fs_uflags & PS_FST_UFLAG_CDIR)
311f2805949SJoe Marcus Clarke 			printf(" cwd ");
3120daf62d9SStanislav Sedov 		else if (fst->fs_uflags & PS_FST_UFLAG_JAIL)
313f2805949SJoe Marcus Clarke 			printf("jail ");
3140daf62d9SStanislav Sedov 		else if (fst->fs_uflags & PS_FST_UFLAG_RDIR)
3150daf62d9SStanislav Sedov 			printf("root ");
3160daf62d9SStanislav Sedov 		else if (fst->fs_uflags & PS_FST_UFLAG_TEXT)
3170daf62d9SStanislav Sedov 			printf("text ");
3180daf62d9SStanislav Sedov 		else if (fst->fs_uflags & PS_FST_UFLAG_TRACE)
3190daf62d9SStanislav Sedov 			printf("trace ");
3200daf62d9SStanislav Sedov 		else
3210daf62d9SStanislav Sedov 			printf("%4d ", fst->fs_fd);
322f2805949SJoe Marcus Clarke 
3230daf62d9SStanislav Sedov 		switch (fst->fs_type) {
3240daf62d9SStanislav Sedov 		case PS_FST_TYPE_VNODE:
3253d91be41SRobert Watson 			str = "v";
3263d91be41SRobert Watson 			break;
3273d91be41SRobert Watson 
3280daf62d9SStanislav Sedov 		case PS_FST_TYPE_SOCKET:
3293d91be41SRobert Watson 			str = "s";
3303d91be41SRobert Watson 			break;
3313d91be41SRobert Watson 
3320daf62d9SStanislav Sedov 		case PS_FST_TYPE_PIPE:
3333d91be41SRobert Watson 			str = "p";
3343d91be41SRobert Watson 			break;
3353d91be41SRobert Watson 
3360daf62d9SStanislav Sedov 		case PS_FST_TYPE_FIFO:
3373d91be41SRobert Watson 			str = "f";
3383d91be41SRobert Watson 			break;
3393d91be41SRobert Watson 
3400daf62d9SStanislav Sedov 		case PS_FST_TYPE_KQUEUE:
3413d91be41SRobert Watson 			str = "k";
3423d91be41SRobert Watson 			break;
3433d91be41SRobert Watson 
3440daf62d9SStanislav Sedov 		case PS_FST_TYPE_CRYPTO:
3453d91be41SRobert Watson 			str = "c";
3463d91be41SRobert Watson 			break;
3473d91be41SRobert Watson 
3480daf62d9SStanislav Sedov 		case PS_FST_TYPE_MQUEUE:
3493d91be41SRobert Watson 			str = "m";
3503d91be41SRobert Watson 			break;
3513d91be41SRobert Watson 
3520daf62d9SStanislav Sedov 		case PS_FST_TYPE_SHM:
35387cb56f6SRobert Watson 			str = "h";
35487cb56f6SRobert Watson 			break;
35587cb56f6SRobert Watson 
3560daf62d9SStanislav Sedov 		case PS_FST_TYPE_PTS:
357bc093719SEd Schouten 			str = "t";
358bc093719SEd Schouten 			break;
359bc093719SEd Schouten 
3600daf62d9SStanislav Sedov 		case PS_FST_TYPE_SEM:
3616bc1e9cdSJohn Baldwin 			str = "e";
3626bc1e9cdSJohn Baldwin 			break;
3636bc1e9cdSJohn Baldwin 
3640daf62d9SStanislav Sedov 		case PS_FST_TYPE_NONE:
3650daf62d9SStanislav Sedov 		case PS_FST_TYPE_UNKNOWN:
3663d91be41SRobert Watson 		default:
3673d91be41SRobert Watson 			str = "?";
3683d91be41SRobert Watson 			break;
3693d91be41SRobert Watson 		}
3703d91be41SRobert Watson 		printf("%1s ", str);
371d57486e2SRobert Watson 		if (!Cflag) {
3723d91be41SRobert Watson 			str = "-";
3730daf62d9SStanislav Sedov 			if (fst->fs_type == PS_FST_TYPE_VNODE) {
374d57486e2SRobert Watson 				error = procstat_get_vnode_info(procstat, fst,
375d57486e2SRobert Watson 				    &vn, NULL);
3760daf62d9SStanislav Sedov 				switch (vn.vn_type) {
3770daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VREG:
3783d91be41SRobert Watson 					str = "r";
3793d91be41SRobert Watson 					break;
3803d91be41SRobert Watson 
3810daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VDIR:
3823d91be41SRobert Watson 					str = "d";
3833d91be41SRobert Watson 					break;
3843d91be41SRobert Watson 
3850daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VBLK:
3863d91be41SRobert Watson 					str = "b";
3873d91be41SRobert Watson 					break;
3883d91be41SRobert Watson 
3890daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VCHR:
3903d91be41SRobert Watson 					str = "c";
3913d91be41SRobert Watson 					break;
3923d91be41SRobert Watson 
3930daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VLNK:
3943d91be41SRobert Watson 					str = "l";
3953d91be41SRobert Watson 					break;
3963d91be41SRobert Watson 
3970daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VSOCK:
3983d91be41SRobert Watson 					str = "s";
3993d91be41SRobert Watson 					break;
4003d91be41SRobert Watson 
4010daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VFIFO:
4023d91be41SRobert Watson 					str = "f";
4033d91be41SRobert Watson 					break;
4043d91be41SRobert Watson 
4050daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VBAD:
4063d91be41SRobert Watson 					str = "x";
4073d91be41SRobert Watson 					break;
4083d91be41SRobert Watson 
4090daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VNON:
4100daf62d9SStanislav Sedov 				case PS_FST_VTYPE_UNKNOWN:
4113d91be41SRobert Watson 				default:
4123d91be41SRobert Watson 					str = "?";
4133d91be41SRobert Watson 					break;
4143d91be41SRobert Watson 				}
4153d91be41SRobert Watson 			}
4163d91be41SRobert Watson 			printf("%1s ", str);
417d57486e2SRobert Watson 		}
4180daf62d9SStanislav Sedov 		printf("%s", fst->fs_fflags & PS_FST_FFLAG_READ ? "r" : "-");
4190daf62d9SStanislav Sedov 		printf("%s", fst->fs_fflags & PS_FST_FFLAG_WRITE ? "w" : "-");
4200daf62d9SStanislav Sedov 		printf("%s", fst->fs_fflags & PS_FST_FFLAG_APPEND ? "a" : "-");
4210daf62d9SStanislav Sedov 		printf("%s", fst->fs_fflags & PS_FST_FFLAG_ASYNC ? "s" : "-");
4220daf62d9SStanislav Sedov 		printf("%s", fst->fs_fflags & PS_FST_FFLAG_SYNC ? "f" : "-");
4230daf62d9SStanislav Sedov 		printf("%s", fst->fs_fflags & PS_FST_FFLAG_NONBLOCK ? "n" : "-");
4240daf62d9SStanislav Sedov 		printf("%s", fst->fs_fflags & PS_FST_FFLAG_DIRECT ? "d" : "-");
4250daf62d9SStanislav Sedov 		printf("%s", fst->fs_fflags & PS_FST_FFLAG_HASLOCK ? "l" : "-");
426d57486e2SRobert Watson 		printf("%s ", fst->fs_fflags & PS_FST_FFLAG_CAPABILITY ?
427d57486e2SRobert Watson 		    "c" : "-");
428d57486e2SRobert Watson 		if (!Cflag) {
4290daf62d9SStanislav Sedov 			if (fst->fs_ref_count > -1)
4300daf62d9SStanislav Sedov 				printf("%3d ", fst->fs_ref_count);
431f2805949SJoe Marcus Clarke 			else
432f2805949SJoe Marcus Clarke 				printf("%3c ", '-');
4330daf62d9SStanislav Sedov 			if (fst->fs_offset > -1)
4340daf62d9SStanislav Sedov 				printf("%7jd ", (intmax_t)fst->fs_offset);
435f2805949SJoe Marcus Clarke 			else
436f2805949SJoe Marcus Clarke 				printf("%7c ", '-');
437d57486e2SRobert Watson 		}
438d57486e2SRobert Watson 		if (Cflag) {
439d57486e2SRobert Watson 			print_capability(fst->fs_cap_rights, capwidth);
440d57486e2SRobert Watson 			printf(" ");
441d57486e2SRobert Watson 		}
4420daf62d9SStanislav Sedov 		switch (fst->fs_type) {
4430daf62d9SStanislav Sedov 		case PS_FST_TYPE_SOCKET:
4440daf62d9SStanislav Sedov 			error = procstat_get_socket_info(procstat, fst, &sock, NULL);
4450daf62d9SStanislav Sedov 			if (error != 0)
4460daf62d9SStanislav Sedov 				break;
4475a246d29SRobert Watson 			printf("%-3s ",
4480daf62d9SStanislav Sedov 			    protocol_to_string(sock.dom_family,
4490daf62d9SStanislav Sedov 			    sock.type, sock.proto));
4503d91be41SRobert Watson 			/*
4513d91be41SRobert Watson 			 * While generally we like to print two addresses,
4523d91be41SRobert Watson 			 * local and peer, for sockets, it turns out to be
4533d91be41SRobert Watson 			 * more useful to print the first non-nul address for
4543d91be41SRobert Watson 			 * local sockets, as typically they aren't bound and
4553d91be41SRobert Watson 			 *  connected, and the path strings can get long.
4563d91be41SRobert Watson 			 */
4570daf62d9SStanislav Sedov 			if (sock.dom_family == AF_LOCAL) {
4583d91be41SRobert Watson 				struct sockaddr_un *sun =
4590daf62d9SStanislav Sedov 				    (struct sockaddr_un *)&sock.sa_local;
4603d91be41SRobert Watson 
4613d91be41SRobert Watson 				if (sun->sun_path[0] != 0)
4620daf62d9SStanislav Sedov 					print_address(&sock.sa_local);
4633d91be41SRobert Watson 				else
4640daf62d9SStanislav Sedov 					print_address(&sock.sa_peer);
4653d91be41SRobert Watson 			} else {
4660daf62d9SStanislav Sedov 				print_address(&sock.sa_local);
4673d91be41SRobert Watson 				printf(" ");
4680daf62d9SStanislav Sedov 				print_address(&sock.sa_peer);
4693d91be41SRobert Watson 			}
4703d91be41SRobert Watson 			break;
4713d91be41SRobert Watson 
4723d91be41SRobert Watson 		default:
473e506e182SJohn Baldwin 			printf("%-3s ", "-");
474e506e182SJohn Baldwin 			printf("%-18s", fst->fs_path != NULL ? fst->fs_path : "-");
4753d91be41SRobert Watson 		}
4763d91be41SRobert Watson 
4773d91be41SRobert Watson 		printf("\n");
4783d91be41SRobert Watson 	}
479*39f6ca65SMikolaj Golub 	procstat_freefiles(procstat, head);
4803d91be41SRobert Watson }
481