wmbiff: Use unsigned data type for port number.
[dockapps.git] / wmnet / drivers.c
bloba6ab0a0b6979e035c1eab0ae71fc1e5e45485d07
1 /* wmnet -- X IP accounting monitor
2 * Copyright 1998 Jesse B. Off <joff@iastate.edu>
4 * $Id: drivers.c,v 1.1 1998/10/07 03:42:21 joff Exp joff $
6 * This software is released under the GNU Public License agreement.
7 * No warranties, whatever.... you know the usuals.... this is free
8 * software. if you use it, great... if you wanna make a change to it,
9 * great, but please send me the diff.
12 #include<stdlib.h>
13 #include<stdio.h>
14 #include<string.h>
15 #include<X11/Xlib.h>
16 #include<fcntl.h>
17 #include<sys/types.h>
18 #include<sys/stat.h>
19 #include<sys/socket.h>
20 #include<unistd.h>
21 #include"config.h"
24 /* For FreeBSD */
25 #ifdef USE_KVM
26 #include<net/if.h>
27 #include<kvm.h>
28 #include<nlist.h>
30 kvm_t *kvmfd;
31 struct nlist symbols[] = {
32 { "_ifnet" },
33 { NULL }
35 unsigned long ifnet_savedaddr;
36 int kvm_test(void);
37 int kvm_updateStats(void);
38 #endif /* USE_KVM */
41 #ifdef USE_LINUX_PPP
42 #include<net/ppp_defs.h>
44 #ifdef linux_libc5
45 # include<linux/if_ppp.h>
46 #else
47 # include<net/if_ppp.h>
48 #endif
50 #include<sys/ioctl.h>
51 int pppfd;
52 int ppp_test(void);
53 int updateStats_ppp(void);
54 static struct ifpppstatsreq ppp_stats_req;
55 #endif
57 #define ACCOUNT_IN_FOUND 1
58 #define ACCOUNT_OUT_FOUND 2
60 extern char buffer[256];
61 extern char *in_rule_string, *out_rule_string, *device;
62 extern unsigned long long int totalbytes_in, totalbytes_out, lastbytes_in, lastbytes_out;
63 extern unsigned long long int totalpackets_in, totalpackets_out, lastpackets_in, lastpackets_out;
64 extern unsigned int diffbytes_in, diffbytes_out;
65 extern unsigned int out_rule, in_rule; /* number of rule in /proc/net/ip_acct to use */
66 extern Bool current_tx, current_rx, rx, tx;
70 char *available_drivers(void);
72 #ifdef USE_IPFWADM
73 int updateStats_ipfwadm(void);
74 int ipfwadm_test(void);
75 #endif
76 #ifdef USE_IPCHAINS
77 int updateStats_ipchains(void);
78 int ipchains_test(void);
79 #endif
80 #ifdef USE_2_1_DEV
81 int updateStats_dev(void);
82 int dev_test(void);
83 #endif
86 typedef int (*parser_func)(void);
87 static struct drivers_struct {
88 char * name;
89 parser_func function;
90 parser_func test;
91 } drivers[] = {
92 #ifdef USE_2_1_DEV
93 {"devstats", updateStats_dev, dev_test},
94 #endif
95 #ifdef USE_IPFWADM
96 {"ipfwadm", updateStats_ipfwadm, ipfwadm_test},
97 #endif
98 #ifdef USE_IPCHAINS
99 {"ipchains", updateStats_ipchains, ipchains_test},
100 #endif
101 #ifdef USE_LINUX_PPP
102 {"pppstats",updateStats_ppp, ppp_test},
103 #endif
104 #ifdef USE_KVM
105 {"kmem",kvm_updateStats, kvm_test},
106 #endif
107 {NULL, NULL}
110 char* available_drivers(void) {
111 int ind = 0;
112 int len = 0;
113 char *string, *ptr;
114 while(drivers[ind].name != NULL) {
115 len += strlen(drivers[ind].name) + 1;
116 ind++;
118 ptr = string = (char *)malloc(len);
119 *string = '\0';
120 ind = 0;
121 while(drivers[ind].name != NULL) {
122 strcpy(string, drivers[ind].name);
123 string += strlen(drivers[ind].name);
124 *string++ = ',';
125 ind++;
127 *(--string) = '\0';
128 return ptr;
133 parser_func find_driver(void) {
134 int ind = 0;
135 while(drivers[ind].name != NULL) {
136 if(drivers[ind].test()) {
137 return drivers[ind].function;
139 ind++;
141 fprintf(stderr, "wmnet: no appropriate stat driver found\n");
142 exit(30);
146 parser_func setup_driver(char * parser_name) {
147 int ind = 0;
148 if (parser_name == NULL) return find_driver();
149 while(drivers[ind].name != NULL) {
150 if(!strcmp(parser_name, drivers[ind].name)) {
151 if (drivers[ind].test()) return drivers[ind].function;
152 fprintf(stderr, "wmnet: driver %s not appropriate for this machine\n", parser_name);
153 exit(18);
155 ind++;
157 fprintf(stderr, "wmnet: no driver %s\n", parser_name);
158 exit(18);
164 #ifdef linux
165 /* All the data gathering is done in here.
166 * Return True if no change to tx/rx.
167 * Return False if display will need to be updated.
169 #ifdef USE_IPFWADM
170 int ipfwadm_test(void) {
171 if(open("/proc/net/ip_acct", O_RDONLY) == -1) return False;
172 fprintf(stderr, "wmnet: using ipfwadm driver to monitor accounting rules %d and %d\n", in_rule, out_rule);
173 return True;
176 int updateStats_ipfwadm(void) {
177 FILE *ip_acct;
178 unsigned int flag = 0, lineno = 0;
179 unsigned int offset = 37;
180 char *ptr;
181 rx = False;
182 tx = False;
185 if ((ip_acct = fopen("/proc/net/ip_acct", "r")) == NULL) {
186 fprintf(stderr, "wmnet: /proc/net/ip_acct unavailable\n"
187 "You either don't have IP accounting compiled in, or this isn't a 2.0 linux kernel.\n");
188 exit(4);
191 /* IP Accounting Rules for 2.0.x linux kernels*/
192 while(flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND) && fgets(buffer, 256, ip_acct)) {
193 switch(lineno == out_rule ? ACCOUNT_OUT_FOUND : ( lineno == in_rule ? ACCOUNT_IN_FOUND : -1 ) ) {
194 case ACCOUNT_IN_FOUND:
195 /* accounting in */
196 flag |= ACCOUNT_IN_FOUND;
197 while(buffer[offset++] != ' ');
198 offset += 18;
199 totalpackets_in = strtoul(&buffer[offset], &ptr, 10);
200 if (totalpackets_in == lastpackets_in) break;
201 totalbytes_in = strtoul(ptr, NULL, 10);
202 diffbytes_in += totalbytes_in - lastbytes_in;
203 lastpackets_in = totalpackets_in;
204 lastbytes_in = totalbytes_in;
205 rx = True;
206 break;
207 case ACCOUNT_OUT_FOUND:
208 /* accounting out */
209 flag |= ACCOUNT_OUT_FOUND;
210 while(buffer[offset++] != ' ');
211 offset += 18;
212 totalpackets_out = strtoul(&buffer[offset], &ptr, 10);
213 if (totalpackets_out == lastpackets_out) break;
214 totalbytes_out = strtoul(ptr, NULL, 10);
215 diffbytes_out += totalbytes_out - lastbytes_out;
216 lastpackets_out = totalpackets_out;
217 lastbytes_out = totalbytes_out;
218 tx = True;
219 break;
221 lineno++;
222 offset = 37;
225 if(flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND)) {
226 fprintf(stderr,"wmnet: couldn't find %s accounting rule to monitor in /proc/net/ip_acct\n",
227 (flag == ACCOUNT_IN_FOUND) ? "the TX" : ((flag == ACCOUNT_OUT_FOUND) ? "the RX" : "a single"));
228 exit(4);
230 fclose(ip_acct);
232 /* return True if no change to tx/rx
233 * return False if display will need to be updated
235 return((rx == current_rx) && (tx == current_tx));
238 #endif /* USE_IPFWADM */
240 #ifdef USE_IPCHAINS
241 int ipchains_test(void) {
242 if (open("/proc/net/ip_fwchains",O_RDONLY) == -1) return False;
243 if (in_rule_string == NULL) in_rule_string = "acctin";
244 if (out_rule_string == NULL) out_rule_string = "acctout";
245 fprintf(stderr, "wmnet: using ipchains driver to monitor chains %s and %s\n", in_rule_string, out_rule_string);
246 return True;
249 /* ipchains parser mostly from Bjoern Kriews <bkr@cut.de> */
250 int updateStats_ipchains(void) {
251 FILE *ip_acct;
252 unsigned int flag = 0;
253 static char name[32];
254 unsigned long pack, bytes;
255 rx = False;
256 tx = False;
259 if ((ip_acct = fopen("/proc/net/ip_fwchains", "r")) == NULL) {
260 fprintf(stderr, "/proc/net/ip_fwchains does not exist?\n"
261 "Do you have IP accounting in your kernel?\n");
262 exit(4);
265 /* IP Chain Rules for Linux kernel 2_1.x */
266 while(flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND) && fgets(buffer, 256, ip_acct)) {
267 *name = 0;
269 sscanf(buffer, "%30s %*s - %*d %*d %*d %*d %lu %*d %lu",
270 name, &pack, &bytes);
273 if(strcmp(name, in_rule_string) == 0) {
274 flag |= ACCOUNT_IN_FOUND;
276 totalpackets_in = pack;
277 if (totalpackets_in != lastpackets_in) {
278 totalbytes_in = bytes;
279 diffbytes_in += totalbytes_in - lastbytes_in;
280 lastpackets_in = totalpackets_in;
281 lastbytes_in = totalbytes_in;
282 rx = True;
285 } else if (strcmp(name, out_rule_string) == 0) {
286 flag |= ACCOUNT_OUT_FOUND;
288 totalpackets_out = pack;
289 if (totalpackets_out != lastpackets_out) {
290 totalbytes_out = bytes;
291 diffbytes_out += totalbytes_out - lastbytes_out;
292 lastpackets_out = totalpackets_out;
293 lastbytes_out = totalbytes_out;
294 tx = True;
299 if(flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND)) {
300 fprintf(stderr,"I couldn't find %s IP chain to monitor in /proc/net/ip_fwchains.\n",
301 (flag == ACCOUNT_IN_FOUND) ? "the TX" : ((flag == ACCOUNT_OUT_FOUND) ? "the RX" : "a single"));
302 exit(4);
304 fclose(ip_acct);
306 /* return True if no change to tx/rx
307 * return False if display will need to be updated
309 return((rx == current_rx) && (tx == current_tx));
312 #endif /* USE_IPCHAINS */
315 #ifdef USE_2_1_DEV
317 int updateStats_dev(void) {
318 FILE *dev;
319 rx = False;
320 tx = False;
322 dev = fopen("/proc/net/dev", "r");
323 if (!dev) {
324 fprintf(stderr, "/proc/net/dev does not exist\n");
325 exit(4);
328 /* the first two lines we can skip */
329 fgets(buffer, 256, dev);
330 fgets(buffer, 256, dev);
332 while(fgets(buffer, 256, dev)) {
334 if (strcmp(buffer, device) > 0){
336 sscanf(buffer, "%*s %llu %llu %*d %*d %*d %*d %*d %*d %llu %llu %*d %*d %*d %*d %*d %*d",
337 &totalbytes_in, &totalpackets_in, &totalbytes_out, &totalpackets_out);
339 if (totalpackets_in != lastpackets_in) {
340 diffbytes_in += totalbytes_in - lastbytes_in;
341 lastpackets_in = totalpackets_in;
342 lastbytes_in = totalbytes_in;
343 rx = True;
346 if (totalpackets_out != lastpackets_out) {
347 diffbytes_out += totalbytes_out - lastbytes_out;
348 lastpackets_out = totalpackets_out;
349 lastbytes_out = totalbytes_out;
350 tx = True;
353 break;
357 fclose(dev);
359 /* return True if no change to tx/rx
360 * return False if display will need to be updated
362 return((rx == current_rx) && (tx == current_tx));
365 int dev_test(void) {
366 int devfd;
367 if((devfd = open("/proc/net/dev", O_RDONLY)) == -1) return False;
368 read(devfd, buffer, 36);
369 if(buffer[35] == '|') return False;
370 if(device == NULL) device = "eth0";
371 fprintf(stderr, "wmnet: using devstats driver to monitor %s\n", device);
372 return True;
375 #endif /* USE_2_1_DEV */
377 #ifdef USE_LINUX_PPP
378 int ppp_test(void) {
379 pppfd = socket(AF_INET, SOCK_DGRAM, 0);
380 if(device == NULL) device = "ppp0";
381 strncpy(ppp_stats_req.ifr__name, device, 15);
382 ppp_stats_req.stats_ptr =(caddr_t) &ppp_stats_req.stats;
383 fprintf(stderr, "wmnet: using pppstats driver to monitor %s\n", device);
384 return True;
388 int updateStats_ppp(void) {
389 if(ioctl(pppfd, SIOCGPPPSTATS, &ppp_stats_req) != 0) {
390 return False;
392 totalpackets_in = ppp_stats_req.stats.p.ppp_ipackets;
393 if (totalpackets_in != lastpackets_in) {
394 totalbytes_in = ppp_stats_req.stats.p.ppp_ibytes;
395 diffbytes_in += totalbytes_in - lastbytes_in;
396 lastpackets_in = totalpackets_in;
397 lastbytes_in = totalbytes_in;
398 rx = True;
402 totalpackets_out = ppp_stats_req.stats.p.ppp_opackets;
403 if (totalpackets_out != lastpackets_out) {
404 totalbytes_out =ppp_stats_req.stats.p.ppp_obytes;
405 diffbytes_out += totalbytes_out - lastbytes_out;
406 lastpackets_out = totalpackets_out;
407 lastbytes_out = totalbytes_out;
408 tx = True;
411 /* return True if no change to tx/rx
412 * return False if display will need to be updated
414 return((rx == current_rx) && (tx == current_tx));
419 #endif /* USE_LINUX_PPP */
422 #endif /* linux */
424 #ifdef USE_KVM
425 int kvm_test(void) {
426 if (((kvmfd = kvm_open(NULL, NULL, NULL, O_RDONLY, buffer)) == NULL) ||
427 (kvm_nlist(kvmfd, symbols) < 0) ||
428 kvm_read(kvmfd, (unsigned long)symbols[0].n_value, &ifnet_savedaddr, sizeof(unsigned long)) == -1 ) return False;
429 if(device == NULL) device = "ec0";
430 fprintf(stderr, "wmnet: using kmem driver to monitor %s\n", device);
431 return True;
434 int kvm_updateStats(void) {
435 struct ifnet * ifnet = (struct ifnet *)buffer;
436 unsigned long ifnet_addr = ifnet_savedaddr;
437 char devname[16];
438 int flag = 0;
439 while (ifnet_addr && flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND)) {
440 kvm_read(kvmfd, ifnet_addr, buffer, sizeof(struct ifnet));
441 #ifdef __OpenBSD__
442 snprintf(devname, 15, "%s", ifnet->if_xname);
443 #else
444 kvm_read(kvmfd, (unsigned long)ifnet->if_name, devname, 15);
445 snprintf(devname, 15, "%s%d", devname, ifnet->if_unit);
446 #endif
447 if(!strncmp(devname, device, strlen(device))) { /* we found our struct */
448 totalpackets_in =ifnet->if_ipackets;
449 if (totalpackets_in != lastpackets_in) {
450 totalbytes_in = ifnet->if_ibytes;
451 diffpackets_in += totalpackets_in - lastpackets_in;
452 diffbytes_in += totalbytes_in - lastbytes_in;
453 lastpackets_in = totalpackets_in;
454 lastbytes_in = totalbytes_in;
455 rx = True;
459 totalpackets_out = ifnet->if_opackets;
460 if (totalpackets_out != lastpackets_out) {
461 totalbytes_out =ifnet->if_obytes;
462 diffpackets_out += totalpackets_out - lastpackets_out;
463 diffbytes_out += totalbytes_out - lastbytes_out;
464 lastpackets_out = totalpackets_out;
465 lastbytes_out = totalbytes_out;
466 tx = True;
468 flag = (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND);
470 } else {
471 #ifdef __OpenBSD__
472 ifnet_addr = (unsigned long)ifnet->if_list.tqe_next;
473 #else
474 ifnet_addr = (unsigned long)ifnet->if_next;
475 #endif
479 /* return True if no change to tx/rx
480 * return False if display will need to be updated
482 return((rx == current_rx) && (tx == current_tx));
486 #endif