10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23399Svikram  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include "cfga_usb.h"
300Sstevel@tonic-gate 
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #define	MAXLINESIZE	512
330Sstevel@tonic-gate #define	FE_BUFLEN 256
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #define	isunary(ch)	((ch) == '~' || (ch) == '-')
360Sstevel@tonic-gate #define	iswhite(ch)	((ch) == ' ' || (ch) == '\t')
370Sstevel@tonic-gate #define	isnewline(ch)	((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
380Sstevel@tonic-gate #define	isalphanum(ch)	(isalpha(ch) || isdigit(ch))
390Sstevel@tonic-gate #define	isnamechar(ch)	(isalphanum(ch) || (ch) == '_' || (ch) == '-')
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #define	MAX(a, b)	((a) < (b) ? (b) : (a))
420Sstevel@tonic-gate #define	GETC(a, cntr)	a[cntr++]
430Sstevel@tonic-gate #define	UNGETC(cntr)	cntr--
440Sstevel@tonic-gate 
450Sstevel@tonic-gate 
460Sstevel@tonic-gate typedef struct usb_configrec {
470Sstevel@tonic-gate 	char    *selection;
480Sstevel@tonic-gate 	int	idVendor, idProduct, cfgndx;
490Sstevel@tonic-gate 	char    *serialno;
500Sstevel@tonic-gate 	char    *pathname;
510Sstevel@tonic-gate 	char    *driver;
520Sstevel@tonic-gate } usb_configrec_t;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate typedef enum {
550Sstevel@tonic-gate 	USB_SELECTION, USB_VENDOR, USB_PRODUCT, USB_CFGNDX, USB_SRNO,
560Sstevel@tonic-gate 	USB_PATH, USB_DRIVER, USB_NONE
570Sstevel@tonic-gate } config_field_t;
580Sstevel@tonic-gate 
590Sstevel@tonic-gate typedef struct usbcfg_var {
600Sstevel@tonic-gate 	const char *name;
610Sstevel@tonic-gate 	config_field_t field;
620Sstevel@tonic-gate } usbcfg_var_t;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static usbcfg_var_t usbcfg_varlist[] = {
650Sstevel@tonic-gate 	{ "selection",	USB_SELECTION },
660Sstevel@tonic-gate 	{ "idVendor",	USB_VENDOR },
670Sstevel@tonic-gate 	{ "idProduct",	USB_PRODUCT },
680Sstevel@tonic-gate 	{ "cfgndx",	USB_CFGNDX },
690Sstevel@tonic-gate 	{ "srno",	USB_SRNO },
700Sstevel@tonic-gate 	{ "pathname",	USB_PATH },
710Sstevel@tonic-gate 	{ "driver",	USB_DRIVER },
720Sstevel@tonic-gate 	{ NULL,		USB_NONE }
730Sstevel@tonic-gate };
740Sstevel@tonic-gate 
750Sstevel@tonic-gate typedef enum {
760Sstevel@tonic-gate 	EQUALS,
770Sstevel@tonic-gate 	AMPERSAND,
780Sstevel@tonic-gate 	BIT_OR,
790Sstevel@tonic-gate 	STAR,
800Sstevel@tonic-gate 	POUND,
810Sstevel@tonic-gate 	COLON,
820Sstevel@tonic-gate 	SEMICOLON,
830Sstevel@tonic-gate 	COMMA,
840Sstevel@tonic-gate 	SLASH,
850Sstevel@tonic-gate 	WHITE_SPACE,
860Sstevel@tonic-gate 	NEWLINE,
870Sstevel@tonic-gate 	E_O_F,
880Sstevel@tonic-gate 	STRING,
890Sstevel@tonic-gate 	HEXVAL,
900Sstevel@tonic-gate 	DECVAL,
910Sstevel@tonic-gate 	NAME
920Sstevel@tonic-gate } token_t;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 
950Sstevel@tonic-gate static char	usbconf_file[] = USBCONF_FILE;
960Sstevel@tonic-gate static int	linenum = 1;
970Sstevel@tonic-gate static int	cntr = 0;
980Sstevel@tonic-gate static int	frec = 0;
990Sstevel@tonic-gate static int	brec = 0;
1000Sstevel@tonic-gate static int	btoken = 0;
1010Sstevel@tonic-gate mutex_t		file_lock = DEFAULTMUTEX;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate  * prototypes
1060Sstevel@tonic-gate  */
1070Sstevel@tonic-gate static int	get_string(u_longlong_t *llptr, char *tchar);
1080Sstevel@tonic-gate static int	getvalue(char *token, u_longlong_t *valuep);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /*
1120Sstevel@tonic-gate  * The next item on the line is a string value. Allocate memory for
1130Sstevel@tonic-gate  * it and copy the string. Return 1, and set arg ptr to newly allocated
1140Sstevel@tonic-gate  * and initialized buffer, or NULL if an error occurs.
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate static int
get_string(u_longlong_t * llptr,char * tchar)1170Sstevel@tonic-gate get_string(u_longlong_t *llptr, char *tchar)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate 	register char *cp;
1200Sstevel@tonic-gate 	register char *start = (char *)0;
1210Sstevel@tonic-gate 	register int len = 0;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	len = strlen(tchar);
1240Sstevel@tonic-gate 	start = tchar;
1250Sstevel@tonic-gate 	/* copy string */
1260Sstevel@tonic-gate 	cp = (char *)calloc(len + 1, sizeof (char));
1270Sstevel@tonic-gate 	if (cp == (char *)NULL) {
1280Sstevel@tonic-gate 		*llptr = NULL;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 		return (0);
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	*llptr = (u_longlong_t)(uintptr_t)cp;
1340Sstevel@tonic-gate 	for (; len > 0; len--) {
1350Sstevel@tonic-gate 		/* convert some common escape sequences */
1360Sstevel@tonic-gate 		if (*start == '\\') {
1370Sstevel@tonic-gate 			switch (*(start + 1)) {
1380Sstevel@tonic-gate 			case 't':
1390Sstevel@tonic-gate 				/* tab */
1400Sstevel@tonic-gate 				*cp++ = '\t';
1410Sstevel@tonic-gate 				len--;
1420Sstevel@tonic-gate 				start += 2;
1430Sstevel@tonic-gate 				break;
1440Sstevel@tonic-gate 			case 'n':
1450Sstevel@tonic-gate 				/* new line */
1460Sstevel@tonic-gate 				*cp++ = '\n';
1470Sstevel@tonic-gate 				len--;
1480Sstevel@tonic-gate 				start += 2;
1490Sstevel@tonic-gate 				break;
1500Sstevel@tonic-gate 			case 'b':
1510Sstevel@tonic-gate 				/* back space */
1520Sstevel@tonic-gate 				*cp++ = '\b';
1530Sstevel@tonic-gate 				len--;
1540Sstevel@tonic-gate 				start += 2;
1550Sstevel@tonic-gate 				break;
1560Sstevel@tonic-gate 			default:
1570Sstevel@tonic-gate 				/* simply copy it */
1580Sstevel@tonic-gate 				*cp++ = *start++;
1590Sstevel@tonic-gate 				break;
1600Sstevel@tonic-gate 			}
1610Sstevel@tonic-gate 		} else {
1620Sstevel@tonic-gate 			*cp++ = *start++;
1630Sstevel@tonic-gate 		}
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate 	*cp = '\0';
1660Sstevel@tonic-gate 	return (1);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate  * get a decimal octal or hex number. Handle '~' for one's complement.
1720Sstevel@tonic-gate  */
1730Sstevel@tonic-gate static int
getvalue(char * token,u_longlong_t * valuep)1740Sstevel@tonic-gate getvalue(char *token, u_longlong_t *valuep)
1750Sstevel@tonic-gate {
1760Sstevel@tonic-gate 	register int radix;
1770Sstevel@tonic-gate 	register u_longlong_t retval = 0;
1780Sstevel@tonic-gate 	register int onescompl = 0;
1790Sstevel@tonic-gate 	register int negate = 0;
1800Sstevel@tonic-gate 	register char c;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	if (*token == '~') {
1830Sstevel@tonic-gate 		onescompl++; /* perform one's complement on result */
1840Sstevel@tonic-gate 		token++;
1850Sstevel@tonic-gate 	} else if (*token == '-') {
1860Sstevel@tonic-gate 		negate++;
1870Sstevel@tonic-gate 		token++;
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 	if (*token == '0') {
1900Sstevel@tonic-gate 		token++;
1910Sstevel@tonic-gate 		c = *token;
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 		if (c == '\0') {
1940Sstevel@tonic-gate 			*valuep = 0;    /* value is 0 */
1950Sstevel@tonic-gate 			return (0);
1960Sstevel@tonic-gate 		}
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 		if (c == 'x' || c == 'X') {
1990Sstevel@tonic-gate 			radix = 16;
2000Sstevel@tonic-gate 			token++;
2010Sstevel@tonic-gate 		} else {
2020Sstevel@tonic-gate 			radix = 8;
2030Sstevel@tonic-gate 		}
2040Sstevel@tonic-gate 	} else {
2050Sstevel@tonic-gate 		radix = 10;
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	while ((c = *token++)) {
2090Sstevel@tonic-gate 		switch (radix) {
2100Sstevel@tonic-gate 		case 8:
2110Sstevel@tonic-gate 			if (c >= '0' && c <= '7') {
2120Sstevel@tonic-gate 				c -= '0';
2130Sstevel@tonic-gate 			} else {
2140Sstevel@tonic-gate 				return (-1);    /* invalid number */
2150Sstevel@tonic-gate 			}
2160Sstevel@tonic-gate 			retval = (retval << 3) + c;
2170Sstevel@tonic-gate 			break;
2180Sstevel@tonic-gate 		case 10:
2190Sstevel@tonic-gate 			if (c >= '0' && c <= '9') {
2200Sstevel@tonic-gate 				c -= '0';
2210Sstevel@tonic-gate 			} else {
2220Sstevel@tonic-gate 				return (-1);    /* invalid number */
2230Sstevel@tonic-gate 			}
2240Sstevel@tonic-gate 			retval = (retval * 10) + c;
2250Sstevel@tonic-gate 			break;
2260Sstevel@tonic-gate 		case 16:
2270Sstevel@tonic-gate 			if (c >= 'a' && c <= 'f') {
2280Sstevel@tonic-gate 				c = c - 'a' + 10;
2290Sstevel@tonic-gate 			} else if (c >= 'A' && c <= 'F') {
2300Sstevel@tonic-gate 				c = c - 'A' + 10;
2310Sstevel@tonic-gate 			} else if (c >= '0' && c <= '9') {
2320Sstevel@tonic-gate 				c -= '0';
2330Sstevel@tonic-gate 			} else {
2340Sstevel@tonic-gate 				return (-1);    /* invalid number */
2350Sstevel@tonic-gate 			}
2360Sstevel@tonic-gate 			retval = (retval << 4) + c;
2370Sstevel@tonic-gate 			break;
2380Sstevel@tonic-gate 		}
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 	if (onescompl)
2410Sstevel@tonic-gate 		retval = ~retval;
2420Sstevel@tonic-gate 	if (negate)
2430Sstevel@tonic-gate 		retval = -retval;
2440Sstevel@tonic-gate 	*valuep = retval;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	return (0);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate /*
2500Sstevel@tonic-gate  * returns the field from the token
2510Sstevel@tonic-gate  */
2520Sstevel@tonic-gate static config_field_t
usb_get_var_type(char * str)2530Sstevel@tonic-gate usb_get_var_type(char *str)
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate 	usbcfg_var_t    *cfgvar;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	cfgvar = &usbcfg_varlist[0];
2580Sstevel@tonic-gate 	while (cfgvar->field != USB_NONE) {
2590Sstevel@tonic-gate 		if (strcasecmp(cfgvar->name, str) == NULL) {
2600Sstevel@tonic-gate 			break;
2610Sstevel@tonic-gate 		} else {
2620Sstevel@tonic-gate 			cfgvar++;
2630Sstevel@tonic-gate 		}
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	return (cfgvar->field);
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate /* ARGSUSED */
2710Sstevel@tonic-gate static token_t
lex(char * buf,char * val,char ** errmsg)2720Sstevel@tonic-gate lex(char *buf, char *val, char **errmsg)
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate 	int	ch, oval, badquote;
2750Sstevel@tonic-gate 	char	*cp;
2760Sstevel@tonic-gate 	token_t token;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	cp = val;
2790Sstevel@tonic-gate 	while ((ch = GETC(buf, cntr)) == ' ' || ch == '\t');
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	/*
2820Sstevel@tonic-gate 	 * Note the beginning of a token
2830Sstevel@tonic-gate 	 */
2840Sstevel@tonic-gate 	btoken = cntr - 1;
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	*cp++ = (char)ch;
2870Sstevel@tonic-gate 	switch (ch) {
2880Sstevel@tonic-gate 	case '=':
2890Sstevel@tonic-gate 		token = EQUALS;
2900Sstevel@tonic-gate 		break;
2910Sstevel@tonic-gate 	case '&':
2920Sstevel@tonic-gate 		token = AMPERSAND;
2930Sstevel@tonic-gate 		break;
2940Sstevel@tonic-gate 	case '|':
2950Sstevel@tonic-gate 		token = BIT_OR;
2960Sstevel@tonic-gate 		break;
2970Sstevel@tonic-gate 	case '*':
2980Sstevel@tonic-gate 		token = STAR;
2990Sstevel@tonic-gate 		break;
3000Sstevel@tonic-gate 	case '#':
3010Sstevel@tonic-gate 		token = POUND;
3020Sstevel@tonic-gate 		break;
3030Sstevel@tonic-gate 	case ':':
3040Sstevel@tonic-gate 		token = COLON;
3050Sstevel@tonic-gate 		break;
3060Sstevel@tonic-gate 	case ';':
3070Sstevel@tonic-gate 		token = SEMICOLON;
3080Sstevel@tonic-gate 		break;
3090Sstevel@tonic-gate 	case ',':
3100Sstevel@tonic-gate 		token = COMMA;
3110Sstevel@tonic-gate 		break;
3120Sstevel@tonic-gate 	case '/':
3130Sstevel@tonic-gate 		token = SLASH;
3140Sstevel@tonic-gate 		break;
3150Sstevel@tonic-gate 	case ' ':
3160Sstevel@tonic-gate 	case '\t':
3170Sstevel@tonic-gate 	case '\f':
3180Sstevel@tonic-gate 		while ((ch  = GETC(buf, cntr)) == ' ' ||
3190Sstevel@tonic-gate 		    ch == '\t' || ch == '\f')
3200Sstevel@tonic-gate 			*cp++ = (char)ch;
3210Sstevel@tonic-gate 		(void) UNGETC(cntr);
3220Sstevel@tonic-gate 		token = WHITE_SPACE;
3230Sstevel@tonic-gate 		break;
3240Sstevel@tonic-gate 	case '\n':
3250Sstevel@tonic-gate 	case '\r':
3260Sstevel@tonic-gate 		token = NEWLINE;
3270Sstevel@tonic-gate 		break;
3280Sstevel@tonic-gate 	case '"':
3290Sstevel@tonic-gate 		cp--;
3300Sstevel@tonic-gate 		badquote = 0;
3310Sstevel@tonic-gate 		while (!badquote && (ch  = GETC(buf, cntr)) != '"') {
3320Sstevel@tonic-gate 			switch (ch) {
3330Sstevel@tonic-gate 			case '\n':
3340Sstevel@tonic-gate 			case -1:
3350Sstevel@tonic-gate 				(void) snprintf(*errmsg, MAXPATHLEN,
3360Sstevel@tonic-gate 				    "Missing \"");
3370Sstevel@tonic-gate 				cp = val;
3380Sstevel@tonic-gate 				*cp++ = '\n';
3390Sstevel@tonic-gate 				badquote = 1;
3400Sstevel@tonic-gate 				/* since we consumed the newline/EOF */
3410Sstevel@tonic-gate 				(void) UNGETC(cntr);
3420Sstevel@tonic-gate 				break;
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 			case '\\':
3450Sstevel@tonic-gate 				ch = (char)GETC(buf, cntr);
3460Sstevel@tonic-gate 				if (!isdigit(ch)) {
3470Sstevel@tonic-gate 					/* escape the character */
3480Sstevel@tonic-gate 					*cp++ = (char)ch;
3490Sstevel@tonic-gate 					break;
3500Sstevel@tonic-gate 				}
3510Sstevel@tonic-gate 				oval = 0;
3520Sstevel@tonic-gate 				while (ch >= '0' && ch <= '7') {
3530Sstevel@tonic-gate 					ch -= '0';
3540Sstevel@tonic-gate 					oval = (oval << 3) + ch;
3550Sstevel@tonic-gate 					ch = (char)GETC(buf, cntr);
3560Sstevel@tonic-gate 				}
3570Sstevel@tonic-gate 				(void) UNGETC(cntr);
3580Sstevel@tonic-gate 				/* check for character overflow? */
3590Sstevel@tonic-gate 				if (oval > 127) {
3600Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
3610Sstevel@tonic-gate 					    "Character overflow detected.\n");
3620Sstevel@tonic-gate 				}
3630Sstevel@tonic-gate 				*cp++ = (char)oval;
3640Sstevel@tonic-gate 				break;
3650Sstevel@tonic-gate 			default:
3660Sstevel@tonic-gate 				*cp++ = (char)ch;
3670Sstevel@tonic-gate 				break;
3680Sstevel@tonic-gate 			}
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 		token = STRING;
3710Sstevel@tonic-gate 		break;
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	default:
3740Sstevel@tonic-gate 		if (ch == -1) {
3750Sstevel@tonic-gate 			token = EOF;
3760Sstevel@tonic-gate 			break;
3770Sstevel@tonic-gate 		}
3780Sstevel@tonic-gate 		/*
3790Sstevel@tonic-gate 		 * detect a lone '-' (including at the end of a line), and
3800Sstevel@tonic-gate 		 * identify it as a 'name'
3810Sstevel@tonic-gate 		 */
3820Sstevel@tonic-gate 		if (ch == '-') {
3830Sstevel@tonic-gate 			*cp++ = (char)(ch = GETC(buf, cntr));
3840Sstevel@tonic-gate 			if (iswhite(ch) || (ch == '\n')) {
3850Sstevel@tonic-gate 				(void) UNGETC(cntr);
3860Sstevel@tonic-gate 				cp--;
3870Sstevel@tonic-gate 				token = NAME;
3880Sstevel@tonic-gate 				break;
3890Sstevel@tonic-gate 			}
3900Sstevel@tonic-gate 		} else if (isunary(ch)) {
3910Sstevel@tonic-gate 			*cp++ = (char)(ch = GETC(buf, cntr));
3920Sstevel@tonic-gate 		}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 		if (isdigit(ch)) {
3950Sstevel@tonic-gate 			if (ch == '0') {
3960Sstevel@tonic-gate 				if ((ch = GETC(buf, cntr)) == 'x') {
3970Sstevel@tonic-gate 					*cp++ = (char)ch;
3980Sstevel@tonic-gate 					ch = GETC(buf, cntr);
3990Sstevel@tonic-gate 					while (isxdigit(ch)) {
4000Sstevel@tonic-gate 						*cp++ = (char)ch;
4010Sstevel@tonic-gate 						ch = GETC(buf, cntr);
4020Sstevel@tonic-gate 					}
4030Sstevel@tonic-gate 					(void) UNGETC(cntr);
4040Sstevel@tonic-gate 					token = HEXVAL;
4050Sstevel@tonic-gate 				} else {
4060Sstevel@tonic-gate 					goto digit;
4070Sstevel@tonic-gate 				}
4080Sstevel@tonic-gate 			} else {
4090Sstevel@tonic-gate 				ch = GETC(buf, cntr);
4100Sstevel@tonic-gate digit:
4110Sstevel@tonic-gate 				while (isdigit(ch)) {
4120Sstevel@tonic-gate 					*cp++ = (char)ch;
4130Sstevel@tonic-gate 					ch = GETC(buf, cntr);
4140Sstevel@tonic-gate 				}
4150Sstevel@tonic-gate 				(void) UNGETC(cntr);
4160Sstevel@tonic-gate 				token = DECVAL;
4170Sstevel@tonic-gate 			}
4180Sstevel@tonic-gate 		} else if (isalpha(ch) || ch == '\\') {
4190Sstevel@tonic-gate 			if (ch != '\\') {
4200Sstevel@tonic-gate 				ch = GETC(buf, cntr);
4210Sstevel@tonic-gate 			} else {
4220Sstevel@tonic-gate 				/*
4230Sstevel@tonic-gate 				 * if the character was a backslash,
4240Sstevel@tonic-gate 				 * back up so we can overwrite it with
4250Sstevel@tonic-gate 				 * the next (i.e. escaped) character.
4260Sstevel@tonic-gate 				 */
4270Sstevel@tonic-gate 				cp--;
4280Sstevel@tonic-gate 			}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 			while (isnamechar(ch) || ch == '\\') {
4310Sstevel@tonic-gate 				if (ch == '\\')
4320Sstevel@tonic-gate 					ch = GETC(buf, cntr);
4330Sstevel@tonic-gate 				*cp++ = (char)ch;
4340Sstevel@tonic-gate 				ch = GETC(buf, cntr);
4350Sstevel@tonic-gate 			}
4360Sstevel@tonic-gate 			(void) UNGETC(cntr);
4370Sstevel@tonic-gate 			token = NAME;
4380Sstevel@tonic-gate 		} else {
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 			return (-1);
4410Sstevel@tonic-gate 		}
4420Sstevel@tonic-gate 		break;
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate 	*cp = '\0';
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	return (token);
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate  * Leave NEWLINE as the next character.
4520Sstevel@tonic-gate  */
4530Sstevel@tonic-gate static void
find_eol(char * buf)4540Sstevel@tonic-gate find_eol(char *buf)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	register int ch;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	while ((ch = GETC(buf, cntr)) != -1) {
4590Sstevel@tonic-gate 		if (isnewline(ch)) {
4600Sstevel@tonic-gate 			(void) UNGETC(cntr);
4610Sstevel@tonic-gate 			break;
4620Sstevel@tonic-gate 		}
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate /*
4680Sstevel@tonic-gate  * Fetch one record from the USBCONF_FILE
4690Sstevel@tonic-gate  */
4700Sstevel@tonic-gate static token_t
usb_get_conf_rec(char * buf,usb_configrec_t ** rec,char ** errmsg)4710Sstevel@tonic-gate usb_get_conf_rec(char *buf, usb_configrec_t **rec, char **errmsg)
4720Sstevel@tonic-gate {
4730Sstevel@tonic-gate 	token_t token;
4740Sstevel@tonic-gate 	char tokval[MAXLINESIZE];
4750Sstevel@tonic-gate 	usb_configrec_t *user_rec;
4760Sstevel@tonic-gate 	config_field_t  cfgvar;
4770Sstevel@tonic-gate 	u_longlong_t    llptr;
4780Sstevel@tonic-gate 	u_longlong_t    value;
4790Sstevel@tonic-gate 	boolean_t	sor = B_TRUE;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	enum {
4820Sstevel@tonic-gate 		USB_NEWVAR, USB_CONFIG_VAR, USB_VAR_EQUAL, USB_VAR_VALUE,
4830Sstevel@tonic-gate 		USB_ERROR
4840Sstevel@tonic-gate 	} parse_state = USB_NEWVAR;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	DPRINTF("usb_get_conf_rec:\n");
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	user_rec = (usb_configrec_t *)calloc(1, sizeof (usb_configrec_t));
4890Sstevel@tonic-gate 	if (user_rec == (usb_configrec_t *)NULL) {
4900Sstevel@tonic-gate 		return (0);
4910Sstevel@tonic-gate 	}
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	user_rec->idVendor = user_rec->idProduct = user_rec->cfgndx = -1;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	token = lex(buf, tokval, errmsg);
4960Sstevel@tonic-gate 	while ((token != EOF) && (token != SEMICOLON)) {
4970Sstevel@tonic-gate 		switch (token) {
4980Sstevel@tonic-gate 		case STAR:
4990Sstevel@tonic-gate 		case POUND:
5000Sstevel@tonic-gate 			/* skip comments */
5010Sstevel@tonic-gate 			find_eol(buf);
5020Sstevel@tonic-gate 			break;
5030Sstevel@tonic-gate 		case NEWLINE:
5040Sstevel@tonic-gate 			linenum++;
5050Sstevel@tonic-gate 			break;
5060Sstevel@tonic-gate 		case NAME:
5070Sstevel@tonic-gate 		case STRING:
5080Sstevel@tonic-gate 			switch (parse_state) {
5090Sstevel@tonic-gate 			case USB_NEWVAR:
5100Sstevel@tonic-gate 				cfgvar = usb_get_var_type(tokval);
5110Sstevel@tonic-gate 				if (cfgvar == USB_NONE) {
5120Sstevel@tonic-gate 					parse_state = USB_ERROR;
5130Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
5140Sstevel@tonic-gate 					    "Syntax Error: Invalid field %s",
5150Sstevel@tonic-gate 					    tokval);
5160Sstevel@tonic-gate 				} else {
5170Sstevel@tonic-gate 					/*
5180Sstevel@tonic-gate 					 * Note the beginning of a record
5190Sstevel@tonic-gate 					 */
5200Sstevel@tonic-gate 					if (sor) {
5210Sstevel@tonic-gate 						brec = btoken;
5220Sstevel@tonic-gate 						if (frec == 0) frec = brec;
5230Sstevel@tonic-gate 						sor = B_FALSE;
5240Sstevel@tonic-gate 					}
5250Sstevel@tonic-gate 					parse_state = USB_CONFIG_VAR;
5260Sstevel@tonic-gate 				}
5270Sstevel@tonic-gate 				break;
5280Sstevel@tonic-gate 			case USB_VAR_VALUE:
5290Sstevel@tonic-gate 				if ((cfgvar == USB_VENDOR) ||
5300Sstevel@tonic-gate 				    (cfgvar == USB_PRODUCT) ||
5310Sstevel@tonic-gate 				    (cfgvar == USB_CFGNDX)) {
5320Sstevel@tonic-gate 					parse_state = USB_ERROR;
5330Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
5340Sstevel@tonic-gate 					    "Syntax Error: Invalid value %s "
5350Sstevel@tonic-gate 					    "for field: %s\n", tokval,
5360Sstevel@tonic-gate 					    usbcfg_varlist[cfgvar].name);
5370Sstevel@tonic-gate 				} else if (get_string(&llptr, tokval)) {
5380Sstevel@tonic-gate 					switch (cfgvar) {
5390Sstevel@tonic-gate 					case USB_SELECTION:
5400Sstevel@tonic-gate 						user_rec->selection =
541399Svikram 						    (char *)(uintptr_t)llptr;
5420Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
5430Sstevel@tonic-gate 						break;
5440Sstevel@tonic-gate 					case USB_SRNO:
5450Sstevel@tonic-gate 						user_rec->serialno =
546399Svikram 						    (char *)(uintptr_t)llptr;
5470Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
5480Sstevel@tonic-gate 						break;
5490Sstevel@tonic-gate 					case USB_PATH:
5500Sstevel@tonic-gate 						user_rec->pathname =
551399Svikram 						    (char *)(uintptr_t)llptr;
5520Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
5530Sstevel@tonic-gate 						break;
5540Sstevel@tonic-gate 					case USB_DRIVER:
5550Sstevel@tonic-gate 						user_rec->driver =
556399Svikram 						    (char *)(uintptr_t)llptr;
5570Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
5580Sstevel@tonic-gate 						break;
5590Sstevel@tonic-gate 					default:
5600Sstevel@tonic-gate 						parse_state = USB_ERROR;
561*918Sqz150045 						free((void *)(uintptr_t)llptr);
5620Sstevel@tonic-gate 					}
5630Sstevel@tonic-gate 				} else {
5640Sstevel@tonic-gate 					parse_state = USB_ERROR;
5650Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
5660Sstevel@tonic-gate 					    "Syntax Error: Invalid value %s "
5670Sstevel@tonic-gate 					    "for field: %s\n", tokval,
5680Sstevel@tonic-gate 					    usbcfg_varlist[cfgvar].name);
5690Sstevel@tonic-gate 				}
5700Sstevel@tonic-gate 				break;
5710Sstevel@tonic-gate 			case USB_ERROR:
5720Sstevel@tonic-gate 				/* just skip */
5730Sstevel@tonic-gate 				break;
5740Sstevel@tonic-gate 			default:
5750Sstevel@tonic-gate 				parse_state = USB_ERROR;
5760Sstevel@tonic-gate 				(void) snprintf(*errmsg, MAXPATHLEN,
5770Sstevel@tonic-gate 				    "Syntax Error: at %s", tokval);
5780Sstevel@tonic-gate 				break;
5790Sstevel@tonic-gate 			}
5800Sstevel@tonic-gate 			break;
5810Sstevel@tonic-gate 		case EQUALS:
5820Sstevel@tonic-gate 			if (parse_state == USB_CONFIG_VAR) {
5830Sstevel@tonic-gate 				if (cfgvar == USB_NONE) {
5840Sstevel@tonic-gate 					parse_state = USB_ERROR;
5850Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
5860Sstevel@tonic-gate 					    "Syntax Error: unexpected '='");
5870Sstevel@tonic-gate 				} else {
5880Sstevel@tonic-gate 					parse_state = USB_VAR_VALUE;
5890Sstevel@tonic-gate 				}
5900Sstevel@tonic-gate 			} else if (parse_state != USB_ERROR) {
5910Sstevel@tonic-gate 				(void) snprintf(*errmsg, MAXPATHLEN,
5920Sstevel@tonic-gate 				    "Syntax Error: unexpected '='");
5930Sstevel@tonic-gate 				parse_state = USB_ERROR;
5940Sstevel@tonic-gate 			}
5950Sstevel@tonic-gate 			break;
5960Sstevel@tonic-gate 		case HEXVAL:
5970Sstevel@tonic-gate 		case DECVAL:
5980Sstevel@tonic-gate 			if ((parse_state == USB_VAR_VALUE) && (cfgvar !=
5990Sstevel@tonic-gate 			    USB_NONE)) {
6000Sstevel@tonic-gate 				(void) getvalue(tokval, &value);
6010Sstevel@tonic-gate 				switch (cfgvar) {
6020Sstevel@tonic-gate 				case USB_VENDOR:
6030Sstevel@tonic-gate 					user_rec->idVendor = (int)value;
6040Sstevel@tonic-gate 					parse_state = USB_NEWVAR;
6050Sstevel@tonic-gate 					break;
6060Sstevel@tonic-gate 				case USB_PRODUCT:
6070Sstevel@tonic-gate 					user_rec->idProduct = (int)value;
6080Sstevel@tonic-gate 					parse_state = USB_NEWVAR;
6090Sstevel@tonic-gate 					break;
6100Sstevel@tonic-gate 				case USB_CFGNDX:
6110Sstevel@tonic-gate 					user_rec->cfgndx = (int)value;
6120Sstevel@tonic-gate 					parse_state = USB_NEWVAR;
6130Sstevel@tonic-gate 					break;
6140Sstevel@tonic-gate 				default:
6150Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
6160Sstevel@tonic-gate 					    "Syntax Error: Invalid value for "
6170Sstevel@tonic-gate 					    "%s", usbcfg_varlist[cfgvar].name);
6180Sstevel@tonic-gate 				}
6190Sstevel@tonic-gate 			} else if (parse_state != USB_ERROR) {
6200Sstevel@tonic-gate 				parse_state = USB_ERROR;
6210Sstevel@tonic-gate 				(void) snprintf(*errmsg, MAXPATHLEN,
6220Sstevel@tonic-gate 				    "Syntax Error: unexpected hex/decimal: %s",
6230Sstevel@tonic-gate 				    tokval);
6240Sstevel@tonic-gate 			}
6250Sstevel@tonic-gate 			break;
6260Sstevel@tonic-gate 		default:
6270Sstevel@tonic-gate 			(void) snprintf(*errmsg, MAXPATHLEN,
6280Sstevel@tonic-gate 			    "Syntax Error: at: %s", tokval);
6290Sstevel@tonic-gate 			parse_state = USB_ERROR;
6300Sstevel@tonic-gate 			break;
6310Sstevel@tonic-gate 		}
6320Sstevel@tonic-gate 		token = lex(buf, tokval, errmsg);
6330Sstevel@tonic-gate 	}
6340Sstevel@tonic-gate 	*rec = user_rec;
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	return (token);
6370Sstevel@tonic-gate }
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate /*
6410Sstevel@tonic-gate  * Here we compare the two records and determine if they are the same
6420Sstevel@tonic-gate  */
6430Sstevel@tonic-gate static boolean_t
usb_cmp_rec(usb_configrec_t * cfg_rec,usb_configrec_t * user_rec)6440Sstevel@tonic-gate usb_cmp_rec(usb_configrec_t *cfg_rec, usb_configrec_t *user_rec)
6450Sstevel@tonic-gate {
6460Sstevel@tonic-gate 	char		*ustr, *cstr;
6470Sstevel@tonic-gate 	boolean_t	srno = B_FALSE, path = B_FALSE;
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	DPRINTF("usb_cmp_rec:\n");
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	if ((cfg_rec->idVendor == user_rec->idVendor) &&
6520Sstevel@tonic-gate 	    (cfg_rec->idProduct == user_rec->idProduct)) {
6530Sstevel@tonic-gate 		if (user_rec->serialno) {
6540Sstevel@tonic-gate 			if (cfg_rec->serialno) {
6550Sstevel@tonic-gate 				srno = (strcmp(cfg_rec->serialno,
6560Sstevel@tonic-gate 				    user_rec->serialno) == 0);
6570Sstevel@tonic-gate 			} else {
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 				return (B_FALSE);
6600Sstevel@tonic-gate 			}
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 		} else if (user_rec->pathname) {
6630Sstevel@tonic-gate 			if (cfg_rec->pathname) {
6640Sstevel@tonic-gate 				/*
6650Sstevel@tonic-gate 				 * Comparing on this is tricky. At this point
6660Sstevel@tonic-gate 				 * hubd knows: ../hubd@P/device@P while user
6670Sstevel@tonic-gate 				 * will specify ..../hubd@P/keyboard@P
6680Sstevel@tonic-gate 				 * First compare till .../hubd@P
6690Sstevel@tonic-gate 				 * Second compare is just P in "device@P"
6700Sstevel@tonic-gate 				 *
6710Sstevel@tonic-gate 				 * XXX: note that we assume P as one character
6720Sstevel@tonic-gate 				 * as there are no 2 digit hubs in the market.
6730Sstevel@tonic-gate 				 */
6740Sstevel@tonic-gate 				ustr = strrchr(user_rec->pathname, '/');
6750Sstevel@tonic-gate 				cstr = strrchr(cfg_rec->pathname, '/');
6760Sstevel@tonic-gate 				path = (strncmp(cfg_rec->pathname,
6770Sstevel@tonic-gate 				    user_rec->pathname,
6780Sstevel@tonic-gate 				    MAX(ustr - user_rec->pathname,
6790Sstevel@tonic-gate 				    cstr - cfg_rec->pathname)) == 0);
6800Sstevel@tonic-gate 				path = path && (*(user_rec->pathname +
6810Sstevel@tonic-gate 				    strlen(user_rec->pathname) -1) ==
6820Sstevel@tonic-gate 					*(cfg_rec->pathname +
6830Sstevel@tonic-gate 					strlen(cfg_rec->pathname) - 1));
6840Sstevel@tonic-gate 			} else {
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 				return (B_FALSE);
6870Sstevel@tonic-gate 			}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 		} else if (cfg_rec->serialno || cfg_rec->pathname) {
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 			return (B_FALSE);
6920Sstevel@tonic-gate 		} else {
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 			return (B_TRUE);
6950Sstevel@tonic-gate 		}
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 		return (srno || path);
6980Sstevel@tonic-gate 	} else {
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 		return (B_FALSE);
7010Sstevel@tonic-gate 	}
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate /*
7060Sstevel@tonic-gate  * free the record allocated in usb_get_conf_rec
7070Sstevel@tonic-gate  */
7080Sstevel@tonic-gate static void
usb_free_rec(usb_configrec_t * rec)7090Sstevel@tonic-gate usb_free_rec(usb_configrec_t *rec)
7100Sstevel@tonic-gate {
7110Sstevel@tonic-gate 	if (rec == (usb_configrec_t *)NULL) {
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 		return;
7140Sstevel@tonic-gate 	}
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	free(rec->selection);
7170Sstevel@tonic-gate 	free(rec->serialno);
7180Sstevel@tonic-gate 	free(rec->pathname);
7190Sstevel@tonic-gate 	free(rec->driver);
7200Sstevel@tonic-gate 	free(rec);
7210Sstevel@tonic-gate }
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate int
add_entry(char * selection,int vid,int pid,int cfgndx,char * srno,char * path,char * driver,char ** errmsg)7250Sstevel@tonic-gate add_entry(char *selection, int vid, int pid, int cfgndx, char *srno,
7260Sstevel@tonic-gate     char *path, char *driver, char **errmsg)
7270Sstevel@tonic-gate {
7280Sstevel@tonic-gate 	int		file;
7290Sstevel@tonic-gate 	int		rval = CFGA_USB_OK;
7300Sstevel@tonic-gate 	char		*buf = (char *)NULL;
7310Sstevel@tonic-gate 	char		str[MAXLINESIZE];
7320Sstevel@tonic-gate 	token_t		token = NEWLINE;
7330Sstevel@tonic-gate 	boolean_t	found = B_FALSE;
7340Sstevel@tonic-gate 	struct stat	st;
7350Sstevel@tonic-gate 	usb_configrec_t cfgrec, *user_rec = NULL;
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	DPRINTF("add_entry: driver=%s, path=%s\n",
7380Sstevel@tonic-gate 	    driver ? driver : "", path ? path : "");
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	if (*errmsg == (char *)NULL) {
7410Sstevel@tonic-gate 		if ((*errmsg = calloc(MAXPATHLEN, 1)) == (char *)NULL) {
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 			return (CFGA_USB_CONFIG_FILE);
7440Sstevel@tonic-gate 		}
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	(void) mutex_lock(&file_lock);
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	/* Initialize the cfgrec */
7500Sstevel@tonic-gate 	cfgrec.selection = selection;
7510Sstevel@tonic-gate 	cfgrec.idVendor = vid;
7520Sstevel@tonic-gate 	cfgrec.idProduct = pid;
7530Sstevel@tonic-gate 	cfgrec.cfgndx = cfgndx;
7540Sstevel@tonic-gate 	cfgrec.serialno = srno;
7550Sstevel@tonic-gate 	cfgrec.pathname = path;
7560Sstevel@tonic-gate 	cfgrec.driver = driver;
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	/* open config_map.conf file */
7590Sstevel@tonic-gate 	file = open(usbconf_file, O_RDWR, 0666);
7600Sstevel@tonic-gate 	if (file == -1) {
7610Sstevel@tonic-gate 		(void) snprintf(*errmsg, MAXPATHLEN,
7620Sstevel@tonic-gate 		    "failed to open config file\n");
7630Sstevel@tonic-gate 		(void) mutex_unlock(&file_lock);
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 		return (CFGA_USB_CONFIG_FILE);
7660Sstevel@tonic-gate 	}
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	if (lockf(file, F_TLOCK, 0) == -1) {
7690Sstevel@tonic-gate 		(void) snprintf(*errmsg, MAXPATHLEN,
7700Sstevel@tonic-gate 		    "failed to lock config file\n");
7710Sstevel@tonic-gate 		close(file);
7720Sstevel@tonic-gate 		(void) mutex_unlock(&file_lock);
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 		return (CFGA_USB_LOCK_FILE);
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	/*
7780Sstevel@tonic-gate 	 * These variables need to be reinitialized here as they may
7790Sstevel@tonic-gate 	 * have been modified by a previous thread that called this
7800Sstevel@tonic-gate 	 * function
7810Sstevel@tonic-gate 	 */
7820Sstevel@tonic-gate 	linenum = 1;
7830Sstevel@tonic-gate 	cntr = 0;
7840Sstevel@tonic-gate 	frec = 0;
7850Sstevel@tonic-gate 	brec = 0;
7860Sstevel@tonic-gate 	btoken = 0;
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	if (fstat(file, &st) != 0) {
7890Sstevel@tonic-gate 		DPRINTF("add_entry: failed to fstat config file\n");
7900Sstevel@tonic-gate 		rval = CFGA_USB_CONFIG_FILE;
7910Sstevel@tonic-gate 		goto exit;
7920Sstevel@tonic-gate 	}
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	if ((buf = (char *)malloc(st.st_size)) == NULL) {
7950Sstevel@tonic-gate 		DPRINTF("add_entry: failed to fstat config file\n");
7960Sstevel@tonic-gate 		rval = CFGA_USB_ALLOC_FAIL;
7970Sstevel@tonic-gate 		goto exit;
7980Sstevel@tonic-gate 	}
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	if (st.st_size != read(file, buf, st.st_size)) {
8010Sstevel@tonic-gate 		DPRINTF("add_entry: failed to read config file\n");
8020Sstevel@tonic-gate 		rval = CFGA_USB_CONFIG_FILE;
8030Sstevel@tonic-gate 		goto exit;
8040Sstevel@tonic-gate 	}
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	/* set up for reading the file */
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	while ((token != EOF) && !found) {
8090Sstevel@tonic-gate 		if (user_rec) {
8100Sstevel@tonic-gate 			usb_free_rec(user_rec);
8110Sstevel@tonic-gate 			user_rec = NULL;
8120Sstevel@tonic-gate 		}
8130Sstevel@tonic-gate 		token = usb_get_conf_rec(buf, &user_rec, errmsg);
8140Sstevel@tonic-gate 		found = usb_cmp_rec(&cfgrec, user_rec);
8150Sstevel@tonic-gate 		DPRINTF("add_entry: token=%x, found=%x\n", token, found);
8160Sstevel@tonic-gate 	}
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	bzero(str, MAXLINESIZE);
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	if (found) {
8210Sstevel@tonic-gate 		DPRINTF("FOUND\n");
8220Sstevel@tonic-gate 		(void) snprintf(str, MAXLINESIZE, "selection=%s idVendor=0x%x "
8230Sstevel@tonic-gate 		    "idProduct=0x%x ",
8240Sstevel@tonic-gate 		    (cfgrec.selection) ? cfgrec.selection : user_rec->selection,
8250Sstevel@tonic-gate 		    user_rec->idVendor, user_rec->idProduct);
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 		if ((user_rec->cfgndx != -1) || (cfgrec.cfgndx != -1)) {
8280Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)], MAXLINESIZE,
8290Sstevel@tonic-gate 			    "cfgndx=0x%x ", (cfgrec.cfgndx != -1) ?
8300Sstevel@tonic-gate 			    cfgrec.cfgndx : user_rec->cfgndx);
8310Sstevel@tonic-gate 		}
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 		if (user_rec->serialno) {
8340Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)],  MAXLINESIZE,
8350Sstevel@tonic-gate 			    "srno=\"%s\" ", user_rec->serialno);
8360Sstevel@tonic-gate 		}
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 		if (user_rec->pathname) {
8390Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)],  MAXLINESIZE,
8400Sstevel@tonic-gate 			    "pathname=\"%s\" ", user_rec->pathname);
8410Sstevel@tonic-gate 		}
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 		if (user_rec->driver) {
8440Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)],  MAXLINESIZE,
8450Sstevel@tonic-gate 			    "driver=\"%s\" ", user_rec->driver);
8460Sstevel@tonic-gate 		} else if (cfgrec.driver != NULL) {
8470Sstevel@tonic-gate 			if (strlen(cfgrec.driver)) {
8480Sstevel@tonic-gate 				(void) snprintf(&str[strlen(str)],  MAXLINESIZE,
8490Sstevel@tonic-gate 				    "driver=\"%s\" ", cfgrec.driver);
8500Sstevel@tonic-gate 			}
8510Sstevel@tonic-gate 		}
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 		(void) strlcat(str, ";", sizeof (str));
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 		/*
8560Sstevel@tonic-gate 		 * Seek to the beginning of the record
8570Sstevel@tonic-gate 		 */
8580Sstevel@tonic-gate 		if (lseek(file, brec, SEEK_SET) == -1) {
8590Sstevel@tonic-gate 			DPRINTF("add_entry: failed to lseek config file\n");
8600Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
8610Sstevel@tonic-gate 			goto exit;
8620Sstevel@tonic-gate 		}
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 		/*
8650Sstevel@tonic-gate 		 * Write the modified record
8660Sstevel@tonic-gate 		 */
8670Sstevel@tonic-gate 		if (write(file, str, strlen(str)) == -1) {
8680Sstevel@tonic-gate 			DPRINTF("add_entry: failed to write config file\n");
8690Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
8700Sstevel@tonic-gate 			goto exit;
8710Sstevel@tonic-gate 		}
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 		/*
8740Sstevel@tonic-gate 		 * Write the rest of the file as it was
8750Sstevel@tonic-gate 		 */
8760Sstevel@tonic-gate 		if (write(file, buf+cntr, st.st_size - cntr) == -1) {
8770Sstevel@tonic-gate 			DPRINTF("add_entry: failed to write config file\n");
8780Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
8790Sstevel@tonic-gate 			goto exit;
8800Sstevel@tonic-gate 		}
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	} else {
8830Sstevel@tonic-gate 		DPRINTF("!FOUND\n");
8840Sstevel@tonic-gate 		(void) snprintf(str, MAXLINESIZE,
8850Sstevel@tonic-gate 		    "selection=%s idVendor=0x%x idProduct=0x%x ",
8860Sstevel@tonic-gate 		    (cfgrec.selection) ? cfgrec.selection : "enable",
8870Sstevel@tonic-gate 		    cfgrec.idVendor, cfgrec.idProduct);
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 		if (cfgrec.cfgndx != -1) {
8900Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)], MAXLINESIZE,
8910Sstevel@tonic-gate 			    "cfgndx=0x%x ", cfgrec.cfgndx);
8920Sstevel@tonic-gate 		}
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 		if (cfgrec.serialno) {
8950Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)], MAXLINESIZE,
8960Sstevel@tonic-gate 			    "srno=\"%s\" ", cfgrec.serialno);
8970Sstevel@tonic-gate 		}
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 		if (cfgrec.pathname != NULL) {
9000Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)], MAXLINESIZE,
9010Sstevel@tonic-gate 			    "pathname=\"%s\" ", cfgrec.pathname);
9020Sstevel@tonic-gate 		}
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 		if (cfgrec.driver != NULL) {
9050Sstevel@tonic-gate 			if (strlen(cfgrec.driver)) {
9060Sstevel@tonic-gate 				(void) snprintf(&str[strlen(str)], MAXLINESIZE,
9070Sstevel@tonic-gate 				    "driver=\"%s\" ", cfgrec.driver);
9080Sstevel@tonic-gate 			}
9090Sstevel@tonic-gate 		}
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 		(void) strlcat(str, ";\n", sizeof (str));
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 		/*
9140Sstevel@tonic-gate 		 * Incase this is the first entry, add it after the comments
9150Sstevel@tonic-gate 		 */
9160Sstevel@tonic-gate 		if (frec == 0) {
9170Sstevel@tonic-gate 			frec = st.st_size;
9180Sstevel@tonic-gate 		}
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 		/*
9210Sstevel@tonic-gate 		 * Go to the beginning of the records
9220Sstevel@tonic-gate 		 */
9230Sstevel@tonic-gate 		if (lseek(file, frec, SEEK_SET) == -1) {
9240Sstevel@tonic-gate 			DPRINTF("add_entry: failed to lseek config file\n");
9250Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
9260Sstevel@tonic-gate 			goto exit;
9270Sstevel@tonic-gate 		}
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 		/*
9300Sstevel@tonic-gate 		 * Add the entry
9310Sstevel@tonic-gate 		 */
9320Sstevel@tonic-gate 		if (write(file, str, strlen(str)) == -1) {
9330Sstevel@tonic-gate 			DPRINTF("add_entry: failed to write config file\n");
9340Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
9350Sstevel@tonic-gate 			goto exit;
9360Sstevel@tonic-gate 		}
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 		/*
9390Sstevel@tonic-gate 		 * write the remaining file as it was
9400Sstevel@tonic-gate 		 */
9410Sstevel@tonic-gate 		if (write(file, buf+frec, st.st_size - frec) == -1) {
9420Sstevel@tonic-gate 			DPRINTF("add_entry: failed to write config file\n");
9430Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
9440Sstevel@tonic-gate 			goto exit;
9450Sstevel@tonic-gate 		}
9460Sstevel@tonic-gate 	}
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	/* no error encountered */
9490Sstevel@tonic-gate 	if (rval == CFGA_USB_OK) {
9500Sstevel@tonic-gate 		free(errmsg);
9510Sstevel@tonic-gate 	}
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate exit:
9540Sstevel@tonic-gate 	if (buf != NULL) {
9550Sstevel@tonic-gate 		free(buf);
9560Sstevel@tonic-gate 	}
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	if (lockf(file, F_ULOCK, 0) == -1) {
9590Sstevel@tonic-gate 		DPRINTF("add_entry: failed to unlock config file\n");
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 		rval = CFGA_USB_LOCK_FILE;
9620Sstevel@tonic-gate 	}
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	close(file);
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	(void) mutex_unlock(&file_lock);
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	return (rval);
9690Sstevel@tonic-gate }
970