mods & restructuring to support Solaris 2
[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.9 1995/06/01 02:23:39 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     sprintf(req.ifr_name, "ppp%d", unit);
293     if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
294         if (errno == ENOTTY)
295             fprintf(stderr, "pppstats: kernel support missing\n");
296         else
297             perror("ioctl(SIOCGPPPSTATS)");
298         exit(1);
299     }
300     *curp = req.stats;
301 }
302
303 get_ppp_cstats(csp)
304     struct ppp_comp_stats *csp;
305 {
306     struct ifpppcstatsreq creq;
307
308     sprintf(creq.ifr_name, "ppp%d", unit);
309     if (ioctl(s, SIOCGPPPCSTATS, &creq) < 0) {
310         if (errno == ENOTTY) {
311             fprintf(stderr, "pppstats: no kernel compression support\n");
312             if (cflag)
313                 exit(1);
314             rflag = 0;
315         } else {
316             perror("ioctl(SIOCGPPPCSTATS)");
317             exit(1);
318         }
319     }
320     *csp = creq.stats;
321 }
322
323 #else   /* __svr4__ */
324 get_ppp_stats(curp)
325     struct ppp_stats *curp;
326 {
327     if (strioctl(s, PPPIO_GETSTAT, curp, 0, sizeof(*curp)) < 0) {
328         if (errno == EINVAL)
329             fprintf(stderr, "pppstats: kernel support missing\n");
330         else
331             perror("pppstats: Couldn't get statistics");
332         exit(1);
333     }
334 }
335
336 get_ppp_cstats(csp)
337     struct ppp_comp_stats *csp;
338 {
339     if (strioctl(s, PPPIO_GETCSTAT, csp, 0, sizeof(*csp)) < 0) {
340         if (errno == ENOTTY) {
341             fprintf(stderr, "pppstats: no kernel compression support\n");
342             if (cflag)
343                 exit(1);
344             rflag = 0;
345         } else {
346             perror("pppstats: Couldn't get compression statistics");
347             exit(1);
348         }
349     }
350 }
351
352 int
353 strioctl(fd, cmd, ptr, ilen, olen)
354     int fd, cmd, ilen, olen;
355     char *ptr;
356 {
357     struct strioctl str;
358
359     str.ic_cmd = cmd;
360     str.ic_timout = 0;
361     str.ic_len = ilen;
362     str.ic_dp = ptr;
363     if (ioctl(fd, I_STR, &str) == -1)
364         return -1;
365     if (str.ic_len != olen)
366         fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
367                olen, str.ic_len, cmd);
368     return 0;
369 }
370 #endif /* __svr4__ */