xref: /freebsd/usr.bin/procstat/procstat_files.c (revision 474b62b876718890adf24759cc7c15fa5cb7778e)
13d91be41SRobert Watson /*-
2d57486e2SRobert Watson  * Copyright (c) 2007-2011 Robert N. M. Watson
3*474b62b8SAllan Jude  * Copyright (c) 2015 Allan Jude <allanjude@freebsd.org>
43d91be41SRobert Watson  * All rights reserved.
53d91be41SRobert Watson  *
63d91be41SRobert Watson  * Redistribution and use in source and binary forms, with or without
73d91be41SRobert Watson  * modification, are permitted provided that the following conditions
83d91be41SRobert Watson  * are met:
93d91be41SRobert Watson  * 1. Redistributions of source code must retain the above copyright
103d91be41SRobert Watson  *    notice, this list of conditions and the following disclaimer.
113d91be41SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
123d91be41SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
133d91be41SRobert Watson  *    documentation and/or other materials provided with the distribution.
143d91be41SRobert Watson  *
153d91be41SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
163d91be41SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
173d91be41SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
183d91be41SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
193d91be41SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
203d91be41SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
213d91be41SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
223d91be41SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
233d91be41SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
243d91be41SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
253d91be41SRobert Watson  * SUCH DAMAGE.
263d91be41SRobert Watson  *
273d91be41SRobert Watson  * $FreeBSD$
283d91be41SRobert Watson  */
293d91be41SRobert Watson 
30e1f323f3SRobert Watson #include <sys/param.h>
31b881b8beSRobert Watson #include <sys/capsicum.h>
323d91be41SRobert Watson #include <sys/socket.h>
333d91be41SRobert Watson #include <sys/sysctl.h>
343d91be41SRobert Watson #include <sys/un.h>
353d91be41SRobert Watson #include <sys/user.h>
363d91be41SRobert Watson 
373d91be41SRobert Watson #include <netinet/in.h>
383d91be41SRobert Watson 
393d91be41SRobert Watson #include <arpa/inet.h>
403d91be41SRobert Watson 
41821df508SXin LI #include <err.h>
420daf62d9SStanislav Sedov #include <libprocstat.h>
433d91be41SRobert Watson #include <inttypes.h>
443d91be41SRobert Watson #include <stdio.h>
453d91be41SRobert Watson #include <stdlib.h>
463d91be41SRobert Watson #include <string.h>
473d91be41SRobert Watson 
483d91be41SRobert Watson #include "procstat.h"
493d91be41SRobert Watson 
503d91be41SRobert Watson static const char *
513d91be41SRobert Watson protocol_to_string(int domain, int type, int protocol)
523d91be41SRobert Watson {
533d91be41SRobert Watson 
543d91be41SRobert Watson 	switch (domain) {
553d91be41SRobert Watson 	case AF_INET:
563d91be41SRobert Watson 	case AF_INET6:
573d91be41SRobert Watson 		switch (protocol) {
583d91be41SRobert Watson 		case IPPROTO_TCP:
593d91be41SRobert Watson 			return ("TCP");
603d91be41SRobert Watson 		case IPPROTO_UDP:
613d91be41SRobert Watson 			return ("UDP");
623d91be41SRobert Watson 		case IPPROTO_ICMP:
635a246d29SRobert Watson 			return ("ICM");
643d91be41SRobert Watson 		case IPPROTO_RAW:
653d91be41SRobert Watson 			return ("RAW");
663d91be41SRobert Watson 		case IPPROTO_SCTP:
675a246d29SRobert Watson 			return ("SCT");
685a246d29SRobert Watson 		case IPPROTO_DIVERT:
695a246d29SRobert Watson 			return ("IPD");
703d91be41SRobert Watson 		default:
715a246d29SRobert Watson 			return ("IP?");
723d91be41SRobert Watson 		}
733d91be41SRobert Watson 
743d91be41SRobert Watson 	case AF_LOCAL:
753d91be41SRobert Watson 		switch (type) {
763d91be41SRobert Watson 		case SOCK_STREAM:
775a246d29SRobert Watson 			return ("UDS");
783d91be41SRobert Watson 		case SOCK_DGRAM:
795a246d29SRobert Watson 			return ("UDD");
803d91be41SRobert Watson 		default:
815a246d29SRobert Watson 			return ("UD?");
823d91be41SRobert Watson 		}
833d91be41SRobert Watson 	default:
845a246d29SRobert Watson 		return ("?");
853d91be41SRobert Watson 	}
863d91be41SRobert Watson }
873d91be41SRobert Watson 
883d91be41SRobert Watson static void
893d91be41SRobert Watson addr_to_string(struct sockaddr_storage *ss, char *buffer, int buflen)
903d91be41SRobert Watson {
913d91be41SRobert Watson 	char buffer2[INET6_ADDRSTRLEN];
923d91be41SRobert Watson 	struct sockaddr_in6 *sin6;
933d91be41SRobert Watson 	struct sockaddr_in *sin;
943d91be41SRobert Watson 	struct sockaddr_un *sun;
953d91be41SRobert Watson 
963d91be41SRobert Watson 	switch (ss->ss_family) {
973d91be41SRobert Watson 	case AF_LOCAL:
983d91be41SRobert Watson 		sun = (struct sockaddr_un *)ss;
993d91be41SRobert Watson 		if (strlen(sun->sun_path) == 0)
1003d91be41SRobert Watson 			strlcpy(buffer, "-", buflen);
1013d91be41SRobert Watson 		else
1023d91be41SRobert Watson 			strlcpy(buffer, sun->sun_path, buflen);
1033d91be41SRobert Watson 		break;
1043d91be41SRobert Watson 
1053d91be41SRobert Watson 	case AF_INET:
1063d91be41SRobert Watson 		sin = (struct sockaddr_in *)ss;
1073d91be41SRobert Watson 		snprintf(buffer, buflen, "%s:%d", inet_ntoa(sin->sin_addr),
1083d91be41SRobert Watson 		    ntohs(sin->sin_port));
1093d91be41SRobert Watson 		break;
1103d91be41SRobert Watson 
1113d91be41SRobert Watson 	case AF_INET6:
1123d91be41SRobert Watson 		sin6 = (struct sockaddr_in6 *)ss;
1133d91be41SRobert Watson 		if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer2,
1143d91be41SRobert Watson 		    sizeof(buffer2)) != NULL)
1153d91be41SRobert Watson 			snprintf(buffer, buflen, "%s.%d", buffer2,
1163d91be41SRobert Watson 			    ntohs(sin6->sin6_port));
1173d91be41SRobert Watson 		else
11801967281SXin LI 			strlcpy(buffer, "-", buflen);
1193d91be41SRobert Watson 		break;
1203d91be41SRobert Watson 
1213d91be41SRobert Watson 	default:
1223d91be41SRobert Watson 		strlcpy(buffer, "", buflen);
1233d91be41SRobert Watson 		break;
1243d91be41SRobert Watson 	}
1253d91be41SRobert Watson }
1263d91be41SRobert Watson 
127d57486e2SRobert Watson static struct cap_desc {
1287008be5bSPawel Jakub Dawidek 	uint64_t	 cd_right;
129d57486e2SRobert Watson 	const char	*cd_desc;
130d57486e2SRobert Watson } cap_desc[] = {
131d57486e2SRobert Watson 	/* General file I/O. */
132d57486e2SRobert Watson 	{ CAP_READ,		"rd" },
133d57486e2SRobert Watson 	{ CAP_WRITE,		"wr" },
1342609222aSPawel Jakub Dawidek 	{ CAP_SEEK,		"se" },
135d57486e2SRobert Watson 	{ CAP_MMAP,		"mm" },
1362609222aSPawel Jakub Dawidek 	{ CAP_CREATE,		"cr" },
137d57486e2SRobert Watson 	{ CAP_FEXECVE,		"fe" },
138d57486e2SRobert Watson 	{ CAP_FSYNC,		"fy" },
139d57486e2SRobert Watson 	{ CAP_FTRUNCATE,	"ft" },
140d57486e2SRobert Watson 
141d57486e2SRobert Watson 	/* VFS methods. */
142d57486e2SRobert Watson 	{ CAP_FCHDIR,		"cd" },
1432609222aSPawel Jakub Dawidek 	{ CAP_FCHFLAGS,		"cf" },
144d57486e2SRobert Watson 	{ CAP_FCHMOD,		"cm" },
145d57486e2SRobert Watson 	{ CAP_FCHOWN,		"cn" },
146d57486e2SRobert Watson 	{ CAP_FCNTL,		"fc" },
147d57486e2SRobert Watson 	{ CAP_FLOCK,		"fl" },
1482609222aSPawel Jakub Dawidek 	{ CAP_FPATHCONF,	"fp" },
149d57486e2SRobert Watson 	{ CAP_FSCK,		"fk" },
150d57486e2SRobert Watson 	{ CAP_FSTAT,		"fs" },
151d57486e2SRobert Watson 	{ CAP_FSTATFS,		"sf" },
152d57486e2SRobert Watson 	{ CAP_FUTIMES,		"fu" },
153bc1ace0bSEd Schouten 	{ CAP_LINKAT_SOURCE,	"ls" },
154bc1ace0bSEd Schouten 	{ CAP_LINKAT_TARGET,	"lt" },
1552609222aSPawel Jakub Dawidek 	{ CAP_MKDIRAT,		"md" },
1562609222aSPawel Jakub Dawidek 	{ CAP_MKFIFOAT,		"mf" },
1572609222aSPawel Jakub Dawidek 	{ CAP_MKNODAT,		"mn" },
158bc1ace0bSEd Schouten 	{ CAP_RENAMEAT_SOURCE,	"rs" },
159bc1ace0bSEd Schouten 	{ CAP_RENAMEAT_TARGET,	"rt" },
1602609222aSPawel Jakub Dawidek 	{ CAP_SYMLINKAT,	"sl" },
1612609222aSPawel Jakub Dawidek 	{ CAP_UNLINKAT,		"un" },
162d57486e2SRobert Watson 
1632609222aSPawel Jakub Dawidek 	/* Lookups - used to constrain *at() calls. */
164d57486e2SRobert Watson 	{ CAP_LOOKUP,		"lo" },
165d57486e2SRobert Watson 
166d57486e2SRobert Watson 	/* Extended attributes. */
167d57486e2SRobert Watson 	{ CAP_EXTATTR_GET,	"eg" },
168d57486e2SRobert Watson 	{ CAP_EXTATTR_SET,	"es" },
169d57486e2SRobert Watson 	{ CAP_EXTATTR_DELETE,	"ed" },
170d57486e2SRobert Watson 	{ CAP_EXTATTR_LIST,	"el" },
171d57486e2SRobert Watson 
172d57486e2SRobert Watson 	/* Access Control Lists. */
173d57486e2SRobert Watson 	{ CAP_ACL_GET,		"ag" },
174d57486e2SRobert Watson 	{ CAP_ACL_SET,		"as" },
175d57486e2SRobert Watson 	{ CAP_ACL_DELETE,	"ad" },
176d57486e2SRobert Watson 	{ CAP_ACL_CHECK,	"ac" },
177d57486e2SRobert Watson 
178d57486e2SRobert Watson 	/* Socket operations. */
179d57486e2SRobert Watson 	{ CAP_ACCEPT,		"at" },
180d57486e2SRobert Watson 	{ CAP_BIND,		"bd" },
181d57486e2SRobert Watson 	{ CAP_CONNECT,		"co" },
182d57486e2SRobert Watson 	{ CAP_GETPEERNAME,	"pn" },
183d57486e2SRobert Watson 	{ CAP_GETSOCKNAME,	"sn" },
184d57486e2SRobert Watson 	{ CAP_GETSOCKOPT,	"gs" },
185d57486e2SRobert Watson 	{ CAP_LISTEN,		"ln" },
186d57486e2SRobert Watson 	{ CAP_PEELOFF,		"pf" },
187d57486e2SRobert Watson 	{ CAP_SETSOCKOPT,	"ss" },
188d57486e2SRobert Watson 	{ CAP_SHUTDOWN,		"sh" },
189d57486e2SRobert Watson 
190d57486e2SRobert Watson 	/* Mandatory Access Control. */
191d57486e2SRobert Watson 	{ CAP_MAC_GET,		"mg" },
192d57486e2SRobert Watson 	{ CAP_MAC_SET,		"ms" },
193d57486e2SRobert Watson 
194d57486e2SRobert Watson 	/* Methods on semaphores. */
195d57486e2SRobert Watson 	{ CAP_SEM_GETVALUE,	"sg" },
196d57486e2SRobert Watson 	{ CAP_SEM_POST,		"sp" },
197d57486e2SRobert Watson 	{ CAP_SEM_WAIT,		"sw" },
198d57486e2SRobert Watson 
199d57486e2SRobert Watson 	/* Event monitoring and posting. */
200ed5848c8SPawel Jakub Dawidek 	{ CAP_EVENT,		"ev" },
201ed5848c8SPawel Jakub Dawidek 	{ CAP_KQUEUE_EVENT,	"ke" },
202ed5848c8SPawel Jakub Dawidek 	{ CAP_KQUEUE_CHANGE,	"kc" },
203d57486e2SRobert Watson 
204d57486e2SRobert Watson 	/* Strange and powerful rights that should not be given lightly. */
205d57486e2SRobert Watson 	{ CAP_IOCTL,		"io" },
206d57486e2SRobert Watson 	{ CAP_TTYHOOK,		"ty" },
207d57486e2SRobert Watson 
2086a9f247cSPawel Jakub Dawidek 	/* Process management via process descriptors. */
209d57486e2SRobert Watson 	{ CAP_PDGETPID,		"pg" },
2106a9f247cSPawel Jakub Dawidek 	{ CAP_PDWAIT,		"pw" },
211d57486e2SRobert Watson 	{ CAP_PDKILL,		"pk" },
2122609222aSPawel Jakub Dawidek 
2137493f24eSPawel Jakub Dawidek 	/*
2147493f24eSPawel Jakub Dawidek 	 * Rights that allow to use bindat(2) and connectat(2) syscalls on a
2157493f24eSPawel Jakub Dawidek 	 * directory descriptor.
2167493f24eSPawel Jakub Dawidek 	 */
2177493f24eSPawel Jakub Dawidek 	{ CAP_BINDAT,		"ba" },
2187493f24eSPawel Jakub Dawidek 	{ CAP_CONNECTAT,	"ca" },
2197493f24eSPawel Jakub Dawidek 
2202609222aSPawel Jakub Dawidek 	/* Aliases and defines that combine multiple rights. */
2212609222aSPawel Jakub Dawidek 	{ CAP_PREAD,		"prd" },
2222609222aSPawel Jakub Dawidek 	{ CAP_PWRITE,		"pwr" },
2232609222aSPawel Jakub Dawidek 
2242609222aSPawel Jakub Dawidek 	{ CAP_MMAP_R,		"mmr" },
2252609222aSPawel Jakub Dawidek 	{ CAP_MMAP_W,		"mmw" },
2262609222aSPawel Jakub Dawidek 	{ CAP_MMAP_X,		"mmx" },
2272609222aSPawel Jakub Dawidek 	{ CAP_MMAP_RW,		"mrw" },
2282609222aSPawel Jakub Dawidek 	{ CAP_MMAP_RX,		"mrx" },
2292609222aSPawel Jakub Dawidek 	{ CAP_MMAP_WX,		"mwx" },
2302609222aSPawel Jakub Dawidek 	{ CAP_MMAP_RWX,		"mma" },
2312609222aSPawel Jakub Dawidek 
2322609222aSPawel Jakub Dawidek 	{ CAP_RECV,		"re" },
2332609222aSPawel Jakub Dawidek 	{ CAP_SEND,		"sd" },
2342609222aSPawel Jakub Dawidek 
2352609222aSPawel Jakub Dawidek 	{ CAP_SOCK_CLIENT,	"scl" },
2362609222aSPawel Jakub Dawidek 	{ CAP_SOCK_SERVER,	"ssr" },
237d57486e2SRobert Watson };
238d57486e2SRobert Watson static const u_int	cap_desc_count = sizeof(cap_desc) /
239d57486e2SRobert Watson 			    sizeof(cap_desc[0]);
240d57486e2SRobert Watson 
241d57486e2SRobert Watson static u_int
2427008be5bSPawel Jakub Dawidek width_capability(cap_rights_t *rightsp)
243d57486e2SRobert Watson {
244d57486e2SRobert Watson 	u_int count, i, width;
245d57486e2SRobert Watson 
246d57486e2SRobert Watson 	count = 0;
247d57486e2SRobert Watson 	width = 0;
248d57486e2SRobert Watson 	for (i = 0; i < cap_desc_count; i++) {
2497008be5bSPawel Jakub Dawidek 		if (cap_rights_is_set(rightsp, cap_desc[i].cd_right)) {
250d57486e2SRobert Watson 			width += strlen(cap_desc[i].cd_desc);
251d57486e2SRobert Watson 			if (count)
252d57486e2SRobert Watson 				width++;
253d57486e2SRobert Watson 			count++;
254d57486e2SRobert Watson 		}
255d57486e2SRobert Watson 	}
256d57486e2SRobert Watson 	return (width);
257d57486e2SRobert Watson }
258d57486e2SRobert Watson 
259d57486e2SRobert Watson static void
2607008be5bSPawel Jakub Dawidek print_capability(cap_rights_t *rightsp, u_int capwidth)
261d57486e2SRobert Watson {
262d57486e2SRobert Watson 	u_int count, i, width;
263d57486e2SRobert Watson 
264d57486e2SRobert Watson 	count = 0;
265d57486e2SRobert Watson 	width = 0;
2667008be5bSPawel Jakub Dawidek 	for (i = width_capability(rightsp); i < capwidth; i++) {
2677008be5bSPawel Jakub Dawidek 		if (i != 0)
268*474b62b8SAllan Jude 			xo_emit(" ");
269d57486e2SRobert Watson 		else
270*474b62b8SAllan Jude 			xo_emit("-");
271d57486e2SRobert Watson 	}
272*474b62b8SAllan Jude 	xo_open_list("capabilities");
273d57486e2SRobert Watson 	for (i = 0; i < cap_desc_count; i++) {
2747008be5bSPawel Jakub Dawidek 		if (cap_rights_is_set(rightsp, cap_desc[i].cd_right)) {
275*474b62b8SAllan Jude 			xo_emit("{D:/%s}{l:capabilities/%s}", count ? "," : "",
276*474b62b8SAllan Jude 			    cap_desc[i].cd_desc);
277d57486e2SRobert Watson 			width += strlen(cap_desc[i].cd_desc);
278d57486e2SRobert Watson 			if (count)
279d57486e2SRobert Watson 				width++;
280d57486e2SRobert Watson 			count++;
281d57486e2SRobert Watson 		}
282d57486e2SRobert Watson 	}
283*474b62b8SAllan Jude 	xo_close_list("capabilities");
284d57486e2SRobert Watson }
285d57486e2SRobert Watson 
2863d91be41SRobert Watson void
2870daf62d9SStanislav Sedov procstat_files(struct procstat *procstat, struct kinfo_proc *kipp)
2883d91be41SRobert Watson {
2890daf62d9SStanislav Sedov 	struct sockstat sock;
2900daf62d9SStanislav Sedov 	struct filestat_list *head;
2910daf62d9SStanislav Sedov 	struct filestat *fst;
2923d91be41SRobert Watson 	const char *str;
2930daf62d9SStanislav Sedov 	struct vnstat vn;
294d57486e2SRobert Watson 	u_int capwidth, width;
2950daf62d9SStanislav Sedov 	int error;
296*474b62b8SAllan Jude 	char src_addr[PATH_MAX];
297*474b62b8SAllan Jude 	char dst_addr[PATH_MAX];
2983d91be41SRobert Watson 
299d57486e2SRobert Watson 	/*
300d57486e2SRobert Watson 	 * To print the header in capability mode, we need to know the width
301d57486e2SRobert Watson 	 * of the widest capability string.  Even if we get no processes
302d57486e2SRobert Watson 	 * back, we will print the header, so we defer aborting due to a lack
303d57486e2SRobert Watson 	 * of processes until after the header logic.
304d57486e2SRobert Watson 	 */
305d57486e2SRobert Watson 	capwidth = 0;
3060daf62d9SStanislav Sedov 	head = procstat_getfiles(procstat, kipp, 0);
307d57486e2SRobert Watson 	if (head != NULL && Cflag) {
308d57486e2SRobert Watson 		STAILQ_FOREACH(fst, head, next) {
3097008be5bSPawel Jakub Dawidek 			width = width_capability(&fst->fs_cap_rights);
310d57486e2SRobert Watson 			if (width > capwidth)
311d57486e2SRobert Watson 				capwidth = width;
312d57486e2SRobert Watson 		}
313d57486e2SRobert Watson 		if (capwidth < strlen("CAPABILITIES"))
314d57486e2SRobert Watson 			capwidth = strlen("CAPABILITIES");
315d57486e2SRobert Watson 	}
316d57486e2SRobert Watson 
317d57486e2SRobert Watson 	if (!hflag) {
318d57486e2SRobert Watson 		if (Cflag)
319*474b62b8SAllan Jude 			xo_emit("{T:/%5s %-16s %5s %1s %-8s %-*s "
320*474b62b8SAllan Jude 			    "%-3s %-12s}\n", "PID", "COMM", "FD", "T",
321d57486e2SRobert Watson 			    "FLAGS", capwidth, "CAPABILITIES", "PRO",
322d57486e2SRobert Watson 			    "NAME");
323d57486e2SRobert Watson 		else
324*474b62b8SAllan Jude 			xo_emit("{T:/%5s %-16s %5s %1s %1s %-8s "
325*474b62b8SAllan Jude 			    "%3s %7s %-3s %-12s}\n", "PID", "COMM", "FD", "T",
326d57486e2SRobert Watson 			    "V", "FLAGS", "REF", "OFFSET", "PRO", "NAME");
327d57486e2SRobert Watson 	}
328d57486e2SRobert Watson 
3290daf62d9SStanislav Sedov 	if (head == NULL)
33008afefa8SJoe Marcus Clarke 		return;
331*474b62b8SAllan Jude 	xo_emit("{ek:process_id/%5d/%d}", kipp->ki_pid);
332*474b62b8SAllan Jude 	xo_emit("{e:command/%-16s/%s}", kipp->ki_comm);
333*474b62b8SAllan Jude 	xo_open_list("files");
3340daf62d9SStanislav Sedov 	STAILQ_FOREACH(fst, head, next) {
335*474b62b8SAllan Jude 		xo_open_instance("files");
336*474b62b8SAllan Jude 		xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid);
337*474b62b8SAllan Jude 		xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm);
3380daf62d9SStanislav Sedov 		if (fst->fs_uflags & PS_FST_UFLAG_CTTY)
339*474b62b8SAllan Jude 			xo_emit("{P: }{:fd/%s} ", "ctty");
3400daf62d9SStanislav Sedov 		else if (fst->fs_uflags & PS_FST_UFLAG_CDIR)
341*474b62b8SAllan Jude 			xo_emit("{P:  }{:fd/%s} ", "cwd");
3420daf62d9SStanislav Sedov 		else if (fst->fs_uflags & PS_FST_UFLAG_JAIL)
343*474b62b8SAllan Jude 			xo_emit("{P: }{:fd/%s} ", "jail");
3440daf62d9SStanislav Sedov 		else if (fst->fs_uflags & PS_FST_UFLAG_RDIR)
345*474b62b8SAllan Jude 			xo_emit("{P: }{:fd/%s} ", "root");
3460daf62d9SStanislav Sedov 		else if (fst->fs_uflags & PS_FST_UFLAG_TEXT)
347*474b62b8SAllan Jude 			xo_emit("{P: }{:fd/%s} ", "text");
3480daf62d9SStanislav Sedov 		else if (fst->fs_uflags & PS_FST_UFLAG_TRACE)
349*474b62b8SAllan Jude 			xo_emit("{:fd/%s} ", "trace");
3500daf62d9SStanislav Sedov 		else
351*474b62b8SAllan Jude 			xo_emit("{:fd/%5d} ", fst->fs_fd);
352f2805949SJoe Marcus Clarke 
3530daf62d9SStanislav Sedov 		switch (fst->fs_type) {
3540daf62d9SStanislav Sedov 		case PS_FST_TYPE_VNODE:
3553d91be41SRobert Watson 			str = "v";
356*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/vnode}");
3573d91be41SRobert Watson 			break;
3583d91be41SRobert Watson 
3590daf62d9SStanislav Sedov 		case PS_FST_TYPE_SOCKET:
3603d91be41SRobert Watson 			str = "s";
361*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/socket}");
3623d91be41SRobert Watson 			break;
3633d91be41SRobert Watson 
3640daf62d9SStanislav Sedov 		case PS_FST_TYPE_PIPE:
3653d91be41SRobert Watson 			str = "p";
366*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/pipe}");
3673d91be41SRobert Watson 			break;
3683d91be41SRobert Watson 
3690daf62d9SStanislav Sedov 		case PS_FST_TYPE_FIFO:
3703d91be41SRobert Watson 			str = "f";
371*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/fifo}");
3723d91be41SRobert Watson 			break;
3733d91be41SRobert Watson 
3740daf62d9SStanislav Sedov 		case PS_FST_TYPE_KQUEUE:
3753d91be41SRobert Watson 			str = "k";
376*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/kqueue}");
3773d91be41SRobert Watson 			break;
3783d91be41SRobert Watson 
3790daf62d9SStanislav Sedov 		case PS_FST_TYPE_CRYPTO:
3803d91be41SRobert Watson 			str = "c";
381*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/crypto}");
3823d91be41SRobert Watson 			break;
3833d91be41SRobert Watson 
3840daf62d9SStanislav Sedov 		case PS_FST_TYPE_MQUEUE:
3853d91be41SRobert Watson 			str = "m";
386*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/mqueue}");
3873d91be41SRobert Watson 			break;
3883d91be41SRobert Watson 
3890daf62d9SStanislav Sedov 		case PS_FST_TYPE_SHM:
39087cb56f6SRobert Watson 			str = "h";
391*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/shm}");
39287cb56f6SRobert Watson 			break;
39387cb56f6SRobert Watson 
3940daf62d9SStanislav Sedov 		case PS_FST_TYPE_PTS:
395bc093719SEd Schouten 			str = "t";
396*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/pts}");
397bc093719SEd Schouten 			break;
398bc093719SEd Schouten 
3990daf62d9SStanislav Sedov 		case PS_FST_TYPE_SEM:
4006bc1e9cdSJohn Baldwin 			str = "e";
401*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/sem}");
4026bc1e9cdSJohn Baldwin 			break;
4036bc1e9cdSJohn Baldwin 
4040daf62d9SStanislav Sedov 		case PS_FST_TYPE_NONE:
405*474b62b8SAllan Jude 			str = "?";
406*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/none}");
407*474b62b8SAllan Jude 			break;
408*474b62b8SAllan Jude 
4090daf62d9SStanislav Sedov 		case PS_FST_TYPE_UNKNOWN:
4103d91be41SRobert Watson 		default:
4113d91be41SRobert Watson 			str = "?";
412*474b62b8SAllan Jude 			xo_emit("{eq:fd_type/unknown}");
4133d91be41SRobert Watson 			break;
4143d91be41SRobert Watson 		}
415*474b62b8SAllan Jude 		xo_emit("{d:fd_type/%1s/%s} ", str);
416d57486e2SRobert Watson 		if (!Cflag) {
4173d91be41SRobert Watson 			str = "-";
4180daf62d9SStanislav Sedov 			if (fst->fs_type == PS_FST_TYPE_VNODE) {
419d57486e2SRobert Watson 				error = procstat_get_vnode_info(procstat, fst,
420d57486e2SRobert Watson 				    &vn, NULL);
4210daf62d9SStanislav Sedov 				switch (vn.vn_type) {
4220daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VREG:
4233d91be41SRobert Watson 					str = "r";
424*474b62b8SAllan Jude 					xo_emit("{eq:vode_type/regular}");
4253d91be41SRobert Watson 					break;
4263d91be41SRobert Watson 
4270daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VDIR:
4283d91be41SRobert Watson 					str = "d";
429*474b62b8SAllan Jude 					xo_emit("{eq:vode_type/directory}");
4303d91be41SRobert Watson 					break;
4313d91be41SRobert Watson 
4320daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VBLK:
4333d91be41SRobert Watson 					str = "b";
434*474b62b8SAllan Jude 					xo_emit("{eq:vode_type/block}");
4353d91be41SRobert Watson 					break;
4363d91be41SRobert Watson 
4370daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VCHR:
4383d91be41SRobert Watson 					str = "c";
439*474b62b8SAllan Jude 					xo_emit("{eq:vode_type/character}");
4403d91be41SRobert Watson 					break;
4413d91be41SRobert Watson 
4420daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VLNK:
4433d91be41SRobert Watson 					str = "l";
444*474b62b8SAllan Jude 					xo_emit("{eq:vode_type/link}");
4453d91be41SRobert Watson 					break;
4463d91be41SRobert Watson 
4470daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VSOCK:
4483d91be41SRobert Watson 					str = "s";
449*474b62b8SAllan Jude 					xo_emit("{eq:vode_type/socket}");
4503d91be41SRobert Watson 					break;
4513d91be41SRobert Watson 
4520daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VFIFO:
4533d91be41SRobert Watson 					str = "f";
454*474b62b8SAllan Jude 					xo_emit("{eq:vode_type/fifo}");
4553d91be41SRobert Watson 					break;
4563d91be41SRobert Watson 
4570daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VBAD:
4583d91be41SRobert Watson 					str = "x";
459*474b62b8SAllan Jude 					xo_emit("{eq:vode_type/revoked_device}");
4603d91be41SRobert Watson 					break;
4613d91be41SRobert Watson 
4620daf62d9SStanislav Sedov 				case PS_FST_VTYPE_VNON:
463*474b62b8SAllan Jude 					str = "?";
464*474b62b8SAllan Jude 					xo_emit("{eq:vode_type/non}");
465*474b62b8SAllan Jude 					break;
466*474b62b8SAllan Jude 
4670daf62d9SStanislav Sedov 				case PS_FST_VTYPE_UNKNOWN:
4683d91be41SRobert Watson 				default:
4693d91be41SRobert Watson 					str = "?";
470*474b62b8SAllan Jude 					xo_emit("{eq:vode_type/unknown}");
4713d91be41SRobert Watson 					break;
4723d91be41SRobert Watson 				}
4733d91be41SRobert Watson 			}
474*474b62b8SAllan Jude 			xo_emit("{d:vnode_type/%1s/%s} ", str);
475d57486e2SRobert Watson 		}
476*474b62b8SAllan Jude 
477*474b62b8SAllan Jude 		xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_READ ?
478*474b62b8SAllan Jude 		    "r" : "-");
479*474b62b8SAllan Jude 		xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_WRITE ?
480*474b62b8SAllan Jude 		    "w" : "-");
481*474b62b8SAllan Jude 		xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_APPEND ?
482*474b62b8SAllan Jude 		    "a" : "-");
483*474b62b8SAllan Jude 		xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_ASYNC ?
484*474b62b8SAllan Jude 		    "s" : "-");
485*474b62b8SAllan Jude 		xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_SYNC ?
486*474b62b8SAllan Jude 		    "f" : "-");
487*474b62b8SAllan Jude 		xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_NONBLOCK ?
488*474b62b8SAllan Jude 		    "n" : "-");
489*474b62b8SAllan Jude 		xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_DIRECT ?
490*474b62b8SAllan Jude 		    "d" : "-");
491*474b62b8SAllan Jude 		xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_HASLOCK ?
492*474b62b8SAllan Jude 		    "l" : "-");
493*474b62b8SAllan Jude 		xo_emit(" ");
494*474b62b8SAllan Jude 		xo_open_list("fd_flags");
495*474b62b8SAllan Jude 		if (fst->fs_fflags & PS_FST_FFLAG_READ)
496*474b62b8SAllan Jude 			xo_emit("{elq:fd_flags/read}");
497*474b62b8SAllan Jude 		if (fst->fs_fflags & PS_FST_FFLAG_WRITE)
498*474b62b8SAllan Jude 			xo_emit("{elq:fd_flags/write}");
499*474b62b8SAllan Jude 		if (fst->fs_fflags & PS_FST_FFLAG_APPEND)
500*474b62b8SAllan Jude 			xo_emit("{elq:fd_flags/append}");
501*474b62b8SAllan Jude 		if (fst->fs_fflags & PS_FST_FFLAG_ASYNC)
502*474b62b8SAllan Jude 			xo_emit("{elq:fd_flags/async}");
503*474b62b8SAllan Jude 		if (fst->fs_fflags & PS_FST_FFLAG_SYNC)
504*474b62b8SAllan Jude 			xo_emit("{elq:fd_flags/fsync}");
505*474b62b8SAllan Jude 		if (fst->fs_fflags & PS_FST_FFLAG_NONBLOCK)
506*474b62b8SAllan Jude 			xo_emit("{elq:fd_flags/nonblocking}");
507*474b62b8SAllan Jude 		if (fst->fs_fflags & PS_FST_FFLAG_DIRECT)
508*474b62b8SAllan Jude 			xo_emit("{elq:fd_flags/direct_io}");
509*474b62b8SAllan Jude 		if (fst->fs_fflags & PS_FST_FFLAG_HASLOCK)
510*474b62b8SAllan Jude 			xo_emit("{elq:fd_flags/lock_held}");
511*474b62b8SAllan Jude 		xo_close_list("fd_flags");
512*474b62b8SAllan Jude 
513d57486e2SRobert Watson 		if (!Cflag) {
5140daf62d9SStanislav Sedov 			if (fst->fs_ref_count > -1)
515*474b62b8SAllan Jude 				xo_emit("{:ref_count/%3d/%d} ",
516*474b62b8SAllan Jude 				    fst->fs_ref_count);
517f2805949SJoe Marcus Clarke 			else
518*474b62b8SAllan Jude 				xo_emit("{q:ref_count/%3c/%c} ", '-');
5190daf62d9SStanislav Sedov 			if (fst->fs_offset > -1)
520*474b62b8SAllan Jude 				xo_emit("{:offset/%7jd/%jd} ",
521*474b62b8SAllan Jude 				    (intmax_t)fst->fs_offset);
522f2805949SJoe Marcus Clarke 			else
523*474b62b8SAllan Jude 				xo_emit("{q:offset/%7c/%c} ", '-');
524d57486e2SRobert Watson 		}
525d57486e2SRobert Watson 		if (Cflag) {
5267008be5bSPawel Jakub Dawidek 			print_capability(&fst->fs_cap_rights, capwidth);
527*474b62b8SAllan Jude 			xo_emit(" ");
528d57486e2SRobert Watson 		}
5290daf62d9SStanislav Sedov 		switch (fst->fs_type) {
5300daf62d9SStanislav Sedov 		case PS_FST_TYPE_SOCKET:
531*474b62b8SAllan Jude 			error = procstat_get_socket_info(procstat, fst, &sock,
532*474b62b8SAllan Jude 			    NULL);
5330daf62d9SStanislav Sedov 			if (error != 0)
5340daf62d9SStanislav Sedov 				break;
535*474b62b8SAllan Jude 			xo_emit("{:protocol/%-3s/%s} ",
5360daf62d9SStanislav Sedov 			    protocol_to_string(sock.dom_family,
5370daf62d9SStanislav Sedov 			    sock.type, sock.proto));
5383d91be41SRobert Watson 			/*
5393d91be41SRobert Watson 			 * While generally we like to print two addresses,
5403d91be41SRobert Watson 			 * local and peer, for sockets, it turns out to be
5413d91be41SRobert Watson 			 * more useful to print the first non-nul address for
5423d91be41SRobert Watson 			 * local sockets, as typically they aren't bound and
5433d91be41SRobert Watson 			 *  connected, and the path strings can get long.
5443d91be41SRobert Watson 			 */
5450daf62d9SStanislav Sedov 			if (sock.dom_family == AF_LOCAL) {
5463d91be41SRobert Watson 				struct sockaddr_un *sun =
5470daf62d9SStanislav Sedov 				    (struct sockaddr_un *)&sock.sa_local;
5483d91be41SRobert Watson 
5493d91be41SRobert Watson 				if (sun->sun_path[0] != 0)
550*474b62b8SAllan Jude 					addr_to_string(&sock.sa_local,
551*474b62b8SAllan Jude 					    src_addr, sizeof(src_addr));
5523d91be41SRobert Watson 				else
553*474b62b8SAllan Jude 					addr_to_string(&sock.sa_peer,
554*474b62b8SAllan Jude 					    src_addr, sizeof(src_addr));
555*474b62b8SAllan Jude 				xo_emit("{:path/%s}", src_addr);
5563d91be41SRobert Watson 			} else {
557*474b62b8SAllan Jude 				addr_to_string(&sock.sa_local, src_addr,
558*474b62b8SAllan Jude 				    sizeof(src_addr));
559*474b62b8SAllan Jude 				addr_to_string(&sock.sa_peer, dst_addr,
560*474b62b8SAllan Jude 				    sizeof(dst_addr));
561*474b62b8SAllan Jude 				xo_emit("{:path/%s %s}", src_addr, dst_addr);
5623d91be41SRobert Watson 			}
5633d91be41SRobert Watson 			break;
5643d91be41SRobert Watson 
5653d91be41SRobert Watson 		default:
566*474b62b8SAllan Jude 			xo_emit("{:protocol/%-3s/%s} ", "-");
567*474b62b8SAllan Jude 			xo_emit("{:path/%-18s/%s}", fst->fs_path != NULL ?
568*474b62b8SAllan Jude 			    fst->fs_path : "-");
5693d91be41SRobert Watson 		}
5703d91be41SRobert Watson 
571*474b62b8SAllan Jude 		xo_emit("\n");
572*474b62b8SAllan Jude 		xo_close_instance("files");
5733d91be41SRobert Watson 	}
574*474b62b8SAllan Jude 	xo_close_list("files");
57539f6ca65SMikolaj Golub 	procstat_freefiles(procstat, head);
5763d91be41SRobert Watson }
577