]> git.proxmox.com Git - mirror_iproute2.git/blame - lib/utils.c
more ifdef excession.
[mirror_iproute2.git] / lib / utils.c
CommitLineData
aba5acdf
SH
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 <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <syslog.h>
21#include <fcntl.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <string.h>
25#include <netdb.h>
26#include <arpa/inet.h>
27#include <resolv.h>
5dfe5561 28#include <asm/types.h>
aba5acdf
SH
29#include <linux/pkt_sched.h>
30
31#include "utils.h"
32
4094db72 33int get_integer(int *val, const char *arg, int base)
aba5acdf
SH
34{
35 long res;
36 char *ptr;
37
38 if (!arg || !*arg)
39 return -1;
40 res = strtol(arg, &ptr, base);
41 if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN)
42 return -1;
43 *val = res;
44 return 0;
45}
46
4094db72 47int get_unsigned(unsigned *val, const char *arg, int base)
aba5acdf
SH
48{
49 unsigned long res;
50 char *ptr;
51
52 if (!arg || !*arg)
53 return -1;
54 res = strtoul(arg, &ptr, base);
55 if (!ptr || ptr == arg || *ptr || res > UINT_MAX)
56 return -1;
57 *val = res;
58 return 0;
59}
60
c7699875 61int get_u64(__u64 *val, const char *arg, int base)
62{
63 unsigned long long res;
64 char *ptr;
65
66 if (!arg || !*arg)
67 return -1;
68 res = strtoull(arg, &ptr, base);
69 if (!ptr || ptr == arg || *ptr || res == 0xFFFFFFFFULL)
70 return -1;
71 *val = res;
72 return 0;
73}
74
4094db72 75int get_u32(__u32 *val, const char *arg, int base)
aba5acdf
SH
76{
77 unsigned long res;
78 char *ptr;
79
80 if (!arg || !*arg)
81 return -1;
82 res = strtoul(arg, &ptr, base);
83 if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
84 return -1;
85 *val = res;
86 return 0;
87}
88
4094db72 89int get_u16(__u16 *val, const char *arg, int base)
aba5acdf
SH
90{
91 unsigned long res;
92 char *ptr;
93
94 if (!arg || !*arg)
95 return -1;
96 res = strtoul(arg, &ptr, base);
97 if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
98 return -1;
99 *val = res;
100 return 0;
101}
102
4094db72 103int get_u8(__u8 *val, const char *arg, int base)
aba5acdf
SH
104{
105 unsigned long res;
106 char *ptr;
107
108 if (!arg || !*arg)
109 return -1;
110 res = strtoul(arg, &ptr, base);
111 if (!ptr || ptr == arg || *ptr || res > 0xFF)
112 return -1;
113 *val = res;
114 return 0;
115}
116
4094db72 117int get_s16(__s16 *val, const char *arg, int base)
aba5acdf
SH
118{
119 long res;
120 char *ptr;
121
122 if (!arg || !*arg)
123 return -1;
124 res = strtol(arg, &ptr, base);
125 if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000)
126 return -1;
127 *val = res;
128 return 0;
129}
130
4094db72 131int get_s8(__s8 *val, const char *arg, int base)
aba5acdf
SH
132{
133 long res;
134 char *ptr;
135
136 if (!arg || !*arg)
137 return -1;
138 res = strtol(arg, &ptr, base);
139 if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80)
140 return -1;
141 *val = res;
142 return 0;
143}
144
4094db72 145int get_addr_1(inet_prefix *addr, const char *name, int family)
aba5acdf 146{
4094db72 147 const char *cp;
aba5acdf
SH
148 unsigned char *ap = (unsigned char*)addr->data;
149 int i;
150
151 memset(addr, 0, sizeof(*addr));
152
153 if (strcmp(name, "default") == 0 ||
154 strcmp(name, "all") == 0 ||
155 strcmp(name, "any") == 0) {
156 if (family == AF_DECnet)
157 return -1;
158 addr->family = family;
159 addr->bytelen = (family == AF_INET6 ? 16 : 4);
160 addr->bitlen = -1;
161 return 0;
162 }
163
164 if (strchr(name, ':')) {
165 addr->family = AF_INET6;
166 if (family != AF_UNSPEC && family != AF_INET6)
167 return -1;
168 if (inet_pton(AF_INET6, name, addr->data) <= 0)
169 return -1;
170 addr->bytelen = 16;
171 addr->bitlen = -1;
172 return 0;
173 }
174
175 if (family == AF_DECnet) {
176 struct dn_naddr dna;
177 addr->family = AF_DECnet;
178 if (dnet_pton(AF_DECnet, name, &dna) <= 0)
179 return -1;
180 memcpy(addr->data, dna.a_addr, 2);
181 addr->bytelen = 2;
182 addr->bitlen = -1;
183 return 0;
184 }
185
186 addr->family = AF_INET;
187 if (family != AF_UNSPEC && family != AF_INET)
188 return -1;
189 addr->bytelen = 4;
190 addr->bitlen = -1;
191 for (cp=name, i=0; *cp; cp++) {
192 if (*cp <= '9' && *cp >= '0') {
193 ap[i] = 10*ap[i] + (*cp-'0');
194 continue;
195 }
196 if (*cp == '.' && ++i <= 3)
197 continue;
198 return -1;
199 }
200 return 0;
201}
202
fb9b1d0f 203int get_prefix_1(inet_prefix *dst, char *arg, int family)
aba5acdf
SH
204{
205 int err;
206 unsigned plen;
207 char *slash;
208
209 memset(dst, 0, sizeof(*dst));
210
211 if (strcmp(arg, "default") == 0 ||
212 strcmp(arg, "any") == 0 ||
213 strcmp(arg, "all") == 0) {
214 if (family == AF_DECnet)
215 return -1;
216 dst->family = family;
217 dst->bytelen = 0;
218 dst->bitlen = 0;
219 return 0;
220 }
221
222 slash = strchr(arg, '/');
223 if (slash)
224 *slash = 0;
fb9b1d0f 225
aba5acdf
SH
226 err = get_addr_1(dst, arg, family);
227 if (err == 0) {
228 switch(dst->family) {
229 case AF_INET6:
230 dst->bitlen = 128;
231 break;
232 case AF_DECnet:
233 dst->bitlen = 16;
234 break;
235 default:
236 case AF_INET:
237 dst->bitlen = 32;
238 }
239 if (slash) {
240 if (get_integer(&plen, slash+1, 0) || plen > dst->bitlen) {
241 err = -1;
242 goto done;
243 }
244 dst->bitlen = plen;
245 }
246 }
247done:
248 if (slash)
249 *slash = '/';
250 return err;
251}
252
c7699875 253int get_addr(inet_prefix *dst, const char *arg, int family)
aba5acdf
SH
254{
255 if (family == AF_PACKET) {
256 fprintf(stderr, "Error: \"%s\" may be inet address, but it is not allowed in this context.\n", arg);
257 exit(1);
258 }
259 if (get_addr_1(dst, arg, family)) {
260 fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", arg);
261 exit(1);
262 }
263 return 0;
264}
265
fb9b1d0f 266int get_prefix(inet_prefix *dst, char *arg, int family)
aba5acdf
SH
267{
268 if (family == AF_PACKET) {
269 fprintf(stderr, "Error: \"%s\" may be inet prefix, but it is not allowed in this context.\n", arg);
270 exit(1);
271 }
272 if (get_prefix_1(dst, arg, family)) {
273 fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", arg);
274 exit(1);
275 }
276 return 0;
277}
278
c7699875 279__u32 get_addr32(const char *name)
aba5acdf
SH
280{
281 inet_prefix addr;
282 if (get_addr_1(&addr, name, AF_INET)) {
283 fprintf(stderr, "Error: an IP address is expected rather than \"%s\"\n", name);
284 exit(1);
285 }
286 return addr.data[0];
287}
288
4094db72 289void incomplete_command(void)
aba5acdf
SH
290{
291 fprintf(stderr, "Command line is not complete. Try option \"help\"\n");
292 exit(-1);
293}
294
c7699875 295void missarg(const char *key)
296{
297 fprintf(stderr, "Error: argument \"%s\" is required\n", key);
298 exit(-1);
299}
300
4094db72 301void invarg(const char *msg, const char *arg)
aba5acdf
SH
302{
303 fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg);
304 exit(-1);
305}
306
4094db72 307void duparg(const char *key, const char *arg)
aba5acdf
SH
308{
309 fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg);
310 exit(-1);
311}
312
4094db72 313void duparg2(const char *key, const char *arg)
aba5acdf
SH
314{
315 fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg);
316 exit(-1);
317}
318
4094db72 319int matches(const char *cmd, const char *pattern)
aba5acdf
SH
320{
321 int len = strlen(cmd);
322 if (len > strlen(pattern))
323 return -1;
324 return memcmp(pattern, cmd, len);
325}
326
4094db72 327int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits)
aba5acdf
SH
328{
329 __u32 *a1 = a->data;
330 __u32 *a2 = b->data;
331 int words = bits >> 0x05;
332
333 bits &= 0x1f;
334
335 if (words)
336 if (memcmp(a1, a2, words << 2))
337 return -1;
338
339 if (bits) {
340 __u32 w1, w2;
341 __u32 mask;
342
343 w1 = a1[words];
344 w2 = a2[words];
345
346 mask = htonl((0xffffffff) << (0x20 - bits));
347
348 if ((w1 ^ w2) & mask)
349 return 1;
350 }
351
352 return 0;
353}
354
355int __iproute2_hz_internal;
356
357int __get_hz(void)
358{
359 char name[1024];
360 int hz = 0;
361 FILE *fp;
362
363 if (getenv("HZ"))
364 return atoi(getenv("HZ")) ? : HZ;
365
366 if (getenv("PROC_NET_PSCHED")) {
367 snprintf(name, sizeof(name)-1, "%s", getenv("PROC_NET_PSCHED"));
c7699875 368 } else if (getenv("PROC_ROOT")) {
aba5acdf
SH
369 snprintf(name, sizeof(name)-1, "%s/net/psched", getenv("PROC_ROOT"));
370 } else {
371 strcpy(name, "/proc/net/psched");
372 }
373 fp = fopen(name, "r");
374
375 if (fp) {
376 unsigned nom, denom;
377 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
378 if (nom == 1000000)
379 hz = denom;
380 fclose(fp);
381 }
382 if (hz)
383 return hz;
384 return HZ;
385}
386
4094db72 387const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen)
aba5acdf
SH
388{
389 switch (af) {
390 case AF_INET:
391 case AF_INET6:
392 return inet_ntop(af, addr, buf, buflen);
393 case AF_IPX:
394 return ipx_ntop(af, addr, buf, buflen);
395 case AF_DECnet:
396 {
397 struct dn_naddr dna = { 2, { 0, 0, }};
398 memcpy(dna.a_addr, addr, 2);
399 return dnet_ntop(af, &dna, buf, buflen);
400 }
401 default:
402 return "???";
403 }
404}
405
406#ifdef RESOLVE_HOSTNAMES
407struct namerec
408{
409 struct namerec *next;
410 inet_prefix addr;
411 char *name;
412};
413
414static struct namerec *nht[256];
415
4094db72 416char *resolve_address(const char *addr, int len, int af)
aba5acdf
SH
417{
418 struct namerec *n;
419 struct hostent *h_ent;
420 unsigned hash;
421 static int notfirst;
422
423
424 if (af == AF_INET6 && ((__u32*)addr)[0] == 0 &&
425 ((__u32*)addr)[1] == 0 && ((__u32*)addr)[2] == htonl(0xffff)) {
426 af = AF_INET;
427 addr += 12;
428 len = 4;
429 }
430
431 hash = addr[len-1] ^ addr[len-2] ^ addr[len-3] ^ addr[len-4];
432
433 for (n = nht[hash]; n; n = n->next) {
434 if (n->addr.family == af &&
435 n->addr.bytelen == len &&
436 memcmp(n->addr.data, addr, len) == 0)
437 return n->name;
438 }
439 if ((n = malloc(sizeof(*n))) == NULL)
440 return NULL;
441 n->addr.family = af;
442 n->addr.bytelen = len;
443 n->name = NULL;
444 memcpy(n->addr.data, addr, len);
445 n->next = nht[hash];
446 nht[hash] = n;
447 if (++notfirst == 1)
448 sethostent(1);
449 fflush(stdout);
450
c7699875 451 if ((h_ent = gethostbyaddr(addr, len, af)) != NULL)
aba5acdf
SH
452 n->name = strdup(h_ent->h_name);
453
454 /* Even if we fail, "negative" entry is remembered. */
455 return n->name;
456}
457#endif
458
459
c7699875 460const char *format_host(int af, int len, const void *addr,
4094db72 461 char *buf, int buflen)
aba5acdf
SH
462{
463#ifdef RESOLVE_HOSTNAMES
464 if (resolve_hosts) {
465 char *n;
466 if (len <= 0) {
467 switch (af) {
468 case AF_INET:
469 len = 4;
470 break;
471 case AF_INET6:
472 len = 16;
473 break;
474 case AF_IPX:
475 len = 10;
476 break;
477#ifdef AF_DECnet
478 /* I see no reasons why gethostbyname
479 may not work for DECnet */
480 case AF_DECnet:
481 len = 2;
482 break;
483#endif
484 default: ;
485 }
486 }
487 if (len > 0 &&
488 (n = resolve_address(addr, len, af)) != NULL)
489 return n;
490 }
491#endif
492 return rt_addr_n2a(af, len, addr, buf, buflen);
493}
494
495
496__u8* hexstring_n2a(const __u8 *str, int len, __u8 *buf, int blen)
497{
498 __u8 *ptr = buf;
499 int i;
500
501 for (i=0; i<len; i++) {
502 if (blen < 3)
503 break;
504 sprintf(ptr, "%02x", str[i]);
505 ptr += 2;
506 blen -= 2;
507 if (i != len-1 && blen > 1) {
508 *ptr++ = ':';
509 blen--;
510 }
511 }
512 return buf;
513}
514
515__u8* hexstring_a2n(const __u8 *str, __u8 *buf, int blen)
516{
517 int cnt = 0;
518
519 for (;;) {
520 unsigned acc;
521 char ch;
522
523 acc = 0;
524
525 while ((ch = *str) != ':' && ch != 0) {
526 if (ch >= '0' && ch <= '9')
527 ch -= '0';
528 else if (ch >= 'a' && ch <= 'f')
529 ch -= 'a'-10;
530 else if (ch >= 'A' && ch <= 'F')
531 ch -= 'A'-10;
532 else
533 return NULL;
534 acc = (acc<<4) + ch;
535 str++;
536 }
537
538 if (acc > 255)
539 return NULL;
540 if (cnt < blen) {
541 buf[cnt] = acc;
542 cnt++;
543 }
544 if (ch == 0)
545 break;
546 ++str;
547 }
548 if (cnt < blen)
549 memset(buf+cnt, 0, blen-cnt);
550 return buf;
551}