diff options
author | Elliott Hughes <enh@google.com> | 2015-09-08 10:39:07 -0500 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2015-09-08 10:39:07 -0500 |
commit | fe998fe2bb75a73ba58a7c048f50f45ee76a0531 (patch) | |
tree | 12d10f52d74c5166967a207d850bc0e40d730363 /toys/pending/netstat.c | |
parent | 104fbaaceaf4001d8c9c998981e7bcc22fdb027d (diff) | |
download | toybox-fe998fe2bb75a73ba58a7c048f50f45ee76a0531.tar.gz |
Fix netstat -p.
netstat -p was failing for any cmdline longer than 21 characters. (A
typical Chrome render process has about half a kilobyte of cmdline.)
There's still a lot of cleanup to be done later, but this is enough to
fix -p and remove a fair amount of unnecessary custom code into the
bargain.
Diffstat (limited to 'toys/pending/netstat.c')
-rw-r--r-- | toys/pending/netstat.c | 162 |
1 files changed, 60 insertions, 102 deletions
diff --git a/toys/pending/netstat.c b/toys/pending/netstat.c index 63be39cc..98db54d7 100644 --- a/toys/pending/netstat.c +++ b/toys/pending/netstat.c @@ -29,8 +29,14 @@ config NETSTAT #define FOR_netstat #include "toys.h" + #include <net/route.h> +GLOBALS( + char current_name[21]; + int some_process_unidentified; +); + typedef union _iaddr { unsigned u; unsigned char b[4]; @@ -56,28 +62,15 @@ enum { }; #define SOCK_NOT_CONNECTED 1 -//For PID/Progrma Name -#define PROGRAM_NAME "PID/Program Name" -#define PROGNAME_LEN 50 typedef struct _pidlist { struct _pidlist *next; long inode; - char name[PROGNAME_LEN]; + char name[21]; } PID_LIST; PID_LIST *pid_list = NULL; /* - * Get base name from the input name. - */ -static const char *get_basename(char *name) -{ - const char *c = strrchr(name, '/'); - if (c) return c + 1; - return name; -} - -/* * locate character in string. */ static char *strchr_nul(char *s, int c) @@ -86,39 +79,6 @@ static char *strchr_nul(char *s, int c) return (char*)s; } -// Find out if the last character of a string matches with the given one. -// Don't underrun the buffer if the string length is 0. -static char *find_last_char(char *str, int c) -{ - if (str && *str) { - size_t sz = strlen(str) - 1; - str += sz; - if ( (unsigned char)*str == c) return (char*)str; - } - return NULL; -} -/* - * Concat path and the file name. - */ -static char *append_pathandfile(char *path, char *fname) -{ - char *c; - if (!path) path = ""; - c = find_last_char(path, '/'); - while (*fname == '/') fname++; - return xmprintf("%s%s%s", path, (c)? "" : "/", fname); -} -/* - * Concat sub-path and the file name. - */ -static char *append_subpathandfile(char *path, char *fname) -{ -#define ISDOTORDOTDOT(s) ((s)[0] == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2]))) - if(!fname) return NULL; - if(ISDOTORDOTDOT(fname)) return NULL; - return append_pathandfile(path, fname); -#undef ISDOTORDOTDOT -} /* * used to converts string into int and validate the input str for invalid int value or out-of-range. */ @@ -361,7 +321,7 @@ static void show_unix_sockets(char *fname, char *label) if (flags & SOCK_NO_SPACE) strcat(sock_flags, "N "); strcat(sock_flags, "]"); } - xprintf("%-5s %-6ld %-11s %-10s %-13s %6lu ", (!label ? "unix" : "??"), refcount, sock_flags, sock_type, sock_state, inode); + xprintf("%-5s %-6ld %-11s %-10s %-13s %8lu ", (!label ? "unix" : "??"), refcount, sock_flags, sock_type, sock_state, inode); if (toys.optflags & FLAG_p) xprintf("%-20s", get_pid_name(inode)); bptr += path_offset; @@ -392,7 +352,7 @@ static long ss_inode(char *link) /* * add inode and progname in the pid list. */ -static void add2list(long inode, char *progname) +static void add2list(long inode) { PID_LIST *node = pid_list; for(; node; node = node->next) { @@ -401,71 +361,61 @@ static void add2list(long inode, char *progname) } PID_LIST *new = (PID_LIST *)xzalloc(sizeof(PID_LIST)); new->inode = inode; - xstrncpy(new->name, progname, PROGNAME_LEN); + xstrncpy(new->name, TT.current_name, sizeof(new->name)); new->next = pid_list; pid_list = new; } -/* - * add pid info in the list. - */ -static void extract_inode(char *path, char *progname) + +static void scan_pid_inodes(char *path) { DIR *dp; struct dirent *entry; if (!(dp = opendir(path))) { - if (errno == EACCES) return; - else perror_exit("%s", path); + if (errno == EACCES) { + TT.some_process_unidentified = 1; + return; + } else perror_exit("%s", path); } while ((entry = readdir(dp))) { - char *link = NULL, *fname = append_subpathandfile(path, entry->d_name); - if (!fname) continue; - link = xreadlink(fname); - if (link) { - long inode = ss_inode(link); - free(link); - if (inode != -1) add2list(inode, progname); - } - free(fname); - }//end of while. + char link_name[64], *link; + long inode; + + if (!isdigit(entry->d_name[0])) continue; + snprintf(link_name, sizeof(link_name), "%s/%s", path, entry->d_name); + link = xreadlink(link_name); + if ((inode = ss_inode(link)) != -1) add2list(inode); + free(link); + } closedir(dp); } -/* - * prepare the list for all pids in /proc directory. - */ -static void get_pid_list(void) + +static void scan_pid(int pid) { - DIR *dp; - struct dirent *entry; - char path[64] = {0,}; - uid_t uid = geteuid(); + char *line, *p, *fd_dir; - if (!(dp = opendir("/proc"))) perror_exit("opendir"); + snprintf(toybuf, sizeof(toybuf), "/proc/%d/cmdline", pid); + line = xreadfile(toybuf, 0, 0); - while ((entry = readdir(dp))) { - int fd, nitems = 0, length = 0; - char *pid, *progname; - - if (!isdigit(*entry->d_name)) continue; - pid = entry->d_name; - length = snprintf(path, sizeof(path), "/proc/%s/cmdline", entry->d_name); - if (sizeof(path) <= length) continue; - - fd = xopen(path, O_RDONLY); - nitems = readall(fd, toybuf, sizeof(toybuf) - 1); - xclose(fd); - if (nitems < 1) continue; - toybuf[nitems] = '\0'; - strcpy(path + length - (sizeof("cmdline")-1), "fd"); - progname = append_pathandfile(pid, (char *)get_basename(toybuf)); //e.g. progname = 2054/gnome-keyring-daemon - extract_inode(path, progname); - free(progname); - }//end of while. - closedir(dp); + if ((p = strchr(line, ' '))) *p = 0; // "/bin/netstat -ntp" -> "/bin/netstat" + snprintf(TT.current_name, sizeof(TT.current_name), "%d/%s", + pid, basename_r(line)); // "584/netstat" + free(line); - if (uid) fprintf(stderr, "(Not all processes could be identified, non-owned process info " - "will not be shown, you would have to be root to see it all.)\n"); + fd_dir = xmprintf("/proc/%d/fd", pid); + scan_pid_inodes(fd_dir); + free(fd_dir); } + +static int scan_pids(struct dirtree *node) +{ + int pid; + + if (!node->parent) return DIRTREE_RECURSE; + if ((pid = atol(node->name))) scan_pid(pid); + return 0; +} + /* * Dealloc pid list. */ @@ -484,9 +434,9 @@ static void clean_pid_list(void) static void show_header(void) { if ((toys.optflags & FLAG_W) && (toys.optflags & FLAG_p)) - xprintf("\nProto Recv-Q Send-Q %-51s %-51s %-12s%s\n", "Local Address", "Foreign Address", "State", PROGRAM_NAME); + xprintf("\nProto Recv-Q Send-Q %-51s %-51s %-12s%s\n", "Local Address", "Foreign Address", "State", "PID/Program Name"); else if (toys.optflags & FLAG_p) - xprintf("\nProto Recv-Q Send-Q %-23s %-23s %-12s%s\n", "Local Address", "Foreign Address", "State", PROGRAM_NAME); + xprintf("\nProto Recv-Q Send-Q %-23s %-23s %-12s%s\n", "Local Address", "Foreign Address", "State", "PID/Program Name"); else if (toys.optflags & FLAG_W) xprintf("\nProto Recv-Q Send-Q %-51s %-51s State \n", "Local Address", "Foreign Address"); else xprintf("\nProto Recv-Q Send-Q %-23s %-23s State \n", "Local Address", "Foreign Address"); @@ -610,7 +560,15 @@ void netstat_main(void) return; } - if (toys.optflags & FLAG_p) get_pid_list(); + if (toys.optflags & FLAG_p) { + dirtree_read("/proc", scan_pids); + // TODO: we probably shouldn't warn if all the processes we're going to + // list were identified. + if (TT.some_process_unidentified) + fprintf(stderr, + "(Not all processes could be identified, non-owned process info\n" + " will not be shown, you would have to be root to see it all.)\n"); + } //For TCP/UDP/RAW. if ( (toys.optflags & FLAG_t) || (toys.optflags & FLAG_u) || (toys.optflags & FLAG_w) ) { @@ -640,8 +598,8 @@ void netstat_main(void) else if (toys.optflags & FLAG_l) xprintf("(only servers)"); else xprintf("(w/o servers)"); - if (toys.optflags & FLAG_p) xprintf("\nProto RefCnt Flags Type State I-Node %s Path\n", PROGRAM_NAME); - else xprintf("\nProto RefCnt Flags Type State I-Node Path\n"); + if (toys.optflags & FLAG_p) xprintf("\nProto RefCnt Flags Type State I-Node PID/Program Name Path\n"); + else xprintf("\nProto RefCnt Flags Type State I-Node Path\n"); show_unix_sockets("/proc/net/unix", "unix"); } if (toys.optflags & FLAG_p) clean_pid_list(); |