|  | /* | 
|  | * This file is part of the UCB release of Plan 9. It is subject to the license | 
|  | * terms in the LICENSE file found in the top-level directory of this | 
|  | * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No | 
|  | * part of the UCB release of Plan 9, including this file, may be copied, | 
|  | * modified, propagated, or distributed except according to the terms contained | 
|  | * in the LICENSE file. | 
|  | */ | 
|  | #include <sys/types.h> | 
|  |  | 
|  | #include <sys/stat.h> | 
|  | #include <fcntl.h> | 
|  | #include <stdlib.h> | 
|  | #include <stdio.h> | 
|  | #include <parlib/parlib.h> | 
|  | #include <unistd.h> | 
|  | #include <signal.h> | 
|  | #include <iplib/iplib.h> | 
|  | #include <dirent.h> | 
|  |  | 
|  | enum { | 
|  | maxproto = 20, | 
|  | }; | 
|  | void pip(char *, struct dirent *); | 
|  | void nstat(char *, void (*)(char *, struct dirent *)); | 
|  | void pipifc(void); | 
|  |  | 
|  | FILE *out; | 
|  | char *netroot; | 
|  | char *proto[maxproto]; | 
|  | int nproto; | 
|  | int notrans; | 
|  |  | 
|  | void usage(char *argv0) | 
|  | { | 
|  | fprintf(stderr, "usage: %s [-in] [-p proto] [network-dir]\n", argv0); | 
|  | fprintf(stderr, "usage"); | 
|  | exit(1); | 
|  | } | 
|  |  | 
|  | void main(int argc, char *argv[]) | 
|  | { | 
|  | int justinterfaces = 0; | 
|  | int i, tot, fd; | 
|  | DIR *dir; | 
|  | struct dirent *d; | 
|  | char buf[128]; | 
|  | out = stdout; | 
|  | argc--, argv++; | 
|  | while (argc > 0 && *argv[0] == '-') { | 
|  | switch (argv[0][1]) { | 
|  | case 'i': | 
|  | justinterfaces = 1; | 
|  | break; | 
|  | case 'n': | 
|  | notrans = 1; | 
|  | break; | 
|  | case 'p': | 
|  | if (nproto >= maxproto){ | 
|  | fprintf(stderr, "too many protos"); | 
|  | exit(1); | 
|  | } | 
|  | if (argc < 2) | 
|  | usage("netstat"); | 
|  | argc--, argv++; | 
|  | proto[nproto++] = argv[0]; | 
|  | break; | 
|  | default: | 
|  | usage("netstat"); | 
|  | } | 
|  | argc--, argv++; | 
|  | } | 
|  |  | 
|  | netroot = "/net"; | 
|  | switch (argc) { | 
|  | case 0: | 
|  | break; | 
|  | case 1: | 
|  | netroot = argv[0]; | 
|  | break; | 
|  | default: | 
|  | usage("netstat"); | 
|  | } | 
|  |  | 
|  | if (justinterfaces) { | 
|  | pipifc(); | 
|  | exit(0); | 
|  | } | 
|  |  | 
|  | if (nproto) { | 
|  | for (i = 0; i < nproto; i++) | 
|  | nstat(proto[i], pip); | 
|  | } else { | 
|  | dir = opendir(netroot); | 
|  | if (!dir) { | 
|  | fprintf(stderr, "open %s: %r", netroot); | 
|  | exit(1); | 
|  | } | 
|  |  | 
|  | while ((d = readdir(dir))) { | 
|  | if (strcmp(d->d_name, "ipifc") == 0) | 
|  | continue; | 
|  | snprintf(buf, sizeof buf, "%s/%s/0/local", netroot, | 
|  | d->d_name); | 
|  | /* access is bogus for now. */ | 
|  | if (1 || access(buf, 0) >= 0) | 
|  | nstat(d->d_name, pip); | 
|  | else | 
|  | fprintf(stderr, "Can't access %s\n", d->d_name); | 
|  | } | 
|  | } | 
|  |  | 
|  | exit(0); | 
|  | } | 
|  |  | 
|  | void nstat(char *net, void (*f) (char *, struct dirent *)) | 
|  | { | 
|  | int fdir, i, tot; | 
|  | struct dirent *d; | 
|  | DIR *dir; | 
|  | char buf[128]; | 
|  |  | 
|  | snprintf(buf, sizeof buf, "%s/%s", netroot, net); | 
|  | dir = opendir(buf); | 
|  | if (!dir) | 
|  | return; | 
|  |  | 
|  | while ((d = readdir(dir))) { | 
|  | (*f) (net, d); | 
|  | } | 
|  | /* leak dir */ | 
|  | } | 
|  |  | 
|  | char *getport(char *net, char *p) | 
|  | { | 
|  | static char port[10]; | 
|  |  | 
|  | strncpy(port, p, sizeof(port) - 1); | 
|  | port[sizeof(port) - 1] = 0; | 
|  | //if(notrans || (p = csgetvalue(netroot, "port", p, net, nil)) == nil) | 
|  | if (1) | 
|  | return port; | 
|  | strncpy(port, p, sizeof(port) - 1); | 
|  | port[sizeof(port) - 1] = 0; | 
|  | free(p); | 
|  | return port; | 
|  | } | 
|  |  | 
|  | void pip(char *net, struct dirent *db) | 
|  | { | 
|  | int n, fd; | 
|  | char buf[128], *p; | 
|  | char *dname; | 
|  |  | 
|  | if (strcmp(db->d_name, "clone") == 0) | 
|  | return; | 
|  | if (strcmp(db->d_name, "stats") == 0) | 
|  | return; | 
|  |  | 
|  | snprintf(buf, sizeof buf, "%s/%s/%s/status", netroot, net, db->d_name); | 
|  | fd = open(buf, O_RDONLY); | 
|  | if (fd < 0) | 
|  | return; | 
|  | n = read(fd, buf, sizeof(buf)); | 
|  | close(fd); | 
|  | if (n < 0) | 
|  | return; | 
|  | buf[n] = 0; | 
|  |  | 
|  | p = strchr(buf, ' '); | 
|  | if (p != 0) | 
|  | *p = 0; | 
|  | p = strrchr(buf, '\n'); | 
|  | if (p != 0) | 
|  | *p = 0; | 
|  | fprintf(out, "%-4s %-4s %-12s ", net, db->d_name, /*db->uid, */ buf); | 
|  |  | 
|  | snprintf(buf, sizeof buf, "%s/%s/%s/local", netroot, net, db->d_name); | 
|  | fd = open(buf, O_RDONLY); | 
|  | if (fd < 0) { | 
|  | fprintf(out, "\n"); | 
|  | return; | 
|  | } | 
|  | n = read(fd, buf, sizeof(buf)); | 
|  | close(fd); | 
|  | if (n < 0) { | 
|  | fprintf(out, "\n"); | 
|  | return; | 
|  | } | 
|  | buf[n - 1] = 0; | 
|  | p = strchr(buf, '!'); | 
|  | if (p == 0) { | 
|  | fprintf(out, "\n"); | 
|  | return; | 
|  | } | 
|  | *p = '\0'; | 
|  | fprintf(out, "%-10s ", getport(net, p + 1)); | 
|  |  | 
|  | snprintf(buf, sizeof buf, "%s/%s/%s/remote", netroot, net, db->d_name); | 
|  | fd = open(buf, O_RDONLY); | 
|  | if (fd < 0) { | 
|  | printf("\n"); | 
|  | return; | 
|  | } | 
|  | n = read(fd, buf, sizeof(buf)); | 
|  | close(fd); | 
|  | if (n < 0) { | 
|  | printf("\n"); | 
|  | return; | 
|  | } | 
|  | buf[n - 1] = 0; | 
|  | p = strchr(buf, '!'); | 
|  | if (p != NULL) | 
|  | *p++ = '\0'; | 
|  |  | 
|  | if (notrans) { | 
|  | fprintf(out, "%-10s %s\n", getport(net, p), buf); | 
|  | return; | 
|  | } | 
|  | dname = NULL;	//csgetvalue(netroot, "ip", buf, "dom", nil); | 
|  | if (dname == NULL) { | 
|  | fprintf(out, "%-10s %s\n", getport(net, p), buf); | 
|  | return; | 
|  | } | 
|  | fprintf(out, "%-10s %s\n", getport(net, p), dname); | 
|  | free(dname); | 
|  | } | 
|  |  | 
|  | void pipifc(void) | 
|  | { | 
|  | struct ipifc *ip, *nip; | 
|  | struct iplifc *lifc; | 
|  | char buf[100]; | 
|  | int l, i; | 
|  |  | 
|  | //  fmtinstall('I', eipfmt); | 
|  | //  fmtinstall('M', eipfmt); | 
|  |  | 
|  | ip = readipifc(netroot, NULL, -1); | 
|  |  | 
|  | l = 7; | 
|  | for (nip = ip; nip; nip = nip->next) { | 
|  | for (lifc = nip->lifc; lifc; lifc = lifc->next) { | 
|  | i = snprintf(buf, sizeof buf, "%I", lifc->ip); | 
|  | if (i > l) | 
|  | l = i; | 
|  | i = snprintf(buf, sizeof buf, "%I", lifc->net); | 
|  | if (i > l) | 
|  | l = i; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (nip = ip; nip; nip = nip->next) { | 
|  | for (lifc = nip->lifc; lifc; lifc = lifc->next) | 
|  | fprintf(out, "%-12s %5d %-*I %5M %-*I %8lud %8lud %8lud %8lud\n", | 
|  | nip->dev, nip->mtu, | 
|  | l, lifc->ip, lifc->mask, l, lifc->net, | 
|  | nip->pktin, nip->pktout, nip->errin, | 
|  | nip->errout); | 
|  | } | 
|  | } |