netstat: fix IPv6 problem (garbage in scope_id); code shrink
No binary (build failed)
—
(log yok)
| @@ -113,24 +113,25 @@ typedef enum { | |
| SS_DISCONNECTING /* in process of disconnecting */ | |
| } socket_state; | |
| - | #define SO_ACCEPTCON (1<<16) /* performed a listen */ |
| - | #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" |
| - | #define PRINT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State " |
| + | #define SO_ACCEPTCON (1<<16) /* performed a listen */ |
| + | #define SO_WAITDATA (1<<17) /* wait data to read */ |
| + | #define SO_NOSPACE (1<<18) /* no space to write */ |
| + | #define ADDR_NORMAL_WIDTH 23 |
| /* 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" |
| - | #define PRINT_NET_CONN_HEADER_WIDE "\nProto Recv-Q Send-Q %-51s %-51s State " |
| + | #define ADDR_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ |
| + | #if ENABLE_FEATURE_NETSTAT_WIDE |
| + | # define FMT_NET_CONN_DATA "%s %6ld %6ld %-*s %-*s %-12s" |
| + | # define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-*s %-*s State %s\n" |
| + | #else |
| + | # define FMT_NET_CONN_DATA "%s %6ld %6ld %-23s %-23s %-12s" |
| + | # define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State %s\n" |
| + | #endif |
| #define PROGNAME_WIDTH 20 | |
| #define PROGNAME_WIDTH_STR "20" | |
| @@ -146,22 +147,30 @@ struct prg_node { | |
| #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 | |
| + | #if ENABLE_FEATURE_NETSTAT_PRG |
| + | const char *progname_banner; |
| + | #endif |
| + | #if ENABLE_FEATURE_NETSTAT_WIDE |
| + | unsigned addr_width; |
| + | #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 prg_hash (G.prg_hash ) |
| + | #if ENABLE_FEATURE_NETSTAT_PRG |
| + | # define progname_banner (G.progname_banner ) |
| + | #else |
| + | # define progname_banner "" |
| + | #endif |
| #define INIT_G() do { \ | |
| SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | |
| flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \ | |
| - | net_conn_line = PRINT_NET_CONN; \ |
| } while (0) | |
| @@ -170,10 +179,6 @@ struct globals { | |
| /* 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); | |
| @@ -226,12 +231,12 @@ static long extract_socket_inode(const char *lname) | |
| 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); |
| + | inode = bb_strtoul(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); |
| + | inode = bb_strtoul(lname + sizeof("[0000]:")-1, NULL, 0); |
| if (errno) /* not NUL terminated? */ | |
| inode = -1; | |
| } | |
| @@ -243,7 +248,7 @@ static long extract_socket_inode(const char *lname) | |
| return inode; | |
| } | |
| - | static int FAST_FUNC file_act(const char *fileName, |
| + | static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName, |
| struct stat *statbuf UNUSED_PARAM, | |
| void *pid_slash_progname, | |
| int depth UNUSED_PARAM) | |
| @@ -267,9 +272,10 @@ static int FAST_FUNC dir_act(const char *fileName, | |
| int depth) | |
| { | |
| const char *pid; | |
| - | char *p, *pid_slash_progname; |
| + | char *pid_slash_progname; |
| + | char proc_pid_fname[sizeof("/proc/%u/cmdline") + sizeof(long)*3]; |
| char cmdline_buf[512]; | |
| - | int i; |
| + | int n, len; |
| if (depth == 0) /* "/proc" itself */ | |
| return TRUE; /* continue looking one level below /proc */ | |
| @@ -278,22 +284,24 @@ static int FAST_FUNC dir_act(const char *fileName, | |
| if (!isdigit(pid[0])) /* skip /proc entries which 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) |
| + | len = snprintf(proc_pid_fname, sizeof(proc_pid_fname), "%s/cmdline", fileName); |
| + | n = open_read_close(proc_pid_fname, cmdline_buf, sizeof(cmdline_buf) - 1); |
| + | if (n < 0) |
| return FALSE; | |
| - | cmdline_buf[i] = '\0'; |
| + | cmdline_buf[n] = '\0'; |
| - | /* go through all files in /proc/PID/fd */ |
| + | /* go through all files in /proc/PID/fd and check whether they are sockets */ |
| + | strcpy(proc_pid_fname + len - (sizeof("cmdline")-1), "fd"); |
| pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */ | |
| - | p = concat_path_file(fileName, "fd"); |
| - | i = recursive_action(p, ACTION_RECURSE | ACTION_QUIET, |
| - | file_act, NULL, (void *)pid_slash_progname, 0); |
| - | free(p); |
| + | n = recursive_action(proc_pid_fname, |
| + | ACTION_RECURSE | ACTION_QUIET, |
| + | add_to_prg_cache_if_socket, |
| + | NULL, |
| + | (void *)pid_slash_progname, |
| + | 0); |
| free(pid_slash_progname); | |
| - | if (!i) |
| + | if (!n) |
| return FALSE; /* signal permissions error to caller */ | |
| return SKIP; /* caller should not recurse further into this dir */ | |
| @@ -318,7 +326,6 @@ static void prg_cache_load(void) | |
| #else | |
| #define prg_cache_clear() ((void)0) | |
| - | #define print_progname_banner() ((void)0) |
| #endif //ENABLE_FEATURE_NETSTAT_PRG | |
| @@ -427,8 +434,11 @@ static void print_inet_line(struct inet_params *param, | |
| char *r = ip_port_str( | |
| ¶m->remaddr.sa, param->rem_port, | |
| proto, flags & NETSTAT_NUMERIC); | |
| - | printf(net_conn_line, |
| - | proto, param->rxq, param->txq, l, r, state_str); |
| + | printf(FMT_NET_CONN_DATA, |
| + | proto, param->rxq, param->txq, |
| + | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) l, |
| + | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) r, |
| + | state_str); |
| #if ENABLE_FEATURE_NETSTAT_PRG | |
| if (option_mask32 & OPT_prg) | |
| printf("%."PROGNAME_WIDTH_STR"s", prg_cache_get(param->inode)); | |
| @@ -443,6 +453,7 @@ static int FAST_FUNC tcp_do_one(char *line) | |
| { | |
| struct inet_params param; | |
| + | memset(¶m, 0, sizeof(param)); |
| if (scan_inet_proc_line(¶m, line)) | |
| return 1; | |
| @@ -470,6 +481,7 @@ static int FAST_FUNC udp_do_one(char *line) | |
| const char *state_str; | |
| struct inet_params param; | |
| + | memset(¶m, 0, sizeof(param)); /* otherwise we display garbage IPv6 scope_ids */ |
| if (scan_inet_proc_line(¶m, line)) | |
| return 1; | |
| @@ -641,7 +653,6 @@ static void do_info(const char *file, int FAST_FUNC (*proc)(char *)) | |
| int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| int netstat_main(int argc UNUSED_PARAM, char **argv) | |
| { | |
| - | const char *net_conn_line_header = PRINT_NET_CONN_HEADER; |
| unsigned opt; | |
| INIT_G(); | |
| @@ -665,12 +676,16 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) | |
| return 0; | |
| } | |
| #endif | |
| + | #if ENABLE_FEATURE_NETSTAT_WIDE |
| + | G.addr_width = ADDR_NORMAL_WIDTH; |
| if (opt & OPT_wide) { // -W | |
| - | net_conn_line = PRINT_NET_CONN_WIDE; |
| - | net_conn_line_header = PRINT_NET_CONN_HEADER_WIDE; |
| + | G.addr_width = ADDR_WIDE; |
| } | |
| + | #endif |
| #if ENABLE_FEATURE_NETSTAT_PRG | |
| + | progname_banner = ""; |
| if (opt & OPT_prg) { // -p | |
| + | progname_banner = PROGNAME_BANNER; |
| prg_cache_load(); | |
| } | |
| #endif | |
| @@ -689,9 +704,11 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) | |
| printf("(only servers)"); | |
| else | |
| printf("(w/o servers)"); | |
| - | printf(net_conn_line_header, "Local Address", "Foreign Address"); |
| - | print_progname_banner(); |
| - | bb_putchar('\n'); |
| + | printf(FMT_NET_CONN_HEADER, |
| + | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Local Address", |
| + | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Foreign Address", |
| + | progname_banner |
| + | ); |
| } | |
| if (flags & NETSTAT_TCP) { | |
| do_info("/proc/net/tcp", tcp_do_one); | |
| @@ -719,9 +736,7 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) | |
| printf("(only servers)"); | |
| else | |
| printf("(w/o servers)"); | |
| - | printf("\nProto RefCnt Flags Type State I-Node "); |
| - | print_progname_banner(); |
| - | printf("Path\n"); |
| + | printf("\nProto RefCnt Flags Type State I-Node %sPath\n", progname_banner); |
| do_info("/proc/net/unix", unix_do_one); | |
| } | |
| prg_cache_clear(); | |