X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=networking%2Fnetstat.c;h=0c3f93191d9a67cb9f2e0ffc98b89bee2b3b6846;hb=510f56aa6fe62465989507b163ab737c2cf882aa;hp=d86c2ff5ea3f623abd807037a1793bbb1ca4d31f;hpb=7221c8c22dd527700204eb5cc4d0651af4273f4f;p=oweals%2Fbusybox.git diff --git a/networking/netstat.c b/networking/netstat.c index d86c2ff5e..0c3f93191 100644 --- a/networking/netstat.c +++ b/networking/netstat.c @@ -8,18 +8,37 @@ * 2002-04-20 * IPV6 support added by Bart Visscher * + * 2008-07-10 + * optional '-p' flag support ported from net-tools by G. Somlo + * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ #include "libbb.h" #include "inet_common.h" +#define NETSTAT_OPTS "laentuwx" \ + IF_ROUTE( "r") \ + IF_FEATURE_NETSTAT_WIDE("W") \ + IF_FEATURE_NETSTAT_PRG( "p") + enum { - OPT_extended = 0x4, - OPT_showroute = 0x100, - OPT_widedisplay = 0x200 * ENABLE_FEATURE_NETSTAT_WIDE, + OPTBIT_KEEP_OLD = 7, + IF_ROUTE( OPTBIT_ROUTE,) + IF_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,) + IF_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 = IF_ROUTE( (1 << OPTBIT_ROUTE)) + 0, // r + OPT_wide = IF_FEATURE_NETSTAT_WIDE((1 << OPTBIT_WIDE )) + 0, // W + OPT_prg = IF_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 @@ -31,7 +50,6 @@ enum { #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, @@ -44,7 +62,7 @@ enum { TCP_CLOSE_WAIT, TCP_LAST_ACK, TCP_LISTEN, - TCP_CLOSING /* now a valid state */ + TCP_CLOSING, /* now a valid state */ }; static const char *const tcp_state[] = { @@ -76,8 +94,8 @@ typedef enum { /* 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 @@ -86,10 +104,201 @@ typedef enum { * 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 " + + +#define PROGNAME_WIDTH 20 +#define PROGNAME_WIDTH_STR "20" +/* PROGNAME_WIDTH chars: 12345678901234567890 */ +#define PROGNAME_BANNER "PID/Program name " + +struct prg_node { + struct prg_node *next; + long inode; + char name[PROGNAME_WIDTH]; +}; + +#define PRG_HASH_SIZE 211 + + +struct globals { + const char *net_conn_line; + smallint flags; +#if ENABLE_FEATURE_NETSTAT_PRG + smallint prg_cache_loaded; + struct prg_node *prg_hash[PRG_HASH_SIZE]; +#endif +}; +#define G (*ptr_to_globals) +#define flags (G.flags ) +#define net_conn_line (G.net_conn_line ) +#define prg_hash (G.prg_hash ) +#define prg_cache_loaded (G.prg_cache_loaded) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ + flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \ + net_conn_line = PRINT_NET_CONN; \ +} while (0) + + +#if ENABLE_FEATURE_NETSTAT_PRG + +/* Deliberately truncating long to unsigned *int* */ +#define PRG_HASHIT(x) ((unsigned)(x) % PRG_HASH_SIZE) + +#define print_progname_banner() do { \ + if (option_mask32 & OPT_prg) printf(PROGNAME_BANNER); \ +} while (0) + +static void prg_cache_add(long inode, char *name) +{ + unsigned hi = PRG_HASHIT(inode); + struct prg_node **pnp, *pn; + + prg_cache_loaded = 2; + for (pnp = prg_hash + hi; (pn = *pnp) != NULL; 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 *net_conn_line = PRINT_NET_CONN; +static const char *prg_cache_get(long 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 "-"; +} + +#if ENABLE_FEATURE_CLEAN_UP +static void prg_cache_clear(void) +{ + struct prg_node **pnp, *pn; + + for (pnp = prg_hash; pnp < prg_hash + PRG_HASH_SIZE; pnp++) { + while ((pn = *pnp) != NULL) { + *pnp = pn->next; + free(pn); + } + } +} +#else +#define prg_cache_clear() ((void)0) +#endif + +static long extract_socket_inode(const char *lname) +{ + long inode = -1; + + if (strncmp(lname, "socket:[", sizeof("socket:[")-1) == 0) { + /* "socket:[12345]", extract the "12345" as inode */ + inode = bb_strtol(lname + sizeof("socket:[")-1, (char**)&lname, 0); + if (*lname != ']') + inode = -1; + } else if (strncmp(lname, "[0000]:", sizeof("[0000]:")-1) == 0) { + /* "[0000]:12345", extract the "12345" as inode */ + inode = bb_strtol(lname + sizeof("[0000]:")-1, NULL, 0); + if (errno) /* not NUL terminated? */ + inode = -1; + } + +#if 0 /* bb_strtol returns all-ones bit pattern on ERANGE anyway */ + if (errno == ERANGE) + inode = -1; +#endif + return inode; +} + +static int FAST_FUNC file_act(const char *fileName, + struct stat *statbuf UNUSED_PARAM, + void *userData, + int depth UNUSED_PARAM) +{ + char *linkname; + long inode; + + linkname = xmalloc_readlink(fileName); + if (linkname != NULL) { + inode = extract_socket_inode(linkname); + free(linkname); + if (inode >= 0) + prg_cache_add(inode, (char *)userData); + } + return TRUE; +} + +static int FAST_FUNC dir_act(const char *fileName, + struct stat *statbuf UNUSED_PARAM, + void *userData UNUSED_PARAM, + int depth) +{ + const char *shortName; + char *p, *q; + char cmdline_buf[512]; + int i; + + if (depth == 0) /* "/proc" itself */ + return TRUE; /* continue looking one level below /proc */ + + shortName = fileName + sizeof("/proc/")-1; /* point after "/proc/" */ + if (!isdigit(shortName[0])) /* skip /proc entries whic aren't processes */ + return SKIP; + + p = concat_path_file(fileName, "cmdline"); /* "/proc/PID/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(shortName, bb_basename(cmdline_buf)); /* "PID/argv0" */ + + /* go through all files in /proc/PID/fd */ + p = concat_path_file(fileName, "fd"); + 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; + + prg_cache_loaded = 1; + load_ok = recursive_action("/proc", ACTION_RECURSE | ACTION_QUIET, + NULL, dir_act, NULL, 0); + if (load_ok) + return; + + if (prg_cache_loaded == 1) + bb_error_msg("can't scan /proc - are you root?"); + else + bb_error_msg("showing only processes with your user ID"); +} + +#else + +#define prg_cache_clear() ((void)0) +#define print_progname_banner() ((void)0) + +#endif //ENABLE_FEATURE_NETSTAT_PRG #if ENABLE_FEATURE_IPV6 @@ -134,11 +343,10 @@ static const char *get_sname(int port, const char *proto, int numeric) static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int numeric) { - enum { salen = USE_FEATURE_IPV6(sizeof(struct sockaddr_in6)) SKIP_FEATURE_IPV6(sizeof(struct sockaddr_in)) }; char *host, *host_port; - /* Code which used "*" for INADDR_ANY is removed: it's ambiguous in IPv6, - * while "0.0.0.0" is not. */ + /* Code which used "*" for INADDR_ANY is removed: it's ambiguous + * in IPv6, while "0.0.0.0" is not. */ host = numeric ? xmalloc_sockaddr2dotted_noport(addr) : xmalloc_sockaddr2host_noport(addr); @@ -148,108 +356,80 @@ static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int return host_port; } -static void tcp_do_one(int lnr, char *line) -{ - char local_addr[64], rem_addr[64]; - char more[512]; - int num, local_port, rem_port, d, state, timer_run, uid, timeout; +struct inet_params { + int local_port, rem_port, state, uid; #if ENABLE_FEATURE_IPV6 struct sockaddr_in6 localaddr, remaddr; #else struct sockaddr_in localaddr, remaddr; #endif - unsigned long rxq, txq, time_len, retr, inode; + unsigned long rxq, txq, inode; +}; - if (lnr == 0) - return; +static int scan_inet_proc_line(struct inet_params *param, char *line) +{ + int num; + char local_addr[64], rem_addr[64]; - more[0] = '\0'; num = sscanf(line, - "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", - &d, local_addr, &local_port, - rem_addr, &rem_port, &state, - &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); + "%*d: %64[0-9A-Fa-f]:%X " + "%64[0-9A-Fa-f]:%X %X " + "%lX:%lX %*X:%*X " + "%*X %d %*d %ld ", + local_addr, ¶m->local_port, + rem_addr, ¶m->rem_port, ¶m->state, + ¶m->txq, ¶m->rxq, + ¶m->uid, ¶m->inode); + if (num < 9) { + return 1; /* error */ + } if (strlen(local_addr) > 8) { #if ENABLE_FEATURE_IPV6 - build_ipv6_addr(local_addr, &localaddr); - build_ipv6_addr(rem_addr, &remaddr); + build_ipv6_addr(local_addr, ¶m->localaddr); + build_ipv6_addr(rem_addr, ¶m->remaddr); #endif } else { - build_ipv4_addr(local_addr, &localaddr); - build_ipv4_addr(rem_addr, &remaddr); - } - - if (num < 10) { - bb_error_msg("warning, got bogus tcp line"); - return; + build_ipv4_addr(local_addr, ¶m->localaddr); + build_ipv4_addr(rem_addr, ¶m->remaddr); } + return 0; +} - if ((rem_port && (flags & NETSTAT_CONNECTED)) - || (!rem_port && (flags & NETSTAT_LISTENING)) +static void print_inet_line(struct inet_params *param, + const char *state_str, const char *proto, int is_connected) +{ + if ((is_connected && (flags & NETSTAT_CONNECTED)) + || (!is_connected && (flags & NETSTAT_LISTENING)) ) { char *l = ip_port_str( - (struct sockaddr *) &localaddr, local_port, - "tcp", flags & NETSTAT_NUMERIC); + (struct sockaddr *) ¶m->localaddr, param->local_port, + proto, flags & NETSTAT_NUMERIC); char *r = ip_port_str( - (struct sockaddr *) &remaddr, rem_port, - "tcp", flags & NETSTAT_NUMERIC); + (struct sockaddr *) ¶m->remaddr, param->rem_port, + proto, flags & NETSTAT_NUMERIC); printf(net_conn_line, - "tcp", rxq, txq, l, r, tcp_state[state]); + proto, param->rxq, param->txq, l, r, state_str); +#if ENABLE_FEATURE_NETSTAT_PRG + if (option_mask32 & OPT_prg) + printf("%."PROGNAME_WIDTH_STR"s", prg_cache_get(param->inode)); +#endif + bb_putchar('\n'); free(l); free(r); } } -static void udp_do_one(int lnr, char *line) +static int FAST_FUNC tcp_do_one(char *line) { - char local_addr[64], rem_addr[64]; - const char *state_str; - char more[512]; - int num, local_port, rem_port, d, state, timer_run, uid, timeout; -#if ENABLE_FEATURE_IPV6 - struct sockaddr_in6 localaddr, remaddr; -#else - struct sockaddr_in localaddr, remaddr; -#endif - unsigned long rxq, txq, time_len, retr, inode; + struct inet_params param; - if (lnr == 0) - return; - - more[0] = '\0'; - num = sscanf(line, - "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", - &d, local_addr, &local_port, - rem_addr, &rem_port, &state, - &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); - - if (strlen(local_addr) > 8) { -#if ENABLE_FEATURE_IPV6 - /* Demangle what the kernel gives us */ - build_ipv6_addr(local_addr, &localaddr); - build_ipv6_addr(rem_addr, &remaddr); -#endif - } else { - build_ipv4_addr(local_addr, &localaddr); - build_ipv4_addr(rem_addr, &remaddr); - } + if (scan_inet_proc_line(¶m, line)) + return 1; - if (num < 10) { - bb_error_msg("warning, got bogus udp line"); - return; - } - switch (state) { - case TCP_ESTABLISHED: - state_str = "ESTABLISHED"; - break; - case TCP_CLOSE: - state_str = ""; - break; - default: - state_str = "UNKNOWN"; - break; - } + print_inet_line(¶m, tcp_state[param.state], "tcp", param.rem_port); + return 0; +} #if ENABLE_FEATURE_IPV6 # define notnull(A) ( \ @@ -264,119 +444,72 @@ static void udp_do_one(int lnr, char *line) #else # define notnull(A) (A.sin_addr.s_addr) #endif - { - int have_remaddr = notnull(remaddr); - if ((have_remaddr && (flags & NETSTAT_CONNECTED)) - || (!have_remaddr && (flags & NETSTAT_LISTENING)) - ) { - char *l = ip_port_str( - (struct sockaddr *) &localaddr, local_port, - "udp", flags & NETSTAT_NUMERIC); - 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); - free(l); - free(r); - } - } -} -static void raw_do_one(int lnr, char *line) +static int FAST_FUNC udp_do_one(char *line) { - char local_addr[64], rem_addr[64]; - char more[512]; - int num, local_port, rem_port, d, state, timer_run, uid, timeout; -#if ENABLE_FEATURE_IPV6 - struct sockaddr_in6 localaddr, remaddr; -#else - struct sockaddr_in localaddr, remaddr; -#endif - unsigned long rxq, txq, time_len, retr, inode; - - if (lnr == 0) - return; + int have_remaddr; + const char *state_str; + struct inet_params param; + + if (scan_inet_proc_line(¶m, line)) + return 1; + + state_str = "UNKNOWN"; + switch (param.state) { + case TCP_ESTABLISHED: + state_str = "ESTABLISHED"; + break; + case TCP_CLOSE: + state_str = ""; + break; + } - more[0] = '\0'; - num = sscanf(line, - "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", - &d, local_addr, &local_port, - rem_addr, &rem_port, &state, - &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); + have_remaddr = notnull(param.remaddr); + print_inet_line(¶m, state_str, "udp", have_remaddr); + return 0; +} - if (strlen(local_addr) > 8) { -#if ENABLE_FEATURE_IPV6 - build_ipv6_addr(local_addr, &localaddr); - build_ipv6_addr(rem_addr, &remaddr); -#endif - } else { - build_ipv4_addr(local_addr, &localaddr); - build_ipv4_addr(rem_addr, &remaddr); - } +static int FAST_FUNC raw_do_one(char *line) +{ + int have_remaddr; + struct inet_params param; - if (num < 10) { - bb_error_msg("warning, got bogus raw line"); - return; - } + if (scan_inet_proc_line(¶m, line)) + return 1; - { - int have_remaddr = notnull(remaddr); - if ((have_remaddr && (flags & NETSTAT_CONNECTED)) - || (!have_remaddr && (flags & NETSTAT_LISTENING)) - ) { - char *l = ip_port_str( - (struct sockaddr *) &localaddr, local_port, - "raw", flags & NETSTAT_NUMERIC); - 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)); - free(l); - free(r); - } - } + have_remaddr = notnull(param.remaddr); + print_inet_line(¶m, itoa(param.state), "raw", have_remaddr); + return 0; } -static void unix_do_one(int nr, char *line) +static int FAST_FUNC unix_do_one(char *line) { unsigned long refcnt, proto, unix_flags; unsigned long inode; int type, state; int num, path_ofs; - void *d; const char *ss_proto, *ss_state, *ss_type; char ss_flags[32]; - if (nr == 0) - return; /* skip header */ - - { - char *last = last_char_is(line, '\n'); - if (last) - *last = '\0'; - } - /* 2.6.15 may report lines like "... @/tmp/fam-user-^@^@^@^@^@^@^@..." - * (those ^@ are NUL bytes). fgets sees them as tons of empty lines. */ + * Other users report long lines filled by NUL bytes. + * (those ^@ are NUL bytes too). We see them as empty lines. */ if (!line[0]) - return; + return 0; path_ofs = 0; /* paranoia */ - num = sscanf(line, "%p: %lX %lX %lX %X %X %lu %n", - &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, &path_ofs); - if (num < 7) { - bb_error_msg("got bogus unix line '%s'", line); - return; + num = sscanf(line, "%*p: %lX %lX %lX %X %X %lu %n", + &refcnt, &proto, &unix_flags, &type, &state, &inode, &path_ofs); + if (num < 6) { + return 1; /* error */ } if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) != (NETSTAT_LISTENING|NETSTAT_CONNECTED)) { if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) { if (!(flags & NETSTAT_LISTENING)) - return; + return 0; } else { if (!(flags & NETSTAT_CONNECTED)) - return; + return 0; } } @@ -445,60 +578,54 @@ static void unix_do_one(int nr, char *line) strcat(ss_flags, "N "); strcat(ss_flags, "]"); - printf("%-5s %-6ld %-11s %-10s %-13s %6lu %s\n", - ss_proto, refcnt, ss_flags, ss_type, ss_state, inode, - line + path_ofs); -} + printf("%-5s %-6ld %-11s %-10s %-13s %6lu ", + ss_proto, refcnt, ss_flags, ss_type, ss_state, inode + ); -#define _PATH_PROCNET_UDP "/proc/net/udp" -#define _PATH_PROCNET_UDP6 "/proc/net/udp6" -#define _PATH_PROCNET_TCP "/proc/net/tcp" -#define _PATH_PROCNET_TCP6 "/proc/net/tcp6" -#define _PATH_PROCNET_RAW "/proc/net/raw" -#define _PATH_PROCNET_RAW6 "/proc/net/raw6" -#define _PATH_PROCNET_UNIX "/proc/net/unix" +#if ENABLE_FEATURE_NETSTAT_PRG + if (option_mask32 & OPT_prg) + printf("%-"PROGNAME_WIDTH_STR"s", prg_cache_get(inode)); +#endif -static void do_info(const char *file, const char *name, void (*proc)(int, char *)) + /* 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); + bb_putchar('\n'); + return 0; +} + +static void do_info(const char *file, int FAST_FUNC (*proc)(char *)) { int lnr; FILE *procinfo; char *buffer; - procinfo = fopen(file, "r"); + /* _stdin is just to save "r" param */ + procinfo = fopen_or_warn_stdin(file); if (procinfo == NULL) { - if (errno != ENOENT) { - bb_simple_perror_msg(file); - } else { - bb_error_msg("no support for '%s' on this system", name); - } return; } lnr = 0; - do { - buffer = xmalloc_fgets(procinfo); - if (buffer) { - (proc)(lnr++, buffer); - free(buffer); - } - } while (buffer); + /* Why xmalloc_fgets_str? because it doesn't stop on NULs */ + while ((buffer = xmalloc_fgets_str(procinfo, "\n")) != NULL) { + /* line 0 is skipped */ + if (lnr && proc(buffer)) + bb_error_msg("%s: bogus data on line %d", file, lnr + 1); + lnr++; + free(buffer); + } fclose(procinfo); } -/* - * Our main function. - */ - int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int netstat_main(int argc, char **argv) +int netstat_main(int argc UNUSED_PARAM, char **argv) { const char *net_conn_line_header = PRINT_NET_CONN_HEADER; unsigned opt; -#if ENABLE_FEATURE_IPV6 - smallint inet = 1; - smallint inet6 = 1; -#else - enum { inet = 1, inet6 = 0 }; -#endif + + INIT_G(); /* Option string must match NETSTAT_xxx constants */ opt = getopt32(argv, NETSTAT_OPTS); @@ -513,7 +640,7 @@ int netstat_main(int argc, char **argv) //if (opt & 0x20) // -u: NETSTAT_UDP //if (opt & 0x40) // -w: NETSTAT_RAW //if (opt & 0x80) // -x: NETSTAT_UNIX - if (opt & OPT_showroute) { // -r + if (opt & OPT_route) { // -r #if ENABLE_ROUTE bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended)); return 0; @@ -521,11 +648,15 @@ int netstat_main(int argc, char **argv) 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_cache_load(); + } +#endif opt &= NETSTAT_ALLPROTO; if (opt) { @@ -542,25 +673,27 @@ int netstat_main(int argc, char **argv) else printf("(w/o servers)"); printf(net_conn_line_header, "Local Address", "Foreign Address"); + print_progname_banner(); + bb_putchar('\n'); } - if (inet && flags & NETSTAT_TCP) - do_info(_PATH_PROCNET_TCP, "AF INET (tcp)", tcp_do_one); + if (flags & NETSTAT_TCP) { + do_info("/proc/net/tcp", tcp_do_one); #if ENABLE_FEATURE_IPV6 - if (inet6 && flags & NETSTAT_TCP) - do_info(_PATH_PROCNET_TCP6, "AF INET6 (tcp)", tcp_do_one); + do_info("/proc/net/tcp6", tcp_do_one); #endif - if (inet && flags & NETSTAT_UDP) - do_info(_PATH_PROCNET_UDP, "AF INET (udp)", udp_do_one); + } + if (flags & NETSTAT_UDP) { + do_info("/proc/net/udp", udp_do_one); #if ENABLE_FEATURE_IPV6 - if (inet6 && flags & NETSTAT_UDP) - do_info(_PATH_PROCNET_UDP6, "AF INET6 (udp)", udp_do_one); + do_info("/proc/net/udp6", udp_do_one); #endif - if (inet && flags & NETSTAT_RAW) - do_info(_PATH_PROCNET_RAW, "AF INET (raw)", raw_do_one); + } + if (flags & NETSTAT_RAW) { + do_info("/proc/net/raw", raw_do_one); #if ENABLE_FEATURE_IPV6 - if (inet6 && flags & NETSTAT_RAW) - do_info(_PATH_PROCNET_RAW6, "AF INET6 (raw)", raw_do_one); + do_info("/proc/net/raw6", raw_do_one); #endif + } if (flags & NETSTAT_UNIX) { printf("Active UNIX domain sockets "); if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED)) @@ -569,8 +702,11 @@ int netstat_main(int argc, char **argv) printf("(only servers)"); else printf("(w/o servers)"); - printf("\nProto RefCnt Flags Type State I-Node Path\n"); - do_info(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one); + printf("\nProto RefCnt Flags Type State I-Node "); + print_progname_banner(); + printf("Path\n"); + do_info("/proc/net/unix", unix_do_one); } + prg_cache_clear(); return 0; }