1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include "cfga_usb.h"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #define	MAXLINESIZE	512
33*7c478bd9Sstevel@tonic-gate #define	FE_BUFLEN 256
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #define	isunary(ch)	((ch) == '~' || (ch) == '-')
36*7c478bd9Sstevel@tonic-gate #define	iswhite(ch)	((ch) == ' ' || (ch) == '\t')
37*7c478bd9Sstevel@tonic-gate #define	isnewline(ch)	((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
38*7c478bd9Sstevel@tonic-gate #define	isalphanum(ch)	(isalpha(ch) || isdigit(ch))
39*7c478bd9Sstevel@tonic-gate #define	isnamechar(ch)	(isalphanum(ch) || (ch) == '_' || (ch) == '-')
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #define	MAX(a, b)	((a) < (b) ? (b) : (a))
42*7c478bd9Sstevel@tonic-gate #define	GETC(a, cntr)	a[cntr++]
43*7c478bd9Sstevel@tonic-gate #define	UNGETC(cntr)	cntr--
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate typedef struct usb_configrec {
47*7c478bd9Sstevel@tonic-gate 	char    *selection;
48*7c478bd9Sstevel@tonic-gate 	int	idVendor, idProduct, cfgndx;
49*7c478bd9Sstevel@tonic-gate 	char    *serialno;
50*7c478bd9Sstevel@tonic-gate 	char    *pathname;
51*7c478bd9Sstevel@tonic-gate 	char    *driver;
52*7c478bd9Sstevel@tonic-gate } usb_configrec_t;
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate typedef enum {
55*7c478bd9Sstevel@tonic-gate 	USB_SELECTION, USB_VENDOR, USB_PRODUCT, USB_CFGNDX, USB_SRNO,
56*7c478bd9Sstevel@tonic-gate 	USB_PATH, USB_DRIVER, USB_NONE
57*7c478bd9Sstevel@tonic-gate } config_field_t;
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate typedef struct usbcfg_var {
60*7c478bd9Sstevel@tonic-gate 	const char *name;
61*7c478bd9Sstevel@tonic-gate 	config_field_t field;
62*7c478bd9Sstevel@tonic-gate } usbcfg_var_t;
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate static usbcfg_var_t usbcfg_varlist[] = {
65*7c478bd9Sstevel@tonic-gate 	{ "selection",	USB_SELECTION },
66*7c478bd9Sstevel@tonic-gate 	{ "idVendor",	USB_VENDOR },
67*7c478bd9Sstevel@tonic-gate 	{ "idProduct",	USB_PRODUCT },
68*7c478bd9Sstevel@tonic-gate 	{ "cfgndx",	USB_CFGNDX },
69*7c478bd9Sstevel@tonic-gate 	{ "srno",	USB_SRNO },
70*7c478bd9Sstevel@tonic-gate 	{ "pathname",	USB_PATH },
71*7c478bd9Sstevel@tonic-gate 	{ "driver",	USB_DRIVER },
72*7c478bd9Sstevel@tonic-gate 	{ NULL,		USB_NONE }
73*7c478bd9Sstevel@tonic-gate };
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate typedef enum {
76*7c478bd9Sstevel@tonic-gate 	EQUALS,
77*7c478bd9Sstevel@tonic-gate 	AMPERSAND,
78*7c478bd9Sstevel@tonic-gate 	BIT_OR,
79*7c478bd9Sstevel@tonic-gate 	STAR,
80*7c478bd9Sstevel@tonic-gate 	POUND,
81*7c478bd9Sstevel@tonic-gate 	COLON,
82*7c478bd9Sstevel@tonic-gate 	SEMICOLON,
83*7c478bd9Sstevel@tonic-gate 	COMMA,
84*7c478bd9Sstevel@tonic-gate 	SLASH,
85*7c478bd9Sstevel@tonic-gate 	WHITE_SPACE,
86*7c478bd9Sstevel@tonic-gate 	NEWLINE,
87*7c478bd9Sstevel@tonic-gate 	E_O_F,
88*7c478bd9Sstevel@tonic-gate 	STRING,
89*7c478bd9Sstevel@tonic-gate 	HEXVAL,
90*7c478bd9Sstevel@tonic-gate 	DECVAL,
91*7c478bd9Sstevel@tonic-gate 	NAME
92*7c478bd9Sstevel@tonic-gate } token_t;
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate static char	usbconf_file[] = USBCONF_FILE;
96*7c478bd9Sstevel@tonic-gate static int	linenum = 1;
97*7c478bd9Sstevel@tonic-gate static int	cntr = 0;
98*7c478bd9Sstevel@tonic-gate static int	frec = 0;
99*7c478bd9Sstevel@tonic-gate static int	brec = 0;
100*7c478bd9Sstevel@tonic-gate static int	btoken = 0;
101*7c478bd9Sstevel@tonic-gate mutex_t		file_lock = DEFAULTMUTEX;
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate /*
105*7c478bd9Sstevel@tonic-gate  * prototypes
106*7c478bd9Sstevel@tonic-gate  */
107*7c478bd9Sstevel@tonic-gate static int	get_string(u_longlong_t *llptr, char *tchar);
108*7c478bd9Sstevel@tonic-gate static int	getvalue(char *token, u_longlong_t *valuep);
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate /*
112*7c478bd9Sstevel@tonic-gate  * The next item on the line is a string value. Allocate memory for
113*7c478bd9Sstevel@tonic-gate  * it and copy the string. Return 1, and set arg ptr to newly allocated
114*7c478bd9Sstevel@tonic-gate  * and initialized buffer, or NULL if an error occurs.
115*7c478bd9Sstevel@tonic-gate  */
116*7c478bd9Sstevel@tonic-gate static int
117*7c478bd9Sstevel@tonic-gate get_string(u_longlong_t *llptr, char *tchar)
118*7c478bd9Sstevel@tonic-gate {
119*7c478bd9Sstevel@tonic-gate 	register char *cp;
120*7c478bd9Sstevel@tonic-gate 	register char *start = (char *)0;
121*7c478bd9Sstevel@tonic-gate 	register int len = 0;
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	len = strlen(tchar);
124*7c478bd9Sstevel@tonic-gate 	start = tchar;
125*7c478bd9Sstevel@tonic-gate 	/* copy string */
126*7c478bd9Sstevel@tonic-gate 	cp = (char *)calloc(len + 1, sizeof (char));
127*7c478bd9Sstevel@tonic-gate 	if (cp == (char *)NULL) {
128*7c478bd9Sstevel@tonic-gate 		*llptr = NULL;
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 		return (0);
131*7c478bd9Sstevel@tonic-gate 	}
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	*llptr = (u_longlong_t)(uintptr_t)cp;
134*7c478bd9Sstevel@tonic-gate 	for (; len > 0; len--) {
135*7c478bd9Sstevel@tonic-gate 		/* convert some common escape sequences */
136*7c478bd9Sstevel@tonic-gate 		if (*start == '\\') {
137*7c478bd9Sstevel@tonic-gate 			switch (*(start + 1)) {
138*7c478bd9Sstevel@tonic-gate 			case 't':
139*7c478bd9Sstevel@tonic-gate 				/* tab */
140*7c478bd9Sstevel@tonic-gate 				*cp++ = '\t';
141*7c478bd9Sstevel@tonic-gate 				len--;
142*7c478bd9Sstevel@tonic-gate 				start += 2;
143*7c478bd9Sstevel@tonic-gate 				break;
144*7c478bd9Sstevel@tonic-gate 			case 'n':
145*7c478bd9Sstevel@tonic-gate 				/* new line */
146*7c478bd9Sstevel@tonic-gate 				*cp++ = '\n';
147*7c478bd9Sstevel@tonic-gate 				len--;
148*7c478bd9Sstevel@tonic-gate 				start += 2;
149*7c478bd9Sstevel@tonic-gate 				break;
150*7c478bd9Sstevel@tonic-gate 			case 'b':
151*7c478bd9Sstevel@tonic-gate 				/* back space */
152*7c478bd9Sstevel@tonic-gate 				*cp++ = '\b';
153*7c478bd9Sstevel@tonic-gate 				len--;
154*7c478bd9Sstevel@tonic-gate 				start += 2;
155*7c478bd9Sstevel@tonic-gate 				break;
156*7c478bd9Sstevel@tonic-gate 			default:
157*7c478bd9Sstevel@tonic-gate 				/* simply copy it */
158*7c478bd9Sstevel@tonic-gate 				*cp++ = *start++;
159*7c478bd9Sstevel@tonic-gate 				break;
160*7c478bd9Sstevel@tonic-gate 			}
161*7c478bd9Sstevel@tonic-gate 		} else {
162*7c478bd9Sstevel@tonic-gate 			*cp++ = *start++;
163*7c478bd9Sstevel@tonic-gate 		}
164*7c478bd9Sstevel@tonic-gate 	}
165*7c478bd9Sstevel@tonic-gate 	*cp = '\0';
166*7c478bd9Sstevel@tonic-gate 	return (1);
167*7c478bd9Sstevel@tonic-gate }
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate /*
171*7c478bd9Sstevel@tonic-gate  * get a decimal octal or hex number. Handle '~' for one's complement.
172*7c478bd9Sstevel@tonic-gate  */
173*7c478bd9Sstevel@tonic-gate static int
174*7c478bd9Sstevel@tonic-gate getvalue(char *token, u_longlong_t *valuep)
175*7c478bd9Sstevel@tonic-gate {
176*7c478bd9Sstevel@tonic-gate 	register int radix;
177*7c478bd9Sstevel@tonic-gate 	register u_longlong_t retval = 0;
178*7c478bd9Sstevel@tonic-gate 	register int onescompl = 0;
179*7c478bd9Sstevel@tonic-gate 	register int negate = 0;
180*7c478bd9Sstevel@tonic-gate 	register char c;
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	if (*token == '~') {
183*7c478bd9Sstevel@tonic-gate 		onescompl++; /* perform one's complement on result */
184*7c478bd9Sstevel@tonic-gate 		token++;
185*7c478bd9Sstevel@tonic-gate 	} else if (*token == '-') {
186*7c478bd9Sstevel@tonic-gate 		negate++;
187*7c478bd9Sstevel@tonic-gate 		token++;
188*7c478bd9Sstevel@tonic-gate 	}
189*7c478bd9Sstevel@tonic-gate 	if (*token == '0') {
190*7c478bd9Sstevel@tonic-gate 		token++;
191*7c478bd9Sstevel@tonic-gate 		c = *token;
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 		if (c == '\0') {
194*7c478bd9Sstevel@tonic-gate 			*valuep = 0;    /* value is 0 */
195*7c478bd9Sstevel@tonic-gate 			return (0);
196*7c478bd9Sstevel@tonic-gate 		}
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 		if (c == 'x' || c == 'X') {
199*7c478bd9Sstevel@tonic-gate 			radix = 16;
200*7c478bd9Sstevel@tonic-gate 			token++;
201*7c478bd9Sstevel@tonic-gate 		} else {
202*7c478bd9Sstevel@tonic-gate 			radix = 8;
203*7c478bd9Sstevel@tonic-gate 		}
204*7c478bd9Sstevel@tonic-gate 	} else {
205*7c478bd9Sstevel@tonic-gate 		radix = 10;
206*7c478bd9Sstevel@tonic-gate 	}
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	while ((c = *token++)) {
209*7c478bd9Sstevel@tonic-gate 		switch (radix) {
210*7c478bd9Sstevel@tonic-gate 		case 8:
211*7c478bd9Sstevel@tonic-gate 			if (c >= '0' && c <= '7') {
212*7c478bd9Sstevel@tonic-gate 				c -= '0';
213*7c478bd9Sstevel@tonic-gate 			} else {
214*7c478bd9Sstevel@tonic-gate 				return (-1);    /* invalid number */
215*7c478bd9Sstevel@tonic-gate 			}
216*7c478bd9Sstevel@tonic-gate 			retval = (retval << 3) + c;
217*7c478bd9Sstevel@tonic-gate 			break;
218*7c478bd9Sstevel@tonic-gate 		case 10:
219*7c478bd9Sstevel@tonic-gate 			if (c >= '0' && c <= '9') {
220*7c478bd9Sstevel@tonic-gate 				c -= '0';
221*7c478bd9Sstevel@tonic-gate 			} else {
222*7c478bd9Sstevel@tonic-gate 				return (-1);    /* invalid number */
223*7c478bd9Sstevel@tonic-gate 			}
224*7c478bd9Sstevel@tonic-gate 			retval = (retval * 10) + c;
225*7c478bd9Sstevel@tonic-gate 			break;
226*7c478bd9Sstevel@tonic-gate 		case 16:
227*7c478bd9Sstevel@tonic-gate 			if (c >= 'a' && c <= 'f') {
228*7c478bd9Sstevel@tonic-gate 				c = c - 'a' + 10;
229*7c478bd9Sstevel@tonic-gate 			} else if (c >= 'A' && c <= 'F') {
230*7c478bd9Sstevel@tonic-gate 				c = c - 'A' + 10;
231*7c478bd9Sstevel@tonic-gate 			} else if (c >= '0' && c <= '9') {
232*7c478bd9Sstevel@tonic-gate 				c -= '0';
233*7c478bd9Sstevel@tonic-gate 			} else {
234*7c478bd9Sstevel@tonic-gate 				return (-1);    /* invalid number */
235*7c478bd9Sstevel@tonic-gate 			}
236*7c478bd9Sstevel@tonic-gate 			retval = (retval << 4) + c;
237*7c478bd9Sstevel@tonic-gate 			break;
238*7c478bd9Sstevel@tonic-gate 		}
239*7c478bd9Sstevel@tonic-gate 	}
240*7c478bd9Sstevel@tonic-gate 	if (onescompl)
241*7c478bd9Sstevel@tonic-gate 		retval = ~retval;
242*7c478bd9Sstevel@tonic-gate 	if (negate)
243*7c478bd9Sstevel@tonic-gate 		retval = -retval;
244*7c478bd9Sstevel@tonic-gate 	*valuep = retval;
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	return (0);
247*7c478bd9Sstevel@tonic-gate }
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate /*
250*7c478bd9Sstevel@tonic-gate  * returns the field from the token
251*7c478bd9Sstevel@tonic-gate  */
252*7c478bd9Sstevel@tonic-gate static config_field_t
253*7c478bd9Sstevel@tonic-gate usb_get_var_type(char *str)
254*7c478bd9Sstevel@tonic-gate {
255*7c478bd9Sstevel@tonic-gate 	usbcfg_var_t    *cfgvar;
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	cfgvar = &usbcfg_varlist[0];
258*7c478bd9Sstevel@tonic-gate 	while (cfgvar->field != USB_NONE) {
259*7c478bd9Sstevel@tonic-gate 		if (strcasecmp(cfgvar->name, str) == NULL) {
260*7c478bd9Sstevel@tonic-gate 			break;
261*7c478bd9Sstevel@tonic-gate 		} else {
262*7c478bd9Sstevel@tonic-gate 			cfgvar++;
263*7c478bd9Sstevel@tonic-gate 		}
264*7c478bd9Sstevel@tonic-gate 	}
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	return (cfgvar->field);
267*7c478bd9Sstevel@tonic-gate }
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
271*7c478bd9Sstevel@tonic-gate static token_t
272*7c478bd9Sstevel@tonic-gate lex(char *buf, char *val, char **errmsg)
273*7c478bd9Sstevel@tonic-gate {
274*7c478bd9Sstevel@tonic-gate 	int	ch, oval, badquote;
275*7c478bd9Sstevel@tonic-gate 	char	*cp;
276*7c478bd9Sstevel@tonic-gate 	token_t token;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	cp = val;
279*7c478bd9Sstevel@tonic-gate 	while ((ch = GETC(buf, cntr)) == ' ' || ch == '\t');
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	/*
282*7c478bd9Sstevel@tonic-gate 	 * Note the beginning of a token
283*7c478bd9Sstevel@tonic-gate 	 */
284*7c478bd9Sstevel@tonic-gate 	btoken = cntr - 1;
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	*cp++ = (char)ch;
287*7c478bd9Sstevel@tonic-gate 	switch (ch) {
288*7c478bd9Sstevel@tonic-gate 	case '=':
289*7c478bd9Sstevel@tonic-gate 		token = EQUALS;
290*7c478bd9Sstevel@tonic-gate 		break;
291*7c478bd9Sstevel@tonic-gate 	case '&':
292*7c478bd9Sstevel@tonic-gate 		token = AMPERSAND;
293*7c478bd9Sstevel@tonic-gate 		break;
294*7c478bd9Sstevel@tonic-gate 	case '|':
295*7c478bd9Sstevel@tonic-gate 		token = BIT_OR;
296*7c478bd9Sstevel@tonic-gate 		break;
297*7c478bd9Sstevel@tonic-gate 	case '*':
298*7c478bd9Sstevel@tonic-gate 		token = STAR;
299*7c478bd9Sstevel@tonic-gate 		break;
300*7c478bd9Sstevel@tonic-gate 	case '#':
301*7c478bd9Sstevel@tonic-gate 		token = POUND;
302*7c478bd9Sstevel@tonic-gate 		break;
303*7c478bd9Sstevel@tonic-gate 	case ':':
304*7c478bd9Sstevel@tonic-gate 		token = COLON;
305*7c478bd9Sstevel@tonic-gate 		break;
306*7c478bd9Sstevel@tonic-gate 	case ';':
307*7c478bd9Sstevel@tonic-gate 		token = SEMICOLON;
308*7c478bd9Sstevel@tonic-gate 		break;
309*7c478bd9Sstevel@tonic-gate 	case ',':
310*7c478bd9Sstevel@tonic-gate 		token = COMMA;
311*7c478bd9Sstevel@tonic-gate 		break;
312*7c478bd9Sstevel@tonic-gate 	case '/':
313*7c478bd9Sstevel@tonic-gate 		token = SLASH;
314*7c478bd9Sstevel@tonic-gate 		break;
315*7c478bd9Sstevel@tonic-gate 	case ' ':
316*7c478bd9Sstevel@tonic-gate 	case '\t':
317*7c478bd9Sstevel@tonic-gate 	case '\f':
318*7c478bd9Sstevel@tonic-gate 		while ((ch  = GETC(buf, cntr)) == ' ' ||
319*7c478bd9Sstevel@tonic-gate 		    ch == '\t' || ch == '\f')
320*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)ch;
321*7c478bd9Sstevel@tonic-gate 		(void) UNGETC(cntr);
322*7c478bd9Sstevel@tonic-gate 		token = WHITE_SPACE;
323*7c478bd9Sstevel@tonic-gate 		break;
324*7c478bd9Sstevel@tonic-gate 	case '\n':
325*7c478bd9Sstevel@tonic-gate 	case '\r':
326*7c478bd9Sstevel@tonic-gate 		token = NEWLINE;
327*7c478bd9Sstevel@tonic-gate 		break;
328*7c478bd9Sstevel@tonic-gate 	case '"':
329*7c478bd9Sstevel@tonic-gate 		cp--;
330*7c478bd9Sstevel@tonic-gate 		badquote = 0;
331*7c478bd9Sstevel@tonic-gate 		while (!badquote && (ch  = GETC(buf, cntr)) != '"') {
332*7c478bd9Sstevel@tonic-gate 			switch (ch) {
333*7c478bd9Sstevel@tonic-gate 			case '\n':
334*7c478bd9Sstevel@tonic-gate 			case -1:
335*7c478bd9Sstevel@tonic-gate 				(void) snprintf(*errmsg, MAXPATHLEN,
336*7c478bd9Sstevel@tonic-gate 				    "Missing \"");
337*7c478bd9Sstevel@tonic-gate 				cp = val;
338*7c478bd9Sstevel@tonic-gate 				*cp++ = '\n';
339*7c478bd9Sstevel@tonic-gate 				badquote = 1;
340*7c478bd9Sstevel@tonic-gate 				/* since we consumed the newline/EOF */
341*7c478bd9Sstevel@tonic-gate 				(void) UNGETC(cntr);
342*7c478bd9Sstevel@tonic-gate 				break;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 			case '\\':
345*7c478bd9Sstevel@tonic-gate 				ch = (char)GETC(buf, cntr);
346*7c478bd9Sstevel@tonic-gate 				if (!isdigit(ch)) {
347*7c478bd9Sstevel@tonic-gate 					/* escape the character */
348*7c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
349*7c478bd9Sstevel@tonic-gate 					break;
350*7c478bd9Sstevel@tonic-gate 				}
351*7c478bd9Sstevel@tonic-gate 				oval = 0;
352*7c478bd9Sstevel@tonic-gate 				while (ch >= '0' && ch <= '7') {
353*7c478bd9Sstevel@tonic-gate 					ch -= '0';
354*7c478bd9Sstevel@tonic-gate 					oval = (oval << 3) + ch;
355*7c478bd9Sstevel@tonic-gate 					ch = (char)GETC(buf, cntr);
356*7c478bd9Sstevel@tonic-gate 				}
357*7c478bd9Sstevel@tonic-gate 				(void) UNGETC(cntr);
358*7c478bd9Sstevel@tonic-gate 				/* check for character overflow? */
359*7c478bd9Sstevel@tonic-gate 				if (oval > 127) {
360*7c478bd9Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
361*7c478bd9Sstevel@tonic-gate 					    "Character overflow detected.\n");
362*7c478bd9Sstevel@tonic-gate 				}
363*7c478bd9Sstevel@tonic-gate 				*cp++ = (char)oval;
364*7c478bd9Sstevel@tonic-gate 				break;
365*7c478bd9Sstevel@tonic-gate 			default:
366*7c478bd9Sstevel@tonic-gate 				*cp++ = (char)ch;
367*7c478bd9Sstevel@tonic-gate 				break;
368*7c478bd9Sstevel@tonic-gate 			}
369*7c478bd9Sstevel@tonic-gate 		}
370*7c478bd9Sstevel@tonic-gate 		token = STRING;
371*7c478bd9Sstevel@tonic-gate 		break;
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	default:
374*7c478bd9Sstevel@tonic-gate 		if (ch == -1) {
375*7c478bd9Sstevel@tonic-gate 			token = EOF;
376*7c478bd9Sstevel@tonic-gate 			break;
377*7c478bd9Sstevel@tonic-gate 		}
378*7c478bd9Sstevel@tonic-gate 		/*
379*7c478bd9Sstevel@tonic-gate 		 * detect a lone '-' (including at the end of a line), and
380*7c478bd9Sstevel@tonic-gate 		 * identify it as a 'name'
381*7c478bd9Sstevel@tonic-gate 		 */
382*7c478bd9Sstevel@tonic-gate 		if (ch == '-') {
383*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)(ch = GETC(buf, cntr));
384*7c478bd9Sstevel@tonic-gate 			if (iswhite(ch) || (ch == '\n')) {
385*7c478bd9Sstevel@tonic-gate 				(void) UNGETC(cntr);
386*7c478bd9Sstevel@tonic-gate 				cp--;
387*7c478bd9Sstevel@tonic-gate 				token = NAME;
388*7c478bd9Sstevel@tonic-gate 				break;
389*7c478bd9Sstevel@tonic-gate 			}
390*7c478bd9Sstevel@tonic-gate 		} else if (isunary(ch)) {
391*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)(ch = GETC(buf, cntr));
392*7c478bd9Sstevel@tonic-gate 		}
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 		if (isdigit(ch)) {
395*7c478bd9Sstevel@tonic-gate 			if (ch == '0') {
396*7c478bd9Sstevel@tonic-gate 				if ((ch = GETC(buf, cntr)) == 'x') {
397*7c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
398*7c478bd9Sstevel@tonic-gate 					ch = GETC(buf, cntr);
399*7c478bd9Sstevel@tonic-gate 					while (isxdigit(ch)) {
400*7c478bd9Sstevel@tonic-gate 						*cp++ = (char)ch;
401*7c478bd9Sstevel@tonic-gate 						ch = GETC(buf, cntr);
402*7c478bd9Sstevel@tonic-gate 					}
403*7c478bd9Sstevel@tonic-gate 					(void) UNGETC(cntr);
404*7c478bd9Sstevel@tonic-gate 					token = HEXVAL;
405*7c478bd9Sstevel@tonic-gate 				} else {
406*7c478bd9Sstevel@tonic-gate 					goto digit;
407*7c478bd9Sstevel@tonic-gate 				}
408*7c478bd9Sstevel@tonic-gate 			} else {
409*7c478bd9Sstevel@tonic-gate 				ch = GETC(buf, cntr);
410*7c478bd9Sstevel@tonic-gate digit:
411*7c478bd9Sstevel@tonic-gate 				while (isdigit(ch)) {
412*7c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
413*7c478bd9Sstevel@tonic-gate 					ch = GETC(buf, cntr);
414*7c478bd9Sstevel@tonic-gate 				}
415*7c478bd9Sstevel@tonic-gate 				(void) UNGETC(cntr);
416*7c478bd9Sstevel@tonic-gate 				token = DECVAL;
417*7c478bd9Sstevel@tonic-gate 			}
418*7c478bd9Sstevel@tonic-gate 		} else if (isalpha(ch) || ch == '\\') {
419*7c478bd9Sstevel@tonic-gate 			if (ch != '\\') {
420*7c478bd9Sstevel@tonic-gate 				ch = GETC(buf, cntr);
421*7c478bd9Sstevel@tonic-gate 			} else {
422*7c478bd9Sstevel@tonic-gate 				/*
423*7c478bd9Sstevel@tonic-gate 				 * if the character was a backslash,
424*7c478bd9Sstevel@tonic-gate 				 * back up so we can overwrite it with
425*7c478bd9Sstevel@tonic-gate 				 * the next (i.e. escaped) character.
426*7c478bd9Sstevel@tonic-gate 				 */
427*7c478bd9Sstevel@tonic-gate 				cp--;
428*7c478bd9Sstevel@tonic-gate 			}
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 			while (isnamechar(ch) || ch == '\\') {
431*7c478bd9Sstevel@tonic-gate 				if (ch == '\\')
432*7c478bd9Sstevel@tonic-gate 					ch = GETC(buf, cntr);
433*7c478bd9Sstevel@tonic-gate 				*cp++ = (char)ch;
434*7c478bd9Sstevel@tonic-gate 				ch = GETC(buf, cntr);
435*7c478bd9Sstevel@tonic-gate 			}
436*7c478bd9Sstevel@tonic-gate 			(void) UNGETC(cntr);
437*7c478bd9Sstevel@tonic-gate 			token = NAME;
438*7c478bd9Sstevel@tonic-gate 		} else {
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 			return (-1);
441*7c478bd9Sstevel@tonic-gate 		}
442*7c478bd9Sstevel@tonic-gate 		break;
443*7c478bd9Sstevel@tonic-gate 	}
444*7c478bd9Sstevel@tonic-gate 	*cp = '\0';
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	return (token);
447*7c478bd9Sstevel@tonic-gate }
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate /*
451*7c478bd9Sstevel@tonic-gate  * Leave NEWLINE as the next character.
452*7c478bd9Sstevel@tonic-gate  */
453*7c478bd9Sstevel@tonic-gate static void
454*7c478bd9Sstevel@tonic-gate find_eol(char *buf)
455*7c478bd9Sstevel@tonic-gate {
456*7c478bd9Sstevel@tonic-gate 	register int ch;
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	while ((ch = GETC(buf, cntr)) != -1) {
459*7c478bd9Sstevel@tonic-gate 		if (isnewline(ch)) {
460*7c478bd9Sstevel@tonic-gate 			(void) UNGETC(cntr);
461*7c478bd9Sstevel@tonic-gate 			break;
462*7c478bd9Sstevel@tonic-gate 		}
463*7c478bd9Sstevel@tonic-gate 	}
464*7c478bd9Sstevel@tonic-gate }
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate /*
468*7c478bd9Sstevel@tonic-gate  * Fetch one record from the USBCONF_FILE
469*7c478bd9Sstevel@tonic-gate  */
470*7c478bd9Sstevel@tonic-gate static token_t
471*7c478bd9Sstevel@tonic-gate usb_get_conf_rec(char *buf, usb_configrec_t **rec, char **errmsg)
472*7c478bd9Sstevel@tonic-gate {
473*7c478bd9Sstevel@tonic-gate 	token_t token;
474*7c478bd9Sstevel@tonic-gate 	char tokval[MAXLINESIZE];
475*7c478bd9Sstevel@tonic-gate 	usb_configrec_t *user_rec;
476*7c478bd9Sstevel@tonic-gate 	config_field_t  cfgvar;
477*7c478bd9Sstevel@tonic-gate 	u_longlong_t    llptr;
478*7c478bd9Sstevel@tonic-gate 	u_longlong_t    value;
479*7c478bd9Sstevel@tonic-gate 	boolean_t	sor = B_TRUE;
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	enum {
482*7c478bd9Sstevel@tonic-gate 		USB_NEWVAR, USB_CONFIG_VAR, USB_VAR_EQUAL, USB_VAR_VALUE,
483*7c478bd9Sstevel@tonic-gate 		USB_ERROR
484*7c478bd9Sstevel@tonic-gate 	} parse_state = USB_NEWVAR;
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 	DPRINTF("usb_get_conf_rec:\n");
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	user_rec = (usb_configrec_t *)calloc(1, sizeof (usb_configrec_t));
489*7c478bd9Sstevel@tonic-gate 	if (user_rec == (usb_configrec_t *)NULL) {
490*7c478bd9Sstevel@tonic-gate 		return (0);
491*7c478bd9Sstevel@tonic-gate 	}
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	user_rec->idVendor = user_rec->idProduct = user_rec->cfgndx = -1;
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	token = lex(buf, tokval, errmsg);
496*7c478bd9Sstevel@tonic-gate 	while ((token != EOF) && (token != SEMICOLON)) {
497*7c478bd9Sstevel@tonic-gate 		switch (token) {
498*7c478bd9Sstevel@tonic-gate 		case STAR:
499*7c478bd9Sstevel@tonic-gate 		case POUND:
500*7c478bd9Sstevel@tonic-gate 			/* skip comments */
501*7c478bd9Sstevel@tonic-gate 			find_eol(buf);
502*7c478bd9Sstevel@tonic-gate 			break;
503*7c478bd9Sstevel@tonic-gate 		case NEWLINE:
504*7c478bd9Sstevel@tonic-gate 			linenum++;
505*7c478bd9Sstevel@tonic-gate 			break;
506*7c478bd9Sstevel@tonic-gate 		case NAME:
507*7c478bd9Sstevel@tonic-gate 		case STRING:
508*7c478bd9Sstevel@tonic-gate 			switch (parse_state) {
509*7c478bd9Sstevel@tonic-gate 			case USB_NEWVAR:
510*7c478bd9Sstevel@tonic-gate 				cfgvar = usb_get_var_type(tokval);
511*7c478bd9Sstevel@tonic-gate 				if (cfgvar == USB_NONE) {
512*7c478bd9Sstevel@tonic-gate 					parse_state = USB_ERROR;
513*7c478bd9Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
514*7c478bd9Sstevel@tonic-gate 					    "Syntax Error: Invalid field %s",
515*7c478bd9Sstevel@tonic-gate 					    tokval);
516*7c478bd9Sstevel@tonic-gate 				} else {
517*7c478bd9Sstevel@tonic-gate 					/*
518*7c478bd9Sstevel@tonic-gate 					 * Note the beginning of a record
519*7c478bd9Sstevel@tonic-gate 					 */
520*7c478bd9Sstevel@tonic-gate 					if (sor) {
521*7c478bd9Sstevel@tonic-gate 						brec = btoken;
522*7c478bd9Sstevel@tonic-gate 						if (frec == 0) frec = brec;
523*7c478bd9Sstevel@tonic-gate 						sor = B_FALSE;
524*7c478bd9Sstevel@tonic-gate 					}
525*7c478bd9Sstevel@tonic-gate 					parse_state = USB_CONFIG_VAR;
526*7c478bd9Sstevel@tonic-gate 				}
527*7c478bd9Sstevel@tonic-gate 				break;
528*7c478bd9Sstevel@tonic-gate 			case USB_VAR_VALUE:
529*7c478bd9Sstevel@tonic-gate 				if ((cfgvar == USB_VENDOR) ||
530*7c478bd9Sstevel@tonic-gate 				    (cfgvar == USB_PRODUCT) ||
531*7c478bd9Sstevel@tonic-gate 				    (cfgvar == USB_CFGNDX)) {
532*7c478bd9Sstevel@tonic-gate 					parse_state = USB_ERROR;
533*7c478bd9Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
534*7c478bd9Sstevel@tonic-gate 					    "Syntax Error: Invalid value %s "
535*7c478bd9Sstevel@tonic-gate 					    "for field: %s\n", tokval,
536*7c478bd9Sstevel@tonic-gate 					    usbcfg_varlist[cfgvar].name);
537*7c478bd9Sstevel@tonic-gate 				} else if (get_string(&llptr, tokval)) {
538*7c478bd9Sstevel@tonic-gate 					switch (cfgvar) {
539*7c478bd9Sstevel@tonic-gate 					case USB_SELECTION:
540*7c478bd9Sstevel@tonic-gate 						user_rec->selection =
541*7c478bd9Sstevel@tonic-gate 						    (char *)llptr;
542*7c478bd9Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
543*7c478bd9Sstevel@tonic-gate 						break;
544*7c478bd9Sstevel@tonic-gate 					case USB_SRNO:
545*7c478bd9Sstevel@tonic-gate 						user_rec->serialno =
546*7c478bd9Sstevel@tonic-gate 						    (char *)llptr;
547*7c478bd9Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
548*7c478bd9Sstevel@tonic-gate 						break;
549*7c478bd9Sstevel@tonic-gate 					case USB_PATH:
550*7c478bd9Sstevel@tonic-gate 						user_rec->pathname =
551*7c478bd9Sstevel@tonic-gate 						    (char *)llptr;
552*7c478bd9Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
553*7c478bd9Sstevel@tonic-gate 						break;
554*7c478bd9Sstevel@tonic-gate 					case USB_DRIVER:
555*7c478bd9Sstevel@tonic-gate 						user_rec->driver =
556*7c478bd9Sstevel@tonic-gate 						    (char *)llptr;
557*7c478bd9Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
558*7c478bd9Sstevel@tonic-gate 						break;
559*7c478bd9Sstevel@tonic-gate 					default:
560*7c478bd9Sstevel@tonic-gate 						parse_state = USB_ERROR;
561*7c478bd9Sstevel@tonic-gate 						free((char *)llptr);
562*7c478bd9Sstevel@tonic-gate 					}
563*7c478bd9Sstevel@tonic-gate 				} else {
564*7c478bd9Sstevel@tonic-gate 					parse_state = USB_ERROR;
565*7c478bd9Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
566*7c478bd9Sstevel@tonic-gate 					    "Syntax Error: Invalid value %s "
567*7c478bd9Sstevel@tonic-gate 					    "for field: %s\n", tokval,
568*7c478bd9Sstevel@tonic-gate 					    usbcfg_varlist[cfgvar].name);
569*7c478bd9Sstevel@tonic-gate 				}
570*7c478bd9Sstevel@tonic-gate 				break;
571*7c478bd9Sstevel@tonic-gate 			case USB_ERROR:
572*7c478bd9Sstevel@tonic-gate 				/* just skip */
573*7c478bd9Sstevel@tonic-gate 				break;
574*7c478bd9Sstevel@tonic-gate 			default:
575*7c478bd9Sstevel@tonic-gate 				parse_state = USB_ERROR;
576*7c478bd9Sstevel@tonic-gate 				(void) snprintf(*errmsg, MAXPATHLEN,
577*7c478bd9Sstevel@tonic-gate 				    "Syntax Error: at %s", tokval);
578*7c478bd9Sstevel@tonic-gate 				break;
579*7c478bd9Sstevel@tonic-gate 			}
580*7c478bd9Sstevel@tonic-gate 			break;
581*7c478bd9Sstevel@tonic-gate 		case EQUALS:
582*7c478bd9Sstevel@tonic-gate 			if (parse_state == USB_CONFIG_VAR) {
583*7c478bd9Sstevel@tonic-gate 				if (cfgvar == USB_NONE) {
584*7c478bd9Sstevel@tonic-gate 					parse_state = USB_ERROR;
585*7c478bd9Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
586*7c478bd9Sstevel@tonic-gate 					    "Syntax Error: unexpected '='");
587*7c478bd9Sstevel@tonic-gate 				} else {
588*7c478bd9Sstevel@tonic-gate 					parse_state = USB_VAR_VALUE;
589*7c478bd9Sstevel@tonic-gate 				}
590*7c478bd9Sstevel@tonic-gate 			} else if (parse_state != USB_ERROR) {
591*7c478bd9Sstevel@tonic-gate 				(void) snprintf(*errmsg, MAXPATHLEN,
592*7c478bd9Sstevel@tonic-gate 				    "Syntax Error: unexpected '='");
593*7c478bd9Sstevel@tonic-gate 				parse_state = USB_ERROR;
594*7c478bd9Sstevel@tonic-gate 			}
595*7c478bd9Sstevel@tonic-gate 			break;
596*7c478bd9Sstevel@tonic-gate 		case HEXVAL:
597*7c478bd9Sstevel@tonic-gate 		case DECVAL:
598*7c478bd9Sstevel@tonic-gate 			if ((parse_state == USB_VAR_VALUE) && (cfgvar !=
599*7c478bd9Sstevel@tonic-gate 			    USB_NONE)) {
600*7c478bd9Sstevel@tonic-gate 				(void) getvalue(tokval, &value);
601*7c478bd9Sstevel@tonic-gate 				switch (cfgvar) {
602*7c478bd9Sstevel@tonic-gate 				case USB_VENDOR:
603*7c478bd9Sstevel@tonic-gate 					user_rec->idVendor = (int)value;
604*7c478bd9Sstevel@tonic-gate 					parse_state = USB_NEWVAR;
605*7c478bd9Sstevel@tonic-gate 					break;
606*7c478bd9Sstevel@tonic-gate 				case USB_PRODUCT:
607*7c478bd9Sstevel@tonic-gate 					user_rec->idProduct = (int)value;
608*7c478bd9Sstevel@tonic-gate 					parse_state = USB_NEWVAR;
609*7c478bd9Sstevel@tonic-gate 					break;
610*7c478bd9Sstevel@tonic-gate 				case USB_CFGNDX:
611*7c478bd9Sstevel@tonic-gate 					user_rec->cfgndx = (int)value;
612*7c478bd9Sstevel@tonic-gate 					parse_state = USB_NEWVAR;
613*7c478bd9Sstevel@tonic-gate 					break;
614*7c478bd9Sstevel@tonic-gate 				default:
615*7c478bd9Sstevel@tonic-gate 					(void) snprintf(*errmsg, MAXPATHLEN,
616*7c478bd9Sstevel@tonic-gate 					    "Syntax Error: Invalid value for "
617*7c478bd9Sstevel@tonic-gate 					    "%s", usbcfg_varlist[cfgvar].name);
618*7c478bd9Sstevel@tonic-gate 				}
619*7c478bd9Sstevel@tonic-gate 			} else if (parse_state != USB_ERROR) {
620*7c478bd9Sstevel@tonic-gate 				parse_state = USB_ERROR;
621*7c478bd9Sstevel@tonic-gate 				(void) snprintf(*errmsg, MAXPATHLEN,
622*7c478bd9Sstevel@tonic-gate 				    "Syntax Error: unexpected hex/decimal: %s",
623*7c478bd9Sstevel@tonic-gate 				    tokval);
624*7c478bd9Sstevel@tonic-gate 			}
625*7c478bd9Sstevel@tonic-gate 			break;
626*7c478bd9Sstevel@tonic-gate 		default:
627*7c478bd9Sstevel@tonic-gate 			(void) snprintf(*errmsg, MAXPATHLEN,
628*7c478bd9Sstevel@tonic-gate 			    "Syntax Error: at: %s", tokval);
629*7c478bd9Sstevel@tonic-gate 			parse_state = USB_ERROR;
630*7c478bd9Sstevel@tonic-gate 			break;
631*7c478bd9Sstevel@tonic-gate 		}
632*7c478bd9Sstevel@tonic-gate 		token = lex(buf, tokval, errmsg);
633*7c478bd9Sstevel@tonic-gate 	}
634*7c478bd9Sstevel@tonic-gate 	*rec = user_rec;
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	return (token);
637*7c478bd9Sstevel@tonic-gate }
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate /*
641*7c478bd9Sstevel@tonic-gate  * Here we compare the two records and determine if they are the same
642*7c478bd9Sstevel@tonic-gate  */
643*7c478bd9Sstevel@tonic-gate static boolean_t
644*7c478bd9Sstevel@tonic-gate usb_cmp_rec(usb_configrec_t *cfg_rec, usb_configrec_t *user_rec)
645*7c478bd9Sstevel@tonic-gate {
646*7c478bd9Sstevel@tonic-gate 	char		*ustr, *cstr;
647*7c478bd9Sstevel@tonic-gate 	boolean_t	srno = B_FALSE, path = B_FALSE;
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 	DPRINTF("usb_cmp_rec:\n");
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 	if ((cfg_rec->idVendor == user_rec->idVendor) &&
652*7c478bd9Sstevel@tonic-gate 	    (cfg_rec->idProduct == user_rec->idProduct)) {
653*7c478bd9Sstevel@tonic-gate 		if (user_rec->serialno) {
654*7c478bd9Sstevel@tonic-gate 			if (cfg_rec->serialno) {
655*7c478bd9Sstevel@tonic-gate 				srno = (strcmp(cfg_rec->serialno,
656*7c478bd9Sstevel@tonic-gate 				    user_rec->serialno) == 0);
657*7c478bd9Sstevel@tonic-gate 			} else {
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 				return (B_FALSE);
660*7c478bd9Sstevel@tonic-gate 			}
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 		} else if (user_rec->pathname) {
663*7c478bd9Sstevel@tonic-gate 			if (cfg_rec->pathname) {
664*7c478bd9Sstevel@tonic-gate 				/*
665*7c478bd9Sstevel@tonic-gate 				 * Comparing on this is tricky. At this point
666*7c478bd9Sstevel@tonic-gate 				 * hubd knows: ../hubd@P/device@P while user
667*7c478bd9Sstevel@tonic-gate 				 * will specify ..../hubd@P/keyboard@P
668*7c478bd9Sstevel@tonic-gate 				 * First compare till .../hubd@P
669*7c478bd9Sstevel@tonic-gate 				 * Second compare is just P in "device@P"
670*7c478bd9Sstevel@tonic-gate 				 *
671*7c478bd9Sstevel@tonic-gate 				 * XXX: note that we assume P as one character
672*7c478bd9Sstevel@tonic-gate 				 * as there are no 2 digit hubs in the market.
673*7c478bd9Sstevel@tonic-gate 				 */
674*7c478bd9Sstevel@tonic-gate 				ustr = strrchr(user_rec->pathname, '/');
675*7c478bd9Sstevel@tonic-gate 				cstr = strrchr(cfg_rec->pathname, '/');
676*7c478bd9Sstevel@tonic-gate 				path = (strncmp(cfg_rec->pathname,
677*7c478bd9Sstevel@tonic-gate 				    user_rec->pathname,
678*7c478bd9Sstevel@tonic-gate 				    MAX(ustr - user_rec->pathname,
679*7c478bd9Sstevel@tonic-gate 				    cstr - cfg_rec->pathname)) == 0);
680*7c478bd9Sstevel@tonic-gate 				path = path && (*(user_rec->pathname +
681*7c478bd9Sstevel@tonic-gate 				    strlen(user_rec->pathname) -1) ==
682*7c478bd9Sstevel@tonic-gate 					*(cfg_rec->pathname +
683*7c478bd9Sstevel@tonic-gate 					strlen(cfg_rec->pathname) - 1));
684*7c478bd9Sstevel@tonic-gate 			} else {
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 				return (B_FALSE);
687*7c478bd9Sstevel@tonic-gate 			}
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 		} else if (cfg_rec->serialno || cfg_rec->pathname) {
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
692*7c478bd9Sstevel@tonic-gate 		} else {
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 			return (B_TRUE);
695*7c478bd9Sstevel@tonic-gate 		}
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 		return (srno || path);
698*7c478bd9Sstevel@tonic-gate 	} else {
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
701*7c478bd9Sstevel@tonic-gate 	}
702*7c478bd9Sstevel@tonic-gate }
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate /*
706*7c478bd9Sstevel@tonic-gate  * free the record allocated in usb_get_conf_rec
707*7c478bd9Sstevel@tonic-gate  */
708*7c478bd9Sstevel@tonic-gate static void
709*7c478bd9Sstevel@tonic-gate usb_free_rec(usb_configrec_t *rec)
710*7c478bd9Sstevel@tonic-gate {
711*7c478bd9Sstevel@tonic-gate 	if (rec == (usb_configrec_t *)NULL) {
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 		return;
714*7c478bd9Sstevel@tonic-gate 	}
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	free(rec->selection);
717*7c478bd9Sstevel@tonic-gate 	free(rec->serialno);
718*7c478bd9Sstevel@tonic-gate 	free(rec->pathname);
719*7c478bd9Sstevel@tonic-gate 	free(rec->driver);
720*7c478bd9Sstevel@tonic-gate 	free(rec);
721*7c478bd9Sstevel@tonic-gate }
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate int
725*7c478bd9Sstevel@tonic-gate add_entry(char *selection, int vid, int pid, int cfgndx, char *srno,
726*7c478bd9Sstevel@tonic-gate     char *path, char *driver, char **errmsg)
727*7c478bd9Sstevel@tonic-gate {
728*7c478bd9Sstevel@tonic-gate 	int		file;
729*7c478bd9Sstevel@tonic-gate 	int		rval = CFGA_USB_OK;
730*7c478bd9Sstevel@tonic-gate 	char		*buf = (char *)NULL;
731*7c478bd9Sstevel@tonic-gate 	char		str[MAXLINESIZE];
732*7c478bd9Sstevel@tonic-gate 	token_t		token = NEWLINE;
733*7c478bd9Sstevel@tonic-gate 	boolean_t	found = B_FALSE;
734*7c478bd9Sstevel@tonic-gate 	struct stat	st;
735*7c478bd9Sstevel@tonic-gate 	usb_configrec_t cfgrec, *user_rec = NULL;
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 	DPRINTF("add_entry: driver=%s, path=%s\n",
738*7c478bd9Sstevel@tonic-gate 	    driver ? driver : "", path ? path : "");
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	if (*errmsg == (char *)NULL) {
741*7c478bd9Sstevel@tonic-gate 		if ((*errmsg = calloc(MAXPATHLEN, 1)) == (char *)NULL) {
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 			return (CFGA_USB_CONFIG_FILE);
744*7c478bd9Sstevel@tonic-gate 		}
745*7c478bd9Sstevel@tonic-gate 	}
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&file_lock);
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 	/* Initialize the cfgrec */
750*7c478bd9Sstevel@tonic-gate 	cfgrec.selection = selection;
751*7c478bd9Sstevel@tonic-gate 	cfgrec.idVendor = vid;
752*7c478bd9Sstevel@tonic-gate 	cfgrec.idProduct = pid;
753*7c478bd9Sstevel@tonic-gate 	cfgrec.cfgndx = cfgndx;
754*7c478bd9Sstevel@tonic-gate 	cfgrec.serialno = srno;
755*7c478bd9Sstevel@tonic-gate 	cfgrec.pathname = path;
756*7c478bd9Sstevel@tonic-gate 	cfgrec.driver = driver;
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 	/* open config_map.conf file */
759*7c478bd9Sstevel@tonic-gate 	file = open(usbconf_file, O_RDWR, 0666);
760*7c478bd9Sstevel@tonic-gate 	if (file == -1) {
761*7c478bd9Sstevel@tonic-gate 		(void) snprintf(*errmsg, MAXPATHLEN,
762*7c478bd9Sstevel@tonic-gate 		    "failed to open config file\n");
763*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&file_lock);
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 		return (CFGA_USB_CONFIG_FILE);
766*7c478bd9Sstevel@tonic-gate 	}
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	if (lockf(file, F_TLOCK, 0) == -1) {
769*7c478bd9Sstevel@tonic-gate 		(void) snprintf(*errmsg, MAXPATHLEN,
770*7c478bd9Sstevel@tonic-gate 		    "failed to lock config file\n");
771*7c478bd9Sstevel@tonic-gate 		close(file);
772*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&file_lock);
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 		return (CFGA_USB_LOCK_FILE);
775*7c478bd9Sstevel@tonic-gate 	}
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 	/*
778*7c478bd9Sstevel@tonic-gate 	 * These variables need to be reinitialized here as they may
779*7c478bd9Sstevel@tonic-gate 	 * have been modified by a previous thread that called this
780*7c478bd9Sstevel@tonic-gate 	 * function
781*7c478bd9Sstevel@tonic-gate 	 */
782*7c478bd9Sstevel@tonic-gate 	linenum = 1;
783*7c478bd9Sstevel@tonic-gate 	cntr = 0;
784*7c478bd9Sstevel@tonic-gate 	frec = 0;
785*7c478bd9Sstevel@tonic-gate 	brec = 0;
786*7c478bd9Sstevel@tonic-gate 	btoken = 0;
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate 	if (fstat(file, &st) != 0) {
789*7c478bd9Sstevel@tonic-gate 		DPRINTF("add_entry: failed to fstat config file\n");
790*7c478bd9Sstevel@tonic-gate 		rval = CFGA_USB_CONFIG_FILE;
791*7c478bd9Sstevel@tonic-gate 		goto exit;
792*7c478bd9Sstevel@tonic-gate 	}
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	if ((buf = (char *)malloc(st.st_size)) == NULL) {
795*7c478bd9Sstevel@tonic-gate 		DPRINTF("add_entry: failed to fstat config file\n");
796*7c478bd9Sstevel@tonic-gate 		rval = CFGA_USB_ALLOC_FAIL;
797*7c478bd9Sstevel@tonic-gate 		goto exit;
798*7c478bd9Sstevel@tonic-gate 	}
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	if (st.st_size != read(file, buf, st.st_size)) {
801*7c478bd9Sstevel@tonic-gate 		DPRINTF("add_entry: failed to read config file\n");
802*7c478bd9Sstevel@tonic-gate 		rval = CFGA_USB_CONFIG_FILE;
803*7c478bd9Sstevel@tonic-gate 		goto exit;
804*7c478bd9Sstevel@tonic-gate 	}
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 	/* set up for reading the file */
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 	while ((token != EOF) && !found) {
809*7c478bd9Sstevel@tonic-gate 		if (user_rec) {
810*7c478bd9Sstevel@tonic-gate 			usb_free_rec(user_rec);
811*7c478bd9Sstevel@tonic-gate 			user_rec = NULL;
812*7c478bd9Sstevel@tonic-gate 		}
813*7c478bd9Sstevel@tonic-gate 		token = usb_get_conf_rec(buf, &user_rec, errmsg);
814*7c478bd9Sstevel@tonic-gate 		found = usb_cmp_rec(&cfgrec, user_rec);
815*7c478bd9Sstevel@tonic-gate 		DPRINTF("add_entry: token=%x, found=%x\n", token, found);
816*7c478bd9Sstevel@tonic-gate 	}
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate 	bzero(str, MAXLINESIZE);
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	if (found) {
821*7c478bd9Sstevel@tonic-gate 		DPRINTF("FOUND\n");
822*7c478bd9Sstevel@tonic-gate 		(void) snprintf(str, MAXLINESIZE, "selection=%s idVendor=0x%x "
823*7c478bd9Sstevel@tonic-gate 		    "idProduct=0x%x ",
824*7c478bd9Sstevel@tonic-gate 		    (cfgrec.selection) ? cfgrec.selection : user_rec->selection,
825*7c478bd9Sstevel@tonic-gate 		    user_rec->idVendor, user_rec->idProduct);
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 		if ((user_rec->cfgndx != -1) || (cfgrec.cfgndx != -1)) {
828*7c478bd9Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)], MAXLINESIZE,
829*7c478bd9Sstevel@tonic-gate 			    "cfgndx=0x%x ", (cfgrec.cfgndx != -1) ?
830*7c478bd9Sstevel@tonic-gate 			    cfgrec.cfgndx : user_rec->cfgndx);
831*7c478bd9Sstevel@tonic-gate 		}
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 		if (user_rec->serialno) {
834*7c478bd9Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)],  MAXLINESIZE,
835*7c478bd9Sstevel@tonic-gate 			    "srno=\"%s\" ", user_rec->serialno);
836*7c478bd9Sstevel@tonic-gate 		}
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 		if (user_rec->pathname) {
839*7c478bd9Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)],  MAXLINESIZE,
840*7c478bd9Sstevel@tonic-gate 			    "pathname=\"%s\" ", user_rec->pathname);
841*7c478bd9Sstevel@tonic-gate 		}
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 		if (user_rec->driver) {
844*7c478bd9Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)],  MAXLINESIZE,
845*7c478bd9Sstevel@tonic-gate 			    "driver=\"%s\" ", user_rec->driver);
846*7c478bd9Sstevel@tonic-gate 		} else if (cfgrec.driver != NULL) {
847*7c478bd9Sstevel@tonic-gate 			if (strlen(cfgrec.driver)) {
848*7c478bd9Sstevel@tonic-gate 				(void) snprintf(&str[strlen(str)],  MAXLINESIZE,
849*7c478bd9Sstevel@tonic-gate 				    "driver=\"%s\" ", cfgrec.driver);
850*7c478bd9Sstevel@tonic-gate 			}
851*7c478bd9Sstevel@tonic-gate 		}
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 		(void) strlcat(str, ";", sizeof (str));
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 		/*
856*7c478bd9Sstevel@tonic-gate 		 * Seek to the beginning of the record
857*7c478bd9Sstevel@tonic-gate 		 */
858*7c478bd9Sstevel@tonic-gate 		if (lseek(file, brec, SEEK_SET) == -1) {
859*7c478bd9Sstevel@tonic-gate 			DPRINTF("add_entry: failed to lseek config file\n");
860*7c478bd9Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
861*7c478bd9Sstevel@tonic-gate 			goto exit;
862*7c478bd9Sstevel@tonic-gate 		}
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 		/*
865*7c478bd9Sstevel@tonic-gate 		 * Write the modified record
866*7c478bd9Sstevel@tonic-gate 		 */
867*7c478bd9Sstevel@tonic-gate 		if (write(file, str, strlen(str)) == -1) {
868*7c478bd9Sstevel@tonic-gate 			DPRINTF("add_entry: failed to write config file\n");
869*7c478bd9Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
870*7c478bd9Sstevel@tonic-gate 			goto exit;
871*7c478bd9Sstevel@tonic-gate 		}
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 		/*
874*7c478bd9Sstevel@tonic-gate 		 * Write the rest of the file as it was
875*7c478bd9Sstevel@tonic-gate 		 */
876*7c478bd9Sstevel@tonic-gate 		if (write(file, buf+cntr, st.st_size - cntr) == -1) {
877*7c478bd9Sstevel@tonic-gate 			DPRINTF("add_entry: failed to write config file\n");
878*7c478bd9Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
879*7c478bd9Sstevel@tonic-gate 			goto exit;
880*7c478bd9Sstevel@tonic-gate 		}
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 	} else {
883*7c478bd9Sstevel@tonic-gate 		DPRINTF("!FOUND\n");
884*7c478bd9Sstevel@tonic-gate 		(void) snprintf(str, MAXLINESIZE,
885*7c478bd9Sstevel@tonic-gate 		    "selection=%s idVendor=0x%x idProduct=0x%x ",
886*7c478bd9Sstevel@tonic-gate 		    (cfgrec.selection) ? cfgrec.selection : "enable",
887*7c478bd9Sstevel@tonic-gate 		    cfgrec.idVendor, cfgrec.idProduct);
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 		if (cfgrec.cfgndx != -1) {
890*7c478bd9Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)], MAXLINESIZE,
891*7c478bd9Sstevel@tonic-gate 			    "cfgndx=0x%x ", cfgrec.cfgndx);
892*7c478bd9Sstevel@tonic-gate 		}
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 		if (cfgrec.serialno) {
895*7c478bd9Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)], MAXLINESIZE,
896*7c478bd9Sstevel@tonic-gate 			    "srno=\"%s\" ", cfgrec.serialno);
897*7c478bd9Sstevel@tonic-gate 		}
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 		if (cfgrec.pathname != NULL) {
900*7c478bd9Sstevel@tonic-gate 			(void) snprintf(&str[strlen(str)], MAXLINESIZE,
901*7c478bd9Sstevel@tonic-gate 			    "pathname=\"%s\" ", cfgrec.pathname);
902*7c478bd9Sstevel@tonic-gate 		}
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 		if (cfgrec.driver != NULL) {
905*7c478bd9Sstevel@tonic-gate 			if (strlen(cfgrec.driver)) {
906*7c478bd9Sstevel@tonic-gate 				(void) snprintf(&str[strlen(str)], MAXLINESIZE,
907*7c478bd9Sstevel@tonic-gate 				    "driver=\"%s\" ", cfgrec.driver);
908*7c478bd9Sstevel@tonic-gate 			}
909*7c478bd9Sstevel@tonic-gate 		}
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 		(void) strlcat(str, ";\n", sizeof (str));
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 		/*
914*7c478bd9Sstevel@tonic-gate 		 * Incase this is the first entry, add it after the comments
915*7c478bd9Sstevel@tonic-gate 		 */
916*7c478bd9Sstevel@tonic-gate 		if (frec == 0) {
917*7c478bd9Sstevel@tonic-gate 			frec = st.st_size;
918*7c478bd9Sstevel@tonic-gate 		}
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 		/*
921*7c478bd9Sstevel@tonic-gate 		 * Go to the beginning of the records
922*7c478bd9Sstevel@tonic-gate 		 */
923*7c478bd9Sstevel@tonic-gate 		if (lseek(file, frec, SEEK_SET) == -1) {
924*7c478bd9Sstevel@tonic-gate 			DPRINTF("add_entry: failed to lseek config file\n");
925*7c478bd9Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
926*7c478bd9Sstevel@tonic-gate 			goto exit;
927*7c478bd9Sstevel@tonic-gate 		}
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 		/*
930*7c478bd9Sstevel@tonic-gate 		 * Add the entry
931*7c478bd9Sstevel@tonic-gate 		 */
932*7c478bd9Sstevel@tonic-gate 		if (write(file, str, strlen(str)) == -1) {
933*7c478bd9Sstevel@tonic-gate 			DPRINTF("add_entry: failed to write config file\n");
934*7c478bd9Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
935*7c478bd9Sstevel@tonic-gate 			goto exit;
936*7c478bd9Sstevel@tonic-gate 		}
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 		/*
939*7c478bd9Sstevel@tonic-gate 		 * write the remaining file as it was
940*7c478bd9Sstevel@tonic-gate 		 */
941*7c478bd9Sstevel@tonic-gate 		if (write(file, buf+frec, st.st_size - frec) == -1) {
942*7c478bd9Sstevel@tonic-gate 			DPRINTF("add_entry: failed to write config file\n");
943*7c478bd9Sstevel@tonic-gate 			rval = CFGA_USB_CONFIG_FILE;
944*7c478bd9Sstevel@tonic-gate 			goto exit;
945*7c478bd9Sstevel@tonic-gate 		}
946*7c478bd9Sstevel@tonic-gate 	}
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate 	/* no error encountered */
949*7c478bd9Sstevel@tonic-gate 	if (rval == CFGA_USB_OK) {
950*7c478bd9Sstevel@tonic-gate 		free(errmsg);
951*7c478bd9Sstevel@tonic-gate 	}
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate exit:
954*7c478bd9Sstevel@tonic-gate 	if (buf != NULL) {
955*7c478bd9Sstevel@tonic-gate 		free(buf);
956*7c478bd9Sstevel@tonic-gate 	}
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	if (lockf(file, F_ULOCK, 0) == -1) {
959*7c478bd9Sstevel@tonic-gate 		DPRINTF("add_entry: failed to unlock config file\n");
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 		rval = CFGA_USB_LOCK_FILE;
962*7c478bd9Sstevel@tonic-gate 	}
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	close(file);
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&file_lock);
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 	return (rval);
969*7c478bd9Sstevel@tonic-gate }
970