Fix it so it compiles with glibc 2 under linux
[ppp.git] / pppstats / pppstats.c
1 /*
2  * print PPP statistics:
3  *      pppstats [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]
4  *
5  *   -a Show absolute values rather than deltas
6  *   -d Show data rate (kB/s) rather than bytes
7  *   -v Show more stats for VJ TCP header compression
8  *   -r Show compression ratio
9  *   -z Show compression statistics instead of default display
10  *
11  * History:
12  *      perkins@cps.msu.edu: Added compression statistics and alternate 
13  *                display. 11/94
14  *      Brad Parker (brad@cayman.com) 6/92
15  *
16  * from the original "slstats" by Van Jacobson
17  *
18  * Copyright (c) 1989 Regents of the University of California.
19  * All rights reserved.
20  *
21  * Redistribution and use in source and binary forms are permitted
22  * provided that the above copyright notice and this paragraph are
23  * duplicated in all such forms and that any documentation,
24  * advertising materials, and other materials related to such
25  * distribution and use acknowledge that the software was developed
26  * by the University of California, Berkeley.  The name of the
27  * University may not be used to endorse or promote products derived
28  * from this software without specific prior written permission.
29  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  */
33
34 #ifndef lint
35 static char rcsid[] = "$Id: pppstats.c,v 1.22 1998/03/31 23:48:03 paulus Exp $";
36 #endif
37
38 #include <stdio.h>
39 #include <stddef.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <signal.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <sys/ioctl.h>
50
51 #ifndef STREAMS
52 #include <sys/socket.h>         /* *BSD, Linux, NeXT, Ultrix etc. */
53 #ifndef _linux_
54 #include <net/if.h>
55 #include <net/ppp_defs.h>
56 #include <net/if_ppp.h>
57 #else
58 /* Linux */
59 #if __GLIBC__ >= 2
60 #include <net/if.h>
61 #else
62 #include <linux/if.h>
63 #endif
64 #include <linux/types.h>
65 #include <linux/ppp_defs.h>
66 #include <linux/if_ppp.h>
67 #endif /* _linux_ */
68
69 #else   /* STREAMS */
70 #include <sys/stropts.h>        /* SVR4, Solaris 2, SunOS 4, OSF/1, etc. */
71 #include <net/ppp_defs.h>
72 #include <net/pppio.h>
73
74 #endif  /* STREAMS */
75
76 int     vflag, rflag, zflag;    /* select type of display */
77 int     aflag;                  /* print absolute values, not deltas */
78 int     dflag;                  /* print data rates, not bytes */
79 int     interval, count;
80 int     infinite;
81 int     unit;
82 int     s;                      /* socket or /dev/ppp file descriptor */
83 int     signalled;              /* set if alarm goes off "early" */
84 char    *progname;
85 char    *interface;
86
87 #if defined(SUNOS4) || defined(ULTRIX) || defined(NeXT)
88 extern int optind;
89 extern char *optarg;
90 #endif
91
92 static void usage __P((void));
93 static void catchalarm __P((int));
94 static void get_ppp_stats __P((struct ppp_stats *));
95 static void get_ppp_cstats __P((struct ppp_comp_stats *));
96 static void intpr __P((void));
97
98 int main __P((int, char *argv[]));
99
100 static void
101 usage()
102 {
103     fprintf(stderr, "Usage: %s [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]\n",
104             progname);
105     exit(1);
106 }
107
108 /*
109  * Called if an interval expires before intpr has completed a loop.
110  * Sets a flag to not wait for the alarm.
111  */
112 static void
113 catchalarm(arg)
114     int arg;
115 {
116     signalled = 1;
117 }
118
119
120 #ifndef STREAMS
121 static void
122 get_ppp_stats(curp)
123     struct ppp_stats *curp;
124 {
125     struct ifpppstatsreq req;
126
127     memset (&req, 0, sizeof (req));
128
129 #ifdef _linux_
130     req.stats_ptr = (caddr_t) &req.stats;
131 #undef ifr_name
132 #define ifr_name ifr__name
133 #endif
134
135     strncpy(req.ifr_name, interface, sizeof(req.ifr_name));
136     if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
137         fprintf(stderr, "%s: ", progname);
138         if (errno == ENOTTY)
139             fprintf(stderr, "kernel support missing\n");
140         else
141             perror("couldn't get PPP statistics");
142         exit(1);
143     }
144     *curp = req.stats;
145 }
146
147 static void
148 get_ppp_cstats(csp)
149     struct ppp_comp_stats *csp;
150 {
151     struct ifpppcstatsreq creq;
152
153     memset (&creq, 0, sizeof (creq));
154
155 #ifdef _linux_
156     creq.stats_ptr = (caddr_t) &creq.stats;
157 #undef  ifr_name
158 #define ifr_name ifr__name
159 #endif
160
161     strncpy(creq.ifr_name, interface, sizeof(creq.ifr_name));
162     if (ioctl(s, SIOCGPPPCSTATS, &creq) < 0) {
163         fprintf(stderr, "%s: ", progname);
164         if (errno == ENOTTY) {
165             fprintf(stderr, "no kernel compression support\n");
166             if (zflag)
167                 exit(1);
168             rflag = 0;
169         } else {
170             perror("couldn't get PPP compression stats");
171             exit(1);
172         }
173     }
174
175 #ifdef _linux_
176     if (creq.stats.c.bytes_out == 0)
177         creq.stats.c.ratio = 0.0;
178     else
179         creq.stats.c.ratio = (double) creq.stats.c.in_count /
180                              (double) creq.stats.c.bytes_out;
181
182     if (creq.stats.d.bytes_out == 0)
183         creq.stats.d.ratio = 0.0;
184     else
185         creq.stats.d.ratio = (double) creq.stats.d.in_count /
186                              (double) creq.stats.d.bytes_out;
187 #endif
188
189     *csp = creq.stats;
190 }
191
192 #else   /* STREAMS */
193
194 int
195 strioctl(fd, cmd, ptr, ilen, olen)
196     int fd, cmd, ilen, olen;
197     char *ptr;
198 {
199     struct strioctl str;
200
201     str.ic_cmd = cmd;
202     str.ic_timout = 0;
203     str.ic_len = ilen;
204     str.ic_dp = ptr;
205     if (ioctl(fd, I_STR, &str) == -1)
206         return -1;
207     if (str.ic_len != olen)
208         fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
209                olen, str.ic_len, cmd);
210     return 0;
211 }
212
213 static void
214 get_ppp_stats(curp)
215     struct ppp_stats *curp;
216 {
217     if (strioctl(s, PPPIO_GETSTAT, curp, 0, sizeof(*curp)) < 0) {
218         fprintf(stderr, "%s: ", progname);
219         if (errno == EINVAL)
220             fprintf(stderr, "kernel support missing\n");
221         else
222             perror("couldn't get PPP statistics");
223         exit(1);
224     }
225 }
226
227 static void
228 get_ppp_cstats(csp)
229     struct ppp_comp_stats *csp;
230 {
231     if (strioctl(s, PPPIO_GETCSTAT, csp, 0, sizeof(*csp)) < 0) {
232         fprintf(stderr, "%s: ", progname);
233         if (errno == ENOTTY) {
234             fprintf(stderr, "no kernel compression support\n");
235             if (zflag)
236                 exit(1);
237             rflag = 0;
238         } else {
239             perror("couldn't get PPP compression statistics");
240             exit(1);
241         }
242     }
243 }
244
245 #endif /* STREAMS */
246
247 #define MAX0(a)         ((int)(a) > 0? (a): 0)
248 #define V(offset)       MAX0(cur.offset - old.offset)
249 #define W(offset)       MAX0(ccs.offset - ocs.offset)
250
251 #define RATIO(c, i, u)  ((c) == 0? 1.0: (u) / ((double)(c) + (i)))
252 #define CRATE(x)        RATIO(W(x.comp_bytes), W(x.inc_bytes), W(x.unc_bytes))
253
254 #define KBPS(n)         ((n) / (interval * 1000.0))
255
256 /*
257  * Print a running summary of interface statistics.
258  * Repeat display every interval seconds, showing statistics
259  * collected over that interval.  Assumes that interval is non-zero.
260  * First line printed is cumulative.
261  */
262 static void
263 intpr()
264 {
265     register int line = 0;
266     sigset_t oldmask, mask;
267     char *bunit;
268     int ratef = 0;
269     struct ppp_stats cur, old;
270     struct ppp_comp_stats ccs, ocs;
271
272     memset(&old, 0, sizeof(old));
273     memset(&ocs, 0, sizeof(ocs));
274
275     while (1) {
276         get_ppp_stats(&cur);
277         if (zflag || rflag)
278             get_ppp_cstats(&ccs);
279
280         (void)signal(SIGALRM, catchalarm);
281         signalled = 0;
282         (void)alarm(interval);
283
284         if ((line % 20) == 0) {
285             if (zflag) {
286                 printf("IN:  COMPRESSED  INCOMPRESSIBLE   COMP | ");
287                 printf("OUT: COMPRESSED  INCOMPRESSIBLE   COMP\n");
288                 bunit = dflag? "KB/S": "BYTE";
289                 printf("    %s   PACK     %s   PACK  RATIO | ", bunit, bunit);
290                 printf("    %s   PACK     %s   PACK  RATIO", bunit, bunit);
291             } else {
292                 printf("%8.8s %6.6s %6.6s",
293                        "IN", "PACK", "VJCOMP");
294
295                 if (!rflag)
296                     printf(" %6.6s %6.6s", "VJUNC", "VJERR");
297                 if (vflag)
298                     printf(" %6.6s %6.6s", "VJTOSS", "NON-VJ");
299                 if (rflag)
300                     printf(" %6.6s %6.6s", "RATIO", "UBYTE");
301                 printf("  | %8.8s %6.6s %6.6s",
302                        "OUT", "PACK", "VJCOMP");
303
304                 if (!rflag)
305                     printf(" %6.6s %6.6s", "VJUNC", "NON-VJ");
306                 if (vflag)
307                     printf(" %6.6s %6.6s", "VJSRCH", "VJMISS");
308                 if (rflag)
309                     printf(" %6.6s %6.6s", "RATIO", "UBYTE");
310             }
311             putchar('\n');
312         }
313
314         if (zflag) {
315             if (ratef) {
316                 printf("%8.3f %6u %8.3f %6u %6.2f",
317                        KBPS(W(d.comp_bytes)),
318                        W(d.comp_packets),
319                        KBPS(W(d.inc_bytes)),
320                        W(d.inc_packets),
321                        ccs.d.ratio * 256.0);
322                 printf(" | %8.3f %6u %8.3f %6u %6.2f",
323                        KBPS(W(c.comp_bytes)),
324                        W(c.comp_packets),
325                        KBPS(W(c.inc_bytes)),
326                        W(c.inc_packets),
327                        ccs.c.ratio * 256.0);
328             } else {
329                 printf("%8u %6u %8u %6u %6.2f",
330                        W(d.comp_bytes),
331                        W(d.comp_packets),
332                        W(d.inc_bytes),
333                        W(d.inc_packets),
334                        ccs.d.ratio * 256.0);
335                 printf(" | %8u %6u %8u %6u %6.2f",
336                        W(c.comp_bytes),
337                        W(c.comp_packets),
338                        W(c.inc_bytes),
339                        W(c.inc_packets),
340                        ccs.c.ratio * 256.0);
341             }
342         
343         } else {
344             if (ratef)
345                 printf("%8.3f", KBPS(V(p.ppp_ibytes)));
346             else
347                 printf("%8u", V(p.ppp_ibytes));
348             printf(" %6u %6u",
349                    V(p.ppp_ipackets),
350                    V(vj.vjs_compressedin));
351             if (!rflag)
352                 printf(" %6u %6u",
353                        V(vj.vjs_uncompressedin),
354                        V(vj.vjs_errorin));
355             if (vflag)
356                 printf(" %6u %6u",
357                        V(vj.vjs_tossed),
358                        V(p.ppp_ipackets) - V(vj.vjs_compressedin)
359                        - V(vj.vjs_uncompressedin) - V(vj.vjs_errorin));
360             if (rflag) {
361                 printf(" %6.2f ", CRATE(d));
362                 if (ratef)
363                     printf("%6.2f", KBPS(W(d.unc_bytes)));
364                 else
365                     printf("%6u", W(d.unc_bytes));
366             }
367             if (ratef)
368                 printf("  | %8.3f", KBPS(V(p.ppp_obytes)));
369             else
370                 printf("  | %8u", V(p.ppp_obytes));
371             printf(" %6u %6u",
372                    V(p.ppp_opackets),
373                    V(vj.vjs_compressed));
374             if (!rflag)
375                 printf(" %6u %6u",
376                        V(vj.vjs_packets) - V(vj.vjs_compressed),
377                        V(p.ppp_opackets) - V(vj.vjs_packets));
378             if (vflag)
379                 printf(" %6u %6u",
380                        V(vj.vjs_searches),
381                        V(vj.vjs_misses));
382             if (rflag) {
383                 printf(" %6.2f ", CRATE(c));
384                 if (ratef)
385                     printf("%6.2f", KBPS(W(c.unc_bytes)));
386                 else
387                     printf("%6u", W(c.unc_bytes));
388             }
389
390         }
391
392         putchar('\n');
393         fflush(stdout);
394         line++;
395
396         count--;
397         if (!infinite && !count)
398             break;
399
400         sigemptyset(&mask);
401         sigaddset(&mask, SIGALRM);
402         sigprocmask(SIG_BLOCK, &mask, &oldmask);
403         if (!signalled) {
404             sigemptyset(&mask);
405             sigsuspend(&mask);
406         }
407         sigprocmask(SIG_SETMASK, &oldmask, NULL);
408         signalled = 0;
409         (void)alarm(interval);
410
411         if (!aflag) {
412             old = cur;
413             ocs = ccs;
414             ratef = dflag;
415         }
416     }
417 }
418
419 int
420 main(argc, argv)
421     int argc;
422     char *argv[];
423 {
424     int c;
425 #ifdef STREAMS
426     char *dev;
427 #endif
428
429     interface = "ppp0";
430     if ((progname = strrchr(argv[0], '/')) == NULL)
431         progname = argv[0];
432     else
433         ++progname;
434
435     while ((c = getopt(argc, argv, "advrzc:w:")) != -1) {
436         switch (c) {
437         case 'a':
438             ++aflag;
439             break;
440         case 'd':
441             ++dflag;
442             break;
443         case 'v':
444             ++vflag;
445             break;
446         case 'r':
447             ++rflag;
448             break;
449         case 'z':
450             ++zflag;
451             break;
452         case 'c':
453             count = atoi(optarg);
454             if (count <= 0)
455                 usage();
456             break;
457         case 'w':
458             interval = atoi(optarg);
459             if (interval <= 0)
460                 usage();
461             break;
462         default:
463             usage();
464         }
465     }
466     argc -= optind;
467     argv += optind;
468
469     if (!interval && count)
470         interval = 5;
471     if (interval && !count)
472         infinite = 1;
473     if (!interval && !count)
474         count = 1;
475     if (aflag)
476         dflag = 0;
477
478     if (argc > 1)
479         usage();
480     if (argc > 0)
481         interface = argv[0];
482
483     if (sscanf(interface, "ppp%d", &unit) != 1) {
484         fprintf(stderr, "%s: invalid interface '%s' specified\n",
485                 progname, interface);
486     }
487
488 #ifndef STREAMS
489     {
490         struct ifreq ifr;
491
492         s = socket(AF_INET, SOCK_DGRAM, 0);
493         if (s < 0) {
494             fprintf(stderr, "%s: ", progname);
495             perror("couldn't create IP socket");
496             exit(1);
497         }
498
499 #ifdef _linux_
500 #undef  ifr_name
501 #define ifr_name ifr_ifrn.ifrn_name
502 #endif
503         strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
504         if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
505             fprintf(stderr, "%s: nonexistent interface '%s' specified\n",
506                     progname, interface);
507             exit(1);
508         }
509     }
510
511 #else   /* STREAMS */
512 #ifdef __osf__
513     dev = "/dev/streams/ppp";
514 #else
515     dev = "/dev/ppp";
516 #endif
517     if ((s = open(dev, O_RDONLY)) < 0) {
518         fprintf(stderr, "%s: couldn't open ", progname);
519         perror(dev);
520         exit(1);
521     }
522     if (strioctl(s, PPPIO_ATTACH, &unit, sizeof(int), 0) < 0) {
523         fprintf(stderr, "%s: ppp%d is not available\n", progname, unit);
524         exit(1);
525     }
526
527 #endif  /* STREAMS */
528
529     intpr();
530     exit(0);
531 }