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