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
|
.\" @(#)fstat.1 8.3 (Berkeley) 2/25/94
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd September 28, 2011
|
.Dd October 19, 2019
|
||||||
.Dt FSTAT 1
|
.Dt FSTAT 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -36,7 +36,7 @@
|
|||||||
.Nd identify active files
|
.Nd identify active files
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl fmnv
|
.Op Fl fmnsv
|
||||||
.Op Fl M Ar core
|
.Op Fl M Ar core
|
||||||
.Op Fl N Ar system
|
.Op Fl N Ar system
|
||||||
.Op Fl p Ar pid
|
.Op Fl p Ar pid
|
||||||
@ -85,6 +85,8 @@ in
|
|||||||
and print the mode of the file in octal instead of symbolic form.
|
and print the mode of the file in octal instead of symbolic form.
|
||||||
.It Fl p
|
.It Fl p
|
||||||
Report all files open by the specified process.
|
Report all files open by the specified process.
|
||||||
|
.It Fl s
|
||||||
|
Print socket endpoint information.
|
||||||
.It Fl u
|
.It Fl u
|
||||||
Report all files open by the specified user.
|
Report all files open by the specified user.
|
||||||
.It Fl v
|
.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
|
For unix domain sockets, its the address of the socket pcb and the address
|
||||||
of the connected pcb (if connected).
|
of the connected pcb (if connected).
|
||||||
Otherwise the protocol number and address of the socket itself are printed.
|
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
|
.Pp
|
||||||
For example, the addresses mentioned above are the addresses which the
|
For example, the addresses mentioned above are the addresses which the
|
||||||
.Dq Li netstat -A
|
.Dq Li netstat -A
|
||||||
@ -211,6 +210,15 @@ connected unix domain stream socket.
|
|||||||
A unidirectional unix domain socket indicates the direction of flow with
|
A unidirectional unix domain socket indicates the direction of flow with
|
||||||
an arrow (``<-'' or ``->''), and a full duplex socket shows a double arrow
|
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
|
.Sh SEE ALSO
|
||||||
.Xr netstat 1 ,
|
.Xr netstat 1 ,
|
||||||
.Xr nfsstat 1 ,
|
.Xr nfsstat 1 ,
|
||||||
|
@ -40,9 +40,12 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/socketvar.h>
|
#include <sys/socketvar.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
@ -61,6 +64,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
static int fsflg, /* show files on same filesystem as file(s) argument */
|
static int fsflg, /* show files on same filesystem as file(s) argument */
|
||||||
pflg, /* show files open by a particular pid */
|
pflg, /* show files open by a particular pid */
|
||||||
|
sflg, /* show socket details */
|
||||||
uflg; /* show files open by a particular (effective) user */
|
uflg; /* show files open by a particular (effective) user */
|
||||||
static int checkfile; /* restrict to particular files or filesystems */
|
static int checkfile; /* restrict to particular files or filesystems */
|
||||||
static int nflg; /* (numerical) display f.s. and rdev as dev_t */
|
static int nflg; /* (numerical) display f.s. and rdev as dev_t */
|
||||||
@ -108,7 +112,7 @@ do_fstat(int argc, char **argv)
|
|||||||
arg = 0;
|
arg = 0;
|
||||||
what = KERN_PROC_PROC;
|
what = KERN_PROC_PROC;
|
||||||
nlistf = memf = NULL;
|
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) {
|
switch((char)ch) {
|
||||||
case 'f':
|
case 'f':
|
||||||
fsflg = 1;
|
fsflg = 1;
|
||||||
@ -135,6 +139,9 @@ do_fstat(int argc, char **argv)
|
|||||||
what = KERN_PROC_PID;
|
what = KERN_PROC_PID;
|
||||||
arg = atoi(optarg);
|
arg = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 's':
|
||||||
|
sflg = 1;
|
||||||
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
if (uflg++)
|
if (uflg++)
|
||||||
usage();
|
usage();
|
||||||
@ -314,6 +321,55 @@ print_file_info(struct procstat *procstat, struct filestat *fst,
|
|||||||
putchar('\n');
|
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
|
static void
|
||||||
print_socket_info(struct procstat *procstat, struct filestat *fst)
|
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 sockstat sock;
|
||||||
struct protoent *pe;
|
struct protoent *pe;
|
||||||
char errbuf[_POSIX2_LINE_MAX];
|
char errbuf[_POSIX2_LINE_MAX];
|
||||||
|
char src_addr[PATH_MAX], dst_addr[PATH_MAX];
|
||||||
|
struct sockaddr_un *sun;
|
||||||
int error;
|
int error;
|
||||||
static int isopen;
|
static int isopen;
|
||||||
|
|
||||||
@ -368,6 +426,11 @@ print_socket_info(struct procstat *procstat, struct filestat *fst)
|
|||||||
}
|
}
|
||||||
else if (sock.so_pcb != 0)
|
else if (sock.so_pcb != 0)
|
||||||
printf(" %lx", (u_long)sock.so_pcb);
|
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;
|
break;
|
||||||
case AF_UNIX:
|
case AF_UNIX:
|
||||||
/* print address of pcb and connected pcb */
|
/* print address of pcb and connected pcb */
|
||||||
@ -385,8 +448,25 @@ print_socket_info(struct procstat *procstat, struct filestat *fst)
|
|||||||
*cp = '\0';
|
*cp = '\0';
|
||||||
printf(" %s %lx", shoconn,
|
printf(" %s %lx", shoconn,
|
||||||
(u_long)sock.unp_conn);
|
(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;
|
break;
|
||||||
default:
|
default:
|
||||||
/* print protocol number and socket address */
|
/* print protocol number and socket address */
|
||||||
|
Loading…
Reference in New Issue
Block a user