svn commit: r354141 - stable/12/usr.bin/fstat

Jeremie Le Hen jlh at FreeBSD.org
Mon Oct 28 21:51:46 UTC 2019


Author: jlh
Date: Mon Oct 28 21:51:45 2019
New Revision: 354141
URL: https://svnweb.freebsd.org/changeset/base/354141

Log:
  MFC r353769, r354140:
  
      Add the fstat -s option to display socket information.
      Grammar fix.

Modified:
  stable/12/usr.bin/fstat/fstat.1
  stable/12/usr.bin/fstat/fstat.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/usr.bin/fstat/fstat.1
==============================================================================
--- stable/12/usr.bin/fstat/fstat.1	Mon Oct 28 21:48:20 2019	(r354140)
+++ stable/12/usr.bin/fstat/fstat.1	Mon Oct 28 21:51:45 2019	(r354141)
@@ -28,7 +28,7 @@
 .\"     @(#)fstat.1	8.3 (Berkeley) 2/25/94
 .\" $FreeBSD$
 .\"
-.Dd September 28, 2011
+.Dd October 19, 2019
 .Dt FSTAT 1
 .Os
 .Sh NAME
@@ -36,7 +36,7 @@
 .Nd identify active files
 .Sh SYNOPSIS
 .Nm
-.Op Fl fmnv
+.Op Fl fmnsv
 .Op Fl M Ar core
 .Op Fl N Ar system
 .Op Fl p Ar pid
@@ -85,6 +85,8 @@ in
 and print the mode of the file in octal instead of symbolic form.
 .It Fl p
 Report all files open by the specified process.
+.It Fl s
+Print socket endpoint information.
 .It Fl u
 Report all files open by the specified user.
 .It Fl v
@@ -199,9 +201,6 @@ For tcp, it is the address of the tcpcb, and for udp, 
 For unix domain sockets, its the address of the socket pcb and the address
 of the connected pcb (if connected).
 Otherwise the protocol number and address of the socket itself are printed.
-The attempt is to make enough information available to
-permit further analysis without duplicating
-.Xr netstat 1 .
 .Pp
 For example, the addresses mentioned above are the addresses which the
 .Dq Li netstat -A
@@ -211,6 +210,15 @@ connected unix domain stream socket.
 A unidirectional unix domain socket indicates the direction of flow with
 an arrow (``<-'' or ``->''), and a full duplex socket shows a double arrow
 (``<->'').
+.Pp
+When the
+.Fl s
+flag is used, socket endpoint information is shown after the address of the
+socket.
+For internet sockets the local and remote addresses are shown, separated with
+a double arrow (``<->'').
+For unix/local sockets either the local or remote address is shown, depending
+on which one is available.
 .Sh SEE ALSO
 .Xr netstat 1 ,
 .Xr nfsstat 1 ,

Modified: stable/12/usr.bin/fstat/fstat.c
==============================================================================
--- stable/12/usr.bin/fstat/fstat.c	Mon Oct 28 21:48:20 2019	(r354140)
+++ stable/12/usr.bin/fstat/fstat.c	Mon Oct 28 21:51:45 2019	(r354141)
@@ -40,9 +40,12 @@ __FBSDID("$FreeBSD$");
 #include <sys/socketvar.h>
 #include <sys/sysctl.h>
 #include <sys/queue.h>
+#include <sys/un.h>
 
 #include <netinet/in.h>
 
+#include <arpa/inet.h>
+
 #include <assert.h>
 #include <ctype.h>
 #include <err.h>
@@ -61,6 +64,7 @@ __FBSDID("$FreeBSD$");
 
 static int 	fsflg,	/* show files on same filesystem as file(s) argument */
 		pflg,	/* show files open by a particular pid */
+		sflg,	/* show socket details */
 		uflg;	/* show files open by a particular (effective) user */
 static int 	checkfile; /* restrict to particular files or filesystems */
 static int	nflg;	/* (numerical) display f.s. and rdev as dev_t */
@@ -108,7 +112,7 @@ do_fstat(int argc, char **argv)
 	arg = 0;
 	what = KERN_PROC_PROC;
 	nlistf = memf = NULL;
-	while ((ch = getopt(argc, argv, "fmnp:u:vN:M:")) != -1)
+	while ((ch = getopt(argc, argv, "fmnp:su:vN:M:")) != -1)
 		switch((char)ch) {
 		case 'f':
 			fsflg = 1;
@@ -135,6 +139,9 @@ do_fstat(int argc, char **argv)
 			what = KERN_PROC_PID;
 			arg = atoi(optarg);
 			break;
+		case 's':
+			sflg = 1;
+			break;
 		case 'u':
 			if (uflg++)
 				usage();
@@ -314,6 +321,55 @@ print_file_info(struct procstat *procstat, struct file
 	putchar('\n');
 }
 
+static char *
+addr_to_string(struct sockaddr_storage *ss, char *buffer, int buflen)
+{
+	char buffer2[INET6_ADDRSTRLEN];
+	struct sockaddr_in6 *sin6;
+	struct sockaddr_in *sin;
+	struct sockaddr_un *sun;
+
+	switch (ss->ss_family) {
+	case AF_LOCAL:
+		sun = (struct sockaddr_un *)ss;
+		if (strlen(sun->sun_path) == 0)
+			strlcpy(buffer, "-", buflen);
+		else
+			strlcpy(buffer, sun->sun_path, buflen);
+		break;
+
+	case AF_INET:
+		sin = (struct sockaddr_in *)ss;
+		if (sin->sin_addr.s_addr == INADDR_ANY)
+			snprintf(buffer, buflen, "%s:%d", "*",
+			    ntohs(sin->sin_port));
+		else if (inet_ntop(AF_INET, &sin->sin_addr, buffer2,
+		    sizeof(buffer2)) != NULL)
+			snprintf(buffer, buflen, "%s:%d", buffer2,
+		            ntohs(sin->sin_port));
+		break;
+
+	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *)ss;
+		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
+			snprintf(buffer, buflen, "%s.%d", "*",
+			    ntohs(sin6->sin6_port));
+		else if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer2,
+		    sizeof(buffer2)) != NULL)
+			snprintf(buffer, buflen, "%s.%d", buffer2,
+			    ntohs(sin6->sin6_port));
+		else
+			strlcpy(buffer, "-", buflen);
+		break;
+
+	default:
+		strlcpy(buffer, "", buflen);
+		break;
+	}
+	return buffer;
+}
+
+
 static void
 print_socket_info(struct procstat *procstat, struct filestat *fst)
 {
@@ -329,6 +385,8 @@ print_socket_info(struct procstat *procstat, struct fi
 	struct sockstat sock;
 	struct protoent *pe;
 	char errbuf[_POSIX2_LINE_MAX];
+	char src_addr[PATH_MAX], dst_addr[PATH_MAX];
+	struct sockaddr_un *sun;
 	int error;
 	static int isopen;
 
@@ -368,6 +426,11 @@ print_socket_info(struct procstat *procstat, struct fi
 		}
 		else if (sock.so_pcb != 0)
 			printf(" %lx", (u_long)sock.so_pcb);
+		if (!sflg)
+			break;
+		printf(" %s <-> %s",
+		    addr_to_string(&sock.sa_local, src_addr, sizeof(src_addr)),
+		    addr_to_string(&sock.sa_peer, dst_addr, sizeof(dst_addr)));
 		break;
 	case AF_UNIX:
 		/* print address of pcb and connected pcb */
@@ -385,8 +448,25 @@ print_socket_info(struct procstat *procstat, struct fi
 				*cp = '\0';
 				printf(" %s %lx", shoconn,
 				    (u_long)sock.unp_conn);
-                        }
+			}
 		}
+		if (!sflg)
+			break;
+		sun = (struct sockaddr_un *)&sock.sa_local;
+		/*
+		 * While generally we like to print two addresses,
+		 * local and peer, for sockets, it turns out to be
+		 * more useful to print the first non-null address for
+		 * local sockets, as typically they aren't bound and
+		 *  connected, and the path strings can get long.
+		 */
+		if (sun->sun_path[0] != 0)
+			addr_to_string(&sock.sa_local,
+			    src_addr, sizeof(src_addr));
+		else
+			addr_to_string(&sock.sa_peer,
+			    src_addr, sizeof(src_addr));
+		printf(" %s", src_addr);
 		break;
 	default:
 		/* print protocol number and socket address */


More information about the svn-src-all mailing list