| /* |
| * 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); |
| } |
| } |