aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/netstat.c109
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
148struct globals { 149struct 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
177static void prg_cache_add(long inode, char *name) 182static 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
246static int FAST_FUNC file_act(const char *fileName, 251static 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 &param->remaddr.sa, param->rem_port, 435 &param->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(&param, 0, sizeof(param));
446 if (scan_inet_proc_line(&param, line)) 457 if (scan_inet_proc_line(&param, 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(&param, 0, sizeof(param)); /* otherwise we display garbage IPv6 scope_ids */
473 if (scan_inet_proc_line(&param, line)) 485 if (scan_inet_proc_line(&param, 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 *))
641int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 653int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
642int netstat_main(int argc UNUSED_PARAM, char **argv) 654int 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();