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