Commit ab01dbbb authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Stephen Hemminger

Fix ss to handle partial records.

Output from /proc may include partial records, so rather than
trying to be sexy and do own parsing, just use stdio.
Signed-off-by: default avatarStephen Hemminger <shemminger@linux-foundation.org>
parent 0ac34704
...@@ -112,89 +112,86 @@ struct filter default_filter = { ...@@ -112,89 +112,86 @@ struct filter default_filter = {
struct filter current_filter; struct filter current_filter;
int generic_proc_open(char *env, char *name) static FILE *generic_proc_open(const char *env, const char *name)
{ {
const char *p = getenv(env);
char store[128]; char store[128];
char *p = getenv(env);
if (!p) { if (!p) {
p = getenv("PROC_ROOT") ? : "/proc"; p = getenv("PROC_ROOT") ? : "/proc";
snprintf(store, sizeof(store)-1, "%s/%s", p, name); snprintf(store, sizeof(store)-1, "%s/%s", p, name);
p = store; p = store;
} }
return open(p, O_RDONLY);
return fopen(p, "r");
} }
int net_tcp_open(void) static FILE *net_tcp_open(void)
{ {
return generic_proc_open("PROC_NET_TCP", "net/tcp"); return generic_proc_open("PROC_NET_TCP", "net/tcp");
} }
int net_tcp6_open(void) static FILE *net_tcp6_open(void)
{ {
return generic_proc_open("PROC_NET_TCP6", "net/tcp6"); return generic_proc_open("PROC_NET_TCP6", "net/tcp6");
} }
int net_udp_open(void) static FILE *net_udp_open(void)
{ {
return generic_proc_open("PROC_NET_UDP", "net/udp"); return generic_proc_open("PROC_NET_UDP", "net/udp");
} }
int net_udp6_open(void) static FILE *net_udp6_open(void)
{ {
return generic_proc_open("PROC_NET_UDP6", "net/udp6"); return generic_proc_open("PROC_NET_UDP6", "net/udp6");
} }
int net_raw_open(void) static FILE *net_raw_open(void)
{ {
return generic_proc_open("PROC_NET_RAW", "net/raw"); return generic_proc_open("PROC_NET_RAW", "net/raw");
} }
int net_raw6_open(void) static FILE *net_raw6_open(void)
{ {
return generic_proc_open("PROC_NET_RAW6", "net/raw6"); return generic_proc_open("PROC_NET_RAW6", "net/raw6");
} }
int net_unix_open(void) static FILE *net_unix_open(void)
{ {
return generic_proc_open("PROC_NET_UNIX", "net/unix"); return generic_proc_open("PROC_NET_UNIX", "net/unix");
} }
int net_packet_open(void) static FILE *net_packet_open(void)
{ {
return generic_proc_open("PROC_NET_PACKET", "net/packet"); return generic_proc_open("PROC_NET_PACKET", "net/packet");
} }
int net_netlink_open(void) static FILE *net_netlink_open(void)
{ {
return generic_proc_open("PROC_NET_NETLINK", "net/netlink"); return generic_proc_open("PROC_NET_NETLINK", "net/netlink");
} }
int slabinfo_open(void) static FILE *slabinfo_open(void)
{ {
return generic_proc_open("PROC_SLABINFO", "slabinfo"); return generic_proc_open("PROC_SLABINFO", "slabinfo");
} }
int net_sockstat_open(void) static FILE *net_sockstat_open(void)
{ {
return generic_proc_open("PROC_NET_SOCKSTAT", "net/sockstat"); return generic_proc_open("PROC_NET_SOCKSTAT", "net/sockstat");
} }
int net_sockstat6_open(void) static FILE *net_sockstat6_open(void)
{ {
return generic_proc_open("PROC_NET_SOCKSTAT6", "net/sockstat6"); return generic_proc_open("PROC_NET_SOCKSTAT6", "net/sockstat6");
} }
int net_snmp_open(void) static FILE *net_snmp_open(void)
{ {
return generic_proc_open("PROC_NET_SNMP", "net/snmp"); return generic_proc_open("PROC_NET_SNMP", "net/snmp");
} }
int net_netstat_open(void) static FILE *ephemeral_ports_open(void)
{
return generic_proc_open("PROC_NET_NETSTAT", "net/netstat");
}
int ephemeral_ports_open(void)
{ {
return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range"); return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range");
} }
...@@ -313,7 +310,8 @@ int get_slabstat(struct slabstat *s) ...@@ -313,7 +310,8 @@ int get_slabstat(struct slabstat *s)
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
if ((fp = fdopen(slabinfo_open(), "r")) == NULL) fp = slabinfo_open();
if (!fp)
return -1; return -1;
cnt = sizeof(*s)/sizeof(int); cnt = sizeof(*s)/sizeof(int);
...@@ -478,7 +476,7 @@ static int ip_local_port_min, ip_local_port_max; ...@@ -478,7 +476,7 @@ static int ip_local_port_min, ip_local_port_max;
static int is_ephemeral(int port) static int is_ephemeral(int port)
{ {
if (!ip_local_port_min) { if (!ip_local_port_min) {
FILE *f = fdopen(ephemeral_ports_open(), "r"); FILE *f = ephemeral_ports_open();
if (f) { if (f) {
fscanf(f, "%d %d", fscanf(f, "%d %d",
&ip_local_port_min, &ip_local_port_max); &ip_local_port_min, &ip_local_port_max);
...@@ -655,7 +653,7 @@ int run_ssfilter(struct ssfilter *f, struct tcpstat *s) ...@@ -655,7 +653,7 @@ int run_ssfilter(struct ssfilter *f, struct tcpstat *s)
return s->lport < 0; return s->lport < 0;
if (!low) { if (!low) {
FILE *fp = fdopen(ephemeral_ports_open(), "r"); FILE *fp = ephemeral_ports_open();
if (fp) { if (fp) {
fscanf(fp, "%d%d", &low, &high); fscanf(fp, "%d%d", &low, &high);
fclose(fp); fclose(fp);
...@@ -1103,7 +1101,7 @@ void *parse_hostcond(char *addr) ...@@ -1103,7 +1101,7 @@ void *parse_hostcond(char *addr)
return res; return res;
} }
static int tcp_show_line(char *line, struct filter *f, int family) static int tcp_show_line(char *line, const struct filter *f, int family)
{ {
struct tcpstat s; struct tcpstat s;
char *loc, *rem, *data; char *loc, *rem, *data;
...@@ -1225,68 +1223,30 @@ static int tcp_show_line(char *line, struct filter *f, int family) ...@@ -1225,68 +1223,30 @@ static int tcp_show_line(char *line, struct filter *f, int family)
return 0; return 0;
} }
static int generic_record_read(int fd, char *buf, int bufsize, static int generic_record_read(FILE *fp,
int (*worker)(char*, struct filter *, int), int (*worker)(char*, const struct filter *, int),
struct filter *f, int fam) const struct filter *f, int fam)
{ {
int n; char line[256];
int recsize;
int eof = 0;
char *p;
/* Load the first chunk and calculate record length from it. */ /* skip header */
n = read(fd, buf, bufsize); if (fgets(line, sizeof(line), fp) == NULL)
if (n < 0)
goto outerr; goto outerr;
/* I _know_ that this is wrong, do not remind. :-)
* But this works nowadays. */ while (fgets(line, sizeof(line), fp) != NULL) {
if (n < bufsize) int n = strlen(line);
eof = 1; if (n == 0 || line[n-1] != '\n') {
p = memchr(buf, '\n', n); errno = -EINVAL;
if (p == NULL || (p-buf) >= n) return -1;
goto outwrongformat;
recsize = (p-buf)+1;
p = buf+recsize;
for (;;) {
while ((p+recsize) - buf <= n) {
if (p[recsize-1] != '\n')
goto outwrongformat;
p[recsize-1] = 0;
if (worker(p, f, fam) < 0)
goto done;
p += recsize;
}
if (!eof) {
int remains = (buf+bufsize) - p;
memcpy(buf, p, remains);
p = buf+remains;
n = read(fd, p, (buf+bufsize) - p);
if (n < 0)
goto outerr;
if (n < (buf+bufsize) - p) {
eof = 1;
if (n == 0) {
if (remains)
goto outwrongformat;
goto done;
}
}
n += remains;
p = buf;
} else {
if (p != buf+n)
goto outwrongformat;
goto done;
} }
} line[n-1] = 0;
done:
return 0;
outwrongformat: if (worker(line, f, fam) < 0)
errno = EINVAL; return 0;
}
outerr: outerr:
return -1;
return ferror(fp) ? -1 : 0;
} }
static char *sprint_bw(char *buf, double bw) static char *sprint_bw(char *buf, double bw)
...@@ -1384,7 +1344,7 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r) ...@@ -1384,7 +1344,7 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r)
} }
} }
int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f) static int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
{ {
struct inet_diag_msg *r = NLMSG_DATA(nlh); struct inet_diag_msg *r = NLMSG_DATA(nlh);
struct tcpstat s; struct tcpstat s;
...@@ -1447,7 +1407,7 @@ int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f) ...@@ -1447,7 +1407,7 @@ int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
return 0; return 0;
} }
int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype) static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
{ {
int fd; int fd;
struct sockaddr_nl nladdr; struct sockaddr_nl nladdr;
...@@ -1581,7 +1541,7 @@ skip_it: ...@@ -1581,7 +1541,7 @@ skip_it:
return 0; return 0;
} }
int tcp_show_netlink_file(struct filter *f) static int tcp_show_netlink_file(struct filter *f)
{ {
FILE *fp; FILE *fp;
char buf[8192]; char buf[8192];
...@@ -1637,9 +1597,9 @@ int tcp_show_netlink_file(struct filter *f) ...@@ -1637,9 +1597,9 @@ int tcp_show_netlink_file(struct filter *f)
} }
} }
int tcp_show(struct filter *f, int socktype) static int tcp_show(struct filter *f, int socktype)
{ {
int fd = -1; FILE *fp = NULL;
char *buf = NULL; char *buf = NULL;
int bufsize = 64*1024; int bufsize = 64*1024;
...@@ -1654,6 +1614,7 @@ int tcp_show(struct filter *f, int socktype) ...@@ -1654,6 +1614,7 @@ int tcp_show(struct filter *f, int socktype)
/* Sigh... We have to parse /proc/net/tcp... */ /* Sigh... We have to parse /proc/net/tcp... */
/* Estimate amount of sockets and try to allocate /* Estimate amount of sockets and try to allocate
* huge buffer to read all the table at one read. * huge buffer to read all the table at one read.
* Limit it by 16MB though. The assumption is: as soon as * Limit it by 16MB though. The assumption is: as soon as
...@@ -1681,18 +1642,21 @@ int tcp_show(struct filter *f, int socktype) ...@@ -1681,18 +1642,21 @@ int tcp_show(struct filter *f, int socktype)
} }
if (f->families & (1<<AF_INET)) { if (f->families & (1<<AF_INET)) {
if ((fd = net_tcp_open()) < 0) if ((fp = net_tcp_open()) < 0)
goto outerr; goto outerr;
if (generic_record_read(fd, buf, bufsize, tcp_show_line, f, AF_INET))
setbuffer(fp, buf, bufsize);
if (generic_record_read(fp, tcp_show_line, f, AF_INET))
goto outerr; goto outerr;
close(fd); fclose(fp);
} }
if ((f->families & (1<<AF_INET6)) && if ((f->families & (1<<AF_INET6)) &&
(fd = net_tcp6_open()) >= 0) { (fp = net_tcp6_open()) >= 0) {
if (generic_record_read(fd, buf, bufsize, tcp_show_line, f, AF_INET6)) setbuffer(fp, buf, bufsize);
if (generic_record_read(fp, tcp_show_line, f, AF_INET6))
goto outerr; goto outerr;
close(fd); fclose(fp);
} }
free(buf); free(buf);
...@@ -1703,15 +1667,15 @@ outerr: ...@@ -1703,15 +1667,15 @@ outerr:
int saved_errno = errno; int saved_errno = errno;
if (buf) if (buf)
free(buf); free(buf);
if (fd >= 0) if (fp)
close(fd); fclose(fp);
errno = saved_errno; errno = saved_errno;
return -1; return -1;
} while (0); } while (0);
} }
int dgram_show_line(char *line, struct filter *f, int family) int dgram_show_line(char *line, const struct filter *f, int family)
{ {
struct tcpstat s; struct tcpstat s;
char *loc, *rem, *data; char *loc, *rem, *data;
...@@ -1805,33 +1769,31 @@ int dgram_show_line(char *line, struct filter *f, int family) ...@@ -1805,33 +1769,31 @@ int dgram_show_line(char *line, struct filter *f, int family)
int udp_show(struct filter *f) int udp_show(struct filter *f)
{ {
int fd = -1; FILE *fp = NULL;
char buf[8192];
int bufsize = sizeof(buf);
dg_proto = UDP_PROTO; dg_proto = UDP_PROTO;
if (f->families&(1<<AF_INET)) { if (f->families&(1<<AF_INET)) {
if ((fd = net_udp_open()) < 0) if ((fp = net_udp_open()) < 0)
goto outerr; goto outerr;
if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET)) if (generic_record_read(fp, dgram_show_line, f, AF_INET))
goto outerr; goto outerr;
close(fd); fclose(fp);
} }
if ((f->families&(1<<AF_INET6)) && if ((f->families&(1<<AF_INET6)) &&
(fd = net_udp6_open()) >= 0) { (fp = net_udp6_open()) >= 0) {
if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET6)) if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
goto outerr; goto outerr;
close(fd); fclose(fp);
} }
return 0; return 0;
outerr: outerr:
do { do {
int saved_errno = errno; int saved_errno = errno;
if (fd >= 0) if (fp)
close(fd); fclose(fp);
errno = saved_errno; errno = saved_errno;
return -1; return -1;
} while (0); } while (0);
...@@ -1839,33 +1801,31 @@ outerr: ...@@ -1839,33 +1801,31 @@ outerr:
int raw_show(struct filter *f) int raw_show(struct filter *f)
{ {
int fd = -1; FILE *fp = NULL;
char buf[8192];
int bufsize = sizeof(buf);
dg_proto = RAW_PROTO; dg_proto = RAW_PROTO;
if (f->families&(1<<AF_INET)) { if (f->families&(1<<AF_INET)) {
if ((fd = net_raw_open()) < 0) if ((fp = net_raw_open()) < 0)
goto outerr; goto outerr;
if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET)) if (generic_record_read(fp, dgram_show_line, f, AF_INET))
goto outerr; goto outerr;
close(fd); fclose(fp);
} }
if ((f->families&(1<<AF_INET6)) && if ((f->families&(1<<AF_INET6)) &&
(fd = net_raw6_open()) >= 0) { (fp = net_raw6_open()) >= 0) {
if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET6)) if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
goto outerr; goto outerr;
close(fd); fclose(fp);
} }
return 0; return 0;
outerr: outerr:
do { do {
int saved_errno = errno; int saved_errno = errno;
if (fd >= 0) if (fp)
close(fd); fclose(fp);
errno = saved_errno; errno = saved_errno;
return -1; return -1;
} while (0); } while (0);
...@@ -1970,7 +1930,7 @@ int unix_show(struct filter *f) ...@@ -1970,7 +1930,7 @@ int unix_show(struct filter *f)
int cnt; int cnt;
struct unixstat *list = NULL; struct unixstat *list = NULL;
if ((fp = fdopen(net_unix_open(), "r")) == NULL) if ((fp = net_unix_open()) == NULL)
return -1; return -1;
fgets(buf, sizeof(buf)-1, fp); fgets(buf, sizeof(buf)-1, fp);
...@@ -2058,7 +2018,7 @@ int packet_show(struct filter *f) ...@@ -2058,7 +2018,7 @@ int packet_show(struct filter *f)
if (!(f->states & (1<<SS_CLOSE))) if (!(f->states & (1<<SS_CLOSE)))
return 0; return 0;
if ((fp = fdopen(net_packet_open(), "r")) == NULL) if ((fp = net_packet_open()) == NULL)
return -1; return -1;
fgets(buf, sizeof(buf)-1, fp); fgets(buf, sizeof(buf)-1, fp);
...@@ -2131,7 +2091,7 @@ int netlink_show(struct filter *f) ...@@ -2131,7 +2091,7 @@ int netlink_show(struct filter *f)
if (!(f->states & (1<<SS_CLOSE))) if (!(f->states & (1<<SS_CLOSE)))
return 0; return 0;
if ((fp = fdopen(net_netlink_open(), "r")) == NULL) if ((fp = net_netlink_open()) == NULL)
return -1; return -1;
fgets(buf, sizeof(buf)-1, fp); fgets(buf, sizeof(buf)-1, fp);
...@@ -2217,7 +2177,7 @@ int get_snmp_int(char *proto, char *key, int *result) ...@@ -2217,7 +2177,7 @@ int get_snmp_int(char *proto, char *key, int *result)
*result = 0; *result = 0;
if ((fp = fdopen(net_snmp_open(), "r")) == NULL) if ((fp = net_snmp_open()) == NULL)
return -1; return -1;
while (fgets(buf, sizeof(buf), fp) != NULL) { while (fgets(buf, sizeof(buf), fp) != NULL) {
...@@ -2310,13 +2270,13 @@ int get_sockstat(struct sockstat *s) ...@@ -2310,13 +2270,13 @@ int get_sockstat(struct sockstat *s)
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
if ((fp = fdopen(net_sockstat_open(), "r")) == NULL) if ((fp = net_sockstat_open()) == NULL)
return -1; return -1;
while(fgets(buf, sizeof(buf), fp) != NULL) while(fgets(buf, sizeof(buf), fp) != NULL)
get_sockstat_line(buf, s); get_sockstat_line(buf, s);
fclose(fp); fclose(fp);
if ((fp = fdopen(net_sockstat6_open(), "r")) == NULL) if ((fp = net_sockstat6_open()) == NULL)
return 0; return 0;
while(fgets(buf, sizeof(buf), fp) != NULL) while(fgets(buf, sizeof(buf), fp) != NULL)
get_sockstat_line(buf, s); get_sockstat_line(buf, s);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment