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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This module implements the routine to parse the configuration file. 31 */ 32 33 34 #include <stdio.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include <stdlib.h> 38 #include <stdarg.h> 39 #include <string.h> 40 #include <ctype.h> 41 #include <alloca.h> 42 #include <limits.h> 43 #include <sys/utsname.h> 44 #include <sys/systeminfo.h> 45 #include <sys/types.h> 46 #include <libintl.h> 47 #include <syslog.h> 48 #include <locale.h> 49 #include <picl.h> 50 #include <picltree.h> 51 #include "picld_pluginutil.h" 52 #include "picld_pluginutil_impl.h" 53 54 /* error codes returned from syntax checking */ 55 #define EC_SYNTAX_OK 0 56 #define EC_INSUFFICIENT_TOKEN 1 57 #define EC_SYNTAX_ERR 2 58 #define EC_UNSUPPORTED 3 59 #define EC_PATH_ERR 4 60 #define EC_NODE_MISMATCH 5 61 #define EC_FAILURE 6 62 #define EC_PICL_ERR 7 63 #define EC_TABLE_MISMATCH 8 64 #define EC_ROW_MISMATCH 9 65 #define EC_ROW_EMPTY 10 66 67 /* 68 * Error message texts 69 */ 70 static char *err_msg[] = { 71 "%s: Syntax OK", /* 0 */ 72 "%s::%s[line %d]: Insufficient token\n", /* 1 */ 73 "%s::%s[line %d]: Syntax error\n", /* 2 */ 74 "%s::%s[line %d]: Unsupported or missing version\n", /* 3 */ 75 "%s::%s[line %d]: Illegal use of nodepath or namepath\n", /* 4 */ 76 "%s::%s[line %d]: Node and endnode mismatch\n", /* 5 */ 77 "%s::%s[line %d]: General system failure\n", /* 6 */ 78 "%s: PICL error code %d\n", /* 7 */ 79 "%s::%s[line %d]: Table and endtable mismatch\n", /* 8 */ 80 "%s::%s[line %d]: Row and endrow mismatch\n", /* 9 */ 81 "%s::%s[line %d]: Row has no entries \n" /* 10 */ 82 }; 83 84 /* token per directive */ 85 #define TOK_CLASSPATH 0 86 #define TOK_NAMEPATH 1 87 #define TOK_NODE 2 88 #define TOK_ENDNODE 3 89 #define TOK_PROP 4 90 #define TOK_REFPROP 5 91 #define TOK_VERSION 6 92 #define TOK_REFNODE 7 93 #define TOK_VERBOSE 8 94 #define TOK_TABLE 9 95 #define TOK_ENDTABLE 10 96 #define TOK_ROW 11 97 #define TOK_ENDROW 12 98 99 static const char *tokens[] = { 100 "_class", /* _CLASS:<classpath> */ 101 "name", /* NAME:<namepath> */ 102 "node", /* NODE <name> <class> */ 103 "endnode", /* ENDNODE */ 104 "prop", /* PROP <name> <type> <access_mode> <size> <value> */ 105 "refprop", /* REFPROP <prop> <destnode> */ 106 "version", /* VERSION <version_number> */ 107 "refnode", /* REFNODE <node> <class> WITH <destnode> */ 108 "verbose", /* VERBOSE <level> */ 109 "table", /* TABLE <table_prop_name> */ 110 "endtable", /* ENDTABLE */ 111 "row", /* ROW */ 112 "endrow" /* ENDROW */ 113 }; 114 115 #define BUF_SIZE_MAX 1024 116 117 /* 118 * print error message 119 */ 120 /*VARARGS2*/ 121 static void 122 verbose_log(int pri, const char *fmt, ...) 123 { 124 va_list ap; 125 126 va_start(ap, fmt); 127 vsyslog(pri, fmt, ap); 128 va_end(ap); 129 } 130 131 /* 132 * Undo the commands which have created valid node/prop handle 133 * The undo order is from last command to the first command. 134 */ 135 static void 136 undo_commands(cmdbuf_t *cmds, int last_cmd_index) 137 { 138 int i; 139 command_t *com = cmds->commands; 140 141 for (i = last_cmd_index; i >= 0; i--) { 142 switch (com[i].type) { 143 case TOK_NODE: 144 if (com[i].nodecmd_nodeh == NULL) 145 break; 146 147 (void) ptree_delete_node(com[i].nodecmd_nodeh); 148 (void) ptree_destroy_node(com[i].nodecmd_nodeh); 149 break; 150 case TOK_REFNODE: 151 if (com[i].refnodecmd_nodeh == NULL) 152 break; 153 (void) ptree_delete_node(com[i].refnodecmd_nodeh); 154 (void) ptree_destroy_node(com[i].refnodecmd_nodeh); 155 break; 156 case TOK_PROP: 157 if (com[i].propcmd_proph == NULL) 158 break; 159 (void) ptree_delete_prop(com[i].propcmd_proph); 160 (void) ptree_destroy_prop(com[i].propcmd_proph); 161 break; 162 case TOK_REFPROP: 163 if (com[i].refpropcmd_proph == NULL) 164 break; 165 (void) ptree_delete_prop(com[i].refpropcmd_proph); 166 (void) ptree_destroy_prop(com[i].refpropcmd_proph); 167 break; 168 case TOK_TABLE: 169 if ((com[i].tablecmd_tblh == NULL) || 170 (com[i].tablecmd_newtbl == 0)) 171 break; 172 (void) ptree_delete_prop(com[i].tablecmd_tblh); 173 (void) ptree_destroy_prop(com[i].tablecmd_tblh); 174 break; 175 case TOK_ENDTABLE: 176 /*FALLTHROUGH*/ 177 case TOK_ROW: 178 /*FALLTHROUGH*/ 179 case TOK_ENDROW: 180 /*FALLTHROUGH*/ 181 case TOK_NAMEPATH: 182 /*FALLTHROUGH*/ 183 case TOK_CLASSPATH: 184 /*FALLTHROUGH*/ 185 case TOK_ENDNODE: 186 /*FALLTHROUGH*/ 187 case TOK_VERBOSE: 188 /*FALLTHROUGH*/ 189 default: 190 break; 191 } 192 } 193 } 194 195 /* 196 * Get the token index from the tokens table 197 */ 198 static int 199 get_token_id(char *t) 200 { 201 int i; 202 203 for (i = 0; i < sizeof (tokens)/ sizeof (char *); ++i) 204 if (strcasecmp(tokens[i], t) == 0) 205 return (i); 206 207 return (-1); 208 } 209 210 /* 211 * Check the version syntax and set the version_no 212 * 213 * VERSION <version_num> -- specify the configuration version 214 */ 215 static int 216 parse_version(cmdbuf_t *cmds, char *line) 217 { 218 char *tok; 219 char *vertok; 220 char *last; 221 char *endptr; 222 223 /* get the VERSION directive */ 224 tok = strtok_r(line, WHITESPACE, &last); 225 if (tok == NULL) 226 return (EC_INSUFFICIENT_TOKEN); 227 228 /* get the version number */ 229 vertok = strtok_r(last, WHITESPACE, &last); 230 if (vertok == NULL) 231 return (EC_INSUFFICIENT_TOKEN); 232 233 cmds->version_no = (float)strtod(vertok, &endptr); 234 if (endptr != (vertok + strlen(vertok))) 235 return (EC_UNSUPPORTED); 236 237 if (cmds->version_no > (float)SUPPORTED_VERSION_NUM) 238 return (EC_UNSUPPORTED); 239 240 /* check if more tokens */ 241 tok = strtok_r(last, WHITESPACE, &last); 242 if (tok != NULL) 243 return (EC_SYNTAX_ERR); 244 245 return (EC_SYNTAX_OK); 246 } 247 248 /* 249 * free path_cmd_t 250 */ 251 static void 252 free_path(command_t *command) 253 { 254 free(command->pathcmd_name); 255 } 256 257 /* 258 * Check the path syntax 259 * NAMEPATH:<namepath> -- gives the anchor node 260 * or 261 * CLASSPATH:<classpath> -- gives the anchor node 262 */ 263 static int 264 parse_path(char *line, command_t *command) 265 { 266 char *tok; 267 char *pathtok; 268 char *last; 269 270 pathtok = strtok_r(line, WHITESPACE, &last); 271 if (pathtok == NULL) 272 return (EC_INSUFFICIENT_TOKEN); 273 274 /* check if more tokens */ 275 tok = strtok_r(last, WHITESPACE, &last); 276 if (tok != NULL) 277 return (EC_SYNTAX_ERR); 278 279 command->pathcmd_name = strdup(pathtok); 280 if (command->pathcmd_name == NULL) 281 return (EC_FAILURE); 282 283 return (EC_SYNTAX_OK); 284 } 285 286 /* 287 * Process the path command and return PICL node handle 288 */ 289 static int 290 process_path(command_t *command, picl_nodehdl_t *nodeh) 291 { 292 int err; 293 294 err = ptree_get_node_by_path(command->pathcmd_name, nodeh); 295 return (err); 296 } 297 298 /* 299 * free node_cmd_t 300 */ 301 static void 302 free_node(command_t *command) 303 { 304 free(command->nodecmd_nodename); 305 free(command->nodecmd_classname); 306 } 307 308 /* 309 * Check the NODE syntax 310 * NODE <name> <class> 311 */ 312 static int 313 parse_node(char *line, command_t *command) 314 { 315 char *tok; 316 char *nametok; 317 char *classtok; 318 char *last; 319 320 /* get the NODE directive */ 321 tok = strtok_r(line, WHITESPACE, &last); 322 if (tok == NULL) 323 return (EC_INSUFFICIENT_TOKEN); 324 325 /* get name */ 326 nametok = strtok_r(last, WHITESPACE, &last); 327 if (nametok == NULL) 328 return (EC_INSUFFICIENT_TOKEN); 329 330 classtok = strtok_r(last, WHITESPACE, &last); 331 if (classtok == NULL) 332 return (EC_INSUFFICIENT_TOKEN); 333 334 /* check if more tokens */ 335 tok = strtok_r(last, WHITESPACE, &last); 336 if (tok != NULL) 337 return (EC_SYNTAX_ERR); 338 339 command->nodecmd_nodename = strdup(nametok); 340 command->nodecmd_classname = strdup(classtok); 341 command->nodecmd_nodeh = NULL; 342 if ((command->nodecmd_nodename == NULL) || 343 (command->nodecmd_classname == NULL)) 344 return (EC_FAILURE); 345 346 return (EC_SYNTAX_OK); 347 } 348 349 /* 350 * Process the NODE command and return PICL node handle 351 */ 352 static int 353 process_node(command_t *command, picl_nodehdl_t parh, picl_nodehdl_t *nodeh) 354 { 355 int err; 356 357 err = ptree_create_and_add_node(parh, command->nodecmd_nodename, 358 command->nodecmd_classname, nodeh); 359 360 if (err == PICL_SUCCESS) 361 command->nodecmd_nodeh = *nodeh; 362 363 return (err); 364 } 365 366 /* 367 * get the PICL property type 368 */ 369 static int 370 getpicltype(char *type) 371 { 372 if (strcasecmp(type, KEYWORD_INT_TYPE) == 0) 373 return (PICL_PTYPE_INT); 374 else if (strcasecmp(type, KEYWORD_UINT_TYPE) == 0) 375 return (PICL_PTYPE_UNSIGNED_INT); 376 else if (strcasecmp(type, KEYWORD_FLOAT_TYPE) == 0) 377 return (PICL_PTYPE_FLOAT); 378 else if (strcasecmp(type, KEYWORD_STRING_TYPE) == 0) 379 return (PICL_PTYPE_CHARSTRING); 380 else if (strcasecmp(type, KEYWORD_VOID_TYPE) == 0) 381 return (PICL_PTYPE_VOID); 382 else 383 return (-1); 384 } 385 386 /* 387 * get the PICL accessmode mode 388 */ 389 static int 390 getpiclmode(char *mode) 391 { 392 if (strcasecmp(mode, KEYWORD_READ_MODE) == 0) 393 return (PICL_READ); 394 else if (strcasecmp(mode, KEYWORD_WRITE_MODE) == 0) 395 return (PICL_WRITE); 396 else if (strcasecmp(mode, KEYWORD_READWRITE_MODE) == 0) 397 return (PICL_READ|PICL_WRITE); 398 else 399 return (-1); 400 } 401 402 /* 403 * check if the size and value are valid given by the prop type 404 */ 405 static int 406 validate_size_and_cvt_val(void *outbuf, size_t size, int type, char *val) 407 { 408 int64_t llval; 409 int32_t intval; 410 int16_t sval; 411 int8_t cval; 412 uint64_t ullval; 413 uint32_t uintval; 414 uint16_t usval; 415 uint8_t ucval; 416 float fval; 417 double dval; 418 char *endptr; 419 420 switch (type) { 421 case PICL_PTYPE_CHARSTRING: 422 break; 423 case PICL_PTYPE_INT: 424 switch (size) { 425 case sizeof (int64_t): 426 llval = strtoll(val, &endptr, 0); 427 if (endptr != (val + strlen(val))) 428 return (EC_SYNTAX_ERR); 429 (void) memcpy(outbuf, &llval, size); 430 break; 431 case sizeof (int32_t): 432 intval = strtol(val, &endptr, 0); 433 if (endptr != (val + strlen(val))) 434 return (EC_SYNTAX_ERR); 435 (void) memcpy(outbuf, &intval, size); 436 break; 437 case sizeof (int16_t): 438 sval = (int16_t)strtol(val, &endptr, 0); 439 if (endptr != (val + strlen(val))) 440 return (EC_SYNTAX_ERR); 441 (void) memcpy(outbuf, &sval, size); 442 break; 443 case sizeof (int8_t): 444 cval = (int8_t)strtol(val, &endptr, 0); 445 if (endptr != (val + strlen(val))) 446 return (EC_SYNTAX_ERR); 447 (void) memcpy(outbuf, &cval, size); 448 break; 449 default: /* invalid size */ 450 return (EC_SYNTAX_ERR); 451 } 452 break; 453 case PICL_PTYPE_UNSIGNED_INT: 454 switch (size) { 455 case sizeof (uint64_t): 456 ullval = strtoull(val, &endptr, 0); 457 if (endptr != (val + strlen(val))) 458 return (EC_SYNTAX_ERR); 459 (void) memcpy(outbuf, &ullval, size); 460 break; 461 case sizeof (uint32_t): 462 uintval = strtoul(val, &endptr, 0); 463 if (endptr != (val + strlen(val))) 464 return (EC_SYNTAX_ERR); 465 (void) memcpy(outbuf, &uintval, size); 466 break; 467 case sizeof (uint16_t): 468 usval = (uint16_t)strtoul(val, &endptr, 0); 469 if (endptr != (val + strlen(val))) 470 return (EC_SYNTAX_ERR); 471 (void) memcpy(outbuf, &usval, size); 472 break; 473 case sizeof (uint8_t): 474 ucval = (uint8_t)strtoul(val, &endptr, 0); 475 if (endptr != (val + strlen(val))) 476 return (EC_SYNTAX_ERR); 477 (void) memcpy(outbuf, &ucval, size); 478 break; 479 default: /* invalid size */ 480 return (EC_SYNTAX_ERR); 481 } 482 break; 483 case PICL_PTYPE_FLOAT: 484 switch (size) { 485 case sizeof (double): 486 dval = strtod(val, &endptr); 487 if (endptr != (val + strlen(val))) 488 return (EC_SYNTAX_ERR); 489 (void) memcpy(outbuf, &dval, size); 490 break; 491 case sizeof (float): 492 fval = (float)strtod(val, &endptr); 493 if (endptr != (val + strlen(val))) 494 return (EC_SYNTAX_ERR); 495 (void) memcpy(outbuf, &fval, size); 496 break; 497 default: /* invalid size */ 498 return (EC_SYNTAX_ERR); 499 } 500 break; 501 default: /* not supported type */ 502 return (EC_SYNTAX_ERR); 503 } 504 505 return (EC_SYNTAX_OK); 506 } 507 508 /* 509 * free prop_cmd_t 510 */ 511 static void 512 free_prop(command_t *command) 513 { 514 free(command->propcmd_pname); 515 if (command->propcmd_type != PICL_PTYPE_VOID) 516 free(command->propcmd_valbuf); 517 } 518 519 /* 520 * return the string token in two double quotes 521 * The current version won't support multiple-line string 522 */ 523 static int 524 get_string_token(char *line, char **valtok) 525 { 526 char *optr; /* ptr to the open quote */ 527 char *cptr; /* ptr to the close quote */ 528 char *ptr; 529 char *tmpbuf; 530 531 if (line == NULL) 532 return (EC_INSUFFICIENT_TOKEN); 533 534 /* skipping leading white spaces */ 535 optr = line; 536 while ((*optr == ' ') || (*optr == '\t') || (*optr == '\n')) 537 optr++; 538 539 /* reach end of string */ 540 if (*optr == '\0') 541 return (EC_INSUFFICIENT_TOKEN); 542 543 /* it's not an open double quote */ 544 if (*optr != '"') 545 return (EC_SYNTAX_ERR); 546 547 /* skipping ending white spaces */ 548 cptr = line + strlen(line) - 1; 549 while ((*cptr == ' ') || (*cptr == '\t') || (*cptr == '\n')) 550 cptr--; 551 552 /* it's not an close double quote */ 553 if (*cptr != '"') 554 return (EC_SYNTAX_ERR); 555 556 /* close double quote is missing */ 557 if (cptr == optr) 558 return (EC_SYNTAX_ERR); 559 560 /* replace close qoute by null to make a string */ 561 *cptr = '\0'; 562 /* move the begin pointer to the first char of string */ 563 optr++; 564 565 tmpbuf = malloc(strlen(optr) + 1); 566 if (tmpbuf == NULL) 567 return (EC_FAILURE); 568 569 for (ptr = tmpbuf; *optr != '\0'; ptr++, optr++) { 570 /* if escape character, go to next character */ 571 if (*optr == '\\') { 572 optr++; 573 if (*optr == '\0') { /* for exampe, "xxx\" */ 574 free(tmpbuf); 575 return (EC_SYNTAX_ERR); 576 } 577 } 578 *ptr = *optr; 579 } 580 581 *ptr = '\0'; 582 *valtok = tmpbuf; 583 return (EC_SYNTAX_OK); 584 } 585 586 /* 587 * Check the PROP syntax 588 * PROP <name> <type> <access_mode> [<size> <value>] 589 * supported prop types: void, int, uint, float, string 590 * supported prop access_modes: r, w, rw 591 * For void prop, <size> and <value> are not needed 592 * For string prop, <size> will be set the actual string size if <size> 593 * is 0 594 */ 595 static int 596 parse_prop(char *line, command_t *command) 597 { 598 char *tok; 599 char *pnametok; 600 int typetok; 601 size_t sizetok; 602 int modetok; 603 char *valtok; 604 char *last; 605 char *endptr; 606 int err; 607 608 /* get the PROP directive */ 609 tok = strtok_r(line, WHITESPACE, &last); 610 if (tok == NULL) 611 return (EC_INSUFFICIENT_TOKEN); 612 613 /* get the property name */ 614 pnametok = strtok_r(last, WHITESPACE, &last); 615 if (pnametok == NULL) 616 return (EC_INSUFFICIENT_TOKEN); 617 618 /* get the type */ 619 tok = strtok_r(last, WHITESPACE, &last); 620 if (tok == NULL) 621 return (EC_INSUFFICIENT_TOKEN); 622 623 if ((typetok = getpicltype(tok)) < 0) 624 return (EC_SYNTAX_ERR); 625 626 /* get mode */ 627 tok = strtok_r(last, WHITESPACE, &last); 628 if (tok == NULL) 629 return (EC_INSUFFICIENT_TOKEN); 630 631 if ((modetok = getpiclmode(tok)) < 0) 632 return (EC_SYNTAX_ERR); 633 634 if (typetok == PICL_PTYPE_VOID) { 635 /* ignore the rest of arguments */ 636 command->propcmd_valbuf = NULL; 637 command->propcmd_pname = strdup(pnametok); 638 if (command->propcmd_pname == NULL) 639 return (EC_FAILURE); 640 command->propcmd_type = typetok; 641 command->propcmd_accessmode = modetok; 642 command->propcmd_size = 0; 643 command->propcmd_proph = NULL; 644 return (EC_SYNTAX_OK); 645 } 646 647 /* get size */ 648 tok = strtok_r(last, WHITESPACE, &last); 649 if (tok == NULL) 650 return (EC_INSUFFICIENT_TOKEN); 651 652 sizetok = (size_t)strtol(tok, &endptr, 0); 653 if (endptr != (tok + strlen(tok))) 654 return (EC_SYNTAX_ERR); 655 656 /* get val */ 657 if (typetok == PICL_PTYPE_CHARSTRING) { 658 err = get_string_token(last, &valtok); 659 if (err != EC_SYNTAX_OK) 660 return (err); 661 if (sizetok == 0) 662 sizetok = strlen(valtok) + 1; 663 command->propcmd_valbuf = valtok; 664 } else { 665 valtok = strtok_r(last, WHITESPACE, &last); 666 if (valtok == NULL) 667 return (EC_INSUFFICIENT_TOKEN); 668 /* check if more tokens */ 669 tok = strtok_r(last, WHITESPACE, &last); 670 if (tok != NULL) 671 return (EC_SYNTAX_ERR); 672 command->propcmd_valbuf = malloc(sizetok); 673 if (command->propcmd_valbuf == NULL) 674 return (EC_FAILURE); 675 err = validate_size_and_cvt_val(command->propcmd_valbuf, 676 sizetok, typetok, valtok); 677 if (err != EC_SYNTAX_OK) { 678 free(command->propcmd_valbuf); 679 return (err); 680 } 681 } 682 683 command->propcmd_pname = strdup(pnametok); 684 if (command->propcmd_pname == NULL) 685 return (EC_FAILURE); 686 command->propcmd_type = typetok; 687 command->propcmd_accessmode = modetok; 688 command->propcmd_size = sizetok; 689 command->propcmd_proph = NULL; 690 return (EC_SYNTAX_OK); 691 } 692 693 /* 694 * Add a property to the row, the row gets added to the node at endrow 695 */ 696 static int 697 add_proph_to_row(command_t *command, picl_prophdl_t proph) 698 { 699 if (command->rowcmd_index >= command->rowcmd_nproph) 700 return (PICL_FAILURE); 701 command->rowcmd_prophs[command->rowcmd_index] = proph; 702 command->rowcmd_index++; 703 return (PICL_SUCCESS); 704 } 705 706 /* 707 * Process the PROP command and add the specified property under the given 708 * node handle 709 */ 710 static int 711 process_prop(cmdbuf_t *cmds, command_t *command, picl_nodehdl_t nodeh) 712 { 713 ptree_propinfo_t propinfo; 714 picl_prophdl_t proph; 715 int err; 716 717 /* prop in discarded row */ 718 if (cmds->inside_row_block && 719 cmds->commands[cmds->current_row].rowcmd_nproph == 0) 720 return (PICL_SUCCESS); 721 722 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 723 command->propcmd_type, command->propcmd_accessmode, 724 command->propcmd_size, command->propcmd_pname, NULL, 725 NULL); 726 727 if (err != PICL_SUCCESS) 728 return (err); 729 730 err = ptree_create_prop(&propinfo, command->propcmd_valbuf, &proph); 731 732 if (err != PICL_SUCCESS) 733 return (err); 734 735 command->propcmd_proph = proph; 736 737 if (cmds->inside_row_block) { 738 err = add_proph_to_row(&cmds->commands[cmds->current_row], 739 proph); 740 } else { 741 err = ptree_add_prop(nodeh, proph); 742 } 743 744 return (err); 745 } 746 747 /* 748 * free refnode_cmd_t 749 */ 750 static void 751 free_refnode(command_t *command) 752 { 753 free(command->refnodecmd_name); 754 free(command->refnodecmd_class); 755 free(command->refnodecmd_dstnode); 756 } 757 758 /* 759 * Check the REFNODE syntax 760 * 761 * REFNODE <name> <class> with <destnode> -- if <destnode> exists, 762 * create node with nodename <name> and piclclass <class> 763 */ 764 static int 765 parse_refnode(char *line, command_t *command) 766 { 767 char *tok; 768 char *dsttok; 769 char *classnm; 770 char *nodenm; 771 char *last; 772 773 /* get the directive */ 774 tok = strtok_r(line, WHITESPACE, &last); 775 if (tok == NULL) 776 return (EC_INSUFFICIENT_TOKEN); 777 778 /* get the nodename */ 779 nodenm = strtok_r(last, WHITESPACE, &last); 780 if (nodenm == NULL) 781 return (EC_INSUFFICIENT_TOKEN); 782 783 /* get the class */ 784 classnm = strtok_r(last, WHITESPACE, &last); 785 if (classnm == NULL) 786 return (EC_INSUFFICIENT_TOKEN); 787 788 /* get the WITH keyword */ 789 tok = strtok_r(last, WHITESPACE, &last); 790 if (tok == NULL) 791 return (EC_INSUFFICIENT_TOKEN); 792 793 if (strcasecmp(tok, KEYWORD_WITH_STR) != 0) 794 return (EC_SYNTAX_ERR); 795 796 /* get the dst node */ 797 dsttok = strtok_r(last, WHITESPACE, &last); 798 if (dsttok == NULL) 799 return (EC_INSUFFICIENT_TOKEN); 800 801 /* check if more tokens */ 802 tok = strtok_r(last, WHITESPACE, &last); 803 if (tok != NULL) 804 return (EC_SYNTAX_ERR); 805 806 command->refnodecmd_name = strdup(nodenm); 807 command->refnodecmd_class = strdup(classnm); 808 command->refnodecmd_dstnode = strdup(dsttok); 809 command->refnodecmd_nodeh = NULL; 810 if ((command->refnodecmd_name == NULL) || 811 (command->refnodecmd_class == NULL) || 812 (command->refnodecmd_dstnode == NULL)) 813 return (EC_FAILURE); 814 815 return (EC_SYNTAX_OK); 816 } 817 818 /* 819 * Process the REFNODE command 820 */ 821 static int 822 process_refnode(command_t *command, picl_nodehdl_t parh) 823 { 824 picl_nodehdl_t dsth; 825 picl_nodehdl_t nodeh; 826 int err; 827 828 if ((ptree_get_node_by_path(command->refnodecmd_dstnode, 829 &dsth) == PICL_SUCCESS)) { 830 err = ptree_create_and_add_node(parh, command->refnodecmd_name, 831 command->refnodecmd_class, &nodeh); 832 if (err == PICL_SUCCESS) 833 command->refnodecmd_nodeh = nodeh; 834 835 return (err); 836 } 837 838 return (PICL_SUCCESS); 839 } 840 841 /* 842 * free refprop_cmd_t 843 */ 844 static void 845 free_refprop(command_t *command) 846 { 847 free(command->refpropcmd_pname); 848 free(command->refpropcmd_dstnode); 849 } 850 851 /* 852 * Check the REFPROP syntax 853 * 854 * REFPROP <prop> <destnode> -- creates a reference property to <destnode> 855 */ 856 static int 857 parse_refprop(char *line, command_t *command) 858 { 859 char *tok; 860 char *pnametok; 861 char *dsttok; 862 char *last; 863 864 /* get the REFPROP directive */ 865 tok = strtok_r(line, WHITESPACE, &last); 866 if (tok == NULL) 867 return (EC_INSUFFICIENT_TOKEN); 868 869 /* get the propname */ 870 pnametok = strtok_r(last, WHITESPACE, &last); 871 if (pnametok == NULL) 872 return (EC_INSUFFICIENT_TOKEN); 873 874 dsttok = strtok_r(last, WHITESPACE, &last); 875 if (dsttok == NULL) 876 return (EC_INSUFFICIENT_TOKEN); 877 878 /* check if more tokens */ 879 tok = strtok_r(last, WHITESPACE, &last); 880 if (tok != NULL) 881 return (EC_SYNTAX_ERR); 882 883 command->refpropcmd_pname = strdup(pnametok); 884 command->refpropcmd_dstnode = strdup(dsttok); 885 command->refpropcmd_proph = NULL; 886 if ((command->refpropcmd_pname == NULL) || 887 (command->refpropcmd_dstnode == NULL)) 888 return (EC_FAILURE); 889 890 return (EC_SYNTAX_OK); 891 } 892 893 /* 894 * Process the REFPROP command 895 */ 896 static int 897 process_refprop(cmdbuf_t *cmds, command_t *command, picl_nodehdl_t nodeh) 898 { 899 int err; 900 picl_nodehdl_t dsth; 901 picl_prophdl_t proph; 902 ptree_propinfo_t propinfo; 903 904 /* refprop in discarded row */ 905 if (cmds->inside_row_block && 906 cmds->commands[cmds->current_row].rowcmd_nproph == 0) 907 return (PICL_SUCCESS); 908 909 /* try finding the refprop's dstnode */ 910 err = ptree_get_node_by_path(command->refpropcmd_dstnode, &dsth); 911 912 /* dstnode doesn't exist, return */ 913 if (err != PICL_SUCCESS) 914 return (err); 915 916 /* dstnode exists, try adding the refprop to nodeh */ 917 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 918 PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t), 919 command->refpropcmd_pname, NULL, NULL); 920 921 if (err != PICL_SUCCESS) 922 return (err); 923 924 err = ptree_create_prop(&propinfo, &dsth, &proph); 925 926 if (err != PICL_SUCCESS) 927 return (err); 928 929 command->refpropcmd_proph = proph; 930 931 if (cmds->inside_row_block) { 932 err = add_proph_to_row(&cmds->commands[cmds->current_row], 933 proph); 934 } else { 935 err = ptree_add_prop(nodeh, proph); 936 } 937 938 return (err); 939 } 940 941 /* 942 * free table_cmd_t 943 */ 944 static void 945 free_table(command_t *command) 946 { 947 if (command->tablecmd_tname) 948 free(command->tablecmd_tname); 949 } 950 951 /* 952 * Check the TABLE syntax 953 * TABLE <table_prop_name> 954 * 955 */ 956 static int 957 parse_table(char *line, command_t *command) 958 { 959 char *tok = NULL; 960 char *tnametok = NULL; 961 char *last = NULL; 962 963 /* get the TABLE directive */ 964 tok = strtok_r(line, WHITESPACE, &last); 965 if (tok == NULL) 966 return (EC_INSUFFICIENT_TOKEN); 967 968 /* get the property name */ 969 tnametok = strtok_r(last, WHITESPACE, &last); 970 if (tnametok == NULL) 971 return (EC_INSUFFICIENT_TOKEN); 972 973 command->tablecmd_tname = strdup(tnametok); 974 if (command->tablecmd_tname == NULL) 975 return (EC_FAILURE); 976 977 command->tablecmd_newtbl = 0; 978 command->tablecmd_tblh = NULL; 979 980 return (EC_SYNTAX_OK); 981 } 982 983 /* 984 * Process the TABLE command and add the specified property under the given 985 * node handle 986 */ 987 static int 988 process_table(command_t *command, picl_nodehdl_t nodeh) 989 { 990 int err; 991 picl_prophdl_t tblh; 992 picl_prophdl_t proph; 993 ptree_propinfo_t propinfo; 994 995 /* find if table already exists */ 996 err = ptree_get_prop_by_name(nodeh, command->tablecmd_tname, &tblh); 997 if (err == PICL_SUCCESS) { 998 err = ptree_get_propinfo(tblh, &propinfo); 999 if (err != PICL_SUCCESS) 1000 return (err); 1001 /* prop with the same name as table? */ 1002 if (propinfo.piclinfo.type != PICL_PTYPE_TABLE) 1003 return (EC_SYNTAX_ERR); 1004 command->tablecmd_newtbl = 0; 1005 command->tablecmd_tblh = tblh; 1006 return (PICL_SUCCESS); 1007 } 1008 1009 /* init and create a new table */ 1010 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1011 PICL_PTYPE_TABLE, PICL_READ|PICL_WRITE, 1012 sizeof (picl_prophdl_t), command->tablecmd_tname, NULL, NULL); 1013 if (err != PICL_SUCCESS) 1014 return (err); 1015 1016 err = ptree_create_table(&tblh); 1017 if (err != PICL_SUCCESS) 1018 return (err); 1019 1020 command->tablecmd_newtbl = 1; 1021 command->tablecmd_tblh = tblh; 1022 1023 err = ptree_create_prop(&propinfo, &tblh, &proph); 1024 if (err != PICL_SUCCESS) 1025 return (err); 1026 1027 err = ptree_add_prop(nodeh, proph); 1028 1029 return (err); 1030 } 1031 1032 /* 1033 * Process the ROW command by alloc'ing space to store the prop handles for 1034 * the whole row. The number of props in the row gets known while parsing. 1035 */ 1036 static int 1037 process_row(command_t *command) 1038 { 1039 command->rowcmd_index = 0; 1040 command->rowcmd_prophs = 1041 malloc(command->rowcmd_nproph * sizeof (picl_prophdl_t)); 1042 1043 if (command->rowcmd_prophs == NULL) 1044 return (PICL_FAILURE); 1045 1046 return (PICL_SUCCESS); 1047 } 1048 1049 /* 1050 * Process the ENDROW command. If a valid row, add the row to the ptree. 1051 */ 1052 static int 1053 process_endrow(cmdbuf_t *cmds) 1054 { 1055 int err; 1056 int i; 1057 command_t *curr_row; 1058 1059 curr_row = &cmds->commands[cmds->current_row]; 1060 1061 /* if nproph == 0, some row prop had problems, don't add */ 1062 if (curr_row->rowcmd_nproph == 0) { 1063 for (i = 0; i < curr_row->rowcmd_index; i++) { 1064 (void) ptree_delete_prop(curr_row->rowcmd_prophs[i]); 1065 (void) ptree_destroy_prop(curr_row->rowcmd_prophs[i]); 1066 } 1067 err = PICL_SUCCESS; 1068 } else 1069 err = ptree_add_row_to_table( 1070 cmds->commands[cmds->current_tbl].tablecmd_tblh, 1071 curr_row->rowcmd_nproph, 1072 curr_row->rowcmd_prophs); 1073 1074 /* let go the space alloc'd in process_row */ 1075 free(curr_row->rowcmd_prophs); 1076 curr_row->rowcmd_prophs = NULL; 1077 1078 return (err); 1079 } 1080 1081 /* 1082 * Check the VERBOSE syntax 1083 * VERBOSE <level> 1084 */ 1085 static int 1086 parse_verbose(cmdbuf_t *cmds, char *line, command_t *command) 1087 { 1088 char *tok; 1089 char *level; 1090 char *last; 1091 char *endptr; 1092 int verbose_level; 1093 1094 /* get the VERBOSE directive */ 1095 tok = strtok_r(line, WHITESPACE, &last); 1096 if (tok == NULL) 1097 return (EC_INSUFFICIENT_TOKEN); 1098 1099 /* get verbose level */ 1100 level = strtok_r(last, WHITESPACE, &last); 1101 if (level == NULL) 1102 return (EC_INSUFFICIENT_TOKEN); 1103 verbose_level = strtol(level, &endptr, 0); 1104 if (endptr != (level + strlen(level))) 1105 return (EC_SYNTAX_ERR); 1106 1107 /* check if more tokens */ 1108 tok = strtok_r(last, WHITESPACE, &last); 1109 if (tok != NULL) 1110 return (EC_SYNTAX_ERR); 1111 1112 cmds->verbose = verbose_level; 1113 command->verbosecmd_level = verbose_level; 1114 1115 return (EC_SYNTAX_OK); 1116 } 1117 1118 /* 1119 * Process the VERBOSE command to set the verbose level 1120 */ 1121 static int 1122 process_verbose(cmdbuf_t *cmds, command_t *command) 1123 { 1124 cmds->verbose = command->verbosecmd_level; 1125 return (PICL_SUCCESS); 1126 } 1127 1128 /* 1129 * parse and tokenize the line 1130 */ 1131 static int 1132 parse_and_tokenize_line(cmdbuf_t *cmds, char *buf, command_t *command) 1133 { 1134 char rec[RECORD_SIZE_MAX]; 1135 char *tok; 1136 int err; 1137 char *last; 1138 int id; 1139 1140 (void) strcpy(rec, buf); 1141 tok = strtok_r(rec, RECORD_WHITESPACE, &last); 1142 if (tok == NULL) 1143 return (EC_INSUFFICIENT_TOKEN); 1144 1145 id = get_token_id(tok); 1146 1147 (void) strcpy(rec, buf); 1148 1149 switch (id) { 1150 case TOK_VERSION: 1151 err = parse_version(cmds, rec); 1152 break; 1153 case TOK_CLASSPATH: 1154 case TOK_NAMEPATH: 1155 if (cmds->inside_node_block != 0) 1156 return (EC_PATH_ERR); 1157 1158 err = parse_path(rec, command); 1159 if (err != EC_SYNTAX_OK) 1160 return (err); 1161 break; 1162 case TOK_NODE: 1163 /* Check for NODE outside of TABLE, ROW */ 1164 if ((cmds->inside_table_block != 0) || 1165 (cmds->inside_row_block != 0)) 1166 return (EC_SYNTAX_ERR); 1167 err = parse_node(rec, command); 1168 if (err != EC_SYNTAX_OK) 1169 return (err); 1170 cmds->inside_node_block++; 1171 break; 1172 case TOK_ENDNODE: 1173 /* Check for ENDNODE outside of TABLE, ROW */ 1174 if ((cmds->inside_table_block != 0) || 1175 (cmds->inside_row_block != 0)) 1176 return (EC_SYNTAX_ERR); 1177 cmds->inside_node_block--; 1178 err = EC_SYNTAX_OK; 1179 break; 1180 case TOK_PROP: 1181 /* Check if inside TABLE, but not in ROW */ 1182 if ((cmds->inside_table_block != 0) && 1183 (cmds->inside_row_block == 0)) 1184 return (EC_SYNTAX_ERR); 1185 err = parse_prop(rec, command); 1186 if (err != EC_SYNTAX_OK) 1187 return (err); 1188 if (cmds->inside_row_block) { 1189 cmds->commands[cmds->current_row].rowcmd_nproph++; 1190 } 1191 break; 1192 case TOK_REFNODE: 1193 err = parse_refnode(rec, command); 1194 if (err != EC_SYNTAX_OK) 1195 return (err); 1196 break; 1197 case TOK_REFPROP: 1198 /* Check if inside TABLE, but not in ROW */ 1199 if ((cmds->inside_table_block != 0) && 1200 (cmds->inside_row_block == 0)) 1201 return (EC_SYNTAX_ERR); 1202 err = parse_refprop(rec, command); 1203 if (err != EC_SYNTAX_OK) 1204 return (err); 1205 if (cmds->inside_row_block) { 1206 cmds->commands[cmds->current_row].rowcmd_nproph++; 1207 } 1208 break; 1209 case TOK_TABLE: 1210 /* Table/Row supported in version 1.1 and above */ 1211 if (cmds->version_no < (float)SUPPORTED_VERSION_NUM) 1212 return (EC_UNSUPPORTED); 1213 if (cmds->inside_table_block != 0) 1214 return (EC_SYNTAX_ERR); 1215 err = parse_table(rec, command); 1216 if (err != EC_SYNTAX_OK) 1217 return (err); 1218 cmds->inside_table_block = 1; 1219 break; 1220 case TOK_ENDTABLE: 1221 /* Check for ENDTABLE before TABLE */ 1222 if (cmds->inside_table_block == 0) 1223 return (EC_SYNTAX_ERR); 1224 1225 cmds->inside_table_block = 0; 1226 1227 break; 1228 case TOK_ROW: 1229 /* Check for ROW outside of TABLE, ROW inside ROW */ 1230 if ((cmds->inside_table_block == 0) || 1231 (cmds->inside_row_block != 0)) 1232 return (EC_SYNTAX_ERR); 1233 cmds->inside_row_block = 1; 1234 break; 1235 case TOK_ENDROW: 1236 /* Check for ENDROW outside of TABLE, ENDROW before ROW */ 1237 if ((cmds->inside_table_block == 0) || 1238 (cmds->inside_row_block == 0)) 1239 return (EC_SYNTAX_ERR); 1240 else 1241 err = EC_SYNTAX_OK; 1242 1243 cmds->inside_row_block = 0; 1244 1245 /* error if row is empty */ 1246 if (cmds->commands[cmds->current_row].rowcmd_nproph <= 0) 1247 return (EC_ROW_EMPTY); 1248 break; 1249 case TOK_VERBOSE: 1250 err = parse_verbose(cmds, rec, command); 1251 if (err != EC_SYNTAX_OK) 1252 return (err); 1253 break; 1254 default: /* unsupported command */ 1255 return (EC_SYNTAX_ERR); 1256 } 1257 1258 command->type = id; 1259 return (EC_SYNTAX_OK); 1260 } 1261 1262 /* 1263 * Check the syntax and save the tokens in the commands buffer 1264 */ 1265 static int 1266 check_line_syntax(cmdbuf_t *cmds, char *buf) 1267 { 1268 int err; 1269 command_t command; 1270 1271 (void) memset(&command, 0, sizeof (command_t)); 1272 err = parse_and_tokenize_line(cmds, buf, &command); 1273 if (err != EC_SYNTAX_OK) 1274 return (err); 1275 1276 /* 1277 * don't add and count version command in the command buffer 1278 */ 1279 if (command.type == TOK_VERSION) 1280 return (EC_SYNTAX_OK); 1281 1282 /* 1283 * check if the commands buffer has been filled 1284 * If it is full, reallocate the buffer. 1285 */ 1286 if (cmds->count == cmds->allocated) { 1287 cmds->commands = realloc(cmds->commands, 1288 sizeof (command_t) * (cmds->allocated + PER_ALLOC_COUNT)); 1289 if (cmds->commands == NULL) 1290 return (EC_FAILURE); 1291 cmds->allocated += PER_ALLOC_COUNT; 1292 } 1293 1294 cmds->commands[cmds->count] = command; /* copy */ 1295 1296 /* 1297 * make a note of the row/endrow command, to keep track of # of props 1298 */ 1299 if (command.type == TOK_ROW) 1300 cmds->current_row = cmds->count; 1301 1302 if (command.type == TOK_ENDROW) 1303 cmds->current_row = 0; 1304 1305 cmds->count++; 1306 1307 return (EC_SYNTAX_OK); 1308 } 1309 1310 /* 1311 * get the line control information 1312 * return 1 if it's the line control information, else return 0 1313 */ 1314 static int 1315 get_line_control_info(char *buf, uint32_t *linenum, char *filename) 1316 { 1317 char *ptr; 1318 char *last; 1319 uint32_t num; 1320 char *fname; 1321 char *endptr; 1322 1323 /* skip # and get next string */ 1324 ptr = strtok_r(buf + 1, WHITESPACE, &last); 1325 if (ptr == NULL) { 1326 return (0); 1327 } 1328 1329 num = strtoul(ptr, &endptr, 0); 1330 1331 /* 1332 * It's not the line control information 1333 */ 1334 if (endptr != (ptr + strlen(ptr))) { 1335 return (0); 1336 } 1337 1338 /* 1339 * get the filename 1340 */ 1341 1342 /* get the beginning double quote */ 1343 last = strchr(last, '"'); 1344 if (last == NULL) 1345 return (0); 1346 1347 last++; 1348 1349 /* get the ending double quote */ 1350 fname = strtok_r(last, DOUBLE_QUOTE, &last); 1351 if (fname == NULL) 1352 return (0); 1353 1354 *linenum = num; 1355 (void) strlcpy(filename, fname, PATH_MAX); 1356 return (1); 1357 } 1358 1359 /* 1360 * check the syntax of the configuration file 1361 */ 1362 static int 1363 check_conffile_syntax(cmdbuf_t *cmds, FILE *fp) 1364 { 1365 char lbuf[RECORD_SIZE_MAX]; 1366 char buf[RECORD_SIZE_MAX]; 1367 uint32_t linenum; 1368 char cppfile[PATH_MAX] = ""; 1369 int err = EC_SYNTAX_OK; 1370 1371 linenum = 0; 1372 while (fgets(buf, sizeof (buf), fp) != NULL) { 1373 /* 1374 * get cpp line control information, if any 1375 */ 1376 if (buf[0] == '#') { 1377 if (!get_line_control_info(buf, &linenum, cppfile)) 1378 ++linenum; 1379 continue; 1380 } 1381 1382 ++linenum; 1383 /* 1384 * skip line whose first char is a newline char 1385 */ 1386 if (buf[0] == '\n') { 1387 continue; 1388 } 1389 1390 if (err == EC_SYNTAX_OK) 1391 (void) strlcpy(lbuf, buf, RECORD_SIZE_MAX); 1392 else if (strlcat(lbuf, buf, RECORD_SIZE_MAX) >= 1393 RECORD_SIZE_MAX) { /* buffer overflow */ 1394 err = EC_FAILURE; 1395 break; 1396 } 1397 1398 err = check_line_syntax(cmds, lbuf); 1399 if ((err != EC_INSUFFICIENT_TOKEN) && (err != EC_SYNTAX_OK)) 1400 break; 1401 } 1402 1403 if (err != EC_SYNTAX_OK) { 1404 if (cmds->verbose) { 1405 verbose_log(LOG_ERR, err_msg[err], 1406 cmds->fname, cppfile, linenum); 1407 } 1408 return (err); 1409 } 1410 1411 /* 1412 * check if the version has been set 1413 */ 1414 if (cmds->version_no > (float)SUPPORTED_VERSION_NUM) { 1415 if (cmds->verbose) { 1416 verbose_log(LOG_ERR, err_msg[EC_UNSUPPORTED], 1417 cmds->fname, cppfile, linenum); 1418 } 1419 return (EC_UNSUPPORTED); 1420 } 1421 1422 /* 1423 * check if node and endnode command mismatch 1424 */ 1425 if (cmds->inside_node_block != 0) { 1426 if (cmds->verbose) { 1427 verbose_log(LOG_ERR, err_msg[EC_NODE_MISMATCH], 1428 cmds->fname, cppfile, linenum); 1429 } 1430 return (EC_NODE_MISMATCH); 1431 } 1432 1433 /* 1434 * check if row and endrow command mismatch 1435 */ 1436 if (cmds->inside_row_block != 0) { 1437 if (cmds->verbose) { 1438 verbose_log(LOG_ERR, err_msg[EC_ROW_MISMATCH], 1439 cmds->fname, cppfile, linenum); 1440 } 1441 return (EC_ROW_MISMATCH); 1442 } 1443 1444 /* 1445 * check if table and endtable command mismatch 1446 */ 1447 if (cmds->inside_table_block != 0) { 1448 if (cmds->verbose) { 1449 verbose_log(LOG_ERR, err_msg[EC_TABLE_MISMATCH], 1450 cmds->fname, cppfile, linenum); 1451 } 1452 return (EC_TABLE_MISMATCH); 1453 } 1454 1455 return (EC_SYNTAX_OK); 1456 } 1457 1458 /* 1459 * If classpath/namepath given is not found in the picl tree, 1460 * skip the whole blocks until next valid classpath or namepath 1461 */ 1462 static void 1463 skip_to_next_valid_path(cmdbuf_t *cmds, int starting_index, 1464 picl_nodehdl_t *parent, int *last_processed_index) 1465 { 1466 int err; 1467 int index; 1468 1469 for (index = starting_index; index < cmds->count; ++index) { 1470 switch (cmds->commands[index].type) { 1471 case TOK_CLASSPATH: 1472 case TOK_NAMEPATH: 1473 err = process_path(&cmds->commands[index], parent); 1474 if (err == PICL_SUCCESS) { 1475 *last_processed_index = index; 1476 return; 1477 } 1478 default: 1479 /* skipped this line */ 1480 break; 1481 } 1482 } 1483 1484 /* reach last command */ 1485 *last_processed_index = cmds->count - 1; 1486 } 1487 1488 /* 1489 * Process the command buffer and return last command index and the new head of 1490 * the handle list 1491 */ 1492 static int 1493 process_commands(cmdbuf_t *cmds, int starting_index, picl_nodehdl_t parent, 1494 int *last_processed_index) 1495 { 1496 int err; 1497 int index; 1498 picl_nodehdl_t rooth; 1499 picl_nodehdl_t nodeh; 1500 command_t *commands = cmds->commands; 1501 1502 for (index = starting_index; index < cmds->count; ++index) { 1503 switch (commands[index].type) { 1504 case TOK_CLASSPATH: 1505 case TOK_NAMEPATH: 1506 err = process_path(&commands[index], &rooth); 1507 if (err != PICL_SUCCESS) { 1508 index++; 1509 (void) skip_to_next_valid_path(cmds, index, 1510 &rooth, &index); 1511 } 1512 parent = rooth; 1513 continue; 1514 case TOK_NODE: 1515 err = process_node(&commands[index], parent, &nodeh); 1516 if (err == PICL_SUCCESS) { 1517 index++; 1518 err = process_commands(cmds, index, nodeh, 1519 &index); 1520 } 1521 break; 1522 case TOK_ENDNODE: 1523 *last_processed_index = index; 1524 return (PICL_SUCCESS); 1525 case TOK_PROP: 1526 err = process_prop(cmds, &commands[index], parent); 1527 break; 1528 case TOK_REFPROP: 1529 err = process_refprop(cmds, &commands[index], parent); 1530 /* no reference node */ 1531 if (err == PICL_NOTNODE) { 1532 err = PICL_SUCCESS; /* discard prop */ 1533 /* discard row by setting nproph = 0 */ 1534 if (cmds->inside_row_block) 1535 cmds->commands[cmds->current_row] 1536 .rowcmd_nproph = 0; 1537 } 1538 break; 1539 case TOK_REFNODE: 1540 err = process_refnode(&commands[index], parent); 1541 break; 1542 case TOK_TABLE: 1543 cmds->inside_table_block = 1; 1544 err = process_table(&commands[index], parent); 1545 cmds->current_tbl = index; 1546 break; 1547 case TOK_ENDTABLE: 1548 cmds->inside_table_block = 0; 1549 cmds->current_tbl = 0; 1550 break; 1551 case TOK_ROW: 1552 cmds->inside_row_block = 1; 1553 err = process_row(&commands[index]); 1554 cmds->current_row = index; 1555 break; 1556 case TOK_ENDROW: 1557 err = process_endrow(cmds); 1558 cmds->inside_row_block = 0; 1559 cmds->current_row = 0; 1560 break; 1561 case TOK_VERBOSE: 1562 err = process_verbose(cmds, &commands[index]); 1563 break; 1564 default: /* won't reach here */ 1565 err = PICL_FAILURE; 1566 break; 1567 } 1568 1569 if ((err != PICL_SUCCESS) && (err != PICL_PROPEXISTS)) { 1570 *last_processed_index = index; 1571 return (err); 1572 } 1573 } 1574 1575 /* reach last command */ 1576 *last_processed_index = cmds->count - 1; 1577 return (PICL_SUCCESS); 1578 } 1579 1580 /* 1581 * clean up the commands buffer 1582 */ 1583 static void 1584 clean_up(cmdbuf_t *cmds) 1585 { 1586 int cmd_index; 1587 1588 for (cmd_index = 0; cmd_index < cmds->count; cmd_index++) { 1589 switch (cmds->commands[cmd_index].type) { 1590 case TOK_CLASSPATH: 1591 case TOK_NAMEPATH: 1592 free_path(&cmds->commands[cmd_index]); 1593 break; 1594 case TOK_NODE: 1595 free_node(&cmds->commands[cmd_index]); 1596 break; 1597 case TOK_PROP: 1598 free_prop(&cmds->commands[cmd_index]); 1599 break; 1600 case TOK_REFPROP: 1601 free_refprop(&cmds->commands[cmd_index]); 1602 break; 1603 case TOK_REFNODE: 1604 free_refnode(&cmds->commands[cmd_index]); 1605 break; 1606 case TOK_TABLE: 1607 free_table(&cmds->commands[cmd_index]); 1608 break; 1609 case TOK_ENDTABLE: 1610 case TOK_ROW: 1611 case TOK_ENDROW: 1612 case TOK_ENDNODE: 1613 case TOK_VERBOSE: 1614 default: 1615 break; 1616 } 1617 } 1618 if (cmds->commands) 1619 free(cmds->commands); 1620 } 1621 1622 /* 1623 * Parse the configuration file and create nodes/properties under nh 1624 * 1625 * It checks the syntax first. If there is any syntax error, 1626 * it returns 1 and won't continue processing the file to add nodes or props. 1627 * 1628 * If any error happens during command processing, all nodes 1629 * and properties just created will be deleted, i.e. undo 1630 * commands which have been processed. It returns 1. 1631 * 1632 * If success, return 0. 1633 */ 1634 int 1635 picld_pluginutil_parse_config_file(picl_nodehdl_t nh, const char *filename) 1636 { 1637 FILE *ifp; 1638 int last_processed_index; 1639 int err; 1640 cmdbuf_t *cmds; 1641 1642 /* set correct locale for use inside pluginutil */ 1643 setlocale(LC_ALL, "C"); 1644 1645 /* 1646 * Initialize the command buffer 1647 */ 1648 1649 cmds = malloc(sizeof (*cmds)); 1650 if (cmds == NULL) { 1651 setlocale(LC_ALL, ""); 1652 return (1); 1653 } 1654 1655 memset(cmds, 0, sizeof (cmdbuf_t)); 1656 1657 cmds->fname = filename; 1658 1659 ifp = fopen(filename, "r"); 1660 if (ifp == NULL) { 1661 setlocale(LC_ALL, ""); 1662 return (1); 1663 } 1664 1665 /* 1666 * check the syntax of the configuration file 1667 */ 1668 err = check_conffile_syntax(cmds, ifp); 1669 1670 (void) fclose(ifp); 1671 1672 if (err != EC_SYNTAX_OK) { 1673 clean_up(cmds); 1674 free(cmds); 1675 setlocale(LC_ALL, ""); 1676 return (1); 1677 } 1678 1679 /* 1680 * Process the commands 1681 */ 1682 err = process_commands(cmds, STARTING_INDEX, nh, &last_processed_index); 1683 1684 /* 1685 * If any PICL error, remove the newly created node/prop 1686 * handles from the PICL tree. 1687 */ 1688 if (err != PICL_SUCCESS) { 1689 undo_commands(cmds, last_processed_index); 1690 if (cmds->verbose) 1691 verbose_log(LOG_ERR, err_msg[EC_PICL_ERR], filename, 1692 err); 1693 } 1694 1695 clean_up(cmds); 1696 free(cmds); 1697 1698 /* reset the locale */ 1699 setlocale(LC_ALL, ""); 1700 1701 return ((err == PICL_SUCCESS) ? 0 : 1); 1702 } 1703