[iproute2,net-next,2/3] ss: Introduce option to display selected columns only

Message ID 9da4822eb4ee33501d2d3970515189dda2b1ec0e.1540910943.git.sbrivio@redhat.com
State Under Review
Delegated to: David Ahern
Headers show
Series
  • ss: Allow selection of columns to be displayed
Related show

Commit Message

Stefano Brivio Oct. 30, 2018, 3:05 p.m.
The new option --columns (short: -c) allows to select columns to be
displayed. Note that this doesn't affect the order in which columns are
displayed.

Reported-by: Yoann P. <yoann.p.public@gmail.com>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
---
 man/man8/ss.8 |  5 +++++
 misc/ss.c     | 62 ++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 57 insertions(+), 10 deletions(-)

Patch

diff --git a/man/man8/ss.8 b/man/man8/ss.8
index 7a6572b17364..c987dec6bcd7 100644
--- a/man/man8/ss.8
+++ b/man/man8/ss.8
@@ -24,6 +24,11 @@  Output version information.
 .B \-H, \-\-no-header
 Suppress header line.
 .TP
+.B \-c COLS, \-\-columns=COLS
+Only display selected columns, separated by commas. The following column names
+are understood: netid, state, local, lport, peer, pport, ext. This does not
+define the order of columns.
+.TP
 .B \-n, \-\-numeric
 Do not try to resolve service names.
 .TP
diff --git a/misc/ss.c b/misc/ss.c
index c3f61ef66258..91be3c6db151 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -132,6 +132,7 @@  enum col_align {
 
 struct column {
 	const enum col_align align;
+	const char *optname;
 	const char *header;
 	const char *ldelim;
 	int disabled;
@@ -140,15 +141,15 @@  struct column {
 };
 
 static struct column columns[] = {
-	{ ALIGN_LEFT,	"Netid",		"",	0, 0, 0 },
-	{ ALIGN_LEFT,	"State",		" ",	0, 0, 0 },
-	{ ALIGN_LEFT,	"Recv-Q",		" ",	0, 0, 0 },
-	{ ALIGN_LEFT,	"Send-Q",		" ",	0, 0, 0 },
-	{ ALIGN_RIGHT,	"Local Address:",	" ",	0, 0, 0 },
-	{ ALIGN_LEFT,	"Port",			"",	0, 0, 0 },
-	{ ALIGN_RIGHT,	"Peer Address:",	" ",	0, 0, 0 },
-	{ ALIGN_LEFT,	"Port",			"",	0, 0, 0 },
-	{ ALIGN_LEFT,	"",			"",	0, 0, 0 },
+	{ ALIGN_LEFT,	"netid",	"Netid",		"",  0, 0, 0 },
+	{ ALIGN_LEFT,	"state",	"State",		" ", 0, 0, 0 },
+	{ ALIGN_LEFT,	"recvq",	"Recv-Q",		" ", 0, 0, 0 },
+	{ ALIGN_LEFT,	"sendq",	"Send-Q",		" ", 0, 0, 0 },
+	{ ALIGN_RIGHT,	"local",	"Local Address:",	" ", 0, 0, 0 },
+	{ ALIGN_LEFT,	"lport",	"Port",			"",  0, 0, 0 },
+	{ ALIGN_RIGHT,	"peer",		"Peer Address:",	" ", 0, 0, 0 },
+	{ ALIGN_LEFT,	"pport",	"Port",			"",  0, 0, 0 },
+	{ ALIGN_LEFT,	"ext",		"",			"",  0, 0, 0 },
 };
 
 static struct column *current_field = columns;
@@ -1073,6 +1074,11 @@  static int field_is_last(struct column *f)
 	return f - columns == COL_MAX - 1;
 }
 
+static int field_is_valid(struct column *f)
+{
+	return f >= columns && f - columns < COL_MAX;
+}
+
 static void field_next(void)
 {
 	field_flush(current_field);
@@ -4666,6 +4672,8 @@  static void _usage(FILE *dest)
 "\n"
 "   -K, --kill          forcibly close sockets, display what was closed\n"
 "   -H, --no-header     Suppress header line\n"
+"   -c, --columns=COLS  display only COLS columns\n"
+"       COLS := {netid|state|local|lport|peer|pport|ext}[,COLS]\n"
 "\n"
 "   -A, --query=QUERY, --socket=QUERY\n"
 "       QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink|vsock_stream|vsock_dgram|tipc}[,QUERY]\n"
@@ -4785,6 +4793,7 @@  static const struct option long_opts[] = {
 	{ "tipcinfo", 0, 0, OPT_TIPCINFO},
 	{ "kill", 0, 0, 'K' },
 	{ "no-header", 0, 0, 'H' },
+	{ "columns", 1, 0, 'c' },
 	{ 0 }
 
 };
@@ -4800,7 +4809,7 @@  int main(int argc, char *argv[])
 	int state_filter = 0;
 
 	while ((ch = getopt_long(argc, argv,
-				 "dhaletuwxnro460spbEf:miA:D:F:vVzZN:KHS",
+				 "dhaletuwxnro460spbEf:miA:D:F:vVzZN:KHc:S",
 				 long_opts, NULL)) != EOF) {
 		switch (ch) {
 		case 'n':
@@ -4966,6 +4975,39 @@  int main(int argc, char *argv[])
 		case 'H':
 			show_header = 0;
 			break;
+		case 'c':
+		{
+			struct column *f;
+			char *p, *p1;
+
+			if (!optarg) {
+				fprintf(stderr, "ss: No columns given.\n");
+				usage();
+			}
+
+			for (f = columns; field_is_valid(f); f++)
+				f->disabled = 1;
+
+			p = optarg;
+			do {
+				p1 = strchr(p, ',');
+				if (p1)
+					*p1 = 0;
+				for (f = columns; field_is_valid(f); f++) {
+					if (!strcmp(f->optname, p)) {
+						f->disabled = 0;
+						break;
+					}
+				}
+				if (!field_is_valid(f)) {
+					fprintf(stderr, "ss: No column %s\n",
+						p);
+					usage();
+				}
+				p = p1 + 1;
+			} while (p1);
+			break;
+		}
 		case 'h':
 			help();
 		case '?':