Index: head/usr.bin/systat/cmds.c =================================================================== --- head/usr.bin/systat/cmds.c (revision 298323) +++ head/usr.bin/systat/cmds.c (revision 298324) @@ -1,196 +1,196 @@ /*- * Copyright (c) 1980, 1992, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #ifdef lint static const char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/29/95"; #endif #include #include #include #include #include #include #include "systat.h" #include "extern.h" void command(const char *cmd) { struct cmdtab *p; char *cp, *tmpstr, *tmpstr1; double t; tmpstr = tmpstr1 = strdup(cmd); for (cp = tmpstr1; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; if (*tmpstr1 == '\0') return; for (; *cp && isspace(*cp); cp++) ; if (strcmp(tmpstr1, "quit") == 0 || strcmp(tmpstr1, "q") == 0) die(0); if (strcmp(tmpstr1, "load") == 0) { load(); goto done; } if (strcmp(tmpstr1, "stop") == 0) { delay = 0; mvaddstr(CMDLINE, 0, "Refresh disabled."); clrtoeol(); goto done; } if (strcmp(tmpstr1, "help") == 0) { int _col, _len; move(CMDLINE, _col = 0); for (p = cmdtab; p->c_name; p++) { _len = strlen(p->c_name); if (_col + _len > COLS) break; addstr(p->c_name); _col += _len; if (_col + 1 < COLS) addch(' '); } clrtoeol(); goto done; } t = strtod(tmpstr1, NULL) * 1000000.0; if (t > 0 && t < (double)UINT_MAX) delay = (unsigned int)t; if ((t <= 0 || t > (double)UINT_MAX) && (strcmp(tmpstr1, "start") == 0 || strcmp(tmpstr1, "interval") == 0)) { if (*cp != '\0') { t = strtod(cp, NULL) * 1000000.0; if (t <= 0 || t >= (double)UINT_MAX) { error("%d: bad interval.", (int)t); goto done; } } } if (t > 0) { delay = (unsigned int)t; display(); status(); goto done; } p = lookup(tmpstr1); if (p == (struct cmdtab *)-1) { error("%s: Ambiguous command.", tmpstr1); goto done; } if (p) { if (curcmd == p) goto done; (*curcmd->c_close)(wnd); curcmd->c_flags &= ~CF_INIT; wnd = (*p->c_open)(); - if (wnd == 0) { + if (wnd == NULL) { error("Couldn't open new display"); wnd = (*curcmd->c_open)(); - if (wnd == 0) { + if (wnd == NULL) { error("Couldn't change back to previous cmd"); exit(1); } p = curcmd; } if ((p->c_flags & CF_INIT) == 0) { if ((*p->c_init)()) p->c_flags |= CF_INIT; else goto done; } curcmd = p; labels(); display(); status(); goto done; } - if (curcmd->c_cmd == 0 || !(*curcmd->c_cmd)(tmpstr1, cp)) + if (curcmd->c_cmd == NULL || !(*curcmd->c_cmd)(tmpstr1, cp)) error("%s: Unknown command.", tmpstr1); done: free(tmpstr); } struct cmdtab * lookup(const char *name) { const char *p, *q; struct cmdtab *ct, *found; int nmatches, longest; longest = 0; nmatches = 0; found = (struct cmdtab *) 0; for (ct = cmdtab; (p = ct->c_name); ct++) { for (q = name; *q == *p++; q++) if (*q == 0) /* exact match? */ return (ct); if (!*q) { /* the name was a prefix */ if (q - name > longest) { longest = q - name; nmatches = 1; found = ct; } else if (q - name == longest) nmatches++; } } if (nmatches > 1) return ((struct cmdtab *)-1); return (found); } void status(void) { error("Showing %s, refresh every %d seconds.", curcmd->c_name, delay / 1000000); } int prefix(const char *s1, const char *s2) { while (*s1 == *s2) { if (*s1 == '\0') return (1); s1++, s2++; } return (*s1 == '\0'); } Index: head/usr.bin/systat/netcmds.c =================================================================== --- head/usr.bin/systat/netcmds.c (revision 298323) +++ head/usr.bin/systat/netcmds.c (revision 298324) @@ -1,308 +1,308 @@ /*- * Copyright (c) 1980, 1992, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #ifdef lint static const char sccsid[] = "@(#)netcmds.c 8.1 (Berkeley) 6/6/93"; #endif /* * Common network command support routines. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "systat.h" #include "extern.h" #define streq(a,b) (strcmp(a,b)==0) static struct hitem { struct in_addr addr; int onoff; } *hosts; int nports, nhosts, protos; static void changeitems(const char *, int); static int selectproto(const char *); static void showprotos(void); static int selectport(long, int); static void showports(void); static int selecthost(struct in_addr *, int); static void showhosts(void); int netcmd(const char *cmd, const char *args) { if (prefix(cmd, "proto")) { if (*args == '\0') { move(CMDLINE, 0); clrtoeol(); addstr("which proto?"); } else if (!selectproto(args)) { error("%s: Unknown protocol.", args); } return (1); } if (prefix(cmd, "ignore") || prefix(cmd, "display")) { changeitems(args, prefix(cmd, "display")); return (1); } if (prefix(cmd, "reset")) { selectproto(0); selecthost(0, 0); selectport(-1, 0); return (1); } if (prefix(cmd, "show")) { move(CMDLINE, 0); clrtoeol(); if (*args == '\0') { showprotos(); showhosts(); showports(); return (1); } if (prefix(args, "protos")) showprotos(); else if (prefix(args, "hosts")) showhosts(); else if (prefix(args, "ports")) showports(); else addstr("show what?"); return (1); } return (0); } static void changeitems(const char *args, int onoff) { char *cp, *tmpstr, *tmpstr1; struct servent *sp; struct hostent *hp; struct in_addr in; tmpstr = tmpstr1 = strdup(args); cp = strchr(tmpstr1, '\n'); if (cp) *cp = '\0'; for (;;tmpstr1 = cp) { for (cp = tmpstr1; *cp && isspace(*cp); cp++) ; tmpstr1 = cp; for (; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; if (cp - tmpstr1 == 0) break; sp = getservbyname(tmpstr1, protos == TCP ? "tcp" : protos == UDP ? "udp" : 0); if (sp) { selectport(sp->s_port, onoff); continue; } hp = gethostbyname(tmpstr1); - if (hp == 0) { + if (hp == NULL) { in.s_addr = inet_addr(tmpstr1); if (in.s_addr == INADDR_NONE) { error("%s: unknown host or port", tmpstr1); continue; } } else in = *(struct in_addr *)hp->h_addr; selecthost(&in, onoff); } free(tmpstr); } static int selectproto(const char *proto) { - if (proto == 0 || streq(proto, "all")) + if (proto == NULL || streq(proto, "all")) protos = TCP | UDP; else if (streq(proto, "tcp")) protos = TCP; else if (streq(proto, "udp")) protos = UDP; else return (0); return (protos); } static void showprotos(void) { if ((protos&TCP) == 0) addch('!'); addstr("tcp "); if ((protos&UDP) == 0) addch('!'); addstr("udp "); } static struct pitem { long port; int onoff; } *ports; static int selectport(long port, int onoff) { struct pitem *p; if (port == -1) { - if (ports == 0) + if (ports == NULL) return (0); free((char *)ports), ports = 0; nports = 0; return (1); } - for (p = ports; p < ports+nports; p++) + for (p = ports; p < ports + nports; p++) if (p->port == port) { p->onoff = onoff; return (0); } if (nports == 0) ports = (struct pitem *)malloc(sizeof (*p)); else ports = (struct pitem *)realloc(ports, (nports+1)*sizeof (*p)); p = &ports[nports++]; p->port = port; p->onoff = onoff; return (1); } int checkport(struct inpcb *inp) { struct pitem *p; if (ports) for (p = ports; p < ports+nports; p++) if (p->port == inp->inp_lport || p->port == inp->inp_fport) return (p->onoff); return (1); } static void showports(void) { struct pitem *p; struct servent *sp; for (p = ports; p < ports+nports; p++) { sp = getservbyport(p->port, protos == (TCP|UDP) ? 0 : protos == TCP ? "tcp" : "udp"); if (!p->onoff) addch('!'); if (sp) printw("%s ", sp->s_name); else printw("%d ", p->port); } } static int selecthost(struct in_addr *in, int onoff) { struct hitem *p; - if (in == 0) { - if (hosts == 0) + if (in == NULL) { + if (hosts == NULL) return (0); free((char *)hosts), hosts = 0; nhosts = 0; return (1); } for (p = hosts; p < hosts+nhosts; p++) if (p->addr.s_addr == in->s_addr) { p->onoff = onoff; return (0); } if (nhosts == 0) hosts = (struct hitem *)malloc(sizeof (*p)); else hosts = (struct hitem *)realloc(hosts, (nhosts+1)*sizeof (*p)); p = &hosts[nhosts++]; p->addr = *in; p->onoff = onoff; return (1); } int checkhost(struct inpcb *inp) { struct hitem *p; if (hosts) for (p = hosts; p < hosts+nhosts; p++) if (p->addr.s_addr == inp->inp_laddr.s_addr || p->addr.s_addr == inp->inp_faddr.s_addr) return (p->onoff); return (1); } static void showhosts(void) { struct hitem *p; struct hostent *hp; for (p = hosts; p < hosts+nhosts; p++) { hp = gethostbyaddr((char *)&p->addr, sizeof (p->addr), AF_INET); if (!p->onoff) addch('!'); printw("%s ", hp ? hp->h_name : (char *)inet_ntoa(p->addr)); } } Index: head/usr.bin/systat/netstat.c =================================================================== --- head/usr.bin/systat/netstat.c (revision 298323) +++ head/usr.bin/systat/netstat.c (revision 298324) @@ -1,657 +1,657 @@ /*- * Copyright (c) 1980, 1992, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #ifdef lint static const char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93"; #endif /* * netstat */ #include #include #include #include #include #include #include #include #include #include #ifdef INET6 #include #endif #include #include #include #include #include #include #include #define TCPSTATES #include #include #include #include #include #include #include #include #include #include #include #include "systat.h" #include "extern.h" static struct netinfo *enter(struct inpcb *, int, const char *); static void enter_kvm(struct inpcb *, struct socket *, int, const char *); static void enter_sysctl(struct inpcb *, struct xsocket *, int, const char *); static void fetchnetstat_kvm(void); static void fetchnetstat_sysctl(void); static char *inetname(struct sockaddr *); static void inetprint(struct sockaddr *, const char *); #define streq(a,b) (strcmp(a,b)==0) #define YMAX(w) (getmaxy(w)-2) WINDOW * opennetstat(void) { sethostent(1); setnetent(1); return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); } struct netinfo { TAILQ_ENTRY(netinfo) chain; short ni_line; /* line on screen */ short ni_seen; /* 0 when not present in list */ short ni_flags; #define NIF_LACHG 0x1 /* local address changed */ #define NIF_FACHG 0x2 /* foreign address changed */ short ni_state; /* tcp state */ const char *ni_proto; /* protocol */ struct sockaddr_storage ni_lsa; /* local address */ struct sockaddr_storage ni_fsa; /* foreign address */ u_int ni_rcvcc; /* rcv buffer character count */ u_int ni_sndcc; /* snd buffer character count */ }; TAILQ_HEAD(netinfohead, netinfo) netcb = TAILQ_HEAD_INITIALIZER(netcb); static int aflag = 0; static int nflag = 0; static int lastrow = 1; void closenetstat(WINDOW *w) { struct netinfo *p; endhostent(); endnetent(); TAILQ_FOREACH(p, &netcb, chain) { if (p->ni_line != -1) lastrow--; p->ni_line = -1; } if (w != NULL) { wclear(w); wrefresh(w); delwin(w); } } static const char *miblist[] = { "net.inet.tcp.pcblist", "net.inet.udp.pcblist" }; static char tcb[] = "tcb", udb[] = "udb"; struct nlist namelist[] = { #define X_TCB 0 { .n_name = tcb }, #define X_UDB 1 { .n_name = udb }, { .n_name = NULL }, }; int initnetstat(void) { protos = TCP|UDP; return(1); } void fetchnetstat(void) { if (use_kvm) fetchnetstat_kvm(); else fetchnetstat_sysctl(); } static void fetchnetstat_kvm(void) { struct inpcb *next; struct netinfo *p; struct inpcbhead head; struct inpcb inpcb; struct socket sockb; struct tcpcb tcpcb; void *off; int istcp; if (namelist[X_TCB].n_value == 0) return; TAILQ_FOREACH(p, &netcb, chain) p->ni_seen = 0; if (protos&TCP) { off = NPTR(X_TCB); istcp = 1; } else if (protos&UDP) { off = NPTR(X_UDB); istcp = 0; } else { error("No protocols to display"); return; } again: KREAD(off, &head, sizeof (struct inpcbhead)); LIST_FOREACH(next, &head, inp_list) { KREAD(next, &inpcb, sizeof (inpcb)); next = &inpcb; if (!aflag) { if (inpcb.inp_vflag & INP_IPV4) { if (inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) continue; } #ifdef INET6 else if (inpcb.inp_vflag & INP_IPV6) { if (memcmp(&inpcb.in6p_laddr, &in6addr_any, sizeof(in6addr_any)) == 0) continue; } #endif } if (nhosts && !checkhost(&inpcb)) continue; if (nports && !checkport(&inpcb)) continue; if (istcp) { if (inpcb.inp_flags & INP_TIMEWAIT) { bzero(&sockb, sizeof(sockb)); enter_kvm(&inpcb, &sockb, TCPS_TIME_WAIT, "tcp"); } else { KREAD(inpcb.inp_socket, &sockb, sizeof (sockb)); KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb)); enter_kvm(&inpcb, &sockb, tcpcb.t_state, "tcp"); } } else enter_kvm(&inpcb, &sockb, 0, "udp"); } if (istcp && (protos&UDP)) { istcp = 0; off = NPTR(X_UDB); goto again; } } static void fetchnetstat_sysctl(void) { struct netinfo *p; int idx; struct xinpgen *inpg; char *cur, *end; struct inpcb *inpcb; struct xinpcb *xip = NULL; struct xtcpcb *xtp = NULL; int plen; size_t lsz; TAILQ_FOREACH(p, &netcb, chain) p->ni_seen = 0; if (protos&TCP) { idx = 0; } else if (protos&UDP) { idx = 1; } else { error("No protocols to display"); return; } for (;idx < 2; idx++) { if (idx == 1 && !(protos&UDP)) break; inpg = (struct xinpgen *)sysctl_dynread(miblist[idx], &lsz); if (inpg == NULL) { error("sysctl(%s...) failed", miblist[idx]); continue; } /* * We currently do no require a consistent pcb list. * Try to be robust in case of struct size changes */ cur = ((char *)inpg) + inpg->xig_len; /* There is also a trailing struct xinpgen */ end = ((char *)inpg) + lsz - inpg->xig_len; if (end <= cur) { free(inpg); continue; } if (idx == 0) { /* TCP */ xtp = (struct xtcpcb *)cur; plen = xtp->xt_len; } else { xip = (struct xinpcb *)cur; plen = xip->xi_len; } while (cur + plen <= end) { if (idx == 0) { /* TCP */ xtp = (struct xtcpcb *)cur; inpcb = &xtp->xt_inp; } else { xip = (struct xinpcb *)cur; inpcb = &xip->xi_inp; } cur += plen; if (!aflag) { if (inpcb->inp_vflag & INP_IPV4) { if (inet_lnaof(inpcb->inp_laddr) == INADDR_ANY) continue; } #ifdef INET6 else if (inpcb->inp_vflag & INP_IPV6) { if (memcmp(&inpcb->in6p_laddr, &in6addr_any, sizeof(in6addr_any)) == 0) continue; } #endif } if (nhosts && !checkhost(inpcb)) continue; if (nports && !checkport(inpcb)) continue; if (idx == 0) /* TCP */ enter_sysctl(inpcb, &xtp->xt_socket, xtp->xt_tp.t_state, "tcp"); else /* UDP */ enter_sysctl(inpcb, &xip->xi_socket, 0, "udp"); } free(inpg); } } static void enter_kvm(struct inpcb *inp, struct socket *so, int state, const char *proto) { struct netinfo *p; if ((p = enter(inp, state, proto)) != NULL) { p->ni_rcvcc = so->so_rcv.sb_ccc; p->ni_sndcc = so->so_snd.sb_ccc; } } static void enter_sysctl(struct inpcb *inp, struct xsocket *so, int state, const char *proto) { struct netinfo *p; if ((p = enter(inp, state, proto)) != NULL) { p->ni_rcvcc = so->so_rcv.sb_cc; p->ni_sndcc = so->so_snd.sb_cc; } } static struct netinfo * enter(struct inpcb *inp, int state, const char *proto) { struct netinfo *p; struct sockaddr_storage lsa, fsa; struct sockaddr_in *sa4; #ifdef INET6 struct sockaddr_in6 *sa6; #endif memset(&lsa, 0, sizeof(lsa)); memset(&fsa, 0, sizeof(fsa)); if (inp->inp_vflag & INP_IPV4) { sa4 = (struct sockaddr_in *)&lsa; sa4->sin_addr = inp->inp_laddr; sa4->sin_port = inp->inp_lport; sa4->sin_family = AF_INET; sa4->sin_len = sizeof(struct sockaddr_in); sa4 = (struct sockaddr_in *)&fsa; sa4->sin_addr = inp->inp_faddr; sa4->sin_port = inp->inp_fport; sa4->sin_family = AF_INET; sa4->sin_len = sizeof(struct sockaddr_in); } #ifdef INET6 else if (inp->inp_vflag & INP_IPV6) { sa6 = (struct sockaddr_in6 *)&lsa; memcpy(&sa6->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr)); sa6->sin6_port = inp->inp_lport; sa6->sin6_family = AF_INET6; sa6->sin6_len = sizeof(struct sockaddr_in6); sa6 = (struct sockaddr_in6 *)&fsa; memcpy(&sa6->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr)); sa6->sin6_port = inp->inp_fport; sa6->sin6_family = AF_INET6; sa6->sin6_len = sizeof(struct sockaddr_in6); } #endif else return NULL; /* * Only take exact matches, any sockets with * previously unbound addresses will be deleted * below in the display routine because they * will appear as ``not seen'' in the kernel * data structures. */ TAILQ_FOREACH(p, &netcb, chain) { if (!streq(proto, p->ni_proto)) continue; if (p->ni_lsa.ss_family != lsa.ss_family || memcmp(&p->ni_lsa, &lsa, lsa.ss_len) != 0) continue; if (p->ni_fsa.ss_family == fsa.ss_family && memcmp(&p->ni_fsa, &fsa, fsa.ss_len) == 0) break; } if (p == NULL) { if ((p = malloc(sizeof(*p))) == NULL) { error("Out of memory"); return NULL; } TAILQ_INSERT_HEAD(&netcb, p, chain); p->ni_line = -1; memcpy(&p->ni_lsa, &lsa, lsa.ss_len); memcpy(&p->ni_fsa, &fsa, fsa.ss_len); p->ni_proto = strdup(proto); p->ni_flags = NIF_LACHG|NIF_FACHG; } p->ni_state = state; p->ni_seen = 1; return p; } /* column locations */ #define LADDR 0 #define FADDR LADDR+23 #define PROTO FADDR+23 #define RCVCC PROTO+6 #define SNDCC RCVCC+7 #define STATE SNDCC+7 void labelnetstat(void) { if (use_kvm && namelist[X_TCB].n_type == 0) return; wmove(wnd, 0, 0); wclrtobot(wnd); mvwaddstr(wnd, 0, LADDR, "Local Address"); mvwaddstr(wnd, 0, FADDR, "Foreign Address"); mvwaddstr(wnd, 0, PROTO, "Proto"); mvwaddstr(wnd, 0, RCVCC, "Recv-Q"); mvwaddstr(wnd, 0, SNDCC, "Send-Q"); mvwaddstr(wnd, 0, STATE, "(state)"); } void shownetstat(void) { struct netinfo *p, *q; char proto[6]; const char *family = ""; /* * First, delete any connections that have gone * away and adjust the position of connections * below to reflect the deleted line. */ p = TAILQ_FIRST(&netcb); while (p != NULL) { if (p->ni_line == -1 || p->ni_seen) { p = TAILQ_NEXT(p, chain); continue; } wmove(wnd, p->ni_line, 0); wdeleteln(wnd); TAILQ_FOREACH(q, &netcb, chain) if (q != p && q->ni_line > p->ni_line) { q->ni_line--; /* this shouldn't be necessary */ q->ni_flags |= NIF_LACHG|NIF_FACHG; } lastrow--; q = TAILQ_NEXT(p, chain); TAILQ_REMOVE(&netcb, p, chain); free(p); p = q; } /* * Update existing connections and add new ones. */ TAILQ_FOREACH(p, &netcb, chain) { if (p->ni_line == -1) { /* * Add a new entry if possible. */ if (lastrow > YMAX(wnd)) continue; p->ni_line = lastrow++; p->ni_flags |= NIF_LACHG|NIF_FACHG; } if (p->ni_flags & NIF_LACHG) { wmove(wnd, p->ni_line, LADDR); inetprint((struct sockaddr *)&p->ni_lsa, p->ni_proto); p->ni_flags &= ~NIF_LACHG; } if (p->ni_flags & NIF_FACHG) { wmove(wnd, p->ni_line, FADDR); inetprint((struct sockaddr *)&p->ni_fsa, p->ni_proto); p->ni_flags &= ~NIF_FACHG; } #ifdef INET6 family = (p->ni_lsa.ss_family == AF_INET) ? "4" : "6"; #endif snprintf(proto, sizeof(proto), "%s%s", p->ni_proto, family); mvwaddstr(wnd, p->ni_line, PROTO, proto); mvwprintw(wnd, p->ni_line, RCVCC, "%6u", p->ni_rcvcc); mvwprintw(wnd, p->ni_line, SNDCC, "%6u", p->ni_sndcc); if (streq(p->ni_proto, "tcp")) { if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES) mvwprintw(wnd, p->ni_line, STATE, "%d", p->ni_state); else mvwaddstr(wnd, p->ni_line, STATE, tcpstates[p->ni_state]); } wclrtoeol(wnd); } if (lastrow < YMAX(wnd)) { wmove(wnd, lastrow, 0); wclrtobot(wnd); wmove(wnd, YMAX(wnd), 0); wdeleteln(wnd); /* XXX */ } } /* * Pretty print an Internet address (net address + port). * If the nflag was specified, use numbers instead of names. */ static void inetprint(struct sockaddr *sa, const char *proto) { struct servent *sp = 0; char line[80], *cp; int port; switch (sa->sa_family) { case AF_INET: port = ((struct sockaddr_in *)sa)->sin_port; break; #ifdef INET6 case AF_INET6: port = ((struct sockaddr_in6 *)sa)->sin6_port; break; #endif default: port = 0; break; } snprintf(line, sizeof(line), "%.*s.", 16, inetname(sa)); cp = strchr(line, '\0'); if (!nflag && port) sp = getservbyport(port, proto); if (sp || port == 0) snprintf(cp, sizeof(line) - (cp - line), "%.8s", sp ? sp->s_name : "*"); else snprintf(cp, sizeof(line) - (cp - line), "%d", ntohs((u_short)port)); /* pad to full column to clear any garbage */ cp = strchr(line, '\0'); while (cp - line < 22) *cp++ = ' '; line[22] = '\0'; waddstr(wnd, line); } /* * Construct an Internet address representation. * If the nflag has been supplied, give * numeric value, otherwise try for symbolic name. */ static char * inetname(struct sockaddr *sa) { char *cp = 0; static char line[NI_MAXHOST]; struct hostent *hp; struct netent *np; struct in_addr in; #ifdef INET6 if (sa->sa_family == AF_INET6) { if (memcmp(&((struct sockaddr_in6 *)sa)->sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0) strcpy(line, "*"); else getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, nflag ? NI_NUMERICHOST : 0); return (line); } #endif in = ((struct sockaddr_in *)sa)->sin_addr; if (!nflag && in.s_addr != INADDR_ANY) { int net = inet_netof(in); int lna = inet_lnaof(in); if (lna == INADDR_ANY) { np = getnetbyaddr(net, AF_INET); if (np) cp = np->n_name; } - if (cp == 0) { + if (cp == NULL) { hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET); if (hp) cp = hp->h_name; } } if (in.s_addr == INADDR_ANY) strcpy(line, "*"); else if (cp) snprintf(line, sizeof(line), "%s", cp); else { in.s_addr = ntohl(in.s_addr); #define C(x) ((x) & 0xff) snprintf(line, sizeof(line), "%u.%u.%u.%u", C(in.s_addr >> 24), C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); } return (line); } int cmdnetstat(const char *cmd, const char *args) { if (prefix(cmd, "all")) { aflag = !aflag; goto fixup; } if (prefix(cmd, "numbers") || prefix(cmd, "names")) { struct netinfo *p; int new; new = prefix(cmd, "numbers"); if (new == nflag) return (1); TAILQ_FOREACH(p, &netcb, chain) { if (p->ni_line == -1) continue; p->ni_flags |= NIF_LACHG|NIF_FACHG; } nflag = new; goto redisplay; } if (!netcmd(cmd, args)) return (0); fixup: fetchnetstat(); redisplay: shownetstat(); refresh(); return (1); }