xref: /dragonfly/usr.sbin/slstat/slstat.c (revision 279dd846)
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