Skip to content

sockstat: Add automatic column sizing and remove -w option #1720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

daminrido139
Copy link

@daminrido139 daminrido139 commented Jun 12, 2025

Refactor sockstat to dynamically size table columns based on content.
This eliminates the need for the -w option, which is now ignored
for backwards compatibility.

Unknown fields are now consistently shown as "??" instead of a mix
of "", "?" and "?" for output uniformity.

Sponsored by: Google, LLC (GSoC 2025)
MFC after: 2 weeks

Copy link

github-actions bot commented Jun 12, 2025

Thank you for taking the time to contribute to FreeBSD!
There is an issue that needs to be fixed:

  • Missing Signed-off-by linesc0df8c6

@asomers
Copy link
Member

asomers commented Jun 16, 2025

The automatic column sizing works pretty well. But it isn't perfect. On my machine, with almost any options, sockets whose protocol is "stream (not connected)" will have misaligned columns. This is easiest to see with the "-l" option. It looks like the "(not connected)" part isn't contributing to the calculation of the width of the PROTO column. For example:

USER   COMMAND    PID   FD PROTO  LOCAL ADDRESS                FOREIGN ADDRESS
somers sshd-sessi 56573 7  stream (not connected)              ??                           ??             
root   sshd-sessi 56571 7  stream (not connected)              ??                           ??             
somers sshd-sessi 4084  7  stream (not connected)              ??                           ??             
root   sshd-sessi 4082  7  stream (not connected)              ??                           ??             
root   sshd       3974  7  tcp6   *:22                         *:*            
root   sshd       3974  8  tcp4   *:22                         *:*            
root   syslogd    2679  6  udp6   *:514                        *:*            
root   syslogd    2679  7  udp4   *:514                        *:*            
root   syslogd    2679  8  dgram  /var/run/log                  <-            
root   syslogd    2679  10 dgram  /var/run/logpriv             ??             
root   nfsuserd   2080  3  udp6   *:633                        *:*            
root   nfsuserd   2079  3  udp6   *:633                        *:*            
root   nfsuserd   2078  3  udp6   *:633                        *:*            
root   nfsuserd   2077  3  udp6   *:633                        *:*            
root   nfsuserd   2076  3  udp6   *:633                        *:*            
root   devd       1593  4  stream /var/run/devd.pipe           ??             
root   devd       1593  5  seqpac /var/run/devd.seqpacket.pipe ??             
??     ??         ??    ?? stream (not connected)              ??                           ??             

Also, there's another change that wasn't mentioned in the commit message. Is this deliberate?

  • Fields that were previously "" are now printed as "??".
  • Fields that were previously "?" for the USER, COMMAND, PID, and FD columns are now "??". Such sockets are most easily seen if NFS is in use.

@daminrido139
Copy link
Author

Thanks, @asomers,

You're absolutely right, "stream (not connected)" should be fully inside the PROTO column. I initially misunderstood and treated (not connected) as part of the LOCAL ADDRESS, but I’ll fix that and ensure the width calculation includes the full string.

Regarding the "??" change - yes, that was intentional. I wanted to make the output more uniform by using "??" for all unknown fields instead of mixing "" and "?". Sorry for not mentioning that in the commit message. happy to amend the commit if you prefer.

@asomers
Copy link
Member

asomers commented Jun 16, 2025

Thanks, @asomers,

You're absolutely right, "stream (not connected)" should be fully inside the PROTO column. I initially misunderstood and treated (not connected) as part of the LOCAL ADDRESS, but I’ll fix that and ensure the width calculation includes the full string.

Regarding the "??" change - yes, that was intentional. I wanted to make the output more uniform by using "??" for all unknown fields instead of mixing "" and "?". Sorry for not mentioning that in the commit message. happy to amend the commit if you prefer.

Using "??" uniformly is ok. The only risk is that it upsets some scripts that people use to parse sockstat's output with awk. But those scripts are fragile anyway. Using libxo would be much more reliable!

printf(" %-*s", cw->local_addr, "(not connected)");
strcpy(buf,"??");
if (laddr->address.ss_len > 0)
formataddr(&laddr->address, buf, sizeof(buf));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line will overwrite the "??" from line 1399. If you meant for line 1399 to be more like a default initializer, I suggest you move it below, with else. There are similar patterns elsewhere, like on line 1407-1409.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed!

@@ -1344,33 +1524,38 @@ display(void)
struct passwd *pwd;
struct file *xf;
struct sock *s;
int n, pos;
int n;
struct col_widths cw;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some spaces snuck in on these two lines. You should consistently indent with tabs.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed!

static void
calculate_column_widths(struct col_widths *cw)
{
cw->user = 4;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here you indented with spaces. Please change them all to tabs. See style(9) for a detailed description of how to format C code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed! Thanks for the reference.

cw->stack = TCP_FUNCTION_NAME_LEN_MAX;
cw->cc = TCP_CA_NAME_MAX;

char buf[512];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a lot of memory to put on the stack. Better to use malloc(). But in this case, you don't have to! It's possible to eliminate the need for buf entirely, but taking advantage of the fact that snprintf always returns the number of characters that it would've written if the buffer had been big enough. So just call len = snprintf(NULL, 0, ...) and remove all of the strlen lines.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed buf and strlen wherever possible by using len = snprintf(NULL, 0, ...) . Used malloc() instead of stack memory.

/* Remote peer we connect(2) to, if any. */
if (faddr->conn != 0) {
struct sock *p;
strcpy(buf, "-> ");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strcpy should almost always be avoided. Use strncpy, or better yet strlcpy.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced strcpy with strlcpy.

@daminrido139 daminrido139 force-pushed the gsoc-sockstat-libxo branch from 9761665 to 7c8ce27 Compare June 18, 2025 11:59
Refactor sockstat to dynamically size table columns based on content.
This eliminates the need for the -w option, which is now ignored
for backwards compatibility.

Unknown fields are now consistently shown as "??" instead of a mix
of "", "?" and "?" for output uniformity.

Sponsored by: Google, LLC (GSoC 2025)
MFC after: 2 weeks
@daminrido139 daminrido139 force-pushed the gsoc-sockstat-libxo branch from 7c8ce27 to c0df8c6 Compare June 20, 2025 13:45
Copy link
Member

@asomers asomers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pro tips:

  • Once a reviewer first looks at a PR, never force-push it. If you must amend
    it, leave your changes in a separate commit. That makes it easy for the
    reviewer to see what's changed since his first review.
  • Never merge the main branch into your PR branch. That can confuse the
    history and doesn't really solve any problems. Instead, better to leave the
    PR out-of-date unless it conflicts with the main branch. If you must resolve
    conflicts, it's better to rebase than to merge.

I'll come back tomorrow for a lengthier review. I'll have to re-review the entire thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants