Linux mods from Al's version
[ppp.git] / pppstats / pppstats.c
1 /*
2  * print PPP statistics:
3  *      pppstats [-i interval] [-v] [-r] [-c] [interface]
4  *
5  *   -i <update interval in seconds>
6  *   -v Verbose mode for default display
7  *   -r Show compression ratio in default display
8  *   -c Show Compression statistics instead of default display
9  *   -a Do not show relative values. Show absolute values at all times.
10  *
11  *
12  * History:
13  *      perkins@cps.msu.edu: Added compression statistics and alternate 
14  *                display. 11/94
15
16  *      Brad Parker (brad@cayman.com) 6/92
17  *
18  * from the original "slstats" by Van Jaconson
19  *
20  * Copyright (c) 1989 Regents of the University of California.
21  * All rights reserved.
22  *
23  * Redistribution and use in source and binary forms are permitted
24  * provided that the above copyright notice and this paragraph are
25  * duplicated in all such forms and that any documentation,
26  * advertising materials, and other materials related to such
27  * distribution and use acknowledge that the software was developed
28  * by the University of California, Berkeley.  The name of the
29  * University may not be used to endorse or promote products derived
30  * from this software without specific prior written permission.
31  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
32  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
33  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
34  *
35  *      Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
36  *      - Initial distribution.
37  */
38
39 #ifndef lint
40 static char rcsid[] = "$Id: pppstats.c,v 1.12 1995/12/11 05:18:59 paulus Exp $";
41 #endif
42
43 #include <ctype.h>
44 #include <errno.h>
45 #include <nlist.h>
46 #include <stdio.h>
47 #include <signal.h>
48 #include <fcntl.h>
49 #include <sys/param.h>
50 #include <sys/types.h>
51 #include <sys/ioctl.h>
52
53 #include <net/ppp_defs.h>
54
55 #ifdef __svr4__
56 #include <sys/stropts.h>
57 #include <net/pppio.h>          /* SVR4, Solaris 2, etc. */
58
59 #else
60 #include <sys/socket.h>
61 #include <net/if.h>
62
63 #ifndef STREAMS
64 #include <net/if_ppp.h>         /* BSD, Linux, NeXT, etc. */
65
66 #else                           /* SunOS 4, AIX 4, OSF/1, etc. */
67 #define PPP_STATS       1       /* should be defined iff it is in ppp_if.c */
68 #include <sys/stream.h>
69 #include <net/ppp_str.h>
70 #endif
71 #endif
72
73 int     vflag, rflag, cflag, aflag;
74 unsigned interval = 5;
75 int     unit;
76 int     s;                      /* socket file descriptor */
77 int     signalled;              /* set if alarm goes off "early" */
78
79 extern  char *malloc();
80 void catchalarm __P((int));
81
82 main(argc, argv)
83     int argc;
84     char *argv[];
85 {
86     --argc; ++argv;
87     while (argc > 0) {
88         if (strcmp(argv[0], "-a") == 0) {
89             ++aflag;
90             ++argv, --argc;
91             continue;
92         }
93         if (strcmp(argv[0], "-v") == 0) {
94             ++vflag;
95             ++argv, --argc;
96             continue;
97         }
98         if (strcmp(argv[0], "-r") == 0) {
99           ++rflag;
100           ++argv, --argc;
101           continue;
102         }
103         if (strcmp(argv[0], "-c") == 0) {
104           ++cflag;
105           ++argv, --argc;
106           continue;
107         }
108         if (strcmp(argv[0], "-i") == 0 && argv[1] &&
109             isdigit(argv[1][0])) {
110             interval = atoi(argv[1]);
111             if (interval < 0)
112                 usage();
113             ++argv, --argc;
114             ++argv, --argc;
115             continue;
116         }
117         if (isdigit(argv[0][0])) {
118             unit = atoi(argv[0]);
119             if (unit < 0)
120                 usage();
121             ++argv, --argc;
122             continue;
123         }
124         usage();
125     }
126
127 #ifdef __svr4__
128     if ((s = open("/dev/ppp", O_RDONLY)) < 0) {
129         perror("pppstats: Couldn't open /dev/ppp: ");
130         exit(1);
131     }
132     if (strioctl(s, PPPIO_ATTACH, &unit, sizeof(int), 0) < 0) {
133         fprintf(stderr, "pppstats: ppp%d is not available\n", unit);
134         exit(1);
135     }
136 #else
137     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
138         perror("couldn't create IP socket");
139         exit(1);
140     }
141 #endif
142     intpr();
143     exit(0);
144 }
145
146 usage()
147 {
148     fprintf(stderr, "Usage: pppstats [-v] [-r] [-c] [-i interval] [unit]\n");
149     exit(1);
150 }
151
152 #define V(offset) (line % 20? cur.offset - old.offset: cur.offset)
153 #define W(offset) (line % 20? ccs.offset - ocs.offset: ccs.offset)
154
155 #define CRATE(comp, inc, unc)   ((unc) == 0? 0.0: \
156                                  1.0 - (double)((comp) + (inc)) / (unc))
157
158 /*
159  * Print a running summary of interface statistics.
160  * Repeat display every interval seconds, showing statistics
161  * collected over that interval.  Assumes that interval is non-zero.
162  * First line printed at top of screen is always cumulative.
163  */
164 intpr()
165 {
166     register int line = 0;
167     sigset_t oldmask, mask;
168     struct ppp_stats cur, old;
169     struct ppp_comp_stats ccs, ocs;
170
171     memset(&old, 0, sizeof(old));
172     memset(&ocs, 0, sizeof(ocs));
173
174     while (1) {
175         get_ppp_stats(&cur);
176         if (cflag || rflag)
177             get_ppp_cstats(&ccs);
178
179         (void)signal(SIGALRM, catchalarm);
180         signalled = 0;
181         (void)alarm(interval);
182     
183         if ((line % 20) == 0) {
184             if (line > 0)
185                 putchar('\n');
186             if (cflag) {
187             
188                 printf("%6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s",
189                        "ubyte", "upack", "cbyte", "cpack", "ibyte", "ipack", "ratio");
190                 printf(" | %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s",
191                        "ubyte", "upack", "cbyte", "cpack", "ibyte", "ipack", "ratio");
192                 putchar('\n');
193             } else {
194
195                 printf("%6.6s %6.6s %6.6s %6.6s %6.6s",
196                        "in", "pack", "comp", "uncomp", "err");
197                 if (vflag)
198                     printf(" %6.6s %6.6s", "toss", "ip");
199                 if (rflag)
200                     printf("   %6.6s %6.6s", "ratio", "ubyte");
201                 printf("  | %6.6s %6.6s %6.6s %6.6s %6.6s",
202                        "out", "pack", "comp", "uncomp", "ip");
203                 if (vflag)
204                     printf(" %6.6s %6.6s", "search", "miss");
205                 if(rflag)
206                     printf("   %6.6s %6.6s", "ratio", "ubyte");
207                 putchar('\n');
208             }
209             memset(&old, 0, sizeof(old));
210             memset(&ocs, 0, sizeof(ocs));
211         }
212         
213         if (cflag) {
214             printf("%6d %6d %6d %6d %6d %6d %6.2f",
215                    W(d.unc_bytes),
216                    W(d.unc_packets),
217                    W(d.comp_bytes),
218                    W(d.comp_packets),
219                    W(d.inc_bytes),
220                    W(d.inc_packets),
221                    W(d.ratio) == 0? 0.0: 1 - 1.0 / W(d.ratio) * 256.0);
222
223             printf(" | %6d %6d %6d %6d %6d %6d %6.2f",
224                    W(c.unc_bytes),
225                    W(c.unc_packets),
226                    W(c.comp_bytes),
227                    W(c.comp_packets),
228                    W(c.inc_bytes),
229                    W(c.inc_packets),
230                    W(d.ratio) == 0? 0.0: 1 - 1.0 / W(d.ratio) * 256.0);
231         
232             putchar('\n');
233         } else {
234
235             printf("%6d %6d %6d %6d %6d",
236                    V(p.ppp_ibytes),
237                    V(p.ppp_ipackets), V(vj.vjs_compressedin),
238                    V(vj.vjs_uncompressedin), V(vj.vjs_errorin));
239             if (vflag)
240                 printf(" %6d %6d", V(vj.vjs_tossed),
241                        V(p.ppp_ipackets) - V(vj.vjs_compressedin) -
242                        V(vj.vjs_uncompressedin) - V(vj.vjs_errorin));
243             if (rflag)
244                 printf("   %6.2f %6d",
245                        CRATE(W(d.comp_bytes), W(d.unc_bytes), W(d.unc_bytes)),
246                        W(d.unc_bytes));
247             printf("  | %6d %6d %6d %6d %6d", V(p.ppp_obytes),
248                    V(p.ppp_opackets), V(vj.vjs_compressed),
249                    V(vj.vjs_packets) - V(vj.vjs_compressed),
250                    V(p.ppp_opackets) - V(vj.vjs_packets));
251             if (vflag)
252                 printf(" %6d %6d", V(vj.vjs_searches), V(vj.vjs_misses));
253
254             if (rflag)
255                 printf("   %6.2f %6d",
256                        CRATE(W(d.comp_bytes), W(d.unc_bytes), W(d.unc_bytes)),
257                        W(c.unc_bytes));
258             
259             putchar('\n');
260         }
261
262         fflush(stdout);
263         line++;
264         if (interval == 0)
265             exit(0);
266
267         sigemptyset(&mask);
268         sigaddset(&mask, SIGALRM);
269         sigprocmask(SIG_BLOCK, &mask, &oldmask);
270         if (! signalled) {
271             sigemptyset(&mask);
272             sigsuspend(&mask);
273         }
274         sigprocmask(SIG_SETMASK, &oldmask, NULL);
275         signalled = 0;
276         (void)alarm(interval);
277
278         if (aflag==0) {
279             old = cur;
280             ocs = ccs;
281         }
282     }
283 }
284
285 /*
286  * Called if an interval expires before sidewaysintpr has completed a loop.
287  * Sets a flag to not wait for the alarm.
288  */
289 void catchalarm(arg)
290     int arg;
291 {
292     signalled = 1;
293 }
294
295 #ifndef __svr4__
296 get_ppp_stats(curp)
297     struct ppp_stats *curp;
298 {
299     struct ifpppstatsreq req;
300
301     memset (&req, 0, sizeof (req));
302
303 #ifdef _linux_
304     req.stats_ptr = (caddr_t) &req.stats;
305 #undef ifr_name
306 #define ifr_name ifr__name
307 #endif
308
309     sprintf(req.ifr_name, "ppp%d", unit);
310     if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
311         if (errno == ENOTTY)
312             fprintf(stderr, "pppstats: kernel support missing\n");
313         else
314             perror("ioctl(SIOCGPPPSTATS)");
315         exit(1);
316     }
317     *curp = req.stats;
318 }
319
320 get_ppp_cstats(csp)
321     struct ppp_comp_stats *csp;
322 {
323     struct ifpppcstatsreq creq;
324
325     memset (&creq, 0, sizeof (creq));
326
327 #ifdef _linux_
328     creq.stats_ptr = (caddr_t) &creq.stats;
329 #undef  ifr_name
330 #define ifr_name ifr__name
331 #endif
332
333     sprintf(creq.ifr_name, "ppp%d", unit);
334     if (ioctl(s, SIOCGPPPCSTATS, &creq) < 0) {
335         if (errno == ENOTTY) {
336             fprintf(stderr, "pppstats: no kernel compression support\n");
337             if (cflag)
338                 exit(1);
339             rflag = 0;
340         } else {
341             perror("ioctl(SIOCGPPPCSTATS)");
342             exit(1);
343         }
344     }
345
346 #ifdef _linux_
347     if (creq.stats.c.bytes_out == 0)
348         creq.stats.c.ratio = 0.0;
349     else
350         creq.stats.c.ratio = (double) creq.stats.c.in_count /
351                              (double) creq.stats.c.bytes_out;
352
353     if (creq.stats.d.bytes_out == 0)
354         creq.stats.d.ratio = 0.0;
355     else
356         creq.stats.d.ratio = (double) creq.stats.d.in_count /
357                              (double) creq.stats.d.bytes_out;
358 #endif
359
360     *csp = creq.stats;
361 }
362
363 #else   /* __svr4__ */
364 get_ppp_stats(curp)
365     struct ppp_stats *curp;
366 {
367     if (strioctl(s, PPPIO_GETSTAT, curp, 0, sizeof(*curp)) < 0) {
368         if (errno == EINVAL)
369             fprintf(stderr, "pppstats: kernel support missing\n");
370         else
371             perror("pppstats: Couldn't get statistics");
372         exit(1);
373     }
374 }
375
376 get_ppp_cstats(csp)
377     struct ppp_comp_stats *csp;
378 {
379     if (strioctl(s, PPPIO_GETCSTAT, csp, 0, sizeof(*csp)) < 0) {
380         if (errno == ENOTTY) {
381             fprintf(stderr, "pppstats: no kernel compression support\n");
382             if (cflag)
383                 exit(1);
384             rflag = 0;
385         } else {
386             perror("pppstats: Couldn't get compression statistics");
387             exit(1);
388         }
389     }
390 }
391
392 int
393 strioctl(fd, cmd, ptr, ilen, olen)
394     int fd, cmd, ilen, olen;
395     char *ptr;
396 {
397     struct strioctl str;
398
399     str.ic_cmd = cmd;
400     str.ic_timout = 0;
401     str.ic_len = ilen;
402     str.ic_dp = ptr;
403     if (ioctl(fd, I_STR, &str) == -1)
404         return -1;
405     if (str.ic_len != olen)
406         fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
407                olen, str.ic_len, cmd);
408     return 0;
409 }
410 #endif /* __svr4__ */