Initial revision
[ppp.git] / pppstats / pppstats.c
1 /*
2  * print PPP statistics:
3  *      pppstats [-i interval] [-v] [interface] [system] [core] 
4  *
5  *      Brad Parker (brad@cayman.com) 6/92
6  *
7  * from the original "slstats" by Van Jaconson
8  *
9  * Copyright (c) 1989 Regents of the University of California.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms are permitted
13  * provided that the above copyright notice and this paragraph are
14  * duplicated in all such forms and that any documentation,
15  * advertising materials, and other materials related to such
16  * distribution and use acknowledge that the software was developed
17  * by the University of California, Berkeley.  The name of the
18  * University may not be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
22  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23  *
24  *      Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
25  *      - Initial distribution.
26  */
27
28 #ifndef lint
29 static char rcsid[] = "$Id: pppstats.c,v 1.1 1993/11/11 03:54:25 paulus Exp $";
30 #endif
31
32 #include <sys/param.h>
33 #include <sys/mbuf.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/file.h>
37 #ifndef KVMLIB
38 #include <machine/pte.h>
39 #endif
40 #ifdef sun
41 #include <kvm.h>
42 #endif
43 #include <ctype.h>
44 #include <errno.h>
45 #include <nlist.h>
46 #include <stdio.h>
47 #include <signal.h>
48 #include <net/if.h>
49 #include <netinet/in.h>
50 #include <netinet/in_systm.h>
51 #include <netinet/ip.h>
52 #include <netinet/ip_var.h>
53
54 #define VJC     1
55 #include <net/slcompress.h>
56 #include <net/if_ppp.h>
57
58 #ifdef STREAMS
59 #include <sys/stream.h>
60 #include "ppp_str.h"
61 #endif
62
63 #ifdef STREAMS
64 struct nlist nl[] = {
65 #define N_SOFTC 0
66         { "_pii" },
67         "",
68 };
69 #else
70 struct nlist nl[] = {
71 #define N_SOFTC 0
72         { "_ppp_softc" },
73         "",
74 };
75 #endif
76
77 #ifndef KVMLIB
78 struct  pte *Sysmap;
79 int     kmem;
80 extern  off_t lseek();
81 #endif
82
83 #ifdef sun
84 kvm_t   *kd;
85 #endif
86
87 #ifdef sun
88 char    *system = "/vmunix";
89 #else
90 #ifdef __NetBSD__
91 char    *system = "/netbsd";
92 #else
93 char    *system = "/386bsd";
94 #endif
95 #endif
96
97 #ifndef KVMLIB
98 char    *kmemf = "/dev/kmem";
99 #else
100 char    *kmemf;
101 #endif
102 int     kflag;
103 int     vflag;
104 unsigned interval = 5;
105 int     unit;
106
107 extern  char *malloc();
108
109
110 main(argc, argv)
111         int argc;
112         char *argv[];
113 {
114         --argc; ++argv;
115         while (argc > 0) {
116                 if (strcmp(argv[0], "-v") == 0) {
117                         ++vflag;
118                         ++argv, --argc;
119                         continue;
120                 }
121                 if (strcmp(argv[0], "-i") == 0 && argv[1] &&
122                     isdigit(argv[1][0])) {
123                         interval = atoi(argv[1]);
124                         if (interval <= 0)
125                                 usage();
126                         ++argv, --argc;
127                         ++argv, --argc;
128                         continue;
129                 }
130                 if (isdigit(argv[0][0])) {
131                         unit = atoi(argv[0]);
132                         if (unit < 0)
133                                 usage();
134                         ++argv, --argc;
135                         continue;
136                 }
137                 if (kflag)
138                         usage();
139
140                 system = *argv;
141                 ++argv, --argc;
142                 if (argc > 0) {
143                         kmemf = *argv++;
144                         --argc;
145                         kflag++;
146                 }
147         }
148 #ifndef KVMLIB
149         if (nlist(system, nl) < 0 || nl[0].n_type == 0) {
150                 fprintf(stderr, "%s: no namelist\n", system);
151                 exit(1);
152         }
153         kmem = open(kmemf, O_RDONLY);
154         if (kmem < 0) {
155                 perror(kmemf);
156                 exit(1);
157         }
158         if (kflag) {
159                 off_t off;
160
161                 Sysmap = (struct pte *)
162                    malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
163                 if (!Sysmap) {
164                         fputs("netstat: can't get memory for Sysmap.\n", stderr);
165                         exit(1);
166                 }
167                 off = nl[N_SYSMAP].n_value & ~KERNBASE;
168                 (void)lseek(kmem, off, L_SET);
169                 (void)read(kmem, (char *)Sysmap,
170                     (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
171         }
172 #else
173 #ifdef sun
174         /* SunOS */
175         if ((kd = kvm_open(system, kmemf, (char *)0, O_RDONLY, NULL)) == NULL) {
176           perror("kvm_open");
177           exit(1);
178         }
179 #else
180         /* BSD4.3+ */
181         if (kvm_openfiles(system, kmemf, (char *)0) == -1) {
182           fprintf(stderr, "kvm_openfiles: %s", kvm_geterr());
183           exit(1);
184         }
185 #endif
186
187 #ifdef sun
188         if (kvm_nlist(kd, nl)) {
189 #else
190         if (kvm_nlist(nl)) {
191 #endif
192           fprintf(stderr, "pppstats: can't find symbols in nlist\n");
193           exit(1);
194         }
195 #endif
196         intpr();
197         exit(0);
198 }
199
200 #ifndef KVMLIB
201 /*
202  * Seek into the kernel for a value.
203  */
204 off_t
205 klseek(fd, base, off)
206         int fd, off;
207         off_t base;
208 {
209         if (kflag) {
210                 /* get kernel pte */
211                 base &= ~KERNBASE;
212                 base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
213         }
214         return (lseek(fd, base, off));
215 }
216 #endif
217
218 usage()
219 {
220         fprintf(stderr,"usage: pppstats [-i interval] [-v] [unit] [system] [core]\n");
221         exit(1);
222 }
223
224 u_char  signalled;                      /* set if alarm goes off "early" */
225
226 #define V(offset) ((line % 20)? sc->offset - osc->offset : sc->offset)
227
228 /*
229  * Print a running summary of interface statistics.
230  * Repeat display every interval seconds, showing statistics
231  * collected over that interval.  Assumes that interval is non-zero.
232  * First line printed at top of screen is always cumulative.
233  */
234 intpr()
235 {
236         register int line = 0;
237         int oldmask;
238 #ifdef __STDC__
239         void catchalarm(int);
240 #else
241         void catchalarm();
242 #endif
243
244 #ifdef STREAMS
245 #define STRUCT struct ppp_if_info
246 #else
247 #define STRUCT struct ppp_softc
248 #endif
249
250         STRUCT *sc, *osc;
251
252         nl[N_SOFTC].n_value += unit * sizeof(struct ppp_softc);
253         sc = (STRUCT *)malloc(sizeof(STRUCT));
254         osc = (STRUCT *)malloc(sizeof(STRUCT));
255
256         bzero((char *)osc, sizeof(STRUCT));
257
258         while (1) {
259 #ifndef KVMLIB
260                 if (klseek(kmem, (off_t)nl[N_SOFTC].n_value, 0) < 0)
261                         if(errno != EINTR)
262                                 perror("kmem seek");
263                 if (read(kmem, (char *)sc, sizeof(STRUCT)) <= 0)
264                         perror("kmem read");
265 #else
266 #ifdef sun
267                 if (kvm_read(kd, nl[N_SOFTC].n_value,
268 #else
269                 if (kvm_read(nl[N_SOFTC].n_value,
270 #endif
271                              sc, sizeof(STRUCT)) !=
272                     sizeof(STRUCT))
273                   perror("kvm_read");
274 #endif
275
276                 (void)signal(SIGALRM, catchalarm);
277                 signalled = 0;
278                 (void)alarm(interval);
279
280                 if ((line % 20) == 0) {
281                         printf("%6.6s %6.6s %6.6s %6.6s %6.6s",
282                                 "in", "pack", "comp", "uncomp", "err");
283                         if (vflag)
284                                 printf(" %6.6s %6.6s", "toss", "ip");
285                         printf(" | %6.6s %6.6s %6.6s %6.6s %6.6s",
286                                 "out", "pack", "comp", "uncomp", "ip");
287                         if (vflag)
288                                 printf(" %6.6s %6.6s", "search", "miss");
289                         putchar('\n');
290                 }
291
292 #ifdef STREAMS
293 #define COMP    pii_sc_comp
294 #define STATS   pii_ifnet
295 #else
296 #define COMP    sc_comp
297 #define STATS   sc_if
298 #endif
299
300                 printf("%6d %6d %6d %6d %6d",
301 #if BSD > 43
302                         V(STATS.if_ibytes),
303 #else
304                         0,
305 #endif
306                         V(STATS.if_ipackets),
307                         V(COMP.sls_compressedin),
308                         V(COMP.sls_uncompressedin),
309                         V(COMP.sls_errorin));
310                 if (vflag)
311                         printf(" %6d %6d",
312                                 V(COMP.sls_tossed),
313                                 V(STATS.if_ipackets) -
314                                   V(COMP.sls_compressedin) -
315                                   V(COMP.sls_uncompressedin) -
316                                   V(COMP.sls_errorin));
317                 printf(" | %6d %6d %6d %6d %6d",
318 #if BSD > 43
319                         V(STATS.if_obytes),
320 #else
321                         0,
322 #endif
323                         V(STATS.if_opackets),
324                         V(COMP.sls_compressed),
325                         V(COMP.sls_packets) - V(COMP.sls_compressed),
326                         V(STATS.if_opackets) - V(COMP.sls_packets));
327                 if (vflag)
328                         printf(" %6d %6d",
329                                 V(COMP.sls_searches),
330                                 V(COMP.sls_misses));
331
332                 putchar('\n');
333                 fflush(stdout);
334                 line++;
335                 oldmask = sigblock(sigmask(SIGALRM));
336                 if (! signalled) {
337                         sigpause(0);
338                 }
339                 sigsetmask(oldmask);
340                 signalled = 0;
341                 (void)alarm(interval);
342                 bcopy((char *)sc, (char *)osc, sizeof(STRUCT));
343         }
344 }
345
346 /*
347  * Called if an interval expires before sidewaysintpr has completed a loop.
348  * Sets a flag to not wait for the alarm.
349  */
350 void catchalarm(arg)
351 int arg;
352 {
353         signalled = 1;
354 }