aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toys/pending/netstat.c245
1 files changed, 62 insertions, 183 deletions
diff --git a/toys/pending/netstat.c b/toys/pending/netstat.c
index a4096650..415a4f65 100644
--- a/toys/pending/netstat.c
+++ b/toys/pending/netstat.c
@@ -5,7 +5,7 @@
*
* Not in SUSv4.
*
-USE_NETSTAT(NEWTOY(netstat, "pWrxwutneal[-al]", TOYFLAG_BIN))
+USE_NETSTAT(NEWTOY(netstat, "pWrxwutneal", TOYFLAG_BIN))
config NETSTAT
bool "netstat"
default n
@@ -14,26 +14,25 @@ config NETSTAT
Display networking information.
- -r Display routing table.
- -a Display all sockets (Default: Connected).
- -l Display listening server sockets.
- -t Display TCP sockets.
- -u Display UDP sockets.
- -w Display Raw sockets.
- -x Display Unix sockets.
- -e Display other/more information.
- -n Don't resolve names.
- -W Wide Display.
- -p Display PID/Program name for sockets.
+ -r routing table
+ -a all sockets (not just connected)
+ -l lay listening server sockets
+ -t TCP sockets
+ -u UDP sockets
+ -w raw sockets
+ -x unix sockets
+ -e extended info
+ -n don't resolve names
+ -W wide display
+ -p PID/Program name for sockets
*/
#define FOR_netstat
#include "toys.h"
-
#include <net/route.h>
GLOBALS(
- char current_name[21];
+ struct num_cache *inodes;
int some_process_unidentified;
);
@@ -54,60 +53,6 @@ typedef union _iaddr6 {
#define ADDR_LEN (INET6_ADDRSTRLEN + 1 + 5 + 1)//IPv6 addr len + : + port + '\0'
-#define SOCK_NOT_CONNECTED 1
-
-typedef struct _pidlist {
- struct _pidlist *next;
- long inode;
- char name[21];
-} PID_LIST;
-
-PID_LIST *pid_list = NULL;
-
-/*
- * used to convert string into int and
- * validate the input str for invalid int value or out-of-range.
- */
-static unsigned long get_strtou(char *str, char **endp, int base)
-{
- unsigned long uli;
- char *endptr;
-
- if (!isalnum(str[0])) {
- errno = ERANGE;
- return UINT_MAX;
- }
- errno = 0;
- uli = strtoul(str, &endptr, base);
- if (uli > UINT_MAX) {
- errno = ERANGE;
- return UINT_MAX;
- }
-
- if (endp) *endp = endptr;
- if (endptr[0]) {
- if (isalnum(endptr[0]) || errno) { //"123abc" or out-of-range
- errno = ERANGE;
- return UINT_MAX;
- }
- errno = EINVAL;
- }
- return uli;
-}
-
-/*
- * used to retrive pid name from pid list.
- */
-static const char *get_pid_name(unsigned long inode)
-{
- PID_LIST *tmp;
-
- for (tmp = pid_list; tmp; tmp = tmp->next)
- if (tmp->inode == inode) return tmp->name;
-
- return "-";
-}
-
/*
* For TCP/UDP/RAW display data.
*/
@@ -126,23 +71,25 @@ static void display_data(unsigned rport, char *label,
int sz = ARRAY_LEN(state_label);
if (!state || state >= sz) state = sz-1;
ss_state = state_label[state];
- }
- else if (!strcmp(label, "udp")) {
+ } else if (!strcmp(label, "udp")) {
if (state == 1) ss_state = state_label[state];
else if (state == 7) ss_state = "";
- }
- else if (!strcmp(label, "raw")) sprintf(ss_state = buf, "%u", state);
+ } else if (!strcmp(label, "raw")) sprintf(ss_state = buf, "%u", state);
- if (!(toys.optflags & FLAG_n) && (pw = getpwuid(uid))) {
+ if (!(toys.optflags & FLAG_n) && (pw = getpwuid(uid)))
snprintf(user, sizeof(user), "%s", pw->pw_name);
- } else snprintf(user, sizeof(user), "%d", uid);
+ else snprintf(user, sizeof(user), "%d", uid);
xprintf("%3s %6d %6d ", label, rxq, txq);
xprintf((toys.optflags & FLAG_W) ? "%-51.51s %-51.51s " : "%-23.23s %-23.23s "
, lip, rip);
xprintf("%-11s", ss_state);
if ((toys.optflags & FLAG_e)) xprintf(" %-10s %-11ld", user, inode);
- if ((toys.optflags & FLAG_p)) xprintf(" %s", get_pid_name(inode));
+ if ((toys.optflags & FLAG_p)) {
+ struct num_cache *nc = get_num_cache(TT.inodes, inode);
+
+ printf(" %s", nc ? nc->data : "-");
+ }
xputc('\n');
}
@@ -169,6 +116,7 @@ static void show_data(unsigned rport, char *label, unsigned rxq, unsigned txq,
static char *get_servname(int port, char *label)
{
int lport = htons(port);
+
if (!lport) return xmprintf("%s", "*");
struct servent *ser = getservbyport(lport, label);
if (ser) return xmprintf("%s", ser->s_name);
@@ -296,7 +244,8 @@ static void show_ipv6(char *fname, char *label)
static void show_unix_sockets(void)
{
char *types[] = {"","STREAM","DGRAM","RAW","RDM","SEQPACKET","DCCP","PACKET"},
- *states[] = {"","LISTENING","CONNECTING","CONNECTED","DISCONNECTING"};
+ *states[] = {"","LISTENING","CONNECTING","CONNECTED","DISCONNECTING"},
+ *s, *ss;
unsigned long refcount, flags, type, state, inode;
FILE *fp = xfopen("/proc/net/unix", "r");
@@ -319,17 +268,19 @@ static void show_unix_sockets(void)
if (type==10) type = 7; // move SOCK_PACKET into line
if (type>ARRAY_LEN(types)) type = 0;
- if (state>ARRAY_LEN(states)) state = 0;
+ if (state>ARRAY_LEN(states) || (state==1 && !flags)) state = 0;
sprintf(toybuf, "[ %s]", flags ? "ACC " : "");
printf("unix %-6ld %-11s %-10s %-13s %8lu ",
refcount, toybuf, types[type], states[state], inode);
- if (toys.optflags & FLAG_p) printf("%-20s", get_pid_name(inode));
+ if (toys.optflags & FLAG_p) {
+ struct num_cache *nc = get_num_cache(TT.inodes, inode);
- if (offset) {
- char *s = toybuf+offset, *ss;
+ printf("%-19.19s", nc ? nc->data : "-");
+ }
- if ((ss = strrchr(s, '\n'))) *ss = 0;
+ if (offset) {
+ if ((ss = strrchr(s = toybuf+offset, '\n'))) *ss = 0;
xprintf("%s", s);
}
xputc('\n');
@@ -338,110 +289,44 @@ static void show_unix_sockets(void)
fclose(fp);
}
-/*
- * extract inode value from the link.
- */
-static long ss_inode(char *link)
-{
- long inode = -1;
- //"link = socket:[12345]", get "12345" as inode.
- if (!strncmp(link, "socket:[", sizeof("socket:[")-1)) {
- inode = get_strtou(link + sizeof("socket:[")-1, (char**)&link, 0);
- if (*link != ']') inode = -1;
- }
- //"link = [0000]:12345", get "12345" as inode.
- else if (!strncmp(link, "[0000]:", sizeof("[0000]:")-1)) {
- inode = get_strtou(link + sizeof("[0000]:")-1, NULL, 0);
- //if not NULL terminated.
- if (errno) inode = -1;
- }
- return inode;
-}
-
-/*
- * add inode and progname in the pid list.
- */
-static void add2list(long inode)
+static int scan_pids(struct dirtree *node)
{
- PID_LIST *node = pid_list;
+ char *s = toybuf+256;
+ struct dirent *entry;
+ DIR *dp;
+ int pid, dirfd;
- for(; node; node = node->next) {
- if(node->inode == inode)
- return;
- }
+ if (!node->parent) return DIRTREE_RECURSE;
+ if (!(pid = atol(node->name))) return 0;
- PID_LIST *new = (PID_LIST *)xzalloc(sizeof(PID_LIST));
- new->inode = inode;
- xstrncpy(new->name, TT.current_name, sizeof(new->name));
- new->next = pid_list;
- pid_list = new;
-}
+ sprintf(toybuf, "/proc/%d/cmdline", pid);
+ if (!(readfile(toybuf, toybuf, 256))) return 0;
-static void scan_pid_inodes(char *path)
-{
- DIR *dp;
- struct dirent *entry;
+ sprintf(s, "%d/fd", pid);
+ if (-1==(dirfd = openat(dirtree_parentfd(node), s, O_RDONLY))) return 0;
+ if (!(dp = fdopendir(dirfd))) {
+ close(dirfd);
- if (!(dp = opendir(path))) {
- if (errno == EACCES) {
- TT.some_process_unidentified = 1;
- return;
- } else perror_exit("%s", path);
+ return 0;
}
+
while ((entry = readdir(dp))) {
- 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);
- if ((link = xreadlink(link_name)) && (inode = ss_inode(link))!=-1)
- add2list(inode);
- free(link);
+ s = toybuf+256;
+ if (!readlinkat0(dirfd, entry->d_name, s, sizeof(toybuf)-256)) continue;
+ // Can the "[0000]:" happen in a modern kernel?
+ if (strstart(&s, "socket:[") || strstart(&s, "[0000]:")) {
+ long long ll = atoll(s);
+
+ sprintf(s, "%d/%s", pid, getbasename(toybuf));
+ add_num_cache(&TT.inodes, ll, s, strlen(s)+1);
+ }
}
closedir(dp);
-}
-
-static void scan_pid(int pid)
-{
- char *line, *p, *fd_dir;
-
- snprintf(toybuf, sizeof(toybuf), "/proc/%d/cmdline", pid);
- line = xreadfile(toybuf, 0, 0);
-
- if ((p = strchr(line, ' '))) *p = 0; // "/bin/netstat -ntp" -> "/bin/netstat"
- snprintf(TT.current_name, sizeof(TT.current_name), "%d/%s",
- pid, getbasename(line)); // "584/netstat"
- free(line);
-
- 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.
- */
-static void clean_pid_list(void)
-{
- PID_LIST *tmp;
- while (pid_list) {
- tmp = pid_list->next;
- free(pid_list);
- pid_list = tmp;
- }
-}
-
-/*
* extract inet4 route info from /proc/net/route file and display it.
*/
static void display_routes(void)
@@ -507,21 +392,14 @@ static void display_routes(void)
fclose(fp);
}
-/*
- * netstat utility main function.
- */
void netstat_main(void)
{
+ int tuwx = FLAG_t|FLAG_u|FLAG_w|FLAG_x;
char *type = "w/o";
- if (toys.optflags & FLAG_r) {
- display_routes();
-
- return;
- }
-
- if (!(toys.optflags&(FLAG_t|FLAG_u|FLAG_w|FLAG_x)))
- toys.optflags |= FLAG_t|FLAG_u|FLAG_w|FLAG_x;
+ if (!(toys.optflags&(FLAG_r|tuwx))) toys.optflags |= tuwx;
+ if (toys.optflags & FLAG_r) display_routes();
+ if (!(toys.optflags&tuwx)) return;
if (toys.optflags & FLAG_a) type = "established and";
else if (toys.optflags & FLAG_l) type = "only";
@@ -569,6 +447,7 @@ void netstat_main(void)
show_unix_sockets();
}
- if (toys.optflags & FLAG_p) clean_pid_list();
+ if ((toys.optflags & FLAG_p) && CFG_TOYBOX_FREE)
+ llist_traverse(TT.inodes, free);
toys.exitval = 0;
}