ts: -i enables incremental timestamping. Thanks, Thomas Vander Stichele
[moreutils.git] / ifdata.c
blob2de98a0b19372bff63be861b5adc755fa52fc74d
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 #include <netinet/in.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <ctype.h>
24 enum {
25 DO_EXISTS = 1,
26 DO_PEXISTS,
27 DO_PADDRESS,
28 DO_PMASK,
29 DO_PMTU,
30 DO_PCAST,
31 DO_PALL,
32 DO_PFLAGS,
33 DO_SINPACKETS,
34 DO_SINBYTES,
35 DO_SINERRORS,
36 DO_SINDROPS,
37 DO_SINALL,
38 DO_SINFIFO,
39 DO_SINFRAME,
40 DO_SINCOMPRESSES,
41 DO_SINMULTICAST,
42 DO_SOUTALL,
43 DO_SOUTBYTES,
44 DO_SOUTPACKETS,
45 DO_SOUTERRORS,
46 DO_SOUTDROPS,
47 DO_SOUTFIFO,
48 DO_SOUTCOLLS,
49 DO_SOUTCARRIER,
50 DO_SOUTMULTICAST,
51 DO_PNETWORK,
52 DO_PHWADDRESS,
53 DO_BIPS,
54 DO_BOPS
57 struct if_stat {
58 unsigned long long in_packets, in_bytes, in_errors, in_drops;
59 unsigned long long in_fifo, in_frame, in_compress, in_multicast;
60 unsigned long long out_bytes, out_packets, out_errors, out_drops;
61 unsigned long long out_fifo, out_colls, out_carrier, out_multicast;
65 void print_quad_ipv4(in_addr_t i) {
66 i = ntohl(i);
67 printf("%d.%d.%d.%d",
68 (i & 0xff000000) >> 24,
69 (i & 0x00ff0000) >> 16,
70 (i & 0x0000ff00) >> 8,
71 (i & 0x000000ff));
74 void print_quad_ipv6(uint16_t *a) {
75 printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
76 a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
79 void print_quad(struct sockaddr *adr) {
80 switch (adr->sa_family) {
81 case AF_INET:
82 print_quad_ipv4(((struct sockaddr_in*)adr)->sin_addr.s_addr);
83 break;
84 case AF_INET6:
85 print_quad_ipv6(((struct sockaddr_in6*)adr)->sin6_addr.s6_addr16);
86 break;
87 default:
88 printf("NON-IP");
89 break;
93 enum print_error_enum {
94 PRINT_ERROR,
95 PRINT_NO_ERROR,
98 /**
99 * return 0 success
100 * 1 error
102 static int do_socket_ioctl(const char *ifname, const unsigned long int request,
103 struct ifreq *req, int *ioctl_errno,
104 const enum print_error_enum print_error) {
105 int sock, res;
107 if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1)
108 return 1;
109 strncpy(req->ifr_name, ifname, IFNAMSIZ);
110 req->ifr_name[IFNAMSIZ - 1] = 0;
112 if ((res = ioctl(sock, request, req)) == -1) {
113 if (ioctl_errno)
114 *ioctl_errno = errno;
115 if (print_error == PRINT_ERROR)
116 fprintf(stderr, "ioctl on %s: %s\n", ifname, strerror(errno));
117 close(sock);
118 return 1;
121 close(sock);
123 return 0;
126 int if_exists(const char *iface) {
127 struct ifreq r;
128 return !do_socket_ioctl(iface, SIOCGIFFLAGS, &r, NULL, PRINT_NO_ERROR);
131 #if defined(__linux__)
133 void if_flags(const char *iface) {
134 struct ifreq r;
135 unsigned int i;
136 const struct {
137 unsigned int flag;
138 char *name;
139 } flags[] = {
140 { IFF_UP, "Up" },
141 { IFF_BROADCAST, "Broadcast" },
142 { IFF_DEBUG, "Debugging" },
143 { IFF_LOOPBACK, "Loopback" },
144 { IFF_POINTOPOINT, "Ppp" },
145 { IFF_NOTRAILERS, "No-trailers" },
146 { IFF_RUNNING, "Running" },
147 { IFF_NOARP, "No-arp" },
148 { IFF_PROMISC, "Promiscuous" },
149 { IFF_ALLMULTI, "All-multicast" },
150 { IFF_MASTER, "Load-master" },
151 { IFF_SLAVE, "Load-slave" },
152 { IFF_MULTICAST, "Multicast" },
153 { IFF_PORTSEL, "Port-select" },
154 { IFF_AUTOMEDIA, "Auto-detect" },
155 { IFF_DYNAMIC, "Dynaddr" },
156 { 0xffff0000, "Unknown-flags" },
159 if (do_socket_ioctl(iface, SIOCGIFFLAGS, &r, NULL, PRINT_ERROR))
160 return;
162 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++)
163 printf("%s%s%s", (r.ifr_flags & flags[i].flag) ? "On " : "Off ",
164 flags[i].name,
165 sizeof(flags) / sizeof(flags[0]) - 1 == i ? "" : "\n");
168 void if_hwaddr(const char *iface) {
169 struct ifreq r;
170 unsigned char *hwaddr;
172 if (do_socket_ioctl(iface, SIOCGIFHWADDR, &r, NULL, PRINT_ERROR))
173 return;
175 hwaddr = (unsigned char *)r.ifr_hwaddr.sa_data;
176 printf("%02X:%02X:%02X:%02X:%02X:%02X",
177 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
180 #endif
182 static struct sockaddr *if_addr_value(const char *iface, struct ifreq *r,
183 unsigned long int request) {
184 int e;
186 if (do_socket_ioctl(iface, request, r, &e, PRINT_NO_ERROR)) {
187 if (e == EADDRNOTAVAIL)
188 return &r->ifr_addr;
189 return NULL;
191 return &r->ifr_addr;
194 struct sockaddr *if_addr(const char *iface, struct ifreq *r) {
195 return if_addr_value(iface, r, SIOCGIFADDR);
198 struct sockaddr *if_mask(const char *iface, struct ifreq *r) {
199 return if_addr_value(iface, r, SIOCGIFNETMASK);
202 struct sockaddr *if_bcast(const char *iface, struct ifreq *r) {
203 return if_addr_value(iface, r, SIOCGIFBRDADDR);
206 struct sockaddr *if_network(const char *iface) {
207 struct sockaddr *saddr;
208 static struct ifreq req;
209 unsigned int mask;
211 if (!(saddr = if_mask(iface, &req)))
212 return NULL;
214 mask = ((struct sockaddr_in*)saddr)->sin_addr.s_addr;
216 if (!(saddr = if_addr(iface, &req)))
217 return NULL;
219 ((struct sockaddr_in*)saddr)->sin_addr.s_addr &= mask;
220 return saddr;
223 int if_mtu(const char *iface) {
224 static struct ifreq req;
226 if (do_socket_ioctl(iface, SIOCGIFMTU, &req, NULL, PRINT_ERROR))
227 return 0;
229 return req.ifr_mtu;
232 #if defined(__linux__)
234 static void skipline(FILE *fd) {
235 int ch;
236 do {
237 ch = getc(fd);
238 } while (ch != '\n' && ch != EOF);
241 struct if_stat *get_stats(const char *iface) {
242 FILE *fd;
243 struct if_stat *ifstat;
244 char name[10];
246 if (!(ifstat = malloc(sizeof(struct if_stat)))) {
247 perror("malloc");
248 return NULL;
251 if ((fd = fopen("/proc/net/dev", "r")) == NULL) {
252 perror("fopen(\"/proc/net/dev\")");
253 free(ifstat);
254 return NULL;
257 /* Skip header */
258 skipline(fd);
259 skipline(fd);
261 do {
262 int items = fscanf(fd,
263 " %20[^:]:%llu %llu %llu %llu %llu %llu %llu %llu "
264 "%llu %llu %llu %llu %llu %llu %llu %llu",
265 name,
266 &ifstat->in_bytes, &ifstat->in_packets,
267 &ifstat->in_errors, &ifstat->in_drops,
268 &ifstat->in_fifo, &ifstat->in_frame,
269 &ifstat->in_compress, &ifstat->in_multicast,
270 &ifstat->out_bytes, &ifstat->out_packets,
271 &ifstat->out_errors, &ifstat->out_drops,
272 &ifstat->out_fifo, &ifstat->out_colls,
273 &ifstat->out_carrier, &ifstat->out_carrier
276 if (items == -1)
277 break;
278 if (items != 17) {
279 fprintf(stderr, "Invalid data read, check!\n");
280 break;
283 if (!strncmp(name, iface, sizeof(name))) {
284 fclose(fd);
285 return ifstat;
287 } while (!feof(fd));
289 fclose(fd);
290 free(ifstat);
291 return NULL;
294 #endif
296 const struct {
297 char *option;
298 unsigned int flag;
299 unsigned int is_stat;
300 char *description;
301 } options[] = {
302 { "-e", DO_EXISTS, 0, "Reports interface existence via return code" },
303 { "-p", DO_PALL, 0, "Print out the whole config of iface" },
304 { "-pe", DO_PEXISTS, 0, "Print out yes or no according to existence" },
305 { "-pa", DO_PADDRESS, 0, "Print out the address" },
306 { "-pn", DO_PMASK, 0, "Print netmask" },
307 { "-pN", DO_PNETWORK, 0, "Print network address" },
308 { "-pb", DO_PCAST, 0, "Print broadcast" },
309 { "-pm", DO_PMTU, 0, "Print mtu" },
310 #if defined(__linux__)
311 { "-ph", DO_PHWADDRESS, 0, "Print out the hardware address" },
312 { "-pf", DO_PFLAGS, 0, "Print flags" },
313 { "-si", DO_SINALL, 1, "Print all statistics on input" },
314 { "-sip", DO_SINPACKETS, 1, "Print # of in packets" },
315 { "-sib", DO_SINBYTES, 1, "Print # of in bytes" },
316 { "-sie", DO_SINERRORS, 1, "Print # of in errors" },
317 { "-sid", DO_SINDROPS, 1, "Print # of in drops" },
318 { "-sif", DO_SINFIFO, 1, "Print # of in fifo overruns" },
319 { "-sic", DO_SINCOMPRESSES, 1, "Print # of in compress" },
320 { "-sim", DO_SINMULTICAST, 1, "Print # of in multicast" },
321 { "-so", DO_SOUTALL, 1, "Print all statistics on output" },
322 { "-sop", DO_SOUTPACKETS, 1, "Print # of out packets" },
323 { "-sob", DO_SOUTBYTES, 1, "Print # of out bytes" },
324 { "-soe", DO_SOUTERRORS, 1, "Print # of out errors" },
325 { "-sod", DO_SOUTDROPS, 1, "Print # of out drops" },
326 { "-sof", DO_SOUTFIFO, 1, "Print # of out fifo overruns" },
327 { "-sox", DO_SOUTCOLLS, 1, "Print # of out collisions" },
328 { "-soc", DO_SOUTCARRIER, 1, "Print # of out carrier loss" },
329 { "-som", DO_SOUTMULTICAST, 1, "Print # of out multicast" },
330 { "-bips",DO_BIPS, 1, "Print # of incoming bytes per second" },
331 { "-bops",DO_BOPS, 1, "Print # of outgoing bytes per second" },
332 #endif
335 void usage(const char *name) {
336 unsigned int i;
338 fprintf(stderr, "Usage: %s [options] iface\n", name);
339 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
340 fprintf(stderr, " %5s %s\n",
341 options[i].option, options[i].description);
345 void add_do(int *ndo, int **todo, int act) {
346 *todo = realloc(*todo, (*ndo+1) * sizeof(int));
347 (*todo)[*ndo] = act;
348 *ndo += 1;
351 static void print_addr(struct sockaddr *sadr) {
352 if (!sadr) {
353 fprintf(stderr, "Error\n");
354 exit(1);
356 print_quad(sadr);
359 struct if_stat *ifstats, *ifstats2 = NULL;
361 void please_do(int ndo, int *todo, const char *ifname) {
362 int i;
363 static struct ifreq req;
364 if (!ndo) return;
365 // printf("I have %d items in my queue.\n",ndo);
366 for (i=0; i<ndo; i++) {
367 switch (todo[i]) {
368 case DO_EXISTS:
369 exit(!if_exists(ifname));
370 case DO_PEXISTS:
371 printf("%s", if_exists(ifname) ? "yes" : "no");
372 break;
373 case DO_PADDRESS:
374 print_addr(if_addr(ifname, &req));
375 break;
376 #if defined(__linux__)
377 case DO_PHWADDRESS:
378 if_hwaddr(ifname);
379 break;
380 case DO_PFLAGS:
381 if_flags(ifname);
382 break;
383 #endif
384 case DO_PMASK:
385 print_addr(if_mask(ifname, &req));
386 break;
387 case DO_PCAST:
388 print_addr(if_bcast(ifname, &req));
389 break;
390 case DO_PMTU:
391 printf("%d", if_mtu(ifname));
392 break;
393 case DO_PNETWORK:
394 print_addr(if_network(ifname));
395 break;
396 case DO_PALL:
397 print_addr(if_addr(ifname, &req));
398 printf(" ");
399 print_addr(if_mask(ifname, &req));
400 printf(" ");
401 print_addr(if_bcast(ifname, &req));
402 printf(" ");
403 printf("%d", if_mtu(ifname));
404 break;
405 #if defined(__linux__)
406 case DO_SINPACKETS:
407 printf("%llu",ifstats->in_packets);
408 break;
409 case DO_SINBYTES:
410 printf("%llu",ifstats->in_bytes);
411 break;
412 case DO_SINERRORS:
413 printf("%llu",ifstats->in_errors);
414 break;
415 case DO_SINDROPS:
416 printf("%llu",ifstats->in_drops);
417 break;
418 case DO_SINFIFO:
419 printf("%llu",ifstats->in_fifo);
420 break;
421 case DO_SINFRAME:
422 printf("%llu",ifstats->in_frame);
423 break;
424 case DO_SINCOMPRESSES:
425 printf("%llu",ifstats->in_compress);
426 break;
427 case DO_SINMULTICAST:
428 printf("%llu",ifstats->in_multicast);
429 break;
430 case DO_SINALL:
431 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
432 ifstats->in_bytes, ifstats->in_packets,
433 ifstats->in_errors, ifstats->in_drops,
434 ifstats->in_fifo, ifstats->in_frame,
435 ifstats->in_compress, ifstats->in_multicast);
436 break;
437 case DO_SOUTBYTES:
438 printf("%llu",ifstats->out_bytes);
439 break;
440 case DO_SOUTPACKETS:
441 printf("%llu",ifstats->out_packets);
442 break;
443 case DO_SOUTERRORS:
444 printf("%llu",ifstats->out_errors);
445 break;
446 case DO_SOUTDROPS:
447 printf("%llu",ifstats->out_drops);
448 break;
449 case DO_SOUTFIFO:
450 printf("%llu",ifstats->out_fifo);
451 break;
452 case DO_SOUTCOLLS:
453 printf("%llu",ifstats->out_colls);
454 break;
455 case DO_SOUTCARRIER:
456 printf("%llu",ifstats->out_carrier);
457 break;
458 case DO_SOUTMULTICAST:
459 printf("%llu",ifstats->out_multicast);
460 break;
461 case DO_BIPS:
462 if (ifstats2 == NULL) {
463 sleep(1);
464 ifstats2 = get_stats(ifname);
466 printf("%llu", ifstats2->in_bytes-ifstats->in_bytes);
467 break;
468 case DO_BOPS:
469 if (ifstats2 == NULL) {
470 sleep(1);
471 ifstats2 = get_stats(ifname);
473 printf("%llu", ifstats2->out_bytes-ifstats->out_bytes);
474 break;
475 case DO_SOUTALL:
476 printf("%llu %llu %llu %llu %llu %llu %llu %llu",
477 ifstats->out_bytes, ifstats->out_packets,
478 ifstats->out_errors, ifstats->out_drops,
479 ifstats->out_fifo, ifstats->out_colls,
480 ifstats->out_carrier, ifstats->out_multicast);
481 break;
482 #endif
483 default:
484 printf("Unknown command: %d", todo[i]);
485 break;
487 printf("\n");
491 int main(int argc, char *argv[]) {
492 int ndo=0;
493 int *todo=NULL;
494 char *ifname=NULL;
495 int narg = 0;
496 int do_stats = 0;
497 unsigned int i, found;
499 if (argc == 1) {
500 usage(*argv);
501 return 1;
504 while (narg < argc - 1) {
505 narg++;
507 found = 0;
509 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
510 if (!strcmp(argv[narg], options[i].option)) {
511 add_do(&ndo, &todo, options[i].flag);
512 do_stats |= options[i].is_stat;
513 found = 1;
514 break;
518 if (found)
519 continue;
521 if (argv[narg][0] == '-') {
522 usage(*argv);
523 return 1;
525 else {
526 ifname = argv[narg];
527 break;
531 if (narg + 1 < argc || !ifname) {
532 usage(*argv);
533 return 1;
536 #if defined(__linux__)
537 if (do_stats && (ifstats = get_stats(ifname)) == NULL) {
538 fprintf(stderr, "Error getting statistics for %s\n", ifname);
539 return 1;
541 #endif
543 please_do(ndo, todo, ifname);
545 return 0;