ss: Drop list traversal from unix_stats_print()

Although this complicates the dedicated procfs-based code path in
unix_show() a bit, it's the only sane way to get rid of unix_show_sock()
output diverging from other socket types in that it prints all socket
details in a new line.

As a side effect, it allows to eliminate all procfs specific code in
the same function.

Signed-off-by: Phil Sutter <phil@nwl.cc>
This commit is contained in:
Phil Sutter 2016-12-02 11:39:50 +01:00 committed by Stephen Hemminger
parent 5f27ac1db9
commit 2d0e538f3e

121
misc/ss.c
View File

@ -3018,16 +3018,14 @@ int unix_state_map[] = { SS_CLOSE, SS_SYN_SENT,
#define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct sockstat))
static void unix_list_free(struct sockstat *list)
static void unix_list_drop_first(struct sockstat **list)
{
while (list) {
struct sockstat *s = list;
struct sockstat *s = *list;
list = list->next;
(*list) = (*list)->next;
free(s->name);
free(s);
}
}
static bool unix_type_skip(struct sockstat *s, struct filter *f)
{
@ -3045,61 +3043,18 @@ static bool unix_use_proc(void)
return getenv("PROC_NET_UNIX") || getenv("PROC_ROOT");
}
static void unix_stats_print(struct sockstat *list, struct filter *f)
static void unix_stats_print(struct sockstat *s, struct filter *f)
{
struct sockstat *s;
char *peer;
bool use_proc = unix_use_proc();
char port_name[30] = {};
for (s = list; s; s = s->next) {
if (!(f->states & (1 << s->state)))
continue;
if (unix_type_skip(s, f))
continue;
peer = "*";
if (s->peer_name)
peer = s->peer_name;
if (s->rport && use_proc) {
struct sockstat *p;
for (p = list; p; p = p->next) {
if (s->rport == p->lport)
break;
}
if (!p) {
peer = "?";
} else {
peer = p->name ? : "*";
}
}
if (use_proc && f->f) {
struct sockstat st = {
.local.family = AF_UNIX,
.remote.family = AF_UNIX,
};
memcpy(st.local.data, &s->name, sizeof(s->name));
if (strcmp(peer, "*"))
memcpy(st.remote.data, &peer, sizeof(peer));
if (run_ssfilter(f->f, &st) == 0)
continue;
}
sock_state_print(s);
sock_addr_print(s->name ?: "*", " ",
int_to_str(s->lport, port_name), NULL);
sock_addr_print(peer, " ", int_to_str(s->rport, port_name),
NULL);
sock_addr_print(s->peer_name ?: "*", " ",
int_to_str(s->rport, port_name), NULL);
proc_ctx_print(s);
printf("\n");
}
}
static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
@ -3148,8 +3103,6 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
unix_stats_print(&stat, f);
if (show_mem || show_details)
printf("\t");
if (show_mem)
print_skmeminfo(tb, UNIX_DIAG_MEMINFO);
if (show_details) {
@ -3160,7 +3113,6 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
}
}
if (show_mem || show_details)
printf("\n");
return 0;
@ -3252,6 +3204,11 @@ static int unix_show(struct filter *f)
if (u->type == SOCK_DGRAM && u->state == SS_CLOSE && u->rport)
u->state = SS_ESTABLISHED;
}
if (unix_type_skip(u, f) ||
!(f->states & (1 << u->state))) {
free(u);
continue;
}
if (!newformat) {
u->rport = 0;
@ -3259,6 +3216,42 @@ static int unix_show(struct filter *f)
u->wq = 0;
}
if (name[0]) {
u->name = strdup(name);
if (!u->name)
break;
}
if (u->rport) {
struct sockstat *p;
for (p = list; p; p = p->next) {
if (u->rport == p->lport)
break;
}
if (!p)
u->peer_name = "?";
else
u->peer_name = p->name ? : "*";
}
if (f->f) {
struct sockstat st = {
.local.family = AF_UNIX,
.remote.family = AF_UNIX,
};
memcpy(st.local.data, &u->name, sizeof(u->name));
if (strcmp(u->peer_name, "*"))
memcpy(st.remote.data, &u->peer_name,
sizeof(u->peer_name));
if (run_ssfilter(f->f, &st) == 0) {
free(u->name);
free(u);
continue;
}
}
insp = &list;
while (*insp) {
if (u->type < (*insp)->type ||
@ -3270,24 +3263,22 @@ static int unix_show(struct filter *f)
u->next = *insp;
*insp = u;
if (name[0]) {
if ((u->name = malloc(strlen(name)+1)) == NULL)
break;
strcpy(u->name, name);
}
if (++cnt > MAX_UNIX_REMEMBER) {
while (list) {
unix_stats_print(list, f);
unix_list_free(list);
list = NULL;
printf("\n");
unix_list_drop_first(&list);
}
cnt = 0;
}
}
fclose(fp);
if (list) {
while (list) {
unix_stats_print(list, f);
unix_list_free(list);
list = NULL;
cnt = 0;
printf("\n");
unix_list_drop_first(&list);
}
return 0;