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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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