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