Enable classic mode.
[dockapps.git] / wmnet / drivers.c
blob2064bf65ee45b38148e1fed2ed78195e8b718a74
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 $
5 *
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 totalbytes_in, totalbytes_out, lastbytes_in, lastbytes_out;
63 extern unsigned long totalpackets_in, totalpackets_out, lastpackets_in, lastpackets_out;
64 extern unsigned int diffpackets_in, diffpackets_out, 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 diffpackets_in += totalpackets_in - lastpackets_in;
203 diffbytes_in += totalbytes_in - lastbytes_in;
204 lastpackets_in = totalpackets_in;
205 lastbytes_in = totalbytes_in;
206 rx = True;
207 break;
208 case ACCOUNT_OUT_FOUND:
209 /* accounting out */
210 flag |= ACCOUNT_OUT_FOUND;
211 while(buffer[offset++] != ' ');
212 offset += 18;
213 totalpackets_out = strtoul(&buffer[offset], &ptr, 10);
214 if (totalpackets_out == lastpackets_out) break;
215 totalbytes_out = strtoul(ptr, NULL, 10);
216 diffpackets_out += totalpackets_out - lastpackets_out;
217 diffbytes_out += totalbytes_out - lastbytes_out;
218 lastpackets_out = totalpackets_out;
219 lastbytes_out = totalbytes_out;
220 tx = True;
221 break;
223 lineno++;
224 offset = 37;
227 if(flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND)) {
228 fprintf(stderr,"wmnet: couldn't find %s accounting rule to monitor in /proc/net/ip_acct\n",
229 (flag == ACCOUNT_IN_FOUND) ? "the TX" : ((flag == ACCOUNT_OUT_FOUND) ? "the RX" : "a single"));
230 exit(4);
232 fclose(ip_acct);
234 /* return True if no change to tx/rx
235 * return False if display will need to be updated
237 return((rx == current_rx) && (tx == current_tx));
240 #endif /* USE_IPFWADM */
242 #ifdef USE_IPCHAINS
243 int ipchains_test(void) {
244 if (open("/proc/net/ip_fwchains",O_RDONLY) == -1) return False;
245 if (in_rule_string == NULL) in_rule_string = "acctin";
246 if (out_rule_string == NULL) out_rule_string = "acctout";
247 fprintf(stderr, "wmnet: using ipchains driver to monitor chains %s and %s\n", in_rule_string, out_rule_string);
248 return True;
251 /* ipchains parser mostly from Bjoern Kriews <bkr@cut.de> */
252 int updateStats_ipchains(void) {
253 FILE *ip_acct;
254 unsigned int flag = 0;
255 static char name[32];
256 unsigned long pack, bytes;
257 rx = False;
258 tx = False;
261 if ((ip_acct = fopen("/proc/net/ip_fwchains", "r")) == NULL) {
262 fprintf(stderr, "/proc/net/ip_fwchains does not exist?\n"
263 "Do you have IP accounting in your kernel?\n");
264 exit(4);
267 /* IP Chain Rules for Linux kernel 2_1.x */
268 while(flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND) && fgets(buffer, 256, ip_acct)) {
269 *name = 0;
271 sscanf(buffer, "%30s %*s - %*d %*d %*d %*d %lu %*d %lu",
272 name, &pack, &bytes);
275 if(strcmp(name, in_rule_string) == 0) {
276 flag |= ACCOUNT_IN_FOUND;
278 totalpackets_in = pack;
279 if (totalpackets_in != lastpackets_in) {
280 totalbytes_in = bytes;
281 diffpackets_in += totalpackets_in - lastpackets_in;
282 diffbytes_in += totalbytes_in - lastbytes_in;
283 lastpackets_in = totalpackets_in;
284 lastbytes_in = totalbytes_in;
285 rx = True;
288 } else if (strcmp(name, out_rule_string) == 0) {
289 flag |= ACCOUNT_OUT_FOUND;
291 totalpackets_out = pack;
292 if (totalpackets_out != lastpackets_out) {
293 totalbytes_out = bytes;
294 diffpackets_out += totalpackets_out - lastpackets_out;
295 diffbytes_out += totalbytes_out - lastbytes_out;
296 lastpackets_out = totalpackets_out;
297 lastbytes_out = totalbytes_out;
298 tx = True;
303 if(flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND)) {
304 fprintf(stderr,"I couldn't find %s IP chain to monitor in /proc/net/ip_fwchains.\n",
305 (flag == ACCOUNT_IN_FOUND) ? "the TX" : ((flag == ACCOUNT_OUT_FOUND) ? "the RX" : "a single"));
306 exit(4);
308 fclose(ip_acct);
310 /* return True if no change to tx/rx
311 * return False if display will need to be updated
313 return((rx == current_rx) && (tx == current_tx));
316 #endif /* USE_IPCHAINS */
319 #ifdef USE_2_1_DEV
321 int updateStats_dev(void) {
322 FILE *dev;
323 char *ptr;
324 unsigned int flag = 0;
325 char *name;
326 rx = False;
327 tx = False;
330 if ((dev = fopen("/proc/net/dev", "r")) == NULL) {
331 fprintf(stderr, "/proc/net/dev does not exist?\n"
332 "Perhaps we are not running Linux?\n");
333 exit(4);
335 /* the first two lines we can skip */
336 fgets(buffer, 256, dev);
337 fgets(buffer, 256, dev);
339 /* IP Chain Rules for Linux kernel 2_1.x */
340 while(flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND) && fgets(buffer, 256, dev)) {
341 ptr = buffer;
342 while(*ptr == ' ') ptr++;
343 name = ptr;
344 while(*ptr != ':') ptr++;
345 *ptr = '\0';
347 if (!strcmp(name, device)) {
349 flag = (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND);
351 totalpackets_in = strtoul(&buffer[15], NULL, 10);
352 if (totalpackets_in != lastpackets_in) {
353 totalbytes_in = strtoul(&buffer[7], NULL, 10);
354 diffpackets_in += totalpackets_in - lastpackets_in;
355 diffbytes_in += totalbytes_in - lastbytes_in;
356 lastpackets_in = totalpackets_in;
357 lastbytes_in = totalbytes_in;
358 rx = True;
362 totalpackets_out = strtoul(&buffer[74], NULL, 10);
363 if (totalpackets_out != lastpackets_out) {
364 totalbytes_out = strtoul(&buffer[66], NULL, 10);
365 diffpackets_out += totalpackets_out - lastpackets_out;
366 diffbytes_out += totalbytes_out - lastbytes_out;
367 lastpackets_out = totalpackets_out;
368 lastbytes_out = totalbytes_out;
369 tx = True;
374 fclose(dev);
376 /* return True if no change to tx/rx
377 * return False if display will need to be updated
379 return((rx == current_rx) && (tx == current_tx));
382 int dev_test(void) {
383 int devfd;
384 if((devfd = open("/proc/net/dev", O_RDONLY)) == -1) return False;
385 read(devfd, buffer, 36);
386 if(buffer[35] == '|') return False;
387 if(device == NULL) device = "eth0";
388 fprintf(stderr, "wmnet: using devstats driver to monitor %s\n", device);
389 return True;
392 #endif /* USE_2_1_DEV */
394 #ifdef USE_LINUX_PPP
395 int ppp_test(void) {
396 pppfd = socket(AF_INET, SOCK_DGRAM, 0);
397 if(device == NULL) device = "ppp0";
398 strncpy(ppp_stats_req.ifr__name, device, 15);
399 ppp_stats_req.stats_ptr =(caddr_t) &ppp_stats_req.stats;
400 fprintf(stderr, "wmnet: using pppstats driver to monitor %s\n", device);
401 return True;
405 int updateStats_ppp(void) {
406 if(ioctl(pppfd, SIOCGPPPSTATS, &ppp_stats_req) != 0) {
407 return False;
409 totalpackets_in = ppp_stats_req.stats.p.ppp_ipackets;
410 if (totalpackets_in != lastpackets_in) {
411 totalbytes_in = ppp_stats_req.stats.p.ppp_ibytes;
412 diffpackets_in += totalpackets_in - lastpackets_in;
413 diffbytes_in += totalbytes_in - lastbytes_in;
414 lastpackets_in = totalpackets_in;
415 lastbytes_in = totalbytes_in;
416 rx = True;
420 totalpackets_out = ppp_stats_req.stats.p.ppp_opackets;
421 if (totalpackets_out != lastpackets_out) {
422 totalbytes_out =ppp_stats_req.stats.p.ppp_obytes;
423 diffpackets_out += totalpackets_out - lastpackets_out;
424 diffbytes_out += totalbytes_out - lastbytes_out;
425 lastpackets_out = totalpackets_out;
426 lastbytes_out = totalbytes_out;
427 tx = True;
430 /* return True if no change to tx/rx
431 * return False if display will need to be updated
433 return((rx == current_rx) && (tx == current_tx));
438 #endif /* USE_LINUX_PPP */
441 #endif /* linux */
443 #ifdef USE_KVM
444 int kvm_test(void) {
445 if (((kvmfd = kvm_open(NULL, NULL, NULL, O_RDONLY, buffer)) == NULL) ||
446 (kvm_nlist(kvmfd, symbols) < 0) ||
447 kvm_read(kvmfd, (unsigned long)symbols[0].n_value, &ifnet_savedaddr, sizeof(unsigned long)) == -1 ) return False;
448 if(device == NULL) device = "ec0";
449 fprintf(stderr, "wmnet: using kmem driver to monitor %s\n", device);
450 return True;
453 int kvm_updateStats(void) {
454 struct ifnet * ifnet = (struct ifnet *)buffer;
455 unsigned long ifnet_addr = ifnet_savedaddr;
456 char devname[16];
457 int flag = 0;
458 while (ifnet_addr && flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND)) {
459 kvm_read(kvmfd, ifnet_addr, buffer, sizeof(struct ifnet));
460 #ifdef __OpenBSD__
461 snprintf(devname, 15, "%s", ifnet->if_xname);
462 #else
463 kvm_read(kvmfd, (unsigned long)ifnet->if_name, devname, 15);
464 snprintf(devname, 15, "%s%d", devname, ifnet->if_unit);
465 #endif
466 if(!strncmp(devname, device, strlen(device))) { /* we found our struct */
467 totalpackets_in =ifnet->if_ipackets;
468 if (totalpackets_in != lastpackets_in) {
469 totalbytes_in = ifnet->if_ibytes;
470 diffpackets_in += totalpackets_in - lastpackets_in;
471 diffbytes_in += totalbytes_in - lastbytes_in;
472 lastpackets_in = totalpackets_in;
473 lastbytes_in = totalbytes_in;
474 rx = True;
478 totalpackets_out = ifnet->if_opackets;
479 if (totalpackets_out != lastpackets_out) {
480 totalbytes_out =ifnet->if_obytes;
481 diffpackets_out += totalpackets_out - lastpackets_out;
482 diffbytes_out += totalbytes_out - lastbytes_out;
483 lastpackets_out = totalpackets_out;
484 lastbytes_out = totalbytes_out;
485 tx = True;
487 flag = (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND);
489 } else {
490 #ifdef __OpenBSD__
491 ifnet_addr = (unsigned long)ifnet->if_list.tqe_next;
492 #else
493 ifnet_addr = (unsigned long)ifnet->if_next;
494 #endif
498 /* return True if no change to tx/rx
499 * return False if display will need to be updated
501 return((rx == current_rx) && (tx == current_tx));
505 #endif