| 1 | /* |
| 2 | * print serial line IP statistics: |
| 3 | * slstat [-i interval] [-v] [interface] |
| 4 | * |
| 5 | * Copyright (c) 1989, 1990, 1991, 1992 Regents of the University of |
| 6 | * California. All rights reserved. |
| 7 | * |
| 8 | * Redistribution and use in source and binary forms are permitted |
| 9 | * provided that the above copyright notice and this paragraph are |
| 10 | * duplicated in all such forms and that any documentation, |
| 11 | * advertising materials, and other materials related to such |
| 12 | * distribution and use acknowledge that the software was developed |
| 13 | * by the University of California, Berkeley. The name of the |
| 14 | * University may not be used to endorse or promote products derived |
| 15 | * from this software without specific prior written permission. |
| 16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
| 17 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
| 18 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
| 19 | * |
| 20 | * Van Jacobson (van@ee.lbl.gov), Dec 31, 1989: |
| 21 | * - Initial distribution. |
| 22 | * |
| 23 | * $FreeBSD: src/usr.sbin/slstat/slstat.c,v 1.14 1999/08/28 01:20:00 peter Exp $ |
| 24 | * $DragonFly: src/usr.sbin/slstat/slstat.c,v 1.3 2003/08/08 04:18:48 dillon Exp $ |
| 25 | */ |
| 26 | |
| 27 | #include <sys/param.h> |
| 28 | #include <sys/mbuf.h> |
| 29 | #include <sys/socket.h> |
| 30 | #include <sys/sysctl.h> |
| 31 | #include <sys/time.h> |
| 32 | |
| 33 | #include <ctype.h> |
| 34 | #include <err.h> |
| 35 | #include <errno.h> |
| 36 | #include <signal.h> |
| 37 | #include <stdio.h> |
| 38 | #include <stdlib.h> |
| 39 | #include <string.h> |
| 40 | #include <unistd.h> |
| 41 | |
| 42 | #include <net/if.h> |
| 43 | #include <net/if_var.h> |
| 44 | #include <net/if_mib.h> |
| 45 | #include <net/if_types.h> |
| 46 | #include <netinet/in.h> |
| 47 | #include <netinet/in_systm.h> |
| 48 | #include <netinet/ip.h> |
| 49 | #include <net/slcompress.h> |
| 50 | #include <net/sl/if_slvar.h> |
| 51 | |
| 52 | static void usage __P((void)); |
| 53 | static void intpr __P((void)); |
| 54 | static void catchalarm __P((int)); |
| 55 | |
| 56 | #define INTERFACE_PREFIX "sl%d" |
| 57 | char interface[IFNAMSIZ]; |
| 58 | |
| 59 | int rflag; |
| 60 | int vflag; |
| 61 | unsigned interval = 5; |
| 62 | int unit; |
| 63 | int name[6]; |
| 64 | |
| 65 | int |
| 66 | main(argc, argv) |
| 67 | int argc; |
| 68 | char *argv[]; |
| 69 | { |
| 70 | int c, i; |
| 71 | size_t len; |
| 72 | int maxifno; |
| 73 | int indx; |
| 74 | struct ifmibdata ifmd; |
| 75 | |
| 76 | while ((c = getopt(argc, argv, "vri:")) != -1) { |
| 77 | switch(c) { |
| 78 | case 'v': |
| 79 | ++vflag; |
| 80 | break; |
| 81 | case 'r': |
| 82 | ++rflag; |
| 83 | break; |
| 84 | case 'i': |
| 85 | interval = atoi(optarg); |
| 86 | if (interval <= 0) |
| 87 | usage(); |
| 88 | break; |
| 89 | default: |
| 90 | usage(); |
| 91 | } |
| 92 | } |
| 93 | if (optind >= argc) |
| 94 | sprintf(interface, INTERFACE_PREFIX, unit); |
| 95 | else if (isdigit(argv[optind][0])) { |
| 96 | unit = atoi(argv[optind]); |
| 97 | if (unit < 0) |
| 98 | usage(); |
| 99 | sprintf(interface, INTERFACE_PREFIX, unit); |
| 100 | } else if (strncmp(argv[optind], "sl", 2) == 0 |
| 101 | && isdigit(argv[optind][2]) |
| 102 | && sscanf(argv[optind], "sl%d", &unit) == 1) { |
| 103 | strncpy(interface, argv[optind], IFNAMSIZ); |
| 104 | } else |
| 105 | usage(); |
| 106 | |
| 107 | name[0] = CTL_NET; |
| 108 | name[1] = PF_LINK; |
| 109 | name[2] = NETLINK_GENERIC; |
| 110 | name[3] = IFMIB_SYSTEM; |
| 111 | name[4] = IFMIB_IFCOUNT; |
| 112 | len = sizeof maxifno; |
| 113 | if (sysctl(name, 5, &maxifno, &len, 0, 0) < 0) |
| 114 | err(1, "sysctl net.link.generic.system.ifcount"); |
| 115 | |
| 116 | name[3] = IFMIB_IFDATA; |
| 117 | name[5] = IFDATA_GENERAL; |
| 118 | len = sizeof ifmd; |
| 119 | for (i = 1; ; i++) { |
| 120 | name[4] = i; |
| 121 | |
| 122 | if (sysctl(name, 6, &ifmd, &len, 0, 0) < 0) |
| 123 | err(1, "sysctl"); |
| 124 | if (strncmp(interface, ifmd.ifmd_name, IFNAMSIZ) == 0 |
| 125 | && ifmd.ifmd_data.ifi_type == IFT_SLIP) { |
| 126 | indx = i; |
| 127 | break; |
| 128 | } |
| 129 | if (i >= maxifno) |
| 130 | errx(1, "interface %s does not exist", interface); |
| 131 | } |
| 132 | |
| 133 | name[4] = indx; |
| 134 | name[5] = IFDATA_LINKSPECIFIC; |
| 135 | intpr(); |
| 136 | exit(0); |
| 137 | } |
| 138 | |
| 139 | #define V(offset) ((line % 20)? ((sc->offset - osc->offset) / \ |
| 140 | (rflag ? interval : 1)) : sc->offset) |
| 141 | #define AMT (sizeof(*sc) - 2 * sizeof(sc->sc_comp.tstate)) |
| 142 | |
| 143 | static void |
| 144 | usage() |
| 145 | { |
| 146 | fprintf(stderr, "usage: slstat [-i interval] [-vr] [unit]\n"); |
| 147 | exit(1); |
| 148 | } |
| 149 | |
| 150 | u_char signalled; /* set if alarm goes off "early" */ |
| 151 | |
| 152 | /* |
| 153 | * Print a running summary of interface statistics. |
| 154 | * Repeat display every interval seconds, showing statistics |
| 155 | * collected over that interval. Assumes that interval is non-zero. |
| 156 | * First line printed at top of screen is always cumulative. |
| 157 | */ |
| 158 | static void |
| 159 | intpr() |
| 160 | { |
| 161 | register int line = 0; |
| 162 | int oldmask; |
| 163 | struct sl_softc *sc, *osc; |
| 164 | size_t len; |
| 165 | |
| 166 | sc = (struct sl_softc *)malloc(AMT); |
| 167 | osc = (struct sl_softc *)malloc(AMT); |
| 168 | bzero((char *)osc, AMT); |
| 169 | len = AMT; |
| 170 | |
| 171 | while (1) { |
| 172 | if (sysctl(name, 6, sc, &len, 0, 0) < 0 && |
| 173 | (errno != ENOMEM || len != AMT)) |
| 174 | err(1, "sysctl linkspecific"); |
| 175 | |
| 176 | (void)signal(SIGALRM, catchalarm); |
| 177 | signalled = 0; |
| 178 | (void)alarm(interval); |
| 179 | |
| 180 | if ((line % 20) == 0) { |
| 181 | printf("%8.8s %6.6s %6.6s %6.6s %6.6s", |
| 182 | "in", "pack", "comp", "uncomp", "unknwn"); |
| 183 | if (vflag) |
| 184 | printf(" %6.6s %6.6s %6.6s", |
| 185 | "toss", "other", "err"); |
| 186 | printf(" | %8.8s %6.6s %6.6s %6.6s %6.6s", |
| 187 | "out", "pack", "comp", "uncomp", "other"); |
| 188 | if (vflag) |
| 189 | printf(" %6.6s %6.6s %6.6s %6.6s", |
| 190 | "search", "miss", "err", "coll"); |
| 191 | putchar('\n'); |
| 192 | } |
| 193 | printf("%8lu %6ld %6u %6u %6u", |
| 194 | V(sc_if.if_ibytes), |
| 195 | V(sc_if.if_ipackets), |
| 196 | V(sc_comp.sls_compressedin), |
| 197 | V(sc_comp.sls_uncompressedin), |
| 198 | V(sc_comp.sls_errorin)); |
| 199 | if (vflag) |
| 200 | printf(" %6u %6lu %6lu", |
| 201 | V(sc_comp.sls_tossed), |
| 202 | V(sc_if.if_ipackets) - |
| 203 | V(sc_comp.sls_compressedin) - |
| 204 | V(sc_comp.sls_uncompressedin) - |
| 205 | V(sc_comp.sls_errorin), |
| 206 | V(sc_if.if_ierrors)); |
| 207 | printf(" | %8lu %6ld %6u %6u %6lu", |
| 208 | V(sc_if.if_obytes) / (rflag ? interval : 1), |
| 209 | V(sc_if.if_opackets), |
| 210 | V(sc_comp.sls_compressed), |
| 211 | V(sc_comp.sls_packets) - V(sc_comp.sls_compressed), |
| 212 | V(sc_if.if_opackets) - V(sc_comp.sls_packets)); |
| 213 | if (vflag) |
| 214 | printf(" %6u %6u %6lu %6lu", |
| 215 | V(sc_comp.sls_searches), |
| 216 | V(sc_comp.sls_misses), |
| 217 | V(sc_if.if_oerrors), |
| 218 | V(sc_if.if_collisions)); |
| 219 | putchar('\n'); |
| 220 | fflush(stdout); |
| 221 | line++; |
| 222 | oldmask = sigblock(sigmask(SIGALRM)); |
| 223 | if (! signalled) { |
| 224 | sigpause(0); |
| 225 | } |
| 226 | sigsetmask(oldmask); |
| 227 | signalled = 0; |
| 228 | (void)alarm(interval); |
| 229 | bcopy((char *)sc, (char *)osc, AMT); |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | /* |
| 234 | * Called if an interval expires before sidewaysintpr has completed a loop. |
| 235 | * Sets a flag to not wait for the alarm. |
| 236 | */ |
| 237 | static void |
| 238 | catchalarm(sig) |
| 239 | int sig; |
| 240 | { |
| 241 | signalled = 1; |
| 242 | } |