xref: /illumos-gate/usr/src/lib/udapl/libdat/common/udat_sr_parser.c (revision 628e3cbed6489fa1db545d8524a06cd6535af456)
1 /*
2  * CDDL HEADER START
3  *
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.
8  *
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.
13  *
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]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
24  */
25 
26 /*
27  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 
34 /*
35  *
36  * MODULE: dat_sr_parser.c
37  *
38  * PURPOSE: static registry parser
39  *
40  * $Id: udat_sr_parser.c,v 1.1 2003/07/31 14:04:19 jlentini Exp $
41  */
42 
43 
44 #include "udat_sr_parser.h"
45 #include "dat_sr.h"
46 
47 
48 /*
49  *
50  * Constants
51  *
52  */
53 
54 #define	DAT_SR_CONF_ENV 		"DAT_OVERRIDE"
55 #define	DAT_SR_CONF_DEFAULT 		"/etc/dat/dat.conf"
56 
57 #define	DAT_SR_TOKEN_THREADSAFE 	"threadsafe"
58 #define	DAT_SR_TOKEN_NONTHREADSAFE 	"nonthreadsafe"
59 #define	DAT_SR_TOKEN_DEFAULT 		"default"
60 #define	DAT_SR_TOKEN_NONDEFAULT 	"nondefault"
61 
62 #define	DAT_SR_CHAR_NEWLINE 		'\n'
63 #define	DAT_SR_CHAR_COMMENT 		'#'
64 #define	DAT_SR_CHAR_QUOTE 		'"'
65 #define	DAT_SR_CHAR_BACKSLASH 		'\\'
66 
67 
68 /*
69  *
70  * Enumerations
71  *
72  */
73 
74 typedef enum
75 {
76 	DAT_SR_TOKEN_STRING,	/* text field (both quoted or unquoted)	*/
77 	DAT_SR_TOKEN_EOR,	/* end of record (newline)		*/
78 	DAT_SR_TOKEN_EOF 	/* end of file				*/
79 } DAT_SR_TOKEN_TYPE;
80 
81 typedef enum
82 {
83 	DAT_SR_API_UDAT,
84 	DAT_SR_API_KDAT
85 } DAT_SR_API_TYPE;
86 
87 
88 /*
89  *
90  * Structures
91  *
92  */
93 
94 typedef struct
95 {
96     DAT_SR_TOKEN_TYPE 	type;
97     char		*value; /* valid if type is DAT_SR_TOKEN_STRING */
98     DAT_OS_SIZE 	value_len;
99 } DAT_SR_TOKEN;
100 
101 typedef struct DAT_SR_STACK_NODE
102 {
103     DAT_SR_TOKEN 		token;
104     struct DAT_SR_STACK_NODE    *next;
105 } DAT_SR_STACK_NODE;
106 
107 typedef struct
108 {
109     DAT_UINT32 			major;
110     DAT_UINT32 			minor;
111 } DAT_SR_VERSION;
112 
113 typedef struct
114 {
115     char			*id;
116     DAT_SR_VERSION 		version;
117 } DAT_SR_PROVIDER_VERSION;
118 
119 typedef struct
120 {
121     DAT_SR_API_TYPE 		type;
122     DAT_SR_VERSION 		version;
123 } DAT_SR_API_VERSION;
124 
125 typedef struct
126 {
127     char			*ia_name;
128     DAT_SR_API_VERSION 		api_version;
129     DAT_BOOLEAN 		is_thread_safe;
130     DAT_BOOLEAN 		is_default;
131     char 			*lib_path;
132     DAT_SR_PROVIDER_VERSION 	provider_version;
133     char 			*ia_params;
134     char  			*platform_params;
135 } DAT_SR_CONF_ENTRY;
136 
137 
138 /*
139  *
140  * Internal Function Declarations
141  *
142  */
143 
144 static DAT_RETURN
145 dat_sr_load_entry(
146     DAT_SR_CONF_ENTRY *entry);
147 
148 static DAT_BOOLEAN
149 dat_sr_is_valid_entry(
150     DAT_SR_CONF_ENTRY *entry);
151 
152 static char *
153 dat_sr_type_to_str(
154     DAT_SR_TOKEN_TYPE type);
155 
156 static DAT_RETURN
157 dat_sr_parse_eof(
158     DAT_OS_FILE *file);
159 
160 static DAT_RETURN
161 dat_sr_parse_entry(
162     DAT_OS_FILE *file);
163 
164 static DAT_RETURN
165 dat_sr_parse_ia_name(
166     DAT_OS_FILE *file,
167     DAT_SR_CONF_ENTRY *entry);
168 
169 static DAT_RETURN
170 dat_sr_parse_api(
171     DAT_OS_FILE *file,
172     DAT_SR_CONF_ENTRY *entry);
173 
174 static DAT_RETURN
175 dat_sr_parse_thread_safety(
176     DAT_OS_FILE *file,
177     DAT_SR_CONF_ENTRY *entry);
178 
179 static DAT_RETURN
180 dat_sr_parse_default(
181     DAT_OS_FILE *file,
182     DAT_SR_CONF_ENTRY *entry);
183 
184 static DAT_RETURN
185 dat_sr_parse_lib_path(
186     DAT_OS_FILE *file,
187     DAT_SR_CONF_ENTRY *entry);
188 
189 static DAT_RETURN
190 dat_sr_parse_provider_version(
191     DAT_OS_FILE *file,
192     DAT_SR_CONF_ENTRY *entry);
193 
194 static DAT_RETURN
195 dat_sr_parse_ia_params(
196     DAT_OS_FILE *file,
197     DAT_SR_CONF_ENTRY *entry);
198 
199 static DAT_RETURN
200 dat_sr_parse_platform_params(
201     DAT_OS_FILE *file,
202     DAT_SR_CONF_ENTRY *entry);
203 
204 static DAT_RETURN
205 dat_sr_parse_eoe(
206     DAT_OS_FILE *file,
207     DAT_SR_CONF_ENTRY *entry);
208 
209 static DAT_RETURN
210 dat_sr_convert_api(
211     char *str,
212     DAT_SR_API_VERSION *api_version);
213 
214 static DAT_RETURN
215 dat_sr_convert_thread_safety(
216     char *str,
217     DAT_BOOLEAN *is_thread_safe);
218 
219 static DAT_RETURN
220 dat_sr_convert_default(
221     char *str,
222     DAT_BOOLEAN *is_default);
223 
224 static DAT_RETURN
225 dat_sr_convert_provider_version(
226     char *str,
227     DAT_SR_PROVIDER_VERSION *provider_version);
228 
229 static DAT_RETURN
230 dat_sr_get_token(
231     DAT_OS_FILE *file,
232     DAT_SR_TOKEN *token);
233 
234 static DAT_RETURN
235 dat_sr_put_token(
236     DAT_OS_FILE *file,
237     DAT_SR_TOKEN *token);
238 
239 static DAT_RETURN
240 dat_sr_read_token(
241     DAT_OS_FILE *file,
242     DAT_SR_TOKEN *token);
243 
244 static DAT_RETURN
245 dat_sr_read_str(
246     DAT_OS_FILE *file,
247     DAT_SR_TOKEN *token,
248     DAT_OS_SIZE token_len);
249 
250 static DAT_RETURN
251 dat_sr_read_quoted_str(
252     DAT_OS_FILE *file,
253     DAT_SR_TOKEN *token,
254     DAT_OS_SIZE token_len,
255     DAT_COUNT num_escape_seq);
256 
257 static void
258 dat_sr_read_comment(
259     DAT_OS_FILE *file);
260 
261 
262 /*
263  *
264  * Global Variables
265  *
266  */
267 
268 static DAT_SR_STACK_NODE 	*g_token_stack = NULL;
269 
270 
271 /*
272  *
273  * External Function Definitions
274  *
275  */
276 
277 /*
278  * Function: dat_sr_load
279  */
280 
281 DAT_RETURN
282 dat_sr_load(void)
283 {
284 	char 			*sr_path;
285 	DAT_OS_FILE 		*sr_file;
286 
287 	sr_path = dat_os_getenv(DAT_SR_CONF_ENV);
288 	if (sr_path == NULL) {
289 		sr_path = DAT_SR_CONF_DEFAULT;
290 	}
291 
292 	dat_os_dbg_print(DAT_OS_DBG_TYPE_SR,
293 	    "DAT Registry: static registry file <%s> \n", sr_path);
294 
295 	sr_file = dat_os_fopen(sr_path);
296 	if (sr_file == NULL) {
297 		return (DAT_INTERNAL_ERROR);
298 	}
299 
300 	for (;;) {
301 		if (DAT_SUCCESS == dat_sr_parse_eof(sr_file)) {
302 			break;
303 		} else if (DAT_SUCCESS == dat_sr_parse_entry(sr_file)) {
304 			continue;
305 		} else {
306 			dat_os_assert(!"unable to parse static registry file");
307 			break;
308 		}
309 	}
310 
311 	if (0 != dat_os_fclose(sr_file)) {
312 		return (DAT_INTERNAL_ERROR);
313 	}
314 
315 	return (DAT_SUCCESS);
316 }
317 
318 
319 /*
320  *
321  * Internal Function Definitions
322  *
323  */
324 
325 /*
326  * Function: dat_sr_is_valid_entry
327  */
328 
329 DAT_BOOLEAN
330 dat_sr_is_valid_entry(
331     DAT_SR_CONF_ENTRY *entry)
332 {
333 	if ((DAT_SR_API_UDAT == entry->api_version.type) &&
334 	    (entry->is_default)) {
335 		return (DAT_TRUE);
336 	} else {
337 		return (DAT_FALSE);
338 	}
339 }
340 
341 
342 /*
343  * Function: dat_sr_load_entry
344  */
345 
346 DAT_RETURN
347 dat_sr_load_entry(
348     DAT_SR_CONF_ENTRY *conf_entry)
349 {
350 	DAT_SR_ENTRY entry;
351 
352 	if (DAT_NAME_MAX_LENGTH < (strlen(conf_entry->ia_name) + 1)) {
353 		dat_os_dbg_print(DAT_OS_DBG_TYPE_SR,
354 		    "DAT Registry: ia name %s is longer than "
355 		    "DAT_NAME_MAX_LENGTH (%i)\n",
356 		    conf_entry->ia_name, DAT_NAME_MAX_LENGTH);
357 
358 		return (DAT_INSUFFICIENT_RESOURCES);
359 	}
360 
361 	(void) dat_os_strncpy(entry.info.ia_name, conf_entry->ia_name,
362 	    DAT_NAME_MAX_LENGTH);
363 	entry.info.dapl_version_major = conf_entry->api_version.version.major;
364 	entry.info.dapl_version_minor = conf_entry->api_version.version.minor;
365 	entry.info.is_thread_safe = conf_entry->is_thread_safe;
366 	entry.lib_path = conf_entry->lib_path;
367 	entry.ia_params = conf_entry->ia_params;
368 	entry.lib_handle = NULL;
369 	entry.ref_count = 0;
370 
371 	dat_os_dbg_print(DAT_OS_DBG_TYPE_SR,
372 	    "DAT Registry: loading provider for %s\n",
373 	    conf_entry->ia_name);
374 
375 	return (dat_sr_insert(&entry.info, &entry));
376 }
377 
378 
379 /*
380  * Function: dat_sr_type_to_str
381  */
382 
383 char *
384 dat_sr_type_to_str(
385     DAT_SR_TOKEN_TYPE type)
386 {
387 	static char *str_array[] = { "string", "eor", "eof" };
388 
389 	if ((type < 0) || (2 < type)) {
390 		return ("error: invalid token type");
391 	}
392 
393 	return (str_array[type]);
394 }
395 
396 
397 /*
398  * Function: dat_sr_parse_eof
399  */
400 
401 DAT_RETURN
402 dat_sr_parse_eof(
403 	DAT_OS_FILE 		*file)
404 {
405 	DAT_SR_TOKEN 	token;
406 
407 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
408 		return (DAT_INTERNAL_ERROR);
409 	}
410 
411 	if (DAT_SR_TOKEN_EOF == token.type) {
412 		return (DAT_SUCCESS);
413 	} else {
414 		(void) dat_sr_put_token(file, &token);
415 		return (DAT_INTERNAL_ERROR);
416 	}
417 }
418 
419 
420 /*
421  * Function: dat_sr_parse_ia_name
422  */
423 
424 DAT_RETURN
425 dat_sr_parse_entry(
426     DAT_OS_FILE 		*file)
427 {
428 	DAT_SR_CONF_ENTRY		entry;
429 	DAT_RETURN 			status;
430 
431 	(void) dat_os_memset(&entry, 0, sizeof (DAT_SR_CONF_ENTRY));
432 
433 	if ((DAT_SUCCESS == dat_sr_parse_ia_name(file, &entry)) &&
434 	    (DAT_SUCCESS == dat_sr_parse_api(file, &entry)) &&
435 	    (DAT_SUCCESS == dat_sr_parse_thread_safety(file, &entry)) &&
436 	    (DAT_SUCCESS == dat_sr_parse_default(file, &entry)) &&
437 	    (DAT_SUCCESS == dat_sr_parse_lib_path(file, &entry)) &&
438 	    (DAT_SUCCESS == dat_sr_parse_provider_version(file, &entry)) &&
439 	    (DAT_SUCCESS == dat_sr_parse_ia_params(file, &entry)) &&
440 	    (DAT_SUCCESS == dat_sr_parse_platform_params(file, &entry)) &&
441 	    (DAT_SUCCESS == dat_sr_parse_eoe(file, &entry))) {
442 		dat_os_dbg_print(DAT_OS_DBG_TYPE_SR,
443 		    "\n"
444 		    "DAT Registry: entry \n"
445 		    " ia_name %s\n"
446 		    " api_version\n"
447 		    "     type 0x%X\n"
448 		    "     major.minor %d.%d\n"
449 		    " is_thread_safe %d\n"
450 		    " is_default %d\n"
451 		    " lib_path %s\n"
452 		    " provider_version\n"
453 		    "     id %s\n"
454 		    "     major.minor %d.%d\n"
455 		    " ia_params %s\n"
456 		    "\n",
457 		    entry.ia_name,
458 		    entry.api_version.type,
459 		    entry.api_version.version.major,
460 		    entry.api_version.version.minor,
461 		    entry.is_thread_safe,
462 		    entry.is_default,
463 		    entry.lib_path,
464 		    entry.provider_version.id,
465 		    entry.provider_version.version.major,
466 		    entry.provider_version.version.minor,
467 		    entry.ia_params);
468 
469 		if (DAT_TRUE == dat_sr_is_valid_entry(&entry)) {
470 			/*
471 			 * The static registry configuration file may have
472 			 * multiple entries with the same IA name. The first
473 			 * entry will be installed in the static registry
474 			 * causing subsequent attempts to register the same IA
475 			 * name to fail. Therefore the return code from
476 			 * dat_sr_load_entry() is ignored.
477 			 */
478 			(void) dat_sr_load_entry(&entry);
479 		}
480 
481 		status = DAT_SUCCESS;
482 	} else { /* resync */
483 		DAT_SR_TOKEN 		token;
484 
485 		/*
486 		 * The static registry format is specified in the DAT
487 		 * specification. While the registry file's contents may change
488 		 * between revisions of the specification, there is no way to
489 		 * determine the specification version to which the
490 		 * configuration file conforms. If an entry is found that does
491 		 * not match the expected format, the entry is discarded
492 		 * and the parsing of the file continues. There is no way to
493 		 * determine if the entry was an error or an entry confirming
494 		 * to an alternate version of specification.
495 		 */
496 
497 		for (;;) {
498 			if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
499 				status = DAT_INTERNAL_ERROR;
500 				break;
501 			}
502 
503 			if (DAT_SR_TOKEN_STRING != token.type) {
504 				status = DAT_SUCCESS;
505 				break;
506 			} else {
507 				dat_os_free(token.value,
508 				    (sizeof (char) *
509 					dat_os_strlen(token.value)) + 1);
510 				continue;
511 			}
512 		}
513 	}
514 
515 	/* free resources */
516 	if (NULL != entry.ia_name) {
517 		dat_os_free(entry.ia_name,
518 		    sizeof (char) * (dat_os_strlen(entry.ia_name) + 1));
519 	}
520 	if (NULL != entry.lib_path) {
521 		dat_os_free(entry.lib_path,
522 		    sizeof (char) * (dat_os_strlen(entry.lib_path) + 1));
523 	}
524 
525 	if (NULL != entry.provider_version.id) {
526 		dat_os_free(entry.provider_version.id,
527 		    sizeof (char) *
528 		    (dat_os_strlen(entry.provider_version.id) + 1));
529 	}
530 
531 	if (NULL != entry.ia_params) {
532 		dat_os_free(entry.ia_params,
533 		    sizeof (char) * (dat_os_strlen(entry.ia_params) + 1));
534 	}
535 
536 	return (status);
537 }
538 
539 
540 /*
541  * Function: dat_sr_parse_ia_name
542  */
543 
544 DAT_RETURN
545 dat_sr_parse_ia_name(
546     DAT_OS_FILE 	*file,
547     DAT_SR_CONF_ENTRY 	*entry)
548 {
549 	DAT_SR_TOKEN 	token;
550 	DAT_RETURN 	status;
551 
552 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
553 		return (DAT_INTERNAL_ERROR);
554 	}
555 
556 	if (DAT_SR_TOKEN_STRING != token.type) {
557 		status = DAT_INTERNAL_ERROR;
558 	} else {
559 		entry->ia_name = token.value;
560 
561 		status = DAT_SUCCESS;
562 	}
563 
564 	if (DAT_SUCCESS != status) {
565 		DAT_RETURN 	status_success;
566 
567 		status_success = dat_sr_put_token(file, &token);
568 		dat_os_assert(DAT_SUCCESS == status_success);
569 	}
570 
571 	return (status);
572 }
573 
574 
575 /*
576  * Function: dat_sr_parse_ia_name
577  */
578 
579 DAT_RETURN
580 dat_sr_parse_api(
581     DAT_OS_FILE 	*file,
582     DAT_SR_CONF_ENTRY 	*entry)
583 {
584 	DAT_SR_TOKEN 	token;
585 	DAT_RETURN 	status;
586 
587 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
588 		return (DAT_INTERNAL_ERROR);
589 	}
590 
591 	if (DAT_SR_TOKEN_STRING != token.type) {
592 		status = DAT_INTERNAL_ERROR;
593 	} else if (DAT_SUCCESS != dat_sr_convert_api(
594 		token.value, &entry->api_version)) {
595 		status = DAT_INTERNAL_ERROR;
596 	} else {
597 		dat_os_free(token.value,
598 		    (sizeof (char) * dat_os_strlen(token.value)) + 1);
599 
600 		status = DAT_SUCCESS;
601 	}
602 
603 	if (DAT_SUCCESS != status) {
604 		DAT_RETURN 	status_success;
605 
606 		status_success = dat_sr_put_token(file, &token);
607 		dat_os_assert(DAT_SUCCESS == status_success);
608 	}
609 
610 	return (status);
611 }
612 
613 
614 /*
615  * Function: dat_sr_parse_thread_safety
616  */
617 
618 static DAT_RETURN
619 dat_sr_parse_thread_safety(
620     DAT_OS_FILE 	*file,
621     DAT_SR_CONF_ENTRY 	*entry)
622 {
623 	DAT_SR_TOKEN 	token;
624 	DAT_RETURN 	status;
625 
626 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
627 		return (DAT_INTERNAL_ERROR);
628 	}
629 
630 	if (DAT_SR_TOKEN_STRING != token.type) {
631 		status = DAT_INTERNAL_ERROR;
632 	} else if (DAT_SUCCESS != dat_sr_convert_thread_safety(
633 		token.value, &entry->is_thread_safe)) {
634 		status = DAT_INTERNAL_ERROR;
635 	} else {
636 		dat_os_free(token.value,
637 		    (sizeof (char) * dat_os_strlen(token.value)) + 1);
638 
639 		status = DAT_SUCCESS;
640 	}
641 
642 	if (DAT_SUCCESS != status) {
643 		DAT_RETURN 	status_success;
644 
645 		status_success = dat_sr_put_token(file, &token);
646 		dat_os_assert(DAT_SUCCESS == status_success);
647 	}
648 
649 	return (status);
650 }
651 
652 
653 /*
654  * Function: dat_sr_parse_default
655  */
656 
657 DAT_RETURN
658 dat_sr_parse_default(
659     DAT_OS_FILE 	*file,
660     DAT_SR_CONF_ENTRY 	*entry)
661 {
662 	DAT_SR_TOKEN 	token;
663 	DAT_RETURN 	status;
664 
665 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
666 		return (DAT_INTERNAL_ERROR);
667 	}
668 
669 	if (DAT_SR_TOKEN_STRING != token.type) {
670 		status = DAT_INTERNAL_ERROR;
671 	} else if (DAT_SUCCESS != dat_sr_convert_default(
672 		token.value, &entry->is_default)) {
673 		status = DAT_INTERNAL_ERROR;
674 	} else {
675 		dat_os_free(token.value,
676 		    (sizeof (char) * dat_os_strlen(token.value)) + 1);
677 
678 		status = DAT_SUCCESS;
679 	}
680 
681 	if (DAT_SUCCESS != status) {
682 		DAT_RETURN 	status_success;
683 
684 		status_success = dat_sr_put_token(file, &token);
685 		dat_os_assert(DAT_SUCCESS == status_success);
686 	}
687 
688 	return (status);
689 }
690 
691 
692 /*
693  * Function: dat_sr_parse_lib_path
694  */
695 
696 DAT_RETURN
697 dat_sr_parse_lib_path(
698     DAT_OS_FILE 	*file,
699     DAT_SR_CONF_ENTRY 	*entry)
700 {
701 	DAT_SR_TOKEN 	token;
702 	DAT_RETURN 	status;
703 
704 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
705 		return (DAT_INTERNAL_ERROR);
706 	}
707 
708 	if (DAT_SR_TOKEN_STRING != token.type) {
709 		status = DAT_INTERNAL_ERROR;
710 	} else {
711 		entry->lib_path = token.value;
712 
713 		status = DAT_SUCCESS;
714 	}
715 
716 	if (DAT_SUCCESS != status) {
717 		DAT_RETURN 	status_success;
718 
719 		status_success = dat_sr_put_token(file, &token);
720 		dat_os_assert(DAT_SUCCESS == status_success);
721 	}
722 
723 	return (status);
724 }
725 
726 /*
727  * Function: dat_sr_parse_provider_version
728  */
729 
730 DAT_RETURN
731 dat_sr_parse_provider_version(
732     DAT_OS_FILE 	*file,
733     DAT_SR_CONF_ENTRY 	*entry)
734 {
735 	DAT_SR_TOKEN 	token;
736 	DAT_RETURN 	status;
737 
738 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
739 		return (DAT_INTERNAL_ERROR);
740 	}
741 
742 	if (DAT_SR_TOKEN_STRING != token.type) {
743 		status = DAT_INTERNAL_ERROR;
744 	} else if (DAT_SUCCESS != dat_sr_convert_provider_version(
745 		token.value, &entry->provider_version)) {
746 		status = DAT_INTERNAL_ERROR;
747 	} else {
748 		dat_os_free(token.value,
749 		    (sizeof (char) * dat_os_strlen(token.value)) + 1);
750 
751 		status = DAT_SUCCESS;
752 	}
753 
754 	if (DAT_SUCCESS != status) {
755 		DAT_RETURN 	status_success;
756 
757 		status_success = dat_sr_put_token(file, &token);
758 		dat_os_assert(DAT_SUCCESS == status_success);
759 	}
760 
761 	return (status);
762 }
763 
764 
765 /*
766  * Function: dat_sr_parse_ia_params
767  */
768 
769 DAT_RETURN
770 dat_sr_parse_ia_params(
771     DAT_OS_FILE *file,
772     DAT_SR_CONF_ENTRY *entry)
773 {
774 	DAT_SR_TOKEN 	token;
775 	DAT_RETURN 	status;
776 
777 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
778 		return (DAT_INTERNAL_ERROR);
779 	}
780 
781 	if (DAT_SR_TOKEN_STRING != token.type) {
782 		status = DAT_INTERNAL_ERROR;
783 	} else {
784 		entry->ia_params = token.value;
785 
786 		status = DAT_SUCCESS;
787 	}
788 
789 	if (DAT_SUCCESS != status) {
790 		DAT_RETURN 	status_success;
791 
792 		status_success = dat_sr_put_token(file, &token);
793 		dat_os_assert(DAT_SUCCESS == status_success);
794 	}
795 
796 	return (status);
797 }
798 
799 
800 /*
801  * Function: dat_sr_parse_platform_params
802  */
803 
804 DAT_RETURN
805 dat_sr_parse_platform_params(
806     DAT_OS_FILE *file,
807     DAT_SR_CONF_ENTRY *entry)
808 {
809 	DAT_SR_TOKEN 	token;
810 	DAT_RETURN 	status;
811 
812 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
813 		return (DAT_INTERNAL_ERROR);
814 	}
815 
816 	if (DAT_SR_TOKEN_STRING != token.type) {
817 		status = DAT_INTERNAL_ERROR;
818 	} else {
819 		entry->platform_params = token.value;
820 
821 		status = DAT_SUCCESS;
822 	}
823 
824 	if (DAT_SUCCESS != status) {
825 		DAT_RETURN 	status_success;
826 
827 		status_success = dat_sr_put_token(file, &token);
828 		dat_os_assert(DAT_SUCCESS == status_success);
829 	}
830 
831 	return (status);
832 }
833 
834 
835 /*
836  * Function: dat_sr_parse_eoe
837  */
838 
839 DAT_RETURN
840 dat_sr_parse_eoe(
841     DAT_OS_FILE *file,
842 	DAT_SR_CONF_ENTRY *entry) /*ARGSUSED*/
843 {
844 	DAT_SR_TOKEN 	token;
845 	DAT_RETURN 	status;
846 
847 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
848 		return (DAT_INTERNAL_ERROR);
849 	}
850 
851 	if ((DAT_SR_TOKEN_EOF != token.type) &&
852 	    (DAT_SR_TOKEN_EOR != token.type)) {
853 		status = DAT_INTERNAL_ERROR;
854 	} else {
855 		status = DAT_SUCCESS;
856 	}
857 
858 	if (DAT_SUCCESS != status) {
859 		DAT_RETURN 	status_success;
860 
861 		status_success = dat_sr_put_token(file, &token);
862 		dat_os_assert(DAT_SUCCESS == status_success);
863 	}
864 
865 	return (status);
866 }
867 
868 
869 /*
870  * Function: dat_sr_convert_api
871  */
872 
873 DAT_RETURN
874 dat_sr_convert_api(
875     char *str,
876     DAT_SR_API_VERSION *api_version)
877 {
878 	int i;
879 	int minor_i;
880 
881 	dat_os_assert(0 < dat_os_strlen(str));
882 
883 	if ('u' == str[0]) {
884 		api_version->type = DAT_SR_API_UDAT;
885 	} else if ('k' == str[0]) {
886 		api_version->type = DAT_SR_API_KDAT;
887 	} else {
888 		return (DAT_INTERNAL_ERROR);
889 	}
890 
891 	for (i = 1 /* move past initial [u|k] */; '\0' != str[i]; i++) {
892 		if ('.' == str[i]) {
893 			break;
894 		} else if (DAT_TRUE != dat_os_isdigit(str[i])) {
895 			return (DAT_INTERNAL_ERROR);
896 		}
897 	}
898 
899 	api_version->version.major = (DAT_UINT32)dat_os_strtol(str + 1, NULL,
900 	    10);
901 
902 	/* move past '.' */
903 	minor_i = ++i;
904 
905 	for (; '\0' != str[i]; i++) {
906 		if (DAT_TRUE != dat_os_isdigit(str[i])) {
907 			return (DAT_INTERNAL_ERROR);
908 		}
909 	}
910 
911 	api_version->version.minor = (DAT_UINT32)dat_os_strtol(str + minor_i,
912 	    NULL, 10);
913 
914 	if ('\0' != str[i]) {
915 		return (DAT_INTERNAL_ERROR);
916 	}
917 
918 	return (DAT_SUCCESS);
919 }
920 
921 
922 /*
923  * Function: dat_sr_convert_thread_safety
924  */
925 
926 static DAT_RETURN
927 dat_sr_convert_thread_safety(
928     char *str,
929     DAT_BOOLEAN *is_thread_safe)
930 {
931 	if (!dat_os_strncmp(str,
932 	    DAT_SR_TOKEN_THREADSAFE,
933 	    dat_os_strlen(DAT_SR_TOKEN_THREADSAFE))) {
934 		*is_thread_safe = DAT_TRUE;
935 		return (DAT_SUCCESS);
936 	} else if (!dat_os_strncmp(str,
937 	    DAT_SR_TOKEN_NONTHREADSAFE,
938 	    dat_os_strlen(DAT_SR_TOKEN_NONTHREADSAFE))) {
939 		*is_thread_safe = DAT_FALSE;
940 		return (DAT_SUCCESS);
941 	} else {
942 		return (DAT_INTERNAL_ERROR);
943 	}
944 }
945 
946 
947 /*
948  * Function: dat_sr_convert_default
949  */
950 
951 static DAT_RETURN
952 dat_sr_convert_default(
953     char *str,
954     DAT_BOOLEAN *is_default)
955 {
956 	if (!dat_os_strncmp(str,
957 	    DAT_SR_TOKEN_DEFAULT,
958 	    dat_os_strlen(DAT_SR_TOKEN_DEFAULT))) {
959 		*is_default = DAT_TRUE;
960 		return (DAT_SUCCESS);
961 	} else if (!dat_os_strncmp(str,
962 	    DAT_SR_TOKEN_NONDEFAULT,
963 	    dat_os_strlen(DAT_SR_TOKEN_NONDEFAULT))) {
964 		*is_default = DAT_FALSE;
965 		return (DAT_SUCCESS);
966 	} else {
967 		return (DAT_INTERNAL_ERROR);
968 	}
969 }
970 
971 
972 /*
973  * Function: dat_sr_convert_provider_version
974  */
975 
976 DAT_RETURN
977 dat_sr_convert_provider_version(
978     char *str,
979     DAT_SR_PROVIDER_VERSION *provider_version)
980 {
981 	DAT_RETURN 	status;
982 	int 		i;
983 	int 		decimal_i;
984 
985 	dat_os_assert(0 < dat_os_strlen(str));
986 	dat_os_assert(NULL == provider_version->id);
987 
988 	status = DAT_SUCCESS;
989 
990 	for (i = 0; '\0' != str[i]; i++) {
991 		if ('.' == str[i]) {
992 			break;
993 		}
994 	}
995 
996 	/* if no id value was found */
997 	if (0 == i) {
998 		status = DAT_INTERNAL_ERROR;
999 		goto exit;
1000 	}
1001 
1002 	if (NULL == (provider_version->id = dat_os_alloc(sizeof (char) *
1003 	    (i + 1)))) {
1004 		status = DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY;
1005 		goto exit;
1006 	}
1007 
1008 	(void) dat_os_strncpy(provider_version->id, str, i);
1009 	provider_version->id[i] = '\0';
1010 
1011 	/* move past '.' */
1012 	decimal_i = ++i;
1013 
1014 	for (; '\0' != str[i]; i++) {
1015 		if ('.' == str[i]) {
1016 			break;
1017 		} else if (DAT_TRUE != dat_os_isdigit(str[i])) {
1018 			status = DAT_INTERNAL_ERROR;
1019 			goto exit;
1020 		}
1021 	}
1022 
1023 	/* if no version value was found */
1024 	if (decimal_i == i) {
1025 		status = DAT_INTERNAL_ERROR;
1026 		goto exit;
1027 	}
1028 
1029 	provider_version->version.major = (DAT_UINT32)
1030 	    dat_os_strtol(str + decimal_i, NULL, 10);
1031 
1032 	/* move past '.' */
1033 	decimal_i = ++i;
1034 
1035 	for (; '\0' != str[i]; i++) {
1036 		if (DAT_TRUE != dat_os_isdigit(str[i])) {
1037 			status = DAT_INTERNAL_ERROR;
1038 			goto exit;
1039 		}
1040 	}
1041 
1042 	/* if no version value was found */
1043 	if (decimal_i == i) {
1044 		status = DAT_INTERNAL_ERROR;
1045 		goto exit;
1046 	}
1047 
1048 	provider_version->version.minor = (DAT_UINT32)
1049 	    dat_os_strtol(str + decimal_i, NULL, 10);
1050 
1051 	if ('\0' != str[i]) {
1052 		status = DAT_INTERNAL_ERROR;
1053 		goto exit;
1054 	}
1055 
1056 exit:
1057 	if (DAT_SUCCESS != status) {
1058 		if (NULL != provider_version->id) {
1059 			dat_os_free(provider_version->id,
1060 			    sizeof (char) *
1061 			    (dat_os_strlen(provider_version->id) + 1));
1062 			provider_version->id = NULL;
1063 		}
1064 	}
1065 
1066 	return (status);
1067 }
1068 
1069 
1070 /*
1071  * Function: dat_sr_get_token
1072  */
1073 
1074 DAT_RETURN
1075 dat_sr_get_token(
1076     DAT_OS_FILE *file,
1077     DAT_SR_TOKEN *token)
1078 {
1079 	if (NULL == g_token_stack) {
1080 		return (dat_sr_read_token(file, token));
1081 	} else {
1082 		DAT_SR_STACK_NODE *top;
1083 
1084 		top = g_token_stack;
1085 
1086 		*token = top->token;
1087 		g_token_stack = top->next;
1088 
1089 		dat_os_free(top, sizeof (DAT_SR_STACK_NODE));
1090 
1091 		return (DAT_SUCCESS);
1092 	}
1093 }
1094 
1095 
1096 /*
1097  * Function: dat_sr_put_token
1098  */
1099 
1100 DAT_RETURN
1101 dat_sr_put_token(
1102     DAT_OS_FILE *file,
1103 	DAT_SR_TOKEN *token) /*ARGSUSED*/
1104 {
1105 	DAT_SR_STACK_NODE *top;
1106 
1107 	if (NULL == (top = dat_os_alloc(sizeof (DAT_SR_STACK_NODE)))) {
1108 		return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY);
1109 	}
1110 
1111 	top->token = *token;
1112 	top->next = g_token_stack;
1113 	g_token_stack = top;
1114 
1115 	return (DAT_SUCCESS);
1116 }
1117 
1118 
1119 /*
1120  * Function: dat_sr_read_token
1121  */
1122 
1123 DAT_RETURN
1124 dat_sr_read_token(
1125     DAT_OS_FILE 		*file,
1126     DAT_SR_TOKEN 		*token)
1127 {
1128 	DAT_OS_FILE_POS 	pos;
1129 	DAT_OS_SIZE 		token_len;
1130 	DAT_COUNT 		num_escape_seq;
1131 	DAT_BOOLEAN 		is_quoted_str;
1132 	DAT_BOOLEAN 		is_prev_char_backslash;
1133 
1134 	/*
1135 	 * The DAT standard does not specify a maximum size for quoted strings.
1136 	 * Therefore the tokenizer must be able to read in a token of arbitrary
1137 	 * size. Instead of allocating a fixed length buffer, the tokenizer
1138 	 * first scans the input a single character at a time looking for the
1139 	 * begining and end of the token. Once the these positions are found,
1140 	 * the entire token is read into memory. By using this algorithm, the
1141 	 * implementation does not place an arbitrary maximum on the token size.
1142 	 */
1143 
1144 	token_len = 0;
1145 	num_escape_seq = 0;
1146 	is_quoted_str = DAT_FALSE;
1147 	is_prev_char_backslash = DAT_FALSE;
1148 
1149 	for (;;) {
1150 		DAT_OS_FILE_POS cur_pos;
1151 		int c;
1152 
1153 		/* if looking for start of the token */
1154 		if (0 == token_len) {
1155 			if (DAT_SUCCESS != dat_os_fgetpos(file, &cur_pos)) {
1156 				return (DAT_INTERNAL_ERROR);
1157 			}
1158 		}
1159 
1160 		c = dat_os_fgetc(file);
1161 
1162 		/* if looking for start of the token */
1163 		if (0 == token_len) {
1164 			if (EOF == c) {
1165 				token->type = DAT_SR_TOKEN_EOF;
1166 				token->value = NULL;
1167 				token->value_len = 0;
1168 				goto success;
1169 			} else if (DAT_SR_CHAR_NEWLINE == c) {
1170 				token->type = DAT_SR_TOKEN_EOR;
1171 				token->value = NULL;
1172 				token->value_len = 0;
1173 				goto success;
1174 			} else if (dat_os_isblank(c)) {
1175 				continue;
1176 			} else if (DAT_SR_CHAR_COMMENT == c) {
1177 				dat_sr_read_comment(file);
1178 				continue;
1179 			} else {
1180 				if (DAT_SR_CHAR_QUOTE == c) {
1181 					is_quoted_str = DAT_TRUE;
1182 				}
1183 
1184 				pos = cur_pos;
1185 				token_len++;
1186 			}
1187 		} else { /* looking for the end of the token */
1188 			if (EOF == c) {
1189 				break;
1190 			} else if (DAT_SR_CHAR_NEWLINE == c) {
1191 				/* put back the newline */
1192 				(void) dat_os_fungetc(file);
1193 				break;
1194 			} else if (!is_quoted_str && dat_os_isblank(c)) {
1195 				break;
1196 			} else {
1197 				token_len++;
1198 
1199 				if ((DAT_SR_CHAR_QUOTE == c) &&
1200 				    !is_prev_char_backslash) {
1201 					break;
1202 				} else if ((DAT_SR_CHAR_BACKSLASH == c) &&
1203 				    !is_prev_char_backslash) {
1204 					is_prev_char_backslash = DAT_TRUE;
1205 					num_escape_seq++;
1206 				} else {
1207 					is_prev_char_backslash = DAT_FALSE;
1208 				}
1209 			}
1210 		}
1211 	}
1212 
1213 	/* the token was a string */
1214 	if (DAT_SUCCESS != dat_os_fsetpos(file, &pos)) {
1215 		return (DAT_INTERNAL_ERROR);
1216 	}
1217 
1218 	if (is_quoted_str) {
1219 		if (DAT_SUCCESS != dat_sr_read_quoted_str(file,
1220 		    token,
1221 		    token_len,
1222 		    num_escape_seq)) {
1223 			return (DAT_INTERNAL_ERROR);
1224 		}
1225 	} else {
1226 		if (DAT_SUCCESS != dat_sr_read_str(file,
1227 		    token,
1228 		    token_len)) {
1229 			return (DAT_INTERNAL_ERROR);
1230 		}
1231 	}
1232 
1233 success:
1234 	dat_os_dbg_print(DAT_OS_DBG_TYPE_SR,
1235 	    "\n"
1236 	    "DAT Registry: token\n"
1237 	    " type  %s\n"
1238 	    " value <%s>\n"
1239 	    "\n",
1240 	    dat_sr_type_to_str(token->type),
1241 	    ((DAT_SR_TOKEN_STRING == token->type) ? token->value : ""));
1242 
1243 	return (DAT_SUCCESS);
1244 }
1245 
1246 
1247 /*
1248  * Function: dat_sr_read_str
1249  */
1250 
1251 DAT_RETURN
1252 dat_sr_read_str(
1253     DAT_OS_FILE *file,
1254     DAT_SR_TOKEN *token,
1255     DAT_OS_SIZE token_len)
1256 {
1257 	token->type = DAT_SR_TOKEN_STRING;
1258 	/* +1 for null termination */
1259 	token->value_len = sizeof (char) * (token_len + 1);
1260 	if (NULL == (token->value = dat_os_alloc(token->value_len))) {
1261 		return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY);
1262 	}
1263 
1264 	if (token_len != dat_os_fread(file, token->value, token_len)) {
1265 		dat_os_free(token->value, token->value_len);
1266 		token->value = NULL;
1267 
1268 		return (DAT_INTERNAL_ERROR);
1269 	}
1270 
1271 	token->value[token->value_len - 1] = '\0';
1272 
1273 	return (DAT_SUCCESS);
1274 }
1275 
1276 
1277 /*
1278  * Function: dat_sr_read_quoted_str
1279  */
1280 
1281 DAT_RETURN
1282 dat_sr_read_quoted_str(
1283     DAT_OS_FILE 	*file,
1284     DAT_SR_TOKEN 	*token,
1285     DAT_OS_SIZE 	token_len,
1286     DAT_COUNT 		num_escape_seq)
1287 {
1288 	DAT_OS_SIZE 	str_len;
1289 	DAT_OS_SIZE 	i;
1290 	DAT_OS_SIZE 	j;
1291 	int 		c;
1292 	DAT_RETURN 	status;
1293 	DAT_BOOLEAN 	is_prev_char_backslash;
1294 
1295 	str_len = token_len - 2; /* minus 2 " characters */
1296 	is_prev_char_backslash = DAT_FALSE;
1297 	status = DAT_SUCCESS;
1298 
1299 	token->type = DAT_SR_TOKEN_STRING;
1300 	/* +1 for null termination */
1301 	token->value_len = sizeof (char) * (str_len - num_escape_seq + 1);
1302 
1303 	if (NULL == (token->value = dat_os_alloc(token->value_len))) {
1304 		status = DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY;
1305 		goto exit;
1306 	}
1307 
1308 	/* throw away " */
1309 	if (DAT_SR_CHAR_QUOTE != dat_os_fgetc(file)) {
1310 		status = DAT_INTERNAL_ERROR;
1311 		goto exit;
1312 	}
1313 
1314 	for (i = 0, j = 0; i < str_len; i++) {
1315 		c = dat_os_fgetc(file);
1316 
1317 		if (EOF == c) {
1318 			status = DAT_INTERNAL_ERROR;
1319 			goto exit;
1320 		} else if ((DAT_SR_CHAR_BACKSLASH == c) &&
1321 		    !is_prev_char_backslash) {
1322 			is_prev_char_backslash = DAT_TRUE;
1323 		} else {
1324 			token->value[j] = c;
1325 			j++;
1326 
1327 			is_prev_char_backslash = DAT_FALSE;
1328 		}
1329 	}
1330 
1331 	/* throw away " */
1332 	if (DAT_SR_CHAR_QUOTE != dat_os_fgetc(file)) {
1333 		status = DAT_INTERNAL_ERROR;
1334 		goto exit;
1335 	}
1336 
1337 	token->value[token->value_len - 1] = '\0';
1338 
1339 exit:
1340 	if (DAT_SUCCESS != status) {
1341 		if (NULL != token->value) {
1342 			dat_os_free(token->value, token->value_len);
1343 			token->value = NULL;
1344 		}
1345 	}
1346 
1347 	return (status);
1348 }
1349 
1350 
1351 /*
1352  * Function: dat_sr_read_comment
1353  */
1354 
1355 void
1356 dat_sr_read_comment(
1357     DAT_OS_FILE *file)
1358 {
1359 	int c;
1360 
1361 	/* read up to an EOR or EOF to move past the comment */
1362 	do {
1363 		c = dat_os_fgetc(file);
1364 	} while ((DAT_SR_CHAR_NEWLINE != c) && (EOF != c));
1365 
1366 	/* put back the newline */
1367 	(void) dat_os_fungetc(file);
1368 }
1369