Add the fstat -s option to display socket information.
Reviewed by: jilles MFC after: 1 week Relnotes: yes Differential Revision: https://reviews.freebsd.org/D21880
This commit is contained in:
parent
0baf65d25a
commit
3073a2ee26
@ -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, the inpcb (socket pcb).
|
||||
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 address 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 ,
|
||||
|
@ -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 filestat *fst,
|
||||
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 filestat *fst)
|
||||
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 filestat *fst)
|
||||
}
|
||||
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 */
|
||||
@ -387,6 +450,23 @@ print_socket_info(struct procstat *procstat, struct filestat *fst)
|
||||
(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 */
|
||||
|
Loading…
Reference in New Issue
Block a user