Sync usage with man page.
[netbsd-mini2440.git] / dist / pppd / pppstats / pppstats.c
blob3d5c5c7d13f1bc7aaec6f8148181966fb3d961b9
1 /* $NetBSD: pppstats.c,v 1.2 2006/03/02 17:32:28 christos Exp $ */
3 /*
4 * print PPP statistics:
5 * pppstats [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]
7 * -a Show absolute values rather than deltas
8 * -d Show data rate (kB/s) rather than bytes
9 * -v Show more stats for VJ TCP header compression
10 * -r Show compression ratio
11 * -z Show compression statistics instead of default display
13 * History:
14 * perkins@cps.msu.edu: Added compression statistics and alternate
15 * display. 11/94
16 * Brad Parker (brad@cayman.com) 6/92
18 * from the original "slstats" by Van Jacobson
20 * Copyright (c) 1989 Regents of the University of California.
21 * All rights reserved.
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.
36 #ifndef __STDC__
37 #define const
38 #endif
40 #include <sys/cdefs.h>
41 #ifndef lint
42 #if 0
43 static const char rcsid[] = "Id: pppstats.c,v 1.29 2002/10/27 12:56:26 fcusack Exp";
44 #else
45 __RCSID("$NetBSD: pppstats.c,v 1.2 2006/03/02 17:32:28 christos Exp $");
46 #endif
47 #endif
49 #include <stdio.h>
50 #include <stddef.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <ctype.h>
54 #include <errno.h>
55 #include <signal.h>
56 #include <fcntl.h>
57 #include <unistd.h>
58 #include <sys/param.h>
59 #include <sys/types.h>
60 #include <sys/ioctl.h>
62 #ifndef STREAMS
63 #if defined(__linux__) && defined(__powerpc__) \
64 && (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
65 /* kludge alert! */
66 #undef __GLIBC__
67 #endif
68 #include <sys/socket.h> /* *BSD, Linux, NeXT, Ultrix etc. */
69 #ifndef __linux__
70 #include <net/if.h>
71 #include <net/ppp_defs.h>
72 #include <net/if_ppp.h>
73 #else
74 /* Linux */
75 #if __GLIBC__ >= 2
76 #include <asm/types.h> /* glibc 2 conflicts with linux/types.h */
77 #include <net/if.h>
78 #else
79 #include <linux/types.h>
80 #include <linux/if.h>
81 #endif
82 #include <linux/ppp_defs.h>
83 #include <linux/if_ppp.h>
84 #endif /* __linux__ */
86 #else /* STREAMS */
87 #include <sys/stropts.h> /* SVR4, Solaris 2, SunOS 4, OSF/1, etc. */
88 #include <net/ppp_defs.h>
89 #include <net/pppio.h>
91 #endif /* STREAMS */
93 int vflag, rflag, zflag; /* select type of display */
94 int aflag; /* print absolute values, not deltas */
95 int dflag; /* print data rates, not bytes */
96 int interval, count;
97 int infinite;
98 int unit;
99 int s; /* socket or /dev/ppp file descriptor */
100 int signalled; /* set if alarm goes off "early" */
101 char *progname;
102 char *interface;
104 #if defined(SUNOS4) || defined(ULTRIX) || defined(NeXT)
105 extern int optind;
106 extern char *optarg;
107 #endif
110 * If PPP_DRV_NAME is not defined, use the legacy "ppp" as the
111 * device name.
113 #if !defined(PPP_DRV_NAME)
114 #define PPP_DRV_NAME "ppp"
115 #endif /* !defined(PPP_DRV_NAME) */
116 #if !defined(SL_DRV_NAME)
117 #define SL_DRV_NAME "sl"
118 #endif /* !defined(SL_DRV_NAME) */
120 static void usage __P((void));
121 static void catchalarm __P((int));
122 static void get_ppp_stats __P((struct ppp_stats *));
123 static void get_ppp_cstats __P((struct ppp_comp_stats *));
124 static void intpr __P((void));
126 int main __P((int, char *argv[]));
128 static void
129 usage()
131 fprintf(stderr, "Usage: %s [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]\n",
132 progname);
133 exit(1);
137 * Called if an interval expires before intpr has completed a loop.
138 * Sets a flag to not wait for the alarm.
140 static void
141 catchalarm(arg)
142 int arg;
144 signalled = 1;
148 #ifndef STREAMS
149 static void
150 get_ppp_stats(curp)
151 struct ppp_stats *curp;
153 struct ifpppstatsreq req;
155 memset (&req, 0, sizeof (req));
157 #ifdef __linux__
158 req.stats_ptr = (caddr_t) &req.stats;
159 #undef ifr_name
160 #define ifr_name ifr__name
161 #endif
163 strncpy(req.ifr_name, interface, sizeof(req.ifr_name));
164 if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
165 fprintf(stderr, "%s: ", progname);
166 if (errno == ENOTTY)
167 fprintf(stderr, "kernel support missing\n");
168 else
169 perror("couldn't get PPP statistics");
170 exit(1);
172 *curp = req.stats;
175 static void
176 get_ppp_cstats(csp)
177 struct ppp_comp_stats *csp;
179 struct ifpppcstatsreq creq;
181 memset (&creq, 0, sizeof (creq));
183 #ifdef __linux__
184 creq.stats_ptr = (caddr_t) &creq.stats;
185 #undef ifr_name
186 #define ifr_name ifr__name
187 #endif
189 strncpy(creq.ifr_name, interface, sizeof(creq.ifr_name));
190 if (ioctl(s, SIOCGPPPCSTATS, &creq) < 0) {
191 fprintf(stderr, "%s: ", progname);
192 if (errno == ENOTTY) {
193 fprintf(stderr, "no kernel compression support\n");
194 if (zflag)
195 exit(1);
196 rflag = 0;
197 } else {
198 perror("couldn't get PPP compression stats");
199 exit(1);
203 #ifdef __linux__
204 if (creq.stats.c.bytes_out == 0) {
205 creq.stats.c.bytes_out = creq.stats.c.comp_bytes + creq.stats.c.inc_bytes;
206 creq.stats.c.in_count = creq.stats.c.unc_bytes;
208 if (creq.stats.c.bytes_out == 0)
209 creq.stats.c.ratio = 0.0;
210 else
211 creq.stats.c.ratio = 256.0 * creq.stats.c.in_count /
212 creq.stats.c.bytes_out;
214 if (creq.stats.d.bytes_out == 0) {
215 creq.stats.d.bytes_out = creq.stats.d.comp_bytes + creq.stats.d.inc_bytes;
216 creq.stats.d.in_count = creq.stats.d.unc_bytes;
218 if (creq.stats.d.bytes_out == 0)
219 creq.stats.d.ratio = 0.0;
220 else
221 creq.stats.d.ratio = 256.0 * creq.stats.d.in_count /
222 creq.stats.d.bytes_out;
223 #endif
225 *csp = creq.stats;
228 #else /* STREAMS */
231 strioctl(fd, cmd, ptr, ilen, olen)
232 int fd, cmd, ilen, olen;
233 char *ptr;
235 struct strioctl str;
237 str.ic_cmd = cmd;
238 str.ic_timout = 0;
239 str.ic_len = ilen;
240 str.ic_dp = ptr;
241 if (ioctl(fd, I_STR, &str) == -1)
242 return -1;
243 if (str.ic_len != olen)
244 fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
245 olen, str.ic_len, cmd);
246 return 0;
249 static void
250 get_ppp_stats(curp)
251 struct ppp_stats *curp;
253 if (strioctl(s, PPPIO_GETSTAT, curp, 0, sizeof(*curp)) < 0) {
254 fprintf(stderr, "%s: ", progname);
255 if (errno == EINVAL)
256 fprintf(stderr, "kernel support missing\n");
257 else
258 perror("couldn't get PPP statistics");
259 exit(1);
263 static void
264 get_ppp_cstats(csp)
265 struct ppp_comp_stats *csp;
267 if (strioctl(s, PPPIO_GETCSTAT, csp, 0, sizeof(*csp)) < 0) {
268 fprintf(stderr, "%s: ", progname);
269 if (errno == ENOTTY) {
270 fprintf(stderr, "no kernel compression support\n");
271 if (zflag)
272 exit(1);
273 rflag = 0;
274 } else {
275 perror("couldn't get PPP compression statistics");
276 exit(1);
281 #endif /* STREAMS */
283 #define MAX0(a) ((int)(a) > 0? (a): 0)
284 #define V(offset) MAX0(cur.offset - old.offset)
285 #define W(offset) MAX0(ccs.offset - ocs.offset)
287 #define RATIO(c, i, u) ((c) == 0? 1.0: (u) / ((double)(c) + (i)))
288 #define CRATE(x) RATIO(W(x.comp_bytes), W(x.inc_bytes), W(x.unc_bytes))
290 #define KBPS(n) ((n) / (interval * 1000.0))
293 * Print a running summary of interface statistics.
294 * Repeat display every interval seconds, showing statistics
295 * collected over that interval. Assumes that interval is non-zero.
296 * First line printed is cumulative.
298 static void
299 intpr()
301 register int line = 0;
302 sigset_t oldmask, mask;
303 char *bunit;
304 int ratef = 0;
305 struct ppp_stats cur, old;
306 struct ppp_comp_stats ccs, ocs;
308 memset(&ccs, 0, sizeof(ccs)); /* XXX gcc */
309 memset(&old, 0, sizeof(old));
310 memset(&ocs, 0, sizeof(ocs));
312 while (1) {
313 get_ppp_stats(&cur);
314 if (zflag || rflag)
315 get_ppp_cstats(&ccs);
317 (void)signal(SIGALRM, catchalarm);
318 signalled = 0;
319 (void)alarm(interval);
321 if ((line % 20) == 0) {
322 if (zflag) {
323 printf("IN: COMPRESSED INCOMPRESSIBLE COMP | ");
324 printf("OUT: COMPRESSED INCOMPRESSIBLE COMP\n");
325 bunit = dflag? "KB/S": "BYTE";
326 printf(" %s PACK %s PACK RATIO | ", bunit, bunit);
327 printf(" %s PACK %s PACK RATIO", bunit, bunit);
328 } else {
329 printf("%8.8s %6.6s %6.6s",
330 "IN", "PACK", "VJCOMP");
332 if (!rflag)
333 printf(" %6.6s %6.6s", "VJUNC", "VJERR");
334 if (vflag)
335 printf(" %6.6s %6.6s", "VJTOSS", "NON-VJ");
336 if (rflag)
337 printf(" %6.6s %6.6s", "RATIO", "UBYTE");
338 printf(" | %8.8s %6.6s %6.6s",
339 "OUT", "PACK", "VJCOMP");
341 if (!rflag)
342 printf(" %6.6s %6.6s", "VJUNC", "NON-VJ");
343 if (vflag)
344 printf(" %6.6s %6.6s", "VJSRCH", "VJMISS");
345 if (rflag)
346 printf(" %6.6s %6.6s", "RATIO", "UBYTE");
348 putchar('\n');
351 if (zflag) {
352 if (ratef) {
353 printf("%8.3f %6u %8.3f %6u %6.2f",
354 KBPS(W(d.comp_bytes)),
355 W(d.comp_packets),
356 KBPS(W(d.inc_bytes)),
357 W(d.inc_packets),
358 ccs.d.ratio / 256.0);
359 printf(" | %8.3f %6u %8.3f %6u %6.2f",
360 KBPS(W(c.comp_bytes)),
361 W(c.comp_packets),
362 KBPS(W(c.inc_bytes)),
363 W(c.inc_packets),
364 ccs.c.ratio / 256.0);
365 } else {
366 printf("%8u %6u %8u %6u %6.2f",
367 W(d.comp_bytes),
368 W(d.comp_packets),
369 W(d.inc_bytes),
370 W(d.inc_packets),
371 ccs.d.ratio / 256.0);
372 printf(" | %8u %6u %8u %6u %6.2f",
373 W(c.comp_bytes),
374 W(c.comp_packets),
375 W(c.inc_bytes),
376 W(c.inc_packets),
377 ccs.c.ratio / 256.0);
380 } else {
381 if (ratef)
382 printf("%8.3f", KBPS(V(p.ppp_ibytes)));
383 else
384 printf("%8u", V(p.ppp_ibytes));
385 printf(" %6u %6u",
386 V(p.ppp_ipackets),
387 V(vj.vjs_compressedin));
388 if (!rflag)
389 printf(" %6u %6u",
390 V(vj.vjs_uncompressedin),
391 V(vj.vjs_errorin));
392 if (vflag)
393 printf(" %6u %6u",
394 V(vj.vjs_tossed),
395 V(p.ppp_ipackets) - V(vj.vjs_compressedin)
396 - V(vj.vjs_uncompressedin) - V(vj.vjs_errorin));
397 if (rflag) {
398 printf(" %6.2f ", CRATE(d));
399 if (ratef)
400 printf("%6.2f", KBPS(W(d.unc_bytes)));
401 else
402 printf("%6u", W(d.unc_bytes));
404 if (ratef)
405 printf(" | %8.3f", KBPS(V(p.ppp_obytes)));
406 else
407 printf(" | %8u", V(p.ppp_obytes));
408 printf(" %6u %6u",
409 V(p.ppp_opackets),
410 V(vj.vjs_compressed));
411 if (!rflag)
412 printf(" %6u %6u",
413 V(vj.vjs_packets) - V(vj.vjs_compressed),
414 V(p.ppp_opackets) - V(vj.vjs_packets));
415 if (vflag)
416 printf(" %6u %6u",
417 V(vj.vjs_searches),
418 V(vj.vjs_misses));
419 if (rflag) {
420 printf(" %6.2f ", CRATE(c));
421 if (ratef)
422 printf("%6.2f", KBPS(W(c.unc_bytes)));
423 else
424 printf("%6u", W(c.unc_bytes));
429 putchar('\n');
430 fflush(stdout);
431 line++;
433 count--;
434 if (!infinite && !count)
435 break;
437 sigemptyset(&mask);
438 sigaddset(&mask, SIGALRM);
439 sigprocmask(SIG_BLOCK, &mask, &oldmask);
440 if (!signalled) {
441 sigemptyset(&mask);
442 sigsuspend(&mask);
444 sigprocmask(SIG_SETMASK, &oldmask, NULL);
445 signalled = 0;
446 (void)alarm(interval);
448 if (!aflag) {
449 old = cur;
450 ocs = ccs;
451 ratef = dflag;
457 main(argc, argv)
458 int argc;
459 char *argv[];
461 int c;
462 #ifdef STREAMS
463 char *dev;
464 #endif
465 const char *fmt;
467 if ((progname = strrchr(argv[0], '/')) == NULL)
468 progname = argv[0];
469 else
470 ++progname;
472 if (strncmp(progname, SL_DRV_NAME, sizeof(SL_DRV_NAME) - 1) == 0) {
473 interface = SL_DRV_NAME "0";
474 fmt = SL_DRV_NAME "%d";
475 } else {
476 interface = PPP_DRV_NAME "0";
477 fmt = PPP_DRV_NAME "%d";
480 while ((c = getopt(argc, argv, "advrzc:w:")) != -1) {
481 switch (c) {
482 case 'a':
483 ++aflag;
484 break;
485 case 'd':
486 ++dflag;
487 break;
488 case 'v':
489 ++vflag;
490 break;
491 case 'r':
492 ++rflag;
493 break;
494 case 'z':
495 ++zflag;
496 break;
497 case 'c':
498 count = atoi(optarg);
499 if (count <= 0)
500 usage();
501 break;
502 case 'w':
503 interval = atoi(optarg);
504 if (interval <= 0)
505 usage();
506 break;
507 default:
508 usage();
511 argc -= optind;
512 argv += optind;
514 if (!interval && count)
515 interval = 5;
516 if (interval && !count)
517 infinite = 1;
518 if (!interval && !count)
519 count = 1;
520 if (aflag)
521 dflag = 0;
523 if (argc > 1)
524 usage();
525 if (argc > 0)
526 interface = argv[0];
528 if (sscanf(interface, fmt, &unit) != 1) {
529 fprintf(stderr, "%s: invalid interface '%s' specified\n",
530 progname, interface);
533 #ifndef STREAMS
535 struct ifreq ifr;
537 s = socket(AF_INET, SOCK_DGRAM, 0);
538 if (s < 0) {
539 fprintf(stderr, "%s: ", progname);
540 perror("couldn't create IP socket");
541 exit(1);
544 #ifdef __linux__
545 #undef ifr_name
546 #define ifr_name ifr_ifrn.ifrn_name
547 #endif
548 strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
549 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
550 fprintf(stderr, "%s: nonexistent interface '%s' specified\n",
551 progname, interface);
552 exit(1);
556 #else /* STREAMS */
557 #ifdef __osf__
558 dev = "/dev/streams/ppp";
559 #else
560 dev = "/dev/" PPP_DRV_NAME;
561 #endif
562 if ((s = open(dev, O_RDONLY)) < 0) {
563 fprintf(stderr, "%s: couldn't open ", progname);
564 perror(dev);
565 exit(1);
567 if (strioctl(s, PPPIO_ATTACH, &unit, sizeof(int), 0) < 0) {
568 fprintf(stderr, "%s: ppp%d is not available\n", progname, unit);
569 exit(1);
572 #endif /* STREAMS */
574 intpr();
575 exit(0);