dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / picl / plugins / lib / picld_pluginutil / picld_pluginutil.c
blobc8e74051b5e5dc5727ad84122f02f009637451be
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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.
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <alloca.h>
39 #include <limits.h>
40 #include <sys/utsname.h>
41 #include <sys/systeminfo.h>
42 #include <sys/types.h>
43 #include <libintl.h>
44 #include <syslog.h>
45 #include <locale.h>
46 #include <picl.h>
47 #include <picltree.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
56 #define EC_PATH_ERR 4
57 #define EC_NODE_MISMATCH 5
58 #define EC_FAILURE 6
59 #define EC_PICL_ERR 7
60 #define EC_TABLE_MISMATCH 8
61 #define EC_ROW_MISMATCH 9
62 #define EC_ROW_EMPTY 10
65 * Error message texts
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
84 #define TOK_NODE 2
85 #define TOK_ENDNODE 3
86 #define TOK_PROP 4
87 #define TOK_REFPROP 5
88 #define TOK_VERSION 6
89 #define TOK_REFNODE 7
90 #define TOK_VERBOSE 8
91 #define TOK_TABLE 9
92 #define TOK_ENDTABLE 10
93 #define TOK_ROW 11
94 #define TOK_ENDROW 12
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 */
108 "row", /* ROW */
109 "endrow" /* ENDROW */
112 #define BUF_SIZE_MAX 1024
115 * print error message
117 /*VARARGS2*/
118 static void
119 verbose_log(int pri, const char *fmt, ...)
121 va_list ap;
123 va_start(ap, fmt);
124 vsyslog(pri, fmt, ap);
125 va_end(ap);
129 * Undo the commands which have created valid node/prop handle
130 * The undo order is from last command to the first command.
132 static void
133 undo_commands(cmdbuf_t *cmds, int last_cmd_index)
135 int i;
136 command_t *com = cmds->commands;
138 for (i = last_cmd_index; i >= 0; i--) {
139 switch (com[i].type) {
140 case TOK_NODE:
141 if (com[i].nodecmd_nodeh == 0)
142 break;
144 (void) ptree_delete_node(com[i].nodecmd_nodeh);
145 (void) ptree_destroy_node(com[i].nodecmd_nodeh);
146 break;
147 case TOK_REFNODE:
148 if (com[i].refnodecmd_nodeh == 0)
149 break;
150 (void) ptree_delete_node(com[i].refnodecmd_nodeh);
151 (void) ptree_destroy_node(com[i].refnodecmd_nodeh);
152 break;
153 case TOK_PROP:
154 if (com[i].propcmd_proph == 0)
155 break;
156 (void) ptree_delete_prop(com[i].propcmd_proph);
157 (void) ptree_destroy_prop(com[i].propcmd_proph);
158 break;
159 case TOK_REFPROP:
160 if (com[i].refpropcmd_proph == 0)
161 break;
162 (void) ptree_delete_prop(com[i].refpropcmd_proph);
163 (void) ptree_destroy_prop(com[i].refpropcmd_proph);
164 break;
165 case TOK_TABLE:
166 if ((com[i].tablecmd_tblh == 0) ||
167 (com[i].tablecmd_newtbl == 0))
168 break;
169 (void) ptree_delete_prop(com[i].tablecmd_tblh);
170 (void) ptree_destroy_prop(com[i].tablecmd_tblh);
171 break;
172 case TOK_ENDTABLE:
173 /*FALLTHROUGH*/
174 case TOK_ROW:
175 /*FALLTHROUGH*/
176 case TOK_ENDROW:
177 /*FALLTHROUGH*/
178 case TOK_NAMEPATH:
179 /*FALLTHROUGH*/
180 case TOK_CLASSPATH:
181 /*FALLTHROUGH*/
182 case TOK_ENDNODE:
183 /*FALLTHROUGH*/
184 case TOK_VERBOSE:
185 /*FALLTHROUGH*/
186 default:
187 break;
193 * Get the token index from the tokens table
195 static int
196 get_token_id(char *t)
198 int i;
200 for (i = 0; i < sizeof (tokens)/ sizeof (char *); ++i)
201 if (strcasecmp(tokens[i], t) == 0)
202 return (i);
204 return (-1);
208 * Check the version syntax and set the version_no
210 * VERSION <version_num> -- specify the configuration version
212 static int
213 parse_version(cmdbuf_t *cmds, char *line)
215 char *tok;
216 char *vertok;
217 char *last;
218 char *endptr;
220 /* get the VERSION directive */
221 tok = strtok_r(line, WHITESPACE, &last);
222 if (tok == NULL)
223 return (EC_INSUFFICIENT_TOKEN);
225 /* get the version number */
226 vertok = strtok_r(last, WHITESPACE, &last);
227 if (vertok == NULL)
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);
239 if (tok != NULL)
240 return (EC_SYNTAX_ERR);
242 return (EC_SYNTAX_OK);
246 * free path_cmd_t
248 static void
249 free_path(command_t *command)
251 free(command->pathcmd_name);
255 * Check the path syntax
256 * NAMEPATH:<namepath> -- gives the anchor node
257 * or
258 * CLASSPATH:<classpath> -- gives the anchor node
260 static int
261 parse_path(char *line, command_t *command)
263 char *tok;
264 char *pathtok;
265 char *last;
267 pathtok = strtok_r(line, WHITESPACE, &last);
268 if (pathtok == NULL)
269 return (EC_INSUFFICIENT_TOKEN);
271 /* check if more tokens */
272 tok = strtok_r(last, WHITESPACE, &last);
273 if (tok != NULL)
274 return (EC_SYNTAX_ERR);
276 command->pathcmd_name = strdup(pathtok);
277 if (command->pathcmd_name == NULL)
278 return (EC_FAILURE);
280 return (EC_SYNTAX_OK);
284 * Process the path command and return PICL node handle
286 static int
287 process_path(command_t *command, picl_nodehdl_t *nodeh)
289 int err;
291 err = ptree_get_node_by_path(command->pathcmd_name, nodeh);
292 return (err);
296 * free node_cmd_t
298 static void
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>
309 static int
310 parse_node(char *line, command_t *command)
312 char *tok;
313 char *nametok;
314 char *classtok;
315 char *last;
317 /* get the NODE directive */
318 tok = strtok_r(line, WHITESPACE, &last);
319 if (tok == NULL)
320 return (EC_INSUFFICIENT_TOKEN);
322 /* get name */
323 nametok = strtok_r(last, WHITESPACE, &last);
324 if (nametok == NULL)
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);
333 if (tok != NULL)
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))
341 return (EC_FAILURE);
343 return (EC_SYNTAX_OK);
347 * Process the NODE command and return PICL node handle
349 static int
350 process_node(command_t *command, picl_nodehdl_t parh, picl_nodehdl_t *nodeh)
352 int err;
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;
360 return (err);
364 * get the PICL property type
366 static int
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);
379 else
380 return (-1);
384 * get the PICL accessmode mode
386 static int
387 getpiclmode(char *mode)
389 if (strcasecmp(mode, KEYWORD_READ_MODE) == 0)
390 return (PICL_READ);
391 else if (strcasecmp(mode, KEYWORD_WRITE_MODE) == 0)
392 return (PICL_WRITE);
393 else if (strcasecmp(mode, KEYWORD_READWRITE_MODE) == 0)
394 return (PICL_READ|PICL_WRITE);
395 else
396 return (-1);
400 * check if the size and value are valid given by the prop type
402 static int
403 validate_size_and_cvt_val(void *outbuf, size_t size, int type, char *val)
405 int64_t llval;
406 int32_t intval;
407 int16_t sval;
408 int8_t cval;
409 uint64_t ullval;
410 uint32_t uintval;
411 uint16_t usval;
412 uint8_t ucval;
413 float fval;
414 double dval;
415 char *endptr;
417 switch (type) {
418 case PICL_PTYPE_CHARSTRING:
419 break;
420 case PICL_PTYPE_INT:
421 switch (size) {
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);
427 break;
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);
433 break;
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);
439 break;
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);
445 break;
446 default: /* invalid size */
447 return (EC_SYNTAX_ERR);
449 break;
450 case PICL_PTYPE_UNSIGNED_INT:
451 switch (size) {
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);
457 break;
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);
463 break;
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);
469 break;
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);
475 break;
476 default: /* invalid size */
477 return (EC_SYNTAX_ERR);
479 break;
480 case PICL_PTYPE_FLOAT:
481 switch (size) {
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);
487 break;
488 case sizeof (float):
489 fval = (float)strtod(val, &endptr);
490 if (endptr != (val + strlen(val)))
491 return (EC_SYNTAX_ERR);
492 (void) memcpy(outbuf, &fval, size);
493 break;
494 default: /* invalid size */
495 return (EC_SYNTAX_ERR);
497 break;
498 default: /* not supported type */
499 return (EC_SYNTAX_ERR);
502 return (EC_SYNTAX_OK);
506 * free prop_cmd_t
508 static void
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
520 static int
521 get_string_token(char *line, char **valtok)
523 char *optr; /* ptr to the open quote */
524 char *cptr; /* ptr to the close quote */
525 char *ptr;
526 char *tmpbuf;
528 if (line == NULL)
529 return (EC_INSUFFICIENT_TOKEN);
531 /* skipping leading white spaces */
532 optr = line;
533 while ((*optr == ' ') || (*optr == '\t') || (*optr == '\n'))
534 optr++;
536 /* reach end of string */
537 if (*optr == '\0')
538 return (EC_INSUFFICIENT_TOKEN);
540 /* it's not an open double quote */
541 if (*optr != '"')
542 return (EC_SYNTAX_ERR);
544 /* skipping ending white spaces */
545 cptr = line + strlen(line) - 1;
546 while ((*cptr == ' ') || (*cptr == '\t') || (*cptr == '\n'))
547 cptr--;
549 /* it's not an close double quote */
550 if (*cptr != '"')
551 return (EC_SYNTAX_ERR);
553 /* close double quote is missing */
554 if (cptr == optr)
555 return (EC_SYNTAX_ERR);
557 /* replace close qoute by null to make a string */
558 *cptr = '\0';
559 /* move the begin pointer to the first char of string */
560 optr++;
562 tmpbuf = malloc(strlen(optr) + 1);
563 if (tmpbuf == NULL)
564 return (EC_FAILURE);
566 for (ptr = tmpbuf; *optr != '\0'; ptr++, optr++) {
567 /* if escape character, go to next character */
568 if (*optr == '\\') {
569 optr++;
570 if (*optr == '\0') { /* for exampe, "xxx\" */
571 free(tmpbuf);
572 return (EC_SYNTAX_ERR);
575 *ptr = *optr;
578 *ptr = '\0';
579 *valtok = tmpbuf;
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>
590 * is 0
592 static int
593 parse_prop(char *line, command_t *command)
595 char *tok;
596 char *pnametok;
597 int typetok;
598 size_t sizetok;
599 int modetok;
600 char *valtok;
601 char *last;
602 char *endptr;
603 int err;
605 /* get the PROP directive */
606 tok = strtok_r(line, WHITESPACE, &last);
607 if (tok == NULL)
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);
615 /* get the type */
616 tok = strtok_r(last, WHITESPACE, &last);
617 if (tok == NULL)
618 return (EC_INSUFFICIENT_TOKEN);
620 if ((typetok = getpicltype(tok)) < 0)
621 return (EC_SYNTAX_ERR);
623 /* get mode */
624 tok = strtok_r(last, WHITESPACE, &last);
625 if (tok == NULL)
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)
636 return (EC_FAILURE);
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);
644 /* get size */
645 tok = strtok_r(last, WHITESPACE, &last);
646 if (tok == NULL)
647 return (EC_INSUFFICIENT_TOKEN);
649 sizetok = (size_t)strtol(tok, &endptr, 0);
650 if (endptr != (tok + strlen(tok)))
651 return (EC_SYNTAX_ERR);
653 /* get val */
654 if (typetok == PICL_PTYPE_CHARSTRING) {
655 err = get_string_token(last, &valtok);
656 if (err != EC_SYNTAX_OK)
657 return (err);
658 if (sizetok == 0)
659 sizetok = strlen(valtok) + 1;
660 command->propcmd_valbuf = valtok;
661 } else {
662 valtok = strtok_r(last, WHITESPACE, &last);
663 if (valtok == NULL)
664 return (EC_INSUFFICIENT_TOKEN);
665 /* check if more tokens */
666 tok = strtok_r(last, WHITESPACE, &last);
667 if (tok != NULL)
668 return (EC_SYNTAX_ERR);
669 command->propcmd_valbuf = malloc(sizetok);
670 if (command->propcmd_valbuf == NULL)
671 return (EC_FAILURE);
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);
676 return (err);
680 command->propcmd_pname = strdup(pnametok);
681 if (command->propcmd_pname == NULL)
682 return (EC_FAILURE);
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
693 static int
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
705 * node handle
707 static int
708 process_prop(cmdbuf_t *cmds, command_t *command, picl_nodehdl_t nodeh)
710 ptree_propinfo_t propinfo;
711 picl_prophdl_t proph;
712 int err;
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,
722 NULL);
724 if (err != PICL_SUCCESS)
725 return (err);
727 err = ptree_create_prop(&propinfo, command->propcmd_valbuf, &proph);
729 if (err != PICL_SUCCESS)
730 return (err);
732 command->propcmd_proph = proph;
734 if (cmds->inside_row_block) {
735 err = add_proph_to_row(&cmds->commands[cmds->current_row],
736 proph);
737 } else {
738 err = ptree_add_prop(nodeh, proph);
741 return (err);
745 * free refnode_cmd_t
747 static void
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>
761 static int
762 parse_refnode(char *line, command_t *command)
764 char *tok;
765 char *dsttok;
766 char *classnm;
767 char *nodenm;
768 char *last;
770 /* get the directive */
771 tok = strtok_r(line, WHITESPACE, &last);
772 if (tok == NULL)
773 return (EC_INSUFFICIENT_TOKEN);
775 /* get the nodename */
776 nodenm = strtok_r(last, WHITESPACE, &last);
777 if (nodenm == NULL)
778 return (EC_INSUFFICIENT_TOKEN);
780 /* get the class */
781 classnm = strtok_r(last, WHITESPACE, &last);
782 if (classnm == NULL)
783 return (EC_INSUFFICIENT_TOKEN);
785 /* get the WITH keyword */
786 tok = strtok_r(last, WHITESPACE, &last);
787 if (tok == NULL)
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);
795 if (dsttok == NULL)
796 return (EC_INSUFFICIENT_TOKEN);
798 /* check if more tokens */
799 tok = strtok_r(last, WHITESPACE, &last);
800 if (tok != NULL)
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))
810 return (EC_FAILURE);
812 return (EC_SYNTAX_OK);
816 * Process the REFNODE command
818 static int
819 process_refnode(command_t *command, picl_nodehdl_t parh)
821 picl_nodehdl_t dsth;
822 picl_nodehdl_t nodeh;
823 int err;
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;
832 return (err);
835 return (PICL_SUCCESS);
839 * free refprop_cmd_t
841 static void
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>
853 static int
854 parse_refprop(char *line, command_t *command)
856 char *tok;
857 char *pnametok;
858 char *dsttok;
859 char *last;
861 /* get the REFPROP directive */
862 tok = strtok_r(line, WHITESPACE, &last);
863 if (tok == NULL)
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);
872 if (dsttok == NULL)
873 return (EC_INSUFFICIENT_TOKEN);
875 /* check if more tokens */
876 tok = strtok_r(last, WHITESPACE, &last);
877 if (tok != NULL)
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))
885 return (EC_FAILURE);
887 return (EC_SYNTAX_OK);
891 * Process the REFPROP command
893 static int
894 process_refprop(cmdbuf_t *cmds, command_t *command, picl_nodehdl_t nodeh)
896 int err;
897 picl_nodehdl_t dsth;
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)
911 return (err);
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)
919 return (err);
921 err = ptree_create_prop(&propinfo, &dsth, &proph);
923 if (err != PICL_SUCCESS)
924 return (err);
926 command->refpropcmd_proph = proph;
928 if (cmds->inside_row_block) {
929 err = add_proph_to_row(&cmds->commands[cmds->current_row],
930 proph);
931 } else {
932 err = ptree_add_prop(nodeh, proph);
935 return (err);
939 * free table_cmd_t
941 static void
942 free_table(command_t *command)
944 free(command->tablecmd_tname);
948 * Check the TABLE syntax
949 * TABLE <table_prop_name>
952 static int
953 parse_table(char *line, command_t *command)
955 char *tok = NULL;
956 char *tnametok = NULL;
957 char *last = NULL;
959 /* get the TABLE directive */
960 tok = strtok_r(line, WHITESPACE, &last);
961 if (tok == NULL)
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)
971 return (EC_FAILURE);
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
981 * node handle
983 static int
984 process_table(command_t *command, picl_nodehdl_t nodeh)
986 int err;
987 picl_prophdl_t tblh;
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)
996 return (err);
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)
1010 return (err);
1012 err = ptree_create_table(&tblh);
1013 if (err != PICL_SUCCESS)
1014 return (err);
1016 command->tablecmd_newtbl = 1;
1017 command->tablecmd_tblh = tblh;
1019 err = ptree_create_prop(&propinfo, &tblh, &proph);
1020 if (err != PICL_SUCCESS)
1021 return (err);
1023 err = ptree_add_prop(nodeh, proph);
1025 return (err);
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.
1032 static int
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.
1048 static int
1049 process_endrow(cmdbuf_t *cmds)
1051 int err;
1052 int i;
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]);
1063 err = PICL_SUCCESS;
1064 } else
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;
1074 return (err);
1078 * Check the VERBOSE syntax
1079 * VERBOSE <level>
1081 static int
1082 parse_verbose(cmdbuf_t *cmds, char *line, command_t *command)
1084 char *tok;
1085 char *level;
1086 char *last;
1087 char *endptr;
1088 int verbose_level;
1090 /* get the VERBOSE directive */
1091 tok = strtok_r(line, WHITESPACE, &last);
1092 if (tok == NULL)
1093 return (EC_INSUFFICIENT_TOKEN);
1095 /* get verbose level */
1096 level = strtok_r(last, WHITESPACE, &last);
1097 if (level == NULL)
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);
1105 if (tok != NULL)
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
1117 static int
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
1127 static int
1128 parse_and_tokenize_line(cmdbuf_t *cmds, char *buf, command_t *command)
1130 char rec[RECORD_SIZE_MAX];
1131 char *tok;
1132 int err;
1133 char *last;
1134 int id;
1136 (void) strcpy(rec, buf);
1137 tok = strtok_r(rec, RECORD_WHITESPACE, &last);
1138 if (tok == NULL)
1139 return (EC_INSUFFICIENT_TOKEN);
1141 id = get_token_id(tok);
1143 (void) strcpy(rec, buf);
1145 switch (id) {
1146 case TOK_VERSION:
1147 err = parse_version(cmds, rec);
1148 break;
1149 case TOK_CLASSPATH:
1150 case TOK_NAMEPATH:
1151 if (cmds->inside_node_block != 0)
1152 return (EC_PATH_ERR);
1154 err = parse_path(rec, command);
1155 if (err != EC_SYNTAX_OK)
1156 return (err);
1157 break;
1158 case TOK_NODE:
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)
1165 return (err);
1166 cmds->inside_node_block++;
1167 break;
1168 case TOK_ENDNODE:
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--;
1174 err = EC_SYNTAX_OK;
1175 break;
1176 case TOK_PROP:
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)
1183 return (err);
1184 if (cmds->inside_row_block) {
1185 cmds->commands[cmds->current_row].rowcmd_nproph++;
1187 break;
1188 case TOK_REFNODE:
1189 err = parse_refnode(rec, command);
1190 if (err != EC_SYNTAX_OK)
1191 return (err);
1192 break;
1193 case TOK_REFPROP:
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)
1200 return (err);
1201 if (cmds->inside_row_block) {
1202 cmds->commands[cmds->current_row].rowcmd_nproph++;
1204 break;
1205 case TOK_TABLE:
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)
1213 return (err);
1214 cmds->inside_table_block = 1;
1215 break;
1216 case TOK_ENDTABLE:
1217 /* Check for ENDTABLE before TABLE */
1218 if (cmds->inside_table_block == 0)
1219 return (EC_SYNTAX_ERR);
1221 cmds->inside_table_block = 0;
1223 break;
1224 case TOK_ROW:
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;
1230 break;
1231 case TOK_ENDROW:
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);
1236 else
1237 err = EC_SYNTAX_OK;
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);
1244 break;
1245 case TOK_VERBOSE:
1246 err = parse_verbose(cmds, rec, command);
1247 if (err != EC_SYNTAX_OK)
1248 return (err);
1249 break;
1250 default: /* unsupported command */
1251 return (EC_SYNTAX_ERR);
1254 command->type = id;
1255 return (EC_SYNTAX_OK);
1259 * Check the syntax and save the tokens in the commands buffer
1261 static int
1262 check_line_syntax(cmdbuf_t *cmds, char *buf)
1264 int err;
1265 command_t command;
1267 (void) memset(&command, 0, sizeof (command_t));
1268 err = parse_and_tokenize_line(cmds, buf, &command);
1269 if (err != EC_SYNTAX_OK)
1270 return (err);
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;
1301 cmds->count++;
1303 return (EC_SYNTAX_OK);
1307 * get the line control information
1308 * return 1 if it's the line control information, else return 0
1310 static int
1311 get_line_control_info(char *buf, uint32_t *linenum, char *filename)
1313 char *ptr;
1314 char *last;
1315 uint32_t num;
1316 char *fname;
1317 char *endptr;
1319 /* skip # and get next string */
1320 ptr = strtok_r(buf + 1, WHITESPACE, &last);
1321 if (ptr == NULL) {
1322 return (0);
1325 num = strtoul(ptr, &endptr, 0);
1328 * It's not the line control information
1330 if (endptr != (ptr + strlen(ptr))) {
1331 return (0);
1335 * get the filename
1338 /* get the beginning double quote */
1339 last = strchr(last, '"');
1340 if (last == NULL)
1341 return (0);
1343 last++;
1345 /* get the ending double quote */
1346 fname = strtok_r(last, DOUBLE_QUOTE, &last);
1347 if (fname == NULL)
1348 return (0);
1350 *linenum = num;
1351 (void) strlcpy(filename, fname, PATH_MAX);
1352 return (1);
1356 * check the syntax of the configuration file
1358 static int
1359 check_conffile_syntax(cmdbuf_t *cmds, FILE *fp)
1361 char lbuf[RECORD_SIZE_MAX];
1362 char buf[RECORD_SIZE_MAX];
1363 uint32_t linenum;
1364 char cppfile[PATH_MAX] = "";
1365 int err = EC_SYNTAX_OK;
1367 linenum = 0;
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))
1374 ++linenum;
1375 continue;
1378 ++linenum;
1380 * skip line whose first char is a newline char
1382 if (buf[0] == '\n') {
1383 continue;
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 */
1390 err = EC_FAILURE;
1391 break;
1394 err = check_line_syntax(cmds, lbuf);
1395 if ((err != EC_INSUFFICIENT_TOKEN) && (err != EC_SYNTAX_OK))
1396 break;
1399 if (err != EC_SYNTAX_OK) {
1400 if (cmds->verbose) {
1401 verbose_log(LOG_ERR, err_msg[err],
1402 cmds->fname, cppfile, linenum);
1404 return (err);
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
1458 static void
1459 skip_to_next_valid_path(cmdbuf_t *cmds, int starting_index,
1460 picl_nodehdl_t *parent, int *last_processed_index)
1462 int err;
1463 int index;
1465 for (index = starting_index; index < cmds->count; ++index) {
1466 switch (cmds->commands[index].type) {
1467 case TOK_CLASSPATH:
1468 case TOK_NAMEPATH:
1469 err = process_path(&cmds->commands[index], parent);
1470 if (err == PICL_SUCCESS) {
1471 *last_processed_index = index;
1472 return;
1474 default:
1475 /* skipped this line */
1476 break;
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
1486 * the handle list
1488 static int
1489 process_commands(cmdbuf_t *cmds, int starting_index, picl_nodehdl_t parent,
1490 int *last_processed_index)
1492 int err;
1493 int 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) {
1500 case TOK_CLASSPATH:
1501 case TOK_NAMEPATH:
1502 err = process_path(&commands[index], &rooth);
1503 if (err != PICL_SUCCESS) {
1504 index++;
1505 (void) skip_to_next_valid_path(cmds, index,
1506 &rooth, &index);
1508 parent = rooth;
1509 continue;
1510 case TOK_NODE:
1511 err = process_node(&commands[index], parent, &nodeh);
1512 if (err == PICL_SUCCESS) {
1513 index++;
1514 err = process_commands(cmds, index, nodeh,
1515 &index);
1517 break;
1518 case TOK_ENDNODE:
1519 *last_processed_index = index;
1520 return (PICL_SUCCESS);
1521 case TOK_PROP:
1522 err = process_prop(cmds, &commands[index], parent);
1523 break;
1524 case TOK_REFPROP:
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]
1532 .rowcmd_nproph = 0;
1534 break;
1535 case TOK_REFNODE:
1536 err = process_refnode(&commands[index], parent);
1537 break;
1538 case TOK_TABLE:
1539 cmds->inside_table_block = 1;
1540 err = process_table(&commands[index], parent);
1541 cmds->current_tbl = index;
1542 break;
1543 case TOK_ENDTABLE:
1544 cmds->inside_table_block = 0;
1545 cmds->current_tbl = 0;
1546 break;
1547 case TOK_ROW:
1548 cmds->inside_row_block = 1;
1549 err = process_row(&commands[index]);
1550 cmds->current_row = index;
1551 break;
1552 case TOK_ENDROW:
1553 err = process_endrow(cmds);
1554 cmds->inside_row_block = 0;
1555 cmds->current_row = 0;
1556 break;
1557 case TOK_VERBOSE:
1558 err = process_verbose(cmds, &commands[index]);
1559 break;
1560 default: /* won't reach here */
1561 err = PICL_FAILURE;
1562 break;
1565 if ((err != PICL_SUCCESS) && (err != PICL_PROPEXISTS)) {
1566 *last_processed_index = index;
1567 return (err);
1571 /* reach last command */
1572 *last_processed_index = cmds->count - 1;
1573 return (PICL_SUCCESS);
1577 * clean up the commands buffer
1579 static void
1580 clean_up(cmdbuf_t *cmds)
1582 int cmd_index;
1584 for (cmd_index = 0; cmd_index < cmds->count; cmd_index++) {
1585 switch (cmds->commands[cmd_index].type) {
1586 case TOK_CLASSPATH:
1587 case TOK_NAMEPATH:
1588 free_path(&cmds->commands[cmd_index]);
1589 break;
1590 case TOK_NODE:
1591 free_node(&cmds->commands[cmd_index]);
1592 break;
1593 case TOK_PROP:
1594 free_prop(&cmds->commands[cmd_index]);
1595 break;
1596 case TOK_REFPROP:
1597 free_refprop(&cmds->commands[cmd_index]);
1598 break;
1599 case TOK_REFNODE:
1600 free_refnode(&cmds->commands[cmd_index]);
1601 break;
1602 case TOK_TABLE:
1603 free_table(&cmds->commands[cmd_index]);
1604 break;
1605 case TOK_ENDTABLE:
1606 case TOK_ROW:
1607 case TOK_ENDROW:
1608 case TOK_ENDNODE:
1609 case TOK_VERBOSE:
1610 default:
1611 break;
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)
1632 FILE *ifp;
1633 int last_processed_index;
1634 int err;
1635 cmdbuf_t *cmds;
1637 /* set correct locale for use inside pluginutil */
1638 setlocale(LC_ALL, "C");
1641 * Initialize the command buffer
1644 cmds = malloc(sizeof (*cmds));
1645 if (cmds == NULL) {
1646 setlocale(LC_ALL, "");
1647 return (1);
1650 memset(cmds, 0, sizeof (cmdbuf_t));
1652 cmds->fname = filename;
1654 ifp = fopen(filename, "r");
1655 if (ifp == NULL) {
1656 setlocale(LC_ALL, "");
1657 free(cmds);
1658 return (1);
1662 * check the syntax of the configuration file
1664 err = check_conffile_syntax(cmds, ifp);
1666 (void) fclose(ifp);
1668 if (err != EC_SYNTAX_OK) {
1669 clean_up(cmds);
1670 free(cmds);
1671 setlocale(LC_ALL, "");
1672 return (1);
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);
1686 if (cmds->verbose)
1687 verbose_log(LOG_ERR, err_msg[EC_PICL_ERR], filename,
1688 err);
1691 clean_up(cmds);
1692 free(cmds);
1694 /* reset the locale */
1695 setlocale(LC_ALL, "");
1697 return ((err == PICL_SUCCESS) ? 0 : 1);