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.pub...@gmail.com>
Signed-off-by: Stefano Brivio <sbri...@redhat.com>
---
 man/man8/ss.8 |  5 +++++
 misc/ss.c     | 62 ++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 57 insertions(+), 10 deletions(-)

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 '?':
-- 
2.19.1

Reply via email to