xref: /freebsd/usr.bin/procstat/procstat_files.c (revision 5a246d2912dd972b376b4cc9a1204b9acfda71e3)
13d91be41SRobert Watson /*-
23d91be41SRobert Watson  * Copyright (c) 2007 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 
293d91be41SRobert Watson #include <sys/types.h>
303d91be41SRobert Watson #include <sys/socket.h>
313d91be41SRobert Watson #include <sys/sysctl.h>
323d91be41SRobert Watson #include <sys/un.h>
333d91be41SRobert Watson #include <sys/user.h>
343d91be41SRobert Watson 
353d91be41SRobert Watson #include <netinet/in.h>
363d91be41SRobert Watson 
373d91be41SRobert Watson #include <arpa/inet.h>
383d91be41SRobert Watson 
393d91be41SRobert Watson #include <err.h>
403d91be41SRobert Watson #include <inttypes.h>
413d91be41SRobert Watson #include <stdio.h>
423d91be41SRobert Watson #include <stdlib.h>
433d91be41SRobert Watson #include <string.h>
443d91be41SRobert Watson 
453d91be41SRobert Watson #include "procstat.h"
463d91be41SRobert Watson 
473d91be41SRobert Watson static const char *
483d91be41SRobert Watson protocol_to_string(int domain, int type, int protocol)
493d91be41SRobert Watson {
503d91be41SRobert Watson 
513d91be41SRobert Watson 	switch (domain) {
523d91be41SRobert Watson 	case AF_INET:
533d91be41SRobert Watson 	case AF_INET6:
543d91be41SRobert Watson 		switch (protocol) {
553d91be41SRobert Watson 		case IPPROTO_TCP:
563d91be41SRobert Watson 			return ("TCP");
573d91be41SRobert Watson 		case IPPROTO_UDP:
583d91be41SRobert Watson 			return ("UDP");
593d91be41SRobert Watson 		case IPPROTO_ICMP:
605a246d29SRobert Watson 			return ("ICM");
613d91be41SRobert Watson 		case IPPROTO_RAW:
623d91be41SRobert Watson 			return ("RAW");
633d91be41SRobert Watson 		case IPPROTO_SCTP:
645a246d29SRobert Watson 			return ("SCT");
655a246d29SRobert Watson 		case IPPROTO_DIVERT:
665a246d29SRobert Watson 			return ("IPD");
673d91be41SRobert Watson 		default:
685a246d29SRobert Watson 			return ("IP?");
693d91be41SRobert Watson 		}
703d91be41SRobert Watson 
713d91be41SRobert Watson 	case AF_LOCAL:
723d91be41SRobert Watson 		switch (type) {
733d91be41SRobert Watson 		case SOCK_STREAM:
745a246d29SRobert Watson 			return ("UDS");
753d91be41SRobert Watson 		case SOCK_DGRAM:
765a246d29SRobert Watson 			return ("UDD");
773d91be41SRobert Watson 		default:
785a246d29SRobert Watson 			return ("UD?");
793d91be41SRobert Watson 		}
803d91be41SRobert Watson 	default:
815a246d29SRobert Watson 		return ("?");
823d91be41SRobert Watson 	}
833d91be41SRobert Watson }
843d91be41SRobert Watson 
853d91be41SRobert Watson static void
863d91be41SRobert Watson addr_to_string(struct sockaddr_storage *ss, char *buffer, int buflen)
873d91be41SRobert Watson {
883d91be41SRobert Watson 	char buffer2[INET6_ADDRSTRLEN];
893d91be41SRobert Watson 	struct sockaddr_in6 *sin6;
903d91be41SRobert Watson 	struct sockaddr_in *sin;
913d91be41SRobert Watson 	struct sockaddr_un *sun;
923d91be41SRobert Watson 
933d91be41SRobert Watson 	switch (ss->ss_family) {
943d91be41SRobert Watson 	case AF_LOCAL:
953d91be41SRobert Watson 		sun = (struct sockaddr_un *)ss;
963d91be41SRobert Watson 		if (strlen(sun->sun_path) == 0)
973d91be41SRobert Watson 			strlcpy(buffer, "-", buflen);
983d91be41SRobert Watson 		else
993d91be41SRobert Watson 			strlcpy(buffer, sun->sun_path, buflen);
1003d91be41SRobert Watson 		break;
1013d91be41SRobert Watson 
1023d91be41SRobert Watson 	case AF_INET:
1033d91be41SRobert Watson 		sin = (struct sockaddr_in *)ss;
1043d91be41SRobert Watson 		snprintf(buffer, buflen, "%s:%d", inet_ntoa(sin->sin_addr),
1053d91be41SRobert Watson 		    ntohs(sin->sin_port));
1063d91be41SRobert Watson 		break;
1073d91be41SRobert Watson 
1083d91be41SRobert Watson 	case AF_INET6:
1093d91be41SRobert Watson 		sin6 = (struct sockaddr_in6 *)ss;
1103d91be41SRobert Watson 		if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer2,
1113d91be41SRobert Watson 		    sizeof(buffer2)) != NULL)
1123d91be41SRobert Watson 			snprintf(buffer, buflen, "%s.%d", buffer2,
1133d91be41SRobert Watson 			    ntohs(sin6->sin6_port));
1143d91be41SRobert Watson 		else
1153d91be41SRobert Watson 			strlcpy(buffer, "-", sizeof(buffer));
1163d91be41SRobert Watson 		break;
1173d91be41SRobert Watson 
1183d91be41SRobert Watson 	default:
1193d91be41SRobert Watson 		strlcpy(buffer, "", buflen);
1203d91be41SRobert Watson 		break;
1213d91be41SRobert Watson 	}
1223d91be41SRobert Watson }
1233d91be41SRobert Watson 
1243d91be41SRobert Watson static void
1253d91be41SRobert Watson print_address(struct sockaddr_storage *ss)
1263d91be41SRobert Watson {
1273d91be41SRobert Watson 	char addr[PATH_MAX];
1283d91be41SRobert Watson 
1293d91be41SRobert Watson 	addr_to_string(ss, addr, sizeof(addr));
1305a246d29SRobert Watson 	printf("%s", addr);
1313d91be41SRobert Watson }
1323d91be41SRobert Watson 
1333d91be41SRobert Watson void
1343d91be41SRobert Watson procstat_files(pid_t pid, struct kinfo_proc *kipp)
1353d91be41SRobert Watson {
1363d91be41SRobert Watson 	struct kinfo_file *freep, *kif;
1373d91be41SRobert Watson 	int error, i, name[4];
1383d91be41SRobert Watson 	const char *str;
1393d91be41SRobert Watson 	size_t len;
1403d91be41SRobert Watson 
1413d91be41SRobert Watson 	if (!hflag)
1425a246d29SRobert Watson 		printf("%5s %-16s %3s %1s %1s %-8s %3s %7s %-3s %-12s\n",
1435a246d29SRobert Watson 		    "PID", "COMM", "FD", "T", "V", "FLAGS", "REF", "OFFSET",
1445a246d29SRobert Watson 		    "PRO", "NAME");
1453d91be41SRobert Watson 
1463d91be41SRobert Watson 	name[0] = CTL_KERN;
1473d91be41SRobert Watson 	name[1] = KERN_PROC;
1483d91be41SRobert Watson 	name[2] = KERN_PROC_FILEDESC;
1493d91be41SRobert Watson 	name[3] = pid;
1503d91be41SRobert Watson 
1513d91be41SRobert Watson 	error = sysctl(name, 4, NULL, &len, NULL, 0);
1523d91be41SRobert Watson 	if (error < 0 && errno != ESRCH && errno != EPERM) {
1533d91be41SRobert Watson 		warn("sysctl: kern.proc.filedesc: %d", pid);
1543d91be41SRobert Watson 		return;
1553d91be41SRobert Watson 	}
1563d91be41SRobert Watson 	if (error < 0)
1573d91be41SRobert Watson 		return;
1583d91be41SRobert Watson 
1593d91be41SRobert Watson 	freep = kif = malloc(len);
1603d91be41SRobert Watson 	if (kif == NULL)
1613d91be41SRobert Watson 		err(-1, "malloc");
1623d91be41SRobert Watson 
1633d91be41SRobert Watson 	if (sysctl(name, 4, kif, &len, NULL, 0) < 0) {
1643d91be41SRobert Watson 		warn("sysctl: kern.proc.filedesc %d", pid);
1653d91be41SRobert Watson 		free(freep);
1663d91be41SRobert Watson 		return;
1673d91be41SRobert Watson 	}
1683d91be41SRobert Watson 
1693d91be41SRobert Watson 	for (i = 0; i < len / sizeof(*kif); i++, kif++) {
1703d91be41SRobert Watson 		if (kif->kf_structsize != sizeof(*kif))
1713d91be41SRobert Watson 			errx(-1, "kinfo_file mismatch");
1723d91be41SRobert Watson 		printf("%5d ", pid);
1735a246d29SRobert Watson 		printf("%-16s ", kipp->ki_comm);
1743d91be41SRobert Watson 		printf("%3d ", kif->kf_fd);
1753d91be41SRobert Watson 		switch (kif->kf_type) {
1763d91be41SRobert Watson 		case KF_TYPE_VNODE:
1773d91be41SRobert Watson 			str = "v";
1783d91be41SRobert Watson 			break;
1793d91be41SRobert Watson 
1803d91be41SRobert Watson 		case KF_TYPE_SOCKET:
1813d91be41SRobert Watson 			str = "s";
1823d91be41SRobert Watson 			break;
1833d91be41SRobert Watson 
1843d91be41SRobert Watson 		case KF_TYPE_PIPE:
1853d91be41SRobert Watson 			str = "p";
1863d91be41SRobert Watson 			break;
1873d91be41SRobert Watson 
1883d91be41SRobert Watson 		case KF_TYPE_FIFO:
1893d91be41SRobert Watson 			str = "f";
1903d91be41SRobert Watson 			break;
1913d91be41SRobert Watson 
1923d91be41SRobert Watson 		case KF_TYPE_KQUEUE:
1933d91be41SRobert Watson 			str = "k";
1943d91be41SRobert Watson 			break;
1953d91be41SRobert Watson 
1963d91be41SRobert Watson 		case KF_TYPE_CRYPTO:
1973d91be41SRobert Watson 			str = "c";
1983d91be41SRobert Watson 			break;
1993d91be41SRobert Watson 
2003d91be41SRobert Watson 		case KF_TYPE_MQUEUE:
2013d91be41SRobert Watson 			str = "m";
2023d91be41SRobert Watson 			break;
2033d91be41SRobert Watson 
2043d91be41SRobert Watson 		case KF_TYPE_NONE:
2053d91be41SRobert Watson 		case KF_TYPE_UNKNOWN:
2063d91be41SRobert Watson 		default:
2073d91be41SRobert Watson 			str = "?";
2083d91be41SRobert Watson 			break;
2093d91be41SRobert Watson 		}
2103d91be41SRobert Watson 		printf("%1s ", str);
2113d91be41SRobert Watson 		str = "-";
2123d91be41SRobert Watson 		if (kif->kf_type == KF_TYPE_VNODE) {
2133d91be41SRobert Watson 			switch (kif->kf_vnode_type) {
2143d91be41SRobert Watson 			case KF_VTYPE_VREG:
2153d91be41SRobert Watson 				str = "r";
2163d91be41SRobert Watson 				break;
2173d91be41SRobert Watson 
2183d91be41SRobert Watson 			case KF_VTYPE_VDIR:
2193d91be41SRobert Watson 				str = "d";
2203d91be41SRobert Watson 				break;
2213d91be41SRobert Watson 
2223d91be41SRobert Watson 			case KF_VTYPE_VBLK:
2233d91be41SRobert Watson 				str = "b";
2243d91be41SRobert Watson 				break;
2253d91be41SRobert Watson 
2263d91be41SRobert Watson 			case KF_VTYPE_VCHR:
2273d91be41SRobert Watson 				str = "c";
2283d91be41SRobert Watson 				break;
2293d91be41SRobert Watson 
2303d91be41SRobert Watson 			case KF_VTYPE_VLNK:
2313d91be41SRobert Watson 				str = "l";
2323d91be41SRobert Watson 				break;
2333d91be41SRobert Watson 
2343d91be41SRobert Watson 			case KF_VTYPE_VSOCK:
2353d91be41SRobert Watson 				str = "s";
2363d91be41SRobert Watson 				break;
2373d91be41SRobert Watson 
2383d91be41SRobert Watson 			case KF_VTYPE_VFIFO:
2393d91be41SRobert Watson 				str = "f";
2403d91be41SRobert Watson 				break;
2413d91be41SRobert Watson 
2423d91be41SRobert Watson 			case KF_VTYPE_VBAD:
2433d91be41SRobert Watson 				str = "x";
2443d91be41SRobert Watson 				break;
2453d91be41SRobert Watson 
2463d91be41SRobert Watson 			case KF_VTYPE_VNON:
2473d91be41SRobert Watson 			case KF_VTYPE_UNKNOWN:
2483d91be41SRobert Watson 			default:
2493d91be41SRobert Watson 				str = "?";
2503d91be41SRobert Watson 				break;
2513d91be41SRobert Watson 			}
2523d91be41SRobert Watson 		}
2533d91be41SRobert Watson 		printf("%1s ", str);
2543d91be41SRobert Watson 		printf("%s", kif->kf_flags & KF_FLAG_READ ? "r" : "-");
2553d91be41SRobert Watson 		printf("%s", kif->kf_flags & KF_FLAG_WRITE ? "w" : "-");
2563d91be41SRobert Watson 		printf("%s", kif->kf_flags & KF_FLAG_APPEND ? "a" : "-");
2573d91be41SRobert Watson 		printf("%s", kif->kf_flags & KF_FLAG_ASYNC ? "s" : "-");
2583d91be41SRobert Watson 		printf("%s", kif->kf_flags & KF_FLAG_FSYNC ? "f" : "-");
2593d91be41SRobert Watson 		printf("%s", kif->kf_flags & KF_FLAG_NONBLOCK ? "n" : "-");
2603d91be41SRobert Watson 		printf("%s", kif->kf_flags & KF_FLAG_DIRECT ? "d" : "-");
2613d91be41SRobert Watson 		printf("%s ", kif->kf_flags & KF_FLAG_HASLOCK ? "l" : "-");
2623d91be41SRobert Watson 		printf("%3d ", kif->kf_ref_count);
2633d91be41SRobert Watson 		printf("%7jd ", (intmax_t)kif->kf_offset);
2643d91be41SRobert Watson 
2653d91be41SRobert Watson 		switch (kif->kf_type) {
2663d91be41SRobert Watson 		case KF_TYPE_VNODE:
2673d91be41SRobert Watson 		case KF_TYPE_FIFO:
2685a246d29SRobert Watson 			printf("%-3s ", "-");
2695a246d29SRobert Watson 			printf("%-18s", kif->kf_path);
2703d91be41SRobert Watson 			break;
2713d91be41SRobert Watson 
2723d91be41SRobert Watson 		case KF_TYPE_SOCKET:
2735a246d29SRobert Watson 			printf("%-3s ",
2743d91be41SRobert Watson 			    protocol_to_string(kif->kf_sock_domain,
2753d91be41SRobert Watson 			    kif->kf_sock_type, kif->kf_sock_protocol));
2763d91be41SRobert Watson 			/*
2773d91be41SRobert Watson 			 * While generally we like to print two addresses,
2783d91be41SRobert Watson 			 * local and peer, for sockets, it turns out to be
2793d91be41SRobert Watson 			 * more useful to print the first non-nul address for
2803d91be41SRobert Watson 			 * local sockets, as typically they aren't bound and
2813d91be41SRobert Watson 			 *  connected, and the path strings can get long.
2823d91be41SRobert Watson 			 */
2833d91be41SRobert Watson 			if (kif->kf_sock_domain == AF_LOCAL) {
2843d91be41SRobert Watson 				struct sockaddr_un *sun =
2853d91be41SRobert Watson 				    (struct sockaddr_un *)&kif->kf_sa_local;
2863d91be41SRobert Watson 
2873d91be41SRobert Watson 				if (sun->sun_path[0] != 0)
2883d91be41SRobert Watson 					print_address(&kif->kf_sa_local);
2893d91be41SRobert Watson 				else
2903d91be41SRobert Watson 					print_address(&kif->kf_sa_peer);
2913d91be41SRobert Watson 			} else {
2923d91be41SRobert Watson 				print_address(&kif->kf_sa_local);
2933d91be41SRobert Watson 				printf(" ");
2943d91be41SRobert Watson 				print_address(&kif->kf_sa_peer);
2953d91be41SRobert Watson 			}
2963d91be41SRobert Watson 			break;
2973d91be41SRobert Watson 
2983d91be41SRobert Watson 		default:
2995a246d29SRobert Watson 			printf("%-3s ", "-");
3005a246d29SRobert Watson 			printf("%-18s", "-");
3013d91be41SRobert Watson 		}
3023d91be41SRobert Watson 
3033d91be41SRobert Watson 		printf("\n");
3043d91be41SRobert Watson 	}
3053d91be41SRobert Watson 	free(freep);
3063d91be41SRobert Watson }
307