]> git.ozlabs.org Git - ppp.git/blob - pppstats/pppstats.c
Various fixes for errors found by coverity static analysis (#109)
[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 __P((void));
110 static void catchalarm __P((int));
111 static void get_ppp_stats __P((struct ppp_stats *));
112 static void get_ppp_cstats __P((struct ppp_comp_stats *));
113 static void intpr __P((void));
114
115 int main __P((int, char *argv[]));
116
117 static void
118 usage()
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(arg)
131     int arg;
132 {
133     signalled = 1;
134 }
135
136
137 #ifndef STREAMS
138 static void
139 get_ppp_stats(curp)
140     struct ppp_stats *curp;
141 {
142     struct ifpppstatsreq req;
143
144     memset (&req, 0, sizeof (req));
145
146 #ifdef __linux__
147     req.stats_ptr = (caddr_t) &req.stats;
148 #undef ifr_name
149 #define ifr_name ifr__name
150 #endif
151
152     strncpy(req.ifr_name, interface, IFNAMSIZ);
153     req.ifr_name[IFNAMSIZ - 1] = 0;
154     if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
155         fprintf(stderr, "%s: ", progname);
156         if (errno == ENOTTY)
157             fprintf(stderr, "kernel support missing\n");
158         else
159             perror("couldn't get PPP statistics");
160         exit(1);
161     }
162     *curp = req.stats;
163 }
164
165 static void
166 get_ppp_cstats(csp)
167     struct ppp_comp_stats *csp;
168 {
169     struct ifpppcstatsreq creq;
170
171     memset (&creq, 0, sizeof (creq));
172
173 #ifdef __linux__
174     creq.stats_ptr = (caddr_t) &creq.stats;
175 #undef  ifr_name
176 #define ifr_name ifr__name
177 #endif
178
179     strncpy(creq.ifr_name, interface, IFNAMSIZ);
180     creq.ifr_name[IFNAMSIZ - 1] = 0;
181     if (ioctl(s, SIOCGPPPCSTATS, &creq) < 0) {
182         fprintf(stderr, "%s: ", progname);
183         if (errno == ENOTTY) {
184             fprintf(stderr, "no kernel compression support\n");
185             if (zflag)
186                 exit(1);
187             rflag = 0;
188         } else {
189             perror("couldn't get PPP compression stats");
190             exit(1);
191         }
192     }
193
194 #ifdef __linux__
195     if (creq.stats.c.bytes_out == 0) {
196         creq.stats.c.bytes_out = creq.stats.c.comp_bytes + creq.stats.c.inc_bytes;
197         creq.stats.c.in_count = creq.stats.c.unc_bytes;
198     }
199     if (creq.stats.c.bytes_out == 0)
200         creq.stats.c.ratio = 0.0;
201     else
202         creq.stats.c.ratio = 256.0 * creq.stats.c.in_count /
203                              creq.stats.c.bytes_out;
204
205     if (creq.stats.d.bytes_out == 0) {
206         creq.stats.d.bytes_out = creq.stats.d.comp_bytes + creq.stats.d.inc_bytes;
207         creq.stats.d.in_count = creq.stats.d.unc_bytes;
208     }
209     if (creq.stats.d.bytes_out == 0)
210         creq.stats.d.ratio = 0.0;
211     else
212         creq.stats.d.ratio = 256.0 * creq.stats.d.in_count /
213                              creq.stats.d.bytes_out;
214 #endif
215
216     *csp = creq.stats;
217 }
218
219 #else   /* STREAMS */
220
221 int
222 strioctl(fd, cmd, ptr, ilen, olen)
223     int fd, cmd, ilen, olen;
224     char *ptr;
225 {
226     struct strioctl str;
227
228     str.ic_cmd = cmd;
229     str.ic_timout = 0;
230     str.ic_len = ilen;
231     str.ic_dp = ptr;
232     if (ioctl(fd, I_STR, &str) == -1)
233         return -1;
234     if (str.ic_len != olen)
235         fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
236                olen, str.ic_len, cmd);
237     return 0;
238 }
239
240 static void
241 get_ppp_stats(curp)
242     struct ppp_stats *curp;
243 {
244     if (strioctl(s, PPPIO_GETSTAT, curp, 0, sizeof(*curp)) < 0) {
245         fprintf(stderr, "%s: ", progname);
246         if (errno == EINVAL)
247             fprintf(stderr, "kernel support missing\n");
248         else
249             perror("couldn't get PPP statistics");
250         exit(1);
251     }
252 }
253
254 static void
255 get_ppp_cstats(csp)
256     struct ppp_comp_stats *csp;
257 {
258     if (strioctl(s, PPPIO_GETCSTAT, csp, 0, sizeof(*csp)) < 0) {
259         fprintf(stderr, "%s: ", progname);
260         if (errno == ENOTTY) {
261             fprintf(stderr, "no kernel compression support\n");
262             if (zflag)
263                 exit(1);
264             rflag = 0;
265         } else {
266             perror("couldn't get PPP compression statistics");
267             exit(1);
268         }
269     }
270 }
271
272 #endif /* STREAMS */
273
274 #define MAX0(a)         ((int)(a) > 0? (a): 0)
275 #define V(offset)       MAX0(cur.offset - old.offset)
276 #define W(offset)       MAX0(ccs.offset - ocs.offset)
277
278 #define RATIO(c, i, u)  ((c) == 0? 1.0: (u) / ((double)(c) + (i)))
279 #define CRATE(x)        RATIO(W(x.comp_bytes), W(x.inc_bytes), W(x.unc_bytes))
280
281 #define KBPS(n)         ((n) / (interval * 1000.0))
282
283 /*
284  * Print a running summary of interface statistics.
285  * Repeat display every interval seconds, showing statistics
286  * collected over that interval.  Assumes that interval is non-zero.
287  * First line printed is cumulative.
288  */
289 static void
290 intpr()
291 {
292     register int line = 0;
293     sigset_t oldmask, mask;
294     char *bunit;
295     int ratef = 0;
296     struct ppp_stats cur, old;
297     struct ppp_comp_stats ccs, ocs;
298
299     memset(&old, 0, sizeof(old));
300     memset(&ocs, 0, sizeof(ocs));
301
302     while (1) {
303         get_ppp_stats(&cur);
304         if (zflag || rflag)
305             get_ppp_cstats(&ccs);
306
307         (void)signal(SIGALRM, catchalarm);
308         signalled = 0;
309         (void)alarm(interval);
310
311         if ((line % 20) == 0) {
312             if (zflag) {
313                 printf("IN:  COMPRESSED  INCOMPRESSIBLE   COMP | ");
314                 printf("OUT: COMPRESSED  INCOMPRESSIBLE   COMP\n");
315                 bunit = dflag? "KB/S": "BYTE";
316                 printf("    %s   PACK     %s   PACK  RATIO | ", bunit, bunit);
317                 printf("    %s   PACK     %s   PACK  RATIO", bunit, bunit);
318             } else {
319                 printf("%8.8s %6.6s %6.6s",
320                        "IN", "PACK", "VJCOMP");
321
322                 if (!rflag)
323                     printf(" %6.6s %6.6s", "VJUNC", "VJERR");
324                 if (vflag)
325                     printf(" %6.6s %6.6s", "VJTOSS", "NON-VJ");
326                 if (rflag)
327                     printf(" %6.6s %6.6s", "RATIO", "UBYTE");
328                 printf("  | %8.8s %6.6s %6.6s",
329                        "OUT", "PACK", "VJCOMP");
330
331                 if (!rflag)
332                     printf(" %6.6s %6.6s", "VJUNC", "NON-VJ");
333                 if (vflag)
334                     printf(" %6.6s %6.6s", "VJSRCH", "VJMISS");
335                 if (rflag)
336                     printf(" %6.6s %6.6s", "RATIO", "UBYTE");
337             }
338             putchar('\n');
339         }
340
341         if (zflag) {
342             if (ratef) {
343                 printf("%8.3f %6u %8.3f %6u %6.2f",
344                        KBPS(W(d.comp_bytes)),
345                        W(d.comp_packets),
346                        KBPS(W(d.inc_bytes)),
347                        W(d.inc_packets),
348                        ccs.d.ratio / 256.0);
349                 printf(" | %8.3f %6u %8.3f %6u %6.2f",
350                        KBPS(W(c.comp_bytes)),
351                        W(c.comp_packets),
352                        KBPS(W(c.inc_bytes)),
353                        W(c.inc_packets),
354                        ccs.c.ratio / 256.0);
355             } else {
356                 printf("%8u %6u %8u %6u %6.2f",
357                        W(d.comp_bytes),
358                        W(d.comp_packets),
359                        W(d.inc_bytes),
360                        W(d.inc_packets),
361                        ccs.d.ratio / 256.0);
362                 printf(" | %8u %6u %8u %6u %6.2f",
363                        W(c.comp_bytes),
364                        W(c.comp_packets),
365                        W(c.inc_bytes),
366                        W(c.inc_packets),
367                        ccs.c.ratio / 256.0);
368             }
369         
370         } else {
371             if (ratef)
372                 printf("%8.3f", KBPS(V(p.ppp_ibytes)));
373             else
374                 printf("%8u", V(p.ppp_ibytes));
375             printf(" %6u %6u",
376                    V(p.ppp_ipackets),
377                    V(vj.vjs_compressedin));
378             if (!rflag)
379                 printf(" %6u %6u",
380                        V(vj.vjs_uncompressedin),
381                        V(vj.vjs_errorin));
382             if (vflag)
383                 printf(" %6u %6u",
384                        V(vj.vjs_tossed),
385                        V(p.ppp_ipackets) - V(vj.vjs_compressedin)
386                        - V(vj.vjs_uncompressedin) - V(vj.vjs_errorin));
387             if (rflag) {
388                 printf(" %6.2f ", CRATE(d));
389                 if (ratef)
390                     printf("%6.2f", KBPS(W(d.unc_bytes)));
391                 else
392                     printf("%6u", W(d.unc_bytes));
393             }
394             if (ratef)
395                 printf("  | %8.3f", KBPS(V(p.ppp_obytes)));
396             else
397                 printf("  | %8u", V(p.ppp_obytes));
398             printf(" %6u %6u",
399                    V(p.ppp_opackets),
400                    V(vj.vjs_compressed));
401             if (!rflag)
402                 printf(" %6u %6u",
403                        V(vj.vjs_packets) - V(vj.vjs_compressed),
404                        V(p.ppp_opackets) - V(vj.vjs_packets));
405             if (vflag)
406                 printf(" %6u %6u",
407                        V(vj.vjs_searches),
408                        V(vj.vjs_misses));
409             if (rflag) {
410                 printf(" %6.2f ", CRATE(c));
411                 if (ratef)
412                     printf("%6.2f", KBPS(W(c.unc_bytes)));
413                 else
414                     printf("%6u", W(c.unc_bytes));
415             }
416
417         }
418
419         putchar('\n');
420         fflush(stdout);
421         line++;
422
423         count--;
424         if (!infinite && !count)
425             break;
426
427         sigemptyset(&mask);
428         sigaddset(&mask, SIGALRM);
429         sigprocmask(SIG_BLOCK, &mask, &oldmask);
430         if (!signalled) {
431             sigemptyset(&mask);
432             sigsuspend(&mask);
433         }
434         sigprocmask(SIG_SETMASK, &oldmask, NULL);
435         signalled = 0;
436         (void)alarm(interval);
437
438         if (!aflag) {
439             old = cur;
440             ocs = ccs;
441             ratef = dflag;
442         }
443     }
444 }
445
446 int
447 main(argc, argv)
448     int argc;
449     char *argv[];
450 {
451     int c;
452 #ifdef STREAMS
453     int unit;
454     char *dev;
455 #endif
456
457     interface = PPP_DRV_NAME "0";
458     if ((progname = strrchr(argv[0], '/')) == NULL)
459         progname = argv[0];
460     else
461         ++progname;
462
463     while ((c = getopt(argc, argv, "advrzc:w:")) != -1) {
464         switch (c) {
465         case 'a':
466             ++aflag;
467             break;
468         case 'd':
469             ++dflag;
470             break;
471         case 'v':
472             ++vflag;
473             break;
474         case 'r':
475             ++rflag;
476             break;
477         case 'z':
478             ++zflag;
479             break;
480         case 'c':
481             count = atoi(optarg);
482             if (count <= 0)
483                 usage();
484             break;
485         case 'w':
486             interval = atoi(optarg);
487             if (interval <= 0)
488                 usage();
489             break;
490         default:
491             usage();
492         }
493     }
494     argc -= optind;
495     argv += optind;
496
497     if (!interval && count)
498         interval = 5;
499     if (interval && !count)
500         infinite = 1;
501     if (!interval && !count)
502         count = 1;
503     if (aflag)
504         dflag = 0;
505
506     if (argc > 1)
507         usage();
508     if (argc > 0)
509         interface = argv[0];
510
511 #ifndef STREAMS
512     {
513         struct ifreq ifr;
514
515         s = socket(AF_INET, SOCK_DGRAM, 0);
516         if (s < 0) {
517             fprintf(stderr, "%s: ", progname);
518             perror("couldn't create IP socket");
519             exit(1);
520         }
521
522 #ifdef __linux__
523 #undef  ifr_name
524 #define ifr_name ifr_ifrn.ifrn_name
525 #endif
526         strncpy(ifr.ifr_name, interface, IFNAMSIZ);
527         ifr.ifr_name[IFNAMSIZ - 1] = 0;
528         if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
529             fprintf(stderr, "%s: nonexistent interface '%s' specified\n",
530                     progname, interface);
531             exit(1);
532         }
533     }
534
535 #else   /* STREAMS */
536     if (sscanf(interface, PPP_DRV_NAME "%d", &unit) != 1) {
537         fprintf(stderr, "%s: invalid interface '%s' specified\n",
538                 progname, interface);
539     }
540
541 #ifdef __osf__
542     dev = "/dev/streams/ppp";
543 #else
544     dev = "/dev/" PPP_DRV_NAME;
545 #endif
546     if ((s = open(dev, O_RDONLY)) < 0) {
547         fprintf(stderr, "%s: couldn't open ", progname);
548         perror(dev);
549         exit(1);
550     }
551     if (strioctl(s, PPPIO_ATTACH, &unit, sizeof(int), 0) < 0) {
552         fprintf(stderr, "%s: ppp%d is not available\n", progname, unit);
553         exit(1);
554     }
555
556 #endif  /* STREAMS */
557
558     intpr();
559     exit(0);
560 }