Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 3 Jun 2002 20:58:08 -0700 (PDT)
From:      Kelly Yancey <kbyanc@posi.net>
To:        freebsd-net@FreeBSD.ORG
Subject:   Request for review: patch to make netstat -rW behave as described in netstat(1)
Message-ID:  <20020603205104.T33228-200000@gateway.posi.net>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]

  I would appreciate it if someone could review the attached patch which makes
netstat calculate column widths for the routing table when the -W flag is
specified rather than just picking larger arbitrary values as it does now.
Other than making -W more useful, it syncs reality to the documentation; from
netstat(1):

     -W    In certain displays, avoid truncating addresses even if this causes
           some fields to overflow.

  Basically, all the patch does is add a preliminary pass to calculate the
necessary column widths when -W is specified.  It is pretty straightforward,
but nonetheless, I'de appreciate feedback before I commit it.  Thanks,

  Kelly
  kbyanc@{posi.net,FreeBSD.org}

 * Wow, netstat is so far from WARNS-clean, it's scary.

[-- Attachment #2 --]
Index: usr.bin/netstat/route.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/netstat/route.c,v
retrieving revision 1.65
diff -u -u -r1.65 route.c
--- usr.bin/netstat/route.c	31 May 2002 04:36:55 -0000	1.65
+++ usr.bin/netstat/route.c	4 Jun 2002 03:47:57 -0000
@@ -126,12 +126,18 @@
 int	NewTree = 0;
 
 static struct sockaddr *kgetsa (struct sockaddr *);
+static void size_cols (int ef, struct radix_node *rn);
+static void size_cols_tree (struct radix_node *rn);
+static void size_cols_rtentry (struct rtentry *rt);
 static void p_tree (struct radix_node *);
 static void p_rtnode (void);
 static void ntreestuff (void);
 static void np_rtentry (struct rt_msghdr *);
 static void p_sockaddr (struct sockaddr *, struct sockaddr *, int, int);
+static const char *fmt_sockaddr (struct sockaddr *sa, struct sockaddr *mask,
+				 int flags);
 static void p_flags (int, char *);
+static const char *fmt_flags(int f);
 static void p_rtentry (struct rtentry *);
 static u_long forgemask (u_long);
 static void domask (char *, u_long, u_long);
@@ -166,6 +172,7 @@
 					p_tree(head.rnh_treetop);
 				}
 			} else if (af == AF_UNSPEC || af == i) {
+				size_cols(i, head.rnh_treetop);
 				pr_family(i);
 				do_rtent = 1;
 				pr_rthdr(i);
@@ -224,17 +231,134 @@
 
 /* column widths; each followed by one space */
 #ifndef INET6
-#define	WID_DST(af) 	18	/* width of destination column */
-#define	WID_GW(af)	18	/* width of gateway column */
-#define	WID_IF(af)	6	/* width of netif column */
+#define	WID_DST_DEFAULT(af) 	18	/* width of destination column */
+#define	WID_GW_DEFAULT(af)	18	/* width of gateway column */
+#define	WID_IF_DEFAULT(af)	6	/* width of netif column */
 #else
-#define	WID_DST(af) \
-	((af) == AF_INET6 ? (Wflag ? 39 : (numeric_addr ? 33: 18)) : 18)
-#define	WID_GW(af) \
-	((af) == AF_INET6 ? (Wflag ? 31 : (numeric_addr ? 29 : 18)) : 18)
-#define	WID_IF(af)	((af) == AF_INET6 ? 8 : 6)
+#define	WID_DST_DEFAULT(af) \
+	((af) == AF_INET6 ? (numeric_addr ? 33: 18) : 18)
+#define	WID_GW_DEFAULT(af) \
+	((af) == AF_INET6 ? (numeric_addr ? 29 : 18) : 18)
+#define	WID_IF_DEFAULT(af)	((af) == AF_INET6 ? 8 : 6)
 #endif /*INET6*/
 
+static int wid_dst;
+static int wid_gw;
+static int wid_flags;
+static int wid_refs;
+static int wid_use;
+static int wid_mtu;
+static int wid_if;
+static int wid_expire;
+
+static void
+size_cols(int ef, struct radix_node *rn)
+{
+	wid_dst = WID_DST_DEFAULT(ef);
+	wid_gw = WID_GW_DEFAULT(ef);
+	wid_flags = 6;
+	wid_refs = 6;
+	wid_use = 8;
+	wid_mtu = 6;
+	wid_if = WID_IF_DEFAULT(ef);
+	wid_expire = 6;
+
+	if (Wflag)
+		size_cols_tree(rn);
+}
+
+static void
+size_cols_tree(struct radix_node *rn)
+{
+again:
+	kget(rn, rnode);
+	if (rnode.rn_bit < 0) {
+		if ((rnode.rn_flags & RNF_ROOT) == 0) {
+			kget(rn, rtentry);
+			size_cols_rtentry(&rtentry);
+		}
+		if ((rn = rnode.rn_dupedkey))
+			goto again;
+	} else {
+		rn = rnode.rn_right;
+		size_cols_tree(rnode.rn_left);
+		size_cols_tree(rn);
+	}
+}
+
+static void
+size_cols_rtentry(struct rtentry *rt)
+{
+	static struct ifnet ifnet, *lastif;
+	struct rtentry parent;
+	static char buffer[100];
+	const char *bp;
+	struct sockaddr *sa;
+	sa_u addr, mask;
+	int len;
+
+	/*
+	 * Don't print protocol-cloned routes unless -a.
+	 */
+	if (rt->rt_flags & RTF_WASCLONED && !aflag) {
+		kget(rt->rt_parent, parent);
+		if (parent.rt_flags & RTF_PRCLONING)
+			return;
+	}
+
+	bzero(&addr, sizeof(addr));
+	if ((sa = kgetsa(rt_key(rt))))
+		bcopy(sa, &addr, sa->sa_len);
+	bzero(&mask, sizeof(mask));
+	if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt))))
+		bcopy(sa, &mask, sa->sa_len);
+	bp = fmt_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags);
+	len = strlen(bp);
+	wid_dst = MAX(len, wid_dst);
+
+	bp = fmt_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST);
+	len = strlen(bp);
+	wid_gw = MAX(len, wid_gw);
+
+	bp = fmt_flags(rt->rt_flags);
+	len = strlen(bp);
+	wid_flags = MAX(len, wid_flags);
+
+	if (addr.u_sa.sa_family == AF_INET || Wflag) {
+		len = snprintf(buffer, sizeof(buffer), "%ld", rt->rt_refcnt);
+		wid_refs = MAX(len, wid_refs);
+		len = snprintf(buffer, sizeof(buffer), "%lu", rt->rt_use);
+		wid_use = MAX(len, wid_use);
+		if (Wflag && rt->rt_rmx.rmx_mtu != 0) {
+			len = snprintf(buffer, sizeof(buffer),
+				       "%lu", rt->rt_rmx.rmx_mtu);
+			wid_mtu = MAX(len, wid_mtu);
+		}
+	}
+	if (rt->rt_ifp) {
+		if (rt->rt_ifp != lastif) {
+			len = snprintf(buffer, sizeof(buffer), "%d",
+				       ifnet.if_unit);
+			kget(rt->rt_ifp, ifnet);
+			kread((u_long)ifnet.if_name, buffer, sizeof(buffer));
+			lastif = rt->rt_ifp;
+			len += strlen(buffer);
+			wid_if = MAX(len, wid_if);
+		}
+		if (rt->rt_rmx.rmx_expire) {
+			time_t expire_time;
+
+			if ((expire_time =
+			    rt->rt_rmx.rmx_expire - time(NULL)) > 0) {
+				snprintf(buffer, sizeof(buffer), "%d",
+					 (int)expire_time);
+				wid_expire = MAX(len, wid_expire);
+			}
+		}
+	}
+}
+
+
 /*
  * Print header for routing table columns.
  */
@@ -244,24 +368,35 @@
 
 	if (Aflag)
 		printf("%-8.8s ","Address");
-	if (af == AF_INET || Wflag)
-		if (Wflag)
-			printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %6.6s %*.*s %6s\n",
-				WID_DST(af), WID_DST(af), "Destination",
-				WID_GW(af), WID_GW(af), "Gateway",
-				"Flags", "Refs", "Use", "Mtu",
-				WID_IF(af), WID_IF(af), "Netif", "Expire");
-		else
-			printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %*.*s %6s\n",
-				WID_DST(af), WID_DST(af), "Destination",
-				WID_GW(af), WID_GW(af), "Gateway",
-				"Flags", "Refs", "Use",
-				WID_IF(af), WID_IF(af), "Netif", "Expire");
-	else
-		printf("%-*.*s %-*.*s %-6.6s  %8.8s %6s\n",
-			WID_DST(af), WID_DST(af), "Destination",
-			WID_GW(af), WID_GW(af), "Gateway",
-			"Flags", "Netif", "Expire");
+	if (af == AF_INET || Wflag) {
+		if (Wflag) {
+			printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*.*s %*s\n",
+				wid_dst,	wid_dst,	"Destination",
+				wid_gw,		wid_gw,		"Gateway",
+				wid_flags,	wid_flags,	"Flags",
+				wid_refs,	wid_refs,	"Refs",
+				wid_use,	wid_use,	"Use",
+				wid_mtu,	wid_mtu,	"Mtu",
+				wid_if,		wid_if,		"Netif",
+				wid_expire,			"Expire");
+		} else {
+			printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*s\n",
+				wid_dst,	wid_dst,	"Destination",
+				wid_gw,		wid_gw,		"Gateway",
+				wid_flags,	wid_flags,	"Flags",
+				wid_refs,	wid_refs,	"Refs",
+				wid_use,	wid_use,	"Use",
+				wid_if,		wid_if,		"Netif",
+				wid_expire,			"Expire");
+		}
+	} else {
+		printf("%-*.*s %-*.*s %-*.*s  %*.*s %*s\n",
+			wid_dst,	wid_dst,	"Destination",
+			wid_gw,		wid_gw,		"Gateway",
+			wid_flags,	wid_flags,	"Flags",
+			wid_if,		wid_if,		"Netif",
+			wid_expire,			"Expire");
+	}
 }
 
 static struct sockaddr *
@@ -422,8 +557,26 @@
 static void
 p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width)
 {
-	char workbuf[128], *cplim;
-	register char *cp = workbuf;
+	const char *cp;
+
+	cp = fmt_sockaddr(sa, mask, flags);
+
+	if (width < 0 )
+		printf("%s ", cp);
+	else {
+		if (numeric_addr)
+			printf("%-*s ", width, cp);
+		else
+			printf("%-*.*s ", width, width, cp);
+	}
+}
+
+static const char *
+fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags)
+{
+	static char workbuf[128];
+	char *cplim;
+	char *cp = workbuf;
 
 	switch(sa->sa_family) {
 	case AF_INET:
@@ -542,27 +695,28 @@
 		cp = workbuf;
 	    }
 	}
-	if (width < 0 )
-		printf("%s ", cp);
-	else {
-		if (numeric_addr)
-			printf("%-*s ", width, cp);
-		else
-			printf("%-*.*s ", width, width, cp);
-	}
+
+	return (cp);
 }
 
 static void
 p_flags(int f, char *format)
 {
-	char name[33], *flags;
-	register struct bits *p = bits;
+	printf(format, fmt_flags(f));
+}
+
+static const char *
+fmt_flags(int f)
+{
+	static char name[33];
+	char *flags;
+	struct bits *p = bits;
 
 	for (flags = name; p->b_mask; p++)
 		if (p->b_mask & f)
 			*flags++ = p->b_val;
 	*flags = '\0';
-	printf(format, name);
+	return (name);
 }
 
 static void
@@ -570,8 +724,8 @@
 {
 	static struct ifnet ifnet, *lastif;
 	struct rtentry parent;
-	static char name[16];
-	static char prettyname[9];
+	static char buffer[128];
+	static char prettyname[128];
 	struct sockaddr *sa;
 	sa_u addr, mask;
 
@@ -590,36 +744,35 @@
 	bzero(&mask, sizeof(mask));
 	if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt))))
 		bcopy(sa, &mask, sa->sa_len);
-	p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags,
-	    WID_DST(addr.u_sa.sa_family));
-	p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST,
-	    WID_GW(addr.u_sa.sa_family));
-	p_flags(rt->rt_flags, "%-6.6s ");
+	p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, wid_dst);
+	p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, wid_gw);
+	snprintf(buffer, sizeof(buffer), "%%-%d.%ds ", wid_flags, wid_flags);
+	p_flags(rt->rt_flags, buffer);
 	if (addr.u_sa.sa_family == AF_INET || Wflag) {
-		printf("%6ld %8lu ", rt->rt_refcnt, rt->rt_use);
+		printf("%*ld %*lu ", wid_refs, rt->rt_refcnt,
+				     wid_use, rt->rt_use);
 		if (Wflag) {
 			if (rt->rt_rmx.rmx_mtu != 0)
-				printf("%6lu ", rt->rt_rmx.rmx_mtu);
+				printf("%*lu ", wid_mtu, rt->rt_rmx.rmx_mtu);
 			else
-				printf("%6s ", "");
+				printf("%*s ", wid_mtu, "");
 		}
 	}
 	if (rt->rt_ifp) {
 		if (rt->rt_ifp != lastif) {
 			kget(rt->rt_ifp, ifnet);
-			kread((u_long)ifnet.if_name, name, 16);
+			kread((u_long)ifnet.if_name, buffer, sizeof(buffer));
 			lastif = rt->rt_ifp;
-			snprintf(prettyname, sizeof prettyname,
-				 "%s%d", name, ifnet.if_unit);
+			snprintf(prettyname, sizeof(prettyname),
+				 "%s%d", buffer, ifnet.if_unit);
 		}
-		printf("%*.*s", WID_IF(addr.u_sa.sa_family),
-		    WID_IF(addr.u_sa.sa_family), prettyname);
+		printf("%*.*s", wid_if, wid_if, prettyname);
 		if (rt->rt_rmx.rmx_expire) {
 			time_t expire_time;
 
 			if ((expire_time =
 			    rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0)
-				printf(" %6d", (int)expire_time);
+				printf(" %*d", wid_expire, (int)expire_time);
 		}
 		if (rt->rt_nodes[0].rn_dupedkey)
 			printf(" =>");

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