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