iplib: Fix thread-unsafeness in myipaddr
[akaros.git] / user / iplib / readipifc.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9 #include <stdlib.h>
10
11 #include <iplib/iplib.h>
12 #include <parlib/parlib.h>
13 #include <signal.h>
14 #include <stdio.h>
15 #include <unistd.h>
16
17 #include <dirent.h>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21
22 #define NFIELD 200
23 #define nelem(x) (sizeof(x) / sizeof(x[0]))
24 static struct ipifc **_readoldipifc(char *buf, struct ipifc **l, int index)
25 {
26         char *f[NFIELD];
27         int i, n;
28         struct ipifc *ifc;
29         struct iplifc *lifc, **ll;
30
31         /* allocate new interface */
32         *l = ifc = calloc(sizeof(struct ipifc), 1);
33         if (ifc == NULL)
34                 return l;
35         l = &ifc->next;
36         ifc->index = index;
37
38         n = tokenize(buf, f, NFIELD);
39         if (n < 2)
40                 return l;
41
42         strncpy(ifc->dev, f[0], sizeof ifc->dev);
43         ifc->dev[sizeof(ifc->dev) - 1] = 0;
44         ifc->mtu = strtoul(f[1], NULL, 10);
45
46         ll = &ifc->lifc;
47         for (i = 2; n - i >= 7; i += 7) {
48                 /* allocate new local address */
49                 *ll = lifc = calloc(sizeof(struct iplifc), 1);
50                 ll = &lifc->next;
51
52                 parseip(lifc->ip, f[i]);
53                 parseipmask(lifc->mask, f[i + 1]);
54                 parseip(lifc->net, f[i + 2]);
55                 ifc->pktin = strtoul(f[i + 3], NULL, 10);
56                 ifc->pktout = strtoul(f[i + 4], NULL, 10);
57                 ifc->errin = strtoul(f[i + 5], NULL, 10);
58                 ifc->errout = strtoul(f[i + 6], NULL, 10);
59         }
60         return l;
61 }
62
63 static char *findfield(char *name, char **f, int n)
64 {
65         int i;
66
67         for (i = 0; i < n - 1; i++)
68                 if (strcmp(f[i], name) == 0)
69                         return f[i + 1];
70         return "";
71 }
72
73 static struct ipifc **_readipifc(char *file, struct ipifc **l, int index)
74 {
75         int i, n, fd, lines;
76         char buf[4 * 1024];
77         char *line[32];
78         char *f[64];
79         struct ipifc *ifc, **l0;
80         struct iplifc *lifc, **ll;
81
82         /* read the file */
83         fd = open(file, O_RDONLY);
84         if (fd < 0)
85                 return l;
86         n = 0;
87         while ((i = read(fd, buf + n, sizeof(buf) - 1 - n)) > 0 &&
88                n < sizeof(buf) - 1)
89                 n += i;
90         buf[n] = 0;
91         close(fd);
92
93         if (strncmp(buf, "device", 6) != 0)
94                 return _readoldipifc(buf, l, index);
95         /* ignore ifcs with no associated device */
96         if (strncmp(buf + 6, "  ", 2) == 0)
97                 return l;
98         /* allocate new interface */
99         *l = ifc = calloc(sizeof(struct ipifc), 1);
100         if (ifc == NULL)
101                 return l;
102         l0 = l;
103         l = &ifc->next;
104         ifc->index = index;
105
106         lines = getfields(buf, line, nelem(line), 1, "\n");
107
108         /* pick off device specific info(first line) */
109         n = tokenize(line[0], f, nelem(f));
110         if (n % 2 != 0)
111                 goto lose;
112         strncpy(ifc->dev, findfield("device", f, n), sizeof(ifc->dev));
113         ifc->dev[sizeof(ifc->dev) - 1] = 0;
114         if (ifc->dev[0] == 0) {
115         lose:
116                 free(ifc);
117                 *l0 = NULL;
118                 return l;
119         }
120         ifc->mtu = strtoul(findfield("maxtu", f, n), NULL, 10);
121         ifc->sendra6 = atoi(findfield("sendra", f, n));
122         ifc->recvra6 = atoi(findfield("recvra", f, n));
123         ifc->rp.mflag = atoi(findfield("mflag", f, n));
124         ifc->rp.oflag = atoi(findfield("oflag", f, n));
125         ifc->rp.maxraint = atoi(findfield("maxraint", f, n));
126         ifc->rp.minraint = atoi(findfield("minraint", f, n));
127         ifc->rp.linkmtu = atoi(findfield("linkmtu", f, n));
128         ifc->rp.reachtime = atoi(findfield("reachtime", f, n));
129         ifc->rp.rxmitra = atoi(findfield("rxmitra", f, n));
130         ifc->rp.ttl = atoi(findfield("ttl", f, n));
131         ifc->rp.routerlt = atoi(findfield("routerlt", f, n));
132         ifc->pktin = strtoul(findfield("pktin", f, n), NULL, 10);
133         ifc->pktout = strtoul(findfield("pktout", f, n), NULL, 10);
134         ifc->errin = strtoul(findfield("errin", f, n), NULL, 10);
135         ifc->errout = strtoul(findfield("errout", f, n), NULL, 10);
136
137         /* now read the addresses */
138         ll = &ifc->lifc;
139         for (i = 1; i < lines; i++) {
140                 n = tokenize(line[i], f, nelem(f));
141                 if (n < 5)
142                         break;
143
144                 /* allocate new local address */
145                 *ll = lifc = calloc(sizeof(struct iplifc), 1);
146                 ll = &lifc->next;
147
148                 parseip(lifc->ip, f[0]);
149                 parseipmask(lifc->mask, f[1]);
150                 parseip(lifc->net, f[2]);
151
152                 lifc->validlt = strtoul(f[3], NULL, 10);
153                 lifc->preflt = strtoul(f[4], NULL, 10);
154         }
155
156         return l;
157 }
158
159 void free_ipifc(struct ipifc *ifc)
160 {
161         struct ipifc *next;
162         struct iplifc *lnext, *lifc;
163
164         if (ifc == NULL)
165                 return;
166         for (; ifc; ifc = next) {
167                 next = ifc->next;
168                 for (lifc = ifc->lifc; lifc; lifc = lnext) {
169                         lnext = lifc->next;
170                         free(lifc);
171                 }
172                 free(ifc);
173         }
174 }
175
176 /* This will free @ifc when passed in.  Some old Plan 9 programs might rely on
177  * it still (like our ping, netstat, ipconfig).  It usually ends up be a
178  * thread-unsafe disaster. */
179 struct ipifc *readipifc(char *net, struct ipifc *ifc, int index)
180 {
181         int fd, i, n;
182         struct dir *dir;
183         char directory[128];
184         char buf[128];
185         struct ipifc **l;
186
187         free_ipifc(ifc);
188
189         l = &ifc;
190         ifc = NULL;
191
192         if (net == 0)
193                 net = "/net";
194         snprintf(directory, sizeof(directory), "%s/ipifc", net);
195
196         if (index >= 0) {
197                 snprintf(buf, sizeof(buf), "%s/%d/status", directory, index);
198                 _readipifc(buf, l, index);
199         } else {
200                 DIR *d;
201                 struct dirent *de;
202                 d = opendir(directory);
203                 if (!d)
204                         return NULL;
205
206                 while (de = readdir(d)) {
207                         if (strcmp(de->d_name, "clone") == 0)
208                                 continue;
209                         if (strcmp(de->d_name, "stats") == 0)
210                                 continue;
211                         snprintf(buf, sizeof(buf), "%s/%s/status", directory, de->d_name);
212                         l = _readipifc(buf, l, atoi(de->d_name));
213                 }
214                 closedir(d);
215         }
216
217         return ifc;
218 }