1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * This module implements the routine to parse the configuration file.
28 */
29
30
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"
50
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
63
64 /*
65 * Error message texts
66 */
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 */
79 };
80
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
95
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 */
110 };
111
112 #define BUF_SIZE_MAX 1024
113
114 /*
115 * print error message
116 */
117 /*VARARGS2*/
118 static void
verbose_log(int pri,const char * fmt,...)119 verbose_log(int pri, const char *fmt, ...)
120 {
121 va_list ap;
122
123 va_start(ap, fmt);
124 vsyslog(pri, fmt, ap);
125 va_end(ap);
126 }
127
128 /*
129 * Undo the commands which have created valid node/prop handle
130 * The undo order is from last command to the first command.
131 */
132 static void
undo_commands(cmdbuf_t * cmds,int last_cmd_index)133 undo_commands(cmdbuf_t *cmds, int last_cmd_index)
134 {
135 int i;
136 command_t *com = cmds->commands;
137
138 for (i = last_cmd_index; i >= 0; i--) {
139 switch (com[i].type) {
140 case TOK_NODE:
141 if (com[i].nodecmd_nodeh == NULL)
142 break;
143
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 == NULL)
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 == NULL)
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 == NULL)
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 == NULL) ||
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;
188 }
189 }
190 }
191
192 /*
193 * Get the token index from the tokens table
194 */
195 static int
get_token_id(char * t)196 get_token_id(char *t)
197 {
198 int i;
199
200 for (i = 0; i < sizeof (tokens)/ sizeof (char *); ++i)
201 if (strcasecmp(tokens[i], t) == 0)
202 return (i);
203
204 return (-1);
205 }
206
207 /*
208 * Check the version syntax and set the version_no
209 *
210 * VERSION <version_num> -- specify the configuration version
211 */
212 static int
parse_version(cmdbuf_t * cmds,char * line)213 parse_version(cmdbuf_t *cmds, char *line)
214 {
215 char *tok;
216 char *vertok;
217 char *last;
218 char *endptr;
219
220 /* get the VERSION directive */
221 tok = strtok_r(line, WHITESPACE, &last);
222 if (tok == NULL)
223 return (EC_INSUFFICIENT_TOKEN);
224
225 /* get the version number */
226 vertok = strtok_r(last, WHITESPACE, &last);
227 if (vertok == NULL)
228 return (EC_INSUFFICIENT_TOKEN);
229
230 cmds->version_no = (float)strtod(vertok, &endptr);
231 if (endptr != (vertok + strlen(vertok)))
232 return (EC_UNSUPPORTED);
233
234 if (cmds->version_no > (float)SUPPORTED_VERSION_NUM)
235 return (EC_UNSUPPORTED);
236
237 /* check if more tokens */
238 tok = strtok_r(last, WHITESPACE, &last);
239 if (tok != NULL)
240 return (EC_SYNTAX_ERR);
241
242 return (EC_SYNTAX_OK);
243 }
244
245 /*
246 * free path_cmd_t
247 */
248 static void
free_path(command_t * command)249 free_path(command_t *command)
250 {
251 free(command->pathcmd_name);
252 }
253
254 /*
255 * Check the path syntax
256 * NAMEPATH:<namepath> -- gives the anchor node
257 * or
258 * CLASSPATH:<classpath> -- gives the anchor node
259 */
260 static int
parse_path(char * line,command_t * command)261 parse_path(char *line, command_t *command)
262 {
263 char *tok;
264 char *pathtok;
265 char *last;
266
267 pathtok = strtok_r(line, WHITESPACE, &last);
268 if (pathtok == NULL)
269 return (EC_INSUFFICIENT_TOKEN);
270
271 /* check if more tokens */
272 tok = strtok_r(last, WHITESPACE, &last);
273 if (tok != NULL)
274 return (EC_SYNTAX_ERR);
275
276 command->pathcmd_name = strdup(pathtok);
277 if (command->pathcmd_name == NULL)
278 return (EC_FAILURE);
279
280 return (EC_SYNTAX_OK);
281 }
282
283 /*
284 * Process the path command and return PICL node handle
285 */
286 static int
process_path(command_t * command,picl_nodehdl_t * nodeh)287 process_path(command_t *command, picl_nodehdl_t *nodeh)
288 {
289 int err;
290
291 err = ptree_get_node_by_path(command->pathcmd_name, nodeh);
292 return (err);
293 }
294
295 /*
296 * free node_cmd_t
297 */
298 static void
free_node(command_t * command)299 free_node(command_t *command)
300 {
301 free(command->nodecmd_nodename);
302 free(command->nodecmd_classname);
303 }
304
305 /*
306 * Check the NODE syntax
307 * NODE <name> <class>
308 */
309 static int
parse_node(char * line,command_t * command)310 parse_node(char *line, command_t *command)
311 {
312 char *tok;
313 char *nametok;
314 char *classtok;
315 char *last;
316
317 /* get the NODE directive */
318 tok = strtok_r(line, WHITESPACE, &last);
319 if (tok == NULL)
320 return (EC_INSUFFICIENT_TOKEN);
321
322 /* get name */
323 nametok = strtok_r(last, WHITESPACE, &last);
324 if (nametok == NULL)
325 return (EC_INSUFFICIENT_TOKEN);
326
327 classtok = strtok_r(last, WHITESPACE, &last);
328 if (classtok == NULL)
329 return (EC_INSUFFICIENT_TOKEN);
330
331 /* check if more tokens */
332 tok = strtok_r(last, WHITESPACE, &last);
333 if (tok != NULL)
334 return (EC_SYNTAX_ERR);
335
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))
341 return (EC_FAILURE);
342
343 return (EC_SYNTAX_OK);
344 }
345
346 /*
347 * Process the NODE command and return PICL node handle
348 */
349 static int
process_node(command_t * command,picl_nodehdl_t parh,picl_nodehdl_t * nodeh)350 process_node(command_t *command, picl_nodehdl_t parh, picl_nodehdl_t *nodeh)
351 {
352 int err;
353
354 err = ptree_create_and_add_node(parh, command->nodecmd_nodename,
355 command->nodecmd_classname, nodeh);
356
357 if (err == PICL_SUCCESS)
358 command->nodecmd_nodeh = *nodeh;
359
360 return (err);
361 }
362
363 /*
364 * get the PICL property type
365 */
366 static int
getpicltype(char * type)367 getpicltype(char *type)
368 {
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);
381 }
382
383 /*
384 * get the PICL accessmode mode
385 */
386 static int
getpiclmode(char * mode)387 getpiclmode(char *mode)
388 {
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);
397 }
398
399 /*
400 * check if the size and value are valid given by the prop type
401 */
402 static int
validate_size_and_cvt_val(void * outbuf,size_t size,int type,char * val)403 validate_size_and_cvt_val(void *outbuf, size_t size, int type, char *val)
404 {
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;
416
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);
448 }
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);
478 }
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);
496 }
497 break;
498 default: /* not supported type */
499 return (EC_SYNTAX_ERR);
500 }
501
502 return (EC_SYNTAX_OK);
503 }
504
505 /*
506 * free prop_cmd_t
507 */
508 static void
free_prop(command_t * command)509 free_prop(command_t *command)
510 {
511 free(command->propcmd_pname);
512 if (command->propcmd_type != PICL_PTYPE_VOID)
513 free(command->propcmd_valbuf);
514 }
515
516 /*
517 * return the string token in two double quotes
518 * The current version won't support multiple-line string
519 */
520 static int
get_string_token(char * line,char ** valtok)521 get_string_token(char *line, char **valtok)
522 {
523 char *optr; /* ptr to the open quote */
524 char *cptr; /* ptr to the close quote */
525 char *ptr;
526 char *tmpbuf;
527
528 if (line == NULL)
529 return (EC_INSUFFICIENT_TOKEN);
530
531 /* skipping leading white spaces */
532 optr = line;
533 while ((*optr == ' ') || (*optr == '\t') || (*optr == '\n'))
534 optr++;
535
536 /* reach end of string */
537 if (*optr == '\0')
538 return (EC_INSUFFICIENT_TOKEN);
539
540 /* it's not an open double quote */
541 if (*optr != '"')
542 return (EC_SYNTAX_ERR);
543
544 /* skipping ending white spaces */
545 cptr = line + strlen(line) - 1;
546 while ((*cptr == ' ') || (*cptr == '\t') || (*cptr == '\n'))
547 cptr--;
548
549 /* it's not an close double quote */
550 if (*cptr != '"')
551 return (EC_SYNTAX_ERR);
552
553 /* close double quote is missing */
554 if (cptr == optr)
555 return (EC_SYNTAX_ERR);
556
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++;
561
562 tmpbuf = malloc(strlen(optr) + 1);
563 if (tmpbuf == NULL)
564 return (EC_FAILURE);
565
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);
573 }
574 }
575 *ptr = *optr;
576 }
577
578 *ptr = '\0';
579 *valtok = tmpbuf;
580 return (EC_SYNTAX_OK);
581 }
582
583 /*
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
591 */
592 static int
parse_prop(char * line,command_t * command)593 parse_prop(char *line, command_t *command)
594 {
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;
604
605 /* get the PROP directive */
606 tok = strtok_r(line, WHITESPACE, &last);
607 if (tok == NULL)
608 return (EC_INSUFFICIENT_TOKEN);
609
610 /* get the property name */
611 pnametok = strtok_r(last, WHITESPACE, &last);
612 if (pnametok == NULL)
613 return (EC_INSUFFICIENT_TOKEN);
614
615 /* get the type */
616 tok = strtok_r(last, WHITESPACE, &last);
617 if (tok == NULL)
618 return (EC_INSUFFICIENT_TOKEN);
619
620 if ((typetok = getpicltype(tok)) < 0)
621 return (EC_SYNTAX_ERR);
622
623 /* get mode */
624 tok = strtok_r(last, WHITESPACE, &last);
625 if (tok == NULL)
626 return (EC_INSUFFICIENT_TOKEN);
627
628 if ((modetok = getpiclmode(tok)) < 0)
629 return (EC_SYNTAX_ERR);
630
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 = NULL;
641 return (EC_SYNTAX_OK);
642 }
643
644 /* get size */
645 tok = strtok_r(last, WHITESPACE, &last);
646 if (tok == NULL)
647 return (EC_INSUFFICIENT_TOKEN);
648
649 sizetok = (size_t)strtol(tok, &endptr, 0);
650 if (endptr != (tok + strlen(tok)))
651 return (EC_SYNTAX_ERR);
652
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);
677 }
678 }
679
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 = NULL;
687 return (EC_SYNTAX_OK);
688 }
689
690 /*
691 * Add a property to the row, the row gets added to the node at endrow
692 */
693 static int
add_proph_to_row(command_t * command,picl_prophdl_t proph)694 add_proph_to_row(command_t *command, picl_prophdl_t proph)
695 {
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);
701 }
702
703 /*
704 * Process the PROP command and add the specified property under the given
705 * node handle
706 */
707 static int
process_prop(cmdbuf_t * cmds,command_t * command,picl_nodehdl_t nodeh)708 process_prop(cmdbuf_t *cmds, command_t *command, picl_nodehdl_t nodeh)
709 {
710 ptree_propinfo_t propinfo;
711 picl_prophdl_t proph;
712 int err;
713
714 /* prop in discarded row */
715 if (cmds->inside_row_block &&
716 cmds->commands[cmds->current_row].rowcmd_nproph == 0)
717 return (PICL_SUCCESS);
718
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);
723
724 if (err != PICL_SUCCESS)
725 return (err);
726
727 err = ptree_create_prop(&propinfo, command->propcmd_valbuf, &proph);
728
729 if (err != PICL_SUCCESS)
730 return (err);
731
732 command->propcmd_proph = proph;
733
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);
739 }
740
741 return (err);
742 }
743
744 /*
745 * free refnode_cmd_t
746 */
747 static void
free_refnode(command_t * command)748 free_refnode(command_t *command)
749 {
750 free(command->refnodecmd_name);
751 free(command->refnodecmd_class);
752 free(command->refnodecmd_dstnode);
753 }
754
755 /*
756 * Check the REFNODE syntax
757 *
758 * REFNODE <name> <class> with <destnode> -- if <destnode> exists,
759 * create node with nodename <name> and piclclass <class>
760 */
761 static int
parse_refnode(char * line,command_t * command)762 parse_refnode(char *line, command_t *command)
763 {
764 char *tok;
765 char *dsttok;
766 char *classnm;
767 char *nodenm;
768 char *last;
769
770 /* get the directive */
771 tok = strtok_r(line, WHITESPACE, &last);
772 if (tok == NULL)
773 return (EC_INSUFFICIENT_TOKEN);
774
775 /* get the nodename */
776 nodenm = strtok_r(last, WHITESPACE, &last);
777 if (nodenm == NULL)
778 return (EC_INSUFFICIENT_TOKEN);
779
780 /* get the class */
781 classnm = strtok_r(last, WHITESPACE, &last);
782 if (classnm == NULL)
783 return (EC_INSUFFICIENT_TOKEN);
784
785 /* get the WITH keyword */
786 tok = strtok_r(last, WHITESPACE, &last);
787 if (tok == NULL)
788 return (EC_INSUFFICIENT_TOKEN);
789
790 if (strcasecmp(tok, KEYWORD_WITH_STR) != 0)
791 return (EC_SYNTAX_ERR);
792
793 /* get the dst node */
794 dsttok = strtok_r(last, WHITESPACE, &last);
795 if (dsttok == NULL)
796 return (EC_INSUFFICIENT_TOKEN);
797
798 /* check if more tokens */
799 tok = strtok_r(last, WHITESPACE, &last);
800 if (tok != NULL)
801 return (EC_SYNTAX_ERR);
802
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))
810 return (EC_FAILURE);
811
812 return (EC_SYNTAX_OK);
813 }
814
815 /*
816 * Process the REFNODE command
817 */
818 static int
process_refnode(command_t * command,picl_nodehdl_t parh)819 process_refnode(command_t *command, picl_nodehdl_t parh)
820 {
821 picl_nodehdl_t dsth;
822 picl_nodehdl_t nodeh;
823 int err;
824
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;
831
832 return (err);
833 }
834
835 return (PICL_SUCCESS);
836 }
837
838 /*
839 * free refprop_cmd_t
840 */
841 static void
free_refprop(command_t * command)842 free_refprop(command_t *command)
843 {
844 free(command->refpropcmd_pname);
845 free(command->refpropcmd_dstnode);
846 }
847
848 /*
849 * Check the REFPROP syntax
850 *
851 * REFPROP <prop> <destnode> -- creates a reference property to <destnode>
852 */
853 static int
parse_refprop(char * line,command_t * command)854 parse_refprop(char *line, command_t *command)
855 {
856 char *tok;
857 char *pnametok;
858 char *dsttok;
859 char *last;
860
861 /* get the REFPROP directive */
862 tok = strtok_r(line, WHITESPACE, &last);
863 if (tok == NULL)
864 return (EC_INSUFFICIENT_TOKEN);
865
866 /* get the propname */
867 pnametok = strtok_r(last, WHITESPACE, &last);
868 if (pnametok == NULL)
869 return (EC_INSUFFICIENT_TOKEN);
870
871 dsttok = strtok_r(last, WHITESPACE, &last);
872 if (dsttok == NULL)
873 return (EC_INSUFFICIENT_TOKEN);
874
875 /* check if more tokens */
876 tok = strtok_r(last, WHITESPACE, &last);
877 if (tok != NULL)
878 return (EC_SYNTAX_ERR);
879
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))
885 return (EC_FAILURE);
886
887 return (EC_SYNTAX_OK);
888 }
889
890 /*
891 * Process the REFPROP command
892 */
893 static int
process_refprop(cmdbuf_t * cmds,command_t * command,picl_nodehdl_t nodeh)894 process_refprop(cmdbuf_t *cmds, command_t *command, picl_nodehdl_t nodeh)
895 {
896 int err;
897 picl_nodehdl_t dsth;
898 picl_prophdl_t proph;
899 ptree_propinfo_t propinfo;
900
901 /* refprop in discarded row */
902 if (cmds->inside_row_block &&
903 cmds->commands[cmds->current_row].rowcmd_nproph == 0)
904 return (PICL_SUCCESS);
905
906 /* try finding the refprop's dstnode */
907 err = ptree_get_node_by_path(command->refpropcmd_dstnode, &dsth);
908
909 /* dstnode doesn't exist, return */
910 if (err != PICL_SUCCESS)
911 return (err);
912
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);
917
918 if (err != PICL_SUCCESS)
919 return (err);
920
921 err = ptree_create_prop(&propinfo, &dsth, &proph);
922
923 if (err != PICL_SUCCESS)
924 return (err);
925
926 command->refpropcmd_proph = proph;
927
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);
933 }
934
935 return (err);
936 }
937
938 /*
939 * free table_cmd_t
940 */
941 static void
free_table(command_t * command)942 free_table(command_t *command)
943 {
944 if (command->tablecmd_tname)
945 free(command->tablecmd_tname);
946 }
947
948 /*
949 * Check the TABLE syntax
950 * TABLE <table_prop_name>
951 *
952 */
953 static int
parse_table(char * line,command_t * command)954 parse_table(char *line, command_t *command)
955 {
956 char *tok = NULL;
957 char *tnametok = NULL;
958 char *last = NULL;
959
960 /* get the TABLE directive */
961 tok = strtok_r(line, WHITESPACE, &last);
962 if (tok == NULL)
963 return (EC_INSUFFICIENT_TOKEN);
964
965 /* get the property name */
966 tnametok = strtok_r(last, WHITESPACE, &last);
967 if (tnametok == NULL)
968 return (EC_INSUFFICIENT_TOKEN);
969
970 command->tablecmd_tname = strdup(tnametok);
971 if (command->tablecmd_tname == NULL)
972 return (EC_FAILURE);
973
974 command->tablecmd_newtbl = 0;
975 command->tablecmd_tblh = NULL;
976
977 return (EC_SYNTAX_OK);
978 }
979
980 /*
981 * Process the TABLE command and add the specified property under the given
982 * node handle
983 */
984 static int
process_table(command_t * command,picl_nodehdl_t nodeh)985 process_table(command_t *command, picl_nodehdl_t nodeh)
986 {
987 int err;
988 picl_prophdl_t tblh;
989 picl_prophdl_t proph;
990 ptree_propinfo_t propinfo;
991
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)
997 return (err);
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);
1004 }
1005
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)
1011 return (err);
1012
1013 err = ptree_create_table(&tblh);
1014 if (err != PICL_SUCCESS)
1015 return (err);
1016
1017 command->tablecmd_newtbl = 1;
1018 command->tablecmd_tblh = tblh;
1019
1020 err = ptree_create_prop(&propinfo, &tblh, &proph);
1021 if (err != PICL_SUCCESS)
1022 return (err);
1023
1024 err = ptree_add_prop(nodeh, proph);
1025
1026 return (err);
1027 }
1028
1029 /*
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.
1032 */
1033 static int
process_row(command_t * command)1034 process_row(command_t *command)
1035 {
1036 command->rowcmd_index = 0;
1037 command->rowcmd_prophs =
1038 malloc(command->rowcmd_nproph * sizeof (picl_prophdl_t));
1039
1040 if (command->rowcmd_prophs == NULL)
1041 return (PICL_FAILURE);
1042
1043 return (PICL_SUCCESS);
1044 }
1045
1046 /*
1047 * Process the ENDROW command. If a valid row, add the row to the ptree.
1048 */
1049 static int
process_endrow(cmdbuf_t * cmds)1050 process_endrow(cmdbuf_t *cmds)
1051 {
1052 int err;
1053 int i;
1054 command_t *curr_row;
1055
1056 curr_row = &cmds->commands[cmds->current_row];
1057
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]);
1063 }
1064 err = PICL_SUCCESS;
1065 } else
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);
1070
1071 /* let go the space alloc'd in process_row */
1072 free(curr_row->rowcmd_prophs);
1073 curr_row->rowcmd_prophs = NULL;
1074
1075 return (err);
1076 }
1077
1078 /*
1079 * Check the VERBOSE syntax
1080 * VERBOSE <level>
1081 */
1082 static int
parse_verbose(cmdbuf_t * cmds,char * line,command_t * command)1083 parse_verbose(cmdbuf_t *cmds, char *line, command_t *command)
1084 {
1085 char *tok;
1086 char *level;
1087 char *last;
1088 char *endptr;
1089 int verbose_level;
1090
1091 /* get the VERBOSE directive */
1092 tok = strtok_r(line, WHITESPACE, &last);
1093 if (tok == NULL)
1094 return (EC_INSUFFICIENT_TOKEN);
1095
1096 /* get verbose level */
1097 level = strtok_r(last, WHITESPACE, &last);
1098 if (level == NULL)
1099 return (EC_INSUFFICIENT_TOKEN);
1100 verbose_level = strtol(level, &endptr, 0);
1101 if (endptr != (level + strlen(level)))
1102 return (EC_SYNTAX_ERR);
1103
1104 /* check if more tokens */
1105 tok = strtok_r(last, WHITESPACE, &last);
1106 if (tok != NULL)
1107 return (EC_SYNTAX_ERR);
1108
1109 cmds->verbose = verbose_level;
1110 command->verbosecmd_level = verbose_level;
1111
1112 return (EC_SYNTAX_OK);
1113 }
1114
1115 /*
1116 * Process the VERBOSE command to set the verbose level
1117 */
1118 static int
process_verbose(cmdbuf_t * cmds,command_t * command)1119 process_verbose(cmdbuf_t *cmds, command_t *command)
1120 {
1121 cmds->verbose = command->verbosecmd_level;
1122 return (PICL_SUCCESS);
1123 }
1124
1125 /*
1126 * parse and tokenize the line
1127 */
1128 static int
parse_and_tokenize_line(cmdbuf_t * cmds,char * buf,command_t * command)1129 parse_and_tokenize_line(cmdbuf_t *cmds, char *buf, command_t *command)
1130 {
1131 char rec[RECORD_SIZE_MAX];
1132 char *tok;
1133 int err;
1134 char *last;
1135 int id;
1136
1137 (void) strcpy(rec, buf);
1138 tok = strtok_r(rec, RECORD_WHITESPACE, &last);
1139 if (tok == NULL)
1140 return (EC_INSUFFICIENT_TOKEN);
1141
1142 id = get_token_id(tok);
1143
1144 (void) strcpy(rec, buf);
1145
1146 switch (id) {
1147 case TOK_VERSION:
1148 err = parse_version(cmds, rec);
1149 break;
1150 case TOK_CLASSPATH:
1151 case TOK_NAMEPATH:
1152 if (cmds->inside_node_block != 0)
1153 return (EC_PATH_ERR);
1154
1155 err = parse_path(rec, command);
1156 if (err != EC_SYNTAX_OK)
1157 return (err);
1158 break;
1159 case TOK_NODE:
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)
1166 return (err);
1167 cmds->inside_node_block++;
1168 break;
1169 case TOK_ENDNODE:
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--;
1175 err = EC_SYNTAX_OK;
1176 break;
1177 case TOK_PROP:
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)
1184 return (err);
1185 if (cmds->inside_row_block) {
1186 cmds->commands[cmds->current_row].rowcmd_nproph++;
1187 }
1188 break;
1189 case TOK_REFNODE:
1190 err = parse_refnode(rec, command);
1191 if (err != EC_SYNTAX_OK)
1192 return (err);
1193 break;
1194 case TOK_REFPROP:
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)
1201 return (err);
1202 if (cmds->inside_row_block) {
1203 cmds->commands[cmds->current_row].rowcmd_nproph++;
1204 }
1205 break;
1206 case TOK_TABLE:
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)
1214 return (err);
1215 cmds->inside_table_block = 1;
1216 break;
1217 case TOK_ENDTABLE:
1218 /* Check for ENDTABLE before TABLE */
1219 if (cmds->inside_table_block == 0)
1220 return (EC_SYNTAX_ERR);
1221
1222 cmds->inside_table_block = 0;
1223
1224 break;
1225 case TOK_ROW:
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;
1231 break;
1232 case TOK_ENDROW:
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);
1237 else
1238 err = EC_SYNTAX_OK;
1239
1240 cmds->inside_row_block = 0;
1241
1242 /* error if row is empty */
1243 if (cmds->commands[cmds->current_row].rowcmd_nproph <= 0)
1244 return (EC_ROW_EMPTY);
1245 break;
1246 case TOK_VERBOSE:
1247 err = parse_verbose(cmds, rec, command);
1248 if (err != EC_SYNTAX_OK)
1249 return (err);
1250 break;
1251 default: /* unsupported command */
1252 return (EC_SYNTAX_ERR);
1253 }
1254
1255 command->type = id;
1256 return (EC_SYNTAX_OK);
1257 }
1258
1259 /*
1260 * Check the syntax and save the tokens in the commands buffer
1261 */
1262 static int
check_line_syntax(cmdbuf_t * cmds,char * buf)1263 check_line_syntax(cmdbuf_t *cmds, char *buf)
1264 {
1265 int err;
1266 command_t command;
1267
1268 (void) memset(&command, 0, sizeof (command_t));
1269 err = parse_and_tokenize_line(cmds, buf, &command);
1270 if (err != EC_SYNTAX_OK)
1271 return (err);
1272
1273 /*
1274 * don't add and count version command in the command buffer
1275 */
1276 if (command.type == TOK_VERSION)
1277 return (EC_SYNTAX_OK);
1278
1279 /*
1280 * check if the commands buffer has been filled
1281 * If it is full, reallocate the buffer.
1282 */
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;
1289 }
1290
1291 cmds->commands[cmds->count] = command; /* copy */
1292
1293 /*
1294 * make a note of the row/endrow command, to keep track of # of props
1295 */
1296 if (command.type == TOK_ROW)
1297 cmds->current_row = cmds->count;
1298
1299 if (command.type == TOK_ENDROW)
1300 cmds->current_row = 0;
1301
1302 cmds->count++;
1303
1304 return (EC_SYNTAX_OK);
1305 }
1306
1307 /*
1308 * get the line control information
1309 * return 1 if it's the line control information, else return 0
1310 */
1311 static int
get_line_control_info(char * buf,uint32_t * linenum,char * filename)1312 get_line_control_info(char *buf, uint32_t *linenum, char *filename)
1313 {
1314 char *ptr;
1315 char *last;
1316 uint32_t num;
1317 char *fname;
1318 char *endptr;
1319
1320 /* skip # and get next string */
1321 ptr = strtok_r(buf + 1, WHITESPACE, &last);
1322 if (ptr == NULL) {
1323 return (0);
1324 }
1325
1326 num = strtoul(ptr, &endptr, 0);
1327
1328 /*
1329 * It's not the line control information
1330 */
1331 if (endptr != (ptr + strlen(ptr))) {
1332 return (0);
1333 }
1334
1335 /*
1336 * get the filename
1337 */
1338
1339 /* get the beginning double quote */
1340 last = strchr(last, '"');
1341 if (last == NULL)
1342 return (0);
1343
1344 last++;
1345
1346 /* get the ending double quote */
1347 fname = strtok_r(last, DOUBLE_QUOTE, &last);
1348 if (fname == NULL)
1349 return (0);
1350
1351 *linenum = num;
1352 (void) strlcpy(filename, fname, PATH_MAX);
1353 return (1);
1354 }
1355
1356 /*
1357 * check the syntax of the configuration file
1358 */
1359 static int
check_conffile_syntax(cmdbuf_t * cmds,FILE * fp)1360 check_conffile_syntax(cmdbuf_t *cmds, FILE *fp)
1361 {
1362 char lbuf[RECORD_SIZE_MAX];
1363 char buf[RECORD_SIZE_MAX];
1364 uint32_t linenum;
1365 char cppfile[PATH_MAX] = "";
1366 int err = EC_SYNTAX_OK;
1367
1368 linenum = 0;
1369 while (fgets(buf, sizeof (buf), fp) != NULL) {
1370 /*
1371 * get cpp line control information, if any
1372 */
1373 if (buf[0] == '#') {
1374 if (!get_line_control_info(buf, &linenum, cppfile))
1375 ++linenum;
1376 continue;
1377 }
1378
1379 ++linenum;
1380 /*
1381 * skip line whose first char is a newline char
1382 */
1383 if (buf[0] == '\n') {
1384 continue;
1385 }
1386
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 */
1391 err = EC_FAILURE;
1392 break;
1393 }
1394
1395 err = check_line_syntax(cmds, lbuf);
1396 if ((err != EC_INSUFFICIENT_TOKEN) && (err != EC_SYNTAX_OK))
1397 break;
1398 }
1399
1400 if (err != EC_SYNTAX_OK) {
1401 if (cmds->verbose) {
1402 verbose_log(LOG_ERR, err_msg[err],
1403 cmds->fname, cppfile, linenum);
1404 }
1405 return (err);
1406 }
1407
1408 /*
1409 * check if the version has been set
1410 */
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);
1415 }
1416 return (EC_UNSUPPORTED);
1417 }
1418
1419 /*
1420 * check if node and endnode command mismatch
1421 */
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);
1426 }
1427 return (EC_NODE_MISMATCH);
1428 }
1429
1430 /*
1431 * check if row and endrow command mismatch
1432 */
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);
1437 }
1438 return (EC_ROW_MISMATCH);
1439 }
1440
1441 /*
1442 * check if table and endtable command mismatch
1443 */
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);
1448 }
1449 return (EC_TABLE_MISMATCH);
1450 }
1451
1452 return (EC_SYNTAX_OK);
1453 }
1454
1455 /*
1456 * If classpath/namepath given is not found in the picl tree,
1457 * skip the whole blocks until next valid classpath or namepath
1458 */
1459 static void
skip_to_next_valid_path(cmdbuf_t * cmds,int starting_index,picl_nodehdl_t * parent,int * last_processed_index)1460 skip_to_next_valid_path(cmdbuf_t *cmds, int starting_index,
1461 picl_nodehdl_t *parent, int *last_processed_index)
1462 {
1463 int err;
1464 int index;
1465
1466 for (index = starting_index; index < cmds->count; ++index) {
1467 switch (cmds->commands[index].type) {
1468 case TOK_CLASSPATH:
1469 case TOK_NAMEPATH:
1470 err = process_path(&cmds->commands[index], parent);
1471 if (err == PICL_SUCCESS) {
1472 *last_processed_index = index;
1473 return;
1474 }
1475 default:
1476 /* skipped this line */
1477 break;
1478 }
1479 }
1480
1481 /* reach last command */
1482 *last_processed_index = cmds->count - 1;
1483 }
1484
1485 /*
1486 * Process the command buffer and return last command index and the new head of
1487 * the handle list
1488 */
1489 static int
process_commands(cmdbuf_t * cmds,int starting_index,picl_nodehdl_t parent,int * last_processed_index)1490 process_commands(cmdbuf_t *cmds, int starting_index, picl_nodehdl_t parent,
1491 int *last_processed_index)
1492 {
1493 int err;
1494 int index;
1495 picl_nodehdl_t rooth;
1496 picl_nodehdl_t nodeh;
1497 command_t *commands = cmds->commands;
1498
1499 for (index = starting_index; index < cmds->count; ++index) {
1500 switch (commands[index].type) {
1501 case TOK_CLASSPATH:
1502 case TOK_NAMEPATH:
1503 err = process_path(&commands[index], &rooth);
1504 if (err != PICL_SUCCESS) {
1505 index++;
1506 (void) skip_to_next_valid_path(cmds, index,
1507 &rooth, &index);
1508 }
1509 parent = rooth;
1510 continue;
1511 case TOK_NODE:
1512 err = process_node(&commands[index], parent, &nodeh);
1513 if (err == PICL_SUCCESS) {
1514 index++;
1515 err = process_commands(cmds, index, nodeh,
1516 &index);
1517 }
1518 break;
1519 case TOK_ENDNODE:
1520 *last_processed_index = index;
1521 return (PICL_SUCCESS);
1522 case TOK_PROP:
1523 err = process_prop(cmds, &commands[index], parent);
1524 break;
1525 case TOK_REFPROP:
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]
1533 .rowcmd_nproph = 0;
1534 }
1535 break;
1536 case TOK_REFNODE:
1537 err = process_refnode(&commands[index], parent);
1538 break;
1539 case TOK_TABLE:
1540 cmds->inside_table_block = 1;
1541 err = process_table(&commands[index], parent);
1542 cmds->current_tbl = index;
1543 break;
1544 case TOK_ENDTABLE:
1545 cmds->inside_table_block = 0;
1546 cmds->current_tbl = 0;
1547 break;
1548 case TOK_ROW:
1549 cmds->inside_row_block = 1;
1550 err = process_row(&commands[index]);
1551 cmds->current_row = index;
1552 break;
1553 case TOK_ENDROW:
1554 err = process_endrow(cmds);
1555 cmds->inside_row_block = 0;
1556 cmds->current_row = 0;
1557 break;
1558 case TOK_VERBOSE:
1559 err = process_verbose(cmds, &commands[index]);
1560 break;
1561 default: /* won't reach here */
1562 err = PICL_FAILURE;
1563 break;
1564 }
1565
1566 if ((err != PICL_SUCCESS) && (err != PICL_PROPEXISTS)) {
1567 *last_processed_index = index;
1568 return (err);
1569 }
1570 }
1571
1572 /* reach last command */
1573 *last_processed_index = cmds->count - 1;
1574 return (PICL_SUCCESS);
1575 }
1576
1577 /*
1578 * clean up the commands buffer
1579 */
1580 static void
clean_up(cmdbuf_t * cmds)1581 clean_up(cmdbuf_t *cmds)
1582 {
1583 int cmd_index;
1584
1585 for (cmd_index = 0; cmd_index < cmds->count; cmd_index++) {
1586 switch (cmds->commands[cmd_index].type) {
1587 case TOK_CLASSPATH:
1588 case TOK_NAMEPATH:
1589 free_path(&cmds->commands[cmd_index]);
1590 break;
1591 case TOK_NODE:
1592 free_node(&cmds->commands[cmd_index]);
1593 break;
1594 case TOK_PROP:
1595 free_prop(&cmds->commands[cmd_index]);
1596 break;
1597 case TOK_REFPROP:
1598 free_refprop(&cmds->commands[cmd_index]);
1599 break;
1600 case TOK_REFNODE:
1601 free_refnode(&cmds->commands[cmd_index]);
1602 break;
1603 case TOK_TABLE:
1604 free_table(&cmds->commands[cmd_index]);
1605 break;
1606 case TOK_ENDTABLE:
1607 case TOK_ROW:
1608 case TOK_ENDROW:
1609 case TOK_ENDNODE:
1610 case TOK_VERBOSE:
1611 default:
1612 break;
1613 }
1614 }
1615 if (cmds->commands)
1616 free(cmds->commands);
1617 }
1618
1619 /*
1620 * Parse the configuration file and create nodes/properties under nh
1621 *
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.
1624 *
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.
1628 *
1629 * If success, return 0.
1630 */
1631 int
picld_pluginutil_parse_config_file(picl_nodehdl_t nh,const char * filename)1632 picld_pluginutil_parse_config_file(picl_nodehdl_t nh, const char *filename)
1633 {
1634 FILE *ifp;
1635 int last_processed_index;
1636 int err;
1637 cmdbuf_t *cmds;
1638
1639 /* set correct locale for use inside pluginutil */
1640 setlocale(LC_ALL, "C");
1641
1642 /*
1643 * Initialize the command buffer
1644 */
1645
1646 cmds = malloc(sizeof (*cmds));
1647 if (cmds == NULL) {
1648 setlocale(LC_ALL, "");
1649 return (1);
1650 }
1651
1652 memset(cmds, 0, sizeof (cmdbuf_t));
1653
1654 cmds->fname = filename;
1655
1656 ifp = fopen(filename, "r");
1657 if (ifp == NULL) {
1658 setlocale(LC_ALL, "");
1659 free(cmds);
1660 return (1);
1661 }
1662
1663 /*
1664 * check the syntax of the configuration file
1665 */
1666 err = check_conffile_syntax(cmds, ifp);
1667
1668 (void) fclose(ifp);
1669
1670 if (err != EC_SYNTAX_OK) {
1671 clean_up(cmds);
1672 free(cmds);
1673 setlocale(LC_ALL, "");
1674 return (1);
1675 }
1676
1677 /*
1678 * Process the commands
1679 */
1680 err = process_commands(cmds, STARTING_INDEX, nh, &last_processed_index);
1681
1682 /*
1683 * If any PICL error, remove the newly created node/prop
1684 * handles from the PICL tree.
1685 */
1686 if (err != PICL_SUCCESS) {
1687 undo_commands(cmds, last_processed_index);
1688 if (cmds->verbose)
1689 verbose_log(LOG_ERR, err_msg[EC_PICL_ERR], filename,
1690 err);
1691 }
1692
1693 clean_up(cmds);
1694 free(cmds);
1695
1696 /* reset the locale */
1697 setlocale(LC_ALL, "");
1698
1699 return ((err == PICL_SUCCESS) ? 0 : 1);
1700 }
1701