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