ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/network_stats.c
Revision: 1.74
Committed: Wed Jul 13 09:31:54 2005 UTC (18 years, 10 months ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.73: +17 -13 lines
Log Message:
Change the name of the duplex value from "dup" to "duplex". This will
break the ABI, but we're changing the fs stats anyway. The API change
is minimal, so hopefully won't affect too many people.

File Contents

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