wmclockmon: update change-log
[dockapps.git] / wmnet / drivers.c
blob4b798e7be95aa6340b699c62e3bae5787f8d4a10
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 char *ptr;
320 unsigned int flag = 0;
321 static char interface[16];
322 rx = False;
323 tx = False;
326 if ((dev = fopen("/proc/net/dev", "r")) == NULL) {
327 fprintf(stderr, "/proc/net/dev does not exist?\n"
328 "Perhaps we are not running Linux?\n");
329 exit(4);
331 /* the first two lines we can skip */
332 fgets(buffer, 256, dev);
333 fgets(buffer, 256, dev);
335 /* IP Chain Rules for Linux kernel 2_1.x */
336 while(flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND) && fgets(buffer, 256, dev)) {
338 sscanf(buffer, "%16s %llu %llu %*d %*d %*d %*d %*d %*d %llu %llu %*d %*d %*d %*d %*d %*d",
339 interface, &totalbytes_in, &totalpackets_in, &totalbytes_out, &totalpackets_out);
341 /* strip trailing colon */
342 ptr = interface;
343 while(*ptr != ':') ptr++;
344 *ptr = '\0';
346 if (!strcmp(interface, device)) {
348 flag = (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND);
350 if (totalpackets_in != lastpackets_in) {
351 diffbytes_in += totalbytes_in - lastbytes_in;
352 lastpackets_in = totalpackets_in;
353 lastbytes_in = totalbytes_in;
354 rx = True;
357 if (totalpackets_out != lastpackets_out) {
358 diffbytes_out += totalbytes_out - lastbytes_out;
359 lastpackets_out = totalpackets_out;
360 lastbytes_out = totalbytes_out;
361 tx = True;
366 fclose(dev);
368 /* return True if no change to tx/rx
369 * return False if display will need to be updated
371 return((rx == current_rx) && (tx == current_tx));
374 int dev_test(void) {
375 int devfd;
376 if((devfd = open("/proc/net/dev", O_RDONLY)) == -1) return False;
377 read(devfd, buffer, 36);
378 if(buffer[35] == '|') return False;
379 if(device == NULL) device = "eth0";
380 fprintf(stderr, "wmnet: using devstats driver to monitor %s\n", device);
381 return True;
384 #endif /* USE_2_1_DEV */
386 #ifdef USE_LINUX_PPP
387 int ppp_test(void) {
388 pppfd = socket(AF_INET, SOCK_DGRAM, 0);
389 if(device == NULL) device = "ppp0";
390 strncpy(ppp_stats_req.ifr__name, device, 15);
391 ppp_stats_req.stats_ptr =(caddr_t) &ppp_stats_req.stats;
392 fprintf(stderr, "wmnet: using pppstats driver to monitor %s\n", device);
393 return True;
397 int updateStats_ppp(void) {
398 if(ioctl(pppfd, SIOCGPPPSTATS, &ppp_stats_req) != 0) {
399 return False;
401 totalpackets_in = ppp_stats_req.stats.p.ppp_ipackets;
402 if (totalpackets_in != lastpackets_in) {
403 totalbytes_in = ppp_stats_req.stats.p.ppp_ibytes;
404 diffbytes_in += totalbytes_in - lastbytes_in;
405 lastpackets_in = totalpackets_in;
406 lastbytes_in = totalbytes_in;
407 rx = True;
411 totalpackets_out = ppp_stats_req.stats.p.ppp_opackets;
412 if (totalpackets_out != lastpackets_out) {
413 totalbytes_out =ppp_stats_req.stats.p.ppp_obytes;
414 diffbytes_out += totalbytes_out - lastbytes_out;
415 lastpackets_out = totalpackets_out;
416 lastbytes_out = totalbytes_out;
417 tx = True;
420 /* return True if no change to tx/rx
421 * return False if display will need to be updated
423 return((rx == current_rx) && (tx == current_tx));
428 #endif /* USE_LINUX_PPP */
431 #endif /* linux */
433 #ifdef USE_KVM
434 int kvm_test(void) {
435 if (((kvmfd = kvm_open(NULL, NULL, NULL, O_RDONLY, buffer)) == NULL) ||
436 (kvm_nlist(kvmfd, symbols) < 0) ||
437 kvm_read(kvmfd, (unsigned long)symbols[0].n_value, &ifnet_savedaddr, sizeof(unsigned long)) == -1 ) return False;
438 if(device == NULL) device = "ec0";
439 fprintf(stderr, "wmnet: using kmem driver to monitor %s\n", device);
440 return True;
443 int kvm_updateStats(void) {
444 struct ifnet * ifnet = (struct ifnet *)buffer;
445 unsigned long ifnet_addr = ifnet_savedaddr;
446 char devname[16];
447 int flag = 0;
448 while (ifnet_addr && flag != (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND)) {
449 kvm_read(kvmfd, ifnet_addr, buffer, sizeof(struct ifnet));
450 #ifdef __OpenBSD__
451 snprintf(devname, 15, "%s", ifnet->if_xname);
452 #else
453 kvm_read(kvmfd, (unsigned long)ifnet->if_name, devname, 15);
454 snprintf(devname, 15, "%s%d", devname, ifnet->if_unit);
455 #endif
456 if(!strncmp(devname, device, strlen(device))) { /* we found our struct */
457 totalpackets_in =ifnet->if_ipackets;
458 if (totalpackets_in != lastpackets_in) {
459 totalbytes_in = ifnet->if_ibytes;
460 diffpackets_in += totalpackets_in - lastpackets_in;
461 diffbytes_in += totalbytes_in - lastbytes_in;
462 lastpackets_in = totalpackets_in;
463 lastbytes_in = totalbytes_in;
464 rx = True;
468 totalpackets_out = ifnet->if_opackets;
469 if (totalpackets_out != lastpackets_out) {
470 totalbytes_out =ifnet->if_obytes;
471 diffpackets_out += totalpackets_out - lastpackets_out;
472 diffbytes_out += totalbytes_out - lastbytes_out;
473 lastpackets_out = totalpackets_out;
474 lastbytes_out = totalbytes_out;
475 tx = True;
477 flag = (ACCOUNT_IN_FOUND|ACCOUNT_OUT_FOUND);
479 } else {
480 #ifdef __OpenBSD__
481 ifnet_addr = (unsigned long)ifnet->if_list.tqe_next;
482 #else
483 ifnet_addr = (unsigned long)ifnet->if_next;
484 #endif
488 /* return True if no change to tx/rx
489 * return False if display will need to be updated
491 return((rx == current_rx) && (tx == current_tx));
495 #endif