Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 3 Aug 2023 12:51:10 GMT
From:      Mike Karels <karels@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 193f782e525e - stable/12 - netstat -i: compute most field widths dynamically
Message-ID:  <202308031251.373CpATv067049@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by karels:

URL: https://cgit.FreeBSD.org/src/commit/?id=193f782e525ed56939c97852f07244b587ab529d

commit 193f782e525ed56939c97852f07244b587ab529d
Author:     Mike Karels <karels@FreeBSD.org>
AuthorDate: 2023-07-26 15:56:52 +0000
Commit:     Mike Karels <karels@FreeBSD.org>
CommitDate: 2023-08-03 12:50:15 +0000

    netstat -i: compute most field widths dynamically
    
    The network and address fields were sometimes truncated for netstat -i
    without -W, and often much too wide for netstat -i with the -W option.
    Fields such as normal packet counts often overflowed.  As a result,
    columns didn't line up, and large white spaces made it harder to
    follow a line across the display.  Change the code to compute the
    required field sizes for network, address, and various packet counts.
    Hoist the code to format network and address into a subroutine that
    can be called twice, once to measure the required field widths,
    and once to emit the values.  Use separate field widths for input
    and output packets, byte counts, and error and drop counters.
    These are left at defaults (the preceding values) with the -h
    option, in which case the fields have a limited total width.
    An extra space is included between the Network and Address, which
    otherwise seemed too close.
    
    Change the mention of -W with -i in the man page to say that most
    field widths are computed dynamically in this case.
    
    Reviewed by:    sjg, glebius
    Differential Revision:  https://reviews.freebsd.org/D41160
    
    (cherry picked from commit 372e3d561d82aba7a66fcd4ecb49a4d0a9f69345)
---
 usr.bin/netstat/if.c      | 217 ++++++++++++++++++++++++++++++----------------
 usr.bin/netstat/netstat.1 |   3 +
 2 files changed, 143 insertions(+), 77 deletions(-)

diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
index 5ba4f3afc67b..e08a0462d56d 100644
--- a/usr.bin/netstat/if.c
+++ b/usr.bin/netstat/if.c
@@ -265,6 +265,99 @@ next_ifma(struct ifmaddrs *ifma, const char *name, const sa_family_t family)
 	return (ifma);
 }
 
+enum process_op { MEASURE, EMIT };
+
+static void
+process_ifa_addr(enum process_op op, struct ifaddrs *ifa, int *max_net_len,
+    int *max_addr_len, bool *network, bool *link)
+{
+	int net_len, addr_len;
+	const char *nn, *rn;
+
+	if (op == EMIT) {
+		net_len = *max_net_len;
+		addr_len = *max_addr_len;
+	}
+
+	switch (ifa->ifa_addr->sa_family) {
+	case AF_UNSPEC:
+		if (op == MEASURE) {
+			net_len = strlen("none");
+			addr_len = strlen("none");
+		} else {
+			xo_emit("{:network/%-*.*s}  ", net_len, net_len,
+			    "none");
+			xo_emit("{:address/%-*.*s} ", addr_len, addr_len,
+			    "none");
+		}
+		break;
+	case AF_INET:
+#ifdef INET6
+	case AF_INET6:
+#endif /* INET6 */
+		nn = netname(ifa->ifa_addr, ifa->ifa_netmask);
+		rn = routename(ifa->ifa_addr, numeric_addr);
+		if (op == MEASURE) {
+			net_len = strlen(nn);
+			addr_len = strlen(rn);
+		} else {
+			xo_emit("{t:network/%-*s}  ", net_len, nn);
+			xo_emit("{t:address/%-*s} ", addr_len, rn);
+		}
+
+		if (network != NULL)
+			*network = true;
+		break;
+	case AF_LINK:
+	    {
+		struct sockaddr_dl *sdl;
+		char linknum[sizeof("<Link#32767>")];
+
+		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+		snprintf(linknum, sizeof(linknum), "<Link#%d>", sdl->sdl_index);
+		if (op == MEASURE) {
+			net_len = strlen(linknum);
+			if (sdl->sdl_nlen == 0 &&
+			    sdl->sdl_alen == 0 &&
+			    sdl->sdl_slen == 0)
+				addr_len = 1;
+			else
+				addr_len = strlen(routename(ifa->ifa_addr, 1));
+		} else {
+			xo_emit("{t:network/%-*.*s}  ", net_len, net_len,
+			    linknum);
+			if (sdl->sdl_nlen == 0 &&
+			    sdl->sdl_alen == 0 &&
+			    sdl->sdl_slen == 0)
+				xo_emit("{P:/%*s} ", addr_len, "");
+			else
+				xo_emit("{t:address/%-*.*s} ", addr_len,
+				    addr_len, routename(ifa->ifa_addr, 1));
+		}
+		if (link != NULL)
+			*link = true;
+		break;
+	    }
+	}
+
+	if (op == MEASURE) {
+		if (net_len > *max_net_len)
+			*max_net_len = net_len;
+		if (addr_len > *max_addr_len)
+			*max_addr_len = addr_len;
+	}
+}
+
+static int
+max_num_len(int max_len, u_long num)
+{
+	int len = 2;		/* include space */
+
+	for (; num > 10; len++)
+		num /= 10;
+	return (MAX(max_len, len));
+}
+
 /*
  * Print a description of the network interfaces.
  */
@@ -274,7 +367,8 @@ intpr(void (*pfunc)(char *), int af)
 	struct ifaddrs *ifap, *ifa;
 	struct ifmaddrs *ifmap, *ifma;
 	u_int ifn_len_max = 5, ifn_len;
-	u_int has_ipv6 = 0, net_len = 13, addr_len = 17;
+	u_int net_len = strlen("Network "), addr_len = strlen("Address ");
+	u_int npkt_len = 8, nbyte_len = 10, nerr_len = 5;
 
 	if (interval)
 		return sidewaysintpr();
@@ -294,39 +388,51 @@ intpr(void (*pfunc)(char *), int af)
 		if ((ifa->ifa_flags & IFF_UP) == 0)
 			++ifn_len;
 		ifn_len_max = MAX(ifn_len_max, ifn_len);
-		if (ifa->ifa_addr->sa_family == AF_INET6)
-			has_ipv6 = 1;
-	}
-	if (Wflag) {
-		if (has_ipv6) {
-			net_len = 24;
-			addr_len = 39;
-		} else
-			net_len = 18;
+		process_ifa_addr(MEASURE, ifa, &net_len, &addr_len,
+		    NULL, NULL);
+
+#define	IFA_STAT(s)	(((struct if_data *)ifa->ifa_data)->ifi_ ## s)
+		if (!hflag) {
+			npkt_len = max_num_len(npkt_len, IFA_STAT(ipackets));
+			npkt_len = max_num_len(npkt_len, IFA_STAT(opackets));
+			nerr_len = max_num_len(nerr_len, IFA_STAT(ierrors));
+			nerr_len = max_num_len(nerr_len, IFA_STAT(iqdrops));
+			nerr_len = max_num_len(nerr_len, IFA_STAT(collisions));
+			if (dflag)
+				nerr_len = max_num_len(nerr_len,
+				    IFA_STAT(oqdrops));
+			if (bflag) {
+				nbyte_len = max_num_len(nbyte_len,
+				    IFA_STAT(ibytes));
+				nbyte_len = max_num_len(nbyte_len,
+				    IFA_STAT(obytes));
+			}
+		}
 	}
 
 	xo_open_list("interface");
 	if (!pfunc) {
 		xo_emit("{T:/%-*.*s}", ifn_len_max, ifn_len_max, "Name");
-		xo_emit(" {T:/%5.5s} {T:/%-*.*s} {T:/%-*.*s} {T:/%8.8s} "
-		    "{T:/%5.5s} {T:/%5.5s}",
+		xo_emit(" {T:/%5.5s} {T:/%-*.*s}  {T:/%-*.*s} {T:/%*.*s} "
+		    "{T:/%*.*s} {T:/%*.*s}",
 		    "Mtu", net_len, net_len, "Network", addr_len, addr_len,
-		    "Address", "Ipkts", "Ierrs", "Idrop");
+		    "Address", npkt_len, npkt_len, "Ipkts",
+		    nerr_len, nerr_len, "Ierrs", nerr_len, nerr_len, "Idrop");
 		if (bflag)
-			xo_emit(" {T:/%10.10s}","Ibytes");
-		xo_emit(" {T:/%8.8s} {T:/%5.5s}", "Opkts", "Oerrs");
+			xo_emit(" {T:/%*.*s}", nbyte_len, nbyte_len, "Ibytes");
+		xo_emit(" {T:/%*.*s} {T:/%*.*s}", npkt_len, npkt_len, "Opkts",
+		    nerr_len, nerr_len, "Oerrs");
 		if (bflag)
-			xo_emit(" {T:/%10.10s}","Obytes");
-		xo_emit(" {T:/%5s}", "Coll");
+			xo_emit(" {T:/%*.*s}", nbyte_len, nbyte_len, "Obytes");
+		xo_emit(" {T:/%*s}", nerr_len, "Coll");
 		if (dflag)
-			xo_emit(" {T:/%5.5s}", "Drop");
+			xo_emit(" {T:/%*.*s}", nerr_len, nerr_len, "Drop");
 		xo_emit("\n");
 	}
 
 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
 		bool network = false, link = false;
 		char *name, *xname, buf[IFNAMSIZ+1];
-		const char *nn, *rn;
 
 		if (interface != NULL && strcmp(ifa->ifa_name, interface) != 0)
 			continue;
@@ -367,72 +473,29 @@ intpr(void (*pfunc)(char *), int af)
 		show_stat("lu", 6, "mtu", IFA_MTU(ifa), IFA_MTU(ifa), 0);
 #undef IFA_MTU
 
-		switch (ifa->ifa_addr->sa_family) {
-		case AF_UNSPEC:
-			xo_emit("{:network/%-*.*s} ", net_len, net_len,
-			    "none");
-			xo_emit("{:address/%-*.*s} ", addr_len, addr_len,
-			    "none");
-			break;
-		case AF_INET:
-#ifdef INET6
-		case AF_INET6:
-#endif /* INET6 */
-			nn = netname(ifa->ifa_addr, ifa->ifa_netmask);
-			rn = routename(ifa->ifa_addr, numeric_addr);
-			if (Wflag) {
-				xo_emit("{t:network/%-*s} ", net_len, nn);
-				xo_emit("{t:address/%-*s} ", addr_len, rn);
-			} else {
-				xo_emit("{d:network/%-*.*s}{et:network} ",
-				    net_len, net_len, nn, nn);
-				xo_emit("{d:address/%-*.*s}{et:address} ",
-				    addr_len, addr_len, rn, rn);
-			}
-
-			network = true;
-			break;
-		case AF_LINK:
-		    {
-			struct sockaddr_dl *sdl;
-			char linknum[sizeof("<Link#32767>")];
-
-			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
-			snprintf(linknum, sizeof(linknum), "<Link#%d>", sdl->sdl_index);
-			xo_emit("{t:network/%-*.*s} ", net_len, net_len,
-			    linknum);
-			if (sdl->sdl_nlen == 0 &&
-			    sdl->sdl_alen == 0 &&
-			    sdl->sdl_slen == 0)
-				xo_emit("{P:/%*s} ", addr_len, "");
-			else
-				xo_emit("{t:address/%-*.*s} ", addr_len,
-				    addr_len, routename(ifa->ifa_addr, 1));
-			link = true;
-			break;
-		    }
-		}
+		process_ifa_addr(EMIT, ifa, &net_len, &addr_len,
+		    &network, &link);
 
-#define	IFA_STAT(s)	(((struct if_data *)ifa->ifa_data)->ifi_ ## s)
-		show_stat("lu", 8, "received-packets", IFA_STAT(ipackets),
-		    link|network, 1);
-		show_stat("lu", 5, "received-errors", IFA_STAT(ierrors),
+		show_stat("lu", npkt_len, "received-packets",
+		    IFA_STAT(ipackets), link|network, 1);
+		show_stat("lu", nerr_len, "received-errors", IFA_STAT(ierrors),
 		    link, 1);
-		show_stat("lu", 5, "dropped-packets", IFA_STAT(iqdrops),
+		show_stat("lu", nerr_len, "dropped-packets", IFA_STAT(iqdrops),
 		    link, 1);
 		if (bflag)
-			show_stat("lu", 10, "received-bytes", IFA_STAT(ibytes),
-			    link|network, 0);
-		show_stat("lu", 8, "sent-packets", IFA_STAT(opackets),
+			show_stat("lu", nbyte_len, "received-bytes",
+			    IFA_STAT(ibytes), link|network, 0);
+		show_stat("lu", npkt_len, "sent-packets", IFA_STAT(opackets),
 		    link|network, 1);
-		show_stat("lu", 5, "send-errors", IFA_STAT(oerrors), link, 1);
+		show_stat("lu", nerr_len, "send-errors", IFA_STAT(oerrors),
+		    link, 1);
 		if (bflag)
-			show_stat("lu", 10, "sent-bytes", IFA_STAT(obytes),
-			    link|network, 0);
-		show_stat("NRSlu", 5, "collisions", IFA_STAT(collisions),
+			show_stat("lu", nbyte_len, "sent-bytes",
+			    IFA_STAT(obytes), link|network, 0);
+		show_stat("NRSlu", nerr_len, "collisions", IFA_STAT(collisions),
 		    link, 1);
 		if (dflag)
-			show_stat("LSlu", 5, "dropped-packets",
+			show_stat("LSlu", nerr_len, "dropped-packets",
 			    IFA_STAT(oqdrops), link, 1);
 		xo_emit("\n");
 
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index a675afa17f61..6c76a653d96c 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -317,6 +317,9 @@ See
 Avoid truncating addresses even if this causes some fields to overflow.
 See
 .Sx GENERAL OPTIONS .
+However, in most cases field widths are determined automatically with the
+.Fl i
+option, and this option has little effect.
 .It Fl f Ar protocol_family
 Filter by
 .Ar protocol_family .



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202308031251.373CpATv067049>