diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-10-27 13:10:29 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-10-27 13:10:29 +0200 |
commit | dd88ba88f5082b1785539b1fb87af7320515b8c9 (patch) | |
tree | 4b307764cdd28883213410ea4f29d65c0ccc22ed /networking/netstat.c | |
parent | c386aa5dcdb1333737827914b213c88e46cf43bd (diff) | |
download | busybox-w32-dd88ba88f5082b1785539b1fb87af7320515b8c9.tar.gz busybox-w32-dd88ba88f5082b1785539b1fb87af7320515b8c9.tar.bz2 busybox-w32-dd88ba88f5082b1785539b1fb87af7320515b8c9.zip |
netstat: fix IPv6 problem (garbage in scope_id); code shrink
function old new delta
add_to_prg_cache_if_socket - 253 +253
print_inet_line 226 241 +15
udp_do_one 119 131 +12
tcp_do_one 65 77 +12
unix_do_one 530 529 -1
dir_act 215 207 -8
netstat_main 585 553 -32
.rodata 145592 145525 -67
file_act 255 - -255
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 3/4 up/down: 292/-363) Total: -71 bytes
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Diffstat (limited to 'networking/netstat.c')
-rw-r--r-- | networking/netstat.c | 109 |
1 files changed, 62 insertions, 47 deletions
diff --git a/networking/netstat.c b/networking/netstat.c index 4fd8728ce..485a7d191 100644 --- a/networking/netstat.c +++ b/networking/netstat.c | |||
@@ -113,24 +113,25 @@ typedef enum { | |||
113 | SS_DISCONNECTING /* in process of disconnecting */ | 113 | SS_DISCONNECTING /* in process of disconnecting */ |
114 | } socket_state; | 114 | } socket_state; |
115 | 115 | ||
116 | #define SO_ACCEPTCON (1<<16) /* performed a listen */ | 116 | #define SO_ACCEPTCON (1<<16) /* performed a listen */ |
117 | #define SO_WAITDATA (1<<17) /* wait data to read */ | 117 | #define SO_WAITDATA (1<<17) /* wait data to read */ |
118 | #define SO_NOSPACE (1<<18) /* no space to write */ | 118 | #define SO_NOSPACE (1<<18) /* no space to write */ |
119 | |||
120 | /* Standard printout size */ | ||
121 | #define PRINT_IP_MAX_SIZE 23 | ||
122 | #define PRINT_NET_CONN "%s %6ld %6ld %-23s %-23s %-12s" | ||
123 | #define PRINT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State " | ||
124 | 119 | ||
120 | #define ADDR_NORMAL_WIDTH 23 | ||
125 | /* When there are IPv6 connections the IPv6 addresses will be | 121 | /* When there are IPv6 connections the IPv6 addresses will be |
126 | * truncated to none-recognition. The '-W' option makes the | 122 | * truncated to none-recognition. The '-W' option makes the |
127 | * address columns wide enough to accomodate for longest possible | 123 | * address columns wide enough to accomodate for longest possible |
128 | * IPv6 addresses, i.e. addresses of the form | 124 | * IPv6 addresses, i.e. addresses of the form |
129 | * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd | 125 | * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd |
130 | */ | 126 | */ |
131 | #define PRINT_IP_MAX_SIZE_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ | 127 | #define ADDR_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ |
132 | #define PRINT_NET_CONN_WIDE "%s %6ld %6ld %-51s %-51s %-12s" | 128 | #if ENABLE_FEATURE_NETSTAT_WIDE |
133 | #define PRINT_NET_CONN_HEADER_WIDE "\nProto Recv-Q Send-Q %-51s %-51s State " | 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 | ||
134 | 135 | ||
135 | #define PROGNAME_WIDTH 20 | 136 | #define PROGNAME_WIDTH 20 |
136 | #define PROGNAME_WIDTH_STR "20" | 137 | #define PROGNAME_WIDTH_STR "20" |
@@ -146,22 +147,30 @@ struct prg_node { | |||
146 | #define PRG_HASH_SIZE 211 | 147 | #define PRG_HASH_SIZE 211 |
147 | 148 | ||
148 | struct globals { | 149 | struct globals { |
149 | const char *net_conn_line; | ||
150 | smallint flags; | 150 | smallint flags; |
151 | #if ENABLE_FEATURE_NETSTAT_PRG | 151 | #if ENABLE_FEATURE_NETSTAT_PRG |
152 | smallint prg_cache_loaded; | 152 | smallint prg_cache_loaded; |
153 | struct prg_node *prg_hash[PRG_HASH_SIZE]; | 153 | struct prg_node *prg_hash[PRG_HASH_SIZE]; |
154 | #endif | 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 | ||
155 | }; | 161 | }; |
156 | #define G (*ptr_to_globals) | 162 | #define G (*ptr_to_globals) |
157 | #define flags (G.flags ) | 163 | #define flags (G.flags ) |
158 | #define net_conn_line (G.net_conn_line ) | ||
159 | #define prg_hash (G.prg_hash ) | ||
160 | #define prg_cache_loaded (G.prg_cache_loaded) | 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 | ||
161 | #define INIT_G() do { \ | 171 | #define INIT_G() do { \ |
162 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | 172 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
163 | flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \ | 173 | flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \ |
164 | net_conn_line = PRINT_NET_CONN; \ | ||
165 | } while (0) | 174 | } while (0) |
166 | 175 | ||
167 | 176 | ||
@@ -170,10 +179,6 @@ struct globals { | |||
170 | /* Deliberately truncating long to unsigned *int* */ | 179 | /* Deliberately truncating long to unsigned *int* */ |
171 | #define PRG_HASHIT(x) ((unsigned)(x) % PRG_HASH_SIZE) | 180 | #define PRG_HASHIT(x) ((unsigned)(x) % PRG_HASH_SIZE) |
172 | 181 | ||
173 | #define print_progname_banner() do { \ | ||
174 | if (option_mask32 & OPT_prg) printf(PROGNAME_BANNER); \ | ||
175 | } while (0) | ||
176 | |||
177 | static void prg_cache_add(long inode, char *name) | 182 | static void prg_cache_add(long inode, char *name) |
178 | { | 183 | { |
179 | unsigned hi = PRG_HASHIT(inode); | 184 | unsigned hi = PRG_HASHIT(inode); |
@@ -226,12 +231,12 @@ static long extract_socket_inode(const char *lname) | |||
226 | 231 | ||
227 | if (strncmp(lname, "socket:[", sizeof("socket:[")-1) == 0) { | 232 | if (strncmp(lname, "socket:[", sizeof("socket:[")-1) == 0) { |
228 | /* "socket:[12345]", extract the "12345" as inode */ | 233 | /* "socket:[12345]", extract the "12345" as inode */ |
229 | inode = bb_strtol(lname + sizeof("socket:[")-1, (char**)&lname, 0); | 234 | inode = bb_strtoul(lname + sizeof("socket:[")-1, (char**)&lname, 0); |
230 | if (*lname != ']') | 235 | if (*lname != ']') |
231 | inode = -1; | 236 | inode = -1; |
232 | } else if (strncmp(lname, "[0000]:", sizeof("[0000]:")-1) == 0) { | 237 | } else if (strncmp(lname, "[0000]:", sizeof("[0000]:")-1) == 0) { |
233 | /* "[0000]:12345", extract the "12345" as inode */ | 238 | /* "[0000]:12345", extract the "12345" as inode */ |
234 | inode = bb_strtol(lname + sizeof("[0000]:")-1, NULL, 0); | 239 | inode = bb_strtoul(lname + sizeof("[0000]:")-1, NULL, 0); |
235 | if (errno) /* not NUL terminated? */ | 240 | if (errno) /* not NUL terminated? */ |
236 | inode = -1; | 241 | inode = -1; |
237 | } | 242 | } |
@@ -243,7 +248,7 @@ static long extract_socket_inode(const char *lname) | |||
243 | return inode; | 248 | return inode; |
244 | } | 249 | } |
245 | 250 | ||
246 | static int FAST_FUNC file_act(const char *fileName, | 251 | static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName, |
247 | struct stat *statbuf UNUSED_PARAM, | 252 | struct stat *statbuf UNUSED_PARAM, |
248 | void *pid_slash_progname, | 253 | void *pid_slash_progname, |
249 | int depth UNUSED_PARAM) | 254 | int depth UNUSED_PARAM) |
@@ -267,9 +272,10 @@ static int FAST_FUNC dir_act(const char *fileName, | |||
267 | int depth) | 272 | int depth) |
268 | { | 273 | { |
269 | const char *pid; | 274 | const char *pid; |
270 | char *p, *pid_slash_progname; | 275 | char *pid_slash_progname; |
276 | char proc_pid_fname[sizeof("/proc/%u/cmdline") + sizeof(long)*3]; | ||
271 | char cmdline_buf[512]; | 277 | char cmdline_buf[512]; |
272 | int i; | 278 | int n, len; |
273 | 279 | ||
274 | if (depth == 0) /* "/proc" itself */ | 280 | if (depth == 0) /* "/proc" itself */ |
275 | return TRUE; /* continue looking one level below /proc */ | 281 | return TRUE; /* continue looking one level below /proc */ |
@@ -278,22 +284,24 @@ static int FAST_FUNC dir_act(const char *fileName, | |||
278 | if (!isdigit(pid[0])) /* skip /proc entries which aren't processes */ | 284 | if (!isdigit(pid[0])) /* skip /proc entries which aren't processes */ |
279 | return SKIP; | 285 | return SKIP; |
280 | 286 | ||
281 | p = concat_path_file(fileName, "cmdline"); /* "/proc/PID/cmdline" */ | 287 | len = snprintf(proc_pid_fname, sizeof(proc_pid_fname), "%s/cmdline", fileName); |
282 | i = open_read_close(p, cmdline_buf, sizeof(cmdline_buf) - 1); | 288 | n = open_read_close(proc_pid_fname, cmdline_buf, sizeof(cmdline_buf) - 1); |
283 | free(p); | 289 | if (n < 0) |
284 | if (i < 0) | ||
285 | return FALSE; | 290 | return FALSE; |
286 | cmdline_buf[i] = '\0'; | 291 | cmdline_buf[n] = '\0'; |
287 | 292 | ||
288 | /* go through all files in /proc/PID/fd */ | 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"); | ||
289 | pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */ | 295 | pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */ |
290 | p = concat_path_file(fileName, "fd"); | 296 | n = recursive_action(proc_pid_fname, |
291 | i = recursive_action(p, ACTION_RECURSE | ACTION_QUIET, | 297 | ACTION_RECURSE | ACTION_QUIET, |
292 | file_act, NULL, (void *)pid_slash_progname, 0); | 298 | add_to_prg_cache_if_socket, |
293 | free(p); | 299 | NULL, |
300 | (void *)pid_slash_progname, | ||
301 | 0); | ||
294 | free(pid_slash_progname); | 302 | free(pid_slash_progname); |
295 | 303 | ||
296 | if (!i) | 304 | if (!n) |
297 | return FALSE; /* signal permissions error to caller */ | 305 | return FALSE; /* signal permissions error to caller */ |
298 | 306 | ||
299 | return SKIP; /* caller should not recurse further into this dir */ | 307 | return SKIP; /* caller should not recurse further into this dir */ |
@@ -318,7 +326,6 @@ static void prg_cache_load(void) | |||
318 | #else | 326 | #else |
319 | 327 | ||
320 | #define prg_cache_clear() ((void)0) | 328 | #define prg_cache_clear() ((void)0) |
321 | #define print_progname_banner() ((void)0) | ||
322 | 329 | ||
323 | #endif //ENABLE_FEATURE_NETSTAT_PRG | 330 | #endif //ENABLE_FEATURE_NETSTAT_PRG |
324 | 331 | ||
@@ -427,8 +434,11 @@ static void print_inet_line(struct inet_params *param, | |||
427 | char *r = ip_port_str( | 434 | char *r = ip_port_str( |
428 | ¶m->remaddr.sa, param->rem_port, | 435 | ¶m->remaddr.sa, param->rem_port, |
429 | proto, flags & NETSTAT_NUMERIC); | 436 | proto, flags & NETSTAT_NUMERIC); |
430 | printf(net_conn_line, | 437 | printf(FMT_NET_CONN_DATA, |
431 | proto, param->rxq, param->txq, l, r, state_str); | 438 | proto, param->rxq, param->txq, |
439 | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) l, | ||
440 | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) r, | ||
441 | state_str); | ||
432 | #if ENABLE_FEATURE_NETSTAT_PRG | 442 | #if ENABLE_FEATURE_NETSTAT_PRG |
433 | if (option_mask32 & OPT_prg) | 443 | if (option_mask32 & OPT_prg) |
434 | printf("%."PROGNAME_WIDTH_STR"s", prg_cache_get(param->inode)); | 444 | printf("%."PROGNAME_WIDTH_STR"s", prg_cache_get(param->inode)); |
@@ -443,6 +453,7 @@ static int FAST_FUNC tcp_do_one(char *line) | |||
443 | { | 453 | { |
444 | struct inet_params param; | 454 | struct inet_params param; |
445 | 455 | ||
456 | memset(¶m, 0, sizeof(param)); | ||
446 | if (scan_inet_proc_line(¶m, line)) | 457 | if (scan_inet_proc_line(¶m, line)) |
447 | return 1; | 458 | return 1; |
448 | 459 | ||
@@ -470,6 +481,7 @@ static int FAST_FUNC udp_do_one(char *line) | |||
470 | const char *state_str; | 481 | const char *state_str; |
471 | struct inet_params param; | 482 | struct inet_params param; |
472 | 483 | ||
484 | memset(¶m, 0, sizeof(param)); /* otherwise we display garbage IPv6 scope_ids */ | ||
473 | if (scan_inet_proc_line(¶m, line)) | 485 | if (scan_inet_proc_line(¶m, line)) |
474 | return 1; | 486 | return 1; |
475 | 487 | ||
@@ -641,7 +653,6 @@ static void do_info(const char *file, int FAST_FUNC (*proc)(char *)) | |||
641 | int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 653 | int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
642 | int netstat_main(int argc UNUSED_PARAM, char **argv) | 654 | int netstat_main(int argc UNUSED_PARAM, char **argv) |
643 | { | 655 | { |
644 | const char *net_conn_line_header = PRINT_NET_CONN_HEADER; | ||
645 | unsigned opt; | 656 | unsigned opt; |
646 | 657 | ||
647 | INIT_G(); | 658 | INIT_G(); |
@@ -665,12 +676,16 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) | |||
665 | return 0; | 676 | return 0; |
666 | } | 677 | } |
667 | #endif | 678 | #endif |
679 | #if ENABLE_FEATURE_NETSTAT_WIDE | ||
680 | G.addr_width = ADDR_NORMAL_WIDTH; | ||
668 | if (opt & OPT_wide) { // -W | 681 | if (opt & OPT_wide) { // -W |
669 | net_conn_line = PRINT_NET_CONN_WIDE; | 682 | G.addr_width = ADDR_WIDE; |
670 | net_conn_line_header = PRINT_NET_CONN_HEADER_WIDE; | ||
671 | } | 683 | } |
684 | #endif | ||
672 | #if ENABLE_FEATURE_NETSTAT_PRG | 685 | #if ENABLE_FEATURE_NETSTAT_PRG |
686 | progname_banner = ""; | ||
673 | if (opt & OPT_prg) { // -p | 687 | if (opt & OPT_prg) { // -p |
688 | progname_banner = PROGNAME_BANNER; | ||
674 | prg_cache_load(); | 689 | prg_cache_load(); |
675 | } | 690 | } |
676 | #endif | 691 | #endif |
@@ -689,9 +704,11 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) | |||
689 | printf("(only servers)"); | 704 | printf("(only servers)"); |
690 | else | 705 | else |
691 | printf("(w/o servers)"); | 706 | printf("(w/o servers)"); |
692 | printf(net_conn_line_header, "Local Address", "Foreign Address"); | 707 | printf(FMT_NET_CONN_HEADER, |
693 | print_progname_banner(); | 708 | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Local Address", |
694 | bb_putchar('\n'); | 709 | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Foreign Address", |
710 | progname_banner | ||
711 | ); | ||
695 | } | 712 | } |
696 | if (flags & NETSTAT_TCP) { | 713 | if (flags & NETSTAT_TCP) { |
697 | do_info("/proc/net/tcp", tcp_do_one); | 714 | do_info("/proc/net/tcp", tcp_do_one); |
@@ -719,9 +736,7 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) | |||
719 | printf("(only servers)"); | 736 | printf("(only servers)"); |
720 | else | 737 | else |
721 | printf("(w/o servers)"); | 738 | printf("(w/o servers)"); |
722 | printf("\nProto RefCnt Flags Type State I-Node "); | 739 | printf("\nProto RefCnt Flags Type State I-Node %sPath\n", progname_banner); |
723 | print_progname_banner(); | ||
724 | printf("Path\n"); | ||
725 | do_info("/proc/net/unix", unix_do_one); | 740 | do_info("/proc/net/unix", unix_do_one); |
726 | } | 741 | } |
727 | prg_cache_clear(); | 742 | prg_cache_clear(); |