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 */
43const char *
44numtostr(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 */
110uintmax_t
111mdb_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	}
145done:
146	return (neg ? -val : val);
147oflow:
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 */
157ulong_t
158strntoul(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 */
173int
174strisnum(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 */
190int
191strisbasenum(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 */
236int
237strtoi(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 */
250char *
251strdup(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 */
262char *
263strndup(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 */
275void
276strfree(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 */
286size_t
287stresc2chr(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 */
366char *
367strchr2esc(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 */
462char *
463strchr2adb(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 */
498char *
499strnchr(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 */
515char *
516strsplit(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 */
530char *
531strrsplit(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 */
549const char *
550strnpbrk(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 */
580char *
581strabbr(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 */
596const char *
597strbasename(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 */
611char *
612strdirname(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 */
644const char *
645strbadid(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 */
654int
655strisprint(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 */
669static void
670convert2ascii(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
744char *
745mdb_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