poolcfg.y revision 26d8ba2242584067b65160d24193c37cdc83cd55
%{
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Overview of poolcfg(1)
*
* poolcfg(1) implements a small grammar for manipulating pools configurations.
* yacc(1) is used to generate the parser and poolcfg.l contains a simple lexer
* (generted by lex(1)) to perform lexical processsing of the input.
*
* Refer to the poolcfg(1) manpage for more details of the grammar.
*
* The parser is designed so that all operations implement the same interface.
* This allows the parser to simply build up the command (using the cmd
* variable) by storing arguments and a pointer to the desired function in the
* cmd. The command is executed when the commands production is matched.
*
* Properties and associations are stored in simple linked lists and processed
* in the order submitted by the user.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <locale.h>
#include <libintl.h>
#include <pool.h>
#include "utils.h"
#include "poolcfg.h"
#define USAGE1 \
"Usage:\n" \
"%s -h\n" \
"%s -c command [ -d | [ file ] ]\n" \
"%s -f command-file [-d | [ file ] ]\n\n"
#define USAGE2 \
"command:\n" \
" info [entity name]\n" \
" display configuration (or specified portion) in readable form\n" \
" create entity name [property-list]\n" \
" make an entity of the specified type and name\n" \
" destroy entity name\n" \
" remove the specified entity\n" \
" modify entity name [property-list]\n" \
" change the listed properties on the named entity\n" \
" associate pool name [resource-list]\n" \
" connect one or more resources to a pool, or replace one or more\n" \
" existing connections\n" \
" transfer to resource name [component-list]\n" \
" transfer one or more discreet components to a resource\n" \
" transfer [quantity] from resource src to tgt\n" \
" transfer a resource quantity from src to tgt\n" \
" transfer [quantity] to resource tgt from src\n" \
" transfer a resource quantity to tgt from src\n" \
" discover\n" \
" create a system entity, with one pool entity and resources to\n" \
" match current system configuration\n" \
" rename entity old_name to new_name\n" \
" change the name of the entity on the system to its new name\n\n" \
"property-list:\n" \
" ( proptype name = value [ ; proptype name = value ]* )\n" \
" where multiple definitions in the sentence for a given\n" \
" proptype, name pair are ignored; the last one provided is used.\n" \
" For property deletion, use \"~ proptype name\"\n\n" \
"resource-list:\n" \
" ( resource name [; resource name ] )\n" \
" where multiple uses of a resource are ignored; the last provided\n" \
" is the one used.\n" \
" There is no deletion syntax for resource lists.\n" \
"component-list:\n" \
" ( cpu id [; cpu id ] )\n" \
" where multiple uses of the same component cause the last provided\n" \
" to be the one used.\n" \
" There is no deletion syntax for component lists.\n" \
"entity:\n" \
" system | pool | pset | cpu\n" \
" where cpu is only valid for transfer, info and modify commands.\n" \
"resource:\n" \
" pset\n\n" \
"proptype:\n" \
" boolean | int | uint | string | float\n\n"
int conf_edit_errno = 0; /* cached errno for error reporting */
int conf_list_errno = 0; /* cached errno for error reporting */
static const char cmdname[] = "poolcfg";
static const char cmd_options[] = "c:df:h";
static void usage(int);
static const char *max_suffix = ".max";
static const char *min_suffix = ".min";
/* yacc externals */
extern int yydebug;
extern void yyerror(char *s);
/* Utility functions */
static void arg_parse(const char *);
static void file_parse(const char *);
static assoc_t *alloc_assoc(int, const char *);
static void check_conf_name(cmd_t *);
static void terminate(void);
static pool_component_t *get_cpu(const char *);
static void process_min_max(pool_resource_t *);
/* Info Commands */
static void parser_conf_info(cmd_t *);
static void parser_pool_info(cmd_t *);
static void parser_resource_info(cmd_t *, const char *);
static void parser_pset_info(cmd_t *);
static void parser_cpu_info(cmd_t *);
/* Create Commands */
static void parser_conf_create(cmd_t *);
static void parser_pool_create(cmd_t *);
static void parser_resource_create(cmd_t *, const char *);
static void parser_pset_create(cmd_t *);
/* Destroy Commands */
static void parser_conf_destroy(cmd_t *);
static void parser_pool_destroy(cmd_t *);
static void parser_resource_destroy(cmd_t *, const char *);
static void parser_pset_destroy(cmd_t *);
/* Modify Commands */
static void parser_conf_modify(cmd_t *);
static void parser_pool_modify(cmd_t *);
static void parser_resource_modify(cmd_t *, const char *);
static void parser_pset_modify(cmd_t *);
static void parser_cpu_modify(cmd_t *);
/* Associate Commands */
static void parser_pool_associate(cmd_t *);
/* Assign Commands */
static void parser_resource_xtransfer(cmd_t *);
static void parser_resource_transfer(cmd_t *);
/* Discover Commands */
static void parser_conf_discover(cmd_t *);
/* Rename Commands */
static void parser_conf_rename(cmd_t *);
static void parser_pool_rename(cmd_t *);
static void parser_pset_rename(cmd_t *);
%}
%union {
double dval;
char *sval;
}
%%
{
free_cmd($1);
}
{
free_cmd($2);
}
{
if (conf_edit_error != POE_OK) {
}
}
};
{
if (conf_list_error != POE_OK) {
}
}
}
{
cmd = $$;
$$->cmd = &parser_conf_info;
}
{
cmd = $$;
switch ($2) {
case PCE_SYSTEM:
$$->cmd = &parser_conf_info;
break;
case PCE_POOL:
$$->cmd = &parser_pool_info;
break;
case PCE_PSET:
$$->cmd = &parser_pset_info;
break;
case PCE_CPU:
$$->cmd = &parser_cpu_info;
break;
default:
}
$$->cmd_tgt1 = $3;
};
{
cmd = $$;
switch ($2) {
case PCE_SYSTEM:
$$->cmd = &parser_conf_create;
/*
* When creating a new system element, ensure
* pre-existing errors are ignored.
*/
break;
case PCE_POOL:
$$->cmd = &parser_pool_create;
break;
case PCE_PSET:
$$->cmd = &parser_pset_create;
break;
default:
}
$$->cmd_tgt1 = $3;
}
{
cmd = $$;
switch ($2) {
case PCE_SYSTEM:
$$->cmd = &parser_conf_destroy;
break;
case PCE_POOL:
$$->cmd = &parser_pool_destroy;
break;
case PCE_PSET:
$$->cmd = &parser_pset_destroy;
break;
default:
}
$$->cmd_tgt1 = $3;
};
{
cmd = $$;
switch ($2) {
case PCE_SYSTEM:
$$->cmd = &parser_conf_modify;
break;
case PCE_POOL:
$$->cmd = &parser_pool_modify;
break;
case PCE_PSET:
$$->cmd = &parser_pset_modify;
break;
case PCE_CPU:
$$->cmd = &parser_cpu_modify;
break;
default:
}
$$->cmd_tgt1 = $3;
}
{
cmd = $$;
$$->cmd = &parser_pool_associate;
}
{
cmd = $$;
$$->cmd = &parser_resource_xtransfer;
}
{
cmd = $$;
$$->cmd = &parser_resource_transfer;
}
{
cmd = $$;
$$->cmd = &parser_resource_transfer;
};
{
cmd = $$;
$$->cmd = &parser_conf_discover;
};
{
cmd = $$;
switch ($2) {
case PCE_SYSTEM:
$$->cmd = &parser_conf_rename;
break;
case PCE_POOL:
$$->cmd = &parser_pool_rename;
break;
case PCE_PSET:
$$->cmd = &parser_pset_rename;
break;
default:
}
$$->cmd_tgt1 = $3;
$$->cmd_tgt2 = $5;
};
| PCV_VAL_UINT { $$.u = $1;}
| PCV_VAL_FLOAT { $$.d = $1;}
| PCV_VAL_BOOLEAN { $$.b = $1;}
| PCV_VAL_STRING { $$.s = $1;};
{
$$->prop_name = $3;
};
| prop_remove;
{
else
$$ = cmd->cmd_prop_list;
}
{
else
$$ = cmd->cmd_prop_list;
};
{
$$->prop_name = $2;
switch ($1) {
case PCT_INT:
break;
case PCT_UINT:
break;
case PCT_BOOLEAN:
break;
case PCT_FLOAT:
break;
case PCT_STRING:
break;
}
};
{
$$ = $2;
};
{
else
$$ = cmd->cmd_assoc_list;
}
{
$$ = $3;
};
{
};
{
$$ = $2;
};
{
else
$$ = cmd->cmd_assoc_list;
}
{
$$ = $3;
};
{
$$ = $2;
};
{
};
| PCT_BOOLEAN {$$ = PCT_BOOLEAN;}
| PCT_STRING {$$ = PCT_STRING;};
%%
#ifndef TEXT_DOMAIN
#define TEXT_DOMAIN "SYS_TEST"
#endif
int
{
int opt;
(void) textdomain(TEXT_DOMAIN);
}
yydebug = 0;
switch (opt) {
case 'c': /* Process command line */
usage(1);
break;
case 'd': /* Manipulate dynamic configuration */
break;
case 'f': /* Process command file */
usage(1);
break;
case 'h':
usage(2);
break;
case '?':
default:
usage(1);
break;
}
}
usage(1);
usage(1);
usage(1);
get_errstr());
}
/*
* Opening a conf is complex, since we may be opening one of the
* following:
* - An existing configuration that we can modify
* - An existing configuration that we can't modify
* - A new configuration that we can modify
* - A new configuration that we can't modify
* The parser_conf_discover() function closes the file and reopens
* in PO_CREAT mode, so we only need be concerned here with the
* first two cases.
* Always try to open RDWR, if fail try RDONLY. Don't check
* if that fails, since we may be trying to discover a configuration
* in which case it's valid for both open attempts to fail. Later, when
* processing commands, if we don't have a valid configuration and
* we are trying to process a command which isn't a create or a discover
* we will fail the command as there is no valid configuration to
* work with.
*/
}
}
if (yyparse() == 0) {
get_errstr());
}
/*
* If the user attempted to change the configuration,
* then we should try to save the changes.
*/
get_errstr());
}
}
}
} else {
}
/*
* Cleanup is performed in terminate(), using atexit
*/
return (0);
}
/*
* Info Commands
* Invoke the appropriate libpool info function and display the returned
* information.
*/
static void
{
char *info_buf;
else {
POC_INVAL ||
}
tgt, get_errstr());
}
}
}
static void
{
char *info_buf;
get_errstr());
}
static void
{
char *info_buf;
}
static void
{
}
static void
{
char *info_buf;
}
}
/*
* Create Commands
* Invoke the appropriate libpool create function and perform any requested
* property operations.
*/
static void
{
const char *tmp_name;
}
}
static void
{
get_errstr());
}
static void
{
== NULL)
get_errstr());
}
static void
{
}
/*
* Rename Commands
* Rename the target by calling pool_put_property for the name property.
*/
static void
{
get_errstr());
}
}
static void
{
}
static void
{
get_errstr());
}
static void
{
get_errstr());
}
/*
* Destroy Commands
* Invoke the appropriate libpool destroy function to remove the target of the
* command from the configuration.
*/
static void
{
if (pool_conf_remove(conf) != 0)
}
static void
{
get_errstr());
get_errstr());
}
static void
{
get_errstr());
get_errstr());
}
static void
{
}
/*
* Modify Commands
* Perform any requested property operations.
*/
static void
{
}
static void
{
get_errstr());
}
static void
{
}
static void
{
}
static void
{
}
/*
* Discover Commands
* Invoke the libpool pool_conf_open function so that discovery will be
* performed.
*/
/*ARGSUSED*/
static void
{
return;
"unknown", get_errstr());
}
}
(void) pool_conf_close(conf);
}
}
/*
* Associate Commands
* Walk the list of specified associations so that the target pool will be
* associated with the required resources.
*/
static void
{
get_errstr());
}
/*
* Assign Commands
* Walk the list of specified assignations so that the required
* components will be assigned to the target resource.
*/
static void
{
}
/*
* Transfer Commands
* Transfer the specified quantity of resource between the src and the tgt.
*/
static void
{
}
/*
* arg_parse() puts the parser into command parsing mode. Create a tmpfile
* and instruct the parser to read instructions from this location by setting
* yyin to the value returned by tmpfile. Write the command into the file.
* Then seek back to to the start of the file so that the parser can read
* the instructions.
*/
static void
{
}
/*
* file_parse() puts the parser into command file parsing mode. Firstly check
* to see if the user wishes to parse from standard input, if so do nothing.
* Attempt to open the specified file and instruct the parser to read
* instructions from this location by setting yyin to the value returned by
* fopen.
*/
static void
file_parse(const char *file)
{
return;
}
}
/*
* free_cmd() releases the resources associated with the supplied cmd parameter.
*/
static void
{
}
}
}
/*
* alloc_cmd() allocates the required resources for a cmd_t. On failure, a
* warning is issued and NULL is returned.
*/
static cmd_t *
alloc_cmd(void)
{
return (NULL);
}
return (cmd);
}
/*
* alloc_prop() allocates the required resources for a prop_t. On failure, a
* warning is issued and NULL is returned. The prop_t is initialised with
* the prop_op_t parameter.
*/
static prop_t *
{
return (NULL);
}
return (NULL);
}
return (prop);
}
/*
* alloc_assoc() allocates the required resources for an assoc_t. On failure, a
* warning is issued and NULL is returned. The assoc_t is initialised with
* the type and name of the association.
*/
static assoc_t *
{
return (NULL);
}
return (assoc);
}
/*
* check_conf_name() ensures the the name of the system in the configuration
* which is being manipulated matches the name of the system in the command.
* If not, the command is terminated with an appropriate error message.
*/
static void
{
const char *name;
get_errstr());
}
== POC_INVAL)
get_errstr());
get_errstr());
}
}
/*
* usage() display brief or verbose help for the poolcfg(1) command.
*/
static void
{
if (help >= 1)
cmdname);
if (help >= 2)
}
/*
* prop_list_walk() walks the property manipulation requests and either puts
* or removes the property as appropriate.
*/
static void
{
case po_create:
prop->prop_value) != 0)
break;
case po_remove:
break;
}
}
}
/*
* assoc_list_walk() walks the resource association requests and attempts
* to associate the pool with the specified resource.
*/
static void
{
switch (assoc->assoc_type) {
case PCE_PSET:
break;
default:
assoc->assoc_type);
break;
}
get_errstr());
}
}
/*
* transfer_list_walk() walks the component assign requests and attempts
* to assign the component with the specified resource.
*/
static void
{
}
}
/*
* terminate() is invoked when poolcfg exits. It cleans up
* configurations and closes the parser input stream.
*/
static void
terminate(void)
{
(void) pool_conf_close(conf);
}
}
/*
* get_cpu() takes the name of a CPU components and attempts to locate
* the element with that name. If the name is not formatted correctly
* (i.e. contains non-numeric characters) then the function terminates
* execution. If the components cannot be uniquely identified by the
* name, then NULL is returned.
*/
static pool_component_t *
{
const char *c;
return (NULL);
pool_value_free(vals[0]);
return (NULL);
}
pool_value_free(vals[0]);
return (NULL);
}
if (!isdigit(*c)){
pool_value_free(vals[0]);
"digits"));
}
}
pool_value_free(vals[0]);
return (NULL);
}
pool_value_free(vals[0]);
return (NULL);
}
NULL) {
pool_value_free(vals[0]);
return (NULL);
}
if (nelem != 1) {
pool_value_free(vals[0]);
return (NULL);
}
pool_value_free(vals[0]);
ret = components[0];
return (ret);
}
/*
* process_min_max() ensures that "min" and "max" properties are
* processed correctly by poolcfg. libpool enforces validity
* constraints on these properties and so it's important that changes
* to them are supplied to the library in the correct order.
*/
void
{
/*
* Before walking the list of properties, it has to be checked
* to ensure there are no clashes between min and max. If
* there are, then process these properties immediately.
*/
const char *pos;
- 4)
- 4)
}
const char *type;
char *prop_name;
+ 1)) == NULL)
} else {
}
}
}