]> git.sur5r.net Git - i3/i3status/blob - src/print_ip_addr.c
fix: use SYSCONFDIR in error message
[i3/i3status] / src / print_ip_addr.c
1 // vim:ts=4:sw=4:expandtab
2 #include <config.h>
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <netinet/in.h>
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <netdb.h>
11 #include <ifaddrs.h>
12 #include <net/if.h>
13
14 #include "i3status.h"
15
16 /*
17  * Return a copy of the .ifa_name field passed as argument where the optional
18  * IP label, if present, is removed.
19  *
20  * example:
21  * - strip_optional_label("eth0") => "eth0"
22  * - strip_optional_label("eth0:label") => "eth0"
23  *
24  * The memory for the returned string is obtained with malloc(3), and can be
25  * freed with free(3).
26  *
27  *
28  */
29 static char *strip_optional_label(const char *ifa_name) {
30     char *copy = sstrdup(ifa_name);
31
32     char *ptr = strchr(copy, ':');
33
34     if (ptr) {
35         *ptr = '\0';
36     }
37
38     return copy;
39 }
40
41 /*
42  * Return the IP address for the given interface or "no IP" if the
43  * interface is up and running but hasn't got an IP address yet
44  *
45  */
46 const char *get_ip_addr(const char *interface, int family) {
47     static char part[512];
48     socklen_t len = 0;
49     if (family == AF_INET)
50         len = sizeof(struct sockaddr_in);
51     else if (family == AF_INET6)
52         len = sizeof(struct sockaddr_in6);
53
54     memset(part, 0, sizeof(part));
55
56     struct ifaddrs *ifaddr, *addrp;
57     bool found = false;
58
59     getifaddrs(&ifaddr);
60
61     if (ifaddr == NULL)
62         return NULL;
63
64     /* Skip until we are at the input family address of interface */
65     for (addrp = ifaddr; addrp != NULL; addrp = addrp->ifa_next) {
66         /* Strip the label if present in the .ifa_name field. */
67         char *stripped_ifa_name = strip_optional_label(addrp->ifa_name);
68
69         bool name_matches = strcmp(stripped_ifa_name, interface) != 0;
70         free(stripped_ifa_name);
71         if (name_matches) {
72             /* The interface does not have the right name, skip it. */
73             continue;
74         }
75
76         if (addrp->ifa_addr != NULL && addrp->ifa_addr->sa_family == family) {
77             /* We found the right interface with the right address. */
78             break;
79         }
80
81         /* Check if the interface is down. If it is, no need to look any
82          * further. */
83         if ((addrp->ifa_flags & IFF_RUNNING) == 0) {
84             freeifaddrs(ifaddr);
85             return NULL;
86         }
87
88         found = true;
89     }
90
91     if (addrp == NULL) {
92         freeifaddrs(ifaddr);
93         return (found ? "no IP" : NULL);
94     }
95
96     int ret;
97     if ((ret = getnameinfo(addrp->ifa_addr, len, part, sizeof(part), NULL, 0, NI_NUMERICHOST)) != 0) {
98         fprintf(stderr, "i3status: getnameinfo(): %s\n", gai_strerror(ret));
99         freeifaddrs(ifaddr);
100         return "no IP";
101     }
102
103     freeifaddrs(ifaddr);
104     return part;
105 }