ss: Fix rendering of continuous output (-E, --events)
Roman Mashak reported that ss currently shows no output when it should continuously report information about terminated sockets (-E, --events switch). This happens because I missed this case in691bd854bf("ss: Buffer raw fields first, then render them as a table") and the rendering function is simply not called. To fix this, we need to: - call render() every time we need to display new socket events from generic_show_sock(), which is only used to follow events. Always call it even if specific socket display functions return errors to ensure we clean up buffers - get the screen width every time we have new events to display, thus factor out getting the screen width from main() into a function we'll call whenever we calculate columns width - reset the current field pointer after rendering, more output might come after render() is called Reported-by: Roman Mashak <mrv@mojatatu.com> Fixes:691bd854bf("ss: Buffer raw fields first, then render them as a table") Signed-off-by: Stefano Brivio <sbrivio@redhat.com> Tested-by: Roman Mashak <mrv@mojatatu.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
This commit is contained in:
parent
79f49f58aa
commit
32ea3d54b4
61
misc/ss.c
61
misc/ss.c
|
|
@ -1106,15 +1106,33 @@ static void buf_free_all(void)
|
||||||
buffer.head = NULL;
|
buffer.head = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get current screen width, default to 80 columns if TIOCGWINSZ fails */
|
||||||
|
static int render_screen_width(void)
|
||||||
|
{
|
||||||
|
int width = 80;
|
||||||
|
|
||||||
|
if (isatty(STDOUT_FILENO)) {
|
||||||
|
struct winsize w;
|
||||||
|
|
||||||
|
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
|
||||||
|
if (w.ws_col > 0)
|
||||||
|
width = w.ws_col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate column width from contents length. If columns don't fit on one
|
/* Calculate column width from contents length. If columns don't fit on one
|
||||||
* line, break them into the least possible amount of lines and keep them
|
* line, break them into the least possible amount of lines and keep them
|
||||||
* aligned across lines. Available screen space is equally spread between fields
|
* aligned across lines. Available screen space is equally spread between fields
|
||||||
* as additional spacing.
|
* as additional spacing.
|
||||||
*/
|
*/
|
||||||
static void render_calc_width(int screen_width)
|
static void render_calc_width(void)
|
||||||
{
|
{
|
||||||
int first, len = 0, linecols = 0;
|
int screen_width = render_screen_width();
|
||||||
struct column *c, *eol = columns - 1;
|
struct column *c, *eol = columns - 1;
|
||||||
|
int first, len = 0, linecols = 0;
|
||||||
|
|
||||||
/* First pass: set width for each column to measured content length */
|
/* First pass: set width for each column to measured content length */
|
||||||
for (first = 1, c = columns; c - columns < COL_MAX; c++) {
|
for (first = 1, c = columns; c - columns < COL_MAX; c++) {
|
||||||
|
|
@ -1195,7 +1213,7 @@ newline:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Render buffered output with spacing and delimiters, then free up buffers */
|
/* Render buffered output with spacing and delimiters, then free up buffers */
|
||||||
static void render(int screen_width)
|
static void render(void)
|
||||||
{
|
{
|
||||||
struct buf_token *token;
|
struct buf_token *token;
|
||||||
int printed, line_started = 0;
|
int printed, line_started = 0;
|
||||||
|
|
@ -1209,7 +1227,7 @@ static void render(int screen_width)
|
||||||
/* Ensure end alignment of last token, it wasn't necessarily flushed */
|
/* Ensure end alignment of last token, it wasn't necessarily flushed */
|
||||||
buffer.tail->end += buffer.cur->len % 2;
|
buffer.tail->end += buffer.cur->len % 2;
|
||||||
|
|
||||||
render_calc_width(screen_width);
|
render_calc_width();
|
||||||
|
|
||||||
/* Rewind and replay */
|
/* Rewind and replay */
|
||||||
buffer.tail = buffer.head;
|
buffer.tail = buffer.head;
|
||||||
|
|
@ -1245,6 +1263,7 @@ static void render(int screen_width)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf_free_all();
|
buf_free_all();
|
||||||
|
current_field = columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sock_state_print(struct sockstat *s)
|
static void sock_state_print(struct sockstat *s)
|
||||||
|
|
@ -4264,23 +4283,33 @@ static int generic_show_sock(const struct sockaddr_nl *addr,
|
||||||
{
|
{
|
||||||
struct sock_diag_msg *r = NLMSG_DATA(nlh);
|
struct sock_diag_msg *r = NLMSG_DATA(nlh);
|
||||||
struct inet_diag_arg inet_arg = { .f = arg, .protocol = IPPROTO_MAX };
|
struct inet_diag_arg inet_arg = { .f = arg, .protocol = IPPROTO_MAX };
|
||||||
|
int ret;
|
||||||
|
|
||||||
switch (r->sdiag_family) {
|
switch (r->sdiag_family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
inet_arg.rth = inet_arg.f->rth_for_killing;
|
inet_arg.rth = inet_arg.f->rth_for_killing;
|
||||||
return show_one_inet_sock(addr, nlh, &inet_arg);
|
ret = show_one_inet_sock(addr, nlh, &inet_arg);
|
||||||
|
break;
|
||||||
case AF_UNIX:
|
case AF_UNIX:
|
||||||
return unix_show_sock(addr, nlh, arg);
|
ret = unix_show_sock(addr, nlh, arg);
|
||||||
|
break;
|
||||||
case AF_PACKET:
|
case AF_PACKET:
|
||||||
return packet_show_sock(addr, nlh, arg);
|
ret = packet_show_sock(addr, nlh, arg);
|
||||||
|
break;
|
||||||
case AF_NETLINK:
|
case AF_NETLINK:
|
||||||
return netlink_show_sock(addr, nlh, arg);
|
ret = netlink_show_sock(addr, nlh, arg);
|
||||||
|
break;
|
||||||
case AF_VSOCK:
|
case AF_VSOCK:
|
||||||
return vsock_show_sock(addr, nlh, arg);
|
ret = vsock_show_sock(addr, nlh, arg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render();
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_follow_request(struct filter *f)
|
static int handle_follow_request(struct filter *f)
|
||||||
|
|
@ -4647,7 +4676,6 @@ int main(int argc, char *argv[])
|
||||||
FILE *filter_fp = NULL;
|
FILE *filter_fp = NULL;
|
||||||
int ch;
|
int ch;
|
||||||
int state_filter = 0;
|
int state_filter = 0;
|
||||||
int screen_width = 80;
|
|
||||||
|
|
||||||
while ((ch = getopt_long(argc, argv,
|
while ((ch = getopt_long(argc, argv,
|
||||||
"dhaletuwxnro460spbEf:miA:D:F:vVzZN:KHS",
|
"dhaletuwxnro460spbEf:miA:D:F:vVzZN:KHS",
|
||||||
|
|
@ -4949,15 +4977,6 @@ int main(int argc, char *argv[])
|
||||||
if (!(current_filter.states & (current_filter.states - 1)))
|
if (!(current_filter.states & (current_filter.states - 1)))
|
||||||
columns[COL_STATE].disabled = 1;
|
columns[COL_STATE].disabled = 1;
|
||||||
|
|
||||||
if (isatty(STDOUT_FILENO)) {
|
|
||||||
struct winsize w;
|
|
||||||
|
|
||||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
|
|
||||||
if (w.ws_col > 0)
|
|
||||||
screen_width = w.ws_col;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (show_header)
|
if (show_header)
|
||||||
print_header();
|
print_header();
|
||||||
|
|
||||||
|
|
@ -4988,7 +5007,7 @@ int main(int argc, char *argv[])
|
||||||
if (show_users || show_proc_ctx || show_sock_ctx)
|
if (show_users || show_proc_ctx || show_sock_ctx)
|
||||||
user_ent_destroy();
|
user_ent_destroy();
|
||||||
|
|
||||||
render(screen_width);
|
render();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue