utils.c revision 351efcde4e62967362a10b29f3b701cfecd7cdfc
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> 28#include <asm/types.h> 29#include <linux/pkt_sched.h> 30#include <time.h> 31#include <sys/time.h> 32 33 34#include "utils.h" 35 36int get_integer(int *val, const char *arg, int base) 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 50int get_unsigned(unsigned *val, const char *arg, int base) 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 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 78int get_u32(__u32 *val, const char *arg, int base) 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 92int get_u16(__u16 *val, const char *arg, int base) 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 106int get_u8(__u8 *val, const char *arg, int base) 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 120int get_s16(__s16 *val, const char *arg, int base) 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 134int get_s8(__s8 *val, const char *arg, int base) 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 148int get_addr_1(inet_prefix *addr, const char *name, int family) 149{ 150 const char *cp; 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 206int get_prefix_1(inet_prefix *dst, char *arg, int family) 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; 228 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) { 243 if (get_unsigned(&plen, slash+1, 0) || plen > dst->bitlen) { 244 err = -1; 245 goto done; 246 } 247 dst->flags |= PREFIXLEN_SPECIFIED; 248 dst->bitlen = plen; 249 } 250 } 251done: 252 if (slash) 253 *slash = '/'; 254 return err; 255} 256 257int get_addr(inet_prefix *dst, const char *arg, int family) 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 270int get_prefix(inet_prefix *dst, char *arg, int family) 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 283__u32 get_addr32(const char *name) 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 293void incomplete_command(void) 294{ 295 fprintf(stderr, "Command line is not complete. Try option \"help\"\n"); 296 exit(-1); 297} 298 299void missarg(const char *key) 300{ 301 fprintf(stderr, "Error: argument \"%s\" is required\n", key); 302 exit(-1); 303} 304 305void invarg(const char *msg, const char *arg) 306{ 307 fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg); 308 exit(-1); 309} 310 311void duparg(const char *key, const char *arg) 312{ 313 fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg); 314 exit(-1); 315} 316 317void duparg2(const char *key, const char *arg) 318{ 319 fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg); 320 exit(-1); 321} 322 323int matches(const char *cmd, const char *pattern) 324{ 325 int len = strlen(cmd); 326 if (len > strlen(pattern)) 327 return -1; 328 return memcmp(pattern, cmd, len); 329} 330 331int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits) 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")); 372 } else if (getenv("PROC_ROOT")) { 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 391int __iproute2_user_hz_internal; 392 393int __get_user_hz(void) 394{ 395 return sysconf(_SC_CLK_TCK); 396} 397 398const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen) 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 427char *resolve_address(const char *addr, int len, int af) 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 462 if ((h_ent = gethostbyaddr(addr, len, af)) != NULL) 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 471const char *format_host(int af, int len, const void *addr, 472 char *buf, int buflen) 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 507char *hexstring_n2a(const __u8 *str, int len, char *buf, int blen) 508{ 509 char *ptr = buf; 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 526__u8* hexstring_a2n(const char *str, __u8 *buf, int blen) 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} 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} 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} 641