]> err.no Git - moreutils/blob - ifdata.c
Update name one more place
[moreutils] / ifdata.c
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
8 #if defined(__linux__)
9         #include <linux/sockios.h>
10         #include <linux/if.h>
11 #endif
12
13 #if defined(__FreeBSD_kernel__)
14         #include <net/if.h>
15 #endif
16
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>
23
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
55 };
56
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;
62 };
63
64
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));
72 }
73
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]);
77 }
78
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;
90         }
91 }
92
93 enum print_error_enum {
94         PRINT_ERROR,
95         PRINT_NO_ERROR,
96 };
97
98 /**
99  * return 0 success
100  *        1 error
101  */
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;
106
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;
111
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;
119         }
120
121         close(sock);
122
123         return 0;
124 }
125
126 int if_exists(const char *iface) {
127         struct ifreq r;
128         return !do_socket_ioctl(iface, SIOCGIFFLAGS, &r, NULL, PRINT_NO_ERROR);
129 }
130
131 #if defined(__linux__)
132
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" },
157         };
158
159         if (do_socket_ioctl(iface, SIOCGIFFLAGS, &r, NULL, PRINT_ERROR))
160                 return;
161
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");
166 }
167
168 void if_hwaddr(const char *iface) {
169         struct ifreq r;
170         unsigned char *hwaddr;
171
172         if (do_socket_ioctl(iface, SIOCGIFHWADDR, &r, NULL, PRINT_ERROR))
173                 return;
174
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]);
178 }
179
180 #endif
181
182 static struct sockaddr *if_addr_value(const char *iface, struct ifreq *r, 
183                                       unsigned long int request) {
184         int e;
185
186         if (do_socket_ioctl(iface, request, r, &e, PRINT_NO_ERROR)) {
187                 if (e == EADDRNOTAVAIL)
188                         return &r->ifr_addr;
189                 return NULL;
190         }
191         return &r->ifr_addr;
192 }
193
194 struct sockaddr *if_addr(const char *iface, struct ifreq *r) {
195         return if_addr_value(iface, r, SIOCGIFADDR);
196 }
197
198 struct sockaddr *if_mask(const char *iface, struct ifreq *r) {
199         return if_addr_value(iface, r, SIOCGIFNETMASK);
200 }
201
202 struct sockaddr *if_bcast(const char *iface, struct ifreq *r) {
203         return if_addr_value(iface, r, SIOCGIFBRDADDR);
204 }
205
206 struct sockaddr *if_network(const char *iface) {
207         struct sockaddr *saddr;
208         static struct ifreq req;
209         unsigned int mask;
210
211         if (!(saddr = if_mask(iface, &req)))
212                 return NULL;
213
214         mask  = ((struct sockaddr_in*)saddr)->sin_addr.s_addr;
215
216         if (!(saddr = if_addr(iface, &req)))
217                 return NULL;
218
219         ((struct sockaddr_in*)saddr)->sin_addr.s_addr &= mask;
220         return saddr;
221 }
222
223 int if_mtu(const char *iface) {
224         static struct ifreq req;
225
226         if (do_socket_ioctl(iface, SIOCGIFMTU, &req, NULL, PRINT_ERROR))
227                 return 0;
228
229         return req.ifr_mtu;
230 }
231
232 #if defined(__linux__)
233
234 static void skipline(FILE *fd) {
235         int ch;
236         do {
237                 ch = getc(fd);
238         } while (ch != '\n' && ch != EOF);
239 }
240
241 struct if_stat *get_stats(const char *iface) {
242         FILE *fd;
243         struct if_stat *ifstat;
244         char name[10];
245
246         if (!(ifstat = malloc(sizeof(struct if_stat)))) {
247                 perror("malloc");
248                 return NULL;
249         }
250
251         if ((fd = fopen("/proc/net/dev", "r")) == NULL) {
252                 perror("fopen(\"/proc/net/dev\")");
253                 free(ifstat);
254                 return NULL;
255         }
256
257         /* Skip header */
258         skipline(fd);
259         skipline(fd);
260
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
274                 );
275                 
276                 if (items == -1)
277                         break;
278                 if (items != 17) {
279                         fprintf(stderr, "Invalid data read, check!\n");
280                         break;
281                 }
282
283                 if (!strncmp(name, iface, sizeof(name))) {
284                         fclose(fd);
285                         return ifstat;
286                 }
287         } while (!feof(fd));
288
289         fclose(fd);
290         free(ifstat);
291         return NULL;
292 }
293
294 #endif
295
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
333 };
334
335 void usage(const char *name) {
336         unsigned int i;
337
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);
342         }
343 }
344
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;
349 }
350
351 static void print_addr(struct sockaddr *sadr) {
352         if (!sadr) {
353                 fprintf(stderr, "Error\n");
354                 exit(1);
355         }
356         print_quad(sadr);
357 }
358
359 struct if_stat *ifstats, *ifstats2 = NULL;
360
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);
465                                 }
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);
472                                 }
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;
486                 }
487                 printf("\n");
488         }
489 }
490
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;
498
499         if (argc == 1) {
500                 usage(*argv);
501                 return 1;
502         }
503
504         while (narg < argc - 1) {
505                 narg++;
506
507                 found = 0;
508
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;
515                         }
516                 }
517
518                 if (found)
519                         continue;
520
521                 if (argv[narg][0] == '-') {
522                         usage(*argv);
523                         return 1;
524                 }
525                 else {
526                         ifname = argv[narg];
527                         break;
528                 }
529         }
530
531         if (narg + 1 < argc || !ifname) {
532                 usage(*argv);
533                 return 1;
534         }
535
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;
540         }
541 #endif
542
543         please_do(ndo, todo, ifname);
544
545         return 0;
546 }