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.5 2004/03/20 17:46:48 cpressey Exp $ 25 */ 26 27 #define _KERNEL_STRUCTURES 28 #include <sys/param.h> 29 #include <sys/mbuf.h> 30 #include <sys/socket.h> 31 #include <sys/sysctl.h> 32 #include <sys/time.h> 33 34 #include <ctype.h> 35 #include <err.h> 36 #include <errno.h> 37 #include <signal.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 43 #include <net/if.h> 44 #include <net/if_var.h> 45 #include <net/if_mib.h> 46 #include <net/if_types.h> 47 #include <netinet/in.h> 48 #include <netinet/in_systm.h> 49 #include <netinet/ip.h> 50 #include <net/slcompress.h> 51 #include <net/sl/if_slvar.h> 52 53 static void usage(void); 54 static void intpr(void); 55 static void catchalarm(int); 56 57 #define INTERFACE_PREFIX "sl%d" 58 59 char interface[IFNAMSIZ]; 60 61 int rflag; 62 int vflag; 63 unsigned interval = 5; 64 int unit; 65 int name[6]; 66 67 int 68 main(int argc, 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(void) 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(void) 160 { 161 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 signal(SIGALRM, catchalarm); 177 signalled = 0; 178 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 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(int sig) 239 { 240 signalled = 1; 241 } 242