changelog
[moreutils.git] / ifdata.c
blob99f30e9cebf9b90b8a283b02e2db5c47d11f2ca5
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>
8 #if defined(__linux__)
9 #include <linux/sockios.h>
10 #include <linux/if.h>
11 #endif
13 #if defined(__FreeBSD_kernel__)
14 #include <net/if.h>
15 #endif
17 #if defined(__GNU__)
18 #include <net/if.h>
19 #endif
21 #if defined(__APPLE__) || defined(__OpenBSD__)
22 #define s6_addr16 __u6_addr.__u6_addr16
23 #include <net/if.h>
24 #endif
26 #if defined(__sun)
27 #define s6_addr16 _S6_un._S6_u8
28 #include <net/if.h>
29 #include <sys/sockio.h>
30 #endif
32 #include <netinet/in.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <ctype.h>
39 enum {
40 DO_EXISTS = 1,
41 DO_PEXISTS,
42 DO_PADDRESS,
43 DO_PMASK,
44 DO_PMTU,
45 DO_PCAST,
46 DO_PALL,
47 DO_PFLAGS,
48 DO_SINPACKETS,
49 DO_SINBYTES,
50 DO_SINERRORS,
51 DO_SINDROPS,
52 DO_SINALL,
53 DO_SINFIFO,
54 DO_SINFRAME,
55 DO_SINCOMPRESSES,
56 DO_SINMULTICAST,
57 DO_SOUTALL,
58 DO_SOUTBYTES,
59 DO_SOUTPACKETS,
60 DO_SOUTERRORS,
61 DO_SOUTDROPS,
62 DO_SOUTFIFO,
63 DO_SOUTCOLLS,
64 DO_SOUTCARRIER,
65 DO_SOUTMULTICAST,
66 DO_PNETWORK,
67 DO_PHWADDRESS,
68 DO_BIPS,
69 DO_BOPS
72 struct if_stat {
73 unsigned long long in_packets, in_bytes, in_errors, in_drops;
74 unsigned long long in_fifo, in_frame, in_compress, in_multicast;
75 unsigned long long out_bytes, out_packets, out_errors, out_drops;
76 unsigned long long out_fifo, out_colls, out_carrier, out_multicast;
80 void print_quad_ipv4(in_addr_t i) {
81 i = ntohl(i);
82 printf("%d.%d.%d.%d",
83 (i & 0xff000000) >> 24,
84 (i & 0x00ff0000) >> 16,
85 (i & 0x0000ff00) >> 8,
86 (i & 0x000000ff));
89 void print_quad_ipv6(uint16_t *a) {
90 printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
91 a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
94 void print_quad(struct sockaddr *adr) {
95 switch (adr->sa_family) {
96 case AF_INET:
97 print_quad_ipv4(((struct sockaddr_in*)adr)->sin_addr.s_addr);
98 break;
99 case AF_INET6:
100 print_quad_ipv6(((struct sockaddr_in6*)adr)->sin6_addr.s6_addr16);
101 break;
102 default:
103 printf("NON-IP");
104 break;
108 enum print_error_enum {
109 PRINT_ERROR,
110 PRINT_NO_ERROR,
114 * return 0 success
115 * 1 error
117 static int do_socket_ioctl(const char *ifname, const unsigned long int request,
118 struct ifreq *req, int *ioctl_errno,
119 const enum print_error_enum print_error) {
120 int sock, res;
122 if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1)
123 return 1;
124 strncpy(req->ifr_name, ifname, IFNAMSIZ);
125 req->ifr_name[IFNAMSIZ - 1] = 0;
127 if ((res = ioctl(sock, request, req)) == -1) {
128 if (ioctl_errno)
129 *ioctl_errno = errno;
130 if (print_error == PRINT_ERROR) {
131 if (errno == ENODEV) {
132 fprintf(stderr, "No such network interface: %s\n", ifname);
133 exit(1);
135 else
136 fprintf(stderr, "ioctl on %s: %s\n", ifname,
137 strerror(errno));
139 close(sock);
140 return 1;
143 close(sock);
145 return 0;
148 int if_exists(const char *iface) {
149 struct ifreq r;
150 return !do_socket_ioctl(iface, SIOCGIFFLAGS, &r, NULL, PRINT_NO_ERROR);
153 #if defined(__linux__)
155 void if_flags(const char *iface) {
156 struct ifreq r;
157 unsigned int i;
158 const struct {
159 unsigned int flag;
160 char *name;
161 } flags[] = {
162 { IFF_UP, "Up" },
163 { IFF_BROADCAST, "Broadcast" },
164 { IFF_DEBUG, "Debugging" },
165 { IFF_LOOPBACK, "Loopback" },
166 { IFF_POINTOPOINT, "Ppp" },
167 { IFF_NOTRAILERS, "No-trailers" },
168 { IFF_RUNNING, "Running" },
169 { IFF_NOARP, "No-arp" },
170 { IFF_PROMISC, "Promiscuous" },
171 { IFF_ALLMULTI, "All-multicast" },
172 { IFF_MASTER, "Load-master" },
173 { IFF_SLAVE, "Load-slave" },
174 { IFF_MULTICAST, "Multicast" },
175 { IFF_PORTSEL, "Port-select" },
176 { IFF_AUTOMEDIA, "Auto-detect" },
177 { IFF_DYNAMIC, "Dynaddr" },
178 { 0xffff0000, "Unknown-flags" },
181 if (do_socket_ioctl(iface, SIOCGIFFLAGS, &r, NULL, PRINT_ERROR))
182 return;
184 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++)
185 printf("%s%s%s", (r.ifr_flags & flags[i].flag) ? "On " : "Off ",
186 flags[i].name,
187 sizeof(flags) / sizeof(flags[0]) - 1 == i ? "" : "\n");
190 void if_hwaddr(const char *iface) {
191 struct ifreq r;
192 unsigned char *hwaddr;
194 if (do_socket_ioctl(iface, SIOCGIFHWADDR, &r, NULL, PRINT_ERROR))
195 return;
197 hwaddr = (unsigned char *)r.ifr_hwaddr.sa_data;
198 printf("%02X:%02X:%02X:%02X:%02X:%02X",
199 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
202 #endif
204 static struct sockaddr *if_addr_value(const char *iface, struct ifreq *r,
205 unsigned long int request) {
206 int e;
208 if (do_socket_ioctl(iface, request, r, &e, PRINT_NO_ERROR)) {
209 if (e == EADDRNOTAVAIL)
210 return &r->ifr_addr;
211 return NULL;
213 return &r->ifr_addr;
216 struct sockaddr *if_addr(const char *iface, struct ifreq *r) {
217 return if_addr_value(iface, r, SIOCGIFADDR);
220 struct sockaddr *if_mask(const char *iface, struct ifreq *r) {
221 return if_addr_value(iface, r, SIOCGIFNETMASK);
224 struct sockaddr *if_bcast(const char *iface, struct ifreq *r) {
225 return if_addr_value(iface, r, SIOCGIFBRDADDR);
228 struct sockaddr *if_network(const char *iface) {
229 struct sockaddr *saddr;
230 static struct ifreq req;
231 unsigned int mask;
233 if (!(saddr = if_mask(iface, &req)))
234 return NULL;
236 mask = ((struct sockaddr_in*)saddr)->sin_addr.s_addr;
238 if (!(saddr = if_addr(iface, &req)))
239 return NULL;
241 ((struct sockaddr_in*)saddr)->sin_addr.s_addr &= mask;
242 return saddr;
245 int ifd_if_mtu(const char *iface) {
246 static struct ifreq req;
248 if (do_socket_ioctl(iface, SIOCGIFMTU, &req, NULL, PRINT_ERROR))
249 return 0;
251 return req.ifr_mtu;
254 #if defined(__linux__)
256 static void skipline(FILE *fd) {
257 int ch;
258 do {
259 ch = getc(fd);
260 } while (ch != '\n' && ch != EOF);
263 struct if_stat *get_stats(const char *iface) {
264 FILE *fd;
265 struct if_stat *ifstat;
266 char name[10];
268 if (!(ifstat = malloc(sizeof(struct if_stat)))) {
269 perror("malloc");
270 return NULL;
273 if ((fd = fopen("/proc/net/dev", "r")) == NULL) {
274 perror("fopen(\"/proc/net/dev\")");
275 free(ifstat);
276 return NULL;
279 /* Skip header */
280 skipline(fd);
281 skipline(fd);
283 do {
284 int items = fscanf(fd,
285 " %20[^:]:%llu %llu %llu %llu %llu %llu %llu %llu "
286 "%llu %llu %llu %llu %llu %llu %llu %llu",
287 name,
288 &ifstat->in_bytes, &ifstat->in_packets,
289 &ifstat->in_errors, &ifstat->in_drops,
290 &ifstat->in_fifo, &ifstat->in_frame,
291 &ifstat->in_compress, &ifstat->in_multicast,
292 &ifstat->out_bytes, &ifstat->out_packets,
293 &ifstat->out_errors, &ifstat->out_drops,
294 &ifstat->out_fifo, &ifstat->out_colls,
295 &ifstat->out_carrier, &ifstat->out_carrier
298 if (items == -1)
299 break;
300 if (items != 17) {
301 fprintf(stderr, "Invalid data read, check!\n");
302 break;
305 if (!strncmp(name, iface, sizeof(name))) {
306 fclose(fd);
307 return ifstat;
309 } while (!feof(fd));
311 fclose(fd);
312 free(ifstat);
313 return NULL;
316 #endif
318 const struct {
319 char *option;
320 unsigned int flag;
321 unsigned int is_stat;
322 char *description;
323 } options[] = {
324 { "-e", DO_EXISTS, 0, "Reports interface existence via return code" },
325 { "-p", DO_PALL, 0, "Print out the whole config of iface" },
326 { "-pe", DO_PEXISTS, 0, "Print out yes or no according to existence" },
327 { "-pa", DO_PADDRESS, 0, "Print out the address" },
328 { "-pn", DO_PMASK, 0, "Print netmask" },
329 { "-pN", DO_PNETWORK, 0, "Print network address" },
330 { "-pb", DO_PCAST, 0, "Print broadcast" },
331 { "-pm", DO_PMTU, 0, "Print mtu" },
332 #if defined(__linux__)
333 { "-ph", DO_PHWADDRESS, 0, "Print out the hardware address" },
334 { "-pf", DO_PFLAGS, 0, "Print flags" },
335 { "-si", DO_SINALL, 1, "Print all statistics on input" },
336 { "-sip", DO_SINPACKETS, 1, "Print # of in packets" },
337 { "-sib", DO_SINBYTES, 1, "Print # of in bytes" },
338 { "-sie", DO_SINERRORS, 1, "Print # of in errors" },
339 { "-sid", DO_SINDROPS, 1, "Print # of in drops" },
340 { "-sif", DO_SINFIFO, 1, "Print # of in fifo overruns" },
341 { "-sic", DO_SINCOMPRESSES, 1, "Print # of in compress" },
342 { "-sim", DO_SINMULTICAST, 1, "Print # of in multicast" },
343 { "-so", DO_SOUTALL, 1, "Print all statistics on output" },
344 { "-sop", DO_SOUTPACKETS, 1, "Print # of out packets" },
345 { "-sob", DO_SOUTBYTES, 1, "Print # of out bytes" },
346 { "-soe", DO_SOUTERRORS, 1, "Print # of out errors" },
347 { "-sod", DO_SOUTDROPS, 1, "Print # of out drops" },
348 { "-sof", DO_SOUTFIFO, 1, "Print # of out fifo overruns" },
349 { "-sox", DO_SOUTCOLLS, 1, "Print # of out collisions" },
350 { "-soc", DO_SOUTCARRIER, 1, "Print # of out carrier loss" },
351 { "-som", DO_SOUTMULTICAST, 1, "Print # of out multicast" },
352 { "-bips",DO_BIPS, 1, "Print # of incoming bytes per second" },
353 { "-bops",DO_BOPS, 1, "Print # of outgoing bytes per second" },
354 #endif
357 void usage(const char *name) {
358 unsigned int i;
360 fprintf(stderr, "Usage: %s [options] iface\n", name);
361 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
362 fprintf(stderr, " %5s %s\n",
363 options[i].option, options[i].description);
367 void add_do(int *ndo, int **todo, int act) {
368 *todo = realloc(*todo, (*ndo+1) * sizeof(int));
369 (*todo)[*ndo] = act;
370 *ndo += 1;
373 static void print_addr(struct sockaddr *sadr) {
374 if (!sadr) {
375 fprintf(stderr, "Error\n");
376 exit(1);
378 print_quad(sadr);
381 struct if_stat *ifstats, *ifstats2 = NULL;
383 void please_do(int ndo, int *todo, const char *ifname) {
384 int i;
385 int exists;
386 static struct ifreq req;
387 if (!ndo) return;
389 exists = if_exists(ifname);
391 // printf("I have %d items in my queue.\n",ndo);
392 for (i=0; i<ndo; i++) {
393 if (!exists &&
394 (todo[i] != DO_EXISTS) && (todo[i] != DO_PEXISTS)) {
395 fprintf(stderr, "No such network interface: %s\n", ifname);
396 exit(1);
399 switch (todo[i]) {
400 case DO_EXISTS:
401 exit(!exists);
402 case DO_PEXISTS:
403 printf("%s", exists ? "yes" : "no");
404 break;
405 case DO_PADDRESS:
406 print_addr(if_addr(ifname, &req));
407 break;
408 #if defined(__linux__)
409 case DO_PHWADDRESS:
410 if_hwaddr(ifname);
411 break;
412 case DO_PFLAGS:
413 if_flags(ifname);
414 break;
415 #endif
416 case DO_PMASK:
417 print_addr(if_mask(ifname, &req));
418 break;
419 case DO_PCAST:
420 print_addr(if_bcast(ifname, &req));
421 break;
422 case DO_PMTU:
423 printf("%d", ifd_if_mtu(ifname));
424 break;
425 case DO_PNETWORK:
426 print_addr(if_network(ifname));
427 break;
428 case DO_PALL:
429 print_addr(if_addr(ifname, &req));
430 printf(" ");
431 print_addr(if_mask(ifname, &req));
432 printf(" ");
433 print_addr(if_bcast(ifname, &req));
434 printf(" ");
435 printf("%d", ifd_if_mtu(ifname));
436 break;
437 #if defined(__linux__)
438 case DO_SINPACKETS:
439 printf("%llu",ifstats->in_packets);
440 break;
441 case DO_SINBYTES:
442 printf("%llu",ifstats->in_bytes);
443 break;
444 case DO_SINERRORS:
445 printf("%llu",ifstats->in_errors);
446 break;
447 case DO_SINDROPS:
448 printf("%llu",ifstats->in_drops);
449 break;
450 case DO_SINFIFO:
451 printf("%llu",ifstats->in_fifo);
452 break;
453 case DO_SINFRAME:
454 printf("%llu",ifstats->in_frame);
455 break;
456 case DO_SINCOMPRESSES:
457 printf("%llu",ifstats->in_compress);
458 break;
459 case DO_SINMULTICAST:
460 printf("%llu",ifstats->in_multicast);
461 break;
462 case DO_SINALL:
463 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
464 ifstats->in_bytes, ifstats->in_packets,
465 ifstats->in_errors, ifstats->in_drops,
466 ifstats->in_fifo, ifstats->in_frame,
467 ifstats->in_compress, ifstats->in_multicast);
468 break;
469 case DO_SOUTBYTES:
470 printf("%llu",ifstats->out_bytes);
471 break;
472 case DO_SOUTPACKETS:
473 printf("%llu",ifstats->out_packets);
474 break;
475 case DO_SOUTERRORS:
476 printf("%llu",ifstats->out_errors);
477 break;
478 case DO_SOUTDROPS:
479 printf("%llu",ifstats->out_drops);
480 break;
481 case DO_SOUTFIFO:
482 printf("%llu",ifstats->out_fifo);
483 break;
484 case DO_SOUTCOLLS:
485 printf("%llu",ifstats->out_colls);
486 break;
487 case DO_SOUTCARRIER:
488 printf("%llu",ifstats->out_carrier);
489 break;
490 case DO_SOUTMULTICAST:
491 printf("%llu",ifstats->out_multicast);
492 break;
493 case DO_BIPS:
494 if (ifstats2 == NULL) {
495 sleep(1);
496 ifstats2 = get_stats(ifname);
498 printf("%llu", ifstats2->in_bytes-ifstats->in_bytes);
499 break;
500 case DO_BOPS:
501 if (ifstats2 == NULL) {
502 sleep(1);
503 ifstats2 = get_stats(ifname);
505 printf("%llu", ifstats2->out_bytes-ifstats->out_bytes);
506 break;
507 case DO_SOUTALL:
508 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
509 ifstats->out_bytes, ifstats->out_packets,
510 ifstats->out_errors, ifstats->out_drops,
511 ifstats->out_fifo, ifstats->out_colls,
512 ifstats->out_carrier, ifstats->out_multicast);
513 break;
514 #endif
515 default:
516 printf("Unknown command: %d", todo[i]);
517 break;
519 printf("\n");
523 int main(int argc, char *argv[]) {
524 int ndo=0;
525 int *todo=NULL;
526 char *ifname=NULL;
527 int narg = 0;
528 int do_stats = 0;
529 unsigned int i, found;
531 if (argc == 1) {
532 usage(*argv);
533 return 1;
536 while (narg < argc - 1) {
537 narg++;
539 found = 0;
541 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
542 if (!strcmp(argv[narg], options[i].option)) {
543 add_do(&ndo, &todo, options[i].flag);
544 do_stats |= options[i].is_stat;
545 found = 1;
546 break;
550 if (found)
551 continue;
553 if (argv[narg][0] == '-') {
554 usage(*argv);
555 return 1;
557 else {
558 ifname = argv[narg];
559 break;
563 if (narg + 1 < argc || !ifname) {
564 usage(*argv);
565 return 1;
568 #if defined(__linux__)
569 if (do_stats && (ifstats = get_stats(ifname)) == NULL) {
570 fprintf(stderr, "Error getting statistics for %s\n", ifname);
571 return 1;
573 #endif
575 please_do(ndo, todo, ifname);
577 return 0;