4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This module implements the routine to parse the configuration file.
40 #include <sys/utsname.h>
41 #include <sys/systeminfo.h>
42 #include <sys/types.h>
48 #include "picld_pluginutil.h"
49 #include "picld_pluginutil_impl.h"
51 /* error codes returned from syntax checking */
52 #define EC_SYNTAX_OK 0
53 #define EC_INSUFFICIENT_TOKEN 1
54 #define EC_SYNTAX_ERR 2
55 #define EC_UNSUPPORTED 3
57 #define EC_NODE_MISMATCH 5
60 #define EC_TABLE_MISMATCH 8
61 #define EC_ROW_MISMATCH 9
62 #define EC_ROW_EMPTY 10
67 static char *err_msg
[] = {
68 "%s: Syntax OK", /* 0 */
69 "%s::%s[line %d]: Insufficient token\n", /* 1 */
70 "%s::%s[line %d]: Syntax error\n", /* 2 */
71 "%s::%s[line %d]: Unsupported or missing version\n", /* 3 */
72 "%s::%s[line %d]: Illegal use of nodepath or namepath\n", /* 4 */
73 "%s::%s[line %d]: Node and endnode mismatch\n", /* 5 */
74 "%s::%s[line %d]: General system failure\n", /* 6 */
75 "%s: PICL error code %d\n", /* 7 */
76 "%s::%s[line %d]: Table and endtable mismatch\n", /* 8 */
77 "%s::%s[line %d]: Row and endrow mismatch\n", /* 9 */
78 "%s::%s[line %d]: Row has no entries \n" /* 10 */
81 /* token per directive */
82 #define TOK_CLASSPATH 0
83 #define TOK_NAMEPATH 1
92 #define TOK_ENDTABLE 10
96 static const char *tokens
[] = {
97 "_class", /* _CLASS:<classpath> */
98 "name", /* NAME:<namepath> */
99 "node", /* NODE <name> <class> */
100 "endnode", /* ENDNODE */
101 "prop", /* PROP <name> <type> <access_mode> <size> <value> */
102 "refprop", /* REFPROP <prop> <destnode> */
103 "version", /* VERSION <version_number> */
104 "refnode", /* REFNODE <node> <class> WITH <destnode> */
105 "verbose", /* VERBOSE <level> */
106 "table", /* TABLE <table_prop_name> */
107 "endtable", /* ENDTABLE */
109 "endrow" /* ENDROW */
112 #define BUF_SIZE_MAX 1024
115 * print error message
119 verbose_log(int pri
, const char *fmt
, ...)
124 vsyslog(pri
, fmt
, ap
);
129 * Undo the commands which have created valid node/prop handle
130 * The undo order is from last command to the first command.
133 undo_commands(cmdbuf_t
*cmds
, int last_cmd_index
)
136 command_t
*com
= cmds
->commands
;
138 for (i
= last_cmd_index
; i
>= 0; i
--) {
139 switch (com
[i
].type
) {
141 if (com
[i
].nodecmd_nodeh
== NULL
)
144 (void) ptree_delete_node(com
[i
].nodecmd_nodeh
);
145 (void) ptree_destroy_node(com
[i
].nodecmd_nodeh
);
148 if (com
[i
].refnodecmd_nodeh
== NULL
)
150 (void) ptree_delete_node(com
[i
].refnodecmd_nodeh
);
151 (void) ptree_destroy_node(com
[i
].refnodecmd_nodeh
);
154 if (com
[i
].propcmd_proph
== NULL
)
156 (void) ptree_delete_prop(com
[i
].propcmd_proph
);
157 (void) ptree_destroy_prop(com
[i
].propcmd_proph
);
160 if (com
[i
].refpropcmd_proph
== NULL
)
162 (void) ptree_delete_prop(com
[i
].refpropcmd_proph
);
163 (void) ptree_destroy_prop(com
[i
].refpropcmd_proph
);
166 if ((com
[i
].tablecmd_tblh
== NULL
) ||
167 (com
[i
].tablecmd_newtbl
== 0))
169 (void) ptree_delete_prop(com
[i
].tablecmd_tblh
);
170 (void) ptree_destroy_prop(com
[i
].tablecmd_tblh
);
193 * Get the token index from the tokens table
196 get_token_id(char *t
)
200 for (i
= 0; i
< sizeof (tokens
)/ sizeof (char *); ++i
)
201 if (strcasecmp(tokens
[i
], t
) == 0)
208 * Check the version syntax and set the version_no
210 * VERSION <version_num> -- specify the configuration version
213 parse_version(cmdbuf_t
*cmds
, char *line
)
220 /* get the VERSION directive */
221 tok
= strtok_r(line
, WHITESPACE
, &last
);
223 return (EC_INSUFFICIENT_TOKEN
);
225 /* get the version number */
226 vertok
= strtok_r(last
, WHITESPACE
, &last
);
228 return (EC_INSUFFICIENT_TOKEN
);
230 cmds
->version_no
= (float)strtod(vertok
, &endptr
);
231 if (endptr
!= (vertok
+ strlen(vertok
)))
232 return (EC_UNSUPPORTED
);
234 if (cmds
->version_no
> (float)SUPPORTED_VERSION_NUM
)
235 return (EC_UNSUPPORTED
);
237 /* check if more tokens */
238 tok
= strtok_r(last
, WHITESPACE
, &last
);
240 return (EC_SYNTAX_ERR
);
242 return (EC_SYNTAX_OK
);
249 free_path(command_t
*command
)
251 free(command
->pathcmd_name
);
255 * Check the path syntax
256 * NAMEPATH:<namepath> -- gives the anchor node
258 * CLASSPATH:<classpath> -- gives the anchor node
261 parse_path(char *line
, command_t
*command
)
267 pathtok
= strtok_r(line
, WHITESPACE
, &last
);
269 return (EC_INSUFFICIENT_TOKEN
);
271 /* check if more tokens */
272 tok
= strtok_r(last
, WHITESPACE
, &last
);
274 return (EC_SYNTAX_ERR
);
276 command
->pathcmd_name
= strdup(pathtok
);
277 if (command
->pathcmd_name
== NULL
)
280 return (EC_SYNTAX_OK
);
284 * Process the path command and return PICL node handle
287 process_path(command_t
*command
, picl_nodehdl_t
*nodeh
)
291 err
= ptree_get_node_by_path(command
->pathcmd_name
, nodeh
);
299 free_node(command_t
*command
)
301 free(command
->nodecmd_nodename
);
302 free(command
->nodecmd_classname
);
306 * Check the NODE syntax
307 * NODE <name> <class>
310 parse_node(char *line
, command_t
*command
)
317 /* get the NODE directive */
318 tok
= strtok_r(line
, WHITESPACE
, &last
);
320 return (EC_INSUFFICIENT_TOKEN
);
323 nametok
= strtok_r(last
, WHITESPACE
, &last
);
325 return (EC_INSUFFICIENT_TOKEN
);
327 classtok
= strtok_r(last
, WHITESPACE
, &last
);
328 if (classtok
== NULL
)
329 return (EC_INSUFFICIENT_TOKEN
);
331 /* check if more tokens */
332 tok
= strtok_r(last
, WHITESPACE
, &last
);
334 return (EC_SYNTAX_ERR
);
336 command
->nodecmd_nodename
= strdup(nametok
);
337 command
->nodecmd_classname
= strdup(classtok
);
338 command
->nodecmd_nodeh
= NULL
;
339 if ((command
->nodecmd_nodename
== NULL
) ||
340 (command
->nodecmd_classname
== NULL
))
343 return (EC_SYNTAX_OK
);
347 * Process the NODE command and return PICL node handle
350 process_node(command_t
*command
, picl_nodehdl_t parh
, picl_nodehdl_t
*nodeh
)
354 err
= ptree_create_and_add_node(parh
, command
->nodecmd_nodename
,
355 command
->nodecmd_classname
, nodeh
);
357 if (err
== PICL_SUCCESS
)
358 command
->nodecmd_nodeh
= *nodeh
;
364 * get the PICL property type
367 getpicltype(char *type
)
369 if (strcasecmp(type
, KEYWORD_INT_TYPE
) == 0)
370 return (PICL_PTYPE_INT
);
371 else if (strcasecmp(type
, KEYWORD_UINT_TYPE
) == 0)
372 return (PICL_PTYPE_UNSIGNED_INT
);
373 else if (strcasecmp(type
, KEYWORD_FLOAT_TYPE
) == 0)
374 return (PICL_PTYPE_FLOAT
);
375 else if (strcasecmp(type
, KEYWORD_STRING_TYPE
) == 0)
376 return (PICL_PTYPE_CHARSTRING
);
377 else if (strcasecmp(type
, KEYWORD_VOID_TYPE
) == 0)
378 return (PICL_PTYPE_VOID
);
384 * get the PICL accessmode mode
387 getpiclmode(char *mode
)
389 if (strcasecmp(mode
, KEYWORD_READ_MODE
) == 0)
391 else if (strcasecmp(mode
, KEYWORD_WRITE_MODE
) == 0)
393 else if (strcasecmp(mode
, KEYWORD_READWRITE_MODE
) == 0)
394 return (PICL_READ
|PICL_WRITE
);
400 * check if the size and value are valid given by the prop type
403 validate_size_and_cvt_val(void *outbuf
, size_t size
, int type
, char *val
)
418 case PICL_PTYPE_CHARSTRING
:
422 case sizeof (int64_t):
423 llval
= strtoll(val
, &endptr
, 0);
424 if (endptr
!= (val
+ strlen(val
)))
425 return (EC_SYNTAX_ERR
);
426 (void) memcpy(outbuf
, &llval
, size
);
428 case sizeof (int32_t):
429 intval
= strtol(val
, &endptr
, 0);
430 if (endptr
!= (val
+ strlen(val
)))
431 return (EC_SYNTAX_ERR
);
432 (void) memcpy(outbuf
, &intval
, size
);
434 case sizeof (int16_t):
435 sval
= (int16_t)strtol(val
, &endptr
, 0);
436 if (endptr
!= (val
+ strlen(val
)))
437 return (EC_SYNTAX_ERR
);
438 (void) memcpy(outbuf
, &sval
, size
);
440 case sizeof (int8_t):
441 cval
= (int8_t)strtol(val
, &endptr
, 0);
442 if (endptr
!= (val
+ strlen(val
)))
443 return (EC_SYNTAX_ERR
);
444 (void) memcpy(outbuf
, &cval
, size
);
446 default: /* invalid size */
447 return (EC_SYNTAX_ERR
);
450 case PICL_PTYPE_UNSIGNED_INT
:
452 case sizeof (uint64_t):
453 ullval
= strtoull(val
, &endptr
, 0);
454 if (endptr
!= (val
+ strlen(val
)))
455 return (EC_SYNTAX_ERR
);
456 (void) memcpy(outbuf
, &ullval
, size
);
458 case sizeof (uint32_t):
459 uintval
= strtoul(val
, &endptr
, 0);
460 if (endptr
!= (val
+ strlen(val
)))
461 return (EC_SYNTAX_ERR
);
462 (void) memcpy(outbuf
, &uintval
, size
);
464 case sizeof (uint16_t):
465 usval
= (uint16_t)strtoul(val
, &endptr
, 0);
466 if (endptr
!= (val
+ strlen(val
)))
467 return (EC_SYNTAX_ERR
);
468 (void) memcpy(outbuf
, &usval
, size
);
470 case sizeof (uint8_t):
471 ucval
= (uint8_t)strtoul(val
, &endptr
, 0);
472 if (endptr
!= (val
+ strlen(val
)))
473 return (EC_SYNTAX_ERR
);
474 (void) memcpy(outbuf
, &ucval
, size
);
476 default: /* invalid size */
477 return (EC_SYNTAX_ERR
);
480 case PICL_PTYPE_FLOAT
:
482 case sizeof (double):
483 dval
= strtod(val
, &endptr
);
484 if (endptr
!= (val
+ strlen(val
)))
485 return (EC_SYNTAX_ERR
);
486 (void) memcpy(outbuf
, &dval
, size
);
489 fval
= (float)strtod(val
, &endptr
);
490 if (endptr
!= (val
+ strlen(val
)))
491 return (EC_SYNTAX_ERR
);
492 (void) memcpy(outbuf
, &fval
, size
);
494 default: /* invalid size */
495 return (EC_SYNTAX_ERR
);
498 default: /* not supported type */
499 return (EC_SYNTAX_ERR
);
502 return (EC_SYNTAX_OK
);
509 free_prop(command_t
*command
)
511 free(command
->propcmd_pname
);
512 if (command
->propcmd_type
!= PICL_PTYPE_VOID
)
513 free(command
->propcmd_valbuf
);
517 * return the string token in two double quotes
518 * The current version won't support multiple-line string
521 get_string_token(char *line
, char **valtok
)
523 char *optr
; /* ptr to the open quote */
524 char *cptr
; /* ptr to the close quote */
529 return (EC_INSUFFICIENT_TOKEN
);
531 /* skipping leading white spaces */
533 while ((*optr
== ' ') || (*optr
== '\t') || (*optr
== '\n'))
536 /* reach end of string */
538 return (EC_INSUFFICIENT_TOKEN
);
540 /* it's not an open double quote */
542 return (EC_SYNTAX_ERR
);
544 /* skipping ending white spaces */
545 cptr
= line
+ strlen(line
) - 1;
546 while ((*cptr
== ' ') || (*cptr
== '\t') || (*cptr
== '\n'))
549 /* it's not an close double quote */
551 return (EC_SYNTAX_ERR
);
553 /* close double quote is missing */
555 return (EC_SYNTAX_ERR
);
557 /* replace close qoute by null to make a string */
559 /* move the begin pointer to the first char of string */
562 tmpbuf
= malloc(strlen(optr
) + 1);
566 for (ptr
= tmpbuf
; *optr
!= '\0'; ptr
++, optr
++) {
567 /* if escape character, go to next character */
570 if (*optr
== '\0') { /* for exampe, "xxx\" */
572 return (EC_SYNTAX_ERR
);
580 return (EC_SYNTAX_OK
);
584 * Check the PROP syntax
585 * PROP <name> <type> <access_mode> [<size> <value>]
586 * supported prop types: void, int, uint, float, string
587 * supported prop access_modes: r, w, rw
588 * For void prop, <size> and <value> are not needed
589 * For string prop, <size> will be set the actual string size if <size>
593 parse_prop(char *line
, command_t
*command
)
605 /* get the PROP directive */
606 tok
= strtok_r(line
, WHITESPACE
, &last
);
608 return (EC_INSUFFICIENT_TOKEN
);
610 /* get the property name */
611 pnametok
= strtok_r(last
, WHITESPACE
, &last
);
612 if (pnametok
== NULL
)
613 return (EC_INSUFFICIENT_TOKEN
);
616 tok
= strtok_r(last
, WHITESPACE
, &last
);
618 return (EC_INSUFFICIENT_TOKEN
);
620 if ((typetok
= getpicltype(tok
)) < 0)
621 return (EC_SYNTAX_ERR
);
624 tok
= strtok_r(last
, WHITESPACE
, &last
);
626 return (EC_INSUFFICIENT_TOKEN
);
628 if ((modetok
= getpiclmode(tok
)) < 0)
629 return (EC_SYNTAX_ERR
);
631 if (typetok
== PICL_PTYPE_VOID
) {
632 /* ignore the rest of arguments */
633 command
->propcmd_valbuf
= NULL
;
634 command
->propcmd_pname
= strdup(pnametok
);
635 if (command
->propcmd_pname
== NULL
)
637 command
->propcmd_type
= typetok
;
638 command
->propcmd_accessmode
= modetok
;
639 command
->propcmd_size
= 0;
640 command
->propcmd_proph
= NULL
;
641 return (EC_SYNTAX_OK
);
645 tok
= strtok_r(last
, WHITESPACE
, &last
);
647 return (EC_INSUFFICIENT_TOKEN
);
649 sizetok
= (size_t)strtol(tok
, &endptr
, 0);
650 if (endptr
!= (tok
+ strlen(tok
)))
651 return (EC_SYNTAX_ERR
);
654 if (typetok
== PICL_PTYPE_CHARSTRING
) {
655 err
= get_string_token(last
, &valtok
);
656 if (err
!= EC_SYNTAX_OK
)
659 sizetok
= strlen(valtok
) + 1;
660 command
->propcmd_valbuf
= valtok
;
662 valtok
= strtok_r(last
, WHITESPACE
, &last
);
664 return (EC_INSUFFICIENT_TOKEN
);
665 /* check if more tokens */
666 tok
= strtok_r(last
, WHITESPACE
, &last
);
668 return (EC_SYNTAX_ERR
);
669 command
->propcmd_valbuf
= malloc(sizetok
);
670 if (command
->propcmd_valbuf
== NULL
)
672 err
= validate_size_and_cvt_val(command
->propcmd_valbuf
,
673 sizetok
, typetok
, valtok
);
674 if (err
!= EC_SYNTAX_OK
) {
675 free(command
->propcmd_valbuf
);
680 command
->propcmd_pname
= strdup(pnametok
);
681 if (command
->propcmd_pname
== NULL
)
683 command
->propcmd_type
= typetok
;
684 command
->propcmd_accessmode
= modetok
;
685 command
->propcmd_size
= sizetok
;
686 command
->propcmd_proph
= NULL
;
687 return (EC_SYNTAX_OK
);
691 * Add a property to the row, the row gets added to the node at endrow
694 add_proph_to_row(command_t
*command
, picl_prophdl_t proph
)
696 if (command
->rowcmd_index
>= command
->rowcmd_nproph
)
697 return (PICL_FAILURE
);
698 command
->rowcmd_prophs
[command
->rowcmd_index
] = proph
;
699 command
->rowcmd_index
++;
700 return (PICL_SUCCESS
);
704 * Process the PROP command and add the specified property under the given
708 process_prop(cmdbuf_t
*cmds
, command_t
*command
, picl_nodehdl_t nodeh
)
710 ptree_propinfo_t propinfo
;
711 picl_prophdl_t proph
;
714 /* prop in discarded row */
715 if (cmds
->inside_row_block
&&
716 cmds
->commands
[cmds
->current_row
].rowcmd_nproph
== 0)
717 return (PICL_SUCCESS
);
719 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
720 command
->propcmd_type
, command
->propcmd_accessmode
,
721 command
->propcmd_size
, command
->propcmd_pname
, NULL
,
724 if (err
!= PICL_SUCCESS
)
727 err
= ptree_create_prop(&propinfo
, command
->propcmd_valbuf
, &proph
);
729 if (err
!= PICL_SUCCESS
)
732 command
->propcmd_proph
= proph
;
734 if (cmds
->inside_row_block
) {
735 err
= add_proph_to_row(&cmds
->commands
[cmds
->current_row
],
738 err
= ptree_add_prop(nodeh
, proph
);
748 free_refnode(command_t
*command
)
750 free(command
->refnodecmd_name
);
751 free(command
->refnodecmd_class
);
752 free(command
->refnodecmd_dstnode
);
756 * Check the REFNODE syntax
758 * REFNODE <name> <class> with <destnode> -- if <destnode> exists,
759 * create node with nodename <name> and piclclass <class>
762 parse_refnode(char *line
, command_t
*command
)
770 /* get the directive */
771 tok
= strtok_r(line
, WHITESPACE
, &last
);
773 return (EC_INSUFFICIENT_TOKEN
);
775 /* get the nodename */
776 nodenm
= strtok_r(last
, WHITESPACE
, &last
);
778 return (EC_INSUFFICIENT_TOKEN
);
781 classnm
= strtok_r(last
, WHITESPACE
, &last
);
783 return (EC_INSUFFICIENT_TOKEN
);
785 /* get the WITH keyword */
786 tok
= strtok_r(last
, WHITESPACE
, &last
);
788 return (EC_INSUFFICIENT_TOKEN
);
790 if (strcasecmp(tok
, KEYWORD_WITH_STR
) != 0)
791 return (EC_SYNTAX_ERR
);
793 /* get the dst node */
794 dsttok
= strtok_r(last
, WHITESPACE
, &last
);
796 return (EC_INSUFFICIENT_TOKEN
);
798 /* check if more tokens */
799 tok
= strtok_r(last
, WHITESPACE
, &last
);
801 return (EC_SYNTAX_ERR
);
803 command
->refnodecmd_name
= strdup(nodenm
);
804 command
->refnodecmd_class
= strdup(classnm
);
805 command
->refnodecmd_dstnode
= strdup(dsttok
);
806 command
->refnodecmd_nodeh
= NULL
;
807 if ((command
->refnodecmd_name
== NULL
) ||
808 (command
->refnodecmd_class
== NULL
) ||
809 (command
->refnodecmd_dstnode
== NULL
))
812 return (EC_SYNTAX_OK
);
816 * Process the REFNODE command
819 process_refnode(command_t
*command
, picl_nodehdl_t parh
)
822 picl_nodehdl_t nodeh
;
825 if ((ptree_get_node_by_path(command
->refnodecmd_dstnode
,
826 &dsth
) == PICL_SUCCESS
)) {
827 err
= ptree_create_and_add_node(parh
, command
->refnodecmd_name
,
828 command
->refnodecmd_class
, &nodeh
);
829 if (err
== PICL_SUCCESS
)
830 command
->refnodecmd_nodeh
= nodeh
;
835 return (PICL_SUCCESS
);
842 free_refprop(command_t
*command
)
844 free(command
->refpropcmd_pname
);
845 free(command
->refpropcmd_dstnode
);
849 * Check the REFPROP syntax
851 * REFPROP <prop> <destnode> -- creates a reference property to <destnode>
854 parse_refprop(char *line
, command_t
*command
)
861 /* get the REFPROP directive */
862 tok
= strtok_r(line
, WHITESPACE
, &last
);
864 return (EC_INSUFFICIENT_TOKEN
);
866 /* get the propname */
867 pnametok
= strtok_r(last
, WHITESPACE
, &last
);
868 if (pnametok
== NULL
)
869 return (EC_INSUFFICIENT_TOKEN
);
871 dsttok
= strtok_r(last
, WHITESPACE
, &last
);
873 return (EC_INSUFFICIENT_TOKEN
);
875 /* check if more tokens */
876 tok
= strtok_r(last
, WHITESPACE
, &last
);
878 return (EC_SYNTAX_ERR
);
880 command
->refpropcmd_pname
= strdup(pnametok
);
881 command
->refpropcmd_dstnode
= strdup(dsttok
);
882 command
->refpropcmd_proph
= NULL
;
883 if ((command
->refpropcmd_pname
== NULL
) ||
884 (command
->refpropcmd_dstnode
== NULL
))
887 return (EC_SYNTAX_OK
);
891 * Process the REFPROP command
894 process_refprop(cmdbuf_t
*cmds
, command_t
*command
, picl_nodehdl_t nodeh
)
898 picl_prophdl_t proph
;
899 ptree_propinfo_t propinfo
;
901 /* refprop in discarded row */
902 if (cmds
->inside_row_block
&&
903 cmds
->commands
[cmds
->current_row
].rowcmd_nproph
== 0)
904 return (PICL_SUCCESS
);
906 /* try finding the refprop's dstnode */
907 err
= ptree_get_node_by_path(command
->refpropcmd_dstnode
, &dsth
);
909 /* dstnode doesn't exist, return */
910 if (err
!= PICL_SUCCESS
)
913 /* dstnode exists, try adding the refprop to nodeh */
914 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
915 PICL_PTYPE_REFERENCE
, PICL_READ
, sizeof (picl_nodehdl_t
),
916 command
->refpropcmd_pname
, NULL
, NULL
);
918 if (err
!= PICL_SUCCESS
)
921 err
= ptree_create_prop(&propinfo
, &dsth
, &proph
);
923 if (err
!= PICL_SUCCESS
)
926 command
->refpropcmd_proph
= proph
;
928 if (cmds
->inside_row_block
) {
929 err
= add_proph_to_row(&cmds
->commands
[cmds
->current_row
],
932 err
= ptree_add_prop(nodeh
, proph
);
942 free_table(command_t
*command
)
944 if (command
->tablecmd_tname
)
945 free(command
->tablecmd_tname
);
949 * Check the TABLE syntax
950 * TABLE <table_prop_name>
954 parse_table(char *line
, command_t
*command
)
957 char *tnametok
= NULL
;
960 /* get the TABLE directive */
961 tok
= strtok_r(line
, WHITESPACE
, &last
);
963 return (EC_INSUFFICIENT_TOKEN
);
965 /* get the property name */
966 tnametok
= strtok_r(last
, WHITESPACE
, &last
);
967 if (tnametok
== NULL
)
968 return (EC_INSUFFICIENT_TOKEN
);
970 command
->tablecmd_tname
= strdup(tnametok
);
971 if (command
->tablecmd_tname
== NULL
)
974 command
->tablecmd_newtbl
= 0;
975 command
->tablecmd_tblh
= NULL
;
977 return (EC_SYNTAX_OK
);
981 * Process the TABLE command and add the specified property under the given
985 process_table(command_t
*command
, picl_nodehdl_t nodeh
)
989 picl_prophdl_t proph
;
990 ptree_propinfo_t propinfo
;
992 /* find if table already exists */
993 err
= ptree_get_prop_by_name(nodeh
, command
->tablecmd_tname
, &tblh
);
994 if (err
== PICL_SUCCESS
) {
995 err
= ptree_get_propinfo(tblh
, &propinfo
);
996 if (err
!= PICL_SUCCESS
)
998 /* prop with the same name as table? */
999 if (propinfo
.piclinfo
.type
!= PICL_PTYPE_TABLE
)
1000 return (EC_SYNTAX_ERR
);
1001 command
->tablecmd_newtbl
= 0;
1002 command
->tablecmd_tblh
= tblh
;
1003 return (PICL_SUCCESS
);
1006 /* init and create a new table */
1007 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
1008 PICL_PTYPE_TABLE
, PICL_READ
|PICL_WRITE
,
1009 sizeof (picl_prophdl_t
), command
->tablecmd_tname
, NULL
, NULL
);
1010 if (err
!= PICL_SUCCESS
)
1013 err
= ptree_create_table(&tblh
);
1014 if (err
!= PICL_SUCCESS
)
1017 command
->tablecmd_newtbl
= 1;
1018 command
->tablecmd_tblh
= tblh
;
1020 err
= ptree_create_prop(&propinfo
, &tblh
, &proph
);
1021 if (err
!= PICL_SUCCESS
)
1024 err
= ptree_add_prop(nodeh
, proph
);
1030 * Process the ROW command by alloc'ing space to store the prop handles for
1031 * the whole row. The number of props in the row gets known while parsing.
1034 process_row(command_t
*command
)
1036 command
->rowcmd_index
= 0;
1037 command
->rowcmd_prophs
=
1038 malloc(command
->rowcmd_nproph
* sizeof (picl_prophdl_t
));
1040 if (command
->rowcmd_prophs
== NULL
)
1041 return (PICL_FAILURE
);
1043 return (PICL_SUCCESS
);
1047 * Process the ENDROW command. If a valid row, add the row to the ptree.
1050 process_endrow(cmdbuf_t
*cmds
)
1054 command_t
*curr_row
;
1056 curr_row
= &cmds
->commands
[cmds
->current_row
];
1058 /* if nproph == 0, some row prop had problems, don't add */
1059 if (curr_row
->rowcmd_nproph
== 0) {
1060 for (i
= 0; i
< curr_row
->rowcmd_index
; i
++) {
1061 (void) ptree_delete_prop(curr_row
->rowcmd_prophs
[i
]);
1062 (void) ptree_destroy_prop(curr_row
->rowcmd_prophs
[i
]);
1066 err
= ptree_add_row_to_table(
1067 cmds
->commands
[cmds
->current_tbl
].tablecmd_tblh
,
1068 curr_row
->rowcmd_nproph
,
1069 curr_row
->rowcmd_prophs
);
1071 /* let go the space alloc'd in process_row */
1072 free(curr_row
->rowcmd_prophs
);
1073 curr_row
->rowcmd_prophs
= NULL
;
1079 * Check the VERBOSE syntax
1083 parse_verbose(cmdbuf_t
*cmds
, char *line
, command_t
*command
)
1091 /* get the VERBOSE directive */
1092 tok
= strtok_r(line
, WHITESPACE
, &last
);
1094 return (EC_INSUFFICIENT_TOKEN
);
1096 /* get verbose level */
1097 level
= strtok_r(last
, WHITESPACE
, &last
);
1099 return (EC_INSUFFICIENT_TOKEN
);
1100 verbose_level
= strtol(level
, &endptr
, 0);
1101 if (endptr
!= (level
+ strlen(level
)))
1102 return (EC_SYNTAX_ERR
);
1104 /* check if more tokens */
1105 tok
= strtok_r(last
, WHITESPACE
, &last
);
1107 return (EC_SYNTAX_ERR
);
1109 cmds
->verbose
= verbose_level
;
1110 command
->verbosecmd_level
= verbose_level
;
1112 return (EC_SYNTAX_OK
);
1116 * Process the VERBOSE command to set the verbose level
1119 process_verbose(cmdbuf_t
*cmds
, command_t
*command
)
1121 cmds
->verbose
= command
->verbosecmd_level
;
1122 return (PICL_SUCCESS
);
1126 * parse and tokenize the line
1129 parse_and_tokenize_line(cmdbuf_t
*cmds
, char *buf
, command_t
*command
)
1131 char rec
[RECORD_SIZE_MAX
];
1137 (void) strcpy(rec
, buf
);
1138 tok
= strtok_r(rec
, RECORD_WHITESPACE
, &last
);
1140 return (EC_INSUFFICIENT_TOKEN
);
1142 id
= get_token_id(tok
);
1144 (void) strcpy(rec
, buf
);
1148 err
= parse_version(cmds
, rec
);
1152 if (cmds
->inside_node_block
!= 0)
1153 return (EC_PATH_ERR
);
1155 err
= parse_path(rec
, command
);
1156 if (err
!= EC_SYNTAX_OK
)
1160 /* Check for NODE outside of TABLE, ROW */
1161 if ((cmds
->inside_table_block
!= 0) ||
1162 (cmds
->inside_row_block
!= 0))
1163 return (EC_SYNTAX_ERR
);
1164 err
= parse_node(rec
, command
);
1165 if (err
!= EC_SYNTAX_OK
)
1167 cmds
->inside_node_block
++;
1170 /* Check for ENDNODE outside of TABLE, ROW */
1171 if ((cmds
->inside_table_block
!= 0) ||
1172 (cmds
->inside_row_block
!= 0))
1173 return (EC_SYNTAX_ERR
);
1174 cmds
->inside_node_block
--;
1178 /* Check if inside TABLE, but not in ROW */
1179 if ((cmds
->inside_table_block
!= 0) &&
1180 (cmds
->inside_row_block
== 0))
1181 return (EC_SYNTAX_ERR
);
1182 err
= parse_prop(rec
, command
);
1183 if (err
!= EC_SYNTAX_OK
)
1185 if (cmds
->inside_row_block
) {
1186 cmds
->commands
[cmds
->current_row
].rowcmd_nproph
++;
1190 err
= parse_refnode(rec
, command
);
1191 if (err
!= EC_SYNTAX_OK
)
1195 /* Check if inside TABLE, but not in ROW */
1196 if ((cmds
->inside_table_block
!= 0) &&
1197 (cmds
->inside_row_block
== 0))
1198 return (EC_SYNTAX_ERR
);
1199 err
= parse_refprop(rec
, command
);
1200 if (err
!= EC_SYNTAX_OK
)
1202 if (cmds
->inside_row_block
) {
1203 cmds
->commands
[cmds
->current_row
].rowcmd_nproph
++;
1207 /* Table/Row supported in version 1.1 and above */
1208 if (cmds
->version_no
< (float)SUPPORTED_VERSION_NUM
)
1209 return (EC_UNSUPPORTED
);
1210 if (cmds
->inside_table_block
!= 0)
1211 return (EC_SYNTAX_ERR
);
1212 err
= parse_table(rec
, command
);
1213 if (err
!= EC_SYNTAX_OK
)
1215 cmds
->inside_table_block
= 1;
1218 /* Check for ENDTABLE before TABLE */
1219 if (cmds
->inside_table_block
== 0)
1220 return (EC_SYNTAX_ERR
);
1222 cmds
->inside_table_block
= 0;
1226 /* Check for ROW outside of TABLE, ROW inside ROW */
1227 if ((cmds
->inside_table_block
== 0) ||
1228 (cmds
->inside_row_block
!= 0))
1229 return (EC_SYNTAX_ERR
);
1230 cmds
->inside_row_block
= 1;
1233 /* Check for ENDROW outside of TABLE, ENDROW before ROW */
1234 if ((cmds
->inside_table_block
== 0) ||
1235 (cmds
->inside_row_block
== 0))
1236 return (EC_SYNTAX_ERR
);
1240 cmds
->inside_row_block
= 0;
1242 /* error if row is empty */
1243 if (cmds
->commands
[cmds
->current_row
].rowcmd_nproph
<= 0)
1244 return (EC_ROW_EMPTY
);
1247 err
= parse_verbose(cmds
, rec
, command
);
1248 if (err
!= EC_SYNTAX_OK
)
1251 default: /* unsupported command */
1252 return (EC_SYNTAX_ERR
);
1256 return (EC_SYNTAX_OK
);
1260 * Check the syntax and save the tokens in the commands buffer
1263 check_line_syntax(cmdbuf_t
*cmds
, char *buf
)
1268 (void) memset(&command
, 0, sizeof (command_t
));
1269 err
= parse_and_tokenize_line(cmds
, buf
, &command
);
1270 if (err
!= EC_SYNTAX_OK
)
1274 * don't add and count version command in the command buffer
1276 if (command
.type
== TOK_VERSION
)
1277 return (EC_SYNTAX_OK
);
1280 * check if the commands buffer has been filled
1281 * If it is full, reallocate the buffer.
1283 if (cmds
->count
== cmds
->allocated
) {
1284 cmds
->commands
= realloc(cmds
->commands
,
1285 sizeof (command_t
) * (cmds
->allocated
+ PER_ALLOC_COUNT
));
1286 if (cmds
->commands
== NULL
)
1287 return (EC_FAILURE
);
1288 cmds
->allocated
+= PER_ALLOC_COUNT
;
1291 cmds
->commands
[cmds
->count
] = command
; /* copy */
1294 * make a note of the row/endrow command, to keep track of # of props
1296 if (command
.type
== TOK_ROW
)
1297 cmds
->current_row
= cmds
->count
;
1299 if (command
.type
== TOK_ENDROW
)
1300 cmds
->current_row
= 0;
1304 return (EC_SYNTAX_OK
);
1308 * get the line control information
1309 * return 1 if it's the line control information, else return 0
1312 get_line_control_info(char *buf
, uint32_t *linenum
, char *filename
)
1320 /* skip # and get next string */
1321 ptr
= strtok_r(buf
+ 1, WHITESPACE
, &last
);
1326 num
= strtoul(ptr
, &endptr
, 0);
1329 * It's not the line control information
1331 if (endptr
!= (ptr
+ strlen(ptr
))) {
1339 /* get the beginning double quote */
1340 last
= strchr(last
, '"');
1346 /* get the ending double quote */
1347 fname
= strtok_r(last
, DOUBLE_QUOTE
, &last
);
1352 (void) strlcpy(filename
, fname
, PATH_MAX
);
1357 * check the syntax of the configuration file
1360 check_conffile_syntax(cmdbuf_t
*cmds
, FILE *fp
)
1362 char lbuf
[RECORD_SIZE_MAX
];
1363 char buf
[RECORD_SIZE_MAX
];
1365 char cppfile
[PATH_MAX
] = "";
1366 int err
= EC_SYNTAX_OK
;
1369 while (fgets(buf
, sizeof (buf
), fp
) != NULL
) {
1371 * get cpp line control information, if any
1373 if (buf
[0] == '#') {
1374 if (!get_line_control_info(buf
, &linenum
, cppfile
))
1381 * skip line whose first char is a newline char
1383 if (buf
[0] == '\n') {
1387 if (err
== EC_SYNTAX_OK
)
1388 (void) strlcpy(lbuf
, buf
, RECORD_SIZE_MAX
);
1389 else if (strlcat(lbuf
, buf
, RECORD_SIZE_MAX
) >=
1390 RECORD_SIZE_MAX
) { /* buffer overflow */
1395 err
= check_line_syntax(cmds
, lbuf
);
1396 if ((err
!= EC_INSUFFICIENT_TOKEN
) && (err
!= EC_SYNTAX_OK
))
1400 if (err
!= EC_SYNTAX_OK
) {
1401 if (cmds
->verbose
) {
1402 verbose_log(LOG_ERR
, err_msg
[err
],
1403 cmds
->fname
, cppfile
, linenum
);
1409 * check if the version has been set
1411 if (cmds
->version_no
> (float)SUPPORTED_VERSION_NUM
) {
1412 if (cmds
->verbose
) {
1413 verbose_log(LOG_ERR
, err_msg
[EC_UNSUPPORTED
],
1414 cmds
->fname
, cppfile
, linenum
);
1416 return (EC_UNSUPPORTED
);
1420 * check if node and endnode command mismatch
1422 if (cmds
->inside_node_block
!= 0) {
1423 if (cmds
->verbose
) {
1424 verbose_log(LOG_ERR
, err_msg
[EC_NODE_MISMATCH
],
1425 cmds
->fname
, cppfile
, linenum
);
1427 return (EC_NODE_MISMATCH
);
1431 * check if row and endrow command mismatch
1433 if (cmds
->inside_row_block
!= 0) {
1434 if (cmds
->verbose
) {
1435 verbose_log(LOG_ERR
, err_msg
[EC_ROW_MISMATCH
],
1436 cmds
->fname
, cppfile
, linenum
);
1438 return (EC_ROW_MISMATCH
);
1442 * check if table and endtable command mismatch
1444 if (cmds
->inside_table_block
!= 0) {
1445 if (cmds
->verbose
) {
1446 verbose_log(LOG_ERR
, err_msg
[EC_TABLE_MISMATCH
],
1447 cmds
->fname
, cppfile
, linenum
);
1449 return (EC_TABLE_MISMATCH
);
1452 return (EC_SYNTAX_OK
);
1456 * If classpath/namepath given is not found in the picl tree,
1457 * skip the whole blocks until next valid classpath or namepath
1460 skip_to_next_valid_path(cmdbuf_t
*cmds
, int starting_index
,
1461 picl_nodehdl_t
*parent
, int *last_processed_index
)
1466 for (index
= starting_index
; index
< cmds
->count
; ++index
) {
1467 switch (cmds
->commands
[index
].type
) {
1470 err
= process_path(&cmds
->commands
[index
], parent
);
1471 if (err
== PICL_SUCCESS
) {
1472 *last_processed_index
= index
;
1476 /* skipped this line */
1481 /* reach last command */
1482 *last_processed_index
= cmds
->count
- 1;
1486 * Process the command buffer and return last command index and the new head of
1490 process_commands(cmdbuf_t
*cmds
, int starting_index
, picl_nodehdl_t parent
,
1491 int *last_processed_index
)
1495 picl_nodehdl_t rooth
;
1496 picl_nodehdl_t nodeh
;
1497 command_t
*commands
= cmds
->commands
;
1499 for (index
= starting_index
; index
< cmds
->count
; ++index
) {
1500 switch (commands
[index
].type
) {
1503 err
= process_path(&commands
[index
], &rooth
);
1504 if (err
!= PICL_SUCCESS
) {
1506 (void) skip_to_next_valid_path(cmds
, index
,
1512 err
= process_node(&commands
[index
], parent
, &nodeh
);
1513 if (err
== PICL_SUCCESS
) {
1515 err
= process_commands(cmds
, index
, nodeh
,
1520 *last_processed_index
= index
;
1521 return (PICL_SUCCESS
);
1523 err
= process_prop(cmds
, &commands
[index
], parent
);
1526 err
= process_refprop(cmds
, &commands
[index
], parent
);
1527 /* no reference node */
1528 if (err
== PICL_NOTNODE
) {
1529 err
= PICL_SUCCESS
; /* discard prop */
1530 /* discard row by setting nproph = 0 */
1531 if (cmds
->inside_row_block
)
1532 cmds
->commands
[cmds
->current_row
]
1537 err
= process_refnode(&commands
[index
], parent
);
1540 cmds
->inside_table_block
= 1;
1541 err
= process_table(&commands
[index
], parent
);
1542 cmds
->current_tbl
= index
;
1545 cmds
->inside_table_block
= 0;
1546 cmds
->current_tbl
= 0;
1549 cmds
->inside_row_block
= 1;
1550 err
= process_row(&commands
[index
]);
1551 cmds
->current_row
= index
;
1554 err
= process_endrow(cmds
);
1555 cmds
->inside_row_block
= 0;
1556 cmds
->current_row
= 0;
1559 err
= process_verbose(cmds
, &commands
[index
]);
1561 default: /* won't reach here */
1566 if ((err
!= PICL_SUCCESS
) && (err
!= PICL_PROPEXISTS
)) {
1567 *last_processed_index
= index
;
1572 /* reach last command */
1573 *last_processed_index
= cmds
->count
- 1;
1574 return (PICL_SUCCESS
);
1578 * clean up the commands buffer
1581 clean_up(cmdbuf_t
*cmds
)
1585 for (cmd_index
= 0; cmd_index
< cmds
->count
; cmd_index
++) {
1586 switch (cmds
->commands
[cmd_index
].type
) {
1589 free_path(&cmds
->commands
[cmd_index
]);
1592 free_node(&cmds
->commands
[cmd_index
]);
1595 free_prop(&cmds
->commands
[cmd_index
]);
1598 free_refprop(&cmds
->commands
[cmd_index
]);
1601 free_refnode(&cmds
->commands
[cmd_index
]);
1604 free_table(&cmds
->commands
[cmd_index
]);
1616 free(cmds
->commands
);
1620 * Parse the configuration file and create nodes/properties under nh
1622 * It checks the syntax first. If there is any syntax error,
1623 * it returns 1 and won't continue processing the file to add nodes or props.
1625 * If any error happens during command processing, all nodes
1626 * and properties just created will be deleted, i.e. undo
1627 * commands which have been processed. It returns 1.
1629 * If success, return 0.
1632 picld_pluginutil_parse_config_file(picl_nodehdl_t nh
, const char *filename
)
1635 int last_processed_index
;
1639 /* set correct locale for use inside pluginutil */
1640 setlocale(LC_ALL
, "C");
1643 * Initialize the command buffer
1646 cmds
= malloc(sizeof (*cmds
));
1648 setlocale(LC_ALL
, "");
1652 memset(cmds
, 0, sizeof (cmdbuf_t
));
1654 cmds
->fname
= filename
;
1656 ifp
= fopen(filename
, "r");
1658 setlocale(LC_ALL
, "");
1664 * check the syntax of the configuration file
1666 err
= check_conffile_syntax(cmds
, ifp
);
1670 if (err
!= EC_SYNTAX_OK
) {
1673 setlocale(LC_ALL
, "");
1678 * Process the commands
1680 err
= process_commands(cmds
, STARTING_INDEX
, nh
, &last_processed_index
);
1683 * If any PICL error, remove the newly created node/prop
1684 * handles from the PICL tree.
1686 if (err
!= PICL_SUCCESS
) {
1687 undo_commands(cmds
, last_processed_index
);
1689 verbose_log(LOG_ERR
, err_msg
[EC_PICL_ERR
], filename
,
1696 /* reset the locale */
1697 setlocale(LC_ALL
, "");
1699 return ((err
== PICL_SUCCESS
) ? 0 : 1);