On Wed, Jul 23, 2008 at 09:38:41AM +0200, Bernhard Fischer wrote:

> bloat-o-meter output? size(1) before and after your patch, with and
> without -p support?

The following numbers are for the newly reworked patch
(please see attached).

Before:
$ size networking/netstat.o 
   text    data     bss     dec     hex filename
   3426       5       0    3431     d67 networking/netstat.o

After, without -p support compiled in (but with the nice, fixed,
standard options and globals code):
$ size networking/netstat.o 
   text    data     bss     dec     hex filename
   3487       0       0    3487     d9f networking/netstat.o


After, with -p support built in:
$ size networking/netstat.o 
   text    data     bss     dec     hex filename
   4642       0       0    4642    1222 networking/netstat.o


> >+#define PROGNAME_WIDTH 20
> >+#define PROGNAME_WIDTHs "%-20s"
> 
> Just curious why you don't use PROGNAME_WIDTH here?

The original, which Denys didn't like on account of being too
complicated, looked like this:

#define PROGNAME_WIDTH 20
#define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
#define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
#define PROGNAME_WIDTH2(s) #s

This allowed PROGNAME_WIDTHs to be used inside a printf format string:

        printf("%-" PROGNAME_WIDTHs "s", some_string);

You can't use PROGNAME_WIDTH directly, since that would substitute to:

        printf("%-" 20 "s", some_string);

which is a syntax error. Also,

        printf("%-PROGNAME_WIDTHs", some_string);

is obviously broken, too.

You can't

#define PROGNAME_WIDTHs "PROGNAME_WIDTH"

either, because you'd end up with the literal string instead of the
desired \"20\"

I'm not an expert on C preprocessor voodoo by any means, but the
original form which Denys didn't like did accomplish creating a preproc.
variable PROGNAME_WIDTHs which automatically takes the string form of
whatever PROGNAME_WIDTH is set to ("20" for 20, "30" for 30, etc).

The (more readable) alternative is to have to modify both by hand. If
you know how to automatically get PROGNAME_WIDTHs to adjust when
modifying PROGNAME_WIDTH, any simpler than the WIDTH1() WIDTH2() trick
above, let me know... Or, how to jam PROGNAME_WIDTH into a printf
format string directly -- I tried and it didn't get substituted :(

> 
> >+static void prg_cache_add(int inode, char *name)
...
> >+    }
> >+    *pnp = xmalloc(sizeof(struct prg_node));
> >+    pn = *pnp;
> >+    pn->next = NULL;
> 
> an xzalloc would have rendered nullifying next moot.

Done.

> >+static const char *prg_cache_get(int inode)
> >+{
> >+    unsigned hi = PRG_HASHIT(inode);
> >+    struct prg_node *pn;
> >+
> >+    for (pn = prg_hash[hi]; pn; pn = pn->next)
> >+            if (pn->inode == inode)
> >+                    return pn->name;
> 
> argh, that's exactly what index_in_strings should have been used for.

Not sure I get that -- index_in_strings searches a contiguous
concatenation of null-terminated strings; netstat has a hash array
with linked lists hanging off each entry (and the list elements have a
string *and* an int member)...

> nah. Use recursive_action() instead of growing your own (huge!) impl
> for it.

Done. However, this requires the addition of an ACTION_QUIET flag to
recursive_action() (also included in the attached patch). We do NOT
want recursive_action() to print to stderr each time it gets a
permission error when trying to open /proc entries, should the user
run netstat as non-root !!!

> The preferred way look like:
> 
> ->+#if ENABLE_FEATURE_NETSTAT_PRG
> ->+           if (prg_flag)
> +>+           if (ENABLE_FEATURE_NETSTAT_PRG && prg_flag)

Respectfully disagree. If ENABLE_FEATURE_NETSTAT_PRG is not enabled,
prg_flag is undeclared, and we get a compile-time error.
Am I missing anything ?

> >+                    printf(PROGNAME_WIDTHs, prg_cache_get(inode));
> >+#endif
> >+            printf("\n");
> 
> Is that \n here on purpose?

Yes. I want to print the string "foo bar\n" with the following
restrictions:

if ENABLE_FEATURE_NETSTAT_PRG is undefined, I only want "foo\n",
always.

if ENABLE_FEATURE_NETSTAT_PRG is true, I want "foo bar\n" if the -p flag
was supplied on the command line, otherwise I still only want "foo\n".

My solution to this was to first print "foo" without \n
then, #if ENABLE_FEATURE_NETSTAT_PRG to check for prg_flag, and if
true to print "bar"
then, last thing, I always print "\n".

You don't *always* want to print the program name and pid if
ENABLE_FEATURE_NETSTAT_PRG is true, so just ifdef-ing the format
string from the get-go isn't a solution.

> 
> Sounds a bit like you are too newline friendly ;)

Maybe, and maybe I've been staring at this thing for too long and the
obvious simple and clean solution escapes me... How would you do it ? :)

> This sounds way too big, please provide the bloat-o-meter and size(1)
> output i mentioned above, and please take my comments into account.

Done -- please let me know your thoughts !

--Gabriel

> TIA,
> Bernhard
> 
diff -NarU5 busybox-svn-22735.orig/include/libbb.h 
busybox-svn-22735/include/libbb.h
--- busybox-svn-22735.orig/include/libbb.h      2008-07-09 23:04:08.000000000 
-0400
+++ busybox-svn-22735/include/libbb.h   2008-07-24 18:21:53.000000000 -0400
@@ -276,10 +276,11 @@
        ACTION_RECURSE        = (1 << 0),
        ACTION_FOLLOWLINKS    = (1 << 1),
        ACTION_FOLLOWLINKS_L0 = (1 << 2),
        ACTION_DEPTHFIRST     = (1 << 3),
        /*ACTION_REVERSE      = (1 << 4), - unused */
+       ACTION_QUIET          = (1 << 5),
 };
 extern int recursive_action(const char *fileName, unsigned flags,
        int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, 
void* userData, int depth),
        int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, 
void* userData, int depth),
        void* userData, unsigned depth) FAST_FUNC;
diff -NarU5 busybox-svn-22735.orig/include/usage.h 
busybox-svn-22735/include/usage.h
--- busybox-svn-22735.orig/include/usage.h      2008-07-09 23:04:08.000000000 
-0400
+++ busybox-svn-22735/include/usage.h   2008-07-23 12:42:05.000000000 -0400
@@ -2813,11 +2813,11 @@
 /*   "\nport numbers can be individual or ranges: lo-hi [inclusive]" */
 
 #endif
 
 #define netstat_trivial_usage \
-       "[-laentuwxr"USE_FEATURE_NETSTAT_WIDE("W")"]"
+       
"[-laentuwxr"USE_FEATURE_NETSTAT_WIDE("W")USE_FEATURE_NETSTAT_PRG("p")"]"
 #define netstat_full_usage "\n\n" \
        "Display networking information\n" \
      "\nOptions:" \
      "\n       -l      Display listening server sockets" \
      "\n       -a      Display all sockets (default: connected)" \
@@ -2828,10 +2828,13 @@
      "\n       -w      Raw sockets" \
      "\n       -x      Unix sockets" \
      "\n       -r      Display routing table" \
        USE_FEATURE_NETSTAT_WIDE( \
      "\n       -W      Display with no column truncation" \
+       ) \
+       USE_FEATURE_NETSTAT_PRG( \
+     "\n       -p      Display PID/Program name for sockets" \
        )
 
 #define nice_trivial_usage \
        "[-n ADJUST] [COMMAND [ARG]...]"
 #define nice_full_usage "\n\n" \
diff -NarU5 busybox-svn-22735.orig/libbb/recursive_action.c 
busybox-svn-22735/libbb/recursive_action.c
--- busybox-svn-22735.orig/libbb/recursive_action.c     2008-07-09 
23:04:07.000000000 -0400
+++ busybox-svn-22735/libbb/recursive_action.c  2008-07-24 18:22:49.000000000 
-0400
@@ -139,8 +139,9 @@
        }
 
        return status;
 
  done_nak_warn:
-       bb_simple_perror_msg(fileName);
+       if (!(flags & ACTION_QUIET))
+               bb_simple_perror_msg(fileName);
        return FALSE;
 }
diff -NarU5 busybox-svn-22735.orig/networking/Config.in 
busybox-svn-22735/networking/Config.in
--- busybox-svn-22735.orig/networking/Config.in 2008-07-09 23:04:03.000000000 
-0400
+++ busybox-svn-22735/networking/Config.in      2008-07-23 12:42:05.000000000 
-0400
@@ -630,10 +630,17 @@
        depends on NETSTAT
        help
          Add support for wide columns. Useful when displaying IPv6 addresses
          (-W option).
 
+config FEATURE_NETSTAT_PRG
+       bool "Enable PID/Program name output"
+       default n
+       depends on NETSTAT
+       help
+         Add support for -p flag to print out PID and program name.
+
 config NSLOOKUP
        bool "nslookup"
        default n
        help
          nslookup is a tool to query Internet name servers.
diff -NarU5 busybox-svn-22735.orig/networking/netstat.c 
busybox-svn-22735/networking/netstat.c
--- busybox-svn-22735.orig/networking/netstat.c 2008-07-09 23:04:03.000000000 
-0400
+++ busybox-svn-22735/networking/netstat.c      2008-07-25 18:10:14.000000000 
-0400
@@ -6,22 +6,41 @@
  * Copyright (C) 2002 by Bart Visscher <[EMAIL PROTECTED]>
  *
  * 2002-04-20
  * IPV6 support added by Bart Visscher <[EMAIL PROTECTED]>
  *
+ * 2008-07-10
+ * optional '-p' flag support ported from net-tools by G. Somlo <[EMAIL 
PROTECTED]>
+ *
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
 
 #include "libbb.h"
 #include "inet_common.h"
 
+#define NETSTAT_OPTS "laentuwx" \
+       USE_ROUTE(               "r") \
+       USE_FEATURE_NETSTAT_WIDE("W") \
+       USE_FEATURE_NETSTAT_PRG( "p")
+
 enum {
-       OPT_extended = 0x4,
-       OPT_showroute = 0x100,
-       OPT_widedisplay = 0x200 * ENABLE_FEATURE_NETSTAT_WIDE,
+       OPTBIT_KEEP_OLD = 7,
+       USE_ROUTE(               OPTBIT_ROUTE,)
+       USE_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,)
+       USE_FEATURE_NETSTAT_PRG( OPTBIT_PRG  ,)
+       OPT_sock_listen = 1 << 0, // l
+       OPT_sock_all    = 1 << 1, // a
+       OPT_extended    = 1 << 2, // e
+       OPT_noresolve   = 1 << 3, // n
+       OPT_sock_tcp    = 1 << 4, // t
+       OPT_sock_udp    = 1 << 5, // u
+       OPT_sock_raw    = 1 << 6, // w
+       OPT_sock_unix   = 1 << 7, // x
+       OPT_route       = USE_ROUTE(               (1<<OPTBIT_ROUTE)) + 0, // r
+       OPT_wide        = USE_FEATURE_NETSTAT_WIDE((1<<OPTBIT_WIDE )) + 0, // W
+       OPT_prg         = USE_FEATURE_NETSTAT_PRG( (1<<OPTBIT_PRG  )) + 0, // p
 };
-# define NETSTAT_OPTS "laentuwxr"USE_FEATURE_NETSTAT_WIDE("W")
 
 #define NETSTAT_CONNECTED 0x01
 #define NETSTAT_LISTENING 0x02
 #define NETSTAT_NUMERIC   0x04
 /* Must match getopt32 option string */
@@ -29,11 +48,10 @@
 #define NETSTAT_UDP       0x20
 #define NETSTAT_RAW       0x40
 #define NETSTAT_UNIX      0x80
 #define NETSTAT_ALLPROTO  (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX)
 
-static smallint flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO;
 
 enum {
        TCP_ESTABLISHED = 1,
        TCP_SYN_SENT,
        TCP_SYN_RECV,
@@ -42,26 +60,12 @@
        TCP_TIME_WAIT,
        TCP_CLOSE,
        TCP_CLOSE_WAIT,
        TCP_LAST_ACK,
        TCP_LISTEN,
-       TCP_CLOSING /* now a valid state */
-};
-
-static const char *const tcp_state[] = {
-       "",
-       "ESTABLISHED",
-       "SYN_SENT",
-       "SYN_RECV",
-       "FIN_WAIT1",
-       "FIN_WAIT2",
-       "TIME_WAIT",
-       "CLOSE",
-       "CLOSE_WAIT",
-       "LAST_ACK",
-       "LISTEN",
-       "CLOSING"
+       TCP_CLOSING, /* now a valid state */
+       TCP_MAX_STATE
 };
 
 typedef enum {
        SS_FREE = 0,     /* not allocated                */
        SS_UNCONNECTED,  /* unconnected to any socket    */
@@ -74,25 +78,253 @@
 #define SO_WAITDATA  (1<<17)   /* wait data to read            */
 #define SO_NOSPACE   (1<<18)   /* no space to write            */
 
 /* Standard printout size */
 #define PRINT_IP_MAX_SIZE           23
-#define PRINT_NET_CONN              "%s   %6ld %6ld %-23s %-23s %-12s\n"
-#define PRINT_NET_CONN_HEADER       "\nProto Recv-Q Send-Q %-23s %-23s State\n"
+#define PRINT_NET_CONN              "%s   %6ld %6ld %-23s %-23s %-12s"
+#define PRINT_NET_CONN_HEADER       "\nProto Recv-Q Send-Q %-23s %-23s State   
   "
 
 /* When there are IPv6 connections the IPv6 addresses will be
  * truncated to none-recognition. The '-W' option makes the
  * address columns wide enough to accomodate for longest possible
  * IPv6 addresses, i.e. addresses of the form
  * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd
  */
 #define PRINT_IP_MAX_SIZE_WIDE      51  /* INET6_ADDRSTRLEN + 5 for the port 
number */
-#define PRINT_NET_CONN_WIDE         "%s   %6ld %6ld %-51s %-51s %-12s\n"
-#define PRINT_NET_CONN_HEADER_WIDE  "\nProto Recv-Q Send-Q %-51s %-51s State\n"
+#define PRINT_NET_CONN_WIDE         "%s   %6ld %6ld %-51s %-51s %-12s"
+#define PRINT_NET_CONN_HEADER_WIDE  "\nProto Recv-Q Send-Q %-51s %-51s State   
   "
+
+#if ENABLE_FEATURE_NETSTAT_PRG
+
+#define PROGNAME_WIDTH 20
+#define PROGNAME_WIDTHs "%-20s"
+
+struct prg_node {
+       struct prg_node *next;
+       int inode;
+       char name[PROGNAME_WIDTH];
+};
+
+#define PRG_HASH_SIZE 211
+#define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE)
+
+#endif
+
+struct globals {
+       smallint flags;
+       char *tcp_state[TCP_MAX_STATE];
+       char *net_conn_line;
+#if ENABLE_FEATURE_NETSTAT_PRG
+       struct prg_node *prg_hash[PRG_HASH_SIZE];
+       char prg_cache_loaded;
+       int prg_flag;
+#endif
+};
+
+#define G (*ptr_to_globals)
+#define flags         (G.flags)
+#define tcp_state     (G.tcp_state)
+#define net_conn_line (G.net_conn_line)
+
+#if ENABLE_FEATURE_NETSTAT_PRG
+#define prg_hash         (G.prg_hash)
+#define prg_cache_loaded (G.prg_cache_loaded)
+#define prg_flag         (G.prg_flag)
+#endif
+
+#define INIT_G() do { \
+       SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+       flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \
+       tcp_state[TCP_ESTABLISHED] = "ESTABLISHED"; \
+       tcp_state[TCP_SYN_SENT] = "SYN_SENT"; \
+       tcp_state[TCP_SYN_RECV] = "SYN_RECV"; \
+       tcp_state[TCP_FIN_WAIT1] = "FIN_WAIT1"; \
+       tcp_state[TCP_FIN_WAIT2] = "FIN_WAIT2"; \
+       tcp_state[TCP_TIME_WAIT] = "TIME_WAIT"; \
+       tcp_state[TCP_CLOSE] = "CLOSE"; \
+       tcp_state[TCP_CLOSE_WAIT] = "CLOSE_WAIT"; \
+       tcp_state[TCP_LAST_ACK] = "LAST_ACK"; \
+       tcp_state[TCP_LISTEN] = "LISTEN"; \
+       tcp_state[TCP_CLOSING] = "CLOSING"; \
+       net_conn_line = PRINT_NET_CONN; \
+} while (0)
+/* NOTE: prg_cache_loaded and prg_flag are initialized to 0 by xzalloc */
+
+
+#if ENABLE_FEATURE_NETSTAT_PRG
+#define PROGNAME_BANNER "PID/Program name"
+
+#define print_progname_banner() do { if (prg_flag) printf(PROGNAME_WIDTHs," " 
PROGNAME_BANNER); } while (0)
+
+#define PRG_SOCKET_PFX   "socket:["
+#define PRG_SOCKET_PFXl  (sizeof(PRG_SOCKET_PFX)-1)
+#define PRG_SOCKET_PFX2  "[0000]:"
+#define PRG_SOCKET_PFX2l (sizeof(PRG_SOCKET_PFX2)-1)
+
+#define PATH_PROC      "/proc"
+#define PATH_FD_SUFF   "fd"
+#define PATH_CMDLINE   "cmdline"
+
+static void prg_cache_add(int inode, char *name)
+{
+       unsigned hi = PRG_HASHIT(inode);
+       struct prg_node **pnp, *pn;
+
+       prg_cache_loaded = 2;
+       for (pnp = prg_hash + hi; (pn = *pnp); pnp = &pn->next) {
+               if (pn->inode == inode) {
+                       /* Some warning should be appropriate here
+                          as we got multiple processes for one i-node */
+                       return;
+               }
+       }
+       *pnp = xzalloc(sizeof(struct prg_node));
+       pn = *pnp;
+       pn->inode = inode;
+       safe_strncpy(pn->name, name, PROGNAME_WIDTH);
+}
+
+static const char *prg_cache_get(int inode)
+{
+       unsigned hi = PRG_HASHIT(inode);
+       struct prg_node *pn;
+
+       for (pn = prg_hash[hi]; pn; pn = pn->next)
+               if (pn->inode == inode)
+                       return pn->name;
+       return "-";
+}
+
+static void prg_cache_clear(void)
+{
+       struct prg_node **pnp, *pn;
+
+       if (prg_cache_loaded == 2)
+               for (pnp = prg_hash; pnp < prg_hash + PRG_HASH_SIZE; pnp++)
+                       while ((pn = *pnp)) {
+                               *pnp = pn->next;
+                               free(pn);
+                       }
+       prg_cache_loaded = 0;
+}
+
+static long extract_socket_inode(const char *lname) {
+
+       size_t llen = strlen(lname);
+       long inode = -1;
+
+       if (llen >= PRG_SOCKET_PFXl + 3 &&
+               memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl) == 0 &&
+               lname[llen - 1] == ']') {
+
+               /* If lname is of the form "socket:[12345]",
+                * extract the "12345" as inode.
+                */
+
+               char inode_str[llen + 1];  /* e.g. "12345" */
+               const int inode_str_len = llen - PRG_SOCKET_PFXl - 1;
+
+               strncpy(inode_str, lname + PRG_SOCKET_PFXl, inode_str_len);
+               inode_str[inode_str_len] = '\0';
+               inode = bb_strtol(inode_str, NULL, 0);
+       } else if (llen >= PRG_SOCKET_PFX2l + 1 &&
+                               memcmp(lname, PRG_SOCKET_PFX2, 
PRG_SOCKET_PFX2l) == 0) {
+
+               /* If lname is of the form "[0000]:12345",
+                * extract the "12345" as inode.
+                */
 
-static const char *net_conn_line = PRINT_NET_CONN;
+               inode = bb_strtol(lname + PRG_SOCKET_PFX2l, NULL, 0);
+       }
+
+       if (errno)      /* bb_strtol() encountered an error */
+               inode = -1;
+
+       return inode;
+}
+
+static int FAST_FUNC file_act(const char *fileName,
+               struct stat *statbuf UNUSED_PARAM,
+               void *userData,
+               int depth)
+{
+       char *link;
+       int i;
 
+       link = xmalloc_readlink(fileName);
+       if (link != NULL) {
+               i = extract_socket_inode(link);
+               free(link);
+               if (i >= 0)
+                       prg_cache_add(i, (char *)userData);
+       }
+       return TRUE;
+}
+
+static int FAST_FUNC dir_act(const char *fileName,
+               struct stat *statbuf UNUSED_PARAM,
+               void *userData UNUSED_PARAM,
+               int depth)
+{
+       char *p, *q;
+       char cmdline_buf[512], progname_buf[PROGNAME_WIDTH];
+       int i;
+
+       if (depth == 0)
+               return TRUE;            /* continue looking one level below 
/proc */
+
+       if (depth == 1)
+               for (p = bb_basename(fileName); *p; p++)
+                       if (!isdigit(*p))
+                               return SKIP;    /* skip any /proc subdir that's 
not a process */
+
+       /* build string containing PID/command */
+       p = concat_path_file(fileName, PATH_CMDLINE);
+       i = open_read_close(p, cmdline_buf, sizeof(cmdline_buf) - 1);
+       free(p);
+       if (i < 0)
+               return FALSE;
+       cmdline_buf[i] = '\0';
+       q = concat_path_file(bb_basename(fileName), bb_basename(cmdline_buf));
+
+       /* go through all files in /proc/<THISPROC>/fd */
+       p = concat_path_file(fileName, PATH_FD_SUFF);
+       i = recursive_action(p, ACTION_RECURSE | ACTION_QUIET,
+                                                       file_act, NULL, (void 
*)q, 0);
+
+       free(p);
+       free(q);
+
+       if (!i)
+               return FALSE;   /* signal permissions error to caller */
+
+       return SKIP;            /* caller should not recurse further into this 
dir. */
+}
+
+static void prg_cache_load(void)
+{
+       int load_ok;
+
+       if (prg_cache_loaded)
+               return;
+       prg_cache_loaded = 1;
+
+       load_ok = recursive_action(PATH_PROC, ACTION_RECURSE | ACTION_QUIET,
+                                               NULL, dir_act, NULL, 0);
+       if (load_ok)
+               return;
+
+       if (prg_cache_loaded == 1)
+               fprintf(stderr, "(No info could be read for \"-p\": 
geteuid()=%d "
+                                               "but you should be root.)\n", 
geteuid());
+       else
+               fprintf(stderr, "(Not all processes could be identified, "
+                                               "non-owned process info will 
not be shown, "
+                                               "you would have to be root to 
see it all.)\n");
+}
+
+#endif //ENABLE_FEATURE_NETSTAT_PRG
 
 #if ENABLE_FEATURE_IPV6
 static void build_ipv6_addr(char* local_addr, struct sockaddr_in6* localaddr)
 {
        char addr6[INET6_ADDRSTRLEN];
@@ -193,10 +425,15 @@
                char *r = ip_port_str(
                                (struct sockaddr *) &remaddr, rem_port,
                                "tcp", flags & NETSTAT_NUMERIC);
                printf(net_conn_line,
                        "tcp", rxq, txq, l, r, tcp_state[state]);
+#if ENABLE_FEATURE_NETSTAT_PRG
+               if (prg_flag)
+                       printf(PROGNAME_WIDTHs, prg_cache_get(inode));
+#endif
+               printf("\n");
                free(l);
                free(r);
        }
        return 0;
 }
@@ -274,10 +511,15 @@
                        char *r = ip_port_str(
                                (struct sockaddr *) &remaddr, rem_port,
                                "udp", flags & NETSTAT_NUMERIC);
                        printf(net_conn_line,
                                "udp", rxq, txq, l, r, state_str);
+#if ENABLE_FEATURE_NETSTAT_PRG
+                       if (prg_flag)
+                               printf(PROGNAME_WIDTHs, prg_cache_get(inode));
+#endif
+                       printf("\n");
                        free(l);
                        free(r);
                }
        }
        return 0;
@@ -330,10 +572,15 @@
                        char *r = ip_port_str(
                                (struct sockaddr *) &remaddr, rem_port,
                                "raw", flags & NETSTAT_NUMERIC);
                        printf(net_conn_line,
                                "raw", rxq, txq, l, r, itoa(state));
+#if ENABLE_FEATURE_NETSTAT_PRG
+                       if (prg_flag)
+                               printf(PROGNAME_WIDTHs, prg_cache_get(inode));
+#endif
+                       printf("\n");
                        free(l);
                        free(r);
                }
        }
        return 0;
@@ -441,10 +688,15 @@
 
        printf("%-5s %-6ld %-11s %-10s %-13s %6lu ",
                ss_proto, refcnt, ss_flags, ss_type, ss_state, inode
                );
 
+#if ENABLE_FEATURE_NETSTAT_PRG
+       if (prg_flag)
+               printf(PROGNAME_WIDTHs, prg_cache_get(inode));
+#endif
+
        /* TODO: currently we stop at first NUL byte. Is it a problem? */
        line += path_ofs;
        *strchrnul(line, '\n') = '\0';
        while (*line)
                fputc_printable(*line++, stdout);
@@ -495,10 +747,12 @@
        smallint inet6 = 1;
 #else
        enum { inet = 1, inet6 = 0 };
 #endif
 
+       INIT_G();
+
        /* Option string must match NETSTAT_xxx constants */
        opt = getopt32(argv, NETSTAT_OPTS);
        if (opt & 0x1) { // -l
                flags &= ~NETSTAT_CONNECTED;
                flags |= NETSTAT_LISTENING;
@@ -508,24 +762,27 @@
        if (opt & 0x8) flags |= NETSTAT_NUMERIC; // -n
        //if (opt & 0x10) // -t: NETSTAT_TCP
        //if (opt & 0x20) // -u: NETSTAT_UDP
        //if (opt & 0x40) // -w: NETSTAT_RAW
        //if (opt & 0x80) // -x: NETSTAT_UNIX
-       if (opt & OPT_showroute) { // -r
-#if ENABLE_ROUTE
+       if (opt & OPT_route) { // -r
                bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & 
OPT_extended));
                return 0;
-#else
-               bb_show_usage();
-#endif
        }
 
-       if (opt & OPT_widedisplay) { // -W
+       if (opt & OPT_wide) { // -W
                net_conn_line = PRINT_NET_CONN_WIDE;
                net_conn_line_header = PRINT_NET_CONN_HEADER_WIDE;
        }
 
+#if ENABLE_FEATURE_NETSTAT_PRG
+       if (opt & OPT_prg) { // -p
+               prg_flag = 1;
+               prg_cache_load();
+       }
+#endif
+
        opt &= NETSTAT_ALLPROTO;
        if (opt) {
                flags &= ~NETSTAT_ALLPROTO;
                flags |= opt;
        }
@@ -537,10 +794,14 @@
                else if (flags & NETSTAT_LISTENING)
                        printf("(only servers)");
                else
                        printf("(w/o servers)");
                printf(net_conn_line_header, "Local Address", "Foreign 
Address");
+#if ENABLE_FEATURE_NETSTAT_PRG
+               print_progname_banner();
+#endif
+               printf("\n");
        }
        if (inet && flags & NETSTAT_TCP)
                do_info(_PATH_PROCNET_TCP, "AF INET (tcp)", tcp_do_one);
 #if ENABLE_FEATURE_IPV6
        if (inet6 && flags & NETSTAT_TCP)
@@ -564,10 +825,18 @@
                        printf("(servers and established)");
                else if (flags & NETSTAT_LISTENING)
                        printf("(only servers)");
                else
                        printf("(w/o servers)");
-               printf("\nProto RefCnt Flags       Type       State         
I-Node Path\n");
+               printf("\nProto RefCnt Flags       Type       State         
I-Node");
+#if ENABLE_FEATURE_NETSTAT_PRG
+               print_progname_banner();
+#endif
+               printf(" Path\n");
                do_info(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one);
        }
+#if ENABLE_FEATURE_NETSTAT_PRG
+       if (ENABLE_FEATURE_CLEAN_UP)
+               prg_cache_clear();
+#endif
        return 0;
 }
_______________________________________________
busybox mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/busybox

Reply via email to