releasing version 0.20
[moreutils.git] / ifdata.c
blob2fd4b5160c235cf18fbe7ce7708fcbb55484dac2
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>
16 enum {
17 DO_EXISTS = 1,
18 DO_PEXISTS,
19 DO_PADDRESS,
20 DO_PMASK,
21 DO_PMTU,
22 DO_PCAST,
23 DO_PALL,
24 DO_PFLAGS,
25 DO_SINPACKETS,
26 DO_SINBYTES,
27 DO_SINERRORS,
28 DO_SINDROPS,
29 DO_SINALL,
30 DO_SINFIFO,
31 DO_SINFRAME,
32 DO_SINCOMPRESSES,
33 DO_SINMULTICAST,
34 DO_SOUTALL,
35 DO_SOUTBYTES,
36 DO_SOUTPACKETS,
37 DO_SOUTERRORS,
38 DO_SOUTDROPS,
39 DO_SOUTFIFO,
40 DO_SOUTCOLLS,
41 DO_SOUTCARRIER,
42 DO_SOUTMULTICAST,
43 DO_PNETWORK,
44 DO_PHWADDRESS,
45 DO_BIPS,
46 DO_BOPS
49 struct if_stat {
50 unsigned long long in_packets, in_bytes, in_errors, in_drops;
51 unsigned long long in_fifo, in_frame, in_compress, in_multicast;
52 unsigned long long out_bytes, out_packets, out_errors, out_drops;
53 unsigned long long out_fifo, out_colls, out_carrier, out_multicast;
57 void print_quad_ipv4(in_addr_t i) {
58 i = ntohl(i);
59 printf("%d.%d.%d.%d",
60 (i & 0xff000000) >> 24,
61 (i & 0x00ff0000) >> 16,
62 (i & 0x0000ff00) >> 8,
63 (i & 0x000000ff));
66 void print_quad_ipv6(uint16_t *a) {
67 printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
68 a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
71 void print_quad(struct sockaddr *adr) {
72 switch (adr->sa_family) {
73 case AF_INET:
74 print_quad_ipv4(((struct sockaddr_in*)adr)->sin_addr.s_addr);
75 break;
76 case AF_INET6:
77 print_quad_ipv6(((struct sockaddr_in6*)adr)->sin6_addr.s6_addr16);
78 break;
79 default:
80 printf("NON-IP");
81 break;
85 enum print_error_enum {
86 PRINT_ERROR,
87 PRINT_NO_ERROR,
90 /**
91 * return 0 success
92 * 1 error
94 static int do_socket_ioctl(const char *ifname, const int request,
95 struct ifreq *req, int *ioctl_errno,
96 const enum print_error_enum print_error) {
97 int sock, res;
99 if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1)
100 return 1;
101 strncpy(req->ifr_name, ifname, IFNAMSIZ);
102 req->ifr_name[IFNAMSIZ - 1] = 0;
104 if ((res = ioctl(sock, request, req)) == -1) {
105 if (ioctl_errno)
106 *ioctl_errno = errno;
107 if (print_error == PRINT_ERROR)
108 fprintf(stderr, "ioctl on %s: %s\n", ifname, strerror(errno));
109 close(sock);
110 return 1;
113 close(sock);
115 return 0;
118 int if_exists(const char *iface) {
119 struct ifreq r;
120 return !do_socket_ioctl(iface, SIOCGIFFLAGS, &r, NULL, PRINT_NO_ERROR);
123 void if_flags(const char *iface) {
124 struct ifreq r;
125 unsigned int i;
126 const struct {
127 unsigned int flag;
128 char *name;
129 } flags[] = {
130 { IFF_UP, "Up" },
131 { IFF_BROADCAST, "Broadcast" },
132 { IFF_DEBUG, "Debugging" },
133 { IFF_LOOPBACK, "Loopback" },
134 { IFF_POINTOPOINT, "Ppp" },
135 { IFF_NOTRAILERS, "No-trailers" },
136 { IFF_RUNNING, "Running" },
137 { IFF_NOARP, "No-arp" },
138 { IFF_PROMISC, "Promiscuous" },
139 { IFF_ALLMULTI, "All-multicast" },
140 { IFF_MASTER, "Load-master" },
141 { IFF_SLAVE, "Load-slave" },
142 { IFF_MULTICAST, "Multicast" },
143 { IFF_PORTSEL, "Port-select" },
144 { IFF_AUTOMEDIA, "Auto-detect" },
145 { IFF_DYNAMIC, "Dynaddr" },
146 { 0xffff0000, "Unknown-flags" },
149 if (do_socket_ioctl(iface, SIOCGIFFLAGS, &r, NULL, PRINT_ERROR))
150 return;
152 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++)
153 printf("%s%s%s", (r.ifr_flags & flags[i].flag) ? "On " : "Off ",
154 flags[i].name,
155 sizeof(flags) / sizeof(flags[0]) - 1 == i ? "" : "\n");
158 void if_hwaddr(const char *iface) {
159 struct ifreq r;
160 unsigned char *hwaddr;
162 if (do_socket_ioctl(iface, SIOCGIFHWADDR, &r, NULL, PRINT_ERROR))
163 return;
165 hwaddr = (unsigned char *)r.ifr_hwaddr.sa_data;
166 printf("%02X:%02X:%02X:%02X:%02X:%02X",
167 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
170 static struct sockaddr *if_addr_value(const char *iface, struct ifreq *r,
171 int request) {
172 int e;
174 if (do_socket_ioctl(iface, request, r, &e, PRINT_NO_ERROR)) {
175 if (e == EADDRNOTAVAIL)
176 return &r->ifr_addr;
177 return NULL;
179 return &r->ifr_addr;
182 struct sockaddr *if_addr(const char *iface, struct ifreq *r) {
183 return if_addr_value(iface, r, SIOCGIFADDR);
186 struct sockaddr *if_mask(const char *iface, struct ifreq *r) {
187 return if_addr_value(iface, r, SIOCGIFNETMASK);
190 struct sockaddr *if_bcast(const char *iface, struct ifreq *r) {
191 return if_addr_value(iface, r, SIOCGIFBRDADDR);
194 struct sockaddr *if_network(const char *iface) {
195 struct sockaddr *saddr;
196 struct ifreq req;
197 unsigned int mask;
199 if (!(saddr = if_mask(iface, &req)))
200 return NULL;
202 mask = ((struct sockaddr_in*)saddr)->sin_addr.s_addr;
204 if (!(saddr = if_addr(iface, &req)))
205 return NULL;
207 ((struct sockaddr_in*)saddr)->sin_addr.s_addr &= mask;
208 return saddr;
211 int if_mtu(const char *iface) {
212 struct ifreq req;
214 if (do_socket_ioctl(iface, SIOCGIFMTU, &req, NULL, PRINT_ERROR))
215 return 0;
217 return req.ifr_mtu;
220 static void skipline(FILE *fd) {
221 int ch;
222 do {
223 ch = getc(fd);
224 } while (ch != '\n' && ch != EOF);
227 struct if_stat *get_stats(const char *iface) {
228 FILE *fd;
229 struct if_stat *ifstat;
230 char name[10];
232 if (!(ifstat = malloc(sizeof(struct if_stat)))) {
233 perror("malloc");
234 return NULL;
237 if ((fd = fopen("/proc/net/dev", "r")) == NULL) {
238 perror("fopen(\"/proc/net/dev\")");
239 free(ifstat);
240 return NULL;
243 /* Skip header */
244 skipline(fd);
245 skipline(fd);
247 do {
248 int items = fscanf(fd,
249 " %6[^:]:%llu %llu %llu %llu %llu %llu %llu %llu "
250 "%llu %llu %llu %llu %llu %llu %llu %llu",
251 name,
252 &ifstat->in_bytes, &ifstat->in_packets,
253 &ifstat->in_errors, &ifstat->in_drops,
254 &ifstat->in_fifo, &ifstat->in_frame,
255 &ifstat->in_compress, &ifstat->in_multicast,
256 &ifstat->out_bytes, &ifstat->out_packets,
257 &ifstat->out_errors, &ifstat->out_drops,
258 &ifstat->out_fifo, &ifstat->out_colls,
259 &ifstat->out_carrier, &ifstat->out_carrier
262 if (items == -1)
263 break;
264 if (items != 17) {
265 fprintf(stderr, "Invalid data read, check!\n");
266 break;
269 if (!strncmp(name, iface, sizeof(name))) {
270 fclose(fd);
271 return ifstat;
273 } while (!feof(fd));
275 fclose(fd);
276 free(ifstat);
277 return NULL;
280 const struct {
281 char *option;
282 unsigned int flag;
283 unsigned int is_stat;
284 char *description;
285 } options[] = {
286 { "-e", DO_EXISTS, 0, "Reports interface existence via return code" },
287 { "-p", DO_PALL, 0, "Print out the whole config of iface" },
288 { "-pe", DO_PEXISTS, 0, "Print out yes or no according to existence" },
289 { "-ph", DO_PHWADDRESS, 0, "Print out the hardware address" },
290 { "-pa", DO_PADDRESS, 0, "Print out the address" },
291 { "-pn", DO_PMASK, 0, "Print netmask" },
292 { "-pN", DO_PNETWORK, 0, "Print network address" },
293 { "-pb", DO_PCAST, 0, "Print broadcast" },
294 { "-pm", DO_PMTU, 0, "Print mtu" },
295 { "-pf", DO_PFLAGS, 0, "Print flags" },
297 { "-si", DO_SINALL, 1, "Print all statistics on input" },
298 { "-sip", DO_SINPACKETS, 1, "Print # of in packets" },
299 { "-sib", DO_SINBYTES, 1, "Print # of in bytes" },
300 { "-sie", DO_SINERRORS, 1, "Print # of in errors" },
301 { "-sid", DO_SINDROPS, 1, "Print # of in drops" },
302 { "-sif", DO_SINFIFO, 1, "Print # of in fifo overruns" },
303 { "-sic", DO_SINCOMPRESSES, 1, "Print # of in compress" },
304 { "-sim", DO_SINMULTICAST, 1, "Print # of in multicast" },
305 { "-so", DO_SOUTALL, 1, "Print all statistics on output" },
306 { "-sop", DO_SOUTPACKETS, 1, "Print # of out packets" },
307 { "-sob", DO_SOUTBYTES, 1, "Print # of out bytes" },
308 { "-soe", DO_SOUTERRORS, 1, "Print # of out errors" },
309 { "-sod", DO_SOUTDROPS, 1, "Print # of out drops" },
310 { "-sof", DO_SOUTFIFO, 1, "Print # of out fifo overruns" },
311 { "-sox", DO_SOUTCOLLS, 1, "Print # of out collisions" },
312 { "-soc", DO_SOUTCARRIER, 1, "Print # of out carrier loss" },
313 { "-som", DO_SOUTMULTICAST, 1, "Print # of out multicast" },
314 { "-bips",DO_BIPS, 1, "Print # of incoming bytes per second" },
315 { "-bops",DO_BOPS, 1, "Print # of outgoing bytes per second" },
318 void usage(const char *name) {
319 unsigned int i;
321 fprintf(stderr, "Usage: %s [options] iface\n", name);
322 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
323 fprintf(stderr, " %5s %s\n",
324 options[i].option, options[i].description);
328 void add_do(int *ndo, int **todo, int act) {
329 *todo = realloc(*todo, (*ndo+1) * sizeof(int));
330 (*todo)[*ndo] = act;
331 *ndo += 1;
334 static void print_addr(struct sockaddr *sadr) {
335 if (!sadr) {
336 fprintf(stderr, "Error\n");
337 exit(1);
339 print_quad(sadr);
342 struct if_stat *ifstats, *ifstats2 = NULL;
344 void please_do(int ndo, int *todo, const char *ifname) {
345 int i;
346 struct ifreq req;
347 if (!ndo) return;
348 // printf("I have %d items in my queue.\n",ndo);
349 for (i=0; i<ndo; i++) {
350 switch (todo[i]) {
351 case DO_EXISTS:
352 exit(!if_exists(ifname));
353 case DO_PEXISTS:
354 printf("%s", if_exists(ifname) ? "yes" : "no");
355 break;
356 case DO_PHWADDRESS:
357 if_hwaddr(ifname);
358 break;
359 case DO_PADDRESS:
360 print_addr(if_addr(ifname, &req));
361 break;
362 case DO_PFLAGS:
363 if_flags(ifname);
364 break;
365 case DO_PMASK:
366 print_addr(if_mask(ifname, &req));
367 break;
368 case DO_PCAST:
369 print_addr(if_bcast(ifname, &req));
370 break;
371 case DO_PMTU:
372 printf("%d", if_mtu(ifname));
373 break;
374 case DO_PNETWORK:
375 print_addr(if_network(ifname));
376 break;
377 case DO_PALL:
378 print_addr(if_addr(ifname, &req));
379 printf(" ");
380 print_addr(if_mask(ifname, &req));
381 printf(" ");
382 print_addr(if_bcast(ifname, &req));
383 printf(" ");
384 printf("%d", if_mtu(ifname));
385 break;
387 case DO_SINPACKETS:
388 printf("%llu",ifstats->in_packets);
389 break;
390 case DO_SINBYTES:
391 printf("%llu",ifstats->in_bytes);
392 break;
393 case DO_SINERRORS:
394 printf("%llu",ifstats->in_errors);
395 break;
396 case DO_SINDROPS:
397 printf("%llu",ifstats->in_drops);
398 break;
399 case DO_SINFIFO:
400 printf("%llu",ifstats->in_fifo);
401 break;
402 case DO_SINFRAME:
403 printf("%llu",ifstats->in_frame);
404 break;
405 case DO_SINCOMPRESSES:
406 printf("%llu",ifstats->in_compress);
407 break;
408 case DO_SINMULTICAST:
409 printf("%llu",ifstats->in_multicast);
410 break;
411 case DO_SINALL:
412 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
413 ifstats->in_bytes, ifstats->in_packets,
414 ifstats->in_errors, ifstats->in_drops,
415 ifstats->in_fifo, ifstats->in_frame,
416 ifstats->in_compress, ifstats->in_multicast);
417 break;
418 case DO_SOUTBYTES:
419 printf("%llu",ifstats->out_bytes);
420 break;
421 case DO_SOUTPACKETS:
422 printf("%llu",ifstats->out_packets);
423 break;
424 case DO_SOUTERRORS:
425 printf("%llu",ifstats->out_errors);
426 break;
427 case DO_SOUTDROPS:
428 printf("%llu",ifstats->out_drops);
429 break;
430 case DO_SOUTFIFO:
431 printf("%llu",ifstats->out_fifo);
432 break;
433 case DO_SOUTCOLLS:
434 printf("%llu",ifstats->out_colls);
435 break;
436 case DO_SOUTCARRIER:
437 printf("%llu",ifstats->out_carrier);
438 break;
439 case DO_SOUTMULTICAST:
440 printf("%llu",ifstats->out_multicast);
441 break;
442 case DO_BIPS:
443 if (ifstats2 == NULL) {
444 sleep(1);
445 ifstats2 = get_stats(ifname);
447 printf("%llu", ifstats2->in_bytes-ifstats->in_bytes);
448 break;
449 case DO_BOPS:
450 if (ifstats2 == NULL) {
451 sleep(1);
452 ifstats2 = get_stats(ifname);
454 printf("%llu", ifstats2->out_bytes-ifstats->out_bytes);
455 break;
456 case DO_SOUTALL:
457 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
458 ifstats->out_bytes, ifstats->out_packets,
459 ifstats->out_errors, ifstats->out_drops,
460 ifstats->out_fifo, ifstats->out_colls,
461 ifstats->out_carrier, ifstats->out_multicast);
462 break;
463 default:
464 printf("Unknown command: %d", todo[i]);
465 break;
467 printf("\n");
471 int main(int argc, char *argv[]) {
472 int ndo=0;
473 int *todo=NULL;
474 char *ifname=NULL;
475 int narg = 0;
476 int do_stats = 0;
477 unsigned int i, found;
479 if (argc == 1) {
480 usage(*argv);
481 return 1;
484 while (narg < argc - 1) {
485 narg++;
487 found = 0;
489 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
490 if (!strcmp(argv[narg], options[i].option)) {
491 add_do(&ndo, &todo, options[i].flag);
492 do_stats |= options[i].is_stat;
493 found = 1;
494 break;
498 if (found)
499 continue;
501 if (argv[narg][0] == '-') {
502 usage(*argv);
503 return 1;
505 else {
506 ifname = argv[narg];
507 break;
511 if (narg + 1 < argc || !ifname) {
512 usage(*argv);
513 return 1;
516 if (do_stats && (ifstats = get_stats(ifname)) == NULL) {
517 fprintf(stderr, "Error getting statistics for %s\n", ifname);
518 return 1;
521 please_do(ndo, todo, ifname);
523 return 0;