xref: /titanic_51/usr/src/lib/libdhcputil/common/dhcp_symbol.c (revision d04ccbb3f3163ae5962a8b7465d9796bff6ca434)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*d04ccbb3Scarlsonj  * Common Development and Distribution License (the "License").
6*d04ccbb3Scarlsonj  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*d04ccbb3Scarlsonj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <strings.h>
317c478bd9Sstevel@tonic-gate #include <limits.h>
327c478bd9Sstevel@tonic-gate #include <errno.h>
337c478bd9Sstevel@tonic-gate #include <dhcp_impl.h>
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include "dhcp_symbol.h"
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate  * The following structure and table are used to define the attributes
397c478bd9Sstevel@tonic-gate  * of a DHCP symbol category.
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate typedef struct dsym_cat {
427c478bd9Sstevel@tonic-gate 	char		*dc_string;	/* string value for the category */
437c478bd9Sstevel@tonic-gate 	int		dc_minlen;	/* min. chars of dc_string to match */
447c478bd9Sstevel@tonic-gate 	dsym_category_t	dc_id;		/* numerical value for the category */
457c478bd9Sstevel@tonic-gate 	boolean_t	dc_dhcptab;	/* valid for dhcptab use? */
467c478bd9Sstevel@tonic-gate 	ushort_t	dc_min;		/* minimum valid code */
477c478bd9Sstevel@tonic-gate 	ushort_t	dc_max;		/* maximum valid code */
487c478bd9Sstevel@tonic-gate } dsym_cat_t;
497c478bd9Sstevel@tonic-gate 
50*d04ccbb3Scarlsonj static dsym_cat_t cats[] = {
517c478bd9Sstevel@tonic-gate 	{ "Extend", 6, DSYM_EXTEND, B_TRUE, DHCP_LAST_STD + 1,
527c478bd9Sstevel@tonic-gate 		DHCP_SITE_OPT - 1 },
537c478bd9Sstevel@tonic-gate 	{ "Vendor=", 6, DSYM_VENDOR, B_TRUE, DHCP_FIRST_OPT,
547c478bd9Sstevel@tonic-gate 		DHCP_LAST_OPT },
557c478bd9Sstevel@tonic-gate 	{ "Site", 4, DSYM_SITE, B_TRUE, DHCP_SITE_OPT, DHCP_LAST_OPT },
567c478bd9Sstevel@tonic-gate 	{ "Standard", 8, DSYM_STANDARD, B_FALSE, DHCP_FIRST_OPT,
577c478bd9Sstevel@tonic-gate 	    DHCP_LAST_STD },
587c478bd9Sstevel@tonic-gate 	{ "Field", 5, DSYM_FIELD, B_FALSE, CD_PACKET_START,
597c478bd9Sstevel@tonic-gate 		CD_PACKET_END },
607c478bd9Sstevel@tonic-gate 	{ "Internal", 8, DSYM_INTERNAL, B_FALSE, CD_INTRNL_START,
617c478bd9Sstevel@tonic-gate 	    CD_INTRNL_END }
627c478bd9Sstevel@tonic-gate };
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * The following structure and table are used to define the attributes
667c478bd9Sstevel@tonic-gate  * of a DHCP symbol type.
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate typedef struct dsym_type {
697c478bd9Sstevel@tonic-gate 	char		*dt_string;	/* string value for the type */
707c478bd9Sstevel@tonic-gate 	dsym_cdtype_t	dt_id;		/* numerical value for the type */
717c478bd9Sstevel@tonic-gate 	boolean_t	dt_dhcptab;	/* valid for dhcptab use? */
727c478bd9Sstevel@tonic-gate } dsym_type_t;
737c478bd9Sstevel@tonic-gate 
74*d04ccbb3Scarlsonj static dsym_type_t types[] = {
757c478bd9Sstevel@tonic-gate 	{ "ASCII", DSYM_ASCII, B_TRUE },
767c478bd9Sstevel@tonic-gate 	{ "OCTET", DSYM_OCTET, B_TRUE },
777c478bd9Sstevel@tonic-gate 	{ "IP", DSYM_IP, B_TRUE },
787c478bd9Sstevel@tonic-gate 	{ "NUMBER", DSYM_NUMBER, B_TRUE },
797c478bd9Sstevel@tonic-gate 	{ "BOOL", DSYM_BOOL, B_TRUE },
807c478bd9Sstevel@tonic-gate 	{ "INCLUDE", DSYM_INCLUDE, B_FALSE },
817c478bd9Sstevel@tonic-gate 	{ "UNUMBER8", DSYM_UNUMBER8, B_TRUE },
827c478bd9Sstevel@tonic-gate 	{ "UNUMBER16", DSYM_UNUMBER16, B_TRUE },
83*d04ccbb3Scarlsonj 	{ "UNUMBER24", DSYM_UNUMBER24, B_TRUE },
847c478bd9Sstevel@tonic-gate 	{ "UNUMBER32", DSYM_UNUMBER32, B_TRUE },
857c478bd9Sstevel@tonic-gate 	{ "UNUMBER64", DSYM_UNUMBER64, B_TRUE },
867c478bd9Sstevel@tonic-gate 	{ "SNUMBER8", DSYM_SNUMBER8, B_TRUE },
877c478bd9Sstevel@tonic-gate 	{ "SNUMBER16", DSYM_SNUMBER16, B_TRUE },
887c478bd9Sstevel@tonic-gate 	{ "SNUMBER32", DSYM_SNUMBER32, B_TRUE },
89*d04ccbb3Scarlsonj 	{ "SNUMBER64", DSYM_SNUMBER64, B_TRUE },
90*d04ccbb3Scarlsonj 	{ "IPV6", DSYM_IPV6, B_TRUE },
91*d04ccbb3Scarlsonj 	{ "DUID", DSYM_DUID, B_TRUE },
92*d04ccbb3Scarlsonj 	{ "DOMAIN", DSYM_DOMAIN, B_TRUE }
937c478bd9Sstevel@tonic-gate };
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * symbol delimiters and constants
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate #define	DSYM_CLASS_DEL		" \t\n"
997c478bd9Sstevel@tonic-gate #define	DSYM_FIELD_DEL		","
1007c478bd9Sstevel@tonic-gate #define	DSYM_VENDOR_DEL		'='
1017c478bd9Sstevel@tonic-gate #define	DSYM_QUOTE		'"'
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * dsym_trim(): trims all whitespace from either side of a string
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  *  input: char **: a pointer to a string to trim of whitespace.
1077c478bd9Sstevel@tonic-gate  * output: none
1087c478bd9Sstevel@tonic-gate  */
109*d04ccbb3Scarlsonj 
1107c478bd9Sstevel@tonic-gate static void
1117c478bd9Sstevel@tonic-gate dsym_trim(char **str)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	char *tmpstr = *str;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	/*
1177c478bd9Sstevel@tonic-gate 	 * Trim all whitespace from the front of the string.
1187c478bd9Sstevel@tonic-gate 	 */
1197c478bd9Sstevel@tonic-gate 	while (*tmpstr != '\0' && isspace(*tmpstr)) {
1207c478bd9Sstevel@tonic-gate 		tmpstr++;
1217c478bd9Sstevel@tonic-gate 	}
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * Move the str pointer to first non-whitespace char.
1257c478bd9Sstevel@tonic-gate 	 */
1267c478bd9Sstevel@tonic-gate 	*str = tmpstr;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	/*
1297c478bd9Sstevel@tonic-gate 	 * Check case where the string is nothing but whitespace.
1307c478bd9Sstevel@tonic-gate 	 */
1317c478bd9Sstevel@tonic-gate 	if (*tmpstr == '\0') {
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 		/*
1347c478bd9Sstevel@tonic-gate 		 * Trim all whitespace from the end of the string.
1357c478bd9Sstevel@tonic-gate 		 */
1367c478bd9Sstevel@tonic-gate 		tmpstr = *str + strlen(*str) - 1;
1377c478bd9Sstevel@tonic-gate 		while (tmpstr >= *str && isspace(*tmpstr)) {
1387c478bd9Sstevel@tonic-gate 			tmpstr--;
1397c478bd9Sstevel@tonic-gate 		}
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 		/*
1427c478bd9Sstevel@tonic-gate 		 * terminate after last non-whitespace char.
1437c478bd9Sstevel@tonic-gate 		 */
1447c478bd9Sstevel@tonic-gate 		*(tmpstr+1) = '\0';
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * dsym_get_token(): strtok_r() like routine, except consecutive delimiters
1507c478bd9Sstevel@tonic-gate  *                   result in an empty string
1517c478bd9Sstevel@tonic-gate  *
1527c478bd9Sstevel@tonic-gate  *   note: original string is modified
1537c478bd9Sstevel@tonic-gate  *
1547c478bd9Sstevel@tonic-gate  *  input: char *: string in which to search for tokens
1557c478bd9Sstevel@tonic-gate  *         char *: list of possible token delimiter characters
1567c478bd9Sstevel@tonic-gate  *         char **: location for next call to routine
1577c478bd9Sstevel@tonic-gate  *         boolean_t: should delimiters be ignored if within quoted string?
1587c478bd9Sstevel@tonic-gate  * output: char *: token, or NULL if no more tokens
1597c478bd9Sstevel@tonic-gate  */
160*d04ccbb3Scarlsonj 
1617c478bd9Sstevel@tonic-gate static char *
1627c478bd9Sstevel@tonic-gate dsym_get_token(char *str, char *dels, char **lasts, boolean_t quote_support)
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	char *ptr = str;
1667c478bd9Sstevel@tonic-gate 	char *del;
1677c478bd9Sstevel@tonic-gate 	boolean_t found = B_FALSE;
1687c478bd9Sstevel@tonic-gate 	boolean_t in_quote = B_FALSE;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/*
1717c478bd9Sstevel@tonic-gate 	 * If incoming string has no tokens return a NULL
1727c478bd9Sstevel@tonic-gate 	 * pointer to signify no more tokens.
1737c478bd9Sstevel@tonic-gate 	 */
1747c478bd9Sstevel@tonic-gate 	if (*ptr == '\0') {
1757c478bd9Sstevel@tonic-gate 		return (NULL);
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	/*
1797c478bd9Sstevel@tonic-gate 	 * Loop until either a token has been identified or until end
1807c478bd9Sstevel@tonic-gate 	 * of string has been reached.
1817c478bd9Sstevel@tonic-gate 	 */
1827c478bd9Sstevel@tonic-gate 	while (!found && *ptr != '\0') {
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 		/*
1857c478bd9Sstevel@tonic-gate 		 * If pointer currently lies within a quoted string,
1867c478bd9Sstevel@tonic-gate 		 * then do not check for the delimiter.
1877c478bd9Sstevel@tonic-gate 		 */
1887c478bd9Sstevel@tonic-gate 		if (!in_quote) {
1897c478bd9Sstevel@tonic-gate 			for (del = dels; !found && *del != '\0'; del++) {
1907c478bd9Sstevel@tonic-gate 				if (*del == *ptr) {
1917c478bd9Sstevel@tonic-gate 					*ptr++ = '\0';
1927c478bd9Sstevel@tonic-gate 					found = B_TRUE;
1937c478bd9Sstevel@tonic-gate 				}
1947c478bd9Sstevel@tonic-gate 			}
1957c478bd9Sstevel@tonic-gate 		}
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		/*
1987c478bd9Sstevel@tonic-gate 		 * If the pointer is pointing at a delimiter, then
1997c478bd9Sstevel@tonic-gate 		 * check to see if it points to at a quote and update
2007c478bd9Sstevel@tonic-gate 		 * the state appropriately.
2017c478bd9Sstevel@tonic-gate 		 */
2027c478bd9Sstevel@tonic-gate 		if (!found) {
2037c478bd9Sstevel@tonic-gate 			if (quote_support && *ptr == DSYM_QUOTE) {
2047c478bd9Sstevel@tonic-gate 				in_quote = !in_quote;
2057c478bd9Sstevel@tonic-gate 			}
2067c478bd9Sstevel@tonic-gate 			ptr++;
2077c478bd9Sstevel@tonic-gate 		}
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	*lasts = ptr;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	return (str);
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate /*
2167c478bd9Sstevel@tonic-gate  * dsym_get_long(): given a numeric string, returns its long value
2177c478bd9Sstevel@tonic-gate  *
2187c478bd9Sstevel@tonic-gate  *  input: const char *: the numeric string
2197c478bd9Sstevel@tonic-gate  *         long *: the return location for the long value
2207c478bd9Sstevel@tonic-gate  * output: DSYM_SUCCESS, DSYM_VALUE_OUT_OF_RANGE or DSYM_SYNTAX_ERROR
2217c478bd9Sstevel@tonic-gate  */
222*d04ccbb3Scarlsonj 
2237c478bd9Sstevel@tonic-gate static dsym_errcode_t
2247c478bd9Sstevel@tonic-gate dsym_get_long(const char *str, long *val)
2257c478bd9Sstevel@tonic-gate {
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	int ret = DSYM_SUCCESS;
2287c478bd9Sstevel@tonic-gate 	int i;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	for (i = 0; str[i] != '\0'; i++) {
2317c478bd9Sstevel@tonic-gate 		if (!isdigit(str[i])) {
2327c478bd9Sstevel@tonic-gate 			return (DSYM_SYNTAX_ERROR);
2337c478bd9Sstevel@tonic-gate 		}
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	errno = 0;
2377c478bd9Sstevel@tonic-gate 	*val = strtol(str, NULL, 10);
2387c478bd9Sstevel@tonic-gate 	if (errno != 0) {
2397c478bd9Sstevel@tonic-gate 		ret = DSYM_VALUE_OUT_OF_RANGE;
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	return (ret);
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate /*
2467c478bd9Sstevel@tonic-gate  * dsym_free_classes(): frees the classes allocated by dsym_parse_classes()
2477c478bd9Sstevel@tonic-gate  *
2487c478bd9Sstevel@tonic-gate  *  input: dhcp_classes_t *: pointer to structure containing classes to free
2497c478bd9Sstevel@tonic-gate  * output: none
2507c478bd9Sstevel@tonic-gate  */
251*d04ccbb3Scarlsonj 
2527c478bd9Sstevel@tonic-gate void
2537c478bd9Sstevel@tonic-gate dsym_free_classes(dhcp_classes_t *classes)
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	int i;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if (classes->dc_names == NULL) {
2597c478bd9Sstevel@tonic-gate 		return;
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	for (i = 0; i < classes->dc_cnt; i++) {
2637c478bd9Sstevel@tonic-gate 		free(classes->dc_names[i]);
2647c478bd9Sstevel@tonic-gate 	}
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	free(classes->dc_names);
2677c478bd9Sstevel@tonic-gate 	classes->dc_names = NULL;
2687c478bd9Sstevel@tonic-gate 	classes->dc_cnt = 0;
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * dsym_parse_classes(): given a "Vendor" class string, builds and returns
2737c478bd9Sstevel@tonic-gate  *                     the list of vendor classes
2747c478bd9Sstevel@tonic-gate  *
2757c478bd9Sstevel@tonic-gate  *  input: char *: the "Vendor" class string
2767c478bd9Sstevel@tonic-gate  *         dhcp_classes_t *: pointer to the classes structure
2777c478bd9Sstevel@tonic-gate  * output: DSYM_SUCCESS, DSYM_INVALID_CAT, DSYM_EXCEEDS_MAX_CLASS_SIZE,
2787c478bd9Sstevel@tonic-gate  *         DSYM_EXCEEDS_CLASS_SIZE, DSYM_SYNTAX_ERROR, or DSYM_NO_MEMORY
2797c478bd9Sstevel@tonic-gate  */
280*d04ccbb3Scarlsonj 
2817c478bd9Sstevel@tonic-gate static dsym_errcode_t
2827c478bd9Sstevel@tonic-gate dsym_parse_classes(char *ptr, dhcp_classes_t *classes_ret)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	char **classes = NULL;
2867c478bd9Sstevel@tonic-gate 	char *cp;
2877c478bd9Sstevel@tonic-gate 	int len;
2887c478bd9Sstevel@tonic-gate 	int ret = DSYM_SUCCESS;
2897c478bd9Sstevel@tonic-gate 	int i;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	while (*ptr != '\0') {
2927c478bd9Sstevel@tonic-gate 		if (*ptr == DSYM_VENDOR_DEL) {
2937c478bd9Sstevel@tonic-gate 			ptr++;
2947c478bd9Sstevel@tonic-gate 			break;
2957c478bd9Sstevel@tonic-gate 		}
2967c478bd9Sstevel@tonic-gate 		ptr++;
2977c478bd9Sstevel@tonic-gate 	}
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	if (*ptr == '\0') {
3007c478bd9Sstevel@tonic-gate 	    return (DSYM_INVALID_CAT);
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	if (strlen(ptr) > DSYM_MAX_CLASS_SIZE) {
3047c478bd9Sstevel@tonic-gate 		return (DSYM_EXCEEDS_MAX_CLASS_SIZE);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	dsym_trim(&ptr);
3087c478bd9Sstevel@tonic-gate 	classes_ret->dc_cnt = 0;
3097c478bd9Sstevel@tonic-gate 	for (i = 0; ret == DSYM_SUCCESS; i++) {
3107c478bd9Sstevel@tonic-gate 		cp = dsym_get_token(ptr, DSYM_CLASS_DEL, &ptr, B_TRUE);
3117c478bd9Sstevel@tonic-gate 		if (cp == NULL) {
3127c478bd9Sstevel@tonic-gate 			break;
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 		len = strlen(cp);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 		if (len == 0) {
3187c478bd9Sstevel@tonic-gate 			continue;
3197c478bd9Sstevel@tonic-gate 		} else if (len > DSYM_CLASS_SIZE) {
3207c478bd9Sstevel@tonic-gate 			ret = DSYM_EXCEEDS_CLASS_SIZE;
3217c478bd9Sstevel@tonic-gate 			continue;
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 		if (cp[0] == DSYM_QUOTE && cp[len-1] != DSYM_QUOTE) {
3257c478bd9Sstevel@tonic-gate 			ret = DSYM_SYNTAX_ERROR;
3267c478bd9Sstevel@tonic-gate 			continue;
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 		/* Strip off the quotes */
3307c478bd9Sstevel@tonic-gate 		if (cp[0] == DSYM_QUOTE) {
3317c478bd9Sstevel@tonic-gate 			cp[len-1] = '\0';
3327c478bd9Sstevel@tonic-gate 			cp++;
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 		classes = realloc(classes_ret->dc_names,
3367c478bd9Sstevel@tonic-gate 		    (sizeof (char **)) * (classes_ret->dc_cnt + 1));
3377c478bd9Sstevel@tonic-gate 		if (classes == NULL ||
3387c478bd9Sstevel@tonic-gate 		    (classes[classes_ret->dc_cnt] = strdup(cp))
3397c478bd9Sstevel@tonic-gate 		    == NULL) {
3407c478bd9Sstevel@tonic-gate 			ret = DSYM_NO_MEMORY;
3417c478bd9Sstevel@tonic-gate 			continue;
3427c478bd9Sstevel@tonic-gate 		}
3437c478bd9Sstevel@tonic-gate 		classes_ret->dc_names = classes;
3447c478bd9Sstevel@tonic-gate 		classes_ret->dc_cnt++;
3457c478bd9Sstevel@tonic-gate 	}
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	if (ret != DSYM_SUCCESS) {
3487c478bd9Sstevel@tonic-gate 		dsym_free_classes(classes_ret);
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	return (ret);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate /*
3557c478bd9Sstevel@tonic-gate  * dsym_get_cat_by_name(): given a category field, returns the pointer to its
3567c478bd9Sstevel@tonic-gate  *                         entry in the internal category table.
3577c478bd9Sstevel@tonic-gate  *
3587c478bd9Sstevel@tonic-gate  *  input: const char *: the category name
3597c478bd9Sstevel@tonic-gate  *         dsym_cat_t *: the return location for the pointer to the table entry
3607c478bd9Sstevel@tonic-gate  *         boolean_t: case-sensitive name compare
3617c478bd9Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT
3627c478bd9Sstevel@tonic-gate  */
363*d04ccbb3Scarlsonj 
3647c478bd9Sstevel@tonic-gate static dsym_errcode_t
3657c478bd9Sstevel@tonic-gate dsym_get_cat_by_name(const char *cat, dsym_cat_t **entry, boolean_t cs)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	dsym_cat_t *entryp = NULL;
3697c478bd9Sstevel@tonic-gate 	int ret = DSYM_SUCCESS;
3707c478bd9Sstevel@tonic-gate 	int cnt = sizeof (cats) / sizeof (dsym_cat_t);
3717c478bd9Sstevel@tonic-gate 	int result;
3727c478bd9Sstevel@tonic-gate 	int len;
3737c478bd9Sstevel@tonic-gate 	int i;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 		len = cats[i].dc_minlen;
3787c478bd9Sstevel@tonic-gate 		if (cs) {
3797c478bd9Sstevel@tonic-gate 			result = strncmp(cat, cats[i].dc_string, len);
3807c478bd9Sstevel@tonic-gate 		} else {
3817c478bd9Sstevel@tonic-gate 			result = strncasecmp(cat, cats[i].dc_string, len);
3827c478bd9Sstevel@tonic-gate 		}
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 		if (result == 0) {
3857c478bd9Sstevel@tonic-gate 			entryp = &cats[i];
3867c478bd9Sstevel@tonic-gate 			break;
3877c478bd9Sstevel@tonic-gate 		}
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	if (entryp != NULL) {
3917c478bd9Sstevel@tonic-gate 		/*
3927c478bd9Sstevel@tonic-gate 		 * Special code required for the Vendor category, because we
3937c478bd9Sstevel@tonic-gate 		 * allow whitespace between the keyword and the delimiter.
3947c478bd9Sstevel@tonic-gate 		 * If there is no delimiter, then this is an illegal category.
3957c478bd9Sstevel@tonic-gate 		 */
3967c478bd9Sstevel@tonic-gate 		const char *ptr = cat + entryp->dc_minlen;
3977c478bd9Sstevel@tonic-gate 		if (entryp->dc_id == DSYM_VENDOR) {
3987c478bd9Sstevel@tonic-gate 			while (*ptr != '\0' && isspace(*ptr)) {
3997c478bd9Sstevel@tonic-gate 				ptr++;
4007c478bd9Sstevel@tonic-gate 			}
4017c478bd9Sstevel@tonic-gate 			if (*ptr != DSYM_VENDOR_DEL) {
4027c478bd9Sstevel@tonic-gate 				ret = DSYM_INVALID_CAT;
4037c478bd9Sstevel@tonic-gate 			}
4047c478bd9Sstevel@tonic-gate 		} else {
4057c478bd9Sstevel@tonic-gate 			if (*ptr != '\0') {
4067c478bd9Sstevel@tonic-gate 				ret = DSYM_INVALID_CAT;
4077c478bd9Sstevel@tonic-gate 			}
4087c478bd9Sstevel@tonic-gate 		}
4097c478bd9Sstevel@tonic-gate 	} else {
4107c478bd9Sstevel@tonic-gate 		ret = DSYM_INVALID_CAT;
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
4147c478bd9Sstevel@tonic-gate 		*entry = entryp;
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	return (ret);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate  * dsym_parse_cat(): given a category field, returns the category value
4227c478bd9Sstevel@tonic-gate  *                 Note: The category must be a valid dhcptab category.
4237c478bd9Sstevel@tonic-gate  *
4247c478bd9Sstevel@tonic-gate  *  input: const char *: a category field
4257c478bd9Sstevel@tonic-gate  *         dsym_category_t *: the return location for the category value
4267c478bd9Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT
4277c478bd9Sstevel@tonic-gate  */
428*d04ccbb3Scarlsonj 
4297c478bd9Sstevel@tonic-gate static dsym_errcode_t
4307c478bd9Sstevel@tonic-gate dsym_parse_cat(const char *field, dsym_category_t *cat)
4317c478bd9Sstevel@tonic-gate {
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	dsym_cat_t *entry;
4347c478bd9Sstevel@tonic-gate 	int ret;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	ret = dsym_get_cat_by_name(field, &entry, B_TRUE);
4377c478bd9Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
4387c478bd9Sstevel@tonic-gate 		/*
4397c478bd9Sstevel@tonic-gate 		 * Since this routine is meant to be used to parse dhcptab
4407c478bd9Sstevel@tonic-gate 		 * symbol definitions, only a subset of the DHCP categories
4417c478bd9Sstevel@tonic-gate 		 * are valid in this context.
4427c478bd9Sstevel@tonic-gate 		 */
4437c478bd9Sstevel@tonic-gate 		if (entry->dc_dhcptab) {
4447c478bd9Sstevel@tonic-gate 			*cat = entry->dc_id;
4457c478bd9Sstevel@tonic-gate 		} else {
4467c478bd9Sstevel@tonic-gate 			ret = DSYM_INVALID_CAT;
4477c478bd9Sstevel@tonic-gate 		}
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	return (ret);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate /*
4547c478bd9Sstevel@tonic-gate  * dsym_parse_intrange(): given a DHCP integer field, returns the value
4557c478bd9Sstevel@tonic-gate  *
4567c478bd9Sstevel@tonic-gate  *  input: const char *: a DHCP code field
4577c478bd9Sstevel@tonic-gate  *         int *: the return location for the value
4587c478bd9Sstevel@tonic-gate  *         int: the minimum valid value
4597c478bd9Sstevel@tonic-gate  *         int: the maximum valid value
4607c478bd9Sstevel@tonic-gate  * output: int: DSYM_SUCCESS, DSYM_SYNTAX_ERROR, or DSYM_VALUE_OUT_OF_RANGE
4617c478bd9Sstevel@tonic-gate  */
462*d04ccbb3Scarlsonj 
4637c478bd9Sstevel@tonic-gate static dsym_errcode_t
4647c478bd9Sstevel@tonic-gate dsym_parse_intrange(const char *field, int *intval, int min, int max)
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	int ret;
4687c478bd9Sstevel@tonic-gate 	long longval;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	ret = dsym_get_long(field, &longval);
4717c478bd9Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
4727c478bd9Sstevel@tonic-gate 		if (longval < min || longval > max) {
4737c478bd9Sstevel@tonic-gate 			ret = DSYM_VALUE_OUT_OF_RANGE;
4747c478bd9Sstevel@tonic-gate 		} else {
4757c478bd9Sstevel@tonic-gate 			*intval = (int)longval;
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 	return (ret);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate /*
4827c478bd9Sstevel@tonic-gate  * dsym_validate_code(): given a symbol category and code, validates
4837c478bd9Sstevel@tonic-gate  *                       that the code is valid for the category
4847c478bd9Sstevel@tonic-gate  *
4857c478bd9Sstevel@tonic-gate  *  input: dsym_category_t: the symbol category
4867c478bd9Sstevel@tonic-gate  *         uint16_t: the symbol code
4877c478bd9Sstevel@tonic-gate  * output: DSYM_SUCCESS, DSYM_INVALID_CAT or DSYM_CODE_OUT_OF_RANGE
4887c478bd9Sstevel@tonic-gate  */
489*d04ccbb3Scarlsonj 
4907c478bd9Sstevel@tonic-gate static dsym_errcode_t
4917c478bd9Sstevel@tonic-gate dsym_validate_code(dsym_category_t cat, ushort_t code)
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	int cnt = sizeof (cats) / sizeof (dsym_cat_t);
4957c478bd9Sstevel@tonic-gate 	int i;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/*
4987c478bd9Sstevel@tonic-gate 	 * Find the category entry from the internal table.
4997c478bd9Sstevel@tonic-gate 	 */
5007c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
5017c478bd9Sstevel@tonic-gate 		dsym_cat_t *entry;
5027c478bd9Sstevel@tonic-gate 		if (cat == cats[i].dc_id) {
5037c478bd9Sstevel@tonic-gate 			entry = &cats[i];
5047c478bd9Sstevel@tonic-gate 			if (code < entry->dc_min || code > entry->dc_max) {
5057c478bd9Sstevel@tonic-gate 				return (DSYM_CODE_OUT_OF_RANGE);
5067c478bd9Sstevel@tonic-gate 			}
5077c478bd9Sstevel@tonic-gate 			return (DSYM_SUCCESS);
5087c478bd9Sstevel@tonic-gate 		}
5097c478bd9Sstevel@tonic-gate 	}
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	return (DSYM_INVALID_CAT);
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate /*
5157c478bd9Sstevel@tonic-gate  * dsym_validate_granularity(): given a symbol type, validates
5167c478bd9Sstevel@tonic-gate  *                       	that the granularity is valid for the type
5177c478bd9Sstevel@tonic-gate  *
5187c478bd9Sstevel@tonic-gate  *  input: dsym_cdtype_t: the symbol type
5197c478bd9Sstevel@tonic-gate  *         uchar_t: the symbol granularity
5207c478bd9Sstevel@tonic-gate  * output: DSYM_SUCCESS or DSYM_VALUE_OUT_OF_RANGE
5217c478bd9Sstevel@tonic-gate  */
522*d04ccbb3Scarlsonj 
5237c478bd9Sstevel@tonic-gate static dsym_errcode_t
5247c478bd9Sstevel@tonic-gate dsym_validate_granularity(dsym_cdtype_t type, uchar_t gran)
5257c478bd9Sstevel@tonic-gate {
5267c478bd9Sstevel@tonic-gate 	/*
5277c478bd9Sstevel@tonic-gate 	 * We only need to check for a 0 with non-boolean types, as
5287c478bd9Sstevel@tonic-gate 	 * anything else is already validated by the ranges passed to
5297c478bd9Sstevel@tonic-gate 	 * dsym_parse_intrange() in dsym_parse_field().
5307c478bd9Sstevel@tonic-gate 	 */
5317c478bd9Sstevel@tonic-gate 	if (gran == 0 && type != DSYM_BOOL) {
5327c478bd9Sstevel@tonic-gate 		return (DSYM_VALUE_OUT_OF_RANGE);
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 	return (DSYM_SUCCESS);
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate  * dsym_get_type_by_name(): given a type field, returns the pointer to its
5397c478bd9Sstevel@tonic-gate  *                          entry in the internal type table.
5407c478bd9Sstevel@tonic-gate  *
5417c478bd9Sstevel@tonic-gate  *  input: const char *: the type name
5427c478bd9Sstevel@tonic-gate  *         dsym_type_t *: the return location for the pointer to the table entry
5437c478bd9Sstevel@tonic-gate  *         boolean_t: case-sensitive name compare
5447c478bd9Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_TYPE
5457c478bd9Sstevel@tonic-gate  */
546*d04ccbb3Scarlsonj 
5477c478bd9Sstevel@tonic-gate static dsym_errcode_t
5487c478bd9Sstevel@tonic-gate dsym_get_type_by_name(const char *type, dsym_type_t **entry, boolean_t cs)
5497c478bd9Sstevel@tonic-gate {
5507c478bd9Sstevel@tonic-gate 	int cnt = sizeof (types) / sizeof (dsym_type_t);
5517c478bd9Sstevel@tonic-gate 	int result;
5527c478bd9Sstevel@tonic-gate 	int i;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 		if (cs) {
5577c478bd9Sstevel@tonic-gate 			result = strcmp(type, types[i].dt_string);
5587c478bd9Sstevel@tonic-gate 		} else {
5597c478bd9Sstevel@tonic-gate 			result = strcasecmp(type, types[i].dt_string);
5607c478bd9Sstevel@tonic-gate 		}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 		if (result == 0) {
5637c478bd9Sstevel@tonic-gate 			*entry = &types[i];
5647c478bd9Sstevel@tonic-gate 			return (DSYM_SUCCESS);
5657c478bd9Sstevel@tonic-gate 		}
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	return (DSYM_INVALID_TYPE);
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate /*
5727c478bd9Sstevel@tonic-gate  * dsym_parse_type(): given a DHCP type string, returns the type id
5737c478bd9Sstevel@tonic-gate  *
5747c478bd9Sstevel@tonic-gate  *  input: char *: a DHCP type string
5757c478bd9Sstevel@tonic-gate  *         dsym_cdtype_t *: the return location for the type id
5767c478bd9Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_TYPE
5777c478bd9Sstevel@tonic-gate  */
578*d04ccbb3Scarlsonj 
5797c478bd9Sstevel@tonic-gate static dsym_errcode_t
5807c478bd9Sstevel@tonic-gate dsym_parse_type(char *field, dsym_cdtype_t *type)
5817c478bd9Sstevel@tonic-gate {
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	dsym_type_t *entry;
5847c478bd9Sstevel@tonic-gate 	int ret;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	ret = dsym_get_type_by_name(field, &entry, B_TRUE);
5877c478bd9Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
5887c478bd9Sstevel@tonic-gate 		/*
5897c478bd9Sstevel@tonic-gate 		 * Since this routine is meant to be used to parse dhcptab
5907c478bd9Sstevel@tonic-gate 		 * symbol definitions, only a subset of the DHCP type
5917c478bd9Sstevel@tonic-gate 		 * are valid in this context.
5927c478bd9Sstevel@tonic-gate 		 */
5937c478bd9Sstevel@tonic-gate 		if (entry->dt_dhcptab) {
5947c478bd9Sstevel@tonic-gate 			*type = entry->dt_id;
5957c478bd9Sstevel@tonic-gate 		} else {
5967c478bd9Sstevel@tonic-gate 			ret = DSYM_INVALID_TYPE;
5977c478bd9Sstevel@tonic-gate 		}
5987c478bd9Sstevel@tonic-gate 	}
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	return (ret);
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate /*
6047c478bd9Sstevel@tonic-gate  * dsym_free_fields(): frees an array of fields allocated by
6057c478bd9Sstevel@tonic-gate  *                     dsym_init_parser().
6067c478bd9Sstevel@tonic-gate  *
6077c478bd9Sstevel@tonic-gate  *  input: char **: array of fields to free
6087c478bd9Sstevel@tonic-gate  * output: none
6097c478bd9Sstevel@tonic-gate  */
610*d04ccbb3Scarlsonj 
6117c478bd9Sstevel@tonic-gate void
6127c478bd9Sstevel@tonic-gate dsym_free_fields(char **fields)
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate 	int i;
6157c478bd9Sstevel@tonic-gate 	if (fields != NULL) {
6167c478bd9Sstevel@tonic-gate 		for (i = 0; i < DSYM_NUM_FIELDS; i++) {
6177c478bd9Sstevel@tonic-gate 			free(fields[i]);
6187c478bd9Sstevel@tonic-gate 		}
6197c478bd9Sstevel@tonic-gate 		free(fields);
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate /*
6247c478bd9Sstevel@tonic-gate  * dsym_close_parser(): free up all resources associated with the parser
6257c478bd9Sstevel@tonic-gate  *
6267c478bd9Sstevel@tonic-gate  *  input: char **: the fields allocated by dsym_init_parser()
6277c478bd9Sstevel@tonic-gate  *         dhcp_symbol_t *: the structure populated by dsym_init_parser()
6287c478bd9Sstevel@tonic-gate  * output: none
6297c478bd9Sstevel@tonic-gate  */
630*d04ccbb3Scarlsonj 
6317c478bd9Sstevel@tonic-gate void
6327c478bd9Sstevel@tonic-gate dsym_close_parser(char **fields, dhcp_symbol_t *sym)
6337c478bd9Sstevel@tonic-gate {
6347c478bd9Sstevel@tonic-gate 	dsym_free_fields(fields);
6357c478bd9Sstevel@tonic-gate 	dsym_free_classes(&sym->ds_classes);
6367c478bd9Sstevel@tonic-gate }
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate /*
6397c478bd9Sstevel@tonic-gate  * dsym_init_parser(): initializes the structures used to parse a symbol
6407c478bd9Sstevel@tonic-gate  *                     value.
6417c478bd9Sstevel@tonic-gate  *
6427c478bd9Sstevel@tonic-gate  *  input: const char *: the symbol name
6437c478bd9Sstevel@tonic-gate  *         const char *: the symbol value in dhcptab format
6447c478bd9Sstevel@tonic-gate  *         char ***: the return location for the symbol fields
6457c478bd9Sstevel@tonic-gate  *         dhcp_symbol_t *: the structure which eventually will
6467c478bd9Sstevel@tonic-gate  *                          be the repository for the parsed symbol data
6477c478bd9Sstevel@tonic-gate  * output: int: DSYM_SUCCESS, DYSM_NO_MEMORY, DSYM_NULL_FIELD or
6487c478bd9Sstevel@tonic-gate  *              DSYM_TOO_MANY_FIELDS
6497c478bd9Sstevel@tonic-gate  */
650*d04ccbb3Scarlsonj 
6517c478bd9Sstevel@tonic-gate dsym_errcode_t
6527c478bd9Sstevel@tonic-gate dsym_init_parser(const char *name, const char *value, char ***fields_ret,
6537c478bd9Sstevel@tonic-gate     dhcp_symbol_t *sym)
6547c478bd9Sstevel@tonic-gate {
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	int ret = DSYM_SUCCESS;
6577c478bd9Sstevel@tonic-gate 	char *cp;
6587c478bd9Sstevel@tonic-gate 	char *next;
6597c478bd9Sstevel@tonic-gate 	char *field;
6607c478bd9Sstevel@tonic-gate 	char **fields;
6617c478bd9Sstevel@tonic-gate 	int i;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	/*
6647c478bd9Sstevel@tonic-gate 	 * Initialize the symbol structure.
6657c478bd9Sstevel@tonic-gate 	 */
6667c478bd9Sstevel@tonic-gate 	sym->ds_category = 0;
6677c478bd9Sstevel@tonic-gate 	sym->ds_code = 0;
6687c478bd9Sstevel@tonic-gate 	(void) strlcpy(sym->ds_name, name, DSYM_MAX_SYM_LEN);
6697c478bd9Sstevel@tonic-gate 	sym->ds_type = 0;
6707c478bd9Sstevel@tonic-gate 	sym->ds_gran = 0;
6717c478bd9Sstevel@tonic-gate 	sym->ds_max = 0;
6727c478bd9Sstevel@tonic-gate 	sym->ds_classes.dc_names = NULL;
6737c478bd9Sstevel@tonic-gate 	sym->ds_classes.dc_cnt = 0;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	if ((cp = strdup(value)) == NULL ||
6767c478bd9Sstevel@tonic-gate 	    (fields = calloc(DSYM_NUM_FIELDS, sizeof (char *))) == NULL) {
6777c478bd9Sstevel@tonic-gate 		ret = DSYM_NO_MEMORY;
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	next = cp;
6817c478bd9Sstevel@tonic-gate 	for (i = 0; ret == DSYM_SUCCESS && i < DSYM_NUM_FIELDS; i++) {
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 		field = dsym_get_token(next, DSYM_FIELD_DEL, &next,
6847c478bd9Sstevel@tonic-gate 			B_FALSE);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 		if (field == NULL) {
6877c478bd9Sstevel@tonic-gate 			ret = DSYM_NULL_FIELD;
6887c478bd9Sstevel@tonic-gate 			continue;
6897c478bd9Sstevel@tonic-gate 		}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 		dsym_trim(&field);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 		if (strlen(field) == 0) {
6947c478bd9Sstevel@tonic-gate 			ret = DSYM_NULL_FIELD;
6957c478bd9Sstevel@tonic-gate 			continue;
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 		if ((fields[i] = strdup(field)) == NULL) {
6997c478bd9Sstevel@tonic-gate 			ret = DSYM_NO_MEMORY;
7007c478bd9Sstevel@tonic-gate 			continue;
7017c478bd9Sstevel@tonic-gate 		}
7027c478bd9Sstevel@tonic-gate 	}
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS &&
7057c478bd9Sstevel@tonic-gate 	    dsym_get_token(next, DSYM_FIELD_DEL, &next, B_FALSE) != NULL) {
7067c478bd9Sstevel@tonic-gate 		ret = DSYM_TOO_MANY_FIELDS;
7077c478bd9Sstevel@tonic-gate 	}
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	if (ret != DSYM_SUCCESS) {
7107c478bd9Sstevel@tonic-gate 		dsym_free_fields(fields);
7117c478bd9Sstevel@tonic-gate 	} else {
7127c478bd9Sstevel@tonic-gate 		*fields_ret = fields;
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	free(cp);
7167c478bd9Sstevel@tonic-gate 	return (ret);
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate /*
7207c478bd9Sstevel@tonic-gate  * dsym_parse_field(): parses the specified symbol field.
7217c478bd9Sstevel@tonic-gate  *
7227c478bd9Sstevel@tonic-gate  *  input: int: the field number to be parsed.
7237c478bd9Sstevel@tonic-gate  *         char **: symbol fields initialized by dsym_init_parser()
7247c478bd9Sstevel@tonic-gate  *         dhcp_symbol_t *: the structure which will be the repository
7257c478bd9Sstevel@tonic-gate  *                          for the parsed field
7267c478bd9Sstevel@tonic-gate  * output: int: DSYM_SUCCESS, DSYM_SYNTAX_ERROR, DSYM_CODE_OUT_OF_RANGE,
7277c478bd9Sstevel@tonic-gate  *              DSYM_INVALID_CAT, DSYM_INVALID_TYPE, DSYM_EXCEEDS_CLASS_SIZE,
7287c478bd9Sstevel@tonic-gate  *              DSYM_EXCEEDS_MAX_CLASS_SIZE, DSYM_NO_MEMORY,
7297c478bd9Sstevel@tonic-gate  *              DSYM_INVALID_FIELD_NUM, DSYM_VALUE_OUT_OF_RANGE
7307c478bd9Sstevel@tonic-gate  */
731*d04ccbb3Scarlsonj 
7327c478bd9Sstevel@tonic-gate dsym_errcode_t
7337c478bd9Sstevel@tonic-gate dsym_parse_field(int field_num, char **fields, dhcp_symbol_t *sym)
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	int 	ret = DSYM_SUCCESS;
7377c478bd9Sstevel@tonic-gate 	int	intval;
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	switch (field_num) {
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	case DSYM_CAT_FIELD:
7427c478bd9Sstevel@tonic-gate 		ret = dsym_parse_cat(fields[field_num], &sym->ds_category);
7437c478bd9Sstevel@tonic-gate 		if (ret == DSYM_SUCCESS && sym->ds_category == DSYM_VENDOR) {
7447c478bd9Sstevel@tonic-gate 			ret = dsym_parse_classes(fields[field_num],
7457c478bd9Sstevel@tonic-gate 			    &sym->ds_classes);
7467c478bd9Sstevel@tonic-gate 		}
7477c478bd9Sstevel@tonic-gate 		break;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	case DSYM_CODE_FIELD:
7507c478bd9Sstevel@tonic-gate 		ret = dsym_parse_intrange(fields[field_num], &intval, 0,
7517c478bd9Sstevel@tonic-gate 		    USHRT_MAX);
7527c478bd9Sstevel@tonic-gate 		if (ret == DSYM_SUCCESS) {
7537c478bd9Sstevel@tonic-gate 			sym->ds_code = (ushort_t)intval;
7547c478bd9Sstevel@tonic-gate 			ret = dsym_validate_code(sym->ds_category,
7557c478bd9Sstevel@tonic-gate 			    sym->ds_code);
7567c478bd9Sstevel@tonic-gate 		}
7577c478bd9Sstevel@tonic-gate 		break;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	case DSYM_TYPE_FIELD:
7607c478bd9Sstevel@tonic-gate 		ret = dsym_parse_type(fields[field_num], &sym->ds_type);
7617c478bd9Sstevel@tonic-gate 		break;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	case DSYM_GRAN_FIELD:
7647c478bd9Sstevel@tonic-gate 		ret = dsym_parse_intrange(fields[field_num], &intval, 0,
7657c478bd9Sstevel@tonic-gate 		    UCHAR_MAX);
7667c478bd9Sstevel@tonic-gate 		if (ret == DSYM_SUCCESS) {
7677c478bd9Sstevel@tonic-gate 			sym->ds_gran = (uchar_t)intval;
7687c478bd9Sstevel@tonic-gate 			ret = dsym_validate_granularity(sym->ds_type,
7697c478bd9Sstevel@tonic-gate 			    sym->ds_gran);
7707c478bd9Sstevel@tonic-gate 		}
7717c478bd9Sstevel@tonic-gate 		break;
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	case DSYM_MAX_FIELD:
7747c478bd9Sstevel@tonic-gate 		ret = dsym_parse_intrange(fields[field_num], &intval, 0,
7757c478bd9Sstevel@tonic-gate 		    UCHAR_MAX);
7767c478bd9Sstevel@tonic-gate 		if (ret == DSYM_SUCCESS) {
7777c478bd9Sstevel@tonic-gate 			sym->ds_max = (uchar_t)intval;
7787c478bd9Sstevel@tonic-gate 		}
7797c478bd9Sstevel@tonic-gate 		break;
7807c478bd9Sstevel@tonic-gate 	default:
7817c478bd9Sstevel@tonic-gate 		ret = DSYM_INVALID_FIELD_NUM;
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	return (ret);
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate /*
7887c478bd9Sstevel@tonic-gate  * dsym_parser(): parses a DHCP symbol value
7897c478bd9Sstevel@tonic-gate  *
7907c478bd9Sstevel@tonic-gate  *  input: char **: symbol fields initialized by dsym_init_parser()
7917c478bd9Sstevel@tonic-gate  *         dhcp_symbol_t *: the structure which will be the repository
7927c478bd9Sstevel@tonic-gate  *                          for the parsed field
7937c478bd9Sstevel@tonic-gate  *         int *: last field processed
7947c478bd9Sstevel@tonic-gate  *         boolean_t: parse all fields even though errors occur?
7957c478bd9Sstevel@tonic-gate  * output: int: DSYM_SUCCESS, DSYM_SYNTAX_ERROR, DSYM_CODE_OUT_OF_RANGE,
7967c478bd9Sstevel@tonic-gate  *              DSYM_INVALID_CAT, DSYM_INVALID_TYPE, DSYM_EXCEEDS_CLASS_SIZE,
7977c478bd9Sstevel@tonic-gate  *              DSYM_EXCEEDS_MAX_CLASS_SIZE, DSYM_NO_MEMORY
7987c478bd9Sstevel@tonic-gate  *              DSYM_INVALID_FIELD_NUM, DSYM_VALUE_OUT_OF_RANGE
7997c478bd9Sstevel@tonic-gate  */
800*d04ccbb3Scarlsonj 
8017c478bd9Sstevel@tonic-gate dsym_errcode_t
8027c478bd9Sstevel@tonic-gate dsym_parser(char **fields, dhcp_symbol_t *sym, int *lastField,
8037c478bd9Sstevel@tonic-gate     boolean_t bestEffort)
8047c478bd9Sstevel@tonic-gate {
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	int ret = DSYM_SUCCESS;
8077c478bd9Sstevel@tonic-gate 	int tret = DSYM_SUCCESS;
8087c478bd9Sstevel@tonic-gate 	int i;
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	*lastField = -1;
8117c478bd9Sstevel@tonic-gate 	for (i = DSYM_FIRST_FIELD;
8127c478bd9Sstevel@tonic-gate 	    tret == DSYM_SUCCESS && i < DSYM_NUM_FIELDS; i++) {
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 		tret = dsym_parse_field(i, fields, sym);
8157c478bd9Sstevel@tonic-gate 		if (tret != DSYM_SUCCESS) {
8167c478bd9Sstevel@tonic-gate 			if (ret == DSYM_SUCCESS) {
8177c478bd9Sstevel@tonic-gate 				ret = tret;
8187c478bd9Sstevel@tonic-gate 			}
8197c478bd9Sstevel@tonic-gate 			if (bestEffort) {
8207c478bd9Sstevel@tonic-gate 				*lastField = i;
8217c478bd9Sstevel@tonic-gate 				tret = DSYM_SUCCESS;
8227c478bd9Sstevel@tonic-gate 			}
8237c478bd9Sstevel@tonic-gate 		}
8247c478bd9Sstevel@tonic-gate 	}
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	if (*lastField == -1) {
8277c478bd9Sstevel@tonic-gate 		*lastField = i - 1;
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	return (ret);
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate /*
8347c478bd9Sstevel@tonic-gate  * dsym_get_cat_id(): given a category string, return the associated id.
8357c478bd9Sstevel@tonic-gate  *
8367c478bd9Sstevel@tonic-gate  *  input: const char *: the category name
8377c478bd9Sstevel@tonic-gate  *         dsym_category_t *: the return location for the id
8387c478bd9Sstevel@tonic-gate  *         boolean_t: case-sensitive name compare
8397c478bd9Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT
8407c478bd9Sstevel@tonic-gate  */
841*d04ccbb3Scarlsonj 
8427c478bd9Sstevel@tonic-gate dsym_errcode_t
8437c478bd9Sstevel@tonic-gate dsym_get_cat_id(const char *cat, dsym_category_t *id, boolean_t cs)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	dsym_cat_t *entry;
8477c478bd9Sstevel@tonic-gate 	int ret;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	ret = dsym_get_cat_by_name(cat, &entry, cs);
8507c478bd9Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
8517c478bd9Sstevel@tonic-gate 		*id = entry->dc_id;
8527c478bd9Sstevel@tonic-gate 	}
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	return (ret);
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate /*
8587c478bd9Sstevel@tonic-gate  * dsym_get_code_ranges(): given a category field, returns its valid code
8597c478bd9Sstevel@tonic-gate  *                         ranges.
8607c478bd9Sstevel@tonic-gate  *
8617c478bd9Sstevel@tonic-gate  *  input: const char *: the category name
8627c478bd9Sstevel@tonic-gate  *         ushort *: return location for the minimum code value.
8637c478bd9Sstevel@tonic-gate  *         ushort *: return location for the maximum code value.
8647c478bd9Sstevel@tonic-gate  *         boolean_t: case-sensitive name compare
8657c478bd9Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT
8667c478bd9Sstevel@tonic-gate  */
867*d04ccbb3Scarlsonj 
8687c478bd9Sstevel@tonic-gate dsym_errcode_t
8697c478bd9Sstevel@tonic-gate dsym_get_code_ranges(const char *cat, ushort_t *min, ushort_t *max,
8707c478bd9Sstevel@tonic-gate     boolean_t cs)
8717c478bd9Sstevel@tonic-gate {
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	dsym_cat_t *entry;
8747c478bd9Sstevel@tonic-gate 	int ret;
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	ret = dsym_get_cat_by_name(cat, &entry, cs);
8777c478bd9Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
8787c478bd9Sstevel@tonic-gate 		*min = entry->dc_min;
8797c478bd9Sstevel@tonic-gate 		*max = entry->dc_max;
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	return (ret);
8837c478bd9Sstevel@tonic-gate }
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate /*
8867c478bd9Sstevel@tonic-gate  * dsym_get_type_id(): given a type string, return the associated type id.
8877c478bd9Sstevel@tonic-gate  *
8887c478bd9Sstevel@tonic-gate  *  input: const char *: the type name
8897c478bd9Sstevel@tonic-gate  *         dsym_cdtype_t *: the return location for the id
8907c478bd9Sstevel@tonic-gate  *         boolean_t: case-sensitive name compare
8917c478bd9Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_TYPE
8927c478bd9Sstevel@tonic-gate  */
893*d04ccbb3Scarlsonj 
8947c478bd9Sstevel@tonic-gate dsym_errcode_t
8957c478bd9Sstevel@tonic-gate dsym_get_type_id(const char *type, dsym_cdtype_t *id, boolean_t cs)
8967c478bd9Sstevel@tonic-gate {
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	dsym_type_t *entry;
8997c478bd9Sstevel@tonic-gate 	int ret;
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	ret = dsym_get_type_by_name(type, &entry, cs);
9027c478bd9Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
9037c478bd9Sstevel@tonic-gate 		*id = entry->dt_id;
9047c478bd9Sstevel@tonic-gate 	}
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	return (ret);
9077c478bd9Sstevel@tonic-gate }
908