ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/network_stats.c
Revision: 1.66
Committed: Wed Apr 7 21:08:40 2004 UTC (20 years, 1 month ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.65: +20 -4 lines
Log Message:
The rest of the error handling stuff (except the vector code).

I've been extremely unimaginative with the string names in error.c, but
they're all in one place so much easier to tidy up. I'm also beginning to
wonder if we actually needed an SG_ERROR_SYSTEM_CALL to indicate some call
into the system failed - because the majority of our errors are those :-)

Still to do, then:
 - vector code
 - better string names in error.c
 - deal with arg string in some way
 - make use of the error status in statgrab/saidar/examples

File Contents

# User Rev Content
1 tdb 1.22 /*
2 tdb 1.64 * i-scream libstatgrab
3 tdb 1.15 * http://www.i-scream.org
4 tdb 1.22 * Copyright (C) 2000-2004 i-scream
5 pajs 1.1 *
6 tdb 1.22 * This library is free software; you can redistribute it and/or
7     * modify it under the terms of the GNU Lesser General Public
8     * License as published by the Free Software Foundation; either
9     * version 2.1 of the License, or (at your option) any later version.
10 pajs 1.1 *
11 tdb 1.22 * This library is distributed in the hope that it will be useful,
12 pajs 1.1 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 tdb 1.22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     * Lesser General Public License for more details.
15 pajs 1.1 *
16 tdb 1.22 * You should have received a copy of the GNU Lesser General Public
17     * License along with this library; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19     * 02111-1307 USA
20 tdb 1.23 *
21 tdb 1.66 * $Id: network_stats.c,v 1.65 2004/04/07 14:53:40 tdb Exp $
22 pajs 1.1 */
23    
24     #ifdef HAVE_CONFIG_H
25     #include "config.h"
26     #endif
27    
28 tdb 1.4 #include <stdlib.h>
29 pajs 1.6 #include <string.h>
30 pajs 1.1 #include "statgrab.h"
31 ats 1.59 #include "vector.h"
32 ats 1.60 #include "tools.h"
33 tdb 1.11 #include <time.h>
34 pajs 1.1 #ifdef SOLARIS
35     #include <kstat.h>
36     #include <sys/sysinfo.h>
37 ats 1.44 #include <sys/types.h>
38     #include <sys/socket.h>
39     #include <sys/ioctl.h>
40     #include <net/if.h>
41     #include <netinet/in.h>
42     #include <sys/sockio.h>
43 tdb 1.61 #include <unistd.h>
44 pajs 1.6 #endif
45     #ifdef LINUX
46     #include <stdio.h>
47     #include <sys/types.h>
48     #include <regex.h>
49 pajs 1.27 #include <sys/ioctl.h>
50     #include <sys/socket.h>
51     #include <net/if.h>
52     #include <ctype.h>
53     /* Stuff which could be defined by defining KERNEL, but
54     * that would be a bad idea, so we'll just declare it here
55     */
56     typedef __uint8_t u8;
57     typedef __uint16_t u16;
58     typedef __uint32_t u32;
59 ats 1.42 typedef __uint64_t u64;
60 pajs 1.27 #include <linux/ethtool.h>
61     #include <linux/sockios.h>
62 ats 1.32 #include <unistd.h>
63 pajs 1.1 #endif
64 ats 1.18 #ifdef ALLBSD
65 pajs 1.14 #include <sys/types.h>
66     #include <sys/socket.h>
67     #include <ifaddrs.h>
68     #include <net/if.h>
69 pajs 1.26 #include <net/if_media.h>
70     #include <sys/ioctl.h>
71 tdb 1.58 #include <unistd.h>
72 pajs 1.14 #endif
73 pajs 1.1
74 ats 1.62 static void network_stat_init(sg_network_io_stats *s) {
75 ats 1.59 s->interface_name = NULL;
76     s->tx = 0;
77     s->rx = 0;
78     s->ipackets = 0;
79     s->opackets = 0;
80     s->ierrors = 0;
81     s->oerrors = 0;
82     s->collisions = 0;
83 pajs 1.3 }
84    
85 ats 1.62 static void network_stat_destroy(sg_network_io_stats *s) {
86 ats 1.59 free(s->interface_name);
87 pajs 1.1 }
88    
89 ats 1.62 VECTOR_DECLARE_STATIC(network_stats, sg_network_io_stats, 5,
90 tdb 1.65 network_stat_init, network_stat_destroy);
91 pajs 1.3
92 ats 1.62 sg_network_io_stats *sg_get_network_io_stats(int *entries){
93 ats 1.59 int interfaces;
94 ats 1.62 sg_network_io_stats *network_stat_ptr;
95 pajs 1.6
96     #ifdef SOLARIS
97 tdb 1.65 kstat_ctl_t *kc;
98     kstat_t *ksp;
99 pajs 1.1 kstat_named_t *knp;
100 pajs 1.6 #endif
101 pajs 1.3
102 pajs 1.6 #ifdef LINUX
103     FILE *f;
104 pajs 1.12 /* Horrible big enough, but it should be easily big enough */
105 pajs 1.6 char line[8096];
106     regex_t regex;
107 ats 1.49 regmatch_t line_match[9];
108 pajs 1.14 #endif
109 ats 1.18 #ifdef ALLBSD
110 pajs 1.14 struct ifaddrs *net, *net_ptr;
111     struct if_data *net_data;
112     #endif
113    
114 ats 1.18 #ifdef ALLBSD
115 pajs 1.14 if(getifaddrs(&net) != 0){
116 tdb 1.66 sg_set_error(SG_ERROR_GETIFADDRS, NULL);
117 pajs 1.14 return NULL;
118     }
119    
120     interfaces=0;
121    
122     for(net_ptr=net;net_ptr!=NULL;net_ptr=net_ptr->ifa_next){
123     if(net_ptr->ifa_addr->sa_family != AF_LINK) continue;
124 ats 1.59
125     if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
126 pajs 1.14 return NULL;
127     }
128     network_stat_ptr=network_stats+interfaces;
129    
130 ats 1.62 if (sg_update_string(&network_stat_ptr->interface_name,
131 tdb 1.65 net_ptr->ifa_name) < 0) {
132 ats 1.60 return NULL;
133     }
134 pajs 1.14 net_data=(struct if_data *)net_ptr->ifa_data;
135     network_stat_ptr->rx=net_data->ifi_ibytes;
136 tdb 1.46 network_stat_ptr->tx=net_data->ifi_obytes;
137     network_stat_ptr->ipackets=net_data->ifi_ipackets;
138     network_stat_ptr->opackets=net_data->ifi_opackets;
139     network_stat_ptr->ierrors=net_data->ifi_ierrors;
140     network_stat_ptr->oerrors=net_data->ifi_oerrors;
141     network_stat_ptr->collisions=net_data->ifi_collisions;
142 pajs 1.14 network_stat_ptr->systime=time(NULL);
143     interfaces++;
144     }
145     freeifaddrs(net);
146 pajs 1.6 #endif
147 pajs 1.1
148 pajs 1.6 #ifdef SOLARIS
149 tdb 1.65 if ((kc = kstat_open()) == NULL) {
150 tdb 1.66 sg_set_error(SG_ERROR_KSTAT_OPEN, NULL);
151 tdb 1.65 return NULL;
152     }
153 pajs 1.1
154 pajs 1.6 interfaces=0;
155 pajs 1.3
156 tdb 1.66 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
157 tdb 1.65 if (!strcmp(ksp->ks_class, "net")) {
158     kstat_read(kc, ksp, NULL);
159 pajs 1.1
160 pajs 1.7 #ifdef SOL7
161 tdb 1.53 #define LRX "rbytes"
162     #define LTX "obytes"
163     #define LIPACKETS "ipackets"
164     #define LOPACKETS "opackets"
165 pajs 1.7 #define VALTYPE value.ui32
166     #else
167 tdb 1.53 #define LRX "rbytes64"
168     #define LTX "obytes64"
169     #define LIPACKETS "ipackets64"
170     #define LOPACKETS "opackets64"
171 pajs 1.7 #define VALTYPE value.ui64
172     #endif
173    
174 tdb 1.53 /* Read rx */
175     if((knp=kstat_data_lookup(ksp, LRX))==NULL){
176 ats 1.44 /* This is a network interface, but it doesn't
177     * have the rbytes/obytes values; for instance,
178     * the loopback devices have this behaviour
179     * (although they do track packets in/out). */
180 ats 1.55 /* FIXME: Show packet counts when byte counts
181     * not available. */
182 pajs 1.1 continue;
183     }
184 pajs 1.3
185 tdb 1.53 /* Create new network_stats */
186 ats 1.59 if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
187 pajs 1.1 return NULL;
188     }
189     network_stat_ptr=network_stats+interfaces;
190 tdb 1.53
191     /* Finish reading rx */
192 pajs 1.7 network_stat_ptr->rx=knp->VALTYPE;
193 pajs 1.1
194 tdb 1.53 /* Read tx */
195     if((knp=kstat_data_lookup(ksp, LTX))==NULL){
196 pajs 1.1 continue;
197     }
198 pajs 1.7 network_stat_ptr->tx=knp->VALTYPE;
199 tdb 1.53
200     /* Read ipackets */
201     if((knp=kstat_data_lookup(ksp, LIPACKETS))==NULL){
202     continue;
203     }
204     network_stat_ptr->ipackets=knp->VALTYPE;
205    
206     /* Read opackets */
207     if((knp=kstat_data_lookup(ksp, LOPACKETS))==NULL){
208     continue;
209     }
210     network_stat_ptr->opackets=knp->VALTYPE;
211    
212     /* Read ierrors */
213     if((knp=kstat_data_lookup(ksp, "ierrors"))==NULL){
214     continue;
215     }
216     network_stat_ptr->ierrors=knp->value.ui32;
217    
218     /* Read oerrors */
219     if((knp=kstat_data_lookup(ksp, "oerrors"))==NULL){
220     continue;
221     }
222     network_stat_ptr->oerrors=knp->value.ui32;
223    
224     /* Read collisions */
225     if((knp=kstat_data_lookup(ksp, "collisions"))==NULL){
226     continue;
227     }
228     network_stat_ptr->collisions=knp->value.ui32;
229    
230     /* Read interface name */
231 ats 1.62 if (sg_update_string(&network_stat_ptr->interface_name,
232 tdb 1.65 ksp->ks_name) < 0) {
233 ats 1.60 return NULL;
234 pajs 1.1 }
235 pajs 1.3
236 tdb 1.53 /* Store systime */
237 pajs 1.3 network_stat_ptr->systime=time(NULL);
238 tdb 1.53
239 pajs 1.1 interfaces++;
240     }
241     }
242 pajs 1.2
243     kstat_close(kc);
244 pajs 1.6 #endif
245     #ifdef LINUX
246     f=fopen("/proc/net/dev", "r");
247     if(f==NULL){
248 tdb 1.66 sg_set_error(SG_ERROR_OPEN, "/proc/net/dev");
249 pajs 1.6 return NULL;
250     }
251     /* read the 2 lines.. Its the title, so we dont care :) */
252     fgets(line, sizeof(line), f);
253     fgets(line, sizeof(line), f);
254    
255    
256 ats 1.50 if((regcomp(&regex, "^ *([^:]+): *([0-9]+) +([0-9]+) +([0-9]+) +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +([0-9]+) +([0-9]+) +([0-9]+) +[0-9]+ +[0-9]+ +([0-9]+)", REG_EXTENDED))!=0){
257 tdb 1.66 sg_set_error(SG_ERROR_PARSE, NULL);
258 pajs 1.6 return NULL;
259     }
260    
261     interfaces=0;
262 pajs 1.1
263 pajs 1.6 while((fgets(line, sizeof(line), f)) != NULL){
264 ats 1.51 if((regexec(&regex, line, 9, line_match, 0))!=0){
265 pajs 1.6 continue;
266     }
267 ats 1.59
268     if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
269     return NULL;
270 pajs 1.6 }
271 tdb 1.65 network_stat_ptr=network_stats+interfaces;
272 pajs 1.6
273     if(network_stat_ptr->interface_name!=NULL){
274     free(network_stat_ptr->interface_name);
275     }
276    
277 ats 1.62 network_stat_ptr->interface_name=sg_get_string_match(line, &line_match[1]);
278     network_stat_ptr->rx=sg_get_ll_match(line, &line_match[2]);
279     network_stat_ptr->tx=sg_get_ll_match(line, &line_match[5]);
280     network_stat_ptr->ipackets=sg_get_ll_match(line, &line_match[3]);
281     network_stat_ptr->opackets=sg_get_ll_match(line, &line_match[6]);
282     network_stat_ptr->ierrors=sg_get_ll_match(line, &line_match[4]);
283     network_stat_ptr->oerrors=sg_get_ll_match(line, &line_match[7]);
284     network_stat_ptr->collisions=sg_get_ll_match(line, &line_match[8]);
285 pajs 1.6 network_stat_ptr->systime=time(NULL);
286    
287     interfaces++;
288     }
289 pajs 1.12 fclose(f);
290 pajs 1.13 regfree(&regex);
291 pajs 1.6
292     #endif
293 ats 1.20
294     #ifdef CYGWIN
295 tdb 1.66 sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin");
296 ats 1.20 return NULL;
297     #endif
298    
299 pajs 1.1 *entries=interfaces;
300    
301     return network_stats;
302 pajs 1.3 }
303    
304 ats 1.62 static long long transfer_diff(long long new, long long old){
305 ats 1.56 #if defined(SOL7) || defined(LINUX) || defined(FREEBSD) || defined(DFBSD) || defined(OPENBSD)
306     /* 32-bit quantities, so we must explicitly deal with wraparound. */
307     #define MAXVAL 0x100000000LL
308     if (new >= old) {
309     return new - old;
310     } else {
311     return MAXVAL + new - old;
312     }
313 pajs 1.8 #else
314 ats 1.56 /* 64-bit quantities, so plain subtraction works. */
315     return new - old;
316 pajs 1.8 #endif
317     }
318    
319 ats 1.62 sg_network_io_stats *sg_get_network_io_stats_diff(int *entries) {
320     VECTOR_DECLARE_STATIC(diff, sg_network_io_stats, 1,
321 tdb 1.65 network_stat_init, network_stat_destroy);
322 ats 1.62 sg_network_io_stats *src = NULL, *dest;
323 ats 1.59 int i, j, diff_count, new_count;
324 ats 1.24
325     if (network_stats == NULL) {
326     /* No previous stats, so we can't calculate a difference. */
327 ats 1.62 return sg_get_network_io_stats(entries);
328 pajs 1.3 }
329    
330 ats 1.24 /* Resize the results array to match the previous stats. */
331 ats 1.59 diff_count = VECTOR_SIZE(network_stats);
332     if (VECTOR_RESIZE(diff, diff_count) < 0) {
333 pajs 1.3 return NULL;
334     }
335    
336 ats 1.24 /* Copy the previous stats into the result. */
337     for (i = 0; i < diff_count; i++) {
338     src = &network_stats[i];
339     dest = &diff[i];
340 pajs 1.3
341 ats 1.62 if (sg_update_string(&dest->interface_name,
342 tdb 1.65 src->interface_name) < 0) {
343 ats 1.60 return NULL;
344 pajs 1.3 }
345 ats 1.24 dest->rx = src->rx;
346     dest->tx = src->tx;
347 tdb 1.47 dest->ipackets = src->ipackets;
348     dest->opackets = src->opackets;
349     dest->ierrors = src->ierrors;
350     dest->oerrors = src->oerrors;
351     dest->collisions = src->collisions;
352 ats 1.24 dest->systime = src->systime;
353     }
354 pajs 1.3
355 ats 1.24 /* Get a new set of stats. */
356 ats 1.62 if (sg_get_network_io_stats(&new_count) == NULL) {
357 ats 1.21 return NULL;
358     }
359 pajs 1.3
360 ats 1.24 /* For each previous stat... */
361     for (i = 0; i < diff_count; i++) {
362     dest = &diff[i];
363    
364     /* ... find the corresponding new stat ... */
365     for (j = 0; j < new_count; j++) {
366     /* Try the new stat in the same position first,
367     since that's most likely to be it. */
368     src = &network_stats[(i + j) % new_count];
369     if (strcmp(src->interface_name, dest->interface_name) == 0) {
370     break;
371     }
372     }
373     if (j == new_count) {
374     /* No match found. */
375     continue;
376 pajs 1.3 }
377    
378 ats 1.24 /* ... and subtract the previous stat from it to get the
379     difference. */
380     dest->rx = transfer_diff(src->rx, dest->rx);
381     dest->tx = transfer_diff(src->tx, dest->tx);
382 tdb 1.47 dest->ipackets = transfer_diff(src->ipackets, dest->ipackets);
383     dest->opackets = transfer_diff(src->opackets, dest->opackets);
384     dest->ierrors = transfer_diff(src->ierrors, dest->ierrors);
385     dest->oerrors = transfer_diff(src->oerrors, dest->oerrors);
386     dest->collisions = transfer_diff(src->collisions, dest->collisions);
387 ats 1.24 dest->systime = src->systime - dest->systime;
388 pajs 1.3 }
389    
390 ats 1.24 *entries = diff_count;
391     return diff;
392     }
393 ats 1.59
394 pajs 1.25 /* NETWORK INTERFACE STATS */
395    
396 ats 1.62 static void network_iface_stat_init(sg_network_iface_stats *s) {
397 ats 1.59 s->interface_name = NULL;
398     s->speed = 0;
399 ats 1.62 s->dup = SG_IFACE_DUPLEX_UNKNOWN;
400 pajs 1.25 }
401    
402 ats 1.62 static void network_iface_stat_destroy(sg_network_iface_stats *s) {
403 ats 1.59 free(s->interface_name);
404 pajs 1.25 }
405    
406 ats 1.62 sg_network_iface_stats *sg_get_network_iface_stats(int *entries){
407     VECTOR_DECLARE_STATIC(network_iface_stats, sg_network_iface_stats, 5,
408 tdb 1.65 network_iface_stat_init, network_iface_stat_destroy);
409 ats 1.62 sg_network_iface_stats *network_iface_stat_ptr;
410 ats 1.43 int ifaces = 0;
411 pajs 1.25
412     #ifdef SOLARIS
413 tdb 1.65 kstat_ctl_t *kc;
414     kstat_t *ksp;
415 pajs 1.25 kstat_named_t *knp;
416 ats 1.44 int sock;
417 pajs 1.25 #endif
418 pajs 1.26 #ifdef ALLBSD
419 tdb 1.65 struct ifaddrs *net, *net_ptr;
420 pajs 1.26 struct ifmediareq ifmed;
421 pajs 1.36 struct ifreq ifr;
422 ats 1.37 int sock;
423 pajs 1.26 int x;
424     #endif
425 pajs 1.27 #ifdef LINUX
426 tdb 1.65 FILE *f;
427     /* Horrible big enough, but it should be easily big enough */
428     char line[8096];
429 pajs 1.27 int sock;
430     #endif
431 ats 1.43
432 pajs 1.26 #ifdef ALLBSD
433 tdb 1.65 if(getifaddrs(&net) != 0){
434 tdb 1.66 sg_set_error(SG_ERROR_GETIFADDRS, NULL);
435 tdb 1.65 return NULL;
436     }
437 pajs 1.26
438 ats 1.37 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == 0) return NULL;
439 pajs 1.26
440     for(net_ptr=net; net_ptr!=NULL; net_ptr=net_ptr->ifa_next){
441 tdb 1.65 if(net_ptr->ifa_addr->sa_family != AF_LINK) continue;
442 ats 1.59
443     if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
444 tdb 1.65 return NULL;
445     }
446     network_iface_stat_ptr = network_iface_stats + ifaces;
447 pajs 1.26
448 ats 1.40 memset(&ifr, 0, sizeof(ifr));
449     strncpy(ifr.ifr_name, net_ptr->ifa_name, sizeof(ifr.ifr_name));
450    
451     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0){
452     continue;
453     }
454     if((ifr.ifr_flags & IFF_UP) != 0){
455     network_iface_stat_ptr->up = 1;
456     }else{
457     network_iface_stat_ptr->up = 0;
458     }
459    
460 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
461 tdb 1.65 net_ptr->ifa_name) < 0) {
462 ats 1.60 return NULL;
463     }
464 ats 1.40
465     network_iface_stat_ptr->speed = 0;
466 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
467 ats 1.40 ifaces++;
468    
469 pajs 1.26 memset(&ifmed, 0, sizeof(struct ifmediareq));
470 ats 1.62 sg_strlcpy(ifmed.ifm_name, net_ptr->ifa_name, sizeof(ifmed.ifm_name));
471 ats 1.37 if(ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed) == -1){
472 ats 1.40 /* Not all interfaces support the media ioctls. */
473 pajs 1.26 continue;
474     }
475    
476     /* We may need to change this if we start doing wireless devices too */
477     if( (ifmed.ifm_active | IFM_ETHER) != ifmed.ifm_active ){
478     /* Not a ETHER device */
479     continue;
480     }
481    
482     /* Only intrested in the first 4 bits) - Assuming only ETHER devices */
483     x = ifmed.ifm_active & 0x0f;
484     switch(x){
485     /* 10 Mbit connections. Speedy :) */
486     case(IFM_10_T):
487     case(IFM_10_2):
488     case(IFM_10_5):
489     case(IFM_10_STP):
490     case(IFM_10_FL):
491     network_iface_stat_ptr->speed = 10;
492     break;
493     /* 100 Mbit conneections */
494     case(IFM_100_TX):
495     case(IFM_100_FX):
496     case(IFM_100_T4):
497     case(IFM_100_VG):
498     case(IFM_100_T2):
499     network_iface_stat_ptr->speed = 100;
500     break;
501     /* 1000 Mbit connections */
502     case(IFM_1000_SX):
503     case(IFM_1000_LX):
504     case(IFM_1000_CX):
505 tdb 1.54 #if defined(IFM_1000_TX) && !defined(OPENBSD)
506     case(IFM_1000_TX): /* FreeBSD 4 and others (but NOT OpenBSD)? */
507 tdb 1.45 #endif
508     #ifdef IFM_1000_FX
509     case(IFM_1000_FX): /* FreeBSD 4 */
510     #endif
511     #ifdef IFM_1000_T
512     case(IFM_1000_T): /* FreeBSD 5 */
513 tdb 1.28 #endif
514 pajs 1.26 network_iface_stat_ptr->speed = 1000;
515     break;
516     /* We don't know what it is */
517     default:
518     network_iface_stat_ptr->speed = 0;
519     break;
520     }
521    
522     if( (ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active ){
523 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_FULL;
524 pajs 1.26 }else if( (ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active ){
525 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_HALF;
526 pajs 1.26 }else{
527 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
528 pajs 1.26 }
529 pajs 1.36
530 pajs 1.26 }
531     freeifaddrs(net);
532 ats 1.37 close(sock);
533 pajs 1.26 #endif
534 pajs 1.25
535     #ifdef SOLARIS
536 ats 1.44 if ((kc = kstat_open()) == NULL) {
537 tdb 1.66 sg_set_error(SG_ERROR_KSTAT_OPEN, NULL);
538 ats 1.44 return NULL;
539     }
540    
541     if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
542 tdb 1.66 sg_set_error(SG_ERROR_SOCKET, NULL);
543 ats 1.44 return NULL;
544     }
545 pajs 1.25
546 ats 1.44 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
547     if (!strcmp(ksp->ks_class, "net")) {
548     struct ifreq ifr;
549    
550     kstat_read(kc, ksp, NULL);
551    
552     strncpy(ifr.ifr_name, ksp->ks_name, sizeof ifr.ifr_name);
553     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
554     /* Not a network interface. */
555 pajs 1.25 continue;
556     }
557 ats 1.44
558 ats 1.59 if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
559 pajs 1.25 return NULL;
560     }
561 pajs 1.26 network_iface_stat_ptr = network_iface_stats + ifaces;
562 ats 1.44 ifaces++;
563    
564 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
565 tdb 1.65 ksp->ks_name) < 0) {
566 ats 1.60 return NULL;
567     }
568 pajs 1.25
569 ats 1.44 if ((ifr.ifr_flags & IFF_UP) != 0) {
570     network_iface_stat_ptr->up = 1;
571     } else {
572     network_iface_stat_ptr->up = 1;
573     }
574 pajs 1.35
575 ats 1.44 if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL) {
576     network_iface_stat_ptr->speed = knp->value.ui64 / (1000 * 1000);
577     } else {
578     network_iface_stat_ptr->speed = 0;
579 pajs 1.25 }
580    
581 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
582 ats 1.44 if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) {
583     switch (knp->value.ui32) {
584     case 1:
585 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_HALF;
586 ats 1.44 break;
587     case 2:
588 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_FULL;
589 ats 1.44 break;
590     }
591 pajs 1.33 }
592 pajs 1.25 }
593     }
594 ats 1.44
595     close(sock);
596 pajs 1.25 kstat_close(kc);
597     #endif
598 pajs 1.27 #ifdef LINUX
599     f = fopen("/proc/net/dev", "r");
600 tdb 1.65 if(f == NULL){
601 tdb 1.66 sg_set_error(SG_ERROR_OPEN, "/proc/net/dev");
602 tdb 1.65 return NULL;
603     }
604 pajs 1.27
605     /* Setup stuff so we can do the ioctl to get the info */
606     if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
607 tdb 1.66 sg_set_error(SG_ERROR_SOCKET, NULL);
608 pajs 1.27 return NULL;
609     }
610    
611     /* Ignore first 2 lines.. Just headings */
612 tdb 1.66 if((fgets(line, sizeof(line), f)) == NULL) {
613     sg_set_error(SG_ERROR_PARSE, NULL);
614     return NULL;
615     }
616     if((fgets(line, sizeof(line), f)) == NULL) {
617     sg_set_error(SG_ERROR_PARSE, NULL);
618     return NULL;
619     }
620 pajs 1.27
621 tdb 1.65 while((fgets(line, sizeof(line), f)) != NULL){
622     char *name, *ptr;
623     struct ifreq ifr;
624     struct ethtool_cmd ethcmd;
625     int err;
626 pajs 1.27
627     /* Get the interface name */
628 tdb 1.65 ptr = strchr(line, ':');
629     if (ptr == NULL) continue;
630     *ptr='\0';
631     name = line;
632     while(isspace(*(name))){
633     name++;
634     }
635 pajs 1.27
636 tdb 1.65 memset(&ifr, 0, sizeof ifr);
637     strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
638 pajs 1.27
639 ats 1.38 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
640     continue;
641     }
642 pajs 1.27
643     /* We have a good interface to add */
644 ats 1.59 if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
645 pajs 1.27 return NULL;
646     }
647     network_iface_stat_ptr = network_iface_stats + ifaces;
648 ats 1.60
649 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
650 tdb 1.65 name) < 0) {
651 ats 1.60 return NULL;
652     }
653 ats 1.38 if ((ifr.ifr_flags & IFF_UP) != 0) {
654 pajs 1.35 network_iface_stat_ptr->up = 1;
655 ats 1.38 } else {
656 pajs 1.35 network_iface_stat_ptr->up = 0;
657     }
658    
659 tdb 1.65 memset(&ethcmd, 0, sizeof ethcmd);
660     ethcmd.cmd = ETHTOOL_GSET;
661     ifr.ifr_data = (caddr_t) &ethcmd;
662 ats 1.38
663 tdb 1.65 err = ioctl(sock, SIOCETHTOOL, &ifr);
664     if (err == 0) {
665 ats 1.38 network_iface_stat_ptr->speed = ethcmd.speed;
666    
667     switch (ethcmd.duplex) {
668     case 0x00:
669 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_FULL;
670 ats 1.38 break;
671     case 0x01:
672 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_HALF;
673 ats 1.38 break;
674     default:
675 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
676 ats 1.38 }
677     } else {
678     /* Not all interfaces support the ethtool ioctl. */
679 ats 1.39 network_iface_stat_ptr->speed = 0;
680 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
681 pajs 1.27 }
682 ats 1.38
683 pajs 1.27 ifaces++;
684     }
685 pajs 1.30 close(sock);
686 ats 1.38 fclose(f);
687 pajs 1.27 #endif
688 pajs 1.26 *entries = ifaces;
689 pajs 1.25 return network_iface_stats;
690     }
691