Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/networking/netstat.c

    r1765 r2725  
    99 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
    1010 *
    11  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     11 * 2008-07-10
     12 * optional '-p' flag support ported from net-tools by G. Somlo <somlo@cmu.edu>
     13 *
     14 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1215 */
    1316
     
    1518#include "inet_common.h"
    1619
     20//usage:#define netstat_trivial_usage
     21//usage:       "[-"IF_ROUTE("r")"al] [-tuwx] [-en"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]"
     22//usage:#define netstat_full_usage "\n\n"
     23//usage:       "Display networking information\n"
     24//usage:     "\nOptions:"
     25//usage:    IF_ROUTE(
     26//usage:     "\n    -r  Routing table"
     27//usage:    )
     28//usage:     "\n    -a  All sockets"
     29//usage:     "\n    -l  Listening sockets"
     30//usage:     "\n        Else: connected sockets"
     31//usage:     "\n    -t  TCP sockets"
     32//usage:     "\n    -u  UDP sockets"
     33//usage:     "\n    -w  Raw sockets"
     34//usage:     "\n    -x  Unix sockets"
     35//usage:     "\n        Else: all socket types"
     36//usage:     "\n    -e  Other/more information"
     37//usage:     "\n    -n  Don't resolve names"
     38//usage:    IF_FEATURE_NETSTAT_WIDE(
     39//usage:     "\n    -W  Wide display"
     40//usage:    )
     41//usage:    IF_FEATURE_NETSTAT_PRG(
     42//usage:     "\n    -p  Show PID/program name for sockets"
     43//usage:    )
     44
     45#define NETSTAT_OPTS "laentuwx" \
     46    IF_ROUTE(               "r") \
     47    IF_FEATURE_NETSTAT_WIDE("W") \
     48    IF_FEATURE_NETSTAT_PRG( "p")
     49
    1750enum {
    18     OPT_extended = 0x4,
    19     OPT_showroute = 0x100,
    20     OPT_widedisplay = 0x200 * ENABLE_FEATURE_NETSTAT_WIDE,
     51    OPT_sock_listen = 1 << 0, // l
     52    OPT_sock_all    = 1 << 1, // a
     53    OPT_extended    = 1 << 2, // e
     54    OPT_noresolve   = 1 << 3, // n
     55    OPT_sock_tcp    = 1 << 4, // t
     56    OPT_sock_udp    = 1 << 5, // u
     57    OPT_sock_raw    = 1 << 6, // w
     58    OPT_sock_unix   = 1 << 7, // x
     59    OPTBIT_x        = 7,
     60    IF_ROUTE(               OPTBIT_ROUTE,)
     61    IF_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,)
     62    IF_FEATURE_NETSTAT_PRG( OPTBIT_PRG  ,)
     63    OPT_route       = IF_ROUTE(               (1 << OPTBIT_ROUTE)) + 0, // r
     64    OPT_wide        = IF_FEATURE_NETSTAT_WIDE((1 << OPTBIT_WIDE )) + 0, // W
     65    OPT_prg         = IF_FEATURE_NETSTAT_PRG( (1 << OPTBIT_PRG  )) + 0, // p
    2166};
    22 # define NETSTAT_OPTS "laentuwxr"USE_FEATURE_NETSTAT_WIDE("W")
    2367
    2468#define NETSTAT_CONNECTED 0x01
     
    3276#define NETSTAT_ALLPROTO  (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX)
    3377
    34 static smallint flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO;
    3578
    3679enum {
     
    4588    TCP_LAST_ACK,
    4689    TCP_LISTEN,
    47     TCP_CLOSING /* now a valid state */
     90    TCP_CLOSING, /* now a valid state */
    4891};
    4992
     
    71114} socket_state;
    72115
    73 #define SO_ACCEPTCON (1<<16)    /* performed a listen           */
    74 #define SO_WAITDATA  (1<<17)    /* wait data to read            */
    75 #define SO_NOSPACE   (1<<18)    /* no space to write            */
    76 
    77 /* Standard printout size */
    78 #define PRINT_IP_MAX_SIZE           23
    79 #define PRINT_NET_CONN              "%s   %6ld %6ld %-23s %-23s %-12s\n"
    80 #define PRINT_NET_CONN_HEADER       "\nProto Recv-Q Send-Q %-23s %-23s State\n"
    81 
     116#define SO_ACCEPTCON (1<<16)  /* performed a listen           */
     117#define SO_WAITDATA  (1<<17)  /* wait data to read            */
     118#define SO_NOSPACE   (1<<18)  /* no space to write            */
     119
     120#define ADDR_NORMAL_WIDTH        23
    82121/* When there are IPv6 connections the IPv6 addresses will be
    83122 * truncated to none-recognition. The '-W' option makes the
     
    86125 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd
    87126 */
    88 #define PRINT_IP_MAX_SIZE_WIDE      51  /* INET6_ADDRSTRLEN + 5 for the port number */
    89 #define PRINT_NET_CONN_WIDE         "%s   %6ld %6ld %-51s %-51s %-12s\n"
    90 #define PRINT_NET_CONN_HEADER_WIDE  "\nProto Recv-Q Send-Q %-51s %-51s State\n"
    91 
    92 static const char *net_conn_line = PRINT_NET_CONN;
     127#define ADDR_WIDE                51  /* INET6_ADDRSTRLEN + 5 for the port number */
     128#if ENABLE_FEATURE_NETSTAT_WIDE
     129# define FMT_NET_CONN_DATA       "%s   %6ld %6ld %-*s %-*s %-12s"
     130# define FMT_NET_CONN_HEADER     "\nProto Recv-Q Send-Q %-*s %-*s State       %s\n"
     131#else
     132# define FMT_NET_CONN_DATA       "%s   %6ld %6ld %-23s %-23s %-12s"
     133# define FMT_NET_CONN_HEADER     "\nProto Recv-Q Send-Q %-23s %-23s State       %s\n"
     134#endif
     135
     136#define PROGNAME_WIDTH     20
     137#define PROGNAME_WIDTH_STR "20"
     138/* PROGNAME_WIDTH chars: 12345678901234567890 */
     139#define PROGNAME_BANNER "PID/Program name    "
     140
     141struct prg_node {
     142    struct prg_node *next;
     143    long inode;
     144    char name[PROGNAME_WIDTH];
     145};
     146
     147#define PRG_HASH_SIZE 211
     148
     149struct globals {
     150    smallint flags;
     151#if ENABLE_FEATURE_NETSTAT_PRG
     152    smallint prg_cache_loaded;
     153    struct prg_node *prg_hash[PRG_HASH_SIZE];
     154#endif
     155#if ENABLE_FEATURE_NETSTAT_PRG
     156    const char *progname_banner;
     157#endif
     158#if ENABLE_FEATURE_NETSTAT_WIDE
     159    unsigned addr_width;
     160#endif
     161};
     162#define G (*ptr_to_globals)
     163#define flags            (G.flags           )
     164#define prg_cache_loaded (G.prg_cache_loaded)
     165#define prg_hash         (G.prg_hash        )
     166#if ENABLE_FEATURE_NETSTAT_PRG
     167# define progname_banner (G.progname_banner )
     168#else
     169# define progname_banner ""
     170#endif
     171#define INIT_G() do { \
     172    SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
     173    flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \
     174} while (0)
     175
     176
     177#if ENABLE_FEATURE_NETSTAT_PRG
     178
     179/* Deliberately truncating long to unsigned *int* */
     180#define PRG_HASHIT(x) ((unsigned)(x) % PRG_HASH_SIZE)
     181
     182static void prg_cache_add(long inode, char *name)
     183{
     184    unsigned hi = PRG_HASHIT(inode);
     185    struct prg_node **pnp, *pn;
     186
     187    prg_cache_loaded = 2;
     188    for (pnp = prg_hash + hi; (pn = *pnp) != NULL; pnp = &pn->next) {
     189        if (pn->inode == inode) {
     190            /* Some warning should be appropriate here
     191               as we got multiple processes for one i-node */
     192            return;
     193        }
     194    }
     195    *pnp = xzalloc(sizeof(struct prg_node));
     196    pn = *pnp;
     197    pn->inode = inode;
     198    safe_strncpy(pn->name, name, PROGNAME_WIDTH);
     199}
     200
     201static const char *prg_cache_get(long inode)
     202{
     203    unsigned hi = PRG_HASHIT(inode);
     204    struct prg_node *pn;
     205
     206    for (pn = prg_hash[hi]; pn; pn = pn->next)
     207        if (pn->inode == inode)
     208            return pn->name;
     209    return "-";
     210}
     211
     212#if ENABLE_FEATURE_CLEAN_UP
     213static void prg_cache_clear(void)
     214{
     215    struct prg_node **pnp, *pn;
     216
     217    for (pnp = prg_hash; pnp < prg_hash + PRG_HASH_SIZE; pnp++) {
     218        while ((pn = *pnp) != NULL) {
     219            *pnp = pn->next;
     220            free(pn);
     221        }
     222    }
     223}
     224#else
     225#define prg_cache_clear() ((void)0)
     226#endif
     227
     228static long extract_socket_inode(const char *lname)
     229{
     230    long inode = -1;
     231
     232    if (strncmp(lname, "socket:[", sizeof("socket:[")-1) == 0) {
     233        /* "socket:[12345]", extract the "12345" as inode */
     234        inode = bb_strtoul(lname + sizeof("socket:[")-1, (char**)&lname, 0);
     235        if (*lname != ']')
     236            inode = -1;
     237    } else if (strncmp(lname, "[0000]:", sizeof("[0000]:")-1) == 0) {
     238        /* "[0000]:12345", extract the "12345" as inode */
     239        inode = bb_strtoul(lname + sizeof("[0000]:")-1, NULL, 0);
     240        if (errno) /* not NUL terminated? */
     241            inode = -1;
     242    }
     243
     244#if 0 /* bb_strtol returns all-ones bit pattern on ERANGE anyway */
     245    if (errno == ERANGE)
     246        inode = -1;
     247#endif
     248    return inode;
     249}
     250
     251static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName,
     252        struct stat *statbuf UNUSED_PARAM,
     253        void *pid_slash_progname,
     254        int depth UNUSED_PARAM)
     255{
     256    char *linkname;
     257    long inode;
     258
     259    linkname = xmalloc_readlink(fileName);
     260    if (linkname != NULL) {
     261        inode = extract_socket_inode(linkname);
     262        free(linkname);
     263        if (inode >= 0)
     264            prg_cache_add(inode, (char *)pid_slash_progname);
     265    }
     266    return TRUE;
     267}
     268
     269static int FAST_FUNC dir_act(const char *fileName,
     270        struct stat *statbuf UNUSED_PARAM,
     271        void *userData UNUSED_PARAM,
     272        int depth)
     273{
     274    const char *pid;
     275    char *pid_slash_progname;
     276    char proc_pid_fname[sizeof("/proc/%u/cmdline") + sizeof(long)*3];
     277    char cmdline_buf[512];
     278    int n, len;
     279
     280    if (depth == 0) /* "/proc" itself */
     281        return TRUE; /* continue looking one level below /proc */
     282
     283    pid = fileName + sizeof("/proc/")-1; /* point after "/proc/" */
     284    if (!isdigit(pid[0])) /* skip /proc entries which aren't processes */
     285        return SKIP;
     286
     287    len = snprintf(proc_pid_fname, sizeof(proc_pid_fname), "%s/cmdline", fileName);
     288    n = open_read_close(proc_pid_fname, cmdline_buf, sizeof(cmdline_buf) - 1);
     289    if (n < 0)
     290        return FALSE;
     291    cmdline_buf[n] = '\0';
     292
     293    /* go through all files in /proc/PID/fd and check whether they are sockets */
     294    strcpy(proc_pid_fname + len - (sizeof("cmdline")-1), "fd");
     295    pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */
     296    n = recursive_action(proc_pid_fname,
     297            ACTION_RECURSE | ACTION_QUIET,
     298            add_to_prg_cache_if_socket,
     299            NULL,
     300            (void *)pid_slash_progname,
     301            0);
     302    free(pid_slash_progname);
     303
     304    if (!n)
     305        return FALSE; /* signal permissions error to caller */
     306
     307    return SKIP; /* caller should not recurse further into this dir */
     308}
     309
     310static void prg_cache_load(void)
     311{
     312    int load_ok;
     313
     314    prg_cache_loaded = 1;
     315    load_ok = recursive_action("/proc", ACTION_RECURSE | ACTION_QUIET,
     316                NULL, dir_act, NULL, 0);
     317    if (load_ok)
     318        return;
     319
     320    if (prg_cache_loaded == 1)
     321        bb_error_msg("can't scan /proc - are you root?");
     322    else
     323        bb_error_msg("showing only processes with your user ID");
     324}
     325
     326#else
     327
     328#define prg_cache_clear()       ((void)0)
     329
     330#endif //ENABLE_FEATURE_NETSTAT_PRG
    93331
    94332
     
    103341           &in6.s6_addr32[2], &in6.s6_addr32[3]);
    104342    inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
    105     inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr->sin6_addr);
     343    inet_pton(AF_INET6, addr6, &localaddr->sin6_addr);
    106344
    107345    localaddr->sin6_family = AF_INET6;
     
    109347#endif
    110348
    111 #if ENABLE_FEATURE_IPV6
    112 static void build_ipv4_addr(char* local_addr, struct sockaddr_in6* localaddr)
    113 #else
    114349static void build_ipv4_addr(char* local_addr, struct sockaddr_in* localaddr)
    115 #endif
    116 {
    117     sscanf(local_addr, "%X",
    118            &((struct sockaddr_in *) localaddr)->sin_addr.s_addr);
    119     ((struct sockaddr *) localaddr)->sa_family = AF_INET;
     350{
     351    sscanf(local_addr, "%X", &localaddr->sin_addr.s_addr);
     352    localaddr->sin_family = AF_INET;
    120353}
    121354
     
    135368static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int numeric)
    136369{
    137     enum { salen = USE_FEATURE_IPV6(sizeof(struct sockaddr_in6)) SKIP_FEATURE_IPV6(sizeof(struct sockaddr_in)) };
    138370    char *host, *host_port;
    139371
    140     /* Code which used "*" for INADDR_ANY is removed: it's ambiguous in IPv6,
    141      * while "0.0.0.0" is not. */
     372    /* Code which used "*" for INADDR_ANY is removed: it's ambiguous
     373     * in IPv6, while "0.0.0.0" is not. */
    142374
    143375    host = numeric ? xmalloc_sockaddr2dotted_noport(addr)
     
    149381}
    150382
    151 static void tcp_do_one(int lnr, const char *line)
    152 {
    153     char local_addr[64], rem_addr[64];
    154     char more[512];
    155     int num, local_port, rem_port, d, state, timer_run, uid, timeout;
     383struct inet_params {
     384    int local_port, rem_port, state, uid;
     385    union {
     386        struct sockaddr     sa;
     387        struct sockaddr_in  sin;
    156388#if ENABLE_FEATURE_IPV6
    157     struct sockaddr_in6 localaddr, remaddr;
    158 #else
    159     struct sockaddr_in localaddr, remaddr;
    160 #endif
    161     unsigned long rxq, txq, time_len, retr, inode;
    162 
    163     if (lnr == 0)
    164         return;
    165 
    166     more[0] = '\0';
     389        struct sockaddr_in6 sin6;
     390#endif
     391    } localaddr, remaddr;
     392    unsigned long rxq, txq, inode;
     393};
     394
     395static int scan_inet_proc_line(struct inet_params *param, char *line)
     396{
     397    int num;
     398    /* IPv6 /proc files use 32-char hex representation
     399     * of IPv6 address, followed by :PORT_IN_HEX
     400     */
     401    char local_addr[33], rem_addr[33]; /* 32 + 1 for NUL */
     402
    167403    num = sscanf(line,
    168             "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
    169             &d, local_addr, &local_port,
    170             rem_addr, &rem_port, &state,
    171             &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
     404            "%*d: %32[0-9A-Fa-f]:%X "
     405            "%32[0-9A-Fa-f]:%X %X "
     406            "%lX:%lX %*X:%*X "
     407            "%*X %d %*d %ld ",
     408            local_addr, &param->local_port,
     409            rem_addr, &param->rem_port, &param->state,
     410            &param->txq, &param->rxq,
     411            &param->uid, &param->inode);
     412    if (num < 9) {
     413        return 1; /* error */
     414    }
    172415
    173416    if (strlen(local_addr) > 8) {
    174417#if ENABLE_FEATURE_IPV6
    175         build_ipv6_addr(local_addr, &localaddr);
    176         build_ipv6_addr(rem_addr, &remaddr);
     418        build_ipv6_addr(local_addr, &param->localaddr.sin6);
     419        build_ipv6_addr(rem_addr, &param->remaddr.sin6);
    177420#endif
    178421    } else {
    179         build_ipv4_addr(local_addr, &localaddr);
    180         build_ipv4_addr(rem_addr, &remaddr);
    181     }
    182 
    183     if (num < 10) {
    184         bb_error_msg("warning, got bogus tcp line");
    185         return;
    186     }
    187 
    188     if ((rem_port && (flags & NETSTAT_CONNECTED))
    189      || (!rem_port && (flags & NETSTAT_LISTENING))
     422        build_ipv4_addr(local_addr, &param->localaddr.sin);
     423        build_ipv4_addr(rem_addr, &param->remaddr.sin);
     424    }
     425    return 0;
     426}
     427
     428static void print_inet_line(struct inet_params *param,
     429        const char *state_str, const char *proto, int is_connected)
     430{
     431    if ((is_connected && (flags & NETSTAT_CONNECTED))
     432     || (!is_connected && (flags & NETSTAT_LISTENING))
    190433    ) {
    191434        char *l = ip_port_str(
    192                 (struct sockaddr *) &localaddr, local_port,
    193                 "tcp", flags & NETSTAT_NUMERIC);
     435                &param->localaddr.sa, param->local_port,
     436                proto, flags & NETSTAT_NUMERIC);
    194437        char *r = ip_port_str(
    195                 (struct sockaddr *) &remaddr, rem_port,
    196                 "tcp", flags & NETSTAT_NUMERIC);
    197         printf(net_conn_line,
    198             "tcp", rxq, txq, l, r, tcp_state[state]);
     438                &param->remaddr.sa, param->rem_port,
     439                proto, flags & NETSTAT_NUMERIC);
     440        printf(FMT_NET_CONN_DATA,
     441            proto, param->rxq, param->txq,
     442            IF_FEATURE_NETSTAT_WIDE(G.addr_width,) l,
     443            IF_FEATURE_NETSTAT_WIDE(G.addr_width,) r,
     444            state_str);
     445#if ENABLE_FEATURE_NETSTAT_PRG
     446        if (option_mask32 & OPT_prg)
     447            printf("%."PROGNAME_WIDTH_STR"s", prg_cache_get(param->inode));
     448#endif
     449        bb_putchar('\n');
    199450        free(l);
    200451        free(r);
     
    202453}
    203454
    204 static void udp_do_one(int lnr, const char *line)
    205 {
    206     char local_addr[64], rem_addr[64];
    207     const char *state_str;
    208     char more[512];
    209     int num, local_port, rem_port, d, state, timer_run, uid, timeout;
     455static int FAST_FUNC tcp_do_one(char *line)
     456{
     457    struct inet_params param;
     458
     459    memset(&param, 0, sizeof(param));
     460    if (scan_inet_proc_line(&param, line))
     461        return 1;
     462
     463    print_inet_line(&param, tcp_state[param.state], "tcp", param.rem_port);
     464    return 0;
     465}
     466
    210467#if ENABLE_FEATURE_IPV6
    211     struct sockaddr_in6 localaddr, remaddr;
    212 #else
    213     struct sockaddr_in localaddr, remaddr;
    214 #endif
    215     unsigned long rxq, txq, time_len, retr, inode;
    216 
    217     if (lnr == 0)
    218         return;
    219 
    220     more[0] = '\0';
    221     num = sscanf(line,
    222             "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
    223             &d, local_addr, &local_port,
    224             rem_addr, &rem_port, &state,
    225             &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
    226 
    227     if (strlen(local_addr) > 8) {
    228 #if ENABLE_FEATURE_IPV6
    229         /* Demangle what the kernel gives us */
    230         build_ipv6_addr(local_addr, &localaddr);
    231         build_ipv6_addr(rem_addr, &remaddr);
    232 #endif
    233     } else {
    234         build_ipv4_addr(local_addr, &localaddr);
    235         build_ipv4_addr(rem_addr, &remaddr);
    236     }
    237 
    238     if (num < 10) {
    239         bb_error_msg("warning, got bogus udp line");
    240         return;
    241     }
    242     switch (state) {
    243         case TCP_ESTABLISHED:
    244             state_str = "ESTABLISHED";
    245             break;
    246         case TCP_CLOSE:
    247             state_str = "";
    248             break;
    249         default:
    250             state_str = "UNKNOWN";
    251             break;
    252     }
    253 
    254 #if ENABLE_FEATURE_IPV6
    255 # define notnull(A) ( \
    256     ( (A.sin6_family == AF_INET6)                               \
    257       && (A.sin6_addr.s6_addr32[0] | A.sin6_addr.s6_addr32[1] | \
    258           A.sin6_addr.s6_addr32[2] | A.sin6_addr.s6_addr32[3])  \
    259     ) || (                                                      \
    260       (A.sin6_family == AF_INET)                                \
    261       && ((struct sockaddr_in*)&A)->sin_addr.s_addr             \
    262     )                                                           \
     468# define NOT_NULL_ADDR(A) ( \
     469    ( (A.sa.sa_family == AF_INET6) \
     470      && (A.sin6.sin6_addr.s6_addr32[0] | A.sin6.sin6_addr.s6_addr32[1] | \
     471          A.sin6.sin6_addr.s6_addr32[2] | A.sin6.sin6_addr.s6_addr32[3])  \
     472    ) || ( \
     473      (A.sa.sa_family == AF_INET) \
     474      && A.sin.sin_addr.s_addr != 0 \
     475    ) \
    263476)
    264477#else
    265 # define notnull(A) (A.sin_addr.s_addr)
    266 #endif
    267     {
    268         int have_remaddr = notnull(remaddr);
    269         if ((have_remaddr && (flags & NETSTAT_CONNECTED))
    270          || (!have_remaddr && (flags & NETSTAT_LISTENING))
    271         ) {
    272             char *l = ip_port_str(
    273                 (struct sockaddr *) &localaddr, local_port,
    274                 "udp", flags & NETSTAT_NUMERIC);
    275             char *r = ip_port_str(
    276                 (struct sockaddr *) &remaddr, rem_port,
    277                 "udp", flags & NETSTAT_NUMERIC);
    278             printf(net_conn_line,
    279                 "udp", rxq, txq, l, r, state_str);
    280             free(l);
    281             free(r);
    282         }
    283     }
    284 }
    285 
    286 static void raw_do_one(int lnr, const char *line)
    287 {
    288     char local_addr[64], rem_addr[64];
    289     char more[512];
    290     int num, local_port, rem_port, d, state, timer_run, uid, timeout;
    291 #if ENABLE_FEATURE_IPV6
    292     struct sockaddr_in6 localaddr, remaddr;
    293 #else
    294     struct sockaddr_in localaddr, remaddr;
    295 #endif
    296     unsigned long rxq, txq, time_len, retr, inode;
    297 
    298     if (lnr == 0)
    299         return;
    300 
    301     more[0] = '\0';
    302     num = sscanf(line,
    303             "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
    304             &d, local_addr, &local_port,
    305             rem_addr, &rem_port, &state,
    306             &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
    307 
    308     if (strlen(local_addr) > 8) {
    309 #if ENABLE_FEATURE_IPV6
    310         build_ipv6_addr(local_addr, &localaddr);
    311         build_ipv6_addr(rem_addr, &remaddr);
    312 #endif
    313     } else {
    314         build_ipv4_addr(local_addr, &localaddr);
    315         build_ipv4_addr(rem_addr, &remaddr);
    316     }
    317 
    318     if (num < 10) {
    319         bb_error_msg("warning, got bogus raw line");
    320         return;
    321     }
    322 
    323     {
    324         int have_remaddr = notnull(remaddr);
    325         if ((have_remaddr && (flags & NETSTAT_CONNECTED))
    326          || (!have_remaddr && (flags & NETSTAT_LISTENING))
    327         ) {
    328             char *l = ip_port_str(
    329                 (struct sockaddr *) &localaddr, local_port,
    330                 "raw", flags & NETSTAT_NUMERIC);
    331             char *r = ip_port_str(
    332                 (struct sockaddr *) &remaddr, rem_port,
    333                 "raw", flags & NETSTAT_NUMERIC);
    334             printf(net_conn_line,
    335                 "raw", rxq, txq, l, r, itoa(state));
    336             free(l);
    337             free(r);
    338         }
    339     }
    340 }
    341 
    342 static void unix_do_one(int nr, const char *line)
    343 {
    344     static smallint has_inode = 0;
    345 
    346     char path[PATH_MAX], ss_flags[32];
     478# define NOT_NULL_ADDR(A) (A.sin.sin_addr.s_addr)
     479#endif
     480
     481static int FAST_FUNC udp_do_one(char *line)
     482{
     483    int have_remaddr;
     484    const char *state_str;
     485    struct inet_params param;
     486
     487    memset(&param, 0, sizeof(param)); /* otherwise we display garbage IPv6 scope_ids */
     488    if (scan_inet_proc_line(&param, line))
     489        return 1;
     490
     491    state_str = "UNKNOWN";
     492    switch (param.state) {
     493    case TCP_ESTABLISHED:
     494        state_str = "ESTABLISHED";
     495        break;
     496    case TCP_CLOSE:
     497        state_str = "";
     498        break;
     499    }
     500
     501    have_remaddr = NOT_NULL_ADDR(param.remaddr);
     502    print_inet_line(&param, state_str, "udp", have_remaddr);
     503    return 0;
     504}
     505
     506static int FAST_FUNC raw_do_one(char *line)
     507{
     508    int have_remaddr;
     509    struct inet_params param;
     510
     511    if (scan_inet_proc_line(&param, line))
     512        return 1;
     513
     514    have_remaddr = NOT_NULL_ADDR(param.remaddr);
     515    print_inet_line(&param, itoa(param.state), "raw", have_remaddr);
     516    return 0;
     517}
     518
     519static int FAST_FUNC unix_do_one(char *line)
     520{
     521    unsigned long refcnt, proto, unix_flags;
     522    unsigned long inode;
     523    int type, state;
     524    int num, path_ofs;
    347525    const char *ss_proto, *ss_state, *ss_type;
    348     int num, state, type, inode;
    349     void *d;
    350     unsigned long refcnt, proto, unix_flags;
    351 
    352     if (nr == 0) {
    353         if (strstr(line, "Inode"))
    354             has_inode = 1;
    355         return;
    356     }
    357     path[0] = '\0';
    358     num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
    359             &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
     526    char ss_flags[32];
     527
     528    /* 2.6.15 may report lines like "... @/tmp/fam-user-^@^@^@^@^@^@^@..."
     529     * Other users report long lines filled by NUL bytes.
     530     * (those ^@ are NUL bytes too). We see them as empty lines. */
     531    if (!line[0])
     532        return 0;
     533
     534    path_ofs = 0; /* paranoia */
     535    num = sscanf(line, "%*p: %lX %lX %lX %X %X %lu %n",
     536            &refcnt, &proto, &unix_flags, &type, &state, &inode, &path_ofs);
    360537    if (num < 6) {
    361         bb_error_msg("warning, got bogus unix line");
    362         return;
    363     }
    364     if (!has_inode)
    365         sprintf(path, "%d", inode);
    366 
     538        return 1; /* error */
     539    }
    367540    if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) != (NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
    368541        if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) {
    369542            if (!(flags & NETSTAT_LISTENING))
    370                 return;
     543                return 0;
    371544        } else {
    372545            if (!(flags & NETSTAT_CONNECTED))
    373                 return;
     546                return 0;
    374547        }
    375548    }
     
    440613    strcat(ss_flags, "]");
    441614
    442     printf("%-5s %-6ld %-11s %-10s %-13s ",
    443            ss_proto, refcnt, ss_flags, ss_type, ss_state);
    444     if (has_inode)
    445         printf("%-6d ", inode);
    446     else
    447         printf("-      ");
    448     puts(path);
    449 }
    450 
    451 #define _PATH_PROCNET_UDP "/proc/net/udp"
    452 #define _PATH_PROCNET_UDP6 "/proc/net/udp6"
    453 #define _PATH_PROCNET_TCP "/proc/net/tcp"
    454 #define _PATH_PROCNET_TCP6 "/proc/net/tcp6"
    455 #define _PATH_PROCNET_RAW "/proc/net/raw"
    456 #define _PATH_PROCNET_RAW6 "/proc/net/raw6"
    457 #define _PATH_PROCNET_UNIX "/proc/net/unix"
    458 
    459 static void do_info(const char *file, const char *name, void (*proc)(int, const char *))
    460 {
    461     int lnr = 0;
     615    printf("%-5s %-6ld %-11s %-10s %-13s %6lu ",
     616        ss_proto, refcnt, ss_flags, ss_type, ss_state, inode
     617        );
     618
     619#if ENABLE_FEATURE_NETSTAT_PRG
     620    if (option_mask32 & OPT_prg)
     621        printf("%-"PROGNAME_WIDTH_STR"s", prg_cache_get(inode));
     622#endif
     623
     624    /* TODO: currently we stop at first NUL byte. Is it a problem? */
     625    line += path_ofs;
     626    *strchrnul(line, '\n') = '\0';
     627    while (*line)
     628        fputc_printable(*line++, stdout);
     629    bb_putchar('\n');
     630    return 0;
     631}
     632
     633static void do_info(const char *file, int FAST_FUNC (*proc)(char *))
     634{
     635    int lnr;
    462636    FILE *procinfo;
    463 
    464     procinfo = fopen(file, "r");
     637    char *buffer;
     638
     639    /* _stdin is just to save "r" param */
     640    procinfo = fopen_or_warn_stdin(file);
    465641    if (procinfo == NULL) {
    466         if (errno != ENOENT) {
    467             bb_perror_msg("%s", file);
    468         } else {
    469             bb_error_msg("no support for '%s' on this system", name);
    470         }
    471642        return;
    472643    }
    473     do {
    474         char *buffer = xmalloc_fgets(procinfo);
    475         if (buffer) {
    476             (proc)(lnr++, buffer);
    477             free(buffer);
    478         }
    479     } while (!feof(procinfo));
     644    lnr = 0;
     645    /* Why xmalloc_fgets_str? because it doesn't stop on NULs */
     646    while ((buffer = xmalloc_fgets_str(procinfo, "\n")) != NULL) {
     647        /* line 0 is skipped */
     648        if (lnr && proc(buffer))
     649            bb_error_msg("%s: bogus data on line %d", file, lnr + 1);
     650        lnr++;
     651        free(buffer);
     652    }
    480653    fclose(procinfo);
    481654}
    482655
    483 /*
    484  * Our main function.
    485  */
    486 
    487 int netstat_main(int argc, char **argv);
    488 int netstat_main(int argc, char **argv)
    489 {
    490     const char *net_conn_line_header = PRINT_NET_CONN_HEADER;
     656int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     657int netstat_main(int argc UNUSED_PARAM, char **argv)
     658{
    491659    unsigned opt;
    492 #if ENABLE_FEATURE_IPV6
    493     smallint inet = 1;
    494     smallint inet6 = 1;
    495 #else
    496     enum { inet = 1, inet6 = 0 };
    497 #endif
     660
     661    INIT_G();
    498662
    499663    /* Option string must match NETSTAT_xxx constants */
    500664    opt = getopt32(argv, NETSTAT_OPTS);
    501     if (opt & 0x1) { // -l
     665    if (opt & OPT_sock_listen) { // -l
    502666        flags &= ~NETSTAT_CONNECTED;
    503667        flags |= NETSTAT_LISTENING;
    504668    }
    505     if (opt & 0x2) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a
    506     //if (opt & 0x4) // -e
    507     if (opt & 0x8) flags |= NETSTAT_NUMERIC; // -n
    508     //if (opt & 0x10) // -t: NETSTAT_TCP
    509     //if (opt & 0x20) // -u: NETSTAT_UDP
    510     //if (opt & 0x40) // -w: NETSTAT_RAW
    511     //if (opt & 0x80) // -x: NETSTAT_UNIX
    512     if (opt & OPT_showroute) { // -r
     669    if (opt & OPT_sock_all) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a
     670    //if (opt & OPT_extended) // -e
     671    if (opt & OPT_noresolve) flags |= NETSTAT_NUMERIC; // -n
     672    //if (opt & OPT_sock_tcp) // -t: NETSTAT_TCP
     673    //if (opt & OPT_sock_udp) // -u: NETSTAT_UDP
     674    //if (opt & OPT_sock_raw) // -w: NETSTAT_RAW
     675    //if (opt & OPT_sock_unix) // -x: NETSTAT_UNIX
    513676#if ENABLE_ROUTE
     677    if (opt & OPT_route) { // -r
    514678        bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended));
    515679        return 0;
    516 #else
    517         bb_show_usage();
    518 #endif
    519     }
    520 
    521     if (opt & OPT_widedisplay) { // -W
    522         net_conn_line = PRINT_NET_CONN_WIDE;
    523         net_conn_line_header = PRINT_NET_CONN_HEADER_WIDE;
    524     }
     680    }
     681#endif
     682#if ENABLE_FEATURE_NETSTAT_WIDE
     683    G.addr_width = ADDR_NORMAL_WIDTH;
     684    if (opt & OPT_wide) { // -W
     685        G.addr_width = ADDR_WIDE;
     686    }
     687#endif
     688#if ENABLE_FEATURE_NETSTAT_PRG
     689    progname_banner = "";
     690    if (opt & OPT_prg) { // -p
     691        progname_banner = PROGNAME_BANNER;
     692        prg_cache_load();
     693    }
     694#endif
    525695
    526696    opt &= NETSTAT_ALLPROTO;
     
    530700    }
    531701    if (flags & (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
    532         printf("Active Internet connections "); /* xxx */
     702        printf("Active Internet connections "); /* xxx */
    533703
    534704        if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED))
     
    538708        else
    539709            printf("(w/o servers)");
    540         printf(net_conn_line_header, "Local Address", "Foreign Address");
    541     }
    542     if (inet && flags & NETSTAT_TCP)
    543         do_info(_PATH_PROCNET_TCP, "AF INET (tcp)", tcp_do_one);
     710        printf(FMT_NET_CONN_HEADER,
     711                IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Local Address",
     712                IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Foreign Address",
     713                progname_banner
     714        );
     715    }
     716    if (flags & NETSTAT_TCP) {
     717        do_info("/proc/net/tcp", tcp_do_one);
    544718#if ENABLE_FEATURE_IPV6
    545     if (inet6 && flags & NETSTAT_TCP)
    546         do_info(_PATH_PROCNET_TCP6, "AF INET6 (tcp)", tcp_do_one);
    547 #endif
    548     if (inet && flags & NETSTAT_UDP)
    549         do_info(_PATH_PROCNET_UDP, "AF INET (udp)", udp_do_one);
     719        do_info("/proc/net/tcp6", tcp_do_one);
     720#endif
     721    }
     722    if (flags & NETSTAT_UDP) {
     723        do_info("/proc/net/udp", udp_do_one);
    550724#if ENABLE_FEATURE_IPV6
    551     if (inet6 && flags & NETSTAT_UDP)
    552         do_info(_PATH_PROCNET_UDP6, "AF INET6 (udp)", udp_do_one);
    553 #endif
    554     if (inet && flags & NETSTAT_RAW)
    555         do_info(_PATH_PROCNET_RAW, "AF INET (raw)", raw_do_one);
     725        do_info("/proc/net/udp6", udp_do_one);
     726#endif
     727    }
     728    if (flags & NETSTAT_RAW) {
     729        do_info("/proc/net/raw", raw_do_one);
    556730#if ENABLE_FEATURE_IPV6
    557     if (inet6 && flags & NETSTAT_RAW)
    558         do_info(_PATH_PROCNET_RAW6, "AF INET6 (raw)", raw_do_one);
    559 #endif
     731        do_info("/proc/net/raw6", raw_do_one);
     732#endif
     733    }
    560734    if (flags & NETSTAT_UNIX) {
    561735        printf("Active UNIX domain sockets ");
     
    566740        else
    567741            printf("(w/o servers)");
    568         printf("\nProto RefCnt Flags       Type       State         I-Node Path\n");
    569         do_info(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one);
    570     }
     742        printf("\nProto RefCnt Flags       Type       State         I-Node %sPath\n", progname_banner);
     743        do_info("/proc/net/unix", unix_do_one);
     744    }
     745    prg_cache_clear();
    571746    return 0;
    572747}
Note: See TracChangeset for help on using the changeset viewer.