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
== 0)
144 (void) ptree_delete_node(com
[i
].nodecmd_nodeh
);
145 (void) ptree_destroy_node(com
[i
].nodecmd_nodeh
);
148 if (com
[i
].refnodecmd_nodeh
== 0)
150 (void) ptree_delete_node(com
[i
].refnodecmd_nodeh
);
151 (void) ptree_destroy_node(com
[i
].refnodecmd_nodeh
);
154 if (com
[i
].propcmd_proph
== 0)
156 (void) ptree_delete_prop(com
[i
].propcmd_proph
);
157 (void) ptree_destroy_prop(com
[i
].propcmd_proph
);
160 if (com
[i
].refpropcmd_proph
== 0)
162 (void) ptree_delete_prop(com
[i
].refpropcmd_proph
);
163 (void) ptree_destroy_prop(com
[i
].refpropcmd_proph
);
166 if ((com
[i
].tablecmd_tblh
== 0) ||
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
= 0;
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
= 0;
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
= 0;
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
= 0;
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
= 0;
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 free(command
->tablecmd_tname
);
948 * Check the TABLE syntax
949 * TABLE <table_prop_name>
953 parse_table(char *line
, command_t
*command
)
956 char *tnametok
= NULL
;
959 /* get the TABLE directive */
960 tok
= strtok_r(line
, WHITESPACE
, &last
);
962 return (EC_INSUFFICIENT_TOKEN
);
964 /* get the property name */
965 tnametok
= strtok_r(last
, WHITESPACE
, &last
);
966 if (tnametok
== NULL
)
967 return (EC_INSUFFICIENT_TOKEN
);
969 command
->tablecmd_tname
= strdup(tnametok
);
970 if (command
->tablecmd_tname
== NULL
)
973 command
->tablecmd_newtbl
= 0;
974 command
->tablecmd_tblh
= 0;
976 return (EC_SYNTAX_OK
);
980 * Process the TABLE command and add the specified property under the given
984 process_table(command_t
*command
, picl_nodehdl_t nodeh
)
988 picl_prophdl_t proph
;
989 ptree_propinfo_t propinfo
;
991 /* find if table already exists */
992 err
= ptree_get_prop_by_name(nodeh
, command
->tablecmd_tname
, &tblh
);
993 if (err
== PICL_SUCCESS
) {
994 err
= ptree_get_propinfo(tblh
, &propinfo
);
995 if (err
!= PICL_SUCCESS
)
997 /* prop with the same name as table? */
998 if (propinfo
.piclinfo
.type
!= PICL_PTYPE_TABLE
)
999 return (EC_SYNTAX_ERR
);
1000 command
->tablecmd_newtbl
= 0;
1001 command
->tablecmd_tblh
= tblh
;
1002 return (PICL_SUCCESS
);
1005 /* init and create a new table */
1006 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
1007 PICL_PTYPE_TABLE
, PICL_READ
|PICL_WRITE
,
1008 sizeof (picl_prophdl_t
), command
->tablecmd_tname
, NULL
, NULL
);
1009 if (err
!= PICL_SUCCESS
)
1012 err
= ptree_create_table(&tblh
);
1013 if (err
!= PICL_SUCCESS
)
1016 command
->tablecmd_newtbl
= 1;
1017 command
->tablecmd_tblh
= tblh
;
1019 err
= ptree_create_prop(&propinfo
, &tblh
, &proph
);
1020 if (err
!= PICL_SUCCESS
)
1023 err
= ptree_add_prop(nodeh
, proph
);
1029 * Process the ROW command by alloc'ing space to store the prop handles for
1030 * the whole row. The number of props in the row gets known while parsing.
1033 process_row(command_t
*command
)
1035 command
->rowcmd_index
= 0;
1036 command
->rowcmd_prophs
=
1037 malloc(command
->rowcmd_nproph
* sizeof (picl_prophdl_t
));
1039 if (command
->rowcmd_prophs
== NULL
)
1040 return (PICL_FAILURE
);
1042 return (PICL_SUCCESS
);
1046 * Process the ENDROW command. If a valid row, add the row to the ptree.
1049 process_endrow(cmdbuf_t
*cmds
)
1053 command_t
*curr_row
;
1055 curr_row
= &cmds
->commands
[cmds
->current_row
];
1057 /* if nproph == 0, some row prop had problems, don't add */
1058 if (curr_row
->rowcmd_nproph
== 0) {
1059 for (i
= 0; i
< curr_row
->rowcmd_index
; i
++) {
1060 (void) ptree_delete_prop(curr_row
->rowcmd_prophs
[i
]);
1061 (void) ptree_destroy_prop(curr_row
->rowcmd_prophs
[i
]);
1065 err
= ptree_add_row_to_table(
1066 cmds
->commands
[cmds
->current_tbl
].tablecmd_tblh
,
1067 curr_row
->rowcmd_nproph
,
1068 curr_row
->rowcmd_prophs
);
1070 /* let go the space alloc'd in process_row */
1071 free(curr_row
->rowcmd_prophs
);
1072 curr_row
->rowcmd_prophs
= NULL
;
1078 * Check the VERBOSE syntax
1082 parse_verbose(cmdbuf_t
*cmds
, char *line
, command_t
*command
)
1090 /* get the VERBOSE directive */
1091 tok
= strtok_r(line
, WHITESPACE
, &last
);
1093 return (EC_INSUFFICIENT_TOKEN
);
1095 /* get verbose level */
1096 level
= strtok_r(last
, WHITESPACE
, &last
);
1098 return (EC_INSUFFICIENT_TOKEN
);
1099 verbose_level
= strtol(level
, &endptr
, 0);
1100 if (endptr
!= (level
+ strlen(level
)))
1101 return (EC_SYNTAX_ERR
);
1103 /* check if more tokens */
1104 tok
= strtok_r(last
, WHITESPACE
, &last
);
1106 return (EC_SYNTAX_ERR
);
1108 cmds
->verbose
= verbose_level
;
1109 command
->verbosecmd_level
= verbose_level
;
1111 return (EC_SYNTAX_OK
);
1115 * Process the VERBOSE command to set the verbose level
1118 process_verbose(cmdbuf_t
*cmds
, command_t
*command
)
1120 cmds
->verbose
= command
->verbosecmd_level
;
1121 return (PICL_SUCCESS
);
1125 * parse and tokenize the line
1128 parse_and_tokenize_line(cmdbuf_t
*cmds
, char *buf
, command_t
*command
)
1130 char rec
[RECORD_SIZE_MAX
];
1136 (void) strcpy(rec
, buf
);
1137 tok
= strtok_r(rec
, RECORD_WHITESPACE
, &last
);
1139 return (EC_INSUFFICIENT_TOKEN
);
1141 id
= get_token_id(tok
);
1143 (void) strcpy(rec
, buf
);
1147 err
= parse_version(cmds
, rec
);
1151 if (cmds
->inside_node_block
!= 0)
1152 return (EC_PATH_ERR
);
1154 err
= parse_path(rec
, command
);
1155 if (err
!= EC_SYNTAX_OK
)
1159 /* Check for NODE outside of TABLE, ROW */
1160 if ((cmds
->inside_table_block
!= 0) ||
1161 (cmds
->inside_row_block
!= 0))
1162 return (EC_SYNTAX_ERR
);
1163 err
= parse_node(rec
, command
);
1164 if (err
!= EC_SYNTAX_OK
)
1166 cmds
->inside_node_block
++;
1169 /* Check for ENDNODE outside of TABLE, ROW */
1170 if ((cmds
->inside_table_block
!= 0) ||
1171 (cmds
->inside_row_block
!= 0))
1172 return (EC_SYNTAX_ERR
);
1173 cmds
->inside_node_block
--;
1177 /* Check if inside TABLE, but not in ROW */
1178 if ((cmds
->inside_table_block
!= 0) &&
1179 (cmds
->inside_row_block
== 0))
1180 return (EC_SYNTAX_ERR
);
1181 err
= parse_prop(rec
, command
);
1182 if (err
!= EC_SYNTAX_OK
)
1184 if (cmds
->inside_row_block
) {
1185 cmds
->commands
[cmds
->current_row
].rowcmd_nproph
++;
1189 err
= parse_refnode(rec
, command
);
1190 if (err
!= EC_SYNTAX_OK
)
1194 /* Check if inside TABLE, but not in ROW */
1195 if ((cmds
->inside_table_block
!= 0) &&
1196 (cmds
->inside_row_block
== 0))
1197 return (EC_SYNTAX_ERR
);
1198 err
= parse_refprop(rec
, command
);
1199 if (err
!= EC_SYNTAX_OK
)
1201 if (cmds
->inside_row_block
) {
1202 cmds
->commands
[cmds
->current_row
].rowcmd_nproph
++;
1206 /* Table/Row supported in version 1.1 and above */
1207 if (cmds
->version_no
< (float)SUPPORTED_VERSION_NUM
)
1208 return (EC_UNSUPPORTED
);
1209 if (cmds
->inside_table_block
!= 0)
1210 return (EC_SYNTAX_ERR
);
1211 err
= parse_table(rec
, command
);
1212 if (err
!= EC_SYNTAX_OK
)
1214 cmds
->inside_table_block
= 1;
1217 /* Check for ENDTABLE before TABLE */
1218 if (cmds
->inside_table_block
== 0)
1219 return (EC_SYNTAX_ERR
);
1221 cmds
->inside_table_block
= 0;
1225 /* Check for ROW outside of TABLE, ROW inside ROW */
1226 if ((cmds
->inside_table_block
== 0) ||
1227 (cmds
->inside_row_block
!= 0))
1228 return (EC_SYNTAX_ERR
);
1229 cmds
->inside_row_block
= 1;
1232 /* Check for ENDROW outside of TABLE, ENDROW before ROW */
1233 if ((cmds
->inside_table_block
== 0) ||
1234 (cmds
->inside_row_block
== 0))
1235 return (EC_SYNTAX_ERR
);
1239 cmds
->inside_row_block
= 0;
1241 /* error if row is empty */
1242 if (cmds
->commands
[cmds
->current_row
].rowcmd_nproph
<= 0)
1243 return (EC_ROW_EMPTY
);
1246 err
= parse_verbose(cmds
, rec
, command
);
1247 if (err
!= EC_SYNTAX_OK
)
1250 default: /* unsupported command */
1251 return (EC_SYNTAX_ERR
);
1255 return (EC_SYNTAX_OK
);
1259 * Check the syntax and save the tokens in the commands buffer
1262 check_line_syntax(cmdbuf_t
*cmds
, char *buf
)
1267 (void) memset(&command
, 0, sizeof (command_t
));
1268 err
= parse_and_tokenize_line(cmds
, buf
, &command
);
1269 if (err
!= EC_SYNTAX_OK
)
1273 * don't add and count version command in the command buffer
1275 if (command
.type
== TOK_VERSION
)
1276 return (EC_SYNTAX_OK
);
1279 * check if the commands buffer has been filled
1280 * If it is full, reallocate the buffer.
1282 if (cmds
->count
== cmds
->allocated
) {
1283 cmds
->commands
= reallocarray(cmds
->commands
,
1284 cmds
->allocated
+ PER_ALLOC_COUNT
, sizeof (command_t
));
1285 if (cmds
->commands
== NULL
)
1286 return (EC_FAILURE
);
1287 cmds
->allocated
+= PER_ALLOC_COUNT
;
1290 cmds
->commands
[cmds
->count
] = command
; /* copy */
1293 * make a note of the row/endrow command, to keep track of # of props
1295 if (command
.type
== TOK_ROW
)
1296 cmds
->current_row
= cmds
->count
;
1298 if (command
.type
== TOK_ENDROW
)
1299 cmds
->current_row
= 0;
1303 return (EC_SYNTAX_OK
);
1307 * get the line control information
1308 * return 1 if it's the line control information, else return 0
1311 get_line_control_info(char *buf
, uint32_t *linenum
, char *filename
)
1319 /* skip # and get next string */
1320 ptr
= strtok_r(buf
+ 1, WHITESPACE
, &last
);
1325 num
= strtoul(ptr
, &endptr
, 0);
1328 * It's not the line control information
1330 if (endptr
!= (ptr
+ strlen(ptr
))) {
1338 /* get the beginning double quote */
1339 last
= strchr(last
, '"');
1345 /* get the ending double quote */
1346 fname
= strtok_r(last
, DOUBLE_QUOTE
, &last
);
1351 (void) strlcpy(filename
, fname
, PATH_MAX
);
1356 * check the syntax of the configuration file
1359 check_conffile_syntax(cmdbuf_t
*cmds
, FILE *fp
)
1361 char lbuf
[RECORD_SIZE_MAX
];
1362 char buf
[RECORD_SIZE_MAX
];
1364 char cppfile
[PATH_MAX
] = "";
1365 int err
= EC_SYNTAX_OK
;
1368 while (fgets(buf
, sizeof (buf
), fp
) != NULL
) {
1370 * get cpp line control information, if any
1372 if (buf
[0] == '#') {
1373 if (!get_line_control_info(buf
, &linenum
, cppfile
))
1380 * skip line whose first char is a newline char
1382 if (buf
[0] == '\n') {
1386 if (err
== EC_SYNTAX_OK
)
1387 (void) strlcpy(lbuf
, buf
, RECORD_SIZE_MAX
);
1388 else if (strlcat(lbuf
, buf
, RECORD_SIZE_MAX
) >=
1389 RECORD_SIZE_MAX
) { /* buffer overflow */
1394 err
= check_line_syntax(cmds
, lbuf
);
1395 if ((err
!= EC_INSUFFICIENT_TOKEN
) && (err
!= EC_SYNTAX_OK
))
1399 if (err
!= EC_SYNTAX_OK
) {
1400 if (cmds
->verbose
) {
1401 verbose_log(LOG_ERR
, err_msg
[err
],
1402 cmds
->fname
, cppfile
, linenum
);
1408 * check if the version has been set
1410 if (cmds
->version_no
> (float)SUPPORTED_VERSION_NUM
) {
1411 if (cmds
->verbose
) {
1412 verbose_log(LOG_ERR
, err_msg
[EC_UNSUPPORTED
],
1413 cmds
->fname
, cppfile
, linenum
);
1415 return (EC_UNSUPPORTED
);
1419 * check if node and endnode command mismatch
1421 if (cmds
->inside_node_block
!= 0) {
1422 if (cmds
->verbose
) {
1423 verbose_log(LOG_ERR
, err_msg
[EC_NODE_MISMATCH
],
1424 cmds
->fname
, cppfile
, linenum
);
1426 return (EC_NODE_MISMATCH
);
1430 * check if row and endrow command mismatch
1432 if (cmds
->inside_row_block
!= 0) {
1433 if (cmds
->verbose
) {
1434 verbose_log(LOG_ERR
, err_msg
[EC_ROW_MISMATCH
],
1435 cmds
->fname
, cppfile
, linenum
);
1437 return (EC_ROW_MISMATCH
);
1441 * check if table and endtable command mismatch
1443 if (cmds
->inside_table_block
!= 0) {
1444 if (cmds
->verbose
) {
1445 verbose_log(LOG_ERR
, err_msg
[EC_TABLE_MISMATCH
],
1446 cmds
->fname
, cppfile
, linenum
);
1448 return (EC_TABLE_MISMATCH
);
1451 return (EC_SYNTAX_OK
);
1455 * If classpath/namepath given is not found in the picl tree,
1456 * skip the whole blocks until next valid classpath or namepath
1459 skip_to_next_valid_path(cmdbuf_t
*cmds
, int starting_index
,
1460 picl_nodehdl_t
*parent
, int *last_processed_index
)
1465 for (index
= starting_index
; index
< cmds
->count
; ++index
) {
1466 switch (cmds
->commands
[index
].type
) {
1469 err
= process_path(&cmds
->commands
[index
], parent
);
1470 if (err
== PICL_SUCCESS
) {
1471 *last_processed_index
= index
;
1475 /* skipped this line */
1480 /* reach last command */
1481 *last_processed_index
= cmds
->count
- 1;
1485 * Process the command buffer and return last command index and the new head of
1489 process_commands(cmdbuf_t
*cmds
, int starting_index
, picl_nodehdl_t parent
,
1490 int *last_processed_index
)
1494 picl_nodehdl_t rooth
;
1495 picl_nodehdl_t nodeh
;
1496 command_t
*commands
= cmds
->commands
;
1498 for (index
= starting_index
; index
< cmds
->count
; ++index
) {
1499 switch (commands
[index
].type
) {
1502 err
= process_path(&commands
[index
], &rooth
);
1503 if (err
!= PICL_SUCCESS
) {
1505 (void) skip_to_next_valid_path(cmds
, index
,
1511 err
= process_node(&commands
[index
], parent
, &nodeh
);
1512 if (err
== PICL_SUCCESS
) {
1514 err
= process_commands(cmds
, index
, nodeh
,
1519 *last_processed_index
= index
;
1520 return (PICL_SUCCESS
);
1522 err
= process_prop(cmds
, &commands
[index
], parent
);
1525 err
= process_refprop(cmds
, &commands
[index
], parent
);
1526 /* no reference node */
1527 if (err
== PICL_NOTNODE
) {
1528 err
= PICL_SUCCESS
; /* discard prop */
1529 /* discard row by setting nproph = 0 */
1530 if (cmds
->inside_row_block
)
1531 cmds
->commands
[cmds
->current_row
]
1536 err
= process_refnode(&commands
[index
], parent
);
1539 cmds
->inside_table_block
= 1;
1540 err
= process_table(&commands
[index
], parent
);
1541 cmds
->current_tbl
= index
;
1544 cmds
->inside_table_block
= 0;
1545 cmds
->current_tbl
= 0;
1548 cmds
->inside_row_block
= 1;
1549 err
= process_row(&commands
[index
]);
1550 cmds
->current_row
= index
;
1553 err
= process_endrow(cmds
);
1554 cmds
->inside_row_block
= 0;
1555 cmds
->current_row
= 0;
1558 err
= process_verbose(cmds
, &commands
[index
]);
1560 default: /* won't reach here */
1565 if ((err
!= PICL_SUCCESS
) && (err
!= PICL_PROPEXISTS
)) {
1566 *last_processed_index
= index
;
1571 /* reach last command */
1572 *last_processed_index
= cmds
->count
- 1;
1573 return (PICL_SUCCESS
);
1577 * clean up the commands buffer
1580 clean_up(cmdbuf_t
*cmds
)
1584 for (cmd_index
= 0; cmd_index
< cmds
->count
; cmd_index
++) {
1585 switch (cmds
->commands
[cmd_index
].type
) {
1588 free_path(&cmds
->commands
[cmd_index
]);
1591 free_node(&cmds
->commands
[cmd_index
]);
1594 free_prop(&cmds
->commands
[cmd_index
]);
1597 free_refprop(&cmds
->commands
[cmd_index
]);
1600 free_refnode(&cmds
->commands
[cmd_index
]);
1603 free_table(&cmds
->commands
[cmd_index
]);
1614 free(cmds
->commands
);
1618 * Parse the configuration file and create nodes/properties under nh
1620 * It checks the syntax first. If there is any syntax error,
1621 * it returns 1 and won't continue processing the file to add nodes or props.
1623 * If any error happens during command processing, all nodes
1624 * and properties just created will be deleted, i.e. undo
1625 * commands which have been processed. It returns 1.
1627 * If success, return 0.
1630 picld_pluginutil_parse_config_file(picl_nodehdl_t nh
, const char *filename
)
1633 int last_processed_index
;
1637 /* set correct locale for use inside pluginutil */
1638 setlocale(LC_ALL
, "C");
1641 * Initialize the command buffer
1644 cmds
= malloc(sizeof (*cmds
));
1646 setlocale(LC_ALL
, "");
1650 memset(cmds
, 0, sizeof (cmdbuf_t
));
1652 cmds
->fname
= filename
;
1654 ifp
= fopen(filename
, "r");
1656 setlocale(LC_ALL
, "");
1662 * check the syntax of the configuration file
1664 err
= check_conffile_syntax(cmds
, ifp
);
1668 if (err
!= EC_SYNTAX_OK
) {
1671 setlocale(LC_ALL
, "");
1676 * Process the commands
1678 err
= process_commands(cmds
, STARTING_INDEX
, nh
, &last_processed_index
);
1681 * If any PICL error, remove the newly created node/prop
1682 * handles from the PICL tree.
1684 if (err
!= PICL_SUCCESS
) {
1685 undo_commands(cmds
, last_processed_index
);
1687 verbose_log(LOG_ERR
, err_msg
[EC_PICL_ERR
], filename
,
1694 /* reset the locale */
1695 setlocale(LC_ALL
, "");
1697 return ((err
== PICL_SUCCESS
) ? 0 : 1);