Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 11 Nov 2006 17:09:32 +0100
From:      Giorgos Keramidas <keramida@freebsd.org>
To:        Josh Carroll <josh.carroll@psualum.com>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: sockstat tcp/udp switches
Message-ID:  <20061111160931.GB3979@kobe.laptop>
In-Reply-To: <20061111154849.GC1972@kobe.laptop>
References:  <20061103024621.GB16445@kobe.laptop> <20061103024837.GB79357@lor.one-eyed-alien.net> <20061103025442.GB16543@kobe.laptop> <8cb6106e0611031550y1381b67agdc74144b89de763b@mail.gmail.com> <20061104062439.GD854@turion.vk2pj.dyndns.org> <8cb6106e0611061517k62c9193fnbbfc8e36db328282@mail.gmail.com> <20061107174151.GA51473@lor.one-eyed-alien.net> <8cb6106e0611071008y6811a79x9ba056c2be94d773@mail.gmail.com> <8cb6106e0611071051y6cbbca1padc24ba315d4a2b3@mail.gmail.com> <20061111154849.GC1972@kobe.laptop>

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

--EeQfGwPcQSOJBaQU
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On 2006-11-11 16:48, Giorgos Keramidas <keramida@freebsd.org> wrote:
> This patch still has some points which are in need of a slight
> modification or rearrangement, but it works fine here.
>
> My comments, and a proposed patch to replace it (after some style fixes
> and partial rewrite of the added code), are below:

Maxim Konovalov reminded me of another style(9) issue we have to
address.  All 'return' statements should use parentheses:

    return (foo);

The attached version of my last patch fixes that too, in the
sockstat.c parts which are new.


--EeQfGwPcQSOJBaQU
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="sockstat-protocol.patch"

Add support for filtering sockets by protocol type.  The default
behavior of sockstat(1) will still be to show "udp", "tcp" and
"divert" protocols, but we can now provide a (comma-separated)
list of protocols, as in:

    % sockstat -P tcp

to list only TCP sockets, or we can filter more than one protocol
by separating the protocol names with a comma:

    % sockstat -P tcp,udp

Protocol names are parsed with getprotobyname(3), so any protocol
whose name is listed in `/etc/protocols' should work fine.

Submitted by:	Josh Carroll <josh.carroll@psualum.com>

diff --git a/usr.bin/sockstat/sockstat.c b/usr.bin/sockstat/sockstat.c
--- a/usr.bin/sockstat/sockstat.c
+++ b/usr.bin/sockstat/sockstat.c
@@ -66,6 +66,16 @@ static int	 opt_u;		/* Show Unix domain 
 static int	 opt_u;		/* Show Unix domain sockets */
 static int	 opt_v;		/* Verbose mode */
 
+/*
+ * Default protocols to use if no -P was defined.
+ */
+static const char *default_protos[] = {"tcp", "udp", "divert" };
+static size_t	   default_numprotos =
+    sizeof(default_protos) / sizeof(default_protos[0]);
+
+static int	*protos;	/* protocols to use */
+static size_t	 numprotos;	/* allocated size of protos[] */
+
 static int	*ports;
 
 #define INT_BIT (sizeof(int)*CHAR_BIT)
@@ -103,6 +113,66 @@ xprintf(const char *fmt, ...)
 		err(1, "printf()");
 	return (len);
 }
+
+
+static int
+get_proto_type(const char *proto)
+{
+	struct protoent *pent;
+
+	if (strlen(proto) == 0)
+		return (0);
+	pent = getprotobyname(proto);
+	if (pent == NULL) {
+		warn("getprotobyname");
+		return (-1);
+	}
+	return (pent->p_proto);
+}
+
+
+static void init_protos(int num)
+{
+	int proto_count = 0;
+
+	if (num > 0) {
+		proto_count = num;
+	} else {
+		/* Find the maximum number of possible protocols. */
+		while (getprotoent() != NULL)
+			proto_count++;
+		endprotoent();
+	}
+
+	if ((protos = malloc(sizeof(int) * proto_count)) == NULL)
+		err(1, "malloc");
+	numprotos = proto_count;
+}
+
+
+static int
+parse_protos(char *protospec)
+{
+	char *prot;
+	char *tmp = protospec;
+	int proto_type, proto_index;
+
+	if (protospec == NULL)
+		return (-1);
+
+	init_protos(0);
+	proto_index = 0;
+	while ((prot = strsep(&tmp, ",")) != NULL) {
+		if (strlen(prot) == 0)
+			continue;
+		proto_type = get_proto_type(prot);
+		if (proto_type != -1)
+			protos[proto_index++] = proto_type;
+	}
+	numprotos = proto_index;
+	return (proto_index);
+}
+
 
 static void
 parse_ports(const char *portspec)
@@ -209,7 +279,7 @@ gather_inet(int proto)
 		protoname = "div";
 		break;
 	default:
-		abort();
+		errx(1, "protocol %d not supported", proto);
 	}
 
 	buf = NULL;
@@ -264,7 +334,7 @@ gather_inet(int proto)
 			so = &xip->xi_socket;
 			break;
 		default:
-			abort();
+			errx(1, "protocol %d not supported", proto);
 		}
 		if ((inp->inp_vflag & vflag) == 0)
 			continue;
@@ -573,19 +643,40 @@ display(void)
 	}
 }
 
+static int set_default_protos(void)
+{
+	struct protoent *prot;
+	const char *pname;
+	size_t pindex;
+
+	init_protos(default_numprotos);
+
+	for (pindex = 0; pindex < default_numprotos; pindex++) {
+		pname = default_protos[pindex];
+		prot = getprotobyname(pname);
+		if (prot == NULL)
+			err(1, "getprotobyname: %s", pname);
+		protos[pindex] = prot->p_proto;
+	}
+	numprotos = pindex;
+	return (pindex);
+}
+
+
 static void
 usage(void)
 {
-	fprintf(stderr, "Usage: sockstat [-46clu] [-p ports]\n");
+	fprintf(stderr, "Usage: sockstat [-46clu] [-p ports] [-P protos]\n");
 	exit(1);
 }
 
 int
 main(int argc, char *argv[])
 {
-	int o;
-
-	while ((o = getopt(argc, argv, "46clp:uv")) != -1)
+	int protos_defined = -1;
+	int o, i;
+
+	while ((o = getopt(argc, argv, "46clp:P:uv")) != -1)
 		switch (o) {
 		case '4':
 			opt_4 = 1;
@@ -602,6 +693,9 @@ main(int argc, char *argv[])
 		case 'p':
 			parse_ports(optarg);
 			break;
+		case 'P':
+			protos_defined = parse_protos(optarg);
+			break;
 		case 'u':
 			opt_u = 1;
 			break;
@@ -618,22 +712,30 @@ main(int argc, char *argv[])
 	if (argc > 0)
 		usage();
 
-	if (!opt_4 && !opt_6 && !opt_u)
-		opt_4 = opt_6 = opt_u = 1;
+	/*
+	 * If protos_defined remains -1, no -P was provided, so we have to
+	 * set up the default protocol list in protos[] first.
+	 */
+	if (!opt_4 && !opt_6 && !opt_u && protos_defined == -1) {
+		opt_u = 1;
+		protos_defined = set_default_protos();
+	}
+
+	if (!opt_4 && !opt_6)
+		opt_4 = opt_6 = 1;
 	if (!opt_c && !opt_l)
 		opt_c = opt_l = 1;
 
 	if (opt_4 || opt_6) {
-		gather_inet(IPPROTO_TCP);
-		gather_inet(IPPROTO_UDP);
-		gather_inet(IPPROTO_DIVERT);
-	}
-	if (opt_u) {
+		for (i = 0; i < protos_defined; i++)
+			gather_inet(protos[i]);
+	}
+
+	if (opt_u || (protos_defined == -1 && !opt_4 && !opt_6)) {
 		gather_unix(SOCK_STREAM);
 		gather_unix(SOCK_DGRAM);
 	}
 	getfiles();
 	display();
-
 	exit(0);
 }

--EeQfGwPcQSOJBaQU--



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