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