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