* ifdata: robustness patch from Adam Lackorzynski, in particular deal with
[moreutils.git] / ifdata.c
blobc9a46222913380164770be30714d8cf3585c0f29
1 #include <stdlib.h>
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <stdio.h>
5 #include <netdb.h>
6 #include <sys/ioctl.h>
7 #include <linux/sockios.h>
8 #include <linux/if.h>
9 #include <netinet/in.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <ctype.h>
15 //#include <linux/socket.h>
17 #define DO_EXISTS 1
18 #define DO_PEXISTS 2
19 #define DO_PADDRESS 3
20 #define DO_PMASK 4
21 #define DO_PMTU 5
22 #define DO_PCAST 6
23 #define DO_PALL 7
24 #define DO_PFLAGS 8
25 #define DO_SINPACKETS 9
26 #define DO_SINBYTES 10
27 #define DO_SINERRORS 11
28 #define DO_SINDROPS 12
29 #define DO_SINALL 13
30 #define DO_SINFIFO 14
31 #define DO_SINFRAME 15
32 #define DO_SINCOMPRESSES 16
33 #define DO_SINMULTICAST 17
34 #define DO_SOUTALL 18
35 #define DO_SOUTBYTES 19
36 #define DO_SOUTPACKETS 20
37 #define DO_SOUTERRORS 21
38 #define DO_SOUTDROPS 22
39 #define DO_SOUTFIFO 23
40 #define DO_SOUTCOLLS 24
41 #define DO_SOUTCARRIER 25
42 #define DO_SOUTMULTICAST 26
43 #define DO_PNETWORK 27
44 #define DO_PHWADDRESS 28
46 struct if_stat {
47 unsigned long long int in_packets;
48 unsigned long long int in_bytes;
49 unsigned long long int in_errors;
50 unsigned long long int in_drops;
51 unsigned long long int in_fifo;
52 unsigned long long int in_frame;
53 unsigned long long int in_compress;
54 unsigned long long int in_multicast;
55 unsigned long long int out_bytes;
56 unsigned long long int out_packets;
57 unsigned long long int out_errors;
58 unsigned long long int out_drops;
59 unsigned long long int out_fifo;
60 unsigned long long int out_colls;
61 unsigned long long int out_carrier;
62 unsigned long long int out_multicast;
66 void print_quad_ipv4(unsigned int i) {
67 #if __BYTE_ORDER == __LITTLE_ENDIAN
68 printf("%d.%d.%d.%d",
69 i&0xff,
70 (i&0xff00)>>8,
71 (i&0xff0000)>>16,
72 (i&0xff000000)>>24);
73 #else
74 printf("%d.%d.%d.%d",
75 (i&0xff000000)>>24,
76 (i&0xff0000)>>16,
77 (i&0xff00)>>8,
78 i&0xff);
79 #endif
82 void print_quad_ipv6(uint16_t *a) {
83 int i;
84 for (i=0; i<7; i++) {
85 printf("%04x:",a[i]);
87 printf("%04x",a[i]);
90 void print_quad(struct sockaddr *adr) {
91 switch (adr->sa_family) {
92 case AF_INET:
93 print_quad_ipv4(((struct sockaddr_in*)adr)->sin_addr.s_addr);
94 break;
95 case AF_INET6:
96 print_quad_ipv6(((struct sockaddr_in6*)adr)->sin6_addr.s6_addr16);
97 break;
98 default:
99 printf("NON-IP");
100 break;
104 #define PREPARE_SOCK(iface) int sock; \
105 static struct ifreq req; \
106 int res; \
107 sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_IP); \
108 strcpy(req.ifr_name,iface)
109 #define CALL_IOCTL(call) res=ioctl(sock,call,&req)
110 #define END_SOCK close(sock)
111 #define CALL_ERROR(todo) if (res==-1) { perror("ioctl"); close(sock); todo; }
113 int if_exists(char *iface) {
114 PREPARE_SOCK(iface);
115 CALL_IOCTL(SIOCGIFFLAGS);
116 if (res==-1 && errno==ENODEV) {
117 END_SOCK;
118 return 0;
120 CALL_ERROR(return 0);
121 END_SOCK;
122 return 1;
125 #define PRINT_IF(cond,tell) if (req.ifr_flags & cond) printf(tell); else printf("No "tell)
127 void if_flags(char *iface) {
128 PREPARE_SOCK(iface);
129 CALL_IOCTL(SIOCGIFFLAGS);
130 CALL_ERROR(return);
131 PRINT_IF(IFF_UP,"Up\n");
132 PRINT_IF(IFF_BROADCAST,"Broadcast\n");
133 PRINT_IF(IFF_DEBUG,"Debugging\n");
134 PRINT_IF(IFF_LOOPBACK,"Loopback\n");
135 PRINT_IF(IFF_POINTOPOINT,"Ppp\n");
136 PRINT_IF(IFF_NOTRAILERS,"No-trailers\n");
137 PRINT_IF(IFF_RUNNING,"Running\n");
138 PRINT_IF(IFF_NOARP,"No-arp\n");
139 PRINT_IF(IFF_PROMISC,"Promiscuous\n");
140 PRINT_IF(IFF_ALLMULTI,"All-multicast\n");
141 PRINT_IF(IFF_MASTER,"Load-master\n");
142 PRINT_IF(IFF_SLAVE,"Load-slave\n");
143 PRINT_IF(IFF_MULTICAST,"Multicast\n");
144 PRINT_IF(IFF_PORTSEL,"Port-select\n");
145 PRINT_IF(IFF_AUTOMEDIA,"Auto-detect\n");
146 PRINT_IF(IFF_DYNAMIC,"Dynaddr\n");
147 PRINT_IF(0xffff0000,"Unknown-flags");
150 void if_hwaddr(char *iface) {
151 unsigned char *hwaddr;
153 PREPARE_SOCK(iface);
154 CALL_IOCTL(SIOCGIFHWADDR);
155 if (res < 0) {
156 CALL_ERROR();
158 hwaddr = (unsigned char *)req.ifr_hwaddr.sa_data;
159 printf("%02X:%02X:%02X:%02X:%02X:%02X",
160 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
161 END_SOCK;
164 struct sockaddr *if_addr(char *iface) {
165 PREPARE_SOCK(iface);
166 CALL_IOCTL(SIOCGIFADDR);
167 if (res==-1 && errno==EADDRNOTAVAIL) {
168 return &req.ifr_addr;
170 CALL_ERROR(return NULL);
171 END_SOCK;
172 return &req.ifr_addr;
175 struct sockaddr *if_mask(char *iface) {
176 PREPARE_SOCK(iface);
177 CALL_IOCTL(SIOCGIFNETMASK);
178 if (res==-1 && errno==EADDRNOTAVAIL) {
179 return &req.ifr_addr;
181 CALL_ERROR(return NULL);
182 END_SOCK;
183 return &req.ifr_addr;
186 struct sockaddr *if_network(char *iface) {
187 struct sockaddr *res;
188 res=if_mask(iface);
189 long int mask=((struct sockaddr_in*)res)->sin_addr.s_addr;
190 res=if_addr(iface);
191 ((struct sockaddr_in*)res)->sin_addr.s_addr &= mask;
192 return res;
195 struct sockaddr *if_bcast(char *iface) {
196 PREPARE_SOCK(iface);
197 CALL_IOCTL(SIOCGIFBRDADDR);
198 if (res==-1 && errno==EADDRNOTAVAIL) {
199 return &req.ifr_addr;
201 CALL_ERROR(return NULL);
202 END_SOCK;
203 return &req.ifr_addr;
206 int if_mtu(char *iface) {
207 PREPARE_SOCK(iface);
208 CALL_IOCTL(SIOCGIFMTU);
209 CALL_ERROR(return 0);
210 END_SOCK;
211 return req.ifr_mtu;
214 #define START 1
215 #define SKIP_LINE 2
216 #define START_LINE 3
217 #define START_IFNAME 4
218 #define IFACE_FOUND 5
219 #define RX_BYTES 6
220 #define WAIT_RX_PACKETS 7
221 #define RX_PACKETS 8
222 #define WAIT_RX_ERRORS 9
223 #define RX_ERRORS 10
224 #define WAIT_RX_DROPS 11
225 #define RX_DROPS 12
226 #define WAIT_RX_FIFO 13
227 #define RX_FIFO 14
228 #define WAIT_RX_FRAME 15
229 #define RX_FRAME 16
230 #define WAIT_RX_COMPRESS 17
231 #define RX_COMPRESS 18
232 #define WAIT_RX_MULTICAST 19
233 #define RX_MULTICAST 20
234 #define WAIT_TX_BYTES 21
235 #define TX_BYTES 22
236 #define WAIT_TX_PACKETS 23
237 #define TX_PACKETS 24
238 #define WAIT_TX_ERRORS 25
239 #define TX_ERRORS 26
240 #define WAIT_TX_DROPS 27
241 #define TX_DROPS 28
242 #define WAIT_TX_FIFO 29
243 #define TX_FIFO 30
244 #define WAIT_TX_COLLS 31
245 #define TX_COLLS 32
246 #define WAIT_TX_CARRIER 33
247 #define TX_CARRIER 34
248 #define WAIT_TX_MULTICAST 35
249 #define TX_MULTICAST 36
251 #define FIRST_DIGIT(val,digit) do {val=digit-'0'; } while(0)
252 #define NEXT_DIGIT(val,digit) do {val*=10; val+=digit-'0'; } while(0)
254 #define READ_INT(cas,val,next) \
255 case WAIT_##cas: \
256 if (isdigit(buffer[i])) { \
257 state=cas; \
258 FIRST_DIGIT(val,buffer[i]); \
260 break; \
261 case cas: \
262 if (isdigit(buffer[i])) \
263 NEXT_DIGIT(val,buffer[i]); \
264 else \
265 state=next; \
266 break;
269 //#define FIRST_DIGIT(val,digit) do {val=digit-'0'; printf(#val " = %d\n",val); } while(0)
270 //#define NEXT_DIGIT(val,digit) do {val*=10; val+=digit-'0'; printf(#val " -> %d\n",val);} while(0)
271 struct if_stat *get_stats(char *iface) {
272 int fd;
273 unsigned char buffer[4096];
274 int i,j=0;
275 int state=START;
276 int len;
277 struct if_stat *res=malloc(sizeof(struct if_stat));
279 if (!res) {
280 perror("malloc");
281 return NULL;
284 fd=open("/proc/net/dev",O_RDONLY);
285 if (fd==-1) {
286 perror("open(\"/proc/net/dev\")");
287 return NULL;
289 while ((len=read(fd,buffer,4096))) {
290 for (i=0; i<len; i++) {
291 switch (state) {
292 case START:
293 if (buffer[i]=='\n') state=SKIP_LINE;
294 break;
295 case SKIP_LINE:
296 if (buffer[i]=='\n') state=START_LINE;
297 break;
298 case START_LINE:
299 if (buffer[i]!=' ') {
300 if (buffer[i]==iface[0]) {
301 state=START_IFNAME;
302 j=1;
303 } else
304 state=SKIP_LINE;
306 break;
307 case START_IFNAME:
308 if (buffer[i]==':' && iface[j]==0)
309 state=IFACE_FOUND;
310 else if (buffer[i]==iface[j])
311 j++;
312 else
313 state=SKIP_LINE;
314 break;
315 case IFACE_FOUND:
316 if (isdigit(buffer[i])) {
317 state=RX_BYTES;
318 FIRST_DIGIT(res->in_bytes,buffer[i]);
320 break;
321 case RX_BYTES:
322 if (isdigit(buffer[i]))
323 NEXT_DIGIT(res->in_bytes,buffer[i]);
324 else
325 state=WAIT_RX_PACKETS;
326 break;
327 READ_INT(RX_PACKETS,res->in_packets,WAIT_RX_ERRORS);
328 READ_INT(RX_ERRORS,res->in_errors,WAIT_RX_DROPS);
329 READ_INT(RX_DROPS,res->in_drops,WAIT_RX_FIFO);
330 READ_INT(RX_FIFO,res->in_fifo,WAIT_RX_FRAME);
331 READ_INT(RX_FRAME,res->in_frame,WAIT_RX_COMPRESS);
332 READ_INT(RX_COMPRESS,res->in_compress,WAIT_RX_MULTICAST);
333 READ_INT(RX_MULTICAST,res->in_multicast,WAIT_TX_BYTES);
334 READ_INT(TX_BYTES,res->out_bytes,WAIT_TX_PACKETS);
335 READ_INT(TX_PACKETS,res->out_packets,WAIT_TX_ERRORS);
336 READ_INT(TX_ERRORS,res->out_errors,WAIT_TX_DROPS);
337 READ_INT(TX_DROPS,res->out_drops,WAIT_TX_FIFO);
338 READ_INT(TX_FIFO,res->out_fifo,WAIT_TX_COLLS);
339 READ_INT(TX_COLLS,res->out_colls,WAIT_TX_CARRIER);
340 READ_INT(TX_CARRIER,res->out_carrier,WAIT_TX_MULTICAST);
341 READ_INT(TX_MULTICAST,res->out_carrier,SKIP_LINE);
342 default:
343 fprintf(stderr,"Mon totomate est po bon!\n");
344 break;
348 return res;
351 void usage(char *name) {
352 fprintf(stderr,"Usage: %s [options] iface\n",name);
353 fprintf(stderr," -e Says if iface exists or not\n"
354 " -p Print out the whole config of iface\n"
355 " -pe Print out yes or no according to existence\n"
356 " -ph Print out the hardware address\n"
357 " -pa Print out the address\n"
358 " -pn Print netmask\n"
359 " -pN Print network address\n"
360 " -pb Print broadcast\n"
361 " -pm Print mtu\n"
362 " -pf Print flags\n"
363 " -si Print all statistics on input\n"
364 " -sip Print # of in packets\n"
365 " -sib Print # of in bytes\n"
366 " -sie Print # of in errors\n"
367 " -sid Print # of in drops\n"
368 " -sif Print # of in fifo overruns\n"
369 " -sic Print # of in compress\n"
370 " -sim Print # of in multicast\n"
371 " -so Print all statistics on output\n"
372 " -sop Print # of out packets\n"
373 " -sob Print # of out bytes\n"
374 " -soe Print # of out errors\n"
375 " -sod Print # of out drops\n"
376 " -sof Print # of out fifo overruns\n"
377 " -sox Print # of out collisions\n"
378 " -soc Print # of out carrier loss\n"
379 " -som Print # of out multicast\n");
382 void add_do(int *ndo, int **todo, int act) {
383 *todo=realloc(*todo,(*ndo+1)*sizeof(int));
384 (*todo)[*ndo]=act;
385 *ndo+=1;
388 #define PRINT_OR_ERR(adr) if (adr) print_quad(adr); else { fprintf(stderr, "Error\n"); exit(1); }
390 void please_do(int ndo, int *todo, char *ifname) {
391 int i;
392 struct sockaddr *sadr;
393 struct if_stat *stats=NULL;
394 if (!ndo) return;
395 // printf("J'ai %d actions a réaliser\n",ndo);
396 for (i=0; i<ndo; i++) {
397 switch (todo[i]) {
398 case DO_EXISTS:
399 if (if_exists(ifname)) {
400 exit(0);
401 } else {
402 exit(1);
404 break;
405 case DO_PEXISTS:
406 if (if_exists(ifname)) {
407 printf("yes");
408 } else {
409 printf("no");
411 break;
412 case DO_PHWADDRESS:
413 if_hwaddr(ifname);
414 break;
415 case DO_PADDRESS:
416 sadr=if_addr(ifname);
417 PRINT_OR_ERR(sadr);
418 break;
419 case DO_PFLAGS:
420 if_flags(ifname);
421 break;
422 case DO_PMASK:
423 sadr=if_mask(ifname);
424 PRINT_OR_ERR(sadr);
425 break;
426 case DO_PCAST:
427 sadr=if_bcast(ifname);
428 PRINT_OR_ERR(sadr);
429 break;
430 case DO_PMTU:
431 printf("%d",if_mtu(ifname));
432 break;
433 case DO_PNETWORK:
434 sadr=if_network(ifname);
435 PRINT_OR_ERR(sadr);
436 break;
437 case DO_PALL:
438 sadr=if_addr(ifname);
439 PRINT_OR_ERR(sadr);
440 printf(" ");
441 sadr=if_mask(ifname);
442 PRINT_OR_ERR(sadr);
443 printf(" ");
444 sadr=if_bcast(ifname);
445 PRINT_OR_ERR(sadr);
446 printf(" ");
447 printf("%d",if_mtu(ifname));
448 break;
449 case DO_SINPACKETS:
450 if (!stats) stats=get_stats(ifname);
451 if (stats)
452 printf("%llu",stats->in_packets);
453 break;
454 case DO_SINBYTES:
455 if (!stats) stats=get_stats(ifname);
456 if (stats)
457 printf("%llu",stats->in_bytes);
458 break;
459 case DO_SINERRORS:
460 if (!stats) stats=get_stats(ifname);
461 if (stats)
462 printf("%llu",stats->in_errors);
463 break;
464 case DO_SINDROPS:
465 if (!stats) stats=get_stats(ifname);
466 if (stats)
467 printf("%llu",stats->in_drops);
468 break;
469 case DO_SINFIFO:
470 if (!stats) stats=get_stats(ifname);
471 if (stats)
472 printf("%llu",stats->in_fifo);
473 break;
474 case DO_SINFRAME:
475 if (!stats) stats=get_stats(ifname);
476 if (stats)
477 printf("%llu",stats->in_frame);
478 break;
479 case DO_SINCOMPRESSES:
480 if (!stats) stats=get_stats(ifname);
481 if (stats)
482 printf("%llu",stats->in_compress);
483 break;
484 case DO_SINMULTICAST:
485 if (!stats) stats=get_stats(ifname);
486 if (stats)
487 printf("%llu",stats->in_multicast);
488 break;
489 case DO_SINALL:
490 if (!stats) stats=get_stats(ifname);
491 if (stats)
492 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
493 stats->in_packets,
494 stats->in_bytes,
495 stats->in_errors,
496 stats->in_drops,
497 stats->in_fifo,
498 stats->in_frame,
499 stats->in_compress,
500 stats->in_multicast);
501 break;
502 case DO_SOUTBYTES:
503 if (!stats) stats=get_stats(ifname);
504 if (stats)
505 printf("%llu",stats->out_bytes);
506 break;
507 case DO_SOUTPACKETS:
508 if (!stats) stats=get_stats(ifname);
509 if (stats)
510 printf("%llu",stats->out_packets);
511 break;
512 case DO_SOUTERRORS:
513 if (!stats) stats=get_stats(ifname);
514 if (stats)
515 printf("%llu",stats->out_errors);
516 break;
517 case DO_SOUTDROPS:
518 if (!stats) stats=get_stats(ifname);
519 if (stats)
520 printf("%llu",stats->out_drops);
521 break;
522 case DO_SOUTFIFO:
523 if (!stats) stats=get_stats(ifname);
524 if (stats)
525 printf("%llu",stats->out_fifo);
526 break;
527 case DO_SOUTCOLLS:
528 if (!stats) stats=get_stats(ifname);
529 if (stats)
530 printf("%llu",stats->out_colls);
531 break;
532 case DO_SOUTCARRIER:
533 if (!stats) stats=get_stats(ifname);
534 if (stats)
535 printf("%llu",stats->out_carrier);
536 break;
537 case DO_SOUTMULTICAST:
538 if (!stats) stats=get_stats(ifname);
539 if (stats)
540 printf("%llu",stats->out_multicast);
541 break;
542 case DO_SOUTALL:
543 if (!stats) stats=get_stats(ifname);
544 if (stats)
545 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
546 stats->out_packets,
547 stats->out_bytes,
548 stats->out_errors,
549 stats->out_drops,
550 stats->out_fifo,
551 stats->out_colls,
552 stats->out_carrier,
553 stats->out_multicast);
554 break;
555 default:
556 printf("Je comprends pas ce que je dois faire: %d\n",todo[i]);
557 break;
559 printf("\n");
563 int main(int argc, char *argv[]) {
564 int ndo=0;
565 int *todo=NULL;
566 char *me=*argv;
567 char *ifname=NULL;
568 int narg=0;
570 print_quad(&res.ifr_addr);
571 s=socket(PF_INET6,SOCK_DGRAM,IPPROTO_IP);
572 ret=ioctl(s,SIOCGIFADDR,&res);
573 print_quad(&res.ifr_addr);
575 if (argc==1) {
576 usage(me);
577 return 1;
579 narg++;
580 while (narg<argc) {
581 if (!strcmp(argv[narg],"-e")) {
582 add_do(&ndo,&todo,DO_EXISTS);
583 } else if (!strcmp(argv[narg],"-p")) {
584 add_do(&ndo,&todo,DO_PALL);
585 } else if (!strcmp(argv[narg],"-ph")) {
586 add_do(&ndo,&todo,DO_PHWADDRESS);
587 } else if (!strcmp(argv[narg],"-pa")) {
588 add_do(&ndo,&todo,DO_PADDRESS);
589 } else if (!strcmp(argv[narg],"-pn")) {
590 add_do(&ndo,&todo,DO_PMASK);
591 } else if (!strcmp(argv[narg],"-pN")) {
592 add_do(&ndo,&todo,DO_PNETWORK);
593 } else if (!strcmp(argv[narg],"-pb")) {
594 add_do(&ndo,&todo,DO_PCAST);
595 } else if (!strcmp(argv[narg],"-pm")) {
596 add_do(&ndo,&todo,DO_PMTU);
597 } else if (!strcmp(argv[narg],"-pe")) {
598 add_do(&ndo,&todo,DO_PEXISTS);
599 } else if (!strcmp(argv[narg],"-pf")) {
600 add_do(&ndo,&todo,DO_PFLAGS);
601 } else if (!strcmp(argv[narg],"-si")) {
602 add_do(&ndo,&todo,DO_SINALL);
603 } else if (!strcmp(argv[narg],"-sip")) {
604 add_do(&ndo,&todo,DO_SINPACKETS);
605 } else if (!strcmp(argv[narg],"-sib")) {
606 add_do(&ndo,&todo,DO_SINBYTES);
607 } else if (!strcmp(argv[narg],"-sie")) {
608 add_do(&ndo,&todo,DO_SINERRORS);
609 } else if (!strcmp(argv[narg],"-sid")) {
610 add_do(&ndo,&todo,DO_SINDROPS);
611 } else if (!strcmp(argv[narg],"-sif")) {
612 add_do(&ndo,&todo,DO_SINFIFO);
613 } else if (!strcmp(argv[narg],"-sic")) {
614 add_do(&ndo,&todo,DO_SINCOMPRESSES);
615 } else if (!strcmp(argv[narg],"-sim")) {
616 add_do(&ndo,&todo,DO_SINMULTICAST);
617 } else if (!strcmp(argv[narg],"-so")) {
618 add_do(&ndo,&todo,DO_SOUTALL);
619 } else if (!strcmp(argv[narg],"-sop")) {
620 add_do(&ndo,&todo,DO_SOUTPACKETS);
621 } else if (!strcmp(argv[narg],"-sob")) {
622 add_do(&ndo,&todo,DO_SOUTBYTES);
623 } else if (!strcmp(argv[narg],"-soe")) {
624 add_do(&ndo,&todo,DO_SOUTERRORS);
625 } else if (!strcmp(argv[narg],"-sod")) {
626 add_do(&ndo,&todo,DO_SOUTDROPS);
627 } else if (!strcmp(argv[narg],"-sof")) {
628 add_do(&ndo,&todo,DO_SOUTFIFO);
629 } else if (!strcmp(argv[narg],"-sox")) {
630 add_do(&ndo,&todo,DO_SOUTCOLLS);
631 } else if (!strcmp(argv[narg],"-soc")) {
632 add_do(&ndo,&todo,DO_SOUTCARRIER);
633 } else if (!strcmp(argv[narg],"-som")) {
634 add_do(&ndo,&todo,DO_SOUTMULTICAST);
635 } else if (!strcmp(argv[narg],"-som")) {
636 usage(me);
637 return 1;
638 } else if (argv[narg][0] == '-') {
639 usage(me);
640 return 1;
641 } else {
642 ifname=argv[narg];
643 narg++;
644 break;
646 narg++;
648 if (narg<argc || ifname==NULL) {
649 usage(me);
650 return 1;
652 // printf("Je travaille sur l'interface %s\n",ifname);
653 please_do(ndo,todo,ifname);
654 return 0;