blob: 63084e15e8bd316910979107229fb2d8c0712f17 [file] [log] [blame]
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001/*
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
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000017#include <stdlib.h>
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000018#include <string.h>
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000019#include <arpa/inet.h>
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000020
21#include "utils.h"
Glenn L McGrath82d2cd42002-11-28 12:45:48 +000022#include "libbb.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000023
24int 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
38int 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
Glenn L McGrath50c00f42002-11-18 07:26:42 +000052int get_u32(__u32 * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000053{
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
Glenn L McGrath50c00f42002-11-18 07:26:42 +000066int get_u16(__u16 * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000067{
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
Glenn L McGrath50c00f42002-11-18 07:26:42 +000080int get_u8(__u8 * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000081{
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
Glenn L McGrath50c00f42002-11-18 07:26:42 +000094int get_s16(__s16 * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000095{
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
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000108int get_s8(__s8 * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000109{
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
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000122int get_addr_1(inet_prefix * addr, char *name, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000123{
124 char *cp;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000125 unsigned char *ap = (unsigned char *) addr->data;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000126 int i;
127
128 memset(addr, 0, sizeof(*addr));
129
130 if (strcmp(name, "default") == 0 ||
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000131 strcmp(name, "all") == 0 || strcmp(name, "any") == 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000132 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;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000154 for (cp = name, i = 0; *cp; cp++) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000155 if (*cp <= '9' && *cp >= '0') {
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000156 ap[i] = 10 * ap[i] + (*cp - '0');
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000157 continue;
158 }
159 if (*cp == '.' && ++i <= 3)
160 continue;
161 return -1;
162 }
163 return 0;
164}
165
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000166int get_prefix_1(inet_prefix * dst, char *arg, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000167{
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) {
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000186 switch (dst->family) {
187 case AF_INET6:
188 dst->bitlen = 128;
189 break;
190 default:
191 case AF_INET:
192 dst->bitlen = 32;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000193 }
194 if (slash) {
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000195 if (get_integer(&plen, slash + 1, 0) || plen > dst->bitlen) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000196 err = -1;
197 goto done;
198 }
199 dst->bitlen = plen;
200 }
201 }
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000202 done:
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000203 if (slash)
204 *slash = '/';
205 return err;
206}
207
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000208int get_addr(inet_prefix * dst, char *arg, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000209{
210 if (family == AF_PACKET) {
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000211 error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context.", arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000212 }
213 if (get_addr_1(dst, arg, family)) {
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000214 error_msg_and_die("an inet address is expected rather than \"%s\".", arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000215 }
216 return 0;
217}
218
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000219int get_prefix(inet_prefix * dst, char *arg, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000220{
221 if (family == AF_PACKET) {
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000222 error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context.", arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000223 }
224 if (get_prefix_1(dst, arg, family)) {
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000225 error_msg_and_die("an inet address is expected rather than \"%s\".", arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000226 }
227 return 0;
228}
229
230__u32 get_addr32(char *name)
231{
232 inet_prefix addr;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000233
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000234 if (get_addr_1(&addr, name, AF_INET)) {
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000235 error_msg_and_die("an IP address is expected rather than \"%s\"", name);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000236 }
237 return addr.data[0];
238}
239
240void incomplete_command()
241{
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000242 error_msg("Command line is not complete. Try option \"help\"");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000243 exit(-1);
244}
245
246void invarg(char *msg, char *arg)
247{
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000248 error_msg("argument \"%s\" is wrong: %s", arg, msg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000249 exit(-1);
250}
251
252void duparg(char *key, char *arg)
253{
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000254 error_msg("duplicate \"%s\": \"%s\" is the second value.", key, arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000255 exit(-1);
256}
257
258void duparg2(char *key, char *arg)
259{
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000260 error_msg("either \"%s\" is duplicate, or \"%s\" is a garbage.", key, arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000261 exit(-1);
262}
263
264int matches(char *cmd, char *pattern)
265{
266 int len = strlen(cmd);
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000267
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000268 if (len > strlen(pattern)) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000269 return -1;
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000270 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000271 return memcmp(pattern, cmd, len);
272}
273
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000274int inet_addr_match(inet_prefix * a, inet_prefix * b, int bits)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000275{
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
302int __iproute2_hz_internal;
303
304int __get_hz(void)
305{
306 int hz = 0;
307 FILE *fp = fopen("/proc/net/psched", "r");
308
309 if (fp) {
310 unsigned nom, denom;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000311
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000312 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
322const 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
334const 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;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000339
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000340 if (len <= 0) {
341 switch (af) {
342 case AF_INET:
343 len = 4;
344 break;
345 case AF_INET6:
346 len = 16;
347 break;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000348 default:;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000349 }
350 }
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000351 if (len > 0 && (h_ent = gethostbyaddr(addr, len, af)) != NULL) {
352 snprintf(buf, buflen - 1, "%s", h_ent->h_name);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000353 return buf;
354 }
355 }
356#endif
357 return rt_addr_n2a(af, len, addr, buf, buflen);
358}