/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This module implements the routine to parse the configuration file.
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <alloca.h>
#include <limits.h>
#include <sys/systeminfo.h>
#include <libintl.h>
#include <syslog.h>
#include <locale.h>
#include <picl.h>
#include <picltree.h>
#include "picld_pluginutil.h"
#include "picld_pluginutil_impl.h"
/* error codes returned from syntax checking */
#define EC_SYNTAX_OK 0
/*
* Error message texts
*/
static char *err_msg[] = {
"%s: Syntax OK", /* 0 */
"%s::%s[line %d]: Insufficient token\n", /* 1 */
"%s::%s[line %d]: Syntax error\n", /* 2 */
"%s::%s[line %d]: Unsupported or missing version\n", /* 3 */
"%s::%s[line %d]: Illegal use of nodepath or namepath\n", /* 4 */
"%s::%s[line %d]: Node and endnode mismatch\n", /* 5 */
"%s::%s[line %d]: General system failure\n", /* 6 */
"%s: PICL error code %d\n", /* 7 */
"%s::%s[line %d]: Table and endtable mismatch\n", /* 8 */
"%s::%s[line %d]: Row and endrow mismatch\n", /* 9 */
"%s::%s[line %d]: Row has no entries \n" /* 10 */
};
/* token per directive */
#define TOK_CLASSPATH 0
static const char *tokens[] = {
"_class", /* _CLASS:<classpath> */
"name", /* NAME:<namepath> */
"node", /* NODE <name> <class> */
"endnode", /* ENDNODE */
"prop", /* PROP <name> <type> <access_mode> <size> <value> */
"refprop", /* REFPROP <prop> <destnode> */
"version", /* VERSION <version_number> */
"refnode", /* REFNODE <node> <class> WITH <destnode> */
"verbose", /* VERBOSE <level> */
"table", /* TABLE <table_prop_name> */
"endtable", /* ENDTABLE */
"row", /* ROW */
"endrow" /* ENDROW */
};
/*
* print error message
*/
/*VARARGS2*/
static void
{
}
/*
* The undo order is from last command to the first command.
*/
static void
{
int i;
for (i = last_cmd_index; i >= 0; i--) {
case TOK_NODE:
break;
break;
case TOK_REFNODE:
break;
break;
case TOK_PROP:
break;
break;
case TOK_REFPROP:
break;
break;
case TOK_TABLE:
(com[i].tablecmd_newtbl == 0))
break;
break;
case TOK_ENDTABLE:
/*FALLTHROUGH*/
case TOK_ROW:
/*FALLTHROUGH*/
case TOK_ENDROW:
/*FALLTHROUGH*/
case TOK_NAMEPATH:
/*FALLTHROUGH*/
case TOK_CLASSPATH:
/*FALLTHROUGH*/
case TOK_ENDNODE:
/*FALLTHROUGH*/
case TOK_VERBOSE:
/*FALLTHROUGH*/
default:
break;
}
}
}
/*
* Get the token index from the tokens table
*/
static int
get_token_id(char *t)
{
int i;
for (i = 0; i < sizeof (tokens)/ sizeof (char *); ++i)
if (strcasecmp(tokens[i], t) == 0)
return (i);
return (-1);
}
/*
* Check the version syntax and set the version_no
*
* VERSION <version_num> -- specify the configuration version
*/
static int
{
char *tok;
char *vertok;
char *last;
char *endptr;
/* get the VERSION directive */
return (EC_INSUFFICIENT_TOKEN);
/* get the version number */
return (EC_INSUFFICIENT_TOKEN);
return (EC_UNSUPPORTED);
return (EC_UNSUPPORTED);
/* check if more tokens */
return (EC_SYNTAX_ERR);
return (EC_SYNTAX_OK);
}
/*
* free path_cmd_t
*/
static void
{
}
/*
* Check the path syntax
* NAMEPATH:<namepath> -- gives the anchor node
* or
* CLASSPATH:<classpath> -- gives the anchor node
*/
static int
{
char *tok;
char *pathtok;
char *last;
return (EC_INSUFFICIENT_TOKEN);
/* check if more tokens */
return (EC_SYNTAX_ERR);
return (EC_FAILURE);
return (EC_SYNTAX_OK);
}
/*
* Process the path command and return PICL node handle
*/
static int
{
int err;
return (err);
}
/*
* free node_cmd_t
*/
static void
{
}
/*
* Check the NODE syntax
* NODE <name> <class>
*/
static int
{
char *tok;
char *nametok;
char *classtok;
char *last;
/* get the NODE directive */
return (EC_INSUFFICIENT_TOKEN);
/* get name */
return (EC_INSUFFICIENT_TOKEN);
return (EC_INSUFFICIENT_TOKEN);
/* check if more tokens */
return (EC_SYNTAX_ERR);
return (EC_FAILURE);
return (EC_SYNTAX_OK);
}
/*
* Process the NODE command and return PICL node handle
*/
static int
{
int err;
if (err == PICL_SUCCESS)
return (err);
}
/*
* get the PICL property type
*/
static int
{
return (PICL_PTYPE_INT);
return (PICL_PTYPE_UNSIGNED_INT);
return (PICL_PTYPE_FLOAT);
return (PICL_PTYPE_CHARSTRING);
return (PICL_PTYPE_VOID);
else
return (-1);
}
/*
* get the PICL accessmode mode
*/
static int
{
return (PICL_READ);
return (PICL_WRITE);
return (PICL_READ|PICL_WRITE);
else
return (-1);
}
/*
* check if the size and value are valid given by the prop type
*/
static int
{
float fval;
double dval;
char *endptr;
switch (type) {
case PICL_PTYPE_CHARSTRING:
break;
case PICL_PTYPE_INT:
switch (size) {
case sizeof (int64_t):
return (EC_SYNTAX_ERR);
break;
case sizeof (int32_t):
return (EC_SYNTAX_ERR);
break;
case sizeof (int16_t):
return (EC_SYNTAX_ERR);
break;
case sizeof (int8_t):
return (EC_SYNTAX_ERR);
break;
default: /* invalid size */
return (EC_SYNTAX_ERR);
}
break;
case PICL_PTYPE_UNSIGNED_INT:
switch (size) {
case sizeof (uint64_t):
return (EC_SYNTAX_ERR);
break;
case sizeof (uint32_t):
return (EC_SYNTAX_ERR);
break;
case sizeof (uint16_t):
return (EC_SYNTAX_ERR);
break;
case sizeof (uint8_t):
return (EC_SYNTAX_ERR);
break;
default: /* invalid size */
return (EC_SYNTAX_ERR);
}
break;
case PICL_PTYPE_FLOAT:
switch (size) {
case sizeof (double):
return (EC_SYNTAX_ERR);
break;
case sizeof (float):
return (EC_SYNTAX_ERR);
break;
default: /* invalid size */
return (EC_SYNTAX_ERR);
}
break;
default: /* not supported type */
return (EC_SYNTAX_ERR);
}
return (EC_SYNTAX_OK);
}
/*
* free prop_cmd_t
*/
static void
{
}
/*
* return the string token in two double quotes
* The current version won't support multiple-line string
*/
static int
{
char *ptr;
char *tmpbuf;
return (EC_INSUFFICIENT_TOKEN);
/* skipping leading white spaces */
optr++;
/* reach end of string */
if (*optr == '\0')
return (EC_INSUFFICIENT_TOKEN);
/* it's not an open double quote */
if (*optr != '"')
return (EC_SYNTAX_ERR);
/* skipping ending white spaces */
cptr--;
/* it's not an close double quote */
if (*cptr != '"')
return (EC_SYNTAX_ERR);
/* close double quote is missing */
return (EC_SYNTAX_ERR);
/* replace close qoute by null to make a string */
*cptr = '\0';
/* move the begin pointer to the first char of string */
optr++;
return (EC_FAILURE);
/* if escape character, go to next character */
if (*optr == '\\') {
optr++;
return (EC_SYNTAX_ERR);
}
}
}
*ptr = '\0';
return (EC_SYNTAX_OK);
}
/*
* Check the PROP syntax
* PROP <name> <type> <access_mode> [<size> <value>]
* supported prop types: void, int, uint, float, string
* supported prop access_modes: r, w, rw
* For void prop, <size> and <value> are not needed
* For string prop, <size> will be set the actual string size if <size>
* is 0
*/
static int
{
char *tok;
char *pnametok;
int typetok;
int modetok;
char *valtok;
char *last;
char *endptr;
int err;
/* get the PROP directive */
return (EC_INSUFFICIENT_TOKEN);
/* get the property name */
return (EC_INSUFFICIENT_TOKEN);
/* get the type */
return (EC_INSUFFICIENT_TOKEN);
return (EC_SYNTAX_ERR);
/* get mode */
return (EC_INSUFFICIENT_TOKEN);
return (EC_SYNTAX_ERR);
if (typetok == PICL_PTYPE_VOID) {
/* ignore the rest of arguments */
return (EC_FAILURE);
command->propcmd_size = 0;
return (EC_SYNTAX_OK);
}
/* get size */
return (EC_INSUFFICIENT_TOKEN);
return (EC_SYNTAX_ERR);
/* get val */
if (typetok == PICL_PTYPE_CHARSTRING) {
if (err != EC_SYNTAX_OK)
return (err);
if (sizetok == 0)
} else {
return (EC_INSUFFICIENT_TOKEN);
/* check if more tokens */
return (EC_SYNTAX_ERR);
return (EC_FAILURE);
if (err != EC_SYNTAX_OK) {
return (err);
}
}
return (EC_FAILURE);
return (EC_SYNTAX_OK);
}
/*
* Add a property to the row, the row gets added to the node at endrow
*/
static int
{
return (PICL_FAILURE);
command->rowcmd_index++;
return (PICL_SUCCESS);
}
/*
* Process the PROP command and add the specified property under the given
* node handle
*/
static int
{
int err;
/* prop in discarded row */
if (cmds->inside_row_block &&
return (PICL_SUCCESS);
NULL);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (cmds->inside_row_block) {
proph);
} else {
}
return (err);
}
/*
* free refnode_cmd_t
*/
static void
{
}
/*
* Check the REFNODE syntax
*
* REFNODE <name> <class> with <destnode> -- if <destnode> exists,
* create node with nodename <name> and piclclass <class>
*/
static int
{
char *tok;
char *dsttok;
char *classnm;
char *nodenm;
char *last;
/* get the directive */
return (EC_INSUFFICIENT_TOKEN);
/* get the nodename */
return (EC_INSUFFICIENT_TOKEN);
/* get the class */
return (EC_INSUFFICIENT_TOKEN);
/* get the WITH keyword */
return (EC_INSUFFICIENT_TOKEN);
return (EC_SYNTAX_ERR);
/* get the dst node */
return (EC_INSUFFICIENT_TOKEN);
/* check if more tokens */
return (EC_SYNTAX_ERR);
return (EC_FAILURE);
return (EC_SYNTAX_OK);
}
/*
* Process the REFNODE command
*/
static int
{
int err;
&dsth) == PICL_SUCCESS)) {
if (err == PICL_SUCCESS)
return (err);
}
return (PICL_SUCCESS);
}
/*
* free refprop_cmd_t
*/
static void
{
}
/*
* Check the REFPROP syntax
*
* REFPROP <prop> <destnode> -- creates a reference property to <destnode>
*/
static int
{
char *tok;
char *pnametok;
char *dsttok;
char *last;
/* get the REFPROP directive */
return (EC_INSUFFICIENT_TOKEN);
/* get the propname */
return (EC_INSUFFICIENT_TOKEN);
return (EC_INSUFFICIENT_TOKEN);
/* check if more tokens */
return (EC_SYNTAX_ERR);
return (EC_FAILURE);
return (EC_SYNTAX_OK);
}
/*
* Process the REFPROP command
*/
static int
{
int err;
/* refprop in discarded row */
if (cmds->inside_row_block &&
return (PICL_SUCCESS);
/* try finding the refprop's dstnode */
/* dstnode doesn't exist, return */
if (err != PICL_SUCCESS)
return (err);
/* dstnode exists, try adding the refprop to nodeh */
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (cmds->inside_row_block) {
proph);
} else {
}
return (err);
}
/*
* free table_cmd_t
*/
static void
{
if (command->tablecmd_tname)
}
/*
* Check the TABLE syntax
* TABLE <table_prop_name>
*
*/
static int
{
/* get the TABLE directive */
return (EC_INSUFFICIENT_TOKEN);
/* get the property name */
return (EC_INSUFFICIENT_TOKEN);
return (EC_FAILURE);
command->tablecmd_newtbl = 0;
return (EC_SYNTAX_OK);
}
/*
* Process the TABLE command and add the specified property under the given
* node handle
*/
static int
{
int err;
/* find if table already exists */
if (err == PICL_SUCCESS) {
if (err != PICL_SUCCESS)
return (err);
/* prop with the same name as table? */
return (EC_SYNTAX_ERR);
command->tablecmd_newtbl = 0;
return (PICL_SUCCESS);
}
/* init and create a new table */
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
return (err);
}
/*
* Process the ROW command by alloc'ing space to store the prop handles for
* the whole row. The number of props in the row gets known while parsing.
*/
static int
{
command->rowcmd_index = 0;
return (PICL_FAILURE);
return (PICL_SUCCESS);
}
/*
* Process the ENDROW command. If a valid row, add the row to the ptree.
*/
static int
{
int err;
int i;
/* if nproph == 0, some row prop had problems, don't add */
if (curr_row->rowcmd_nproph == 0) {
for (i = 0; i < curr_row->rowcmd_index; i++) {
}
err = PICL_SUCCESS;
} else
/* let go the space alloc'd in process_row */
return (err);
}
/*
* Check the VERBOSE syntax
* VERBOSE <level>
*/
static int
{
char *tok;
char *level;
char *last;
char *endptr;
int verbose_level;
/* get the VERBOSE directive */
return (EC_INSUFFICIENT_TOKEN);
/* get verbose level */
return (EC_INSUFFICIENT_TOKEN);
return (EC_SYNTAX_ERR);
/* check if more tokens */
return (EC_SYNTAX_ERR);
return (EC_SYNTAX_OK);
}
/*
* Process the VERBOSE command to set the verbose level
*/
static int
{
return (PICL_SUCCESS);
}
/*
* parse and tokenize the line
*/
static int
{
char *tok;
int err;
char *last;
int id;
return (EC_INSUFFICIENT_TOKEN);
switch (id) {
case TOK_VERSION:
break;
case TOK_CLASSPATH:
case TOK_NAMEPATH:
if (cmds->inside_node_block != 0)
return (EC_PATH_ERR);
if (err != EC_SYNTAX_OK)
return (err);
break;
case TOK_NODE:
/* Check for NODE outside of TABLE, ROW */
if ((cmds->inside_table_block != 0) ||
(cmds->inside_row_block != 0))
return (EC_SYNTAX_ERR);
if (err != EC_SYNTAX_OK)
return (err);
break;
case TOK_ENDNODE:
/* Check for ENDNODE outside of TABLE, ROW */
if ((cmds->inside_table_block != 0) ||
(cmds->inside_row_block != 0))
return (EC_SYNTAX_ERR);
err = EC_SYNTAX_OK;
break;
case TOK_PROP:
/* Check if inside TABLE, but not in ROW */
if ((cmds->inside_table_block != 0) &&
(cmds->inside_row_block == 0))
return (EC_SYNTAX_ERR);
if (err != EC_SYNTAX_OK)
return (err);
if (cmds->inside_row_block) {
}
break;
case TOK_REFNODE:
if (err != EC_SYNTAX_OK)
return (err);
break;
case TOK_REFPROP:
/* Check if inside TABLE, but not in ROW */
if ((cmds->inside_table_block != 0) &&
(cmds->inside_row_block == 0))
return (EC_SYNTAX_ERR);
if (err != EC_SYNTAX_OK)
return (err);
if (cmds->inside_row_block) {
}
break;
case TOK_TABLE:
return (EC_UNSUPPORTED);
if (cmds->inside_table_block != 0)
return (EC_SYNTAX_ERR);
if (err != EC_SYNTAX_OK)
return (err);
break;
case TOK_ENDTABLE:
/* Check for ENDTABLE before TABLE */
if (cmds->inside_table_block == 0)
return (EC_SYNTAX_ERR);
cmds->inside_table_block = 0;
break;
case TOK_ROW:
/* Check for ROW outside of TABLE, ROW inside ROW */
if ((cmds->inside_table_block == 0) ||
(cmds->inside_row_block != 0))
return (EC_SYNTAX_ERR);
break;
case TOK_ENDROW:
/* Check for ENDROW outside of TABLE, ENDROW before ROW */
if ((cmds->inside_table_block == 0) ||
(cmds->inside_row_block == 0))
return (EC_SYNTAX_ERR);
else
err = EC_SYNTAX_OK;
cmds->inside_row_block = 0;
/* error if row is empty */
return (EC_ROW_EMPTY);
break;
case TOK_VERBOSE:
if (err != EC_SYNTAX_OK)
return (err);
break;
default: /* unsupported command */
return (EC_SYNTAX_ERR);
}
return (EC_SYNTAX_OK);
}
/*
* Check the syntax and save the tokens in the commands buffer
*/
static int
{
int err;
if (err != EC_SYNTAX_OK)
return (err);
/*
* don't add and count version command in the command buffer
*/
return (EC_SYNTAX_OK);
/*
* check if the commands buffer has been filled
* If it is full, reallocate the buffer.
*/
return (EC_FAILURE);
}
/*
*/
cmds->current_row = 0;
return (EC_SYNTAX_OK);
}
/*
* get the line control information
* return 1 if it's the line control information, else return 0
*/
static int
{
char *ptr;
char *last;
char *fname;
char *endptr;
/* skip # and get next string */
return (0);
}
/*
* It's not the line control information
*/
return (0);
}
/*
* get the filename
*/
/* get the beginning double quote */
return (0);
last++;
/* get the ending double quote */
return (0);
return (1);
}
/*
* check the syntax of the configuration file
*/
static int
{
linenum = 0;
/*
* get cpp line control information, if any
*/
if (buf[0] == '#') {
++linenum;
continue;
}
++linenum;
/*
* skip line whose first char is a newline char
*/
if (buf[0] == '\n') {
continue;
}
if (err == EC_SYNTAX_OK)
RECORD_SIZE_MAX) { /* buffer overflow */
err = EC_FAILURE;
break;
}
break;
}
if (err != EC_SYNTAX_OK) {
}
return (err);
}
/*
* check if the version has been set
*/
}
return (EC_UNSUPPORTED);
}
/*
* check if node and endnode command mismatch
*/
if (cmds->inside_node_block != 0) {
}
return (EC_NODE_MISMATCH);
}
/*
* check if row and endrow command mismatch
*/
if (cmds->inside_row_block != 0) {
}
return (EC_ROW_MISMATCH);
}
/*
* check if table and endtable command mismatch
*/
if (cmds->inside_table_block != 0) {
}
return (EC_TABLE_MISMATCH);
}
return (EC_SYNTAX_OK);
}
/*
* skip the whole blocks until next valid classpath or namepath
*/
static void
{
int err;
int index;
case TOK_CLASSPATH:
case TOK_NAMEPATH:
if (err == PICL_SUCCESS) {
return;
}
default:
/* skipped this line */
break;
}
}
/* reach last command */
}
/*
* Process the command buffer and return last command index and the new head of
* the handle list
*/
static int
int *last_processed_index)
{
int err;
int index;
case TOK_CLASSPATH:
case TOK_NAMEPATH:
if (err != PICL_SUCCESS) {
index++;
}
continue;
case TOK_NODE:
if (err == PICL_SUCCESS) {
index++;
&index);
}
break;
case TOK_ENDNODE:
return (PICL_SUCCESS);
case TOK_PROP:
break;
case TOK_REFPROP:
/* no reference node */
if (err == PICL_NOTNODE) {
/* discard row by setting nproph = 0 */
if (cmds->inside_row_block)
.rowcmd_nproph = 0;
}
break;
case TOK_REFNODE:
break;
case TOK_TABLE:
break;
case TOK_ENDTABLE:
cmds->inside_table_block = 0;
cmds->current_tbl = 0;
break;
case TOK_ROW:
break;
case TOK_ENDROW:
cmds->inside_row_block = 0;
cmds->current_row = 0;
break;
case TOK_VERBOSE:
break;
default: /* won't reach here */
err = PICL_FAILURE;
break;
}
return (err);
}
}
/* reach last command */
return (PICL_SUCCESS);
}
/*
* clean up the commands buffer
*/
static void
{
int cmd_index;
case TOK_CLASSPATH:
case TOK_NAMEPATH:
break;
case TOK_NODE:
break;
case TOK_PROP:
break;
case TOK_REFPROP:
break;
case TOK_REFNODE:
break;
case TOK_TABLE:
break;
case TOK_ENDTABLE:
case TOK_ROW:
case TOK_ENDROW:
case TOK_ENDNODE:
case TOK_VERBOSE:
default:
break;
}
}
}
/*
* Parse the configuration file and create nodes/properties under nh
*
* It checks the syntax first. If there is any syntax error,
* it returns 1 and won't continue processing the file to add nodes or props.
*
* If any error happens during command processing, all nodes
* and properties just created will be deleted, i.e. undo
* commands which have been processed. It returns 1.
*
* If success, return 0.
*/
int
{
int last_processed_index;
int err;
/* set correct locale for use inside pluginutil */
/*
* Initialize the command buffer
*/
return (1);
}
return (1);
}
/*
* check the syntax of the configuration file
*/
if (err != EC_SYNTAX_OK) {
return (1);
}
/*
* Process the commands
*/
/*
* handles from the PICL tree.
*/
if (err != PICL_SUCCESS) {
err);
}
/* reset the locale */
}