blob: 2e2aa90f8564da8c479af8f885a7cc17e24aa4ab [file] [log] [blame]
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001/*
2 * utils.c
3 *
Bernhard Reutner-Fischer20f40002006-01-30 17:17:14 +00004 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00005 *
6 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
7 *
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00008 * Changes:
9 *
10 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
11 */
12
Rob Landleyecae66a2006-06-02 20:53:38 +000013#include "libbb.h"
14
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000015#include <string.h>
Eric Andersen496411b2003-02-12 10:56:53 +000016#include <unistd.h>
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000017
18#include "utils.h"
"Vladimir N. Oleynik"007a0112005-09-22 11:11:11 +000019#include "inet_common.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000020
21int get_integer(int *val, char *arg, int base)
22{
23 long res;
24 char *ptr;
25
26 if (!arg || !*arg)
27 return -1;
28 res = strtol(arg, &ptr, base);
29 if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN)
30 return -1;
31 *val = res;
32 return 0;
33}
34
35int get_unsigned(unsigned *val, char *arg, int base)
36{
37 unsigned long res;
38 char *ptr;
39
40 if (!arg || !*arg)
41 return -1;
42 res = strtoul(arg, &ptr, base);
43 if (!ptr || ptr == arg || *ptr || res > UINT_MAX)
44 return -1;
45 *val = res;
46 return 0;
47}
48
Glenn L McGrath50c00f42002-11-18 07:26:42 +000049int get_u32(__u32 * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000050{
51 unsigned long res;
52 char *ptr;
53
54 if (!arg || !*arg)
55 return -1;
56 res = strtoul(arg, &ptr, base);
57 if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
58 return -1;
59 *val = res;
60 return 0;
61}
62
Glenn L McGrath50c00f42002-11-18 07:26:42 +000063int get_u16(__u16 * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000064{
65 unsigned long res;
66 char *ptr;
67
68 if (!arg || !*arg)
69 return -1;
70 res = strtoul(arg, &ptr, base);
71 if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
72 return -1;
73 *val = res;
74 return 0;
75}
76
Glenn L McGrath50c00f42002-11-18 07:26:42 +000077int get_u8(__u8 * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000078{
79 unsigned long res;
80 char *ptr;
81
82 if (!arg || !*arg)
83 return -1;
84 res = strtoul(arg, &ptr, base);
85 if (!ptr || ptr == arg || *ptr || res > 0xFF)
86 return -1;
87 *val = res;
88 return 0;
89}
90
Glenn L McGrath50c00f42002-11-18 07:26:42 +000091int get_s16(__s16 * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000092{
93 long res;
94 char *ptr;
95
96 if (!arg || !*arg)
97 return -1;
98 res = strtol(arg, &ptr, base);
99 if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000)
100 return -1;
101 *val = res;
102 return 0;
103}
104
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000105int get_s8(__s8 * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000106{
107 long res;
108 char *ptr;
109
110 if (!arg || !*arg)
111 return -1;
112 res = strtol(arg, &ptr, base);
113 if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80)
114 return -1;
115 *val = res;
116 return 0;
117}
118
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000119int get_addr_1(inet_prefix * addr, char *name, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000120{
121 char *cp;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000122 unsigned char *ap = (unsigned char *) addr->data;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000123 int i;
124
125 memset(addr, 0, sizeof(*addr));
126
"Vladimir N. Oleynik"007a0112005-09-22 11:11:11 +0000127 if (strcmp(name, bb_INET_default) == 0 ||
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000128 strcmp(name, "all") == 0 || strcmp(name, "any") == 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000129 addr->family = family;
130 addr->bytelen = (family == AF_INET6 ? 16 : 4);
131 addr->bitlen = -1;
132 return 0;
133 }
134
135 if (strchr(name, ':')) {
136 addr->family = AF_INET6;
137 if (family != AF_UNSPEC && family != AF_INET6)
138 return -1;
139 if (inet_pton(AF_INET6, name, addr->data) <= 0)
140 return -1;
141 addr->bytelen = 16;
142 addr->bitlen = -1;
143 return 0;
144 }
145
146 addr->family = AF_INET;
147 if (family != AF_UNSPEC && family != AF_INET)
148 return -1;
149 addr->bytelen = 4;
150 addr->bitlen = -1;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000151 for (cp = name, i = 0; *cp; cp++) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000152 if (*cp <= '9' && *cp >= '0') {
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000153 ap[i] = 10 * ap[i] + (*cp - '0');
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000154 continue;
155 }
156 if (*cp == '.' && ++i <= 3)
157 continue;
158 return -1;
159 }
160 return 0;
161}
162
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000163int get_prefix_1(inet_prefix * dst, char *arg, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000164{
165 int err;
Eric Andersend78aea82006-01-30 18:00:02 +0000166 int plen;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000167 char *slash;
168
169 memset(dst, 0, sizeof(*dst));
170
"Vladimir N. Oleynik"007a0112005-09-22 11:11:11 +0000171 if (strcmp(arg, bb_INET_default) == 0 || strcmp(arg, "any") == 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000172 dst->family = family;
173 dst->bytelen = 0;
174 dst->bitlen = 0;
175 return 0;
176 }
177
178 slash = strchr(arg, '/');
179 if (slash)
180 *slash = 0;
181 err = get_addr_1(dst, arg, family);
182 if (err == 0) {
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000183 switch (dst->family) {
184 case AF_INET6:
185 dst->bitlen = 128;
186 break;
187 default:
188 case AF_INET:
189 dst->bitlen = 32;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000190 }
191 if (slash) {
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000192 if (get_integer(&plen, slash + 1, 0) || plen > dst->bitlen) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000193 err = -1;
194 goto done;
195 }
196 dst->bitlen = plen;
197 }
198 }
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000199 done:
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000200 if (slash)
201 *slash = '/';
202 return err;
203}
204
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000205int get_addr(inet_prefix * dst, char *arg, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000206{
207 if (family == AF_PACKET) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000208 bb_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 +0000209 }
210 if (get_addr_1(dst, arg, family)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000211 bb_error_msg_and_die("an inet address is expected rather than \"%s\".", arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000212 }
213 return 0;
214}
215
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000216int get_prefix(inet_prefix * dst, char *arg, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000217{
218 if (family == AF_PACKET) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000219 bb_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 +0000220 }
221 if (get_prefix_1(dst, arg, family)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000222 bb_error_msg_and_die("an inet address is expected rather than \"%s\".", arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000223 }
224 return 0;
225}
226
227__u32 get_addr32(char *name)
228{
229 inet_prefix addr;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000230
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000231 if (get_addr_1(&addr, name, AF_INET)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000232 bb_error_msg_and_die("an IP address is expected rather than \"%s\"", name);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000233 }
234 return addr.data[0];
235}
236
Mike Frysinger4e5936e2005-04-16 04:30:38 +0000237void incomplete_command(void)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000238{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000239 bb_error_msg("Command line is not complete. Try option \"help\"");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000240 exit(-1);
241}
242
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000243void invarg(const char const *arg, const char const *opt)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000244{
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000245 bb_error_msg(bb_msg_invalid_arg, arg, opt);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000246 exit(-1);
247}
248
249void duparg(char *key, char *arg)
250{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000251 bb_error_msg("duplicate \"%s\": \"%s\" is the second value.", key, arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000252 exit(-1);
253}
254
255void duparg2(char *key, char *arg)
256{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000257 bb_error_msg("either \"%s\" is duplicate, or \"%s\" is a garbage.", key, arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000258 exit(-1);
259}
260
261int matches(char *cmd, char *pattern)
262{
263 int len = strlen(cmd);
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000264
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000265 if (len > strlen(pattern)) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000266 return -1;
Glenn L McGrath82d2cd42002-11-28 12:45:48 +0000267 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000268 return memcmp(pattern, cmd, len);
269}
270
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000271int inet_addr_match(inet_prefix * a, inet_prefix * b, int bits)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000272{
273 __u32 *a1 = a->data;
274 __u32 *a2 = b->data;
275 int words = bits >> 0x05;
276
277 bits &= 0x1f;
278
279 if (words)
280 if (memcmp(a1, a2, words << 2))
281 return -1;
282
283 if (bits) {
284 __u32 w1, w2;
285 __u32 mask;
286
287 w1 = a1[words];
288 w2 = a2[words];
289
290 mask = htonl((0xffffffff) << (0x20 - bits));
291
292 if ((w1 ^ w2) & mask)
293 return 1;
294 }
295
296 return 0;
297}
298
299int __iproute2_hz_internal;
300
301int __get_hz(void)
302{
303 int hz = 0;
304 FILE *fp = fopen("/proc/net/psched", "r");
305
306 if (fp) {
307 unsigned nom, denom;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000308
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000309 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
310 if (nom == 1000000)
311 hz = denom;
312 fclose(fp);
313 }
314 if (hz)
315 return hz;
Eric Andersen496411b2003-02-12 10:56:53 +0000316 return sysconf(_SC_CLK_TCK);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000317}
318
Bernhard Reutner-Fischer20f40002006-01-30 17:17:14 +0000319const char *rt_addr_n2a(int af, int ATTRIBUTE_UNUSED len,
320 void *addr, char *buf, int buflen)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000321{
322 switch (af) {
323 case AF_INET:
324 case AF_INET6:
325 return inet_ntop(af, addr, buf, buflen);
326 default:
327 return "???";
328 }
329}
330
331
332const char *format_host(int af, int len, void *addr, char *buf, int buflen)
333{
334#ifdef RESOLVE_HOSTNAMES
335 if (resolve_hosts) {
336 struct hostent *h_ent;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000337
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000338 if (len <= 0) {
339 switch (af) {
340 case AF_INET:
341 len = 4;
342 break;
343 case AF_INET6:
344 len = 16;
345 break;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000346 default:;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000347 }
348 }
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000349 if (len > 0 && (h_ent = gethostbyaddr(addr, len, af)) != NULL) {
350 snprintf(buf, buflen - 1, "%s", h_ent->h_name);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000351 return buf;
352 }
353 }
354#endif
355 return rt_addr_n2a(af, len, addr, buf, buflen);
356}