This seems sufficient for ifup and ifdown to actually work
[oweals/busybox.git] / networking / libiproute / utils.c
1 /*
2  * utils.c
3  *
4  *              This program is free software; you can redistribute it and/or
5  *              modify it under the terms of the GNU General Public License
6  *              as published by the Free Software Foundation; either version
7  *              2 of the License, or (at your option) any later version.
8  *
9  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10  *
11  *
12  * Changes:
13  *
14  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
15  */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <arpa/inet.h>
20
21 #include "utils.h"
22 #include "libbb.h"
23
24 int get_integer(int *val, char *arg, int base)
25 {
26         long res;
27         char *ptr;
28
29         if (!arg || !*arg)
30                 return -1;
31         res = strtol(arg, &ptr, base);
32         if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN)
33                 return -1;
34         *val = res;
35         return 0;
36 }
37
38 int get_unsigned(unsigned *val, char *arg, int base)
39 {
40         unsigned long res;
41         char *ptr;
42
43         if (!arg || !*arg)
44                 return -1;
45         res = strtoul(arg, &ptr, base);
46         if (!ptr || ptr == arg || *ptr || res > UINT_MAX)
47                 return -1;
48         *val = res;
49         return 0;
50 }
51
52 int get_u32(__u32 * val, char *arg, int base)
53 {
54         unsigned long res;
55         char *ptr;
56
57         if (!arg || !*arg)
58                 return -1;
59         res = strtoul(arg, &ptr, base);
60         if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
61                 return -1;
62         *val = res;
63         return 0;
64 }
65
66 int get_u16(__u16 * val, char *arg, int base)
67 {
68         unsigned long res;
69         char *ptr;
70
71         if (!arg || !*arg)
72                 return -1;
73         res = strtoul(arg, &ptr, base);
74         if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
75                 return -1;
76         *val = res;
77         return 0;
78 }
79
80 int get_u8(__u8 * val, char *arg, int base)
81 {
82         unsigned long res;
83         char *ptr;
84
85         if (!arg || !*arg)
86                 return -1;
87         res = strtoul(arg, &ptr, base);
88         if (!ptr || ptr == arg || *ptr || res > 0xFF)
89                 return -1;
90         *val = res;
91         return 0;
92 }
93
94 int get_s16(__s16 * val, char *arg, int base)
95 {
96         long res;
97         char *ptr;
98
99         if (!arg || !*arg)
100                 return -1;
101         res = strtol(arg, &ptr, base);
102         if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000)
103                 return -1;
104         *val = res;
105         return 0;
106 }
107
108 int get_s8(__s8 * val, char *arg, int base)
109 {
110         long res;
111         char *ptr;
112
113         if (!arg || !*arg)
114                 return -1;
115         res = strtol(arg, &ptr, base);
116         if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80)
117                 return -1;
118         *val = res;
119         return 0;
120 }
121
122 int get_addr_1(inet_prefix * addr, char *name, int family)
123 {
124         char *cp;
125         unsigned char *ap = (unsigned char *) addr->data;
126         int i;
127
128         memset(addr, 0, sizeof(*addr));
129
130         if (strcmp(name, "default") == 0 ||
131                 strcmp(name, "all") == 0 || strcmp(name, "any") == 0) {
132                 addr->family = family;
133                 addr->bytelen = (family == AF_INET6 ? 16 : 4);
134                 addr->bitlen = -1;
135                 return 0;
136         }
137
138         if (strchr(name, ':')) {
139                 addr->family = AF_INET6;
140                 if (family != AF_UNSPEC && family != AF_INET6)
141                         return -1;
142                 if (inet_pton(AF_INET6, name, addr->data) <= 0)
143                         return -1;
144                 addr->bytelen = 16;
145                 addr->bitlen = -1;
146                 return 0;
147         }
148
149         addr->family = AF_INET;
150         if (family != AF_UNSPEC && family != AF_INET)
151                 return -1;
152         addr->bytelen = 4;
153         addr->bitlen = -1;
154         for (cp = name, i = 0; *cp; cp++) {
155                 if (*cp <= '9' && *cp >= '0') {
156                         ap[i] = 10 * ap[i] + (*cp - '0');
157                         continue;
158                 }
159                 if (*cp == '.' && ++i <= 3)
160                         continue;
161                 return -1;
162         }
163         return 0;
164 }
165
166 int get_prefix_1(inet_prefix * dst, char *arg, int family)
167 {
168         int err;
169         unsigned plen;
170         char *slash;
171
172         memset(dst, 0, sizeof(*dst));
173
174         if (strcmp(arg, "default") == 0 || strcmp(arg, "any") == 0) {
175                 dst->family = family;
176                 dst->bytelen = 0;
177                 dst->bitlen = 0;
178                 return 0;
179         }
180
181         slash = strchr(arg, '/');
182         if (slash)
183                 *slash = 0;
184         err = get_addr_1(dst, arg, family);
185         if (err == 0) {
186                 switch (dst->family) {
187                 case AF_INET6:
188                         dst->bitlen = 128;
189                         break;
190                 default:
191                 case AF_INET:
192                         dst->bitlen = 32;
193                 }
194                 if (slash) {
195                         if (get_integer(&plen, slash + 1, 0) || plen > dst->bitlen) {
196                                 err = -1;
197                                 goto done;
198                         }
199                         dst->bitlen = plen;
200                 }
201         }
202   done:
203         if (slash)
204                 *slash = '/';
205         return err;
206 }
207
208 int get_addr(inet_prefix * dst, char *arg, int family)
209 {
210         if (family == AF_PACKET) {
211                 error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context.", arg);
212         }
213         if (get_addr_1(dst, arg, family)) {
214                 error_msg_and_die("an inet address is expected rather than \"%s\".", arg);
215         }
216         return 0;
217 }
218
219 int get_prefix(inet_prefix * dst, char *arg, int family)
220 {
221         if (family == AF_PACKET) {
222                 error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context.", arg);
223         }
224         if (get_prefix_1(dst, arg, family)) {
225                 error_msg_and_die("an inet address is expected rather than \"%s\".", arg);
226         }
227         return 0;
228 }
229
230 __u32 get_addr32(char *name)
231 {
232         inet_prefix addr;
233
234         if (get_addr_1(&addr, name, AF_INET)) {
235                 error_msg_and_die("an IP address is expected rather than \"%s\"", name);
236         }
237         return addr.data[0];
238 }
239
240 void incomplete_command()
241 {
242         error_msg("Command line is not complete. Try option \"help\"");
243         exit(-1);
244 }
245
246 void invarg(char *msg, char *arg)
247 {
248         error_msg("argument \"%s\" is wrong: %s", arg, msg);
249         exit(-1);
250 }
251
252 void duparg(char *key, char *arg)
253 {
254         error_msg("duplicate \"%s\": \"%s\" is the second value.", key, arg);
255         exit(-1);
256 }
257
258 void duparg2(char *key, char *arg)
259 {
260         error_msg("either \"%s\" is duplicate, or \"%s\" is a garbage.", key, arg);
261         exit(-1);
262 }
263
264 int matches(char *cmd, char *pattern)
265 {
266         int len = strlen(cmd);
267
268         if (len > strlen(pattern)) {
269                 return -1;
270         }
271         return memcmp(pattern, cmd, len);
272 }
273
274 int inet_addr_match(inet_prefix * a, inet_prefix * b, int bits)
275 {
276         __u32 *a1 = a->data;
277         __u32 *a2 = b->data;
278         int words = bits >> 0x05;
279
280         bits &= 0x1f;
281
282         if (words)
283                 if (memcmp(a1, a2, words << 2))
284                         return -1;
285
286         if (bits) {
287                 __u32 w1, w2;
288                 __u32 mask;
289
290                 w1 = a1[words];
291                 w2 = a2[words];
292
293                 mask = htonl((0xffffffff) << (0x20 - bits));
294
295                 if ((w1 ^ w2) & mask)
296                         return 1;
297         }
298
299         return 0;
300 }
301
302 int __iproute2_hz_internal;
303
304 int __get_hz(void)
305 {
306         int hz = 0;
307         FILE *fp = fopen("/proc/net/psched", "r");
308
309         if (fp) {
310                 unsigned nom, denom;
311
312                 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
313                         if (nom == 1000000)
314                                 hz = denom;
315                 fclose(fp);
316         }
317         if (hz)
318                 return hz;
319         return HZ;
320 }
321
322 const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen)
323 {
324         switch (af) {
325         case AF_INET:
326         case AF_INET6:
327                 return inet_ntop(af, addr, buf, buflen);
328         default:
329                 return "???";
330         }
331 }
332
333
334 const char *format_host(int af, int len, void *addr, char *buf, int buflen)
335 {
336 #ifdef RESOLVE_HOSTNAMES
337         if (resolve_hosts) {
338                 struct hostent *h_ent;
339
340                 if (len <= 0) {
341                         switch (af) {
342                         case AF_INET:
343                                 len = 4;
344                                 break;
345                         case AF_INET6:
346                                 len = 16;
347                                 break;
348                         default:;
349                         }
350                 }
351                 if (len > 0 && (h_ent = gethostbyaddr(addr, len, af)) != NULL) {
352                         snprintf(buf, buflen - 1, "%s", h_ent->h_name);
353                         return buf;
354                 }
355         }
356 #endif
357         return rt_addr_n2a(af, len, addr, buf, buflen);
358 }