Changeset View
Changeset View
Standalone View
Standalone View
usr.bin/fstat/fstat.c
Show All 34 Lines | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/user.h> | #include <sys/user.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#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> | ||||
#include <libprocstat.h> | #include <libprocstat.h> | ||||
#include <limits.h> | #include <limits.h> | ||||
#include <pwd.h> | #include <pwd.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <stddef.h> | #include <stddef.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <netdb.h> | #include <netdb.h> | ||||
#include "functions.h" | #include "functions.h" | ||||
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 */ | ||||
static int mflg; /* include memory-mapped files */ | static int mflg; /* include memory-mapped files */ | ||||
static int vflg; /* be verbose */ | static int vflg; /* be verbose */ | ||||
typedef struct devs { | typedef struct devs { | ||||
struct devs *next; | struct devs *next; | ||||
Show All 31 Lines | do_fstat(int argc, char **argv) | ||||
struct passwd *passwd; | struct passwd *passwd; | ||||
struct procstat *procstat; | struct procstat *procstat; | ||||
int arg, ch, what; | int arg, ch, what; | ||||
int cnt, i; | int cnt, i; | ||||
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; | ||||
break; | break; | ||||
case 'M': | case 'M': | ||||
memf = optarg; | memf = optarg; | ||||
break; | break; | ||||
case 'N': | case 'N': | ||||
Show All 10 Lines | case 'p': | ||||
usage(); | usage(); | ||||
if (!isdigit(*optarg)) { | if (!isdigit(*optarg)) { | ||||
warnx("-p requires a process id"); | warnx("-p requires a process id"); | ||||
usage(); | usage(); | ||||
} | } | ||||
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(); | ||||
if (!(passwd = getpwnam(optarg))) | if (!(passwd = getpwnam(optarg))) | ||||
errx(1, "%s: unknown uid", optarg); | errx(1, "%s: unknown uid", optarg); | ||||
what = KERN_PROC_UID; | what = KERN_PROC_UID; | ||||
arg = passwd->pw_uid; | arg = passwd->pw_uid; | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | if (vflg) | ||||
"unknown file type %d for file %d of pid %d\n", | "unknown file type %d for file %d of pid %d\n", | ||||
fst->fs_type, fst->fs_fd, pid); | fst->fs_type, fst->fs_fd, pid); | ||||
} | } | ||||
if (filename && !fsflg) | if (filename && !fsflg) | ||||
printf(" %s", filename); | printf(" %s", filename); | ||||
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; | |||||
#define IS_INADDR_ANY(x) ((x).s_addr == INADDR_ANY) | |||||
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; | |||||
snprintf(buffer, buflen, "%s:%d", | |||||
IS_INADDR_ANY(sin->sin_addr) ? | |||||
"*" : inet_ntoa(sin->sin_addr), | |||||
jilles: Perhaps use `inet_ntop()` here as well to avoid using mutable static data (even though this… | |||||
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) | ||||
{ | { | ||||
static const char *stypename[] = { | static const char *stypename[] = { | ||||
"unused", /* 0 */ | "unused", /* 0 */ | ||||
"stream", /* 1 */ | "stream", /* 1 */ | ||||
"dgram", /* 2 */ | "dgram", /* 2 */ | ||||
"raw", /* 3 */ | "raw", /* 3 */ | ||||
"rdm", /* 4 */ | "rdm", /* 4 */ | ||||
"seqpak" /* 5 */ | "seqpak" /* 5 */ | ||||
}; | }; | ||||
#define STYPEMAX 5 | #define STYPEMAX 5 | ||||
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; | ||||
error = procstat_get_socket_info(procstat, fst, &sock, errbuf); | error = procstat_get_socket_info(procstat, fst, &sock, errbuf); | ||||
if (error != 0) { | if (error != 0) { | ||||
printf("* error"); | printf("* error"); | ||||
return; | return; | ||||
} | } | ||||
Show All 23 Lines | case AF_INET6: | ||||
else | else | ||||
printf(" %d", sock.proto); | printf(" %d", sock.proto); | ||||
if (sock.proto == IPPROTO_TCP ) { | if (sock.proto == IPPROTO_TCP ) { | ||||
if (sock.inp_ppcb != 0) | if (sock.inp_ppcb != 0) | ||||
printf(" %lx", (u_long)sock.inp_ppcb); | printf(" %lx", (u_long)sock.inp_ppcb); | ||||
} | } | ||||
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; | 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: | case AF_UNIX: | ||||
/* print address of pcb and connected pcb */ | /* print address of pcb and connected pcb */ | ||||
if (sock.so_pcb != 0) { | if (sock.so_pcb != 0) { | ||||
printf(" %lx", (u_long)sock.so_pcb); | printf(" %lx", (u_long)sock.so_pcb); | ||||
if (sock.unp_conn) { | if (sock.unp_conn) { | ||||
char shoconn[4], *cp; | char shoconn[4], *cp; | ||||
cp = shoconn; | cp = shoconn; | ||||
if (!(sock.so_rcv_sb_state & SBS_CANTRCVMORE)) | if (!(sock.so_rcv_sb_state & SBS_CANTRCVMORE)) | ||||
*cp++ = '<'; | *cp++ = '<'; | ||||
*cp++ = '-'; | *cp++ = '-'; | ||||
if (!(sock.so_snd_sb_state & SBS_CANTSENDMORE)) | if (!(sock.so_snd_sb_state & SBS_CANTSENDMORE)) | ||||
*cp++ = '>'; | *cp++ = '>'; | ||||
*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-nul address for | |||||
jillesUnsubmitted Done Inline Actionsnon-NULL (NUL is '\0') jilles: non-NULL (NUL is `'\0'`) | |||||
* 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 */ | ||||
printf(" %d %lx", sock.proto, (u_long)sock.so_addr); | printf(" %d %lx", sock.proto, (u_long)sock.so_addr); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 174 Lines • Show Last 20 Lines |
Perhaps use inet_ntop() here as well to avoid using mutable static data (even though this program is single-threaded).