prep release
[moreutils.git] / ifdata.c
blobadf9f8748240c9924718bc9af0433784efdcc936
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__)
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 fprintf(stderr, "ioctl on %s: %s\n", ifname, strerror(errno));
132 close(sock);
133 return 1;
136 close(sock);
138 return 0;
141 int if_exists(const char *iface) {
142 struct ifreq r;
143 return !do_socket_ioctl(iface, SIOCGIFFLAGS, &r, NULL, PRINT_NO_ERROR);
146 #if defined(__linux__)
148 void if_flags(const char *iface) {
149 struct ifreq r;
150 unsigned int i;
151 const struct {
152 unsigned int flag;
153 char *name;
154 } flags[] = {
155 { IFF_UP, "Up" },
156 { IFF_BROADCAST, "Broadcast" },
157 { IFF_DEBUG, "Debugging" },
158 { IFF_LOOPBACK, "Loopback" },
159 { IFF_POINTOPOINT, "Ppp" },
160 { IFF_NOTRAILERS, "No-trailers" },
161 { IFF_RUNNING, "Running" },
162 { IFF_NOARP, "No-arp" },
163 { IFF_PROMISC, "Promiscuous" },
164 { IFF_ALLMULTI, "All-multicast" },
165 { IFF_MASTER, "Load-master" },
166 { IFF_SLAVE, "Load-slave" },
167 { IFF_MULTICAST, "Multicast" },
168 { IFF_PORTSEL, "Port-select" },
169 { IFF_AUTOMEDIA, "Auto-detect" },
170 { IFF_DYNAMIC, "Dynaddr" },
171 { 0xffff0000, "Unknown-flags" },
174 if (do_socket_ioctl(iface, SIOCGIFFLAGS, &r, NULL, PRINT_ERROR))
175 return;
177 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++)
178 printf("%s%s%s", (r.ifr_flags & flags[i].flag) ? "On " : "Off ",
179 flags[i].name,
180 sizeof(flags) / sizeof(flags[0]) - 1 == i ? "" : "\n");
183 void if_hwaddr(const char *iface) {
184 struct ifreq r;
185 unsigned char *hwaddr;
187 if (do_socket_ioctl(iface, SIOCGIFHWADDR, &r, NULL, PRINT_ERROR))
188 return;
190 hwaddr = (unsigned char *)r.ifr_hwaddr.sa_data;
191 printf("%02X:%02X:%02X:%02X:%02X:%02X",
192 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
195 #endif
197 static struct sockaddr *if_addr_value(const char *iface, struct ifreq *r,
198 unsigned long int request) {
199 int e;
201 if (do_socket_ioctl(iface, request, r, &e, PRINT_NO_ERROR)) {
202 if (e == EADDRNOTAVAIL)
203 return &r->ifr_addr;
204 return NULL;
206 return &r->ifr_addr;
209 struct sockaddr *if_addr(const char *iface, struct ifreq *r) {
210 return if_addr_value(iface, r, SIOCGIFADDR);
213 struct sockaddr *if_mask(const char *iface, struct ifreq *r) {
214 return if_addr_value(iface, r, SIOCGIFNETMASK);
217 struct sockaddr *if_bcast(const char *iface, struct ifreq *r) {
218 return if_addr_value(iface, r, SIOCGIFBRDADDR);
221 struct sockaddr *if_network(const char *iface) {
222 struct sockaddr *saddr;
223 static struct ifreq req;
224 unsigned int mask;
226 if (!(saddr = if_mask(iface, &req)))
227 return NULL;
229 mask = ((struct sockaddr_in*)saddr)->sin_addr.s_addr;
231 if (!(saddr = if_addr(iface, &req)))
232 return NULL;
234 ((struct sockaddr_in*)saddr)->sin_addr.s_addr &= mask;
235 return saddr;
238 int if_mtu(const char *iface) {
239 static struct ifreq req;
241 if (do_socket_ioctl(iface, SIOCGIFMTU, &req, NULL, PRINT_ERROR))
242 return 0;
244 return req.ifr_mtu;
247 #if defined(__linux__)
249 static void skipline(FILE *fd) {
250 int ch;
251 do {
252 ch = getc(fd);
253 } while (ch != '\n' && ch != EOF);
256 struct if_stat *get_stats(const char *iface) {
257 FILE *fd;
258 struct if_stat *ifstat;
259 char name[10];
261 if (!(ifstat = malloc(sizeof(struct if_stat)))) {
262 perror("malloc");
263 return NULL;
266 if ((fd = fopen("/proc/net/dev", "r")) == NULL) {
267 perror("fopen(\"/proc/net/dev\")");
268 free(ifstat);
269 return NULL;
272 /* Skip header */
273 skipline(fd);
274 skipline(fd);
276 do {
277 int items = fscanf(fd,
278 " %20[^:]:%llu %llu %llu %llu %llu %llu %llu %llu "
279 "%llu %llu %llu %llu %llu %llu %llu %llu",
280 name,
281 &ifstat->in_bytes, &ifstat->in_packets,
282 &ifstat->in_errors, &ifstat->in_drops,
283 &ifstat->in_fifo, &ifstat->in_frame,
284 &ifstat->in_compress, &ifstat->in_multicast,
285 &ifstat->out_bytes, &ifstat->out_packets,
286 &ifstat->out_errors, &ifstat->out_drops,
287 &ifstat->out_fifo, &ifstat->out_colls,
288 &ifstat->out_carrier, &ifstat->out_carrier
291 if (items == -1)
292 break;
293 if (items != 17) {
294 fprintf(stderr, "Invalid data read, check!\n");
295 break;
298 if (!strncmp(name, iface, sizeof(name))) {
299 fclose(fd);
300 return ifstat;
302 } while (!feof(fd));
304 fclose(fd);
305 free(ifstat);
306 return NULL;
309 #endif
311 const struct {
312 char *option;
313 unsigned int flag;
314 unsigned int is_stat;
315 char *description;
316 } options[] = {
317 { "-e", DO_EXISTS, 0, "Reports interface existence via return code" },
318 { "-p", DO_PALL, 0, "Print out the whole config of iface" },
319 { "-pe", DO_PEXISTS, 0, "Print out yes or no according to existence" },
320 { "-pa", DO_PADDRESS, 0, "Print out the address" },
321 { "-pn", DO_PMASK, 0, "Print netmask" },
322 { "-pN", DO_PNETWORK, 0, "Print network address" },
323 { "-pb", DO_PCAST, 0, "Print broadcast" },
324 { "-pm", DO_PMTU, 0, "Print mtu" },
325 #if defined(__linux__)
326 { "-ph", DO_PHWADDRESS, 0, "Print out the hardware address" },
327 { "-pf", DO_PFLAGS, 0, "Print flags" },
328 { "-si", DO_SINALL, 1, "Print all statistics on input" },
329 { "-sip", DO_SINPACKETS, 1, "Print # of in packets" },
330 { "-sib", DO_SINBYTES, 1, "Print # of in bytes" },
331 { "-sie", DO_SINERRORS, 1, "Print # of in errors" },
332 { "-sid", DO_SINDROPS, 1, "Print # of in drops" },
333 { "-sif", DO_SINFIFO, 1, "Print # of in fifo overruns" },
334 { "-sic", DO_SINCOMPRESSES, 1, "Print # of in compress" },
335 { "-sim", DO_SINMULTICAST, 1, "Print # of in multicast" },
336 { "-so", DO_SOUTALL, 1, "Print all statistics on output" },
337 { "-sop", DO_SOUTPACKETS, 1, "Print # of out packets" },
338 { "-sob", DO_SOUTBYTES, 1, "Print # of out bytes" },
339 { "-soe", DO_SOUTERRORS, 1, "Print # of out errors" },
340 { "-sod", DO_SOUTDROPS, 1, "Print # of out drops" },
341 { "-sof", DO_SOUTFIFO, 1, "Print # of out fifo overruns" },
342 { "-sox", DO_SOUTCOLLS, 1, "Print # of out collisions" },
343 { "-soc", DO_SOUTCARRIER, 1, "Print # of out carrier loss" },
344 { "-som", DO_SOUTMULTICAST, 1, "Print # of out multicast" },
345 { "-bips",DO_BIPS, 1, "Print # of incoming bytes per second" },
346 { "-bops",DO_BOPS, 1, "Print # of outgoing bytes per second" },
347 #endif
350 void usage(const char *name) {
351 unsigned int i;
353 fprintf(stderr, "Usage: %s [options] iface\n", name);
354 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
355 fprintf(stderr, " %5s %s\n",
356 options[i].option, options[i].description);
360 void add_do(int *ndo, int **todo, int act) {
361 *todo = realloc(*todo, (*ndo+1) * sizeof(int));
362 (*todo)[*ndo] = act;
363 *ndo += 1;
366 static void print_addr(struct sockaddr *sadr) {
367 if (!sadr) {
368 fprintf(stderr, "Error\n");
369 exit(1);
371 print_quad(sadr);
374 struct if_stat *ifstats, *ifstats2 = NULL;
376 void please_do(int ndo, int *todo, const char *ifname) {
377 int i;
378 static struct ifreq req;
379 if (!ndo) return;
380 // printf("I have %d items in my queue.\n",ndo);
381 for (i=0; i<ndo; i++) {
382 switch (todo[i]) {
383 case DO_EXISTS:
384 exit(!if_exists(ifname));
385 case DO_PEXISTS:
386 printf("%s", if_exists(ifname) ? "yes" : "no");
387 break;
388 case DO_PADDRESS:
389 print_addr(if_addr(ifname, &req));
390 break;
391 #if defined(__linux__)
392 case DO_PHWADDRESS:
393 if_hwaddr(ifname);
394 break;
395 case DO_PFLAGS:
396 if_flags(ifname);
397 break;
398 #endif
399 case DO_PMASK:
400 print_addr(if_mask(ifname, &req));
401 break;
402 case DO_PCAST:
403 print_addr(if_bcast(ifname, &req));
404 break;
405 case DO_PMTU:
406 printf("%d", if_mtu(ifname));
407 break;
408 case DO_PNETWORK:
409 print_addr(if_network(ifname));
410 break;
411 case DO_PALL:
412 print_addr(if_addr(ifname, &req));
413 printf(" ");
414 print_addr(if_mask(ifname, &req));
415 printf(" ");
416 print_addr(if_bcast(ifname, &req));
417 printf(" ");
418 printf("%d", if_mtu(ifname));
419 break;
420 #if defined(__linux__)
421 case DO_SINPACKETS:
422 printf("%llu",ifstats->in_packets);
423 break;
424 case DO_SINBYTES:
425 printf("%llu",ifstats->in_bytes);
426 break;
427 case DO_SINERRORS:
428 printf("%llu",ifstats->in_errors);
429 break;
430 case DO_SINDROPS:
431 printf("%llu",ifstats->in_drops);
432 break;
433 case DO_SINFIFO:
434 printf("%llu",ifstats->in_fifo);
435 break;
436 case DO_SINFRAME:
437 printf("%llu",ifstats->in_frame);
438 break;
439 case DO_SINCOMPRESSES:
440 printf("%llu",ifstats->in_compress);
441 break;
442 case DO_SINMULTICAST:
443 printf("%llu",ifstats->in_multicast);
444 break;
445 case DO_SINALL:
446 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
447 ifstats->in_bytes, ifstats->in_packets,
448 ifstats->in_errors, ifstats->in_drops,
449 ifstats->in_fifo, ifstats->in_frame,
450 ifstats->in_compress, ifstats->in_multicast);
451 break;
452 case DO_SOUTBYTES:
453 printf("%llu",ifstats->out_bytes);
454 break;
455 case DO_SOUTPACKETS:
456 printf("%llu",ifstats->out_packets);
457 break;
458 case DO_SOUTERRORS:
459 printf("%llu",ifstats->out_errors);
460 break;
461 case DO_SOUTDROPS:
462 printf("%llu",ifstats->out_drops);
463 break;
464 case DO_SOUTFIFO:
465 printf("%llu",ifstats->out_fifo);
466 break;
467 case DO_SOUTCOLLS:
468 printf("%llu",ifstats->out_colls);
469 break;
470 case DO_SOUTCARRIER:
471 printf("%llu",ifstats->out_carrier);
472 break;
473 case DO_SOUTMULTICAST:
474 printf("%llu",ifstats->out_multicast);
475 break;
476 case DO_BIPS:
477 if (ifstats2 == NULL) {
478 sleep(1);
479 ifstats2 = get_stats(ifname);
481 printf("%llu", ifstats2->in_bytes-ifstats->in_bytes);
482 break;
483 case DO_BOPS:
484 if (ifstats2 == NULL) {
485 sleep(1);
486 ifstats2 = get_stats(ifname);
488 printf("%llu", ifstats2->out_bytes-ifstats->out_bytes);
489 break;
490 case DO_SOUTALL:
491 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
492 ifstats->out_bytes, ifstats->out_packets,
493 ifstats->out_errors, ifstats->out_drops,
494 ifstats->out_fifo, ifstats->out_colls,
495 ifstats->out_carrier, ifstats->out_multicast);
496 break;
497 #endif
498 default:
499 printf("Unknown command: %d", todo[i]);
500 break;
502 printf("\n");
506 int main(int argc, char *argv[]) {
507 int ndo=0;
508 int *todo=NULL;
509 char *ifname=NULL;
510 int narg = 0;
511 int do_stats = 0;
512 unsigned int i, found;
514 if (argc == 1) {
515 usage(*argv);
516 return 1;
519 while (narg < argc - 1) {
520 narg++;
522 found = 0;
524 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
525 if (!strcmp(argv[narg], options[i].option)) {
526 add_do(&ndo, &todo, options[i].flag);
527 do_stats |= options[i].is_stat;
528 found = 1;
529 break;
533 if (found)
534 continue;
536 if (argv[narg][0] == '-') {
537 usage(*argv);
538 return 1;
540 else {
541 ifname = argv[narg];
542 break;
546 if (narg + 1 < argc || !ifname) {
547 usage(*argv);
548 return 1;
551 #if defined(__linux__)
552 if (do_stats && (ifstats = get_stats(ifname)) == NULL) {
553 fprintf(stderr, "Error getting statistics for %s\n", ifname);
554 return 1;
556 #endif
558 please_do(ndo, todo, ifname);
560 return 0;