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