1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <netinet/in.h> 28 #include <limits.h> 29 #include <sys/types.h> 30 #include <sys/socket.h> 31 32 #include <mdb/mdb_string.h> 33 #include <mdb/mdb_modapi.h> 34 #include <mdb/mdb_lex.h> 35 #include <mdb/mdb_debug.h> 36 #include <mdb/mdb.h> 37 38 /* 39 * Convert the specified integer value to a string represented in the given 40 * base. The flags parameter is a bitfield of the formatting flags defined in 41 * mdb_string.h. A pointer to a static conversion buffer is returned. 42 */ 43 const char * 44 numtostr(uintmax_t uvalue, int base, uint_t flags) 45 { 46 static const char ldigits[] = "0123456789abcdef"; 47 static const char udigits[] = "0123456789ABCDEF"; 48 49 static char buf[68]; /* Enough for ULLONG_MAX in binary plus prefixes */ 50 51 const char *digits = (flags & NTOS_UPCASE) ? udigits : ldigits; 52 int i = sizeof (buf); 53 54 intmax_t value = (intmax_t)uvalue; 55 int neg = (flags & NTOS_UNSIGNED) == 0 && value < 0; 56 uintmax_t rem = neg ? -value : value; 57 58 buf[--i] = 0; 59 60 do { 61 buf[--i] = digits[rem % base]; 62 rem /= base; 63 } while (rem != 0); 64 65 if (flags & NTOS_SHOWBASE) { 66 uintmax_t lim; 67 char c = 0; 68 69 switch (base) { 70 case 2: 71 lim = 1; 72 c = 'i'; 73 break; 74 case 8: 75 lim = 7; 76 c = 'o'; 77 break; 78 case 10: 79 lim = 9; 80 c = 't'; 81 break; 82 case 16: 83 lim = 9; 84 c = 'x'; 85 break; 86 } 87 88 if (c != 0 && uvalue > lim) { 89 buf[--i] = c; 90 buf[--i] = '0'; 91 } 92 } 93 94 if (neg) 95 buf[--i] = '-'; 96 else if (flags & NTOS_SIGNPOS) 97 buf[--i] = '+'; 98 99 return ((const char *)(&buf[i])); 100 } 101 102 #define CTOI(x) (((x) >= '0' && (x) <= '9') ? (x) - '0' : \ 103 ((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A') 104 105 /* 106 * Convert a string to an unsigned integer value using the specified base. 107 * In the event of overflow or an invalid character, we generate an 108 * error message and longjmp back to the main loop using yyerror(). 109 */ 110 uintmax_t 111 mdb_strtonum(const char *s, int base) 112 { 113 uintmax_t multmax = (uintmax_t)ULLONG_MAX / (uintmax_t)(uint_t)base; 114 uintmax_t val = 0; 115 int c, i, neg = 0; 116 117 switch (c = *s) { 118 case '-': 119 neg++; 120 /*FALLTHRU*/ 121 case '+': 122 c = *++s; 123 } 124 125 if (c == '\0') 126 goto done; 127 128 if ((val = CTOI(c)) >= base) 129 yyerror("digit '%c' is invalid in current base\n", c); 130 131 for (c = *++s; c != '\0'; c = *++s) { 132 if (val > multmax) 133 goto oflow; 134 135 if ((i = CTOI(c)) >= base) 136 yyerror("digit '%c' is invalid in current base\n", c); 137 138 val *= base; 139 140 if ((uintmax_t)ULLONG_MAX - val < (uintmax_t)i) 141 goto oflow; 142 143 val += i; 144 } 145 done: 146 return (neg ? -val : val); 147 oflow: 148 yyerror("specified value exceeds maximum immediate value\n"); 149 return ((uintmax_t)ULLONG_MAX); 150 } 151 152 /* 153 * Quick string to unsigned long conversion function. This function performs 154 * no overflow checking and is only meant for internal mdb use. It allows 155 * the caller to specify the length of the string in bytes and a base. 156 */ 157 ulong_t 158 strntoul(const char *s, size_t nbytes, int base) 159 { 160 ulong_t n; 161 int c; 162 163 for (n = 0; nbytes != 0 && (c = *s) != '\0'; s++, nbytes--) 164 n = n * base + CTOI(c); 165 166 return (n); 167 } 168 169 /* 170 * Return a boolean value indicating whether or not a string consists 171 * solely of characters which are digits 0..9. 172 */ 173 int 174 strisnum(const char *s) 175 { 176 for (; *s != '\0'; s++) { 177 if (*s < '0' || *s > '9') 178 return (0); 179 } 180 181 return (1); 182 } 183 184 /* 185 * Return a boolean value indicating whether or not a string contains a 186 * number. The number may be in the current radix, or it may have an 187 * explicit radix qualifier. The number will be validated against the 188 * legal characters for the given radix. 189 */ 190 int 191 strisbasenum(const char *s) 192 { 193 char valid[] = "0123456789aAbBcCdDeEfF"; 194 int radix = mdb.m_radix; 195 196 if (s[0] == '0') { 197 switch (s[1]) { 198 case 'I': 199 case 'i': 200 radix = 2; 201 s += 2; 202 break; 203 case 'O': 204 case 'o': 205 radix = 8; 206 s += 2; 207 break; 208 case 'T': 209 case 't': 210 radix = 10; 211 s += 2; 212 break; 213 case 'x': 214 case 'X': 215 radix = 16; 216 s += 2; 217 break; 218 } 219 } 220 221 /* limit `valid' to the digits valid for this base */ 222 valid[radix > 10 ? 10 + (radix - 10) * 2 : radix] = '\0'; 223 224 do { 225 if (!strchr(valid, *s)) 226 return (0); 227 } while (*++s != '\0'); 228 229 return (1); 230 } 231 232 /* 233 * Quick string to integer (base 10) conversion function. This performs 234 * no overflow checking and is only meant for internal mdb use. 235 */ 236 int 237 strtoi(const char *s) 238 { 239 int c, n; 240 241 for (n = 0; (c = *s) >= '0' && c <= '9'; s++) 242 n = n * 10 + c - '0'; 243 244 return (n); 245 } 246 247 /* 248 * Create a copy of string s using the mdb allocator interface. 249 */ 250 char * 251 strdup(const char *s) 252 { 253 char *s1 = mdb_alloc(strlen(s) + 1, UM_SLEEP); 254 255 (void) strcpy(s1, s); 256 return (s1); 257 } 258 259 /* 260 * Create a copy of string s, but only duplicate the first n bytes. 261 */ 262 char * 263 strndup(const char *s, size_t n) 264 { 265 char *s2 = mdb_alloc(n + 1, UM_SLEEP); 266 267 (void) strncpy(s2, s, n); 268 s2[n] = '\0'; 269 return (s2); 270 } 271 272 /* 273 * Convenience routine for freeing strings. 274 */ 275 void 276 strfree(char *s) 277 { 278 mdb_free(s, strlen(s) + 1); 279 } 280 281 /* 282 * Transform string s inline, converting each embedded C escape sequence string 283 * to the corresponding character. For example, the substring "\n" is replaced 284 * by an inline '\n' character. The length of the resulting string is returned. 285 */ 286 size_t 287 stresc2chr(char *s) 288 { 289 char *p, *q, c; 290 int esc = 0; 291 292 for (p = q = s; (c = *p) != '\0'; p++) { 293 if (esc) { 294 switch (c) { 295 case '0': 296 case '1': 297 case '2': 298 case '3': 299 case '4': 300 case '5': 301 case '6': 302 case '7': 303 c -= '0'; 304 p++; 305 306 if (*p >= '0' && *p <= '7') { 307 c = c * 8 + *p++ - '0'; 308 309 if (*p >= '0' && *p <= '7') 310 c = c * 8 + *p - '0'; 311 else 312 p--; 313 } else 314 p--; 315 316 *q++ = c; 317 break; 318 319 case 'a': 320 *q++ = '\a'; 321 break; 322 case 'b': 323 *q++ = '\b'; 324 break; 325 case 'f': 326 *q++ = '\f'; 327 break; 328 case 'n': 329 *q++ = '\n'; 330 break; 331 case 'r': 332 *q++ = '\r'; 333 break; 334 case 't': 335 *q++ = '\t'; 336 break; 337 case 'v': 338 *q++ = '\v'; 339 break; 340 case '"': 341 case '\\': 342 *q++ = c; 343 break; 344 default: 345 *q++ = '\\'; 346 *q++ = c; 347 } 348 349 esc = 0; 350 351 } else { 352 if ((esc = c == '\\') == 0) 353 *q++ = c; 354 } 355 } 356 357 *q = '\0'; 358 return ((size_t)(q - s)); 359 } 360 361 /* 362 * Create a copy of string s in which certain unprintable or special characters 363 * have been converted to the string representation of their C escape sequence. 364 * For example, the newline character is expanded to the string "\n". 365 */ 366 char * 367 strchr2esc(const char *s, size_t n) 368 { 369 const char *p; 370 char *q, *s2, c; 371 size_t addl = 0; 372 373 for (p = s; p < s + n; p++) { 374 switch (c = *p) { 375 case '\0': 376 case '\a': 377 case '\b': 378 case '\f': 379 case '\n': 380 case '\r': 381 case '\t': 382 case '\v': 383 case '"': 384 case '\\': 385 addl++; /* 1 add'l char needed to follow \ */ 386 break; 387 case ' ': 388 break; 389 default: 390 if (c < '!' || c > '~') 391 addl += 3; /* 3 add'l chars following \ */ 392 } 393 } 394 395 s2 = mdb_alloc(n + addl + 1, UM_SLEEP); 396 397 for (p = s, q = s2; p < s + n; p++) { 398 switch (c = *p) { 399 case '\0': 400 *q++ = '\\'; 401 *q++ = '0'; 402 break; 403 case '\a': 404 *q++ = '\\'; 405 *q++ = 'a'; 406 break; 407 case '\b': 408 *q++ = '\\'; 409 *q++ = 'b'; 410 break; 411 case '\f': 412 *q++ = '\\'; 413 *q++ = 'f'; 414 break; 415 case '\n': 416 *q++ = '\\'; 417 *q++ = 'n'; 418 break; 419 case '\r': 420 *q++ = '\\'; 421 *q++ = 'r'; 422 break; 423 case '\t': 424 *q++ = '\\'; 425 *q++ = 't'; 426 break; 427 case '\v': 428 *q++ = '\\'; 429 *q++ = 'v'; 430 break; 431 case '"': 432 *q++ = '\\'; 433 *q++ = '"'; 434 break; 435 case '\\': 436 *q++ = '\\'; 437 *q++ = '\\'; 438 break; 439 case ' ': 440 *q++ = c; 441 break; 442 default: 443 if (c < '!' || c > '~') { 444 *q++ = '\\'; 445 *q++ = ((c >> 6) & 3) + '0'; 446 *q++ = ((c >> 3) & 7) + '0'; 447 *q++ = (c & 7) + '0'; 448 } else 449 *q++ = c; 450 } 451 } 452 453 *q = '\0'; 454 return (s2); 455 } 456 457 /* 458 * Create a copy of string s in which certain unprintable or special characters 459 * have been converted to an odd representation of their escape sequence. 460 * This algorithm is the old adb convention for representing such sequences. 461 */ 462 char * 463 strchr2adb(const char *s, size_t n) 464 { 465 size_t addl = 0; 466 const char *p; 467 char *q, *s2; 468 469 for (p = s; p < s + n; p++) { 470 char c = *p & CHAR_MAX; 471 472 if (c < ' ' || c == CHAR_MAX) 473 addl++; /* 1 add'l char needed for "^" */ 474 } 475 476 s2 = mdb_alloc(n + addl + 1, UM_SLEEP); 477 478 for (p = s, q = s2; p < s + n; p++) { 479 char c = *p & CHAR_MAX; 480 481 if (c == CHAR_MAX) { 482 *q++ = '^'; 483 *q++ = '?'; 484 } else if (c < ' ') { 485 *q++ = '^'; 486 *q++ = c + '@'; 487 } else 488 *q++ = c; 489 } 490 491 *q = '\0'; 492 return (s2); 493 } 494 495 /* 496 * Same as strchr, but we only search the first n characters 497 */ 498 char * 499 strnchr(const char *s, int c, size_t n) 500 { 501 int i = 0; 502 503 for (i = 0; i < n; i++) { 504 if (*(s + i) == (char)c) 505 return ((char *)(s + i)); 506 } 507 508 return (NULL); 509 } 510 511 /* 512 * Split the string s at the first occurrence of character c. This character 513 * is replaced by \0, and a pointer to the remainder of the string is returned. 514 */ 515 char * 516 strsplit(char *s, char c) 517 { 518 char *p; 519 520 if ((p = strchr(s, c)) == NULL) 521 return (NULL); 522 523 *p++ = '\0'; 524 return (p); 525 } 526 527 /* 528 * Same as strsplit, but split from the last occurrence of character c. 529 */ 530 char * 531 strrsplit(char *s, char c) 532 { 533 char *p; 534 535 if ((p = strrchr(s, c)) == NULL) 536 return (NULL); 537 538 *p++ = '\0'; 539 return (p); 540 } 541 542 /* 543 * Return the address of the first occurrence of any character from s2 544 * in the string s1, or NULL if none exists. This is similar to libc's 545 * strpbrk, but we add a third parameter to limit the search to the 546 * specified number of bytes in s1, or a \0 character, whichever is 547 * encountered first. 548 */ 549 const char * 550 strnpbrk(const char *s1, const char *s2, size_t nbytes) 551 { 552 const char *p; 553 554 if (nbytes == 0) 555 return (NULL); 556 557 do { 558 for (p = s2; *p != '\0' && *p != *s1; p++) 559 continue; 560 561 if (*p != '\0') 562 return (s1); 563 564 } while (--nbytes != 0 && *s1++ != '\0'); 565 566 return (NULL); 567 } 568 569 /* 570 * Abbreviate a string if it meets or exceeds the specified length, including 571 * the terminating null character. The string is abbreviated by replacing the 572 * last four characters with " ...". strabbr is useful in constructs such as 573 * this one, where nbytes = sizeof (buf): 574 * 575 * if (mdb_snprintf(buf, nbytes, "%s %d %c", ...) >= nbytes) 576 * (void) strabbr(buf, nbytes); 577 * 578 * No modifications are made if nbytes is too small to hold the suffix itself. 579 */ 580 char * 581 strabbr(char *s, size_t nbytes) 582 { 583 static const char suffix[] = " ..."; 584 585 if (nbytes > sizeof (suffix) && strlen(s) >= nbytes - 1) 586 (void) strcpy(&s[nbytes - sizeof (suffix)], suffix); 587 588 return (s); 589 } 590 591 /* 592 * Return the basename (name after final /) of the given string. We use 593 * strbasename rather than basename to avoid conflicting with libgen.h's 594 * non-const function prototype. 595 */ 596 const char * 597 strbasename(const char *s) 598 { 599 const char *p = strrchr(s, '/'); 600 601 if (p == NULL) 602 return (s); 603 604 return (++p); 605 } 606 607 /* 608 * Return the directory name (name prior to the final /) of the given string. 609 * The string itself is modified. 610 */ 611 char * 612 strdirname(char *s) 613 { 614 static char slash[] = "/"; 615 static char dot[] = "."; 616 char *p; 617 618 if (s == NULL || *s == '\0') 619 return (dot); 620 621 for (p = s + strlen(s); p != s && *--p == '/'; ) 622 continue; 623 624 if (p == s && *p == '/') 625 return (slash); 626 627 while (p != s) { 628 if (*--p == '/') { 629 while (*p == '/' && p != s) 630 p--; 631 *++p = '\0'; 632 return (s); 633 } 634 } 635 636 return (dot); 637 } 638 639 /* 640 * Return a pointer to the first character in the string that makes it an 641 * invalid identifer (i.e. incompatible with the mdb syntax), or NULL if 642 * the string is a valid identifier. 643 */ 644 const char * 645 strbadid(const char *s) 646 { 647 return (strpbrk(s, "#%^&*-+=,:$/\\?<>;|!`'\"[]\n\t() {}")); 648 } 649 650 /* 651 * Return a boolean value indicating if the given string consists solely 652 * of printable ASCII characters terminated by \0. 653 */ 654 int 655 strisprint(const char *s) 656 { 657 for (; *s != '\0'; s++) { 658 if (*s < ' ' || *s > '~') 659 return (0); 660 } 661 662 return (1); 663 } 664 665 /* 666 * This is a near direct copy of the inet_ntop() code in 667 * uts/common/inet/ip/ipv6.c, duplicated here for kmdb's sake. 668 */ 669 static void 670 convert2ascii(char *buf, const in6_addr_t *addr) 671 { 672 int hexdigits; 673 int head_zero = 0; 674 int tail_zero = 0; 675 /* tempbuf must be big enough to hold ffff:\0 */ 676 char tempbuf[6]; 677 char *ptr; 678 uint16_t *addr_component, host_component; 679 size_t len; 680 int first = FALSE; 681 int med_zero = FALSE; 682 int end_zero = FALSE; 683 684 addr_component = (uint16_t *)addr; 685 ptr = buf; 686 687 /* First count if trailing zeroes higher in number */ 688 for (hexdigits = 0; hexdigits < 8; hexdigits++) { 689 if (*addr_component == 0) { 690 if (hexdigits < 4) 691 head_zero++; 692 else 693 tail_zero++; 694 } 695 addr_component++; 696 } 697 addr_component = (uint16_t *)addr; 698 if (tail_zero > head_zero && (head_zero + tail_zero) != 7) 699 end_zero = TRUE; 700 701 for (hexdigits = 0; hexdigits < 8; hexdigits++) { 702 /* if entry is a 0 */ 703 if (*addr_component == 0) { 704 if (!first && *(addr_component + 1) == 0) { 705 if (end_zero && (hexdigits < 4)) { 706 *ptr++ = '0'; 707 *ptr++ = ':'; 708 } else { 709 if (hexdigits == 0) 710 *ptr++ = ':'; 711 /* add another */ 712 *ptr++ = ':'; 713 first = TRUE; 714 med_zero = TRUE; 715 } 716 } else if (first && med_zero) { 717 if (hexdigits == 7) 718 *ptr++ = ':'; 719 addr_component++; 720 continue; 721 } else { 722 *ptr++ = '0'; 723 *ptr++ = ':'; 724 } 725 addr_component++; 726 continue; 727 } 728 if (med_zero) 729 med_zero = FALSE; 730 731 tempbuf[0] = '\0'; 732 mdb_nhconvert(&host_component, addr_component, 733 sizeof (uint16_t)); 734 (void) mdb_snprintf(tempbuf, sizeof (tempbuf), "%x:", 735 host_component & 0xffff); 736 len = strlen(tempbuf); 737 bcopy(tempbuf, ptr, len); 738 ptr = ptr + len; 739 addr_component++; 740 } 741 *--ptr = '\0'; 742 } 743 744 char * 745 mdb_inet_ntop(int af, const void *addr, char *buf, size_t buflen) 746 { 747 in6_addr_t *v6addr; 748 uchar_t *v4addr; 749 char *caddr; 750 751 #define UC(b) (((int)b) & 0xff) 752 switch (af) { 753 case AF_INET: 754 ASSERT(buflen >= INET_ADDRSTRLEN); 755 v4addr = (uchar_t *)addr; 756 (void) mdb_snprintf(buf, buflen, "%d.%d.%d.%d", 757 UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3])); 758 return (buf); 759 760 case AF_INET6: 761 ASSERT(buflen >= INET6_ADDRSTRLEN); 762 v6addr = (in6_addr_t *)addr; 763 if (IN6_IS_ADDR_V4MAPPED(v6addr)) { 764 caddr = (char *)addr; 765 (void) mdb_snprintf(buf, buflen, "::ffff:%d.%d.%d.%d", 766 UC(caddr[12]), UC(caddr[13]), 767 UC(caddr[14]), UC(caddr[15])); 768 } else if (IN6_IS_ADDR_V4COMPAT(v6addr)) { 769 caddr = (char *)addr; 770 (void) mdb_snprintf(buf, buflen, "::%d.%d.%d.%d", 771 UC(caddr[12]), UC(caddr[13]), UC(caddr[14]), 772 UC(caddr[15])); 773 } else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) { 774 (void) mdb_snprintf(buf, buflen, "::"); 775 } else { 776 convert2ascii(buf, v6addr); 777 } 778 return (buf); 779 } 780 #undef UC 781 782 return (NULL); 783 } 784