Makefile: Warn users of pkgx.dev about their poor life choices
[moreutils.git] / ifdata.c
blob6e0bd0b1052ec0f4abce5b64e0455b6cae5a906b
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;
199 if (!hwaddr[0] && !hwaddr[1] && !hwaddr[2] &&
200 !hwaddr[3] && !hwaddr[4] && !hwaddr[5]) {
201 fprintf(stderr, "Error: %s: no hardware address\n", iface);
202 exit(1);
205 printf("%02X:%02X:%02X:%02X:%02X:%02X",
206 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
209 #endif
211 static struct sockaddr *if_addr_value(const char *iface, struct ifreq *r,
212 unsigned long int request) {
213 int e;
215 if (do_socket_ioctl(iface, request, r, &e, PRINT_NO_ERROR)) {
216 if (e == EADDRNOTAVAIL)
217 return &r->ifr_addr;
218 return NULL;
220 return &r->ifr_addr;
223 struct sockaddr *if_addr(const char *iface, struct ifreq *r) {
224 return if_addr_value(iface, r, SIOCGIFADDR);
227 struct sockaddr *if_mask(const char *iface, struct ifreq *r) {
228 return if_addr_value(iface, r, SIOCGIFNETMASK);
231 struct sockaddr *if_bcast(const char *iface, struct ifreq *r) {
232 return if_addr_value(iface, r, SIOCGIFBRDADDR);
235 struct sockaddr *if_network(const char *iface) {
236 struct sockaddr *saddr;
237 static struct ifreq req;
238 unsigned int mask;
240 if (!(saddr = if_mask(iface, &req)))
241 return NULL;
243 mask = ((struct sockaddr_in*)saddr)->sin_addr.s_addr;
245 if (!(saddr = if_addr(iface, &req)))
246 return NULL;
248 ((struct sockaddr_in*)saddr)->sin_addr.s_addr &= mask;
249 return saddr;
252 int ifd_if_mtu(const char *iface) {
253 static struct ifreq req;
255 if (do_socket_ioctl(iface, SIOCGIFMTU, &req, NULL, PRINT_ERROR))
256 return 0;
258 return req.ifr_mtu;
261 #if defined(__linux__)
263 static void skipline(FILE *fd) {
264 int ch;
265 do {
266 ch = getc(fd);
267 } while (ch != '\n' && ch != EOF);
270 struct if_stat *get_stats(const char *iface) {
271 FILE *fd;
272 struct if_stat *ifstat;
273 char name[10];
275 if (!(ifstat = malloc(sizeof(struct if_stat)))) {
276 perror("malloc");
277 return NULL;
280 if ((fd = fopen("/proc/net/dev", "r")) == NULL) {
281 perror("fopen(\"/proc/net/dev\")");
282 free(ifstat);
283 return NULL;
286 /* Skip header */
287 skipline(fd);
288 skipline(fd);
290 do {
291 int items = fscanf(fd,
292 " %20[^:]:%llu %llu %llu %llu %llu %llu %llu %llu "
293 "%llu %llu %llu %llu %llu %llu %llu %llu",
294 name,
295 &ifstat->in_bytes, &ifstat->in_packets,
296 &ifstat->in_errors, &ifstat->in_drops,
297 &ifstat->in_fifo, &ifstat->in_frame,
298 &ifstat->in_compress, &ifstat->in_multicast,
299 &ifstat->out_bytes, &ifstat->out_packets,
300 &ifstat->out_errors, &ifstat->out_drops,
301 &ifstat->out_fifo, &ifstat->out_colls,
302 &ifstat->out_carrier, &ifstat->out_carrier
305 if (items == -1)
306 break;
307 if (items != 17) {
308 fprintf(stderr, "Invalid data read, check!\n");
309 break;
312 if (!strncmp(name, iface, sizeof(name))) {
313 fclose(fd);
314 return ifstat;
316 } while (!feof(fd));
318 fclose(fd);
319 free(ifstat);
320 return NULL;
323 #endif
325 const struct {
326 char *option;
327 unsigned int flag;
328 unsigned int is_stat;
329 char *description;
330 } options[] = {
331 { "-e", DO_EXISTS, 0, "Reports interface existence via return code" },
332 { "-p", DO_PALL, 0, "Print out the whole config of iface" },
333 { "-pe", DO_PEXISTS, 0, "Print out yes or no according to existence" },
334 { "-pa", DO_PADDRESS, 0, "Print out the address" },
335 { "-pn", DO_PMASK, 0, "Print netmask" },
336 { "-pN", DO_PNETWORK, 0, "Print network address" },
337 { "-pb", DO_PCAST, 0, "Print broadcast" },
338 { "-pm", DO_PMTU, 0, "Print mtu" },
339 #if defined(__linux__)
340 { "-ph", DO_PHWADDRESS, 0, "Print out the hardware address" },
341 { "-pf", DO_PFLAGS, 0, "Print flags" },
342 { "-si", DO_SINALL, 1, "Print all statistics on input" },
343 { "-sip", DO_SINPACKETS, 1, "Print # of in packets" },
344 { "-sib", DO_SINBYTES, 1, "Print # of in bytes" },
345 { "-sie", DO_SINERRORS, 1, "Print # of in errors" },
346 { "-sid", DO_SINDROPS, 1, "Print # of in drops" },
347 { "-sif", DO_SINFIFO, 1, "Print # of in fifo overruns" },
348 { "-sic", DO_SINCOMPRESSES, 1, "Print # of in compress" },
349 { "-sim", DO_SINMULTICAST, 1, "Print # of in multicast" },
350 { "-so", DO_SOUTALL, 1, "Print all statistics on output" },
351 { "-sop", DO_SOUTPACKETS, 1, "Print # of out packets" },
352 { "-sob", DO_SOUTBYTES, 1, "Print # of out bytes" },
353 { "-soe", DO_SOUTERRORS, 1, "Print # of out errors" },
354 { "-sod", DO_SOUTDROPS, 1, "Print # of out drops" },
355 { "-sof", DO_SOUTFIFO, 1, "Print # of out fifo overruns" },
356 { "-sox", DO_SOUTCOLLS, 1, "Print # of out collisions" },
357 { "-soc", DO_SOUTCARRIER, 1, "Print # of out carrier loss" },
358 { "-som", DO_SOUTMULTICAST, 1, "Print # of out multicast" },
359 { "-bips",DO_BIPS, 1, "Print # of incoming bytes per second" },
360 { "-bops",DO_BOPS, 1, "Print # of outgoing bytes per second" },
361 #endif
364 void usage(const char *name) {
365 unsigned int i;
367 fprintf(stderr, "Usage: %s [options] iface\n", name);
368 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
369 fprintf(stderr, " %5s %s\n",
370 options[i].option, options[i].description);
374 void add_do(int *ndo, int **todo, int act) {
375 *todo = realloc(*todo, (*ndo+1) * sizeof(int));
376 (*todo)[*ndo] = act;
377 *ndo += 1;
380 static void print_addr(struct sockaddr *sadr) {
381 if (!sadr) {
382 fprintf(stderr, "Error\n");
383 exit(1);
385 print_quad(sadr);
388 struct if_stat *ifstats, *ifstats2 = NULL;
390 void please_do(int ndo, int *todo, const char *ifname) {
391 int i;
392 int exists;
393 static struct ifreq req;
394 if (!ndo) return;
396 exists = if_exists(ifname);
398 // printf("I have %d items in my queue.\n",ndo);
399 for (i=0; i<ndo; i++) {
400 if (!exists &&
401 (todo[i] != DO_EXISTS) && (todo[i] != DO_PEXISTS)) {
402 fprintf(stderr, "No such network interface: %s\n", ifname);
403 exit(1);
406 switch (todo[i]) {
407 case DO_EXISTS:
408 exit(!exists);
409 case DO_PEXISTS:
410 printf("%s", exists ? "yes" : "no");
411 break;
412 case DO_PADDRESS:
413 print_addr(if_addr(ifname, &req));
414 break;
415 #if defined(__linux__)
416 case DO_PHWADDRESS:
417 if_hwaddr(ifname);
418 break;
419 case DO_PFLAGS:
420 if_flags(ifname);
421 break;
422 #endif
423 case DO_PMASK:
424 print_addr(if_mask(ifname, &req));
425 break;
426 case DO_PCAST:
427 print_addr(if_bcast(ifname, &req));
428 break;
429 case DO_PMTU:
430 printf("%d", ifd_if_mtu(ifname));
431 break;
432 case DO_PNETWORK:
433 print_addr(if_network(ifname));
434 break;
435 case DO_PALL:
436 print_addr(if_addr(ifname, &req));
437 printf(" ");
438 print_addr(if_mask(ifname, &req));
439 printf(" ");
440 print_addr(if_bcast(ifname, &req));
441 printf(" ");
442 printf("%d", ifd_if_mtu(ifname));
443 break;
444 #if defined(__linux__)
445 case DO_SINPACKETS:
446 printf("%llu",ifstats->in_packets);
447 break;
448 case DO_SINBYTES:
449 printf("%llu",ifstats->in_bytes);
450 break;
451 case DO_SINERRORS:
452 printf("%llu",ifstats->in_errors);
453 break;
454 case DO_SINDROPS:
455 printf("%llu",ifstats->in_drops);
456 break;
457 case DO_SINFIFO:
458 printf("%llu",ifstats->in_fifo);
459 break;
460 case DO_SINFRAME:
461 printf("%llu",ifstats->in_frame);
462 break;
463 case DO_SINCOMPRESSES:
464 printf("%llu",ifstats->in_compress);
465 break;
466 case DO_SINMULTICAST:
467 printf("%llu",ifstats->in_multicast);
468 break;
469 case DO_SINALL:
470 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
471 ifstats->in_bytes, ifstats->in_packets,
472 ifstats->in_errors, ifstats->in_drops,
473 ifstats->in_fifo, ifstats->in_frame,
474 ifstats->in_compress, ifstats->in_multicast);
475 break;
476 case DO_SOUTBYTES:
477 printf("%llu",ifstats->out_bytes);
478 break;
479 case DO_SOUTPACKETS:
480 printf("%llu",ifstats->out_packets);
481 break;
482 case DO_SOUTERRORS:
483 printf("%llu",ifstats->out_errors);
484 break;
485 case DO_SOUTDROPS:
486 printf("%llu",ifstats->out_drops);
487 break;
488 case DO_SOUTFIFO:
489 printf("%llu",ifstats->out_fifo);
490 break;
491 case DO_SOUTCOLLS:
492 printf("%llu",ifstats->out_colls);
493 break;
494 case DO_SOUTCARRIER:
495 printf("%llu",ifstats->out_carrier);
496 break;
497 case DO_SOUTMULTICAST:
498 printf("%llu",ifstats->out_multicast);
499 break;
500 case DO_BIPS:
501 if (ifstats2 == NULL) {
502 sleep(1);
503 ifstats2 = get_stats(ifname);
505 printf("%llu", ifstats2->in_bytes-ifstats->in_bytes);
506 break;
507 case DO_BOPS:
508 if (ifstats2 == NULL) {
509 sleep(1);
510 ifstats2 = get_stats(ifname);
512 printf("%llu", ifstats2->out_bytes-ifstats->out_bytes);
513 break;
514 case DO_SOUTALL:
515 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
516 ifstats->out_bytes, ifstats->out_packets,
517 ifstats->out_errors, ifstats->out_drops,
518 ifstats->out_fifo, ifstats->out_colls,
519 ifstats->out_carrier, ifstats->out_multicast);
520 break;
521 #endif
522 default:
523 printf("Unknown command: %d", todo[i]);
524 break;
526 printf("\n");
530 int main(int argc, char *argv[]) {
531 int ndo=0;
532 int *todo=NULL;
533 char *ifname=NULL;
534 int narg = 0;
535 int do_stats = 0;
536 unsigned int i, found;
538 if (argc == 1) {
539 usage(*argv);
540 return 1;
543 while (narg < argc - 1) {
544 narg++;
546 found = 0;
548 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
549 if (!strcmp(argv[narg], options[i].option)) {
550 add_do(&ndo, &todo, options[i].flag);
551 do_stats |= options[i].is_stat;
552 found = 1;
553 break;
557 if (found)
558 continue;
560 if (argv[narg][0] == '-') {
561 usage(*argv);
562 return 1;
564 else {
565 ifname = argv[narg];
566 break;
570 if (narg + 1 < argc || !ifname) {
571 usage(*argv);
572 return 1;
575 #if defined(__linux__)
576 if (do_stats && (ifstats = get_stats(ifname)) == NULL) {
577 fprintf(stderr, "Error getting statistics for %s\n", ifname);
578 return 1;
580 #endif
582 please_do(ndo, todo, ifname);
584 return 0;