aboutsummaryrefslogtreecommitdiff
path: root/toys/pending
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2015-10-06 07:34:58 -0500
committerRob Landley <rob@landley.net>2015-10-06 07:34:58 -0500
commit8b94351f089f8e6ef0a4a12092bfe2f04ffd960a (patch)
tree1ed86dcd9e26b5377370cfb9f4a4bfb3e6c7eb08 /toys/pending
parent661540a99f2c346d7fb2a4b83db2e31a7d204490 (diff)
downloadtoybox-8b94351f089f8e6ef0a4a12092bfe2f04ffd960a.tar.gz
Decode netlink sockets in lsof.
Refactor the /proc/net parsing so this only adds 7 lines overall. Also clear the DEVICE field for sockets and fix alignment for long usernames (until someone implements the two-pass output that measures columns).
Diffstat (limited to 'toys/pending')
-rw-r--r--toys/pending/lsof.c177
1 files changed, 92 insertions, 85 deletions
diff --git a/toys/pending/lsof.c b/toys/pending/lsof.c
index ac38fddb..18013f77 100644
--- a/toys/pending/lsof.c
+++ b/toys/pending/lsof.c
@@ -72,7 +72,7 @@ static void print_header()
char* names[] = {
"COMMAND", "PID", "USER", "FD", "TYPE", "DEVICE", "SIZE/OFF", "NODE", "NAME"
};
- printf("%-9s %5s %10s %4s %7s %18s %9s %10s %s\n", names[0], names[1],
+ printf("%-9s %5s %10.10s %4s %7s %18s %9s %10s %s\n", names[0], names[1],
names[2], names[3], names[4], names[5], names[6], names[7], names[8]);
TT.shown_header = 1;
}
@@ -88,7 +88,7 @@ static void print_info(void *data)
printf("%d\n", (TT.last_shown_pid = fi->pi.pid));
} else {
if (!TT.shown_header) print_header();
- printf("%-9s %5d %10s %4s%c%c %7s %18s %9s %10s %s\n",
+ printf("%-9s %5d %10.10s %4s%c%c %7s %18s %9s %10s %s\n",
fi->pi.cmd, fi->pi.pid, fi->pi.user,
fi->fd, fi->rw, fi->locks, fi->type, fi->device, fi->size_off,
fi->node, fi->name);
@@ -129,9 +129,11 @@ static char *chomp(char *s)
return s;
}
-static int find_unix_socket(struct file_info *fi, long sought_inode)
+static int scan_proc_net_file(char *path, int family, char type,
+ void (*fn)(char *, int, char, struct file_info *, long),
+ struct file_info *fi, long sought_inode)
{
- FILE *fp = fopen("/proc/net/unix", "r");
+ FILE *fp = fopen(path, "r");
char *line = NULL;
size_t line_length = 0;
@@ -140,19 +142,8 @@ static int find_unix_socket(struct file_info *fi, long sought_inode)
if (!getline(&line, &line_length, fp)) return 0; // Skip header.
while (getline(&line, &line_length, fp) > 0) {
- long inode;
- int path_pos;
-
- if (sscanf(line, "%*p: %*X %*X %*X %*X %*X %lu %n",
- &inode, &path_pos) >= 1) {
- if (inode == sought_inode) {
- char *name = chomp(line + path_pos);
-
- strcpy(fi->type, "unix");
- fi->name = strdup(*name ? name : "socket");
- break;
- }
- }
+ fn(line, family, type, fi, sought_inode);
+ if (fi->name != 0) break;
}
free(line);
@@ -161,87 +152,102 @@ static int find_unix_socket(struct file_info *fi, long sought_inode)
return fi->name != 0;
}
-// Matches lines in either /proc/net/tcp or /proc/net/tcp6, depending on 'af'.
-static int ip_match(int af, char* line, struct in6_addr* l, int* l_port,
- struct in6_addr* r, int* r_port, int* state, long* inode)
+static void match_unix(char *line, int af, char type, struct file_info *fi,
+ long sought_inode)
{
- if (af == AF_INET) {
- return sscanf(line, " %*d: %x:%x %x:%x %x %*x:%*x %*X:%*X %*X %*d %*d %ld",
- &(l->s6_addr32[0]), l_port, &(r->s6_addr32[0]), r_port,
- state, inode) == 6;
- } else {
- return sscanf(line, " %*d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x "
- "%*x:%*x %*X:%*X %*X %*d %*d %ld",
- &(l->s6_addr32[0]), &(l->s6_addr32[1]), &(l->s6_addr32[2]),
- &(l->s6_addr32[3]), l_port, &(r->s6_addr32[0]),
- &(r->s6_addr32[1]), &(r->s6_addr32[2]), &(r->s6_addr32[3]),
- r_port, state, inode) == 12;
+ long inode;
+ int path_pos;
+
+ if (sscanf(line, "%*p: %*X %*X %*X %*X %*X %lu %n", &inode, &path_pos) >= 1 &&
+ inode == sought_inode) {
+ char *name = chomp(line + path_pos);
+
+ strcpy(fi->type, "unix");
+ fi->name = strdup(*name ? name : "socket");
}
}
-static int find_ip_socket(struct file_info *fi, const char *path,
- int af, int type, long sought_inode)
+static void match_netlink(char *line, int af, char type, struct file_info *fi,
+ long sought_inode)
+{
+ unsigned state;
+ long inode;
+ char *netlink_states[] = {
+ "ROUTE", "UNUSED", "USERSOCK", "FIREWALL", "SOCK_DIAG", "NFLOG", "XFRM",
+ "SELINUX", "ISCSI", "AUDIT", "FIB_LOOKUP", "CONNECTOR", "NETFILTER",
+ "IP6_FW", "DNRTMSG", "KOBJECT_UEVENT", "GENERIC", "DM", "SCSITRANSPORT",
+ "ENCRYPTFS", "RDMA", "CRYPTO"
+ };
+
+ if (sscanf(line, "%*p %u %*u %*x %*u %*u %*u %*u %*u %lu",
+ &state, &inode) < 2 || inode != sought_inode) {
+ return;
+ }
+
+ strcpy(fi->type, "netlink");
+ fi->name =
+ strdup(state < ARRAY_LEN(netlink_states) ? netlink_states[state] : "?");
+}
+
+static void match_ip(char *line, int af, char type, struct file_info *fi,
+ long sought_inode)
{
- FILE *fp = fopen(path, "r");
- char *line = NULL;
- size_t line_length = 0;
char *tcp_states[] = {
"UNKNOWN", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1", "FIN_WAIT2",
"TIME_WAIT", "CLOSE", "CLOSE_WAIT", "LAST_ACK", "LISTEN", "CLOSING"
};
+ char local_ip[INET6_ADDRSTRLEN] = {0};
+ char remote_ip[INET6_ADDRSTRLEN] = {0};
+ struct in6_addr local, remote;
+ int local_port, remote_port, state;
+ long inode;
+ int ok;
- if (!fp) return 0;
-
- if (!getline(&line, &line_length, fp)) return 0; // Skip header.
-
- while (getline(&line, &line_length, fp) > 0) {
- struct in6_addr local, remote;
- int local_port, remote_port, state;
- long inode;
-
- if (ip_match(af, line, &local, &local_port, &remote, &remote_port,
- &state, &inode)) {
- if (inode == sought_inode) {
- char local_ip[INET6_ADDRSTRLEN] = {0};
- char remote_ip[INET6_ADDRSTRLEN] = {0};
-
- strcpy(fi->type, af == AF_INET ? "IPv4" : "IPv6");
- inet_ntop(af, &local, local_ip, sizeof(local_ip));
- inet_ntop(af, &remote, remote_ip, sizeof(remote_ip));
- if (type == SOCK_STREAM) {
- if (state < 0 || state > TCP_CLOSING) state = 0;
- fi->name = xmprintf(af == AF_INET ?
- "TCP %s:%d->%s:%d (%s)" :
- "TCP [%s]:%d->[%s]:%d (%s)",
- local_ip, local_port, remote_ip, remote_port,
- tcp_states[state]);
- } else {
- fi->name = xmprintf(af == AF_INET ?
- "%s %s:%d->%s:%d" : "%s [%s]:%d->[%s]:%d",
- type == SOCK_DGRAM ? "UDP" : "RAW",
- local_ip, local_port, remote_ip, remote_port);
- }
- break;
- }
- }
+ if (af == 4) {
+ ok = sscanf(line, " %*d: %x:%x %x:%x %x %*x:%*x %*X:%*X %*X %*d %*d %ld",
+ &(local.s6_addr32[0]), &local_port,
+ &(remote.s6_addr32[0]), &remote_port,
+ &state, &inode) == 6;
+ } else {
+ ok = sscanf(line, " %*d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x "
+ "%*x:%*x %*X:%*X %*X %*d %*d %ld",
+ &(local.s6_addr32[0]), &(local.s6_addr32[1]),
+ &(local.s6_addr32[2]), &(local.s6_addr32[3]),
+ &local_port,
+ &(remote.s6_addr32[0]), &(remote.s6_addr32[1]),
+ &(remote.s6_addr32[2]), &(remote.s6_addr32[3]),
+ &remote_port, &state, &inode) == 12;
+ }
+ if (!ok || inode != sought_inode) return;
+
+ strcpy(fi->type, af == 4 ? "IPv4" : "IPv6");
+ inet_ntop(af, &local, local_ip, sizeof(local_ip));
+ inet_ntop(af, &remote, remote_ip, sizeof(remote_ip));
+ if (type == 't') {
+ if (state < 0 || state > TCP_CLOSING) state = 0;
+ fi->name = xmprintf(af == 4 ?
+ "TCP %s:%d->%s:%d (%s)" :
+ "TCP [%s]:%d->[%s]:%d (%s)",
+ local_ip, local_port, remote_ip, remote_port,
+ tcp_states[state]);
+ } else {
+ fi->name = xmprintf(af == 4 ? "%s %s:%d->%s:%d" : "%s [%s]:%d->[%s]:%d",
+ type == 'u' ? "UDP" : "RAW",
+ local_ip, local_port, remote_ip, remote_port);
}
-
- free(line);
- fclose(fp);
-
- return fi->name != 0;
}
static int find_socket(struct file_info *fi, long inode)
{
- // TODO: other protocols (netlink).
- return find_unix_socket(fi, inode) ||
- find_ip_socket(fi, "/proc/net/tcp", AF_INET, SOCK_STREAM, inode) ||
- find_ip_socket(fi, "/proc/net/tcp6", AF_INET6, SOCK_STREAM, inode) ||
- find_ip_socket(fi, "/proc/net/udp", AF_INET, SOCK_DGRAM, inode) ||
- find_ip_socket(fi, "/proc/net/udp6", AF_INET6, SOCK_DGRAM, inode) ||
- find_ip_socket(fi, "/proc/net/raw", AF_INET, SOCK_RAW, inode) ||
- find_ip_socket(fi, "/proc/net/raw6", AF_INET6, SOCK_RAW, inode);
+ // TODO: other protocols (packet).
+ return scan_proc_net_file("/proc/net/tcp", 4, 't', match_ip, fi, inode) ||
+ scan_proc_net_file("/proc/net/tcp6", 6, 't', match_ip, fi, inode) ||
+ scan_proc_net_file("/proc/net/udp", 4, 'u', match_ip, fi, inode) ||
+ scan_proc_net_file("/proc/net/udp6", 6, 'u', match_ip, fi, inode) ||
+ scan_proc_net_file("/proc/net/raw", 4, 'r', match_ip, fi, inode) ||
+ scan_proc_net_file("/proc/net/raw6", 6, 'r', match_ip, fi, inode) ||
+ scan_proc_net_file("/proc/net/unix", 0, 0, match_unix, fi, inode) ||
+ scan_proc_net_file("/proc/net/netlink", 0, 0, match_netlink, fi, inode);
}
static void fill_stat(struct file_info *fi, const char* path)
@@ -269,8 +275,9 @@ static void fill_stat(struct file_info *fi, const char* path)
// Fill DEVICE.
dev = (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) ? sb.st_rdev : sb.st_dev;
- snprintf(fi->device, sizeof(fi->device), "%ld,%ld",
- (long)major(dev), (long)minor(dev));
+ if (!S_ISSOCK(sb.st_mode))
+ snprintf(fi->device, sizeof(fi->device), "%ld,%ld",
+ (long)major(dev), (long)minor(dev));
// Fill SIZE/OFF.
if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))